Compare commits

...

1 Commits

Author SHA1 Message Date
Ian Chua
14537aac9e fix: load 3mf project after sync 2026-05-25 16:57:26 +08:00
2 changed files with 92 additions and 32 deletions

View File

@@ -737,36 +737,50 @@ void GUI_App::post_init()
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", init with input files, size %1%, input_gcode %2%") BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", init with input files, size %1%, input_gcode %2%")
%this->init_params->input_files.size() %this->init_params->input_gcode; %this->init_params->input_files.size() %this->init_params->input_gcode;
switch_to_3d = true; bool load_immediately = true;
if (app_config->get("sync_user_preset") == "true" && m_agent && m_agent->is_user_login()
&& !this->init_params->input_gcode
&& !(this->init_params->input_files.size() == 1 && is_supported_open_protocol(this->init_params->input_files.front()))) {
// Defer loading until after cloud sync completes, so project settings
// from the 3MF override synced presets instead of the reverse.
m_pending_input_files = std::move(this->init_params->input_files);
this->init_params->input_files.clear();
load_immediately = false;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": deferring input file load until after cloud sync";
}
const auto first_url = this->init_params->input_files.front(); if (load_immediately) {
if (this->init_params->input_files.size() == 1 && is_supported_open_protocol(first_url)) { switch_to_3d = true;
start_download(first_url);
m_open_method = "url"; const auto first_url = this->init_params->input_files.front();
} else { if (this->init_params->input_files.size() == 1 && is_supported_open_protocol(first_url)) {
if (this->init_params->input_gcode) { start_download(first_url);
mainframe->select_tab(size_t(MainFrame::tp3DEditor)); m_open_method = "url";
plater_->select_view_3D("3D");
this->plater()->load_gcode(from_u8(this->init_params->input_files.front()));
m_open_method = "gcode";
} else { } else {
mainframe->select_tab(size_t(MainFrame::tp3DEditor)); if (this->init_params->input_gcode) {
plater_->select_view_3D("3D"); mainframe->select_tab(size_t(MainFrame::tp3DEditor));
wxArrayString input_files; plater_->select_view_3D("3D");
for (auto& file : this->init_params->input_files) { this->plater()->load_gcode(from_u8(this->init_params->input_files.front()));
input_files.push_back(wxString::FromUTF8(file)); m_open_method = "gcode";
} } else {
this->plater()->set_project_filename(_L("Untitled")); mainframe->select_tab(size_t(MainFrame::tp3DEditor));
this->plater()->load_files(input_files); plater_->select_view_3D("3D");
try { wxArrayString input_files;
if (!input_files.empty()) { for (auto& file : this->init_params->input_files) {
std::string file_path = input_files.front().ToStdString(); input_files.push_back(wxString::FromUTF8(file));
std::filesystem::path path(file_path); }
m_open_method = "file_" + path.extension().string(); this->plater()->set_project_filename(_L("Untitled"));
this->plater()->load_files(input_files);
try {
if (!input_files.empty()) {
std::string file_path = input_files.front().ToStdString();
std::filesystem::path path(file_path);
m_open_method = "file_" + path.extension().string();
}
} catch (...) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ", file path exception!";
m_open_method = "file";
} }
} catch (...) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ", file path exception!";
m_open_method = "file";
} }
} }
} }
@@ -887,12 +901,9 @@ void GUI_App::post_init()
show_network_plugin_download_dialog(false); show_network_plugin_download_dialog(false);
} }
// Start preset sync after project opened, otherwise we could have preset change during project opening which could cause crash // Start preset sync. When input files are present, loading is deferred so
// the sync runs first and the 3MF project settings override synced defaults.
if (app_config->get("sync_user_preset") == "true") { if (app_config->get("sync_user_preset") == "true") {
// BBS loading user preset
// Always async, not such startup step
// BOOST_LOG_TRIVIAL(info) << "Loading user presets...";
// scrn->SetText(_L("Loading user presets..."));
if (m_agent) { if (m_agent) {
start_sync_user_preset(); start_sync_user_preset();
} }
@@ -901,6 +912,12 @@ void GUI_App::post_init()
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " sync_user_preset: false"; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " sync_user_preset: false";
} }
// If input files were deferred but sync wasn't started (not logged in, etc.), load them now
if (!m_pending_input_files.empty() && !m_user_sync_token) {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": sync not started, loading deferred input files directly";
CallAfter([this]() { load_pending_input_files(); });
}
// The extra CallAfter() is needed because of Mac, where this is the only way // The extra CallAfter() is needed because of Mac, where this is the only way
// to popup a modal dialog on start without screwing combo boxes. // to popup a modal dialog on start without screwing combo boxes.
// This is ugly but I honestly found no better way to do it. // This is ugly but I honestly found no better way to do it.
@@ -5895,6 +5912,38 @@ void GUI_App::remove_user_presets()
} }
} }
void GUI_App::load_pending_input_files()
{
if (m_pending_input_files.empty() || is_closing()) return;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": loading " << m_pending_input_files.size() << " deferred input file(s)";
mainframe->select_tab(size_t(MainFrame::tp3DEditor));
plater_->select_view_3D("3D");
wxArrayString input_files;
for (auto& file : m_pending_input_files)
input_files.push_back(wxString::FromUTF8(file));
this->plater()->set_project_filename(_L("Untitled"));
this->plater()->load_files(input_files);
try {
if (!input_files.empty()) {
std::string file_path = input_files.front().ToStdString();
std::filesystem::path path(file_path);
m_open_method = "file_" + path.extension().string();
}
} catch (...) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ", file path exception!";
m_open_method = "file";
}
plater_->trigger_restore_project(1);
m_pending_input_files.clear();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": deferred input files loaded";
}
// Check if the user's OrcaCloud profile directory is empty and offer to migrate // Check if the user's OrcaCloud profile directory is empty and offer to migrate
// existing profiles from the default or BambuCloud user folder. // existing profiles from the default or BambuCloud user folder.
// Returns true if migration was performed, false otherwise. // Returns true if migration was performed, false otherwise.
@@ -6657,6 +6706,15 @@ void GUI_App::start_sync_user_preset(bool with_progress_dlg)
if (ret == 0 && m_agent && !t.expired()) if (ret == 0 && m_agent && !t.expired())
reload_settings(); reload_settings();
// After initial sync cycle, load any input files that were deferred
// so the 3MF project settings override the freshly-synced cloud defaults.
if (!m_pending_input_files.empty()) {
CallAfter([this]() {
if (!m_pending_input_files.empty())
load_pending_input_files();
});
}
// For orca specific syncing // For orca specific syncing
auto orca_agent = std::dynamic_pointer_cast<OrcaCloudServiceAgent>(m_agent->get_cloud_agent()); auto orca_agent = std::dynamic_pointer_cast<OrcaCloudServiceAgent>(m_agent->get_cloud_agent());
int tick_tock = -1, sync_count = 0; // tick_tock = -1 to immediately run sync the frist time this thread runs int tick_tock = -1, sync_count = 0; // tick_tock = -1 to immediately run sync the frist time this thread runs

View File

@@ -322,6 +322,7 @@ private:
boost::thread m_sync_update_thread; boost::thread m_sync_update_thread;
std::shared_ptr<int> m_user_sync_token; std::shared_ptr<int> m_user_sync_token;
std::atomic<bool> m_restart_sync_pending {false}; std::atomic<bool> m_restart_sync_pending {false};
std::vector<std::string> m_pending_input_files; // input files deferred until after cloud sync
bool m_is_dark_mode{ false }; bool m_is_dark_mode{ false };
bool m_adding_script_handler { false }; bool m_adding_script_handler { false };
bool m_side_popup_status{false}; bool m_side_popup_status{false};
@@ -521,6 +522,7 @@ public:
void push_notification(const MachineObject* obj, wxString msg, wxString title = wxEmptyString, UserNotificationStyle style = UserNotificationStyle::UNS_NORMAL); void push_notification(const MachineObject* obj, wxString msg, wxString title = wxEmptyString, UserNotificationStyle style = UserNotificationStyle::UNS_NORMAL);
void reload_settings(); void reload_settings();
void remove_user_presets(); void remove_user_presets();
void load_pending_input_files();
bool maybe_migrate_user_presets_on_login(); bool maybe_migrate_user_presets_on_login();