xref: /trunk/test/odf-validate/fixtures/writer/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#
22# usage: runpy.sh fixtures/writer/make.py <port> <outdir>
23# Writer constructs the corpus lacks (fields, variables, references, indexes, forms, settings, tracked changes, ...). Saves with the office's configured ODF version: run it against the strict and extended profiles.
24import sys, os, traceback, uno
25from unohelp import connect, desktop, pv
26
27port, out = int(sys.argv[1]), os.path.abspath(sys.argv[2])
28os.makedirs(out, exist_ok=True)
29desk_ctx = connect(port)
30desk = desktop(desk_ctx)
31failed = []
32ODT = "writer8"
33
34
35def new(factory="private:factory/swriter"):
36    return desk.loadComponentFromURL(factory, "_blank", 0, (pv("Hidden", True),))
37
38
39SUF = ""
40
41
42def save(doc, name, filt=ODT):
43    base, ext = os.path.splitext(name)
44    name = base + SUF + ext
45    try:
46        doc.storeToURL(uno.systemPathToFileUrl(os.path.join(out, name)), (pv("FilterName", filt),))
47        print("saved", name, filt)
48    except Exception as e:
49        failed.append(name)
50        print("FAIL", name, filt, type(e).__name__, str(e)[:200], 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, type(e).__name__, str(e)[:100], repr(e)[:200], "line", traceback.extract_tb(e.__traceback__)[-1].lineno)
59
60
61class W:
62    def __init__(self, doc):
63        self.doc = doc
64        self.text = doc.Text
65        self.cur = self.text.createTextCursor()
66        self.cur.gotoEnd(False)
67
68    def s(self, txt):
69        self.text.insertString(self.cur, txt, False)
70
71    def para(self, txt=""):
72        self.text.insertControlCharacter(self.cur, 0, False)
73        if txt:
74            self.s(txt)
75
76    def mk(self, service, **props):
77        o = self.doc.createInstance(service)
78        for k, v in props.items():
79            setattr(o, k, v)
80        return o
81
82    def put(self, content, absorb=False):
83        self.text.insertTextContent(self.cur, content, absorb)
84
85    def field(self, kind, label=None, **props):
86        lab = label or kind
87        try:
88            f = self.mk("com.sun.star.text.TextField." + kind, **props)
89            self.put(f)
90            self.s(" ")
91            return f
92        except Exception as e:
93            failed.append("field " + lab)
94            print("FAIL field", lab, type(e).__name__, str(e)[:100], repr(e)[:160])
95
96
97def dt(y=2024, mo=3, d=15, h=10, mi=30, s=0):
98    return uno.createUnoStruct("com.sun.star.util.DateTime", 0, s, mi, h, d, mo, y)
99
100
101def date(y=2024, mo=3, d=15):
102    return uno.createUnoStruct("com.sun.star.util.Date", d, mo, y)
103
104
105def numfmt(doc, fmt, lang="en", country="US"):
106    nf = doc.NumberFormats
107    loc = uno.createUnoStruct("com.sun.star.lang.Locale", lang, country, "")
108    k = nf.queryKey(fmt, loc, False)
109    if k == -1:
110        k = nf.addNew(fmt, loc)
111    return k
112
113
114def doc_fields_info():
115    doc = new()
116    w = W(doc)
117    doc.DocumentProperties.Title = "Field title"
118    doc.DocumentProperties.Subject = "Field subject"
119    doc.DocumentProperties.Description = "Field description"
120    doc.DocumentProperties.Keywords = ("one", "two")
121    doc.DocumentProperties.Author = "Field Author"
122    doc.DocumentProperties.PrintedBy = "Printer Person"
123    doc.DocumentProperties.PrintDate = dt(2024, 4, 1)
124    doc.DocumentProperties.ModifiedBy = "Modifier"
125    doc.DocumentProperties.ModificationDate = dt(2024, 5, 2)
126    doc.DocumentProperties.EditingCycles = 7
127    doc.DocumentProperties.EditingDuration = 3661
128    udp = doc.DocumentProperties.UserDefinedProperties
129    doc.DocumentProperties.DefaultTarget = "_self"
130    doc.DocumentProperties.AutoloadURL = "http://example.org/reload"
131    doc.DocumentProperties.AutoloadSecs = 90
132    doc.DocumentProperties.TemplateName = "tpl"
133    doc.DocumentProperties.TemplateURL = "file:///tmp/tpl.ott"
134    doc.DocumentProperties.Language = uno.createUnoStruct("com.sun.star.lang.Locale", "en", "US", "")
135    for nm, val in (("cstr", "text"), ("cnum", 42.5), ("cbool", True), ("cdate", dt(2024, 6, 7)), ("cdate2", date(2024, 6, 8)),
136                    ("ctime", uno.createUnoStruct("com.sun.star.util.Time", 0, 3, 2, 1)),
137                    ("cdur", uno.createUnoStruct("com.sun.star.util.Duration", False, 0, 1, 2, 3, 4, 5, 6))):
138        try:
139            udp.addProperty(nm, 128, val)
140        except Exception as e:
141            print("udp", nm, repr(e)[:100])
142    fid = 0
143    for sub in ("DocInfo.Title", "DocInfo.Subject", "DocInfo.Description", "DocInfo.KeyWords",
144                "DocInfo.CreateAuthor", "DocInfo.ChangeAuthor", "DocInfo.PrintAuthor"):
145        for fixed in (True, False):
146            w.field(sub, sub + str(fixed), IsFixed=fixed)
147    w.para()
148    for sub in ("DocInfo.CreateDateTime", "DocInfo.ChangeDateTime", "DocInfo.PrintDateTime"):
149        for isdate in (True, False):
150            for fixed in (True, False):
151                w.field(sub, "%s %s %s" % (sub, isdate, fixed), IsDate=isdate, IsFixed=fixed,
152                        NumberFormat=numfmt(doc, "YYYY-MM-DD" if isdate else "HH:MM:SS"))
153        w.para()
154    w.field("DocInfo.EditTime", NumberFormat=numfmt(doc, "[HH]:MM:SS"))
155    w.field("DocInfo.Revision", IsFixed=True)
156    w.field("DocInfo.Revision", "rev2", IsFixed=False)
157    w.para()
158    for nm in ("cstr", "cnum", "cbool", "cdate", "cdate2", "ctime", "cdur"):
159        for fixed in (True, False):
160            w.field("DocInfo.Custom", "custom " + nm, Name=nm, IsFixed=fixed, NumberFormat=numfmt(doc, "0.00"))
161    w.para()
162    save(doc, "fields-docinfo.odt")
163    doc.close(True)
164
165
166
167def doc_fields_misc():
168    doc = new()
169    w = W(doc)
170    doc.DocumentProperties.Author = "Misc Author"
171    for fixed in (True, False):
172        for full in (True, False):
173            w.field("Author", "author %s %s" % (fixed, full), IsFixed=fixed, FullName=full, Content="A. Person")
174    w.para()
175    for part in range(15):
176        for fixed in (True, False):
177            w.field("ExtendedUser", "sender %d %s" % (part, fixed), UserDataType=part, IsFixed=fixed,
178                    Content="sender%d" % part)
179    w.para()
180    for isdate in (True, False):
181        for fixed in (True, False):
182            for adj in (0, 5, -3):
183                w.field("DateTime", "datetime %s %s %d" % (isdate, fixed, adj), IsDate=isdate, IsFixed=fixed, Adjust=adj,
184                        NumberFormat=numfmt(doc, "DD.MM.YYYY" if isdate else "HH:MM"),
185                        DateTimeValue=dt())
186        w.para()
187    for sub in (0, 1, 2):
188        for ntype in (4, 0, 1, 2, 3, 6, 9, 10):
189            w.field("PageNumber", "pagenum %d %d" % (sub, ntype), SubType=sub, NumberingType=ntype, Offset=2 if sub == 1 else 0,
190                    UserText="p")
191    w.para()
192    for kind in ("PageCount", "ParagraphCount", "WordCount", "CharacterCount", "TableCount",
193                 "GraphicObjectCount", "EmbeddedObjectCount"):
194        for ntype in (4, 0, 1, 2, 3, 9, 10):
195            w.field(kind, "%s %d" % (kind, ntype), NumberingType=ntype)
196    w.para()
197    for fmt in range(4):
198        w.field("FileName", "filename %d" % fmt, FileFormat=fmt, IsFixed=(fmt % 2 == 0))
199    for fmt in range(6):
200        w.field("TemplateName", "template %d" % fmt, FileFormat=fmt)
201    w.para()
202    for fmt in range(5):
203        for lvl in (0, 3):
204            w.field("Chapter", "chapter %d %d" % (fmt, lvl), ChapterFormat=fmt, Level=lvl)
205    w.para()
206    for ptype in range(5):
207        w.field("JumpEdit", "placeholder %d" % ptype, PlaceHolderType=ptype, PlaceHolder="ph%d" % ptype, Hint="hint")
208    w.para()
209    w.field("Input", "input", Content="text", Hint="descr", Help="help text", Tooltip="tip text")
210    w.field("Input", "input2", Content="x", Hint="d2")
211    w.para()
212    w.field("ConditionalText", "cond", Condition="1==1", TrueContent="yes", FalseContent="no")
213    w.field("ConditionalText", "cond2", Condition="1==2", TrueContent="yes", FalseContent="no")
214    w.field("HiddenText", "hidden", Condition="1==2", Content="secret")
215    w.field("HiddenText", "hidden2", Condition="1==1", Content="secret2")
216    w.field("HiddenParagraph", "hiddenpar", Condition="1==2")
217    w.para("after hidden paragraph")
218    w.field("HiddenParagraph", "hiddenpar2", Condition="1==1")
219    w.para()
220    w.field("DropDown", "dropdown", Name="dd", Items=("one", "two", "three"), SelectedItem="two", Help="dh", Tooltip="dt")
221    w.field("DropDown", "dropdown2", Name="dd2", Items=("a",), SelectedItem="zzz")
222    w.para()
223    w.field("Script", "script1", ScriptType="text/javascript", Content="alert(1)", URLContent=False)
224    w.field("Script", "script2", ScriptType="text/javascript", Content="http://example.org/s.js", URLContent=True)
225    w.para()
226    w.field("ReferencePageSet", "refpageset", On=True, Offset=3)
227    w.field("ReferencePageSet", "refpageset0", On=False, Offset=0)
228    w.field("ReferencePageGet", "refpageget", NumberingType=4)
229    w.field("ReferencePageGet", "refpageget2", NumberingType=1)
230    w.para()
231    w.field("CombinedCharacters", "combined", Content="ab")
232    w.para()
233    w.field("Macro", "macro", Hint="macro hint", MacroLibrary="Standard", MacroName="Module1.Macro1")
234    w.field("Macro", "macro2", Hint="h", ScriptURL="vnd.sun.star.script:Module1.Macro1?language=Basic&location=document",
235            MacroLibrary="", MacroName="")
236    w.para()
237    save(doc, "fields-misc.odt")
238    doc.close(True)
239
240
241
242NF = {"date": 2, "time": 4, "datetime": 6, "currency": 8, "number": 16, "scientific": 32, "fraction": 64,
243      "percent": 128, "text": 256, "boolean": 1024}
244
245
246def stdfmt(doc, kind):
247    loc = uno.createUnoStruct("com.sun.star.lang.Locale", "en", "US", "")
248    return doc.NumberFormats.getStandardFormat(NF[kind], loc)
249
250
251def doc_variables():
252    doc = new()
253    w = W(doc)
254
255    def setvar(name, sub, content, fmt=None, visible=True, value=None, inp=False, hint=None, label=None):
256        m = doc.createInstance("com.sun.star.text.FieldMaster.SetExpression")
257        try:
258            m.Name = name
259        except Exception:
260            pass
261        m.SubType = sub
262        f = doc.createInstance("com.sun.star.text.TextField.SetExpression")
263        f.attachTextFieldMaster(m)
264        f.SubType = sub
265        f.Content = content
266        if fmt is not None:
267            f.NumberFormat = fmt
268        f.IsVisible = visible
269        if value is not None:
270            f.Value = value
271        if inp:
272            f.IsInput = True
273            if hint:
274                f.Hint = hint
275        w.put(f)
276        w.s(" ")
277        return f
278
279    for kind in ("number", "date", "time", "datetime", "currency", "percent", "scientific", "fraction", "boolean"):
280        attempt("setvar " + kind, setvar, "var_" + kind, 0, "1+2" if kind != "boolean" else "1", stdfmt(doc, kind), True, 3.5)
281    w.para()
282    attempt("setvar hidden", setvar, "var_hidden", 0, "5", stdfmt(doc, "number"), False)
283    attempt("setvar string", setvar, "var_str", 3, "some text", stdfmt(doc, "text"))
284    attempt("setvar string2", setvar, "var_str2", 3, "other", None, False)
285    attempt("setvar input num", setvar, "var_in", 0, "7", stdfmt(doc, "number"), True, 7.0, True, "num hint")
286    attempt("setvar input str", setvar, "var_in2", 3, "txt", None, True, None, True, "str hint")
287    attempt("setvar input date", setvar, "var_in3", 0, "40000", stdfmt(doc, "date"), True, 40000.0, True, "date hint")
288    w.para()
289    for kind in ("number", "date", "currency", "percent", "boolean"):
290        for show in (False, True):
291            f = w.field("GetExpression", "getvar %s %s" % (kind, show), Content="var_" + kind, SubType=0,
292                        NumberFormat=stdfmt(doc, kind), IsShowFormula=show)
293    w.field("GetExpression", "getvar str", Content="var_str", SubType=3, NumberFormat=stdfmt(doc, "text"))
294    w.para()
295    for show in (False, True):
296        for kind in ("number", "date", "percent"):
297            w.field("GetExpression", "expr %s %s" % (kind, show), Content="1+2*3", SubType=2,
298                    NumberFormat=stdfmt(doc, kind), IsShowFormula=show)
299    w.field("GetExpression", "expr nofmt", Content="var_number*2", SubType=2)
300    w.para()
301
302    um = []
303    for name, isexpr, val in (("usr_num", True, 12.5), ("usr_str", False, "hello"), ("usr_num2", True, 3.0)):
304        m = doc.createInstance("com.sun.star.text.FieldMaster.User")
305        m.Name = name
306        m.IsExpression = isexpr
307        if isexpr:
308            m.Value = val
309        else:
310            m.Content = val
311        um.append(m)
312    for m in um:
313        for kind in ("number", "date", "currency", "text"):
314            for visible in (True, False):
315                for show in (False, True):
316                    f = doc.createInstance("com.sun.star.text.TextField.User")
317                    try:
318                        f.attachTextFieldMaster(m)
319                        f.NumberFormat = stdfmt(doc, kind)
320                        f.IsVisible = visible
321                        f.IsShowFormula = show
322                        w.put(f)
323                        w.s(" ")
324                    except Exception as e:
325                        print("FAIL userfield", m.Name, kind, repr(e)[:100])
326                        failed.append("userfield")
327    w.para()
328    f = doc.createInstance("com.sun.star.text.TextField.InputUser")
329    f.Content = "usr_str"
330    f.Hint = "user hint"
331    w.put(f)
332    w.s(" ")
333    w.para()
334    ddem = doc.createInstance("com.sun.star.text.FieldMaster.DDE")
335    ddem.Name = "ddeconn"
336    ddem.DDECommandType = "soffice"
337    ddem.DDECommandFile = "file.ods"
338    ddem.DDECommandElement = "Sheet1.A1"
339    ddem.IsAutomaticUpdate = False
340    f = doc.createInstance("com.sun.star.text.TextField.DDE")
341    f.attachTextFieldMaster(ddem)
342    w.put(f)
343    w.s(" ")
344    ddem2 = doc.createInstance("com.sun.star.text.FieldMaster.DDE")
345    ddem2.Name = "ddeconn2"
346    ddem2.DDECommandType = "soffice"
347    ddem2.DDECommandFile = "file2.ods"
348    ddem2.DDECommandElement = "Sheet1.B2"
349    ddem2.IsAutomaticUpdate = True
350    f = doc.createInstance("com.sun.star.text.TextField.DDE")
351    f.attachTextFieldMaster(ddem2)
352    w.put(f)
353    w.s(" ")
354    w.para()
355    save(doc, "variables.odt")
356    doc.close(True)
357
358
359
360def tpl(**kw):
361    return tuple(pv(k, v) for k, v in kw.items())
362
363
364def mark(w, service, text, absorb_len=0, **props):
365    m = w.mk("com.sun.star.text." + service, **props)
366    if absorb_len:
367        w.cur.goLeft(absorb_len, True)
368        w.text.insertTextContent(w.cur, m, True)
369        w.cur.gotoEnd(False)
370    else:
371        w.put(m)
372    return m
373
374
375def doc_indexes():
376    doc = new()
377    w = W(doc)
378    w.cur.ParaStyleName = "Heading 1"
379    w.s("Chapter one")
380    w.para()
381    w.cur.ParaStyleName = "Standard"
382    w.s("Body paragraph with an ")
383    w.s("alpha")
384    attempt("docmark range", mark, w, "DocumentIndexMark", "alpha", 5, AlternativeText="", PrimaryKey="Greek", SecondaryKey="first",
385            TextReading="a", PrimaryKeyReading="g", SecondaryKeyReading="f", IsMainEntry=True)
386    w.s(" and ")
387    attempt("docmark point", mark, w, "DocumentIndexMark", "", 0, AlternativeText="beta entry", PrimaryKey="Greek",
388            SecondaryKey="second", IsMainEntry=False, TextReading="b", PrimaryKeyReading="g2", SecondaryKeyReading="s2")
389    w.s(" and ")
390    w.s("gamma")
391    attempt("docmark range2", mark, w, "DocumentIndexMark", "gamma", 5, PrimaryKey="Greek", IsMainEntry=False)
392    w.s(" and tocmark ")
393    attempt("tocmark point", mark, w, "ContentIndexMark", "", 0, AlternativeText="toc point", Level=1)
394    w.s(" tocrange")
395    attempt("tocmark range", mark, w, "ContentIndexMark", "", 8, Level=2)
396    w.s(" and usermark ")
397    attempt("usermark point", mark, w, "UserIndexMark", "", 0, AlternativeText="user point", Level=0, UserIndexName="MyIndex")
398    w.s(" userrange")
399    attempt("usermark range", mark, w, "UserIndexMark", "", 9, Level=1, UserIndexName="MyIndex")
400    w.s(".")
401    w.para()
402    w.cur.ParaStyleName = "Heading 2"
403    w.s("Section 1.1")
404    w.para()
405    w.cur.ParaStyleName = "Standard"
406    w.para("Another body.")
407    w.cur.ParaStyleName = "Heading 3"
408    w.para("Deep heading")
409    w.cur.ParaStyleName = "Standard"
410    w.para("")
411
412    def seqfield(cat, desc):
413        w.para("%s " % cat)
414        try:
415            mname = "com.sun.star.text.FieldMaster.SetExpression." + cat
416            master = doc.TextFieldMasters.getByName(mname)
417        except Exception:
418            master = doc.createInstance("com.sun.star.text.FieldMaster.SetExpression")
419            master.Name = cat
420            master.SubType = 1
421        f = doc.createInstance("com.sun.star.text.TextField.SetExpression")
422        f.attachTextFieldMaster(master)
423        f.SubType = 1
424        f.NumberingType = 9 if cat == "Text" else 4
425        f.Content = cat + "+1"
426        w.put(f)
427        w.s(": " + desc)
428
429    for cat in ("Illustration", "Illustration", "Table", "Table", "Drawing", "Text"):
430        attempt("seq " + cat, seqfield, cat, "description of " + cat)
431    w.para()
432
433    def add(label, service, props, levels=None, lps=None):
434        w.para("")
435        w.s("")
436        idx = w.mk("com.sun.star.text." + service)
437        for k, v in props.items():
438            try:
439                setattr(idx, k, v)
440            except Exception as e:
441                print("prop fail", label, k, repr(e)[:80])
442                failed.append(label + " " + k)
443        if lps:
444            try:
445                for lv, names in lps.items():
446                    uno.invoke(idx.LevelParagraphStyles, "replaceByIndex", (lv, uno.Any("[]string", tuple(names))))
447            except Exception as e:
448                print("lps fail", label, repr(e)[:120])
449                failed.append(label + " lps")
450        if levels:
451            try:
452                lf = idx.LevelFormat
453                for lv, toks in levels.items():
454                    uno.invoke(lf, "replaceByIndex", (lv, uno.Any("[][]com.sun.star.beans.PropertyValue", tuple(tuple(t) for t in toks))))
455            except Exception as e:
456                print("levels fail", label, repr(e)[:120])
457                failed.append(label + " levels")
458        w.put(idx)
459        w.cur.gotoEnd(False)
460        try:
461            idx.update()
462        except Exception as e:
463            print("update fail", label, repr(e)[:100])
464        return idx
465
466    toks_toc = [
467        tpl(TokenType="TokenEntryNumber", CharacterStyleName="Strong Emphasis"),
468        tpl(TokenType="TokenText", Text="> ", CharacterStyleName="Emphasis"),
469        tpl(TokenType="TokenHyperlinkStart", CharacterStyleName="Internet link"),
470        tpl(TokenType="TokenEntryText", CharacterStyleName="Emphasis"),
471        tpl(TokenType="TokenHyperlinkEnd", CharacterStyleName="Internet link"),
472        tpl(TokenType="TokenTabStop", TabStopRightAligned=False, TabStopPosition=3000, TabStopFillCharacter="-", WithTab=False,
473            CharacterStyleName="Emphasis"),
474        tpl(TokenType="TokenTabStop", TabStopRightAligned=True, TabStopFillCharacter=".", WithTab=True),
475        tpl(TokenType="TokenPageNumber", CharacterStyleName="Strong Emphasis"),
476        tpl(TokenType="TokenChapterInfo", ChapterFormat=1, ChapterLevel=2, CharacterStyleName="Emphasis"),
477    ]
478    attempt("toc1", add, "toc1", "ContentIndex", dict(Title="Contents", Level=10, CreateFromOutline=True, CreateFromMarks=False,
479            CreateFromLevelParagraphStyles=True, IsRelativeTabstops=False, CreateFromChapter=True, IsProtected=True,
480            ParaStyleHeading="Heading 2", ParaStyleLevel1="Heading 3", Name="TOC one"),
481            {1: toks_toc, 2: toks_toc[:4]}, {0: ("Heading 4", "Title"), 2: ("Subtitle",)})
482    attempt("toc2", add, "toc2", "ContentIndex", dict(Title="", Level=3, CreateFromOutline=False, CreateFromMarks=True,
483            IsRelativeTabstops=True, Name="TOC two"))
484    attempt("toc3", add, "toc3", "ContentIndex", dict(Title="Plain", Level=1, CreateFromOutline=True, CreateFromMarks=True))
485
486    toks_alpha = [
487        tpl(TokenType="TokenEntryText", CharacterStyleName="Emphasis"),
488        tpl(TokenType="TokenTabStop", TabStopRightAligned=True, TabStopFillCharacter=" "),
489        tpl(TokenType="TokenPageNumber"),
490        tpl(TokenType="TokenChapterInfo", ChapterFormat=4, ChapterLevel=1),
491    ]
492    for n, props in enumerate((
493            dict(Title="Alpha 1", UseAlphabeticalSeparators=True, UseCombinedEntries=False, UseDash=True, UseKeyAsEntry=True,
494                 UsePP=False, UseUpperCase=True, IsCommaSeparated=True, IsCaseSensitive=True, CreateFromChapter=True,
495                 IsRelativeTabstops=False, MainEntryCharacterStyleName="Strong Emphasis", SortAlgorithm="alphanumeric",
496                 Locale=uno.createUnoStruct("com.sun.star.lang.Locale", "en", "US", "")),
497            dict(Title="Alpha 2", UseAlphabeticalSeparators=False, UseCombinedEntries=True, UseDash=False, UseKeyAsEntry=False,
498                 UsePP=True, UseUpperCase=False, IsCommaSeparated=False, IsCaseSensitive=False,
499                 SortAlgorithm="", Locale=uno.createUnoStruct("com.sun.star.lang.Locale", "de", "DE", ""))), 1):
500        attempt("alpha%d" % n, add, "alpha%d" % n, "DocumentIndex", props, {1: toks_alpha, 2: toks_alpha[:2], 3: toks_alpha[:3]})
501
502    for n, (service, props) in enumerate((
503            ("IllustrationsIndex", dict(Title="Figures", CreateFromLabels=True, LabelCategory="Illustration", LabelDisplayType=5,
504                                         CreateFromChapter=True, IsRelativeTabstops=False)),
505            ("IllustrationsIndex", dict(Title="Figures 2", CreateFromLabels=False, LabelCategory="Drawing", LabelDisplayType=5)),
506            ("IllustrationsIndex", dict(Title="Figures 3", LabelCategory="Text", LabelDisplayType=6)),
507            ("TableIndex", dict(Title="Tables", CreateFromLabels=True, LabelCategory="Table", LabelDisplayType=5,
508                                CreateFromChapter=True, IsRelativeTabstops=False)),
509            ("TableIndex", dict(Title="Tables 2", CreateFromLabels=False, LabelCategory="Table", LabelDisplayType=6)),
510            ("TableIndex", dict(Title="Tables 3", LabelCategory="Table", LabelDisplayType=6)))):
511        attempt("%s%d" % (service, n), add, "%s%d" % (service, n), service, props,
512                {1: toks_alpha[:3]})
513
514    for n, props in enumerate((
515            dict(Title="Objects", CreateFromOtherEmbeddedObjects=True, CreateFromStarCalc=True, CreateFromStarChart=True,
516                 CreateFromStarDraw=True, CreateFromStarMath=True, CreateFromChapter=True, IsRelativeTabstops=False),
517            dict(Title="Objects 2", CreateFromOtherEmbeddedObjects=False, CreateFromStarCalc=False, CreateFromStarChart=False,
518                 CreateFromStarDraw=False, CreateFromStarMath=False))):
519        attempt("objidx%d" % n, add, "objidx%d" % n, "ObjectIndex", props, {1: toks_alpha[:3]})
520
521    for n, props in enumerate((
522            dict(Title="User", UserIndexName="MyIndex", CreateFromEmbeddedObjects=True, CreateFromGraphicObjects=True,
523                 CreateFromMarks=True, CreateFromTables=True, CreateFromTextFrames=True, UseLevelFromSource=True,
524                 CreateFromLevelParagraphStyles=True, CreateFromChapter=True, IsRelativeTabstops=False,
525                 ParaStyleLevel1="Heading 1"),
526            dict(Title="User 2", UserIndexName="Other", CreateFromEmbeddedObjects=False, CreateFromGraphicObjects=False,
527                 CreateFromMarks=False, CreateFromTables=False, CreateFromTextFrames=False, UseLevelFromSource=False,
528                 CreateFromLevelParagraphStyles=False))):
529        attempt("userindex%d" % n, add, "userindex%d" % n, "UserIndex", props, {1: toks_toc[:5], 2: toks_toc[:3]}, {0: ("Heading 5",), 1: ("Heading 6", "Heading 7")})
530
531    save(doc, "indexes.odt")
532    doc.close(True)
533
534
535
536def doc_objects():
537    doc = new()
538    w = W(doc)
539    w.s("objects ")
540    for name, clsid in (("math", "078B7ABA-54FC-457F-8551-6147e776a997"), ("calc", "47BBB4CB-CE4C-4E80-A591-42D9AE74950F"),
541                        ("chart", "12DCAE26-281F-416F-a234-c3086127382e"), ("draw", "8BC6B165-B1B2-4EDD-aa47-dae2ee689dd6"),
542                        ("impress", "9176E48A-637A-4D1F-803B-99D9BFAC1047")):
543        try:
544            o = doc.createInstance("com.sun.star.text.TextEmbeddedObject")
545            o.CLSID = clsid
546            o.Name = "obj_" + name
547            w.put(o)
548            w.para()
549        except Exception as e:
550            failed.append("embed " + name)
551            print("FAIL embed", name, repr(e)[:100])
552    for n, props in enumerate((
553            dict(Title="Objects", CreateFromOtherEmbeddedObjects=True, CreateFromStarCalc=True, CreateFromStarChart=True,
554                 CreateFromStarDraw=True, CreateFromStarMath=True, CreateFromChapter=True, IsRelativeTabstops=False),
555            dict(Title="Objects 2", CreateFromOtherEmbeddedObjects=False, CreateFromStarCalc=False, CreateFromStarChart=False,
556                 CreateFromStarDraw=False, CreateFromStarMath=False))):
557        idx = w.mk("com.sun.star.text.ObjectIndex", **props)
558        w.put(idx)
559        w.cur.gotoEnd(False)
560        idx.update()
561    doc.IndexAutoMarkFileURL = "file:///tmp/automark.sdi"
562    save(doc, "objects.odt")
563    doc.close(True)
564
565
566BIB_NAMES = ["Identifier", "BibiliographicType", "Address", "Annote", "Author", "Booktitle", "Chapter", "Edition", "Editor",
567             "Howpublished", "Institution", "Journal", "Month", "Note", "Number", "Organizations", "Pages", "Publisher", "School",
568             "Series", "Title", "Volume", "Year", "URL", "Custom1", "Custom2", "Custom3", "Custom4", "Custom5", "ISBN", "ReportType"]
569
570
571def doc_bibliography():
572    doc = new()
573    w = W(doc)
574    w.s("Citations: ")
575    for t in range(22):
576        fields = [pv(n, "%s-%d" % (n, t)) for n in BIB_NAMES if n != "BibiliographicType"]
577        fields.append(pv("BibiliographicType", t))
578        f = w.mk("com.sun.star.text.TextField.Bibliography")
579        f.Fields = tuple(fields)
580        w.put(f)
581        w.s(" ")
582    w.para()
583    f = w.mk("com.sun.star.text.TextField.Bibliography")
584    f.Fields = (pv("Identifier", "only-id"), pv("BibiliographicType", 1))
585    w.put(f)
586    w.para()
587    master = doc.TextFieldMasters.getByName("com.sun.star.text.FieldMaster.Bibliography")
588    master.BracketBefore = "("
589    master.BracketAfter = ")"
590    master.IsNumberEntries = True
591    master.IsSortByPosition = False
592    master.SortAlgorithm = "alphanumeric"
593    master.Locale = uno.createUnoStruct("com.sun.star.lang.Locale", "en", "US", "")
594    master.SortKeys = (tuple([pv("SortKey", 4), pv("IsSortAscending", True)]), tuple([pv("SortKey", 20), pv("IsSortAscending", False)]),
595                       tuple([pv("SortKey", 22), pv("IsSortAscending", True)]))
596    idx = w.mk("com.sun.star.text.Bibliography", Title="Bibliography", IsProtected=True, Name="Bib index")
597    lf = idx.LevelFormat
598    for lvl in range(1, 23):
599        toks = [tpl(TokenType="TokenBibliographyDataField", BibliographyDataField=(lvl - 1 + k) % 31, CharacterStyleName="Emphasis")
600                for k in range(3)] + [tpl(TokenType="TokenText", Text=" | ")]
601        uno.invoke(lf, "replaceByIndex", (lvl, uno.Any("[][]com.sun.star.beans.PropertyValue", tuple(toks))))
602    w.put(idx)
603    w.cur.gotoEnd(False)
604    idx.update()
605    idx2 = w.mk("com.sun.star.text.Bibliography", Title="Bibliography 2")
606    lf = idx2.LevelFormat
607    toks = [tpl(TokenType="TokenBibliographyDataField", BibliographyDataField=k) for k in range(31)]
608    uno.invoke(lf, "replaceByIndex", (1, uno.Any("[][]com.sun.star.beans.PropertyValue", tuple(toks))))
609    w.put(idx2)
610    w.cur.gotoEnd(False)
611    idx2.update()
612    save(doc, "bibliography.odt")
613    doc.close(True)
614
615
616
617def seqmaster(doc, name):
618    try:
619        return doc.TextFieldMasters.getByName("com.sun.star.text.FieldMaster.SetExpression." + name)
620    except Exception:
621        m = doc.createInstance("com.sun.star.text.FieldMaster.SetExpression")
622        m.Name = name
623        m.SubType = 1
624        return m
625
626
627def getref(w, source, part, name, seq=None, label=None):
628    f = w.mk("com.sun.star.text.TextField.GetReference", ReferenceFieldSource=source, ReferenceFieldPart=part, SourceName=name)
629    if seq is not None:
630        f.SequenceNumber = seq
631    w.put(f)
632    w.s(" ")
633    return f
634
635
636def doc_refs_notes():
637    doc = new()
638    w = W(doc)
639    fs = doc.FootnoteSettings
640    fs.FootnoteCounting = 1
641    fs.NumberingType = 9
642    fs.StartAt = 2
643    fs.Prefix = "["
644    fs.Suffix = "]"
645    fs.PositionEndOfDoc = True
646    fs.BeginNotice = "continued from previous page"
647    fs.EndNotice = "continued on next page"
648    es = doc.EndnoteSettings
649    es.NumberingType = 10
650    es.StartAt = 3
651    es.Prefix = "<"
652    es.Suffix = ">"
653    for st, nm in ((fs, "Footnote"), (es, "Endnote")):
654        try:
655            st.ParaStyleName = nm
656            st.CharStyleName = "Footnote Characters" if nm == "Footnote" else "Endnote Characters"
657            st.AnchorCharStyleName = "Footnote Anchor" if nm == "Footnote" else "Endnote Anchor"
658            st.PageStyleName = "Footnote" if nm == "Footnote" else "Endnote"
659        except Exception as e:
660            print("notes style", nm, repr(e)[:100])
661    w.s("Heading text with a note")
662    for kind in ("Footnote", "Endnote", "Footnote", "Endnote"):
663        n = w.mk("com.sun.star.text." + kind)
664        w.put(n)
665        n.String = "note text " + kind
666        if kind == "Footnote" and doc.Footnotes.Count == 2:
667            n.Label = "*"
668    w.s(" ")
669    w.para()
670    w.s("bookmark target text")
671    w.cur.goLeft(6, True)
672    bm = w.mk("com.sun.star.text.Bookmark", Name="bm1")
673    w.text.insertTextContent(w.cur, bm, True)
674    w.cur.gotoEnd(False)
675    bm2 = w.mk("com.sun.star.text.Bookmark", Name="bm2")
676    w.put(bm2)
677    w.s(" ")
678    w.para("reference mark ")
679    w.s("ranged")
680    w.cur.goLeft(6, True)
681    rm = w.mk("com.sun.star.text.ReferenceMark", Name="rm1")
682    w.text.insertTextContent(w.cur, rm, True)
683    w.cur.gotoEnd(False)
684    rm2 = w.mk("com.sun.star.text.ReferenceMark", Name="rm2")
685    w.put(rm2)
686    w.s(" ")
687    w.para()
688    for part in range(0, 11):
689        for src, name in ((2, "bm1"), (2, "bm2"), (0, "rm1"), (0, "rm2")):
690            attempt("getref %d %d %s" % (src, part, name), getref, w, src, part, name)
691    w.para()
692    for part in (0, 1, 2, 3, 5, 6, 7, 8, 9, 10):
693        for cat, num in (("Illustration", 0), ("Table", 1)):
694            attempt("seqref", getref, w, 1, part, cat, num)
695    w.para("Illustration ")
696    m = seqmaster(doc, "Illustration")
697    f = w.mk("com.sun.star.text.TextField.SetExpression")
698    f.attachTextFieldMaster(m)
699    f.SubType = 1
700    f.NumberingType = 4
701    f.Content = "Illustration+1"
702    w.put(f)
703    w.s(": a caption")
704    w.para("Table ")
705    m2 = seqmaster(doc, "Table")
706    f = w.mk("com.sun.star.text.TextField.SetExpression")
707    f.attachTextFieldMaster(m2)
708    f.SubType = 1
709    f.NumberingType = 4
710    f.Content = "Table+1"
711    w.put(f)
712    w.s(": a table caption")
713    w.para()
714    ids = [doc.Footnotes.getByIndex(i).ReferenceId for i in range(doc.Footnotes.Count)]
715    eids = [doc.Endnotes.getByIndex(i).ReferenceId for i in range(doc.Endnotes.Count)]
716    for src, lst in ((3, ids), (4, eids)):
717        for rid in lst:
718            for part in (0, 1, 2, 3, 8, 9, 10):
719                attempt("noteref", getref, w, src, part, "", rid)
720    w.para()
721    doc.TextFields.refresh()
722    save(doc, "refs-notes.odt")
723    doc.close(True)
724
725
726def doc_notes_variants():
727    doc = new()
728    w = W(doc)
729    fs = doc.FootnoteSettings
730    for cnt, eod in ((0, False), (2, False)):
731        fs.FootnoteCounting = cnt
732        fs.PositionEndOfDoc = eod
733    es = doc.EndnoteSettings
734    es.NumberingType = 4
735    w.s("one")
736    n = w.mk("com.sun.star.text.Footnote")
737    w.put(n)
738    n.String = "fn"
739    w.s(" two")
740    n = w.mk("com.sun.star.text.Endnote")
741    w.put(n)
742    n.String = "en"
743    save(doc, "notes-variants.odt")
744    doc.close(True)
745
746
747def doc_annotations():
748    doc = new()
749    w = W(doc)
750    w.s("plain text with a ranged annotation here and a point annotation")
751    w.cur.gotoStart(False)
752    w.cur.goRight(5, False)
753    w.cur.goRight(4, True)
754    a = w.mk("com.sun.star.text.TextField.Annotation", Author="Ann Author", Content="ranged comment", Initials="AA",
755             DateTimeValue=dt(2024, 7, 8, 9, 10), Name="ann1")
756    w.text.insertTextContent(w.cur, a, True)
757    w.cur.gotoEnd(False)
758    a2 = w.mk("com.sun.star.text.TextField.Annotation", Author="Bob", Content="point comment", Initials="B",
759              DateTimeValue=dt(2024, 7, 9, 9, 10))
760    w.put(a2)
761    w.s(" after")
762    w.para("second para ranged")
763    w.cur.goLeft(6, True)
764    a3 = w.mk("com.sun.star.text.TextField.Annotation", Author="Cy", Content="third", Name="ann3")
765    w.text.insertTextContent(w.cur, a3, True)
766    w.cur.gotoEnd(False)
767    save(doc, "annotations.odt")
768    doc.close(True)
769
770
771def doc_hyperlinks():
772    doc = new()
773    w = W(doc)
774    w.s("link one ")
775    w.cur.goLeft(9, True)
776    w.cur.HyperLinkURL = "http://example.org/one"
777    w.cur.HyperLinkName = "one name"
778    w.cur.HyperLinkTarget = "_blank"
779    w.cur.UnvisitedCharStyleName = "Internet link"
780    w.cur.VisitedCharStyleName = "Visited Internet Link"
781    w.cur.gotoEnd(False)
782    w.cur.setPropertyToDefault("HyperLinkURL")
783    w.s("link two ")
784    w.cur.goLeft(9, True)
785    w.cur.HyperLinkURL = "http://example.org/two"
786    w.cur.HyperLinkTarget = "_self"
787    w.cur.gotoEnd(False)
788    w.cur.setPropertyToDefault("HyperLinkURL")
789    w.s("link three ")
790    w.cur.goLeft(11, True)
791    w.cur.HyperLinkURL = "#bookmark"
792    w.cur.HyperLinkTarget = "_top"
793    w.cur.gotoEnd(False)
794    w.cur.setPropertyToDefault("HyperLinkURL")
795    w.s("link four ")
796    w.cur.goLeft(10, True)
797    w.cur.HyperLinkURL = "http://example.org/four"
798    w.cur.HyperLinkTarget = "_parent"
799    w.cur.gotoEnd(False)
800    w.cur.setPropertyToDefault("HyperLinkURL")
801    w.s("link five ")
802    w.cur.goLeft(10, True)
803    w.cur.HyperLinkURL = "http://example.org/five"
804    w.cur.HyperLinkTarget = "named_frame"
805    w.cur.gotoEnd(False)
806    w.cur.setPropertyToDefault("HyperLinkURL")
807    w.para("ruby ")
808    w.s("base")
809    w.cur.goLeft(4, True)
810    w.cur.RubyText = "ruby"
811    w.cur.RubyAdjust = 1
812    w.cur.RubyCharStyleName = "Emphasis"
813    w.cur.RubyIsAbove = False
814    w.cur.gotoEnd(False)
815    w.s(" more")
816    w.cur.goLeft(4, True)
817    w.cur.RubyText = "r2"
818    w.cur.RubyAdjust = 3
819    w.cur.RubyIsAbove = True
820    w.cur.gotoEnd(False)
821    save(doc, "hyperlinks-ruby.odt")
822    doc.close(True)
823
824
825
826def png_file():
827    import struct, zlib, tempfile
828    raw = b"".join(b"\x00" + b"\xff\x00\x00\xff" * 4 for _ in range(4))
829    def chunk(t, d):
830        c = struct.pack(">I", len(d)) + t + d
831        return c + struct.pack(">I", zlib.crc32(t + d) & 0xffffffff)
832    data = b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", 4, 4, 8, 6, 0, 0, 0)) + chunk(b"IDAT", zlib.compress(raw)) + chunk(b"IEND", b"")
833    p = os.path.join(tempfile.gettempdir(), "t12_writer_bullet.png")
834    open(p, "wb").write(data)
835    return uno.systemPathToFileUrl(p)
836
837
838def setlevel(rules, i, **props):
839    uno.invoke(rules, "replaceByIndex", (i, uno.Any("[]com.sun.star.beans.PropertyValue", tuple(pv(k, v) for k, v in props.items()))))
840
841
842def doc_lists():
843    doc = new()
844    w = W(doc)
845    styles = doc.StyleFamilies.getByName("NumberingStyles")
846    st = doc.createInstance("com.sun.star.style.NumberingStyle")
847    styles.insertByName("T12 List", st)
848    rules = st.NumberingRules
849    fd = uno.createUnoStruct("com.sun.star.awt.FontDescriptor")
850    fd.Name = "OpenSymbol"
851    img = png_file()
852    cfgs = [
853        dict(NumberingType=4, Prefix="(", Suffix=")", StartWith=3, ParentNumbering=1, Adjust=1, LeftMargin=500, FirstLineOffset=-300, SymbolTextDistance=100),
854        dict(NumberingType=0, Prefix="", Suffix=".", StartWith=1, ParentNumbering=2, Adjust=2, CharStyleName="Emphasis"),
855        dict(NumberingType=9, Suffix=":"),
856        dict(NumberingType=6, BulletChar="*", BulletFont=fd, BulletRelSize=60, Prefix="<", Suffix=">", BulletColor=0x336699),
857        dict(NumberingType=8, GraphicURL=img, GraphicSize=uno.createUnoStruct("com.sun.star.awt.Size", 400, 300), VertOrient=1),
858        dict(NumberingType=8, GraphicURL=img, GraphicSize=uno.createUnoStruct("com.sun.star.awt.Size", 400, 300), VertOrient=2),
859        dict(NumberingType=8, GraphicURL=img, GraphicSize=uno.createUnoStruct("com.sun.star.awt.Size", 400, 300), VertOrient=3),
860        dict(NumberingType=2, PositionAndSpaceMode=1, LabelFollowedBy=1, ListtabStopPosition=2000, FirstLineIndent=-500, IndentAt=1500),
861        dict(NumberingType=3, PositionAndSpaceMode=1, LabelFollowedBy=2, FirstLineIndent=-500, IndentAt=1500),
862        dict(NumberingType=10, PositionAndSpaceMode=1, LabelFollowedBy=0, ListtabStopPosition=1000, FirstLineIndent=-300, IndentAt=900),
863    ]
864    for i, c in enumerate(cfgs):
865        attempt("list level %d" % i, setlevel, rules, i, **c)
866    st.NumberingRules = rules
867    st2 = doc.createInstance("com.sun.star.style.NumberingStyle")
868    styles.insertByName("T12 List 2", st2)
869    r2 = st2.NumberingRules
870    for i in range(3):
871        attempt("list2 level %d" % i, setlevel, r2, i, NumberingType=6, BulletChar="-", BulletFont=fd)
872    st2.NumberingRules = r2
873
874    for lvl in range(10):
875        w.cur.NumberingStyleName = "T12 List"
876        w.cur.NumberingLevel = lvl
877        w.s("item level %d" % lvl)
878        w.para()
879    w.cur.NumberingStyleName = ""
880    w.cur.setPropertyToDefault("NumberingStyleName")
881    w.para("between lists")
882
883    def item(txt, style="T12 List", lvl=0, **props):
884        w.cur.NumberingStyleName = style
885        w.cur.NumberingLevel = lvl
886        for k, v in props.items():
887            setattr(w.cur, k, v)
888        w.s(txt)
889        w.para()
890
891    item("restart item", ParaIsNumberingRestart=True, NumberingStartValue=7)
892    item("normal item")
893    item("not numbered item", NumberingIsNumber=False)
894    item("sub restart", lvl=1, ParaIsNumberingRestart=True, NumberingStartValue=4)
895    item("other style item", style="T12 List 2", lvl=1)
896    item("back to first", ParaIsNumberingRestart=False)
897    w.cur.setPropertyToDefault("NumberingStyleName")
898    w.cur.setPropertyToDefault("ParaIsNumberingRestart")
899    w.cur.setPropertyToDefault("NumberingIsNumber")
900    w.para("break")
901
902    h = doc.ChapterNumberingRules
903    ocfg = [dict(NumberingType=4, Prefix="Ch ", Suffix=".", StartWith=2, ParentNumbering=1),
904            dict(NumberingType=0, Prefix="", Suffix=")", StartWith=3),
905            dict(NumberingType=9, Prefix="[", Suffix="]", StartWith=1),
906            dict(NumberingType=1, StartWith=4),
907            dict(NumberingType=10), dict(NumberingType=2), dict(NumberingType=3), dict(NumberingType=4), dict(NumberingType=5)]
908    for i, c in enumerate(ocfg):
909        attempt("outline level %d" % i, setlevel, h, i, **c)
910    for lvl in (1, 2, 3, 2, 1):
911        w.cur.ParaStyleName = "Heading %d" % lvl
912        w.s("Heading level %d" % lvl)
913        w.para()
914    w.cur.ParaStyleName = "Heading 1"
915    w.cur.ParaIsNumberingRestart = True
916    w.cur.NumberingStartValue = 5
917    w.s("Heading restart")
918    w.para()
919    w.cur.ParaIsNumberingRestart = False
920    w.cur.NumberingIsNumber = False
921    w.s("Heading not numbered")
922    w.para()
923    w.cur.NumberingIsNumber = True
924    w.cur.ParaStyleName = "Standard"
925    w.s("end")
926    save(doc, "lists-outline.odt")
927    doc.close(True)
928
929
930def doc_linenumbers():
931    for pos in (0, 1, 2):
932        doc = new()
933        w = W(doc)
934        lp = doc.LineNumberingProperties
935        lp.IsOn = True
936        lp.NumberPosition = pos
937        lp.Interval = 2
938        lp.SeparatorText = ""
939        w.s("numbered line")
940        save(doc, "linenumbers-%d.odt" % pos)
941        doc.close(True)
942
943
944def doc_structure():
945    doc = new()
946    w = W(doc)
947    lp = doc.LineNumberingProperties
948    lp.IsOn = False
949    lp.CountEmptyLines = False
950    lp.CountLinesInFrames = True
951    lp.RestartAtEachPage = True
952    lp.Distance = 700
953    lp.NumberingType = 9
954    lp.NumberPosition = 3
955    lp.Interval = 3
956    lp.SeparatorText = "|"
957    lp.SeparatorInterval = 4
958    lp.CharStyleName = "Emphasis"
959    for i in range(6):
960        w.para("line number test paragraph %d" % i)
961    w.para()
962    for n, props in enumerate((
963            dict(Condition="1==1", IsVisible=False, IsProtected=True, ProtectionKey=b"\x01\x02\x03\x04\x05"),
964            dict(Condition="1==2", IsVisible=True),
965            dict(Condition="", IsVisible=False, IsProtected=False),
966            dict(FileLink=uno.createUnoStruct("com.sun.star.text.SectionFileLink", "file:///tmp/t12_missing.odt", "writer8"),
967                 LinkRegion="region1"),
968            dict(FileLink=uno.createUnoStruct("com.sun.star.text.SectionFileLink", "file:///tmp/t12_missing2.odt", ""), LinkRegion=""),
969            dict(DDECommandType="soffice", DDECommandFile="file.ods", DDECommandElement="Sheet1.A1", IsAutomaticUpdate=True),
970            dict(DDECommandType="soffice", DDECommandFile="file2.ods", DDECommandElement="Sheet1.B1", IsAutomaticUpdate=False))):
971        w.para("before section %d" % n)
972        w.s("")
973        sec = w.mk("com.sun.star.text.TextSection", Name="sec%d" % n)
974        try:
975            for k, v in props.items():
976                if k == "ProtectionKey":
977                    v = uno.ByteSequence(v)
978                setattr(sec, k, v)
979        except Exception as e:
980            print("FAIL section prop", n, k, repr(e)[:100])
981            failed.append("section %d %s" % (n, k))
982        try:
983            w.cur.gotoEnd(False)
984            w.text.insertTextContent(w.cur, sec, False)
985            w.cur.gotoEnd(False)
986            w.s("section body %d" % n)
987        except Exception as e:
988            print("FAIL section", n, repr(e)[:100])
989            failed.append("section %d" % n)
990        w.cur.gotoEnd(False)
991        w.para()
992    sec = w.mk("com.sun.star.text.TextSection", Name="cols")
993    cols = doc.createInstance("com.sun.star.text.TextColumns")
994    cols.setColumnCount(2)
995    sec.TextColumns = cols
996    w.text.insertTextContent(w.cur, sec, False)
997    w.cur.gotoEnd(False)
998    w.s("two column section")
999    w.para()
1000    w.s("tail")
1001    save(doc, "structure.odt")
1002    doc.close(True)
1003
1004
1005
1006def enum(t, v):
1007    return uno.Enum("com.sun.star.form." + t, v)
1008
1009
1010class Forms:
1011    def __init__(self, doc):
1012        self.doc = doc
1013        self.page = doc.DrawPage
1014        self.forms = self.page.Forms
1015        self.n = 0
1016        self.y = 0
1017
1018    def form(self, name, **props):
1019        f = self.doc.createInstance("com.sun.star.form.component.Form")
1020        self.forms.insertByName(name, f)
1021        for k, v in props.items():
1022            try:
1023                setattr(f, k, v)
1024            except Exception as e:
1025                print("FAIL form prop", name, k, repr(e)[:80])
1026                failed.append("form prop " + k)
1027        return f
1028
1029    def control(self, form, service, name, **props):
1030        try:
1031            m = self.doc.createInstance("com.sun.star.form.component." + service)
1032        except Exception as e:
1033            print("FAIL control", service, repr(e)[:100])
1034            failed.append("control " + service)
1035            return None
1036        m.Name = name
1037        info = m.getPropertySetInfo()
1038        if info.hasPropertyByName("Tag"):
1039            m.Tag = "tag " + name
1040        for k, v in props.items():
1041            try:
1042                if k == "LabelControl":
1043                    continue
1044                if not info.hasPropertyByName(k):
1045                    print("no property", service, k)
1046                    continue
1047                setattr(m, k, v)
1048            except Exception as e:
1049                print("FAIL prop", service, k, repr(e)[:80])
1050                failed.append("%s.%s" % (service, k))
1051        form.insertByName(name, m)
1052        if "LabelControl" in props:
1053            try:
1054                m.LabelControl = props["LabelControl"]
1055            except Exception as e:
1056                print("FAIL LabelControl", repr(e)[:80])
1057        shape = self.doc.createInstance("com.sun.star.drawing.ControlShape")
1058        shape.setSize(uno.createUnoStruct("com.sun.star.awt.Size", 5000, 800))
1059        shape.setPosition(uno.createUnoStruct("com.sun.star.awt.Point", 500, 500 + self.y))
1060        self.y += 1000
1061        if service == "HiddenControl":
1062            return m
1063        try:
1064            shape.Control = m
1065            self.page.add(shape)
1066        except Exception as e:
1067            print("FAIL shape", service, repr(e)[:100])
1068            failed.append("shape " + service)
1069        return m
1070
1071
1072def doc_forms():
1073    doc = new()
1074    w = W(doc)
1075    w.s("form controls")
1076    doc.AutomaticControlFocus = True
1077    doc.ApplyFormDesignMode = False
1078    F = Forms(doc)
1079    f1 = F.form("Form1", DataSourceName="Bibliography", Command="biblio", CommandType=0, AllowDeletes=False, AllowInserts=False,
1080                AllowUpdates=False, ApplyFilter=True, EscapeProcessing=False, IgnoreResult=True, Filter="Year>1990", Order="Title",
1081                SubmitEncoding=enum("FormSubmitEncoding", "MULTIPART"), SubmitMethod=enum("FormSubmitMethod", "POST"),
1082                NavigationBarMode=enum("NavigationBarMode", "PARENT"), Cycle=enum("TabulatorCycle", "PAGE"),
1083                TargetFrame="_blank", TargetURL="http://example.org/submit")
1084    f2 = F.form("Form2", DataSourceName="file:///tmp/t12_missing.odb", Command="SELECT * FROM x", CommandType=2,
1085                SubmitEncoding=enum("FormSubmitEncoding", "TEXT"), SubmitMethod=enum("FormSubmitMethod", "GET"),
1086                NavigationBarMode=enum("NavigationBarMode", "NONE"), Cycle=enum("TabulatorCycle", "CURRENT"),
1087                MasterFields=("a", "b"), DetailFields=("c", "d"))
1088    f3 = F.form("Form3", Command="q1", CommandType=1, DataSourceName="OtherSource", NavigationBarMode=enum("NavigationBarMode", "CURRENT"),
1089                Cycle=enum("TabulatorCycle", "RECORDS"), AllowDeletes=True, ApplyFilter=False)
1090    f4 = F.form("Form4")
1091    C = F.control
1092    for i, (bt, extra) in enumerate((("PUSH", {}), ("SUBMIT", {}), ("RESET", {}), ("URL", dict(TargetURL="http://example.org/b", TargetFrame="_top")))):
1093        C(f1, "CommandButton", "btn%d" % i, Label="Button %d" % i, ButtonType=enum("FormButtonType", bt), DefaultButton=(i == 0),
1094          Toggle=(i == 1), FocusOnClick=(i != 2), ImagePosition=i, ImageAlign=i % 4, Tabstop=(i % 2 == 0), TabIndex=i + 1,
1095          Enabled=(i != 3), Printable=(i != 1), HelpText="tip %d" % i, RepeatDelay=100 * i, Repeat=(i == 1), State=i % 2, **extra)
1096    for i in range(13):
1097        C(f1, "CheckBox", "chkpos%d" % i, Label="Pos %d" % i, ImagePosition=i, ImageURL=png_file())
1098        C(f1, "RadioButton", "radpos%d" % i, Label="Pos %d" % i, ImagePosition=i, ImageURL=png_file())
1099        C(f1, "CommandButton", "btnpos%d" % i, Label="Pos %d" % i, ImagePosition=i, ImageAlign=i % 3, ImageURL=png_file())
1100    for i in range(4):
1101        C(f1, "ImageButton", "imgbtn%d" % i, ButtonType=enum("FormButtonType", ("PUSH", "SUBMIT", "RESET", "URL")[i]),
1102          ImageURL=png_file(), Tabstop=(i % 2 == 0), Enabled=(i != 1), Printable=(i != 2), TabIndex=10 + i, HelpText="img tip",
1103          TargetURL="http://example.org/i" if i == 3 else "", TargetFrame="_blank" if i == 3 else "", ScaleImage=(i % 2 == 0))
1104    for i, st in enumerate((0, 1, 2)):
1105        C(f1, "CheckBox", "chk%d" % i, Label="Check %d" % i, State=st, DefaultState=st, TriState=(i == 2), VisualEffect=i % 3,
1106          ImagePosition=i + 1 if i < 2 else 3, ImageAlign=i, RefValue="ref%d" % i, Tabstop=(i == 0), Enabled=(i != 1), Printable=(i != 2),
1107          TabIndex=20 + i, HelpText="chk tip", DataField="Author", InputRequired=False)
1108    for i in range(4):
1109        C(f1, "RadioButton", "rad%d" % i, Label="Radio %d" % i, State=(i % 2), DefaultState=(i % 2 == 0), RefValue="r%d" % i,
1110          VisualEffect=i % 3, ImagePosition=i + 1 if i < 3 else 0, ImageAlign=i % 3, Tabstop=(i == 1), Enabled=(i != 2),
1111          Printable=(i != 3), TabIndex=30 + i, HelpText="rad tip")
1112    C(f1, "GroupBox", "grp", Label="Group", Enabled=False, Printable=False, HelpText="grp tip")
1113    fx = C(f1, "FixedText", "fixed", Label="Fixed label", MultiLine=True, Enabled=False, Printable=False, HelpText="fx tip")
1114    C(f1, "FixedText", "fixed2", Label="Fixed label 2", MultiLine=False)
1115    for i in range(3):
1116        C(f1, "TextField", "text%d" % i, Text="abc%d" % i, DefaultText="def%d" % i, MaxTextLen=10 * (i + 1), ReadOnly=(i == 1),
1117          Enabled=(i != 2), Printable=(i != 0), Tabstop=(i % 2 == 0), TabIndex=40 + i, HelpText="txt tip", DataField="Title",
1118          ConvertEmptyToNull=(i == 0), InputRequired=(i != 1), **({"LabelControl": fx} if i == 0 else {}))
1119    C(f1, "TextField", "textarea", Text="line1\nline2", MultiLine=True, ReadOnly=True, MaxTextLen=50, DataField="Note",
1120      Enabled=False, Printable=False, Tabstop=True, ConvertEmptyToNull=True)
1121    C(f1, "TextField", "password", Text="secret", EchoChar=ord("*"), MaxTextLen=8, Tabstop=True)
1122    C(f1, "TextField", "richtext", RichText=True, MultiLine=True)
1123    for i in range(2):
1124        C(f1, "FormattedField", "fmt%d" % i, EffectiveValue=12.5, EffectiveDefault=1.5, EffectiveMin=0.0, EffectiveMax=100.0,
1125          TreatAsNumber=(i == 0), Spin=(i == 0), RepeatDelay=50, ReadOnly=(i == 1), MaxTextLen=12, Enabled=(i == 0), Printable=(i == 0),
1126          Tabstop=True, TabIndex=50 + i, HelpText="fmt tip", DataField="Number", ConvertEmptyToNull=(i == 1), InputRequired=(i == 0),
1127          StrictFormat=(i == 0))
1128    for i in range(2):
1129        C(f1, "NumericField", "num%d" % i, Value=3.0, DefaultValue=2.0, ValueMin=0.0, ValueMax=9.0, ValueStep=0.5, DecimalAccuracy=2,
1130          ShowThousandsSeparator=(i == 0), Spin=(i == 0), StrictFormat=(i == 1), ReadOnly=(i == 1), RepeatDelay=70, Enabled=(i == 0),
1131          Printable=(i == 0), Tabstop=True, TabIndex=55 + i, HelpText="num tip", DataField="N", ConvertEmptyToNull=(i == 1),
1132          InputRequired=(i == 0))
1133    C(f1, "CurrencyField", "cur", Value=3.0, DefaultValue=2.0, ValueMin=0.0, ValueMax=9.0, ValueStep=0.5, DecimalAccuracy=2,
1134      CurrencySymbol="EUR", PrependCurrencySymbol=True, Spin=True, ReadOnly=False)
1135    C(f1, "PatternField", "pat", Text="12-34", DefaultText="00-00", EditMask="NN-NN", LiteralMask="__-__", StrictFormat=True,
1136      ReadOnly=True, MaxTextLen=5, ConvertEmptyToNull=True, DataField="Pat", InputRequired=False)
1137    for i in range(2):
1138        C(f1, "DateField", "date%d" % i, Date=20240315, DefaultDate=20240101, DateMin=20000101, DateMax=20301231,
1139          DateFormat=i * 3, Dropdown=(i == 0), Spin=(i == 1), StrictFormat=(i == 0), ReadOnly=(i == 1), RepeatDelay=20, Enabled=(i == 0),
1140          Printable=(i == 0), Tabstop=(i == 1), TabIndex=60 + i, HelpText="date tip", DataField="D", ConvertEmptyToNull=(i == 1),
1141          InputRequired=(i == 0))
1142    for i in range(2):
1143        C(f1, "TimeField", "time%d" % i, Time=12300500, DefaultTime=8000000, TimeMin=0, TimeMax=23595900,
1144          TimeFormat=i * 2, Spin=(i == 0), StrictFormat=(i == 1), ReadOnly=(i == 1), RepeatDelay=30, Enabled=(i == 0), Printable=(i == 0),
1145          Tabstop=True, TabIndex=65 + i, HelpText="time tip", DataField="T", ConvertEmptyToNull=(i == 0), InputRequired=(i == 1))
1146    for i in range(2):
1147        C(f1, "ListBox", "list%d" % i, StringItemList=("one", "two", "three"),
1148          SelectedItems=uno.Any("[]short", (1,)) if i == 0 else uno.Any("[]short", (0, 2)),
1149          DefaultSelection=uno.Any("[]short", (2,)), Dropdown=(i == 0), MultiSelection=(i == 1), LineCount=4 + i,
1150          ListSourceType=enum("ListSourceType", "VALUELIST"), BoundColumn=i, Enabled=(i == 0), Printable=(i == 0), Tabstop=(i == 1),
1151          TabIndex=70 + i, HelpText="list tip", DataField="L", InputRequired=(i == 0))
1152    for i, lst in enumerate(("TABLE", "QUERY", "SQL", "SQLPASSTHROUGH", "TABLEFIELDS")):
1153        C(f1, "ListBox", "listsrc%d" % i, ListSourceType=enum("ListSourceType", lst), ListSource=("biblio",), BoundColumn=1, DataField="X",
1154          Dropdown=(i % 2 == 0))
1155    for i, lst in enumerate(("VALUELIST", "TABLE", "QUERY", "SQL", "SQLPASSTHROUGH", "TABLEFIELDS")):
1156        C(f1, "ComboBox", "combo%d" % i, StringItemList=("alpha", "beta"), Text="alp", DefaultText="al", Dropdown=(i % 2 == 0),
1157          Autocomplete=(i % 2 == 1), LineCount=3 + i, MaxTextLen=20, ReadOnly=(i == 1), ListSourceType=enum("ListSourceType", lst),
1158          ListSource="biblio" if lst != "VALUELIST" else "", ConvertEmptyToNull=(i == 0), DataField="C", InputRequired=(i == 0),
1159          Enabled=(i != 2), Printable=(i != 3), Tabstop=(i == 4), TabIndex=80 + i, HelpText="combo tip")
1160    C(f1, "FileControl", "file", Text="/tmp/x.txt", DefaultText="/tmp/y.txt", Enabled=False, Printable=False, Tabstop=True, TabIndex=90,
1161      HelpText="file tip")
1162    C(f1, "DatabaseImageControl", "imgctl", ImageURL=png_file(), ReadOnly=True, Enabled=False, Printable=False, HelpText="imgctl tip", DataField="Pic",
1163      InputRequired=False, ScaleImage=True)
1164    C(f1, "HiddenControl", "hidden", HiddenValue="hv")
1165    C(f1, "ScrollBar", "scroll", ScrollValue=5, ScrollValueMin=0, ScrollValueMax=50, LineIncrement=2, BlockIncrement=10, Orientation=1,
1166      RepeatDelay=40, Enabled=False, Printable=False, HelpText="scr tip")
1167    C(f1, "ScrollBar", "scroll2", ScrollValue=1, ScrollValueMin=0, ScrollValueMax=10, Orientation=0)
1168    C(f1, "SpinButton", "spin", SpinValue=3, SpinValueMin=0, SpinValueMax=20, SpinIncrement=2, Orientation=1, RepeatDelay=60,
1169      Enabled=False, Printable=False, HelpText="spin tip")
1170    C(f1, "NavigationToolBar", "navbar")
1171    g = C(f1, "GridControl", "grid", Enabled=False, Printable=False, Tabstop=True, TabIndex=99, HelpText="grid tip")
1172    for i, ct in enumerate(("TextField", "CheckBox", "ComboBox", "ListBox", "DateField", "TimeField", "NumericField", "CurrencyField",
1173                            "PatternField", "FormattedField")):
1174        try:
1175            col = g.createColumn(ct)
1176            col.Label = "Col %d" % i
1177            col.Width = 1000 + i
1178            col.Align = i % 3
1179            col.Hidden = (i == 3)
1180            col.HelpText = "col tip"
1181            col.DataField = "F%d" % i
1182            g.insertByName("col%d" % i, col)
1183        except Exception as e:
1184            print("FAIL column", ct, repr(e)[:100])
1185            failed.append("column " + ct)
1186    m = C(f4, "TextField", "dyn")
1187    T = lambda: uno.createUnoStruct("com.sun.star.util.Time", 0, 3, 2, 1)
1188    dyn = [("dyn_string", "text"), ("dyn_bool", True), ("dyn_double", 2.5), ("dyn_long", 42), ("dyn_date", date(2024, 5, 6)),
1189           ("dyn_time", T()), ("dyn_datetime", dt()),
1190           ("dyn_seqs", uno.Any("[]string", ("a", "b"))), ("dyn_seqb", uno.Any("[]boolean", (True, False))),
1191           ("dyn_seqd", uno.Any("[]double", (1.5, 2.5))), ("dyn_seql", uno.Any("[]long", (1, 2))),
1192           ("dyn_seqt", uno.Any("[]com.sun.star.util.Time", (T(),))), ("dyn_seqdate", uno.Any("[]com.sun.star.util.Date", (date(2024, 5, 6),))),
1193           ("dyn_seqdt", uno.Any("[]com.sun.star.util.DateTime", (dt(),))),
1194           ]
1195    for nm, val in dyn:
1196        try:
1197            uno.invoke(m, "addProperty", (nm, 128, val))
1198        except Exception as e:
1199            print("FAIL dyn prop", nm, repr(e)[:100])
1200            failed.append("dyn " + nm)
1201    save(doc, "forms.odt")
1202    doc.close(True)
1203
1204
1205
1206def doc_database():
1207    doc = new()
1208    w = W(doc)
1209    for n, (src, url, ctype) in enumerate((("Bibliography", "", 0), ("Bibliography", "", 1), ("Bibliography", "", 2), ("", "file:///tmp/t12_missing.odb", 0),
1210                                          ("", "file:///tmp/t12_missing.odb", 2))):
1211        m = doc.createInstance("com.sun.star.text.FieldMaster.Database")
1212        try:
1213            m.DataBaseName = src
1214            if url:
1215                m.DataBaseURL = url
1216            m.DataTableName = "biblio%d" % n
1217            m.DataColumnName = "Identifier"
1218            m.DataCommandType = ctype
1219        except Exception as e:
1220            print("FAIL master prop", n, repr(e)[:100])
1221        for fmtkind in (None, "number", "date"):
1222            for visible in (True, False):
1223                f = doc.createInstance("com.sun.star.text.TextField.Database")
1224                try:
1225                    f.attachTextFieldMaster(m)
1226                    f.Content = "<Identifier>"
1227                    f.IsVisible = visible
1228                    if fmtkind:
1229                        f.DataBaseFormat = False
1230                        f.NumberFormat = stdfmt(doc, fmtkind)
1231                    w.put(f)
1232                    w.s(" ")
1233                except Exception as e:
1234                    print("FAIL dbfield", n, fmtkind, repr(e)[:100])
1235                    failed.append("dbfield")
1236        w.para()
1237        for kind, extra in (("DatabaseName", dict(IsVisible=True)), ("DatabaseName", dict(IsVisible=False)),
1238                            ("DatabaseNextSet", dict(Condition="1==1")), ("DatabaseNumberOfSet", dict(Condition="2==2", SetNumber=3)),
1239                            ("DatabaseSetNumber", dict(SetNumber=5, NumberingType=4, IsVisible=True)),
1240                            ("DatabaseSetNumber", dict(SetNumber=6, NumberingType=1, IsVisible=False))):
1241            props = dict(DataBaseName=src, DataTableName="tab%d" % n, DataCommandType=ctype)
1242            if url:
1243                props["DataBaseURL"] = url
1244            props.update(extra)
1245            w.field(kind, "%s %d" % (kind, n), **props)
1246        w.para()
1247    save(doc, "database-fields.odt")
1248    doc.close(True)
1249
1250
1251def doc_redlines():
1252    doc = new()
1253    w = W(doc)
1254    for t in ("First paragraph of original text.", "Second paragraph with a word to delete.", "Third paragraph to format.",
1255              "Fourth paragraph restyled.", "Fifth paragraph removed entirely.", "Sixth paragraph removed too.", "Seventh paragraph."):
1256        w.s(t)
1257        w.para()
1258    w.s("end")
1259    doc.RecordChanges = True
1260    paras = doc.Text.createEnumeration()
1261    ps = []
1262    while paras.hasMoreElements():
1263        ps.append(paras.nextElement())
1264
1265    def cur_in(p, skip, n):
1266        c = doc.Text.createTextCursorByRange(p.Start)
1267        c.goRight(skip, False)
1268        if n:
1269            c.goRight(n, True)
1270        return c
1271
1272    cur_in(ps[0], 6, 0).String = "inserted "
1273    c = cur_in(ps[1], 22, 4)
1274    c.String = ""
1275    c = cur_in(ps[2], 6, 9)
1276    c.CharWeight = 150
1277    c.CharPosture = 1
1278    c = cur_in(ps[3], 0, 6)
1279    ps[3].ParaStyleName = "Heading 1"
1280    c = doc.Text.createTextCursorByRange(ps[4].Start)
1281    c.gotoRange(ps[5].End, True)
1282    c.String = ""
1283    c = cur_in(ps[6], 0, 7)
1284    c.CharColor = 0xff0000
1285    t = doc.createInstance("com.sun.star.text.TextTable")
1286    t.initialize(2, 2)
1287    doc.Text.insertTextContent(doc.Text.End, t, False)
1288    doc.RecordChanges = True
1289    save(doc, "redlines.odt")
1290    doc.RecordChanges = False
1291    save(doc, "redlines-notrack.odt")
1292    doc.close(True)
1293
1294
1295
1296def doc_table_fields():
1297    doc = new()
1298    w = W(doc)
1299    t = w.mk("com.sun.star.text.TextTable")
1300    t.initialize(4, 3)
1301    w.put(t)
1302    for r in range(3):
1303        for c in range(2):
1304            t.getCellByPosition(c, r).Value = r * 2 + c + 1
1305    for n, (content, fmt, show) in enumerate((("sum <A1:A3>", "number", False), ("=<A1>+<B1>", "currency", True), ("mean <A1:B3>", None, False),
1306                                                ("=<A2>*2", "percent", False))):
1307        cell = t.getCellByPosition(2, n)
1308        f = doc.createInstance("com.sun.star.text.TextField.TableFormula")
1309        f.Content = content
1310        f.IsShowFormula = show
1311        if fmt:
1312            f.NumberFormat = stdfmt(doc, fmt)
1313        cell.Text.insertTextContent(cell.Text.createTextCursor(), f, False)
1314    t.getCellByPosition(0, 3).Formula = "=sum <A1:A3>"
1315    t.getCellByPosition(1, 3).Formula = "=<A1>+<B1>"
1316    t.getCellByPosition(1, 3).NumberFormat = stdfmt(doc, "currency")
1317    save(doc, "table-fields.odt")
1318    doc.close(True)
1319
1320
1321def doc_master():
1322    doc = new("private:factory/swriter/GlobalDocument")
1323    w = W(doc)
1324    w.s("master document body")
1325    w.para()
1326    for n in range(2):
1327        sec = w.mk("com.sun.star.text.TextSection", Name="Linked%d" % n)
1328        sec.FileLink = uno.createUnoStruct("com.sun.star.text.SectionFileLink", "file:///tmp/t12_missing_sub%d.odt" % n, "writer8")
1329        try:
1330            w.text.insertTextContent(w.cur, sec, False)
1331        except Exception as e:
1332            print("FAIL master section", n, repr(e)[:100])
1333            failed.append("master section %d" % n)
1334        w.cur.gotoEnd(False)
1335        w.para()
1336    idx = w.mk("com.sun.star.text.ContentIndex", Title="Master contents")
1337    w.put(idx)
1338    save(doc, "master-doc.odm", "writerglobal8")
1339    save(doc, "master-doc-as-text.odt", "writerglobal8_writer")
1340    doc.close(True)
1341
1342
1343def doc_settings():
1344    doc = new()
1345    w = W(doc)
1346    w.s("settings")
1347    st = doc.createInstance("com.sun.star.document.Settings")
1348    base = [("LinkUpdateMode", 0), ("FieldAutoUpdate", False), ("ChartAutoUpdate", False), ("AddParaTableSpacing", False),
1349            ("AddParaTableSpacingAtStart", False), ("AlignTabStopPosition", False), ("IsKernAsianPunctuation", True),
1350            ("CharacterCompressionType", 2), ("ApplyUserData", False), ("SaveGlobalDocumentLinks", True),
1351            ("CurrentDatabaseDataSource", "Bibliography"), ("CurrentDatabaseCommand", "biblio"), ("CurrentDatabaseCommandType", 1),
1352            ("SaveVersionOnClose", True), ("UpdateFromTemplate", False), ("PrinterIndependentLayout", 1), ("IsLabelDocument", True),
1353            ("AddFrameOffsets", True), ("AddExternalLeading", False), ("UseOldNumbering", True), ("OutlineLevelYieldsNumbering", True),
1354            ("AllowPrintJobCancel", False), ("UseFormerLineSpacing", True), ("AddParaSpacingToTableCells", False),
1355            ("UseFormerObjectPositioning", True), ("UseFormerTextWrapping", True), ("ConsiderTextWrapOnObjPos", True),
1356            ("IgnoreFirstLineIndentInNumbering", True), ("DoNotJustifyLinesWithManualBreak", True), ("DoNotResetParaAttrsForNumFont", True),
1357            ("TableRowKeep", True), ("IgnoreTabsAndBlanksForLineCalculation", True), ("LoadReadonly", True),
1358            ("DoNotCaptureDrawObjsOnPage", True), ("ClipAsCharacterAnchoredWriterFlyFrames", True), ("UnxForceZeroExtLeading", True),
1359            ("UseOldPrinterMetrics", True), ("TabsRelativeToIndent", False), ("ProtectForm", True),
1360            ("TabAtLeftIndentForParagraphsInList", True), ("MathBaselineAlignment", False),
1361            ("RedlineProtectionKey", uno.Any("[]byte", (1, 2, 3)))]
1362    for k, v in base:
1363        try:
1364            if isinstance(v, uno.Any):
1365                uno.invoke(st, "setPropertyValue", (k, v))
1366            else:
1367                st.setPropertyValue(k, v)
1368        except Exception as e:
1369            print("settings prop", k, repr(e)[:80])
1370    save(doc, "settings.odt")
1371    doc.close(True)
1372
1373
1374def doc_web():
1375    doc = new("private:factory/swriter/web")
1376    w = W(doc)
1377    w.s("web doc with field ")
1378    w.field("PageCount", NumberingType=4)
1379    w.para()
1380    f = w.mk("com.sun.star.text.TextField.Annotation", Author="W", Content="web note")
1381    w.put(f)
1382    save(doc, "web-fields.odt", "writerweb8_writer")
1383    doc.close(True)
1384
1385
1386def run_all():
1387    attempt("fields-docinfo", doc_fields_info)
1388    attempt("fields-misc", doc_fields_misc)
1389    attempt("variables", doc_variables)
1390    attempt("indexes", doc_indexes)
1391    attempt("objects", doc_objects)
1392    attempt("bibliography", doc_bibliography)
1393    attempt("refs-notes", doc_refs_notes)
1394    attempt("notes-variants", doc_notes_variants)
1395    attempt("annotations", doc_annotations)
1396    attempt("hyperlinks-ruby", doc_hyperlinks)
1397    attempt("lists-outline", doc_lists)
1398    attempt("structure", doc_structure)
1399    attempt("linenumbers", doc_linenumbers)
1400    attempt("forms", doc_forms)
1401    attempt("database-fields", doc_database)
1402    attempt("redlines", doc_redlines)
1403    attempt("table-fields", doc_table_fields)
1404    attempt("master", doc_master)
1405    attempt("settings", doc_settings)
1406    attempt("web", doc_web)
1407
1408
1409def set_compat(flag):
1410    cp = desk_ctx.ServiceManager.createInstanceWithContext("com.sun.star.configuration.ConfigurationProvider", desk_ctx)
1411    ca = cp.createInstanceWithArguments("com.sun.star.configuration.ConfigurationUpdateAccess",
1412                                        (pv("nodepath", "/org.openoffice.Office.Common/Save/Document"),))
1413    ca.setPropertyValue("SaveBackwardCompatibleODF", flag)
1414    ca.commitChanges()
1415
1416
1417run_all()
1418SUF = "-nocompat"
1419# SaveBackwardCompatibleODF=true (the default) writes the ODF 1.1 element names; the second pass shows what the 1.2 names would be
1420try:
1421    set_compat(False)
1422    for n, fn in (("fields-misc", doc_fields_misc), ("refs-notes", doc_refs_notes), ("variables", doc_variables),
1423                  ("indexes", doc_indexes), ("lists-outline", doc_lists), ("structure", doc_structure)):
1424        attempt(n + SUF, fn)
1425except Exception as e:
1426    print("FAIL nocompat pass", repr(e)[:150])
1427    failed.append("nocompat")
1428finally:
1429    try:
1430        set_compat(True)
1431    except Exception as e:
1432        print("FAIL restoring SaveBackwardCompatibleODF", repr(e)[:100])
1433sys.exit(1 if failed else 0)
1434