mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-14 12:37:46 +00:00
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
This commit is contained in:
226
docs/U1_Filament_Compatibility_Fix.md
Normal file
226
docs/U1_Filament_Compatibility_Fix.md
Normal file
@@ -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<Preset&>(*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<Preset&>(*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
|
||||||
@@ -16275,7 +16275,10 @@ msgstr ""
|
|||||||
msgid "Point and point assembly"
|
msgid "Point and point assembly"
|
||||||
msgstr ""
|
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 ""
|
msgstr ""
|
||||||
|
|
||||||
msgid "Connection has been disconnected and recovery attempt failed. Please reconnect."
|
msgid "Connection has been disconnected and recovery attempt failed. Please reconnect."
|
||||||
|
|||||||
@@ -15309,8 +15309,11 @@ msgstr "面和面组装"
|
|||||||
msgid "Point and point assembly"
|
msgid "Point and point assembly"
|
||||||
msgstr "点和点组装"
|
msgstr "点和点组装"
|
||||||
|
|
||||||
msgid "Please do not include the special characters #, *, and ;in filenames."
|
msgid "Please do not include the special characters #, *, ;, \\, /, :, \", <, >, or | in filenames."
|
||||||
msgstr "在文件名中勿使用特殊字符“#”、“*”和“;”。"
|
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."
|
msgid "Connection has been disconnected and recovery attempt failed. Please reconnect."
|
||||||
msgstr "已断开连接,尝试恢复连接失败。请重新连接。"
|
msgstr "已断开连接,尝试恢复连接失败。请重新连接。"
|
||||||
|
|||||||
@@ -1150,12 +1150,15 @@ void PlaterPresetComboBox::update()
|
|||||||
|
|
||||||
for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) {
|
for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) {
|
||||||
std::string filament_name = iter->second.first;
|
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()) {
|
if (item_iter == filaments.end()) {
|
||||||
item_iter = std::find_if(filaments.begin(), 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()) {
|
if (item_iter != filaments.end()) {
|
||||||
@@ -1721,12 +1724,15 @@ void TabPresetComboBox::update()
|
|||||||
|
|
||||||
for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) {
|
for (auto iter = machine_filaments.begin(); iter != machine_filaments.end();) {
|
||||||
std::string filament_name = iter->second.first;
|
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()) {
|
if (item_iter == filaments.end()) {
|
||||||
item_iter = std::find_if(filaments.begin(), 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()) {
|
if (item_iter != filaments.end()) {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ void PrintHostSendDialog::init()
|
|||||||
|
|
||||||
const AppConfig* app_config = wxGetApp().app_config;
|
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());
|
label_dir_hint->Wrap(CONTENT_WIDTH * wxGetApp().em_unit());
|
||||||
|
|
||||||
content_sizer->Add(txt_filename, 0, wxEXPAND);
|
content_sizer->Add(txt_filename, 0, wxEXPAND);
|
||||||
@@ -135,9 +135,9 @@ void PrintHostSendDialog::init()
|
|||||||
// .gcode suffix control
|
// .gcode suffix control
|
||||||
auto validate_path = [this](const wxString &path) -> bool {
|
auto validate_path = [this](const wxString &path) -> bool {
|
||||||
// BBS: 检查文件名是否包含特殊字符
|
// BBS: 检查文件名是否包含特殊字符
|
||||||
if (path.find_first_of("#*;") != wxString::npos) {
|
if (path.find_first_of("#*;\\/:\"<>|") != wxString::npos) {
|
||||||
MessageDialog msg_window(this,
|
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);
|
wxString(SLIC3R_APP_NAME), wxYES | wxNO | wxICON_WARNING);
|
||||||
if (msg_window.ShowModal() == wxID_NO)
|
if (msg_window.ShowModal() == wxID_NO)
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user