* @brief Load a snapshot file back into ProjectModel; returns true on success. */
| 172 | * @brief Load a snapshot file back into ProjectModel; returns true on success. |
| 173 | */ |
| 174 | bool Misc::BackupManager::restore(const QString& path) |
| 175 | { |
| 176 | if (path.isEmpty()) |
| 177 | return false; |
| 178 | |
| 179 | QFile in(path); |
| 180 | if (!in.open(QIODevice::ReadOnly)) |
| 181 | return false; |
| 182 | |
| 183 | const auto bytes = in.readAll(); |
| 184 | in.close(); |
| 185 | |
| 186 | QJsonParseError err{}; |
| 187 | const auto doc = QJsonDocument::fromJson(bytes, &err); |
| 188 | if (err.error != QJsonParseError::NoError || !doc.isObject()) |
| 189 | return false; |
| 190 | |
| 191 | auto obj = doc.object(); |
| 192 | if (obj.contains(kBackupMetaKey)) { |
| 193 | const auto meta = obj.value(kBackupMetaKey).toObject(); |
| 194 | const int fmt = meta.value(QStringLiteral("format")).toInt(0); |
| 195 | if (fmt > kSnapshotFormat) { |
| 196 | qWarning() << "[BackupManager] Refusing snapshot with format" << fmt |
| 197 | << "(this build understands up to" << kSnapshotFormat << ")"; |
| 198 | return false; |
| 199 | } |
| 200 | obj.remove(kBackupMetaKey); |
| 201 | } |
| 202 | const QJsonDocument projectDoc(obj); |
| 203 | |
| 204 | auto& pm = DataModel::ProjectModel::instance(); |
| 205 | |
| 206 | const auto originalPath = pm.jsonFilePath(); |
| 207 | |
| 208 | (void)snapshot(QStringLiteral("pre-restore")); |
| 209 | |
| 210 | pm.setSuppressMessageBoxes(true); |
| 211 | const bool ok = pm.loadFromJsonDocument(projectDoc, originalPath); |
| 212 | pm.setSuppressMessageBoxes(false); |
| 213 | if (!ok) |
| 214 | return false; |
| 215 | |
| 216 | pm.setModified(true); |
| 217 | Q_EMIT restored(path); |
| 218 | return true; |
| 219 | } |
| 220 | |
| 221 | /** |
| 222 | * @brief Enumerate snapshot files for the current project, newest first. |
no test coverage detected