aboutsummaryrefslogtreecommitdiff
path: root/xpdf-qt/XpdfWidget.h
blob: 0e33d0d4f32223310197d608f1e77c53eaba43c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
//========================================================================
//
// XpdfWidget.h
//
// Copyright 2009-2021 Glyph & Cog, LLC
//
//========================================================================

//! \mainpage
//!
//! XpdfWidget is a PDF viewer widget class for Qt.
//! <br><br>
//! <a href="changes.html">Change history</a>
//! <br><br>
//! Copyright 2009-2022 Glyph & Cog, LLC

//! \file

#ifndef XPDFWIDGET_H
#define XPDFWIDGET_H

#include <aconf.h>

#ifdef USE_GCC_PRAGMAS
#pragma interface
#endif

#include <QAbstractScrollArea>

class QMutex;
class QTimer;
#if XPDFWIDGET_PRINTING
class QPrinter;
class QPrintDialog;
#endif

class GString;
class PDFDoc;
class QtPDFCore;

//------------------------------------------------------------------------


/*! Opaque handle used to represent an outline node. */
typedef void *XpdfOutlineHandle;

/*! Opaque handle used to represent a layer. */
typedef void *XpdfLayerHandle;

/*! Opaque handle used to represent a layer display order tree node. */
typedef void *XpdfLayerOrderHandle;

/*! Opaque handle used to represent an annotation. */
typedef void *XpdfAnnotHandle;

/*! Opaque handle used to represent a form field. */
typedef void *XpdfFormFieldHandle;

/*! Opaque handle used to represent a PDF document. */
typedef void *XpdfDocHandle;

//------------------------------------------------------------------------

/*! Text search result, returned by XpdfWidget::findAll(). */
struct XpdfFindResult {

  //! \cond PROTECTED
  XpdfFindResult(int pageA, double xMinA, double yMinA,
		 double xMaxA, double yMaxA)
    : page(pageA), xMin(xMinA), yMin(yMinA), xMax(xMaxA), yMax(yMaxA) {}
  XpdfFindResult(): page(0), xMin(0), yMin(0), xMax(0), yMax(0) {}
  //! \endcond

  /*! Page number. */
  int page;

  /*! \name Bounding box. */
  ///@{
  double xMin, yMin, xMax, yMax;
  ///@}
};

//------------------------------------------------------------------------

//! A PDF viewer widget class for Qt.
class XpdfWidget: public QAbstractScrollArea {
  Q_OBJECT

public:

  //! Error codes returned by certain XpdfViewer functions.
  enum ErrorCode {
    pdfOk               =    0,	//!< no error
    pdfErrOpenFile      =    1,	//!< couldn't open the PDF file
    pdfErrBadCatalog    =    2,	//!< couldn't read the page catalog
    pdfErrDamaged       =    3,	//!< PDF file was damaged and couldn't be
				//!<   repaired
    pdfErrEncrypted     =    4,	//!< file was encrypted and password was
				//!<   incorrect or not supplied
    pdfErrHighlightFile =    5,	//!< nonexistent or invalid highlight file
    pdfErrBadPrinter    =    6,	//!< invalid printer
    pdfErrPrinting      =    7,	//!< error during printing
    pdfErrPermission    =    8,	//!< PDF file doesn't allow that operation
    pdfErrBadPageNum    =    9,	//!< invalid page number
    pdfErrFileIO        =   10,	//!< file I/O error
    pdfErrNoHandle      = 1001,	//!< NULL object handle
    pdfErrOutOfMemory   = 1002,	//!< out of memory
    pdfErrBusy          = 1003,	//!< PDF component is busy
    pdfErrBadArg        = 1004	//!< invalid argument
  };

  //! Display modes, to be passed to XpdfWidget::setDisplayMode().
  enum DisplayMode {
    pdfDisplaySingle,			//!< single page
    pdfDisplayContinuous,		//!< pages stacked vertically
    pdfDisplaySideBySideSingle,		//!< two facing pages
    pdfDisplaySideBySideContinuous,	//!< facing pages, stacked vertically
    pdfDisplayHorizontalContinuous	//!< pages stacked horizontally
  };

  //! \name Zoom values
  //! Special values for XpdfWidget::setZoom() / XpdfWidget::getZoom()
  //@{
  static const int zoomToPage  = -1;	//!< zoom to fit whole page
  static const int zoomToWidth = -2;	//!< zoom to fit page width
  static const int zoomToHeight = -3;	//!< zoom to fit page height
  //@}

  //! \name Find flags
  //! Flags to be passed to XpdfWidget::find()
  //@{
  //! search backward from the starting point
  static const int findBackward      = 0x00000001;
  //! perform a case-sensitive search (default is case-insensitive)
  static const int findCaseSensitive = 0x00000002;
  //! start searching from the previous search result
  static const int findNext          = 0x00000004;
  //! limit the search to the current page
  static const int findOnePageOnly   = 0x00000008;
  //! limit the search to whole words
  static const int findWholeWord     = 0x00000010;
  //@}

