#ifndef slic3r_PresetBundle_hpp_ #define slic3r_PresetBundle_hpp_ #include "Config.hpp" #include "Preset.hpp" #include "PresetCacheFormat.hpp" #include "AppConfig.hpp" #include "PrintConfig.hpp" #include "PublishSettings.hpp" #include "Semver.hpp" #include "enum_bitmask.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_USER_FOLDER_NAME "default" #define BUNDLE_STRUCTURE_JSON_NAME "bundle_structure.json" #define VALIDATE_PRESETS_SUCCESS 0 #define VALIDATE_PRESETS_PRINTER_NOT_FOUND 1 #define VALIDATE_PRESETS_FILAMENTS_NOT_FOUND 2 #define VALIDATE_PRESETS_MODIFIED_GCODES 3 // define an enum class of vendor type enum class VendorType { Unknown = 0, Klipper, Marlin, Marlin_BBL, Klipper_Qidi }; namespace Slic3r { struct AMSMapInfo { /*for new ams mapping*/ // from struct FilamentInfo std::string ams_id{""}; std::string slot_id{""}; }; struct AMSComboInfo { std::vector ams_filament_colors; std::vector> ams_multi_color_filment; std::vector ams_filament_presets; std::vector ams_names; void clear() { ams_filament_colors.clear(); ams_multi_color_filment.clear(); ams_filament_presets.clear(); ams_names.clear(); } bool empty() { return ams_names.empty(); } }; struct MergeFilamentInfo { std::vector> merges; bool is_empty() { return merges.empty();} }; struct FilamentBaseInfo { std::string filament_name; std::string filament_id; std::string filament_type; std::string vendor; int nozzle_temp_range_low{ 220 }; int nozzle_temp_range_high{ 220 }; int temperature_vitrification = INT_MAX; bool is_support{ false }; bool is_system{ true }; int filament_printable = 3; // filament_extruder_compatibility packs one compatibility level per extruder into a single // 32-bit int, 3 bits per extruder (up to 10 extruders). Levels: 0 = printable, 1 = error, // 2 = critical warning, 3 = warning (4-7 reserved). extruder_id is 0-based. int get_extruder_compatibility(int extruder_id) const { constexpr int bits_per_extruder = 3; constexpr int extruder_mask = (1 << bits_per_extruder) - 1; // 0x7 constexpr int max_extruder_count = 32 / bits_per_extruder; // 10 if (extruder_id < 0 || extruder_id >= max_extruder_count) return 0; return (m_filament_extruder_compatibility >> (bits_per_extruder * extruder_id)) & extruder_mask; } void set_filament_extruder_compatibility(int value) { m_filament_extruder_compatibility = value; } int get_filament_extruder_compatibility() const { return m_filament_extruder_compatibility; } private: int m_filament_extruder_compatibility = 0; }; enum BundleType{ Default = 0, Local, Subscribed, }; // Orca: Bundle metadata structure for imported preset bundles struct BundleMetadata { std::string id; // Bundle ID: UUID (OrcaCloud) or name+timestamp (external) std::string name; // Display name std::string version; // Bundle version std::string description; std::string author; long long imported_time{0}; long long updated_time{0}; BundleType bundle_type{Default}; std::string path; // Cached preset names by type (populated on load) std::vector print_presets; std::vector filament_presets; std::vector printer_presets; // Runtime-only flags bool is_subscribed{false}; bool update_available{false}; bool not_found{false}; bool unauthorized{false}; bool load_from_json(const std::string& path); bool save_to_json(const std::string& path) const; }; struct PresetBundleMetadata { // To make sure write locks take precedent, pausereads needs to be true for when Orca needs to read or manipulate the container // We only need to explicitly pause reads when entering a region in Orca which we deem necessary to quickly acquire write locks. std::unordered_map m_bundles; std::shared_mutex RWMtx; std::atomic pauseReads{false}; void PauseRead() { pauseReads.store(true); } void UnpauseRead() { pauseReads.store(false); } void ReadLock() { RWMtx.lock_shared(); } void ReadUnlock() { RWMtx.unlock_shared(); } void WriteLock() { RWMtx.lock(); } void WriteUnlock() { RWMtx.unlock(); } }; // A "published" 3MF project: keeps the user's currently-selected presets and overlays only the // author-selected published keys onto the edited presets. struct PublishedConfig { bool published = false; std::vector published_keys; // Per-slot published material keys, applied positionally (author slot N -> receiver slot N). // Partial entries are gated by the author's optional type requirement and written onto the // slot's stored preset in place; full entries instead detach (see PublishedMaterialEntry in // PublishSettings.hpp). std::vector material_keys; // Keys that could not be applied (missing on the user's machine or vector size mismatch), // filled in by load_config_file_config for notification purposes. std::vector skipped_keys; // Human-readable notices of the slot material replacements performed while loading a // published project, for the load notification. std::vector material_replacements; // Mixed-filament entries that had to be moved off their authored slot on load (a real, // physical filament occupied it): maps the author's zero-based slot number to its final // zero-based slot. Consumers (e.g. model extruder/color-painting remapping) use this to // keep geometry references pointing at the relocated definitions. std::map mixed_slot_relocations; }; // Bundle of Print + Filament + Printer presets. class PresetBundle { public: // ---- Per-vendor preset cache -------------------------------------------- // One cache file per vendor (plus the Orca filament library), stamped with // the vendor's own profile version rather than a directory scan. The bytes // on disk are VendorCacheFile's business (PresetCacheFormat.hpp); what // lives here is how a cache's contents install into a bundle. // The cache is not something a caller loads from: a vendor is loaded with // load_vendor_configs_from_json, which comes from the cache whenever one covers // it. What is public here is what the cache's own tests drive directly. // Load a per-vendor cache into this bundle by installing its entries, with // base_bundle's filament library as the inheritance base. Rejects (returns // false, with this bundle left clean) unless VendorCacheFile::load accepts // the file — see its contract for the version and identity checks — and // every entry installs. Options this build no longer defines are dropped, // not fatal — the payload names its own keys. 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); // Enable writing a per-vendor cache after a JSON parse (off by default). Cache // content is pure parse output, so the guard is policy, not correctness: only // the deliberate generators (load_system_presets_from_json, the cache build // tool) write files, not every incidental load a dialog performs. void set_generate_vendor_caches(bool enable) { m_generate_vendor_caches = enable; } static DynamicPrintConfig construct_full_config(Preset &in_printer_preset, Preset &in_print_preset, const DynamicPrintConfig &project_config, std::vector &in_filament_presets, bool apply_extruder, std::optional> filament_maps_new, std::optional> filament_volume_maps_new = std::nullopt); // ORCA: utility function to find the vendor for a given preset name static std::string find_preset_vendor(const std::string& preset_name, Preset::Type type); // Keys a project keeps when its presets are loaded: those listed in its escaped // "different_settings_to_system" entry for the preset, plus the preset bookkeeping keys. static std::set project_different_keys(const std::string &different_settings); // A project filament saved under a name the current presets split per nozzle (e.g. H2D 0.6) is loaded from // the preset that now holds its values. static void convert_filament_preset_name(const std::string& machine_name, std::string& filament_name); PresetBundle(); PresetBundle(const PresetBundle &rhs); PresetBundle& operator=(const PresetBundle &rhs); // Remove all the presets but the "-- default --". // Optionally remove all the files referenced by the presets from the user profile directory. void reset(bool delete_files); void setup_directories(); void copy_files(const std::string& from); struct PresetPreferences { std::string printer_model_id;// name of a preferred printer model std::string printer_variant; // name of a preferred printer variant std::string filament; // name of a preferred filament preset std::string sla_material; // name of a preferred sla_material preset }; // Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets. // Load selections (current print, current filaments, current printer) from config.ini // select preferred presets, if any exist PresetsConfigSubstitutions load_presets(AppConfig &config, ForwardCompatibilitySubstitutionRule rule, const PresetPreferences& preferred_selection = PresetPreferences(), std::string *errors = nullptr, bool read_only = false); // Resolve an explicitly named source file through a canonical flattened // preset. Exact loaded-file identity is preferred; otherwise a manifest- // backed vendor tree is loaded from that source root without using caches. 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); // Resolve a source file whose JSON omits `type`. Succeeds only when exactly // one FFF preset collection owns the file and returns that collection's type. 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); // Resolve a system preset by name. The vendor tree is read from data_dir()/system when installed // there, as the GUI reads it, and from the bundled profiles otherwise. bool resolve_system_preset(DynamicPrintConfig &config, Preset::Type type, const std::string &name, ForwardCompatibilitySubstitutionRule compatibility_rule, std::string &error); // Load selections (current print, current filaments, current printer) from config.ini // This is done just once on application start up. //BBS: change it to public void load_selections(AppConfig &config, const PresetPreferences& preferred_selection = PresetPreferences()); // BBS Load user presets PresetsConfigSubstitutions load_user_presets(std::string user, ForwardCompatibilitySubstitutionRule rule, bool read_only = false); PresetsConfigSubstitutions load_user_presets(AppConfig &config, std::map>& my_presets, ForwardCompatibilitySubstitutionRule rule); bool reload_local_bundle(const std::string& preset_folder, const std::string& bundle_id, std::string* error = nullptr); std::vector list_local_bundle_ids(const std::string& preset_folder); // Orca: Import subscribed bundle presets (load and save to disk in one operation), handles one bundle at a time PresetsConfigSubstitutions update_subscribed_presets(AppConfig& config, const std::map>& bundle_presets, const BundleMetadata& remote_metadata, ForwardCompatibilitySubstitutionRule rule); PresetsConfigSubstitutions import_presets(std::vector& files, std::function override_confirm, ForwardCompatibilitySubstitutionRule rule, AppConfig& config); bool import_json_presets(PresetsConfigSubstitutions& substitutions, std::string& file, std::function override_confirm, ForwardCompatibilitySubstitutionRule rule, int& overwrite, std::vector& result, const std::string& bundle_dir = "", const std::map &bed_asset_paths = {}, bool *bed_paths_loaded = nullptr); void save_user_presets(AppConfig& config, std::map& need_to_delete_list); void check_and_fix_user_presets_syncinfo(const std::string& user_id); void remove_users_preset(AppConfig &config, std::map> * 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>& system_presets); // Apply vendor configuration changes (Core library version, no GUI dependencies) // This function installs vendors from resources and loads them into the preset bundle // // Parameters: // new_vendors: Map of vendor names to their enabled printer models and variants // new_filaments: Map of filament names to their settings // app_config: Pointer to AppConfig to update with new vendor/filament selections // preferred_printer_model: Optional preferred printer model to select // preferred_printer_variant: Optional preferred printer variant to select // preferred_filament: Optional preferred filament to select // // Returns: true if successful, false otherwise bool apply_vendor_config( const std::map>>& new_vendors, const std::map& 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()); //BBS: add API to get previous machine int validate_presets(const std::string &file_name, DynamicPrintConfig& config, std::set& different_gcodes); //BBS: add function to generate differed preset for save //the pointer should be freed by the caller Preset* get_preset_differed_for_save(Preset& preset); int get_differed_values_to_update(Preset& preset, std::map& key_values); //BBS: get vendor's current version Semver get_vendor_profile_version(std::string vendor_name); std::optional get_filament_by_filament_id(const std::string& filament_id, const std::string& printer_name = std::string()) const; // Orca: get vendor type VendorType get_current_vendor_type(); // Vendor related handy functions bool is_bbl_vendor() { return get_current_vendor_type() == VendorType::Marlin_BBL; } // Whether using bbl network for print upload bool use_bbl_network(); // Whether using bbl's device tab bool use_bbl_device_tab(); bool backup_user_folder() const; // Writes the user preset folder into a zip archive at zip_path, its entries under "user/". bool backup_user_folder_to_zip(const std::string &zip_path) const; // User filament presets made against an older release that no longer show on printers their parent // listed then (resources/info/legacy_compatible_printers.json). std::vector legacy_user_filament_presets(); // Backs up the user preset folder into a zip in data_dir(), then writes each preset's printers into its file // under one hold of the user presets lock. Nothing is written when the backup failed (backup empty) or the // lock could not be taken (locked false); otherwise failed names the presets whose files could not be written. struct LegacyUserFilamentPresetMigration { bool locked{false}; std::string backup; std::vector failed; }; LegacyUserFilamentPresetMigration migrate_legacy_user_filament_presets(const std::vector &legacy_presets); //BBS: project embedded preset logic PresetsConfigSubstitutions load_project_embedded_presets(std::vector project_presets, ForwardCompatibilitySubstitutionRule substitution_rule); std::vector get_current_project_embedded_presets(); void reset_project_embedded_presets(); // What importing a file's settings replaces, so that an import which fails part-way, or whose // file is then rejected, can be undone without copying every preset. struct Selection { struct Collection { std::string selected; DynamicPrintConfig edited; // The baseline saved_is_dirty() compares against, which feeds the project dirty state. DynamicPrintConfig saved; // By index: an import only inserts project-embedded presets, which a restore drops first. std::vector visible; }; Collection prints, filaments, printers; std::vector filament_presets; DynamicPrintConfig project_config; std::vector> extruder_ams_counts; }; // Nothing while project-embedded presets exist: a restore drops them, which would lose a loaded project's presets. std::optional selection() const; void restore_selection(const Selection &selection); //BBS: find printer model 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); // Export selections (current print, current filaments, current printer) into config.ini void export_selections(AppConfig &config); // While one lives, export_selections() writes nothing, so a selection only shown for a while (the // settings of a G-code being previewed) is not remembered as the user's. It also covers the // exports the GUI makes on its own while refreshing. class SelectionExportBlocker { public: explicit SelectionExportBlocker(PresetBundle &bundle) : m_bundle(bundle) { ++m_bundle.m_selection_export_blockers; } ~SelectionExportBlocker() { --m_bundle.m_selection_export_blockers; } SelectionExportBlocker(const SelectionExportBlocker &) = delete; SelectionExportBlocker &operator=(const SelectionExportBlocker &) = delete; private: PresetBundle &m_bundle; }; // n is the total slot count, and growth appends at the raw tail - which is where the mixed // slots live. A caller adding physical filaments has to add num_mixed_filaments() on top and // then move the new slots ahead of the mixed tail, as Sidebar::add_custom_filament does. 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> &unknowns, bool use_map, std::map &maps, bool enable_append, MergeFilamentInfo &merge_info, bool color_only = false); //BBS: check whether this is the only edited filament bool is_the_only_edited_filament(unsigned int filament_index); void reset_default_nozzle_volume_type(); std::vector get_used_tpu_filaments(const std::vector &used_filaments); // Orca: update selected filament and print void update_selections(AppConfig &config); void set_calibrate_printer(std::string name); void set_is_validation_mode(bool mode) { validation_mode = mode; } void set_vendor_to_validate(std::string vendor) { vendor_to_validate = vendor; } std::vector> get_extruder_filament_info() const; std::set get_printer_names_by_printer_type_and_nozzle(const std::string &printer_type, std::string nozzle_diameter_str, bool system_only = true); // Orca: the root filament presets a connected machine can use, resolved with the rule the rest // of the app applies (is_compatible_with_printer): an empty compatible_printers means every // printer, minus the alias shadowing exclusions the Orca Filament Library records in // Preset::m_excluded_from. std::vector get_filament_presets_for_machine(const std::string &printer_type, const std::string &nozzle_diameter_str, bool include_user_presets); // Orca: the variant index of a filament preset's per-variant options on extruder extruder_id of a printer // preset, with the nozzle volume type the machine reports; 0 when the filament has no such variant. static int get_filament_variant_index(const DynamicPrintConfig &filament_config, const DynamicPrintConfig &printer_config, int extruder_id, NozzleVolumeType nozzle_volume_type); // extruder_id and nozzle_volume_type identify the tray's nozzle, whose variant the temperature range is compared for. 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 prints; PresetCollection sla_prints; PresetCollection filaments; PresetCollection sla_materials; PresetCollection& materials(PrinterTechnology pt) { return pt == ptFFF ? this->filaments : this->sla_materials; } const PresetCollection& materials(PrinterTechnology pt) const { return pt == ptFFF ? this->filaments : this->sla_materials; } PrinterPresetCollection printers; PhysicalPrinterCollection physical_printers; // Filament preset names for a multi-extruder or multi-material print. // extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size() std::vector filament_presets; // BBS: ams std::map filament_ams_list; std::vector> ams_multi_color_filment; std::vector> extruder_ams_counts; // Calibrate Preset const * calibrate_printer = nullptr; std::set calibrate_filaments; // The project configuration values are kept separated from the print/filament/printer preset, // they are being serialized / deserialized from / to the .amf, .3mf, .config, .gcode, // and they are being used by slicing core. DynamicPrintConfig project_config; // There will be an entry for each system profile loaded, // and the system profiles will point to the VendorProfile instances owned by PresetBundle::vendors. VendorMap vendors; // Orca: for OrcaFilamentLibrary std::map m_config_maps; std::map m_filament_id_maps; // Orca: Bundle metadata and cached preset names // std::map m_bundles; boost::filesystem::path dir_user_presets_local; boost::filesystem::path dir_user_presets_subscribed; PresetBundleMetadata bundles; struct ObsoletePresets { std::vector prints; std::vector sla_prints; std::vector filaments; std::vector sla_materials; std::vector printers; }; ObsoletePresets obsolete_presets; bool has_defauls_only() const { return prints.has_defaults_only() && filaments.has_defaults_only() && printers.has_defaults_only(); } DynamicPrintConfig full_config(bool apply_extruder = true, std::optional>filament_maps = std::nullopt, std::optional> filament_volume_maps = std::nullopt) const; // full_config() with the some "useless" config removed. DynamicPrintConfig full_config_secure(std::optional>filament_maps = std::nullopt) const; // Default per-filament nozzle-volume types: each filament inherits the volume type of the // extruder it maps to (1-based f_maps), Standard when unknown. std::vector get_default_nozzle_volume_types_for_filaments(std::vector& f_maps); // Per-extruder flush matrix [extruder_id][from_filament][to_filament] in mm^3, optionally scaled // by the per-extruder flush_multiplier (or flush_multiplier_fast when prime_volume_mode==Fast). // Used by the print-dispatch nozzle-mapping flush-weight estimate. std::vector>> get_full_flush_matrix(bool with_multiplier = true) const; //BBS: add some functions for multiple extruders int get_printer_extruder_count() const; bool support_different_extruders() const; // Orca: Ensure filament_presets has at least one slot per nozzle on FFF printers. // Called from (load|update)_selections before the parallel project_config arrays // (filament_colour/colour_type/map) are sized off filament_presets.size(), so a // short saved filament list doesn't truncate the loaded colors. void update_filament_count(); // Load user configuration and store it into the user profiles. // This method is called by the configuration wizard. void load_config_from_wizard(const std::string &name, DynamicPrintConfig config, Semver file_version) { this->load_config_file_config(name, false, std::move(config), file_version, true); } // Load configuration that comes from a model file containing configuration, such as 3MF et al. // This method is called by the Plater. void load_config_model(const std::string &name, DynamicPrintConfig config, Semver file_version = Semver(), PublishedConfig *published_config = nullptr) { this->load_config_file_config(name, true, std::move(config), file_version, false, published_config); } // Load an external config file containing the print, filament and printer presets. // Instead of a config file, a G-code may be loaded containing the full set of parameters. // In the future the configuration will likely be read from an AMF file as well. // If the file is loaded successfully, its print / filament / printer profiles will be activated. ConfigSubstitutions load_config_file(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule); // The settings an OrcaSlicer G-code was sliced with, from its config block, ready for load_config_model(). // Throws when the file carries no such block (another slicer, or the block was left out). DynamicPrintConfig config_from_gcode(const std::string &path, ForwardCompatibilitySubstitutionRule compatibility_rule, ConfigSubstitutions &substitutions) const; // Load a config bundle file, into presets and store the loaded presets into separate files // of the local configuration directory. // Load settings into the provided settings instance. // Activate the presets stored in the config bundle. // Returns the number of presets loaded successfully. enum LoadConfigBundleAttribute { // Save the profiles, which have been loaded. SaveImported, // Delete all old config profiles before loading. ResetUserProfile, // Load a system config bundle. LoadSystem, LoadVendorOnly, LoadFilamentOnly, }; using LoadConfigBundleAttributes = enum_bitmask; // Load the config bundle based on the flags. // Don't do any config substitutions when loading a system profile, perform and report substitutions otherwise. /*std::pair load_configbundle( const std::string &path, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule);*/ //Orca: load config bundle from json, pass the base bundle to support cross vendor inheritance // Orca: `dir` is where the vendor is looked for — its own directory, whether or // not the profile JSONs are still there. A whole-vendor load comes from the // vendor's preset cache whenever one covers the profile on disk and allow_cache // is true, and is parsed from the JSONs in `dir` otherwise. Nothing here reads // resources implicitly. std::pair 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); // Export a config bundle file containing all the presets and the names of the active presets. //void export_configbundle(const std::string &path, bool export_system_settings = false, bool export_physical_printers = false); //BBS: add a function to export current configbundle as default //void export_current_configbundle(const std::string &path); //BBS: add a function to export system presets for cloud-slicer //void export_system_configs(const std::string &path); std::vector export_current_configs(const std::string &path, std::function override_confirm, bool include_modify, bool export_system_settings = false); // Enable / disable the "- default -" preset. void set_default_suppressed(bool default_suppressed); // Set the filament preset name. As the name could come from the UI selection box, // an optional "(modified)" suffix will be removed from the filament name. void set_filament_preset(size_t idx, const std::string &name); // Read out the number of extruders from an active printer preset, // update size and content of filament_presets. void update_multi_material_filament_presets(size_t to_delete_filament_id = size_t(-1)); // Mixed-color filament slots: virtual slots realized from 2-3 physical filaments. bool is_mixed_filament(size_t idx) const; std::vector physical_filament_config_indices() const; // How many slots are mixed. They sit at the tail of the filament list and have no nozzle of // their own, so any resize driven by the printer's extruder count has to add this on top. size_t num_mixed_filaments() const; // How many slots hold a real filament, i.e. everything ahead of the mixed tail. size_t num_physical_filaments() const; void on_extruders_count_changed(int extruder_count); // Update the is_compatible flag of all print and filament presets depending on whether they are marked // as compatible with the currently selected printer (and print in case of filament presets). // Also updates the is_visible flag of each preset. // If select_other_if_incompatible is true, then the print or filament preset is switched to some compatible // preset if the current print or filament preset is not compatible. void update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible); void update_compatible(PresetSelectCompatibleType select_other_if_incompatible) { this->update_compatible(select_other_if_incompatible, select_other_if_incompatible); } // Rewrite compatible_printers / compatible_prints references that point at a renamed system // preset to the current name, mirroring Preset::normalize_inherits for the "inherits" field. // Call after loading presets and before selection; requires update_system_maps() to have run. void normalize_compatible_presets(); // Set the is_visible flag for printer vendors, printer models and printer variants // based on the user configuration. // If the "vendor" section is missing, enable all models and variants of the particular vendor. 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; // Save current preset of a provided type under a new name. If the name is different from the old one, // Unselected option would be reverted to the beginning values //BBS: add project embedded preset logic void save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector& unselected_options, bool save_to_project = false); std::pair load_system_models_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule); std::pair load_system_filaments_json(ForwardCompatibilitySubstitutionRule compatibility_rule); VendorProfile get_custom_vendor_models() const; //orca: add 'custom' as default static const char *ORCA_DEFAULT_BUNDLE; static const char *ORCA_DEFAULT_PRINTER_MODEL; static const char *ORCA_DEFAULT_PRINTER_VARIANT; static const char *ORCA_DEFAULT_FILAMENT; static const char *ORCA_FILAMENT_LIBRARY; static const char *ORCA_DEFAULT_FILAMENT_PLACEHOLDER; static std::array types_list(PrinterTechnology pt) { if (pt == ptFFF) return { Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT }; return { Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL }; } // Orca: for validation only. bool has_errors(bool check_duplicate_filament_subtypes = false) const; // Errors the last load recorded. What the cache's error accounting promises — // a cache-served vendor reports what its parse would — is pinned against this. int error_count() const { return m_errors; } // Orca: for validation only. Flag any system preset whose inherits / compatible_printers / // compatible_prints references a deleted (unknown) or renamed (old) preset name. bool check_preset_references() const; // Validator-only: every system FFF printer variant needs a compatible system filament // named in its model's default_materials, every name there and in the printer's // default_filament_profile must resolve to a system filament. bool check_printer_default_materials() const; // One vendor to load, and the directory it is installed in. struct VendorSource { std::string name; boost::filesystem::path dir; }; // Load `vendors` into this bundle, the Orca filament library directly and every // other vendor in parallel into a bundle of its own that inherits from it, merged // in the order given. A vendor that cannot be loaded has its error added to the // returned text, or thrown in validation mode, and its name to `failed`; it is // left out, except for the library, which keeps what it installed before the // failure. Once `cancel` is set, no further vendor starts loading. std::pair load_vendors(const std::vector& vendors, ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache, const std::atomic* cancel = nullptr, std::vector* failed = nullptr); private: // Move the presets and vendor profiles of `others` into this bundle, in one pass // over each collection. A preset whose name this bundle or an earlier one of // `others` already has is left out and listed under the bundle that repeats it. std::vector> merge_presets(const std::vector &others); // What parsing one entry's JSON sub-file reported. Its errors and warnings are // logged when the entry installs, so they come out in listing order with the // entry's install errors, as parsing and installing one entry at a time leaves them. struct EntryParse { ConfigSubstitutions substitutions; // Counted in the bundle's error count. std::vector errors; std::vector warnings; }; // An EntryParse for each entry of the VendorCacheData list of the same name. struct VendorParse { std::vector process_entries; std::vector filament_entries; std::vector machine_entries; }; // One vendor read from its cache or its JSONs by read_vendor, for // install_vendor_read to install. struct VendorRead { std::string dir; std::string vendor_name; LoadConfigBundleAttributes flags; ForwardCompatibilitySubstitutionRule compatibility_rule; // The errors this bundle had counted before the read, which the cache stamp leaves out. int errors_at_entry { 0 }; // A whole-vendor load, which can read a cache and write one. bool cacheable { false }; // Read from the cache at cache_path, which install can still reject. bool from_cache { false }; std::string cache_path; // Only the vendor profile was asked for. bool vendor_only { false }; VendorCacheData data; // What each entry's JSON parse reported, and whether and with which version // the cache is written once the entries install. VendorParse parsed; bool will_cache { false }; std::string version; // The sub-file the parse stopped at, its kind, why, and the errors it reported. std::string reason; std::string failed_subfile; const char* failed_kind { nullptr }; std::vector failed_errors; }; // Read a vendor into this bundle's vendor profiles and `data`, from its cache // when one covers it, else from its JSONs; nothing is installed. Throws // ConfigurationError when the vendor's own JSON cannot be parsed. VendorRead read_vendor(const std::string& dir, const std::string& vendor_name, LoadConfigBundleAttributes flags, ForwardCompatibilitySubstitutionRule compatibility_rule, bool allow_cache); // Parse the vendor's JSONs into `read`, up to the first sub-file that fails. void parse_vendor_json(VendorRead& read); // Install what read_vendor read, against base_bundle's filament library. A cache // that cannot be installed is replaced by a parse of the JSONs. Throws // ConfigurationError at the first entry that cannot be installed, or after // installing the entries before a sub-file that could not be parsed. std::pair install_vendor_read(VendorRead&& read, const PresetBundle* base_bundle); // Install a cache's entries. False, with this bundle left clean, when one of them // cannot be installed. bool install_vendor_cache(const std::string& cache_path, const std::string& vendor_name, VendorCacheData&& data, const PresetBundle* base_bundle); // Log and count errors reported by a resolve or a parse. void log_errors(const std::vector& errors); // The state of installing one collection of one vendor, which // resolve_vendor_preset reads through a const reference and only // commit_vendor_preset writes. struct VendorInstall { // The directory holding /, whose sub-paths the entries name. std::string path; std::string vendor_name; const VendorProfile* vendor_profile; const PresetBundle* base_bundle; LoadConfigBundleAttributes flags; PresetCollection* presets; // The Orca filament library, which keeps every config for other vendors to // resolve against. bool is_from_lib; PresetsConfigSubstitutions* substitutions; // The names some entry inherits / includes, the only ones whose configs / // include diffs are looked up again. std::set inherited; std::set included; std::map config_maps; std::map include_maps; std::map filament_id_maps; std::unordered_set installed_names; size_t count { 0 }; }; // Install a vendor's source-form entries, parsed from its JSON or read from its // cache: processes, then filaments, then printers. Both loads go through here, // so a cache-loaded bundle cannot come out different from a JSON-loaded one. // `parsed` is given for entries parsed just now. `complete` says the entries // are the vendor's whole lists; only then are the filament library's configs // and filament ids left in m_config_maps and m_filament_id_maps. Returns the // number of presets installed, and throws ConfigurationError at the first // entry that cannot be installed. 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); // Install one collection's entries in the order they are listed. void install_vendor_entries(VendorInstall& install, const std::vector& entries, std::vector* parsed); // One entry flattened against the preset it inherits, before anything this // bundle shares has been touched. struct PresetInstall { DynamicPrintConfig config; std::string file_path; // Empty when the preset is its own alias. std::string alias; std::string filament_id; std::vector renamed_from; // Reported by commit, so resolving entries together leaves the log and // the error count as one entry at a time produces them. std::vector errors; // What a base states for the presets that include it, when it is retained. std::optional included; // The config kept for the entries that inherit this one, or for other // vendors when this is the filament library. std::optional retained; // Not instantiated, so it contributes a config and no preset. bool config_only { false }; // Non-empty when the entry is rejected, and says why. std::string reason; }; // Flatten one entry against the config it inherits, from this collection's // config_maps or base_bundle's filament library, with the include diffs it // names layered in. It looks up nothing but the names the entry inherits and // includes, and writes nothing. PresetInstall resolve_vendor_preset(const CachedPreset& entry, const VendorInstall& install) const; // Install a resolved entry. The collections, the maps in `install` and the // error count are touched here and only here, one entry at a time. // Presets are appended, so a repeated name is caught with `installed_names`, // and the collection is sorted once every entry is in. std::string commit_vendor_preset(const CachedPreset& entry, PresetInstall&& resolved, ConfigSubstitutions&& substitutions, VendorInstall& install); // Clear every collection's m_printer_hold_alias, which reset() leaves alone. void clear_printer_hold_aliases(); // Whether to (re)write a per-vendor cache after a JSON parse. bool m_generate_vendor_caches { false }; bool m_preserve_vendor_source_paths { false }; // Vendor trees loaded by resolve_preset_config's manifest path, so every preset // resolved through this bundle shares one load per source root and vendor. The // filament library is one such tree, shared by every vendor under its root. // A tree read from its preset cache is kept apart: its presets carry no source file. std::map, std::unique_ptr> m_source_vendor_bundles; 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); // Orca: validation only - flag any printer with two or more compatible // filament presets sharing one filament_id (ambiguous AMS subtype match). bool check_duplicate_filament_subtypes() const; //std::pair load_system_presets(ForwardCompatibilitySubstitutionRule compatibility_rule); //BBS: add json related logic // Reads each vendor from its preset cache where one covers the profile, as every load does. // write_caches = false keeps a read-only load from writing caches into the data directory. std::pair load_system_presets_from_json(ForwardCompatibilitySubstitutionRule compatibility_rule, bool write_caches = true); // Update the multicolor information for filaments. void update_filament_multi_color(); // Update renamed_from and alias maps of system profiles. void update_system_maps(); // Set the is_visible flag for filaments and sla materials, // apply defaults based on enabled printers when no filaments/materials are installed. void load_installed_filaments(AppConfig &config); void load_installed_sla_materials(AppConfig &config); // Load print, filament & printer presets from a config. If it is an external config, then the name is extracted from the external path. // and the external config is just referenced, not stored into user profile directory. // If it is not an external config, then the config will be stored into the user profile directory. 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); /*ConfigSubstitutions load_config_file_config_bundle( const std::string &path, const boost::property_tree::ptree &tree, ForwardCompatibilitySubstitutionRule compatibility_rule);*/ DynamicPrintConfig full_fff_config(bool apply_extruder, std::optional> filament_maps=std::nullopt, std::optional> filament_volume_maps=std::nullopt) const; DynamicPrintConfig full_sla_config() const; // Orca: used for validation only bool validation_mode = false; std::string vendor_to_validate = ""; int m_errors = 0; // The live SelectionExportBlockers. int m_selection_export_blockers = 0; // Helper function: save preset to bundle directory with common logic 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); }; ENABLE_ENUM_BITMASK_OPERATORS(PresetBundle::LoadConfigBundleAttribute) } // namespace Slic3r #endif /* slic3r_PresetBundle_hpp_ */