xref: /trunk/test/odf-validate/fixtures/chart/make.py (revision 0e16a31d78a652c56c5c0fc79c752f48b9048df9)
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#**************************************************************
21# usage: runpy.sh fixtures/chart/make.py <port> <outdir>
22# Charts inside Calc, Writer and Impress/Draw hosts (a standalone chart model crashes the office on store). Saves with the office's configured ODF version.
23import sys, os, uno
24from unohelp import connect, desktop, pv
25from com.sun.star.awt import Rectangle, Size, Point
26from com.sun.star.table import CellRangeAddress
27from com.sun.star.chart.ChartDataRowSource import COLUMNS, ROWS
28
29port, out = int(sys.argv[1]), sys.argv[2]
30os.makedirs(out, exist_ok=True)
31ctx = connect(port)
32desk = desktop(ctx)
33failed = []
34FILTERS = {"ods": "calc8", "odt": "writer8", "odp": "impress8", "odg": "draw8"}
35TPL = "com.sun.star.chart2.template."
36C2 = "com.sun.star.chart2."
37
38
39def new(factory):
40    return desk.loadComponentFromURL(factory, "_blank", 0, (pv("Hidden", True),))
41
42
43def save(doc, name):
44    try:
45        doc.storeToURL(uno.systemPathToFileUrl(os.path.join(out, name)),
46                       (pv("FilterName", FILTERS[name.rsplit(".", 1)[1]]),))
47        print("saved", name)
48    except Exception as e:
49        failed.append(name)
50        print("FAIL save", name, repr(e)[:200])
51
52
53def attempt(label, fn, *a, **kw):
54    try:
55        return fn(*a, **kw)
56    except Exception as e:
57        failed.append(label)
58        print("FAIL", label, repr(e)[:300])
59
60
61def setp(obj, label="", **kw):
62    for k, v in kw.items():
63        try:
64            try:
65                obj.setPropertyValue(k, v)
66            except AttributeError:
67                setattr(obj, k, v)
68        except Exception as e:
69            print("NOPROP", label, k, repr(e)[:120])
70
71
72def const(name):
73    return uno.getConstantByName(name)
74
75
76def enum(typ, val):
77    return uno.Enum(typ, val)
78
79
80CATS = ["Q1", "Q2", "Q3", "Q4", "Q5", "Q6"]
81BLOCKS = {}
82
83
84def fill_data(sh):
85    def put(col, row, v):
86        c = sh.getCellByPosition(col, row)
87        if isinstance(v, str):
88            c.String = v
89        else:
90            c.Value = v
91
92    def cats(col, hdr=""):
93        put(col, 0, hdr)
94        for r, t in enumerate(CATS):
95            put(col, r + 1, t)
96
97    def block(col, names, gen):
98        for j, n in enumerate(names):
99            put(col + j, 0, n)
100            for r in range(6):
101                put(col + j, r + 1, gen(j, r))
102
103    cats(0)
104    block(1, ["north", "south", "east", "west"], lambda j, r: 3 + ((r * (j + 2) * 5 + j * 3) % 9))
105    block(6, ["x", "y1", "y2"], lambda j, r: (r + 1) * 1.5 if j == 0 else (r + 1) * (j + 1) + (r % 3))
106    block(10, ["bx", "by", "size"], lambda j, r: (r + 1) if j == 0 else ((r * 3 + 2) % 7 + 1 if j == 1 else 2 + (r * 5) % 6))
107    cats(15)
108    for j, n in enumerate(["open", "low", "high", "close"]):
109        put(16 + j, 0, n)
110    for r in range(6):
111        o = 20 + (r * 3) % 5
112        lo, hi = o - 3 - r % 2, o + 4 + r % 3
113        cl = o + (2 if r % 2 else -1)
114        for j, v in enumerate([o, lo, hi, cl]):
115            put(16 + j, r + 1, v)
116    cats(21)
117    for j, n in enumerate(["volume", "open", "low", "high", "close"]):
118        put(22 + j, 0, n)
119    for r in range(6):
120        o = 20 + (r * 3) % 5
121        lo, hi = o - 3 - r % 2, o + 4 + r % 3
122        cl = o + (2 if r % 2 else -1)
123        for j, v in enumerate([100 + 30 * r, o, lo, hi, cl]):
124            put(22 + j, r + 1, v)
125    cats(46)
126    for j, n in enumerate(["volume", "low", "high", "close"]):
127        put(47 + j, 0, n)
128    for r in range(6):
129        o = 20 + (r * 3) % 5
130        for j, v in enumerate([100 + 30 * r, o - 3, o + 4, o + 1 + r % 2]):
131            put(47 + j, r + 1, v)
132    cats(28)
133    for j, n in enumerate(["low", "high", "close"]):
134        put(29 + j, 0, n)
135    for r in range(6):
136        o = 20 + (r * 3) % 5
137        for j, v in enumerate([o - 3, o + 4, o + 1 + r % 2]):
138            put(29 + j, r + 1, v)
139    put(33, 0, "date")
140    for j, n in enumerate(["d1", "d2"]):
141        put(34 + j, 0, n)
142    for r in range(6):
143        c = sh.getCellByPosition(33, r + 1)
144        c.Value = 40000 + (0, 1, 3, 4, 9, 15)[r]
145        put(34, r + 1, 5 + (r * 3) % 7)
146        put(35, r + 1, 9 - (r * 2) % 5)
147    sh.getCellRangeByName("AH2:AH7").NumberFormat = date_format(sh)
148    put(37, 0, "gaps")
149    for j, n in enumerate(["g1", "g2"]):
150        put(38 + j, 0, n)
151    for r in range(6):
152        put(37, r + 1, CATS[r])
153        if r != 2:
154            put(38, r + 1, 4 + r)
155        if r != 4:
156            put(39, r + 1, 9 - r)
157    put(41, 0, "err")
158    for j, n in enumerate(["e1", "ep", "en"]):
159        put(42 + j, 0, n)
160    for r in range(6):
161        put(41, r + 1, CATS[r])
162        put(42, r + 1, 6 + (r * 4) % 7)
163        put(43, r + 1, 0.5 + r * 0.25)
164        put(44, r + 1, 0.3 + r * 0.1)
165
166
167def date_format(sh):
168    fm = CURRENT[0].NumberFormats
169    loc = uno.createUnoStruct("com.sun.star.lang.Locale", "en", "US", "")
170    k = fm.queryKey("YYYY-MM-DD", loc, False)
171    return fm.addNew("YYYY-MM-DD", loc) if k == -1 else k
172
173
174CURRENT = [None]
175CHART_CLSID = "12dcae26-281f-416f-a234-c3086127382e"
176
177
178def set_data(ch, data):
179    d = ch.getData()
180    d.setData(tuple(tuple(float(v) for v in row) for row in data["rows"]))
181    d.setRowDescriptions(tuple(data["cats"]))
182    d.setColumnDescriptions(tuple(data["names"]))
183RANGES = {
184    "cat": "Sheet1.A1:E7", "cat1": "Sheet1.A1:B7", "cat2": "Sheet1.A1:C7", "xy": "Sheet1.G1:I7",
185    "bub": "Sheet1.K1:M7", "olhc": "Sheet1.P1:T7", "vol": "Sheet1.V1:AA7", "lhc": "Sheet1.AC1:AF7",
186    "vlhc": "Sheet1.AU1:AY7", "date": "Sheet1.AH1:AJ7", "gap": "Sheet1.AL1:AN7", "err": "Sheet1.AP1:AS7",
187}
188
189
190def a1(sh, ref):
191    return sh.getCellRangeByName(ref.split(".", 1)[1]).RangeAddress
192
193
194class Host:
195    def __init__(self, name, kind="ods"):
196        self.name, self.kind, self.n = name, kind, 0
197        self.doc = new({"ods": "private:factory/scalc", "odt": "private:factory/swriter",
198                        "odp": "private:factory/simpress", "odg": "private:factory/sdraw"}[kind])
199        CURRENT[0] = self.doc
200        if kind == "ods":
201            self.sh = self.doc.Sheets.getByIndex(0)
202            fill_data(self.sh)
203
204    def chart(self, cname, rng, tpl=None, cfg=None, rows=False, cats=True, labels=True, data=None):
205        i = self.n
206        self.n += 1
207        label = "%s/%s" % (self.name, cname)
208        if self.kind == "ods":
209            rect = Rectangle(500 + (i % 3) * 9500, 8000 + (i // 3) * 7200, 9000, 6800)
210            self.sh.Charts.addNewByName(cname, rect, (a1(self.sh, RANGES[rng]),), cats, labels)
211            ch = self.sh.Charts.getByName(cname).EmbeddedObject
212            if tpl:
213                dp = ch.getDataProvider()
214                args = (pv("CellRangeRepresentation", RANGES[rng]), pv("DataRowSource", ROWS if rows else COLUMNS),
215                        pv("FirstCellAsLabel", labels), pv("HasCategories", cats))
216                t = ch.ChartTypeManager.createInstance(TPL + tpl)
217                dia = t.createDiagramByDataSource(dp.createDataSource(args), args)
218                ch.setFirstDiagram(dia)
219        else:
220            ch = self.embed(cname, i)
221            if data:
222                set_data(ch, data)
223            if tpl:
224                t = ch.ChartTypeManager.createInstance(TPL + tpl)
225                t.changeDiagram(ch.getFirstDiagram())
226        if cfg:
227            cfg(ch)
228        return ch
229
230    def embed(self, cname, i):
231        if self.kind == "odt":
232            shape = self.doc.createInstance("com.sun.star.text.TextEmbeddedObject")
233            shape.CLSID = CHART_CLSID
234            shape.Name = cname
235            self.doc.Text.insertTextContent(self.doc.Text.getEnd(), shape, False)
236            return shape.getEmbeddedObject()
237        shape = self.doc.createInstance("com.sun.star.drawing.OLE2Shape")
238        shape.CLSID = CHART_CLSID
239        shape.Position = Point(500 + (i % 2) * 11000, 500 + (i // 2) * 8000)
240        shape.Size = Size(10000, 7000)
241        page = self.doc.DrawPages.getByIndex(0)
242        page.add(shape)
243        return shape.Model
244
245    def done(self):
246        save(self.doc, "%s.%s" % (self.name, self.kind))
247        self.doc.close(True)
248
249
250def series_of(ch):
251    res = []
252    for cs in ch.getFirstDiagram().getCoordinateSystems():
253        for ct in cs.getChartTypes():
254            res.extend(ct.getDataSeries())
255    return res
256
257
258def title(text, sub=None):
259    def f(ch):
260        ch.HasMainTitle = True
261        ch.Title.String = text
262        if sub:
263            ch.HasSubTitle = True
264            ch.SubTitle.String = sub
265    return f
266
267
268def combine(*fs):
269    def f(ch):
270        for g in fs:
271            if g:
272                attempt("cfg " + getattr(g, "__name__", "?"), g, ch)
273    return f
274
275
276def legacy(**kw):
277    def f(ch):
278        setp(ch.getDiagram(), "diagram", **kw)
279    return f
280
281
282def axis(which, **kw):
283    def f(ch):
284        d = ch.getDiagram()
285        setp(getattr(d, which), which, **kw)
286    return f
287
288
289def sprops(idx=None, **kw):
290    def f(ch):
291        for i, s in enumerate(series_of(ch)):
292            if idx is None or i == idx:
293                setp(s, "series%d" % i, **kw)
294    return f
295
296
297def types_doc(name, rng, names, extra=None, kind="ods", data=None):
298    h = Host(name, kind)
299    for n in names:
300        attempt("%s/%s" % (name, n), h.chart, n, rng, n, combine(title(n), extra), False, True, True, data)
301    h.done()
302
303
304def topic_types():
305    types_doc("types-column", "cat", ["Column", "StackedColumn", "PercentStackedColumn", "Bar", "StackedBar",
306              "PercentStackedBar", "ThreeDColumnDeep", "ThreeDColumnFlat", "StackedThreeDColumnFlat",
307              "PercentStackedThreeDColumnFlat", "ThreeDBarDeep", "ThreeDBarFlat", "StackedThreeDBarFlat",
308              "PercentStackedThreeDBarFlat", "ColumnWithLine", "StackedColumnWithLine"])
309    types_doc("types-line", "cat", ["Symbol", "StackedSymbol", "PercentStackedSymbol", "Line", "StackedLine",
310              "PercentStackedLine", "LineSymbol", "StackedLineSymbol", "PercentStackedLineSymbol", "ThreeDLine",
311              "StackedThreeDLine", "PercentStackedThreeDLine", "ThreeDLineDeep"])
312    types_doc("types-area", "cat", ["Area", "StackedArea", "PercentStackedArea", "ThreeDArea", "StackedThreeDArea",
313              "PercentStackedThreeDArea"])
314    types_doc("types-net", "cat", ["Net", "NetSymbol", "NetLine", "StackedNet", "StackedNetSymbol", "StackedNetLine",
315              "PercentStackedNet", "PercentStackedNetSymbol", "PercentStackedNetLine", "FilledNet",
316              "StackedFilledNet", "PercentStackedFilledNet"])
317    types_doc("types-pie", "cat1", ["Pie", "PieAllExploded", "Donut", "DonutAllExploded", "ThreeDPie",
318              "ThreeDPieAllExploded", "ThreeDDonut", "ThreeDDonutAllExploded"])
319    h = Host("types-xy")
320    for n in ["ScatterLineSymbol", "ScatterLine", "ScatterSymbol", "ThreeDScatter"]:
321        attempt("types-xy/" + n, h.chart, n, "xy", n, title(n))
322    attempt("types-xy/Bubble", h.chart, "Bubble", "bub", "Bubble", title("Bubble"))
323    h.done()
324    h = Host("types-stock")
325    attempt("stock/lhc", h.chart, "lhc", "lhc", "StockLowHighClose", title("lhc"))
326    attempt("stock/olhc", h.chart, "olhc", "olhc", "StockOpenLowHighClose", title("olhc"))
327    attempt("stock/vlhc", h.chart, "vlhc", "vlhc", "StockVolumeLowHighClose", title("vlhc"))
328    attempt("stock/volhc", h.chart, "volhc", "vol", "StockVolumeOpenLowHighClose", title("volhc"))
329    h.done()
330
331
332def topic_stock():
333    def markers(ch):
334        d = ch.getDiagram()
335        setp(d.getUpBar(), "upbar", FillColor=0x00ff00, LineColor=0x006600, LineWidth=30, FillStyle=enum("com.sun.star.drawing.FillStyle", "SOLID"))
336        setp(d.getDownBar(), "downbar", FillColor=0xff0000, LineColor=0x660000, LineStyle=enum("com.sun.star.drawing.LineStyle", "DASH"))
337        setp(d.getMinMaxLine(), "minmax", LineColor=0x0000ff, LineWidth=50)
338    h = Host("stock-variants")
339    attempt("stock/markers", h.chart, "m1", "olhc", "StockOpenLowHighClose", combine(title("markers"), markers))
340    attempt("stock/lhc-style", h.chart, "m2", "lhc", "StockLowHighClose", combine(title("lhc styled"), markers))
341    attempt("stock/vol-style", h.chart, "m3", "vol", "StockVolumeOpenLowHighClose", combine(title("vol styled"), markers))
342    attempt("stock/vol2", h.chart, "m4", "vlhc", "StockVolumeLowHighClose", combine(title("vlhc styled"), markers, axis("YAxis", Logarithmic=True)))
343    attempt("stock/updown-off", h.chart, "m5", "olhc", "StockOpenLowHighClose", combine(title("updown off"), legacy(UpDown=False)))
344    h.done()
345
346
347def topic_threed():
348    PM = "com.sun.star.drawing.ProjectionMode"
349    SM = "com.sun.star.drawing.ShadeMode"
350    h = Host("three-d")
351    cases = [
352        ("flat", dict(D3DSceneShadeMode=enum(SM, "FLAT"), D3DScenePerspective=enum(PM, "PARALLEL"))),
353        ("phong", dict(D3DSceneShadeMode=enum(SM, "PHONG"), D3DSceneTwoSidedLighting=True)),
354        ("smooth", dict(D3DSceneShadeMode=enum(SM, "SMOOTH"), D3DSceneTwoSidedLighting=False)),
355        ("draft", dict(D3DSceneShadeMode=enum(SM, "DRAFT"), D3DSceneTwoSidedLighting=True)),
356        ("rot", dict(RightAngledAxes=False, RotationHorizontal=30, RotationVertical=-20, Perspective=40)),
357        ("rot2", dict(RightAngledAxes=True, RotationHorizontal=-45, RotationVertical=10, Perspective=80)),
358    ]
359    for n, kw in cases:
360        attempt("3d/" + n, h.chart, n, "cat", "ThreeDColumnDeep", combine(title("3d " + n), legacy(**kw)))
361    attempt("3d/lights", h.chart, "lights", "cat", "ThreeDColumnFlat", combine(title("lights"), legacy(
362        D3DSceneAmbientColor=0x404040, D3DSceneLightOn1=True, D3DSceneLightColor1=0xffffff, D3DSceneLightOn2=True,
363        D3DSceneLightColor2=0xff0000, D3DSceneLightOn3=True, D3DSceneLightColor3=0x00ff00, D3DSceneLightOn4=True,
364        D3DSceneLightColor4=0x0000ff)))
365    h.done()
366    h = Host("solid-types")
367    for n, v in (("cylinder", 0), ("cone", 1), ("cuboid", 2), ("pyramid", 3)):
368        attempt("solid/" + n, h.chart, n, "cat", "ThreeDColumnDeep", combine(title(n), legacy(SolidType=v)))
369        attempt("solid/bar-" + n, h.chart, "b" + n, "cat", "ThreeDBarDeep", combine(title("bar " + n), legacy(SolidType=v)))
370    attempt("solid/flat-cone", h.chart, "flatcone", "cat", "ThreeDColumnFlat", combine(title("flat cone"), legacy(SolidType=1)))
371    attempt("solid/stacked-cyl", h.chart, "stcyl", "cat", "StackedThreeDColumnFlat", combine(title("stacked cyl"), legacy(SolidType=0)))
372    h.done()
373
374
375def topic_pie():
376    h = Host("pie-variants")
377    attempt("pie/offset", h.chart, "off", "cat1", "Pie", combine(title("offset"), sprops(0, Offset=0.3)))
378    attempt("pie/angle", h.chart, "ang", "cat1", "Pie", combine(title("angle"), legacy(StartingAngle=90)))
379    attempt("pie/donut-angle", h.chart, "dang", "cat1", "Donut", combine(title("donut angle"), legacy(StartingAngle=270)))
380    attempt("pie/2series-donut", h.chart, "d2", "cat", "Donut", title("two rings"))
381
382    def pt(ch):
383        s = series_of(ch)[0]
384        for i in range(3):
385            p = s.getDataPointByIndex(i)
386            setp(p, "pt%d" % i, Offset=0.1 * (i + 1), Color=0x336699 + i * 0x2000)
387    attempt("pie/point-offset", h.chart, "ptoff", "cat1", "Pie", combine(title("point offset"), pt))
388    h.done()
389
390
391AX = "com.sun.star.chart.ChartAxis"
392
393
394def axis_titles(ch):
395    d = ch.getDiagram()
396    for flag, getter, text in (("HasXAxisTitle", d.getXAxisTitle, "x title"), ("HasYAxisTitle", d.getYAxisTitle, "y title")):
397        setp(d, "diagram", **{flag: True})
398        getter().String = text
399
400
401def topic_axes():
402    CP = "com.sun.star.chart.ChartAxisPosition"
403    LP = "com.sun.star.chart.ChartAxisLabelPosition"
404    MP = "com.sun.star.chart.ChartAxisMarkPosition"
405    AO = "com.sun.star.chart.ChartAxisArrangeOrderType"
406    h = Host("axes")
407    A = lambda n, rng, tpl, *fs: attempt("axes/" + n, h.chart, n, rng, tpl, combine(title(n), *fs))
408    A("scale", "cat", "Column", axis("YAxis", Min=1.0, Max=14.0, StepMain=2.0, StepHelpCount=4, Origin=1.0,
409                                       Marks=3, HelpMarks=3))
410    A("marks-none", "cat", "Column", axis("YAxis", Marks=0, HelpMarks=0), axis("XAxis", Marks=1, HelpMarks=2))
411    A("marks-in", "cat", "Column", axis("YAxis", Marks=1, HelpMarks=1), axis("XAxis", Marks=2, HelpMarks=0))
412    A("log", "cat", "Line", axis("YAxis", Logarithmic=True))
413    A("reverse", "cat", "Column", axis("YAxis", ReverseDirection=True), axis("XAxis", ReverseDirection=True))
414    A("grids", "cat", "Column", legacy(HasXAxisGrid=True, HasXAxisHelpGrid=True, HasYAxisGrid=True, HasYAxisHelpGrid=True))
415    A("nogrid", "cat", "Column", legacy(HasYAxisGrid=False, HasXAxisGrid=False))
416    A("hidden-labels", "cat", "Column", axis("XAxis", DisplayLabels=False), axis("YAxis", DisplayLabels=False))
417    A("hidden-axes", "cat", "Column", legacy(HasXAxis=False, HasYAxis=False))
418    A("titles", "cat", "Column", axis_titles)
419    A("rotation", "cat", "Column", axis("XAxis", TextRotation=4500), axis("YAxis", TextRotation=9000))
420    A("stacked-text", "cat", "Column", axis("XAxis", StackedText=True))
421    A("text-break", "cat", "Column", axis("XAxis", TextBreak=True, TextOverlap=True))
422    A("arrange-odd", "cat", "Column", axis("XAxis", ArrangeOrder=enum(AO, "STAGGER_ODD")))
423    A("arrange-even", "cat", "Column", axis("XAxis", ArrangeOrder=enum(AO, "STAGGER_EVEN")))
424    A("arrange-side", "cat", "Column", axis("XAxis", ArrangeOrder=enum(AO, "SIDE_BY_SIDE")))
425    for p in ("START", "END", "VALUE", "ZERO"):
426        A("cross-" + p, "cat", "Column", axis("XAxis", CrossoverPosition=enum(CP, p), CrossoverValue=3.0),
427          axis("YAxis", CrossoverPosition=enum(CP, p), CrossoverValue=2.0))
428    for p in ("NEAR_AXIS", "NEAR_AXIS_OTHER_SIDE", "OUTSIDE_START", "OUTSIDE_END"):
429        A("labelpos-" + p, "cat", "Column", axis("XAxis", LabelPosition=enum(LP, p)), axis("YAxis", LabelPosition=enum(LP, p)))
430    for p in ("AT_LABELS", "AT_AXIS", "AT_LABELS_AND_AXIS"):
431        A("markpos-" + p, "cat", "Column", axis("XAxis", MarkPosition=enum(MP, p)), axis("YAxis", MarkPosition=enum(MP, p)))
432    A("numfmt-link", "cat", "Column", axis("YAxis", LinkNumberFormatToSource=True))
433    A("numfmt-own", "cat", "Column", axis("YAxis", LinkNumberFormatToSource=False, NumberFormat=1))
434    h.done()
435
436    h = Host("axes2")
437    A = lambda n, rng, tpl, *fs: attempt("axes2/" + n, h.chart, n, rng, tpl, combine(title(n), *fs))
438
439    def second(ch):
440        d = ch.getDiagram()
441        d.HasSecondaryYAxis = True
442        d.HasSecondaryXAxis = True
443        series_of(ch)[1].setPropertyValue("AttachedAxisIndex", 1)
444        series_of(ch)[3].setPropertyValue("AttachedAxisIndex", 1)
445        setp(d.SecondaryYAxis, "sec", Min=0.0, Max=20.0)
446    A("secondary", "cat", "Column", second)
447    A("secondary-line", "cat", "Line", second)
448    A("secondary-bar", "cat", "Bar", second)
449    A("xy-axes", "xy", "ScatterLineSymbol", axis("XAxis", Min=0.0, Max=10.0, StepMain=2.0, Logarithmic=False),
450      axis("YAxis", Min=0.0, Max=30.0, StepMain=5.0))
451    A("xy-log", "xy", "ScatterSymbol", axis("XAxis", Logarithmic=True), axis("YAxis", Logarithmic=True))
452    A("zaxis", "cat", "ThreeDColumnDeep", axis("ZAxis", DisplayLabels=True, Marks=3))
453    A("zaxis-title", "cat", "ThreeDColumnDeep", legacy(HasZAxisTitle=True, HasZAxisGrid=True, HasZAxisHelpGrid=True))
454    A("net-axes", "cat", "Net", axis("YAxis", Min=0.0, Max=12.0, StepMain=3.0))
455    A("hidden-cat", "cat", "Column", legacy(HasXAxis=False))
456
457    def dates(ch):
458        ax = ch.getFirstDiagram().getCoordinateSystems()[0].getAxisByDimension(0, 0)
459        sd = ax.getScaleData()
460        sd.AxisType = const("com.sun.star.chart2.AxisType.DATE")
461        sd.AutoDateAxis = False
462        ti = uno.createUnoStruct("com.sun.star.chart.TimeIncrement")
463        ti.TimeResolution = const("com.sun.star.chart.TimeUnit.DAY")
464        ti.MajorTimeInterval = uno.createUnoStruct("com.sun.star.chart.TimeInterval", 2, const("com.sun.star.chart.TimeUnit.DAY"))
465        ti.MinorTimeInterval = uno.createUnoStruct("com.sun.star.chart.TimeInterval", 1, const("com.sun.star.chart.TimeUnit.DAY"))
466        sd.TimeIncrement = ti
467        ax.setScaleData(sd)
468
469    def dates_month(ch):
470        ax = ch.getFirstDiagram().getCoordinateSystems()[0].getAxisByDimension(0, 0)
471        sd = ax.getScaleData()
472        sd.AxisType = const("com.sun.star.chart2.AxisType.DATE")
473        sd.AutoDateAxis = True
474        ti = uno.createUnoStruct("com.sun.star.chart.TimeIncrement")
475        ti.TimeResolution = const("com.sun.star.chart.TimeUnit.MONTH")
476        ti.MajorTimeInterval = uno.createUnoStruct("com.sun.star.chart.TimeInterval", 1, const("com.sun.star.chart.TimeUnit.YEAR"))
477        ti.MinorTimeInterval = uno.createUnoStruct("com.sun.star.chart.TimeInterval", 3, const("com.sun.star.chart.TimeUnit.MONTH"))
478        sd.TimeIncrement = ti
479        ax.setScaleData(sd)
480
481    def real_axis(ch):
482        ax = ch.getFirstDiagram().getCoordinateSystems()[0].getAxisByDimension(0, 0)
483        sd = ax.getScaleData()
484        sd.AxisType = const("com.sun.star.chart2.AxisType.REALNUMBER")
485        ax.setScaleData(sd)
486    A("date-day", "date", "Line", dates)
487    A("date-month", "date", "LineSymbol", dates_month)
488    A("date-col", "date", "Column", dates)
489    A("date-auto", "date", "Line")
490    A("xy-date", "date", "ScatterLineSymbol", dates)
491    A("cat-as-real", "cat", "Line", real_axis)
492    h.done()
493
494
495def label(num=False, pct=False, cat=False, sym=False):
496    return uno.createUnoStruct("com.sun.star.chart2.DataPointLabel", num, pct, cat, sym)
497
498
499def topic_labels():
500    h = Host("labels")
501    combos = [("value", label(num=True)), ("pct", label(pct=True)), ("value-pct", label(num=True, pct=True)),
502              ("cat", label(cat=True)), ("sym", label(sym=True)), ("all", label(True, True, True, True)),
503              ("cat-value", label(num=True, cat=True)), ("sym-value", label(num=True, sym=True)),
504              ("pct-cat-sym", label(pct=True, cat=True, sym=True)), ("none", label())]
505    for n, lab in combos:
506        for tpl, rng in (("Column", "cat"), ("Pie", "cat1")):
507            attempt("labels/%s-%s" % (n, tpl), h.chart, n + tpl, rng, tpl, combine(title(n + " " + tpl), sprops(None, Label=lab)))
508    h.done()
509
510    h = Host("label-opts")
511    seps = [" ", "; ", "\n", ", "]
512    for i, sp in enumerate(seps):
513        attempt("labsep/%d" % i, h.chart, "sep%d" % i, "cat", "Column",
514                combine(title("sep %d" % i), sprops(None, Label=label(num=True, cat=True, pct=True), LabelSeparator=sp)))
515    PL = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
516    for k in range(0, len(PL), 4):
517        vals = PL[k:k + 4]
518
519        def f(ch, vals=vals):
520            for i, s in enumerate(series_of(ch)):
521                if i < len(vals):
522                    setp(s, "place", Label=label(num=True), LabelPlacement=vals[i])
523        attempt("labplace/%d" % k, h.chart, "place%d" % k, "cat", "LineSymbol", combine(title("placement %d" % k), f))
524    attempt("labfmt/own", h.chart, "fmt", "cat", "Column", sprops(None, Label=label(num=True, pct=True), NumberFormat=3, PercentageNumberFormat=10))
525    attempt("labrot", h.chart, "rot", "cat", "Column", sprops(None, Label=label(num=True), TextRotation=90.0))
526
527    def pointlabels(ch):
528        s = series_of(ch)[0]
529        for i in range(3):
530            p = ch.getDiagram().getDataPointProperties(i, 0)
531            setp(p, "pt%d" % i, DataCaption=(1, 2, 3)[i])
532    attempt("labpoint", h.chart, "pt", "cat", "Column", combine(title("point labels"), pointlabels))
533    h.done()
534
535
536def topic_stats():
537    EI = "com.sun.star.chart.ChartErrorIndicatorType"
538    RC = "com.sun.star.chart.ChartRegressionCurveType"
539    h = Host("stats-error")
540    styles = [(1, "variance"), (2, "stddev"), (3, "constant"), (4, "percent"), (5, "margin"), (6, "stderr"), (7, "range")]
541    inds = ["TOP_AND_BOTTOM", "UPPER", "LOWER"]
542    for st, n in styles:
543        for ind in inds:
544            def f(ch, st=st, ind=ind):
545                d = ch.getDiagram()
546                for i in range(2):
547                    p = d.getDataRowProperties(i)
548                    setp(p, "row", ErrorBarStyle=st, ErrorIndicator=enum(EI, ind), ConstantErrorHigh=1.5,
549                         ConstantErrorLow=0.5, PercentageError=12.0, ErrorMargin=8.0)
550                    if st == 7:
551                        setp(p, "range", ErrorBarRangePositive="Sheet1.AR2:AR7", ErrorBarRangeNegative="Sheet1.AS2:AS7")
552            kind = "Column" if ind != "LOWER" else "LineSymbol"
553            attempt("err/%s-%s" % (n, ind), h.chart, "e%d%s" % (st, ind), "cat", kind, combine(title("%s %s" % (n, ind)), f))
554    h.done()
555
556    h = Host("stats-regression")
557    for rc in ("LINEAR", "LOGARITHM", "EXPONENTIAL", "POWER"):
558        def f(ch, rc=rc):
559            d = ch.getDiagram()
560            for i in range(2):
561                setp(d.getDataRowProperties(i), "row", RegressionCurves=enum(RC, rc))
562        attempt("reg/" + rc, h.chart, "r" + rc, "xy", "ScatterSymbol", combine(title(rc), f))
563        attempt("reg/line/" + rc, h.chart, "l" + rc, "cat", "LineSymbol", combine(title("line " + rc), f))
564
565    def equation(ch, rc, show_eq, show_r2, pos):
566        for s in series_of(ch)[:2]:
567            for c in s.getRegressionCurves():
568                e = c.getEquationProperties()
569                setp(e, "eq", ShowEquation=show_eq, ShowCorrelationCoefficient=show_r2,
570                     RelativePosition=uno.createUnoStruct("com.sun.star.chart2.RelativePosition", pos, 0.2,
571                                                           uno.Enum("com.sun.star.drawing.Alignment", "TOP_LEFT")),
572                     NumberFormat=1)
573    for rc in ("LINEAR", "LOGARITHM", "EXPONENTIAL", "POWER"):
574        for sh_eq, sh_r in ((True, False), (False, True), (True, True)):
575            def f(ch, rc=rc, a=sh_eq, b=sh_r):
576                d = ch.getDiagram()
577                for i in range(2):
578                    setp(d.getDataRowProperties(i), "row", RegressionCurves=enum(RC, rc))
579                equation(ch, rc, a, b, 0.3)
580            attempt("eq/%s%s%s" % (rc, sh_eq, sh_r), h.chart, "q%s%d%d" % (rc, sh_eq, sh_r), "xy", "ScatterSymbol",
581                    combine(title("%s eq=%s r2=%s" % (rc, sh_eq, sh_r)), f))
582
583    def curve_style(ch):
584        for s in series_of(ch)[:2]:
585            for c in s.getRegressionCurves():
586                setp(c, "curve", LineColor=0xff0000, LineWidth=60, LineStyle=enum("com.sun.star.drawing.LineStyle", "DASH"))
587        setp(ch.getDiagram().getDataRowProperties(0), "row", RegressionCurves=enum(RC, "LINEAR"))
588    attempt("reg/style", h.chart, "style", "xy", "ScatterLineSymbol", combine(title("curve style"), curve_style))
589    h.done()
590
591    h = Host("stats-mean")
592    for tpl, rng in (("Column", "cat"), ("Line", "cat"), ("ScatterSymbol", "xy"), ("Bar", "cat"), ("Area", "cat")):
593        def f(ch):
594            d = ch.getDiagram()
595            for i in range(2):
596                setp(d.getDataRowProperties(i), "row", MeanValue=True)
597        attempt("mean/" + tpl, h.chart, "m" + tpl, rng, tpl, combine(title("mean " + tpl), f))
598
599    def mean_style(ch):
600        d = ch.getDiagram()
601        for i in range(3):
602            p = d.getDataRowProperties(i)
603            setp(p, "row", MeanValue=True)
604            mp = p.getPropertyValue("DataMeanValueProperties")
605            setp(mp, "mean", LineColor=0x00aa00 + i * 0x1000, LineWidth=40 * (i + 1))
606    attempt("mean/style", h.chart, "mstyle", "cat", "Column", combine(title("mean styled"), mean_style))
607
608    def all_stats(ch):
609        d = ch.getDiagram()
610        p = d.getDataRowProperties(0)
611        setp(p, "row", MeanValue=True, RegressionCurves=enum(RC, "LINEAR"), ErrorBarStyle=3,
612             ErrorIndicator=enum(EI, "TOP_AND_BOTTOM"), ConstantErrorHigh=1.0, ConstantErrorLow=1.0)
613        equation(ch, "LINEAR", True, True, 0.5)
614    attempt("stats/all", h.chart, "all", "xy", "ScatterLineSymbol", combine(title("all stats"), all_stats))
615    h.done()
616
617
618def chart_types(ch):
619    return [ct for cs in ch.getFirstDiagram().getCoordinateSystems() for ct in cs.getChartTypes()]
620
621
622def topic_legend():
623    LP = "com.sun.star.chart.ChartLegendPosition"
624    LE = "com.sun.star.chart.ChartLegendExpansion"
625    h = Host("legend")
626    for p in ("LEFT", "TOP", "RIGHT", "BOTTOM", "NONE"):
627        def f(ch, p=p):
628            ch.HasLegend = True
629            setp(ch.Legend, "legend", Alignment=enum(LP, p))
630        attempt("legend/" + p, h.chart, "L" + p, "cat", "Column", combine(title("legend " + p, "sub " + p), f))
631    for e in ("WIDE", "HIGH", "CUSTOM"):
632        def f(ch, e=e):
633            ch.HasLegend = True
634            setp(ch.Legend, "legend", Expansion=enum(LE, e), Alignment=enum(LP, "TOP"))
635            if e == "CUSTOM":
636                ch.Legend.Size = Size(5000, 2500)
637        attempt("legend/exp" + e, h.chart, "E" + e, "cat", "Line", combine(title("expansion " + e), f))
638
639    def nolegend(ch):
640        ch.HasLegend = False
641    attempt("legend/off", h.chart, "off", "cat", "Column", combine(title("no legend"), nolegend))
642
643    def legend_style(ch):
644        ch.HasLegend = True
645        setp(ch.Legend, "legend", FillStyle=enum("com.sun.star.drawing.FillStyle", "SOLID"), FillColor=0xffffcc,
646             LineStyle=enum("com.sun.star.drawing.LineStyle", "SOLID"), LineColor=0x333333, CharHeight=14.0,
647             CharColor=0x990000, CharWeight=150.0, CharPosture=enum("com.sun.star.awt.FontSlant", "ITALIC"))
648    attempt("legend/style", h.chart, "style", "cat", "Column", combine(title("legend style"), legend_style))
649
650    def titles(ch):
651        ch.HasMainTitle = True
652        ch.HasSubTitle = True
653        ch.Title.String = "Main\nTwo lines"
654        ch.SubTitle.String = "Subtitle text"
655        setp(ch.Title, "title", CharHeight=18.0, CharColor=0x0000ff, CharFontName="Arial", CharWeight=150.0,
656             TextRotation=0, CharUnderline=1)
657        setp(ch.SubTitle, "sub", CharHeight=11.0, CharPosture=enum("com.sun.star.awt.FontSlant", "ITALIC"), TextRotation=90)
658        ch.Title.Position = Point(2000, 100)
659        ch.SubTitle.Position = Point(2000, 1200)
660    attempt("legend/titles", h.chart, "titles", "cat", "Column", titles)
661
662    def rotated(ch):
663        ch.HasMainTitle = True
664        ch.Title.String = "rot"
665        setp(ch.Title, "title", TextRotation=45)
666        axis_titles(ch)
667        d = ch.getDiagram()
668        setp(d.getXAxisTitle(), "xt", TextRotation=90)
669        setp(d.getYAxisTitle(), "yt", TextRotation=270)
670    attempt("legend/rot", h.chart, "rot", "cat", "Column", rotated)
671
672    def wall(ch):
673        d = ch.getDiagram()
674        setp(d.getWall(), "wall", FillStyle=enum("com.sun.star.drawing.FillStyle", "SOLID"), FillColor=0xeeeeff,
675             LineStyle=enum("com.sun.star.drawing.LineStyle", "SOLID"), LineColor=0x888888, LineWidth=30)
676        setp(d.getFloor(), "floor", FillStyle=enum("com.sun.star.drawing.FillStyle", "SOLID"), FillColor=0xccffcc)
677        setp(ch.getPageBackground(), "page", FillStyle=enum("com.sun.star.drawing.FillStyle", "SOLID"), FillColor=0xffeeee)
678    attempt("legend/wall", h.chart, "wall", "cat", "Column", combine(title("wall floor"), wall))
679    attempt("legend/wall3d", h.chart, "wall3d", "cat", "ThreeDColumnDeep", combine(title("3d wall floor"), wall))
680    h.done()
681
682
683def png_file():
684    import zlib, struct, tempfile
685    w = h = 8
686    raw = b"".join(b"\x00" + b"".join(bytes((30 * x, 30 * y, 160)) for x in range(w)) for y in range(h))
687
688    def chunk(t, d):
689        c = struct.pack(">I", len(d)) + t + d
690        return c + struct.pack(">I", zlib.crc32(t + d) & 0xffffffff)
691    data = b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0)) + chunk(b"IDAT", zlib.compress(raw)) + chunk(b"IEND", b"")
692    fd, path = tempfile.mkstemp(suffix=".png")
693    os.write(fd, data)
694    os.close(fd)
695    return path
696
697
698def topic_symbols():
699    global PNG
700    PNG = png_file()
701    SS = "com.sun.star.chart2.SymbolStyle"
702    h = Host("symbols")
703
704    def sym(style, n=0, size=300, fill=0xff6600, border=0x003366):
705        s = uno.createUnoStruct("com.sun.star.chart2.Symbol")
706        s.Style = enum(SS, style)
707        s.StandardSymbol = n
708        s.Size = Size(size, size)
709        s.FillColor = fill
710        s.BorderColor = border
711        return s
712
713    for k in range(0, 15, 4):
714        def f(ch, k=k):
715            for i, s in enumerate(series_of(ch)):
716                setp(s, "sym", Symbol=sym("STANDARD", k + i if k + i < 15 else 0, 200 + 100 * i))
717        attempt("sym/%d" % k, h.chart, "s%d" % k, "cat", "LineSymbol", combine(title("symbols %d.." % k), f))
718
719    def none_auto(ch):
720        ss = series_of(ch)
721        setp(ss[0], "s", Symbol=sym("NONE"))
722        setp(ss[1], "s", Symbol=sym("AUTO"))
723    attempt("sym/none-auto", h.chart, "na", "cat", "LineSymbol", combine(title("none auto"), none_auto))
724
725    def graphic(ch):
726        gp = ctx.ServiceManager.createInstanceWithContext("com.sun.star.graphic.GraphicProvider", ctx)
727        g = gp.queryGraphic((pv("URL", uno.systemPathToFileUrl(PNG)),))
728        s = sym("GRAPHIC")
729        s.Graphic = g
730        setp(series_of(ch)[0], "s", Symbol=s)
731    attempt("sym/graphic", h.chart, "gr", "cat", "LineSymbol", combine(title("graphic"), graphic))
732    attempt("sym/scatter", h.chart, "sc", "xy", "ScatterSymbol", combine(title("scatter sym"), sprops(0, Symbol=sym("STANDARD", 5, 400))))
733    for n, v in (("none", 0), ("cubic", 1), ("bspline", 2)):
734        def f(ch, v=v):
735            setp(ch.getDiagram(), "d", SplineType=v, SplineOrder=3 + v, SplineResolution=20 + 10 * v)
736        attempt("interp/" + n, h.chart, "i" + n, "cat", "LineSymbol", combine(title("spline " + n), f))
737        attempt("interp/xy-" + n, h.chart, "x" + n, "xy", "ScatterLineSymbol", combine(title("xy spline " + n), f))
738    attempt("sym/lines-off", h.chart, "nolines", "xy", "ScatterSymbol", combine(title("lines off"), legacy(Lines=False)))
739    attempt("sym/lines-on", h.chart, "lines", "cat", "Symbol", combine(title("lines on"), legacy(Lines=True)))
740    h.done()
741
742
743def topic_data():
744    h = Host("data")
745    A = lambda n, rng, tpl, cats, labels, *fs, rows=False: attempt("data/" + n, h.chart, n, rng, tpl,
746        combine(title(n), *fs), rows, cats, labels)
747    A("no-labels", "cat", "Column", False, False)
748    A("col-labels", "cat", "Column", False, True)
749    A("row-labels", "cat", "Column", True, False)
750    A("both", "cat", "Column", True, True)
751    A("rows", "cat", "Column", True, True, rows=True)
752    A("rows-nolabels", "cat", "Line", False, False, rows=True)
753    for n, v in (("gap", 0), ("zero", 1), ("cont", 2)):
754        A("missing-" + n, "gap", "LineSymbol", True, True, legacy(MissingValueTreatment=v))
755        A("missing-col-" + n, "gap", "Column", True, True, legacy(MissingValueTreatment=v))
756        A("missing-area-" + n, "gap", "Area", True, True, legacy(MissingValueTreatment=v))
757    A("hidden-on", "cat", "Column", True, True, legacy(IncludeHiddenCells=True))
758    A("hidden-off", "cat", "Column", True, True, legacy(IncludeHiddenCells=False))
759    A("sort-x", "xy", "ScatterLineSymbol", True, True, legacy(SortByXValues=True))
760    A("gapwidth", "cat", "Column", True, True, axis("YAxis", GapWidth=150, Overlap=-30))
761    A("gapwidth-bar", "cat", "Bar", True, True, axis("YAxis", GapWidth=20, Overlap=100))
762    A("gapwidth-2axes", "cat", "Column", True, True, lambda ch: [
763        setp(ch.getDiagram(), "d", HasSecondaryYAxis=True), series_of(ch)[1].setPropertyValue("AttachedAxisIndex", 1),
764        setp(ch.getDiagram().SecondaryYAxis, "y2", GapWidth=70, Overlap=20)])
765    A("connect", "cat", "StackedColumn", True, True, legacy(StackedBarsConnected=True))
766    A("connect-bar", "cat", "StackedBar", True, True, legacy(StackedBarsConnected=True))
767
768    def group(ch):
769        d = ch.getDiagram()
770        d.HasSecondaryYAxis = True
771        series_of(ch)[1].setPropertyValue("AttachedAxisIndex", 1)
772        setp(d, "d", GroupBarsPerAxis=False)
773    A("group-bars", "cat", "Column", True, True, group)
774    A("group-bars-on", "cat", "Column", True, True, lambda ch: [setp(ch.getDiagram(), "d", GroupBarsPerAxis=True), group(ch)])
775    A("scale-text", "cat", "Column", True, True, axis("XAxis", ScaleText=True), axis("YAxis", ScaleText=True),
776      lambda ch: setp(ch.Title, "t", ScaleText=True))
777    A("lineseries", "cat", "ColumnWithLine", True, True, legacy(NumberOfLines=2))
778    A("lineseries-stacked", "cat", "StackedColumnWithLine", True, True, legacy(NumberOfLines=3))
779    A("percent-off", "cat", "StackedColumn", True, True, legacy(Percent=False, Stacked=True))
780    A("stack-off", "cat", "Column", True, True, legacy(Stacked=False, Percent=False))
781    A("vertical-on", "cat", "Column", True, True, legacy(Vertical=True))
782    A("area-deep", "cat", "ThreeDArea", True, True, legacy(Deep=True))
783    A("area-flat", "cat", "ThreeDArea", True, True, legacy(Deep=False))
784    A("line3d-flat", "cat", "ThreeDLine", True, True, legacy(Deep=False))
785    A("dim3d-off", "cat", "ThreeDColumnDeep", True, True, legacy(Dim3D=False))
786    A("bubble-hdr", "bub", "Bubble", True, False)
787    A("scatter-nocats", "xy", "ScatterSymbol", False, True)
788    A("pie-rows", "cat", "Pie", True, True, rows=True)
789    h.done()
790
791    h = Host("point-props")
792
793    def points(ch):
794        d = ch.getDiagram()
795        for i in range(4):
796            p = d.getDataPointProperties(i, 0)
797            setp(p, "pt", FillColor=0x203060 + i * 0x302010, LineColor=0x101010, LineWidth=20 * i,
798                 FillStyle=enum("com.sun.star.drawing.FillStyle", "SOLID"), DataCaption=i % 4,
799                 LineStyle=enum("com.sun.star.drawing.LineStyle", ("SOLID", "DASH", "NONE", "SOLID")[i]),
800                 FillTransparence=10 * i, LineTransparence=5 * i)
801    for t in ("Column", "Line", "Area", "Bar", "StackedColumn"):
802        attempt("pts/" + t, h.chart, "pts" + t, "cat", t, combine(title("points " + t), points))
803
804    def series_style(ch):
805        for i, s in enumerate(series_of(ch)):
806            setp(s, "s", Color=0x113355 + i * 0x303030, FillStyle=enum("com.sun.star.drawing.FillStyle", ("SOLID", "GRADIENT", "HATCH", "SOLID")[i]),
807                 LineStyle=enum("com.sun.star.drawing.LineStyle", "SOLID"), LineWidth=30 * (i + 1), Transparency=20 * i,
808                 CharHeight=9.0 + i, CharColor=0x000000 + i * 0x101010, CharFontName="Helvetica",
809                 CharWeight=100.0 + 20 * i, CharUnderline=i)
810    attempt("series/style", h.chart, "ss", "cat", "Column", combine(title("series style"), series_style))
811    attempt("series/style-line", h.chart, "ssl", "cat", "LineSymbol", combine(title("series style line"), series_style))
812
813    def fills(ch):
814        ss = series_of(ch)
815        g = uno.createUnoStruct("com.sun.star.awt.Gradient")
816        g.Style = enum("com.sun.star.awt.GradientStyle", "LINEAR")
817        g.StartColor = 0xff0000
818        g.EndColor = 0x0000ff
819        g.Angle = 300
820        g.Border = 5
821        g.XOffset = 50
822        g.YOffset = 50
823        g.StartIntensity = 100
824        g.EndIntensity = 100
825        g.StepCount = 0
826        ch.createInstance("com.sun.star.drawing.GradientTable").insertByName("grad1", g)
827        setp(ss[0], "g", FillStyle=enum("com.sun.star.drawing.FillStyle", "GRADIENT"), GradientName="grad1")
828        hs = uno.createUnoStruct("com.sun.star.drawing.Hatch")
829        hs.Style = enum("com.sun.star.drawing.HatchStyle", "DOUBLE")
830        hs.Color = 0x00aa00
831        hs.Distance = 100
832        hs.Angle = 450
833        ch.createInstance("com.sun.star.drawing.HatchTable").insertByName("hatch1", hs)
834        setp(ss[1], "h", FillStyle=enum("com.sun.star.drawing.FillStyle", "HATCH"), HatchName="hatch1", FillBackground=True,
835             Color=0xffffaa)
836    attempt("series/gradient-hatch", h.chart, "grad", "cat", "Column", combine(title("gradient hatch"), fills))
837    h.done()
838
839
840D5 = {"cats": CATS[:5], "names": ["north", "south", "east"],
841      "rows": [(4, 7, 5), (6, 3, 8), (5, 9, 4), (8, 6, 7), (3, 5, 9)]}
842DX = {"cats": ["1", "2", "3", "4", "5"], "names": ["y1", "y2"], "rows": [(2, 3), (4, 3.5), (5, 6), (7, 5.5), (9, 8)]}
843DS = {"cats": CATS[:5], "names": ["open", "low", "high", "close"],
844      "rows": [(20, 17, 24, 22), (21, 18, 26, 20), (22, 19, 25, 24), (23, 18, 27, 25), (21, 17, 26, 19)]}
845DV = {"cats": CATS[:5], "names": ["volume", "open", "low", "high", "close"],
846      "rows": [(120, 20, 17, 24, 22), (90, 21, 18, 26, 20), (150, 22, 19, 25, 24), (80, 23, 18, 27, 25), (110, 21, 17, 26, 19)]}
847EMBED = [
848    ("Column", D5), ("StackedColumn", D5), ("PercentStackedBar", D5), ("Line", D5), ("LineSymbol", D5), ("Area", D5),
849    ("StackedArea", D5), ("Pie", {"cats": CATS[:5], "names": ["share"], "rows": [(4,), (6,), (5,), (8,), (3,)]}),
850    ("Donut", D5), ("ScatterLineSymbol", DX), ("Net", D5), ("FilledNet", D5), ("StockOpenLowHighClose", DS),
851    ("StockVolumeOpenLowHighClose", DV), ("StockLowHighClose", {"cats": CATS[:5], "names": ["low", "high", "close"],
852        "rows": [(17, 24, 22), (18, 26, 20), (19, 25, 24), (18, 27, 25), (17, 26, 19)]}),
853    ("ThreeDColumnDeep", D5), ("ThreeDPie", {"cats": CATS[:5], "names": ["share"], "rows": [(4,), (6,), (5,), (8,), (3,)]}),
854    ("ThreeDArea", D5), ("ColumnWithLine", D5), ("Bar", D5),
855]
856
857
858def embedded_doc(name, kind, items, extra=None):
859    h = Host(name, kind)
860    for i, (tpl, data) in enumerate(items):
861        attempt("%s/%s" % (name, tpl), h.chart, "%s%d" % (tpl, i), None, tpl, combine(title(tpl, "sub " + tpl), extra), data=data)
862    h.done()
863
864
865def topic_hosts():
866    def legend_labels(ch):
867        ch.HasLegend = True
868        sprops(None, Label=label(num=True))(ch)
869    embedded_doc("embed-writer", "odt", EMBED[:10], legend_labels)
870    embedded_doc("embed-writer2", "odt", EMBED[10:], axis_titles)
871    embedded_doc("embed-impress", "odp", EMBED[:10], legend_labels)
872    embedded_doc("embed-impress2", "odp", EMBED[10:], None)
873    embedded_doc("embed-draw", "odg", EMBED[:8])
874    embedded_doc("embed-draw2", "odg", EMBED[8:])
875
876
877def topic_writer_table():
878    doc = new("private:factory/swriter")
879    CURRENT[0] = doc
880    try:
881        for rows in (5, 5):
882            t = doc.createInstance("com.sun.star.text.TextTable")
883            t.initialize(rows, 4)
884            doc.Text.insertTextContent(doc.Text.getEnd(), t, False)
885            for c in "BCD":
886                t.getCellByName(c + "1").String = "s" + c
887            for r in range(2, rows + 1):
888                t.getCellByName("A%d" % r).String = "c%d" % r
889                for j, c in enumerate("BCD"):
890                    t.getCellByName("%s%d" % (c, r)).Value = (r * (j + 2) * 3) % 9 + 1
891            doc.Text.insertControlCharacter(doc.Text.getEnd(), uno.getConstantByName("com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK"), False)
892    except Exception as e:
893        failed.append("writer-table")
894        import traceback
895        traceback.print_exc()
896        print("FAIL writer table", repr(e)[:200])
897    dp = doc.createInstance("com.sun.star.chart2.data.DataProvider")
898    print("writer dp", dp is not None)
899    for i, (tn, tpl) in enumerate((("Table1", "Column"), ("Table1", "Line"), ("Table2", "Pie"), ("Table2", "StockOpenLowHighClose"),
900                                   ("Table1", "Bar"), ("Table2", "Area"))):
901        def mk(tn=tn, tpl=tpl, i=i):
902            shape = doc.createInstance("com.sun.star.text.TextEmbeddedObject")
903            shape.CLSID = CHART_CLSID
904            shape.Name = "wc%d" % i
905            doc.Text.insertTextContent(doc.Text.getEnd(), shape, False)
906            ch = shape.getEmbeddedObject()
907            ch.attachDataProvider(doc.createInstance("com.sun.star.chart2.data.DataProvider"))
908            rng = tn + ".A1:D5" if tpl != "Pie" else tn + ".A1:B5"
909            args = (pv("CellRangeRepresentation", rng), pv("DataRowSource", COLUMNS), pv("FirstCellAsLabel", True), pv("HasCategories", True))
910            ch.setArguments(args)
911            t = ch.ChartTypeManager.createInstance(TPL + tpl)
912            ch.setFirstDiagram(t.createDiagramByDataSource(ch.getDataProvider().createDataSource(args), args))
913            title("table chart %s %s" % (tn, tpl))(ch)
914            ch.HasLegend = True
915        attempt("writer-table/%s-%s" % (tn, tpl), mk)
916    save(doc, "embed-writer-table.odt")
917    doc.close(True)
918
919
920for _t in (topic_types, topic_stock, topic_threed, topic_pie, topic_axes, topic_labels, topic_stats, topic_legend,
921           topic_symbols, topic_data, topic_hosts, topic_writer_table):
922    attempt(_t.__name__, _t)
923try:
924    os.remove(PNG)
925except Exception:
926    pass
927print("failed:", failed)
928sys.exit(1 if failed else 0)
929