OfficeVba/docx/utils/TSWdRange.tsf

490 lines
11 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 Operator[](index);
Function Run();
Function Refresh();
Function GetStart();
Function GetEnd();
Function SplitRun();overload;
Function SplitRun(index);overload;
Function Clear(deleteAll);
Function Size();
Function Print();
Begin
println("data = {}", data_);
End;
private
Function FindRangeByPosition(startNode);
Function FindRangeByNode(startNode);
Function AddEntirety(len, node);
Function AddRunInfo(runNode, tParagraph);
Function AddRunInfo2(runNode, tParagraph);
Function ParagraphRange(node);
Function CalcPosition(startNode);
public
data_; // 管理range结构的数组字段如下
// lsplit: 左边丢弃的字符数
// rsplit: 右边丢弃的字符数
// tparagraph: TOfficeObj("TParagraph")对象
// trun: TOfficeObj("TRun")对象
// text: 文本内容
// entirety: 是否是完整的段落/表格/单元格
// -- 以便在对range操作时候知道操作一个段落还是一个run比如range.shading range.Border
private
start_position_; // 开始位置
end_position_; // 结束位置, 开始与结束遵循左闭右开原则
cur_position_; // 当前位置
root_node_; // 根节点
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 = -1 ? INF : endP;
target_node_ := nil;
self.Init();
End;
Function TSWdRange.Create(rootNode, targetNode);overload;
Begin
root_node_ := rootNode;
target_node_ := targetNode;
start_position_ := nil;
end_position_ := nil;
self.Init();
End;
Function TSWdRange.Init();
Begin
cur_position_ := 0;
split_flag_ := false;
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
self.FindRangeByNode(target_node_);
else
self.FindRangeByPosition(root_node_);
End;
Function TSWdRange.Refresh();
Begin
self.Init();
End;
Function TSWdRange.Size();
Begin
return length(data_);
End;
Function TSWdRange.GetStart();
Begin
if ifnil(start_position_) then self.CalcPosition(root_node_);
return start_position_;
End;
Function TSWdRange.GetEnd();
Begin
if ifnil(end_position_) then self.CalcPosition(root_node_);
return end_position_;
End;
Function TSWdRange.SplitRun();overload;
Begin
if split_flag_ then return;
for i:=0 to length(data_)-1 do
self.SplitRun(i);
split_flag_ := true;
End;
Function TSWdRange.SplitRun(index);overload;
Begin
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
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 data_[index]["rsplit"] then // 分割右边的run
begin
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
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
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
first["trun"].ClearText();
data_ := array();
if not deleteAll then data_[0] := first;
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
self.AddRunInfo(nil, paragraph_obj);
end
else begin
sub_node := node.FirstChildElement();
while ifObj(sub_node) do
begin
case sub_node.GetName() of
"w:r":
begin
self.AddRunInfo(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
self.AddRunInfo(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 := self.FindRangeByPosition(tc);
if flag then return 1;
if cur_position_ >= end_position_ then return 1;
self.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;
self.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(runNode, tParagraph);
Begin
run_obj := TOfficeObj("TRun");
run_obj.Init(runNode);
text := ifObj(runNode) ? run_obj.Text() : "";
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;
// 左边切割,左边丢弃的字符数
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
self.FindRangeByNode(node);
node := node.NextElement();
end
end
case startNode.GetName() of
"w:p": self.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.CalcPosition(startNode);
Begin
node := startNode.FirstChildElement();
while ifObj(node) do
begin
if node.Eq(target_node_) then
begin
eq_flag := true;
start_position_ := cur_position_;
end
case node.GetName() of
"w:p":
begin
paragraph_obj := TOfficeObj("TParagraph");
paragraph_obj.Init(node);
if paragraph_obj.Empty() then // 空段落
begin
cur_position_ += 1;
end
else begin
sub_node := node.FirstChildElement();
while ifObj(sub_node) do
begin
case sub_node.GetName() of
"w:r":
begin
run_obj := TOfficeObj("TRun");
run_obj.Init(sub_node);
text := run_obj.Text();
if class(TSXml).IsUtf8() then text := Utf8ToAnsi(text);
cur_position_ += lengthw(text);
end
"w:ins", "w:del":
begin
run_node := sub_node.FirstChildElement("w:r");
while ifObj(run_node) do
begin
run_obj := TOfficeObj("TRun");
run_obj.Init(run_node);
text := run_obj.Text();
if class(TSXml).IsUtf8() then text := Utf8ToAnsi(text);
cur_position_ += lengthw(text);
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
flag := self.CalcPosition(tc);
if flag then return 1;
tc := tc.NextElement("w:tc");
end
cur_position_ += 1;
tr := tr.NextElement("w:tr");
end
end
end;
if eq_flag then
begin
end_position_ := cur_position_;
return 1;
end
node := node.NextElement();
end
End;
Function TSWdRange.ParagraphRange(node);
Begin
paragraph_obj := TOfficeObj("TParagraph");
paragraph_obj.Init(node);
if paragraph_obj.Empty() then
begin
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": self.AddRunInfo2(sub_node, paragraph_obj);
"w:ins", "w:del":
begin
run_node := sub_node.FirstChildElement("w:r");
while ifObj(run_node) do
begin
self.AddRunInfo2(run_node, paragraph_obj);
run_node := run_node.NextElement("w:r");
end
end
end;
sub_node := sub_node.NextElement();
end
end
End;
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]["entirety"] := target_node_;
End;