Wizard and PresetUpdater changes
updater: - Sync downloads also missing thumbnails. - Copying of downloaded resources (perform_updates) also downloads missing ones (new vendor or installing vendor with added printers ). - This copy&download shows progress dialog now. - Fix of crash when installing new vendor (not in rsrc dir) Wizard: - Cancel updater sync when starting wizard to avoid multiple downloads. - Load thumbnails from cache dir (downloaded by updater sync). Preset: - Profiles now has settable name of thumbnail. If not specified, name + _thubnail.png is used (as it was before).
This commit is contained in:
parent
1589d89ca2
commit
fc65d73c2d
6 changed files with 188 additions and 46 deletions
|
@ -205,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));
|
||||
}
|
||||
|
@ -2138,7 +2142,7 @@ namespace PresetUtils {
|
|||
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.id + "_thumbnail.png" } ) {
|
||||
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))
|
||||
|
|
|
@ -53,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)
|
||||
|
|
|
@ -239,15 +239,23 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt
|
|||
}
|
||||
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)) {
|
||||
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")
|
||||
% vendor.id
|
||||
% model.id;
|
||||
load_bitmap(Slic3r::var(PRINTER_PLACEHOLDER), bitmap, bitmap_width);
|
||||
|
||||
bool found = false;
|
||||
for (const std::string& res : { Slic3r::data_dir() + "/vendor/" + vendor.id + "/", Slic3r::resources_dir() + "/profiles/" + vendor.id + "/", Slic3r::data_dir() + "/cache/" + vendor.id + "/" } ) {
|
||||
if (load_bitmap(GUI::from_u8(res + "/" + model.thumbnail), 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")
|
||||
% model.thumbnail
|
||||
% vendor.id
|
||||
% model.id;
|
||||
load_bitmap(Slic3r::var(PRINTER_PLACEHOLDER), bitmap, bitmap_width);
|
||||
}
|
||||
|
||||
auto *title = new wxStaticText(this, wxID_ANY, from_u8(model.name), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
|
||||
title->SetFont(font_name);
|
||||
const int wrap_width = std::max((int)MODEL_MIN_WRAP, bitmap_width);
|
||||
|
@ -3053,7 +3061,9 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
|||
if (install_bundles.size() > 0) {
|
||||
// Install bundles from resources or cache / vendor.
|
||||
// Don't create snapshot - we've already done that above if applicable.
|
||||
if (! updater->install_bundles_rsrc_or_cache_vendor(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;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "No bundles need to be installed from resources or cache / vendor";
|
||||
|
|
|
@ -2999,6 +2999,8 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage
|
|||
wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null");
|
||||
|
||||
if (reason == ConfigWizard::RR_USER) {
|
||||
// Cancel sync before starting wizard to prevent two downloads at same time
|
||||
preset_updater->cancel_sync();
|
||||
if (preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD) == PresetUpdater::R_ALL_CANCELED)
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -264,9 +264,12 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors, const std::string
|
|||
BOOST_LOG_TRIVIAL(error) << "Download of vedor profiles archive zip failed.";
|
||||
return;
|
||||
}
|
||||
if (cancel) { return; }
|
||||
if (cancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unzip archive to cache / vendor
|
||||
std::vector<std::string> vendors_only_in_archive;
|
||||
mz_zip_archive archive;
|
||||
mz_zip_zero_struct(&archive);
|
||||
if (!open_zip_reader(&archive, archive_path.string())) {
|
||||
|
@ -293,22 +296,64 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors, const std::string
|
|||
file.write(buffer.c_str(), buffer.size());
|
||||
file.close();
|
||||
fs::rename(tmp_path, target_path);
|
||||
|
||||
if (name.substr(name.size() - 3) == "ini")
|
||||
vendors_only_in_archive.push_back(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
close_zip_reader(&archive);
|
||||
}
|
||||
|
||||
auto get_missing_resource = [&self = std::as_const(*this)](const std::string& vendor, const std::string& filename,
|
||||
const std::string& url, const fs::path& vendor_path,
|
||||
const fs::path& rsrc_path, const fs::path& cache_path)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
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.
|
||||
return;
|
||||
}
|
||||
if (fs::exists(file_in_rsrc)) { // In resources dir since installation. No need to do anything.
|
||||
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() == '/' ? "" : "/", filename); // vendor should already be in url
|
||||
|
||||
if (!fs::exists(file_in_cache.parent_path()))
|
||||
fs::create_directory(file_in_cache.parent_path());
|
||||
|
||||
self.get_file(resource_url, file_in_cache);
|
||||
return;
|
||||
};
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
const auto vendor_it = vendors.find(index.vendor());
|
||||
if (vendor_it == vendors.end()) {
|
||||
BOOST_LOG_TRIVIAL(info) << "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();
|
||||
continue;
|
||||
}
|
||||
|
||||
const VendorProfile &vendor = vendor_it->second;
|
||||
const std::string idx_path = (cache_path / (vendor.id + ".idx")).string();
|
||||
const std::string idx_path_temp = (cache_vendor_path / (vendor.id + ".idx")).string();
|
||||
|
@ -367,32 +412,59 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors, const std::string
|
|||
if (vp.config_version != recommended)
|
||||
continue;
|
||||
copy_file_fix(path_in_archive, path_in_cache);
|
||||
// vendors that are checked here, doesnt need to be checked again later
|
||||
const auto archive_it = std::find(vendors_only_in_archive.begin(), vendors_only_in_archive.end(), index.vendor() + ".ini");
|
||||
if (archive_it != vendors_only_in_archive.end()) {
|
||||
vendors_only_in_archive.erase(archive_it);
|
||||
}
|
||||
|
||||
// check the fresh bundle for missing resources
|
||||
// for that, the ini file must be parsed (done above)
|
||||
auto check_and_get_resource = [&self = std::as_const(*this)](const std::string& vendor, const std::string& filename,
|
||||
const std::string& url, const fs::path& vendor_path,
|
||||
const fs::path& rsrc_path, const fs::path& cache_path)
|
||||
{
|
||||
if (!fs::exists((vendor_path / (vendor + "/" + filename)))
|
||||
&& !fs::exists((rsrc_path / (vendor + "/" + filename)))) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Resources check could not find " << vendor << " / " << filename << " bed texture. Downloading.";
|
||||
const auto resource_url = format("%1%/%2%/%3%", url, vendor, filename);
|
||||
const auto resource_path = (cache_path / (vendor + "/" + filename));
|
||||
if (!fs::exists(resource_path.parent_path()))
|
||||
fs::create_directory(resource_path.parent_path());
|
||||
self.get_file(resource_url, resource_path);
|
||||
}
|
||||
};
|
||||
for (const auto& model : vp.models) {
|
||||
for (const std::string& res : { model.bed_texture, model.bed_model, model.id +"_thumbnail.png"} ) {
|
||||
if (! res.empty())
|
||||
check_and_get_resource(vp.id, res, vendor.config_update_url, vendor_path, rsrc_path, cache_path);
|
||||
for (const std::string& res : { model.bed_texture, model.bed_model, model.thumbnail/*id +"_thumbnail.png"*/} ) {
|
||||
if (! res.empty()) {
|
||||
try
|
||||
{
|
||||
// for debug (wont pass check inside function)
|
||||
//std::string fake_url = "https://github.com/kocikdav/PrusaSlicer-settings/raw/master/resources/" + vp.id;
|
||||
get_missing_resource(vp.id, res, vendor.config_update_url, vendor_path, rsrc_path, cache_path);
|
||||
}
|
||||
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)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << vendor;
|
||||
const auto path_in_archive = cache_vendor_path / vendor;
|
||||
assert(boost::filesystem::exists(path_in_archive));
|
||||
auto vp = VendorProfile::from_ini(path_in_archive, true);
|
||||
for (const auto& model : vp.models) {
|
||||
if (!model.thumbnail.empty()) {
|
||||
try
|
||||
{
|
||||
// for debug (wont pass check inside function)
|
||||
//std::string fake_url = "https://github.com/kocikdav/PrusaSlicer-settings/raw/master/resources/" + vp.id;
|
||||
get_missing_resource(vp.id, model.thumbnail, vp.config_update_url, vendor_path, rsrc_path, cache_path);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to get " << model.thumbnail << " for " << vp.id << " " << model.id << ": " << e.what();
|
||||
}
|
||||
}
|
||||
if (cancel)
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Install indicies from resources. Only installs those that are either missing or older than in resources.
|
||||
|
@ -643,6 +715,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"));
|
||||
progress_dialog.Pulse();
|
||||
|
||||
for (const auto &update : updates.updates) {
|
||||
BOOST_LOG_TRIVIAL(info) << '\t' << update;
|
||||
|
||||
|
@ -681,32 +756,71 @@ bool PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons
|
|||
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); }
|
||||
|
||||
auto copy_missing_resource = [](const std::string& vendor, const std::string& filename,
|
||||
auto get_and_copy_missing_resource = [&self = std::as_const(*this)](const std::string& vendor, const std::string& filename,
|
||||
const fs::path& vendor_path, const fs::path& rsrc_path,
|
||||
const fs::path& cache_path)
|
||||
const fs::path& cache_path, const std::string& url)
|
||||
{
|
||||
if ( !fs::exists((vendor_path / (vendor + "/" + filename)))
|
||||
&& !fs::exists((rsrc_path / (vendor + "/" + filename)))) {
|
||||
if (filename.empty() || vendor.empty())
|
||||
return;
|
||||
|
||||
if (!fs::exists((cache_path / (vendor + "/" + filename)))) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Resources missing in cache directory: " << vendor << " / " << filename;
|
||||
return;
|
||||
}
|
||||
if (!fs::exists((vendor_path / vendor)))
|
||||
fs::create_directory((vendor_path / vendor));
|
||||
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));
|
||||
|
||||
copy_file_fix((cache_path / (vendor + "/" + filename)), (vendor_path / (vendor + "/" + filename)));
|
||||
if (fs::exists(file_in_vendor)) { // Already in vendor. No need to do anything.
|
||||
return;
|
||||
}
|
||||
if (fs::exists(file_in_rsrc)) { // In resources dir since installation. No need to do anything.
|
||||
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() == '/' ? "" : "/", filename); // vendor should already be in url
|
||||
|
||||
if (!fs::exists(file_in_vendor.parent_path()))
|
||||
fs::create_directory(file_in_vendor.parent_path());
|
||||
|
||||
self.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);
|
||||
};
|
||||
|
||||
// check if any resorces of installed bundle are missing. If so, new ones should be already downloaded at cache/vendor_id/
|
||||
auto vp = VendorProfile::from_ini(update.target, true);
|
||||
progress_dialog.Update(1, GUI::format_wxstr(_L("Downloading resources for %1%."),vp.id));
|
||||
progress_dialog.Pulse();
|
||||
for (const auto& model : vp.models) {
|
||||
copy_missing_resource(vp.id, model.bed_texture, vendor_path, rsrc_path, cache_path);
|
||||
copy_missing_resource(vp.id, model.bed_model, vendor_path, rsrc_path, cache_path);
|
||||
copy_missing_resource(vp.id, model.id + "_thumbnail.png", vendor_path, rsrc_path, cache_path);
|
||||
for (const std::string& resource : { model.bed_texture, model.bed_model, model.thumbnail }) {
|
||||
if (resource.empty())
|
||||
continue;
|
||||
try
|
||||
{
|
||||
// for debug (wont pass check inside function)
|
||||
//std::string fake_url = "https://github.com/kocikdav/PrusaSlicer-settings/raw/master/resources/" + vp.id;
|
||||
get_and_copy_missing_resource(vp.id, resource, vendor_path, rsrc_path, cache_path, 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;
|
||||
|
@ -752,6 +866,16 @@ void PresetUpdater::sync(const PresetBundle *preset_bundle)
|
|||
});
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -932,10 +1056,10 @@ bool PresetUpdater::install_bundles_rsrc_or_cache_vendor(std::vector<std::string
|
|||
|
||||
// find if in cache vendor is newer version than in resources
|
||||
if (is_in_cache_vendor) {
|
||||
auto vp_cache = VendorProfile::from_ini(path_in_cache_vendor, false);
|
||||
auto vp_rsrc = VendorProfile::from_ini(path_in_rsrc, false);
|
||||
auto version_cache = VendorProfile::from_ini(path_in_cache_vendor, false).config_version;
|
||||
auto version_rsrc = !is_in_rsrc ? Semver::zero() : VendorProfile::from_ini(path_in_rsrc, false).config_version;
|
||||
|
||||
if (! is_in_rsrc || vp_cache.config_version > vp_rsrc.config_version) {
|
||||
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
|
||||
auto path_idx_cache_vendor(path_in_cache_vendor);
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
|
||||
// If either version check or config updating is enabled, get the appropriate data in the background and cache it.
|
||||
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();
|
||||
|
|
Loading…
Reference in a new issue