mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 06:55:53 +08:00
Improve startup of ConfigWizard (SPE-2457)
This commit is contained in:
parent
1bd7be797a
commit
68f8925461
@ -139,3 +139,4 @@ src/slic3r/Utils/PresetUpdater.cpp
|
||||
src/slic3r/Utils/Process.cpp
|
||||
src/slic3r/Utils/PrusaConnect.cpp
|
||||
src/slic3r/Utils/Repetier.cpp
|
||||
src/slic3r/Utils/PresetUpdaterWrapper.cpp
|
||||
|
@ -127,7 +127,6 @@ public:
|
||||
TYPE_PHYSICAL_PRINTER,
|
||||
// This type is here to support search through the Preferences
|
||||
TYPE_PREFERENCES,
|
||||
TYPE_WEBVIEW,
|
||||
};
|
||||
|
||||
Type type = TYPE_INVALID;
|
||||
|
@ -356,6 +356,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/Bonjour.hpp
|
||||
Utils/PresetUpdater.cpp
|
||||
Utils/PresetUpdater.hpp
|
||||
Utils/PresetUpdaterWrapper.cpp
|
||||
Utils/PresetUpdaterWrapper.hpp
|
||||
Utils/Process.cpp
|
||||
Utils/Process.hpp
|
||||
Utils/RaycastManager.cpp
|
||||
|
@ -62,12 +62,10 @@
|
||||
#include "Field.hpp"
|
||||
#include "DesktopIntegrationDialog.hpp"
|
||||
#include "slic3r/Config/Snapshot.hpp"
|
||||
#include "slic3r/Utils/PresetUpdater.hpp"
|
||||
#include "format.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "UnsavedChangesDialog.hpp"
|
||||
#include "UpdatesUIManager.hpp"
|
||||
#include "PresetArchiveDatabase.hpp"
|
||||
#include "Plater.hpp" // #ysFIXME - implement getter for preset_archive_database from GetApp()???
|
||||
#include "slic3r/Utils/AppUpdater.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
@ -86,30 +84,9 @@
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
||||
using Config::Snapshot;
|
||||
using Config::SnapshotDB;
|
||||
|
||||
|
||||
|
||||
ConfigWizardLoadingDialog::ConfigWizardLoadingDialog(wxWindow* parent, const wxString& message)
|
||||
: wxDialog(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxFRAME_FLOAT_ON_PARENT)
|
||||
{
|
||||
auto* text = new wxStaticText(this, wxID_ANY, message, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);
|
||||
auto* vsizer = new wxBoxSizer(wxVERTICAL);
|
||||
auto *top_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
vsizer->Add(text, 1, wxEXPAND);
|
||||
top_sizer->Add(vsizer, 1, wxEXPAND | wxALL, 15);
|
||||
SetSizer(top_sizer);
|
||||
#ifdef _WIN32
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
#endif
|
||||
Fit();
|
||||
}
|
||||
|
||||
|
||||
// Configuration data structures extensions needed for the wizard
|
||||
|
||||
bool Bundle::load(fs::path source_path, BundleLocation location, bool ais_prusa_bundle)
|
||||
{
|
||||
this->preset_bundle = std::make_unique<PresetBundle>();
|
||||
@ -138,6 +115,7 @@ bool Bundle::load(fs::path source_path, BundleLocation location, bool ais_prusa_
|
||||
return true;
|
||||
}
|
||||
|
||||
// Configuration data structures extensions needed for the wizard
|
||||
Bundle::Bundle(Bundle &&other)
|
||||
: preset_bundle(std::move(other.preset_bundle))
|
||||
, vendor_profile(other.vendor_profile)
|
||||
@ -151,7 +129,7 @@ BundleMap BundleMap::load()
|
||||
{
|
||||
BundleMap res;
|
||||
|
||||
const PresetArchiveDatabase* pad = wxGetApp().plater()->get_preset_archive_database();
|
||||
const Slic3r::PresetUpdaterWrapper* preset_updater_wrapper = wxGetApp().get_preset_updater_wrapper();
|
||||
const auto vendor_dir = (boost::filesystem::path(Slic3r::data_dir()) / "vendor").make_preferred();
|
||||
const auto archive_dir = (boost::filesystem::path(Slic3r::data_dir()) / "cache" / "vendor").make_preferred();
|
||||
const auto rsrc_vendor_dir = (boost::filesystem::path(resources_dir()) / "profiles").make_preferred();
|
||||
@ -228,7 +206,7 @@ BundleMap BundleMap::load()
|
||||
BOOST_LOG_TRIVIAL(error) << format("Could not load bundle %1% due to corrupted profile file %2%. Message: %3%", id, dir_entry.path().string(), e.what());
|
||||
continue;
|
||||
}
|
||||
if (vp.repo_id.empty() || !pad->is_selected_repository_by_id(vp.repo_id)) {
|
||||
if (vp.repo_id.empty() || !preset_updater_wrapper->is_selected_repository_by_id(vp.repo_id)) {
|
||||
continue;
|
||||
}
|
||||
// Don't load
|
||||
@ -655,7 +633,7 @@ PageUpdateManager::PageUpdateManager(ConfigWizard* parent_in)
|
||||
|
||||
const int em = em_unit(this);
|
||||
|
||||
manager = std::make_unique<RepositoryUpdateUIManager>(this, wxGetApp().plater()->get_preset_archive_database(), em);
|
||||
manager = std::make_unique<RepositoryUpdateUIManager>(this, wxGetApp().get_preset_updater_wrapper(), em);
|
||||
|
||||
warning_text = new wxStaticText(this, wxID_ANY, _L("WARNING: Select at least one source."));
|
||||
warning_text->SetFont(wxGetApp().bold_font());
|
||||
@ -3327,7 +3305,7 @@ static std::string get_first_added_preset(const std::map<std::string, std::strin
|
||||
return *diff.begin();
|
||||
}
|
||||
|
||||
bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater, bool& apply_keeped_changes)
|
||||
bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdaterWrapper *updater, bool& apply_keeped_changes)
|
||||
{
|
||||
wxString header, caption = _L("Configuration is edited in ConfigWizard");
|
||||
const auto enabled_vendors = appconfig_new.vendors();
|
||||
@ -3461,9 +3439,7 @@ 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.
|
||||
GUI_App& app = wxGetApp();
|
||||
const auto* archive_db = app.plater()->get_preset_archive_database();
|
||||
bool install_result = updater->install_bundles_rsrc_or_cache_vendor(std::move(install_bundles), archive_db->get_selected_archive_repositories(), false);
|
||||
bool install_result = updater->install_bundles_rsrc_or_cache_vendor(std::move(install_bundles), false);
|
||||
if (!install_result)
|
||||
return false;
|
||||
} else {
|
||||
@ -3594,7 +3570,7 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
||||
used_repo_ids.emplace_back(repo_id);
|
||||
}
|
||||
}
|
||||
wxGetApp().plater()->get_preset_archive_database()->set_installed_printer_repositories(std::move(used_repo_ids));
|
||||
wxGetApp().get_preset_updater_wrapper()->set_installed_printer_repositories(std::move(used_repo_ids));
|
||||
|
||||
// apply materials in app_config
|
||||
for (const std::string& section_name : {AppConfig::SECTION_FILAMENTS, AppConfig::SECTION_MATERIALS})
|
||||
@ -3705,17 +3681,8 @@ bool ConfigWizard::priv::check_sla_selected()
|
||||
void ConfigWizard::priv::set_config_updated_from_archive(bool load_installed_printers, bool run_preset_updater)
|
||||
{
|
||||
if (run_preset_updater) {
|
||||
// This block of preset_updater functions is done in GUI_App::run_wizard before ConfigWizard::run()
|
||||
// It needs to be also done when repos are confirmed inside wizard.
|
||||
// Possible optimalization - do not run this block if no repos were changed.
|
||||
GUI_App& app = wxGetApp();
|
||||
// Do blocking sync on every change of archive repos, so user is always offered recent profiles.
|
||||
const SharedArchiveRepositoryVector &repos = app.plater()->get_preset_archive_database()->get_selected_archive_repositories();
|
||||
app.preset_updater->sync_blocking(app.preset_bundle, &app, repos);
|
||||
// Offer update installation. It used to be offered only when wizard run reason was RR_USER.
|
||||
app.preset_updater->update_index_db();
|
||||
app.preset_updater->config_update(app.app_config->orig_version(), PresetUpdater::UpdateParams::SHOW_TEXT_BOX, repos);
|
||||
|
||||
// TRN: Progress dialog title
|
||||
wxGetApp().get_preset_updater_wrapper()->wizard_sync(wxGetApp().preset_bundle, wxGetApp().app_config->orig_version(), q, true, _L("Updating Configuration sources"));
|
||||
// We have now probably changed data. We need to rebuild database from which wizards constructs.
|
||||
// Just reload bundles and upadte installed printer from appconfig_new.
|
||||
bundles = BundleMap::load();
|
||||
@ -3751,8 +3718,7 @@ bool ConfigWizard::priv::any_installed_vendor_for_repo(const std::string& repo_i
|
||||
|
||||
static bool to_delete(PagePrinters* page, const std::set<std::string>& selected_uuids)
|
||||
{
|
||||
const PresetArchiveDatabase* pad = wxGetApp().plater()->get_preset_archive_database();
|
||||
const SharedArchiveRepositoryVector& archs = pad->get_all_archive_repositories();
|
||||
const SharedArchiveRepositoryVector& archs = wxGetApp().get_preset_updater_wrapper()->get_all_archive_repositories();
|
||||
|
||||
bool unselect_all = true;
|
||||
|
||||
@ -3768,14 +3734,14 @@ static bool to_delete(PagePrinters* page, const std::set<std::string>& selected_
|
||||
|
||||
static void unselect(PagePrinters* page)
|
||||
{
|
||||
const PresetArchiveDatabase* pad = wxGetApp().plater()->get_preset_archive_database();
|
||||
const SharedArchiveRepositoryVector& archs = pad->get_all_archive_repositories();
|
||||
const Slic3r::PresetUpdaterWrapper* puw = wxGetApp().get_preset_updater_wrapper();
|
||||
const SharedArchiveRepositoryVector& archs = puw->get_all_archive_repositories();
|
||||
|
||||
bool unselect_all = true;
|
||||
|
||||
for (const auto* archive : archs) {
|
||||
if (page->get_vendor_repo_id() == archive->get_manifest().id) {
|
||||
if (pad->is_selected_repository_by_uuid(archive->get_uuid()))
|
||||
if (puw->is_selected_repository_by_uuid(archive->get_uuid()))
|
||||
unselect_all = false;
|
||||
//break; ! don't break here, because there can be several archives with same repo_id
|
||||
}
|
||||
@ -3866,16 +3832,16 @@ void ConfigWizard::priv::load_pages_from_archive()
|
||||
|
||||
// fill vendors and printers pages from Update manager
|
||||
|
||||
auto pad = wxGetApp().plater()->get_preset_archive_database();
|
||||
const auto* puw = wxGetApp().get_preset_updater_wrapper();
|
||||
|
||||
const SharedArchiveRepositoryVector& archs = pad->get_all_archive_repositories();
|
||||
const SharedArchiveRepositoryVector& archs = puw->get_all_archive_repositories();
|
||||
|
||||
only_sla_mode = true;
|
||||
bool is_primary_printer_page_set = false;
|
||||
|
||||
for (const auto* archive : archs) {
|
||||
const auto& data = archive->get_manifest();
|
||||
const bool is_selected_arch = pad->is_selected_repository_by_uuid(archive->get_uuid());
|
||||
const bool is_selected_arch = puw->is_selected_repository_by_uuid(archive->get_uuid());
|
||||
|
||||
std::vector<const VendorProfile*> vendors;
|
||||
const bool any_installed_vendor = any_installed_vendor_for_repo(data.id, vendors);
|
||||
@ -4148,7 +4114,7 @@ bool ConfigWizard::run(RunReason reason, StartPage start_page)
|
||||
|
||||
if (ShowModal() == wxID_OK) {
|
||||
bool apply_keeped_changes = false;
|
||||
if (! p->apply_config(app.app_config, app.preset_bundle, app.preset_updater, apply_keeped_changes))
|
||||
if (! p->apply_config(app.app_config, app.preset_bundle, app.get_preset_updater_wrapper(), apply_keeped_changes))
|
||||
return false;
|
||||
|
||||
if (apply_keeped_changes)
|
||||
@ -4169,7 +4135,8 @@ void ConfigWizard::update_login()
|
||||
{
|
||||
if (p->page_login && p->page_login->login_changed()) {
|
||||
// repos changed - we need rebuild
|
||||
wxGetApp().plater()->get_preset_archive_database()->sync_blocking();
|
||||
// TRN: Progress dialog title
|
||||
wxGetApp().get_preset_updater_wrapper()->wizard_sync(wxGetApp().preset_bundle, wxGetApp().app_config->orig_version(), this, false, _L("Updating Configuration sources"));
|
||||
// now change PageUpdateManager
|
||||
p->page_update_manager->manager->update();
|
||||
}
|
||||
|
@ -22,15 +22,11 @@ namespace Slic3r {
|
||||
|
||||
class PresetBundle;
|
||||
class PresetUpdater;
|
||||
class AppConfig;
|
||||
class PresetArchiveDatabase;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class ConfigWizardLoadingDialog : public wxDialog
|
||||
{
|
||||
public:
|
||||
ConfigWizardLoadingDialog(wxWindow* parent, const wxString& message);
|
||||
};
|
||||
|
||||
namespace DownloaderUtils {
|
||||
class Worker : public wxBoxSizer
|
||||
{
|
||||
@ -102,8 +98,6 @@ private:
|
||||
friend struct ConfigWizardPage;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,9 +132,9 @@ void ConfigWizardWebViewPage::on_navigation_request(wxWebViewEvent &evt)
|
||||
evt.Veto();
|
||||
m_vetoed = true;
|
||||
wxPostEvent(wxGetApp().plater(), Event<std::string>(EVT_LOGIN_VIA_WIZARD, into_u8(url)));
|
||||
} else if (url.Find("accounts.google.com") != wxString::npos
|
||||
|| url.Find("appleid.apple.com") != wxString::npos
|
||||
|| url.Find("facebook.com") != wxString::npos)
|
||||
} else if (url.Find("accounts.google.com") != wxNOT_FOUND
|
||||
|| url.Find("appleid.apple.com") != wxNOT_FOUND
|
||||
|| url.Find("facebook.com") != wxNOT_FOUND)
|
||||
{
|
||||
auto& sc = Utils::ServiceConfig::instance();
|
||||
if (!m_evt_sent && !url.starts_with(GUI::from_u8(sc.account_url()))) {
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "slic3r/Utils/PresetUpdater.hpp"
|
||||
#include "slic3r/Utils/PresetUpdaterWrapper.hpp"
|
||||
#include "BedShapeDialog.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "SavePresetDialog.hpp"
|
||||
@ -702,7 +702,7 @@ struct ConfigWizard::priv
|
||||
bool can_select_all();
|
||||
bool on_bnt_finish();
|
||||
bool check_and_install_missing_materials(Technology technology, const std::string &only_for_model_id = std::string());
|
||||
bool apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdater *updater, bool& apply_keeped_changes);
|
||||
bool apply_config(AppConfig *app_config, PresetBundle *preset_bundle, const PresetUpdaterWrapper *updater, bool& apply_keeped_changes);
|
||||
// #ys_FIXME_alise
|
||||
void update_presets_in_config(const std::string& section, const std::string& alias_key, bool add);
|
||||
//#ifdef __linux__
|
||||
|
@ -75,6 +75,7 @@
|
||||
#include "GLCanvas3D.hpp"
|
||||
|
||||
#include "../Utils/PresetUpdater.hpp"
|
||||
#include "../Utils/PresetUpdaterWrapper.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
#include "../Utils/Process.hpp"
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
@ -847,17 +848,11 @@ void GUI_App::post_init()
|
||||
// to popup a modal dialog on start without screwing combo boxes.
|
||||
// This is ugly but I honestly found no better way to do it.
|
||||
// Neither wxShowEvent nor wxWindowCreateEvent work reliably.
|
||||
if (this->preset_updater) { // G-Code Viewer does not initialize preset_updater.
|
||||
|
||||
#if 0 // This code was moved to EVT_CONFIG_UPDATER_SYNC_DONE bind - after preset_updater finishes synchronization.
|
||||
if (! this->check_updates(false))
|
||||
// Configuration is not compatible and reconfigure was refused by the user. Application is closing.
|
||||
return;
|
||||
#endif
|
||||
if (this->get_preset_updater_wrapper()) { // G-Code Viewer does not initialize preset_updater.
|
||||
CallAfter([this] {
|
||||
// preset_updater->sync downloads profile updates and than via event checks updates and incompatible presets. We need to run it on startup.
|
||||
// start before cw so it is canceled by cw if needed?
|
||||
this->preset_updater->sync(preset_bundle, this, plater()->get_preset_archive_database()->get_selected_archive_repositories());
|
||||
this->get_preset_updater_wrapper()->sync_preset_updater(this, preset_bundle);
|
||||
bool cw_showed = this->config_wizard_startup();
|
||||
if (! cw_showed) {
|
||||
// The CallAfter is needed as well, without it, GL extensions did not show.
|
||||
@ -900,7 +895,6 @@ GUI_App::~GUI_App()
|
||||
{
|
||||
delete app_config;
|
||||
delete preset_bundle;
|
||||
delete preset_updater;
|
||||
}
|
||||
|
||||
// If formatted for github, plaintext with OpenGL extensions enclosed into <details>.
|
||||
@ -1435,7 +1429,7 @@ bool GUI_App::on_init_inner()
|
||||
associate_stl_files();
|
||||
#endif // __WXMSW__
|
||||
|
||||
preset_updater = new PresetUpdater();
|
||||
m_preset_updater_wrapper = std::make_unique<PresetUpdaterWrapper>();
|
||||
Bind(EVT_SLIC3R_VERSION_ONLINE, &GUI_App::on_version_read, this);
|
||||
Bind(EVT_SLIC3R_EXPERIMENTAL_VERSION_ONLINE, [this](const wxCommandEvent& evt) {
|
||||
if (this->plater_ != nullptr && (m_app_updater->get_triggered_by_user() || app_config->get("notify_release") == "all")) {
|
||||
@ -3279,48 +3273,16 @@ bool GUI_App::run_wizard(ConfigWizard::RunReason reason, ConfigWizard::StartPage
|
||||
{
|
||||
wxCHECK_MSG(mainframe != nullptr, false, "Internal error: Main frame not created / null");
|
||||
|
||||
// Cancel sync before starting wizard to prevent two downloads at same time.
|
||||
preset_updater->cancel_sync();
|
||||
// Show login dialog before wizard.
|
||||
#if 0
|
||||
bool user_was_logged = plater()->get_user_account()->is_logged();
|
||||
if (!user_was_logged) {
|
||||
m_login_dialog = std::make_unique<LoginDialog>(mainframe, plater()->get_user_account());
|
||||
m_login_dialog->ShowModal();
|
||||
mainframe->RemoveChild(m_login_dialog.get());
|
||||
m_login_dialog->Destroy();
|
||||
// Destructor does not call Destroy.
|
||||
m_login_dialog.reset();
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
// ConfigWizard can take some time to start. Because it is a wxWidgets window, it has to be done
|
||||
// in UI thread, so displaying a nice modal dialog and letting the CW start in a worker thread
|
||||
// is not an option. Let's at least show a modeless dialog before the UI thread freezes.
|
||||
// TRN: Text showing while the ConfigWizard is loading, so the user knows something is happening.
|
||||
auto cw_loading_dlg = new ConfigWizardLoadingDialog(mainframe, _L("Loading Configuration Wizard..."));
|
||||
cw_loading_dlg->CenterOnParent();
|
||||
cw_loading_dlg->Show();
|
||||
wxYield();
|
||||
|
||||
// We have to update repos
|
||||
plater()->get_preset_archive_database()->sync_blocking();
|
||||
|
||||
if (reason == ConfigWizard::RunReason::RR_USER) {
|
||||
// Since there might be new repos, we need to sync preset updater
|
||||
const SharedArchiveRepositoryVector &repos = plater()->get_preset_archive_database()->get_selected_archive_repositories();
|
||||
preset_updater->sync_blocking(preset_bundle, this, repos);
|
||||
preset_updater->update_index_db();
|
||||
// Offer update installation.
|
||||
preset_updater->config_update(app_config->orig_version(), PresetUpdater::UpdateParams::SHOW_TEXT_BOX, repos);
|
||||
}
|
||||
|
||||
// Loading of Config Wizard takes some time.
|
||||
// First part is to download neccessary data.
|
||||
// That is done on worker thread while nice modal progress is shown.
|
||||
// TRN: Progress dialog title
|
||||
get_preset_updater_wrapper()->wizard_sync(preset_bundle, app_config->orig_version(), mainframe, reason == ConfigWizard::RunReason::RR_USER, _L("Opening Configuration Wizard"));
|
||||
// Then the wizard itself will start and that also takes time.
|
||||
// But for now no ui is shown until then. (Showing modal progress dialog while showing another would be a headacke)
|
||||
m_config_wizard = new ConfigWizard(mainframe);
|
||||
cw_loading_dlg->Close();
|
||||
|
||||
const bool res = m_config_wizard->run(reason, start_page);
|
||||
|
||||
|
||||
// !!! Deallocate memory after close ConfigWizard.
|
||||
// Note, that mainframe is a parent of ConfigWizard.
|
||||
// So, wizard will be destroyed only during destroying of mainframe
|
||||
@ -3541,28 +3503,13 @@ bool GUI_App::config_wizard_startup()
|
||||
|
||||
bool GUI_App::check_updates(const bool invoked_by_user)
|
||||
{
|
||||
if (invoked_by_user) {
|
||||
// do preset_updater sync so if user runs slicer for a long time, check for updates actually delivers updates.
|
||||
// for preset_updater sync we need to sync archive database first
|
||||
plater()->get_preset_archive_database()->sync_blocking();
|
||||
// Now re-extract offline repos
|
||||
std::string failed_paths;
|
||||
if (!plater()->get_preset_archive_database()->extract_archives_with_check(failed_paths)) {
|
||||
int cnt = std::count(failed_paths.begin(), failed_paths.end(), '\n') + 1;
|
||||
// TRN: %1% contains paths from which loading failed. They are separated by \n, there is no \n at the end.
|
||||
failed_paths = GUI::format(_L_PLURAL("It was not possible to extract data from %1%. The source will not be updated.",
|
||||
"It was not possible to extract data for following local sources. They will not be updated.\n\n %1%", cnt), failed_paths);
|
||||
show_error(nullptr, failed_paths);
|
||||
}
|
||||
// then its time for preset_updater sync
|
||||
preset_updater->sync_blocking(preset_bundle, this, plater()->get_preset_archive_database()->get_selected_archive_repositories());
|
||||
// and then we check updates
|
||||
}
|
||||
|
||||
PresetUpdater::UpdateResult updater_result;
|
||||
try {
|
||||
preset_updater->update_index_db();
|
||||
updater_result = preset_updater->config_update(app_config->orig_version(), invoked_by_user ? PresetUpdater::UpdateParams::SHOW_TEXT_BOX : PresetUpdater::UpdateParams::SHOW_NOTIFICATION, plater()->get_preset_archive_database()->get_selected_archive_repositories());
|
||||
if (invoked_by_user)
|
||||
{
|
||||
updater_result = get_preset_updater_wrapper()->check_updates_on_user_request(preset_bundle, app_config->orig_version(), mainframe);
|
||||
} else {
|
||||
updater_result = get_preset_updater_wrapper()->check_updates_on_startup( app_config->orig_version());
|
||||
}
|
||||
if (updater_result == PresetUpdater::R_INCOMPAT_EXIT) {
|
||||
mainframe->Close();
|
||||
// Applicaiton is closing.
|
||||
@ -3575,10 +3522,6 @@ bool GUI_App::check_updates(const bool invoked_by_user)
|
||||
MsgNoUpdates dlg;
|
||||
dlg.ShowModal();
|
||||
}
|
||||
}
|
||||
catch (const std::exception & ex) {
|
||||
show_error(nullptr, ex.what());
|
||||
}
|
||||
// Applicaiton will continue.
|
||||
return true;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ namespace Slic3r {
|
||||
|
||||
class AppConfig;
|
||||
class PresetBundle;
|
||||
class PresetUpdater;
|
||||
class PresetUpdaterWrapper;
|
||||
class ModelObject;
|
||||
class PrintHostJobQueue;
|
||||
class Model;
|
||||
@ -357,11 +357,9 @@ public:
|
||||
|
||||
AppConfig* app_config{ nullptr };
|
||||
PresetBundle* preset_bundle{ nullptr };
|
||||
PresetUpdater* preset_updater{ nullptr };
|
||||
MainFrame* mainframe{ nullptr };
|
||||
Plater* plater_{ nullptr };
|
||||
|
||||
PresetUpdater* get_preset_updater() { return preset_updater; }
|
||||
PresetUpdaterWrapper* get_preset_updater_wrapper() { return m_preset_updater_wrapper.get(); }
|
||||
|
||||
wxBookCtrlBase* tab_panel() const ;
|
||||
int extruders_cnt() const;
|
||||
@ -468,7 +466,7 @@ private:
|
||||
std::map< ConfigMenuIDs, wxMenuItem*> m_config_menu_updatable_items;
|
||||
|
||||
ConfigWizard* m_config_wizard {nullptr};
|
||||
|
||||
std::unique_ptr<PresetUpdaterWrapper> m_preset_updater_wrapper;
|
||||
};
|
||||
|
||||
DECLARE_APP(GUI_App)
|
||||
|
@ -111,6 +111,7 @@
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "../Utils/PresetUpdater.hpp"
|
||||
#include "../Utils/PresetUpdaterWrapper.hpp"
|
||||
#include "../Utils/Process.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "InstanceCheck.hpp"
|
||||
@ -272,7 +273,6 @@ struct Plater::priv
|
||||
Preview *preview;
|
||||
std::unique_ptr<NotificationManager> notification_manager;
|
||||
std::unique_ptr<UserAccount> user_account;
|
||||
std::unique_ptr<PresetArchiveDatabase> preset_archive_database;
|
||||
// Login dialog needs to be kept somewhere.
|
||||
// It is created inside evt Bind. But it might be closed from another event.
|
||||
LoginWebViewDialog* login_dialog { nullptr };
|
||||
@ -625,7 +625,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
, sidebar(new Sidebar(q))
|
||||
, notification_manager(std::make_unique<NotificationManager>(q))
|
||||
, user_account(std::make_unique<UserAccount>(q, wxGetApp().app_config, wxGetApp().get_instance_hash_string()))
|
||||
, preset_archive_database(std::make_unique<PresetArchiveDatabase>(wxGetApp().app_config, q))
|
||||
, m_worker{q, std::make_unique<NotificationProgressIndicator>(notification_manager.get()), "ui_worker"}
|
||||
, m_sla_import_dlg{new SLAImportDialog{q}}
|
||||
, delayed_scene_refresh(false)
|
||||
@ -791,7 +790,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
this->q->Bind(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, [this](ExportGcodeNotificationClickedEvent&) { this->q->export_gcode(true); });
|
||||
this->q->Bind(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, [](PresetUpdateAvailableClickedEvent&) {
|
||||
GUI_App &app = wxGetApp();
|
||||
app.get_preset_updater()->on_update_notification_confirm(app.plater()->get_preset_archive_database()->get_selected_archive_repositories());
|
||||
app.get_preset_updater_wrapper()->on_update_notification_confirm();
|
||||
});
|
||||
this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this, q](RemovableDriveEjectEvent &evt) {
|
||||
if (evt.data.second) {
|
||||
@ -903,11 +902,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
#endif // SLIC3R_DESKTOP_INTEGRATION
|
||||
#endif // __linux__
|
||||
std::string service;
|
||||
if (evt.GetString().Find(L"accounts.google.com") != wxString::npos) {
|
||||
if (evt.GetString().Find(L"accounts.google.com") != wxNOT_FOUND) {
|
||||
service = "google";
|
||||
} else if (evt.GetString().Find(L"appleid.apple.com") != wxString::npos) {
|
||||
} else if (evt.GetString().Find(L"appleid.apple.com") != wxNOT_FOUND) {
|
||||
service = "apple";
|
||||
} else if (evt.GetString().Find(L"facebook.com") != wxString::npos) {
|
||||
} else if (evt.GetString().Find(L"facebook.com") != wxNOT_FOUND) {
|
||||
service = "facebook";
|
||||
}
|
||||
wxString url = user_account->get_login_redirect_url(service);
|
||||
@ -6996,16 +6995,6 @@ const NotificationManager * Plater::get_notification_manager() const
|
||||
return p->notification_manager.get();
|
||||
}
|
||||
|
||||
PresetArchiveDatabase* Plater::get_preset_archive_database()
|
||||
{
|
||||
return p->preset_archive_database.get();
|
||||
}
|
||||
|
||||
const PresetArchiveDatabase* Plater::get_preset_archive_database() const
|
||||
{
|
||||
return p->preset_archive_database.get();
|
||||
}
|
||||
|
||||
UserAccount* Plater::get_user_account()
|
||||
{
|
||||
return p->user_account.get();
|
||||
|
@ -360,9 +360,6 @@ public:
|
||||
NotificationManager* get_notification_manager();
|
||||
const NotificationManager* get_notification_manager() const;
|
||||
|
||||
PresetArchiveDatabase* get_preset_archive_database();
|
||||
const PresetArchiveDatabase* get_preset_archive_database() const;
|
||||
|
||||
UserAccount* get_user_account();
|
||||
const UserAccount* get_user_account() const;
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/UserAccount.hpp"
|
||||
#include "slic3r/Utils/PresetUpdaterWrapper.hpp"
|
||||
#include "slic3r/GUI/Field.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "libslic3r/AppConfig.hpp"
|
||||
#include "libslic3r/miniz_extension.hpp"
|
||||
@ -25,7 +27,6 @@
|
||||
namespace pt = boost::property_tree;
|
||||
namespace fs = boost::filesystem;
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
static const char* TMP_EXTENSION = ".download";
|
||||
|
||||
@ -191,7 +192,7 @@ void add_authorization_header(Http& http)
|
||||
|
||||
}
|
||||
|
||||
bool OnlineArchiveRepository::get_file_inner(const std::string& url, const fs::path& target_path) const
|
||||
bool OnlineArchiveRepository::get_file_inner(const std::string& url, const fs::path& target_path, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
|
||||
bool res = false;
|
||||
@ -210,10 +211,9 @@ bool OnlineArchiveRepository::get_file_inner(const std::string& url, const fs::p
|
||||
//if (cancel) { cancel = true; }
|
||||
})
|
||||
.on_error([&](std::string body, std::string error, unsigned http_status) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Error getting: `%1%`: HTTP %2%, %3%",
|
||||
url,
|
||||
http_status,
|
||||
body);
|
||||
BOOST_LOG_TRIVIAL(error) << format("Error getting: `%1%`: HTTP %2%, %3%", url, http_status, body);
|
||||
ui_status->set_error(error);
|
||||
res = false;
|
||||
})
|
||||
.on_complete([&](std::string body, unsigned /* http_status */) {
|
||||
if (body.empty()) {
|
||||
@ -225,30 +225,38 @@ bool OnlineArchiveRepository::get_file_inner(const std::string& url, const fs::p
|
||||
fs::rename(tmp_path, target_path);
|
||||
res = true;
|
||||
})
|
||||
.perform_sync();
|
||||
.on_retry([&](int attempt, unsigned delay) {
|
||||
return !ui_status->on_attempt(attempt, delay);
|
||||
})
|
||||
.perform_sync(ui_status->get_retry_policy());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool OnlineArchiveRepository::get_archive(const fs::path& target_path) const
|
||||
bool OnlineArchiveRepository::get_archive(const fs::path& target_path, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
return get_file_inner(m_data.index_url.empty() ? m_data.url + "vendor_indices.zip" : m_data.index_url, target_path);
|
||||
return get_file_inner(m_data.index_url.empty() ? m_data.url + "vendor_indices.zip" : m_data.index_url, target_path, ui_status);
|
||||
}
|
||||
|
||||
bool OnlineArchiveRepository::get_file(const std::string& source_subpath, const fs::path& target_path, const std::string& repository_id) const
|
||||
bool OnlineArchiveRepository::get_file(const std::string& source_subpath, const fs::path& target_path, const std::string& repository_id, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
if (repository_id != m_data.id) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error getting file " << source_subpath << ". The repository_id was not matching.";
|
||||
return false;
|
||||
}
|
||||
|
||||
ui_status->set_target(target_path.filename().string());
|
||||
|
||||
const std::string escaped_source_subpath = escape_path_by_element(source_subpath);
|
||||
return get_file_inner(m_data.url + escaped_source_subpath, target_path);
|
||||
return get_file_inner(m_data.url + escaped_source_subpath, target_path, ui_status);
|
||||
}
|
||||
|
||||
bool OnlineArchiveRepository::get_ini_no_id(const std::string& source_subpath, const fs::path& target_path) const
|
||||
bool OnlineArchiveRepository::get_ini_no_id(const std::string& source_subpath, const fs::path& target_path, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
ui_status->set_target(target_path.filename().string());
|
||||
|
||||
const std::string escaped_source_subpath = escape_path_by_element(source_subpath);
|
||||
return get_file_inner(m_data.url + escaped_source_subpath, target_path);
|
||||
return get_file_inner(m_data.url + escaped_source_subpath, target_path, ui_status);
|
||||
}
|
||||
|
||||
bool LocalArchiveRepository::get_file_inner(const fs::path& source_path, const fs::path& target_path) const
|
||||
@ -277,7 +285,7 @@ bool LocalArchiveRepository::get_file_inner(const fs::path& source_path, const f
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LocalArchiveRepository::get_file(const std::string& source_subpath, const fs::path& target_path, const std::string& repository_id) const
|
||||
bool LocalArchiveRepository::get_file(const std::string& source_subpath, const fs::path& target_path, const std::string& repository_id, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
if (repository_id != m_data.id) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error getting file " << source_subpath << ". The repository_id was not matching.";
|
||||
@ -285,11 +293,11 @@ bool LocalArchiveRepository::get_file(const std::string& source_subpath, const f
|
||||
}
|
||||
return get_file_inner(m_data.tmp_path / source_subpath, target_path);
|
||||
}
|
||||
bool LocalArchiveRepository::get_ini_no_id(const std::string& source_subpath, const fs::path& target_path) const
|
||||
bool LocalArchiveRepository::get_ini_no_id(const std::string& source_subpath, const fs::path& target_path, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
return get_file_inner(m_data.tmp_path / source_subpath, target_path);
|
||||
}
|
||||
bool LocalArchiveRepository::get_archive(const fs::path& target_path) const
|
||||
bool LocalArchiveRepository::get_archive(const fs::path& target_path, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
fs::path source_path = fs::path(m_data.tmp_path) / "vendor_indices.zip";
|
||||
return get_file_inner(std::move(source_path), target_path);
|
||||
@ -306,9 +314,8 @@ void LocalArchiveRepository::do_extract()
|
||||
|
||||
//-------------------------------------PresetArchiveDatabase-------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
PresetArchiveDatabase::PresetArchiveDatabase(AppConfig* app_config, wxEvtHandler* evt_handler)
|
||||
PresetArchiveDatabase::PresetArchiveDatabase()
|
||||
{
|
||||
//
|
||||
boost::system::error_code ec;
|
||||
m_unq_tmp_path = fs::temp_directory_path() / fs::unique_path();
|
||||
fs::create_directories(m_unq_tmp_path, ec);
|
||||
@ -362,7 +369,8 @@ bool PresetArchiveDatabase::set_selected_repositories(const std::vector<std::str
|
||||
bool PresetArchiveDatabase::extract_archives_with_check(std::string &msg)
|
||||
{
|
||||
extract_local_archives();
|
||||
for (const std::pair<const std::string, bool>& pair : m_selected_repositories_uuid) {
|
||||
// std::map<std::string, bool> m_selected_repositories_uuid
|
||||
for (const auto& pair : m_selected_repositories_uuid) {
|
||||
if (!pair.second) {
|
||||
continue;
|
||||
}
|
||||
@ -868,7 +876,7 @@ std::string PresetArchiveDatabase::get_next_uuid()
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool sync_inner(std::string& manifest)
|
||||
bool sync_inner(std::string& manifest, PresetUpdaterUIStatus* ui_status)
|
||||
{
|
||||
bool ret = false;
|
||||
std::string url = Utils::ServiceConfig::instance().preset_repo_repos_url();
|
||||
@ -878,23 +886,33 @@ bool sync_inner(std::string& manifest)
|
||||
.timeout_max(30)
|
||||
.on_error([&](std::string body, std::string error, unsigned http_status) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to get online archive source manifests: "<< body << " ; " << error << " ; " << http_status;
|
||||
ui_status->set_error(error);
|
||||
ret = false;
|
||||
})
|
||||
.on_complete([&](std::string body, unsigned /* http_status */) {
|
||||
manifest = body;
|
||||
ret = true;
|
||||
})
|
||||
.perform_sync();
|
||||
.on_retry([&](int attempt, unsigned delay) {
|
||||
return !ui_status->on_attempt(attempt, delay);
|
||||
})
|
||||
.perform_sync(ui_status->get_retry_policy());
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void PresetArchiveDatabase::sync_blocking()
|
||||
bool PresetArchiveDatabase::sync_blocking(PresetUpdaterUIStatus* ui_status)
|
||||
{
|
||||
assert(ui_status);
|
||||
std::string manifest;
|
||||
if (!sync_inner(manifest))
|
||||
return;
|
||||
bool sync_res = false;
|
||||
ui_status->set_target("Archive Database Mainfest");
|
||||
sync_res = sync_inner(manifest, ui_status);
|
||||
if (!sync_res) {
|
||||
return false;
|
||||
}
|
||||
read_server_manifest(std::move(manifest));
|
||||
return true;
|
||||
}
|
||||
|
||||
}} // Slic3r::GUI
|
||||
} // Slic3r
|
@ -13,7 +13,8 @@
|
||||
|
||||
namespace Slic3r {
|
||||
class AppConfig;
|
||||
namespace GUI {
|
||||
|
||||
class PresetUpdaterUIStatus;
|
||||
|
||||
struct ArchiveRepositoryGetFileArgs {
|
||||
boost::filesystem::path target_path;
|
||||
@ -75,12 +76,12 @@ public:
|
||||
{}
|
||||
virtual ~ArchiveRepository() {}
|
||||
// Gets vendor_indices.zip to target_path
|
||||
virtual bool get_archive(const boost::filesystem::path& target_path) const = 0;
|
||||
virtual bool get_archive(const boost::filesystem::path& target_path, PresetUpdaterUIStatus* ui_status) const = 0;
|
||||
// Gets file if repository_id arg matches m_id.
|
||||
// Should be used to get the most recent ini file and every missing resource.
|
||||
virtual bool get_file(const std::string& source_subpath, const boost::filesystem::path& target_path, const std::string& repository_id) const = 0;
|
||||
virtual bool get_file(const std::string& source_subpath, const boost::filesystem::path& target_path, const std::string& repository_id, PresetUpdaterUIStatus* ui_status) const = 0;
|
||||
// Gets file without id check - for not yet encountered vendors only!
|
||||
virtual bool get_ini_no_id(const std::string& source_subpath, const boost::filesystem::path& target_path) const = 0;
|
||||
virtual bool get_ini_no_id(const std::string& source_subpath, const boost::filesystem::path& target_path, PresetUpdaterUIStatus* ui_status) const = 0;
|
||||
const RepositoryManifest& get_manifest() const { return m_data; }
|
||||
std::string get_uuid() const { return m_uuid; }
|
||||
// Only local archvies can return false
|
||||
@ -103,15 +104,15 @@ public:
|
||||
}
|
||||
}
|
||||
// Gets vendor_indices.zip to target_path.
|
||||
bool get_archive(const boost::filesystem::path& target_path) const override;
|
||||
bool get_archive(const boost::filesystem::path& target_path, PresetUpdaterUIStatus* ui_status) const override;
|
||||
// Gets file if repository_id arg matches m_id.
|
||||
// Should be used to get the most recent ini file and every missing resource.
|
||||
bool get_file(const std::string& source_subpath, const boost::filesystem::path& target_path, const std::string& repository_id) const override;
|
||||
bool get_file(const std::string& source_subpath, const boost::filesystem::path& target_path, const std::string& repository_id, PresetUpdaterUIStatus* ui_status) const override;
|
||||
// Gets file without checking id.
|
||||
// Should be used only if no previous ini file exists.
|
||||
bool get_ini_no_id(const std::string& source_subpath, const boost::filesystem::path& target_path) const override;
|
||||
bool get_ini_no_id(const std::string& source_subpath, const boost::filesystem::path& target_path, PresetUpdaterUIStatus* ui_status) const override;
|
||||
private:
|
||||
bool get_file_inner(const std::string& url, const boost::filesystem::path& target_path) const;
|
||||
bool get_file_inner(const std::string& url, const boost::filesystem::path& target_path, PresetUpdaterUIStatus* ui_status) const;
|
||||
};
|
||||
|
||||
class LocalArchiveRepository : public ArchiveRepository
|
||||
@ -120,13 +121,13 @@ public:
|
||||
LocalArchiveRepository(const std::string& uuid, RepositoryManifest&& data, bool extracted) : ArchiveRepository(uuid, std::move(data)), m_extracted(extracted)
|
||||
{}
|
||||
// Gets vendor_indices.zip to target_path.
|
||||
bool get_archive(const boost::filesystem::path& target_path) const override;
|
||||
bool get_archive(const boost::filesystem::path& target_path, PresetUpdaterUIStatus* ui_status) const override;
|
||||
// Gets file if repository_id arg matches m_id.
|
||||
// Should be used to get the most recent ini file and every missing resource.
|
||||
bool get_file(const std::string& source_subpath, const boost::filesystem::path& target_path, const std::string& repository_id) const override;
|
||||
bool get_file(const std::string& source_subpath, const boost::filesystem::path& target_path, const std::string& repository_id, PresetUpdaterUIStatus* ui_status) const override;
|
||||
// Gets file without checking id.
|
||||
// Should be used only if no previous ini file exists.
|
||||
bool get_ini_no_id(const std::string& source_subpath, const boost::filesystem::path& target_path) const override;
|
||||
bool get_ini_no_id(const std::string& source_subpath, const boost::filesystem::path& target_path, PresetUpdaterUIStatus* ui_status) const override;
|
||||
bool is_extracted() const override { return m_extracted; }
|
||||
void do_extract() override;
|
||||
|
||||
@ -141,10 +142,10 @@ typedef std::vector<const ArchiveRepository*> SharedArchiveRepositoryVector;
|
||||
class PresetArchiveDatabase
|
||||
{
|
||||
public:
|
||||
PresetArchiveDatabase(AppConfig* app_config, wxEvtHandler* evt_handler);
|
||||
PresetArchiveDatabase();
|
||||
~PresetArchiveDatabase() {}
|
||||
|
||||
void sync_blocking();
|
||||
// returns true if successfully got the data
|
||||
bool sync_blocking(PresetUpdaterUIStatus* ui_status = nullptr);
|
||||
|
||||
// Do not use get_all_archive_repositories to perform any GET calls. Use get_selected_archive_repositories instead.
|
||||
SharedArchiveRepositoryVector get_all_archive_repositories() const;
|
||||
@ -179,6 +180,6 @@ private:
|
||||
boost::uuids::random_generator m_uuid_generator;
|
||||
};
|
||||
|
||||
}} // Slic3r::GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif // PresetArchiveDatabase
|
@ -277,9 +277,9 @@ boost::filesystem::path AppUpdateDownloadDialog::get_download_path() const
|
||||
|
||||
// MsgUpdateConfig
|
||||
|
||||
MsgUpdateConfig::MsgUpdateConfig(const std::vector<Update> &updates, bool force_before_wizard/* = false*/) :
|
||||
MsgDialog(nullptr, force_before_wizard ? _L("Opening Configuration Wizard") : _L("Configuration update"),
|
||||
force_before_wizard ? _L("PrusaSlicer is not using the newest configuration available.\n"
|
||||
MsgUpdateConfig::MsgUpdateConfig(const std::vector<Update> &updates, PresetUpdater::UpdateParams update_params) :
|
||||
MsgDialog(nullptr, update_params == PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD ? _L("Opening Configuration Wizard") : _L("Configuration update"),
|
||||
update_params == PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD ? _L("PrusaSlicer is not using the newest configuration available.\n"
|
||||
"Configuration Wizard may not offer the latest printers, filaments and SLA materials to be installed.") :
|
||||
_L("Configuration update is available"), wxICON_ERROR)
|
||||
{
|
||||
@ -333,12 +333,19 @@ MsgUpdateConfig::MsgUpdateConfig(const std::vector<Update> &updates, bool force_
|
||||
content_sizer->Add(versions);
|
||||
content_sizer->AddSpacer(2*VERT_SPACING);
|
||||
|
||||
add_button(wxID_OK, true, force_before_wizard ? _L("Install") : "OK");
|
||||
if (force_before_wizard) {
|
||||
if (update_params == PresetUpdater::UpdateParams::FORCED_BEFORE_WIZARD) {
|
||||
add_button(wxID_OK, true, _L("Install"));
|
||||
auto* btn = add_button(wxID_CLOSE, false, _L("Don't install"));
|
||||
btn->Bind(wxEVT_BUTTON, [this](const wxCommandEvent&) { this->EndModal(wxID_CLOSE); });
|
||||
}
|
||||
add_button(wxID_CANCEL);
|
||||
} else if (update_params == PresetUpdater::UpdateParams::SHOW_TEXT_BOX_YES_NO) {
|
||||
add_button(wxID_OK, true, _L("Yes"));
|
||||
add_button(wxID_CANCEL, false, _L("No"));
|
||||
} else {
|
||||
assert(update_params == PresetUpdater::UpdateParams::SHOW_TEXT_BOX);
|
||||
add_button(wxID_OK, true, "OK");
|
||||
add_button(wxID_CANCEL);
|
||||
}
|
||||
|
||||
finalize();
|
||||
}
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "libslic3r/Semver.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
|
||||
#include "slic3r/Utils/PresetUpdater.hpp"
|
||||
|
||||
class wxBoxSizer;
|
||||
class wxCheckBox;
|
||||
|
||||
@ -102,7 +104,7 @@ public:
|
||||
};
|
||||
|
||||
// force_before_wizard - indicates that check of updated is forced before ConfigWizard opening
|
||||
MsgUpdateConfig(const std::vector<Update> &updates, bool force_before_wizard = false);
|
||||
MsgUpdateConfig(const std::vector<Update> &updates, PresetUpdater::UpdateParams update_params);
|
||||
MsgUpdateConfig(MsgUpdateConfig &&) = delete;
|
||||
MsgUpdateConfig(const MsgUpdateConfig &) = delete;
|
||||
MsgUpdateConfig &operator=(MsgUpdateConfig &&) = delete;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "UpdatesUIManager.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "PresetArchiveDatabase.hpp"
|
||||
#include "slic3r/Utils/PresetUpdaterWrapper.hpp"
|
||||
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
@ -22,9 +22,9 @@ namespace fs = boost::filesystem;
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
RepositoryUpdateUIManager::RepositoryUpdateUIManager(wxWindow* parent, PresetArchiveDatabase* pad, int em) :
|
||||
RepositoryUpdateUIManager::RepositoryUpdateUIManager(wxWindow* parent, Slic3r::PresetUpdaterWrapper* puw, int em) :
|
||||
m_parent(parent)
|
||||
,m_pad(pad)
|
||||
,m_puw(puw)
|
||||
,m_main_sizer(new wxBoxSizer(wxVERTICAL))
|
||||
{
|
||||
auto online_label = new wxStaticText(m_parent, wxID_ANY, _L("Online sources"));
|
||||
@ -104,10 +104,10 @@ void RepositoryUpdateUIManager::fill_entries(bool init_selection/* = false*/)
|
||||
m_online_entries.clear();
|
||||
m_offline_entries.clear();
|
||||
|
||||
const SharedArchiveRepositoryVector& archs = m_pad->get_all_archive_repositories();
|
||||
const SharedArchiveRepositoryVector& archs = m_puw->get_all_archive_repositories();
|
||||
for (const auto* archive : archs) {
|
||||
const std::string& uuid = archive->get_uuid();
|
||||
if (init_selection && m_pad->is_selected_repository_by_uuid(uuid))
|
||||
if (init_selection && m_puw->is_selected_repository_by_uuid(uuid))
|
||||
m_selected_uuids.emplace(uuid);
|
||||
|
||||
const bool is_selected = m_selected_uuids.find(uuid) != m_selected_uuids.end();
|
||||
@ -260,7 +260,7 @@ void RepositoryUpdateUIManager::update()
|
||||
|
||||
void RepositoryUpdateUIManager::remove_offline_repos(const std::string& id)
|
||||
{
|
||||
m_pad->remove_local_archive(id);
|
||||
m_puw->remove_local_archive(id);
|
||||
m_selected_uuids.erase(id);
|
||||
check_selection();
|
||||
|
||||
@ -291,7 +291,7 @@ void RepositoryUpdateUIManager::load_offline_repos()
|
||||
try {
|
||||
fs::path input_path = fs::path(input_file);
|
||||
std::string msg;
|
||||
std::string uuid = m_pad->add_local_archive(input_path, msg);
|
||||
std::string uuid = m_puw->add_local_archive(input_path, msg);
|
||||
if (uuid.empty()) {
|
||||
ErrorDialog(m_parent, from_u8(msg), false).ShowModal();
|
||||
}
|
||||
@ -314,7 +314,7 @@ bool RepositoryUpdateUIManager::set_selected_repositories()
|
||||
|
||||
std::string msg;
|
||||
|
||||
if (m_pad->set_selected_repositories(used_ids, msg)) {
|
||||
if (m_puw->set_selected_repositories(used_ids, msg)) {
|
||||
check_selection();
|
||||
return true;
|
||||
}
|
||||
@ -328,7 +328,7 @@ bool RepositoryUpdateUIManager::set_selected_repositories()
|
||||
|
||||
void RepositoryUpdateUIManager::check_selection()
|
||||
{
|
||||
for (const auto& [uuid, is_selected] : m_pad->get_selected_repositories_uuid() )
|
||||
for (const auto& [uuid, is_selected] : m_puw->get_selected_repositories_uuid() )
|
||||
if ((is_selected && m_selected_uuids.find(uuid) == m_selected_uuids.end() )||
|
||||
(!is_selected && m_selected_uuids.find(uuid) != m_selected_uuids.end())) {
|
||||
m_is_selection_changed = true;
|
||||
@ -338,7 +338,7 @@ void RepositoryUpdateUIManager::check_selection()
|
||||
m_is_selection_changed = false;
|
||||
}
|
||||
|
||||
ManagePresetRepositoriesDialog::ManagePresetRepositoriesDialog(PresetArchiveDatabase* pad)
|
||||
ManagePresetRepositoriesDialog::ManagePresetRepositoriesDialog(Slic3r::PresetUpdaterWrapper* puw)
|
||||
: DPIDialog(static_cast<wxWindow*>(wxGetApp().mainframe), wxID_ANY,
|
||||
format_wxstr("%1% - %2%", SLIC3R_APP_NAME, _L("Manage Updates")),
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
@ -346,7 +346,7 @@ ManagePresetRepositoriesDialog::ManagePresetRepositoriesDialog(PresetArchiveData
|
||||
this->SetFont(wxGetApp().normal_font());
|
||||
const int em = em_unit();
|
||||
|
||||
m_manager = std::make_unique<RepositoryUpdateUIManager>(this, pad, em);
|
||||
m_manager = std::make_unique<RepositoryUpdateUIManager>(this, puw, em);
|
||||
|
||||
auto sizer = m_manager->get_sizer();
|
||||
|
||||
|
@ -14,10 +14,10 @@ class wxSizer;
|
||||
class wxFlexGridSizer;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class PresetUpdaterWrapper;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class PresetArchiveDatabase;
|
||||
|
||||
class RepositoryUpdateUIManager
|
||||
{
|
||||
struct OnlineEntry {
|
||||
@ -44,7 +44,7 @@ class RepositoryUpdateUIManager
|
||||
boost::filesystem::path source_path;
|
||||
};
|
||||
|
||||
PresetArchiveDatabase* m_pad { nullptr };
|
||||
PresetUpdaterWrapper* m_puw { nullptr };
|
||||
wxWindow* m_parent { nullptr };
|
||||
wxSizer* m_main_sizer { nullptr };
|
||||
|
||||
@ -68,7 +68,7 @@ class RepositoryUpdateUIManager
|
||||
|
||||
public:
|
||||
RepositoryUpdateUIManager() {}
|
||||
RepositoryUpdateUIManager(wxWindow* parent, PresetArchiveDatabase* pad, int em);
|
||||
RepositoryUpdateUIManager(wxWindow* parent, Slic3r::PresetUpdaterWrapper* puw, int em);
|
||||
~RepositoryUpdateUIManager() {}
|
||||
|
||||
void update();
|
||||
@ -83,7 +83,7 @@ public:
|
||||
class ManagePresetRepositoriesDialog : public DPIDialog
|
||||
{
|
||||
public:
|
||||
ManagePresetRepositoriesDialog(PresetArchiveDatabase* pad);
|
||||
ManagePresetRepositoriesDialog(PresetUpdaterWrapper* puw);
|
||||
~ManagePresetRepositoriesDialog() {}
|
||||
|
||||
protected:
|
||||
|
@ -26,17 +26,6 @@ std::string parse_tree_for_param(const pt::ptree& tree, const std::string& param
|
||||
return {};
|
||||
}
|
||||
|
||||
/*void parse_tree_for_param_vector(
|
||||
const pt::ptree &tree, const std::string& param, std::vector<std::string>& results) {
|
||||
for (const auto §ion : tree) {
|
||||
if (section.first == param) {
|
||||
results.emplace_back(section.second.data());
|
||||
} else {
|
||||
parse_tree_for_param_vector(section.second, param, results);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
pt::ptree parse_tree_for_subtree(const pt::ptree& tree, const std::string& param) {
|
||||
for (const auto §ion : tree) {
|
||||
if (section.first == param) {
|
||||
|
@ -1539,9 +1539,9 @@ void LoginWebViewDialog::on_navigation_request(wxWebViewEvent &evt)
|
||||
evt.Veto();
|
||||
m_ret_val = into_u8(url);
|
||||
EndModal(wxID_OK);
|
||||
} else if (url.Find(L"accounts.google.com") != wxString::npos
|
||||
|| url.Find(L"appleid.apple.com") != wxString::npos
|
||||
|| url.Find(L"facebook.com") != wxString::npos) {
|
||||
} else if (url.Find(L"accounts.google.com") != wxNOT_FOUND
|
||||
|| url.Find(L"appleid.apple.com") != wxNOT_FOUND
|
||||
|| url.Find(L"facebook.com") != wxNOT_FOUND) {
|
||||
auto& sc = Utils::ServiceConfig::instance();
|
||||
if (!m_evt_sent && !url.starts_with(GUI::from_u8(sc.account_url()))) {
|
||||
wxCommandEvent* evt = new wxCommandEvent(EVT_OPEN_EXTERNAL_LOGIN);
|
||||
|
@ -136,6 +136,7 @@ struct Http::priv
|
||||
Http::ErrorFn errorfn;
|
||||
Http::ProgressFn progressfn;
|
||||
Http::IPResolveFn ipresolvefn;
|
||||
Http::RetryFn retryfn;
|
||||
|
||||
priv(const std::string &url);
|
||||
~priv();
|
||||
@ -395,6 +396,12 @@ void Http::priv::http_perform(const HttpRetryOpt& retry_opts)
|
||||
std::chrono::milliseconds delay = std::chrono::milliseconds(randomized_delay(generator));
|
||||
size_t num_retries = 0;
|
||||
do {
|
||||
// break if canceled outside
|
||||
if (retryfn && !retryfn(num_retries + 1, num_retries < retry_opts.max_retries ? delay.count() : 0)) {
|
||||
res = CURLE_ABORTED_BY_CALLBACK;
|
||||
cancel = true;
|
||||
break;
|
||||
}
|
||||
res = ::curl_easy_perform(curl);
|
||||
|
||||
if (res == CURLE_OK)
|
||||
@ -409,6 +416,7 @@ void Http::priv::http_perform(const HttpRetryOpt& retry_opts)
|
||||
<< "), retrying in " << delay.count() / 1000.0f << " s";
|
||||
std::this_thread::sleep_for(delay);
|
||||
delay = std::min(delay * 2, retry_opts.max_delay);
|
||||
|
||||
}
|
||||
} while (retry);
|
||||
|
||||
@ -643,6 +651,12 @@ Http& Http::on_ip_resolve(IPResolveFn fn)
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::on_retry(RetryFn fn)
|
||||
{
|
||||
if (p) { p->retryfn = std::move(fn); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::cookie_file(const std::string& file_path)
|
||||
{
|
||||
if (p) {
|
||||
|
@ -61,6 +61,8 @@ public:
|
||||
typedef std::function<void(Progress, bool& /* cancel */)> ProgressFn;
|
||||
|
||||
typedef std::function<void(std::string/* address */)> IPResolveFn;
|
||||
//<bool - false if canceled(int - attempt number, unsigned - ms to next attempt, 0 if last)>
|
||||
typedef std::function<bool(int, unsigned)> RetryFn;
|
||||
|
||||
Http(Http &&other);
|
||||
|
||||
@ -140,6 +142,8 @@ public:
|
||||
// Called if curl_easy_getinfo resolved just used IP address.
|
||||
Http& on_ip_resolve(IPResolveFn fn);
|
||||
|
||||
Http& on_retry(RetryFn fn);
|
||||
|
||||
Http& cookie_file(const std::string& file_path);
|
||||
Http& cookie_jar(const std::string& file_path);
|
||||
Http& set_referer(const std::string& referer);
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/UpdateDialogs.hpp"
|
||||
#include "slic3r/GUI/ConfigWizard.hpp"
|
||||
#include "slic3r/Utils/PresetUpdaterWrapper.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
@ -74,24 +74,8 @@ 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;
|
||||
}*/
|
||||
}
|
||||
|
||||
wxDEFINE_EVENT(EVT_CONFIG_UPDATER_SYNC_DONE, wxCommandEvent);
|
||||
|
||||
struct Update
|
||||
{
|
||||
fs::path source;
|
||||
@ -170,18 +154,13 @@ struct PresetUpdater::priv
|
||||
{
|
||||
std::vector<Index> index_db;
|
||||
|
||||
bool enabled_version_check;
|
||||
bool enabled_config_update;
|
||||
std::string version_check_url;
|
||||
|
||||
fs::path cache_path;
|
||||
fs::path cache_vendor_path;
|
||||
fs::path rsrc_path;
|
||||
fs::path vendor_path;
|
||||
|
||||
bool cancel;
|
||||
std::thread thread;
|
||||
|
||||
bool has_waiting_updates { false };
|
||||
Updates waiting_updates;
|
||||
|
||||
@ -190,16 +169,16 @@ struct PresetUpdater::priv
|
||||
void set_download_prefs(const AppConfig *app_config);
|
||||
void prune_tmps() const;
|
||||
void clear_cache_vendor() const;
|
||||
void sync_config(const VendorMap& vendors, const GUI::ArchiveRepository* archive);
|
||||
void sync_config(const VendorMap& vendors, const ArchiveRepository* archive, PresetUpdaterUIStatus* ui_status);
|
||||
|
||||
void check_install_indices() const;
|
||||
Updates get_config_updates(const Semver& old_slic3r_version) const;
|
||||
bool perform_updates(Updates &&updates, const SharedArchiveRepositoryVector& repositories, bool snapshot = true) const;
|
||||
bool perform_updates(Updates &&updates, const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status, bool snapshot = true) const;
|
||||
void set_waiting_updates(Updates u);
|
||||
// checks existence and downloads resource to cache
|
||||
void get_missing_resource(const GUI::ArchiveRepository* archive, const std::string& vendor, const std::string& filename, const std::string& repository_id_from_ini) const;
|
||||
void get_missing_resource(const ArchiveRepository* archive, const std::string& vendor, const std::string& filename, const std::string& repository_id_from_ini, PresetUpdaterUIStatus* ui_status) const;
|
||||
// checks existence and downloads resource to vendor or copy from cache to vendor
|
||||
void get_or_copy_missing_resource(const GUI::ArchiveRepository* archive, const std::string& vendor, const std::string& filename, const std::string& repository_id_from_ini) const;
|
||||
void get_or_copy_missing_resource(const ArchiveRepository* archive, const std::string& vendor, const std::string& filename, const std::string& repository_id_from_ini, PresetUpdaterUIStatus* ui_status) const;
|
||||
void update_index_db();
|
||||
};
|
||||
|
||||
@ -208,7 +187,7 @@ PresetUpdater::priv::priv()
|
||||
, cache_vendor_path(cache_path / "vendor")
|
||||
, rsrc_path(fs::path(resources_dir()) / "profiles")
|
||||
, vendor_path(fs::path(Slic3r::data_dir()) / "vendor")
|
||||
, cancel(false)
|
||||
//, cancel(false)
|
||||
{
|
||||
set_download_prefs(GUI::wxGetApp().app_config);
|
||||
// Install indicies from resources. Only installs those that are either missing or older than in resources.
|
||||
@ -225,8 +204,6 @@ void PresetUpdater::priv::update_index_db()
|
||||
// Pull relevant preferences from AppConfig
|
||||
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();
|
||||
enabled_config_update = app_config->get_bool("preset_update") && !app_config->legacy_datadir();
|
||||
}
|
||||
|
||||
@ -253,7 +230,7 @@ void PresetUpdater::priv::clear_cache_vendor() const
|
||||
}
|
||||
|
||||
// gets resource to cache/<vendor_name>/
|
||||
void PresetUpdater::priv::get_missing_resource(const GUI::ArchiveRepository* archive, const std::string& vendor, const std::string& filename, const std::string& repository_id_from_ini) const
|
||||
void PresetUpdater::priv::get_missing_resource(const ArchiveRepository* archive, const std::string& vendor, const std::string& filename, const std::string& repository_id_from_ini, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
assert(!filename.empty() && !vendor.empty());
|
||||
//if (filename.empty() || vendor.empty()) {
|
||||
@ -282,13 +259,12 @@ void PresetUpdater::priv::get_missing_resource(const GUI::ArchiveRepository* arc
|
||||
if (!fs::exists(file_in_cache.parent_path()))
|
||||
fs::create_directory(file_in_cache.parent_path());
|
||||
|
||||
//std::string escaped_filename = escape_string_url(filename);
|
||||
const std::string resource_subpath = GUI::format("%1%/%2%",vendor, filename);
|
||||
archive->get_file(resource_subpath, file_in_cache, repository_id_from_ini);
|
||||
archive->get_file(resource_subpath, file_in_cache, repository_id_from_ini, ui_status);
|
||||
return;
|
||||
}
|
||||
// gets resource to vendor/<vendor_name>/
|
||||
void PresetUpdater::priv::get_or_copy_missing_resource(const GUI::ArchiveRepository* archive, const std::string& vendor, const std::string& filename, const std::string& repository_id_from_ini) const
|
||||
void PresetUpdater::priv::get_or_copy_missing_resource(const ArchiveRepository* archive, const std::string& vendor, const std::string& filename, const std::string& repository_id_from_ini, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
assert(!filename.empty() && !vendor.empty());
|
||||
|
||||
@ -313,9 +289,8 @@ void PresetUpdater::priv::get_or_copy_missing_resource(const GUI::ArchiveReposit
|
||||
if (!fs::exists(file_in_cache)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Downloading resources missing in cache directory: " << vendor << " / " << filename;
|
||||
|
||||
//std::string escaped_filename = escape_string_url(filename);
|
||||
const std::string resource_subpath = GUI::format("%1%/%2%", vendor, filename);
|
||||
archive->get_file(resource_subpath, file_in_vendor, repository_id_from_ini);
|
||||
archive->get_file(resource_subpath, file_in_vendor, repository_id_from_ini, ui_status);
|
||||
return;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(debug) << "Copiing: " << file_in_cache << " to " << file_in_vendor;
|
||||
@ -324,19 +299,22 @@ void PresetUpdater::priv::get_or_copy_missing_resource(const GUI::ArchiveReposit
|
||||
|
||||
// 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, const GUI::ArchiveRepository* archive_repository)
|
||||
void PresetUpdater::priv::sync_config(const VendorMap& vendors, const ArchiveRepository* archive_repository, PresetUpdaterUIStatus* ui_status)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "Syncing configuration cache";
|
||||
|
||||
if (!enabled_config_update) { return; }
|
||||
|
||||
assert(ui_status);
|
||||
ui_status->set_target(archive_repository->get_manifest().id + " archive");
|
||||
|
||||
// Download profiles archive zip
|
||||
fs::path archive_path(cache_path / "vendor_indices.zip");
|
||||
if (!archive_repository->get_archive(archive_path)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Download of vedor profiles archive zip failed.";
|
||||
if (!archive_repository->get_archive(archive_path, ui_status)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Download of vedor profiles archive zip of " << archive_repository->get_manifest().id << " repository has failed.";
|
||||
return;
|
||||
}
|
||||
if (cancel) {
|
||||
if (ui_status->get_canceled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -406,7 +384,7 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
// Update vendor preset bundles if in Vendor
|
||||
// Over all indices from the cache directory:
|
||||
for (auto &index : index_db) {
|
||||
if (cancel) {
|
||||
if (ui_status->get_canceled()) {
|
||||
return;
|
||||
}
|
||||
auto archive_it = std::find_if(vendors_with_status.begin(), vendors_with_status.end(),
|
||||
@ -452,7 +430,7 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
BOOST_LOG_TRIVIAL(error) << format("Could not load downloaded index %1% for vendor %2%: invalid index?", idx_path, vendor.name);
|
||||
continue;
|
||||
}
|
||||
if (cancel)
|
||||
if (ui_status->get_canceled())
|
||||
return;
|
||||
}
|
||||
|
||||
@ -480,9 +458,9 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
BOOST_LOG_TRIVIAL(info) << "Downloading new bundle for vendor: " << vendor.name;
|
||||
const std::string source_subpath = GUI::format("%1%/%2%.ini", vendor.id, recommended.to_string());
|
||||
const fs::path bundle_path = cache_path / (vendor.id + ".ini");
|
||||
if (!archive_repository->get_file(source_subpath, bundle_path, vendor.repo_id))
|
||||
if (!archive_repository->get_file(source_subpath, bundle_path, vendor.repo_id, ui_status))
|
||||
continue;
|
||||
if (cancel)
|
||||
if (ui_status->get_canceled())
|
||||
return;
|
||||
// vp is fully loaded to get all resources
|
||||
VendorProfile vp;
|
||||
@ -499,7 +477,7 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
if (! res.empty()) {
|
||||
try
|
||||
{
|
||||
get_missing_resource(archive_repository, vp.id, res, vendor.repo_id);
|
||||
get_missing_resource(archive_repository, vp.id, res, vendor.repo_id, ui_status);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
@ -507,7 +485,7 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
}
|
||||
|
||||
}
|
||||
if (cancel)
|
||||
if (ui_status->get_canceled())
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -539,7 +517,7 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
if (!fs::exists(ini_path_in_archive)){
|
||||
// Download recommneded to vendor - we do not have any existing ini file so we have to use archive url.
|
||||
const std::string source_subpath = GUI::format("%1%/%2%.ini", vendor.first, recommended.to_string());
|
||||
if (!archive_repository->get_ini_no_id(source_subpath, ini_path_in_archive))
|
||||
if (!archive_repository->get_ini_no_id(source_subpath, ini_path_in_archive, ui_status))
|
||||
continue;
|
||||
} else {
|
||||
// check existing ini version
|
||||
@ -560,7 +538,7 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
if (vp.config_version != recommended) {
|
||||
// Take url from existing ini. This way we prevent downloading files from multiple sources.
|
||||
const std::string source_subpath = GUI::format("%1%/%2%.ini", vp.id, recommended.to_string());
|
||||
if (!archive_repository->get_file(source_subpath, ini_path_in_archive, vp.repo_id))
|
||||
if (!archive_repository->get_file(source_subpath, ini_path_in_archive, vp.repo_id, ui_status))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -577,14 +555,14 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
if (!model.thumbnail.empty()) {
|
||||
try
|
||||
{
|
||||
get_missing_resource(archive_repository, vp.id, model.thumbnail, vp.repo_id);
|
||||
get_missing_resource(archive_repository, vp.id, model.thumbnail, vp.repo_id, ui_status);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to get " << model.thumbnail << " for " << vp.id << " " << model.id << ": " << e.what();
|
||||
}
|
||||
}
|
||||
if (cancel)
|
||||
if (ui_status->get_canceled())
|
||||
return;
|
||||
}
|
||||
} else if (vendor.second == VendorStatus::IN_CACHE) {
|
||||
@ -653,7 +631,7 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
continue;
|
||||
}
|
||||
const std::string source_subpath = GUI::format("%1%/%2%.ini", vp.id, recommended_archive.to_string());
|
||||
if (!archive_repository->get_file(source_subpath, ini_path_in_archive, vp.repo_id)) {
|
||||
if (!archive_repository->get_file(source_subpath, ini_path_in_archive, vp.repo_id, ui_status)) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Failed to get new vendor .ini file when checking missing resources: %1%", ini_path_in_archive.string());
|
||||
continue;
|
||||
}
|
||||
@ -670,7 +648,7 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
}
|
||||
if (vp.config_version != recommended_archive) {
|
||||
const std::string source_subpath = GUI::format("%1%/%2%.ini", vp.id, recommended_archive.to_string());
|
||||
if (!archive_repository->get_file(source_subpath, ini_path_in_archive, vp.repo_id)) {
|
||||
if (!archive_repository->get_file(source_subpath, ini_path_in_archive, vp.repo_id, ui_status)) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Failed to open vendor .ini file when checking missing resources: %1%", ini_path_in_archive);
|
||||
continue;
|
||||
}
|
||||
@ -694,14 +672,14 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
if (!model.thumbnail.empty()) {
|
||||
try
|
||||
{
|
||||
get_missing_resource(archive_repository, vp.id, model.thumbnail, vp.repo_id);
|
||||
get_missing_resource(archive_repository, vp.id, model.thumbnail, vp.repo_id, ui_status);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to get " << model.thumbnail << " for " << vp.id << " " << model.id << ": " << e.what();
|
||||
}
|
||||
}
|
||||
if (cancel)
|
||||
if (ui_status->get_canceled())
|
||||
return;
|
||||
}
|
||||
} else if (vendor.second == VendorStatus::INSTALLED || vendor.second == VendorStatus::NEW_VERSION) {
|
||||
@ -724,14 +702,14 @@ void PresetUpdater::priv::sync_config(const VendorMap& vendors, const GUI::Archi
|
||||
if (!res.empty()) {
|
||||
try
|
||||
{
|
||||
get_or_copy_missing_resource(archive_repository, vp.id, res, vp.repo_id);
|
||||
get_or_copy_missing_resource(archive_repository, vp.id, res, vp.repo_id, ui_status);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to get " << res << " for " << vp.id << " " << model.id << ": " << e.what();
|
||||
}
|
||||
}
|
||||
if (cancel)
|
||||
if (ui_status->get_canceled())
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -962,7 +940,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version
|
||||
return updates;
|
||||
}
|
||||
|
||||
bool PresetUpdater::priv::perform_updates(Updates &&updates, const SharedArchiveRepositoryVector& repositories, bool snapshot) const
|
||||
bool PresetUpdater::priv::perform_updates(Updates &&updates, const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status, bool snapshot) const
|
||||
{
|
||||
if (updates.incompats.size() > 0) {
|
||||
if (snapshot) {
|
||||
@ -1051,7 +1029,7 @@ bool PresetUpdater::priv::perform_updates(Updates &&updates, const SharedArchive
|
||||
{
|
||||
auto it = std::find_if(repositories.begin(), repositories.end(), [&vp](const auto* i){ return vp.repo_id == i->get_manifest().id; });
|
||||
if (it != repositories.end())
|
||||
get_or_copy_missing_resource((*it), vp.id, resource, vp.repo_id);
|
||||
get_or_copy_missing_resource((*it), vp.id, resource, vp.repo_id, ui_status);
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to prepare " << resource << " for " << vp.id << " " << model.id << ": Missing record for source with repo_id " << vp.repo_id;
|
||||
}
|
||||
@ -1085,74 +1063,20 @@ PresetUpdater::PresetUpdater() :
|
||||
|
||||
PresetUpdater::~PresetUpdater()
|
||||
{
|
||||
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::sync(const PresetBundle *preset_bundle, wxEvtHandler* evt_handler,SharedArchiveRepositoryVector&& repositories)
|
||||
{
|
||||
p->set_download_prefs(GUI::wxGetApp().app_config);
|
||||
if (!p->enabled_config_update) { return; }
|
||||
|
||||
p->thread = std::thread([this, &vendors = preset_bundle->vendors, repositories = std::move(repositories), evt_handler]() {
|
||||
this->p->clear_cache_vendor();
|
||||
this->p->prune_tmps();
|
||||
for (const GUI::ArchiveRepository* archive : repositories) {
|
||||
this->p->sync_config(vendors, archive);
|
||||
}
|
||||
wxCommandEvent* evt = new wxCommandEvent(EVT_CONFIG_UPDATER_SYNC_DONE);
|
||||
evt_handler->QueueEvent(evt);
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
p->cancel = false;
|
||||
}
|
||||
|
||||
void PresetUpdater::sync_blocking(const PresetBundle* preset_bundle, wxEvtHandler* evt_handler, const SharedArchiveRepositoryVector& repositories)
|
||||
void PresetUpdater::sync_blocking(const VendorMap& vendors, const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status)
|
||||
{
|
||||
p->set_download_prefs(GUI::wxGetApp().app_config);
|
||||
if (!p->enabled_config_update) { return; }
|
||||
|
||||
this->p->clear_cache_vendor();
|
||||
this->p->prune_tmps();
|
||||
for (const GUI::ArchiveRepository* archive : repositories) {
|
||||
this->p->sync_config(preset_bundle->vendors, archive);
|
||||
for (const ArchiveRepository* archive : repositories) {
|
||||
if (ui_status && ui_status->get_canceled()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void PresetUpdater::slic3r_update_notify()
|
||||
{
|
||||
if (! p->enabled_version_check)
|
||||
return;
|
||||
auto* app_config = GUI::wxGetApp().app_config;
|
||||
const auto ver_online_str = app_config->get("version_online");
|
||||
const auto ver_online = Semver::parse(ver_online_str);
|
||||
const auto ver_online_seen = Semver::parse(app_config->get("version_online_seen"));
|
||||
|
||||
if (ver_online) {
|
||||
// Only display the notification if the version available online is newer AND if we haven't seen it before
|
||||
if (*ver_online > Slic3r::SEMVER && (! ver_online_seen || *ver_online_seen < *ver_online)) {
|
||||
GUI::MsgUpdateSlic3r notification(Slic3r::SEMVER, *ver_online);
|
||||
notification.ShowModal();
|
||||
if (notification.disable_version_check()) {
|
||||
app_config->set("notify_release", "none");
|
||||
p->enabled_version_check = false;
|
||||
}
|
||||
}
|
||||
|
||||
app_config->set("version_online_seen", ver_online_str);
|
||||
this->p->sync_config(vendors, archive, ui_status);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1175,7 +1099,7 @@ static bool reload_configs_update_gui()
|
||||
return true;
|
||||
}
|
||||
|
||||
PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3r_version, UpdateParams params, const SharedArchiveRepositoryVector& repositories) const
|
||||
PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3r_version, UpdateParams params, const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status) const
|
||||
{
|
||||
if (! p->enabled_config_update) { return R_NOOP; }
|
||||
|
||||
@ -1209,7 +1133,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
|
||||
|
||||
// This effectively removes the incompatible bundles:
|
||||
// (snapshot is taken beforehand)
|
||||
if (! p->perform_updates(std::move(updates), repositories) ||
|
||||
if (! p->perform_updates(std::move(updates), repositories, ui_status) ||
|
||||
! GUI::wxGetApp().run_wizard(GUI::ConfigWizard::RR_DATA_INCOMPAT))
|
||||
return R_INCOMPAT_EXIT;
|
||||
|
||||
@ -1251,7 +1175,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
|
||||
const auto res = dlg.ShowModal();
|
||||
if (res == wxID_OK) {
|
||||
BOOST_LOG_TRIVIAL(info) << "User wants to update...";
|
||||
if (! p->perform_updates(std::move(updates), repositories) ||
|
||||
if (! p->perform_updates(std::move(updates), repositories, ui_status) ||
|
||||
! reload_configs_update_gui())
|
||||
return R_INCOMPAT_EXIT;
|
||||
return R_UPDATE_INSTALLED;
|
||||
@ -1289,12 +1213,12 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
|
||||
updates_msg.emplace_back(update.vendor, update.version.config_version, update.version.comment, std::move(changelog_url), std::move(printers));
|
||||
}
|
||||
|
||||
GUI::MsgUpdateConfig dlg(updates_msg, params == UpdateParams::FORCED_BEFORE_WIZARD);
|
||||
GUI::MsgUpdateConfig dlg(updates_msg, params);
|
||||
|
||||
const auto res = dlg.ShowModal();
|
||||
if (res == wxID_OK) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "User agreed to perform the update";
|
||||
if (! p->perform_updates(std::move(updates), repositories) ||
|
||||
if (! p->perform_updates(std::move(updates), repositories, ui_status) ||
|
||||
! reload_configs_update_gui())
|
||||
return R_ALL_CANCELED;
|
||||
return R_UPDATE_INSTALLED;
|
||||
@ -1315,7 +1239,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3
|
||||
return R_NOOP;
|
||||
}
|
||||
|
||||
bool PresetUpdater::install_bundles_rsrc_or_cache_vendor(std::vector<std::string> bundles, const SharedArchiveRepositoryVector& repositories, bool snapshot) const
|
||||
bool PresetUpdater::install_bundles_rsrc_or_cache_vendor(std::vector<std::string> bundles, const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status, bool snapshot) const
|
||||
{
|
||||
Updates updates;
|
||||
|
||||
@ -1418,10 +1342,10 @@ bool PresetUpdater::install_bundles_rsrc_or_cache_vendor(std::vector<std::string
|
||||
}
|
||||
}
|
||||
|
||||
return p->perform_updates(std::move(updates), repositories, snapshot);
|
||||
return p->perform_updates(std::move(updates), repositories, ui_status, snapshot);
|
||||
}
|
||||
|
||||
void PresetUpdater::on_update_notification_confirm(const SharedArchiveRepositoryVector& repositories)
|
||||
void PresetUpdater::on_update_notification_confirm(const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status)
|
||||
{
|
||||
if (!p->has_waiting_updates)
|
||||
return;
|
||||
@ -1439,12 +1363,12 @@ void PresetUpdater::on_update_notification_confirm(const SharedArchiveRepository
|
||||
updates_msg.emplace_back(update.vendor, update.version.config_version, update.version.comment, std::move(changelog_url), std::move(printers));
|
||||
}
|
||||
|
||||
GUI::MsgUpdateConfig dlg(updates_msg);
|
||||
GUI::MsgUpdateConfig dlg(updates_msg, UpdateParams::SHOW_TEXT_BOX);
|
||||
|
||||
const auto res = dlg.ShowModal();
|
||||
if (res == wxID_OK) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "User agreed to perform the update";
|
||||
if (p->perform_updates(std::move(p->waiting_updates), repositories) &&
|
||||
if (p->perform_updates(std::move(p->waiting_updates), repositories, ui_status) &&
|
||||
reload_configs_update_gui()) {
|
||||
p->has_waiting_updates = false;
|
||||
}
|
||||
@ -1454,28 +1378,10 @@ void PresetUpdater::on_update_notification_confirm(const SharedArchiveRepository
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetUpdater::version_check_enabled() const
|
||||
{
|
||||
return p->enabled_version_check;
|
||||
}
|
||||
|
||||
void PresetUpdater::update_index_db()
|
||||
{
|
||||
p->update_index_db();
|
||||
}
|
||||
void PresetUpdater::add_additional_archive(const std::string& archive_url, const std::string& download_url)
|
||||
{
|
||||
if (std::find_if(m_additional_archives.begin(), m_additional_archives.end(), [archive_url](const std::pair<std::string, std::string>& it) { return it.first == archive_url; }) == m_additional_archives.end()) {
|
||||
m_additional_archives.emplace_back(archive_url, download_url);
|
||||
}
|
||||
}
|
||||
|
||||
void PresetUpdater::add_additional_archives(const std::vector<std::pair<std::string, std::string>>& archives)
|
||||
{
|
||||
for (const auto& pair : archives) {
|
||||
add_additional_archive(pair.first, pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -10,16 +10,16 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/event.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
class VendorProfile;
|
||||
typedef std::map<std::string, VendorProfile> VendorMap;
|
||||
class AppConfig;
|
||||
class PresetBundle;
|
||||
class Semver;
|
||||
class PresetUpdaterUIStatus;
|
||||
|
||||
typedef std::vector<const GUI::ArchiveRepository*> SharedArchiveRepositoryVector;
|
||||
typedef std::vector<const ArchiveRepository*> SharedArchiveRepositoryVector;
|
||||
|
||||
static constexpr const int SLIC3R_VERSION_BODY_MAX = 256;
|
||||
|
||||
@ -33,14 +33,7 @@ public:
|
||||
PresetUpdater &operator=(const PresetUpdater &) = delete;
|
||||
~PresetUpdater();
|
||||
|
||||
// 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, wxEvtHandler* evt_handler, SharedArchiveRepositoryVector&& repositories);
|
||||
void cancel_sync();
|
||||
|
||||
void sync_blocking(const PresetBundle* preset_bundle, wxEvtHandler* evt_handler, const SharedArchiveRepositoryVector& repositories);
|
||||
|
||||
// If version check is enabled, check if chaced online slic3r version is newer, notify if so.
|
||||
void slic3r_update_notify();
|
||||
void sync_blocking(const VendorMap& vendors, const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status);
|
||||
|
||||
enum UpdateResult {
|
||||
R_NOOP,
|
||||
@ -55,35 +48,26 @@ public:
|
||||
enum class UpdateParams {
|
||||
SHOW_TEXT_BOX, // force modal textbox
|
||||
SHOW_NOTIFICATION, // only shows notification
|
||||
FORCED_BEFORE_WIZARD // indicates that check of updated is forced before ConfigWizard opening
|
||||
FORCED_BEFORE_WIZARD, // indicates that check of updated is forced before ConfigWizard opening
|
||||
SHOW_TEXT_BOX_YES_NO // like first option but different buttons in dialog
|
||||
};
|
||||
|
||||
// If updating is enabled, check if updates are available in cache, if so, ask about installation.
|
||||
// A false return value implies Slic3r should exit due to incompatibility of configuration.
|
||||
// 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 SharedArchiveRepositoryVector& repositories) const;
|
||||
UpdateResult config_update(const Semver &old_slic3r_version, UpdateParams params, const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status) const;
|
||||
|
||||
void update_index_db();
|
||||
|
||||
// "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, const SharedArchiveRepositoryVector& repositories, bool snapshot = true) const;
|
||||
bool install_bundles_rsrc_or_cache_vendor(std::vector<std::string> bundles, const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status, bool snapshot = true) const;
|
||||
|
||||
void on_update_notification_confirm(const SharedArchiveRepositoryVector& repositories);
|
||||
void on_update_notification_confirm(const SharedArchiveRepositoryVector& repositories, PresetUpdaterUIStatus* ui_status);
|
||||
|
||||
bool version_check_enabled() const;
|
||||
|
||||
void add_additional_archive(const std::string& archive_url, const std::string& download_url);
|
||||
void add_additional_archives(const std::vector<std::pair<std::string, std::string>>& archives);
|
||||
private:
|
||||
struct priv;
|
||||
std::unique_ptr<priv> p;
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> m_additional_archives;
|
||||
};
|
||||
|
||||
//wxDECLARE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent);
|
||||
//wxDECLARE_EVENT(EVT_SLIC3R_EXPERIMENTAL_VERSION_ONLINE, wxCommandEvent);
|
||||
wxDECLARE_EVENT(EVT_CONFIG_UPDATER_SYNC_DONE, wxCommandEvent);
|
||||
}
|
||||
#endif
|
||||
|
354
src/slic3r/Utils/PresetUpdaterWrapper.cpp
Normal file
354
src/slic3r/Utils/PresetUpdaterWrapper.cpp
Normal file
@ -0,0 +1,354 @@
|
||||
#include "PresetUpdaterWrapper.hpp"
|
||||
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Semver.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
wxDEFINE_EVENT(EVT_PRESET_UPDATER_STATUS_END, PresetUpdaterStatusSimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_PRESET_UPDATER_STATUS_PRINT, PresetUpdaterStatusMessageEvent);
|
||||
wxDEFINE_EVENT(EVT_CONFIG_UPDATER_SYNC_DONE, wxCommandEvent);
|
||||
|
||||
PresetUpdaterWrapper::PresetUpdaterWrapper()
|
||||
: m_preset_updater(std::make_unique<PresetUpdater>())
|
||||
, m_preset_archive_database(std::make_unique<PresetArchiveDatabase>())
|
||||
{
|
||||
}
|
||||
PresetUpdaterWrapper::~PresetUpdaterWrapper()
|
||||
{
|
||||
if (m_worker_thread.joinable()) {
|
||||
if (m_ui_status)
|
||||
m_ui_status->set_canceled(true);
|
||||
m_worker_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetUpdaterWrapper::wizard_sync(const PresetBundle* preset_bundle, const Semver& old_slic3r_version, wxWindow* parent, bool full_sync, const wxString& headline)
|
||||
{
|
||||
assert(!m_modal_thread.joinable());
|
||||
// Cancel sync before starting wizard to prevent two downloads at same time.
|
||||
cancel_worker_thread();
|
||||
PresetUpdaterUIStatus* ui_status = new PresetUpdaterUIStatus(PresetUpdaterUIStatus::PresetUpdaterRetryPolicy::PURP_5_TRIES);
|
||||
Slic3r::ScopeGuard sg([ui_status]() { delete ui_status; });
|
||||
GUI::ProgressUpdaterDialog* dialog = new GUI::ProgressUpdaterDialog(ui_status, parent, headline);
|
||||
ui_status->set_handler(dialog);
|
||||
VendorMap vendors_copy = preset_bundle->vendors;
|
||||
auto worker_body = [ui_status, this, vendors_copy, full_sync]()
|
||||
{
|
||||
if (!m_preset_archive_database->sync_blocking(ui_status)) {
|
||||
ui_status->end();
|
||||
return;
|
||||
}
|
||||
if (ui_status->get_canceled()) { ui_status->end(); return; }
|
||||
|
||||
if (full_sync) {
|
||||
// Since there might be new repos, we need to sync preset updater
|
||||
const SharedArchiveRepositoryVector &repos = m_preset_archive_database->get_selected_archive_repositories();
|
||||
m_preset_updater->sync_blocking(vendors_copy, repos, ui_status);
|
||||
if (ui_status->get_canceled()) { ui_status->end(); return; }
|
||||
m_preset_updater->update_index_db();
|
||||
}
|
||||
ui_status->end();
|
||||
};
|
||||
m_modal_thread = std::thread(worker_body);
|
||||
// We need to call ShowModal here instead of prompting it from event callback.
|
||||
// Otherwise UI thread would freez on job_thread.join();
|
||||
dialog->CenterOnParent();
|
||||
dialog->ShowModal();
|
||||
m_modal_thread.join();
|
||||
parent->RemoveChild(dialog);
|
||||
dialog->Destroy();
|
||||
ui_status->set_handler(nullptr);
|
||||
|
||||
// Only now it is possible to work with ui_status, that was previously used in worker thread.
|
||||
|
||||
if (std::string s = ui_status->get_error(); !s.empty()) {
|
||||
std::string err_text = GUI::format(_u8L("Failed to download %1%"), ui_status->get_target());
|
||||
GUI::ErrorDialog err_msg(nullptr, err_text + "\n\n" + s, false);
|
||||
err_msg.ShowModal();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Should m_preset_updater->config_update run even if there is cancel?
|
||||
if (ui_status->get_canceled() /*&& !full_sync*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Offer update installation.
|
||||
if (full_sync) {
|
||||
const SharedArchiveRepositoryVector &repos = m_preset_archive_database->get_selected_archive_repositories();
|
||||
m_preset_updater->config_update(old_slic3r_version, PresetUpdater::UpdateParams::SHOW_TEXT_BOX_YES_NO, repos, ui_status);
|
||||
}
|
||||
bool res = !ui_status->get_canceled();
|
||||
return res;
|
||||
}
|
||||
|
||||
PresetUpdater::UpdateResult PresetUpdaterWrapper::check_updates_on_user_request(const PresetBundle* preset_bundle, const Semver& old_slic3r_version, wxWindow* parent)
|
||||
{
|
||||
assert(!m_modal_thread.joinable());
|
||||
cancel_worker_thread();
|
||||
PresetUpdaterUIStatus* ui_status = new PresetUpdaterUIStatus(PresetUpdaterUIStatus::PresetUpdaterRetryPolicy::PURP_5_TRIES);
|
||||
Slic3r::ScopeGuard sg([ui_status]() { delete ui_status; });
|
||||
// TRN: Headline of Progress dialog
|
||||
GUI::ProgressUpdaterDialog* dialog = new GUI::ProgressUpdaterDialog(ui_status, parent, _L("Checking for Configuration Updates"));
|
||||
ui_status->set_handler(dialog);
|
||||
VendorMap vendors_copy = preset_bundle->vendors;
|
||||
std::string failed_paths;
|
||||
PresetUpdater::UpdateResult updater_result = PresetUpdater::UpdateResult::R_ALL_CANCELED;
|
||||
auto worker_body = [ui_status, this, vendors_copy, &failed_paths]()
|
||||
{
|
||||
if (!m_preset_archive_database->sync_blocking(ui_status)) {
|
||||
ui_status->end();
|
||||
return;
|
||||
}
|
||||
if (ui_status->get_canceled()) { ui_status->end(); return; }
|
||||
m_preset_archive_database->extract_archives_with_check(failed_paths);
|
||||
const SharedArchiveRepositoryVector &repos = m_preset_archive_database->get_selected_archive_repositories();
|
||||
m_preset_updater->sync_blocking(vendors_copy, repos, ui_status);
|
||||
if (ui_status->get_canceled()) { ui_status->end(); return; }
|
||||
|
||||
m_preset_updater->update_index_db();
|
||||
ui_status->end();
|
||||
};
|
||||
|
||||
m_modal_thread = std::thread(worker_body);
|
||||
// We need to call ShowModal here instead of prompting it from event callback.
|
||||
// Otherwise UI thread would freez on job_thread.join();
|
||||
dialog->CenterOnParent();
|
||||
dialog->ShowModal();
|
||||
m_modal_thread.join();
|
||||
parent->RemoveChild(dialog);
|
||||
dialog->Destroy();
|
||||
ui_status->set_handler(nullptr);
|
||||
|
||||
// Only now it is possible to work with ui_status, that was previously used in worker thread.
|
||||
|
||||
if (std::string s = ui_status->get_error(); !s.empty()) {
|
||||
std::string err_text = GUI::format(_u8L("Failed to download %1%"), ui_status->get_target());
|
||||
GUI::ErrorDialog err_msg(nullptr, s, false);
|
||||
err_msg.ShowModal();
|
||||
return PresetUpdater::UpdateResult::R_ALL_CANCELED;
|
||||
}
|
||||
|
||||
if (ui_status->get_canceled()) {
|
||||
return PresetUpdater::UpdateResult::R_ALL_CANCELED;
|
||||
}
|
||||
|
||||
if (!failed_paths.empty()) {
|
||||
int cnt = std::count(failed_paths.begin(), failed_paths.end(), '\n') + 1;
|
||||
// TRN: %1% contains paths from which loading failed. They are separated by \n, there is no \n at the end.
|
||||
failed_paths = GUI::format(_L_PLURAL("It was not possible to extract data from %1%. The source will not be updated.",
|
||||
"It was not possible to extract data for following local sources. They will not be updated.\n\n %1%", cnt), failed_paths);
|
||||
GUI::ErrorDialog err_msg(nullptr, failed_paths, false);
|
||||
err_msg.ShowModal();
|
||||
}
|
||||
// preset_updater::config_update does show wxDialog
|
||||
updater_result = m_preset_updater->config_update(old_slic3r_version, PresetUpdater::UpdateParams::SHOW_TEXT_BOX, m_preset_archive_database->get_selected_archive_repositories(), ui_status);
|
||||
return updater_result;
|
||||
}
|
||||
|
||||
PresetUpdater::UpdateResult PresetUpdaterWrapper::check_updates_on_startup(const Semver& old_slic3r_version)
|
||||
{
|
||||
if (m_modal_thread.joinable()) {
|
||||
return PresetUpdater::UpdateResult::R_ALL_CANCELED;
|
||||
}
|
||||
PresetUpdaterUIStatus ui_status(PresetUpdaterUIStatus::PresetUpdaterRetryPolicy::PURP_NO_RETRY);
|
||||
// preset_updater::config_update does show wxDialog
|
||||
m_preset_updater->update_index_db();
|
||||
return m_preset_updater->config_update(old_slic3r_version, PresetUpdater::UpdateParams::SHOW_NOTIFICATION, m_preset_archive_database->get_selected_archive_repositories(), &ui_status);
|
||||
}
|
||||
|
||||
void PresetUpdaterWrapper::on_update_notification_confirm()
|
||||
{
|
||||
if (m_modal_thread.joinable()) {
|
||||
return;
|
||||
}
|
||||
PresetUpdaterUIStatus ui_status(PresetUpdaterUIStatus::PresetUpdaterRetryPolicy::PURP_NO_RETRY);
|
||||
// preset_updater::on_update_notification_confirm does show wxDialog
|
||||
const SharedArchiveRepositoryVector &repos = m_preset_archive_database->get_selected_archive_repositories();
|
||||
m_preset_updater->on_update_notification_confirm(repos, &ui_status);
|
||||
}
|
||||
|
||||
bool PresetUpdaterWrapper::install_bundles_rsrc_or_cache_vendor(std::vector<std::string> bundles, bool snapshot/* = true*/) const
|
||||
{
|
||||
PresetUpdaterUIStatus ui_status(PresetUpdaterUIStatus::PresetUpdaterRetryPolicy::PURP_NO_RETRY);
|
||||
const SharedArchiveRepositoryVector &repos = m_preset_archive_database->get_selected_archive_repositories();
|
||||
return m_preset_updater->install_bundles_rsrc_or_cache_vendor(bundles, repos, &ui_status, snapshot);
|
||||
}
|
||||
|
||||
void PresetUpdaterWrapper::sync_preset_updater(wxEvtHandler* end_evt_handler, const PresetBundle* preset_bundle)
|
||||
{
|
||||
cancel_worker_thread();
|
||||
m_ui_status = new PresetUpdaterUIStatus(PresetUpdaterUIStatus::PresetUpdaterRetryPolicy::PURP_NO_RETRY);
|
||||
VendorMap vendors_copy = preset_bundle->vendors;
|
||||
|
||||
auto worker_body = [ this, vendors_copy, end_evt_handler]()
|
||||
{
|
||||
const SharedArchiveRepositoryVector &repos = m_preset_archive_database->get_selected_archive_repositories();
|
||||
m_preset_updater->sync_blocking(vendors_copy, repos, this->m_ui_status);
|
||||
if (this->m_ui_status->get_canceled()) { return; }
|
||||
wxCommandEvent* evt = new wxCommandEvent(EVT_CONFIG_UPDATER_SYNC_DONE);
|
||||
wxQueueEvent(end_evt_handler, evt);
|
||||
};
|
||||
|
||||
m_worker_thread = std::thread(worker_body);
|
||||
}
|
||||
|
||||
void PresetUpdaterWrapper::cancel_worker_thread()
|
||||
{
|
||||
if (m_worker_thread.joinable()) {
|
||||
if (m_ui_status) {
|
||||
m_ui_status->set_canceled(true);
|
||||
} else assert(true);
|
||||
|
||||
m_worker_thread.join();
|
||||
|
||||
if (m_ui_status) {
|
||||
delete m_ui_status;
|
||||
m_ui_status = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::map<PresetUpdaterUIStatus::PresetUpdaterRetryPolicy, HttpRetryOpt> PresetUpdaterUIStatus::policy_map = {
|
||||
{PresetUpdaterUIStatus::PresetUpdaterRetryPolicy::PURP_5_TRIES, {500ms, 5s, 4}},
|
||||
{PresetUpdaterUIStatus::PresetUpdaterRetryPolicy::PURP_NO_RETRY, {0ms}}
|
||||
};
|
||||
PresetUpdaterUIStatus::PresetUpdaterUIStatus(PresetUpdaterUIStatus::PresetUpdaterRetryPolicy policy)
|
||||
{
|
||||
if (auto it = policy_map.find(policy); it != policy_map.end()) {
|
||||
m_retry_policy = it->second;
|
||||
} else {
|
||||
assert(true);
|
||||
m_retry_policy = {0ms};
|
||||
}
|
||||
}
|
||||
bool PresetUpdaterUIStatus::on_attempt(int attempt, unsigned delay)
|
||||
{
|
||||
if (attempt == 1) {
|
||||
// TRN: Text of progress dialog. %1% is a name of file.
|
||||
set_status(GUI::format_wxstr(_L("Downloading Resources: %1%"), m_target));
|
||||
} else {
|
||||
// TRN: Text of progress dialog. %1% is a name of file. %2% is a number of attept.
|
||||
set_status(GUI::format_wxstr(_L("Downloading Resources: %1%. Attempt %2%."), m_target, std::to_string(attempt)));
|
||||
}
|
||||
return get_canceled();
|
||||
}
|
||||
void PresetUpdaterUIStatus::set_target(const std::string& target)
|
||||
{
|
||||
m_target = target;
|
||||
}
|
||||
void PresetUpdaterUIStatus::set_status(const wxString& status)
|
||||
{
|
||||
if (m_evt_handler)
|
||||
wxQueueEvent(m_evt_handler, new PresetUpdaterStatusMessageEvent(EVT_PRESET_UPDATER_STATUS_PRINT, status));
|
||||
}
|
||||
|
||||
void PresetUpdaterUIStatus::end()
|
||||
{
|
||||
if (m_evt_handler)
|
||||
wxQueueEvent(m_evt_handler, new PresetUpdaterStatusSimpleEvent(EVT_PRESET_UPDATER_STATUS_END));
|
||||
}
|
||||
|
||||
namespace GUI {
|
||||
ProgressUpdaterDialog::ProgressUpdaterDialog(PresetUpdaterUIStatus* ui_status, wxWindow* parent, const wxString first_line)
|
||||
// TRN: Text of progress dialog.
|
||||
:wxGenericProgressDialog(first_line, _L("Initializing"), 100, parent, wxPD_AUTO_HIDE|wxPD_APP_MODAL|wxPD_CAN_ABORT)
|
||||
, PresetUpdaterUIStatusCancel(ui_status)
|
||||
{
|
||||
SetMinSize(wxSize(32 * wxGetApp().em_unit(),12 * wxGetApp().em_unit()));
|
||||
Bind(EVT_PRESET_UPDATER_STATUS_END, &ProgressUpdaterDialog::on_end, this);
|
||||
Bind(EVT_PRESET_UPDATER_STATUS_PRINT, &ProgressUpdaterDialog::on_set_status, this);
|
||||
}
|
||||
ProgressUpdaterDialog::~ProgressUpdaterDialog()
|
||||
{
|
||||
}
|
||||
void ProgressUpdaterDialog::on_set_status(const PresetUpdaterStatusMessageEvent& evt)
|
||||
{
|
||||
if (!Pulse(evt.data)) {
|
||||
set_cancel(true);
|
||||
}
|
||||
}
|
||||
void ProgressUpdaterDialog::on_end(const PresetUpdaterStatusSimpleEvent& evt)
|
||||
{
|
||||
EndModal(0);
|
||||
}
|
||||
#if 0
|
||||
CommonUpdaterDialog::CommonUpdaterDialog(PresetUpdaterUIStatus* ui_status, wxWindow* parent, const wxString first_line, int milisecond_until_cancel_shown)
|
||||
: wxDialog(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxFRAME_FLOAT_ON_PARENT)
|
||||
, PresetUpdaterUIStatusCancel(ui_status)
|
||||
{
|
||||
auto* headline = new wxStaticText(this, wxID_ANY, first_line, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);
|
||||
m_status_text = new wxStaticText(this, wxID_ANY, _L("Initializing..."), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);
|
||||
m_cancel_button = new wxButton(this, wxID_CANCEL, "Cancel");
|
||||
// Layout using sizer
|
||||
wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
hsizer->Add(m_status_text, 1, wxALIGN_CENTER_VERTICAL | wxALL, 10);
|
||||
hsizer->Add(m_cancel_button, 0, wxALIGN_CENTER_VERTICAL | wxALL, 10);
|
||||
wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL);
|
||||
vsizer->Add(headline, 0, wxALIGN_CENTER | wxALL, 10);
|
||||
vsizer->Add(hsizer, 0, wxEXPAND | wxALL, 5);
|
||||
this->SetSizer(vsizer);
|
||||
SetMinSize(wxSize(wxGetApp().em_unit() * 40, wxGetApp().em_unit() * 5));
|
||||
m_cancel_button->Bind(wxEVT_BUTTON, [this](const wxCommandEvent& event) {
|
||||
set_cancel(true);
|
||||
m_status_text->SetLabel("Canceling...");
|
||||
Update();
|
||||
Fit();
|
||||
});
|
||||
|
||||
if (milisecond_until_cancel_shown > 0) {
|
||||
m_cancel_button->Show(false);
|
||||
m_show_cancel_timer = new wxTimer(this);
|
||||
Bind(wxEVT_TIMER, [this](wxTimerEvent&)
|
||||
{
|
||||
m_cancel_button->Show();
|
||||
Layout();
|
||||
Fit();
|
||||
});
|
||||
m_show_cancel_timer->StartOnce(milisecond_until_cancel_shown);
|
||||
}
|
||||
|
||||
Bind(EVT_PRESET_UPDATER_STATUS_END, &CommonUpdaterDialog::on_end, this);
|
||||
Bind(EVT_PRESET_UPDATER_STATUS_PRINT, &CommonUpdaterDialog::on_set_status, this);
|
||||
|
||||
#ifdef _WIN32
|
||||
wxGetApp().UpdateDlgDarkUI(this);
|
||||
#endif
|
||||
Fit();
|
||||
}
|
||||
CommonUpdaterDialog::~CommonUpdaterDialog()
|
||||
{
|
||||
if (m_show_cancel_timer) {
|
||||
m_show_cancel_timer->Stop();
|
||||
delete m_show_cancel_timer;
|
||||
}
|
||||
}
|
||||
void CommonUpdaterDialog::on_set_status(const PresetUpdaterStatusMessageEvent& evt)
|
||||
{
|
||||
m_status_text->SetLabel(evt.data);
|
||||
Update();
|
||||
Fit();
|
||||
}
|
||||
void CommonUpdaterDialog::on_end(const PresetUpdaterStatusSimpleEvent& evt)
|
||||
{
|
||||
EndModal(0);
|
||||
}
|
||||
|
||||
DummyPresetUpdaterUIStatusHandler::DummyPresetUpdaterUIStatusHandler()
|
||||
:wxEvtHandler()
|
||||
{
|
||||
Bind(EVT_PRESET_UPDATER_STATUS_END, &DummyPresetUpdaterUIStatusHandler::on_end, this);
|
||||
Bind(EVT_PRESET_UPDATER_STATUS_PRINT, &DummyPresetUpdaterUIStatusHandler::on_set_status, this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
215
src/slic3r/Utils/PresetUpdaterWrapper.hpp
Normal file
215
src/slic3r/Utils/PresetUpdaterWrapper.hpp
Normal file
@ -0,0 +1,215 @@
|
||||
#ifndef slic3r_PresetUpdateWrapper_hpp_
|
||||
#define slic3r_PresetUpdateWrapper_hpp_
|
||||
|
||||
#include "slic3r/GUI/PresetArchiveDatabase.hpp"
|
||||
#include "slic3r/GUI/ConfigWizard.hpp"
|
||||
#include "slic3r/GUI/Event.hpp"
|
||||
#include "slic3r/Utils/PresetUpdater.hpp"
|
||||
#include "slic3r/Utils/Http.hpp"
|
||||
|
||||
#include <wx/event.h>
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/button.h>
|
||||
#include <wx/progdlg.h>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
using PresetUpdaterStatusSimpleEvent = GUI::SimpleEvent;
|
||||
using PresetUpdaterStatusMessageEvent = GUI::Event<wxString>;
|
||||
wxDECLARE_EVENT(EVT_PRESET_UPDATER_STATUS_END, PresetUpdaterStatusSimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_PRESET_UPDATER_STATUS_PRINT, PresetUpdaterStatusMessageEvent);
|
||||
wxDECLARE_EVENT(EVT_CONFIG_UPDATER_SYNC_DONE, wxCommandEvent);
|
||||
class PresetBundle;
|
||||
class Semver;
|
||||
|
||||
// class that is passed to inner thread function.
|
||||
// Each call from inner thread triggers event, that is handled by wx object on UI thread (m_evt_handler).
|
||||
// Communication in opposite direction is done via pointer that should use only set_canceled. (PresetUpdaterUIStatusCancel)
|
||||
class PresetUpdaterUIStatus
|
||||
{
|
||||
public:
|
||||
enum class PresetUpdaterRetryPolicy
|
||||
{
|
||||
PURP_5_TRIES,
|
||||
PURP_NO_RETRY,
|
||||
};
|
||||
// called from PresetUpdaterWrapper
|
||||
PresetUpdaterUIStatus(PresetUpdaterUIStatus::PresetUpdaterRetryPolicy policy);
|
||||
~PresetUpdaterUIStatus(){}
|
||||
void set_handler(wxEvtHandler* evt_handler) {m_evt_handler = evt_handler;}
|
||||
|
||||
// called from worker thread
|
||||
bool on_attempt(int attempt, unsigned delay);
|
||||
void set_target(const std::string& target);
|
||||
void set_status(const wxString& status);
|
||||
void end();
|
||||
bool get_canceled() const {return m_canceled.load(); }
|
||||
HttpRetryOpt get_retry_policy() const { return m_retry_policy; }
|
||||
std::string get_error() const { return m_error_msg; }
|
||||
std::string get_target() const { return m_target; }
|
||||
|
||||
// called from PresetUpdaterUIStatusCancel (ui thread)
|
||||
void set_canceled(bool val) { m_canceled.store(val); }
|
||||
void set_error(const std::string& msg) { m_error_msg = msg; }
|
||||
private:
|
||||
wxEvtHandler* m_evt_handler {nullptr};
|
||||
std::atomic<bool> m_canceled {false};
|
||||
std::string m_error_msg;
|
||||
|
||||
std::string m_target;
|
||||
|
||||
HttpRetryOpt m_retry_policy;
|
||||
static const std::map<PresetUpdaterUIStatus::PresetUpdaterRetryPolicy, HttpRetryOpt> policy_map;
|
||||
};
|
||||
|
||||
// Purpose of this class:
|
||||
// Serves as a hub a entering 2 classes: PresetArchiveDatabase and PresetUpdater
|
||||
// PresetUpdater:
|
||||
// - Does not contain outside getters / setters
|
||||
// - Sync function can be run in worker thread
|
||||
// ! other functions like config_update does show modal dialogs or notification and must be run in UI tread
|
||||
// PresetArchiveDatabase:
|
||||
// - Many functions gets or sets its inner data
|
||||
// ! Including sync function
|
||||
// - Does not use direct UI components f.e. dialog
|
||||
// This class is accessible via wxGetApp().get_preset_updater_wrapper()
|
||||
// but it should be done only in certain cases:
|
||||
// 1) Sync of PresetUpdater
|
||||
// - Runs on worker thread
|
||||
// - Is called only during startup
|
||||
// - Needs to be canceled before other operations
|
||||
// - Ends by queueing EVT_CONFIG_UPDATER_SYNC_DONE
|
||||
// 2) Callbacks of EVT_CONFIG_UPDATER_SYNC_DONE
|
||||
// - Needs to be run in UI thread
|
||||
// - Might chain (evt -> PresetUpdater function -> notification -> Plater -> PresetUpdater function -> dialog)
|
||||
// 3) Check of update triggered by user
|
||||
// - Runs most of the operations in own thread while having Modal Dialog for user
|
||||
// - Used before and inside Config Wizard or when Check for Config Updates
|
||||
// - Might use UI thread PresetUpdater functions after its thread is done
|
||||
// - The inner thread is stored as m_modal_thread due to
|
||||
// 4) Config Wizard run
|
||||
// - Config Wizard often needs to get or set data of PresetArchiveDatabase
|
||||
// - Config Wizard runs in UI thread as Modal Dialog
|
||||
// Possibility of conflicts:
|
||||
// 1 x 2 - No conflict due 2 being triggered only by end of 1
|
||||
// 1 x 3 - No conflict due 3 calling Cancel on 1 before runing
|
||||
// 1 x 4 - No conflict due 4 run after 3
|
||||
// 2 x 2 - All 2 functions does create modal window and are triggered by ui buttons - ui thread might work on other events but ui should be inaccessible
|
||||
// 2 x 3 - If 1 finnished (2 starts) and 3 is triggered by user - both are triggered via events
|
||||
// - If order of events is event triggering 3 first and then event queued by 1 is second
|
||||
// - 2 would run when inner thread of 3 changes data - Therefor functions of 2 must check if inner thread of 3 (m_modal_thread) is joinable
|
||||
// 2 x 4 - No conflict due 2 and 4 run on both UI thread
|
||||
// 3 x 4 - No conflict due either 3 blocking ui or even calling 4 only after it finnishes
|
||||
|
||||
class PresetUpdaterWrapper
|
||||
{
|
||||
public:
|
||||
PresetUpdaterWrapper();
|
||||
~PresetUpdaterWrapper();
|
||||
|
||||
// 1) Sync of PresetUpdater functions
|
||||
// runs worker thread and leaves
|
||||
void sync_preset_updater(wxEvtHandler* end_evt_handler, const PresetBundle* preset_bundle);
|
||||
|
||||
// 2) Callbacks of EVT_CONFIG_UPDATER_SYNC_DONE
|
||||
// Runs on UI thread
|
||||
PresetUpdater::UpdateResult check_updates_on_startup(const Semver& old_slic3r_version);
|
||||
void on_update_notification_confirm();
|
||||
|
||||
// 3) Check of update triggered by user
|
||||
// runs own thread but blocks until its done
|
||||
bool wizard_sync(const PresetBundle* preset_bundle, const Semver& old_slic3r_version, wxWindow* parent, bool full_sync, const wxString& headline);
|
||||
PresetUpdater::UpdateResult check_updates_on_user_request(const PresetBundle* preset_bundle, const Semver& old_slic3r_version, wxWindow* parent);
|
||||
|
||||
// 4) Config Wizard run
|
||||
// These function are either const reading from m_preset_archive_database,
|
||||
// Or sets inner data of m_preset_archive_database
|
||||
// problem would be if at same time worker thread runs m_preset_archive_database->sync_blocking
|
||||
bool is_selected_repository_by_id(const std::string& repo_id) const { return m_preset_archive_database->is_selected_repository_by_id(repo_id); }
|
||||
bool is_selected_repository_by_uuid(const std::string& uuid) const { return m_preset_archive_database->is_selected_repository_by_uuid(uuid); }
|
||||
SharedArchiveRepositoryVector get_all_archive_repositories() const { return m_preset_archive_database->get_all_archive_repositories(); }
|
||||
SharedArchiveRepositoryVector get_selected_archive_repositories() const { return m_preset_archive_database->get_selected_archive_repositories();}
|
||||
const std::map<std::string, bool>& get_selected_repositories_uuid() const { return m_preset_archive_database->get_selected_repositories_uuid(); }
|
||||
bool set_selected_repositories(const std::vector<std::string>& used_uuids, std::string& msg) { return m_preset_archive_database->set_selected_repositories(used_uuids, msg); }
|
||||
void set_installed_printer_repositories(const std::vector<std::string> &used_ids) { m_preset_archive_database->set_installed_printer_repositories(used_ids); }
|
||||
void remove_local_archive(const std::string& uuid) { m_preset_archive_database->remove_local_archive(uuid); }
|
||||
std::string add_local_archive(const boost::filesystem::path path, std::string& msg) { return m_preset_archive_database->add_local_archive(path, msg); }
|
||||
|
||||
bool install_bundles_rsrc_or_cache_vendor(std::vector<std::string> bundles, bool snapshot = true) const ;
|
||||
|
||||
private:
|
||||
void cancel_worker_thread();
|
||||
|
||||
// Do not share these 2 out of PresetUpdaterWrapper
|
||||
std::unique_ptr<PresetArchiveDatabase> m_preset_archive_database;
|
||||
std::unique_ptr<PresetUpdater> m_preset_updater;
|
||||
|
||||
// m_worker_thread runs on background while m_modal_thread runs only when modal window exists.
|
||||
std::thread m_worker_thread;
|
||||
PresetUpdaterUIStatus* m_ui_status {nullptr};
|
||||
std::thread m_modal_thread;
|
||||
};
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class PresetUpdaterUIStatusCancel
|
||||
{
|
||||
public:
|
||||
PresetUpdaterUIStatusCancel(PresetUpdaterUIStatus* ui_status) : p_ui_status(ui_status) {}
|
||||
~PresetUpdaterUIStatusCancel() {}
|
||||
void set_cancel(bool c) {p_ui_status->set_canceled(c);}
|
||||
private:
|
||||
PresetUpdaterUIStatus* p_ui_status;
|
||||
};
|
||||
|
||||
class ProgressUpdaterDialog : public wxGenericProgressDialog, public PresetUpdaterUIStatusCancel
|
||||
{
|
||||
public:
|
||||
ProgressUpdaterDialog(PresetUpdaterUIStatus* ui_status, wxWindow* parent, const wxString first_line);
|
||||
~ProgressUpdaterDialog();
|
||||
void on_set_status(const PresetUpdaterStatusMessageEvent& evt);
|
||||
void on_end(const PresetUpdaterStatusSimpleEvent& evt);
|
||||
private:
|
||||
};
|
||||
|
||||
#if 0
|
||||
// basic dialog
|
||||
class CommonUpdaterDialog : public wxDialog, public PresetUpdaterUIStatusCancel
|
||||
{
|
||||
public:
|
||||
CommonUpdaterDialog(PresetUpdaterUIStatus* ui_status, wxWindow* parent, const wxString first_line, int milisecond_until_cancel_shown);
|
||||
~CommonUpdaterDialog();
|
||||
void on_set_status(const PresetUpdaterStatusMessageEvent& evt);
|
||||
void on_end(const PresetUpdaterStatusSimpleEvent& evt);
|
||||
private:
|
||||
wxStaticText* m_status_text;
|
||||
wxButton* m_cancel_button;
|
||||
wxTimer* m_show_cancel_timer {nullptr};
|
||||
};
|
||||
|
||||
// testing purpose dummy class
|
||||
class DummyPresetUpdaterUIStatusHandler : public wxEvtHandler
|
||||
{
|
||||
public:
|
||||
DummyPresetUpdaterUIStatusHandler();
|
||||
~DummyPresetUpdaterUIStatusHandler() {}
|
||||
void on_set_status(const PresetUpdaterStatusMessageEvent& evt) {}
|
||||
void on_end(const PresetUpdaterStatusSimpleEvent& evt)
|
||||
{
|
||||
if(m_end_callback)
|
||||
m_end_callback();
|
||||
}
|
||||
void set_end_callback(std::function<void(void)> callback) {m_end_callback = callback; }
|
||||
private:
|
||||
std::function<void(void)> m_end_callback;
|
||||
};
|
||||
#endif
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
#endif //slic3r_PresetUpdateWrapper_hpp_
|
@ -23,31 +23,6 @@ namespace pt = boost::property_tree;
|
||||
namespace Slic3r {
|
||||
namespace
|
||||
{
|
||||
/*std::string escape_string(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;
|
||||
}
|
||||
std::string escape_path_by_element(const boost::filesystem::path& path)
|
||||
{
|
||||
std::string ret_val = escape_string(path.filename().string());
|
||||
boost::filesystem::path parent(path.parent_path());
|
||||
while (!parent.empty() && parent.string() != "/") // "/" check is for case "/file.gcode" was inserted. Then boost takes "/" as parent_path.
|
||||
{
|
||||
ret_val = escape_string(parent.filename().string()) + "/" + ret_val;
|
||||
parent = parent.parent_path();
|
||||
}
|
||||
return ret_val;
|
||||
}*/
|
||||
|
||||
boost::optional<std::string> get_error_message_from_response_body(const std::string& body)
|
||||
{
|
||||
@ -112,19 +87,6 @@ bool PrusaConnectNew::init_upload(PrintHostUpload upload_data, std::string& out)
|
||||
const std::string upload_filename = upload_data.upload_path.filename().string();
|
||||
std::string url = GUI::format("%1%/app/users/teams/%2%/uploads", get_host(), m_team_id);
|
||||
std::string request_body_json = upload_data.data_json;
|
||||
// GUI::format(
|
||||
// "{"
|
||||
// "\"filename\": \"%1%\", "
|
||||
// "\"size\": %2%, "
|
||||
// "\"path\": \"%3%\", "
|
||||
// "\"force\": true, "
|
||||
// "\"printer_uuid\": \"%4%\""
|
||||
// "}"
|
||||
// , upload_filename
|
||||
// , file_size
|
||||
// , upload_data.upload_path.generic_string()
|
||||
// , m_uuid
|
||||
//);
|
||||
|
||||
// replace plaholder filename
|
||||
assert(request_body_json.find("%1%") != std::string::npos);
|
||||
@ -189,20 +151,10 @@ bool PrusaConnectNew::upload(PrintHostUpload upload_data, ProgressFn progress_fn
|
||||
}
|
||||
const std::string name = get_name();
|
||||
const std::string access_token = GUI::wxGetApp().plater()->get_user_account()->get_access_token();
|
||||
// const std::string escaped_upload_path = upload_data.storage + "/" + escape_path_by_element(upload_data.upload_path.string());
|
||||
// const std::string set_ready = upload_data.set_ready.empty() ? "" : "&set_ready=" + upload_data.set_ready;
|
||||
// const std::string position = upload_data.position.empty() ? "" : "&position=" + upload_data.position;
|
||||
// const std::string wait_until = upload_data.wait_until.empty() ? "" : "&wait_until=" + upload_data.wait_until;
|
||||
const std::string url = GUI::format(
|
||||
"%1%/app/teams/%2%/files/raw"
|
||||
"?upload_id=%3%"
|
||||
// "&force=true"
|
||||
// "&printer_uuid=%4%"
|
||||
// "&path=%5%"
|
||||
// "%6%"
|
||||
// "%7%"
|
||||
// "%8%"
|
||||
, get_host(), m_team_id, upload_id/*, m_uuid, escaped_upload_path, set_ready, position, wait_until*/);
|
||||
, get_host(), m_team_id, upload_id);
|
||||
bool res = true;
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user