Page item delegate

This commit is contained in:
Jakub Melka 2021-07-07 18:30:03 +02:00
parent 522413f2dc
commit bdaaa01476
7 changed files with 332 additions and 6 deletions

View File

@ -43,6 +43,7 @@ INSTALLS += application
SOURCES += \
main.cpp \
mainwindow.cpp \
pageitemdelegate.cpp \
pageitemmodel.cpp
FORMS += \
@ -50,6 +51,7 @@ FORMS += \
HEADERS += \
mainwindow.h \
pageitemdelegate.h \
pageitemmodel.h
RESOURCES += \

View File

@ -19,6 +19,12 @@
#include "ui_mainwindow.h"
#include "pdfwidgetutils.h"
#include "pdfdocumentreader.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QInputDialog>
#include <QDesktopWidget>
namespace pdfdocpage
{
@ -26,18 +32,139 @@ namespace pdfdocpage
MainWindow::MainWindow(QWidget* parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
m_model(new PageItemModel(this))
m_model(new PageItemModel(this)),
m_delegate(new PageItemDelegate(m_model, this))
{
ui->setupUi(this);
ui->documentItemsView->setModel(m_model);
m_delegate->setPageImageSize(getDefaultPageImageSize());
ui->documentItemsView->setModel(m_model);
ui->documentItemsView->setItemDelegate(m_delegate);
setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(800, 600)));
loadSettings();
}
MainWindow::~MainWindow()
{
saveSettings();
delete ui;
}
QSize MainWindow::getMinPageImageSize() const
{
return pdf::PDFWidgetUtils::scaleDPI(this, QSize(40, 40));
}
QSize MainWindow::getDefaultPageImageSize() const
{
return pdf::PDFWidgetUtils::scaleDPI(this, QSize(100, 100));
}
QSize MainWindow::getMaxPageImageSize() const
{
return pdf::PDFWidgetUtils::scaleDPI(this, QSize(250, 250));
}
void MainWindow::on_actionClose_triggered()
{
close();
}
void MainWindow::on_actionAddDocument_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)"));
if (!fileName.isEmpty())
{
addDocument(fileName);
}
}
void MainWindow::updateActions()
{
}
void MainWindow::loadSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.beginGroup("MainWindow");
QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray();
if (geometry.isEmpty())
{
QRect availableGeometry = QApplication::desktop()->availableGeometry(this);
QRect windowRect(0, 0, availableGeometry.width() / 2, availableGeometry.height() / 2);
windowRect = windowRect.translated(availableGeometry.center() - windowRect.center());
setGeometry(windowRect);
}
else
{
restoreGeometry(geometry);
}
QByteArray state = settings.value("windowState", QByteArray()).toByteArray();
if (!state.isEmpty())
{
restoreState(state);
}
settings.endGroup();
settings.beginGroup("Settings");
m_settings.directory = settings.value("directory").toString();
settings.endGroup();
}
void MainWindow::saveSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
settings.beginGroup("MainWindow");
settings.setValue("geometry", saveGeometry());
settings.setValue("windowState", saveState());
settings.endGroup();
settings.beginGroup("Settings");
settings.setValue("directory", m_settings.directory);
settings.endGroup();
}
void MainWindow::addDocument(const QString& fileName)
{
auto queryPassword = [this](bool* ok)
{
*ok = false;
return QInputDialog::getText(this, tr("Encrypted document"), tr("Enter password to access document content"), QLineEdit::Password, QString(), ok);
};
// Mark current directory as this
QFileInfo fileInfo(fileName);
m_settings.directory = fileInfo.dir().absolutePath();
// Try to open a new document
pdf::PDFDocumentReader reader(nullptr, qMove(queryPassword), true, false);
pdf::PDFDocument document = reader.readFromFile(fileName);
QString errorMessage = reader.getErrorMessage();
pdf::PDFDocumentReader::Result result = reader.getReadingResult();
if (result == pdf::PDFDocumentReader::Result::OK)
{
const pdf::PDFSecurityHandler* securityHandler = document.getStorage().getSecurityHandler();
if (securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::Assemble) ||
securityHandler->isAllowed(pdf::PDFSecurityHandler::Permission::Modify))
{
m_model->addDocument(fileName, qMove(document));
}
else
{
QMessageBox::critical(this, tr("Error"), tr("Document security doesn't permit to organize pages."));
}
}
else if (result == pdf::PDFDocumentReader::Result::Failed)
{
QMessageBox::critical(this, tr("Error"), errorMessage);
}
updateActions();
}
} // namespace pdfdocpage

