Rendering error reporting dialog

This commit is contained in:
Jakub Melka
2019-02-24 19:42:00 +01:00
parent 60bb835a4e
commit 0666f976b1
11 changed files with 330 additions and 2 deletions

View File

@ -51,7 +51,8 @@ SOURCES += \
sources/pdfcolorspaces.cpp \ sources/pdfcolorspaces.cpp \
sources/pdfrenderer.cpp \ sources/pdfrenderer.cpp \
sources/pdfpagecontentprocessor.cpp \ sources/pdfpagecontentprocessor.cpp \
sources/pdfpainter.cpp sources/pdfpainter.cpp \
sources/pdfrenderingerrorswidget.cpp
HEADERS += \ HEADERS += \
sources/pdfobject.h \ sources/pdfobject.h \
@ -75,7 +76,8 @@ HEADERS += \
sources/pdfrenderer.h \ sources/pdfrenderer.h \
sources/pdfpagecontentprocessor.h \ sources/pdfpagecontentprocessor.h \
sources/pdfpainter.h \ sources/pdfpainter.h \
sources/pdfutils.h sources/pdfutils.h \
sources/pdfrenderingerrorswidget.h
unix { unix {
target.path = /usr/lib target.path = /usr/lib
@ -87,3 +89,6 @@ CONFIG += force_debug_info
QMAKE_CXXFLAGS += /std:c++latest /utf-8 QMAKE_CXXFLAGS += /std:c++latest /utf-8
FORMS += \
sources/pdfrenderingerrorswidget.ui

View File

@ -535,10 +535,38 @@ void PDFDrawWidgetProxy::draw(QPainter* painter, QRect rect)
PDFRenderer renderer(m_controller->getDocument()); PDFRenderer renderer(m_controller->getDocument());
QList<PDFRenderError> errors = renderer.render(painter, placedRect, item.pageIndex); QList<PDFRenderError> errors = renderer.render(painter, placedRect, item.pageIndex);
if (!errors.empty())
{
emit renderingError(item.pageIndex, errors);
}
} }
} }
} }
std::vector<PDFInteger> PDFDrawWidgetProxy::getPagesIntersectingRect(QRect rect) const
{
std::vector<PDFInteger> 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) void PDFDrawWidgetProxy::performOperation(Operation operation)
{ {
switch (operation) switch (operation)

View File

@ -20,6 +20,7 @@
#include "pdfglobal.h" #include "pdfglobal.h"
#include "pdfdocument.h" #include "pdfdocument.h"
#include "pdfrenderer.h"
#include <QRectF> #include <QRectF>
#include <QObject> #include <QObject>
@ -177,11 +178,16 @@ public:
/// Returns the page layout /// Returns the page layout
PageLayout getPageLayout() const { return m_controller->getPageLayout(); } PageLayout getPageLayout() const { return m_controller->getPageLayout(); }
/// Returns pages, which are intersecting rectangle (even partially)
/// \param rect Rectangle to test
std::vector<PDFInteger> getPagesIntersectingRect(QRect rect) const;
static constexpr PDFReal ZOOM_STEP = 1.2; static constexpr PDFReal ZOOM_STEP = 1.2;
signals: signals:
void drawSpaceChanged(); void drawSpaceChanged();
void pageLayoutChanged(); void pageLayoutChanged();
void renderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors);
private: private:
struct LayoutItem struct LayoutItem

View File

@ -49,6 +49,7 @@ PDFWidget::PDFWidget(QWidget* parent) :
m_proxy = new PDFDrawWidgetProxy(this); m_proxy = new PDFDrawWidgetProxy(this);
m_proxy->init(this); m_proxy->init(this);
connect(m_proxy, &PDFDrawWidgetProxy::renderingError, this, &PDFWidget::onRenderingError);
} }
PDFWidget::~PDFWidget() PDFWidget::~PDFWidget()
@ -61,6 +62,24 @@ void PDFWidget::setDocument(const PDFDocument* document)
m_proxy->setDocument(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<PDFRenderError>& 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) : PDFDrawWidget::PDFDrawWidget(PDFWidget* widget, QWidget* parent) :
QWidget(parent), QWidget(parent),
m_widget(widget), m_widget(widget),
@ -74,6 +93,11 @@ PDFDrawWidget::~PDFDrawWidget()
} }
std::vector<PDFInteger> PDFDrawWidget::getCurrentPages() const
{
return m_widget->getDrawWidgetProxy()->getPagesIntersectingRect(this->rect());
}
QSize PDFDrawWidget::minimumSizeHint() const QSize PDFDrawWidget::minimumSizeHint() const
{ {
return QSize(200, 200); return QSize(200, 200);

View File

@ -20,6 +20,7 @@
#define PDFDRAWWIDGET_H #define PDFDRAWWIDGET_H
#include "pdfglobal.h" #include "pdfglobal.h"
#include "pdfrenderer.h"
#include <QWidget> #include <QWidget>
#include <QScrollBar> #include <QScrollBar>
@ -38,6 +39,8 @@ public:
explicit PDFWidget(QWidget* parent); explicit PDFWidget(QWidget* parent);
virtual ~PDFWidget() override; virtual ~PDFWidget() override;
using PageRenderingErrors = std::map<PDFInteger, QList<PDFRenderError>>;
/// Sets the document to be viewed in this widget. Document can be nullptr, /// Sets the document to be viewed in this widget. Document can be nullptr,
/// in that case, widget contents are cleared. /// in that case, widget contents are cleared.
/// \param document Document /// \param document Document
@ -47,12 +50,20 @@ public:
QScrollBar* getHorizontalScrollbar() const { return m_horizontalScrollBar; } QScrollBar* getHorizontalScrollbar() const { return m_horizontalScrollBar; }
QScrollBar* getVerticalScrollbar() const { return m_verticalScrollBar; } QScrollBar* getVerticalScrollbar() const { return m_verticalScrollBar; }
PDFDrawWidgetProxy* getDrawWidgetProxy() const { return m_proxy; } PDFDrawWidgetProxy* getDrawWidgetProxy() const { return m_proxy; }
const PageRenderingErrors* getPageRenderingErrors() const { return &m_pageRenderingErrors; }
int getPageRenderingErrorCount() const;
signals:
void pageRenderingErrorsChanged(PDFInteger pageIndex, int errorsCount);
private: private:
void onRenderingError(PDFInteger pageIndex, const QList<PDFRenderError>& errors);
PDFDrawWidget* m_drawWidget; PDFDrawWidget* m_drawWidget;
QScrollBar* m_horizontalScrollBar; QScrollBar* m_horizontalScrollBar;
QScrollBar* m_verticalScrollBar; QScrollBar* m_verticalScrollBar;
PDFDrawWidgetProxy* m_proxy; PDFDrawWidgetProxy* m_proxy;
PageRenderingErrors m_pageRenderingErrors;
}; };
class PDFFORQTLIBSHARED_EXPORT PDFDrawWidget : public QWidget class PDFFORQTLIBSHARED_EXPORT PDFDrawWidget : public QWidget
@ -63,6 +74,9 @@ public:
explicit PDFDrawWidget(PDFWidget* widget, QWidget* parent); explicit PDFDrawWidget(PDFWidget* widget, QWidget* parent);
virtual ~PDFDrawWidget() override; virtual ~PDFDrawWidget() override;
/// Returns page indices, which are currently displayed in the widget
std::vector<PDFInteger> getCurrentPages() const;
virtual QSize minimumSizeHint() const override; virtual QSize minimumSizeHint() const override;
protected: protected:

View File

@ -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 <https://www.gnu.org/licenses/>.
#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<PDFInteger> 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

View File

@ -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 <https://www.gnu.org/licenses/>.
#ifndef PDFRENDERINGERRORSWIDGET_H
#define PDFRENDERINGERRORSWIDGET_H
#include "pdfglobal.h"
#include <QDialog>
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

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PDFRenderingErrorsWidget</class>
<widget class="QDialog" name="PDFRenderingErrorsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>798</width>
<height>510</height>
</rect>
</property>
<property name="windowTitle">
<string>Rendering errors</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeWidget" name="renderErrorsTreeWidget">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PDFRenderingErrorsWidget</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PDFRenderingErrorsWidget</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -23,6 +23,7 @@
#include "pdfstreamfilters.h" #include "pdfstreamfilters.h"
#include "pdfdrawwidget.h" #include "pdfdrawwidget.h"
#include "pdfdrawspacecontroller.h" #include "pdfdrawspacecontroller.h"
#include "pdfrenderingerrorswidget.h"
#include <QSettings> #include <QSettings>
#include <QFileDialog> #include <QFileDialog>
@ -76,6 +77,7 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget *parent) :
setFocusProxy(m_pdfWidget); setFocusProxy(m_pdfWidget);
connect(m_pdfWidget->getDrawWidgetProxy(), &pdf::PDFDrawWidgetProxy::pageLayoutChanged, this, &PDFViewerMainWindow::updatePageLayoutActions); connect(m_pdfWidget->getDrawWidgetProxy(), &pdf::PDFDrawWidgetProxy::pageLayoutChanged, this, &PDFViewerMainWindow::updatePageLayoutActions);
connect(m_pdfWidget, &pdf::PDFWidget::pageRenderingErrorsChanged, this, &PDFViewerMainWindow::onPageRenderingErrorsChanged, Qt::QueuedConnection);
readSettings(); readSettings();
updatePageLayoutActions(); updatePageLayoutActions();
@ -105,6 +107,14 @@ void PDFViewerMainWindow::onActionQuitTriggered()
close(); 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() void PDFViewerMainWindow::readSettings()
{ {
QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName()); 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 } // namespace pdfviewer

