Physical Printers.

- save/load printers
 - consistency between selection on Tab and Plater
This commit is contained in:
YuSanka 2020-06-24 08:50:01 +02:00
parent 7c7dcab032
commit 02624689ce
9 changed files with 600 additions and 223 deletions

View file

@ -1339,108 +1339,178 @@ const Preset* PrinterPresetCollection::find_by_model_id(const std::string &model
return it != cend() ? &*it : nullptr;
}
/*
PhysicalPrinter& PhysicalPrinterCollection::load_external_printer(
// Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
const std::string& path,
// Name of the profile, derived from the source file name.
const std::string& name,
// Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored.
const std::string& original_name,
// Config to initialize the preset from.
const DynamicPrintConfig& config,
// Select the preset after loading?
bool select)
{
// Load the preset over a default preset, so that the missing fields are filled in from the default preset.
DynamicPrintConfig cfg(this->default_printer().config);
cfg.apply_only(config, cfg.keys(), true);
// Is there a preset already loaded with the name stored inside the config?
std::deque<PhysicalPrinter>::iterator it = this->find_printer_internal(original_name);
bool found = it != m_printers.end() && it->name == original_name;
if (!found) {
// Try to match the original_name against the "renamed_from" profile names of loaded system profiles.
/ *
it = this->find_preset_renamed(original_name);
found = it != m_presets.end();
* /
}
if (found) {
if (profile_print_params_same(it->config, cfg)) {
// The preset exists and it matches the values stored inside config.
if (select)
this->select_printer(it - m_printers.begin());
return *it;
}
if (profile_host_params_same_or_anonymized(it->config, cfg) == ProfileHostParams::Anonymized) {
// The project being loaded is anonymized. Replace the empty host keys of the loaded profile with the data from the original profile.
// See "Octoprint Settings when Opening a .3MF file" GH issue #3244
auto opt_update = [it, &cfg](const std::string& opt_key) {
auto opt = it->config.option<ConfigOptionString>(opt_key);
if (opt != nullptr)
cfg.set_key_value(opt_key, opt->clone());
};
opt_update("print_host");
opt_update("printhost_apikey");
opt_update("printhost_cafile");
}
}
// The external preset does not match an internal preset, load the external preset.
std::string new_name;
for (size_t idx = 0;; ++idx) {
std::string suffix;
if (original_name.empty()) {
if (idx > 0)
suffix = " (" + std::to_string(idx) + ")";
}
else {
if (idx == 0)
suffix = " (" + original_name + ")";
else
suffix = " (" + original_name + "-" + std::to_string(idx) + ")";
}
new_name = name + suffix;
it = this->find_printer_internal(new_name);
if (it == m_printers.end() || it->name != new_name)
// Unique profile name. Insert a new profile.
break;
if (profile_print_params_same(it->config, cfg)) {
// The preset exists and it matches the values stored inside config.
if (select)
this->select_printer(it - m_printers.begin());
return *it;
}
// Form another profile name.
}
// Insert a new profile.
PhysicalPrinter& printer = this->load_printer(path, new_name, std::move(cfg), select);
return printer;
// -------------------------
// *** PhysicalPrinter ***
// -------------------------
const std::vector<std::string>& PhysicalPrinter::printer_options()
{
static std::vector<std::string> s_opts;
if (s_opts.empty()) {
s_opts = {
"preset_name",
"printer_technology",
"host_type",
"print_host",
"printhost_apikey",
"printhost_cafile",
"login",
"password"
};
}
return s_opts;
}
void PhysicalPrinterCollection::save_printer(const std::string& new_name)
const std::string& PhysicalPrinter::get_preset_name()
{
return config.opt_string("preset_name");
}
void PhysicalPrinter::update_from_preset(const Preset& preset)
{
config.apply_only(preset.config, printer_options(), false);
// add preset name to the options list
config.set_key_value("preset_name", new ConfigOptionString(preset.name));
}
void PhysicalPrinter::update_from_config(const DynamicPrintConfig& new_config)
{
config.apply_only(new_config, printer_options(), false);
}
PhysicalPrinter::PhysicalPrinter(const std::string& name, const Preset& preset) :
name(name)
{
update_from_preset(preset);
}
// -----------------------------------
// *** PhysicalPrinterCollection ***
// -----------------------------------
PhysicalPrinterCollection::PhysicalPrinterCollection( const std::vector<std::string>& keys)
{
}
// Load all presets found in dir_path.
// Throws an exception on error.
void PhysicalPrinterCollection::load_printers(const std::string& dir_path, const std::string& subdir)
{
boost::filesystem::path dir = boost::filesystem::canonical(boost::filesystem::path(dir_path) / subdir).make_preferred();
m_dir_path = dir.string();
std::string errors_cummulative;
// Store the loaded printers into a new vector, otherwise the binary search for already existing presets would be broken.
std::deque<PhysicalPrinter> printers_loaded;
for (auto& dir_entry : boost::filesystem::directory_iterator(dir))
if (Slic3r::is_ini_file(dir_entry)) {
std::string name = dir_entry.path().filename().string();
// Remove the .ini suffix.
name.erase(name.size() - 4);
if (this->find_printer(name, false)) {
// This happens when there's is a preset (most likely legacy one) with the same name as a system preset
// that's already been loaded from a bundle.
BOOST_LOG_TRIVIAL(warning) << "Preset already present, not loading: " << name;
continue;
}
try {
PhysicalPrinter printer(name);
printer.file = dir_entry.path().string();
// Load the preset file, apply preset values on top of defaults.
try {
DynamicPrintConfig config;
config.load_from_ini(printer.file);
printer.update_from_config(config);
printer.loaded = true;
}
catch (const std::ifstream::failure& err) {
throw std::runtime_error(std::string("The selected preset cannot be loaded: ") + printer.file + "\n\tReason: " + err.what());
}
catch (const std::runtime_error& err) {
throw std::runtime_error(std::string("Failed loading the preset file: ") + printer.file + "\n\tReason: " + err.what());
}
printers_loaded.emplace_back(printer);
}
catch (const std::runtime_error& err) {
errors_cummulative += err.what();
errors_cummulative += "\n";
}
}
m_printers.insert(m_printers.end(), std::make_move_iterator(printers_loaded.begin()), std::make_move_iterator(printers_loaded.end()));
std::sort(m_printers.begin(), m_printers.end());
//! this->select_preset(first_visible_idx());
if (!errors_cummulative.empty())
throw std::runtime_error(errors_cummulative);
}
PhysicalPrinter* PhysicalPrinterCollection::find_printer( const std::string& name, bool first_visible_if_not_found)
{
PhysicalPrinter key(name);
auto it = this->find_printer_internal(name);
// Ensure that a temporary copy is returned if the preset found is currently selected.
return (it != m_printers.end() && it->name == key.name) ? &this->printer(it - m_printers.begin()) :
first_visible_if_not_found ? &this->printer(0) : nullptr;
}
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
std::string PhysicalPrinterCollection::path_from_name(const std::string& new_name) const
{
std::string file_name = boost::iends_with(new_name, ".ini") ? new_name : (new_name + ".ini");
return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string();
}
void PhysicalPrinterCollection::save_printer(const PhysicalPrinter& edited_printer)
{
// 1) Find the printer with a new_name or create a new one,
// initialize it with the edited config.
auto it = this->find_printer_internal(new_name);
if (it != m_printers.end() && it->name == new_name) {
// Preset with the same name found.
PhysicalPrinter& printer = *it;
auto it = this->find_printer_internal(edited_printer.name);
if (it != m_printers.end() && it->name == edited_printer.name) {
// Printer with the same name found.
// Overwriting an existing preset.
printer.config = std::move(m_edited_printer.config);
it->config = std::move(edited_printer.config);
}
else {
// Creating a new printer.
PhysicalPrinter& printer = *m_printers.insert(it, m_edited_printer);
std::string old_name = printer.name;
printer.name = new_name;
it = m_printers.insert(it, edited_printer);
}
// 2) Activate the saved preset.
this->select_printer_by_name(new_name, true);
// 3) Store the active preset to disk.
this->get_selected_preset().save();
assert(it != m_printers.end());
// 2) Save printer
PhysicalPrinter& printer = *it;
if (printer.file.empty())
printer.file = this->path_from_name(printer.name);
printer.save();
// update idx_selected
m_idx_selected = it - m_printers.begin();
}
*/
bool PhysicalPrinterCollection::delete_printer(const std::string& name)
{
auto it = this->find_printer_internal(name);
const PhysicalPrinter& printer = *it;
if (it == m_printers.end())
return false;
// Erase the preset file.
boost::nowide::remove(printer.file.c_str());
m_printers.erase(it);
return true;
}
PhysicalPrinter& PhysicalPrinterCollection::select_printer_by_name(const std::string& name)
{
auto it = this->find_printer_internal(name);
assert(it != m_printers.end());
// update idx_selected
m_idx_selected = it - m_printers.begin();
return *it;
}
namespace PresetUtils {
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset)
{

View file

@ -535,14 +535,14 @@ namespace PresetUtils {
class PhysicalPrinter
{
public:
PhysicalPrinter(const std::string& name) : name(name) {}
PhysicalPrinter() {}
PhysicalPrinter(const std::string& name) : name(name){}
PhysicalPrinter(const std::string& name, const Preset& preset);
// Name of the Physical Printer, usually derived form the file name.
std::string name;
// File name of the Physical Printer.
std::string file;
// Name of the related Printer preset
std::string preset_name;
// Has this profile been loaded?
bool loaded = false;
@ -550,7 +550,13 @@ public:
// Configuration data, loaded from a file, or set from the defaults.
DynamicPrintConfig config;
static const std::vector<std::string>& printer_options();
const std::string& get_preset_name();
void save() { this->config.save(this->file); }
void save_to(const std::string& file_name) const { this->config.save(file_name); }
void update_from_preset(const Preset& preset);
void update_from_config(const DynamicPrintConfig &new_config);
// Return a printer technology, return ptFFF if the printer technology is not set.
static PrinterTechnology printer_technology(const DynamicPrintConfig& cfg) {
@ -562,18 +568,22 @@ public:
PrinterTechnology printer_technology() const { return printer_technology(this->config); }
// Sort lexicographically by a preset name. The preset name shall be unique across a single PresetCollection.
bool operator<(const Preset& other) const { return this->name < other.name; }
bool operator<(const PhysicalPrinter& other) const { return this->name < other.name; }
protected:
friend class PhysicalPrinterCollection;
};
/*
// Collections of presets of the same type (one of the Print, Filament or Printer type).
// ---------------------------------
// *** PhysicalPrinterCollection ***
// ---------------------------------
// Collections of physical printers
class PhysicalPrinterCollection
{
public:
// Initialize the PresetCollection with the "- default -" preset.
PhysicalPrinterCollection(const std::vector<std::string>& keys) : m_idx_selected(0) {}
PhysicalPrinterCollection(const std::vector<std::string>& keys);
~PhysicalPrinterCollection() {}
typedef std::deque<PhysicalPrinter>::iterator Iterator;
@ -585,63 +595,39 @@ public:
ConstIterator end() const { return m_printers.cend(); }
ConstIterator cend() const { return m_printers.cend(); }
bool empty() const {return m_printers.empty(); }
void reset(bool delete_files) {};
const std::deque<PhysicalPrinter>& operator()() const { return m_printers; }
// Load ini files of the particular type from the provided directory path.
void load_printers(const std::string& dir_path, const std::string& subdir){};
// Load a preset from an already parsed config file, insert it into the sorted sequence of presets
// and select it, losing previous modifications.
PhysicalPrinter& load_printer(const std::string& path, const std::string& name, const DynamicPrintConfig& config, bool select = true);
PhysicalPrinter& load_printer(const std::string& path, const std::string& name, DynamicPrintConfig&& config, bool select = true);
PhysicalPrinter& load_external_printer(
// Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
const std::string& path,
// Name of the profile, derived from the source file name.
const std::string& name,
// Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored.
const std::string& original_name,
// Config to initialize the preset from.
const DynamicPrintConfig& config,
// Select the preset after loading?
bool select = true);
void load_printers(const std::string& dir_path, const std::string& subdir);
// Save the printer under a new name. If the name is different from the old one,
// a new printer is stored into the list of printers.
// ? New printer is activated.
void save_printer(const std::string& new_name);
// New printer is activated.
void save_printer(const PhysicalPrinter& printer);
// Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully.
bool delete_current_printer() {return true;}
// Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully.
bool delete_printer(const std::string& name) { return true; }
bool delete_printer(const std::string& name);
// Select a printer. If an invalid index is provided, the first visible printer is selected.
PhysicalPrinter& select_printer(size_t idx);
// Return the selected preset, without the user modifications applied.
PhysicalPrinter& get_selected_preset() { return m_printers[m_idx_selected]; }
const PhysicalPrinter& get_selected_preset() const { return m_printers[m_idx_selected]; }
PhysicalPrinter& get_selected_printer() { return m_printers[m_idx_selected]; }
const PhysicalPrinter& get_selected_printer() const { return m_printers[m_idx_selected]; }
size_t get_selected_idx() const { return m_idx_selected; }
// Returns the name of the selected preset, or an empty string if no preset is selected.
std::string get_selected_preset_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : this->get_selected_preset().name; }
PhysicalPrinter& get_edited_preset() { return m_edited_printer; }
const PhysicalPrinter& get_edited_preset() const { return m_edited_printer; }
std::string get_selected_printer_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : this->get_selected_printer().name; }
DynamicPrintConfig* get_selected_printer_config() { return (m_idx_selected == size_t(-1)) ? nullptr : &(this->get_selected_printer().config); }
// Return a preset possibly with modifications.
PhysicalPrinter& default_printer(size_t idx = 0) { return m_printers[idx]; }
const PhysicalPrinter& default_printer(size_t idx = 0) const { return m_printers[idx]; }
// select printer with name and return reference on it
PhysicalPrinter& select_printer_by_name(const std::string& name);
bool has_selection() const { return m_idx_selected != size_t(-1); }
void unselect_printer() { m_idx_selected = size_t(-1); }
// used to update preset_choice from Tab
const std::deque<PhysicalPrinter>& get_presets() const { return m_printers; }
size_t get_idx_selected() { return m_idx_selected; }
// Return a preset by an index. If the preset is active, a temporary copy is returned.
PhysicalPrinter& printer(size_t idx) { return (idx == m_idx_selected) ? m_edited_printer : m_printers[idx]; }
// Return a printer by an index. If the printer is active, a temporary copy is returned.
PhysicalPrinter& printer(size_t idx) { return m_printers[idx]; }
const PhysicalPrinter& printer(size_t idx) const { return const_cast<PhysicalPrinterCollection*>(this)->printer(idx); }
// Return a preset by its name. If the preset is active, a temporary copy is returned.
@ -652,20 +638,10 @@ public:
return const_cast<PhysicalPrinterCollection*>(this)->find_printer(name, first_visible_if_not_found);
}
// Return number of presets including the "- default -" preset.
size_t size() const { return m_printers.size(); }
// Select a profile by its name. Return true if the selection changed.
// Without force, the selection is only updated if the index changes.
// With force, the changes are reverted if the new index is the same as the old index.
bool select_printer_by_name(const std::string& name, bool force) {};
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
std::string path_from_name(const std::string& new_name) const;
private:
// PhysicalPrinterCollection();
PhysicalPrinterCollection(const PhysicalPrinterCollection& other);
PhysicalPrinterCollection& operator=(const PhysicalPrinterCollection& other);
// Find a preset position in the sorted list of presets.
@ -674,8 +650,8 @@ private:
// If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name.
std::deque<PhysicalPrinter>::iterator find_printer_internal(const std::string& name)
{
PhysicalPrinter key(name);
auto it = std::lower_bound(m_printers.begin()+0, m_printers.end(), key);
PhysicalPrinter printer(name);
auto it = std::lower_bound(m_printers.begin(), m_printers.end(), printer);
return it;
}
std::deque<PhysicalPrinter>::const_iterator find_printer_internal(const std::string& name) const
@ -683,23 +659,18 @@ private:
return const_cast<PhysicalPrinterCollection*>(this)->find_printer_internal(name);
}
static std::vector<std::string> dirty_options(const Preset* edited, const Preset* reference, const bool is_printer_type = false);
// List of presets, starting with the "- default -" preset.
// List of printers
// Use deque to force the container to allocate an object per each entry,
// so that the addresses of the presets don't change during resizing of the container.
std::deque<PhysicalPrinter> m_printers;
// Initially this printer contains a copy of the selected printer. Later on, this copy may be modified by the user.
PhysicalPrinter m_edited_printer;
// Selected preset.
size_t m_idx_selected;
// Selected printer.
size_t m_idx_selected = size_t(-1);
// Path to the directory to store the config files into.
std::string m_dir_path;
};
//////////////////////////////////////////////////////////////////////
*/
} // namespace Slic3r

View file

@ -41,7 +41,8 @@ PresetBundle::PresetBundle() :
filaments(Preset::TYPE_FILAMENT, Preset::filament_options(), static_cast<const HostConfig&>(FullPrintConfig::defaults())),
sla_materials(Preset::TYPE_SLA_MATERIAL, Preset::sla_material_options(), static_cast<const SLAMaterialConfig&>(SLAFullPrintConfig::defaults())),
sla_prints(Preset::TYPE_SLA_PRINT, Preset::sla_print_options(), static_cast<const SLAPrintObjectConfig&>(SLAFullPrintConfig::defaults())),
printers(Preset::TYPE_PRINTER, Preset::printer_options(), static_cast<const HostConfig&>(FullPrintConfig::defaults()), "- default FFF -")
printers(Preset::TYPE_PRINTER, Preset::printer_options(), static_cast<const HostConfig&>(FullPrintConfig::defaults()), "- default FFF -"),
physical_printers(PhysicalPrinter::printer_options())
{
// The following keys are handled by the UI, they do not have a counterpart in any StaticPrintConfig derived classes,
// therefore they need to be handled differently. As they have no counterpart in StaticPrintConfig, they are not being
@ -139,14 +140,16 @@ void PresetBundle::setup_directories()
data_dir / "presets" / "filament",
data_dir / "presets" / "sla_print",
data_dir / "presets" / "sla_material",
data_dir / "presets" / "printer"
data_dir / "presets" / "printer",
data_dir / "presets" / "physical_printer"
#else
// Store the print/filament/printer presets at the same location as the upstream Slic3r.
data_dir / "print",
data_dir / "filament",
data_dir / "sla_print",
data_dir / "sla_material",
data_dir / "printer"
data_dir / "printer",
data_dir / "physical_printer"
#endif
};
for (const boost::filesystem::path &path : paths) {
@ -196,6 +199,11 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_
} catch (const std::runtime_error &err) {
errors_cummulative += err.what();
}
try {
this->physical_printers.load_printers(dir_user_presets, "physical_printer");
} catch (const std::runtime_error &err) {
errors_cummulative += err.what();
}
this->update_multi_material_filament_presets();
this->update_compatible(PresetSelectCompatibleType::Never);
if (! errors_cummulative.empty())
@ -422,6 +430,14 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr
// exist.
this->update_compatible(PresetSelectCompatibleType::Always);
this->update_multi_material_filament_presets();
// Parse the initial physical printer name.
std::string initial_physical_printer_name = remove_ini_suffix(config.get("extras", "physical_printer"));
// Activate physical printer from the config
const PhysicalPrinter* initial_physical_printer = physical_printers.find_printer(initial_physical_printer_name);
if (initial_physical_printer)
physical_printers.select_printer_by_name(initial_physical_printer_name);
}
// Export selections (current print, current filaments, current printer) into config.ini
@ -441,6 +457,8 @@ void PresetBundle::export_selections(AppConfig &config)
config.set("presets", "sla_print", sla_prints.get_selected_preset_name());
config.set("presets", "sla_material", sla_materials.get_selected_preset_name());
config.set("presets", "printer", printers.get_selected_preset_name());
config.set("extras", "physical_printer", physical_printers.get_selected_printer_name());
}
DynamicPrintConfig PresetBundle::full_config() const

View file

@ -39,6 +39,7 @@ public:
PresetCollection& materials(PrinterTechnology pt) { return pt == ptFFF ? this->filaments : this->sla_materials; }
const PresetCollection& materials(PrinterTechnology pt) const { return pt == ptFFF ? this->filaments : this->sla_materials; }
PrinterPresetCollection printers;
PhysicalPrinterCollection physical_printers;
// Filament preset names for a multi-extruder or multi-material print.
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
std::vector<std::string> filament_presets;

View file

@ -130,6 +130,26 @@ void PrintConfigDef::init_common_params()
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.2));
// Options used by physical printers
def = this->add("login", coString);
def->label = L("Login");
// def->tooltip = L("");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("password", coString);
def->label = L("Password");
// def->tooltip = L("");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("preset_name", coString);
def->label = L("Printer preset name");
def->tooltip = L("Related printer preset name");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
}
void PrintConfigDef::init_fff_params()