View File

@ -21,6 +21,7 @@
#include <QMainWindow>
#include "pageitemmodel.h"
#include "pageitemdelegate.h"
namespace Ui
{
@ -38,10 +39,30 @@ public:
explicit MainWindow(QWidget* parent);
virtual ~MainWindow() override;
QSize getMinPageImageSize() const;
QSize getDefaultPageImageSize() const;
QSize getMaxPageImageSize() const;
private slots:
void on_actionClose_triggered();
void on_actionAddDocument_triggered();
void updateActions();
private:
void loadSettings();
void saveSettings();
void addDocument(const QString& fileName);
struct Settings
{
QString directory;
};
Ui::MainWindow* ui;
PageItemModel* m_model;
PageItemDelegate* m_delegate;
Settings m_settings;
};
} // namespace pdfdocpage

View File

@ -0,0 +1,103 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of Pdf4Qt.
//
// Pdf4Qt 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
// with the written consent of the copyright owner, any later version.
//
// Pdf4Qt 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 Pdf4Qt. If not, see <https://www.gnu.org/licenses/>.
#include "pageitemdelegate.h"
#include "pageitemmodel.h"
#include "pdfwidgetutils.h"
#include <QPainter>
namespace pdfdocpage
{
PageItemDelegate::PageItemDelegate(PageItemModel* model, QObject* parent) :
BaseClass(parent),
m_model(model)
{
}
PageItemDelegate::~PageItemDelegate()
{
}
void PageItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
const PageGroupItem* item = m_model->getItem(index);
if (!item)
{
return;
}
QRect rect = option.rect;
QSize scaledSize = pdf::PDFWidgetUtils::scaleDPI(option.widget, m_pageImageSize);
int verticalSpacing = pdf::PDFWidgetUtils::scaleDPI_y(option.widget, getVerticalSpacing());
QRect pageBoundingRect = QRect(QPoint(rect.left() + (rect.width() - scaledSize.width()) / 2, rect.top() + verticalSpacing), scaledSize);
// Draw page preview
if (!item->groups.empty())
{
const PageGroupItem::GroupItem& groupItem = item->groups.front();
QSize pageImageSize = groupItem.rotatedPageDimensionsMM.scaled(pageBoundingRect.size(), Qt::KeepAspectRatio).toSize();
QRect pageImageRect(pageBoundingRect.topLeft() + QPoint((pageBoundingRect.width() - pageImageSize.width()) / 2, (pageBoundingRect.height() - pageImageSize.height()) / 2), pageImageSize);
painter->setPen(QPen(Qt::black));
painter->setBrush(Qt::white);
painter->drawRect(pageImageRect);
}
int textOffset = pageBoundingRect.bottom() + verticalSpacing;
QRect textRect = option.rect;
textRect.setTop(textOffset);
textRect.setHeight(option.fontMetrics.lineSpacing());
painter->drawText(textRect, Qt::AlignCenter | Qt::TextSingleLine, item->groupName);
textRect.translate(0, textRect.height());
painter->drawText(textRect, Qt::AlignCenter | Qt::TextSingleLine, item->pagesCaption);
if (option.state.testFlag(QStyle::State_Selected))
{
QColor selectedColor = option.palette.color(QPalette::Active, QPalette::Highlight);
selectedColor.setAlphaF(0.3);
painter->fillRect(rect, selectedColor);
}
}
QSize PageItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
{
Q_UNUSED(index);
QSize scaledSize = pdf::PDFWidgetUtils::scaleDPI(option.widget, m_pageImageSize);
int height = scaledSize.height() + option.fontMetrics.lineSpacing() * 2 + 2 * pdf::PDFWidgetUtils::scaleDPI_y(option.widget, getVerticalSpacing());
int width = qMax(pdf::PDFWidgetUtils::scaleDPI_x(option.widget, 40), scaledSize.width() + 2 * pdf::PDFWidgetUtils::scaleDPI_x(option.widget, getHorizontalSpacing()));
return QSize(height, width);
}
QSize PageItemDelegate::getPageImageSize() const
{
return m_pageImageSize;
}
void PageItemDelegate::setPageImageSize(const QSize& pageImageSize)
{
m_pageImageSize = pageImageSize;
}
} // namespace pdfdocpage

