OfficeVba/docx/utils/TSWdRange.tsf

341 lines
7.9 KiB
Plaintext
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.

Type TSWdRange = Class
public
Function Create(rootNode, startP, endP);overload;
Function Create(rootNode, targetNode);overload;
Function Init();
Function Run();
Function GetStart();
Function GetEnd();
Function SplitRun();overload;
Function SplitRun(arr);overload;
Function Clear();
Function Print();
public
Data; // 管理range结构的数组字段如下
// lsplit: 左边丢弃的字符数
// rsplit: 右边丢弃的字符数
// tparagraph: TOfficeObj("TParagraph")对象
// trun: TOfficeObj("TRun")对象
// text: 文本内容
// root: 根节点
// parent: 父节点
// entirety: 是否是完整的段落/表格/单元格
private
Function FindRangeByPosition(startNode);
Function FindRangeByNode(startNode);
Function AddEntirety(len, node);
Function AddRunInfo(parentNode, runNode, tParagraph);
Function AddRunInfo2(parentNode, runNode, tParagraph);
Function ParagraphRange(node);
private
start_position_; // 开始位置
end_position_; // 结束位置, 开始与结束遵循左闭右开原则
cur_position_; // 当前位置
root_node_; // 根节点
target_node_; // 目标节点使用paragraph.Rangetable.Range, cell.Range时用
split_flag_; // 切割标志
End;
Function TSWdRange.Create(rootNode, startP, endP);overload;
Begin
root_node_ := rootNode;
start_position_ := startP;
end_position_ := endP;
targetNode := nil;
Init();
End;
Function TSWdRange.Create(rootNode, targetNode);overload;
Begin
root_node_ := rootNode;
target_node_ := targetNode;
start_position_ := nil;
end_position_ := nil;
Init();
End;
Function TSWdRange.Init();
Begin
cur_position_ := 0;
split_flag_ := false;
Data := array();
Run();
End;
Function TSWdRange.Run();
Begin
if target_node_ then
FindRangeByNode(target_node_);
else
FindRangeByPosition(root_node_);
End;
Function TSWdRange.Print();
Begin
println("print... {}", Data);
End;
Function TSWdRange.GetStart();
Begin
if ifnil(start_position_) then return 0;
return start_position_;
End;
Function TSWdRange.GetEnd();
Begin
if ifnil(end_position_) then return 0;
return end_position_;
End;
Function TSWdRange.SplitRun();overload;
Begin
if split_flag_ then return;
for i:=0 to length(Data)-1 do
Data[i] := SplitRun(Data[i]);
split_flag_ := true;
End;
Function TSWdRange.SplitRun(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
if ifnil(arr["lsplit"]) and ifnil(arr["rsplit"]) then return arr;
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;
Function TSWdRange.FindRangeByPosition(startNode);
Begin
node := startNode.FirstChildElement();
while ifObj(node) do
begin
len := length(Data); // 标记完整段落/表格的起始位置
case node.GetName() of
"w:p":
begin
paragraph_obj := TOfficeObj("TParagraph");
paragraph_obj.Init(node);
if paragraph_obj.Empty() then // 空段落
begin
AddRunInfo(startNode, nil, paragraph_obj);
end
else begin
sub_node := node.FirstChildElement();
while ifObj(sub_node) do
begin
case sub_node.GetName() of
"w:r":
begin
AddRunInfo(startNode, sub_node, paragraph_obj);
if cur_position_ >= end_position_ then return 1;
end
"w:ins", "w:del":
begin
run_node := sub_node.FirstChildElement("w:r");
while ifObj(run_node) do
begin
AddRunInfo(startNode, run_node, paragraph_obj);
if cur_position_ >= end_position_ then return 1;
run_node := run_node.NextElement("w:r");
end
end
end;
sub_node := sub_node.NextElement();
end
// 完整段落
cur_position_ += 1;
end
end
"w:tbl":
begin
tr := node.FirstChildElement("w:tr");
while ifObj(tr) do
begin
tc := tr.FirstChildElement("w:tc");
while ifObj(tc) do
begin
cell_len := length(Data);
flag := FindRangeByPosition(tc);
if flag then return 1;
if cur_position_ >= end_position_ then return 1;
AddEntirety(cell_len, tc);
tc := tc.NextElement("w:tc");
end
cur_position_ += 1;
if cur_position_ >= end_position_ then return 1;
tr := tr.NextElement("w:tr");
end
end
end;
AddEntirety(len, node);
if cur_position_ >= end_position_ then return 1;
node := node.NextElement();
end
End;
Function TSWdRange.AddEntirety(len, node);
Begin
for i:=len to length(Data)-1 do
Data[i]["entirety"] := node;
End;
Function TSWdRange.AddRunInfo(parentNode, runNode, tParagraph);
Begin
run_obj := TOfficeObj("TRun");
run_obj.Init(runNode);
text := ifObj(runNode) ? run_obj.Text() : "";
len := text ? length(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;
// 左边切割,左边丢弃的字符数
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_;
end
cur_position_ += len;
End;
Function TSWdRange.FindRangeByNode(startNode);
Begin
tc_pf := function(tc);
begin
node := tc.FirstChildElement();
while ifObj(node) do
begin
FindRangeByNode(node);
node := node.NextElement();
end
end
case startNode.GetName() of
"w:p": ParagraphRange(startNode);
"w:tbl":
begin
tr := startNode.FirstChildElement("w:tr");
while ifObj(tr) do
begin
tc := tr.FirstChildElement("w:tc");
while ifObj(tc) do
begin
##tc_pf(tc);
tc := tc.NextElement("w:tc");
end
tr := tr.NextElement("w:tr");
end
end
"w:tc":
begin
##tc_pf(startNode);
end
end;
End;
Function TSWdRange.ParagraphRange(node);
Begin
paragraph_obj := TOfficeObj("TParagraph");
paragraph_obj.Init(node);
if paragraph_obj.Empty() then
begin
AddRunInfo2(nil, 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:ins", "w:del":
begin
run_node := sub_node.FirstChildElement("w:r");
while ifObj(run_node) do
begin
AddRunInfo2(nil, run_obj, paragraph_obj);
run_node := run_node.NextElement("w:r");
end
end
end;
sub_node := sub_node.NextElement();
end
end
End;
Function TSWdRange.AddRunInfo2(parentNode, 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_;
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;