565 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AIProofread.Controls;
using Microsoft.Office.Interop.Word;
using Microsoft.Office.Tools.Word;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml.Linq;
using UtilLib;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Header;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock;
using Document = Microsoft.Office.Interop.Word.Document;
namespace AIProofread
{
public enum BridgeEvent
{
LoginSuccess,
WindowClose
}
public delegate void BridgeEventHandler(object sender, EventArgs e);
[ClassInterface(ClassInterfaceType.AutoDual)]
[ComVisible(true)]
public class Bridge
{
public static Bridge bridge = new Bridge();
private static readonly Dictionary<string, WebView2> webViewDict = new Dictionary<string, WebView2>();
private static readonly Dictionary<BridgeEvent, List<BridgeEventHandler>> eventHandlers = new Dictionary<BridgeEvent, List<BridgeEventHandler>>();
public static Dictionary<int, ProofreadItem> marks;
private static int selectProofreadId = -1;
private static object missing = System.Reflection.Missing.Value;
public string GetAppVersion()
{
return Config.APP_VERSION;
}
public void showDialog(string message)
{
System.Windows.Forms.MessageBox.Show(message);
}
public int getMinWIdth()
{
return Globals.ThisAddIn.GetMinWidth();
}
/// <summary>
/// 添加事件
/// </summary>
/// <param name="eventName"></param>
/// <param name="handler"></param>
public static void AddEventHandler(BridgeEvent eventName, BridgeEventHandler handler)
{
if (!eventHandlers.ContainsKey(eventName))
{
eventHandlers.Add(eventName, new List<BridgeEventHandler>());
}
eventHandlers[eventName].Add(handler);
}
public static void RemoveEventHandler(BridgeEvent eventName, BridgeEventHandler handler)
{
if (eventHandlers.ContainsKey(eventName))
{
eventHandlers[eventName].Remove(handler);
}
}
// 打开网页
public void OpenUrlWithOsBrowser(string url)
{
try
{
Process.Start(url);
}
catch
{
showDialog("打开网页失败");
}
}
public void StartProofread()
{
Globals.ThisAddIn.SendMessageToWeb("start", "login");
}
public void ShowCurrentPane()
{
Globals.ThisAddIn.currentDocumentTaskPane.Visible = true;
}
public void HideCurrentPane()
{
Globals.ThisAddIn.currentDocumentTaskPane.Visible = false;
}
public void Logout(string action)
{
if (action == "async-info")
{
// web同步注销到ribbon
Globals.ThisAddIn.SyncLogout();
}
else
{
// ribbon 发送注销动作到 web
Globals.ThisAddIn.SendMessageToWeb("logout", null);
}
}
/// <summary>
/// 登录成功后通知后端
/// </summary>
public void loginSuccess(string userinfo)
{
if (userinfo == null || userinfo.Length == 0) return;
//
Userinfo info = JsonConvert.DeserializeObject<Userinfo>(userinfo);
// 登录成功 展示
Globals.ThisAddIn.ribbon.ProcessLoginInfo(info);
//Globals.ThisAddIn.SendMessageToWeb("async-login-success", null);
}
// 获取文档所有文本数据
public Dictionary<string, object> getAllText()
{
return Tools.GetAllText();
}
public string getDocumentData()
{
Dictionary<string, object> data = new Dictionary<string, object>();
var name = Globals.ThisAddIn.Application.ActiveDocument.Name;
data.Add("name", name);
data.Add("fullName", Globals.ThisAddIn.Application.ActiveDocument.FullName);
data.Add("content", Tools.GetAllText());
return Tools.GetJSONString(data);
}
public void ShowUpgrade(string data)
{
var upgradeData = JsonConvert.DeserializeObject<UpgradeData>(data);
var ret = System.Windows.Forms.MessageBox.Show(upgradeData.Message, "更新提示", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question);
if (ret == System.Windows.Forms.DialogResult.Yes)
{
OpenUrlWithOsBrowser(upgradeData.DownloadUrl);
}
}
public void noticeOtherWeb(string json, string targetWebName)
{
if (targetWebName != null)
{
if (webViewDict.ContainsKey(targetWebName))
{
SendMessageToWeb(webViewDict[targetWebName], json);
}
}
else
{
// 如果没有指定 则向所有 webview 发送消息
foreach (var item in webViewDict)
{
SendMessageToWeb(item.Value, json);
}
}
}
private void SendMessageToWeb(WebView2 webView, string json)
{
webView.CoreWebView2.PostWebMessageAsJson(json);
}
public async static void InitWebEnvAsync(string name, WebView2 webView)
{
webView.Name = name;
if (webViewDict.ContainsKey(webView.Name))
{
webViewDict[name] = webView;
}
else
{
webViewDict.Add(name, webView);
}
// 禁用web安全允许跨域 否则需要web编译为umd加载模式
var ops = new CoreWebView2EnvironmentOptions("--disable-web-security");
var env = await CoreWebView2Environment.CreateAsync(null, Config.WEB_DATA_PATH, ops);
await webView.EnsureCoreWebView2Async(env);
//webView.CoreWebView2.Settings.AreDevToolsEnabled = false;
//webView.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
//webView.CoreWebView2.Settings.AreHostObjectsAllowed = true;
// 添加 js与客户端代理
webView.CoreWebView2.AddHostObjectToScript("bridge", bridge);
}
// 清除所有标记
public void clearAllProofreadMark()
{
// 设置当前文档数据
Globals.ThisAddIn.ActiveCurrentDocumentMarks();
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();
}
}
marks.Clear();
DocumentUtil.ClearProofreadMarks();
}catch (Exception ex)
{
Logger.Log("ClearAllProofreadMark",ex);
}
}
public void removeBookmark(string markId)
{
DocumentUtil.RemoveBookmark(markId);
}
public void addBookmark(string data)
{
var item = JsonConvert.DeserializeObject<CorrectedContent>(data);
//var mark = DocumentUtil.AddBookmark(item.color, item.start, item.end);
// 初始化校对对象
marks.Add(item.id, new ProofreadItem(item));
}
public string getAllBookmark()
{
return ToJSON(DocumentUtil.GetAllBookmark());
}
public string getSectionText()
{
return ToJSON(DocumentUtil.GetSectionText());
}
private static string ToJSON(object data)
{
return JsonConvert.SerializeObject(data);
}
public string GetCheckText()
{
var document = Globals.ThisAddIn.Application.ActiveDocument;
int count = Globals.ThisAddIn.Application.ActiveDocument.Paragraphs.Count;
if (count > 10000)
{
return document.Content.Text;
}
string text = "";
for (int i = 0; i < count; i++)
{
string input = document.Paragraphs[i + 1].Range.Text.Replace("\f\r", "");
string pattern = "[\\r\\f\\n]";
string replacement = "\t";
string text2 = Regex.Replace(input, pattern, replacement);
if (text2.EndsWith("\t"))
{
text2 = text2.Substring(0, text2.Length - 1);
}
text2 += "\r";
text += text2;
}
return text;
}
public string GetSelectedText()
{
// 文档对象
var document = Globals.ThisAddIn.Application.ActiveDocument;
var vstoDocument = Globals.Factory.GetVstoObject(document);
// 获取选区
var selection = Globals.ThisAddIn.Application.Selection;
// 段落数
int count = selection.Paragraphs.Count;
if (count > 10000)
{
return selection.Text;
}
string text = "";
if (count == 1)
{
string input = selection.Text.Replace("\f\r", "");
string pattern = "[\\r\\f\\n]";
string replacement = "\t";
string text2 = Regex.Replace(input, pattern, replacement);
return text + text2;
}
for (int i = 0; i < count; i++)
{
string input;
if (i == 0)
{
int start = selection.Range.Start;
int end = selection.Paragraphs[i + 1].Range.End;
Document obj = document;
object Start = start;
object End = end;
input = obj.Range(ref Start, ref End).Text;
}
else if (i == count - 1)
{
int start2 = selection.Paragraphs[i + 1].Range.Start;
int end2 = selection.Range.End;
Document obj2 = document;
object End = start2;
object Start = end2;
input = obj2.Range(ref End, ref Start).Text;
}
else
{
input = selection.Paragraphs[i + 1].Range.Text;
}
input = input.Replace("\f\r", "");
string pattern2 = "[\\r\\f\\n]";
string replacement2 = "\t";
string text3 = Regex.Replace(input, pattern2, replacement2);
if (text3.EndsWith("\t"))
{
text3 = text3.Substring(0, text3.Length - 1);
}
text3 += "\r";
text += text3;
}
return text;
}
public void ShowLoginForm(string action)
{
Globals.ThisAddIn.ShowLoginForm(action);
}
public void ShowSettingForm()
{
FormSetting frm = new FormSetting();
frm.Show();
}
public void MoveCursor(int pos)
{
var rng = Globals.ThisAddIn.Application.ActiveDocument.Range(pos, pos);
rng.Select();
}
public void SelectMarkById(int proofreadId)
{
// 设置当前文档数据
Globals.ThisAddIn.ActiveCurrentDocumentMarks();
if (proofreadId == selectProofreadId) return;
var doc = Globals.ThisAddIn.Application.ActiveDocument;
// 取消上一个标签移除
if (selectProofreadId > 0 && marks.ContainsKey(selectProofreadId))
{
var m = marks[selectProofreadId];
if (doc.Bookmarks.Exists(m.Name))
{
marks[selectProofreadId].UnSelect();
}
else
{
marks.Remove(selectProofreadId);
}
}
selectProofreadId = proofreadId;
if (proofreadId > 0 && marks.ContainsKey(proofreadId))
{
var mark = marks[proofreadId].mark;
// 已经不存在该标签了
if (!doc.Bookmarks.Exists(mark.Name))
{
marks.Remove(selectProofreadId);
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;
//doc.GoTo(mark);
//mark.Range.GoTo();
Globals.ThisAddIn.Application.ActiveWindow.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);
}
Globals.ThisAddIn.SendMessageToWeb("select_proofread", proofreadId);
}
public void processMark(int proofreadId, int status)
{
if (proofreadId > 0 && marks.ContainsKey(proofreadId))
{
marks[proofreadId].Process(status);
}
}
public void InitContent(string content)
{
List<DocumentCorrectItem> list = JsonConvert.DeserializeObject<List<DocumentCorrectItem>>(content);
// 先清除所有数据
clearAllProofreadMark();
//var app = Globals.ThisAddIn.Application;
//var cur = app.Selection;
//
foreach (var correct in list)
{
//cur.TypeText(correct.Insert);
//var rng = cur.Range;
if (correct.Diffs != null && correct.Diffs.Count > 0)
{
//var diffs = correct.Diffs.OrderBy(it =>
//{
// if (it.tag != "i") return it.start;
// return it.start + correct.Insert_len;
//}).ToList();
int index = 0;
foreach (var item in correct.Diffs)
{
var mark = AddBookmark(item, index, correct.Sentence_offset, correct.Insert_len, correct.Paragraph_offset);
if (item.tag != "i") index++;
if (mark != null) {
marks.Add(item.id, new ProofreadItem(item, mark));
}
}
}
}
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)
{
// 给选区添加背景颜色
item.Value.mark.Shading.BackgroundPatternColor = (WdColor)ColorTranslator.ToOle(Colors.FromHex(item.Value.content.color));
}
}
}
}
public string GetParagraph(int index)
{
var document = Globals.ThisAddIn.Application.ActiveDocument;
try
{
var paragraphs = document.Paragraphs;
var total = paragraphs.Count;
// 判断索引是否超出范围
if (index > total)
{
return null;
}
var paragraph = document.Paragraphs[index];
return paragraph.Range.Text;
}
catch (Exception ex)
{
return "error:" + ex.Message;
}
}
public Microsoft.Office.Tools.Word.Bookmark AddBookmark(CorrectedContent item, int findIndex, int offset, int length,int paragraphIndex)
{
Microsoft.Office.Tools.Word.Bookmark bookmark = null;
try
{
var document = Globals.ThisAddIn.Application.ActiveDocument;
ControlCollection controls = Globals.Factory.GetVstoObject(document).Controls;
// 判断并获取当前段落
if (paragraphIndex > document.Paragraphs.Count) return null;
var paragraph = document.Paragraphs[paragraphIndex];
var paragraphStart = paragraph.Range.Start;
var Start = paragraphStart + offset;
var End = Start + length - 1;
if(End > paragraph.Range.End)
{
End = paragraph.Range.End;
}
// 当前句子的选区
var fullRange = document.Range(Start, End);
string fullText = fullRange.Text;
Start = paragraphStart + offset + item.start;
End = paragraphStart + offset + item.end;
// 定位要操作的文字
var r = document.Range(Start, End);
var markName = Config.BuildBookmarkName(item.id);
// 判断是否已经存在
if (controls.Contains(markName))
{
controls.Remove(markName);
}
// 判断选区是否正确
if (item.tag == "i" || r.Text == item.origin)
{
bookmark = controls.AddBookmark(r, markName);
bookmark.Tag = "ai_proofread";
}
else
{
int startPos = 0, index, findCount = 0;
while ((index = fullText.IndexOf(item.origin, startPos)) != -1)
{
if (findCount == findIndex)
{
r = document.Range(offset + index, offset + index + item.origin.Length);
bookmark = controls.AddBookmark(r, markName);
bookmark.Tag = "ai_proofread";
break;
}
startPos = index;
findCount++;
}
}
}
catch (Exception ex)
{
Logger.Log("create mark error:" + ex.Message + "\n" + ex.StackTrace + "\n\n");
}
return bookmark;
}
}
}