diff --git a/PdfForQtLib/PdfForQtLib.pro b/PdfForQtLib/PdfForQtLib.pro index 342c656..3ad96bb 100644 --- a/PdfForQtLib/PdfForQtLib.pro +++ b/PdfForQtLib/PdfForQtLib.pro @@ -51,7 +51,8 @@ SOURCES += \ sources/pdfcolorspaces.cpp \ sources/pdfrenderer.cpp \ sources/pdfpagecontentprocessor.cpp \ - sources/pdfpainter.cpp + sources/pdfpainter.cpp \ + sources/pdfrenderingerrorswidget.cpp HEADERS += \ sources/pdfobject.h \ @@ -75,7 +76,8 @@ HEADERS += \ sources/pdfrenderer.h \ sources/pdfpagecontentprocessor.h \ sources/pdfpainter.h \ - sources/pdfutils.h + sources/pdfutils.h \ + sources/pdfrenderingerrorswidget.h unix { target.path = /usr/lib @@ -87,3 +89,6 @@ CONFIG += force_debug_info QMAKE_CXXFLAGS += /std:c++latest /utf-8 + +FORMS += \ + sources/pdfrenderingerrorswidget.ui diff --git a/PdfForQtLib/sources/pdfdrawspacecontroller.cpp b/PdfForQtLib/sources/pdfdrawspacecontroller.cpp index eac9b43..cc08181 100644 --- a/PdfForQtLib/sources/pdfdrawspacecontroller.cpp +++ b/PdfForQtLib/sources/pdfdrawspacecontroller.cpp @@ -535,10 +535,38 @@ void PDFDrawWidgetProxy::draw(QPainter* painter, QRect rect) PDFRenderer renderer(m_controller->getDocument()); QList errors = renderer.render(painter, placedRect, item.pageIndex); + + if (!errors.empty()) + { + emit renderingError(item.pageIndex, errors); + } } } } +std::vector PDFDrawWidgetProxy::getPagesIntersectingRect(QRect rect) const +{ + std::vector pages; + + // We assume, that no more, than 32 pages will be displayed in the rectangle + pages.reserve(32); + + // Iterate trough pages, place them and test, if they intersects with rectangle + for (const LayoutItem& item : m_layout.items) + { + // The offsets m_horizontalOffset and m_verticalOffset are offsets to the + // topleft point of the block. But block maybe doesn't start at (0, 0), + // so we must also use translation from the block beginning. + QRect placedRect = item.pageRect.translated(m_horizontalOffset - m_layout.blockRect.left(), m_verticalOffset - m_layout.blockRect.top()); + if (placedRect.intersects(rect)) + { + pages.push_back(item.pageIndex); + } + } + + return pages; +} + void PDFDrawWidgetProxy::performOperation(Operation operation) { switch (operation) diff --git a/PdfForQtLib/sources/pdfdrawspacecontroller.h b/PdfForQtLib/sources/pdfdrawspacecontroller.h index f2be291..f122492 100644 --- a/PdfForQtLib/sources/pdfdrawspacecontroller.h +++ b/PdfForQtLib/sources/pdfdrawspacecontroller.h @@ -20,6 +20,7 @@ #include "pdfglobal.h" #include "pdfdocument.h" +#include "pdfrenderer.h" #include #include @@ -177,11 +178,16 @@ public: /// Returns the page layout PageLayout getPageLayout() const { return m_controller->getPageLayout(); } + /// Returns pages, which are intersecting rectangle (even partially) + /// \param rect Rectangle to test + std::vector getPagesIntersectingRect(QRect rect) const; + static constexpr PDFReal ZOOM_STEP = 1.2; signals: void drawSpaceChanged(); void pageLayoutChanged(); + void renderingError(PDFInteger pageIndex, const QList& errors); private: struct LayoutItem diff --git a/PdfForQtLib/sources/pdfdrawwidget.cpp b/PdfForQtLib/sources/pdfdrawwidget.cpp index 3a48ccd..8f05abc 100644 --- a/PdfForQtLib/sources/pdfdrawwidget.cpp +++ b/PdfForQtLib/sources/pdfdrawwidget.cpp @@ -49,6 +49,7 @@ PDFWidget::PDFWidget(QWidget* parent) : m_proxy = new PDFDrawWidgetProxy(this); m_proxy->init(this); + connect(m_proxy, &PDFDrawWidgetProxy::renderingError, this, &PDFWidget::onRenderingError); } PDFWidget::~PDFWidget() @@ -61,6 +62,24 @@ void PDFWidget::setDocument(const PDFDocument* document) m_proxy->setDocument(document); } +int PDFWidget::getPageRenderingErrorCount() const +{ + int count = 0; + for (const auto& item : m_pageRenderingErrors) + { + count += item.second.size(); + } + return count; +} + +void PDFWidget::onRenderingError(PDFInteger pageIndex, const QList& errors) +{ + // Empty list of error should not be reported! + Q_ASSERT(!errors.empty()); + m_pageRenderingErrors[pageIndex] = errors; + emit pageRenderingErrorsChanged(pageIndex, errors.size()); +} + PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) : QWidget(parent), m_widget(widget), @@ -74,6 +93,11 @@ PDFDrawWidget::~PDFDrawWidget() } +std::vector PDFDrawWidget::getCurrentPages() const +{ + return m_widget->getDrawWidgetProxy()->getPagesIntersectingRect(this->rect()); +} + QSize PDFDrawWidget::minimumSizeHint() const { return QSize(200, 200); diff --git a/PdfForQtLib/sources/pdfdrawwidget.h b/PdfForQtLib/sources/pdfdrawwidget.h index 25448c4..befcacd 100644 --- a/PdfForQtLib/sources/pdfdrawwidget.h +++ b/PdfForQtLib/sources/pdfdrawwidget.h @@ -20,6 +20,7 @@ #define PDFDRAWWIDGET_H #include "pdfglobal.h" +#include "pdfrenderer.h" #include #include @@ -38,6 +39,8 @@ public: explicit PDFWidget(QWidget* parent); virtual ~PDFWidget() override; + using PageRenderingErrors = std::map>; + /// Sets the document to be viewed in this widget. Document can be nullptr, /// in that case, widget contents are cleared. /// \param document Document @@ -47,12 +50,20 @@ public: QScrollBar* getHorizontalScrollbar() const { return m_horizontalScrollBar; } QScrollBar* getVerticalScrollbar() const { return m_verticalScrollBar; } PDFDrawWidgetProxy* getDrawWidgetProxy() const { return m_proxy; } + const PageRenderingErrors* getPageRenderingErrors() const { return &m_pageRenderingErrors; } + int getPageRenderingErrorCount() const; + +signals: + void pageRenderingErrorsChanged(PDFInteger pageIndex, int errorsCount); private: + void onRenderingError(PDFInteger pageIndex, const QList& errors); + PDFDrawWidget* m_drawWidget; QScrollBar* m_horizontalScrollBar; QScrollBar* m_verticalScrollBar; PDFDrawWidgetProxy* m_proxy; + PageRenderingErrors m_pageRenderingErrors; }; class PDFFORQTLIBSHARED_EXPORT PDFDrawWidget : public QWidget @@ -63,6 +74,9 @@ public: explicit PDFDrawWidget(PDFWidget* widget, QWidget* parent); virtual ~PDFDrawWidget() override; + /// Returns page indices, which are currently displayed in the widget + std::vector getCurrentPages() const; + virtual QSize minimumSizeHint() const override; protected: diff --git a/PdfForQtLib/sources/pdfrenderingerrorswidget.cpp b/PdfForQtLib/sources/pdfrenderingerrorswidget.cpp new file mode 100644 index 0000000..7f57f77 --- /dev/null +++ b/PdfForQtLib/sources/pdfrenderingerrorswidget.cpp @@ -0,0 +1,95 @@ +// Copyright (C) 2019 Jakub Melka +// +// This file is part of PdfForQt. +// +// PdfForQt is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// PdfForQt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with PDFForQt. If not, see . + +#include "pdfrenderingerrorswidget.h" +#include "pdfdrawwidget.h" +#include "ui_pdfrenderingerrorswidget.h" + +namespace pdf +{ + +PDFRenderingErrorsWidget::PDFRenderingErrorsWidget(QWidget* parent, PDFWidget* pdfWidget) : + QDialog(parent), + ui(new Ui::PDFRenderingErrorsWidget) +{ + ui->setupUi(this); + + ui->renderErrorsTreeWidget->setColumnCount(3); + ui->renderErrorsTreeWidget->setColumnWidth(0, 100); + ui->renderErrorsTreeWidget->setColumnWidth(1, 300); + ui->renderErrorsTreeWidget->setHeaderLabels({ tr("Page"), tr("Error type"), tr("Description") }); + + Q_ASSERT(pdfWidget); + std::vector currentPages = pdfWidget->getDrawWidget()->getCurrentPages(); + qSort(currentPages); + + QTreeWidgetItem* scrollToItem = nullptr; + const PDFWidget::PageRenderingErrors* pageRenderingErrors = pdfWidget->getPageRenderingErrors(); + for (const auto& pageRenderingError : *pageRenderingErrors) + { + // TODO: udelat realna cisla stranek + const PDFInteger pageIndex = pageRenderingError.first; + QTreeWidgetItem* root = new QTreeWidgetItem(ui->renderErrorsTreeWidget, QStringList() << QString::number(pageIndex + 1) << QString() << QString()); + + for (const PDFRenderError& error : pageRenderingError.second) + { + QString typeString; + switch (error.type) + { + case RenderErrorType::Error: + { + typeString = tr("Error"); + break; + } + + case RenderErrorType::NotImplemented: + { + typeString = tr("Not implemented"); + break; + } + + default: + { + Q_ASSERT(false); + break; + } + } + + new QTreeWidgetItem(root, QStringList() << QString() << typeString << error.message); + } + + bool isCurrentPage = std::binary_search(currentPages.cbegin(), currentPages.cend(), pageIndex); + ui->renderErrorsTreeWidget->setItemExpanded(root, isCurrentPage); + + if (isCurrentPage && !scrollToItem) + { + scrollToItem = root; + } + } + + if (scrollToItem) + { + ui->renderErrorsTreeWidget->scrollToItem(scrollToItem, QAbstractItemView::EnsureVisible); + } +} + +PDFRenderingErrorsWidget::~PDFRenderingErrorsWidget() +{ + delete ui; +} + +} // namespace pdf diff --git a/PdfForQtLib/sources/pdfrenderingerrorswidget.h b/PdfForQtLib/sources/pdfrenderingerrorswidget.h new file mode 100644 index 0000000..f7d1657 --- /dev/null +++ b/PdfForQtLib/sources/pdfrenderingerrorswidget.h @@ -0,0 +1,48 @@ +// Copyright (C) 2019 Jakub Melka +// +// This file is part of PdfForQt. +// +// PdfForQt is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// PdfForQt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with PDFForQt. If not, see . + +#ifndef PDFRENDERINGERRORSWIDGET_H +#define PDFRENDERINGERRORSWIDGET_H + +#include "pdfglobal.h" + +#include + +namespace Ui +{ +class PDFRenderingErrorsWidget; +} + +namespace pdf +{ +class PDFWidget; + +class PDFFORQTLIBSHARED_EXPORT PDFRenderingErrorsWidget : public QDialog +{ + Q_OBJECT + +public: + explicit PDFRenderingErrorsWidget(QWidget* parent, PDFWidget* pdfWidget); + virtual ~PDFRenderingErrorsWidget() override; + +private: + Ui::PDFRenderingErrorsWidget* ui; +}; + +} // namespace pdf + +#endif // PDFRENDERINGERRORSWIDGET_H diff --git a/PdfForQtLib/sources/pdfrenderingerrorswidget.ui b/PdfForQtLib/sources/pdfrenderingerrorswidget.ui new file mode 100644 index 0000000..954bd99 --- /dev/null +++ b/PdfForQtLib/sources/pdfrenderingerrorswidget.ui @@ -0,0 +1,73 @@ + + + PDFRenderingErrorsWidget + + + + 0 + 0 + 798 + 510 + + + + Rendering errors + + + + + + + 1 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + PDFRenderingErrorsWidget + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PDFRenderingErrorsWidget + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/PdfForQtViewer/pdfviewermainwindow.cpp b/PdfForQtViewer/pdfviewermainwindow.cpp index 7035084..bad78ea 100644 --- a/PdfForQtViewer/pdfviewermainwindow.cpp +++ b/PdfForQtViewer/pdfviewermainwindow.cpp @@ -23,6 +23,7 @@ #include "pdfstreamfilters.h" #include "pdfdrawwidget.h" #include "pdfdrawspacecontroller.h" +#include "pdfrenderingerrorswidget.h" #include #include @@ -76,6 +77,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget *parent) : setFocusProxy(m_pdfWidget); connect(m_pdfWidget->getDrawWidgetProxy(), &pdf::PDFDrawWidgetProxy::pageLayoutChanged, this, &PDFViewerMainWindow::updatePageLayoutActions); + connect(m_pdfWidget, &pdf::PDFWidget::pageRenderingErrorsChanged, this, &PDFViewerMainWindow::onPageRenderingErrorsChanged, Qt::QueuedConnection); readSettings(); updatePageLayoutActions(); @@ -105,6 +107,14 @@ void PDFViewerMainWindow::onActionQuitTriggered() close(); } +void PDFViewerMainWindow::onPageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount) +{ + if (errorsCount > 0) + { + statusBar()->showMessage(tr("Rendering of page %1: %2 errors occured.").arg(pageIndex + 1).arg(errorsCount), 4000); + } +} + void PDFViewerMainWindow::readSettings() { QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); @@ -287,4 +297,10 @@ void PDFViewerMainWindow::on_actionFirstPageOnRightSide_triggered() } } +void PDFViewerMainWindow::on_actionRendering_Errors_triggered() +{ + pdf::PDFRenderingErrorsWidget renderingErrorsDialog(this, m_pdfWidget); + renderingErrorsDialog.exec(); +} + } // namespace pdfviewer diff --git a/PdfForQtViewer/pdfviewermainwindow.h b/PdfForQtViewer/pdfviewermainwindow.h index 2df12ed..64df6a4 100644 --- a/PdfForQtViewer/pdfviewermainwindow.h +++ b/PdfForQtViewer/pdfviewermainwindow.h @@ -19,6 +19,7 @@ #define PDFVIEWERMAINWINDOW_H #include "pdfcatalog.h" +#include "pdfrenderer.h" #include #include @@ -54,10 +55,13 @@ private slots: void on_actionPageLayoutTwoColumns_triggered(); void on_actionFirstPageOnRightSide_triggered(); + void on_actionRendering_Errors_triggered(); + private: void onActionOpenTriggered(); void onActionCloseTriggered(); void onActionQuitTriggered(); + void onPageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount); void readSettings(); void writeSettings(); diff --git a/PdfForQtViewer/pdfviewermainwindow.ui b/PdfForQtViewer/pdfviewermainwindow.ui index 077d888..cfd62a3 100644 --- a/PdfForQtViewer/pdfviewermainwindow.ui +++ b/PdfForQtViewer/pdfviewermainwindow.ui @@ -53,9 +53,16 @@ + + + Tools + + + + @@ -139,6 +146,14 @@ Ctrl+5 + + + Rendering Errors + + + Ctrl+E + +