View File

@ -19,6 +19,7 @@
#define PDFVIEWERMAINWINDOW_H #define PDFVIEWERMAINWINDOW_H
#include "pdfcatalog.h" #include "pdfcatalog.h"
#include "pdfrenderer.h"
#include <QMainWindow> #include <QMainWindow>
#include <QSharedPointer> #include <QSharedPointer>
@ -54,10 +55,13 @@ private slots:
void on_actionPageLayoutTwoColumns_triggered(); void on_actionPageLayoutTwoColumns_triggered();
void on_actionFirstPageOnRightSide_triggered(); void on_actionFirstPageOnRightSide_triggered();
void on_actionRendering_Errors_triggered();
private: private:
void onActionOpenTriggered(); void onActionOpenTriggered();
void onActionCloseTriggered(); void onActionCloseTriggered();
void onActionQuitTriggered(); void onActionQuitTriggered();
void onPageRenderingErrorsChanged(pdf::PDFInteger pageIndex, int errorsCount);
void readSettings(); void readSettings();
void writeSettings(); void writeSettings();

View File

@ -53,9 +53,16 @@
</widget> </widget>
<addaction name="menuPage_Layout"/> <addaction name="menuPage_Layout"/>
</widget> </widget>
<widget class="QMenu" name="menuTools">
<property name="title">
<string>Tools</string>
</property>
<addaction name="actionRendering_Errors"/>
</widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
<addaction name="menuView"/> <addaction name="menuView"/>
<addaction name="menuGoTo"/> <addaction name="menuGoTo"/>
<addaction name="menuTools"/>
</widget> </widget>
<widget class="QToolBar" name="mainToolBar"> <widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea"> <attribute name="toolBarArea">
@ -139,6 +146,14 @@
<string>Ctrl+5</string> <string>Ctrl+5</string>
</property> </property>
</action> </action>
<action name="actionRendering_Errors">
<property name="text">
<string>Rendering Errors</string>
</property>
<property name="shortcut">
<string>Ctrl+E</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources/> <resources/>