From 61834d3fdb44ef5b4616bd48ade47b98ab1e1eb1 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 23 Feb 2024 15:19:38 +0100 Subject: [PATCH] SavePresetDialog: Fixed preset name validation. Prevent saving a new preset with a name that differs from an existing preset only in a case-sensitive manner. Related to #6798 - Printer profile gone again and print settings gone again: Profile name differing in case only --- src/slic3r/GUI/SavePresetDialog.cpp | 56 ++++++++++++++++++++++++++--- src/slic3r/GUI/SavePresetDialog.hpp | 12 ++++++- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/SavePresetDialog.cpp b/src/slic3r/GUI/SavePresetDialog.cpp index d8eaf95971..c915c5c170 100644 --- a/src/slic3r/GUI/SavePresetDialog.cpp +++ b/src/slic3r/GUI/SavePresetDialog.cpp @@ -52,6 +52,18 @@ std::string SavePresetDialog::Item::get_init_preset_name(const std::string &suff return preset_name; } +void SavePresetDialog::Item::init_casei_preset_names() +{ + m_casei_preset_names.clear(); + m_casei_preset_names.reserve(m_presets->size()); + + for (const Preset& preset : *m_presets) + if (!preset.is_default) + m_casei_preset_names.emplace_back(PresetName({ boost::to_lower_copy(preset.name), preset.name })); + + std::sort(m_casei_preset_names.begin(), m_casei_preset_names.end()); +} + void SavePresetDialog::Item::init_input_name_ctrl(wxBoxSizer *input_name_sizer, const std::string preset_name) { if (m_use_text_ctrl) { @@ -114,6 +126,8 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBox input_name_sizer->Add(m_valid_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, BORDER_W); init_input_name_ctrl(input_name_sizer, get_init_preset_name(suffix)); + init_casei_preset_names(); + if (label_top) sizer->Add(label_top, 0, wxEXPAND | wxTOP| wxBOTTOM, BORDER_W); sizer->Add(input_name_sizer,0, wxEXPAND | (label_top ? 0 : wxTOP) | wxBOTTOM, BORDER_W); @@ -144,14 +158,44 @@ SavePresetDialog::Item::Item(wxWindow* parent, wxBoxSizer* sizer, const std::str update(); } +static std::string get_conflict_name(const std::vector& casei_names, const std::string& preset_name) +{ + if (!casei_names.empty()) { + const std::string lower_name = boost::to_lower_copy(preset_name); + auto it = Slic3r::lower_bound_by_predicate(casei_names.begin(), casei_names.end(), + [lower_name](const auto& l) { return l.casei_name < lower_name; }); + if (it != casei_names.end() && it->casei_name == lower_name) + return it->name; + } + return std::string(); +} + +std::string SavePresetDialog::Item::preset_name() const +{ + if (m_use_text_ctrl) + return m_preset_name; + + const std::string existed_preset_name = get_conflict_name(m_casei_preset_names, m_preset_name); + if (existed_preset_name.empty()) + return m_preset_name; + + return existed_preset_name; +} + const Preset* SavePresetDialog::Item::get_existing_preset() const { + std::string existed_preset_name = get_conflict_name(m_casei_preset_names, m_preset_name); + if (existed_preset_name.empty()) { + // Preset has not been not found in the sorted list of non-default presets. Try the defaults. + return nullptr; + } + if (m_presets) - return m_presets->find_preset(m_preset_name, false); + return m_presets->find_preset(existed_preset_name, false); for (const Preset::Type& type : PresetBundle::types_list(m_printer_technology)) { const PresetCollection& presets = wxGetApp().preset_bundle->get_presets(type); - if (const Preset* preset = presets.find_preset(m_preset_name, false)) + if (const Preset* preset = presets.find_preset(existed_preset_name, false)) return preset; } @@ -191,6 +235,7 @@ void SavePresetDialog::Item::update() if (m_valid_type == ValidationType::Valid && existing && (existing->is_default || existing->is_system)) { info_line = m_use_text_ctrl ? _L("This name is used for a system profile name, use another.") : _L("Cannot overwrite a system profile."); + info_line += "\n" + GUI::format_wxstr("(%1%)", existing->name); m_valid_type = ValidationType::NoValid; } @@ -211,10 +256,11 @@ void SavePresetDialog::Item::update() } else { if (existing->is_compatible) - info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists.")) % m_preset_name).str()); + info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists.")) % existing->name).str()); else - info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is incompatible with selected printer.")) % m_preset_name).str()); - info_line += "\n" + _L("Note: This preset will be replaced after saving"); + info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is incompatible with selected printer.")) % existing->name).str()); + info_line += "\n" + (m_use_text_ctrl ? _L("Note: This preset will be replaced after renaming") : + _L("Note: Preset modifications will be saved exactly into this preset")); m_valid_type = ValidationType::Warning; } } diff --git a/src/slic3r/GUI/SavePresetDialog.hpp b/src/slic3r/GUI/SavePresetDialog.hpp index 04ba731702..6922dcfa9b 100644 --- a/src/slic3r/GUI/SavePresetDialog.hpp +++ b/src/slic3r/GUI/SavePresetDialog.hpp @@ -49,7 +49,14 @@ public: bool is_valid() const { return m_valid_type != ValidationType::NoValid; } Preset::Type type() const { return m_type; } - std::string preset_name() const { return m_preset_name; } + std::string preset_name() const; + + struct PresetName { + std::string casei_name; + std::string name; + + bool operator<(const PresetName& other) const { return other.casei_name > this->casei_name; } + }; private: Preset::Type m_type {Preset::TYPE_INVALID}; @@ -66,8 +73,11 @@ public: PresetCollection* m_presets {nullptr}; + std::vector m_casei_preset_names; + std::string get_init_preset_name(const std::string &suffix); void init_input_name_ctrl(wxBoxSizer *input_name_sizer, std::string preset_name); + void init_casei_preset_names(); const Preset* get_existing_preset() const ; void update();