Gui: AutoSaver and recovery changes
* Fix AutoSaver inconsistent BinaryBrep setting * Use temperary name when auto saving, so that it won't overwrite the original file, which may cause corruption when crashing in the middel of auto saving, especially if auto saving in a separate thread. * Support auto recovery document containing external links * Do not mark success after auto recover, in case the program crash again before the user remember to save the just recovered file. Only mark when user saves the document.
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#ifndef _PreComp_
|
||||
# include <QApplication>
|
||||
# include <QFile>
|
||||
# include <QDir>
|
||||
# include <QRunnable>
|
||||
# include <QTextStream>
|
||||
# include <QThreadPool>
|
||||
@@ -49,6 +50,8 @@
|
||||
#include "MainWindow.h"
|
||||
#include "ViewProvider.h"
|
||||
|
||||
FC_LOG_LEVEL_INIT("App",true,true)
|
||||
|
||||
using namespace Gui;
|
||||
|
||||
AutoSaver* AutoSaver::self = 0;
|
||||
@@ -71,6 +74,15 @@ AutoSaver* AutoSaver::instance()
|
||||
return self;
|
||||
}
|
||||
|
||||
void AutoSaver::renameFile(QString dirName, QString file, QString tmpFile)
|
||||
{
|
||||
FC_LOG("auto saver rename " << tmpFile.toUtf8().constData()
|
||||
<< " -> " << file.toUtf8().constData());
|
||||
QDir dir(dirName);
|
||||
dir.remove(file);
|
||||
dir.rename(tmpFile,file);
|
||||
}
|
||||
|
||||
void AutoSaver::setTimeout(int ms)
|
||||
{
|
||||
timeout = Base::clamp<int>(ms, 0, 3600000); // between 0 and 60 min
|
||||
@@ -122,7 +134,7 @@ void AutoSaver::saveDocument(const std::string& name, AutoSaveProperty& saver)
|
||||
{
|
||||
Gui::WaitCursor wc;
|
||||
App::Document* doc = App::GetApplication().getDocument(name.c_str());
|
||||
if (doc) {
|
||||
if (doc && !doc->testStatus(App::Document::PartialDoc)) {
|
||||
// Set the document's current transient directory
|
||||
std::string dirName = doc->TransientDir.getValue();
|
||||
dirName += "/fc_recovery_files";
|
||||
@@ -159,8 +171,11 @@ void AutoSaver::saveDocument(const std::string& name, AutoSaveProperty& saver)
|
||||
{
|
||||
if (!this->compressed) {
|
||||
RecoveryWriter writer(saver);
|
||||
if (hGrp->GetBool("SaveBinaryBrep", true))
|
||||
writer.setMode("BinaryBrep");
|
||||
|
||||
// We will be using thread pool if not compressed.
|
||||
// So, always force binary format because ASCII
|
||||
// is not reentrant. See PropertyPartShape::SaveDocFile
|
||||
writer.setMode("BinaryBrep");
|
||||
|
||||
writer.putNextEntry("Document.xml");
|
||||
|
||||
@@ -310,10 +325,11 @@ public:
|
||||
, writer(dir)
|
||||
{
|
||||
writer.setModes(modes);
|
||||
// always force binary format because ASCII
|
||||
// is not reentrant. See PropertyPartShape::SaveDocFile
|
||||
writer.setMode("BinaryBrep");
|
||||
writer.putNextEntry(file);
|
||||
|
||||
dirName = QString::fromUtf8(dir);
|
||||
fileName = QString::fromUtf8(file);
|
||||
tmpName = QString::fromLatin1("%1.tmp%2").arg(fileName).arg(rand());
|
||||
writer.putNextEntry(tmpName.toUtf8().constData());
|
||||
}
|
||||
virtual ~RecoveryRunnable()
|
||||
{
|
||||
@@ -322,11 +338,24 @@ public:
|
||||
virtual void run()
|
||||
{
|
||||
prop->SaveDocFile(writer);
|
||||
writer.close();
|
||||
|
||||
// We could have renamed the file in this thread. However, there is
|
||||
// still chance of crash when we deleted the original and before rename
|
||||
// the new file. So we ask the main thread to do it. There is still
|
||||
// possibility of crash caused by thread other than the main, but
|
||||
// that's the best we can do for now.
|
||||
QMetaObject::invokeMethod(AutoSaver::instance(), "renameFile",
|
||||
Qt::QueuedConnection, Q_ARG(QString,dirName)
|
||||
,Q_ARG(QString,fileName),Q_ARG(QString,tmpName));
|
||||
}
|
||||
|
||||
private:
|
||||
App::Property* prop;
|
||||
Base::FileWriter writer;
|
||||
QString dirName;
|
||||
QString fileName;
|
||||
QString tmpName;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user