diff --git a/Demo/wordHelp.tsl b/Demo/wordHelp.tsl index 675b329..12d1579 100644 --- a/Demo/wordHelp.tsl +++ b/Demo/wordHelp.tsl @@ -69,7 +69,9 @@ _Annotation(docx); _Faq(docx); ///目录 -docx.AddTableContent(paragraphTitle, 1, 3); +content := docx.AddTableContent(paragraphTitle, 1, 3); +docx.AddPageBreak(content.node_); + v := docx.SaveAs('', TOfficeApi().CurCodePageToGBK('DocxFile使用帮助.docx')); println('Test Over!\n Save {}: {},time={}秒', file, v, mtoc); diff --git a/DocxFile使用帮助.docx b/DocxFile使用帮助.docx index 3482fc1..47a36d6 100644 Binary files a/DocxFile使用帮助.docx and b/DocxFile使用帮助.docx differ diff --git a/Linux-x86_64/liboffice_plugin.so b/Linux-x86_64/liboffice_plugin.so index a3aaba9..fb424b1 100644 Binary files a/Linux-x86_64/liboffice_plugin.so and b/Linux-x86_64/liboffice_plugin.so differ diff --git a/Windows-X64/office_plugin.dll b/Windows-X64/office_plugin.dll index 2028291..9a686e3 100644 Binary files a/Windows-X64/office_plugin.dll and b/Windows-X64/office_plugin.dll differ diff --git a/funcext/TSOffice/TOfficeObj.tsf b/funcext/TSOffice/TOfficeObj.tsf index 608dedc..7e48236 100644 --- a/funcext/TSOffice/TOfficeObj.tsf +++ b/funcext/TSOffice/TOfficeObj.tsf @@ -1,4 +1,4 @@ -// Version 1.3.5 +// Version 1.4.4 Function TOfficeObj(n); Begin @@ -167,6 +167,8 @@ Begin return new TNumPr(); "ttextbox": return new TTextBox(); + "twhyperlinkimpl": + return new TWHyperLinkImpl(); "twppr": return new TwpPr(); "tcnvgraphicframepr": @@ -285,10 +287,10 @@ Begin return new TDocxStyle(); "tdocpartobj": return new TDocPartObj(); - "tstdpr": - return new TStdPr(); - "tstdendpr": - return new TStdEndPr(); + "tsdtpr": + return new TSdtPr(); + "tsdtendpr": + return new TSdtEndPr(); "tsdtcontent": return new TSdtContent(); "ttablecontentimpl": @@ -5843,10 +5845,10 @@ type TwrPr=class(NodeInfo) Begin HandleChildren(); return array(("field":"rFont","name":rFont.NodeName,"obj":rFont,"attrEx":"","nodeType":"","attrName":"", "desc":"", "class":"TwFont") - ,("field":"Bold","name":"w:b","obj":Bold,"attrEx":"","nodeType":"empty","attrName":"", "desc":"黑体", "class":"") + ,("field":"Bold","name":"w:b","obj":Bold,"attrEx":"w:val","nodeType":"empty","attrName":"", "desc":"黑体", "class":"") ,("field":"noProof","name":"w:noProof","obj":noProof,"attrEx":"","nodeType":"empty","attrName":"", "desc":"不检查拼写或语法)", "class":"") ,("field":"Color","name":"w:color","obj":Color,"attrEx":"w:val","nodeType":"","attrName":"", "desc":"字体颜色", "class":"") - ,("field":"bCs","name":"w:bCs","obj":bCs,"attrEx":"","nodeType":"empty","attrName":"", "desc":"复杂脚本黑体", "class":"") + ,("field":"bCs","name":"w:bCs","obj":bCs,"attrEx":"w:val","nodeType":"empty","attrName":"", "desc":"复杂脚本黑体", "class":"") ,("field":"Italic","name":"w:i","obj":Italic,"attrEx":"","nodeType":"empty","attrName":"", "desc":"斜体", "class":"") ,("field":"Strike","name":"w:strike","obj":Strike,"attrEx":"","nodeType":"empty","attrName":"", "desc":"单个删除线", "class":"") ,("field":"dStrike","name":"w:dstrike","obj":dStrike,"attrEx":"w:val","nodeType":"","attrName":"", "desc":"两个删除线", "class":"") @@ -5859,6 +5861,8 @@ type TwrPr=class(NodeInfo) ,("field":"Lang","name":"w:lang","obj":Lang,"attrEx":"w:val","nodeType":"","attrName":"", "desc":"处理使用拉丁字符的本次运行内容时用于检查拼写和语法的语言.", "class":"") ,("field":"bidi","name":"w:lang","obj":bidi,"attrEx":"w:bidi","nodeType":"","attrName":"", "desc":"处理使用复杂脚本字符的运行内容时应使用的语言.", "class":"") ,("field":"Del","name":Del.NodeName,"obj":Del,"attrEx":"","nodeType":"","attrName":"", "desc":"disable", "class":"TOptInfo") + ,("field":"StyleId","name":"w:rStyle","obj":StyleId,"attrEx":"w:val","nodeType":"","attrName":"", "desc":"disable", "class":"") + ,("field":"WebHidden","name":"w:webHidden","obj":WebHidden,"attrEx":"w:val","nodeType":"empty","attrName":"", "desc":"disable", "class":"") ) union ExtNodes; End; @@ -5909,6 +5913,8 @@ type TwrPr=class(NodeInfo) Lang; bidi; Del; + StyleId; + WebHidden; End; /////////////////////////////////////////////////////////////// @@ -6003,6 +6009,50 @@ type TTextBoxImpl=class(NodeInfo) P; End; +/////////////////////////////////////////////////////////////// +/// TWHyperLinkImpl +/////////////////////////////////////////////////////////////// +type TWHyperLinkImpl=class(NodeInfo) + Function Create(); overload; + Begin + Create(nil, 'w:hyperlink'); + End; + + Function Create(p, name); overload; + Begin + Class(NodeInfo).Create(p, name); + Init(); + End; + + Function Init(); + Begin + //TODO... + End; + + Function InitRootNode(node); + Begin + RootObj := node; + End; + + Function GetAttrs(); override; + Begin + HandleAttrs(); + return array(("Anchor", "w:anchor", Anchor, ""),("History", "w:history", History, "")) union ExtAttr; + End; + + Function GetChildren(); override; + Begin + HandleChildren(); + return ExtNodes; + End; + + //Attributes + Anchor; + History; + + //Nodes +End; + /////////////////////////////////////////////////////////////// /// TwpPr /////////////////////////////////////////////////////////////// @@ -6067,10 +6117,11 @@ type TwpPr=class(NodeInfo) ,("field":"OutlineLevel","name":"w:outlineLvl","obj":OutlineLevel,"attrEx":"w:val","nodeType":"","attrName":"", "desc":"设置当前文档中第一段的大纲级别", "class":"") ,("field":"KeepTogether","name":"w:keepLines","obj":KeepTogether,"attrEx":"w:val","nodeType":"","attrName":"", "desc":"段落是否应保持完整且不应跨越页面边界", "class":"") ,("field":"KeepWithNext","name":"w:keepNext","obj":KeepWithNext,"attrEx":"w:val","nodeType":"","attrName":"", "desc":"该段是否应与下一段保持在同一页上", "class":"") - ,("field":"PageBreakBefore","name":"w:pageBreakBefore","obj":PageBreakBefore,"attrEx":"","nodeType":"empty","attrName":"", "desc":"该段该段出现在前一段之后的页面顶部", "class":"") + ,("field":"PageBreakBefore","name":"w:pageBreakBefore","obj":PageBreakBefore,"attrEx":"w:val","nodeType":"empty","attrName":"", "desc":"该段该段出现在前一段之后的页面顶部", "class":"") ,("field":"WidowControl","name":"w:widowControl","obj":WidowControl,"attrEx":"w:val","nodeType":"","attrName":"", "desc":"当Word对文档重新分页时,如果段落中的第一行和最后一行与段落的其余部分保持在同一页上", "class":"") ,("field":"TextAlignment","name":"w:textAlignment","obj":TextAlignment,"attrEx":"","nodeType":"empty","attrName":"", "desc":"该值指示文本内容的水平对齐方式", "class":"") - ,("field":"AdjustRightInd","name":"w:adjustRightInd","obj":AdjustRightInd,"attrEx":"","nodeType":"empty","attrName":"", "desc":"使用文档网格时自动调整右缩进", "class":"") + ,("field":"AdjustRightInd","name":"w:adjustRightInd","obj":AdjustRightInd,"attrEx":"w:val","nodeType":"empty","attrName":"", "desc":"使用文档网格时自动调整右缩进", "class":"") + ,("field":"SnapToGrid","name":"w:snapToGrid","obj":SnapToGrid,"attrEx":"w:val","nodeType":"empty","attrName":"", "desc":"如果定义了文档网络,则对齐到网格", "class":"") ,("field":"AutoSpaceDE","name":"w:autoSpaceDE","obj":AutoSpaceDE,"attrEx":"","nodeType":"empty","attrName":"", "desc":"自动调整拉丁语和东亚文本的间距", "class":"") ,("field":"AutoSpaceDN","name":"w:autoSpaceDN","obj":AutoSpaceDN,"attrEx":"","nodeType":"empty","attrName":"", "desc":"自动调整东亚文本和数字的间距", "class":"") ,("field":"Tabs","name":Tabs.NodeName,"obj":Tabs,"attrEx":"","nodeType":"","attrName":"", "desc":"disable", "class":"TTabStops") @@ -6110,6 +6161,7 @@ type TwpPr=class(NodeInfo) WidowControl; TextAlignment; AdjustRightInd; + SnapToGrid; AutoSpaceDE; AutoSpaceDN; Tabs; @@ -7894,24 +7946,22 @@ type TPage=class(NodeInfo) Function GetAttrs(); override; Begin HandleAttrs(); - return array(("Code", "w:code", Code, "纸张类型(指定打印机特定的纸张代码)."),("Height", "w:h", Height, "当前节中所有页面的高度(以二十分之一点为单位).")) union ExtAttr; + return array(("Code", "w:code", Code, "纸张类型(指定打印机特定的纸张代码)."),("Height", "w:h", Height, "当前节中所有页面的高度(以二十分之一点为单位)."),("Width", "w:w", Width, "此属性表示当前节中所有页面的宽度(以二十分之一为单位)."),("Orient ", "w:orient ", Orient , "指定此节中所有页面的方向.")) union ExtAttr; End; Function GetChildren(); override; Begin HandleChildren(); - return array(("field":"Weight","name":"w:w","obj":Weight,"attrEx":"","nodeType":"","attrName":"", "desc":"此属性表示当前节中所有页面的宽度(以二十分之一为单位).", "class":"") - ,("field":"Orient ","name":"w:orient ","obj":Orient ,"attrEx":"","nodeType":"","attrName":"", "desc":"指定此节中所有页面的方向.", "class":"") - ) union ExtNodes; + return ExtNodes; End; //Attributes Code; Height; + Width; + Orient ; //Nodes - Weight; - Orient ; End; /////////////////////////////////////////////////////////////// @@ -9320,9 +9370,9 @@ type TDocPartObj=class(NodeInfo) End; /////////////////////////////////////////////////////////////// -/// TStdPr +/// TSdtPr /////////////////////////////////////////////////////////////// -type TStdPr=class(NodeInfo) +type TSdtPr=class(NodeInfo) Function Create(); overload; Begin Create(nil, 'w:sdtPr'); @@ -9372,9 +9422,9 @@ type TStdPr=class(NodeInfo) End; /////////////////////////////////////////////////////////////// -/// TStdEndPr +/// TSdtEndPr /////////////////////////////////////////////////////////////// -type TStdEndPr=class(NodeInfo) +type TSdtEndPr=class(NodeInfo) Function Create(); overload; Begin Create(nil, 'w:sdtEndPr'); @@ -9476,18 +9526,18 @@ type TTableContentImpl=class(NodeInfo) Function Init(); Begin - stdPr := new TStdPr(self, 'w:sdtPr'); - stdEndPr := new TStdEndPr(self, 'w:sdtEndPr'); - SdtContent := new TSdtContent(self, 'w:sdtContent'); + sdtPr := new TSdtPr(self, 'w:sdtPr'); + sdtEndPr := new TSdtEndPr(self, 'w:sdtEndPr'); + sdtContent := new TSdtContent(self, 'w:sdtContent'); //TODO... End; Function InitRootNode(node); Begin RootObj := node; - stdPr.InitRootNode(node); - stdEndPr.InitRootNode(node); - SdtContent.InitRootNode(node); + sdtPr.InitRootNode(node); + sdtEndPr.InitRootNode(node); + sdtContent.InitRootNode(node); End; Function GetAttrs(); override; @@ -9499,18 +9549,18 @@ type TTableContentImpl=class(NodeInfo) Function GetChildren(); override; Begin HandleChildren(); - return array(("field":"stdPr","name":stdPr.NodeName,"obj":stdPr,"attrEx":"","nodeType":"","attrName":"", "desc":"", "class":"TStdPr") - ,("field":"stdEndPr","name":stdEndPr.NodeName,"obj":stdEndPr,"attrEx":"","nodeType":"","attrName":"", "desc":"", "class":"TStdEndPr") - ,("field":"SdtContent","name":SdtContent.NodeName,"obj":SdtContent,"attrEx":"","nodeType":"","attrName":"", "desc":"", "class":"TSdtContent") + return array(("field":"sdtPr","name":sdtPr.NodeName,"obj":sdtPr,"attrEx":"","nodeType":"","attrName":"", "desc":"", "class":"TSdtPr") + ,("field":"sdtEndPr","name":sdtEndPr.NodeName,"obj":sdtEndPr,"attrEx":"","nodeType":"","attrName":"", "desc":"", "class":"TSdtEndPr") + ,("field":"sdtContent","name":sdtContent.NodeName,"obj":sdtContent,"attrEx":"","nodeType":"","attrName":"", "desc":"", "class":"TSdtContent") ) union ExtNodes; End; //Attributes //Nodes - stdPr; - stdEndPr; - SdtContent; + sdtPr; + sdtEndPr; + sdtContent; End; /////////////////////////////////////////////////////////////// @@ -10782,6 +10832,20 @@ End; // 'w:rPr', 'w:sectPr', 'w:pPrChange' //w:p +Type TWHyperLink = Class(TWHyperLinkImpl) + Function AddRun(txt, newLine); + Begin + o := new TRun(); + //o.Parent := self; + NewChildNode( array("field":"", "name":"w:r", "obj":o, "attrEx":"", "nodeType":"") ); + if txt then + o.SetText(txt); + if newLine then + o.Br.Type := ''; + return o; + End; +End; + Type TParagraph = Class(DocObject, TParagraphImpl) Function Create();overload; Begin @@ -10916,6 +10980,15 @@ Type TParagraph = Class(DocObject, TParagraphImpl) o.Br.Type := ''; return o; End; + + ///段落添加 + ///返回:TWHyperLink + Function AddHyperLink(); + Begin + o := new TWHyperLink(); + NewChildNode( array("field":"", "name":"w:r", "obj":o, "attrEx":"", "nodeType":"") ); + return o; + End; ///在段落对象后面追加TRun对象 ///返回TRun对象 @@ -11007,6 +11080,25 @@ Type TParagraph = Class(DocObject, TParagraphImpl) markEnd.SetAttribute('w:id', bookMarkID); return name; End; + + ///判断是否为空段落 + ///返回: bool + Function Empty(); + Begin + if ifObj(node_) then + begin + sub_node := node_.FirstChildElement(); + if not ifObj(sub_node) then return true; + // 兼容wps + sub_node2 := sub_node.NextElement(); + if sub_node.GetName() = 'w:bookmarkStart' and ifObj(sub_node2) and sub_node2.GetName() = 'w:bookmarkEnd' then + return true; + // 兼容word + if sub_node.GetName() = 'w:pPr' and not ifObj(sub_node2) then + return true; + end + return false; + End; Function CopyRunFormat(del, toRunNode); Begin @@ -12620,7 +12712,7 @@ Type TSectPr = Class LineRatio := 1.0; if ifObj(pPr) then Begin if pPr.LineSpacingRule = 'exact' and pPr.LineSpacing then //固定行距 - defaultLineHeight := _pPr.LineSpacing; + defaultLineHeight := pPr.LineSpacing; else if pPr.LineSpacing then Begin LineRatio := pPr.LineSpacing / 240; //LineRatio := 1.0; @@ -12675,7 +12767,8 @@ Type TSectPr = Class n += cnt; if newLine then Begin _addLine(startPage, curPageNo, curLinePos, LineHeight + (linesCnt ? 0 : more), before, linesCnt ? false : true, t); //加入一行 - PageLine.CurrentLine += _getHanging(linesCnt+1, pPr); + if ifObj(pPr) then + PageLine.CurrentLine += _getHanging(linesCnt+1, pPr); linesCnt ++; End; End; @@ -12783,7 +12876,7 @@ Type TSectPr = Class Function _Font2LineHeight(rPr, LineRatio); Begin - size := max(rPr.Size, rPr.szCs); + size := max(ifnil(rPr.Size) ? 0 : rPr.Size, ifnil(rPr.szCs) ? 0 : rPr.szCs); if size = 0 then size := 21;//缺省五号字 if rPr.rFont.hint in array('eastAsia', 'zh-CN') or rPr.rFont.eastAsia <> '' then Begin return ceil(size*10/(LinePitch*LineRatio-200/3)); @@ -12874,6 +12967,32 @@ Type TDocumentBody = Class(DocObject) _set_lastParagraph_(posOpt, p.node_);//设置最后一个段落 return p; End; + + ///复制w:p节点内容 + ///paragraphObj: TParagraph对象 + ///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;DocumentPart对象 在posOpt之后新添加段落 + ///返回TParagraph对象 + Function CopyWp(paragraphObj, posOpt); + Begin + addPart(posOpt, paragraphObj, true); + p := new TParagraph(paragraphObj.node_); + //复制段落字体属性 + p.CopyRunFormat(false, nil); + _set_lastParagraph_(posOpt, p.node_);//设置最后一个段落 + return p; + End; + + ///复制w:tbl节点内容 + ///ttable: TTable对象 + ///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;DocumentPart对象 在posOpt之后新添加段落 + ///返回TTable对象 + Function CopyWtbl(table, posOpt); + Begin + addPart(posOpt, table, true); + p := new TTable(table.node_); + _set_lastParagraph_(posOpt, p.node_); + return p; + End; ///删除指定段落 ///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 第N段;posOpt段落 @@ -12889,10 +13008,15 @@ Type TDocumentBody = Class(DocObject) End; if not ifObj(node) then return false; + reset_position := false; + if node.Eq(TOfficeApi().GetCurrentPosition()) then + reset_position := true; next := node.NextElement('w:p'); node_.DeleteChild(node); if not ifObj(next) then _setLastParagraph(); + if reset_position then + TOfficeApi().Set('CurrentPosition', lastParagraph_); return true; End; @@ -13051,14 +13175,14 @@ Type TDocumentBody = Class(DocObject) *) End; - if ifObj(tblCellMar) then Begin - c := class(TSXml).GetNode(trNode, 'w:tblPrEx/w:tblCellMar', 'first'); - class(TSXml).UpdateNode(c, cellmar[0]['attributes'], cellmar[0]['children']); - End; - if ifObj(tblBorders) then Begin - b := class(TSXml).GetNode(trNode, 'w:tblPrEx/w:tblBorders', 'first'); - class(TSXml).UpdateNode(b, borders[0]['attributes'], borders[0]['children']); - End; + //if ifObj(tblCellMar) then Begin + // c := class(TSXml).GetNode(trNode, 'w:tblPrEx/w:tblCellMar', 'first'); + // class(TSXml).UpdateNode(c, cellmar[0]['attributes'], cellmar[0]['children']); + //End; + //if ifObj(tblBorders) then Begin + // b := class(TSXml).GetNode(trNode, 'w:tblPrEx/w:tblBorders', 'first'); + // class(TSXml).UpdateNode(b, borders[0]['attributes'], borders[0]['children']); + //End; End; node_.Parent().SetAttribute('mc:Ignorable', 'w14 w15 wp14'); node_.Parent().SetAttribute('xmlns:w15', 'http://schemas.microsoft.com/office/word/2012/wordml'); @@ -13138,6 +13262,7 @@ Type TDocumentBody = Class(DocObject) p := new TPicture(picture.node_); _set_lastParagraph_(posOpt, picture.node_); + picture.node_.InsertFirstChild('element', 'w:pPr'); TOfficeApi().Set('CurrentShape', picture.node_); return p; End; @@ -13777,7 +13902,7 @@ Type TDocumentBody = Class(DocObject) sectPr.Append(p); numId := p.Format.NumPr.Value('numId'); lvlStr := p.Format.NumPr.Value('Level'); - if numId and lvlStr then Begin + if not ifnil(numId) and not ifnil(lvlStr) then Begin ilvl := Class(TSXml).SafeStrToIntDef(lvlStr, -1); if ilvl >= 0 and ilvl < 10 then Begin if not istable(numIds[numId]) then @@ -13799,11 +13924,11 @@ Type TDocumentBody = Class(DocObject) if ifObj(obj) then Begin level := obj.HeadingLevel(); iLevel := Class(TSXml).SafeStrToIntDef(level, -1); - if iLevel+1 >= UpperHeadingLevel and iLevel+1 <= LowerHeadingLevel then Begin + if p.Text() <> "" and iLevel+1 >= UpperHeadingLevel and iLevel+1 <= LowerHeadingLevel then Begin r[ind]['Level'] := strtoint(level); r[ind]['Paragraph'] := p; r[ind]['Text'] := p.Text(); - r[ind]['numId'] := numId; //数字项目编号 + r[ind]['numId'] := ifnumber(numId) ? integer(numId) : 0; //数字项目编号 r[ind]['ilvl'] := ilvl; //级别 r[ind]['numArr'] := numArr; //累加数字编码 sectPr.Mark(ind);//标记段落 @@ -13860,13 +13985,14 @@ Type TDocumentBody = Class(DocObject) return id; End; - Function addPart(posOpt, o); + Function addPart(posOpt, o, flag); Begin node := posOpt; if ifObj(posOpt) and not (posOpt is Class(XmlNode)) then node := posOpt.Node(); node := findNode(node, true); - nodeArr := o.Marshal(); + if flag then nodeArr := o.node_.Marshal()[0]; + else nodeArr := o.Marshal(); if ifObj(node) then Begin o.node_ := node_.InsertAfterChild(node, nodeArr); //XmlNode节点对象或DocObject对象 End @@ -14242,12 +14368,13 @@ Type TCell = Class(TDocumentBody, TWTc) Function Create(node);overload; Begin Class(TDocumentBody).Create(node); - Create(nil, 'w:tc'); + Create(node, 'w:tc'); End; Function Create(pNode, name);overload; Begin - Class(TWTc).Create(pNode, 'w:tc'); + Class(TWTc).Create(nil, 'w:tc'); + InitRootNode(pNode); name_ := 'w:tc'; mergeSpan_ := 0; pPr_ := new TwpPr(); @@ -14412,23 +14539,23 @@ Type TTable = Class(DocObject, TTableImpl) data := array(fields) union data; End; Data_ := data; - //TblPr.StyleId := 'Normal Table'; + TblPr.StyleId := _GetStyle(docx, 'normaltable'); TblPr.Width := 0; TblPr.WidthType := 'auto'; - TblPr.Borders.Top.Val := 'single'; - TblPr.Borders.Left.Val := 'single'; - TblPr.Borders.Bottom.Val := 'single'; - TblPr.Borders.Right.Val := 'single'; - TblPr.Borders.InsideH.Val := 'single'; - TblPr.Borders.InsideV.Val := 'single'; - TblPr.CellMar.Top := 0; - TblPr.CellMar.Left := 108; - TblPr.CellMar.Bottom := 0; - TblPr.CellMar.Right := 108; - TblPr.CellMar.TopType := 'dxa'; - TblPr.CellMar.LeftType := 'dxa'; - TblPr.CellMar.BottomType := 'dxa'; - TblPr.CellMar.RightType := 'dxa'; + //TblPr.Borders.Top.Val := 'single'; + //TblPr.Borders.Left.Val := 'single'; + //TblPr.Borders.Bottom.Val := 'single'; + //TblPr.Borders.Right.Val := 'single'; + //TblPr.Borders.InsideH.Val := 'single'; + //TblPr.Borders.InsideV.Val := 'single'; + //TblPr.CellMar.Top := 0; + //TblPr.CellMar.Left := 108; + //TblPr.CellMar.Bottom := 0; + //TblPr.CellMar.Right := 108; + //TblPr.CellMar.TopType := 'dxa'; + //TblPr.CellMar.LeftType := 'dxa'; + //TblPr.CellMar.BottomType := 'dxa'; + //TblPr.CellMar.RightType := 'dxa'; //TblPr.FirstColumn := 1; //TblPr.FirstRow := 1; //TblPr.LastColumn := 0; @@ -14449,7 +14576,16 @@ Type TTable = Class(DocObject, TTableImpl) End; TblGrid.GridCol := gridArr; End; - + + Function _GetStyle(obj, id); + Begin + style := obj.StyleObject().GetStyleById(id); + if not ifObj(style) then Begin + style := obj.StyleObject().AddDefaultStyle(id); + End; + return style.StyleId; + End; + Property Format read readFormat; Function readFormat(); Begin @@ -14506,6 +14642,45 @@ Type TTable = Class(DocObject, TTableImpl) if n >0 and n <= length(TblGrid.GridCol) then TblGrid.GridCol[n-1]['obj'].W := wth; End; + + /// 设置行高 + Function RowHeight(row, height); + Begin + if row <= 0 or row > Rows() then return; + node := node_.FirstChildElement('w:tr'); + cnt := row - 1; + while(cnt) do + begin + node := node.NextElement('w:tr'); + cnt--; + end + trnode := node.FirstChildElement("w:trPr"); + if not ifObj(trnode) then trnode := node.InsertFirstChild('element', 'w:trPr'); + node := trnode.FirstChildElement('w:trHeight'); + if not ifObj(node) then node := trnode.InsertFirstChild('element', 'w:trHeight'); + node.SetAttribute('w:val', height); + End; + + Function Height(row); + Begin + if row <= 0 or row > Rows() then return nil; + node := node_.FirstChildElement('w:tr'); + cnt := row - 1; + while(cnt) do + begin + node := node.NextElement('w:tr'); + cnt--; + end + obj := new TwTr(); + obj.InitRootNode(node); + return obj.TrPr.Value('Height'); + End; + + Function Width(col); + Begin + obj := Cell(1, col); + return obj.Format.Value('Width'); + End; ///合并单元格 ///del: bool,是否删除其它单元格内容(只保留左上单元格内容) @@ -14891,6 +15066,11 @@ Type TDocxStyle = Class(TDocxStyleImpl) class(TSXml).UpdateNode(pPr_.Root(), arr['attributes'], arr['children']); End; End; + + arr := self.Marshal(); + if length(arr['attributes']) or length(arr['children']) then Begin + class(TSXml).UpdateNode(node_, arr['attributes'], arr['children']); + End; End; node_; diff --git a/funcext/TSOffice/TOfficeTemplate.tsf b/funcext/TSOffice/TOfficeTemplate.tsf index 0a34fbe..4306f42 100644 --- a/funcext/TSOffice/TOfficeTemplate.tsf +++ b/funcext/TSOffice/TOfficeTemplate.tsf @@ -59,7 +59,12 @@ Type TTemplateObj = class map_["wstyle/heading8char.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJjaGFyYWN0ZXIiIHc6Y3VzdG9tU3R5bGU9IjEiIHc6c3R5bGVJZD0iSGVhZGluZzhDaGFyIj4NCgk8dzpuYW1lIHc6dmFsPSJIZWFkaW5nIDggQ2hhciIgLz4NCgk8dzpiYXNlZE9uIHc6dmFsPSJEZWZhdWx0UGFyYWdyYXBoRm9udCIgLz4NCgk8dzpsaW5rIHc6dmFsPSJIZWFkaW5nOCIgLz4NCgk8dzp1aVByaW9yaXR5IHc6dmFsPSI5IiAvPg0KCTx3OnNlbWlIaWRkZW4gLz4NCgk8dzpyc2lkIHc6dmFsPSIwMEZDNjkzRiIgLz4NCgk8dzpyUHI+DQoJCTx3OnJGb250cyB3OmFzY2lpVGhlbWU9Im1ham9ySEFuc2kiIHc6ZWFzdEFzaWFUaGVtZT0ibWFqb3JFYXN0QXNpYSIgdzpoQW5zaVRoZW1lPSJtYWpvckhBbnNpIiB3OmNzdGhlbWU9Im1ham9yQmlkaSIgLz4NCgkJPHc6Y29sb3Igdzp2YWw9IjRGODFCRCIgdzp0aGVtZUNvbG9yPSJhY2NlbnQxIiAvPg0KCQk8dzpzeiB3OnZhbD0iMjAiIC8+DQoJCTx3OnN6Q3Mgdzp2YWw9IjIwIiAvPg0KCTwvdzpyUHI+DQo8L3c6c3R5bGU+DQo=","binary":nil); map_["wstyle/heading9.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJwYXJhZ3JhcGgiIHc6c3R5bGVJZD0iSGVhZGluZzkiPg0KCTx3Om5hbWUgdzp2YWw9ImhlYWRpbmcgOSIgLz4NCgk8dzpiYXNlZE9uIHc6dmFsPSJOb3JtYWwiIC8+DQoJPHc6bmV4dCB3OnZhbD0iTm9ybWFsIiAvPg0KCTx3Omxpbmsgdzp2YWw9IkhlYWRpbmc5Q2hhciIgLz4NCgk8dzp1aVByaW9yaXR5IHc6dmFsPSI5IiAvPg0KCTx3OnNlbWlIaWRkZW4gLz4NCgk8dzp1bmhpZGVXaGVuVXNlZCAvPg0KCTx3OnFGb3JtYXQgLz4NCgk8dzpyc2lkIHc6dmFsPSIwMEZDNjkzRiIgLz4NCgk8dzpwUHI+DQoJCTx3OmtlZXBOZXh0IC8+DQoJCTx3OmtlZXBMaW5lcyAvPg0KCQk8dzpzcGFjaW5nIHc6YmVmb3JlPSIyMDAiIHc6YWZ0ZXI9IjAiIC8+DQoJCTx3Om91dGxpbmVMdmwgdzp2YWw9IjgiIC8+DQoJPC93OnBQcj4NCgk8dzpyUHI+DQoJCTx3OnJGb250cyB3OmFzY2lpVGhlbWU9Im1ham9ySEFuc2kiIHc6ZWFzdEFzaWFUaGVtZT0ibWFqb3JFYXN0QXNpYSIgdzpoQW5zaVRoZW1lPSJtYWpvckhBbnNpIiB3OmNzdGhlbWU9Im1ham9yQmlkaSIgLz4NCgkJPHc6aSAvPg0KCQk8dzppQ3MgLz4NCgkJPHc6Y29sb3Igdzp2YWw9IjQwNDA0MCIgdzp0aGVtZUNvbG9yPSJ0ZXh0MSIgdzp0aGVtZVRpbnQ9IkJGIiAvPg0KCQk8dzpzeiB3OnZhbD0iMjAiIC8+DQoJCTx3OnN6Q3Mgdzp2YWw9IjIwIiAvPg0KCTwvdzpyUHI+DQo8L3c6c3R5bGU+DQo=","binary":nil); map_["wstyle/heading9char.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJjaGFyYWN0ZXIiIHc6Y3VzdG9tU3R5bGU9IjEiIHc6c3R5bGVJZD0iSGVhZGluZzlDaGFyIj4NCgk8dzpuYW1lIHc6dmFsPSJIZWFkaW5nIDkgQ2hhciIgLz4NCgk8dzpiYXNlZE9uIHc6dmFsPSJEZWZhdWx0UGFyYWdyYXBoRm9udCIgLz4NCgk8dzpsaW5rIHc6dmFsPSJIZWFkaW5nOSIgLz4NCgk8dzp1aVByaW9yaXR5IHc6dmFsPSI5IiAvPg0KCTx3OnNlbWlIaWRkZW4gLz4NCgk8dzpyc2lkIHc6dmFsPSIwMEZDNjkzRiIgLz4NCgk8dzpyUHI+DQoJCTx3OnJGb250cyB3OmFzY2lpVGhlbWU9Im1ham9ySEFuc2kiIHc6ZWFzdEFzaWFUaGVtZT0ibWFqb3JFYXN0QXNpYSIgdzpoQW5zaVRoZW1lPSJtYWpvckhBbnNpIiB3OmNzdGhlbWU9Im1ham9yQmlkaSIgLz4NCgkJPHc6aSAvPg0KCQk8dzppQ3MgLz4NCgkJPHc6Y29sb3Igdzp2YWw9IjQwNDA0MCIgdzp0aGVtZUNvbG9yPSJ0ZXh0MSIgdzp0aGVtZVRpbnQ9IkJGIiAvPg0KCQk8dzpzeiB3OnZhbD0iMjAiIC8+DQoJCTx3OnN6Q3Mgdzp2YWw9IjIwIiAvPg0KCTwvdzpyUHI+DQo8L3c6c3R5bGU+DQo=","binary":nil); + map_["wstyle/normaltable.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJ0YWJsZSIgdzpzdHlsZUlkPSJub3JtYWx0YWJsZSI+DQogICAgPHc6bmFtZSB3OnZhbD0iVGFibGUgR3JpZCIgLz4NCiAgICA8dzpiYXNlZE9uIHc6dmFsPSJhMSIgLz4NCiAgICA8dzp1aVByaW9yaXR5IHc6dmFsPSIzOSIgLz4NCiAgICA8dzpyc2lkIHc6dmFsPSIwMDc4NkFERSIgLz4NCiAgICA8dzp0YmxQcj4NCiAgICAgICAgPHc6dGJsQm9yZGVycz4NCiAgICAgICAgICAgIDx3OnRvcCB3OnZhbD0ic2luZ2xlIiB3OnN6PSI0IiB3OnNwYWNlPSIwIiB3OmNvbG9yPSJhdXRvIiAvPg0KICAgICAgICAgICAgPHc6bGVmdCB3OnZhbD0ic2luZ2xlIiB3OnN6PSI0IiB3OnNwYWNlPSIwIiB3OmNvbG9yPSJhdXRvIiAvPg0KICAgICAgICAgICAgPHc6Ym90dG9tIHc6dmFsPSJzaW5nbGUiIHc6c3o9IjQiIHc6c3BhY2U9IjAiIHc6Y29sb3I9ImF1dG8iIC8+DQogICAgICAgICAgICA8dzpyaWdodCB3OnZhbD0ic2luZ2xlIiB3OnN6PSI0IiB3OnNwYWNlPSIwIiB3OmNvbG9yPSJhdXRvIiAvPg0KICAgICAgICAgICAgPHc6aW5zaWRlSCB3OnZhbD0ic2luZ2xlIiB3OnN6PSI0IiB3OnNwYWNlPSIwIiB3OmNvbG9yPSJhdXRvIiAvPg0KICAgICAgICAgICAgPHc6aW5zaWRlViB3OnZhbD0ic2luZ2xlIiB3OnN6PSI0IiB3OnNwYWNlPSIwIiB3OmNvbG9yPSJhdXRvIiAvPg0KICAgICAgICA8L3c6dGJsQm9yZGVycz4NCiAgICA8L3c6dGJsUHI+DQo8L3c6c3R5bGU+","binary":nil); map_["wstyle/title.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJwYXJhZ3JhcGgiIHc6c3R5bGVJZD0iVGl0bGUiPg0KCTx3Om5hbWUgdzp2YWw9IlRpdGxlIiAvPg0KCTx3OmJhc2VkT24gdzp2YWw9Ik5vcm1hbCIgLz4NCgk8dzpuZXh0IHc6dmFsPSJOb3JtYWwiIC8+DQoJPHc6bGluayB3OnZhbD0iVGl0bGVDaGFyIiAvPg0KCTx3OnVpUHJpb3JpdHkgdzp2YWw9IjEwIiAvPg0KCTx3OnFGb3JtYXQgLz4NCgk8dzpyc2lkIHc6dmFsPSIwMEZDNjkzRiIgLz4NCgk8dzpwUHI+DQoJCTx3OnBCZHI+DQoJCQk8dzpib3R0b20gdzp2YWw9InNpbmdsZSIgdzpzej0iOCIgdzpzcGFjZT0iNCIgdzpjb2xvcj0iNEY4MUJEIiB3OnRoZW1lQ29sb3I9ImFjY2VudDEiIC8+DQoJCTwvdzpwQmRyPg0KCQk8dzpzcGFjaW5nIHc6YWZ0ZXI9IjMwMCIgdzpsaW5lPSIyNDAiIHc6bGluZVJ1bGU9ImF1dG8iIC8+DQoJCTx3OmNvbnRleHR1YWxTcGFjaW5nIC8+DQoJPC93OnBQcj4NCgk8dzpyUHI+DQoJCTx3OnJGb250cyB3OmFzY2lpVGhlbWU9Im1ham9ySEFuc2kiIHc6ZWFzdEFzaWFUaGVtZT0ibWFqb3JFYXN0QXNpYSIgdzpoQW5zaVRoZW1lPSJtYWpvckhBbnNpIiB3OmNzdGhlbWU9Im1ham9yQmlkaSIgLz4NCgkJPHc6Y29sb3Igdzp2YWw9IjE3MzY1RCIgdzp0aGVtZUNvbG9yPSJ0ZXh0MiIgdzp0aGVtZVNoYWRlPSJCRiIgLz4NCgkJPHc6c3BhY2luZyB3OnZhbD0iNSIgLz4NCgkJPHc6a2VybiB3OnZhbD0iMjgiIC8+DQoJCTx3OnN6IHc6dmFsPSI1MiIgLz4NCgkJPHc6c3pDcyB3OnZhbD0iNTIiIC8+DQoJPC93OnJQcj4NCjwvdzpzdHlsZT4NCg==","binary":nil); map_["wstyle/titlechar.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJjaGFyYWN0ZXIiIHc6Y3VzdG9tU3R5bGU9IjEiIHc6c3R5bGVJZD0iVGl0bGVDaGFyIj4NCgk8dzpuYW1lIHc6dmFsPSJUaXRsZSBDaGFyIiAvPg0KCTx3OmJhc2VkT24gdzp2YWw9IkRlZmF1bHRQYXJhZ3JhcGhGb250IiAvPg0KCTx3Omxpbmsgdzp2YWw9IlRpdGxlIiAvPg0KCTx3OnVpUHJpb3JpdHkgdzp2YWw9IjEwIiAvPg0KCTx3OnJzaWQgdzp2YWw9IjAwRkM2OTNGIiAvPg0KCTx3OnJQcj4NCgkJPHc6ckZvbnRzIHc6YXNjaWlUaGVtZT0ibWFqb3JIQW5zaSIgdzplYXN0QXNpYVRoZW1lPSJtYWpvckVhc3RBc2lhIiB3OmhBbnNpVGhlbWU9Im1ham9ySEFuc2kiIHc6Y3N0aGVtZT0ibWFqb3JCaWRpIiAvPg0KCQk8dzpjb2xvciB3OnZhbD0iMTczNjVEIiB3OnRoZW1lQ29sb3I9InRleHQyIiB3OnRoZW1lU2hhZGU9IkJGIiAvPg0KCQk8dzpzcGFjaW5nIHc6dmFsPSI1IiAvPg0KCQk8dzprZXJuIHc6dmFsPSIyOCIgLz4NCgkJPHc6c3ogdzp2YWw9IjUyIiAvPg0KCQk8dzpzekNzIHc6dmFsPSI1MiIgLz4NCgk8L3c6clByPg0KPC93OnN0eWxlPg0K","binary":nil); + map_["wstyle/toc.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJwYXJhZ3JhcGgiIHc6c3R5bGVJZD0iVE9DIj4NCiAgICA8dzpuYW1lIHc6dmFsPSJUT0MgSGVhZGluZyIgLz4NCiAgICA8dzpiYXNlZE9uIHc6dmFsPSIxIiAvPg0KICAgIDx3Om5leHQgdzp2YWw9ImEiIC8+DQogICAgPHc6dWlQcmlvcml0eSB3OnZhbD0iMzkiIC8+DQogICAgPHc6dW5oaWRlV2hlblVzZWQgLz4NCiAgICA8dzpxRm9ybWF0IC8+DQogICAgPHc6cnNpZCB3OnZhbD0iMDA4OTZGN0QiIC8+DQogICAgPHc6cFByPg0KICAgICAgICA8dzpzcGFjaW5nIHc6YmVmb3JlPSIyNDAiIHc6bGluZT0iMjU5IiB3OmxpbmVSdWxlPSJhdXRvIiAvPg0KICAgICAgICA8dzpvdXRsaW5lTHZsIHc6dmFsPSI5IiAvPg0KICAgIDwvdzpwUHI+DQogICAgPHc6clByPg0KICAgICAgICA8dzpiIHc6dmFsPSIwIiAvPg0KICAgICAgICA8dzpiQ3Mgdzp2YWw9IjAiIC8+DQogICAgICAgIDx3OnN6IHc6dmFsPSIzMiIgLz4NCiAgICAgICAgPHc6c3pDcyB3OnZhbD0iMzIiIC8+DQogICAgPC93OnJQcj4NCjwvdzpzdHlsZT4=","binary":nil); + map_["wstyle/toc1.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJwYXJhZ3JhcGgiIHc6c3R5bGVJZD0iVE9DMSI+DQoJPHc6bmFtZSB3OnZhbD0idG9jIDEiIC8+DQoJPHc6YmFzZWRPbiB3OnZhbD0iYSIgLz4NCgk8dzpuZXh0IHc6dmFsPSJhIiAvPg0KCTx3OmF1dG9SZWRlZmluZSAvPg0KCTx3OnVpUHJpb3JpdHkgdzp2YWw9IjM5IiAvPg0KCTx3OnVuaGlkZVdoZW5Vc2VkIC8+DQoJPHc6cnNpZCB3OnZhbD0iMDA4RDQ3NkQiIC8+DQogICAgPHc6cFByIC8+DQogICAgPHc6clByIC8+DQo8L3c6c3R5bGU+DQo=","binary":nil); + map_["wstyle/toc2.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJwYXJhZ3JhcGgiIHc6c3R5bGVJZD0iVE9DMiI+DQoJPHc6bmFtZSB3OnZhbD0idG9jIDIiIC8+DQoJPHc6YmFzZWRPbiB3OnZhbD0iYSIgLz4NCgk8dzpuZXh0IHc6dmFsPSJhIiAvPg0KCTx3OmF1dG9SZWRlZmluZSAvPg0KCTx3OnVpUHJpb3JpdHkgdzp2YWw9IjM5IiAvPg0KCTx3OnVuaGlkZVdoZW5Vc2VkIC8+DQoJPHc6cnNpZCB3OnZhbD0iMDA4RDQ3NkQiIC8+DQoJPHc6cFByPg0KCQk8dzppbmQgdzpsZWZ0Q2hhcnM9IjIwMCIgdzpsZWZ0PSI0MjAiIC8+DQoJPC93OnBQcj4NCiAgICA8dzpyUHIgLz4NCjwvdzpzdHlsZT4NCg==","binary":nil); + map_["wstyle/toc3.xml"] := array("base64":"PHc6c3R5bGUgdzp0eXBlPSJwYXJhZ3JhcGgiIHc6c3R5bGVJZD0iVE9DMyI+DQoJPHc6bmFtZSB3OnZhbD0idG9jIDMiIC8+DQoJPHc6YmFzZWRPbiB3OnZhbD0iYSIgLz4NCgk8dzpuZXh0IHc6dmFsPSJhIiAvPg0KCTx3OmF1dG9SZWRlZmluZSAvPg0KCTx3OnVpUHJpb3JpdHkgdzp2YWw9IjM5IiAvPg0KCTx3OnVuaGlkZVdoZW5Vc2VkIC8+DQoJPHc6cnNpZCB3OnZhbD0iMDA4RDQ3NkQiIC8+DQoJPHc6cFByPg0KCQk8dzppbmQgdzpsZWZ0Q2hhcnM9IjQwMCIgdzpsZWZ0PSI4NDAiIC8+DQoJPC93OnBQcj4NCiAgICA8dzpyUHIgLz4NCjwvdzpzdHlsZT4NCg==","binary":nil); End; End; diff --git a/funcext/TSOffice/TSDocxFile.tsf b/funcext/TSOffice/TSDocxFile.tsf index 8173458..ca72dc0 100644 --- a/funcext/TSOffice/TSDocxFile.tsf +++ b/funcext/TSOffice/TSDocxFile.tsf @@ -1,4 +1,4 @@ -// Version 1.3.5 +// Version 1.4.4 Type TSDocxFile = Class ///Version: V1.0 2022-09-20 @@ -49,6 +49,7 @@ Type TSDocxFile = Class Function OpenFile(alias, fname, passwd); Begin if not ifObj(zipfile_) then return array(-1, 'Create ZipFile object fail.'); + if zipfile_.FilesCount() > 0 then zipfile_ := new ZipFile(); [err, errmsg] := zipfile_.Open(alias, fname, passwd); if err=0 then Begin document_ := new docxDocument(zipfile_); @@ -140,6 +141,7 @@ Type TSDocxFile = Class ///返回TParagraph对象 Function AddHeading(title, posOpt, level); Begin + if ifstring(level) then return document_.Body().AddHeading(title, getPosNode(posOpt), level); styleName := level = 0 ? 'Title' : 'Heading ' $ level; style := StyleObject().GetStyle(styleName); if not ifObj(style) and ifInt(level) and level >= 0 and level <= 9 then @@ -206,7 +208,7 @@ Type TSDocxFile = Class End; ///word文档指定表格 - ///n: int 第n个表格 + ///n: int 从0开始,第n个表格 ///返回:TTable对象 Function GetTable(n); Begin @@ -369,6 +371,24 @@ Type TSDocxFile = Class End; return nil; End; + + ///复制Word内容 + ///docxObj: TSDocxFile对象 + ///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加图片 + ///返回: [err, TDocxCopy对象] + ///TDocxCopy.GetCopiedTable() 返回复制的对象表格数组 + ///TDocxCopy.GetCopiedParagraph() 返回复制对象的段落数组 + ///TDocxCopy.GetCopiedDrawing() 返回复制对象的图表数组 + Function InsertFile(alias, fileName, posOpt); + Begin + docxObj := new TSDocxFile(); + [err, msg] := docxObj.OpenFile(alias, fileName); + if err then return array(err, msg); + copy_obj := new TDocxCopy(self, docxObj); + copy_obj.Init(); + copy_obj.Copy(posOpt); + return array(0, copy_obj); + End; ///遍历文档中所有[TSTAG][/TSTAG]标签,针对每一个TAG执行tagObj.Apply() ///tagName:string 标签名称 @@ -480,7 +500,7 @@ Type TSDocxFile = Class content.node_ := document_.Body().node_.InsertAfterChild(node, content.Marshal()); else content.node_ := document_.Body().node_.InsertFirstChild(content.Marshal()); - AddPageBreak(content.node_); + //AddPageBreak(content.node_); return content; End; @@ -559,8 +579,8 @@ Type TSDocxFile = Class DocPrId_ ++; return DocPrId_; End; -private - Function getPosNode(posOpt); + + Function GetPosNode(posOpt); Begin node := posOpt; if ifObj(node) and not (node is Class(XmlNode)) then diff --git a/funcext/TSOffice/TSExcelFile.tsf b/funcext/TSOffice/TSExcelFile.tsf index e3cee24..4dbce57 100644 --- a/funcext/TSOffice/TSExcelFile.tsf +++ b/funcext/TSOffice/TSExcelFile.tsf @@ -1,4 +1,4 @@ -// Version 1.3.5 +// Version 1.4.4 Type TSExcelFile = Class ///Version: V1.0 2022-08-08 @@ -49,8 +49,8 @@ Type TSExcelFile = Class ///返回: [err, errmsg] Function OpenFile(alias, fname, passwd); Begin - init(); if not ifObj(zipfile_) then return array(-1, 'Create ZipFile object fail.'); + if zipfile_.FilesCount() > 0 then zipfile_ := new ZipFile(); [err, errmsg] := zipfile_.Open(alias, fname, passwd); if err=0 then Begin workbook_ := new xlsxWorkBook(zipfile_); diff --git a/funcext/TSOffice/TSUtils/NodeInfo.tsf b/funcext/TSOffice/TSUtils/NodeInfo.tsf index f8a40e7..964fc29 100644 --- a/funcext/TSOffice/TSUtils/NodeInfo.tsf +++ b/funcext/TSOffice/TSUtils/NodeInfo.tsf @@ -1,10 +1,10 @@ Type NodeInfo = class public - Function Create(p, name); + Function Create(parentObj, name); Begin - if ifObj(p) then - NodeUri := p.NodeUri = '' ? name : (p.NodeUri + '/' + name); + if ifObj(parentObj) then + NodeUri := parentObj.NodeUri = '' ? name : (parentObj.NodeUri + '/' + name); else NodeUri := ''; NodeName := name; @@ -98,8 +98,9 @@ public arr := array('type': 'element', 'name': children_[i]['name'], 'attributes': array()); if node_type = 'empty' then // begin - if obj = 0 then arr['attributes'] := array('val': 0); - else if obj = 1 then arr['attributes'] := array('val': 1) + empty_name := children_[i]['attrEx'] ? children_[i]['attrEx'] : 'val'; + if obj = 0 then arr['attributes'] := array(empty_name: 0); + else if obj = 1 then arr['attributes'] := array(empty_name: 1) end else if node_type = 'pcdata' then begin @@ -270,7 +271,7 @@ public ExtNodes; //Parent; ReplaceArr; - RootObj; + RootObj; // xml node NodeUri:string; children_; End diff --git a/funcext/TSOffice/TSUtils/TSXml.tsf b/funcext/TSOffice/TSUtils/TSXml.tsf index 8218d22..326849a 100644 --- a/funcext/TSOffice/TSUtils/TSXml.tsf +++ b/funcext/TSOffice/TSUtils/TSXml.tsf @@ -408,6 +408,7 @@ Type TSXml = Class class Function SafeStrToIntDef(s, defaultV); Begin + if ifnumber(s) then return integer(s); if not ifstring(s) then return defaultV; return StrToIntDef(s, defaultV); diff --git a/funcext/TSOffice/document/TDocxCopy.tsf b/funcext/TSOffice/document/TDocxCopy.tsf new file mode 100644 index 0000000..994e409 --- /dev/null +++ b/funcext/TSOffice/document/TDocxCopy.tsf @@ -0,0 +1,450 @@ +Type TDocxCopy = class + + Function Create(oldObj, newObj) + Begin + old_docx_obj_ := oldObj; + new_docx_obj_ := newObj; + copy_table_ := array(); + copy_paragraph_ := array(); + copy_drawing_ := array(); + style_copy_obj_ := new TDocxStyleCopy(oldObj.StyleObject(), newObj.StyleObject()); + number_copy_obj_ := new TDocxNumberCopy(oldObj, newObj); + End; + + Function Init(); + Begin + style_copy_obj_.Init(); + End; + + ///从posOpt位置开始复制word + ///posOpt: 段落位置,0 在DOCX文件开头;-1 文件尾;N 在第N段之后;XmlNode节点对象或DocObject对象 在posOpt之后新添加图片 + Function Copy(posOpt); + Begin + // 复制所有的样式 + style_copy_obj_.CopyStyle(); + + parts := new_docx_obj_.Body().Parts(); + pos := old_docx_obj_.GetPosNode(posOpt); + for i:=0 to length(parts)-1 do + begin + case GetPartType(parts[i]) of + 0: pos := CopyParagraph(parts[i], pos); + 1: pos := CopyDrawing(parts[i], pos); + 2: pos := CopyTable(parts[i], pos); + end; + end + End; + + Function CopyParagraph(obj, pos); + Begin + paragraph := old_docx_obj_.Body().CopyWp(obj, pos); + SetParagraphInfo(paragraph); + copy_paragraph_[length(copy_paragraph_)] := paragraph; + return paragraph; + End; + + Function CopyDrawing(obj, pos); + Begin + paragraph := old_docx_obj_.Body().CopyWp(obj, pos); + SetDrawingInfo(paragraph); + copy_drawing_[length(copy_drawing_)] := paragraph; + return paragraph; + End; + + Function CopyTable(obj, pos); + Begin + table := old_docx_obj_.Body().CopyWtbl(obj, pos); + SetTableInfo(table); + copy_table_[length(copy_table_)] := table; + return table; + End; + + Function GetCopiedTable(); + Begin + return copy_table_; + End; + + Function GetCopiedParagraph(); + Begin + return copy_paragraph_; + End; + + Function GetCopiedDrawing(); + Begin + return copy_drawing_; + End; + +private + + Function DeleteComment(paragraph); + Begin + node := paragraph.node_.FirstChildElement('w:commentRangeStart'); + while ifObj(node) do + begin + name := node.GetName(); + if name = "w:commentRangeStart" or name = "w:commentRangeEnd" then + begin + delete_node := node; + node := node.NextElement(); + paragraph.node_.DeleteChild(delete_node); + if node.FirstChildElement('w:commentReference') then + begin + delete_node := node; + node := node.NextElement(); + paragraph.node_.DeleteChild(delete_node); + end + end + else begin + node := node.NextElement(); + end + end + End; + + Function SetPic(node); + Begin + // 获取新文件的图片 + rembed := node.GetAttribute('r:embed'); + rels := new_docx_obj_.Zip().Get('word/_rels/document.xml.rels'); + target := class(TSXml).FindRelationshipTarget(rels, rembed); + image_file := new_docx_obj_.Zip().Get('word/' $ target).Data(); + + // 比较新文件的图片在旧文件中是否存在 + zip := old_docx_obj_.Zip(); + files := sselect ['FileName'] from zip.Files() where AnsiStartsText('word/media/image', ['FileName']) end; + for i:=0 to length(files)-1 do Begin + if zip.Diff(files[i], image_file) = 0 then Begin + prefix := ReplaceStr(files[i], 'word/', ''); + [maxRid, imageFile, rid] := class(TSXml).FindRelationshipRid(xml, prefix); + End; + End; + xml := zip.Get('word/_rels/document.xml.rels'); + if rid = 0 then + begin + image_cnt := length(files) + 1; + if ParseRegExpr("\\w+$", target, "", result, Mpos, Mlen) then + begin + postfix := result[0][0]; + image_path := "media/image" $ image_cnt $ '.' $ postfix; + [rid, tar] := class(TSXml).FindRelationshipRid(xml, ''); + rid ++; + class(TSXml).AddRelationshipRid(xml, image_path, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image', 'rId' $ rid); + zip.Add('word/' + image_path, image_file); + contentXml := zip.Get('[Content_Types].xml'); + class(TSXml).AddDefaultContentType(contentXml, postfix, 'image/' $ postfix); + node.SetAttribute('r:embed', 'rId' $ rid); + end + end + End; + + Function SetChart(node); + Begin + rid := node.GetAttribute('r:id'); + rels := new_docx_obj_.Zip().Get('word/_rels/document.xml.rels'); + target := class(TSXml).FindRelationshipTarget(rels, rid); + new_zip := new_docx_obj_.Zip(); + chart_file := new_zip.Get('word/' $ target); + + // 复制charN.xml + zip := old_docx_obj_.Zip(); + files := sselect ['FileName'] from zip.Files() where AnsiStartsText('word/charts/chart', ['FileName']) end; + new_chart_file := "charts/chart" $ (length(files) + 1) $ ".xml"; + xml := zip.Get('word/_rels/document.xml.rels'); + [new_rid, tar] := class(TSXml).FindRelationshipRid(xml, ''); + new_rid++; + class(TSXml).AddRelationshipRid(xml, new_chart_file, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", 'rId' $ new_rid); + zip.Add('word/' + new_chart_file, chart_file.Data()); + contentXml := zip.Get('[Content_Types].xml'); + class(TSXml).AddOverrideContentType(contentXml, '/word/' + new_chart_file, 'application/vnd.openxmlformats-officedocument.drawingml.chart+xml'); + node.SetAttribute('r:id', 'rId' $ new_rid); + + // 复制charN.xml.rels + chart_rels := "word/charts/_rels" + target[pos('/', target):] $ ".rels"; + chart_rels_xml := new_zip.Get(chart_rels); + if ifObj(chart_rels_xml) then + begin + zip.Add('word/charts/_rels/chart' $ (length(files) + 1) $ ".xml.rels", chart_rels_xml.Data()); + relationship := chart_rels_xml.FirstChildElement('Relationships').FirstChildElement('Relationship'); + while ifObj(relationship) do + begin + target := relationship.GetAttribute('Target'); + target_path := AnsiReplaceText(target, '..', 'word'); + file := new_zip.Get(target_path); + if ifObj(file) then + begin + [new_file, filetype] := GetNewTargetFileName(zip, target_path); + zip.Add(new_file, file.Data()); + if filetype then Class(TSXml).AddDefaultContentType(contentXml, filetype[2:], 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); + end + relationship := relationship.NextElement(); + end; + end + End; + + Function GetNewTargetFileName(zip, fileName); + Begin + files := zip.Files()[:, 'FileName']; + ret := ParseRegExpr("(.*/)(\\w+)(\.\\w+)$", fileName, "", result, Mpos, Mlen); + count := 0; + while fileName in files do + begin + if ret then + fileName := result[0][1] $ result[0][2] $ "tinysoft" $ count $ result[0][3]; + else fileName := fileName $ "tinysoft" $ count; + count++; + end + if ret then filetype := result[0][3]; + return array(fileName, filetype); + End; + + Function SetDrawingInfo(drawing); + Begin + graphic_node := class(TSXml).GetNode(drawing.node_,'w:r/w:drawing/wp:inline/a:graphic/a:graphicData'); + if ifObj(graphic_node) then + begin + node := class(TSXml).GetNode(graphic_node,'pic:pic/pic:blipFill/a:blip'); + if ifObj(node) then SetPic(node); + node := class(TSXml).GetNode(graphic_node, 'c:chart'); + if ifObj(node) then SetChart(node); + end; + End; + + Function SetParagraphInfo(paragraph); + Begin + style := class(TSXml).GetNode(paragraph.node_, 'w:pPr/w:pStyle'); + if ifObj(style) then + begin + styleid := style.GetAttribute('w:val'); + new_id := style_copy_obj_.GetStyleNewId(styleid); + if new_id then style.SetAttribute('w:val', new_id); + end + numpr := class(TSXml).GetNode(paragraph.node_, 'w:pPr/w:numPr/w:numId'); + if ifObj(numpr) then + begin + id := numpr.GetAttribute('w:val'); + numberid := number_copy_obj_.CopyNumbering(id); + numpr.SetAttribute('w:val', id); + end + DeleteComment(paragraph); // 删除批注 + End; + + Function SetTableInfo(table); + Begin + style := class(TSXml).GetNode(table.node_, 'w:tblPr/w:tblStyle'); + if ifObj(style) then + begin + id := style.GetAttribute('w:val'); + new_id := style_copy_obj_.GetStyleNewId(id); + if new_id then style.SetAttribute('w:val', new_id); + end + col := table.Cols(); + row := table.Rows(); + for r:=1 to row do + begin + for c:=1 to col do + begin + cell := table.Cell(r, c); + if not cell then continue; + node := cell.node_; + if (tbl := node.FirstChildElement('w:tbl')) then + begin + obj := TOfficeObj('TTable'); + obj.Init(tbl); + SetTableInfo(obj); + end + else if (p := node.FirstChildElement('w:p')) then + begin + draw := class(TSXml).GetNode(p, 'w:r/w:drawing'); + if ifObj(draw) then + begin + obj := TOfficeObj('TPicture'); + obj.Init(p); + SetDrawingInfo(obj); + end + else begin + obj := TOfficeObj('TParagraph'); + obj.Init(p); + SetParagraphInfo(obj); + end + end + end + end + End; + + /// 普通段落: 0 + /// 图片段落: 1 + /// 表格: 2 + /// 其他类型暂不复制 + Function GetPartType(part); + Begin + name := part.name_; + case name of + 'w:p': + begin + if class(TSXml).GetNode(part.node_, 'w:r/w:drawing') then return 1; + return 0; + end + 'w:tbl': + return 2; + else + return -1; + end + End; + +private + old_docx_obj_; + new_docx_obj_; + style_copy_obj_; + number_copy_obj_; + + copy_table_; + copy_paragraph_; + copy_drawing_; +End; + +Type TDocxStyleCopy = class + + Function Create(oldObj, newObj); + Begin + old_style_obj_ := oldObj; + new_style_obj_ := newObj; + style_id_map_ := array(); + style_name_map_ := array(); + style_id_map2_ := array(); + style_name_map2_ := array(); + id_map_ := array(); + End; + + Function Init(); + Begin + id_styles := new_style_obj_.Styles(); + for id, obj in id_styles do + begin + new_obj := obj; + id_map_[id] := new_obj; + SetId(new_obj, id); + SetName(new_obj); + end + End; + + Function CopyStyle(); + Begin + for id, obj in id_map_ do + begin + SetBasedOn(obj); + SetLink(obj); + old_style_obj_.CopyStyle(obj); + end; + End; + + Function GetStyleNewId(oldId) + Begin + if ifnumber(oldId) then oldId := tostring(oldId); + return style_id_map_[oldId]; + End; + +private + + Function SetId(obj, id); + Begin + new_id := GetNewId(id); + obj.node_.SetAttribute('w:styleId', new_id); + style_id_map_[id] := new_id; + style_id_map2_[new_id] := id; + End; + + Function SetName(obj); + Begin + name_node := obj.node_.FirstChildElement('w:name'); + name := name_node.GetAttribute('w:val'); + new_name := GetNewName(name); + name_node.SetAttribute('w:val', new_name); + style_name_map_[name] := new_name; + style_name_map2_[new_name] := name; + End; + + Function SetBasedOn(obj); + Begin + basedon := obj.node_.FirstChildElement('w:basedOn'); + if ifObj(basedon) then + begin + val := basedon.GetAttribute('w:val'); + if style_id_map_[val] then basedOn.SetAttribute('w:val', style_id_map_[val]); + end + End; + + Function SetLink(obj); + Begin + link := obj.node_.FirstChildElement('w:link'); + if ifObj(link) then + begin + val := link.GetAttribute('w:val'); + if style_id_map_[val] then link.SetAttribute('w:val', style_id_map_[val]); + end + End; + + Function GetNewName(name); + Begin + new_name := name; + count := 0; + while ifObj(old_style_obj_.GetStyle(new_name)) or style_name_map2_[new_name] do + new_name := new_name $ count++; + return new_name; + End; + + Function GetNewId(id); + Begin + new_id := id; + count := 0; + while ifObj(old_style_obj_.GetStyleById(new_id)) or style_id_map2_[new_id] do + new_id := new_id $ count++; + return new_id; + End; + +private + old_style_obj_; + new_style_obj_; + + style_id_map_; // [old_id: new_id]; + style_name_map_; // [old_name: new_name]; + style_id_map2_; // [new_id: old_id]; + style_name_map2_; // [old_name: new_name]; + + id_map_; // [id: styleobj] +End; + +Type TDocxNumberCopy = class + + Function Create(oldObj, newObj); + Begin + numberingxml := newObj.Zip().Get('word/numbering.xml'); + if ifObj(numberingxml) then + begin + old_number_obj_ := oldObj.NumberingObject(); + new_number_obj_ := newObj.NumberingObject(); + end + else begin + old_number_obj_ := nil; + new_number_obj_ := nil; + end + id_map_ := array(); + End; + + Function CopyNumbering(number); + Begin + if ifObj(old_number_obj_) and ifObj(new_number_obj_) then + begin + if (obj := new_number_obj_.NumberStyle(number)) and not id_map_[number] then + begin + number_obj := old_number_obj_.CopyNumber(obj); + id_map_[number] := number_obj; + return number_obj; + end + end; + End; + +private + old_number_obj_; + new_number_obj_; + + id_map_; // [id: styleobj] +End; diff --git a/funcext/TSOffice/document/TDocxStyles.tsf b/funcext/TSOffice/document/TDocxStyles.tsf index 8f7ec48..8911cad 100644 --- a/funcext/TSOffice/document/TDocxStyles.tsf +++ b/funcext/TSOffice/document/TDocxStyles.tsf @@ -52,7 +52,7 @@ Type TDocxStyles = Class ///返回:TDocxStyle对象 Function GetStyle(name); Begin - return nameMap_[ lowercase(name) ]; + return nameMap_[ class(TSXml).CurCodePageToUtf8(lowercase(name)) ]; End; ///返回指定StyleId名称的TDocxStyle @@ -60,7 +60,8 @@ Type TDocxStyles = Class ///返回:TDocxStyle对象 Function GetStyleById(id); Begin - return idMap_[ id ]; + newid := ifnumber(id) ? tostring(id) : id; + return idMap_[ newid ]; End; //返回全部LatentStyles对象列表 @@ -133,6 +134,23 @@ Type TDocxStyles = Class return nil; End; + ///复制样式 + ///newstyle:样式节点TDocxStyle对象 + ///返回:TDocxStyle对象 + Function CopyStyle(newstyle); + Begin + if ifObj(newstyle) and ifObj(newstyle.node_) then Begin + node := stylesXml_.FirstChildElement('w:styles').InsertEndChild(newstyle.node_.Marshal()[0]); + obj := TOfficeObj('TDocxStyle'); + obj.StyleId := node.GetAttribute('w:styleId'); + obj.Name := node.FirstChildElement('w:name').GetAttribute('w:val'); + obj.Init(node); + _addStyle(obj); + return obj; + End; + return nil; + End; + ///插入新的LatentStyle段落样式 ///o:TDocxStyle对象 ///返回:TDocxStyle对象 @@ -185,4 +203,4 @@ private idMap_; nameMap_; maxStyleId_:integer; -End; \ No newline at end of file +End; diff --git a/funcext/TSOffice/document/TNumbering.tsf b/funcext/TSOffice/document/TNumbering.tsf index cbfb2bf..f9c1d76 100644 --- a/funcext/TSOffice/document/TNumbering.tsf +++ b/funcext/TSOffice/document/TNumbering.tsf @@ -76,6 +76,19 @@ Type TNumbering = Class numIdMap_[''$num.numId] := num.abstractNumId; return num.numId; End; + + ///复制number样式 + ///numberObj: 样式xmlNode + Function CopyNumber(numberObj); + Begin + obj := AddStyle(numberObj, true); + num := TOfficeObj('TNumber'); + num.numId := maxNumId_++; + num.abstractNumId := obj.Id; + numberingXml_.FirstChildElement('w:numbering').InsertEndChild(num.Marshal()); + numIdMap_[''$num.numId] := num.abstractNumId; + return num.numId; + End; ///根据numId获取TNumStyle对象(已存在) ///返回:TNumStyle对象 @@ -148,14 +161,20 @@ Type TNumbering = Class ///新添加项目样式 ///o:TNumStyle对象 ///返回:TNumStyle对象 - Function AddStyle(o); + Function AddStyle(o, flag); Begin if ifObj(o) then Begin o.abstractNumId := maxAbstractNumId_++; + if flag then + begin + o.node_.SetAttribute('w:abstractNumId', o.abstractNumId); + marshal := o.node_.Marshal()[0]; + end + else marshal := o.Marshal(); if ifObj(lastAbstractNumStyle_) then - node := numberingXml_.FirstChildElement('w:numbering').InsertAfterChild(lastAbstractNumStyle_, o.Marshal()); + node := numberingXml_.FirstChildElement('w:numbering').InsertAfterChild(lastAbstractNumStyle_, marshal); else - node := numberingXml_.FirstChildElement('w:numbering').InsertFirstChild(o.Marshal()); + node := numberingXml_.FirstChildElement('w:numbering').InsertFirstChild(marshal); lastAbstractNumStyle_ := node; o := TOfficeObj('TNumStyle'); o.Init(node); diff --git a/funcext/TSOffice/document/TTableContent.tsf b/funcext/TSOffice/document/TTableContent.tsf index 7dac361..9d45b46 100644 --- a/funcext/TSOffice/document/TTableContent.tsf +++ b/funcext/TSOffice/document/TTableContent.tsf @@ -18,32 +18,36 @@ Type TTableContent = class Function SetDefaultFormat(); Begin - defultFont := impl_.stdPr.rPr; + defultFont := impl_.sdtPr.rPr; defultFont.rFont.cstheme := 'minorBidi'; defultFont.rFont.XMLeastAsia := '宋体'; defultFont.rFont.XMLhAnsi := '宋体'; defultFont.rFont.XMLascii := '宋体'; //defultFont.kern := 2; - defultFont.Size := 21; + defultFont.Size := 21/2; defultFont.SzCs := 24; defultFont.Lang := 'en-US'; defultFont.bidi := 'ar-SA'; defultFont.eastAsia := 'zh-CN'; defultFont.Color := 'DBDBDB'; - defultFormat := impl_.stdPr; + defultFormat := impl_.sdtPr; defultFormat.ID := integer(time()*24*3600); //defultFormat.Color := 'DBDBDB'; defultFormat.docPartObj.docPartGallery := 'Table of Contents'; defultFormat.docPartObj.docPartUnique := 1; - //impl_.stdEndPr.rPr.Size := 20; - //impl_.stdEndPr.rPr.SzCs := 20; - impl_.stdEndPr.rPr.Bold := true; + //impl_.sdtEndPr.rPr.Size := 21; + //impl_.sdtEndPr.rPr.SzCs := 22; + impl_.sdtEndPr.rPr.Bold := true; End; ///应用目录样式 Function Apply(); override; Begin - arr := impl_.Marshal(); + // sdtContent 不应该updateNode + tmp_impl := TOfficeObj('TTableContentImpl'); + tmp_impl.sdtPr := impl_.sdtPr; + tmp_impl.sdtEndPr := impl_.sdtEndPr; + arr := tmp_impl.Marshal(); class(TSXml).UpdateNode(node_, arr['attributes'], arr['children']); End; @@ -68,10 +72,12 @@ Type TTableContent = class mParagraph.pPr.RightIndent := 0; mParagraph.pPr.LeftChars := 0; mParagraph.pPr.LeftIndent := 0; + mParagraph.pPr.StyleID := _GetStyle('TOC'); mParagraph.Run.T := '目录'; - mParagraph.Run.rPr.SetName('宋体', true); - mParagraph.Run.rPr.Size := 21; - mParagraph.Run.rPr.Bold := true; + mParagraph.Run.rPr.Lang := 'zh-CN'; + //mParagraph.Run.rPr.SetName('宋体', true); + //mParagraph.Run.rPr.Size := 21/2; + //mParagraph.Run.rPr.Bold := true; _AddStdContent(mParagraph); goback := TOfficeObj('TParagraph'); @@ -79,13 +85,13 @@ Type TTableContent = class goback.MarkStart.Name := '_GoBack'; goback.MarkStart.ID := id; goback.MarkEnd.ID := id; - _AddStdContent(goback); + //_AddStdContent(goback); //缺省目录,需要word或wps打开后,更新目录 - _AddDefaultTableContent(UpperHeadingLevel, LowerHeadingLevel); + //_AddDefaultTableContent(UpperHeadingLevel, LowerHeadingLevel); //自定义页码计算与word、wps有差异,不推荐使用 - //_AddTableContent(posOpt, UpperHeadingLevel, LowerHeadingLevel); + _AddTableContent(posOpt, UpperHeadingLevel, LowerHeadingLevel); End; Function _AddDefaultTableContent(UpperHeadingLevel, LowerHeadingLevel); @@ -123,7 +129,7 @@ Type TTableContent = class //instrText r2 := p.AddRun(); r2.instrTextSpace := 'preserve'; - r2.instrText := 'TOC \\o \"' $ UpperHeadingLevel $ '-' $ LowerHeadingLevel $ '\" \\h \\u '; + r2.instrText := 'TOC \\o \"' $ UpperHeadingLevel $ '-' $ LowerHeadingLevel $ '\" \\h \\z \\u '; //fldCharType r3 := p.AddRun(); @@ -140,75 +146,74 @@ Type TTableContent = class for i:=0 to length(r)-1 do Begin p := _AddItem(UpperHeadingLevel, LowerHeadingLevel, r[i]['Level'], i = 0 ? true: false); //fldCharType - r4 := p.AddRun(); - r4.fldCharType := 'begin'; - - //instrText + h := p.AddHyperLink(); bookmarke := _GetBookMarkId(r[i]['Paragraph']); - r5 := p.AddRun(); - r5.instrTextSpace := 'preserve'; - r5.instrText := ' HYPERLINK \\l ' $ bookmarke $ ' '; - - //fldCharType - r6 := p.AddRun(); - r6.fldCharType := 'separate'; - - //目录条目文字内容 - r7 := p.AddRun(); - r7.Font.SetName('宋体', true); + h.Anchor := bookmarke; + h.history := 1; + + r1 := h.AddRun(); + r1.rPr.StyleId := _GetStyle(level); + r1.rPr.noProof := true; numStr := ''; //数字项目编号 if r[i]['numId'] then Begin style := docx_.NumberingObject().NumberStyle(r[i]['numId']);//支持数字、字符串StyleId if ifObj(style) then numStr := style.GetText(r[i]['ilvl'], r[i]['numArr']); End - r7.T := numStr + r[i]['Text']; - - //Tab - r8 := p.AddRun(); - r8.Tab := true; - - //fldCharType - r9 := p.AddRun(); - r9.fldCharType := 'begin'; - + if numStr <> '' then run_t := numStr + ' ' + r[i]['Text']; + else run_t := r[i]['Text']; + r1.SetText(run_t); + + r2 := h.AddRun(); + r2.rPr.noProof := true; + r2.rPr.WebHidden := true; + r2.Tab := true; + + r3 := h.AddRun(); + r3.rPr.noProof := true; + r3.rPr.WebHidden := true; + r3.fldCharType := 'begin'; + //instrText - r10 := p.AddRun(); - r10.instrTextSpace := 'preserve'; - r10.instrText := ' PAGEREF ' $ bookmarke $ ' \\h '; - + r4 := h.AddRun(); + r4.rPr.noProof := true; + r4.rPr.WebHidden := true; + r4.instrTextSpace := 'preserve'; + r4.instrText := ' PAGEREF ' $ bookmarke $ ' \\h '; + + r5 := h.AddRun(); + r5.rPr.noProof := true; + r5.rPr.WebHidden := true; + r5.Tab := true; + //fldCharType - r11 := p.AddRun(); - r11.fldCharType := 'separate'; - + r6 := h.AddRun(); + r6.rPr.noProof := true; + r6.rPr.WebHidden := true; + r6.fldCharType := 'separate'; + //页码 - r12 := p.AddRun(); - r12.T := '' $ r[i]['pageNo']; - + r7 := h.AddRun(); + r7.T := 0;//'' $ r[i]['pageNo']; + //fldCharType - r13 := p.AddRun(); - r13.fldCharType := 'end'; - - //fldCharType - r14 := p.AddRun(); - r14.fldCharType := 'end'; - - if r[i]['Level']+1 = UpperHeadingLevel then Begin //第一级标题,设置为粗体 - p.Format.rPr.Bold := true; - r4.rPr.Bold := true; - r5.rPr.Bold := true; - r6.rPr.Bold := true; - r7.rPr.Bold := true; - r8.rPr.Bold := true; - //r9.rPr.Bold := true; - r10.rPr.Bold := true; - //r11.rPr.Bold := true; - r12.Font.Bold := true; - //r13.rPr.Bold := true; - r14.rPr.Bold := true; - End; + r8 := h.AddRun(); + r8.rPr.noProof := true; + r8.rPr.WebHidden := true; + r8.fldCharType := 'end'; + _AddStdContent(p); + End; + + p2 := TOfficeObj('TParagraph'); + //p2.Format.SpaceAfter := 0; + run := p2.AddRun(); + run.rPr.Bold := true; + run.rPr.noProof := true; + run.fldCharType := 'end'; + _AddStdContent(p2); + End; ///更新目录 @@ -224,21 +229,21 @@ Type TTableContent = class Property Format read readFormat; Function readFormat(); Begin - return impl_.stdPr; + return impl_.sdtPr; End; Property EndFormat read readEndFormat; Function readEndFormat(); Begin - return impl_.stdEndPr; + return impl_.sdtEndPr; End; Property Font read readFont; Function readFont(); Begin - return impl_.stdPr.rPr; + return impl_.sdtPr.rPr; End; - + Function _AddStdContent(o); Begin impl_.SdtContent.NewChildNode( array("field":"", "name":"w:p", "obj":o, "attrEx":"", "nodeType":"") ); @@ -246,18 +251,10 @@ Type TTableContent = class Function _GetStyle(level); Begin - styleName := 'Tinysoft目录 ' $ (level + 1); - style := docx_.StyleObject().GetStyle(styleName); + styleName := ifstring(level) ? level : 'TOC' $ (level + 1); + style := docx_.StyleObject().GetStyleById(styleName); if not ifObj(style) then Begin - style := TOfficeObj('TDocxStyle'); - style.wType := 'paragraph'; - style.CustomStyle := 1; - style.Name := styleName; - style.uiPriority := 0; - style.pPr.LeftChars := 200 * level; - style.rPr.Size := 20; - style.rPr.SzCs := 20; - docx_.StyleObject().AddStyle(style, 'TsToc' $ (level + 1)); + style := docx_.StyleObject().AddDefaultStyle(styleName); End; return style.StyleId; End; @@ -301,4 +298,4 @@ Type TTableContent = class docx_; node_; impl_; -End; \ No newline at end of file +End; diff --git a/更新日志.md b/更新日志.md index 8af6991..1e8ec34 100644 --- a/更新日志.md +++ b/更新日志.md @@ -1,5 +1,79 @@ # 更新日志 +## 2023-8-28 + +### V1.4.4 + +#### word + +1. 修复`insertFile`样式错误问题 +2. 修复`insertFile`后删除段落再新增段落位置错误问题 +3. 修复生成目录中文编码未转换导致word打开失败问题 + +## 2023-8-22 + +### V1.4.3 + +#### word + +支持段落判空`TParagraph.Empty()` + +## 2023-8-18 + +### V1.4.2 + +#### word + +支持插入另一个word内容`InsertFile(alias, fileName, posOpt)` + +## 2023-8-11 + +### V1.4.1 + +#### word + +修复插入表格后,设置样式ID无法全部生效问题 + +## 2023-8-10 + +### V1.4.0 + +#### word + +支持三级以内目录设置字体,一级目录样式ID为`TOC1`,二级目录样式ID为`TOC2`,三级为`TOC3`,通过样式设置相关属性即可修改目录字体 + +## 2023-8-7 + +### V1.3.9 + +#### word + +支持`AddHeading`时传入样式Id + +## 2023-8-2 + +### V1.3.8 + +#### word + +修复插入图片后,设置对齐失效问题 + +## 2023-7-26 + +### V1.3.7 + +#### word + +新增表格获取高度和宽度方法`table.Height(row) table.Width(col)` + +## 2023-7-19 + +### V1.3.6 + +#### word + +新增对表格的行高设置`table.RowHeight(row, height)` + ## 2023-7-14 ### V1.3.5