// 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 "aboutdialog.h" #include "pdfwidgetutils.h" #include "pdfdocumentreader.h" #include #include #include #include #include #include namespace pdfdocdiff { MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_progress(new pdf::PDFProgress(this)), m_taskbarButton(new QWinTaskbarButton(this)), m_progressTaskbarIndicator(nullptr), m_diff(nullptr), m_isChangingProgressStep(false), m_dontDisplayErrorMessage(false) { ui->setupUi(this); setMinimumSize(pdf::PDFWidgetUtils::scaleDPI(this, QSize(800, 600))); // Initialize task bar progress m_progressTaskbarIndicator = m_taskbarButton->progress(); ui->actionGet_Source->setData(int(Operation::GetSource)); ui->actionAbout->setData(int(Operation::About)); ui->actionOpen_Left->setData(int(Operation::OpenLeft)); ui->actionOpen_Right->setData(int(Operation::OpenRight)); ui->actionCompare->setData(int(Operation::Compare)); ui->actionClose->setData(int(Operation::Close)); QToolBar* mainToolbar = addToolBar(tr("Main")); mainToolbar->setObjectName("main_toolbar"); mainToolbar->addActions({ ui->actionOpen_Left, ui->actionOpen_Right }); mainToolbar->addSeparator(); mainToolbar->addAction(ui->actionCompare); QSize iconSize = pdf::PDFWidgetUtils::scaleDPI(this, QSize(24, 24)); auto toolbars = findChildren(); for (QToolBar* toolbar : toolbars) { toolbar->setIconSize(iconSize); ui->menuToolbars->addAction(toolbar->toggleViewAction()); } connect(&m_mapper, QOverload::of(&QSignalMapper::mapped), this, &MainWindow::onMappedActionTriggered); 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()); } } connect(m_progress, &pdf::PDFProgress::progressStarted, this, &MainWindow::onProgressStarted); connect(m_progress, &pdf::PDFProgress::progressStep, this, &MainWindow::onProgressStep); connect(m_progress, &pdf::PDFProgress::progressFinished, this, &MainWindow::onProgressFinished); m_diff.setProgress(m_progress); m_diff.setOption(pdf::PDFDiff::Asynchronous, true); connect(&m_diff, &pdf::PDFDiff::comparationFinished, this, &MainWindow::onComparationFinished); m_diff.setLeftDocument(&m_leftDocument); m_diff.setRightDocument(&m_rightDocument); loadSettings(); updateActions(); } MainWindow::~MainWindow() { saveSettings(); delete ui; } void MainWindow::showEvent(QShowEvent* event) { Q_UNUSED(event); m_taskbarButton->setWindow(windowHandle()); } void MainWindow::closeEvent(QCloseEvent* event) { BaseClass::closeEvent(event); m_diff.stop(); } void MainWindow::onMappedActionTriggered(int actionId) { performOperation(static_cast(actionId)); } void MainWindow::onComparationFinished() { auto result = m_diff.getResult().getResult(); if (!result && !m_dontDisplayErrorMessage) { QMessageBox::critical(this, tr("Error"), result.getErrorMessage()); } } 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(); } bool MainWindow::canPerformOperation(Operation operation) const { switch (operation) { case Operation::OpenLeft: case Operation::OpenRight: case Operation::Compare: case Operation::Close: case Operation::GetSource: case Operation::About: return true; default: Q_ASSERT(false); break; } return false; } void MainWindow::performOperation(Operation operation) { switch (operation) { case Operation::OpenLeft: { pdf::PDFTemporaryValueChange guard(&m_dontDisplayErrorMessage, true); m_diff.stop(); std::optional document = openDocument(); if (document) { m_leftDocument = std::move(*document); const size_t pageCount = m_leftDocument.getCatalog()->getPageCount(); if (pageCount > 1) { ui->leftPageSelectionEdit->setText(QString("1-%2").arg(pageCount)); } else if (pageCount == 1) { ui->leftPageSelectionEdit->setText("1"); } else { ui->leftPageSelectionEdit->clear(); } } break; } case Operation::OpenRight: { pdf::PDFTemporaryValueChange guard(&m_dontDisplayErrorMessage, true); m_diff.stop(); std::optional document = openDocument(); if (document) { m_rightDocument = std::move(*document); const size_t pageCount = m_rightDocument.getCatalog()->getPageCount(); if (pageCount > 1) { ui->rightPageSelectionEdit->setText(QString("1-%2").arg(pageCount)); } else if (pageCount == 1) { ui->rightPageSelectionEdit->setText("1"); } else { ui->rightPageSelectionEdit->clear(); } } break; } case Operation::Compare: { pdf::PDFTemporaryValueChange guard(&m_dontDisplayErrorMessage, true); m_diff.stop(); QString errorMessage; pdf::PDFClosedIntervalSet rightPageIndices; pdf::PDFClosedIntervalSet leftPageIndices = pdf::PDFClosedIntervalSet::parse(1, qMax(1, m_leftDocument.getCatalog()->getPageCount()), ui->leftPageSelectionEdit->text(), &errorMessage); if (errorMessage.isEmpty()) { rightPageIndices = pdf::PDFClosedIntervalSet::parse(1, qMax(1, m_rightDocument.getCatalog()->getPageCount()), ui->rightPageSelectionEdit->text(), &errorMessage); } // Check if pages are succesfully parsed if (!errorMessage.isEmpty()) { QMessageBox::critical(this, tr("Error"), errorMessage); break; } leftPageIndices.translate(-1); rightPageIndices.translate(-1); m_diff.setPagesForLeftDocument(std::move(leftPageIndices)); m_diff.setPagesForRightDocument(std::move(rightPageIndices)); m_diff.start(); break; } case Operation::Close: { close(); break; } case Operation::GetSource: { QDesktopServices::openUrl(QUrl("https://github.com/JakubMelka/PDF4QT")); break; } case Operation::About: { PDFAboutDialog aboutDialog(this); aboutDialog.exec(); break; } default: { Q_ASSERT(false); break; } } updateActions(); } std::optional MainWindow::openDocument() { QString fileName = QFileDialog::getOpenFileName(this, tr("Select PDF document"), m_settings.directory, tr("PDF document (*.pdf)")); if (fileName.isEmpty()) { return std::nullopt; } 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) { return document; } else if (result == pdf::PDFDocumentReader::Result::Failed) { QMessageBox::critical(this, tr("Error"), errorMessage); } return pdf::PDFDocument(); } void MainWindow::onProgressStarted(pdf::ProgressStartupInfo info) { m_progressTaskbarIndicator->setRange(0, 100); m_progressTaskbarIndicator->reset(); m_progressTaskbarIndicator->show(); } void MainWindow::onProgressStep(int percentage) { if (m_isChangingProgressStep) { return; } pdf::PDFTemporaryValueChange guard(&m_isChangingProgressStep, true); m_progressTaskbarIndicator->setValue(percentage); } void MainWindow::onProgressFinished() { m_progressTaskbarIndicator->hide(); } } // namespace pdfdocdiff