From 4f0894aa6c0cb9cea87ecf5958c307baf13c68be Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 20 Feb 2024 13:11:47 +0100 Subject: [PATCH 01/14] SPE-2028 : Implement the command line interface for querying presets --- src/PrusaSlicer.cpp | 100 ++++++- src/PrusaSlicer.hpp | 3 + src/libslic3r/PrintConfig.cpp | 39 ++- src/libslic3r/PrintConfig.hpp | 10 + src/slic3r/CMakeLists.txt | 2 + src/slic3r/Utils/ProfilesSharingUtils.cpp | 335 ++++++++++++++++++++++ src/slic3r/Utils/ProfilesSharingUtils.hpp | 16 ++ 7 files changed, 502 insertions(+), 3 deletions(-) create mode 100644 src/slic3r/Utils/ProfilesSharingUtils.cpp create mode 100644 src/slic3r/Utils/ProfilesSharingUtils.hpp diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 685bc42bb1..d8ca4f1d4d 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -32,6 +32,9 @@ #include #include #include +#include +#include +#include #include #include "unix/fhs.hpp" // Generated by CMake from ../platform/unix/fhs.hpp.in @@ -61,6 +64,8 @@ #include "PrusaSlicer.hpp" +#include "slic3r/Utils/ProfilesSharingUtils.hpp" + #ifdef SLIC3R_GUI #include "slic3r/GUI/GUI_Init.hpp" #endif /* SLIC3R_GUI */ @@ -693,6 +698,8 @@ int CLI::run(int argc, char **argv) } } + if (processed_profiles_sharing()) + return 1; if (start_gui) { #ifdef SLIC3R_GUI @@ -815,6 +822,8 @@ bool CLI::setup(int argc, char **argv) m_actions.emplace_back(opt_key); else if (cli_transform_config_def.has(opt_key)) m_transforms.emplace_back(opt_key); + else if (cli_profiles_sharing_config_def.has(opt_key)) + m_profiles_sharing.emplace_back(opt_key); } { @@ -833,7 +842,10 @@ bool CLI::setup(int argc, char **argv) std::string validity = m_config.validate(); // Initialize with defaults. - for (const t_optiondef_map *options : { &cli_actions_config_def.options, &cli_transform_config_def.options, &cli_misc_config_def.options }) + for (const t_optiondef_map *options : { &cli_actions_config_def.options + , &cli_transform_config_def.options + , &cli_profiles_sharing_config_def.options + , &cli_misc_config_def.options }) for (const t_optiondef_map::value_type &optdef : *options) m_config.option(optdef.first, true); @@ -863,6 +875,7 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn << std::endl << "Actions:" << std::endl; cli_actions_config_def.print_cli_help(boost::nowide::cout, false); + cli_profiles_sharing_config_def.print_cli_help(boost::nowide::cout, false); boost::nowide::cout << std::endl @@ -874,6 +887,11 @@ void CLI::print_help(bool include_print_options, PrinterTechnology printer_techn << "Other options:" << std::endl; cli_misc_config_def.print_cli_help(boost::nowide::cout, false); + //boost::nowide::cout + // << std::endl + // << "Profiles sharing options:" << std::endl; + // cli_profiles_sharing_config_def.print_cli_help(boost::nowide::cout, false); + boost::nowide::cout << std::endl << "Print options are processed in the following order:" << std::endl @@ -939,6 +957,86 @@ std::string CLI::output_filepath(const Model &model, IO::ExportFormat format) co return proposed_path.string(); } +std::set query_options = { + "printer-profile" +}; + +bool CLI::processed_profiles_sharing() +{ + if (m_profiles_sharing.empty()) + return false; + + std::string ret; + for (auto const& opt_key : m_profiles_sharing) { + if (query_options.find(opt_key) != query_options.end()) + continue; + if (opt_key == "query-printer-models") { + ret = Slic3r::get_json_printer_models(Preset::printer_technology(m_config)); + } + else if (opt_key == "query-printer-profiles") { + if (!m_config.has("printer_model") || !m_config.has("printer_variant")) { + boost::nowide::cerr << "error in '" << opt_key << "' : this action requires set 'printer-model' and 'printer-variant' options" << std::endl; + break; + } + ret = Slic3r::get_json_printer_profiles(m_config.opt_string("printer_model"), m_config.opt_string("printer_variant")); + + if (ret.empty()) + ret = "\nPrinter_model '" + m_config.opt_string("printer_model") + + "' with printer_variant '" + m_config.opt_string("printer_variant") + + "' wasn't found among intalled printers.\nOr the request can be wrong.\n"; + } + else if (opt_key == "query-print-filament-profiles") { + if (!m_config.has("printer-profile")) { + boost::nowide::cerr << "error: this action requires set printer-preset option" << opt_key << std::endl; + break; + } + ret = Slic3r::get_json_print_filament_profiles(m_config.opt_string("printer-profile")); + + if (ret.empty()) + ret = "\nPrinter profile '" + m_config.opt_string("printer-profile") + + "' wasn't found among intalled printers.\nOr the request can be wrong.\n"; + } + else { + boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; + break; + } + } + + // use --output when available + + std::string cmdline_param = m_config.opt_string("output"); + if (cmdline_param.empty()) { + printf("\n"); + if (ret.empty()) + printf("Wrong request"); + else + printf(ret.c_str()); + } + else { + // if we were supplied a directory, use it and append our automatically generated filename + boost::filesystem::path cmdline_path(cmdline_param); + boost::filesystem::path proposed_path = boost::filesystem::path(Slic3r::resources_dir()) / "out.json"; + if (boost::filesystem::is_directory(cmdline_path)) + proposed_path = (cmdline_path / proposed_path.filename()); + else if (cmdline_path.extension().empty()) + proposed_path = cmdline_path.replace_extension("json"); + else + proposed_path = cmdline_path; + const std::string file = proposed_path.string(); + + boost::nowide::ofstream c; + c.open(file, std::ios::out | std::ios::trunc); + c << ret << std::endl; + c.close(); + + printf("\nOutput for your request in written into \""); + printf(file.c_str()); + printf("\"\n"); + } + + return true; +} + // __has_feature() is used later for Clang, this is for compatibility with other compilers (such as GCC and MSVC) #ifndef __has_feature # define __has_feature(x) 0 diff --git a/src/PrusaSlicer.hpp b/src/PrusaSlicer.hpp index 0554580e53..8910f56980 100644 --- a/src/PrusaSlicer.hpp +++ b/src/PrusaSlicer.hpp @@ -28,6 +28,7 @@ private: std::vector m_input_files; std::vector m_actions; std::vector m_transforms; + std::vector m_profiles_sharing; std::vector m_models; bool setup(int argc, char **argv); @@ -39,6 +40,8 @@ private: bool export_models(IO::ExportFormat format); bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); } + + bool processed_profiles_sharing(); std::string output_filepath(const Model &model, IO::ExportFormat format) const; }; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 4404aea7be..59f1b08527 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2191,7 +2191,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Printer type"); def->tooltip = L("Type of the printer."); def->set_default_value(new ConfigOptionString()); - def->cli = ConfigOptionDef::nocli; +// def->cli = ConfigOptionDef::nocli; def = this->add("printer_notes", coString); def->label = L("Printer notes"); @@ -2212,7 +2212,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Printer variant"); def->tooltip = L("Name of the printer variant. For example, the printer variants may be differentiated by a nozzle diameter."); def->set_default_value(new ConfigOptionString()); - def->cli = ConfigOptionDef::nocli; +// def->cli = ConfigOptionDef::nocli; def = this->add("print_settings_id", coString); def->set_default_value(new ConfigOptionString("")); @@ -5121,15 +5121,50 @@ CLIMiscConfigDef::CLIMiscConfigDef() #endif /* _MSC_VER */ } +CLIProfilesSharingConfigDef::CLIProfilesSharingConfigDef() +{ + ConfigOptionDef* def; + + def = this->add("query-printer-models", coBool); + def->label = L("Get list of printer models"); + def->tooltip = L("Get available printer models into JSON.\n" + "Note:\nTo print printer models for required technology use 'printer-technology' option. By default printer_technology is FFF.\n" + "To print out JSON into file use 'output' option.\n" + "To specify configuration folder use 'datadir' option. Otherwise all known vendors will be loaded and processed."); + + + def = this->add("query-printer-profiles", coBool); + def->label = L("Get list of printer profiles in respect to selected printer model and printer variant"); + def->tooltip = L("Get list of printer profiles in respect to selected 'printer-model' and 'printer-variant' into JSON.\n" + "Note:\n" + "To print out JSON into file use 'output' option.\n" + "To specify configuration folder use 'datadir' option. Otherwise all known vendors will be loaded and processed."); + + + def = this->add("query-print-filament-profiles", coBool); + def->label = L("Get list of prints and filaments profiles in respect to selected printer profile"); + def->tooltip = L("Get list of prints and filaments profiles in respect to selected 'printer-profile' into JSON.\n" + "Note:\n" + "To print out JSON into file use 'output' option.\n" + "To specify configuration folder use 'datadir' option. Otherwise all known vendors will be loaded and processed."); + + def = this->add("printer-profile", coString); + def->label = L("Printer preset name"); + def->tooltip = L("Name of the printer preset used for slicing."); + def->set_default_value(new ConfigOptionString()); +} + const CLIActionsConfigDef cli_actions_config_def; const CLITransformConfigDef cli_transform_config_def; const CLIMiscConfigDef cli_misc_config_def; +const CLIProfilesSharingConfigDef cli_profiles_sharing_config_def; DynamicPrintAndCLIConfig::PrintAndCLIConfigDef DynamicPrintAndCLIConfig::s_def; void DynamicPrintAndCLIConfig::handle_legacy(t_config_option_key &opt_key, std::string &value) const { if (cli_actions_config_def .options.find(opt_key) == cli_actions_config_def .options.end() && + cli_profiles_sharing_config_def.options.find(opt_key) == cli_profiles_sharing_config_def.options.end() && cli_transform_config_def.options.find(opt_key) == cli_transform_config_def.options.end() && cli_misc_config_def .options.find(opt_key) == cli_misc_config_def .options.end()) { PrintConfigDef::handle_legacy(opt_key, value); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index f1dc6b96a4..c14230d4f4 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1211,6 +1211,12 @@ public: CLIMiscConfigDef(); }; +class CLIProfilesSharingConfigDef : public ConfigDef +{ +public: + CLIProfilesSharingConfigDef(); +}; + typedef std::string t_custom_gcode_key; // This map containes list of specific placeholders for each custom G-code, if any exist const std::map& custom_gcode_specific_placeholders(); @@ -1282,6 +1288,9 @@ extern const CLITransformConfigDef cli_transform_config_def; // This class defines all command line options that are not actions or transforms. extern const CLIMiscConfigDef cli_misc_config_def; +// This class defines the command line options representing profiles sharing commands. +extern const CLIProfilesSharingConfigDef cli_profiles_sharing_config_def; + class DynamicPrintAndCLIConfig : public DynamicPrintConfig { public: @@ -1306,6 +1315,7 @@ private: this->options.insert(cli_actions_config_def.options.begin(), cli_actions_config_def.options.end()); this->options.insert(cli_transform_config_def.options.begin(), cli_transform_config_def.options.end()); this->options.insert(cli_misc_config_def.options.begin(), cli_misc_config_def.options.end()); + this->options.insert(cli_profiles_sharing_config_def.options.begin(), cli_profiles_sharing_config_def.options.end()); for (const auto &kvp : this->options) this->by_serialization_key_ordinal[kvp.second.serialization_key_ordinal] = &kvp.second; } diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index fea794c943..d22dc873ce 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -335,6 +335,8 @@ set(SLIC3R_GUI_SOURCES Utils/WxFontUtils.hpp Utils/WifiScanner.hpp Utils/WifiScanner.cpp + Utils/ProfilesSharingUtils.hpp + Utils/ProfilesSharingUtils.cpp ) find_package(NanoSVG REQUIRED) diff --git a/src/slic3r/Utils/ProfilesSharingUtils.cpp b/src/slic3r/Utils/ProfilesSharingUtils.cpp new file mode 100644 index 0000000000..adfbab9bdb --- /dev/null +++ b/src/slic3r/Utils/ProfilesSharingUtils.cpp @@ -0,0 +1,335 @@ +///|/ Copyright (c) Prusa Research 2021 - 2023 Oleksandra Iushchenko @YuSanka +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#include "ProfilesSharingUtils.hpp" +#include "libslic3r/utils.hpp" + +#include "slic3r/GUI/ConfigWizard_private.hpp" +#include "slic3r/GUI/format.hpp" + +#include + +namespace Slic3r { + +namespace pt = boost::property_tree; + +using namespace GUI; + +static pt::ptree get_printer_models_for_vendor(const VendorProfile* vendor_profile, PrinterTechnology printer_technology) +{ + pt::ptree vendor_node; + + for (const auto& printer_model : vendor_profile->models) { + if (printer_technology != ptAny && printer_model.technology != printer_technology) + continue; + + pt::ptree data_node; + data_node.put("vendor_name", vendor_profile->name); + data_node.put("id", printer_model.id); + data_node.put("name", printer_model.name); + + if (printer_model.technology == ptFFF) { + pt::ptree variants_node; + for (const auto& variant : printer_model.variants) { + pt::ptree variant_node; + variant_node.put("", variant.name); + variants_node.push_back(std::make_pair("", variant_node)); + } + data_node.add_child("variants", variants_node); + } + + data_node.put("technology", printer_model.technology == ptFFF ? "FFF" : "SLA"); + data_node.put("family", printer_model.family); + + pt::ptree def_materials_node; + for (const std::string& material : printer_model.default_materials) { + pt::ptree material_node; + material_node.put("", material); + def_materials_node.push_back(std::make_pair("", material_node)); + } + data_node.add_child("default_materials", def_materials_node); + + vendor_node.push_back(std::make_pair("", data_node)); + } + + return vendor_node; +} + +static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle) +{ + AppConfig app_config = AppConfig(AppConfig::EAppMode::Editor); + if (!app_config.exists()) { + printf("Configuration wasn't found. Check your 'datadir' value.\n"); + return false; + } + + printf("Loading: AppConfig"); + + if (std::string error = app_config.load(); !error.empty()) { + throw Slic3r::RuntimeError(Slic3r::format("Error parsing PrusaSlicer config file, it is probably corrupted. " + "Try to manually delete the file to recover from the error. Your user profiles will not be affected." + "\n\n%1%\n\n%2%", app_config.config_path(), error)); + return false; + } + + // just checking for existence of Slic3r::data_dir is not enough : it may be an empty directory + // supplied as argument to --datadir; in that case we should still run the wizard + preset_bundle.setup_directories(); + + std::string delayed_error_load_presets; + // Suppress the '- default -' presets. + preset_bundle.set_default_suppressed(app_config.get_bool("no_defaults")); + try { + printf(", presets"); + auto preset_substitutions = preset_bundle.load_presets(app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent); + if (!preset_substitutions.empty()) { + printf("Some substitutions are found during loading presets.\n"); + return false; + } + + // Post-process vendor map to delete non-installed models/varians + + VendorMap& vendors = preset_bundle.vendors; + for (auto& [vendor_id, vendor_profile] : vendors) { + std::vector models; + + for (auto& printer_model : vendor_profile.models) { + std::vector variants; + + for (const auto& variant : printer_model.variants) { + // check if printer model with variant is intalled + if (app_config.get_variant(vendor_id, printer_model.id, variant.name)) + variants.push_back(variant); + } + + if (!variants.empty()) { + if (printer_model.variants.size() != variants.size()) + printer_model.variants = variants; + models.push_back(printer_model); + } + } + + if (!models.empty()) { + if (vendor_profile.models.size() != models.size()) + vendor_profile.models = models; + } + } + + return true; + } + catch (const std::exception& ex) { + delayed_error_load_presets = ex.what(); + printf(delayed_error_load_presets.c_str()); + return false; + } +} + +std::string get_json_printer_models(PrinterTechnology printer_technology) +{ + // Build a property tree with all the information. + pt::ptree root; + + if (data_dir().empty()) { + printf("Loading of all known vendors ."); + BundleMap bundles = BundleMap::load(); + + for (const auto& [bundle_id, bundle] : bundles) { + pt::ptree vendor_node = get_printer_models_for_vendor(bundle.vendor_profile, printer_technology); + if (!vendor_node.empty()) + root.add_child(bundle_id, vendor_node); + } + } + else { + PresetBundle preset_bundle; + if (!load_preset_bandle_from_datadir(preset_bundle)) + return ""; + printf(", vendors"); + + const VendorMap& vendors_map = preset_bundle.vendors; + for (const auto& [vendor_id, vendor] : vendors_map) { + pt::ptree vendor_node = get_printer_models_for_vendor(&vendor, printer_technology); + if (!vendor_node.empty()) + root.add_child(vendor_id, vendor_node); + } + } + + // Serialize the tree into JSON and return it. + std::stringstream ss; + pt::write_json(ss, root); + return ss.str(); +} + + + +struct PrinterAttr +{ + std::string model_name; + std::string variant; +}; + +static std::string get_printer_profiles(const VendorProfile* vendor_profile, + const PresetBundle* preset_bundle, + const PrinterAttr& printer_attr) +{ + for (const auto& printer_model : vendor_profile->models) { + if (printer_model.name != printer_attr.model_name) + continue; + + for (const auto& variant : printer_model.variants) + if (variant.name == printer_attr.variant) + { + pt::ptree data_node; + data_node.put("printer_model", printer_model.name); + data_node.put("printer_variant", printer_attr.variant); + + pt::ptree printer_profiles_node; + for (const Preset& printer_preset : preset_bundle->printers) { + if (printer_preset.vendor->id == vendor_profile->id && + printer_preset.is_visible && // ??? + printer_preset.config.opt_string("printer_model") == printer_model.id && + printer_preset.config.opt_string("printer_variant") == printer_attr.variant) { + pt::ptree profile_node; + profile_node.put("", printer_preset.name); + printer_profiles_node.push_back(std::make_pair("", profile_node)); + } + } + data_node.add_child("printer_profiles", printer_profiles_node); + + // Serialize the tree into JSON and return it. + std::stringstream ss; + pt::write_json(ss, data_node); + return ss.str(); + } + } + + return ""; +} + +std::string get_json_printer_profiles(const std::string& printer_model_name, const std::string& printer_variant) +{ + PrinterAttr printer_attr({printer_model_name, printer_variant}); + + if (data_dir().empty()) { + printf("Loading of all known vendors ."); + BundleMap bundles = BundleMap::load(); + + for (const auto& [bundle_id, bundle] : bundles) { + std::string out = get_printer_profiles(bundle.vendor_profile, bundle.preset_bundle.get(), printer_attr); + if (!out.empty()) + return out; + } + } + else { + PresetBundle preset_bundle; + if (!load_preset_bandle_from_datadir(preset_bundle)) + return ""; + printf(", vendors"); + + const VendorMap& vendors = preset_bundle.vendors; + for (const auto& [vendor_id, vendor] : vendors) { + std::string out = get_printer_profiles(&vendor, &preset_bundle, printer_attr); + if (!out.empty()) + return out; + } + } + + return ""; +} + + +static std::string get_installed_print_and_filament_profiles(const PresetBundle* preset_bundle, const Preset* printer_preset) +{ + PrinterTechnology printer_technology = printer_preset->printer_technology(); + + printf("\n\nSearching for compatible print profiles ."); + + pt::ptree print_profiles; + + const PresetWithVendorProfile printer_preset_with_vendor_profile = preset_bundle->printers.get_preset_with_vendor_profile(*printer_preset); + + const PresetCollection& print_presets = printer_technology == ptFFF ? preset_bundle->prints : preset_bundle->sla_prints; + const PresetCollection& material_presets = printer_technology == ptFFF ? preset_bundle->filaments : preset_bundle->sla_materials; + const std::string material_node_name = printer_technology == ptFFF ? "filament_profiles" : "sla_material_profiles"; + + int output_counter{ 0 }; + for (auto print_preset : print_presets) { + + ++output_counter; + if (output_counter == 10) { + printf("."); + output_counter = 0; + } + + const PresetWithVendorProfile print_preset_with_vendor_profile = print_presets.get_preset_with_vendor_profile(print_preset); + + if (is_compatible_with_printer(print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) + { + pt::ptree print_profile_node; + print_profile_node.put("name", print_preset.name); + + pt::ptree materials_profile_node; + + for (auto material_preset : material_presets) { + + // ?! check visible and no-template presets only + if (!material_preset.is_visible || material_preset.vendor->templates_profile) + continue; + + const PresetWithVendorProfile material_preset_with_vendor_profile = material_presets.get_preset_with_vendor_profile(material_preset); + + if (is_compatible_with_printer(material_preset_with_vendor_profile, printer_preset_with_vendor_profile) && + is_compatible_with_print(material_preset_with_vendor_profile, print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) { + pt::ptree material_node; + material_node.put("", material_preset.name); + materials_profile_node.push_back(std::make_pair("", material_node)); + } + } + + print_profile_node.add_child(material_node_name, materials_profile_node); + print_profiles.push_back(std::make_pair("", print_profile_node)); + } + } + + printf("\n"); + + if (print_profiles.empty()) + return ""; + + pt::ptree tree; + tree.put("printer_profile", printer_preset->name); + tree.add_child("print_profiles", print_profiles); + + // Serialize the tree into JSON and return it. + std::stringstream ss; + pt::write_json(ss, tree); + return ss.str(); +} + +std::string get_json_print_filament_profiles(const std::string& printer_profile) +{ + if (data_dir().empty()) { + printf("Loading of all known vendors ."); + BundleMap bundles = BundleMap::load(); + + printf(GUI::format("\n\nSearching for \"%1%\" .", printer_profile).c_str()); + + for (const auto& [bundle_id, bundle] : bundles) { + printf("."); + if (const Preset* preset = bundle.preset_bundle->printers.find_preset(printer_profile, false, false)) + return get_installed_print_and_filament_profiles(bundle.preset_bundle.get(), preset); + } + } + else { + PresetBundle preset_bundle; + if (!load_preset_bandle_from_datadir(preset_bundle)) + return ""; + + if (const Preset* preset = preset_bundle.printers.find_preset(printer_profile, false, false)) + return get_installed_print_and_filament_profiles(&preset_bundle, preset); + } + + return ""; +} + +} // namespace Slic3r diff --git a/src/slic3r/Utils/ProfilesSharingUtils.hpp b/src/slic3r/Utils/ProfilesSharingUtils.hpp new file mode 100644 index 0000000000..ab870f8984 --- /dev/null +++ b/src/slic3r/Utils/ProfilesSharingUtils.hpp @@ -0,0 +1,16 @@ +///|/ Copyright (c) Prusa Research 2021 Oleksandra Iushchenko @YuSanka +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ +#ifndef slic3r_ProfilesSharingUtils_hpp_ +#define slic3r_ProfilesSharingUtils_hpp_ + +namespace Slic3r { + +std::string get_json_printer_models(PrinterTechnology printer_technology); +std::string get_json_printer_profiles(const std::string& printer_model, const std::string& printer_variant); +std::string get_json_print_filament_profiles(const std::string& printer_profile); + +} // namespace Slic3r + +#endif // slic3r_ProfilesSharingUtils_hpp_ From 4e997d8dd5e8a0d2f4f4fcf38a3c3c288ff8ca57 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 21 Feb 2024 12:13:21 +0100 Subject: [PATCH 02/14] ProfilesSharingUtils : Implemented detection of the application DataDir to avoid manual set for this value. Use just native functions (without wxWidgets) Note: Most of code is extracted from wxWidgest (wxStandardPaths and wxFileName classes implementation) to avoid use of wxString --- src/libslic3r/libslic3r.h | 5 + src/slic3r/GUI/GUI_App.cpp | 13 +-- src/slic3r/Utils/MacUtils.mm | 12 +++ src/slic3r/Utils/ProfilesSharingUtils.cpp | 107 +++++++++++++++++++++- src/slic3r/Utils/ProfilesSharingUtils.hpp | 7 ++ 5 files changed, 130 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 4b39b4bc40..0f24b85f5e 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -15,6 +15,11 @@ #define _libslic3r_h_ #include "libslic3r_version.h" + +//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME +#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME "-alpha" +//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME "-beta" + #define GCODEVIEWER_APP_NAME "PrusaSlicer G-code Viewer" #define GCODEVIEWER_APP_KEY "PrusaSlicerGcodeViewer" diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index ebd79f8892..eb9c04cfcb 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -923,18 +923,7 @@ static boost::optional parse_semver_from_ini(std::string path) void GUI_App::init_app_config() { // Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release. - -// SetAppName(SLIC3R_APP_KEY); - SetAppName(SLIC3R_APP_KEY "-alpha"); -// SetAppName(SLIC3R_APP_KEY "-beta"); - - -// SetAppDisplayName(SLIC3R_APP_NAME); - - // Set the Slic3r data directory at the Slic3r XS module. - // Unix: ~/ .Slic3rP - // Windows : "C:\Users\username\AppData\Roaming\Slic3r" or "C:\Documents and Settings\username\Application Data\Slic3r" - // Mac : "~/Library/Application Support/Slic3r" + SetAppName(SLIC3R_APP_FULL_NAME); if (data_dir().empty()) { #ifndef __linux__ diff --git a/src/slic3r/Utils/MacUtils.mm b/src/slic3r/Utils/MacUtils.mm index 31a28f14e4..b570dd566d 100644 --- a/src/slic3r/Utils/MacUtils.mm +++ b/src/slic3r/Utils/MacUtils.mm @@ -1,4 +1,5 @@ #import "AppUpdater.hpp" +#import "ProfilesSharingUtils.hpp" #import @@ -15,4 +16,15 @@ std::string get_downloads_path_mac() //[NSURL fileURLWithPath:[NSHomeDirectory() stringByAppendingPathComponent:@"Downloads"]]; //return std::string(); } + +// ProfilesSharingUtils.hpp +std::string GetDataDir() +{ + NSURL* url = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory + inDomain:NSUserDomainMask + appropriateForURL:nil create:NO error:nil]; + + return std::string([(CFStringRef)url.path UTF8String]); +} + } diff --git a/src/slic3r/Utils/ProfilesSharingUtils.cpp b/src/slic3r/Utils/ProfilesSharingUtils.cpp index adfbab9bdb..081182b5de 100644 --- a/src/slic3r/Utils/ProfilesSharingUtils.cpp +++ b/src/slic3r/Utils/ProfilesSharingUtils.cpp @@ -3,15 +3,109 @@ ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher ///|/ #include "ProfilesSharingUtils.hpp" -#include "libslic3r/utils.hpp" - +#include "libslic3r/Utils.hpp" #include "slic3r/GUI/ConfigWizard_private.hpp" #include "slic3r/GUI/format.hpp" #include +#if defined(_WIN32) + +#include + +static std::string GetDataDir() +{ + HRESULT hr = E_FAIL; + + std::wstring buffer; + buffer.resize(MAX_PATH); + + hr = ::SHGetFolderPath + ( + NULL, // parent window, not used + CSIDL_APPDATA, + NULL, // access token (current user) + SHGFP_TYPE_CURRENT, // current path, not just default value + (LPWSTR)buffer.data() + ); + + // somewhat incredibly, the error code in the Unicode version is + // different from the one in ASCII version for this function +#if wxUSE_UNICODE + if (hr == E_FAIL) +#else + if (hr == S_FALSE) +#endif + { + // directory doesn't exist, maybe we can get its default value? + hr = ::SHGetFolderPath + ( + NULL, + CSIDL_APPDATA, + NULL, + SHGFP_TYPE_DEFAULT, + (LPWSTR)buffer.data() + ); + } + + for (int i=0; i< MAX_PATH; i++) + if (buffer.data()[i] == '\0') { + buffer.resize(i); + break; + } + + return boost::nowide::narrow(buffer); +} + +#elif defined(__linux__) + +#include +#include + +static std::string GetDataDir() +{ + std::string dir; + + char* ptr; + if ((ptr = getenv("XDG_CONFIG_HOME"))) + dir = std::string(ptr); + else { + if ((ptr = getenv("HOME"))) + dir = std::string(ptr); + else { + struct passwd* who = (struct passwd*)NULL; + if ((ptr = getenv("USER")) || (ptr = getenv("LOGNAME"))) + who = getpwnam(ptr); + // make sure the user exists! + if (!who) + who = getpwuid(getuid()); + + dir = std::string(who ? who->pw_dir : 0); + } + dir += "/.config"; + } + + if (dir.empty()) + printf("GetDataDir() > unsupported file layout \n"); + + return dir; +} + +#endif + namespace Slic3r { +static bool is_datadir() +{ + if (!data_dir().empty()) + return true; + + const std::string config_dir = GetDataDir(); + const std::string data_dir = (boost::filesystem::path(config_dir) / SLIC3R_APP_FULL_NAME).make_preferred().string(); + + set_data_dir(data_dir); + return true; +} namespace pt = boost::property_tree; using namespace GUI; @@ -127,6 +221,9 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle) std::string get_json_printer_models(PrinterTechnology printer_technology) { + if (!is_datadir()) + return ""; + // Build a property tree with all the information. pt::ptree root; @@ -208,6 +305,9 @@ static std::string get_printer_profiles(const VendorProfile* vendor_profile, std::string get_json_printer_profiles(const std::string& printer_model_name, const std::string& printer_variant) { + if (!is_datadir()) + return ""; + PrinterAttr printer_attr({printer_model_name, printer_variant}); if (data_dir().empty()) { @@ -308,6 +408,9 @@ static std::string get_installed_print_and_filament_profiles(const PresetBundle* std::string get_json_print_filament_profiles(const std::string& printer_profile) { + if (!is_datadir()) + return ""; + if (data_dir().empty()) { printf("Loading of all known vendors ."); BundleMap bundles = BundleMap::load(); diff --git a/src/slic3r/Utils/ProfilesSharingUtils.hpp b/src/slic3r/Utils/ProfilesSharingUtils.hpp index ab870f8984..4de698cc7d 100644 --- a/src/slic3r/Utils/ProfilesSharingUtils.hpp +++ b/src/slic3r/Utils/ProfilesSharingUtils.hpp @@ -5,12 +5,19 @@ #ifndef slic3r_ProfilesSharingUtils_hpp_ #define slic3r_ProfilesSharingUtils_hpp_ +#include "libslic3r/Config.hpp" + namespace Slic3r { std::string get_json_printer_models(PrinterTechnology printer_technology); std::string get_json_printer_profiles(const std::string& printer_model, const std::string& printer_variant); std::string get_json_print_filament_profiles(const std::string& printer_profile); +#if __APPLE__ +//implemented at MacUtils.mm +std::string GetDataDir(); +#endif //__APPLE__ + } // namespace Slic3r #endif // slic3r_ProfilesSharingUtils_hpp_ From 61ceac8ea2f740e8040511a2a258a1cb444c5d29 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 4 Jan 2024 10:13:52 +0100 Subject: [PATCH 03/14] ProfilesSharingUtils : Improvements for requests. * "query-printer-models" is extended to expose printer presets for each printer variant * "query-printer-profiles" is currently commented as not-used * "query-print-filament-profiles" is extended to expose "is_user_profile" state for each print/material profiles + Removed includes related to GUI. + Removed a code to loaded all known vendors. --- src/PrusaSlicer.cpp | 2 + src/libslic3r/PrintConfig.cpp | 13 +- src/slic3r/Utils/ProfilesSharingUtils.cpp | 275 ++++++++++++---------- src/slic3r/Utils/ProfilesSharingUtils.hpp | 2 +- 4 files changed, 154 insertions(+), 138 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index d8ca4f1d4d..4ca32a2113 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -973,6 +973,7 @@ bool CLI::processed_profiles_sharing() if (opt_key == "query-printer-models") { ret = Slic3r::get_json_printer_models(Preset::printer_technology(m_config)); } +/* else if (opt_key == "query-printer-profiles") { if (!m_config.has("printer_model") || !m_config.has("printer_variant")) { boost::nowide::cerr << "error in '" << opt_key << "' : this action requires set 'printer-model' and 'printer-variant' options" << std::endl; @@ -985,6 +986,7 @@ bool CLI::processed_profiles_sharing() "' with printer_variant '" + m_config.opt_string("printer_variant") + "' wasn't found among intalled printers.\nOr the request can be wrong.\n"; } +*/ else if (opt_key == "query-print-filament-profiles") { if (!m_config.has("printer-profile")) { boost::nowide::cerr << "error: this action requires set printer-preset option" << opt_key << std::endl; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 59f1b08527..1ec641d672 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5129,24 +5129,21 @@ CLIProfilesSharingConfigDef::CLIProfilesSharingConfigDef() def->label = L("Get list of printer models"); def->tooltip = L("Get available printer models into JSON.\n" "Note:\nTo print printer models for required technology use 'printer-technology' option. By default printer_technology is FFF.\n" - "To print out JSON into file use 'output' option.\n" - "To specify configuration folder use 'datadir' option. Otherwise all known vendors will be loaded and processed."); - + "To print out JSON into file use 'output' option."); +/* def = this->add("query-printer-profiles", coBool); def->label = L("Get list of printer profiles in respect to selected printer model and printer variant"); def->tooltip = L("Get list of printer profiles in respect to selected 'printer-model' and 'printer-variant' into JSON.\n" "Note:\n" - "To print out JSON into file use 'output' option.\n" - "To specify configuration folder use 'datadir' option. Otherwise all known vendors will be loaded and processed."); - + "To print out JSON into file use 'output' option."); +*/ def = this->add("query-print-filament-profiles", coBool); def->label = L("Get list of prints and filaments profiles in respect to selected printer profile"); def->tooltip = L("Get list of prints and filaments profiles in respect to selected 'printer-profile' into JSON.\n" "Note:\n" - "To print out JSON into file use 'output' option.\n" - "To specify configuration folder use 'datadir' option. Otherwise all known vendors will be loaded and processed."); + "To print out JSON into file use 'output' option."); def = this->add("printer-profile", coString); def->label = L("Printer preset name"); diff --git a/src/slic3r/Utils/ProfilesSharingUtils.cpp b/src/slic3r/Utils/ProfilesSharingUtils.cpp index 081182b5de..4857704f34 100644 --- a/src/slic3r/Utils/ProfilesSharingUtils.cpp +++ b/src/slic3r/Utils/ProfilesSharingUtils.cpp @@ -4,8 +4,9 @@ ///|/ #include "ProfilesSharingUtils.hpp" #include "libslic3r/Utils.hpp" -#include "slic3r/GUI/ConfigWizard_private.hpp" -#include "slic3r/GUI/format.hpp" +#include "libslic3r/format.hpp" +#include "libslic3r/PrintConfig.hpp" +#include "libslic3r/PresetBundle.hpp" #include @@ -106,49 +107,6 @@ static bool is_datadir() set_data_dir(data_dir); return true; } -namespace pt = boost::property_tree; - -using namespace GUI; - -static pt::ptree get_printer_models_for_vendor(const VendorProfile* vendor_profile, PrinterTechnology printer_technology) -{ - pt::ptree vendor_node; - - for (const auto& printer_model : vendor_profile->models) { - if (printer_technology != ptAny && printer_model.technology != printer_technology) - continue; - - pt::ptree data_node; - data_node.put("vendor_name", vendor_profile->name); - data_node.put("id", printer_model.id); - data_node.put("name", printer_model.name); - - if (printer_model.technology == ptFFF) { - pt::ptree variants_node; - for (const auto& variant : printer_model.variants) { - pt::ptree variant_node; - variant_node.put("", variant.name); - variants_node.push_back(std::make_pair("", variant_node)); - } - data_node.add_child("variants", variants_node); - } - - data_node.put("technology", printer_model.technology == ptFFF ? "FFF" : "SLA"); - data_node.put("family", printer_model.family); - - pt::ptree def_materials_node; - for (const std::string& material : printer_model.default_materials) { - pt::ptree material_node; - material_node.put("", material); - def_materials_node.push_back(std::make_pair("", material_node)); - } - data_node.add_child("default_materials", def_materials_node); - - vendor_node.push_back(std::make_pair("", data_node)); - } - - return vendor_node; -} static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle) { @@ -219,47 +177,9 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle) } } -std::string get_json_printer_models(PrinterTechnology printer_technology) -{ - if (!is_datadir()) - return ""; - - // Build a property tree with all the information. - pt::ptree root; - - if (data_dir().empty()) { - printf("Loading of all known vendors ."); - BundleMap bundles = BundleMap::load(); - - for (const auto& [bundle_id, bundle] : bundles) { - pt::ptree vendor_node = get_printer_models_for_vendor(bundle.vendor_profile, printer_technology); - if (!vendor_node.empty()) - root.add_child(bundle_id, vendor_node); - } - } - else { - PresetBundle preset_bundle; - if (!load_preset_bandle_from_datadir(preset_bundle)) - return ""; - printf(", vendors"); - - const VendorMap& vendors_map = preset_bundle.vendors; - for (const auto& [vendor_id, vendor] : vendors_map) { - pt::ptree vendor_node = get_printer_models_for_vendor(&vendor, printer_technology); - if (!vendor_node.empty()) - root.add_child(vendor_id, vendor_node); - } - } - - // Serialize the tree into JSON and return it. - std::stringstream ss; - pt::write_json(ss, root); - return ss.str(); -} - - - -struct PrinterAttr +namespace pt = boost::property_tree; +/* +struct PrinterAttr_ { std::string model_name; std::string variant; @@ -267,7 +187,7 @@ struct PrinterAttr static std::string get_printer_profiles(const VendorProfile* vendor_profile, const PresetBundle* preset_bundle, - const PrinterAttr& printer_attr) + const PrinterAttr_& printer_attr) { for (const auto& printer_model : vendor_profile->models) { if (printer_model.name != printer_attr.model_name) @@ -308,35 +228,144 @@ std::string get_json_printer_profiles(const std::string& printer_model_name, con if (!is_datadir()) return ""; - PrinterAttr printer_attr({printer_model_name, printer_variant}); + PrinterAttr_ printer_attr({printer_model_name, printer_variant}); - if (data_dir().empty()) { - printf("Loading of all known vendors ."); - BundleMap bundles = BundleMap::load(); + PresetBundle preset_bundle; + if (!load_preset_bandle_from_datadir(preset_bundle)) + return ""; + printf(", vendors"); - for (const auto& [bundle_id, bundle] : bundles) { - std::string out = get_printer_profiles(bundle.vendor_profile, bundle.preset_bundle.get(), printer_attr); - if (!out.empty()) - return out; - } - } - else { - PresetBundle preset_bundle; - if (!load_preset_bandle_from_datadir(preset_bundle)) - return ""; - printf(", vendors"); - - const VendorMap& vendors = preset_bundle.vendors; - for (const auto& [vendor_id, vendor] : vendors) { - std::string out = get_printer_profiles(&vendor, &preset_bundle, printer_attr); - if (!out.empty()) - return out; - } + const VendorMap& vendors = preset_bundle.vendors; + for (const auto& [vendor_id, vendor] : vendors) { + std::string out = get_printer_profiles(&vendor, &preset_bundle, printer_attr); + if (!out.empty()) + return out; } return ""; } +*/ +struct PrinterAttr +{ + std::string vendor_id; + std::string model_id; + std::string variant_name; +}; + +static bool is_compatible_preset(const Preset& printer_preset, const PrinterAttr& attr) +{ + return printer_preset.vendor->id == attr.vendor_id && + printer_preset.config.opt_string("printer_model") == attr.model_id && + printer_preset.config.opt_string("printer_variant") == attr.variant_name; +} + +static void add_profile_node(pt::ptree& printer_profiles_node, const Preset& printer_preset) +{ + pt::ptree profile_node; + profile_node.put("name", printer_preset.name); + profile_node.put("is_user_profile", printer_preset.is_user()); + printer_profiles_node.push_back(std::make_pair("", profile_node)); +} + +static pt::ptree get_printer_profiles_node(const PrinterPresetCollection& printer_presets, + const PrinterAttr& attr) +{ + pt::ptree printer_profiles_node; + + for (const Preset& printer_preset : printer_presets) { + + if (printer_preset.is_user()) { + const Preset* parent_preset = printer_presets.get_preset_parent(printer_preset); + if (parent_preset && printer_preset.is_visible && is_compatible_preset(*parent_preset, attr)) + add_profile_node(printer_profiles_node, printer_preset); + } + else if (printer_preset.is_visible && is_compatible_preset(printer_preset, attr)) + add_profile_node(printer_profiles_node, printer_preset); + } + return printer_profiles_node; +} + +static void add_printer_models(pt::ptree& vendor_node, + const VendorProfile* vendor_profile, + PrinterTechnology printer_technology, + const PrinterPresetCollection& printer_presets) +{ + for (const auto& printer_model : vendor_profile->models) { + if (printer_technology != ptAny && printer_model.technology != printer_technology) + continue; + + pt::ptree variants_node; + pt::ptree printer_profiles_node; + + if (printer_model.technology == ptSLA) { + PrinterAttr attr({ vendor_profile->id, printer_model.id, "default" }); + + printer_profiles_node = get_printer_profiles_node(printer_presets, attr); + if (printer_profiles_node.empty()) + continue; + } + else { + for (const auto& variant : printer_model.variants) { + + PrinterAttr attr({ vendor_profile->id, printer_model.id, variant.name }); + + printer_profiles_node = get_printer_profiles_node(printer_presets, attr); + if (printer_profiles_node.empty()) + continue; + + pt::ptree variant_node; + variant_node.put("name", variant.name); + variant_node.add_child("printer_profiles", printer_profiles_node); + + variants_node.push_back(std::make_pair("", variant_node)); + } + + if (variants_node.empty()) + continue; + } + + pt::ptree data_node; + data_node.put("id", printer_model.id); + data_node.put("name", printer_model.name); + data_node.put("technology", printer_model.technology == ptFFF ? "FFF" : "SLA"); + + if (!variants_node.empty()) + data_node.add_child("variants", variants_node); + else + data_node.add_child("printer_profiles", printer_profiles_node); + + data_node.put("vendor_name", vendor_profile->name); + data_node.put("vendor_id", vendor_profile->id); + + vendor_node.push_back(std::make_pair("", data_node)); + } +} + +std::string get_json_printer_models(PrinterTechnology printer_technology) +{ + if (!is_datadir()) + return ""; + + PresetBundle preset_bundle; + if (!load_preset_bandle_from_datadir(preset_bundle)) + return ""; + printf(", vendors"); + + pt::ptree vendor_node; + + const VendorMap& vendors_map = preset_bundle.vendors; + for (const auto& [vendor_id, vendor] : vendors_map) + add_printer_models(vendor_node, &vendor, printer_technology, preset_bundle.printers); + + pt::ptree root; + root.add_child("printer_models", vendor_node); + + // Serialize the tree into JSON and return it. + std::stringstream ss; + pt::write_json(ss, root); + return ss.str(); +} static std::string get_installed_print_and_filament_profiles(const PresetBundle* preset_bundle, const Preset* printer_preset) { @@ -367,13 +396,14 @@ static std::string get_installed_print_and_filament_profiles(const PresetBundle* { pt::ptree print_profile_node; print_profile_node.put("name", print_preset.name); + print_profile_node.put("is_user_profile", print_preset.is_user()); pt::ptree materials_profile_node; for (auto material_preset : material_presets) { // ?! check visible and no-template presets only - if (!material_preset.is_visible || material_preset.vendor->templates_profile) + if (!material_preset.is_visible || (material_preset.vendor && material_preset.vendor->templates_profile)) continue; const PresetWithVendorProfile material_preset_with_vendor_profile = material_presets.get_preset_with_vendor_profile(material_preset); @@ -381,7 +411,8 @@ static std::string get_installed_print_and_filament_profiles(const PresetBundle* if (is_compatible_with_printer(material_preset_with_vendor_profile, printer_preset_with_vendor_profile) && is_compatible_with_print(material_preset_with_vendor_profile, print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) { pt::ptree material_node; - material_node.put("", material_preset.name); + material_node.put("name", material_preset.name); + material_node.put("is_user_profile", material_preset.is_user()); materials_profile_node.push_back(std::make_pair("", material_node)); } } @@ -411,24 +442,10 @@ std::string get_json_print_filament_profiles(const std::string& printer_profile) if (!is_datadir()) return ""; - if (data_dir().empty()) { - printf("Loading of all known vendors ."); - BundleMap bundles = BundleMap::load(); - - printf(GUI::format("\n\nSearching for \"%1%\" .", printer_profile).c_str()); - - for (const auto& [bundle_id, bundle] : bundles) { - printf("."); - if (const Preset* preset = bundle.preset_bundle->printers.find_preset(printer_profile, false, false)) - return get_installed_print_and_filament_profiles(bundle.preset_bundle.get(), preset); - } - } - else { - PresetBundle preset_bundle; - if (!load_preset_bandle_from_datadir(preset_bundle)) - return ""; - - if (const Preset* preset = preset_bundle.printers.find_preset(printer_profile, false, false)) + PresetBundle preset_bundle; + if (load_preset_bandle_from_datadir(preset_bundle)) { + const Preset* preset = preset_bundle.printers.find_preset(printer_profile, false, false); + if (preset) return get_installed_print_and_filament_profiles(&preset_bundle, preset); } diff --git a/src/slic3r/Utils/ProfilesSharingUtils.hpp b/src/slic3r/Utils/ProfilesSharingUtils.hpp index 4de698cc7d..62de5a15b5 100644 --- a/src/slic3r/Utils/ProfilesSharingUtils.hpp +++ b/src/slic3r/Utils/ProfilesSharingUtils.hpp @@ -10,7 +10,7 @@ namespace Slic3r { std::string get_json_printer_models(PrinterTechnology printer_technology); -std::string get_json_printer_profiles(const std::string& printer_model, const std::string& printer_variant); +//std::string get_json_printer_profiles(const std::string& printer_model, const std::string& printer_variant); std::string get_json_print_filament_profiles(const std::string& printer_profile); #if __APPLE__ From 02b65b2366907aa12c32c43c3716fc8d20febd64 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 3 Jan 2024 21:11:47 +0100 Subject: [PATCH 04/14] ProfilesSharingUtils : Implemented load_full_print_config() function to load full print config from PresetBundle. --- src/PrusaSlicer.cpp | 5 ++++ src/slic3r/Utils/ProfilesSharingUtils.cpp | 36 +++++++++++++++++++++++ src/slic3r/Utils/ProfilesSharingUtils.hpp | 4 ++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 4ca32a2113..105078fa39 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -964,7 +964,12 @@ std::set query_options = { bool CLI::processed_profiles_sharing() { if (m_profiles_sharing.empty()) +#if 0 // fsFIXME !!! just for the test + DynamicPrintConfig config = Slic3r::load_full_print_config("0.20mm QUALITY @MINI", "Prusament PLA", "Original Prusa MINI & MINI+"); + return true; +#else return false; +#endif std::string ret; for (auto const& opt_key : m_profiles_sharing) { diff --git a/src/slic3r/Utils/ProfilesSharingUtils.cpp b/src/slic3r/Utils/ProfilesSharingUtils.cpp index 4857704f34..92c19cca56 100644 --- a/src/slic3r/Utils/ProfilesSharingUtils.cpp +++ b/src/slic3r/Utils/ProfilesSharingUtils.cpp @@ -452,4 +452,40 @@ std::string get_json_print_filament_profiles(const std::string& printer_profile) return ""; } +// Helper function for FS +DynamicPrintConfig load_full_print_config(const std::string& print_preset_name, const std::string& filament_preset_name, const std::string& printer_preset_name) +{ + DynamicPrintConfig config = {}; + + if (is_datadir()) { + PresetBundle preset_bundle; + + if (load_preset_bandle_from_datadir(preset_bundle)) { + config.apply(FullPrintConfig::defaults()); + + const Preset* print_preset = preset_bundle.prints.find_preset(print_preset_name); + if (print_preset) + config.apply_only(print_preset->config, print_preset->config.keys()); + else + printf("Print profile '%s' wasn't found.\n", print_preset->name.c_str()); + + const Preset* filament_preset = preset_bundle.filaments.find_preset(filament_preset_name); + if (filament_preset) + config.apply_only(filament_preset->config, filament_preset->config.keys()); + else + printf("Filament profile '%s' wasn't found.\n", filament_preset->name.c_str()); + + const Preset* printer_preset = preset_bundle.printers.find_preset(printer_preset_name); + if (printer_preset) + config.apply_only(printer_preset->config, printer_preset->config.keys()); + else + printf("Printer profile '%s' wasn't found.\n", printer_preset->name.c_str()); + } + } + else + printf("Datadir wasn't found\n"); + + return config; +} + } // namespace Slic3r diff --git a/src/slic3r/Utils/ProfilesSharingUtils.hpp b/src/slic3r/Utils/ProfilesSharingUtils.hpp index 62de5a15b5..0edb0a96eb 100644 --- a/src/slic3r/Utils/ProfilesSharingUtils.hpp +++ b/src/slic3r/Utils/ProfilesSharingUtils.hpp @@ -5,7 +5,7 @@ #ifndef slic3r_ProfilesSharingUtils_hpp_ #define slic3r_ProfilesSharingUtils_hpp_ -#include "libslic3r/Config.hpp" +#include "libslic3r/PrintConfig.hpp" namespace Slic3r { @@ -18,6 +18,8 @@ std::string get_json_print_filament_profiles(const std::string& printer_profile) std::string GetDataDir(); #endif //__APPLE__ +DynamicPrintConfig load_full_print_config(const std::string& print_preset, const std::string& filament_preset, const std::string& printer_preset); + } // namespace Slic3r #endif // slic3r_ProfilesSharingUtils_hpp_ From 5f5147377efb75c918529b1b8f6e4d4bfe6c64c2 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 8 Jan 2024 13:39:46 +0100 Subject: [PATCH 05/14] Move ProfilesSharingUtils to backend (to libslic3r from GUI) --- src/PrusaSlicer.cpp | 3 +-- src/libslic3r/CMakeLists.txt | 8 ++++++++ src/libslic3r/MacUtils.mm | 17 +++++++++++++++++ .../ProfilesSharingUtils.cpp | 8 ++++---- .../ProfilesSharingUtils.hpp | 0 src/slic3r/CMakeLists.txt | 2 -- src/slic3r/Utils/MacUtils.mm | 11 ----------- 7 files changed, 30 insertions(+), 19 deletions(-) create mode 100644 src/libslic3r/MacUtils.mm rename src/{slic3r/Utils => libslic3r}/ProfilesSharingUtils.cpp (99%) rename src/{slic3r/Utils => libslic3r}/ProfilesSharingUtils.hpp (100%) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 105078fa39..7dc94ddff1 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -61,11 +61,10 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Thread.hpp" #include "libslic3r/BlacklistedLibraryCheck.hpp" +#include "libslic3r/ProfilesSharingUtils.hpp" #include "PrusaSlicer.hpp" -#include "slic3r/Utils/ProfilesSharingUtils.hpp" - #ifdef SLIC3R_GUI #include "slic3r/GUI/GUI_Init.hpp" #endif /* SLIC3R_GUI */ diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index afaff965c8..393157db13 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -508,8 +508,16 @@ set(SLIC3R_SOURCES Arachne/WallToolPaths.hpp Arachne/WallToolPaths.cpp StaticMap.hpp + ProfilesSharingUtils.hpp + ProfilesSharingUtils.cpp ) +if (APPLE) + list(APPEND SLIC3R_SOURCES + MacUtils.mm + ) +endif () + add_library(libslic3r STATIC ${SLIC3R_SOURCES}) if (WIN32) diff --git a/src/libslic3r/MacUtils.mm b/src/libslic3r/MacUtils.mm new file mode 100644 index 0000000000..30d3ab825d --- /dev/null +++ b/src/libslic3r/MacUtils.mm @@ -0,0 +1,17 @@ +#import "ProfilesSharingUtils.hpp" + +#import + +namespace Slic3r { + +// ProfilesSharingUtils.hpp +std::string GetDataDir() +{ + NSURL* url = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory + inDomain:NSUserDomainMask + appropriateForURL:nil create:NO error:nil]; + + return std::string([(CFStringRef)url.path UTF8String]); +} + +} diff --git a/src/slic3r/Utils/ProfilesSharingUtils.cpp b/src/libslic3r/ProfilesSharingUtils.cpp similarity index 99% rename from src/slic3r/Utils/ProfilesSharingUtils.cpp rename to src/libslic3r/ProfilesSharingUtils.cpp index 92c19cca56..d25ce8184d 100644 --- a/src/slic3r/Utils/ProfilesSharingUtils.cpp +++ b/src/libslic3r/ProfilesSharingUtils.cpp @@ -3,10 +3,10 @@ ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher ///|/ #include "ProfilesSharingUtils.hpp" -#include "libslic3r/Utils.hpp" -#include "libslic3r/format.hpp" -#include "libslic3r/PrintConfig.hpp" -#include "libslic3r/PresetBundle.hpp" +#include "Utils.hpp" +#include "format.hpp" +#include "PrintConfig.hpp" +#include "PresetBundle.hpp" #include diff --git a/src/slic3r/Utils/ProfilesSharingUtils.hpp b/src/libslic3r/ProfilesSharingUtils.hpp similarity index 100% rename from src/slic3r/Utils/ProfilesSharingUtils.hpp rename to src/libslic3r/ProfilesSharingUtils.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index d22dc873ce..fea794c943 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -335,8 +335,6 @@ set(SLIC3R_GUI_SOURCES Utils/WxFontUtils.hpp Utils/WifiScanner.hpp Utils/WifiScanner.cpp - Utils/ProfilesSharingUtils.hpp - Utils/ProfilesSharingUtils.cpp ) find_package(NanoSVG REQUIRED) diff --git a/src/slic3r/Utils/MacUtils.mm b/src/slic3r/Utils/MacUtils.mm index b570dd566d..5c54c2b90e 100644 --- a/src/slic3r/Utils/MacUtils.mm +++ b/src/slic3r/Utils/MacUtils.mm @@ -1,5 +1,4 @@ #import "AppUpdater.hpp" -#import "ProfilesSharingUtils.hpp" #import @@ -17,14 +16,4 @@ std::string get_downloads_path_mac() //return std::string(); } -// ProfilesSharingUtils.hpp -std::string GetDataDir() -{ - NSURL* url = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory - inDomain:NSUserDomainMask - appropriateForURL:nil create:NO error:nil]; - - return std::string([(CFStringRef)url.path UTF8String]); -} - } From eb8a460b24b3f6423202bffb1d8a9d393e453d8f Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 9 Jan 2024 16:58:54 +0100 Subject: [PATCH 06/14] ProfilesSharingUtils : Improvements for requests. "query-printer-models" and "query-print-filament-profiles" return presets which are separated to "user" and regular print/material/printer profiles + Removed print of state information --- src/libslic3r/ProfilesSharingUtils.cpp | 78 +++++++++++++------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/src/libslic3r/ProfilesSharingUtils.cpp b/src/libslic3r/ProfilesSharingUtils.cpp index d25ce8184d..018ec64f6b 100644 --- a/src/libslic3r/ProfilesSharingUtils.cpp +++ b/src/libslic3r/ProfilesSharingUtils.cpp @@ -116,8 +116,6 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle) return false; } - printf("Loading: AppConfig"); - if (std::string error = app_config.load(); !error.empty()) { throw Slic3r::RuntimeError(Slic3r::format("Error parsing PrusaSlicer config file, it is probably corrupted. " "Try to manually delete the file to recover from the error. Your user profiles will not be affected." @@ -133,7 +131,6 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle) // Suppress the '- default -' presets. preset_bundle.set_default_suppressed(app_config.get_bool("no_defaults")); try { - printf(", presets"); auto preset_substitutions = preset_bundle.load_presets(app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent); if (!preset_substitutions.empty()) { printf("Some substitutions are found during loading presets.\n"); @@ -233,7 +230,6 @@ std::string get_json_printer_profiles(const std::string& printer_model_name, con PresetBundle preset_bundle; if (!load_preset_bandle_from_datadir(preset_bundle)) return ""; - printf(", vendors"); const VendorMap& vendors = preset_bundle.vendors; for (const auto& [vendor_id, vendor] : vendors) { @@ -260,30 +256,28 @@ static bool is_compatible_preset(const Preset& printer_preset, const PrinterAttr printer_preset.config.opt_string("printer_variant") == attr.variant_name; } -static void add_profile_node(pt::ptree& printer_profiles_node, const Preset& printer_preset) +static void add_profile_node(pt::ptree& printer_profiles_node, const std::string& preset_name) { pt::ptree profile_node; - profile_node.put("name", printer_preset.name); - profile_node.put("is_user_profile", printer_preset.is_user()); + profile_node.put("", preset_name); printer_profiles_node.push_back(std::make_pair("", profile_node)); } -static pt::ptree get_printer_profiles_node(const PrinterPresetCollection& printer_presets, - const PrinterAttr& attr) +static void get_printer_profiles_node(pt::ptree& printer_profiles_node, + pt::ptree& user_printer_profiles_node, + const PrinterPresetCollection& printer_presets, + const PrinterAttr& attr) { - pt::ptree printer_profiles_node; - for (const Preset& printer_preset : printer_presets) { if (printer_preset.is_user()) { const Preset* parent_preset = printer_presets.get_preset_parent(printer_preset); if (parent_preset && printer_preset.is_visible && is_compatible_preset(*parent_preset, attr)) - add_profile_node(printer_profiles_node, printer_preset); + add_profile_node(user_printer_profiles_node, printer_preset.name); } else if (printer_preset.is_visible && is_compatible_preset(printer_preset, attr)) - add_profile_node(printer_profiles_node, printer_preset); + add_profile_node(printer_profiles_node, printer_preset.name); } - return printer_profiles_node; } static void add_printer_models(pt::ptree& vendor_node, @@ -297,12 +291,13 @@ static void add_printer_models(pt::ptree& vendor_node, pt::ptree variants_node; pt::ptree printer_profiles_node; + pt::ptree user_printer_profiles_node; if (printer_model.technology == ptSLA) { PrinterAttr attr({ vendor_profile->id, printer_model.id, "default" }); - printer_profiles_node = get_printer_profiles_node(printer_presets, attr); - if (printer_profiles_node.empty()) + get_printer_profiles_node(printer_profiles_node, user_printer_profiles_node, printer_presets, attr); + if (printer_profiles_node.empty() && user_printer_profiles_node.empty()) continue; } else { @@ -310,13 +305,15 @@ static void add_printer_models(pt::ptree& vendor_node, PrinterAttr attr({ vendor_profile->id, printer_model.id, variant.name }); - printer_profiles_node = get_printer_profiles_node(printer_presets, attr); - if (printer_profiles_node.empty()) + get_printer_profiles_node(printer_profiles_node, user_printer_profiles_node, printer_presets, attr); + if (printer_profiles_node.empty() && user_printer_profiles_node.empty()) continue; pt::ptree variant_node; variant_node.put("name", variant.name); variant_node.add_child("printer_profiles", printer_profiles_node); + if (!user_printer_profiles_node.empty()) + variant_node.add_child("user_printer_profiles", user_printer_profiles_node); variants_node.push_back(std::make_pair("", variant_node)); } @@ -332,8 +329,11 @@ static void add_printer_models(pt::ptree& vendor_node, if (!variants_node.empty()) data_node.add_child("variants", variants_node); - else + else { data_node.add_child("printer_profiles", printer_profiles_node); + if (!user_printer_profiles_node.empty()) + data_node.add_child("user_printer_profiles", user_printer_profiles_node); + } data_node.put("vendor_name", vendor_profile->name); data_node.put("vendor_id", vendor_profile->id); @@ -350,7 +350,6 @@ std::string get_json_printer_models(PrinterTechnology printer_technology) PresetBundle preset_bundle; if (!load_preset_bandle_from_datadir(preset_bundle)) return ""; - printf(", vendors"); pt::ptree vendor_node; @@ -371,9 +370,8 @@ static std::string get_installed_print_and_filament_profiles(const PresetBundle* { PrinterTechnology printer_technology = printer_preset->printer_technology(); - printf("\n\nSearching for compatible print profiles ."); - pt::ptree print_profiles; + pt::ptree user_print_profiles; const PresetWithVendorProfile printer_preset_with_vendor_profile = preset_bundle->printers.get_preset_with_vendor_profile(*printer_preset); @@ -381,24 +379,14 @@ static std::string get_installed_print_and_filament_profiles(const PresetBundle* const PresetCollection& material_presets = printer_technology == ptFFF ? preset_bundle->filaments : preset_bundle->sla_materials; const std::string material_node_name = printer_technology == ptFFF ? "filament_profiles" : "sla_material_profiles"; - int output_counter{ 0 }; for (auto print_preset : print_presets) { - ++output_counter; - if (output_counter == 10) { - printf("."); - output_counter = 0; - } - const PresetWithVendorProfile print_preset_with_vendor_profile = print_presets.get_preset_with_vendor_profile(print_preset); if (is_compatible_with_printer(print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) { - pt::ptree print_profile_node; - print_profile_node.put("name", print_preset.name); - print_profile_node.put("is_user_profile", print_preset.is_user()); - pt::ptree materials_profile_node; + pt::ptree user_materials_profile_node; for (auto material_preset : material_presets) { @@ -411,25 +399,35 @@ static std::string get_installed_print_and_filament_profiles(const PresetBundle* if (is_compatible_with_printer(material_preset_with_vendor_profile, printer_preset_with_vendor_profile) && is_compatible_with_print(material_preset_with_vendor_profile, print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) { pt::ptree material_node; - material_node.put("name", material_preset.name); - material_node.put("is_user_profile", material_preset.is_user()); - materials_profile_node.push_back(std::make_pair("", material_node)); + material_node.put("", material_preset.name); + if (material_preset.is_user()) + user_materials_profile_node.push_back(std::make_pair("", material_node)); + else + materials_profile_node.push_back(std::make_pair("", material_node)); } } + pt::ptree print_profile_node; + print_profile_node.put("name", print_preset.name); print_profile_node.add_child(material_node_name, materials_profile_node); - print_profiles.push_back(std::make_pair("", print_profile_node)); + if (!user_materials_profile_node.empty()) + print_profile_node.add_child("user_" + material_node_name, user_materials_profile_node); + + if (print_preset.is_user()) + user_print_profiles.push_back(std::make_pair("", print_profile_node)); + else + print_profiles.push_back(std::make_pair("", print_profile_node)); } } - printf("\n"); - - if (print_profiles.empty()) + if (print_profiles.empty() && user_print_profiles.empty()) return ""; pt::ptree tree; tree.put("printer_profile", printer_preset->name); tree.add_child("print_profiles", print_profiles); + if (!user_print_profiles.empty()) + tree.add_child("user_print_profiles", user_print_profiles); // Serialize the tree into JSON and return it. std::stringstream ss; From 5bea4e710403e34797c1ea450b41b9c74d20a34e Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 10 Jan 2024 10:37:27 +0100 Subject: [PATCH 07/14] Follow-up 85c0d636 - Fix for get_printer_profiles_node() Clear nodes before filling. + Fixed tooltips for "query-..." options --- src/PrusaSlicer.cpp | 1 - src/libslic3r/PrintConfig.cpp | 31 ++++++++++++++++---------- src/libslic3r/ProfilesSharingUtils.cpp | 11 +++++---- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 7dc94ddff1..21bd6938c9 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -1012,7 +1012,6 @@ bool CLI::processed_profiles_sharing() std::string cmdline_param = m_config.opt_string("output"); if (cmdline_param.empty()) { - printf("\n"); if (ret.empty()) printf("Wrong request"); else diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 1ec641d672..413e01b5ab 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5125,29 +5125,36 @@ CLIProfilesSharingConfigDef::CLIProfilesSharingConfigDef() { ConfigOptionDef* def; + // Information from this def will be used just for console output. + // So, don't use L marker to label and tooltips values to avoid extract those phrases to translation. + def = this->add("query-printer-models", coBool); - def->label = L("Get list of printer models"); - def->tooltip = L("Get available printer models into JSON.\n" - "Note:\nTo print printer models for required technology use 'printer-technology' option. By default printer_technology is FFF.\n" - "To print out JSON into file use 'output' option."); + def->label = ("Get list of printer models"); + def->tooltip = ("Get list of installed printer models into JSON.\n" + "Note:\n" + "To print printer models for required technology use 'printer-technology' option with value FFF or SLA. By default printer_technology is FFF.\n" + "To print out JSON into file use 'output' option.\n" + "To specify configuration folder use 'datadir' option."); /* def = this->add("query-printer-profiles", coBool); - def->label = L("Get list of printer profiles in respect to selected printer model and printer variant"); - def->tooltip = L("Get list of printer profiles in respect to selected 'printer-model' and 'printer-variant' into JSON.\n" + def->label = ("Get list of printer profiles for the selected printer model and printer variant"); + def->tooltip = ("Get list of printer profiles for the selected 'printer-model' and 'printer-variant' into JSON.\n" "Note:\n" - "To print out JSON into file use 'output' option."); + "To print out JSON into file use 'output' option.\n" + "To specify configuration folder use 'datadir' option."); */ def = this->add("query-print-filament-profiles", coBool); - def->label = L("Get list of prints and filaments profiles in respect to selected printer profile"); - def->tooltip = L("Get list of prints and filaments profiles in respect to selected 'printer-profile' into JSON.\n" + def->label = ("Get list of print profiles and filament profiles for the selected printer profile"); + def->tooltip = ("Get list of print profiles and filament profiles for the selected 'printer-profile' into JSON.\n" "Note:\n" - "To print out JSON into file use 'output' option."); + "To print out JSON into file use 'output' option.\n" + "To specify configuration folder use 'datadir' option."); def = this->add("printer-profile", coString); - def->label = L("Printer preset name"); - def->tooltip = L("Name of the printer preset used for slicing."); + def->label = ("Printer preset name"); + def->tooltip = ("Name of the printer preset used for slicing."); def->set_default_value(new ConfigOptionString()); } diff --git a/src/libslic3r/ProfilesSharingUtils.cpp b/src/libslic3r/ProfilesSharingUtils.cpp index 018ec64f6b..dfe72381f5 100644 --- a/src/libslic3r/ProfilesSharingUtils.cpp +++ b/src/libslic3r/ProfilesSharingUtils.cpp @@ -268,6 +268,9 @@ static void get_printer_profiles_node(pt::ptree& printer_profiles_node, const PrinterPresetCollection& printer_presets, const PrinterAttr& attr) { + printer_profiles_node.clear(); + user_printer_profiles_node.clear(); + for (const Preset& printer_preset : printer_presets) { if (printer_preset.is_user()) { @@ -465,23 +468,23 @@ DynamicPrintConfig load_full_print_config(const std::string& print_preset_name, if (print_preset) config.apply_only(print_preset->config, print_preset->config.keys()); else - printf("Print profile '%s' wasn't found.\n", print_preset->name.c_str()); + BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Print profile '%1%' wasn't found.", print_preset_name); const Preset* filament_preset = preset_bundle.filaments.find_preset(filament_preset_name); if (filament_preset) config.apply_only(filament_preset->config, filament_preset->config.keys()); else - printf("Filament profile '%s' wasn't found.\n", filament_preset->name.c_str()); + BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Filament profile '%1%' wasn't found.", filament_preset_name); const Preset* printer_preset = preset_bundle.printers.find_preset(printer_preset_name); if (printer_preset) config.apply_only(printer_preset->config, printer_preset->config.keys()); else - printf("Printer profile '%s' wasn't found.\n", printer_preset->name.c_str()); + BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Printer profile '%1%' wasn't found.", printer_preset_name); } } else - printf("Datadir wasn't found\n"); + BOOST_LOG_TRIVIAL(error) << "Datadir wasn't found\n"; return config; } From fbe63ba1ab63fe04b367e9ed1f7356ac633f6a8d Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 11 Jan 2024 21:52:37 +0100 Subject: [PATCH 08/14] Improvements and refactoring of datadir handling --- src/PrusaSlicer.cpp | 32 ++-- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/ProfilesSharingUtils.cpp | 189 ++++++----------------- src/libslic3r/ProfilesSharingUtils.hpp | 5 +- src/libslic3r/Utils/DirectoriesUtils.cpp | 94 +++++++++++ src/libslic3r/Utils/DirectoriesUtils.hpp | 10 ++ src/libslic3r/libslic3r.h | 9 +- src/slic3r/GUI/GUI_App.cpp | 35 +---- src/slic3r/GUI/GUI_App.hpp | 1 - 9 files changed, 185 insertions(+), 192 deletions(-) create mode 100644 src/libslic3r/Utils/DirectoriesUtils.cpp create mode 100644 src/libslic3r/Utils/DirectoriesUtils.hpp diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 21bd6938c9..5a4ab0dc10 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -62,6 +62,7 @@ #include "libslic3r/Thread.hpp" #include "libslic3r/BlacklistedLibraryCheck.hpp" #include "libslic3r/ProfilesSharingUtils.hpp" +#include "libslic3r/Utils/DirectoriesUtils.hpp" #include "PrusaSlicer.hpp" @@ -848,7 +849,10 @@ bool CLI::setup(int argc, char **argv) for (const t_optiondef_map::value_type &optdef : *options) m_config.option(optdef.first, true); - set_data_dir(m_config.opt_string("datadir")); + if (std::string provided_datadir = m_config.opt_string("datadir"); provided_datadir.empty()) { + set_data_dir(get_default_datadir()); + } else + set_data_dir(provided_datadir); //FIXME Validating at this stage most likely does not make sense, as the config is not fully initialized yet. if (!validity.empty()) { @@ -962,13 +966,15 @@ std::set query_options = { bool CLI::processed_profiles_sharing() { - if (m_profiles_sharing.empty()) + if (m_profiles_sharing.empty()) { #if 0 // fsFIXME !!! just for the test - DynamicPrintConfig config = Slic3r::load_full_print_config("0.20mm QUALITY @MINI", "Prusament PLA", "Original Prusa MINI & MINI+"); + Slic3r::DynamicPrintConfig config = {}; + bool was_loaded = Slic3r::load_full_print_config("0.20mm QUALITY @MINI", "Prusament PLA", "Original Prusa MINI & MINI+", config); return true; #else return false; #endif + } std::string ret; for (auto const& opt_key : m_profiles_sharing) { @@ -986,9 +992,10 @@ bool CLI::processed_profiles_sharing() ret = Slic3r::get_json_printer_profiles(m_config.opt_string("printer_model"), m_config.opt_string("printer_variant")); if (ret.empty()) - ret = "\nPrinter_model '" + m_config.opt_string("printer_model") + - "' with printer_variant '" + m_config.opt_string("printer_variant") + - "' wasn't found among intalled printers.\nOr the request can be wrong.\n"; + boost::nowide::cerr << "Printer_model '" << m_config.opt_string("printer_model") << + "' with printer_variant '" << m_config.opt_string("printer_variant") << + "' wasn't found among installed printers." << std::endl << + "Or the request can be wrong." << std::endl; } */ else if (opt_key == "query-print-filament-profiles") { @@ -999,8 +1006,9 @@ bool CLI::processed_profiles_sharing() ret = Slic3r::get_json_print_filament_profiles(m_config.opt_string("printer-profile")); if (ret.empty()) - ret = "\nPrinter profile '" + m_config.opt_string("printer-profile") + - "' wasn't found among intalled printers.\nOr the request can be wrong.\n"; + boost::nowide::cerr << "Printer profile '" << m_config.opt_string("printer-profile") << + "' wasn't found among installed printers." << std::endl << + "Or the request can be wrong." << std::endl; } else { boost::nowide::cerr << "error: option not implemented yet: " << opt_key << std::endl; @@ -1013,9 +1021,9 @@ bool CLI::processed_profiles_sharing() std::string cmdline_param = m_config.opt_string("output"); if (cmdline_param.empty()) { if (ret.empty()) - printf("Wrong request"); + boost::nowide::cerr << "Wrong request" << std::endl; else - printf(ret.c_str()); + printf("%s", ret.c_str()); } else { // if we were supplied a directory, use it and append our automatically generated filename @@ -1034,9 +1042,7 @@ bool CLI::processed_profiles_sharing() c << ret << std::endl; c.close(); - printf("\nOutput for your request in written into \""); - printf(file.c_str()); - printf("\"\n"); + boost::nowide::cout << "Output for your request is written into " << file << std::endl; } return true; diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 393157db13..c260991bf2 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -510,6 +510,8 @@ set(SLIC3R_SOURCES StaticMap.hpp ProfilesSharingUtils.hpp ProfilesSharingUtils.cpp + Utils/DirectoriesUtils.hpp + Utils/DirectoriesUtils.cpp ) if (APPLE) diff --git a/src/libslic3r/ProfilesSharingUtils.cpp b/src/libslic3r/ProfilesSharingUtils.cpp index dfe72381f5..8de4828477 100644 --- a/src/libslic3r/ProfilesSharingUtils.cpp +++ b/src/libslic3r/ProfilesSharingUtils.cpp @@ -7,119 +7,25 @@ #include "format.hpp" #include "PrintConfig.hpp" #include "PresetBundle.hpp" +#include "Utils/DirectoriesUtils.hpp" #include - -#if defined(_WIN32) - -#include - -static std::string GetDataDir() -{ - HRESULT hr = E_FAIL; - - std::wstring buffer; - buffer.resize(MAX_PATH); - - hr = ::SHGetFolderPath - ( - NULL, // parent window, not used - CSIDL_APPDATA, - NULL, // access token (current user) - SHGFP_TYPE_CURRENT, // current path, not just default value - (LPWSTR)buffer.data() - ); - - // somewhat incredibly, the error code in the Unicode version is - // different from the one in ASCII version for this function -#if wxUSE_UNICODE - if (hr == E_FAIL) -#else - if (hr == S_FALSE) -#endif - { - // directory doesn't exist, maybe we can get its default value? - hr = ::SHGetFolderPath - ( - NULL, - CSIDL_APPDATA, - NULL, - SHGFP_TYPE_DEFAULT, - (LPWSTR)buffer.data() - ); - } - - for (int i=0; i< MAX_PATH; i++) - if (buffer.data()[i] == '\0') { - buffer.resize(i); - break; - } - - return boost::nowide::narrow(buffer); -} - -#elif defined(__linux__) - -#include -#include - -static std::string GetDataDir() -{ - std::string dir; - - char* ptr; - if ((ptr = getenv("XDG_CONFIG_HOME"))) - dir = std::string(ptr); - else { - if ((ptr = getenv("HOME"))) - dir = std::string(ptr); - else { - struct passwd* who = (struct passwd*)NULL; - if ((ptr = getenv("USER")) || (ptr = getenv("LOGNAME"))) - who = getpwnam(ptr); - // make sure the user exists! - if (!who) - who = getpwuid(getuid()); - - dir = std::string(who ? who->pw_dir : 0); - } - dir += "/.config"; - } - - if (dir.empty()) - printf("GetDataDir() > unsupported file layout \n"); - - return dir; -} - -#endif +#include namespace Slic3r { -static bool is_datadir() -{ - if (!data_dir().empty()) - return true; - - const std::string config_dir = GetDataDir(); - const std::string data_dir = (boost::filesystem::path(config_dir) / SLIC3R_APP_FULL_NAME).make_preferred().string(); - - set_data_dir(data_dir); - return true; -} - -static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle) +static bool load_preset_bundle_from_datadir(PresetBundle& preset_bundle) { AppConfig app_config = AppConfig(AppConfig::EAppMode::Editor); if (!app_config.exists()) { - printf("Configuration wasn't found. Check your 'datadir' value.\n"); + BOOST_LOG_TRIVIAL(error) << "Configuration wasn't found. Check your 'datadir' value."; return false; } if (std::string error = app_config.load(); !error.empty()) { - throw Slic3r::RuntimeError(Slic3r::format("Error parsing PrusaSlicer config file, it is probably corrupted. " + BOOST_LOG_TRIVIAL(error) << Slic3r::format("Error parsing PrusaSlicer config file, it is probably corrupted. " "Try to manually delete the file to recover from the error. Your user profiles will not be affected." - "\n\n%1%\n\n%2%", app_config.config_path(), error)); + "\n%1%\n%2%", app_config.config_path(), error); return false; } @@ -133,7 +39,7 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle) try { auto preset_substitutions = preset_bundle.load_presets(app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent); if (!preset_substitutions.empty()) { - printf("Some substitutions are found during loading presets.\n"); + BOOST_LOG_TRIVIAL(error) << "Some substitutions are found during loading presets."; return false; } @@ -164,14 +70,13 @@ static bool load_preset_bandle_from_datadir(PresetBundle& preset_bundle) vendor_profile.models = models; } } - - return true; } catch (const std::exception& ex) { - delayed_error_load_presets = ex.what(); - printf(delayed_error_load_presets.c_str()); + BOOST_LOG_TRIVIAL(error) << ex.what(); return false; } + + return true; } namespace pt = boost::property_tree; @@ -228,7 +133,7 @@ std::string get_json_printer_profiles(const std::string& printer_model_name, con PrinterAttr_ printer_attr({printer_model_name, printer_variant}); PresetBundle preset_bundle; - if (!load_preset_bandle_from_datadir(preset_bundle)) + if (!load_preset_bundle_from_datadir(preset_bundle)) return ""; const VendorMap& vendors = preset_bundle.vendors; @@ -347,11 +252,8 @@ static void add_printer_models(pt::ptree& vendor_node, std::string get_json_printer_models(PrinterTechnology printer_technology) { - if (!is_datadir()) - return ""; - PresetBundle preset_bundle; - if (!load_preset_bandle_from_datadir(preset_bundle)) + if (!load_preset_bundle_from_datadir(preset_bundle)) return ""; pt::ptree vendor_node; @@ -440,11 +342,8 @@ static std::string get_installed_print_and_filament_profiles(const PresetBundle* std::string get_json_print_filament_profiles(const std::string& printer_profile) { - if (!is_datadir()) - return ""; - PresetBundle preset_bundle; - if (load_preset_bandle_from_datadir(preset_bundle)) { + if (load_preset_bundle_from_datadir(preset_bundle)) { const Preset* preset = preset_bundle.printers.find_preset(printer_profile, false, false); if (preset) return get_installed_print_and_filament_profiles(&preset_bundle, preset); @@ -454,39 +353,41 @@ std::string get_json_print_filament_profiles(const std::string& printer_profile) } // Helper function for FS -DynamicPrintConfig load_full_print_config(const std::string& print_preset_name, const std::string& filament_preset_name, const std::string& printer_preset_name) +bool load_full_print_config(const std::string& print_preset_name, const std::string& filament_preset_name, const std::string& printer_preset_name, DynamicPrintConfig& config) { - DynamicPrintConfig config = {}; - - if (is_datadir()) { - PresetBundle preset_bundle; - - if (load_preset_bandle_from_datadir(preset_bundle)) { - config.apply(FullPrintConfig::defaults()); - - const Preset* print_preset = preset_bundle.prints.find_preset(print_preset_name); - if (print_preset) - config.apply_only(print_preset->config, print_preset->config.keys()); - else - BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Print profile '%1%' wasn't found.", print_preset_name); - - const Preset* filament_preset = preset_bundle.filaments.find_preset(filament_preset_name); - if (filament_preset) - config.apply_only(filament_preset->config, filament_preset->config.keys()); - else - BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Filament profile '%1%' wasn't found.", filament_preset_name); - - const Preset* printer_preset = preset_bundle.printers.find_preset(printer_preset_name); - if (printer_preset) - config.apply_only(printer_preset->config, printer_preset->config.keys()); - else - BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Printer profile '%1%' wasn't found.", printer_preset_name); - } + PresetBundle preset_bundle; + if (!load_preset_bundle_from_datadir(preset_bundle)){ + BOOST_LOG_TRIVIAL(error) << Slic3r::format("Failed to load data from the datadir '%1%'.", data_dir()); + return false; } - else - BOOST_LOG_TRIVIAL(error) << "Datadir wasn't found\n"; - return config; + config = {}; + config.apply(FullPrintConfig::defaults()); + + bool is_failed{ false }; + + if (const Preset* print_preset = preset_bundle.prints.find_preset(print_preset_name)) + config.apply_only(print_preset->config, print_preset->config.keys()); + else { + BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Print profile '%1%' wasn't found.", print_preset_name); + is_failed |= true; + } + + if (const Preset* filament_preset = preset_bundle.filaments.find_preset(filament_preset_name)) + config.apply_only(filament_preset->config, filament_preset->config.keys()); + else { + BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Filament profile '%1%' wasn't found.", filament_preset_name); + is_failed |= true; + } + + if (const Preset* printer_preset = preset_bundle.printers.find_preset(printer_preset_name)) + config.apply_only(printer_preset->config, printer_preset->config.keys()); + else { + BOOST_LOG_TRIVIAL(warning) << Slic3r::format("Printer profile '%1%' wasn't found.", printer_preset_name); + is_failed |= true; + } + + return !is_failed; } } // namespace Slic3r diff --git a/src/libslic3r/ProfilesSharingUtils.hpp b/src/libslic3r/ProfilesSharingUtils.hpp index 0edb0a96eb..4ea1539dbd 100644 --- a/src/libslic3r/ProfilesSharingUtils.hpp +++ b/src/libslic3r/ProfilesSharingUtils.hpp @@ -5,8 +5,6 @@ #ifndef slic3r_ProfilesSharingUtils_hpp_ #define slic3r_ProfilesSharingUtils_hpp_ -#include "libslic3r/PrintConfig.hpp" - namespace Slic3r { std::string get_json_printer_models(PrinterTechnology printer_technology); @@ -18,7 +16,8 @@ std::string get_json_print_filament_profiles(const std::string& printer_profile) std::string GetDataDir(); #endif //__APPLE__ -DynamicPrintConfig load_full_print_config(const std::string& print_preset, const std::string& filament_preset, const std::string& printer_preset); +class DynamicPrintConfig; +bool load_full_print_config(const std::string& print_preset, const std::string& filament_preset, const std::string& printer_preset, DynamicPrintConfig& out_config); } // namespace Slic3r diff --git a/src/libslic3r/Utils/DirectoriesUtils.cpp b/src/libslic3r/Utils/DirectoriesUtils.cpp new file mode 100644 index 0000000000..202da3b591 --- /dev/null +++ b/src/libslic3r/Utils/DirectoriesUtils.cpp @@ -0,0 +1,94 @@ +#include "DirectoriesUtils.hpp" +#include "../libslic3r.h" + +#include + +#if defined(_WIN32) + +#include + +static std::string GetDataDir() +{ + HRESULT hr = E_FAIL; + + std::wstring buffer; + buffer.resize(MAX_PATH); + + hr = ::SHGetFolderPathW + ( + NULL, // parent window, not used + CSIDL_APPDATA, + NULL, // access token (current user) + SHGFP_TYPE_CURRENT, // current path, not just default value + (LPWSTR)buffer.data() + ); + + if (hr == E_FAIL) + { + // directory doesn't exist, maybe we can get its default value? + hr = ::SHGetFolderPathW + ( + NULL, + CSIDL_APPDATA, + NULL, + SHGFP_TYPE_DEFAULT, + (LPWSTR)buffer.data() + ); + } + + for (int i=0; i< MAX_PATH; i++) + if (buffer.data()[i] == '\0') { + buffer.resize(i); + break; + } + + return boost::nowide::narrow(buffer); +} + +#elif defined(__linux__) + +#include +#include + +static std::string GetDataDir() +{ + std::string dir; + + char* ptr; + if ((ptr = getenv("XDG_CONFIG_HOME"))) + dir = std::string(ptr); + else { + if ((ptr = getenv("HOME"))) + dir = std::string(ptr); + else { + struct passwd* who = (struct passwd*)NULL; + if ((ptr = getenv("USER")) || (ptr = getenv("LOGNAME"))) + who = getpwnam(ptr); + // make sure the user exists! + if (!who) + who = getpwuid(getuid()); + + dir = std::string(who ? who->pw_dir : 0); + } + if (! dir.empty()) + dir += "/.config"; + } + + if (dir.empty()) + BOOST_LOG_TRIVIAL(error) << "GetDataDir() > unsupported file layout"; + + return dir; +} + +#endif + +namespace Slic3r { + +std::string get_default_datadir() +{ + const std::string config_dir = GetDataDir(); + const std::string data_dir = (boost::filesystem::path(config_dir) / SLIC3R_APP_FULL_NAME).make_preferred().string(); + return data_dir; +} + +} // namespace Slic3r diff --git a/src/libslic3r/Utils/DirectoriesUtils.hpp b/src/libslic3r/Utils/DirectoriesUtils.hpp new file mode 100644 index 0000000000..b7cc5dbceb --- /dev/null +++ b/src/libslic3r/Utils/DirectoriesUtils.hpp @@ -0,0 +1,10 @@ +#ifndef slic3r_DirectoriesUtils_hpp_ +#define slic3r_DirectoriesUtils_hpp_ + +namespace Slic3r { + +std::string get_default_datadir(); + +} // namespace Slic3r + +#endif // slic3r_DirectoriesUtils_hpp_ diff --git a/src/libslic3r/libslic3r.h b/src/libslic3r/libslic3r.h index 0f24b85f5e..b62243369f 100644 --- a/src/libslic3r/libslic3r.h +++ b/src/libslic3r/libslic3r.h @@ -16,9 +16,12 @@ #include "libslic3r_version.h" -//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME -#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME "-alpha" -//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_NAME "-beta" +// Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release. +//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_KEY + #define SLIC3R_APP_FULL_NAME SLIC3R_APP_KEY "-alpha" +//#define SLIC3R_APP_FULL_NAME SLIC3R_APP_KEY "-beta" + + #define GCODEVIEWER_APP_NAME "PrusaSlicer G-code Viewer" #define GCODEVIEWER_APP_KEY "PrusaSlicerGcodeViewer" diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index eb9c04cfcb..a5646bb52e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -63,6 +63,7 @@ #include "libslic3r/PresetBundle.hpp" #include "libslic3r/Color.hpp" #include "libslic3r/Format/SLAArchiveFormatRegistry.hpp" +#include "libslic3r/Utils/DirectoriesUtils.hpp" #include "GUI.hpp" #include "GUI_Utils.hpp" @@ -412,20 +413,14 @@ bool static check_old_linux_datadir(const wxString& app_name) { // To be precise, the datadir should exist, it is created when single instance // lock happens. Instead of checking for existence, check the contents. - namespace fs = boost::filesystem; - std::string new_path = Slic3r::data_dir(); - wxString dir; - if (! wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() ) - dir = wxFileName::GetHomeDir() + wxS("/.config"); - std::string default_path = (dir + "/" + app_name).ToUTF8().data(); - - if (new_path != default_path) { - // This happens when the user specifies a custom --datadir. - // Do not show anything in that case. + // If the config folder is redefined - do not check + // This happens when the user specifies a custom --datadir. + if (new_path != get_default_datadir()) return true; - } + + namespace fs = boost::filesystem; fs::path data_dir = fs::path(new_path); if (! fs::is_directory(data_dir)) @@ -922,24 +917,8 @@ static boost::optional parse_semver_from_ini(std::string path) void GUI_App::init_app_config() { - // Profiles for the alpha are stored into the PrusaSlicer-alpha directory to not mix with the current release. SetAppName(SLIC3R_APP_FULL_NAME); - if (data_dir().empty()) { - #ifndef __linux__ - set_data_dir(wxStandardPaths::Get().GetUserDataDir().ToUTF8().data()); - #else - // Since version 2.3, config dir on Linux is in ${XDG_CONFIG_HOME}. - // https://github.com/prusa3d/PrusaSlicer/issues/2911 - wxString dir; - if (! wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() ) - dir = wxFileName::GetHomeDir() + wxS("/.config"); - set_data_dir((dir + "/" + GetAppName()).ToUTF8().data()); - #endif - } else { - m_datadir_redefined = true; - } - if (!app_config) app_config = new AppConfig(is_editor() ? AppConfig::EAppMode::Editor : AppConfig::EAppMode::GCodeViewer); @@ -970,7 +949,7 @@ std::string GUI_App::check_older_app_config(Semver current_version, bool backup) std::string older_data_dir_path; // If the config folder is redefined - do not check - if (m_datadir_redefined) + if (data_dir() != get_default_datadir()) return {}; // find other version app config (alpha / beta / release) diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 726a1689aa..6d14123af3 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -418,7 +418,6 @@ private: // inititate read of version file online in separate thread void app_version_check(bool from_user); - bool m_datadir_redefined { false }; bool m_wifi_config_dialog_shown { false }; }; From f4f1eb5f9b29bae3e1171fd832666d5efe2939b5 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 13 Feb 2024 13:40:19 +0100 Subject: [PATCH 09/14] Information about extruders count is added for each of printer profiles + Added JsonUtils to post-process written json. --- src/libslic3r/CMakeLists.txt | 2 ++ src/libslic3r/ProfilesSharingUtils.cpp | 29 +++++++++++++------------- src/libslic3r/Utils/JsonUtils.cpp | 22 +++++++++++++++++++ src/libslic3r/Utils/JsonUtils.hpp | 12 +++++++++++ 4 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 src/libslic3r/Utils/JsonUtils.cpp create mode 100644 src/libslic3r/Utils/JsonUtils.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index c260991bf2..103b3d9f7e 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -512,6 +512,8 @@ set(SLIC3R_SOURCES ProfilesSharingUtils.cpp Utils/DirectoriesUtils.hpp Utils/DirectoriesUtils.cpp + Utils/JsonUtils.hpp + Utils/JsonUtils.cpp ) if (APPLE) diff --git a/src/libslic3r/ProfilesSharingUtils.cpp b/src/libslic3r/ProfilesSharingUtils.cpp index 8de4828477..79d46e1e1a 100644 --- a/src/libslic3r/ProfilesSharingUtils.cpp +++ b/src/libslic3r/ProfilesSharingUtils.cpp @@ -8,8 +8,8 @@ #include "PrintConfig.hpp" #include "PresetBundle.hpp" #include "Utils/DirectoriesUtils.hpp" +#include "Utils/JsonUtils.hpp" -#include #include namespace Slic3r { @@ -116,9 +116,7 @@ static std::string get_printer_profiles(const VendorProfile* vendor_profile, data_node.add_child("printer_profiles", printer_profiles_node); // Serialize the tree into JSON and return it. - std::stringstream ss; - pt::write_json(ss, data_node); - return ss.str(); + return write_json_with_post_process(data_node); } } @@ -161,10 +159,14 @@ static bool is_compatible_preset(const Preset& printer_preset, const PrinterAttr printer_preset.config.opt_string("printer_variant") == attr.variant_name; } -static void add_profile_node(pt::ptree& printer_profiles_node, const std::string& preset_name) +static void add_profile_node(pt::ptree& printer_profiles_node, const std::string& preset_name, const int extruders_cnt) { pt::ptree profile_node; - profile_node.put("", preset_name); + + profile_node.put("name", preset_name); + if (extruders_cnt > 0) + profile_node.put("extruders_cnt", extruders_cnt); + printer_profiles_node.push_back(std::make_pair("", profile_node)); } @@ -178,13 +180,16 @@ static void get_printer_profiles_node(pt::ptree& printer_profiles_node, for (const Preset& printer_preset : printer_presets) { + int extruders_cnt = printer_preset.printer_technology() == ptSLA ? 0 : + printer_preset.config.option("nozzle_diameter")->values.size(); + if (printer_preset.is_user()) { const Preset* parent_preset = printer_presets.get_preset_parent(printer_preset); if (parent_preset && printer_preset.is_visible && is_compatible_preset(*parent_preset, attr)) - add_profile_node(user_printer_profiles_node, printer_preset.name); + add_profile_node(user_printer_profiles_node, printer_preset.name, extruders_cnt); } else if (printer_preset.is_visible && is_compatible_preset(printer_preset, attr)) - add_profile_node(printer_profiles_node, printer_preset.name); + add_profile_node(printer_profiles_node, printer_preset.name, extruders_cnt); } } @@ -266,9 +271,7 @@ std::string get_json_printer_models(PrinterTechnology printer_technology) root.add_child("printer_models", vendor_node); // Serialize the tree into JSON and return it. - std::stringstream ss; - pt::write_json(ss, root); - return ss.str(); + return write_json_with_post_process(root); } static std::string get_installed_print_and_filament_profiles(const PresetBundle* preset_bundle, const Preset* printer_preset) @@ -335,9 +338,7 @@ static std::string get_installed_print_and_filament_profiles(const PresetBundle* tree.add_child("user_print_profiles", user_print_profiles); // Serialize the tree into JSON and return it. - std::stringstream ss; - pt::write_json(ss, tree); - return ss.str(); + return write_json_with_post_process(tree); } std::string get_json_print_filament_profiles(const std::string& printer_profile) diff --git a/src/libslic3r/Utils/JsonUtils.cpp b/src/libslic3r/Utils/JsonUtils.cpp new file mode 100644 index 0000000000..0419075987 --- /dev/null +++ b/src/libslic3r/Utils/JsonUtils.cpp @@ -0,0 +1,22 @@ +#include "JsonUtils.hpp" + +namespace Slic3r { + +namespace pt = boost::property_tree; + +std::string write_json_with_post_process(const pt::ptree& ptree) +{ + std::stringstream oss; + pt::write_json(oss, ptree); + + // fix json-out to show node values as a string just for string nodes + std::regex reg("\\\"([0-9]+\\.{0,1}[0-9]*)\\\""); // code is borrowed from https://stackoverflow.com/questions/2855741/why-does-boost-property-tree-write-json-save-everything-as-string-is-it-possibl + std::string result = std::regex_replace(oss.str(), reg, "$1"); + + boost::replace_all(result, "\"true\"", "true"); + boost::replace_all(result, "\"false\"", "false"); + + return result; +} + +} // namespace Slic3r diff --git a/src/libslic3r/Utils/JsonUtils.hpp b/src/libslic3r/Utils/JsonUtils.hpp new file mode 100644 index 0000000000..08745a620c --- /dev/null +++ b/src/libslic3r/Utils/JsonUtils.hpp @@ -0,0 +1,12 @@ +#ifndef slic3r_JsonUtils_hpp_ +#define slic3r_JsonUtils_hpp_ + +#include + +namespace Slic3r { + +std::string write_json_with_post_process(const boost::property_tree::ptree& ptree); + +} // namespace Slic3r + +#endif // slic3r_jsonUtils_hpp_ From a46980ca47f63e8d589df44ccb09f1dcb214c072 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 20 Feb 2024 13:13:17 +0100 Subject: [PATCH 10/14] Added CLI options to slice using the installed profiles SPE-2164 --- src/PrusaSlicer.cpp | 38 ++++++++ src/PrusaSlicer.hpp | 2 + src/libslic3r/PrintConfig.cpp | 21 +++- src/libslic3r/ProfilesSharingUtils.cpp | 129 +++++++++++++++++++++++++ src/libslic3r/ProfilesSharingUtils.hpp | 9 ++ 5 files changed, 194 insertions(+), 5 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 5a4ab0dc10..a57663fa35 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -173,6 +173,13 @@ int CLI::run(int argc, char **argv) m_print_config.apply(config); } + bool has_config_from_profiles = m_profiles_sharing.empty() && + (!m_config.opt_string("print-profile").empty() || + !m_config.option("material-profile")->values.empty() || + !m_config.opt_string("printer-profile").empty() ); + if (has_config_from_profiles && !check_and_load_input_profiles(printer_technology)) + return 1; + #ifdef SLIC3R_GUI #if ENABLE_GL_CORE_PROFILE std::pair opengl_version = { 0, 0 }; @@ -264,6 +271,9 @@ int CLI::run(int argc, char **argv) } Model model; try { + if (has_config_from_profiles) + model = Model::read_from_file(file, nullptr, nullptr, Model::LoadAttribute::AddDefaultInstances); + else { // When loading an AMF or 3MF, config is imported as well, including the printer technology. DynamicPrintConfig config; ConfigSubstitutionContext config_substitutions(config_substitution_rule); @@ -285,6 +295,7 @@ int CLI::run(int argc, char **argv) // config is applied to m_print_config before the current m_config values. config += std::move(m_print_config); m_print_config = std::move(config); + } } catch (std::exception& e) { boost::nowide::cerr << file << ": " << e.what() << std::endl; @@ -1048,6 +1059,33 @@ bool CLI::processed_profiles_sharing() return true; } +bool CLI::check_and_load_input_profiles(PrinterTechnology& printer_technology) +{ + Slic3r::DynamicPrintConfig config = {}; + std::string ret = Slic3r::load_full_print_config(m_config.opt_string("print-profile"), + m_config.option("material-profile")->values, + m_config.opt_string("printer-profile"), + config, printer_technology); + if (!ret.empty()) { + boost::nowide::cerr << ret << std::endl; + return false; + } + + config.normalize_fdm(); + + PrinterTechnology other_printer_technology = get_printer_technology(config); + if (printer_technology == ptUnknown) + printer_technology = other_printer_technology; + else if (printer_technology != other_printer_technology && other_printer_technology != ptUnknown) { + boost::nowide::cerr << "Mixing configurations for FFF and SLA technologies" << std::endl; + return false; + } + + m_print_config.apply(config); + + return true; +} + // __has_feature() is used later for Clang, this is for compatibility with other compilers (such as GCC and MSVC) #ifndef __has_feature # define __has_feature(x) 0 diff --git a/src/PrusaSlicer.hpp b/src/PrusaSlicer.hpp index 8910f56980..b11e1b5d30 100644 --- a/src/PrusaSlicer.hpp +++ b/src/PrusaSlicer.hpp @@ -42,6 +42,8 @@ private: bool has_print_action() const { return m_config.opt_bool("export_gcode") || m_config.opt_bool("export_sla"); } bool processed_profiles_sharing(); + + bool check_and_load_input_profiles(PrinterTechnology& printer_technology); std::string output_filepath(const Model &model, IO::ExportFormat format) const; }; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 413e01b5ab..391db4309e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5119,6 +5119,22 @@ CLIMiscConfigDef::CLIMiscConfigDef() def->tooltip = L("Render with a software renderer. The bundled MESA software renderer is loaded instead of the default OpenGL driver."); def->min = 0; #endif /* _MSC_VER */ + + def = this->add("printer-profile", coString); + def->label = ("Printer preset name"); + def->tooltip = ("Name of the printer preset used for slicing."); + def->set_default_value(new ConfigOptionString()); + + def = this->add("print-profile", coString); + def->label = ("Print preset name"); + def->tooltip = ("Name of the print preset used for slicing."); + def->set_default_value(new ConfigOptionString()); + + def = this->add("material-profile", coStrings); + def->label = ("Material preset name(s)"); + def->tooltip = ("Name(s) of the material preset(s) used for slicing.\n" + "Could be filaments or sla_material preset name(s) depending on printer tochnology"); + def->set_default_value(new ConfigOptionStrings()); } CLIProfilesSharingConfigDef::CLIProfilesSharingConfigDef() @@ -5151,11 +5167,6 @@ CLIProfilesSharingConfigDef::CLIProfilesSharingConfigDef() "Note:\n" "To print out JSON into file use 'output' option.\n" "To specify configuration folder use 'datadir' option."); - - def = this->add("printer-profile", coString); - def->label = ("Printer preset name"); - def->tooltip = ("Name of the printer preset used for slicing."); - def->set_default_value(new ConfigOptionString()); } const CLIActionsConfigDef cli_actions_config_def; diff --git a/src/libslic3r/ProfilesSharingUtils.cpp b/src/libslic3r/ProfilesSharingUtils.cpp index 79d46e1e1a..97564120f9 100644 --- a/src/libslic3r/ProfilesSharingUtils.cpp +++ b/src/libslic3r/ProfilesSharingUtils.cpp @@ -391,4 +391,133 @@ bool load_full_print_config(const std::string& print_preset_name, const std::str return !is_failed; } +// Helper function for load full config from installed presets by profile names +std::string load_full_print_config(const std::string& print_preset_name, + const std::vector& material_preset_names_in, + const std::string& printer_preset_name, + DynamicPrintConfig& config, + PrinterTechnology printer_technology) +{ + // check entered profile names + + if (print_preset_name.empty() || + material_preset_names_in.empty() || + printer_preset_name.empty()) + return "Request is not completed. All of Print/Material/Printer profiles have to be entered"; + + // check preset bundle + + PresetBundle preset_bundle; + if (!load_preset_bundle_from_datadir(preset_bundle)) + return Slic3r::format("Failed to load data from the datadir '%1%'.", data_dir()); + + // check existance of required profiles + + std::string errors; + + const Preset* printer_preset = preset_bundle.printers.find_preset(printer_preset_name); + if (!printer_preset) + errors += "\n" + Slic3r::format("Printer profile '%1%' wasn't found.", printer_preset_name); + else if (printer_technology == ptUnknown) + printer_technology = printer_preset->printer_technology(); + else if (printer_technology != printer_preset->printer_technology()) + errors += "\n" + std::string("Printer technology of the selected printer preset is differs with required printer technology"); + + PresetCollection& print_presets = printer_technology == ptFFF ? preset_bundle.prints : preset_bundle.sla_prints; + + const Preset* print_preset = print_presets.find_preset(print_preset_name); + if (!print_preset) + errors += "\n" + Slic3r::format("Print profile '%1%' wasn't found.", print_preset_name); + + PresetCollection& material_presets = printer_technology == ptFFF ? preset_bundle.filaments : preset_bundle.sla_materials; + + auto check_material = [&material_presets] (const std::string& name, std::string& errors) -> void { + const Preset* material_preset = material_presets.find_preset(name); + if (!material_preset) + errors += "\n" + Slic3r::format("Material profile '%1%' wasn't found.", name); + }; + + check_material(material_preset_names_in.front(), errors); + if (material_preset_names_in.size() > 1) { + for (int idx = 1; idx < material_preset_names_in.size(); idx++) { + if (material_preset_names_in[idx] != material_preset_names_in.front()) + check_material(material_preset_names_in[idx], errors); + } + } + + if (!errors.empty()) + return errors; + + // check and update list of material presets + + std::vector material_preset_names = material_preset_names_in; + + if (printer_technology == ptSLA && material_preset_names.size() > 1) { + BOOST_LOG_TRIVIAL(warning) << "Note: More than one sla material profiles were entered. Extras material profiles will be ignored."; + material_preset_names.resize(1); + } + + if (printer_technology == ptFFF) { + const int extruders_count = static_cast(printer_preset->config.option("nozzle_diameter"))->values.size(); + if (extruders_count > material_preset_names.size()) { + BOOST_LOG_TRIVIAL(warning) << "Note: Less than needed filament profiles were entered. Missed filament profiles will be filled with first material."; + material_preset_names.reserve(extruders_count); + for (int i = extruders_count - material_preset_names.size(); i > 0; i--) + material_preset_names.push_back(material_preset_names.front()); + } + else if (extruders_count < material_preset_names.size()) { + BOOST_LOG_TRIVIAL(warning) << "Note: More than needed filament profiles were entered. Extras filament profiles will be ignored."; + material_preset_names.resize(extruders_count); + } + } + + // check profiles compatibility + + const PresetWithVendorProfile printer_preset_with_vendor_profile = preset_bundle.printers.get_preset_with_vendor_profile(*printer_preset); + const PresetWithVendorProfile print_preset_with_vendor_profile = print_presets.get_preset_with_vendor_profile(*print_preset); + + if (!is_compatible_with_printer(print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) + errors += "\n" + Slic3r::format("Print profile '%1%' is not compatible with printer profile %2%.", print_preset_name, printer_preset_name); + + auto check_material_preset_compatibility = [&material_presets, printer_preset_name, print_preset_name, printer_preset_with_vendor_profile, print_preset_with_vendor_profile] + (const std::string& name, std::string& errors) -> void { + const Preset* material_preset = material_presets.find_preset(name); + const PresetWithVendorProfile material_preset_with_vendor_profile = material_presets.get_preset_with_vendor_profile(*material_preset); + + if (!is_compatible_with_printer(material_preset_with_vendor_profile, printer_preset_with_vendor_profile)) + errors += "\n" + Slic3r::format("Material profile '%1%' is not compatible with printer profile %2%.", name, printer_preset_name); + + if (!is_compatible_with_print(material_preset_with_vendor_profile, print_preset_with_vendor_profile, printer_preset_with_vendor_profile)) + errors += "\n" + Slic3r::format("Material profile '%1%' is not compatible with print profile %2%.", name, print_preset_name); + }; + + check_material_preset_compatibility(material_preset_names.front(), errors); + if (material_preset_names.size() > 1) { + for (int idx = 1; idx < material_preset_names.size(); idx++) { + if (material_preset_names[idx] != material_preset_names.front()) + check_material_preset_compatibility(material_preset_names[idx], errors); + } + } + + if (!errors.empty()) + return errors; + + // get full print configuration + + preset_bundle.printers.select_preset_by_name(printer_preset_name, true); + print_presets.select_preset_by_name(print_preset_name, true); + if (printer_technology == ptSLA) + material_presets.select_preset_by_name(material_preset_names.front(), true); + else if (printer_technology == ptFFF) { + auto& extruders_filaments = preset_bundle.extruders_filaments; + extruders_filaments.clear(); + for (size_t i = 0; i < material_preset_names.size(); ++i) + extruders_filaments.emplace_back(ExtruderFilaments(&preset_bundle.filaments, i, material_preset_names[i])); + } + + config = preset_bundle.full_config(); + + return ""; +} + } // namespace Slic3r diff --git a/src/libslic3r/ProfilesSharingUtils.hpp b/src/libslic3r/ProfilesSharingUtils.hpp index 4ea1539dbd..5eafe899e3 100644 --- a/src/libslic3r/ProfilesSharingUtils.hpp +++ b/src/libslic3r/ProfilesSharingUtils.hpp @@ -19,6 +19,15 @@ std::string GetDataDir(); class DynamicPrintConfig; bool load_full_print_config(const std::string& print_preset, const std::string& filament_preset, const std::string& printer_preset, DynamicPrintConfig& out_config); +// Load full print config into config +// Return error/warning string if any exists +std::string load_full_print_config( const std::string& print_preset_name, + const std::vector& material_preset_names, + const std::string& printer_preset_name, + DynamicPrintConfig& config, + PrinterTechnology printer_technology); + + } // namespace Slic3r #endif // slic3r_ProfilesSharingUtils_hpp_ From ce910eb60a38abb5d75104b9dfc2766f8a38eb47 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 20 Feb 2024 13:36:20 +0100 Subject: [PATCH 11/14] CLI: Fixed "query-printer-models". If printer_technology options isn't used, then ALL installed printer models will be returned. --- src/PrusaSlicer.cpp | 2 +- src/libslic3r/ProfilesSharingUtils.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index a57663fa35..20cfa5594a 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -992,7 +992,7 @@ bool CLI::processed_profiles_sharing() if (query_options.find(opt_key) != query_options.end()) continue; if (opt_key == "query-printer-models") { - ret = Slic3r::get_json_printer_models(Preset::printer_technology(m_config)); + ret = Slic3r::get_json_printer_models(get_printer_technology(m_config)); } /* else if (opt_key == "query-printer-profiles") { diff --git a/src/libslic3r/ProfilesSharingUtils.cpp b/src/libslic3r/ProfilesSharingUtils.cpp index 97564120f9..30d5232f5a 100644 --- a/src/libslic3r/ProfilesSharingUtils.cpp +++ b/src/libslic3r/ProfilesSharingUtils.cpp @@ -199,7 +199,7 @@ static void add_printer_models(pt::ptree& vendor_node, const PrinterPresetCollection& printer_presets) { for (const auto& printer_model : vendor_profile->models) { - if (printer_technology != ptAny && printer_model.technology != printer_technology) + if (printer_technology != ptUnknown && printer_model.technology != printer_technology) continue; pt::ptree variants_node; From d0e31a0e615cb29f7bd4fe16fabfdf7621cec5ed Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 20 Feb 2024 14:12:06 +0100 Subject: [PATCH 12/14] CLI: If model for slicing is loaded from 3mf file, then its geometry has to be used and arrange couldn't be apply for this model. So, check a state of "dont_arrange" parameter and set it to "true", if its value is "false". --- src/PrusaSlicer.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 20cfa5594a..0acdea245b 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -296,6 +296,12 @@ int CLI::run(int argc, char **argv) config += std::move(m_print_config); m_print_config = std::move(config); } + + // If model for slicing is loaded from 3mf file, then its geometry has to be used and arrange couldn't be apply for this model. + if ((boost::algorithm::iends_with(file, ".3mf") || boost::algorithm::iends_with(file, ".zip")) && !m_config.opt_bool("dont_arrange")) { + //So, check a state of "dont_arrange" parameter and set it to true, if its value is false. + m_config.set_key_value("dont_arrange", new ConfigOptionBool(true)); + } } catch (std::exception& e) { boost::nowide::cerr << file << ": " << e.what() << std::endl; From 7553d26b3ca2636dd2db458c1af651d32b608203 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Tue, 20 Feb 2024 14:41:32 +0100 Subject: [PATCH 13/14] Fixed OSX build --- src/libslic3r/MacUtils.mm | 7 ++----- src/libslic3r/ProfilesSharingUtils.hpp | 5 ----- src/libslic3r/Utils/DirectoriesUtils.hpp | 7 +++++++ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/MacUtils.mm b/src/libslic3r/MacUtils.mm index 30d3ab825d..ee1462fb79 100644 --- a/src/libslic3r/MacUtils.mm +++ b/src/libslic3r/MacUtils.mm @@ -1,10 +1,8 @@ -#import "ProfilesSharingUtils.hpp" +#import "Utils/DirectoriesUtils.hpp" #import -namespace Slic3r { - -// ProfilesSharingUtils.hpp +// Utils/DirectoriesUtils.hpp std::string GetDataDir() { NSURL* url = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory @@ -14,4 +12,3 @@ std::string GetDataDir() return std::string([(CFStringRef)url.path UTF8String]); } -} diff --git a/src/libslic3r/ProfilesSharingUtils.hpp b/src/libslic3r/ProfilesSharingUtils.hpp index 5eafe899e3..89c1068333 100644 --- a/src/libslic3r/ProfilesSharingUtils.hpp +++ b/src/libslic3r/ProfilesSharingUtils.hpp @@ -11,11 +11,6 @@ std::string get_json_printer_models(PrinterTechnology printer_technology); //std::string get_json_printer_profiles(const std::string& printer_model, const std::string& printer_variant); std::string get_json_print_filament_profiles(const std::string& printer_profile); -#if __APPLE__ -//implemented at MacUtils.mm -std::string GetDataDir(); -#endif //__APPLE__ - class DynamicPrintConfig; bool load_full_print_config(const std::string& print_preset, const std::string& filament_preset, const std::string& printer_preset, DynamicPrintConfig& out_config); diff --git a/src/libslic3r/Utils/DirectoriesUtils.hpp b/src/libslic3r/Utils/DirectoriesUtils.hpp index b7cc5dbceb..cafc054708 100644 --- a/src/libslic3r/Utils/DirectoriesUtils.hpp +++ b/src/libslic3r/Utils/DirectoriesUtils.hpp @@ -1,6 +1,13 @@ #ifndef slic3r_DirectoriesUtils_hpp_ #define slic3r_DirectoriesUtils_hpp_ +#include + +#if __APPLE__ +//implemented at MacUtils.mm +std::string GetDataDir(); +#endif //__APPLE__ + namespace Slic3r { std::string get_default_datadir(); From 1afb514fa1b9446229aa3ff23a07c61bde7fd1e0 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 1 Mar 2024 08:53:15 +0100 Subject: [PATCH 14/14] CLI: Printers with no vendor information are added for "--query-printer-profile" --- src/libslic3r/ProfilesSharingUtils.cpp | 42 ++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/ProfilesSharingUtils.cpp b/src/libslic3r/ProfilesSharingUtils.cpp index 30d5232f5a..b950b37c0d 100644 --- a/src/libslic3r/ProfilesSharingUtils.cpp +++ b/src/libslic3r/ProfilesSharingUtils.cpp @@ -179,16 +179,17 @@ static void get_printer_profiles_node(pt::ptree& printer_profiles_node, user_printer_profiles_node.clear(); for (const Preset& printer_preset : printer_presets) { - + if (!printer_preset.is_visible) + continue; int extruders_cnt = printer_preset.printer_technology() == ptSLA ? 0 : printer_preset.config.option("nozzle_diameter")->values.size(); if (printer_preset.is_user()) { const Preset* parent_preset = printer_presets.get_preset_parent(printer_preset); - if (parent_preset && printer_preset.is_visible && is_compatible_preset(*parent_preset, attr)) + if (parent_preset && is_compatible_preset(*parent_preset, attr)) add_profile_node(user_printer_profiles_node, printer_preset.name, extruders_cnt); } - else if (printer_preset.is_visible && is_compatible_preset(printer_preset, attr)) + else if (is_compatible_preset(printer_preset, attr)) add_profile_node(printer_profiles_node, printer_preset.name, extruders_cnt); } } @@ -255,6 +256,38 @@ static void add_printer_models(pt::ptree& vendor_node, } } +static void add_undef_printer_models(pt::ptree& vendor_node, + PrinterTechnology printer_technology, + const PrinterPresetCollection& printer_presets) +{ + for (auto pt : { ptFFF, ptSLA }) { + if (printer_technology != ptUnknown && printer_technology != pt) + continue; + + pt::ptree printer_profiles_node; + for (const Preset& preset : printer_presets) { + if (!preset.is_visible || preset.printer_technology() != pt || + preset.vendor || printer_presets.get_preset_parent(preset)) + continue; + + int extruders_cnt = preset.printer_technology() == ptSLA ? 0 : + preset.config.option("nozzle_diameter")->values.size(); + add_profile_node(printer_profiles_node, preset.name, extruders_cnt); + } + + if (!printer_profiles_node.empty()) { + pt::ptree data_node; + data_node.put("id", ""); + data_node.put("technology", pt == ptFFF ? "FFF" : "SLA"); + data_node.add_child("printer_profiles", printer_profiles_node); + data_node.put("vendor_name", ""); + data_node.put("vendor_id", ""); + + vendor_node.push_back(std::make_pair("", data_node)); + } + } +} + std::string get_json_printer_models(PrinterTechnology printer_technology) { PresetBundle preset_bundle; @@ -267,6 +300,9 @@ std::string get_json_printer_models(PrinterTechnology printer_technology) for (const auto& [vendor_id, vendor] : vendors_map) add_printer_models(vendor_node, &vendor, printer_technology, preset_bundle.printers); + // add printers with no vendor information + add_undef_printer_models(vendor_node, printer_technology, preset_bundle.printers); + pt::ptree root; root.add_child("printer_models", vendor_node);