Skip to content

Commit 0e54ec9

Browse files
committed
Improve file recovery experience
1 parent 077a357 commit 0e54ec9

3 files changed

Lines changed: 114 additions & 19 deletions

File tree

src/plugins/coreplugin/internal/addon/RecentFileAddOn.cpp

Lines changed: 103 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "RecentFileAddOn.h"
22

3+
#include <exception>
34
#include <memory>
45

56
#include <QDir>
@@ -20,6 +21,8 @@
2021

2122
#include <QAKQuick/quickactioncontext.h>
2223

24+
#include <SVSCraftQuick/MessageBox.h>
25+
2326
#include <uishell/USDef.h>
2427

2528
#include <coreplugin/CoreInterface.h>
@@ -154,6 +157,76 @@ namespace Core::Internal {
154157
return QDir(recoveryRootPath()).filePath(QStringLiteral("latest_unsaved_project.dspx"));
155158
}
156159

160+
static void showRecoveryRestoreFailure() {
161+
SVS::MessageBox::critical(
162+
RuntimeInterface::qmlEngine(),
163+
nullptr,
164+
RecentFileAddOn::tr("Failed to restore recovery file"),
165+
RecentFileAddOn::tr("Cannot restore the recovery file.")
166+
);
167+
}
168+
169+
static void showPartialRecoveryWarning() {
170+
SVS::MessageBox::warning(
171+
RuntimeInterface::qmlEngine(),
172+
nullptr,
173+
RecentFileAddOn::tr("Complete recovery failed"),
174+
RecentFileAddOn::tr("Complete recovery failed. Partial recovery will be attempted."),
175+
SVS::SVSCraft::Ok,
176+
SVS::SVSCraft::Ok
177+
);
178+
}
179+
180+
static std::unique_ptr<dspx::Document> restoreRecoveryDocument(const QDir &recoveryDirectory,
181+
dspx::Document::RestoreOptions options,
182+
QString *errorMessage) {
183+
QFile snapshotFile(recoveryDirectory.filePath(QStringLiteral("snapshot")));
184+
if (!snapshotFile.open(QIODevice::ReadOnly)) {
185+
if (errorMessage) {
186+
*errorMessage = QStringLiteral("Failed to open recovery snapshot \"%1\": %2")
187+
.arg(snapshotFile.fileName(), snapshotFile.errorString());
188+
}
189+
return nullptr;
190+
}
191+
192+
QFile logsFile(recoveryDirectory.filePath(QStringLiteral("logs")));
193+
QIODevice *logsDevice = nullptr;
194+
if (logsFile.exists()) {
195+
if (!logsFile.open(QIODevice::ReadOnly)) {
196+
if (errorMessage) {
197+
*errorMessage = QStringLiteral("Failed to open recovery log \"%1\": %2")
198+
.arg(logsFile.fileName(), logsFile.errorString());
199+
}
200+
return nullptr;
201+
}
202+
logsDevice = &logsFile;
203+
}
204+
205+
try {
206+
auto *document = dspx::Document::restore(&snapshotFile, logsDevice, options);
207+
if (!document) {
208+
if (errorMessage) {
209+
*errorMessage = QStringLiteral("Document::restore returned null for recovery directory \"%1\"")
210+
.arg(recoveryDirectory.absolutePath());
211+
}
212+
return nullptr;
213+
}
214+
return std::unique_ptr<dspx::Document>(document);
215+
} catch (const std::exception &e) {
216+
if (errorMessage) {
217+
*errorMessage = QStringLiteral("Failed to restore document from recovery directory \"%1\": %2")
218+
.arg(recoveryDirectory.absolutePath(), QString::fromUtf8(e.what()));
219+
}
220+
return nullptr;
221+
} catch (...) {
222+
if (errorMessage) {
223+
*errorMessage = QStringLiteral("Failed to restore document from recovery directory \"%1\": unknown exception")
224+
.arg(recoveryDirectory.absolutePath());
225+
}
226+
return nullptr;
227+
}
228+
}
229+
157230
static bool recoveryDirectoryInUse(const QDir &directory) {
158231
QLockFile lock(directory.filePath(QStringLiteral("active.lock")));
159232
if (lock.tryLock(0)) {
@@ -262,32 +335,44 @@ namespace Core::Internal {
262335
}
263336

264337
QDir recoveryDirectory(path);
265-
QFile snapshotFile(recoveryDirectory.filePath(QStringLiteral("snapshot")));
266-
if (!snapshotFile.open(QIODevice::ReadOnly)) {
267-
qCWarning(lcRecentFileAddOn) << "Failed to open recovery snapshot:" << snapshotFile.fileName() << snapshotFile.errorString();
268-
return;
269-
}
270-
271-
QFile logsFile(recoveryDirectory.filePath(QStringLiteral("logs")));
272-
QIODevice *logsDevice = nullptr;
273-
if (logsFile.exists()) {
274-
if (!logsFile.open(QIODevice::ReadOnly)) {
275-
qCWarning(lcRecentFileAddOn) << "Failed to open recovery log:" << logsFile.fileName() << logsFile.errorString();
338+
QString completeRecoveryError;
339+
auto restoredDocument = restoreRecoveryDocument(recoveryDirectory, {}, &completeRecoveryError);
340+
if (!restoredDocument) {
341+
qCCritical(lcRecentFileAddOn) << "Complete recovery failed:" << completeRecoveryError;
342+
showPartialRecoveryWarning();
343+
344+
QString partialRecoveryError;
345+
restoredDocument = restoreRecoveryDocument(
346+
recoveryDirectory,
347+
dspx::Document::RO_DiscardInvalidCommitLogTail,
348+
&partialRecoveryError
349+
);
350+
if (!restoredDocument) {
351+
qCCritical(lcRecentFileAddOn) << "Partial recovery failed:" << partialRecoveryError;
352+
showRecoveryRestoreFailure();
276353
return;
277354
}
278-
logsDevice = &logsFile;
355+
qCWarning(lcRecentFileAddOn) << "Partial recovery succeeded after complete recovery failed:"
356+
<< recoveryDirectory.absolutePath();
279357
}
280358

281-
std::unique_ptr<dspx::Document> restoredDocument;
359+
opendspx::Model openDspxModel;
282360
try {
283-
restoredDocument.reset(dspx::Document::restore(&snapshotFile, logsDevice));
361+
dspx::Model restoredModel(restoredDocument.get());
362+
openDspxModel = restoredModel.toOpenDSPX();
363+
} catch (const std::exception &e) {
364+
qCCritical(lcRecentFileAddOn) << "Failed to convert restored recovery document to OpenDSPX:"
365+
<< recoveryDirectory.absolutePath()
366+
<< e.what();
367+
showRecoveryRestoreFailure();
368+
return;
284369
} catch (...) {
285-
qCWarning(lcRecentFileAddOn) << "Failed to restore document log:" << recoveryDirectory.absolutePath();
370+
qCCritical(lcRecentFileAddOn) << "Failed to convert restored recovery document to OpenDSPX:"
371+
<< recoveryDirectory.absolutePath()
372+
<< "Unknown exception";
373+
showRecoveryRestoreFailure();
286374
return;
287375
}
288-
289-
dspx::Model restoredModel(restoredDocument.get());
290-
auto openDspxModel = restoredModel.toOpenDSPX();
291376
auto defaultDocumentName = defaultDocumentNameFromRecoveryName(item->data(UIShell::USDef::RF_NameRole).toString());
292377
auto projectDocumentContext = std::make_unique<ProjectDocumentContext>();
293378
if (!projectDocumentContext->newFile(openDspxModel, defaultDocumentName, false)) {

src/plugins/coreplugin/project/document/ProjectDocumentContext.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ namespace Core {
126126
return projectName;
127127
}
128128
}
129+
if (fileLocker && !fileLocker->path().isEmpty()) {
130+
auto baseName = QFileInfo(fileLocker->entryName()).completeBaseName();
131+
if (!baseName.isEmpty()) {
132+
return baseName;
133+
}
134+
auto fileName = QFileInfo(fileLocker->path()).fileName();
135+
if (!fileName.isEmpty()) {
136+
return fileName;
137+
}
138+
}
129139
if (!defaultDocumentName.isEmpty()) {
130140
auto baseName = QFileInfo(defaultDocumentName).completeBaseName();
131141
if (!baseName.isEmpty()) {

0 commit comments

Comments
 (0)