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# usage: runpy.sh fixtures/leak/make.py <port> <outdir> 21# Documents for names that AOO's export code can emit but no ODF 1.2 schema pattern defines (runs/task12/gaps/strict-leak.txt). 22# Saves with the office's configured ODF version. ODF packages go to <outdir>; the report-definition package and the 23# old-format chart copies go to <outdir>/../other and <outdir>/../oldfmt so the ODF checkers do not see them. 24import os, struct, sys, traceback, zlib, uno 25from unohelp import connect, desktop, pv 26from com.sun.star.awt import Rectangle, Size, Point 27from com.sun.star.table import CellAddress, CellRangeAddress, BorderLine 28 29port, out = int(sys.argv[1]), os.path.abspath(sys.argv[2]) 30base = os.path.dirname(out) 31other, oldfmt, work = (os.path.join(base, d) for d in ("other", "oldfmt", "work")) 32for d in (out, other, oldfmt, work): 33 os.makedirs(d, exist_ok=True) 34ctx = connect(port) 35sm = ctx.ServiceManager 36desk = desktop(ctx) 37failed = [] 38URL = uno.systemPathToFileUrl 39ANCHOR = uno.Enum("com.sun.star.text.TextContentAnchorType", "AS_CHARACTER") 40TPL = "com.sun.star.chart2.template." 41 42 43def new(factory): 44 return desk.loadComponentFromURL(factory, "_blank", 0, (pv("Hidden", True),)) 45 46 47def save(doc, path, filt): 48 doc.storeToURL(URL(path), (pv("FilterName", filt),)) 49 print("saved", os.path.basename(path), filt) 50 51 52def step(name, fn): 53 try: 54 fn() 55 except Exception as e: 56 failed.append(name) 57 print("FAIL", name, repr(e)[:300]) 58 traceback.print_exc(limit=3) 59 60 61def make_png(path): 62 w = h = 8 63 raw = b"".join(b"\x00" + bytes([200, 30, 30] * w) for _ in range(h)) 64 65 def chunk(t, b): 66 return struct.pack(">I", len(b)) + t + b + struct.pack(">I", zlib.crc32(t + b) & 0xFFFFFFFF) 67 68 with open(path, "wb") as f: 69 f.write(b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0)) 70 + chunk(b"IDAT", zlib.compress(raw)) + chunk(b"IEND", b"")) 71 72 73def set_all(obj, props): 74 for k, v in props: 75 try: 76 uno.invoke(obj, "setPropertyValue", (k, v)) if isinstance(v, uno.Any) else obj.setPropertyValue(k, v) 77 except Exception as e: 78 print("note: cannot set", k, repr(e)[:80]) 79 80 81def writer_fields(): 82 doc = new("private:factory/swriter") 83 try: 84 text = doc.Text 85 cur = text.createTextCursor() 86 text.insertString(cur, "fields: ", False) 87 88 def field(svc, **kw): 89 f = doc.createInstance("com.sun.star.text.TextField." + svc) 90 for k, v in kw.items(): 91 setattr(f, k, v) 92 text.insertTextContent(cur, f, False) 93 text.insertString(cur, " ", False) 94 95 field("Input", Content="x", Hint="hint", Help="help text", Tooltip="tooltip text") 96 field("DropDown", Name="dd", Items=("a", "b", "c"), SelectedItem="b", Help="help dd", Tooltip="tip dd") 97 pn = uno.Enum("com.sun.star.text.PageNumberType", "NEXT") 98 field("PageNumber", SubType=pn, UserText="next page", NumberingType=6) 99 pn = uno.Enum("com.sun.star.text.PageNumberType", "PREV") 100 field("PageNumber", SubType=pn, UserText="prev page", NumberingType=6) 101 fn = doc.createInstance("com.sun.star.text.Footnote") 102 text.insertTextContent(cur, fn, False) 103 fn.String = "note" 104 fs = doc.FootnoteSettings 105 fs.EndNotice = "continued on next page" 106 fs.BeginNotice = "continued from previous page" 107 save(doc, os.path.join(out, "writer-fields.odt"), "writer8") 108 finally: 109 doc.close(True) 110 111 112def writer_toc_image(): 113 png = os.path.join(work, "red.png") 114 make_png(png) 115 doc = new("private:factory/swriter") 116 try: 117 text = doc.Text 118 cur = text.createTextCursor() 119 text.insertString(cur, "Heading one", False) 120 cur.gotoStart(False) 121 cur.gotoEndOfParagraph(True) 122 cur.ParaStyleName = "Heading 1" 123 cur.gotoEnd(False) 124 text.insertControlCharacter(cur, uno.getConstantByName("com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK"), False) 125 g = doc.createInstance("com.sun.star.text.GraphicObject") 126 g.GraphicURL = URL(png) 127 g.Width = g.Height = 3000 128 g.AnchorType = ANCHOR 129 text.insertTextContent(cur, g, False) 130 g.GraphicRotation = 900 131 toc = doc.createInstance("com.sun.star.text.ContentIndex") 132 toc.CreateFromOutline = True 133 lf = toc.LevelFormat 134 new_level = [] 135 for tok in lf.getByIndex(1): 136 tok = list(tok) 137 for p in tok: 138 if p.Name == "WithTab": 139 p.Value = False 140 new_level.append(tuple(tok)) 141 uno.invoke(lf, "replaceByIndex", (1, uno.Any("[][]com.sun.star.beans.PropertyValue", tuple(new_level)))) 142 text.insertTextContent(cur, toc, False) 143 toc.update() 144 save(doc, os.path.join(out, "writer-toc-image.odt"), "writer8") 145 finally: 146 doc.close(True) 147 148 149def writer_forms(): 150 doc = new("private:factory/swriter") 151 try: 152 dp = doc.DrawPage 153 dp.Forms.insertByName("F1", doc.createInstance("com.sun.star.form.component.Form")) 154 form = dp.Forms.getByName("F1") 155 y = 300 156 for kind in ("TextField", "FormattedField", "NumericField", "DateField", "TimeField", "CurrencyField", "PatternField", 157 "CheckBox", "ComboBox", "ListBox", "RadioButton"): 158 m = doc.createInstance("com.sun.star.form.component." + kind) 159 set_all(m, (("InputRequired", False), ("EnableVisible", False))) 160 m.Name = kind 161 form.insertByName(kind, m) 162 s = doc.createInstance("com.sun.star.drawing.ControlShape") 163 s.Size = Size(3000, 600) 164 s.Position = Point(500, y) 165 y += 800 166 s.setControl(m) 167 dp.add(s) 168 for i, (n, v) in enumerate((("FontWidth", uno.Any("short", 20)), ("FontCharWidth", uno.Any("float", 90.0)), 169 ("FontWordLineMode", True))): 170 m = doc.createInstance("com.sun.star.form.component.TextField") 171 set_all(m, ((n, v),)) 172 m.Name = "font_" + n 173 form.insertByName(m.Name, m) 174 s = doc.createInstance("com.sun.star.drawing.ControlShape") 175 s.Size = Size(3000, 600) 176 s.Position = Point(4500, 300 + i * 800) 177 s.setControl(m) 178 dp.add(s) 179 save(doc, os.path.join(out, "writer-forms.odt"), "writer8") 180 finally: 181 doc.close(True) 182 183 184def writer_redline(): 185 doc = new("private:factory/swriter") 186 try: 187 doc.Text.insertString(doc.Text.createTextCursor(), "first para\nsecond para\nthird para", False) 188 t = doc.createInstance("com.sun.star.text.TextTable") 189 t.initialize(2, 2) 190 c = doc.Text.createTextCursor() 191 c.gotoEnd(False) 192 doc.Text.insertTextContent(c, t, False) 193 doc.RecordChanges = True 194 c = doc.Text.createTextCursor() 195 c.gotoStart(False) 196 c.goRight(3, False) 197 c.gotoEndOfParagraph(True) 198 c.goRight(1, True) 199 c.setString("") 200 c = doc.Text.createTextCursor() 201 c.gotoEnd(False) 202 c.goLeft(4, True) 203 c.setString("") 204 e = doc.Redlines.createEnumeration() 205 while e.hasMoreElements(): 206 r = e.nextElement() 207 print("redline", r.RedlineType, "MergeLastPara", r.getPropertyValue("MergeLastPara")) 208 save(doc, os.path.join(out, "writer-redline.odt"), "writer8") 209 finally: 210 doc.close(True) 211 212 213def writer_pagegrid(): 214 doc = new("private:factory/swriter") 215 try: 216 doc.Text.insertString(doc.Text.createTextCursor(), "grid", False) 217 ps = doc.StyleFamilies.getByName("PageStyles").getByName("Standard") 218 set_all(ps, (("GridMode", 2), ("GridLines", 20), ("GridBaseHeight", 600), ("GridBaseWidth", 500), 219 ("GridSnapToChars", True), ("StandardPageMode", True), ("GridDisplay", True), ("GridPrint", True))) 220 save(doc, os.path.join(out, "writer-pagegrid.odt"), "writer8") 221 finally: 222 doc.close(True) 223 224 225def fill_rows(sh, rows): 226 for r, row in enumerate(rows): 227 for c, v in enumerate(row): 228 cell = sh.getCellByPosition(c, r) 229 if isinstance(v, str): 230 cell.String = v 231 else: 232 cell.Value = v 233 234 235def calc_misc(): 236 doc = new("private:factory/scalc") 237 try: 238 sh = doc.Sheets.getByIndex(0) 239 sh.TabColor = 0xFF8000 240 for i, mode in enumerate((0, 1, 2)): 241 sh.getCellByPosition(12, i).Formula = '=DDE("soffice";"/tmp/x.ods";"Sheet1.A%d";%d)' % (i + 1, mode) 242 fill_rows(sh, [("", "", "", "L0", 1, ""), ("", "", "", "L1", 2, ""), ("", "", "", "L2", 3, "")]) 243 for r in range(3): 244 sh.getCellByPosition(1, r + 4).Value = r + 5 245 sh.getCellByPosition(0, r + 4).String = "L%d" % r 246 cd = doc.createConsolidationDescriptor(False) 247 cd.Function = uno.Enum("com.sun.star.sheet.GeneralFunction", "SUM") 248 cd.Sources = (CellRangeAddress(0, 0, 4, 1, 6), CellRangeAddress(0, 3, 0, 4, 2)) 249 cd.StartOutputPosition = CellAddress(0, 7, 7) 250 cd.UseColumnHeaders = True 251 cd.UseRowHeaders = True 252 cd.InsertLinks = False 253 doc.consolidate(cd) 254 c = sh.getCellByPosition(10, 10) 255 c.String = "diagonal" 256 bl = BorderLine() 257 bl.OuterLineWidth = 50 258 bl.Color = 0xFF0000 259 c.DiagonalBLTR = bl 260 c.DiagonalTLBR = bl 261 ps = doc.StyleFamilies.getByName("PageStyles").getByName(sh.PageStyle) 262 set_all(ps, (("ScaleToPagesX", 2), ("ScaleToPagesY", 3))) 263 save(doc, os.path.join(out, "calc-misc.ods"), "calc8") 264 finally: 265 doc.close(True) 266 267 268def calc_pivot_group(): 269 doc = new("private:factory/scalc") 270 try: 271 sh = doc.Sheets.getByIndex(0) 272 fill_rows(sh, [("Region", "Qty")] + [(r, i + 1) for i, r in enumerate(["North", "South", "East", "West", "North", "East"])]) 273 dps = sh.DataPilotTables 274 desc = dps.createDataPilotDescriptor() 275 desc.setSourceRange(CellRangeAddress(0, 0, 0, 1, 6)) 276 fl = desc.getDataPilotFields() 277 ori = lambda n: uno.Enum("com.sun.star.sheet.DataPilotFieldOrientation", n) 278 fl.getByName("Region").Orientation = ori("ROW") 279 fl.getByName("Qty").Orientation = ori("DATA") 280 dps.insertNewByName("pv", CellAddress(0, 4, 1), desc) 281 f = dps.getByName("pv").getDataPilotFields().getByName("Region") 282 f.createNameGroup(("North", "South")) 283 save(doc, os.path.join(out, "calc-pivot-group.ods"), "calc8") 284 finally: 285 doc.close(True) 286 287 288def calc_tracked(): 289 doc = new("private:factory/scalc") 290 try: 291 dh = sm.createInstanceWithContext("com.sun.star.frame.DispatchHelper", ctx) 292 dh.executeDispatch(doc.CurrentController.Frame, ".uno:TraceChangeMode", "", 0, (pv("TraceChangeMode", True),)) 293 sh = doc.Sheets.getByIndex(0) 294 for r in range(6): 295 sh.getCellByPosition(0, r).Value = r 296 for r in range(6): 297 sh.getCellByPosition(0, r).Value = r * 10 298 sh.Rows.insertByIndex(2, 2) 299 sh.Rows.removeByIndex(3, 2) 300 save(doc, os.path.join(out, "calc-tracked.ods"), "calc8") 301 finally: 302 doc.close(True) 303 304 305def chart_doc(name, charts, post=None): 306 doc = new("private:factory/scalc") 307 try: 308 sh = doc.Sheets.getByIndex(0) 309 loc = uno.createUnoStruct("com.sun.star.lang.Locale", "en", "US", "") 310 key = doc.NumberFormats.queryKey("YYYY-MM-DD", loc, False) 311 if key == -1: 312 key = doc.NumberFormats.addNew("YYYY-MM-DD", loc) 313 for r in range(6): 314 for c in range(5): 315 if r == 0: 316 sh.getCellByPosition(c, r).String = "s%d" % c if c else "cat" 317 else: 318 sh.getCellByPosition(c, r).Value = 40000 + r * 30 if c == 0 else r * 2 + c 319 sh.getCellRangeByName("A2:A6").NumberFormat = key 320 for i, (cname, ncols, tpl) in enumerate(charts): 321 rng = CellRangeAddress(0, 0, 0, ncols, 5) 322 sh.Charts.addNewByName(cname, Rectangle(500 + i * 9500, 8000, 9000, 6800), (rng,), True, True) 323 ch = sh.Charts.getByName(cname).EmbeddedObject 324 if tpl: 325 dp = ch.getDataProvider() 326 args = (pv("CellRangeRepresentation", "$Sheet1.$A$1:$%s$6" % "ABCDE"[ncols]), 327 pv("DataRowSource", uno.Enum("com.sun.star.chart.ChartDataRowSource", "COLUMNS")), 328 pv("FirstCellAsLabel", True), pv("HasCategories", True)) 329 t = ch.ChartTypeManager.createInstance(TPL + tpl) 330 ch.setFirstDiagram(t.createDiagramByDataSource(dp.createDataSource(args), args)) 331 if post: 332 post(ch) 333 save(doc, os.path.join(out, name + ".ods"), "calc8") 334 try: 335 save(doc, os.path.join(oldfmt, name + ".sxc"), "StarOffice XML (Calc)") 336 except Exception as e: 337 print("note: old format save failed", repr(e)[:100]) 338 finally: 339 doc.close(True) 340 341 342def label_and_date_axis(ch): 343 cs = ch.getFirstDiagram().getCoordinateSystems()[0] 344 for s in cs.getChartTypes()[0].getDataSeries(): 345 s.setPropertyValue("LabelSeparator", "a\tb\nc") 346 s.setPropertyValue("Label", uno.createUnoStruct("com.sun.star.chart2.DataPointLabel", True, False, False, False)) 347 ax = cs.getAxisByDimension(0, 0) 348 sd = ax.getScaleData() 349 sd.AxisType = 4 350 ti = uno.createUnoStruct("com.sun.star.chart.TimeIncrement") 351 ti.TimeResolution = 1 352 ti.MajorTimeInterval = uno.createUnoStruct("com.sun.star.chart.TimeInterval", 2, 1) 353 ti.MinorTimeInterval = uno.createUnoStruct("com.sun.star.chart.TimeInterval", 1, 0) 354 sd.TimeIncrement = ti 355 ax.setScaleData(sd) 356 357 358def draw_fontwork(): 359 doc = new("private:factory/sdraw") 360 try: 361 page = doc.DrawPages.getByIndex(0) 362 s = doc.createInstance("com.sun.star.drawing.RectangleShape") 363 page.add(s) 364 s.Size = Size(5000, 3000) 365 s.Position = Point(500, 500) 366 s.String = "fontwork" 367 set_all(s, (("FontWorkStyle", 0), ("FontWorkAdjust", 1), ("FontWorkDistance", 100), ("FontWorkStart", 50), 368 ("FontWorkMirror", True), ("FontWorkOutline", True), ("FontWorkShadow", 1), ("FontWorkShadowColor", 0xFF0000), 369 ("FontWorkShadowOffsetX", 100), ("FontWorkShadowOffsetY", 100), ("FontWorkHideForm", True), 370 ("FontWorkShadowTransparence", 50))) 371 for svc in ("RectangleShape", "TextShape", "PolyPolygonShape", "CustomShape"): 372 o = doc.createInstance("com.sun.star.drawing." + svc) 373 print("FontWorkForm on", svc, o.getPropertySetInfo().hasPropertyByName("FontWorkForm")) 374 a = doc.createInstance("com.sun.star.drawing.AppletShape") 375 page.add(a) 376 a.Size = Size(3000, 2000) 377 a.Position = Point(6000, 500) 378 set_all(a, (("AppletName", "myapplet"), ("AppletCode", "Foo.class"), ("AppletCodeBase", "file:///tmp/"), ("AppletIsScript", True))) 379 print("applet AppletName reads back", repr(a.getPropertyValue("AppletName"))) 380 t = doc.createInstance("com.sun.star.drawing.TextShape") 381 page.add(t) 382 t.Size = Size(5000, 3000) 383 t.Position = Point(500, 4500) 384 t.String = "one\ntwo" 385 nr = t.getPropertyValue("NumberingRules") 386 lvl = list(nr.getByIndex(0)) 387 for p in lvl: 388 if p.Name == "NumberingType": 389 p.Value = 4 390 uno.invoke(nr, "replaceByIndex", (0, uno.Any("[]com.sun.star.beans.PropertyValue", tuple(lvl)))) 391 t.setPropertyValue("NumberingRules", nr) 392 save(doc, os.path.join(out, "draw-fontwork.odg"), "draw8") 393 finally: 394 doc.close(True) 395 396 397def set_info(ds, **kw): 398 bag = ds.Settings 399 for k, v in kw.items(): 400 if bag.getPropertySetInfo().hasPropertyByName(k): 401 uno.invoke(bag, "setPropertyValue", (k, v)) 402 else: 403 uno.invoke(bag, "addProperty", (k, 128 | 1, v)) 404 405 406def base_doc(): 407 dbc = sm.createInstanceWithContext("com.sun.star.sdb.DatabaseContext", ctx) 408 path = os.path.join(out, "leak-base.odb") 409 for p in (path, path + ".lck"): 410 if os.path.exists(p): 411 os.remove(p) 412 ds = dbc.createInstance() 413 ds.URL = "sdbc:embedded:hsqldb" 414 ds.DatabaseDocument.storeAsURL(URL(path), ()) 415 try: 416 q = ds.QueryDefinitions.createInstance() 417 q.Command = 'SELECT "ID", "NAME" FROM "CUSTOMERS"' 418 q.Filter = '"ID" > 0' 419 q.ApplyFilter = True 420 q.Order = '"NAME"' 421 ds.QueryDefinitions.insertByName("Q", q) 422 q = ds.QueryDefinitions.getByName("Q") 423 print("ApplyOrder on query", q.getPropertySetInfo().hasPropertyByName("ApplyOrder"), 424 "on table definition", ds.Tables.createInstance().getPropertySetInfo().hasPropertyByName("ApplyOrder")) 425 set_all(q, (("FontWidth", uno.Any("short", 20)), ("FontCharWidth", uno.Any("float", 90.0)))) 426 for name, props in (("ID", dict(Hidden=True, HelpText="id column")), ("NAME", dict(HelpText="name", ControlDefault="x"))): 427 d = q.Columns.createDataDescriptor() 428 d.Name = name 429 for k, v in props.items(): 430 d.setPropertyValue(k, v) 431 q.Columns.appendByDescriptor(d) 432 ds.DatabaseDocument.store() 433 finally: 434 ds.DatabaseDocument.close(True) 435 if os.path.exists(path + ".lck"): 436 os.remove(path + ".lck") 437 print("saved", os.path.basename(path)) 438 439 440def base_dbase(): 441 dbc = sm.createInstanceWithContext("com.sun.star.sdb.DatabaseContext", ctx) 442 d = os.path.join(work, "dbase") 443 os.makedirs(d, exist_ok=True) 444 path = os.path.join(out, "leak-base-dbase.odb") 445 for p in (path, path + ".lck"): 446 if os.path.exists(p): 447 os.remove(p) 448 ds = dbc.createInstance() 449 ds.URL = "sdbc:dbase:" + URL(d) + "/" 450 set_info(ds, Extension="dbf", CharSet="utf-8") 451 ds.DatabaseDocument.storeAsURL(URL(path), ()) 452 try: 453 ds.DatabaseDocument.store() 454 finally: 455 ds.DatabaseDocument.close(True) 456 if os.path.exists(path + ".lck"): 457 os.remove(path + ".lck") 458 print("saved", os.path.basename(path)) 459 460 461def report_definition(): 462 r = sm.createInstanceWithContext("com.sun.star.report.ReportDefinition", ctx) 463 r.Caption = "Leak report" 464 r.Name = "rpt" 465 r.ReportHeaderOn = True 466 path = os.path.join(other, "report-definition.odr") 467 stg = sm.createInstanceWithContext("com.sun.star.embed.StorageFactory", ctx).createInstanceWithArguments((URL(path), 7)) 468 r.storeToStorage(stg, ()) 469 stg.commit() 470 stg.dispose() 471 print("saved", os.path.basename(path), "(report definition)") 472 473 474for name, fn in (("writer-fields", writer_fields), ("writer-toc-image", writer_toc_image), ("writer-forms", writer_forms), 475 ("writer-redline", writer_redline), ("writer-pagegrid", writer_pagegrid), ("calc-misc", calc_misc), 476 ("calc-pivot-group", calc_pivot_group), ("calc-tracked", calc_tracked), 477 ("calc-chart-axis", lambda: chart_doc("calc-chart-axis", (("c1", 3, None),), label_and_date_axis)), 478 ("calc-chart-types", lambda: chart_doc("calc-chart-types", (("cl", 3, "ColumnWithLine"), ("sv", 4, "StockVolumeLowHighClose")))), 479 ("draw-fontwork", draw_fontwork), ("base", base_doc), ("base-dbase", base_dbase), ("report", report_definition)): 480 step(name, fn) 481print("FAILED:", failed if failed else "none") 482