mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-11 11:07:40 +00:00
prune stale plugin capability overrides (#14862)
* prune stale plugin capability overrides * fix: configure button still shows (n) modified configs after removing * fix: add slicing_pipeline_plugin to deep_diff
This commit is contained in:
@@ -3504,7 +3504,7 @@ inline t_config_option_keys deep_diff(const ConfigBase &config_this, const Confi
|
|||||||
if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
|
if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
|
||||||
{
|
{
|
||||||
//BBS: add bed_exclude_area
|
//BBS: add bed_exclude_area
|
||||||
if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "thumbnails" || opt_key == "wrapping_exclude_area") {
|
if (opt_key == "printable_area" || opt_key == "bed_exclude_area" || opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "thumbnails" || opt_key == "wrapping_exclude_area", "slicing_pipeline_plugin") {
|
||||||
// Scalar variable, or a vector variable, which is independent from number of extruders,
|
// Scalar variable, or a vector variable, which is independent from number of extruders,
|
||||||
// thus the vector is presented to the user as a single input.
|
// thus the vector is presented to the user as a single input.
|
||||||
diff.emplace_back(opt_key);
|
diff.emplace_back(opt_key);
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "GUI_ObjectList.hpp"
|
#include "GUI_ObjectList.hpp"
|
||||||
#include "slic3r/Utils/PresetUpdater.hpp"
|
#include "slic3r/Utils/PresetUpdater.hpp"
|
||||||
|
#include "slic3r/plugin/PluginConfig.hpp"
|
||||||
#include "Plater.hpp"
|
#include "Plater.hpp"
|
||||||
#include "MainFrame.hpp"
|
#include "MainFrame.hpp"
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
@@ -1795,9 +1796,19 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
|||||||
|
|
||||||
// Keep this preset's "plugins" manifest in sync when a plugin picker changes, so full_config() and
|
// Keep this preset's "plugins" manifest in sync when a plugin picker changes, so full_config() and
|
||||||
// save_to_json() always find resolved "name;uuid;capability" references and rebuild it nowhere else.
|
// save_to_json() always find resolved "name;uuid;capability" references and rebuild it nowhere else.
|
||||||
|
// Also drop any plugin_config_overrides entries for a capability the change just stopped
|
||||||
|
// referencing (e.g. a plugin removed from slicing_pipeline_plugin), so a saved preset never
|
||||||
|
// carries configuration for a capability it no longer names. The Configure button is a separate
|
||||||
|
// field holding its own cached copy of that value, so it needs to be told explicitly, or it
|
||||||
|
// keeps showing the stale count until something else happens to refresh it.
|
||||||
if (const ConfigOptionDef* opt_def = m_config->def()->get(opt_key);
|
if (const ConfigOptionDef* opt_def = m_config->def()->get(opt_key);
|
||||||
opt_def && opt_def->is_plugin_backed())
|
opt_def && opt_def->is_plugin_backed()) {
|
||||||
m_config->update_plugin_manifest();
|
m_config->update_plugin_manifest();
|
||||||
|
if (prune_stale_plugin_overrides(*m_config)) {
|
||||||
|
if (Field* overrides_field = get_field(PLUGIN_OVERRIDES_OPTION_KEY))
|
||||||
|
overrides_field->set_value(boost::any(m_config->opt_string(PLUGIN_OVERRIDES_OPTION_KEY)), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (opt_key == "gcode_flavor" && m_type == Preset::TYPE_PRINTER) {
|
if (opt_key == "gcode_flavor" && m_type == Preset::TYPE_PRINTER) {
|
||||||
if (auto printer_tab = dynamic_cast<TabPrinter*>(this))
|
if (auto printer_tab = dynamic_cast<TabPrinter*>(this))
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
#include <boost/nowide/fstream.hpp>
|
#include <boost/nowide/fstream.hpp>
|
||||||
|
|
||||||
|
#include <libslic3r/Config.hpp>
|
||||||
#include <libslic3r/PresetBundle.hpp>
|
#include <libslic3r/PresetBundle.hpp>
|
||||||
#include <libslic3r/PrintConfig.hpp>
|
#include <libslic3r/PrintConfig.hpp>
|
||||||
#include <slic3r/GUI/GUI.hpp>
|
#include <slic3r/GUI/GUI.hpp>
|
||||||
@@ -164,6 +165,20 @@ bool CapabilityConfigDocument::erase(const PluginCapabilityId& id)
|
|||||||
return erased;
|
return erased;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CapabilityConfigDocument::prune_unreferenced(const std::set<std::pair<PluginCapabilityType, std::string>>& referenced)
|
||||||
|
{
|
||||||
|
bool changed = false;
|
||||||
|
for (auto it = m_entries.begin(); it != m_entries.end();) {
|
||||||
|
if (referenced.count({it->first.type, it->first.name}) != 0) {
|
||||||
|
++it;
|
||||||
|
} else {
|
||||||
|
it = m_entries.erase(it);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
bool CapabilityConfigDocument::empty() const
|
bool CapabilityConfigDocument::empty() const
|
||||||
{
|
{
|
||||||
return m_entries.empty() && m_opaque_entries.empty();
|
return m_entries.empty() && m_opaque_entries.empty();
|
||||||
@@ -342,6 +357,50 @@ std::string serialize_plugin_overrides(const CapabilityConfigDocument& document)
|
|||||||
return document.empty() ? std::string() : document.serialize_entries().dump();
|
return document.empty() ? std::string() : document.serialize_entries().dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool prune_stale_plugin_overrides(DynamicConfig& config)
|
||||||
|
{
|
||||||
|
const auto* overrides_opt = dynamic_cast<const ConfigOptionString*>(config.option(PLUGIN_OVERRIDES_OPTION_KEY));
|
||||||
|
if (overrides_opt == nullptr || overrides_opt->value.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CapabilityConfigDocument overrides;
|
||||||
|
std::string error;
|
||||||
|
if (!parse_plugin_overrides(overrides_opt->value, overrides, error)) {
|
||||||
|
// Malformed text is not ours to fix up here: leave it untouched rather than risk
|
||||||
|
// discarding data the user might still be able to recover.
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "prune_stale_plugin_overrides: " << error;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capability names currently referenced by a plugin-backed option's value(s) — e.g.
|
||||||
|
// slicing_pipeline_plugin's ConfigOptionStrings entries name SlicingPipeline capabilities
|
||||||
|
// directly, the same raw values save_plugin_collection() resolves into the "plugins" manifest.
|
||||||
|
std::set<std::pair<PluginCapabilityType, std::string>> referenced;
|
||||||
|
const ConfigDef* def = config.def();
|
||||||
|
for (const std::string& opt_key : config.keys()) {
|
||||||
|
const ConfigOptionDef* opt_def = def != nullptr ? def->get(opt_key) : nullptr;
|
||||||
|
if (opt_def == nullptr || !opt_def->is_plugin_backed())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const ConfigOption* opt = config.option(opt_key);
|
||||||
|
const PluginCapabilityType type = plugin_capability_type_from_string(opt_def->plugin_type);
|
||||||
|
if (const auto* string_opt = dynamic_cast<const ConfigOptionString*>(opt)) {
|
||||||
|
if (!string_opt->value.empty())
|
||||||
|
referenced.emplace(type, string_opt->value);
|
||||||
|
} else if (const auto* vector_opt = dynamic_cast<const ConfigOptionVectorBase*>(opt)) {
|
||||||
|
for (const std::string& value : vector_opt->vserialize())
|
||||||
|
if (!value.empty())
|
||||||
|
referenced.emplace(type, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!overrides.prune_unreferenced(referenced))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
config.set_key_value(PLUGIN_OVERRIDES_OPTION_KEY, new ConfigOptionString(serialize_plugin_overrides(overrides)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
EffectiveCapabilityConfig PresetPluginConfigService::get_effective_config(const CapabilityConfigDocument& overrides,
|
EffectiveCapabilityConfig PresetPluginConfigService::get_effective_config(const CapabilityConfigDocument& overrides,
|
||||||
const PluginCapabilityId& id) const
|
const PluginCapabilityId& id) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,9 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#define PLUGIN_CONFIG_DIR "config.json"
|
#define PLUGIN_CONFIG_DIR "config.json"
|
||||||
@@ -16,6 +18,7 @@
|
|||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
class Preset;
|
class Preset;
|
||||||
|
class DynamicConfig;
|
||||||
struct CapabilityConfigEntry
|
struct CapabilityConfigEntry
|
||||||
{
|
{
|
||||||
PluginCapabilityId id;
|
PluginCapabilityId id;
|
||||||
@@ -35,6 +38,9 @@ public:
|
|||||||
bool contains(const PluginCapabilityId& id) const;
|
bool contains(const PluginCapabilityId& id) const;
|
||||||
bool upsert(CapabilityConfigEntry entry);
|
bool upsert(CapabilityConfigEntry entry);
|
||||||
bool erase(const PluginCapabilityId& id);
|
bool erase(const PluginCapabilityId& id);
|
||||||
|
// Drops every entry whose (type, name) is not in `referenced`, e.g. capabilities a preset's
|
||||||
|
// plugin-backed options no longer name. Returns true if anything was removed.
|
||||||
|
bool prune_unreferenced(const std::set<std::pair<PluginCapabilityType, std::string>>& referenced);
|
||||||
bool empty() const;
|
bool empty() const;
|
||||||
nlohmann::json serialize_entries() const;
|
nlohmann::json serialize_entries() const;
|
||||||
nlohmann::json root_json() const;
|
nlohmann::json root_json() const;
|
||||||
@@ -50,6 +56,14 @@ std::string plugin_overrides_of(const Preset& preset);
|
|||||||
bool parse_plugin_overrides(const std::string& raw, CapabilityConfigDocument& document, std::string& error);
|
bool parse_plugin_overrides(const std::string& raw, CapabilityConfigDocument& document, std::string& error);
|
||||||
std::string serialize_plugin_overrides(const CapabilityConfigDocument& document);
|
std::string serialize_plugin_overrides(const CapabilityConfigDocument& document);
|
||||||
|
|
||||||
|
// Drops plugin_config_overrides entries for capabilities no longer named by any plugin-backed
|
||||||
|
// option's current value in `config` (e.g. slicing_pipeline_plugin cleared or switched to a
|
||||||
|
// different capability), and writes the result back if anything changed. Called wherever a
|
||||||
|
// plugin-backed option's value changes, so a saved preset never carries configuration for a
|
||||||
|
// capability it no longer references. Returns true if `config` was modified, so a caller holding a
|
||||||
|
// GUI field over PLUGIN_OVERRIDES_OPTION_KEY knows it must refresh that field's displayed value.
|
||||||
|
bool prune_stale_plugin_overrides(DynamicConfig& config);
|
||||||
|
|
||||||
struct EffectiveCapabilityConfig
|
struct EffectiveCapabilityConfig
|
||||||
{
|
{
|
||||||
PluginCapabilityId id;
|
PluginCapabilityId id;
|
||||||
|
|||||||
Reference in New Issue
Block a user