mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-13 02:08:08 +08:00
Apply printer model / variant preferences when loading presets
This commit is contained in:
parent
57e47a3296
commit
e53949f2c8
@ -154,7 +154,7 @@ sub OnInit {
|
|||||||
$self->{mainframe}->config_wizard(1);
|
$self->{mainframe}->config_wizard(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->{preset_updater}->download($self->{preset_bundle});
|
# $self->{preset_updater}->download($self->{preset_bundle});
|
||||||
});
|
});
|
||||||
|
|
||||||
# The following event is emited by the C++ menu implementation of application language change.
|
# The following event is emited by the C++ menu implementation of application language change.
|
||||||
|
@ -646,7 +646,11 @@ sub config_wizard {
|
|||||||
|
|
||||||
|
|
||||||
# TODO: Offer "reset user profile"
|
# TODO: Offer "reset user profile"
|
||||||
Slic3r::GUI::open_config_wizard();
|
Slic3r::GUI::open_config_wizard(wxTheApp->{preset_bundle});
|
||||||
|
# Load the currently selected preset into the GUI, update the preset selection box.
|
||||||
|
foreach my $tab (values %{$self->{options_tabs}}) { # XXX: only if not cancelled?
|
||||||
|
$tab->load_current_preset;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
# Enumerate the profiles bundled with the Slic3r installation under resources/profiles.
|
# Enumerate the profiles bundled with the Slic3r installation under resources/profiles.
|
||||||
|
@ -999,6 +999,7 @@ default_print_profile = 0.15mm OPTIMAL MK3
|
|||||||
[printer:Original Prusa i3 MK3 0.25 nozzle]
|
[printer:Original Prusa i3 MK3 0.25 nozzle]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
nozzle_diameter = 0.25
|
nozzle_diameter = 0.25
|
||||||
|
printer_variant = 0.25
|
||||||
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
|
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
|
||||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
|
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
|
||||||
retract_lift_below = 209
|
retract_lift_below = 209
|
||||||
@ -1009,6 +1010,7 @@ default_print_profile = 0.10mm DETAIL MK3
|
|||||||
[printer:Original Prusa i3 MK3 0.6 nozzle]
|
[printer:Original Prusa i3 MK3 0.6 nozzle]
|
||||||
inherits = *common*
|
inherits = *common*
|
||||||
nozzle_diameter = 0.6
|
nozzle_diameter = 0.6
|
||||||
|
printer_variant = 0.6
|
||||||
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
|
end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
|
||||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
|
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
|
||||||
retract_lift_below = 209
|
retract_lift_below = 209
|
||||||
|
@ -135,7 +135,7 @@ void AppConfig::save()
|
|||||||
|
|
||||||
bool AppConfig::get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const
|
bool AppConfig::get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const
|
||||||
{
|
{
|
||||||
std::cerr << "AppConfig::get_variant(" << vendor << ", " << model << ", " << variant << ") ";
|
// std::cerr << "AppConfig::get_variant(" << vendor << ", " << model << ", " << variant << ") " << std::endl;
|
||||||
|
|
||||||
const auto it_v = m_vendors.find(vendor);
|
const auto it_v = m_vendors.find(vendor);
|
||||||
if (it_v == m_vendors.end()) { return false; }
|
if (it_v == m_vendors.end()) { return false; }
|
||||||
@ -161,6 +161,12 @@ void AppConfig::set_variant(const std::string &vendor, const std::string &model,
|
|||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppConfig::set_vendors(const AppConfig &from)
|
||||||
|
{
|
||||||
|
m_vendors = from.m_vendors;
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
std::string AppConfig::get_last_dir() const
|
std::string AppConfig::get_last_dir() const
|
||||||
{
|
{
|
||||||
const auto it = m_storage.find("recent");
|
const auto it = m_storage.find("recent");
|
||||||
|
@ -68,12 +68,9 @@ public:
|
|||||||
void clear_section(const std::string §ion)
|
void clear_section(const std::string §ion)
|
||||||
{ m_storage[section].clear(); }
|
{ m_storage[section].clear(); }
|
||||||
|
|
||||||
// TODO: remove / upgrade
|
|
||||||
// ConfigOptionStrings get_strings(const std::string §ion, const std::string &key) const;
|
|
||||||
// void set_strings(const std::string §ion, const std::string &key, const ConfigOptionStrings &value);
|
|
||||||
// TODO:
|
|
||||||
bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const;
|
bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const;
|
||||||
void set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable);
|
void set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable);
|
||||||
|
void set_vendors(const AppConfig &from);
|
||||||
|
|
||||||
// return recent/skein_directory or recent/config_directory or empty string.
|
// return recent/skein_directory or recent/config_directory or empty string.
|
||||||
std::string get_last_dir() const;
|
std::string get_last_dir() const;
|
||||||
|
@ -74,13 +74,17 @@ void ConfigWizardPage::append_text(wxString text)
|
|||||||
auto *widget = new wxStaticText(this, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
|
auto *widget = new wxStaticText(this, wxID_ANY, text, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
|
||||||
widget->Wrap(CONTENT_WIDTH);
|
widget->Wrap(CONTENT_WIDTH);
|
||||||
widget->SetMinSize(wxSize(CONTENT_WIDTH, -1));
|
widget->SetMinSize(wxSize(CONTENT_WIDTH, -1));
|
||||||
// content->Add(widget, 1, wxALIGN_LEFT | wxTOP | wxBOTTOM, 10);
|
|
||||||
content->Add(widget, 0, wxALIGN_LEFT | wxTOP | wxBOTTOM, 10);
|
content->Add(widget, 0, wxALIGN_LEFT | wxTOP | wxBOTTOM, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigWizardPage::append_widget(wxWindow *widget, int proportion)
|
void ConfigWizardPage::append_widget(wxWindow *widget, int proportion, int flag, int border)
|
||||||
{
|
{
|
||||||
content->Add(widget, proportion, wxEXPAND | wxTOP | wxBOTTOM, 10);
|
content->Add(widget, proportion, flag, border);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigWizardPage::append_sizer(wxSizer *sizer, int proportion)
|
||||||
|
{
|
||||||
|
content->Add(sizer, proportion, wxEXPAND | wxTOP | wxBOTTOM, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigWizardPage::append_spacer(int space)
|
void ConfigWizardPage::append_spacer(int space)
|
||||||
@ -99,17 +103,19 @@ void ConfigWizardPage::enable_next(bool enable) { parent->p->enable_next(enable)
|
|||||||
|
|
||||||
// Wizard pages
|
// Wizard pages
|
||||||
|
|
||||||
PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) :
|
// PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) :
|
||||||
|
PageWelcome::PageWelcome(ConfigWizard *parent) :
|
||||||
ConfigWizardPage(parent, _(L("Welcome to the Slic3r Configuration assistant")), _(L("Welcome"))),
|
ConfigWizardPage(parent, _(L("Welcome to the Slic3r Configuration assistant")), _(L("Welcome"))),
|
||||||
others_buttons(new wxPanel(parent)),
|
others_buttons(new wxPanel(parent)),
|
||||||
variants_checked(0)
|
variants_checked(0)
|
||||||
{
|
{
|
||||||
append_text(_(L("Hello, welcome to Slic3r Prusa Edition! TODO: This text.")));
|
append_text(_(L("Hello, welcome to Slic3r Prusa Edition! TODO: This text.")));
|
||||||
|
|
||||||
|
const PresetBundle &bundle = wizard_p()->bundle_vendors;
|
||||||
const auto &vendors = bundle.vendors;
|
const auto &vendors = bundle.vendors;
|
||||||
const auto vendor_prusa = std::find(vendors.cbegin(), vendors.cend(), VendorProfile("PrusaResearch"));
|
const auto vendor_prusa = std::find(vendors.cbegin(), vendors.cend(), VendorProfile("PrusaResearch"));
|
||||||
|
|
||||||
// TODO: preload checkiness from app config
|
const AppConfig &appconfig_vendors = wizard_p()->appconfig_vendors;
|
||||||
|
|
||||||
if (vendor_prusa != vendors.cend()) {
|
if (vendor_prusa != vendors.cend()) {
|
||||||
const auto &models = vendor_prusa->models;
|
const auto &models = vendor_prusa->models;
|
||||||
@ -138,12 +144,20 @@ PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) :
|
|||||||
|
|
||||||
sizer->AddSpacer(20);
|
sizer->AddSpacer(20);
|
||||||
|
|
||||||
|
std::string model_id = model->id;
|
||||||
|
|
||||||
for (const auto &variant : model->variants) {
|
for (const auto &variant : model->variants) {
|
||||||
|
std::string variant_name = variant.name;
|
||||||
auto *cbox = new wxCheckBox(panel, wxID_ANY, wxString::Format("%s %s %s", variant.name, _(L("mm")), _(L("nozzle"))));
|
auto *cbox = new wxCheckBox(panel, wxID_ANY, wxString::Format("%s %s %s", variant.name, _(L("mm")), _(L("nozzle"))));
|
||||||
|
bool enabled = appconfig_vendors.get_variant("PrusaResearch", model_id, variant_name);
|
||||||
|
variants_checked += enabled;
|
||||||
|
cbox->SetValue(enabled);
|
||||||
sizer->Add(cbox, 0, wxBOTTOM, 3);
|
sizer->Add(cbox, 0, wxBOTTOM, 3);
|
||||||
cbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) {
|
cbox->Bind(wxEVT_CHECKBOX, [=](wxCommandEvent &event) {
|
||||||
this->variants_checked += event.IsChecked() ? 1 : -1;
|
this->variants_checked += event.IsChecked() ? 1 : -1;
|
||||||
this->on_variant_checked();
|
this->on_variant_checked();
|
||||||
|
AppConfig &appconfig_vendors = this->wizard_p()->appconfig_vendors;
|
||||||
|
appconfig_vendors.set_variant("PrusaResearch", model_id, variant_name, event.IsChecked());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,6 +170,7 @@ PageWelcome::PageWelcome(ConfigWizard *parent, const PresetBundle &bundle) :
|
|||||||
{
|
{
|
||||||
auto *sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto *sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
auto *other_vendors = new wxButton(others_buttons, wxID_ANY, _(L("Other vendors")));
|
auto *other_vendors = new wxButton(others_buttons, wxID_ANY, _(L("Other vendors")));
|
||||||
|
other_vendors->Disable();
|
||||||
auto *custom_setup = new wxButton(others_buttons, wxID_ANY, _(L("Custom setup")));
|
auto *custom_setup = new wxButton(others_buttons, wxID_ANY, _(L("Custom setup")));
|
||||||
|
|
||||||
sizer->Add(other_vendors);
|
sizer->Add(other_vendors);
|
||||||
@ -181,17 +196,24 @@ void PageWelcome::on_variant_checked()
|
|||||||
}
|
}
|
||||||
|
|
||||||
PageUpdate::PageUpdate(ConfigWizard *parent) :
|
PageUpdate::PageUpdate(ConfigWizard *parent) :
|
||||||
ConfigWizardPage(parent, _(L("Automatic updates")), _(L("Updates")))
|
ConfigWizardPage(parent, _(L("Automatic updates")), _(L("Updates"))),
|
||||||
|
version_check(true),
|
||||||
|
preset_update(true)
|
||||||
{
|
{
|
||||||
|
const AppConfig *app_config = GUI::get_app_config();
|
||||||
|
|
||||||
append_text(_(L("TODO: text")));
|
append_text(_(L("TODO: text")));
|
||||||
auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for Slic3r updates")));
|
auto *box_slic3r = new wxCheckBox(this, wxID_ANY, _(L("Check for Slic3r updates")));
|
||||||
box_slic3r->SetValue(true);
|
box_slic3r->SetValue(app_config->get("version_check") == "1");
|
||||||
append_widget(box_slic3r);
|
append_widget(box_slic3r);
|
||||||
|
|
||||||
append_text(_(L("TODO: text")));
|
append_text(_(L("TODO: text")));
|
||||||
auto *box_presets = new wxCheckBox(this, wxID_ANY, _(L("Update built-in Presets automatically")));
|
auto *box_presets = new wxCheckBox(this, wxID_ANY, _(L("Update built-in Presets automatically")));
|
||||||
box_presets->SetValue(true);
|
box_presets->SetValue(app_config->get("preset_update") == "1");
|
||||||
append_widget(box_presets);
|
append_widget(box_presets);
|
||||||
|
|
||||||
|
box_slic3r->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->version_check = event.IsChecked(); });
|
||||||
|
box_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) { this->preset_update = event.IsChecked(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void PageUpdate::presets_update_enable(bool enable)
|
void PageUpdate::presets_update_enable(bool enable)
|
||||||
@ -201,7 +223,42 @@ void PageUpdate::presets_update_enable(bool enable)
|
|||||||
|
|
||||||
PageVendors::PageVendors(ConfigWizard *parent) :
|
PageVendors::PageVendors(ConfigWizard *parent) :
|
||||||
ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors")))
|
ConfigWizardPage(parent, _(L("Other Vendors")), _(L("Other Vendors")))
|
||||||
{}
|
{
|
||||||
|
enum {
|
||||||
|
INDENT_SPACING = 30,
|
||||||
|
VERTICAL_SPACING = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
append_text(_(L("Other vendors! TODO: This text.")));
|
||||||
|
|
||||||
|
const PresetBundle &bundle = wizard_p()->bundle_vendors;
|
||||||
|
auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||||
|
boldfont.SetWeight(wxFONTWEIGHT_BOLD);
|
||||||
|
|
||||||
|
for (const auto &vendor : bundle.vendors) {
|
||||||
|
if (vendor.id == "PrusaResearch") { continue; }
|
||||||
|
|
||||||
|
auto *label_vendor = new wxStaticText(this, wxID_ANY, vendor.name);
|
||||||
|
label_vendor->SetFont(boldfont);
|
||||||
|
append_thing(label_vendor, 0, 0, 0);
|
||||||
|
|
||||||
|
for (const auto &model : vendor.models) {
|
||||||
|
auto *label_model = new wxStaticText(this, wxID_ANY, model.name);
|
||||||
|
label_model->SetFont(boldfont);
|
||||||
|
append_thing(label_model, 0, wxLEFT, INDENT_SPACING);
|
||||||
|
|
||||||
|
for (const auto &variant : model.variants) {
|
||||||
|
auto *cbox = new wxCheckBox(this, wxID_ANY, variant.name);
|
||||||
|
append_thing(cbox, 0, wxEXPAND | wxLEFT, 2 * INDENT_SPACING);
|
||||||
|
cbox->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent &event) {
|
||||||
|
// TODO
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
append_spacer(VERTICAL_SPACING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PageFirmware::PageFirmware(ConfigWizard *parent) :
|
PageFirmware::PageFirmware(ConfigWizard *parent) :
|
||||||
ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware")))
|
ConfigWizardPage(parent, _(L("Firmware Type")), _(L("Firmware")))
|
||||||
@ -289,6 +346,31 @@ void ConfigWizardIndex::on_paint(wxPaintEvent & evt)
|
|||||||
|
|
||||||
// priv
|
// priv
|
||||||
|
|
||||||
|
void ConfigWizard::priv::load_vendors()
|
||||||
|
{
|
||||||
|
const auto vendor_dir = fs::path(Slic3r::data_dir()) / "vendor";
|
||||||
|
// const auto profiles_dir = fs::path(resources_dir()) / "profiles";
|
||||||
|
for (fs::directory_iterator it(vendor_dir); it != fs::directory_iterator(); ++it) {
|
||||||
|
if (it->path().extension() == ".ini") {
|
||||||
|
bundle_vendors.load_configbundle(it->path().native(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
// for (const auto &vendor : bundle_vendors.vendors) {
|
||||||
|
// std::cerr << "vendor: " << vendor.name << std::endl;
|
||||||
|
// std::cerr << " URL: " << vendor.config_update_url << std::endl;
|
||||||
|
// for (const auto &model : vendor.models) {
|
||||||
|
// std::cerr << "\tmodel: " << model.id << " (" << model.name << ")" << std::endl;
|
||||||
|
// for (const auto &variant : model.variants) {
|
||||||
|
// std::cerr << "\t\tvariant: " << variant.name << std::endl;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
appconfig_vendors.set_vendors(*GUI::get_app_config());
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigWizard::priv::index_refresh()
|
void ConfigWizard::priv::index_refresh()
|
||||||
{
|
{
|
||||||
index->load_items(page_welcome);
|
index->load_items(page_welcome);
|
||||||
@ -344,12 +426,31 @@ void ConfigWizard::priv::on_custom_setup()
|
|||||||
set_page(page_firmware);
|
set_page(page_firmware);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigWizard::priv::on_finish()
|
||||||
|
{
|
||||||
|
const bool is_custom_setup = page_welcome->page_next() == page_firmware;
|
||||||
|
|
||||||
|
if (! is_custom_setup) {
|
||||||
|
AppConfig *app_config = GUI::get_app_config();
|
||||||
|
app_config->set_vendors(appconfig_vendors);
|
||||||
|
|
||||||
|
app_config->set("version_check", page_update->version_check ? "1" : "0");
|
||||||
|
app_config->set("preset_update", page_update->preset_update ? "1" : "0");
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
q->EndModal(wxID_OK);
|
||||||
|
}
|
||||||
|
|
||||||
// Public
|
// Public
|
||||||
|
|
||||||
ConfigWizard::ConfigWizard(wxWindow *parent, const PresetBundle &bundle) :
|
ConfigWizard::ConfigWizard(wxWindow *parent) :
|
||||||
wxDialog(parent, wxID_ANY, _(L("Configuration Assistant")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
|
wxDialog(parent, wxID_ANY, _(L("Configuration Assistant")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
|
||||||
p(new priv(this))
|
p(new priv(this))
|
||||||
{
|
{
|
||||||
|
p->load_vendors();
|
||||||
|
|
||||||
p->index = new ConfigWizardIndex(this);
|
p->index = new ConfigWizardIndex(this);
|
||||||
|
|
||||||
auto *vsizer = new wxBoxSizer(wxVERTICAL);
|
auto *vsizer = new wxBoxSizer(wxVERTICAL);
|
||||||
@ -372,7 +473,7 @@ ConfigWizard::ConfigWizard(wxWindow *parent, const PresetBundle &bundle) :
|
|||||||
p->btnsizer->Add(p->btn_finish, 0, wxLEFT, BTN_SPACING);
|
p->btnsizer->Add(p->btn_finish, 0, wxLEFT, BTN_SPACING);
|
||||||
p->btnsizer->Add(p->btn_cancel, 0, wxLEFT, BTN_SPACING);
|
p->btnsizer->Add(p->btn_cancel, 0, wxLEFT, BTN_SPACING);
|
||||||
|
|
||||||
p->add_page(p->page_welcome = new PageWelcome(this, bundle));
|
p->add_page(p->page_welcome = new PageWelcome(this));
|
||||||
p->add_page(p->page_update = new PageUpdate(this));
|
p->add_page(p->page_update = new PageUpdate(this));
|
||||||
p->add_page(p->page_vendors = new PageVendors(this));
|
p->add_page(p->page_vendors = new PageVendors(this));
|
||||||
p->add_page(p->page_firmware = new PageFirmware(this));
|
p->add_page(p->page_firmware = new PageFirmware(this));
|
||||||
@ -397,35 +498,24 @@ ConfigWizard::ConfigWizard(wxWindow *parent, const PresetBundle &bundle) :
|
|||||||
|
|
||||||
p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); });
|
p->btn_prev->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_prev(); });
|
||||||
p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_next(); });
|
p->btn_next->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->go_next(); });
|
||||||
|
p->btn_finish->Bind(wxEVT_BUTTON, [this](const wxCommandEvent &evt) { this->p->on_finish(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigWizard::~ConfigWizard() {}
|
ConfigWizard::~ConfigWizard() {}
|
||||||
|
|
||||||
void ConfigWizard::run(wxWindow *parent)
|
void ConfigWizard::run(wxWindow *parent, PresetBundle *preset_bundle)
|
||||||
{
|
{
|
||||||
PresetBundle bundle;
|
|
||||||
|
|
||||||
const auto profiles_dir = fs::path(resources_dir()) / "profiles";
|
const auto profiles_dir = fs::path(resources_dir()) / "profiles";
|
||||||
for (fs::directory_iterator it(profiles_dir); it != fs::directory_iterator(); ++it) {
|
for (fs::directory_iterator it(profiles_dir); it != fs::directory_iterator(); ++it) {
|
||||||
if (it->path().extension() == ".ini") {
|
if (it->path().extension() == ".ini") {
|
||||||
bundle.load_configbundle(it->path().native(), PresetBundle::LOAD_CFGBUNDLE_VENDOR_ONLY);
|
PresetBundle::install_vendor_configbundle(it->path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX
|
ConfigWizard wizard(parent);
|
||||||
for (const auto &vendor : bundle.vendors) {
|
if (wizard.ShowModal() == wxID_OK) {
|
||||||
std::cerr << "vendor: " << vendor.name << std::endl;
|
preset_bundle->load_presets(*GUI::get_app_config());
|
||||||
std::cerr << " URL: " << vendor.config_update_url << std::endl;
|
|
||||||
for (const auto &model : vendor.models) {
|
|
||||||
std::cerr << "\tmodel: " << model.id << " (" << model.name << ")" << std::endl;
|
|
||||||
for (const auto &variant : model.variants) {
|
|
||||||
std::cerr << "\t\tvariant: " << variant.name << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigWizard wizard(parent, bundle);
|
|
||||||
wizard.ShowModal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,14 +15,15 @@ namespace GUI {
|
|||||||
class ConfigWizard: public wxDialog
|
class ConfigWizard: public wxDialog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConfigWizard(wxWindow *parent, const PresetBundle &bundle);
|
// ConfigWizard(wxWindow *parent, const PresetBundle &bundle);
|
||||||
|
ConfigWizard(wxWindow *parent);
|
||||||
ConfigWizard(ConfigWizard &&) = delete;
|
ConfigWizard(ConfigWizard &&) = delete;
|
||||||
ConfigWizard(const ConfigWizard &) = delete;
|
ConfigWizard(const ConfigWizard &) = delete;
|
||||||
ConfigWizard &operator=(ConfigWizard &&) = delete;
|
ConfigWizard &operator=(ConfigWizard &&) = delete;
|
||||||
ConfigWizard &operator=(const ConfigWizard &) = delete;
|
ConfigWizard &operator=(const ConfigWizard &) = delete;
|
||||||
~ConfigWizard();
|
~ConfigWizard();
|
||||||
|
|
||||||
static void run(wxWindow *parent);
|
static void run(wxWindow *parent, PresetBundle *preset_bundle);
|
||||||
private:
|
private:
|
||||||
struct priv;
|
struct priv;
|
||||||
std::unique_ptr<priv> p;
|
std::unique_ptr<priv> p;
|
||||||
|
@ -9,6 +9,9 @@
|
|||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
#include <wx/button.h>
|
#include <wx/button.h>
|
||||||
|
|
||||||
|
#include "AppConfig.hpp"
|
||||||
|
#include "PresetBundle.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
@ -34,12 +37,21 @@ struct ConfigWizardPage: wxPanel
|
|||||||
|
|
||||||
virtual ~ConfigWizardPage();
|
virtual ~ConfigWizardPage();
|
||||||
|
|
||||||
ConfigWizardPage *page_prev() const { return p_prev; }
|
ConfigWizardPage* page_prev() const { return p_prev; }
|
||||||
ConfigWizardPage *page_next() const { return p_next; }
|
ConfigWizardPage* page_next() const { return p_next; }
|
||||||
ConfigWizardPage* chain(ConfigWizardPage *page);
|
ConfigWizardPage* chain(ConfigWizardPage *page);
|
||||||
|
|
||||||
void append_text(wxString text);
|
void append_text(wxString text);
|
||||||
void append_widget(wxWindow *widget, int proportion = 0);
|
void append_widget(wxWindow *widget, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10);
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void append_thing(T *thing, int proportion = 0, int flag = wxEXPAND|wxTOP|wxBOTTOM, int border = 10)
|
||||||
|
{
|
||||||
|
content->Add(thing, proportion, flag, border);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove:
|
||||||
|
void append_sizer(wxSizer *sizer, int proportion = 0);
|
||||||
void append_spacer(int space);
|
void append_spacer(int space);
|
||||||
|
|
||||||
ConfigWizard::priv *wizard_p() const { return parent->p.get(); }
|
ConfigWizard::priv *wizard_p() const { return parent->p.get(); }
|
||||||
@ -60,7 +72,7 @@ struct PageWelcome: ConfigWizardPage
|
|||||||
wxPanel *others_buttons;
|
wxPanel *others_buttons;
|
||||||
unsigned variants_checked;
|
unsigned variants_checked;
|
||||||
|
|
||||||
PageWelcome(ConfigWizard *parent, const PresetBundle &bundle);
|
PageWelcome(ConfigWizard *parent);
|
||||||
|
|
||||||
virtual wxPanel* extra_buttons() { return others_buttons; }
|
virtual wxPanel* extra_buttons() { return others_buttons; }
|
||||||
virtual void on_page_set();
|
virtual void on_page_set();
|
||||||
@ -70,6 +82,9 @@ struct PageWelcome: ConfigWizardPage
|
|||||||
|
|
||||||
struct PageUpdate: ConfigWizardPage
|
struct PageUpdate: ConfigWizardPage
|
||||||
{
|
{
|
||||||
|
bool version_check;
|
||||||
|
bool preset_update;
|
||||||
|
|
||||||
PageUpdate(ConfigWizard *parent);
|
PageUpdate(ConfigWizard *parent);
|
||||||
|
|
||||||
void presets_update_enable(bool enable);
|
void presets_update_enable(bool enable);
|
||||||
@ -124,6 +139,9 @@ private:
|
|||||||
struct ConfigWizard::priv
|
struct ConfigWizard::priv
|
||||||
{
|
{
|
||||||
ConfigWizard *q;
|
ConfigWizard *q;
|
||||||
|
AppConfig appconfig_vendors;
|
||||||
|
PresetBundle bundle_vendors;
|
||||||
|
|
||||||
wxBoxSizer *topsizer = nullptr;
|
wxBoxSizer *topsizer = nullptr;
|
||||||
wxBoxSizer *btnsizer = nullptr;
|
wxBoxSizer *btnsizer = nullptr;
|
||||||
ConfigWizardPage *page_current = nullptr;
|
ConfigWizardPage *page_current = nullptr;
|
||||||
@ -143,6 +161,7 @@ struct ConfigWizard::priv
|
|||||||
|
|
||||||
priv(ConfigWizard *q) : q(q) {}
|
priv(ConfigWizard *q) : q(q) {}
|
||||||
|
|
||||||
|
void load_vendors();
|
||||||
void add_page(ConfigWizardPage *page);
|
void add_page(ConfigWizardPage *page);
|
||||||
void index_refresh();
|
void index_refresh();
|
||||||
void set_page(ConfigWizardPage *page);
|
void set_page(ConfigWizardPage *page);
|
||||||
@ -152,6 +171,7 @@ struct ConfigWizard::priv
|
|||||||
|
|
||||||
void on_other_vendors();
|
void on_other_vendors();
|
||||||
void on_custom_setup();
|
void on_custom_setup();
|
||||||
|
void on_finish();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -353,18 +353,13 @@ void add_debug_menu(wxMenuBar *menu, int event_language_change)
|
|||||||
//#endif
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_config_wizard()
|
void open_config_wizard(PresetBundle *preset_bundle)
|
||||||
{
|
{
|
||||||
if (g_wxMainFrame == nullptr) {
|
if (g_wxMainFrame == nullptr) {
|
||||||
throw std::runtime_error("Main frame not set");
|
throw std::runtime_error("Main frame not set");
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto *wizard = new ConfigWizard(static_cast<wxWindow*>(g_wxMainFrame)); // FIXME: lifetime
|
ConfigWizard::run(g_wxMainFrame, preset_bundle);
|
||||||
|
|
||||||
// wizard->run();
|
|
||||||
ConfigWizard::run(g_wxMainFrame);
|
|
||||||
|
|
||||||
// show_info(g_wxMainFrame, "After wizard", "After wizard");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void open_preferences_dialog(int event_preferences)
|
void open_preferences_dialog(int event_preferences)
|
||||||
|
@ -86,7 +86,7 @@ wxColour* get_sys_label_clr();
|
|||||||
void add_debug_menu(wxMenuBar *menu, int event_language_change);
|
void add_debug_menu(wxMenuBar *menu, int event_language_change);
|
||||||
|
|
||||||
// Opens the first-time configuration wizard
|
// Opens the first-time configuration wizard
|
||||||
void open_config_wizard();
|
void open_config_wizard(PresetBundle *preset_bundle);
|
||||||
|
|
||||||
// Create "Preferences" dialog after selecting menu "Preferences" in Perl part
|
// Create "Preferences" dialog after selecting menu "Preferences" in Perl part
|
||||||
void open_preferences_dialog(int event_preferences);
|
void open_preferences_dialog(int event_preferences);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#include "Preset.hpp"
|
#include "Preset.hpp"
|
||||||
|
#include "AppConfig.hpp"
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
@ -175,6 +176,16 @@ bool Preset::update_compatible_with_printer(const Preset &active_printer, const
|
|||||||
return this->is_compatible = is_compatible_with_printer(active_printer, extra_config);
|
return this->is_compatible = is_compatible_with_printer(active_printer, extra_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Preset::set_visible_from_appconfig(const AppConfig &app_config)
|
||||||
|
{
|
||||||
|
if (vendor == nullptr) { return; }
|
||||||
|
const std::string &model = config.opt_string("printer_model");
|
||||||
|
const std::string &variant = config.opt_string("printer_variant");
|
||||||
|
if (model.empty() || variant.empty()) { return; }
|
||||||
|
is_visible = app_config.get_variant(vendor->id, model, variant);
|
||||||
|
std::cerr << vendor->id << " / " << model << " / " << variant << ": visible: " << is_visible << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& Preset::print_options()
|
const std::vector<std::string>& Preset::print_options()
|
||||||
{
|
{
|
||||||
static std::vector<std::string> s_opts {
|
static std::vector<std::string> s_opts {
|
||||||
|
@ -13,6 +13,8 @@ class wxItemContainer;
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class AppConfig;
|
||||||
|
|
||||||
enum ConfigFileType
|
enum ConfigFileType
|
||||||
{
|
{
|
||||||
CONFIG_FILE_TYPE_UNKNOWN,
|
CONFIG_FILE_TYPE_UNKNOWN,
|
||||||
@ -35,14 +37,14 @@ public:
|
|||||||
PrinterVariant() {}
|
PrinterVariant() {}
|
||||||
PrinterVariant(const std::string &name) : name(name) {}
|
PrinterVariant(const std::string &name) : name(name) {}
|
||||||
std::string name;
|
std::string name;
|
||||||
bool enabled = true;
|
// bool enabled = true; // TODO: remove these?
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PrinterModel {
|
struct PrinterModel {
|
||||||
PrinterModel() {}
|
PrinterModel() {}
|
||||||
std::string id;
|
std::string id;
|
||||||
std::string name;
|
std::string name;
|
||||||
bool enabled = true;
|
// bool enabled = true;
|
||||||
std::vector<PrinterVariant> variants;
|
std::vector<PrinterVariant> variants;
|
||||||
PrinterVariant* variant(const std::string &name) {
|
PrinterVariant* variant(const std::string &name) {
|
||||||
for (auto &v : this->variants)
|
for (auto &v : this->variants)
|
||||||
@ -85,7 +87,7 @@ public:
|
|||||||
bool is_external = false;
|
bool is_external = false;
|
||||||
// System preset is read-only.
|
// System preset is read-only.
|
||||||
bool is_system = false;
|
bool is_system = false;
|
||||||
// Preset is visible, if it is compatible with the active Printer.
|
// Preset is visible, if it is compatible with the active Printer. TODO: fix
|
||||||
// Also the "default" preset is only visible, if it is the only preset in the list.
|
// Also the "default" preset is only visible, if it is the only preset in the list.
|
||||||
bool is_visible = true;
|
bool is_visible = true;
|
||||||
// Has this preset been modified?
|
// Has this preset been modified?
|
||||||
@ -131,6 +133,9 @@ public:
|
|||||||
// Mark this preset as compatible if it is compatible with active_printer.
|
// Mark this preset as compatible if it is compatible with active_printer.
|
||||||
bool update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config);
|
bool update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config);
|
||||||
|
|
||||||
|
// Set is_visible according to application config
|
||||||
|
void set_visible_from_appconfig(const AppConfig &app_config);
|
||||||
|
|
||||||
// Resize the extruder specific fields, initialize them with the content of the 1st extruder.
|
// Resize the extruder specific fields, initialize them with the content of the 1st extruder.
|
||||||
void set_num_extruders(unsigned int n) { set_num_extruders(this->config, n); }
|
void set_num_extruders(unsigned int n) { set_num_extruders(this->config, n); }
|
||||||
|
|
||||||
@ -162,6 +167,13 @@ public:
|
|||||||
PresetCollection(Preset::Type type, const std::vector<std::string> &keys);
|
PresetCollection(Preset::Type type, const std::vector<std::string> &keys);
|
||||||
~PresetCollection();
|
~PresetCollection();
|
||||||
|
|
||||||
|
typedef std::deque<Preset>::iterator Iterator;
|
||||||
|
typedef std::deque<Preset>::const_iterator ConstIterator;
|
||||||
|
Iterator begin() { return m_presets.begin() + 1; }
|
||||||
|
ConstIterator begin() const { return m_presets.begin() + 1; }
|
||||||
|
Iterator end() { return m_presets.end(); }
|
||||||
|
ConstIterator end() const { return m_presets.end(); }
|
||||||
|
|
||||||
void reset(bool delete_files);
|
void reset(bool delete_files);
|
||||||
|
|
||||||
Preset::Type type() const { return m_type; }
|
Preset::Type type() const { return m_type; }
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "PresetBundle.hpp"
|
#include "PresetBundle.hpp"
|
||||||
#include "BitmapCache.hpp"
|
#include "BitmapCache.hpp"
|
||||||
|
|
||||||
|
#include <iostream> // XXX
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
@ -105,7 +106,7 @@ void PresetBundle::setup_directories()
|
|||||||
std::initializer_list<boost::filesystem::path> paths = {
|
std::initializer_list<boost::filesystem::path> paths = {
|
||||||
data_dir,
|
data_dir,
|
||||||
data_dir / "vendor",
|
data_dir / "vendor",
|
||||||
data_dir / "cache",
|
data_dir / "cache", // TODO: rename as vendor-cache? (Check usage elsewhere!)
|
||||||
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
||||||
// Store the print/filament/printer presets into a "presets" directory.
|
// Store the print/filament/printer presets into a "presets" directory.
|
||||||
data_dir / "presets",
|
data_dir / "presets",
|
||||||
@ -200,8 +201,12 @@ static inline std::string remove_ini_suffix(const std::string &name)
|
|||||||
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
|
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
|
||||||
void PresetBundle::load_installed_printers(const AppConfig &config)
|
void PresetBundle::load_installed_printers(const AppConfig &config)
|
||||||
{
|
{
|
||||||
// TODO
|
std::cerr << "load_installed_printers()" << std::endl;
|
||||||
// m_storage
|
|
||||||
|
for (auto &preset : printers) {
|
||||||
|
std::cerr << "preset: printer: " << preset.name << std::endl;
|
||||||
|
preset.set_visible_from_appconfig(config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load selections (current print, current filaments, current printer) from config.ini
|
// Load selections (current print, current filaments, current printer) from config.ini
|
||||||
@ -221,6 +226,10 @@ void PresetBundle::load_selections(const AppConfig &config)
|
|||||||
break;
|
break;
|
||||||
this->set_filament_preset(i, remove_ini_suffix(config.get("presets", name)));
|
this->set_filament_preset(i, remove_ini_suffix(config.get("presets", name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update visibility of presets based on application vendor / model / variant configuration.
|
||||||
|
this->load_installed_printers(config);
|
||||||
|
|
||||||
// Update visibility of presets based on their compatibility with the active printer.
|
// Update visibility of presets based on their compatibility with the active printer.
|
||||||
// Always try to select a compatible print and filament preset to the current printer preset,
|
// Always try to select a compatible print and filament preset to the current printer preset,
|
||||||
// as the application may have been closed with an active "external" preset, which does not
|
// as the application may have been closed with an active "external" preset, which does not
|
||||||
@ -708,6 +717,11 @@ static void load_vendor_profile(const boost::property_tree::ptree &tree, VendorP
|
|||||||
void PresetBundle::install_vendor_configbundle(const std::string &src_path0)
|
void PresetBundle::install_vendor_configbundle(const std::string &src_path0)
|
||||||
{
|
{
|
||||||
boost::filesystem::path src_path(src_path0);
|
boost::filesystem::path src_path(src_path0);
|
||||||
|
install_vendor_configbundle(src_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PresetBundle::install_vendor_configbundle(const boost::filesystem::path &src_path)
|
||||||
|
{
|
||||||
boost::filesystem::copy_file(src_path, (boost::filesystem::path(data_dir()) / "vendor" / src_path.filename()).make_preferred(), boost::filesystem::copy_option::overwrite_if_exists);
|
boost::filesystem::copy_file(src_path, (boost::filesystem::path(data_dir()) / "vendor" / src_path.filename()).make_preferred(), boost::filesystem::copy_option::overwrite_if_exists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "Preset.hpp"
|
#include "Preset.hpp"
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
@ -88,6 +89,7 @@ public:
|
|||||||
|
|
||||||
// Install the Vendor specific config bundle into user's directory.
|
// Install the Vendor specific config bundle into user's directory.
|
||||||
void install_vendor_configbundle(const std::string &src_path);
|
void install_vendor_configbundle(const std::string &src_path);
|
||||||
|
static void install_vendor_configbundle(const boost::filesystem::path &src_path);
|
||||||
|
|
||||||
// Export a config bundle file containing all the presets and the names of the active presets.
|
// 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);
|
void export_configbundle(const std::string &path); // , const DynamicPrintConfig &settings);
|
||||||
|
@ -11,9 +11,9 @@
|
|||||||
|
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
#include "slic3r/GUI/GUI.hpp"
|
#include "slic3r/GUI/GUI.hpp"
|
||||||
// #include "slic3r/GUI/AppConfig.hpp"
|
|
||||||
#include "slic3r/GUI/PresetBundle.hpp"
|
#include "slic3r/GUI/PresetBundle.hpp"
|
||||||
#include "slic3r/Utils/Http.hpp"
|
#include "slic3r/Utils/Http.hpp"
|
||||||
|
#include "slic3r/Utils/Semver.hpp"
|
||||||
|
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
|
@ -54,8 +54,8 @@ int combochecklist_get_flags(SV *ui)
|
|||||||
void set_app_config(AppConfig *app_config)
|
void set_app_config(AppConfig *app_config)
|
||||||
%code%{ Slic3r::GUI::set_app_config(app_config); %};
|
%code%{ Slic3r::GUI::set_app_config(app_config); %};
|
||||||
|
|
||||||
void open_config_wizard()
|
void open_config_wizard(PresetBundle *preset_bundle)
|
||||||
%code%{ Slic3r::GUI::open_config_wizard(); %};
|
%code%{ Slic3r::GUI::open_config_wizard(preset_bundle); %};
|
||||||
|
|
||||||
void open_preferences_dialog(int preferences_event)
|
void open_preferences_dialog(int preferences_event)
|
||||||
%code%{ Slic3r::GUI::open_preferences_dialog(preferences_event); %};
|
%code%{ Slic3r::GUI::open_preferences_dialog(preferences_event); %};
|
||||||
|
@ -147,7 +147,7 @@ PresetCollection::arrayref()
|
|||||||
void install_vendor_configbundle(const char *path)
|
void install_vendor_configbundle(const char *path)
|
||||||
%code%{
|
%code%{
|
||||||
try {
|
try {
|
||||||
THIS->install_vendor_configbundle(path);
|
THIS->install_vendor_configbundle(std::string(path));
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
croak("Installing a vendor config bundle %s failed:\n%s\n", path, e.what());
|
croak("Installing a vendor config bundle %s failed:\n%s\n", path, e.what());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user