OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::PluginConfig Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/plugin/PluginConfig.hpp>

Collaboration diagram for Slic3r::PluginConfig:

Public Member Functions

void load ()
bool save ()
void save_config (const CapabilityConfigEntry &config)
bool store_capability_config (const PluginCapabilityId &id, const nlohmann::json &config)
bool erase_capability_config (const PluginCapabilityId &id)
std::optional< CapabilityConfigEntry > get_config (const PluginCapabilityId &id) const
bool has_config (const PluginCapabilityId &id) const
bool dirty () const

Static Public Member Functions

static const std::string plugin_config_file ()
static std::string capability_type_label (PluginCapabilityType type)
static nlohmann::json capabilities_payload (const std::vector< PluginCapabilityId > &caps)
static nlohmann::json get_config_response (const PluginCapabilityId &id)
static nlohmann::json save_config_response (const PluginCapabilityId &id, const nlohmann::json &config)
static nlohmann::json restore_config_response (const PluginCapabilityId &id)

Private Attributes

std::mutex m_mutex
CapabilityConfigDocument m_document
bool m_dirty = false

Detailed Description

Member Function Documentation

◆ capabilities_payload()

nlohmann::json Slic3r::PluginConfig::capabilities_payload ( const std::vector< PluginCapabilityId > & caps)
static
539{
540 nlohmann::json payload = nlohmann::json::array();
541 for (const PluginCapabilityId& id : caps) {
542 // A capability unloaded since the list was built has nothing to configure.
543 const auto capability = PluginManager::instance().get_plugin_capability(id, false);
544 if (!capability)
545 continue;
546
547 nlohmann::json entry;
548 entry["plugin_key"] = id.plugin_key;
549 entry["name"] = id.name;
550 entry["type"] = capability_type_label(id.type);
551 entry["type_key"] = plugin_capability_type_to_string(id.type);
552 entry["has_config_ui"] = capability->config_ui_available();
553 payload.push_back(std::move(entry));
554 }
555 return payload;
556}
static std::string capability_type_label(PluginCapabilityType type)
Definition PluginConfig.cpp:522
static PluginManager & instance()
Definition PluginManager.cpp:74
std::shared_ptr< PluginCapabilityInterface > get_plugin_capability(const PluginCapabilityId &id, bool only_enabled=true) const
Definition PluginManager.cpp:616
std::string plugin_capability_type_to_string(PluginCapabilityType type)
Definition PythonPluginInterface.hpp:40

References capability_type_label(), Slic3r::PluginManager::get_plugin_capability(), Slic3r::PluginManager::instance(), and Slic3r::plugin_capability_type_to_string().

Referenced by Slic3r::GUI::anonymous_namespace{PluginsDialog.cpp}::build_plugin_payload_item(), and Slic3r::GUI::PluginsConfigDialog::send_capabilities().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ capability_type_label()

std::string Slic3r::PluginConfig::capability_type_label ( PluginCapabilityType type)
static
523{
524 switch (type) {
525 case PluginCapabilityType::PrinterConnection: return _u8L("Printer connection");
526 case PluginCapabilityType::Pages: return _u8L("Pages");
527 case PluginCapabilityType::Analysis: return _u8L("Analysis");
528 case PluginCapabilityType::Importer: return _u8L("Importer");
529 case PluginCapabilityType::Exporter: return _u8L("Exporter");
530 case PluginCapabilityType::Visualization: return _u8L("Visualization");
531 case PluginCapabilityType::Script: return _u8L("Script");
532 case PluginCapabilityType::SlicingPipeline: return _u8L("Slicing Pipeline");
533 case PluginCapabilityType::ResourceTexture: return _u8L("Resource Texture");
534 default: return _u8L("Unknown");
535 }
536}
@ Importer
Definition PythonPluginInterface.hpp:17
@ SlicingPipeline
Definition PythonPluginInterface.hpp:17
@ Pages
Definition PythonPluginInterface.hpp:17
@ Analysis
Definition PythonPluginInterface.hpp:17
@ ResourceTexture
Definition PythonPluginInterface.hpp:17
@ Visualization
Definition PythonPluginInterface.hpp:17
@ Exporter
Definition PythonPluginInterface.hpp:17
@ PrinterConnection
Definition PythonPluginInterface.hpp:17
@ Script
Definition PythonPluginInterface.hpp:17
#define _u8L(s)
Definition I18N.hpp:11