  //! Initialize the XpdfWidget class, reading a configuration file.
  //! If \a configFileName is non-empty, the specified file is
  //! tried first.  If \a configFileName is empty, or the file
  //! doesn't exist, the default location is tried (\c <exe-dir>/xpdfrc
  //! on Windows; \c ~/\c .xpdfrc on Unix).
  //!
  //! This function must be called before any other XpdfWidget functions
  //! (including the constructor).  It will be called automatically
  //! (with a NULL \a configFileName) if it hasn't already been
  //! called when the first XpdfWidget function is used.
  static void init(const QString &configFileName = QString());

  //! Process a configuration command, i.e., one line of an xpdfrc file.
  //! Note that this applies globally to all XpdfWidget instances.
  static void setConfig(const QString &command);

  //! The XpdfWidget constructor.
  //! \param paperColor the paper background color (which should generally
  //!        be left as white)
  //! \param matteColor the matte color displayed between pages, and around
  //!        pages that are smaller than the window
  //! \param reverseVideo sets reverse video at startup
  //! \param parentA the parent QWidget
  XpdfWidget(const QColor &paperColor = QColor(0xff, 0xff, 0xff),
	     const QColor &matteColor = QColor(0x80, 0x80, 0x80),
	     bool reverseVideo = false, QWidget *parentA = 0);

  //! The XpdfWidget constructor.
  //! \param paperColor the paper background color (which should generally
  //!        be left as white)
  //! \param matteColor the matte color displayed between pages, and around
  //!        pages that are smaller than the window
  //! \param reverseVideo sets reverse video at startup
  //! \param parentA the parent QWidget
  //! This version has the \a parent argument first so it works correctly
  //! with Qt Designer.
  XpdfWidget(QWidget *parentA,
	     const QColor &paperColor = QColor(0xff, 0xff, 0xff),
	     const QColor &matteColor = QColor(0x80, 0x80, 0x80),
	     bool reverseVideo = false);

  //! Destroys the XpdfWidget.
  virtual ~XpdfWidget();

  //! Control handling of hyperlinks.
  //! If enabled, the viewer will follow hyperlinks when clicked with the
  //! left mouse button.  If disabled, the viewer will ignore left mouse
  //! button clicks on hyperlinks.  The default is enabled.
  void enableHyperlinks(bool on);

  //! Control handling of external hyperlinks.
  //! This setting allows disabling external hyperlinks (links that
  //! open another PDF file, or that involve a URL), independent of
  //! internal hyperlinks (links to locations within the same PDF
  //! file).  This setting is ignored if all hyperlinks are disabled
  //! (enableHyperlinks(false)).  The default is enabled.
  void enableExternalHyperlinks(bool on);

  //! Control handling of text selection.
  //! If enabled, the viewer will allow the user to select rectangular
  //! regions of text when the user drags with the left mouse button.  If
  //! disabled, dragging with the left mouse button is ignored.  The
  //! default is enabled.
  void enableSelect(bool on);

  //! Control mouse panning.
  //! If enabled, dragging with the middle mouse button pressed will pan
  //! the page.  If disabled, the middle button is ignored.  The default
  //! is enabled.
  void enablePan(bool on);

  //! Control touchscreen panning.
  //! If enabled, QPanGestures are recognized and used to pan the PDF
  //! view.
  void enableTouchPan(bool on);

  //! Control touchscreen zooming.
  //! If enabled QPinchGestures are recognized and used to pinch-zoom
  //! the PDF view.
  void enableTouchZoom(bool on);

  //! Control keypress passthrough.
  //! If enabled, XpdfWidget will pass keypress events through to the
  //! keyPress signal, with no other processing.  If disabled, XpdfWidget
  //! will implement some built-in key bindings.  The default is disabled.
  void setKeyPassthrough(bool on) { keyPassthrough = on; }

  //! Control mouse event passthrough.
  //! If enabled, XpdfWidget will pass mouse events through to the
  //! mousePress/mouseRelease signals, with no other processing.  If
  //! disabled, XpdfWidget will implement some built-in mouse handling
  //! (in addition to sending the signals).  The default is disabled.
  void setMousePassthrough(bool on) { mousePassthrough = on; }

  //! Control the password dialog.
  //! If enabled, the viewer will show a password dialog for encrypted
  //! files; if disabled, it will simply return \c pdfErrEncrypted unless
  //! the correct password is passed to \c pdfLoadFileWithPassword.  The
  //! default is enabled.
  void showPasswordDialog(bool showDlg);

  //! Set the matte color, i.e., the color used for background outside
  //! the actual page area.  The default is a medium gray.
  void setMatteColor(const QColor &matteColor);

  //! Turn reverse video mode on/off.  The default is off.
  void setReverseVideo(bool reverse);

  //! Set the cursor.  The requested cursor will only be displayed in
  //! the viewport (not in the scrollbars).
  void setCursor(const QCursor &cursor);

