mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-07-09 16:51:48 +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.
|
||||
//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";
|
||||
// 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_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 (get("no_defaults").empty())
|
||||
set("no_defaults", "1");
|
||||
if (get("no_templates").empty())
|
||||
set("no_templates", "0");
|
||||
if (get("show_incompatible_presets").empty())
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
return boost::filesystem::exists(config_path());
|
||||
|
@ -139,6 +139,11 @@ public:
|
||||
// Get the Slic3r version check url.
|
||||
// This returns a hardcoded string unless it is overriden by "version_check_url" in the ini file.
|
||||
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
|
||||
// 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();
|
||||
}
|
||||
|
||||
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) {
|
||||
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_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())
|
||||
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)
|
||||
{
|
||||
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.
|
||||
return false;
|
||||
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)
|
||||
{
|
||||
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.
|
||||
return false;
|
||||
auto &condition = preset.preset.compatible_printers_condition();
|
||||
@ -1185,6 +1196,7 @@ size_t PresetCollection::update_compatible_internal(const PresetWithVendorProfil
|
||||
if (opt)
|
||||
config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast<const ConfigOptionFloats*>(opt)->values.size()));
|
||||
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) {
|
||||
bool selected = idx_preset == m_idx_selected;
|
||||
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);
|
||||
if (selected)
|
||||
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.
|
||||
if (m_idx_selected >= m_num_default_presets && m_default_suppressed)
|
||||
for (size_t i = 0; i < m_num_default_presets; ++ i)
|
||||
@ -2099,6 +2133,25 @@ namespace PresetUtils {
|
||||
}
|
||||
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 Slic3r
|
||||
|
@ -34,6 +34,7 @@ public:
|
||||
Semver config_version;
|
||||
std::string config_update_url;
|
||||
std::string changelog_url;
|
||||
bool templates_profile { false };
|
||||
|
||||
struct PrinterVariant {
|
||||
PrinterVariant() {}
|
||||
@ -52,6 +53,7 @@ public:
|
||||
// Vendor & Printer Model specific print bed model & texture.
|
||||
std::string bed_model;
|
||||
std::string bed_texture;
|
||||
std::string thumbnail;
|
||||
|
||||
PrinterVariant* variant(const std::string &name) {
|
||||
for (auto &v : this->variants)
|
||||
@ -619,6 +621,7 @@ namespace PresetUtils {
|
||||
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset);
|
||||
std::string system_printer_bed_model(const Preset& preset);
|
||||
std::string system_printer_bed_texture(const Preset& preset);
|
||||
bool vendor_profile_has_all_resources(const VendorProfile& vp);
|
||||
} // namespace PresetUtils
|
||||
|
||||
|
||||
|
@ -159,6 +159,7 @@ void PresetBundle::setup_directories()
|
||||
data_dir,
|
||||
data_dir / "vendor",
|
||||
data_dir / "cache",
|
||||
data_dir / "cache" / "vendor",
|
||||
data_dir / "shapes",
|
||||
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
||||
// Store the print/filament/printer presets into a "presets" directory.
|
||||
@ -1307,17 +1308,26 @@ std::pair<PresetsConfigSubstitutions, size_t> PresetBundle::load_configbundle(
|
||||
try {
|
||||
pt::read_ini(ifs, tree);
|
||||
} 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;
|
||||
if (flags.has(LoadConfigBundleAttribute::LoadSystem) || flags.has(LoadConfigBundleAttribute::LoadVendorOnly)) {
|
||||
auto vp = VendorProfile::from_ini(tree, path);
|
||||
if (vp.models.size() == 0) {
|
||||
VendorProfile vp;
|
||||
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;
|
||||
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;
|
||||
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:")) {
|
||||
presets = &this->filaments;
|
||||
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:")) {
|
||||
presets = &this->sla_prints;
|
||||
preset_name = section.first.substr(10);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -60,18 +60,25 @@ enum Technology {
|
||||
T_ANY = ~0,
|
||||
};
|
||||
|
||||
enum BundleLocation{
|
||||
IN_VENDOR,
|
||||
IN_ARCHIVE,
|
||||
IN_RESOURCES
|
||||
};
|
||||
|
||||
struct Bundle
|
||||
{
|
||||
std::unique_ptr<PresetBundle> preset_bundle;
|
||||
VendorProfile* vendor_profile{ nullptr };
|
||||
bool is_in_resources{ false };
|
||||
//bool is_in_resources{ false };
|
||||
BundleLocation location;
|
||||
bool is_prusa_bundle{ false };
|
||||
|
||||
Bundle() = default;
|
||||
Bundle(Bundle&& other);
|
||||
|
||||
// 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; }
|
||||
};
|
||||
@ -84,74 +91,8 @@ struct BundleMap : std::map<std::string /* = vendor ID */, Bundle>
|
||||
const Bundle& prusa_bundle() const;
|
||||
};
|
||||
|
||||
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;
|
||||
struct Materials;
|
||||
|
||||
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;
|
||||
@ -344,6 +285,10 @@ struct PageMaterials: ConfigWizardPage
|
||||
std::string empty_printers_label;
|
||||
bool first_paint = { false };
|
||||
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 } ;
|
||||
|
||||
PageMaterials(ConfigWizard *parent, Materials *materials, wxString title, wxString shortname, wxString list1name);
|
||||
@ -368,6 +313,82 @@ struct PageMaterials: ConfigWizardPage
|
||||
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
|
||||
{
|
||||
PageCustom(ConfigWizard *parent);
|
||||
@ -608,9 +629,11 @@ struct ConfigWizard::priv
|
||||
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_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)
|
||||
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;
|
||||
wxBoxSizer *hscroll_sizer = nullptr;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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."),
|
||||
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",
|
||||
L("Show incompatible print and filament presets"),
|
||||
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);
|
||||
#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" };
|
||||
|
||||
for (const std::string& option : options_to_recreate_GUI) {
|
||||
@ -761,6 +768,9 @@ void PreferencesDialog::accept(wxEvent&)
|
||||
|
||||
wxGetApp().update_ui_from_settings();
|
||||
clear_cache();
|
||||
|
||||
if (update_filament_sidebar)
|
||||
wxGetApp().plater()->sidebar().update_presets(Preset::Type::TYPE_FILAMENT);
|
||||
}
|
||||
|
||||
void PreferencesDialog::revert(wxEvent&)
|
||||
|
@ -798,7 +798,7 @@ void PlaterPresetComboBox::show_edit_menu()
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
std::map<wxString, wxBitmapBundle*> nonsys_presets;
|
||||
std::map<wxString, wxBitmapBundle*> template_presets;
|
||||
|
||||
wxString selected_user_preset;
|
||||
wxString tooltip;
|
||||
@ -883,10 +884,18 @@ void PlaterPresetComboBox::update()
|
||||
|
||||
const std::string name = preset.alias.empty() ? preset.name : preset.alias;
|
||||
if (preset.is_default || preset.is_system) {
|
||||
Append(get_preset_name(preset), *bmp);
|
||||
validate_selection(is_selected);
|
||||
if (is_selected)
|
||||
tooltip = from_u8(preset.name);
|
||||
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);
|
||||
validate_selection(is_selected);
|
||||
if (is_selected)
|
||||
tooltip = from_u8(preset.name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -899,6 +908,8 @@ void PlaterPresetComboBox::update()
|
||||
if (i + 1 == m_collection->num_default_presets())
|
||||
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
|
||||
}
|
||||
|
||||
|
||||
if (!nonsys_presets.empty())
|
||||
{
|
||||
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)
|
||||
{
|
||||
// add Physical printers, if any exists
|
||||
@ -1046,6 +1066,8 @@ void TabPresetComboBox::update()
|
||||
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>> template_presets;
|
||||
|
||||
wxString selected = "";
|
||||
if (!presets.front().is_visible)
|
||||
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
|
||||
@ -1078,11 +1100,19 @@ void TabPresetComboBox::update()
|
||||
auto bmp = get_bmp(bitmap_key, main_icon_name, "lock_closed", is_enabled, preset.is_compatible, preset.is_system || preset.is_default);
|
||||
assert(bmp);
|
||||
|
||||
if (preset.is_default || preset.is_system) {
|
||||
int item_id = Append(get_preset_name(preset), *bmp);
|
||||
if (!is_enabled)
|
||||
set_label_marker(item_id, LABEL_ITEM_DISABLED);
|
||||
validate_selection(i == idx_selected);
|
||||
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);
|
||||
if (!is_enabled)
|
||||
set_label_marker(item_id, LABEL_ITEM_DISABLED);
|
||||
validate_selection(i == idx_selected);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1094,6 +1124,7 @@ void TabPresetComboBox::update()
|
||||
if (i + 1 == m_collection->num_default_presets())
|
||||
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
|
||||
}
|
||||
|
||||
if (!nonsys_presets.empty())
|
||||
{
|
||||
set_label_marker(Append(separator(L("User presets")), NullBitmapBndl()));
|
||||
@ -1105,7 +1136,19 @@ void TabPresetComboBox::update()
|
||||
validate_selection(it->first == selected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
// add Physical printers, if any exists
|
||||
|
@ -285,17 +285,17 @@ void SavePresetDialog::Item::Enable(bool enable /*= true*/)
|
||||
// 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)
|
||||
{
|
||||
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),
|
||||
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)
|
||||
@ -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__)
|
||||
// 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()); });
|
||||
|
||||
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);
|
||||
|
||||
SetSizer(topSizer);
|
||||
@ -371,6 +380,15 @@ std::string SavePresetDialog::get_name(Preset::Type type)
|
||||
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
|
||||
{
|
||||
for (const Item* item : m_items)
|
||||
|
@ -76,6 +76,7 @@ private:
|
||||
wxStaticText* m_label {nullptr};
|
||||
wxBoxSizer* m_radio_sizer {nullptr};
|
||||
ActionType m_action {UndefAction};
|
||||
wxCheckBox* m_template_filament_checkbox {nullptr};
|
||||
|
||||
std::string m_ph_printer_name;
|
||||
std::string m_old_preset_name;
|
||||
@ -88,8 +89,8 @@ public:
|
||||
|
||||
const wxString& get_info_line_extention() { return m_info_line_extention; }
|
||||
|
||||
SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix = "");
|
||||
SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix = "", PresetBundle* preset_bundle = nullptr);
|
||||
SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix = "", bool template_filament = false);
|
||||
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() override;
|
||||
|
||||
@ -105,12 +106,13 @@ public:
|
||||
bool Layout() override;
|
||||
bool is_for_rename() { return m_use_for_rename; }
|
||||
|
||||
bool get_template_filament_checkbox();
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
void on_sys_color_changed() override {}
|
||||
|
||||
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 accept();
|
||||
};
|
||||
|
@ -3715,11 +3715,25 @@ void Tab::save_preset(std::string name /*= ""*/, bool detach)
|
||||
// focus currently.is there anything better than this ?
|
||||
//! 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()) {
|
||||
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)
|
||||
return;
|
||||
name = dlg.get_name();
|
||||
if (from_template)
|
||||
from_template = dlg.get_template_filament_checkbox();
|
||||
}
|
||||
|
||||
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)
|
||||
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.
|
||||
// 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);
|
||||
|
@ -12,14 +12,17 @@
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/progdlg.h>
|
||||
|
||||
#include "libslic3r/libslic3r.h"
|
||||
#include "libslic3r/format.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/miniz_extension.hpp"
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/UpdateDialogs.hpp"
|
||||
@ -49,7 +52,7 @@ namespace Slic3r {
|
||||
static const char *INDEX_FILENAME = "index.idx";
|
||||
static const char *TMP_EXTENSION = ".download";
|
||||
|
||||
|
||||
namespace {
|
||||
void copy_file_fix(const fs::path &source, const fs::path &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;
|
||||
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
|
||||
{
|
||||
fs::path source;
|
||||
@ -144,6 +161,7 @@ struct PresetUpdater::priv
|
||||
std::string version_check_url;
|
||||
|
||||
fs::path cache_path;
|
||||
fs::path cache_vendor_path;
|
||||
fs::path rsrc_path;
|
||||
fs::path vendor_path;
|
||||
|
||||
@ -155,19 +173,25 @@ struct PresetUpdater::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;
|
||||
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;
|
||||
Updates get_config_updates(const Semver& old_slic3r_version) const;
|
||||
bool perform_updates(Updates &&updates, bool snapshot = true) const;
|
||||
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()
|
||||
: cache_path(fs::path(Slic3r::data_dir()) / "cache")
|
||||
, cache_vendor_path(cache_path / "vendor")
|
||||
, rsrc_path(fs::path(resources_dir()) / "profiles")
|
||||
, vendor_path(fs::path(Slic3r::data_dir()) / "vendor")
|
||||
, cancel(false)
|
||||
@ -179,8 +203,13 @@ PresetUpdater::priv::priv()
|
||||
index_db = Index::load_db();
|
||||
}
|
||||
|
||||
void PresetUpdater::priv::update_index_db()
|
||||
{
|
||||
index_db = Index::load_db();
|
||||
}
|
||||
|
||||
// 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";
|
||||
version_check_url = app_config->version_check_url();
|
||||
@ -232,46 +261,208 @@ 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.
|
||||
// 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";
|
||||
|
||||
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:
|
||||
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());
|
||||
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;
|
||||
}
|
||||
|
||||
if (archive_it != vendors_with_status.end())
|
||||
archive_it->second = VendorStatus::INSTALLED;
|
||||
|
||||
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_temp = idx_path + "-update";
|
||||
//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; }
|
||||
|
||||
const std::string idx_path_temp = (cache_vendor_path / (vendor.id + ".idx")).string();
|
||||
|
||||
// Load the fresh index up
|
||||
{
|
||||
Index new_index;
|
||||
@ -282,10 +473,11 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors)
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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
|
||||
//index = std::move(new_index);
|
||||
try {
|
||||
@ -315,12 +507,265 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors)
|
||||
|
||||
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;
|
||||
const auto bundle_url = format("%1%/%2%.ini", vendor.config_update_url, recommended.to_string());
|
||||
const auto bundle_path = cache_path / (vendor.id + ".ini");
|
||||
if (! get_file(bundle_url, bundle_path)) { continue; }
|
||||
if (cancel) { return; }
|
||||
if (!get_file(bundle_url, bundle_path))
|
||||
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.
|
||||
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
|
||||
// from the internet, or installed / updated from the installation resources.
|
||||
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
|
||||
|
||||
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.
|
||||
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);
|
||||
@ -443,10 +894,13 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version
|
||||
fs::path bundle_path_idx_to_install;
|
||||
if (fs::exists(path_in_cache)) {
|
||||
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) {
|
||||
// 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.
|
||||
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);
|
||||
// and install the config index from the cache into vendor's directory.
|
||||
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());
|
||||
|
||||
wxProgressDialog progress_dialog(_L("Installing profiles"), _L("Installing profiles") , 100, nullptr, wxPD_AUTO_HIDE);
|
||||
progress_dialog.Pulse();
|
||||
|
||||
for (const auto &update : updates.updates) {
|
||||
BOOST_LOG_TRIVIAL(info) << '\t' << update;
|
||||
|
||||
@ -601,12 +1058,40 @@ 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_materials/*filaments*/) { obsolete_remover("sla_material", 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;
|
||||
}
|
||||
|
||||
|
||||
void PresetUpdater::priv::set_waiting_updates(Updates u)
|
||||
{
|
||||
waiting_updates = u;
|
||||
@ -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);
|
||||
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
|
||||
// into the closure (but perhaps the compiler can elide this).
|
||||
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->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()
|
||||
{
|
||||
if (! p->enabled_version_check)
|
||||
@ -810,7 +1306,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
|
||||
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;
|
||||
|
||||
@ -818,8 +1314,66 @@ bool PresetUpdater::install_bundles_rsrc(std::vector<std::string> bundles, bool
|
||||
|
||||
for (const auto &bundle : bundles) {
|
||||
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");
|
||||
updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", "");
|
||||
|
||||
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(), "", "");
|
||||
}
|
||||
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);
|
||||
@ -857,4 +1411,9 @@ bool PresetUpdater::version_check_enabled() const
|
||||
return p->enabled_version_check;
|
||||
}
|
||||
|
||||
void PresetUpdater::update_index_db()
|
||||
{
|
||||
p->update_index_db();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ public:
|
||||
~PresetUpdater();
|
||||
|
||||
// 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.
|
||||
void slic3r_update_notify();
|
||||
@ -52,9 +53,11 @@ public:
|
||||
// Providing old slic3r version upgrade profiles on upgrade of an application even in case
|
||||
// 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;
|
||||
|
||||
void update_index_db();
|
||||
|
||||
// "Update" a list of bundles from resources (behaves like an online update).
|
||||
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();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user