From 5989d15428976306b7292705bf90d7c2e0f6c42c Mon Sep 17 00:00:00 2001 From: xiaoyeliu <166936931+womendoushihaoyin@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:30:38 +0800 Subject: [PATCH] feature: add filename validation & check the compatiblity of the filament from device (#132) * Fix: didn't check the compatiblity of the filament which is gotten from machine * Optimize the filename validation --- docs/U1_Filament_Compatibility_Fix.md | 226 ++++++++++++++++++ localization/i18n/Snapmaker_Orca.pot | 5 +- .../i18n/zh_CN/Snapmaker_Orca_zh_CN.po | 7 +- src/slic3r/GUI/PresetComboBoxes.cpp | 18 +- src/slic3r/GUI/PrintHostDialogs.cpp | 6 +- 5 files changed, 250 insertions(+), 12 deletions(-) create mode 100644 docs/U1_Filament_Compatibility_Fix.md diff --git a/docs/U1_Filament_Compatibility_Fix.md b/docs/U1_Filament_Compatibility_Fix.md new file mode 100644 index 0000000000..1fc39a5b89 --- /dev/null +++ b/docs/U1_Filament_Compatibility_Fix.md @@ -0,0 +1,226 @@ +# U1设备耗材兼容性检查修复 + +## 问题描述 + +当连接 Snapmaker U1 设备时,如果设备上编辑的耗材是 "Snapmaker PETG",耗材下拉框的 "Machine Filament" 部分会显示该耗材。然而,`Snapmaker PETG.json` 配置文件的 `compatible_printers` 列表中**不包含** U1 设备(仅包含 A250/A350 系列),导致显示了一个不兼容的耗材配置。 + +### 现象 + +- 引导页和选择耗材页**没有** "Snapmaker PETG @U1" 选项(正常) +- 连接 U1 设备后,下拉框 "Machine Filament" 部分**有** "Snapmaker PETG"(问题) +- 但 `Snapmaker PETG` 的 `compatible_printers` 不包含 U1,配置不匹配 + +## 根本原因 + +### 代码位置 + +`src/slic3r/GUI/PresetComboBoxes.cpp` + +- 第一处:第 1151-1164 行(`PlaterPresetComboBox::update()` 函数) +- 第二处:第 1725-1738 行(另一个同名函数,可能是不同类) + +### 问题代码 + +```cpp +// 修改前的代码 +for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) { + std::string filament_name = iter->second.first; + // 1. 精确匹配名称 + auto item_iter = std::find_if(filaments.begin(), filaments.end(), + [&filament_name, this](auto& f) { return f.name == filament_name; }); + + // 2. 如果没找到,尝试带 @U1 后缀 + if (item_iter == filaments.end()) { + item_iter = std::find_if(filaments.begin(), filaments.end(), + [&filament_name, this](auto& f) { return f.name == filament_name + " @U1"; }); + } + + // 3. 只要找到就添加,没有检查 is_compatible! + if (item_iter != filaments.end()) { + const_cast(*item_iter).is_visible = true; + // ... 添加到下拉框 + } +} +``` + +### 缺少的检查 + +代码只检查了耗材名称是否匹配,**没有检查** `is_compatible` 标志。这个标志是由 `PresetCollection::update_compatible_internal()` 函数根据 `compatible_printers` 配置计算的。 + +### 耗材同步流程 + +1. 设备连接时,通过 `SSWCP_Instance::update_filament_info()`(SSWCP.cpp:1440-1588)同步耗材 +2. 设备发送:`filament_vendor="Snapmaker"`, `filament_type="PETG"`, `filament_sub_type="NONE"` +3. 构建耗材名称:`"Snapmaker PETG"`(**不带 @U1 后缀**) +4. 存储到 `wxGetApp().preset_bundle->machine_filaments` +5. 下拉框更新时尝试匹配此名称 + +## 修复方案 + +### 修改内容 + +在两次匹配的 lambda 表达式中都增加 `&& f.is_compatible` 检查: + +```cpp +// 修改后的代码 +for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) { + std::string filament_name = iter->second.first; + + // 第一次匹配: 精确匹配名称 + 兼容性检查 + auto item_iter = std::find_if(filaments.begin(), filaments.end(), + [&filament_name, this](auto& f) { return f.name == filament_name && f.is_compatible; }); + + // 第二次匹配: 如果第一次失败,尝试带 @U1 后缀 + 兼容性检查 + if (item_iter == filaments.end()) { + item_iter = std::find_if(filaments.begin(), filaments.end(), + [&filament_name, this](auto& f) { return f.name == filament_name + " @U1" && f.is_compatible; }); + } + + if (item_iter != filaments.end()) { + const_cast(*item_iter).is_visible = true; + // ... 添加到下拉框 + } else { + iter = machine_filaments.erase(iter); + } +} +``` + +### 修复逻辑 + +1. **第一次匹配**:精确匹配 "Snapmaker PETG" + 检查 `is_compatible` + - 如果 `Snapmaker PETG.json` 的 `compatible_printers` 不包含 U1 + - 则 `is_compatible = false`,匹配失败 + +2. **第二次匹配**:尝试 "Snapmaker PETG @U1" + 检查 `is_compatible` + - 如果在 Snapmaker.json 中注册了 "Snapmaker PETG @U1" + - 且其 `compatible_printers` 包含 U1 + - 则匹配成功 + +3. **结果**:只有**名称匹配且兼容**的耗材才会显示 + +## 技术细节 + +### is_compatible 计算逻辑 + +位置:`src/libslic3r/Preset.cpp:639-670` + +```cpp +bool is_compatible_with_printer(const PresetWithVendorProfile &preset, + const PresetWithVendorProfile &active_printer, + const DynamicPrintConfig *extra_config) +{ + auto *compatible_printers = preset.preset.config.option("compatible_printers"); + bool has_compatible_printers = compatible_printers != nullptr && + !compatible_printers->values.empty(); + + return preset.preset.is_default || + active_printer.preset.name.empty() || + !has_compatible_printers || + std::find(compatible_printers->values.begin(), + compatible_printers->values.end(), + active_printer.preset.name) != compatible_printers->values.end(); +} +``` + +### 下拉框填充顺序 + +`PlaterPresetComboBox::update()` 函数按以下顺序填充下拉框: + +1. **Machine Filament** - 从设备同步的耗材(本次修复部分) +2. **Project-inside presets** - 项目内嵌预设 +3. **User presets** - 用户自定义预设 +4. **System presets** - 系统预设(本来就检查 `is_compatible`,第 1073 行) + +### 两处修改的原因 + +在 `PresetComboBoxes.cpp` 中有两处几乎相同的代码,可能属于不同的类或重载函数: + +- 第 1151-1164 行:`PlaterPresetComboBox::update()` +- 第 1725-1738 行:另一个相同的逻辑(可能是不同 UI 组件) + +两处都需要修改以确保一致性。 + +## 相关配置文件 + +### Snapmaker PETG.json + +位置:`resources/profiles/Snapmaker/filament/Snapmaker PETG.json` + +```json +{ + "type": "filament", + "name": "Snapmaker PETG", + "compatible_printers": [ + "Snapmaker A250 (0.4 nozzle)", + "Snapmaker A250 (0.6 nozzle)", + ... + "Snapmaker A350 QSKit (0.8 nozzle)" + ] +} +``` + +**不包含 U1 设备** + +### Snapmaker PETG @U1.json + +位置:`resources/profiles/Snapmaker/filament/Snapmaker PETG @U1.json` + +```json +{ + "type": "filament", + "name": "Snapmaker PETG @U1", + "compatible_printers": [ + "Snapmaker U1 (0.4 nozzle)" + ] +} +``` + +**文件存在但未在 Snapmaker.json 中注册** + +## 后续建议 + +要让 U1 设备正确识别 Snapmaker PETG 耗材,需要以下操作之一: + +### 选项 A:注册 @U1 专用配置(推荐) + +在 `resources/profiles/Snapmaker.json` 的 `filament_list` 中添加: + +```json +{ + "name": "Snapmaker PETG @U1", + "sub_path": "filament/Snapmaker PETG @U1.json" +} +``` + +### 选项 B:扩展通用配置的兼容性 + +在 `resources/profiles/Snapmaker/filament/Snapmaker PETG.json` 的 `compatible_printers` 中添加: + +```json +"compatible_printers": [ + ...existing..., + "Snapmaker U1 (0.4 nozzle)" +] +``` + +## 测试建议 + +1. **测试不兼容耗材不显示**: + - 连接 U1 设备 + - 确认下拉框 "Machine Filament" 部分不显示 "Snapmaker PETG"(如果不兼容) + +2. **测试兼容耗材正常显示**: + - 在 Snapmaker.json 中注册 "Snapmaker PETG @U1" + - 连接 U1 设备 + - 确认下拉框正确显示 "Snapmaker PETG @U1" + +3. **测试其他耗材不受影响**: + - 确认其他已注册的 U1 兼容耗材(如 "Snapmaker ABS @U1")正常显示 + +## 修改文件 + +- `src/slic3r/GUI/PresetComboBoxes.cpp`(两处修改) + +## 修改日期 + +2026-01-22 diff --git a/localization/i18n/Snapmaker_Orca.pot b/localization/i18n/Snapmaker_Orca.pot index 7d8d07ba49..e3ea9ca77d 100644 --- a/localization/i18n/Snapmaker_Orca.pot +++ b/localization/i18n/Snapmaker_Orca.pot @@ -16275,7 +16275,10 @@ msgstr "" msgid "Point and point assembly" msgstr "" -msgid "Please do not include the special characters #, *, and ;in filenames." +msgid "Please do not include the special characters #, *, ;, \\, /, :, \", <, >, or | in filenames." +msgstr "" + +msgid "The filename '%s' contains special characters (#, *, ;, \\, /, :, \", <, >, or |) which may cause issues.Do you wish to continue?" msgstr "" msgid "Connection has been disconnected and recovery attempt failed. Please reconnect." diff --git a/localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po b/localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po index 154323af2e..b04fe92447 100644 --- a/localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po +++ b/localization/i18n/zh_CN/Snapmaker_Orca_zh_CN.po @@ -15309,8 +15309,11 @@ msgstr "面和面组装" msgid "Point and point assembly" msgstr "点和点组装" -msgid "Please do not include the special characters #, *, and ;in filenames." -msgstr "在文件名中勿使用特殊字符“#”、“*”和“;”。" +msgid "Please do not include the special characters #, *, ;, \\, /, :, \", <, >, or | in filenames." +msgstr "在文件名中勿使用特殊字符"#"*""";""\\""/" ":"\""<"">"或"|"。" + +msgid "The filename '%s' contains special characters (#, *, ;, \\, /, :, \", <, >, or |) which may cause issues.Do you wish to continue?" +msgstr "文件名"%s"包含特殊字符(# * ; \\ / : \" < > |)可能会导致问题。是否继续?" msgid "Connection has been disconnected and recovery attempt failed. Please reconnect." msgstr "已断开连接,尝试恢复连接失败。请重新连接。" diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 2b2d6c74d7..18d7528336 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -1150,12 +1150,15 @@ void PlaterPresetComboBox::update() for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) { std::string filament_name = iter->second.first; - auto item_iter = std::find_if(filaments.begin(), filaments.end(), - [&filament_name, this](auto& f) { return f.name == filament_name; }); + // First match: exact name + compatibility check + auto item_iter = std::find_if(filaments.begin(), filaments.end(), + [&filament_name, this](auto& f) { return f.name == filament_name && f.is_compatible; }); + + // Second match: if first fails, try with @U1 suffix + compatibility check if (item_iter == filaments.end()) { item_iter = std::find_if(filaments.begin(), filaments.end(), - [&filament_name, this](auto& f) { return f.name == filament_name + " @U1"; }); + [&filament_name, this](auto& f) { return f.name == filament_name + " @U1" && f.is_compatible; }); } if (item_iter != filaments.end()) { @@ -1721,12 +1724,15 @@ void TabPresetComboBox::update() for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) { std::string filament_name = iter->second.first; - auto item_iter = std::find_if(filaments.begin(), filaments.end(), - [&filament_name, this](auto& f) { return f.name == filament_name; }); + // First match: exact name + compatibility check + auto item_iter = std::find_if(filaments.begin(), filaments.end(), + [&filament_name, this](auto& f) { return f.name == filament_name && f.is_compatible; }); + + // Second match: if first fails, try with @U1 suffix + compatibility check if (item_iter == filaments.end()) { item_iter = std::find_if(filaments.begin(), filaments.end(), - [&filament_name, this](auto& f) { return f.name == filament_name + " @U1"; }); + [&filament_name, this](auto& f) { return f.name == filament_name + " @U1" && f.is_compatible; }); } if (item_iter != filaments.end()) { diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index e728d2b075..24b022243a 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -68,7 +68,7 @@ void PrintHostSendDialog::init() const AppConfig* app_config = wxGetApp().app_config; - auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _L("Please do not include the special characters #, *, and ;in filenames.")); + auto *label_dir_hint = new wxStaticText(this, wxID_ANY, _L("Please do not include the special characters #, *, ;, \\, /, :, \", <, >, or | in filenames.")); label_dir_hint->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); content_sizer->Add(txt_filename, 0, wxEXPAND); @@ -135,9 +135,9 @@ void PrintHostSendDialog::init() // .gcode suffix control auto validate_path = [this](const wxString &path) -> bool { // BBS: 检查文件名是否包含特殊字符 - if (path.find_first_of("#*;") != wxString::npos) { + if (path.find_first_of("#*;\\/:\"<>|") != wxString::npos) { MessageDialog msg_window(this, - wxString::Format(_L("The filename '%s' contains special characters (#, *, or ;) which may cause issues.Do you wish to continue?"), path), + wxString::Format(_L("The filename '%s' contains special characters (#, *, ;, \\, /, :, \", <, >, or |) which may cause issues.Do you wish to continue?"), path), wxString(SLIC3R_APP_NAME), wxYES | wxNO | wxICON_WARNING); if (msg_window.ShowModal() == wxID_NO) return false;