mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-19 08:52:09 +00:00
fix: merge branch feat/plugin-feature
This commit is contained in:
@@ -116,8 +116,8 @@ struct PluginDialogItem
|
||||
PluginAvailableActions available_actions;
|
||||
};
|
||||
|
||||
constexpr bool kFetchCloudCatalog = true;
|
||||
constexpr bool kUseCurrentCloudCatalog = false;
|
||||
constexpr bool kFetchCloudMeta = true;
|
||||
constexpr bool kUseCurrentCloudMeta = false;
|
||||
|
||||
// The type of a package's first loaded capability. A package that is not loaded has no type.
|
||||
PluginCapabilityType primary_capability_type_of(PluginManager& manager, const std::string& plugin_key)
|
||||
@@ -126,7 +126,7 @@ PluginCapabilityType primary_capability_type_of(PluginManager& manager, const st
|
||||
return capabilities.empty() ? PluginCapabilityType::Unknown : capabilities.front()->type();
|
||||
}
|
||||
|
||||
std::vector<PluginDescriptor> current_cloud_catalog_snapshot()
|
||||
std::vector<PluginDescriptor> current_cloud_metadata_snapshot()
|
||||
{
|
||||
std::vector<PluginDescriptor> cloud_entries;
|
||||
for (const PluginDescriptor& entry : PluginManager::instance().get_plugin_descriptors(/*include_invalid=*/true))
|
||||
@@ -147,20 +147,18 @@ PluginDescriptor as_cloud_only_descriptor(PluginDescriptor descriptor)
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
// rescan_plugins() clears the whole catalog and rediscovers only local packages, so when no fresh cloud
|
||||
// data is needed, restore the current cloud rows afterwards or cloud-only rows would disappear.
|
||||
void refresh_plugin_catalog_blocking(bool fetch_cloud)
|
||||
void refresh_plugin_metadata_blocking(bool fetch_cloud)
|
||||
{
|
||||
PluginManager& manager = PluginManager::instance();
|
||||
|
||||
std::vector<std::string> not_found, unauthorized;
|
||||
const std::vector<PluginDescriptor> current_cloud_catalog = fetch_cloud ? std::vector<PluginDescriptor>{} :
|
||||
current_cloud_catalog_snapshot();
|
||||
const std::vector<PluginDescriptor> current_cloud_metadata = fetch_cloud ? std::vector<PluginDescriptor>{} :
|
||||
current_cloud_metadata_snapshot();
|
||||
|
||||
manager.rescan_plugins();
|
||||
|
||||
if (!fetch_cloud) {
|
||||
manager.update_cloud_catalog(current_cloud_catalog);
|
||||
manager.update_cloud_metadata(current_cloud_metadata);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -450,7 +448,7 @@ void PluginsDialog::set_open_terminal_dlg_fn()
|
||||
|
||||
void PluginsDialog::update_plugin_dialog_ui()
|
||||
{
|
||||
// Called after the shared catalog is already updated, for example from the
|
||||
// Called after the any metadata is already updated, for example from the
|
||||
// cloud-plugin state callback. Do not fetch here or the callback can re-enter.
|
||||
send_plugins();
|
||||
resolve_pending_activation();
|
||||
@@ -482,10 +480,21 @@ void PluginsDialog::on_script_message(const nlohmann::json& payload)
|
||||
if (handle_common_script_command(payload))
|
||||
return;
|
||||
|
||||
// Defer command handling out of the webview script-message callback: GTK and macOS
|
||||
// deliver it synchronously inside the native webview callback (see ui_create_window
|
||||
// in PluginHostUi.cpp), and window work on that stack is the crash class fixed in
|
||||
// b779a7bfed/f2ccbfc8b5. Deferring at this single entry point keeps every command
|
||||
// handler, current and future, off that stack by construction.
|
||||
wxGetApp().CallAfter([this, alive = m_alive, payload]() {
|
||||
if (alive->load(std::memory_order_acquire))
|
||||
handle_web_command(payload);
|
||||
});
|
||||
}
|
||||
|
||||
void PluginsDialog::handle_web_command(const nlohmann::json& payload)
|
||||
{
|
||||
const std::string command = payload.value("command", "");
|
||||
if (command == "request_plugins") {
|
||||
// Discovery already runs at startup and on login, so the shared catalog is up to date by the
|
||||
// time the dialog opens: render it without a blocking fetch. Refresh is what rediscovers.
|
||||
send_plugins();
|
||||
} else if (command == "refresh_plugins") {
|
||||
refresh_plugins();
|
||||
@@ -498,8 +507,8 @@ void PluginsDialog::on_script_message(const nlohmann::json& payload)
|
||||
install_plugin_from_file();
|
||||
} else if (command == "plugin_menu_action") {
|
||||
handle_plugin_menu_action(payload.value("plugin_key", ""), payload.value("action", ""));
|
||||
} else if (command == "run_script_plugin") {
|
||||
run_script_plugin(payload.value("plugin_key", ""), payload.value("capability_name", ""));
|
||||
} else if (command == "run_script_plugin_capability") {
|
||||
run_script_plugin_capability(payload.value("plugin_key", ""), payload.value("capability_name", ""));
|
||||
} else if (command == "open_terminal") {
|
||||
m_open_terminal_dlg_fn();
|
||||
} else if (command == "update_plugin") {
|
||||
@@ -575,16 +584,16 @@ bool PluginsDialog::get_descriptor(const std::string& plugin_key, PluginDescript
|
||||
return manager.try_get_plugin_descriptor(plugin_key, descriptor) && descriptor.is_invalid_package();
|
||||
}
|
||||
|
||||
void PluginsDialog::refresh_plugin_catalog_async(const wxString& title, const wxString& message, bool fetch_cloud)
|
||||
void PluginsDialog::refresh_plugin_metadata_async(const wxString& title, const wxString& message, bool fetch_cloud)
|
||||
{
|
||||
run_with_dialog([fetch_cloud]() { refresh_plugin_catalog_blocking(fetch_cloud); }, [this]() { send_plugins(); }, title, message);
|
||||
run_with_dialog([fetch_cloud]() { refresh_plugin_metadata_blocking(fetch_cloud); }, [this]() { send_plugins(); }, title, message);
|
||||
}
|
||||
|
||||
void PluginsDialog::refresh_plugins()
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "Refreshing plugins from Plugins dialog";
|
||||
|
||||
refresh_plugin_catalog_async(_L("Refreshing"), _L("Refreshing plugins data"), kFetchCloudCatalog);
|
||||
refresh_plugin_metadata_async(_L("Refreshing"), _L("Refreshing plugins data"), kFetchCloudMeta);
|
||||
}
|
||||
|
||||
void PluginsDialog::toggle_plugin(const std::string& plugin_key, bool enabled)
|
||||
@@ -596,7 +605,6 @@ void PluginsDialog::toggle_plugin(const std::string& plugin_key, bool enabled)
|
||||
|
||||
PluginDescriptor row_data;
|
||||
if (!get_descriptor(plugin_key, row_data)) {
|
||||
// The catalog changed under the UI. Toggling is local, so just re-render from it.
|
||||
send_plugins();
|
||||
return;
|
||||
}
|
||||
@@ -688,7 +696,6 @@ void PluginsDialog::toggle_plugin_capability(const std::string& plugin_key,
|
||||
|
||||
PluginDescriptor row_data;
|
||||
if (!get_descriptor(plugin_key, row_data)) {
|
||||
// The catalog changed under the UI. Toggling is local, so just re-render from it.
|
||||
send_plugins();
|
||||
return;
|
||||
}
|
||||
@@ -741,12 +748,24 @@ void PluginsDialog::handle_plugin_menu_action(const std::string& plugin_key, con
|
||||
}
|
||||
}
|
||||
|
||||
void PluginsDialog::restore_z_order()
|
||||
{
|
||||
// Deferred so it runs on a clean stack after the modal has fully torn down; the
|
||||
// alive guard covers the dialog being destroyed while the CallAfter is queued.
|
||||
wxGetApp().CallAfter([this, alive = m_alive]() {
|
||||
if (alive->load(std::memory_order_acquire) && IsShown())
|
||||
Raise();
|
||||
});
|
||||
}
|
||||
|
||||
void PluginsDialog::install_plugin_from_file()
|
||||
{
|
||||
wxFileDialog dialog(this, _L("Select plugin package"), wxEmptyString, wxEmptyString, _L("Plugin files (*.py;*.whl)|*.py;*.whl"),
|
||||
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
|
||||
if (dialog.ShowModal() != wxID_OK)
|
||||
const int rc = dialog.ShowModal();
|
||||
restore_z_order();
|
||||
if (rc != wxID_OK)
|
||||
return;
|
||||
|
||||
if (!install_plugin_package(dialog.GetPath().ToUTF8().data())) {
|
||||
@@ -799,7 +818,9 @@ bool PluginsDialog::install_plugin_package(const std::string& package_path)
|
||||
plugin_name),
|
||||
kOverwritePluginTitle, wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING);
|
||||
dialog.SetOKCancelLabels(_L("Overwrite"), _L("Cancel"));
|
||||
if (dialog.ShowModal() != wxID_OK) {
|
||||
const int overwrite_rc = dialog.ShowModal();
|
||||
restore_z_order();
|
||||
if (overwrite_rc != wxID_OK) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Plugin package installation cancelled before overwrite. package=" << package_path
|
||||
<< " plugin=" << plugin_descriptor.name;
|
||||
return false;
|
||||
@@ -827,7 +848,7 @@ bool PluginsDialog::install_plugin_package(const std::string& package_path)
|
||||
BOOST_LOG_TRIVIAL(info) << "Plugin package installed successfully from " << package_path;
|
||||
const wxString installed_name = from_u8(plugin_descriptor.name.empty() ? package_file.filename().string() : plugin_descriptor.name);
|
||||
show_status(wxString::Format(_L("Installed \"%s\"."), installed_name), "success");
|
||||
refresh_plugin_catalog_async(_L("Refreshing"), _L("Refreshing plugins data"), kUseCurrentCloudCatalog);
|
||||
refresh_plugin_metadata_async(_L("Refreshing"), _L("Refreshing plugins data"), kUseCurrentCloudMeta);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -910,7 +931,7 @@ void PluginsDialog::restore_capability_config(const PluginCapabilityId& id)
|
||||
show_status(_L("Default configuration restored."), "success");
|
||||
}
|
||||
|
||||
void PluginsDialog::run_script_plugin(const std::string& plugin_key, const std::string& capability_name)
|
||||
void PluginsDialog::run_script_plugin_capability(const std::string& plugin_key, const std::string& capability_name)
|
||||
{
|
||||
PluginManager& manager = PluginManager::instance();
|
||||
|
||||
@@ -1046,16 +1067,17 @@ void PluginsDialog::delete_local_plugin(const PluginDescriptor& plugin)
|
||||
const wxString plugin_name = from_u8(plugin.name);
|
||||
const int rc = wxMessageBox(wxString::Format(_L("Delete plugin \"%s\"?\n\nThis permanently removes the plugin folder."), plugin_name),
|
||||
kDeletePluginTitle, wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this);
|
||||
restore_z_order();
|
||||
if (rc != wxYES)
|
||||
return;
|
||||
|
||||
auto state = std::make_shared<PluginOperationState>();
|
||||
run_with_dialog(
|
||||
[plugin_key = plugin.plugin_key, refresh_catalog = plugin.is_cloud_plugin(), state]() {
|
||||
[plugin_key = plugin.plugin_key, should_refresh = plugin.is_cloud_plugin(), state]() {
|
||||
std::string error;
|
||||
const bool succeeded = PluginManager::instance().delete_plugin(plugin_key, error);
|
||||
if (succeeded && refresh_catalog)
|
||||
refresh_plugin_catalog_blocking(kFetchCloudCatalog);
|
||||
if (succeeded && should_refresh)
|
||||
refresh_plugin_metadata_blocking(kFetchCloudMeta);
|
||||
store_plugin_operation_result(state, succeeded, std::move(error));
|
||||
},
|
||||
[this, state, plugin_name]() {
|
||||
@@ -1078,6 +1100,7 @@ void PluginsDialog::unsubscribe_cloud_plugin(const PluginDescriptor& plugin)
|
||||
wxString::Format(_L("Unsubscribe plugin \"%s\"?\n\nThis will stop tracking the plugin and delete any local plugin files."),
|
||||
plugin_name),
|
||||
kUnsubscribeTitle, wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this);
|
||||
restore_z_order();
|
||||
if (rc != wxYES)
|
||||
return;
|
||||
|
||||
@@ -1159,7 +1182,7 @@ void PluginsDialog::reinstall_cloud_plugin(const PluginDescriptor& plugin)
|
||||
return;
|
||||
}
|
||||
|
||||
manager.update_cloud_catalog(std::vector<PluginDescriptor>{as_cloud_only_descriptor(plugin)});
|
||||
manager.update_cloud_metadata(std::vector<PluginDescriptor>{as_cloud_only_descriptor(plugin)});
|
||||
}
|
||||
|
||||
if (!install_cloud_plugin(plugin_key, plugin.version, from_u8(plugin.name))) {
|
||||
@@ -1207,6 +1230,7 @@ void PluginsDialog::delete_mine_local_and_cloud_plugin(const std::string& plugin
|
||||
"deletes the plugin from the cloud. This action cannot be undone."),
|
||||
plugin_name),
|
||||
kDeletePluginTitle, wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this);
|
||||
restore_z_order();
|
||||
if (rc != wxYES)
|
||||
return;
|
||||
|
||||
@@ -1216,8 +1240,6 @@ void PluginsDialog::delete_mine_local_and_cloud_plugin(const std::string& plugin
|
||||
return;
|
||||
}
|
||||
|
||||
// delete_mine_local_and_cloud_plugin already updated the in-memory catalog (see
|
||||
// finalize_cloud_plugin_removal), so a UI refresh is sufficient here.
|
||||
send_plugins();
|
||||
show_status(wxString::Format(_L("Deleted \"%s\"."), plugin_name), "success");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user