diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index 35916377b..51557af0c 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -8,6 +8,7 @@ name = Prusa Research config_version = 0.8.0-beta # Where to get the updates from? config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/ +changelog_url = http://files.prusa3d.com/?latest=slicer-profiles&lng=%1% # The printer models will be shown by the Configuration Wizard in this order, # also the first model installed & the first nozzle installed will be activated after install. diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp index 6fb3da5a6..3f3054373 100644 --- a/src/slic3r/GUI/Preset.cpp +++ b/src/slic3r/GUI/Preset.cpp @@ -127,11 +127,16 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem res.config_version = std::move(*config_version); } - auto config_update_url = vendor_section.find("config_update_url"); + const auto config_update_url = vendor_section.find("config_update_url"); if (config_update_url != vendor_section.not_found()) { res.config_update_url = config_update_url->second.data(); } + const auto changelog_url = vendor_section.find("changelog_url"); + if (changelog_url != vendor_section.not_found()) { + res.changelog_url = changelog_url->second.data(); + } + if (! load_all) { return res; } diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp index bac1bfc4f..8fd1652a8 100644 --- a/src/slic3r/GUI/Preset.hpp +++ b/src/slic3r/GUI/Preset.hpp @@ -44,6 +44,7 @@ public: std::string id; Semver config_version; std::string config_update_url; + std::string changelog_url; struct PrinterVariant { PrinterVariant() {} diff --git a/src/slic3r/GUI/UpdateDialogs.cpp b/src/slic3r/GUI/UpdateDialogs.cpp index 99e630cff..252bd64d2 100644 --- a/src/slic3r/GUI/UpdateDialogs.cpp +++ b/src/slic3r/GUI/UpdateDialogs.cpp @@ -1,5 +1,8 @@ #include "UpdateDialogs.hpp" +#include +#include + #include #include #include @@ -21,7 +24,11 @@ namespace Slic3r { namespace GUI { -static const std::string CONFIG_UPDATE_WIKI_URL("https://github.com/prusa3d/Slic3r/wiki/Slic3r-PE-1.40-configuration-update"); +static const char* URL_CHANGELOG = "http://files.prusa3d.com/file/?type=slicerstable&lng=%1%"; +static const char* URL_DOWNLOAD = "https://www.prusa3d.com/downloads&lng=%1%"; +static const char* URL_DEV = "https://github.com/prusa3d/PrusaSlicer/releases/tag/version_%1%"; + +static const std::string CONFIG_UPDATE_WIKI_URL("https://github.com/prusa3d/PrusaSlicer/wiki/Slic3r-PE-1.40-configuration-update"); // MsgUpdateSlic3r @@ -31,15 +38,8 @@ MsgUpdateSlic3r::MsgUpdateSlic3r(const Semver &ver_current, const Semver &ver_on ver_current(ver_current), ver_online(ver_online) { - const auto url = wxString::Format("https://github.com/prusa3d/Slic3r/releases/tag/version_%s", ver_online.to_string()); - auto *link = new wxHyperlinkCtrl(this, wxID_ANY, url, url); - - auto *text = new wxStaticText(this, wxID_ANY, _(L("To download, follow the link below."))); - const auto link_width = link->GetSize().GetWidth(); - const int content_width = CONTENT_WIDTH * wxGetApp().em_unit(); - text->Wrap(content_width > link_width ? content_width : link_width); - content_sizer->Add(text); - content_sizer->AddSpacer(VERT_SPACING); + const auto version = Semver::parse(SLIC3R_VERSION); + const bool dev_version = version->prerelease() != nullptr; auto *versions = new wxFlexGridSizer(2, 0, VERT_SPACING); versions->Add(new wxStaticText(this, wxID_ANY, _(L("Current version:")))); @@ -49,7 +49,25 @@ MsgUpdateSlic3r::MsgUpdateSlic3r(const Semver &ver_current, const Semver &ver_on content_sizer->Add(versions); content_sizer->AddSpacer(VERT_SPACING); - content_sizer->Add(link); + if (dev_version) { + const std::string url = (boost::format(URL_DEV) % ver_online.to_string()).str(); + const wxString url_wx = from_u8(url); + auto *link = new wxHyperlinkCtrl(this, wxID_ANY, _(L("Changelog && Download")), url_wx); + content_sizer->Add(link); + } else { + const auto lang_code = wxGetApp().current_language_code().ToStdString(); + + const std::string url_log = (boost::format(URL_CHANGELOG) % lang_code).str(); + const wxString url_log_wx = from_u8(url_log); + auto *link_log = new wxHyperlinkCtrl(this, wxID_ANY, _(L("Open changelog page")), url_log_wx); + content_sizer->Add(link_log); + + const std::string url_dw = (boost::format(URL_DOWNLOAD) % lang_code).str(); + const wxString url_dw_wx = from_u8(url_dw); + auto *link_dw = new wxHyperlinkCtrl(this, wxID_ANY, _(L("Open download page")), url_dw_wx); + content_sizer->Add(link_dw); + } + content_sizer->AddSpacer(2*VERT_SPACING); cbox = new wxCheckBox(this, wxID_ANY, _(L("Don't notify about new releases any more"))); @@ -69,7 +87,7 @@ bool MsgUpdateSlic3r::disable_version_check() const // MsgUpdateConfig -MsgUpdateConfig::MsgUpdateConfig(const std::unordered_map &updates) : +MsgUpdateConfig::MsgUpdateConfig(const std::vector &updates) : MsgDialog(nullptr, _(L("Configuration update")), _(L("Configuration update is available")), wxID_NONE) { auto *text = new wxStaticText(this, wxID_ANY, _(L( @@ -82,12 +100,31 @@ MsgUpdateConfig::MsgUpdateConfig(const std::unordered_mapAdd(text); content_sizer->AddSpacer(VERT_SPACING); - auto *versions = new wxFlexGridSizer(2, 0, VERT_SPACING); + const auto lang_code = wxGetApp().current_language_code().ToStdString(); + + auto *versions = new wxBoxSizer(wxVERTICAL); for (const auto &update : updates) { - auto *text_vendor = new wxStaticText(this, wxID_ANY, update.first); + auto *flex = new wxFlexGridSizer(2, 0, VERT_SPACING); + + auto *text_vendor = new wxStaticText(this, wxID_ANY, update.vendor); text_vendor->SetFont(boldfont); - versions->Add(text_vendor); - versions->Add(new wxStaticText(this, wxID_ANY, update.second)); + flex->Add(text_vendor); + flex->Add(new wxStaticText(this, wxID_ANY, update.version.to_string())); + + if (! update.comment.empty()) { + flex->Add(new wxStaticText(this, wxID_ANY, _(L("Comment:"))), 0, wxALIGN_RIGHT); + flex->Add(new wxStaticText(this, wxID_ANY, from_u8(update.comment))); + } + + versions->Add(flex); + + if (! update.changelog_url.empty()) { + auto *line = new wxBoxSizer(wxHORIZONTAL); + auto changelog_url = (boost::format(update.changelog_url) % lang_code).str(); + line->AddSpacer(3*VERT_SPACING); + line->Add(new wxHyperlinkCtrl(this, wxID_ANY, _(L("Open changelog page")), changelog_url)); + versions->Add(line); + } } content_sizer->Add(versions); diff --git a/src/slic3r/GUI/UpdateDialogs.hpp b/src/slic3r/GUI/UpdateDialogs.hpp index 62548b98b..2a580e251 100644 --- a/src/slic3r/GUI/UpdateDialogs.hpp +++ b/src/slic3r/GUI/UpdateDialogs.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "slic3r/Utils/Semver.hpp" #include "MsgDialog.hpp" @@ -40,8 +41,22 @@ private: class MsgUpdateConfig : public MsgDialog { public: - // updates is a map of "vendor name" -> "version (comment)" - MsgUpdateConfig(const std::unordered_map &updates); + struct Update + { + std::string vendor; + Semver version; + std::string comment; + std::string changelog_url; + + Update(std::string vendor, Semver version, std::string comment, std::string changelog_url) + : vendor(std::move(vendor)) + , version(std::move(version)) + , comment(std::move(comment)) + , changelog_url(std::move(changelog_url)) + {} + }; + + MsgUpdateConfig(const std::vector &updates); MsgUpdateConfig(MsgUpdateConfig &&) = delete; MsgUpdateConfig(const MsgUpdateConfig &) = delete; MsgUpdateConfig &operator=(MsgUpdateConfig &&) = delete; diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 1128df29c..dbed76492 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -50,15 +50,17 @@ struct Update fs::path source; fs::path target; Version version; + std::string vendor; + std::string changelog_url; - Update(fs::path &&source, fs::path &&target, const Version &version) : - source(std::move(source)), - target(std::move(target)), - version(version) + Update(fs::path &&source, fs::path &&target, const Version &version, std::string vendor, std::string changelog_url) + : source(std::move(source)) + , target(std::move(target)) + , version(version) + , vendor(std::move(vendor)) + , changelog_url(std::move(changelog_url)) {} - std::string name() const { return source.stem().string(); } - friend std::ostream& operator<<(std::ostream& os , const Update &self) { os << "Update(" << self.source.string() << " -> " << self.target.string() << ')'; return os; @@ -69,14 +71,14 @@ struct Incompat { fs::path bundle; Version version; + std::string vendor; - Incompat(fs::path &&bundle, const Version &version) : - bundle(std::move(bundle)), - version(version) + Incompat(fs::path &&bundle, const Version &version, std::string vendor) + : bundle(std::move(bundle)) + , version(version) + , vendor(std::move(vendor)) {} - std::string name() const { return bundle.stem().string(); } - friend std::ostream& operator<<(std::ostream& os , const Incompat &self) { os << "Incompat(" << self.bundle.string() << ')'; return os; @@ -351,7 +353,7 @@ Updates PresetUpdater::priv::get_config_updates() const } // Perform a basic load and check the version - const auto vp = VendorProfile::from_ini(bundle_path, false); + auto vp = VendorProfile::from_ini(bundle_path, false); // Getting a recommended version from the latest index, wich may have been downloaded // from the internet, or installed / updated from the installation resources. @@ -376,7 +378,7 @@ Updates PresetUpdater::priv::get_config_updates() const if (ver_current_found && !ver_current->is_current_slic3r_supported()) { BOOST_LOG_TRIVIAL(warning) << "Current Slic3r incompatible with installed bundle: " << bundle_path.string(); - updates.incompats.emplace_back(std::move(bundle_path), *ver_current); + updates.incompats.emplace_back(std::move(bundle_path), *ver_current, vp.name); } else if (recommended->config_version > vp.config_version) { // Config bundle update situation @@ -406,12 +408,12 @@ Updates PresetUpdater::priv::get_config_updates() const auto new_vp = VendorProfile::from_ini(path_src, false); bool found = false; if (new_vp.config_version == recommended->config_version) { - updates.updates.emplace_back(std::move(path_src), std::move(bundle_path), *recommended); + updates.updates.emplace_back(std::move(path_src), std::move(bundle_path), *recommended, vp.name, vp.changelog_url); found = true; } else if (! path_in_rsrc.empty() && fs::exists(path_in_rsrc)) { new_vp = VendorProfile::from_ini(path_in_rsrc, false); if (new_vp.config_version == recommended->config_version) { - updates.updates.emplace_back(std::move(path_in_rsrc), std::move(bundle_path), *recommended); + updates.updates.emplace_back(std::move(path_in_rsrc), std::move(bundle_path), *recommended, vp.name, vp.changelog_url); found = true; } } @@ -560,6 +562,7 @@ void PresetUpdater::slic3r_update_notify() p->enabled_version_check = false; } } + app_config->set("version_online_seen", ver_online_str); } } @@ -574,8 +577,6 @@ bool PresetUpdater::config_update() const std::unordered_map incompats_map; for (const auto &incompat : updates.incompats) { - auto vendor = incompat.name(); - const auto min_slic3r = incompat.version.min_slic3r_version; const auto max_slic3r = incompat.version.max_slic3r_version; wxString restrictions; @@ -590,7 +591,7 @@ bool PresetUpdater::config_update() const restrictions = wxString::Format(_(L("requires max. %s")), max_slic3r.to_string()); } - incompats_map.emplace(std::make_pair(std::move(vendor), std::move(restrictions))); + incompats_map.emplace(std::make_pair(incompat.vendor, std::move(restrictions))); } p->had_config_update = true; // This needs to be done before a dialog is shown because of OnIdle() + CallAfter() in Perl @@ -613,19 +614,15 @@ bool PresetUpdater::config_update() const else if (updates.updates.size() > 0) { BOOST_LOG_TRIVIAL(info) << boost::format("Update of %1% bundles available. Asking for confirmation ...") % updates.updates.size(); - std::unordered_map updates_map; + std::vector updates_msg; for (const auto &update : updates.updates) { - auto vendor = update.name(); - auto ver_str = update.version.config_version.to_string(); - if (! update.version.comment.empty()) { - ver_str += std::string(" (") + update.version.comment + ")"; - } - updates_map.emplace(std::make_pair(std::move(vendor), std::move(ver_str))); + std::string changelog_url = update.version.config_version.prerelease() == nullptr ? update.changelog_url : std::string(); + updates_msg.emplace_back(update.vendor, update.version.config_version, update.version.comment, std::move(changelog_url)); } p->had_config_update = true; // Ditto, see above - GUI::MsgUpdateConfig dlg(std::move(updates_map)); + GUI::MsgUpdateConfig dlg(updates_msg); const auto res = dlg.ShowModal(); if (res == wxID_OK) { @@ -655,7 +652,7 @@ void PresetUpdater::install_bundles_rsrc(std::vector bundles, bool for (const auto &bundle : bundles) { auto path_in_rsrc = p->rsrc_path / bundle; auto path_in_vendors = p->vendor_path / bundle; - updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version()); + updates.updates.emplace_back(std::move(path_in_rsrc), std::move(path_in_vendors), Version(), "", ""); } p->perform_updates(std::move(updates), snapshot);