Move project save write planning to app core

This commit is contained in:
2026-06-06 12:00:57 +02:00
parent ed9709ade8
commit a03db82307
8 changed files with 199 additions and 15 deletions

View File

@@ -103,6 +103,21 @@ struct DocumentCanvasProjectSaveTargetPlan {
std::string timelapse_path;
};
enum class DocumentCanvasProjectSaveWriteAction {
write_direct_to_target,
write_temporary_then_swap,
};
struct DocumentCanvasProjectSaveWritePlan {
DocumentCanvasProjectSaveWriteAction action = DocumentCanvasProjectSaveWriteAction::write_direct_to_target;
std::string write_path;
std::string target_path;
std::string temporary_path;
bool target_exists = false;
bool uses_temporary = false;
bool falls_back_to_direct_on_temporary_open_failure = false;
};
class DocumentCanvasClearServices {
public:
virtual ~DocumentCanvasClearServices() = default;
@@ -350,6 +365,38 @@ plan_document_canvas_project_save_target(
return pp::foundation::Result<DocumentCanvasProjectSaveTargetPlan>::success(std::move(plan));
}
[[nodiscard]] inline pp::foundation::Result<DocumentCanvasProjectSaveWritePlan>
plan_document_canvas_project_save_write(
const DocumentCanvasProjectSaveTargetPlan& target,
bool target_exists)
{
if (target.target_path.empty()) {
return pp::foundation::Result<DocumentCanvasProjectSaveWritePlan>::failure(
pp::foundation::Status::invalid_argument("project save write target path must not be empty"));
}
DocumentCanvasProjectSaveWritePlan plan;
plan.target_exists = target_exists;
plan.target_path = target.target_path;
plan.temporary_path = target.temporary_path;
if (!target_exists) {
plan.write_path = target.target_path;
return pp::foundation::Result<DocumentCanvasProjectSaveWritePlan>::success(std::move(plan));
}
if (target.temporary_path.empty()) {
return pp::foundation::Result<DocumentCanvasProjectSaveWritePlan>::failure(
pp::foundation::Status::invalid_argument("project save temporary path must not be empty"));
}
plan.action = DocumentCanvasProjectSaveWriteAction::write_temporary_then_swap;
plan.write_path = target.temporary_path;
plan.uses_temporary = true;
plan.falls_back_to_direct_on_temporary_open_failure = true;
return pp::foundation::Result<DocumentCanvasProjectSaveWritePlan>::success(std::move(plan));
}
[[nodiscard]] inline pp::foundation::Result<DocumentCanvasClearPlan> plan_document_canvas_clear(
bool has_canvas,
float r = 0.0F,

View File

@@ -2370,7 +2370,7 @@ bool Canvas::project_save_thread(std::string file_path, bool show_progress)
// static char name[128];
// sprintf(name, "%s/latlong.ppi", data_path.c_str());
FILE* fp;
FILE* fp = nullptr;
const auto save_target = pp::app::plan_document_canvas_project_save_target(App::I->data_path, file_path);
if (!save_target) {
@@ -2385,15 +2385,25 @@ bool Canvas::project_save_thread(std::string file_path, bool show_progress)
LOG("file name %s", file_name.c_str());
LOG("tmp path %s", tmp_path.c_str());
bool use_tmp = false;
// check if file already exists
if ((fp = fopen(file_path.c_str(), "rb")))
{
bool target_exists = false;
if ((fp = fopen(file_path.c_str(), "rb"))) {
fclose(fp);
fp = nullptr;
target_exists = true;
}
const auto write_plan = pp::app::plan_document_canvas_project_save_write(save_paths, target_exists);
if (!write_plan) {
LOG("cannot plan project save write for %s: %s", file_path.c_str(), write_plan.status().message);
return false;
}
bool use_tmp = write_plan.value().uses_temporary;
if (write_plan.value().uses_temporary)
{
LOG("use tmp file");
// use tmp file for writing
use_tmp = true;
if (!(fp = fopen(tmp_path.c_str(), "wb")))
fp = fopen(write_plan.value().write_path.c_str(), "wb");
if (!fp)
{
LOG("cannot write tmp project to %s", tmp_path.c_str());
use_tmp = false;