Save document capability

This commit is contained in:
Jakub Melka
2020-06-07 17:46:49 +02:00
parent e6d4eea9a2
commit 4e4bf111da
6 changed files with 118 additions and 19 deletions

View File

@ -299,5 +299,5 @@ void PDFExamplesGenerator::generateAnnotationsExample()
// Write result to a file // Write result to a file
pdf::PDFDocument document = builder.build(); pdf::PDFDocument document = builder.build();
pdf::PDFDocumentWriter writer(nullptr); pdf::PDFDocumentWriter writer(nullptr);
writer.write("Ex_Annotations.pdf", &document); writer.write("Ex_Annotations.pdf", &document, false);
} }

View File

@ -21,6 +21,7 @@
#include "pdfparser.h" #include "pdfparser.h"
#include <QFile> #include <QFile>
#include <QSaveFile>
namespace pdf namespace pdf
{ {
@ -170,7 +171,32 @@ void PDFWriteObjectVisitor::visitReference(const PDFObjectReference reference)
m_device->write("R "); m_device->write("R ");
} }
PDFOperationResult PDFDocumentWriter::write(const QString& fileName, const PDFDocument* document) PDFOperationResult PDFDocumentWriter::write(const QString& fileName, const PDFDocument* document, bool safeWrite)
{
if (safeWrite)
{
QSaveFile file(fileName);
file.setDirectWriteFallback(true);
if (file.open(QFile::WriteOnly | QFile::Truncate))
{
PDFOperationResult result = write(&file, document);
if (result)
{
file.commit();
}
else
{
file.cancelWriting();
}
return result;
}
else
{
return tr("File '%1' can't be opened for writing. %2").arg(fileName, file.errorString());
}
}
else
{ {
QFile file(fileName); QFile file(fileName);
@ -185,6 +211,7 @@ PDFOperationResult PDFDocumentWriter::write(const QString& fileName, const PDFDo
return tr("File '%1' can't be opened for writing. %2").arg(fileName, file.errorString()); return tr("File '%1' can't be opened for writing. %2").arg(fileName, file.errorString());
} }
} }
}
PDFOperationResult PDFDocumentWriter::write(QIODevice* device, const PDFDocument* document) PDFOperationResult PDFDocumentWriter::write(QIODevice* device, const PDFDocument* document)
{ {

View File

@ -40,7 +40,20 @@ public:
} }
PDFOperationResult write(const QString& fileName, const PDFDocument* document); /// Writes document to the file. If \p safeWrite is true, then document is first
/// written to the temporary file, and then renamed to original file name atomically,
/// so no data can be lost on, for example, power failure. If it is not possible to
/// create temporary file, then writing operation will attempt to write to the file
/// directly.
/// \param fileName File name
/// \param document Document
/// \param safeWrite Write document to the temporary file and then rename
PDFOperationResult write(const QString& fileName, const PDFDocument* document, bool safeWrite);
/// Write document to the output device. Device must be writable (i.e. opened
/// for writing).
/// \param device Output device
/// \param document Document
PDFOperationResult write(QIODevice* device, const PDFDocument* document); PDFOperationResult write(QIODevice* device, const PDFDocument* document);
/// Calculates document file size, as if it is written to the disk. /// Calculates document file size, as if it is written to the disk.

View File