References _u8L, Slic3r::Analysis, Slic3r::Exporter, Slic3r::Importer, Slic3r::Pages, Slic3r::PrinterConnection, Slic3r::ResourceTexture, Slic3r::Script, Slic3r::SlicingPipeline, and Slic3r::Visualization.

Referenced by Slic3r::GUI::anonymous_namespace{PluginsDialog.cpp}::build_plugin_dialog_item(), Slic3r::GUI::anonymous_namespace{PluginsDialog.cpp}::build_plugin_payload_item(), capabilities_payload(), Slic3r::PluginManager::check_registry_locked(), and Slic3r::plugin_loader::load().

Here is the caller graph for this function:

◆ dirty()

bool Slic3r::PluginConfig::dirty ( ) const
326{
327 std::lock_guard<std::mutex> lock(m_mutex);
328 return m_dirty;
329}
std::mutex m_mutex
Definition PluginConfig.hpp:121
bool m_dirty
Definition PluginConfig.hpp:123
@ lock
Definition GLGizmoEmboss.cpp:209

References m_dirty, and m_mutex.

◆ erase_capability_config()

bool Slic3r::PluginConfig::erase_capability_config ( const PluginCapabilityId & id)
299{
300 if (id.empty())
301 return false;
302
303 {
304 std::lock_guard<std::mutex> lock(m_mutex);
305 if (!m_document.erase(id))
306 return true;
307 m_dirty = true;
308 }
309
310 return save();
311}
bool save()
Definition PluginConfig.cpp:250
CapabilityConfigDocument m_document
Definition PluginConfig.hpp:122
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:273

References Slic3r::empty(), m_dirty, m_document, m_mutex, and save().

Here is the call graph for this function:

◆ get_config()

std::optional< CapabilityConfigEntry > Slic3r::PluginConfig::get_config ( const PluginCapabilityId & id) const
314{
315 std::lock_guard<std::mutex> lock(m_mutex);
316 return m_document.find(id);
317}

References m_document, and m_mutex.

Referenced by get_config_response(), Slic3r::PresetPluginConfigService::get_effective_config(), restore_config_response(), and save_config_response().

Here is the caller graph for this function:

◆ get_config_response()

nlohmann::json Slic3r::PluginConfig::get_config_response ( const PluginCapabilityId & id)
static
561{
562 nlohmann::json response;
563 response["command"] = "capability_config";
564 response["plugin_key"] = id.plugin_key;
565 response["capability_name"] = id.name;
566 response["capability_type"] = plugin_capability_type_to_string(id.type);
567 response["config"] = nlohmann::json::object();
568 response["custom_html"] = "";
569 response["error"] = "";
570
571 // Scoped to the full identity, so a stale request from a page that has not caught up with a
572 // refresh misses rather than reading a different plugin's config.
573 const auto cap = PluginManager::instance().get_plugin_capability(id, false);
574 if (!cap) {
575 BOOST_LOG_TRIVIAL(warning) << "Ignoring config request for a capability that is no longer loaded. plugin_key="
576 << id.plugin_key << " capability_name=" << id.name;
577 response["error"] = GUI::into_u8(_L("This capability is no longer available."));
578 return response;
579 }
580
581 if (const auto stored = PluginManager::instance().get_config().get_config(id))
582 response["config"] = stored->config;
583
584 if (cap->config_ui_available()) {
585 // A raising or empty get_config_ui() costs the capability only its custom UI: report the
586 // failure and let the page fall back to the default JSON editor over the same stored config.
587 std::string html;
588 std::string error;
589 {
590 wxBusyCursor busy;
591 try {
592 PythonGILState gil;
593 html = cap->get_config_ui();
594 } catch (const std::exception& ex) {
595 error = ex.what();
596 } catch (...) {
597 error = _u8L("Unknown error");
598 }
599 }
600
601 if (!error.empty()) {
602 BOOST_LOG_TRIVIAL(error) << "Plugin capability get_config_ui() failed. plugin_key=" << id.plugin_key
603 << " capability_name=" << id.name << " error=" << error;
604 response["error"] = GUI::into_u8(GUI::format_wxstr(_L("The plugin's configuration UI failed to load (%1%). Showing the default editor."),
605 GUI::from_u8(error)));
606 } else if (html.empty()) {
607 BOOST_LOG_TRIVIAL(warning) << "Plugin capability reports a config UI but returned no HTML. plugin_key=" << id.plugin_key
608 << " capability_name=" << id.name;
609 response["error"] = GUI::into_u8(_L("The plugin's configuration UI was empty. Showing the default editor."));
610 } else {
611 response["custom_html"] = html;
612 }
613 }
614
615 return response;
616}
#define _L(s)
Definition OBJ.cpp:34
std::optional< CapabilityConfigEntry > get_config(const PluginCapabilityId &id) const
Definition PluginConfig.cpp:313
wxString format_wxstr(const char *fmt, TArgs &&... args)
Definition format.hpp:22
std::string into_u8(const wxString &str)
Definition GUI.cpp:549
wxString from_u8(const std::string &str)
Definition GUI.cpp:544

