//======================================================================== // // XpdfWidget.cc // // Copyright 2009 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #ifdef _WIN32 #include #endif #include #include #include #include #include #include #include #include #if XPDFWIDGET_PRINTING # include # include #endif #include "gmem.h" #include "gmempp.h" #include "gfile.h" #include "GString.h" #include "GList.h" #include "SplashBitmap.h" #include "config.h" #include "GlobalParams.h" #include "PDFDoc.h" #include "Object.h" #include "SplashOutputDev.h" #include "Outline.h" #include "OptionalContent.h" #include "Link.h" #include "Annot.h" #include "AcroForm.h" #include "TextString.h" #include "QtPDFCore.h" #include "XpdfWidget.h" #if XPDFWIDGET_PRINTING # include "XpdfWidgetPrint.h" #endif //------------------------------------------------------------------------ // Time (in ms) between incremental updates. #define incrementalUpdateInterval 100 //------------------------------------------------------------------------ QMutex XpdfWidget::initMutex; //------------------------------------------------------------------------ XpdfWidget::XpdfWidget(const QColor &paperColor, const QColor &matteColor, bool reverseVideo, QWidget *parentA): QAbstractScrollArea(parentA) { setup(paperColor, matteColor, reverseVideo); } XpdfWidget::XpdfWidget(QWidget *parentA, const QColor &paperColor, const QColor &matteColor, bool reverseVideo): QAbstractScrollArea(parentA) { setup(paperColor, matteColor, reverseVideo); } void XpdfWidget::setup(const QColor &paperColor, const QColor &matteColor, bool reverseVideo) { SplashColor paperColor2, matteColor2; init(); paperColor2[0] = (Guchar)paperColor.red(); paperColor2[1] = (Guchar)paperColor.green(); paperColor2[2] = (Guchar)paperColor.blue(); matteColor2[0] = (Guchar)matteColor.red(); matteColor2[1] = (Guchar)matteColor.green(); matteColor2[2] = (Guchar)matteColor.blue(); try { core = new QtPDFCore(viewport(), horizontalScrollBar(), verticalScrollBar(), paperColor2, matteColor2, (GBool)reverseVideo); core->setUpdateCbk(updateCbk, this); core->setMidPageChangedCbk(midPageChangedCbk, this); core->setPreLoadCbk(preLoadCbk, this); core->setPostLoadCbk(postLoadCbk, this); core->setLinkCbk(linkCbk, this); core->setSelectDoneCbk(selectDoneCbk, this); core->setPaintDoneCbk(paintDoneCbk, this); core->setTileDoneCbk(tileDoneCbk, this); connect(this, SIGNAL(tileDone()), viewport(), SLOT(update())); scaleFactor = core->getScaleFactor(); } catch (GMemException e) { //~ what should this do? core = NULL; } #if XPDFWIDGET_PRINTING printerForDialog = NULL; printDialog = NULL; printHDPI = printVDPI = 0; #endif keyPassthrough = false; mousePassthrough = false; lastMousePressX[0] = lastMousePressX[1] = lastMousePressX[2] = 0; lastMousePressY[0] = lastMousePressY[1] = lastMousePressY[2] = 0; lastMousePressTime[0] = lastMousePressTime[1] = lastMousePressTime[2] = 0; lastMouseEventWasPress = false; viewport()->installEventFilter(this); touchPanEnabled = false; touchZoomEnabled = false; pinchZoomStart = 100; tickTimer = new QTimer(this); connect(tickTimer, SIGNAL(timeout()), this, SLOT(tick())); tickTimer->start(incrementalUpdateInterval); } XpdfWidget::~XpdfWidget() { #if XPDFWIDGET_PRINTING delete printerForDialog; delete printDialog; #endif delete tickTimer; delete core; } void XpdfWidget::init(const QString &configFileName) { #ifdef _WIN32 char buf[512]; GString *dir, *path; char *configFileName2; int n; #endif initMutex.lock(); if (!globalParams) { try { #ifdef _WIN32 // get the executable directory n = GetModuleFileNameA(NULL, buf, sizeof(buf)); if (n <= 0 || n >= sizeof(buf)) { // error or path too long for buffer - just use the current dir buf[0] = '\0'; } dir = grabPath(buf); // load the config file path = NULL; if (configFileName.isEmpty()) { path = appendToPath(dir->copy(), xpdfSysConfigFile); configFileName2 = path->getCString(); } else { configFileName2 = (char *)configFileName.toLocal8Bit().constData(); } globalParams = new GlobalParams(configFileName2); globalParams->setBaseDir(dir->getCString()); globalParams->setErrQuiet(gTrue); if (path) { delete path; } // set up the base fonts appendToPath(dir, "t1fonts"); globalParams->setupBaseFonts(dir->getCString()); delete dir; #else globalParams = new GlobalParams( (char *)configFileName.toLocal8Bit().constData()); globalParams->setErrQuiet(gTrue); globalParams->setupBaseFonts(NULL); #endif } catch (GMemException e) { // there's no way to return an error code here return; } } initMutex.unlock(); } void XpdfWidget::setConfig(const QString &command) { GString *fileName; init(); try { fileName = new GString("(none)"); globalParams->parseLine((char *)command.toLocal8Bit().constData(), fileName, 1); delete fileName; } catch (GMemException e) { } } void XpdfWidget::enableHyperlinks(bool on) { try { core->enableHyperlinks((GBool)on); } catch (GMemException e) { } } void XpdfWidget::enableExternalHyperlinks(bool on) { try { core->enableExternalHyperlinks((GBool)on); } catch (GMemException e) { } } void XpdfWidget::enableSelect(bool on) { try { core->enableSelect((GBool)on); } catch (GMemException e) { } } void XpdfWidget::enablePan(bool on) { try { core->enablePan((GBool)on); } catch (GMemException e) { } } void XpdfWidget::enableTouchPan(bool on) { touchPanEnabled = on; if (touchPanEnabled) { viewport()->grabGesture(Qt::PanGesture); } else { viewport()->ungrabGesture(Qt::PanGesture); } } void XpdfWidget::enableTouchZoom(bool on) { touchZoomEnabled = on; if (touchZoomEnabled) { viewport()->grabGesture(Qt::PinchGesture); } else { viewport()->ungrabGesture(Qt::PinchGesture); } } void XpdfWidget::showPasswordDialog(bool showDlg) { try { core->setShowPasswordDialog((GBool)showDlg); } catch (GMemException e) { } } void XpdfWidget::setMatteColor(const QColor &matteColor) { SplashColor matteColor2; matteColor2[0] = (Guchar)matteColor.red(); matteColor2[1] = (Guchar)matteColor.green(); matteColor2[2] = (Guchar)matteColor.blue(); try { core->setMatteColor(matteColor2); } catch (GMemException e) { } } void XpdfWidget::setReverseVideo(bool reverse) { try { core->setReverseVideo((GBool)reverse); } catch (GMemException e) { } } void XpdfWidget::setCursor(const QCursor &cursor) { core->doSetCursor(cursor); } void XpdfWidget::unsetCursor() { core->doUnsetCursor(); } XpdfWidget::ErrorCode XpdfWidget::loadFile(const QString &fileName, const QString &password) { GString *passwordStr; #ifdef _WIN32 wchar_t *fileNameStr; int n, i; #else GString *fileNameStr; #endif int err; try { if (password.isEmpty()) { passwordStr = NULL; } else { passwordStr = new GString(password.toLocal8Bit().constData()); } #ifdef _WIN32 // this should use QString::toWCharArray(), but Qt builds their // library with /Zc:wchar_t-, which confuses things n = fileName.length(); fileNameStr = (wchar_t *)gmallocn(n, sizeof(wchar_t)); for (i = 0; i < n; ++i) { fileNameStr[i] = (wchar_t)fileName[i].unicode(); } err = core->loadFile(fileNameStr, n, passwordStr, passwordStr); gfree(fileNameStr); #else fileNameStr = new GString(fileName.toLocal8Bit().constData()); err = core->loadFile(fileNameStr, passwordStr, passwordStr); delete fileNameStr; #endif if (passwordStr) { delete passwordStr; } if (!err) { core->displayPage(1, gTrue, gFalse); } return (ErrorCode)err; } catch (GMemException e) { return pdfErrOutOfMemory; } } XpdfWidget::ErrorCode XpdfWidget::loadMem(const char *buffer, unsigned int bufferLength, const QString &password) { Object obj; MemStream *stream; GString *passwordStr; int err; try { obj.initNull(); stream = new MemStream((char *)buffer, 0, bufferLength, &obj); if (password.isEmpty()) { passwordStr = NULL; } else { passwordStr = new GString(password.toLocal8Bit().constData()); } err = core->loadFile(stream, passwordStr, passwordStr); if (passwordStr) { delete passwordStr; } if (!err) { core->displayPage(1, gTrue, gFalse); } return (ErrorCode)err; } catch (GMemException e) { return pdfErrOutOfMemory; } } XpdfWidget::ErrorCode XpdfWidget::readDoc(XpdfDocHandle *docPtr, const QString &fileName, const QString &password) { GString *passwordStr; #ifdef _WIN32 wchar_t *fileNameStr; int n, i; #else GString *fileNameStr; #endif PDFDoc *doc; ErrorCode err; *docPtr = NULL; try { if (password.isEmpty()) { passwordStr = NULL; } else { passwordStr = new GString(password.toLocal8Bit().constData()); } #ifdef _WIN32 // this should use QString::toWCharArray(), but Qt builds their // library with /Zc:wchar_t-, which confuses things n = fileName.length(); fileNameStr = (wchar_t *)gmallocn(n, sizeof(wchar_t)); for (i = 0; i < n; ++i) { fileNameStr[i] = (wchar_t)fileName[i].unicode(); } doc = new PDFDoc(fileNameStr, n, passwordStr, passwordStr, core); gfree(fileNameStr); #else fileNameStr = new GString(fileName.toLocal8Bit().constData()); doc = new PDFDoc(fileNameStr, passwordStr, passwordStr, core); #endif if (passwordStr) { delete passwordStr; } if (doc->isOk()) { *docPtr = doc; err = pdfOk; } else { err = (ErrorCode)doc->getErrorCode(); delete doc; } } catch (GMemException e) { err = pdfErrOutOfMemory; } return err; } XpdfWidget::ErrorCode XpdfWidget::loadDoc(XpdfDocHandle doc) { if (!doc) { return pdfErrNoHandle; } core->loadDoc((PDFDoc *)doc); core->displayPage(1, gTrue, gFalse, gTrue); return pdfOk; } void XpdfWidget::freeDoc(XpdfDocHandle doc) { if (!doc) { return; } delete (PDFDoc *)doc; } XpdfWidget::ErrorCode XpdfWidget::reload() { try { return (ErrorCode)core->reload(); } catch (GMemException e) { return pdfErrOutOfMemory; } } void XpdfWidget::closeFile() { try { core->clear(); } catch (GMemException e) { } } XpdfWidget::ErrorCode XpdfWidget::saveAs(const QString &fileName) { GString *s; try { if (!core->getDoc()) { return pdfErrNoHandle; } s = new GString(fileName.toLocal8Bit().constData()); if (!core->getDoc()->saveAs(s)) { delete s; return pdfErrOpenFile; } delete s; return pdfOk; } catch (GMemException e) { return pdfErrOutOfMemory; } } bool XpdfWidget::hasOpenDocument() const { try { return core->getDoc() != NULL; } catch (GMemException e) { return false; } } QString XpdfWidget::getFileName() const { try { if (!core->getDoc() || !core->getDoc()->getFileName()) { return QString(); } #ifdef _WIN32 return QString::fromWCharArray(core->getDoc()->getFileNameU()); #else return QString::fromLocal8Bit(core->getDoc()->getFileName()->getCString()); #endif } catch (GMemException e) { return QString(); } } int XpdfWidget::getNumPages() const { try { if (!core->getDoc()) { return -1; } return core->getDoc()->getNumPages(); } catch (GMemException e) { return -1; } } int XpdfWidget::getCurrentPage() const { try { return core->getPageNum(); } catch (GMemException e) { return -1; } } int XpdfWidget::getMidPage() const { try { return core->getMidPageNum(); } catch (GMemException e) { return -1; } } void XpdfWidget::gotoPage(int pageNum) { try { core->displayPage(pageNum, gTrue, gFalse); } catch (GMemException e) { } } void XpdfWidget::gotoFirstPage() { try { core->displayPage(1, gTrue, gFalse); } catch (GMemException e) { } } void XpdfWidget::gotoLastPage() { try { if (!core->getDoc()) { return; } core->displayPage(core->getDoc()->getNumPages(), gTrue, gFalse); } catch (GMemException e) { } } void XpdfWidget::gotoNextPage(bool scrollToTop) { try { core->gotoNextPage(1, scrollToTop); } catch (GMemException e) { } } void XpdfWidget::gotoPreviousPage(bool scrollToTop) { try { core->gotoPrevPage(1, scrollToTop, gFalse); } catch (GMemException e) { } } bool XpdfWidget::gotoNamedDestination(const QString &dest) { GString *destStr; try { destStr = new GString(dest.toLocal8Bit().constData()); if (!core->gotoNamedDestination(destStr)) { delete destStr; return false; } delete destStr; return true; } catch (GMemException e) { return false; } } void XpdfWidget::goForward() { try { core->goForward(); } catch (GMemException e) { } } void XpdfWidget::goBackward() { try { core->goBackward(); } catch (GMemException e) { } } void XpdfWidget::scrollPageUp() { try { core->scrollPageUp(); } catch (GMemException e) { } } void XpdfWidget::scrollPageDown() { try { core->scrollPageDown(); } catch (GMemException e) { } } void XpdfWidget::scrollTo(int xx, int yy) { try { core->scrollTo(xx, yy); } catch (GMemException e) { } } void XpdfWidget::scrollBy(int dx, int dy) { try { core->scrollTo(core->getScrollX() + dx, core->getScrollY()+ dy); } catch (GMemException e) { } } int XpdfWidget::getScrollX() const { try { return core->getScrollX(); } catch (GMemException e) { return 0; } } int XpdfWidget::getScrollY() const { try { return core->getScrollY(); } catch (GMemException e) { return 0; } } void XpdfWidget::setZoom(double zoom) { try { core->setZoom(zoom); } catch (GMemException e) { } } double XpdfWidget::getZoom() const { try { return core->getZoom(); } catch (GMemException e) { return 0; } } double XpdfWidget::getZoomPercent(int page) const { double zoom; try { if (!core->getDoc() || page < 1 || page > core->getDoc()->getNumPages()) { return 0; } zoom = core->getZoom(); if (zoom <= 0) { zoom = 100 * core->getZoomDPI(page) / 72; } return zoom; } catch (GMemException e) { return 0; } } void XpdfWidget::zoomToRect(int page, double xMin, double yMin, double xMax, double yMax) { try { core->zoomToRect(page, xMin, yMin, xMax, yMax); } catch (GMemException e) { } } void XpdfWidget::zoomCentered(double zoom) { try { core->zoomCentered(zoom); } catch (GMemException e) { } } void XpdfWidget::zoomToCurrentWidth() { try { core->zoomToCurrentWidth(); } catch (GMemException e) { } } void XpdfWidget::setRotate(int rotate) { if (!(rotate == 0 || rotate == 90 || rotate == 180 || rotate == 270)) { return; } try { core->setRotate(rotate); } catch (GMemException e) { } } int XpdfWidget::getRotate() const { try { return core->getRotate(); } catch (GMemException e) { return 0; } } void XpdfWidget::setContinuousMode(bool continuous) { try { core->setDisplayMode(continuous ? displayContinuous : displaySingle); } catch (GMemException e) { } } bool XpdfWidget::getContinuousMode() const { try { return core->getDisplayMode() == displayContinuous; } catch (GMemException e) { return false; } } void XpdfWidget::setDisplayMode(XpdfWidget::DisplayMode mode) { try { core->setDisplayMode((::DisplayMode)mode); } catch (GMemException e) { } } XpdfWidget::DisplayMode XpdfWidget::getDisplayMode() { try { return (XpdfWidget::DisplayMode)core->getDisplayMode(); } catch (GMemException e) { return pdfDisplaySingle; } } bool XpdfWidget::mouseOverLink() { QPoint pt; int page; double xx, yy; try { if (core->getHyperlinksEnabled()) { return core->getLinkAction() != NULL; } else { pt = mapFromGlobal(QCursor::pos()); if (!convertWindowToPDFCoords(pt.x(), pt.y(), &page, &xx, &yy)) { return false; } return core->findLink(page, xx, yy) != NULL; } } catch (GMemException e) { return false; } } bool XpdfWidget::onLink(int page, double xx, double yy) { try { if (!core->getDoc()) { return false; } if (page < 1 || page > core->getDoc()->getNumPages()) { return false; } return core->findLink(page, xx, yy) != NULL; } catch (GMemException e) { return false; } } QString XpdfWidget::getLinkInfo(int page, double xx, double yy) { LinkAction *action; try { if (!core->getDoc()) { return QString(); } if (page < 1 || page > core->getDoc()->getNumPages()) { return QString(); } if (!(action = core->findLink(page, xx, yy))) { return QString(); } return core->getLinkInfo(action); } catch (GMemException e) { return QString(); } } QString XpdfWidget::getMouseLinkInfo() { try { if (!core->getLinkAction()) { return QString(); } return core->getLinkInfo(core->getLinkAction()); } catch (GMemException e) { return QString(); } } bool XpdfWidget::gotoLinkAt(int page, double xx, double yy) { LinkAction *action; try { if (!core->getDoc()) { return false; } if (page < 1 || page > core->getDoc()->getNumPages()) { return false; } if ((action = core->findLink(page, xx, yy))) { if (!core->doAction(action)) { return false; } } } catch (GMemException e) { } return true; } bool XpdfWidget::getLinkTarget(int page, double xx, double yy, QString &targetFileName, int &targetPage, QString &targetDest) { LinkAction *action; LinkDest *dest; GString *fileName, *namedDest, *path; Ref pageRef; char *s; try { if (!core->getDoc()) { return false; } if (page < 1 || page > core->getDoc()->getNumPages()) { return false; } if (!(action = core->findLink(page, xx, yy))) { return false; } switch (action->getKind()) { case actionGoTo: if (!core->getDoc()->getFileName()) { return false; } targetFileName = core->getDoc()->getFileName()->getCString(); if ((dest = ((LinkGoTo *)action)->getDest())) { if (dest->isPageRef()) { pageRef = dest->getPageRef(); targetPage = core->getDoc()->findPage(pageRef.num, pageRef.gen); } else { targetPage = dest->getPageNum(); } targetDest = ""; } else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) { targetDest = namedDest->getCString(); targetPage = 1; } return true; case actionGoToR: s = ((LinkGoToR *)action)->getFileName()->getCString(); if (isAbsolutePath(s)) { targetFileName = s; } else { if (!core->getDoc()->getFileName()) { return false; } path = appendToPath( grabPath(core->getDoc()->getFileName()->getCString()), s); targetFileName = path->getCString(); delete path; } if ((dest = ((LinkGoToR *)action)->getDest())) { if (dest->isPageRef()) { return false; } targetPage = dest->getPageNum(); targetDest = ""; } else if ((namedDest = ((LinkGoToR *)action)->getNamedDest())) { targetDest = namedDest->getCString(); targetPage = 1; } return true; case actionLaunch: fileName = ((LinkLaunch *)action)->getFileName(); s = fileName->getCString(); if (!(fileName->getLength() >= 4 && (!strcmp(s + fileName->getLength() - 4, ".pdf") || !strcmp(s + fileName->getLength() - 4, ".PDF")))) { return false; } if (isAbsolutePath(s)) { targetFileName = s; } else { if (!core->getDoc()->getFileName()) { return false; } path = appendToPath( grabPath(core->getDoc()->getFileName()->getCString()), s); targetFileName = path->getCString(); delete path; } targetPage = 1; targetDest = ""; return true; default: return false; } } catch (GMemException e) { return false; } } XpdfAnnotHandle XpdfWidget::onAnnot(int page, double xx, double yy) { try { if (!core->getDoc()) { return NULL; } return (XpdfAnnotHandle)core->findAnnot(page, xx, yy); } catch (GMemException e) { return NULL; } } QString XpdfWidget::getAnnotType(XpdfAnnotHandle annot) { try { return ((Annot *)annot)->getType()->getCString(); } catch (GMemException e) { return QString(); } } QString XpdfWidget::getAnnotContent(XpdfAnnotHandle annot) { QString s; Object annotObj, contentsObj; TextString *ts; Unicode *u; int i; try { if (((Annot *)annot)->getObject(&annotObj)->isDict()) { if (annotObj.dictLookup("Contents", &contentsObj)->isString()) { ts = new TextString(contentsObj.getString()); u = ts->getUnicode(); for (i = 0; i < ts->getLength(); ++i) { s.append((QChar)u[i]); } } contentsObj.free(); } annotObj.free(); return s; } catch (GMemException e) { return QString(); } } XpdfFormFieldHandle XpdfWidget::onFormField(int page, double xx, double yy) { try { if (!core->getDoc()) { return NULL; } return (XpdfFormFieldHandle)core->findFormField(page, xx, yy); } catch (GMemException e) { return NULL; } } QString XpdfWidget::getFormFieldType(XpdfFormFieldHandle field) { try { return ((AcroFormField *)field)->getType(); } catch (GMemException e) { return QString(); } } QString XpdfWidget::getFormFieldName(XpdfFormFieldHandle field) { Unicode *u; QString s; int length, i; try { u = ((AcroFormField *)field)->getName(&length); for (i = 0; i < length; ++i) { s.append((QChar)u[i]); } gfree(u); return s; } catch (GMemException e) { return QString(); } } QString XpdfWidget::getFormFieldValue(XpdfFormFieldHandle field) { Unicode *u; QString s; int length, i; try { u = ((AcroFormField *)field)->getValue(&length); for (i = 0; i < length; ++i) { s.append((QChar)u[i]); } gfree(u); return s; } catch (GMemException e) { return QString(); } } void XpdfWidget::getFormFieldBBox(XpdfFormFieldHandle field, int *pageNum, double *xMin, double *yMin, double *xMax, double *yMax) { try { *pageNum = ((AcroFormField *)field)->getPageNum(); ((AcroFormField *)field)->getBBox(xMin, yMin, xMax, yMax); } catch (GMemException e) { } } bool XpdfWidget::convertWindowToPDFCoords(int winX, int winY, int *page, double *pdfX, double *pdfY) { try { return core->cvtWindowToUser(winX, winY, page, pdfX, pdfY); } catch (GMemException e) { return false; } } void XpdfWidget::convertPDFToWindowCoords(int page, double pdfX, double pdfY, int *winX, int *winY) { try { core->cvtUserToWindow(page, pdfX, pdfY, winX, winY); } catch (GMemException e) { } } void XpdfWidget::enableRedraw(bool enable) { setUpdatesEnabled(enable); } void XpdfWidget::getPageBox(int page, const QString &box, double *xMin, double *yMin, double *xMax, double *yMax) const { PDFRectangle *r; *xMin = *yMin = *xMax = *yMax = 0; try { if (!core->getDoc()) { return; } if (page < 1 || page > core->getDoc()->getNumPages()) { return; } if (!box.compare("media", Qt::CaseInsensitive)) { r = core->getDoc()->getCatalog()->getPage(page)->getMediaBox(); } else if (!box.compare("crop", Qt::CaseInsensitive)) { r = core->getDoc()->getCatalog()->getPage(page)->getCropBox(); } else if (!box.compare("bleed", Qt::CaseInsensitive)) { r = core->getDoc()->getCatalog()->getPage(page)->getBleedBox(); } else if (!box.compare("trim", Qt::CaseInsensitive)) { r = core->getDoc()->getCatalog()->getPage(page)->getTrimBox(); } else if (!box.compare("art", Qt::CaseInsensitive)) { r = core->getDoc()->getCatalog()->getPage(page)->getArtBox(); } else { return; } *xMin = r->x1; *yMin = r->y1; *xMax = r->x2; *yMax = r->y2; } catch (GMemException e) { } } double XpdfWidget::getPageWidth(int page) const { try { if (!core->getDoc()) { return 0; } if (page < 1 || page > core->getDoc()->getNumPages()) { return 0; } return core->getDoc()->getPageCropWidth(page); } catch (GMemException e) { return 0; } } double XpdfWidget::getPageHeight(int page) const { try { if (!core->getDoc()) { return 0; } if (page < 1 || page > core->getDoc()->getNumPages()) { return 0; } return core->getDoc()->getPageCropHeight(page); } catch (GMemException e) { return 0; } } int XpdfWidget::getPageRotation(int page) const { try { if (!core->getDoc()) { return 0; } if (page < 1 || page > core->getDoc()->getNumPages()) { return 0; } return core->getDoc()->getCatalog()->getPage(page)->getRotate(); } catch (GMemException e) { return 0; } } bool XpdfWidget::hasSelection() { try { return (bool)core->hasSelection(); } catch (GMemException e) { return false; } } bool XpdfWidget::getCurrentSelection(int *page, double *x0, double *y0, double *x1, double *y1) const { try { return (bool)core->getSelection(page, x0, y0, x1, y1); } catch (GMemException e) { return false; } } void XpdfWidget::setCurrentSelection(int page, double x0, double y0, double x1, double y1) { int ulx, uly, lrx, lry, t; try { core->cvtUserToDev(page, x0, y0, &ulx, &uly); core->cvtUserToDev(page, x1, y1, &lrx, &lry); if (ulx > lrx) { t = ulx; ulx = lrx; lrx = t; } if (uly > lry) { t = uly; uly = lry; lry = t; } core->setSelection(page, ulx, uly, lrx, lry); } catch (GMemException e) { } } void XpdfWidget::clearSelection() { try { core->clearSelection(); } catch (GMemException e) { } } bool XpdfWidget::isBlockSelectMode() { try { return core->getSelectMode() == selectModeBlock; } catch (GMemException e) { return false; } } bool XpdfWidget::isLinearSelectMode() { try { return core->getSelectMode() == selectModeLinear; } catch (GMemException e) { return false; } } void XpdfWidget::setBlockSelectMode() { try { core->setSelectMode(selectModeBlock); } catch (GMemException e) { } } void XpdfWidget::setLinearSelectMode() { try { core->setSelectMode(selectModeLinear); } catch (GMemException e) { } } void XpdfWidget::setSelectionColor(const QColor &selectionColor) { SplashColor col; try { col[0] = (Guchar)selectionColor.red(); col[1] = (Guchar)selectionColor.green(); col[2] = (Guchar)selectionColor.blue(); core->setSelectionColor(col); } catch (GMemException e) { } } void XpdfWidget::forceRedraw() { try { core->forceRedraw(); } catch (GMemException e) { } } #if XPDFWIDGET_PRINTING bool XpdfWidget::okToPrint() const { try { if (!core->getDoc()) { return false; } return (bool)core->getDoc()->okToPrint(); } catch (GMemException e) { return false; } } XpdfWidget::ErrorCode XpdfWidget::print(bool showDialog) { GString *defaultPrinter; ErrorCode err; try { if (!core->getDoc()) { return pdfErrNoHandle; } if (!printerForDialog) { printerForDialog = new QPrinter(QPrinter::HighResolution); if ((defaultPrinter = globalParams->getDefaultPrinter())) { printerForDialog->setPrinterName( QString::fromUtf8(defaultPrinter->getCString())); delete defaultPrinter; } } printerForDialog->setFromTo(1, core->getDoc()->getNumPages()); if (showDialog) { if (!printDialog) { printDialog = new QPrintDialog(printerForDialog, this); } if (printDialog->exec() != QDialog::Accepted) { return pdfErrPrinting; } } printCanceled = false; err = printPDF(core->getDoc(), printerForDialog, printHDPI, printVDPI, this); return err; } catch (GMemException e) { return pdfErrOutOfMemory; } } XpdfWidget::ErrorCode XpdfWidget::print(QPrinter *prt) { try { if (!core->getDoc()) { return pdfErrNoHandle; } printCanceled = false; return printPDF(core->getDoc(), prt, printHDPI, printVDPI, this); } catch (GMemException e) { return pdfErrOutOfMemory; } } void XpdfWidget::updatePrintStatus(int nextPage, int firstPage, int lastPage) { emit printStatus(nextPage, firstPage, lastPage); } void XpdfWidget::setPrintDPI(int hDPI, int vDPI) { printHDPI = hDPI; printVDPI = vDPI; } #endif // XPDFWIDGET_PRINTING QImage XpdfWidget::convertPageToImage(int page, double dpi, bool transparent) { try { PDFDoc *doc = core->getDoc(); if (!doc) { return QImage(); } if (page < 1 || page > doc->getNumPages()) { return QImage(); } if (transparent) { SplashColor paperColor; paperColor[0] = paperColor[1] = paperColor[2] = 0xff; // unused SplashOutputDev *out = new SplashOutputDev(splashModeRGB8, 1, gFalse, paperColor); out->setNoComposite(gTrue); out->startDoc(doc->getXRef()); doc->displayPage(out, page, dpi, dpi, core->getRotate(), gFalse, gTrue, gFalse); SplashBitmap *bitmap = out->getBitmap(); QImage img(bitmap->getWidth(), bitmap->getHeight(), QImage::Format_ARGB32); Guchar *pix = bitmap->getDataPtr(); Guchar *alpha = bitmap->getAlphaPtr(); Guint *argb = (Guint *)img.bits(); for (int y = 0; y < bitmap->getHeight(); ++y) { for (int x = 0; x < bitmap->getWidth(); ++x) { *argb = (*alpha << 24) | (pix[0] << 16) | (pix[1] << 8) | pix[2]; pix += 3; ++alpha; ++argb; } } delete out; return img; } else { SplashColor paperColor; paperColor[0] = paperColor[1] = paperColor[2] = 0xff; SplashOutputDev *out = new SplashOutputDev(splashModeRGB8, 4, gFalse, paperColor); out->startDoc(doc->getXRef()); doc->displayPage(out, page, dpi, dpi, core->getRotate(), gFalse, gTrue, gFalse); SplashBitmap *bitmap = out->getBitmap(); QImage *img = new QImage((const uchar *)bitmap->getDataPtr(), bitmap->getWidth(), bitmap->getHeight(), QImage::Format_RGB888); // force a copy QImage img2(img->copy()); delete img; delete out; return img2; } } catch (GMemException e) { return QImage(); } } QImage XpdfWidget::convertRegionToImage(int page, double x0, double y0, double x1, double y1, double dpi, bool transparent) { try { PDFDoc *doc = core->getDoc(); if (!doc) { return QImage(); } if (page < 1 || page > doc->getNumPages()) { return QImage(); } if (x0 > x1) { double t = x0; x0 = x1; x1 = t; } if (y0 > y1) { double t = y0; y0 = y1; y1 = t; } PDFRectangle *box = doc->getCatalog()->getPage(page)->getCropBox(); int rot = doc->getPageRotate(page); double k = dpi / 72.0; int sliceX, sliceY, sliceW, sliceH; if (rot == 90) { sliceX = (int)(k * (y0 - box->y1)); sliceY = (int)(k * (x0 - box->x1)); sliceW = (int)(k * (y1 - y0)); sliceH = (int)(k * (x1 - x0)); } else if (rot == 180) { sliceX = (int)(k * (box->x2 - x1)); sliceY = (int)(k * (y0 - box->y1)); sliceW = (int)(k * (x1 - x0)); sliceH = (int)(k * (y1 - y0)); } else if (rot == 270) { sliceX = (int)(k * (box->y2 - y1)); sliceY = (int)(k * (box->x2 - x1)); sliceW = (int)(k * (y1 - y0)); sliceH = (int)(k * (x1 - x0)); } else { sliceX = (int)(k * (x0 - box->x1)); sliceY = (int)(k * (box->y2 - y1)); sliceW = (int)(k * (x1 - x0)); sliceH = (int)(k * (y1 - y0)); } if (transparent) { SplashColor paperColor; paperColor[0] = paperColor[1] = paperColor[2] = 0xff; // unused SplashOutputDev *out = new SplashOutputDev(splashModeRGB8, 1, gFalse, paperColor); out->setNoComposite(gTrue); out->startDoc(doc->getXRef()); doc->displayPageSlice(out, page, dpi, dpi, core->getRotate(), gFalse, gTrue, gFalse, sliceX, sliceY, sliceW, sliceH); SplashBitmap *bitmap = out->getBitmap(); QImage img(bitmap->getWidth(), bitmap->getHeight(), QImage::Format_ARGB32); Guchar *pix = bitmap->getDataPtr(); Guchar *alpha = bitmap->getAlphaPtr(); Guint *argb = (Guint *)img.bits(); for (int y = 0; y < bitmap->getHeight(); ++y) { for (int x = 0; x < bitmap->getWidth(); ++x) { *argb = (*alpha << 24) | (pix[0] << 16) | (pix[1] << 8) | pix[2]; pix += 3; ++alpha; ++argb; } } delete out; return img; } else { SplashColor paperColor; paperColor[0] = paperColor[1] = paperColor[2] = 0xff; SplashOutputDev *out = new SplashOutputDev(splashModeRGB8, 4, gFalse, paperColor); out->startDoc(doc->getXRef()); doc->displayPageSlice(out, page, dpi, dpi, core->getRotate(), gFalse, gTrue, gFalse, sliceX, sliceY, sliceW, sliceH); SplashBitmap *bitmap = out->getBitmap(); QImage *img = new QImage((const uchar *)bitmap->getDataPtr(), bitmap->getWidth(), bitmap->getHeight(), QImage::Format_RGB888); // force a copy QImage img2(img->copy()); delete img; delete out; return img2; } } catch (GMemException e) { return QImage(); } } QImage XpdfWidget::getThumbnail(int page) { Object thumbObj, decodeObj, colorSpaceObj, obj; Dict *thumbDict; GfxColorSpace *colorSpace; GfxImageColorMap *colorMap; ImageStream *imgStream; Guchar *line, *rgb; int w, h, bpc, yy; try { if (!core->getDoc()) { return QImage(); } if (page < 1 || page > core->getDoc()->getNumPages()) { return QImage(); } // get the thumbnail image object if (!core->getDoc()->getCatalog()->getPage(page) ->getThumbnail(&thumbObj)->isStream()) { thumbObj.free(); return QImage(); } // get the image parameters thumbDict = thumbObj.streamGetDict(); if (!thumbDict->lookup("Width", &obj)->isInt()) { obj.free(); thumbObj.free(); return QImage(); } w = obj.getInt(); obj.free(); if (!thumbDict->lookup("Height", &obj)->isInt()) { obj.free(); thumbObj.free(); return QImage(); } h = obj.getInt(); obj.free(); if (!thumbDict->lookup("BitsPerComponent", &obj)->isInt()) { obj.free(); thumbObj.free(); return QImage(); } bpc = obj.getInt(); obj.free(); // create the color space and color map thumbDict->lookup("Decode", &decodeObj); thumbDict->lookup("ColorSpace", &colorSpaceObj); colorSpace = GfxColorSpace::parse(&colorSpaceObj ); colorMap = new GfxImageColorMap(bpc, &decodeObj, colorSpace); colorSpaceObj.free(); decodeObj.free(); imgStream = new ImageStream(thumbObj.getStream(), w, colorSpace->getNComps(), bpc); // create the QImage, and read the image data QImage img(w, h, QImage::Format_RGB888); rgb = (Guchar *)gmallocn(w, 3); imgStream->reset(); for (yy = 0; yy < h; ++yy) { line = imgStream->getLine(); colorMap->getRGBByteLine(line, rgb, w, gfxRenderingIntentPerceptual); memcpy(img.scanLine(yy), rgb, 3 * w); } gfree(rgb); delete colorMap; delete imgStream; thumbObj.free(); return img; } catch (GMemException e) { return QImage(); } } bool XpdfWidget::okToExtractText() const { try { if (!core->getDoc()) { return false; } return (bool)core->getDoc()->okToCopy(); } catch (GMemException e) { return false; } } void XpdfWidget::setTextEncoding(const QString &encodingName) { init(); try { globalParams->setTextEncoding((char *)encodingName.toLatin1().constData()); } catch (GMemException e) { } } QString XpdfWidget::extractText(int page, double x0, double y0, double x1, double y1) { GString *s, *enc; GBool twoByte; QString ret; int i; try { if (!core->getDoc()) { return QString(); } if (!(s = core->extractText(page, x0, y0, x1, y1))) { return QString(); } enc = globalParams->getTextEncodingName(); twoByte = !enc->cmp("UCS-2"); delete enc; if (twoByte) { for (i = 0; i+1 < s->getLength(); i += 2) { ret.append((QChar)(((s->getChar(i) & 0xff) << 8) + (s->getChar(i+1) & 0xff))); } } else { ret.append(s->getCString()); } delete s; return ret; } catch (GMemException e) { return QString(); } } QString XpdfWidget::getSelectedText() { try { return core->getSelectedTextQString(); } catch (GMemException e) { return ""; } } void XpdfWidget::copySelection() { try { core->copySelection(gTrue); } catch (GMemException e) { } } bool XpdfWidget::find(const QString &text, int flags) { Unicode *u; bool ret; int len, i; try { if (!core->getDoc()) { return false; } len = text.length(); u = (Unicode *)gmallocn(len, sizeof(Unicode)); for (i = 0; i < len; ++i) { u[i] = (Unicode)text[i].unicode(); } ret = (bool)core->findU(u, len, (flags & findCaseSensitive) ? gTrue : gFalse, (flags & findNext) ? gTrue : gFalse, (flags & findBackward) ? gTrue : gFalse, (flags & findWholeWord) ? gTrue : gFalse, (flags & findOnePageOnly) ? gTrue : gFalse); gfree(u); return ret; } catch (GMemException e) { return false; } } QVector XpdfWidget::findAll(const QString &text, int firstPage, int lastPage, int flags) { QVector v; try { if (!core->getDoc()) { return v; } int len = text.length(); Unicode *u = (Unicode *)gmallocn(len, sizeof(Unicode)); for (int i = 0; i < len; ++i) { u[i] = (Unicode)text[i].unicode(); } GList *results = core->findAll(u, len, (flags & findCaseSensitive) ? gTrue : gFalse, (flags & findWholeWord) ? gTrue : gFalse, firstPage, lastPage); gfree(u); for (int i = 0; i < results->getLength(); ++i) { FindResult *result = (FindResult *)results->get(i); v.append(XpdfFindResult(result->page, result->xMin, result->yMin, result->xMax, result->yMax)); } deleteGList(results, FindResult); return v; } catch (GMemException e) { return v; } } bool XpdfWidget::hasPageLabels() { try { if (!core->getDoc()) { return false; } return core->getDoc()->getCatalog()->hasPageLabels(); } catch (GMemException e) { return false; } } QString XpdfWidget::getPageLabelFromPageNum(int pageNum) { try { if (!core->getDoc()) { return QString(); } TextString *ts = core->getDoc()->getCatalog()->getPageLabel(pageNum); if (!ts) { return QString(); } QString qs; Unicode *u = ts->getUnicode(); for (int i = 0; i < ts->getLength(); ++i) { qs.append((QChar)u[i]); } delete ts; return qs; } catch (GMemException e) { return QString(); } } int XpdfWidget::getPageNumFromPageLabel(QString pageLabel) { try { if (!core->getDoc()) { return -1; } TextString *ts = new TextString(); for (int i = 0; i < pageLabel.size(); ++i) { ts->append((Unicode)pageLabel.at(i).unicode()); } int pg = core->getDoc()->getCatalog()->getPageNumFromPageLabel(ts); delete ts; return pg; } catch (GMemException e) { return -1; } } int XpdfWidget::getOutlineNumChildren(XpdfOutlineHandle outline) { GList *items; try { if (!core->getDoc()) { return 0; } if (outline) { ((OutlineItem *)outline)->open(); items = ((OutlineItem *)outline)->getKids(); } else { items = core->getDoc()->getOutline()->getItems(); } if (!items) { return 0; } return items->getLength(); } catch (GMemException e) { return 0; } } XpdfOutlineHandle XpdfWidget::getOutlineChild(XpdfOutlineHandle outline, int idx) { GList *items; try { if (!core->getDoc()) { return NULL; } if (outline) { ((OutlineItem *)outline)->open(); items = ((OutlineItem *)outline)->getKids(); } else { items = core->getDoc()->getOutline()->getItems(); } if (!items) { return NULL; } if (idx < 0 || idx >= items->getLength()) { return NULL; } return (XpdfOutlineHandle)items->get(idx); } catch (GMemException e) { return NULL; } } XpdfOutlineHandle XpdfWidget::getOutlineParent(XpdfOutlineHandle outline) { if (!outline) { return NULL; } return (XpdfOutlineHandle)((OutlineItem *)outline)->getParent(); } QString XpdfWidget::getOutlineTitle(XpdfOutlineHandle outline) { Unicode *title; QString s; int titleLen, i; if (!outline) { return QString(); } try { title = ((OutlineItem *)outline)->getTitle(); titleLen = ((OutlineItem *)outline)->getTitleLength(); for (i = 0; i < titleLen; ++i) { s.append((QChar)title[i]); } return s; } catch (GMemException e) { return QString(); } } bool XpdfWidget::getOutlineStartsOpen(XpdfOutlineHandle outline) { if (!outline) { return false; } try { return (bool)((OutlineItem *)outline)->isOpen(); } catch (GMemException e) { return false; } } int XpdfWidget::getOutlineTargetPage(XpdfOutlineHandle outline) { try { if (!outline || !core->getDoc()) { return 0; } return core->getDoc()->getOutlineTargetPage((OutlineItem *)outline); } catch (GMemException e) { return 0; } } void XpdfWidget::gotoOutlineTarget(XpdfOutlineHandle outline) { if (!outline) { return; } try { if (((OutlineItem *)outline)->getAction()) { core->doAction(((OutlineItem *)outline)->getAction()); } } catch (GMemException e) { } } int XpdfWidget::getNumLayers() const { try { if (!core->getDoc()) { return 0; } return core->getDoc()->getOptionalContent()->getNumOCGs(); } catch (GMemException e) { return 0; } } XpdfLayerHandle XpdfWidget::getLayer(int idx) const { try { if (!core->getDoc() || idx < 0 || idx >= core->getDoc()->getOptionalContent()->getNumOCGs()) { return NULL; } return (XpdfLayerHandle)core->getDoc()->getOptionalContent()->getOCG(idx); } catch (GMemException e) { return NULL; } } QString XpdfWidget::getLayerName(XpdfLayerHandle layer) const { Unicode *name; QString s; int nameLen, i; if (!layer) { return QString(); } try { name = ((OptionalContentGroup *)layer)->getName(); nameLen = ((OptionalContentGroup *)layer)->getNameLength(); for (i = 0; i < nameLen; ++i) { s.append((QChar)name[i]); } return s; } catch (GMemException e) { return QString(); } } bool XpdfWidget::getLayerVisibility(XpdfLayerHandle layer) const { if (!layer) { return false; } try { return (bool)((OptionalContentGroup *)layer)->getState(); } catch (GMemException e) { return false; } } void XpdfWidget::setLayerVisibility(XpdfLayerHandle layer, bool visibility) { try { if (!core->getDoc() || !layer) { return; } core->setOCGState(((OptionalContentGroup *)layer), (GBool)visibility); } catch (GMemException e) { return; } } int XpdfWidget::getLayerViewState(XpdfLayerHandle layer) const { int s; if (!layer) { return 0; } try { s = ((OptionalContentGroup *)layer)->getViewState(); return (s == ocUsageOn) ? 1 : (s == ocUsageOff) ? 0 : -1; } catch (GMemException e) { return 0; } } int XpdfWidget::getLayerPrintState(XpdfLayerHandle layer) const { int s; if (!layer) { return 0; } try { s = ((OptionalContentGroup *)layer)->getPrintState(); return (s == ocUsageOn) ? 1 : (s == ocUsageOff) ? 0 : -1; } catch (GMemException e) { return 0; } } XpdfLayerOrderHandle XpdfWidget::getLayerOrderRoot() const { try { if (!core->getDoc()) { return NULL; } return (XpdfLayerOrderHandle) core->getDoc()->getOptionalContent()->getDisplayRoot(); } catch (GMemException e) { return NULL; } } bool XpdfWidget::getLayerOrderIsName(XpdfLayerOrderHandle order) const { if (!order) { return false; } try { return ((OCDisplayNode *)order)->getOCG() == NULL; } catch (GMemException e) { return false; } } QString XpdfWidget::getLayerOrderName(XpdfLayerOrderHandle order) const { Unicode *name; QString s; int nameLen, i; if (!order) { return QString(); } try { name = ((OCDisplayNode *)order)->getName(); nameLen = ((OCDisplayNode *)order)->getNameLength(); for (i = 0; i < nameLen; ++i) { s.append((QChar)name[i]); } return s; } catch (GMemException e) { return QString(); } } XpdfLayerHandle XpdfWidget::getLayerOrderLayer(XpdfLayerOrderHandle order) { if (!order) { return NULL; } try { return (XpdfLayerHandle)((OCDisplayNode *)order)->getOCG(); } catch (GMemException e) { return NULL; } } int XpdfWidget::getLayerOrderNumChildren(XpdfLayerOrderHandle order) { if (!order) { return 0; } try { return ((OCDisplayNode *)order)->getNumChildren(); } catch (GMemException e) { return 0; } } XpdfLayerOrderHandle XpdfWidget::getLayerOrderChild(XpdfLayerOrderHandle order, int idx) { if (!order) { return NULL; } try { if (idx < 0 || idx >= ((OCDisplayNode *)order)->getNumChildren()) { return NULL; } return (XpdfLayerOrderHandle)((OCDisplayNode *)order)->getChild(idx); } catch (GMemException e) { return NULL; } } XpdfLayerOrderHandle XpdfWidget::getLayerOrderParent( XpdfLayerOrderHandle order) { if (!order) { return NULL; } try { return (XpdfLayerOrderHandle)((OCDisplayNode *)order)->getParent(); } catch (GMemException e) { return NULL; } } int XpdfWidget::getNumEmbeddedFiles() { try { if (!core->getDoc()) { return 0; } return core->getDoc()->getNumEmbeddedFiles(); } catch (GMemException e) { return 0; } } QString XpdfWidget::getEmbeddedFileName(int idx) { Unicode *name; QString s; int nameLen, i; try { if (!core->getDoc() || idx < 0 || idx >= core->getDoc()->getNumEmbeddedFiles()) { return ""; } name = core->getDoc()->getEmbeddedFileName(idx); nameLen = core->getDoc()->getEmbeddedFileNameLength(idx); for (i = 0; i < nameLen; ++i) { s.append((QChar)name[i]); } return s; } catch (GMemException e) { return 0; } } bool XpdfWidget::saveEmbeddedFile(int idx, QString fileName) { try { if (!core->getDoc() || idx < 0 || idx >= core->getDoc()->getNumEmbeddedFiles()) { return false; } return core->getDoc()->saveEmbeddedFile( idx, fileName.toLocal8Bit().constData()); } catch (GMemException e) { return false; } } QSize XpdfWidget::sizeHint() const { try { return core->getBestSize(); } catch (GMemException e) { } return QSize(612, 792); } //------------------------------------------------------------------------ // callbacks from QtPDFCore //------------------------------------------------------------------------ void XpdfWidget::updateCbk(void *data, GString *fileName, int pageNum, int numPages, const char *linkLabel) { XpdfWidget *xpdf = (XpdfWidget *)data; if (fileName) { if (pageNum >= 0) { emit xpdf->pageChange(pageNum); } } } void XpdfWidget::midPageChangedCbk(void *data, int pageNum) { XpdfWidget *xpdf = (XpdfWidget *)data; emit xpdf->midPageChange(pageNum); } void XpdfWidget::preLoadCbk(void *data) { XpdfWidget *xpdf = (XpdfWidget *)data; emit xpdf->preLoad(); } void XpdfWidget::postLoadCbk(void *data) { XpdfWidget *xpdf = (XpdfWidget *)data; emit xpdf->postLoad(); } void XpdfWidget::linkCbk(void *data, const char *type, const char *dest, int page) { XpdfWidget *xpdf = (XpdfWidget *)data; emit xpdf->linkClick(type, dest, page); } void XpdfWidget::selectDoneCbk(void *data) { XpdfWidget *xpdf = (XpdfWidget *)data; emit xpdf->selectDone(); } void XpdfWidget::paintDoneCbk(void *data, bool finished) { XpdfWidget *xpdf = (XpdfWidget *)data; emit xpdf->paintDone(finished); } // NB: this function is called on a worker thread. void XpdfWidget::tileDoneCbk(void *data) { XpdfWidget *xpdf = (XpdfWidget *)data; emit xpdf->tileDone(); } //------------------------------------------------------------------------ // events from the QAbstractScrollArea //------------------------------------------------------------------------ void XpdfWidget::paintEvent(QPaintEvent *eventA) { core->paintEvent(eventA->rect().left(), eventA->rect().top(), eventA->rect().width(), eventA->rect().height()); } void XpdfWidget::resizeEvent(QResizeEvent *eventA) { core->resizeEvent(); emit resized(); } void XpdfWidget::scrollContentsBy(int dx, int dy) { core->scrollEvent(); } void XpdfWidget::keyPressEvent(QKeyEvent *e) { int key; if (!keyPassthrough) { key = e->key(); if (key == Qt::Key_Left) { core->scrollLeft(); return; } else if (key == Qt::Key_Right) { core->scrollRight(); return; } else if (key == Qt::Key_Up) { core->scrollUp(); return; } else if (key == Qt::Key_Down) { core->scrollDown(); return; } else if (key == Qt::Key_PageUp) { core->scrollPageUp(); return; } else if (key == Qt::Key_PageDown || key == Qt::Key_Space) { core->scrollPageDown(); return; } } emit keyPress(e); } void XpdfWidget::mousePressEvent(QMouseEvent *e) { int x, y; lastMousePressX[0] = lastMousePressX[1]; lastMousePressY[0] = lastMousePressY[1]; lastMousePressTime[0] = lastMousePressTime[1]; lastMousePressX[1] = lastMousePressX[2]; lastMousePressY[1] = lastMousePressY[2]; lastMousePressTime[1] = lastMousePressTime[2]; lastMousePressX[2] = e->pos().x(); lastMousePressY[2] = e->pos().y(); lastMousePressTime[2] = e->timestamp(); lastMouseEventWasPress = true; if (!mousePassthrough) { x = (int)(e->pos().x() * scaleFactor); y = (int)(e->pos().y() * scaleFactor); if (e->button() == Qt::LeftButton) { core->startSelection(x, y, e->modifiers() & Qt::ShiftModifier); } else if (e->button() == Qt::MiddleButton) { core->startPan(x, y); } } emit mousePress(e); } void XpdfWidget::mouseReleaseEvent(QMouseEvent *e) { int x, y; // some versions of Qt drop mouse press events in double-clicks (?) if (!lastMouseEventWasPress) { mousePressEvent(e); } lastMouseEventWasPress = false; x = y = 0; if (!mousePassthrough) { x = (int)(e->pos().x() * scaleFactor); y = (int)(e->pos().y() * scaleFactor); if (e->button() == Qt::LeftButton) { core->endSelection(x, y); } else if (e->button() == Qt::MiddleButton) { core->endPan(x, y); } } emit mouseRelease(e); // double and triple clicks have to be "quick" and "nearby"; // single clicks just have to be "nearby" ulong maxTime = (ulong)QApplication::doubleClickInterval(); int maxDistance = QApplication::startDragDistance(); if (e->timestamp() - lastMousePressTime[0] < 2 * maxTime && abs(e->pos().x() - lastMousePressX[0]) + abs(e->pos().y() - lastMousePressY[0]) <= maxDistance) { if (!mousePassthrough && e->button() == Qt::LeftButton) { core->selectLine(x, y); } emit mouseTripleClick(e); } else if (e->timestamp() - lastMousePressTime[1] < maxTime && abs(e->pos().x() - lastMousePressX[1]) + abs(e->pos().y() - lastMousePressY[1]) <= maxDistance) { if (!mousePassthrough && e->button() == Qt::LeftButton) { core->selectWord(x, y); } emit mouseDoubleClick(e); } else if (abs(e->pos().x() - lastMousePressX[2]) + abs(e->pos().y() - lastMousePressY[2]) <= maxDistance) { emit mouseClick(e); } } void XpdfWidget::mouseMoveEvent(QMouseEvent *e) { int x, y; x = (int)(e->pos().x() * scaleFactor); y = (int)(e->pos().y() * scaleFactor); core->mouseMove(x, y); emit mouseMove(e); } void XpdfWidget::wheelEvent(QWheelEvent *e) { if (!mousePassthrough) { QAbstractScrollArea::wheelEvent(e); } emit mouseWheel(e); } bool XpdfWidget::eventFilter(QObject *obj, QEvent *event) { QGestureEvent *gestureEvent; QPanGesture *panGesture; QPinchGesture *pinchGesture; double z; if (obj == viewport() && event->type() == QEvent::Gesture) { gestureEvent = (QGestureEvent *)event; if (touchPanEnabled && (panGesture = (QPanGesture *)gestureEvent->gesture(Qt::PanGesture))) { core->scrollTo(core->getScrollX() - (int)panGesture->delta().x(), core->getScrollY() - (int)panGesture->delta().y()); gestureEvent->accept(); return true; } else if (touchZoomEnabled && (pinchGesture = (QPinchGesture *)gestureEvent->gesture(Qt::PinchGesture))) { if (pinchGesture->changeFlags() & QPinchGesture::ScaleFactorChanged) { if (pinchGesture->state() == Qt::GestureStarted) { pinchZoomStart = getZoomPercent(core->getMidPageNum()); } else { z = pinchZoomStart * pinchGesture->totalScaleFactor(); if (z < 10) { z = 10; } else if (z > 800) { z = 800; } core->zoomCentered(z); } } gestureEvent->accept(); return true; } } return QAbstractScrollArea::eventFilter(obj, event); } void XpdfWidget::tick() { core->tick(); }