  //! Reset to the default cursor.
  void unsetCursor();

  //! Load a PDF file and display its first page.
  //! \param fileName the PDF file to load
  //! \param password a string to be tried first as the owner password
  //!        and then as the user password
  //! \return \c pdfOk if successful; an error code, otherwise
  ErrorCode loadFile(const QString &fileName,
		     const QString &password = "");

  //! Load a PDF file from a memory buffer and display its first page.
  //! \param buffer the PDF file in memory
  //! \param bufferLength length of \a buffer
  //! \param password a string to be tried first as the owner password
  //!        and then as the user password
  //! \return \c pdfOk if successful; an error code otherwise
  ErrorCode loadMem(const char *buffer, unsigned int bufferLength,
		    const QString &password = "");

  //! Load a PDF file and return a handle.

  //! This function can be safely called from a non-GUI thread.  Use
  //! XpdfWidget::loadDoc (on the GUI thread) to load the document
  //! handle into the viewer.  The handle returned in *\c docPtr
  //! should be passed to either XpdfWidget::loadDoc or
  //! XpdfWidget::freeDoc.
  //!
  //! Calling XpdfWidget::readDoc + XpdfWidget::loadDoc is equivalent
  //! to calling XpdfWidget::loadFile.  The difference is that readDoc
  //! can be called on a background thread to avoid stalling the user
  //! interface.
  //! \param docPtr the PDF document handle will be returned her
  //! \param fileName the PDF file to load
  //! \param password a string to be tried first as the owner password
  //!        and then as the user password
  //! \return \c pdfOk if successful; an error code, otherwise
  ErrorCode readDoc(XpdfDocHandle *docPtr,
		    const QString &fileName,
		    const QString &password = "");

  //! Load a PDF document and display its first page.
  //! This function displays a PDF document handle created by
  //! XpdfWidget::readDoc.  The document handle should not be used for
  //! anything else after calling this function.
  //! \return \c pdfOk if successful; an error code, otherwise
  ErrorCode loadDoc(XpdfDocHandle doc);

  //! Free a PDF document.
  //! This function frees a PDF document handle created by
  //! XpdfWidget::readDoc.  It should only be called if the document
  //! is not going to be displayed.  That is: after calling
  //! XpdfWidget::readDoc, you should call either XpdfWidget::loadDoc
  //! or XpdfWidget::freeDoc.  The document handle should not be used
  //! for anything else after calling this function.
  void freeDoc(XpdfDocHandle doc);

  //! Reload the current PDF file.
  //! This reloads the current PDF file, maintaining the zoom and
  //! scroll position (if possible).  This only works if the PDF file
  //! was loaded from a file (i.e., with XpdfWidget::loadFile, not
  //! with XpdfWidget::loadMem).
  //! \return \c pdfOk if successful; an error code otherwise
  ErrorCode reload();

  //! Close the currently open PDF file (if any).
  //! Calling this function is optional - the current PDF file will be
  //! automatically closed if XpdfWidget::loadFile or XpdfWidget::loadMem
  //! is called.
  void closeFile();

  //! Save the PDF file with another name.
  //! \param fileName the file to be written
  //! \return \c pdfOk if successful; an error code otherwise
  ErrorCode saveAs(const QString &fileName);

  //! Get the file name of the currently open PDF file.
  QString getFileName() const;

  //! Returns true if there is currently a PDF file open.
  bool hasOpenDocument() const;

  //! Return the number of pages in the currently open PDF file.
  //! Returns -1 if no file is open.
  int getNumPages() const;

  //! Return the currently displayed page number.
  //! Returns -1 if no file is open.
  int getCurrentPage() const;

  //! Return the page number corresponding to the middle of the
  //! window.
  int getMidPage() const;

  //! Display the specified page.
  void gotoPage(int pageNum);

  //! Display the first page.
  //! This is equivalent to \code
  //!     gotoPage(1)
  //! \endcode
  void gotoFirstPage();

  //! Display the last page.
  //! This is equivalent to \code
  //!     gotoPage(getNumPages())
  //! \endcode
  void gotoLastPage();

  //! Display the next page.
  void gotoNextPage(bool scrollToTop = true);

  //! Display the previous page.
  void gotoPreviousPage(bool scrollToTop = true);

  //! Go to a named destination.
  bool gotoNamedDestination(const QString &dest);

  //! Go forward along the history list.
  void goForward();

  //! Go backward along the history list.
  void goBackward();

  //! Scroll one screen up.
  void scrollPageUp();

  //! Scroll one screen down.
  void scrollPageDown();

  //! Scroll the page so that the top-left corner of the window is
  //! (\a xx,\a yy) pixels from the top-left corner of the PDF page.
  void scrollTo(int xx, int yy);