References _L, _u8L, Slic3r::GUI::format_wxstr(), Slic3r::GUI::from_u8(), get_config(), Slic3r::PluginManager::get_plugin_capability(), Slic3r::PluginManager::instance(), Slic3r::GUI::into_u8(), and Slic3r::plugin_capability_type_to_string().

Referenced by Slic3r::GUI::PluginsDialog::send_capability_config().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ has_config()

bool Slic3r::PluginConfig::has_config ( const PluginCapabilityId & id) const
320{
321 std::lock_guard<std::mutex> lock(m_mutex);
322 return m_document.contains(id);
323}

References m_document, and m_mutex.

◆ load()

void Slic3r::PluginConfig::load ( )
220{
221 const std::string path = plugin_config_file();
222
223 std::lock_guard<std::mutex> lock(m_mutex);
224 m_document = CapabilityConfigDocument();
225 m_dirty = false;
226
227 boost::system::error_code ec;
228 if (!boost::filesystem::exists(path, ec))
229 return;
230
231 nlohmann::json root;
232 try {
233 boost::nowide::ifstream ifs(path.c_str());
234 ifs >> root;
235 } catch (const std::exception& err) {
236 BOOST_LOG_TRIVIAL(error) << "PluginConfig: cannot read " << path << ": " << err.what() << "; starting with an empty config";
237 return;
238 }
239
240 const auto entries = root.find(CapabilityConfigDocument::KeyEntries);
241 if (entries == root.end() || !entries->is_array()) {
242 BOOST_LOG_TRIVIAL(warning) << "PluginConfig: " << path << " has no \"" << CapabilityConfigDocument::KeyEntries
243 << "\" array; starting with an empty config";
244 return;
245 }
246
248}
static constexpr const char * KeyEntries
Definition PluginConfig.hpp:31
static CapabilityConfigDocument from_root_json(const nlohmann::json &root)
Definition PluginConfig.cpp:125
static const std::string plugin_config_file()
Definition PluginConfig.hpp:98

References Slic3r::CapabilityConfigDocument::from_root_json(), Slic3r::CapabilityConfigDocument::KeyEntries, m_dirty, m_document, m_mutex, and plugin_config_file().

Here is the call graph for this function:

◆ plugin_config_file()

const std::string Slic3r::PluginConfig::plugin_config_file ( )
inlinestatic
98{ return (boost::filesystem::path(get_orca_plugins_dir()) / PLUGIN_CONFIG_DIR).string(); }
#define PLUGIN_CONFIG_DIR
Definition PluginConfig.hpp:16
std::string get_orca_plugins_dir()
Definition PluginFsUtils.cpp:41

References Slic3r::get_orca_plugins_dir(), and PLUGIN_CONFIG_DIR.

Referenced by load(), and save().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ restore_config_response()

