mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-10 00:11:46 +08:00
Merge branch 'dk_templates_merge'
This commit is contained in:
commit
644deef392
2
resources/profiles/Templates.idx
Normal file
2
resources/profiles/Templates.idx
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
min_slic3r_version = 2.6.0-alpha0
|
||||||
|
1.0.0 Initial
|
2144
resources/profiles/Templates.ini
Normal file
2144
resources/profiles/Templates.ini
Normal file
File diff suppressed because it is too large
Load Diff
@ -36,6 +36,10 @@ static const std::string MODEL_PREFIX = "model:";
|
|||||||
// are phased out, then we will revert to the original name.
|
// are phased out, then we will revert to the original name.
|
||||||
//static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version";
|
//static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version";
|
||||||
static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version2";
|
static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version2";
|
||||||
|
// Url to index archive zip that contains latest indicies
|
||||||
|
static const std::string INDEX_ARCHIVE_URL= "https://files.prusa3d.com/wp-content/uploads/repository/vendor_indices.zip";
|
||||||
|
// Url to folder with vendor profile files. Used when downloading new profiles that are not in resources folder.
|
||||||
|
static const std::string PROFILE_FOLDER_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/";
|
||||||
|
|
||||||
const std::string AppConfig::SECTION_FILAMENTS = "filaments";
|
const std::string AppConfig::SECTION_FILAMENTS = "filaments";
|
||||||
const std::string AppConfig::SECTION_MATERIALS = "sla_materials";
|
const std::string AppConfig::SECTION_MATERIALS = "sla_materials";
|
||||||
@ -68,6 +72,8 @@ void AppConfig::set_defaults()
|
|||||||
// If set, the "- default -" selections of print/filament/printer are suppressed, if there is a valid preset available.
|
// If set, the "- default -" selections of print/filament/printer are suppressed, if there is a valid preset available.
|
||||||
if (get("no_defaults").empty())
|
if (get("no_defaults").empty())
|
||||||
set("no_defaults", "1");
|
set("no_defaults", "1");
|
||||||
|
if (get("no_templates").empty())
|
||||||
|
set("no_templates", "0");
|
||||||
if (get("show_incompatible_presets").empty())
|
if (get("show_incompatible_presets").empty())
|
||||||
set("show_incompatible_presets", "0");
|
set("show_incompatible_presets", "0");
|
||||||
|
|
||||||
@ -665,6 +671,26 @@ std::string AppConfig::version_check_url() const
|
|||||||
return from_settings.empty() ? VERSION_CHECK_URL : from_settings;
|
return from_settings.empty() ? VERSION_CHECK_URL : from_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string AppConfig::index_archive_url() const
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
// this code is for debug & testing purposes only - changed url wont get trough inner checks anyway.
|
||||||
|
auto from_settings = get("index_archive_url");
|
||||||
|
return from_settings.empty() ? INDEX_ARCHIVE_URL : from_settings;
|
||||||
|
#endif
|
||||||
|
return INDEX_ARCHIVE_URL;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AppConfig::profile_folder_url() const
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
// this code is for debug & testing purposes only - changed url wont get trough inner checks anyway.
|
||||||
|
auto from_settings = get("profile_folder_url");
|
||||||
|
return from_settings.empty() ? PROFILE_FOLDER_URL : from_settings;
|
||||||
|
#endif
|
||||||
|
return PROFILE_FOLDER_URL;
|
||||||
|
}
|
||||||
|
|
||||||
bool AppConfig::exists()
|
bool AppConfig::exists()
|
||||||
{
|
{
|
||||||
return boost::filesystem::exists(config_path());
|
return boost::filesystem::exists(config_path());
|
||||||
|
@ -139,6 +139,11 @@ public:
|
|||||||
// Get the Slic3r version check url.
|
// Get the Slic3r version check url.
|
||||||
// This returns a hardcoded string unless it is overriden by "version_check_url" in the ini file.
|
// This returns a hardcoded string unless it is overriden by "version_check_url" in the ini file.
|
||||||
std::string version_check_url() const;
|
std::string version_check_url() const;
|
||||||
|
// Get the Slic3r url to vendor index archive zip.
|
||||||
|
std::string index_archive_url() const;
|
||||||
|
// Get the Slic3r url to folder with vendor profile files.
|
||||||
|
std::string profile_folder_url() const;
|
||||||
|
|
||||||
|
|
||||||
// Returns the original Slic3r version found in the ini file before it was overwritten
|
// Returns the original Slic3r version found in the ini file before it was overwritten
|
||||||
// by the current version
|
// by the current version
|
||||||
|
@ -146,6 +146,11 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem
|
|||||||
res.changelog_url = changelog_url->second.data();
|
res.changelog_url = changelog_url->second.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto templates_profile = vendor_section.find("templates_profile");
|
||||||
|
if (templates_profile != vendor_section.not_found()) {
|
||||||
|
res.templates_profile = templates_profile->second.data() == "1";
|
||||||
|
}
|
||||||
|
|
||||||
if (! load_all) {
|
if (! load_all) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -200,6 +205,10 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem
|
|||||||
}
|
}
|
||||||
model.bed_model = section.second.get<std::string>("bed_model", "");
|
model.bed_model = section.second.get<std::string>("bed_model", "");
|
||||||
model.bed_texture = section.second.get<std::string>("bed_texture", "");
|
model.bed_texture = section.second.get<std::string>("bed_texture", "");
|
||||||
|
model.thumbnail = section.second.get<std::string>("thumbnail", "");
|
||||||
|
if (model.thumbnail.empty())
|
||||||
|
model.thumbnail = model.id + "_thumbnail.png";
|
||||||
|
|
||||||
if (! model.id.empty() && ! model.variants.empty())
|
if (! model.id.empty() && ! model.variants.empty())
|
||||||
res.models.push_back(std::move(model));
|
res.models.push_back(std::move(model));
|
||||||
}
|
}
|
||||||
@ -336,7 +345,8 @@ std::string Preset::label() const
|
|||||||
|
|
||||||
bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer)
|
bool is_compatible_with_print(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer)
|
||||||
{
|
{
|
||||||
if (preset.vendor != nullptr && preset.vendor != active_printer.vendor)
|
// templates_profile vendor profiles should be decided as same vendor profiles
|
||||||
|
if (preset.vendor != nullptr && preset.vendor != active_printer.vendor && !preset.vendor->templates_profile)
|
||||||
// The current profile has a vendor assigned and it is different from the active print's vendor.
|
// The current profile has a vendor assigned and it is different from the active print's vendor.
|
||||||
return false;
|
return false;
|
||||||
auto &condition = preset.preset.compatible_prints_condition();
|
auto &condition = preset.preset.compatible_prints_condition();
|
||||||
@ -358,7 +368,8 @@ bool is_compatible_with_print(const PresetWithVendorProfile &preset, const Prese
|
|||||||
|
|
||||||
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config)
|
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config)
|
||||||
{
|
{
|
||||||
if (preset.vendor != nullptr && preset.vendor != active_printer.vendor)
|
// templates_profile vendor profiles should be decided as same vendor profiles
|
||||||
|
if (preset.vendor != nullptr && preset.vendor != active_printer.vendor && !preset.vendor->templates_profile)
|
||||||
// The current profile has a vendor assigned and it is different from the active print's vendor.
|
// The current profile has a vendor assigned and it is different from the active print's vendor.
|
||||||
return false;
|
return false;
|
||||||
auto &condition = preset.preset.compatible_printers_condition();
|
auto &condition = preset.preset.compatible_printers_condition();
|
||||||
@ -1185,6 +1196,7 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
|
|||||||
if (opt)
|
if (opt)
|
||||||
config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast<const ConfigOptionFloats*>(opt)->values.size()));
|
config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast<const ConfigOptionFloats*>(opt)->values.size()));
|
||||||
bool some_compatible = false;
|
bool some_compatible = false;
|
||||||
|
std::vector<size_t> indices_of_template_presets;
|
||||||
for (size_t idx_preset = m_num_default_presets; idx_preset < m_presets.size(); ++ idx_preset) {
|
for (size_t idx_preset = m_num_default_presets; idx_preset < m_presets.size(); ++ idx_preset) {
|
||||||
bool selected = idx_preset == m_idx_selected;
|
bool selected = idx_preset == m_idx_selected;
|
||||||
Preset &preset_selected = m_presets[idx_preset];
|
Preset &preset_selected = m_presets[idx_preset];
|
||||||
@ -1201,7 +1213,29 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
|
|||||||
m_idx_selected = size_t(-1);
|
m_idx_selected = size_t(-1);
|
||||||
if (selected)
|
if (selected)
|
||||||
preset_selected.is_compatible = preset_edited.is_compatible;
|
preset_selected.is_compatible = preset_edited.is_compatible;
|
||||||
|
if (preset_edited.vendor && preset_edited.vendor->templates_profile) {
|
||||||
|
indices_of_template_presets.push_back(idx_preset);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// filter out template profiles where profile with same alias and compability exists
|
||||||
|
if (!indices_of_template_presets.empty()) {
|
||||||
|
for (size_t idx_preset = m_num_default_presets; idx_preset < m_presets.size(); ++idx_preset) {
|
||||||
|
if (m_presets[idx_preset].vendor && !m_presets[idx_preset].vendor->templates_profile && m_presets[idx_preset].is_compatible) {
|
||||||
|
std::string preset_alias = m_presets[idx_preset].alias;
|
||||||
|
for (size_t idx_of_template_in_presets : indices_of_template_presets) {
|
||||||
|
if (m_presets[idx_of_template_in_presets].alias == preset_alias) {
|
||||||
|
// unselect selected template filament if there is non-template alias compatible
|
||||||
|
if (idx_of_template_in_presets == m_idx_selected && (unselect_if_incompatible == PresetSelectCompatibleType::Always || unselect_if_incompatible == PresetSelectCompatibleType::OnlyIfWasCompatible)) {
|
||||||
|
m_idx_selected = size_t(-1);
|
||||||
|
}
|
||||||
|
m_presets[idx_of_template_in_presets].is_compatible = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update visibility of the default profiles here if the defaults are suppressed, the current profile is not compatible and we don't want to select another compatible profile.
|
// Update visibility of the default profiles here if the defaults are suppressed, the current profile is not compatible and we don't want to select another compatible profile.
|
||||||
if (m_idx_selected >= m_num_default_presets && m_default_suppressed)
|
if (m_idx_selected >= m_num_default_presets && m_default_suppressed)
|
||||||
for (size_t i = 0; i < m_num_default_presets; ++ i)
|
for (size_t i = 0; i < m_num_default_presets; ++ i)
|
||||||
@ -2099,6 +2133,25 @@ namespace PresetUtils {
|
|||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool vendor_profile_has_all_resources(const VendorProfile& vp)
|
||||||
|
{
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
|
std::string vendor_folder = Slic3r::data_dir() + "/vendor/" + vp.id + "/";
|
||||||
|
std::string rsrc_folder = Slic3r::resources_dir() + "/profiles/" + vp.id + "/";
|
||||||
|
std::string cache_folder = Slic3r::data_dir() + "/cache/" + vp.id + "/";
|
||||||
|
for (const VendorProfile::PrinterModel& model : vp.models) {
|
||||||
|
for (const std::string& res : { model.bed_texture, model.bed_model, model.thumbnail } ) {
|
||||||
|
if (! res.empty()
|
||||||
|
&& !fs::exists(fs::path(vendor_folder + res))
|
||||||
|
&& !fs::exists(fs::path(rsrc_folder + res))
|
||||||
|
&& !fs::exists(fs::path(cache_folder + res)))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
} // namespace PresetUtils
|
} // namespace PresetUtils
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -34,6 +34,7 @@ public:
|
|||||||
Semver config_version;
|
Semver config_version;
|
||||||
std::string config_update_url;
|
std::string config_update_url;
|
||||||
std::string changelog_url;
|
std::string changelog_url;
|
||||||
|
bool templates_profile { false };
|
||||||
|
|
||||||
struct PrinterVariant {
|
struct PrinterVariant {
|
||||||
PrinterVariant() {}
|
PrinterVariant() {}
|
||||||
@ -52,6 +53,7 @@ public:
|
|||||||
// Vendor & Printer Model specific print bed model & texture.
|
// Vendor & Printer Model specific print bed model & texture.
|
||||||
std::string bed_model;
|
std::string bed_model;
|
||||||
std::string bed_texture;
|
std::string bed_texture;
|
||||||
|
std::string thumbnail;
|
||||||
|
|
||||||
PrinterVariant* variant(const std::string &name) {
|
PrinterVariant* variant(const std::string &name) {
|
||||||
for (auto &v : this->variants)
|
for (auto &v : this->variants)
|
||||||
@ -619,6 +621,7 @@ namespace PresetUtils {
|
|||||||
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset);
|
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset);
|
||||||
std::string system_printer_bed_model(const Preset& preset);
|
std::string system_printer_bed_model(const Preset& preset);
|
||||||
std::string system_printer_bed_texture(const Preset& preset);
|
std::string system_printer_bed_texture(const Preset& preset);
|
||||||
|
bool vendor_profile_has_all_resources(const VendorProfile& vp);
|
||||||
} // namespace PresetUtils
|
} // namespace PresetUtils
|
||||||
|
|
||||||
|
|
||||||
|
@ -159,6 +159,7 @@ void PresetBundle::setup_directories()
|
|||||||
data_dir,
|
data_dir,
|
||||||
data_dir / "vendor",
|
data_dir / "vendor",
|
||||||
data_dir / "cache",
|
data_dir / "cache",
|
||||||
|
data_dir / "cache" / "vendor",
|
||||||
data_dir / "shapes",
|
data_dir / "shapes",
|
||||||
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
||||||
// Store the print/filament/printer presets into a "presets" directory.
|
// Store the print/filament/printer presets into a "presets" directory.
|
||||||
@ -1307,17 +1308,26 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle(
|
|||||||
try {
|
try {
|
||||||
pt::read_ini(ifs, tree);
|
pt::read_ini(ifs, tree);
|
||||||
} catch (const boost::property_tree::ini_parser::ini_parser_error &err) {
|
} catch (const boost::property_tree::ini_parser::ini_parser_error &err) {
|
||||||
throw Slic3r::RuntimeError(format("Failed loading config bundle \"%1%\"\nError: \"%2%\" at line %3%", path, err.message(), err.line()).c_str());
|
// This throw was uncatched. While other similar problems later are just returning empty pair.
|
||||||
|
//throw Slic3r::RuntimeError(format("Failed loading config bundle \"%1%\"\nError: \"%2%\" at line %3%", path, err.message(), err.line()).c_str());
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Failed loading config bundle \"%1%\"\nError: \"%2%\" at line %3%", path, err.message(), err.line()).c_str();
|
||||||
|
return std::make_pair(PresetsConfigSubstitutions{}, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const VendorProfile *vendor_profile = nullptr;
|
const VendorProfile *vendor_profile = nullptr;
|
||||||
if (flags.has(LoadConfigBundleAttribute::LoadSystem) || flags.has(LoadConfigBundleAttribute::LoadVendorOnly)) {
|
if (flags.has(LoadConfigBundleAttribute::LoadSystem) || flags.has(LoadConfigBundleAttribute::LoadVendorOnly)) {
|
||||||
auto vp = VendorProfile::from_ini(tree, path);
|
VendorProfile vp;
|
||||||
if (vp.models.size() == 0) {
|
try {
|
||||||
|
vp = VendorProfile::from_ini(tree, path);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: Failed to open profile file.") % path;
|
||||||
|
return std::make_pair(PresetsConfigSubstitutions{}, 0);
|
||||||
|
}
|
||||||
|
if (vp.models.size() == 0 && !vp.templates_profile) {
|
||||||
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: No printer model defined.") % path;
|
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: No printer model defined.") % path;
|
||||||
return std::make_pair(PresetsConfigSubstitutions{}, 0);
|
return std::make_pair(PresetsConfigSubstitutions{}, 0);
|
||||||
} else if (vp.num_variants() == 0) {
|
} else if (vp.num_variants() == 0 && !vp.templates_profile) {
|
||||||
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: No printer variant defined") % path;
|
BOOST_LOG_TRIVIAL(error) << boost::format("Vendor bundle: `%1%`: No printer variant defined") % path;
|
||||||
return std::make_pair(PresetsConfigSubstitutions{}, 0);
|
return std::make_pair(PresetsConfigSubstitutions{}, 0);
|
||||||
}
|
}
|
||||||
@ -1359,6 +1369,9 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle(
|
|||||||
} else if (boost::starts_with(section.first, "filament:")) {
|
} else if (boost::starts_with(section.first, "filament:")) {
|
||||||
presets = &this->filaments;
|
presets = &this->filaments;
|
||||||
preset_name = section.first.substr(9);
|
preset_name = section.first.substr(9);
|
||||||
|
if (vendor_profile && vendor_profile->templates_profile) {
|
||||||
|
preset_name += " @Template";
|
||||||
|
}
|
||||||
} else if (boost::starts_with(section.first, "sla_print:")) {
|
} else if (boost::starts_with(section.first, "sla_print:")) {
|
||||||
presets = &this->sla_prints;
|
presets = &this->sla_prints;
|
||||||
preset_name = section.first.substr(10);
|
preset_name = section.first.substr(10);
|
||||||
|
@ -73,10 +73,10 @@ using Config::SnapshotDB;
|
|||||||
|
|
||||||
// Configuration data structures extensions needed for the wizard
|
// Configuration data structures extensions needed for the wizard
|
||||||
|
|
||||||
bool Bundle::load(fs::path source_path, bool ais_in_resources, bool ais_prusa_bundle)
|
bool Bundle::load(fs::path source_path, BundleLocation location, bool ais_prusa_bundle)
|
||||||
{
|
{
|
||||||
this->preset_bundle = std::make_unique<PresetBundle>();
|
this->preset_bundle = std::make_unique<PresetBundle>();
|
||||||
this->is_in_resources = ais_in_resources;
|
this->location = location;
|
||||||
this->is_prusa_bundle = ais_prusa_bundle;
|
this->is_prusa_bundle = ais_prusa_bundle;
|
||||||
|
|
||||||
std::string path_string = source_path.string();
|
std::string path_string = source_path.string();
|
||||||
@ -104,7 +104,7 @@ bool Bundle::load(fs::path source_path, bool ais_in_resources, bool ais_prusa_bu
|
|||||||
Bundle::Bundle(Bundle &&other)
|
Bundle::Bundle(Bundle &&other)
|
||||||
: preset_bundle(std::move(other.preset_bundle))
|
: preset_bundle(std::move(other.preset_bundle))
|
||||||
, vendor_profile(other.vendor_profile)
|
, vendor_profile(other.vendor_profile)
|
||||||
, is_in_resources(other.is_in_resources)
|
, location(other.location)
|
||||||
, is_prusa_bundle(other.is_prusa_bundle)
|
, is_prusa_bundle(other.is_prusa_bundle)
|
||||||
{
|
{
|
||||||
other.vendor_profile = nullptr;
|
other.vendor_profile = nullptr;
|
||||||
@ -115,25 +115,35 @@ BundleMap BundleMap::load()
|
|||||||
BundleMap res;
|
BundleMap res;
|
||||||
|
|
||||||
const auto vendor_dir = (boost::filesystem::path(Slic3r::data_dir()) / "vendor").make_preferred();
|
const auto vendor_dir = (boost::filesystem::path(Slic3r::data_dir()) / "vendor").make_preferred();
|
||||||
|
const auto archive_dir = (boost::filesystem::path(Slic3r::data_dir()) / "cache" / "vendor").make_preferred();
|
||||||
const auto rsrc_vendor_dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred();
|
const auto rsrc_vendor_dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred();
|
||||||
|
|
||||||
|
// Load Prusa bundle from the datadir/vendor directory or from datadir/cache/vendor (archive) or from resources/profiles.
|
||||||
auto prusa_bundle_path = (vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini");
|
auto prusa_bundle_path = (vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini");
|
||||||
auto prusa_bundle_rsrc = false;
|
BundleLocation prusa_bundle_loc = BundleLocation::IN_VENDOR;
|
||||||
if (! boost::filesystem::exists(prusa_bundle_path)) {
|
if (! boost::filesystem::exists(prusa_bundle_path)) {
|
||||||
|
prusa_bundle_path = (archive_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini");
|
||||||
|
prusa_bundle_loc = BundleLocation::IN_ARCHIVE;
|
||||||
|
}
|
||||||
|
if (!boost::filesystem::exists(prusa_bundle_path)) {
|
||||||
prusa_bundle_path = (rsrc_vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini");
|
prusa_bundle_path = (rsrc_vendor_dir / PresetBundle::PRUSA_BUNDLE).replace_extension(".ini");
|
||||||
prusa_bundle_rsrc = true;
|
prusa_bundle_loc = BundleLocation::IN_RESOURCES;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Bundle prusa_bundle;
|
Bundle prusa_bundle;
|
||||||
if (prusa_bundle.load(std::move(prusa_bundle_path), prusa_bundle_rsrc, true))
|
if (prusa_bundle.load(std::move(prusa_bundle_path), prusa_bundle_loc, true))
|
||||||
res.emplace(PresetBundle::PRUSA_BUNDLE, std::move(prusa_bundle));
|
res.emplace(PresetBundle::PRUSA_BUNDLE, std::move(prusa_bundle));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the other bundles in the datadir/vendor directory
|
// Load the other bundles in the datadir/vendor directory
|
||||||
// and then additionally from resources/profiles.
|
// and then additionally from datadir/cache/vendor (archive) and resources/profiles.
|
||||||
bool is_in_resources = false;
|
// Should we concider case where archive has older profiles than resources (shouldnt happen)?
|
||||||
for (auto dir : { &vendor_dir, &rsrc_vendor_dir }) {
|
typedef std::pair<const fs::path&, BundleLocation> DirData;
|
||||||
for (const auto &dir_entry : boost::filesystem::directory_iterator(*dir)) {
|
std::vector<DirData> dir_list { {vendor_dir, BundleLocation::IN_VENDOR}, {archive_dir, BundleLocation::IN_ARCHIVE}, {rsrc_vendor_dir, BundleLocation::IN_RESOURCES} };
|
||||||
|
for ( auto dir : dir_list) {
|
||||||
|
if (!fs::exists(dir.first))
|
||||||
|
continue;
|
||||||
|
for (const auto &dir_entry : boost::filesystem::directory_iterator(dir.first)) {
|
||||||
if (Slic3r::is_ini_file(dir_entry)) {
|
if (Slic3r::is_ini_file(dir_entry)) {
|
||||||
std::string id = dir_entry.path().stem().string(); // stem() = filename() without the trailing ".ini" part
|
std::string id = dir_entry.path().stem().string(); // stem() = filename() without the trailing ".ini" part
|
||||||
|
|
||||||
@ -141,12 +151,10 @@ BundleMap BundleMap::load()
|
|||||||
if (res.find(id) != res.end()) { continue; }
|
if (res.find(id) != res.end()) { continue; }
|
||||||
|
|
||||||
Bundle bundle;
|
Bundle bundle;
|
||||||
if (bundle.load(dir_entry.path(), is_in_resources))
|
if (bundle.load(dir_entry.path(), dir.second))
|
||||||
res.emplace(std::move(id), std::move(bundle));
|
res.emplace(std::move(id), std::move(bundle));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
is_in_resources = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -220,29 +228,41 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
|
|||||||
|
|
||||||
bool is_variants = false;
|
bool is_variants = false;
|
||||||
|
|
||||||
|
const fs::path vendor_dir_path = (fs::path(Slic3r::data_dir()) / "vendor").make_preferred();
|
||||||
|
const fs::path cache_dir_path = (fs::path(Slic3r::data_dir()) / "cache").make_preferred();
|
||||||
|
const fs::path rsrc_dir_path = (fs::path(resources_dir()) / "profiles").make_preferred();
|
||||||
|
|
||||||
for (const auto &model : models) {
|
for (const auto &model : models) {
|
||||||
if (! filter(model)) { continue; }
|
if (! filter(model)) { continue; }
|
||||||
|
|
||||||
wxBitmap bitmap;
|
wxBitmap bitmap;
|
||||||
int bitmap_width = 0;
|
int bitmap_width = 0;
|
||||||
auto load_bitmap = [](const wxString& bitmap_file, wxBitmap& bitmap, int& bitmap_width)->bool {
|
auto load_bitmap = [](const wxString& bitmap_file, wxBitmap& bitmap, int& bitmap_width) {
|
||||||
if (wxFileExists(bitmap_file)) {
|
|
||||||
bitmap.LoadFile(bitmap_file, wxBITMAP_TYPE_PNG);
|
bitmap.LoadFile(bitmap_file, wxBITMAP_TYPE_PNG);
|
||||||
bitmap_width = bitmap.GetWidth();
|
bitmap_width = bitmap.GetWidth();
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
if (!load_bitmap(GUI::from_u8(Slic3r::data_dir() + "/vendor/" + vendor.id + "/" + model.id + "_thumbnail.png"), bitmap, bitmap_width)) {
|
|
||||||
if (!load_bitmap(GUI::from_u8(Slic3r::resources_dir() + "/profiles/" + vendor.id + "/" + model.id + "_thumbnail.png"), bitmap, bitmap_width)) {
|
bool found = false;
|
||||||
|
for (const fs::path& res : { rsrc_dir_path / vendor.id / model.thumbnail
|
||||||
|
, vendor_dir_path / vendor.id / model.thumbnail
|
||||||
|
, cache_dir_path / vendor.id / model.thumbnail })
|
||||||
|
{
|
||||||
|
if (!fs::exists(res))
|
||||||
|
continue;
|
||||||
|
load_bitmap(GUI::from_u8(res.string()), bitmap, bitmap_width);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
BOOST_LOG_TRIVIAL(warning) << boost::format("Can't find bitmap file `%1%` for vendor `%2%`, printer `%3%`, using placeholder icon instead")
|
BOOST_LOG_TRIVIAL(warning) << boost::format("Can't find bitmap file `%1%` for vendor `%2%`, printer `%3%`, using placeholder icon instead")
|
||||||
% (Slic3r::resources_dir() + "/profiles/" + vendor.id + "/" + model.id + "_thumbnail.png")
|
% model.thumbnail
|
||||||
% vendor.id
|
% vendor.id
|
||||||
% model.id;
|
% model.id;
|
||||||
load_bitmap(Slic3r::var(PRINTER_PLACEHOLDER), bitmap, bitmap_width);
|
load_bitmap(Slic3r::var(PRINTER_PLACEHOLDER), bitmap, bitmap_width);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
auto *title = new wxStaticText(this, wxID_ANY, from_u8(model.name), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
|
wxStaticText* title = new wxStaticText(this, wxID_ANY, from_u8(model.name), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
|
||||||
title->SetFont(font_name);
|
title->SetFont(font_name);
|
||||||
const int wrap_width = std::max((int)MODEL_MIN_WRAP, bitmap_width);
|
const int wrap_width = std::max((int)MODEL_MIN_WRAP, bitmap_width);
|
||||||
title->Wrap(wrap_width);
|
title->Wrap(wrap_width);
|
||||||
@ -255,7 +275,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
|
|||||||
|
|
||||||
titles.push_back(title);
|
titles.push_back(title);
|
||||||
|
|
||||||
auto *bitmap_widget = new wxStaticBitmap(this, wxID_ANY, bitmap);
|
wxStaticBitmap* bitmap_widget = new wxStaticBitmap(this, wxID_ANY, bitmap);
|
||||||
bitmaps.push_back(bitmap_widget);
|
bitmaps.push_back(bitmap_widget);
|
||||||
|
|
||||||
auto *variants_panel = new wxPanel(this);
|
auto *variants_panel = new wxPanel(this);
|
||||||
@ -278,7 +298,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
|
|||||||
is_variants = true;
|
is_variants = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *cbox = new Checkbox(variants_panel, label, model_id, variant.name);
|
Checkbox* cbox = new Checkbox(variants_panel, label, model_id, variant.name);
|
||||||
i == 0 ? cboxes.push_back(cbox) : cboxes_alt.push_back(cbox);
|
i == 0 ? cboxes.push_back(cbox) : cboxes_alt.push_back(cbox);
|
||||||
|
|
||||||
const bool enabled = appconfig.get_variant(vendor.id, model_id, variant.name);
|
const bool enabled = appconfig.get_variant(vendor.id, model_id, variant.name);
|
||||||
@ -620,6 +640,7 @@ void PagePrinters::set_run_reason(ConfigWizard::RunReason run_reason)
|
|||||||
|
|
||||||
|
|
||||||
const std::string PageMaterials::EMPTY;
|
const std::string PageMaterials::EMPTY;
|
||||||
|
const std::string PageMaterials::TEMPLATES = "templates";
|
||||||
|
|
||||||
PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name)
|
PageMaterials::PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name)
|
||||||
: ConfigWizardPage(parent, std::move(title), std::move(shortname))
|
: ConfigWizardPage(parent, std::move(title), std::move(shortname))
|
||||||
@ -727,6 +748,11 @@ void PageMaterials::reload_presets()
|
|||||||
clear();
|
clear();
|
||||||
|
|
||||||
list_printer->append(_L("(All)"), &EMPTY);
|
list_printer->append(_L("(All)"), &EMPTY);
|
||||||
|
|
||||||
|
const AppConfig* app_config = wxGetApp().app_config;
|
||||||
|
if (materials->technology == T_FFF && app_config->get("no_templates") == "0")
|
||||||
|
list_printer->append(_L("(Templates)"), &TEMPLATES);
|
||||||
|
|
||||||
//list_printer->SetLabelMarkup("<b>bald</b>");
|
//list_printer->SetLabelMarkup("<b>bald</b>");
|
||||||
for (const Preset* printer : materials->printers) {
|
for (const Preset* printer : materials->printers) {
|
||||||
list_printer->append(printer->name, &printer->name);
|
list_printer->append(printer->name, &printer->name);
|
||||||
@ -758,8 +784,12 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector<std::s
|
|||||||
const auto text_clr = wxGetApp().get_label_clr_default();
|
const auto text_clr = wxGetApp().get_label_clr_default();
|
||||||
const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
|
const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue()));
|
||||||
const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
|
const auto text_clr_str = encode_color(ColorRGB(text_clr.Red(), text_clr.Green(), text_clr.Blue()));
|
||||||
wxString first_line = format_wxstr(_L("%1% marked with <b>*</b> are <b>not</b> compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
|
|
||||||
wxString text;
|
wxString text;
|
||||||
|
if (materials->technology == T_FFF && template_shown) {
|
||||||
|
text = format_wxstr(_L("%1% visible for <b>(\"Template\")</b> printer are universal profiles available for all printers. These might not be compatible with your printer."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
|
||||||
|
} else {
|
||||||
|
wxString first_line = format_wxstr(_L("%1% marked with <b>*</b> are <b>not</b> compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials"));
|
||||||
|
|
||||||
if (all_printers) {
|
if (all_printers) {
|
||||||
wxString second_line = format_wxstr(_L("All installed printers are compatible with the selected %1%."), materials->technology == T_FFF ? _L("filament") : _L("SLA material"));
|
wxString second_line = format_wxstr(_L("All installed printers are compatible with the selected %1%."), materials->technology == T_FFF ? _L("filament") : _L("SLA material"));
|
||||||
text = wxString::Format(
|
text = wxString::Format(
|
||||||
@ -780,7 +810,8 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector<std::s
|
|||||||
, first_line
|
, first_line
|
||||||
, second_line
|
, second_line
|
||||||
);
|
);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
wxString second_line;
|
wxString second_line;
|
||||||
if (!printer_names.empty())
|
if (!printer_names.empty())
|
||||||
second_line = (materials->technology == T_FFF ?
|
second_line = (materials->technology == T_FFF ?
|
||||||
@ -819,6 +850,8 @@ void PageMaterials::set_compatible_printers_html_window(const std::vector<std::s
|
|||||||
"</html>"
|
"</html>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
wxFont font = get_default_font_for_dpi(this, get_dpi_for_window(this));
|
wxFont font = get_default_font_for_dpi(this, get_dpi_for_window(this));
|
||||||
const int fs = font.GetPointSize();
|
const int fs = font.GetPointSize();
|
||||||
@ -863,6 +896,8 @@ void PageMaterials::on_material_highlighted(int sel_material)
|
|||||||
std::vector<std::string> names;
|
std::vector<std::string> names;
|
||||||
for (const Preset* printer : materials->printers) {
|
for (const Preset* printer : materials->printers) {
|
||||||
for (const Preset* material : matching_materials) {
|
for (const Preset* material : matching_materials) {
|
||||||
|
if (material->vendor && material->vendor->templates_profile)
|
||||||
|
continue;
|
||||||
if (is_compatible_with_printer(PresetWithVendorProfile(*material, material->vendor), PresetWithVendorProfile(*printer, printer->vendor))) {
|
if (is_compatible_with_printer(PresetWithVendorProfile(*material, material->vendor), PresetWithVendorProfile(*printer, printer->vendor))) {
|
||||||
names.push_back(printer->name);
|
names.push_back(printer->name);
|
||||||
break;
|
break;
|
||||||
@ -880,6 +915,8 @@ void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected
|
|||||||
wxArrayInt sel_printers;
|
wxArrayInt sel_printers;
|
||||||
int sel_printers_count = list_printer->GetSelections(sel_printers);
|
int sel_printers_count = list_printer->GetSelections(sel_printers);
|
||||||
|
|
||||||
|
bool templates_available = list_printer->size() > 1 && list_printer->get_data(1) == TEMPLATES;
|
||||||
|
|
||||||
// Does our wxWidgets version support operator== for wxArrayInt ?
|
// Does our wxWidgets version support operator== for wxArrayInt ?
|
||||||
// https://github.com/prusa3d/PrusaSlicer/issues/5152#issuecomment-787208614
|
// https://github.com/prusa3d/PrusaSlicer/issues/5152#issuecomment-787208614
|
||||||
#if wxCHECK_VERSION(3, 1, 1)
|
#if wxCHECK_VERSION(3, 1, 1)
|
||||||
@ -895,13 +932,14 @@ void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected
|
|||||||
};
|
};
|
||||||
if (!are_equal(sel_printers, sel_printers_prev)) {
|
if (!are_equal(sel_printers, sel_printers_prev)) {
|
||||||
#endif
|
#endif
|
||||||
|
template_shown = false;
|
||||||
// Refresh type list
|
// Refresh type list
|
||||||
list_type->Clear();
|
list_type->Clear();
|
||||||
list_type->append(_L("(All)"), &EMPTY);
|
list_type->append(_L("(All)"), &EMPTY);
|
||||||
if (sel_printers_count > 0) {
|
if (sel_printers_count > 1) {
|
||||||
// If all is selected with other printers
|
// If all is selected with other printers
|
||||||
// unselect "all" or all printers depending on last value
|
// unselect "all" or all printers depending on last value
|
||||||
|
// same with "templates"
|
||||||
if (sel_printers[0] == 0 && sel_printers_count > 1) {
|
if (sel_printers[0] == 0 && sel_printers_count > 1) {
|
||||||
if (last_selected_printer == 0) {
|
if (last_selected_printer == 0) {
|
||||||
list_printer->SetSelection(wxNOT_FOUND);
|
list_printer->SetSelection(wxNOT_FOUND);
|
||||||
@ -911,7 +949,18 @@ void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected
|
|||||||
sel_printers_count = list_printer->GetSelections(sel_printers);
|
sel_printers_count = list_printer->GetSelections(sel_printers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sel_printers[0] != 0) {
|
if (materials->technology == T_FFF && templates_available && (sel_printers[0] == 1 || sel_printers[1] == 1) && sel_printers_count > 1) {
|
||||||
|
if (last_selected_printer == 1) {
|
||||||
|
list_printer->SetSelection(wxNOT_FOUND);
|
||||||
|
list_printer->SetSelection(1);
|
||||||
|
}
|
||||||
|
else if (last_selected_printer != 0) {
|
||||||
|
list_printer->SetSelection(1, false);
|
||||||
|
sel_printers_count = list_printer->GetSelections(sel_printers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sel_printers_count > 0 && sel_printers[0] != 0 && ((materials->technology == T_FFF && templates_available && sel_printers[0] != 1) || materials->technology != T_FFF || !templates_available)) {
|
||||||
for (int i = 0; i < sel_printers_count; i++) {
|
for (int i = 0; i < sel_printers_count; i++) {
|
||||||
const std::string& printer_name = list_printer->get_data(sel_printers[i]);
|
const std::string& printer_name = list_printer->get_data(sel_printers[i]);
|
||||||
const Preset* printer = nullptr;
|
const Preset* printer = nullptr;
|
||||||
@ -921,20 +970,35 @@ void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
materials->filter_presets(printer, EMPTY, EMPTY, [this](const Preset* p) {
|
materials->filter_presets(printer, printer_name, EMPTY, EMPTY, [this](const Preset* p) {
|
||||||
const std::string& type = this->materials->get_type(p);
|
const std::string& type = this->materials->get_type(p);
|
||||||
if (list_type->find(type) == wxNOT_FOUND) {
|
if (list_type->find(type) == wxNOT_FOUND) {
|
||||||
list_type->append(type, &type);
|
list_type->append(type, &type);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else if (sel_printers_count > 0 && last_selected_printer == 0) {
|
||||||
//clear selection except "ALL"
|
//clear selection except "ALL"
|
||||||
list_printer->SetSelection(wxNOT_FOUND);
|
list_printer->SetSelection(wxNOT_FOUND);
|
||||||
list_printer->SetSelection(0);
|
list_printer->SetSelection(0);
|
||||||
sel_printers_count = list_printer->GetSelections(sel_printers);
|
sel_printers_count = list_printer->GetSelections(sel_printers);
|
||||||
|
|
||||||
materials->filter_presets(nullptr, EMPTY, EMPTY, [this](const Preset* p) {
|
materials->filter_presets(nullptr, EMPTY, EMPTY, EMPTY, [this](const Preset* p) {
|
||||||
|
const std::string& type = this->materials->get_type(p);
|
||||||
|
if (list_type->find(type) == wxNOT_FOUND) {
|
||||||
|
list_type->append(type, &type);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (materials->technology == T_FFF && templates_available && sel_printers_count > 0 && last_selected_printer == 1) {
|
||||||
|
//clear selection except "TEMPLATES"
|
||||||
|
list_printer->SetSelection(wxNOT_FOUND);
|
||||||
|
list_printer->SetSelection(1);
|
||||||
|
sel_printers_count = list_printer->GetSelections(sel_printers);
|
||||||
|
template_shown = true;
|
||||||
|
materials->filter_presets(nullptr, TEMPLATES, EMPTY, EMPTY,
|
||||||
|
[this](const Preset* p) {
|
||||||
const std::string& type = this->materials->get_type(p);
|
const std::string& type = this->materials->get_type(p);
|
||||||
if (list_type->find(type) == wxNOT_FOUND) {
|
if (list_type->find(type) == wxNOT_FOUND) {
|
||||||
list_type->append(type, &type);
|
list_type->append(type, &type);
|
||||||
@ -942,7 +1006,6 @@ void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
sort_list_data(list_type, true, true);
|
sort_list_data(list_type, true, true);
|
||||||
}
|
|
||||||
|
|
||||||
sel_printers_prev = sel_printers;
|
sel_printers_prev = sel_printers;
|
||||||
sel_type = 0;
|
sel_type = 0;
|
||||||
@ -971,7 +1034,7 @@ void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
materials->filter_presets(printer, type, EMPTY, [this](const Preset* p) {
|
materials->filter_presets(printer, printer_name, type, EMPTY, [this](const Preset* p) {
|
||||||
const std::string& vendor = this->materials->get_vendor(p);
|
const std::string& vendor = this->materials->get_vendor(p);
|
||||||
if (list_vendor->find(vendor) == wxNOT_FOUND) {
|
if (list_vendor->find(vendor) == wxNOT_FOUND) {
|
||||||
list_vendor->append(vendor, &vendor);
|
list_vendor->append(vendor, &vendor);
|
||||||
@ -996,7 +1059,7 @@ void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected
|
|||||||
if (sel_printers_count != 0 && sel_type != wxNOT_FOUND && sel_vendor != wxNOT_FOUND) {
|
if (sel_printers_count != 0 && sel_type != wxNOT_FOUND && sel_vendor != wxNOT_FOUND) {
|
||||||
const std::string& type = list_type->get_data(sel_type);
|
const std::string& type = list_type->get_data(sel_type);
|
||||||
const std::string& vendor = list_vendor->get_data(sel_vendor);
|
const std::string& vendor = list_vendor->get_data(sel_vendor);
|
||||||
// finst printer preset
|
// first printer preset
|
||||||
std::vector<ProfilePrintData> to_list;
|
std::vector<ProfilePrintData> to_list;
|
||||||
for (int i = 0; i < sel_printers_count; i++) {
|
for (int i = 0; i < sel_printers_count; i++) {
|
||||||
const std::string& printer_name = list_printer->get_data(sel_printers[i]);
|
const std::string& printer_name = list_printer->get_data(sel_printers[i]);
|
||||||
@ -1007,15 +1070,14 @@ void PageMaterials::update_lists(int sel_type, int sel_vendor, int last_selected
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
materials->filter_presets(printer, printer_name, type, vendor, [this, &to_list](const Preset* p) {
|
||||||
materials->filter_presets(printer, type, vendor, [this, &to_list](const Preset* p) {
|
|
||||||
const std::string& section = materials->appconfig_section();
|
const std::string& section = materials->appconfig_section();
|
||||||
bool checked = wizard_p()->appconfig_new.has(section, p->name);
|
bool checked = wizard_p()->appconfig_new.has(section, p->name);
|
||||||
bool was_checked = false;
|
bool was_checked = false;
|
||||||
|
|
||||||
int cur_i = list_profile->find(p->alias);
|
int cur_i = list_profile->find(p->alias);
|
||||||
if (cur_i == wxNOT_FOUND) {
|
if (cur_i == wxNOT_FOUND) {
|
||||||
cur_i = list_profile->append(p->alias + (materials->get_omnipresent(p) ? "" : " *"), &p->alias);
|
cur_i = list_profile->append(p->alias + (materials->get_omnipresent(p) || template_shown ? "" : " *"), &p->alias);
|
||||||
to_list.emplace_back(p->alias, materials->get_omnipresent(p), checked);
|
to_list.emplace_back(p->alias, materials->get_omnipresent(p), checked);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1053,10 +1115,15 @@ void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool mat
|
|||||||
|
|
||||||
std::vector<std::reference_wrapper<const std::string>> prusa_profiles;
|
std::vector<std::reference_wrapper<const std::string>> prusa_profiles;
|
||||||
std::vector<std::reference_wrapper<const std::string>> other_profiles;
|
std::vector<std::reference_wrapper<const std::string>> other_profiles;
|
||||||
|
bool add_TEMPLATES_item = false;
|
||||||
for (int i = 0 ; i < list->size(); ++i) {
|
for (int i = 0 ; i < list->size(); ++i) {
|
||||||
const std::string& data = list->get_data(i);
|
const std::string& data = list->get_data(i);
|
||||||
if (data == EMPTY) // do not sort <all> item
|
if (data == EMPTY) // do not sort <all> item
|
||||||
continue;
|
continue;
|
||||||
|
if (data == TEMPLATES) {// do not sort <templates> item
|
||||||
|
add_TEMPLATES_item = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!material_type_ordering && data.find("Prusa") != std::string::npos)
|
if (!material_type_ordering && data.find("Prusa") != std::string::npos)
|
||||||
prusa_profiles.push_back(data);
|
prusa_profiles.push_back(data);
|
||||||
else
|
else
|
||||||
@ -1095,10 +1162,13 @@ void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool mat
|
|||||||
list->Clear();
|
list->Clear();
|
||||||
if (add_All_item)
|
if (add_All_item)
|
||||||
list->append(_L("(All)"), &EMPTY);
|
list->append(_L("(All)"), &EMPTY);
|
||||||
|
if (materials->technology == T_FFF && add_TEMPLATES_item)
|
||||||
|
list->append(_L("(Templates)"), &TEMPLATES);
|
||||||
for (const auto& item : prusa_profiles)
|
for (const auto& item : prusa_profiles)
|
||||||
list->append(item, &const_cast<std::string&>(item.get()));
|
list->append(item, &const_cast<std::string&>(item.get()));
|
||||||
for (const auto& item : other_profiles)
|
for (const auto& item : other_profiles)
|
||||||
list->append(item, &const_cast<std::string&>(item.get()));
|
list->append(item, &const_cast<std::string&>(item.get()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageMaterials::sort_list_data(PresetList* list, const std::vector<ProfilePrintData>& data)
|
void PageMaterials::sort_list_data(PresetList* list, const std::vector<ProfilePrintData>& data)
|
||||||
@ -1125,11 +1195,11 @@ void PageMaterials::sort_list_data(PresetList* list, const std::vector<ProfilePr
|
|||||||
});
|
});
|
||||||
list->Clear();
|
list->Clear();
|
||||||
for (size_t i = 0; i < prusa_profiles.size(); ++i) {
|
for (size_t i = 0; i < prusa_profiles.size(); ++i) {
|
||||||
list->append(std::string(prusa_profiles[i].name) + (prusa_profiles[i].omnipresent ? "" : " *"), &const_cast<std::string&>(prusa_profiles[i].name.get()));
|
list->append(std::string(prusa_profiles[i].name) + (prusa_profiles[i].omnipresent || template_shown ? "" : " *"), &const_cast<std::string&>(prusa_profiles[i].name.get()));
|
||||||
list->Check(i, prusa_profiles[i].checked);
|
list->Check(i, prusa_profiles[i].checked);
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < other_profiles.size(); ++i) {
|
for (size_t i = 0; i < other_profiles.size(); ++i) {
|
||||||
list->append(std::string(other_profiles[i].name) + (other_profiles[i].omnipresent ? "" : " *"), &const_cast<std::string&>(other_profiles[i].name.get()));
|
list->append(std::string(other_profiles[i].name) + (other_profiles[i].omnipresent || template_shown ? "" : " *"), &const_cast<std::string&>(other_profiles[i].name.get()));
|
||||||
list->Check(i + prusa_profiles.size(), other_profiles[i].checked);
|
list->Check(i + prusa_profiles.size(), other_profiles[i].checked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1139,6 +1209,15 @@ void PageMaterials::select_material(int i)
|
|||||||
const bool checked = list_profile->IsChecked(i);
|
const bool checked = list_profile->IsChecked(i);
|
||||||
|
|
||||||
const std::string& alias_key = list_profile->get_data(i);
|
const std::string& alias_key = list_profile->get_data(i);
|
||||||
|
if (checked && template_shown && !notification_shown) {
|
||||||
|
notification_shown = true;
|
||||||
|
wxString message = _L("You have selected template filament. Please note that these filaments are available for all printers but are NOT certain to be compatible with your printer. Do you still wish to have this filament selected?\n(This message won't be displayed again.)");
|
||||||
|
MessageDialog msg(this, message, _L("Notice"), wxYES_NO);
|
||||||
|
if (msg.ShowModal() == wxID_NO) {
|
||||||
|
list_profile->Check(i, false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
wizard_p()->update_presets_in_config(materials->appconfig_section(), alias_key, checked);
|
wizard_p()->update_presets_in_config(materials->appconfig_section(), alias_key, checked);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1543,6 +1622,8 @@ PageVendors::PageVendors(ConfigWizard *parent)
|
|||||||
for (const auto &pair : wizard_p()->bundles) {
|
for (const auto &pair : wizard_p()->bundles) {
|
||||||
const VendorProfile *vendor = pair.second.vendor_profile;
|
const VendorProfile *vendor = pair.second.vendor_profile;
|
||||||
if (vendor->id == PresetBundle::PRUSA_BUNDLE) { continue; }
|
if (vendor->id == PresetBundle::PRUSA_BUNDLE) { continue; }
|
||||||
|
if (vendor && vendor->templates_profile)
|
||||||
|
continue;
|
||||||
|
|
||||||
auto *cbox = new wxCheckBox(this, wxID_ANY, vendor->name);
|
auto *cbox = new wxCheckBox(this, wxID_ANY, vendor->name);
|
||||||
cbox->Bind(wxEVT_CHECKBOX, [=](wxCommandEvent &event) {
|
cbox->Bind(wxEVT_CHECKBOX, [=](wxCommandEvent &event) {
|
||||||
@ -2199,11 +2280,17 @@ void ConfigWizard::priv::load_pages()
|
|||||||
|
|
||||||
// Filaments & Materials
|
// Filaments & Materials
|
||||||
if (any_fff_selected) { index->add_page(page_filaments); }
|
if (any_fff_selected) { index->add_page(page_filaments); }
|
||||||
|
// Filaments page if only custom printer is selected
|
||||||
|
const AppConfig* app_config = wxGetApp().app_config;
|
||||||
|
if (!any_fff_selected && (custom_printer_selected || custom_printer_in_bundle) && (app_config->get("no_templates") == "0")) {
|
||||||
|
update_materials(T_ANY);
|
||||||
|
index->add_page(page_filaments);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (any_sla_selected) { index->add_page(page_sla_materials); }
|
if (any_sla_selected) { index->add_page(page_sla_materials); }
|
||||||
|
|
||||||
// there should to be selected at least one printer
|
// there should to be selected at least one printer
|
||||||
btn_finish->Enable(any_fff_selected || any_sla_selected || custom_printer_selected);
|
btn_finish->Enable(any_fff_selected || any_sla_selected || custom_printer_selected || custom_printer_in_bundle);
|
||||||
|
|
||||||
index->add_page(page_update);
|
index->add_page(page_update);
|
||||||
index->add_page(page_downloader);
|
index->add_page(page_downloader);
|
||||||
@ -2265,6 +2352,13 @@ void ConfigWizard::priv::load_vendors()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& printer : wxGetApp().preset_bundle->printers) {
|
||||||
|
if (!printer.is_default && !printer.is_system && printer.is_visible) {
|
||||||
|
custom_printer_in_bundle = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the is_visible flag in printer Presets
|
// Initialize the is_visible flag in printer Presets
|
||||||
for (auto &pair : bundles) {
|
for (auto &pair : bundles) {
|
||||||
pair.second.preset_bundle->load_installed_printers(appconfig_new);
|
pair.second.preset_bundle->load_installed_printers(appconfig_new);
|
||||||
@ -2386,7 +2480,7 @@ void ConfigWizard::priv::set_run_reason(RunReason run_reason)
|
|||||||
|
|
||||||
void ConfigWizard::priv::update_materials(Technology technology)
|
void ConfigWizard::priv::update_materials(Technology technology)
|
||||||
{
|
{
|
||||||
if (any_fff_selected && (technology & T_FFF)) {
|
if ((any_fff_selected || custom_printer_in_bundle || custom_printer_selected) && (technology & T_FFF)) {
|
||||||
filaments.clear();
|
filaments.clear();
|
||||||
aliases_fff.clear();
|
aliases_fff.clear();
|
||||||
// Iterate filaments in all bundles
|
// Iterate filaments in all bundles
|
||||||
@ -2409,11 +2503,22 @@ void ConfigWizard::priv::update_materials(Technology technology)
|
|||||||
filaments.add_printer(&printer);
|
filaments.add_printer(&printer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// template filament bundle has no printers - filament would be never added
|
||||||
|
if(pair.second.vendor_profile&& pair.second.vendor_profile->templates_profile && pair.second.preset_bundle->printers.begin() == pair.second.preset_bundle->printers.end())
|
||||||
|
{
|
||||||
|
if (!filaments.containts(&filament)) {
|
||||||
|
filaments.push(&filament);
|
||||||
|
if (!filament.alias.empty())
|
||||||
|
aliases_fff[filament.alias].insert(filament.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// count compatible printers
|
// count compatible printers
|
||||||
for (const auto& preset : filaments.presets) {
|
for (const auto& preset : filaments.presets) {
|
||||||
|
// skip template filaments
|
||||||
|
if (preset->vendor && preset->vendor->templates_profile)
|
||||||
|
continue;
|
||||||
|
|
||||||
const auto filter = [preset](const std::pair<std::string, size_t> element) {
|
const auto filter = [preset](const std::pair<std::string, size_t> element) {
|
||||||
return preset->alias == element.first;
|
return preset->alias == element.first;
|
||||||
@ -2421,17 +2526,19 @@ void ConfigWizard::priv::update_materials(Technology technology)
|
|||||||
if (std::find_if(filaments.compatibility_counter.begin(), filaments.compatibility_counter.end(), filter) != filaments.compatibility_counter.end()) {
|
if (std::find_if(filaments.compatibility_counter.begin(), filaments.compatibility_counter.end(), filter) != filaments.compatibility_counter.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// find all aliases (except templates)
|
||||||
std::vector<size_t> idx_with_same_alias;
|
std::vector<size_t> idx_with_same_alias;
|
||||||
for (size_t i = 0; i < filaments.presets.size(); ++i) {
|
for (size_t i = 0; i < filaments.presets.size(); ++i) {
|
||||||
if (preset->alias == filaments.presets[i]->alias)
|
if (preset->alias == filaments.presets[i]->alias && ((filaments.presets[i]->vendor && !filaments.presets[i]->vendor->templates_profile) || !filaments.presets[i]->vendor))
|
||||||
idx_with_same_alias.push_back(i);
|
idx_with_same_alias.push_back(i);
|
||||||
}
|
}
|
||||||
|
// check compatibility with each printer
|
||||||
size_t counter = 0;
|
size_t counter = 0;
|
||||||
for (const auto& printer : filaments.printers) {
|
for (const auto& printer : filaments.printers) {
|
||||||
if (!(*printer).is_visible || (*printer).printer_technology() != ptFFF)
|
if (!(*printer).is_visible || (*printer).printer_technology() != ptFFF)
|
||||||
continue;
|
continue;
|
||||||
bool compatible = false;
|
bool compatible = false;
|
||||||
// Test otrher materials with same alias
|
// Test other materials with same alias
|
||||||
for (size_t i = 0; i < idx_with_same_alias.size() && !compatible; ++i) {
|
for (size_t i = 0; i < idx_with_same_alias.size() && !compatible; ++i) {
|
||||||
const Preset& prst = *(filaments.presets[idx_with_same_alias[i]]);
|
const Preset& prst = *(filaments.presets[idx_with_same_alias[i]]);
|
||||||
const Preset& prntr = *printer;
|
const Preset& prntr = *printer;
|
||||||
@ -2694,6 +2801,21 @@ bool ConfigWizard::priv::check_and_install_missing_materials(Technology technolo
|
|||||||
has_material = true;
|
has_material = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find if preset.first is part of the templates profile (up is searching if preset.first is part of printer vendor preset)
|
||||||
|
for (const auto& bp : bundles) {
|
||||||
|
if (!bp.second.preset_bundle->vendors.empty() && bp.second.preset_bundle->vendors.begin()->second.templates_profile) {
|
||||||
|
const PresetCollection& template_materials = bp.second.preset_bundle->materials(technology);
|
||||||
|
const Preset* template_material = template_materials.find_preset(preset.first, false);
|
||||||
|
if (template_material && is_compatible_with_printer(PresetWithVendorProfile(*template_material, &bp.second.preset_bundle->vendors.begin()->second), PresetWithVendorProfile(printer, nullptr))) {
|
||||||
|
has_material = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_material)
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! has_material)
|
if (! has_material)
|
||||||
@ -2702,6 +2824,27 @@ bool ConfigWizard::priv::check_and_install_missing_materials(Technology technolo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// todo: just workaround so template_profile_selected wont get to false after this function is called for SLA
|
||||||
|
// this will work unltil there are no SLA template filaments
|
||||||
|
if (technology == ptFFF) {
|
||||||
|
// template_profile_selected check
|
||||||
|
template_profile_selected = false;
|
||||||
|
for (const auto& bp : bundles) {
|
||||||
|
if (!bp.second.preset_bundle->vendors.empty() && bp.second.preset_bundle->vendors.begin()->second.templates_profile) {
|
||||||
|
for (const auto& preset : appconfig_presets) {
|
||||||
|
const PresetCollection& template_materials = bp.second.preset_bundle->materials(technology);
|
||||||
|
const Preset* template_material = template_materials.find_preset(preset.first, false);
|
||||||
|
if (template_material){
|
||||||
|
template_profile_selected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (template_profile_selected) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
assert(printer_models_without_material.empty() || only_for_model_id.empty() || only_for_model_id == (*printer_models_without_material.begin())->id);
|
assert(printer_models_without_material.empty() || only_for_model_id.empty() || only_for_model_id == (*printer_models_without_material.begin())->id);
|
||||||
return printer_models_without_material;
|
return printer_models_without_material;
|
||||||
};
|
};
|
||||||
@ -2852,10 +2995,10 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
|||||||
if (!check_unsaved_preset_changes)
|
if (!check_unsaved_preset_changes)
|
||||||
act_btns |= ActionButtons::SAVE;
|
act_btns |= ActionButtons::SAVE;
|
||||||
|
|
||||||
// Install bundles from resources if needed:
|
// Install bundles from resources or cache / vendor if needed:
|
||||||
std::vector<std::string> install_bundles;
|
std::vector<std::string> install_bundles;
|
||||||
for (const auto &pair : bundles) {
|
for (const auto &pair : bundles) {
|
||||||
if (! pair.second.is_in_resources) { continue; }
|
if (pair.second.location == BundleLocation::IN_VENDOR) { continue; }
|
||||||
|
|
||||||
if (pair.second.is_prusa_bundle) {
|
if (pair.second.is_prusa_bundle) {
|
||||||
// Always install Prusa bundle, because it has a lot of filaments/materials
|
// Always install Prusa bundle, because it has a lot of filaments/materials
|
||||||
@ -2865,7 +3008,14 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto vendor = enabled_vendors.find(pair.first);
|
const auto vendor = enabled_vendors.find(pair.first);
|
||||||
if (vendor == enabled_vendors.end()) { continue; }
|
if (vendor == enabled_vendors.end()) {
|
||||||
|
// vendor not found
|
||||||
|
// if templates vendor and needs to be installed, add it
|
||||||
|
// then continue
|
||||||
|
if (template_profile_selected && pair.second.vendor_profile && pair.second.vendor_profile->templates_profile)
|
||||||
|
install_bundles.emplace_back(pair.first);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
size_t size_sum = 0;
|
size_t size_sum = 0;
|
||||||
for (const auto &model : vendor->second) { size_sum += model.second.size(); }
|
for (const auto &model : vendor->second) { size_sum += model.second.size(); }
|
||||||
@ -2915,12 +3065,14 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (install_bundles.size() > 0) {
|
if (install_bundles.size() > 0) {
|
||||||
// Install bundles from resources.
|
// Install bundles from resources or cache / vendor.
|
||||||
// Don't create snapshot - we've already done that above if applicable.
|
// Don't create snapshot - we've already done that above if applicable.
|
||||||
if (! updater->install_bundles_rsrc(std::move(install_bundles), false))
|
|
||||||
|
bool install_result = updater->install_bundles_rsrc_or_cache_vendor(std::move(install_bundles), false);
|
||||||
|
if (!install_result)
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
BOOST_LOG_TRIVIAL(info) << "No bundles need to be installed from resources";
|
BOOST_LOG_TRIVIAL(info) << "No bundles need to be installed from resources or cache / vendor";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page_welcome->reset_user_profile()) {
|
if (page_welcome->reset_user_profile()) {
|
||||||
|
@ -60,18 +60,25 @@ enum Technology {
|
|||||||
T_ANY = ~0,
|
T_ANY = ~0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum BundleLocation{
|
||||||
|
IN_VENDOR,
|
||||||
|
IN_ARCHIVE,
|
||||||
|
IN_RESOURCES
|
||||||
|
};
|
||||||
|
|
||||||
struct Bundle
|
struct Bundle
|
||||||
{
|
{
|
||||||
std::unique_ptr<PresetBundle> preset_bundle;
|
std::unique_ptr<PresetBundle> preset_bundle;
|
||||||
VendorProfile* vendor_profile{ nullptr };
|
VendorProfile* vendor_profile{ nullptr };
|
||||||
bool is_in_resources{ false };
|
//bool is_in_resources{ false };
|
||||||
|
BundleLocation location;
|
||||||
bool is_prusa_bundle{ false };
|
bool is_prusa_bundle{ false };
|
||||||
|
|
||||||
Bundle() = default;
|
Bundle() = default;
|
||||||
Bundle(Bundle&& other);
|
Bundle(Bundle&& other);
|
||||||
|
|
||||||
// Returns false if not loaded. Reason for that is logged as boost::log error.
|
// Returns false if not loaded. Reason for that is logged as boost::log error.
|
||||||
bool load(fs::path source_path, bool is_in_resources, bool is_prusa_bundle = false);
|
bool load(fs::path source_path, BundleLocation location, bool is_prusa_bundle = false);
|
||||||
|
|
||||||
const std::string& vendor_id() const { return vendor_profile->id; }
|
const std::string& vendor_id() const { return vendor_profile->id; }
|
||||||
};
|
};
|
||||||
@ -84,74 +91,8 @@ struct BundleMap : std::map<std::string /* = vendor ID */, Bundle>
|
|||||||
const Bundle& prusa_bundle() const;
|
const Bundle& prusa_bundle() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Materials
|
struct Materials;
|
||||||
{
|
|
||||||
Technology technology;
|
|
||||||
// use vector for the presets to purpose of save of presets sorting in the bundle
|
|
||||||
std::vector<const Preset*> presets;
|
|
||||||
// String is alias of material, size_t number of compatible counters
|
|
||||||
std::vector<std::pair<std::string, size_t>> compatibility_counter;
|
|
||||||
std::set<std::string> types;
|
|
||||||
std::set<const Preset*> printers;
|
|
||||||
|
|
||||||
Materials(Technology technology) : technology(technology) {}
|
|
||||||
|
|
||||||
void push(const Preset *preset);
|
|
||||||
void add_printer(const Preset* preset);
|
|
||||||
void clear();
|
|
||||||
bool containts(const Preset *preset) const {
|
|
||||||
//return std::find(presets.begin(), presets.end(), preset) != presets.end();
|
|
||||||
return std::find_if(presets.begin(), presets.end(),
|
|
||||||
[preset](const Preset* element) { return element == preset; }) != presets.end();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_omnipresent(const Preset* preset) {
|
|
||||||
return get_printer_counter(preset) == printers.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<const Preset*> get_presets_by_alias(const std::string name) {
|
|
||||||
std::vector<const Preset*> ret_vec;
|
|
||||||
for (auto it = presets.begin(); it != presets.end(); ++it) {
|
|
||||||
if ((*it)->alias == name)
|
|
||||||
ret_vec.push_back((*it));
|
|
||||||
}
|
|
||||||
return ret_vec;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
size_t get_printer_counter(const Preset* preset) {
|
|
||||||
for (auto it : compatibility_counter) {
|
|
||||||
if (it.first == preset->alias)
|
|
||||||
return it.second;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& appconfig_section() const;
|
|
||||||
const std::string& get_type(const Preset *preset) const;
|
|
||||||
const std::string& get_vendor(const Preset *preset) const;
|
|
||||||
|
|
||||||
template<class F> void filter_presets(const Preset* printer, const std::string& type, const std::string& vendor, F cb) {
|
|
||||||
for (auto preset : presets) {
|
|
||||||
const Preset& prst = *(preset);
|
|
||||||
const Preset& prntr = *printer;
|
|
||||||
if ((printer == nullptr || is_compatible_with_printer(PresetWithVendorProfile(prst, prst.vendor), PresetWithVendorProfile(prntr, prntr.vendor))) &&
|
|
||||||
(type.empty() || get_type(preset) == type) &&
|
|
||||||
(vendor.empty() || get_vendor(preset) == vendor)) {
|
|
||||||
|
|
||||||
cb(preset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const std::string UNKNOWN;
|
|
||||||
static const std::string& get_filament_type(const Preset *preset);
|
|
||||||
static const std::string& get_filament_vendor(const Preset *preset);
|
|
||||||
static const std::string& get_material_type(const Preset *preset);
|
|
||||||
static const std::string& get_material_vendor(const Preset *preset);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct PrinterPickerEvent;
|
struct PrinterPickerEvent;
|
||||||
@ -344,6 +285,10 @@ struct PageMaterials: ConfigWizardPage
|
|||||||
std::string empty_printers_label;
|
std::string empty_printers_label;
|
||||||
bool first_paint = { false };
|
bool first_paint = { false };
|
||||||
static const std::string EMPTY;
|
static const std::string EMPTY;
|
||||||
|
static const std::string TEMPLATES;
|
||||||
|
// notify user first time they choose template profile
|
||||||
|
bool template_shown = { false };
|
||||||
|
bool notification_shown = { false };
|
||||||
int last_hovered_item = { -1 } ;
|
int last_hovered_item = { -1 } ;
|
||||||
|
|
||||||
PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name);
|
PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name);
|
||||||
@ -368,6 +313,82 @@ struct PageMaterials: ConfigWizardPage
|
|||||||
virtual void on_activate() override;
|
virtual void on_activate() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Materials
|
||||||
|
{
|
||||||
|
Technology technology;
|
||||||
|
// use vector for the presets to purpose of save of presets sorting in the bundle
|
||||||
|
std::vector<const Preset*> presets;
|
||||||
|
// String is alias of material, size_t number of compatible counters
|
||||||
|
std::vector<std::pair<std::string, size_t>> compatibility_counter;
|
||||||
|
std::set<std::string> types;
|
||||||
|
std::set<const Preset*> printers;
|
||||||
|
|
||||||
|
Materials(Technology technology) : technology(technology) {}
|
||||||
|
|
||||||
|
void push(const Preset* preset);
|
||||||
|
void add_printer(const Preset* preset);
|
||||||
|
void clear();
|
||||||
|
bool containts(const Preset* preset) const {
|
||||||
|
//return std::find(presets.begin(), presets.end(), preset) != presets.end();
|
||||||
|
return std::find_if(presets.begin(), presets.end(),
|
||||||
|
[preset](const Preset* element) { return element == preset; }) != presets.end();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_omnipresent(const Preset* preset) {
|
||||||
|
return get_printer_counter(preset) == printers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<const Preset*> get_presets_by_alias(const std::string name) {
|
||||||
|
std::vector<const Preset*> ret_vec;
|
||||||
|
for (auto it = presets.begin(); it != presets.end(); ++it) {
|
||||||
|
if ((*it)->alias == name)
|
||||||
|
ret_vec.push_back((*it));
|
||||||
|
}
|
||||||
|
return ret_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t get_printer_counter(const Preset* preset) {
|
||||||
|
for (auto it : compatibility_counter) {
|
||||||
|
if (it.first == preset->alias)
|
||||||
|
return it.second;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& appconfig_section() const;
|
||||||
|
const std::string& get_type(const Preset* preset) const;
|
||||||
|
const std::string& get_vendor(const Preset* preset) const;
|
||||||
|
|
||||||
|
template<class F> void filter_presets(const Preset* printer, const std::string& printer_name, const std::string& type, const std::string& vendor, F cb) {
|
||||||
|
for (auto preset : presets) {
|
||||||
|
const Preset& prst = *(preset);
|
||||||
|
const Preset& prntr = *printer;
|
||||||
|
if (((printer == nullptr && printer_name == PageMaterials::EMPTY) || (printer != nullptr && is_compatible_with_printer(PresetWithVendorProfile(prst, prst.vendor), PresetWithVendorProfile(prntr, prntr.vendor)))) &&
|
||||||
|
(type.empty() || get_type(preset) == type) &&
|
||||||
|
(vendor.empty() || get_vendor(preset) == vendor) &&
|
||||||
|
prst.vendor && !prst.vendor->templates_profile) {
|
||||||
|
|
||||||
|
cb(preset);
|
||||||
|
}
|
||||||
|
else if ((printer == nullptr && printer_name == PageMaterials::TEMPLATES) && prst.vendor && prst.vendor->templates_profile &&
|
||||||
|
(type.empty() || get_type(preset) == type) &&
|
||||||
|
(vendor.empty() || get_vendor(preset) == vendor)) {
|
||||||
|
cb(preset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::string UNKNOWN;
|
||||||
|
static const std::string& get_filament_type(const Preset* preset);
|
||||||
|
static const std::string& get_filament_vendor(const Preset* preset);
|
||||||
|
static const std::string& get_material_type(const Preset* preset);
|
||||||
|
static const std::string& get_material_vendor(const Preset* preset);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct PageCustom: ConfigWizardPage
|
struct PageCustom: ConfigWizardPage
|
||||||
{
|
{
|
||||||
PageCustom(ConfigWizard *parent);
|
PageCustom(ConfigWizard *parent);
|
||||||
@ -608,9 +629,11 @@ struct ConfigWizard::priv
|
|||||||
std::unique_ptr<DynamicPrintConfig> custom_config; // Backing for custom printer definition
|
std::unique_ptr<DynamicPrintConfig> custom_config; // Backing for custom printer definition
|
||||||
bool any_fff_selected; // Used to decide whether to display Filaments page
|
bool any_fff_selected; // Used to decide whether to display Filaments page
|
||||||
bool any_sla_selected; // Used to decide whether to display SLA Materials page
|
bool any_sla_selected; // Used to decide whether to display SLA Materials page
|
||||||
bool custom_printer_selected { false };
|
bool custom_printer_selected { false }; // New custom printer is requested
|
||||||
|
bool custom_printer_in_bundle { false }; // Older custom printer already exists when wizard starts
|
||||||
// Set to true if there are none FFF printers on the main FFF page. If true, only SLA printers are shown (not even custum printers)
|
// Set to true if there are none FFF printers on the main FFF page. If true, only SLA printers are shown (not even custum printers)
|
||||||
bool only_sla_mode { false };
|
bool only_sla_mode { false };
|
||||||
|
bool template_profile_selected { false }; // This bool has one purpose - to tell that template profile should be installed if its not (because it cannot be added to appconfig)
|
||||||
|
|
||||||
wxScrolledWindow *hscroll = nullptr;
|
wxScrolledWindow *hscroll = nullptr;
|
||||||
wxBoxSizer *hscroll_sizer = nullptr;
|
wxBoxSizer *hscroll_sizer = nullptr;
|
||||||
|
@ -808,6 +808,7 @@ void GUI_App::post_init()
|
|||||||
// Configuration is not compatible and reconfigure was refused by the user. Application is closing.
|
// Configuration is not compatible and reconfigure was refused by the user. Application is closing.
|
||||||
return;
|
return;
|
||||||
CallAfter([this] {
|
CallAfter([this] {
|
||||||
|
// preset_updater->sync downloads profile updates on background so it must begin after config wizard finished.
|
||||||
bool cw_showed = this->config_wizard_startup();
|
bool cw_showed = this->config_wizard_startup();
|
||||||
this->preset_updater->sync(preset_bundle);
|
this->preset_updater->sync(preset_bundle);
|
||||||
this->app_version_check(false);
|
this->app_version_check(false);
|
||||||
@ -1282,6 +1283,7 @@ bool GUI_App::on_init_inner()
|
|||||||
#endif // __WXMSW__
|
#endif // __WXMSW__
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string delayed_error_load_presets;
|
||||||
// Suppress the '- default -' presets.
|
// Suppress the '- default -' presets.
|
||||||
preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1");
|
preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1");
|
||||||
try {
|
try {
|
||||||
@ -1290,7 +1292,7 @@ bool GUI_App::on_init_inner()
|
|||||||
// installation of a compatible system preset, thus nullifying the system preset substitutions.
|
// installation of a compatible system preset, thus nullifying the system preset substitutions.
|
||||||
init_params->preset_substitutions = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent);
|
init_params->preset_substitutions = preset_bundle->load_presets(*app_config, ForwardCompatibilitySubstitutionRule::EnableSystemSilent);
|
||||||
} catch (const std::exception &ex) {
|
} catch (const std::exception &ex) {
|
||||||
show_error(nullptr, ex.what());
|
delayed_error_load_presets = ex.what();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
@ -1307,6 +1309,9 @@ bool GUI_App::on_init_inner()
|
|||||||
if (scrn && is_editor())
|
if (scrn && is_editor())
|
||||||
scrn->SetText(_L("Preparing settings tabs") + dots);
|
scrn->SetText(_L("Preparing settings tabs") + dots);
|
||||||
|
|
||||||
|
if (!delayed_error_load_presets.empty())
|
||||||
|
show_error(nullptr, delayed_error_load_presets);
|
||||||
|
|
||||||
mainframe = new MainFrame();
|
mainframe = new MainFrame();
|
||||||
// hide settings tabs after first Layout
|
// hide settings tabs after first Layout
|
||||||
if (is_editor())
|
if (is_editor())
|
||||||
@ -2998,6 +3003,9 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage
|
|||||||
wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null");
|
wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null");
|
||||||
|
|
||||||
if (reason == ConfigWizard::RR_USER) {
|
if (reason == ConfigWizard::RR_USER) {
|
||||||
|
// Cancel sync before starting wizard to prevent two downloads at same time
|
||||||
|
preset_updater->cancel_sync();
|
||||||
|
preset_updater->update_index_db();
|
||||||
if (preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD) == PresetUpdater::R_ALL_CANCELED)
|
if (preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD) == PresetUpdater::R_ALL_CANCELED)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -3180,6 +3188,7 @@ bool GUI_App::check_updates(const bool verbose)
|
|||||||
{
|
{
|
||||||
PresetUpdater::UpdateResult updater_result;
|
PresetUpdater::UpdateResult updater_result;
|
||||||
try {
|
try {
|
||||||
|
preset_updater->update_index_db();
|
||||||
updater_result = preset_updater->config_update(app_config->orig_version(), verbose ? PresetUpdater::UpdateParams::SHOW_TEXT_BOX : PresetUpdater::UpdateParams::SHOW_NOTIFICATION);
|
updater_result = preset_updater->config_update(app_config->orig_version(), verbose ? PresetUpdater::UpdateParams::SHOW_TEXT_BOX : PresetUpdater::UpdateParams::SHOW_NOTIFICATION);
|
||||||
if (updater_result == PresetUpdater::R_INCOMPAT_EXIT) {
|
if (updater_result == PresetUpdater::R_INCOMPAT_EXIT) {
|
||||||
mainframe->Close();
|
mainframe->Close();
|
||||||
|
@ -301,6 +301,11 @@ void PreferencesDialog::build()
|
|||||||
L("Suppress \" - default - \" presets in the Print / Filament / Printer selections once there are any other valid presets available."),
|
L("Suppress \" - default - \" presets in the Print / Filament / Printer selections once there are any other valid presets available."),
|
||||||
app_config->get("no_defaults") == "1");
|
app_config->get("no_defaults") == "1");
|
||||||
|
|
||||||
|
append_bool_option(m_optgroup_general, "no_templates",
|
||||||
|
L("Suppress \" Template \" filament presets"),
|
||||||
|
L("Suppress \" Template \" filament presets in configuration wizard and sidebar visibility."),
|
||||||
|
app_config->get("no_templates") == "1");
|
||||||
|
|
||||||
append_bool_option(m_optgroup_general, "show_incompatible_presets",
|
append_bool_option(m_optgroup_general, "show_incompatible_presets",
|
||||||
L("Show incompatible print and filament presets"),
|
L("Show incompatible print and filament presets"),
|
||||||
L("When checked, the print and filament presets are shown in the preset editor "
|
L("When checked, the print and filament presets are shown in the preset editor "
|
||||||
@ -692,6 +697,8 @@ void PreferencesDialog::accept(wxEvent&)
|
|||||||
DesktopIntegrationDialog::perform_desktop_integration(true);
|
DesktopIntegrationDialog::perform_desktop_integration(true);
|
||||||
#endif // __linux__
|
#endif // __linux__
|
||||||
|
|
||||||
|
bool update_filament_sidebar = (m_values.find("no_templates") != m_values.end());
|
||||||
|
|
||||||
std::vector<std::string> options_to_recreate_GUI = { "no_defaults", "tabs_as_menu", "sys_menu_enabled" };
|
std::vector<std::string> options_to_recreate_GUI = { "no_defaults", "tabs_as_menu", "sys_menu_enabled" };
|
||||||
|
|
||||||
for (const std::string& option : options_to_recreate_GUI) {
|
for (const std::string& option : options_to_recreate_GUI) {
|
||||||
@ -761,6 +768,9 @@ void PreferencesDialog::accept(wxEvent&)
|
|||||||
|
|
||||||
wxGetApp().update_ui_from_settings();
|
wxGetApp().update_ui_from_settings();
|
||||||
clear_cache();
|
clear_cache();
|
||||||
|
|
||||||
|
if (update_filament_sidebar)
|
||||||
|
wxGetApp().plater()->sidebar().update_presets(Preset::Type::TYPE_FILAMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesDialog::revert(wxEvent&)
|
void PreferencesDialog::revert(wxEvent&)
|
||||||
|
@ -798,7 +798,7 @@ void PlaterPresetComboBox::show_edit_menu()
|
|||||||
|
|
||||||
wxString PlaterPresetComboBox::get_preset_name(const Preset& preset)
|
wxString PlaterPresetComboBox::get_preset_name(const Preset& preset)
|
||||||
{
|
{
|
||||||
std::string name = preset.alias.empty() ? preset.name : preset.alias;
|
std::string name = preset.alias.empty() ? preset.name : (preset.vendor && preset.vendor->templates_profile ? preset.name : preset.alias);
|
||||||
return from_u8(name + suffix(preset));
|
return from_u8(name + suffix(preset));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -836,6 +836,7 @@ void PlaterPresetComboBox::update()
|
|||||||
null_icon_width = (wide_icons ? 3 : 2) * norm_icon_width + thin_space_icon_width + wide_space_icon_width;
|
null_icon_width = (wide_icons ? 3 : 2) * norm_icon_width + thin_space_icon_width + wide_space_icon_width;
|
||||||
|
|
||||||
std::map<wxString, wxBitmapBundle*> nonsys_presets;
|
std::map<wxString, wxBitmapBundle*> nonsys_presets;
|
||||||
|
std::map<wxString, wxBitmapBundle*> template_presets;
|
||||||
|
|
||||||
wxString selected_user_preset;
|
wxString selected_user_preset;
|
||||||
wxString tooltip;
|
wxString tooltip;
|
||||||
@ -883,11 +884,19 @@ void PlaterPresetComboBox::update()
|
|||||||
|
|
||||||
const std::string name = preset.alias.empty() ? preset.name : preset.alias;
|
const std::string name = preset.alias.empty() ? preset.name : preset.alias;
|
||||||
if (preset.is_default || preset.is_system) {
|
if (preset.is_default || preset.is_system) {
|
||||||
|
if (preset.vendor && preset.vendor->templates_profile) {
|
||||||
|
template_presets.emplace(get_preset_name(preset), bmp);
|
||||||
|
if (is_selected) {
|
||||||
|
selected_user_preset = get_preset_name(preset);
|
||||||
|
tooltip = from_u8(preset.name);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
Append(get_preset_name(preset), *bmp);
|
Append(get_preset_name(preset), *bmp);
|
||||||
validate_selection(is_selected);
|
validate_selection(is_selected);
|
||||||
if (is_selected)
|
if (is_selected)
|
||||||
tooltip = from_u8(preset.name);
|
tooltip = from_u8(preset.name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nonsys_presets.emplace(get_preset_name(preset), bmp);
|
nonsys_presets.emplace(get_preset_name(preset), bmp);
|
||||||
@ -899,6 +908,8 @@ void PlaterPresetComboBox::update()
|
|||||||
if (i + 1 == m_collection->num_default_presets())
|
if (i + 1 == m_collection->num_default_presets())
|
||||||
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
|
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!nonsys_presets.empty())
|
if (!nonsys_presets.empty())
|
||||||
{
|
{
|
||||||
set_label_marker(Append(separator(L("User presets")), NullBitmapBndl()));
|
set_label_marker(Append(separator(L("User presets")), NullBitmapBndl()));
|
||||||
@ -908,6 +919,15 @@ void PlaterPresetComboBox::update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AppConfig* app_config = wxGetApp().app_config;
|
||||||
|
if (!template_presets.empty() && app_config->get("no_templates") == "0") {
|
||||||
|
set_label_marker(Append(separator(L("Template presets")), wxNullBitmap));
|
||||||
|
for (std::map<wxString, wxBitmapBundle*>::iterator it = template_presets.begin(); it != template_presets.end(); ++it) {
|
||||||
|
Append(it->first, *it->second);
|
||||||
|
validate_selection(it->first == selected_user_preset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_type == Preset::TYPE_PRINTER)
|
if (m_type == Preset::TYPE_PRINTER)
|
||||||
{
|
{
|
||||||
// add Physical printers, if any exists
|
// add Physical printers, if any exists
|
||||||
@ -1046,6 +1066,8 @@ void TabPresetComboBox::update()
|
|||||||
const std::deque<Preset>& presets = m_collection->get_presets();
|
const std::deque<Preset>& presets = m_collection->get_presets();
|
||||||
|
|
||||||
std::map<wxString, std::pair<wxBitmapBundle*, bool>> nonsys_presets;
|
std::map<wxString, std::pair<wxBitmapBundle*, bool>> nonsys_presets;
|
||||||
|
std::map<wxString, std::pair<wxBitmapBundle*, bool>> template_presets;
|
||||||
|
|
||||||
wxString selected = "";
|
wxString selected = "";
|
||||||
if (!presets.front().is_visible)
|
if (!presets.front().is_visible)
|
||||||
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
|
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
|
||||||
@ -1079,11 +1101,19 @@ void TabPresetComboBox::update()
|
|||||||
assert(bmp);
|
assert(bmp);
|
||||||
|
|
||||||
if (preset.is_default || preset.is_system) {
|
if (preset.is_default || preset.is_system) {
|
||||||
|
if (preset.vendor && preset.vendor->templates_profile) {
|
||||||
|
template_presets.emplace(get_preset_name(preset), std::pair<wxBitmapBundle*, bool>(bmp, is_enabled));
|
||||||
|
if (i == idx_selected)
|
||||||
|
selected = get_preset_name(preset);
|
||||||
|
} else {
|
||||||
int item_id = Append(get_preset_name(preset), *bmp);
|
int item_id = Append(get_preset_name(preset), *bmp);
|
||||||
if (!is_enabled)
|
if (!is_enabled)
|
||||||
set_label_marker(item_id, LABEL_ITEM_DISABLED);
|
set_label_marker(item_id, LABEL_ITEM_DISABLED);
|
||||||
validate_selection(i == idx_selected);
|
validate_selection(i == idx_selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::pair<wxBitmapBundle*, bool> pair(bmp, is_enabled);
|
std::pair<wxBitmapBundle*, bool> pair(bmp, is_enabled);
|
||||||
@ -1094,6 +1124,7 @@ void TabPresetComboBox::update()
|
|||||||
if (i + 1 == m_collection->num_default_presets())
|
if (i + 1 == m_collection->num_default_presets())
|
||||||
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
|
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nonsys_presets.empty())
|
if (!nonsys_presets.empty())
|
||||||
{
|
{
|
||||||
set_label_marker(Append(separator(L("User presets")), NullBitmapBndl()));
|
set_label_marker(Append(separator(L("User presets")), NullBitmapBndl()));
|
||||||
@ -1106,6 +1137,18 @@ void TabPresetComboBox::update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AppConfig* app_config = wxGetApp().app_config;
|
||||||
|
if (!template_presets.empty() && app_config->get("no_templates") == "0") {
|
||||||
|
set_label_marker(Append(separator(L("Template presets")), wxNullBitmap));
|
||||||
|
for (std::map<wxString, std::pair<wxBitmapBundle*, bool>>::iterator it = template_presets.begin(); it != template_presets.end(); ++it) {
|
||||||
|
int item_id = Append(it->first, *it->second.first);
|
||||||
|
bool is_enabled = it->second.second;
|
||||||
|
if (!is_enabled)
|
||||||
|
set_label_marker(item_id, LABEL_ITEM_DISABLED);
|
||||||
|
validate_selection(it->first == selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_type == Preset::TYPE_PRINTER)
|
if (m_type == Preset::TYPE_PRINTER)
|
||||||
{
|
{
|
||||||
// add Physical printers, if any exists
|
// add Physical printers, if any exists
|
||||||
|
@ -285,17 +285,17 @@ void SavePresetDialog::Item::Enable(bool enable /*= true*/)
|
|||||||
// SavePresetDialog
|
// SavePresetDialog
|
||||||
//-----------------------------------------------
|
//-----------------------------------------------
|
||||||
|
|
||||||
SavePresetDialog::SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix)
|
SavePresetDialog::SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix, bool template_filament)
|
||||||
: DPIDialog(parent, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
|
: DPIDialog(parent, wxID_ANY, _L("Save preset"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
|
||||||
{
|
{
|
||||||
build(std::vector<Preset::Type>{type}, suffix);
|
build(std::vector<Preset::Type>{type}, suffix, template_filament);
|
||||||
}
|
}
|
||||||
|
|
||||||
SavePresetDialog::SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix, PresetBundle* preset_bundle/* = nullptr*/)
|
SavePresetDialog::SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix, bool template_filament/* =false*/, PresetBundle* preset_bundle/* = nullptr*/)
|
||||||
: DPIDialog(parent, wxID_ANY, _L("Save presets"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER),
|
: DPIDialog(parent, wxID_ANY, _L("Save presets"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER),
|
||||||
m_preset_bundle(preset_bundle)
|
m_preset_bundle(preset_bundle)
|
||||||
{
|
{
|
||||||
build(types, suffix);
|
build(types, suffix, template_filament);
|
||||||
}
|
}
|
||||||
|
|
||||||
SavePresetDialog::SavePresetDialog(wxWindow* parent, Preset::Type type, bool rename, const wxString& info_line_extention)
|
SavePresetDialog::SavePresetDialog(wxWindow* parent, Preset::Type type, bool rename, const wxString& info_line_extention)
|
||||||
@ -312,7 +312,7 @@ SavePresetDialog::~SavePresetDialog()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SavePresetDialog::build(std::vector<Preset::Type> types, std::string suffix)
|
void SavePresetDialog::build(std::vector<Preset::Type> types, std::string suffix, bool template_filament)
|
||||||
{
|
{
|
||||||
#if defined(__WXMSW__)
|
#if defined(__WXMSW__)
|
||||||
// ys_FIXME! temporary workaround for correct font scaling
|
// ys_FIXME! temporary workaround for correct font scaling
|
||||||
@ -341,6 +341,15 @@ void SavePresetDialog::build(std::vector<Preset::Type> types, std::string suffix
|
|||||||
btnOK->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(enable_ok_btn()); });
|
btnOK->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(enable_ok_btn()); });
|
||||||
|
|
||||||
topSizer->Add(m_presets_sizer, 0, wxEXPAND | wxALL, BORDER_W);
|
topSizer->Add(m_presets_sizer, 0, wxEXPAND | wxALL, BORDER_W);
|
||||||
|
|
||||||
|
// Add checkbox for Template filament saving
|
||||||
|
if (template_filament && types.size() == 1 && *types.begin() == Preset::Type::TYPE_FILAMENT) {
|
||||||
|
m_template_filament_checkbox = new wxCheckBox(this, wxID_ANY, _L("Save as profile derived from current printer only."));
|
||||||
|
wxBoxSizer* check_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
check_sizer->Add(m_template_filament_checkbox);
|
||||||
|
topSizer->Add(check_sizer, 0, wxEXPAND | wxALL, BORDER_W);
|
||||||
|
}
|
||||||
|
|
||||||
topSizer->Add(btns, 0, wxEXPAND | wxALL, BORDER_W);
|
topSizer->Add(btns, 0, wxEXPAND | wxALL, BORDER_W);
|
||||||
|
|
||||||
SetSizer(topSizer);
|
SetSizer(topSizer);
|
||||||
@ -371,6 +380,15 @@ std::string SavePresetDialog::get_name(Preset::Type type)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SavePresetDialog::get_template_filament_checkbox()
|
||||||
|
{
|
||||||
|
if (m_template_filament_checkbox)
|
||||||
|
{
|
||||||
|
return m_template_filament_checkbox->GetValue();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool SavePresetDialog::enable_ok_btn() const
|
bool SavePresetDialog::enable_ok_btn() const
|
||||||
{
|
{
|
||||||
for (const Item* item : m_items)
|
for (const Item* item : m_items)
|
||||||
|
@ -76,6 +76,7 @@ private:
|
|||||||
wxStaticText* m_label {nullptr};
|
wxStaticText* m_label {nullptr};
|
||||||
wxBoxSizer* m_radio_sizer {nullptr};
|
wxBoxSizer* m_radio_sizer {nullptr};
|
||||||
ActionType m_action {UndefAction};
|
ActionType m_action {UndefAction};
|
||||||
|
wxCheckBox* m_template_filament_checkbox {nullptr};
|
||||||
|
|
||||||
std::string m_ph_printer_name;
|
std::string m_ph_printer_name;
|
||||||
std::string m_old_preset_name;
|
std::string m_old_preset_name;
|
||||||
@ -88,8 +89,8 @@ public:
|
|||||||
|
|
||||||
const wxString& get_info_line_extention() { return m_info_line_extention; }
|
const wxString& get_info_line_extention() { return m_info_line_extention; }
|
||||||
|
|
||||||
SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix = "");
|
SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix = "", bool template_filament = false);
|
||||||
SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix = "", PresetBundle* preset_bundle = nullptr);
|
SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix = "", bool template_filament = false, PresetBundle* preset_bundle = nullptr);
|
||||||
SavePresetDialog(wxWindow* parent, Preset::Type type, bool rename, const wxString& info_line_extention);
|
SavePresetDialog(wxWindow* parent, Preset::Type type, bool rename, const wxString& info_line_extention);
|
||||||
~SavePresetDialog() override;
|
~SavePresetDialog() override;
|
||||||
|
|
||||||
@ -105,12 +106,13 @@ public:
|
|||||||
bool Layout() override;
|
bool Layout() override;
|
||||||
bool is_for_rename() { return m_use_for_rename; }
|
bool is_for_rename() { return m_use_for_rename; }
|
||||||
|
|
||||||
|
bool get_template_filament_checkbox();
|
||||||
protected:
|
protected:
|
||||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||||
void on_sys_color_changed() override {}
|
void on_sys_color_changed() override {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void build(std::vector<Preset::Type> types, std::string suffix = "");
|
void build(std::vector<Preset::Type> types, std::string suffix = "", bool template_filament = false);
|
||||||
void update_physical_printers(const std::string& preset_name);
|
void update_physical_printers(const std::string& preset_name);
|
||||||
void accept();
|
void accept();
|
||||||
};
|
};
|
||||||
|
@ -3715,11 +3715,25 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach)
|
|||||||
// focus currently.is there anything better than this ?
|
// focus currently.is there anything better than this ?
|
||||||
//! m_treectrl->OnSetFocus();
|
//! m_treectrl->OnSetFocus();
|
||||||
|
|
||||||
|
auto& old_preset = m_presets->get_edited_preset();
|
||||||
|
bool from_template = false;
|
||||||
|
std::string edited_printer;
|
||||||
|
if (m_type == Preset::TYPE_FILAMENT && old_preset.vendor && old_preset.vendor->templates_profile)
|
||||||
|
{
|
||||||
|
//TODO: is this really the best way to get "printer_model" option of currently edited printer?
|
||||||
|
edited_printer = wxGetApp().preset_bundle->printers.get_edited_preset().config.opt<ConfigOptionString>("printer_model")->serialize();
|
||||||
|
if (!edited_printer.empty())
|
||||||
|
from_template = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
SavePresetDialog dlg(m_parent, m_type, detach ? _u8L("Detached") : "");
|
SavePresetDialog dlg(m_parent, m_type, detach ? _u8L("Detached") : "", from_template);
|
||||||
if (dlg.ShowModal() != wxID_OK)
|
if (dlg.ShowModal() != wxID_OK)
|
||||||
return;
|
return;
|
||||||
name = dlg.get_name();
|
name = dlg.get_name();
|
||||||
|
if (from_template)
|
||||||
|
from_template = dlg.get_template_filament_checkbox();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (detach && m_type == Preset::TYPE_PRINTER)
|
if (detach && m_type == Preset::TYPE_PRINTER)
|
||||||
@ -3731,6 +3745,19 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach)
|
|||||||
if (detach && m_type == Preset::TYPE_PRINTER)
|
if (detach && m_type == Preset::TYPE_PRINTER)
|
||||||
wxGetApp().mainframe->on_config_changed(m_config);
|
wxGetApp().mainframe->on_config_changed(m_config);
|
||||||
|
|
||||||
|
// Update compatible printers
|
||||||
|
if (from_template && !edited_printer.empty()) {
|
||||||
|
auto& new_preset = m_presets->get_edited_preset();
|
||||||
|
std::string cond = new_preset.compatible_printers_condition();
|
||||||
|
if (!cond.empty())
|
||||||
|
cond += " and ";
|
||||||
|
cond += "printer_model == \""+edited_printer+"\"";
|
||||||
|
new_preset.config.set("compatible_printers_condition", cond);
|
||||||
|
new_preset.save();
|
||||||
|
m_presets->save_current_preset(name, detach);
|
||||||
|
load_current_preset();
|
||||||
|
}
|
||||||
|
|
||||||
// Mark the print & filament enabled if they are compatible with the currently selected preset.
|
// Mark the print & filament enabled if they are compatible with the currently selected preset.
|
||||||
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
|
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
|
||||||
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
|
m_preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
|
||||||
|
@ -12,14 +12,17 @@
|
|||||||
#include <boost/filesystem/fstream.hpp>
|
#include <boost/filesystem/fstream.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
#include <wx/app.h>
|
#include <wx/app.h>
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
|
#include <wx/progdlg.h>
|
||||||
|
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
#include "libslic3r/format.hpp"
|
#include "libslic3r/format.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
|
#include "libslic3r/miniz_extension.hpp"
|
||||||
#include "slic3r/GUI/GUI.hpp"
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
#include "slic3r/GUI/I18N.hpp"
|
#include "slic3r/GUI/I18N.hpp"
|
||||||
#include "slic3r/GUI/UpdateDialogs.hpp"
|
#include "slic3r/GUI/UpdateDialogs.hpp"
|
||||||
@ -49,7 +52,7 @@ namespace Slic3r {
|
|||||||
static const char *INDEX_FILENAME = "index.idx";
|
static const char *INDEX_FILENAME = "index.idx";
|
||||||
static const char *TMP_EXTENSION = ".download";
|
static const char *TMP_EXTENSION = ".download";
|
||||||
|
|
||||||
|
namespace {
|
||||||
void copy_file_fix(const fs::path &source, const fs::path &target)
|
void copy_file_fix(const fs::path &source, const fs::path &target)
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(debug) << format("PresetUpdater: Copying %1% -> %2%", source, target);
|
BOOST_LOG_TRIVIAL(debug) << format("PresetUpdater: Copying %1% -> %2%", source, target);
|
||||||
@ -66,7 +69,21 @@ void copy_file_fix(const fs::path &source, const fs::path &target)
|
|||||||
static constexpr const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read;
|
static constexpr const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read;
|
||||||
fs::permissions(target, perms);
|
fs::permissions(target, perms);
|
||||||
}
|
}
|
||||||
|
std::string escape_string_url(const std::string& unescaped)
|
||||||
|
{
|
||||||
|
std::string ret_val;
|
||||||
|
CURL* curl = curl_easy_init();
|
||||||
|
if (curl) {
|
||||||
|
char* decoded = curl_easy_escape(curl, unescaped.c_str(), unescaped.size());
|
||||||
|
if (decoded) {
|
||||||
|
ret_val = std::string(decoded);
|
||||||
|
curl_free(decoded);
|
||||||
|
}
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
struct Update
|
struct Update
|
||||||
{
|
{
|
||||||
fs::path source;
|
fs::path source;
|
||||||
@ -144,6 +161,7 @@ struct PresetUpdater::priv
|
|||||||
std::string version_check_url;
|
std::string version_check_url;
|
||||||
|
|
||||||
fs::path cache_path;
|
fs::path cache_path;
|
||||||
|
fs::path cache_vendor_path;
|
||||||
fs::path rsrc_path;
|
fs::path rsrc_path;
|
||||||
fs::path vendor_path;
|
fs::path vendor_path;
|
||||||
|
|
||||||
@ -155,19 +173,25 @@ struct PresetUpdater::priv
|
|||||||
|
|
||||||
priv();
|
priv();
|
||||||
|
|
||||||
void set_download_prefs(AppConfig *app_config);
|
void set_download_prefs(const AppConfig *app_config);
|
||||||
bool get_file(const std::string &url, const fs::path &target_path) const;
|
bool get_file(const std::string &url, const fs::path &target_path) const;
|
||||||
void prune_tmps() const;
|
void prune_tmps() const;
|
||||||
void sync_config(const VendorMap vendors);
|
void sync_config(const VendorMap vendors, const std::string& index_archive_url);
|
||||||
|
|
||||||
void check_install_indices() const;
|
void check_install_indices() const;
|
||||||
Updates get_config_updates(const Semver& old_slic3r_version) const;
|
Updates get_config_updates(const Semver& old_slic3r_version) const;
|
||||||
bool perform_updates(Updates &&updates, bool snapshot = true) const;
|
bool perform_updates(Updates &&updates, bool snapshot = true) const;
|
||||||
void set_waiting_updates(Updates u);
|
void set_waiting_updates(Updates u);
|
||||||
|
// checks existence and downloads resource to cache
|
||||||
|
void get_missing_resource(const std::string& vendor, const std::string& filename, const std::string& url) const;
|
||||||
|
// checks existence and downloads resource to vendor or copy from cache to vendor
|
||||||
|
void get_or_copy_missing_resource(const std::string& vendor, const std::string& filename, const std::string& url) const;
|
||||||
|
void update_index_db();
|
||||||
};
|
};
|
||||||
|
|
||||||
PresetUpdater::priv::priv()
|
PresetUpdater::priv::priv()
|
||||||
: cache_path(fs::path(Slic3r::data_dir()) / "cache")
|
: cache_path(fs::path(Slic3r::data_dir()) / "cache")
|
||||||
|
, cache_vendor_path(cache_path / "vendor")
|
||||||
, rsrc_path(fs::path(resources_dir()) / "profiles")
|
, rsrc_path(fs::path(resources_dir()) / "profiles")
|
||||||
, vendor_path(fs::path(Slic3r::data_dir()) / "vendor")
|
, vendor_path(fs::path(Slic3r::data_dir()) / "vendor")
|
||||||
, cancel(false)
|
, cancel(false)
|
||||||
@ -179,8 +203,13 @@ PresetUpdater::priv::priv()
|
|||||||
index_db = Index::load_db();
|
index_db = Index::load_db();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PresetUpdater::priv::update_index_db()
|
||||||
|
{
|
||||||
|
index_db = Index::load_db();
|
||||||
|
}
|
||||||
|
|
||||||
// Pull relevant preferences from AppConfig
|
// Pull relevant preferences from AppConfig
|
||||||
void PresetUpdater::priv::set_download_prefs(AppConfig *app_config)
|
void PresetUpdater::priv::set_download_prefs(const AppConfig *app_config)
|
||||||
{
|
{
|
||||||
enabled_version_check = app_config->get("notify_release") != "none";
|
enabled_version_check = app_config->get("notify_release") != "none";
|
||||||
version_check_url = app_config->version_check_url();
|
version_check_url = app_config->version_check_url();
|
||||||
@ -232,45 +261,207 @@ void PresetUpdater::priv::prune_tmps() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PresetUpdater::priv::get_missing_resource(const std::string& vendor, const std::string& filename, const std::string& url) const
|
||||||
|
{
|
||||||
|
if (filename.empty() || vendor.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!boost::starts_with(url, "http://files.prusa3d.com/wp-content/uploads/repository/") &&
|
||||||
|
!boost::starts_with(url, "https://files.prusa3d.com/wp-content/uploads/repository/"))
|
||||||
|
{
|
||||||
|
throw Slic3r::CriticalException(GUI::format("URL outside prusa3d.com network: %1%", url));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string escaped_filename = escape_string_url(filename);
|
||||||
|
const fs::path file_in_vendor(vendor_path / (vendor + "/" + filename));
|
||||||
|
const fs::path file_in_rsrc(rsrc_path / (vendor + "/" + filename));
|
||||||
|
const fs::path file_in_cache(cache_path / (vendor + "/" + filename));
|
||||||
|
|
||||||
|
if (fs::exists(file_in_vendor)) { // Already in vendor. No need to do anything.
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Resource " << vendor << " / " << filename << " found in vendor folder. No need to download.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fs::exists(file_in_rsrc)) { // In resources dir since installation. No need to do anything.
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Resource " << vendor << " / " << filename << " found in resources folder. No need to download.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fs::exists(file_in_cache)) { // In cache/venodr_name/ dir. No need to do anything.
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Resource " << vendor << " / " << filename << " found in cache folder. No need to download.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Resources check could not find " << vendor << " / " << filename << " bed texture. Downloading.";
|
||||||
|
|
||||||
|
const auto resource_url = format("%1%%2%%3%", url, url.back() == '/' ? "" : "/", escaped_filename); // vendor should already be in url
|
||||||
|
|
||||||
|
if (!fs::exists(file_in_cache.parent_path()))
|
||||||
|
fs::create_directory(file_in_cache.parent_path());
|
||||||
|
|
||||||
|
get_file(resource_url, file_in_cache);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PresetUpdater::priv::get_or_copy_missing_resource(const std::string& vendor, const std::string& filename, const std::string& url) const
|
||||||
|
{
|
||||||
|
if (filename.empty() || vendor.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string escaped_filename = escape_string_url(filename);
|
||||||
|
const fs::path file_in_vendor(vendor_path / (vendor + "/" + filename));
|
||||||
|
const fs::path file_in_rsrc(rsrc_path / (vendor + "/" + filename));
|
||||||
|
const fs::path file_in_cache(cache_path / (vendor + "/" + filename));
|
||||||
|
|
||||||
|
if (fs::exists(file_in_vendor)) { // Already in vendor. No need to do anything.
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Resource " << vendor << " / " << filename << " found in vendor folder. No need to download.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fs::exists(file_in_rsrc)) { // In resources dir since installation. No need to do anything.
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Resource " << vendor << " / " << filename << " found in resources folder. No need to download.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!fs::exists(file_in_cache)) { // No file to copy. Download it to straight to the vendor dir.
|
||||||
|
if (!boost::starts_with(url, "http://files.prusa3d.com/wp-content/uploads/repository/") &&
|
||||||
|
!boost::starts_with(url, "https://files.prusa3d.com/wp-content/uploads/repository/"))
|
||||||
|
{
|
||||||
|
throw Slic3r::CriticalException(GUI::format("URL outside prusa3d.com network: %1%", url));
|
||||||
|
}
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Downloading resources missing in cache directory: " << vendor << " / " << filename;
|
||||||
|
|
||||||
|
const auto resource_url = format("%1%%2%%3%", url, url.back() == '/' ? "" : "/", escaped_filename); // vendor should already be in url
|
||||||
|
|
||||||
|
if (!fs::exists(file_in_vendor.parent_path()))
|
||||||
|
fs::create_directory(file_in_vendor.parent_path());
|
||||||
|
|
||||||
|
get_file(resource_url, file_in_vendor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs::exists(file_in_vendor.parent_path())) // create vendor_name dir in vendor
|
||||||
|
fs::create_directory(file_in_vendor.parent_path());
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Copiing: " << file_in_cache << " to " << file_in_vendor;
|
||||||
|
copy_file_fix(file_in_cache, file_in_vendor);
|
||||||
|
}
|
||||||
|
|
||||||
// Download vendor indices. Also download new bundles if an index indicates there's a new one available.
|
// Download vendor indices. Also download new bundles if an index indicates there's a new one available.
|
||||||
// Both are saved in cache.
|
// Both are saved in cache.
|
||||||
void PresetUpdater::priv::sync_config(const VendorMap vendors)
|
void PresetUpdater::priv::sync_config(const VendorMap vendors, const std::string& index_archive_url)
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(info) << "Syncing configuration cache";
|
BOOST_LOG_TRIVIAL(info) << "Syncing configuration cache";
|
||||||
|
|
||||||
if (!enabled_config_update) { return; }
|
if (!enabled_config_update) { return; }
|
||||||
|
|
||||||
// Donwload vendor preset bundles
|
// Download profiles archive zip
|
||||||
|
// dk: Do we want to return here on error? Or skip archive dwnld and unzip and work with previous run state cache / vendor? I think return.
|
||||||
|
// Any error here also doesnt show any info in UI. Do we want maybe notification?
|
||||||
|
fs::path archive_path(cache_path / "vendor_indices.zip");
|
||||||
|
if (index_archive_url.empty()) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Downloading profile archive failed - url has no value.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Downloading vedor profiles archive zip from " << index_archive_url;
|
||||||
|
//check if idx_url is leading to our site
|
||||||
|
if (!boost::starts_with(index_archive_url, "http://files.prusa3d.com/wp-content/uploads/repository/") &&
|
||||||
|
!boost::starts_with(index_archive_url, "https://files.prusa3d.com/wp-content/uploads/repository/"))
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Unsafe url path for vedor profiles archive zip. Download is rejected.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!get_file(index_archive_url, archive_path)) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Download of vedor profiles archive zip failed.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cancel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class VendorStatus
|
||||||
|
{
|
||||||
|
IN_ARCHIVE,
|
||||||
|
IN_CACHE,
|
||||||
|
NEW_VERSION,
|
||||||
|
INSTALLED
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, VendorStatus>> vendors_with_status;
|
||||||
|
// Unzip archive to cache / vendor
|
||||||
|
mz_zip_archive archive;
|
||||||
|
mz_zip_zero_struct(&archive);
|
||||||
|
if (!open_zip_reader(&archive, archive_path.string())) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Couldn't open zipped bundle.";
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
mz_uint num_entries = mz_zip_reader_get_num_files(&archive);
|
||||||
|
// loop the entries
|
||||||
|
mz_zip_archive_file_stat stat;
|
||||||
|
for (mz_uint i = 0; i < num_entries; ++i) {
|
||||||
|
if (mz_zip_reader_file_stat(&archive, i, &stat)) {
|
||||||
|
std::string name(stat.m_filename);
|
||||||
|
if (stat.m_uncomp_size > 0) {
|
||||||
|
std::string buffer((size_t)stat.m_uncomp_size, 0);
|
||||||
|
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
|
||||||
|
if (res == 0) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Failed to unzip " << stat.m_filename;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// create file from buffer
|
||||||
|
fs::path tmp_path(cache_vendor_path / (name + ".tmp"));
|
||||||
|
if (!fs::exists(tmp_path.parent_path())) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Failed to unzip file " << name << ". Directories are not supported. Skipping file.";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fs::path target_path(cache_vendor_path / name);
|
||||||
|
fs::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc);
|
||||||
|
file.write(buffer.c_str(), buffer.size());
|
||||||
|
file.close();
|
||||||
|
boost::system::error_code ec;
|
||||||
|
bool exists = fs::exists(tmp_path, ec);
|
||||||
|
if(!exists || ec) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Failed to find unzipped file at " << tmp_path << ". Terminating Preset updater synchorinzation." ;
|
||||||
|
close_zip_reader(&archive);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fs::rename(tmp_path, target_path, ec);
|
||||||
|
if (ec) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Failed to rename unzipped file at " << tmp_path << ". Terminating Preset updater synchorinzation. Error message: " << ec.message();
|
||||||
|
close_zip_reader(&archive);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: what if unexpected happens here (folder inside zip) - crash!
|
||||||
|
|
||||||
|
if (name.substr(name.size() - 3) == "idx")
|
||||||
|
vendors_with_status.emplace_back(name.substr(0, name.size() - 4), VendorStatus::IN_ARCHIVE); // asume for now its only in archive - if not, it will change later.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close_zip_reader(&archive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update vendor preset bundles if in Vendor
|
||||||
// Over all indices from the cache directory:
|
// Over all indices from the cache directory:
|
||||||
for (auto &index : index_db) {
|
for (auto &index : index_db) {
|
||||||
if (cancel) { return; }
|
if (cancel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto archive_it = std::find_if(vendors_with_status.begin(), vendors_with_status.end(),
|
||||||
|
[&index](const std::pair<std::string, VendorStatus>& element) { return element.first == index.vendor(); });
|
||||||
|
//assert(archive_it != vendors_with_status.end()); // this would mean there is a index for vendor that is missing in recently downloaded archive
|
||||||
|
|
||||||
const auto vendor_it = vendors.find(index.vendor());
|
const auto vendor_it = vendors.find(index.vendor());
|
||||||
if (vendor_it == vendors.end()) {
|
if (vendor_it == vendors.end()) {
|
||||||
BOOST_LOG_TRIVIAL(warning) << "No such vendor: " << index.vendor();
|
// Not installed vendor yet we need to check missing thumbnails (of new printers)
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "No such vendor: " << index.vendor();
|
||||||
|
if (archive_it != vendors_with_status.end())
|
||||||
|
archive_it->second = VendorStatus::IN_CACHE;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (archive_it != vendors_with_status.end())
|
||||||
|
archive_it->second = VendorStatus::INSTALLED;
|
||||||
|
|
||||||
const VendorProfile &vendor = vendor_it->second;
|
const VendorProfile &vendor = vendor_it->second;
|
||||||
if (vendor.config_update_url.empty()) {
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Vendor has no config_update_url: " << vendor.name;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download a fresh index
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Downloading index for vendor: " << vendor.name;
|
|
||||||
const auto idx_url = vendor.config_update_url + "/" + INDEX_FILENAME;
|
|
||||||
const std::string idx_path = (cache_path / (vendor.id + ".idx")).string();
|
const std::string idx_path = (cache_path / (vendor.id + ".idx")).string();
|
||||||
const std::string idx_path_temp = idx_path + "-update";
|
const std::string idx_path_temp = (cache_vendor_path / (vendor.id + ".idx")).string();
|
||||||
//check if idx_url is leading to our site
|
|
||||||
if (! boost::starts_with(idx_url, "http://files.prusa3d.com/wp-content/uploads/repository/") &&
|
|
||||||
! boost::starts_with(idx_url, "https://files.prusa3d.com/wp-content/uploads/repository/"))
|
|
||||||
{
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "unsafe url path for vendor \"" << vendor.name << "\" rejected: " << idx_url;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!get_file(idx_url, idx_path_temp)) { continue; }
|
|
||||||
if (cancel) { return; }
|
|
||||||
|
|
||||||
// Load the fresh index up
|
// Load the fresh index up
|
||||||
{
|
{
|
||||||
@ -282,10 +473,11 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (new_index.version() < index.version()) {
|
if (new_index.version() < index.version()) {
|
||||||
BOOST_LOG_TRIVIAL(warning) << format("The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index.", idx_path_temp, vendor.name);
|
BOOST_LOG_TRIVIAL(info) << format("The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index.", idx_path_temp, vendor.name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Slic3r::rename_file(idx_path_temp, idx_path);
|
copy_file_fix(idx_path_temp, idx_path);
|
||||||
|
|
||||||
//if we rename path we need to change it in Index object too or create the object again
|
//if we rename path we need to change it in Index object too or create the object again
|
||||||
//index = std::move(new_index);
|
//index = std::move(new_index);
|
||||||
try {
|
try {
|
||||||
@ -315,12 +507,265 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors)
|
|||||||
|
|
||||||
if (vendor.config_version >= recommended) { continue; }
|
if (vendor.config_version >= recommended) { continue; }
|
||||||
|
|
||||||
// Download a fresh bundle
|
// vendors that are checked here, doesnt need to be checked again later
|
||||||
|
if (archive_it != vendors_with_status.end())
|
||||||
|
archive_it->second = VendorStatus::NEW_VERSION;
|
||||||
|
|
||||||
|
// Download recomended ini to cache
|
||||||
|
const auto path_in_cache = cache_path / (vendor.id + ".ini");
|
||||||
BOOST_LOG_TRIVIAL(info) << "Downloading new bundle for vendor: " << vendor.name;
|
BOOST_LOG_TRIVIAL(info) << "Downloading new bundle for vendor: " << vendor.name;
|
||||||
const auto bundle_url = format("%1%/%2%.ini", vendor.config_update_url, recommended.to_string());
|
const auto bundle_url = format("%1%/%2%.ini", vendor.config_update_url, recommended.to_string());
|
||||||
const auto bundle_path = cache_path / (vendor.id + ".ini");
|
const auto bundle_path = cache_path / (vendor.id + ".ini");
|
||||||
if (! get_file(bundle_url, bundle_path)) { continue; }
|
if (!get_file(bundle_url, bundle_path))
|
||||||
if (cancel) { return; }
|
continue;
|
||||||
|
if (cancel)
|
||||||
|
return;
|
||||||
|
// vp is fully loaded to get all resources
|
||||||
|
VendorProfile vp;
|
||||||
|
try {
|
||||||
|
vp = VendorProfile::from_ini(bundle_path, true);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1% at %2%, message: %3%", vendor.id, bundle_path, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// check the fresh bundle for missing resources
|
||||||
|
// for that, the ini file must be parsed (done above)
|
||||||
|
for (const auto& model : vp.models) {
|
||||||
|
for (const std::string& res : { model.bed_texture, model.bed_model, model.thumbnail/*id +"_thumbnail.png"*/} ) {
|
||||||
|
if (! res.empty()) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
get_missing_resource(vp.id, res, vendor.config_update_url);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Failed to get " << res << " for " << vp.id << " " << model.id << ": " << e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (cancel)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Download missing thumbnails for not-installed vendors.
|
||||||
|
//for (const std::string& vendor : vendors_only_in_archive)
|
||||||
|
for (const std::pair<std::string, VendorStatus >& vendor : vendors_with_status) {
|
||||||
|
if (vendor.second == VendorStatus::IN_ARCHIVE) {
|
||||||
|
// index in archive and not in cache and not installed vendor
|
||||||
|
|
||||||
|
const auto idx_path_in_archive = cache_vendor_path / (vendor.first + ".idx");
|
||||||
|
const auto ini_path_in_archive = cache_vendor_path / (vendor.first + ".ini");
|
||||||
|
if (!fs::exists(idx_path_in_archive))
|
||||||
|
continue;
|
||||||
|
Index index;
|
||||||
|
try {
|
||||||
|
index.load(idx_path_in_archive);
|
||||||
|
}
|
||||||
|
catch (const std::exception& /* err */) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Could not load downloaded index %1% for vendor %2%: invalid index?", idx_path_in_archive, vendor.first);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto recommended_it = index.recommended();
|
||||||
|
if (recommended_it == index.end()) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("No recommended version for vendor: %1%, invalid index? (%2%)", vendor.first, idx_path_in_archive);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto recommended = recommended_it->config_version;
|
||||||
|
if (!fs::exists(ini_path_in_archive)){
|
||||||
|
// Download recommneded to vendor - we do not have any existing ini file so we have to use hardcoded url.
|
||||||
|
const std::string fixed_url = GUI::wxGetApp().app_config->profile_folder_url();
|
||||||
|
const auto bundle_url = format("%1%/%2%/%3%.ini", fixed_url, vendor.first, recommended.to_string());
|
||||||
|
if (!get_file(bundle_url, ini_path_in_archive))
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// check existing ini version
|
||||||
|
// then download recommneded to vendor if needed
|
||||||
|
VendorProfile vp;
|
||||||
|
try {
|
||||||
|
vp = VendorProfile::from_ini(ini_path_in_archive, true);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1% at %2%, message: %3%", vendor.first, ini_path_in_archive, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (vp.config_version != recommended) {
|
||||||
|
const std::string fixed_url = GUI::wxGetApp().app_config->profile_folder_url();
|
||||||
|
const auto bundle_url = format("%1%/%2%/%3%.ini", fixed_url, vendor.first, recommended.to_string());
|
||||||
|
if (!get_file(bundle_url, ini_path_in_archive))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check missing thumbnails
|
||||||
|
VendorProfile vp;
|
||||||
|
try {
|
||||||
|
vp = VendorProfile::from_ini(ini_path_in_archive, true);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1% at %2%, message: %3%", vendor.first, ini_path_in_archive, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const auto& model : vp.models) {
|
||||||
|
if (!model.thumbnail.empty()) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
get_missing_resource(vp.id, model.thumbnail, vp.config_update_url);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Failed to get " << model.thumbnail << " for " << vp.id << " " << model.id << ": " << e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cancel)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (vendor.second == VendorStatus::IN_CACHE) {
|
||||||
|
// find those where archive index recommends other version than index in cache and get it if not present
|
||||||
|
const auto idx_path_in_archive = cache_vendor_path / (vendor.first + ".idx");
|
||||||
|
const auto ini_path_in_archive = cache_vendor_path / (vendor.first + ".ini");
|
||||||
|
const auto idx_path_in_cache = cache_path / (vendor.first + ".idx");
|
||||||
|
|
||||||
|
if (!fs::exists(idx_path_in_archive) || !fs::exists(idx_path_in_cache))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Compare index in cache and recetly downloaded one as part of zip archive
|
||||||
|
Index index_cache;
|
||||||
|
try {
|
||||||
|
index_cache.load(idx_path_in_cache);
|
||||||
|
}
|
||||||
|
catch (const std::exception& /* err */) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Could not load downloaded index %1% for vendor %2%: invalid index?", idx_path_in_cache, vendor.first);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto recommended_it_cache = index_cache.recommended();
|
||||||
|
if (recommended_it_cache == index_cache.end()) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("No recommended version for vendor: %1%, invalid index? (%2%)", vendor.first, idx_path_in_cache);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto recommended_cache = recommended_it_cache->config_version;
|
||||||
|
|
||||||
|
Index index_archive;
|
||||||
|
try {
|
||||||
|
index_archive.load(idx_path_in_archive);
|
||||||
|
}
|
||||||
|
catch (const std::exception& /* err */) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Could not load downloaded index %1% for vendor %2%: invalid index?", idx_path_in_archive, vendor.first);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto recommended_it_archive = index_archive.recommended();
|
||||||
|
if (recommended_it_archive == index_archive.end()) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("No recommended version for vendor: %1%, invalid index? (%2%)", vendor.first, idx_path_in_archive);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto recommended_archive = recommended_it_archive->config_version;
|
||||||
|
|
||||||
|
if (recommended_archive <= recommended_cache) {
|
||||||
|
// There isn't more recent recomended version online. This vendor is also not istalled.
|
||||||
|
// Thus only .ini is in resources and came with installation.
|
||||||
|
// And we expect all resources are present.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download new .ini if needed. So next time user runs Wizard, most recent profiles are shown & installed.
|
||||||
|
if (!fs::exists(ini_path_in_archive) || fs::is_empty(ini_path_in_archive)) {
|
||||||
|
// download recommneded to vendor
|
||||||
|
const fs::path ini_path_in_rsrc = rsrc_path / (vendor.first + ".ini");
|
||||||
|
if (!fs::exists(ini_path_in_rsrc)) {
|
||||||
|
// THIS SHOULD NOT HAPPEN
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Get download path from existing ini.
|
||||||
|
VendorProfile vp;
|
||||||
|
try {
|
||||||
|
vp = VendorProfile::from_ini(ini_path_in_rsrc, false);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1% at %2%, message: %3%", vendor.first, ini_path_in_rsrc, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto bundle_url = format("%1%/%2%.ini", vp.config_update_url, recommended_archive.to_string());
|
||||||
|
if (!get_file(bundle_url, ini_path_in_archive)) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Failed to open vendor .ini file when checking missing resources: %1%", ini_path_in_rsrc);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check existing ini version.
|
||||||
|
// Then download recommneded to vendor if needed.
|
||||||
|
VendorProfile vp;
|
||||||
|
try {
|
||||||
|
vp = VendorProfile::from_ini(ini_path_in_archive, false);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1% at %2%, message: %3%", vendor.first, ini_path_in_archive, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (vp.config_version != recommended_archive) {
|
||||||
|
const auto bundle_url = format("%1%/%2%.ini", vp.config_update_url, recommended_archive.to_string());
|
||||||
|
if (!get_file(bundle_url, ini_path_in_archive)) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Failed to open vendor .ini file when checking missing resources: %1%", ini_path_in_archive);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fs::exists(ini_path_in_archive)) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Resources check failed to find ini file for vendor: " << vendor.first;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// check missing thumbnails
|
||||||
|
VendorProfile vp;
|
||||||
|
try {
|
||||||
|
vp = VendorProfile::from_ini(ini_path_in_archive, true);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1% at %2%, message: %3%", vendor.first, ini_path_in_archive, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const auto& model : vp.models) {
|
||||||
|
if (!model.thumbnail.empty()) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
get_missing_resource(vp.id, model.thumbnail, vp.config_update_url);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Failed to get " << model.thumbnail << " for " << vp.id << " " << model.id << ": " << e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cancel)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (vendor.second == VendorStatus::INSTALLED || vendor.second == VendorStatus::NEW_VERSION) {
|
||||||
|
// Installed vendors need to check that no resource is missing. Do this only for files in vendor folder (not in resorces)
|
||||||
|
// VendorStatus::NEW_VERSION might seem like a mistake here since files are downloaded when preparing update higher in this function.
|
||||||
|
// But this is a check for ini file in vendor where resources might be still missing since last update.
|
||||||
|
const auto path_in_vendor = vendor_path / (vendor.first + ".ini");
|
||||||
|
if(!fs::exists(path_in_vendor))
|
||||||
|
continue;
|
||||||
|
VendorProfile vp;
|
||||||
|
try {
|
||||||
|
vp = VendorProfile::from_ini(path_in_vendor, true);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1% at %2%, message: %3%", vendor.first, path_in_vendor, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const auto& model : vp.models) {
|
||||||
|
for (const std::string& res : { model.bed_texture, model.bed_model, model.thumbnail }) {
|
||||||
|
if (!model.thumbnail.empty()) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
get_or_copy_missing_resource(vp.id, res, vp.config_update_url);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Failed to get " << model.thumbnail << " for " << vp.id << " " << model.id << ": " << e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cancel)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,8 +815,14 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Perform a basic load and check the version of the installed preset bundle.
|
// Perform a basic load and check the version of the installed preset bundle.
|
||||||
auto vp = VendorProfile::from_ini(bundle_path, false);
|
VendorProfile vp;
|
||||||
|
try {
|
||||||
|
vp = VendorProfile::from_ini(bundle_path, false);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1% at %2%, message: %3%", idx.vendor(), bundle_path, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// Getting a recommended version from the latest index, wich may have been downloaded
|
// Getting a recommended version from the latest index, wich may have been downloaded
|
||||||
// from the internet, or installed / updated from the installation resources.
|
// from the internet, or installed / updated from the installation resources.
|
||||||
auto recommended = idx.recommended();
|
auto recommended = idx.recommended();
|
||||||
@ -401,7 +852,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version
|
|||||||
bool current_not_supported = false; //if slcr is incompatible but situation is not downgrade, we do forced updated and this bool is information to do it
|
bool current_not_supported = false; //if slcr is incompatible but situation is not downgrade, we do forced updated and this bool is information to do it
|
||||||
|
|
||||||
if (ver_current_found && !ver_current->is_current_slic3r_supported()){
|
if (ver_current_found && !ver_current->is_current_slic3r_supported()){
|
||||||
if(ver_current->is_current_slic3r_downgrade()) {
|
if (ver_current->is_current_slic3r_downgrade()) {
|
||||||
// "Reconfigure" situation.
|
// "Reconfigure" situation.
|
||||||
BOOST_LOG_TRIVIAL(warning) << "Current Slic3r incompatible with installed bundle: " << bundle_path.string();
|
BOOST_LOG_TRIVIAL(warning) << "Current Slic3r incompatible with installed bundle: " << bundle_path.string();
|
||||||
updates.incompats.emplace_back(std::move(bundle_path), *ver_current, vp.name);
|
updates.incompats.emplace_back(std::move(bundle_path), *ver_current, vp.name);
|
||||||
@ -443,10 +894,13 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version
|
|||||||
fs::path bundle_path_idx_to_install;
|
fs::path bundle_path_idx_to_install;
|
||||||
if (fs::exists(path_in_cache)) {
|
if (fs::exists(path_in_cache)) {
|
||||||
try {
|
try {
|
||||||
VendorProfile new_vp = VendorProfile::from_ini(path_in_cache, false);
|
VendorProfile new_vp = VendorProfile::from_ini(path_in_cache, true);
|
||||||
if (new_vp.config_version == recommended->config_version) {
|
if (new_vp.config_version == recommended->config_version) {
|
||||||
// The config bundle from the cache directory matches the recommended version of the index from the cache directory.
|
// The config bundle from the cache directory matches the recommended version of the index from the cache directory.
|
||||||
// This is the newest known recommended config. Use it.
|
// This is the newest known recommended config. Use it.
|
||||||
|
if (!PresetUtils::vendor_profile_has_all_resources(new_vp)) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "Some resources are missing for update of vedor " << new_vp.id;
|
||||||
|
}
|
||||||
new_update = Update(std::move(path_in_cache), std::move(bundle_path), *recommended, vp.name, vp.changelog_url, current_not_supported);
|
new_update = Update(std::move(path_in_cache), std::move(bundle_path), *recommended, vp.name, vp.changelog_url, current_not_supported);
|
||||||
// and install the config index from the cache into vendor's directory.
|
// and install the config index from the cache into vendor's directory.
|
||||||
bundle_path_idx_to_install = idx.path();
|
bundle_path_idx_to_install = idx.path();
|
||||||
@ -564,6 +1018,9 @@ bool PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons
|
|||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << format("Performing %1% updates", updates.updates.size());
|
BOOST_LOG_TRIVIAL(info) << format("Performing %1% updates", updates.updates.size());
|
||||||
|
|
||||||
|
wxProgressDialog progress_dialog(_L("Installing profiles"), _L("Installing profiles") , 100, nullptr, wxPD_AUTO_HIDE);
|
||||||
|
progress_dialog.Pulse();
|
||||||
|
|
||||||
for (const auto &update : updates.updates) {
|
for (const auto &update : updates.updates) {
|
||||||
BOOST_LOG_TRIVIAL(info) << '\t' << update;
|
BOOST_LOG_TRIVIAL(info) << '\t' << update;
|
||||||
|
|
||||||
@ -601,7 +1058,35 @@ bool PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons
|
|||||||
for (const auto &name : bundle.obsolete_presets.sla_prints) { obsolete_remover("sla_print", name); }
|
for (const auto &name : bundle.obsolete_presets.sla_prints) { obsolete_remover("sla_print", name); }
|
||||||
for (const auto &name : bundle.obsolete_presets.sla_materials/*filaments*/) { obsolete_remover("sla_material", name); }
|
for (const auto &name : bundle.obsolete_presets.sla_materials/*filaments*/) { obsolete_remover("sla_material", name); }
|
||||||
for (const auto &name : bundle.obsolete_presets.printers) { obsolete_remover("printer", name); }
|
for (const auto &name : bundle.obsolete_presets.printers) { obsolete_remover("printer", name); }
|
||||||
|
|
||||||
|
// check if any resorces of installed bundle are missing. If so, new ones should be already downloaded at cache/vendor_id/
|
||||||
|
VendorProfile vp;
|
||||||
|
try {
|
||||||
|
vp = VendorProfile::from_ini(update.target, true);
|
||||||
}
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1%, message: %2%", update.target, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
progress_dialog.Update(1, GUI::format_wxstr(_L("Downloading resources for %1%."),vp.id));
|
||||||
|
progress_dialog.Pulse();
|
||||||
|
for (const auto& model : vp.models) {
|
||||||
|
for (const std::string& resource : { model.bed_texture, model.bed_model, model.thumbnail }) {
|
||||||
|
if (resource.empty())
|
||||||
|
continue;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
get_or_copy_missing_resource(vp.id, resource, vp.config_update_url);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Failed to prepare " << resource << " for " << vp.id << " " << model.id << ": " << e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
progress_dialog.Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -630,7 +1115,7 @@ PresetUpdater::~PresetUpdater()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresetUpdater::sync(PresetBundle *preset_bundle)
|
void PresetUpdater::sync(const PresetBundle *preset_bundle)
|
||||||
{
|
{
|
||||||
p->set_download_prefs(GUI::wxGetApp().app_config);
|
p->set_download_prefs(GUI::wxGetApp().app_config);
|
||||||
if (!p->enabled_version_check && !p->enabled_config_update) { return; }
|
if (!p->enabled_version_check && !p->enabled_config_update) { return; }
|
||||||
@ -639,13 +1124,24 @@ void PresetUpdater::sync(PresetBundle *preset_bundle)
|
|||||||
// Unfortunatelly as of C++11, it needs to be copied again
|
// Unfortunatelly as of C++11, it needs to be copied again
|
||||||
// into the closure (but perhaps the compiler can elide this).
|
// into the closure (but perhaps the compiler can elide this).
|
||||||
VendorMap vendors = preset_bundle->vendors;
|
VendorMap vendors = preset_bundle->vendors;
|
||||||
|
std::string index_archive_url = GUI::wxGetApp().app_config->index_archive_url();
|
||||||
|
|
||||||
p->thread = std::thread([this, vendors]() {
|
p->thread = std::thread([this, vendors, index_archive_url]() {
|
||||||
this->p->prune_tmps();
|
this->p->prune_tmps();
|
||||||
this->p->sync_config(std::move(vendors));
|
this->p->sync_config(std::move(vendors), index_archive_url);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PresetUpdater::cancel_sync()
|
||||||
|
{
|
||||||
|
if (p && p->thread.joinable()) {
|
||||||
|
// This will stop transfers being done by the thread, if any.
|
||||||
|
// Cancelling takes some time, but should complete soon enough.
|
||||||
|
p->cancel = true;
|
||||||
|
p->thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PresetUpdater::slic3r_update_notify()
|
void PresetUpdater::slic3r_update_notify()
|
||||||
{
|
{
|
||||||
if (! p->enabled_version_check)
|
if (! p->enabled_version_check)
|
||||||
@ -810,7 +1306,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
|
|||||||
return R_NOOP;
|
return R_NOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PresetUpdater::install_bundles_rsrc(std::vector<std::string> bundles, bool snapshot) const
|
bool PresetUpdater::install_bundles_rsrc_or_cache_vendor(std::vector<std::string> bundles, bool snapshot) const
|
||||||
{
|
{
|
||||||
Updates updates;
|
Updates updates;
|
||||||
|
|
||||||
@ -818,9 +1314,67 @@ bool PresetUpdater::install_bundles_rsrc(std::vector<std::string> bundles, bool
|
|||||||
|
|
||||||
for (const auto &bundle : bundles) {
|
for (const auto &bundle : bundles) {
|
||||||
auto path_in_rsrc = (p->rsrc_path / bundle).replace_extension(".ini");
|
auto path_in_rsrc = (p->rsrc_path / bundle).replace_extension(".ini");
|
||||||
|
auto path_in_cache_vendor = (p->cache_vendor_path / bundle).replace_extension(".ini");
|
||||||
auto path_in_vendors = (p->vendor_path / bundle).replace_extension(".ini");
|
auto path_in_vendors = (p->vendor_path / bundle).replace_extension(".ini");
|
||||||
|
|
||||||
|
bool is_in_rsrc = fs::exists(path_in_rsrc);
|
||||||
|
bool is_in_cache_vendor = fs::exists(path_in_cache_vendor) && !fs::is_empty(path_in_cache_vendor);
|
||||||
|
|
||||||
|
// find if in cache vendor is newer version than in resources
|
||||||
|
if (is_in_cache_vendor) {
|
||||||
|
Semver version_cache = Semver::zero();
|
||||||
|
try {
|
||||||
|
auto vp_cache = VendorProfile::from_ini(path_in_cache_vendor, false);
|
||||||
|
version_cache = vp_cache.config_version;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1%, message: %2%", path_in_cache_vendor, e.what());
|
||||||
|
// lets use file in resources
|
||||||
|
if (is_in_rsrc) {
|
||||||
updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", "");
|
updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", "");
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Semver version_rsrc = Semver::zero();
|
||||||
|
try {
|
||||||
|
if (is_in_rsrc) {
|
||||||
|
auto vp = VendorProfile::from_ini(path_in_rsrc, false);
|
||||||
|
version_rsrc = vp.config_version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << format("Corrupted profile file for vendor %1%, message: %2%", path_in_rsrc, e.what());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_in_rsrc || version_cache > version_rsrc) {
|
||||||
|
// in case we are installing from cache / vendor. we should also copy index to cache
|
||||||
|
// This needs to be done now bcs the current one would be missing this version on next start
|
||||||
|
// dk: Should we copy it to vendor dir too?
|
||||||
|
auto path_idx_cache_vendor(path_in_cache_vendor);
|
||||||
|
path_idx_cache_vendor.replace_extension(".idx");
|
||||||
|
auto path_idx_cache = (p->cache_path / bundle).replace_extension(".idx");
|
||||||
|
// DK: do this during perform_updates() too?
|
||||||
|
if (fs::exists(path_idx_cache_vendor))
|
||||||
|
copy_file_fix(path_idx_cache_vendor, path_idx_cache);
|
||||||
|
else // Should we dialog this?
|
||||||
|
BOOST_LOG_TRIVIAL(error) << GUI::format(_L("Couldn't locate idx file %1% when performing updates."), path_idx_cache_vendor.string());
|
||||||
|
updates.updates.emplace_back(std::move(path_in_cache_vendor), std::move(path_in_vendors), Version(), "", "");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (is_in_rsrc)
|
||||||
|
updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", "");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (! is_in_rsrc) {
|
||||||
|
// This should not happen. Instead of an assert, make it crash in Release mode too.
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Internal error in PresetUpdater! Terminating the application.";
|
||||||
|
std::terminate();
|
||||||
|
}
|
||||||
|
updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return p->perform_updates(std::move(updates), snapshot);
|
return p->perform_updates(std::move(updates), snapshot);
|
||||||
}
|
}
|
||||||
@ -857,4 +1411,9 @@ bool PresetUpdater::version_check_enabled() const
|
|||||||
return p->enabled_version_check;
|
return p->enabled_version_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PresetUpdater::update_index_db()
|
||||||
|
{
|
||||||
|
p->update_index_db();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,8 @@ public:
|
|||||||
~PresetUpdater();
|
~PresetUpdater();
|
||||||
|
|
||||||
// If either version check or config updating is enabled, get the appropriate data in the background and cache it.
|
// If either version check or config updating is enabled, get the appropriate data in the background and cache it.
|
||||||
void sync(PresetBundle *preset_bundle);
|
void sync(const PresetBundle *preset_bundle);
|
||||||
|
void cancel_sync();
|
||||||
|
|
||||||
// If version check is enabled, check if chaced online slic3r version is newer, notify if so.
|
// If version check is enabled, check if chaced online slic3r version is newer, notify if so.
|
||||||
void slic3r_update_notify();
|
void slic3r_update_notify();
|
||||||
@ -53,8 +54,10 @@ public:
|
|||||||
// that the config index installed from the Internet is equal to the index contained in the installation package.
|
// that the config index installed from the Internet is equal to the index contained in the installation package.
|
||||||
UpdateResult config_update(const Semver &old_slic3r_version, UpdateParams params) const;
|
UpdateResult config_update(const Semver &old_slic3r_version, UpdateParams params) const;
|
||||||
|
|
||||||
// "Update" a list of bundles from resources (behaves like an online update).
|
void update_index_db();
|
||||||
bool install_bundles_rsrc(std::vector<std::string> bundles, bool snapshot = true) const;
|
|
||||||
|
// "Update" a list of bundles from resources or cache/vendor (behaves like an online update).
|
||||||
|
bool install_bundles_rsrc_or_cache_vendor(std::vector<std::string> bundles, bool snapshot = true) const;
|
||||||
|
|
||||||
void on_update_notification_confirm();
|
void on_update_notification_confirm();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user