  //! Scroll the page by (\a dx,\a dy) pixels.  If \a dx is positive,
  //! scrolls right; if \a dx is negative, scrolls left.  Similarly,
  //! positive and negative values of \a dy scroll down and up,
  //! respectively.
  void scrollBy(int dx, int dy);

  //! Return the current scroll position x coordinate.
  int getScrollX() const;

  //! Return the current scroll position y coordinate.
  int getScrollY() const;

  //! Change the zoom factor.
  //! This can be a percentage factor (where 100 means 72 dpi) or one of
  //! the special values, XpdfWidget::zoomToPage or XpdfWidget::zoomToWidth.
  void setZoom(double zoom);

  //! Return the current zoom factor.
  //! This can be a percentage factor or one of the special values,
  //! XpdfWidget::zoomToPage or XpdfWidget::zoomToWidth.
  double getZoom() const;

  //! Return the current zoom factor as a percentage.
  //! If the zoom is set to XpdfWidget::zoomToPage or
  //! XpdfWidget::zoomToWidth, returns the computed zoom percentage
  //! for the specified page, based on the current window size.
  double getZoomPercent(int page = 1) const;

  //! Zoom in to the specified rectangle.
  //! The coordinate system is the same one used by
  //! XpdfWidget::getCurrentSelection.  This function will set the zoom
  //! factor and scroll position so that the specified rectangle just fits
  //! in the window.
  void zoomToRect(int page, double xMin, double yMin,
		  double xMax, double yMax);

  //! Set the zoom factor, while maintaining the current center.
  //! Accepts the same zoom values as XpdfWidget::setZoom.
  void zoomCentered(double zoom);

  //! Zoom so that the current page(s) fill the window width.
  //! Maintains the vertical center.
  void zoomToCurrentWidth();

  //! Change the page rotation.
  //! \param rotate rotation angle in degrees - must be 0, 90, 180, or 270
  void setRotate(int rotate);

  //! Return the current page rotation.
  //! The angle can be 0, 90, 180, or 270.
  int getRotate() const;

  //! Set continuous or single-page view mode.
  //! Deprecated: this is equivalent to calling setDisplayMode() with
  //! pdfDisplaySingle or pdfDisplayContinuous.
  //! \param continuous true for continous view mode, false for single-page
  //!        view mode
  void setContinuousMode(bool continuous);

  //! Return true if the viewer is in continuous view mode, or false
  //! if it is in any other mode.  Deprecated: see getDisplayMode().
  bool getContinuousMode() const;

  //! Set the display mode.
  void setDisplayMode(DisplayMode mode);

  //! Return the current display mode.
  DisplayMode getDisplayMode();

  //! Returns true if the mouse is currently over a hyperlink.
  bool mouseOverLink();

  //! Returns true if the specified coordinates are inside a
  //! hyperlink.  Note: This function expects PDF coordinates, not window
  //! coordinates.
  bool onLink(int page, double xx, double yy);

  //! Get destination information for the hyperlink at the specified
  //! page and coordinates.  If there is a link at the specified
  //! point, returns a string suitable for displaying to a user;
  //! otherwise returns an empty string.  Note: This function expects
  //! PDF coordinates, not window coordinates.
  QString getLinkInfo(int page, double xx, double yy);

  //! Get destination information for the hyperlink under the mouse.
  //! If the mouse is currently over a hyperlink, return an info
  //! string (same as with getLinkInfo()); otherwise return an empty
  //! string.
  QString getMouseLinkInfo();

  //! Activate the link (if any) at the specified page and coordinates.
  //! Returns true if successful.  Note: This function expects PDF
  //! coordinates, not window coordinates.
  bool gotoLinkAt(int page, double xx, double yy);

  //! Check for an annotation containing the specified point.
  //! Returns NULL if there is no annotation at this point.  Note:
  //! This function expects PDF coordinates, not window coordinates.
  XpdfAnnotHandle onAnnot(int page, double xx, double yy);

  //! Get the annotation type.
  QString getAnnotType(XpdfAnnotHandle annot);

  //! Get the annotation's content.
  //! Usage of this depends on the annotation type.
  QString getAnnotContent(XpdfAnnotHandle annot);

  //! Check for a form field containing the specified point.
  //! Returns NULL if there is no annotation at this point.  Note:
  //! This function expects PDF coordinates, not window coordinates.
  XpdfFormFieldHandle onFormField(int page, double xx, double yy);

  //! Get the form field's type.
  QString getFormFieldType(XpdfFormFieldHandle field);

  //! Get the form field's name.
  QString getFormFieldName(XpdfFormFieldHandle field);

  //! Get the form field's content.
  //! Usage of this depends on the field type.
  QString getFormFieldValue(XpdfFormFieldHandle field);

  //! Get the form field's bounding box.
  void getFormFieldBBox(XpdfFormFieldHandle field, int *pageNum,
			double *xMin, double *yMin,
			double *xMax, double *yMax);