nlohmann::json Slic3r::PluginConfig::restore_config_response ( const PluginCapabilityId & id)
static
666{
667 nlohmann::json response;
668 response["command"] = "capability_config_saved";
669 response["plugin_key"] = id.plugin_key;
670 response["capability_name"] = id.name;
671 response["capability_type"] = plugin_capability_type_to_string(id.type);
672 response["ok"] = false;
673 response["error"] = "";
674
675 const auto cap = PluginManager::instance().get_plugin_capability(id, false);
676 if (!cap) {
677 BOOST_LOG_TRIVIAL(warning) << "Refusing to restore config for a capability that is no longer loaded. plugin_key="
678 << id.plugin_key << " capability_name=" << id.name;
679 response["error"] = GUI::into_u8(_L("This capability is no longer available."));
680 return response;
681 }
682
683 nlohmann::json defaults;
684 std::string error;
685 {
686 wxBusyCursor busy;
687 try {
688 PythonGILState gil;
689 defaults = cap->get_default_config();
690 } catch (const std::exception& ex) {
691 error = ex.what();
692 } catch (...) {
693 error = _u8L("Unknown error");
694 }
695 }
696
697 // A raising hook leaves the stored config as it was: better to restore nothing than to wipe the
698 // user's settings on the strength of a broken plugin.
699 if (!error.empty()) {
700 BOOST_LOG_TRIVIAL(error) << "Plugin capability get_default_config() failed. plugin_key=" << id.plugin_key
701 << " capability_name=" << id.name << " error=" << error;
702 response["error"] = GUI::into_u8(GUI::format_wxstr(_L("The plugin could not supply a default configuration (%1%). "
703 "Nothing was changed."),
704 GUI::from_u8(error)));
705 return response;
706 }
707
709 BOOST_LOG_TRIVIAL(error) << "Failed to write the plugin config file while restoring defaults. plugin_key="
710 << id.plugin_key << " capability_name=" << id.name;
711 response["error"] = GUI::into_u8(_L("The configuration could not be written to disk. Nothing was changed."));
712 return response;
713 }
714
715 BOOST_LOG_TRIVIAL(info) << "Restored default plugin capability config. plugin_key=" << id.plugin_key
716 << " capability_name=" << id.name;
717
718 response["ok"] = true;
719 if (const auto stored = PluginManager::instance().get_config().get_config(id))
720 response["config"] = stored->config;
721 return response;
722}
bool store_capability_config(const PluginCapabilityId &id, const nlohmann::json &config)
Definition PluginConfig.cpp:278

References _L, _u8L, Slic3r::GUI::format_wxstr(), Slic3r::GUI::from_u8(), get_config(), Slic3r::PluginManager::get_plugin_capability(), Slic3r::PluginManager::instance(), Slic3r::GUI::into_u8(), Slic3r::plugin_capability_type_to_string(), and store_capability_config().

Referenced by Slic3r::GUI::PluginsDialog::restore_capability_config().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ save()

bool Slic3r::PluginConfig::save ( )
251{
252 const std::string path = plugin_config_file();
253
254 std::lock_guard<std::mutex> lock(m_mutex);
255 if (!m_dirty)
256 return true;
257
258 const nlohmann::json root = m_document.root_json();
259
260 boost::system::error_code ec;
261 boost::filesystem::create_directories(boost::filesystem::path(path).parent_path(), ec);
262 if (ec) {
263 BOOST_LOG_TRIVIAL(error) << "PluginConfig: cannot create the plugin directory: " << ec.message();
264 return false;
265 }
266
267 // Written beside the target and moved into place, so a crash mid-write cannot truncate an
268 // existing config.
269 if (const std::error_code ec = write_file_atomically(path, root.dump(1, '\t') + "\n")) {
270 BOOST_LOG_TRIVIAL(error) << "PluginConfig: failed to write " << path << ": " << ec.message() << "; keeping the existing config";
271 return false;
272 }
273
274 m_dirty = false;
275 return true;
276}
std::error_code write_file_atomically(const std::string &path, std::initializer_list< std::string_view > chunks, bool binary)
Definition utils.cpp:796

