Ask Before Migrating User Filament Presets to Their Legacy Printers

Instead of giving user presets their parent's 2.4.2 printers in memory,
detect the user presets that inherit their parent's compatible_printers
and are missing printers from the legacy map, and offer to migrate them
at startup or from Help > Migrate Filament Presets.

Migrating first backs up the user folder to
filament_preset_migration_<datetime>_backup.zip in the configuration
folder, and migrates nothing if that fails. It then writes the printers
into each preset's compatible_printers, patching only that key so the
preset keeps the parent name it was saved with and older releases can
still resolve it. Cloud-synced presets are marked for upload.

No asks again at the next launch; "Don't remind me again" stops the
startup prompt.
This commit is contained in:
Hanif Koh
2026-10-12 18:18:41 +08:00
parent e55ac357b5
commit 65e97cddd2
15 changed files with 430 additions and 90 deletions
+64 -20
View File
@@ -81,6 +81,7 @@
#include "LifecycleEvents.hpp"
#include "Utils.hpp"
#include "InstanceLock.hpp"
#include "nlohmann/json.hpp"
#include <sstream>
#include "PlaceholderParser.hpp"
@@ -932,14 +933,10 @@ bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const Pre
return true;
}
}
const std::vector<std::string> &legacy = preset.preset.legacy_compatible_printers;
auto is_legacy_printer = [&legacy](const std::string &name) { return std::find(legacy.begin(), legacy.end(), name) != legacy.end(); };
return preset.preset.is_default || active_printer.preset.name.empty() || !has_compatible_printers ||
std::find(compatible_printers->values.begin(), compatible_printers->values.end(), active_printer.preset.name) !=
compatible_printers->values.end() ||
(!active_printer.preset.is_system && is_compatible_with_parent_printer(preset, active_printer)) ||
is_legacy_printer(active_printer.preset.name) ||
(!active_printer.preset.is_system && is_legacy_printer(active_printer.preset.inherits()));
(!active_printer.preset.is_system && is_compatible_with_parent_printer(preset, active_printer));
}
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer)
@@ -2745,27 +2742,80 @@ const Preset *PresetCollection::system_parent_with_inherited_printers(const Pres
return own != nullptr && inherited != nullptr && own->values == inherited->values ? parent : nullptr;
}
void PresetCollection::set_legacy_compatible_printers(const std::map<std::string, std::vector<std::string>> &printers_by_parent)
std::vector<LegacyPrinterMigration> PresetCollection::legacy_printer_migrations(const std::map<std::string, std::vector<std::string>> &printers_by_parent) const
{
lock();
for (Preset &preset : m_presets) {
preset.legacy_compatible_printers.clear();
std::vector<LegacyPrinterMigration> migrations;
for (const Preset &preset : m_presets) {
const Preset *parent = system_parent_with_inherited_printers(preset);
if (parent == nullptr)
continue;
// An empty list already covers every printer.
const std::vector<std::string> &own = preset.config.option<ConfigOptionStrings>("compatible_printers")->values;
if (own.empty())
continue;
// The map names the parent as it was when the map was written; a later rename keeps that name in renamed_from.
auto it = printers_by_parent.find(parent->name);
for (auto old_name = parent->renamed_from.begin(); it == printers_by_parent.end() && old_name != parent->renamed_from.end(); ++old_name)
it = printers_by_parent.find(*old_name);
if (it == printers_by_parent.end())
continue;
preset.legacy_compatible_printers = it->second;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": user preset " << preset.name << " keeps " << it->second.size()
<< " printer(s) its parent " << parent->name << " listed in an older release";
LegacyPrinterMigration migration{preset.name, parent->name, {}};
for (const std::string &printer : it->second)
if (std::find(own.begin(), own.end(), printer) == own.end())
migration.printers.push_back(printer);
if (!migration.printers.empty())
migrations.push_back(std::move(migration));
}
if (m_idx_selected < m_presets.size() && m_edited_preset.name == m_presets[m_idx_selected].name)
m_edited_preset.legacy_compatible_printers = m_presets[m_idx_selected].legacy_compatible_printers;
return migrations;
}
bool PresetCollection::apply_legacy_printer_migration(const LegacyPrinterMigration &migration)
{
lock();
auto it = this->find_preset_internal(migration.preset);
if (it == m_presets.end() || it->name != migration.preset || system_parent_with_inherited_printers(*it) == nullptr) {
unlock();
return false;
}
Preset &preset = *it;
std::vector<std::string> printers = preset.config.option<ConfigOptionStrings>("compatible_printers")->values;
for (const std::string &printer : migration.printers)
if (std::find(printers.begin(), printers.end(), printer) == printers.end())
printers.push_back(printer);
const bool selected = m_idx_selected == static_cast<size_t>(it - m_presets.begin());
unlock();
// Only compatible_printers changes in the file. Saving the whole preset would also rewrite an inherits that
// names a renamed parent by its old name, the only name older releases know it by.
{
InstanceLock instance_lock(user_presets_lock_path());
try {
boost::nowide::ifstream in(preset.file);
json j = json::parse(in);
j["compatible_printers"] = printers;
if (const std::error_code ec = write_file_atomically(preset.file, j.dump(1, '\t'))) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": failed to save " << preset.file << ": " << ec.message();
return false;
}
} catch (const std::exception &err) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": can not migrate " << preset.file << ": " << err.what();
return false;
}
}
lock();
preset.config.option<ConfigOptionStrings>("compatible_printers")->values = printers;
if (selected)
m_edited_preset.config.option<ConfigOptionStrings>("compatible_printers", true)->values = printers;
unlock();
// Push the change to the cloud copy, as an edit in the settings tab would.
if (!preset.setting_id.empty()) {
preset.sync_info = "update";
preset.save_info();
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": user preset " << preset.name << " gets " << migration.printers.size()
<< " printer(s) its parent listed in an older release";
return true;
}
//BBS: validate_preset
@@ -3121,7 +3171,6 @@ bool PresetCollection::clone_presets(std::vector<Preset const *> const &presets,
preset.vendor = nullptr;
preset.renamed_from.clear();
preset.m_excluded_from.clear();
preset.legacy_compatible_printers.clear();
preset.setting_id.clear();
preset.inherits().clear();
preset.is_default = false;
@@ -3259,9 +3308,6 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
preset.m_excluded_from.clear();
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(": save preset %1% , with detach")%new_name;
}
// Legacy printers belong only to a preset that still inherits its system parent's printer list.
if (system_parent_with_inherited_printers(preset) == nullptr)
preset.legacy_compatible_printers.clear();
//BBS: add lock logic for sync preset in background
if (m_type == Preset::TYPE_PRINT)
@@ -3314,8 +3360,6 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
}
else
preset.is_project_embedded = false;
if (system_parent_with_inherited_printers(preset) == nullptr)
preset.legacy_compatible_printers.clear();
if (m_type == Preset::TYPE_PRINT)
preset.config.option<ConfigOptionString>("print_settings_id", true)->value = new_name;
else if (m_type == Preset::TYPE_FILAMENT)
+16 -9
View File
@@ -311,10 +311,6 @@ public:
// certain printer models defined in the vendor profile as well, in this case we want to hide this generic preset for these printer models.
std::set<std::string> m_excluded_from;
// Printers a user filament preset is also compatible with because its system parent listed them in
// an older release; see PresetCollection::set_legacy_compatible_printers().
std::vector<std::string> legacy_compatible_printers;
// Orca: flag to indicate if this preset is from Orca Filament Library
bool m_from_orca_filament_lib = false;
@@ -555,6 +551,14 @@ struct PresetConfigSubstitutions {
// PrusaSlicer and reading the user Print / Filament / Printer profiles.
using PresetsConfigSubstitutions = std::vector<PresetConfigSubstitutions>;
// A user filament preset that no longer shows on printers its system parent listed in an older release,
// and those printers. Migrating it writes them into the preset's own compatible_printers.
struct LegacyPrinterMigration {
std::string preset;
std::string parent;
std::vector<std::string> printers;
};
// Collections of presets of the same type (one of the Print, Filament or Printer type).
class PresetCollection
{
@@ -606,10 +610,13 @@ public:
bool load_user_preset(std::string name, std::map<std::string, std::string> preset_values, PresetsConfigSubstitutions& substitutions, ForwardCompatibilitySubstitutionRule rule, const PresetOrigin &load_origin = PresetOrigin(PresetOrigin::Kind::User));
void update_after_user_presets_loaded();
// User presets store only their diff, so a user preset inherits its system parent's compatible_printers
// and disappears from a printer once a profile update narrows that list. Give each user preset that
// inherits the list the printers its parent covered in an older release (printers_by_parent, keyed by the
// parent's current name), so it keeps showing on the printers it was made for.
void set_legacy_compatible_printers(const std::map<std::string, std::vector<std::string>> &printers_by_parent);
// and disappears from a printer once a profile update narrows that list. Lists the user presets that
// inherit the list and the printers their parent covered in an older release (printers_by_parent, keyed
// by the parent's name then) but no longer lists.
std::vector<LegacyPrinterMigration> legacy_printer_migrations(const std::map<std::string, std::vector<std::string>> &printers_by_parent) const;
// Adds the migration's printers to the preset's own compatible_printers and saves the preset to disk.
// False if the preset no longer inherits its parent's list or could not be saved.
bool apply_legacy_printer_migration(const LegacyPrinterMigration &migration);
//BBS: get user presets
int get_user_presets(PresetBundle *preset_bundle, std::vector<Preset> &result_presets);
void set_sync_info_and_save(std::string name, std::string setting_id, std::string syncinfo, long long update_time, const std::string& user_id);
@@ -903,7 +910,7 @@ public:
protected:
// The system parent of a user preset whose compatible_printers is the parent's, or nullptr: the presets
// set_legacy_compatible_printers() gives legacy printers to.
// legacy_printer_migrations() considers.
const Preset* system_parent_with_inherited_printers(const Preset &preset) const;
PresetCollection() = default;
+52 -3
View File
@@ -2,6 +2,7 @@
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/directory.hpp>
#include <boost/filesystem/file_status.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/optional/optional.hpp>
#include <boost/algorithm/string/split.hpp>
@@ -39,6 +40,8 @@
#include "ParallelResolve.hpp"
#include "Preset.hpp"
#include "PresetCacheFormat.hpp"
#include "Time.hpp"
#include "Zipper.hpp"
#include "PrintConfig.hpp"
#include "PublishSettings.hpp"
#include "FilamentMixer.hpp"
@@ -918,7 +921,6 @@ PresetsConfigSubstitutions PresetBundle::load_presets(AppConfig &config, Forward
// raw vendor-JSON references instead of the silently-repaired ones.
if (!validation_mode)
this->normalize_compatible_presets();
filaments.set_legacy_compatible_printers(legacy_compatible_printers());
this->update_multi_material_filament_presets();
this->update_compatible(PresetSelectCompatibleType::Never);
@@ -1075,6 +1077,55 @@ bool PresetBundle::backup_user_folder() const
}
}
bool PresetBundle::backup_user_folder_to_zip(const std::string &zip_path) const
{
const fs::path user_dir = fs::path(data_dir()) / PRESET_USER_DIR;
BOOST_LOG_TRIVIAL(info) << "Backing up user folder to: " << zip_path;
try {
Zipper zipper(zip_path);
// Directories get their own entries, which extract_archive_confined() needs to recreate them.
zipper.add_entry(std::string(PRESET_USER_DIR) + "/", nullptr, 0);
for (const fs::directory_entry &entry : fs::recursive_directory_iterator(user_dir)) {
const std::string name = (fs::path(PRESET_USER_DIR) / entry.path().lexically_relative(user_dir)).generic_string();
if (fs::is_directory(entry.status())) {
zipper.add_entry(name + "/", nullptr, 0);
continue;
}
if (!fs::is_regular_file(entry.status()))
continue;
boost::nowide::ifstream in(entry.path().string(), std::ios::binary);
const std::string data((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
if (!in.good() && !in.eof())
throw Slic3r::RuntimeError("can not read " + entry.path().string());
zipper.add_entry(name, data.data(), data.size());
}
zipper.finalize();
return true;
} catch (const std::exception &ex) {
BOOST_LOG_TRIVIAL(error) << "Exception during user folder backup: " << ex.what();
boost::system::error_code ec;
fs::remove(zip_path, ec);
return false;
}
}
std::vector<LegacyPrinterMigration> PresetBundle::legacy_printer_migrations() const
{
return filaments.legacy_printer_migrations(legacy_compatible_printers());
}
std::string PresetBundle::migrate_legacy_printers(const std::vector<LegacyPrinterMigration> &migrations, std::vector<std::string> &failed)
{
const std::string zip_path = data_dir() + "/filament_preset_migration_" +
Utils::time2str(Utils::TimeZone::utc, Utils::TimeFormat::iso8601Z) + "_backup.zip";
if (!backup_user_folder_to_zip(zip_path))
return {};
for (const LegacyPrinterMigration &migration : migrations)
if (!filaments.apply_legacy_printer_migration(migration))
failed.push_back(migration.preset);
return zip_path;
}
std::optional<FilamentBaseInfo> PresetBundle::get_filament_by_filament_id(const std::string& filament_id, const std::string& printer_name) const
{
if (filament_id.empty())
@@ -1547,7 +1598,6 @@ PresetsConfigSubstitutions PresetBundle::load_user_presets(AppConfig &
// Rewrite renamed compatible references in synced user presets before compatibility is evaluated.
this->normalize_compatible_presets();
filaments.set_legacy_compatible_printers(legacy_compatible_printers());
this->update_multi_material_filament_presets();
this->update_compatible(PresetSelectCompatibleType::Never);
@@ -2554,7 +2604,6 @@ PresetsConfigSubstitutions PresetBundle::update_subscribed_presets(
// Rewrite renamed compatible references in synced user presets before compatibility is evaluated.
this->normalize_compatible_presets();
filaments.set_legacy_compatible_printers(legacy_compatible_printers());
this->update_multi_material_filament_presets();
this->update_compatible(PresetSelectCompatibleType::Never);
+10
View File
@@ -376,6 +376,16 @@ public:
bool use_bbl_device_tab();
bool backup_user_folder() const;
// Writes the user preset folder into a zip archive at zip_path, its entries under "user/".
bool backup_user_folder_to_zip(const std::string &zip_path) const;
// User filament presets that no longer show on printers their parent listed in an older release
// (resources/info/legacy_compatible_printers.json).
std::vector<LegacyPrinterMigration> legacy_printer_migrations() const;
// Backs up the user preset folder into a zip in data_dir(), then writes each migration's printers into its
// preset file. Returns the zip's path, or an empty string when the backup failed and nothing was migrated.
// The presets that could not be migrated are added to failed.
std::string migrate_legacy_printers(const std::vector<LegacyPrinterMigration> &migrations, std::vector<std::string> &failed);
//BBS: project embedded preset logic
PresetsConfigSubstitutions load_project_embedded_presets(std::vector<Preset*> project_presets, ForwardCompatibilitySubstitutionRule substitution_rule);
+2
View File
@@ -362,6 +362,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Lazy.hpp
GUI/LazyPage.cpp
GUI/LazyPage.hpp
GUI/LegacyPrinterMigrationDialog.cpp
GUI/LegacyPrinterMigrationDialog.hpp
GUI/LibVGCode/LibVGCodeWrapper.hpp
GUI/LibVGCode/LibVGCodeWrapper.cpp
GUI/LinuxDisplayBackend.cpp
+47
View File
@@ -12,6 +12,7 @@
#include "DeviceManager.hpp"
#include "HMS.hpp"
#include "PresetBundleDialog.hpp"
#include "LegacyPrinterMigrationDialog.hpp"
#include "WebUserLoginDialog.hpp"
#include "WebViewDialog.hpp"
#include "slic3r/Utils/BBLCloudServiceAgent.hpp"
@@ -1109,6 +1110,8 @@ void GUI_App::post_init()
}
this->check_new_version_sf();
if (!cw_showed)
this->check_legacy_printer_migration(false);
const auto cloud_provider = get_printer_cloud_provider();
if (is_user_login(cloud_provider) && !app_config->get_stealth_mode()) {
// this->check_privacy_version(0);
@@ -6822,6 +6825,50 @@ void GUI_App::reload_settings()
}
}
void GUI_App::check_legacy_printer_migration(bool by_user)
{
const std::vector<LegacyPrinterMigration> migrations = preset_bundle->legacy_printer_migrations();
if (migrations.empty()) {
if (by_user)
MessageDialog(mainframe, _L("All your filament presets are available on the printers they were made for."),
_L("Migrate Filament Presets"), wxOK | wxICON_INFORMATION).ShowModal();
return;
}
if (!by_user && app_config->get_bool("legacy_printer_migration_dont_remind"))
return;
LegacyPrinterMigrationDialog dlg(mainframe, migrations, !by_user);
const bool migrate = dlg.ShowModal() == wxID_YES;
if (dlg.dont_remind())
app_config->set_bool("legacy_printer_migration_dont_remind", true);
if (!migrate)
return;
std::vector<std::string> failed;
const std::string backup = preset_bundle->migrate_legacy_printers(migrations, failed);
if (backup.empty()) {
show_error(mainframe, _L("Your presets could not be backed up, so they were not migrated."));
return;
}
preset_bundle->update_compatible(PresetSelectCompatibleType::Never);
mainframe->update_side_preset_ui();
for (auto tab : tabs_list) {
tab->reload_config();
tab->update_changed_ui();
}
if (plater_)
plater_->sidebar().update_all_preset_comboboxes();
wxString message = format_wxstr(_L("Your filament presets were migrated. Select them again in the filament list where you used them.\n\n"
"A backup of your presets was saved to:\n%1%"), backup);
if (!failed.empty()) {
message += "\n\n" + _L("These presets could not be migrated:");
for (const std::string &name : failed)
message += "\n" + from_u8(name);
}
MessageDialog(mainframe, message, _L("Migrate Filament Presets"), wxOK | (failed.empty() ? wxICON_INFORMATION : wxICON_WARNING)).ShowModal();
}
//BBS reload when logout
void GUI_App::remove_user_presets()
{
+4
View File
@@ -568,6 +568,10 @@ public:
void check_update(bool show_tips, int by_user);
void check_new_version(bool show_tips = false, int by_user = 0);
void check_new_version_sf(bool show_tips = false, int by_user = 0);
// Offers to migrate user filament presets that lost printers their parent listed in an older release.
// At startup it asks once per release unless the user chose not to be reminded; by_user also reports
// when there is nothing to migrate.
void check_legacy_printer_migration(bool by_user);
bool process_network_msg(std::string dev_id, std::string msg);
void request_new_version(int by_user);
void enter_force_upgrade();
@@ -0,0 +1,96 @@
#include "LegacyPrinterMigrationDialog.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
#include "GUI_Utils.hpp"
#include "I18N.hpp"
#include "MainFrame.hpp"
#include "format.hpp"
#include "libslic3r/Preset.hpp"
#include "Widgets/Button.hpp"
#include "Widgets/CheckBox.hpp"
#include "Widgets/DialogButtons.hpp"
#include "Widgets/Label.hpp"
#include <wx/event.h>
#include <wx/gdicmn.h>
#include <wx/sizer.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/toplevel.h>
#include <string>
#include <vector>
namespace Slic3r { namespace GUI {
LegacyPrinterMigrationDialog::LegacyPrinterMigrationDialog(wxWindow *parent, const std::vector<LegacyPrinterMigration> &migrations,
bool offer_dont_remind)
: DPIDialog(parent ? parent : static_cast<wxWindow *>(wxGetApp().mainframe), wxID_ANY, _L("Migrate Filament Presets"),
wxDefaultPosition, wxDefaultSize, wxCAPTION | wxCLOSE_BOX)
{
SetBackgroundColour(*wxWHITE);
SetFont(Label::Body_14);
auto *sizer = new wxBoxSizer(wxVERTICAL);
auto *message = new Label(this,
_L("Since OrcaSlicer 2.5.0, filament presets have been restructured to support more features. Some of your "
"presets need to be migrated to the new structure, or they will no longer be available for some of your "
"printers.\n\n"
"Would you like to migrate them now? Your presets will be backed up first, and this only needs to be done "
"once. You can also do it later from Help > Migrate Filament Presets."),
0);
message->Wrap(FromDIP(520));
sizer->Add(message, 0, wxEXPAND | wxALL, FromDIP(15));
sizer->Add(new Label(this, _L("Affected presets:")), 0, wxLEFT | wxRIGHT, FromDIP(15));
sizer->AddSpacer(FromDIP(5));
wxString details;
for (const LegacyPrinterMigration &migration : migrations) {
details += format_wxstr(_L("%1% (based on %2%)"), migration.preset, migration.parent) + "\n";
for (const std::string &printer : migration.printers)
details += " " + from_u8(printer) + "\n";
}
auto *list = new wxTextCtrl(this, wxID_ANY, details, wxDefaultPosition, wxSize(-1, FromDIP(220)),
wxTE_MULTILINE | wxTE_READONLY | wxTE_DONTWRAP);
sizer->Add(list, 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(15));
if (offer_dont_remind) {
auto *dont_remind_sizer = new wxBoxSizer(wxHORIZONTAL);
m_dont_remind = new ::CheckBox(this);
auto *dont_remind_label = new Label(this, _L("Don't remind me again"));
dont_remind_label->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) {
m_dont_remind->SetValue(!m_dont_remind->GetValue());
e.Skip();
});
dont_remind_sizer->Add(m_dont_remind, 0, wxALIGN_CENTER_VERTICAL);
dont_remind_sizer->Add(dont_remind_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(6));
sizer->Add(dont_remind_sizer, 0, wxLEFT | wxRIGHT | wxTOP, FromDIP(15));
}
auto *buttons = new DialogButtons(this, {"Yes", "No"}, "Yes");
buttons->GetYES()->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { EndModal(wxID_YES); });
buttons->GetNO()->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { EndModal(wxID_NO); });
sizer->Add(buttons, 0, wxEXPAND);
SetSizerAndFit(sizer);
CenterOnParent();
wxGetApp().UpdateDlgDarkUI(this);
}
bool LegacyPrinterMigrationDialog::dont_remind() const
{
return m_dont_remind != nullptr && m_dont_remind->GetValue();
}
void LegacyPrinterMigrationDialog::on_dpi_changed(const wxRect &)
{
if (m_dont_remind != nullptr)
m_dont_remind->Rescale();
GetSizer()->SetSizeHints(this);
Refresh();
}
}} // namespace Slic3r::GUI
@@ -0,0 +1,34 @@
#pragma once
#include "GUI_Utils.hpp"
#include <vector>
class CheckBox;
class wxWindow;
class wxRect;
namespace Slic3r {
struct LegacyPrinterMigration;
namespace GUI {
// Lists the user filament presets that no longer show on printers their parent listed in an older
// release, and asks whether to migrate them. ShowModal() returns wxID_YES to migrate. With
// offer_dont_remind it also offers to stop the startup reminder for good.
class LegacyPrinterMigrationDialog : public DPIDialog
{
public:
LegacyPrinterMigrationDialog(wxWindow *parent, const std::vector<LegacyPrinterMigration> &migrations, bool offer_dont_remind);
bool dont_remind() const;
protected:
void on_dpi_changed(const wxRect &suggested_rect) override;
private:
::CheckBox *m_dont_remind{nullptr};
};
}} // namespace Slic3r::GUI
+4
View File
@@ -2827,6 +2827,10 @@ wxMenu* MainFrame::generate_help_menu()
append_menu_item(helpMenu, wxID_ANY, _L("Show Configuration Folder"), _L("Show Configuration Folder"),
[](wxCommandEvent&) { Slic3r::GUI::desktop_open_datadir_folder(); });
append_menu_item(helpMenu, wxID_ANY, _L("Migrate Filament Presets"),
_L("Bring back filament presets that a profile update removed from printers they were made for"),
[](wxCommandEvent&) { wxGetApp().check_legacy_printer_migration(true); });
helpMenu->AppendSeparator();
// Troubleshoot center
+4
View File
@@ -589,6 +589,10 @@ std::vector<NativeCommand> build_command_catalog()
Slic3r::GUI::desktop_open_datadir_folder();
return AppActionRunResult{AppActionRunResult::Level::Success};
});
add("help_migrate_filament_presets", L("Migrate Filament Presets"), L("Help"), [](const std::string&) {
wxGetApp().check_legacy_printer_migration(true);
return AppActionRunResult{AppActionRunResult::Level::Success};
});
add("help_troubleshoot", L("Troubleshoot Center"), L("Help"), [](const std::string&) {
wxGetApp().troubleshoot();
return AppActionRunResult{AppActionRunResult::Level::Success};