diff --git a/WordAddIn/.vs/WordAddIn/CopilotIndices/17.14.1577.30250/CodeChunks.db b/WordAddIn/.vs/WordAddIn/CopilotIndices/17.14.1577.30250/CodeChunks.db
index e5dbd6f..5c06287 100644
Binary files a/WordAddIn/.vs/WordAddIn/CopilotIndices/17.14.1577.30250/CodeChunks.db and b/WordAddIn/.vs/WordAddIn/CopilotIndices/17.14.1577.30250/CodeChunks.db differ
diff --git a/WordAddIn/.vs/WordAddIn/CopilotIndices/17.14.1577.30250/SemanticSymbols.db b/WordAddIn/.vs/WordAddIn/CopilotIndices/17.14.1577.30250/SemanticSymbols.db
index e5a4d31..ae61eab 100644
Binary files a/WordAddIn/.vs/WordAddIn/CopilotIndices/17.14.1577.30250/SemanticSymbols.db and b/WordAddIn/.vs/WordAddIn/CopilotIndices/17.14.1577.30250/SemanticSymbols.db differ
diff --git a/WordAddIn/.vs/WordAddIn/FileContentIndex/cc724fb2-aece-4705-bab6-f396d457e01f.vsidx b/WordAddIn/.vs/WordAddIn/FileContentIndex/cc724fb2-aece-4705-bab6-f396d457e01f.vsidx
deleted file mode 100644
index 9b46f80..0000000
Binary files a/WordAddIn/.vs/WordAddIn/FileContentIndex/cc724fb2-aece-4705-bab6-f396d457e01f.vsidx and /dev/null differ
diff --git a/WordAddIn/.vs/WordAddIn/v17/.suo b/WordAddIn/.vs/WordAddIn/v17/.suo
index 2722bcd..09748e3 100644
Binary files a/WordAddIn/.vs/WordAddIn/v17/.suo and b/WordAddIn/.vs/WordAddIn/v17/.suo differ
diff --git a/WordAddIn/.vs/WordAddIn/v17/DocumentLayout.backup.json b/WordAddIn/.vs/WordAddIn/v17/DocumentLayout.backup.json
index f2bc6b6..ac31668 100644
--- a/WordAddIn/.vs/WordAddIn/v17/DocumentLayout.backup.json
+++ b/WordAddIn/.vs/WordAddIn/v17/DocumentLayout.backup.json
@@ -3,8 +3,20 @@
"WorkspaceRootPath": "D:\\dsWork\\aiData\\WordAddIn\\",
"Documents": [
{
- "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|d:\\dswork\\aidata\\wordaddin\\wordaddin\\modeldefinitions.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\modeldefinitions.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|d:\\dswork\\aidata\\wordaddin\\wordaddin\\outlineresultform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form",
+ "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\outlineresultform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|D:\\dsWork\\aiData\\WordAddIn\\wordaddin\\loginform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form",
+ "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\loginform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|D:\\dsWork\\aiData\\WordAddIn\\wordaddin\\imageoptionsform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form",
+ "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\imageoptionsform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|D:\\dsWork\\aiData\\WordAddIn\\wordaddin\\createoutlineform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form",
+ "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\createoutlineform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form"
}
],
"DocumentGroupContainers": [
@@ -23,15 +35,47 @@
{
"$type": "Document",
"DocumentIndex": 0,
- "Title": "ModelDefinitions.cs",
- "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\ModelDefinitions.cs",
- "RelativeDocumentMoniker": "WordAddIn\\ModelDefinitions.cs",
- "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\ModelDefinitions.cs",
- "RelativeToolTip": "WordAddIn\\ModelDefinitions.cs",
- "ViewState": "AgIAAAkAAAAAAAAAAAAuwBIAAAAoAAAAAAAAAA==",
+ "Title": "OutlineResultForm.cs [\u8BBE\u8BA1]",
+ "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\OutlineResultForm.cs",
+ "RelativeDocumentMoniker": "WordAddIn\\OutlineResultForm.cs",
+ "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\OutlineResultForm.cs [\u8BBE\u8BA1]",
+ "RelativeToolTip": "WordAddIn\\OutlineResultForm.cs [\u8BBE\u8BA1]",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-01-28T13:21:19.787Z",
- "EditorCaption": ""
+ "WhenOpened": "2026-01-28T23:14:29.889Z",
+ "EditorCaption": " [\u8BBE\u8BA1]"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 1,
+ "Title": "LoginForm.cs [\u8BBE\u8BA1]",
+ "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\LoginForm.cs",
+ "RelativeDocumentMoniker": "WordAddIn\\LoginForm.cs",
+ "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\LoginForm.cs [\u8BBE\u8BA1]",
+ "RelativeToolTip": "WordAddIn\\LoginForm.cs [\u8BBE\u8BA1]",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-28T23:14:26.027Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 2,
+ "Title": "ImageOptionsForm.cs [\u8BBE\u8BA1]",
+ "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\ImageOptionsForm.cs",
+ "RelativeDocumentMoniker": "WordAddIn\\ImageOptionsForm.cs",
+ "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\ImageOptionsForm.cs [\u8BBE\u8BA1]",
+ "RelativeToolTip": "WordAddIn\\ImageOptionsForm.cs [\u8BBE\u8BA1]",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-28T23:14:18.293Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 3,
+ "Title": "CreateOutlineForm.cs [\u8BBE\u8BA1]",
+ "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\CreateOutlineForm.cs",
+ "RelativeDocumentMoniker": "WordAddIn\\CreateOutlineForm.cs",
+ "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\CreateOutlineForm.cs [\u8BBE\u8BA1]",
+ "RelativeToolTip": "WordAddIn\\CreateOutlineForm.cs [\u8BBE\u8BA1]",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-28T23:14:17.315Z"
}
]
}
diff --git a/WordAddIn/.vs/WordAddIn/v17/DocumentLayout.json b/WordAddIn/.vs/WordAddIn/v17/DocumentLayout.json
index f2bc6b6..ac31668 100644
--- a/WordAddIn/.vs/WordAddIn/v17/DocumentLayout.json
+++ b/WordAddIn/.vs/WordAddIn/v17/DocumentLayout.json
@@ -3,8 +3,20 @@
"WorkspaceRootPath": "D:\\dsWork\\aiData\\WordAddIn\\",
"Documents": [
{
- "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|d:\\dswork\\aidata\\wordaddin\\wordaddin\\modeldefinitions.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
- "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\modeldefinitions.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
+ "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|d:\\dswork\\aidata\\wordaddin\\wordaddin\\outlineresultform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form",
+ "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\outlineresultform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|D:\\dsWork\\aiData\\WordAddIn\\wordaddin\\loginform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form",
+ "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\loginform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|D:\\dsWork\\aiData\\WordAddIn\\wordaddin\\imageoptionsform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form",
+ "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\imageoptionsform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form"
+ },
+ {
+ "AbsoluteMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|D:\\dsWork\\aiData\\WordAddIn\\wordaddin\\createoutlineform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form",
+ "RelativeMoniker": "D:0:0:{EC0A80FA-FCBD-4239-945A-627B20CCCBAA}|WordAddIn\\WordAddIn.csproj|solutionrelative:wordaddin\\createoutlineform.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}|Form"
}
],
"DocumentGroupContainers": [
@@ -23,15 +35,47 @@
{
"$type": "Document",
"DocumentIndex": 0,
- "Title": "ModelDefinitions.cs",
- "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\ModelDefinitions.cs",
- "RelativeDocumentMoniker": "WordAddIn\\ModelDefinitions.cs",
- "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\ModelDefinitions.cs",
- "RelativeToolTip": "WordAddIn\\ModelDefinitions.cs",
- "ViewState": "AgIAAAkAAAAAAAAAAAAuwBIAAAAoAAAAAAAAAA==",
+ "Title": "OutlineResultForm.cs [\u8BBE\u8BA1]",
+ "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\OutlineResultForm.cs",
+ "RelativeDocumentMoniker": "WordAddIn\\OutlineResultForm.cs",
+ "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\OutlineResultForm.cs [\u8BBE\u8BA1]",
+ "RelativeToolTip": "WordAddIn\\OutlineResultForm.cs [\u8BBE\u8BA1]",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
- "WhenOpened": "2026-01-28T13:21:19.787Z",
- "EditorCaption": ""
+ "WhenOpened": "2026-01-28T23:14:29.889Z",
+ "EditorCaption": " [\u8BBE\u8BA1]"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 1,
+ "Title": "LoginForm.cs [\u8BBE\u8BA1]",
+ "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\LoginForm.cs",
+ "RelativeDocumentMoniker": "WordAddIn\\LoginForm.cs",
+ "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\LoginForm.cs [\u8BBE\u8BA1]",
+ "RelativeToolTip": "WordAddIn\\LoginForm.cs [\u8BBE\u8BA1]",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-28T23:14:26.027Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 2,
+ "Title": "ImageOptionsForm.cs [\u8BBE\u8BA1]",
+ "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\ImageOptionsForm.cs",
+ "RelativeDocumentMoniker": "WordAddIn\\ImageOptionsForm.cs",
+ "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\ImageOptionsForm.cs [\u8BBE\u8BA1]",
+ "RelativeToolTip": "WordAddIn\\ImageOptionsForm.cs [\u8BBE\u8BA1]",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-28T23:14:18.293Z"
+ },
+ {
+ "$type": "Document",
+ "DocumentIndex": 3,
+ "Title": "CreateOutlineForm.cs [\u8BBE\u8BA1]",
+ "DocumentMoniker": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\CreateOutlineForm.cs",
+ "RelativeDocumentMoniker": "WordAddIn\\CreateOutlineForm.cs",
+ "ToolTip": "D:\\dsWork\\aiData\\WordAddIn\\WordAddIn\\CreateOutlineForm.cs [\u8BBE\u8BA1]",
+ "RelativeToolTip": "WordAddIn\\CreateOutlineForm.cs [\u8BBE\u8BA1]",
+ "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
+ "WhenOpened": "2026-01-28T23:14:17.315Z"
}
]
}
diff --git a/WordAddIn/WordAddIn/AiRibbon.cs b/WordAddIn/WordAddIn/AiRibbon.cs
index 80badce..dc956bb 100644
--- a/WordAddIn/WordAddIn/AiRibbon.cs
+++ b/WordAddIn/WordAddIn/AiRibbon.cs
@@ -32,14 +32,69 @@ namespace WordAddIn
private AiService _aiService = new AiService();
// 登录状态标识 (静态变量,确保在插件生命周期内保持状态)
- private static bool _isLoggedIn = false;
+ private static bool _isLoggedIn = false;
+ // 登录凭证存储路径
+ private string _tokenFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "WordAddIn", "login.cookie");
+
+ ///
+ /// 保存登录状态到本地文件
+ ///
+ private void SaveLoginState()
+ {
+ try
+ {
+ string dir = Path.GetDirectoryName(_tokenFilePath);
+ if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
+ File.WriteAllText(_tokenFilePath, "logged_in|" + DateTime.Now.Ticks);
+ }
+ catch (Exception ex)
+ {
+ try { File.AppendAllText(@"C:\Users\Public\WordAddInLog.txt", $"{DateTime.Now} SaveLoginState Error: {ex.Message}\n"); } catch { }
+ }
+ }
+
+ ///
+ /// 加载本地登录状态
+ ///
+ private void LoadLoginState()
+ {
+ try
+ {
+ if (File.Exists(_tokenFilePath))
+ {
+ // 简单验证:文件存在即视为已登录。实际可校验内容有效期。
+ _isLoggedIn = true;
+ }
+ }
+ catch (Exception ex)
+ {
+ try { File.AppendAllText(@"C:\Users\Public\WordAddInLog.txt", $"{DateTime.Now} LoadLoginState Error: {ex.Message}\n"); } catch { }
+ }
+ }
+
// 存储文档的全文分析上下文 (通过"通读全文"功能生成),用于辅助 AI 理解文档背景
private string _documentContext = null;
// 存储外部参考文档内容 (通过"补充背景"功能导入),用于辅助 AI 进行写作
private string _referenceContext = null;
+ // 样式刷状态常量
+ private const int BRUSH_NONE = -1;
+ private const int BRUSH_MAIN_TITLE = 0;
+ private const int BRUSH_HEADING1 = 1;
+ private const int BRUSH_HEADING2 = 2;
+ private const int BRUSH_HEADING3 = 3;
+ private const int BRUSH_BODY = 10;
+
+ // 当前激活的样式刷等级
+ private int _currentBrushLevel = BRUSH_NONE;
+
+ // 样式刷配置缓存与状态控制
+ private OutlineStyleConfig _cachedStyleConfig = null;
+ private long _lastBrushClickTicks = 0;
+ private bool _isBrushSticky = false;
+
///
/// 默认构造函数
///
@@ -98,6 +153,596 @@ namespace WordAddIn
}
catch {}
this.ribbon = ribbonUI;
+
+ // 加载登录状态
+ LoadLoginState();
+
+ try
+ {
+ if (AddInContext.CurrentApplication != null)
+ {
+ AddInContext.CurrentApplication.WindowSelectionChange += CurrentApplication_WindowSelectionChange;
+ }
+ }
+ catch { }
+ }
+
+ ///
+ /// 控制 Ribbon 按钮的可用状态 (Enabled)。
+ /// 未登录时返回 false (灰色不可用),登录后返回 true。
+ ///
+ /// 控件
+ /// 是否可用
+ public bool GetControlEnabled(Office.IRibbonControl control)
+ {
+ return _isLoggedIn;
+ }
+
+ ///
+ /// 【登录】按钮点击事件处理。
+ ///
+ /// 控件
+ public void OnLoginClick(Office.IRibbonControl control)
+ {
+ using (LoginForm login = new LoginForm())
+ {
+ if (login.ShowDialog() == DialogResult.OK)
+ {
+ _isLoggedIn = true;
+ SaveLoginState();
+
+ // 刷新 Ribbon 状态,使按钮变亮
+ if (ribbon != null)
+ {
+ ribbon.Invalidate();
+ }
+ }
+ }
+ }
+
+ public void OnStyleBrushToggle(Office.IRibbonControl control, bool pressed)
+ {
+ int targetLevel = BRUSH_NONE;
+ switch (control.Id)
+ {
+ case "tbtnStyleMainTitle": targetLevel = BRUSH_MAIN_TITLE; break;
+ case "tbtnStyleLevel1": targetLevel = BRUSH_HEADING1; break;
+ case "tbtnStyleLevel2": targetLevel = BRUSH_HEADING2; break;
+ case "tbtnStyleLevel3": targetLevel = BRUSH_HEADING3; break;
+ case "tbtnStyleBody": targetLevel = BRUSH_BODY; break;
+ }
+
+ if (pressed)
+ {
+ // 激活样式刷
+ _currentBrushLevel = targetLevel;
+ _lastBrushClickTicks = DateTime.Now.Ticks;
+ _isBrushSticky = false; // 默认为单次使用模式
+
+ // 缓存配置,避免每次选区变化都反序列化,提高性能
+ try
+ {
+ string styleJson = Settings.Default.OutlineStyles;
+ _cachedStyleConfig = string.IsNullOrEmpty(styleJson) ? new OutlineStyleConfig() : JsonConvert.DeserializeObject(styleJson);
+ }
+ catch { _cachedStyleConfig = new OutlineStyleConfig(); }
+
+ // 反向模式:如果已经选中了文字,直接应用样式并退出刷子模式
+ bool appliedImmediate = false;
+ try
+ {
+ if (AddInContext.CurrentApplication != null)
+ {
+ var sel = AddInContext.CurrentApplication.Selection;
+ // wdSelectionNormal = 2 (普通文本选区)
+ if (sel != null && sel.Type == Word.WdSelectionType.wdSelectionNormal && sel.Range.End > sel.Range.Start)
+ {
+ foreach (Word.Paragraph p in sel.Range.Paragraphs)
+ {
+ ApplyStyleToParagraph(p, targetLevel, _cachedStyleConfig);
+ }
+ appliedImmediate = true;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ try { File.AppendAllText(@"C:\Users\Public\WordAddInLog.txt", $"{DateTime.Now} ReverseApply Error: {ex.Message}\n"); } catch { }
+ }
+
+ if (appliedImmediate)
+ {
+ // 如果已立即应用,则重置刷子状态
+ _currentBrushLevel = BRUSH_NONE;
+ _cachedStyleConfig = null;
+
+ // 刷新控件状态,使按钮弹起
+ if (ribbon != null)
+ {
+ ribbon.InvalidateControl(control.Id);
+ // 确保其他按钮状态也正确
+ ribbon.InvalidateControl("tbtnStyleMainTitle");
+ ribbon.InvalidateControl("tbtnStyleLevel1");
+ ribbon.InvalidateControl("tbtnStyleLevel2");
+ ribbon.InvalidateControl("tbtnStyleLevel3");
+ ribbon.InvalidateControl("tbtnStyleBody");
+ }
+ return;
+ }
+ }
+ else
+ {
+ // 尝试关闭样式刷
+ long elapsedTicks = DateTime.Now.Ticks - _lastBrushClickTicks;
+ TimeSpan elapsed = new TimeSpan(elapsedTicks);
+
+ // 如果点击间隔很短 (例如 500ms 内),视为双击,进入"连续使用"模式
+ // 此时保持激活状态,并设为粘滞模式
+ if (elapsed.TotalMilliseconds < 500 && _currentBrushLevel == targetLevel)
+ {
+ _isBrushSticky = true;
+ // 强制刷新控件状态,使其保持按下
+ ribbon.InvalidateControl(control.Id);
+ return;
+ }
+
+ // 正常关闭
+ _currentBrushLevel = BRUSH_NONE;
+ _cachedStyleConfig = null;
+ _isBrushSticky = false;
+ }
+
+ // 刷新所有相关按钮状态
+ if (ribbon != null)
+ {
+ ribbon.InvalidateControl("tbtnStyleMainTitle");
+ ribbon.InvalidateControl("tbtnStyleLevel1");
+ ribbon.InvalidateControl("tbtnStyleLevel2");
+ ribbon.InvalidateControl("tbtnStyleLevel3");
+ ribbon.InvalidateControl("tbtnStyleBody");
+ }
+ }
+
+ public bool GetStyleBrushPressed(Office.IRibbonControl control)
+ {
+ switch (control.Id)
+ {
+ case "tbtnStyleMainTitle": return _currentBrushLevel == BRUSH_MAIN_TITLE;
+ case "tbtnStyleLevel1": return _currentBrushLevel == BRUSH_HEADING1;
+ case "tbtnStyleLevel2": return _currentBrushLevel == BRUSH_HEADING2;
+ case "tbtnStyleLevel3": return _currentBrushLevel == BRUSH_HEADING3;
+ case "tbtnStyleBody": return _currentBrushLevel == BRUSH_BODY;
+ default: return false;
+ }
+ }
+
+ private void CurrentApplication_WindowSelectionChange(Word.Selection Sel)
+ {
+ if (_currentBrushLevel == BRUSH_NONE) return;
+ if (_cachedStyleConfig == null) return;
+
+ try
+ {
+ foreach (Word.Paragraph p in Sel.Paragraphs)
+ {
+ ApplyStyleToParagraph(p, _currentBrushLevel, _cachedStyleConfig);
+ }
+
+ // 如果不是粘滞模式 (单次使用),应用一次后立即关闭
+ if (!_isBrushSticky)
+ {
+ _currentBrushLevel = BRUSH_NONE;
+ _cachedStyleConfig = null;
+
+ if (ribbon != null)
+ {
+ ribbon.InvalidateControl("tbtnStyleMainTitle");
+ ribbon.InvalidateControl("tbtnStyleLevel1");
+ ribbon.InvalidateControl("tbtnStyleLevel2");
+ ribbon.InvalidateControl("tbtnStyleLevel3");
+ ribbon.InvalidateControl("tbtnStyleBody");
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ try { File.AppendAllText(@"C:\Users\Public\WordAddInLog.txt", $"{DateTime.Now} Brush Error: {ex.Message}\n"); } catch { }
+ }
+ }
+
+ private void ApplyStyleToParagraph(Word.Paragraph p, int level, OutlineStyleConfig styleConfig)
+ {
+ TextStyle ts = null;
+ try
+ {
+ switch (level)
+ {
+ case 0: // 主标题
+ ts = styleConfig.MainTitle;
+ p.set_Style(Word.WdBuiltinStyle.wdStyleTitle);
+ p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevelBodyText;
+ p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevelBodyText;
+ break;
+ case 1: // 一级标题
+ ts = styleConfig.Heading1;
+ p.set_Style(Word.WdBuiltinStyle.wdStyleHeading1);
+ p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel1;
+ p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel1;
+ break;
+ case 2: // 二级标题
+ ts = styleConfig.Heading2;
+ p.set_Style(Word.WdBuiltinStyle.wdStyleHeading2);
+ p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel2;
+ p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel2;
+ break;
+ case 3: // 三级标题
+ ts = styleConfig.Heading3;
+ p.set_Style(Word.WdBuiltinStyle.wdStyleHeading3);
+ p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel3;
+ p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel3;
+ break;
+ case 10: // 正文
+ p.set_Style(Word.WdBuiltinStyle.wdStyleNormal);
+ p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevelBodyText;
+ p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevelBodyText;
+ p.Format.CharacterUnitFirstLineIndent = 2; // 首行缩进2字符
+ return;
+ default:
+ if (level >= 1 && level <= 5) {
+ ts = styleConfig.Heading3;
+ p.set_Style(Word.WdBuiltinStyle.wdStyleHeading3);
+ }
+ break;
+ }
+ }
+ catch
+ {
+ try
+ {
+ if (level == 0) p.set_Style("标题");
+ else if (level == 10) p.set_Style("正文");
+ else p.set_Style("标题 " + level);
+ }
+ catch { }
+ }
+
+ if (ts != null)
+ {
+ try { p.Range.Font.Name = ts.FontName; } catch { }
+ try { p.Range.Font.NameFarEast = ts.FontName; } catch { }
+ try { p.Range.Font.Size = ts.FontSize; } catch { }
+ try { p.Range.Font.Bold = ts.IsBold ? 1 : 0; } catch { }
+ try { p.Range.Font.Color = (Word.WdColor)ts.Color; } catch { }
+
+ if (level == 0)
+ {
+ p.Format.Alignment = (Word.WdParagraphAlignment)ts.Alignment;
+ }
+
+ p.Format.CharacterUnitFirstLineIndent = 0;
+ p.Format.FirstLineIndent = 0;
+ }
+
+ // 智能序号填充 (Smart Numbering)
+ // 仅对 Level 1-3 生效,尝试探测上一级或同级序号并自动填充
+ if (level >= 1 && level <= 3)
+ {
+ SmartNumbering.Apply(p, level);
+ }
+ }
+
+ ///
+ /// 智能序号处理辅助类
+ ///
+ private static class SmartNumbering
+ {
+ // 常见序号正则
+ // 1. 中文序号: 一、 (支持 一、到 九十九、)
+ private static readonly Regex RegexChinese = new Regex(@"^([一二三四五六七八九十]+)、");
+ // 2. 章节序号: 第一章 (支持 第一章 到 第九十九章)
+ private static readonly Regex RegexChapter = new Regex(@"^第([0-9一二三四五六七八九十]+)章");
+ // 3. 数字点序号: 1. (支持 1. 到 99.)
+ private static readonly Regex RegexNumericDot = new Regex(@"^(\d+)\.");
+ // 4. 层级数字序号: 1.1 或 1.1.1
+ private static readonly Regex RegexHierarchical = new Regex(@"^(\d+(\.\d+)+)");
+ // 5. 括号数字: (1) 或 (一) - 暂不作为主要探测目标,避免误判
+
+ public static void Apply(Word.Paragraph p, int level)
+ {
+ try
+ {
+ // 1. 寻找前一个同级标题 (Sibling)
+ var siblingInfo = FindPreviousSibling(p, level);
+
+ if (siblingInfo.Found)
+ {
+ // 发现同级,延续序号
+ string newPrefix = IncrementNumbering(siblingInfo.Text, siblingInfo.Type);
+ if (!string.IsNullOrEmpty(newPrefix))
+ {
+ ReplacePrefix(p, newPrefix);
+ }
+ }
+ else
+ {
+ // 未发现同级,寻找父级 (Parent) 以决定起始序号
+ // 例如: Level 2 未找到同级,但找到 Level 1 "第一章",则可能开始 "1.1" 或 "一、"
+ // 策略:如果找不到同级,尝试根据父级重置为 "1" 或 "1.1"
+ var parentInfo = FindParent(p, level);
+ if (parentInfo.Found)
+ {
+ string startPrefix = GenerateStartNumbering(parentInfo.Text, level);
+ if (!string.IsNullOrEmpty(startPrefix))
+ {
+ ReplacePrefix(p, startPrefix);
+ }
+ }
+ else
+ {
+ // 既无同级也无父级 (可能是文档开头),尝试默认初始化
+ // 如果是 Level 1 且无前文,默认 "一、"
+ if (level == 1)
+ {
+ ReplacePrefix(p, "一、");
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ try { File.AppendAllText(@"C:\Users\Public\WordAddInLog.txt", $"{DateTime.Now} SmartNumbering Error: {ex.Message}\n"); } catch { }
+ }
+ }
+
+ private struct NumberingInfo
+ {
+ public bool Found;
+ public string Text;
+ public NumberingType Type;
+ }
+
+ private enum NumberingType
+ {
+ None,
+ Chinese, // 一、
+ Chapter, // 第一章
+ NumericDot, // 1.
+ Hierarchical // 1.1
+ }
+
+ private static NumberingInfo FindPreviousSibling(Word.Paragraph p, int level)
+ {
+ // 向前搜索最多 100 段,避免性能问题
+ int maxLookBack = 100;
+ Word.Paragraph curr = p;
+
+ for (int i = 0; i < maxLookBack; i++)
+ {
+ curr = curr.Previous();
+ if (curr == null) break;
+
+ int currLevel = (int)curr.Format.OutlineLevel; // wdOutlineLevel1 = 1
+
+ if (currLevel == level)
+ {
+ // 找到同级
+ string text = curr.Range.Text.Trim();
+ var type = DetectType(text);
+ if (type != NumberingType.None)
+ {
+ return new NumberingInfo { Found = true, Text = text, Type = type };
+ }
+ }
+ else if (currLevel < level && currLevel >= 1) // wdOutlineLevel1=1 < wdOutlineLevel2=2
+ {
+ // 遇到父级 (OutlineLevel 值越小级别越高)
+ // 停止搜索,说明是该章节的第一项
+ return new NumberingInfo { Found = false };
+ }
+ }
+ return new NumberingInfo { Found = false };
+ }
+
+ private static NumberingInfo FindParent(Word.Paragraph p, int level)
+ {
+ int maxLookBack = 200;
+ Word.Paragraph curr = p;
+
+ for (int i = 0; i < maxLookBack; i++)
+ {
+ curr = curr.Previous();
+ if (curr == null) break;
+
+ int currLevel = (int)curr.Format.OutlineLevel;
+ if (currLevel < level && currLevel >= 1) // 找到父级
+ {
+ string text = curr.Range.Text.Trim();
+ return new NumberingInfo { Found = true, Text = text, Type = DetectType(text) };
+ }
+ }
+ return new NumberingInfo { Found = false };
+ }
+
+ private static NumberingType DetectType(string text)
+ {
+ if (RegexHierarchical.IsMatch(text)) return NumberingType.Hierarchical;
+ if (RegexChapter.IsMatch(text)) return NumberingType.Chapter;
+ if (RegexChinese.IsMatch(text)) return NumberingType.Chinese;
+ if (RegexNumericDot.IsMatch(text)) return NumberingType.NumericDot;
+ return NumberingType.None;
+ }
+
+ private static string IncrementNumbering(string text, NumberingType type)
+ {
+ try
+ {
+ if (type == NumberingType.Chinese)
+ {
+ var match = RegexChinese.Match(text);
+ string numStr = match.Groups[1].Value;
+ int num = ChineseToInt(numStr);
+ return IntToChinese(num + 1) + "、";
+ }
+ else if (type == NumberingType.Chapter)
+ {
+ var match = RegexChapter.Match(text);
+ string numStr = match.Groups[1].Value;
+ // 可能是中文也可能是数字
+ int num = 0;
+ if (int.TryParse(numStr, out int n)) num = n;
+ else num = ChineseToInt(numStr);
+
+ // 保持原格式 (中文或数字)
+ string newNumStr = int.TryParse(numStr, out _) ? (num + 1).ToString() : IntToChinese(num + 1);
+ return "第" + newNumStr + "章 "; // 增加一个空格
+ }
+ else if (type == NumberingType.NumericDot)
+ {
+ var match = RegexNumericDot.Match(text);
+ int num = int.Parse(match.Groups[1].Value);
+ return (num + 1) + ". ";
+ }
+ else if (type == NumberingType.Hierarchical)
+ {
+ var match = RegexHierarchical.Match(text);
+ string fullNum = match.Groups[1].Value; // "1.1"
+ string[] parts = fullNum.Split('.');
+ if (parts.Length > 0)
+ {
+ int last = int.Parse(parts[parts.Length - 1]);
+ parts[parts.Length - 1] = (last + 1).ToString();
+ return string.Join(".", parts) + " ";
+ }
+ }
+ }
+ catch { }
+ return null;
+ }
+
+ private static string GenerateStartNumbering(string parentText, int currentLevel)
+ {
+ // 根据父级生成子级其实序号
+ // 父: 第1章 -> 子: 1.1
+ // 父: 1. -> 子: 1.1
+ // 父: 1.1 -> 子: 1.1.1
+ // 父: 一、 -> 子: 1. (或其他)
+
+ try
+ {
+ var parentType = DetectType(parentText);
+ string parentNum = "1";
+
+ if (parentType == NumberingType.Chapter)
+ {
+ var m = RegexChapter.Match(parentText);
+ string s = m.Groups[1].Value;
+ if (int.TryParse(s, out int n)) parentNum = n.ToString();
+ else parentNum = ChineseToInt(s).ToString();
+ }
+ else if (parentType == NumberingType.NumericDot)
+ {
+ var m = RegexNumericDot.Match(parentText);
+ parentNum = m.Groups[1].Value;
+ }
+ else if (parentType == NumberingType.Hierarchical)
+ {
+ var m = RegexHierarchical.Match(parentText);
+ parentNum = m.Groups[1].Value;
+ }
+ // Chinese "一、" usually maps to child "1" not "1.1" depending on style
+
+ // 构造
+ // 如果父级是 "1",当前是 Level 2,则 "1.1"
+ // 如果父级是 "1.1",当前是 Level 3,则 "1.1.1"
+ return parentNum + ".1 ";
+ }
+ catch { }
+
+ return "1. "; // Fallback
+ }
+
+ private static void ReplacePrefix(Word.Paragraph p, string newPrefix)
+ {
+ string text = p.Range.Text;
+ // 移除旧的前缀
+ string cleanText = text;
+ if (RegexHierarchical.IsMatch(text)) cleanText = RegexHierarchical.Replace(text, "", 1);
+ else if (RegexChapter.IsMatch(text)) cleanText = RegexChapter.Replace(text, "", 1);
+ else if (RegexChinese.IsMatch(text)) cleanText = RegexChinese.Replace(text, "", 1);
+ else if (RegexNumericDot.IsMatch(text)) cleanText = RegexNumericDot.Replace(text, "", 1);
+
+ cleanText = cleanText.TrimStart(); // 去除可能的空格
+
+ // 写入新文本 (注意保留段落标记)
+ // 直接设置 Range.Text 会覆盖格式,需小心
+ // 策略:Range.InsertBefore? 不,这会保留旧文本
+ // 策略:定位到 Start,删除旧前缀长度,插入新前缀
+
+ // 简单实现:覆盖 Text,重置 Style (因为 Text 赋值会清除部分格式,但我们是在 ApplyStyle 中,Style 刚被设置)
+ // 更好:只操作 Range 的 Start 到 Match End
+
+ // 正则匹配旧前缀的长度
+ int oldLength = 0;
+ if (RegexHierarchical.IsMatch(text)) oldLength = RegexHierarchical.Match(text).Length;
+ else if (RegexChapter.IsMatch(text)) oldLength = RegexChapter.Match(text).Length;
+ else if (RegexChinese.IsMatch(text)) oldLength = RegexChinese.Match(text).Length;
+ else if (RegexNumericDot.IsMatch(text)) oldLength = RegexNumericDot.Match(text).Length;
+
+ // 删除旧前缀
+ if (oldLength > 0)
+ {
+ var range = p.Range;
+ range.End = range.Start + oldLength;
+ range.Delete();
+ }
+
+ // 插入新前缀
+ p.Range.InsertBefore(newPrefix);
+ }
+
+ // 简易中文数字转换 (支持 1-99)
+ private static readonly string[] CN_Nums = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九" };
+ private static readonly string[] CN_Units = { "", "十", "百" };
+
+ private static int ChineseToInt(string s)
+ {
+ if (string.IsNullOrEmpty(s)) return 0;
+ // 简单映射
+ int result = 0;
+ int temp = 0; // 当前位数值
+
+ // 仅处理 一到九十九
+ // 十 -> 10, 十一 -> 11, 二十 -> 20
+ if (s.StartsWith("十")) result += 10;
+
+ foreach (char c in s)
+ {
+ string cs = c.ToString();
+ int idx = Array.IndexOf(CN_Nums, cs);
+ if (idx > 0)
+ {
+ temp = idx;
+ if (s.EndsWith(cs)) result += temp; // 个位
+ }
+ else if (cs == "十")
+ {
+ if (temp == 0) temp = 1; // "十" 前没数视为1
+ result += temp * 10;
+ temp = 0;
+ }
+ }
+ if (s == "十") return 10;
+ return result > 0 ? result : 0;
+ }
+
+ private static string IntToChinese(int n)
+ {
+ if (n <= 0) return n.ToString();
+ if (n <= 10) return CN_Nums[n];
+ if (n < 20) return "十" + CN_Nums[n % 10];
+ if (n < 100) return CN_Nums[n / 10] + "十" + (n % 10 == 0 ? "" : CN_Nums[n % 10]);
+ return n.ToString(); // 超过99暂返数字
+ }
}
///
@@ -722,6 +1367,25 @@ namespace WordAddIn
headings = new List();
}
+ // 加载大纲样式配置
+ string styleJson = Settings.Default.OutlineStyles;
+ OutlineStyleConfig styleConfig = null;
+ try
+ {
+ styleConfig = string.IsNullOrEmpty(styleJson)
+ ? new OutlineStyleConfig()
+ : JsonConvert.DeserializeObject(styleJson);
+ }
+ catch
+ {
+ styleConfig = new OutlineStyleConfig();
+ }
+ if (styleConfig == null) styleConfig = new OutlineStyleConfig();
+ var defaultStyleConfig = new OutlineStyleConfig();
+ if (styleConfig.Heading1 == null) styleConfig.Heading1 = defaultStyleConfig.Heading1;
+ if (styleConfig.Heading2 == null) styleConfig.Heading2 = defaultStyleConfig.Heading2;
+ if (styleConfig.Heading3 == null) styleConfig.Heading3 = defaultStyleConfig.Heading3;
+
// 4. 应用样式 (在 UI 线程操作 Word 对象)
// 遍历所有段落,性能可能受文档长度影响,但对于一般文档可接受
int changeCount = 0;
@@ -737,31 +1401,14 @@ namespace WordAddIn
if (match != null)
{
- // 是标题:设置对应的 Word 内置标题样式
- Word.WdBuiltinStyle styleEnum = Word.WdBuiltinStyle.wdStyleNormal;
- switch (match.level)
- {
- case 1: styleEnum = Word.WdBuiltinStyle.wdStyleHeading1; break;
- case 2: styleEnum = Word.WdBuiltinStyle.wdStyleHeading2; break;
- case 3: styleEnum = Word.WdBuiltinStyle.wdStyleHeading3; break;
- case 4: styleEnum = Word.WdBuiltinStyle.wdStyleHeading4; break;
- case 5: styleEnum = Word.WdBuiltinStyle.wdStyleHeading5; break;
- default: styleEnum = Word.WdBuiltinStyle.wdStyleHeading1; break;
- }
-
- p.set_Style(styleEnum);
-
- // 标题通常不需要首行缩进,强制清除
- p.Format.CharacterUnitFirstLineIndent = 0;
- p.Format.FirstLineIndent = 0;
-
+ // 使用统一的样式应用方法
+ ApplyStyleToParagraph(p, match.level, styleConfig);
changeCount++;
}
else
{
- // 6. 非标题(正文):统一设置首行缩进 2 字符
- // 让文档看起来更规范
- p.Format.CharacterUnitFirstLineIndent = 2;
+ // 6. 非标题(正文):应用正文样式(包含首行缩进)
+ ApplyStyleToParagraph(p, 10, styleConfig);
indentCount++;
}
}
@@ -769,7 +1416,7 @@ namespace WordAddIn
string msg = $"格式美化完成!\n- 已调整 {changeCount} 处标题格式。";
if (indentCount > 0)
{
- msg += $"\n- 已对 {indentCount} 个段落应用首行缩进。";
+ msg += $"\n- 已对 {indentCount} 个段落应用正文样式(首行缩进)。";
}
MessageBox.Show(msg);
}
@@ -812,41 +1459,29 @@ namespace WordAddIn
prompt = prompt.Trim();
}
- // 2. 如果选区为空(或只包含空白字符),尝试获取剪贴板文本
- if (string.IsNullOrWhiteSpace(prompt))
- {
- try
- {
- if (Clipboard.ContainsText())
- {
- prompt = Clipboard.GetText().Trim();
- }
- }
- catch (Exception ex)
- {
- // 忽略剪贴板访问错误(如被其他进程占用)
- Console.WriteLine("Clipboard access failed: " + ex.Message);
- }
- }
-
- // 3. 如果依然为空,提示用户
- if (string.IsNullOrWhiteSpace(prompt))
- {
- MessageBox.Show("未能获取生图描述。\n请选择文档中的文字,或确保剪贴板中有文本内容。");
- return;
- }
-
// 获取全文背景和参考资料上下文,合并到 Prompt 中供用户预览和编辑
string context = GetCombinedContext();
if (!string.IsNullOrWhiteSpace(context))
{
+ // 注意:这里我们只把 Selection 作为 SourceText 传给 Form
+ // Context 可以作为补充,但目前的 Form 逻辑主要是处理 SourceText
+ // 如果需要 Context,可能需要 Form 支持额外参数,或者直接 append 到 prompt
+ // 为了保持简单,我们暂时只传递选区文本,Context 在这里 append 到 prompt 会导致
+ // SourceText 包含 Context,这可能不是用户想要的(如果他们只选了一个词)
+ // 但之前的逻辑是 append,所以我们保持一致,或者让 Form 决定
+
+ // 之前的逻辑: prompt += context
+ // 现在的逻辑: prompt 传给 Form.SourceText
+ // 如果 prompt 包含 context,那么 Form 的 Input Box 也会包含 context
+ // 这对于“选区”来说可能有点多,但对于“生成”来说是必要的
+ // 让我们暂时保持原样,把 context 加进去,用户可以在 Input Box 里删掉
prompt += $"\n\n{context}";
}
// 弹出选项窗体
using (var form = new ImageOptionsForm())
{
- // 传入源文本
+ // 传入源文本 (可能是选区,也可能是空)
form.SourceText = prompt;
if (form.ShowDialog() != DialogResult.OK)
@@ -893,12 +1528,15 @@ namespace WordAddIn
///
/// 【关于】按钮点击事件处理。
- /// 显示插件版本和作者信息。
+ /// 显示插件版本和作者信息,以及功能使用说明。
///
/// 触发事件的 Ribbon 控件
public void OnAboutClick(Office.IRibbonControl control)
{
- MessageBox.Show("Version 0.2\n作者:黄海", "关于 AI 助手");
+ using (var form = new AboutForm())
+ {
+ form.ShowDialog();
+ }
}
///
@@ -986,71 +1624,14 @@ namespace WordAddIn
p.Range.Text = item.Title.Trim() + "\r";
// 7. 根据层级应用对应的样式 (字体、大小、加粗、对齐)
- TextStyle ts = null;
try
{
File.AppendAllText(@"C:\Users\Public\WordAddInLog.txt", $"{DateTime.Now} Processing Item: {item.Title}, Level: {item.Level}\n");
-
- switch (item.Level)
- {
- case 0: // 主标题
- ts = styleConfig.MainTitle;
- p.set_Style(Word.WdBuiltinStyle.wdStyleTitle);
- p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevelBodyText;
- p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevelBodyText;
- break;
- case 1: // 一级标题
- ts = styleConfig.Heading1;
- p.set_Style(Word.WdBuiltinStyle.wdStyleHeading1);
- p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel1;
- p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel1;
- break;
- case 2: // 二级标题
- ts = styleConfig.Heading2;
- p.set_Style(Word.WdBuiltinStyle.wdStyleHeading2);
- p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel2;
- p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel2;
- break;
- case 3: // 三级标题
- ts = styleConfig.Heading3;
- p.set_Style(Word.WdBuiltinStyle.wdStyleHeading3);
- p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel3;
- p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel3;
- break;
- default:
- ts = styleConfig.Heading3;
- // 默认也应用三级标题样式,确保出现在大纲中
- p.set_Style(Word.WdBuiltinStyle.wdStyleHeading3);
- p.Format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel3;
- p.Range.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevel3;
- break;
- }
+ ApplyStyleToParagraph(p, item.Level, styleConfig);
}
catch (Exception ex)
{
File.AppendAllText(@"C:\Users\Public\WordAddInLog.txt", $"{DateTime.Now} Error setting style: {ex.Message}\n");
- // Fallback: try setting style by name if object fails
- try
- {
- if (item.Level == 0) p.set_Style("标题");
- else p.set_Style("标题 " + item.Level);
- }
- catch { }
- }
-
- // 应用自定义样式属性
- if (ts != null)
- {
- p.Range.Font.Name = ts.FontName;
- try { p.Range.Font.NameFarEast = ts.FontName; } catch { }
- p.Range.Font.Size = ts.FontSize;
- p.Range.Font.Bold = ts.IsBold ? 1 : 0;
- p.Range.Font.Color = Word.WdColor.wdColorBlack; // 强制设为黑色,避免出现默认蓝色的情况
-
- if (item.Level == 0) // 仅主标题应用自定义对齐方式
- {
- p.Format.Alignment = (Word.WdParagraphAlignment)ts.Alignment;
- }
}
// 更新插入位置到当前段落之后,准备插入下一行
@@ -1128,7 +1709,26 @@ namespace WordAddIn
return false;
}
- private static void ApplyHeadingStylesToInsertedRange(Word.Document doc, int start, int end, OutlineStyleConfig styleConfig)
+ private static int GuessHeadingLevel(string text)
+ {
+ if (string.IsNullOrWhiteSpace(text)) return 10;
+ string t = text.Trim();
+
+ // Level 3: 1.1.1
+ if (Regex.IsMatch(t, @"^\d+\.\d+\.\d+")) return 3;
+
+ // Level 2: 1.1
+ if (Regex.IsMatch(t, @"^\d+\.\d+")) return 2;
+
+ // Level 1: 1. or 1、 or 第x章 or 一、
+ if (Regex.IsMatch(t, @"^第[一二三四五六七八九十0-9]+章")) return 1;
+ if (Regex.IsMatch(t, @"^[一二三四五六七八九十]+、")) return 1;
+ if (Regex.IsMatch(t, @"^\d+(\.|、)")) return 1;
+
+ return 10; // Body
+ }
+
+ private void ApplyHeadingStylesToInsertedRange(Word.Document doc, int start, int end, OutlineStyleConfig styleConfig)
{
if (doc == null) return;
if (end <= start) return;
@@ -1155,74 +1755,7 @@ namespace WordAddIn
level = GuessHeadingLevel(text);
}
- ApplyParagraphStyle(p, level, styleConfig);
- }
- }
-
- private static int GuessHeadingLevel(string text)
- {
- var t = (text ?? "").Trim();
- if (string.IsNullOrWhiteSpace(t)) return 1;
-
- if (Regex.IsMatch(t, @"^第[一二三四五六七八九十0-9]+章")) return 1;
- if (Regex.IsMatch(t, @"^(附录|结语|结论|参考文献|致谢)\b")) return 1;
- if (Regex.IsMatch(t, @"^\d+\.\d+\.\d+")) return 3;
- if (Regex.IsMatch(t, @"^\d+\.\d+")) return 2;
- if (Regex.IsMatch(t, @"^\d+\s")) return 1;
- if (Regex.IsMatch(t, @"^[一二三四五六七八九十]+、")) return 2;
- return 1;
- }
-
- private static void ApplyParagraphStyle(Word.Paragraph p, int level, OutlineStyleConfig styleConfig)
- {
- if (p == null) return;
- if (styleConfig == null) styleConfig = new OutlineStyleConfig();
-
- if (level < 0) level = 0;
- if (level > 3) level = 3;
-
- TextStyle ts;
- Word.WdOutlineLevel outlineLevel;
-
- switch (level)
- {
- case 0:
- ts = styleConfig.MainTitle;
- p.set_Style(Word.WdBuiltinStyle.wdStyleTitle);
- outlineLevel = Word.WdOutlineLevel.wdOutlineLevel1;
- break;
- case 1:
- ts = styleConfig.Heading1;
- p.set_Style(Word.WdBuiltinStyle.wdStyleHeading1);
- outlineLevel = Word.WdOutlineLevel.wdOutlineLevel1;
- break;
- case 2:
- ts = styleConfig.Heading2;
- p.set_Style(Word.WdBuiltinStyle.wdStyleHeading2);
- outlineLevel = Word.WdOutlineLevel.wdOutlineLevel2;
- break;
- default:
- ts = styleConfig.Heading3;
- p.set_Style(Word.WdBuiltinStyle.wdStyleHeading3);
- outlineLevel = Word.WdOutlineLevel.wdOutlineLevel3;
- break;
- }
-
- try { p.Format.OutlineLevel = outlineLevel; } catch { }
- try { p.Range.ParagraphFormat.OutlineLevel = outlineLevel; } catch { }
-
- if (ts != null)
- {
- try { p.Range.Font.Name = ts.FontName; } catch { }
- try { p.Range.Font.NameFarEast = ts.FontName; } catch { }
- try { p.Range.Font.Size = ts.FontSize; } catch { }
- try { p.Range.Font.Bold = ts.IsBold ? 1 : 0; } catch { }
- try { p.Range.Font.Color = Word.WdColor.wdColorBlack; } catch { }
-
- if (level == 0)
- {
- try { p.Format.Alignment = (Word.WdParagraphAlignment)ts.Alignment; } catch { }
- }
+ ApplyStyleToParagraph(p, level, styleConfig);
}
}
diff --git a/WordAddIn/WordAddIn/AiRibbon.xml b/WordAddIn/WordAddIn/AiRibbon.xml
index 8c16637..65355db 100644
--- a/WordAddIn/WordAddIn/AiRibbon.xml
+++ b/WordAddIn/WordAddIn/AiRibbon.xml
@@ -2,21 +2,33 @@
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
diff --git a/WordAddIn/WordAddIn/CreateOutlineForm.cs b/WordAddIn/WordAddIn/CreateOutlineForm.cs
index bf9087d..fd6a52c 100644
--- a/WordAddIn/WordAddIn/CreateOutlineForm.cs
+++ b/WordAddIn/WordAddIn/CreateOutlineForm.cs
@@ -56,14 +56,14 @@ namespace WordAddIn
this.txtTopic.Multiline = true;
this.txtTopic.Name = "txtTopic";
this.txtTopic.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
- this.txtTopic.Size = new System.Drawing.Size(440, 240);
+ this.txtTopic.Size = new System.Drawing.Size(460, 240);
this.txtTopic.TabIndex = 1;
//
// btnGenerate
//
this.btnGenerate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnGenerate.DialogResult = System.Windows.Forms.DialogResult.OK;
- this.btnGenerate.Location = new System.Drawing.Point(240, 310);
+ this.btnGenerate.Location = new System.Drawing.Point(260, 310);
this.btnGenerate.Name = "btnGenerate";
this.btnGenerate.Size = new System.Drawing.Size(100, 35);
this.btnGenerate.TabIndex = 2;
@@ -75,7 +75,7 @@ namespace WordAddIn
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
- this.btnCancel.Location = new System.Drawing.Point(360, 310);
+ this.btnCancel.Location = new System.Drawing.Point(380, 310);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(100, 35);
this.btnCancel.TabIndex = 3;
@@ -86,6 +86,7 @@ namespace WordAddIn
//
// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+ this.Font = new System.Drawing.Font("Microsoft YaHei UI", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(500, 370);
this.MinimumSize = new System.Drawing.Size(400, 300);
diff --git a/WordAddIn/WordAddIn/ImageOptionsForm.cs b/WordAddIn/WordAddIn/ImageOptionsForm.cs
index d876a9d..36e0ef5 100644
--- a/WordAddIn/WordAddIn/ImageOptionsForm.cs
+++ b/WordAddIn/WordAddIn/ImageOptionsForm.cs
@@ -37,11 +37,15 @@ namespace WordAddIn
public string SelectedStyle { get; private set; }
private ComboBox cmbStyles;
+ private RadioButton rbClipboard;
+ private RadioButton rbInput;
+ private TextBox txtInput;
private TextBox txtFinalPrompt;
private CheckBox chkOptimize;
private Button btnOk;
private Button btnCancel;
private Label lblStyle;
+ private Label lblSource;
private Label lblPrompt;
private readonly Dictionary _styleTemplates = new Dictionary();
@@ -93,17 +97,22 @@ namespace WordAddIn
private void InitializeComponent()
{
- this.Text = "生成配图选项 - 支持编辑提示词";
- this.Size = new Size(500, 520);
- this.MinimumSize = new Size(400, 400); // 设置最小尺寸
+ this.Text = "生成配图设置";
+ this.Size = new Size(500, 650);
+ this.MinimumSize = new Size(400, 500);
this.StartPosition = FormStartPosition.CenterParent;
- this.AutoScaleMode = AutoScaleMode.Dpi; // 支持 DPI 缩放
- this.FormBorderStyle = FormBorderStyle.Sizable; // 允许调整大小
- this.MaximizeBox = true; // 允许最大化
+ this.AutoScaleMode = AutoScaleMode.Dpi;
+ this.Font = new System.Drawing.Font("Microsoft YaHei UI", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.FormBorderStyle = FormBorderStyle.Sizable;
+ this.MaximizeBox = true;
this.MinimizeBox = true;
this.lblStyle = new Label();
this.cmbStyles = new ComboBox();
+ this.lblSource = new Label();
+ this.rbClipboard = new RadioButton();
+ this.rbInput = new RadioButton();
+ this.txtInput = new TextBox();
this.lblPrompt = new Label();
this.txtFinalPrompt = new TextBox();
this.chkOptimize = new CheckBox();
@@ -115,52 +124,81 @@ namespace WordAddIn
// lblStyle
this.lblStyle.AutoSize = true;
this.lblStyle.Location = new Point(20, 20);
- this.lblStyle.Text = "图片风格:";
+ this.lblStyle.Text = "1. 图片风格:";
// cmbStyles
this.cmbStyles.DropDownStyle = ComboBoxStyle.DropDownList;
this.cmbStyles.Location = new Point(20, 45);
this.cmbStyles.Size = new Size(440, 25);
- this.cmbStyles.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; // 宽度自适应
+ this.cmbStyles.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
this.cmbStyles.SelectedIndexChanged += CmbStyles_SelectedIndexChanged;
+ // lblSource
+ this.lblSource.AutoSize = true;
+ this.lblSource.Location = new Point(20, 85);
+ this.lblSource.Text = "2. 内容来源:";
+
+ // rbClipboard
+ this.rbClipboard.AutoSize = true;
+ this.rbClipboard.Location = new Point(40, 110);
+ this.rbClipboard.Text = "使用剪贴板内容";
+ this.rbClipboard.CheckedChanged += RbSource_CheckedChanged;
+
+ // rbInput
+ this.rbInput.AutoSize = true;
+ this.rbInput.Location = new Point(200, 110);
+ this.rbInput.Text = "手动录入/编辑";
+ this.rbInput.CheckedChanged += RbSource_CheckedChanged;
+
+ // txtInput
+ this.txtInput.Location = new Point(40, 140);
+ this.txtInput.Multiline = true;
+ this.txtInput.ScrollBars = ScrollBars.Vertical;
+ this.txtInput.Size = new Size(420, 100);
+ this.txtInput.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
+ this.txtInput.TextChanged += TxtInput_TextChanged;
+
// lblPrompt
this.lblPrompt.AutoSize = true;
- this.lblPrompt.Location = new Point(20, 85);
- this.lblPrompt.Text = "提示词预览 (您可以直接修改下面的生成指令):";
+ this.lblPrompt.Location = new Point(20, 255);
+ this.lblPrompt.Text = "3. 最终提示词预览 (可直接修改):";
// txtFinalPrompt
- this.txtFinalPrompt.Location = new Point(20, 110);
+ this.txtFinalPrompt.Location = new Point(20, 280);
this.txtFinalPrompt.Multiline = true;
this.txtFinalPrompt.ScrollBars = ScrollBars.Vertical;
- this.txtFinalPrompt.Size = new Size(440, 280);
- this.txtFinalPrompt.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; // 全向自适应
+ this.txtFinalPrompt.Size = new Size(440, 220);
+ this.txtFinalPrompt.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
// chkOptimize
this.chkOptimize.AutoSize = true;
- this.chkOptimize.Location = new Point(20, 400);
- this.chkOptimize.Size = new Size(400, 20);
+ this.chkOptimize.Location = new Point(20, 520);
+ this.chkOptimize.Size = new Size(400, 24);
this.chkOptimize.Text = "使用 AI 优化提示词 (自动翻译成英文并丰富细节)";
this.chkOptimize.Checked = true;
- this.chkOptimize.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; // 底部固定
+ this.chkOptimize.Anchor = AnchorStyles.Bottom | AnchorStyles.Left;
// btnOk
this.btnOk.Text = "开始生成";
this.btnOk.DialogResult = DialogResult.OK;
- this.btnOk.Location = new Point(280, 430);
- this.btnOk.Size = new Size(90, 30);
- this.btnOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; // 右下固定
+ this.btnOk.Location = new Point(260, 560);
+ this.btnOk.Size = new Size(100, 35);
+ this.btnOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
this.btnOk.Click += BtnOk_Click;
// btnCancel
this.btnCancel.Text = "取消";
this.btnCancel.DialogResult = DialogResult.Cancel;
- this.btnCancel.Location = new Point(380, 430);
- this.btnCancel.Size = new Size(80, 30);
- this.btnCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; // 右下固定
+ this.btnCancel.Location = new Point(380, 560);
+ this.btnCancel.Size = new Size(80, 35);
+ this.btnCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
this.Controls.Add(this.lblStyle);
this.Controls.Add(this.cmbStyles);
+ this.Controls.Add(this.lblSource);
+ this.Controls.Add(this.rbClipboard);
+ this.Controls.Add(this.rbInput);
+ this.Controls.Add(this.txtInput);
this.Controls.Add(this.lblPrompt);
this.Controls.Add(this.txtFinalPrompt);
this.Controls.Add(this.chkOptimize);
@@ -174,16 +212,68 @@ namespace WordAddIn
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
- // 默认选中第一个风格(通常是逻辑架构图,如果 keys 顺序不对可能需要指定)
+
+ // Initialize Source Logic
+ // If SourceText is provided (from Selection), populate txtInput and select rbInput
+ if (!string.IsNullOrWhiteSpace(this.SourceText))
+ {
+ this.txtInput.Text = this.SourceText;
+ this.rbInput.Checked = true;
+ }
+ else
+ {
+ // No selection, check clipboard
+ this.rbClipboard.Checked = true;
+ // Trigger logic to load clipboard if possible
+ RbSource_CheckedChanged(this.rbClipboard, EventArgs.Empty);
+ }
+
+ // Default Style Selection
if (this.cmbStyles.Items.Count > 0)
{
- // 尝试找到上次选中的或默认逻辑架构图
int index = this.cmbStyles.FindString("逻辑架构图");
this.cmbStyles.SelectedIndex = index >= 0 ? index : 0;
}
else
{
- // Fallback update if no items or default
+ UpdatePrompt();
+ }
+ }
+
+ private void RbSource_CheckedChanged(object sender, EventArgs e)
+ {
+ if (rbClipboard.Checked)
+ {
+ this.txtInput.Enabled = false;
+ try
+ {
+ if (Clipboard.ContainsText())
+ {
+ this.SourceText = Clipboard.GetText().Trim();
+ }
+ else
+ {
+ this.SourceText = "";
+ }
+ }
+ catch
+ {
+ this.SourceText = "";
+ }
+ }
+ else if (rbInput.Checked)
+ {
+ this.txtInput.Enabled = true;
+ this.SourceText = this.txtInput.Text;
+ }
+ UpdatePrompt();
+ }
+
+ private void TxtInput_TextChanged(object sender, EventArgs e)
+ {
+ if (rbInput.Checked)
+ {
+ this.SourceText = this.txtInput.Text;
UpdatePrompt();
}
}
diff --git a/WordAddIn/WordAddIn/LoadingForm.cs b/WordAddIn/WordAddIn/LoadingForm.cs
index 7b3b0c6..af55616 100644
--- a/WordAddIn/WordAddIn/LoadingForm.cs
+++ b/WordAddIn/WordAddIn/LoadingForm.cs
@@ -55,7 +55,7 @@ namespace WordAddIn
//
this.lblMessage.BackColor = System.Drawing.Color.Transparent;
this.lblMessage.Dock = System.Windows.Forms.DockStyle.None;
- this.lblMessage.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.lblMessage.Font = new System.Drawing.Font("Microsoft YaHei UI", 14F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblMessage.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
this.lblMessage.Location = new System.Drawing.Point(0, 150);
this.lblMessage.Name = "lblMessage";
@@ -68,7 +68,7 @@ namespace WordAddIn
//
this.txtProgress.BackColor = System.Drawing.Color.White;
this.txtProgress.BorderStyle = System.Windows.Forms.BorderStyle.None;
- this.txtProgress.Font = new System.Drawing.Font("Microsoft YaHei UI", 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.txtProgress.Font = new System.Drawing.Font("Microsoft YaHei UI", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.txtProgress.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
this.txtProgress.Location = new System.Drawing.Point(40, 190);
this.txtProgress.Name = "txtProgress";
diff --git a/WordAddIn/WordAddIn/LoginForm.cs b/WordAddIn/WordAddIn/LoginForm.cs
index 912d59d..520d0f1 100644
--- a/WordAddIn/WordAddIn/LoginForm.cs
+++ b/WordAddIn/WordAddIn/LoginForm.cs
@@ -43,7 +43,7 @@ namespace WordAddIn
// lblTitle
//
this.lblTitle.AutoSize = false;
- this.lblTitle.Font = new System.Drawing.Font("微软雅黑", 16F, System.Drawing.FontStyle.Bold);
+ this.lblTitle.Font = new System.Drawing.Font("微软雅黑", 18F, System.Drawing.FontStyle.Bold);
this.lblTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(43)))), ((int)(((byte)(87)))), ((int)(((byte)(154)))));
this.lblTitle.Location = new System.Drawing.Point(0, 25);
this.lblTitle.Name = "lblTitle";
@@ -55,7 +55,7 @@ namespace WordAddIn
// lblUser
//
this.lblUser.AutoSize = true;
- this.lblUser.Font = new System.Drawing.Font("微软雅黑", 11F);
+ this.lblUser.Font = new System.Drawing.Font("微软雅黑", 13F);
this.lblUser.Location = new System.Drawing.Point(80, 85);
this.lblUser.Name = "lblUser";
this.lblUser.Size = new System.Drawing.Size(63, 20);
@@ -64,7 +64,7 @@ namespace WordAddIn
//
// txtUsername
//
- this.txtUsername.Font = new System.Drawing.Font("微软雅黑", 11F);
+ this.txtUsername.Font = new System.Drawing.Font("微软雅黑", 13F);
this.txtUsername.Location = new System.Drawing.Point(160, 80);
this.txtUsername.Name = "txtUsername";
this.txtUsername.Size = new System.Drawing.Size(220, 27);
@@ -74,7 +74,7 @@ namespace WordAddIn
// lblPass
//
this.lblPass.AutoSize = true;
- this.lblPass.Font = new System.Drawing.Font("微软雅黑", 11F);
+ this.lblPass.Font = new System.Drawing.Font("微软雅黑", 13F);
this.lblPass.Location = new System.Drawing.Point(80, 145);
this.lblPass.Name = "lblPass";
this.lblPass.Size = new System.Drawing.Size(58, 20);
@@ -83,7 +83,7 @@ namespace WordAddIn
//
// txtPassword
//
- this.txtPassword.Font = new System.Drawing.Font("微软雅黑", 11F);
+ this.txtPassword.Font = new System.Drawing.Font("微软雅黑", 13F);
this.txtPassword.Location = new System.Drawing.Point(160, 140);
this.txtPassword.Name = "txtPassword";
this.txtPassword.PasswordChar = '●';
@@ -97,7 +97,7 @@ namespace WordAddIn
this.btnLogin.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnLogin.FlatAppearance.BorderSize = 0;
this.btnLogin.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
- this.btnLogin.Font = new System.Drawing.Font("微软雅黑", 10F, System.Drawing.FontStyle.Bold);
+ this.btnLogin.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold);
this.btnLogin.ForeColor = System.Drawing.Color.White;
this.btnLogin.Location = new System.Drawing.Point(110, 220);
this.btnLogin.Name = "btnLogin";
@@ -111,7 +111,7 @@ namespace WordAddIn
//
this.btnCancel.Cursor = System.Windows.Forms.Cursors.Hand;
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
- this.btnCancel.Font = new System.Drawing.Font("微软雅黑", 10F);
+ this.btnCancel.Font = new System.Drawing.Font("微软雅黑", 12F);
this.btnCancel.Location = new System.Drawing.Point(250, 220);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(120, 40);
@@ -124,6 +124,7 @@ namespace WordAddIn
this.AcceptButton = this.btnLogin;
// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+ this.Font = new System.Drawing.Font("Microsoft YaHei UI", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.BackColor = System.Drawing.Color.White;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(500, 320);
diff --git a/WordAddIn/WordAddIn/Models.cs b/WordAddIn/WordAddIn/Models.cs
index 73088ab..1daeb4e 100644
--- a/WordAddIn/WordAddIn/Models.cs
+++ b/WordAddIn/WordAddIn/Models.cs
@@ -206,5 +206,14 @@ namespace WordAddIn.Models
/// 2: 右对齐
///
public int Alignment { get; set; } = 0;
+
+ ///
+ /// 字体颜色 (Word WdColor 枚举值)
+ /// 默认值为黑色 (wdColorBlack = -16777216, but usually 0 or auto)
+ /// 在 Word Interop 中,wdColorBlack = 0 (0x000000)
+ /// wdColorAutomatic = -16777216 (0xFF000000)
+ /// 我们存储 int 值。
+ ///
+ public int Color { get; set; } = 0; // 0 = Black
}
}
diff --git a/WordAddIn/WordAddIn/OutlineResultForm.cs b/WordAddIn/WordAddIn/OutlineResultForm.cs
index b0c4ba7..58ea7de 100644
--- a/WordAddIn/WordAddIn/OutlineResultForm.cs
+++ b/WordAddIn/WordAddIn/OutlineResultForm.cs
@@ -79,6 +79,7 @@ namespace WordAddIn
// OutlineResultForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+ this.Font = new System.Drawing.Font("Microsoft YaHei UI", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.ClientSize = new System.Drawing.Size(584, 461);
this.Controls.Add(this.btnClose);
this.Controls.Add(this.btnCopy);
diff --git a/WordAddIn/WordAddIn/OutlineSettingsForm.cs b/WordAddIn/WordAddIn/OutlineSettingsForm.cs
index e098c80..e849016 100644
--- a/WordAddIn/WordAddIn/OutlineSettingsForm.cs
+++ b/WordAddIn/WordAddIn/OutlineSettingsForm.cs
@@ -81,6 +81,7 @@ namespace WordAddIn
this.AcceptButton = this.btnSave;
// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+ this.Font = new System.Drawing.Font("Microsoft YaHei UI", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(450, 360);
this.MinimumSize = new System.Drawing.Size(350, 300);
diff --git a/WordAddIn/WordAddIn/ReferenceGeneratorForm.cs b/WordAddIn/WordAddIn/ReferenceGeneratorForm.cs
index 1c76e26..27bb6aa 100644
--- a/WordAddIn/WordAddIn/ReferenceGeneratorForm.cs
+++ b/WordAddIn/WordAddIn/ReferenceGeneratorForm.cs
@@ -82,7 +82,7 @@ namespace WordAddIn
| System.Windows.Forms.AnchorStyles.Right)));
this.tabControl.Controls.Add(this.tabFile);
this.tabControl.Controls.Add(this.tabText);
- this.tabControl.Font = new System.Drawing.Font("微软雅黑", 11F);
+ this.tabControl.Font = new System.Drawing.Font("微软雅黑", 13F);
this.tabControl.Location = new System.Drawing.Point(25, 25);
this.tabControl.Name = "tabControl";
this.tabControl.SelectedIndex = 0;
@@ -105,7 +105,7 @@ namespace WordAddIn
// lblFileTip
//
this.lblFileTip.AutoSize = true;
- this.lblFileTip.Font = new System.Drawing.Font("微软雅黑", 12F);
+ this.lblFileTip.Font = new System.Drawing.Font("微软雅黑", 14F);
this.lblFileTip.Location = new System.Drawing.Point(30, 60);
this.lblFileTip.Name = "lblFileTip";
this.lblFileTip.Size = new System.Drawing.Size(255, 21);
@@ -116,7 +116,7 @@ namespace WordAddIn
//
this.txtFilePath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
- this.txtFilePath.Font = new System.Drawing.Font("微软雅黑", 11F);
+ this.txtFilePath.Font = new System.Drawing.Font("微软雅黑", 13F);
this.txtFilePath.Location = new System.Drawing.Point(30, 100);
this.txtFilePath.Name = "txtFilePath";
this.txtFilePath.ReadOnly = true;
@@ -127,7 +127,7 @@ namespace WordAddIn
//
this.btnBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnBrowse.Cursor = System.Windows.Forms.Cursors.Hand;
- this.btnBrowse.Font = new System.Drawing.Font("微软雅黑", 10F);
+ this.btnBrowse.Font = new System.Drawing.Font("微软雅黑", 12F);
this.btnBrowse.Location = new System.Drawing.Point(440, 98);
this.btnBrowse.Name = "btnBrowse";
this.btnBrowse.Size = new System.Drawing.Size(100, 35);
@@ -152,7 +152,7 @@ namespace WordAddIn
this.txtReferenceInput.BackColor = System.Drawing.Color.WhiteSmoke;
this.txtReferenceInput.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.txtReferenceInput.Dock = System.Windows.Forms.DockStyle.Fill;
- this.txtReferenceInput.Font = new System.Drawing.Font("微软雅黑", 11F);
+ this.txtReferenceInput.Font = new System.Drawing.Font("微软雅黑", 13F);
this.txtReferenceInput.Location = new System.Drawing.Point(10, 10);
this.txtReferenceInput.Name = "txtReferenceInput";
this.txtReferenceInput.Size = new System.Drawing.Size(557, 247);
@@ -163,7 +163,7 @@ namespace WordAddIn
//
this.lblWordCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.lblWordCount.AutoSize = true;
- this.lblWordCount.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Bold);
+ this.lblWordCount.Font = new System.Drawing.Font("微软雅黑", 14F, System.Drawing.FontStyle.Bold);
this.lblWordCount.Location = new System.Drawing.Point(30, 355);
this.lblWordCount.Name = "lblWordCount";
this.lblWordCount.Size = new System.Drawing.Size(117, 22);
@@ -173,7 +173,7 @@ namespace WordAddIn
// numWordCount
//
this.numWordCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
- this.numWordCount.Font = new System.Drawing.Font("微软雅黑", 14F);
+ this.numWordCount.Font = new System.Drawing.Font("微软雅黑", 16F);
this.numWordCount.Increment = new decimal(new int[] {
100,
0,
@@ -246,6 +246,7 @@ namespace WordAddIn
this.AcceptButton = this.btnGenerate;
// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+ this.Font = new System.Drawing.Font("Microsoft YaHei UI", 11F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.BackColor = System.Drawing.Color.White;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(650, 520);
diff --git a/WordAddIn/WordAddIn/StyleEditorControl.cs b/WordAddIn/WordAddIn/StyleEditorControl.cs
index 220573f..0ed74cb 100644
--- a/WordAddIn/WordAddIn/StyleEditorControl.cs
+++ b/WordAddIn/WordAddIn/StyleEditorControl.cs
@@ -18,6 +18,10 @@ namespace WordAddIn
private NumericUpDown numSize;
private CheckBox chkBold;
private ComboBox cmbAlign;
+ private Button btnColor; // 颜色选择按钮
+ private Panel pnlColorPreview; // 颜色预览面板
+ private int _selectedColor = 0; // 存储选中的颜色值 (Word WdColor)
+
private bool _showAlign;
///
@@ -70,6 +74,17 @@ namespace WordAddIn
this.Controls.Add(numSize);
this.Controls.Add(chkBold);
+ // 颜色选择
+ Label lblColor = new Label { Text = "颜色:", Location = new Point(180, 67), AutoSize = true };
+ btnColor = new Button { Text = "选择...", Location = new Point(220, 63), Width = 60, Height = 25 };
+ pnlColorPreview = new Panel { Location = new Point(290, 65), Width = 20, Height = 20, BorderStyle = BorderStyle.FixedSingle, BackColor = Color.Black };
+
+ btnColor.Click += BtnColor_Click;
+
+ this.Controls.Add(lblColor);
+ this.Controls.Add(btnColor);
+ this.Controls.Add(pnlColorPreview);
+
// 对齐方式 (可选)
if (_showAlign)
{
@@ -83,6 +98,35 @@ namespace WordAddIn
}
}
+ private void BtnColor_Click(object sender, EventArgs e)
+ {
+ using (ColorDialog colorDialog = new ColorDialog())
+ {
+ // Set initial color based on current selection
+ colorDialog.Color = pnlColorPreview.BackColor;
+
+ if (colorDialog.ShowDialog() == DialogResult.OK)
+ {
+ pnlColorPreview.BackColor = colorDialog.Color;
+
+ // Convert .NET Color to Word WdColor (int)
+ // Word stores colors as BGR (0xBBGGRR) in lower 24 bits
+ // But .NET Color.ToArgb() returns ARGB (0xAARRGGBB)
+ // WdColor is weird.
+ // wdColorBlack = 0
+ // wdColorRed = 255 (0x0000FF)
+ // It seems to be standard RGB or BGR integer value.
+ // Let's use ColorTranslator or manual conversion.
+ // Word Interop usually expects BGR int for some properties, or standard OLE color.
+ // Actually, WdColor enum has values like wdColorRed = 0xFF.
+ // The safest way is to cast the RGB value.
+ // However, ColorTranslator.ToOle(c) returns BGR, which is what Office usually expects.
+
+ _selectedColor = ColorTranslator.ToOle(colorDialog.Color);
+ }
+ }
+ }
+
///
/// 将 TextStyle 对象应用到界面控件。
///
@@ -98,6 +142,17 @@ namespace WordAddIn
numSize.Value = (decimal)style.FontSize;
chkBold.Checked = style.IsBold;
+
+ _selectedColor = style.Color;
+ // Convert OLE Color back to .NET Color for preview
+ try
+ {
+ pnlColorPreview.BackColor = ColorTranslator.FromOle(_selectedColor);
+ }
+ catch
+ {
+ pnlColorPreview.BackColor = Color.Black;
+ }
if (_showAlign && cmbAlign != null)
{
@@ -116,6 +171,8 @@ namespace WordAddIn
style.FontName = cmbFont.Text;
style.FontSize = (float)numSize.Value;
style.IsBold = chkBold.Checked;
+ style.Color = _selectedColor;
+
if (_showAlign && cmbAlign != null)
{
style.Alignment = cmbAlign.SelectedIndex;
diff --git a/WordAddIn/WordAddIn/WordAddIn.csproj b/WordAddIn/WordAddIn/WordAddIn.csproj
index b79b50c..a9504ab 100644
--- a/WordAddIn/WordAddIn/WordAddIn.csproj
+++ b/WordAddIn/WordAddIn/WordAddIn.csproj
@@ -288,6 +288,9 @@
UserControl
+
+ Form
+
ThisAddIn.cs
diff --git a/WordAddIn/WordAddIn/bin/Release/WordAddIn.dll b/WordAddIn/WordAddIn/bin/Release/WordAddIn.dll
index a3d5ec7..4fc2a5a 100644
Binary files a/WordAddIn/WordAddIn/bin/Release/WordAddIn.dll and b/WordAddIn/WordAddIn/bin/Release/WordAddIn.dll differ
diff --git a/WordAddIn/WordAddIn/bin/Release/WordAddIn.dll.manifest b/WordAddIn/WordAddIn/bin/Release/WordAddIn.dll.manifest
index 710aabf..b4cafde 100644
--- a/WordAddIn/WordAddIn/bin/Release/WordAddIn.dll.manifest
+++ b/WordAddIn/WordAddIn/bin/Release/WordAddIn.dll.manifest
@@ -166,14 +166,14 @@
-
+
- b7Cc32gOO4NDdlCmmAwOKVKIxiGSuuKv6qdRFKUoZo8=
+ Sv+qgHZFDhjy9IFwv7kNOHU+fY7HZYjsKfxAAPn7OKk=
@@ -200,4 +200,4 @@
-UhpvvvhZ0JKx4s3N602bgk5DyV5yFn1sFdOJrcd9Vjg=GZa7zL6wJ+jKnaAHu66eweHxTbmrpypWRicD0zClj3D28NdnnNe1IO51tYdaVglSZ9frQUYeS0mDj2FrUXr26NET0eFZTrfjXBwXtTsiiVnD53Zfd/MGpLF1LlXran/i7/Q8CknNtNDechzMVjs7uDS2Gx+PsycmEu03QrNpC1Y=23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=AQABCN=DESKTOP-Q6H7B6L\AdministratorvkwRm4lIKJ57QGSD+RJm0qwloH1cmITo8KKjBN5VXXY=Sk6rRKpxCaPMi39cj35dPg3SXlS0etffN9z9NtdtGDm2TdptcSY9ljLa1p8fhfNBSTQn2T8wpTC+BYYgLfBI0ymRfH38uKAFdfXvTkOTfM0LPWguRxvu/GLrXsh9K3SrxJnuLk3Dc1Rdh5/BG91NPAtojdkcVvXhnB4fdPZlboM=23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=AQABMIICDTCCAXagAwIBAgIQJpSlsxfGbpRNgyjD5Q/yDjANBgkqhkiG9w0BAQsFADBFMUMwQQYDVQQDHjoARABFAFMASwBUAE8AUAAtAFEANgBIADcAQgA2AEwAXABBAGQAbQBpAG4AaQBzAHQAcgBhAHQAbwByMB4XDTI2MDEyNDAwMzYxNVoXDTI3MDEyNDA2MzYxNVowRTFDMEEGA1UEAx46AEQARQBTAEsAVABPAFAALQBRADYASAA3AEIANgBMAFwAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaECAwEAATANBgkqhkiG9w0BAQsFAAOBgQC3GjWMhEFFrn9PGYrQVGNAaibG1sR/eRX3ZWNRjYLhiqbsdeHvm4CX/W0EWd9yZlbaej87XyeUbX+mC3q3yMFVPCRn/W65WYyBPbWTWmSfU9VLKKULAH6WqjS7CqEU3cQSuKcU6nYG4AJu2/FkQJaA82tr3pvcQD28HmOlDeNh0Q==
\ No newline at end of file
+ZOkNjAKYNyMSBNhvZ8gVr+wBPStzS85tNEApEJeuU10=m54F1LbgqoSzKzsz7VyEaU5L5VPSErBFaVB+4TDGDHYawHVbgmm+xC3AcJZeVCYlrEobHTKRQrug9hgt0u3q6pK+tYcye6oXQEkxZPWvSR+HCMd642w1HnEXe0OYgQrgr3BCfGgCbbqjGgSCyI3JsakstMSgAudffFmbmK9rbLI=23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=AQABCN=DESKTOP-Q6H7B6L\Administratort0BRfVoNqhoaPOc2UKbHbTHoevSy5xe2FpaMu7/cbao=yhN59Dtne4w1PdCUP45PNv5AM8RCDXSK1L/BP2VtKtHrZuR58L+mJcST1vBX4HkDilbegq8WX2Ox7Hf+kqLSuS6LMP4teKrzuzF9ROH0TFnLKUOPuWrJjtBoZAmInun8Vfqxq2fCpOCDd/wRrDqRjm2YQHn/qHwHQkXNzlzfjuA=23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=AQABMIICDTCCAXagAwIBAgIQJpSlsxfGbpRNgyjD5Q/yDjANBgkqhkiG9w0BAQsFADBFMUMwQQYDVQQDHjoARABFAFMASwBUAE8AUAAtAFEANgBIADcAQgA2AEwAXABBAGQAbQBpAG4AaQBzAHQAcgBhAHQAbwByMB4XDTI2MDEyNDAwMzYxNVoXDTI3MDEyNDA2MzYxNVowRTFDMEEGA1UEAx46AEQARQBTAEsAVABPAFAALQBRADYASAA3AEIANgBMAFwAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaECAwEAATANBgkqhkiG9w0BAQsFAAOBgQC3GjWMhEFFrn9PGYrQVGNAaibG1sR/eRX3ZWNRjYLhiqbsdeHvm4CX/W0EWd9yZlbaej87XyeUbX+mC3q3yMFVPCRn/W65WYyBPbWTWmSfU9VLKKULAH6WqjS7CqEU3cQSuKcU6nYG4AJu2/FkQJaA82tr3pvcQD28HmOlDeNh0Q==
\ No newline at end of file
diff --git a/WordAddIn/WordAddIn/bin/Release/WordAddIn.pdb b/WordAddIn/WordAddIn/bin/Release/WordAddIn.pdb
index 9c663fb..aa50c45 100644
Binary files a/WordAddIn/WordAddIn/bin/Release/WordAddIn.pdb and b/WordAddIn/WordAddIn/bin/Release/WordAddIn.pdb differ
diff --git a/WordAddIn/WordAddIn/bin/Release/WordAddIn.vsto b/WordAddIn/WordAddIn/bin/Release/WordAddIn.vsto
index 4e55349..da6b110 100644
--- a/WordAddIn/WordAddIn/bin/Release/WordAddIn.vsto
+++ b/WordAddIn/WordAddIn/bin/Release/WordAddIn.vsto
@@ -14,8 +14,8 @@
- obQbc7h6zkA0TnoIduOuBc41vNKQMHpPh/AfJA2YISk=
+ 9reCGw0n5BNGpv4nRAlMEl+9KA74gqf2Bi31YDIuVSE=
-ZwzyY1yEsVCU4BhxJzLlO8ZQHNeXqVPqlmSJisLn3tY=crILPNEfy0A7RZ296BpImLzFIcUZ0g/jODUjoCsDq5DmdI/7irDKROQteazqexi045TvacD9fYe6amgHBgdxM4ET4/rIoivBaRBjMdzsUKvowukrNf9VhMJC3RpRd8HWkugN8+7/JfKjXTsCdZyVXNNOzKr0eYJeuYe3ghBj33E=23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=AQABCN=DESKTOP-Q6H7B6L\Administrator2aT8MYvx/mBGrPRVOvz9piTveMU6NJjxI8LltLyjLWw=hqq7e3z1TzCr+rHGXu1pVw078sk9+Ur7YDZf2YI3Pw1Y5+78F0ize4FhdGdcVjmBmq7f0/5qrA3jqbCcf0hUwd+4AiQSlEeAV50B9SlrvcoRwVjXl6CjkSnKyUEOChNJgA7rgr931hNUXsdIUQ6vtEqdHMLf4WT1bSDiqqvfxYI=23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=AQABMIICDTCCAXagAwIBAgIQJpSlsxfGbpRNgyjD5Q/yDjANBgkqhkiG9w0BAQsFADBFMUMwQQYDVQQDHjoARABFAFMASwBUAE8AUAAtAFEANgBIADcAQgA2AEwAXABBAGQAbQBpAG4AaQBzAHQAcgBhAHQAbwByMB4XDTI2MDEyNDAwMzYxNVoXDTI3MDEyNDA2MzYxNVowRTFDMEEGA1UEAx46AEQARQBTAEsAVABPAFAALQBRADYASAA3AEIANgBMAFwAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaECAwEAATANBgkqhkiG9w0BAQsFAAOBgQC3GjWMhEFFrn9PGYrQVGNAaibG1sR/eRX3ZWNRjYLhiqbsdeHvm4CX/W0EWd9yZlbaej87XyeUbX+mC3q3yMFVPCRn/W65WYyBPbWTWmSfU9VLKKULAH6WqjS7CqEU3cQSuKcU6nYG4AJu2/FkQJaA82tr3pvcQD28HmOlDeNh0Q==
\ No newline at end of file
+SUC6Yjv6NvxmVHgsXQGLba0wVDBY01J0NUXy81ARtjM=rJF3Cswyo7dSJZ0ZBkoYjEc/BDekJOQ+kDoxvMOf7UWBYec+2EOUBXb+XZwVF7uVLXOJsDTJncnHBf9hcrcwnq8fF7HWuDw9lOMkzvDs5kPvkp9aTIFvPuu8BotBAYV3sn1jHnrtOAf2mkmD/1LU2hyhiH5ymyyI0w17Rwi+f0k=23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=AQABCN=DESKTOP-Q6H7B6L\AdministratorBmlXdT7EP/tEd4mBeMHh2OJ8nURtQ9BfdX3rIi01DPA=eRIoPFOTfeko5ygKR1m63sb+yJ8qFp9CZniS9T8sMW1WmMAZozZJXiMH+bYIHO1P6Z+47rJHoSfmvUSESLpHIzk0s+WYSd/w4NK/aGE+vIwFA/SeHCWeqfhqC65ZjS0hVbQJ7ScoJfiBTLjNBEPmD/tQhQM/m8/jLv6cRZ8ToQA=23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaE=AQABMIICDTCCAXagAwIBAgIQJpSlsxfGbpRNgyjD5Q/yDjANBgkqhkiG9w0BAQsFADBFMUMwQQYDVQQDHjoARABFAFMASwBUAE8AUAAtAFEANgBIADcAQgA2AEwAXABBAGQAbQBpAG4AaQBzAHQAcgBhAHQAbwByMB4XDTI2MDEyNDAwMzYxNVoXDTI3MDEyNDA2MzYxNVowRTFDMEEGA1UEAx46AEQARQBTAEsAVABPAFAALQBRADYASAA3AEIANgBMAFwAQQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA23ghUI75yy8GcLhPT5yA+v2ssRfSW+chNqMI+pq5OAr7RXQJOt/+bHdoT9NoS9GQkvblc7ekoUNShIcN601ZZOPgAxkXaQS+La14Wp8GOwnM1qHNJwgla4VAIYjmCj3CUMXLsxspOFVZKRnB6/idYku4Gzhc7NjRBAwe8qWBXaECAwEAATANBgkqhkiG9w0BAQsFAAOBgQC3GjWMhEFFrn9PGYrQVGNAaibG1sR/eRX3ZWNRjYLhiqbsdeHvm4CX/W0EWd9yZlbaej87XyeUbX+mC3q3yMFVPCRn/W65WYyBPbWTWmSfU9VLKKULAH6WqjS7CqEU3cQSuKcU6nYG4AJu2/FkQJaA82tr3pvcQD28HmOlDeNh0Q==
\ No newline at end of file
diff --git a/WordAddIn/WordAddIn/obj/Debug/WordAddIn.csproj.FileListAbsolute.txt b/WordAddIn/WordAddIn/obj/Debug/WordAddIn.csproj.FileListAbsolute.txt
index dc1abd6..2ee1712 100644
--- a/WordAddIn/WordAddIn/obj/Debug/WordAddIn.csproj.FileListAbsolute.txt
+++ b/WordAddIn/WordAddIn/obj/Debug/WordAddIn.csproj.FileListAbsolute.txt
@@ -12,3 +12,17 @@ D:\dsWork\aiData\addOne\WordAddIn\WordAddIn\obj\Debug\WordAddIn.csproj.CoreCompi
D:\dsWork\aiData\addOne\WordAddIn\WordAddIn\obj\Debug\WordAddIn.csproj.Up2Date
D:\dsWork\aiData\addOne\WordAddIn\WordAddIn\obj\Debug\WordAddIn.dll
D:\dsWork\aiData\addOne\WordAddIn\WordAddIn\obj\Debug\WordAddIn.pdb
+d:\dsWork\aiData\WordAddIn\WordAddIn\bin\Debug\WordAddIn.dll
+d:\dsWork\aiData\WordAddIn\WordAddIn\bin\Debug\WordAddIn.pdb
+d:\dsWork\aiData\WordAddIn\WordAddIn\bin\Debug\WordAddIn.dll.manifest
+d:\dsWork\aiData\WordAddIn\WordAddIn\bin\Debug\WordAddIn.vsto
+d:\dsWork\aiData\WordAddIn\WordAddIn\bin\Debug\Microsoft.Office.Tools.Common.v4.0.Utilities.dll
+d:\dsWork\aiData\WordAddIn\WordAddIn\bin\Debug\Newtonsoft.Json.dll
+d:\dsWork\aiData\WordAddIn\WordAddIn\bin\Debug\Newtonsoft.Json.xml
+d:\dsWork\aiData\WordAddIn\WordAddIn\obj\Debug\WordAddIn.csproj.AssemblyReference.cache
+d:\dsWork\aiData\WordAddIn\WordAddIn\obj\Debug\WordAddIn.Properties.Resources.resources
+d:\dsWork\aiData\WordAddIn\WordAddIn\obj\Debug\WordAddIn.csproj.GenerateResource.cache
+d:\dsWork\aiData\WordAddIn\WordAddIn\obj\Debug\WordAddIn.csproj.CoreCompileInputs.cache
+d:\dsWork\aiData\WordAddIn\WordAddIn\obj\Debug\WordAddIn.csproj.Up2Date
+d:\dsWork\aiData\WordAddIn\WordAddIn\obj\Debug\WordAddIn.dll
+d:\dsWork\aiData\WordAddIn\WordAddIn\obj\Debug\WordAddIn.pdb
diff --git a/WordAddIn/WordAddIn/obj/Release/WordAddIn.csproj.CoreCompileInputs.cache b/WordAddIn/WordAddIn/obj/Release/WordAddIn.csproj.CoreCompileInputs.cache
index e58e509..bcfb20e 100644
--- a/WordAddIn/WordAddIn/obj/Release/WordAddIn.csproj.CoreCompileInputs.cache
+++ b/WordAddIn/WordAddIn/obj/Release/WordAddIn.csproj.CoreCompileInputs.cache
@@ -1 +1 @@
-e154ea9669b13c0b299747f4b6bfc75e5ab40e13fd7d98491977bb58e397c4dc
+a8dbfbd53c9d2d6a82eb262741605b35dd6e229dda7031b84eeac3678ff78031
diff --git a/WordAddIn/WordAddIn/obj/Release/WordAddIn.dll b/WordAddIn/WordAddIn/obj/Release/WordAddIn.dll
index a3d5ec7..4fc2a5a 100644
Binary files a/WordAddIn/WordAddIn/obj/Release/WordAddIn.dll and b/WordAddIn/WordAddIn/obj/Release/WordAddIn.dll differ
diff --git a/WordAddIn/WordAddIn/obj/Release/WordAddIn.pdb b/WordAddIn/WordAddIn/obj/Release/WordAddIn.pdb
index 9c663fb..aa50c45 100644
Binary files a/WordAddIn/WordAddIn/obj/Release/WordAddIn.pdb and b/WordAddIn/WordAddIn/obj/Release/WordAddIn.pdb differ
diff --git a/WordAddIn/WpsInstaller/Program.cs b/WordAddIn/WpsInstaller/Program.cs
index 09dd199..06e6c79 100644
--- a/WordAddIn/WpsInstaller/Program.cs
+++ b/WordAddIn/WpsInstaller/Program.cs
@@ -121,6 +121,102 @@ namespace WpsInstaller
Pause();
}
+ static void UninstallOldVersions()
+ {
+ Console.WriteLine("Checking for existing versions to uninstall...");
+
+ // 1. Cleanup VSTO Keys
+ CleanupVstoKeys();
+
+ // 2. Cleanup WPS Keys
+ CleanupWpsKeys();
+
+ // 3. Cleanup COM Registration (WPS)
+ UnregisterCom("{D8E52004-9D68-4509-8A11-66774D4F0523}", "WordAddIn.WpsAddIn");
+ }
+
+ static void UnregisterCom(string guid, string progId)
+ {
+ try
+ {
+ // Try to find CodeBase from HKCR\CLSID\{GUID}\InprocServer32
+ string clsidKeyPath = @"CLSID\" + guid;
+ string inprocKeyPath = clsidKeyPath + @"\InprocServer32";
+ string oldDllPath = null;
+
+ using (RegistryKey key = Registry.ClassesRoot.OpenSubKey(inprocKeyPath))
+ {
+ if (key != null)
+ {
+ oldDllPath = key.GetValue("CodeBase") as string;
+ if (string.IsNullOrEmpty(oldDllPath))
+ {
+ oldDllPath = key.GetValue("") as string; // Default value
+ }
+ }
+ }
+
+ if (!string.IsNullOrEmpty(oldDllPath))
+ {
+ // Fix file:/// prefix if present
+ if (oldDllPath.StartsWith("file:///", StringComparison.OrdinalIgnoreCase))
+ {
+ oldDllPath = oldDllPath.Substring(8).Replace('/', '\\');
+ }
+
+ if (File.Exists(oldDllPath))
+ {
+ Console.WriteLine(" Found old COM registration pointing to: " + oldDllPath);
+ Console.WriteLine(" Unregistering assembly...");
+
+ string regAsmPath = GetRegAsmPath();
+ if (!string.IsNullOrEmpty(regAsmPath))
+ {
+ string args = string.Format("\"{0}\" /u /tlb", oldDllPath);
+ ProcessStartInfo psi = new ProcessStartInfo(regAsmPath, args);
+ psi.UseShellExecute = false;
+ psi.RedirectStandardOutput = true;
+ psi.CreateNoWindow = true;
+
+ using (Process p = Process.Start(psi))
+ {
+ string output = p.StandardOutput.ReadToEnd();
+ p.WaitForExit();
+ // Console.WriteLine(output); // Optional: show output
+ }
+ Console.WriteLine(" [OK] RegAsm /u completed.");
+ }
+ }
+ else
+ {
+ Console.WriteLine(" Old COM DLL not found at: " + oldDllPath + ". Skipping RegAsm /u.");
+ }
+ }
+
+ // Force delete registry keys to be sure
+ try
+ {
+ Registry.ClassesRoot.DeleteSubKeyTree(clsidKeyPath, false);
+ Console.WriteLine(" [OK] Deleted HKCR\\" + clsidKeyPath);
+ }
+ catch {}
+
+ try
+ {
+ if (!string.IsNullOrEmpty(progId))
+ {
+ Registry.ClassesRoot.DeleteSubKeyTree(progId, false);
+ Console.WriteLine(" [OK] Deleted HKCR\\" + progId);
+ }
+ }
+ catch {}
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(" Warning during COM unregistration: " + ex.Message);
+ }
+ }
+
static void Pause()
{
Console.WriteLine("\nPress any key to exit...");
diff --git a/WordAddIn/WpsInstaller/bin/Debug/WpsInstaller.exe b/WordAddIn/WpsInstaller/bin/Debug/WpsInstaller.exe
index 32a7def..07080cf 100644
Binary files a/WordAddIn/WpsInstaller/bin/Debug/WpsInstaller.exe and b/WordAddIn/WpsInstaller/bin/Debug/WpsInstaller.exe differ
diff --git a/WordAddIn/WpsInstaller/bin/Debug/WpsInstaller.pdb b/WordAddIn/WpsInstaller/bin/Debug/WpsInstaller.pdb
index d12ce85..2b6bb43 100644
Binary files a/WordAddIn/WpsInstaller/bin/Debug/WpsInstaller.pdb and b/WordAddIn/WpsInstaller/bin/Debug/WpsInstaller.pdb differ
diff --git a/WordAddIn/WpsInstaller/bin/Release/WpsInstaller.exe b/WordAddIn/WpsInstaller/bin/Release/WpsInstaller.exe
index d9db986..371d1ac 100644
Binary files a/WordAddIn/WpsInstaller/bin/Release/WpsInstaller.exe and b/WordAddIn/WpsInstaller/bin/Release/WpsInstaller.exe differ
diff --git a/WordAddIn/WpsInstaller/bin/Release/WpsInstaller.pdb b/WordAddIn/WpsInstaller/bin/Release/WpsInstaller.pdb
index 7e6dbd8..84ac618 100644
Binary files a/WordAddIn/WpsInstaller/bin/Release/WpsInstaller.pdb and b/WordAddIn/WpsInstaller/bin/Release/WpsInstaller.pdb differ
diff --git a/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.csproj.AssemblyReference.cache b/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.csproj.AssemblyReference.cache
deleted file mode 100644
index c5dbbe8..0000000
Binary files a/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.csproj.AssemblyReference.cache and /dev/null differ
diff --git a/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.csproj.FileListAbsolute.txt b/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.csproj.FileListAbsolute.txt
index dce9807..560a125 100644
--- a/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.csproj.FileListAbsolute.txt
+++ b/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.csproj.FileListAbsolute.txt
@@ -1,6 +1,5 @@
D:\dsWork\aiData\WordAddIn\WpsInstaller\bin\Debug\WpsInstaller.exe
D:\dsWork\aiData\WordAddIn\WpsInstaller\bin\Debug\WpsInstaller.pdb
-D:\dsWork\aiData\WordAddIn\WpsInstaller\obj\Debug\WpsInstaller.csproj.AssemblyReference.cache
-D:\dsWork\aiData\WordAddIn\WpsInstaller\obj\Debug\WpsInstaller.csproj.CoreCompileInputs.cache
D:\dsWork\aiData\WordAddIn\WpsInstaller\obj\Debug\WpsInstaller.exe
D:\dsWork\aiData\WordAddIn\WpsInstaller\obj\Debug\WpsInstaller.pdb
+d:\dsWork\aiData\WordAddIn\WpsInstaller\obj\Debug\WpsInstaller.csprojResolveAssemblyReference.cache
diff --git a/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.exe b/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.exe
index 32a7def..07080cf 100644
Binary files a/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.exe and b/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.exe differ
diff --git a/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.pdb b/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.pdb
index d12ce85..2b6bb43 100644
Binary files a/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.pdb and b/WordAddIn/WpsInstaller/obj/Debug/WpsInstaller.pdb differ
diff --git a/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.csproj.AssemblyReference.cache b/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.csproj.AssemblyReference.cache
index c5dbbe8..442efad 100644
Binary files a/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.csproj.AssemblyReference.cache and b/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.csproj.AssemblyReference.cache differ
diff --git a/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.exe b/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.exe
index d9db986..371d1ac 100644
Binary files a/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.exe and b/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.exe differ
diff --git a/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.pdb b/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.pdb
index 7e6dbd8..84ac618 100644
Binary files a/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.pdb and b/WordAddIn/WpsInstaller/obj/Release/WpsInstaller.pdb differ