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

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/PresetBundle.hpp>

Collaboration diagram for Slic3r::PresetBundle:

Classes

struct  PresetPreferences
struct  LegacyUserFilamentPresetMigration
struct  Selection
class  SelectionExportBlocker
struct  ObsoletePresets
struct  VendorSource
struct  EntryParse
struct  VendorParse
struct  VendorRead
struct  VendorInstall
struct  PresetInstall

Public Types

enum  LoadConfigBundleAttribute {
  SaveImported , ResetUserProfile , LoadSystem , LoadVendorOnly ,
  LoadFilamentOnly
}
using LoadConfigBundleAttributes = enum_bitmask<LoadConfigBundleAttribute>

Public Member Functions

bool load_vendor_cache (const std::string &cache_path, const std::string &expected_vendor_name, const Semver &expected_vendor_version, const PresetBundle *base_bundle=nullptr)
void set_generate_vendor_caches (bool enable)
 PresetBundle ()
 PresetBundle (const PresetBundle &rhs)
PresetBundle & operator= (const PresetBundle &rhs)
void reset (bool delete_files)
void setup_directories ()
void copy_files (const std::string &from)
PresetsConfigSubstitutions load_presets (AppConfig &config, ForwardCompatibilitySubstitutionRule rule, const PresetPreferences &preferred_selection=PresetPreferences(), std::string *errors=nullptr, bool read_only=false)
bool resolve_preset_config (DynamicPrintConfig &config, Preset::Type type, const std::string &source_file, ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error, bool allow_source_manifest=true)
bool resolve_preset_config_type (DynamicPrintConfig &config, Preset::Type &type, const std::string &source_file, ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error, bool allow_source_manifest=true)
bool resolve_system_preset (DynamicPrintConfig &config, Preset::Type type, const std::string &name, ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error)
void load_selections (AppConfig &config, const PresetPreferences &preferred_selection=PresetPreferences())
PresetsConfigSubstitutions load_user_presets (std::string user, ForwardCompatibilitySubstitutionRule rule, bool read_only=false)
PresetsConfigSubstitutions load_user_presets (AppConfig &config, std::map< std::string, std::map< std::string, std::string > > &my_presets, ForwardCompatibilitySubstitutionRule rule)
bool reload_local_bundle (const std::string &preset_folder, const std::string &bundle_id, std::string *error=nullptr)
std::vector< std::string > list_local_bundle_ids (const std::string &preset_folder)
PresetsConfigSubstitutions update_subscribed_presets (AppConfig &config, const std::map< std::string, std::map< std::string, std::string > > &bundle_presets, const BundleMetadata &remote_metadata, ForwardCompatibilitySubstitutionRule rule)
PresetsConfigSubstitutions import_presets (std::vector< std::string > &files, std::function< int(std::string const &)> override_confirm, ForwardCompatibilitySubstitutionRule rule, AppConfig &config)
bool import_json_presets (PresetsConfigSubstitutions &substitutions, std::string &file, std::function< int(std::string const &)> override_confirm, ForwardCompatibilitySubstitutionRule rule, int &overwrite, std::vector< std::string > &result, const std::string &bundle_dir="", const std::map< std::string, std::string > &bed_asset_paths={}, bool *bed_paths_loaded=nullptr)
void save_user_presets (AppConfig &config, std::map< std::string, std::string > &need_to_delete_list)
void check_and_fix_user_presets_syncinfo (const std::string &user_id)
void remove_users_preset (AppConfig &config, std::map< std::string, std::map< std::string, std::string > > *my_presets=nullptr)
void update_user_presets_directory (const std::string preset_folder)
void remove_user_presets_directory (const std::string preset_folder)
void update_system_preset_setting_ids (std::map< std::string, std::map< std::string, std::string > > &system_presets)
bool apply_vendor_config (const std::map< std::string, std::map< std::string, std::set< std::string > > > &new_vendors, const std::map< std::string, std::string > &new_filaments, AppConfig *app_config, bool overwrite=true, const std::string &preferred_printer_model=std::string(), const std::string &preferred_printer_variant=std::string(), const std::string &preferred_filament=std::string())
int validate_presets (const std::string &file_name, DynamicPrintConfig &config, std::set< std::string > &different_gcodes)
Preset * get_preset_differed_for_save (Preset &preset)
int get_differed_values_to_update (Preset &preset, std::map< std::string, std::string > &key_values)
Semver get_vendor_profile_version (std::string vendor_name)
std::optional< FilamentBaseInfo > get_filament_by_filament_id (const std::string &filament_id, const std::string &printer_name=std::string()) const
VendorType get_current_vendor_type ()
bool is_bbl_vendor ()
bool use_bbl_network ()
bool use_bbl_device_tab ()
bool backup_user_folder () const
bool backup_user_folder_to_zip (const std::string &zip_path) const
std::vector< LegacyUserFilamentPreset > legacy_user_filament_presets ()
LegacyUserFilamentPresetMigration migrate_legacy_user_filament_presets (const std::vector< LegacyUserFilamentPreset > &legacy_presets)
PresetsConfigSubstitutions load_project_embedded_presets (std::vector< Preset * > project_presets, ForwardCompatibilitySubstitutionRule substitution_rule)
std::vector< Preset * > get_current_project_embedded_presets ()
void reset_project_embedded_presets ()
std::optional< Selection > selection () const
void restore_selection (const Selection &selection)
std::string get_texture_for_printer_model (std::string model_name)
std::string get_stl_model_for_printer_model (std::string model_name)
std::string get_hotend_model_for_printer_model (std::string model_name)
void export_selections (AppConfig &config)
void set_num_filaments (unsigned int n, std::string new_col="")
void update_num_filaments (unsigned int to_del_flament_id)
void get_ams_cobox_infos (AMSComboInfo &combox_info)
unsigned int sync_ams_list (std::vector< std::pair< DynamicPrintConfig *, std::string > > &unknowns, bool use_map, std::map< int, AMSMapInfo > &maps, bool enable_append, MergeFilamentInfo &merge_info, bool color_only=false)
bool is_the_only_edited_filament (unsigned int filament_index)
void reset_default_nozzle_volume_type ()
std::vector< int > get_used_tpu_filaments (const std::vector< int > &used_filaments)
void update_selections (AppConfig &config)
void set_calibrate_printer (std::string name)
void set_is_validation_mode (bool mode)
void set_vendor_to_validate (std::string vendor)
std::vector< std::vector< DynamicPrintConfig > > get_extruder_filament_info () const
std::set< std::string > get_printer_names_by_printer_type_and_nozzle (const std::string &printer_type, std::string nozzle_diameter_str, bool system_only=true)
std::vector< Preset * > get_filament_presets_for_machine (const std::string &printer_type, const std::string &nozzle_diameter_str, bool include_user_presets)
bool check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray (const std::string &printer_type, std::string &nozzle_diameter_str, std::string &setting_id, std::string &tag_uid, std::string &nozzle_temp_min, std::string &nozzle_temp_max, std::string &preset_setting_id, int extruder_id, NozzleVolumeType nozzle_volume_type)
Preset * get_similar_printer_preset (std::string printer_model, std::string printer_variant)
PresetCollection & materials (PrinterTechnology pt)
const PresetCollection & materials (PrinterTechnology pt) const
bool has_defauls_only () const
DynamicPrintConfig full_config (bool apply_extruder=true, std::optional< std::vector< int > >filament_maps=std::nullopt, std::optional< std::vector< int > > filament_volume_maps=std::nullopt) const
DynamicPrintConfig full_config_secure (std::optional< std::vector< int > >filament_maps=std::nullopt) const
std::vector< int > get_default_nozzle_volume_types_for_filaments (std::vector< int > &f_maps)
std::vector< std::vector< std::vector< float > > > get_full_flush_matrix (bool with_multiplier=true) const
int get_printer_extruder_count () const
bool support_different_extruders () const
void update_filament_count ()
void load_config_from_wizard (const std::string &name, DynamicPrintConfig config, Semver file_version)
void load_config_model (const std::string &name, DynamicPrintConfig config, Semver file_version=Semver(), PublishedConfig *published_config=nullptr)
ConfigSubstitutions load_config_file (const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule)
DynamicPrintConfig config_from_gcode (const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule, ConfigSubstitutions &substitutions) const
std::pair< PresetsConfigSubstitutions, size_t > load_vendor_configs_from_json (const std::string &dir, const std::string &vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule, const PresetBundle *base_bundle=nullptr, bool allow_cache=true)
std::vector< std::string > export_current_configs (const std::string &path, std::function< int(std::string const &)> override_confirm, bool include_modify, bool export_system_settings=false)
void set_default_suppressed (bool default_suppressed)
void set_filament_preset (size_t idx, const std::string &name)
void update_multi_material_filament_presets (size_t to_delete_filament_id=size_t(-1))
bool is_mixed_filament (size_t idx) const
std::vector< size_t > physical_filament_config_indices () const
size_t num_mixed_filaments () const
size_t num_physical_filaments () const
void on_extruders_count_changed (int extruder_count)
void update_compatible (PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible)
void update_compatible (PresetSelectCompatibleType select_other_if_incompatible)
void normalize_compatible_presets ()
void load_installed_printers (const AppConfig &config)
const std::string & get_preset_name_by_alias (const Preset::Type &preset_type, const std::string &alias) const
const int get_required_hrc_by_filament_type (const std::string &filament_type) const
void save_changes_for_preset (const std::string &new_name, Preset::Type type, const std::vector< std::string > &unselected_options, bool save_to_project=false)
std::pair< PresetsConfigSubstitutions, std::string > load_system_models_from_json (ForwardCompatibilitySubstitutionRule compatibility_rule)
std::pair< PresetsConfigSubstitutions, std::string > load_system_filaments_json (ForwardCompatibilitySubstitutionRule compatibility_rule)
VendorProfile get_custom_vendor_models () const
bool has_errors (bool check_duplicate_filament_subtypes=false) const
int error_count () const
bool check_preset_references () const
bool check_printer_default_materials () const
std::pair< PresetsConfigSubstitutions, std::string > load_vendors (const std::vector< VendorSource > &vendors, ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache, const std::atomic< bool > *cancel=nullptr, std::vector< std::string > *failed=nullptr)

Static Public Member Functions

static DynamicPrintConfig construct_full_config (Preset &in_printer_preset, Preset &in_print_preset, const DynamicPrintConfig &project_config, std::vector< Preset > &in_filament_presets, bool apply_extruder, std::optional< std::vector< int > > filament_maps_new, std::optional< std::vector< int > > filament_volume_maps_new=std::nullopt)
static std::string find_preset_vendor (const std::string &preset_name, Preset::Type type)
static std::set< std::string > project_different_keys (const std::string &different_settings)
static void convert_filament_preset_name (const std::string &machine_name, std::string &filament_name)
static int get_filament_variant_index (const DynamicPrintConfig &filament_config, const DynamicPrintConfig &printer_config, int extruder_id, NozzleVolumeType nozzle_volume_type)
static std::array< Preset::Type, 3 > types_list (PrinterTechnology pt)

Public Attributes

PresetCollection prints
PresetCollection sla_prints
PresetCollection filaments
PresetCollection sla_materials
PrinterPresetCollection printers
PhysicalPrinterCollection physical_printers
std::vector< std::string > filament_presets
std::map< int, DynamicPrintConfig > filament_ams_list
std::vector< std::vector< std::string > > ams_multi_color_filment
std::vector< std::map< int, int > > extruder_ams_counts
Preset const * calibrate_printer = nullptr
std::set< Preset const * > calibrate_filaments
DynamicPrintConfig project_config
VendorMap vendors
std::map< std::string, DynamicPrintConfig > m_config_maps
std::map< std::string, std::string > m_filament_id_maps
boost::filesystem::path dir_user_presets_local
boost::filesystem::path dir_user_presets_subscribed
PresetBundleMetadata bundles
ObsoletePresets obsolete_presets

Static Public Attributes

static const char * ORCA_DEFAULT_BUNDLE = "Custom"
static const char * ORCA_DEFAULT_PRINTER_MODEL = "MyKlipper 0.4 nozzle"
static const char * ORCA_DEFAULT_PRINTER_VARIANT = "0.4"
static const char * ORCA_DEFAULT_FILAMENT = "Generic PLA @System"
static const char * ORCA_FILAMENT_LIBRARY = "OrcaFilamentLibrary"
static const char * ORCA_DEFAULT_FILAMENT_PLACEHOLDER = "Default Filament"

Private Member Functions

size_t min_filament_count () const
std::vector< std::vector< std::string > > merge_presets (const std::vector< PresetBundle * > &others)
VendorRead read_vendor (const std::string &dir, const std::string &vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache)
void parse_vendor_json (VendorRead &read)
std::pair< PresetsConfigSubstitutions, size_t > install_vendor_read (VendorRead &&read, const PresetBundle *base_bundle)
bool install_vendor_cache (const std::string &cache_path, const std::string &vendor_name, VendorCacheData &&data, const PresetBundle *base_bundle)
void log_errors (const std::vector< std::string > &errors)
size_t install_vendor (const std::string &path, const std::string &vendor_name, const PresetBundle *base_bundle, LoadConfigBundleAttributes flags, const VendorCacheData &entries, VendorParse *parsed, bool complete, PresetsConfigSubstitutions &substitutions)
void install_vendor_entries (VendorInstall &install, const std::vector< CachedPreset > &entries, std::vector< EntryParse > *parsed)
PresetInstall resolve_vendor_preset (const CachedPreset &entry, const VendorInstall &install) const
std::string commit_vendor_preset (const CachedPreset &entry, PresetInstall &&resolved, ConfigSubstitutions &&substitutions, VendorInstall &install)
void clear_printer_hold_aliases ()
const PresetBundle * load_source_vendor (const boost::filesystem::path &root_dir, const std::string &vendor_id, ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error, bool allow_cache=false)
bool check_duplicate_filament_subtypes () const
std::pair< PresetsConfigSubstitutions, std::string > load_system_presets_from_json (ForwardCompatibilitySubstitutionRule compatibility_rule, bool write_caches=true)
void update_filament_multi_color ()
void update_system_maps ()
void load_installed_filaments (AppConfig &config)
void load_installed_sla_materials (AppConfig &config)
void load_config_file_config (const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config, Semver file_version=Semver(), bool selected=false, PublishedConfig *published_config=nullptr)
DynamicPrintConfig full_fff_config (bool apply_extruder, std::optional< std::vector< int > > filament_maps=std::nullopt, std::optional< std::vector< int > > filament_volume_maps=std::nullopt) const
DynamicPrintConfig full_sla_config () const
bool save_preset_to_bundle_dir (Preset &preset, PresetCollection *collection, const std::string &bundle_id, const std::string &type_subdir, const std::string &bundle_base_dir)

Private Attributes

bool m_generate_vendor_caches { false }
bool m_preserve_vendor_source_paths { false }
std::map< std::tuple< std::string, std::string, ForwardCompatibilitySubstitutionRule, bool >, std::unique_ptr< PresetBundle > > m_source_vendor_bundles
bool validation_mode = false
std::string vendor_to_validate = ""
int m_errors = 0
int m_selection_export_blockers = 0

Detailed Description


Class Documentation

◆ Slic3r::PresetBundle::PresetPreferences

struct Slic3r::PresetBundle::PresetPreferences
Collaboration diagram for Slic3r::PresetBundle::PresetPreferences:
Class Members
string filament
string printer_model_id
string printer_variant
string sla_material

◆ Slic3r::PresetBundle::LegacyUserFilamentPresetMigration

struct Slic3r::PresetBundle::LegacyUserFilamentPresetMigration
Collaboration diagram for Slic3r::PresetBundle::LegacyUserFilamentPresetMigration:
Class Members
string backup
vector< string > failed
bool locked {false}

◆ Slic3r::PresetBundle::Selection

struct Slic3r::PresetBundle::Selection
Collaboration diagram for Slic3r::PresetBundle::Selection:
Class Members
vector< map< int, int > > extruder_ams_counts
vector< string > filament_presets
Collection filaments
Collection printers
Collection prints
DynamicPrintConfig project_config

◆ Slic3r::PresetBundle::ObsoletePresets

struct Slic3r::PresetBundle::ObsoletePresets
Collaboration diagram for Slic3r::PresetBundle::ObsoletePresets:
Class Members
vector< string > filaments
vector< string > printers
vector< string > prints
vector< string > sla_materials
vector< string > sla_prints

◆ Slic3r::PresetBundle::VendorSource

struct Slic3r::PresetBundle::VendorSource
Collaboration diagram for Slic3r::PresetBundle::VendorSource:
Class Members
path dir
string name

◆ Slic3r::PresetBundle::EntryParse

struct Slic3r::PresetBundle::EntryParse
Collaboration diagram for Slic3r::PresetBundle::EntryParse:
Class Members
vector< string > errors
ConfigSubstitutions substitutions
vector< string > warnings

◆ Slic3r::PresetBundle::VendorParse

struct Slic3r::PresetBundle::VendorParse
Collaboration diagram for Slic3r::PresetBundle::VendorParse:
Class Members
vector< EntryParse > filament_entries
vector< EntryParse > machine_entries
vector< EntryParse > process_entries

◆ Slic3r::PresetBundle::VendorRead

struct Slic3r::PresetBundle::VendorRead
Collaboration diagram for Slic3r::PresetBundle::VendorRead:
Class Members
string cache_path
bool cacheable { false }
ForwardCompatibilitySubstitutionRule compatibility_rule
VendorCacheData data
string dir
int errors_at_entry { 0 }
vector< string > failed_errors
const char * failed_kind { nullptr }
string failed_subfile
LoadConfigBundleAttributes flags
bool from_cache { false }
VendorParse parsed
string reason
string vendor_name
bool vendor_only { false }
string version
bool will_cache { false }

◆ Slic3r::PresetBundle::VendorInstall

struct Slic3r::PresetBundle::VendorInstall
Collaboration diagram for Slic3r::PresetBundle::VendorInstall:
Class Members
const PresetBundle * base_bundle
map< string, DynamicPrintConfig > config_maps
size_t count { 0 }
map< string, string > filament_id_maps
LoadConfigBundleAttributes flags
map< string, DynamicPrintConfig > include_maps
set< string > included
set< string > inherited
unordered_set< string > installed_names
bool is_from_lib
string path
PresetCollection * presets
PresetsConfigSubstitutions * substitutions
string vendor_name
const VendorProfile * vendor_profile

◆ Slic3r::PresetBundle::PresetInstall

struct Slic3r::PresetBundle::PresetInstall
Collaboration diagram for Slic3r::PresetBundle::PresetInstall:
Class Members
string alias
DynamicPrintConfig config
bool config_only { false }
vector< string > errors
string filament_id
string file_path
optional< DynamicPrintConfig > included
string reason
vector< string > renamed_from
optional< DynamicPrintConfig > retained

Member Typedef Documentation

◆ LoadConfigBundleAttributes

Member Enumeration Documentation

◆ LoadConfigBundleAttribute

Enumerator
SaveImported 
ResetUserProfile 
LoadSystem 
LoadVendorOnly 
LoadFilamentOnly 
599 {
600 // Save the profiles, which have been loaded.
602 // Delete all old config profiles before loading.
604 // Load a system config bundle.
608 };
@ ResetUserProfile
Definition PresetBundle.hpp:603
@ LoadSystem
Definition PresetBundle.hpp:605
@ LoadVendorOnly
Definition PresetBundle.hpp:606
@ SaveImported
Definition PresetBundle.hpp:601
@ LoadFilamentOnly
Definition PresetBundle.hpp:607

Constructor & Destructor Documentation

◆ PresetBundle() [1/2]

Slic3r::PresetBundle::PresetBundle ( )
485 : prints(Preset::TYPE_PRINT, Preset::print_options(), static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()))
487 , sla_materials(Preset::TYPE_SLA_MATERIAL, Preset::sla_material_options(), static_cast<const SLAMaterialConfig &>(SLAFullPrintConfig::defaults()))
488 , sla_prints(Preset::TYPE_SLA_PRINT, Preset::sla_print_options(), static_cast<const SLAPrintObjectConfig &>(SLAFullPrintConfig::defaults()))
489 , printers(Preset::TYPE_PRINTER, Preset::printer_options(), static_cast<const PrintRegionConfig &>(FullPrintConfig::defaults()), "Default Printer")
491{
492 // The following keys are handled by the UI, they do not have a counterpart in any StaticPrintConfig derived classes,
493 // therefore they need to be handled differently. As they have no counterpart in StaticPrintConfig, they are not being
494 // initialized based on PrintConfigDef(), but to empty values (zeros, empty vectors, empty strings).
495 //
496 // "compatible_printers", "compatible_printers_condition", "inherits",
497 // "print_settings_id", "filament_settings_id", "printer_settings_id", "printer_settings_id"
498 // "printer_model", "printer_variant", "default_print_profile", "default_filament_profile"
499
500 // Create the ID config keys, as they are not part of the Static print config classes.
501 this->prints.default_preset().config.optptr("print_settings_id", true);
502 this->prints.default_preset().compatible_printers_condition();
503 this->prints.default_preset().inherits();
504
505 this->filaments.default_preset().config.option<ConfigOptionStrings>("filament_settings_id", true)->values = {""};
506 this->filaments.default_preset().compatible_printers_condition();
507 this->filaments.default_preset().inherits();
508 // Set all the nullable values to nils.
509 {
510 auto& default_config = this->filaments.default_preset().config;
511 for(const std::string& opt_key : default_config.keys()){
512 ConfigOption* opt = default_config.optptr(opt_key, false);
513 bool is_override_key = is_filament_extruder_override_key(opt_key);
514 if(!is_override_key || !opt->nullable())
515 continue;
516 opt->deserialize("nil",ForwardCompatibilitySubstitutionRule::Disable);
517 }
518 }
519
520 this->sla_materials.default_preset().config.optptr("sla_material_settings_id", true);
521 this->sla_materials.default_preset().compatible_printers_condition();
522 this->sla_materials.default_preset().inherits();
523
524 this->sla_prints.default_preset().config.optptr("sla_print_settings_id", true);
525 this->sla_prints.default_preset().config.opt_string("filename_format", true) = "[input_filename_base].sl1";
526 this->sla_prints.default_preset().compatible_printers_condition();
527 this->sla_prints.default_preset().inherits();
528
529 //this->printers.add_default_preset(Preset::sla_printer_options(), static_cast<const SLAMaterialConfig &>(SLAFullPrintConfig::defaults()), "- default SLA -");
530 //this->printers.preset(1).printer_technology_ref() = ptSLA;
531 for (size_t i = 0; i < 1; ++i) {
532 // The following ugly switch is to avoid printers.preset(0) to return the edited instance, as the 0th default is the current one.
533 Preset &preset = this->printers.default_preset(i);
534 for (const char *key : {"printer_settings_id", "printer_model", "printer_variant", "thumbnails"}) preset.config.optptr(key, true);
535 //if (i == 0) {
536 preset.config.optptr("default_print_profile", true);
537 preset.config.option<ConfigOptionStrings>("default_filament_profile", true);
538 //} else {
539 // preset.config.optptr("default_sla_print_profile", true);
540 // preset.config.optptr("default_sla_material_profile", true);
541 //}
542 // default_sla_material_profile
543 preset.inherits();
544 }
545
546 // Re-activate the default presets, so their "edited" preset copies will be updated with the additional configuration values above.
547 this->prints.select_preset(0);
548 this->sla_prints.select_preset(0);
549 this->filaments.select_preset(0);
550 this->sla_materials.select_preset(0);
551 this->printers.select_preset(0);
552
553 this->project_config.apply_only(FullPrintConfig::defaults(), s_project_options);
554}
static const std::vector< std::string > & printer_options()
Definition Preset.cpp:4572
PresetCollection sla_prints
Definition PresetBundle.hpp:498
PrinterPresetCollection printers
Definition PresetBundle.hpp:503
static const char * ORCA_DEFAULT_FILAMENT_PLACEHOLDER
Definition PresetBundle.hpp:691
DynamicPrintConfig project_config
Definition PresetBundle.hpp:521
PresetCollection sla_materials
Definition PresetBundle.hpp:500
PresetCollection prints
Definition PresetBundle.hpp:497
PresetCollection filaments
Definition PresetBundle.hpp:499
PhysicalPrinterCollection physical_printers
Definition PresetBundle.hpp:504
static const std::vector< std::string > & sla_material_options()
Definition Preset.cpp:1712
static const std::vector< std::string > & print_options()
Definition Preset.cpp:1705
static const std::vector< std::string > & printer_options()
Definition Preset.cpp:1715
static const std::vector< std::string > & filament_options()
Definition Preset.cpp:1706
@ TYPE_SLA_PRINT
Definition Preset.hpp:247
@ TYPE_PRINTER
Definition Preset.hpp:250
@ TYPE_PRINT
Definition Preset.hpp:246
@ TYPE_SLA_MATERIAL
Definition Preset.hpp:249
@ TYPE_FILAMENT
Definition Preset.hpp:248
static const std::vector< std::string > & sla_print_options()
Definition Preset.cpp:1711
@ Disable
Definition Config.hpp:243
zaa_minimize_perimeter_height PrintRegionConfig
Definition PrintConfig.hpp:2183
bool is_filament_extruder_override_key(const std::string &opt_key)
Definition PrintConfig.cpp:130
@ Preset
Definition calib.hpp:39
static std::vector< std::string > s_project_options
Definition PresetBundle.cpp:125

References filaments, ORCA_DEFAULT_FILAMENT_PLACEHOLDER, physical_printers, printers, Slic3r::PrintRegionConfig, prints, sla_materials, sla_prints, and Slic3r::ConfigOptionVector< T >::values.

Referenced by PresetBundle(), Slic3r::PresetBundle::SelectionExportBlocker::SelectionExportBlocker(), full_fff_config(), install_vendor(), install_vendor_cache(), install_vendor_read(), load_source_vendor(), load_system_filaments_json(), load_vendor_cache(), load_vendor_configs_from_json(), merge_presets(), operator=(), reload_local_bundle(), resolve_preset_config(), resolve_system_preset(), and resolve_vendor_preset().

Here is the caller graph for this function:

◆ PresetBundle() [2/2]

Slic3r::PresetBundle::PresetBundle ( const PresetBundle & rhs)
762{
763 *this = rhs;
764}

References PresetBundle().

Here is the call graph for this function:

Member Function Documentation

◆ apply_vendor_config()

bool Slic3r::PresetBundle::apply_vendor_config ( const std::map< std::string, std::map< std::string, std::set< std::string > > > & new_vendors,
const std::map< std::string, std::string > & new_filaments,
AppConfig * app_config,
bool overwrite = true,
const std::string & preferred_printer_model = std::string(),
const std::string & preferred_printer_variant = std::string(),
const std::string & preferred_filament = std::string() )
1960{
1961
1962 // Get current configuration from AppConfig
1963 const auto old_vendors = app_config->vendors();
1964 const auto old_filaments = app_config->has_section(AppConfig::SECTION_FILAMENTS)
1965 ? app_config->get_section(AppConfig::SECTION_FILAMENTS)
1966 : std::map<std::string, std::string>();
1967
1968 // Find vendors that need installation
1969 std::vector<std::string> install_bundles;
1970 for (const auto &it : new_vendors) {
1971 if (it.second.size() > 0) {
1972 if (!is_vendor_installed(it.first)) {
1973 install_bundles.emplace_back(it.first);
1974 }
1975 }
1976 }
1977
1978 // Install bundles from resources
1979 if (!install_bundles.empty()) {
1980 BOOST_LOG_TRIVIAL(info) << "Installing " << install_bundles.size() << " vendor bundles from resources";
1981 if (!Slic3r::install_vendor_bundles_from_resources(install_bundles)) {
1982 BOOST_LOG_TRIVIAL(error) << "Failed to install vendor bundles";
1983 return false;
1984 }
1985 } else {
1986 BOOST_LOG_TRIVIAL(info) << "No bundles need to be installed from resource directory";
1987 }
1988
1989 // For each @System filament, check if a vendor-specific override exists
1990 // in the loaded profiles. If so, replace the @System variant with the
1991 // override (e.g. replace "Generic ABS @System" with BBL "Generic ABS").
1992 // When printers from the default bundle are also selected, keep @System
1993 // too since those printers need it.
1994 static const std::string system_suffix = " @System";
1995 auto it_default = new_vendors.find(PresetBundle::ORCA_DEFAULT_BUNDLE);
1996 bool has_default_bundle_printer = it_default != new_vendors.end() && !it_default->second.empty();
1997
1998 // Check if any non-default vendor has selected printers
1999 bool has_vendor_printer = false;
2000 for (const auto& [vendor, models] : new_vendors) {
2001 if (vendor != PresetBundle::ORCA_DEFAULT_BUNDLE && !models.empty()) {
2002 has_vendor_printer = true;
2003 break;
2004 }
2005 }
2006
2007 std::map<std::string, std::string> supplemented_filaments;
2008 for (const auto& [name, value] : new_filaments) {
2009 if (name.size() > system_suffix.size() &&
2010 name.compare(name.size() - system_suffix.size(), system_suffix.size(), system_suffix) == 0) {
2011 std::string short_name = name.substr(0, name.size() - system_suffix.size());
2012
2013 if (has_vendor_printer) {
2014 // Check if this filament exists in the loaded vendor profiles
2015 // For @System filaments, we check if the short_name exists as a vendor-specific filament
2016 bool has_vendor_filament = false;
2017 for (const auto& [vendor, models] : new_vendors) {
2018 if (vendor != PresetBundle::ORCA_DEFAULT_BUNDLE) {
2019 auto vendor_it = this->vendors.find(vendor);
2020 // Check if this vendor is loaded in the preset bundle
2021 if (vendor_it != this->vendors.end()) {
2022 // Vendor is loaded, check if the filament exists
2023 for (auto f : vendor_it->second.default_filaments) {
2024 BOOST_LOG_TRIVIAL(info) << " checking if vendor filament " << f << " matches " << short_name << "(" << name << ")";
2025 if (f.find(short_name) != std::string::npos) {
2026 BOOST_LOG_TRIVIAL(info) << name << " has filament from vendor: " << vendor;
2027 has_vendor_filament = true;
2028 break;
2029 }
2030 }
2031 break;
2032 }
2033 }
2034 }
2035
2036 if (has_vendor_filament) {
2037 supplemented_filaments[short_name] = value;
2038 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Replacing @System filament: '" << name << "' -> '" << short_name << "'";
2039 if (has_default_bundle_printer) {
2040 supplemented_filaments[name] = value;
2041 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Also keeping '" << name << "' for default bundle printers";
2042 }
2043 continue;
2044 }
2045 }
2046 }
2047 supplemented_filaments[name] = value;
2048 }
2049
2050 // Update AppConfig - merge with existing values instead of overwriting depending on bool
2051 if (overwrite) {
2052 app_config->set_section(AppConfig::SECTION_FILAMENTS, supplemented_filaments);
2053 app_config->set_vendors(new_vendors);
2054 }
2055 else {
2056 // Merge filaments
2057 std::map<std::string, std::string> merged_filaments = old_filaments;
2058 for (const auto& [name, value] : supplemented_filaments) {
2059 merged_filaments[name] = value;
2060 }
2061 app_config->set_section(AppConfig::SECTION_FILAMENTS, merged_filaments);
2062
2063 // Merge vendors
2064 std::map<std::string, std::map<std::string, std::set<std::string>>> merged_vendors = old_vendors;
2065 for (const auto& [vendor, models] : new_vendors) {
2066 auto& vendor_entry = merged_vendors[vendor];
2067 for (const auto& [model, variants] : models) {
2068 auto& model_entry = vendor_entry[model];
2069 model_entry.insert(variants.begin(), variants.end());
2070 }
2071 }
2072 app_config->set_vendors(merged_vendors);
2073 }
2074
2075 // Load presets with new configuration
2077 {preferred_printer_model, preferred_printer_variant, preferred_filament, std::string()});
2078
2079 // Ensure active filament compatibility
2080 // If the active filament is not in the wizard-selected filaments, switch to the first
2081 // compatible wizard-selected filament. This handles the first-run case where load_presets
2082 // falls back to "Generic PLA" even though the user selected a different filament.
2083 if (!supplemented_filaments.empty()) {
2084 bool active_filament_selected = supplemented_filaments.count(this->filament_presets.front()) > 0;
2085 if (!active_filament_selected) {
2086 for (const auto& [filament_name, _] : supplemented_filaments) {
2087 const Preset* preset = this->filaments.find_preset(filament_name);
2088 if (preset && preset->is_visible && preset->is_compatible) {
2089 this->filaments.select_preset_by_name(filament_name, true);
2090 this->filament_presets.front() = this->filaments.get_selected_preset_name();
2091 break;
2092 }
2093 }
2094 }
2095 }
2096
2097 // Export selections
2098 this->export_selections(*app_config);
2099 return true;
2100}
#define _(s)
Definition 3mf.cpp:306
static const std::string SECTION_FILAMENTS
Definition AppConfig.hpp:408
void export_selections(AppConfig &config)
Definition PresetBundle.cpp:4232
PresetsConfigSubstitutions load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule rule, const PresetPreferences &preferred_selection=PresetPreferences(), std::string *errors=nullptr, bool read_only=false)
Definition PresetBundle.cpp:881
static const char * ORCA_DEFAULT_BUNDLE
Definition PresetBundle.hpp:686
VendorMap vendors
Definition PresetBundle.hpp:525
std::vector< std::string > filament_presets
Definition PresetBundle.hpp:507
@ Enable
Definition Config.hpp:245
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124
bool is_vendor_installed(const std::string &vendor)
Definition utils.cpp:1973
bool install_vendor_bundles_from_resources(const std::vector< std::string > &bundle_names, const std::string &resource_subdir, const std::string &data_subdir)
Definition utils.cpp:2041

References _, apply_vendor_config(), Slic3r::Enable, export_selections(), Slic3r::f(), filament_presets, filaments, Slic3r::AppConfig::get_section(), Slic3r::AppConfig::has_section(), Slic3r::install_vendor_bundles_from_resources(), Slic3r::Preset::is_compatible, Slic3r::is_vendor_installed(), Slic3r::Preset::is_visible, load_presets(), ORCA_DEFAULT_BUNDLE, Slic3r::AppConfig::SECTION_FILAMENTS, Slic3r::AppConfig::set_section(), Slic3r::AppConfig::set_vendors(), Slic3r::AppConfig::vendors(), and vendors.

Referenced by Slic3r::GUI::GuideFrame::apply_config(), and apply_vendor_config().

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

◆ backup_user_folder()

bool Slic3r::PresetBundle::backup_user_folder ( ) const
1048{
1049 const std::string backup_folderpath = data_dir() + "/" + (boost::format("user_backup-v%1%") % SoftFever_VERSION).str();
1050
1051 // Check if backup file already exists
1052 if (boost::filesystem::exists(boost::filesystem::path(backup_folderpath)))
1053 return false;
1054
1055 BOOST_LOG_TRIVIAL(info) << "Backing up user folder to: " << backup_folderpath;
1056 try {
1057 // Copy the user folder to the backup folder
1058 boost::filesystem::copy(data_dir() + "/" + PRESET_USER_DIR, backup_folderpath, boost::filesystem::copy_options::recursive);
1059 BOOST_LOG_TRIVIAL(info) << "User folder backup completed successfully";
1060 return true;
1061 } catch (const std::exception& ex) {
1062 BOOST_LOG_TRIVIAL(error) << "Exception during user folder backup: " << ex.what();
1063 // Try to clean up partially copied backup folder
1064 if (boost::filesystem::exists(boost::filesystem::path(backup_folderpath)))
1065 boost::filesystem::remove_all(boost::filesystem::path(backup_folderpath));
1066 return false;
1067 }
1068}
#define PRESET_USER_DIR
Definition Preset.hpp:32
const std::string & data_dir()
Definition utils.cpp:365

References backup_user_folder(), Slic3r::data_dir(), and PRESET_USER_DIR.

Referenced by backup_user_folder().

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

◆ backup_user_folder_to_zip()

bool Slic3r::PresetBundle::backup_user_folder_to_zip ( const std::string & zip_path) const
1071{
1072 const fs::path user_dir = fs::path(data_dir()) / PRESET_USER_DIR;
1073 BOOST_LOG_TRIVIAL(info) << "Backing up user folder to: " << zip_path;
1074 try {
1075 Zipper zipper(zip_path);
1076 // Directories get their own entries, which extract_archive_confined() needs to recreate them.
1077 zipper.add_entry(std::string(PRESET_USER_DIR) + "/", nullptr, 0);
1078 // The loader follows symlinked folders, and migration writes the presets in them.
1079 for (const fs::directory_entry &entry : fs::recursive_directory_iterator(user_dir, fs::directory_options::follow_directory_symlink)) {
1080 const std::string name = (fs::path(PRESET_USER_DIR) / entry.path().lexically_relative(user_dir)).generic_string();
1081 if (fs::is_directory(entry.status())) {
1082 zipper.add_entry(name + "/", nullptr, 0);
1083 continue;
1084 }
1085 if (!fs::is_regular_file(entry.status()))
1086 continue;
1087 boost::nowide::ifstream in(entry.path().string(), std::ios::binary);
1088 const std::string data((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
1089 if (!in.good() && !in.eof())
1090 throw Slic3r::RuntimeError("can not read " + entry.path().string());
1091 zipper.add_entry(name, data.data(), data.size());
1092 }
1093 zipper.finalize();
1094 return true;
1095 } catch (const std::exception &ex) {
1096 BOOST_LOG_TRIVIAL(error) << "Exception during user folder backup: " << ex.what();
1097 boost::system::error_code ec;
1098 fs::remove(zip_path, ec);
1099 return false;
1100 }
1101}

References Slic3r::Zipper::add_entry(), backup_user_folder_to_zip(), Slic3r::data_dir(), Slic3r::Zipper::finalize(), and PRESET_USER_DIR.

Referenced by backup_user_folder_to_zip(), and migrate_legacy_user_filament_presets().

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

◆ check_and_fix_user_presets_syncinfo()

void Slic3r::PresetBundle::check_and_fix_user_presets_syncinfo ( const std::string & user_id)
2724{
2725 auto process_collection = [&user_id](PresetCollection& collection) {
2726 collection.lock();
2727 for (auto& preset : collection) {
2728 if (preset.is_user()) {
2729 collection.check_and_fix_syncinfo(preset, user_id);
2730 }
2731 }
2732 collection.unlock();
2733 };
2734 process_collection(this->prints);
2735 process_collection(this->filaments);
2736 process_collection(this->printers);
2737}

References check_and_fix_user_presets_syncinfo(), filaments, Slic3r::Preset::is_user(), printers, and prints.

Referenced by check_and_fix_user_presets_syncinfo().

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

◆ check_duplicate_filament_subtypes()

bool Slic3r::PresetBundle::check_duplicate_filament_subtypes ( ) const
private
8939{
8940 // Pre-collect system filament presets (each carries its effective filament_id,
8941 // inherited from its @base at load time), grouped by vendor so we only test a
8942 // printer against its own vendor's filaments. A vendor's compatible_printers
8943 // only names that vendor's printers, so same-vendor scoping is correctness
8944 // preserving and avoids an O(all printers x all filaments) sweep. The one
8945 // exception is the Orca Filament Library: its presets have empty
8946 // compatible_printers (= compatible with every printer, minus the alias-shadowing
8947 // exclusions that is_compatible_with_printer checks via m_excluded_from), so they
8948 // are tested against every vendor's printers as well.
8949 std::map<std::string, std::vector<const Preset *>> filaments_by_vendor;
8950 for (const auto &preset : filaments) {
8951 if (!preset.is_system || preset.filament_id.empty() || preset.vendor == nullptr)
8952 continue;
8953 filaments_by_vendor[preset.vendor->name].push_back(&preset);
8954 }
8955
8956 const std::vector<const Preset *> no_filaments;
8957 const auto library_it = filaments_by_vendor.find(ORCA_FILAMENT_LIBRARY);
8958 const std::vector<const Preset *> &library_filaments = library_it == filaments_by_vendor.end() ? no_filaments : library_it->second;
8959
8960 bool found_duplicates = false;
8961 for (const auto &printer : printers) {
8962 if (!printer.is_system || printer.vendor == nullptr)
8963 continue;
8964 auto vendor_it = filaments_by_vendor.find(printer.vendor->name);
8965 const std::vector<const Preset *> &vendor_filaments = vendor_it == filaments_by_vendor.end() ? no_filaments : vendor_it->second;
8966 if (vendor_filaments.empty() && library_filaments.empty())
8967 continue;
8968
8969 const PresetWithVendorProfile active_printer = printers.get_preset_with_vendor_profile(printer);
8970 // std::map keeps the reported errors in a deterministic (sorted) order.
8971 std::map<std::string, std::vector<const Preset *>> by_filament_id;
8972 for (const Preset *fil : vendor_filaments)
8973 if (is_compatible_with_printer(filaments.get_preset_with_vendor_profile(*fil), active_printer))
8974 by_filament_id[fil->filament_id].push_back(fil);
8975 if (&vendor_filaments != &library_filaments)
8976 for (const Preset *fil : library_filaments)
8977 if (is_compatible_with_printer(filaments.get_preset_with_vendor_profile(*fil), active_printer))
8978 by_filament_id[fil->filament_id].push_back(fil);
8979
8980 for (const auto &entry : by_filament_id) {
8981 if (entry.second.size() < 2)
8982 continue;
8983 found_duplicates = true;
8984 // List each conflicting preset with a clickable file:// URI on its own
8985 // line, so the profile author can jump straight to the files to fix.
8986 // A preset from another bundle (the Orca Filament Library) is tagged with
8987 // its vendor so the source bundle is obvious.
8988 std::string presets;
8989 for (const Preset *p : entry.second) {
8990 presets += "\n - " + p->name;
8991 if (p->vendor != nullptr && p->vendor->name != printer.vendor->name)
8992 presets += " [" + p->vendor->name + "]";
8993 presets += "\n " + preset_file_uri(p->file);
8994 }
8995 BOOST_LOG_TRIVIAL(error)
8996 << "Ambiguous AMS filament match: " << entry.second.size()
8997 << " filament presets share filament_id \"" << entry.first
8998 << "\" and are all compatible with printer \"" << printer.name
8999 << "\". When matching an AMS spool the slicer cannot tell them apart and"
9000 " silently picks whichever loads first." << presets;
9001 }
9002 }
9003
9004 // Print the troubleshooting guidance once, not per error, to keep the log readable.
9005 if (found_duplicates)
9006 BOOST_LOG_TRIVIAL(error) << "\n========================================\n"
9007 << "How to fix \"Ambiguous AMS filament match\" errors: make sure only ONE filament"
9008 " preset with a given filament_id is compatible with each printer. Either"
9009 "\n (a) remove the overlapping printer from a preset's \"compatible_printers\""
9010 " list (e.g. a '@printer' preset over-claiming a nozzle that already has its own"
9011 " '@printer 0.x nozzle' preset), or"
9012 "\n (b) if these are genuinely different materials, give each its own"
9013 " \"filament_id\" - a common cause is a wrong \"inherits\" pointing at another"
9014 " material's @base preset.";
9015
9016 return found_duplicates;
9017}
static const char * ORCA_FILAMENT_LIBRARY
Definition PresetBundle.hpp:690
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config)
Definition Preset.cpp:909
static std::string preset_file_uri(const std::string &file)
Definition PresetBundle.cpp:8785

References check_duplicate_filament_subtypes(), Slic3r::Preset::filament_id, filaments, Slic3r::Preset::file, Slic3r::is_compatible_with_printer(), Slic3r::Preset::is_system, Slic3r::Preset::name, Slic3r::VendorProfile::name, ORCA_FILAMENT_LIBRARY, Slic3r::preset_file_uri(), printers, and Slic3r::Preset::vendor.

Referenced by check_duplicate_filament_subtypes(), and has_errors().

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

◆ check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray()

bool Slic3r::PresetBundle::check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray ( const std::string & printer_type,
std::string & nozzle_diameter_str,
std::string & setting_id,
std::string & tag_uid,
std::string & nozzle_temp_min,
std::string & nozzle_temp_max,
std::string & preset_setting_id,
int extruder_id,
NozzleVolumeType nozzle_volume_type )
5231{
5232 bool is_equation = true;
5233
5234 std::map<std::string, std::vector<Preset const *>> filament_list = filaments.get_filament_presets();
5235 std::set<std::string> printer_names = get_printer_names_by_printer_type_and_nozzle(printer_type, nozzle_diameter_str);
5236
5237 auto filament_iter = filament_list.find(setting_id);
5238 if (filament_iter == filament_list.end())
5239 return is_equation;
5240
5241 for (const Preset *preset : filament_iter->second) {
5242 if (tag_uid == "0" || (tag_uid.size() == 16 && tag_uid.substr(12, 2) == "01")) continue;
5243 if (preset && !preset->is_user()) continue;
5244 ConfigOption * printer_opt = const_cast<Preset *>(preset)->config.option("compatible_printers");
5245 ConfigOptionStrings *printer_strs = dynamic_cast<ConfigOptionStrings *>(printer_opt);
5246 bool compared = false;
5247 for (const std::string &printer_str : printer_strs->values) {
5248 if (printer_names.find(printer_str) != printer_names.end()) {
5249 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << "nozzle temp matching: preset name: " << preset->name << " printer name: " << printer_str;
5250 // Compare only once
5251 if (!compared) {
5252 compared = true;
5253 const Preset *printer = printers.find_preset(printer_str);
5254 const int variant_index = printer ? get_filament_variant_index(preset->config, printer->config, extruder_id, nozzle_volume_type) : 0;
5255 bool min_temp_equation = false, max_temp_equation = false;
5256 int min_nozzle_temp = std::stoi(nozzle_temp_min);
5257 int max_nozzle_temp = std::stoi(nozzle_temp_max);
5258 ConfigOption *opt_min = const_cast<Preset *>(preset)->config.option("nozzle_temperature_range_low");
5259 if (opt_min) {
5260 ConfigOptionInts *opt_min_ints = dynamic_cast<ConfigOptionInts *>(opt_min);
5261 min_nozzle_temp = opt_min_ints->get_at(variant_index);
5262 if (std::to_string(min_nozzle_temp) == nozzle_temp_min)
5263 min_temp_equation = true;
5264 else {
5265 BOOST_LOG_TRIVIAL(info) << "tray min temp: " << nozzle_temp_min << " preset min temp: " << min_nozzle_temp;
5266 nozzle_temp_min = std::to_string(min_nozzle_temp);
5267 }
5268 }
5269 ConfigOption *opt_max = const_cast<Preset *>(preset)->config.option("nozzle_temperature_range_high");
5270 if (opt_max) {
5271 ConfigOptionInts *opt_max_ints = dynamic_cast<ConfigOptionInts *>(opt_max);
5272 max_nozzle_temp = opt_max_ints->get_at(variant_index);
5273 if (std::to_string(max_nozzle_temp) == nozzle_temp_max)
5274 max_temp_equation = true;
5275 else {
5276 BOOST_LOG_TRIVIAL(info) << "tray max temp: " << nozzle_temp_max << " preset min temp: " << max_nozzle_temp;
5277 nozzle_temp_max = std::to_string(max_nozzle_temp);
5278 }
5279 }
5280 if (min_temp_equation && max_temp_equation) {
5281 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << "Determine if the temperature has changed: no changed";
5282 } else {
5283 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << "Determine if the temperature has changed: has changed";
5284 preset_setting_id = preset->setting_id;
5285 is_equation = false;
5286 }
5287 } else {
5288 assert(false);
5289 }
5290 }
5291 }
5292 }
5293 return is_equation;
5294}
const int & get_at(size_t i) const
Definition Config.hpp:676
std::set< std::string > get_printer_names_by_printer_type_and_nozzle(const std::string &printer_type, std::string nozzle_diameter_str, bool system_only=true)
Definition PresetBundle.cpp:5156
static int get_filament_variant_index(const DynamicPrintConfig &filament_config, const DynamicPrintConfig &printer_config, int extruder_id, NozzleVolumeType nozzle_volume_type)
Definition PresetBundle.cpp:5220
ConfigOptionIntsTempl< false > ConfigOptionInts
Definition Config.hpp:1154
zaa_minimize_perimeter_height nozzle_volume_type((ConfigOptionStrings, extruder_ams_count))((ConfigOptionStrings

References check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(), Slic3r::Preset::config, filaments, Slic3r::ConfigOptionVector< int >::get_at(), get_filament_variant_index(), get_printer_names_by_printer_type_and_nozzle(), Slic3r::Preset::is_user(), Slic3r::Preset::name, Slic3r::nozzle_volume_type(), printers, Slic3r::Preset::setting_id, and Slic3r::ConfigOptionVector< T >::values.

Referenced by Slic3r::MachineObject::check_ams_filament_valid(), and check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray().

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

◆ check_preset_references()

bool Slic3r::PresetBundle::check_preset_references ( ) const
8818{
8819 bool found = false;
8820
8821 // Resolve one reference (an inherits parent or a compatible_* entry) against its target
8822 // collection and log if it is dangling (unknown) or uses a renamed preset's old name.
8823 auto report_ref = [&](const Preset &p, const std::string &name, const PresetCollection &target,
8824 const char *verb, const char *noun) {
8825 const Preset *resolved = target.find_preset(name, false);
8826 if (resolved == nullptr) {
8827 found = true;
8828 BOOST_LOG_TRIVIAL(error) << "Preset \"" << p.name << "\" " << verb << " unknown " << noun << " \"" << name << "\":\n"
8829 << preset_file_uri(p.file);
8830 } else if (resolved->name != name) {
8831 found = true;
8832 BOOST_LOG_TRIVIAL(error) << "Preset \"" << p.name << "\" " << verb << " renamed " << noun << " \"" << name
8833 << "\" (now \"" << resolved->name << "\"):\n" << preset_file_uri(p.file);
8834 }
8835 };
8836
8837 auto check_list = [&](const Preset &p, const char *key, const PresetCollection &target) {
8838 const auto *opt = p.config.option<ConfigOptionStrings>(key);
8839 if (opt == nullptr)
8840 return;
8841 for (const std::string &name : opt->values)
8842 if (!name.empty())
8843 report_ref(p, name, target, "references", key);
8844 };
8845
8846 auto check_collection = [&](const PresetCollection &holders, const PresetCollection *processes) {
8847 for (const Preset &p : holders) {
8848 if (!p.is_system)
8849 continue;
8850 if (const std::string &inh = p.inherits(); !inh.empty())
8851 report_ref(p, inh, holders, "inherits", "parent");
8852 check_list(p, "compatible_printers", this->printers);
8853 if (processes != nullptr)
8854 check_list(p, "compatible_prints", *processes);
8855 }
8856 };
8857
8858 // Printers carry no compatible_printers/compatible_prints (those name a printer, so a printer
8859 // holding them makes no sense); check_list is a no-op for them, so only their inherits is checked.
8860 check_collection(this->printers, nullptr);
8861 check_collection(this->prints, nullptr);
8862 check_collection(this->filaments, &this->prints);
8863 check_collection(this->sla_prints, nullptr);
8864 check_collection(this->sla_materials, &this->sla_prints);
8865
8866 return found;
8867}

References check_preset_references(), Slic3r::Preset::config, filaments, Slic3r::Preset::file, Slic3r::Preset::inherits(), Slic3r::Preset::is_system, Slic3r::Preset::name, Slic3r::ConfigBase::option(), Slic3r::preset_file_uri(), printers, prints, sla_materials, and sla_prints.

Referenced by check_preset_references(), and has_errors().

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

◆ check_printer_default_materials()

bool Slic3r::PresetBundle::check_printer_default_materials ( ) const
8870{
8871 bool found = false;
8872 // A model's default_materials list is shared by its variants, so report each unknown name once.
8873 std::set<const VendorProfile::PrinterModel *> checked_models;
8874 // default_filament_profile is inherited from shared base machine presets, so one bad name can
8875 // surface on many variants; report it once, at the first printer that names it.
8876 std::set<std::string> reported_unknown_profiles;
8877 for (const Preset &printer : printers) {
8878 if (!printer.is_system || printer.vendor == nullptr || printer.printer_technology() != ptFFF)
8879 continue;
8880
8881 const VendorProfile::PrinterModel *model = PresetUtils::system_printer_model(printer);
8882 const PresetWithVendorProfile active_printer = printers.get_preset_with_vendor_profile(printer);
8883 // Use the same name lookup as load_installed_filaments, not UI aliases or fuzzy matching.
8884 // A model's defaults can cover different nozzles, but at least one must cover this variant.
8885 const bool has_default = model != nullptr && std::any_of(model->default_materials.begin(), model->default_materials.end(),
8886 [&](const std::string &name) {
8887 const Preset *filament = filaments.find_preset(name, false);
8888 return filament != nullptr && filament->is_system &&
8889 is_compatible_with_printer(filaments.get_preset_with_vendor_profile(*filament), active_printer);
8890 });
8891 if (!has_default) {
8892 found = true;
8893 BOOST_LOG_TRIVIAL(error) << "Printer preset \"" << printer.name << "\" (vendor \"" << printer.vendor->name
8894 << "\", model \"" << printer.config.opt_string("printer_model") << "\", variant \""
8895 << printer.config.opt_string("printer_variant")
8896 << "\") has no compatible system filament in its model's \"default_materials\". "
8897 "Add at least one full filament preset name compatible with this printer variant:\n"
8898 << preset_file_uri(printer.file);
8899 }
8900
8901 if (model != nullptr && checked_models.insert(model).second) {
8902 for (const std::string &name : model->default_materials) {
8903 const Preset *filament = filaments.find_preset(name, false);
8904 if (filament == nullptr || !filament->is_system) {
8905 found = true;
8906 BOOST_LOG_TRIVIAL(error) << "Printer model \"" << model->name << "\" (vendor \"" << printer.vendor->name
8907 << "\") names the unknown system filament \"" << name
8908 << "\" in its \"default_materials\":\n" << preset_file_uri(printer.file);
8909 }
8910 }
8911 }
8912
8913 if (printer.config.has("default_filament_profile")) {
8914 for (const std::string &name : printer.config.opt<ConfigOptionStrings>("default_filament_profile")->values) {
8915 // A ";"-separated list can leave an empty trailing segment; formatting noise, not a name.
8916 if (name.empty())
8917 continue;
8918 const Preset *filament = filaments.find_preset(name, false);
8919 if ((filament == nullptr || !filament->is_system) && reported_unknown_profiles.insert(name).second) {
8920 found = true;
8921 BOOST_LOG_TRIVIAL(error) << "Printer preset \"" << printer.name << "\" (vendor \"" << printer.vendor->name
8922 << "\", model \"" << printer.config.opt_string("printer_model") << "\", variant \""
8923 << printer.config.opt_string("printer_variant")
8924 << "\") names the unknown system filament \"" << name
8925 << "\" in its \"default_filament_profile\":\n" << preset_file_uri(printer.file);
8926 }
8927 }
8928 }
8929 }
8930 return found;
8931}
const VendorProfile::PrinterModel * system_printer_model(const Preset &preset)
Definition Preset.cpp:5081
@ ptFFF
Definition Config.hpp:231

References check_printer_default_materials(), Slic3r::VendorProfile::PrinterModel::default_materials, filaments, Slic3r::Preset::is_system, Slic3r::VendorProfile::PrinterModel::name, Slic3r::preset_file_uri(), printers, Slic3r::ptFFF, Slic3r::PresetUtils::system_printer_model(), and Slic3r::ConfigOptionVector< T >::values.

Referenced by check_printer_default_materials(), and has_errors().

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

◆ clear_printer_hold_aliases()

void Slic3r::PresetBundle::clear_printer_hold_aliases ( )
private
3304{
3305 this->prints.m_printer_hold_alias.clear();
3306 this->sla_prints.m_printer_hold_alias.clear();
3307 this->filaments.m_printer_hold_alias.clear();
3308 this->sla_materials.m_printer_hold_alias.clear();
3309 this->printers.m_printer_hold_alias.clear();
3310}

References clear_printer_hold_aliases(), filaments, printers, prints, sla_materials, and sla_prints.

Referenced by clear_printer_hold_aliases(), and install_vendor_cache().

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

◆ commit_vendor_preset()

std::string Slic3r::PresetBundle::commit_vendor_preset ( const CachedPreset & entry,
PresetInstall && resolved,
ConfigSubstitutions && substitutions,
VendorInstall & install )
private
7759{
7760 const std::string& path = install.path;
7761 const std::string& vendor_name = install.vendor_name;
7762 PresetCollection* presets_collection = install.presets;
7763 const VendorProfile* current_vendor_profile = install.vendor_profile;
7764 const std::string& preset_name = entry.name;
7765
7766 log_errors(resolved.errors);
7767 if (resolved.included)
7768 install.include_maps.emplace(preset_name, std::move(*resolved.included));
7769 if (! resolved.reason.empty())
7770 return resolved.reason;
7771
7772 if (resolved.config_only) {
7773 if (resolved.retained)
7774 install.config_maps.emplace(preset_name, std::move(*resolved.retained));
7775 if ((presets_collection->type() == Preset::TYPE_FILAMENT) && (!resolved.filament_id.empty()))
7776 install.filament_id_maps.emplace(preset_name, resolved.filament_id);
7777 return std::string();
7778 }
7779
7780 if (! install.installed_names.insert(preset_name).second) {
7781 ++m_errors;
7782 BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
7783 preset_name << "\" has already been loaded from another Config Bundle.";
7784 return std::string("duplicated defines");
7785 }
7786
7787 // Load the preset into the list of presets, save it to disk.
7788 Preset &loaded = presets_collection->append_preset(std::move(resolved.file_path), preset_name, std::move(resolved.config));
7790 loaded.is_system = true;
7791 loaded.vendor = current_vendor_profile;
7792 loaded.version = current_vendor_profile->config_version;
7793 loaded.description = entry.description;
7794 loaded.setting_id = entry.setting_id;
7795 // Derive the preset setting_id on the fly when a profile ships without one,
7796 // matching scripts/orca_profile_tool.py. Only instantiated presets carry an id;
7797 // non-instantiated base profiles return earlier above. This never
7798 // touches the per-user cloud-sync setting_id written into user .info files.
7799 if (loaded.setting_id.empty() && entry.instantiation == "true")
7800 loaded.setting_id = generate_preset_setting_id(
7801 vendor_name, Preset::get_type_string(presets_collection->type()), preset_name);
7802 loaded.filament_id = resolved.filament_id;
7803 loaded.m_from_orca_filament_lib = install.is_from_lib;
7804 if (presets_collection->type() == Preset::TYPE_FILAMENT) {
7805 if (resolved.filament_id.empty() && "Template" != vendor_name) {
7806 ++m_errors;
7807 BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": can not find filament_id for " << preset_name;
7808 //throw ConfigurationError(format("can not find inherits %1% for %2%", inherits, preset_name));
7809 return "Can not find filament_id for " + preset_name;
7810 }
7811 else {
7812 install.filament_id_maps.emplace(preset_name, resolved.filament_id);
7813 }
7814 }
7815 }
7816
7817 if (resolved.alias.empty())
7818 loaded.alias = preset_name;
7819 else {
7820 loaded.alias = std::move(resolved.alias);
7821 filaments.set_printer_hold_alias(loaded.alias, loaded);
7822 }
7823 loaded.renamed_from = std::move(resolved.renamed_from);
7824 if (! substitutions.empty())
7825 install.substitutions->push_back({
7826 preset_name, presets_collection->type(), PresetConfigSubstitutions::Source::ConfigBundle,
7827 std::string(), std::move(substitutions) });
7828 if (resolved.retained)
7829 install.config_maps.emplace(preset_name, std::move(*resolved.retained));
7830 ++install.count;
7831 //BBS: add config related logs
7832 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << ", got preset " << loaded.name << ", filament_id " << loaded.filament_id
7833 << ", from " << path << "/" << vendor_name << "/" << entry.sub_path;
7834 return std::string();
7835}
int m_errors
Definition PresetBundle.hpp:948
void log_errors(const std::vector< std::string > &errors)
Definition PresetBundle.cpp:7574
static std::string get_type_string(Preset::Type type)
Definition Preset.cpp:590
std::string generate_preset_setting_id(const std::string &vendor, const std::string &type, const std::string &name)
Definition Preset.cpp:608
void install(Class cls)
Definition MacIME.mm:123
@ ConfigBundle
Definition Preset.hpp:538

References Slic3r::Preset::alias, Slic3r::PresetCollection::append_preset(), commit_vendor_preset(), Slic3r::VendorProfile::config_version, Slic3r::PresetConfigSubstitutions::ConfigBundle, Slic3r::CachedPreset::description, Slic3r::Preset::description, Slic3r::Preset::filament_id, filaments, Slic3r::generate_preset_setting_id(), Slic3r::Preset::get_type_string(), Slic3r::CachedPreset::instantiation, Slic3r::Preset::is_system, LoadSystem, log_errors(), m_errors, Slic3r::Preset::m_from_orca_filament_lib, Slic3r::CachedPreset::name, Slic3r::Preset::name, Slic3r::Preset::renamed_from, Slic3r::CachedPreset::setting_id, Slic3r::Preset::setting_id, Slic3r::CachedPreset::sub_path, Slic3r::PresetCollection::type(), Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::vendor, and Slic3r::Preset::version.

Referenced by commit_vendor_preset(), and install_vendor_entries().

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

◆ config_from_gcode()

DynamicPrintConfig Slic3r::PresetBundle::config_from_gcode ( const std::string & path,
ForwardCompatibilitySubstitutionRule compatibility_rule,
ConfigSubstitutions & substitutions ) const
5887{
5888 DynamicPrintConfig config;
5889 config.apply(FullPrintConfig::defaults());
5890 // The config block leaves a few project settings out (filament_colour_type, prime_volume_mode,
5891 // flush_multiplier_fast); those keep this bundle's values rather than falling back to the defaults.
5892 config.apply(this->project_config);
5893 const DynamicPrintConfig base = config;
5894 substitutions = config.load_from_gcode_file(path, compatibility_rule);
5895 // An empty list of choices sets nothing: G-code written by a tool rather than from presets leaves per-extruder
5896 // lists such as nozzle_volume_type empty, and the settings tabs expect a choice per extruder. An empty text
5897 // list, such as filament_multi_colour, is a value of its own and stays.
5898 for (const std::string &key : config.keys())
5899 if (const ConfigOption *opt = config.option(key); opt->type() == coEnums && static_cast<const ConfigOptionVectorBase *>(opt)->size() == 0)
5900 if (const ConfigOption *below = base.option(key); below != nullptr && static_cast<const ConfigOptionVectorBase *>(below)->size() > 0)
5901 config.set_key_value(key, below->clone());
5902 Preset::normalize(config);
5903 // The block holds flush_volumes_matrix already multiplied by the multiplier the slice used, so a
5904 // multiplier of 1 keeps the purge volumes the file was sliced with. G-code from before 2.3.2 held the
5905 // plain matrix and loses a multiplier other than 1.
5906 for (const char *key : { "flush_multiplier", "flush_multiplier_fast" })
5907 if (auto *multiplier = config.option<ConfigOptionFloats>(key))
5908 std::fill(multiplier->values.begin(), multiplier->values.end(), 1.);
5909 return config;
5910}
static void normalize(DynamicPrintConfig &config)
Definition Preset.cpp:524
@ coEnums
Definition Config.hpp:216
ConfigOptionFloatsTempl< false > ConfigOptionFloats
Definition Config.hpp:1015

References Slic3r::ConfigBase::apply(), Slic3r::coEnums, config_from_gcode(), Slic3r::DynamicConfig::keys(), Slic3r::ConfigBase::load_from_gcode_file(), Slic3r::Preset::normalize(), Slic3r::ConfigBase::option(), project_config, Slic3r::DynamicConfig::set_key_value(), and Slic3r::ConfigOptionVectorBase::size().

Referenced by config_from_gcode(), load_config_file(), and Slic3r::GUI::Plater::load_gcode().

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

◆ construct_full_config()

DynamicPrintConfig Slic3r::PresetBundle::construct_full_config ( Preset & in_printer_preset,
Preset & in_print_preset,
const DynamicPrintConfig & project_config,
std::vector< Preset > & in_filament_presets,
bool apply_extruder,
std::optional< std::vector< int > > filament_maps_new,
std::optional< std::vector< int > > filament_volume_maps_new = std::nullopt )
static
202{
203 DynamicPrintConfig &printer_config = in_printer_preset.config;
204 DynamicPrintConfig &print_config = in_print_preset.config;
205
206 DynamicPrintConfig out;
207 out.apply(FullPrintConfig::defaults());
208 out.apply(printer_config);
209 out.apply(print_config);
210 out.apply(project_config);
211 out.apply(in_filament_presets[0].config);
212
213 size_t num_filaments = in_filament_presets.size();
214
215 std::vector<int> filament_maps = out.option<ConfigOptionInts>("filament_map")->values;
216 std::vector<int> filament_volume_maps(num_filaments, (int)nvtStandard);
217
218 ConfigOptionInts* filament_volume_map_opt = out.option<ConfigOptionInts>("filament_volume_map");
219 if (filament_maps_new.has_value())
220 filament_maps = *filament_maps_new;
221 if (filament_volume_maps_new.has_value())
222 filament_volume_maps = *filament_volume_maps_new;
223 else if (filament_volume_map_opt && filament_volume_map_opt->values.size() == num_filaments)
224 filament_volume_maps = filament_volume_map_opt->values;
225
226 // in some middle state, they may be different
227 if (filament_maps.size() != num_filaments) {
228 filament_maps.resize(num_filaments, 1);
229 }
230 if (filament_volume_maps.size() != num_filaments) {
231 filament_volume_maps.resize(num_filaments, nvtStandard);
232 }
233
234 auto *extruder_diameter = dynamic_cast<const ConfigOptionFloats *>(out.option("nozzle_diameter"));
235 // Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector.
236 std::vector<std::string> compatible_printers_condition;
237 std::vector<std::string> compatible_prints_condition;
238 std::vector<std::string> inherits;
239 std::vector<std::string> filament_ids;
240 std::vector<std::string> print_compatible_printers;
241 // BBS: add logic for settings check between different system presets
242 std::vector<std::string> different_settings;
243 std::string different_print_settings, different_printer_settings;
244 compatible_printers_condition.emplace_back(in_print_preset.compatible_printers_condition());
245
246 const ConfigOptionStrings *compatible_printers = print_config.option<ConfigOptionStrings>("compatible_printers", false);
247 if (compatible_printers) print_compatible_printers = compatible_printers->values;
248 // BBS: add logic for settings check between different system presets
249 std::string print_inherits = in_print_preset.inherits();
250 inherits.emplace_back(print_inherits);
251
252 // BBS: update printer config related with variants
253 std::vector<std::vector<NozzleVolumeType>> nozzle_volume_types;
254 int extruder_count = 1, extruder_volume_type_count = 1;
255 bool different_extruder = false;
256 if (apply_extruder) {
257 different_extruder = out.support_different_extruders(extruder_count);
258 extruder_volume_type_count = out.get_extruder_nozzle_volume_count(extruder_count, nozzle_volume_types);
259
260 if ((extruder_count > 1) || different_extruder) {
261 // Orca: keep processing variant_1 before variant_2 here; variant_2 slots are resolved
262 // against the printer id/variant lists as rewritten by the variant_1 pass, and the
263 // composed values depend on that order. Note the order is load-bearing, not correct
264 // in general: the variant_2 pass reads the original full-width arrays through indices
265 // resolved on the shrunk lists, which mis-reads presets whose variant_2 columns differ
266 // per variant (e.g. X2D machine_max_speed_e/machine_max_acceleration_e). The slicing
267 // path composes variant_2 first and is unaffected; changing the order here would alter
268 // long-standing composed values, so any fix must re-baseline them.
269 out.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, printer_options_with_variant_1, "printer_extruder_id", "printer_extruder_variant");
270 out.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, printer_options_with_variant_2, "printer_extruder_id", "printer_extruder_variant", 2);
271 // update print config related with variants
272 out.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, print_options_with_variant, "print_extruder_id", "print_extruder_variant");
273 }
274 }
275
276 if (num_filaments <= 1) {
277 // BBS: update filament config related with variants
278 DynamicPrintConfig filament_config = in_filament_presets[0].config;
279 // Orca: a multi-variant filament resolves its variants on a single-variant printer too.
280 if (apply_extruder && ((extruder_count > 1) || different_extruder || filament_config.has_multi_variant_filament()))
281 filament_config.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[0], (NozzleVolumeType)filament_volume_maps[0]);
282 out.apply(filament_config);
283 compatible_printers_condition.emplace_back(in_filament_presets[0].compatible_printers_condition());
284 compatible_prints_condition.emplace_back(in_filament_presets[0].compatible_prints_condition());
285 std::string filament_inherits = in_filament_presets[0].inherits();
286 inherits.emplace_back(filament_inherits);
287 filament_ids.emplace_back(in_filament_presets[0].filament_id);
288
289 std::vector<int> &filament_self_indice = out.option<ConfigOptionInts>("filament_self_index", true)->values;
290 int index_size = out.option<ConfigOptionStrings>("filament_extruder_variant")->size();
291 filament_self_indice.resize(index_size, 1);
292 } else {
293 std::vector<const DynamicPrintConfig *> filament_configs;
294 std::vector<const Preset *> filament_presets;
295 for (const Preset & preset : in_filament_presets) {
296 filament_presets.emplace_back(&preset);
297 filament_configs.emplace_back(&(preset.config));
298 }
299
300 std::vector<DynamicPrintConfig> filament_temp_configs;
301 filament_temp_configs.resize(num_filaments);
302 for (size_t i = 0; i < num_filaments; ++i) {
303 filament_temp_configs[i] = *(filament_configs[i]);
304 // Orca: a multi-variant filament resolves its variants on a single-variant printer too.
305 if (apply_extruder && ((extruder_count > 1) || different_extruder || filament_temp_configs[i].has_multi_variant_filament()))
306 filament_temp_configs[i].update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[i], (NozzleVolumeType)filament_volume_maps[i]);
307 }
308
309 // loop through options and apply them to the resulting config.
310 std::vector<int> filament_variant_count(num_filaments, 1);
311 for (const t_config_option_key &key : in_filament_presets[0].config.keys()) {
312 if (key == "compatible_prints" || key == "compatible_printers") continue;
313 // Get a destination option.
314 ConfigOption *opt_dst = out.option(key, false);
315 if (opt_dst->is_scalar()) {
316 // Get an option, do not create if it does not exist.
317 const ConfigOption *opt_src = filament_temp_configs.front().option(key);
318 if (opt_src != nullptr) opt_dst->set(opt_src);
319 } else {
320 // BBS
321 ConfigOptionVectorBase *opt_vec_dst = static_cast<ConfigOptionVectorBase *>(opt_dst);
322 {
323 if (apply_extruder) {
324 std::vector<const ConfigOption *> filament_opts(num_filaments, nullptr);
325 // Setting a vector value from all filament_configs.
326 for (size_t i = 0; i < filament_opts.size(); ++i) filament_opts[i] = filament_temp_configs[i].option(key);
327 opt_vec_dst->set(filament_opts);
328 } else {
329 for (size_t i = 0; i < num_filaments; ++i) {
330 const ConfigOptionVectorBase *filament_option = static_cast<const ConfigOptionVectorBase *>(filament_temp_configs[i].option(key));
331 if (i == 0)
332 opt_vec_dst->set(filament_option);
333 else
334 opt_vec_dst->append(filament_option);
335
336 if (key == "filament_extruder_variant") filament_variant_count[i] = filament_option->size();
337 }
338 }
339 }
340 }
341 }
342
343 if (!apply_extruder) {
344 // append filament_self_index
345 std::vector<int> &filament_self_indice = out.option<ConfigOptionInts>("filament_self_index", true)->values;
346 int index_size = out.option<ConfigOptionStrings>("filament_extruder_variant")->size();
347 filament_self_indice.resize(index_size, 1);
348 int k = 0;
349 for (size_t i = 0; i < num_filaments; i++) {
350 for (size_t j = 0; j < filament_variant_count[i]; j++) { filament_self_indice[k++] = i + 1; }
351 }
352 }
353 }
354
355 // These value types clash between the print and filament profiles. They should be renamed.
356 out.erase("compatible_prints");
357 out.erase("compatible_prints_condition");
358 out.erase("compatible_printers");
359 out.erase("compatible_printers_condition");
360 out.erase("inherits");
361 // BBS: add logic for settings check between different system presets
362 out.erase("different_settings_to_system");
363
364 static const char *keys[] = {"support_filament", "support_interface_filament"};
365 for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) {
366 std::string key = std::string(keys[i]);
367 auto *opt = dynamic_cast<ConfigOptionInt *>(out.option(key, false));
368 assert(opt != nullptr);
369 opt->value = boost::algorithm::clamp<int>(opt->value, 0, int(num_filaments));
370 }
371
372 std::vector<std::string> filamnet_preset_names;
373 for (auto preset : in_filament_presets) {
374 filamnet_preset_names.emplace_back(preset.name);
375 }
376 out.option<ConfigOptionString>("print_settings_id", true)->value = in_print_preset.name;
377 out.option<ConfigOptionStrings>("filament_settings_id", true)->values = filamnet_preset_names;
378 out.option<ConfigOptionString>("printer_settings_id", true)->value = in_printer_preset.name;
379 out.option<ConfigOptionStrings>("filament_ids", true)->values = filament_ids;
380 out.option<ConfigOptionInts>("filament_map", true)->values = filament_maps;
381 out.option<ConfigOptionInts>("filament_volume_map", true)->values = filament_volume_maps;
382
383 auto add_if_some_non_empty = [&out](std::vector<std::string> &&values, const std::string &key) {
384 bool nonempty = false;
385 for (const std::string &v : values)
386 if (!v.empty()) {
387 nonempty = true;
388 break;
389 }
390 if (nonempty) out.set_key_value(key, new ConfigOptionStrings(std::move(values)));
391 };
392 add_if_some_non_empty(std::move(compatible_printers_condition), "compatible_machine_expression_group");
393 add_if_some_non_empty(std::move(compatible_prints_condition), "compatible_process_expression_group");
394 add_if_some_non_empty(std::move(inherits), "inherits_group");
395 // BBS: add logic for settings check between different system presets
396 //add_if_some_non_empty(std::move(different_settings), "different_settings_to_system");
397 add_if_some_non_empty(std::move(print_compatible_printers), "print_compatible_printers");
398
399 out.option<ConfigOptionEnumGeneric>("printer_technology", true)->value = ptFFF;
400 return out;
401}
NozzleVolumeType
Definition PrintConfig.hpp:618
@ nvtStandard
Definition PrintConfig.hpp:619
std::set< std::string > printer_options_with_variant_1
Definition PrintConfig.cpp:10236
std::string t_config_option_key
Definition Config.hpp:96
std::set< std::string > printer_options_with_variant_2
Definition PrintConfig.cpp:10270
zaa_minimize_perimeter_height ConfigOptionString
Definition PrintConfig.hpp:1702
zaa_minimize_perimeter_height filament_ids((ConfigOptionStrings, filament_colour))((ConfigOptionStrings
std::set< std::string > filament_options_with_variant
Definition PrintConfig.cpp:10150
std::set< std::string > print_options_with_variant
Definition PrintConfig.cpp:10102

References Slic3r::ConfigOptionVectorBase::append(), Slic3r::ConfigBase::apply(), Slic3r::Preset::compatible_printers_condition(), Slic3r::Preset::config, Slic3r::DynamicConfig::erase(), Slic3r::filament_ids(), Slic3r::filament_options_with_variant, filament_presets, Slic3r::DynamicPrintConfig::get_extruder_nozzle_volume_count(), Slic3r::DynamicPrintConfig::has_multi_variant_filament(), Slic3r::Preset::inherits(), Slic3r::ConfigOption::is_scalar(), Slic3r::Preset::name, Slic3r::nvtStandard, Slic3r::ConfigBase::option(), Slic3r::print_options_with_variant, Slic3r::printer_options_with_variant_1, Slic3r::printer_options_with_variant_2, project_config, Slic3r::ptFFF, Slic3r::ConfigOption::set(), Slic3r::ConfigOptionVectorBase::set(), Slic3r::DynamicConfig::set_key_value(), Slic3r::ConfigOptionVectorBase::size(), Slic3r::DynamicPrintConfig::support_different_extruders(), Slic3r::DynamicPrintConfig::update_values_to_printer_extruders(), Slic3r::ConfigOptionVector< T >::values, and Slic3r::ConfigOptionVector< int >::values.

Referenced by Slic3r::GUI::CalibUtils::calib_generic_auto_pa_cali().

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

◆ convert_filament_preset_name()

void Slic3r::PresetBundle::convert_filament_preset_name ( const std::string & machine_name,
std::string & filament_name )
static
6108{
6109 auto machine_iter = filament_preset_convert.find(machine_name);
6110 if (machine_iter != filament_preset_convert.end())
6111 {
6112 std::map<std::string, std::string>& filament_maps = machine_iter->second;
6113 auto filament_iter = filament_maps.find(filament_name);
6114 if (filament_iter != filament_maps.end())
6115 {
6116 filament_name = filament_iter->second;
6117 }
6118 }
6119}
static std::map< std::string, std::map< std::string, std::string > > filament_preset_convert
Definition PresetBundle.cpp:5962

References convert_filament_preset_name(), and Slic3r::filament_preset_convert.

Referenced by convert_filament_preset_name(), load_config_file_config(), and Slic3r::CLI::run().

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

◆ copy_files()

void Slic3r::PresetBundle::copy_files ( const std::string & from)
861{
862 boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
863 // list of searched paths based on current directory system in setup_directories()
864 // do not copy cache and snapshots
865 boost::filesystem::path from_data_dir = boost::filesystem::path(from);
866 //BBS: change directoties by design
867 std::initializer_list<boost::filesystem::path> from_dirs= {
868 //from_data_dir / "vendor",
869 // Store the print/filament/printer presets at the same location as the upstream Slic3r.
870 from_data_dir / PRESET_PRINT_NAME,
871 from_data_dir / PRESET_FILAMENT_NAME,
872 from_data_dir / PRESET_PRINTER_NAME
873 };
874 // copy recursively all files
875 //BBS: change directoties by design
876 for (const boost::filesystem::path& from_dir : from_dirs) {
877 copy_dir(from_dir, data_dir /"old"/from_dir.filename());
878 }
879}
#define PRESET_PRINTER_NAME
Definition Preset.hpp:35
#define PRESET_PRINT_NAME
Definition Preset.hpp:34
#define PRESET_FILAMENT_NAME
Definition Preset.hpp:33
static void copy_dir(const boost::filesystem::path &from_dir, const boost::filesystem::path &to_dir)
Definition PresetBundle.cpp:840

References Slic3r::copy_dir(), copy_files(), Slic3r::data_dir(), PRESET_FILAMENT_NAME, PRESET_PRINT_NAME, and PRESET_PRINTER_NAME.

Referenced by copy_files().

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

◆ error_count()

int Slic3r::PresetBundle::error_count ( ) const
inline
705{ return m_errors; }

References m_errors.

◆ export_current_configs()

std::vector< std::string > Slic3r::PresetBundle::export_current_configs ( const std::string & path,
std::function< int(std::string const &)> override_confirm,
bool include_modify,
bool export_system_settings = false )
8701{
8702 const Preset &print_preset = include_modify ? prints.get_edited_preset() : prints.get_selected_preset();
8703 const Preset &printer_preset = include_modify ? printers.get_edited_preset() : printers.get_selected_preset();
8704 std::set<Preset const *> presets { &print_preset, &printer_preset };
8705 for (auto &f : filament_presets) {
8706 auto filament_preset = filaments.find_preset(f, include_modify);
8707 if (filament_preset) presets.insert(filament_preset);
8708 }
8709
8710 int overwrite = 0;
8711 std::vector<std::string> result;
8712 for (auto preset : presets) {
8713 if ((preset->is_system && !export_system_settings) || preset->is_default)
8714 continue;
8715 std::string file = path + "/" + preset->name + ".json";
8716 if (overwrite == 0) overwrite = 1;
8717 if (boost::filesystem::exists(file) && overwrite < 2) {
8718 overwrite = override_confirm(preset->name);
8719 if (overwrite == 0 || overwrite == 2)
8720 continue;
8721 }
8722 preset->config.save_to_json(file, preset->name, "", preset->version.to_string());
8723 result.push_back(file);
8724 }
8725 return result;
8726}

References Slic3r::Preset::config, export_current_configs(), Slic3r::f(), filament_presets, filaments, Slic3r::Preset::is_default, Slic3r::Preset::is_system, Slic3r::Preset::name, printers, prints, Slic3r::ConfigBase::save_to_json(), Slic3r::Semver::to_string(), and Slic3r::Preset::version.

Referenced by export_current_configs().

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

◆ export_selections()

void Slic3r::PresetBundle::export_selections ( AppConfig & config)
4233{
4235 return;
4236 assert(this->printers.get_edited_preset().printer_technology() != ptFFF || filament_presets.size() >= 1);
4237 //assert(this->printers.get_edited_preset().printer_technology() != ptFFF || filament_presets.size() > 1 || filaments.get_selected_preset_name() == filament_presets.front());
4238 config.clear_section("presets");
4239 auto printer_name = printers.get_selected_preset_name();
4240 config.set("presets", PRESET_PRINTER_NAME, printer_name);
4241
4242 // Don't persist settings for the built-in "Default Printer" placeholder —
4243 // it's only the initial state before a real printer is loaded/selected.
4244 // Also clean up any stale entry that other code paths (e.g. bed type change)
4245 // may have created for "Default Printer".
4246 if (printer_name == "Default Printer") {
4247 config.clear_printer_settings("Default Printer");
4248 return;
4249 }
4250
4251 config.clear_printer_settings(printer_name);
4252 config.set_printer_setting(printer_name, PRESET_PRINTER_NAME, printer_name);
4253 config.set_printer_setting(printer_name, PRESET_PRINT_NAME, prints.get_selected_preset_name());
4254 config.set_printer_setting(printer_name, PRESET_FILAMENT_NAME, filament_presets.front());
4255 config.set_printer_setting(printer_name, "curr_bed_type", config.get("curr_bed_type"));
4256 for (unsigned i = 1; i < filament_presets.size(); ++i) {
4257 char name[64];
4258 assert(!filament_presets[i].empty());
4259 sprintf(name, "filament_%02u", i);
4260 config.set_printer_setting(printer_name, name, filament_presets[i]);
4261 }
4262 // Load project config data into app config
4263 CNumericLocalesSetter locales_setter;
4264 std::string filament_colors = boost::algorithm::join(project_config.option<ConfigOptionStrings>("filament_colour")->values, ",");
4265 config.set_printer_setting(printer_name, "filament_colors", filament_colors);
4266
4267 // Load filament multi color data into app config
4268 std::string filament_multi_colors = boost::algorithm::join(project_config.option<ConfigOptionStrings>("filament_multi_colour")->values, ",");
4269 config.set_printer_setting(printer_name, "filament_multi_colors", filament_multi_colors);
4270
4271 // Load filament color type data into app config
4272 std::string filament_color_types = boost::algorithm::join(project_config.option<ConfigOptionStrings>("filament_colour_type")->values, ",");
4273 config.set_printer_setting(printer_name, "filament_color_types", filament_color_types);
4274
4275 // Load ams counts data into app config
4276 std::string extruder_ams_count_str = boost::algorithm::join(save_extruder_ams_count_to_string(this->extruder_ams_counts), ",");
4277 config.set_printer_setting(printer_name, "extruder_ams_count", extruder_ams_count_str);
4278
4279 std::string flush_volumes_matrix = boost::algorithm::join(project_config.option<ConfigOptionFloats>("flush_volumes_matrix")->values |
4280 boost::adaptors::transformed(static_cast<std::string (*)(double)>(std::to_string)),
4281 "|");
4282 config.set_printer_setting(printer_name, "flush_volumes_matrix", flush_volumes_matrix);
4283 std::string flush_volumes_vector = boost::algorithm::join(project_config.option<ConfigOptionFloats>("flush_volumes_vector")->values |
4284 boost::adaptors::transformed(static_cast<std::string (*)(double)>(std::to_string)),
4285 "|");
4286 config.set_printer_setting(printer_name, "flush_volumes_vector", flush_volumes_vector);
4287
4288
4289 std::string flush_multiplier_str = boost::algorithm::join(project_config.option<ConfigOptionFloats>("flush_multiplier")->values |
4290 boost::adaptors::transformed(static_cast<std::string (*)(double)>(std::to_string)),
4291 "|");
4292 config.set_printer_setting(printer_name, "flush_multiplier", flush_multiplier_str);
4293
4294 // Mixed-color filament metadata goes into the per-printer snapshot next to the filament list
4295 // it indexes (see load_mixed_filament_settings). Bools are ','-joined and the component, ratio
4296 // and range strings '|'-joined; the gradient curve is escaped instead, as it contains '|'.
4297 auto join_bools = [](const std::vector<unsigned char> &vals) {
4298 std::string s;
4299 for (size_t i = 0; i < vals.size(); ++i) {
4300 if (i > 0) s += ",";
4301 s += (vals[i] ? "1" : "0");
4302 }
4303 return s;
4304 };
4305 if (auto *opt = project_config.option<ConfigOptionBools>("filament_is_mixed"))
4306 config.set_printer_setting(printer_name, "filament_is_mixed", join_bools(opt->values));
4307 if (auto *opt = project_config.option<ConfigOptionStrings>("filament_mixed_components"))
4308 config.set_printer_setting(printer_name, "filament_mixed_components", boost::algorithm::join(opt->values, "|"));
4309 if (auto *opt = project_config.option<ConfigOptionStrings>("filament_mixed_sublayer_ratios"))
4310 config.set_printer_setting(printer_name, "filament_mixed_sublayer_ratios", boost::algorithm::join(opt->values, "|"));
4311 if (auto *opt = project_config.option<ConfigOptionBools>("filament_mixed_gradient"))
4312 config.set_printer_setting(printer_name, "filament_mixed_gradient", join_bools(opt->values));
4313 if (auto *opt = project_config.option<ConfigOptionStrings>("filament_mixed_gradient_range"))
4314 config.set_printer_setting(printer_name, "filament_mixed_gradient_range", boost::algorithm::join(opt->values, "|"));
4315 if (auto *opt = project_config.option<ConfigOptionStrings>("filament_mixed_gradient_curve"))
4316 config.set_printer_setting(printer_name, "filament_mixed_gradient_curve", escape_strings_cstyle(opt->values));
4317 if (auto *opt = project_config.option<ConfigOptionBools>("filament_mixed_gradient_per_part"))
4318 config.set_printer_setting(printer_name, "filament_mixed_gradient_per_part", join_bools(opt->values));
4319
4320 // BBS
4321 //config.set("presets", "sla_print", sla_prints.get_selected_preset_name());
4322 //config.set("presets", "sla_material", sla_materials.get_selected_preset_name());
4323 //config.set("presets", "physical_printer", physical_printers.get_selected_full_printer_name());
4324 //BBS: add config related log
4325 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": printer %1%, print %2%, filaments[0] %3% ")%printers.get_selected_preset_name() % prints.get_selected_preset_name() %filament_presets[0];
4326}
std::vector< double > values
Definition Config.hpp:418
std::vector< std::map< int, int > > extruder_ams_counts
Definition PresetBundle.hpp:512
int m_selection_export_blockers
Definition PresetBundle.hpp:951
ConfigOptionBoolsTempl< false > ConfigOptionBools
Definition Config.hpp:2066
std::vector< std::string > save_extruder_ams_count_to_string(const std::vector< std::map< int, int > > &extruder_ams_count)
Definition PrintConfig.cpp:891
zaa_minimize_perimeter_height flush_volumes_matrix((ConfigOptionFloats, flush_volumes_vector))((ConfigOptionFloat
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:273
std::string escape_strings_cstyle(const std::vector< std::string > &strs)
Definition Config.cpp:99

References Slic3r::AppConfig::clear_printer_settings(), Slic3r::AppConfig::clear_section(), Slic3r::empty(), Slic3r::escape_strings_cstyle(), export_selections(), extruder_ams_counts, filament_presets, Slic3r::flush_volumes_matrix(), Slic3r::AppConfig::get(), m_selection_export_blockers, PRESET_FILAMENT_NAME, PRESET_PRINT_NAME, PRESET_PRINTER_NAME, printers, prints, project_config, Slic3r::ptFFF, Slic3r::save_extruder_ams_count_to_string(), Slic3r::AppConfig::set(), Slic3r::AppConfig::set_printer_setting(), and Slic3r::ConfigOptionVector< T >::values.

Referenced by Slic3r::GUI::ConfigWizard::priv::apply_config(), apply_vendor_config(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::bind_filament_target(), export_selections(), and Slic3r::GUI::GuideFrame::run().

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

◆ find_preset_vendor()

std::string Slic3r::PresetBundle::find_preset_vendor ( const std::string & preset_name,
Preset::Type type )
static
404{
405 // Get the resources preset directory (contains all bundled vendor profiles)
406 fs::path system_dir = fs::path(Slic3r::resources_dir()) / PRESET_PROFILES_DIR;
407 if (!fs::exists(system_dir) || !fs::is_directory(system_dir)) {
408 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " Resources profiles directory does not exist: " << system_dir.string();
409 return "";
410 }
411
412 // Determine which preset list key to search for based on type
413 const char* preset_list_key = nullptr;
414 if (type == Preset::Type::TYPE_PRINT)
415 preset_list_key = BBL_JSON_KEY_PROCESS_LIST;
416 else if (type == Preset::Type::TYPE_FILAMENT)
417 preset_list_key = BBL_JSON_KEY_FILAMENT_LIST;
418 else if (type == Preset::Type::TYPE_PRINTER)
419 preset_list_key = BBL_JSON_KEY_MACHINE_LIST;
420 else {
421 // Not supported for other types
422 return "";
423 }
424
425 // A vendor is named by its profile or, where the build ships preset caches
426 // instead of the raw profile JSONs, by its cache alone.
427 for (const std::string& vendor_name : vendor_names_in(system_dir)) {
428 const fs::path vendor_json = system_dir / (vendor_name + ".json");
429 if (! fs::exists(vendor_json)) {
430 if (VendorCacheFile::carries_preset((system_dir / (vendor_name + ".opc")).string(), vendor_name, type, preset_name)) {
431 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Found preset " << preset_name
432 << " in vendor cache " << vendor_name;
433 return vendor_name;
434 }
435 continue;
436 }
437 const std::string vendor_file = vendor_json.string();
438 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Checking vendor: " << vendor_file;
439
440 try {
441 // Load and parse the vendor JSON file
442 boost::nowide::ifstream ifs(vendor_file);
443 json j;
444 ifs >> j;
445
446 // Check if the preset list key exists
447 if (!j.contains(preset_list_key))
448 continue;
449
450 auto& preset_list = j[preset_list_key];
451 if (!preset_list.is_array())
452 continue;
453
454 // Search for the preset in the list
455 for (auto& preset_entry : preset_list) {
456 if (!preset_entry.is_object())
457 continue;
458
459 // Get the preset name
460 std::string p_name;
461 if (preset_entry.contains(BBL_JSON_KEY_NAME) && preset_entry[BBL_JSON_KEY_NAME].is_string())
462 p_name = preset_entry[BBL_JSON_KEY_NAME].get<std::string>();
463
464 if (p_name != preset_name)
465 continue;
466
467 // Found the preset! Get the vendor name and install the entire bundle
468 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Found preset " << p_name
469 << " in vendor bundle " << vendor_name;
470
471 return vendor_name;
472 }
473 }
474 catch (const std::exception &e) {
475 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to find vendor name for " << preset_name << ": " << e.what();
476 return "";
477 }
478 }
479
480 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Could not find vendor for preset " << preset_name;
481 return "";
482}
#define BBL_JSON_KEY_PROCESS_LIST
Definition Preset.hpp:62
#define BBL_JSON_KEY_FILAMENT_LIST
Definition Preset.hpp:64
#define BBL_JSON_KEY_MACHINE_LIST
Definition Preset.hpp:65
#define BBL_JSON_KEY_NAME
Definition Preset.hpp:58
#define PRESET_PROFILES_DIR
Definition Preset.hpp:38
static bool carries_preset(const std::string &path, const std::string &vendor_name, Preset::Type type, const std::string &preset_name)
Definition PresetCacheFormat.cpp:569
nlohmann::json json
Definition AssembleList.cpp:42
const std::string & resources_dir()
Definition utils.cpp:296
std::set< std::string > vendor_names_in(const boost::filesystem::path &dir)
Definition utils.cpp:2005

References BBL_JSON_KEY_FILAMENT_LIST, BBL_JSON_KEY_MACHINE_LIST, BBL_JSON_KEY_NAME, BBL_JSON_KEY_PROCESS_LIST, Slic3r::VendorCacheFile::carries_preset(), PRESET_PROFILES_DIR, Slic3r::resources_dir(), Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::TYPE_PRINT, Slic3r::Preset::TYPE_PRINTER, and Slic3r::vendor_names_in().

Referenced by Slic3r::GUI::GUI_App::add_pending_vendor_preset(), and resolve_system_preset().

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

◆ full_config()

DynamicPrintConfig Slic3r::PresetBundle::full_config ( bool apply_extruder = true,
std::optional< std::vector< int > > filament_maps = std::nullopt,
std::optional< std::vector< int > > filament_volume_maps = std::nullopt ) const
5428{
5429 return (this->printers.get_edited_preset().printer_technology() == ptFFF) ?
5430 this->full_fff_config(apply_extruder, filament_maps, filament_volume_maps) :
5431 this->full_sla_config();
5432}
DynamicPrintConfig full_fff_config(bool apply_extruder, std::optional< std::vector< int > > filament_maps=std::nullopt, std::optional< std::vector< int > > filament_volume_maps=std::nullopt) const
Definition PresetBundle.cpp:5498
DynamicPrintConfig full_sla_config() const
Definition PresetBundle.cpp:5812

References full_config(), full_fff_config(), full_sla_config(), printers, and Slic3r::ptFFF.

Referenced by Slic3r::GUI::Plater::_calib_pa_pattern_gen_gcode(), Slic3r::GUI::_get_used_nozzle_idxes(), Slic3r::GUI::PublishSettingsDialog::build_option_model(), Slic3r::GUI::collect_imex_warnings(), full_config(), get_full_flush_matrix(), Slic3r::GUI::PartPlate::imex_wipe_tower_hull(), Slic3r::GUI::Plater::load_gcode(), Slic3r::GUI::manuallySetNozzleCount(), Slic3r::GUI::Plater::priv::on_select_bed_type(), Slic3r::GUI::s_get_slicing_extuder_nozzles(), and anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_config().

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

◆ full_config_secure()

DynamicPrintConfig Slic3r::PresetBundle::full_config_secure ( std::optional< std::vector< int > > filament_maps = std::nullopt) const
5435{
5436 DynamicPrintConfig config = this->full_fff_config(false, filament_maps);
5437 //FIXME legacy, the keys should not be there after conversion to a Physical Printer profile.
5438 config.erase("print_host");
5439 config.erase("print_host_webui");
5440 config.erase("printhost_apikey");
5441 config.erase("printhost_cafile");
5442 config.erase("printhost_user");
5443 config.erase("printhost_password");
5444 config.erase("printhost_port");
5445 return config;
5446}

References Slic3r::DynamicConfig::erase(), full_config_secure(), and full_fff_config().

Referenced by full_config_secure().

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

◆ full_fff_config()

DynamicPrintConfig Slic3r::PresetBundle::full_fff_config ( bool apply_extruder,
std::optional< std::vector< int > > filament_maps = std::nullopt,
std::optional< std::vector< int > > filament_volume_maps = std::nullopt ) const
private
5499{
5500 DynamicPrintConfig out;
5501 out.apply(FullPrintConfig::defaults());
5502 out.apply(this->prints.get_edited_preset().config);
5503 // Add the default filament preset to have the "filament_preset_id" defined.
5504 out.apply(this->filaments.default_preset().config);
5505 out.apply(this->printers.get_edited_preset().config);
5506 out.apply(this->project_config);
5507
5508 // BBS
5509 size_t num_filaments = this->filament_presets.size();
5510
5511 std::vector<int> filament_maps = out.option<ConfigOptionInts>("filament_map")->values;
5512 std::vector<int> filament_volume_maps(num_filaments, (int)nvtStandard);
5513
5514 ConfigOptionInts* filament_volume_map_opt = out.option<ConfigOptionInts>("filament_volume_map");
5515 if (filament_maps_new.has_value())
5516 filament_maps = *filament_maps_new;
5517 if (filament_volume_maps_new.has_value()) {
5518 filament_volume_maps = *filament_volume_maps_new;
5519 out.option<ConfigOptionInts>("filament_volume_map", true)->values = filament_volume_maps;
5520 }
5521 else if (filament_volume_map_opt && filament_volume_map_opt->values.size() == num_filaments)
5522 filament_volume_maps = filament_volume_map_opt->values;
5523 //in some middle state, they may be different
5524 if (filament_maps.size() != num_filaments) {
5525 filament_maps.resize(num_filaments, 1);
5526 }
5527 else {
5528 assert(filament_maps.size() == num_filaments);
5529 }
5530 if (filament_volume_maps.size() != num_filaments) {
5531 filament_volume_maps.resize(num_filaments, nvtStandard);
5532 }
5533
5534 auto* extruder_diameter = dynamic_cast<const ConfigOptionFloats*>(out.option("nozzle_diameter"));
5535 // Collect the "compatible_printers_condition" and "inherits" values over all presets (print, filaments, printers) into a single vector.
5536 std::vector<std::string> compatible_printers_condition;
5537 std::vector<std::string> compatible_prints_condition;
5538 std::vector<std::string> inherits;
5539 std::vector<std::string> filament_ids;
5540 std::vector<std::string> print_compatible_printers;
5541 //BBS: add logic for settings check between different system presets
5542 std::vector<std::string> different_settings;
5543 std::string different_print_settings, different_printer_settings;
5544 compatible_printers_condition.emplace_back(this->prints.get_edited_preset().compatible_printers_condition());
5545
5546 const ConfigOptionStrings* compatible_printers = (const_cast<PresetBundle*>(this))->prints.get_edited_preset().config.option<ConfigOptionStrings>("compatible_printers", false);
5547 if (compatible_printers)
5548 print_compatible_printers = compatible_printers->values;
5549 //BBS: add logic for settings check between different system presets
5550 std::string print_inherits = this->prints.get_edited_preset().inherits();
5551 inherits .emplace_back(print_inherits);
5552 const Preset* print_parent_preset = this->prints.get_selected_preset_parent();
5553 if (print_parent_preset) {
5554 std::vector<std::string> dirty_options = this->prints.dirty_options_without_option_list(&(this->prints.get_edited_preset()), print_parent_preset, ignore_settings_list, false);
5555 if (!dirty_options.empty()) {
5556 different_print_settings = Slic3r::escape_strings_cstyle(dirty_options);
5557 }
5558 }
5559 different_settings.emplace_back(different_print_settings);
5560
5561 //BBS: update printer config related with variants
5562 std::vector<std::vector<NozzleVolumeType>> nozzle_volume_types;
5563 int extruder_count = 1, extruder_volume_type_count = 1;
5564 bool different_extruder = false;
5565 if (apply_extruder) {
5566 different_extruder = out.support_different_extruders(extruder_count);
5567 extruder_volume_type_count = out.get_extruder_nozzle_volume_count(extruder_count, nozzle_volume_types);
5568
5569 if ((extruder_count > 1) || different_extruder) {
5570 // Orca: keep processing variant_1 before variant_2 here; variant_2 slots are resolved
5571 // against the printer id/variant lists as rewritten by the variant_1 pass, and the
5572 // composed values depend on that order. Note the order is load-bearing, not correct
5573 // in general: the variant_2 pass reads the original full-width arrays through indices
5574 // resolved on the shrunk lists, which mis-reads presets whose variant_2 columns differ
5575 // per variant (e.g. X2D machine_max_speed_e/machine_max_acceleration_e). The slicing
5576 // path composes variant_2 first and is unaffected; changing the order here would alter
5577 // long-standing composed values, so any fix must re-baseline them.
5578 out.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, printer_options_with_variant_1, "printer_extruder_id", "printer_extruder_variant");
5579 out.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, printer_options_with_variant_2, "printer_extruder_id", "printer_extruder_variant", 2);
5580 //update print config related with variants
5581 out.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, print_options_with_variant, "print_extruder_id", "print_extruder_variant");
5582 }
5583 }
5584
5585 if (num_filaments <= 1) {
5586 //BBS: update filament config related with variants
5587 DynamicPrintConfig filament_config = this->filaments.get_edited_preset().config;
5588 // Orca: a multi-variant filament resolves its variants on a single-variant printer too.
5589 if (apply_extruder && ((extruder_count > 1) || different_extruder || filament_config.has_multi_variant_filament()))
5590 filament_config.update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[0], (NozzleVolumeType)filament_volume_maps[0]);
5591 out.apply(filament_config);
5592 compatible_printers_condition.emplace_back(this->filaments.get_edited_preset().compatible_printers_condition());
5593 compatible_prints_condition .emplace_back(this->filaments.get_edited_preset().compatible_prints_condition());
5594 //BBS: add logic for settings check between different system presets
5595 //std::string filament_inherits = this->filaments.get_edited_preset().inherits();
5596 std::string current_preset_name = this->filament_presets[0];
5597 const Preset* preset = this->filaments.find_preset(current_preset_name, true);
5598 std::string filament_inherits = preset->inherits();
5599 inherits .emplace_back(filament_inherits);
5600 filament_ids.emplace_back(this->filaments.get_edited_preset().filament_id);
5601
5602 std::string different_filament_settings;
5603 const Preset* filament_parent_preset = this->filaments.get_selected_preset_parent();
5604 if (filament_parent_preset) {
5605 std::vector<std::string> dirty_options = this->filaments.dirty_options_without_option_list(&(this->filaments.get_edited_preset()), filament_parent_preset, ignore_settings_list, false);
5606 if (!dirty_options.empty()) {
5607 different_filament_settings = Slic3r::escape_strings_cstyle(dirty_options);
5608 }
5609 }
5610
5611 different_settings.emplace_back(different_filament_settings);
5612
5613 std::vector<int>& filament_self_indice = out.option<ConfigOptionInts>("filament_self_index", true)->values;
5614 int index_size = out.option<ConfigOptionStrings>("filament_extruder_variant")->size();
5615 filament_self_indice.resize(index_size, 1);
5616 } else {
5617 // Retrieve filament presets and build a single config object for them.
5618 // First collect the filament configurations based on the user selection of this->filament_presets.
5619 // Here this->filaments.find_preset() and this->filaments.first_visible() return the edited copy of the preset if active.
5620 std::vector<const DynamicPrintConfig*> filament_configs;
5621 std::vector<const Preset*> filament_presets;
5622 for (const std::string& filament_preset_name : this->filament_presets) {
5623 const Preset* preset = this->filaments.find_preset(filament_preset_name, true);
5624 filament_presets.emplace_back(preset);
5625 filament_configs.emplace_back(&(preset->config));
5626 }
5627 while (filament_configs.size() < num_filaments) {
5628 const Preset* preset = &this->filaments.first_visible();
5629 filament_presets.emplace_back(preset);
5630 filament_configs.emplace_back(&(preset->config));
5631 }
5632 for (int index = 0; index < num_filaments; index++) {
5633 const DynamicPrintConfig *cfg = filament_configs[index];
5634 const Preset *preset = filament_presets[index];
5635 // The compatible_prints/printers_condition() returns a reference to configuration key, which may not yet exist.
5636 DynamicPrintConfig &cfg_rw = *const_cast<DynamicPrintConfig*>(cfg);
5637 compatible_printers_condition.emplace_back(Preset::compatible_printers_condition(cfg_rw));
5638 compatible_prints_condition .emplace_back(Preset::compatible_prints_condition(cfg_rw));
5639
5640 //BBS: add logic for settings check between different system presets
5641 std::string filament_inherits = Preset::inherits(cfg_rw);
5642 inherits .emplace_back(filament_inherits);
5643 filament_ids.emplace_back(preset->filament_id);
5644 std::string different_filament_settings;
5645
5646 const Preset* filament_parent_preset = nullptr;
5647 if (preset->is_system || preset->is_default) {
5648 bool is_selected = this->filaments.get_selected_preset_name() == preset->name;
5649 if (is_selected) {
5650 //use the real preset
5651 filament_parent_preset = const_cast<PresetBundle*>(this)->filaments.find_preset(preset->name, false, true);
5652 }
5653 else {
5654 filament_parent_preset = preset;
5655 }
5656 }
5657 else if (!filament_inherits.empty())
5658 filament_parent_preset = const_cast<PresetBundle*>(this)->filaments.find_preset(filament_inherits, false, true);
5659
5660 if (filament_parent_preset) {
5661 std::vector<std::string> dirty_options = cfg_rw.diff(filament_parent_preset->config);
5662 if (!dirty_options.empty()) {
5663 auto iter = dirty_options.begin();
5664 while (iter != dirty_options.end()) {
5665 if (ignore_settings_list.find(*iter) != ignore_settings_list.end()) {
5666 iter = dirty_options.erase(iter);
5667 }
5668 else {
5669 ++iter;
5670 }
5671 }
5672 different_filament_settings = Slic3r::escape_strings_cstyle(dirty_options);
5673 }
5674 }
5675
5676 different_settings.emplace_back(different_filament_settings);
5677 }
5678
5679 std::vector<DynamicPrintConfig> filament_temp_configs;
5680 filament_temp_configs.resize(num_filaments);
5681 for (size_t i = 0; i < num_filaments; ++i) {
5682 filament_temp_configs[i] = *(filament_configs[i]);
5683 // Orca: a multi-variant filament resolves its variants on a single-variant printer too.
5684 if (apply_extruder && ((extruder_count > 1) || different_extruder || filament_temp_configs[i].has_multi_variant_filament()))
5685 filament_temp_configs[i].update_values_to_printer_extruders(out, extruder_count, extruder_volume_type_count, nozzle_volume_types, filament_options_with_variant, "", "filament_extruder_variant", 1, filament_maps[i], (NozzleVolumeType)filament_volume_maps[i]);
5686 }
5687
5688 // loop through options and apply them to the resulting config.
5689 std::vector<int> filament_variant_count(num_filaments, 1);
5690 for (const t_config_option_key &key : this->filaments.default_preset().config.keys()) {
5691 if (key == "compatible_prints" || key == "compatible_printers")
5692 continue;
5693 // Get a destination option.
5694 ConfigOption *opt_dst = out.option(key, false);
5695 if (opt_dst->is_scalar()) {
5696 // Get an option, do not create if it does not exist.
5697 const ConfigOption *opt_src = filament_temp_configs.front().option(key);
5698 if (opt_src != nullptr)
5699 opt_dst->set(opt_src);
5700 } else {
5701 // BBS
5702 ConfigOptionVectorBase* opt_vec_dst = static_cast<ConfigOptionVectorBase*>(opt_dst);
5703 {
5704 if (apply_extruder) {
5705 std::vector<const ConfigOption*> filament_opts(num_filaments, nullptr);
5706 // Setting a vector value from all filament_configs.
5707 for (size_t i = 0; i < filament_opts.size(); ++i)
5708 filament_opts[i] = filament_temp_configs[i].option(key);
5709 opt_vec_dst->set(filament_opts);
5710 }
5711 else {
5712 for (size_t i = 0; i < num_filaments; ++i) {
5713 const ConfigOptionVectorBase* filament_option = static_cast<const ConfigOptionVectorBase*>(filament_temp_configs[i].option(key));
5714 if (i == 0)
5715 opt_vec_dst->set(filament_option);
5716 else
5717 opt_vec_dst->append(filament_option);
5718
5719 if (key == "filament_extruder_variant")
5720 filament_variant_count[i] = filament_option->size();
5721 }
5722 }
5723 }
5724 }
5725 }
5726
5727 if (!apply_extruder) {
5728 //append filament_self_index
5729 std::vector<int>& filament_self_indice = out.option<ConfigOptionInts>("filament_self_index", true)->values;
5730 int index_size = out.option<ConfigOptionStrings>("filament_extruder_variant")->size();
5731 filament_self_indice.resize(index_size, 1);
5732 int k = 0;
5733 for (size_t i = 0; i < num_filaments; i++) {
5734 for (size_t j = 0; j < filament_variant_count[i]; j++) {
5735 filament_self_indice[k++] = i + 1;
5736 }
5737 }
5738 }
5739 }
5740
5741 //BBS: add logic for settings check between different system presets
5742 std::string printer_inherits = this->printers.get_edited_preset().inherits();
5743 // Don't store the "compatible_printers_condition" for the printer profile, there is none.
5744 inherits .emplace_back(printer_inherits);
5745 const Preset* printer_parent_preset = this->printers.get_selected_preset_parent();
5746 if (printer_parent_preset) {
5747 std::vector<std::string> dirty_options = this->printers.dirty_options_without_option_list(&(this->printers.get_edited_preset()), printer_parent_preset, ignore_settings_list, false);
5748 if (!dirty_options.empty()) {
5749 different_printer_settings = Slic3r::escape_strings_cstyle(dirty_options);
5750 }
5751 }
5752 different_settings.emplace_back(different_printer_settings);
5753
5754 // These value types clash between the print and filament profiles. They should be renamed.
5755 out.erase("compatible_prints");
5756 out.erase("compatible_prints_condition");
5757 out.erase("compatible_printers");
5758 out.erase("compatible_printers_condition");
5759 out.erase("inherits");
5760 //BBS: add logic for settings check between different system presets
5761 out.erase("different_settings_to_system");
5762
5763 static const char* keys[] = {"support_filament", "support_interface_filament", "wipe_tower_filament"};
5764 for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++ i) {
5765 std::string key = std::string(keys[i]);
5766 auto *opt = dynamic_cast<ConfigOptionInt*>(out.option(key, false));
5767 assert(opt != nullptr);
5768 opt->value = boost::algorithm::clamp<int>(opt->value, 0, int(num_filaments));
5769 }
5770
5771 static const char* keys_with_default[] = {
5772 "outer_wall_filament_id", "inner_wall_filament_id", "sparse_infill_filament_id",
5773 "internal_solid_filament_id", "top_surface_filament_id", "bottom_surface_filament_id"
5774 };
5775 for (size_t i = 0; i < sizeof(keys_with_default) / sizeof(keys_with_default[0]); ++ i) {
5776 std::string key = std::string(keys_with_default[i]);
5777 auto *opt = dynamic_cast<ConfigOptionInt*>(out.option(key, false));
5778 assert(opt != nullptr);
5779 if(opt->value < 0 || opt->value > int(num_filaments))
5780 opt->value = 0;
5781 }
5782 out.option<ConfigOptionString >("print_settings_id", true)->value = this->prints.get_selected_preset_name();
5783 out.option<ConfigOptionStrings>("filament_settings_id", true)->values = this->filament_presets;
5784 out.option<ConfigOptionString >("printer_settings_id", true)->value = this->printers.get_selected_preset_name();
5785 out.option<ConfigOptionStrings>("filament_ids", true)->values = filament_ids;
5786 out.option<ConfigOptionInts>("filament_map", true)->values = filament_maps;
5787 // Serialize the collected "compatible_printers_condition" and "inherits" fields.
5788 // There will be 1 + num_exturders fields for "inherits" and 2 + num_extruders for "compatible_printers_condition" stored.
5789 // The vector will not be stored if all fields are empty strings.
5790 auto add_if_some_non_empty = [&out](std::vector<std::string> &&values, const std::string &key) {
5791 bool nonempty = false;
5792 for (const std::string &v : values)
5793 if (! v.empty()) {
5794 nonempty = true;
5795 break;
5796 }
5797 if (nonempty)
5798 out.set_key_value(key, new ConfigOptionStrings(std::move(values)));
5799 };
5800 add_if_some_non_empty(std::move(compatible_printers_condition), "compatible_machine_expression_group");
5801 add_if_some_non_empty(std::move(compatible_prints_condition), "compatible_process_expression_group");
5802 add_if_some_non_empty(std::move(inherits), "inherits_group");
5803 //BBS: add logic for settings check between different system presets
5804 add_if_some_non_empty(std::move(different_settings), "different_settings_to_system");
5805 add_if_some_non_empty(std::move(print_compatible_printers), "print_compatible_printers");
5806 out.option<ConfigOptionStrings>("extruder_ams_count", true)->values = save_extruder_ams_count_to_string(this->extruder_ams_counts);
5807
5808 out.option<ConfigOptionEnumGeneric>("printer_technology", true)->value = ptFFF;
5809 return out;
5810}
PresetBundle()
Definition PresetBundle.cpp:484
std::string & inherits()
Definition Preset.hpp:358
std::string & compatible_prints_condition()
Definition Preset.hpp:377
std::string & compatible_printers_condition()
Definition Preset.hpp:385
const std::set< std::string > ignore_settings_list
Definition PresetBundle.cpp:5484

References PresetBundle(), Slic3r::ConfigOptionVectorBase::append(), Slic3r::ConfigBase::apply(), Slic3r::Preset::compatible_printers_condition(), Slic3r::Preset::compatible_prints_condition(), Slic3r::Preset::config, Slic3r::DynamicConfig::diff(), Slic3r::DynamicConfig::erase(), Slic3r::escape_strings_cstyle(), extruder_ams_counts, Slic3r::Preset::filament_id, Slic3r::filament_ids(), Slic3r::filament_options_with_variant, filament_presets, filaments, full_fff_config(), Slic3r::DynamicPrintConfig::get_extruder_nozzle_volume_count(), Slic3r::DynamicPrintConfig::has_multi_variant_filament(), Slic3r::ignore_settings_list, Slic3r::Preset::inherits(), Slic3r::Preset::is_default, Slic3r::ConfigOption::is_scalar(), Slic3r::Preset::is_system, Slic3r::Preset::name, Slic3r::nvtStandard, Slic3r::ConfigBase::option(), Slic3r::print_options_with_variant, Slic3r::printer_options_with_variant_1, Slic3r::printer_options_with_variant_2, printers, prints, project_config, Slic3r::ptFFF, Slic3r::save_extruder_ams_count_to_string(), Slic3r::ConfigOption::set(), Slic3r::ConfigOptionVectorBase::set(), Slic3r::DynamicConfig::set_key_value(), Slic3r::ConfigOptionVectorBase::size(), Slic3r::DynamicPrintConfig::support_different_extruders(), Slic3r::DynamicPrintConfig::update_values_to_printer_extruders(), Slic3r::ConfigOptionVector< T >::values, and Slic3r::ConfigOptionVector< int >::values.

Referenced by full_config(), full_config_secure(), and full_fff_config().

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

◆ full_sla_config()

DynamicPrintConfig Slic3r::PresetBundle::full_sla_config ( ) const
private
5813{
5814 DynamicPrintConfig out;
5815 out.apply(SLAFullPrintConfig::defaults());
5816 out.apply(this->sla_prints.get_edited_preset().config);
5817 out.apply(this->sla_materials.get_edited_preset().config);
5818 out.apply(this->printers.get_edited_preset().config);
5819 // There are no project configuration values as of now, the project_config is reserved for FFF printers.
5820// out.apply(this->project_config);
5821
5822 // Collect the "compatible_printers_condition" and "inherits" values over all presets (sla_prints, sla_materials, printers) into a single vector.
5823 std::vector<std::string> compatible_printers_condition;
5824 std::vector<std::string> compatible_prints_condition;
5825 std::vector<std::string> inherits;
5826 compatible_printers_condition.emplace_back(this->sla_prints.get_edited_preset().compatible_printers_condition());
5827 inherits .emplace_back(this->sla_prints.get_edited_preset().inherits());
5828 compatible_printers_condition.emplace_back(this->sla_materials.get_edited_preset().compatible_printers_condition());
5829 compatible_prints_condition .emplace_back(this->sla_materials.get_edited_preset().compatible_prints_condition());
5830 inherits .emplace_back(this->sla_materials.get_edited_preset().inherits());
5831 inherits .emplace_back(this->printers.get_edited_preset().inherits());
5832
5833 // These two value types clash between the print and filament profiles. They should be renamed.
5834 out.erase("compatible_printers");
5835 out.erase("compatible_printers_condition");
5836 out.erase("inherits");
5837
5838 out.option<ConfigOptionString >("sla_print_settings_id", true)->value = this->sla_prints.get_selected_preset_name();
5839 out.option<ConfigOptionString >("sla_material_settings_id", true)->value = this->sla_materials.get_selected_preset_name();
5840 out.option<ConfigOptionString >("printer_settings_id", true)->value = this->printers.get_selected_preset_name();
5841
5842 // Serialize the collected "compatible_printers_condition" and "inherits" fields.
5843 // There will be 1 + num_exturders fields for "inherits" and 2 + num_extruders for "compatible_printers_condition" stored.
5844 // The vector will not be stored if all fields are empty strings.
5845 auto add_if_some_non_empty = [&out](std::vector<std::string> &&values, const std::string &key) {
5846 bool nonempty = false;
5847 for (const std::string &v : values)
5848 if (! v.empty()) {
5849 nonempty = true;
5850 break;
5851 }
5852 if (nonempty)
5853 out.set_key_value(key, new ConfigOptionStrings(std::move(values)));
5854 };
5855 add_if_some_non_empty(std::move(compatible_printers_condition), "compatible_machine_expression_group");
5856 add_if_some_non_empty(std::move(compatible_prints_condition), "compatible_process_expression_group");
5857 add_if_some_non_empty(std::move(inherits), "inherits_group");
5858
5859 out.option<ConfigOptionEnumGeneric>("printer_technology", true)->value = ptSLA;
5860 return out;
5861}
@ ptSLA
Definition Config.hpp:233

References Slic3r::ConfigBase::apply(), Slic3r::DynamicConfig::erase(), full_sla_config(), Slic3r::ConfigBase::option(), printers, Slic3r::ptSLA, Slic3r::DynamicConfig::set_key_value(), sla_materials, and sla_prints.

Referenced by full_config(), and full_sla_config().

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

◆ get_ams_cobox_infos()

void Slic3r::PresetBundle::get_ams_cobox_infos ( AMSComboInfo & combox_info)
4517{
4518 combox_info.clear();
4519 for (auto &entry : filament_ams_list) {
4520 auto &ams = entry.second;
4521 auto filament_id = ams.opt_string("filament_id", 0u);
4522 auto filament_color = ams.opt_string("filament_colour", 0u);
4523 auto ams_name = ams.opt_string("tray_name", 0u);
4524 auto filament_changed = !ams.has("filament_changed") || ams.opt_bool("filament_changed");
4525 auto filament_multi_color = ams.opt<ConfigOptionStrings>("filament_multi_colour")->values;
4526 if (filament_id.empty()) {
4527 continue;
4528 }
4529 if (!filament_changed && this->filament_presets.size() > combox_info.ams_filament_presets.size()) {
4530 combox_info.ams_filament_presets.push_back(this->filament_presets[combox_info.ams_filament_presets.size()]);
4531 combox_info.ams_filament_colors.push_back(filament_color);
4532 combox_info.ams_multi_color_filment.push_back(filament_multi_color);
4533 combox_info.ams_names.push_back(ams_name);
4534 continue;
4535 }
4536 auto iter = std::find_if(filaments.begin(), filaments.end(),
4537 [this, &filament_id](auto &f) { return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; });
4538 warn_ambiguous_filament_id_match(filaments, iter, filament_id);
4539 if (iter == filaments.end()) {
4540 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
4541 auto filament_type = ams.opt_string("filament_type", 0u);
4542 if (!filament_type.empty()) {
4543 filament_type = "Generic " + filament_type;
4544 iter = std::find_if(filaments.begin(), filaments.end(),
4545 [&filament_type](auto &f) { return f.is_compatible && f.is_system && boost::algorithm::starts_with(f.name, filament_type); });
4546 }
4547 if (iter == filaments.end()) {
4548 // Prefer old selection
4549 if (combox_info.ams_filament_presets.size() < this->filament_presets.size()) {
4550 combox_info.ams_filament_presets.push_back(this->filament_presets[combox_info.ams_filament_presets.size()]);
4551 combox_info.ams_filament_colors.push_back(filament_color);
4552 combox_info.ams_multi_color_filment.push_back(filament_multi_color);
4553 combox_info.ams_names.push_back(ams_name);
4554 continue;
4555 }
4556 iter = std::find_if(filaments.begin(), filaments.end(), [](auto &f) { return f.is_compatible && f.is_system; });
4557 if (iter == filaments.end())
4558 continue;
4559 }
4560 filament_id = iter->filament_id;
4561 }
4562 combox_info.ams_filament_presets.push_back(iter->name);
4563 combox_info.ams_filament_colors.push_back(filament_color);
4564 combox_info.ams_multi_color_filment.push_back(filament_multi_color);
4565 combox_info.ams_names.push_back(ams_name);
4566 }
4567}
std::map< int, DynamicPrintConfig > filament_ams_list
Definition PresetBundle.hpp:509
zaa_minimize_perimeter_height filament_type((ConfigOptionBools, filament_soluble))((ConfigOptionStrings
static void warn_ambiguous_filament_id_match(const PresetCollection &filaments, PresetCollection::ConstIterator match, const std::string &filament_id)
Definition PresetBundle.cpp:4502

References Slic3r::AMSComboInfo::ams_filament_colors, Slic3r::AMSComboInfo::ams_filament_presets, Slic3r::AMSComboInfo::ams_multi_color_filment, Slic3r::AMSComboInfo::ams_names, Slic3r::AMSComboInfo::clear(), Slic3r::f(), filament_ams_list, filament_presets, Slic3r::filament_type(), filaments, get_ams_cobox_infos(), and Slic3r::warn_ambiguous_filament_id_match().

Referenced by get_ams_cobox_infos().

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

◆ get_current_project_embedded_presets()

std::vector< Preset * > Slic3r::PresetBundle::get_current_project_embedded_presets ( )
1223{
1224 std::vector<Preset*> project_presets;
1225
1226 project_presets = this->prints.get_project_embedded_presets();
1227
1228 auto filament_presets = this->filaments.get_project_embedded_presets();
1229 if (!filament_presets.empty())
1230 std::copy(filament_presets.begin(), filament_presets.end(), std::back_inserter(project_presets));
1231 auto printer_presets = this->printers.get_project_embedded_presets();
1232 if (!printer_presets.empty())
1233 std::copy(printer_presets.begin(), printer_presets.end(), std::back_inserter(project_presets));
1234
1235 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, returned project_presets count %1%")%project_presets.size();
1236 return project_presets;
1237}
Iterator begin()
Definition Preset.hpp:583
Iterator end()
Definition Preset.hpp:586
PresetCollection & printer_presets(PresetBundle &bundle)
Definition PluginHostPresets.cpp:50

References Slic3r::PresetCollection::begin(), Slic3r::PresetCollection::end(), filament_presets, filaments, get_current_project_embedded_presets(), printers, and prints.

Referenced by Slic3r::GUI::Plater::export_3mf(), and get_current_project_embedded_presets().

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

◆ get_current_vendor_type()

VendorType Slic3r::PresetBundle::get_current_vendor_type ( )
993{
994 auto t = VendorType::Unknown;
995 auto config = &printers.get_edited_preset().config;
996 const auto* printer_model = config->opt<ConfigOptionString>("printer_model");
997 if (printer_model == nullptr) {
998 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": printer_model is "
999 << (config->has("printer_model") ? "not a string" : "missing")
1000 << ", vendor type is Unknown";
1001 return t;
1002 }
1003
1004 std::string vendor_name;
1005 for (const auto& vendor_profile : vendors) {
1006 for (const auto& vendor_model : vendor_profile.second.models) {
1007 if (vendor_model.name == printer_model->value) {
1008 vendor_name = vendor_profile.first;
1009 break;
1010 }
1011 }
1012 if (!vendor_name.empty())
1013 break;
1014 }
1015 if (!vendor_name.empty())
1016 {
1017 if(vendor_name.compare("BBL") == 0)
1019
1020 if(vendor_name.compare("Qidi") == 0)
1022 }
1023 return t;
1024}
@ Klipper_Qidi
Definition PresetBundle.hpp:46
@ Marlin_BBL
Definition PresetBundle.hpp:45
@ Unknown
Definition PresetBundle.hpp:42

References get_current_vendor_type(), Klipper_Qidi, Marlin_BBL, printers, Unknown, and vendors.

Referenced by get_current_vendor_type(), and is_bbl_vendor().

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

◆ get_custom_vendor_models()

VendorProfile Slic3r::PresetBundle::get_custom_vendor_models ( ) const
3603{
3604 VendorProfile vendor;
3605 vendor.name = PRESET_CUSTOM_VENDOR;
3606 vendor.id = PRESET_CUSTOM_VENDOR;
3607 for (auto &preset : printers.get_presets()) {
3608 if (preset.is_system) continue;
3609 if (printers.get_preset_base(preset) != &preset) continue;
3610 if (preset.is_default) continue;
3611 auto model = preset.config.opt_string("printer_model");
3612 auto variant = preset.config.opt_string("printer_variant");
3613 auto iter_model = std::find_if(vendor.models.begin(), vendor.models.end(), [model](VendorProfile::PrinterModel &m) {
3614 return m.name == model;
3615 });
3616 if (iter_model == vendor.models.end()) {
3617 iter_model = vendor.models.emplace(vendor.models.end(), VendorProfile::PrinterModel{});
3618 iter_model->id = model;
3619 iter_model->name = model;
3620 iter_model->variants = {VendorProfile::PrinterVariant(variant)};
3621 } else {
3622 iter_model->variants.push_back(VendorProfile::PrinterVariant(variant));
3623 }
3624 }
3625 return vendor;
3626}
#define PRESET_CUSTOM_VENDOR
Definition Preset.hpp:41

References Slic3r::Preset::config, get_custom_vendor_models(), Slic3r::VendorProfile::id, Slic3r::Preset::is_default, Slic3r::Preset::is_system, Slic3r::VendorProfile::models, Slic3r::VendorProfile::name, Slic3r::DynamicConfig::opt_string(), PRESET_CUSTOM_VENDOR, and printers.

Referenced by get_custom_vendor_models(), and Slic3r::GUI::get_exist_vendor_choices().

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

◆ get_default_nozzle_volume_types_for_filaments()

std::vector< int > Slic3r::PresetBundle::get_default_nozzle_volume_types_for_filaments ( std::vector< int > & f_maps)
5412{
5413 std::vector<int> result;
5414 int filament_count = f_maps.size();
5415 result.resize(filament_count, static_cast<int>(NozzleVolumeType::nvtStandard));
5416
5417 auto opt_nozzle_volume_type = dynamic_cast<const ConfigOptionEnumsGeneric*>(this->project_config.option("nozzle_volume_type"));
5418 for (int index = 0; index < filament_count; index++)
5419 {
5420 if (opt_nozzle_volume_type && opt_nozzle_volume_type->values.size() > (f_maps[index] - 1))
5421 result[index] = opt_nozzle_volume_type->values[f_maps[index] - 1];
5422 }
5423
5424 return result;
5425}
ConfigOptionEnumsGenericTempl< false > ConfigOptionEnumsGeneric
Definition Config.hpp:2311

References get_default_nozzle_volume_types_for_filaments(), Slic3r::nvtStandard, and project_config.

Referenced by get_default_nozzle_volume_types_for_filaments(), and anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_config().

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

◆ get_differed_values_to_update()

int Slic3r::PresetBundle::get_differed_values_to_update ( Preset & preset,
std::map< std::string, std::string > & key_values )
958{
959 PresetCollection* preset_collection;
960
961 switch(preset.type) {
963 preset_collection = &(this->prints);
964 break;
966 preset_collection = &(this->printers);
967 break;
969 preset_collection = &(this->filaments);
970 break;
971 default:
972 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" invalid type %1%, return directly")%preset.type;
973 return -1;
974 }
975
976 return preset_collection->get_differed_values_to_update(preset, key_values);
977}

References filaments, get_differed_values_to_update(), Slic3r::PresetCollection::get_differed_values_to_update(), printers, prints, Slic3r::Preset::type, Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::TYPE_PRINT, and Slic3r::Preset::TYPE_PRINTER.

Referenced by get_differed_values_to_update().

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

◆ get_extruder_filament_info()

std::vector< std::vector< DynamicPrintConfig > > Slic3r::PresetBundle::get_extruder_filament_info ( ) const
5137{
5138 std::vector<std::vector<DynamicPrintConfig>> filament_infos;
5139 int extruder_nums = get_printer_extruder_count();
5140 if (extruder_nums > 1) {
5141 filament_infos.resize(extruder_nums, std::vector<DynamicPrintConfig>());
5142 for (auto ams_item : filament_ams_list) {
5143 if (ams_item.first & 0x10000) { // right
5144 filament_infos[1].push_back(ams_item.second);
5145 } else { // left
5146 filament_infos[0].push_back(ams_item.second);
5147 }
5148 }
5149 }
5150 return filament_infos;
5151}
int get_printer_extruder_count() const
Definition PresetBundle.cpp:5364

References filament_ams_list, get_extruder_filament_info(), and get_printer_extruder_count().

Referenced by get_extruder_filament_info().

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

◆ get_filament_by_filament_id()

std::optional< FilamentBaseInfo > Slic3r::PresetBundle::get_filament_by_filament_id ( const std::string & filament_id,
const std::string & printer_name = std::string() ) const
1138{
1139 if (filament_id.empty())
1140 return std::nullopt;
1141
1142 // basic filament info should be same in the parent preset and child preset
1143 // so just match the filament id is enough
1144
1145 for (auto iter = filaments.begin(); iter != filaments.end(); ++iter) {
1146 const Preset& filament_preset = *iter;
1147 const auto& config = filament_preset.config;
1148 if (filament_preset.filament_id == filament_id) {
1149 FilamentBaseInfo info;
1150 info.filament_id = filament_id;
1151 info.is_system = filament_preset.is_system;
1152 info.filament_name = filament_preset.alias;
1153 if (config.has("filament_is_support"))
1154 info.is_support = config.option<ConfigOptionBools>("filament_is_support")->values[0];
1155 if (config.has("filament_type"))
1156 info.filament_type = config.option<ConfigOptionStrings>("filament_type")->values[0];
1157 if (config.has("filament_vendor"))
1158 info.vendor = config.option<ConfigOptionStrings>("filament_vendor")->values[0];
1159 if (config.has("nozzle_temperature_range_high"))
1160 info.nozzle_temp_range_high = config.option<ConfigOptionInts>("nozzle_temperature_range_high")->values[0];
1161 if (config.has("nozzle_temperature_range_low"))
1162 info.nozzle_temp_range_low = config.option<ConfigOptionInts>("nozzle_temperature_range_low")->values[0];
1163 if(config.has("temperature_vitrification"))
1164 info.temperature_vitrification = config.option<ConfigOptionInts>("temperature_vitrification")->values[0];
1165
1166 if (!printer_name.empty()) {
1167 std::vector<std::string> compatible_printers = config.option<ConfigOptionStrings>("compatible_printers")->values;
1168 auto iter = std::find(compatible_printers.begin(), compatible_printers.end(), printer_name);
1169 if (iter != compatible_printers.end() && config.has("filament_printable")) {
1170 info.filament_printable = config.option<ConfigOptionInts>("filament_printable")->values[0];
1171 if (config.has("filament_extruder_compatibility"))
1172 info.set_filament_extruder_compatibility(config.option<ConfigOptionInts>("filament_extruder_compatibility")->values[0]);
1173 return info;
1174 }
1175 }
1176 else {
1177 return info;
1178 }
1179 }
1180 }
1181 return std::nullopt;
1182}

References Slic3r::Preset::alias, Slic3r::Preset::config, Slic3r::FilamentBaseInfo::filament_id, Slic3r::Preset::filament_id, Slic3r::FilamentBaseInfo::filament_name, Slic3r::FilamentBaseInfo::filament_printable, Slic3r::FilamentBaseInfo::filament_type, filaments, get_filament_by_filament_id(), Slic3r::FilamentBaseInfo::is_support, Slic3r::FilamentBaseInfo::is_system, Slic3r::Preset::is_system, Slic3r::FilamentBaseInfo::nozzle_temp_range_high, Slic3r::FilamentBaseInfo::nozzle_temp_range_low, Slic3r::FilamentBaseInfo::set_filament_extruder_compatibility(), Slic3r::FilamentBaseInfo::temperature_vitrification, and Slic3r::FilamentBaseInfo::vendor.

Referenced by Slic3r::_get_filament_name_from_ams(), Slic3r::check_filaments_printable(), get_filament_by_filament_id(), and Slic3r::GUI::AMSDryCtrWin::update_filament_list().

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

◆ get_filament_presets_for_machine()

std::vector< Preset * > Slic3r::PresetBundle::get_filament_presets_for_machine ( const std::string & printer_type,
const std::string & nozzle_diameter_str,
bool include_user_presets )
5189{
5190 // Printer model plus nozzle diameter is expected to resolve to a single system printer preset;
5191 // get_printer_names_by_printer_type_and_nozzle asserts as much in debug builds.
5192 const std::set<std::string> printer_names = get_printer_names_by_printer_type_and_nozzle(printer_type, nozzle_diameter_str);
5193 const Preset *printer = printer_names.empty() ? nullptr : printers.find_preset(*printer_names.begin());
5194 if (printer == nullptr)
5195 return {};
5196
5197 // Preset::is_visible is deliberately not consulted: it tracks what the Configuration Wizard
5198 // installed, while the caller identifies a physically connected machine the user may never
5199 // have installed - gating on it would empty the list for exactly those machines.
5200 const PresetWithVendorProfile active_printer = printers.get_preset_with_vendor_profile(*printer);
5201 // Loop invariant - the two argument is_compatible_with_printer() would rebuild it per preset.
5202 DynamicPrintConfig printer_config;
5203 printer_config.set_key_value("printer_preset", new ConfigOptionString(printer->name));
5204 if (const ConfigOption *opt = printer->config.option("nozzle_diameter"))
5205 printer_config.set_key_value("num_extruders", new ConfigOptionInt((int) static_cast<const ConfigOptionFloats *>(opt)->values.size()));
5206
5207 std::vector<Preset *> compatible;
5208 for (Preset &preset : filaments) {
5209 /* The situation where the preset is not offered is as follows:
5210 1. Not a root preset
5211 2. Not a system preset and the printer firmware does not support user presets */
5212 if (filaments.get_preset_base(preset) != &preset || (!preset.is_system && !include_user_presets))
5213 continue;
5214 if (is_compatible_with_printer(filaments.get_preset_with_vendor_profile(preset), active_printer, &printer_config))
5215 compatible.push_back(&preset);
5216 }
5217 return compatible;
5218}
size_t size() const override
Definition Config.hpp:722

References Slic3r::Preset::config, filaments, get_filament_presets_for_machine(), get_printer_names_by_printer_type_and_nozzle(), Slic3r::is_compatible_with_printer(), Slic3r::Preset::is_system, Slic3r::Preset::name, Slic3r::ConfigBase::option(), printers, and Slic3r::DynamicConfig::set_key_value().

Referenced by Slic3r::GUI::NewCalibrationHistoryDialog::get_all_filaments(), get_filament_presets_for_machine(), Slic3r::GUI::AMSMaterialsSetting::on_select_filament(), Slic3r::GUI::AMSMaterialsSetting::Popup(), and Slic3r::GUI::AMSDryCtrWin::update_filament_list().

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

◆ get_filament_variant_index()

int Slic3r::PresetBundle::get_filament_variant_index ( const DynamicPrintConfig & filament_config,
const DynamicPrintConfig & printer_config,
int extruder_id,
NozzleVolumeType nozzle_volume_type )
static
5222{
5223 const auto *extruder_types = printer_config.option<ConfigOptionEnumsGeneric>("extruder_type");
5224 const ExtruderType extruder_type = extruder_types && !extruder_types->empty() ? ExtruderType(extruder_types->get_at(extruder_id)) : etDirectDrive;
5225 return std::max(0, filament_config.get_index_for_extruder(1, "", extruder_type, nozzle_volume_type, "filament_extruder_variant"));
5226}
bool empty() const override
Definition Config.hpp:723
ExtruderType
Definition PrintConfig.hpp:612
@ etDirectDrive
Definition PrintConfig.hpp:613

References Slic3r::etDirectDrive, get_filament_variant_index(), Slic3r::DynamicPrintConfig::get_index_for_extruder(), Slic3r::nozzle_volume_type(), and Slic3r::ConfigBase::option().

Referenced by check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(), Slic3r::GUI::AMSMaterialsSetting::get_filament_variant_index(), and get_filament_variant_index().

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

◆ get_full_flush_matrix()

std::vector< std::vector< std::vector< float > > > Slic3r::PresetBundle::get_full_flush_matrix ( bool with_multiplier = true) const
5449{
5450 auto full_config = this->full_config();
5451 int extruder_nums = full_config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
5452 std::vector<double> flush_volume_value = full_config.option<ConfigOptionFloats>("flush_volumes_matrix")->values;
5453 int filament_nums = full_config.option<ConfigOptionStrings>("filament_type")->values.size();
5454
5455 std::vector<std::vector<std::vector<float>>> matrix;
5456 for (size_t extruder_id = 0; extruder_id < extruder_nums; ++extruder_id) {
5457 std::vector<float> flush_matrix(cast<float>(get_flush_volumes_matrix(flush_volume_value, extruder_id, extruder_nums)));
5458 std::vector<std::vector<float>> wipe_volumes;
5459 for (unsigned int i = 0; i < filament_nums; ++i)
5460 wipe_volumes.push_back(std::vector<float>(flush_matrix.begin() + i * filament_nums, flush_matrix.begin() + (i + 1) * filament_nums));
5461
5462 matrix.emplace_back(wipe_volumes);
5463 }
5464
5465 if (with_multiplier) {
5466 // Fast purge mode uses flush_multiplier_fast; the default prime_volume_mode==Default
5467 // (or the key absent) reads flush_multiplier, so this is inert.
5468 auto* mode_opt = project_config.option<ConfigOptionEnum<PrimeVolumeMode>>("prime_volume_mode");
5469 const bool use_fast = mode_opt && mode_opt->value == PrimeVolumeMode::pvmFast;
5470 auto* mult_opt = project_config.option<ConfigOptionFloats>(use_fast ? "flush_multiplier_fast" : "flush_multiplier");
5471 auto flush_multiplies = mult_opt ? mult_opt->values : project_config.option<ConfigOptionFloats>("flush_multiplier")->values;
5472 flush_multiplies.resize(extruder_nums, 1);
5473 for (size_t extruder_id = 0; extruder_id < extruder_nums; ++extruder_id) {
5474 for (auto& vec : matrix[extruder_id]) {
5475 for (auto& v : vec)
5476 v *= flush_multiplies[extruder_id];
5477 }
5478 }
5479 }
5480
5481 return matrix;
5482}
void resize(size_t n, const ConfigOption *opt_default=nullptr) override
Definition Config.hpp:687
DynamicPrintConfig full_config(bool apply_extruder=true, std::optional< std::vector< int > >filament_maps=std::nullopt, std::optional< std::vector< int > > filament_volume_maps=std::nullopt) const
Definition PresetBundle.cpp:5427
static std::vector< T > get_flush_volumes_matrix(const std::vector< T > &fv_matrix, size_t extruder_id=-1, size_t nozzle_nums=1)
Definition PrintConfig.hpp:2685
@ pvmFast
Definition PrintConfig.hpp:659
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299

References Slic3r::cast(), full_config(), Slic3r::get_flush_volumes_matrix(), get_full_flush_matrix(), project_config, Slic3r::pvmFast, Slic3r::ConfigOptionVector< double >::resize(), Slic3r::ConfigOptionVector< T >::size(), and Slic3r::ConfigOptionSingle< T >::value.

Referenced by get_full_flush_matrix().

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

◆ get_hotend_model_for_printer_model()

std::string Slic3r::PresetBundle::get_hotend_model_for_printer_model ( std::string model_name)
1361{
1362 std::string hotend_stl, vendor_name, out;
1363
1364 for (auto vendor_profile: this->vendors)
1365 {
1366 for (auto vendor_model: vendor_profile.second.models)
1367 {
1368 if (vendor_model.name == model_name)
1369 {
1370 hotend_stl = vendor_model.hotend_model;
1371 vendor_name = vendor_profile.first;
1372 break;
1373 }
1374 }
1375 }
1376
1377 if (!hotend_stl.empty())
1378 {
1379 out = Slic3r::data_dir() + "/vendor/" + vendor_name + "/" + hotend_stl;
1380 if (!boost::filesystem::exists(boost::filesystem::path(out)))
1381 out = Slic3r::resources_dir() + "/profiles/" + vendor_name + "/" + hotend_stl;
1382 }
1383
1384 if (out.empty() ||!boost::filesystem::exists(boost::filesystem::path(out)))
1385 out = Slic3r::resources_dir() + "/profiles/hotend.stl";
1386
1387 return out;
1388}

References Slic3r::data_dir(), get_hotend_model_for_printer_model(), Slic3r::resources_dir(), and vendors.

Referenced by get_hotend_model_for_printer_model(), and Slic3r::GUI::GCodeViewer::init().

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

◆ get_preset_differed_for_save()

Preset * Slic3r::PresetBundle::get_preset_differed_for_save ( Preset & preset)
936{
937 PresetCollection* preset_collection;
938
939 switch(preset.type) {
941 preset_collection = &(this->prints);
942 break;
944 preset_collection = &(this->printers);
945 break;
947 preset_collection = &(this->filaments);
948 break;
949 default:
950 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" invalid type %1%, return directly")%preset.type;
951 return nullptr;
952 }
953
954 return preset_collection->get_preset_differed_for_save(preset);
955}

References filaments, get_preset_differed_for_save(), Slic3r::PresetCollection::get_preset_differed_for_save(), printers, prints, Slic3r::Preset::type, Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::TYPE_PRINT, and Slic3r::Preset::TYPE_PRINTER.

Referenced by get_preset_differed_for_save().

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

◆ get_preset_name_by_alias()

const std::string & Slic3r::PresetBundle::get_preset_name_by_alias ( const Preset::Type & preset_type,
const std::string & alias ) const
3693{
3694 if (preset_type == Preset::TYPE_INVALID)
3695 return alias;
3696
3697 const PresetCollection& presets = preset_type == Preset::TYPE_PRINT ? prints :
3698 preset_type == Preset::TYPE_SLA_PRINT ? sla_prints :
3699 preset_type == Preset::TYPE_FILAMENT ? filaments :
3700 preset_type == Preset::TYPE_PRINTER ? printers :
3702
3703 return presets.get_preset_name_by_alias(alias);
3704}
@ TYPE_INVALID
Definition Preset.hpp:245

References filaments, get_preset_name_by_alias(), Slic3r::PresetCollection::get_preset_name_by_alias(), printers, prints, sla_materials, sla_prints, Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::TYPE_INVALID, Slic3r::Preset::TYPE_PRINT, Slic3r::Preset::TYPE_PRINTER, and Slic3r::Preset::TYPE_SLA_PRINT.

Referenced by get_preset_name_by_alias(), and load_selections().

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

◆ get_printer_extruder_count()

int Slic3r::PresetBundle::get_printer_extruder_count ( ) const
5365{
5366 const Preset& printer_preset = this->printers.get_edited_preset();
5367
5368 const auto* nozzle_diameter = printer_preset.config.option<ConfigOptionFloats>("nozzle_diameter");
5369 if (nozzle_diameter == nullptr) {
5370 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": nozzle_diameter is missing, using 1 extruder";
5371 return 1;
5372 }
5373 if (nozzle_diameter->values.empty()) {
5374 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": nozzle_diameter is empty, using 1 extruder";
5375 return 1;
5376 }
5377
5378 int count = int(nozzle_diameter->values.size());
5379
5380 return count;
5381}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
zaa_minimize_perimeter_height nozzle_diameter((ConfigOptionBool, reduce_infill_retraction))((ConfigOptionBool

References Slic3r::Preset::config, count, get_printer_extruder_count(), Slic3r::nozzle_diameter(), Slic3r::ConfigBase::option(), and printers.

Referenced by Slic3r::GUI::MainFrame::create_side_tools(), get_extruder_filament_info(), get_printer_extruder_count(), Slic3r::GUI::GCodeViewer::init(), min_filament_count(), Slic3r::GUI::Sidebar::need_auto_sync_extruder_list_after_connect_priner(), Slic3r::GUI::PartPlate::refresh_imex_icon(), Slic3r::GUI::PartPlate::register_raycasters_for_picking(), Slic3r::GUI::PartPlate::render_icons(), Slic3r::GUI::seedExtruderNozzleStats(), Slic3r::GUI::PartPlate::set_shape(), Slic3r::GUI::setExtruderNozzleCount(), sync_ams_list(), Slic3r::GUI::Sidebar::priv::sync_extruder_list(), update_multi_material_filament_presets(), and Slic3r::GUI::Sidebar::priv::update_sync_status().

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

◆ get_printer_names_by_printer_type_and_nozzle()

std::set< std::string > Slic3r::PresetBundle::get_printer_names_by_printer_type_and_nozzle ( const std::string & printer_type,
std::string nozzle_diameter_str,
bool system_only = true )
5157{
5158 std::set<std::string> printer_names;
5159 if ("0.0" == nozzle_diameter_str || nozzle_diameter_str.empty()) {
5160 nozzle_diameter_str = "0.4";
5161 }
5162 std::ostringstream stream;
5163
5164 for (auto printer_it = this->printers.begin(); printer_it != this->printers.end(); printer_it++) {
5165 if (system_only && !printer_it->is_system) continue;
5166
5167 ConfigOption * printer_model_opt = printer_it->config.option("printer_model");
5168 ConfigOptionString *printer_model_str = dynamic_cast<ConfigOptionString *>(printer_model_opt);
5169 if (!printer_model_str) continue;
5170
5171 // use printer_model as printer type
5172 if (printer_model_str->value != printer_type) continue;
5173
5174 if (printer_it->name.find(nozzle_diameter_str) != std::string::npos) printer_names.insert(printer_it->name);
5175 }
5176
5177 assert(printer_names.size() == 1);
5178
5179 for (auto& printer_name : printer_names) {
5180 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << " printer name: " << printer_name;
5181 }
5182
5183 return printer_names;
5184}

References get_printer_names_by_printer_type_and_nozzle(), printers, and Slic3r::ConfigOptionSingle< T >::value.

Referenced by check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(), get_filament_presets_for_machine(), Slic3r::GUI::AMSMaterialsSetting::get_filament_variant_index(), get_printer_names_by_printer_type_and_nozzle(), and Slic3r::MachineObject::update_printer_preset_name().

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

◆ get_required_hrc_by_filament_type()

const int Slic3r::PresetBundle::get_required_hrc_by_filament_type ( const std::string & filament_type) const
3708{
3709 static std::unordered_map<std::string, int>filament_type_to_hrc;
3710 if (filament_type_to_hrc.empty()) {
3711 for (auto iter = filaments.m_presets.begin(); iter != filaments.m_presets.end(); iter++) {
3712 if (iter->vendor && iter->vendor->id == "BBL") {
3713 if (iter->config.has("filament_type") && iter->config.has("required_nozzle_HRC")) {
3714 auto type = iter->config.opt_string("filament_type", 0);
3715 auto hrc = iter->config.opt_int("required_nozzle_HRC", 0);
3716 filament_type_to_hrc[type] = hrc;
3717 }
3718 }
3719 }
3720 }
3721 auto iter = filament_type_to_hrc.find(filament_type);
3722 if (iter != filament_type_to_hrc.end())
3723 return iter->second;
3724 else
3725 return 0;
3726}

References Slic3r::filament_type(), filaments, and get_required_hrc_by_filament_type().

Referenced by get_required_hrc_by_filament_type().

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

◆ get_similar_printer_preset()

Preset * Slic3r::PresetBundle::get_similar_printer_preset ( std::string printer_model,
std::string printer_variant )
5297{
5298 if (printer_model.empty())
5299 printer_model = printers.get_selected_preset().config.opt_string("printer_model");
5300 if (printer_model.empty()) // ORCA ensure a compatible model exist. fixes switches to blank preset if preset has no inherited value
5301 return nullptr;
5302 auto printer_variant_old = printers.get_selected_preset().config.opt_string("printer_variant");
5303 std::map<std::string, Preset*> printer_presets;
5304 for (auto &preset : printers.m_presets) {
5305 if (printer_variant.empty() && !preset.is_system)
5306 continue;
5307 if (preset.config.opt_string("printer_model") == printer_model)
5308 printer_presets.insert({preset.name, &preset});
5309 }
5310 if (printer_presets.empty())
5311 return nullptr;
5312 auto prefer_printer = printers.get_selected_preset().alias; //.name ORCA use alias instead "name" for calling system presets. otherwise nozzle combo will not change printer presets if they custom named
5313
5314 if (!printer_variant.empty())
5315 boost::replace_all(prefer_printer, printer_variant_old, printer_variant);
5316 else if (auto n = prefer_printer.find(printer_variant_old); n != std::string::npos)
5317 prefer_printer = printer_model + " " + printer_variant_old + prefer_printer.substr(n + printer_variant_old.length());
5318 if (auto iter = printer_presets.find(prefer_printer); iter != printer_presets.end()) {
5319 return iter->second;
5320 }
5321 if (printer_variant.empty())
5322 printer_variant = printer_variant_old;
5323 for (auto& preset : printer_presets) {
5324 if (preset.second->config.opt_string("printer_variant") == printer_variant)
5325 return preset.second;
5326 }
5327 return printer_presets.begin()->second;
5328}

References Slic3r::PresetCollection::begin(), Slic3r::Preset::config, Slic3r::PresetCollection::end(), get_similar_printer_preset(), Slic3r::Preset::is_system, Slic3r::Preset::name, Slic3r::DynamicConfig::opt_string(), and printers.

Referenced by get_similar_printer_preset().

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

◆ get_stl_model_for_printer_model()

std::string Slic3r::PresetBundle::get_stl_model_for_printer_model ( std::string model_name)
1334{
1335 std::string stl_name, vendor_name, out;
1336
1337 for (auto vendor_profile: this->vendors)
1338 {
1339 for (auto vendor_model: vendor_profile.second.models)
1340 {
1341 if (vendor_model.name == model_name)
1342 {
1343 stl_name = vendor_model.bed_model;
1344 vendor_name = vendor_profile.first;
1345 break;
1346 }
1347 }
1348 }
1349
1350 if (!stl_name.empty())
1351 {
1352 out = Slic3r::data_dir() + "/vendor/" + vendor_name + "/" + stl_name;
1353 if (!boost::filesystem::exists(boost::filesystem::path(out)))
1354 out = Slic3r::resources_dir() + "/profiles/" + vendor_name + "/" + stl_name;
1355 }
1356
1357 return out;
1358}

References Slic3r::data_dir(), get_stl_model_for_printer_model(), Slic3r::resources_dir(), and vendors.

Referenced by get_stl_model_for_printer_model().

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

◆ get_texture_for_printer_model()

std::string Slic3r::PresetBundle::get_texture_for_printer_model ( std::string model_name)
1306{
1307 std::string texture_name, vendor_name, out;
1308
1309 for (auto vendor_profile: this->vendors)
1310 {
1311 for (auto vendor_model: vendor_profile.second.models)
1312 {
1313 if (vendor_model.name == model_name || vendor_model.id == model_name)
1314 {
1315 texture_name = vendor_model.bed_texture;
1316 vendor_name = vendor_profile.first;
1317 break;
1318 }
1319 }
1320 }
1321
1322 if (!texture_name.empty())
1323 {
1324 out = Slic3r::data_dir() + "/vendor/" + vendor_name + "/" + texture_name;
1325 if (!boost::filesystem::exists(boost::filesystem::path(out)))
1326 out = Slic3r::resources_dir() + "/profiles/" + vendor_name + "/" + texture_name;
1327 }
1328
1329 return out;
1330}

References Slic3r::data_dir(), get_texture_for_printer_model(), Slic3r::resources_dir(), and vendors.

Referenced by get_texture_for_printer_model().

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

◆ get_used_tpu_filaments()

std::vector< int > Slic3r::PresetBundle::get_used_tpu_filaments ( const std::vector< int > & used_filaments)
5090{
5091 std::vector<int> tpu_filaments;
5092 for (size_t i = 0; i < this->filament_presets.size(); ++i) {
5093 auto iter = std::find(used_filaments.begin(), used_filaments.end(), i + 1);
5094 if (iter == used_filaments.end()) continue;
5095
5096 std::string filament_name = this->filament_presets[i];
5097 for (int f_index = 0; f_index < this->filaments.size(); f_index++) {
5098 PresetCollection *filament_presets = &this->filaments;
5099 Preset *preset = &filament_presets->preset(f_index);
5100 int size = this->filaments.size();
5101 if (preset && filament_name.compare(preset->name) == 0) {
5102 std::string display_filament_type;
5103 std::string filament_type = preset->config.get_filament_type(display_filament_type);
5104 if (display_filament_type == "TPU") {
5105 tpu_filaments.push_back(i);
5106 }
5107 }
5108 }
5109 }
5110 return tpu_filaments;
5111}

References Slic3r::Preset::config, filament_presets, Slic3r::filament_type(), filaments, Slic3r::DynamicPrintConfig::get_filament_type(), get_used_tpu_filaments(), and Slic3r::Preset::name.

Referenced by get_used_tpu_filaments().

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

◆ get_vendor_profile_version()

Semver Slic3r::PresetBundle::get_vendor_profile_version ( std::string vendor_name)
981{
982 Semver result_ver;
983
984 auto vendor_profile = vendors.find(vendor_name);
985 if (vendor_profile != vendors.end()) {
986 result_ver = vendor_profile->second.config_version;
987 }
988
989 return result_ver;
990}

References get_vendor_profile_version(), and vendors.

Referenced by get_vendor_profile_version().

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

◆ has_defauls_only()

bool Slic3r::PresetBundle::has_defauls_only ( ) const
inline
548 { return prints.has_defaults_only() && filaments.has_defaults_only() && printers.has_defaults_only(); }

References filaments, printers, and prints.

◆ has_errors()

bool Slic3r::PresetBundle::has_errors ( bool check_duplicate_filament_subtypes = false) const
8749{
8750 if (m_errors != 0 || printers.m_errors != 0 || filaments.m_errors != 0 || prints.m_errors != 0)
8751 return true;
8752
8753 bool has_errors = false;
8754 // Orca: check if all filament presets have compatible_printers setting
8755 for (auto& preset : filaments) {
8756 if (!preset.is_system)
8757 continue;
8758 // It's per design that the Orca Filament Library can have the empty compatible_printers.
8759 if(preset.vendor->name == PresetBundle::ORCA_FILAMENT_LIBRARY)
8760 continue;
8761 auto* compatible_printers = dynamic_cast<const ConfigOptionStrings*>(preset.config.option("compatible_printers"));
8762 if (compatible_printers == nullptr || compatible_printers->values.empty()) {
8763 has_errors = true;
8764 BOOST_LOG_TRIVIAL(error) << "Filament preset \"" << preset.file << "\" is missing compatible_printers setting";
8765 }
8766 }
8767
8769 has_errors = true;
8770
8771 if (this->check_preset_references())
8772 has_errors = true;
8773
8775 has_errors = true;
8776
8777 return has_errors;
8778}
bool check_preset_references() const
Definition PresetBundle.cpp:8817
bool check_duplicate_filament_subtypes() const
Definition PresetBundle.cpp:8938
bool has_errors(bool check_duplicate_filament_subtypes=false) const
Definition PresetBundle.cpp:8748
bool check_printer_default_materials() const
Definition PresetBundle.cpp:8869

References check_duplicate_filament_subtypes(), check_preset_references(), check_printer_default_materials(), Slic3r::Preset::config, filaments, Slic3r::Preset::file, has_errors(), Slic3r::Preset::is_system, m_errors, Slic3r::VendorProfile::name, Slic3r::ConfigBase::option(), ORCA_FILAMENT_LIBRARY, printers, prints, and Slic3r::Preset::vendor.

Referenced by has_errors().

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

◆ import_json_presets()

bool Slic3r::PresetBundle::import_json_presets ( PresetsConfigSubstitutions & substitutions,
std::string & file,
std::function< int(std::string const &)> override_confirm,
ForwardCompatibilitySubstitutionRule rule,
int & overwrite,
std::vector< std::string > & result,
const std::string & bundle_dir = "",
const std::map< std::string, std::string > & bed_asset_paths = {},
bool * bed_paths_loaded = nullptr )
2568{
2569 try {
2570 DynamicPrintConfig config;
2571 // BBS: change to json format
2572 // ConfigSubstitutions config_substitutions = config.load_from_ini(preset.file, substitution_rule);
2573 std::map<std::string, std::string> key_values;
2574 std::string reason;
2575 ConfigSubstitutions config_substitutions = config.load_from_json(file, rule, key_values, reason);
2576 std::string name = key_values[BBL_JSON_KEY_NAME];
2577 std::string version_str = key_values[BBL_JSON_KEY_VERSION];
2578 boost::optional<Semver> version = Semver::parse(version_str);
2579 if (!version) return false;
2580
2581 std::string type_subdir; // also note the type subdir for bundles
2582 PresetCollection *collection = nullptr;
2583 if (config.has("printer_settings_id")) {
2584 collection = &printers;
2585 type_subdir = PRESET_PRINTER_NAME;
2586 }
2587 else if (config.has("print_settings_id")) {
2588 collection = &prints;
2589 type_subdir = PRESET_PRINT_NAME;
2590 }
2591 else if (config.has("filament_settings_id")) {
2592 collection = &filaments;
2593 type_subdir = PRESET_FILAMENT_NAME;
2594 }
2595 if (collection == nullptr) {
2596 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset type is unknown, not loading: " << name;
2597 return false;
2598 }
2599 if (!is_path_within_root(name, fs::path(collection->m_dir_path))) {
2600 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset name escapes the preset directory, not loading: " << name;
2601 return false;
2602 }
2603 const PresetOrigin load_origin = detect_origin_from_path(boost::filesystem::path(bundle_dir));
2604 const std::string preset_name = get_preset_canonical_name(name, load_origin);
2605
2606 if (overwrite == 0) overwrite = 1;
2607 if (auto p = collection->find_preset(preset_name, false)) {
2608 if (p->is_default || p->is_system) {
2609 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset already present and is system preset, not loading: " << preset_name;
2610 return false;
2611 }
2612 if (overwrite != 2 && overwrite != 3) overwrite = override_confirm(preset_name); //3: yes to all 2: no to all
2613 }
2614 if (overwrite == 0 || overwrite == 2) {
2615 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Preset already present, not loading: " << preset_name;
2616 return false;
2617 }
2618
2619 DynamicPrintConfig new_config;
2620 Preset * inherit_preset = nullptr;
2621 ConfigOption * inherits_config = config.option(BBL_JSON_KEY_INHERITS);
2622 std::string inherits_value;
2623 if (inherits_config) {
2624 ConfigOptionString *option_str = dynamic_cast<ConfigOptionString *>(inherits_config);
2625 inherits_value = option_str->value;
2626 inherit_preset = collection->find_preset2(inherits_value, true);
2627 Preset::normalize_inherits(config, inherit_preset);
2628 if (inherit_preset)
2629 inherits_value = inherit_preset->name; // keep the base_id redo below in sync
2630 }
2631 if (collection == &printers) {
2632 for (const auto &entry : bed_asset_paths)
2633 config.option<ConfigOptionString>(entry.first, true)->value = entry.second;
2634 }
2635 if (inherit_preset) {
2636 new_config = inherit_preset->config;
2637 new_config.apply(std::move(config));
2638 } else {
2639 // We support custom root preset now
2640 auto inherits_config2 = dynamic_cast<ConfigOptionString *>(inherits_config);
2641 if (inherits_config2 && !inherits_config2->value.empty()) {
2642 // we should skip this preset here
2643 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find inherit preset for user preset %1%, just skip") % name;
2644 return false;
2645 }
2646 // Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field.
2647 const Preset &default_preset = collection->default_preset_for(config);
2648 new_config = default_preset.config;
2649 new_config.apply(std::move(config));
2650 extend_default_config_length(new_config, true, default_preset.config);
2651 }
2652 if (bed_paths_loaded != nullptr && collection == &printers && !bed_asset_paths.empty())
2653 *bed_paths_loaded = true;
2654
2655 Preset &preset = collection->load_preset(collection->path_from_name(name, inherit_preset == nullptr), preset_name, std::move(new_config), false);
2656 preset.bundle_id = load_origin.bundle_id;
2657 if (key_values.find(BBL_JSON_KEY_FILAMENT_ID) != key_values.end())
2658 preset.filament_id = key_values[BBL_JSON_KEY_FILAMENT_ID];
2659 preset.is_external = true;
2660 preset.version = *version;
2661 inherit_preset = collection->find_preset(inherits_value, false, true); // pointer maybe wrong after insert, redo find
2662 if (inherit_preset) preset.base_id = inherit_preset->setting_id;
2663 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " " << __LINE__ << preset.name << " have filament_id: " << preset.filament_id << " and base_id: " << preset.base_id;
2664 Preset::normalize(preset.config);
2665 // Report configuration fields, which are misplaced into a wrong group.
2666 const Preset &default_preset = collection->default_preset_for(new_config);
2667 std::string incorrect_keys = Preset::remove_invalid_keys(preset.config, default_preset.config);
2668 if (!incorrect_keys.empty()) {
2669 ++m_errors;
2670 BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" << preset.file
2671 << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
2672 }
2673 if (!config_substitutions.empty())
2674 substitutions.push_back({name, collection->type(), PresetConfigSubstitutions::Source::UserFile, file, std::move(config_substitutions)});
2675 collection->set_custom_preset_alias(preset);
2676
2677 // If bundle_dir is provided, use it for the save operation
2678 if (!bundle_dir.empty()) {
2679 if (!save_preset_to_bundle_dir(preset, collection, load_origin.bundle_id, type_subdir, bundle_dir)) {
2680 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to save preset " << preset_name << " to bundle directory";
2681 return false;
2682 }
2683 } else {
2684 preset.save(inherit_preset ? &inherit_preset->config : nullptr);
2685 }
2686
2687 result.push_back(file);
2688 } catch (const std::ifstream::failure &err) {
2689 ++m_errors;
2690 BOOST_LOG_TRIVIAL(error) << boost::format("The config cannot be loaded: %1%. Reason: %2%") % file % err.what();
2691 } catch (const std::runtime_error &err) {
2692 ++m_errors;
2693 BOOST_LOG_TRIVIAL(error) << boost::format("Failed importing config file: %1%. Reason: %2%") % file % err.what();
2694 }
2695 return true;
2696}
#define BBL_JSON_KEY_VERSION
Definition Preset.hpp:55
#define BBL_JSON_KEY_FILAMENT_ID
Definition Preset.hpp:71
#define BBL_JSON_KEY_INHERITS
Definition Preset.hpp:75
bool save_preset_to_bundle_dir(Preset &preset, PresetCollection *collection, const std::string &bundle_id, const std::string &type_subdir, const std::string &bundle_base_dir)
Definition PresetBundle.cpp:2959
static std::string remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config, const DynamicPrintConfig *added=nullptr)
Definition Preset.cpp:573
static void normalize_inherits(DynamicPrintConfig &cfg, const Preset *resolved_parent)
Definition Preset.hpp:366
static boost::optional< Semver > parse(const std::string &str)
Definition Semver.hpp:63
std::vector< ConfigSubstitution > ConfigSubstitutions
Definition Config.hpp:269
bool is_path_within_root(const std::string &rel_path, const boost::filesystem::path &root)
Definition utils.cpp:1219
PresetOrigin detect_origin_from_path(const boost::filesystem::path &path, const PresetOrigin &explicit_origin)
Definition Preset.cpp:178
std::string get_preset_canonical_name(const std::string &preset_bare_name, const PresetOrigin &origin)
Definition Preset.cpp:134
void extend_default_config_length(DynamicPrintConfig &config, const bool set_nil_to_default, const DynamicPrintConfig &defaults)
Definition Preset.cpp:301
@ UserFile
Definition Preset.hpp:537

References Slic3r::ConfigBase::apply(), Slic3r::Preset::base_id, BBL_JSON_KEY_FILAMENT_ID, BBL_JSON_KEY_INHERITS, BBL_JSON_KEY_NAME, BBL_JSON_KEY_VERSION, Slic3r::Preset::bundle_id, Slic3r::PresetOrigin::bundle_id, Slic3r::Preset::config, Slic3r::PresetCollection::default_preset_for(), Slic3r::detect_origin_from_path(), Slic3r::extend_default_config_length(), Slic3r::Preset::filament_id, filaments, Slic3r::Preset::file, Slic3r::PresetCollection::find_preset(), Slic3r::PresetCollection::find_preset2(), Slic3r::get_preset_canonical_name(), Slic3r::ConfigOptionResolver::has(), import_json_presets(), Slic3r::Preset::is_external, Slic3r::is_path_within_root(), Slic3r::ConfigBase::load_from_json(), Slic3r::PresetCollection::load_preset(), Slic3r::PresetCollection::m_dir_path, m_errors, Slic3r::Preset::name, Slic3r::Preset::normalize(), Slic3r::Preset::normalize_inherits(), Slic3r::ConfigBase::option(), Slic3r::Semver::parse(), Slic3r::PresetCollection::path_from_name(), PRESET_FILAMENT_NAME, PRESET_PRINT_NAME, PRESET_PRINTER_NAME, printers, prints, Slic3r::Preset::remove_invalid_keys(), Slic3r::Preset::save(), save_preset_to_bundle_dir(), Slic3r::PresetCollection::set_custom_preset_alias(), Slic3r::Preset::setting_id, Slic3r::PresetCollection::type(), Slic3r::PresetConfigSubstitutions::UserFile, Slic3r::ConfigOptionSingle< T >::value, and Slic3r::Preset::version.

Referenced by import_json_presets(), and import_presets().

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

◆ import_presets()

PresetsConfigSubstitutions Slic3r::PresetBundle::import_presets ( std::vector< std::string > & files,
std::function< int(std::string const &)> override_confirm,
ForwardCompatibilitySubstitutionRule rule,
AppConfig & config )
2359{
2360 bundles.PauseRead(); // Pause threads from reading
2361 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " entry";
2362 PresetsConfigSubstitutions substitutions;
2363 int overwrite = 0;
2364 std::vector<std::string> result;
2365 std::string user_id = config.get("preset_folder");
2366 if (user_id.empty())
2367 user_id = DEFAULT_USER_FOLDER_NAME;
2368 this->update_user_presets_directory(user_id);
2369 for (auto &file : files) {
2370 if (Slic3r::is_json_file(file)) {
2371 import_json_presets(substitutions, file, override_confirm, rule, overwrite, result);
2372 }
2373 // Determine if it is a preset bundle
2374 if (boost::iends_with(file, ".orca_printer") || boost::iends_with(file, ".orca_bundle") || boost::iends_with(file, ".orca_filament") || boost::iends_with(file, ".zip")) {
2375 boost::system::error_code ec;
2376 // create user folder
2377 fs::path user_folder(data_dir() + "/" + PRESET_USER_DIR);
2378 if (!fs::exists(user_folder)) fs::create_directory(user_folder, ec);
2379 if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " create directory failed: " << ec.message();
2380 // create default folder
2381 fs::path configs_folder(user_folder / user_id);
2382 if (!fs::exists(configs_folder)) fs::create_directory(configs_folder, ec);
2383 if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " create directory failed: " << ec.message();
2384 //create temp folder
2385 //std::string user_default_temp_dir = data_dir() + "/" + PRESET_USER_DIR + "/" + DEFAULT_USER_FOLDER_NAME + "/" + "temp";
2386 // Under cache/, per process and per import, so two instances importing
2387 // at once do not clear each other's extraction and no preset scan reads it.
2388 static std::atomic<unsigned> import_counter{0};
2389 fs::path temp_folder(fs::path(data_dir()) / "cache" / ("import." + std::to_string(get_current_pid()) + "." + std::to_string(import_counter++)));
2390 std::string user_default_temp_dir = temp_folder.make_preferred().string();
2391 fs::create_directories(temp_folder, ec);
2392 if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " create directory failed: " << ec.message();
2393
2394 file = boost::filesystem::path(file).make_preferred().string();
2395 mz_zip_archive zip_archive;
2396 mz_zip_zero_struct(&zip_archive);
2397 mz_bool status;
2398
2399 FILE *zipFile = boost::nowide::fopen(file.c_str(), "rb");
2400 status = mz_zip_reader_init_cfile(&zip_archive, zipFile, 0, MZ_ZIP_FLAG_CASE_SENSITIVE | MZ_ZIP_FLAG_IGNORE_PATH);
2401 if (MZ_FALSE == status) {
2402 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Failed to initialize reader ZIP archive";
2403 if (zipFile != nullptr)
2404 std::fclose(zipFile);
2405 fs::remove_all(temp_folder, ec);
2406 return substitutions;
2407 } else {
2408 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Success to initialize reader ZIP archive";
2409 }
2410
2411 // First, extract bundle_structure.json to get the bundle_id
2412 // Track whether bundle_structure.json exists to determine routing
2413 bool has_bundle_structure = false;
2414 BundleMetadata metadata;
2415 fs::path metadata_path = temp_folder / BUNDLE_STRUCTURE_JSON_NAME;
2416 status = mz_zip_reader_extract_file_to_file(&zip_archive, BUNDLE_STRUCTURE_JSON_NAME, encode_path(metadata_path.string().c_str()).c_str(), MZ_ZIP_FLAG_CASE_SENSITIVE);
2417 if (status) {
2418 if (metadata.load_from_json(metadata_path.string())) {
2419 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Found bundle_id: " << metadata.id << " from " << BUNDLE_STRUCTURE_JSON_NAME;
2420 has_bundle_structure = true;
2421 }
2422 }
2423
2424 if (has_bundle_structure && metadata.id.empty()) {
2425 boost::uuids::uuid uuid = boost::uuids::random_generator()();
2426 metadata.id = to_string(uuid);
2427 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " bundle_id was empty, so generating a UUID: " << metadata.id;
2428 }
2429 if (has_bundle_structure && !is_path_within_root(metadata.id, user_folder / user_id / PRESET_LOCAL_DIR)) {
2430 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " bundle id escapes the bundle directory, not importing: " << metadata.id;
2431 fclose(zipFile);
2432 fs::remove_all(temp_folder, ec);
2433 continue;
2434 }
2435
2436 // Build bundle directory path based on whether bundle_structure.json was present
2437 fs::path bundle_base_dir;
2438 if (has_bundle_structure) {
2439 // Use the bundle ID from metadata when bundle_structure.json exists
2440 bundle_base_dir = user_folder / user_id / PRESET_LOCAL_DIR / metadata.id;
2441 if (!fs::exists(bundle_base_dir))
2442 fs::create_directories(bundle_base_dir, ec);
2443 if (ec)
2444 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to create bundle directory: " << bundle_base_dir.string() << " error: " << ec.message();
2445 } else {
2446 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " No bundle_structure.json found, importing presets into the user preset directory";
2447 }
2448
2449 json bundle_json = json::object();
2450 std::unordered_set<std::string> bed_asset_entries;
2451 std::vector<PendingBedAsset> bed_assets;
2452 std::map<std::string, std::map<std::string, std::string>> bed_paths_by_printer;
2453 bool bed_paths_loaded = false;
2454 if (has_bundle_structure && !bundle_base_dir.empty()) {
2455 try {
2456 boost::nowide::ifstream manifest_in(metadata_path.string());
2457 manifest_in >> bundle_json;
2458 } catch (const std::exception &err) {
2459 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " failed to read bundle manifest: " << err.what();
2460 bundle_json = json::object();
2461 }
2462 std::unordered_set<std::string> zip_entries;
2463 const int zip_file_count = mz_zip_reader_get_num_files(&zip_archive);
2464 for (int zi = 0; zi < zip_file_count; ++zi) {
2465 mz_zip_archive_file_stat st;
2466 if (mz_zip_reader_file_stat(&zip_archive, zi, &st))
2467 zip_entries.insert(zip_slashes(st.m_filename));
2468 }
2469 bed_assets = pending_bed_assets(bundle_json, bundle_base_dir, bed_asset_entries, zip_entries);
2470 for (PendingBedAsset &asset : bed_assets)
2471 if (stage_bed_asset(zip_archive, asset, temp_folder))
2472 bed_paths_by_printer[asset.printer_key].emplace(asset.option, asset.dest);
2473 }
2474
2475 // Extract Files
2476 int num_files = mz_zip_reader_get_num_files(&zip_archive);
2477 const std::map<std::string, std::string> no_bed_paths;
2478 for (int i = 0; i < num_files; i++) {
2479 mz_zip_archive_file_stat file_stat;
2480 status = mz_zip_reader_file_stat(&zip_archive, i, &file_stat);
2481 if (status) {
2482 std::string file_name = file_stat.m_filename;
2483 const std::string zip_entry = zip_slashes(file_name);
2484 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " From zip file: " << file << ". Read file name: " << file_stat.m_filename;
2485 if (is_pending_bed_asset_entry(file_name, bed_asset_entries))
2486 continue;
2487 size_t index = file_name.find_last_of("/\\");
2488 if (std::string::npos != index) {
2489 file_name = file_name.substr(index + 1);
2490 }
2491 if (BUNDLE_STRUCTURE_JSON_NAME == file_name) continue;
2492 if (!is_path_within_root(file_name, temp_folder)) {
2493 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " zip entry escapes the temp directory, skipping: " << file_stat.m_filename;
2494 continue;
2495 }
2496 // create target file path
2497 std::string target_file_path = boost::filesystem::path(temp_folder / file_name).make_preferred().string();
2498
2499 status = mz_zip_reader_extract_to_file(&zip_archive, i, encode_path(target_file_path.c_str()).c_str(), MZ_ZIP_FLAG_CASE_SENSITIVE);
2500 // target file is opened
2501 if (MZ_FALSE == status) {
2502 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Failed to open target file: " << target_file_path;
2503 } else {
2504 const auto paths_it = bed_paths_by_printer.find(zip_entry);
2505 const std::map<std::string, std::string> &this_bed_paths =
2506 paths_it != bed_paths_by_printer.end() ? paths_it->second : no_bed_paths;
2507 bool is_success = import_json_presets(substitutions, target_file_path, override_confirm, rule, overwrite, result,
2508 has_bundle_structure ? bundle_base_dir.string() : std::string(),
2509 this_bed_paths, &bed_paths_loaded);
2510 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " import target file: " << target_file_path << " import result" << is_success;
2511 }
2512 }
2513 }
2514
2515 // Copy into bed/ only after this import loads a printer that still holds the staged path.
2516 // A preset left from an earlier import must not count: declining this import leaves its files alone.
2517 if (bed_paths_loaded) {
2518 for (const PendingBedAsset &asset : bed_assets) {
2519 if (printer_kept_bed_paths(printers, {{asset.option, asset.dest}}))
2520 install_bed_asset(asset);
2521 }
2522 }
2523
2524 // Set imported_time to current time if not already set
2525 if (metadata.imported_time == 0) {
2526 metadata.imported_time = std::time(nullptr);
2527 }
2528
2529 // Only save bundle_metadata.json for bundles (when bundle_structure.json was present)
2530 if (has_bundle_structure) {
2531 // Save metadata to bundle_metadata.json
2532 fs::path metadata_save_path = bundle_base_dir / PRESET_BUNDLE_METADATA;
2533 if (metadata.save_to_json(metadata_save_path.string())) {
2534 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Saved bundle metadata to: " << metadata_save_path.string();
2535
2536 metadata.bundle_type = BundleType::Local;
2537 metadata.path = metadata_save_path.string();
2538 // Store the bundle metadata in m_bundles for tracking
2539
2540
2541 bundles.WriteLock();
2542 bundles.m_bundles[metadata.id] = metadata;
2543 bundles.WriteUnlock();
2544 } else {
2545 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Failed to save bundle metadata to: " << metadata_save_path.string();
2546 }
2547 }
2548
2549 fclose(zipFile);
2550 if (fs::exists(temp_folder)) fs::remove_all(temp_folder, ec);
2551 if (ec) BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " remove directory failed: " << ec.message();
2552 }
2553 }
2554 bundles.UnpauseRead();
2555 files = result;
2556 return substitutions;
2557}
#define BUNDLE_STRUCTURE_JSON_NAME
Definition PresetBundle.hpp:32
#define DEFAULT_USER_FOLDER_NAME
Definition PresetBundle.hpp:31
#define PRESET_BUNDLE_METADATA
Definition Preset.hpp:46
#define PRESET_LOCAL_DIR
Definition Preset.hpp:44
bool import_json_presets(PresetsConfigSubstitutions &substitutions, std::string &file, std::function< int(std::string const &)> override_confirm, ForwardCompatibilitySubstitutionRule rule, int &overwrite, std::vector< std::string > &result, const std::string &bundle_dir="", const std::map< std::string, std::string > &bed_asset_paths={}, bool *bed_paths_loaded=nullptr)
Definition PresetBundle.cpp:2559
PresetBundleMetadata bundles
Definition PresetBundle.hpp:535
void update_user_presets_directory(const std::string preset_folder)
Definition PresetBundle.cpp:3034
std::vector< PendingBedAsset > pending_bed_assets(const json &bundle_json, const fs::path &bundle_dir, std::unordered_set< std::string > &skip_names, const std::unordered_set< std::string > &zip_entries)
Definition PresetBundle.cpp:2212
bool install_bed_asset(const PendingBedAsset &asset)
Definition PresetBundle.cpp:2278
std::string zip_slashes(std::string name)
Definition PresetBundle.cpp:2115
bool printer_kept_bed_paths(const PresetCollection &printers, const std::map< std::string, std::string > &paths)
Definition PresetBundle.cpp:2296
bool is_pending_bed_asset_entry(const std::string &entry, const std::unordered_set< std::string > &names)
Definition PresetBundle.cpp:2291
bool stage_bed_asset(mz_zip_archive &zip, PendingBedAsset &asset, const fs::path &temp_folder)
Definition PresetBundle.cpp:2249
std::string encode_path(const char *src)
Definition utils.cpp:1382
std::vector< PresetConfigSubstitutions > PresetsConfigSubstitutions
Definition Preset.hpp:552
bool is_json_file(const std::string &path)
Definition utils.cpp:1214
unsigned get_current_pid()
Definition utils.cpp:1480
@ Local
Definition PresetBundle.hpp:113
std::string to_string(const Vec2crd &pt)
Definition Point.hpp:165

References BUNDLE_STRUCTURE_JSON_NAME, Slic3r::BundleMetadata::bundle_type, bundles, Slic3r::data_dir(), DEFAULT_USER_FOLDER_NAME, Slic3r::encode_path(), Slic3r::AppConfig::get(), Slic3r::get_current_pid(), Slic3r::BundleMetadata::id, import_json_presets(), import_presets(), Slic3r::BundleMetadata::imported_time, Slic3r::is_json_file(), Slic3r::is_path_within_root(), Slic3r::BundleMetadata::load_from_json(), Slic3r::Local, Slic3r::BundleMetadata::path, PRESET_BUNDLE_METADATA, PRESET_LOCAL_DIR, PRESET_USER_DIR, printers, Slic3r::BundleMetadata::save_to_json(), Slic3r::to_string(), and update_user_presets_directory().

Referenced by import_presets().

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

◆ install_vendor()

size_t Slic3r::PresetBundle::install_vendor ( const std::string & path,
const std::string & vendor_name,
const PresetBundle * base_bundle,
LoadConfigBundleAttributes flags,
const VendorCacheData & entries,
VendorParse * parsed,
bool complete,
PresetsConfigSubstitutions & substitutions )
private
7902{
7903 const bool is_orca_lib = vendor_name == ORCA_FILAMENT_LIBRARY;
7904 const VendorProfile* vendor_profile = &this->vendors.at(vendor_name);
7905 size_t count = 0;
7906 auto install_collection = [&](const std::vector<CachedPreset>& list, std::vector<EntryParse>* list_parsed,
7907 PresetCollection* presets, bool is_from_lib) {
7908 VendorInstall install { path, vendor_name, vendor_profile, base_bundle, flags, presets, is_from_lib, &substitutions };
7909 install_vendor_entries(install, list, list_parsed);
7910 count += install.count;
7911 return install;
7912 };
7913 install_collection(entries.process_entries, parsed ? &parsed->process_entries : nullptr, &this->prints, false);
7914 VendorInstall filaments = install_collection(entries.filament_entries, parsed ? &parsed->filament_entries : nullptr,
7915 &this->filaments, is_orca_lib);
7916 if (is_orca_lib && complete) {
7917 m_config_maps = std::move(filaments.config_maps);
7918 m_filament_id_maps = std::move(filaments.filament_id_maps);
7919 }
7920 install_collection(entries.machine_entries, parsed ? &parsed->machine_entries : nullptr, &this->printers, false);
7921 return count;
7922}
std::map< std::string, std::string > m_filament_id_maps
Definition PresetBundle.hpp:529
void install_vendor_entries(VendorInstall &install, const std::vector< CachedPreset > &entries, std::vector< EntryParse > *parsed)
Definition PresetBundle.cpp:7837
std::map< std::string, DynamicPrintConfig > m_config_maps
Definition PresetBundle.hpp:528
Definition PresetBundle.hpp:821

References PresetBundle(), count, Slic3r::PresetBundle::VendorParse::filament_entries, Slic3r::VendorCacheData::filament_entries, filaments, install_vendor(), install_vendor_entries(), m_config_maps, m_filament_id_maps, Slic3r::PresetBundle::VendorParse::machine_entries, Slic3r::VendorCacheData::machine_entries, ORCA_FILAMENT_LIBRARY, Slic3r::PresetBundle::VendorParse::process_entries, Slic3r::VendorCacheData::process_entries, and vendors.

Referenced by install_vendor(), install_vendor_cache(), and install_vendor_read().

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

◆ install_vendor_cache()

bool Slic3r::PresetBundle::install_vendor_cache ( const std::string & cache_path,
const std::string & vendor_name,
VendorCacheData && data,
const PresetBundle * base_bundle )
private
9116{
9117 // What this bundle had counted before the cache was tried. The caller
9118 // measures its own parse against this same baseline, so a rejection must
9119 // put it back rather than reset it to zero.
9120 const int errors_at_entry = this->m_errors;
9121 try {
9122 this->vendors = std::move(data.vendors);
9123
9124 // What the parse counted before install took over; install recounts its
9125 // own below, so m_errors comes out as a JSON parse would leave it.
9126 m_errors += int(data.parse_errors);
9127
9128 // Stays empty, since the entries were substituted when they were parsed.
9129 PresetsConfigSubstitutions substitutions;
9130 install_vendor(boost::filesystem::path(cache_path).parent_path().string(), vendor_name, base_bundle,
9131 LoadConfigBundleAttribute::LoadSystem, data, nullptr, true, substitutions);
9132 return true;
9133 } catch (const std::exception& e) {
9134 // A cancellation of the caller's task group stops the install without
9135 // anything being wrong with the cache.
9136 if (tbb::is_current_task_group_canceling())
9137 throw;
9138 BOOST_LOG_TRIVIAL(warning) << "PresetBundle: rejecting vendor cache " << cache_path << ": " << e.what();
9139 // Restore a clean state so the caller can fall back to the JSON parse.
9140 this->reset(false);
9141 this->vendors.clear();
9142 this->m_config_maps.clear();
9143 this->m_filament_id_maps.clear();
9144 this->m_errors = errors_at_entry;
9145 // A failure partway through installing may have left presets in some
9146 // collections with hold aliases already registered.
9148 return false;
9149 }
9150}
size_t install_vendor(const std::string &path, const std::string &vendor_name, const PresetBundle *base_bundle, LoadConfigBundleAttributes flags, const VendorCacheData &entries, VendorParse *parsed, bool complete, PresetsConfigSubstitutions &substitutions)
Definition PresetBundle.cpp:7899
void reset(bool delete_files)
Definition PresetBundle.cpp:791
void clear_printer_hold_aliases()
Definition PresetBundle.cpp:3303

References PresetBundle(), clear_printer_hold_aliases(), install_vendor(), install_vendor_cache(), LoadSystem, m_config_maps, m_errors, m_filament_id_maps, reset(), and vendors.

Referenced by install_vendor_cache(), install_vendor_read(), and load_vendor_cache().

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

◆ install_vendor_entries()

void Slic3r::PresetBundle::install_vendor_entries ( VendorInstall & install,
const std::vector< CachedPreset > & entries,
std::vector< EntryParse > * parsed )
private
7839{
7840 assert(parsed == nullptr || parsed->size() == entries.size());
7841 for (const CachedPreset& entry : entries) {
7842 if (! entry.inherits.empty())
7843 install.inherited.insert(entry.inherits);
7844 install.included.insert(entry.includes.begin(), entry.includes.end());
7845 }
7846 // The names an appended preset may not repeat, since the collection cannot be
7847 // searched until it is sorted again.
7848 for (const Preset& preset : install.presets->m_presets)
7849 install.installed_names.insert(preset.name);
7850 // Held until the collection is sorted again, also when an entry throws, so a reader
7851 // holding the lock never finds it unsorted.
7852 install.presets->lock();
7853 ScopeGuard sort_on_exit([&install] {
7854 install.presets->sort_presets();
7855 install.presets->unlock();
7856 });
7857
7858 auto resolve = [&](size_t i) { return resolve_vendor_preset(entries[i], install); };
7859 auto commit = [&](size_t i, PresetInstall&& resolved) {
7860 ConfigSubstitutions substitutions;
7861 if (parsed != nullptr) {
7862 log_errors((*parsed)[i].errors);
7863 for (const std::string& warning : (*parsed)[i].warnings)
7864 BOOST_LOG_TRIVIAL(error) << warning;
7865 substitutions = std::move((*parsed)[i].substitutions);
7866 }
7867 const std::string reason = commit_vendor_preset(entries[i], std::move(resolved), std::move(substitutions), install);
7868 if (! reason.empty()) {
7869 ++m_errors;
7870 const std::string subfile_path = install.path + "/" + install.vendor_name + "/" + entries[i].sub_path;
7871 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": can not install " << entries[i].name << " from " << subfile_path << ": " << reason;
7872 throw failed_loading_error(subfile_path, install.path);
7873 }
7874 };
7875 // A run of entries resolves together and commits in listing order, and ends
7876 // before an entry that inherits or includes one already in it. So no entry
7877 // resolves against a registration from its own run, and the result matches
7878 // installing one at a time.
7879 std::unordered_set<std::string> run_names;
7880 size_t run_begin = 0;
7881 auto install_run = [&](size_t run_end) {
7882 resolve_then_commit(run_end - run_begin,
7883 [&](size_t k) { return resolve(run_begin + k); },
7884 [&](size_t k, PresetInstall&& resolved) { commit(run_begin + k, std::move(resolved)); });
7885 run_names.clear();
7886 run_begin = run_end;
7887 };
7888 auto in_run = [&](const std::string& name) { return run_names.count(name) != 0; };
7889 for (size_t i = 0; i < entries.size(); ++ i) {
7890 const CachedPreset& entry = entries[i];
7891 if (in_run(entry.inherits) || std::any_of(entry.includes.begin(), entry.includes.end(), in_run))
7892 install_run(i);
7893 if (install.inherited.count(entry.name) != 0 || install.included.count(entry.name) != 0)
7894 run_names.insert(entry.name);
7895 }
7896 install_run(entries.size());
7897}
PresetInstall resolve_vendor_preset(const CachedPreset &entry, const VendorInstall &install) const
Definition PresetBundle.cpp:7582
std::string commit_vendor_preset(const CachedPreset &entry, PresetInstall &&resolved, ConfigSubstitutions &&substitutions, VendorInstall &install)
Definition PresetBundle.cpp:7757
Definition PresetBundle.hpp:863
static ConfigurationError failed_loading_error(const std::string &file, const std::string &dir)
Definition PresetBundle.cpp:7569
void resolve_then_commit(size_t count, Resolve resolve, Commit commit)
Definition ParallelResolve.hpp:40

References commit_vendor_preset(), Slic3r::failed_loading_error(), Slic3r::CachedPreset::includes, Slic3r::CachedPreset::inherits, install_vendor_entries(), log_errors(), m_errors, Slic3r::CachedPreset::name, Slic3r::Preset::name, Slic3r::resolve_then_commit(), and resolve_vendor_preset().

Referenced by install_vendor(), and install_vendor_entries().

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

◆ install_vendor_read()

std::pair< PresetsConfigSubstitutions, size_t > Slic3r::PresetBundle::install_vendor_read ( VendorRead && read,
const PresetBundle * base_bundle )
private
8338{
8339 const std::string& dir = read.dir;
8340 const std::string& vendor_name = read.vendor_name;
8341 PresetsConfigSubstitutions substitutions;
8342 if (read.from_cache) {
8343 if (this->install_vendor_cache(read.cache_path, vendor_name, std::move(read.data), base_bundle)) {
8344 size_t presets_loaded = 0;
8345 for (const PresetCollection* coll : std::initializer_list<const PresetCollection*>{
8346 &this->prints, &this->sla_prints, &this->filaments, &this->sla_materials, &this->printers })
8347 presets_loaded += coll->m_presets.size() - coll->m_num_default_presets;
8348 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", %1% served from its preset cache, %2% presets")%vendor_name%presets_loaded;
8349 return std::make_pair(std::move(substitutions), presets_loaded);
8350 }
8351 this->parse_vendor_json(read);
8352 }
8353 if (read.vendor_only)
8354 return std::make_pair(PresetsConfigSubstitutions{}, 0);
8355
8356 int parse_errors = 0;
8357 for (const std::vector<EntryParse>* list : { &read.parsed.process_entries, &read.parsed.filament_entries, &read.parsed.machine_entries })
8358 for (const EntryParse& entry_parsed : *list)
8359 parse_errors += int(entry_parsed.errors.size());
8360 const int errors_before_install = m_errors;
8361 const size_t presets_loaded = install_vendor(dir, vendor_name, base_bundle, read.flags, read.data, &read.parsed,
8362 read.reason.empty(), substitutions);
8363 // Errors added by install are counted apart: a cache load runs install again,
8364 // so the parse_errors stamped into the cache must hold only what a cache load
8365 // will not recount.
8366 const int install_errors = m_errors - errors_before_install - parse_errors;
8367 if (! read.reason.empty()) {
8368 log_errors(read.failed_errors);
8369 ++m_errors;
8370 //parse error
8371 std::string subfile_path = dir + "/" + vendor_name + "/" + read.failed_subfile;
8372 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", got error when parse %1% setting from %2%") % read.failed_kind % subfile_path;
8373 throw failed_loading_error(subfile_path, dir);
8374 }
8375
8376 if (read.will_cache) {
8377 // Clamped: the count is a difference of three tallies, and a stamp that
8378 // wrapped would be added to every future load of this vendor.
8379 read.data.parse_errors = uint64_t(std::max(0, m_errors - read.errors_at_entry - install_errors));
8380 read.data.vendors = this->vendors;
8381 if (! VendorCacheFile::save((boost::filesystem::path(dir) / (vendor_name + ".opc")).string(), vendor_name,
8382 read.version, read.data))
8383 BOOST_LOG_TRIVIAL(warning) << "PresetBundle: failed to save vendor cache for " << vendor_name;
8384 }
8385
8386 //BBS: add config related logs
8387 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(", finished, presets_loaded %1%")%presets_loaded;
8388 return std::make_pair(std::move(substitutions), presets_loaded);
8389}
void parse_vendor_json(VendorRead &read)
Definition PresetBundle.cpp:7981
bool install_vendor_cache(const std::string &cache_path, const std::string &vendor_name, VendorCacheData &&data, const PresetBundle *base_bundle)
Definition PresetBundle.cpp:9114
Definition PresetBundle.hpp:749
static bool save(const std::string &path, const std::string &vendor_name, const std::string &vendor_version, const VendorCacheData &data)
Definition PresetCacheFormat.cpp:444
void read(const nlohmann::json &j, const char *k, T &out)
Definition TextureDisplacement.cpp:5749

References PresetBundle(), Slic3r::failed_loading_error(), filaments, install_vendor(), install_vendor_cache(), install_vendor_read(), log_errors(), m_errors, parse_vendor_json(), printers, prints, Slic3r::VendorCacheFile::save(), sla_materials, sla_prints, and vendors.

Referenced by install_vendor_read(), and load_vendor_configs_from_json().

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

◆ is_bbl_vendor()

bool Slic3r::PresetBundle::is_bbl_vendor ( )
inline
VendorType get_current_vendor_type()
Definition PresetBundle.cpp:992

References get_current_vendor_type(), and Marlin_BBL.

Referenced by Slic3r::GUI::Plater::_calib_pa_pattern(), Slic3r::GUI::Plater::_calib_pa_pattern_gen_gcode(), Slic3r::GUI::MainFrame::create_side_tools(), Slic3r::GUI::Plater::export_3mf(), Slic3r::GUI::PartPlate::get_effective_exclusion_filament_maps(), Slic3r::GUI::Sidebar::priv::layout_printer(), Slic3r::GUI::Plater::priv::load_files(), Slic3r::GUI::ArrangeJob::process(), Slic3r::GUI::FillBedJob::process(), Slic3r::BackgroundSlicingProcess::process_fff(), Slic3r::GUI::PartPlate::refresh_imex_icon(), Slic3r::GUI::PartPlate::register_raycasters_for_picking(), Slic3r::GUI::PartPlate::render_icons(), Slic3r::GUI::set_arrange_polygon_bed_exclusion_extruders(), Slic3r::GUI::PartPlate::set_shape(), Slic3r::GUI::Sidebar::should_show_SEMM_buttons(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_config(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_selection(), Slic3r::GUI::try_pop_up_before_slice(), Slic3r::GUI::Sidebar::update_all_preset_comboboxes(), Slic3r::GUI::Sidebar::update_presets(), use_bbl_device_tab(), and use_bbl_network().

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

◆ is_mixed_filament()

bool Slic3r::PresetBundle::is_mixed_filament ( size_t idx) const
4466{
4467 auto *opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
4468 return opt && idx < opt->values.size() && opt->values[idx];
4469}

References is_mixed_filament(), and project_config.

Referenced by Slic3r::anonymous_namespace{PluginHostPresets.cpp}::bind_filament_target(), is_mixed_filament(), load_config_file_config(), and physical_filament_config_indices().

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

◆ is_the_only_edited_filament()

bool Slic3r::PresetBundle::is_the_only_edited_filament ( unsigned int filament_index)
5332{
5333 unsigned n = this->filament_presets.size();
5334 if (filament_index >= n)
5335 return false;
5336
5337 std::string name = this->filament_presets[filament_index];
5338 Preset& edited_preset = this->filaments.get_edited_preset();
5339 if (edited_preset.name != name)
5340 return false;
5341
5342 unsigned index = 0;
5343 while (index < n)
5344 {
5345 if (index == filament_index) {
5346 index ++;
5347 continue;
5348 }
5349 std::string filament_preset = this->filament_presets[index];
5350 if (edited_preset.name == filament_preset)
5351 return false;
5352 else
5353 index ++;
5354 }
5355 return true;
5356}

References filament_presets, filaments, is_the_only_edited_filament(), and Slic3r::Preset::name.

Referenced by is_the_only_edited_filament().

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

◆ legacy_user_filament_presets()

std::vector< LegacyUserFilamentPreset > Slic3r::PresetBundle::legacy_user_filament_presets ( )
1104{
1105 return filaments.legacy_user_filament_presets(legacy_compatible_printers());
1106}
static std::map< std::string, std::vector< std::string > > legacy_compatible_printers()
Definition PresetBundle.cpp:109

References filaments, Slic3r::legacy_compatible_printers(), and legacy_user_filament_presets().

Referenced by legacy_user_filament_presets().

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

◆ list_local_bundle_ids()

std::vector< std::string > Slic3r::PresetBundle::list_local_bundle_ids ( const std::string & preset_folder)
1580{
1581 std::vector<std::string> ids;
1582 const std::string user = preset_folder.empty() ? DEFAULT_USER_FOLDER_NAME : preset_folder;
1583 if (!is_single_path_component(user))
1584 return ids;
1585
1586 const fs::path user_dir = fs::path(data_dir()) / PRESET_USER_DIR / user;
1587 const fs::path local_dir = user_dir / PRESET_LOCAL_DIR;
1588 try {
1589 if (!fs::is_directory(local_dir))
1590 return ids;
1591 for (const auto& entry : fs::directory_iterator(local_dir)) {
1592 const std::string bundle_id = entry.path().filename().string();
1593 try {
1594 BundleMetadata metadata;
1595 std::string error;
1596 if (check_local_bundle(bundles, user_dir, bundle_id, metadata, error))
1597 ids.push_back(bundle_id);
1598 } catch (const std::exception& exception) {
1599 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": skipping " << bundle_id << ": " << exception.what();
1600 }
1601 }
1602 } catch (const std::exception& exception) {
1603 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": " << exception.what();
1604 }
1605 std::sort(ids.begin(), ids.end());
1606 return ids;
1607}
static bool is_single_path_component(const std::string &value)
Definition PresetBundle.cpp:1541
static bool check_local_bundle(PresetBundleMetadata &bundles, const fs::path &user_dir, const std::string &bundle_id, BundleMetadata &metadata, std::string &error)
Definition PresetBundle.cpp:1548

References bundles, Slic3r::check_local_bundle(), Slic3r::data_dir(), DEFAULT_USER_FOLDER_NAME, Slic3r::is_single_path_component(), list_local_bundle_ids(), PRESET_LOCAL_DIR, and PRESET_USER_DIR.

Referenced by Slic3r::anonymous_namespace{PluginHostPresets.cpp}::list_bundle_ids(), and list_local_bundle_ids().

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

◆ load_config_file()

ConfigSubstitutions Slic3r::PresetBundle::load_config_file ( const std::string & path,
ForwardCompatibilitySubstitutionRule compatibility_rule )
5868{
5869 if (is_gcode_file(path)) {
5870 //BBS: add config related logs
5871 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, gcodefile %1%, compatibility_rule %2%")%path %compatibility_rule;
5872 ConfigSubstitutions config_substitutions;
5873 DynamicPrintConfig config = config_from_gcode(path, compatibility_rule, config_substitutions);
5874 load_config_file_config(path, true, std::move(config));
5875 return config_substitutions;
5876 }
5877
5878 //BBS: add config related logs
5879 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" can not load config file %1% not from gcode")%path ;
5880 throw Slic3r::RuntimeError((boost::format(L("Unknown configuration file: %1%")) % path).str());
5881
5882 return ConfigSubstitutions{};
5883}
#define L(s)
Definition ExtrusionEntity.cpp:25
DynamicPrintConfig config_from_gcode(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule, ConfigSubstitutions &substitutions) const
Definition PresetBundle.cpp:5885
void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config, Semver file_version=Semver(), bool selected=false, PublishedConfig *published_config=nullptr)
Definition PresetBundle.cpp:6122
bool is_gcode_file(const std::string &path)
Definition utils.cpp:1208

References config_from_gcode(), Slic3r::is_gcode_file(), L, load_config_file(), and load_config_file_config().

Referenced by load_config_file().

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

◆ load_config_file_config()

void Slic3r::PresetBundle::load_config_file_config ( const std::string & name_or_path,
bool is_external,
DynamicPrintConfig && config,
Semver file_version = Semver(),
bool selected = false,
PublishedConfig * published_config = nullptr )
private
6123{
6125
6126 // A "published" 3MF project keeps the user's currently-selected presets and overlays only
6127 // the author-selected published keys onto the edited presets.
6128 const bool is_published = published_config != nullptr && published_config->published;
6129
6130 auto clear_compatible_printers = [](DynamicPrintConfig& config){
6131 ConfigOption *opt_compatible = config.optptr("compatible_printers");
6132 if (opt_compatible != nullptr) {
6133 assert(opt_compatible->type() == coStrings);
6134 if (opt_compatible->type() == coStrings)
6135 static_cast<ConfigOptionStrings*>(opt_compatible)->values.clear();
6136 }
6137 };
6138 clear_compatible_printers(config);
6139
6140 // Dynamic per-nozzle filament mapping reflects live device state, not a stored setting;
6141 // drop it from any imported config so it only comes from the connected printer.
6142 config.erase("enable_filament_dynamic_map");
6143
6144#if 0
6145 size_t num_extruders = (printer_technology == ptFFF) ?
6146 std::min(config.option<ConfigOptionFloats>("nozzle_diameter" )->values.size(),
6147 config.option<ConfigOptionFloats>("filament_diameter")->values.size()) :
6148 // 1 SLA material
6149 1;
6150#else
6151 // BBS: use filament_colour insteadof filament_settings_id, filament_settings_id sometimes is not generated
6152 ConfigOptionStrings* filament_colour_option = config.option<ConfigOptionStrings>("filament_colour");
6153 size_t num_filaments = filament_colour_option?filament_colour_option->size():0;
6154 if (num_filaments == 0)
6155 throw Slic3r::RuntimeError((boost::format(L("Invalid configuration file: %1%")) % name_or_path).str());
6156#endif
6157
6158 //BBS: add config related logs
6159 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": , name_or_path %1%, is_external %2%, num_filaments %3%") % name_or_path % is_external % num_filaments;
6160 // Make a copy of the "compatible_machine_expression_group" and "inherits_group" vectors, which
6161 // accumulate values over all presets (print, filaments, printers).
6162 // These values will be distributed into their particular presets when loading.
6163 std::vector<std::string> compatible_printers_condition_values = std::move(config.option<ConfigOptionStrings>("compatible_machine_expression_group", true)->values);
6164 std::vector<std::string> compatible_prints_condition_values = std::move(config.option<ConfigOptionStrings>("compatible_process_expression_group", true)->values);
6165 std::vector<std::string> inherits_values = std::move(config.option<ConfigOptionStrings>("inherits_group", true)->values);
6166 std::vector<std::string> filament_ids = std::move(config.option<ConfigOptionStrings>("filament_ids", true)->values);
6167 std::vector<std::string> print_compatible_printers = std::move(config.option<ConfigOptionStrings>("print_compatible_printers", true)->values);
6168 //BBS: add different settings check logic
6169 bool has_different_settings_to_system = config.option("different_settings_to_system")?true:false;
6170 std::vector<std::string> different_values = std::move(config.option<ConfigOptionStrings>("different_settings_to_system", true)->values);
6171 std::string &compatible_printers_condition = Preset::compatible_printers_condition(config);
6172 std::string &compatible_prints_condition = Preset::compatible_prints_condition(config);
6173 std::string &inherits = Preset::inherits(config);
6174 compatible_printers_condition_values.resize(num_filaments + 2, std::string());
6175 compatible_prints_condition_values.resize(num_filaments, std::string());
6176 inherits_values.resize(num_filaments + 2, std::string());
6177 different_values.resize(num_filaments + 2, std::string());
6178 filament_ids.resize(num_filaments, std::string());
6179 // The "default_filament_profile" will be later extracted into the printer profile.
6180 switch (printer_technology) {
6181 case ptFFF:
6182 config.option<ConfigOptionString>("default_print_profile", true);
6183 config.option<ConfigOptionStrings>("default_filament_profile", true);
6184 break;
6185 case ptSLA:
6186 config.option<ConfigOptionString>("default_sla_print_profile", true);
6187 config.option<ConfigOptionString>("default_sla_material_profile", true);
6188 break;
6189 default: break;
6190 }
6191
6192 bool process_multi_extruder = false;
6193 std::vector<int> filament_variant_index;
6194 size_t extruder_variant_count;
6195 // A config loaded over the full defaults has a one-entry index even when the file has none.
6196 ConfigOptionInts* filament_self_index_opt = config.option<ConfigOptionInts>("filament_self_index", true);
6197 if (filament_self_index_opt->size() < num_filaments) {
6198 std::vector<int>& filament_self_indice = filament_self_index_opt->values;
6199 filament_self_indice.resize(num_filaments);
6200 for (int index = 0; index < num_filaments; index++)
6201 filament_self_indice[index] = index + 1;
6202 }
6203 std::vector<int> filament_self_indice = std::move(filament_self_index_opt->values);
6204 // ORCA: Initialize filament_extruder_variant for backward compatibility with old 3mf files
6205 // that don't have this option saved or have it with default single-element value
6206 ConfigOptionStrings* filament_extruder_variant_opt = config.option<ConfigOptionStrings>("filament_extruder_variant");
6207 if (!filament_extruder_variant_opt || filament_extruder_variant_opt->size() < num_filaments) {
6208 std::vector<std::string>& filament_extruder_variant = config.option<ConfigOptionStrings>("filament_extruder_variant", true)->values;
6209 filament_extruder_variant.resize(num_filaments, "Direct Drive Standard");
6210 }
6211 if (config.option("extruder_variant_list")) {
6212 //3mf support multiple extruder logic
6213 size_t extruder_count = config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
6214 extruder_variant_count = config.option<ConfigOptionStrings>("filament_extruder_variant", true)->size();
6215 if ((extruder_variant_count != filament_self_indice.size())
6216 || (extruder_variant_count < num_filaments)) {
6217 assert(false);
6218 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": invalid config file %1%, can not find suitable filament_extruder_variant or filament_self_index") % name_or_path;
6219 throw Slic3r::RuntimeError((boost::format(L("Invalid configuration file: %1%")) % name_or_path).str());
6220 }
6221 if (num_filaments != extruder_variant_count) {
6222 process_multi_extruder = true;
6223 filament_variant_index.resize(num_filaments, 0);
6224
6225 size_t cur_filament_id = 1;
6226 for (size_t index = 0; index < filament_self_indice.size(); index++) {
6227 if (filament_self_indice[index] == cur_filament_id) {
6228 filament_variant_index[cur_filament_id - 1] = index;
6229 cur_filament_id++;
6230 if (cur_filament_id > num_filaments)
6231 break;
6232 }
6233 }
6234 }
6235 }
6236 //no need to parse extruder_ams_count
6237 std::vector<std::string> extruder_ams_count = std::move(config.option<ConfigOptionStrings>("extruder_ams_count", true)->values);
6238 config.erase("extruder_ams_count");
6239 if (this->extruder_ams_counts.empty())
6240 this->extruder_ams_counts = get_extruder_ams_count(extruder_ams_count);
6241
6242
6243 // 1) Create a name from the file name.
6244 // Keep the suffix (.ini, .gcode, .amf, .3mf etc) to differentiate it from the normal profiles.
6245 std::string name = is_external ? boost::filesystem::path(name_or_path).filename().string() : name_or_path;
6246
6247 // 2) If the loading succeeded, split and load the config into print / filament / printer settings.
6248 // First load the print and printer presets.
6249
6250 auto load_preset =
6251 [&config, &inherits, &inherits_values,
6252 &compatible_printers_condition, &compatible_printers_condition_values,
6253 &compatible_prints_condition, &compatible_prints_condition_values,
6254 is_external, &name, &name_or_path, file_version, selected]
6255 (PresetCollection &presets, size_t idx, const std::string &key, const std::set<std::string> &different_keys, std::string filament_id) {
6256 // Split the "compatible_printers_condition" and "inherits" values one by one from a single vector to the print & printer profiles.
6257 inherits = inherits_values[idx];
6258 compatible_printers_condition = compatible_printers_condition_values[idx];
6259 if (idx > 0 && idx - 1 < compatible_prints_condition_values.size())
6260 compatible_prints_condition = compatible_prints_condition_values[idx - 1];
6261 //BBS: add config related logs
6262 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": , name %1%, is_external %2%, inherits %3%")%name %is_external %inherits;
6263 if (is_external)
6264 presets.load_external_preset(name_or_path, name, config.opt_string(key, true), config, different_keys, PresetCollection::LoadAndSelect::Always, file_version, filament_id);
6265 else
6266 presets.load_preset(presets.path_from_name(name, inherits.empty()), name, config, selected, file_version).save(nullptr);
6267 };
6268
6269 switch (Preset::printer_technology(config)) {
6270 case ptFFF:
6271 {
6272 // A "published" 3MF project keeps the user's currently-selected presets, so the
6273 // print / printer / filament presets are NOT loaded from the file. Only the
6274 // project config values and the published keys are applied below.
6275 if (!is_published) {
6276 //BBS: add different settings logic
6277 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": load print preset from print_settings_id");
6278 std::set<std::string> print_different_keys_set = project_different_keys(different_values[0]);
6279 if (!print_compatible_printers.empty()) {
6280 ConfigOptionStrings* compatible_printers = config.option<ConfigOptionStrings>("compatible_printers", true);
6281 compatible_printers->values = print_compatible_printers;
6282 }
6283
6284 load_preset(this->prints, 0, "print_settings_id", print_different_keys_set, std::string());
6285
6286 //clear compatible printers
6287 clear_compatible_printers(config);
6288
6289 std::set<std::string> printer_different_keys_set = project_different_keys(different_values[num_filaments + 1]);
6290 //BBS: add config related logs
6291 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": load printer preset from printer_settings_id");
6292 load_preset(this->printers, num_filaments + 1, "printer_settings_id", printer_different_keys_set, std::string());
6293
6294 // 3) Now load the filaments. If there are multiple filament presets, split them and load them.
6295 auto old_filament_profile_names = config.option<ConfigOptionStrings>("filament_settings_id", true);
6296 old_filament_profile_names->values.resize(num_filaments, std::string());
6297
6298 auto old_machine_profile_name = config.option<ConfigOptionString>("printer_settings_id", true);
6299
6300 if (num_filaments <= 1) {
6301 // Split the "compatible_printers_condition" and "inherits" values from the cummulative vectors to separate filament presets.
6302 inherits = inherits_values[1];
6303 compatible_printers_condition = compatible_printers_condition_values[1];
6304 compatible_prints_condition = compatible_prints_condition_values.front();
6305 Preset *loaded = nullptr;
6306
6307 //BBS: add different settings logic
6308 std::set<std::string> filament_different_keys_set = project_different_keys(different_values[1]);
6309
6310 std::string filament_id = filament_ids[0];
6311 //BBS: add config related logs
6312 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": load single filament preset from filament_settings_id");
6313 if (is_external) {
6314 if (inherits.empty())
6315 convert_filament_preset_name(old_machine_profile_name->value, old_filament_profile_names->values.front());
6316 else
6317 convert_filament_preset_name(old_machine_profile_name->value, inherits);
6318 loaded = this->filaments.load_external_preset(name_or_path, name, old_filament_profile_names->values.front(), config, filament_different_keys_set, PresetCollection::LoadAndSelect::Always, file_version, filament_id).first;
6319 }
6320 else {
6321 // called from Config Wizard.
6322 loaded= &this->filaments.load_preset(this->filaments.path_from_name(name, inherits.empty()), name, config, true, file_version);
6323 loaded->save(nullptr);
6324 }
6325 this->filament_presets.clear();
6326 this->filament_presets.emplace_back(loaded->name);
6327 } else {
6328 assert(is_external);
6329 // Split the filament presets, load each of them separately.
6330 std::vector<DynamicPrintConfig> configs(num_filaments, this->filaments.default_preset().config);
6331 // loop through options and scatter them into configs.
6332 for (const t_config_option_key &key : this->filaments.default_preset().config.keys()) {
6333 ConfigOption *other_opt = config.option(key);
6334 if (other_opt == nullptr)
6335 continue;
6336 if (other_opt->is_scalar()) {
6337 for (size_t i = 0; i < configs.size(); ++ i)
6338 configs[i].option(key, false)->set(other_opt);
6339 }
6340 else if (key != "compatible_printers" && key != "compatible_prints") {
6341 for (size_t i = 0; i < configs.size(); ++i) {
6342 if (process_multi_extruder && (filament_options_with_variant.find(key) != filament_options_with_variant.end())) {
6343 ConfigOptionVectorBase* other_opt_vec = static_cast<ConfigOptionVectorBase*>(other_opt);
6344 if (other_opt_vec->size() != extruder_variant_count) {
6345 other_opt_vec->resize(extruder_variant_count);
6346 }
6347 size_t next_index = (i < (configs.size() - 1)) ? filament_variant_index[i + 1] : extruder_variant_count;
6348 static_cast<ConfigOptionVectorBase*>(configs[i].option(key, false))->set(other_opt, filament_variant_index[i], next_index - filament_variant_index[i]);
6349 }
6350 else
6351 static_cast<ConfigOptionVectorBase*>(configs[i].option(key, false))->set_at(other_opt, 0, i);
6352 }
6353 }
6354 }
6355 // Load the configs into this->filaments and make them active.
6356 this->filament_presets = std::vector<std::string>(configs.size());
6357 // To avoid incorrect selection of the first filament preset (means a value of Preset->m_idx_selected)
6358 // in a case when next added preset take a place of previosly selected preset,
6359 // we should add presets from last to first
6360 bool any_modified = false;
6361 //BBS: add config related logs
6362 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": load multiple filament preset from filament_settings_id");
6363 for (int i = (int)configs.size()-1; i >= 0; i--) {
6364 DynamicPrintConfig &cfg = configs[i];
6365 // Split the "compatible_printers_condition" and "inherits" from the cummulative vectors to separate filament presets.
6366 cfg.opt_string("compatible_printers_condition", true) = compatible_printers_condition_values[i + 1];
6367 cfg.opt_string("compatible_prints_condition", true) = compatible_prints_condition_values[i];
6368 cfg.opt_string("inherits", true) = inherits_values[i + 1];
6369
6370 //BBS: add different settings logic
6371 std::set<std::string> filament_different_keys_set = project_different_keys(different_values[i+1]);
6372
6373 std::string filament_id = filament_ids[i];
6374
6375 // Load all filament presets, but only select the first one in the preset dialog.
6376 std::string& filament_inherit = cfg.opt_string("inherits", true);
6377 if (filament_inherit.empty() && (i < int(old_filament_profile_names->values.size())))
6378 convert_filament_preset_name(old_machine_profile_name->value, old_filament_profile_names->values[i]);
6379 else
6380 convert_filament_preset_name(old_machine_profile_name->value, filament_inherit);
6381 auto [loaded, modified] = this->filaments.load_external_preset(name_or_path, name,
6382 (i < int(old_filament_profile_names->values.size())) ? old_filament_profile_names->values[i] : "",
6383 std::move(cfg),
6384 filament_different_keys_set,
6385 i == 0 ?
6387 any_modified ?
6390 file_version,
6391 filament_id);
6392 any_modified |= modified;
6393 this->filament_presets[i] = loaded->name;
6394 }
6395 }
6396 } // !is_published
6397
6398 // Load the project config values. In published mode only the plate/bed geometry keys
6399 // cross over (the receiver must not inherit the author's filament/purge data).
6400 this->project_config.apply_only(config, is_published ? s_project_options_published : s_project_options);
6401 // Older projects inherit one-element mixed defaults, regardless of their filament count.
6402 if (!is_published)
6403 resize_mixed_filament_metadata(this->project_config, num_filaments, num_filaments);
6404
6405 break;
6406 }
6407 case ptSLA:
6408 {
6409 /*std::set<std::string> different_keys_set;
6410 load_preset(this->sla_prints, 0, "sla_print_settings_id", different_keys_set);
6411 load_preset(this->sla_materials, 1, "sla_material_settings_id", different_keys_set);
6412 load_preset(this->printers, 2, "printer_settings_id", different_keys_set);*/
6413 break;
6414 }
6415 default:
6416 break;
6417 }
6418
6421
6422 // A "published" 3MF project overlays the author-selected published keys onto the user's
6423 // currently-selected (edited) process preset. Keys that cannot be applied are collected for
6424 // notification; filament-class keys in published_keys (which only the material pass knows
6425 // how to apply) fall through into skipped_keys.
6426 if (is_published) {
6427 std::vector<std::string> skipped_keys;
6428 std::set<std::string> applied_keys;
6429 // Only re-select the edited filament preset when the material overlay changed
6430 // something: re-selecting unconditionally would discard the user's unsaved in-memory
6431 // filament edits when the published file touches nothing.
6432 bool material_applied = false;
6433 // Structural keys are never applied (they would rewrite the user's preset
6434 // inheritance/structure). Defense-in-depth: a hand-crafted 3MF could list them despite
6435 // the dialog, so skip them here too.
6436 const std::set<std::string>& structural_keys = publish_structural_keys();
6437 // The printer overlay is restricted to the publishable retraction/z-hop allowlist;
6438 // printer-class keys outside it are contract-excluded (never applied, never reported).
6439 const std::set<std::string>& printer_allowlist = publishable_printer_keys();
6440 const std::vector<std::string>& printer_options = Preset::printer_options();
6441 const std::set<std::string> printer_option_set(printer_options.begin(), printer_options.end());
6442 std::set<std::string> contract_excluded_keys;
6443 auto apply_published = [&](DynamicPrintConfig& target, const std::set<std::string>* allowlist) {
6444 // Single-extruder receivers collapse a base key's per-extruder "#N" variants onto
6445 // their single slot: only the first serialized variant of a base key is applied
6446 // (the author's "left or right" whichever came first), the rest are reported as
6447 // skipped. Per-target, so the process and printer passes each track their own bases.
6448 std::set<std::string> collapsed_bases;
6449 for (const std::string& key : published_config->published_keys) {
6450 if (applied_keys.count(key) != 0)
6451 continue; // already applied
6452 // A '#' suffix denotes a variant key; resolve the base key.
6453 const std::string base_key = publish_base_key(key);
6454 // Structural keys are never applied (not "skipped due to mismatch"), so bail
6455 // out before the applied/skipped bookkeeping.
6456 if (structural_keys.count(base_key) != 0)
6457 continue;
6458 if (allowlist != nullptr && printer_option_set.count(base_key) != 0 && allowlist->count(base_key) == 0) {
6459 // Printer-class key outside the publishable allowlist: contract-excluded.
6460 contract_excluded_keys.insert(base_key);
6461 continue;
6462 }
6463 const ConfigOption* src_opt = config.option(base_key);
6464 if (src_opt == nullptr)
6465 continue; // key not present in the loaded config; record later
6466 if (src_opt->is_vector()) {
6467 ConfigOption* dst_opt = target.option(base_key);
6468 if (dst_opt == nullptr || !dst_opt->is_vector())
6469 continue; // cannot apply; will be reported as skipped
6470 // Type mismatch: ConfigOptionVector::set() throws ConfigurationError on a
6471 // mismatch, which would abort the whole project load; report the key as
6472 // skipped instead (the material pass guards the same way). Note that the
6473 // nullable variants report the same type() as their non-nullable base, so
6474 // this catches genuinely different option kinds (e.g. a string where a float
6475 // vector is expected), not nullable-ness.
6476 if (dst_opt->type() != src_opt->type())
6477 continue;
6478 // A '#N' variant key (e.g. per-extruder retraction_length#2) applies one
6479 // element, so the index only needs to be in range on the author's side - the
6480 // receiver may have a different extruder count than the author. Out-of-range
6481 // indices are skipped (set_at would otherwise resize the receiver's vector).
6482 if (key.size() > base_key.size()) {
6483 // Strict numeric suffix parse: a malformed variant ("#abc", "#1x")
6484 // must be reported as skipped, not silently applied as element 0.
6485 const std::string suffix = key.substr(base_key.size() + 1);
6486 size_t idx = 0;
6487 bool valid = !suffix.empty();
6488 for (const char c : suffix) {
6489 if (c < '0' || c > '9') {
6490 valid = false;
6491 break;
6492 }
6493 idx = idx * 10 + size_t(c - '0');
6494 if (idx > 1000000) { // overflow guard; real vector sizes are tiny
6495 valid = false;
6496 break;
6497 }
6498 }
6499 const size_t src_size = static_cast<const ConfigOptionVectorBase*>(src_opt)->size();
6500 if (!valid || idx >= src_size)
6501 continue; // malformed or out-of-range on the author's side: cannot apply; reported as skipped
6502 const size_t dst_size = static_cast<const ConfigOptionVectorBase*>(dst_opt)->size();
6503 if (dst_size == 1) {
6504 // Single-extruder receiver: collapse the author's per-extruder slots
6505 // onto the receiver's single slot. Only the first serialized variant
6506 // of a base key is applied (the author's "left or right" whichever was
6507 // published first); later variants of the same base are reported as
6508 // skipped, mirroring the receiver's single extruder.
6509 if (collapsed_bases.count(base_key) != 0)
6510 continue;
6511 collapsed_bases.insert(base_key);
6512 static_cast<ConfigOptionVectorBase*>(dst_opt)->set_at(src_opt, 0, idx);
6513 } else {
6514 if (idx >= dst_size)
6515 continue; // out-of-range variant: cannot apply; reported as skipped
6516 target.apply_only(config, {key}, true);
6517 }
6518 } else if (static_cast<const ConfigOptionVectorBase*>(src_opt)->size() !=
6519 static_cast<const ConfigOptionVectorBase*>(dst_opt)->size()) {
6520 // Whole-vector base key: the receiver must have a matching vector size,
6521 // otherwise applying would overwrite a different number of elements.
6522 continue; // cannot apply; will be reported as skipped
6523 } else {
6524 target.apply_only(config, {key}, true);
6525 }
6526 applied_keys.insert(key);
6527 } else {
6528 // A scalar key cannot carry a '#N' suffix; a hand-crafted file listing one
6529 // is reported as skipped instead of being silently marked applied.
6530 if (key.find('#') != std::string::npos)
6531 continue;
6532 // Scalar key: apply only if present on the user's machine.
6533 const ConfigOption* dst_opt = target.option(base_key);
6534 if (dst_opt == nullptr)
6535 continue; // not present on the edited preset; will be reported as skipped
6536 // Type mismatch: skipped, never thrown (see the vector branch above).
6537 if (dst_opt->type() != src_opt->type())
6538 continue;
6539 target.apply_only(config, {key}, true);
6540 applied_keys.insert(key);
6541 }
6542 }
6543 };
6544 apply_published(this->prints.get_edited_preset().config, nullptr);
6545 apply_published(this->printers.get_edited_preset().config, &printer_allowlist);
6546
6547 // Material pass: positional per-slot entries. The author published, per slot, either the
6548 // entire filament (full) or specific keys plus optionally a curated type and/or colour.
6549 // - full: lands on a freshly created standalone detached copy (no library preset used
6550 // or mutated);
6551 // - partial: a type requirement gates application; on mismatch the slot is replaced
6552 // with the best visible candidate by published identity (exact name, setting_id,
6553 // filament_id, vendor+type, type); with no replacement the receiver's material is
6554 // kept and the keys are reported as skipped;
6555 // - colour: applied regardless of the type gate.
6556 // - capacity: past the printer's physical nozzles the entry becomes an empty
6557 // mixed-filament placeholder; on a single-physical-slot receiver it is dropped.
6558 // Applied partial values land on the collection's edited layer when the slot references
6559 // it and that layer survives the load, otherwise on the stored preset in place. Slots
6560 // aliasing a shared preset are re-pointed at distinct presets before the values apply.
6561 {
6562 // Grow the receiver's slots only as far as the highest published slot (never
6563 // shrink, never pull filler materials for unpublished slots).
6564 bool has_published_entries = false;
6565 // Physical filament capacity of the receiver's printer: a non-SEMM tool-changer
6566 // feeds filament N from nozzle N, so the nozzle count is the hard limit; a SEMM
6567 // printer (single_extruder_multi_material) sizes its slot list by hand, so only
6568 // the global slot limit applies (same condition as GUI_App::load_current_presets).
6569 // Published entries that would need a NEW physical slot past this capacity are
6570 // appended as empty mixed-filament placeholders instead of growing the list.
6571 size_t physical_capacity = size_t(EnforcerBlockerType::ExtruderMax);
6572 {
6573 const Preset& receiver_printer = this->printers.get_edited_preset();
6574 if (receiver_printer.printer_technology() == ptFFF &&
6575 !receiver_printer.config.opt_bool("single_extruder_multi_material")) {
6576 if (const auto* nozzle_diameter = receiver_printer.config.option<ConfigOptionFloats>("nozzle_diameter");
6577 nozzle_diameter != nullptr && !nozzle_diameter->values.empty())
6578 physical_capacity = nozzle_diameter->values.size();
6579 }
6580 }
6581 const std::set<std::string>& mixed_definitions = publish_mixed_keys();
6582 auto is_mixed_definition = [&mixed_definitions](const PublishedMaterialEntry& entry) {
6583 return std::any_of(entry.keys.begin(), entry.keys.end(), [&](const std::string& key) {
6584 return mixed_definitions.count(publish_base_key(key)) != 0;
6585 });
6586 };
6587 size_t grow_target = 0;
6588 for (const PublishedMaterialEntry& entry : published_config->material_keys) {
6589 has_published_entries = true;
6590 if (entry.slot < 0)
6591 continue;
6592 // A physical entry past the capacity becomes a tail placeholder below; its
6593 // growth is covered by the append counter, not the positional target.
6594 if (!is_mixed_definition(entry) && size_t(entry.slot) >= physical_capacity)
6595 continue;
6596 grow_target = std::max(grow_target, size_t(entry.slot) + 1);
6597 }
6598 // Mixed-filament definitions live in project-level virtual slots, so applying one
6599 // positionally onto a receiver slot holding a real filament would convert hardware
6600 // state into a virtual mix. Compute each entry's destination before anything
6601 // consumes entry.slot: a definition on a slot that already holds a mixed definition
6602 // keeps its place (like-for-like); everything else follows one monotone append
6603 // counter preserving author order (dest = max(authored, next_free)). Appends past
6604 // the extruder limit are dropped and reported. Physical entries past capacity join
6605 // the same counter as mixed_placeholder empties the GUI flags for assignment.
6606 //
6607 // The finished project keeps the physical-first invariant (see the sidebar's
6608 // add_custom_filament: mixed slots always sit at the tail, physical slots packed
6609 // first). That invariant must survive an import, so every receiver mixed slot that
6610 // would end up inside (or ahead of) the incoming physical region is displaced to a
6611 // fresh tail slot, and the tail allocator starts at the physical boundary rather
6612 // than the receiver's slot count - otherwise a relocated mix can collide with a
6613 // keep-placed new real slot.
6614 size_t physical_boundary = this->num_physical_filaments();
6615 for (const PublishedMaterialEntry& entry : published_config->material_keys)
6616 // Mirror the payload-real keep-place decision below: a real keeps its authored
6617 // slot when that slot already exists on the receiver, or lies within the
6618 // printer's physical capacity. Both end up as physical slots at index
6619 // entry.slot, so they bound the physical region even past the capacity.
6620 if (entry.slot >= 0 && !is_mixed_definition(entry) &&
6621 (size_t(entry.slot) < this->filament_presets.size() || size_t(entry.slot) < physical_capacity))
6622 physical_boundary = std::max(physical_boundary, size_t(entry.slot) + 1);
6623 size_t next_free_slot = std::max(physical_boundary, this->filament_presets.size());
6624 bool any_mixed_relocated = false;
6625 // All authored-slot -> destination moves decided by this pass, applied to the
6626 // incoming config in one batched snapshot step below (an earlier move's
6627 // destination can overlap a later move's source: adjacent tail mixes relocate
6628 // onto consecutive slots, so incremental in-place shifts would overwrite a
6629 // definition that has not been moved yet).
6630 std::vector<std::pair<size_t, size_t>> mixed_moves;
6631 // Receiver-mix relocations land in project_config, not the incoming config, so they
6632 // get their own move list, applied below after the arrays grow. The swept set lets
6633 // the payload loop below treat a displaced receiver mix as the physical slot it will
6634 // become (a payload mix like-for-like overriding such a slot must itself relocate).
6635 std::vector<std::pair<size_t, size_t>> receiver_mix_moves;
6636 std::set<size_t> swept_mix_slots;
6637 for (size_t slot = 0; slot < this->filament_presets.size(); ++slot) {
6638 if (!this->is_mixed_filament(slot))
6639 continue;
6640 // Slot 0 is the receiver's base filament and is never a virtual mix; the
6641 // sidebar's physical-first layout guarantees it, so never displace it.
6642 if (slot == 0)
6643 continue;
6644 if (slot >= physical_boundary)
6645 continue; // already lives in the tail region
6646 const size_t dest = next_free_slot++;
6647 swept_mix_slots.insert(slot);
6648 receiver_mix_moves.emplace_back(slot, dest);
6649 any_mixed_relocated = true;
6650 // A payload mix authored at the same slot (a mix inside the physical region) is
6651 // processed after this sweep and overrides its own destination below.
6652 published_config->mixed_slot_relocations.insert_or_assign(int(slot), int(dest));
6653 // TRN Filament slot change after loading a published project. %1% and %2% are slot numbers.
6654 published_config->material_replacements.emplace_back(
6655 (boost::format(L("slot %1% -> slot %2%: mixed filament")) % slot % dest).str());
6656 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": published 3MF relocated receiver mixed filament slot " << slot
6657 << " -> " << dest << " (physical-first rebalance)";
6658 }
6659 for (auto entry_it = published_config->material_keys.begin(); entry_it != published_config->material_keys.end();) {
6660 PublishedMaterialEntry& entry = *entry_it;
6661 if (entry.slot < 0) {
6662 ++entry_it;
6663 continue;
6664 }
6665 const bool is_payload_mix = is_mixed_definition(entry);
6666 // Does this entry need a tail slot at all? A payload mixed definition does,
6667 // except when it like-for-like overrides a receiver slot that is already a
6668 // mix (bounds-checked). A physical entry only becomes a placeholder when it
6669 // would need a NEW physical slot: an authored position the receiver's list
6670 // already covers is applied positionally as before, even when that list sits
6671 // above the printer's capacity (pre-existing state is never shrunk).
6672 bool keep_place = false;
6673 if (is_payload_mix)
6674 keep_place = this->is_mixed_filament(size_t(entry.slot)) && swept_mix_slots.count(size_t(entry.slot)) == 0;
6675 else
6676 keep_place = size_t(entry.slot) < this->filament_presets.size() ||
6677 size_t(entry.slot) < physical_capacity;
6678 if (keep_place) {
6679 ++entry_it;
6680 continue;
6681 }
6682 const std::string material_label = !entry.filament_id.empty() ? entry.filament_id :
6683 !entry.publish_type_value.empty() ? entry.publish_type_value :
6684 entry.filament_type;
6685 if (std::max(size_t(entry.slot), next_free_slot) >= size_t(EnforcerBlockerType::ExtruderMax)) {
6686 // No free virtual slot left: report instead of destroying a real filament.
6687 // The local skipped_keys is published wholesale at the end of the pass;
6688 // writing published_config->skipped_keys here would be clobbered by it.
6689 skipped_keys.emplace_back("material:" + material_label + " (" +
6690 (is_payload_mix ? L("mixed filament definition: filament slot limit reached") :
6691 L("filament slot limit reached")) +
6692 ")");
6693 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": published 3MF " << (is_payload_mix ? "mixed filament definition" : "material")
6694 << " from slot " << entry.slot << " could not be placed: all " << next_free_slot
6695 << " slots exhausted";
6696 entry_it = published_config->material_keys.erase(entry_it);
6697 continue;
6698 }
6699 if (!is_payload_mix && physical_capacity < 2) {
6700 // A single physical slot can never host a mixed-filament editor (the
6701 // sidebar's mixed section needs two physical filaments to mix), so a
6702 // placeholder would be invisible and unfixable: drop the entry and
6703 // report it like any other unappliable input.
6704 skipped_keys.emplace_back("material:" + material_label + " (" +
6705 (boost::format(L("the printer's filament limit is %1%")) % physical_capacity).str() + ")");
6706 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": published 3MF material from slot " << entry.slot
6707 << " dropped: printer supports only " << physical_capacity << " filament";
6708 entry_it = published_config->material_keys.erase(entry_it);
6709 continue;
6710 }
6711 const int authored_slot = entry.slot;
6712 const int dest_slot = is_payload_mix ? int(std::max(size_t(authored_slot), next_free_slot)) : int(next_free_slot);
6713 next_free_slot = size_t(dest_slot) + 1;
6714 if (is_payload_mix) {
6715 if (dest_slot == authored_slot)
6716 // Uncontended fresh tail slot: the definition is already readable there.
6717 ++entry_it;
6718 else {
6719 entry.slot = dest_slot;
6720 any_mixed_relocated = true;
6721 mixed_moves.emplace_back(size_t(authored_slot), size_t(entry.slot));
6722 published_config->mixed_slot_relocations.insert_or_assign(authored_slot, entry.slot);
6723 published_config->material_replacements.emplace_back(
6724 (boost::format(L("slot %1% -> slot %2%: mixed filament")) % authored_slot % entry.slot).str());
6725 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": published 3MF relocated mixed filament slot " << authored_slot
6726 << " -> " << entry.slot;
6727 ++entry_it;
6728 }
6729 } else {
6730 // Surplus published material beyond the printer's capacity: become an
6731 // empty mixed-filament placeholder at the next free tail slot. The flag
6732 // routes the entry to the placeholder finalize below; the slot's
6733 // definition stays empty until the user assigns components.
6734 entry.mixed_placeholder = true;
6735 any_mixed_relocated = true;
6736 if (dest_slot != authored_slot) {
6737 entry.slot = dest_slot;
6738 mixed_moves.emplace_back(size_t(authored_slot), size_t(dest_slot));
6739 published_config->mixed_slot_relocations.insert_or_assign(authored_slot, dest_slot);
6740 }
6741 published_config->material_replacements.emplace_back(
6742 dest_slot != authored_slot ?
6743 (boost::format(L("slot %1% -> slot %2%: unassigned mixed filament (the printer's filament limit is %3%)")) %
6744 authored_slot % dest_slot % physical_capacity).str() :
6745 (boost::format(L("slot %1%: unassigned mixed filament (the printer's filament limit is %2%)")) % dest_slot %
6746 physical_capacity).str());
6747 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": published 3MF material from slot " << authored_slot
6748 << " placed as an unassigned mixed filament at slot " << dest_slot
6749 << " (printer supports only " << physical_capacity << " filaments)";
6750 ++entry_it;
6751 }
6752 }
6753 if (!mixed_moves.empty())
6754 for (const std::string& mixed_key : mixed_definitions)
6755 apply_mixed_config_relocations(config, mixed_key, mixed_moves);
6756 if (has_published_entries) {
6757 // Defensive cap: growth never exceeds the file's own filament count. The
6758 // receiver's current slot count is a floor: neither the preset list nor the
6759 // project vectors are ever shrunk, even when the file carries fewer filaments
6760 // than the receiver has slots. Relocated mixed entries and capacity
6761 // placeholders legitimately land past the file's own slot count (virtual
6762 // slots consume no nozzle or tray), so their append destinations lift the
6763 // ceiling explicitly.
6764 const size_t target_slots = std::max({this->filament_presets.size(), std::min(grow_target, num_filaments),
6765 any_mixed_relocated ? next_free_slot : size_t(0)});
6766 // Slots carrying published content, steering the initial preset selection of
6767 // newly grown slots.
6768 std::set<int> published_slots;
6769 for (const PublishedMaterialEntry& entry : published_config->material_keys)
6770 if (entry.slot >= 0)
6771 published_slots.insert(entry.slot);
6772 // Grown slots the receiver creates that carry no published content of their own
6773 // (e.g. an unpublished mixed slot left as a gap by a published mix's authored
6774 // position) at or beyond the receiver's physical capacity. They must not become
6775 // physical filaments (that would overflow the nozzle count): finalized as empty
6776 // mixed placeholders below, like the surplus-material placeholders.
6777 std::set<int> virtual_gap_slots;
6778 // Exact-name resolution of each published slot's preset through the collection's
6779 // own name machinery: find_preset2 follows renamed_from (vendor profile renames)
6780 // and canonical bundle names, and auto-matches removed vendor-generic profiles
6781 // to the Orca Filament Library. First entry per slot wins (mirrors the loops'
6782 // break-on-first behavior); an empty value means "no resolution" and the string
6783 // tiers (raw name / trimmed bare name / alias) below take over.
6784 std::map<int, std::string> exact_name_by_slot;
6785 for (const PublishedMaterialEntry& entry : published_config->material_keys)
6786 if (entry.slot >= 0 && !entry.preset_name.empty() && exact_name_by_slot.count(entry.slot) == 0)
6787 if (const Preset* resolved = this->filaments.find_preset2(entry.preset_name, true))
6788 exact_name_by_slot.emplace(entry.slot, resolved->name);
6789 auto resolved_name_for = [&exact_name_by_slot](int slot) -> std::string {
6790 const auto it = exact_name_by_slot.find(slot);
6791 return it == exact_name_by_slot.end() ? std::string() : it->second;
6792 };
6793 // Mirror first_visible_idx()'s start index so suppressed default presets are
6794 // never picked as a slot material.
6795 const size_t first_candidate = this->filaments.is_default_suppressed() ? this->filaments.num_default_presets() : 0;
6796 // Candidate preference for a published entry: exact preset name (raw author and
6797 // collection-resolved), then trimmed bare form / alias, then exact setting_id
6798 // (variant-level), then exact filament_id, then vendor+type, then type only.
6799 auto candidate_score = [](const Preset& candidate, const PublishedMaterialEntry& entry,
6800 const std::string& resolved_name) -> int {
6801 // Exact preset name: raw and collection-resolved forms both outrank the
6802 // fuzzy bare/alias tier by tier value, so a receiver preset literally named
6803 // "Generic PLA" (tier 4) can never beat the author's exact
6804 // "Generic PLA @Vendor" (tier 5). Within one tier the strict ">"
6805 // comparison keeps the first candidate in collection order.
6806 if (!entry.preset_name.empty() && candidate.name == entry.preset_name)
6807 return 5;
6808 if (!resolved_name.empty() && candidate.name == resolved_name)
6809 return 5;
6810 if (!entry.preset_name.empty()) {
6811 std::string bare_name = entry.preset_name.substr(0, entry.preset_name.find('@'));
6812 boost::trim_right(bare_name);
6813 if (!bare_name.empty() &&
6814 (candidate.alias == entry.preset_name || candidate.name == bare_name || candidate.alias == bare_name))
6815 return 4;
6816 }
6817 if (!entry.setting_id.empty() && candidate.setting_id == entry.setting_id)
6818 return 3;
6819 const ConfigOptionStrings* types = candidate.config.opt<ConfigOptionStrings>("filament_type");
6820 const ConfigOptionStrings* vendors = candidate.config.opt<ConfigOptionStrings>("filament_vendor");
6821 const std::string type = (types != nullptr && !types->values.empty()) ? types->get_at(0) : std::string();
6822 const std::string vendor = (vendors != nullptr && !vendors->values.empty()) ? vendors->get_at(0) : std::string();
6823 if (!entry.filament_id.empty() && candidate.filament_id == entry.filament_id)
6824 return 2;
6825 // Tier 0/1 family gate: the explicit type requirement when published as
6826 // such, otherwise the entry's own material family - so identity scoring
6827 // also applies to entries published without a checked Type row.
6828 const std::string required_type = !entry.publish_type_value.empty() ? entry.publish_type_value :
6829 normalize_filament_type(entry.filament_type);
6830 if (!required_type.empty() && normalize_filament_type(type) == required_type) {
6831 if (!entry.filament_vendor.empty() && vendor == entry.filament_vendor)
6832 return 1;
6833 return 0;
6834 }
6835 return -1;
6836 };
6837 while (this->filament_presets.size() < target_slots) {
6838 const size_t new_slot_idx = this->filament_presets.size();
6839 std::string initial_preset;
6840 if (new_slot_idx >= physical_capacity && published_slots.count(static_cast<int>(new_slot_idx)) == 0)
6841 // An unpublished grown slot past the printer's physical capacity cannot
6842 // host a real filament: finalize it as a virtual placeholder below.
6843 virtual_gap_slots.insert(static_cast<int>(new_slot_idx));
6844 if (published_slots.count(static_cast<int>(new_slot_idx)) != 0) {
6845 // Grow the slot the way the sidebar "add filament" does: seed it with
6846 // the receiver's last preset.
6847 if (!this->filament_presets.empty())
6848 initial_preset = this->filament_presets.back();
6849 }
6850 if (initial_preset.empty())
6851 // Unpublished filler slot, or every visible preset is already used:
6852 // repeat the receiver's last preset ("Add one filament" behaviour).
6853 initial_preset = this->filament_presets.empty() ? this->filaments.first_visible().name :
6854 this->filament_presets.back();
6855 this->filament_presets.emplace_back(initial_preset);
6856 }
6857 // Published slots that alias another slot (multi-extruder with one filament)
6858 // get re-pointed at distinct presets: the overlay writes onto the slot's
6859 // effective preset in place, so a shared preset would leak one slot's published
6860 // values into every aliased slot. Slot 0 (the receiver's own material) is never
6861 // re-assigned; when no unused candidate exists the aliasing stays (unavoidable).
6862 auto referenced_elsewhere = [&](const std::string& preset_name, size_t except_slot) {
6863 for (size_t s = 0; s < this->filament_presets.size(); ++s)
6864 if (s != except_slot && this->filament_presets[s] == preset_name)
6865 return true;
6866 return false;
6867 };
6868 for (size_t slot = 1; slot < this->filament_presets.size(); ++slot) {
6869 if (published_slots.count(static_cast<int>(slot)) == 0 || !referenced_elsewhere(this->filament_presets[slot], slot))
6870 continue;
6871 // A slot whose published entry writes nothing into a shared preset in place
6872 // keeps its own preset: de-aliasing would needlessly swap the material. Only
6873 // keys routed to the slot's preset can leak across an aliased slot (colour is
6874 // slot-scoped via project_config; a type requirement is handled by the
6875 // type-gate below; full detaches separately). Mixed-definition keys go to the
6876 // per-slot project arrays, never the preset.
6877 bool writes_preset_keys = false;
6878 for (const PublishedMaterialEntry& entry : published_config->material_keys) {
6879 if (entry.slot != static_cast<int>(slot))
6880 continue;
6881 for (const std::string& key : entry.keys)
6882 if (mixed_definitions.count(publish_base_key(key)) == 0) {
6883 writes_preset_keys = true;
6884 break;
6885 }
6886 if (writes_preset_keys)
6887 break;
6888 }
6889 if (!writes_preset_keys)
6890 continue;
6891 // Prefer the best distinct candidate for the slot's published material
6892 // (exact id, then vendor+type, then type only), compatible presets first...
6893 std::string replacement;
6894 int best_score = -1;
6895 for (const PublishedMaterialEntry& entry : published_config->material_keys) {
6896 // Scored for every entry with an identity, not only when a Type
6897 // requirement was checked (same as the growth seeding above).
6898 if (entry.slot != static_cast<int>(slot))
6899 continue;
6900 const std::string resolved_name = resolved_name_for(entry.slot);
6901 auto scan = [&](bool compatible_only) -> std::pair<int, std::string> {
6902 int best_score = -1;
6903 std::string best_name;
6904 for (size_t i = first_candidate; i < this->filaments.size(); ++i) {
6905 const Preset& candidate = this->filaments.preset(i);
6906 if (compatible_only && !candidate.is_compatible)
6907 continue;
6908 const int score = candidate_score(candidate, entry, resolved_name);
6909 // Exact identity tiers (name / setting_id) may use a hidden preset;
6910 // the referenced check stays: re-pointing exists to de-alias.
6911 if (score < 3 && !candidate.is_visible)
6912 continue;
6913 if (referenced_elsewhere(candidate.name, size_t(-1)))
6914 continue;
6915 if (score > best_score) {
6916 best_score = score;
6917 best_name = candidate.name;
6918 }
6919 }
6920 return {best_score, best_name};
6921 };
6922 const auto [compat_score, compat_name] = scan(true);
6923 const auto [any_score, any_name] = scan(false);
6924 if (compat_score >= 0) {
6925 best_score = compat_score;
6926 replacement = compat_name;
6927 } else if (any_score >= 0) {
6928 best_score = any_score;
6929 replacement = any_name;
6930 }
6931 if (best_score >= 0)
6932 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": published 3MF re-pointed slot " << slot << " to " << replacement
6933 << " (score " << best_score << ", preset_name \"" << entry.preset_name << "\", type \""
6934 << entry.publish_type_value << "\")";
6935 break;
6936 }
6937 // ...otherwise any distinct visible preset not referenced by another slot,
6938 // preferring the published material's own family when it is known.
6939 if (replacement.empty()) {
6940 std::string slot_family;
6941 for (const PublishedMaterialEntry& entry : published_config->material_keys)
6942 if (entry.slot == static_cast<int>(slot)) {
6943 slot_family = !entry.publish_type_value.empty() ? entry.publish_type_value :
6944 normalize_filament_type(entry.filament_type);
6945 break;
6946 }
6947 for (size_t i = first_candidate; i < this->filaments.size(); ++i) {
6948 const Preset& candidate = this->filaments.preset(i);
6949 if (!candidate.is_visible || referenced_elsewhere(candidate.name, size_t(-1)))
6950 continue;
6951 if (!slot_family.empty()) {
6952 const ConfigOptionStrings* types = candidate.config.opt<ConfigOptionStrings>("filament_type");
6953 const std::string cand_type = (types != nullptr && !types->values.empty()) ? types->get_at(0) :
6954 std::string();
6955 if (normalize_filament_type(cand_type) != slot_family)
6956 continue;
6957 }
6958 replacement = candidate.name;
6959 break;
6960 }
6961 }
6962 if (replacement.empty())
6963 continue; // every visible preset is referenced: aliasing is unavoidable
6964 const std::string aliased_name = this->filament_presets[slot];
6965 this->filament_presets[slot] = replacement;
6966 material_applied = true;
6967 // The re-point used to be silent; surface it like the other slot changes.
6968 // TRN Filament slot change after loading a published project. %1% is the slot number, %2% the old preset, %3% the new one.
6969 published_config->material_replacements.emplace_back(
6970 (boost::format(L("slot %1%: %2% -> %3%")) % slot % aliased_name % replacement).str());
6971 }
6972 // Grow the per-slot colour/type/map project vectors to the new slot count and
6973 // seed the new entries so the slots render with colours instead of blank chips
6974 // (mirrors set_num_filaments; existing values are left untouched).
6975 ConfigOptionStrings* proj_colour = this->project_config.opt<ConfigOptionStrings>("filament_colour");
6976 ConfigOptionStrings* proj_multi_colour = this->project_config.opt<ConfigOptionStrings>("filament_multi_colour");
6977 ConfigOptionStrings* proj_colour_type = this->project_config.opt<ConfigOptionStrings>("filament_colour_type");
6978 ConfigOptionInts* proj_map = this->project_config.opt<ConfigOptionInts>("filament_map");
6979 ConfigOptionInts* proj_nozzle_map = this->project_config.opt<ConfigOptionInts>("filament_nozzle_map");
6980 ConfigOptionInts* proj_volume_map = this->project_config.opt<ConfigOptionInts>("filament_volume_map");
6981 const size_t old_colour_count = (proj_colour != nullptr) ? proj_colour->values.size() : 0;
6982 // Grow-only: an already-larger project vector is left untouched (the receiver's
6983 // slot count never shrinks below its own setup).
6984 if (proj_colour && proj_colour->values.size() < target_slots)
6985 proj_colour->resize(target_slots);
6986 if (proj_multi_colour && proj_multi_colour->values.size() < target_slots)
6987 proj_multi_colour->values.resize(target_slots);
6988 if (proj_colour_type && proj_colour_type->values.size() < target_slots)
6989 proj_colour_type->values.resize(target_slots);
6990 if (proj_map && proj_map->values.size() < target_slots)
6991 proj_map->values.resize(target_slots, 1);
6992 if (proj_nozzle_map && proj_nozzle_map->values.size() < target_slots)
6993 proj_nozzle_map->values.resize(target_slots, 0);
6994 if (proj_volume_map && proj_volume_map->values.size() < target_slots)
6995 proj_volume_map->values.resize(target_slots, static_cast<int>(NozzleVolumeType::nvtStandard));
6996 // The mixed-color project arrays are parallel per-slot like filament_colour;
6997 // grow them in lockstep so a published mix slot has room for its definition.
6998 // Defaults mirror set_num_filaments (false / empty string).
6999 if (auto* opt = this->project_config.opt<ConfigOptionBools>("filament_is_mixed"))
7000 if (opt->values.size() < target_slots)
7001 opt->values.resize(target_slots, false);
7002 if (auto* opt = this->project_config.opt<ConfigOptionStrings>("filament_mixed_components"))
7003 if (opt->values.size() < target_slots)
7004 opt->values.resize(target_slots, std::string{});
7005 if (auto* opt = this->project_config.opt<ConfigOptionStrings>("filament_mixed_sublayer_ratios"))
7006 if (opt->values.size() < target_slots)
7007 opt->values.resize(target_slots, std::string{});
7008 if (auto* opt = this->project_config.opt<ConfigOptionBools>("filament_mixed_gradient"))
7009 if (opt->values.size() < target_slots)
7010 opt->values.resize(target_slots, false);
7011 if (auto* opt = this->project_config.opt<ConfigOptionStrings>("filament_mixed_gradient_range"))
7012 if (opt->values.size() < target_slots)
7013 opt->values.resize(target_slots, std::string{});
7014 if (auto* opt = this->project_config.opt<ConfigOptionStrings>("filament_mixed_gradient_curve"))
7015 if (opt->values.size() < target_slots)
7016 opt->values.resize(target_slots, std::string{});
7017 if (auto* opt = this->project_config.opt<ConfigOptionBools>("filament_mixed_gradient_per_part"))
7018 if (opt->values.size() < target_slots)
7019 opt->values.resize(target_slots, false);
7020 if (this->ams_multi_color_filment.size() < target_slots)
7021 this->ams_multi_color_filment.resize(target_slots);
7022 for (size_t slot = old_colour_count; slot < target_slots; ++slot) {
7023 std::string seed;
7024 for (const PublishedMaterialEntry& entry : published_config->material_keys)
7025 if (entry.slot == static_cast<int>(slot) && entry.publish_color && !entry.color.empty()) {
7026 seed = entry.color;
7027 break;
7028 }
7029 if (seed.empty()) {
7030 if (const Preset* preset = this->filaments.find_preset(this->filament_presets[slot], false)) {
7031 const ConfigOptionStrings* colours = preset->config.opt<ConfigOptionStrings>("filament_colour");
7032 if (colours != nullptr && !colours->values.empty())
7033 seed = colours->values.front();
7034 }
7035 if (seed.empty()) {
7036 // Fall back to the option's registered default instead of a
7037 // duplicated literal; if the lookup fails the chip stays blank.
7038 if (const ConfigOptionDef* colour_def = print_config_def.get("filament_colour"))
7039 if (const auto* default_colours = dynamic_cast<const ConfigOptionStrings*>(colour_def->default_value.get()))
7040 if (!default_colours->values.empty())
7041 seed = default_colours->values.front();
7042 }
7043 }
7044 if (proj_colour && slot < proj_colour->values.size())
7045 proj_colour->values[slot] = seed;
7046 if (proj_multi_colour && slot < proj_multi_colour->values.size())
7047 proj_multi_colour->values[slot] = seed;
7048 if (proj_colour_type && slot < proj_colour_type->values.size())
7049 proj_colour_type->values[slot] = "1"; // default colour type
7050 }
7051 // Rebuild the flush volumes for the grown slot count (as set_num_filaments does).
7053
7054 auto apply_slot_keys = [&](DynamicPrintConfig& preset_config, const std::vector<std::string>& slot_keys, int author_slot,
7055 const std::string& material_label) {
7056 for (const std::string& key : slot_keys) {
7057 const std::string base_key = publish_base_key(key);
7058 if (structural_keys.count(base_key) != 0)
7059 continue;
7060 const ConfigOption* src_opt = config.option(base_key);
7061 if (src_opt == nullptr || !src_opt->is_vector() || author_slot < 0 ||
7062 author_slot >= static_cast<int>(static_cast<const ConfigOptionVectorBase*>(src_opt)->size())) {
7063 skipped_keys.emplace_back("material:" + material_label + " (" + key + ")");
7064 continue;
7065 }
7066 ConfigOption* dst_opt = preset_config.option(base_key);
7067 if (dst_opt == nullptr || !dst_opt->is_vector() || static_cast<const ConfigOptionVectorBase*>(dst_opt)->empty() ||
7068 dst_opt->type() != src_opt->type()) {
7069 skipped_keys.emplace_back("material:" + material_label + " (" + key + ")");
7070 continue;
7071 }
7072 // Per-slot scalar copy: the receiver preset holds one value per key
7073 // (vector of size 1), the file holds the per-slot vector.
7074 static_cast<ConfigOptionVectorBase*>(dst_opt)->set_at(src_opt, 0, author_slot);
7075 material_applied = true;
7076 }
7077 };
7078
7079 // The slot's values are applied onto the slot's effective preset (the
7080 // collection's edited layer when the slot references it, otherwise the stored
7081 // preset in place); the per-entry type gate below may re-point the slot first.
7082 //
7083 // The edited layer only survives the load when the final re-select below stays
7084 // off, i.e. slot 0's preset still matches the edited preset. Otherwise the
7085 // re-select re-snapshots the edited layer from a stored preset and silently
7086 // discards everything written there: route the overlay to the stored presets
7087 // instead so the values survive. (Residual edge: a slot-0 type replacement
7088 // re-pointing slot 0 mid-loop can still invalidate the layer after earlier
7089 // slots wrote to it; that compound case is not chased.)
7090 const bool edited_survives_load = this->filament_presets.empty() ||
7091 this->filament_presets.front() == this->filaments.get_edited_preset().name;
7092 // Displaced receiver mixes (see the physical-first rebalance above): move their
7093 // per-slot cells onto the grown tail slots and reset the vacated physical slots,
7094 // so the incoming real filaments can claim them. Runs before mixed_final_slots is
7095 // built, so the rebalanced layout is what the mix validation sees.
7097 // Final layout for mix-definition validation: every slot that will hold a
7098 // mixed definition once this load completes - the receiver's own virtual
7099 // slots, each published mixed entry's final (possibly relocated) slot, and
7100 // each capacity placeholder (they become mixes in the finalize below, before
7101 // this loop's is_mixed_filament scan would see them). Mix components are
7102 // 1-based slot numbers, so a component is valid only when the slot it names
7103 // exists and does not itself hold a mixed filament.
7104 std::set<int> mixed_final_slots;
7105 for (const PublishedMaterialEntry& mix_entry : published_config->material_keys)
7106 if (mix_entry.slot >= 0 && (is_mixed_definition(mix_entry) || mix_entry.mixed_placeholder))
7107 mixed_final_slots.insert(mix_entry.slot);
7108 for (size_t i = 0; i < this->filament_presets.size(); ++i)
7109 if (this->is_mixed_filament(i))
7110 mixed_final_slots.insert(int(i));
7111 // Unpublished gap slots past the capacity are virtual too: count them in the
7112 // final layout so a published mix whose components collide with one is caught.
7113 for (int gap_slot : virtual_gap_slots)
7114 mixed_final_slots.insert(gap_slot);
7115 const size_t mixed_final_slot_count = this->filament_presets.size();
7116 // Finalize a slot as an empty mixed-filament placeholder: mark it virtual with
7117 // an intentionally empty definition, and add it to the final-layout set so a
7118 // later entry's components validate against the new state. Used by the capacity
7119 // placeholders and by any mixed definition that has to be rejected after its
7120 // slot was already grown and seeded - without it such a slot would keep the
7121 // seeded preset and masquerade as a real filament. No definition is written:
7122 // the placeholder carries no material of its own (the GUI flags the empty mix
7123 // via check_mixed_filament_integrity and blocks slicing until components are
7124 // assigned). The slot's colour was already seeded by the growth pass above.
7125 auto finalize_mixed_placeholder = [&](size_t slot_idx) {
7126 if (ConfigOptionBools* is_mixed_opt = this->project_config.opt<ConfigOptionBools>("filament_is_mixed");
7127 is_mixed_opt != nullptr && slot_idx < is_mixed_opt->values.size())
7128 is_mixed_opt->values[slot_idx] = true;
7129 mixed_final_slots.insert(int(slot_idx));
7130 material_applied = true;
7131 };
7132 // Full Publish within-load dedup: identical Full materials (same setting_id
7133 // + preset_name identity) share one created instance, so an author who
7134 // pointed two slots at one preset yields one standalone copy here.
7135 std::map<std::string, std::string> published_full_dedup;
7136 for (const PublishedMaterialEntry& entry : published_config->material_keys) {
7137 if (entry.slot < 0 || size_t(entry.slot) >= this->filament_presets.size())
7138 continue; // out of range: nothing to do for this slot
7139 const size_t slot = size_t(entry.slot);
7140
7141 // Surplus published material beyond the printer's capacity: finalize the
7142 // tail placeholder - mark the slot virtual with an intentionally empty
7143 // definition. The GUI flags the empty mix (check_mixed_filament_integrity)
7144 // and blocks slicing until the user assigns components from their own
7145 // filaments. The entry's keys are deliberately not applied and no preset
7146 // is detached: the placeholder carries no material of its own. The colour
7147 // was already seeded into the project arrays by the growth pass above.
7148 if (entry.mixed_placeholder) {
7149 finalize_mixed_placeholder(slot);
7150 continue;
7151 }
7152
7153 // Resolve the stored preset itself (real=true), never the edited snapshot:
7154 // find_preset would return &m_edited_preset for the selected slot. The
7155 // overlay target below decides between the edited layer and this preset.
7156 Preset* recv = this->filaments.find_preset(this->filament_presets[slot], false, true);
7157 if (recv == nullptr) {
7158 // Defensive: the slot exists (grown and seeded above) but its preset
7159 // could not be resolved. A mixed definition left unapplied on such a
7160 // slot would keep the seeded preset and look like a real filament:
7161 // finalize it as an empty placeholder instead, like a rejected
7162 // definition below.
7163 if (is_mixed_definition(entry) && !this->is_mixed_filament(slot)) {
7164 finalize_mixed_placeholder(slot);
7165 published_config->material_replacements.emplace_back(
7166 (boost::format(L("slot %1%: mixed filament definition could not be imported")) % slot).str());
7167 }
7168 continue;
7169 }
7170
7171 const std::string material_label = entry.filament_id.empty() ?
7172 (entry.publish_type_value.empty() ? entry.filament_type :
7173 entry.publish_type_value) :
7174 entry.filament_id;
7175
7176 // Import-side validation of a mixed-filament definition: the publish
7177 // dialog cannot produce a definition whose components reference slots
7178 // that do not exist or hold other mixed filaments, so a broken one here
7179 // means the payload itself is broken (hand-crafted or corrupt file).
7180 // Report it through the same channel as every other rejected input and
7181 // skip the entry, instead of shipping a mix the GUI integrity check
7182 // (check_mixed_filament_integrity) would only flag later. A payload
7183 // that omits the mixed arrays entirely is not an error here: the key
7184 // routing below reports those per key as usual.
7185 if (is_mixed_definition(entry)) {
7186 std::string mix_error;
7187 if (const ConfigOptionStrings* comp_opt = config.opt<ConfigOptionStrings>("filament_mixed_components");
7188 comp_opt != nullptr && entry.slot < static_cast<int>(comp_opt->values.size())) {
7189 const std::vector<unsigned int> comps = parse_mixed_components(comp_opt->values[entry.slot]);
7190 if (comps.size() < 2)
7191 // An empty definition cell counts as broken too: applying it
7192 // would ship a mix the sidebar would only flag later.
7193 mix_error = L("needs at least two components");
7194 else
7195 for (unsigned int comp : comps)
7196 if (comp < 1 || size_t(comp) > mixed_final_slot_count ||
7197 mixed_final_slots.count(int(comp) - 1) != 0) {
7198 mix_error = L("components reference missing slots");
7199 break;
7200 }
7201 }
7202 if (!mix_error.empty()) {
7203 skipped_keys.emplace_back("material:" + material_label + " (" +
7204 (boost::format(L("mixed filament definition: %1%")) % mix_error).str() + ")");
7205 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": published 3MF mixed filament from slot " << entry.slot
7206 << " rejected: " << mix_error;
7207 // Degradation, not silent corruption: the slot was already grown and
7208 // seeded by the pass above, so skipping the definition alone would
7209 // leave it holding the seeded preset and looking like a real
7210 // filament that carries the mix identity but no mix.
7211 // - a slot that was NOT already a receiver mix is finalized as an
7212 // empty mixed placeholder (consistent with the capacity
7213 // placeholders; the user assigns components there);
7214 // - a like-for-like override of the receiver's own mix leaves that
7215 // valid definition untouched: nothing was applied, so the
7216 // receiver's cells are intact and only the author's definition
7217 // is reported as skipped above.
7218 if (!this->is_mixed_filament(slot)) {
7219 finalize_mixed_placeholder(slot);
7220 published_config->material_replacements.emplace_back(
7221 (boost::format(L("slot %1%: mixed filament definition could not be imported (%2%)")) % slot % mix_error).str());
7222 }
7223 continue;
7224 }
7225 }
7226
7227 // Full Publish: always create a standalone detached copy (even on exact
7228 // identity match) as a "Preset Inside Project" (project-embedded: lives
7229 // in this project only, never written to the library), universally
7230 // compatible, named after the author's preset with its variant tail
7231 // stripped ("(Published)" uniquification on collision). No existing
7232 // preset is ever mutated.
7233 if (entry.full) {
7234 std::string dedup_key = entry.setting_id + std::string("\x1f") + entry.preset_name;
7235 // Identity-less hand-crafted files (empty setting_id+name) must not
7236 // collide: fall back to slot-scoped key so each slot gets its own copy
7237 // unless the dedup above is meaningful.
7238 if (dedup_key == std::string("\x1f"))
7239 dedup_key = dedup_key + std::to_string(slot);
7240 else if (!entry.filament_id.empty())
7241 dedup_key += std::string("\x1f") + entry.filament_id;
7242 std::string new_name;
7243 const auto dedup_it = published_full_dedup.find(dedup_key);
7244 if (dedup_it != published_full_dedup.end()) {
7245 new_name = dedup_it->second;
7246 } else {
7247 // Baseline: clone the receiver slot's stored preset config (schema-
7248 // complete across versions), then overlay the published full_keys.
7249 DynamicPrintConfig new_cfg = recv != nullptr ? recv->config : this->filaments.default_preset().config;
7250 for (const std::string& key : entry.full_keys) {
7251 const std::string base_key = publish_base_key(key);
7252 if (structural_keys.count(base_key) != 0)
7253 continue;
7254 const ConfigOption* src_opt = config.option(base_key);
7255 if (src_opt == nullptr || !src_opt->is_vector() || entry.slot < 0 ||
7256 entry.slot >= static_cast<int>(static_cast<const ConfigOptionVectorBase*>(src_opt)->size()))
7257 continue;
7258 ConfigOption* dst_opt = new_cfg.option(base_key);
7259 if (dst_opt == nullptr || !dst_opt->is_vector() ||
7260 static_cast<const ConfigOptionVectorBase*>(dst_opt)->empty() || dst_opt->type() != src_opt->type())
7261 continue;
7262 static_cast<ConfigOptionVectorBase*>(dst_opt)->set_at(src_opt, 0, entry.slot);
7263 }
7264 // The published colour is authoritative even for Full (the payload's
7265 // filament_colour plus the explicit publish_color field).
7266 if (entry.publish_color && !entry.color.empty()) {
7267 if (ConfigOptionStrings* col = new_cfg.opt<ConfigOptionStrings>("filament_colour", true)) {
7268 if (col->values.empty())
7269 col->values.emplace_back();
7270 col->values[0] = entry.color;
7271 }
7272 }
7273 make_publish_universal(new_cfg);
7274 // Naming: stripped variant tail ("Generic PLA @System" -> "Generic
7275 // PLA"), then identity fallbacks; collisions uniquify with
7276 // "(Published)" / "(Published N)" inside add_detached_preset.
7277 std::string base_name = entry.preset_name.empty() ? std::string() :
7278 publish_material_base_name(entry.preset_name);
7279 if (base_name.empty()) {
7280 base_name = !entry.filament_id.empty() ?
7281 entry.filament_id :
7282 (!entry.publish_type_value.empty() ? entry.publish_type_value : entry.filament_type);
7283 if (base_name.empty())
7284 base_name = "Published Filament";
7285 }
7286 new_name = this->filaments.add_detached_preset(base_name, std::move(new_cfg), entry.filament_id);
7287 published_full_dedup.emplace(dedup_key, new_name);
7288 }
7289 const std::string old_name = this->filament_presets[slot];
7290 this->filament_presets[slot] = new_name;
7291 material_applied = true;
7292 published_config->material_replacements.emplace_back(
7293 (boost::format(L("slot %1%: %2% -> %3%")) % slot % old_name % new_name).str());
7294 // Colour is slot-scoped and project-visible: sync into project_config
7295 // (the copy already baked it, this makes the chips render).
7296 if (entry.publish_color && !entry.color.empty()) {
7297 if (ConfigOptionStrings* proj_colour = this->project_config.opt<ConfigOptionStrings>("filament_colour")) {
7298 if (slot < proj_colour->values.size())
7299 proj_colour->values[slot] = entry.color;
7300 }
7301 if (ConfigOptionStrings* proj_multi_colour = this->project_config.opt<ConfigOptionStrings>(
7302 "filament_multi_colour")) {
7303 if (slot < proj_multi_colour->values.size())
7304 proj_multi_colour->values[slot] = entry.color;
7305 }
7306 } else if (proj_colour && new_name != old_name) {
7307 // Fall back to the copy's colour so the chip is never blank: try
7308 // the newly created preset's filament_colour, then the option default.
7309 std::string seed;
7310 if (const Preset* created = this->filaments.find_preset(new_name, false, true)) {
7311 if (const ConfigOptionStrings* cols = created->config.opt<ConfigOptionStrings>("filament_colour"))
7312 if (!cols->values.empty())
7313 seed = cols->values.front();
7314 }
7315 if (seed.empty()) {
7316 if (const ConfigOptionDef* colour_def = print_config_def.get("filament_colour"))
7317 if (const auto* defaults = dynamic_cast<const ConfigOptionStrings*>(colour_def->default_value.get()))
7318 if (!defaults->values.empty())
7319 seed = defaults->values.front();
7320 }
7321 if (!seed.empty()) {
7322 if (proj_colour && slot < proj_colour->values.size())
7323 proj_colour->values[slot] = seed;
7324 if (proj_multi_colour && slot < proj_multi_colour->values.size())
7325 proj_multi_colour->values[slot] = seed;
7326 }
7327 }
7328 if (proj_colour_type && slot < proj_colour_type->values.size())
7329 proj_colour_type->values[slot] = "1";
7330 continue;
7331 }
7332
7333 bool apply_slot = true;
7334 // The gate compares against the slot's effective material type: the edited
7335 // layer when the slot references the collection's edited preset and that
7336 // layer will survive the load (see edited_survives_load below), the stored
7337 // preset otherwise.
7338 const DynamicPrintConfig& effective_config = (edited_survives_load &&
7339 recv->name == this->filaments.get_edited_preset().name) ?
7340 this->filaments.get_edited_preset().config :
7341 recv->config;
7342 if (entry.publish_type && !entry.publish_type_value.empty()) {
7343 // Null-guard: a malformed receiver preset may lack filament_type.
7344 const ConfigOptionStrings* recv_types = effective_config.opt<ConfigOptionStrings>("filament_type");
7345 const std::string recv_type = (recv_types != nullptr && !recv_types->values.empty()) ? recv_types->get_at(0) :
7346 std::string();
7347 if (normalize_filament_type(recv_type) != entry.publish_type_value) {
7348 // Type mismatch: replace the slot with the best matching preset,
7349 // scored by the published identity (exact preset name, then exact
7350 // setting_id, exact filament_id, then vendor+type, then type only).
7351 // A preset no other slot references wins on equal scores; a shared
7352 // exact-material preset is taken even though mutating it also
7353 // affects the other slot. Compatible presets are searched first: an
7354 // incompatible preset is only picked when no compatible candidate
7355 // exists at all.
7356 auto find_best = [&](bool compatible_only) -> std::pair<int, std::string> {
7357 auto scan = [&](bool unreferenced_only) -> std::pair<int, std::string> {
7358 int best_score = -1;
7359 std::string best_name;
7360 const std::string resolved_name = resolved_name_for(entry.slot);
7361 for (size_t i = first_candidate; i < this->filaments.size(); ++i) {
7362 const Preset& candidate = this->filaments.preset(i);
7363 if (compatible_only && !candidate.is_compatible)
7364 continue;
7365 const int score = candidate_score(candidate, entry, resolved_name);
7366 if (score <= best_score)
7367 continue;
7368 // Lower tiers (vendor+type, type only) need a visible preset;
7369 // an exact identity match (name / setting_id) wins even when
7370 // the preset is hidden in the library.
7371 if (score < 3 && !candidate.is_visible)
7372 continue;
7373 if (unreferenced_only) {
7374 bool used = false;
7375 for (size_t s = 0; s < this->filament_presets.size(); ++s)
7376 if (s != slot && this->filament_presets[s] == candidate.name) {
7377 used = true;
7378 break;
7379 }
7380 if (used)
7381 continue;
7382 }
7383 best_score = score;
7384 best_name = candidate.name;
7385 }
7386 return {best_score, best_name};
7387 };
7388 const auto [strict_score, strict_name] = scan(true);
7389 const auto [relaxed_score, relaxed_name] = scan(false);
7390 if (relaxed_score > strict_score)
7391 return {relaxed_score, relaxed_name};
7392 return {strict_score, strict_name};
7393 };
7394 const auto [compat_score, compat_name] = find_best(true);
7395 const auto [any_score, any_name] = find_best(false);
7396 int score = any_score;
7397 std::string replacement = any_name;
7398 if (compat_score >= 0) {
7399 score = compat_score;
7400 replacement = compat_name;
7401 }
7402 if (!replacement.empty()) {
7403 const std::string old_name = recv->name;
7404 this->filament_presets[slot] = replacement;
7405 recv = this->filaments.find_preset(replacement, false, true);
7406 material_applied = true;
7407 BOOST_LOG_TRIVIAL(info)
7408 << __FUNCTION__ << ": published 3MF slot " << slot << " material " << old_name << " -> " << replacement
7409 << " (score " << score << ", preset_name \"" << entry.preset_name << "\", filament_id \""
7410 << entry.filament_id << "\", setting_id \"" << entry.setting_id << "\", type \""
7411 << entry.publish_type_value << "\")";
7412 // A pick that is not the exact published material is a substitute;
7413 // an entry without identity fields cannot be judged, so it stays plain.
7414 const bool is_substitute = score < 2 && (!entry.filament_id.empty() || !entry.filament_vendor.empty());
7415 std::string replacement_line = (boost::format(is_substitute ? L("slot %1%: %2% -> %3% (substitute)") :
7416 L("slot %1%: %2% -> %3%")) %
7417 slot % old_name % replacement).str();
7418 published_config->material_replacements.emplace_back(std::move(replacement_line));
7419 } else {
7420 // Partial publish with no replacement: keep the receiver's
7421 // material and report the slot's keys as skipped. (Full entries
7422 // never reach this gate: they detach above.)
7423 for (const std::string& key : entry.keys)
7424 skipped_keys.emplace_back("material:" + material_label + " (" + key + ")");
7425 apply_slot = false;
7426 // A mixed definition left unapplied here would keep the grown
7427 // slot's seeded preset and masquerade as a real filament:
7428 // finalize it as an empty placeholder like a rejected
7429 // definition (a like-for-like override of the receiver's own
7430 // mix is left untouched).
7431 if (is_mixed_definition(entry) && !this->is_mixed_filament(slot)) {
7432 finalize_mixed_placeholder(slot);
7433 published_config->material_replacements.emplace_back(
7434 (boost::format(L("slot %1%: mixed filament definition could not be imported")) % slot).str());
7435 }
7436 }
7437 }
7438 }
7439
7440 // The values below are applied onto the slot's effective preset: the edited
7441 // layer when the slot references the collection's edited preset and that
7442 // layer will survive the load (visible as a modification and revertible,
7443 // preserving the user's unsaved edits), otherwise the stored preset it ended
7444 // up on (original or partial type replacement), in place. Full entries never
7445 // get here - they detach above.
7446 DynamicPrintConfig& write_config = (edited_survives_load && recv->name == this->filaments.get_edited_preset().name) ?
7447 this->filaments.get_edited_preset().config :
7448 recv->config;
7449
7450 // Colour is slot-scoped and independent of the type gate; it is also synced
7451 // into project_config for GUI rendering.
7452 if (entry.publish_color && !entry.color.empty()) {
7453 // A mixed-definition entry carries the mix's blended colour for the
7454 // swatch only: never write it into the slot's (possibly shared) preset
7455 // config, only into the project-level colour arrays.
7456 const bool is_mixed_entry = is_mixed_definition(entry);
7457 if (!is_mixed_entry && recv != nullptr) {
7458 // Create the key when the target preset lacks it: the colour is a
7459 // requirement, not an override.
7460 if (ConfigOptionStrings* colour = write_config.opt<ConfigOptionStrings>("filament_colour", true)) {
7461 if (colour->values.empty())
7462 colour->values.emplace_back();
7463 colour->values[0] = entry.color;
7464 material_applied = true;
7465 }
7466 }
7467 if (ConfigOptionStrings* proj_colour = this->project_config.opt<ConfigOptionStrings>("filament_colour")) {
7468 if (slot < proj_colour->values.size())
7469 proj_colour->values[slot] = entry.color;
7470 }
7471 if (ConfigOptionStrings* proj_multi_colour = this->project_config.opt<ConfigOptionStrings>(
7472 "filament_multi_colour")) {
7473 if (slot < proj_multi_colour->values.size())
7474 proj_multi_colour->values[slot] = entry.color;
7475 }
7476 }
7477
7478 if (apply_slot && recv != nullptr) {
7479 // Mixed-color definition keys live in project_config (parallel per-slot
7480 // arrays), not in a filament preset; route them there. Normal keys keep
7481 // the per-slot preset path below.
7482 const std::set<std::string>& mixed_keys = publish_mixed_keys();
7483 std::vector<std::string> preset_keys;
7484 for (const std::string& key : entry.keys) {
7485 const std::string base_key = publish_base_key(key);
7486 if (mixed_keys.count(base_key) != 0) {
7487 const ConfigOption* src_opt = config.option(base_key);
7488 if (src_opt != nullptr && src_opt->is_vector() && entry.slot >= 0 &&
7489 entry.slot < static_cast<int>(static_cast<const ConfigOptionVectorBase*>(src_opt)->size())) {
7490 if (ConfigOption* dst_opt = this->project_config.option(base_key)) {
7491 if (dst_opt->is_vector() && dst_opt->type() == src_opt->type() &&
7492 slot < static_cast<const ConfigOptionVectorBase*>(dst_opt)->size()) {
7493 static_cast<ConfigOptionVectorBase*>(dst_opt)->set_at(src_opt, slot, entry.slot);
7494 material_applied = true;
7495 continue;
7496 }
7497 }
7498 }
7499 // The slot (or its arrays) could not be written: report rather
7500 // than drop the mix silently.
7501 skipped_keys.emplace_back("material:" + material_label + " (" + key + ")");
7502 continue;
7503 }
7504 preset_keys.emplace_back(key);
7505 }
7506 apply_slot_keys(write_config, preset_keys, entry.slot, material_label);
7507 }
7508 }
7509 // Unpublished gap slots past the printer's physical capacity: the receiver grew
7510 // them only to reach a published definition, so they must not become physical
7511 // filaments (that would overflow the nozzle count). Finalize each as an empty
7512 // mixed placeholder, exactly like the surplus-material placeholders above.
7513 for (int gap_slot : virtual_gap_slots)
7514 if (!this->is_mixed_filament(size_t(gap_slot))) {
7515 finalize_mixed_placeholder(size_t(gap_slot));
7516 published_config->material_replacements.emplace_back(
7517 (boost::format(L("slot %1%: unassigned mixed filament (the printer's filament limit is %2%)")) % gap_slot %
7518 physical_capacity).str());
7519 }
7520 }
7521 }
7522
7523 for (const std::string& key : published_config->published_keys) {
7524 if (applied_keys.count(key) != 0)
7525 continue;
7526 const std::string base_key = publish_base_key(key);
7527 // Structural keys are silently ignored, never reported as skipped: a hand-crafted
7528 // 3MF must not trigger the "could not be applied" warning for them.
7529 if (structural_keys.count(base_key) != 0)
7530 continue;
7531 // Printer-class keys outside the publishable allowlist are contract-excluded too.
7532 if (contract_excluded_keys.count(base_key) != 0)
7533 continue;
7534 skipped_keys.emplace_back(key);
7535 }
7536 published_config->skipped_keys = std::move(skipped_keys);
7537
7538 // The overlay lands on the edited layer only when it survives the load (slot 0's preset
7539 // still matches the edited preset; see edited_survives_load) and on the stored presets
7540 // otherwise. The edited preset is a snapshot taken when the preset was last selected, so
7541 // a slot-0 preset change (type replacement) still needs a re-select to surface; when
7542 // slot 0 is unchanged the edited layer already carries the overlay, and re-selecting
7543 // would discard both it and the user's unsaved edits.
7544 if (material_applied && !this->filament_presets.empty() &&
7545 this->filament_presets.front() != this->filaments.get_edited_preset().name)
7546 this->filaments.select_preset_by_name(this->filament_presets.front(), false);
7547 }
7548
7549
7550 //BBS
7551 //const std::string &physical_printer = config.option<ConfigOptionString>("physical_printer_settings_id", true)->value;
7552 const std::string physical_printer;
7553 if (!is_published) {
7554 if (this->printers.get_edited_preset().is_external || physical_printer.empty()) {
7555 this->physical_printers.unselect_printer();
7556 } else {
7557 // Activate the physical printer profile if possible.
7558 PhysicalPrinter *pp = this->physical_printers.find_printer(physical_printer, true);
7559 if (pp != nullptr && std::find(pp->preset_names.begin(), pp->preset_names.end(), this->printers.get_edited_preset().name) != pp->preset_names.end())
7560 this->physical_printers.select_printer(pp->name, this->printers.get_edited_preset().name);
7561 else
7562 this->physical_printers.unselect_printer();
7563 }
7564 }
7565 //BBS: add config related logs
7566 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": finished");
7567}
const ConfigOptionDef * get(const t_config_option_key &opt_key) const
Definition Config.hpp:2662
void update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible)
Definition PresetBundle.cpp:8517
void update_multi_material_filament_presets(size_t to_delete_filament_id=size_t(-1))
Definition PresetBundle.cpp:8399
std::vector< std::vector< std::string > > ams_multi_color_filment
Definition PresetBundle.hpp:510
static void convert_filament_preset_name(const std::string &machine_name, std::string &filament_name)
Definition PresetBundle.cpp:6107
size_t num_physical_filaments() const
Definition PresetBundle.cpp:4482
static std::set< std::string > project_different_keys(const std::string &different_settings)
Definition PresetBundle.cpp:5489
bool is_mixed_filament(size_t idx) const
Definition PresetBundle.cpp:4465
@ Always
Definition Preset.hpp:671
@ Never
Definition Preset.hpp:669
@ OnlyIfModified
Definition Preset.hpp:673
PrinterTechnology printer_technology() const
Definition Preset.hpp:399
printer_technology((ConfigOptionPoints, printable_area))((ConfigOptionFloat
zaa_minimize_perimeter_height filament_extruder_variant((ConfigOptionInts, filament_self_index))((ConfigOptionBool
PrinterTechnology
Definition Config.hpp:229
static void apply_receiver_mix_relocations(DynamicPrintConfig &config, std::vector< std::vector< std::string > > &ams_multi_color_filment, const std::vector< std::pair< size_t, size_t > > &moves)
Definition PresetBundle.cpp:6023
void resize_mixed_filament_metadata(DynamicPrintConfig &config, size_t old_slot_count, size_t new_slot_count)
Definition PrintConfig.cpp:11475
@ ExtruderMax
Definition TriangleSelector.hpp:66
std::vector< unsigned int > parse_mixed_components(const std::string &str)
Definition FilamentMixer.cpp:172
const PrintConfigDef print_config_def
Definition PrintConfig.cpp:10099
const std::set< std::string > & publish_mixed_keys()
Definition PublishSettings.cpp:111
const std::set< std::string > & publish_structural_keys()
Definition PublishSettings.cpp:90
static std::vector< std::string > s_project_options_published
Definition PresetBundle.cpp:184
void make_publish_universal(DynamicPrintConfig &config)
Definition PublishSettings.cpp:64
std::string publish_material_base_name(const std::string &preset_name)
Definition PublishSettings.cpp:80
@ coStrings
Definition Config.hpp:194
std::vector< std::map< int, int > > get_extruder_ams_count(const std::vector< std::string > &strs)
Definition PrintConfig.cpp:869
const std::set< std::string > & publishable_printer_keys()
Definition PublishSettings.cpp:163
std::string normalize_filament_type(const std::string &type)
Definition PublishSettings.cpp:47
static void apply_mixed_config_relocations(DynamicPrintConfig &config, const std::string &key, const std::vector< std::pair< size_t, size_t > > &moves)
Definition PresetBundle.cpp:5978
std::string publish_base_key(const std::string &key)
Definition PublishSettings.cpp:20
@ Never
Definition Preset.hpp:523
size_t cols(const T &raster)
Definition MarchingSquares.hpp:173

References Slic3r::Preset::alias, Slic3r::PresetCollection::Always, ams_multi_color_filment, Slic3r::apply_mixed_config_relocations(), Slic3r::ConfigBase::apply_only(), Slic3r::apply_receiver_mix_relocations(), Slic3r::ConfigOptionVector< T >::clear(), Slic3r::PublishedMaterialEntry::color, Slic3r::Preset::compatible_printers_condition(), Slic3r::Preset::compatible_prints_condition(), Slic3r::Preset::config, convert_filament_preset_name(), Slic3r::coStrings, Slic3r::ConfigOptionVectorBase::empty(), extruder_ams_counts, Slic3r::ExtruderMax, Slic3r::filament_extruder_variant(), Slic3r::Preset::filament_id, Slic3r::PublishedMaterialEntry::filament_id, Slic3r::filament_ids(), Slic3r::filament_options_with_variant, filament_presets, Slic3r::PublishedMaterialEntry::filament_type, Slic3r::PublishedMaterialEntry::filament_vendor, filaments, Slic3r::PublishedMaterialEntry::full, Slic3r::PublishedMaterialEntry::full_keys, Slic3r::ConfigOptionVector< T >::get_at(), Slic3r::get_extruder_ams_count(), Slic3r::Preset::inherits(), Slic3r::Preset::is_compatible, is_mixed_filament(), Slic3r::ConfigOption::is_scalar(), Slic3r::ConfigOption::is_vector(), Slic3r::Preset::is_visible, Slic3r::PublishedMaterialEntry::keys, L, load_config_file_config(), Slic3r::make_publish_universal(), Slic3r::PublishedConfig::material_keys, Slic3r::PublishedConfig::material_replacements, Slic3r::PublishedMaterialEntry::mixed_placeholder, Slic3r::PublishedConfig::mixed_slot_relocations, Slic3r::PhysicalPrinter::name, Slic3r::Preset::name, Slic3r::PresetCollection::Never, Slic3r::Never, Slic3r::normalize_filament_type(), Slic3r::nozzle_diameter(), num_physical_filaments(), Slic3r::nvtStandard, Slic3r::PresetCollection::OnlyIfModified, Slic3r::DynamicConfig::opt(), Slic3r::DynamicConfig::opt_bool(), Slic3r::DynamicConfig::opt_string(), Slic3r::ConfigBase::option(), Slic3r::parse_mixed_components(), physical_printers, Slic3r::PublishedMaterialEntry::preset_name, Slic3r::PhysicalPrinter::preset_names, Slic3r::print_config_def, Slic3r::Preset::printer_options(), Slic3r::Preset::printer_technology(), Slic3r::printer_technology(), printers, prints, project_config, project_different_keys(), Slic3r::ptFFF, Slic3r::ptSLA, Slic3r::publish_base_key(), Slic3r::PublishedMaterialEntry::publish_color, Slic3r::publish_material_base_name(), Slic3r::publish_mixed_keys(), Slic3r::publish_structural_keys(), Slic3r::PublishedMaterialEntry::publish_type, Slic3r::PublishedMaterialEntry::publish_type_value, Slic3r::publishable_printer_keys(), Slic3r::PublishedConfig::published, Slic3r::PublishedConfig::published_keys, Slic3r::ConfigOptionVector< T >::resize(), Slic3r::ConfigOptionVectorBase::resize(), Slic3r::resize_mixed_filament_metadata(), Slic3r::s_project_options, Slic3r::s_project_options_published, Slic3r::Preset::save(), Slic3r::ConfigOptionVectorBase::set(), Slic3r::ConfigOptionVectorBase::set_at(), Slic3r::Preset::setting_id, Slic3r::PublishedMaterialEntry::setting_id, Slic3r::ConfigOptionVector< T >::size(), Slic3r::ConfigOptionVector< int >::size(), Slic3r::ConfigOptionVectorBase::size(), Slic3r::PublishedConfig::skipped_keys, Slic3r::PublishedMaterialEntry::slot, Slic3r::ConfigOption::type(), update_compatible(), update_multi_material_filament_presets(), Slic3r::ConfigOptionVector< T >::values, Slic3r::ConfigOptionVector< int >::values, and vendors.

Referenced by load_config_file(), load_config_file_config(), load_config_from_wizard(), and load_config_model().

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

◆ load_config_from_wizard()

void Slic3r::PresetBundle::load_config_from_wizard ( const std::string & name,
DynamicPrintConfig config,
Semver file_version )
inline
576 { this->load_config_file_config(name, false, std::move(config), file_version, true); }

References load_config_file_config().

Referenced by Slic3r::GUI::ConfigWizard::priv::apply_config().

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

◆ load_config_model()

void Slic3r::PresetBundle::load_config_model ( const std::string & name,
DynamicPrintConfig config,
Semver file_version = Semver(),
PublishedConfig * published_config = nullptr )
inline
581 { this->load_config_file_config(name, true, std::move(config), file_version, false, published_config); }

References load_config_file_config().

Referenced by Slic3r::GUI::Plater::priv::load_files(), and Slic3r::GUI::Plater::load_gcode().

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

◆ load_installed_filaments()

void Slic3r::PresetBundle::load_installed_filaments ( AppConfig & config)
private
3758{
3759 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": enter, printer size %1%")%printers.size();
3760 //if (! config.has_section(AppConfig::SECTION_FILAMENTS)
3761 // || config.get_section(AppConfig::SECTION_FILAMENTS).empty()) {
3762 // Compatibility with the PrusaSlicer 2.1.1 and older, where the filament profiles were not installable yet.
3763 // Find all filament profiles, which are compatible with installed printers, and act as if these filament profiles
3764 // were installed.
3765 std::unordered_set<const Preset*> compatible_filaments;
3766 for (const Preset &printer : printers)
3767 if (printer.is_visible && printer.printer_technology() == ptFFF && printer.vendor && (!printer.vendor->models.empty())) {
3768 bool add_default_materials = true;
3769 if (config.has_section(AppConfig::SECTION_FILAMENTS))
3770 {
3771 const std::map<std::string, std::string>& installed_filament = config.get_section(AppConfig::SECTION_FILAMENTS);
3772 for (auto filament_iter : installed_filament)
3773 {
3774 Preset* filament = filaments.find_preset(filament_iter.first, false, true);
3775 if (filament && is_compatible_with_printer(PresetWithVendorProfile(*filament, filament->vendor), PresetWithVendorProfile(printer, printer.vendor)))
3776 {
3777
3778 //already has compatible filament
3779 add_default_materials = false;
3780 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": printer %1% vendor %2% already has default filament %3%")%printer.name %printer.vendor %filament_iter.first;
3781 break;
3782 }
3783 }
3784 }
3785
3786 if (!add_default_materials)
3787 continue;
3788
3789 const VendorProfile::PrinterModel *printer_model = PresetUtils::system_printer_model(printer);
3790 if (!printer_model) {
3791 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": can not find printer_model for printer %1%")%printer.name;
3792 continue;
3793 }
3794 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": printer %1% vendor %2% don't have filament visible, will add %3% default filaments")%printer.name %printer.vendor %printer_model->default_materials.size();
3795 for (auto default_filament: printer_model->default_materials)
3796 {
3797 Preset* filament = filaments.find_preset(default_filament, false, true);
3798 if (filament && filament->is_system)
3799 compatible_filaments.insert(filament);
3800 }
3801 //const PresetWithVendorProfile printer_with_vendor_profile = printers.get_preset_with_vendor_profile(printer);
3802 //for (const Preset &filament : filaments)
3803 // if (filament.is_system && is_compatible_with_printer(filaments.get_preset_with_vendor_profile(filament), printer_with_vendor_profile))
3804 // compatible_filaments.insert(&filament);
3805 }
3806 // and mark these filaments as installed, therefore this code will not be executed at the next start of the application.
3807 for (const auto &filament: compatible_filaments) {
3808 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": set filament %1% to visible by default")%filament->name;
3809 config.set(AppConfig::SECTION_FILAMENTS, filament->name, "true");
3810 }
3811 //}
3812
3813 for (auto &preset : filaments)
3814 preset.set_visible_from_appconfig(config);
3815 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": exit.");
3816}

References Slic3r::VendorProfile::PrinterModel::default_materials, filaments, Slic3r::AppConfig::get_section(), Slic3r::AppConfig::has_section(), Slic3r::is_compatible_with_printer(), Slic3r::Preset::is_system, load_installed_filaments(), printers, Slic3r::ptFFF, Slic3r::AppConfig::SECTION_FILAMENTS, Slic3r::AppConfig::set(), Slic3r::Preset::set_visible_from_appconfig(), Slic3r::PresetUtils::system_printer_model(), and Slic3r::Preset::vendor.

Referenced by load_installed_filaments(), and load_selections().

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

◆ load_installed_printers()

void Slic3r::PresetBundle::load_installed_printers ( const AppConfig & config)
3686{
3687 this->update_system_maps();
3688 for (auto &preset : printers)
3689 preset.set_visible_from_appconfig(config);
3690}
void update_system_maps()
Definition PresetBundle.cpp:3657

References load_installed_printers(), printers, Slic3r::Preset::set_visible_from_appconfig(), and update_system_maps().

Referenced by load_installed_printers(), load_selections(), and anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers().

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

◆ load_installed_sla_materials()

void Slic3r::PresetBundle::load_installed_sla_materials ( AppConfig & config)
private
3819{
3820 if (! config.has_section(AppConfig::SECTION_MATERIALS)) {
3821 std::unordered_set<const Preset*> comp_sla_materials;
3822 // Compatibility with the PrusaSlicer 2.1.1 and older, where the SLA material profiles were not installable yet.
3823 // Find all SLA material profiles, which are compatible with installed printers, and act as if these SLA material profiles
3824 // were installed.
3825 for (const Preset &printer : printers)
3826 if (printer.is_visible && printer.printer_technology() == ptSLA) {
3827 const PresetWithVendorProfile printer_with_vendor_profile = printers.get_preset_with_vendor_profile(printer);
3828 for (const Preset &material : sla_materials)
3829 if (material.is_system && is_compatible_with_printer(sla_materials.get_preset_with_vendor_profile(material), printer_with_vendor_profile))
3830 comp_sla_materials.insert(&material);
3831 }
3832 // and mark these SLA materials as installed, therefore this code will not be executed at the next start of the application.
3833 for (const auto &material: comp_sla_materials)
3834 config.set(AppConfig::SECTION_MATERIALS, material->name, "true");
3835 }
3836
3837 for (auto &preset : sla_materials)
3838 preset.set_visible_from_appconfig(config);
3839}
static const std::string SECTION_MATERIALS
Definition AppConfig.hpp:409

References Slic3r::AppConfig::has_section(), Slic3r::is_compatible_with_printer(), load_installed_sla_materials(), printers, Slic3r::ptSLA, Slic3r::AppConfig::SECTION_MATERIALS, Slic3r::AppConfig::set(), Slic3r::Preset::set_visible_from_appconfig(), and sla_materials.

Referenced by load_installed_sla_materials(), and load_selections().

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

◆ load_presets()

PresetsConfigSubstitutions Slic3r::PresetBundle::load_presets ( AppConfig & config,
ForwardCompatibilitySubstitutionRule rule,
const PresetPreferences & preferred_selection = PresetPreferences(),
std::string * errors = nullptr,
bool read_only = false )
884{
885 // First load the vendor specific system presets.
886 PresetsConfigSubstitutions substitutions;
887 std::string errors_cummulative;
888
889 //BBS: add config related logs
890 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, substitution_rule %1%, preferred printer_model_id %2%")%substitution_rule%preferred_selection.printer_model_id;
891 const auto startup_t0 = std::chrono::steady_clock::now();
892
893 //BBS: change system config to json
894 std::tie(substitutions, errors_cummulative) = this->load_system_presets_from_json(substitution_rule, !read_only);
895 if (errors != nullptr)
896 *errors = errors_cummulative;
897
898 // BBS load preset from user's folder, load system default if
899 // BBS: change directories by design
900 std::string dir_user_presets = config.get("preset_folder");
901 if (dir_user_presets.empty()) {
902 load_user_presets(DEFAULT_USER_FOLDER_NAME, substitution_rule, read_only);
903 } else {
904 load_user_presets(dir_user_presets, substitution_rule, read_only);
905 }
906 if (errors != nullptr && errors->empty() && m_errors != 0)
907 *errors = "Preset loading reported " + std::to_string(m_errors) + " error(s)";
908
909 // Rewrite renamed compatible_printers / compatible_prints references before selection. Skipped
910 // in validation mode so the profile validator (has_errors -> check_preset_references) sees the
911 // raw vendor-JSON references instead of the silently-repaired ones.
912 if (!validation_mode)
914
917
918 this->load_selections(config, preferred_selection);
919
921
922 {
923 const auto total_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
924 std::chrono::steady_clock::now() - startup_t0).count();
925 BOOST_LOG_TRIVIAL(info) << "PresetBundle: all presets loaded in " << total_ms << " ms";
926 }
927
928 //BBS: add config related logs
929 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" finished, returned substitutions %1%")%substitutions.size();
930 return substitutions;
931}
void load_selections(AppConfig &config, const PresetPreferences &preferred_selection=PresetPreferences())
Definition PresetBundle.cpp:4021
std::pair< PresetsConfigSubstitutions, std::string > load_system_presets_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule, bool write_caches=true)
Definition PresetBundle.cpp:3313
bool validation_mode
Definition PresetBundle.hpp:946
void normalize_compatible_presets()
Definition PresetBundle.cpp:8498
void set_calibrate_printer(std::string name)
Definition PresetBundle.cpp:5113
PresetsConfigSubstitutions load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule rule, bool read_only=false)
Definition PresetBundle.cpp:1411

References DEFAULT_USER_FOLDER_NAME, Slic3r::AppConfig::get(), load_presets(), load_selections(), load_system_presets_from_json(), load_user_presets(), m_errors, Slic3r::Never, normalize_compatible_presets(), Slic3r::PresetBundle::PresetPreferences::printer_model_id, set_calibrate_printer(), update_compatible(), update_multi_material_filament_presets(), and validation_mode.

Referenced by Slic3r::GUI::ConfigWizard::priv::apply_config(), apply_vendor_config(), load_presets(), and anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers().

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

◆ load_project_embedded_presets()

PresetsConfigSubstitutions Slic3r::PresetBundle::load_project_embedded_presets ( std::vector< Preset * > project_presets,
ForwardCompatibilitySubstitutionRule substitution_rule )
1186{
1187 // First load the vendor specific system presets.
1188 PresetsConfigSubstitutions substitutions;
1189 std::string errors_cummulative;
1190
1191 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, substitution_rule %1%, preset toltal count %2%")%substitution_rule% project_presets.size();
1192 try {
1193 this->prints.load_project_embedded_presets(project_presets, PRESET_PRINT_NAME, substitutions, substitution_rule);
1194 } catch (const std::runtime_error &err) {
1195 errors_cummulative += err.what();
1196 }
1197 try {
1198 this->filaments.load_project_embedded_presets(project_presets, PRESET_FILAMENT_NAME, substitutions, substitution_rule);
1199 } catch (const std::runtime_error &err) {
1200 errors_cummulative += err.what();
1201 }
1202 try {
1203 this->printers.load_project_embedded_presets(project_presets, PRESET_PRINTER_NAME, substitutions, substitution_rule);
1204 } catch (const std::runtime_error &err) {
1205 errors_cummulative += err.what();
1206 }
1207
1208 //this->update_multi_material_filament_presets();
1209 //this->update_compatible(PresetSelectCompatibleType::Never);
1210 // Rewrite renamed compatible references before the caller (Plater) selects the project presets.
1212 if (! errors_cummulative.empty())
1213 throw Slic3r::RuntimeError(errors_cummulative);
1214
1215 //this->load_selections(config, "");
1216
1217 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, returned substitutions %1%")%substitutions.size();
1218 return substitutions;
1219}

References filaments, load_project_embedded_presets(), normalize_compatible_presets(), PRESET_FILAMENT_NAME, PRESET_PRINT_NAME, PRESET_PRINTER_NAME, printers, and prints.

Referenced by Slic3r::GUI::Plater::priv::load_files(), and load_project_embedded_presets().

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

◆ load_selections()

void Slic3r::PresetBundle::load_selections ( AppConfig & config,
const PresetPreferences & preferred_selection = PresetPreferences() )
4022{
4023 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": enter, preferred printer_model_id %1%")%preferred_selection.printer_model_id;
4024 // Update visibility of presets based on application vendor / model / variant configuration.
4025 this->load_installed_printers(config);
4026
4027 // Update visibility of filament and sla material presets
4028 this->load_installed_filaments(config);
4029 this->load_installed_sla_materials(config);
4030
4031 // Parse the initial print / filament / printer profile names.
4032 // std::string initial_sla_print_profile_name = remove_ini_suffix(config.get("presets", PRESET_SLA_PRINT_NAME));
4033 // std::string initial_sla_material_profile_name = remove_ini_suffix(config.get("presets", PRESET_SLA_MATERIALS_NAME));
4034 std::string initial_printer_profile_name = remove_ini_suffix(config.get("presets", PRESET_PRINTER_NAME));
4035
4036 // Activate print / filament / printer profiles from either the config,
4037 // or from the preferred_model_id suggestion passed in by ConfigWizard.
4038 // If the printer profile enumerated by the config are not visible, select an alternate preset.
4039 // Do not select alternate profiles for the print / filament profiles as those presets
4040 // will be selected by the following call of this->update_compatible(PresetSelectCompatibleType::Always).
4041
4042 const Preset *initial_printer = printers.find_preset(initial_printer_profile_name);
4043 // If executed due to a Config Wizard update, preferred_printer contains the first newly installed printer, otherwise nullptr.
4044 const Preset *preferred_printer = printers.find_system_preset_by_model_and_variant(preferred_selection.printer_model_id, preferred_selection.printer_variant);
4045 printers.select_preset_by_name(preferred_printer ? preferred_printer->name : initial_printer_profile_name, true);
4046 Preset &selected_printer = printers.get_edited_preset();
4047 if (selected_printer.printer_technology() == ptFFF) {
4048 BedType bed_type = selected_printer.get_default_bed_type(this);
4049 const std::string saved_bed_type = config.get_printer_setting(selected_printer.name, "curr_bed_type");
4050 const int saved_bed_type_value = atoi(saved_bed_type.c_str());
4051 if (saved_bed_type_value > btDefault && saved_bed_type_value < btCount)
4052 bed_type = static_cast<BedType>(saved_bed_type_value);
4053 project_config.set_key_value("curr_bed_type", new ConfigOptionEnum<BedType>(bed_type));
4054 config.set("curr_bed_type", std::to_string(static_cast<int>(bed_type)));
4055 }
4056 CNumericLocalesSetter locales_setter;
4057
4058 // Orca: load from orca_presets
4059 // const auto os_presets = config.get_machine_settings(initial_printer_profile_name);
4060 std::string initial_print_profile_name = config.get_printer_setting(initial_printer_profile_name, PRESET_PRINT_NAME);
4061 std::string initial_filament_profile_name = config.get_printer_setting(initial_printer_profile_name, PRESET_FILAMENT_NAME);
4062
4063 //BBS: set default print/filament profiles to BBL's default setting
4064 if (preferred_printer)
4065 {
4066 const std::string& prefered_print_profile = preferred_printer->config.opt_string("default_print_profile");
4067 if ((!initial_print_profile_name.compare("Default Setting")) && (prefered_print_profile.size() > 0))
4068 initial_print_profile_name = prefered_print_profile;
4069
4070 const std::vector<std::string>& prefered_filament_profiles = preferred_printer->config.option<ConfigOptionStrings>("default_filament_profile")->values;
4071 if ((!initial_filament_profile_name.compare(ORCA_DEFAULT_FILAMENT_PLACEHOLDER)) && (prefered_filament_profiles.size() > 0)) {
4072 // Check if preferred filament is visible
4073 const Preset* preferred_preset = this->filaments.find_preset(prefered_filament_profiles[0], false);
4074 if (preferred_preset && preferred_preset->is_visible) {
4075 initial_filament_profile_name = prefered_filament_profiles[0];
4076 }
4077 // If not visible, keep the default ORCA_DEFAULT_FILAMENT_PLACEHOLDER which will be resolved later
4078 }
4079 }
4080
4081 // Selects the profile, leaves it to -1 if the initial profile name is empty or if it was not found.
4082 prints.select_preset_by_name_strict(initial_print_profile_name);
4083 filaments.select_preset_by_name_strict(initial_filament_profile_name);
4084 // sla_prints.select_preset_by_name_strict(initial_sla_print_profile_name);
4085 // sla_materials.select_preset_by_name_strict(initial_sla_material_profile_name);
4086
4087 // Load the names of the other filament profiles selected for a multi-material printer.
4088 // Load it even if the current printer technology is SLA.
4089 // The possibly excessive filament names will be later removed with this->update_multi_material_filament_presets()
4090 // once the FFF technology gets selected.
4091 this->filament_presets = { filaments.get_selected_preset_name() };
4092 for (unsigned int i = 1; i < 1000; ++ i) {
4093 char name[64];
4094 sprintf(name, "filament_%02u", i);
4095 auto f_name = config.get_printer_setting(initial_printer_profile_name, name);
4096 if (f_name.empty())
4097 break;
4098 this->filament_presets.emplace_back(remove_ini_suffix(f_name));
4099 }
4100
4102
4103 // Load data from AppConfig to ProjectConfig when Studio is initialized.
4104 std::vector<std::string> filament_colors;
4105 auto f_colors = config.get_printer_setting(initial_printer_profile_name, "filament_colors");
4106 if (!f_colors.empty()) {
4107 boost::algorithm::split(filament_colors, f_colors, boost::algorithm::is_any_of(","));
4108 }
4109 filament_colors.resize(filament_presets.size(), "#26A69A");
4110 project_config.option<ConfigOptionStrings>("filament_colour")->values = filament_colors;
4111
4112 std::vector<std::string> multi_filament_colors;
4113 if (config.has_printer_setting(initial_printer_profile_name, "filament_multi_colors")) {
4114 boost::algorithm::split(multi_filament_colors, config.get_printer_setting(initial_printer_profile_name, "filament_multi_colors"), boost::algorithm::is_any_of(","));
4115 }
4116 if (multi_filament_colors.size() == 0) project_config.option<ConfigOptionStrings>("filament_multi_colour")->values = filament_colors;
4117 else project_config.option<ConfigOptionStrings>("filament_multi_colour")->values = multi_filament_colors;
4118
4119 std::vector<std::string> filament_color_types;
4120 if (config.has_printer_setting(initial_printer_profile_name, "filament_color_types")) {
4121 boost::algorithm::split(filament_color_types, config.get_printer_setting(initial_printer_profile_name, "filament_color_types"), boost::algorithm::is_any_of(","));
4122 }
4123 filament_color_types.resize(filament_presets.size(), "1");
4124 project_config.option<ConfigOptionStrings>("filament_colour_type")->values = filament_color_types;
4125
4126 std::vector<int> filament_maps(filament_colors.size(), 1);
4127 project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
4128
4129 std::vector<int> filament_nozzle_maps(filament_colors.size(), 0);
4130 project_config.option<ConfigOptionInts>("filament_nozzle_map")->values = filament_nozzle_maps;
4131
4132 std::vector<int> filament_volume_maps(filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
4133 project_config.option<ConfigOptionInts>("filament_volume_map")->values = filament_volume_maps;
4134
4135 std::vector<std::string> extruder_ams_count_str;
4136 if (config.has_printer_setting(initial_printer_profile_name, "extruder_ams_count")) {
4137 boost::algorithm::split(extruder_ams_count_str, config.get_printer_setting(initial_printer_profile_name, "extruder_ams_count"), boost::algorithm::is_any_of(","));
4138 }
4139 this->extruder_ams_counts = get_extruder_ams_count(extruder_ams_count_str);
4140
4141 std::vector<std::string> matrix;
4142 if (config.has_printer_setting(initial_printer_profile_name, "flush_volumes_matrix")) {
4143 boost::algorithm::split(matrix, config.get_printer_setting(initial_printer_profile_name, "flush_volumes_matrix"), boost::algorithm::is_any_of("|"));
4144 auto flush_volumes_matrix = matrix | boost::adaptors::transformed(boost::lexical_cast<double, std::string>);
4145 project_config.option<ConfigOptionFloats>("flush_volumes_matrix")->values = std::vector<double>(flush_volumes_matrix.begin(), flush_volumes_matrix.end());
4146 }
4147 if (config.has_printer_setting(initial_printer_profile_name, "flush_volumes_vector")) {
4148 boost::algorithm::split(matrix, config.get_printer_setting(initial_printer_profile_name, "flush_volumes_vector"), boost::algorithm::is_any_of("|"));
4149 auto flush_volumes_vector = matrix | boost::adaptors::transformed(boost::lexical_cast<double, std::string>);
4150 project_config.option<ConfigOptionFloats>("flush_volumes_vector")->values = std::vector<double>(flush_volumes_vector.begin(), flush_volumes_vector.end());
4151 }
4152 if (config.has_printer_setting(initial_printer_profile_name, "flush_multiplier")) {
4153 boost::algorithm::split(matrix, config.get_printer_setting(initial_printer_profile_name, "flush_multiplier"), boost::algorithm::is_any_of("|"));
4154 auto flush_multipliers = matrix | boost::adaptors::transformed(boost::lexical_cast<double, std::string>);
4155 project_config.option<ConfigOptionFloats>("flush_multiplier")->values = std::vector<double>(flush_multipliers.begin(), flush_multipliers.end());
4156 }
4157 load_mixed_filament_settings(project_config, config, initial_printer_profile_name, filament_presets.size(), true);
4158
4159 // Update visibility of presets based on their compatibility with the active printer.
4160 // Always try to select a compatible print and filament preset to the current printer preset,
4161 // as the application may have been closed with an active "external" preset, which does not
4162 // exist.
4165
4166 if (initial_printer != nullptr && (preferred_printer == nullptr || initial_printer == preferred_printer)) {
4167 // Don't run the following code, as we want to activate default filament / SLA material profiles when installing and selecting a new printer.
4168 // Only run this code if just a filament / SLA material was installed by Config Wizard for an active Printer.
4169 auto printer_technology = printers.get_selected_preset().printer_technology();
4170 if (printer_technology == ptFFF && ! preferred_selection.filament.empty()) {
4171 std::string preferred_preset_name = get_preset_name_by_alias(Preset::Type::TYPE_FILAMENT, preferred_selection.filament);
4172 if (auto it = filaments.find_preset_internal(preferred_preset_name);
4173 it != filaments.end() && (it->name == preferred_preset_name ) && it->is_visible && it->is_compatible) {
4174 filaments.select_preset_by_name_strict(preferred_preset_name);
4175 this->filament_presets.front() = filaments.get_selected_preset_name();
4176 }
4177 } else if (printer_technology == ptSLA && ! preferred_selection.sla_material.empty()) {
4178 std::string preferred_preset_name = get_preset_name_by_alias(Preset::Type::TYPE_SLA_MATERIAL, preferred_selection.sla_material);
4179 if (auto it = sla_materials.find_preset_internal(preferred_preset_name);
4180 it != sla_materials.end() && it->is_visible && it->is_compatible)
4181 sla_materials.select_preset_by_name_strict(preferred_preset_name);
4182 }
4183 }
4184
4185 std::string first_visible_filament_name;
4186 for (auto & fp : filament_presets) {
4187 // Orca: also match the ORCA_DEFAULT_FILAMENT_PLACEHOLDER placeholder — see update_selections.
4188 if (auto it = filaments.find_preset_internal(fp); fp == ORCA_DEFAULT_FILAMENT_PLACEHOLDER || it == filaments.end() || !it->is_visible || !it->is_compatible) {
4189 if (first_visible_filament_name.empty())
4190 first_visible_filament_name = filaments.first_compatible().name;
4191 fp = first_visible_filament_name;
4192 }
4193 }
4194
4195 const Preset& current_printer = printers.get_selected_preset();
4196 const Preset* base_printer = printers.get_preset_base(current_printer);
4197 bool use_default_nozzle_volume_type = true;
4198 if (base_printer) {
4199 std::string prev_nozzle_volume_type = config.get_nozzle_volume_types_from_config(base_printer->name);
4200 if (!prev_nozzle_volume_type.empty()) {
4201 ConfigOptionEnumsGeneric* nozzle_volume_type_option = project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
4202 if (nozzle_volume_type_option->deserialize(prev_nozzle_volume_type)) {
4203 use_default_nozzle_volume_type = false;
4204 }
4205 }
4206 }
4207
4208 if (use_default_nozzle_volume_type) {
4209 project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values = current_printer.config.option<ConfigOptionEnumsGeneric>("default_nozzle_volume_type")->values;
4210 } else {
4211 // Orca: make sure `nozzle_volume_type` not shorter than `default_nozzle_volume_type`, otherwise we got array out of bound access
4212 // later in `Tab::switch_excluder`
4213 auto& opt = project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
4214 const auto& opt_default = current_printer.config.option<ConfigOptionEnumsGeneric>("default_nozzle_volume_type")->values;
4215 while (opt.size() < opt_default.size()) {
4216 opt.emplace_back(opt_default[opt.size()]);
4217 }
4218 }
4219
4220 // Parse the initial physical printer name.
4221 std::string initial_physical_printer_name = remove_ini_suffix(config.get("presets", "physical_printer"));
4222
4223 // Activate physical printer from the config
4224 if (!initial_physical_printer_name.empty())
4225 physical_printers.select_printer(initial_physical_printer_name);
4226
4227 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": finished, preferred printer_model_id %1%")%preferred_selection.printer_model_id;
4228}
void load_installed_printers(const AppConfig &config)
Definition PresetBundle.cpp:3685
void update_filament_count()
Definition PresetBundle.cpp:5390
void load_installed_sla_materials(AppConfig &config)
Definition PresetBundle.cpp:3818
const std::string & get_preset_name_by_alias(const Preset::Type &preset_type, const std::string &alias) const
Definition PresetBundle.cpp:3692
void load_installed_filaments(AppConfig &config)
Definition PresetBundle.cpp:3757
py::object selected_printer()
Definition PluginHostApp.cpp:131
BedType
Definition PrintConfig.hpp:507
@ btDefault
Definition PrintConfig.hpp:508
@ btCount
Definition PrintConfig.hpp:515
static void load_mixed_filament_settings(DynamicPrintConfig &project_config, AppConfig &config, const std::string &printer_name, size_t n_filaments, bool fallback_to_global)
Definition PresetBundle.cpp:3848
static std::string remove_ini_suffix(const std::string &name)
Definition PresetBundle.cpp:3674
@ Always
Definition Preset.hpp:527

References Slic3r::Always, Slic3r::btCount, Slic3r::btDefault, Slic3r::Preset::config, Slic3r::ConfigOptionEnumsGenericTempl< NULLABLE >::deserialize(), extruder_ams_counts, Slic3r::PresetBundle::PresetPreferences::filament, filament_presets, filaments, Slic3r::flush_volumes_matrix(), Slic3r::AppConfig::get(), Slic3r::get_extruder_ams_count(), Slic3r::AppConfig::get_nozzle_volume_types_from_config(), get_preset_name_by_alias(), Slic3r::AppConfig::get_printer_setting(), Slic3r::AppConfig::has_printer_setting(), Slic3r::Preset::is_visible, load_installed_filaments(), load_installed_printers(), load_installed_sla_materials(), Slic3r::load_mixed_filament_settings(), load_selections(), Slic3r::Preset::name, Slic3r::nvtStandard, Slic3r::DynamicConfig::opt_string(), Slic3r::ConfigBase::option(), ORCA_DEFAULT_FILAMENT_PLACEHOLDER, physical_printers, PRESET_FILAMENT_NAME, PRESET_PRINT_NAME, PRESET_PRINTER_NAME, Slic3r::PresetBundle::PresetPreferences::printer_model_id, Slic3r::printer_technology(), Slic3r::PresetBundle::PresetPreferences::printer_variant, printers, prints, project_config, Slic3r::ptFFF, Slic3r::ptSLA, Slic3r::remove_ini_suffix(), Slic3r::ConfigOptionVector< T >::resize(), Slic3r::AppConfig::set(), Slic3r::ConfigOptionVector< int >::size(), Slic3r::PresetBundle::PresetPreferences::sla_material, sla_materials, Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::TYPE_SLA_MATERIAL, update_compatible(), update_filament_count(), and update_multi_material_filament_presets().

Referenced by load_presets(), load_selections(), and Slic3r::GUI::GuideFrame::run().

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

◆ load_source_vendor()

const PresetBundle * Slic3r::PresetBundle::load_source_vendor ( const boost::filesystem::path & root_dir,
const std::string & vendor_id,
ForwardCompatibilitySubstitutionRule compatibility_rule,
std::string & error,
bool allow_cache = false )
private
658{
659 auto key = std::make_tuple(root_dir.string(), vendor_id, compatibility_rule, allow_cache);
660 if (auto it = m_source_vendor_bundles.find(key); it != m_source_vendor_bundles.end())
661 return it->second.get();
662
663 // The library loads with no base of its own, so the tree a vendor inherits from
664 // is the same one that resolves the library's own presets. It is only a base, so
665 // it comes from its cache whenever that is all that is installed, even when the
666 // vendor itself is parsed (a vendor updated over the air).
667 const std::string library_file = std::string(ORCA_FILAMENT_LIBRARY);
668 const bool library_json = boost::filesystem::is_regular_file(root_dir / (library_file + ".json"));
669 const bool library_cache_only = !library_json && boost::filesystem::is_regular_file(root_dir / (library_file + ".opc"));
670 const PresetBundle *library = nullptr;
671 if (vendor_id != ORCA_FILAMENT_LIBRARY && (library_json || library_cache_only)) {
672 library = load_source_vendor(root_dir, ORCA_FILAMENT_LIBRARY, compatibility_rule, error, allow_cache || library_cache_only);
673 if (library == nullptr) {
674 error = "OrcaFilamentLibrary contains invalid presets";
675 return nullptr;
676 }
677 }
678
679 auto bundle = std::make_unique<PresetBundle>();
680 bundle->m_preserve_vendor_source_paths = true;
681 bundle->load_vendor_configs_from_json(root_dir.string(), vendor_id, LoadSystem, compatibility_rule, library, allow_cache);
682 if (bundle->error_count() != 0) {
683 error = "Vendor bundle contains invalid presets";
684 return nullptr;
685 }
686 return m_source_vendor_bundles.emplace(std::move(key), std::move(bundle)).first->second.get();
687}
std::map< std::tuple< std::string, std::string, ForwardCompatibilitySubstitutionRule, bool >, std::unique_ptr< PresetBundle > > m_source_vendor_bundles
Definition PresetBundle.hpp:909
const PresetBundle * load_source_vendor(const boost::filesystem::path &root_dir, const std::string &vendor_id, ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error, bool allow_cache=false)
Definition PresetBundle.cpp:654

References PresetBundle(), load_source_vendor(), LoadSystem, m_source_vendor_bundles, and ORCA_FILAMENT_LIBRARY.

Referenced by load_source_vendor(), resolve_preset_config(), and resolve_system_preset().

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

◆ load_system_filaments_json()

std::pair< PresetsConfigSubstitutions, std::string > Slic3r::PresetBundle::load_system_filaments_json ( ForwardCompatibilitySubstitutionRule compatibility_rule)
3554{
3555 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, compatibility_rule %1%") % compatibility_rule;
3557 // Loading system presets, don't log substitutions.
3560 // Loading system presets, throw on unknown option value.
3562
3563 // Here the vendor specific read only Config Bundles are stored.
3564 boost::filesystem::path dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred();
3565 PresetsConfigSubstitutions substitutions;
3566 std::string errors_cummulative;
3567 bool first = true;
3568 // The filament library loads first, so the filaments that inherit its bases resolve.
3569 std::vector<std::string> vendor_names;
3570 for (const std::string &vendor_name : vendor_names_in(dir))
3571 vendor_names.insert(vendor_name == ORCA_FILAMENT_LIBRARY ? vendor_names.begin() : vendor_names.end(), vendor_name);
3572 for (const std::string &vendor_name : vendor_names) {
3573 try {
3574 if (first) {
3575 // Reset this PresetBundle and load the first vendor config.
3576 append(substitutions, this->load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule).first);
3577 first = false;
3578 } else {
3579 // Load the other vendor configs, merge them with this PresetBundle.
3580 // Report duplicate profiles.
3581 PresetBundle other;
3582 append(substitutions, other.load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadSystem | PresetBundle::LoadFilamentOnly, compatibility_rule, this).first);
3583 std::vector<std::string> duplicates = std::move(this->merge_presets({ &other }).front());
3584 if (!duplicates.empty()) {
3585 errors_cummulative += "Found duplicated settings in vendor " + vendor_name + "'s json file lists: ";
3586 for (size_t i = 0; i < duplicates.size(); ++i) {
3587 if (i > 0) errors_cummulative += ", ";
3588 errors_cummulative += duplicates[i];
3589 }
3590 }
3591 }
3592 } catch (const std::runtime_error &err) {
3593 errors_cummulative += err.what();
3594 errors_cummulative += "\n";
3595 }
3596 }
3597
3598 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, errors_cummulative %1%") % errors_cummulative;
3599 return std::make_pair(std::move(substitutions), errors_cummulative);
3600}
std::vector< std::vector< std::string > > merge_presets(const std::vector< PresetBundle * > &others)
Definition PresetBundle.cpp:3628
std::pair< PresetsConfigSubstitutions, size_t > load_vendor_configs_from_json(const std::string &dir, const std::string &vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule, const PresetBundle *base_bundle=nullptr, bool allow_cache=true)
Definition PresetBundle.cpp:7925
@ EnableSystemSilent
Definition Config.hpp:249
@ EnableSilent
Definition Config.hpp:247
@ EnableSilentDisableSystem
Definition Config.hpp:251
void append(std::vector< T, Alloc > &dest, const std::vector< T, Alloc2 > &src)
Definition libslic3r.h:157

References PresetBundle(), Slic3r::append(), Slic3r::Disable, Slic3r::EnableSilent, Slic3r::EnableSilentDisableSystem, Slic3r::EnableSystemSilent, load_system_filaments_json(), load_vendor_configs_from_json(), LoadFilamentOnly, LoadSystem, merge_presets(), ORCA_FILAMENT_LIBRARY, Slic3r::resources_dir(), and Slic3r::vendor_names_in().

Referenced by Slic3r::GUI::load_filament_id_sources(), and load_system_filaments_json().

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

◆ load_system_models_from_json()

std::pair< PresetsConfigSubstitutions, std::string > Slic3r::PresetBundle::load_system_models_from_json ( ForwardCompatibilitySubstitutionRule compatibility_rule)
3526{
3527 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, compatibility_rule %1%") % compatibility_rule;
3529 // Loading system presets, don't log substitutions.
3532 // Loading system presets, throw on unknown option value.
3534
3535 // Here the vendor specific read only Config Bundles are stored.
3536 boost::filesystem::path dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred();
3537 PresetsConfigSubstitutions substitutions;
3538 std::string errors_cummulative;
3539 for (const std::string &vendor_name : vendor_names_in(dir)) {
3540 try {
3541 // Load the config bundle, flatten it.
3542 append(substitutions, load_vendor_configs_from_json(dir.string(), vendor_name, PresetBundle::LoadVendorOnly, compatibility_rule).first);
3543 } catch (const std::runtime_error &err) {
3544 errors_cummulative += err.what();
3545 errors_cummulative += "\n";
3546 }
3547 }
3548
3549 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, errors_cummulative %1%") % errors_cummulative;
3550 return std::make_pair(std::move(substitutions), errors_cummulative);
3551}

References Slic3r::append(), Slic3r::Disable, Slic3r::EnableSilent, Slic3r::EnableSilentDisableSystem, Slic3r::EnableSystemSilent, load_system_models_from_json(), load_vendor_configs_from_json(), LoadVendorOnly, Slic3r::resources_dir(), and Slic3r::vendor_names_in().

Referenced by Slic3r::GUI::get_exist_vendor_choices(), and load_system_models_from_json().

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

◆ load_system_presets_from_json()

std::pair< PresetsConfigSubstitutions, std::string > Slic3r::PresetBundle::load_system_presets_from_json ( ForwardCompatibilitySubstitutionRule compatibility_rule,
bool write_caches = true )
private
3315{
3316 //BBS: add config related logs
3317 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, compatibility_rule %1%")%compatibility_rule;
3319 // Loading system presets, don't log substitutions.
3322 // Loading system presets, throw on unknown option value.
3324
3325 // Here the vendor specific read only Config Bundles are stored.
3326 //BBS: change directory by design
3327 boost::filesystem::path dir = (boost::filesystem::path(data_dir()) / PRESET_SYSTEM_DIR).make_preferred();
3328 if (validation_mode)
3329 dir = (boost::filesystem::path(data_dir())).make_preferred();
3330
3331 // The vendors below are loaded whole and against each other — the filament
3332 // library first, then every other vendor with it as the base — so each parse
3333 // is complete enough to be worth caching.
3335
3336 // Sorted, so any duplicate-preset warning comes out in the same order on every run.
3337 std::vector<VendorSource> vendors;
3338 for (const std::string& name : vendor_names_in(dir))
3339 if (name == ORCA_FILAMENT_LIBRARY || !(validation_mode && !vendor_to_validate.empty() && name != vendor_to_validate))
3340 vendors.push_back({ name, dir });
3341 auto result = this->load_vendors(vendors, compatibility_rule, true);
3342
3343 this->update_system_maps();
3344
3345 //BBS: add config related logs
3346 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, errors_cummulative %1%")%result.second;
3347 return result;
3348}
#define PRESET_SYSTEM_DIR
Definition Preset.hpp:31
std::pair< PresetsConfigSubstitutions, std::string > load_vendors(const std::vector< VendorSource > &vendors, ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache, const std::atomic< bool > *cancel=nullptr, std::vector< std::string > *failed=nullptr)
Definition PresetBundle.cpp:3350
bool m_generate_vendor_caches
Definition PresetBundle.hpp:901
std::string vendor_to_validate
Definition PresetBundle.hpp:947

References Slic3r::data_dir(), Slic3r::Disable, Slic3r::EnableSilent, Slic3r::EnableSilentDisableSystem, Slic3r::EnableSystemSilent, load_system_presets_from_json(), load_vendors(), m_generate_vendor_caches, ORCA_FILAMENT_LIBRARY, PRESET_SYSTEM_DIR, update_system_maps(), validation_mode, Slic3r::vendor_names_in(), vendor_to_validate, and vendors.

Referenced by load_presets(), and load_system_presets_from_json().

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

◆ load_user_presets() [1/2]

PresetsConfigSubstitutions Slic3r::PresetBundle::load_user_presets ( AppConfig & config,
std::map< std::string, std::map< std::string, std::string > > & my_presets,
ForwardCompatibilitySubstitutionRule rule )
1873{
1874 // First load the vendor specific system presets.
1875 PresetsConfigSubstitutions substitutions;
1876 std::string errors_cummulative;
1877 bool process_added = false, filament_added = false, machine_added = false;
1878
1879 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, substitution_rule %1%, preset toltal count %2%")%substitution_rule%my_presets.size();
1880 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" print's selected_idx %1%, selected_name %2%") %prints.get_selected_idx() %prints.get_selected_preset_name();
1881 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" filament's selected_idx %1%, selected_name %2%") %filaments.get_selected_idx() %filaments.get_selected_preset_name();
1882 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" printers's selected_idx %1%, selected_name %2%") %printers.get_selected_idx() %printers.get_selected_preset_name();
1883
1884 // Sync removing
1885 remove_users_preset(config, &my_presets);
1886
1887 std::map<std::string, std::map<std::string, std::string>>::iterator it;
1888 for (int pass = 0; pass < 2; ++pass)
1889 for (it = my_presets.begin(); it != my_presets.end(); it++) {
1890 std::string name = it->first;
1891 std::map<std::string, std::string>& value_map = it->second;
1892 // Load user root presets at first pass
1893 std::map<std::string, std::string>::iterator inherits_iter = value_map.find(BBL_JSON_KEY_INHERITS);
1894 if ((pass == 1) == (inherits_iter == value_map.end() || inherits_iter->second.empty()))
1895 continue;
1896 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " start load from cloud: " << name;
1897 //get the type first
1898 std::map<std::string, std::string>::iterator type_iter = value_map.find(BBL_JSON_KEY_TYPE);
1899 if (type_iter == value_map.end()) {
1900 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(" can not find type for setting %1%")%name;
1901 continue;
1902 }
1903 try {
1904 PresetCollection *preset_collection = nullptr;
1905 if (type_iter->second == PRESET_IOT_PRINT_TYPE) {
1906 preset_collection = &(this->prints);
1907 process_added |= preset_collection->load_user_preset(name, value_map, substitutions, substitution_rule, PresetOrigin(PresetOrigin::Kind::User));
1908 }
1909 else if (type_iter->second == PRESET_IOT_FILAMENT_TYPE) {
1910 preset_collection = &(this->filaments);
1911 filament_added |= preset_collection->load_user_preset(name, value_map, substitutions, substitution_rule, PresetOrigin(PresetOrigin::Kind::User));
1912 }
1913 else if (type_iter->second == PRESET_IOT_PRINTER_TYPE) {
1914 preset_collection = &(this->printers);
1915 machine_added |= preset_collection->load_user_preset(name, value_map, substitutions, substitution_rule, PresetOrigin(PresetOrigin::Kind::User));
1916 }
1917 else {
1918 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("invalid type %1% for setting %2%") %type_iter->second %name;
1919 continue;
1920 }
1921 }
1922 catch (const std::runtime_error& err) {
1923 errors_cummulative += err.what();
1924 }
1925 }
1926 /*if (process_added) {
1927 this->prints.update_after_user_presets_loaded();
1928 }
1929 if (filament_added) {
1930 this->filaments.update_after_user_presets_loaded();
1931 }
1932 if (machine_added) {
1933 this->printers.update_after_user_presets_loaded();
1934 }*/
1935
1936 // Rewrite renamed compatible references in synced user presets before compatibility is evaluated.
1938
1941 //this->load_selections(config, PresetPreferences());
1942
1944
1945 if (! errors_cummulative.empty())
1946 throw Slic3r::RuntimeError(errors_cummulative);
1947
1948 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished, process_added %1%, filament_added %2%, machine_added %3%")%process_added %filament_added %machine_added;
1949 return substitutions;
1950}
#define PRESET_IOT_FILAMENT_TYPE
Definition Preset.hpp:50
#define BBL_JSON_KEY_TYPE
Definition Preset.hpp:66
#define PRESET_IOT_PRINT_TYPE
Definition Preset.hpp:51
#define PRESET_IOT_PRINTER_TYPE
Definition Preset.hpp:49
void remove_users_preset(AppConfig &config, std::map< std::string, std::map< std::string, std::string > > *my_presets=nullptr)
Definition PresetBundle.cpp:3202
@ User
Definition Preset.hpp:495

References BBL_JSON_KEY_INHERITS, BBL_JSON_KEY_TYPE, filaments, Slic3r::PresetCollection::load_user_preset(), load_user_presets(), Slic3r::Never, normalize_compatible_presets(), PRESET_IOT_FILAMENT_TYPE, PRESET_IOT_PRINT_TYPE, PRESET_IOT_PRINTER_TYPE, printers, prints, remove_users_preset(), set_calibrate_printer(), update_compatible(), update_multi_material_filament_presets(), and Slic3r::PresetOrigin::User.

Here is the call graph for this function:

◆ load_user_presets() [2/2]

PresetsConfigSubstitutions Slic3r::PresetBundle::load_user_presets ( std::string user,
ForwardCompatibilitySubstitutionRule rule,
bool read_only = false )
1412{
1413 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " entry and user is: " << user;
1414 PresetsConfigSubstitutions substitutions;
1415 std::string errors_cummulative;
1416
1417 fs::path user_folder(data_dir() + "/" + PRESET_USER_DIR);
1418 if (!fs::exists(user_folder)) {
1419 if (read_only)
1420 return substitutions;
1421 fs::create_directory(user_folder);
1422 }
1423
1424 std::string dir_user_presets = data_dir() + "/" + PRESET_USER_DIR + "/" + user;
1425 fs::path folder(user_folder / user);
1426 if (!fs::exists(folder)) {
1427 if (read_only)
1428 return substitutions;
1429 fs::create_directory(folder);
1430 }
1431
1432 bundles.WriteLock();
1433 bundles.m_bundles.clear();
1434 bundles.WriteUnlock();
1435
1436 const auto user_load_t0 = std::chrono::steady_clock::now();
1437
1438 // Reads one bundle's metadata under the lock, per file, so the lock is never
1439 // held when bundles.WriteLock() is taken afterwards.
1440 auto load_bundle_metadata = [read_only](const fs::path &metadata_file, BundleMetadata &metadata) {
1441 InstanceLock instance_lock(user_presets_lock_path(read_only));
1442 return metadata.load_from_json(metadata_file.string());
1443 };
1444
1445 // Load bundle metadata from _local directory first
1446 fs::path local_dir(folder / PRESET_LOCAL_DIR);
1447 if (fs::exists(local_dir)) {
1448 dir_user_presets_local = local_dir;
1449 for (auto& entry : fs::directory_iterator(local_dir)) {
1450 if (!fs::is_directory(entry.path())) continue;
1451
1452 std::string bundle_dir = entry.path().string();
1453
1454 fs::path metadata_file = entry.path() / PRESET_BUNDLE_METADATA;
1455 if (!fs::exists(metadata_file)) continue;
1456
1457 BundleMetadata metadata;
1458 if (!load_bundle_metadata(metadata_file, metadata)) continue;
1459 load_bundle_presets(*this, bundle_dir, metadata, PresetOrigin(PresetOrigin::Kind::LocalBundle, metadata.id),
1460 substitutions, substitution_rule, read_only);
1461 metadata.bundle_type = BundleType::Local;
1462 metadata.path = metadata_file.string();
1463
1464 bundles.WriteLock();
1465 bundles.m_bundles[metadata.id] = metadata;
1466 bundles.WriteUnlock();
1467 }
1468 }
1469
1470 // Load bundle metadata from _subscribed directory
1471 fs::path subscribed_dir(folder / PRESET_SUBSCRIBED_DIR);
1472 if (fs::exists(subscribed_dir)) {
1473 for (auto& entry : fs::directory_iterator(subscribed_dir)) {
1474 if (!fs::is_directory(entry.path())) continue;
1475
1476 std::string bundle_dir = entry.path().string();
1477
1478 fs::path metadata_file = entry.path() / PRESET_BUNDLE_METADATA;
1479 if (!fs::exists(metadata_file)) continue;
1480
1481 BundleMetadata metadata;
1482 if (!load_bundle_metadata(metadata_file, metadata)) continue;
1483 metadata.is_subscribed = true;
1484
1485 load_bundle_presets(*this, bundle_dir, metadata, PresetOrigin(PresetOrigin::Kind::SubscribedBundle, metadata.id),
1486 substitutions, substitution_rule, read_only);
1487
1488 metadata.bundle_type = BundleType::Subscribed;
1489 metadata.path = metadata_file.string();
1490 metadata.update_available = false;
1491
1492 bundles.WriteLock();
1493 bundles.m_bundles[metadata.id] = metadata;
1494 bundles.WriteUnlock();
1495 }
1496 }
1497
1498 // BBS do not load sla_print
1499 // BBS: change directories by design
1500
1501 {
1502 const auto json_t0 = std::chrono::steady_clock::now();
1503 try {
1504 std::string sel = prints.get_selected_preset().name;
1505 this->prints.load_presets(dir_user_presets, PRESET_PRINT_NAME, substitutions, substitution_rule,
1506 nullptr, PresetOrigin(), read_only);
1507 prints.select_preset_by_name(sel, false);
1508 } catch (const std::runtime_error& err) { errors_cummulative += err.what(); }
1509 try {
1510 std::string sel = filaments.get_selected_preset().name;
1511 this->filaments.load_presets(dir_user_presets, PRESET_FILAMENT_NAME, substitutions, substitution_rule,
1512 nullptr, PresetOrigin(), read_only);
1513 filaments.select_preset_by_name(sel, false);
1514 } catch (const std::runtime_error& err) { errors_cummulative += err.what(); }
1515 try {
1516 std::string sel = printers.get_selected_preset().name;
1517 this->printers.load_presets(dir_user_presets, PRESET_PRINTER_NAME, substitutions, substitution_rule,
1518 nullptr, PresetOrigin(), read_only);
1519 printers.select_preset_by_name(sel, false);
1520 } catch (const std::runtime_error& err) { errors_cummulative += err.what(); }
1521 if (!errors_cummulative.empty()) throw Slic3r::RuntimeError(errors_cummulative);
1522
1523 const auto json_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
1524 std::chrono::steady_clock::now() - json_t0).count();
1525 BOOST_LOG_TRIVIAL(info) << "PresetBundle: user presets loaded from JSON in " << json_ms << " ms";
1526 }
1527
1528 {
1529 const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
1530 std::chrono::steady_clock::now() - user_load_t0).count();
1531 BOOST_LOG_TRIVIAL(info) << "PresetBundle: user + bundle presets loaded in " << ms << " ms";
1532 }
1533
1537
1539}
#define PRESET_SUBSCRIBED_DIR
Definition Preset.hpp:45
boost::filesystem::path dir_user_presets_local
Definition PresetBundle.hpp:533
std::string user_presets_lock_path(bool read_only)
Definition Preset.cpp:146
static void load_bundle_presets(PresetBundle &bundle, const std::string &bundle_dir, BundleMetadata &metadata, const PresetOrigin &origin, PresetsConfigSubstitutions &substitutions, ForwardCompatibilitySubstitutionRule substitution_rule, bool read_only=false)
Definition PresetBundle.cpp:1390
@ Subscribed
Definition PresetBundle.hpp:114
@ SubscribedBundle
Definition Preset.hpp:495
@ LocalBundle
Definition Preset.hpp:495

References Slic3r::BundleMetadata::bundle_type, bundles, Slic3r::data_dir(), dir_user_presets_local, filaments, Slic3r::BundleMetadata::id, Slic3r::BundleMetadata::is_subscribed, Slic3r::load_bundle_presets(), load_user_presets(), Slic3r::Local, Slic3r::PresetOrigin::LocalBundle, Slic3r::Never, Slic3r::BundleMetadata::path, PRESET_BUNDLE_METADATA, PRESET_FILAMENT_NAME, PRESET_LOCAL_DIR, PRESET_PRINT_NAME, PRESET_PRINTER_NAME, PRESET_SUBSCRIBED_DIR, PRESET_USER_DIR, printers, prints, set_calibrate_printer(), Slic3r::Subscribed, Slic3r::PresetOrigin::SubscribedBundle, Slic3r::BundleMetadata::update_available, update_compatible(), update_multi_material_filament_presets(), and Slic3r::user_presets_lock_path().

Referenced by Slic3r::GUI::CreateFilamentPresetDialog::get_all_filament_presets(), Slic3r::GUI::load_filament_id_sources(), load_presets(), Slic3r::GUI::CreatePrinterPresetDialog::load_system_and_user_presets_with_curr_model(), load_user_presets(), and load_user_presets().

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

◆ load_vendor_cache()

bool Slic3r::PresetBundle::load_vendor_cache ( const std::string & cache_path,
const std::string & expected_vendor_name,
const Semver & expected_vendor_version,
const PresetBundle * base_bundle = nullptr )
9104{
9105 // Read and validated before this bundle is touched: a rejected file leaves
9106 // no state to roll back.
9107 VendorCacheData data;
9108 if (! VendorCacheFile::load(cache_path, expected_vendor_name, expected_vendor_version, data))
9109 return false;
9110 // VendorCacheFile::load checked the names match.
9111 return this->install_vendor_cache(cache_path, expected_vendor_name, std::move(data), base_bundle);
9112}
static bool load(const std::string &path, const std::string &expected_vendor_name, const Semver &expected_vendor_version, VendorCacheData &data)
Definition PresetCacheFormat.cpp:505

References PresetBundle(), install_vendor_cache(), Slic3r::VendorCacheFile::load(), and load_vendor_cache().

Referenced by anonymous_namespace{profile_include_dump.cpp}::load_vendor(), and load_vendor_cache().

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

◆ load_vendor_configs_from_json()

std::pair< PresetsConfigSubstitutions, size_t > Slic3r::PresetBundle::load_vendor_configs_from_json ( const std::string & dir,
const std::string & vendor_name,
LoadConfigBundleAttributes flags,
ForwardCompatibilitySubstitutionRule compatibility_rule,
const PresetBundle * base_bundle = nullptr,
bool allow_cache = true )
7928{
7929 return this->install_vendor_read(this->read_vendor(dir, vendor_name, flags, compatibility_rule, allow_cache), base_bundle);
7930}
std::pair< PresetsConfigSubstitutions, size_t > install_vendor_read(VendorRead &&read, const PresetBundle *base_bundle)
Definition PresetBundle.cpp:8337
VendorRead read_vendor(const std::string &dir, const std::string &vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache)
Definition PresetBundle.cpp:7932

References PresetBundle(), install_vendor_read(), load_vendor_configs_from_json(), and read_vendor().

Referenced by Slic3r::GUI::CreatePrinterPresetDialog::load_system_and_user_presets_with_curr_model(), load_system_filaments_json(), load_system_models_from_json(), anonymous_namespace{profile_include_dump.cpp}::load_vendor(), and load_vendor_configs_from_json().

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

◆ load_vendors()

std::pair< PresetsConfigSubstitutions, std::string > Slic3r::PresetBundle::load_vendors ( const std::vector< VendorSource > & vendors,
ForwardCompatibilitySubstitutionRule compatibility_rule,
bool allow_cache,
const std::atomic< bool > * cancel = nullptr,
std::vector< std::string > * failed = nullptr )
3353{
3354 const auto load_t0 = std::chrono::steady_clock::now();
3355 auto canceled = [cancel] { return cancel != nullptr && cancel->load(); };
3356
3357 PresetsConfigSubstitutions substitutions;
3358 std::string errors_cummulative;
3359 bool first = true;
3360 // Other vendors inherit from nothing but the library, and only installing them
3361 // looks it up, so each is read while it loads and installed once both are done.
3362 const VendorSource* orca_lib = nullptr;
3363 std::vector<const VendorSource*> other_vendors;
3364 other_vendors.reserve(vendors.size());
3365 for (const VendorSource& vendor : vendors) {
3366 if (vendor.name == ORCA_FILAMENT_LIBRARY)
3367 orca_lib = &vendor;
3368 else
3369 other_vendors.push_back(&vendor);
3370 }
3371
3372 // One of the other vendors, loaded into a PresetBundle of its own.
3373 struct VendorLoad
3374 {
3375 const VendorSource* source { nullptr };
3376 std::unique_ptr<PresetBundle> bundle;
3377 VendorRead read;
3378 PresetsConfigSubstitutions substitutions;
3379 std::string error;
3380 // Counts the vendor's read and the library load; the second to finish installs it.
3381 std::atomic<int> ready { 0 };
3382 };
3383 std::vector<VendorLoad> loads(other_vendors.size());
3384 for (size_t i = 0; i < other_vendors.size(); ++i)
3385 loads[i].source = other_vendors[i];
3386
3387 // Started slowest first, since the load ends when the slowest vendor does.
3388 std::vector<size_t> by_cost(loads.size());
3389 std::iota(by_cost.begin(), by_cost.end(), size_t(0));
3390 // A parse from JSON costs far more than any cache load, so parses go first, and
3391 // within each group the bigger file, the cache or the <vendor>.json that lists what
3392 // to parse. A cache older than its profile is ordered as a parse.
3393 const bool reads_caches = allow_cache && ! validation_mode;
3394 std::vector<std::pair<bool, uintmax_t>> vendor_costs(loads.size());
3395 for (size_t i = 0; i < loads.size(); ++i) {
3396 const VendorSource& vendor = *loads[i].source;
3397 const boost::filesystem::path cache = vendor.dir / (vendor.name + ".opc");
3398 const boost::filesystem::path profile = vendor.dir / (vendor.name + ".json");
3399 boost::system::error_code ec, profile_ec;
3400 const uintmax_t cache_size = reads_caches ? boost::filesystem::file_size(cache, ec) : 0;
3401 if (reads_caches && ! ec) {
3402 const std::time_t profile_time = boost::filesystem::last_write_time(profile, profile_ec);
3403 if (profile_ec || profile_time <= boost::filesystem::last_write_time(cache, ec)) {
3404 vendor_costs[i] = { false, cache_size };
3405 continue;
3406 }
3407 }
3408 const uintmax_t profile_size = boost::filesystem::file_size(profile, profile_ec);
3409 vendor_costs[i] = { true, profile_ec ? 0 : profile_size };
3410 }
3411 std::stable_sort(by_cost.begin(), by_cost.end(),
3412 [&](size_t a, size_t b) { return vendor_costs[a] > vendor_costs[b]; });
3413
3414 // A vendor that failed to read, or that is still to install when `cancel` is
3415 // set, is left out.
3416 auto install = [&](VendorLoad& load) {
3417 if (load.bundle && ! canceled()) {
3418 try {
3419 load.substitutions = load.bundle->install_vendor_read(std::move(load.read), this).first;
3420 } catch (const std::runtime_error &err) {
3421 load.error = err.what();
3422 load.bundle.reset();
3423 }
3424 } else
3425 load.bundle.reset();
3426 load.read = VendorRead();
3427 };
3428 tbb::task_group group;
3429 group.run([&] {
3430 // An auto_partitioner splits the range only while a worker is asking for work,
3431 // which at this size left every vendor on the calling thread.
3432 tbb::parallel_for(tbb::blocked_range<size_t>(0, loads.size(), 1),
3433 [&](const tbb::blocked_range<size_t>& range) {
3434 for (size_t k = range.begin(); k < range.end(); ++k) {
3435 VendorLoad& load = loads[by_cost[k]];
3436 if (! canceled()) {
3437 try {
3438 auto bundle = std::make_unique<PresetBundle>();
3439 bundle->set_is_validation_mode(validation_mode);
3440 bundle->set_generate_vendor_caches(m_generate_vendor_caches);
3441 load.read = bundle->read_vendor(load.source->dir.string(), load.source->name,
3442 PresetBundle::LoadSystem, compatibility_rule, allow_cache);
3443 load.bundle = std::move(bundle);
3444 } catch (const std::runtime_error &err) {
3445 load.error = err.what();
3446 }
3447 }
3448 if (++ load.ready == 2)
3449 install(load);
3450 }
3451 }, tbb::simple_partitioner());
3452 });
3453 if (orca_lib != nullptr && ! canceled()) {
3454 try {
3455 // Match a fresh launch before parsing: hold aliases and the error
3456 // counter survive reset(), and would otherwise carry prior-cycle
3457 // state into this load.
3459 this->m_errors = 0;
3460 append(substitutions, this->load_vendor_configs_from_json(
3461 orca_lib->dir.string(), orca_lib->name, PresetBundle::LoadSystem, compatibility_rule, nullptr, allow_cache).first);
3462 first = false;
3463 } catch (const std::runtime_error &err) {
3464 if (validation_mode)
3465 throw err;
3466 errors_cummulative += err.what();
3467 errors_cummulative += "\n";
3468 if (failed != nullptr)
3469 failed->push_back(orca_lib->name);
3470 }
3471 }
3472 for (size_t k : by_cost)
3473 if (++ loads[k].ready == 2)
3474 group.run([&install, &load = loads[k]] { install(load); });
3475 group.wait();
3476
3477 // Merged in the original vendor order, so any duplicate-warning output stays
3478 // stable across runs.
3479 std::vector<PresetBundle*> bundles;
3480 for (VendorLoad& load : loads)
3481 if (load.bundle)
3482 bundles.push_back(load.bundle.get());
3483 const std::vector<std::vector<std::string>> duplicates = this->merge_presets(bundles);
3484 size_t merged = 0;
3485 for (VendorLoad& load : loads) {
3486 if (! load.error.empty()) {
3487 if (validation_mode)
3488 throw std::runtime_error(load.error);
3489 errors_cummulative += load.error;
3490 errors_cummulative += "\n";
3491 if (failed != nullptr)
3492 failed->push_back(load.source->name);
3493 continue;
3494 }
3495 if (! load.bundle)
3496 continue;
3497
3498 const std::string& vendor_name = load.source->name;
3499 const std::vector<std::string>& vendor_duplicates = duplicates[merged ++];
3500 append(substitutions, std::move(load.substitutions));
3501 first = false;
3502 if (!vendor_duplicates.empty()) {
3503 errors_cummulative += "Found duplicated settings in vendor " + vendor_name + "'s json file lists: ";
3504 for (size_t k = 0; k < vendor_duplicates.size(); ++k) {
3505 if (k > 0)
3506 errors_cummulative += ", ";
3507 errors_cummulative += vendor_duplicates[k];
3508 ++m_errors;
3509 BOOST_LOG_TRIVIAL(error) << "Found duplicated preset: " + vendor_duplicates[k] + " in vendor: " + vendor_name + ": ";
3510 }
3511 }
3512 }
3513
3514 if (first) {
3515 // No config bundle loaded, reset.
3516 this->reset(false);
3517 }
3518
3519 const auto load_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
3520 std::chrono::steady_clock::now() - load_t0).count();
3521 BOOST_LOG_TRIVIAL(info) << "PresetBundle: " << vendors.size() << " vendor(s) loaded in " << load_ms << " ms";
3522 return std::make_pair(std::move(substitutions), errors_cummulative);
3523}
void load(Archive &archive, wxString &d)
Definition GLGizmoEmboss.cpp:3405
boost::filesystem::path dir
Definition PresetBundle.hpp:720
Definition PresetBundle.hpp:767
Definition PresetBundle.hpp:718
auto range(Cont &&cont)
Definition libslic3r.h:405

References Slic3r::PresetBundle::VendorSource::dir, load(), load_vendors(), Slic3r::PresetBundle::VendorSource::name, ORCA_FILAMENT_LIBRARY, Slic3r::range(), validation_mode, and vendors.

Referenced by Slic3r::GUI::GuideFrame::BuildProfileDataFromVendors(), load_system_presets_from_json(), and load_vendors().

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

◆ log_errors()

void Slic3r::PresetBundle::log_errors ( const std::vector< std::string > & errors)
private
7575{
7576 for (const std::string& error : errors) {
7577 ++m_errors;
7578 BOOST_LOG_TRIVIAL(error) << error;
7579 }
7580}

References log_errors(), and m_errors.

Referenced by commit_vendor_preset(), install_vendor_entries(), install_vendor_read(), and log_errors().

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

◆ materials() [1/2]

PresetCollection & Slic3r::PresetBundle::materials ( PrinterTechnology pt)
inline
501{ return pt == ptFFF ? this->filaments : this->sla_materials; }

References Slic3r::ptFFF.

◆ materials() [2/2]

const PresetCollection & Slic3r::PresetBundle::materials ( PrinterTechnology pt) const
inline
502{ return pt == ptFFF ? this->filaments : this->sla_materials; }

References Slic3r::ptFFF.

◆ merge_presets()

std::vector< std::vector< std::string > > Slic3r::PresetBundle::merge_presets ( const std::vector< PresetBundle * > & others)
private
3629{
3630 for (PresetBundle *other : others)
3631 this->vendors.insert(other->vendors.begin(), other->vendors.end());
3632 std::vector<std::vector<std::string>> duplicates(others.size());
3633 auto merge = [&](auto collection) {
3634 std::vector<PresetCollection*> other_collections;
3635 for (PresetBundle *other : others)
3636 other_collections.push_back(&(other->*collection));
3637 std::vector<std::vector<std::string>> collection_duplicates = (this->*collection).merge_presets(other_collections, this->vendors);
3638 for (size_t i = 0; i < others.size(); ++ i)
3639 append(duplicates[i], std::move(collection_duplicates[i]));
3640 };
3646 for (PresetBundle *other : others) {
3647 append(this->obsolete_presets.prints, std::move(other->obsolete_presets.prints));
3648 append(this->obsolete_presets.sla_prints, std::move(other->obsolete_presets.sla_prints));
3649 append(this->obsolete_presets.filaments, std::move(other->obsolete_presets.filaments));
3650 append(this->obsolete_presets.sla_materials, std::move(other->obsolete_presets.sla_materials));
3651 append(this->obsolete_presets.printers, std::move(other->obsolete_presets.printers));
3652 m_errors += other->m_errors;
3653 }
3654 return duplicates;
3655}
ObsoletePresets obsolete_presets
Definition PresetBundle.hpp:545
void merge(std::vector< _EpicMesh > &srcs, _EpicMesh &dst)
Definition MeshBoolean.cpp:560

References PresetBundle(), Slic3r::append(), filaments, m_errors, merge_presets(), obsolete_presets, printers, prints, sla_materials, sla_prints, and vendors.

Referenced by load_system_filaments_json(), and merge_presets().

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

◆ migrate_legacy_user_filament_presets()

PresetBundle::LegacyUserFilamentPresetMigration Slic3r::PresetBundle::migrate_legacy_user_filament_presets ( const std::vector< LegacyUserFilamentPreset > & legacy_presets)
1109{
1111 std::vector<LegacyUserFilamentPreset> written;
1112 const std::string zip_path = data_dir() + "/filament_preset_migration_" +
1114 // Before the lock: zipping a large folder takes longer than a guard may be held.
1115 if (!backup_user_folder_to_zip(zip_path))
1116 return result;
1117 result.backup = zip_path;
1118 {
1119 // One hold for every write, so a lock another instance keeps is one outcome rather than a failure per
1120 // preset (the lock backs off for a while after a miss). Held without the collection mutex, the order
1121 // InstanceLock requires; each write re-reads its file, so a save that slipped in before is respected.
1122 const std::string lock_path = user_presets_lock_path();
1123 InstanceLock instance_lock(lock_path);
1124 if (!lock_path.empty() && !instance_lock.locked())
1125 return result;
1126 result.locked = true;
1127 for (const LegacyUserFilamentPreset &legacy : legacy_presets)
1129 written.push_back(legacy);
1130 else
1131 result.failed.push_back(legacy.preset);
1132 }
1133 filaments.apply_legacy_user_filament_presets(written);
1134 return result;
1135}
bool backup_user_folder_to_zip(const std::string &zip_path) const
Definition PresetBundle.cpp:1070
static bool write_legacy_user_filament_preset(const LegacyUserFilamentPreset &legacy)
Definition Preset.cpp:2834
@ iso8601Z
Definition Time.hpp:14
std::string time2str(const time_t &t, TimeZone zone, TimeFormat fmt)
Definition Time.cpp:197
@ utc
Definition Time.hpp:13

References Slic3r::PresetBundle::LegacyUserFilamentPresetMigration::backup, backup_user_folder_to_zip(), Slic3r::data_dir(), Slic3r::PresetBundle::LegacyUserFilamentPresetMigration::failed, filaments, Slic3r::Utils::iso8601Z, Slic3r::InstanceLock::locked(), Slic3r::PresetBundle::LegacyUserFilamentPresetMigration::locked, migrate_legacy_user_filament_presets(), Slic3r::Utils::time2str(), Slic3r::user_presets_lock_path(), Slic3r::Utils::utc, and Slic3r::PresetCollection::write_legacy_user_filament_preset().

Referenced by migrate_legacy_user_filament_presets().

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

◆ min_filament_count()

size_t Slic3r::PresetBundle::min_filament_count ( ) const
private
5384{
5385 if (printers.get_edited_preset().config.opt_bool("single_extruder_multi_material"))
5386 return 1;
5387 return static_cast<size_t>(get_printer_extruder_count());
5388}

References get_printer_extruder_count(), min_filament_count(), and printers.

Referenced by min_filament_count(), update_filament_count(), and update_multi_material_filament_presets().

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

◆ normalize_compatible_presets()

void Slic3r::PresetBundle::normalize_compatible_presets ( )
8499{
8500 // compatible_printers references a printer preset; compatible_prints (filaments / SLA materials)
8501 // references a process preset. System presets are normalized too: a vendor profile can itself
8502 // reference a sibling preset by a name that was later renamed, and the rewrite is in-memory only
8503 // (system presets are never persisted back to vendor JSON). (begin()/end() skip defaults.)
8504 auto normalize = [this](PresetCollection &holders, PresetCollection *processes) {
8505 for (Preset &p : holders) {
8506 normalize_compatible_field(p, "compatible_printers", this->printers);
8507 if (processes != nullptr)
8508 normalize_compatible_field(p, "compatible_prints", *processes);
8509 }
8510 };
8511 normalize(this->prints, nullptr);
8512 normalize(this->filaments, &this->prints);
8513 normalize(this->sla_prints, nullptr);
8514 normalize(this->sla_materials, &this->sla_prints);
8515}
static void normalize_compatible_field(Preset &preset, const char *field_key, PresetCollection &target)
Definition PresetBundle.cpp:8479
Vec3 normalize(const Vec3 &v)
Definition Utils.cpp:32

References filaments, Slic3r::normalize_compatible_field(), normalize_compatible_presets(), printers, prints, sla_materials, and sla_prints.

Referenced by load_presets(), load_project_embedded_presets(), load_user_presets(), normalize_compatible_presets(), and update_subscribed_presets().

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

◆ num_mixed_filaments()

size_t Slic3r::PresetBundle::num_mixed_filaments ( ) const
4472{
4473 const auto *opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
4474 if (opt == nullptr)
4475 return 0;
4476 const size_t slot_count = project_config.option<ConfigOptionStrings>("filament_colour")->values.size();
4477 return size_t(std::count(opt->values.begin(), opt->values.begin() + std::min(slot_count, opt->values.size()), true));
4478}

References num_mixed_filaments(), project_config, and Slic3r::ConfigOptionVector< T >::size().

Referenced by num_mixed_filaments(), and num_physical_filaments().

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

◆ num_physical_filaments()

size_t Slic3r::PresetBundle::num_physical_filaments ( ) const
4483{
4484 const auto *colors = project_config.option<ConfigOptionStrings>("filament_colour");
4485 return colors->values.size() - num_mixed_filaments();
4486}
size_t num_mixed_filaments() const
Definition PresetBundle.cpp:4471

References num_mixed_filaments(), num_physical_filaments(), project_config, and Slic3r::ConfigOptionVector< T >::values.

Referenced by load_config_file_config(), and num_physical_filaments().

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

◆ on_extruders_count_changed()

void Slic3r::PresetBundle::on_extruders_count_changed ( int extruder_count)
8392{
8393 printers.get_edited_preset().set_num_extruders(extruders_count);
8396 extruder_ams_counts.resize(extruders_count);
8397}
void reset_default_nozzle_volume_type()
Definition PresetBundle.cpp:5358

References extruder_ams_counts, on_extruders_count_changed(), printers, reset_default_nozzle_volume_type(), and update_multi_material_filament_presets().

Referenced by on_extruders_count_changed().

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

◆ operator=()

PresetBundle & Slic3r::PresetBundle::operator= ( const PresetBundle & rhs)
767{
768 prints = rhs.prints;
769 sla_prints = rhs.sla_prints;
770 filaments = rhs.filaments;
771 sla_materials = rhs.sla_materials;
772 printers = rhs.printers;
773 physical_printers = rhs.physical_printers;
774
775 filament_presets = rhs.filament_presets;
776 project_config = rhs.project_config;
777 vendors = rhs.vendors;
778 obsolete_presets = rhs.obsolete_presets;
779 m_errors = rhs.m_errors;
780
781 // Adjust Preset::vendor pointers to point to the copied vendors map.
782 prints .update_vendor_ptrs_after_copy(this->vendors);
783 sla_prints .update_vendor_ptrs_after_copy(this->vendors);
784 filaments .update_vendor_ptrs_after_copy(this->vendors);
785 sla_materials.update_vendor_ptrs_after_copy(this->vendors);
786 printers .update_vendor_ptrs_after_copy(this->vendors);
787
788 return *this;
789}

References PresetBundle(), filament_presets, filaments, m_errors, obsolete_presets, operator=(), physical_printers, printers, prints, project_config, sla_materials, sla_prints, and vendors.

Referenced by operator=().

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

◆ parse_vendor_json()

void Slic3r::PresetBundle::parse_vendor_json ( VendorRead & read)
private
7982{
7983 // Starts over from what read_vendor was asked for, since a cache that could
7984 // not be installed leaves its own state behind.
7985 read = VendorRead { std::move(read.dir), std::move(read.vendor_name), read.flags, read.compatibility_rule,
7986 read.errors_at_entry, read.cacheable };
7987 const std::string& dir = read.dir;
7988 const std::string& vendor_name = read.vendor_name;
7989 LoadConfigBundleAttributes flags = read.flags;
7990
7991 // 1) load the vroot json and construct the vendor profile
7992 VendorProfile vendor_profile(vendor_name);
7993 std::string root_file = dir + "/" + vendor_name + ".json";
7994 std::vector<std::pair<std::string, std::string>> machine_model_subfiles;
7995 std::vector<std::pair<std::string, std::string>> process_subfiles;
7996 std::vector<std::pair<std::string, std::string>> filament_subfiles;
7997 std::vector<std::pair<std::string, std::string>> machine_subfiles;
7998 auto get_name_and_subpath = [this](json::iterator& it, std::vector<std::pair<std::string, std::string>>& subfile_map) {
7999 if (it.value().is_array()) {
8000 size_t index = 0;
8001 for (auto iter1 = it.value().begin(); iter1 != it.value().end(); iter1++, index++) {
8002 if (iter1.value().is_object()) {
8003 std::string name, subpath;
8004 for (auto iter2 = iter1.value().begin(); iter2 != iter1.value().end(); iter2++) {
8005 if (iter2.value().is_string()) {
8006 if (boost::iequals(iter2.key(), BBL_JSON_KEY_NAME)) {
8007 name = iter2.value();
8008 } else if (boost::iequals(iter2.key(), BBL_JSON_KEY_SUB_PATH)) {
8009 subpath = iter2.value();
8010 }
8011 }
8012 else {
8013 ++m_errors;
8014 BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": invalid value type for " << iter2.key();
8015 }
8016 }
8017 if (!name.empty() && !subpath.empty())
8018 subfile_map.push_back(std::make_pair(name, subpath));
8019 } else {
8020 ++m_errors;
8021 // An array element has no key, and asking one for it throws
8022 // nlohmann's invalid_iterator — not a parse_error, so it would
8023 // escape the catch around this parse. Say where it is instead.
8024 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": invalid type for " << it.key() << "[" << index << "]";
8025 }
8026 }
8027 } else {
8028 ++m_errors;
8029 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": invalid type for " << it.key();
8030 }
8031 };
8032 try {
8033 boost::nowide::ifstream ifs(root_file);
8034 json j;
8035 ifs >> j;
8036 //parse the json elements
8037 for (auto it = j.begin(); it != j.end(); it++) {
8038 if (boost::iequals(it.key(), BBL_JSON_KEY_VERSION)) {
8039 //get version
8040 std::string version_str = it.value();
8041 auto config_version = Semver::parse(version_str);
8042 if (! config_version) {
8043 ++m_errors;
8044 // TRN %1% is the vendor name, %2% the version found in its profile, %3% the profile directory.
8045 throw ConfigurationError((boost::format(L("Vendor %1%'s config version: %2% invalid\nSuggest cleaning the directory %3% first"))
8046 % vendor_name % version_str % dir).str());
8047 } else {
8048 vendor_profile.config_version = std::move(*config_version);
8049 }
8050 }
8051 else if (boost::iequals(it.key(), BBL_JSON_KEY_URL)) {
8052 //get url
8053 vendor_profile.config_update_url = it.value();
8054 }
8055 else if (boost::iequals(it.key(), BBL_JSON_KEY_DESCRIPTION)) {
8056 //get description
8057 BOOST_LOG_TRIVIAL(info) << __FUNCTION__<< ": parse "<<root_file<<", got description: " << it.value();
8058 }
8059 else if (boost::iequals(it.key(), BBL_JSON_KEY_NAME)) {
8060 //get name
8061 vendor_profile.name = it.value();
8062 }
8063 else if (boost::iequals(it.key(), BBL_JSON_KEY_MACHINE_MODEL_LIST)) {
8064 //get machine model list
8065 get_name_and_subpath(it, machine_model_subfiles);
8066 }
8067 else if (boost::iequals(it.key(), BBL_JSON_KEY_PROCESS_LIST)) {
8068 //get process list
8069 get_name_and_subpath(it, process_subfiles);
8070 }
8071 else if (boost::iequals(it.key(), BBL_JSON_KEY_FILAMENT_LIST)) {
8072 //get filament list
8073 get_name_and_subpath(it, filament_subfiles);
8074 }
8075 else if (boost::iequals(it.key(), BBL_JSON_KEY_MACHINE_LIST)) {
8076 //get machine list
8077 get_name_and_subpath(it, machine_subfiles);
8078 }
8079 }
8080 }
8081 catch(nlohmann::detail::parse_error &err) {
8082 BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<<root_file<<" got a nlohmann::detail::parse_error, reason = " << err.what();
8083 throw ConfigurationError((boost::format(L("Failed loading configuration file %1%: %2%\nSuggest cleaning the directory %3% first"))
8084 %root_file %err.what() % dir).str());
8085 //goto __error_process;
8086 }
8087
8089 machine_model_subfiles.clear();
8090 machine_subfiles.clear();
8091 process_subfiles.clear();
8092 }
8093
8094 //2) paste the machine model
8095 for (auto& machine_model : machine_model_subfiles)
8096 {
8097 std::string subfile = dir + "/" + vendor_name + "/" + machine_model.second;
8098 VendorProfile::PrinterModel model;
8099 model.id = machine_model.first;
8100 try {
8101 boost::nowide::ifstream ifs(subfile);
8102 json j;
8103 ifs >> j;
8104 //parse the json elements
8105 for (auto it = j.begin(); it != j.end(); it++) {
8106 if (boost::iequals(it.key(), BBL_JSON_KEY_VERSION)) {
8107 //get version
8108 }
8109 else if (boost::iequals(it.key(), BBL_JSON_KEY_URL)) {
8110 //get url
8111 }
8112 else if (boost::iequals(it.key(), BBL_JSON_KEY_NAME)) {
8113 //get name
8114 model.name = it.value();
8115 }
8116 else if (boost::iequals(it.key(), BBL_JSON_KEY_MODEL_ID)) {
8117 //get model_id
8118 model.model_id = it.value();
8119 }
8120 else if (boost::iequals(it.key(), BBL_JSON_KEY_NOZZLE_DIAMETER)) {
8121 //get nozzle diameter
8122 std::string nozzle_diameters = it.value();
8123 std::vector<std::string> variants;
8124 if (Slic3r::unescape_strings_cstyle(nozzle_diameters, variants)) {
8125 for (const std::string &variant_name : variants) {
8126 if (model.variant(variant_name) == nullptr)
8127 model.variants.emplace_back(VendorProfile::PrinterVariant(variant_name));
8128 }
8129 } else {
8130 ++m_errors;
8131 BOOST_LOG_TRIVIAL(error)<< __FUNCTION__ << boost::format(": invalid nozzle_diameters %1% for Vendor %1%") % nozzle_diameters % vendor_name;
8132 }
8133 }
8134 else if (boost::iequals(it.key(), BBL_JSON_KEY_PRINTER_TECH)) {
8135 //get printer tech
8136 if (boost::algorithm::starts_with(it.value(), "SL"))
8137 model.technology = ptSLA;
8138 else
8139 model.technology = ptFFF;
8140 }
8141 else if (boost::iequals(it.key(), BBL_JSON_KEY_FAMILY)) {
8142 //get family
8143 model.family = it.value();
8144 }
8145 else if (boost::iequals(it.key(), BBL_JSON_KEY_BED_MODEL)) {
8146 //get bed model
8147 model.bed_model = it.value();
8148 } else if (boost::iequals(it.key(), BBL_JSON_KEY_BOTTOM_TEXTURE_END_NAME)) {
8149 model.bottom_texture_end_name = it.value();
8150 } else if (boost::iequals(it.key(), BBL_JSON_KEY_USE_DOUBLE_EXTRUDER_DEFAULT_TEXTURE)) {
8151 model.use_double_extruder_default_texture = it.value();
8152 } else if (boost::iequals(it.key(), BBL_JSON_KEY_BOTTOM_TEXTURE_RECT)) {
8153 model.bottom_texture_rect = it.value();
8154 } else if (boost::iequals(it.key(), BBL_JSON_KEY_BOTTOM_TEXTURE_RECT_LONGER)) {
8155 model.bottom_texture_rect_longer = it.value();
8156 } else if (boost::iequals(it.key(), BBL_JSON_KEY_MIDDLE_TEXTURE_RECT)) {
8157 model.middle_texture_rect = it.value();
8158 }
8159 else if (boost::iequals(it.key(), BBL_JSON_KEY_IMAGE_BED_TYPE)) {
8160 model.image_bed_type = it.value();
8161 }
8162 else if (boost::iequals(it.key(), BBL_JSON_KEY_BED_TEXTURE)) {
8163 //get bed texture
8164 model.bed_texture = it.value();
8165 }
8166 else if (boost::iequals(it.key(), BBL_JSON_KEY_HOTEND_MODEL)) {
8167 model.hotend_model = it.value();
8168 }
8169 else if (boost::iequals(it.key(), BBL_JSON_KEY_DEFAULT_MATERIALS)) {
8170 //get machine list
8171 std::string default_materials_field = it.value();
8172 if (Slic3r::unescape_strings_cstyle(default_materials_field, model.default_materials)) {
8173 Slic3r::sort_remove_duplicates(model.default_materials);
8174 if (! model.default_materials.empty() && model.default_materials.front().empty())
8175 // An empty material was inserted into the list of default materials. Remove it.
8176 model.default_materials.erase(model.default_materials.begin());
8177 } else {
8178 ++m_errors;
8179 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(": invalid default_materials %1% for Vendor %1%") % default_materials_field % vendor_name;
8180 }
8181 } else if (boost::iequals(it.key(), BBL_JSON_KEY_NOT_SUPPORT_BED_TYPE)) {
8182 // get machine list
8183 std::string not_support_bed_type_field = it.value();
8184 if (Slic3r::unescape_strings_cstyle(not_support_bed_type_field, model.not_support_bed_types)) {
8185 Slic3r::sort_remove_duplicates(model.not_support_bed_types);
8186 if (!model.not_support_bed_types.empty() && model.not_support_bed_types.front().empty())
8187 // An empty material was inserted into the list of default materials. Remove it.
8188 model.not_support_bed_types.erase(model.not_support_bed_types.begin());
8189 } else {
8190 BOOST_LOG_TRIVIAL(error) << __FUNCTION__
8191 << boost::format(": invalid not_support_bed_types %1% for Vendor %1%") % not_support_bed_type_field % vendor_name;
8192 }
8193 }
8194 }
8195 }
8196 catch(nlohmann::detail::parse_error &err) {
8197 BOOST_LOG_TRIVIAL(error) << __FUNCTION__<< ": parse "<< subfile <<" got a nlohmann::detail::parse_error, reason = " << err.what();
8198 throw ConfigurationError((boost::format(L("Failed loading configuration file %1%: %2%\nSuggest cleaning the directory %3% first"))
8199 %subfile %err.what() % dir).str());
8200 }
8201
8202 if (! model.id.empty() && ! model.variants.empty())
8203 vendor_profile.models.push_back(std::move(model));
8204 }
8205
8206 //insert the vendor profile
8207 this->vendors.emplace(vendor_name, vendor_profile);
8208
8209 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(", loaded vendor profile, name %1%, id %2%, version %3%")%vendor_profile.name%vendor_profile.id%vendor_profile.config_version.to_string();
8210
8212 read.vendor_only = true;
8213 return;
8214 }
8215
8216 // 3) paste the process/filament/print configs
8217
8218 // Parse one subfile into a source-form entry — everything the JSON states,
8219 // nothing resolved. Installing the entries (install_vendor) is the
8220 // same code whether they were parsed just now or deserialized from the
8221 // vendor's cache.
8222 auto parse_subfile = [&dir, &vendor_name](
8223 ConfigSubstitutionContext& substitution_context,
8224 const std::pair<std::string, std::string>& subfile_iter,
8225 CachedPreset& entry, std::vector<std::string>& errors, std::vector<std::string>& warnings) -> std::string {
8226
8227 std::string subfile = dir + "/" + vendor_name + "/" + subfile_iter.second;
8228 std::string reason;
8229 try {
8230 std::map<std::string, std::string> key_values;
8231 substitution_context.substitutions.clear();
8232
8233 //parse the json elements
8234 entry.sub_path = subfile_iter.second;
8235 entry.config_src.load_from_json(subfile, substitution_context, false, key_values, reason);
8236 if (!reason.empty()) {
8237 errors.push_back(std::string(__FUNCTION__) + ": load config file " + subfile + " Failed!");
8238 return reason;
8239 }
8240 entry.name = key_values[BBL_JSON_KEY_NAME];
8241 entry.description = key_values[BBL_JSON_KEY_DESCRIPTION];
8242 // A file that states no instantiation and is named as G-code, or has no
8243 // name, is a template that is only there to be included. A nameless one
8244 // goes by its name in the vendor index.
8245 if (auto it = key_values.find(BBL_JSON_KEY_INSTANTIATION);
8246 (it == key_values.end() || it->second.empty()) && (entry.name.empty() || entry.name.find("gcode") != std::string::npos)) {
8247 key_values[BBL_JSON_KEY_INSTANTIATION] = "false";
8248 if (entry.name.empty())
8249 entry.name = subfile_iter.first;
8250 }
8251 if(key_values.find(BBL_JSON_KEY_INSTANTIATION) == key_values.end())
8252 errors.push_back(std::string(__FUNCTION__) + ": Missing instantiation attribute for " + entry.name);
8253 entry.instantiation = key_values[BBL_JSON_KEY_INSTANTIATION];
8254 if(entry.instantiation != "false" && entry.instantiation != "true")
8255 errors.push_back(std::string(__FUNCTION__) + ": Missing instantiation attribute for " + entry.name);
8256 auto setting_it = key_values.find(BBL_JSON_KEY_SETTING_ID);
8257 if (setting_it != key_values.end())
8258 entry.setting_id = setting_it->second;
8259 auto filament_it = key_values.find(BBL_JSON_KEY_FILAMENT_ID);
8260 if (filament_it != key_values.end())
8261 entry.filament_id = filament_it->second;
8262 auto it1 = key_values.find(BBL_JSON_KEY_INHERITS);
8263 if (it1 != key_values.end()) {
8264 entry.inherits = it1->second;
8265 // An `inherits` key naming nothing can never resolve; fail it
8266 // here so install can key off the empty string as "no inherits".
8267 if (entry.inherits.empty()) {
8268 errors.push_back(std::string(__FUNCTION__) + ": can not find inherits " + entry.inherits + " for " + entry.name);
8269 reason = "Can not find inherits: " + entry.inherits;
8270 return reason;
8271 }
8272 }
8273 if (auto it = key_values.find(BBL_JSON_KEY_INCLUDES); it != key_values.end()) {
8274 // An array of names, or one bare name; load_from_json kept the JSON text.
8275 nlohmann::json includes = nlohmann::json::parse(it->second);
8276 if (!includes.is_array())
8277 includes = nlohmann::json::array({std::move(includes)});
8278 for (const auto& name : includes) {
8279 if (name.is_string())
8280 entry.includes.push_back(name.get<std::string>());
8281 else
8282 errors.push_back(std::string(__FUNCTION__) + ": invalid include " + name.dump() + " for " + entry.name);
8283 }
8284 }
8285 if (key_values.find(ORCA_JSON_KEY_RENAMED_FROM) != key_values.end()) {
8286 if (!unescape_strings_cstyle(key_values[ORCA_JSON_KEY_RENAMED_FROM], entry.renamed_from))
8287 warnings.push_back("Error in a Config \"" + dir + "\": The preset \"" + entry.name +
8288 "\" contains invalid \"renamed_from\" key, which is being ignored.");
8289 }
8290 }
8291 catch(nlohmann::detail::parse_error &err) {
8292 errors.push_back(std::string(__FUNCTION__) + ": parse " + subfile + " got a nlohmann::detail::parse_error, reason = " + err.what());
8293 reason = std::string("json parse error") + err.what();
8294 return reason;
8295 }
8296 return reason;
8297 };
8298
8299 // Orca: whether to (re)write the vendor's cache after this parse, leaving it
8300 // in step with the profile so the next run reads it instead. It is written
8301 // where the vendor was looked for, even when the profile came from resources,
8302 // and stamped with the version that profile claims — a profile without one
8303 // cannot be judged for staleness later, and a cache nothing can invalidate is
8304 // worse than none.
8305 read.will_cache = read.cacheable && m_generate_vendor_caches && vendor_profile.config_version.valid();
8306 read.version = vendor_profile.config_version.to_string();
8307 // Enable substitutions for user config bundle, throw an exception when loading a system profile.
8308 ConfigSubstitutionContext substitution_context { read.compatibility_rule };
8309 // Parsed up to the first sub-file that fails, and the ones before it are
8310 // installed before that failure is raised, since the filament library and a
8311 // filament-only scan keep what a throwing load installed.
8312 auto parse_subfiles = [&](const std::vector<std::pair<std::string, std::string>>& subfiles,
8313 std::vector<CachedPreset>& entries, std::vector<EntryParse>& entries_parsed, const char* kind) {
8314 for (const auto& subfile : subfiles) {
8315 CachedPreset entry;
8316 std::vector<std::string> errors, warnings;
8317 read.reason = parse_subfile(substitution_context, subfile, entry, errors, warnings);
8318 if (! read.reason.empty()) {
8319 read.failed_subfile = subfile.second;
8320 read.failed_kind = kind;
8321 read.failed_errors = std::move(errors);
8322 return false;
8323 }
8324 entries.emplace_back(std::move(entry));
8325 entries_parsed.push_back({ std::move(substitution_context.substitutions), std::move(errors), std::move(warnings) });
8326 }
8327 return true;
8328 };
8329 // One setter for every sub-file, so the ones load_from_json makes have
8330 // nothing to set.
8331 CNumericLocalesSetter locales_setter;
8332 if (parse_subfiles(process_subfiles, read.data.process_entries, read.parsed.process_entries, "process") &&
8333 parse_subfiles(filament_subfiles, read.data.filament_entries, read.parsed.filament_entries, "filament"))
8334 parse_subfiles(machine_subfiles, read.data.machine_entries, read.parsed.machine_entries, "printer");
8335}
#define BBL_JSON_KEY_MIDDLE_TEXTURE_RECT
Definition Preset.hpp:88
#define BBL_JSON_KEY_DESCRIPTION
Definition Preset.hpp:59
#define BBL_JSON_KEY_DEFAULT_MATERIALS
Definition Preset.hpp:91
#define BBL_JSON_KEY_PRINTER_TECH
Definition Preset.hpp:79
#define BBL_JSON_KEY_BOTTOM_TEXTURE_END_NAME
Definition Preset.hpp:84
#define BBL_JSON_KEY_MACHINE_MODEL_LIST
Definition Preset.hpp:61
#define BBL_JSON_KEY_NOZZLE_DIAMETER
Definition Preset.hpp:78
#define BBL_JSON_KEY_BED_TEXTURE
Definition Preset.hpp:82
#define BBL_JSON_KEY_INCLUDES
Definition Preset.hpp:76
#define BBL_JSON_KEY_INSTANTIATION
Definition Preset.hpp:77
#define BBL_JSON_KEY_HOTEND_MODEL
Definition Preset.hpp:90
#define BBL_JSON_KEY_USE_DOUBLE_EXTRUDER_DEFAULT_TEXTURE
Definition Preset.hpp:85
#define BBL_JSON_KEY_URL
Definition Preset.hpp:57
#define BBL_JSON_KEY_IMAGE_BED_TYPE
Definition Preset.hpp:83
#define BBL_JSON_KEY_BOTTOM_TEXTURE_RECT
Definition Preset.hpp:86
#define ORCA_JSON_KEY_RENAMED_FROM
Definition Preset.hpp:96
#define BBL_JSON_KEY_SUB_PATH
Definition Preset.hpp:63
#define BBL_JSON_KEY_MODEL_ID
Definition Preset.hpp:93
#define BBL_JSON_KEY_NOT_SUPPORT_BED_TYPE
Definition Preset.hpp:92
#define BBL_JSON_KEY_FAMILY
Definition Preset.hpp:80
#define BBL_JSON_KEY_BED_MODEL
Definition Preset.hpp:81
#define BBL_JSON_KEY_SETTING_ID
Definition Preset.hpp:68
#define BBL_JSON_KEY_BOTTOM_TEXTURE_RECT_LONGER
Definition Preset.hpp:87
enum_bitmask< LoadConfigBundleAttribute > LoadConfigBundleAttributes
Definition PresetBundle.hpp:609
bool unescape_strings_cstyle(const std::string &str, std::vector< std::string > &out)
Definition Config.cpp:173
void sort_remove_duplicates(std::vector< T > &vec)
Definition libslic3r.h:231

References BBL_JSON_KEY_BED_MODEL, BBL_JSON_KEY_BED_TEXTURE, BBL_JSON_KEY_BOTTOM_TEXTURE_END_NAME, BBL_JSON_KEY_BOTTOM_TEXTURE_RECT, BBL_JSON_KEY_BOTTOM_TEXTURE_RECT_LONGER, BBL_JSON_KEY_DEFAULT_MATERIALS, BBL_JSON_KEY_DESCRIPTION, BBL_JSON_KEY_FAMILY, BBL_JSON_KEY_FILAMENT_ID, BBL_JSON_KEY_FILAMENT_LIST, BBL_JSON_KEY_HOTEND_MODEL, BBL_JSON_KEY_IMAGE_BED_TYPE, BBL_JSON_KEY_INCLUDES, BBL_JSON_KEY_INHERITS, BBL_JSON_KEY_INSTANTIATION, BBL_JSON_KEY_MACHINE_LIST, BBL_JSON_KEY_MACHINE_MODEL_LIST, BBL_JSON_KEY_MIDDLE_TEXTURE_RECT, BBL_JSON_KEY_MODEL_ID, BBL_JSON_KEY_NAME, BBL_JSON_KEY_NOT_SUPPORT_BED_TYPE, BBL_JSON_KEY_NOZZLE_DIAMETER, BBL_JSON_KEY_PRINTER_TECH, BBL_JSON_KEY_PROCESS_LIST, BBL_JSON_KEY_SETTING_ID, BBL_JSON_KEY_SUB_PATH, BBL_JSON_KEY_URL, BBL_JSON_KEY_USE_DOUBLE_EXTRUDER_DEFAULT_TEXTURE, BBL_JSON_KEY_VERSION, Slic3r::VendorProfile::PrinterModel::bed_model, Slic3r::VendorProfile::PrinterModel::bed_texture, Slic3r::VendorProfile::PrinterModel::bottom_texture_end_name, Slic3r::VendorProfile::PrinterModel::bottom_texture_rect, Slic3r::VendorProfile::PrinterModel::bottom_texture_rect_longer, Slic3r::VendorProfile::config_update_url, Slic3r::VendorProfile::config_version, Slic3r::VendorProfile::PrinterModel::default_materials, Slic3r::VendorProfile::PrinterModel::family, Slic3r::enum_bitmask< option_type, typename >::has(), Slic3r::VendorProfile::PrinterModel::hotend_model, Slic3r::VendorProfile::id, Slic3r::VendorProfile::PrinterModel::id, Slic3r::VendorProfile::PrinterModel::image_bed_type, L, LoadFilamentOnly, LoadVendorOnly, m_errors, m_generate_vendor_caches, Slic3r::VendorProfile::PrinterModel::middle_texture_rect, Slic3r::VendorProfile::PrinterModel::model_id, Slic3r::VendorProfile::models, Slic3r::VendorProfile::name, Slic3r::VendorProfile::PrinterModel::name, Slic3r::VendorProfile::PrinterModel::not_support_bed_types, ORCA_JSON_KEY_RENAMED_FROM, Slic3r::Semver::parse(), parse_vendor_json(), Slic3r::ptFFF, Slic3r::ptSLA, Slic3r::sort_remove_duplicates(), Slic3r::VendorProfile::PrinterModel::technology, Slic3r::Semver::to_string(), Slic3r::unescape_strings_cstyle(), Slic3r::VendorProfile::PrinterModel::use_double_extruder_default_texture, Slic3r::Semver::valid(), Slic3r::VendorProfile::PrinterModel::variant(), Slic3r::VendorProfile::PrinterModel::variants, and vendors.

Referenced by install_vendor_read(), parse_vendor_json(), and read_vendor().

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

◆ physical_filament_config_indices()

std::vector< size_t > Slic3r::PresetBundle::physical_filament_config_indices ( ) const
4489{
4490 std::vector<size_t> indices;
4491 for (size_t i = 0; i < filament_presets.size(); ++i)
4492 if (!is_mixed_filament(i))
4493 indices.push_back(i);
4494 return indices;
4495}

References filament_presets, is_mixed_filament(), and physical_filament_config_indices().

Referenced by physical_filament_config_indices().

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

◆ project_different_keys()

std::set< std::string > Slic3r::PresetBundle::project_different_keys ( const std::string & different_settings)
static
5490{
5491 std::vector<std::string> keys;
5492 Slic3r::unescape_strings_cstyle(different_settings, keys);
5493 std::set<std::string> keys_set(keys.begin(), keys.end());
5494 keys_set.insert(ignore_settings_list.begin(), ignore_settings_list.end());
5495 return keys_set;
5496}

References Slic3r::ignore_settings_list, project_different_keys(), and Slic3r::unescape_strings_cstyle().

Referenced by load_config_file_config(), project_different_keys(), and Slic3r::CLI::run().

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

◆ read_vendor()

PresetBundle::VendorRead Slic3r::PresetBundle::read_vendor ( const std::string & dir,
const std::string & vendor_name,
LoadConfigBundleAttributes flags,
ForwardCompatibilitySubstitutionRule compatibility_rule,
bool allow_cache )
private
7934{
7935 VendorRead read { dir, vendor_name, flags, compatibility_rule };
7936 read.errors_at_entry = m_errors;
7937
7938 //BBS: add config related logs
7939 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" enter, path %1%, compatibility_rule %2%")%dir.c_str()%compatibility_rule;
7941 // Reset this bundle, delete user profile files if SaveImported.
7943
7944 // Orca: only a whole-vendor load writes a cache, and a vendor-only or filament-only
7945 // scan reads one only where it is the whole installation, as in a shipped build.
7946 // Validation reads the JSONs whatever is cached.
7947 const bool vendor_only = flags.has(LoadConfigBundleAttribute::LoadVendorOnly);
7948 const bool filament_only = flags.has(LoadConfigBundleAttribute::LoadFilamentOnly);
7949 read.cacheable = allow_cache && flags.has(LoadConfigBundleAttribute::LoadSystem) && ! filament_only;
7950 const boost::filesystem::path dir_path(dir);
7951 const boost::filesystem::path profile = dir_path / (vendor_name + ".json");
7952 const bool has_profile = boost::filesystem::exists(profile);
7953 if (allow_cache && ! validation_mode && (read.cacheable || ((vendor_only || filament_only) && ! has_profile))) {
7954 // The cache is judged against the profile beside it, or, where the cache is the
7955 // whole of the installation, against nothing, since nothing on disk can then be
7956 // newer than it. That state is Semver::inf(), which no real profile carries.
7957 const Semver version = has_profile ? get_version_from_json(profile.string()) : Semver::inf();
7958 read.cache_path = (dir_path / (vendor_name + ".opc")).string();
7959 if (vendor_only) {
7960 VendorProfile vendor_profile;
7961 if (VendorCacheFile::load_vendor_profile(read.cache_path, vendor_name, version, vendor_profile)) {
7962 this->vendors.emplace(vendor_name, std::move(vendor_profile));
7963 read.vendor_only = true;
7964 return read;
7965 }
7966 } else if (VendorCacheFile::load(read.cache_path, vendor_name, version, read.data)) {
7967 read.from_cache = true;
7968 if (filament_only) {
7969 read.data.process_entries.clear();
7970 read.data.machine_entries.clear();
7971 // The stamp counts errors across the whole vendor.
7972 read.data.parse_errors = 0;
7973 }
7974 return read;
7975 }
7976 }
7977 this->parse_vendor_json(read);
7978 return read;
7979}
static bool load_vendor_profile(const std::string &path, const std::string &expected_vendor_name, const Semver &expected_vendor_version, VendorProfile &vendor)
Definition PresetCacheFormat.cpp:518
Semver get_version_from_json(std::string file_path)
Definition Preset.cpp:197

References Slic3r::get_version_from_json(), Slic3r::enum_bitmask< option_type, typename >::has(), Slic3r::Semver::inf(), Slic3r::VendorCacheFile::load(), Slic3r::VendorCacheFile::load_vendor_profile(), LoadFilamentOnly, LoadSystem, LoadVendorOnly, m_errors, parse_vendor_json(), read_vendor(), reset(), ResetUserProfile, SaveImported, validation_mode, and vendors.

Referenced by load_vendor_configs_from_json(), and read_vendor().

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

◆ reload_local_bundle()

bool Slic3r::PresetBundle::reload_local_bundle ( const std::string & preset_folder,
const std::string & bundle_id,
std::string * error = nullptr )
1610{
1611 auto fail = [error](const std::string& message) {
1612 if (error != nullptr)
1613 *error = message;
1614 return false;
1615 };
1616 if (!is_single_path_component(bundle_id))
1617 return fail("Local bundle id must be a single path component");
1618
1619 const std::string user = preset_folder.empty() ? DEFAULT_USER_FOLDER_NAME : preset_folder;
1620 if (!is_single_path_component(user))
1621 return fail("Preset folder must be a single path component");
1622
1623 try {
1624 const fs::path user_dir = fs::path(data_dir()) / PRESET_USER_DIR / user;
1625 const fs::path bundle_dir = user_dir / PRESET_LOCAL_DIR / bundle_id;
1626 const fs::path metadata_file = bundle_dir / PRESET_BUNDLE_METADATA;
1627
1628 BundleMetadata metadata;
1629 std::string check_error;
1630 if (!check_local_bundle(bundles, user_dir, bundle_id, metadata, check_error))
1631 return fail(check_error);
1632
1633 // Keep background preset sync from changing the collections between copying and committing them.
1634 std::scoped_lock collection_lock(prints.m_mutex, filaments.m_mutex, printers.m_mutex);
1635 const std::string target_prefix = std::string(PRESET_LOCAL_DIR) + "/" + bundle_id + "/";
1636 const auto is_target = [&](const Preset& preset) {
1637 return preset.bundle_id == bundle_id && boost::starts_with(preset.name, target_prefix);
1638 };
1639 struct Selection {
1640 std::string name;
1641 Preset base{Preset::TYPE_INVALID, std::string()};
1642 Preset edited{Preset::TYPE_INVALID, std::string()};
1643 std::vector<std::string> dirty_options;
1644 };
1645 auto snapshot = [&](const PresetCollection& collection, Selection& selection) {
1646 selection.name = collection.get_selected_preset_name();
1647 if (selection.name.empty())
1648 return false;
1649 for (const Preset& preset : collection.get_presets()) {
1650 if (preset.name == selection.name) {
1651 selection.base = preset;
1652 selection.edited = collection.get_edited_preset();
1653 selection.dirty_options = PresetCollection::dirty_options(&selection.edited, &selection.base);
1654 return true;
1655 }
1656 }
1657 return false;
1658 };
1659
1660 Selection print_selection, filament_selection, printer_selection;
1661 if (!snapshot(prints, print_selection) || !snapshot(filaments, filament_selection) || !snapshot(printers, printer_selection))
1662 return fail("Preset selections are not initialized");
1663
1664 PresetBundle staged;
1665 // Collection copies keep vendor pointers into the live vendor map, which is not replaced by this reload.
1666 staged.prints = prints;
1667 staged.filaments = filaments;
1668 staged.printers = printers;
1669 staged.filament_presets = filament_presets;
1670 staged.project_config.apply_only(project_config, {"flush_volumes_matrix", "flush_volumes_vector", "flush_multiplier"});
1671 auto remove_target = [&](PresetCollection& collection) {
1672 auto begin = collection.m_presets.begin() + collection.m_num_default_presets;
1673 collection.m_presets.erase(std::remove_if(begin, collection.m_presets.end(), is_target), collection.m_presets.end());
1674 collection.sort_presets();
1675 };
1676 remove_target(staged.prints);
1677 remove_target(staged.filaments);
1678 remove_target(staged.printers);
1679
1680 const std::array<int, 3> errors_before = { staged.prints.error_count(), staged.filaments.error_count(), staged.printers.error_count() };
1681 PresetsConfigSubstitutions substitutions;
1682 load_bundle_presets(staged, bundle_dir.string(), metadata, PresetOrigin(PresetOrigin::Kind::LocalBundle, bundle_id),
1684 if (staged.prints.error_count() != errors_before[0] || staged.filaments.error_count() != errors_before[1] || staged.printers.error_count() != errors_before[2])
1685 return fail("Local bundle contains an invalid preset");
1686
1687 auto dirty_target_was_removed = [&](const Selection& selection, const PresetCollection& collection) {
1688 if (selection.dirty_options.empty() || !is_target(selection.base))
1689 return false;
1690 for (const Preset& preset : collection.get_presets())
1691 if (preset.name == selection.name && is_target(preset))
1692 return false;
1693 return true;
1694 };
1695 if (dirty_target_was_removed(print_selection, staged.prints) ||
1696 dirty_target_was_removed(filament_selection, staged.filaments) ||
1697 dirty_target_was_removed(printer_selection, staged.printers))
1698 return fail("A modified selected preset was removed or renamed");
1699
1700 auto external_child_name = [&](const PresetCollection& collection) {
1701 auto depends_on_target = [&](const Preset& preset) {
1702 if (is_target(preset))
1703 return false;
1704 const Preset* parent = &preset;
1705 std::unordered_set<const Preset*> visited;
1706 while ((parent = collection.get_preset_parent(*parent)) != nullptr && visited.insert(parent).second)
1707 if (is_target(*parent))
1708 return true;
1709 for (const char* key : {"compatible_prints", "compatible_printers"}) {
1710 const auto* names = preset.config.option<ConfigOptionStrings>(key);
1711 if (names == nullptr)
1712 continue;
1713 const PresetCollection& referenced = std::string(key) == "compatible_printers" ? printers : prints;
1714 for (const std::string& name : names->values) {
1715 const Preset* dependency = referenced.find_preset(name, false);
1716 if (dependency != nullptr && is_target(*dependency))
1717 return true;
1718 }
1719 }
1720 return false;
1721 };
1722 for (const Preset& preset : collection.get_presets())
1723 if (depends_on_target(preset))
1724 return preset.name;
1725 if (depends_on_target(collection.get_edited_preset()))
1726 return collection.get_edited_preset().name;
1727 return std::string();
1728 };
1729 for (const PresetCollection* collection : std::array<const PresetCollection*, 3>{&prints, &filaments, &printers}) {
1730 const std::string child_name = external_child_name(*collection);
1731 if (!child_name.empty())
1732 return fail("Preset outside this bundle depends on it: " + child_name);
1733 }
1734
1735 auto restore_selection = [](PresetCollection& collection, const Selection& selection) {
1736 if (collection.find_preset(selection.name, false, true) == nullptr) {
1737 collection.select_preset(collection.first_visible_idx());
1738 return false;
1739 }
1740 collection.select_preset_by_name(selection.name, true);
1741 if (collection.get_selected_preset_name() != selection.name)
1742 return false;
1743 Preset& edited = collection.get_edited_preset();
1744 for (const std::string& key : selection.dirty_options) {
1745 if (const ConfigOption* option = selection.edited.config.option(key))
1746 edited.config.set_key_value(key, option->clone());
1747 else
1748 edited.config.erase(key);
1749 }
1750 collection.update_dirty();
1751 return true;
1752 };
1753
1754 staged.prints.update_map_alias_to_profile_name();
1755 staged.filaments.update_map_alias_to_profile_name();
1756 staged.printers.update_map_alias_to_profile_name();
1757 const bool printer_preserved = restore_selection(staged.printers, printer_selection);
1758 const bool print_preserved = restore_selection(staged.prints, print_selection);
1759 const bool filament_preserved = restore_selection(staged.filaments, filament_selection);
1760 const auto selection_mode = [printer_preserved](bool selection_preserved) {
1761 if (!selection_preserved)
1764 };
1765 if (staged.printers.get_edited_preset().printer_technology() != ptFFF)
1766 return fail("Local bundle reload requires an FFF printer selection");
1767 staged.update_compatible(selection_mode(print_preserved), selection_mode(filament_preserved));
1768 for (std::string& name : staged.filament_presets)
1769 if (boost::starts_with(name, target_prefix) && staged.filaments.find_preset(name, false) == nullptr)
1770 name = staged.filaments.first_compatible().name;
1771 staged.update_multi_material_filament_presets();
1772
1773 struct Collection
1774 {
1775 PresetCollection& live;
1776 PresetCollection& candidate;
1777 size_t original_size;
1778 };
1779 std::array<Collection, 3> collections{{{prints, staged.prints, prints.size()},
1780 {filaments, staged.filaments, filaments.size()},
1781 {printers, staged.printers, printers.size()}}};
1782 for (size_t i = 0; i < collections.size(); ++i) {
1783 const auto& collection = collections[i];
1784 const auto dirty_options = collection.live.current_dirty_options();
1785 if (dirty_options.empty())
1786 continue;
1787 if (collection.live.get_selected_preset_name() != collection.candidate.get_selected_preset_name())
1788 return fail("Reload would discard a modified selected preset");
1789 for (const std::string& key : dirty_options) {
1790 const ConfigOption* before = collection.live.get_edited_preset().config.option(key);
1791 const ConfigOption* after = collection.candidate.get_edited_preset().config.option(key);
1792 if ((before == nullptr) != (after == nullptr) || (before != nullptr && *before != *after))
1793 return fail("Reload would discard a modified preset option: " + key);
1794 }
1795 }
1796
1797 if (calibrate_printer != nullptr && staged.printers.find_preset(calibrate_printer->name, false, true) != nullptr)
1798 staged.set_calibrate_printer(calibrate_printer->name);
1799 std::array<std::pair<ConfigOptionFloats*, ConfigOptionFloats*>, 3> flush_options;
1800 size_t i = 0;
1801 for (const char* key : {"flush_volumes_matrix", "flush_volumes_vector", "flush_multiplier"})
1802 flush_options[i++] = {project_config.option<ConfigOptionFloats>(key), staged.project_config.option<ConfigOptionFloats>(key)};
1803
1804 metadata.bundle_type = BundleType::Local;
1805 metadata.is_subscribed = false;
1806 metadata.update_available = false;
1807 metadata.path = metadata_file.string();
1808 fs::path local_dir = user_dir / PRESET_LOCAL_DIR;
1809 std::unique_lock<std::shared_mutex> lock(bundles.RWMtx);
1810 const auto existing = bundles.m_bundles.find(bundle_id);
1811 if (existing != bundles.m_bundles.end() &&
1812 (existing->second.bundle_type == BundleType::Subscribed || existing->second.is_subscribed))
1813 return fail("A subscribed bundle already uses this id");
1814
1815 std::set<const Preset*> calibration_filaments;
1816 const Preset* calibration_printer = nullptr;
1817 try {
1818 // Growing a deque preserves existing objects. Roll back appended copies if preparation fails.
1819 for (size_t i = 0; i < collections.size(); ++i) {
1820 auto& collection = collections[i];
1821 while (collection.live.size() < collection.candidate.size())
1822 collection.live.m_presets.emplace_back(collection.candidate.m_presets[collection.live.size()]);
1823 }
1824 auto calibration_preset = [](const Preset* preset, PresetCollection& live, PresetCollection& candidate) -> const Preset* {
1825 if (preset == nullptr)
1826 return nullptr;
1827 if (preset == &candidate.get_edited_preset())
1828 return &live.get_edited_preset();
1829 const auto it = candidate.find_preset_internal(preset->name);
1830 return &live.m_presets[it - candidate.m_presets.begin()];
1831 };
1832 calibration_printer = calibration_preset(staged.calibrate_printer, printers, staged.printers);
1833 for (const Preset* preset : staged.calibrate_filaments)
1834 calibration_filaments.insert(calibration_preset(preset, filaments, staged.filaments));
1835 // Insertion is the last allocating operation. Replacing metadata only moves its members.
1836 bundles.m_bundles.insert_or_assign(bundle_id, std::move(metadata));
1837 } catch (...) {
1838 for (size_t i = 0; i < collections.size(); ++i)
1839 while (collections[i].live.size() > collections[i].original_size)
1840 collections[i].live.m_presets.pop_back();
1841 throw;
1842 }
1843 auto install_target = [](PresetCollection& live, PresetCollection& candidate) noexcept {
1844 // Keep stored Preset references alive when the collection's layout is unchanged.
1845 // Adding/removing presets retains the collection's usual sorted-position semantics.
1846 for (size_t i = 0; i < candidate.size(); ++i)
1847 live.m_presets[i] = std::move(candidate.m_presets[i]);
1848 while (live.size() > candidate.size())
1849 live.m_presets.pop_back();
1850 live.m_map_alias_to_profile_name.swap(candidate.m_map_alias_to_profile_name);
1851 // Move assignment does not allocate (including Semver); swapping Presets would construct temporary containers.
1852 live.m_edited_preset = std::move(candidate.m_edited_preset);
1853 live.m_saved_preset = std::move(candidate.m_saved_preset);
1854 live.m_idx_selected = candidate.m_idx_selected;
1855 };
1856 for (size_t i = 0; i < collections.size(); ++i)
1857 install_target(collections[i].live, collections[i].candidate);
1858 filament_presets.swap(staged.filament_presets);
1859 for (const auto& options : flush_options)
1860 options.first->values.swap(options.second->values);
1861 calibrate_printer = calibration_printer;
1862 calibrate_filaments.swap(calibration_filaments);
1863 dir_user_presets_local.swap(local_dir);
1864 return true;
1865 } catch (const std::exception& exception) {
1866 return fail(std::string("Failed to reload local bundle: ") + exception.what());
1867 }
1868}
Preset const * calibrate_printer
Definition PresetBundle.hpp:515
std::optional< Selection > selection() const
Definition PresetBundle.cpp:5912
void restore_selection(const Selection &selection)
Definition PresetBundle.cpp:5934
std::set< Preset const * > calibrate_filaments
Definition PresetBundle.hpp:516
Definition PresetBundle.hpp:406
static std::vector< std::string > dirty_options(const Preset *edited, const Preset *reference, const bool deep_compare=false)
Definition Preset.cpp:4092
T * begin(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:838
@ OnlyIfWasCompatible
Definition Preset.hpp:525
@ lock
Definition GLGizmoEmboss.cpp:209

References PresetBundle(), Slic3r::Always, Slic3r::ConfigBase::apply_only(), Slic3r::Preset::bundle_id, Slic3r::BundleMetadata::bundle_type, bundles, calibrate_filaments, calibrate_printer, Slic3r::check_local_bundle(), Slic3r::Preset::config, Slic3r::PresetCollection::current_dirty_options(), Slic3r::data_dir(), DEFAULT_USER_FOLDER_NAME, dir_user_presets_local, Slic3r::PresetCollection::dirty_options(), Slic3r::Enable, Slic3r::DynamicConfig::erase(), Slic3r::PresetCollection::error_count(), filament_presets, filaments, Slic3r::PresetCollection::find_preset(), Slic3r::PresetCollection::first_compatible(), Slic3r::PresetCollection::first_visible_idx(), Slic3r::PresetCollection::get_edited_preset(), Slic3r::PresetCollection::get_preset_parent(), Slic3r::PresetCollection::get_presets(), Slic3r::PresetCollection::get_selected_preset_name(), Slic3r::is_single_path_component(), Slic3r::BundleMetadata::is_subscribed, Slic3r::load_bundle_presets(), Slic3r::Local, Slic3r::PresetOrigin::LocalBundle, Slic3r::PresetCollection::m_edited_preset, Slic3r::PresetCollection::m_idx_selected, Slic3r::PresetCollection::m_map_alias_to_profile_name, Slic3r::PresetCollection::m_num_default_presets, Slic3r::PresetCollection::m_presets, Slic3r::PresetCollection::m_saved_preset, Slic3r::Preset::name, Slic3r::Never, Slic3r::OnlyIfWasCompatible, Slic3r::ConfigBase::option(), Slic3r::BundleMetadata::path, PRESET_BUNDLE_METADATA, PRESET_LOCAL_DIR, PRESET_USER_DIR, Slic3r::Preset::printer_technology(), printers, prints, project_config, Slic3r::ptFFF, reload_local_bundle(), restore_selection(), Slic3r::PresetCollection::select_preset(), Slic3r::PresetCollection::select_preset_by_name(), selection(), set_calibrate_printer(), Slic3r::DynamicConfig::set_key_value(), Slic3r::PresetCollection::size(), Slic3r::PresetCollection::sort_presets(), Slic3r::Subscribed, Slic3r::Preset::TYPE_INVALID, Slic3r::BundleMetadata::update_available, update_compatible(), Slic3r::PresetCollection::update_dirty(), Slic3r::PresetCollection::update_map_alias_to_profile_name(), and update_multi_material_filament_presets().

Referenced by Slic3r::anonymous_namespace{PluginHostPresets.cpp}::reload_local_bundle(), and reload_local_bundle().

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

◆ remove_user_presets_directory()

void Slic3r::PresetBundle::remove_user_presets_directory ( const std::string preset_folder)
3056{
3057 const std::string dir_user_presets = data_dir() + "/" + PRESET_USER_DIR + "/" + preset_folder;
3058
3059 if (preset_folder.empty()) {
3060 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": preset_folder is empty, no need to remove directory : %1%") % dir_user_presets;
3061 return;
3062 }
3063 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, delete directory : %1%") % dir_user_presets;
3064 boost::system::error_code ec;
3065 InstanceLock instance_lock(user_presets_lock_path());
3066 fs::remove_all(fs::path(dir_user_presets), ec);
3067}

References Slic3r::data_dir(), PRESET_USER_DIR, remove_user_presets_directory(), and Slic3r::user_presets_lock_path().

Referenced by remove_user_presets_directory().

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

◆ remove_users_preset()

void Slic3r::PresetBundle::remove_users_preset ( AppConfig & config,
std::map< std::string, std::map< std::string, std::string > > * my_presets = nullptr )
3203{
3204 auto check_removed = [my_presets](Preset &preset) -> bool {
3205 if (my_presets == nullptr) return true;
3206 if (my_presets->find(preset.name) != my_presets->end()) return false;
3207 if (!preset.sync_info.empty()) return false; // syncing, not remove
3208 if (preset.setting_id.empty()) return false; // no id, not remove
3209 // Saved preset is removed by another session
3210 if (preset.is_dirty) {
3211 preset.setting_id.clear();
3212 return false;
3213 }
3214 preset.remove_files(true /* cloud_already_deleted */);
3215 return true;
3216 };
3217 std::string preset_folder_user_id = config.get("preset_folder");
3218 std::string printer_selected_preset_name = printers.get_selected_preset().name;
3219 bool need_reset_printer_preset = false;
3220 for (auto it = printers.begin(); it != printers.end();) {
3221 if (it->is_user() && it->user_id.compare(preset_folder_user_id) == 0 && check_removed(*it)) {
3222 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":printers erase %1%, type %2%, user_id %3%") % it->name % Preset::get_type_string(it->type) % it->user_id;
3223 if (it->name == printer_selected_preset_name)
3224 need_reset_printer_preset = true;
3225 it = printers.erase(it);
3226 }
3227 else {
3228 it++;
3229 }
3230 }
3231
3232 if (need_reset_printer_preset) {
3233 std::string default_printer_model = ORCA_DEFAULT_PRINTER_MODEL;
3234 std::string default_printer_name;
3235 for (auto it = printers.begin(); it != printers.end(); it++) {
3236 if (it->config.has("printer_model")) {
3237 if (it->config.opt_string("printer_model") == default_printer_model) {
3238 default_printer_name = it->name;
3239 break;
3240 }
3241 }
3242 }
3243 printers.select_preset_by_name(default_printer_name, true);
3244 } else {
3245 printers.select_preset_by_name(printer_selected_preset_name, false);
3246 }
3247
3248 std::string selected_print_name = prints.get_selected_preset().name;
3249 bool need_reset_print_preset = false;
3250 // remove preset if user_id is not current user
3251 for (auto it = prints.begin(); it != prints.end();) {
3252 if (it->is_user() && it->user_id.compare(preset_folder_user_id) == 0 && check_removed(*it)) {
3253 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":prints erase %1%, type %2%, user_id %3%")%it->name %Preset::get_type_string(it->type) %it->user_id;
3254 if (it->name == selected_print_name)
3255 need_reset_print_preset = true;
3256 it = prints.erase(it);
3257 }
3258 else {
3259 it++;
3260 }
3261 }
3262 if (need_reset_print_preset && printers.get_selected_preset().config.has("default_print_profile")) {
3263 std::string default_print_profile_name = printers.get_selected_preset().config.opt_string("default_print_profile");
3264 prints.select_preset_by_name(default_print_profile_name, true);
3265 } else {
3266 prints.select_preset_by_name(selected_print_name, false);
3267 }
3268
3269 std::string selected_filament_name = filaments.get_selected_preset().name;
3270 bool need_reset_filament_preset = false;
3271 for (auto it = filaments.begin(); it != filaments.end();) {
3272 if (it->is_user() && it->user_id.compare(preset_folder_user_id) == 0 && check_removed(*it)) {
3273 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":filaments erase %1%, type %2%, user_id %3%")%it->name %Preset::get_type_string(it->type) %it->user_id;
3274 if (it->name == selected_filament_name)
3275 need_reset_filament_preset = true;
3276 it = filaments.erase(it);
3277 }
3278 else {
3279 it++;
3280 }
3281 }
3282 if (need_reset_filament_preset && printers.get_selected_preset().config.has("default_filament_profile")) {
3283 const std::vector<std::string>& prefered_filament_profiles = printers.get_selected_preset().config.option<ConfigOptionStrings>("default_filament_profile")->values;
3284 if (prefered_filament_profiles.size() > 0)
3285 filaments.select_preset_by_name(prefered_filament_profiles[0], true);
3286 } else {
3287 filaments.select_preset_by_name(selected_filament_name, false);
3288 }
3289
3291
3292 /* set selected preset */
3293 for (size_t i = 0; i < filament_presets.size(); ++i)
3294 {
3295 auto preset = this->filaments.find_preset(filament_presets[i]);
3296 if (preset == nullptr)
3297 filament_presets[i] = filaments.get_selected_preset_name();
3298 }
3299}
static const char * ORCA_DEFAULT_PRINTER_MODEL
Definition PresetBundle.hpp:687

References Slic3r::Always, filament_presets, filaments, Slic3r::AppConfig::get(), Slic3r::Preset::get_type_string(), Slic3r::Preset::is_dirty, Slic3r::Preset::name, ORCA_DEFAULT_PRINTER_MODEL, printers, prints, Slic3r::Preset::remove_files(), remove_users_preset(), Slic3r::Preset::setting_id, Slic3r::Preset::sync_info, and update_compatible().

Referenced by load_user_presets(), and remove_users_preset().

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

◆ reset()

void Slic3r::PresetBundle::reset ( bool delete_files)
792{
793 // Clear the existing presets, delete their respective files.
794 this->vendors.clear();
795 this->prints .reset(delete_files);
796 this->sla_prints .reset(delete_files);
797 this->filaments .reset(delete_files);
798 this->sla_materials.reset(delete_files);
799 this->printers .reset(delete_files);
800 // BBS: filament_presets is load from project config, not handled here
801 //this->filament_presets.clear();
802 if (this->filament_presets.empty())
803 this->filament_presets.emplace_back(this->filaments.get_selected_preset_name());
804 this->obsolete_presets.prints.clear();
805 this->obsolete_presets.sla_prints.clear();
806 this->obsolete_presets.filaments.clear();
807 this->obsolete_presets.sla_materials.clear();
808 this->obsolete_presets.printers.clear();
809}

References filament_presets, filaments, obsolete_presets, printers, prints, reset(), sla_materials, sla_prints, and vendors.

Referenced by install_vendor_cache(), read_vendor(), and reset().

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

◆ reset_default_nozzle_volume_type()

void Slic3r::PresetBundle::reset_default_nozzle_volume_type ( )
5359{
5360 Preset& current_printer = this->printers.get_edited_preset();
5361 this->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values = current_printer.config.option<ConfigOptionEnumsGeneric>("default_nozzle_volume_type")->values;
5362}

References Slic3r::Preset::config, Slic3r::ConfigBase::option(), printers, project_config, and reset_default_nozzle_volume_type().

Referenced by on_extruders_count_changed(), reset_default_nozzle_volume_type(), and anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_config().

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

◆ reset_project_embedded_presets()

void Slic3r::PresetBundle::reset_project_embedded_presets ( )
1241{
1242 std::string prefer_printer;
1243 Preset& current_printer = this->printers.get_selected_preset();
1244 ConfigOption* inherits = current_printer.config.option("inherits");
1245 if (inherits) {
1246 prefer_printer = dynamic_cast<ConfigOptionString *>(inherits)->value;
1247 }
1248 //first printer, then filament, then print
1249 bool printer_reselect = this->printers.reset_project_embedded_presets();
1250 bool filament_reselect = this->filaments.reset_project_embedded_presets();
1251 bool print_reselect = this->prints.reset_project_embedded_presets();
1252
1253 if (printer_reselect) {
1254 if (!prefer_printer.empty())
1255 this->printers.select_preset_by_name(prefer_printer, true);
1256 else
1257 this->printers.select_preset(this->printers.first_visible_idx());
1258
1259 //this->update_multi_material_filament_presets();
1261 }
1262 else if (filament_reselect || print_reselect) {
1263 //Preset& current_printer = this->printers.get_selected_preset();
1264 /*if (filament_reselect) {
1265 const std::vector<std::string> &prefered_filament_profiles = current_printer.config.option<ConfigOptionStrings>("default_filament_profile")->values;
1266 const std::string prefered_filament_profile = prefered_filament_profiles.empty() ? std::string() : prefered_filament_profiles.front();
1267 if (!prefered_filament_profile.empty())
1268 this->filaments.select_preset_by_name(prefered_filament_profile, true);
1269 else
1270 this->filaments.select_preset(this->filaments.first_visible_idx());
1271 }
1272
1273 if (print_reselect) {
1274 }*/
1276 }
1277
1278 //this->update_multi_material_filament_presets();
1279
1280 //update filament_presets
1281 for (size_t i = 0; i < filament_presets.size(); ++ i)
1282 {
1283 Preset* selected_filament = this->filaments.find_preset(filament_presets[i], false);
1284 if (!selected_filament) {
1285 //it should be the project embedded presets
1286 Preset& current_printer = this->printers.get_selected_preset();
1287 const std::vector<std::string> &prefered_filament_profiles = current_printer.config.option<ConfigOptionStrings>("default_filament_profile")->values;
1288 const std::string prefered_filament_profile = prefered_filament_profiles.empty() ? std::string() : prefered_filament_profiles.front();
1289 if (!prefered_filament_profile.empty()) {
1290 // Check if preferred filament exists and is visible
1291 const Preset* preferred_preset = this->filaments.find_preset(prefered_filament_profile, false);
1292 if (preferred_preset && preferred_preset->is_visible) {
1293 filament_presets[i] = prefered_filament_profile;
1294 } else {
1295 // Fall back to first visible filament
1296 filament_presets[i] = this->filaments.first_visible().name;
1297 }
1298 } else
1299 filament_presets[i] = this->filaments.first_visible().name;
1300 }
1301 }
1302}

References Slic3r::Preset::config, filament_presets, filaments, Slic3r::Preset::is_visible, Slic3r::Never, Slic3r::ConfigBase::option(), printers, prints, reset_project_embedded_presets(), and update_compatible().

Referenced by reset_project_embedded_presets().

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

◆ resolve_preset_config()

bool Slic3r::PresetBundle::resolve_preset_config ( DynamicPrintConfig & config,
Preset::Type type,
const std::string & source_file,
ForwardCompatibilitySubstitutionRule compatibility_rule,
std::string & error,
bool allow_source_manifest = true )
560{
565
566 auto collection_for_type = [](const PresetBundle &bundle, Preset::Type preset_type) -> const PresetCollection * {
567 switch (preset_type) {
568 case Preset::TYPE_PRINT: return &bundle.prints;
569 case Preset::TYPE_FILAMENT: return &bundle.filaments;
570 case Preset::TYPE_PRINTER: return &bundle.printers;
571 default: return nullptr;
572 }
573 };
574
575 const PresetCollection *collection = collection_for_type(*this, type);
576 if (collection == nullptr) {
577 error = "Unsupported preset type";
578 return false;
579 }
580
581 const boost::filesystem::path source_path = boost::filesystem::absolute(source_file).lexically_normal();
582 auto find_loaded = [&](const PresetBundle &bundle) -> const Preset * {
583 const PresetCollection *loaded_collection = collection_for_type(bundle, type);
584 const Preset *resolved = nullptr;
585 for (const Preset &preset : loaded_collection->get_presets()) {
586 if (preset.file.empty())
587 continue;
588
589 boost::system::error_code ec;
590 const bool same_file = boost::filesystem::equivalent(source_path, boost::filesystem::path(preset.file), ec);
591 if (ec || !same_file)
592 continue;
593 if (resolved != nullptr) {
594 error = "Preset identity is ambiguous";
595 return nullptr;
596 }
597 resolved = &preset;
598 }
599 return resolved;
600 };
601
602 if (const Preset *resolved = find_loaded(*this)) {
603 config = resolved->config;
604 error.clear();
605 return true;
606 }
607 if (error == "Preset identity is ambiguous")
608 return false;
609 if (!allow_source_manifest) {
610 error = "Preset was not found in the loaded bundle";
611 return false;
612 }
613
614 // A manifest-backed source file can be resolved without requiring the vendor
615 // to have been copied into data_dir()/system. Find the nearest ancestor whose
616 // sibling manifest names it, then let the canonical vendor loader flatten the
617 // complete tree (including nested sub_path entries and library inheritance).
618 for (boost::filesystem::path vendor_dir = source_path.parent_path(); !vendor_dir.empty(); vendor_dir = vendor_dir.parent_path()) {
619 const std::string vendor_id = vendor_dir.filename().string();
620 if (vendor_id.empty())
621 continue;
622 const boost::filesystem::path root_dir = vendor_dir.parent_path();
623 const boost::filesystem::path manifest = root_dir / (vendor_id + ".json");
624 if (!boost::filesystem::is_regular_file(manifest))
625 continue;
626 const boost::filesystem::path manifest_relative = source_path.lexically_relative(vendor_dir);
627 if (manifest_relative.empty() || *manifest_relative.begin() == "..")
628 continue;
629
630 try {
631 const PresetBundle *loaded = load_source_vendor(root_dir, vendor_id, compatibility_rule, error);
632 if (loaded == nullptr)
633 return false;
634
635 const Preset *resolved = find_loaded(*loaded);
636 if (resolved == nullptr) {
637 if (error.empty())
638 error = "Source file is not an instantiated preset in its vendor manifest";
639 return false;
640 }
641 config = resolved->config;
642 error.clear();
643 return true;
644 } catch (const std::exception &ex) {
645 error = ex.what();
646 return false;
647 }
648 }
649
650 error = "Preset was not found in the loaded bundle";
651 return false;
652}
Type
Definition Preset.hpp:244

References PresetBundle(), Slic3r::Preset::config, Slic3r::Disable, Slic3r::EnableSilent, Slic3r::EnableSilentDisableSystem, Slic3r::EnableSystemSilent, filaments, Slic3r::Preset::file, Slic3r::PresetCollection::get_presets(), load_source_vendor(), printers, prints, resolve_preset_config(), Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::TYPE_PRINT, and Slic3r::Preset::TYPE_PRINTER.

Referenced by resolve_preset_config(), resolve_preset_config_type(), and Slic3r::CLI::run().

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

◆ resolve_preset_config_type()

bool Slic3r::PresetBundle::resolve_preset_config_type ( DynamicPrintConfig & config,
Preset::Type & type,
const std::string & source_file,
ForwardCompatibilitySubstitutionRule compatibility_rule,
std::string & error,
bool allow_source_manifest = true )
693{
694 std::optional<std::pair<Preset::Type, DynamicPrintConfig>> resolved;
695 for (Preset::Type candidate_type : types_list(ptFFF)) {
696 DynamicPrintConfig candidate_config(config);
697 std::string candidate_error;
698 if (!resolve_preset_config(candidate_config, candidate_type, source_file, compatibility_rule,
699 candidate_error, allow_source_manifest)) {
700 if (candidate_error == "Preset identity is ambiguous") {
701 error = std::move(candidate_error);
702 return false;
703 }
704 continue;
705 }
706 if (resolved) {
707 error = "Preset type is ambiguous";
708 return false;
709 }
710 resolved.emplace(candidate_type, std::move(candidate_config));
711 }
712
713 if (!resolved) {
714 error = "Preset type could not be resolved";
715 return false;
716 }
717
718 type = resolved->first;
719 config = std::move(resolved->second);
720 error.clear();
721 return true;
722}
static std::array< Preset::Type, 3 > types_list(PrinterTechnology pt)
Definition PresetBundle.hpp:694
bool resolve_preset_config(DynamicPrintConfig &config, Preset::Type type, const std::string &source_file, ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error, bool allow_source_manifest=true)
Definition PresetBundle.cpp:556

References Slic3r::ptFFF, resolve_preset_config(), resolve_preset_config_type(), and types_list().

Referenced by resolve_preset_config_type(), and Slic3r::CLI::run().

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

◆ resolve_system_preset()

bool Slic3r::PresetBundle::resolve_system_preset ( DynamicPrintConfig & config,
Preset::Type type,
const std::string & name,
ForwardCompatibilitySubstitutionRule compatibility_rule,
std::string & error )
726{
727 const std::string vendor_id = find_preset_vendor(name, type);
728 if (vendor_id.empty()) {
729 error = "No vendor lists the preset";
730 return false;
731 }
732 // Release builds ship a vendor as its preset cache alone, without the profile JSONs.
733 auto installed = [&vendor_id](const fs::path &root) {
734 return fs::is_regular_file(root / (vendor_id + ".json")) || fs::is_regular_file(root / (vendor_id + ".opc"));
735 };
736 fs::path root_dir = fs::path(data_dir()) / PRESET_SYSTEM_DIR;
737 if (!installed(root_dir))
738 root_dir = fs::path(resources_dir()) / PRESET_PROFILES_DIR;
739 const bool cache_only = !fs::is_regular_file(root_dir / (vendor_id + ".json"));
740
741 try {
742 const PresetBundle *vendor = load_source_vendor(root_dir, vendor_id, compatibility_rule, error, cache_only);
743 if (vendor == nullptr)
744 return false;
745 const PresetCollection &collection = type == Preset::TYPE_PRINTER ? vendor->printers :
746 type == Preset::TYPE_PRINT ? vendor->prints : vendor->filaments;
747 const Preset *preset = collection.find_preset(name, false);
748 if (preset == nullptr) {
749 error = "Preset was not found in its vendor bundle";
750 return false;
751 }
752 config = preset->config;
753 } catch (const std::exception &ex) {
754 error = ex.what();
755 return false;
756 }
757 error.clear();
758 return true;
759}
static std::string find_preset_vendor(const std::string &preset_name, Preset::Type type)
Definition PresetBundle.cpp:403

References PresetBundle(), Slic3r::Preset::config, Slic3r::data_dir(), filaments, Slic3r::PresetCollection::find_preset(), find_preset_vendor(), load_source_vendor(), PRESET_PROFILES_DIR, PRESET_SYSTEM_DIR, printers, prints, resolve_system_preset(), Slic3r::resources_dir(), Slic3r::Preset::TYPE_PRINT, and Slic3r::Preset::TYPE_PRINTER.

Referenced by resolve_system_preset().

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

◆ resolve_vendor_preset()

PresetBundle::PresetInstall Slic3r::PresetBundle::resolve_vendor_preset ( const CachedPreset & entry,
const VendorInstall & install ) const
private
7583{
7584 const std::string& path = install.path;
7585 const std::string& vendor_name = install.vendor_name;
7586 const PresetBundle* base_bundle = install.base_bundle;
7587 const PresetCollection& presets_collection = *install.presets;
7588 const VendorProfile& current_vendor_profile = *install.vendor_profile;
7589 const std::string& preset_name = entry.name;
7590 const DynamicPrintConfig* default_config = nullptr;
7591 const bool retain = install.is_from_lib || install.inherited.count(preset_name) != 0;
7592
7593 PresetInstall out;
7594 out.filament_id = entry.filament_id;
7595 out.renamed_from = entry.renamed_from;
7596
7597 //check whether it inherits other preset or not
7598 if (! entry.inherits.empty()) {
7599 auto it2 = install.config_maps.find(entry.inherits);
7600 if (it2 != install.config_maps.end())
7601 default_config = &(it2->second);
7602 if (default_config == nullptr && base_bundle != nullptr) {
7603 auto base_it2 = base_bundle->m_config_maps.find(entry.inherits);
7604 if (base_it2 != base_bundle->m_config_maps.end())
7605 default_config = &(base_it2->second);
7606 }
7607 if (default_config != nullptr) {
7608 if (out.filament_id.empty() && (presets_collection.type() == Preset::TYPE_FILAMENT)) {
7609 auto filament_id_map_iter = install.filament_id_maps.find(entry.inherits);
7610 if (filament_id_map_iter != install.filament_id_maps.end()) {
7611 out.filament_id = filament_id_map_iter->second;
7612 }
7613 if (out.filament_id.empty() && base_bundle != nullptr) {
7614 auto base_filament_id_map_iter = base_bundle->m_filament_id_maps.find(entry.inherits);
7615 if (base_filament_id_map_iter != base_bundle->m_filament_id_maps.end()) {
7616 out.filament_id = base_filament_id_map_iter->second;
7617 }
7618 }
7619 }
7620 }
7621 else {
7622 out.errors.push_back(std::string(__FUNCTION__) + ": can not find inherits " + entry.inherits + " for " + preset_name);
7623 out.reason = "Can not find inherits: " + entry.inherits;
7624 return out;
7625 }
7626 }
7627 else
7628 default_config = &presets_collection.default_preset_for(entry.config_src).config;
7629 out.config = *default_config;
7630 // Layer each included preset's own keys over the parent, in the order listed;
7631 // this preset's own keys go on top.
7632 for (const std::string& name : entry.includes) {
7633 auto it = install.include_maps.find(name);
7634 if (it == install.include_maps.end()) {
7635 out.errors.push_back(std::string(__FUNCTION__) + ": can not find include " + name + " for " + preset_name);
7636 continue;
7637 }
7638 out.config.apply(it->second);
7639 }
7640 out.config.apply(entry.config_src);
7641 // Record what a base states, its diff against the default, for the presets
7642 // that include it. It is taken before extend_default_config_length pads every
7643 // per-variant key to the base's variant count: the padded defaults would
7644 // otherwise override the values each includer inherits.
7645 if (entry.instantiation == "false" && install.included.count(preset_name) != 0) {
7646 out.included.emplace();
7647 out.included->apply_only(out.config, out.config.diff(presets_collection.default_preset_for(out.config).config));
7648 }
7649 extend_default_config_length(out.config, true, *default_config);
7650 // Report configuration fields, which are misplaced into a wrong group, before
7651 // Preset::normalize derives keys from them. An include diff holds only keys of the
7652 // collection default, so only the entry's own keys can be missing from default_config.
7653 std::string incorrect_keys = Preset::remove_invalid_keys(out.config, *default_config, &entry.config_src);
7654 if (!incorrect_keys.empty())
7655 out.errors.push_back(std::string(__FUNCTION__) + ": The config " + path + "/" + vendor_name + "/" + entry.sub_path +
7656 " contains incorrect keys: " + incorrect_keys + ", which were removed");
7657 if (entry.instantiation == "false" && "Template" != vendor_name) {
7658 out.config_only = true;
7659 if (retain)
7660 out.retained = std::move(out.config);
7661 return out;
7662 }
7663 if (out.config.has("alias"))
7664 out.alias = (dynamic_cast<const ConfigOptionString *>(out.config.option("alias")))->value;
7665
7666 Preset::normalize(out.config);
7667
7668 if (presets_collection.type() == Preset::TYPE_PRINTER) {
7669 // Filter out printer presets, which are not mentioned in the vendor profile.
7670 // These presets are considered not installed.
7671 auto printer_model = out.config.opt_string("printer_model");
7672 if (printer_model.empty()) {
7673 out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
7674 preset_name + "\" defines no printer model, it will be ignored.");
7675 out.reason = std::string("can not find printer_model");
7676 return out;
7677 }
7678 auto printer_variant = out.config.opt_string("printer_variant");
7679 if (printer_variant.empty()) {
7680 out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
7681 preset_name + "\" defines no printer variant, it will be ignored.");
7682 out.reason = std::string("can not find printer_variant");
7683 return out;
7684 }
7685 auto it_model = std::find_if(current_vendor_profile.models.cbegin(), current_vendor_profile.models.cend(),
7686 [&](const VendorProfile::PrinterModel &m) { return m.id == printer_model; }
7687 );
7688 if (it_model == current_vendor_profile.models.end()) {
7689 out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
7690 preset_name + "\" defines invalid printer model \"" + printer_model + "\", it will be ignored.");
7691 out.reason = std::string("can not find printer model in vendor profile");
7692 return out;
7693 }
7694 auto it_variant = it_model->variant(printer_variant);
7695 if (it_variant == nullptr) {
7696 out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
7697 preset_name + "\" defines invalid printer variant \"" + printer_variant + "\", it will be ignored.");
7698 out.reason = std::string("can not find printer_variant in vendor profile");
7699 return out;
7700 }
7701 // An instantiation printer profile's nozzle_diameter must match the numeric (diameter)
7702 // prefix of its printer_variant: "0.4" -> {0.4}, "0.8HF" -> {0.8} (a trailing
7703 // non-numeric suffix such as "HF"/"HS" distinguishes a hardware sub-variant and is
7704 // ignored here), and for multi-nozzle printers "0.4+0.6" -> {0.4, 0.6}.
7705 // Note: a variant may legitimately repeat across presets of the same model (e.g. speed
7706 // modes, IDEX copy/mirror, or different control boards), so only the diameter is
7707 // validated, not variant uniqueness. Validation-only so the app keeps loading existing
7708 // profiles unchanged.
7709 if (validation_mode && entry.instantiation == "true") {
7710 const auto *nd = out.config.option<ConfigOptionFloats>("nozzle_diameter");
7711 std::set<double> nozzles, variant_nozzles;
7712 if (nd != nullptr)
7713 nozzles.insert(nd->values.begin(), nd->values.end());
7714 std::vector<std::string> variant_tokens;
7715 boost::algorithm::split(variant_tokens, printer_variant, boost::algorithm::is_any_of("+"));
7716 bool variant_ok = true; // printer_variant is already guaranteed non-empty above
7717 for (const std::string &tok : variant_tokens) {
7718 size_t consumed = 0;
7719 double d = string_to_double_decimal_point(tok, &consumed);
7720 // Require a leading numeric diameter; a trailing suffix (e.g. "HF") is allowed.
7721 if (consumed == 0) { variant_ok = false; break; }
7722 variant_nozzles.insert(d);
7723 }
7724 if (!variant_ok || variant_nozzles != nozzles) {
7725 out.errors.push_back("Error in a Vendor Config Bundle \"" + path + "\": The printer preset \"" +
7726 preset_name + "\" has printer_variant \"" + printer_variant +
7727 "\" that does not match its nozzle_diameter \"" + (nd ? nd->serialize() : std::string()) + "\". "
7728 "printer_variant must begin with the nozzle diameter, optionally followed by a non-numeric suffix "
7729 "(e.g. \"0.4\", \"0.8HF\"); for multi-nozzle printers, join the per-nozzle diameters with \"+\" in "
7730 "nozzle order (e.g. \"0.4+0.6\").");
7731 }
7732 }
7733 }
7734
7735 // Derive the profile logical name aka alias from the preset name if the alias was not stated explicitely.
7736 if (out.alias.empty()) {
7737 size_t end_pos = preset_name.find_first_of("@");
7738 if (end_pos != std::string::npos) {
7739 out.alias = preset_name.substr(0, end_pos);
7740 if (out.renamed_from.empty())
7741 // Add the preset name with the '@' character removed into the "renamed_from" list.
7742 out.renamed_from.emplace_back(out.alias + preset_name.substr(end_pos + 1));
7743 boost::trim_right(out.alias);
7744 }
7745 }
7746
7747 out.file_path = (boost::filesystem::path(data_dir()) / PRESET_SYSTEM_DIR / vendor_name / entry.sub_path).make_preferred().string();
7748 if (validation_mode)
7749 out.file_path = (boost::filesystem::path(data_dir()) / vendor_name / entry.sub_path).make_preferred().string();
7751 out.file_path = (boost::filesystem::path(path) / vendor_name / entry.sub_path).make_preferred().string();
7752 if (retain)
7753 out.retained = out.config;
7754 return out;
7755}
std::string filament_id
Definition PresetBundle.hpp:868
bool m_preserve_vendor_source_paths
Definition PresetBundle.hpp:902
double string_to_double_decimal_point(const std::string_view str, size_t *pos)
Definition LocalesUtils.cpp:86

References PresetBundle(), Slic3r::PresetBundle::PresetInstall::alias, Slic3r::ConfigBase::apply(), Slic3r::Preset::config, Slic3r::PresetBundle::PresetInstall::config, Slic3r::PresetBundle::PresetInstall::config_only, Slic3r::CachedPreset::config_src, Slic3r::data_dir(), Slic3r::PresetCollection::default_preset_for(), Slic3r::DynamicConfig::diff(), Slic3r::PresetBundle::PresetInstall::errors, Slic3r::extend_default_config_length(), Slic3r::CachedPreset::filament_id, Slic3r::PresetBundle::PresetInstall::filament_id, Slic3r::PresetBundle::PresetInstall::file_path, Slic3r::ConfigOptionResolver::has(), Slic3r::PresetBundle::PresetInstall::included, Slic3r::CachedPreset::includes, Slic3r::CachedPreset::inherits, Slic3r::CachedPreset::instantiation, m_config_maps, m_filament_id_maps, m_preserve_vendor_source_paths, Slic3r::VendorProfile::models, Slic3r::CachedPreset::name, Slic3r::Preset::normalize(), Slic3r::DynamicConfig::opt_string(), Slic3r::ConfigBase::option(), PRESET_SYSTEM_DIR, Slic3r::PresetBundle::PresetInstall::reason, Slic3r::Preset::remove_invalid_keys(), Slic3r::CachedPreset::renamed_from, Slic3r::PresetBundle::PresetInstall::renamed_from, resolve_vendor_preset(), Slic3r::PresetBundle::PresetInstall::retained, Slic3r::string_to_double_decimal_point(), Slic3r::CachedPreset::sub_path, Slic3r::PresetCollection::type(), Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::TYPE_PRINTER, and validation_mode.

Referenced by install_vendor_entries(), and resolve_vendor_preset().

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

◆ restore_selection()

void Slic3r::PresetBundle::restore_selection ( const Selection & selection)
5935{
5936 auto restore = [](PresetCollection &presets, const Selection::Collection &saved) {
5937 presets.reset_project_embedded_presets();
5938 // Before selecting: select_preset_by_name() passes over a hidden preset.
5939 assert(presets.m_presets.size() == saved.visible.size());
5940 for (size_t i = 0; i < std::min(presets.m_presets.size(), saved.visible.size()); ++i)
5941 presets.m_presets[i].is_visible = saved.visible[i];
5942 presets.select_preset_by_name(saved.selected, true);
5943 presets.m_saved_preset.config = saved.saved;
5944 presets.get_edited_preset().config = saved.edited;
5945 presets.update_dirty();
5946 };
5947 restore(this->printers, selection.printers);
5948 restore(this->prints, selection.prints);
5949 restore(this->filaments, selection.filaments);
5952 // Last, as update_multi_material_filament_presets() resizes filament_presets and the flush data in project_config.
5953 this->filament_presets = selection.filament_presets;
5954 this->project_config = selection.project_config;
5955 this->extruder_ams_counts = selection.extruder_ams_counts;
5956}
Definition PresetBundle.hpp:408

References Slic3r::Preset::config, extruder_ams_counts, filament_presets, filaments, Slic3r::PresetCollection::get_edited_preset(), Slic3r::PresetCollection::m_presets, Slic3r::PresetCollection::m_saved_preset, Slic3r::Never, printers, prints, project_config, Slic3r::PresetCollection::reset_project_embedded_presets(), restore_selection(), Slic3r::PresetCollection::select_preset_by_name(), selection(), update_compatible(), Slic3r::PresetCollection::update_dirty(), and update_multi_material_filament_presets().

Referenced by Slic3r::GUI::Plater::load_gcode(), reload_local_bundle(), and restore_selection().

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

◆ save_changes_for_preset()

void Slic3r::PresetBundle::save_changes_for_preset ( const std::string & new_name,
Preset::Type type,
const std::vector< std::string > & unselected_options,
bool save_to_project = false )
3731{
3732 PresetCollection& presets = type == Preset::TYPE_PRINT ? prints :
3736
3737 // if we want to save just some from selected options
3738 if (!unselected_options.empty()) {
3739 // revert unselected options to the old values
3740 presets.get_edited_preset().config.apply_only(presets.get_selected_preset().config, unselected_options);
3741 }
3742
3743 // Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
3744 //BBS: add project embedded preset logic
3745 //presets.save_current_preset(new_name);
3746 presets.save_current_preset(new_name, false, save_to_project);
3747 // Mark the print & filament enabled if they are compatible with the currently selected preset.
3748 // If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
3750
3751 if (type == Preset::TYPE_FILAMENT) {
3752 // synchronize the first filament presets.
3753 set_filament_preset(0, filaments.get_selected_preset_name());
3754 }
3755}
void set_filament_preset(size_t idx, const std::string &name)
Definition PresetBundle.cpp:8730

References Slic3r::ConfigBase::apply_only(), Slic3r::Preset::config, filaments, Slic3r::PresetCollection::get_edited_preset(), Slic3r::PresetCollection::get_selected_preset(), Slic3r::Never, printers, prints, save_changes_for_preset(), Slic3r::PresetCollection::save_current_preset(), set_filament_preset(), sla_materials, sla_prints, Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::TYPE_PRINT, Slic3r::Preset::TYPE_SLA_MATERIAL, Slic3r::Preset::TYPE_SLA_PRINT, and update_compatible().

Referenced by save_changes_for_preset().

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

◆ save_preset_to_bundle_dir()

bool Slic3r::PresetBundle::save_preset_to_bundle_dir ( Preset & preset,
PresetCollection * collection,
const std::string & bundle_id,
const std::string & type_subdir,
const std::string & bundle_base_dir )
private
2962{
2963 if (bundle_base_dir.empty()) {
2964 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " bundle_base_dir is empty, cannot save preset " << preset.name;
2965 return false;
2966 }
2967
2968 // Store original directory path
2969 std::string original_dir_path = collection->m_dir_path;
2970
2971 try {
2972 // Create bundle directory if it doesn't exist
2973 boost::filesystem::path bundle_dir(bundle_base_dir);
2974 boost::system::error_code ec;
2975 if (!boost::filesystem::exists(bundle_dir))
2976 boost::filesystem::create_directories(bundle_dir, ec);
2977 if (ec) {
2978 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed to create bundle directory: " << bundle_dir.string() << " error: " << ec.message();
2979 return false;
2980 }
2981
2982 // Create bundle type directory
2983 boost::filesystem::path type_dir = bundle_dir / type_subdir;
2984 if (!boost::filesystem::exists(type_dir)) {
2985 boost::filesystem::create_directories(type_dir, ec);
2986 if (ec) {
2987 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed to create type directory: " << type_dir.string() << " error: " << ec.message();
2988 return false;
2989 }
2990 }
2991
2992 preset.bundle_id = bundle_id;
2993
2994 // Bundle preset names may include the subscribed/local prefix path.
2995 // Persist the file under the type directory using only the base preset name.
2996 const std::string preset_filename = boost::filesystem::path(preset.name).filename().string();
2997 const std::string file_name = boost::iends_with(preset_filename, ".json") ? preset_filename : (preset_filename + ".json");
2998 preset.file = (type_dir / file_name).make_preferred().string();
2999
3000 // Save with parent config if inherits from another preset
3001 std::string inherits = Preset::inherits(preset.config);
3002 if (inherits.empty()) {
3003 // Root preset - save full config
3004 preset.save(nullptr);
3005 } else {
3006 Preset* parent_preset = collection->find_preset2(inherits, true);
3007 if (!parent_preset) {
3008 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " cannot find parent preset for " << preset.name << ", inherits " << inherits;
3009 } else {
3010 // Orca: take the saved diff against the resolved parent (renamed / library-matched).
3011 Preset::normalize_inherits(preset.config, parent_preset);
3012 if (preset.base_id.empty())
3013 preset.base_id = parent_preset->setting_id;
3014 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " saved preset " << preset.name
3015 << " filament_id: " << preset.filament_id
3016 << " base_id: " << preset.base_id
3017 << " bundle: " << bundle_id;
3018 preset.save(&(parent_preset->config));
3019 }
3020 }
3021
3022 // Restore original directory path
3023 collection->m_dir_path = original_dir_path;
3024 return true;
3025
3026 } catch (const std::exception& e) {
3027 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " exception saving preset " << preset.name << ": " << e.what();
3028 collection->m_dir_path = original_dir_path;
3029 return false;
3030 }
3031}

References Slic3r::Preset::base_id, Slic3r::Preset::bundle_id, Slic3r::Preset::config, Slic3r::Preset::filament_id, Slic3r::Preset::file, Slic3r::PresetCollection::find_preset2(), Slic3r::Preset::inherits(), Slic3r::PresetCollection::m_dir_path, Slic3r::Preset::name, Slic3r::Preset::normalize_inherits(), Slic3r::Preset::save(), save_preset_to_bundle_dir(), and Slic3r::Preset::setting_id.

Referenced by import_json_presets(), save_preset_to_bundle_dir(), and update_subscribed_presets().

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

◆ save_user_presets()

void Slic3r::PresetBundle::save_user_presets ( AppConfig & config,
std::map< std::string, std::string > & need_to_delete_list )
2700{
2701 std::string user_sub_folder = DEFAULT_USER_FOLDER_NAME;
2702 if (!config.get("preset_folder").empty())
2703 user_sub_folder = config.get("preset_folder");
2704 //BBS: change directory by design
2705 const std::string dir_user_presets = data_dir() + "/" + PRESET_USER_DIR + "/"+ user_sub_folder;
2706
2707 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, save to %1%")%dir_user_presets;
2708
2709 fs::path user_folder(data_dir() + "/" + PRESET_USER_DIR);
2710 if (!fs::exists(user_folder))
2711 fs::create_directory(user_folder);
2712
2713 fs::path folder(dir_user_presets);
2714 if (!fs::exists(folder))
2715 fs::create_directory(folder);
2716
2717 this->prints.save_user_presets(dir_user_presets, PRESET_PRINT_NAME, need_to_delete_list);
2718 this->filaments.save_user_presets(dir_user_presets, PRESET_FILAMENT_NAME, need_to_delete_list);
2719 this->printers.save_user_presets(dir_user_presets, PRESET_PRINTER_NAME, need_to_delete_list);
2720 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished");
2721}

References Slic3r::data_dir(), DEFAULT_USER_FOLDER_NAME, filaments, Slic3r::AppConfig::get(), PRESET_FILAMENT_NAME, PRESET_PRINT_NAME, PRESET_PRINTER_NAME, PRESET_USER_DIR, printers, prints, and save_user_presets().

Referenced by save_user_presets().

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

◆ selection()

std::optional< PresetBundle::Selection > Slic3r::PresetBundle::selection ( ) const
5913{
5914 auto capture = [](const PresetCollection &presets, Selection::Collection &out) {
5915 if (std::any_of(presets.m_presets.begin(), presets.m_presets.end(), [](const Preset &preset) { return preset.is_project_embedded; }))
5916 return false;
5917 out.selected = presets.get_selected_preset_name();
5918 out.edited = presets.get_edited_preset().config;
5919 out.saved = presets.m_saved_preset.config;
5920 out.visible.reserve(presets.m_presets.size());
5921 for (const Preset &preset : presets.m_presets)
5922 out.visible.push_back(preset.is_visible);
5923 return true;
5924 };
5926 if (!capture(this->prints, selection.prints) || !capture(this->filaments, selection.filaments) || !capture(this->printers, selection.printers))
5927 return std::nullopt;
5928 selection.filament_presets = this->filament_presets;
5929 selection.project_config = this->project_config;
5930 selection.extruder_ams_counts = this->extruder_ams_counts;
5931 return selection;
5932}

References Slic3r::Preset::config, extruder_ams_counts, filament_presets, filaments, Slic3r::PresetCollection::get_edited_preset(), Slic3r::PresetCollection::get_selected_preset_name(), Slic3r::Preset::is_visible, Slic3r::PresetCollection::m_presets, Slic3r::PresetCollection::m_saved_preset, printers, prints, project_config, and selection().

Referenced by Slic3r::GUI::Plater::load_gcode(), reload_local_bundle(), restore_selection(), and selection().

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

◆ set_calibrate_printer()

void Slic3r::PresetBundle::set_calibrate_printer ( std::string name)
5114{
5115 if (name.empty()) {
5116 calibrate_filaments.clear();
5117 return;
5118 }
5119 if (!name.empty())
5120 calibrate_printer = printers.find_preset(name);
5121 const Preset & printer_preset = calibrate_printer ? *calibrate_printer : printers.get_edited_preset();
5122 const PresetWithVendorProfile active_printer = printers.get_preset_with_vendor_profile(printer_preset);
5123 DynamicPrintConfig config;
5124 config.set_key_value("printer_preset", new ConfigOptionString(active_printer.preset.name));
5125 const ConfigOption *opt = active_printer.preset.config.option("nozzle_diameter");
5126 if (opt) config.set_key_value("num_extruders", new ConfigOptionInt((int) static_cast<const ConfigOptionFloats *>(opt)->values.size()));
5127 calibrate_filaments.clear();
5128 for (size_t i = filaments.num_default_presets(); i < filaments.size(); ++i) {
5129 const Preset & preset = filaments.m_presets[i];
5130 const PresetWithVendorProfile this_preset_with_vendor_profile = filaments.get_preset_with_vendor_profile(preset);
5131 bool is_compatible = is_compatible_with_printer(this_preset_with_vendor_profile, active_printer, &config);
5132 if (is_compatible) calibrate_filaments.insert(&preset);
5133 }
5134}

References calibrate_filaments, calibrate_printer, Slic3r::Preset::config, filaments, Slic3r::is_compatible_with_printer(), Slic3r::Preset::name, Slic3r::ConfigBase::option(), Slic3r::PresetWithVendorProfile::preset, printers, set_calibrate_printer(), and Slic3r::DynamicConfig::set_key_value().

Referenced by load_presets(), load_user_presets(), load_user_presets(), reload_local_bundle(), set_calibrate_printer(), Slic3r::GUI::CalibrationPresetPage::update_combobox_filaments(), and update_subscribed_presets().

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

◆ set_default_suppressed()

void Slic3r::PresetBundle::set_default_suppressed ( bool default_suppressed)
8740{
8741 prints.set_default_suppressed(default_suppressed);
8742 filaments.set_default_suppressed(default_suppressed);
8743 sla_prints.set_default_suppressed(default_suppressed);
8744 sla_materials.set_default_suppressed(default_suppressed);
8745 printers.set_default_suppressed(default_suppressed);
8746}

References filaments, printers, prints, set_default_suppressed(), sla_materials, and sla_prints.

Referenced by set_default_suppressed().

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

◆ set_filament_preset()

void Slic3r::PresetBundle::set_filament_preset ( size_t idx,
const std::string & name )
8731{
8732 if (idx >= filament_presets.size()) {
8733 BOOST_LOG_TRIVIAL(warning) << boost::format("Warning: set_filament_preset out of range %1% - %2%") % idx % filament_presets.size();
8734 return;
8735 }
8737}
static std::string remove_suffix_modified(const std::string &name)
Definition Preset.cpp:516

References filament_presets, Slic3r::Preset::remove_suffix_modified(), and set_filament_preset().

Referenced by Slic3r::anonymous_namespace{PluginHostPresets.cpp}::bind_filament_target(), save_changes_for_preset(), set_filament_preset(), and Slic3r::GUI::Sidebar::update_presets().

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

◆ set_generate_vendor_caches()

void Slic3r::PresetBundle::set_generate_vendor_caches ( bool enable)
inline
235{ m_generate_vendor_caches = enable; }

References m_generate_vendor_caches.

Referenced by anonymous_namespace{profile_include_dump.cpp}::load_vendor().

Here is the caller graph for this function:

◆ set_is_validation_mode()

void Slic3r::PresetBundle::set_is_validation_mode ( bool mode)
inline
466{ validation_mode = mode; }

References validation_mode.

Referenced by anonymous_namespace{profile_include_dump.cpp}::load_vendor(), and anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers().

Here is the caller graph for this function:

◆ set_num_filaments()

void Slic3r::PresetBundle::set_num_filaments ( unsigned int n,
std::string new_col = "" )
4329{
4330 unsigned old_filament_count = this->filament_presets.size();
4331 if (n > old_filament_count && old_filament_count != 0)
4332 filament_presets.resize(n, filament_presets.back());
4333 else {
4334 filament_presets.resize(n);
4335 }
4336 ConfigOptionStrings* filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
4337 ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
4338 ConfigOptionStrings* filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
4340 ConfigOptionInts* filament_nozzle_map = project_config.option<ConfigOptionInts>("filament_nozzle_map");
4341 ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
4342
4343 // Which slots are new is a fact about the arrays below, not about filament_presets:
4344 // on a tool changer, update_multi_material_filament_presets() tops that list up to the tool
4345 // count on its own, so it can already sit at the new size while every array below is still at
4346 // the old one.
4347 const size_t old_slot_count = filament_color->values.size();
4348
4349 filament_color->resize(n);
4350 // Sync filament multi colour
4351 filament_multi_color->values.resize(n);
4352 for (size_t i = 0; i < n; i++) {
4353 filament_multi_color->values[i] = filament_color->values[i];
4354 }
4355 filament_color_type->resize(n);
4356 filament_map->values.resize(n, 1);
4357 filament_nozzle_map->values.resize(n, 0);
4358 filament_volume_map->values.resize(n, static_cast<int>(NozzleVolumeType::nvtStandard));
4359 ams_multi_color_filment.resize(n);
4360
4362
4363 //BBS set new filament color to new_color
4364 if (!new_color.empty()) {
4365 for (size_t i = old_slot_count; i < n; i++) {
4366 filament_color->values[i] = new_color;
4367 filament_multi_color->values[i] = new_color;
4368 filament_color_type->values[i] = "1"; // default color type
4369 }
4370 }
4371
4373}
zaa_minimize_perimeter_height filament_nozzle_map((ConfigOptionInts, filament_map_2))((ConfigOptionStrings
zaa_minimize_perimeter_height filament_map((ConfigOptionInts, filament_volume_map))((ConfigOptionInts

References ams_multi_color_filment, Slic3r::filament_map(), Slic3r::filament_nozzle_map(), filament_presets, Slic3r::nvtStandard, project_config, Slic3r::ConfigOptionVector< T >::resize(), Slic3r::resize_mixed_filament_metadata(), set_num_filaments(), update_multi_material_filament_presets(), and Slic3r::ConfigOptionVector< T >::values.

Referenced by set_num_filaments(), and anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_config().

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

◆ set_vendor_to_validate()

void Slic3r::PresetBundle::set_vendor_to_validate ( std::string vendor)
inline
467{ vendor_to_validate = vendor; }

References vendor_to_validate.

Referenced by anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers().

Here is the caller graph for this function:

◆ setup_directories()

void Slic3r::PresetBundle::setup_directories ( )
812{
813 boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
814 //BBS: change directoties by design
815 std::initializer_list<boost::filesystem::path> paths = {
816 data_dir,
817 data_dir / "ota",
820 // Store the print/filament/printer presets at the same location as the upstream Slic3r.
821 //data_dir / PRESET_SYSTEM_DIR / PRESET_PRINT_NAME,
822 //data_dir / PRESET_SYSTEM_DIR / PRESET_FILAMENT_NAME,
823 //data_dir / PRESET_SYSTEM_DIR / PRESET_PRINTER_NAME
824 };
825 for (const boost::filesystem::path &path : paths) {
826 boost::filesystem::path subdir = path;
827 subdir.make_preferred();
828 if (! boost::filesystem::is_directory(subdir) &&
829 ! boost::filesystem::create_directory(subdir)) {
830 if (boost::filesystem::is_directory(subdir)) {
831 BOOST_LOG_TRIVIAL(warning) << boost::format("creating directory %1% failed, maybe created by other instance, go on!")%subdir.string();
832 }
833 else
834 throw Slic3r::RuntimeError((boost::format(L("Unable to create directory %1%")) % subdir.string()).str());
835 }
836 }
837}

References Slic3r::data_dir(), L, PRESET_SYSTEM_DIR, PRESET_USER_DIR, and setup_directories().

Referenced by setup_directories().

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

◆ support_different_extruders()

bool Slic3r::PresetBundle::support_different_extruders ( ) const
5403{
5404 const Preset& printer_preset = this->printers.get_edited_preset();
5405 int extruder_count;
5406 bool supported = printer_preset.config.support_different_extruders(extruder_count);
5407
5408 return supported;
5409}

References Slic3r::Preset::config, printers, Slic3r::DynamicPrintConfig::support_different_extruders(), and support_different_extruders().

Referenced by support_different_extruders(), and Slic3r::GUI::Sidebar::update_presets().

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

◆ sync_ams_list()

unsigned int Slic3r::PresetBundle::sync_ams_list ( std::vector< std::pair< DynamicPrintConfig *, std::string > > & unknowns,
bool use_map,
std::map< int, AMSMapInfo > & maps,
bool enable_append,
MergeFilamentInfo & merge_info,
bool color_only = false )
4570{
4571 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "use_map:" << use_map << " enable_append:" << enable_append;
4572 std::vector<std::string> ams_filament_presets;
4573 std::vector<std::string> ams_filament_colors;
4574 std::vector<std::string> ams_filament_color_types;
4575 std::vector<AMSMapInfo> ams_array_maps;
4577 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": filament_ams_list size: %1%") % filament_ams_list.size();
4578 struct AmsInfo
4579 {
4580 bool valid{false};
4581 bool is_map{false};
4582 bool is_placeholder{false};
4583 std::string filament_color = "";
4584 std::string filament_color_type = "";
4585 std::string filament_preset = "";
4586 std::vector<std::string> mutli_filament_color;
4587 };
4588 auto is_double_extruder = get_printer_extruder_count() == 2;
4589 std::vector<AmsInfo> ams_infos;
4590 int index = 0;
4591 for (auto &entry : filament_ams_list) {
4592 auto & ams = entry.second;
4593 auto filament_id = ams.opt_string("filament_id", 0u);
4594 auto filament_color = ams.opt_string("filament_colour", 0u);
4595 auto filament_color_type = ams.opt_string("filament_colour_type", 0u);
4596 auto filament_changed = !ams.has("filament_changed") || ams.opt_bool("filament_changed");
4597 auto filament_multi_color = ams.opt<ConfigOptionStrings>("filament_multi_colour")->values;
4598 auto ams_id = ams.opt_string("ams_id", 0u);
4599 auto slot_id = ams.opt_string("slot_id", 0u);
4600 auto is_placeholder = ams.has("filament_slot_placeholder") && ams.opt_bool("filament_slot_placeholder", 0u);
4601 ams_infos.push_back({filament_id.empty() ? false : true, false, is_placeholder, filament_color});
4602 AMSMapInfo temp = {ams_id, slot_id};
4603 ams_array_maps.push_back(temp);
4604 index++;
4605 if (filament_id.empty()) {
4606 if (use_map) {
4607 for (int j = maps.size() - 1; j >= 0; j--) {
4608 if (maps[j].slot_id == slot_id && maps[j].ams_id == ams_id) {
4609 maps.erase(j);
4610 }
4611 }
4612 ams_filament_presets.push_back("Generic PLA");//for unknow matieral
4613 auto default_unknown_color = "#CECECE";
4614 ams_filament_colors.push_back(default_unknown_color);
4615 ams_filament_color_types.push_back("1");
4616 if (filament_multi_color.size() == 0) {
4617 filament_multi_color.push_back(default_unknown_color);
4618 }
4619 ams_multi_color_filment.push_back(filament_multi_color);
4620 } else if (is_placeholder) {
4621 // Orca: push placeholders to keep index alignment with ams_infos
4622 ams_filament_presets.push_back("");
4623 ams_filament_colors.push_back("");
4624 ams_filament_color_types.push_back("");
4625 ams_multi_color_filment.push_back({});
4626 }
4627 continue;
4628 }
4629 if (!filament_changed && this->filament_presets.size() > ams_filament_presets.size()) {
4630 ams_filament_presets.push_back(this->filament_presets[ams_filament_presets.size()]);
4631 ams_filament_colors.push_back(filament_color);
4632 ams_filament_color_types.push_back(filament_color_type);
4633 ams_multi_color_filment.push_back(filament_multi_color);
4634 continue;
4635 }
4636 bool has_type = false;
4637 auto filament_type = ams.opt_string("filament_type", 0u);
4638 auto iter = std::find_if(filaments.begin(), filaments.end(), [this, &filament_id, &has_type, filament_type](auto &f) {
4639 has_type |= f.config.opt_string("filament_type", 0u) == filament_type;
4640 return f.is_compatible && filaments.get_preset_base(f) == &f && f.filament_id == filament_id; });
4641 warn_ambiguous_filament_id_match(filaments, iter, filament_id);
4642 if (iter == filaments.end()) {
4643 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": filament_id %1% not found or system or compatible") % filament_id;
4644 if (!filament_type.empty()) {
4645 auto original_type = filament_type;
4646 filament_type = "Generic " + filament_type;
4647 iter = std::find_if(filaments.begin(), filaments.end(), [&filament_type](auto &f) {
4648 return f.is_compatible && f.is_system
4649 && boost::algorithm::starts_with(f.name, filament_type);
4650 });
4651 if (iter == filaments.end()) {
4652 // Similarity fallback: find a generic preset whose filament_type
4653 // appears as a whole word in the AMS type (e.g. "ASA" in "ASA Sparkle").
4654 auto upper_type = boost::to_upper_copy(original_type);
4655 auto contains_word = [](const std::string& haystack, const std::string& needle) {
4656 auto pos = haystack.find(needle);
4657 while (pos != std::string::npos) {
4658 bool start_ok = (pos == 0 || !std::isalnum(static_cast<unsigned char>(haystack[pos - 1])));
4659 bool end_ok = (pos + needle.size() >= haystack.size() ||
4660 !std::isalnum(static_cast<unsigned char>(haystack[pos + needle.size()])));
4661 if (start_ok && end_ok)
4662 return true;
4663 pos = haystack.find(needle, pos + 1);
4664 }
4665 return false;
4666 };
4667 // Find the longest-matching preset type to prefer e.g. "PA-CF" over "PA".
4668 size_t best_len = 0;
4669 for (auto it = filaments.begin(); it != filaments.end(); ++it) {
4670 if (!it->is_compatible || !it->is_system || !boost::algorithm::starts_with(it->name, "Generic "))
4671 continue;
4672 auto preset_type = boost::to_upper_copy(it->config.opt_string("filament_type", 0u));
4673 if (preset_type.size() > best_len && contains_word(upper_type, preset_type)) {
4674 iter = it;
4675 best_len = preset_type.size();
4676 filament_type = "Generic " + it->config.opt_string("filament_type", 0u);
4677 }
4678 }
4679 }
4680 }
4681 if (iter == filaments.end()) {
4682 // Prefer old selection
4683 if (ams_filament_presets.size() < this->filament_presets.size()) {
4684 ams_filament_presets.push_back(this->filament_presets[ams_filament_presets.size()]);
4685 ams_filament_colors.push_back(filament_color);
4686 ams_filament_color_types.push_back(filament_color_type);
4687 ams_multi_color_filment.push_back(filament_multi_color);
4688 unknowns.emplace_back(&ams, has_type ? L("The filament may not be compatible with the current machine settings. Generic filament presets will be used.") :
4689 L("The filament model is unknown. Still using the previous filament preset."));
4690 continue;
4691 }
4692 iter = std::find_if(filaments.begin(), filaments.end(), [](auto &f) {
4693 return f.is_compatible && f.is_system
4694 && boost::algorithm::starts_with(f.name, "Generic ");
4695 });
4696 if (iter == filaments.end())
4697 iter = std::find_if(filaments.begin(), filaments.end(), [](auto &f) {
4698 return f.is_compatible && f.is_system;
4699 });
4700 if (iter == filaments.end())
4701 continue;
4702 }
4703 unknowns.emplace_back(&ams, boost::algorithm::starts_with(iter->name, filament_type) ?
4704 (has_type ? L("The filament may not be compatible with the current machine settings. Generic filament presets will be used.") :
4705 L("The filament model is unknown. Generic filament presets will be used.")) :
4706 (has_type ? L("The filament may not be compatible with the current machine settings. A random filament preset will be used.") :
4707 L("The filament model is unknown. A random filament preset will be used.")));
4708 filament_id = iter->filament_id;
4709 }
4710 ams_filament_presets.push_back(iter->name);
4711 ams_filament_colors.push_back(filament_color);
4712 ams_filament_color_types.push_back(filament_color_type);
4713 ams_multi_color_filment.push_back(filament_multi_color);
4714 }
4715 if (ams_filament_presets.empty())
4716 return 0;
4717 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "get filament_colour and from config";
4718 ConfigOptionStrings *filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
4719 ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
4721 ConfigOptionInts * filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
4722 // Snapshot and temporarily strip mixed filament slots so AMS sync operates on physical
4723 // filaments only. A mixed slot is virtual and has no tray to sync against; leaving it in
4724 // would let AMS mapping overwrite it and would break the physical-first slot ordering the
4725 // rest of the feature relies on. The slots are re-appended verbatim after the sync.
4726 struct MixedSlotSnapshot {
4727 std::string preset;
4728 std::string color;
4729 std::string color_type;
4730 std::string mixed_components;
4731 std::string mixed_sublayer_ratios;
4732 bool mixed_gradient = false;
4733 std::string mixed_gradient_range;
4734 std::string mixed_gradient_curve;
4735 bool mixed_gradient_per_part = false;
4736 };
4737 std::vector<MixedSlotSnapshot> mixed_snapshots;
4738 auto* is_mixed_opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
4739 auto* mixed_comp_opt = project_config.option<ConfigOptionStrings>("filament_mixed_components");
4740 auto* mixed_ratios_opt = project_config.option<ConfigOptionStrings>("filament_mixed_sublayer_ratios");
4741 auto* mixed_gradient_opt = project_config.option<ConfigOptionBools>("filament_mixed_gradient");
4742 auto* mixed_grad_range_opt = project_config.option<ConfigOptionStrings>("filament_mixed_gradient_range");
4743 auto* mixed_grad_curve_opt = project_config.option<ConfigOptionStrings>("filament_mixed_gradient_curve");
4744 auto* mixed_per_part_opt = project_config.option<ConfigOptionBools>("filament_mixed_gradient_per_part");
4745 if (is_mixed_opt) {
4746 for (size_t i = 0; i < is_mixed_opt->values.size() && i < this->filament_presets.size(); ++i) {
4747 if (!is_mixed_opt->values[i])
4748 continue;
4749 MixedSlotSnapshot snap;
4750 snap.preset = this->filament_presets[i];
4751 snap.color = (i < filament_color->values.size()) ? filament_color->values[i] : "";
4752 snap.color_type = (i < filament_color_type->values.size()) ? filament_color_type->values[i] : "";
4753 if (mixed_comp_opt && i < mixed_comp_opt->values.size()) snap.mixed_components = mixed_comp_opt->values[i];
4754 if (mixed_ratios_opt && i < mixed_ratios_opt->values.size()) snap.mixed_sublayer_ratios = mixed_ratios_opt->values[i];
4755 if (mixed_gradient_opt && i < mixed_gradient_opt->values.size()) snap.mixed_gradient = mixed_gradient_opt->values[i];
4756 if (mixed_grad_range_opt && i < mixed_grad_range_opt->values.size()) snap.mixed_gradient_range = mixed_grad_range_opt->values[i];
4757 if (mixed_grad_curve_opt && i < mixed_grad_curve_opt->values.size()) snap.mixed_gradient_curve = mixed_grad_curve_opt->values[i];
4758 if (mixed_per_part_opt && i < mixed_per_part_opt->values.size()) snap.mixed_gradient_per_part = mixed_per_part_opt->values[i];
4759 mixed_snapshots.push_back(snap);
4760 }
4761 if (!mixed_snapshots.empty()) {
4762 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": stripping " << mixed_snapshots.size() << " mixed filament slot(s) before AMS sync";
4763 size_t phys_count = this->filament_presets.size() - mixed_snapshots.size();
4764 this->filament_presets.resize(phys_count);
4765 filament_color->values.resize(phys_count);
4766 filament_color_type->values.resize(phys_count);
4767 filament_map->values.resize(phys_count, 1);
4768 is_mixed_opt->values.resize(phys_count);
4769 if (mixed_comp_opt) mixed_comp_opt->values.resize(phys_count);
4770 if (mixed_ratios_opt) mixed_ratios_opt->values.resize(phys_count);
4771 if (mixed_gradient_opt) mixed_gradient_opt->values.resize(phys_count);
4772 if (mixed_grad_range_opt) mixed_grad_range_opt->values.resize(phys_count);
4773 if (mixed_grad_curve_opt) mixed_grad_curve_opt->values.resize(phys_count);
4774 if (mixed_per_part_opt) mixed_per_part_opt->values.resize(phys_count);
4775 }
4776 }
4777
4778 if (color_only) {
4779 auto get_map_index = [&ams_infos](const std::vector<AMSMapInfo> &infos, const AMSMapInfo &temp) {
4780 for (int i = 0; i < infos.size(); i++) {
4781 if (infos[i].slot_id == temp.slot_id && infos[i].ams_id == temp.ams_id) {
4782 ams_infos[i].is_map = true;
4783 return i;
4784 }
4785 }
4786 return -1;
4787 };
4788
4789 auto exist_colors = filament_color->values;
4790 std::vector<std::vector<std::string>> exist_multi_color_filment(exist_colors.size());
4791 for (size_t i = 0; i < exist_colors.size(); i++) {
4792 exist_multi_color_filment[i] = {exist_colors[i]};
4793 }
4794
4795 ConfigOptionStrings *project_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
4796 if (project_multi_color) {
4797 for (size_t i = 0; i < std::min(exist_multi_color_filment.size(), project_multi_color->values.size()); i++) {
4798 std::vector<std::string> colors = split_string(project_multi_color->values[i], ' ');
4799 if (!colors.empty()) {
4800 exist_multi_color_filment[i] = colors;
4801 }
4802 }
4803 }
4804
4805 bool mapped_any = false;
4806 if (use_map && !maps.empty()) {
4807 for (size_t i = 0; i < exist_colors.size(); i++) {
4808 if (maps.find(i) == maps.end()) {
4809 continue;
4810 }
4811 int valid_index = get_map_index(ams_array_maps, maps[i]);
4812 if (valid_index >= 0 && valid_index < int(ams_filament_colors.size()) && !ams_filament_colors[valid_index].empty()) {
4813 exist_colors[i] = ams_filament_colors[valid_index];
4814 mapped_any = true;
4815 if (valid_index < int(ams_multi_color_filment.size()) && !ams_multi_color_filment[valid_index].empty()) {
4816 exist_multi_color_filment[i] = ams_multi_color_filment[valid_index];
4817 } else {
4818 exist_multi_color_filment[i] = {ams_filament_colors[valid_index]};
4819 }
4820 }
4821 }
4822 }
4823 // Fallback to index-based color sync if no mapping was applied.
4824 if (!use_map || maps.empty() || !mapped_any) {
4825 size_t sync_count = std::min(exist_colors.size(), ams_filament_colors.size());
4826 for (size_t i = 0; i < sync_count; i++) {
4827 if (ams_filament_colors[i].empty()) {
4828 continue;
4829 }
4830 exist_colors[i] = ams_filament_colors[i];
4831 if (i < ams_multi_color_filment.size() && !ams_multi_color_filment[i].empty()) {
4832 exist_multi_color_filment[i] = ams_multi_color_filment[i];
4833 } else {
4834 exist_multi_color_filment[i] = {ams_filament_colors[i]};
4835 }
4836 }
4837 }
4838
4839 filament_color->values = exist_colors;
4840 ams_multi_color_filment = exist_multi_color_filment;
4841 merge_info.merges.clear();
4842 } else if (use_map) {
4843 auto check_has_merge_info = [](std::map<int, AMSMapInfo> &maps, MergeFilamentInfo &merge_info, int exist_colors_size) {
4844 std::set<int> done;
4845 for (auto it_i = maps.begin(); it_i != maps.end(); ++it_i) {
4846 std::vector<int> same_ams;
4847 same_ams.emplace_back(it_i->first);
4848 for (auto it_j = std::next(it_i); it_j != maps.end(); ++it_j) {
4849 if (done.find(it_j->first) != done.end()) {
4850 continue;
4851 }
4852 if (it_i->second.slot_id == "" || it_i->second.ams_id == ""){
4853 continue;
4854 }
4855 if (it_i->second.slot_id == it_j->second.slot_id && it_i->second.ams_id == it_j->second.ams_id) {
4856 same_ams.emplace_back(it_j->first);
4857 done.insert(it_j->first);
4858 }
4859 }
4860 if (same_ams.size() > 1) {
4861 merge_info.merges.emplace_back(same_ams);
4862 }
4863 }
4864 };
4865 check_has_merge_info(maps, merge_info,filament_color->values.size());
4866 auto get_map_index = [&ams_infos](const std::vector<AMSMapInfo> &infos, const AMSMapInfo &temp) {
4867 for (int i = 0; i < infos.size(); i++) {
4868 if (infos[i].slot_id == temp.slot_id && infos[i].ams_id == temp.ams_id) {
4869 ams_infos[i].is_map = true;
4870 return i;
4871 }
4872 }
4873 return -1;
4874 };
4875 std::vector<AmsInfo> need_append_colors;
4876 auto exist_colors = filament_color->values;
4877 auto exist_color_types = filament_color_type->values;
4878 auto exist_filament_presets = this->filament_presets;
4879 std::vector<std::vector<std::string>> exist_multi_color_filment;
4880 exist_multi_color_filment.resize(exist_colors.size());
4881 for (int i = 0; i < exist_colors.size(); i++) {
4882 exist_multi_color_filment[i] = {exist_colors[i]};
4883 }
4884 for (size_t i = 0; i < exist_colors.size(); i++) {
4885 if (maps.find(i) != maps.end()) {//mapping exist
4886 auto valid_index = get_map_index(ams_array_maps, maps[i]);
4887 if (valid_index >= 0 && valid_index < ams_filament_presets.size()) {
4888 exist_colors[i] = ams_filament_colors[valid_index];
4889 exist_color_types[i] = ams_filament_color_types[valid_index];
4890 exist_filament_presets[i] = ams_filament_presets[valid_index];
4891 exist_multi_color_filment[i] = ams_multi_color_filment[valid_index];
4892 } else {
4893 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "check error: array bound (mapping exist)";
4894 }
4895 }
4896 }
4897 for (size_t i = 0; i < ams_infos.size(); i++) {// check append
4898 if (ams_infos[i].valid) {
4899 if (i >= ams_filament_presets.size()) {
4900 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << "check error: array bound (check append)";
4901 continue;
4902 }
4903 ams_infos[i].filament_preset = ams_filament_presets[i];
4904 ams_infos[i].mutli_filament_color = ams_multi_color_filment[i];
4905 if (!ams_infos[i].is_map) {
4906 need_append_colors.emplace_back(ams_infos[i]);
4907 ams_filament_colors[i] = "";
4908 ams_filament_color_types[i] = "";
4909 ams_filament_presets[i] = "";
4910 ams_multi_color_filment[i] = std::vector<std::string>();
4911 }
4912 }
4913 else {
4914 ams_filament_colors[i] = "";
4915 ams_filament_color_types[i] = "";
4916 ams_filament_presets[i] = "";
4917 ams_multi_color_filment[i] = std::vector<std::string>();
4918 }
4919 }
4920 //delete redundant color
4921 ams_filament_colors.erase(std::remove_if(ams_filament_colors.begin(), ams_filament_colors.end(), [](std::string &value) { return value.empty(); }),
4922 ams_filament_colors.end());
4923 ams_filament_color_types.erase(std::remove_if(ams_filament_color_types.begin(), ams_filament_color_types.end(), [](std::string &value) { return value.empty(); }),
4924 ams_filament_color_types.end());
4925 ams_filament_presets.erase(std::remove_if(ams_filament_presets.begin(), ams_filament_presets.end(), [](std::string &value) { return value.empty(); }),
4926 ams_filament_presets.end());
4928 [](std::vector<std::string> &value) { return value.empty(); }),
4930 if (need_append_colors.size() > 0 && enable_append) {
4931 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "need_append_colors.size() > 0 && enable_append";
4932 auto get_idx_in_array = [](std::vector<std::string> &presets, std::vector<std::string> &colors, const std::string &preset, const std::string &color) -> int {
4933 for (size_t i = 0; i < presets.size(); i++) {
4934 if (presets[i] == preset && colors[i] == color) {
4935 return i;
4936 }
4937 }
4938 return -1;
4939 };
4940 for (size_t i = 0; i < need_append_colors.size(); i++){
4941 if (exist_filament_presets.size() >= MAXIMUM_AMS_SYNC_FILAMENT_NUMBER){
4942 break;
4943 }
4944 auto idx = get_idx_in_array(exist_filament_presets, exist_colors, need_append_colors[i].filament_preset, need_append_colors[i].filament_color);
4945 if (idx >= 0) {
4946 continue;
4947 }
4948 exist_filament_presets.push_back(need_append_colors[i].filament_preset);
4949 exist_colors.push_back(need_append_colors[i].filament_color);
4950 exist_color_types.push_back(need_append_colors[i].filament_color_type);
4951 exist_multi_color_filment.push_back(need_append_colors[i].mutli_filament_color);
4952 }
4953 }
4954 filament_color->values = exist_colors;
4955 filament_color_type->values = exist_color_types;
4956 ams_multi_color_filment = exist_multi_color_filment;
4957 this->filament_presets = exist_filament_presets;
4958 filament_map->values.resize(exist_filament_presets.size(), 1);
4959 filament_volume_map->values.resize(exist_filament_presets.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
4960 }
4961 else {//overwrite;
4962 bool has_placeholders = std::any_of(ams_infos.begin(), ams_infos.end(),
4963 [](const AmsInfo& a) { return a.is_placeholder; });
4964 if (has_placeholders) {
4965 // Orca: merge — keep existing filaments for empty slots
4966 auto exist_colors = filament_color->values;
4967 auto exist_color_types = filament_color_type->values;
4968 auto exist_presets = this->filament_presets;
4969
4970 size_t tray_count = ams_filament_presets.size();
4971 size_t total = std::max(tray_count, exist_presets.size());
4972
4973 std::vector<std::string> result_colors;
4974 std::vector<std::string> result_color_types;
4975 std::vector<std::string> result_presets;
4976 std::vector<std::vector<std::string>> result_multi_colors;
4977
4978 for (size_t i = 0; i < total; i++) {
4979 bool is_loaded = (i < ams_infos.size() && ams_infos[i].valid);
4980
4981 if (is_loaded) {
4982 // Loaded tray: use tray's filament data
4983 result_colors.push_back(ams_filament_colors[i]);
4984 result_color_types.push_back(ams_filament_color_types[i]);
4985 result_presets.push_back(ams_filament_presets[i]);
4986 result_multi_colors.push_back(
4988 : std::vector<std::string>{ams_filament_colors[i]});
4989 } else if (i < exist_presets.size()) {
4990 // Empty tray or beyond tray count: keep existing filament
4991 result_colors.push_back(exist_colors[i]);
4992 result_color_types.push_back(exist_color_types[i]);
4993 result_presets.push_back(exist_presets[i]);
4994 result_multi_colors.push_back({exist_colors[i]});
4995 } else {
4996 // New slot beyond existing count: prefer a generic filament preset
4997 auto it = std::find_if(filaments.begin(), filaments.end(), [](const Preset &f) {
4998 return f.is_compatible && f.is_system
4999 && boost::algorithm::starts_with(f.name, "Generic ");
5000 });
5001 std::string fallback_name = (it != filaments.end()) ? it->name : filaments.first_visible().name;
5002 result_colors.push_back("#CECECE");
5003 result_color_types.push_back("1");
5004 result_presets.push_back(fallback_name);
5005 result_multi_colors.push_back({"#CECECE"});
5006 }
5007 }
5008
5009 filament_color->values = result_colors;
5010 filament_color_type->values = result_color_types;
5011 this->filament_presets = result_presets;
5012 ams_multi_color_filment = result_multi_colors;
5013 filament_map->values.resize(total, 1);
5014 filament_volume_map->values.resize(total, static_cast<int>(NozzleVolumeType::nvtStandard));
5015 } else {
5016 // BBL: existing wholesale replace
5017 filament_color->values = ams_filament_colors;
5018 filament_color_type->values = ams_filament_color_types;
5019 this->filament_presets = ams_filament_presets;
5020 filament_map->values.resize(ams_filament_colors.size(), 1);
5021 filament_volume_map->values.resize(ams_filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
5022 }
5023
5024 auto& print_config = this->prints.get_edited_preset().config;
5025 auto support_filament_opt = print_config.option<ConfigOptionInt>("support_filament");
5026 auto support_interface_filament_opt = print_config.option<ConfigOptionInt>("support_interface_filament");
5027 if (support_filament_opt->value > filament_color_type->values.size())
5028 support_filament_opt->value = 0;
5029
5030 if (support_interface_filament_opt->value > filament_color_type->values.size())
5031 support_interface_filament_opt->value = 0;
5032 }
5033 // Re-append mixed filament slots that were stripped before AMS sync
5034 if (!mixed_snapshots.empty()) {
5035 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": re-appending " << mixed_snapshots.size() << " mixed filament slot(s) after AMS sync";
5036 size_t new_phys_count = this->filament_presets.size();
5037 if (is_mixed_opt) is_mixed_opt->values.resize(new_phys_count, (unsigned char)false);
5038 if (mixed_comp_opt) mixed_comp_opt->values.resize(new_phys_count);
5039 if (mixed_ratios_opt) mixed_ratios_opt->values.resize(new_phys_count);
5040 if (mixed_gradient_opt) mixed_gradient_opt->values.resize(new_phys_count, (unsigned char)false);
5041 if (mixed_grad_range_opt) mixed_grad_range_opt->values.resize(new_phys_count);
5042 if (mixed_grad_curve_opt) mixed_grad_curve_opt->values.resize(new_phys_count);
5043 if (mixed_per_part_opt) mixed_per_part_opt->values.resize(new_phys_count, (unsigned char)false);
5044
5045 for (auto& snap : mixed_snapshots) {
5046 this->filament_presets.push_back(snap.preset);
5047 filament_color->values.push_back(snap.color);
5048 filament_color_type->values.push_back(snap.color_type);
5049 ams_multi_color_filment.push_back({snap.color});
5050 filament_map->values.push_back(1);
5051 if (is_mixed_opt) is_mixed_opt->values.push_back((unsigned char)true);
5052 if (mixed_comp_opt) mixed_comp_opt->values.push_back(snap.mixed_components);
5053 if (mixed_ratios_opt) mixed_ratios_opt->values.push_back(snap.mixed_sublayer_ratios);
5054 if (mixed_gradient_opt) mixed_gradient_opt->values.push_back((unsigned char)snap.mixed_gradient);
5055 if (mixed_grad_range_opt) mixed_grad_range_opt->values.push_back(snap.mixed_gradient_range);
5056 if (mixed_grad_curve_opt) mixed_grad_curve_opt->values.push_back(snap.mixed_gradient_curve);
5057 if (mixed_per_part_opt) mixed_per_part_opt->values.push_back((unsigned char)snap.mixed_gradient_per_part);
5058 }
5059 }
5060
5061 // Update ams_multi_color_filment
5064 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "finish sync ams list";
5065 return this->filament_presets.size();
5066}
void update_filament_multi_color()
Definition PresetBundle.cpp:5068
static constexpr size_t MAXIMUM_AMS_SYNC_FILAMENT_NUMBER
Definition libslic3r.h:75
Slic3r::GradientCurve mixed_gradient_curve(const Slic3r::DynamicPrintConfig &cfg, size_t slot)
Definition FilamentBitmapUtils.cpp:138
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16
std::vector< std::string > split_string(const std::string &str, char delimiter)
Definition utils.cpp:1424

References ams_multi_color_filment, Slic3r::empty(), Slic3r::f(), filament_ams_list, Slic3r::filament_map(), filament_presets, Slic3r::filament_type(), filaments, get_printer_extruder_count(), L, MAXIMUM_AMS_SYNC_FILAMENT_NUMBER, Slic3r::MergeFilamentInfo::merges, Slic3r::nvtStandard, prints, project_config, Slic3r::ConfigOptionVector< T >::size(), Slic3r::ConfigOptionVector< unsigned char >::size(), Slic3r::split_string(), sync_ams_list(), update_filament_multi_color(), update_multi_material_filament_presets(), Slic3r::ConfigOptionSingle< T >::value, Slic3r::ConfigOptionVector< T >::values, Slic3r::ConfigOptionVector< unsigned char >::values, and Slic3r::warn_ambiguous_filament_id_match().

Referenced by sync_ams_list().

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

◆ types_list()

std::array< Preset::Type, 3 > Slic3r::PresetBundle::types_list ( PrinterTechnology pt)
inlinestatic

References Slic3r::ptFFF, Slic3r::Preset::TYPE_FILAMENT, Slic3r::Preset::TYPE_PRINT, Slic3r::Preset::TYPE_PRINTER, Slic3r::Preset::TYPE_SLA_MATERIAL, and Slic3r::Preset::TYPE_SLA_PRINT.

Referenced by resolve_preset_config_type(), and Slic3r::GUI::DiffPresetDialog::types_list().

Here is the caller graph for this function:

◆ update_compatible() [1/2]

void Slic3r::PresetBundle::update_compatible ( PresetSelectCompatibleType select_other_if_incompatible)
inline
661{ this->update_compatible(select_other_if_incompatible, select_other_if_incompatible); }

References update_compatible().

Referenced by update_compatible().

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

◆ update_compatible() [2/2]

void Slic3r::PresetBundle::update_compatible ( PresetSelectCompatibleType select_other_print_if_incompatible,
PresetSelectCompatibleType select_other_filament_if_incompatible )
8518{
8519 const Preset &printer_preset = this->printers.get_edited_preset();
8520 const PresetWithVendorProfile printer_preset_with_vendor_profile = this->printers.get_preset_with_vendor_profile(printer_preset);
8521
8522 class PreferedProfileMatch
8523 {
8524 public:
8525 PreferedProfileMatch(const std::string &prefered_alias, const std::string &prefered_name) :
8526 m_prefered_alias(prefered_alias), m_prefered_name(prefered_name) {}
8527
8528 int operator()(const Preset &preset) const
8529 {
8530 return
8531 preset.is_default || preset.is_external ?
8532 // Don't match any properties of the "-- default --" profile or the external profiles when switching printer profile.
8533 0 :
8534 ! m_prefered_alias.empty() && m_prefered_alias == preset.alias ?
8535 // Matching an alias, always take this preset with priority.
8536 std::numeric_limits<int>::max() :
8537 // Otherwise take the prefered profile, or the first compatible.
8538 preset.name == m_prefered_name;
8539 }
8540
8541 private:
8542 const std::string m_prefered_alias;
8543 const std::string &m_prefered_name;
8544 };
8545
8546 // Matching by the layer height in addition.
8547 class PreferedPrintProfileMatch : public PreferedProfileMatch
8548 {
8549 public:
8550 PreferedPrintProfileMatch(const Preset *preset, const std::string &prefered_name) :
8551 PreferedProfileMatch(preset ? preset->alias : std::string(), prefered_name), m_prefered_layer_height(preset ? preset->config.opt_float("layer_height") : 0) {}
8552
8553 int operator()(const Preset &preset) const
8554 {
8555 // Don't match any properties of the "-- default --" profile or the external profiles when switching printer profile.
8556 if (preset.is_default || preset.is_external)
8557 return 0;
8558 int match_quality = PreferedProfileMatch::operator()(preset);
8559 if (match_quality < std::numeric_limits<int>::max()) {
8560 match_quality += 1;
8561 if (preset.is_visible)
8562 match_quality += 1;
8563 if (m_prefered_layer_height > 0. && std::abs(preset.config.opt_float("layer_height") - m_prefered_layer_height) < 0.0005)
8564 match_quality *= 10;
8565 }
8566 return match_quality;
8567 }
8568
8569 private:
8570 const double m_prefered_layer_height;
8571 };
8572
8573 // Matching by the layer height in addition.
8574 class PreferedFilamentProfileMatch : public PreferedProfileMatch
8575 {
8576 public:
8577 PreferedFilamentProfileMatch(const Preset *preset, const std::string &prefered_name) :
8578 PreferedProfileMatch(preset ? preset->alias : std::string(), prefered_name),
8579 m_prefered_filament_type(preset ? preset->config.opt_string("filament_type", 0) : std::string()) {}
8580
8581 int operator()(const Preset &preset) const
8582 {
8583 // Don't match any properties of the "-- default --" profile or the external profiles when switching printer profile.
8584 if (preset.is_default || preset.is_external)
8585 return 0;
8586 int match_quality = PreferedProfileMatch::operator()(preset);
8587 if (match_quality < std::numeric_limits<int>::max()) {
8588 match_quality += 1;
8589 if(preset.is_visible)
8590 match_quality += 1;
8591 if (! m_prefered_filament_type.empty() && m_prefered_filament_type == preset.config.opt_string("filament_type", 0))
8592 match_quality *= 10;
8593 }
8594 return match_quality;
8595 }
8596
8597 private:
8598 const std::string m_prefered_filament_type;
8599 };
8600
8601 // Matching by the layer height in addition.
8602 class PreferedFilamentsProfileMatch
8603 {
8604 public:
8605 PreferedFilamentsProfileMatch(const Preset *preset, const std::vector<std::string> &prefered_names) :
8606 m_prefered_alias(preset ? preset->alias : std::string()),
8607 m_prefered_filament_type(preset ? preset->config.opt_string("filament_type", 0) : std::string("PLA")), // BBS: default choose PLA
8608 m_prefered_names(prefered_names)
8609 {}
8610
8611 int operator()(const Preset &preset) const
8612 {
8613 // Don't match any properties of the "-- default --" profile or the external profiles when switching printer profile.
8614 if (preset.is_default || preset.is_external || !preset.is_visible)
8615 return 0;
8616 if (! m_prefered_alias.empty() && m_prefered_alias == preset.alias)
8617 // Matching an alias, always take this preset with priority.
8618 return std::numeric_limits<int>::max();
8619 int match_quality = (std::find(m_prefered_names.begin(), m_prefered_names.end(), preset.name) != m_prefered_names.end()) + 1;
8620 if (! m_prefered_filament_type.empty() && m_prefered_filament_type == preset.config.opt_string("filament_type", 0))
8621 match_quality *= 10;
8622 return match_quality;
8623 }
8624
8625 private:
8626 const std::string m_prefered_alias;
8627 const std::string m_prefered_filament_type;
8628 const std::vector<std::string> &m_prefered_names;
8629 };
8630
8631 BOOST_LOG_TRIVIAL(info) << boost::format("update_compatibility for all presets enter, select_other_print_if_incompatible %1%, select_other_filament_if_incompatible %2%")%(int)select_other_print_if_incompatible %(int)select_other_filament_if_incompatible;
8632 switch (printer_preset.printer_technology()) {
8633 case ptFFF:
8634 {
8635 assert(printer_preset.config.has("default_print_profile"));
8636 assert(printer_preset.config.has("default_filament_profile"));
8637 const std::vector<std::string> &prefered_filament_profiles = printer_preset.config.option<ConfigOptionStrings>("default_filament_profile")->values;
8638 this->prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible,
8639 PreferedPrintProfileMatch(this->prints.get_selected_idx() == size_t(-1) ? nullptr : &this->prints.get_edited_preset(), printer_preset.config.opt_string("default_print_profile")));
8640 const PresetWithVendorProfile print_preset_with_vendor_profile = this->prints.get_edited_preset_with_vendor_profile();
8641 // Remember whether the filament profiles were compatible before updating the filament compatibility.
8642 std::vector<char> filament_preset_was_compatible(this->filament_presets.size(), false);
8643 for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
8644 Preset *preset = this->filaments.find_preset(this->filament_presets[idx], false);
8645 filament_preset_was_compatible[idx] = preset != nullptr && preset->is_compatible;
8646 }
8647 // First select a first compatible profile for the preset editor.
8648 BOOST_LOG_TRIVIAL(info) << boost::format("prefered filaments: size %1%, previous selected %2%") %prefered_filament_profiles.size() % this->filaments.get_selected_idx();
8649 if (this->filaments.get_selected_idx() != size_t(-1))
8650 {
8651 BOOST_LOG_TRIVIAL(info) << boost::format("previous selected filament: %1%") % this->filaments.get_edited_preset().name;
8652 }
8653 for (size_t idx = 0; idx < prefered_filament_profiles.size(); ++idx) {
8654 BOOST_LOG_TRIVIAL(info) << boost::format("prefered filament: %1%") % prefered_filament_profiles[idx];
8655 }
8656 this->filaments.update_compatible(printer_preset_with_vendor_profile, &print_preset_with_vendor_profile, select_other_filament_if_incompatible,
8657 PreferedFilamentsProfileMatch(this->filaments.get_selected_idx() == size_t(-1) ? nullptr : &this->filaments.get_edited_preset(), prefered_filament_profiles));
8658 if (select_other_filament_if_incompatible != PresetSelectCompatibleType::Never) {
8659 // Verify validity of the current filament presets.
8660 const std::string prefered_filament_profile = prefered_filament_profiles.empty() ? std::string() : prefered_filament_profiles.front();
8661 if (this->filament_presets.size() == 1) {
8662 // The compatible profile should have been already selected for the preset editor. Just use it.
8663 if (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible.front())
8664 this->filament_presets.front() = this->filaments.get_edited_preset().name;
8665 } else {
8666 for (size_t idx = 0; idx < this->filament_presets.size(); ++ idx) {
8667 std::string &filament_name = this->filament_presets[idx];
8668 Preset *preset = this->filaments.find_preset(filament_name, false);
8669 if (preset == nullptr || (! preset->is_compatible && (select_other_filament_if_incompatible == PresetSelectCompatibleType::Always || filament_preset_was_compatible[idx])))
8670 // Pick a compatible profile. If there are prefered_filament_profiles, use them.
8671 filament_name = this->filaments.first_compatible(
8672 PreferedFilamentProfileMatch(preset,
8673 (idx < prefered_filament_profiles.size()) ? prefered_filament_profiles[idx] : prefered_filament_profile)).name;
8674 }
8675 }
8676 }
8677 break;
8678 }
8679 case ptSLA:
8680 {
8681 assert(printer_preset.config.has("default_sla_print_profile"));
8682 assert(printer_preset.config.has("default_sla_material_profile"));
8683 this->sla_prints.update_compatible(printer_preset_with_vendor_profile, nullptr, select_other_print_if_incompatible,
8684 PreferedPrintProfileMatch(this->sla_prints.get_selected_idx() == size_t(-1) ? nullptr : &this->sla_prints.get_edited_preset(), printer_preset.config.opt_string("default_sla_print_profile")));
8685 const PresetWithVendorProfile sla_print_preset_with_vendor_profile = this->sla_prints.get_edited_preset_with_vendor_profile();
8686 this->sla_materials.update_compatible(printer_preset_with_vendor_profile, &sla_print_preset_with_vendor_profile, select_other_filament_if_incompatible,
8687 PreferedProfileMatch(this->sla_materials.get_selected_idx() == size_t(-1) ? std::string() : this->sla_materials.get_edited_preset().alias, printer_preset.config.opt_string("default_sla_material_profile")));
8688 break;
8689 }
8690 default: break;
8691 }
8692
8693 BOOST_LOG_TRIVIAL(info) << boost::format("update_compatibility for all presets exit");
8694}

References Slic3r::Preset::alias, Slic3r::Always, Slic3r::Preset::config, filament_presets, filaments, Slic3r::ConfigOptionResolver::has(), Slic3r::Preset::is_compatible, Slic3r::Preset::is_default, Slic3r::Preset::is_external, Slic3r::Preset::is_visible, Slic3r::Preset::name, Slic3r::Never, Slic3r::DynamicConfig::opt_float(), Slic3r::DynamicConfig::opt_string(), Slic3r::ConfigBase::option(), Slic3r::Preset::printer_technology(), printers, prints, Slic3r::ptFFF, Slic3r::ptSLA, sla_materials, sla_prints, and update_compatible().

Referenced by Slic3r::GUI::CreatePrinterPresetDialog::create_page2_dialog_buttons(), Slic3r::GUI::ExportConfigsDialog::data_init(), Slic3r::GUI::ExportPresetBundleDialog::InitExportData(), load_config_file_config(), load_presets(), load_selections(), Slic3r::GUI::CreatePrinterPresetDialog::load_system_and_user_presets_with_curr_model(), load_user_presets(), load_user_presets(), reload_local_bundle(), remove_users_preset(), reset_project_embedded_presets(), restore_selection(), save_changes_for_preset(), Slic3r::GUI::Tab::select_preset(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers(), Slic3r::GUI::DiffPresetDialog::update_compatibility(), update_compatible(), update_selections(), and update_subscribed_presets().

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

◆ update_filament_count()

void Slic3r::PresetBundle::update_filament_count ( )
5391{
5392 if (printers.get_edited_preset().printer_technology() != ptFFF)
5393 return;
5394 const size_t min_filaments = min_filament_count();
5395 if (filament_presets.size() >= min_filaments)
5396 return;
5397 filament_presets.resize(min_filaments, filament_presets.empty()
5398 ? filaments.first_visible().name
5399 : filament_presets.back());
5400}
size_t min_filament_count() const
Definition PresetBundle.cpp:5383

References filament_presets, filaments, min_filament_count(), printers, Slic3r::ptFFF, and update_filament_count().

Referenced by load_selections(), update_filament_count(), and update_selections().

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

◆ update_filament_multi_color()

void Slic3r::PresetBundle::update_filament_multi_color ( )
private
5069{
5070 std::vector<std::string> exsit_multi_colors;
5071 for (auto &fil_item : ams_multi_color_filment){
5072 if (fil_item.empty()) break;
5073 if (fil_item.size() == 1)
5074 exsit_multi_colors.push_back(fil_item[0]);
5075 else {
5076 std::string colors = "";
5077 for (auto &color : fil_item){
5078 colors += color + " ";
5079 }
5080 colors.erase(colors.size() - 1); // remove last space
5081 exsit_multi_colors.push_back(colors);
5082 }
5083 }
5084 ConfigOptionStrings *filament_multi_colour = project_config.option<ConfigOptionStrings>("filament_multi_colour");
5085 filament_multi_colour->resize(exsit_multi_colors.size());
5086 filament_multi_colour->values = exsit_multi_colors;
5087}

References ams_multi_color_filment, project_config, Slic3r::ConfigOptionVector< T >::resize(), update_filament_multi_color(), and Slic3r::ConfigOptionVector< T >::values.

Referenced by sync_ams_list(), and update_filament_multi_color().

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

◆ update_multi_material_filament_presets()

void Slic3r::PresetBundle::update_multi_material_filament_presets ( size_t to_delete_filament_id = size_t(-1))
8400{
8401 if (printers.get_edited_preset().printer_technology() != ptFFF)
8402 return;
8403
8404 // Orca: when there are fewer filament presets than the printer runs with (min_filament_count(): one per tool on a
8405 // tool changer, one on a printer sharing its nozzles), append copies of the last one. Padding a shared-nozzle printer
8406 // up to its nozzle count would bring back a filament the user deleted, in this list alone, without the colours and
8407 // maps of the parallel per-filament arrays.
8408 //
8409 // Verify and select the filament presets.
8410 size_t num_filaments = this->filament_presets.size();
8411
8412 const size_t min_filaments = min_filament_count();
8413 if (min_filaments > num_filaments) { // Verify validity of the current filament presets.
8414 for (size_t i = 0; i < this->filament_presets.size(); ++i)
8415 this->filament_presets[i] = this->filaments.find_preset(this->filament_presets[i], true)->name;
8416 // Append the rest of filament presets.
8417 this->filament_presets.resize(min_filaments, this->filament_presets.empty() ? this->filaments.first_visible().name :
8418 this->filament_presets.back());
8419 num_filaments = this->filament_presets.size();
8420 }
8421 if (to_delete_filament_id == -1)
8422 to_delete_filament_id = num_filaments;
8423
8424 // Now verify if flush_volumes_matrix has proper size (it is used to deduce number of extruders in wipe tower generator):
8425 std::vector<double> old_matrix = this->project_config.option<ConfigOptionFloats>("flush_volumes_matrix")->values;
8426 size_t old_nozzle_nums = this->project_config.option<ConfigOptionFloats>("flush_multiplier")->values.size();
8427 size_t old_number_of_filaments = size_t(sqrt(old_matrix.size() / old_nozzle_nums) + EPSILON);
8428 size_t nozzle_nums = get_printer_extruder_count();
8429 if (old_nozzle_nums != nozzle_nums) {
8430 std::vector<double>& f_multiplier = this->project_config.option<ConfigOptionFloats>("flush_multiplier")->values;
8431 f_multiplier.resize(nozzle_nums, 1.f);
8432 }
8433
8434 if (old_matrix.size() != num_filaments * num_filaments * nozzle_nums) {
8435 // First verify if purging volumes presets for each extruder matches number of extruders
8436 std::vector<double>& filaments = this->project_config.option<ConfigOptionFloats>("flush_volumes_vector")->values;
8437 while (filaments.size() < 2* num_filaments) {
8438 filaments.push_back(filaments.size()>1 ? filaments[0] : 140.); // copy the values from the first extruder
8439 filaments.push_back(filaments.size()>1 ? filaments[1] : 140.);
8440 }
8441 while (filaments.size() > 2* num_filaments) {
8442 filaments.pop_back();
8443 filaments.pop_back();
8444 }
8445
8446 size_t old_matrix_size = old_number_of_filaments * old_number_of_filaments;
8447 size_t new_matrix_size = num_filaments * num_filaments;
8448 std::vector<double> new_matrix(new_matrix_size * nozzle_nums, 0);
8449 for (unsigned int i = 0; i < num_filaments; ++i)
8450 for (unsigned int j = 0; j < num_filaments; ++j) {
8451 if (i < old_number_of_filaments && j < old_number_of_filaments) {
8452 unsigned int old_i = i >= to_delete_filament_id ? i + 1 : i;
8453 unsigned int old_j = j >= to_delete_filament_id ? j + 1 : j;
8454 for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) {
8455 // Orca: only copy from old_matrix when the old layout actually has data
8456 // for this nozzle slot; otherwise initialize from the per-filament
8457 // flush volumes the same way the (i,j) out-of-range branch does.
8458 if (nozzle_id < old_nozzle_nums) {
8459 new_matrix[i * num_filaments + j + new_matrix_size * nozzle_id] = old_matrix[old_i * old_number_of_filaments + old_j + old_matrix_size * nozzle_id];
8460 } else {
8461 new_matrix[i * num_filaments + j + new_matrix_size * nozzle_id] = (i == j ? 0. : filaments[2 * i] + filaments[2 * j + 1]);
8462 }
8463 }
8464 } else {
8465 for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) {
8466 new_matrix[i * num_filaments + j + new_matrix_size * nozzle_id] = (i == j ? 0. : filaments[2 * i] + filaments[2 * j + 1]);
8467 }
8468 }
8469 }
8470 this->project_config.option<ConfigOptionFloats>("flush_volumes_matrix")->values = new_matrix;
8471 }
8472}
#define EPSILON
Definition ColorUtils.cpp:64

References EPSILON, filament_presets, filaments, get_printer_extruder_count(), min_filament_count(), printers, project_config, Slic3r::ptFFF, and update_multi_material_filament_presets().

Referenced by load_config_file_config(), load_presets(), load_selections(), load_user_presets(), load_user_presets(), on_extruders_count_changed(), reload_local_bundle(), restore_selection(), set_num_filaments(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers(), sync_ams_list(), update_multi_material_filament_presets(), update_num_filaments(), update_selections(), and update_subscribed_presets().

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

◆ update_num_filaments()

void Slic3r::PresetBundle::update_num_filaments ( unsigned int to_del_flament_id)
4376{
4377 unsigned old_filament_count = this->filament_presets.size();
4378 assert(to_del_flament_id < old_filament_count);
4379 filament_presets.erase(filament_presets.begin() + to_del_flament_id);
4380
4381 // update edited_preset
4382 {
4383 Preset& edited_preset = filaments.get_edited_preset();
4384 bool edited_preset_deleted = true;
4385 for (std::string filament_preset_name : filament_presets) {
4386 if (filament_preset_name == edited_preset.name) {
4387 edited_preset_deleted = false;
4388 }
4389 }
4390 if (edited_preset_deleted) {
4391 filaments.select_preset_by_name(filament_presets.front(), false);
4392 }
4393 }
4394
4395 ConfigOptionStrings *filament_color = project_config.option<ConfigOptionStrings>("filament_colour");
4396 ConfigOptionStrings *filament_multi_color = project_config.option<ConfigOptionStrings>("filament_multi_colour");
4397 ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
4399 ConfigOptionInts* filament_nozzle_map = project_config.option<ConfigOptionInts>("filament_nozzle_map");
4400 ConfigOptionInts* filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
4401 if (filament_color->values.size() > to_del_flament_id) {
4402 filament_color->values.erase(filament_color->values.begin() + to_del_flament_id);
4403 if (filament_map->values.size() > to_del_flament_id) {
4404 filament_map->values.erase(filament_map->values.begin() + to_del_flament_id);
4405 }
4406 if (filament_nozzle_map->values.size() > to_del_flament_id) {
4407 filament_nozzle_map->values.erase(filament_nozzle_map->values.begin() + to_del_flament_id);
4408 }
4409 if (filament_volume_map->values.size() > to_del_flament_id) {
4410 filament_volume_map->values.erase(filament_volume_map->values.begin() + to_del_flament_id);
4411 }
4412 }
4413 else {
4414 filament_color->values.resize(to_del_flament_id);
4415 filament_map->values.resize(to_del_flament_id, 1);
4416 filament_nozzle_map->values.resize(to_del_flament_id, 0);
4417 filament_volume_map->values.resize(to_del_flament_id, static_cast<int>(NozzleVolumeType::nvtStandard));
4418 }
4419
4420 // lambda function to erase or resize the container
4421 auto erase_or_resize = [to_del_flament_id](auto& container) {
4422 if (container.size() > to_del_flament_id) {
4423 container.erase(container.begin() + to_del_flament_id);
4424 } else {
4425 container.resize(to_del_flament_id);
4426 }
4427 };
4428
4429 erase_or_resize(filament_multi_color->values);
4430 erase_or_resize(filament_color_type->values);
4431 erase_or_resize(ams_multi_color_filment);
4432
4433 // Mixed-color metadata. Component IDs reference other slots by 1-based index, so a deleted
4434 // *physical* filament must be remapped out of every mix before the arrays themselves shrink.
4435 // Deleting a mixed slot needs no remap (nothing references a mixed slot as a component).
4436 {
4437 auto *is_mixed_opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
4438 auto *comp_opt = project_config.option<ConfigOptionStrings>("filament_mixed_components");
4439 if (is_mixed_opt && comp_opt) {
4440 bool del_is_physical = (to_del_flament_id >= is_mixed_opt->values.size()
4441 || !is_mixed_opt->values[to_del_flament_id]);
4442 if (del_is_physical)
4443 remap_mixed_components_on_delete(is_mixed_opt->values, comp_opt->values,
4444 to_del_flament_id + 1);
4445 }
4446 if (is_mixed_opt)
4447 erase_or_resize(is_mixed_opt->values);
4448 if (comp_opt)
4449 erase_or_resize(comp_opt->values);
4450 }
4451 if (auto *opt = project_config.option<ConfigOptionStrings>("filament_mixed_sublayer_ratios"))
4452 erase_or_resize(opt->values);
4453 if (auto *opt = project_config.option<ConfigOptionBools>("filament_mixed_gradient"))
4454 erase_or_resize(opt->values);
4455 if (auto *opt = project_config.option<ConfigOptionStrings>("filament_mixed_gradient_range"))
4456 erase_or_resize(opt->values);
4457 if (auto *opt = project_config.option<ConfigOptionStrings>("filament_mixed_gradient_curve"))
4458 erase_or_resize(opt->values);
4459 if (auto *opt = project_config.option<ConfigOptionBools>("filament_mixed_gradient_per_part"))
4460 erase_or_resize(opt->values);
4461
4462 update_multi_material_filament_presets(to_del_flament_id);
4463}
void remap_mixed_components_on_delete(const std::vector< unsigned char > &is_mixed, std::vector< std::string > &comp_strs, unsigned int del_1based)
Definition FilamentMixer.cpp:540

References ams_multi_color_filment, Slic3r::filament_map(), Slic3r::filament_nozzle_map(), filament_presets, filaments, Slic3r::Preset::name, Slic3r::nvtStandard, project_config, Slic3r::remap_mixed_components_on_delete(), update_multi_material_filament_presets(), update_num_filaments(), Slic3r::ConfigOptionVector< T >::values, and Slic3r::ConfigOptionVector< unsigned char >::values.

Referenced by update_num_filaments().

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

◆ update_selections()

void Slic3r::PresetBundle::update_selections ( AppConfig & config)
3915{
3916 std::string initial_printer_profile_name = printers.get_selected_preset_name();
3917 // Orca: load from orca_presets
3918 std::string initial_print_profile_name = config.get_printer_setting(initial_printer_profile_name, PRESET_PRINT_NAME);
3919 std::string initial_filament_profile_name = config.get_printer_setting(initial_printer_profile_name, PRESET_FILAMENT_NAME);
3920
3921 // Selects the profiles, which were selected at the last application close.
3922 prints.select_preset_by_name_strict(initial_print_profile_name);
3923 filaments.select_preset_by_name_strict(initial_filament_profile_name);
3924
3925 // Load the names of the other filament profiles selected for a multi-material printer.
3926 // Load it even if the current printer technology is SLA.
3927 // The possibly excessive filament names will be later removed with this->update_multi_material_filament_presets()
3928 // once the FFF technology gets selected.
3929 this->filament_presets = { filaments.get_selected_preset_name() };
3930 for (unsigned int i = 1; i < 1000; ++ i) {
3931 char name[64];
3932 sprintf(name, "filament_%02u", i);
3933 auto f_name = config.get_printer_setting(initial_printer_profile_name, name);
3934 if (f_name.empty())
3935 break;
3936 this->filament_presets.emplace_back(remove_ini_suffix(f_name));
3937 }
3938
3940
3941 std::vector<std::string> filament_colors;
3942 auto f_colors = config.get_printer_setting(initial_printer_profile_name, "filament_colors");
3943 if (!f_colors.empty()) {
3944 boost::algorithm::split(filament_colors, f_colors, boost::algorithm::is_any_of(","));
3945 }
3946 filament_colors.resize(filament_presets.size(), "#26A69A");
3947 project_config.option<ConfigOptionStrings>("filament_colour")->values = filament_colors;
3948
3949 std::vector<std::string> multi_filament_colors;
3950 if (config.has_printer_setting(initial_printer_profile_name, "filament_multi_colors")) {
3951 boost::algorithm::split(multi_filament_colors, config.get_printer_setting(initial_printer_profile_name, "filament_multi_colors"), boost::algorithm::is_any_of(","));
3952 }
3953 if (multi_filament_colors.size() == 0) project_config.option<ConfigOptionStrings>("filament_multi_colour")->values = filament_colors;
3954 else project_config.option<ConfigOptionStrings>("filament_multi_colour")->values = multi_filament_colors;
3955
3956 std::vector<std::string> filament_color_types;
3957 if (config.has_printer_setting(initial_printer_profile_name, "filament_color_types")) {
3958 boost::algorithm::split(filament_color_types, config.get_printer_setting(initial_printer_profile_name, "filament_color_types"), boost::algorithm::is_any_of(","));
3959 }
3960 filament_color_types.resize(filament_presets.size(), "1");
3961 project_config.option<ConfigOptionStrings>("filament_colour_type")->values = filament_color_types;
3962
3963 std::vector<int> filament_maps(filament_colors.size(), 1);
3964 project_config.option<ConfigOptionInts>("filament_map")->values = filament_maps;
3965
3966 std::vector<int> filament_nozzle_maps(filament_colors.size(), 0);
3967 project_config.option<ConfigOptionInts>("filament_nozzle_map")->values = filament_nozzle_maps;
3968
3969 std::vector<int> filament_volume_maps(filament_colors.size(), static_cast<int>(NozzleVolumeType::nvtStandard));
3970 project_config.option<ConfigOptionInts>("filament_volume_map")->values = filament_volume_maps;
3971
3972 std::vector<std::string> extruder_ams_count_str;
3973 if (config.has_printer_setting(initial_printer_profile_name, "extruder_ams_count")) {
3974 boost::algorithm::split(extruder_ams_count_str, config.get_printer_setting(initial_printer_profile_name, "extruder_ams_count"), boost::algorithm::is_any_of(","));
3975 }
3976 this->extruder_ams_counts = get_extruder_ams_count(extruder_ams_count_str);
3977
3978 std::vector<std::string> matrix;
3979 if (config.has_printer_setting(initial_printer_profile_name, "flush_volumes_matrix")) {
3980 boost::algorithm::split(matrix, config.get_printer_setting(initial_printer_profile_name, "flush_volumes_matrix"), boost::algorithm::is_any_of("|"));
3981 auto flush_volumes_matrix = matrix | boost::adaptors::transformed(boost::lexical_cast<double, std::string>);
3982 project_config.option<ConfigOptionFloats>("flush_volumes_matrix")->values = std::vector<double>(flush_volumes_matrix.begin(), flush_volumes_matrix.end());
3983 }
3984 if (config.has_printer_setting(initial_printer_profile_name, "flush_volumes_vector")) {
3985 boost::algorithm::split(matrix, config.get_printer_setting(initial_printer_profile_name, "flush_volumes_vector"), boost::algorithm::is_any_of("|"));
3986 auto flush_volumes_vector = matrix | boost::adaptors::transformed(boost::lexical_cast<double, std::string>);
3987 project_config.option<ConfigOptionFloats>("flush_volumes_vector")->values = std::vector<double>(flush_volumes_vector.begin(), flush_volumes_vector.end());
3988 }
3989 if (config.has_printer_setting(initial_printer_profile_name, "flush_multiplier")) {
3990 boost::algorithm::split(matrix, config.get_printer_setting(initial_printer_profile_name, "flush_multiplier"), boost::algorithm::is_any_of("|"));
3991 auto flush_multipliers = matrix | boost::adaptors::transformed(boost::lexical_cast<double, std::string>);
3992 project_config.option<ConfigOptionFloats>("flush_multiplier")->values = std::vector<double>(flush_multipliers.begin(), flush_multipliers.end());
3993 }
3994 // No global fallback here: on a printer change the legacy shared keys describe another
3995 // printer's filament list, so absent per-printer keys must clear the mixes, not revive them.
3996 load_mixed_filament_settings(project_config, config, initial_printer_profile_name, filament_presets.size(), false);
3997
3998 // Update visibility of presets based on their compatibility with the active printer.
3999 // Always try to select a compatible print and filament preset to the current printer preset,
4000 // as the application may have been closed with an active "external" preset, which does not
4001 // exist.
4004
4005 std::string first_visible_filament_name;
4006 for (auto & fp : filament_presets) {
4007 // Orca: also match the ORCA_DEFAULT_FILAMENT_PLACEHOLDER placeholder. update_compatible_internal
4008 // iterates from m_num_default_presets, so the placeholder's is_compatible flag
4009 // stays true and the not-found/visible/compatible predicate alone would miss it.
4010 if (auto it = filaments.find_preset_internal(fp); fp == ORCA_DEFAULT_FILAMENT_PLACEHOLDER || it == filaments.end() || !it->is_visible || !it->is_compatible) {
4011 if (first_visible_filament_name.empty())
4012 first_visible_filament_name = filaments.first_compatible().name;
4013 fp = first_visible_filament_name;
4014 }
4015 }
4016
4017}

References Slic3r::Always, extruder_ams_counts, filament_presets, filaments, Slic3r::flush_volumes_matrix(), Slic3r::get_extruder_ams_count(), Slic3r::AppConfig::get_printer_setting(), Slic3r::AppConfig::has_printer_setting(), Slic3r::load_mixed_filament_settings(), Slic3r::nvtStandard, ORCA_DEFAULT_FILAMENT_PLACEHOLDER, PRESET_FILAMENT_NAME, PRESET_PRINT_NAME, printers, prints, project_config, Slic3r::remove_ini_suffix(), Slic3r::ConfigOptionVector< T >::resize(), update_compatible(), update_filament_count(), update_multi_material_filament_presets(), and update_selections().

Referenced by update_selections().

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

◆ update_subscribed_presets()

PresetsConfigSubstitutions Slic3r::PresetBundle::update_subscribed_presets ( AppConfig & config,
const std::map< std::string, std::map< std::string, std::string > > & bundle_presets,
const BundleMetadata & remote_metadata,
ForwardCompatibilitySubstitutionRule rule )
2745{
2746 PresetsConfigSubstitutions substitutions;
2747 std::string errors_cumulative;
2748 bool process_added = false, filament_added = false, machine_added = false;
2749
2750 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " enter, substitution_rule " << substitution_rule << ", bundle_id: " << remote_metadata.id << ", preset count: " << bundle_presets.size();
2751
2752 BundleMetadata merged_metadata;
2753 auto existing_it = bundles.m_bundles.find(remote_metadata.id);
2754 if (existing_it != bundles.m_bundles.end()) {
2755 merged_metadata = existing_it->second;
2756 } else {
2757 merged_metadata.imported_time = std::time(nullptr);
2758 }
2759
2760 merged_metadata.id = remote_metadata.id;
2761 merged_metadata.name = remote_metadata.name;
2762 merged_metadata.version = remote_metadata.version;
2763 merged_metadata.description = remote_metadata.description;
2764 merged_metadata.author = remote_metadata.author;
2765 merged_metadata.updated_time = remote_metadata.updated_time;
2766 merged_metadata.bundle_type = BundleType::Subscribed;
2767 merged_metadata.is_subscribed = true;
2768 merged_metadata.update_available = false;
2769 merged_metadata.unauthorized = false;
2770
2771 const PresetOrigin subscribed_origin(PresetOrigin::Kind::SubscribedBundle, remote_metadata.id);
2772
2773 std::unordered_set<std::string> remote_prints;
2774 std::unordered_set<std::string> remote_filaments;
2775 std::unordered_set<std::string> remote_printers;
2776
2777 for (const auto& [preset_name, value_map] : bundle_presets) {
2778 auto type_iter = value_map.find(BBL_JSON_KEY_TYPE);
2779 if (type_iter == value_map.end()) {
2780 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " cannot find type for preset " << preset_name;
2781 continue;
2782 }
2783
2784 const std::string subscribed_name = get_preset_canonical_name(preset_name, subscribed_origin);
2785 if (type_iter->second == PRESET_IOT_PRINT_TYPE)
2786 remote_prints.insert(subscribed_name);
2787 else if (type_iter->second == PRESET_IOT_FILAMENT_TYPE)
2788 remote_filaments.insert(subscribed_name);
2789 else if (type_iter->second == PRESET_IOT_PRINTER_TYPE)
2790 remote_printers.insert(subscribed_name);
2791 }
2792
2793 auto remove_obsolete_bundle_presets =
2794 [&](PresetCollection& collection, const std::unordered_set<std::string>& remote_names, const char* type_name) -> int {
2795 int removed_count = 0;
2796 std::vector<std::string> to_delete;
2797
2798 for (const Preset& preset : collection.get_presets()) {
2799 if (!preset.is_from_bundle() || preset.bundle_id != remote_metadata.id)
2800 continue;
2801
2802 if (remote_names.find(preset.name) == remote_names.end())
2803 to_delete.push_back(preset.name);
2804 }
2805
2806 for (const std::string& preset_name : to_delete) {
2807 if (collection.delete_preset(preset_name, true)) {
2808 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": " << type_name << " preset '" << preset_name << "' no longer in remote bundle, deleted";
2809 ++removed_count;
2810 } else {
2811 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": failed to delete obsolete " << type_name << " preset '" << preset_name << "'";
2812 }
2813 }
2814
2815 return removed_count;
2816 };
2817
2818 int total_removed = 0;
2819 total_removed += remove_obsolete_bundle_presets(this->prints, remote_prints, "print");
2820 total_removed += remove_obsolete_bundle_presets(this->filaments, remote_filaments, "filament");
2821 total_removed += remove_obsolete_bundle_presets(this->printers, remote_printers, "printer");
2822
2823 if (total_removed > 0) {
2824 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": deleted " << total_removed << " obsolete presets from bundle " << remote_metadata.id;
2825 }
2826
2827 // Get current user ID for path construction
2828 std::string user_id = config.get("preset_folder");
2829 if (user_id.empty()) user_id = DEFAULT_USER_FOLDER_NAME;
2830
2831 // Create the subscribed directory base path
2832 boost::filesystem::path user_folder(Slic3r::data_dir() + "/" + PRESET_USER_DIR);
2833 boost::filesystem::path subscribed_base(user_folder / user_id / PRESET_SUBSCRIBED_DIR);
2834
2835 // Ensure subscribed directory exists
2836 boost::system::error_code ec;
2837 if (!boost::filesystem::exists(subscribed_base))
2838 boost::filesystem::create_directories(subscribed_base, ec);
2839 if (ec) {
2840 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed to create subscribed directory: " << subscribed_base.string() << " error: " << ec.message();
2841 return substitutions;
2842 }
2843
2844 dir_user_presets_subscribed = subscribed_base;
2845
2846 // Create bundle directory
2847 boost::filesystem::path bundle_dir(subscribed_base / remote_metadata.id);
2848 if (!boost::filesystem::exists(bundle_dir))
2849 boost::filesystem::create_directories(bundle_dir, ec);
2850 if (ec) {
2851 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed to create bundle directory: " << bundle_dir.string() << " error: " << ec.message();
2852 return substitutions;
2853 }
2854
2855 merged_metadata.print_presets.clear();
2856 merged_metadata.filament_presets.clear();
2857 merged_metadata.printer_presets.clear();
2858
2859 // Load each preset from the bundle and save to disk
2860 for (const auto& preset_entry : bundle_presets) {
2861 const std::string& preset_name = preset_entry.first;
2862 const std::string subscribed_name = get_preset_canonical_name(preset_name, subscribed_origin);
2863 std::map<std::string, std::string> value_map = preset_entry.second; // Make a copy since we might modify it
2864
2865 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " importing preset: " << preset_name << " from bundle: " << remote_metadata.id;
2866
2867 // Get the type first
2868 auto type_iter = value_map.find(BBL_JSON_KEY_TYPE);
2869 if (type_iter == value_map.end()) {
2870 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " cannot find type for preset " << preset_name;
2871 continue;
2872 }
2873
2874 // If this preset inherits from another preset inside the same bundle, rewrite the
2875 // reference to the canonical (bundle-prefixed) name so the lookup matches the stored identity.
2876 auto inherits_iter = value_map.find(BBL_JSON_KEY_INHERITS);
2877 if (inherits_iter != value_map.end() && !inherits_iter->second.empty() && bundle_presets.find(inherits_iter->second) != bundle_presets.end())
2878 inherits_iter->second = get_preset_canonical_name(inherits_iter->second, subscribed_origin);
2879
2880 try {
2881 PresetCollection* preset_collection = nullptr;
2882 std::string type_subdir;
2883 bool preset_added = false;
2884
2885 if (type_iter->second == PRESET_IOT_PRINT_TYPE) {
2886 preset_collection = &(this->prints);
2887 type_subdir = PRESET_PRINT_NAME;
2888 preset_added = preset_collection->load_user_preset(preset_name, value_map, substitutions, substitution_rule, subscribed_origin);
2889 process_added |= preset_added;
2890 }
2891 else if (type_iter->second == PRESET_IOT_FILAMENT_TYPE) {
2892 preset_collection = &(this->filaments);
2893 type_subdir = PRESET_FILAMENT_NAME;
2894 preset_added = preset_collection->load_user_preset(preset_name, value_map, substitutions, substitution_rule, subscribed_origin);
2895 filament_added |= preset_added;
2896 }
2897 else if (type_iter->second == PRESET_IOT_PRINTER_TYPE) {
2898 preset_collection = &(this->printers);
2899 type_subdir = PRESET_PRINTER_NAME;
2900 preset_added = preset_collection->load_user_preset(preset_name, value_map, substitutions, substitution_rule, subscribed_origin);
2901 machine_added |= preset_added;
2902 }
2903 else {
2904 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " invalid type " << type_iter->second << " for preset " << preset_name;
2905 continue;
2906 }
2907
2908 // If preset was loaded/added, save it to the bundle directory.
2909 // Find the preset that was just loaded using its canonical (bundle-prefixed) name.
2910 Preset* preset = preset_collection->find_preset(subscribed_name, false, true);
2911 if (preset) {
2912 // Use helper function to save preset to bundle directory
2913 if (!save_preset_to_bundle_dir(*preset, preset_collection, remote_metadata.id, type_subdir, bundle_dir.string())) {
2914 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed to save preset " << preset_name << " to bundle directory";
2915 continue;
2916 }
2917
2918 if (type_iter->second == PRESET_IOT_PRINT_TYPE)
2919 merged_metadata.print_presets.push_back(preset->name);
2920 else if (type_iter->second == PRESET_IOT_FILAMENT_TYPE)
2921 merged_metadata.filament_presets.push_back(preset->name);
2922 else if (type_iter->second == PRESET_IOT_PRINTER_TYPE)
2923 merged_metadata.printer_presets.push_back(preset->name);
2924 }
2925 }
2926 catch (const std::runtime_error& err) {
2927 errors_cumulative += err.what();
2928 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " error importing preset " << preset_name << ": " << err.what();
2929 }
2930 }
2931
2932 boost::filesystem::path metadata_save_path = bundle_dir / PRESET_BUNDLE_METADATA;
2933 merged_metadata.path = metadata_save_path.string();
2934 bundles.m_bundles[remote_metadata.id] = merged_metadata;
2935
2936 if (bundles.m_bundles[remote_metadata.id].save_to_json(metadata_save_path.string())) {
2937 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " saved bundle metadata to: " << metadata_save_path.string();
2938 } else {
2939 BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " failed to save bundle metadata to: " << metadata_save_path.string();
2940 }
2941
2942 // Rewrite renamed compatible references in synced user presets before compatibility is evaluated.
2944
2947
2949
2950 if (!errors_cumulative.empty())
2951 throw Slic3r::RuntimeError(errors_cumulative);
2952
2953 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << " finished, process_added " << process_added << ", filament_added " << filament_added << ", machine_added " << machine_added;
2954 return substitutions;
2955}
boost::filesystem::path dir_user_presets_subscribed
Definition PresetBundle.hpp:534

References Slic3r::BundleMetadata::author, BBL_JSON_KEY_INHERITS, BBL_JSON_KEY_TYPE, Slic3r::Preset::bundle_id, Slic3r::BundleMetadata::bundle_type, bundles, Slic3r::data_dir(), DEFAULT_USER_FOLDER_NAME, Slic3r::PresetCollection::delete_preset(), Slic3r::BundleMetadata::description, dir_user_presets_subscribed, Slic3r::BundleMetadata::filament_presets, filaments, Slic3r::PresetCollection::find_preset(), Slic3r::AppConfig::get(), Slic3r::get_preset_canonical_name(), Slic3r::PresetCollection::get_presets(), Slic3r::BundleMetadata::id, Slic3r::BundleMetadata::imported_time, Slic3r::Preset::is_from_bundle(), Slic3r::BundleMetadata::is_subscribed, Slic3r::PresetCollection::load_user_preset(), Slic3r::BundleMetadata::name, Slic3r::Preset::name, Slic3r::Never, normalize_compatible_presets(), Slic3r::BundleMetadata::path, PRESET_BUNDLE_METADATA, PRESET_FILAMENT_NAME, PRESET_IOT_FILAMENT_TYPE, PRESET_IOT_PRINT_TYPE, PRESET_IOT_PRINTER_TYPE, PRESET_PRINT_NAME, PRESET_PRINTER_NAME, PRESET_SUBSCRIBED_DIR, PRESET_USER_DIR, Slic3r::BundleMetadata::print_presets, Slic3r::BundleMetadata::printer_presets, printers, prints, save_preset_to_bundle_dir(), set_calibrate_printer(), Slic3r::Subscribed, Slic3r::PresetOrigin::SubscribedBundle, Slic3r::BundleMetadata::unauthorized, Slic3r::BundleMetadata::update_available, update_compatible(), update_multi_material_filament_presets(), update_subscribed_presets(), Slic3r::BundleMetadata::updated_time, and Slic3r::BundleMetadata::version.

Referenced by update_subscribed_presets().

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

◆ update_system_maps()

void Slic3r::PresetBundle::update_system_maps ( )
private
3658{
3659 this->prints .update_map_system_profile_renamed();
3660 this->sla_prints .update_map_system_profile_renamed();
3661 this->filaments .update_map_system_profile_renamed();
3662 this->sla_materials.update_map_system_profile_renamed();
3663 this->printers .update_map_system_profile_renamed();
3664
3665 this->prints .update_map_alias_to_profile_name();
3666 this->sla_prints .update_map_alias_to_profile_name();
3667 this->filaments .update_map_alias_to_profile_name();
3668 this->sla_materials.update_map_alias_to_profile_name();
3669 this->printers .update_map_alias_to_profile_name();
3670
3671 this->filaments.update_library_profile_excluded_from();
3672}

References filaments, printers, prints, sla_materials, sla_prints, and update_system_maps().

Referenced by load_installed_printers(), load_system_presets_from_json(), and update_system_maps().

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

◆ update_system_preset_setting_ids()

void Slic3r::PresetBundle::update_system_preset_setting_ids ( std::map< std::string, std::map< std::string, std::string > > & system_presets)
3070{
3071 for (auto iterator: system_presets)
3072 {
3073 std::string name = iterator.first;
3074 std::map<std::string, std::string>& value_map = iterator.second;
3075 //get the type first
3076 std::map<std::string, std::string>::iterator type_iter = value_map.find(BBL_JSON_KEY_TYPE);
3077 if (type_iter == value_map.end()) {
3078 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(" can not find type for setting %1%")%name;
3079 continue;
3080 }
3081 PresetCollection *preset_collection = nullptr;
3082 if (type_iter->second == PRESET_IOT_PRINTER_TYPE) {
3083 preset_collection = &(this->printers);
3084 }
3085 else if (type_iter->second == PRESET_IOT_PRINTER_TYPE) {
3086 preset_collection = &(this->printers);
3087 }
3088 else if (type_iter->second == PRESET_IOT_PRINTER_TYPE) {
3089 preset_collection = &(this->printers);
3090 }
3091 else {
3092 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("invalid type %1% for setting %2%") %type_iter->second %name;
3093 continue;
3094 }
3095 std::string setting_id;
3096 if (value_map.count(BBL_JSON_KEY_SETTING_ID) > 0)
3097 setting_id = value_map[BBL_JSON_KEY_SETTING_ID];
3098 else {
3099 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(" can not find setting_id for setting %1%")%name;
3100 continue;
3101 }
3102 Preset* preset = preset_collection->find_preset(name, false, true);
3103 if (preset) {
3104 if (!preset->setting_id.empty() && (preset->setting_id.compare(setting_id) != 0)) {
3105 ++m_errors;
3106 BOOST_LOG_TRIVIAL(error) << boost::format("name %1%, local setting_id %2% is different with remote id %3%")
3107 %preset->name %preset->setting_id %setting_id;
3108 }
3109 else if (preset->setting_id.empty())
3110 preset->setting_id = setting_id;
3111 }
3112 else {
3113 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("can not find setting %1% in system presets, type %2%") %name %type_iter->second;
3114 continue;
3115 }
3116 }
3117 return;
3118}

References BBL_JSON_KEY_SETTING_ID, BBL_JSON_KEY_TYPE, Slic3r::PresetCollection::find_preset(), m_errors, Slic3r::Preset::name, PRESET_IOT_PRINTER_TYPE, printers, Slic3r::Preset::setting_id, and update_system_preset_setting_ids().

Referenced by update_system_preset_setting_ids().

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

◆ update_user_presets_directory()

void Slic3r::PresetBundle::update_user_presets_directory ( const std::string preset_folder)
3035{
3036 //BBS: change directory by design
3037 const std::string dir_user_presets = data_dir() + "/" + PRESET_USER_DIR + "/"+ preset_folder;
3038
3039 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" enter, update directory to %1%")%dir_user_presets;
3040
3041 fs::path user_folder(data_dir() + "/" + PRESET_USER_DIR);
3042 if (!fs::exists(user_folder))
3043 fs::create_directory(user_folder);
3044
3045 fs::path folder(dir_user_presets);
3046 if (!fs::exists(folder))
3047 fs::create_directory(folder);
3048
3049 this->prints.update_user_presets_directory(dir_user_presets, PRESET_PRINT_NAME);
3050 this->filaments.update_user_presets_directory(dir_user_presets, PRESET_FILAMENT_NAME);
3051 this->printers.update_user_presets_directory(dir_user_presets, PRESET_PRINTER_NAME);
3052 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(" finished");
3053}

References Slic3r::data_dir(), filaments, PRESET_FILAMENT_NAME, PRESET_PRINT_NAME, PRESET_PRINTER_NAME, PRESET_USER_DIR, printers, prints, and update_user_presets_directory().

Referenced by import_presets(), and update_user_presets_directory().

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

◆ use_bbl_device_tab()

bool Slic3r::PresetBundle::use_bbl_device_tab ( )
1033 {
1034 if (!is_bbl_vendor()) {
1035 return false;
1036 }
1037
1038 if (use_bbl_network()) {
1039 return true;
1040 }
1041
1042 const auto cfg = printers.get_edited_preset().config;
1043 // Use bbl device tab if printhost webui url is not set
1044 return cfg.opt_string("print_host_webui").empty();
1045}
bool is_bbl_vendor()
Definition PresetBundle.hpp:374
bool use_bbl_network()
Definition PresetBundle.cpp:1026

References is_bbl_vendor(), printers, use_bbl_device_tab(), and use_bbl_network().

Referenced by Slic3r::GUI::MainFrame::load_printer_url(), Slic3r::GUI::Sidebar::update_all_preset_comboboxes(), and use_bbl_device_tab().

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

◆ use_bbl_network()

bool Slic3r::PresetBundle::use_bbl_network ( )
1027{
1028 const auto cfg = printers.get_edited_preset().config;
1029 const bool use_bbl_network = is_bbl_vendor() && !cfg.opt_bool("bbl_use_printhost");
1030 return use_bbl_network;
1031}

References is_bbl_vendor(), printers, and use_bbl_network().

Referenced by Slic3r::GUI::Plater::priv::on_action_print_all(), Slic3r::GUI::Plater::priv::on_action_print_plate(), Slic3r::GUI::Sidebar::update_all_preset_comboboxes(), Slic3r::GUI::Sidebar::update_presets(), use_bbl_device_tab(), and use_bbl_network().

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

◆ validate_presets()

int Slic3r::PresetBundle::validate_presets ( const std::string & file_name,
DynamicPrintConfig & config,
std::set< std::string > & different_gcodes )
3124{
3125 bool validated = false;
3126 std::vector<std::string> inherits_values = config.option<ConfigOptionStrings>("inherits_group", true)->values;
3127 std::vector<std::string> filament_preset_name = config.option<ConfigOptionStrings>("filament_settings_id", true)->values;
3128 std::string printer_preset = config.option<ConfigOptionString>("printer_settings_id", true)->value;
3129 bool has_different_settings_to_system = config.option("different_settings_to_system")?true:false;
3130 std::vector<std::string> different_values;
3131 int ret = VALIDATE_PRESETS_SUCCESS;
3132
3133 if (has_different_settings_to_system)
3134 different_values = config.option<ConfigOptionStrings>("different_settings_to_system", true)->values;
3135
3136 //PrinterTechnology printer_technology = Preset::printer_technology(config);
3137 size_t filament_count = config.option<ConfigOptionFloats>("filament_diameter")->values.size();
3138 inherits_values.resize(filament_count + 2, std::string());
3139 different_values.resize(filament_count + 2, std::string());
3140 filament_preset_name.resize(filament_count, std::string());
3141
3142 std::string printer_inherits = inherits_values[filament_count + 1];
3143
3144 validated = this->printers.validate_preset(printer_preset, printer_inherits);
3145 if (!validated) {
3146 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found the printer preset not inherit from system") % file_name;
3147 different_gcodes.emplace(printer_preset);
3149 }
3150 for(unsigned int index = 0; index < filament_count; index ++)
3151 {
3152 std::string filament_preset = filament_preset_name[index];
3153 std::string filament_inherits = inherits_values[index+1];
3154
3155 // filament_preset_name is padded up to filament_count from filament_diameter. Unfilled
3156 // slots have no assigned preset, so there's nothing to validate or warn about.
3157 if (filament_preset.empty())
3158 continue;
3159
3160 validated = this->filaments.validate_preset(filament_preset, filament_inherits);
3161 if (!validated) {
3162 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found the filament %2% preset not inherit from system") % file_name %(index+1);
3163 different_gcodes.emplace(filament_preset);
3165 }
3166 }
3167
3168 //self defined presets, return directly
3169 if (ret)
3170 {
3171 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found self defined presets, count %2%") %file_name %different_gcodes.size();
3172 return ret;
3173 }
3174
3175 for(unsigned int index = 1; index < filament_count; index ++)
3176 {
3177 std::string different_settingss = different_values[index];
3178
3179 std::vector<std::string> different_keys;
3180
3181 Slic3r::unescape_strings_cstyle(different_settingss, different_keys);
3182
3183 for (unsigned int j = 0; j < different_keys.size(); j++) {
3184 if (gcodes_key_set.find(different_keys[j]) != gcodes_key_set.end()) {
3185 different_gcodes.emplace(different_keys[j]);
3186 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":preset index %1%, different key %2%") %index %different_keys[j];
3187 }
3188 }
3189 }
3190
3191 if (!different_gcodes.empty())
3192 {
3193 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":file_name %1%, found different gcodes count %2%") %file_name %different_gcodes.size();
3195 }
3196
3197 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":file_name %1%, validate presets success!") % file_name;
3198
3200}
#define VALIDATE_PRESETS_PRINTER_NOT_FOUND
Definition PresetBundle.hpp:35
#define VALIDATE_PRESETS_MODIFIED_GCODES
Definition PresetBundle.hpp:37
#define VALIDATE_PRESETS_FILAMENTS_NOT_FOUND
Definition PresetBundle.hpp:36
#define VALIDATE_PRESETS_SUCCESS
Definition PresetBundle.hpp:34
static std::set< std::string > gcodes_key_set
Definition PresetBundle.cpp:3121

References filaments, Slic3r::gcodes_key_set, Slic3r::ConfigBase::option(), printers, Slic3r::unescape_strings_cstyle(), validate_presets(), VALIDATE_PRESETS_FILAMENTS_NOT_FOUND, VALIDATE_PRESETS_MODIFIED_GCODES, VALIDATE_PRESETS_PRINTER_NOT_FOUND, and VALIDATE_PRESETS_SUCCESS.

Referenced by Slic3r::GUI::Plater::priv::load_files(), and validate_presets().

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

Member Data Documentation

◆ ams_multi_color_filment

std::vector<std::vector<std::string> > Slic3r::PresetBundle::ams_multi_color_filment

◆ bundles

◆ calibrate_filaments

std::set<Preset const *> Slic3r::PresetBundle::calibrate_filaments

◆ calibrate_printer

Preset const* Slic3r::PresetBundle::calibrate_printer = nullptr

◆ dir_user_presets_local

boost::filesystem::path Slic3r::PresetBundle::dir_user_presets_local

◆ dir_user_presets_subscribed

boost::filesystem::path Slic3r::PresetBundle::dir_user_presets_subscribed

◆ extruder_ams_counts

◆ filament_ams_list

std::map<int, DynamicPrintConfig> Slic3r::PresetBundle::filament_ams_list

◆ filament_presets

std::vector<std::string> Slic3r::PresetBundle::filament_presets

Referenced by apply_vendor_config(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::bind_filament_target(), Slic3r::GUI::PublishSettingsDialog::build_option_model(), Slic3r::GUI::GLGizmoTextureDisplacement::cached_palette(), Slic3r::capabilities_in_use(), Slic3r::GUI::collect_imex_warnings(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::PresetTransaction::commit(), construct_full_config(), Slic3r::GUI::EditFilamentPresetDialog::create_dialog_buttons(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::current_filament_presets(), export_current_configs(), export_selections(), Slic3r::GUI::find_decompose_standard_preset_name(), full_fff_config(), get_ams_cobox_infos(), get_current_project_embedded_presets(), get_used_tpu_filaments(), Slic3r::GUI::PublishSettingsDialog::GetPublishedMaterialKeys(), is_the_only_edited_filament(), load_config_file_config(), Slic3r::GUI::Plater::priv::load_files(), load_selections(), Slic3r::GUI::anonymous_namespace{PublishSettingsDialog.cpp}::material_title(), Slic3r::GUI::GLCanvas3D::CenterOfMass::model_markers(), operator=(), physical_filament_config_indices(), Slic3r::GUI::Plater::post_process_string_object_exception(), Slic3r::refresh_missing_plugins(), reload_local_bundle(), remove_users_preset(), reset(), reset_project_embedded_presets(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::resolved_slot_preset(), restore_selection(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::select_printer_default_presets(), selection(), set_filament_preset(), set_num_filaments(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers(), sync_ams_list(), update_compatible(), update_filament_count(), update_multi_material_filament_presets(), update_num_filaments(), Slic3r::GUI::Sidebar::update_presets_from_to(), and update_selections().

◆ filaments

PresetCollection Slic3r::PresetBundle::filaments

Referenced by PresetBundle(), Slic3r::active_capability_config(), apply_vendor_config(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::bind_filament_target(), Slic3r::GUI::GuideFrame::BuildProfileJson(), Slic3r::capabilities_in_use(), Slic3r::MachineObject::check_ams_filament_valid(), check_and_fix_user_presets_syncinfo(), check_duplicate_filament_subtypes(), check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(), check_preset_references(), check_printer_default_materials(), clear_printer_hold_aliases(), Slic3r::collect_dirty_settings_keys(), Slic3r::GUI::collect_imex_warnings(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::collection_for(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::PresetTransaction::commit(), commit_vendor_preset(), Slic3r::GUI::CreatePresetForPrinterDialog::create_dialog_buttons(), Slic3r::GUI::EditFilamentPresetDialog::create_dialog_buttons(), Slic3r::GUI::CreatePrinterPresetDialog::create_page2_dialog_buttons(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::current_filament_presets(), Slic3r::GUI::PluginsConfigDialog::current_preset(), Slic3r::GUI::ExportConfigsDialog::data_init(), export_current_configs(), full_fff_config(), generate_custom_presets(), Slic3r::GUI::CreateFilamentPresetDialog::get_all_filament_presets(), Slic3r::GUI::NewCalibrationHistoryDialog::get_all_filaments(), get_ams_cobox_infos(), Slic3r::GUI::ExtrusionCalibration::get_bed_type_incompatible(), get_current_project_embedded_presets(), Slic3r::GUI::get_default_name(), get_differed_values_to_update(), get_filament_by_filament_id(), Slic3r::GUI::get_filament_id(), Slic3r::GUI::CreateFilamentPresetDialog::get_filament_presets_by_machine(), get_filament_presets_for_machine(), get_preset_differed_for_save(), get_preset_name_by_alias(), get_required_hrc_by_filament_type(), Slic3r::GUI::EditFilamentPresetDialog::get_same_filament_id_presets(), get_used_tpu_filaments(), Slic3r::GUI::PublishSettingsDialog::GetPublishedMaterialKeys(), has_defauls_only(), has_errors(), import_json_presets(), Slic3r::GUI::ExportPresetBundleDialog::InitExportData(), install_vendor(), install_vendor_read(), is_the_only_edited_filament(), legacy_user_filament_presets(), Slic3r::load_bundle_presets(), load_config_file_config(), load_installed_filaments(), load_project_embedded_presets(), load_selections(), load_user_presets(), load_user_presets(), Slic3r::GUI::anonymous_namespace{PublishSettingsDialog.cpp}::material_title(), merge_presets(), migrate_legacy_user_filament_presets(), Slic3r::GUI::GLCanvas3D::CenterOfMass::model_markers(), normalize_compatible_presets(), Slic3r::GUI::ExtrusionCalibration::on_click_cali(), Slic3r::GUI::ExtrusionCalibration::on_click_save(), Slic3r::GUI::AMSMaterialsSetting::on_select_reset(), operator=(), Slic3r::GUI::AMSMaterialsSetting::Popup(), Slic3r::GUI::Plater::post_process_string_object_exception(), anonymous_namespace{profile_include_dump.cpp}::presets_of(), Slic3r::refresh_missing_plugins(), reload_local_bundle(), remove_users_preset(), reset(), reset_project_embedded_presets(), resolve_preset_config(), resolve_system_preset(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::resolved_slot_preset(), restore_selection(), Slic3r::CLI::run(), save_changes_for_preset(), save_user_presets(), Slic3r::GUI::sCheckFilamentInfo(), Slic3r::GUI::Tab::select_preset(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::select_printer_default_presets(), selection(), set_calibrate_printer(), set_default_suppressed(), Slic3r::MachineObject::setting_id_to_type(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers(), sync_ams_list(), Slic3r::GUI::ExtrusionCalibration::update_combobox_filaments(), update_compatible(), Slic3r::GUI::update_custom_filaments(), update_filament_count(), Slic3r::GUI::ExtrusionCalibration::update_filament_info(), Slic3r::GUI::AMSDryCtrWin::update_filament_list(), Slic3r::MachineObject::update_filament_list(), update_multi_material_filament_presets(), update_num_filaments(), Slic3r::GUI::Sidebar::update_presets(), Slic3r::GUI::CreatePrinterPresetDialog::update_presets_list(), update_selections(), update_subscribed_presets(), update_system_maps(), update_user_presets_directory(), and validate_presets().

◆ m_config_maps

std::map<std::string, DynamicPrintConfig> Slic3r::PresetBundle::m_config_maps

◆ m_errors

◆ m_filament_id_maps

std::map<std::string, std::string> Slic3r::PresetBundle::m_filament_id_maps

◆ m_generate_vendor_caches

bool Slic3r::PresetBundle::m_generate_vendor_caches { false }
private

◆ m_preserve_vendor_source_paths

bool Slic3r::PresetBundle::m_preserve_vendor_source_paths { false }
private
902{ false };

Referenced by resolve_vendor_preset().

◆ m_selection_export_blockers

int Slic3r::PresetBundle::m_selection_export_blockers = 0
private

Referenced by export_selections().

◆ m_source_vendor_bundles

std::map<std::tuple<std::string, std::string, ForwardCompatibilitySubstitutionRule, bool>, std::unique_ptr<PresetBundle> > Slic3r::PresetBundle::m_source_vendor_bundles
private

Referenced by load_source_vendor().

◆ obsolete_presets

ObsoletePresets Slic3r::PresetBundle::obsolete_presets

Referenced by merge_presets(), operator=(), and reset().

◆ ORCA_DEFAULT_BUNDLE

◆ ORCA_DEFAULT_FILAMENT

const char * Slic3r::PresetBundle::ORCA_DEFAULT_FILAMENT = "Generic PLA @System"
static

◆ ORCA_DEFAULT_FILAMENT_PLACEHOLDER

const char * Slic3r::PresetBundle::ORCA_DEFAULT_FILAMENT_PLACEHOLDER = "Default Filament"
static

◆ ORCA_DEFAULT_PRINTER_MODEL

const char * Slic3r::PresetBundle::ORCA_DEFAULT_PRINTER_MODEL = "MyKlipper 0.4 nozzle"
static

◆ ORCA_DEFAULT_PRINTER_VARIANT

const char * Slic3r::PresetBundle::ORCA_DEFAULT_PRINTER_VARIANT = "0.4"
static

◆ ORCA_FILAMENT_LIBRARY

◆ physical_printers

PhysicalPrinterCollection Slic3r::PresetBundle::physical_printers

◆ printers

PrinterPresetCollection Slic3r::PresetBundle::printers

Referenced by PresetBundle(), Slic3r::GUI::_collect_sorted_machines(), Slic3r::active_capability_config(), Slic3r::GUI::SelectMachineDialog::build_nozzles_info(), Slic3r::GUI::SyncAmsInfoDialog::build_nozzles_info(), Slic3r::GUI::GuideFrame::BuildProfileJson(), Slic3r::GUI::PartPlate::calc_imex_zones(), Slic3r::capabilities_in_use(), Slic3r::GUI::Plater::priv::check_ams_status_impl(), check_and_fix_user_presets_syncinfo(), check_duplicate_filament_subtypes(), check_filament_temp_equation_by_printer_type_and_nozzle_for_mas_tray(), check_preset_references(), check_printer_default_materials(), clear_printer_hold_aliases(), Slic3r::collect_dirty_settings_keys(), Slic3r::GUI::collect_imex_warnings(), Slic3r::GUI::CreatePrinterPresetDialog::create_page2_dialog_buttons(), Slic3r::GUI::PluginsConfigDialog::current_preset(), Slic3r::GUI::ExportConfigsDialog::data_init(), Slic3r::effective_physical_extruder_map(), Slic3r::GUI::Plater::export_3mf(), export_current_configs(), Slic3r::GUI::Plater::export_gcode(), export_selections(), Slic3r::GUI::extruder_supports_tpu_high_flow(), full_config(), full_fff_config(), full_sla_config(), generate_custom_presets(), Slic3r::GUI::NewCalibrationHistoryDialog::get_all_filaments(), Slic3r::GUI::CreateFilamentPresetDialog::get_all_visible_printer_name(), get_current_project_embedded_presets(), get_current_vendor_type(), get_custom_vendor_models(), get_differed_values_to_update(), get_filament_presets_for_machine(), Slic3r::GUI::AMSMaterialsSetting::get_filament_variant_index(), Slic3r::GUI::Plater::priv::get_machine_sync_status(), get_preset_differed_for_save(), get_preset_name_by_alias(), get_printer_extruder_count(), get_printer_names_by_printer_type_and_nozzle(), Slic3r::GUI::CalibrationPresetPage::get_printer_preset(), Slic3r::GUI::get_printer_preset(), Slic3r::Preset::get_printer_type(), Slic3r::GUI::Plater::get_selected_printer_name_in_combox(), get_similar_printer_preset(), Slic3r::GUI::getExtruderNozzleCount(), Slic3r::GUI::getExtruderNozzleCountTotal(), has_defauls_only(), has_errors(), Slic3r::Preset::has_lidar(), import_json_presets(), import_presets(), Slic3r::GUI::GCodeViewer::init(), Slic3r::GUI::ExportPresetBundleDialog::InitExportData(), install_vendor_read(), Slic3r::GUI::Plater::is_same_printer_for_connected_and_selected(), Slic3r::GUI::SelectMachineDialog::is_same_printer_model(), Slic3r::GUI::SyncAmsInfoDialog::is_same_printer_model(), Slic3r::GUI::Sidebar::priv::layout_printer(), Slic3r::load_bundle_presets(), load_config_file_config(), load_installed_filaments(), load_installed_printers(), load_installed_sla_materials(), Slic3r::GUI::MainFrame::load_printer_url(), load_project_embedded_presets(), load_selections(), Slic3r::GUI::CreatePrinterPresetDialog::load_system_and_user_presets_with_curr_model(), load_user_presets(), load_user_presets(), Slic3r::GUI::manuallySetNozzleCount(), merge_presets(), min_filament_count(), Slic3r::GUI::Sidebar::need_auto_sync_extruder_list_after_connect_priner(), normalize_compatible_presets(), on_extruders_count_changed(), Slic3r::GUI::Plater::priv::on_select_bed_type(), Slic3r::GUI::AMSMaterialsSetting::on_select_filament(), Slic3r::GUI::Plater::priv::on_select_preset(), Slic3r::GUI::ExportPresetBundleDialog::OnRequestPresets(), operator=(), Slic3r::GUI::AMSMaterialsSetting::Popup(), anonymous_namespace{profile_include_dump.cpp}::presets_of(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::printer_presets(), Slic3r::GUI::PartPlate::refresh_imex_icon(), Slic3r::refresh_missing_plugins(), Slic3r::GUI::PartPlate::register_raycasters_for_picking(), reload_local_bundle(), remove_users_preset(), Slic3r::GUI::PartPlate::render_icons(), Slic3r::GUI::GCodeViewer::render_markers(), Slic3r::GUI::anonymous_namespace{SceneBenchmark.cpp}::SceneBenchmarkDialog::report(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::require_tab(), reset(), reset_default_nozzle_volume_type(), reset_project_embedded_presets(), resolve_preset_config(), resolve_system_preset(), restore_selection(), Slic3r::CLI::run(), Slic3r::GUI::GuideFrame::run(), Slic3r::GUI::s_get_slicing_extuder_nozzles(), save_changes_for_preset(), save_user_presets(), Slic3r::GUI::seedExtruderNozzleStats(), Slic3r::GUI::ExportConfigsDialog::select_curr_radiobox(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::select_printer_default_presets(), selection(), set_calibrate_printer(), Slic3r::GUI::CreatePrinterPresetDialog::set_current_visible_printer(), set_default_suppressed(), Slic3r::GUI::PartPlate::set_shape(), Slic3r::GUI::setExtruderNozzleCount(), Slic3r::GUI::Sidebar::should_show_SEMM_buttons(), Slic3r::GUI::SelectMachineDialog::show_status(), Slic3r::GUI::SyncAmsInfoDialog::show_status(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_config(), support_different_extruders(), Slic3r::GUI::Sidebar::priv::sync_extruder_list(), Slic3r::GUI::TabPrinter::toggle_options(), Slic3r::GUI::ConfigManipulation::toggle_print_fff_options(), Slic3r::GUI::Sidebar::update_all_preset_comboboxes(), Slic3r::GUI::ExtrusionCalibration::update_combobox_filaments(), Slic3r::GUI::DiffPresetDialog::update_compatibility(), update_compatible(), update_filament_count(), update_multi_material_filament_presets(), Slic3r::GUI::Sidebar::update_presets(), update_selections(), Slic3r::GUI::SelectMachineDialog::update_show_status(), update_subscribed_presets(), Slic3r::GUI::Sidebar::priv::update_sync_status(), update_system_maps(), update_system_preset_setting_ids(), update_user_presets_directory(), Slic3r::GUI::updateNozzleCountDisplay(), use_bbl_device_tab(), use_bbl_network(), and validate_presets().

◆ prints

PresetCollection Slic3r::PresetBundle::prints

Referenced by PresetBundle(), Slic3r::active_capability_config(), Slic3r::GUI::GuideFrame::BuildProfileJson(), Slic3r::GUI::PartPlate::calc_imex_zones(), Slic3r::capabilities_in_use(), check_and_fix_user_presets_syncinfo(), check_preset_references(), clear_printer_hold_aliases(), Slic3r::collect_dirty_settings_keys(), Slic3r::anonymous_namespace{PluginHostPresets.cpp}::collection_for(), Slic3r::GUI::CreatePrinterPresetDialog::create_page2_dialog_buttons(), Slic3r::GUI::PluginsConfigDialog::current_preset(), Slic3r::GUI::ExportConfigsDialog::data_init(), export_current_configs(), export_selections(), full_fff_config(), generate_custom_presets(), get_current_project_embedded_presets(), get_differed_values_to_update(), get_preset_differed_for_save(), get_preset_name_by_alias(), Slic3r::GUI::CalibrationPresetPage::get_print_preset(), has_defauls_only(), has_errors(), Slic3r::GUI::PartPlate::imex_wipe_tower_hull(), import_json_presets(), Slic3r::GUI::ExportPresetBundleDialog::InitExportData(), install_vendor_read(), Slic3r::load_bundle_presets(), load_config_file_config(), load_project_embedded_presets(), load_selections(), load_user_presets(), load_user_presets(), merge_presets(), normalize_compatible_presets(), operator=(), anonymous_namespace{profile_include_dump.cpp}::presets_of(), Slic3r::GUI::anonymous_namespace{PublishSettingsDialog.cpp}::project_used_filament_slots(), Slic3r::refresh_missing_plugins(), reload_local_bundle(), remove_users_preset(), Slic3r::GUI::GCodeViewer::render_markers(), Slic3r::GUI::anonymous_namespace{SceneBenchmark.cpp}::SceneBenchmarkDialog::report(), reset(), reset_project_embedded_presets(), resolve_preset_config(), resolve_system_preset(), restore_selection(), Slic3r::CLI::run(), save_changes_for_preset(), save_user_presets(), Slic3r::GUI::Tab::select_preset(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::select_printer_default_presets(), selection(), set_default_suppressed(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_all_printers(), sync_ams_list(), update_compatible(), Slic3r::GUI::CreatePrinterPresetDialog::update_presets_list(), update_selections(), update_subscribed_presets(), update_system_maps(), and update_user_presets_directory().

◆ project_config

DynamicPrintConfig Slic3r::PresetBundle::project_config

Referenced by Slic3r::GUI::ConfigWizard::priv::apply_config(), Slic3r::GUI::SelectMachineDialog::build_nozzles_info(), Slic3r::GUI::SyncAmsInfoDialog::build_nozzles_info(), Slic3r::GUI::GLGizmoTextureDisplacement::cached_palette(), Slic3r::GUI::CalibUtils::calib_generic_auto_pa_cali(), Slic3r::GUI::Plater::priv::check_ams_status_impl(), Slic3r::GUI::collect_imex_warnings(), config_from_gcode(), construct_full_config(), Slic3r::effective_physical_extruder_map(), export_selections(), full_fff_config(), get_default_nozzle_volume_types_for_filaments(), get_full_flush_matrix(), Slic3r::GUI::Sidebar::priv::get_nozzle_options(), Slic3r::GUI::PartPlate::imex_wipe_tower_hull(), is_mixed_filament(), load_config_file_config(), Slic3r::GUI::Plater::priv::load_files(), Slic3r::GUI::Plater::load_gcode(), load_selections(), num_mixed_filaments(), num_physical_filaments(), operator=(), Slic3r::BackgroundSlicingProcess::process_fff(), reload_local_bundle(), reset_default_nozzle_volume_type(), Slic3r::GUI::ProjectDirtyStateManager::reset_initial_presets(), restore_selection(), Slic3r::GUI::s_get_slicing_extuder_nozzles(), Slic3r::GUI::seedExtruderNozzleStats(), selection(), Slic3r::GUI::set_arrange_polygon_bed_exclusion_extruders(), set_num_filaments(), Slic3r::GUI::SelectMachineDialog::Show(), anonymous_namespace{OrcaSlicer_profile_validator.cpp}::slice_config(), sync_ams_list(), update_filament_multi_color(), Slic3r::GUI::ProjectDirtyStateManager::update_from_presets(), update_multi_material_filament_presets(), update_num_filaments(), and update_selections().

◆ sla_materials

◆ sla_prints

◆ validation_mode

bool Slic3r::PresetBundle::validation_mode = false
private

◆ vendor_to_validate

std::string Slic3r::PresetBundle::vendor_to_validate = ""
private

◆ vendors


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