  //! Convert window coordinates to PDF coordinates.  Returns true if
  //! successful, i.e., if the specified point falls on a PDF page.
  bool convertWindowToPDFCoords(int winX, int winY,
				int *page, double *pdfX, double *pdfY);

  //! Convert PDF coordinates to window coordinates.
  void convertPDFToWindowCoords(int page, double pdfX, double pdfY,
				int *winX, int *winY);

  //! Enable or disable window redraws.
  //! This is useful, e.g., for avoiding extra redraws during window
  //! resizing.  Deprecated -- this just calls setUpdatesEnabled().
  void enableRedraw(bool enable);

  //! Return the coordinates of the specified page box.
  //! \param page the page number
  //! \param box the requested page box - one of "media", "crop",
  //!        "bleed", "trim", or "art" (\a box is not case-sensitive)
  //! \param *xMin returns the minimum x coordinate of the box
  //! \param *yMin returns the minimum y coordinate of the box
  //! \param *xMax returns the maximum x coordinate of the box
  //! \param *yMax returns the maximum y coordinate of the box
  //!
  //! All coordinates are in points (1 point = 1/72 inch).
  void getPageBox(int page, const QString &box,
		  double *xMin, double *yMin, double *xMax, double *yMax) const;

  //! Return the width of the specified page.
  //! This function returns the crop box width, measured in points
  //! (1 point = 1/72 inch).
  double getPageWidth(int page) const;

  //! Return the height of the specified page.
  //! This function returns the crop box height, measured in points
  //! (1 point = 1/72 inch).
  double getPageHeight(int page) const;

  //! Get the default rotation for the specified page.
  //! This is the default viewing rotation specified in the PDF file -
  //! it will be one of 0, 90, 180, or 270.
  int getPageRotation(int page) const;

  //! Check to see if there is a selection.
  //! Returns true if there is a currently active selection.
  bool hasSelection();

  //! Returns the current selection.
  //! If there is a currently active selection, sets *\a page, (*\a x0,*\a y0),
  //! and (*\a x1,*\a y1) to the page number and upper-left and lower-right
  //! coordinates, respectively, and returns true.  If there is no selection,
  //! returns false.
  bool getCurrentSelection(int *page, double *x0, double *y0,
			   double *x1, double *y1) const;

  //! Set the selection.
  //! Sets the current selection to the rectangle with upper-left corner
  //! (\a x0,\a y0) and lower-right corner (\a x1,\a y1) on \a page.
  void setCurrentSelection(int page, double x0, double y0,
			   double x1, double y1);

  //! Clear the selection.
  void clearSelection();

  //! Check for block selection mode.
  //! Returns true if the current selection mode is block.
  bool isBlockSelectMode();

  //! Check for linear selection mode.
  //! Returns true if the current selection mode is linear.
  bool isLinearSelectMode();

  //! Set block selection mode.
  //! In this mode, the selection is a simple rectangle.  Any part of
  //! the page can be selected, regardless of the content on the page.
  void setBlockSelectMode();

  //! Set linear selection mode.
  //! In this mode, the selection follows text.  Non-text regions
  //! cannot be selected.
  void setLinearSelectMode();

  //! Set the selection color.
  void setSelectionColor(const QColor &selectionColor);


  //! Force a complete redraw.
  void forceRedraw();

#if XPDFWIDGET_PRINTING
  //! Checks to see if printing is allowed.
  //! This function returns false if the currently displayed PDF file
  //! is encrypted and does not allow printing (or if no PDF file is
  //! currently open).  The owner password can be used to circumvent
  //! this: if a valid owner password was supplied to
  //! XpdfWidget::loadFile, this function will always return true.  If
  //! this function returns false, the printing functions will return
  //! an error.
  bool okToPrint() const;

  //! Print the currently displayed PDF file.
  //! Prints the currently displayed PDF file.  If \a showDialog is
  //! true, displays the Qt print dialog, and uses the printer
  //! selected by the user.  If \a showDialog is false, prints to the
  //! default printer without showing any dialogs.
  ErrorCode print(bool showDialog);

  //! Print the currently displayed PDF file.
  //! Prints the currently displayed PDF file to \a prt.
  ErrorCode print(QPrinter *prt);

  //! Cancel an in-progress print job.  This should be called in
  //! response to a printStatus signal.
  void cancelPrint() { printCanceled = true; }

  void updatePrintStatus(int nextPage, int firstPage, int lastPage);
  bool isPrintCanceled() { return printCanceled; }

  //! Set the horizontal and vertical print resolution, in dots per
  //! inch (DPI).  The horizontal and vertical resolutions are
  //! typically the same.  (There are exceptions, such as some chart
  //! printers.)
  void setPrintDPI(int hDPI, int vDPI);
#endif // XPDFWIDGET_PRINTING

  //! Convert a page to a color image.
  //! This function converts the page number \a page to a 24-bit RGB
  //! bitmap, at a resolution of \a dpi dots per inch.  If \a
  //! transparent is true, the returned image will be 32-bit ARGB
  //! instead, and will include an alpha channel.
  QImage convertPageToImage(int page, double dpi, bool transparent = false);

  //! Convert a rectangular region of a page to a color image.
  //! This function converts a rectangular region, defined by corners
  //! (\a x0,\a y0) and (\a x1,\a y1), of page number \a page to a
  //! 24-bit RGB bitmap, at a resolution of \a dpi dots per inch.  If
  //! \a transparent is true, the returned image will be 32-bit ARGB
  //! instead, and will include an alpha channel.
  QImage convertRegionToImage(int page, double x0, double y0,
			      double x1, double y1, double dpi,
			      bool transparent = false);

  //! Retrieve an embedded thumbnail image.
  //! This function returns the embedded thumbnail image for the
  //! specified page, or a null image if there is no embedded
  //! thumbnail.  This function does not do any rasterization -- it
  //! only returns a non-null image if there is an embedded thumbnail
  //! in the PDF file.
  QImage getThumbnail(int page);

  //! Checks to see if text extraction is allowed.
  //! This function returns false if the currently displayed PDF file
  //! is encrypted and does not allow extraction of text (or if no PDF
  //! file is currently open).  The owner password can be used to
  //! circumvent this: if a valid owner password was supplied to
  //! XpdfWidget::loadFile, this function will always return true.
  //! If this function returns false, the text extraction functions will
  //! not return any text.
  bool okToExtractText() const;

  //! Set the encoding to use for text extraction.
  //! The following encodings are predefined:
  //!   - \c "Latin1": ISO-8859-1 (this is the default value)
  //!   - \c "ASCII7": 7-bit ASCII
  //!   - \c "UTF-8": Unicode in UTF-8 format
  //!   - \c "UCS-2": Unicode in UCS-2 format
  //!
  //! Additional encodings can be defined via the xpdfrc config file.
  void setTextEncoding(const QString &encodingName);

  //! Extract text from a region of a page.
  //! This function extracts and returns text from the rectangular
  //! region, defined by corners (\a x0,\a y0) and (\a x1,\a y1), of
  //! page number \a page.  The coordinates returned by
  //! XpdfWidget::getCurrentSelection may be passed directly to this
  //! function.  Returns an empty string if no file is open or if
  //! text extraction is not allowed.
  QString extractText(int page, double x0, double y0,
		      double x1, double y1);

  //! Get the currently selected text.
  //! Returns an empty string if there is no selection (or if there is
  //! no text in the selected region).
  QString getSelectedText();

  //! Copy the current selection to the clipboard.
  void copySelection();

  //! Find a text string.
  //! This function searches for a Unicode text string.  Starts
  //! searching after (before, if searching backward) the current
  //! selection (if there is a selection), or at the top (bottom,
  //! if searching backward) of the current page (if there is no
  //! selection).  The \a flags argument consists of zero or more
  //! of the following, or-ed together:
  //!   - \c findBackward - search backward from the starting point
  //!   - \c findCaseSensitive - perform a case-sensitive search
  //!     (default is case-insensitive)
  //!   - \c findNext - start searching from the previous search result
  //!   - \c findOnePageOnly - limit the search to the current page
  //!   - \c findWholeWord - limit the search to whole words
  bool find(const QString &text, int flags = 0);

  //! Find all occurrences of a text string.
  //! This function searches for a Unicode text string, in pages
  //! \a firstPage .. \a lastPage.  The \a flags argument consists of
  //! zero or more of the following, or-ed together:
  //!   - \c findCaseSensitive - perform a case-sensitive search
  //!     (default is case-insensitive)
  //!   - \c findWholeWord - limit the search to whole words
  //! Returns a list of search results.
  QVector<XpdfFindResult> findAll(const QString &text, int firstPage,
				  int lastPage, int flags = 0);

  //! Check if the PDF file has page labels.
  //! Return true if the currently open PDF file has page labels.
  bool hasPageLabels();

  //! Convert a page number to a page label.
  //! Return the page label for page number \a pageNum.  Returns an
  //! empty string if the page number is invalid or if the PDF file
  //! doesn't have page labels.
  QString getPageLabelFromPageNum(int pageNum);

  //! Convert a page label to a page number.
  //! Return the page number for \a pageLabel.  Returns -1 if there is
  //! no matching page label or if the PDF file doesn't have page
  //! labels.
  int getPageNumFromPageLabel(QString pageLabel);

  //! Return the number of children of an outline tree node.
  //! This function returns the number of children of node \a outline,
  //! or the number of root outline entries if \a outline is \c NULL.
  int getOutlineNumChildren(XpdfOutlineHandle outline);

  //! Return a child of an outline tree node.
  //! This function returns the \a idx 'th child of node \a outline,
  //! or the \a idx 'th root entry if \a outline is \c NULL.
  XpdfOutlineHandle getOutlineChild(XpdfOutlineHandle outline, int idx);

  //! Return the parent of an outline tree node.
  //! This function returns the parent of node \a outline, or NULL if
  //! \a outline is a root item.
  XpdfOutlineHandle getOutlineParent(XpdfOutlineHandle outline);

  //! Get the title of an outline tree node.
  //! This function returns the title of node \a outline.
  QString getOutlineTitle(XpdfOutlineHandle outline);

  //! Return true if the specified outline entry starts open.
  bool getOutlineStartsOpen(XpdfOutlineHandle outline);

  //! Return the target page number for the specified outline entry.
  int getOutlineTargetPage(XpdfOutlineHandle outline);

  //! Jump to the target of the specified outline entry.
  void gotoOutlineTarget(XpdfOutlineHandle outline);

  //! Return the number of layers in the PDF file.
  //! Note that a PDF file can have zero or more layers.
  int getNumLayers() const;

  //! Get a layer handle.
  //! This function returns a handle for the \a idx 'th layer.
  XpdfLayerHandle getLayer(int idx) const;

  //! Get the name of a layer.
  //! This function returns the title of \a layer.
  QString getLayerName(XpdfLayerHandle layer) const;

  //! Get the visibility state of a layer.
  //! Returns true if the layer is currently visible, false if not.
  bool getLayerVisibility(XpdfLayerHandle layer) const;

  //! Set the visibility state of a layer.
  //! \param layer the layer handle
  //! \param visibility the new state - true for visible, false for not
  //!        visible
  void setLayerVisibility(XpdfLayerHandle layer, bool visibility);

  //! Get the suggested state for this layer in viewing mode.
  //! This function returns one of:
  //!   -  1: on
  //!   -  0: off
  //!   - -1: unset
  int getLayerViewState(XpdfLayerHandle layer) const;

  //! Get the suggested state for this layer in printing mode.
  //! This function returns one of:
  //!   -  1: on
  //!   -  0: off
  //!   - -1: unset
  int getLayerPrintState(XpdfLayerHandle layer) const;

  //! Get the root of the layer display order tree.
  XpdfLayerOrderHandle getLayerOrderRoot() const;

  //! Check the type of a layer display order tree node.
  //! Returns true if the specified node of the layer display order
  //! tree is a name; false if the node is a layer.
  bool getLayerOrderIsName(XpdfLayerOrderHandle order) const;

  //! Get the name of a layer display order tree node.
  //! This should only be called if getLayerOrderIsName returns true.
  QString getLayerOrderName(XpdfLayerOrderHandle order) const;

  //! Get the layer associated with a layer display order tree node.
  XpdfLayerHandle getLayerOrderLayer(XpdfLayerOrderHandle order);

  //! Returns the number of children attached to a layer display order
  //! tree node.
  int getLayerOrderNumChildren(XpdfLayerOrderHandle order);

  //! Returns the \a idx 'th child of a layer display order tree node.
  XpdfLayerOrderHandle getLayerOrderChild(XpdfLayerOrderHandle order, int idx);

  //! Return the parent of a layer display order tree node.
  //! This function returns the parent of node \a order, or NULL if \a
  //! order is the root node.
  XpdfLayerOrderHandle getLayerOrderParent(XpdfLayerOrderHandle order);

  //! Return the number of embedded files in the current PDF file.
  int getNumEmbeddedFiles();

  //! Return the name of the \a idx 'th embedded file.
  QString getEmbeddedFileName(int idx);

  //! Save the \a idx 'th embedded file with the specified file name.
  //! Returns true if successful.
  bool saveEmbeddedFile(int idx, QString fileName);

  //--- for internal use

  //! \cond

  virtual QSize sizeHint() const;
  QtPDFCore *getCore() { return core; }

  //! \endcond

signals:

  //! This signal is emitted whenever the viewer displays a new page.
  //! It can be triggered by user actions (e.g., the PageDown button),
  //! or program control (e.g., the gotoNextPage function).
  //! \param pageNum - the new page number
  void pageChange(int pageNum);

  //! This signal is emitted whenever the page shown at the middle of
  //! the window changes.
  //! It is similar to XpdfWidget::pageChange, except that it reflects
  //! the page shown at the middle of the window (instead of the page
  //! at the top of the window).
  void midPageChange(int pageNum);

  //! This signal is emitted just before a PDF file is loaded.
  void preLoad();

  //! This signal is emitted just after a PDF file is loaded.
  void postLoad();

  //! This signal is emitted whenever a key is pressed.
  void keyPress(QKeyEvent *e);

  //! This signal is emitted whenever a mouse button is pressed.
  void mousePress(QMouseEvent *e);

  //! This signal is emitted whenever a mouse button is released.
  void mouseRelease(QMouseEvent *e);

  //! This signal is emitted whenever a mouse button is clicked.
  //! A click is defined as a button press and release within a short
  //! distance of each other (a few pixels).  The sequence of signals
  //! is: mousePress, possibly a few mouseMoves, mouseRelease, and
  //! then mouseClick.
  void mouseClick(QMouseEvent *e);

