From ebb9f4723fad4e753f933033a89477927695191d Mon Sep 17 00:00:00 2001 From: wmayer Date: Thu, 21 Oct 2021 21:45:52 +0200 Subject: [PATCH] Gui: code-refactoring of document recovery handling to reduce code duplication --- src/Gui/Application.cpp | 76 +------------------ src/Gui/DocumentRecovery.cpp | 143 +++++++++++++++++++++++++++-------- src/Gui/DocumentRecovery.h | 19 +++++ 3 files changed, 132 insertions(+), 106 deletions(-) diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp index 99500fa9c4..fa233c9ce9 100644 --- a/src/Gui/Application.cpp +++ b/src/Gui/Application.cpp @@ -2416,80 +2416,8 @@ void Application::setStyleSheet(const QString& qssFile, bool tiledBackground) void Application::checkForPreviousCrashes() { - QDir tmp = QString::fromUtf8(App::Application::getTempPath().c_str()); - tmp.setNameFilters(QStringList() << QString::fromLatin1("*.lock")); - tmp.setFilter(QDir::Files); - - QList restoreDocFiles; - QString exeName = QString::fromLatin1(App::GetApplication().getExecutableName()); - QList locks = tmp.entryInfoList(); - for (QList::iterator it = locks.begin(); it != locks.end(); ++it) { - QString bn = it->baseName(); - // ignore the lock file for this instance - QString pid = QString::number(QCoreApplication::applicationPid()); - if (bn.startsWith(exeName) && bn.indexOf(pid) < 0) { - QString fn = it->absoluteFilePath(); - boost::interprocess::file_lock flock((const char*)fn.toLocal8Bit()); - if (flock.try_lock()) { - // OK, this file is a leftover from a previous crash - QString crashed_pid = bn.mid(exeName.length()+1); - // search for transient directories with this PID - QString filter; - QTextStream str(&filter); - str << exeName << "_Doc_*_" << crashed_pid; - tmp.setNameFilters(QStringList() << filter); - tmp.setFilter(QDir::Dirs); - QList dirs = tmp.entryInfoList(); - if (dirs.isEmpty()) { - // delete the lock file immediately if no transient directories are related - tmp.remove(fn); - } - else { - int countDeletedDocs = 0; - QString recovery_files = QString::fromLatin1("fc_recovery_files"); - for (QList::iterator it = dirs.begin(); it != dirs.end(); ++it) { - QDir doc_dir(it->absoluteFilePath()); - doc_dir.setFilter(QDir::NoDotAndDotDot|QDir::AllEntries); - uint entries = doc_dir.entryList().count(); - if (entries == 0) { - // in this case we can delete the transient directory because - // we cannot do anything - if (tmp.rmdir(it->filePath())) - countDeletedDocs++; - } - // search for the existence of a recovery file - else if (doc_dir.exists(QLatin1String("fc_recovery_file.xml"))) { - // store the transient directory in case it's not empty - restoreDocFiles << *it; - } - // search for the 'fc_recovery_files' sub-directory and check that it's the only entry - else if (entries == 1 && doc_dir.exists(recovery_files)) { - // if the sub-directory is empty delete the transient directory - QDir rec_dir(doc_dir.absoluteFilePath(recovery_files)); - rec_dir.setFilter(QDir::NoDotAndDotDot|QDir::AllEntries); - if (rec_dir.entryList().isEmpty()) { - doc_dir.rmdir(recovery_files); - if (tmp.rmdir(it->filePath())) - countDeletedDocs++; - } - } - } - - // all directories corresponding to the lock file have been deleted - // so delete the lock file, too - if (countDeletedDocs == dirs.size()) { - tmp.remove(fn); - } - } - } - } - } - - if (!restoreDocFiles.isEmpty()) { - Gui::Dialog::DocumentRecovery dlg(restoreDocFiles, Gui::getMainWindow()); - if (dlg.foundDocuments()) - dlg.exec(); - } + Gui::Dialog::DocumentRecoveryFinder finder; + finder.checkForPreviousCrashes(); } App::Document *Application::reopen(App::Document *doc) { diff --git a/src/Gui/DocumentRecovery.cpp b/src/Gui/DocumentRecovery.cpp index 44e7f74116..4f2d60006e 100644 --- a/src/Gui/DocumentRecovery.cpp +++ b/src/Gui/DocumentRecovery.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,7 @@ FC_LOG_LEVEL_INIT("Gui",true,true) using namespace Gui; using namespace Gui::Dialog; +namespace sp = std::placeholders; // taken from the script doctools.py std::string DocumentRecovery::doctools = @@ -553,41 +555,20 @@ void DocumentRecovery::on_buttonCleanup_clicked() d_ptr->ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); d_ptr->ui.buttonBox->button(QDialogButtonBox::Cancel)->setEnabled(true); - QDir tmp = QString::fromUtf8(App::Application::getTempPath().c_str()); - tmp.setNameFilters(QStringList() << QString::fromLatin1("*.lock")); - tmp.setFilter(QDir::Files); + DocumentRecoveryHandler handler; + handler.checkForPreviousCrashes(std::bind(&DocumentRecovery::cleanup, this, sp::_1, sp::_2, sp::_3)); + QMessageBox::information(this, tr("Finished"), tr("Transient directories deleted.")); +} - QString exeName = QString::fromLatin1(App::GetApplication().getExecutableName()); - QList locks = tmp.entryInfoList(); - for (QList::iterator it = locks.begin(); it != locks.end(); ++it) { - QString bn = it->baseName(); - // ignore the lock file for this instance - QString pid = QString::number(QCoreApplication::applicationPid()); - if (bn.startsWith(exeName) && bn.indexOf(pid) < 0) { - QString fn = it->absoluteFilePath(); - boost::interprocess::file_lock flock((const char*)fn.toLocal8Bit()); - if (flock.try_lock()) { - // OK, this file is a leftover from a previous crash - QString crashed_pid = bn.mid(exeName.length()+1); - // search for transient directories with this PID - QString filter; - QTextStream str(&filter); - str << exeName << "_Doc_*_" << crashed_pid; - tmp.setNameFilters(QStringList() << filter); - tmp.setFilter(QDir::Dirs); - QList dirs = tmp.entryInfoList(); - if (!dirs.isEmpty()) { - for (QList::iterator jt = dirs.begin(); jt != dirs.end(); ++jt) { - clearDirectory(*jt); - tmp.rmdir(jt->fileName()); - } - } - tmp.remove(it->fileName()); - } +void DocumentRecovery::cleanup(QDir& tmp, const QList& dirs, const QString& lockFile) +{ + if (!dirs.isEmpty()) { + for (QList::const_iterator jt = dirs.cbegin(); jt != dirs.cend(); ++jt) { + clearDirectory(*jt); + tmp.rmdir(jt->fileName()); } } - - QMessageBox::information(this, tr("Finished"), tr("Transient directories deleted.")); + tmp.remove(lockFile); } void DocumentRecovery::clearDirectory(const QFileInfo& dir) @@ -613,4 +594,102 @@ void DocumentRecovery::clearDirectory(const QFileInfo& dir) } } +// ---------------------------------------------------------------------------- + +void DocumentRecoveryFinder::checkForPreviousCrashes() +{ + DocumentRecoveryHandler handler; + handler.checkForPreviousCrashes(std::bind(&DocumentRecoveryFinder::checkDocumentDirs, this, sp::_1, sp::_2, sp::_3)); + + showRecoveryDialogIfNeeded(); +} + +void DocumentRecoveryFinder::checkDocumentDirs(QDir& tmp, const QList& dirs, const QString& fn) +{ + if (dirs.isEmpty()) { + // delete the lock file immediately if no transient directories are related + tmp.remove(fn); + } + else { + int countDeletedDocs = 0; + QString recovery_files = QString::fromLatin1("fc_recovery_files"); + for (QList::const_iterator it = dirs.cbegin(); it != dirs.cend(); ++it) { + QDir doc_dir(it->absoluteFilePath()); + doc_dir.setFilter(QDir::NoDotAndDotDot|QDir::AllEntries); + uint entries = doc_dir.entryList().count(); + if (entries == 0) { + // in this case we can delete the transient directory because + // we cannot do anything + if (tmp.rmdir(it->filePath())) + countDeletedDocs++; + } + // search for the existence of a recovery file + else if (doc_dir.exists(QLatin1String("fc_recovery_file.xml"))) { + // store the transient directory in case it's not empty + restoreDocFiles << *it; + } + // search for the 'fc_recovery_files' sub-directory and check that it's the only entry + else if (entries == 1 && doc_dir.exists(recovery_files)) { + // if the sub-directory is empty delete the transient directory + QDir rec_dir(doc_dir.absoluteFilePath(recovery_files)); + rec_dir.setFilter(QDir::NoDotAndDotDot|QDir::AllEntries); + if (rec_dir.entryList().isEmpty()) { + doc_dir.rmdir(recovery_files); + if (tmp.rmdir(it->filePath())) + countDeletedDocs++; + } + } + } + + // all directories corresponding to the lock file have been deleted + // so delete the lock file, too + if (countDeletedDocs == dirs.size()) { + tmp.remove(fn); + } + } +} + +void DocumentRecoveryFinder::showRecoveryDialogIfNeeded() +{ + if (!restoreDocFiles.isEmpty()) { + Gui::Dialog::DocumentRecovery dlg(restoreDocFiles, Gui::getMainWindow()); + if (dlg.foundDocuments()) + dlg.exec(); + } +} + +// ---------------------------------------------------------------------------- + +void DocumentRecoveryHandler::checkForPreviousCrashes(const std::function&, const QString&)> & callableFunc) const +{ + QDir tmp = QString::fromUtf8(App::Application::getTempPath().c_str()); + tmp.setNameFilters(QStringList() << QString::fromLatin1("*.lock")); + tmp.setFilter(QDir::Files); + + QString exeName = QString::fromLatin1(App::GetApplication().getExecutableName()); + QList locks = tmp.entryInfoList(); + for (QList::iterator it = locks.begin(); it != locks.end(); ++it) { + QString bn = it->baseName(); + // ignore the lock file for this instance + QString pid = QString::number(QCoreApplication::applicationPid()); + if (bn.startsWith(exeName) && bn.indexOf(pid) < 0) { + QString fn = it->absoluteFilePath(); + boost::interprocess::file_lock flock((const char*)fn.toLocal8Bit()); + if (flock.try_lock()) { + // OK, this file is a leftover from a previous crash + QString crashed_pid = bn.mid(exeName.length()+1); + // search for transient directories with this PID + QString filter; + QTextStream str(&filter); + str << exeName << "_Doc_*_" << crashed_pid; + tmp.setNameFilters(QStringList() << filter); + tmp.setFilter(QDir::Dirs); + QList dirs = tmp.entryInfoList(); + + callableFunc(tmp, dirs, it->fileName()); + } + } + } +} + #include "moc_DocumentRecovery.cpp" diff --git a/src/Gui/DocumentRecovery.h b/src/Gui/DocumentRecovery.h index 966f551173..4b47306fe5 100644 --- a/src/Gui/DocumentRecovery.h +++ b/src/Gui/DocumentRecovery.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace Gui { namespace Dialog { @@ -53,6 +54,7 @@ protected: void contextMenuEvent(QContextMenuEvent*); QString createProjectFile(const QString&); void clearDirectory(const QFileInfo&); + void cleanup(QDir&, const QList&, const QString&); protected Q_SLOTS: void on_buttonCleanup_clicked(); @@ -65,6 +67,23 @@ private: Q_DECLARE_PRIVATE(DocumentRecovery) }; +class DocumentRecoveryFinder { +public: + void checkForPreviousCrashes(); + +private: + void checkDocumentDirs(QDir&, const QList&, const QString&); + void showRecoveryDialogIfNeeded(); + +private: + QList restoreDocFiles; +}; + +class DocumentRecoveryHandler { +public: + void checkForPreviousCrashes(const std::function&, const QString&)> & callableFunc) const; +}; + } //namespace Dialog } //namespace Gui