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:
Zheng, Lei
2019-07-10 09:03:31 +08:00
committed by wmayer
parent c8891be856
commit 8227103ceb
4 changed files with 109 additions and 39 deletions

View File

@@ -47,6 +47,7 @@
# include <sstream>
#endif
#include <Base/Console.h>
#include "DocumentRecovery.h"
#include "ui_DocumentRecovery.h"
#include "WaitCursor.h"
@@ -63,6 +64,8 @@
#include <QDomDocument>
#include <boost/interprocess/sync/file_lock.hpp>
FC_LOG_LEVEL_INIT("Gui",true,true);
using namespace Gui;
using namespace Gui::Dialog;
@@ -81,8 +84,10 @@ std::string DocumentRecovery::doctools =
" self.dirname = dirname\n"
"\n"
" def startElement(self, name, attributes):\n"
" if name == 'XLink':\n"
" return\n"
" item=attributes.get(\"file\")\n"
" if item != None:\n"
" if item:\n"
" self.files.append(os.path.join(self.dirname,str(item)))\n"
"\n"
" def characters(self, data):\n"
@@ -237,33 +242,25 @@ void DocumentRecovery::accept()
if (!d->recovered) {
WaitCursor wc;
int index = 0;
for (QList<DocumentRecoveryPrivate::Info>::iterator it = d->recoveryInfo.begin(); it != d->recoveryInfo.end(); ++it, index++) {
int index = -1;
std::vector<int> indices;
std::vector<std::string> filenames, pathes, labels, errs;
for(auto &info : d->recoveryInfo) {
++index;
std::string documentName;
QString errorInfo;
QTreeWidgetItem* item = d_ptr->ui.treeWidget->topLevelItem(index);
try {
QString file = it->projectFile;
QString file = info.projectFile;
QFileInfo fi(file);
if (fi.fileName() == QLatin1String("Document.xml"))
file = createProjectFile(it->projectFile);
App::Document* document = App::GetApplication().newDocument();
documentName = document->getName();
document->FileName.setValue(file.toUtf8().constData());
file = createProjectFile(info.projectFile);
// If something goes wrong an exception will be thrown here
document->restore();
file = it->fileName;
document->FileName.setValue(file.toUtf8().constData());
document->Label.setValue(it->label.toUtf8().constData());
// Set the modified flag so that the user cannot close by accident
Gui::Document* guidoc = Gui::Application::Instance->getDocument(document);
if (guidoc) {
guidoc->setModified(true);
}
pathes.emplace_back(file.toUtf8().constData());
filenames.emplace_back(info.fileName.toUtf8().constData());
labels.emplace_back(info.label.toUtf8().constData());
indices.push_back(index);
}
catch (const std::exception& e) {
errorInfo = QString::fromLatin1(e.what());
@@ -275,31 +272,71 @@ void DocumentRecovery::accept()
errorInfo = tr("Unknown problem occurred");
}
// an error occurred so close the document again
if (!errorInfo.isEmpty()) {
if (!documentName.empty())
App::GetApplication().closeDocument(documentName.c_str());
it->status = DocumentRecoveryPrivate::Failure;
info.status = DocumentRecoveryPrivate::Failure;
if (item) {
item->setText(1, tr("Failed to recover"));
item->setToolTip(1, errorInfo);
item->setForeground(1, QColor(170,0,0));
}
d->writeRecoveryInfo(info);
}
// everything OK
else {
it->status = DocumentRecoveryPrivate::Success;
}
auto docs = App::GetApplication().openDocuments(filenames,&pathes,&labels,&errs);
for(int i=0;i<(int)docs.size();++i) {
auto &info = d->recoveryInfo[indices[i]];
QTreeWidgetItem* item = d_ptr->ui.treeWidget->topLevelItem(indices[i]);
if(!docs[i] || errs[i].size()) {
if(docs[i])
App::GetApplication().closeDocument(docs[i]->getName());
info.status = DocumentRecoveryPrivate::Failure;
if (item) {
item->setText(1, tr("Failed to recover"));
item->setToolTip(1, QString::fromUtf8(errs[index].c_str()));
item->setForeground(1, QColor(170,0,0));
}
// write back current status
d->writeRecoveryInfo(info);
}else{
auto gdoc = Application::Instance->getDocument(docs[i]);
if(gdoc)
gdoc->setModified(true);
info.status = DocumentRecoveryPrivate::Success;
if (item) {
item->setText(1, tr("Successfully recovered"));
item->setForeground(1, QColor(0,170,0));
}
}
// write back current status
d->writeRecoveryInfo(*it);
QDir transDir(QString::fromUtf8(docs[i]->TransientDir.getValue()));
QFileInfo xfi(info.xmlFile);
QFileInfo fi(info.projectFile);
bool res = false;
if(fi.fileName() == QLatin1String("fc_recovery_file.fcstd")) {
transDir.remove(fi.fileName());
res = transDir.rename(fi.absoluteFilePath(),fi.fileName());
}else{
transDir.rmdir(fi.dir().dirName());
res = transDir.rename(fi.absolutePath(),fi.dir().dirName());
}
if(res) {
transDir.remove(xfi.fileName());
res = transDir.rename(xfi.absoluteFilePath(),xfi.fileName());
}
if(!res) {
FC_WARN("Failed to move recovery file of document '"
<< docs[i]->Label.getValue() << "'");
}else{
clearDirectory(xfi.absolutePath());
QDir().rmdir(xfi.absolutePath());
}
// DO NOT write success into recovery info, in case the program
// crash again before the user save the just recovered file.
}
}
d->ui.buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Finish"));