View File

@ -0,0 +1,55 @@
// Copyright (C) 2021 Jakub Melka
//
// This file is part of Pdf4Qt.
//
// Pdf4Qt 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
// with the written consent of the copyright owner, any later version.
//
// Pdf4Qt 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 Pdf4Qt. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDOCPAGEORGANIZER_PAGEITEMDELEGATE_H
#define PDFDOCPAGEORGANIZER_PAGEITEMDELEGATE_H
#include <QAbstractItemDelegate>
namespace pdfdocpage
{
class PageItemModel;
class PageItemDelegate : public QAbstractItemDelegate
{
Q_OBJECT
private:
using BaseClass = QAbstractItemDelegate;
public:
explicit PageItemDelegate(PageItemModel* model, QObject* parent);
virtual ~PageItemDelegate() override;
virtual void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
virtual QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
QSize getPageImageSize() const;
void setPageImageSize(const QSize& pageImageSize);
private:
static constexpr int getVerticalSpacing() { return 5; }
static constexpr int getHorizontalSpacing() { return 5; }
PageItemModel* m_model;
QSize m_pageImageSize;
};
} // namespace pdfdocpage
#endif // PDFDOCPAGEORGANIZER_PAGEITEMDELEGATE_H

View File

@ -55,7 +55,7 @@ QModelIndex PageItemModel::parent(const QModelIndex& index) const
int PageItemModel::rowCount(const QModelIndex& parent) const
{
if (!parent.isValid())
if (parent.isValid())
{
return 0;
}
@ -65,7 +65,7 @@ int PageItemModel::rowCount(const QModelIndex& parent) const
int PageItemModel::columnCount(const QModelIndex& parent) const
{
if (!parent.isValid())
if (parent.isValid())
{
return 0;
}
@ -112,6 +112,19 @@ int PageItemModel::addDocument(QString fileName, pdf::PDFDocument document)
return newIndex;
}
const PageGroupItem* PageItemModel::getItem(const QModelIndex& index) const
{
if (index.isValid())
{
if (index.row() < m_pageGroupItems.size())
{
return &m_pageGroupItems.at(index.row());
}
}
return nullptr;
}
void PageItemModel::createDocumentGroup(int index)
{
const DocumentItem& item = m_documents.at(index);
@ -134,7 +147,7 @@ void PageItemModel::createDocumentGroup(int index)
PageGroupItem::GroupItem groupItem;
groupItem.documentIndex = index;
groupItem.pageIndex = i;
groupItem.rotatedPageDimensionsMM = item.document.getCatalog()->getPage(i)->getRotatedMediaBoxMM().size();
groupItem.rotatedPageDimensionsMM = item.document.getCatalog()->getPage(i - 1)->getRotatedMediaBoxMM().size();
newItem.groups.push_back(qMove(groupItem));
}

View File

@ -70,6 +70,11 @@ public:
/// \returns Identifier of the document (internal index)
int addDocument(QString fileName, pdf::PDFDocument document);
/// Returns item at a given index. If item doesn't exist,
/// then nullptr is returned.
/// \param index Index
const PageGroupItem* getItem(const QModelIndex& index) const;
private:
void createDocumentGroup(int index);
QString getGroupNameFromDocument(int index) const;