@ -38,6 +38,7 @@
#include "pdfsendmail.h" #include "pdfsendmail.h"
#include "pdfexecutionpolicy.h" #include "pdfexecutionpolicy.h"
#include "pdfwidgetutils.h" #include "pdfwidgetutils.h"
#include "pdfdocumentwriter.h"
#include <QPainter> #include <QPainter>
#include <QSettings> #include <QSettings>
@ -56,6 +57,7 @@
#include <QLabel> #include <QLabel>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <QDesktopServices> #include <QDesktopServices>
#include <QFileDialog>
#include <QtPrintSupport/QPrinter> #include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QPrintDialog> #include <QtPrintSupport/QPrintDialog>
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
@ -122,6 +124,8 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
ui->actionPrint->setShortcut(QKeySequence::Print); ui->actionPrint->setShortcut(QKeySequence::Print);
ui->actionUndo->setShortcut(QKeySequence::Undo); ui->actionUndo->setShortcut(QKeySequence::Undo);
ui->actionRedo->setShortcut(QKeySequence::Redo); ui->actionRedo->setShortcut(QKeySequence::Redo);
ui->actionSave->setShortcut(QKeySequence::Save);
ui->actionSave_As->setShortcut(QKeySequence::SaveAs);
for (QAction* action : m_recentFileManager->getActions()) for (QAction* action : m_recentFileManager->getActions())
{ {
@ -764,9 +768,9 @@ void PDFViewerMainWindow::updateTitle()
QString title = m_pdfDocument->getInfo()->title; QString title = m_pdfDocument->getInfo()->title;
if (title.isEmpty()) if (title.isEmpty())
{ {
title = m_currentFile; title = m_fileInfo.fileName;
} }
setWindowTitle(tr("%1 - PDF Viewer").arg(m_currentFile)); setWindowTitle(tr("%1 - PDF Viewer").arg(m_fileInfo.fileName));
} }
else else
{ {
@ -888,6 +892,8 @@ void PDFViewerMainWindow::updateActionsAvailability()
ui->actionPrint->setEnabled(hasValidDocument && canPrint); ui->actionPrint->setEnabled(hasValidDocument && canPrint);
ui->actionRender_to_Images->setEnabled(hasValidDocument && canPrint); ui->actionRender_to_Images->setEnabled(hasValidDocument && canPrint);
ui->actionOptimize->setEnabled(hasValidDocument); ui->actionOptimize->setEnabled(hasValidDocument);
ui->actionSave->setEnabled(hasValidDocument);
ui->actionSave_As->setEnabled(hasValidDocument);
setEnabled(!isBusy); setEnabled(!isBusy);
updateUndoRedoActions(); updateUndoRedoActions();
} }
@ -917,11 +923,8 @@ void PDFViewerMainWindow::onRenderingOptionTriggered(bool checked)
m_settings->setFeatures(features); m_settings->setFeatures(features);
} }
void PDFViewerMainWindow::openDocument(const QString& fileName) void PDFViewerMainWindow::updateFileInfo(const QString& fileName)
{ {
// First close old document
closeDocument();
QFileInfo fileInfo(fileName); QFileInfo fileInfo(fileName);
m_fileInfo.originalFileName = fileName; m_fileInfo.originalFileName = fileName;
m_fileInfo.fileName = fileInfo.fileName(); m_fileInfo.fileName = fileInfo.fileName();
@ -931,6 +934,14 @@ void PDFViewerMainWindow::openDocument(const QString& fileName)
m_fileInfo.creationTime = fileInfo.created(); m_fileInfo.creationTime = fileInfo.created();
m_fileInfo.lastModifiedTime = fileInfo.lastModified(); m_fileInfo.lastModifiedTime = fileInfo.lastModified();
m_fileInfo.lastReadTime = fileInfo.lastRead(); m_fileInfo.lastReadTime = fileInfo.lastRead();
}
void PDFViewerMainWindow::openDocument(const QString& fileName)
{
// First close old document
closeDocument();
updateFileInfo(fileName);
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::WaitCursor);
auto readDocument = [this, fileName]() -> AsyncReadingResult auto readDocument = [this, fileName]() -> AsyncReadingResult
@ -981,7 +992,6 @@ void PDFViewerMainWindow::onDocumentReadingFinished()
// Mark current directory as this // Mark current directory as this
QFileInfo fileInfo(m_fileInfo.originalFileName); QFileInfo fileInfo(m_fileInfo.originalFileName);
m_settings->setDirectory(fileInfo.dir().absolutePath()); m_settings->setDirectory(fileInfo.dir().absolutePath());
m_currentFile = fileInfo.fileName();
// We add file to recent files only, if we have successfully read the document // We add file to recent files only, if we have successfully read the document
m_recentFileManager->addRecentFile(m_fileInfo.originalFileName); m_recentFileManager->addRecentFile(m_fileInfo.originalFileName);
@ -1423,5 +1433,36 @@ void PDFViewerMainWindow::on_actionOptimize_triggered()
} }
} }
} // namespace pdfviewer void PDFViewerMainWindow::on_actionSave_As_triggered()
{
QFileInfo fileInfo(m_fileInfo.originalFileName);
QString saveFileName = QFileDialog::getSaveFileName(this, tr("Save As"), fileInfo.dir().absoluteFilePath(m_fileInfo.originalFileName), tr("Portable Document (*.pdf);;All files (*.*)"));
if (!saveFileName.isEmpty())
{
saveDocument(saveFileName);
}
}
void PDFViewerMainWindow::on_actionSave_triggered()
{
saveDocument(m_fileInfo.originalFileName);
}
void PDFViewerMainWindow::saveDocument(const QString& fileName)
{
pdf::PDFDocumentWriter writer(nullptr);
pdf::PDFOperationResult result = writer.write(fileName, m_pdfDocument.data(), true);
if (result)
{
updateFileInfo(fileName);
updateTitle();
m_recentFileManager->addRecentFile(fileName);
}
else
{
QMessageBox::critical(this, tr("Error"), result.getErrorMessage());
}
}
} // namespace pdfviewer

