- 引入 log4net 库,统一日志记录方式,提升可维护性。 - 优化异常处理,增加详细日志记录,增强代码健壮性。 - 调整资源文件引用,新增图标资源,删除无用资源。 - 优化文档事件处理逻辑,改进面板显示与隐藏逻辑。 - 增加对 WPS 环境的支持,动态调整功能行为。 - 禁用部分功能(如常识性检测、客服、升级和帮助)。 - 删除冗余代码,清理注释,统一代码风格。 - 更新程序集版本至 2.2.5,改进调试与生产环境配置。
1080 lines
38 KiB
C#
1080 lines
38 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
using AIProofread.Controls;
|
|
using AIProofread.core;
|
|
using AIProofread.Util;
|
|
using DocumentFormat.OpenXml.Office2013.WebExtentionPane;
|
|
using log4net;
|
|
using Microsoft.Office.Interop.Word;
|
|
using Newtonsoft.Json;
|
|
using UtilLib;
|
|
using CustomTaskPane = Microsoft.Office.Tools.CustomTaskPane;
|
|
|
|
namespace AIProofread.Model
|
|
{
|
|
/// <summary>
|
|
/// 文档信息 包含文档相关数据、面板及对文档的相关操作
|
|
/// </summary>
|
|
public class DocumentInfo
|
|
{
|
|
public ILog Logger = LogHelper.GetLogger(typeof(DocumentInfo));
|
|
public static readonly int MIN_WIDTH = 420;
|
|
private static char[] ArticleSpecialChars = new char[4] { '\a', '\r', '\v', '\f' };
|
|
|
|
private static object missing = System.Reflection.Missing.Value;
|
|
/// <summary>
|
|
/// 是否已经校对
|
|
/// </summary>
|
|
public bool hasProofreaded = false;
|
|
/// <summary>
|
|
/// 是否已经处理了校对结果
|
|
/// </summary>
|
|
public bool hasProcessMark = false;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public Dictionary<int, ProofreadItem> marks = new Dictionary<int, ProofreadItem>();
|
|
|
|
/// <summary>
|
|
/// 最小宽度
|
|
/// </summary>
|
|
public static int MinWidth = 0;
|
|
/// <summary>
|
|
/// 校对选区集合
|
|
/// </summary>
|
|
private List<Range> ranges = new List<Range>();
|
|
|
|
/// <summary>
|
|
/// 当前选中对现象编号
|
|
/// </summary>
|
|
private int selectProofreadId;
|
|
|
|
//private Document currentDocument;
|
|
/// <summary>
|
|
/// 当前对应文档
|
|
/// </summary>
|
|
public Document CurrentDocument { get; set; }
|
|
|
|
/// <summary>
|
|
/// 文件名称
|
|
/// </summary>
|
|
public string fileName;
|
|
|
|
private string uniqueId;
|
|
public string UniqueId { get { return uniqueId; } }
|
|
|
|
public string ProofreadCachePath
|
|
{
|
|
get
|
|
{
|
|
return CurrentDocument.FullName + "-proofread.json";
|
|
}
|
|
}
|
|
|
|
public bool IsActive { get; internal set; } = false;
|
|
public bool PaneVisible { get; set; } = false;
|
|
public int Id { get; set; }
|
|
|
|
public CustomTaskPane TaskPane { get; set; }
|
|
public WdProtectionType ProtectionType { get { return CurrentDocument.ProtectionType; } }
|
|
|
|
/// <summary>
|
|
/// 是否已校对
|
|
/// </summary>
|
|
public bool Proofread { get; set; }
|
|
/// <summary>
|
|
/// 是否校对中
|
|
/// </summary>
|
|
public bool Proofreading { get; set; }
|
|
|
|
// 初始化
|
|
public DocumentInfo(Document doc)
|
|
{
|
|
this.CurrentDocument = doc;
|
|
Initialize();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 显示面板
|
|
/// </summary>
|
|
public void ShowPane()
|
|
{
|
|
if (null == TaskPane)
|
|
{
|
|
CreateTaskPane();
|
|
}
|
|
Logger.Debug("TaskPane.Visible {" + TaskPane == null ? "null" : (TaskPane.Visible ? "true" : "false") + " => true");
|
|
TaskPane.Visible = PaneVisible = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 隐藏面板
|
|
/// </summary>
|
|
public void HidePane()
|
|
{
|
|
//if (!PaneVisible) return;
|
|
ShowDocumentStatus("HidePane");
|
|
Logger.Debug($"TaskPane.Visible {TaskPane.Visible} => false");
|
|
TaskPane.Visible = PaneVisible = false;
|
|
}
|
|
|
|
|
|
public void RunInMainThread(Action action)
|
|
{
|
|
Logger.Debug($"RunInMainThread {action}");
|
|
if (null == TaskPane)
|
|
{
|
|
CreateTaskPane();
|
|
}
|
|
TaskPane.Control.BeginInvoke(action);
|
|
}
|
|
|
|
public void ShowDialog(string message, string confirmText, string confirmAction)
|
|
{
|
|
TaskPane.Control.BeginInvoke(new Action(() =>
|
|
{
|
|
//MessageBox.Show(message, "提示");
|
|
FormMessage.ShowMessage(message, confirmText, confirmAction);
|
|
}));
|
|
}
|
|
public FormMessage ShowMessage(string message, int closeDelay, bool showCloseBtn = true)
|
|
{
|
|
var msgForm = FormMessage.ShowMessage(message, closeDelay);
|
|
if (closeDelay > 0)
|
|
{
|
|
|
|
if (!showCloseBtn)
|
|
{
|
|
msgForm.HideCloseBtn();
|
|
}
|
|
// n毫秒后自动关闭
|
|
System.Threading.Tasks.Task.Delay(closeDelay).ContinueWith(t =>
|
|
{
|
|
if (msgForm.IsDisposed) return;
|
|
TaskPane.Control.BeginInvoke(new Action(() =>
|
|
{
|
|
msgForm.Close();
|
|
}));
|
|
});
|
|
}
|
|
return msgForm;
|
|
}
|
|
|
|
public void ShowLogin(string action)
|
|
{
|
|
TaskPane.Control.BeginInvoke(new Action(() =>
|
|
{
|
|
FormLogin frm = new FormLogin(action);
|
|
Globals.ThisAddIn.LoginFormList.Add(frm);
|
|
frm.ShowDialog();
|
|
}));
|
|
}
|
|
|
|
private void ShowDocumentStatus(string tag)
|
|
{
|
|
// Logger.Log($"{fileName} {tag} PaneVisible is {PaneVisible} Poofread is {Proofread} Proofreading is {Proofreading}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 激活
|
|
/// </summary>
|
|
public void Active()
|
|
{
|
|
try
|
|
{
|
|
Logger.Debug("激活 for " + CurrentDocument.FullName + " 没有 visible is " + PaneVisible);
|
|
ShowDocumentStatus("Active");
|
|
IsActive = true;
|
|
if (Config.IS_WPS && null != TaskPane)
|
|
{
|
|
TaskPane.Visible = PaneVisible;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Logger.Error("Active Error", e);
|
|
}
|
|
}
|
|
|
|
public void Deactive()
|
|
{
|
|
try
|
|
{
|
|
ShowDocumentStatus("Deactive");
|
|
IsActive = false;
|
|
if (Config.IS_WPS && null != TaskPane)
|
|
{
|
|
PaneVisible = TaskPane.Visible;
|
|
TaskPane.Visible = false;
|
|
Logger.Debug("取消 for " + CurrentDocument.FullName + " current visible " + PaneVisible);
|
|
}
|
|
}catch (Exception e)
|
|
{
|
|
Logger.Error("Deactive Error", e);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
try
|
|
{
|
|
// 判断TaskPane是否已经释放
|
|
if (null == TaskPane) return;
|
|
if (TaskPane.Control.IsDisposed) return;
|
|
|
|
ProofreadMainControl control = (ProofreadMainControl)TaskPane.Control;
|
|
control.ResetWeb();
|
|
|
|
HidePane();
|
|
TaskPane?.Dispose();
|
|
// 释放com
|
|
try
|
|
{
|
|
Marshal.ReleaseComObject(CurrentDocument);
|
|
}
|
|
catch (Exception) { }
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LogHelper.Log("Error", e);
|
|
}
|
|
}
|
|
|
|
// 计算uniqueId
|
|
private void ComputeUniqueId()
|
|
{
|
|
string filename = CurrentDocument.FullName;
|
|
if (!string.IsNullOrEmpty(uniqueId) || string.IsNullOrEmpty(filename))
|
|
{
|
|
return;
|
|
}
|
|
// 通过文档路径生成唯一id
|
|
uniqueId = filename.GetHashCode().ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加变量控制重复调用
|
|
/// </summary>
|
|
private bool isResizing = false;
|
|
private void Control_SizeChanged(object sender, EventArgs e)
|
|
{
|
|
if (isResizing) return;
|
|
if (TaskPane != null && TaskPane.Visible && TaskPane.Width < MinWidth)
|
|
{
|
|
isResizing = true;
|
|
SendKeys.Send("{ESC}");
|
|
TaskPane.Width = MinWidth;
|
|
isResizing = false;
|
|
}
|
|
}
|
|
|
|
// 创建pane 并初始化
|
|
public void CreateTaskPane()
|
|
{
|
|
Logger.Debug("CreateTaskPane");
|
|
var control = new ProofreadMainControl();
|
|
if (MinWidth < 10)
|
|
{
|
|
MinWidth = MIN_WIDTH * control.LabelWidth() / 42;
|
|
}
|
|
// 创建pane
|
|
TaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(control, Config.RUN_IN_DEBUG ? CurrentDocument.Name : " ");
|
|
// 默认隐藏
|
|
TaskPane.Visible = false;
|
|
// 设置宽度
|
|
control.Width = MinWidth;
|
|
TaskPane.Width = MinWidth;
|
|
|
|
// 监听尺寸变化 防止最小尺寸小于设置值
|
|
control.SizeChanged += Control_SizeChanged;
|
|
TaskPane.VisibleChanged += TaskPane_VisibleChanged;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查按钮状态
|
|
/// </summary>
|
|
public void CheckBtnStatus()
|
|
{
|
|
//
|
|
if (Globals.ThisAddIn.ribbon != null)
|
|
{
|
|
Globals.ThisAddIn.ribbon.BtnShowPanel.Enabled = !PaneVisible && Proofread;
|
|
Globals.ThisAddIn.ribbon.SetCommonBtnStatus(!Proofreading);
|
|
}
|
|
}
|
|
|
|
private void TaskPane_VisibleChanged(object sender, EventArgs e)
|
|
{
|
|
if (Config.IS_WPS)
|
|
{
|
|
if(CurrentDocument == Globals.ThisAddIn.ActiveDocument)
|
|
{
|
|
Logger.Debug($"VisibleChanged ${CurrentDocument.Name} is {TaskPane.Visible}");
|
|
// 如果已经隐藏 则记录隐藏用于(WPS)多面板的切换的处理
|
|
PaneVisible = TaskPane.Visible;
|
|
}
|
|
}
|
|
CheckBtnStatus();
|
|
//Globals.ThisAddIn.ribbon.BtnShowPanel.Enabled = !TaskPane.Visible && Proofread;
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
this.fileName = CurrentDocument.FullName;
|
|
ranges.Clear();
|
|
ComputeUniqueId();
|
|
if (TaskPane == null)
|
|
{
|
|
Logger.Debug("init document Initialize(318) and CreateTaskPane");
|
|
CreateTaskPane();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//处理文档选区时 判断当前选区是否有校对项 有则选择该范围
|
|
public void ProcessSelectionChange(Selection s)
|
|
{
|
|
// 判断选区内是否有书签
|
|
if (s.Bookmarks != null && s.Bookmarks.Count > 0)
|
|
{
|
|
// 判断是否时点击 点击的起始和结束位置相同
|
|
if (s.Range.Start == s.Range.End)
|
|
{
|
|
//
|
|
var count = s.Bookmarks.Count;
|
|
// 原则只有一个书签
|
|
//foreach (Microsoft.Office.Interop.Word.Bookmark item in s.Bookmarks)
|
|
//{
|
|
// int proofreadId = Config.GetBookmarkIdByName(item.Name);
|
|
// if (proofreadId > 0)
|
|
// {
|
|
// //Bridge.bridge.SelectMarkById(proofreadId, 0);
|
|
// return;
|
|
// }
|
|
//}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 获取当前文档文本
|
|
public string GetAllText()
|
|
{
|
|
return CurrentDocument.Range().Text;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取当前选中文本
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string GetSelectedText()
|
|
{
|
|
// 获取当前文档的选区
|
|
var selection = Globals.ThisAddIn.Application.Selection;
|
|
return selection.Text;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取指定选区的文本
|
|
/// </summary>
|
|
/// <param name="range"></param>
|
|
/// <returns></returns>
|
|
public string GetRangeText(Range range)
|
|
{
|
|
string text = range?.Text;
|
|
return string.IsNullOrEmpty(text) ? "" : text;
|
|
}
|
|
/// <summary>
|
|
/// 获取指定选区的文本
|
|
/// </summary>
|
|
/// <param name="start"></param>
|
|
/// <param name="end"></param>
|
|
/// <returns></returns>
|
|
public string GetRangeText(int start, int end)
|
|
{
|
|
if (start >= end) return null;
|
|
return GetRangeText(CurrentDocument.Range(start, end));
|
|
}
|
|
|
|
public Range Range(int start, int end)
|
|
{
|
|
if (start >= end) return null;
|
|
return CurrentDocument.Range(start, end);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存校对缓存结果
|
|
/// </summary>
|
|
private void SaveProofreadCache(string cacheData)
|
|
{
|
|
// 判断文档是否已经保存
|
|
|
|
if (!CurrentDocument.Saved)
|
|
{
|
|
// 保存文档
|
|
if (!CurrentDocument.Saved)
|
|
{
|
|
// 提示保存文档
|
|
var result = MessageBox.Show("当前文档尚未保存,是否保存?", "提示", MessageBoxButtons.YesNo);
|
|
if (result == DialogResult.Yes)
|
|
{
|
|
CurrentDocument.Save();
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 定位所有的校对项
|
|
public void LocateAllProofreadItems(List<CorrectContext> list)
|
|
{
|
|
// 获取所有的校对项
|
|
//List<Range> proofreadItems = GetProofreadItems();
|
|
var prevOffset = 0;
|
|
foreach (var item in list)
|
|
{
|
|
if (item.CorrectItems != null && item.CorrectItems.Count > 0)
|
|
{
|
|
foreach (var correct in item.CorrectItems)
|
|
{
|
|
var range = LocateProofreadItem(correct, item, ref prevOffset);
|
|
if (range == null) continue;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查找偏移量
|
|
/// </summary>
|
|
private static readonly int INSERT_FIND_OFFSET = 5;
|
|
/// <summary>
|
|
/// 定位校对项
|
|
/// </summary>
|
|
/// <param name="correct">校对项</param>
|
|
/// <param name="ctx">校对上下文</param>
|
|
/// <param name="prevOffset">上一步的</param>
|
|
/// <returns></returns>
|
|
private Range LocateProofreadItem(CorrectItem correct, CorrectContext ctx, ref int prevOffset)
|
|
{
|
|
var document = CurrentDocument;
|
|
// 校对项的段落号超过文档的段落数,直接返回
|
|
if (ctx.ParagraphNumber > document.Paragraphs.Count) return null;
|
|
// 获取当前段落
|
|
var paragraph = document.Paragraphs[ctx.ParagraphNumber];
|
|
if (paragraph == null) return null;
|
|
|
|
|
|
var paraRange = paragraph.Range;
|
|
var paraText = paraRange.Text;
|
|
var paraStart = paraRange.Start;
|
|
|
|
//var offset = paraStart + ctx.SentenceOffset;
|
|
//var cutLength = Math.Min(c.InsertLen, paraText.Length - offset);
|
|
var sentence = paraRange.Sentences[ctx.SentenceNumber]; //paraText.Substring(ctx.SentenceOffset, ctx.InsertLength);
|
|
ctx.SentenceOffset = sentence.Start;
|
|
var offset = paraStart + ctx.SentenceOffset;
|
|
if (sentence.Text == ctx.Insert)
|
|
{ // 比对原始内容与校对原文是否一致
|
|
var range = document.Range(offset + correct.Start, offset + correct.End);
|
|
//
|
|
if (range.Text == correct.Origin) return range;
|
|
}
|
|
|
|
var originText = ctx.Insert;
|
|
// 如果是新增 则查找定位
|
|
if (correct.Tag == "i")
|
|
{
|
|
// 找前缀
|
|
var prefix1 = correct.Start > 2 ? (
|
|
correct.Start > INSERT_FIND_OFFSET
|
|
? originText.Substring(correct.Start - INSERT_FIND_OFFSET, INSERT_FIND_OFFSET)
|
|
: originText.Substring(0, correct.Start)
|
|
) : null;
|
|
// 找后缀
|
|
var suffix1 = prefix1 == null ? (
|
|
correct.End + INSERT_FIND_OFFSET < originText.Length
|
|
? originText.Substring(correct.Start, INSERT_FIND_OFFSET)
|
|
: originText.Substring(correct.Start, originText.Length - correct.Start)
|
|
) : null;
|
|
// 偏移量
|
|
var start1 = prefix1 != null || suffix1 != null
|
|
? paraText.IndexOf(prefix1 ?? suffix1, prevOffset)
|
|
: -1;
|
|
if (start1 != -1)
|
|
{
|
|
var findOffset = paraStart + start1 + (prefix1 != null ? prefix1.Length : 0);
|
|
return document.Range(findOffset, findOffset);
|
|
}
|
|
}
|
|
|
|
// 执行查找
|
|
int wordStart = correct.Start;
|
|
int wordEnd = correct.End;
|
|
|
|
// 找前缀
|
|
var prefix = wordStart > 2 ? (
|
|
wordStart > INSERT_FIND_OFFSET
|
|
? originText.Substring(wordStart - INSERT_FIND_OFFSET, INSERT_FIND_OFFSET)
|
|
: originText.Substring(0, wordStart)
|
|
) : null;
|
|
|
|
// 找后缀
|
|
var suffix = prefix == null ? (
|
|
wordEnd + INSERT_FIND_OFFSET < originText.Length
|
|
? originText.Substring(wordStart, INSERT_FIND_OFFSET)
|
|
: originText.Substring(wordStart, originText.Length - wordStart)
|
|
) : null;
|
|
var start = prefix != null || suffix != null
|
|
? paraText.IndexOf(prefix ?? suffix, prevOffset) // item.start +
|
|
: -1;
|
|
if (start != -1)
|
|
{
|
|
var findOffset = paraRange.Start + start + (prefix != null ? prefix.Length : 0);
|
|
var range = document.Range(findOffset, findOffset + wordEnd - wordStart);
|
|
if (range.Text == correct.Origin) { return range; }
|
|
}
|
|
// 直接定位查找
|
|
start = paraText.IndexOf(correct.Origin, prevOffset);
|
|
if (start == -1) return null;
|
|
// 定位整体开始位置
|
|
start = paraStart + start;
|
|
return document.Range(start, start + correct.Origin.Length);
|
|
|
|
}
|
|
|
|
public void GlobalCallback(string callbackId, string result)
|
|
{
|
|
ProofreadMainControl control = (ProofreadMainControl)TaskPane.Control;
|
|
try
|
|
{
|
|
if (control.web.CoreWebView2 == null)
|
|
{
|
|
Thread.Sleep(1000);
|
|
}
|
|
control.web.CoreWebView2.ExecuteScriptAsync($"window.__global_callback_function('{callbackId}','{result}');");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.Log("GlobalCallback", "call web global function error \n" + ex.Message + "\n" + callbackId + result);
|
|
}
|
|
}
|
|
public void SendMessageToWeb(string msg, object data)
|
|
{
|
|
var json = JsonConvert.SerializeObject(new WebMessage(msg, data));
|
|
ProofreadMainControl control = (ProofreadMainControl)TaskPane.Control;
|
|
try
|
|
{
|
|
if (control.web.CoreWebView2 == null)
|
|
{
|
|
Thread.Sleep(1000);
|
|
}
|
|
control.web.CoreWebView2.PostWebMessageAsJson(json);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.Log("SendMessage", "send message to web error \n" + ex.Message + "\n" + msg + data.ToString());
|
|
}
|
|
}
|
|
|
|
public void ClearAllProofreadMark()
|
|
{
|
|
try
|
|
{
|
|
selectProofreadId = -1;
|
|
foreach (var item in marks.Values)
|
|
{
|
|
if (item.mark != null)
|
|
{
|
|
if (item.content.Tag == "i" && item.content.IsAccept == AcceptStatus.Default)
|
|
{
|
|
item.mark.Text = "";
|
|
}
|
|
item.ResetMarkStyle();
|
|
}
|
|
}
|
|
DocumentUtil.ClearProofreadMarks();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.Log("ClearAllProofreadMark", ex);
|
|
}
|
|
// 清空marks
|
|
marks.Clear();
|
|
}
|
|
|
|
|
|
public void SelectMarkById(int proofreadId)
|
|
{
|
|
SelectMarkById(proofreadId, true);
|
|
}
|
|
/// <summary>
|
|
/// 选中标签
|
|
/// </summary>
|
|
/// <param name="proofreadId"></param>
|
|
public void SelectMarkById(int proofreadId, bool noticeToWeb)
|
|
{
|
|
if (proofreadId == selectProofreadId) return;
|
|
// 取消上一个标签移除
|
|
if (selectProofreadId != -1 && marks.ContainsKey(selectProofreadId))
|
|
{
|
|
var m = marks[selectProofreadId];
|
|
if (m != null && CurrentDocument.Bookmarks.Exists(m.Name))
|
|
{
|
|
marks[selectProofreadId].UnSelect();
|
|
}
|
|
else
|
|
{
|
|
marks.Remove(selectProofreadId);
|
|
}
|
|
}
|
|
selectProofreadId = proofreadId;
|
|
|
|
if (proofreadId != -1 && marks.ContainsKey(proofreadId))
|
|
{
|
|
var mark = marks[proofreadId].mark;
|
|
if (mark == null) return;
|
|
// 已经不存在该标签了
|
|
if (mark != null && !CurrentDocument.Bookmarks.Exists(mark.Name))
|
|
{
|
|
marks.Remove(proofreadId);
|
|
return;
|
|
}
|
|
//object lineNum = (int)mark.Range.Information[WdInformation.wdFirstCharacterLineNumber] - 1;
|
|
//object goToLine = WdGoToItem.wdGoToLine;
|
|
//object goNext = WdGoToDirection.wdGoToNext;
|
|
//Globals.ThisAddIn.Application.ActiveWindow.Selection.GoTo(ref goToLine, ref goNext, ref lineNum);
|
|
//
|
|
//object bookmark = WdGoToItem.wdGoToBookmark;
|
|
//object bookmarkName = mark.Name;
|
|
var targetRange = mark.Range;
|
|
// 选中
|
|
targetRange.Select();
|
|
Globals.ThisAddIn.Application.ActiveWindow.ScrollIntoView(targetRange);//.Selection.GoTo(ref bookmark, ref missing, ref missing, ref bookmarkName);
|
|
|
|
//
|
|
//mark.DisableCharacterSpaceGrid = false;
|
|
// 先滚动到可视区域
|
|
//doc.ActiveWindow.ScrollIntoView(mark.Range);
|
|
marks[proofreadId].Select();
|
|
//Globals.ThisAddIn.SendMessageToWeb("select", proofreadId);
|
|
}
|
|
if (noticeToWeb)
|
|
{
|
|
Globals.ThisAddIn.SendMessageToWeb("select-proofread", proofreadId);
|
|
}
|
|
}
|
|
|
|
|
|
public void InitProofread(List<CorrectContext> list)
|
|
{
|
|
hasProofreaded = true;
|
|
int prevOffset = 0;
|
|
|
|
List<int> disabledList = new List<int>();
|
|
List<InsertMarkData> insertMarks = new List<InsertMarkData>();
|
|
foreach (var correct in list)
|
|
{
|
|
if (LogHelper.LoggerForm != null)
|
|
{
|
|
LogHelper.Log(string.Format("correct content:{0}", correct.Insert));
|
|
}
|
|
int currentOffset = correct.SentenceOffset;
|
|
if (correct.CorrectItems != null && correct.CorrectItems.Count > 0)
|
|
{
|
|
prevOffset = 0;
|
|
int index = 0;
|
|
foreach (var item in correct.CorrectItems)
|
|
{
|
|
if (marks.ContainsKey(item.Id)) continue;
|
|
// Logger.Log(string.Format("mark type {0} data {1}->{2}", item.Tag, item.Origin, item.Text));
|
|
int _prev = prevOffset;
|
|
bool isDisabled = false;
|
|
// 判断查找内容是否在原始数据中,否则直跳过
|
|
if (item.Tag != "i" && item.Origin.Trim().Length > 0)
|
|
{
|
|
isDisabled = correct.Insert.IndexOf(item.Origin) == -1;
|
|
}
|
|
// 查找对应区域并再该区域添加书签
|
|
var mark = isDisabled ? null : DocumentUtil.FindRangeAndCreateBookmark(item, correct, CurrentDocument, ref prevOffset);
|
|
// 防止调用方法中没有更新
|
|
if (_prev >= prevOffset)
|
|
{
|
|
prevOffset = currentOffset + item.Start;
|
|
}
|
|
|
|
if (item.Tag != "i") index++;
|
|
if (mark != null)
|
|
{
|
|
marks.Add(item.Id, new ProofreadItem(item, correct.Insert, mark, Id));
|
|
try
|
|
{
|
|
if (item.Tag == "i")
|
|
{
|
|
insertMarks.Add(new InsertMarkData()
|
|
{
|
|
Mark = mark,
|
|
InsertLength = item.Text.Length
|
|
});
|
|
}
|
|
else
|
|
{
|
|
SetMarkStyle(mark);
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
LogHelper.Log(string.Format("mark color error {0}", e.Message));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
disabledList.Add(item.Id);
|
|
var msg = new Dictionary<string, object>{
|
|
{"message","没有找到标记对象" },
|
|
{ "origin",item },
|
|
{ "origin_correct",correct },
|
|
{ "new_text",correct.NewText },
|
|
{ "paragraph_num",correct.ParagraphNumber },
|
|
};
|
|
LogHelper.Log(JsonConvert.SerializeObject(msg));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 为了避免影响其他文本定位,操作完成后才使用空格填充
|
|
try
|
|
{
|
|
foreach (var item in insertMarks)
|
|
{
|
|
item.Mark.Text = ToolUtil.GetBlankText(item.InsertLength);
|
|
SetMarkStyle(item.Mark);
|
|
}
|
|
}
|
|
catch (Exception) { }
|
|
insertMarks.Clear();
|
|
//foreach (var item in marks)
|
|
//{
|
|
// if (item.Value.mark != null)
|
|
// {
|
|
// if (item.Value.content.Tag == "i")
|
|
// {
|
|
// item.Value.mark.Text = ToolUtil.GetBlankText(item.Value.content.Text.Length);
|
|
// }
|
|
// if (item.Value.content.Color != null)
|
|
// {
|
|
// try
|
|
// {
|
|
// var color = (WdColor)ColorTranslator.ToOle(Colors.FromHex(item.Value.content.Color));
|
|
// // 给选区添加背景颜色
|
|
// item.Value.mark.Shading.BackgroundPatternColor = color;
|
|
// }
|
|
// catch (Exception)
|
|
// {
|
|
// //item.Value.mark.Shading.BackgroundPatternColor = WdColor.wdColorLightOrange;
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
// 隐藏面板对应校对项
|
|
MainPanelWebMessage.DisabledProofreadItem(disabledList);
|
|
}
|
|
|
|
private void SetMarkStyle(Microsoft.Office.Tools.Word.Bookmark mark)
|
|
{
|
|
// 颜色转码
|
|
var color = (WdColor)ColorTranslator.ToOle(Colors.FromHex(Config.TextBackgroundColor));
|
|
// 给选区添加背景颜色
|
|
mark.Shading.BackgroundPatternColor = color;
|
|
}
|
|
|
|
|
|
public void InitProofreadCache(List<CorrectContext> list, Dictionary<int, ProofreadRangeInfo> itemInfoDic)
|
|
{
|
|
marks.Clear();
|
|
|
|
foreach (var correct in list)
|
|
{
|
|
correct.CorrectItems.ForEach(item =>
|
|
{
|
|
var mark = DocumentUtil.FindBookMarkByCorrect(item);
|
|
if (mark != null)
|
|
{
|
|
var pi = new ProofreadItem(item, correct.Insert, mark, Id);
|
|
// 是否存在样式信息
|
|
if (itemInfoDic != null && itemInfoDic.ContainsKey(item.Id))
|
|
{
|
|
// 获取样式信息并还原
|
|
var info = itemInfoDic[item.Id];
|
|
try
|
|
{
|
|
pi.originColor = info.Color;
|
|
pi.originBackgroundColor = info.Background;
|
|
pi.originSize = info.Size;
|
|
}
|
|
catch (Exception ex) { LogHelper.Log(ex); }
|
|
}
|
|
marks.Add(item.Id, pi);
|
|
}
|
|
});
|
|
//marks.Add(item.Id, new ProofreadItem(item.CorrectItems[0], null, Id));
|
|
}
|
|
}
|
|
|
|
private void FindMarkByCorrectItem()
|
|
{
|
|
|
|
}
|
|
|
|
public DocumentContent GetAllParagraphs()
|
|
{
|
|
string rangeText = CurrentDocument.Content.Text;
|
|
string trimText = HostHelper.ReplaceSpecialChars(rangeText, isReplaceMultSpaceLine: true);
|
|
|
|
string[] separator = new string[5] { "\r\a", "\a", "\r", "\v", "\f" };
|
|
string[] array4 = rangeText.Split(separator, StringSplitOptions.None);
|
|
string[] array5 = trimText.Split('\n');
|
|
|
|
List<string> list = new List<string>();
|
|
var paragraphs = CurrentDocument.Paragraphs;
|
|
int total = paragraphs.Count;
|
|
for (int i = 1; i <= total; i++)
|
|
{
|
|
list.Add(GetParagraphText(paragraphs[i]));
|
|
}
|
|
|
|
return new DocumentContent()
|
|
{
|
|
OriginCut = array4,
|
|
TrimCut = array5,
|
|
Paragraphs = list.ToArray(),
|
|
};
|
|
}
|
|
|
|
private string GetParagraphText(Paragraph paragraph)
|
|
{
|
|
// 需要
|
|
return GetRangeText(paragraph.Range);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取文档段落总数
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public int GetTotalParagraphNumber()
|
|
{
|
|
return CurrentDocument.Paragraphs.Count;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 读取文档原始文件并转换成base64
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string GetOriginFileData()
|
|
{
|
|
FileStream fs = new FileStream(CurrentDocument.FullName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
|
byte[] bytes = new byte[fs.Length];
|
|
fs.Read(bytes, 0, bytes.Length);
|
|
return Convert.ToBase64String(bytes);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 采纳校对项
|
|
/// </summary>
|
|
/// <param name="proofreadId"></param>
|
|
/// <param name="status"></param>
|
|
internal void ProcessMark(int proofreadId, int status)
|
|
{
|
|
// 是否存在书签
|
|
if (proofreadId > 0 && marks.ContainsKey(proofreadId))
|
|
{
|
|
hasProcessMark = true;
|
|
// 采纳
|
|
marks[proofreadId].Process(status);
|
|
}
|
|
else
|
|
{
|
|
Logger.Debug("不存在此校对项");
|
|
}
|
|
}
|
|
|
|
internal bool Saved()
|
|
{
|
|
if (CurrentDocument.Saved)
|
|
{
|
|
return true;
|
|
}
|
|
if (!hasProofreaded && !CurrentDocument.Saved) // 没有校对前需要提示保存
|
|
{
|
|
return false;
|
|
}
|
|
if (hasProofreaded && hasProcessMark && !CurrentDocument.Saved)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void Save()
|
|
{
|
|
try
|
|
{
|
|
CurrentDocument.Save();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.Log(ex);
|
|
}
|
|
}
|
|
public void FocusToPanel()
|
|
{
|
|
TaskPane.Visible = true;
|
|
TaskPane.Control.Focus();
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
try
|
|
{
|
|
// 清除标记内存数据
|
|
marks.Clear();
|
|
// 清除区域相关数据
|
|
ranges.Clear();
|
|
// TaskPane.Dispose();
|
|
this.Dispose();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogHelper.Log(ex);
|
|
}
|
|
}
|
|
|
|
public void ExportResult(string modelType)
|
|
{
|
|
TaskPane.Control.BeginInvoke(new Action(() =>
|
|
{
|
|
DocumentUtil.ExportProofreadResult(modelType);
|
|
}));
|
|
}
|
|
|
|
public void ShowUpgrade(string data, bool force)
|
|
{
|
|
TaskPane.Control.BeginInvoke(new Action(() =>
|
|
{
|
|
var upgradeData = JsonConvert.DeserializeObject<UpgradeData>(data);
|
|
var needUpgrade = upgradeData.NeedUpgrade(Config.APP_VERSION);
|
|
//force = force && !Config.UpgradeForcedNotice;
|
|
|
|
if (force)
|
|
{
|
|
// 已经强制更新但被忽略过则不再提示
|
|
if (Config.UpgradeForcedNotice) return;
|
|
|
|
var result = MessageBox.Show(upgradeData.Message, "是否确认更新", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question);
|
|
if (result == DialogResult.No)
|
|
{
|
|
Config.UpgradeForcedNotice = true;
|
|
Globals.ThisAddIn.ribbon.SetBtnStatus("disable-by-upgrade", false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (upgradeData.Ext == 1)
|
|
{
|
|
if (!needUpgrade)
|
|
{
|
|
ShowDialog("当前版本为最新版本,无需升级", "", "");
|
|
}
|
|
else
|
|
{
|
|
if (!force)
|
|
{
|
|
// 非强制则再问一次
|
|
var ret = MessageBox.Show(upgradeData.Message, "是否确认更新", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question);
|
|
if (ret == DialogResult.No)
|
|
{
|
|
Globals.ThisAddIn.ribbon.SetBtnStatus("disable-by-upgrade", false);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Bridge.bridge.OpenUrlWithOsBrowser(upgradeData.DownloadUrl);
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Bridge.StartUpgradeProcess();
|
|
}
|
|
}));
|
|
}
|
|
|
|
public void ShowSetting()
|
|
{
|
|
|
|
TaskPane.Control.BeginInvoke(new Action(() =>
|
|
{
|
|
FormSetting frm = new FormSetting();
|
|
frm.Show();
|
|
}));
|
|
}
|
|
public void ShowWebView(string url, int width, int height, bool dialog)
|
|
{
|
|
TaskPane.Control.BeginInvoke(new Action(() =>
|
|
{
|
|
FormWebView view = new FormWebView(url, width, height);
|
|
if (dialog)
|
|
{
|
|
view.StartPosition = FormStartPosition.CenterScreen;
|
|
view.ShowDialog();
|
|
}
|
|
else
|
|
{
|
|
view.StartPosition = FormStartPosition.CenterParent;
|
|
view.Show();
|
|
}
|
|
}));
|
|
}
|
|
|
|
public Dictionary<int, ProofreadRangeInfo> GetProofreadOriginData()
|
|
{
|
|
Dictionary<int, ProofreadRangeInfo> dic = new Dictionary<int, ProofreadRangeInfo>();
|
|
// 变量文档所有marks 记录mark对应range的背景、大小、颜色
|
|
foreach (var item in marks)
|
|
{
|
|
if (item.Value.mark != null)
|
|
{
|
|
// 添加到数据
|
|
dic.Add(item.Key, new ProofreadRangeInfo()
|
|
{
|
|
Background = item.Value.originBackgroundColor,
|
|
Color = item.Value.originColor,
|
|
Size = item.Value.originSize
|
|
});
|
|
}
|
|
}
|
|
return dic;
|
|
}
|
|
|
|
public void CheckPanel()
|
|
{
|
|
LogHelper.Log(CurrentDocument.FullName + $" TaskPane visible {PaneVisible} has " + (TaskPane == null ? "null" : "exists"));
|
|
if (TaskPane == null) CreateTaskPane();
|
|
}
|
|
}
|
|
}
|