1################################################################ 2# 3# Licensed to the Apache Software Foundation (ASF) under one 4# or more contributor license agreements. See the NOTICE file 5# distributed with this work for additional information 6# regarding copyright ownership. The ASF licenses this file 7# to you under the Apache License, Version 2.0 (the 8# "License"); you may not use this file except in compliance 9# with the License. You may obtain a copy of the License at 10# 11# http://www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, 14# software distributed under the License is distributed on an 15# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16# KIND, either express or implied. See the License for the 17# specific language governing permissions and limitations 18# under the License. 19 20"""Builders for documents the tests start from: each creates one or more documents through the API and stores them. Ported from the 21ODF harness's fixtures/*/make.py; the expected values read back from them are in data/checks/.""" 22import os 23import re 24import zipfile 25 26import uno 27from com.sun.star.awt import Gradient, Point, Size 28from com.sun.star.awt.GradientStyle import LINEAR 29from com.sun.star.drawing import Hatch 30from com.sun.star.drawing.BitmapMode import NO_REPEAT, REPEAT, STRETCH 31from com.sun.star.drawing.FillStyle import BITMAP, GRADIENT, HATCH, SOLID 32from com.sun.star.drawing.HatchStyle import SINGLE 33 34from aootest_worker.ops import core, scripts 35from aootest_worker.ops.core import pv 36from aootest_worker.ops.encrypted import _png 37 38 39def _grad(): 40 g = Gradient() 41 g.Style = LINEAR 42 g.StartColor, g.EndColor = 0xFF0000, 0x0000FF 43 g.Angle = g.Border = 0 44 g.XOffset = g.YOffset = 50 45 g.StartIntensity = g.EndIntensity = 100 46 g.StepCount = 0 47 return g 48 49 50def _new(kind): 51 doc = core._desktop().loadComponentFromURL("private:factory/" + kind, "_blank", 0, (pv("Hidden", True),)) 52 if doc is None: 53 raise core.Fail("uno", "could not create a new %s document" % kind) 54 return doc 55 56 57def _save(doc, outdir, name, flt): 58 try: 59 doc.storeToURL(uno.systemPathToFileUrl(os.path.join(outdir, name)), (pv("FilterName", flt),)) 60 finally: 61 core._close(doc) 62 return name 63 64 65def page_fill(outdir): 66 """Writer page styles whose page, header and footer carry each kind of fill (fixtures/page-fill/make.py).""" 67 png = os.path.join(outdir, "tile.png") 68 _png(png) 69 png_url = uno.systemPathToFileUrl(png) 70 doc = _new("swriter") 71 72 def hatch(): 73 h = Hatch() 74 h.Style, h.Color, h.Distance, h.Angle = SINGLE, 0x00AA00, 200, 450 75 return h 76 77 def fill(o, pre, kind, color=0xFFCC00): 78 if kind == "solid": 79 setattr(o, pre + "FillStyle", SOLID) 80 setattr(o, pre + "FillColor", color) 81 elif kind == "solid_transp": 82 setattr(o, pre + "FillStyle", SOLID) 83 setattr(o, pre + "FillColor", color) 84 setattr(o, pre + "FillTransparence", 40) 85 elif kind == "gradient": 86 setattr(o, pre + "FillStyle", GRADIENT) 87 setattr(o, pre + "FillGradient", _grad()) 88 elif kind == "hatch": 89 setattr(o, pre + "FillStyle", HATCH) 90 setattr(o, pre + "FillHatch", hatch()) 91 setattr(o, pre + "FillColor", 0xFFFFCC) 92 setattr(o, pre + "FillBackground", True) 93 elif kind == "bitmap": 94 setattr(o, pre + "FillStyle", BITMAP) 95 setattr(o, pre + "FillBitmapURL", png_url) 96 97 ps = doc.StyleFamilies.getByName("PageStyles") 98 specs = [("P_solid", "solid", "solid", "solid"), ("P_transp", "solid_transp", "solid_transp", "solid_transp"), 99 ("P_grad", "gradient", "gradient", "hatch"), ("P_bitmap", "bitmap", "bitmap", "bitmap")] 100 for name, pg, hd, ft in specs: 101 s = doc.createInstance("com.sun.star.style.PageStyle") 102 ps.insertByName(name, s) 103 s.HeaderIsOn = True 104 s.FooterIsOn = True 105 fill(s, "", pg, 0x66CCFF) 106 fill(s, "Header", hd, 0xCCFF66) 107 fill(s, "Footer", ft, 0xFF66CC) 108 text = doc.Text 109 cur = text.createTextCursor() 110 pb = uno.getConstantByName("com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK") 111 for name, *_ in specs: 112 text.insertString(cur, "page " + name, False) 113 text.insertControlCharacter(cur, pb, False) 114 en = text.createEnumeration() 115 for name, *_ in specs: 116 en.nextElement().PageDescName = name 117 return [_save(doc, outdir, "page-fill.odt", "writer8")] 118 119 120def fill_others(outdir): 121 """Other consumers of fills: Writer frame/table/section, Calc cell/page/shape, Draw shape/page, Impress shape/slide.""" 122 def shape(doc, page, x, y, kind, text, fillkind): 123 s = doc.createInstance(kind) 124 page.add(s) 125 s.Position = Point(x, y) 126 s.Size = Size(4000, 2000) 127 s.String = text 128 if fillkind == "solid": 129 s.FillStyle = SOLID 130 s.FillColor = 0x33AA55 131 else: 132 s.FillStyle = GRADIENT 133 s.FillGradient = _grad() 134 return s 135 136 done = [] 137 doc = _new("swriter") 138 text = doc.Text 139 cur = text.createTextCursor() 140 for fk in ("solid", "gradient"): 141 fr = doc.createInstance("com.sun.star.text.TextFrame") 142 fr.Width, fr.Height = 4000, 1500 143 text.insertTextContent(cur, fr, False) 144 fr.Text.String = "frame " + fk 145 if fk == "solid": 146 fr.FillStyle = SOLID 147 fr.FillColor = 0x33AA55 148 else: 149 fr.FillStyle = GRADIENT 150 fr.FillGradient = _grad() 151 tbl = doc.createInstance("com.sun.star.text.TextTable") 152 tbl.initialize(2, 2) 153 text.insertTextContent(text.End, tbl, False) 154 tbl.getCellByName("A1").BackColor = 0xFFCC00 155 tbl.getCellByName("B1").BackColor = 0xFFAACC 156 tbl.BackColor = 0xCCFFCC 157 sec = doc.createInstance("com.sun.star.text.TextSection") 158 text.insertTextContent(text.End, sec, False) 159 sec.BackColor = 0xCCCCFF 160 done.append(_save(doc, outdir, "others-writer.odt", "writer8")) 161 162 doc = _new("scalc") 163 sh = doc.Sheets.getByIndex(0) 164 sh.getCellByPosition(0, 0).String = "cell" 165 sh.getCellByPosition(0, 0).CellBackColor = 0xFFCC00 166 sh.getCellByPosition(1, 0).String = "grad" 167 doc.StyleFamilies.getByName("PageStyles").getByName("Default").BackColor = 0xDDEEFF 168 shape(doc, sh.DrawPage, 1000, 3000, "com.sun.star.drawing.RectangleShape", "calc shape", "gradient") 169 done.append(_save(doc, outdir, "others-calc.ods", "calc8")) 170 171 doc = _new("sdraw") 172 page = doc.DrawPages.getByIndex(0) 173 shape(doc, page, 1000, 1000, "com.sun.star.drawing.RectangleShape", "draw solid", "solid") 174 shape(doc, page, 6000, 1000, "com.sun.star.drawing.EllipseShape", "draw grad", "gradient") 175 try: 176 page.Background = None 177 bg = doc.createInstance("com.sun.star.drawing.Background") 178 bg.FillStyle = GRADIENT 179 bg.FillGradient = _grad() 180 page.Background = bg 181 except Exception: 182 pass 183 done.append(_save(doc, outdir, "others-draw.odg", "draw8")) 184 185 doc = _new("simpress") 186 page = doc.DrawPages.getByIndex(0) 187 shape(doc, page, 1000, 1000, "com.sun.star.drawing.RectangleShape", "impress solid", "solid") 188 shape(doc, page, 6000, 1000, "com.sun.star.drawing.RectangleShape", "impress grad", "gradient") 189 try: 190 bg = doc.createInstance("com.sun.star.drawing.Background") 191 bg.FillStyle = SOLID 192 bg.FillColor = 0xCCEEFF 193 page.Background = bg 194 except Exception: 195 pass 196 done.append(_save(doc, outdir, "others-impress.odp", "impress8")) 197 return done 198 199 200def t13(outdir): 201 """The features ODF 1.3 changes: drop-down fields, annotation initials, Calc tab colour, Calc page scale-to, chart inner 202 plot position and legend size (fixtures/t13/make.py). Everything is fixed: no dates from the clock, nothing random.""" 203 def dt(y, mo, d, h, mi): 204 return uno.createUnoStruct("com.sun.star.util.DateTime", 0, 0, mi, h, d, mo, y) 205 206 def ensure_sheets(doc, n): 207 sheets = doc.Sheets 208 while sheets.Count > n: 209 sheets.removeByName(sheets.getByIndex(sheets.Count - 1).Name) 210 while sheets.Count < n: 211 sheets.insertNewByName("Sheet%d" % (sheets.Count + 1), sheets.Count) 212 return sheets 213 214 def put_field(doc, cur, kind, **props): 215 f = doc.createInstance("com.sun.star.text.TextField." + kind) 216 for k, v in props.items(): 217 setattr(f, k, v) 218 doc.Text.insertTextContent(cur, f, False) 219 220 done = [] 221 doc = _new("swriter") 222 cur = doc.Text.createTextCursor() 223 doc.Text.insertString(cur, "First: ", False) 224 put_field(doc, cur, "DropDown", Name="dd1", Items=("one", "two", "three"), SelectedItem="two", Help="help one", Tooltip="tip one") 225 doc.Text.insertControlCharacter(cur, 0, False) 226 doc.Text.insertString(cur, "Second: ", False) 227 # SwDropDownField accepts only a listed SelectedItem: "zzz" reads back as "" (nothing selected, the field shows "a") 228 put_field(doc, cur, "DropDown", Name="dd2", Items=("a", "b"), SelectedItem="zzz", Help="help two", Tooltip="tip two") 229 done.append(_save(doc, outdir, "dropdown.odt", "writer8")) 230 231 doc = _new("swriter") 232 cur = doc.Text.createTextCursor() 233 doc.Text.insertString(cur, "with initials ", False) 234 put_field(doc, cur, "Annotation", Author="Ann Author", Initials="AB", Content="first note", DateTimeValue=dt(2024, 7, 8, 9, 10)) 235 doc.Text.insertControlCharacter(cur, 0, False) 236 doc.Text.insertString(cur, "without initials ", False) 237 put_field(doc, cur, "Annotation", Author="Bob Author", Content="second note", DateTimeValue=dt(2024, 7, 9, 9, 10)) 238 done.append(_save(doc, outdir, "annot.odt", "writer8")) 239 240 doc = _new("scalc") 241 sheets = ensure_sheets(doc, 3) 242 for i, color in ((0, 0xFF0000), (2, 0x3366CC)): 243 sheets.getByIndex(i).TabColor = color 244 for i in range(3): 245 sheets.getByIndex(i).getCellByPosition(0, 0).setString("sheet %d" % i) 246 done.append(_save(doc, outdir, "tabcolor.ods", "calc8")) 247 248 doc = _new("scalc") 249 ps = doc.StyleFamilies.getByName("PageStyles") 250 sheets = ensure_sheets(doc, 4) 251 # setting ScaleToPagesX/Y clears ScaleToPages and PageScale in the style (sc/source/ui/unoobj/styleuno.cxx) 252 for name, props in (("PS_xy", {"ScaleToPagesX": 2, "ScaleToPagesY": 3}), ("PS_x", {"ScaleToPagesX": 2}), 253 ("PS_pages", {"ScaleToPages": 4}), ("PS_scale", {"PageScale": 80})): 254 ps.insertByName(name, doc.createInstance("com.sun.star.style.PageStyle")) 255 st = ps.getByName(name) 256 for k, v in props.items(): 257 setattr(st, k, v) 258 for i, name in enumerate(("PS_xy", "PS_x", "PS_pages", "PS_scale")): 259 sh = sheets.getByIndex(i) 260 sh.PageStyle = name 261 sh.getCellByPosition(0, 0).setString(name) 262 done.append(_save(doc, outdir, "scaleto.ods", "calc8")) 263 264 doc = _new("scalc") 265 sh = doc.Sheets.getByIndex(0) 266 for r in range(3): 267 sh.getCellByPosition(0, r).setString("c%d" % r) 268 sh.getCellByPosition(1, r).setValue(r + 1) 269 rect = uno.createUnoStruct("com.sun.star.awt.Rectangle", 1000, 1000, 12000, 9000) 270 sh.Charts.addNewByName("C1", rect, (sh.getCellRangeByName("A1:B3").RangeAddress,), True, True) 271 ch = sh.Charts.getByName("C1").EmbeddedObject 272 ch.HasLegend = True 273 dg = ch.Diagram 274 # inner plot position in 1/100 mm; the legend is positioned and given a custom size 275 dg.setDiagramPositionExcludingAxes(uno.createUnoStruct("com.sun.star.awt.Rectangle", 1500, 1200, 6000, 4500)) 276 lg = ch.Legend 277 lg.Expansion = uno.Enum("com.sun.star.chart.ChartLegendExpansion", "CUSTOM") 278 lg.setSize(uno.createUnoStruct("com.sun.star.awt.Size", 2500, 1800)) 279 lg.setPosition(uno.createUnoStruct("com.sun.star.awt.Point", 8800, 1500)) 280 done.append(_save(doc, outdir, "chart.ods", "calc8")) 281 return done 282 283 284def page_fill_13(outdir): 285 """Page styles with each kind of fill, built in Writer (aoo-src.odt), and a Calc page style with a background image and 286 colour (calc-src.ods) with a copy whose master page names a usable drawing page style (fixtures/page-fill-1_3).""" 287 png = os.path.join(outdir, "tile.png") 288 _png(png) 289 png_url = uno.systemPathToFileUrl(png) 290 kinds = "solid,solid_transp,gradient,gradient_transp,gradient_tgrad,hatch,hatch_nobg,bitmap_tile,bitmap_stretch,bitmap_once,none,shared".split(",") 291 doc = _new("swriter") 292 293 def gr(c1, c2, b): 294 g = Gradient() 295 g.Style, g.StartColor, g.EndColor = LINEAR, c1, c2 296 g.Angle, g.Border, g.XOffset, g.YOffset = 0, b, 50, 50 297 g.StartIntensity = g.EndIntensity = 100 298 g.StepCount = 0 299 return g 300 301 def fill(o, pre, kind): 302 def sp(n, v): 303 o.setPropertyValue(pre + n, v) 304 if kind == "solid": 305 sp("FillStyle", SOLID) 306 sp("FillColor", 0x33AA55) 307 elif kind == "solid_transp": 308 sp("FillStyle", SOLID) 309 sp("FillColor", 0x3355AA) 310 sp("FillTransparence", 40) 311 elif kind in ("gradient", "shared"): 312 sp("FillStyle", GRADIENT) 313 sp("FillGradient", gr(0xFF0000, 0x0000FF, 10)) 314 elif kind == "gradient_transp": 315 sp("FillStyle", GRADIENT) 316 sp("FillGradient", gr(0xFF0000, 0x0000FF, 10)) 317 sp("FillTransparence", 30) 318 elif kind == "gradient_tgrad": 319 sp("FillStyle", GRADIENT) 320 sp("FillGradient", gr(0x00FF00, 0xFF00FF, 0)) 321 tg = doc.createInstance("com.sun.star.drawing.TransparencyGradientTable") 322 if not tg.hasByName("TG1"): 323 tg.insertByName("TG1", gr(0x000000, 0xFFFFFF, 0)) 324 sp("FillTransparenceGradientName", "TG1") 325 elif kind in ("hatch", "hatch_nobg"): 326 h = Hatch() 327 h.Style, h.Color, h.Distance, h.Angle = SINGLE, 0x00AA00, 200, 450 328 sp("FillStyle", HATCH) 329 sp("FillHatch", h) 330 if kind == "hatch": 331 sp("FillColor", 0xFFFFCC) 332 sp("FillBackground", True) 333 else: 334 sp("FillBackground", False) 335 elif kind.startswith("bitmap"): 336 sp("FillStyle", BITMAP) 337 sp("FillBitmapURL", png_url) 338 sp("FillBitmapMode", {"bitmap_tile": REPEAT, "bitmap_stretch": STRETCH, "bitmap_once": NO_REPEAT}[kind]) 339 340 ps = doc.StyleFamilies.getByName("PageStyles") 341 for k in kinds: 342 ps.insertByName("P_" + k, doc.createInstance("com.sun.star.style.PageStyle")) 343 if k != "none": 344 fill(ps.getByName("P_" + k), "", k) 345 ps.getByName("P_shared").FollowStyle = "P_shared" 346 ps.insertByName("P_shared2", doc.createInstance("com.sun.star.style.PageStyle")) 347 fill(ps.getByName("P_shared2"), "", "shared") 348 s = ps.getByName("P_gradient") 349 s.HeaderIsOn = True 350 fill(s, "Header", "hatch") 351 fill(ps.getByName("Standard"), "", "solid") 352 fill(ps.getByName("First Page"), "", "hatch_nobg") 353 text = doc.Text 354 cur = text.createTextCursor() 355 pb = uno.getConstantByName("com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK") 356 names = ["First Page"] + ["P_" + k for k in kinds] + ["P_shared2"] 357 for i, n in enumerate(names): 358 text.insertString(cur, "page " + n, False) 359 if i < len(names) - 1: 360 text.insertControlCharacter(cur, pb, False) 361 en = text.createEnumeration() 362 for n in names: 363 en.nextElement().PageDescName = n 364 done = [_save(doc, outdir, "aoo-src.odt", "writer8")] 365 366 doc = _new("scalc") 367 ps = doc.StyleFamilies.getByName("PageStyles") 368 ps.insertByName("P_image", doc.createInstance("com.sun.star.style.PageStyle")) 369 s = ps.getByName("P_image") 370 s.BackColor = 0x66CCFF 371 s.BackGraphicURL = png_url 372 s.BackGraphicLocation = uno.Enum("com.sun.star.style.GraphicLocation", "TILED") 373 sheet = doc.Sheets.getByIndex(0) 374 sheet.PageStyle = "P_image" 375 sheet.getCellByPosition(0, 0).setString("page P_image") 376 done.append(_save(doc, outdir, "calc-src.ods", "calc8")) 377 378 src = os.path.join(outdir, "calc-src.ods") 379 with zipfile.ZipFile(src) as zi, zipfile.ZipFile(os.path.join(outdir, "calc-drawing-page.ods"), "w") as zo: 380 for it in zi.infolist(): 381 data = zi.read(it.filename) 382 if it.filename == "styles.xml": 383 t = data.decode("utf-8") 384 m = re.search(r'<style:master-page style:name="P_5f_image"[^>]*?(/?)>', t) 385 if not (m and t.count("</office:automatic-styles>") == 1): 386 raise core.Fail("uno", "calc-src.ods has an unexpected styles.xml: no master page P_5f_image") 387 t = t.replace(m.group(0), m.group(0)[:-len(m.group(1)) - 1] + ' draw:style-name="Mdp9"' + m.group(1) + ">", 1) 388 t = t.replace("</office:automatic-styles>", '<style:style style:name="Mdp9" style:family="drawing-page"><style:drawing-page-properties ' 389 'draw:fill="solid" draw:fill-color="#ff0000"/></style:style></office:automatic-styles>', 1) 390 data = t.encode("utf-8") 391 zo.writestr(it, data, compress_type=zipfile.ZIP_STORED if it.filename == "mimetype" else zipfile.ZIP_DEFLATED) 392 done.append("calc-drawing-page.ods") 393 return done 394 395 396def row_split(outdir): 397 doc = _new("swriter") 398 tbl = doc.createInstance("com.sun.star.text.TextTable") 399 tbl.initialize(3, 2) 400 doc.Text.insertTextContent(doc.Text.End, tbl, False) 401 rows = tbl.Rows 402 rows.getByIndex(0).IsSplitAllowed = True 403 rows.getByIndex(1).IsSplitAllowed = False 404 rows.getByIndex(2).IsSplitAllowed = True 405 rows.getByIndex(2).Height = 1000 406 return [_save(doc, outdir, "row-split.odt", "writer8")] 407 408 409def grid_snap(outdir): 410 doc = _new("swriter") 411 ps = doc.StyleFamilies.getByName("PageStyles") 412 specs = [("G_snap_on", True, 2), ("G_snap_off", False, 2), ("G_lines_off", False, 1)] 413 for name, snap, mode in specs: 414 s = doc.createInstance("com.sun.star.style.PageStyle") 415 ps.insertByName(name, s) 416 s.GridMode = mode 417 s.StandardPageMode = True 418 s.GridSnapToChars = snap 419 text = doc.Text 420 cur = text.createTextCursor() 421 pb = uno.getConstantByName("com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK") 422 for name, *_ in specs: 423 text.insertString(cur, "grid " + name, False) 424 text.insertControlCharacter(cur, pb, False) 425 en = text.createEnumeration() 426 for name, *_ in specs: 427 en.nextElement().PageDescName = name 428 out = os.path.join(outdir, "grid-snap.odt") 429 _save(doc, outdir, "grid-snap.odt", "writer8") 430 # older builds did not write standard-mode next to base-width and the importer does not infer it, so add it where it is missing 431 tmp = out + ".tmp" 432 tag = re.compile(rb"<[^<>]*style:layout-grid-base-width=[^<>]*>") 433 with zipfile.ZipFile(out) as zi, zipfile.ZipFile(tmp, "w") as zo: 434 for it in zi.infolist(): 435 data = zi.read(it.filename) 436 if it.filename == "styles.xml": 437 data = tag.sub(lambda m: m.group(0) if b"style:layout-grid-standard-mode=" in m.group(0) 438 else m.group(0).replace(b"style:layout-grid-base-width=", b'style:layout-grid-standard-mode="true" style:layout-grid-base-width=', 1), data) 439 zo.writestr(it, data, compress_type=it.compress_type) 440 os.replace(tmp, out) 441 return ["grid-snap.odt"] 442 443 444def ole_text(outdir): 445 """A Draw page with an OLE object without text and one with text.""" 446 doc = _new("sdraw") 447 page = doc.DrawPages.getByIndex(0) 448 for i, text in enumerate(("", "OLE label")): 449 s = doc.createInstance("com.sun.star.drawing.OLE2Shape") 450 s.CLSID = "078B7ABA-54FC-457F-8551-6147e776a997" 451 page.add(s) 452 s.Position = Point(2000 + i * 8000, 2000) 453 s.Size = Size(5000, 3000) 454 if text: 455 s.String = text 456 return [_save(doc, outdir, "ole-text.odg", "draw8")] 457 458 459def ole_text_edge(outdir): 460 """OLE shapes whose text is: none, a label, one space, a line break only, a date field only.""" 461 doc = _new("sdraw") 462 page = doc.DrawPages.getByIndex(0) 463 for i, text in enumerate(("", "OLE label", " ", "\n", None)): 464 s = doc.createInstance("com.sun.star.drawing.OLE2Shape") 465 s.CLSID = "078B7ABA-54FC-457F-8551-6147e776a997" 466 page.add(s) 467 s.Position = Point(1000 + i * 5000, 2000) 468 s.Size = Size(4000, 3000) 469 if text is None: 470 f = doc.createInstance("com.sun.star.text.TextField.DateTime") 471 f.IsFixed = True 472 f.IsDate = True 473 s.insertTextContent(s.createTextCursor(), f, False) 474 elif text: 475 s.String = text 476 return [_save(doc, outdir, "ole-text-edge.odg", "draw8")] 477 478 479def chart_shapes(outdir): 480 """A Calc chart with additional shapes (polyline, rectangle, text) in the chart draw page.""" 481 from com.sun.star.awt import Rectangle 482 from com.sun.star.table import CellRangeAddress 483 doc = _new("scalc") 484 sh = doc.Sheets.getByIndex(0) 485 for r, (a, b) in enumerate(((1, 2), (2, 4), (3, 3))): 486 sh.getCellByPosition(0, r).Value = a 487 sh.getCellByPosition(1, r).Value = b 488 rng = CellRangeAddress() 489 rng.Sheet, rng.StartColumn, rng.StartRow, rng.EndColumn, rng.EndRow = 0, 0, 0, 1, 2 490 r = Rectangle() 491 r.X, r.Y, r.Width, r.Height = 1000, 4000, 10000, 7000 492 sh.Charts.addNewByName("c1", r, (rng,), False, False) 493 ch = sh.Charts.getByName("c1").EmbeddedObject 494 page = ch.DrawPage 495 496 def mk(kind, x, y, w, h): 497 s = ch.createInstance(kind) 498 page.add(s) 499 s.Position = Point(x, y) 500 s.Size = Size(w, h) 501 return s 502 pl = mk("com.sun.star.drawing.PolyLineShape", 500, 500, 3000, 1500) 503 pl.PolyPolygon = ((Point(0, 1500), Point(1000, 500), Point(3000, 0)),) 504 mk("com.sun.star.drawing.RectangleShape", 4000, 500, 2000, 1000).String = "rect" 505 mk("com.sun.star.drawing.TextShape", 6500, 500, 2000, 800).String = "note" 506 return [_save(doc, outdir, "chart-shapes.ods", "calc8")] 507 508 509def normal_values_5b(outdir): 510 """Two charts, one with a graphic as the series symbol, and a hidden column.""" 511 from com.sun.star.awt import Rectangle 512 png = os.path.join(outdir, "symbol.png") 513 _png(png) 514 doc = _new("scalc") 515 sh = doc.Sheets.getByIndex(0) 516 for r, row in enumerate([["", "a", "b"], ["x", 1, 2], ["y", 3, 5], ["z", 4, 8]]): 517 for c, v in enumerate(row): 518 cell = sh.getCellByPosition(c, r) 519 if isinstance(v, str): 520 cell.String = v 521 else: 522 cell.Value = v 523 rng = sh.getCellRangeByName("A1:C4").getRangeAddress() 524 r = Rectangle() 525 r.X, r.Y, r.Width, r.Height = 8000, 1000, 9000, 7000 526 sh.Charts.addNewByName("c1", r, (rng,), True, True) 527 m = sh.Charts.getByName("c1").EmbeddedObject 528 gp = core._create("com.sun.star.graphic.GraphicProvider") 529 g = gp.queryGraphic((pv("URL", uno.systemPathToFileUrl(png)),)) 530 s = m.getFirstDiagram().getCoordinateSystems()[0].getChartTypes()[0].getDataSeries()[0] 531 sym = s.Symbol 532 sym.Style = uno.Enum("com.sun.star.chart2.SymbolStyle", "GRAPHIC") 533 sym.Graphic = g 534 s.Symbol = sym 535 sh.getColumns().getByIndex(2).IsVisible = False 536 r2 = Rectangle() 537 r2.X, r2.Y, r2.Width, r2.Height = 8000, 9000, 9000, 7000 538 sh.Charts.addNewByName("c2", r2, (sh.getCellRangeByName("A1:C4").getRangeAddress(),), True, True) 539 return [_save(doc, outdir, "normal5b.ods", "calc8")] 540 541 542def connector_viewbox(outdir): 543 """Connectors of every kind, connected and free, axis-aligned and diagonal, in Draw and Impress.""" 544 from com.sun.star.drawing.ConnectorType import CURVE, LINE, LINES, STANDARD 545 546 def build(doc, page): 547 def rect(x, y, w, h): 548 s = doc.createInstance("com.sun.star.drawing.RectangleShape") 549 page.add(s) 550 s.Position = Point(x, y) 551 s.Size = Size(w, h) 552 return s 553 554 def conn(kind, a, b, name): 555 c = doc.createInstance("com.sun.star.drawing.ConnectorShape") 556 page.add(c) 557 c.EdgeKind = kind 558 c.StartPosition = Point(*a) 559 c.EndPosition = Point(*b) 560 c.Name = name 561 return c 562 r1, r2 = rect(1000, 12000, 3000, 2000), rect(12000, 16000, 3000, 2000) 563 r3, r4 = rect(1000, 20000, 3000, 2000), rect(9000, 24000, 3000, 2000) 564 conn(STANDARD, (2000, 2000), (8000, 6000), "std_free") 565 conn(CURVE, (10000, 2000), (16000, 6000), "curve_free") 566 conn(LINE, (2000, 8000), (8000, 8000), "line_h") 567 conn(LINE, (10000, 8000), (10000, 11000), "line_v") 568 conn(LINE, (18000, 9000), (14000, 5000), "line_rev") 569 conn(STANDARD, (2000, 28000), (8000, 28000), "std_h") 570 conn(STANDARD, (16000, 28000), (16000, 32000), "std_v") 571 c = conn(STANDARD, (0, 0), (0, 0), "std_conn") 572 c.StartShape, c.EndShape = r1, r2 573 c = conn(CURVE, (0, 0), (0, 0), "curve_conn") 574 c.StartShape, c.EndShape = r3, r4 575 conn(LINES, (2000, 34000), (9000, 38000), "lines_free") 576 577 done = [] 578 for kind, name, flt in (("sdraw", "conn.odg", "draw8"), ("simpress", "conn.odp", "impress8")): 579 doc = _new(kind) 580 build(doc, doc.DrawPages.getByIndex(0)) 581 done.append(_save(doc, outdir, name, flt)) 582 return done 583 584 585def para_fill(outdir): 586 """Paragraphs and paragraph styles with each kind of fill, direct and through a style (fixtures/para-fill/make.py).""" 587 png = os.path.join(outdir, "tile.png") 588 _png(png) 589 png_url = uno.systemPathToFileUrl(png) 590 doc = _new("swriter") 591 text = doc.Text 592 593 def hatch(): 594 h = Hatch() 595 h.Style, h.Color, h.Distance, h.Angle = SINGLE, 0x00AA00, 200, 450 596 return h 597 598 def fill(o, kind): 599 if kind == "solid": 600 o.ParaBackColor = 0xFFCC00 601 o.ParaBackTransparent = False 602 elif kind == "solid_fill": 603 o.FillStyle = SOLID 604 o.FillColor = 0x33AA55 605 elif kind == "solid_transp": 606 o.FillStyle = SOLID 607 o.FillColor = 0x3355AA 608 o.FillTransparence = 40 609 elif kind == "gradient": 610 o.FillStyle = GRADIENT 611 o.FillGradient = _grad() 612 elif kind == "hatch": 613 o.FillStyle = HATCH 614 o.FillHatch = hatch() 615 o.FillColor = 0xFFFFCC 616 o.FillBackground = True 617 elif kind == "bitmap": 618 o.FillStyle = BITMAP 619 o.FillBitmapURL = png_url 620 621 kinds = ["solid", "solid_fill", "solid_transp", "gradient", "hatch", "bitmap"] 622 styles = doc.StyleFamilies.getByName("ParagraphStyles") 623 for k in kinds: 624 s = doc.createInstance("com.sun.star.style.ParagraphStyle") 625 s.ParentStyle = "Standard" 626 styles.insertByName("S_" + k, s) 627 fill(s, k) 628 pb = uno.getConstantByName("com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK") 629 cur = text.createTextCursor() 630 labels = [] 631 for k in kinds: 632 for kind in ("direct", "styled"): 633 text.insertString(cur, kind + " " + k, False) 634 text.insertControlCharacter(cur, pb, False) 635 labels.append((kind, k)) 636 paras = doc.Text.createEnumeration() 637 for kind, k in labels: 638 p = paras.nextElement() 639 if kind == "direct": 640 fill(p, k) 641 else: 642 p.ParaStyleName = "S_" + k 643 return [_save(doc, outdir, "para-fill.odt", "writer8")] 644 645 646def alien_attrs(outdir): 647 """Preserved alien attributes in ODF namespaces and in a foreign namespace on the carriers that keep them: Writer paragraph, 648 character, section, table and table cell, a Draw shape, a Calc cell.""" 649 ns = {"text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0", "style": "urn:oasis:names:tc:opendocument:xmlns:style:1.0", 650 "draw": "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", "table": "urn:oasis:names:tc:opendocument:xmlns:table:1.0", 651 "office": "urn:oasis:names:tc:opendocument:xmlns:office:1.0", "svg": "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0", 652 "fo": "http://www.w3.org/1999/XSL/Format", "ex": "urn:example:foreign"} 653 attrs = (("text", "enable-numbering"), ("style", "alien-style"), ("draw", "alien-draw"), ("table", "alien-table"), 654 ("office", "alien-office"), ("svg", "alien-svg"), ("fo", "alien-fo"), ("ex", "alien-foreign")) 655 656 def put(container): 657 for p, n in attrs: 658 a = uno.createUnoStruct("com.sun.star.xml.AttributeData") 659 a.Namespace, a.Type, a.Value = ns[p], "CDATA", "v-" + p 660 container.insertByName(p + ":" + n, a) 661 662 done = [] 663 doc = _new("swriter") 664 text = doc.Text 665 cur = text.createTextCursor() 666 text.insertString(cur, "para text", False) 667 text.insertControlCharacter(cur, 0, False) 668 cur.gotoStart(False) 669 cur.goRight(4, True) 670 cont = cur.ParaUserDefinedAttributes 671 put(cont) 672 cur.ParaUserDefinedAttributes = cont 673 cont = cur.TextUserDefinedAttributes 674 put(cont) 675 cur.TextUserDefinedAttributes = cont 676 cur.gotoEnd(False) 677 tbl = doc.createInstance("com.sun.star.text.TextTable") 678 tbl.initialize(2, 2) 679 text.insertTextContent(cur, tbl, False) 680 for tgt in (tbl, tbl.getCellByName("A1")): 681 cont = tgt.UserDefinedAttributes 682 put(cont) 683 tgt.UserDefinedAttributes = cont 684 sec = doc.createInstance("com.sun.star.text.TextSection") 685 text.insertTextContent(text.End, sec, False) 686 cont = sec.UserDefinedAttributes 687 put(cont) 688 sec.UserDefinedAttributes = cont 689 done.append(_save(doc, outdir, "alien-writer.odt", "writer8")) 690 691 doc = _new("sdraw") 692 page = doc.DrawPages.getByIndex(0) 693 s = doc.createInstance("com.sun.star.drawing.RectangleShape") 694 page.add(s) 695 s.Position = Point(2000, 2000) 696 s.Size = Size(4000, 2000) 697 s.String = "alien" 698 cont = s.UserDefinedAttributes 699 put(cont) 700 s.UserDefinedAttributes = cont 701 done.append(_save(doc, outdir, "alien-draw.odg", "draw8")) 702 703 doc = _new("scalc") 704 c = doc.Sheets.getByIndex(0).getCellByPosition(0, 0) 705 c.Value = 1 706 cont = c.UserDefinedAttributes 707 put(cont) 708 c.UserDefinedAttributes = cont 709 done.append(_save(doc, outdir, "alien-calc.ods", "calc8")) 710 return done 711 712 713def para_fill_foreign(outdir): 714 """The paragraphs and paragraph styles another producer writes with fill properties, built with AOO's own (aoo-form.odt).""" 715 png = os.path.join(outdir, "tile.png") 716 _png(png) 717 png_url = uno.systemPathToFileUrl(png) 718 doc = _new("swriter") 719 720 def grad(c1, c2): 721 g = Gradient() 722 g.Style, g.StartColor, g.EndColor = LINEAR, c1, c2 723 g.Angle, g.Border, g.XOffset, g.YOffset = 300, 10, 50, 50 724 g.StartIntensity = g.EndIntensity = 100 725 g.StepCount = 0 726 return g 727 728 def hatch(): 729 h = Hatch() 730 h.Style, h.Color, h.Distance, h.Angle = SINGLE, 0xFFAA00, 200, 450 731 return h 732 733 def fill(o, kind): 734 if kind == "solid": 735 o.FillStyle = SOLID 736 o.FillColor = 0x33AA55 737 elif kind == "solid_transp": 738 o.FillStyle = SOLID 739 o.FillColor = 0x3355AA 740 o.FillTransparence = 40 741 elif kind == "gradient": 742 o.FillStyle = GRADIENT 743 o.FillGradient = grad(0xFF0000, 0x0000FF) 744 elif kind == "gradient_transp": 745 o.FillStyle = GRADIENT 746 o.FillGradient = grad(0xFF0000, 0x0000FF) 747 o.FillTransparence = 30 748 elif kind == "hatch": 749 o.FillStyle = HATCH 750 o.FillHatch = hatch() 751 o.FillColor = 0xFFFFCC 752 o.FillBackground = True 753 elif kind == "hatch_nobg": 754 o.FillStyle = HATCH 755 o.FillHatch = hatch() 756 o.FillBackground = False 757 elif kind.startswith("bitmap"): 758 o.FillStyle = BITMAP 759 o.FillBitmapURL = png_url 760 o.FillBitmapMode = {"bitmap_stretch": STRETCH, "bitmap_once": NO_REPEAT}.get(kind, REPEAT) 761 if kind == "bitmap_transp": 762 o.FillTransparence = 50 763 764 kinds = ["solid", "solid_transp", "gradient", "gradient_transp", "hatch", "hatch_nobg", "bitmap_tile", "bitmap_stretch", "bitmap_once", 765 "bitmap_transp"] 766 styles = doc.StyleFamilies.getByName("ParagraphStyles") 767 for k in kinds: 768 s = doc.createInstance("com.sun.star.style.ParagraphStyle") 769 s.ParentStyle = "Standard" 770 styles.insertByName("S_" + k, s) 771 fill(s, k) 772 pb = uno.getConstantByName("com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK") 773 cur = doc.Text.createTextCursor() 774 for k in kinds: 775 for kind in ("direct", "styled"): 776 doc.Text.insertString(cur, kind + " " + k, False) 777 doc.Text.insertControlCharacter(cur, pb, False) 778 paras = doc.Text.createEnumeration() 779 for k in kinds: 780 fill(paras.nextElement(), k) 781 paras.nextElement().ParaStyleName = "S_" + k 782 return [_save(doc, outdir, "aoo-form.odt", "writer8")] 783 784 785def boolean_writer(outdir): 786 """Writer table cells and set-expression fields with a boolean number format, holding 12345, 1 and 0.""" 787 from com.sun.star.lang import Locale 788 from com.sun.star.util.NumberFormat import LOGICAL 789 doc = _new("swriter") 790 key = doc.NumberFormats.getStandardFormat(LOGICAL, Locale("en", "US", "")) 791 tbl = doc.createInstance("com.sun.star.text.TextTable") 792 tbl.initialize(1, 3) 793 doc.Text.insertTextContent(doc.Text.End, tbl, False) 794 for i, v in enumerate((12345, 1, 0)): 795 c = tbl.getCellByPosition(i, 0) 796 c.NumberFormat = key 797 c.setValue(v) 798 cur = doc.Text.createTextCursor() 799 cur.gotoEnd(False) 800 for i, v in enumerate((12345.0, 1.0, 0.0)): 801 f = doc.createInstance("com.sun.star.text.TextField.SetExpression") 802 mst = doc.createInstance("com.sun.star.text.FieldMaster.SetExpression") 803 mst.Name = "bv%d" % i 804 mst.SubType = 0 805 f.Content = "" 806 f.NumberFormat = key 807 f.SubType = 0 808 f.IsShowFormula = False 809 f.attachTextFieldMaster(mst) 810 doc.Text.insertTextContent(cur, f, False) 811 f.Value = v 812 doc.Text.insertString(cur, " ", False) 813 return [_save(doc, outdir, "boolean-writer.odt", "writer8")] 814 815 816def normal_values(outdir): 817 """A Writer table with a merged cell, a page break, a footnote with references to it, and two frames anchored to a page.""" 818 from com.sun.star.style.BreakType import PAGE_BEFORE 819 from com.sun.star.text.TextContentAnchorType import AT_PAGE 820 doc = _new("swriter") 821 text = doc.Text 822 tbl = doc.createInstance("com.sun.star.text.TextTable") 823 tbl.initialize(2, 3) 824 text.insertTextContent(text.End, tbl, False) 825 c = tbl.createCursorByCellName("A1") 826 c.goRight(1, True) 827 c.mergeRange() 828 cur = text.createTextCursor() 829 cur.gotoEnd(False) 830 text.insertString(cur, "\nbody\n", False) 831 cur.gotoEnd(False) 832 cur.BreakType = PAGE_BEFORE 833 text.insertString(cur, "page two\n", False) 834 fn = doc.createInstance("com.sun.star.text.Footnote") 835 fn.Label = "" 836 cur.gotoEnd(False) 837 text.insertTextContent(cur, fn, False) 838 fn.String = "note text" 839 text.insertString(cur, " ", False) 840 for part in (0, 3, 2): 841 f = doc.createInstance("com.sun.star.text.TextField.GetReference") 842 f.ReferenceFieldSource = 3 843 f.SourceName = "" 844 f.SequenceNumber = fn.ReferenceId 845 f.ReferenceFieldPart = part 846 text.insertTextContent(cur, f, False) 847 text.insertString(cur, " ", False) 848 for name, page in (("frame_p2", 2), ("frame_nopage", 0)): 849 fr = doc.createInstance("com.sun.star.text.TextFrame") 850 fr.AnchorType = AT_PAGE 851 if page: 852 fr.AnchorPageNo = page 853 fr.Width = 3000 854 fr.Height = 1000 855 text.insertTextContent(cur, fr, False) 856 fr.setName(name) 857 fr.Text.String = name 858 return [_save(doc, outdir, "normal-values.odt", "writer8")] 859 860 861def note_ref(outdir): 862 """A footnote and an endnote, each with reference fields for every part (page, direction, text, the three sequence-only ones).""" 863 doc = _new("swriter") 864 text = doc.Text 865 cur = text.createTextCursor() 866 text.insertString(cur, "body", False) 867 fn = doc.createInstance("com.sun.star.text.Footnote") 868 text.insertTextContent(cur, fn, False) 869 fn.String = "note text" 870 en = doc.createInstance("com.sun.star.text.Endnote") 871 text.insertTextContent(cur, en, False) 872 en.String = "end text" 873 text.insertString(cur, " ", False) 874 for src, note in ((3, fn), (4, en)): 875 for part in (0, 3, 2, 5, 6, 7): 876 f = doc.createInstance("com.sun.star.text.TextField.GetReference") 877 f.ReferenceFieldSource = src 878 f.SourceName = "" 879 f.SequenceNumber = note.ReferenceId 880 f.ReferenceFieldPart = part 881 text.insertTextContent(cur, f, False) 882 text.insertString(cur, " ", False) 883 return [_save(doc, outdir, "note-ref.odt", "writer8")] 884 885 886BUILDERS = {"page-fill": page_fill, "fill-others": fill_others, "t13": t13, "page-fill-1_3": page_fill_13, "row-split": row_split, 887 "grid-snap": grid_snap, "ole-text": ole_text, "ole-text-edge": ole_text_edge, "chart-shapes": chart_shapes, 888 "normal-values5b": normal_values_5b, "connector-viewbox": connector_viewbox, "para-fill": para_fill, 889 "alien-attrs": alien_attrs, "para-fill-foreign": para_fill_foreign, "boolean-writer": boolean_writer, 890 "normal-values": normal_values, "note-ref": note_ref} 891 892# The large builders are the old harness's scripts, run as they are (see ops/scripts.py). In a fresh office the draw script stalls at 893# its `annotations` step (twice in a row); that step alone and the script without it both finish, so they are two builders. 894_DRAW_STEPS = ("pres-settings header-footer layouts transitions animations actions draw-links image-maps shapes layers special fills " 895 "masters-notes writer-shapes writer-group-frame writer-graphics calc-shapes custom-presets custom-full fontwork 3d-odg " 896 "3d-odp").split() 897SCRIPTS = {"writer": ("writer.py", ()), "draw": ("draw.py", _DRAW_STEPS), "draw-annotations": ("draw.py", ("annotations",)), 898 "calc": ("calc.py", ()), "styles-gfx": ("styles_gfx.py", ()), "chart": ("chart.py", ()), "styles-text": ("styles_text.py", ()), 899 "leak": ("leak.py", ()), "base": ("base.py", ()), "p8-drawings": ("make_drawings.py", ()), "doctypes": ("doctypes.py", ())} 900BUILDERS.update({name: (lambda outdir, script=script, args=args: scripts.run_script(script, outdir, args)) 901 for name, (script, args) in SCRIPTS.items()}) 902 903 904def generate(builder, outdir): 905 """Runs the named builder; the documents it makes are stored in `outdir`. Returns {"files": [names]}.""" 906 if builder not in BUILDERS: 907 raise core.Fail("bad_args", "unknown builder %r" % builder) 908 os.makedirs(outdir, exist_ok=True) 909 return {"files": BUILDERS[builder](os.path.abspath(outdir))} 910 911 912OPS = {"generate": core.guarded(generate)} 913