Plan document export reporting
This commit is contained in:
@@ -653,6 +653,9 @@ Known local toolchain state:
|
|||||||
dialog metadata for equirectangular image, layer/frame collection,
|
dialog metadata for equirectangular image, layer/frame collection,
|
||||||
depth/cube, animation MP4, and timelapse success paths as JSON, including
|
depth/cube, animation MP4, and timelapse success paths as JSON, including
|
||||||
platform-style destinations and suppressed/no-message paths.
|
platform-style destinations and suppressed/no-message paths.
|
||||||
|
- `pano_cli plan-export-report` exposes `pp_app_core` export failure and
|
||||||
|
license-disabled dialog metadata as JSON; live export dialogs consume the
|
||||||
|
same metadata before retained legacy export execution or logging continues.
|
||||||
- `pano_cli plan-export-start` exposes `pp_app_core` export availability
|
- `pano_cli plan-export-start` exposes `pp_app_core` export availability
|
||||||
planning for license-gated, demo-blocked, and missing-canvas states as JSON;
|
planning for license-gated, demo-blocked, and missing-canvas states as JSON;
|
||||||
the live image, layer, animation-frame, depth, and cube-face export dialogs
|
the live image, layer, animation-frame, depth, and cube-face export dialogs
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -523,6 +523,9 @@ canvas/recording export execution.
|
|||||||
metadata now consumed by the live legacy export bridge for equirectangular,
|
metadata now consumed by the live legacy export bridge for equirectangular,
|
||||||
layer/frame, depth/cube, animation MP4, and timelapse success reporting,
|
layer/frame, depth/cube, animation MP4, and timelapse success reporting,
|
||||||
including platform-style destinations and no-message/suppressed branches.
|
including platform-style destinations and no-message/suppressed branches.
|
||||||
|
`pano_cli plan-export-report` exposes app-core failure and license-disabled
|
||||||
|
dialog metadata now consumed by live export dialogs before retained legacy
|
||||||
|
export execution/logging continues.
|
||||||
`pano_cli plan-recording-session` exposes the app-core recording start, stop,
|
`pano_cli plan-recording-session` exposes the app-core recording start, stop,
|
||||||
clear, platform recorded-file cleanup, frame reset, and export progress-total
|
clear, platform recorded-file cleanup, frame reset, and export progress-total
|
||||||
decisions used by the live recording controls. Recording lifecycle and MP4
|
decisions used by the live recording controls. Recording lifecycle and MP4
|
||||||
@@ -662,6 +665,9 @@ before legacy export dialogs and renderer/video execution continue.
|
|||||||
Export success-message metadata now also comes from `pp_app_core` through
|
Export success-message metadata now also comes from `pp_app_core` through
|
||||||
`pano_cli plan-export-message` and the legacy document-export bridge, reducing
|
`pano_cli plan-export-message` and the legacy document-export bridge, reducing
|
||||||
the bridge to export execution, platform handoff, and retained threading.
|
the bridge to export execution, platform handoff, and retained threading.
|
||||||
|
Export failure/license dialog metadata now comes from `pp_app_core` through
|
||||||
|
`pano_cli plan-export-report`, with legacy `App::dialog_export*` only showing
|
||||||
|
the planned dialog and dispatching retained export calls.
|
||||||
`pano_cli plan-grid-operation` exposes app-core planning for grid heightmap
|
`pano_cli plan-grid-operation` exposes app-core planning for grid heightmap
|
||||||
pick/load/reload/clear, lightmap render capability/limit checks, and heightmap
|
pick/load/reload/clear, lightmap render capability/limit checks, and heightmap
|
||||||
commit used by the live grid panel. Grid execution now dispatches through
|
commit used by the live grid panel. Grid execution now dispatches through
|
||||||
|
|||||||
@@ -92,6 +92,18 @@ enum class DocumentExportSuccessDestination {
|
|||||||
generic_success,
|
generic_success,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class DocumentExportExecutionKind {
|
||||||
|
equirectangular_file,
|
||||||
|
layers_collection,
|
||||||
|
layers_stem,
|
||||||
|
animation_frames_collection,
|
||||||
|
animation_frames_stem,
|
||||||
|
depth,
|
||||||
|
cube_faces,
|
||||||
|
animation_mp4,
|
||||||
|
timelapse,
|
||||||
|
};
|
||||||
|
|
||||||
struct DocumentExportMenuPlan {
|
struct DocumentExportMenuPlan {
|
||||||
DocumentExportMenuKind kind = DocumentExportMenuKind::jpeg;
|
DocumentExportMenuKind kind = DocumentExportMenuKind::jpeg;
|
||||||
DocumentExportMenuAction action = DocumentExportMenuAction::show_jpeg_dialog;
|
DocumentExportMenuAction action = DocumentExportMenuAction::show_jpeg_dialog;
|
||||||
@@ -271,6 +283,68 @@ public:
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr DocumentExportSuccessKind document_export_collection_success_kind(
|
||||||
|
DocumentExportCollectionKind kind) noexcept
|
||||||
|
{
|
||||||
|
switch (kind) {
|
||||||
|
case DocumentExportCollectionKind::layers:
|
||||||
|
return DocumentExportSuccessKind::layers;
|
||||||
|
case DocumentExportCollectionKind::animation_frames:
|
||||||
|
return DocumentExportSuccessKind::animation_frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DocumentExportSuccessKind::layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const char* document_export_failure_dialog_title(
|
||||||
|
DocumentExportSuccessKind kind) noexcept
|
||||||
|
{
|
||||||
|
switch (kind) {
|
||||||
|
case DocumentExportSuccessKind::equirectangular:
|
||||||
|
return "Export Equirectangular";
|
||||||
|
case DocumentExportSuccessKind::layers:
|
||||||
|
case DocumentExportSuccessKind::animation_frames:
|
||||||
|
return "Export Layers";
|
||||||
|
case DocumentExportSuccessKind::depth:
|
||||||
|
return "Export 3D View + Depth";
|
||||||
|
case DocumentExportSuccessKind::cube_faces:
|
||||||
|
return "Export Cube Faces";
|
||||||
|
case DocumentExportSuccessKind::animation_mp4:
|
||||||
|
return "Export Animation";
|
||||||
|
case DocumentExportSuccessKind::timelapse:
|
||||||
|
return "Export Timelapse";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Export";
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr const char* document_export_execution_log_message(
|
||||||
|
DocumentExportExecutionKind kind) noexcept
|
||||||
|
{
|
||||||
|
switch (kind) {
|
||||||
|
case DocumentExportExecutionKind::equirectangular_file:
|
||||||
|
return "Document export file action failed";
|
||||||
|
case DocumentExportExecutionKind::layers_collection:
|
||||||
|
return "Document layer collection export failed";
|
||||||
|
case DocumentExportExecutionKind::layers_stem:
|
||||||
|
return "Document layer stem export failed";
|
||||||
|
case DocumentExportExecutionKind::animation_frames_collection:
|
||||||
|
return "Document animation frame collection export failed";
|
||||||
|
case DocumentExportExecutionKind::animation_frames_stem:
|
||||||
|
return "Document animation frame stem export failed";
|
||||||
|
case DocumentExportExecutionKind::depth:
|
||||||
|
return "Document depth export failed";
|
||||||
|
case DocumentExportExecutionKind::cube_faces:
|
||||||
|
return "Document cube-face export failed";
|
||||||
|
case DocumentExportExecutionKind::animation_mp4:
|
||||||
|
return "Document animation export failed";
|
||||||
|
case DocumentExportExecutionKind::timelapse:
|
||||||
|
return "Document timelapse export failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Document export failed";
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr DocumentExportCollectionTargetPlan plan_document_export_collection_target(
|
[[nodiscard]] constexpr DocumentExportCollectionTargetPlan plan_document_export_collection_target(
|
||||||
DocumentExportCollectionKind kind,
|
DocumentExportCollectionKind kind,
|
||||||
bool use_work_directory_collection) noexcept
|
bool use_work_directory_collection) noexcept
|
||||||
@@ -284,6 +358,24 @@ public:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline AppMessageDialogPlan plan_document_export_failure_dialog(
|
||||||
|
DocumentExportSuccessKind kind,
|
||||||
|
std::string_view status_message)
|
||||||
|
{
|
||||||
|
return plan_app_message_dialog(
|
||||||
|
document_export_failure_dialog_title(kind),
|
||||||
|
status_message,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] inline AppMessageDialogPlan plan_document_export_license_disabled_dialog()
|
||||||
|
{
|
||||||
|
return plan_app_message_dialog(
|
||||||
|
"License",
|
||||||
|
"This function is disabled in demo mode.",
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline DocumentExportSuccessDialogPlan plan_document_export_success_dialog(
|
[[nodiscard]] inline DocumentExportSuccessDialogPlan plan_document_export_success_dialog(
|
||||||
DocumentExportSuccessKind kind,
|
DocumentExportSuccessKind kind,
|
||||||
DocumentExportSuccessDestination destination,
|
DocumentExportSuccessDestination destination,
|
||||||
|
|||||||
@@ -45,8 +45,11 @@ namespace {
|
|||||||
case pp::app::DocumentExportStartDecision::start_now:
|
case pp::app::DocumentExportStartDecision::start_now:
|
||||||
return true;
|
return true;
|
||||||
case pp::app::DocumentExportStartDecision::show_license_disabled:
|
case pp::app::DocumentExportStartDecision::show_license_disabled:
|
||||||
app.message_box("License", "This function is disabled in demo mode.");
|
{
|
||||||
|
const auto plan = pp::app::plan_document_export_license_disabled_dialog();
|
||||||
|
app.message_box(plan.title, plan.message, plan.show_cancel);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
case pp::app::DocumentExportStartDecision::unavailable_no_canvas:
|
case pp::app::DocumentExportStartDecision::unavailable_no_canvas:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -56,14 +59,12 @@ namespace {
|
|||||||
|
|
||||||
void start_document_export_collection(
|
void start_document_export_collection(
|
||||||
App& app,
|
App& app,
|
||||||
pp::app::DocumentExportCollectionKind kind,
|
pp::app::DocumentExportCollectionKind kind)
|
||||||
const char* message_title,
|
|
||||||
const char* collection_log_message,
|
|
||||||
const char* stem_log_message)
|
|
||||||
{
|
{
|
||||||
const auto plan = pp::app::plan_document_export_collection_target(
|
const auto plan = pp::app::plan_document_export_collection_target(
|
||||||
kind,
|
kind,
|
||||||
app.uses_work_directory_document_export_collections());
|
app.uses_work_directory_document_export_collections());
|
||||||
|
const auto success_kind = pp::app::document_export_collection_success_kind(kind);
|
||||||
|
|
||||||
if (plan.destination == pp::app::DocumentExportCollectionDestination::work_directory_collection) {
|
if (plan.destination == pp::app::DocumentExportCollectionDestination::work_directory_collection) {
|
||||||
const auto target = pp::app::make_document_export_collection_target(
|
const auto target = pp::app::make_document_export_collection_target(
|
||||||
@@ -71,7 +72,8 @@ void start_document_export_collection(
|
|||||||
app.doc_name,
|
app.doc_name,
|
||||||
plan.suffix);
|
plan.suffix);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
app.message_box(message_title, target.status().message);
|
const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message);
|
||||||
|
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,19 +82,25 @@ void start_document_export_collection(
|
|||||||
plan.kind,
|
plan.kind,
|
||||||
target.value());
|
target.value());
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("%s: %s", collection_log_message, status.message);
|
LOG(
|
||||||
|
"%s: %s",
|
||||||
|
pp::app::document_export_execution_log_message(
|
||||||
|
kind == pp::app::DocumentExportCollectionKind::layers
|
||||||
|
? pp::app::DocumentExportExecutionKind::layers_collection
|
||||||
|
: pp::app::DocumentExportExecutionKind::animation_frames_collection),
|
||||||
|
status.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.pick_dir([
|
app.pick_dir([
|
||||||
&app,
|
&app,
|
||||||
kind = plan.kind,
|
kind = plan.kind,
|
||||||
title = std::string(message_title),
|
success_kind
|
||||||
log_message = std::string(stem_log_message)
|
|
||||||
](std::string path) {
|
](std::string path) {
|
||||||
const auto target = pp::app::make_document_export_stem_target(path, app.doc_name);
|
const auto target = pp::app::make_document_export_stem_target(path, app.doc_name);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
app.message_box(title, target.status().message);
|
const auto dialog = pp::app::plan_document_export_failure_dialog(success_kind, target.status().message);
|
||||||
|
app.message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +109,13 @@ void start_document_export_collection(
|
|||||||
kind,
|
kind,
|
||||||
target.value());
|
target.value());
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("%s: %s", log_message.c_str(), status.message);
|
LOG(
|
||||||
|
"%s: %s",
|
||||||
|
pp::app::document_export_execution_log_message(
|
||||||
|
kind == pp::app::DocumentExportCollectionKind::layers
|
||||||
|
? pp::app::DocumentExportExecutionKind::layers_stem
|
||||||
|
: pp::app::DocumentExportExecutionKind::animation_frames_stem),
|
||||||
|
status.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,13 +423,20 @@ void App::dialog_export(std::string ext)
|
|||||||
// TODO: use picker
|
// TODO: use picker
|
||||||
const auto target = pp::app::make_document_export_file_target(work_path, doc_name, ext);
|
const auto target = pp::app::make_document_export_file_target(work_path, doc_name, ext);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
message_box("Export Equirectangular", target.status().message);
|
const auto dialog = pp::app::plan_document_export_failure_dialog(
|
||||||
|
pp::app::DocumentExportSuccessKind::equirectangular,
|
||||||
|
target.status().message);
|
||||||
|
message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto status = pp::panopainter::execute_legacy_document_export_file(*this, target.value());
|
const auto status = pp::panopainter::execute_legacy_document_export_file(*this, target.value());
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("Document export file action failed: %s", status.message);
|
LOG(
|
||||||
|
"%s: %s",
|
||||||
|
pp::app::document_export_execution_log_message(
|
||||||
|
pp::app::DocumentExportExecutionKind::equirectangular_file),
|
||||||
|
status.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::dialog_export_layers()
|
void App::dialog_export_layers()
|
||||||
@@ -425,10 +446,7 @@ void App::dialog_export_layers()
|
|||||||
|
|
||||||
start_document_export_collection(
|
start_document_export_collection(
|
||||||
*this,
|
*this,
|
||||||
pp::app::DocumentExportCollectionKind::layers,
|
pp::app::DocumentExportCollectionKind::layers);
|
||||||
"Export Layers",
|
|
||||||
"Document layer collection export failed",
|
|
||||||
"Document layer stem export failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::dialog_export_anim_frames()
|
void App::dialog_export_anim_frames()
|
||||||
@@ -438,10 +456,7 @@ void App::dialog_export_anim_frames()
|
|||||||
|
|
||||||
start_document_export_collection(
|
start_document_export_collection(
|
||||||
*this,
|
*this,
|
||||||
pp::app::DocumentExportCollectionKind::animation_frames,
|
pp::app::DocumentExportCollectionKind::animation_frames);
|
||||||
"Export Layers",
|
|
||||||
"Document animation frame collection export failed",
|
|
||||||
"Document animation frame stem export failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::dialog_export_depth()
|
void App::dialog_export_depth()
|
||||||
@@ -451,7 +466,10 @@ void App::dialog_export_depth()
|
|||||||
|
|
||||||
const auto status = pp::panopainter::execute_legacy_document_export_depth(*this, doc_name);
|
const auto status = pp::panopainter::execute_legacy_document_export_depth(*this, doc_name);
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("Document depth export failed: %s", status.message);
|
LOG(
|
||||||
|
"%s: %s",
|
||||||
|
pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::depth),
|
||||||
|
status.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::dialog_resize()
|
void App::dialog_resize()
|
||||||
@@ -487,7 +505,10 @@ void App::dialog_export_cube_faces()
|
|||||||
|
|
||||||
const auto status = pp::panopainter::execute_legacy_document_export_cube_faces(*this, doc_name);
|
const auto status = pp::panopainter::execute_legacy_document_export_cube_faces(*this, doc_name);
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("Document cube-face export failed: %s", status.message);
|
LOG(
|
||||||
|
"%s: %s",
|
||||||
|
pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::cube_faces),
|
||||||
|
status.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::dialog_layer_rename()
|
void App::dialog_layer_rename()
|
||||||
@@ -575,7 +596,10 @@ void App::dialog_timelapse_export()
|
|||||||
{
|
{
|
||||||
const auto target = pp::app::make_document_export_suggested_name(doc_name, "-timelapse");
|
const auto target = pp::app::make_document_export_suggested_name(doc_name, "-timelapse");
|
||||||
if (!target) {
|
if (!target) {
|
||||||
message_box("Export Timelapse", target.status().message);
|
const auto dialog = pp::app::plan_document_export_failure_dialog(
|
||||||
|
pp::app::DocumentExportSuccessKind::timelapse,
|
||||||
|
target.status().message);
|
||||||
|
message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,7 +611,11 @@ void App::dialog_timelapse_export()
|
|||||||
path,
|
path,
|
||||||
false);
|
false);
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("Document timelapse export failed: %s", status.message);
|
LOG(
|
||||||
|
"%s: %s",
|
||||||
|
pp::app::document_export_execution_log_message(
|
||||||
|
pp::app::DocumentExportExecutionKind::timelapse),
|
||||||
|
status.message);
|
||||||
},
|
},
|
||||||
[](const std::string& path, bool saved) {
|
[](const std::string& path, bool saved) {
|
||||||
(void)path;
|
(void)path;
|
||||||
@@ -604,7 +632,10 @@ void App::dialog_timelapse_export()
|
|||||||
path,
|
path,
|
||||||
true);
|
true);
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("Document timelapse export failed: %s", status.message);
|
LOG(
|
||||||
|
"%s: %s",
|
||||||
|
pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::timelapse),
|
||||||
|
status.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,7 +648,10 @@ void App::dialog_export_mp4()
|
|||||||
{
|
{
|
||||||
const auto target = pp::app::make_document_export_suggested_name(doc_name, "-animation");
|
const auto target = pp::app::make_document_export_suggested_name(doc_name, "-animation");
|
||||||
if (!target) {
|
if (!target) {
|
||||||
message_box("Export Animation", target.status().message);
|
const auto dialog = pp::app::plan_document_export_failure_dialog(
|
||||||
|
pp::app::DocumentExportSuccessKind::animation_mp4,
|
||||||
|
target.status().message);
|
||||||
|
message_box(dialog.title, dialog.message, dialog.show_cancel);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -629,7 +663,11 @@ void App::dialog_export_mp4()
|
|||||||
path,
|
path,
|
||||||
false);
|
false);
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("Document animation export failed: %s", status.message);
|
LOG(
|
||||||
|
"%s: %s",
|
||||||
|
pp::app::document_export_execution_log_message(
|
||||||
|
pp::app::DocumentExportExecutionKind::animation_mp4),
|
||||||
|
status.message);
|
||||||
},
|
},
|
||||||
[](const std::string& path, bool saved) {
|
[](const std::string& path, bool saved) {
|
||||||
(void)path;
|
(void)path;
|
||||||
@@ -646,7 +684,10 @@ void App::dialog_export_mp4()
|
|||||||
path,
|
path,
|
||||||
true);
|
true);
|
||||||
if (!status.ok())
|
if (!status.ok())
|
||||||
LOG("Document animation export failed: %s", status.message);
|
LOG(
|
||||||
|
"%s: %s",
|
||||||
|
pp::app::document_export_execution_log_message(pp::app::DocumentExportExecutionKind::animation_mp4),
|
||||||
|
status.message);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -930,6 +930,25 @@ if(TARGET pano_cli)
|
|||||||
WILL_FAIL TRUE
|
WILL_FAIL TRUE
|
||||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-export-message\".*\"message\":\"unknown export message kind\"")
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-export-message\".*\"message\":\"unknown export message kind\"")
|
||||||
|
|
||||||
|
add_test(NAME pano_cli_plan_export_report_failure_smoke
|
||||||
|
COMMAND pano_cli plan-export-report --kind animation-mp4 --message "video export path must not be empty")
|
||||||
|
set_tests_properties(pano_cli_plan_export_report_failure_smoke PROPERTIES
|
||||||
|
LABELS "app;integration;desktop-fast;fuzz"
|
||||||
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-export-report\".*\"kind\":\"animation-mp4\".*\"title\":\"Export Animation\".*\"message\":\"video export path must not be empty\".*\"showCancel\":false")
|
||||||
|
|
||||||
|
add_test(NAME pano_cli_plan_export_report_license_smoke
|
||||||
|
COMMAND pano_cli plan-export-report --kind license-disabled)
|
||||||
|
set_tests_properties(pano_cli_plan_export_report_license_smoke PROPERTIES
|
||||||
|
LABELS "app;integration;desktop-fast"
|
||||||
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-export-report\".*\"kind\":\"license-disabled\".*\"title\":\"License\".*\"message\":\"This function is disabled in demo mode\\.\".*\"showCancel\":false")
|
||||||
|
|
||||||
|
add_test(NAME pano_cli_plan_export_report_rejects_unknown
|
||||||
|
COMMAND pano_cli plan-export-report --kind nope)
|
||||||
|
set_tests_properties(pano_cli_plan_export_report_rejects_unknown PROPERTIES
|
||||||
|
LABELS "app;integration;desktop-fast;fuzz"
|
||||||
|
WILL_FAIL TRUE
|
||||||
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-export-report\".*\"message\":\"unknown export message kind\"")
|
||||||
|
|
||||||
add_test(NAME pano_cli_plan_cloud_upload_clean_smoke
|
add_test(NAME pano_cli_plan_cloud_upload_clean_smoke
|
||||||
COMMAND pano_cli plan-cloud-upload)
|
COMMAND pano_cli plan-cloud-upload)
|
||||||
set_tests_properties(pano_cli_plan_cloud_upload_clean_smoke PROPERTIES
|
set_tests_properties(pano_cli_plan_cloud_upload_clean_smoke PROPERTIES
|
||||||
|
|||||||
@@ -327,6 +327,64 @@ void export_success_dialog_suppresses_unsupported_destinations(pp::tests::Harnes
|
|||||||
PP_EXPECT(harness, invalid_combo.dialog.message.empty());
|
PP_EXPECT(harness, invalid_combo.dialog.message.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void export_failure_dialog_plans_titles_and_messages(pp::tests::Harness& harness)
|
||||||
|
{
|
||||||
|
const auto equirect = pp::app::plan_document_export_failure_dialog(
|
||||||
|
pp::app::DocumentExportSuccessKind::equirectangular,
|
||||||
|
"document name must not be empty");
|
||||||
|
const auto frames = pp::app::plan_document_export_failure_dialog(
|
||||||
|
pp::app::DocumentExportSuccessKind::animation_frames,
|
||||||
|
"document name must not be empty");
|
||||||
|
const auto animation = pp::app::plan_document_export_failure_dialog(
|
||||||
|
pp::app::DocumentExportSuccessKind::animation_mp4,
|
||||||
|
"video export path must not be empty");
|
||||||
|
|
||||||
|
PP_EXPECT(harness, equirect.title == "Export Equirectangular");
|
||||||
|
PP_EXPECT(harness, equirect.message == "document name must not be empty");
|
||||||
|
PP_EXPECT(harness, !equirect.show_cancel);
|
||||||
|
PP_EXPECT(harness, frames.title == "Export Layers");
|
||||||
|
PP_EXPECT(harness, animation.title == "Export Animation");
|
||||||
|
PP_EXPECT(harness, animation.message == "video export path must not be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
void export_license_disabled_dialog_preserves_legacy_warning(pp::tests::Harness& harness)
|
||||||
|
{
|
||||||
|
const auto plan = pp::app::plan_document_export_license_disabled_dialog();
|
||||||
|
|
||||||
|
PP_EXPECT(harness, plan.title == "License");
|
||||||
|
PP_EXPECT(harness, plan.message == "This function is disabled in demo mode.");
|
||||||
|
PP_EXPECT(harness, !plan.show_cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void export_execution_log_messages_cover_legacy_paths(pp::tests::Harness& harness)
|
||||||
|
{
|
||||||
|
PP_EXPECT(
|
||||||
|
harness,
|
||||||
|
std::string_view(pp::app::document_export_execution_log_message(
|
||||||
|
pp::app::DocumentExportExecutionKind::equirectangular_file))
|
||||||
|
== "Document export file action failed");
|
||||||
|
PP_EXPECT(
|
||||||
|
harness,
|
||||||
|
std::string_view(pp::app::document_export_execution_log_message(
|
||||||
|
pp::app::DocumentExportExecutionKind::layers_collection))
|
||||||
|
== "Document layer collection export failed");
|
||||||
|
PP_EXPECT(
|
||||||
|
harness,
|
||||||
|
std::string_view(pp::app::document_export_execution_log_message(
|
||||||
|
pp::app::DocumentExportExecutionKind::animation_frames_stem))
|
||||||
|
== "Document animation frame stem export failed");
|
||||||
|
PP_EXPECT(
|
||||||
|
harness,
|
||||||
|
std::string_view(pp::app::document_export_execution_log_message(
|
||||||
|
pp::app::DocumentExportExecutionKind::cube_faces))
|
||||||
|
== "Document cube-face export failed");
|
||||||
|
PP_EXPECT(
|
||||||
|
harness,
|
||||||
|
std::string_view(pp::app::document_export_execution_log_message(
|
||||||
|
pp::app::DocumentExportExecutionKind::timelapse))
|
||||||
|
== "Document timelapse export failed");
|
||||||
|
}
|
||||||
|
|
||||||
void export_start_allows_valid_canvas_state(pp::tests::Harness& harness)
|
void export_start_allows_valid_canvas_state(pp::tests::Harness& harness)
|
||||||
{
|
{
|
||||||
PP_EXPECT(
|
PP_EXPECT(
|
||||||
@@ -666,6 +724,9 @@ int main()
|
|||||||
harness.run("export success dialog plans depth and cube destinations", export_success_dialog_plans_depth_and_cube_destinations);
|
harness.run("export success dialog plans depth and cube destinations", export_success_dialog_plans_depth_and_cube_destinations);
|
||||||
harness.run("export success dialog plans video destinations", export_success_dialog_plans_video_destinations);
|
harness.run("export success dialog plans video destinations", export_success_dialog_plans_video_destinations);
|
||||||
harness.run("export success dialog suppresses unsupported destinations", export_success_dialog_suppresses_unsupported_destinations);
|
harness.run("export success dialog suppresses unsupported destinations", export_success_dialog_suppresses_unsupported_destinations);
|
||||||
|
harness.run("export failure dialog plans titles and messages", export_failure_dialog_plans_titles_and_messages);
|
||||||
|
harness.run("export license disabled dialog preserves legacy warning", export_license_disabled_dialog_preserves_legacy_warning);
|
||||||
|
harness.run("export execution log messages cover legacy paths", export_execution_log_messages_cover_legacy_paths);
|
||||||
harness.run("export start allows valid canvas state", export_start_allows_valid_canvas_state);
|
harness.run("export start allows valid canvas state", export_start_allows_valid_canvas_state);
|
||||||
harness.run("export start blocks demo only when license required", export_start_blocks_demo_only_when_license_required);
|
harness.run("export start blocks demo only when license required", export_start_blocks_demo_only_when_license_required);
|
||||||
harness.run("export start reports missing canvas after license gate", export_start_reports_missing_canvas_after_license_gate);
|
harness.run("export start reports missing canvas after license gate", export_start_reports_missing_canvas_after_license_gate);
|
||||||
|
|||||||
@@ -174,6 +174,11 @@ struct PlanExportMessageArgs {
|
|||||||
std::string detail = "D:/Paint";
|
std::string detail = "D:/Paint";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct PlanExportReportArgs {
|
||||||
|
std::string kind = "equirectangular";
|
||||||
|
std::string message = "document name must not be empty";
|
||||||
|
};
|
||||||
|
|
||||||
struct PlanExportStartArgs {
|
struct PlanExportStartArgs {
|
||||||
bool requires_license = false;
|
bool requires_license = false;
|
||||||
bool license_valid = true;
|
bool license_valid = true;
|
||||||
@@ -2358,6 +2363,7 @@ void print_help()
|
|||||||
<< " plan-export-menu --kind jpeg|png|layers|cube-faces|depth|animation-frames|animation-mp4|timelapse [--demo] [--no-canvas]\n"
|
<< " plan-export-menu --kind jpeg|png|layers|cube-faces|depth|animation-frames|animation-mp4|timelapse [--demo] [--no-canvas]\n"
|
||||||
<< " plan-export-target --kind file|collection|stem|name --doc-name NAME [--work-dir DIR] [--directory DIR] [--extension EXT] [--suffix SUFFIX]\n"
|
<< " plan-export-target --kind file|collection|stem|name --doc-name NAME [--work-dir DIR] [--directory DIR] [--extension EXT] [--suffix SUFFIX]\n"
|
||||||
<< " plan-export-message --kind equirectangular|layers|animation-frames|depth|cube-faces|animation-mp4|timelapse --destination photos|pictures|files|work|path|success|suppressed [--detail TEXT]\n"
|
<< " plan-export-message --kind equirectangular|layers|animation-frames|depth|cube-faces|animation-mp4|timelapse --destination photos|pictures|files|work|path|success|suppressed [--detail TEXT]\n"
|
||||||
|
<< " plan-export-report --kind license-disabled|equirectangular|layers|animation-frames|depth|cube-faces|animation-mp4|timelapse [--message TEXT]\n"
|
||||||
<< " plan-cloud-upload [--no-canvas] [--new-document] [--unsaved]\n"
|
<< " plan-cloud-upload [--no-canvas] [--new-document] [--unsaved]\n"
|
||||||
<< " plan-cloud-browse [--no-canvas] [--selected-file FILE]\n"
|
<< " plan-cloud-browse [--no-canvas] [--selected-file FILE]\n"
|
||||||
<< " plan-cloud-upload-all [--file-count N] [--no-progress-ui]\n"
|
<< " plan-cloud-upload-all [--file-count N] [--no-progress-ui]\n"
|
||||||
@@ -3780,6 +3786,62 @@ int plan_export_message(int argc, char** argv)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp::foundation::Status parse_plan_export_report_args(
|
||||||
|
int argc,
|
||||||
|
char** argv,
|
||||||
|
PlanExportReportArgs& args)
|
||||||
|
{
|
||||||
|
for (int i = 2; i < argc; ++i) {
|
||||||
|
const std::string_view key(argv[i]);
|
||||||
|
if (key == "--kind") {
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
return pp::foundation::Status::invalid_argument("missing value for option");
|
||||||
|
}
|
||||||
|
args.kind = argv[++i];
|
||||||
|
} else if (key == "--message") {
|
||||||
|
if (i + 1 >= argc) {
|
||||||
|
return pp::foundation::Status::invalid_argument("missing value for option");
|
||||||
|
}
|
||||||
|
args.message = argv[++i];
|
||||||
|
} else {
|
||||||
|
return pp::foundation::Status::invalid_argument("unknown option");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Status::success();
|
||||||
|
}
|
||||||
|
|
||||||
|
int plan_export_report(int argc, char** argv)
|
||||||
|
{
|
||||||
|
PlanExportReportArgs args;
|
||||||
|
const auto status = parse_plan_export_report_args(argc, argv, args);
|
||||||
|
if (!status.ok()) {
|
||||||
|
print_error("plan-export-report", status.message);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pp::app::AppMessageDialogPlan dialog;
|
||||||
|
if (args.kind == "license-disabled") {
|
||||||
|
dialog = pp::app::plan_document_export_license_disabled_dialog();
|
||||||
|
} else {
|
||||||
|
const auto kind = parse_document_export_success_kind(args.kind);
|
||||||
|
if (!kind) {
|
||||||
|
print_error("plan-export-report", kind.status().message);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
dialog = pp::app::plan_document_export_failure_dialog(kind.value(), args.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "{\"ok\":true,\"command\":\"plan-export-report\""
|
||||||
|
<< ",\"state\":{\"kind\":\"" << json_escape(args.kind)
|
||||||
|
<< "\",\"message\":\"" << json_escape(args.message)
|
||||||
|
<< "\"},\"dialog\":{\"title\":\"" << json_escape(dialog.title)
|
||||||
|
<< "\",\"message\":\"" << json_escape(dialog.message)
|
||||||
|
<< "\",\"showCancel\":" << json_bool(dialog.show_cancel)
|
||||||
|
<< "}}\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
pp::foundation::Status parse_plan_cloud_upload_args(
|
pp::foundation::Status parse_plan_cloud_upload_args(
|
||||||
int argc,
|
int argc,
|
||||||
char** argv,
|
char** argv,
|
||||||
@@ -11383,6 +11445,10 @@ int main(int argc, char** argv)
|
|||||||
return plan_export_message(argc, argv);
|
return plan_export_message(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (command == "plan-export-report") {
|
||||||
|
return plan_export_report(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
if (command == "plan-cloud-upload") {
|
if (command == "plan-cloud-upload") {
|
||||||
return plan_cloud_upload(argc, argv);
|
return plan_cloud_upload(argc, argv);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user