diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 6e52797275..5d6d8e4a65 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -128,7 +128,8 @@ sub OnInit { # On OSX the UI was not initialized correctly if the wizard was called # before the UI was up and running. $self->CallAfter(sub { - $self->{mainframe}->config_wizard; + # Run the config wizard, don't offer the "reset user profile" checkbox. + $self->{mainframe}->config_wizard(1); }); } diff --git a/lib/Slic3r/GUI/ConfigWizard.pm b/lib/Slic3r/GUI/ConfigWizard.pm index be6fb2575e..a32d345ed0 100644 --- a/lib/Slic3r/GUI/ConfigWizard.pm +++ b/lib/Slic3r/GUI/ConfigWizard.pm @@ -14,13 +14,13 @@ our $wizard = 'Wizard'; $wizard = 'Assistant' if &Wx::wxMAC || &Wx::wxGTK; sub new { - my ($class, $parent, $presets) = @_; + my ($class, $parent, $presets, $fresh_start) = @_; my $self = $class->SUPER::new($parent, -1, "Configuration $wizard"); # initialize an empty repository $self->{config} = Slic3r::Config->new; - my $welcome_page = Slic3r::GUI::ConfigWizard::Page::Welcome->new($self); + my $welcome_page = Slic3r::GUI::ConfigWizard::Page::Welcome->new($self, $fresh_start); $self->add_page($welcome_page); $self->add_page(Slic3r::GUI::ConfigWizard::Page::Firmware->new($self)); $self->add_page(Slic3r::GUI::ConfigWizard::Page::Bed->new($self)); @@ -50,9 +50,13 @@ sub add_page { sub run { my ($self) = @_; - my $result = undef; + my $result; if (Wx::Wizard::RunWizard($self, $self->{pages}[0])) { my $preset_name = $self->{pages}[0]->{preset_name}; + $result = { + preset_name => $preset_name, + reset_user_profile => $self->{pages}[0]->{reset_user_profile} + }; if ($preset_name eq 'Other') { # it would be cleaner to have these defined inside each page class, # in some event getting called before leaving the page @@ -67,9 +71,7 @@ sub run { # set first_layer_bed_temperature to temperature + 5 $self->{config}->set('first_layer_bed_temperature', [ ($self->{config}->bed_temperature->[0] > 0) ? ($self->{config}->bed_temperature->[0] + 5) : 0 ]); - $result = $self->{config}; - } else { - $result = $preset_name; + $result->{config} = $self->{config}; } } $self->Destroy; @@ -266,13 +268,13 @@ sub config { package Slic3r::GUI::ConfigWizard::Page::Welcome; use base 'Slic3r::GUI::ConfigWizard::Page'; use Wx qw(:misc :sizer wxID_FORWARD); -use Wx::Event qw(EVT_ACTIVATE EVT_CHOICE); +use Wx::Event qw(EVT_ACTIVATE EVT_CHOICE EVT_CHECKBOX); sub new { - my $class = shift; - my ($parent) = @_; + my ($class, $parent, $fresh_start) = @_; my $self = $class->SUPER::new($parent, "Welcome to the Slic3r Configuration $wizard", 'Welcome'); $self->{full_wizard_workflow} = 1; + $self->{reset_user_profile} = 0; # Test for the existence of the old config path. my $message_has_legacy; @@ -300,6 +302,10 @@ sub new { $self->{choice} = my $choice = Wx::Choice->new($self, -1, wxDefaultPosition, wxDefaultSize, []); $self->{vsizer}->Add($choice, 0, wxEXPAND | wxTOP | wxBOTTOM, 10); + if (! $fresh_start) { + $self->{reset_checkbox} = Wx::CheckBox->new($self, -1, "Reset user profile, install from scratch"); + $self->{vsizer}->Add($self->{reset_checkbox}, 0, wxEXPAND | wxTOP | wxBOTTOM, 10); + } EVT_CHOICE($parent, $choice, sub { my $sel = $self->{choice}->GetStringSelection; @@ -307,6 +313,12 @@ sub new { $self->set_full_wizard_workflow(($sel eq 'Other') || ($sel eq '')); }); + if (! $fresh_start) { + EVT_CHECKBOX($self, $self->{reset_checkbox}, sub { + $self->{reset_user_profile} = $self->{reset_checkbox}->GetValue(); + }); + } + EVT_ACTIVATE($parent, sub { $self->set_full_wizard_workflow($self->{preset_name} eq 'Other'); }); diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index eae598a09a..952b24aa2d 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -299,7 +299,8 @@ sub _init_menubar { my $helpMenu = Wx::Menu->new; { $self->_append_menu_item($helpMenu, "&Configuration $Slic3r::GUI::ConfigWizard::wizard…", "Run Configuration $Slic3r::GUI::ConfigWizard::wizard", sub { - $self->config_wizard; + # Run the config wizard, offer the "reset user profile" checkbox. + $self->config_wizard(0); }); $helpMenu->AppendSeparator(); $self->_append_menu_item($helpMenu, "Prusa 3D Drivers", 'Open the Prusa3D drivers download page in your browser', sub { @@ -580,7 +581,7 @@ sub export_configbundle { # to auto-install a config bundle on a fresh user account, # but that behavior was not documented and likely buggy. sub load_configbundle { - my ($self, $file) = @_; + my ($self, $file, $reset_user_profile) = @_; return unless $self->check_unsaved_changes; if (!$file) { my $dlg = Wx::FileDialog->new($self, 'Select configuration to load:', @@ -595,7 +596,7 @@ sub load_configbundle { wxTheApp->{app_config}->update_config_dir(dirname($file)); my $presets_imported = 0; - eval { $presets_imported = wxTheApp->{preset_bundle}->load_configbundle($file); }; + eval { $presets_imported = wxTheApp->{preset_bundle}->load_configbundle($file, $reset_user_profile ? 1 : 0); }; Slic3r::GUI::catch_error($self) and return; # Load the currently selected preset into the GUI, update the preset selection box. @@ -616,7 +617,7 @@ sub load_config { } sub config_wizard { - my ($self) = @_; + my ($self, $fresh_start) = @_; # Exit wizard if there are unsaved changes and the user cancels the action. return unless $self->check_unsaved_changes; # Enumerate the profiles bundled with the Slic3r installation under resources/profiles. @@ -632,22 +633,25 @@ sub config_wizard { closedir(DIR); } # Open the wizard. - if (my $config = Slic3r::GUI::ConfigWizard->new($self, \@profiles)->run) { - if (ref($config)) { + if (my $result = Slic3r::GUI::ConfigWizard->new($self, \@profiles, $fresh_start)->run) { + if ($result->{reset_user_profile}) { + eval { wxTheApp->{preset_bundle}->reset(1) }; + } + if (defined $result->{config}) { # Wizard returned a config. Add the config to each of the preset types. for my $tab (values %{$self->{options_tabs}}) { # Select the first visible preset, force. $tab->select_preset(undef, 1); } # Load the config over the previously selected defaults. - $self->load_config($config); + $self->load_config($result->{config}); for my $tab (values %{$self->{options_tabs}}) { # Save the settings under a new name, select the name. $tab->save_preset('My Settings'); } } else { # Wizard returned a name of a preset bundle bundled with the installation. Unpack it. - eval { wxTheApp->{preset_bundle}->load_configbundle($directory . '/' . $config . '.ini'); }; + eval { wxTheApp->{preset_bundle}->load_configbundle($directory . '/' . $result->{preset_name} . '.ini'); }; Slic3r::GUI::catch_error($self) and return; # Load the currently selected preset into the GUI, update the preset selection box. foreach my $tab (values %{$self->{options_tabs}}) { diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index adc996030b..49c999737c 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -263,6 +263,21 @@ PresetCollection::~PresetCollection() m_bitmap_main_frame = nullptr; } +void PresetCollection::reset(bool delete_files) +{ + if (m_presets.size() > 1) { + if (delete_files) { + // Erase the preset files. + for (Preset &preset : m_presets) + if (! preset.is_default && ! preset.is_external) + boost::nowide::remove(preset.file.c_str()); + } + // Don't use m_presets.resize() here as it requires a default constructor for Preset. + m_presets.erase(m_presets.begin() + 1, m_presets.end()); + this->select_preset(0); + } +} + // Load all presets found in dir_path. // Throws an exception on error. void PresetCollection::load_presets(const std::string &dir_path, const std::string &subdir) @@ -501,9 +516,11 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui) std::string preset_name = Preset::remove_suffix_modified(old_label); const Preset *preset = this->find_preset(preset_name, false); assert(preset != nullptr); - std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name; - if (old_label != new_label) - ui->SetString(ui_id, wxString::FromUTF8(new_label.c_str())); + if (preset != nullptr) { + std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name; + if (old_label != new_label) + ui->SetString(ui_id, wxString::FromUTF8(new_label.c_str())); + } } return was_dirty != is_dirty; } diff --git a/xs/src/slic3r/GUI/Preset.hpp b/xs/src/slic3r/GUI/Preset.hpp index bfb7d6e202..b379820175 100644 --- a/xs/src/slic3r/GUI/Preset.hpp +++ b/xs/src/slic3r/GUI/Preset.hpp @@ -116,6 +116,8 @@ public: PresetCollection(Preset::Type type, const std::vector &keys); ~PresetCollection(); + void reset(bool delete_files); + Preset::Type type() const { return m_type; } std::string name() const; const std::deque& operator()() const { return m_presets; } diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 4dc2e56ce2..6454775415 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -69,6 +69,16 @@ PresetBundle::~PresetBundle() delete bitmap.second; } +void PresetBundle::reset(bool delete_files) +{ + // Clear the existing presets, delete their respective files. + this->prints .reset(delete_files); + this->filaments.reset(delete_files); + this->printers .reset(delete_files); + this->filament_presets.clear(); + this->filament_presets.emplace_back(this->filaments.get_selected_preset().name); +} + void PresetBundle::setup_directories() { boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir()); @@ -376,7 +386,8 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const { // 1) Load the config bundle into a temp data. PresetBundle tmp_bundle; - tmp_bundle.load_configbundle(path); + // Load the config bundle, don't save the loaded presets to user profile directory. + tmp_bundle.load_configbundle(path, 0); std::string bundle_name = std::string(" - ") + boost::filesystem::path(path).filename().string(); // 2) Extract active configs from the config bundle, copy them and activate them in this bundle. @@ -430,8 +441,11 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const // Load a config bundle file, into presets and store the loaded presets into separate files // of the local configuration directory. -size_t PresetBundle::load_configbundle(const std::string &path) +size_t PresetBundle::load_configbundle(const std::string &path, unsigned int flags) { + if (flags & LOAD_CFGBNDLE_RESET_USER_PROFILE) + this->reset(flags & LOAD_CFGBNDLE_SAVE); + // 1) Read the complete config file into a boost::property_tree. namespace pt = boost::property_tree; pt::ptree tree; @@ -504,7 +518,9 @@ size_t PresetBundle::load_configbundle(const std::string &path) #endif / presets->name() / file_name).make_preferred(); // Load the preset into the list of presets, save it to disk. - presets->load_preset(file_path.string(), preset_name, std::move(config), false).save(); + Preset &loaded = presets->load_preset(file_path.string(), preset_name, std::move(config), false); + if (flags & LOAD_CFGBNDLE_SAVE) + loaded.save(); ++ presets_loaded; } } diff --git a/xs/src/slic3r/GUI/PresetBundle.hpp b/xs/src/slic3r/GUI/PresetBundle.hpp index 238e7c802b..308785fdab 100644 --- a/xs/src/slic3r/GUI/PresetBundle.hpp +++ b/xs/src/slic3r/GUI/PresetBundle.hpp @@ -15,6 +15,10 @@ public: PresetBundle(); ~PresetBundle(); + // Remove all the presets but the "-- default --". + // Optionally remove all the files referenced by the presets from the user profile directory. + void reset(bool delete_files); + void setup_directories(); // Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets. @@ -51,7 +55,14 @@ public: // Load settings into the provided settings instance. // Activate the presets stored in the config bundle. // Returns the number of presets loaded successfully. - size_t load_configbundle(const std::string &path); + enum { + // Save the profiles, which have been loaded. + LOAD_CFGBNDLE_SAVE = 1, + // Delete all old config profiles before loading. + LOAD_CFGBNDLE_RESET_USER_PROFILE = 2 + }; + // Load the config bundle, store it to the user profile directory by default. + size_t load_configbundle(const std::string &path, unsigned int flags = LOAD_CFGBNDLE_SAVE); // Export a config bundle file containing all the presets and the names of the active presets. void export_configbundle(const std::string &path); // , const DynamicPrintConfig &settings); diff --git a/xs/xsp/GUI_Preset.xsp b/xs/xsp/GUI_Preset.xsp index 905ff4ecde..ed5db01e9e 100644 --- a/xs/xsp/GUI_Preset.xsp +++ b/xs/xsp/GUI_Preset.xsp @@ -100,6 +100,8 @@ PresetCollection::arrayref() PresetBundle(); ~PresetBundle(); + void reset(bool delete_files); + void setup_directories() %code%{ try { @@ -128,7 +130,7 @@ PresetCollection::arrayref() size_t load_configbundle(const char *path) %code%{ try { - RETVAL = THIS->load_configbundle(path); + RETVAL = THIS->load_configbundle(path, PresetBundle::LOAD_CFGBNDLE_SAVE); } catch (std::exception& e) { croak("Loading of a config bundle %s failed:\n%s\n", path, e.what()); }