From fed8783e30ac917af8224375792c4976006d14ab Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 25 Mar 2014 14:04:01 +0100 Subject: [PATCH] New commands for exporting/importing full config bundles. Useful for printer vendors. #1365 --- lib/Slic3r/Config.pm | 32 ++++++++---- lib/Slic3r/GUI.pm | 22 +++++++++ lib/Slic3r/GUI/SkeinPanel.pm | 94 ++++++++++++++++++++++++++++++++++++ lib/Slic3r/GUI/Tab.pm | 11 ++--- 4 files changed, 143 insertions(+), 16 deletions(-) diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index 3655a91a..12947eca 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -77,9 +77,16 @@ sub load { my ($file) = @_; my $ini = __PACKAGE__->read_ini($file); + return $class->load_ini_hash($ini->{_}); +} + +sub load_ini_hash { + my $class = shift; + my ($ini_hash) = @_; + my $config = $class->new; - foreach my $opt_key (keys %{$ini->{_}}) { - ($opt_key, my $value) = _handle_legacy($opt_key, $ini->{_}{$opt_key}); + foreach my $opt_key (keys %$ini_hash) { + ($opt_key, my $value) = _handle_legacy($opt_key, $ini_hash->{$opt_key}); next if !defined $opt_key; $config->set_deserialize($opt_key, $value); } @@ -119,7 +126,7 @@ sub _handle_legacy { if ($opt_key eq 'gcode_flavor' && $value eq 'makerbot') { $value = 'makerware'; } - if ($opt_key eq 'fill_density' && defined($value) && $value <= 1) { + if ($opt_key eq 'fill_density' && defined($value) && $value !~ /%/ && $value <= 1) { # fill_density was turned into a percent value $value *= 100; $value = "$value"; # force update of the PV value, workaround for bug https://rt.cpan.org/Ticket/Display.html?id=94110 @@ -161,16 +168,22 @@ sub set_ifndef { } } -sub save { - my $self = shift; - my ($file) = @_; +sub as_ini { + my ($self) = @_; my $ini = { _ => {} }; foreach my $opt_key (sort @{$self->get_keys}) { next if $Options->{$opt_key}{shortcut}; $ini->{_}{$opt_key} = $self->serialize($opt_key); } - __PACKAGE__->write_ini($file, $ini); + return $ini; +} + +sub save { + my $self = shift; + my ($file) = @_; + + __PACKAGE__->write_ini($file, $self->as_ini); } sub setenv { @@ -382,7 +395,8 @@ sub write_ini { binmode $fh, ':utf8'; my $localtime = localtime; printf $fh "# generated by Slic3r $Slic3r::VERSION on %s\n", "$localtime"; - foreach my $category (sort keys %$ini) { + # make sure the _ category is the first one written + foreach my $category (sort { ($a eq '_') ? -1 : ($a cmp $b) } keys %$ini) { printf $fh "\n[%s]\n", $category if $category ne '_'; foreach my $key (sort keys %{$ini->{$category}}) { printf $fh "%s = %s\n", $key, $ini->{$category}{$key}; @@ -406,7 +420,7 @@ sub read_ini { next if /^\s+/; next if /^$/; next if /^\s*#/; - if (/^\[(\w+)\]$/) { + if (/^\[(.+?)\]$/) { $category = $1; next; } diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 4d152a4a..448a26e5 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -3,6 +3,7 @@ use strict; use warnings; use utf8; +use File::Basename qw(basename); use FindBin; use Slic3r::GUI::AboutDialog; use Slic3r::GUI::ConfigWizard; @@ -25,7 +26,9 @@ use Wx::Event qw(EVT_CLOSE EVT_MENU EVT_IDLE); use base 'Wx::App'; use constant MI_LOAD_CONF => &Wx::NewId; +use constant MI_LOAD_CONFBUNDLE => &Wx::NewId; use constant MI_EXPORT_CONF => &Wx::NewId; +use constant MI_EXPORT_CONFBUNDLE => &Wx::NewId; use constant MI_QUICK_SLICE => &Wx::NewId; use constant MI_REPEAT_QUICK => &Wx::NewId; use constant MI_QUICK_SAVE_AS => &Wx::NewId; @@ -117,6 +120,8 @@ sub OnInit { { $fileMenu->Append(MI_LOAD_CONF, "&Load Config…\tCtrl+L", 'Load exported configuration file'); $fileMenu->Append(MI_EXPORT_CONF, "&Export Config…\tCtrl+E", 'Export current configuration to file'); + $fileMenu->Append(MI_LOAD_CONFBUNDLE, "&Load Config Bundle…", 'Load presets from a bundle'); + $fileMenu->Append(MI_EXPORT_CONFBUNDLE, "&Export Config Bundle…", 'Export all presets to file'); $fileMenu->AppendSeparator(); $fileMenu->Append(MI_QUICK_SLICE, "Q&uick Slice…\tCtrl+U", 'Slice file'); $fileMenu->Append(MI_QUICK_SAVE_AS, "Quick Slice and Save &As…\tCtrl+Alt+U", 'Slice file and save as'); @@ -132,7 +137,9 @@ sub OnInit { $fileMenu->AppendSeparator(); $fileMenu->Append(wxID_EXIT, "&Quit", 'Quit Slic3r'); EVT_MENU($frame, MI_LOAD_CONF, sub { $self->{skeinpanel}->load_config_file }); + EVT_MENU($frame, MI_LOAD_CONFBUNDLE, sub { $self->{skeinpanel}->load_configbundle }); EVT_MENU($frame, MI_EXPORT_CONF, sub { $self->{skeinpanel}->export_config }); + EVT_MENU($frame, MI_EXPORT_CONFBUNDLE, sub { $self->{skeinpanel}->export_configbundle }); EVT_MENU($frame, MI_QUICK_SLICE, sub { $self->{skeinpanel}->quick_slice; $repeat->Enable(defined $Slic3r::GUI::SkeinPanel::last_input_file) }); EVT_MENU($frame, MI_REPEAT_QUICK, sub { $self->{skeinpanel}->quick_slice(reslice => 1) }); @@ -309,6 +316,21 @@ sub save_settings { Slic3r::Config->write_ini("$datadir/slic3r.ini", $Settings); } +sub presets { + my ($class, $section) = @_; + + my %presets = (); + opendir my $dh, "$Slic3r::GUI::datadir/$section" or die "Failed to read directory $Slic3r::GUI::datadir/$section (errno: $!)\n"; + foreach my $file (grep /\.ini$/i, readdir $dh) { + my $name = basename($file); + $name =~ s/\.ini$//; + $presets{$name} = "$Slic3r::GUI::datadir/$section/$file"; + } + closedir $dh; + + return %presets; +} + sub have_version_check { my $class = shift; diff --git a/lib/Slic3r/GUI/SkeinPanel.pm b/lib/Slic3r/GUI/SkeinPanel.pm index 7db15639..11ff0dae 100644 --- a/lib/Slic3r/GUI/SkeinPanel.pm +++ b/lib/Slic3r/GUI/SkeinPanel.pm @@ -284,6 +284,100 @@ sub load_config_file { } } +sub export_configbundle { + my $self = shift; + + eval { + # validate current configuration in case it's dirty + $self->config->validate; + }; + Slic3r::GUI::catch_error($self) and return; + + my $dir = $last_config ? dirname($last_config) : $Slic3r::GUI::Settings->{recent}{config_directory} || $Slic3r::GUI::Settings->{recent}{skein_directory} || ''; + my $filename = "Slic3r_config_bundle.ini"; + my $dlg = Wx::FileDialog->new($self, 'Save presets bundle as:', $dir, $filename, + FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); + if ($dlg->ShowModal == wxID_OK) { + my $file = $dlg->GetPath; + $Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file); + Slic3r::GUI->save_settings; + + # leave default category empty to prevent the bundle from being parsed as a normal config file + my $ini = { _ => {} }; + $ini->{settings}{$_} = $Slic3r::GUI::Settings->{_}{$_} for qw(autocenter mode); + $ini->{presets} = $Slic3r::GUI::Settings->{presets}; + if (-e "$Slic3r::GUI::datadir/simple.ini") { + my $config = Slic3r::Config->load("$Slic3r::GUI::datadir/simple.ini"); + $ini->{simple} = $config->as_ini->{_}; + } + + foreach my $section (qw(print filament printer)) { + my %presets = Slic3r::GUI->presets($section); + foreach my $preset_name (keys %presets) { + my $config = Slic3r::Config->load($presets{$preset_name}); + $ini->{"$section:$preset_name"} = $config->as_ini->{_}; + } + } + + Slic3r::Config->write_ini($file, $ini); + } + $dlg->Destroy; +} + +sub load_configbundle { + my $self = shift; + + my $dir = $last_config ? dirname($last_config) : $Slic3r::GUI::Settings->{recent}{config_directory} || $Slic3r::GUI::Settings->{recent}{skein_directory} || ''; + my $dlg = Wx::FileDialog->new($self, 'Select configuration to load:', $dir, "config.ini", + FILE_WILDCARDS->{ini}, wxFD_OPEN | wxFD_FILE_MUST_EXIST); + return unless $dlg->ShowModal == wxID_OK; + my ($file) = $dlg->GetPaths; + $dlg->Destroy; + + $Slic3r::GUI::Settings->{recent}{config_directory} = dirname($file); + Slic3r::GUI->save_settings; + + # load .ini file + my $ini = Slic3r::Config->read_ini($file); + + if ($ini->{settings}) { + $Slic3r::GUI::Settings->{_}{$_} = $ini->{settings}{$_} for keys %{$ini->{settings}}; + Slic3r::GUI->save_settings; + } + if ($ini->{presets}) { + $Slic3r::GUI::Settings->{presets} = $ini->{presets}; + Slic3r::GUI->save_settings; + } + if ($ini->{simple}) { + my $config = Slic3r::Config->load_ini_hash($ini->{simple}); + $config->save("$Slic3r::GUI::datadir/simple.ini"); + if ($self->{mode} eq 'simple') { + foreach my $tab (values %{$self->{options_tabs}}) { + $tab->load_config($config) for values %{$self->{options_tabs}}; + } + } + } + my $imported = 0; + foreach my $ini_category (sort keys %$ini) { + next unless $ini_category =~ /^(print|filament|printer):(.+)$/; + my ($section, $preset_name) = ($1, $2); + my $config = Slic3r::Config->load_ini_hash($ini->{$ini_category}); + $config->save(sprintf "$Slic3r::GUI::datadir/%s/%s.ini", $section, $preset_name); + $imported++; + } + if ($self->{mode} eq 'expert') { + foreach my $tab (values %{$self->{options_tabs}}) { + $tab->load_presets; + } + } + my $message = sprintf "%d presets successfully imported.", $imported; + if ($self->{mode} eq 'simple' && $Slic3r::GUI::Settings->{_}{mode} eq 'expert') { + Slic3r::GUI::show_info($self, "$message You need to restart Slic3r to make the changes effective."); + } else { + Slic3r::GUI::show_info($self, $message); + } +} + sub load_config { my $self = shift; my ($config) = @_; diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 49393897..f4e72ab6 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -345,16 +345,13 @@ sub load_presets { name => '- default -', }]; - opendir my $dh, "$Slic3r::GUI::datadir/" . $self->name or die "Failed to read directory $Slic3r::GUI::datadir/" . $self->name . " (errno: $!)\n"; - foreach my $file (sort grep /\.ini$/i, readdir $dh) { - my $name = basename($file); - $name =~ s/\.ini$//; + my %presets = Slic3r::GUI->presets($self->name); + foreach my $preset_name (keys %presets) { push @{$self->{presets}}, { - file => "$Slic3r::GUI::datadir/" . $self->name . "/$file", - name => $name, + name => $preset_name, + file => $presets{$preset_name}, }; } - closedir $dh; $self->{presets_choice}->Clear; $self->{presets_choice}->Append($_->{name}) for @{$self->{presets}};