View File

@ -101,6 +101,10 @@ private slots:
void on_actionOptimize_triggered(); void on_actionOptimize_triggered();
void on_actionSave_As_triggered();
void on_actionSave_triggered();
private: private:
void onActionOpenTriggered(); void onActionOpenTriggered();
void onActionCloseTriggered(); void onActionCloseTriggered();
@ -139,8 +143,10 @@ private:
void openDocument(const QString& fileName); void openDocument(const QString& fileName);
void setDocument(pdf::PDFModifiedDocument document); void setDocument(pdf::PDFModifiedDocument document);
void closeDocument(); void closeDocument();
void saveDocument(const QString& fileName);
void setPageLayout(pdf::PageLayout pageLayout); void setPageLayout(pdf::PageLayout pageLayout);
void updateFileInfo(const QString& fileName);
std::vector<QAction*> getRenderingOptionActions() const; std::vector<QAction*> getRenderingOptionActions() const;
QList<QAction*> getActions() const; QList<QAction*> getActions() const;
@ -160,7 +166,6 @@ private:
PDFViewerSettings* m_settings; PDFViewerSettings* m_settings;
pdf::PDFWidget* m_pdfWidget; pdf::PDFWidget* m_pdfWidget;
pdf::PDFDocumentPointer m_pdfDocument; pdf::PDFDocumentPointer m_pdfDocument;
QString m_currentFile;
PDFSidebarWidget* m_sidebarWidget; PDFSidebarWidget* m_sidebarWidget;
QDockWidget* m_sidebarDockWidget; QDockWidget* m_sidebarDockWidget;
PDFAdvancedFindWidget* m_advancedFindWidget; PDFAdvancedFindWidget* m_advancedFindWidget;

View File

@ -30,6 +30,9 @@
<addaction name="actionOpen"/> <addaction name="actionOpen"/>
<addaction name="actionClose"/> <addaction name="actionClose"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionSave"/>
<addaction name="actionSave_As"/>
<addaction name="separator"/>
<addaction name="actionSend_by_E_Mail"/> <addaction name="actionSend_by_E_Mail"/>
<addaction name="actionPrint"/> <addaction name="actionPrint"/>
<addaction name="actionRender_to_Images"/> <addaction name="actionRender_to_Images"/>
@ -536,6 +539,16 @@
<string>Optimize</string> <string>Optimize</string>
</property> </property>
</action> </action>
<action name="actionSave_As">
<property name="text">
<string>Save &amp;As</string>
</property>
</action>
<action name="actionSave">
<property name="text">
<string>Save</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources> <resources>