// 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 . #include "mainwindow.h" #include "ui_mainwindow.h" #include "pdfwidgetutils.h" #include "pdfdocumentreader.h" #include #include #include #include #include #include namespace pdfdocpage { MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_model(new PageItemModel(this)), m_delegate(new PageItemDelegate(m_model, this)) { ui->setupUi(this); m_delegate->setPageImageSize(getDefaultPageImageSize()); ui->documentItemsView->setModel(m_model); ui->documentItemsView->setItemDelegate(m_delegate); setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(800, 600))); 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"); 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"); insertToolbar->addActions({ ui->actionInsert_Page_from_PDF, ui->actionInsert_Image, ui->actionInsert_Empty_Page }); QToolBar* selectToolbar = addToolBar(tr("Select")); selectToolbar->setObjectName("select_toolbar"); 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"); zoomToolbar->addActions({ ui->actionZoom_In, ui->actionZoom_Out }); QToolBar* makeToolbar = addToolBar(tr("Make")); makeToolbar->setObjectName("make_toolbar"); 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(); for (QToolBar* toolbar : toolbars) { toolbar->setIconSize(iconSize); } connect(&m_mapper, QOverload::of(&QSignalMapper::mapped), this, &MainWindow::onMappedActionTriggered); connect(ui->documentItemsView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MainWindow::updateActions); QList actions = findChildren(); 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()); } } loadSettings(); updateActions(); } 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::onMappedActionTriggered(int actionId) { performOperation(static_cast(actionId)); } void MainWindow::updateActions() { QList actions = findChildren(); for (QAction* action : actions) { QVariant actionData = action->data(); if (actionData.isValid()) { action->setEnabled(canPerformOperation(static_cast(actionData.toInt()))); } } } 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(); } bool MainWindow::canPerformOperation(Operation operation) const { QModelIndexList selection = ui->documentItemsView->selectionModel()->selection().indexes(); const bool isSelected = !selection.isEmpty(); const bool isModelEmpty = m_model->rowCount(QModelIndex()) == 0; switch (operation) { case Operation::CloneSelection: case Operation::RemoveSelection: case Operation::ReplaceSelection: return isSelected; case Operation::RestoreRemovedItems: return !m_trashBin.empty(); case Operation::Cut: case Operation::Copy: return isSelected; case Operation::Paste: return !QApplication::clipboard()->text().isEmpty(); case Operation::RotateLeft: case Operation::RotateRight: return isSelected; case Operation::Group: return isSelected; 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: break; case Operation::Group: case Operation::Ungroup: 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; 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(); } } // namespace pdfdocpage