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
pdf::PDFDocument document = builder.build();
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 <QFile>
#include <QSaveFile>
namespace pdf
{
@ -170,19 +171,45 @@ void PDFWriteObjectVisitor::visitReference(const PDFObjectReference reference)
m_device->write("R ");
}
PDFOperationResult PDFDocumentWriter::write(const QString& fileName, const PDFDocument* document)
PDFOperationResult PDFDocumentWriter::write(const QString& fileName, const PDFDocument* document, bool safeWrite)
{
QFile file(fileName);
if (file.open(QFile::WriteOnly | QFile::Truncate))
if (safeWrite)
{
PDFOperationResult result = write(&file, document);
file.close();
return result;
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
{
return tr("File '%1' can't be opened for writing. %2").arg(fileName, file.errorString());
QFile file(fileName);
if (file.open(QFile::WriteOnly | QFile::Truncate))
{
PDFOperationResult result = write(&file, document);
file.close();
return result;
}
else
{
return tr("File '%1' can't be opened for writing. %2").arg(fileName, file.errorString());
}
}
}

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);
/// Calculates document file size, as if it is written to the disk.

View File

@ -38,6 +38,7 @@
#include "pdfsendmail.h"
#include "pdfexecutionpolicy.h"
#include "pdfwidgetutils.h"
#include "pdfdocumentwriter.h"
#include <QPainter>
#include <QSettings>
@ -56,6 +57,7 @@
#include <QLabel>
#include <QDoubleSpinBox>
#include <QDesktopServices>
#include <QFileDialog>
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QPrintDialog>
#include <QtConcurrent/QtConcurrent>
@ -122,6 +124,8 @@ PDFViewerMainWindow::PDFViewerMainWindow(QWidget* parent) :
ui->actionPrint->setShortcut(QKeySequence::Print);
ui->actionUndo->setShortcut(QKeySequence::Undo);
ui->actionRedo->setShortcut(QKeySequence::Redo);
ui->actionSave->setShortcut(QKeySequence::Save);
ui->actionSave_As->setShortcut(QKeySequence::SaveAs);
for (QAction* action : m_recentFileManager->getActions())
{
@ -764,9 +768,9 @@ void PDFViewerMainWindow::updateTitle()
QString title = m_pdfDocument->getInfo()->title;
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
{
@ -888,6 +892,8 @@ void PDFViewerMainWindow::updateActionsAvailability()
ui->actionPrint->setEnabled(hasValidDocument && canPrint);
ui->actionRender_to_Images->setEnabled(hasValidDocument && canPrint);
ui->actionOptimize->setEnabled(hasValidDocument);
ui->actionSave->setEnabled(hasValidDocument);
ui->actionSave_As->setEnabled(hasValidDocument);
setEnabled(!isBusy);
updateUndoRedoActions();
}
@ -917,11 +923,8 @@ void PDFViewerMainWindow::onRenderingOptionTriggered(bool checked)
m_settings->setFeatures(features);
}
void PDFViewerMainWindow::openDocument(const QString& fileName)
void PDFViewerMainWindow::updateFileInfo(const QString& fileName)
{
// First close old document
closeDocument();
QFileInfo fileInfo(fileName);
m_fileInfo.originalFileName = fileName;
m_fileInfo.fileName = fileInfo.fileName();
@ -931,6 +934,14 @@ void PDFViewerMainWindow::openDocument(const QString& fileName)
m_fileInfo.creationTime = fileInfo.created();
m_fileInfo.lastModifiedTime = fileInfo.lastModified();
m_fileInfo.lastReadTime = fileInfo.lastRead();
}
void PDFViewerMainWindow::openDocument(const QString& fileName)
{
// First close old document
closeDocument();
updateFileInfo(fileName);
QApplication::setOverrideCursor(Qt::WaitCursor);
auto readDocument = [this, fileName]() -> AsyncReadingResult
@ -981,7 +992,6 @@ void PDFViewerMainWindow::onDocumentReadingFinished()
// Mark current directory as this
QFileInfo fileInfo(m_fileInfo.originalFileName);
m_settings->setDirectory(fileInfo.dir().absolutePath());
m_currentFile = fileInfo.fileName();
// We add file to recent files only, if we have successfully read the document
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_actionSave_As_triggered();
void on_actionSave_triggered();
private:
void onActionOpenTriggered();
void onActionCloseTriggered();
@ -139,8 +143,10 @@ private:
void openDocument(const QString& fileName);
void setDocument(pdf::PDFModifiedDocument document);
void closeDocument();
void saveDocument(const QString& fileName);
void setPageLayout(pdf::PageLayout pageLayout);
void updateFileInfo(const QString& fileName);
std::vector<QAction*> getRenderingOptionActions() const;
QList<QAction*> getActions() const;
@ -160,7 +166,6 @@ private:
PDFViewerSettings* m_settings;
pdf::PDFWidget* m_pdfWidget;
pdf::PDFDocumentPointer m_pdfDocument;
QString m_currentFile;
PDFSidebarWidget* m_sidebarWidget;
QDockWidget* m_sidebarDockWidget;
PDFAdvancedFindWidget* m_advancedFindWidget;

View File

@ -30,6 +30,9 @@
<addaction name="actionOpen"/>
<addaction name="actionClose"/>
<addaction name="separator"/>
<addaction name="actionSave"/>
<addaction name="actionSave_As"/>
<addaction name="separator"/>
<addaction name="actionSend_by_E_Mail"/>
<addaction name="actionPrint"/>
<addaction name="actionRender_to_Images"/>
@ -536,6 +539,16 @@
<string>Optimize</string>
</property>
</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>
<layoutdefault spacing="6" margin="11"/>
<resources>