diff options
author | Ken Moore <ken@ixsystems.com> | 2018-03-20 13:26:15 -0400 |
---|---|---|
committer | Ken Moore <ken@ixsystems.com> | 2018-03-20 13:26:15 -0400 |
commit | e8a1a0cd0fd113960d8199799e7c8b2e5194e9eb (patch) | |
tree | 02ca053195c87f97bfb1c2903d31d4f762e63ffd /src-qt5/desktop-utils/lumina-pdf | |
parent | Quick checkpoint on the new NativeWindow class (Widgets). (diff) | |
parent | Disabled Properties, Find, and Bookmarks for Poppler but enabled by default f... (diff) | |
download | lumina-e8a1a0cd0fd113960d8199799e7c8b2e5194e9eb.tar.gz lumina-e8a1a0cd0fd113960d8199799e7c8b2e5194e9eb.tar.bz2 lumina-e8a1a0cd0fd113960d8199799e7c8b2e5194e9eb.zip |
Merge branch 'master' of github.com:trueos/lumina
Diffstat (limited to 'src-qt5/desktop-utils/lumina-pdf')
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/PresentationLabel.h | 18 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp | 391 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/PrintWidget.h | 227 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp | 278 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp | 90 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/Renderer.h | 66 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/mainUI.cpp | 103 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/mainUI.h | 131 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/propDialog.cpp | 3 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/propDialog.h | 5 | ||||
-rw-r--r-- | src-qt5/desktop-utils/lumina-pdf/textData.h | 44 |
11 files changed, 740 insertions, 616 deletions
diff --git a/src-qt5/desktop-utils/lumina-pdf/PresentationLabel.h b/src-qt5/desktop-utils/lumina-pdf/PresentationLabel.h index c5b552a6..e838c46a 100644 --- a/src-qt5/desktop-utils/lumina-pdf/PresentationLabel.h +++ b/src-qt5/desktop-utils/lumina-pdf/PresentationLabel.h @@ -15,21 +15,21 @@ #include <QDebug> class PresentationLabel : public QLabel{ - Q_OBJECT + Q_OBJECT signals: - void nextSlide(); + void nextSlide(); public: - PresentationLabel() : QLabel(0, Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint){ - this->setContextMenuPolicy(Qt::CustomContextMenu); - } + PresentationLabel() : QLabel(0, Qt::Window | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint){ + this->setContextMenuPolicy(Qt::CustomContextMenu); + } protected: - void mousePressEvent(QMouseEvent *ev){ - QLabel::mousePressEvent(ev); - if(ev->button()==Qt::LeftButton){ emit nextSlide(); } - } + void mousePressEvent(QMouseEvent *ev){ + QLabel::mousePressEvent(ev); + if(ev->button()==Qt::LeftButton){ emit nextSlide(); } + } }; #endif diff --git a/src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp b/src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp index 5c7fa1dd..7c0fd323 100644 --- a/src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp +++ b/src-qt5/desktop-utils/lumina-pdf/PrintWidget.cpp @@ -1,7 +1,8 @@ #include "PrintWidget.h" -PrintWidget::PrintWidget(QWidget *parent) : QGraphicsView(parent), scene(0), curPage(1), - viewMode(SinglePageView), zoomMode(FitInView), zoomFactor(1), initialized(false), fitting(true) { +PrintWidget::PrintWidget(Renderer *backend, QWidget *parent) : + QGraphicsView(parent), scene(0), curPage(1), viewMode(SinglePageView), + zoomMode(FitInView), zoomFactor(1), initialized(false), fitting(true), BACKEND(backend) { this->setMouseTracking(true); QList<QWidget*> children = this->findChildren<QWidget*>("",Qt::FindChildrenRecursively); @@ -9,24 +10,22 @@ PrintWidget::PrintWidget(QWidget *parent) : QGraphicsView(parent), scene(0), cur children[i]->setContextMenuPolicy(Qt::CustomContextMenu); connect(children[i], SIGNAL(customContextMenuRequested(const QPoint&)), this, SIGNAL(customContextMenuRequested(const QPoint&)) ); } - this->setInteractive(false); - this->setDragMode(QGraphicsView::ScrollHandDrag); - this->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); + this->setInteractive(false); + this->setDragMode(QGraphicsView::ScrollHandDrag); + this->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate); this->setFocusPolicy(Qt::NoFocus); - QObject::connect(this->verticalScrollBar(), SIGNAL(valueChanged(int)), - this, SLOT(updateCurrentPage())); - QObject::connect(this, SIGNAL(resized()), this, SLOT(fit())); - - scene = new QGraphicsScene(this); - scene->setBackgroundBrush(Qt::gray); - this->setScene(scene); - this->degrees = 0; - this->rotMatrix = QMatrix(1, 0, 0, 1, 0 ,0); - - /*QVBoxLayout *layout = new QVBoxLayout; - setLayout(layout); - layout->setContentsMargins(0, 0, 0, 0); - layout->addWidget(this);*/ + QObject::connect(this->verticalScrollBar(), SIGNAL(valueChanged(int)), + this, SLOT(updateCurrentPage())); + QObject::connect(this, SIGNAL(resized()), this, SLOT(fit())); + + scene = new QGraphicsScene(this); + scene->setBackgroundBrush(Qt::gray); + this->setScene(scene); + + /*QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(this);*/ } PrintWidget::~PrintWidget() { @@ -48,8 +47,8 @@ void PrintWidget::fitToWidth() { void PrintWidget::setZoomMode(ZoomMode mode) { zoomMode = mode; - fitting = true; - fit(true); + fitting = true; + fit(true); } void PrintWidget::setAllPagesViewMode() { @@ -65,31 +64,31 @@ void PrintWidget::setFacingPagesViewMode() { } void PrintWidget::setViewMode(ViewMode mode) { - viewMode = mode; - layoutPages(); - if (viewMode == AllPagesView) { - this->fitInView(scene->itemsBoundingRect(), Qt::KeepAspectRatio); - fitting = false; - zoomMode = CustomZoom; - //zoomFactor = this->transform().m11() * (double(printer->logicalDpiY()) / logicalDpiY()); - } else { - fitting = true; - fit(); - } + viewMode = mode; + layoutPages(); + if (viewMode == AllPagesView) { + this->fitInView(scene->itemsBoundingRect(), Qt::KeepAspectRatio); + fitting = false; + zoomMode = CustomZoom; + //zoomFactor = this->transform().m11() * (double(printer->logicalDpiY()) / logicalDpiY()); + } else { + fitting = true; + fit(); + } } void PrintWidget::zoomIn(double factor) { - fitting = false; - zoomMode = CustomZoom; - zoomFactor *= factor; - this->scale(factor, factor); + fitting = false; + zoomMode = CustomZoom; + zoomFactor *= factor; + this->scale(factor, factor); } void PrintWidget::zoomOut(double factor) { - fitting = false; - zoomMode = CustomZoom; - zoomFactor *= factor; - this->scale(1/factor, 1/factor); + fitting = false; + zoomMode = CustomZoom; + zoomFactor *= factor; + this->scale(1/factor, 1/factor); } void PrintWidget::updatePreview() { @@ -99,43 +98,63 @@ void PrintWidget::updatePreview() { } void PrintWidget::setVisible(bool visible) { - if(visible and !initialized) - updatePreview(); - QGraphicsView::setVisible(visible); + if(visible and !initialized) + updatePreview(); + QGraphicsView::setVisible(visible); } void PrintWidget::setCurrentPage(int pageNumber) { - if(pageNumber < 0 || pageNumber > (pages.count()+1) ){ return; } - publicPageNum = pageNumber; //publicly requested page number (+/- 1 from actual page range) - emit currentPageChanged(); - if(pageNumber < 1 || pageNumber > pages.count()) - return; - int lastPage = curPage; - curPage = pageNumber; - - if (lastPage != curPage && lastPage > 0 && lastPage <= pages.count()) { - if (zoomMode != FitInView) { - QScrollBar *hsc = this->horizontalScrollBar(); - QScrollBar *vsc = this->verticalScrollBar(); - QPointF pt = this->transform().map(pages.at(curPage-1)->pos()); - vsc->setValue(int(pt.y()) - 10); - hsc->setValue(int(pt.x()) - 10); - } else { - this->centerOn(pages.at(curPage-1)); - } - } + if(pageNumber < 0 || pageNumber > (pages.count()+1) ){ return; } + publicPageNum = pageNumber; //publicly requested page number (+/- 1 from actual page range) + emit currentPageChanged(); + if(pageNumber < 1 || pageNumber > pages.count()) + return; + int lastPage = curPage; + curPage = pageNumber; + + if (lastPage != curPage && lastPage > 0 && lastPage <= pages.count()) { + if (zoomMode != FitInView) { + QScrollBar *hsc = this->horizontalScrollBar(); + QScrollBar *vsc = this->verticalScrollBar(); + QPointF pt = this->transform().map(pages.at(curPage-1)->pos()); + vsc->setValue(int(pt.y()) - 10); + hsc->setValue(int(pt.x()) - 10); + } else { + this->centerOn(pages.at(curPage-1)); + } + } } void PrintWidget::highlightText(TextData *text) { //Creates a rectangle around the text if the text has not already been highlighted if(!text->highlighted()) { - //qDebug() << "Highlighting text: " << text->text() << "At page: " << text->page(); - QRect rect = text->loc(); - double pageHeight = pages.at(0)->boundingRect().height(); - QRectF textRect = rect.adjusted(0, pageHeight*(text->page()-1), 0, 0); //move the rectangle onto the right page - QBrush highlightFill(QColor(255, 255, 177, 50)); - QPen highlightOutline(QColor(255, 255, 100, 98)); - scene->addRect(textRect, highlightOutline, highlightFill); + double pageHeight = pages.at(text->page()-1)->boundingRect().height(); + int degrees = BACKEND->rotatedDegrees(); + //Shows the text's location on a non-rotated page + QRectF rect = text->loc(); + //Rotates the rectangle by the page's center and gets the right calculation for text's new location + if(degrees != 0) { + QSize center = BACKEND->imageHash(text->page()-1).size()/2; + + if(degrees == 90 or degrees == 270) + center.transpose(); + + double cx = center.width(), cy = center.height(); + rect.adjust(-cx, -cy, -cx, -cy); + QMatrix matrix; + matrix.rotate(BACKEND->rotatedDegrees()); + rect = matrix.mapRect(rect); + if(BACKEND->rotatedDegrees() == 180) + rect.adjust(cx, cy, cx, cy); + else + rect.adjust(cy, cx, cy, cx); + } + //Moves the rectangle onto the right page + rect.moveTop(rect.y() + pageHeight*(text->page()-1)); + //Transparent yellow for the highlight box + QBrush highlightFill(QColor(255, 255, 177, 100)); + QPen highlightOutline(QColor(255, 255, 100, 125)); + scene->addRect(rect, highlightOutline, highlightFill); text->highlighted(true); } } @@ -143,23 +162,25 @@ void PrintWidget::highlightText(TextData *text) { //Private functions void PrintWidget::generatePreview() { - populateScene(); // i.e. setPreviewPrintedPictures() e.l. - layoutPages(); - curPage = qBound(1, curPage, pages.count()); - publicPageNum = curPage; - emit currentPageChanged(); - if (fitting){ fit(); } + qDebug() << "Generating Preview"; + populateScene(); // i.e. setPreviewPrintedPictures() e.l. + layoutPages(); + curPage = qBound(1, curPage, pages.count()); + publicPageNum = curPage; + emit currentPageChanged(); + if (fitting){ fit(); } } void PrintWidget::layoutPages() { - int numPages = pages.count(); - if (numPages < 1) - return; - - int numPagePlaces = numPages; - int cols = 1; // singleMode and default - if (viewMode == AllPagesView) { - cols = ((pictures->value(0)).width() > (pictures->value(0)).height()) ? qFloor(qSqrt(numPages)) : qCeil(qSqrt(numPages)); + int numPages = pages.count(); + if (numPages < 1) + return; + + int numPagePlaces = numPages; + int cols = 1; // singleMode and default + QSize pageSize = BACKEND->imageHash(0).size(); + if (viewMode == AllPagesView) { + cols = pageSize.width() > pageSize.height() ? qFloor(qSqrt(numPages)) : qCeil(qSqrt(numPages)); cols += cols % 2; // Nicer with an even number of cols } else if (viewMode == FacingPagesView) { cols = 2; @@ -177,152 +198,120 @@ void PrintWidget::layoutPages() { pages.at(pageNum-1)->setPos(QPointF(j*itemWidth, i*itemHeight)); pageNum++; } - } - } - scene->setSceneRect(scene->itemsBoundingRect()); + } + } + scene->setSceneRect(scene->itemsBoundingRect()); + qDebug() << "Finished Page Layout"; } void PrintWidget::populateScene() { for (int i = 0; i < pages.size(); i++){ - scene->removeItem(pages.at(i)); + scene->removeItem(pages.at(i)); } qDeleteAll(pages); pages.clear(); - //qDebug() << "populateScene"; - if(pictures==0){ return; } //nothing to show yet - int numPages = pictures->count(); + qDebug() << "populateScene"; + int numPages = BACKEND->numPages(); + if(BACKEND->hashSize() < numPages){ return; } //nothing to show yet for (int i = 0; i < numPages; i++) { - QImage pagePicture = pictures->value(i); - - QSize paperSize = pictures->value(i).size(); + QImage pagePicture = BACKEND->imageHash(i); - //Changes the paper orientation if rotated by 90 or 270 degrees - if(degrees == 90 or degrees == 270) - paperSize.transpose(); + QSize paperSize = pagePicture.size(); - if(degrees != 0) { - pagePicture = pagePicture.transformed(rotMatrix, Qt::SmoothTransformation); - //qDebug() << "Rotating by: " << degrees << " degrees"; - } if(pagePicture.isNull()) { qDebug() << "NULL IMAGE ON PAGE " << i; continue; } - PageItem* item = new PageItem(i+1, pagePicture, paperSize); - scene->addItem(item); - pages.append(item); + PageItem* item = new PageItem(i+1, pagePicture, paperSize); + scene->addItem(item); + pages.append(item); } } //Private Slots void PrintWidget::updateCurrentPage() { - if (viewMode == AllPagesView) - return; - - int newPage = calcCurrentPage(); - if (newPage != curPage) { - curPage = newPage; - publicPageNum = curPage; - emit currentPageChanged(); - } + if (viewMode == AllPagesView) + return; + + int newPage = calcCurrentPage(); + if (newPage != curPage) { + curPage = newPage; + publicPageNum = curPage; + emit currentPageChanged(); + } } int PrintWidget::calcCurrentPage() { - int maxArea = 0; - int newPage = curPage; - QRect viewRect = this->viewport()->rect(); - QList<QGraphicsItem*> items = this->items(viewRect); - for (int i=0; i<items.size(); ++i) { - PageItem* pg = static_cast<PageItem*>(items.at(i)); - QRect overlap = this->mapFromScene(pg->sceneBoundingRect()).boundingRect() & viewRect; - int area = overlap.width() * overlap.height(); - if (area > maxArea) { - maxArea = area; - newPage = pg->pageNumber(); - } else if (area == maxArea && pg->pageNumber() < newPage) { - newPage = pg->pageNumber(); - } - } - return newPage; + int maxArea = 0; + int newPage = curPage; + QRect viewRect = this->viewport()->rect(); + QList<QGraphicsItem*> items = this->items(viewRect); + for (int i=0; i<items.size(); ++i) { + PageItem* pg = static_cast<PageItem*>(items.at(i)); + QRect overlap = this->mapFromScene(pg->sceneBoundingRect()).boundingRect() & viewRect; + int area = overlap.width() * overlap.height(); + if (area > maxArea) { + maxArea = area; + newPage = pg->pageNumber(); + } else if (area == maxArea && pg->pageNumber() < newPage) { + newPage = pg->pageNumber(); + } + } + return newPage; } void PrintWidget::fit(bool doFitting) { - if (curPage < 1 || curPage > pages.count()) - return; - if (!doFitting && !fitting) - return; - - if (doFitting && fitting) { - QRect viewRect = this->viewport()->rect(); - if (zoomMode == FitInView) { - QList<QGraphicsItem*> containedItems = this->items(viewRect, Qt::ContainsItemBoundingRect); - foreach(QGraphicsItem* item, containedItems) { - PageItem* pg = static_cast<PageItem*>(item); - if (pg->pageNumber() == curPage) - return; - } - } - - int newPage = calcCurrentPage(); - if (newPage != curPage) - curPage = newPage; - } - - QRectF target = pages.at(curPage-1)->sceneBoundingRect(); - if (viewMode == FacingPagesView) { - if (curPage % 2) - target.setLeft(target.left() - target.width()); - else - target.setRight(target.right() + target.width()); - } else if (viewMode == AllPagesView) { - target = scene->itemsBoundingRect(); - } - - if (zoomMode == FitToWidth) { - QTransform t; - qreal scale = this->viewport()->width() / target.width(); - t.scale(scale, scale); - this->setTransform(t); - if (doFitting && fitting) { - QRectF viewSceneRect = this->viewportTransform().mapRect(this->viewport()->rect()); - viewSceneRect.moveTop(target.top()); - this->ensureVisible(viewSceneRect); // Nah... - } - } else { - this->fitInView(target, Qt::KeepAspectRatio); - if (zoomMode == FitInView) { - int step = qRound(this->matrix().mapRect(target).height()); - this->verticalScrollBar()->setSingleStep(step); - this->verticalScrollBar()->setPageStep(step); - } - } - - //zoomFactor = this->transform().m11() * (float(printer->logicalDpiY()) / this->logicalDpiY()); -} + if (curPage < 1 || curPage > pages.count()) + return; + if (!doFitting && !fitting) + return; + + if (doFitting && fitting) { + QRect viewRect = this->viewport()->rect(); + if (zoomMode == FitInView) { + QList<QGraphicsItem*> containedItems = this->items(viewRect, Qt::ContainsItemBoundingRect); + foreach(QGraphicsItem* item, containedItems) { + PageItem* pg = static_cast<PageItem*>(item); + if (pg->pageNumber() == curPage) + return; + } + } -void PrintWidget::setPictures(QHash<int, QImage> *hash) { - pictures = hash; - this->setVisible(hash!=0); -} + int newPage = calcCurrentPage(); + if (newPage != curPage) + curPage = newPage; + } -//Sets how much to rotate the image, by either 90, 180, or 270 degrees. Adds 90 degrees for cw and -90 for ccw. -void PrintWidget::setDegrees(int degrees) { - //Mods by 360, but adds and remods because of how C++ treats negative mods - this->degrees = ( ( ( this->degrees + degrees ) % 360 ) + 360 ) % 360; - switch(this->degrees) { - case 270: - rotMatrix = QMatrix(0, -1, 1, 0, 0, 0); - break; - case 90: - rotMatrix = QMatrix(0, 1, -1, 0, 0, 0); - break; - case 180: - rotMatrix = QMatrix(-1, 0, 0, -1, 0, 0); - break; - default: - rotMatrix = QMatrix(1, 0, 0, 1, 0 ,0); + QRectF target = pages.at(curPage-1)->sceneBoundingRect(); + if (viewMode == FacingPagesView) { + if (curPage % 2) + target.setLeft(target.left() - target.width()); + else + target.setRight(target.right() + target.width()); + } else if (viewMode == AllPagesView) { + target = scene->itemsBoundingRect(); } - this->updatePreview(); + + if (zoomMode == FitToWidth) { + QTransform t; + qreal scale = this->viewport()->width() / target.width(); + t.scale(scale, scale); + this->setTransform(t); + if (doFitting && fitting) { + QRectF viewSceneRect = this->viewportTransform().mapRect(this->viewport()->rect()); + viewSceneRect.moveTop(target.top()); + this->ensureVisible(viewSceneRect); // Nah... + } + } else { + this->fitInView(target, Qt::KeepAspectRatio); + if (zoomMode == FitInView) { + int step = qRound(this->matrix().mapRect(target).height()); + this->verticalScrollBar()->setSingleStep(step); + this->verticalScrollBar()->setPageStep(step); + } + } + + //zoomFactor = this->transform().m11() * (float(printer->logicalDpiY()) / this->logicalDpiY()); } diff --git a/src-qt5/desktop-utils/lumina-pdf/PrintWidget.h b/src-qt5/desktop-utils/lumina-pdf/PrintWidget.h index 38227e78..98bcd259 100644 --- a/src-qt5/desktop-utils/lumina-pdf/PrintWidget.h +++ b/src-qt5/desktop-utils/lumina-pdf/PrintWidget.h @@ -19,60 +19,60 @@ #include <QStyleOptionGraphicsItem> #include <QtMath> #include <QPageLayout> +#include "Renderer.h" #include "textData.h" class PageItem : public QGraphicsItem { public: - PageItem(int _pageNum, QImage _pagePicture, QSize _paperSize) + PageItem(int _pageNum, QImage _pagePicture, QSize _paperSize) : pageNum(_pageNum), pagePicture(_pagePicture), paperSize(_paperSize) - { - brect = QRectF(QPointF(-25, -25), - QSizeF(paperSize)+QSizeF(50, 50)); - setCacheMode(DeviceCoordinateCache); - } - - QRectF boundingRect() const Q_DECL_OVERRIDE - { return brect; } - - inline int pageNumber() const - { return pageNum; } - - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) Q_DECL_OVERRIDE - { - Q_UNUSED(widget); - //Ensure all the antialiasing/smoothing options are turned on - painter->setRenderHint(QPainter::Antialiasing); - painter->setRenderHint(QPainter::TextAntialiasing); - painter->setRenderHint(QPainter::SmoothPixmapTransform); - - QRectF paperRect(0,0, paperSize.width(), paperSize.height()); - - // Draw shadow - painter->setClipRect(option->exposedRect); - qreal shWidth = paperRect.width()/100; - QRectF rshadow(paperRect.topRight() + QPointF(0, shWidth), - paperRect.bottomRight() + QPointF(shWidth, 0)); - QLinearGradient rgrad(rshadow.topLeft(), rshadow.topRight()); - rgrad.setColorAt(0.0, QColor(0,0,0,255)); - rgrad.setColorAt(1.0, QColor(0,0,0,0)); - painter->fillRect(rshadow, QBrush(rgrad)); - QRectF bshadow(paperRect.bottomLeft() + QPointF(shWidth, 0), - paperRect.bottomRight() + QPointF(0, shWidth)); - QLinearGradient bgrad(bshadow.topLeft(), bshadow.bottomLeft()); - bgrad.setColorAt(0.0, QColor(0,0,0,255)); - bgrad.setColorAt(1.0, QColor(0,0,0,0)); - painter->fillRect(bshadow, QBrush(bgrad)); - QRectF cshadow(paperRect.bottomRight(), - paperRect.bottomRight() + QPointF(shWidth, shWidth)); - QRadialGradient cgrad(cshadow.topLeft(), shWidth, cshadow.topLeft()); - cgrad.setColorAt(0.0, QColor(0,0,0,255)); - cgrad.setColorAt(1.0, QColor(0,0,0,0)); - painter->fillRect(cshadow, QBrush(cgrad)); - painter->setClipRect(paperRect & option->exposedRect); - painter->fillRect(paperRect, Qt::white); - painter->drawImage(QPoint(0,0), pagePicture); - } + { + brect = QRectF(QPointF(-25, -25), + QSizeF(paperSize)+QSizeF(50, 50)); + setCacheMode(DeviceCoordinateCache); + } + + QRectF boundingRect() const Q_DECL_OVERRIDE + { return brect; } + + inline int pageNumber() const + { return pageNum; } + + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) Q_DECL_OVERRIDE + { + Q_UNUSED(widget); + //Ensure all the antialiasing/smoothing options are turned on + painter->setRenderHint(QPainter::Antialiasing); + painter->setRenderHint(QPainter::TextAntialiasing); + painter->setRenderHint(QPainter::SmoothPixmapTransform); + + QRectF paperRect(0,0, paperSize.width(), paperSize.height()); + // Draw shadow + painter->setClipRect(option->exposedRect); + qreal shWidth = paperRect.width()/100; + QRectF rshadow(paperRect.topRight() + QPointF(0, shWidth), + paperRect.bottomRight() + QPointF(shWidth, 0)); + QLinearGradient rgrad(rshadow.topLeft(), rshadow.topRight()); + rgrad.setColorAt(0.0, QColor(0,0,0,255)); + rgrad.setColorAt(1.0, QColor(0,0,0,0)); + painter->fillRect(rshadow, QBrush(rgrad)); + QRectF bshadow(paperRect.bottomLeft() + QPointF(shWidth, 0), + paperRect.bottomRight() + QPointF(0, shWidth)); + QLinearGradient bgrad(bshadow.topLeft(), bshadow.bottomLeft()); + bgrad.setColorAt(0.0, QColor(0,0,0,255)); + bgrad.setColorAt(1.0, QColor(0,0,0,0)); + painter->fillRect(bshadow, QBrush(bgrad)); + QRectF cshadow(paperRect.bottomRight(), + paperRect.bottomRight() + QPointF(shWidth, shWidth)); + QRadialGradient cgrad(cshadow.topLeft(), shWidth, cshadow.topLeft()); + cgrad.setColorAt(0.0, QColor(0,0,0,255)); + cgrad.setColorAt(1.0, QColor(0,0,0,0)); + painter->fillRect(cshadow, QBrush(cgrad)); + painter->setClipRect(paperRect & option->exposedRect); + painter->fillRect(paperRect, Qt::white); + painter->drawImage(QPoint(0,0), pagePicture); + } private: int pageNum; @@ -84,86 +84,83 @@ private: class PrintWidget : public QGraphicsView { - Q_OBJECT + Q_OBJECT public: - enum ViewMode { - SinglePageView, - FacingPagesView, - AllPagesView - }; - - enum ZoomMode { - CustomZoom, - FitToWidth, - FitInView - }; + enum ViewMode { + SinglePageView, + FacingPagesView, + AllPagesView + }; + + enum ZoomMode { + CustomZoom, + FitToWidth, + FitInView + }; private: - void generatePreview(); - void layoutPages(); - void populateScene(); - void setViewMode(ViewMode); - void setZoomMode(ZoomMode); - - QGraphicsScene *scene; - QMatrix rotMatrix; - int curPage, publicPageNum; - ViewMode viewMode; - ZoomMode zoomMode; - QPageLayout::Orientation orientation; - double zoomFactor; - bool initialized, fitting; - QList<QGraphicsItem*> pages; - QHash<int, QImage> *pictures; - int degrees; + void generatePreview(); + void layoutPages(); + void populateScene(); + void setViewMode(ViewMode); + void setZoomMode(ZoomMode); + + QGraphicsScene *scene; + int curPage, publicPageNum; + ViewMode viewMode; + ZoomMode zoomMode; + QPageLayout::Orientation orientation; + double zoomFactor; + bool initialized, fitting; + QList<QGraphicsItem*> pages; + int degrees; + Renderer *BACKEND; public: - PrintWidget(QWidget *parent = 0); - ~PrintWidget(); + PrintWidget(Renderer *backend, QWidget *parent = 0); + ~PrintWidget(); - double getZoomFactor() const { return this->zoomFactor; }; - ZoomMode getZoomMode() const { return this->zoomMode; }; - int currentPage() const { return publicPageNum; }; - void setPictures(QHash<int, QImage>*); + double getZoomFactor() const { return this->zoomFactor; }; + ZoomMode getZoomMode() const { return this->zoomMode; }; + int currentPage() const { return publicPageNum; }; signals: - void resized(); - void customContextMenuRequested(const QPoint&); - void currentPageChanged(); + void resized(); + void customContextMenuRequested(const QPoint&); + void currentPageChanged(); public slots: - void zoomIn(double factor=1.2); - void zoomOut(double factor=1.2); - void setCurrentPage(int); - void setVisible(bool) Q_DECL_OVERRIDE; - void highlightText(TextData*); - void setDegrees(int); - - void updatePreview(); - void fitView(); - void fitToWidth(); - void setAllPagesViewMode(); - void setSinglePageViewMode(); - void setFacingPagesViewMode(); + void zoomIn(double factor=1.2); + void zoomOut(double factor=1.2); + void setCurrentPage(int); + void setVisible(bool) Q_DECL_OVERRIDE; + void highlightText(TextData*); + + void updatePreview(); + void fitView(); + void fitToWidth(); + void setAllPagesViewMode(); + void setSinglePageViewMode(); + void setFacingPagesViewMode(); private slots: - void updateCurrentPage(); - int calcCurrentPage(); - void fit(bool doFitting=false); + void updateCurrentPage(); + int calcCurrentPage(); + void fit(bool doFitting=false); protected: - void resizeEvent(QResizeEvent* e) Q_DECL_OVERRIDE { - /*{ - const QSignalBlocker blocker(verticalScrollBar()); // Don't change page, QTBUG-14517 - QGraphicsView::resizeEvent(e); - }*/ - QGraphicsView::resizeEvent(e); - emit resized(); - } - - void showEvent(QShowEvent* e) Q_DECL_OVERRIDE { - QGraphicsView::showEvent(e); - emit resized(); - } + void resizeEvent(QResizeEvent* e) Q_DECL_OVERRIDE { + /*{ + const QSignalBlocker blocker(verticalScrollBar()); // Don't change page, QTBUG-14517 + QGraphicsView::resizeEvent(e); + }*/ + QGraphicsView::resizeEvent(e); + emit resized(); + } + + void showEvent(QShowEvent* e) Q_DECL_OVERRIDE { + QGraphicsView::showEvent(e); + emit resized(); + } }; #endif diff --git a/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp b/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp index 799f6584..23d9b3d1 100644 --- a/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp +++ b/src-qt5/desktop-utils/lumina-pdf/Renderer-mupdf.cpp @@ -1,152 +1,215 @@ #include "Renderer.h" #include <QDateTime> #include <mupdf/fitz.h> -//#include <pthread.h> +#include <QMutex> +#include <QFuture> +#include <QtConcurrent> + +class Data { + public: + Data(int _pagenum, fz_context *_ctx, fz_display_list *_list, fz_rect _bbox, fz_pixmap *_pix, fz_matrix _ctm, double _sf) : + pagenumber(_pagenum), + ctx(_ctx), + list(_list), + bbox(_bbox), + pix(_pix), + ctm(_ctm), + sf(_sf) + { } + + ~Data() { } + + int pagenumber; + fz_context *ctx; + fz_display_list *list; + fz_rect bbox; + fz_pixmap *pix; + fz_matrix ctm; + QImage img; + QFuture<void> renderThread; + double sf; +}; fz_document *DOC; fz_context *CTX; +QHash<int, Data*> dataHash; +QMutex mutex[FZ_LOCK_MAX]; +fz_locks_context locks; inline QString getTextInfo(QString str) { - char infoBuff[1000]; - int size = DOC->lookup_metadata(CTX, DOC, ("info:"+str).toLocal8Bit().data(), infoBuff, 1000); + char infoBuff[1000]; + int size = DOC->lookup_metadata(CTX, DOC, ("info:"+str).toLocal8Bit().data(), infoBuff, 1000); if(size != -1){ return QString::fromLatin1(infoBuff); } return ""; } -/*void lock_mutex(void *user, int lock) { - pthread_mutex_t *mutex = (pthread_mutex_t *) user; - pthread_mutex_lock(&mutex[lock]); +void lock_mutex(void *user, int lock) { + QMutex *mutex = (QMutex*) user; + mutex[lock].lock(); } void unlock_mutex(void *user, int lock) { - pthread_mutex_t *mutex = (pthread_mutex_t *) user; - pthread_mutex_unlock(&mutex[lock]); -}*/ + QMutex *mutex = (QMutex*) user; + mutex[lock].unlock(); +} Renderer::Renderer(){ - /*pthread_mutex_t mutex[FZ_LOCK_MAX]; - fz_locks_context locks; - locks.user = mutex; - locks.lock = lock_mutex; - locks.unlock = unlock_mutex; - - for (int i = 0; i < FZ_LOCK_MAX; i++) - pthread_mutex_init(&mutex[i], NULL);*/ + locks.user = mutex; + locks.lock = lock_mutex; + locks.unlock = unlock_mutex; - mutex = new QMutex(); DOC = 0; - //CTX = fz_new_context(NULL, &locks, FZ_STORE_UNLIMITED); - CTX = fz_new_context(NULL, NULL, FZ_STORE_UNLIMITED); - qDebug() << "Context created"; + qDebug() << "Creating Context"; + CTX = fz_new_context(NULL, &locks, FZ_STORE_UNLIMITED); needpass = false; + degrees = 0; } Renderer::~Renderer(){ - + qDebug() << "Calling destructor"; + qDeleteAll(dataHash); + dataHash.clear(); + fz_drop_document(CTX, DOC); + DOC = NULL; + fz_drop_context(CTX); + CTX = NULL; } -//bool Renderer::loadMultiThread(){ return true; } - -QJsonObject Renderer::properties(){ - QJsonObject jobj; - jobj.insert("title", getTextInfo("Title") ); - jobj.insert("subject", getTextInfo("Subject") ); - jobj.insert("author", getTextInfo("Author") ); - jobj.insert("creator", getTextInfo("Creator") ); - jobj.insert("producer", getTextInfo("Producer") ); - jobj.insert("keywords", getTextInfo("Keywords") ); - jobj.insert("dt_created", QDateTime::fromString( getTextInfo("CreationDate").left(16), "'D:'yyyyMMddHHmmss").toString() ); - jobj.insert("dt_modified", QDateTime::fromString( getTextInfo("ModDate").left(16), "'D:'yyyyMMddHHmmss").toString() ); - return jobj; -} +bool Renderer::loadMultiThread(){ return false; } bool Renderer::loadDocument(QString path, QString password){ - //first time through - if(DOC==0){ - fz_register_document_handlers(CTX); - qDebug() << "Document handlers registered"; - }else if(path!=docpath){ - //fz_close_document(DOC); - //Clear out the old document first - delete DOC; - DOC=0; - needpass = false; - docpath = path; - } + //first time through + if(path != docpath) { + if(DOC != 0) { + qDebug() << "New document"; + fz_drop_document(CTX, DOC); + DOC = NULL; + needpass = false; + docpath = path; + }else if(DOC==0){ + fz_register_document_handlers(CTX); + qDebug() << "Document handlers registered"; + } - if(DOC==0){ DOC = fz_open_document(CTX, path.toLocal8Bit().data()); - docpath = path; - qDebug() << "File opened"; + docpath = path; + qDebug() << "File opened" << DOC; if(DOC==0){ qDebug() << "Could not open file:" << path; return false; } needpass = (fz_needs_password(CTX, DOC) != 0); - } - if(needpass && password.isEmpty()){ return false; } - else if(needpass){ - needpass = !fz_authenticate_password(CTX, DOC, password.toLocal8Bit()); - if(needpass){ return false; } //incorrect password + if(needpass && password.isEmpty()){ + return false; + }else if(needpass){ + needpass = !fz_authenticate_password(CTX, DOC, password.toLocal8Bit()); + if(needpass){ return false; } //incorrect password + } + + //qDebug() << "Password Check cleared"; + pnum = fz_count_pages(CTX, DOC); + qDebug() << "Page count: " << pnum; + + doctitle.clear(); + //qDebug() << "Opening File:" << path; + jobj.insert("title", getTextInfo("Title") ); + jobj.insert("subject", getTextInfo("Subject") ); + jobj.insert("author", getTextInfo("Author") ); + jobj.insert("creator", getTextInfo("Creator") ); + jobj.insert("producer", getTextInfo("Producer") ); + jobj.insert("keywords", getTextInfo("Keywords") ); + jobj.insert("dt_created", QDateTime::fromString( getTextInfo("CreationDate").left(16), "'D:'yyyyMMddHHmmss").toString() ); + jobj.insert("dt_modified", QDateTime::fromString( getTextInfo("ModDate").left(16), "'D:'yyyyMMddHHmmss").toString() ); + + if(!jobj["title"].isNull()) + doctitle = jobj["title"].toString(); + else + doctitle = path.section("/",-1); + + qDebug() << "Page Loaded"; + //Possibly check Page orientation + return true; } + return false; +} - qDebug() << "Password Check cleared"; - - //Could read/access the PDF - go ahead and load the info now - pnum = -1; - doctitle.clear(); - //qDebug() << "Opening File:" << path; - QString title = getTextInfo("Subject"); - if(!title.isNull()) - doctitle = title; - else - doctitle = path.section("/",-1); - pnum = fz_count_pages(CTX, DOC); - //Setup the Document - fz_page *PAGE = fz_load_page(CTX, DOC, 0); - qDebug() << "Page Loaded"; - //Possibly check Page orientation"; - - return (PAGE); +void renderer(Data *data, Renderer *obj) +{ + int pagenum = data->pagenumber; + //qDebug() << "Rendering:" << pagenum; + fz_context *ctx = data->ctx; + fz_display_list *list = data->list; + fz_rect bbox = data->bbox; + fz_pixmap *pixmap = data->pix; + fz_matrix ctm = data->ctm; + fz_device *dev; + + ctx = fz_clone_context(ctx); + dev = fz_new_draw_device(ctx, &fz_identity, pixmap); + fz_run_display_list(ctx, list, dev, &ctm, &bbox, NULL); + + data->img = QImage(pixmap->samples, pixmap->w, pixmap->h, pixmap->stride, QImage::Format_RGB888); + fz_close_device(ctx, dev); + fz_drop_device(ctx, dev); + + fz_drop_context(ctx); + + if(dataHash.find(pagenum) == dataHash.end()) + dataHash.insert(pagenum, data); + else + dataHash[pagenum] = data; + emit obj->PageLoaded(pagenum); } //Consider rendering through a display list -QImage Renderer::renderPage(int pagenum, QSize DPI){ - QImage img; - fz_matrix matrix; - fz_pixmap *pixmap = nullptr; - - fz_scale(&matrix, DPI.width()/96.0, DPI.height()/96.0); - - //fz_context *ctx = fz_clone_context(CTX); - mutex->lock(); - - fz_try(CTX) { - pixmap = fz_new_pixmap_from_page_number(CTX, DOC, pagenum, &matrix, fz_device_rgb(CTX), 0); - }fz_catch(CTX){ - qDebug() << "Error when rendering page using MuPDF"; - } - - mutex->unlock(); - - img = QImage(pixmap->samples, pixmap->w, pixmap->h, pixmap->stride, QImage::Format_RGB888); - qDebug() << "Render Page:" << pagenum; - return img; +void Renderer::renderPage(int pagenum, QSize DPI, int degrees){ + //qDebug() << "- Rendering Page:" << pagenum << degrees; + Data *data; + fz_matrix matrix; + fz_rect bbox; + fz_irect rbox; + fz_pixmap *pixmap; + fz_display_list *list; + + double pageDPI = 96.0; + double sf = DPI.width() / pageDPI; + fz_scale(&matrix, sf, sf); + fz_pre_rotate(&matrix, degrees); + + fz_page *PAGE = fz_load_page(CTX, DOC, pagenum); + fz_bound_page(CTX, PAGE, &bbox); + emit OrigSize(QSizeF(bbox.x1 - bbox.x0, bbox.y1 - bbox.y0)); + + fz_transform_rect(&bbox, &matrix); + list = fz_new_display_list(CTX, &bbox); + fz_device *dev = fz_new_list_device(CTX, list); + fz_run_page(CTX, PAGE, dev, &fz_identity, NULL); + + fz_close_device(CTX, dev); + fz_drop_device(CTX, dev); + fz_drop_page(CTX, PAGE); + + pixmap = fz_new_pixmap_with_bbox(CTX, fz_device_rgb(CTX), fz_round_rect(&rbox, &bbox), NULL, 0); + fz_clear_pixmap_with_value(CTX, pixmap, 0xff); + + data = new Data(pagenum, CTX, list, bbox, pixmap, matrix, sf); + data->renderThread = QtConcurrent::run(&renderer, data, this); } QList<TextData*> Renderer::searchDocument(QString text, bool matchCase){ fz_rect rectBuffer[1000]; QList<TextData*> results; for(int i = 0; i < pnum; i++) { - int count = fz_search_page_number(CTX, DOC, i, text.toLatin1().data(), rectBuffer, 1000); + int count = fz_search_display_list(CTX, dataHash[i]->list, text.toLatin1().data(), rectBuffer, 1000); //qDebug() << "Page " << i+1 << ": Count, " << count; for(int j = 0; j < count; j++) { - QRect rect(rectBuffer[j].x0, rectBuffer[j].y0, rectBuffer[j].x1-rectBuffer[j].x0, rectBuffer[j].y1 - rectBuffer[j].y0); + double sf = dataHash[i]->sf; + QRectF rect(rectBuffer[j].x0*sf, rectBuffer[j].y0*sf, (rectBuffer[j].x1-rectBuffer[j].x0)*sf, (rectBuffer[j].y1 - rectBuffer[j].y0)*sf); TextData *t = new TextData(rect, i+1, text); //MuPDF search does not match case, so retrieve the exact text at the location found and determine whether or not it matches the case of the search text if the user selected to match case if(matchCase){ - fz_stext_page *sPage = fz_new_stext_page_from_page_number(CTX, DOC, i, NULL); + fz_stext_page *sPage = fz_new_stext_page_from_display_list(CTX, dataHash[i]->list, NULL); QString currentStr = QString(fz_copy_selection(CTX, sPage, *fz_rect_min(&rectBuffer[j]), *fz_rect_max(&rectBuffer[j]), false)); if(currentStr.contains(text, Qt::CaseSensitive)){ results.append(t); } }else{ @@ -156,3 +219,22 @@ QList<TextData*> Renderer::searchDocument(QString text, bool matchCase){ } return results; } + +QImage Renderer::imageHash(int pagenum) { + return dataHash[pagenum]->img; +} + +int Renderer::hashSize() { + return dataHash.size(); +} + +void Renderer::clearHash() { + for(int i = 0; i < dataHash.size(); i++) { + fz_drop_pixmap(CTX, dataHash[i]->pix); + fz_drop_display_list(CTX, dataHash[i]->list); + } + qDeleteAll(dataHash); + dataHash.clear(); +} + +bool Renderer::supportsExtraFeatures() { return true; } diff --git a/src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp b/src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp index 693faa64..439fd804 100644 --- a/src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp +++ b/src-qt5/desktop-utils/lumina-pdf/Renderer-poppler.cpp @@ -1,23 +1,27 @@ #include "Renderer.h" #include <poppler/qt5/poppler-qt5.h> +#include <QThread> static Poppler::Document *DOC; +QHash<int, QImage> loadingHash; Renderer::Renderer(){ DOC = 0; needpass = false; pnum = 0; + degrees = 0; } Renderer::~Renderer(){ - + //qDeleteAll(loadingHash); + loadingHash.clear(); } -//bool Renderer::loadMultiThread(){ return true; } +bool Renderer::loadMultiThread(){ return true; } -QJsonObject Renderer::properties(){ +/*QJsonObject Renderer::properties(){ return QJsonObject(); //TO-DO -} +}*/ bool Renderer::loadDocument(QString path, QString password){ //qDebug() << "Load Document:" << path; @@ -27,13 +31,13 @@ bool Renderer::loadDocument(QString path, QString password){ DOC=0; needpass = false; pnum=0; - docpath = path; + docpath = path; } //Load the Document (if needed); if(DOC==0){ //qDebug() << "Loading Document"; DOC = Poppler::Document::load(path); - docpath = path; + docpath = path; } if(DOC==0){ @@ -65,36 +69,62 @@ bool Renderer::loadDocument(QString path, QString password){ return false; //nothing to load } -QImage Renderer::renderPage(int pagenum, QSize DPI){ - //qDebug() << "Render Page:" << pagenum << DPI; - if(DOC==0){ return QImage(); } - Poppler::Page *PAGE = DOC->page(pagenum); - QImage img; - if(PAGE!=0){ - //qDebug() << "Render Page:" << pagenum; - img = PAGE->renderToImage(DPI.width(),DPI.height()); - delete PAGE; +void Renderer::renderPage(int pagenum, QSize DPI, int degrees){ + //qDebug() << "Render Page:" << pagenum << DPI << degrees; + if(DOC!=0){ + Poppler::Page *PAGE = DOC->page(pagenum); + QImage img; + if(PAGE!=0){ + Poppler::Page::Rotation rotation; + switch(degrees) { + case 90: + rotation = Poppler::Page::Rotation::Rotate90; + break; + case 180: + rotation = Poppler::Page::Rotation::Rotate180; + break; + case 270: + rotation = Poppler::Page::Rotation::Rotate270; + break; + default: + rotation = Poppler::Page::Rotation::Rotate0; + } + img = PAGE->renderToImage(DPI.width(),DPI.height(), -1, -1, -1, -1, rotation); + loadingHash.insert(pagenum, img); + delete PAGE; + } + //qDebug() << "Done Render Page:" << pagenum << img.size(); + }else{ + loadingHash.insert(pagenum, QImage()); } - //qDebug() << "Done Render Page:" << pagenum << img.size(); - return img; + emit PageLoaded(pagenum); } QList<TextData*> Renderer::searchDocument(QString text, bool matchCase){ QList<TextData*> results; - /*for(int i = 0; i < pnum; i++) { - int count = fz_search_page_number(CTX, DOC, i, text.toLatin1().data(), rectBuffer, 1000); - //qDebug() << "Page " << i+1 << ": Count, " << count; - for(int j = 0; j < count; j++) { - TextData *t = new TextData(rectBuffer[j], i+1, text); - //MuPDF search does not match case, so retrieve the exact text at the location found and determine whether or not it matches the case of the search text if the user selected to match case - if(matchCase){ - fz_stext_page *sPage = fz_new_stext_page_from_page_number(CTX, DOC, i, NULL); - QString currentStr = QString(fz_copy_selection(CTX, sPage, *fz_rect_min(&rectBuffer[j]), *fz_rect_max(&rectBuffer[j]), false)); - if(currentStr.contains(text, Qt::CaseSensitive)){ results.append(t); } - }else{ - results.append(t); + for(int i = 0; i < pnum; i++) { + QList<Poppler::TextBox*> textList = DOC->page(i)->textList(); + for(int j = 0; j < textList.size(); j++) { + if(textList[j]->text().contains(text, + (matchCase) ? Qt::CaseSensitive : Qt::CaseInsensitive)) { + TextData *t = new TextData(textList[j]->boundingBox(), i+1, text); + results.append(t); } } - }*/ + } return results; } + +QImage Renderer::imageHash(int pagenum) { + return loadingHash[pagenum]; +} + +int Renderer::hashSize() { + return loadingHash.keys().length(); +} + +void Renderer::clearHash() { + loadingHash.clear(); +} + +bool Renderer::supportsExtraFeatures() { return false; } diff --git a/src-qt5/desktop-utils/lumina-pdf/Renderer.h b/src-qt5/desktop-utils/lumina-pdf/Renderer.h index c9e13c7f..ab86724d 100644 --- a/src-qt5/desktop-utils/lumina-pdf/Renderer.h +++ b/src-qt5/desktop-utils/lumina-pdf/Renderer.h @@ -1,5 +1,4 @@ -// ================================ -// Simple abstraction class between backend renderers +// ================================ // Simple abstraction class between backend renderers // ================================ // Written by Ken Moore: Feb 26, 2018 // Available under the 3-Clause BSD License @@ -11,31 +10,52 @@ #include <QImage> #include <QDebug> #include <QJsonObject> -#include <QMutex> #include "textData.h" -class Renderer{ +class Renderer : public QObject { +Q_OBJECT + private: - int pnum; //number of pages - set on loading document - bool needpass; - QString docpath; //save the path for the currently-loaded document - QString doctitle; - QMutex *mutex; + int pnum; //number of pages - set on loading document + bool needpass; + QString docpath; //save the path for the currently-loaded document + QString doctitle; + QJsonObject jobj; + int degrees; + public: - Renderer(); - ~Renderer(); - //bool loadMultiThread(); - - //Information functions (usually needs to be loaded first) - int numPages(){ return pnum; } - bool needPassword(){ return needpass; } - QString title(){ return doctitle; } - QJsonObject properties(); - - //Main access functions - bool loadDocument(QString path, QString password); - QImage renderPage(int pagenum, QSize DPI); - QList<TextData*> searchDocument(QString text, bool matchCase); + Renderer(); + ~Renderer(); + bool loadMultiThread(); + + //Information functions (usually needs to be loaded first) + int numPages(){ return pnum; } + bool needPassword(){ return needpass; } + QString title(){ return doctitle; } + QJsonObject properties() { return jobj; } + int hashSize(); + QImage imageHash(int pagenum); + int rotatedDegrees() { return degrees; } + + //Main access functions + bool loadDocument(QString path, QString password); + void renderPage(int pagenum, QSize DPI, int degrees=0); + QList<TextData*> searchDocument(QString text, bool matchCase); + + void clearHash(); + //Makes sure degrees is between 0 and 360 then rotates the matrix and + void setDegrees(int degrees) { + //Mods by 360, but adds and remods because of how C++ treats negative mods + this->degrees = ( ( ( this->degrees + degrees ) % 360 ) + 360 ) % 360; + emit reloadPages(this->degrees); + } + + bool supportsExtraFeatures(); + +signals: + void PageLoaded(int); + void OrigSize(QSizeF); + void reloadPages(int); }; #endif diff --git a/src-qt5/desktop-utils/lumina-pdf/mainUI.cpp b/src-qt5/desktop-utils/lumina-pdf/mainUI.cpp index 4d255f64..3c2d1541 100644 --- a/src-qt5/desktop-utils/lumina-pdf/mainUI.cpp +++ b/src-qt5/desktop-utils/lumina-pdf/mainUI.cpp @@ -21,8 +21,6 @@ #include <LuminaXDG.h> #include "PrintWidget.h" -#define TESTING 0 - MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI()){ ui->setupUi(this); //this->setWindowTitle(tr("Lumina PDF Viewer")); @@ -31,11 +29,12 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI()){ CurrentPage = 1; lastdir = QDir::homePath(); BACKEND = new Renderer(); + PROPDIALOG=nullptr; //Create the interface widgets - WIDGET = new PrintWidget(this->centralWidget()); - WIDGET->setVisible(false); + WIDGET = new PrintWidget(BACKEND, this->centralWidget()); WIDGET->setContextMenuPolicy(Qt::CustomContextMenu); WIDGET->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + loadingQueue.clear(); clockTimer = new QTimer(this); clockTimer->setInterval(1000); //1-second updates to clock connect(clockTimer, SIGNAL(timeout()), this, SLOT(updateClock()) ); @@ -51,16 +50,13 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI()){ //Context Menu contextMenu = new QMenu(this); connect(contextMenu, SIGNAL(aboutToShow()), this, SLOT(updateContextMenu())); - //Now put the widgets into the UI - //ui->bookmarksFrame->setParent(WIDGET); - //ui->findGroup->setParent(WIDGET); - //qDebug() << "Setting central widget"; - this->centralWidget()->layout()->replaceWidget(ui->label_replaceme, WIDGET); //setCentralWidget(WIDGET); + this->centralWidget()->layout()->replaceWidget(ui->label_replaceme, WIDGET); ui->label_replaceme->setVisible(false); WIDGET->setContextMenuPolicy(Qt::CustomContextMenu); connect(WIDGET, SIGNAL(customContextMenuRequested(const QPoint&)),this, SLOT(showContextMenu(const QPoint&)) ); connect(WIDGET, SIGNAL(currentPageChanged()), this, SLOT(updatePageNumber()) ); - connect(this, SIGNAL(PageLoaded(int)), this, SLOT(slotPageLoaded(int)) ); + connect(BACKEND, SIGNAL(PageLoaded(int)), this, SLOT(slotPageLoaded(int)) ); + connect(BACKEND, SIGNAL(reloadPages(int)), this, SLOT(startLoadingPages(int))); PrintDLG = new QPrintDialog(this); connect(PrintDLG, SIGNAL(accepted(QPrinter*)), this, SLOT(paintToPrinter(QPrinter*)) ); @@ -106,8 +102,8 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI()){ //connect(ui->actionSelect_Mode, &QAction::triggered, this, [&] { this->setScroll(false); }); connect(ui->actionZoom_In, &QAction::triggered, WIDGET, [&] { WIDGET->zoomIn(1.2); }); connect(ui->actionZoom_Out, &QAction::triggered, WIDGET, [&] { WIDGET->zoomOut(1.2); }); - connect(ui->actionRotate_Counterclockwise, &QAction::triggered, this, [&] { WIDGET->setDegrees(-90); }); - connect(ui->actionRotate_Clockwise, &QAction::triggered, this, [&] { WIDGET->setDegrees(90); }); + connect(ui->actionRotate_Counterclockwise, &QAction::triggered, this, [&] { if(results.size() != 0) { foreach(TextData *x, results) { x->highlighted(false); } } BACKEND->setDegrees(-90); }); + connect(ui->actionRotate_Clockwise, &QAction::triggered, this, [&] { if(results.size() != 0) { foreach(TextData *x, results) { x->highlighted(false); } } BACKEND->setDegrees(90); }); connect(ui->actionZoom_In_2, &QAction::triggered, WIDGET, [&] { WIDGET->zoomIn(1.2); }); connect(ui->actionZoom_Out_2, &QAction::triggered, WIDGET, [&] { WIDGET->zoomOut(1.2); }); connect(ui->actionFirst_Page, SIGNAL(triggered()), this, SLOT(firstPage()) ); @@ -115,6 +111,7 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI()){ connect(ui->actionNext_Page, SIGNAL(triggered()), this, SLOT(nextPage()) ); connect(ui->actionLast_Page, SIGNAL(triggered()), this, SLOT(lastPage()) ); connect(ui->actionProperties, &QAction::triggered, WIDGET, [&] { PROPDIALOG->show(); }); + connect(BACKEND, &Renderer::OrigSize, this, [&](QSizeF _pageSize) { pageSize = _pageSize; }); connect(ui->actionFind, &QAction::triggered, this, [&] { if(ui->findGroup->isVisible()) { ui->findGroup->setVisible(false); @@ -211,6 +208,7 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI()){ ui->bookmarksFrame->setVisible(false); //TESTING features/functionality + bool TESTING = BACKEND->supportsExtraFeatures(); ui->actionSettings->setEnabled(TESTING); ui->actionSettings->setVisible(TESTING); ui->actionBookmarks->setEnabled(TESTING); @@ -227,6 +225,12 @@ MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI()){ ui->menubar->removeAction(ui->menuSettings->menuAction() ); } + ui->actionSettings->setEnabled(false); + ui->actionSettings->setVisible(false); + ui->actionScroll_Mode->setEnabled(false); + ui->actionScroll_Mode->setVisible(false); + ui->actionSelect_Mode->setEnabled(false); + ui->actionSelect_Mode->setVisible(false); } MainUI::~MainUI(){ @@ -237,27 +241,25 @@ void MainUI::loadFile(QString path){ if(!QFile::exists(path) || path.isEmpty() ){ return; } QString password; bool ok = true; + while( ok && !BACKEND->loadDocument(path, password) && BACKEND->needPassword() ){ password = QInputDialog::getText(this, tr("Unlock PDF"), tr("Password:"), QLineEdit::Password, "", &ok); if(!ok){ break; } //cancelled } //Clear the current display - WIDGET->setPictures(0); //Turn off the loadingHash in the preview widget for now - loadingHash.clear(); - QTimer::singleShot(10, WIDGET, SLOT(updatePreview())); //start loading the file preview + WIDGET->setVisible(false); + QTimer::singleShot(10, WIDGET, SLOT(updatePreview())); //Load the new document info this->setWindowTitle( BACKEND->title()); if(BACKEND->needPassword()){ return; } //cancelled; - //qDebug() << " - Document Setup : start loading pages now"; - //startLoadingPages(); - QTimer::singleShot(50, this, SLOT(startLoadingPages()) ); + qDebug() << " - Document Setup : start loading pages now"; + QTimer::singleShot(50, [&]() { startLoadingPages(0); } ); } -void MainUI::loadPage(int num, MainUI *obj, QSize dpi){ +void MainUI::loadPage(int num, MainUI *obj, QSize dpi, int degrees){ //qDebug() << " - Render Page:" << num; - QImage img = BACKEND->renderPage(num, dpi); - loadingHash.insert(num, img); - obj->emit PageLoaded(num); + BACKEND->renderPage(num, dpi, degrees); + //qDebug() << "Image at" << num << "accessed outside:" << BACKEND->imageHash(num).isNull(); } QScreen* MainUI::getScreen(bool current, bool &cancelled){ @@ -293,7 +295,7 @@ QScreen* MainUI::getScreen(bool current, bool &cancelled){ } void MainUI::startPresentation(bool atStart){ - if(loadingHash.isEmpty()){ return; } //just in case + if(BACKEND->hashSize() == 0){ return; } //just in case bool cancelled = false; QScreen *screen = getScreen(false, cancelled); //let the user select which screen to use (if multiples) if(cancelled){ return;} @@ -341,7 +343,7 @@ void MainUI::ShowPage(int page){ //qDebug() << "Show Page:" << page << "/" << numPages; CurrentPage = page; QImage PAGEIMAGE; - if(page<BACKEND->numPages()+1){ PAGEIMAGE = loadingHash[page-1]; } + if(page<BACKEND->numPages()+1){ PAGEIMAGE = BACKEND->imageHash(page-1); } //Now scale the image according to the user-designations and show it if(!PAGEIMAGE.isNull()){ @@ -367,10 +369,14 @@ void MainUI::endPresentation(){ updatePageNumber(); } -void MainUI::startLoadingPages(){ - //qDebug() <<"Start Loading Pages"; - if(!loadingHash.isEmpty()){ return; } //currently loaded[ing] - //loadingHash.clear(); +void MainUI::startLoadingPages(int degrees){ + qDebug() <<"Start Loading Pages"; + //if(BACKEND->hashSize() != 0) { return; } //currently loaded[ing] + loadingQueue.clear(); + if(PROPDIALOG) + delete PROPDIALOG; + BACKEND->clearHash(); + WIDGET->setVisible(false); //qDebug() << "Update Progress Bar"; progress->setRange(0, BACKEND->numPages()); progress->setValue(0); @@ -383,26 +389,30 @@ void MainUI::startLoadingPages(){ QSize DPI(300,300); //print-quality (some printers even go to 600 DPI nowdays) - /*qDebug() << "Screen Resolutions:"; + qDebug() << "Screen Resolutions:"; QList<QScreen*> screens = QApplication::screens(); for(int i=0; i<screens.length(); i++){ qDebug() << screens[i]->name() << screens[i]->logicalDotsPerInchX() << screens[i]->logicalDotsPerInchY(); - }*/ + } for(int i=0; i<BACKEND->numPages(); i++){ //qDebug() << " - Kickoff page load:" << i; - QtConcurrent::run(this, &MainUI::loadPage, i, this, DPI); + if(BACKEND->loadMultiThread()) { + QtConcurrent::run(this, &MainUI::loadPage, i, this, DPI, degrees); + }else{ + BACKEND->renderPage(i, DPI, degrees); + } } //qDebug() << "Finish page loading kickoff"; } void MainUI::slotPageLoaded(int page){ - Q_UNUSED(page); - //qDebug() << "Page Loaded:" << page; - int finished = loadingHash.keys().length(); - //qDebug() << " - finished:" << finished; + loadingQueue.push_back(page); + int finished = loadingQueue.size(); + //qDebug() << "Page Loaded:" << page << finished; if(finished == BACKEND->numPages()){ + //qDebug() << " - finished:" << finished; progAct->setVisible(false); - WIDGET->setPictures(&loadingHash); + WIDGET->setVisible(true); WIDGET->setCurrentPage(1); PROPDIALOG = new PropDialog(BACKEND); PROPDIALOG->setSize(pageSize); @@ -410,7 +420,7 @@ void MainUI::slotPageLoaded(int page){ ui->actionStart_Here->setEnabled(true); ui->actionStart_Begin->setEnabled(true); pageAct->setVisible(true); - //qDebug() << " - Document Setup: All pages loaded"; + qDebug() << " - Document Setup: All pages loaded"; QTimer::singleShot(10, WIDGET, SLOT(updatePreview())); //start loading the file preview }else{ progress->setValue(finished); @@ -418,7 +428,7 @@ void MainUI::slotPageLoaded(int page){ } void MainUI::paintToPrinter(QPrinter *PRINTER){ - if(loadingHash.keys().length() != BACKEND->numPages()){ return; } + if(BACKEND->hashSize() != BACKEND->numPages()){ return; } //qDebug() << "paintToPrinter"; int pages = BACKEND->numPages(); int firstpage = 0; @@ -426,7 +436,6 @@ void MainUI::paintToPrinter(QPrinter *PRINTER){ bool collate = PRINTER->collateCopies(); bool reverse = (PRINTER->pageOrder()==QPrinter::LastPageFirst); qDebug() << "PRINTER DPI:" << PRINTER->resolution() << PRINTER->supportedResolutions(); - //return; if(PRINTER->resolution() < 300){ //Try to get 300 DPI resolution at least PRINTER->setResolution(300); @@ -450,24 +459,21 @@ void MainUI::paintToPrinter(QPrinter *PRINTER){ //for(int c=1; c<copies && !collate; c++){ pageCount << i; } //add any copies of this page as needed } //qDebug() << "Got Page Range:" << pageCount; - //QT 5.9+ : Do not need to manually reverse the pages (already handled internally) - if(reverse){ + if(reverse) { //Need to reverse the order of the list QList<int> tmp = pageCount; pageCount.clear(); for(int i=tmp.length()-1; i>=0; i--){ pageCount << tmp[i]; } //qDebug() << " - reversed:" << pageCount; } - - //QT 5.9+ : Do not need to manually stack "copies". Already handled internally + //QT 5.9+ : Do not need to manually stack "copies". Already handled internally; /*if(collate && copies>0){ QList<int> orig = pageCount; //original array of pages for(int c=1; c<copies; c++){ pageCount << orig; //add a new copy of the entire page range } }*/ - //qDebug() << "Final Page Range:" << pageCount; //Generate the sizing information for the printer QSize sz(PRINTER->pageRect().width(), PRINTER->pageRect().height()); @@ -490,7 +496,7 @@ void MainUI::paintToPrinter(QPrinter *PRINTER){ //qDebug() << "Printing Page:" << pageCount[i]; progress->setValue(i); QApplication::processEvents(); - QImage img = loadingHash[pageCount[i]].scaled(sz, Qt::KeepAspectRatio, Qt::SmoothTransformation); + QImage img = BACKEND->imageHash(pageCount[i]).scaled(sz, Qt::KeepAspectRatio, Qt::SmoothTransformation); //Now draw the image painter.drawImage(0,0,img); } @@ -567,6 +573,10 @@ void MainUI::keyPressEvent(QKeyEvent *event){ /*qDebug() << "Send Wheel Event"; QWheelEvent wEvent( WIDGET->mapFromGlobal(QCursor::pos()), QCursor::pos(),QPoint(0,0), QPoint(0,30), 0, Qt::Vertical, Qt::LeftButton, Qt::NoModifier); QApplication::sendEvent(WIDGET, &wEvent);*/ + }else if(event->key() == Qt::Key_Enter) { + /*if(ui->findGroup->hasFocus()) { + find(ui->textEdit->text(), true); + }*/ }else{ QMainWindow::keyPressEvent(event); } @@ -598,7 +608,7 @@ void MainUI::find(QString text, bool forward) { delete td; results.clear(); } - QTimer::singleShot(10, WIDGET, SLOT(updatePreview())); + WIDGET->updatePreview(); ui->resultsLabel->setText(""); //Get the new search results results = BACKEND->searchDocument(text, matchCase); @@ -628,7 +638,6 @@ void MainUI::find(QString text, bool forward) { //qDebug() << "Jump to page: " << currentText.page; - //Current Bug: Does not highlight results[0] WIDGET->highlightText(currentText); }else{ ui->resultsLabel->setText("No results found"); diff --git a/src-qt5/desktop-utils/lumina-pdf/mainUI.h b/src-qt5/desktop-utils/lumina-pdf/mainUI.h index 74badbfd..311bb46d 100644 --- a/src-qt5/desktop-utils/lumina-pdf/mainUI.h +++ b/src-qt5/desktop-utils/lumina-pdf/mainUI.h @@ -27,88 +27,85 @@ #include "textData.h" namespace Ui{ - class MainUI; + class MainUI; }; class MainUI : public QMainWindow{ - Q_OBJECT + Q_OBJECT public: - MainUI(); - ~MainUI(); + MainUI(); + ~MainUI(); - void loadFile(QString path); + void loadFile(QString path); private: - QSizeF pageSize; - PrintWidget *WIDGET; - Ui::MainUI *ui; - PropDialog *PROPDIALOG; - QPrintDialog *PrintDLG; - QString lastdir; - bool matchCase; - QList<TextData*> results; - int currentHighlight; - - //Other Interface elements - QProgressBar *progress; - QAction *progAct; //action associated with the progressbar - QTimer *clockTimer; - QMenu *contextMenu; - //QFrame *frame_presenter; - QLabel *label_clock, *label_page; - QAction *clockAct, *pageAct; - - //PDF Page Loading cache variables - Renderer *BACKEND; - QHash<int, QImage> loadingHash; - - void loadPage(int num, MainUI *obj, QSize dpi); - - //Functions/variables for the presentation mode - PresentationLabel *presentationLabel; - QScreen *getScreen(bool current, bool &cancelled); - int CurrentPage; - void startPresentation(bool atStart); - void ShowPage(int page); - void endPresentation(); + QSizeF pageSize; + PrintWidget *WIDGET; + Ui::MainUI *ui; + PropDialog *PROPDIALOG; + QPrintDialog *PrintDLG; + QString lastdir; + bool matchCase; + QList<TextData*> results; + QList<int> loadingQueue; + int currentHighlight; + + //Other Interface elements + QProgressBar *progress; + QAction *progAct; //action associated with the progressbar + QTimer *clockTimer; + QMenu *contextMenu; + //QFrame *frame_presenter; + QLabel *label_clock, *label_page; + QAction *clockAct, *pageAct; + + //PDF Page Loading cache variables + Renderer *BACKEND; + + void loadPage(int num, MainUI *obj, QSize dpi, int degrees); + + //Functions/variables for the presentation mode + PresentationLabel *presentationLabel; + QScreen *getScreen(bool current, bool &cancelled); + int CurrentPage; + void startPresentation(bool atStart); + void ShowPage(int page); + void endPresentation(); private slots: - void startLoadingPages(); - void slotPageLoaded(int); + void startLoadingPages(int degrees = 0); + void slotPageLoaded(int); - //Simplification routines - void nextPage(){ ShowPage( WIDGET->currentPage()+1 ); } //currentPage() starts at 1 rather than 0 - void prevPage(){ ShowPage( WIDGET->currentPage()-1 ); } //currentPage() starts at 1 rather than 0 - void firstPage(){ ShowPage(1); } - void lastPage(){ ShowPage(BACKEND->numPages()); } - void startPresentationHere(){ startPresentation(false); } - void startPresentationBeginning(){ startPresentation(true); } - void closePresentation(){ endPresentation(); } + //Simplification routines + void nextPage(){ ShowPage( WIDGET->currentPage()+1 ); } //currentPage() starts at 1 rather than 0 + void prevPage(){ ShowPage( WIDGET->currentPage()-1 ); } //currentPage() starts at 1 rather than 0 + void firstPage(){ ShowPage(1); } + void lastPage(){ ShowPage(BACKEND->numPages()); } + void startPresentationHere(){ startPresentation(false); } + void startPresentationBeginning(){ startPresentation(true); } + void closePresentation(){ endPresentation(); } - void find(QString text, bool forward); - void showBookmarks(); + void find(QString text, bool forward); + void showBookmarks(); - void paintToPrinter(QPrinter *PRINTER); + void paintToPrinter(QPrinter *PRINTER); - //Button Slots - void OpenNewFile(); + //Button Slots + void OpenNewFile(); - //Other interface slots - void updateClock(); - void updatePageNumber(); - void showContextMenu(const QPoint&){ contextMenu->popup(QCursor::pos()); } - void updateContextMenu(); - //void setScroll(bool); - -signals: - void PageLoaded(int); + //Other interface slots + void updateClock(); + void updatePageNumber(); + void showContextMenu(const QPoint&){ contextMenu->popup(QCursor::pos()); } + void updateContextMenu(); + //void setScroll(bool); protected: - void keyPressEvent(QKeyEvent*); - void wheelEvent(QWheelEvent*); - void closeEvent(QCloseEvent *ev){ - endPresentation(); - QMainWindow::closeEvent(ev); - } + void keyPressEvent(QKeyEvent*); + void wheelEvent(QWheelEvent*); + void closeEvent(QCloseEvent *ev){ + endPresentation(); + QMainWindow::closeEvent(ev); + } }; #endif diff --git a/src-qt5/desktop-utils/lumina-pdf/propDialog.cpp b/src-qt5/desktop-utils/lumina-pdf/propDialog.cpp index c40f537e..c721f65f 100644 --- a/src-qt5/desktop-utils/lumina-pdf/propDialog.cpp +++ b/src-qt5/desktop-utils/lumina-pdf/propDialog.cpp @@ -41,8 +41,7 @@ PropDialog::PropDialog(Renderer *Backend) : QDialog(), ui(new Ui::PropDialog()){ ui->keywordE->setText( info.value("keywords").toString() ); ui->createdEntry->setText( info.value("dt_created").toString() ); ui->modifiedEntry->setText( info.value("dt_modified").toString() ); - ui->numberL->setText( QString::number(Backend->numPages()) ); - + ui->numberL->setText( ui->numberL->text() + QString::number(Backend->numPages()) ); } //Load size from mainUI after pages have loaded diff --git a/src-qt5/desktop-utils/lumina-pdf/propDialog.h b/src-qt5/desktop-utils/lumina-pdf/propDialog.h index a09f2563..23b8c877 100644 --- a/src-qt5/desktop-utils/lumina-pdf/propDialog.h +++ b/src-qt5/desktop-utils/lumina-pdf/propDialog.h @@ -12,19 +12,16 @@ #include "Renderer.h" namespace Ui{ - class PropDialog; + class PropDialog; }; class PropDialog : public QDialog { Q_OBJECT public: PropDialog(Renderer *Backend); - void setSize(QSizeF); private: - //void setInfo(fz_context*, pdf_obj*, QTextEdit*, QString); - Ui::PropDialog *ui; }; #endif diff --git a/src-qt5/desktop-utils/lumina-pdf/textData.h b/src-qt5/desktop-utils/lumina-pdf/textData.h index 546920b3..9bf7e5bb 100644 --- a/src-qt5/desktop-utils/lumina-pdf/textData.h +++ b/src-qt5/desktop-utils/lumina-pdf/textData.h @@ -4,28 +4,32 @@ #include <QRect> class TextData { - private: - QRect _loc; - bool _highlighted=false; - int _page=0; - QString _text=""; + private: + QRectF p_loc; + bool p_highlighted=false; + int p_page=0; + QString p_text=""; + //int p_degrees=0; - public: - TextData(QRect _loc, int _page, QString _text) { - this->_loc = _loc; - this->_page = _page; - this->_text = _text; - } + public: + TextData(QRectF _loc, int _page, QString _text) : + p_loc(_loc), + p_page(_page), + p_text(_text) + //p_degrees(_degrees) + { } - QRect loc() { return this->_loc; } - bool highlighted() { return this->_highlighted; } - int page() { return this->_page; } - QString text() { return this->_text; } - - void loc(QRect loc) { this->_loc = loc; } - void highlighted(bool highlighted) { this->_highlighted = highlighted; } - void page(int page) { this->_page = page; } - void text(QString text) { this->_text = text; } + QRectF loc() { return p_loc; } + bool highlighted() { return p_highlighted; } + int page() { return p_page; } + QString text() { return p_text; } + //int degrees() { return p_degrees; } + + void loc(QRect loc) { p_loc = loc; } + void highlighted(bool highlighted) { p_highlighted = highlighted; } + void page(int page) { p_page = page; } + void text(QString text) { p_text = text; } + //void degrees(int degrees) { p_degrees = degrees; } }; #endif |