完善range

This commit is contained in:
csh
2023-12-20 09:06:40 +08:00
parent f0560b2330
commit b9e419541b
29 changed files with 1553 additions and 494 deletions
-229
View File
@@ -1,229 +0,0 @@
Type TSWdCommon = Class
Class Function AddRun(rootNode, parentNode, runNode, tParagraph, pStart, pEnd, pTotal, arr);
Begin
run_obj := TOfficeObj("TRun");
run_obj.Init(runNode);
text := ifObj(runNode) ? run_obj.Text() : "";
len := text ? length(text) : 1;
if pTotal + len > pStart then
begin
length := length(arr);
arr[length]["tparagraph"] := tparagraph;
arr[length]["trun"] := run_obj;
arr[length]["text"] := text;
arr[length]["root"] := rootNode;
arr[length]["parent"] := parentNode;
// 左边切割
if pTotal < pstart and pTotal + len > pStart + 1 then
arr[length]["lsplit"] := pStart - pTotal; // 左边丢弃的字符数
// 右边切割
if pTotal + len > pEnd then
arr[length]["rsplit"] := pTotal + len - pEnd; // 右边丢弃的字符数
end
return len;
End;
Class Function SplitRange(root, startNode, pStart, pEnd, pTotal, arr);
Begin
node := startNode.FirstChildElement();
while ifObj(node) do
begin
case node.GetName() of
"w:p":
begin
paragraph_obj := TOfficeObj("TParagraph");
paragraph_obj.Init(node);
if paragraph_obj.Empty() then
begin
AddRun(root, startNode, nil, paragraph_obj, pStart, pEnd, pTotal, arr);
end
else begin
paragraph_len := length(arr); // 标记段落完整的起始位置
sub_node := node.FirstChildElement();
while ifObj(sub_node) do
begin
case sub_node.GetName() of
"w:r":
begin
pTotal += AddRun(root, startNode, sub_node, paragraph_obj, pStart, pEnd, pTotal, arr);
if pTotal >= pEnd then return 1;
end
"w:ins", "w:del":
begin
run_node := sub_node.FirstChildElement("w:r");
while ifObj(run_node) do
begin
AddRun(paragraph_obj, root, run_node, pStart, pEnd, pTotal, arr);
run_node := run_node.NextElement("w:r");
end
end
end;
sub_node := sub_node.NextElement();
end
for i:=paragraph_len to length(arr)-1 do
arr[i]["entirety"] := node;
end
pTotal += 1;
if pTotal >= pEnd then return 1;
end
"w:tbl":
begin
table_len := length(arr);
tr := node.FirstChildElement("w:tr");
while ifObj(tr) do
begin
tc := tr.FirstChildElement("w:tc");
while ifObj(tc) do
begin
cell_len := length(arr);
flag := SplitRange(root, tc, pStart, pEnd, pTotal, arr);
if flag then return 1;
tc := tc.NextElement("w:tc");
if pTotal >= pEnd then return 1;
for i:=cell_len to length(arr)-1 do
arr[i]["entirety"] := node;
end
tr := tr.NextElement("w:tr");
pTotal += 1;
if pTotal >= pEnd then return 1;
end
for i:=table_len to length(arr)-1 do
arr[i]["entirety"] := node;
end
end;
node := node.NextElement();
end
End;
Class Function AddRange(root, startNode, findNode, tParagraph, runNode, arr);
Begin
run_obj := TOfficeObj("TRun");
run_obj.Init(runNode);
length := length(arr);
arr[length]["tparagraph"] := tParagraph;
arr[length]["trun"] := run_obj;
arr[length]["root"] := root;
arr[length]["parent"] := startNode;
arr[length]["entirety"] := findNode;
text := ifObj(runNode) ? run_obj.Text() : "";
return text ? length(text) : 1;
End;
Class Function ParagraphRange(root, startNode, findNode, node, pend, arr);
Begin
paragraph_obj := TOfficeObj("TParagraph");
paragraph_obj.Init(node);
if paragraph_obj.Empty() then
begin
AddRange(root, startNode, findNode, paragraph_obj, nil, arr);
end
else begin
sub_node := node.FirstChildElement();
while ifObj(sub_node) do
begin
case sub_node.GetName() of
"w:r": pend += AddRange(root, startNode, findNode, paragraph_obj, sub_node, arr);
"w:ins", "w:del":
begin
run_node := sub_node.FirstChildElement("w:r");
while ifObj(run_node) do
begin
pend += AddRange(root, findNode, paragraph_obj, run_node, arr);
run_node := run_node.NextElement("w:r");
end
end
end;
sub_node := sub_node.NextElement();
end
end
pend += 1;
End;
Class Function CalculateRange(root, startNode, findNode, findFlag, pbegin, pend, arr);
Begin
if findFlag then arr := array();
node := startNode.FirstChildElement();
while ifObj(node) do
begin
if node.Eq(findNode) then
begin
find_flag2 := true;
arr := array();
end
case node.GetName() of
"w:p": ParagraphRange(root, startNode, findNode, node, pend, arr);
"w:tbl":
begin
tr := node.FirstChildElement("w:tr");
while ifObj(tr) do
begin
tc := tr.FirstChildElement("w:tc");
while ifObj(tc) do
begin
tc_node := tc;
new_flag := tc_node.Eq(findNode);
if new_flag then temp := pbegin; // 把pbegin存起来,防止递归覆盖
flag := CalculateRange(root, tc_node, findNode, new_flag, pbegin, pend, arr);
if new_flag then pbegin := temp;
if flag then return 1;
tc := tc.NextElement("w:tc");
end
tr := tr.NextElement("w:tr");
pend += 1;
end
end
end;
if find_flag2 then return 1;
if not flag then pbegin := pend;
node := node.NextElement();
end
if findFlag then return 1;
End;
Class Function SplitRangeRun(rangeArr);overload;
Begin
for i:=0 to length(rangeArr)-1 do
rangeArr[i] := SplitSingleRangeRun(rangeArr[i]);
End;
Class Function SplitSingleRangeRun(arr);overload;
Begin
insert_run := function(root, node);
begin
new_node := root.InsertAfterChild(node, "element", "w:r");
run := TOfficeObj("TRun");
run.Init(new_node);
return run;
end
paragraph := arr["tparagraph"];
run := arr["trun"];
text := arr["text"];
if arr["lsplit"] then // 分割左边
begin
lpos := arr["lsplit"];
run.SetText(text[:lpos]);
run := ##insert_run(paragraph.Root(), run.Root());
text := text[lpos + 1:];
run.SetText(text);
arr["text"] := text;
arr["lsplit"] := nil;
end
if arr["rsplit"] then // 分割右边的run
begin
rpos := length(text) - arr["rsplit"];
run.SetText(text[1:rpos]);
new_run := ##insert_run(paragraph.Root(), run.Root());
new_run.SetText(text[rpos+1:]);
arr["rsplit"] := nil;
arr["text"] := text[1:rpos];
end
arr["trun"] := run;
return arr;
End;
End;
+183 -108
View File
@@ -1,36 +1,43 @@
Type TSWdRange = Class
public
Function Create(rootNode, startP, endP);overload;
Function Create(rootNode, targetNode);overload;
Function Init();
Function Operator[](index);
Function Run();
Function Refresh();
Function GetStart();
Function GetEnd();
Function SplitRun();overload;
Function SplitRun(arr);overload;
Function Clear();
Function Print();
Function SplitRun(index);overload;
Function Clear(deleteAll);
Function Size();
Function Root();
public
Data; // 管理range结构的数组,字段如下
// lsplit: 左边丢弃的字符数
// rsplit: 右边丢弃的字符数
// tparagraph: TOfficeObj("TParagraph")对象
// trun: TOfficeObj("TRun")对象
// text: 文本内容
// root: 根节点
// parent: 父节点
// entirety: 是否是完整的段落/表格/单元格
Function Print();
Begin
println("data = {}", data_);
End;
private
Function FindRangeByPosition(startNode);
Function FindRangeByNode(startNode);
Function AddEntirety(len, node);
Function AddRunInfo(parentNode, runNode, tParagraph);
Function AddRunInfo2(parentNode, runNode, tParagraph);
Function AddRunInfo(runNode, tParagraph);
Function AddRunInfo2(runNode, tParagraph);
Function ParagraphRange(node);
public
data_; // 管理range结构的数组,字段如下
// lsplit: 左边丢弃的字符数
// rsplit: 右边丢弃的字符数
// tparagraph: TOfficeObj("TParagraph")对象
// trun: TOfficeObj("TRun")对象
// text: 文本内容
// entirety: 是否是完整的段落/表格/单元格
// -- 以便在对range操作时候知道操作一个段落还是一个run,比如range.shading range.Border
private
start_position_; // 开始位置
end_position_; // 结束位置, 开始与结束遵循左闭右开原则
@@ -39,15 +46,69 @@ private
target_node_; // 目标节点,使用paragraph.Rangetable.Range, cell.Range时用
split_flag_; // 切割标志
proxy_; // 代理类,提供外部对数组data_的读写
End;
Type Proxy = Class
public
Function Create(obj);
property TRun read ReadTRun write WriteTRun;
property TParagraph read ReadTParagraph write WriteTParagraph;
property Entirety read ReadEntirety write WriteEntirety;
Function WriteEntirety(value);
Function ReadEntirety();
Function WriteTParagraph(value);
Function ReadTParagraph();
Function WriteTRun(value);
Function ReadTRun();
[weakref]obj_;
index_;
End;
Function Proxy.Create(obj);
Begin
obj_ := obj;
index_ := nil;
End;
Function Proxy.WriteEntirety(value);
Begin
obj_.data_[index_]["entirety"] := value;
End;
Function Proxy.ReadEntirety();
Begin
return obj_.data_[index_]["entirety"];
End;
Function Proxy.WriteTParagraph(value);
Begin
obj_.data_[index_]["tparagraph"] := value;
End;
Function Proxy.ReadTParagraph();
Begin
return obj_.data_[index_]["tparagraph"];
End;
Function Proxy.WriteTRun(value);
Begin
obj_.data_[index_]["trun"] := value;
End;
Function Proxy.ReadTRun();
Begin
return obj_.data_[index_]["trun"];
End;
// TSWdRange实现
Function TSWdRange.Create(rootNode, startP, endP);overload;
Begin
root_node_ := rootNode;
start_position_ := startP;
end_position_ := endP;
targetNode := nil;
Init();
target_node_ := nil;
self.Init();
End;
Function TSWdRange.Create(rootNode, targetNode);overload;
@@ -56,28 +117,46 @@ Begin
target_node_ := targetNode;
start_position_ := nil;
end_position_ := nil;
Init();
self.Init();
End;
Function TSWdRange.Init();
Begin
cur_position_ := 0;
split_flag_ := false;
Data := array();
Run();
data_ := array();
self.Run();
proxy_ := new Proxy(self);
End;
Function Operator TSWdRange.[](index);
Begin
proxy_.index_ := index;
return proxy_;
End;
Function TSWdRange.Run();
Begin
if target_node_ then
FindRangeByNode(target_node_);
self.FindRangeByNode(target_node_);
else
FindRangeByPosition(root_node_);
self.FindRangeByPosition(root_node_);
End;
Function TSWdRange.Print();
Function TSWdRange.Refresh();
Begin
println("print... {}", Data);
if target_node_ then self.FindRangeByNode(target_node_);
End;
Function TSWdRange.Size();
Begin
return length(data_);
End;
Function TSWdRange.Root();
Begin
node := root_node_;
return node;
End;
Function TSWdRange.GetStart();
@@ -95,44 +174,65 @@ End;
Function TSWdRange.SplitRun();overload;
Begin
if split_flag_ then return;
for i:=0 to length(Data)-1 do
Data[i] := SplitRun(Data[i]);
for i:=0 to length(data_)-1 do
self.SplitRun(i);
split_flag_ := true;
End;
Function TSWdRange.SplitRun(arr);overload;
Function TSWdRange.SplitRun(index);overload;
Begin
insert_run := function(root, node);
if ifnil(data_[index]["lsplit"]) and ifnil(data_[index]["rsplit"]) then return data_[index];
paragraph := data_[index]["tparagraph"];
run := data_[index]["trun"];
text := data_[index]["text"];
if data_[index]["lsplit"] then // 分割左边
begin
new_node := root.InsertAfterChild(node, "element", "w:r");
run := TOfficeObj("TRun");
run.Init(new_node);
return run;
lpos := data_[index]["lsplit"];
run.SetText(AnsiToUtf8(leftstr(text, lpos)));
new_run := paragraph.AppendRun(run);
new_run.CopyFontFormat(run);
text := rightstr(text, lengthw(text)-lpos);
new_run.SetText(AnsiToUtf8(text));
data_[index]["text"] := text;
data_[index]["lsplit"] := nil;
run := new_run;
end
if ifnil(arr["lsplit"]) and ifnil(arr["rsplit"]) then return arr;
paragraph := arr["tparagraph"];
run := arr["trun"];
text := arr["text"];
if arr["lsplit"] then // 分割左边
if data_[index]["rsplit"] then // 分割右边的run
begin
lpos := arr["lsplit"];
run.SetText(text[:lpos]);
run := ##insert_run(paragraph.Root(), run.Root());
text := text[lpos + 1:];
run.SetText(text);
arr["text"] := text;
arr["lsplit"] := nil;
rpos := data_[index]["rsplit"];
new_run := paragraph.AppendRun(run);
new_run.CopyFontFormat(run);
new_run.SetText(AnsiToUtf8(rightstr(text, rpos)));
new_text := AnsiToUtf8(leftstr(text, lengthw(text) - rpos));
run.SetText(new_text);
data_[index]["rsplit"] := nil;
data_[index]["text"] := new_text;
end
if arr["rsplit"] then // 分割右边的run
data_[index]["trun"] := run;
End;
Function TSWdRange.Clear(deleteAll);
Begin
self.SplitRun();
arr := array();
first := data_[0];
para := first["tparagraph"];
if deleteAll then arr[length(arr)] := para.Root();
for i:=1 to length(data_)-1 do
begin
rpos := length(text) - arr["rsplit"];
run.SetText(text[1:rpos]);
new_run := ##insert_run(paragraph.Root(), run.Root());
new_run.SetText(text[rpos+1:]);
arr["rsplit"] := nil;
arr["text"] := text[1:rpos];
if data_[i]["tparagraph"] <> para then
begin
arr[length(arr)] := data_[i]["tparagraph"].Root();
end
else begin
p := data_[i]["tparagraph"];
r := data_[i]["trun"];
if ifObj(r.Root()) then p.Root().DeleteChild(r.Root());
end
end
arr["trun"] := run;
first["trun"].ClearText();
data_ := array();
if not deleteAll then data_[0] := first;
return arr;
End;
@@ -141,7 +241,7 @@ Begin
node := startNode.FirstChildElement();
while ifObj(node) do
begin
len := length(Data); // 标记完整段落/表格的起始位置
len := length(data_); // 标记完整段落/表格的起始位置
case node.GetName() of
"w:p":
begin
@@ -149,7 +249,7 @@ Begin
paragraph_obj.Init(node);
if paragraph_obj.Empty() then // 空段落
begin
AddRunInfo(startNode, nil, paragraph_obj);
self.AddRunInfo(nil, paragraph_obj);
end
else begin
sub_node := node.FirstChildElement();
@@ -158,7 +258,7 @@ Begin
case sub_node.GetName() of
"w:r":
begin
AddRunInfo(startNode, sub_node, paragraph_obj);
self.AddRunInfo(sub_node, paragraph_obj);
if cur_position_ >= end_position_ then return 1;
end
@@ -167,7 +267,7 @@ Begin
run_node := sub_node.FirstChildElement("w:r");
while ifObj(run_node) do
begin
AddRunInfo(startNode, run_node, paragraph_obj);
self.AddRunInfo(run_node, paragraph_obj);
if cur_position_ >= end_position_ then return 1;
run_node := run_node.NextElement("w:r");
end
@@ -188,11 +288,11 @@ Begin
tc := tr.FirstChildElement("w:tc");
while ifObj(tc) do
begin
cell_len := length(Data);
flag := FindRangeByPosition(tc);
cell_len := length(data_);
flag := self.FindRangeByPosition(tc);
if flag then return 1;
if cur_position_ >= end_position_ then return 1;
AddEntirety(cell_len, tc);
self.AddEntirety(cell_len, tc);
tc := tc.NextElement("w:tc");
end
cur_position_ += 1;
@@ -201,7 +301,7 @@ Begin
end
end
end;
AddEntirety(len, node);
self.AddEntirety(len, node);
if cur_position_ >= end_position_ then return 1;
node := node.NextElement();
end
@@ -209,32 +309,31 @@ End;
Function TSWdRange.AddEntirety(len, node);
Begin
for i:=len to length(Data)-1 do
Data[i]["entirety"] := node;
for i:=len to length(data_)-1 do
data_[i]["entirety"] := node;
End;
Function TSWdRange.AddRunInfo(parentNode, runNode, tParagraph);
Function TSWdRange.AddRunInfo(runNode, tParagraph);
Begin
run_obj := TOfficeObj("TRun");
run_obj.Init(runNode);
text := ifObj(runNode) ? run_obj.Text() : "";
len := text ? length(text) : 1;
if class(TSXml).IsUtf8() then text := Utf8ToAnsi(text);
len := text ? lengthw(text) : 1;
if cur_position_ + len > start_position_ then
begin
length := length(Data);
Data[length]["tparagraph"] := tparagraph;
Data[length]["trun"] := run_obj;
Data[length]["text"] := text;
Data[length]["root"] := root_node_;
Data[length]["parent"] := parentNode;
length := length(data_);
data_[length]["tparagraph"] := tparagraph;
data_[length]["trun"] := run_obj;
data_[length]["text"] := text;
// 左边切割,左边丢弃的字符数
if cur_position_ < start_position_ and cur_position_ + len > start_position_ + 1 then
Data[length]["lsplit"] := start_position_ - cur_position_;
if cur_position_ < start_position_ and cur_position_ + len >= start_position_ + 1 then
data_[length]["lsplit"] := start_position_ - cur_position_;
// 右边切割,右边丢弃的字符数
if cur_position_ + len > end_position_ then
Data[length]["rsplit"] := cur_position_ + len - end_position_;
data_[length]["rsplit"] := cur_position_ + len - end_position_;
end
cur_position_ += len;
End;
@@ -246,12 +345,12 @@ Begin
node := tc.FirstChildElement();
while ifObj(node) do
begin
FindRangeByNode(node);
self.FindRangeByNode(node);
node := node.NextElement();
end
end
case startNode.GetName() of
"w:p": ParagraphRange(startNode);
"w:p": self.ParagraphRange(startNode);
"w:tbl":
begin
tr := startNode.FirstChildElement("w:tr");
@@ -279,21 +378,21 @@ Begin
paragraph_obj.Init(node);
if paragraph_obj.Empty() then
begin
AddRunInfo2(nil, nil, paragraph_obj);
self.AddRunInfo2(nil, paragraph_obj);
end
else begin
sub_node := node.FirstChildElement();
while ifObj(sub_node) do
begin
case sub_node.GetName() of
"w:r": AddRunInfo2(nil, sub_node, paragraph_obj);
"w:r": self.AddRunInfo2(sub_node, paragraph_obj);
"w:ins", "w:del":
begin
run_node := sub_node.FirstChildElement("w:r");
while ifObj(run_node) do
begin
AddRunInfo2(nil, run_obj, paragraph_obj);
self.AddRunInfo2(run_node, paragraph_obj);
run_node := run_node.NextElement("w:r");
end
end
@@ -303,38 +402,14 @@ Begin
end
End;
Function TSWdRange.AddRunInfo2(parentNode, runNode, tParagraph);
Function TSWdRange.AddRunInfo2(runNode, tParagraph);
Begin
run_obj := TOfficeObj("TRun");
run_obj.Init(runNode);
length := length(Data);
Data[length]["tparagraph"] := tParagraph;
Data[length]["trun"] := run_obj;
Data[length]["root"] := root_node_;
Data[length]["parent"] := parentNode;
Data[length]["entirety"] := target_node_;
length := length(data_);
data_[length]["tparagraph"] := tParagraph;
data_[length]["trun"] := run_obj;
data_[length]["entirety"] := target_node_;
End;
Function TSWdRange.Clear();
Begin
SplitRun();
first := Data[0];
para := first["tparagraph"];
index := 0;
for i:=1 to length(Data)-1 do
begin
if Data[i]["tparagraph"] <> para then
begin
parent := Data[i]["parent"];
parent.DeleteChild(Data[i]["tparagraph"].Root());
end
else begin
p := Data[i]["tparagraph"];
r := Data[i]["trun"];
if ifObj(p.Root()) and ifObj(r.Root()) then p.Root().DeleteChild(r.Root());
end
end
Data := array();
Data[0] := first;
End;