490 lines
11 KiB
Plaintext
490 lines
11 KiB
Plaintext
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.Range,table.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
|
||
if target_node_ then self.FindRangeByNode(target_node_);
|
||
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;
|
||
|