  //! This signal is emitted whenever a mouse button is double-clicked.
  //! Double clicks are two clicks within a few pixels of each other,
  //! and within a certain time of each other.  The sequence of
  //! signals is: mousePress, mouseRelease, mouseClick, mousePress,
  //! mouseRelease, mouseDoubleClick.  There may also be mouseMoves
  //! between the presses and releases.
  void mouseDoubleClick(QMouseEvent *e);

  //! This signal is emitted whenever a mouse button is triple-clicked.
  //! Triple clicks are three clicks within a few pixels of each
  //! other, and within a certain time of each other.  The sequence of
  //! signals is: mousePress, mouseRelease, mouseClick, mousePress,
  //! mouseRelease, mouseDoubleClick, mousePress, mouseRelease,
  //! mouseTripleClick.  There may also be mouseMoves between the
  //! presses and releases.
  void mouseTripleClick(QMouseEvent *e);

  //! This signal is emitted whenever the mouse pointer is moved.
  void mouseMove(QMouseEvent *e);

  //! This signal is emitted whenever a mouse wheel is clicked.
  void mouseWheel(QWheelEvent *e);

  //! This signal is emitted whenever the user clicks on a hyperlink.
  //! \param linkType the type of link - one of:
  //!          - \c "goto": a link to another page in the same PDF
  //!            file - \a dest is empty; \a page is the destination
  //!            page number
  //!          - \c "pdf": a link to another PDF file - \a dest is the
  //!            target PDF file; \a page is 0
  //!          - \c "launch": an arbitrary command to be run - \a dest
  //!            is the command; \a page is 0
  //!          - \c "url": a URL link - \a dest is the URL; \a page is 0
  //!          - \c "named": a "named action" link - \a dest is the
  //!            action (see the PDF spec for details); \a page is 0
  //!          - \c "unknown": an unknown link type - \a dest is empty;
  //!            \a page is 0
  //! \param dest destination string
  //! \param page destination page number
  void linkClick(const QString &linkType, const QString &dest, int page);

  //! This signal is emitted when the user selects an area.
  //! Use XpdfWidget::getCurrentSelection to retrieve the selection.
  void selectDone();

  //! This signal is emitted whenever the widget is repainted.  \a
  //! finished is true if the painted view is complete, or false if
  //! this was an incremental update, i.e., if the view is still being
  //! rendered.
  void paintDone(bool finished);

  //! This signal is emitted when the widget is resized.
  void resized();


#if XPDFWIDGET_PRINTING
  //! This signal is called before each page is spooled, and after the
  //! last page is spooled.  It is typically used to update a print
  //! status dialog.  \a nextPage is the next page to be printed.
  //! \a firstPage and \a lastPage specify the range of pages being
  //! printed.
  void printStatus(int nextPage, int firstPage, int lastPage);
#endif

  //! \cond PROTECTED

  void tileDone();

  //! \endcond

protected:

  //! \cond PROTECTED

  virtual void paintEvent(QPaintEvent *eventA);
  virtual void resizeEvent(QResizeEvent *eventA);
  virtual void scrollContentsBy(int dx, int dy);
  virtual void keyPressEvent(QKeyEvent *e);
  virtual void mousePressEvent(QMouseEvent *e);
  virtual void mouseReleaseEvent(QMouseEvent *e);
  virtual void mouseMoveEvent(QMouseEvent *e);
  virtual void wheelEvent(QWheelEvent *e);
  virtual bool eventFilter(QObject *obj, QEvent *event);

  //! \endcond

private slots:

  void tick();

private:

  void setup(const QColor &paperColor, const QColor &matteColor,
	     bool reverseVideo);
  static void updateCbk(void *data, GString *fileName,
			int pageNum, int numPages,
			const char *linkLabel);
  static void midPageChangedCbk(void *data, int pageNum);
  static void preLoadCbk(void *data);
  static void postLoadCbk(void *data);
  static void linkCbk(void *data, const char *type,
		      const char *dest, int page);
  static void selectDoneCbk(void *data);
  static void paintDoneCbk(void *data, bool finished);
  static void tileDoneCbk(void *data);

  friend class XpdfViewer;
  bool getLinkTarget(int page, double xx, double yy,
		     QString &targetFileName, int &targetPage,
		     QString &targetDest);

#if XPDFWIDGET_PRINTING
  QPrinter *printerForDialog;
  QPrintDialog *printDialog;
  int printHDPI, printVDPI;
  bool printCanceled;
#endif

  static QMutex initMutex;

  QtPDFCore *core;
  double scaleFactor;

  bool keyPassthrough;
  bool mousePassthrough;
  int lastMousePressX[3], lastMousePressY[3];
  ulong lastMousePressTime[3];
  bool lastMouseEventWasPress;

  bool touchPanEnabled;
  bool touchZoomEnabled;
  double pinchZoomStart;

  QTimer *tickTimer;
};

#endif