References m_dirty, m_document, m_mutex, plugin_config_file(), and Slic3r::write_file_atomically().

Referenced by erase_capability_config(), and store_capability_config().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ save_config()

void Slic3r::PluginConfig::save_config ( const CapabilityConfigEntry & config)
288{
289 if (config.id.empty()) {
290 BOOST_LOG_TRIVIAL(error) << "PluginConfig: refusing to store a config without a complete capability identity";
291 return;
292 }
293
294 std::lock_guard<std::mutex> lock(m_mutex);
295 m_dirty = m_document.upsert(config) || m_dirty;
296}

References Slic3r::PluginCapabilityId::empty(), Slic3r::CapabilityConfigEntry::id, m_dirty, m_document, and m_mutex.

Referenced by store_capability_config().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ save_config_response()

nlohmann::json Slic3r::PluginConfig::save_config_response ( const PluginCapabilityId & id,
const nlohmann::json & config )
static
619{
620 nlohmann::json response;
621 response["command"] = "capability_config_saved";
622 response["plugin_key"] = id.plugin_key;
623 response["capability_name"] = id.name;
624 response["capability_type"] = plugin_capability_type_to_string(id.type);
625 response["ok"] = false;
626 response["error"] = "";
627
628 const auto cap = PluginManager::instance().get_plugin_capability(id, false);
629 if (!cap) {
630 BOOST_LOG_TRIVIAL(warning) << "Refusing to save config for a capability that is no longer loaded. plugin_key="
631 << id.plugin_key << " capability_name=" << id.name;
632 response["error"] = GUI::into_u8(_L("This capability is no longer available. Your changes were not saved."));
633 return response;
634 }
635
636 nlohmann::json parsed = config;
637 if (config.is_string()) {
638 // The page validates as the user types, but it is not the authority: re-parse so a malformed
639 // document is rejected before it can reach config.json.
640 parsed = nlohmann::json::parse(config.get<std::string>(), nullptr, /* allow_exceptions */ false);
641 if (parsed.is_discarded()) {
642 response["error"] = GUI::into_u8(_L("The configuration is not valid JSON. Your changes were not saved."));
643 return response;
644 }
645 }
646
648 BOOST_LOG_TRIVIAL(error) << "Failed to write the plugin config file. plugin_key=" << id.plugin_key
649 << " capability_name=" << id.name;
650 response["error"] = GUI::into_u8(_L("The configuration could not be written to disk. Your changes were not saved."));
651 return response;
652 }
653
654 BOOST_LOG_TRIVIAL(info) << "Saved plugin capability config. plugin_key=" << id.plugin_key << " capability_name=" << id.name;
655
656 // Echo back what was persisted, not what the user typed, so the editor reloads from the store.
657 response["ok"] = true;
658 if (const auto stored = PluginManager::instance().get_config().get_config(id))
659 response["config"] = stored->config;
660 return response;
661}

References _L, get_config(), Slic3r::PluginManager::get_plugin_capability(), Slic3r::PluginManager::instance(), Slic3r::GUI::into_u8(), Slic3r::plugin_capability_type_to_string(), and store_capability_config().

Referenced by Slic3r::GUI::PluginsDialog::save_capability_config().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ store_capability_config()

bool Slic3r::PluginConfig::store_capability_config ( const PluginCapabilityId & id,
const nlohmann::json & config )
279{
280 if (id.empty())
281 return false;
282
283 save_config({id, running_plugin_version(id.plugin_key), config});
284 return save();
285}
void save_config(const CapabilityConfigEntry &config)
Definition PluginConfig.cpp:287
std::string running_plugin_version(const std::string &plugin_key)
Definition PluginConfig.cpp:78

References Slic3r::empty(), save(), and save_config().

Referenced by Slic3r::capability_save_config(), restore_config_response(), and save_config_response().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ m_dirty

bool Slic3r::PluginConfig::m_dirty = false
private

◆ m_document

CapabilityConfigDocument Slic3r::PluginConfig::m_document
private

◆ m_mutex

std::mutex Slic3r::PluginConfig::m_mutex
mutableprivate

The documentation for this class was generated from the following files: