diff --git a/README.md b/README.md index dca8cf6..97c0004 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # UserStringProperty -Rhino 插件,用于根据用户自定义 XML 配置,给 Block 实例附加构件属性(UserString)。 +Rhino 插件,根据用户自定义 XML 配置,给 Block 实例附加属性(UserString)。 ## 功能 @@ -9,7 +9,7 @@ Rhino 插件,用于根据用户自定义 XML 配置,给 Block 实例附加 - 自动保存到 Rhino Block 的 UserString - 支持多个 XML 模板同时加载、合并 - 模板自动持久化,Rhino 重启后自动恢复 -- 导入时提供四种合并模式(追加、替代、合并更新、智能合并) +- 导入时检测属性集冲突,覆盖或新增 ## 安装 @@ -32,28 +32,25 @@ dotnet build 1. 在 Rhino 中输入命令:`UserstringProperty` 2. 选择要编辑的 Block 实例 3. 默认模板首次启动自动加载;点 **加载XML** 导入自定义模板 -4. 在下拉框中选择属性集,编辑各字段值 -5. 点击 **保存** +4. 在弹出的对话框中选择 cmig 和属性集,若同名已存在则需确认覆盖 +5. 在下拉框中选择属性集,编辑各字段值 +6. 点击 **写入属性** -## 模板导入模式 +## 模板导入 -加载 XML 时,如果已有模板,会弹出对话框让选择导入模式: +加载 XML 时,会弹出对话框让选择 cmig 和属性集,检测同名冲突: -| 模式 | 说明 | -|------|------| -| 添加为新属性集 | 追加到现有列表末尾 | -| 完全替代现有模板 | 清空所有现有属性集 | -| 合并更新 | 同名属性集覆盖,其他保留 | -| 智能合并 | 同名覆盖,同时追加新属性集 | +- **同名属性集不存在** → 直接保存为新模板 +- **同名属性集已存在** → 需确认是否覆盖 ## XML 配置格式 -插件根据 XML 动态生成 UI。示例参见 `Component_Property_base.xml` 和 `Component_Property_carbon.xml`。 +插件根据 XML 动态生成 UI。示例 XML 格式如下: ```xml - - + + @@ -95,7 +92,7 @@ dotnet build ``` UserStringProperty/ -├── CLAUDE.md # agent 指示(不要当作文档) +├── CLAUDE.md # agent 指示 ├── PLAN.md # 待办事项与开发计划 ├── UserStringProperty.csproj ├── UserStringProperty.cs # 插件主类 @@ -111,11 +108,15 @@ UserStringProperty/ └── EmbeddedTemplates.cs # 内嵌默认 XML 模板 ``` -## 环境要求 +## 编译环境 + +- **.NET SDK 8.0** +- **Rhino 8**(包含 RhinoCommon.dll SDK 引用) +- Windows 10/11 + +## 运行时要求 - Rhino 8 -- .NET Framework 4.8 -- .NET SDK 8.0(编译用) ## License diff --git a/UserStringProperty/Core/TemplateManager.cs b/UserStringProperty/Core/TemplateManager.cs index a8285b6..4ae65e2 100644 --- a/UserStringProperty/Core/TemplateManager.cs +++ b/UserStringProperty/Core/TemplateManager.cs @@ -38,7 +38,8 @@ namespace UserStringProperty { _pluginFolder = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), - "McNeel", "Rhinoceros", "8.0", "plugins", "UserStringProperty" + "McNeel", "Rhinoceros", "8.0", "Plug-ins", + "UserStringProperty (C286E052-06F6-475F-A882-1C1AA31744CF)" ); if (!Directory.Exists(_pluginFolder)) Directory.CreateDirectory(_pluginFolder); @@ -61,6 +62,8 @@ namespace UserStringProperty // 执行导入 public void Import(string filePath, string cmigName, string propertysetName) { + RebuildIndexIfMissing(); + var config = XmlPropertyConfig.Load(filePath); // 检查文件是否已存在 @@ -82,6 +85,13 @@ namespace UserStringProperty { File.WriteAllText(destPath, xmlContent); _loadedPaths.Add(destPath); + + // 将新导入的 config 加入内存列表 + var newConfig = XmlPropertyConfig.Load(destPath); + if (newConfig.PropertySets.Count > 0) + { + _configs.Add(newConfig); + } } SaveIndex(); @@ -192,6 +202,30 @@ namespace UserStringProperty File.WriteAllLines(GetIndexFilePath(), _loadedPaths); } + private void RebuildIndexIfMissing() + { + var indexPath = GetIndexFilePath(); + if (!File.Exists(indexPath)) + { + var files = GetLocalTemplateFiles(); + _loadedPaths.Clear(); + foreach (var file in files) + { + try + { + var config = XmlPropertyConfig.Load(file); + if (config.PropertySets.Count > 0) + { + _configs.Add(config); + _loadedPaths.Add(file); + } + } + catch { } + } + SaveIndex(); + } + } + private void SaveTemplatesToPluginFolder() { // 按 [cmig name]-[propertyset name].xml 格式保存 diff --git a/UserStringProperty/Resources/EmbeddedTemplates.cs b/UserStringProperty/Resources/EmbeddedTemplates.cs index 1457840..f8119f2 100644 --- a/UserStringProperty/Resources/EmbeddedTemplates.cs +++ b/UserStringProperty/Resources/EmbeddedTemplates.cs @@ -7,7 +7,7 @@ namespace UserStringProperty.Resources public const string BaseXml = @" - + @@ -118,13 +118,107 @@ namespace UserStringProperty.Resources +"; + + public const string ContractXml = @" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "; public static void ExtractToFolder(string folder) { if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); - File.WriteAllText(Path.Combine(folder, "构件属性-构件属性-基础.xml"), BaseXml); + File.WriteAllText(Path.Combine(folder, "构件属性-构件属性-基本.xml"), BaseXml); File.WriteAllText(Path.Combine(folder, "构件碳排放属性-构件碳排放属性.xml"), CarbonXml); + File.WriteAllText(Path.Combine(folder, "构件合同属性-构件合同属性.xml"), ContractXml); } } } \ No newline at end of file diff --git a/UserStringProperty/UI/MainDialog.cs b/UserStringProperty/UI/MainDialog.cs index 8efe3bc..94b1332 100644 --- a/UserStringProperty/UI/MainDialog.cs +++ b/UserStringProperty/UI/MainDialog.cs @@ -40,7 +40,7 @@ namespace UserStringProperty.UI private void InitializeComponent() { - this.Text = "构件属性编辑"; + this.Text = "属性编辑"; this.Size = new Size(550, 580); this.StartPosition = FormStartPosition.CenterParent; this.FormBorderStyle = FormBorderStyle.FixedDialog; @@ -68,7 +68,7 @@ namespace UserStringProperty.UI // PropertySet 选择 var lblPropertySet = new Label { - Text = "属性模板:", + Text = "属性集:", Location = new Point(285, 10), Size = new Size(80, 20) }; @@ -91,19 +91,6 @@ namespace UserStringProperty.UI }; _btnLoadXml.Click += BtnLoadXml_Click; - var btnResetTemplate = new Button - { - Text = "重置模板", - Location = new Point(105, 38), - Size = new Size(90, 25) - }; - btnResetTemplate.Click += (s, e) => - { - TemplateManager.Instance.Clear(); - RefreshCmigCombo(); - UpdateTemplateInfo(); - }; - _lblTemplateInfo = new Label { Text = "", @@ -135,7 +122,7 @@ namespace UserStringProperty.UI _btnCancel.Click += (s, e) => this.Close(); this.Controls.AddRange(new Control[] { - _btnLoadXml, btnResetTemplate, _lblTemplateInfo, + _btnLoadXml, _lblTemplateInfo, lblCmig, _cmbCmig, lblPropertySet, _cmbPropertySet, lblFields, _panelFields, _btnSave, _btnCancel }); diff --git a/UserStringProperty/UI/XmlImportDialog.cs b/UserStringProperty/UI/XmlImportDialog.cs index d877528..ecf3608 100644 --- a/UserStringProperty/UI/XmlImportDialog.cs +++ b/UserStringProperty/UI/XmlImportDialog.cs @@ -41,7 +41,7 @@ namespace UserStringProperty.UI private void InitializeComponent() { this.Text = "导入属性集"; - this.Size = new Size(550, 350); + this.Size = new Size(550, 250); this.StartPosition = FormStartPosition.CenterParent; this.FormBorderStyle = FormBorderStyle.FixedDialog; this.MaximizeBox = false; @@ -49,22 +49,10 @@ namespace UserStringProperty.UI int y = 15; - // 第一段:选择属性集 - var lblSection1 = new Label - { - Text = "第一段:选择属性集", - Location = new Point(15, y), - Size = new Size(200, 20), - Font = new Font(Font.FontFamily, 10, FontStyle.Bold) - }; - this.Controls.Add(lblSection1); - - y += 30; - // 选择 Cmig var lblCmig = new Label { - Text = "属性容器 (cmig):", + Text = "模板类型 (cmig):", Location = new Point(15, y), Size = new Size(120, 20) }; @@ -108,30 +96,6 @@ namespace UserStringProperty.UI y += 35; - // 分隔线 - var separator = new Label - { - Text = "────────────────────────────────────────────────────", - Location = new Point(15, y), - Size = new Size(500, 15), - ForeColor = Color.Gray - }; - this.Controls.Add(separator); - - y += 25; - - // 第二段:导入模式 - var lblSection2 = new Label - { - Text = "第二段:检测冲突", - Location = new Point(15, y), - Size = new Size(200, 20), - Font = new Font(Font.FontFamily, 10, FontStyle.Bold) - }; - this.Controls.Add(lblSection2); - - y += 30; - // 即将导入的信息 _lblIncomingInfo = new Label { @@ -150,8 +114,7 @@ namespace UserStringProperty.UI { Text = "", Location = new Point(15, y), - Size = new Size(500, 30), - ForeColor = Color.DarkOrange + Size = new Size(500, 20) }; this.Controls.Add(_lblConflictWarning); @@ -166,8 +129,24 @@ namespace UserStringProperty.UI }; _btnOK.Click += (s, e) => { - SelectedCmigName = _cmbCmig.SelectedItem?.ToString(); - SelectedPropertySetName = _cmbPropertySet.SelectedItem?.ToString(); + var cmigName = _cmbCmig.SelectedItem?.ToString() ?? ""; + var psName = _cmbPropertySet.SelectedItem?.ToString() ?? ""; + var fileName = $"{cmigName}-{psName}.xml"; + var existingPath = Path.Combine(_pluginFolder, fileName); + + if (File.Exists(existingPath)) + { + var result = MessageBox.Show( + $"文件 {fileName} 已存在,是否覆盖?", + "确认覆盖", + MessageBoxButtons.YesNo, + MessageBoxIcon.Warning); + if (result != DialogResult.Yes) + return; + } + + SelectedCmigName = cmigName; + SelectedPropertySetName = psName; this.DialogResult = DialogResult.OK; this.Close(); }; @@ -203,16 +182,16 @@ namespace UserStringProperty.UI var existingPath = Path.Combine(_pluginFolder, fileName); var exists = File.Exists(existingPath); - _lblIncomingInfo.Text = $"待导入: {fileName}"; + _lblIncomingInfo.Text = $"待导入: {cmigName}-{psName}"; if (exists) { - _lblConflictWarning.Text = $"⚠ 文件已存在: {fileName}\n是否替换现有文件?"; - _lblConflictWarning.ForeColor = Color.Red; + _lblConflictWarning.Text = $"⚠ 同名属性集已存在,将覆盖现有文件"; + _lblConflictWarning.ForeColor = Color.DarkOrange; } else { - _lblConflictWarning.Text = $"✓ 文件不存在,将作为新文件保存"; + _lblConflictWarning.Text = $"✓ 同名属性集不存在,将作为新文件保存"; _lblConflictWarning.ForeColor = Color.DarkGreen; } } diff --git a/UserStringProperty/UserStringProperty.cs b/UserStringProperty/UserStringProperty.cs index 198c49d..5ed0ae4 100644 --- a/UserStringProperty/UserStringProperty.cs +++ b/UserStringProperty/UserStringProperty.cs @@ -1,7 +1,11 @@ using System; +using System.Reflection; +using System.Runtime.InteropServices; using Rhino; using Rhino.PlugIns; +[assembly: Guid("C286E052-06F6-475F-A882-1C1AA31744CF")] + namespace UserStringProperty { public class UserStringPropertyPlugin : PlugIn diff --git a/UserStringProperty/UserStringProperty.csproj b/UserStringProperty/UserStringProperty.csproj index cf848cf..b55f0d2 100644 --- a/UserStringProperty/UserStringProperty.csproj +++ b/UserStringProperty/UserStringProperty.csproj @@ -18,8 +18,7 @@ 1.0 YourCompany User String Property Plugin - - + en