PDF4QT/Pdf4QtDocPageOrganizer/mainwindow.cpp

404 lines
14 KiB
C++
Raw Normal View History

2021-07-05 16:57:08 +02:00
// 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 "mainwindow.h"
#include "ui_mainwindow.h"
2021-07-06 18:35:29 +02:00
#include "pdfwidgetutils.h"
2021-07-07 18:30:03 +02:00
#include "pdfdocumentreader.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QInputDialog>
#include <QDesktopWidget>
2021-07-08 13:48:27 +02:00
#include <QClipboard>
#include <QToolBar>
2021-07-06 18:35:29 +02:00
2021-07-05 16:57:08 +02:00
namespace pdfdocpage
{
2021-07-07 18:30:03 +02:00
MainWindow::MainWindow(QWidget* parent) :
2021-07-05 16:57:08 +02:00
QMainWindow(parent),
2021-07-06 18:35:29 +02:00
ui(new Ui::MainWindow),
2021-07-07 18:30:03 +02:00
m_model(new PageItemModel(this)),
m_delegate(new PageItemDelegate(m_model, this))
2021-07-05 16:57:08 +02:00
{
ui->setupUi(this);
2021-07-06 18:35:29 +02:00
2021-07-07 18:30:03 +02:00
m_delegate->setPageImageSize(getDefaultPageImageSize());
2021-07-06 18:35:29 +02:00
2021-07-07 18:30:03 +02:00
ui->documentItemsView->setModel(m_model);
ui->documentItemsView->setItemDelegate(m_delegate);
2021-07-06 18:35:29 +02:00
setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(800, 600)));
2021-07-07 18:30:03 +02:00
2021-07-08 13:48:27 +02:00
ui->actionCloneSelection->setData(int(Operation::CloneSelection));
ui->actionRemoveSelection->setData(int(Operation::RemoveSelection));
ui->actionReplaceSelection->setData(int(Operation::ReplaceSelection));
ui->actionRestoreRemovedItems->setData(int(Operation::RestoreRemovedItems));
ui->actionCut->setData(int(Operation::Cut));
ui->actionCopy->setData(int(Operation::Copy));
ui->actionPaste->setData(int(Operation::Paste));
ui->actionRotate_Left->setData(int(Operation::RotateLeft));
ui->actionRotate_Right->setData(int(Operation::RotateRight));
ui->actionGroup->setData(int(Operation::Group));
ui->actionUngroup->setData(int(Operation::Ungroup));
ui->actionSelect_None->setData(int(Operation::SelectNone));
ui->actionSelect_All->setData(int(Operation::SelectAll));
ui->actionSelect_Even->setData(int(Operation::SelectEven));
ui->actionSelect_Odd->setData(int(Operation::SelectOdd));
ui->actionSelect_Portrait->setData(int(Operation::SelectPortrait));
ui->actionSelect_Landscape->setData(int(Operation::SelectLandscape));
ui->actionZoom_In->setData(int(Operation::ZoomIn));
ui->actionZoom_Out->setData(int(Operation::ZoomOut));
ui->actionUnited_Document->setData(int(Operation::Unite));
ui->actionSeparate_to_Multiple_Documents->setData(int(Operation::Separate));
ui->actionSeparate_to_Multiple_Documents_Grouped->setData(int(Operation::SeparateGrouped));
QToolBar* mainToolbar = addToolBar(tr("Main"));
mainToolbar->setObjectName("main_toolbar");
2021-07-08 13:48:27 +02:00
mainToolbar->addAction(ui->actionAddDocument);
mainToolbar->addSeparator();
mainToolbar->addActions({ ui->actionCloneSelection, ui->actionRemoveSelection });
mainToolbar->addSeparator();
mainToolbar->addActions({ ui->actionCut, ui->actionCopy, ui->actionPaste });
mainToolbar->addSeparator();
mainToolbar->addActions({ ui->actionGroup, ui->actionUngroup });
QToolBar* insertToolbar = addToolBar(tr("Insert"));
insertToolbar->setObjectName("insert_toolbar");
2021-07-08 13:48:27 +02:00
insertToolbar->addActions({ ui->actionInsert_Page_from_PDF, ui->actionInsert_Image, ui->actionInsert_Empty_Page });
QToolBar* selectToolbar = addToolBar(tr("Select"));
selectToolbar->setObjectName("select_toolbar");
2021-07-08 13:48:27 +02:00
selectToolbar->addActions({ ui->actionSelect_None, ui->actionSelect_All, ui->actionSelect_Even, ui->actionSelect_Odd, ui->actionSelect_Portrait, ui->actionSelect_Landscape });
QToolBar* zoomToolbar = addToolBar(tr("Zoom"));
zoomToolbar->setObjectName("zoom_toolbar");
2021-07-08 13:48:27 +02:00
zoomToolbar->addActions({ ui->actionZoom_In, ui->actionZoom_Out });
QToolBar* makeToolbar = addToolBar(tr("Make"));
makeToolbar->setObjectName("make_toolbar");
2021-07-08 13:48:27 +02:00
makeToolbar->addActions({ ui->actionUnited_Document, ui->actionSeparate_to_Multiple_Documents, ui->actionSeparate_to_Multiple_Documents_Grouped });
QSize iconSize = pdf::PDFWidgetUtils::scaleDPI(this, QSize(24, 24));
auto toolbars = findChildren<QToolBar*>();
for (QToolBar* toolbar : toolbars)
2021-07-08 13:48:27 +02:00
{
toolbar->setIconSize(iconSize);
}
connect(&m_mapper, QOverload<int>::of(&QSignalMapper::mapped), this, &MainWindow::onMappedActionTriggered);
connect(ui->documentItemsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::updateActions);
QList<QAction*> actions = findChildren<QAction*>();
for (QAction* action : actions)
{
QVariant actionData = action->data();
if (actionData.isValid())
{
connect(action, &QAction::triggered, &m_mapper, QOverload<>::of(&QSignalMapper::map));
m_mapper.setMapping(action, actionData.toInt());
}
}
2021-07-07 18:30:03 +02:00
loadSettings();
2021-07-08 13:48:27 +02:00
updateActions();
2021-07-05 16:57:08 +02:00
}
MainWindow::~MainWindow()
{
2021-07-07 18:30:03 +02:00
saveSettings();
2021-07-05 16:57:08 +02:00
delete ui;
}
2021-07-07 18:30:03 +02:00
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);
}
}
2021-07-08 13:48:27 +02:00
void MainWindow::onMappedActionTriggered(int actionId)
2021-07-07 18:30:03 +02:00
{
2021-07-08 13:48:27 +02:00
performOperation(static_cast<Operation>(actionId));
}
2021-07-07 18:30:03 +02:00
2021-07-08 13:48:27 +02:00
void MainWindow::updateActions()
{
QList<QAction*> actions = findChildren<QAction*>();
for (QAction* action : actions)
{
QVariant actionData = action->data();
if (actionData.isValid())
{
action->setEnabled(canPerformOperation(static_cast<Operation>(actionData.toInt())));
}
}
2021-07-07 18:30:03 +02:00
}
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();
}
2021-07-08 13:48:27 +02:00
bool MainWindow::canPerformOperation(Operation operation) const
{
QModelIndexList selection = ui->documentItemsView->selectionModel()->selection().indexes();
const bool isSelected = !selection.isEmpty();
2021-07-09 19:50:00 +02:00
const bool isMultiSelected = selection.size() > 1;
2021-07-08 13:48:27 +02:00
const bool isModelEmpty = m_model->rowCount(QModelIndex()) == 0;
switch (operation)
{
case Operation::CloneSelection:
case Operation::RemoveSelection:
case Operation::ReplaceSelection:
return isSelected;
case Operation::RestoreRemovedItems:
2021-07-09 19:50:00 +02:00
return !m_model->isTrashBinEmpty();
2021-07-08 13:48:27 +02:00
case Operation::Cut:
case Operation::Copy:
return isSelected;
case Operation::Paste:
2021-07-11 17:17:13 +02:00
{
const QMimeData* mimeData = QApplication::clipboard()->mimeData();
return mimeData && mimeData->hasFormat(PageItemModel::getMimeDataType());
}
2021-07-08 13:48:27 +02:00
case Operation::RotateLeft:
case Operation::RotateRight:
return isSelected;
case Operation::Group:
2021-07-09 19:50:00 +02:00
return isMultiSelected;
2021-07-08 13:48:27 +02:00
case Operation::Ungroup:
return m_model->isGrouped(selection);
case Operation::SelectNone:
return isSelected;
case Operation::SelectAll:
case Operation::SelectEven:
case Operation::SelectOdd:
case Operation::SelectPortrait:
case Operation::SelectLandscape:
return !isModelEmpty;
case Operation::ZoomIn:
return m_delegate->getPageImageSize() != getMaxPageImageSize();
case Operation::ZoomOut:
return m_delegate->getPageImageSize() != getMinPageImageSize();
case Operation::Unite:
case Operation::Separate:
case Operation::SeparateGrouped:
return !isModelEmpty;
default:
Q_ASSERT(false);
break;
}
return false;
}
void MainWindow::performOperation(Operation operation)
{
switch (operation)
{
case Operation::CloneSelection:
case Operation::RemoveSelection:
case Operation::ReplaceSelection:
case Operation::RestoreRemovedItems:
case Operation::Cut:
case Operation::Copy:
case Operation::Paste:
case Operation::RotateLeft:
case Operation::RotateRight:
2021-07-09 19:50:00 +02:00
Q_ASSERT(false);
break;
case Operation::Group:
2021-07-09 19:50:00 +02:00
m_model->group(ui->documentItemsView->selectionModel()->selection().indexes());
break;
case Operation::Ungroup:
2021-07-09 19:50:00 +02:00
m_model->ungroup(ui->documentItemsView->selectionModel()->selection().indexes());
break;
case Operation::SelectNone:
ui->documentItemsView->clearSelection();
break;
case Operation::SelectAll:
ui->documentItemsView->selectAll();
break;
case Operation::SelectEven:
ui->documentItemsView->selectionModel()->select(m_model->getSelectionEven(), QItemSelectionModel::ClearAndSelect);
break;
case Operation::SelectOdd:
ui->documentItemsView->selectionModel()->select(m_model->getSelectionOdd(), QItemSelectionModel::ClearAndSelect);
break;
case Operation::SelectPortrait:
ui->documentItemsView->selectionModel()->select(m_model->getSelectionPortrait(), QItemSelectionModel::ClearAndSelect);
break;
case Operation::SelectLandscape:
ui->documentItemsView->selectionModel()->select(m_model->getSelectionLandscape(), QItemSelectionModel::ClearAndSelect);
break;
2021-07-08 13:48:27 +02:00
case Operation::ZoomIn:
{
QSize pageImageSize = m_delegate->getPageImageSize();
pageImageSize *= 1.2;
pageImageSize = pageImageSize.boundedTo(getMaxPageImageSize());
if (pageImageSize != m_delegate->getPageImageSize())
{
m_delegate->setPageImageSize(pageImageSize);
}
break;
}
case Operation::ZoomOut:
{
QSize pageImageSize = m_delegate->getPageImageSize();
pageImageSize /= 1.2;
pageImageSize = pageImageSize.expandedTo(getMinPageImageSize());
if (pageImageSize != m_delegate->getPageImageSize())
{
m_delegate->setPageImageSize(pageImageSize);
}
break;
}
case Operation::Unite:
case Operation::Separate:
case Operation::SeparateGrouped:
default:
Q_ASSERT(false);
break;
}
updateActions();
2021-07-08 13:48:27 +02:00
}
2021-07-05 16:57:08 +02:00
} // namespace pdfdocpage