mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-20 01:12:09 +00:00
Add actions speed dial
This commit is contained in:
@@ -4,10 +4,9 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "OrcaCloudServiceAgent.hpp"
|
||||
#include "PluginScriptRunner.hpp"
|
||||
#include "slic3r/plugin/PluginFsUtils.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
#include "slic3r/plugin/PythonInterpreter.hpp"
|
||||
#include "slic3r/plugin/pluginTypes/script/ScriptPluginCapability.hpp"
|
||||
|
||||
#include <libslic3r/Utils.hpp>
|
||||
|
||||
@@ -19,8 +18,6 @@
|
||||
#include <slic3r/plugin/PythonPluginInterface.hpp>
|
||||
#include <slic3r/plugin/PluginLoader.hpp>
|
||||
|
||||
#include <pybind11/embed.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
@@ -898,147 +895,22 @@ wxString PluginsDialog::plugin_display_name(const std::string& plugin_key) const
|
||||
|
||||
void PluginsDialog::run_script_plugin(const std::string& plugin_key, const std::string& capability_name)
|
||||
{
|
||||
if (plugin_key.empty() || capability_name.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Ignoring run_script_plugin with an empty plugin key or capability name";
|
||||
send_plugins();
|
||||
// Shared with the speed dial; validation, GIL/UI-thread execution, re-entrancy latch
|
||||
// and error bookkeeping all live in run_script_plugin_capability.
|
||||
const ScriptRunOutcome outcome = run_script_plugin_capability(plugin_key, capability_name);
|
||||
if (outcome.level == ScriptRunOutcome::Level::Busy)
|
||||
return;
|
||||
}
|
||||
|
||||
PluginManager& manager = PluginManager::instance();
|
||||
auto cap = manager.get_loader().get_plugin_capability_by_name(
|
||||
plugin_key, Slic3r::PluginCapabilityType::Script, capability_name);
|
||||
if (!cap) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Ignoring stale run request for missing script capability. plugin_key=" << plugin_key
|
||||
<< " capability_name=" << capability_name;
|
||||
send_plugins();
|
||||
return;
|
||||
}
|
||||
if (!cap->enabled) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Ignoring stale run request for disabled script capability. plugin_key=" << plugin_key
|
||||
<< " capability_name=" << capability_name;
|
||||
send_plugins();
|
||||
return;
|
||||
}
|
||||
|
||||
// A plugin's modal orca.host.ui dialog or the result message box pumps a nested event
|
||||
// loop; the WebView could re-dispatch this command mid-run. Refuse the overlapping run.
|
||||
if (m_script_running) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Ignoring run_script_plugin; a plugin is already running. plugin_key=" << plugin_key;
|
||||
return;
|
||||
}
|
||||
m_script_running = true;
|
||||
ScopeGuard running_guard([this]() { m_script_running = false; });
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Run script plugin requested from Plugins dialog. plugin_key=" << plugin_key
|
||||
<< " capability_name=" << capability_name;
|
||||
|
||||
auto complete_with_error = [this, &manager, &plugin_key](const std::string& plugin_error, const wxString& status_message) {
|
||||
const std::string normalized_error = plugin_error.empty() ? "Script plugin failed." : plugin_error;
|
||||
if (!manager.get_catalog().set_plugin_error(plugin_key, normalized_error))
|
||||
BOOST_LOG_TRIVIAL(warning) << "Failed to record plugin error. plugin_key=" << plugin_key;
|
||||
|
||||
if (!manager.get_loader().unload_plugin(plugin_key))
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to unload plugin after script error. plugin_key=" << plugin_key;
|
||||
|
||||
send_plugins();
|
||||
|
||||
// The row now shows an "Error" status and the Diagnostics tab holds the full text, so surface
|
||||
// the outcome in the footer status bar instead of a modal box (prefer the friendlier override).
|
||||
const wxString message = status_message.empty() ? from_u8(normalized_error) : status_message;
|
||||
show_status(message, "error");
|
||||
};
|
||||
|
||||
PluginDescriptor descriptor;
|
||||
if (!get_descriptor(plugin_key, descriptor)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Cannot run script plugin because manifest was not found. plugin_key=" << plugin_key;
|
||||
complete_with_error("Plugin manifest was not found.", _L("Plugin manifest was not found."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (descriptor.has_error()) {
|
||||
complete_with_error(descriptor.normalized_error(), wxString());
|
||||
return;
|
||||
}
|
||||
|
||||
// Should not reach here, handle for extra safety
|
||||
if (!descriptor.is_metadata_valid()) {
|
||||
std::string plugin_type_str = plugin_capability_type_to_string(descriptor.primary_capability_type());
|
||||
std::string metadata_valid = descriptor.is_metadata_valid() ? "true" : "false";
|
||||
const std::string plugin_error = "Cannot run plugin because its metadata is invalid:\n\tplugin type: " + plugin_type_str +
|
||||
"\n\tmetadata_valid: " + metadata_valid;
|
||||
BOOST_LOG_TRIVIAL(error) << "Cannot run plugin because its metadata is invalid. plugin_key=" << plugin_key
|
||||
<< " is_metadata_valid=" << descriptor.is_metadata_valid()
|
||||
<< " type=" << plugin_capability_type_to_string(descriptor.primary_capability_type());
|
||||
complete_with_error(plugin_error, _L("Only plugins with valid metadata can be run from this dialog."));
|
||||
return;
|
||||
}
|
||||
|
||||
// Should not reach here as non-loaded plugins have disabled run buttons, handle for extra safety
|
||||
if (!manager.get_loader().is_plugin_loaded(plugin_key)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Cannot run script plugin because it is not loaded. plugin_key=" << plugin_key;
|
||||
complete_with_error("Load the script plugin before running it: Cannot run script plugin because it is not loaded.",
|
||||
_L("Load the script plugin before running it."));
|
||||
return;
|
||||
}
|
||||
|
||||
auto plugin = std::dynamic_pointer_cast<Slic3r::ScriptPluginCapability>(cap->instance);
|
||||
if (!plugin) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Loaded plugin does not implement ScriptPluginCapability. plugin_key=" << plugin_key;
|
||||
complete_with_error("The selected plugin is not a runnable script plugin: Loaded plugin does not implement ScriptPluginCapability.",
|
||||
_L("The selected plugin is not a runnable script plugin."));
|
||||
return;
|
||||
}
|
||||
|
||||
std::string error;
|
||||
ExecutionResult result;
|
||||
|
||||
// Script plugins run on the main/UI thread (not a worker). They hold live, non-owning
|
||||
// ModelObject*/ModelVolume*/ModelInstance* aliases into host data and can mint ObjectIDs,
|
||||
// which libslic3r requires on the main thread (ObjectID.hpp's non-atomic s_last_id). Running
|
||||
// here makes those reads/instantiations legal and means nothing mutates the model underneath
|
||||
// a run. The trade-off is that a slow execute() freezes the UI: the contract (see
|
||||
// plugin_development.md) is to keep execute() quick and offload heavy work to the plugin's own
|
||||
// threading.Thread. orca.host.ui calls already no-op their main-thread marshaling here.
|
||||
{
|
||||
wxBusyCursor busy;
|
||||
try {
|
||||
PythonGILState gil;
|
||||
result = plugin->execute();
|
||||
} catch (const std::exception& ex) {
|
||||
error = ex.what();
|
||||
BOOST_LOG_TRIVIAL(error) << "Script plugin execution threw exception. plugin_key=" << plugin_key << " error=" << error;
|
||||
} catch (...) {
|
||||
error = "Unknown error";
|
||||
BOOST_LOG_TRIVIAL(error) << "Script plugin execution threw unknown exception. plugin_key=" << plugin_key;
|
||||
}
|
||||
}
|
||||
|
||||
if (!error.empty()) {
|
||||
plugin.reset();
|
||||
cap.reset();
|
||||
complete_with_error(error, wxString());
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Script plugin execution completed. plugin_key=" << plugin_key
|
||||
<< " status=" << static_cast<int>(result.status) << " message=" << result.message << " data=" << result.data;
|
||||
|
||||
const bool failed = result.status == PluginResult::RecoverableError || result.status == PluginResult::FatalError;
|
||||
if (failed) {
|
||||
plugin.reset();
|
||||
cap.reset();
|
||||
// complete_with_error normalizes an empty message to "Script plugin failed." and reports via the status bar.
|
||||
complete_with_error(result.message, wxString());
|
||||
return;
|
||||
}
|
||||
|
||||
manager.clear_plugin_error(plugin_key);
|
||||
send_plugins();
|
||||
|
||||
const bool skipped = result.status == PluginResult::Skipped;
|
||||
const wxString fallback = skipped ? _L("Script plugin skipped.") : _L("Script plugin finished.");
|
||||
const wxString message = result.message.empty() ? fallback : from_u8(result.message);
|
||||
show_status(message, skipped ? "info" : "success");
|
||||
// The row shows any "Error" status and the Diagnostics tab holds the full text, so surface
|
||||
// the outcome in the footer status bar instead of a modal box (prefer the friendlier override).
|
||||
if (outcome.message.empty())
|
||||
return;
|
||||
const char* level = outcome.level == ScriptRunOutcome::Level::Error ? "error" :
|
||||
outcome.level == ScriptRunOutcome::Level::Success ? "success" :
|
||||
"info";
|
||||
show_status(outcome.message, level);
|
||||
}
|
||||
|
||||
void PluginsDialog::update_plugin(const std::string& plugin_key)
|
||||
|
||||
Reference in New Issue
Block a user