summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
Diffstat (limited to 'sw')
-rw-r--r--sw/CppunitTest_sw_apitests.mk1
-rw-r--r--sw/CppunitTest_sw_core_accessibilitycheck.mk4
-rw-r--r--sw/CppunitTest_sw_core_draw.mk1
-rw-r--r--sw/CppunitTest_sw_core_theme.mk63
-rw-r--r--sw/CppunitTest_sw_filter_ww8.mk75
-rw-r--r--sw/CppunitTest_sw_macros_test.mk1
-rw-r--r--sw/CppunitTest_sw_ooxmlexport18.mk18
-rw-r--r--sw/CppunitTest_sw_ooxmlimport.mk1
-rw-r--r--sw/CppunitTest_sw_ooxmlimport2.mk1
-rw-r--r--sw/CppunitTest_sw_tiledrendering.mk1
-rw-r--r--sw/CppunitTest_sw_uibase_dialog.mk76
-rw-r--r--sw/CppunitTest_sw_uibase_dochdl.mk1
-rw-r--r--sw/CppunitTest_sw_uibase_frmdlg.mk1
-rw-r--r--sw/CppunitTest_sw_uibase_shells.mk3
-rw-r--r--sw/CppunitTest_sw_uibase_uno.mk1
-rw-r--r--sw/CppunitTest_sw_uwriter.mk1
-rw-r--r--sw/CppunitTest_sw_ww8export4.mk14
-rw-r--r--sw/Library_sw.mk9
-rw-r--r--sw/Library_swui.mk3
-rw-r--r--sw/Library_vbaswobj.mk12
-rw-r--r--sw/Module_sw.mk7
-rw-r--r--sw/UIConfig_swriter.mk3
-rw-r--r--sw/UITest_sw_ui_misc.mk16
-rw-r--r--sw/UITest_sw_uibase_docvw.mk16
-rw-r--r--sw/inc/AccessibilityCheckStrings.hrc8
-rw-r--r--sw/inc/GrammarContact.hxx (renamed from sw/inc/IGrammarContact.hxx)51
-rw-r--r--sw/inc/IDocumentMarkAccess.hxx9
-rw-r--r--sw/inc/IMark.hxx27
-rw-r--r--sw/inc/OnlineAccessibilityCheck.hxx76
-rw-r--r--sw/inc/bitmaps.hlst4
-rw-r--r--sw/inc/charfmt.hxx3
-rw-r--r--sw/inc/cmdid.h16
-rw-r--r--sw/inc/crsrsh.hxx11
-rw-r--r--sw/inc/doc.hxx17
-rw-r--r--sw/inc/fldbas.hxx1
-rw-r--r--sw/inc/fmtcol.hxx2
-rw-r--r--sw/inc/formatcontentcontrol.hxx95
-rw-r--r--sw/inc/ndole.hxx4
-rw-r--r--sw/inc/ndtxt.hxx37
-rw-r--r--sw/inc/node.hxx23
-rw-r--r--sw/inc/pam.hxx3
-rw-r--r--sw/inc/strings.hrc4
-rw-r--r--sw/inc/swabstdlg.hxx24
-rw-r--r--sw/inc/swtypes.hxx7
-rw-r--r--sw/inc/swundo.hxx1
-rw-r--r--sw/inc/textcontentcontrol.hxx32
-rw-r--r--sw/inc/txatbase.hxx2
-rw-r--r--sw/inc/txtrfmrk.hxx2
-rw-r--r--sw/inc/unoprnms.hxx11
-rw-r--r--sw/inc/unotextcursor.hxx1
-rw-r--r--sw/inc/unotxdoc.hxx12
-rw-r--r--sw/inc/view.hxx2
-rw-r--r--sw/inc/viscrs.hxx8
-rw-r--r--sw/layoutwriter_setup.mk1
-rw-r--r--sw/ooxmlexport_setup.mk1
-rw-r--r--sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx303
-rw-r--r--sw/qa/core/accessibilitycheck/data/AccessibilityTests1.odtbin20915 -> 19334 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/AccessibilityTests_NumberingCheck.odtbin0 -> 14373 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/BackgroundImageTest.odtbin0 -> 8263 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/FakeCaptionTest.odtbin0 -> 12314 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/FakeFootnoteTest.odtbin0 -> 8875 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/HighlightTest.odtbin0 -> 8599 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/HyperlinkTest.odtbin0 -> 8663 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/NewlineTest.odtbin0 -> 8609 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/OnlineCheck.odtbin0 -> 11226 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/ParagraphTest.odtbin0 -> 8330 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/SpaceTest.odtbin0 -> 8565 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/TableFormattingTest.odtbin0 -> 9111 bytes
-rw-r--r--sw/qa/core/accessibilitycheck/data/TabsTest.odtbin0 -> 9333 bytes
-rw-r--r--sw/qa/core/crsr/crsr.cxx42
-rw-r--r--sw/qa/core/data/docm/testModernVBA.docmbin0 -> 32970 bytes
-rw-r--r--sw/qa/core/data/docm/testVBA.docmbin0 -> 32380 bytes
-rw-r--r--sw/qa/core/doc/doc.cxx30
-rw-r--r--sw/qa/core/draw/data/sdt-textbox-header.docxbin0 -> 30694 bytes
-rw-r--r--sw/qa/core/draw/draw.cxx11
-rw-r--r--sw/qa/core/layout/data/header-textbox.docxbin0 -> 5778 bytes
-rw-r--r--sw/qa/core/layout/layout.cxx15
-rw-r--r--sw/qa/core/macros-test.cxx27
-rw-r--r--sw/qa/core/text/data/number-portion-format.odtbin0 -> 8984 bytes
-rw-r--r--sw/qa/core/text/data/number-portion-noformat.docxbin0 -> 13230 bytes
-rw-r--r--sw/qa/core/text/text.cxx376
-rw-r--r--sw/qa/core/theme/ThemeTest.cxx83
-rw-r--r--sw/qa/core/theme/data/ThemeColorInHeading.docxbin0 -> 12352 bytes
-rw-r--r--sw/qa/core/txtnode/txtnode.cxx128
-rw-r--r--sw/qa/core/unocore/data/paragraph-marker-formatted-run.docxbin0 -> 13294 bytes
-rw-r--r--sw/qa/core/unocore/data/paragraph-marker.docxbin0 -> 13282 bytes
-rw-r--r--sw/qa/core/unocore/unocore.cxx213
-rw-r--r--sw/qa/extras/htmlexport/htmlexport.cxx134
-rw-r--r--sw/qa/extras/htmlimport/data/green-highlight.html1
-rw-r--r--sw/qa/extras/htmlimport/data/tdf155011.html31
-rw-r--r--sw/qa/extras/htmlimport/htmlimport.cxx18
-rw-r--r--sw/qa/extras/layout/data/tdf155611_table_and_nested_section.fodt33
-rw-r--r--sw/qa/extras/layout/data/three_sections.fodt18
-rw-r--r--sw/qa/extras/layout/layout2.cxx74
-rw-r--r--sw/qa/extras/odfexport/data/section-columns-separator.fodt24
-rw-r--r--sw/qa/extras/odfexport/data/table-in-frame-in-table-in-header-base.odtbin0 -> 10398 bytes
-rw-r--r--sw/qa/extras/odfexport/data/tdf151100.docxbin0 -> 17741 bytes
-rw-r--r--sw/qa/extras/odfexport/odfexport.cxx20
-rw-r--r--sw/qa/extras/odfexport/odfexport2.cxx49
-rw-r--r--sw/qa/extras/odfimport/data/tdf149978.fodt53
-rw-r--r--sw/qa/extras/odfimport/odfimport.cxx12
-rw-r--r--sw/qa/extras/ooxmlexport/data/content-control-grab-bag.docxbin0 -> 30547 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/crop-roundtrip.docxbin0 -> 143445 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docxbin0 -> 19290 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/inline-sdt-header.docxbin0 -> 14930 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/number-portion-format.odtbin0 -> 8984 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/sdt-duplicated-id.docxbin0 -> 11940 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf125338.docmbin0 -> 20187 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf141652_fillBitmapName.docxbin152902 -> 0 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf146955.odtbin0 -> 77349 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf147892.fodt25
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf150966_regularInset.docxbin0 -> 17569 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf151548_activeContentDemo.docmbin0 -> 47797 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf152200-field+textbox.docxbin0 -> 15009 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf152425.docxbin0 -> 16904 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf152636_lostPageBreak2.docxbin0 -> 16206 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf153613_sdtAfterPgBreak.docxbin0 -> 46930 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak14.docxbin0 -> 14353 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak15.docxbin0 -> 14358 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/data/tdf157136_TwoContentControls.docxbin0 -> 22502 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport10.cxx6
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport11.cxx13
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport13.cxx18
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport16.cxx2
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport17.cxx57
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport18.cxx328
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport2.cxx3
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport3.cxx15
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport4.cxx1
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport5.cxx2
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport6.cxx10
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport8.cxx12
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport9.cxx10
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx61
-rw-r--r--sw/qa/extras/ooxmlimport/data/tdf152200-bad_fldChar_end.docxbin0 -> 10153 bytes
-rw-r--r--sw/qa/extras/ooxmlimport/ooxmlimport2.cxx6
-rw-r--r--sw/qa/extras/tiledrendering/data/content-control.odtbin9683 -> 0 bytes
-rw-r--r--sw/qa/extras/tiledrendering/data/multiline.odtbin0 -> 10456 bytes
-rw-r--r--sw/qa/extras/tiledrendering/data/savedauthorfield.odtbin0 -> 9373 bytes
-rw-r--r--sw/qa/extras/tiledrendering/data/testTableCommentRemoveCallback.odtbin0 -> 11077 bytes
-rw-r--r--sw/qa/extras/tiledrendering/tiledrendering.cxx179
-rw-r--r--sw/qa/extras/uiwriter/data/HiddenSection.odtbin0 -> 8378 bytes
-rw-r--r--sw/qa/extras/uiwriter/data/tdf142715.odtbin0 -> 11275 bytes
-rw-r--r--sw/qa/extras/uiwriter/data/tdf147507.fodt77
-rw-r--r--sw/qa/extras/uiwriter/data/tdf151548_tabNavigation.docmbin0 -> 13417 bytes
-rw-r--r--sw/qa/extras/uiwriter/uiwriter2.cxx71
-rw-r--r--sw/qa/extras/uiwriter/uiwriter3.cxx36
-rw-r--r--sw/qa/extras/uiwriter/uiwriter4.cxx43
-rw-r--r--sw/qa/extras/ww8export/data/tdf151548_formFieldMacros.docbin0 -> 43520 bytes
-rw-r--r--sw/qa/extras/ww8export/ww8export4.cxx57
-rw-r--r--sw/qa/extras/ww8import/data/tdf120761_zOrder.dot (renamed from sw/qa/extras/ww8import/data/tdf120761_zOrder.doc)bin53760 -> 53760 bytes
-rw-r--r--sw/qa/extras/ww8import/ww8import.cxx2
-rw-r--r--sw/qa/filter/ww8/ww8.cxx172
-rw-r--r--sw/qa/inc/swmodeltestbase.hxx13
-rw-r--r--sw/qa/uibase/dialog/dialog.cxx58
-rw-r--r--sw/qa/uibase/fldui/fldui.cxx27
-rw-r--r--sw/qa/uibase/shells/shells.cxx692
-rw-r--r--sw/qa/uibase/shells/textfld.cxx88
-rw-r--r--sw/qa/uibase/shells/textsh.cxx63
-rw-r--r--sw/qa/uibase/uno/uno.cxx312
-rw-r--r--sw/qa/uibase/wrtsh/wrtsh.cxx50
-rw-r--r--sw/qa/uitest/ui/misc/misc.py62
-rw-r--r--sw/qa/uitest/uibase/docvw/docvw.py36
-rw-r--r--sw/qa/unit/swmodeltestbase.cxx21
-rw-r--r--sw/sdi/_basesh.sdi12
-rw-r--r--sw/sdi/_grfsh.sdi1
-rw-r--r--sw/sdi/_textsh.sdi77
-rw-r--r--sw/sdi/_viewsh.sdi17
-rw-r--r--sw/sdi/swriter.sdi221
-rw-r--r--sw/sdi/viewsh.sdi6
-rw-r--r--sw/secmod.dbbin0 -> 16384 bytes
-rw-r--r--sw/source/core/access/AccessibilityCheck.cxx619
-rw-r--r--sw/source/core/crsr/bookmark.cxx293
-rw-r--r--sw/source/core/crsr/callnk.cxx42
-rw-r--r--sw/source/core/crsr/contentcontrolbutton.cxx43
-rw-r--r--sw/source/core/crsr/crbm.cxx10
-rw-r--r--sw/source/core/crsr/crsrsh.cxx22
-rw-r--r--sw/source/core/crsr/crstrvl.cxx137
-rw-r--r--sw/source/core/crsr/pam.cxx18
-rw-r--r--sw/source/core/crsr/viscrs.cxx57
-rw-r--r--sw/source/core/doc/DocumentContentOperationsManager.cxx18
-rw-r--r--sw/source/core/doc/DocumentRedlineManager.cxx7
-rw-r--r--sw/source/core/doc/DocumentStylePoolManager.cxx16
-rw-r--r--sw/source/core/doc/dbgoutsw.cxx8
-rw-r--r--sw/source/core/doc/doc.cxx33
-rw-r--r--sw/source/core/doc/docbm.cxx56
-rw-r--r--sw/source/core/doc/docfld.cxx28
-rw-r--r--sw/source/core/doc/docfmt.cxx2
-rw-r--r--sw/source/core/doc/doclay.cxx11
-rw-r--r--sw/source/core/doc/docnew.cxx18
-rw-r--r--sw/source/core/doc/docredln.cxx6
-rw-r--r--sw/source/core/doc/fmtcol.cxx15
-rw-r--r--sw/source/core/doc/textboxhelper.cxx16
-rw-r--r--sw/source/core/docnode/ndsect.cxx1
-rw-r--r--sw/source/core/docnode/ndtbl1.cxx3
-rw-r--r--sw/source/core/docnode/node.cxx18
-rw-r--r--sw/source/core/docnode/nodes.cxx20
-rw-r--r--sw/source/core/draw/dcontact.cxx52
-rw-r--r--sw/source/core/draw/dflyobj.cxx13
-rw-r--r--sw/source/core/fields/docufld.cxx11
-rw-r--r--sw/source/core/fields/fldbas.cxx31
-rw-r--r--sw/source/core/frmedt/fetab.cxx10
-rw-r--r--sw/source/core/inc/AccessibilityCheck.hxx29
-rw-r--r--sw/source/core/inc/AccessibilityIssue.hxx6
-rw-r--r--sw/source/core/inc/DocumentContentOperationsManager.hxx3
-rw-r--r--sw/source/core/inc/MarkManager.hxx6
-rw-r--r--sw/source/core/inc/ThemeColorChanger.hxx36
-rw-r--r--sw/source/core/inc/UndoAttribute.hxx2
-rw-r--r--sw/source/core/inc/UndoTable.hxx8
-rw-r--r--sw/source/core/inc/bookmark.hxx138
-rw-r--r--sw/source/core/inc/contentcontrolbutton.hxx2
-rw-r--r--sw/source/core/inc/dflyobj.hxx1
-rw-r--r--sw/source/core/inc/layact.hxx18
-rw-r--r--sw/source/core/inc/rolbck.hxx2
-rw-r--r--sw/source/core/inc/sectfrm.hxx2
-rw-r--r--sw/source/core/inc/unocontentcontrol.hxx20
-rw-r--r--sw/source/core/inc/unoport.hxx7
-rw-r--r--sw/source/core/layout/anchoreddrawobject.cxx8
-rw-r--r--sw/source/core/layout/atrfrm.cxx4
-rw-r--r--sw/source/core/layout/flowfrm.cxx5
-rw-r--r--sw/source/core/layout/frmtool.cxx63
-rw-r--r--sw/source/core/layout/layact.cxx146
-rw-r--r--sw/source/core/layout/layhelp.hxx3
-rw-r--r--sw/source/core/layout/sectfrm.cxx93
-rw-r--r--sw/source/core/layout/wsfrm.cxx5
-rw-r--r--sw/source/core/model/ThemeColorChanger.cxx274
-rw-r--r--sw/source/core/ole/ndole.cxx89
-rw-r--r--sw/source/core/table/swtable.cxx6
-rw-r--r--sw/source/core/text/itrform2.cxx183
-rw-r--r--sw/source/core/text/itrtxt.cxx37
-rw-r--r--sw/source/core/text/porfld.cxx5
-rw-r--r--sw/source/core/text/porfld.hxx5
-rw-r--r--sw/source/core/text/porlay.cxx4
-rw-r--r--sw/source/core/text/porrst.cxx24
-rw-r--r--sw/source/core/text/redlnitr.cxx2
-rw-r--r--sw/source/core/text/txtfld.cxx29
-rw-r--r--sw/source/core/text/txtfly.cxx19
-rw-r--r--sw/source/core/text/txtfrm.cxx6
-rw-r--r--sw/source/core/text/xmldump.cxx5
-rw-r--r--sw/source/core/txtnode/GrammarContact.cxx (renamed from sw/source/core/txtnode/SwGrammarContact.cxx)84
-rw-r--r--sw/source/core/txtnode/OnlineAccessibilityCheck.cxx301
-rw-r--r--sw/source/core/txtnode/atrref.cxx27
-rw-r--r--sw/source/core/txtnode/attrcontentcontrol.cxx395
-rw-r--r--sw/source/core/txtnode/chrfmt.cxx19
-rw-r--r--sw/source/core/txtnode/modeltoviewhelper.cxx12
-rw-r--r--sw/source/core/txtnode/ndtxt.cxx26
-rw-r--r--sw/source/core/txtnode/thints.cxx37
-rw-r--r--sw/source/core/txtnode/txtatr2.cxx15
-rw-r--r--sw/source/core/txtnode/txtedt.cxx149
-rw-r--r--sw/source/core/undo/docundo.cxx9
-rw-r--r--sw/source/core/undo/unattr.cxx47
-rw-r--r--sw/source/core/undo/undobj.cxx3
-rw-r--r--sw/source/core/undo/untbl.cxx2
-rw-r--r--sw/source/core/unocore/unobkm.cxx2
-rw-r--r--sw/source/core/unocore/unocontentcontrol.cxx333
-rw-r--r--sw/source/core/unocore/unoflatpara.cxx6
-rw-r--r--sw/source/core/unocore/unomap.cxx3
-rw-r--r--sw/source/core/unocore/unomap1.cxx16
-rw-r--r--sw/source/core/unocore/unomapproperties.hxx9
-rw-r--r--sw/source/core/unocore/unoobj.cxx214
-rw-r--r--sw/source/core/unocore/unoport.cxx57
-rw-r--r--sw/source/core/unocore/unoportenum.cxx25
-rw-r--r--sw/source/core/unocore/unostyle.cxx1310
-rw-r--r--sw/source/core/unocore/unotext.cxx81
-rw-r--r--sw/source/core/unocore/unotextmarkup.cxx11
-rw-r--r--sw/source/core/view/viewimp.cxx5
-rw-r--r--sw/source/core/view/viewsh.cxx2
-rw-r--r--sw/source/filter/html/css1atr.cxx3
-rw-r--r--sw/source/filter/html/htmlatr.cxx13
-rw-r--r--sw/source/filter/html/htmlfldw.cxx3
-rw-r--r--sw/source/filter/html/htmlnumwriter.cxx21
-rw-r--r--sw/source/filter/html/htmlplug.cxx10
-rw-r--r--sw/source/filter/html/parcss1.cxx26
-rw-r--r--sw/source/filter/html/wrthtml.cxx7
-rw-r--r--sw/source/filter/html/wrthtml.hxx3
-rw-r--r--sw/source/filter/inc/wwstyles.hxx1
-rw-r--r--sw/source/filter/ww8/WW8TableInfo.cxx2
-rw-r--r--sw/source/filter/ww8/attributeoutputbase.hxx12
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx379
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx34
-rw-r--r--sw/source/filter/ww8/docxexport.cxx67
-rw-r--r--sw/source/filter/ww8/docxexportfilter.cxx35
-rw-r--r--sw/source/filter/ww8/rtfattributeoutput.cxx12
-rw-r--r--sw/source/filter/ww8/rtfattributeoutput.hxx9
-rw-r--r--sw/source/filter/ww8/styles.cxx186
-rw-r--r--sw/source/filter/ww8/wrtw8nds.cxx68
-rw-r--r--sw/source/filter/ww8/wrtw8sty.cxx384
-rw-r--r--sw/source/filter/ww8/wrtww8.cxx16
-rw-r--r--sw/source/filter/ww8/wrtww8.hxx47
-rw-r--r--sw/source/filter/ww8/ww8atr.cxx6
-rw-r--r--sw/source/filter/ww8/ww8attributeoutput.hxx6
-rw-r--r--sw/source/filter/ww8/ww8par3.cxx1
-rw-r--r--sw/source/filter/xml/xmlexp.hxx4
-rw-r--r--sw/source/filter/xml/xmlfmte.cxx12
-rw-r--r--sw/source/filter/xml/xmliteme.cxx2
-rw-r--r--sw/source/filter/xml/xmltble.cxx197
-rw-r--r--sw/source/filter/xml/xmltexte.hxx16
-rw-r--r--sw/source/filter/xml/xmltexti.cxx9
-rw-r--r--sw/source/ui/chrdlg/numpara.cxx14
-rw-r--r--sw/source/ui/chrdlg/pardlg.cxx4
-rw-r--r--sw/source/ui/chrdlg/tblnumfm.cxx3
-rw-r--r--sw/source/ui/dialog/swdlgfact.cxx74
-rw-r--r--sw/source/ui/dialog/swdlgfact.hxx54
-rw-r--r--sw/source/ui/dialog/uiregionsw.cxx31
-rw-r--r--sw/source/ui/frmdlg/cption.cxx41
-rw-r--r--sw/source/ui/index/cnttab.cxx25
-rw-r--r--sw/source/ui/misc/contentcontroldlg.cxx114
-rw-r--r--sw/source/ui/misc/pagenumberdlg.cxx92
-rw-r--r--sw/source/ui/misc/pggrid.cxx27
-rw-r--r--sw/source/ui/misc/translatelangselect.cxx159
-rw-r--r--sw/source/ui/table/splittbl.cxx11
-rw-r--r--sw/source/ui/uno/swdetect.cxx25
-rw-r--r--sw/source/ui/vba/vbaapplication.cxx315
-rw-r--r--sw/source/ui/vba/vbacontentcontrol.cxx753
-rw-r--r--sw/source/ui/vba/vbacontentcontrol.hxx142
-rw-r--r--sw/source/ui/vba/vbacontentcontrollistentries.cxx166
-rw-r--r--sw/source/ui/vba/vbacontentcontrollistentries.hxx51
-rw-r--r--sw/source/ui/vba/vbacontentcontrollistentry.cxx167
-rw-r--r--sw/source/ui/vba/vbacontentcontrollistentry.hxx54
-rw-r--r--sw/source/ui/vba/vbacontentcontrols.cxx268
-rw-r--r--sw/source/ui/vba/vbacontentcontrols.hxx40
-rw-r--r--sw/source/ui/vba/vbadocument.cxx37
-rw-r--r--sw/source/ui/vba/vbadocument.hxx3
-rw-r--r--sw/source/ui/vba/vbaformfield.cxx258
-rw-r--r--sw/source/ui/vba/vbaformfield.hxx87
-rw-r--r--sw/source/ui/vba/vbaformfieldcheckbox.cxx117
-rw-r--r--sw/source/ui/vba/vbaformfieldcheckbox.hxx54
-rw-r--r--sw/source/ui/vba/vbaformfielddropdown.cxx99
-rw-r--r--sw/source/ui/vba/vbaformfielddropdown.hxx52
-rw-r--r--sw/source/ui/vba/vbaformfielddropdownlistentries.cxx162
-rw-r--r--sw/source/ui/vba/vbaformfielddropdownlistentries.hxx49
-rw-r--r--sw/source/ui/vba/vbaformfielddropdownlistentry.cxx56
-rw-r--r--sw/source/ui/vba/vbaformfielddropdownlistentry.hxx48
-rw-r--r--sw/source/ui/vba/vbaformfields.cxx235
-rw-r--r--sw/source/ui/vba/vbaformfields.hxx41
-rw-r--r--sw/source/ui/vba/vbaformfieldtextinput.cxx130
-rw-r--r--sw/source/ui/vba/vbaformfieldtextinput.hxx68
-rw-r--r--sw/source/ui/vba/vbaglobals.cxx9
-rw-r--r--sw/source/ui/vba/vbaglobals.hxx1
-rw-r--r--sw/source/ui/vba/vbawordbasic.cxx265
-rw-r--r--sw/source/ui/vba/vbawordbasic.hxx83
-rw-r--r--sw/source/uibase/app/docst.cxx2
-rw-r--r--sw/source/uibase/app/docstyle.cxx22
-rw-r--r--sw/source/uibase/app/swmodule.cxx2
-rw-r--r--sw/source/uibase/dbui/dbmgr.cxx37
-rw-r--r--sw/source/uibase/dialog/regionsw.cxx27
-rw-r--r--sw/source/uibase/dochdl/swdtflvr.cxx2
-rw-r--r--sw/source/uibase/docvw/FrameControlsManager.cxx27
-rw-r--r--sw/source/uibase/docvw/PageBreakWin.cxx1
-rw-r--r--sw/source/uibase/docvw/PostItMgr.cxx11
-rw-r--r--sw/source/uibase/docvw/contentcontrolaliasbutton.cxx150
-rw-r--r--sw/source/uibase/docvw/edtwin.cxx181
-rw-r--r--sw/source/uibase/fldui/fldmgr.cxx35
-rw-r--r--sw/source/uibase/inc/AccessibilityStatusBarControl.hxx36
-rw-r--r--sw/source/uibase/inc/FrameControlsManager.hxx2
-rw-r--r--sw/source/uibase/inc/contentcontrolaliasbutton.hxx42
-rw-r--r--sw/source/uibase/inc/contentcontroldlg.hxx5
-rw-r--r--sw/source/uibase/inc/cption.hxx1
-rw-r--r--sw/source/uibase/inc/edtwin.hxx12
-rw-r--r--sw/source/uibase/inc/numpara.hxx2
-rw-r--r--sw/source/uibase/inc/pagenumberdlg.hxx51
-rw-r--r--sw/source/uibase/inc/splittbl.hxx12
-rw-r--r--sw/source/uibase/inc/tblnumfm.hxx3
-rw-r--r--sw/source/uibase/inc/translatehelper.hxx42
-rw-r--r--sw/source/uibase/inc/translatelangselect.hxx69
-rw-r--r--sw/source/uibase/inc/wrtsh.hxx10
-rw-r--r--sw/source/uibase/shells/basesh.cxx258
-rw-r--r--sw/source/uibase/shells/drwtxtex.cxx8
-rw-r--r--sw/source/uibase/shells/olesh.cxx12
-rw-r--r--sw/source/uibase/shells/tabsh.cxx76
-rw-r--r--sw/source/uibase/shells/textfld.cxx413
-rw-r--r--sw/source/uibase/shells/textsh.cxx10
-rw-r--r--sw/source/uibase/shells/textsh1.cxx501
-rw-r--r--sw/source/uibase/shells/translatehelper.cxx215
-rw-r--r--sw/source/uibase/sidebar/ThemePanel.cxx439
-rw-r--r--sw/source/uibase/sidebar/ThemePanel.hxx7
-rw-r--r--sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx14
-rw-r--r--sw/source/uibase/uiview/formatclipboard.cxx8
-rw-r--r--sw/source/uibase/uiview/view.cxx12
-rw-r--r--sw/source/uibase/uiview/view0.cxx31
-rw-r--r--sw/source/uibase/uiview/view2.cxx11
-rw-r--r--sw/source/uibase/uiview/viewdlg2.cxx11
-rw-r--r--sw/source/uibase/uno/loktxdoc.cxx494
-rw-r--r--sw/source/uibase/uno/unotxdoc.cxx96
-rw-r--r--sw/source/uibase/utlui/AccessibilityStatusBarControl.cxx81
-rw-r--r--sw/source/uibase/wrtsh/wrtsh1.cxx50
-rw-r--r--sw/source/uibase/wrtsh/wrtsh2.cxx38
-rw-r--r--sw/source/uibase/wrtsh/wrtsh3.cxx23
-rw-r--r--sw/source/uibase/wrtsh/wrtsh4.cxx6
-rw-r--r--sw/uiconfig/sglobal/menubar/menubar.xml4
-rw-r--r--sw/uiconfig/sglobal/statusbar/statusbar.xml1
-rw-r--r--sw/uiconfig/swriter/menubar/menubar.xml8
-rw-r--r--sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml2
-rw-r--r--sw/uiconfig/swriter/statusbar/statusbar.xml1
-rw-r--r--sw/uiconfig/swriter/ui/assignstylesdialog.ui3
-rw-r--r--sw/uiconfig/swriter/ui/contentcontrolaliasbutton.ui28
-rw-r--r--sw/uiconfig/swriter/ui/contentcontroldlg.ui53
-rw-r--r--sw/uiconfig/swriter/ui/pagenumberdlg.ui222
-rw-r--r--sw/uiconfig/swriter/ui/sidebartheme.ui164
-rw-r--r--sw/uiconfig/swriter/ui/sidebarwrap.ui94
-rw-r--r--sw/uiconfig/swriter/ui/translationdialog.ui104
-rw-r--r--sw/uiwriter_setup.mk1
-rw-r--r--sw/ww8export_setup.mk1
403 files changed, 18632 insertions, 3337 deletions
diff --git a/sw/CppunitTest_sw_apitests.mk b/sw/CppunitTest_sw_apitests.mk
index 9af8873079d3..716607dbe404 100644
--- a/sw/CppunitTest_sw_apitests.mk
+++ b/sw/CppunitTest_sw_apitests.mk
@@ -29,6 +29,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_apitests, \
cppu \
cppuhelper \
drawinglayer \
+ docmodel \
editeng \
for \
forui \
diff --git a/sw/CppunitTest_sw_core_accessibilitycheck.mk b/sw/CppunitTest_sw_core_accessibilitycheck.mk
index 0d102842a6e1..91b455dda736 100644
--- a/sw/CppunitTest_sw_core_accessibilitycheck.mk
+++ b/sw/CppunitTest_sw_core_accessibilitycheck.mk
@@ -25,10 +25,12 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_core_accessibilitycheck, \
svx \
sfx \
sw \
- swqahelper \
+ swqahelper \
test \
unotest \
utl \
+ tl \
+ vcl \
))
$(eval $(call gb_CppunitTest_use_externals,sw_core_accessibilitycheck,\
diff --git a/sw/CppunitTest_sw_core_draw.mk b/sw/CppunitTest_sw_core_draw.mk
index 7e38fbce1386..b1b32169514e 100644
--- a/sw/CppunitTest_sw_core_draw.mk
+++ b/sw/CppunitTest_sw_core_draw.mk
@@ -21,6 +21,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_core_draw, \
comphelper \
cppu \
cppuhelper \
+ docmodel \
sal \
sfx \
svxcore \
diff --git a/sw/CppunitTest_sw_core_theme.mk b/sw/CppunitTest_sw_core_theme.mk
new file mode 100644
index 000000000000..03b42a32e666
--- /dev/null
+++ b/sw/CppunitTest_sw_core_theme.mk
@@ -0,0 +1,63 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,sw_core_theme))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_core_theme))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sw_core_theme, \
+ sw/qa/core/theme/ThemeTest \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sw_core_theme, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ docmodel \
+ sal \
+ sfx \
+ subsequenttest \
+ sw \
+ swqahelper \
+ test \
+ unotest \
+ utl \
+ vcl \
+ svt \
+ tl \
+ svl \
+ svxcore \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sw_core_theme,\
+ boost_headers \
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sw_core_theme,\
+ -I$(SRCDIR)/sw/inc \
+ -I$(SRCDIR)/sw/source/core/inc \
+ -I$(SRCDIR)/sw/source/uibase/inc \
+ -I$(SRCDIR)/sw/qa/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sw_core_theme,\
+ udkapi \
+ offapi \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,sw_core_theme))
+$(eval $(call gb_CppunitTest_use_vcl,sw_core_theme))
+$(eval $(call gb_CppunitTest_use_rdb,sw_core_theme,services))
+$(eval $(call gb_CppunitTest_use_configuration,sw_core_theme))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/CppunitTest_sw_filter_ww8.mk b/sw/CppunitTest_sw_filter_ww8.mk
new file mode 100644
index 000000000000..0452776478df
--- /dev/null
+++ b/sw/CppunitTest_sw_filter_ww8.mk
@@ -0,0 +1,75 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,sw_filter_ww8))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_filter_ww8))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sw_filter_ww8, \
+ sw/qa/filter/ww8/ww8 \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sw_filter_ww8, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ editeng \
+ sal \
+ sfx \
+ svl \
+ svx \
+ svxcore \
+ sw \
+ swqahelper \
+ test \
+ unotest \
+ utl \
+ vcl \
+ tl \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sw_filter_ww8,\
+ boost_headers \
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sw_filter_ww8,\
+ -I$(SRCDIR)/sw/inc \
+ -I$(SRCDIR)/sw/source/core/inc \
+ -I$(SRCDIR)/sw/source/uibase/inc \
+ -I$(SRCDIR)/sw/qa/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sw_filter_ww8,\
+ udkapi \
+ offapi \
+ oovbaapi \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,sw_filter_ww8))
+$(eval $(call gb_CppunitTest_use_vcl,sw_filter_ww8))
+
+$(eval $(call gb_CppunitTest_use_rdb,sw_filter_ww8,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,sw_filter_ww8,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,sw_filter_ww8))
+
+$(eval $(call gb_CppunitTest_use_uiconfigs,sw_filter_ww8, \
+ modules/swriter \
+))
+
+$(eval $(call gb_CppunitTest_use_more_fonts,sw_filter_ww8))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/CppunitTest_sw_macros_test.mk b/sw/CppunitTest_sw_macros_test.mk
index 805242613b58..a3024928e021 100644
--- a/sw/CppunitTest_sw_macros_test.mk
+++ b/sw/CppunitTest_sw_macros_test.mk
@@ -25,6 +25,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_macros_test, \
cppu \
cppuhelper \
drawinglayer \
+ docmodel \
editeng \
for \
forui \
diff --git a/sw/CppunitTest_sw_ooxmlexport18.mk b/sw/CppunitTest_sw_ooxmlexport18.mk
new file mode 100644
index 000000000000..cf085f8eb0f6
--- /dev/null
+++ b/sw/CppunitTest_sw_ooxmlexport18.mk
@@ -0,0 +1,18 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call sw_ooxmlexport_test,18))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,sw_ooxmlexport18,\
+ officecfg/registry \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/CppunitTest_sw_ooxmlimport.mk b/sw/CppunitTest_sw_ooxmlimport.mk
index f4273f909e18..116520dc0c87 100644
--- a/sw/CppunitTest_sw_ooxmlimport.mk
+++ b/sw/CppunitTest_sw_ooxmlimport.mk
@@ -24,6 +24,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_ooxmlimport, \
comphelper \
cppu \
cppuhelper \
+ docmodel \
sal \
sfx \
test \
diff --git a/sw/CppunitTest_sw_ooxmlimport2.mk b/sw/CppunitTest_sw_ooxmlimport2.mk
index 67c4077fcecd..5a67cab8f901 100644
--- a/sw/CppunitTest_sw_ooxmlimport2.mk
+++ b/sw/CppunitTest_sw_ooxmlimport2.mk
@@ -24,6 +24,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_ooxmlimport2, \
comphelper \
cppu \
cppuhelper \
+ docmodel \
sal \
sfx \
test \
diff --git a/sw/CppunitTest_sw_tiledrendering.mk b/sw/CppunitTest_sw_tiledrendering.mk
index 8697cbf11209..1508770ddb7d 100644
--- a/sw/CppunitTest_sw_tiledrendering.mk
+++ b/sw/CppunitTest_sw_tiledrendering.mk
@@ -22,6 +22,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_tiledrendering, \
cppu \
cppuhelper \
editeng \
+ docmodel \
sal \
sfx \
svl \
diff --git a/sw/CppunitTest_sw_uibase_dialog.mk b/sw/CppunitTest_sw_uibase_dialog.mk
new file mode 100644
index 000000000000..eaecfc5abeb6
--- /dev/null
+++ b/sw/CppunitTest_sw_uibase_dialog.mk
@@ -0,0 +1,76 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call gb_CppunitTest_CppunitTest,sw_uibase_dialog))
+
+$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_uibase_dialog))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,sw_uibase_dialog, \
+ sw/qa/uibase/dialog/dialog \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,sw_uibase_dialog, \
+ comphelper \
+ cppu \
+ cppuhelper \
+ editeng \
+ sal \
+ sfx \
+ subsequenttest \
+ svl \
+ svx \
+ svxcore \
+ sw \
+ swqahelper \
+ test \
+ unotest \
+ utl \
+ vcl \
+ tl \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,sw_uibase_dialog,\
+ boost_headers \
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_set_include,sw_uibase_dialog,\
+ -I$(SRCDIR)/sw/inc \
+ -I$(SRCDIR)/sw/source/core/inc \
+ -I$(SRCDIR)/sw/source/uibase/inc \
+ -I$(SRCDIR)/sw/qa/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_CppunitTest_use_api,sw_uibase_dialog,\
+ udkapi \
+ offapi \
+ oovbaapi \
+))
+
+$(eval $(call gb_CppunitTest_use_ure,sw_uibase_dialog))
+$(eval $(call gb_CppunitTest_use_vcl,sw_uibase_dialog))
+
+$(eval $(call gb_CppunitTest_use_rdb,sw_uibase_dialog,services))
+
+$(eval $(call gb_CppunitTest_use_custom_headers,sw_uibase_dialog,\
+ officecfg/registry \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,sw_uibase_dialog))
+
+$(eval $(call gb_CppunitTest_use_uiconfigs,sw_uibase_dialog, \
+ modules/swriter \
+))
+
+$(eval $(call gb_CppunitTest_use_more_fonts,sw_uibase_dialog))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/CppunitTest_sw_uibase_dochdl.mk b/sw/CppunitTest_sw_uibase_dochdl.mk
index 36494c0e7a8c..f605226206bb 100644
--- a/sw/CppunitTest_sw_uibase_dochdl.mk
+++ b/sw/CppunitTest_sw_uibase_dochdl.mk
@@ -33,6 +33,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_uibase_dochdl, \
unotest \
utl \
vcl \
+ tl \
))
$(eval $(call gb_CppunitTest_use_externals,sw_uibase_dochdl,\
diff --git a/sw/CppunitTest_sw_uibase_frmdlg.mk b/sw/CppunitTest_sw_uibase_frmdlg.mk
index 5225def8fc2f..aea77b87d33d 100644
--- a/sw/CppunitTest_sw_uibase_frmdlg.mk
+++ b/sw/CppunitTest_sw_uibase_frmdlg.mk
@@ -33,6 +33,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_uibase_frmdlg, \
unotest \
utl \
vcl \
+ tl \
))
$(eval $(call gb_CppunitTest_use_externals,sw_uibase_frmdlg,\
diff --git a/sw/CppunitTest_sw_uibase_shells.mk b/sw/CppunitTest_sw_uibase_shells.mk
index 44901cc56d85..ea651ae573a7 100644
--- a/sw/CppunitTest_sw_uibase_shells.mk
+++ b/sw/CppunitTest_sw_uibase_shells.mk
@@ -14,6 +14,8 @@ $(eval $(call gb_CppunitTest_CppunitTest,sw_uibase_shells))
$(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_uibase_shells))
$(eval $(call gb_CppunitTest_add_exception_objects,sw_uibase_shells, \
+ sw/qa/uibase/shells/textfld \
+ sw/qa/uibase/shells/textsh \
sw/qa/uibase/shells/shells \
))
@@ -33,6 +35,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_uibase_shells, \
unotest \
utl \
vcl \
+ tl \
))
$(eval $(call gb_CppunitTest_use_externals,sw_uibase_shells,\
diff --git a/sw/CppunitTest_sw_uibase_uno.mk b/sw/CppunitTest_sw_uibase_uno.mk
index 36c54d04db33..d6e43918e4a4 100644
--- a/sw/CppunitTest_sw_uibase_uno.mk
+++ b/sw/CppunitTest_sw_uibase_uno.mk
@@ -33,6 +33,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_uibase_uno, \
unotest \
utl \
vcl \
+ tl \
))
$(eval $(call gb_CppunitTest_use_externals,sw_uibase_uno,\
diff --git a/sw/CppunitTest_sw_uwriter.mk b/sw/CppunitTest_sw_uwriter.mk
index aad626119569..5cef990520e3 100644
--- a/sw/CppunitTest_sw_uwriter.mk
+++ b/sw/CppunitTest_sw_uwriter.mk
@@ -34,6 +34,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_uwriter, \
cppuhelper \
$(call gb_Helper_optional,DBCONNECTIVITY, \
dbtools) \
+ docmodel \
drawinglayer \
editeng \
i18nlangtag \
diff --git a/sw/CppunitTest_sw_ww8export4.mk b/sw/CppunitTest_sw_ww8export4.mk
new file mode 100644
index 000000000000..47ac483ba688
--- /dev/null
+++ b/sw/CppunitTest_sw_ww8export4.mk
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#*************************************************************************
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+#*************************************************************************
+
+$(eval $(call sw_ww8export_test,4))
+
+# vim: set noet sw=4 ts=4:
diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk
index a49d53d0509f..df31cb18d150 100644
--- a/sw/Library_sw.mk
+++ b/sw/Library_sw.mk
@@ -58,6 +58,7 @@ $(eval $(call gb_Library_use_libraries,sw,\
cppuhelper \
$(call gb_Helper_optional,DBCONNECTIVITY, \
dbtools) \
+ docmodel \
drawinglayer \
editeng \
i18nlangtag \
@@ -358,6 +359,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
sw/source/core/layout/wsfrm \
sw/source/core/model/ModelTraverser \
sw/source/core/model/SearchResultLocator \
+ sw/source/core/model/ThemeColorChanger \
sw/source/core/objectpositioning/anchoredobjectposition \
sw/source/core/objectpositioning/ascharanchoredobjectposition \
sw/source/core/objectpositioning/environmentofanchoredobject \
@@ -422,7 +424,8 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
sw/source/core/tox/ToxTabStopTokenHandler \
sw/source/core/tox/ToxTextGenerator \
sw/source/core/tox/ToxWhitespaceStripper \
- sw/source/core/txtnode/SwGrammarContact \
+ sw/source/core/txtnode/GrammarContact \
+ sw/source/core/txtnode/OnlineAccessibilityCheck \
sw/source/core/txtnode/attrcontentcontrol \
sw/source/core/txtnode/atrfld \
sw/source/core/txtnode/atrflyin \
@@ -635,6 +638,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
sw/source/uibase/docvw/SidebarWinAcc \
sw/source/uibase/docvw/HeaderFooterWin \
sw/source/uibase/docvw/OutlineContentVisibilityWin \
+ sw/source/uibase/docvw/contentcontrolaliasbutton \
sw/source/uibase/docvw/edtdd \
sw/source/uibase/docvw/edtwin \
sw/source/uibase/docvw/edtwin2 \
@@ -687,6 +691,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
sw/source/uibase/shells/grfsh \
sw/source/uibase/shells/grfshex \
sw/source/uibase/shells/langhelper \
+ sw/source/uibase/shells/translatehelper \
sw/source/uibase/shells/listsh \
sw/source/uibase/shells/mediash \
sw/source/uibase/shells/navsh \
@@ -757,7 +762,9 @@ $(eval $(call gb_Library_add_exception_objects,sw,\
sw/source/uibase/uno/unomod \
sw/source/uibase/uno/unomodule \
sw/source/uibase/uno/unotxdoc \
+ sw/source/uibase/uno/loktxdoc \
sw/source/uibase/uno/unotxvw \
+ sw/source/uibase/utlui/AccessibilityStatusBarControl \
sw/source/uibase/utlui/attrdesc \
sw/source/uibase/utlui/bookctrl \
sw/source/uibase/utlui/condedit \
diff --git a/sw/Library_swui.mk b/sw/Library_swui.mk
index 4c1d9614f56c..c34451317dd7 100644
--- a/sw/Library_swui.mk
+++ b/sw/Library_swui.mk
@@ -77,6 +77,7 @@ $(eval $(call gb_Library_use_libraries,swui,\
utl \
vcl \
drawinglayer \
+ lng \
))
$(eval $(call gb_Library_add_exception_objects,swui,\
@@ -140,6 +141,7 @@ $(eval $(call gb_Library_add_exception_objects,swui,\
sw/source/ui/misc/bookmark \
sw/source/ui/misc/contentcontroldlg \
sw/source/ui/misc/contentcontrollistitemdlg \
+ sw/source/ui/misc/pagenumberdlg \
sw/source/ui/misc/docfnote \
sw/source/ui/misc/glosbib \
sw/source/ui/misc/glossary \
@@ -150,6 +152,7 @@ $(eval $(call gb_Library_add_exception_objects,swui,\
sw/source/ui/misc/pgfnote \
sw/source/ui/misc/pggrid \
sw/source/ui/misc/srtdlg \
+ sw/source/ui/misc/translatelangselect \
sw/source/ui/misc/swmodalredlineacceptdlg \
sw/source/ui/misc/titlepage \
sw/source/ui/table/colwd \
diff --git a/sw/Library_vbaswobj.mk b/sw/Library_vbaswobj.mk
index 8867fcf5ede4..8ad9dcc604e7 100644
--- a/sw/Library_vbaswobj.mk
+++ b/sw/Library_vbaswobj.mk
@@ -72,6 +72,17 @@ $(eval $(call gb_Library_add_exception_objects,vbaswobj,\
sw/source/ui/vba/vbacells \
sw/source/ui/vba/vbacolumn \
sw/source/ui/vba/vbacolumns \
+ sw/source/ui/vba/vbacontentcontrol \
+ sw/source/ui/vba/vbacontentcontrols \
+ sw/source/ui/vba/vbacontentcontrollistentry \
+ sw/source/ui/vba/vbacontentcontrollistentries \
+ sw/source/ui/vba/vbaformfield \
+ sw/source/ui/vba/vbaformfields \
+ sw/source/ui/vba/vbaformfieldcheckbox \
+ sw/source/ui/vba/vbaformfielddropdown \
+ sw/source/ui/vba/vbaformfielddropdownlistentries \
+ sw/source/ui/vba/vbaformfielddropdownlistentry \
+ sw/source/ui/vba/vbaformfieldtextinput \
sw/source/ui/vba/vbaframe \
sw/source/ui/vba/vbaframes \
sw/source/ui/vba/vbalistformat \
@@ -130,6 +141,7 @@ $(eval $(call gb_Library_add_exception_objects,vbaswobj,\
sw/source/ui/vba/vbatableofcontents \
sw/source/ui/vba/vbatablesofcontents \
sw/source/ui/vba/vbavariable \
+ sw/source/ui/vba/vbawordbasic \
sw/source/ui/vba/vbadocuments \
sw/source/ui/vba/vbaparagraphformat \
sw/source/ui/vba/vbaborders \
diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk
index ce9a13066a96..6dfdede6caf8 100644
--- a/sw/Module_sw.mk
+++ b/sw/Module_sw.mk
@@ -89,6 +89,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
CppunitTest_sw_ooxmlexport15 \
CppunitTest_sw_ooxmlexport16 \
CppunitTest_sw_ooxmlexport17 \
+ CppunitTest_sw_ooxmlexport18 \
CppunitTest_sw_ooxmlexport_template \
CppunitTest_sw_ooxmlfieldexport \
CppunitTest_sw_ooxmllinks \
@@ -99,6 +100,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
CppunitTest_sw_ww8export \
CppunitTest_sw_ww8export2 \
CppunitTest_sw_ww8export3 \
+ CppunitTest_sw_ww8export4 \
CppunitTest_sw_ww8import \
CppunitTest_sw_rtfimport \
CppunitTest_sw_odfexport \
@@ -126,6 +128,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
CppunitTest_sw_uibase_dochdl \
CppunitTest_sw_uibase_frmdlg \
CppunitTest_sw_uibase_uno \
+ CppunitTest_sw_uibase_dialog \
CppunitTest_sw_uibase_wrtsh \
CppunitTest_sw_core_accessibilitycheck \
CppunitTest_sw_core_layout \
@@ -142,6 +145,8 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
CppunitTest_sw_core_edit \
CppunitTest_sw_uibase_fldui \
CppunitTest_sw_core_attr \
+ CppunitTest_sw_filter_ww8 \
+ CppunitTest_sw_core_theme \
))
ifneq ($(DISABLE_GUI),TRUE)
@@ -197,6 +202,8 @@ $(eval $(call gb_Module_add_uicheck_targets,sw,\
UITest_sw_styleInspector \
UITest_sw_ui_fmtui \
UITest_sw_ui_index \
+ UITest_sw_uibase_docvw \
+ UITest_sw_ui_misc \
UITest_sw_uibase_shells \
UITest_classification \
UITest_writer_macro_tests \
diff --git a/sw/UIConfig_swriter.mk b/sw/UIConfig_swriter.mk
index 73abd66dee9b..b5fab9613f66 100644
--- a/sw/UIConfig_swriter.mk
+++ b/sw/UIConfig_swriter.mk
@@ -121,6 +121,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/swriter,\
sw/uiconfig/swriter/ui/combobox \
sw/uiconfig/swriter/ui/comboboxfragment \
sw/uiconfig/swriter/ui/conditionpage \
+ sw/uiconfig/swriter/ui/contentcontrolaliasbutton \
sw/uiconfig/swriter/ui/contentcontrolcalendar \
sw/uiconfig/swriter/ui/contentcontroldlg \
sw/uiconfig/swriter/ui/contentcontroldropdown \
@@ -178,6 +179,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/swriter,\
sw/uiconfig/swriter/ui/insertautotextdialog \
sw/uiconfig/swriter/ui/insertbookmark \
sw/uiconfig/swriter/ui/insertbreak \
+ sw/uiconfig/swriter/ui/translationdialog \
sw/uiconfig/swriter/ui/insertcaption \
sw/uiconfig/swriter/ui/insertdbcolumnsdialog \
sw/uiconfig/swriter/ui/insertfootnote \
@@ -241,6 +243,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/swriter,\
sw/uiconfig/swriter/ui/notebookbar_online \
sw/uiconfig/swriter/ui/pagecolumncontrol \
sw/uiconfig/swriter/ui/pagemargincontrol \
+ sw/uiconfig/swriter/ui/pagenumberdlg \
sw/uiconfig/swriter/ui/pageorientationcontrol \
sw/uiconfig/swriter/ui/pagesizecontrol \
sw/uiconfig/swriter/ui/pagestylemenu \
diff --git a/sw/UITest_sw_ui_misc.mk b/sw/UITest_sw_ui_misc.mk
new file mode 100644
index 000000000000..13e8e0d073c2
--- /dev/null
+++ b/sw/UITest_sw_ui_misc.mk
@@ -0,0 +1,16 @@
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_UITest_UITest,sw_ui_misc))
+
+$(eval $(call gb_UITest_add_modules,sw_ui_misc,$(SRCDIR)/sw/qa/uitest,\
+ ui/misc/ \
+))
+
+$(eval $(call gb_UITest_set_defs,sw_ui_misc, \
+ TDOC="$(SRCDIR)/sw/qa/uitest/data" \
+))
diff --git a/sw/UITest_sw_uibase_docvw.mk b/sw/UITest_sw_uibase_docvw.mk
new file mode 100644
index 000000000000..7b07dd8ca8e5
--- /dev/null
+++ b/sw/UITest_sw_uibase_docvw.mk
@@ -0,0 +1,16 @@
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_UITest_UITest,sw_uibase_docvw))
+
+$(eval $(call gb_UITest_add_modules,sw_uibase_docvw,$(SRCDIR)/sw/qa/uitest,\
+ uibase/docvw/ \
+))
+
+$(eval $(call gb_UITest_set_defs,sw_uibase_docvw, \
+ TDOC="$(SRCDIR)/sw/qa/uitest/data" \
+))
diff --git a/sw/inc/AccessibilityCheckStrings.hrc b/sw/inc/AccessibilityCheckStrings.hrc
index 2c098e50edc8..baa61cbcb8ba 100644
--- a/sw/inc/AccessibilityCheckStrings.hrc
+++ b/sw/inc/AccessibilityCheckStrings.hrc
@@ -17,10 +17,17 @@
#define STR_TABLE_MERGE_SPLIT NC_("STR_TABLE_MERGE_SPLIT", "Table '%OBJECT_NAME%' contains merges or splits")
#define STR_FAKE_NUMBERING NC_("STR_FAKE_NUMBERING", "Fake numbering '%NUMBERING%'")
#define STR_HYPERLINK_TEXT_IS_LINK NC_("STR_HYPERLINK_TEXT_IS_LINK", "Hyperlink text is the same as the link address '%LINK%'")
+#define STR_HYPERLINK_TEXT_IS_SHORT NC_("STR_HYPERLINK_TEXT_IS_SHORT", "Hyperlink text is too short.")
#define STR_TEXT_CONTRAST NC_("STR_TEXT_CONTRAST", "Text contrast is too low.")
#define STR_TEXT_BLINKING NC_("STR_TEXT_BLINKING", "Blinking text.")
#define STR_AVOID_FOOTNOTES NC_("STR_AVOID_FOOTNOTES", "Avoid footnotes.")
+#define STR_AVOID_FAKE_FOOTNOTES NC_("STR_AVOID_FAKE_FOOTNOTES", "Avoid fake footnotes.")
+#define STR_AVOID_FAKE_CAPTIONS NC_("STR_AVOID_FAKE_CAPTIONS", "Avoid fake captions.")
#define STR_AVOID_ENDNOTES NC_("STR_AVOID_ENDNOTES", "Avoid endnotes.")
+#define STR_AVOID_BACKGROUND_IMAGES NC_("STR_AVOID_BACKGROUND_IMAGES", "Avoid background images.")
+#define STR_AVOID_NEWLINES_SPACE NC_("STR_AVOID_NEWLINES_SPACE", "Avoid newlines to create space.")
+#define STR_AVOID_SPACES_SPACE NC_("STR_AVOID_SPACES_SPACE", "Avoid spaces to create space.")
+#define STR_AVOID_TABS_FORMATTING NC_("STR_AVOID_TABS_FORMATTING", "Avoid using tabs for formatting.")
#define STR_HEADINGS_NOT_IN_ORDER NC_("STR_HEADINGS_NOT_IN_ORDER", "Headings not in order.")
#define STR_TEXT_FORMATTING_CONVEYS_MEANING NC_("STR_TEXT_FORMATTING_CONVEYS_MEANING", "The text formatting conveys additional meaning.")
#define STR_NON_INTERACTIVE_FORMS NC_("STR_NON_INTERACTIVE_FORMS", "An input form is not interactive.")
@@ -28,6 +35,7 @@
#define STR_HEADING_IN_TABLE NC_("STR_HEADING_IN_TABLE", "Tables must not contain headings.")
#define STR_HEADING_ORDER NC_("STR_HEADING_ORDER", "Keep headings' levels ordered. Heading level %LEVEL_CURRENT% must not go after %LEVEL_PREV%.")
#define STR_FONTWORKS NC_("STR_FONTWORKS", "Avoid Fontwork objects in your documents. Make sure you use it for samples or other meaningless text.")
+#define STR_TABLE_FORMATTING NC_("STR_TABLE_FORMATTING", "Avoid using empty table cells for formatting.")
#define STR_DOCUMENT_DEFAULT_LANGUAGE NC_("STR_DOCUMENT_DEFAULT_LANGUAGE", "Document default language is not set")
#define STR_STYLE_NO_LANGUAGE NC_("STR_STYLE_NO_LANGUAGE", "Style '%STYLE_NAME%' has no language set")
diff --git a/sw/inc/IGrammarContact.hxx b/sw/inc/GrammarContact.hxx
index 68be355807ef..9b47984b9587 100644
--- a/sw/inc/IGrammarContact.hxx
+++ b/sw/inc/GrammarContact.hxx
@@ -20,29 +20,52 @@
#ifndef INCLUDED_SW_INC_IGRAMMARCONTACT_HXX
#define INCLUDED_SW_INC_IGRAMMARCONTACT_HXX
+#include <SwGrammarMarkUp.hxx>
+#include <svl/listener.hxx>
+#include <vcl/timer.hxx>
+
struct SwPosition;
class SwTextNode;
-class SwGrammarMarkUp;
-/** Organizer of the contact between SwTextNodes and grammar checker
-*/
-class IGrammarContact
+namespace sw
{
+/**
+ * This class is responsible for the delayed display of grammar checks when a paragraph is edited
+ * It's a client of the paragraph the cursor points to.
+ * If the cursor position changes, updateCursorPosition has to be called
+ * If the grammar checker wants to set a grammar marker at a paragraph, he has to request
+ * the grammar list from this class. If the requested paragraph is not edited, it returns
+ * the normal grammar list. But if the paragraph is the active one, a proxy list will be returned and
+ * all changes are set in this proxy list. If the cursor leaves the paragraph the proxy list
+ * will replace the old list. If the grammar checker has completed the paragraph ('setChecked')
+ * then a timer is setup which replaces the old list as well.
+ */
+class GrammarContact final : public SvtListener
+{
+ Timer m_aTimer;
+ std::unique_ptr<SwGrammarMarkUp> m_pProxyList;
+ bool m_isFinished;
+ SwTextNode* m_pTextNode;
+ DECL_LINK(TimerRepaint, Timer*, void);
+
public:
+ GrammarContact();
+ ~GrammarContact() { m_aTimer.Stop(); }
+
/** Update cursor position reacts to a change of the current input cursor
As long as the cursor in inside a paragraph, the grammar checking does
not show new grammar faults. When the cursor leaves the paragraph, these
faults are shown.
@returns void
*/
- virtual void updateCursorPosition(const SwPosition& rNewPos) = 0;
+ void updateCursorPosition(const SwPosition& rNewPos);
/** getGrammarCheck checks if the given text node is blocked by the current cursor
if not, the normal markup list is returned
if blocked, it will return a markup list "proxy"
@returns a markup list (grammar) for the given SwTextNode
*/
- virtual SwGrammarMarkUp* getGrammarCheck(SwTextNode& rTextNode, bool bCreate) = 0;
+ SwGrammarMarkUp* getGrammarCheck(SwTextNode& rTextNode, bool bCreate);
/** finishGrammarCheck() has to be called if a grammar checking has been completed
for a text node. If this text node has not been hidden by the current proxy list
@@ -50,28 +73,24 @@ public:
repaint will be triggered by a timer
@returns void
*/
- virtual void finishGrammarCheck(SwTextNode& rTextNode) = 0;
+ void finishGrammarCheck(SwTextNode& rTextNode);
-public:
- virtual ~IGrammarContact() {}
+ void CheckBroadcaster();
};
-/** Factory for a grammar contact
-@returns a new created grammar contact object
-*/
-IGrammarContact* createGrammarContact();
-
/* Helper functions */
/** getGrammarContact() delivers the grammar contact of the document (for a given textnode)
@returns grammar contact
*/
-IGrammarContact* getGrammarContact(const SwTextNode&);
+GrammarContact* getGrammarContactFor(const SwTextNode&);
/** finishGrammarCheck() calls the same function of the grammar contact of the document (for a given textnode)
@returns void
*/
-void finishGrammarCheck(SwTextNode&);
+void finishGrammarCheckFor(SwTextNode&);
+
+} // end sw
#endif // INCLUDED_SW_INC_IGRAMMARCONTACT_HXX
diff --git a/sw/inc/IDocumentMarkAccess.hxx b/sw/inc/IDocumentMarkAccess.hxx
index d7f3bdd6674b..93991cdd1987 100644
--- a/sw/inc/IDocumentMarkAccess.hxx
+++ b/sw/inc/IDocumentMarkAccess.hxx
@@ -314,6 +314,8 @@ class IDocumentMarkAccess
*/
virtual const_iterator_t findFirstBookmarkStartsAfter(const SwPosition& rPos) const =0;
+ /// Get the innermost bookmark that contains rPos.
+ virtual sw::mark::IMark* getBookmarkFor(const SwPosition& rPos) const = 0;
// Fieldmarks
/** returns a STL-like random access iterator to the begin of the sequence of fieldmarks.
@@ -324,11 +326,14 @@ class IDocumentMarkAccess
*/
virtual const_iterator_t getFieldmarksEnd() const =0;
+ /// returns the number of IFieldmarks.
+ virtual sal_Int32 getFieldmarksCount() const = 0;
+
/// get Fieldmark for CH_TXT_ATR_FIELDSTART/CH_TXT_ATR_FIELDEND at rPos
virtual ::sw::mark::IFieldmark* getFieldmarkAt(const SwPosition& rPos) const =0;
virtual ::sw::mark::IFieldmark* getFieldmarkFor(const SwPosition& pos) const =0;
- virtual ::sw::mark::IFieldmark* getFieldmarkBefore(const SwPosition& pos) const =0;
- virtual ::sw::mark::IFieldmark* getFieldmarkAfter(const SwPosition& pos) const =0;
+ virtual sw::mark::IFieldmark* getFieldmarkBefore(const SwPosition& pos, bool bLoop) const =0;
+ virtual sw::mark::IFieldmark* getFieldmarkAfter(const SwPosition& pos, bool bLoop) const =0;
virtual ::sw::mark::IFieldmark* getDropDownFor(const SwPosition& pos) const=0;
virtual std::vector<::sw::mark::IFieldmark*> getNoTextFieldmarksIn(const SwPaM &rPaM) const=0;
diff --git a/sw/inc/IMark.hxx b/sw/inc/IMark.hxx
index 151c9a9333fb..c256c2ef997c 100644
--- a/sw/inc/IMark.hxx
+++ b/sw/inc/IMark.hxx
@@ -102,6 +102,10 @@ namespace sw::mark
virtual void SetFieldname(const OUString& rFieldname) =0;
virtual void SetFieldHelptext(const OUString& rFieldHelptext) =0;
virtual void Invalidate() = 0;
+
+ virtual OUString GetContent() const { return OUString(); }
+ virtual void ReplaceContent(const OUString& /*sNewContent*/) {}
+
private:
IFieldmark(IFieldmark const &) = delete;
IFieldmark &operator =(IFieldmark const&) = delete;
@@ -121,6 +125,25 @@ namespace sw::mark
ICheckboxFieldmark &operator =(ICheckboxFieldmark const&) = delete;
};
+ class SW_DLLPUBLIC IDropdownFieldmark
+ : virtual public IFieldmark
+ {
+ protected:
+ IDropdownFieldmark() = default;
+
+ public:
+ virtual OUString GetContent(sal_Int32* pIndex) const = 0;
+ virtual OUString GetContent() const override = 0;
+ virtual void AddContent(const OUString& rText, sal_Int32* pIndex = nullptr) = 0;
+ virtual void DelContent(sal_Int32 nDelIndex = -1) = 0;
+ virtual void ReplaceContent(const OUString* pText, sal_Int32* pIndex) = 0;
+ virtual void ReplaceContent(const OUString& sNewContent) override = 0;
+
+ private:
+ IDropdownFieldmark(IDropdownFieldmark const &) = delete;
+ IDropdownFieldmark &operator =(IDropdownFieldmark const&) = delete;
+ };
+
class SW_DLLPUBLIC IDateFieldmark
: virtual public IFieldmark
{
@@ -128,8 +151,8 @@ namespace sw::mark
IDateFieldmark() = default;
public:
- virtual OUString GetContent() const = 0;
- virtual void ReplaceContent(const OUString& sNewContent) = 0;
+ virtual OUString GetContent() const override = 0;
+ virtual void ReplaceContent(const OUString& sNewContent) override = 0;
virtual std::pair<bool, double> GetCurrentDate() const = 0;
virtual void SetCurrentDate(double fDate) = 0;
diff --git a/sw/inc/OnlineAccessibilityCheck.hxx b/sw/inc/OnlineAccessibilityCheck.hxx
new file mode 100644
index 000000000000..8f52b73f35bd
--- /dev/null
+++ b/sw/inc/OnlineAccessibilityCheck.hxx
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#pragma once
+
+#include "ndindex.hxx"
+#include "ndtxt.hxx"
+#include <svl/listener.hxx>
+#include <vcl/timer.hxx>
+#include <AccessibilityCheck.hxx>
+#include <map>
+
+struct SwPosition;
+class SwTextNode;
+
+namespace sw
+{
+/// Contains the node and tracks if the node gets deleted.
+/// Note: the node needs to extend sw::BroadcastingModify.
+class WeakNodeContainer : public SvtListener
+{
+private:
+ SwNode* m_pNode;
+
+public:
+ WeakNodeContainer(SwNode* pNode);
+ ~WeakNodeContainer();
+
+ /// Is the node still alive or it was deleted?
+ bool isAlive();
+
+ /// Returns the pointer of the node or nullptr if the node
+ /// got deleted.
+ SwNode* getNode();
+};
+
+class OnlineAccessibilityCheck : public SvtListener
+{
+private:
+ std::map<SwNode*, std::unique_ptr<WeakNodeContainer>> m_aNodes;
+
+ SwDoc& m_rDocument;
+ sw::AccessibilityCheck m_aAccessibilityCheck;
+ SwNode* m_pPreviousNode;
+ SwNodeOffset m_nPreviousNodeIndex;
+ sal_Int32 m_nAccessibilityIssues;
+ bool m_bInitialCheck;
+ bool m_bOnlineCheckStatus;
+ std::unique_ptr<sfx::AccessibilityIssueCollection> m_pDocumentAccessibilityIssues;
+
+ void runAccessibilityCheck(SwNode* pNode);
+ void updateStatusbar();
+ void updateNodeStatus(SwNode* pContentNode);
+ void initialCheck();
+ void lookForPreviousNodeAndUpdate(SwPosition const& rNewPos);
+ void clearAccessibilityIssuesFromAllNodes();
+ void runDocumentLevelAccessibilityCheck();
+
+public:
+ OnlineAccessibilityCheck(SwDoc& rDocument);
+ void update(SwPosition const& rNewPos);
+ void resetAndQueue(SwNode* pNode);
+ void updateCheckerActivity();
+ sal_Int32 getNumberOfAccessibilityIssues() { return m_nAccessibilityIssues; }
+};
+
+} // end sw
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/inc/bitmaps.hlst b/sw/inc/bitmaps.hlst
index 2e52f1e47352..b0acb7420db9 100644
--- a/sw/inc/bitmaps.hlst
+++ b/sw/inc/bitmaps.hlst
@@ -111,6 +111,10 @@
#define RID_BMP_PREVIEW_FALLBACK "sw/res/image-example.png"
+#define RID_BMP_A11Y_CHECK_ISSUES_NOT_FOUND "svx/res/a11y_check_issues_not_found.png"
+#define RID_BMP_A11Y_CHECK_ISSUES_FOUND "svx/res/a11y_check_issues_found.png"
+
#endif
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/sw/inc/charfmt.hxx b/sw/inc/charfmt.hxx
index e08d2f5f3a3f..84571d26263a 100644
--- a/sw/inc/charfmt.hxx
+++ b/sw/inc/charfmt.hxx
@@ -36,10 +36,11 @@ class SW_DLLPUBLIC SwCharFormat final : public SwFormat
{}
public:
+ ~SwCharFormat();
void dumpAsXml(xmlTextWriterPtr pWriter) const;
- void SetLinkedParaFormat(SwTextFormatColl& rLink);
+ void SetLinkedParaFormat(SwTextFormatColl* pLink);
const SwTextFormatColl* GetLinkedParaFormat() const;
};
diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h
index e9f961c605b1..483abfaf6400 100644
--- a/sw/inc/cmdid.h
+++ b/sw/inc/cmdid.h
@@ -194,6 +194,7 @@
// Region: Insert
#define FN_INSERT_BOOKMARK (FN_INSERT + 2 ) /* Bookmark */
+// FN_INSERT + 3 is FN_INSERT_BREAK
#define FN_INSERT_BREAK_DLG (FN_INSERT + 4 ) /* Break */
#define FN_INSERT_COLUMN_BREAK (FN_INSERT + 5 ) /* Column break */
@@ -218,9 +219,11 @@
#define FN_CONTENT_CONTROL_PROPERTIES (FN_INSERT + 25) /* Content control properties */
#define FN_INSERT_PICTURE_CONTENT_CONTROL (FN_INSERT + 26) /* Picture content control */
#define FN_INSERT_DATE_CONTENT_CONTROL (FN_INSERT + 27) /* Date content control */
+#define FN_INSERT_PLAIN_TEXT_CONTENT_CONTROL (FN_INSERT + 28) /* Plain text content control */
#define FN_POSTIT (FN_INSERT + 29) /* Insert/edit PostIt */
#define FN_INSERT_TABLE (FN_INSERT + 30) /* Insert Table */
#define FN_INSERT_STRING (FN_INSERT+31)
+#define FN_INSERT_COMBO_BOX_CONTENT_CONTROL (FN_INSERT + 32) /* Combo box content control */
#define FN_INSERT_FRAME_INTERACT (FN_INSERT + 33) /* Insert interactive frame */
#define FN_INSERT_FRAME (FN_INSERT + 34) /* Insert Frame */
@@ -230,6 +233,7 @@
#define FN_TOOL_ANCHOR_PAGE (FN_INSERT + 50) /* anchor Draw object to page */
#define FN_TOOL_ANCHOR_PARAGRAPH (FN_INSERT + 51) /* anchor Draw object to paragraph */
#define FN_TOOL_HIERARCHIE (FN_INSERT + 52) /* change hierarchy */
+#define FN_PGNUMBER_WIZARD (FN_INSERT + 53) /* page number wizard */
#define FN_MAILMERGE_WIZARD (FN_INSERT + 64) /* mail merge wizard */
#define FN_TOOL_ANCHOR_FRAME (FN_INSERT + 66) /* anchor Draw-Object to frame*/
@@ -300,10 +304,21 @@
#define FN_PROTECT_FIELDS (FN_INSERT2 + 26)
#define FN_PROTECT_BOOKMARKS (FN_INSERT2 + 27)
+#define FN_UPDATE_TEXT_FORMFIELDS (FN_INSERT2 + 28)
+#define FN_UPDATE_TEXT_FORMFIELD (FN_INSERT2 + 29)
+
// clipboard table content
#define FN_PASTE_NESTED_TABLE (FN_INSERT2 + 30) /* instead of the cell-by-cell copy between source and target tables */
#define FN_TABLE_PASTE_ROW_BEFORE (FN_INSERT2 + 31) /* paste table as new table rows */
#define FN_TABLE_PASTE_COL_BEFORE (FN_INSERT2 + 32) /* paste table as new table columns */
+#define FN_UPDATE_BOOKMARKS (FN_INSERT2 + 34)
+#define FN_UPDATE_SECTIONS (FN_INSERT2 + 35)
+#define FN_DELETE_TEXT_FORMFIELDS (FN_INSERT2 + 36)
+#define FN_UPDATE_BOOKMARK (FN_INSERT2 + 37)
+#define FN_UPDATE_FIELD (FN_INSERT2 + 38)
+#define FN_DELETE_BOOKMARKS (FN_INSERT2 + 39)
+#define FN_DELETE_FIELDS (FN_INSERT2 + 40)
+#define FN_DELETE_SECTIONS (FN_INSERT2 + 41)
// Region: Format
#define FN_AUTOFORMAT_APPLY (FN_FORMAT + 1 ) /* apply autoformat options */
@@ -844,6 +859,7 @@
#define FN_STAT_SELMODE (FN_STAT + 5)
#define FN_STAT_BOOKMARK (FN_STAT + 8) /* For Popup Bookmarks*/
#define FN_STAT_WORDCOUNT (FN_STAT + 9)
+#define FN_STAT_ACCESSIBILITY_CHECK (FN_STAT + 10)
// Region: Page preview
#define FN_SHOW_TWO_PAGES (FN_PGPREVIEW + 1)
diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx
index 2dd27529810a..431cdd503ab3 100644
--- a/sw/inc/crsrsh.hxx
+++ b/sw/inc/crsrsh.hxx
@@ -45,6 +45,7 @@
class SfxItemSet;
class SfxPoolItem;
+class SwCallLink;
class SwContentFrame;
class SwUnoCursor;
class SwFormatField;
@@ -59,6 +60,7 @@ class SwBlockCursor;
class SwPostItField;
class SwTextField;
class SwTextFootnote;
+class SwTextContentControl;
namespace i18nutil {
struct SearchOptions2;
@@ -435,6 +437,7 @@ public:
* stack
* @return <true> if there was one on the stack, <false> otherwise
*/
+ bool Pop(PopMode, ::std::unique_ptr<SwCallLink> pLink);
bool Pop(PopMode);
/*
* Combine 2 Cursors.
@@ -568,8 +571,8 @@ public:
bool IsFormProtected();
::sw::mark::IFieldmark* GetCurrentFieldmark();
- ::sw::mark::IFieldmark* GetFieldmarkAfter();
- ::sw::mark::IFieldmark* GetFieldmarkBefore();
+ sw::mark::IFieldmark* GetFieldmarkAfter(bool bLoop);
+ sw::mark::IFieldmark* GetFieldmarkBefore(bool bLoop);
bool GotoFieldmark( const ::sw::mark::IFieldmark* const pMark );
// update Cursr, i.e. reset it into content should only be called when the
@@ -706,6 +709,8 @@ public:
bool GotoFormatContentControl(const SwFormatContentControl& rContentControl);
+ void GotoFormControl(bool bNext);
+
static SwTextField* GetTextFieldAtPos(
const SwPosition* pPos,
const bool bIncludeInputFieldAtStart );
@@ -717,7 +722,7 @@ public:
const bool bIncludeInputFieldAtStart );
SwField* GetCurField( const bool bIncludeInputFieldAtStart = false ) const;
bool CursorInsideInputField() const;
- bool CursorInsideContentControl() const;
+ SwTextContentControl* CursorInsideContentControl() const;
static bool PosInsideInputField( const SwPosition& rPos );
bool DocPtInsideInputField( const Point& rDocPt ) const;
static sal_Int32 StartOfInputFieldAtPos( const SwPosition& rPos );
diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index f7749190e3ea..3abf8e4e9536 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -113,7 +113,6 @@ struct SwSortOptions;
struct SwDefTOXBase_Impl;
class SwPrintUIOptions;
struct SwConversionArgs;
-class IGrammarContact;
class SwRenderData;
class IDocumentUndoRedo;
class IDocumentSettingAccess;
@@ -135,6 +134,7 @@ class IDocumentExternalData;
class IDocumentMarkAccess;
class SetGetExpFields;
struct SwInsertTableOptions;
+class SwContentControlManager;
enum class SvMacroItemId : sal_uInt16;
enum class SvxFrameDirection;
enum class RndStdIds;
@@ -163,6 +163,8 @@ namespace sw {
class DocumentLayoutManager;
class DocumentStylePoolManager;
class DocumentExternalDataManager;
+ class GrammarContact;
+ class OnlineAccessibilityCheck;
}
namespace com::sun::star {
@@ -210,6 +212,7 @@ class SW_DLLPUBLIC SwDoc final
const std::unique_ptr< ::sw::mark::MarkManager> mpMarkManager;
const std::unique_ptr< ::sw::MetaFieldManager > m_pMetaFieldManager;
+ const std::unique_ptr< ::SwContentControlManager > m_pContentControlManager;
const std::unique_ptr< ::sw::DocumentDrawModelManager > m_pDocumentDrawModelManager;
const std::unique_ptr< ::sw::DocumentRedlineManager > m_pDocumentRedlineManager;
const std::unique_ptr< ::sw::DocumentStateManager > m_pDocumentStateManager;
@@ -279,7 +282,8 @@ class SW_DLLPUBLIC SwDoc final
std::unique_ptr<SwLayoutCache> mpLayoutCache; /**< Layout cache to read and save with the
document for a faster formatting */
- std::unique_ptr<IGrammarContact> mpGrammarContact; //< for grammar checking in paragraphs during editing
+ std::unique_ptr<sw::GrammarContact> mpGrammarContact; //< for grammar checking in paragraphs during editing
+ std::unique_ptr<sw::OnlineAccessibilityCheck> mpOnlineAccessibilityCheck;
css::uno::Reference< css::script::vba::XVBAEventProcessor > mxVbaEvents;
css::uno::Reference<css::container::XNameContainer> m_xTemplateToProjectCache;
@@ -1305,6 +1309,8 @@ public:
If array pointer is 0 return only whether a RefMark is set in document. */
sal_uInt16 GetRefMarks( std::vector<OUString>* = nullptr ) const;
+ void DeleteFormatRefMark(const SwFormatRefMark* pFormatRefMark);
+
// Insert label. If a FlyFormat is created, return it.
SwFlyFrameFormat* InsertLabel( const SwLabelType eType, const OUString &rText, const OUString& rSeparator,
const OUString& rNumberingSeparator,
@@ -1554,7 +1560,11 @@ public:
*/
bool ContainsHiddenChars() const;
- IGrammarContact* getGrammarContact() const { return mpGrammarContact.get(); }
+ std::unique_ptr<sw::GrammarContact> const& getGrammarContact() const { return mpGrammarContact; }
+ std::unique_ptr<sw::OnlineAccessibilityCheck> const& getOnlineAccessibilityCheck() const
+ {
+ return mpOnlineAccessibilityCheck;
+ }
/** Marks/Unmarks a list level of a certain list
@@ -1625,6 +1635,7 @@ public:
const css::uno::Reference< css::container::XNameContainer >& GetVBATemplateToProjectCache() const { return m_xTemplateToProjectCache; };
::sfx2::IXmlIdRegistry& GetXmlIdRegistry();
::sw::MetaFieldManager & GetMetaFieldManager();
+ ::SwContentControlManager& GetContentControlManager();
::sw::UndoManager & GetUndoManager();
::sw::UndoManager const& GetUndoManager() const;
diff --git a/sw/inc/fldbas.hxx b/sw/inc/fldbas.hxx
index 0251ba1f9a23..37e3d871ca0e 100644
--- a/sw/inc/fldbas.hxx
+++ b/sw/inc/fldbas.hxx
@@ -234,6 +234,7 @@ enum SwDateTimeSubType {
/// General tools.
OUString FormatNumber(sal_uInt32 nNum, SvxNumType nFormat, LanguageType nLang = LANGUAGE_NONE);
+SwFieldTypesEnum SwFieldTypeFromString(std::u16string_view rString);
/** Instances of SwFields and those derived from it occur 0 to n times.
For each class there is one instance of the associated type class.
diff --git a/sw/inc/fmtcol.hxx b/sw/inc/fmtcol.hxx
index 1b1bd7d2e46d..be547df3d840 100644
--- a/sw/inc/fmtcol.hxx
+++ b/sw/inc/fmtcol.hxx
@@ -103,7 +103,7 @@ public:
inline void SetNextTextFormatColl(SwTextFormatColl& rNext);
SwTextFormatColl& GetNextTextFormatColl() const { return *mpNextTextFormatColl; }
- void SetLinkedCharFormat(SwCharFormat& rLink);
+ void SetLinkedCharFormat(SwCharFormat* pLink);
const SwCharFormat* GetLinkedCharFormat() const;
diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx
index 3bb9f6d64489..f65b67d37cc4 100644
--- a/sw/inc/formatcontentcontrol.hxx
+++ b/sw/inc/formatcontentcontrol.hxx
@@ -28,6 +28,10 @@
#include "calbck.hxx"
#include "swdllapi.h"
+namespace vcl
+{
+class KeyCode;
+}
class SwContentControl;
class SwTextContentControl;
class SwTextNode;
@@ -40,6 +44,8 @@ enum class SwContentControlType
DROP_DOWN_LIST,
PICTURE,
DATE,
+ PLAIN_TEXT,
+ COMBO_BOX,
};
/// SfxPoolItem subclass that wraps an SwContentControl.
@@ -70,6 +76,7 @@ public:
* (re-)moved.
*/
void NotifyChangeTextNode(SwTextNode* pTextNode);
+ SwTextNode* GetTextNode() const;
static SwFormatContentControl* CreatePoolDefault(sal_uInt16 nWhich);
std::shared_ptr<SwContentControl> GetContentControl() { return m_pContentControl; }
const std::shared_ptr<SwContentControl>& GetContentControl() const { return m_pContentControl; }
@@ -138,6 +145,15 @@ class SW_DLLPUBLIC SwContentControl : public sw::BroadcastingModify
/// Date in YYYY-MM-DDT00:00:00Z format.
OUString m_aCurrentDate;
+ /// Plain text, i.e. not rich text.
+ bool m_bPlainText = false;
+
+ /// Same as drop-down, but free-form input is also accepted.
+ bool m_bComboBox = false;
+
+ /// Same as combo box, but free-form input is not accepted.
+ bool m_bDropDown = false;
+
/// The placeholder's doc part: just remembered.
OUString m_aPlaceholderDocPart;
@@ -153,10 +169,30 @@ class SW_DLLPUBLIC SwContentControl : public sw::BroadcastingModify
/// The color: just remembered.
OUString m_aColor;
+ /// The appearance: just remembered.
+ OUString m_aAppearance;
+
+ /// The alias: just remembered.
+ OUString m_aAlias;
+
+ /// The tag: just remembered.
+ OUString m_aTag;
+
+ /// The id: just remembered.
+ sal_Int32 m_nId = 0;
+
+ /// The tabIndex: just remembered.
+ sal_uInt32 m_nTabIndex = 0;
+
+ /// The control and content locks: mostly just remembered.
+ OUString m_aLock;
+
/// Stores a list item index, in case the doc model is not yet updated.
+ // i.e. temporarily store the selected item until the text is inserted by GotoContentControl.
std::optional<size_t> m_oSelectedListItem;
/// Stores a date timestamp, in case the doc model is not yet updated.
+ // i.e. temporarily store the date until the text is inserted by GotoContentControl.
std::optional<double> m_oSelectedDate;
/**
@@ -217,13 +253,15 @@ public:
std::vector<SwContentControlListItem> GetListItems() const { return m_aListItems; }
- bool HasListItems() const { return !m_aListItems.empty(); }
-
void SetListItems(const std::vector<SwContentControlListItem>& rListItems)
{
m_aListItems = rListItems;
}
+ bool AddListItem(size_t nZIndex, const OUString& rDisplayText, const OUString& rValue);
+ void DeleteListItem(size_t nZIndex);
+ void ClearListItems();
+
void SetPicture(bool bPicture) { m_bPicture = bPicture; }
bool GetPicture() const { return m_bPicture; }
@@ -253,6 +291,18 @@ public:
/// Formats m_oSelectedDate, taking m_aDateFormat and m_aDateLanguage into account.
OUString GetDateString() const;
+ void SetPlainText(bool bPlainText) { m_bPlainText = bPlainText; }
+
+ bool GetPlainText() const { return m_bPlainText; }
+
+ void SetComboBox(bool bComboBox) { m_bComboBox = bComboBox; }
+
+ bool GetComboBox() const { return m_bComboBox; }
+
+ void SetDropDown(bool bDropDown) { m_bDropDown = bDropDown; }
+
+ bool GetDropDown() const { return m_bDropDown; }
+
void SetPlaceholderDocPart(const OUString& rPlaceholderDocPart)
{
m_aPlaceholderDocPart = rPlaceholderDocPart;
@@ -267,10 +317,20 @@ public:
std::optional<size_t> GetSelectedListItem() const { return m_oSelectedListItem; }
+ /// Get a copy of selected list item's index,
+ /// potentially even if the selection is already written out to text (i.e. validated).
+ std::optional<size_t> GetSelectedListItem(bool bCheckDocModel) const;
+
void SetSelectedDate(std::optional<double> oSelectedDate) { m_oSelectedDate = oSelectedDate; }
std::optional<double> GetSelectedDate() const { return m_oSelectedDate; }
+ /// Should this character (during key input) interact with the content control?
+ bool IsInteractingCharacter(sal_Unicode cCh);
+
+ /// Given rKeyCode as a keyboard event, should a popup be opened for this content control?
+ bool ShouldOpenPopup(const vcl::KeyCode& rKeyCode);
+
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
void SetDataBindingPrefixMappings(const OUString& rDataBindingPrefixMappings)
@@ -298,9 +358,40 @@ public:
OUString GetColor() const { return m_aColor; }
+ void SetAppearance(const OUString& rAppearance) { m_aAppearance = rAppearance; }
+
+ const OUString& GetAppearance() const { return m_aAppearance; }
+
+ void SetAlias(const OUString& rAlias) { m_aAlias = rAlias; }
+
+ const OUString& GetAlias() const { return m_aAlias; }
+
+ void SetTag(const OUString& rTag) { m_aTag = rTag; }
+
+ const OUString& GetTag() const { return m_aTag; }
+
+ void SetId(sal_Int32 nId) { m_nId = nId; }
+
+ sal_Int32 GetId() const { return m_nId; }
+
+ void SetTabIndex(sal_uInt32 nTabIndex) { m_nTabIndex = nTabIndex; }
+
+ sal_uInt32 GetTabIndex() const { return m_nTabIndex; }
+
+ // At the design level, define how the control should be locked. No effect at implementation lvl
+ void SetLock(bool bLockContent, bool bLockControl);
+ void SetLock(const OUString& rLock) { m_aLock = rLock; }
+
+ // At the design level, get how the control is locked. Does not reflect actual implementation.
+ std::optional<bool> GetLock(bool bControl) const;
+ const OUString& GetLock() const { return m_aLock; }
+
void SetReadWrite(bool bReadWrite) { m_bReadWrite = bReadWrite; }
+ // At the implementation level, define whether the user can directly modify the contents.
bool GetReadWrite() const { return m_bReadWrite; }
+
+ SwContentControlType GetType() const;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/inc/ndole.hxx b/sw/inc/ndole.hxx
index 302c9a0a5ebe..15e79f691e64 100644
--- a/sw/inc/ndole.hxx
+++ b/sw/inc/ndole.hxx
@@ -28,7 +28,7 @@ class SwGrfFormatColl;
class SwDoc;
class SwOLENode;
class SwOLEListener_Impl;
-class SwEmbedObjectLink;
+namespace sfx2 { class SvBaseLink; }
class DeflateData;
class SW_DLLPUBLIC SwOLEObj
@@ -93,7 +93,7 @@ class SW_DLLPUBLIC SwOLENode final: public SwNoTextNode
bool mbOLESizeInvalid; /**< Should be considered at SwDoc::PrtOLENotify
(e.g. copied). Is not persistent. */
- SwEmbedObjectLink* mpObjectLink;
+ sfx2::SvBaseLink* mpObjectLink;
OUString maLinkURL;
SwOLENode( const SwNodeIndex &rWhere,
diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 9e83ded061f6..1ed4cff26f7c 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -59,7 +59,6 @@ class SwInterHyphInfo;
class SwWrongList;
class SwGrammarMarkUp;
struct SwDocStat;
-struct SwParaIdleData_Impl;
enum class ExpandMode;
enum class SwFieldIds : sal_uInt16;
class SwField;
@@ -75,6 +74,29 @@ namespace com::sun::star {
typedef o3tl::sorted_vector< sal_Int32 > SwSoftPageBreakList;
+namespace sw
+{
+
+enum class WrongState { TODO, PENDING, DONE };
+
+struct ParagraphIdleData
+{
+ std::unique_ptr<SwWrongList> pWrong; // for spell checking
+ std::unique_ptr<SwGrammarMarkUp> pGrammarCheck; // for grammar checking / proof reading
+ std::unique_ptr<SwWrongList> pSmartTags;
+ sal_uLong nNumberOfWords = 0;
+ sal_uLong nNumberOfAsianWords = 0;
+ sal_uLong nNumberOfChars = 0;
+ sal_uLong nNumberOfCharsExcludingSpaces = 0;
+ bool bWordCountDirty = true;
+ WrongState eWrongDirty = WrongState::TODO; ///< online spell checking needed/done?
+ bool bGrammarCheckDirty = true;
+ bool bSmartTagDirty = true;
+ bool bAutoComplDirty = true; ///< auto complete list dirty
+};
+
+} // end namespace sw
+
/// SwTextNode is a paragraph in the document model.
class SW_DLLPUBLIC SwTextNode final
: public SwContentNode
@@ -97,7 +119,7 @@ class SW_DLLPUBLIC SwTextNode final
OUString m_Text;
- SwParaIdleData_Impl* m_pParaIdleData_Impl;
+ mutable sw::ParagraphIdleData m_aParagraphIdleData;
/** Some of the chars this para are hidden. Paragraph has to be reformatted
on changing the view to print preview. */
@@ -164,10 +186,6 @@ class SW_DLLPUBLIC SwTextNode final
LanguageType nLang, sal_uInt16 nLangWhichId,
const vcl::Font *pFont, sal_uInt16 nFontWhichId );
- /// Start: Data collected during idle time
-
- SAL_DLLPRIVATE void InitSwParaStatistics( bool bNew );
-
inline void TryDeleteSwpHints();
SAL_DLLPRIVATE void impl_FormatToTextAttr(const SfxItemSet& i_rAttrSet);
@@ -177,16 +195,14 @@ class SW_DLLPUBLIC SwTextNode final
void DelFrames_TextNodePart();
public:
- enum class WrongState { TODO, PENDING, DONE };
-
bool IsWordCountDirty() const;
- WrongState GetWrongDirty() const;
+ sw::WrongState GetWrongDirty() const;
bool IsWrongDirty() const;
bool IsGrammarCheckDirty() const;
bool IsSmartTagDirty() const;
bool IsAutoCompleteWordDirty() const;
void SetWordCountDirty( bool bNew ) const;
- void SetWrongDirty(WrongState eNew) const;
+ void SetWrongDirty(sw::WrongState eNew) const;
void SetGrammarCheckDirty( bool bNew ) const;
void SetSmartTagDirty( bool bNew ) const;
void SetAutoCompleteWordDirty( bool bNew ) const;
@@ -209,7 +225,6 @@ public:
/// End: Data collected during idle time
-
public:
using SwContentNode::GetAttr;
/// for hanging TextFormatCollections somewhere else (Outline-Numbering!)
diff --git a/sw/inc/node.hxx b/sw/inc/node.hxx
index bdcc9c801a49..a3b9e13ad52d 100644
--- a/sw/inc/node.hxx
+++ b/sw/inc/node.hxx
@@ -30,6 +30,8 @@
#include "fmtcol.hxx"
#include "nodeoffset.hxx"
+#include <sfx2/AccessibilityIssue.hxx>
+
#include <memory>
#include <vector>
@@ -77,6 +79,18 @@ namespace drawinglayer::attribute {
typedef std::shared_ptr< SdrAllFillAttributesHelper > SdrAllFillAttributesHelperPtr;
}
+// Accessibiity check
+
+namespace sw
+{
+struct AccessibilityCheckStatus
+{
+ std::unique_ptr<sfx::AccessibilityIssueCollection> pCollection;
+ void reset();
+};
+
+}
+
/// Base class of the Writer document model elements.
class SW_DLLPUBLIC SwNode
: public sw::BorderCacheOwner, private BigPtrEntry
@@ -89,6 +103,8 @@ class SW_DLLPUBLIC SwNode
sal_uInt8 m_nAFormatNumLvl : 3;
bool m_bIgnoreDontExpand : 1; ///< for Text Attributes - ignore the flag
+ mutable sw::AccessibilityCheckStatus m_aAccessibilityCheckStatus;
+
public:
/// sw_redlinehide: redline node merge state
enum class Merge { None, First, NonFirst, Hidden };
@@ -304,6 +320,13 @@ public:
*/
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
+ sw::AccessibilityCheckStatus& getAccessibilityCheckStatus()
+ {
+ return m_aAccessibilityCheckStatus;
+ }
+
+ void resetAndQueueAccessibilityCheck();
+
private:
SwNode( const SwNode & rNodes ) = delete;
SwNode & operator= ( const SwNode & rNodes ) = delete;
diff --git a/sw/inc/pam.hxx b/sw/inc/pam.hxx
index 7c45c59740d1..312ef2b07f6f 100644
--- a/sw/inc/pam.hxx
+++ b/sw/inc/pam.hxx
@@ -57,6 +57,9 @@ struct SAL_WARN_UNUSED SW_DLLPUBLIC SwPosition
bool operator ==(const SwPosition &) const;
bool operator !=(const SwPosition &) const;
void dumpAsXml(xmlTextWriterPtr pWriter) const;
+
+ SwNodeOffset GetNodeIndex() const { return nNode.GetIndex(); }
+ SwNode& GetNode() const { return nNode.GetNode(); }
};
SW_DLLPUBLIC std::ostream &operator <<(std::ostream& s, const SwPosition& position);
diff --git a/sw/inc/strings.hrc b/sw/inc/strings.hrc
index 25d518d58def..45d448f373e9 100644
--- a/sw/inc/strings.hrc
+++ b/sw/inc/strings.hrc
@@ -299,6 +299,7 @@
#define STR_DELETE_NOTE_AUTHOR NC_("STR_DELETE_NOTE_AUTHOR", "Delete ~All Comments by $1")
#define STR_HIDE_NOTE_AUTHOR NC_("STR_HIDE_NOTE_AUTHOR", "H~ide All Comments by $1")
#define STR_OUTLINE_NUMBERING NC_("STR_OUTLINE_NUMBERING", "Chapter Numbering")
+#define STR_STATSTR_SWTRANSLATE NC_("STR_STATSTR_SWTRANSLATE", "Translating document...")
/* To translators: $1 == will be replaced by STR_WORDCOUNT_WORDARG, and $2 by STR_WORDCOUNT_COLARG
e.g. Selected: 1 word, 2 characters */
#define STR_WORDCOUNT NC_("STR_WORDCOUNT", "Selected: $1, $2")
@@ -330,6 +331,7 @@
#define STR_SOUTH NC_("STR_SOUTH", "South")
#define STR_SUM NC_("STR_SUM", "Sum")
#define STR_INVALID_AUTOFORMAT_NAME NC_("STR_INVALID_AUTOFORMAT_NAME", "You have entered an invalid name.\nThe desired AutoFormat could not be created. \nTry again using a different name.")
+#define STR_CANT_SAVE_MACROS NC_("STR_CANT_SAVE_MACROS", "This document has macros, but macros will not be saved in this file format.")
#define STR_NUMERIC NC_("STR_NUMERIC", "Numeric")
#define STR_ROW NC_("STR_ROW", "Rows")
#define STR_COL NC_("STR_COL", "Column")
@@ -581,6 +583,7 @@
#define STR_UNDO_TBLSTYLE_UPDATE NC_("STR_UNDO_TBLSTYLE_UPDATE", "Update table style: $1")
#define STR_UNDO_TABLE_DELETE NC_("STR_UNDO_TABLE_DELETE", "Delete table")
#define STR_UNDO_INSERT_FORM_FIELD NC_("STR_UNDO_INSERT_FORM_FIELD", "Insert form field")
+#define STR_UNDO_INSERT_PAGE_NUMBER NC_("STR_UNDO_INSERT_PAGE_NUMBER", "Insert page number")
#define STR_DROP_DOWN_FIELD_ITEM_LIMIT NC_("STR_DROP_DOWN_FIELD_ITEM_LIMIT", "You can specify maximum of 25 items for a drop-down form field.")
#define STR_ACCESS_DOC_NAME NC_("STR_ACCESS_DOC_NAME", "Document view")
@@ -1086,6 +1089,7 @@
#define STR_BOOKCTRL_HINT NC_("STR_BOOKCTRL_HINT", "Page number in document. Click to open Go to Page dialog or right-click for bookmark list.")
#define STR_BOOKCTRL_HINT_EXTENDED NC_("STR_BOOKCTRL_HINT_EXTENDED", "Page number in document (Page number on printed document). Click to open Go to Page dialog.")
#define STR_TMPLCTRL_HINT NC_("STR_TMPLCTRL_HINT", "Page Style. Right-click to change style or click to open Style dialog.")
+#define STR_ACCESSIBILITY_CHECK_HINT NC_("STR_ACCESSIBILITY_CHECK_HINT", "Status of the accessibility check.\nNumber of issues found: %issues%.")
// Strings for textual attributes.
#define STR_DROP_OVER NC_("STR_DROP_OVER", "Drop Caps over")
diff --git a/sw/inc/swabstdlg.hxx b/sw/inc/swabstdlg.hxx
index 0963de35da21..adcc12012654 100644
--- a/sw/inc/swabstdlg.hxx
+++ b/sw/inc/swabstdlg.hxx
@@ -229,6 +229,16 @@ public:
};
+/// Interface for the insert -> fields -> page number wizard dialog
+class AbstractSwPageNumberDlg : public VclAbstractDialog
+{
+protected:
+ virtual ~AbstractSwPageNumberDlg() override = default;
+public:
+ virtual int GetPageNumberPosition() const = 0;
+ virtual int GetPageNumberAlignment() const = 0;
+};
+
class AbstractSwBreakDlg
{
protected:
@@ -375,6 +385,18 @@ public:
virtual sal_uInt16 GetRestartPage() const = 0;
};
+class SwLanguageListItem;
+
+class AbstractSwTranslateLangSelectDlg
+{
+protected:
+ virtual ~AbstractSwTranslateLangSelectDlg() = default;
+public:
+ virtual std::shared_ptr<weld::DialogController> getDialogController() = 0;
+ virtual std::optional<SwLanguageListItem> GetSelectedLanguage() = 0;
+};
+
+
class SwAbstractDialogFactory
{
public:
@@ -398,6 +420,7 @@ public:
CreateSwContentControlListItemDlg(weld::Window* pParent, SwContentControlListItem& rItem) = 0;
virtual std::shared_ptr<AbstractSwBreakDlg> CreateSwBreakDlg(weld::Window *pParent, SwWrtShell &rSh) = 0;
+ virtual std::shared_ptr<AbstractSwTranslateLangSelectDlg> CreateSwTranslateLangSelectDlg(weld::Window *pParent, SwWrtShell &rSh) = 0;
virtual VclPtr<VclAbstractDialog> CreateSwChangeDBDlg(SwView& rVw) = 0;
virtual VclPtr<SfxAbstractTabDialog> CreateSwCharDlg(weld::Window* pParent, SwView& pVw, const SfxItemSet& rCoreSet,
SwCharDlgMode nDialogMode, const OUString* pFormatStr = nullptr) = 0;
@@ -454,6 +477,7 @@ public:
css::uno::Reference< css::container::XNamed > & xNamed,
css::uno::Reference< css::container::XNameAccess > & xNameAccess) = 0;
virtual VclPtr<AbstractSwModalRedlineAcceptDlg> CreateSwModalRedlineAcceptDlg(weld::Window *pParent) = 0;
+ virtual VclPtr<AbstractSwPageNumberDlg> CreateSwPageNumberDlg(weld::Window* pParent) = 0;
virtual VclPtr<VclAbstractDialog> CreateTableMergeDialog(weld::Window* pParent, bool& rWithPrev) = 0;
virtual VclPtr<SfxAbstractTabDialog> CreateFrameTabDialog(const OUString &rDialogType,
diff --git a/sw/inc/swtypes.hxx b/sw/inc/swtypes.hxx
index 64ac704d6ff6..02bd3704f773 100644
--- a/sw/inc/swtypes.hxx
+++ b/sw/inc/swtypes.hxx
@@ -144,17 +144,19 @@ enum class SetAttrMode
NOHINTADJUST = 0x0008, // No merging of ranges.
NOFORMATATTR = 0x0010, // Do not change into format attribute.
APICALL = 0x0020, // Called from API (all UI related
- // functionality will be disabled).
+ // functionality will be disabled).
/// Force hint expand (only matters for hints with CH_TXTATR).
FORCEHINTEXPAND = 0x0040,
/// The inserted item is a copy -- intended for use in ndtxt.cxx.
IS_COPY = 0x0080,
/// for Undo, translated to SwInsertFlags::NOHINTEXPAND
NOHINTEXPAND = 0x0100,
+ /// don't change the cursor position
+ NO_CURSOR_CHANGE = 0x0200
};
namespace o3tl
{
- template<> struct typed_flags<SetAttrMode> : is_typed_flags<SetAttrMode, 0x1ff> {};
+ template<> struct typed_flags<SetAttrMode> : is_typed_flags<SetAttrMode, 0x3ff> {};
}
constexpr bool SW_ISPRINTABLE(sal_Unicode c) { return c >= ' ' && 127 != c; }
@@ -237,6 +239,7 @@ enum class FrameControlType
Header,
Footer,
FloatingTable,
+ ContentControl,
Outline
};
diff --git a/sw/inc/swundo.hxx b/sw/inc/swundo.hxx
index cda4ec02c49f..7e9e0108b71f 100644
--- a/sw/inc/swundo.hxx
+++ b/sw/inc/swundo.hxx
@@ -166,6 +166,7 @@ enum class SwUndoId
INSERT_FORM_FIELD, // 135
OUTLINE_EDIT, // 136
+ INSERT_PAGE_NUMBER, // 137
};
OUString GetUndoComment(SwUndoId eId);
diff --git a/sw/inc/textcontentcontrol.hxx b/sw/inc/textcontentcontrol.hxx
index 1c445d812099..b3926bd25ce9 100644
--- a/sw/inc/textcontentcontrol.hxx
+++ b/sw/inc/textcontentcontrol.hxx
@@ -20,15 +20,19 @@
#include "txatbase.hxx"
+class SwContentControlManager;
class SwFormatContentControl;
/// SwTextAttr subclass that tracks the location of the wrapped SwFormatContentControl.
class SW_DLLPUBLIC SwTextContentControl final : public SwTextAttrNesting
{
- SwTextContentControl(SwFormatContentControl& rAttr, sal_Int32 nStart, sal_Int32 nEnd);
+ SwContentControlManager* m_pManager;
+
+ SwTextContentControl(SwContentControlManager* pManager, SwFormatContentControl& rAttr,
+ sal_Int32 nStart, sal_Int32 nEnd);
public:
- static SwTextContentControl* CreateTextContentControl(SwTextNode* pTargetTextNode,
+ static SwTextContentControl* CreateTextContentControl(SwDoc& rDoc, SwTextNode* pTargetTextNode,
SwFormatContentControl& rAttr,
sal_Int32 nStart, sal_Int32 nEnd,
bool bIsCopy);
@@ -37,7 +41,31 @@ public:
void ChgTextNode(SwTextNode* pNode);
+ void Delete(bool bSaveContents);
+
+ SwTextNode* GetTextNode() const;
+ /// Get the current (potentially invalid) string from the doc
+ OUString ToString() const;
+ void Invalidate();
+
void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};
+/// Knows all the text content controls in the document.
+class SW_DLLPUBLIC SwContentControlManager
+{
+ /// Non-owning reference to text content controls.
+ std::vector<SwTextContentControl*> m_aContentControls;
+
+public:
+ SwContentControlManager();
+ void Insert(SwTextContentControl* pTextContentControl);
+ void Erase(SwTextContentControl* pTextContentControl);
+ size_t GetCount() const { return m_aContentControls.size(); }
+ bool IsEmpty() const { return m_aContentControls.empty(); }
+ SwTextContentControl* Get(size_t nIndex);
+ SwTextContentControl* UnsortedGet(size_t nIndex);
+ void dumpAsXml(xmlTextWriterPtr pWriter) const;
+};
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/inc/txatbase.hxx b/sw/inc/txatbase.hxx
index 183e254f8817..00e2f9b51470 100644
--- a/sw/inc/txatbase.hxx
+++ b/sw/inc/txatbase.hxx
@@ -132,7 +132,7 @@ public:
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
};
-class SAL_DLLPUBLIC_RTTI SwTextAttrEnd : public virtual SwTextAttr
+class SW_DLLPUBLIC SwTextAttrEnd : public virtual SwTextAttr
{
protected:
sal_Int32 m_nEnd;
diff --git a/sw/inc/txtrfmrk.hxx b/sw/inc/txtrfmrk.hxx
index 0d25090197c1..6c9eafc35fb6 100644
--- a/sw/inc/txtrfmrk.hxx
+++ b/sw/inc/txtrfmrk.hxx
@@ -33,6 +33,8 @@ public:
SwTextRefMark( SwFormatRefMark& rAttr,
sal_Int32 const nStart, sal_Int32 const*const pEnd = nullptr);
+ ~SwTextRefMark();
+
virtual const sal_Int32* GetEnd() const override; // SwTextAttr
virtual void SetEnd(sal_Int32) override; // SwTextAttr
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 1ac7b671c695..3a8df7c69182 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -502,6 +502,7 @@
#define UNO_NAME_IS_SKIP_HIDDEN_TEXT "IsSkipHiddenText"
#define UNO_NAME_IS_SKIP_PROTECTED_TEXT "IsSkipProtectedText"
#define UNO_NAME_RESET_PARAGRAPH_LIST_ATTRIBUTES "ResetParagraphListAttributes"
+#define UNO_NAME_NO_FORMAT_ATTR "NoFormatAttr"
#define UNO_NAME_DOCUMENT_INDEX_MARKS "DocumentIndexMarks"
#define UNO_NAME_FOOTNOTE_IS_COLLECT_AT_TEXT_END "FootnoteIsCollectAtTextEnd"
#define UNO_NAME_FOOTNOTE_IS_RESTART_NUMBERING "FootnoteIsRestartNumbering"
@@ -880,11 +881,21 @@
#define UNO_NAME_DATE_FORMAT "DateFormat"
#define UNO_NAME_DATE_LANGUAGE "DateLanguage"
#define UNO_NAME_CURRENT_DATE "CurrentDate"
+#define UNO_NAME_PLAIN_TEXT "PlainText"
+#define UNO_NAME_COMBO_BOX "ComboBox"
+#define UNO_NAME_DROP_DOWN "DropDown"
#define UNO_NAME_PLACEHOLDER_DOC_PART "PlaceholderDocPart"
#define UNO_NAME_DATA_BINDING_PREFIX_MAPPINGS "DataBindingPrefixMappings"
#define UNO_NAME_DATA_BINDING_XPATH "DataBindingXpath"
#define UNO_NAME_DATA_BINDING_STORE_ITEM_ID "DataBindingStoreItemID"
#define UNO_NAME_COLOR "Color"
+#define UNO_NAME_APPEARANCE "Appearance"
+#define UNO_NAME_ALIAS "Alias"
+#define UNO_NAME_TAG "Tag"
+#define UNO_NAME_ID "Id"
+#define UNO_NAME_TAB_INDEX "TabIndex"
+#define UNO_NAME_LOCK "Lock"
+#define UNO_NAME_DATE_STRING "DateString"
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/inc/unotextcursor.hxx b/sw/inc/unotextcursor.hxx
index b055f2d64504..25c71effa57c 100644
--- a/sw/inc/unotextcursor.hxx
+++ b/sw/inc/unotextcursor.hxx
@@ -76,6 +76,7 @@ private:
const CursorType m_eType;
const css::uno::Reference< css::text::XText > m_xParentText;
sw::UnoCursorPointer m_pUnoCursor;
+ SetAttrMode m_nAttrMode = SetAttrMode::DEFAULT;
SwUnoCursor& GetCursorOrThrow() {
if(!m_pUnoCursor)
diff --git a/sw/inc/unotxdoc.hxx b/sw/inc/unotxdoc.hxx
index dc022d34ccc7..e2d3ac144992 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -29,6 +29,7 @@
#include <com/sun/star/text/XNumberingRulesSupplier.hpp>
#include <com/sun/star/text/XFootnotesSupplier.hpp>
#include <com/sun/star/text/XEndnotesSupplier.hpp>
+#include <com/sun/star/text/XContentControlsSupplier.hpp>
#include <com/sun/star/text/XTextSectionsSupplier.hpp>
#include <com/sun/star/text/XLineNumberingProperties.hpp>
#include <com/sun/star/text/XChapterNumberingSupplier.hpp>
@@ -99,6 +100,7 @@ typedef cppu::ImplInheritanceHelper
css::text::XNumberingRulesSupplier,
css::text::XFootnotesSupplier,
css::text::XEndnotesSupplier,
+ css::text::XContentControlsSupplier,
css::util::XReplaceable,
css::text::XPagePrintable,
css::text::XReferenceMarksSupplier,
@@ -156,6 +158,7 @@ private:
css::uno::Reference< css::beans::XPropertySet > mxXFootnoteSettings;
css::uno::Reference< css::container::XIndexAccess > mxXEndnotes;
css::uno::Reference< css::beans::XPropertySet > mxXEndnoteSettings;
+ css::uno::Reference< css::container::XIndexAccess > mxXContentControls;
css::uno::Reference< css::container::XNameAccess > mxXReferenceMarks;
css::uno::Reference< css::container::XEnumerationAccess > mxXTextFieldTypes;
css::uno::Reference< css::container::XNameAccess > mxXTextFieldMasters;
@@ -265,6 +268,9 @@ public:
virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getEndnotes() override;
virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getEndnoteSettings() override;
+ // XContentControlsSupplier
+ css::uno::Reference<css::container::XIndexAccess> SAL_CALL getContentControls() override;
+
//XReplaceable
virtual css::uno::Reference< css::util::XReplaceDescriptor > SAL_CALL createReplaceDescriptor() override;
virtual sal_Int32 SAL_CALL replaceAll(const css::uno::Reference< css::util::XSearchDescriptor > & xDesc) override;
@@ -452,6 +458,12 @@ public:
/// @see vcl::ITiledRenderable::executeContentControlEvent().
void executeContentControlEvent(const StringMap& aArguments) override;
+ /// @see vcl::ITiledRenderable::getCommandValues().
+ void getCommandValues(tools::JsonWriter& rJsonWriter, const OString& rCommand) override;
+
+ /// @see vcl::ITiledRenderable::supportsCommandValues().
+ bool supportsCommand(const OUString& rCommand) override;
+
void Invalidate();
void Reactivate(SwDocShell* pNewDocShell);
SwXDocumentPropertyHelper * GetPropertyHelper ();
diff --git a/sw/inc/view.hxx b/sw/inc/view.hxx
index d074f0d552a7..514074e603c9 100644
--- a/sw/inc/view.hxx
+++ b/sw/inc/view.hxx
@@ -693,7 +693,7 @@ public:
virtual tools::Rectangle getLOKVisibleArea() const override;
virtual void flushPendingLOKInvalidateTiles() override;
- virtual OString getLOKPayload(int nType, int nViewId, bool* ignore) const override;
+ virtual std::optional<OString> getLOKPayload(int nType, int nViewId) const override;
};
inline tools::Long SwView::GetXScroll() const
diff --git a/sw/inc/viscrs.hxx b/sw/inc/viscrs.hxx
index c5d97fc023c1..123ff61b2303 100644
--- a/sw/inc/viscrs.hxx
+++ b/sw/inc/viscrs.hxx
@@ -26,6 +26,8 @@
#include "swregion.hxx"
#include "swdllapi.h"
+#include <optional>
+
namespace sdr::overlay { class OverlayObject; }
class SwCursorShell;
@@ -61,7 +63,7 @@ public:
void SetPosAndShow(SfxViewShell const * pViewShell);
const vcl::Cursor& GetTextCursor() const;
- OString getLOKPayload(int nType, int nViewId, bool* ignore) const;
+ std::optional<OString> getLOKPayload(int nType, int nViewId) const;
};
// From here classes/methods for selections.
@@ -115,13 +117,15 @@ public:
void SetShowContentControlOverlay(const bool bShow) { m_bShowContentControlOverlay = bShow; }
+ VclPtr<SwContentControlButton> GetContentControlButton() const;
+
const SwCursorShell* GetShell() const { return m_pCursorShell; }
// check current MapMode of the shell and set possibly the static members.
// Optional set the parameters pX, pY
static void Get1PixelInLogic( const SwViewShell& rSh,
tools::Long* pX = nullptr, tools::Long* pY = nullptr );
- OString getLOKPayload(int nType, int nViewId, bool* ignore) const;
+ std::optional<OString> getLOKPayload(int nType, int nViewId) const;
};
class SW_DLLPUBLIC SwShellCursor : public virtual SwCursor, public SwSelPaintRects
diff --git a/sw/layoutwriter_setup.mk b/sw/layoutwriter_setup.mk
index 0fb848f106de..9b249678ff44 100644
--- a/sw/layoutwriter_setup.mk
+++ b/sw/layoutwriter_setup.mk
@@ -26,6 +26,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_layoutwriter$(1), \
comphelper \
cppu \
cppuhelper \
+ docmodel \
editeng \
msword \
sal \
diff --git a/sw/ooxmlexport_setup.mk b/sw/ooxmlexport_setup.mk
index 404ee5153438..8c17689b9077 100644
--- a/sw/ooxmlexport_setup.mk
+++ b/sw/ooxmlexport_setup.mk
@@ -13,6 +13,7 @@ define sw_ooxmlexport_libraries
comphelper \
cppu \
cppuhelper \
+ docmodel \
editeng \
sal \
sfx \
diff --git a/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx b/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx
index 2545171d6c38..713537422f8c 100644
--- a/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx
+++ b/sw/qa/core/accessibilitycheck/AccessibilityCheckTest.cxx
@@ -11,6 +11,14 @@
#include <AccessibilityCheck.hxx>
#include <unotxdoc.hxx>
#include <docsh.hxx>
+#include <AccessibilityIssue.hxx>
+#include <OnlineAccessibilityCheck.hxx>
+#include <wrtsh.hxx>
+#include <vcl/scheduler.hxx>
+#include <comphelper/propertysequence.hxx>
+
+#include <comphelper/scopeguard.hxx>
+#include <officecfg/Office/Common.hxx>
constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/accessibilitycheck/data/";
@@ -48,6 +56,301 @@ CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testTableSplitMergeAndAltText)
CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::NO_ALT_SHAPE, aIssues[6]->m_eIssueID);
}
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheckParagraphIssues)
+{
+ // Tests whether formatting issues are detected when the whole paragraph has them instead of
+ // some text inside the paragraph
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "ParagraphTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheckBackgroundImage)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "BackgroundImageTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::DOCUMENT_BACKGROUND, aIssues[0]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheckNewlineSpace)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "NewlineTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[1]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheckSpacebarSpace)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "SpaceTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testHyperlinks)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "HyperlinkTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::HYPERLINK_SHORT, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::HYPERLINK_IS_TEXT, aIssues[1]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheckHighlightedText)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "HighlightTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheckFakeFootnote)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "FakeFootnoteTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::FAKE_FOOTNOTE, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::FAKE_FOOTNOTE, aIssues[1]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheckFakeCaption)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "FakeCaptionTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::FAKE_CAPTION, aIssues[0]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheckTableFormatting)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "TableFormattingTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(1), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TABLE_FORMATTING, aIssues[0]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testCheckTabsFormatting)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "TabsTest.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(4), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[1]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[2]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[3]->m_eIssueID);
+}
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testNumberingCheck)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "AccessibilityTests_NumberingCheck.odt");
+ CPPUNIT_ASSERT(pDoc);
+ sw::AccessibilityCheck aCheck(pDoc);
+ aCheck.check();
+ auto& aIssues = aCheck.getIssueCollection().getIssues();
+ CPPUNIT_ASSERT_EQUAL(size_t(5), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING, aIssues[1]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING, aIssues[2]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING, aIssues[3]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::MANUAL_NUMBERING, aIssues[4]->m_eIssueID);
+}
+
+namespace
+{
+std::vector<std::shared_ptr<sfx::AccessibilityIssue>>
+scanAccessibilityIssuesOnNodes(SwDoc* pDocument)
+{
+ std::vector<std::shared_ptr<sfx::AccessibilityIssue>> aIssues;
+ auto const& pNodes = pDocument->GetNodes();
+ for (SwNodeOffset n(0); n < pNodes.Count(); ++n)
+ {
+ SwNode* pNode = pNodes[n];
+ auto& pCollection = pNode->getAccessibilityCheckStatus().pCollection;
+ if (pCollection)
+ {
+ for (auto& pIssue : pCollection->getIssues())
+ {
+ aIssues.push_back(pIssue);
+ }
+ }
+ }
+ return aIssues;
+}
+
+void checkIssuePosition(std::shared_ptr<sfx::AccessibilityIssue> const& pIssue, int nLine,
+ sal_Int32 nStart, sal_Int32 nEnd, SwNodeOffset nIndex)
+{
+ auto* pSwIssue = static_cast<sw::AccessibilityIssue*>(pIssue.get());
+
+ OString sFailMessage = OString::Concat("Start doesn't match at line: ")
+ + OString::Concat(OString::number(nLine));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailMessage.getStr(), nStart, pSwIssue->getStart());
+
+ sFailMessage
+ = OString::Concat("End doesn't match at line: ") + OString::Concat(OString::number(nLine));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailMessage.getStr(), nEnd, pSwIssue->getEnd());
+
+ sFailMessage = OString::Concat("Offset doesn't match at line: ")
+ + OString::Concat(OString::number(nLine));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailMessage.getStr(), nIndex, pSwIssue->getNode()->GetIndex());
+}
+
+} // end anonymous ns
+
+CPPUNIT_TEST_FIXTURE(AccessibilityCheckTest, testOnlineNodeSplitAppend)
+{
+ // Checks the a11y checker is setting the a11y issues to the nodes
+ // correctly when splitting and appending nodes (through undo), which
+ // happen on editing all the time.
+ // When a node is split, it can happen that both nodes get a11y issues
+ // if the node splits the area of direct formatting.
+
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "OnlineCheck.odt");
+ CPPUNIT_ASSERT(pDoc);
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ CPPUNIT_ASSERT(pWrtShell);
+
+ // Enable online a11y checker
+ {
+ auto pBatch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::set(true, pBatch);
+ pBatch->commit();
+ }
+ comphelper::ScopeGuard g([] {
+ auto pBatch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::set(false, pBatch);
+ pBatch->commit();
+ });
+
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0),
+ pDoc->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
+ // Trigger a11y checker
+ pWrtShell->Down(/*bSelect*/ false, /*nCount*/ 0);
+
+ // Check we have 1 a11y issue
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2),
+ pDoc->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
+ auto aIssues = scanAccessibilityIssuesOnNodes(pDoc);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[1]->m_eIssueID);
+ checkIssuePosition(aIssues[0], __LINE__, 0, 32, SwNodeOffset(9));
+ checkIssuePosition(aIssues[1], __LINE__, 33, 136, SwNodeOffset(9));
+
+ // Position the cursor and hit "enter" (trigger split-node action)
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 33, /*bBasicCall=*/false);
+ pWrtShell->SplitNode();
+
+ // Check the result
+ CPPUNIT_ASSERT_EQUAL(OUString("He heard quiet steps behind him. "),
+ getParagraph(1)->getString());
+ CPPUNIT_ASSERT_EQUAL(OUString("That didn't bode well. Who could be following him this late at "
+ "night and in this deadbeat part of town?"),
+ getParagraph(2)->getString());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2),
+ pDoc->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
+
+ aIssues = scanAccessibilityIssuesOnNodes(pDoc);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[1]->m_eIssueID);
+ checkIssuePosition(aIssues[0], __LINE__, 0, 32, SwNodeOffset(9));
+ checkIssuePosition(aIssues[1], __LINE__, 0, 103, SwNodeOffset(10));
+
+ // Position cursor and split again
+ pWrtShell->Down(/*bSelect*/ false, /*nCount*/ 0);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 23, /*bBasicCall=*/false);
+ pWrtShell->SplitNode();
+
+ // Check the result
+ CPPUNIT_ASSERT_EQUAL(OUString("He heard quiet steps behind him. "),
+ getParagraph(1)->getString());
+ CPPUNIT_ASSERT_EQUAL(OUString("That didn't bode well. "), getParagraph(2)->getString());
+ CPPUNIT_ASSERT_EQUAL(
+ OUString(
+ "Who could be following him this late at night and in this deadbeat part of town?"),
+ getParagraph(3)->getString());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(3),
+ pDoc->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
+ aIssues = scanAccessibilityIssuesOnNodes(pDoc);
+ CPPUNIT_ASSERT_EQUAL(size_t(3), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[1]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[2]->m_eIssueID);
+ checkIssuePosition(aIssues[0], __LINE__, 0, 32, SwNodeOffset(9));
+ checkIssuePosition(aIssues[1], __LINE__, 0, 23, SwNodeOffset(10));
+ checkIssuePosition(aIssues[2], __LINE__, 0, 80, SwNodeOffset(11));
+
+ // Undo second change
+ dispatchCommand(mxComponent, ".uno:Undo", {});
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(OUString("He heard quiet steps behind him. "),
+ getParagraph(1)->getString());
+ CPPUNIT_ASSERT_EQUAL(OUString("That didn't bode well. Who could be following him this late at "
+ "night and in this deadbeat part of town?"),
+ getParagraph(2)->getString());
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2),
+ pDoc->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
+ aIssues = scanAccessibilityIssuesOnNodes(pDoc);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[1]->m_eIssueID);
+ checkIssuePosition(aIssues[0], __LINE__, 0, 32, SwNodeOffset(9));
+ checkIssuePosition(aIssues[1], __LINE__, 0, 103, SwNodeOffset(10));
+
+ // Undo first change
+ dispatchCommand(mxComponent, ".uno:Undo", {});
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2),
+ pDoc->getOnlineAccessibilityCheck()->getNumberOfAccessibilityIssues());
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("He heard quiet steps behind him. That didn't bode well. Who could be following "
+ "him this late at night and in this deadbeat part of town?"),
+ getParagraph(1)->getString());
+ aIssues = scanAccessibilityIssuesOnNodes(pDoc);
+ CPPUNIT_ASSERT_EQUAL(size_t(2), aIssues.size());
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[0]->m_eIssueID);
+ CPPUNIT_ASSERT_EQUAL(sfx::AccessibilityIssueID::TEXT_FORMATTING, aIssues[1]->m_eIssueID);
+ checkIssuePosition(aIssues[0], __LINE__, 0, 32, SwNodeOffset(9));
+ checkIssuePosition(aIssues[1], __LINE__, 33, 136, SwNodeOffset(9));
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/accessibilitycheck/data/AccessibilityTests1.odt b/sw/qa/core/accessibilitycheck/data/AccessibilityTests1.odt
index 2e319f58e7a2..6b55335e773d 100644
--- a/sw/qa/core/accessibilitycheck/data/AccessibilityTests1.odt
+++ b/sw/qa/core/accessibilitycheck/data/AccessibilityTests1.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/AccessibilityTests_NumberingCheck.odt b/sw/qa/core/accessibilitycheck/data/AccessibilityTests_NumberingCheck.odt
new file mode 100644
index 000000000000..190ee91a8fde
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/AccessibilityTests_NumberingCheck.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/BackgroundImageTest.odt b/sw/qa/core/accessibilitycheck/data/BackgroundImageTest.odt
new file mode 100644
index 000000000000..eff6f178394b
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/BackgroundImageTest.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/FakeCaptionTest.odt b/sw/qa/core/accessibilitycheck/data/FakeCaptionTest.odt
new file mode 100644
index 000000000000..9630bfcf73d7
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/FakeCaptionTest.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/FakeFootnoteTest.odt b/sw/qa/core/accessibilitycheck/data/FakeFootnoteTest.odt
new file mode 100644
index 000000000000..fdacf6cb35de
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/FakeFootnoteTest.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/HighlightTest.odt b/sw/qa/core/accessibilitycheck/data/HighlightTest.odt
new file mode 100644
index 000000000000..da4821681502
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/HighlightTest.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/HyperlinkTest.odt b/sw/qa/core/accessibilitycheck/data/HyperlinkTest.odt
new file mode 100644
index 000000000000..1eba1932ce21
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/HyperlinkTest.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/NewlineTest.odt b/sw/qa/core/accessibilitycheck/data/NewlineTest.odt
new file mode 100644
index 000000000000..9ff715916fc2
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/NewlineTest.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/OnlineCheck.odt b/sw/qa/core/accessibilitycheck/data/OnlineCheck.odt
new file mode 100644
index 000000000000..d24fb4ff1abf
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/OnlineCheck.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/ParagraphTest.odt b/sw/qa/core/accessibilitycheck/data/ParagraphTest.odt
new file mode 100644
index 000000000000..766ecd0b4e2e
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/ParagraphTest.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/SpaceTest.odt b/sw/qa/core/accessibilitycheck/data/SpaceTest.odt
new file mode 100644
index 000000000000..0f00f78f9698
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/SpaceTest.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/TableFormattingTest.odt b/sw/qa/core/accessibilitycheck/data/TableFormattingTest.odt
new file mode 100644
index 000000000000..adc63daaf7cb
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/TableFormattingTest.odt
Binary files differ
diff --git a/sw/qa/core/accessibilitycheck/data/TabsTest.odt b/sw/qa/core/accessibilitycheck/data/TabsTest.odt
new file mode 100644
index 000000000000..29b415df87a7
--- /dev/null
+++ b/sw/qa/core/accessibilitycheck/data/TabsTest.odt
Binary files differ
diff --git a/sw/qa/core/crsr/crsr.cxx b/sw/qa/core/crsr/crsr.cxx
index 7732727cbb3a..7b42d4df3716 100644
--- a/sw/qa/core/crsr/crsr.cxx
+++ b/sw/qa/core/crsr/crsr.cxx
@@ -19,11 +19,13 @@
#include <comphelper/propertysequence.hxx>
#include <svl/srchitem.hxx>
#include <vcl/scheduler.hxx>
+#include <comphelper/propertyvalue.hxx>
#include <docsh.hxx>
#include <unotxdoc.hxx>
#include <wrtsh.hxx>
#include <ndtxt.hxx>
+#include <formatcontentcontrol.hxx>
constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/crsr/data/";
@@ -164,6 +166,46 @@ CPPUNIT_TEST_FIXTURE(SwCoreCrsrTest, testContentControlReadOnly)
CPPUNIT_ASSERT(pWrtShell->HasReadonlySel());
}
+CPPUNIT_TEST_FIXTURE(SwCoreCrsrTest, testDropdownContentControl)
+{
+ // Given a document with a dropdown content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);
+
+ // When entering the content control:
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+
+ // Then make sure that the cursor is read-only:
+ // Without the accompanying fix in place, this test would have failed, it was possible to type
+ // into the drop-down content control, providing content that is not one of the list items.
+ CPPUNIT_ASSERT(pWrtShell->HasReadonlySel());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreCrsrTest, testContentControlProtectedSection)
+{
+ // Given a document with a date content control in a protected section:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::DATE);
+ pWrtShell->SelAll();
+ OUString aSectionName = pWrtShell->GetUniqueSectionName();
+ SwSectionData aSection(SectionType::Content, aSectionName);
+ aSection.SetProtectFlag(true);
+ pWrtShell->InsertSection(aSection);
+
+ // When entering the content control:
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+
+ // Then make sure that the cursor is read-only:
+ // Without the accompanying fix in place, this test would have failed, it was not possible to
+ // pick a date in a protected section (the new value was inserted, but the placeholder was not
+ // removed).
+ CPPUNIT_ASSERT(!pWrtShell->HasReadonlySel());
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/data/docm/testModernVBA.docm b/sw/qa/core/data/docm/testModernVBA.docm
new file mode 100644
index 000000000000..c08d738c8adb
--- /dev/null
+++ b/sw/qa/core/data/docm/testModernVBA.docm
Binary files differ
diff --git a/sw/qa/core/data/docm/testVBA.docm b/sw/qa/core/data/docm/testVBA.docm
new file mode 100644
index 000000000000..44e59f03a753
--- /dev/null
+++ b/sw/qa/core/data/docm/testVBA.docm
Binary files differ
diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx
index 26d02e60318b..ff006bda3faf 100644
--- a/sw/qa/core/doc/doc.cxx
+++ b/sw/qa/core/doc/doc.cxx
@@ -19,6 +19,7 @@
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
#include <vcl/scheduler.hxx>
+#include <comphelper/propertyvalue.hxx>
#include <wrtsh.hxx>
#include <fmtanchr.hxx>
@@ -255,6 +256,35 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testContentControlDelete)
CPPUNIT_ASSERT_EQUAL(OUString("\x0001test\x0001"), pTextNode->GetText());
}
+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testLinkedStyleDelete)
+{
+ // Given a document with linked styles: myparastyle is linked to mycharstyle and vica versa:
+ createSwDoc();
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xParaStyle(
+ xFactory->createInstance("com.sun.star.style.ParagraphStyle"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xCharStyle(
+ xFactory->createInstance("com.sun.star.style.CharacterStyle"), uno::UNO_QUERY);
+ uno::Reference<container::XNameContainer> xParaStyles(getStyles("ParagraphStyles"),
+ uno::UNO_QUERY);
+ xParaStyles->insertByName("myparastyle", uno::Any(xParaStyle));
+ uno::Reference<container::XNameContainer> xCharStyles(getStyles("CharacterStyles"),
+ uno::UNO_QUERY);
+ xCharStyles->insertByName("mycharstyle", uno::Any(xCharStyle));
+ xParaStyle->setPropertyValue("LinkStyle", uno::Any(OUString("mycharstyle")));
+ xCharStyle->setPropertyValue("LinkStyle", uno::Any(OUString("myparastyle")));
+
+ // When deleting the paragraph style (and only that):
+ xParaStyles->removeByName("myparastyle");
+
+ // Then make sure we don't crash on save:
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FilterName", OUString("writer8")),
+ };
+ xStorable->storeAsURL(maTempFile.GetURL(), aArgs);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/draw/data/sdt-textbox-header.docx b/sw/qa/core/draw/data/sdt-textbox-header.docx
new file mode 100644
index 000000000000..a8b2d9625fbe
--- /dev/null
+++ b/sw/qa/core/draw/data/sdt-textbox-header.docx
Binary files differ
diff --git a/sw/qa/core/draw/draw.cxx b/sw/qa/core/draw/draw.cxx
index c2514808f8e4..feb347adc8d4 100644
--- a/sw/qa/core/draw/draw.cxx
+++ b/sw/qa/core/draw/draw.cxx
@@ -141,6 +141,17 @@ CPPUNIT_TEST_FIXTURE(SwCoreDrawTest, testTdf107727FrameBorder)
CPPUNIT_ASSERT_EQUAL(Color(0x0000ff), Color(ColorTransparency, aBorder.Color));
}
+CPPUNIT_TEST_FIXTURE(SwCoreDrawTest, testSdtTextboxHeader)
+{
+ // Given a 2 page document, same header on both pages, content control in the header and
+ // shape+fly pair (textbox) anchored in the same header:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "sdt-textbox-header.docx";
+
+ // When loading that document, then make sure that layout doesn't fail with an assertion because
+ // the "master SdrObj should have the highest index" invariant doesn't hold:
+ mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument", {});
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/layout/data/header-textbox.docx b/sw/qa/core/layout/data/header-textbox.docx
new file mode 100644
index 000000000000..4df72cccd3e7
--- /dev/null
+++ b/sw/qa/core/layout/data/header-textbox.docx
Binary files differ
diff --git a/sw/qa/core/layout/layout.cxx b/sw/qa/core/layout/layout.cxx
index abd77b3e217d..3bdeabe9b9f7 100644
--- a/sw/qa/core/layout/layout.cxx
+++ b/sw/qa/core/layout/layout.cxx
@@ -238,6 +238,21 @@ CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testTextboxModification)
CPPUNIT_ASSERT(!pDocShell->IsModified());
}
+CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testTextBoxInHeaderIsPositioned)
+{
+ // Load a document with a floating text box in the header
+ load(DATA_DIRECTORY, "header-textbox.docx");
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ CPPUNIT_ASSERT(pXmlDoc);
+
+ // Without the fix in place, this test would have failed with
+ // - Expected: 8051
+ // - Actual : 1418
+ // Comparison with 7000 chosen due to variability between devices
+ CPPUNIT_ASSERT_GREATEREQUAL(
+ double(7000), getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "left").toDouble());
+}
+
CPPUNIT_TEST_FIXTURE(SwCoreLayoutTest, testBtlrNestedCell)
{
// Load a document with a nested table, the inner A1 cell has a btlr text direction.
diff --git a/sw/qa/core/macros-test.cxx b/sw/qa/core/macros-test.cxx
index 91c7a928a46a..43b47198243a 100644
--- a/sw/qa/core/macros-test.cxx
+++ b/sw/qa/core/macros-test.cxx
@@ -64,7 +64,7 @@ class SwMacrosTest : public test::BootstrapFixture, public unotest::MacrosTest
public:
SwMacrosTest();
- void createFileURL(std::u16string_view aFileBase, std::u16string_view aFileExtension, OUString& rFilePath);
+ void createFileURL(std::u16string_view aFile, OUString& rFilePath);
virtual void setUp() override;
virtual void tearDown() override;
@@ -94,24 +94,35 @@ private:
OUString m_aBaseString;
};
-void SwMacrosTest::createFileURL(std::u16string_view aFileBase, std::u16string_view aFileExtension, OUString& rFilePath)
+void SwMacrosTest::createFileURL(std::u16string_view aFile, OUString& rFilePath)
{
- rFilePath = m_directories.getSrcRootURL() + m_aBaseString + "/" + aFileExtension + "/"
- + aFileBase + aFileExtension;
+ auto i = aFile.find_last_of('.');
+ CPPUNIT_ASSERT_MESSAGE("Missing Extension", i != std::string_view::npos);
+ std::u16string_view aFileExtension = aFile.substr(i+1);
+
+ rFilePath = m_directories.getSrcRootURL() + m_aBaseString + "/" + aFileExtension + "/" + aFile;
}
void SwMacrosTest::testVba()
{
TestMacroInfo testInfo[] = {
{
- OUString("testVba."),
+ OUString("testVba.doc"),
OUString("vnd.sun.Star.script:Project.NewMacros.Macro1?language=Basic&location=document")
+ },
+ {
+ OUString("testVBA.docm"),
+ OUString("vnd.sun.Star.script:Project.ThisDocument.testAll?language=Basic&location=document")
+ },
+ {
+ OUString("testModernVBA.docm"),
+ OUString("vnd.sun.Star.script:Project.ThisDocument.testAll?language=Basic&location=document")
}
};
for ( size_t i=0; i<SAL_N_ELEMENTS( testInfo ); ++i )
{
OUString aFileName;
- createFileURL(testInfo[i].sFileBaseName, u"doc", aFileName);
+ createFileURL(testInfo[i].sFileBaseName, aFileName);
uno::Reference< css::lang::XComponent > xComponent = loadFromDesktop(aFileName, "com.sun.star.text.TextDocument");
OUString sUrl = testInfo[i].sMacroUrl;
Any aRet;
@@ -203,7 +214,7 @@ void SwMacrosTest::testBookmarkDeleteTdf90816()
void SwMacrosTest::testControlShapeGrouping()
{
OUString aFileName;
- createFileURL(u"testControlShapeGrouping.", u"odt", aFileName);
+ createFileURL(u"testControlShapeGrouping.odt", aFileName);
Reference< css::lang::XComponent > xComponent(
loadFromDesktop(aFileName, "com.sun.star.text.TextDocument"));
@@ -343,7 +354,7 @@ void SwMacrosTest::testFdo55289()
void SwMacrosTest::testFdo68983()
{
OUString aFileName;
- createFileURL(u"fdo68983.", u"odt", aFileName);
+ createFileURL(u"fdo68983.odt", aFileName);
Reference< css::lang::XComponent > xComponent =
loadFromDesktop(aFileName, "com.sun.star.text.TextDocument");
Reference< frame::XStorable > xDocStorable(xComponent, UNO_QUERY_THROW);
diff --git a/sw/qa/core/text/data/number-portion-format.odt b/sw/qa/core/text/data/number-portion-format.odt
new file mode 100644
index 000000000000..19b23ae84420
--- /dev/null
+++ b/sw/qa/core/text/data/number-portion-format.odt
Binary files differ
diff --git a/sw/qa/core/text/data/number-portion-noformat.docx b/sw/qa/core/text/data/number-portion-noformat.docx
new file mode 100644
index 000000000000..b289b9c69ef4
--- /dev/null
+++ b/sw/qa/core/text/data/number-portion-noformat.docx
Binary files differ
diff --git a/sw/qa/core/text/text.cxx b/sw/qa/core/text/text.cxx
index f43727ed5f3f..8cc59e8e3a2a 100644
--- a/sw/qa/core/text/text.cxx
+++ b/sw/qa/core/text/text.cxx
@@ -12,11 +12,14 @@
#include <memory>
#include <com/sun/star/text/BibliographyDataType.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
#include <vcl/gdimtf.hxx>
#include <vcl/filter/PDFiumLibrary.hxx>
#include <comphelper/propertyvalue.hxx>
#include <unotools/mediadescriptor.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
#include <docsh.hxx>
#include <unotxdoc.hxx>
@@ -32,6 +35,11 @@
#include <fmtcntnt.hxx>
#include <fmtfsize.hxx>
#include <IDocumentRedlineAccess.hxx>
+#include <formatcontentcontrol.hxx>
+#include <strings.hrc>
+#include <ndtxt.hxx>
+#include <txatbase.hxx>
+#include <textcontentcontrol.hxx>
constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/text/data/";
@@ -114,18 +122,10 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testBibliographyUrlPdfExport)
xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false);
// When exporting to PDF:
- uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
- utl::MediaDescriptor aMediaDescriptor;
- aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
- xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+ StoreToTempFile("writer_pdf_Export");
// Then make sure the field links the source.
- SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ);
- SvMemoryStream aMemory;
- aMemory.WriteStream(aFile);
- std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
- = pPDFium->openDocument(aMemory.GetData(), aMemory.GetSize());
- CPPUNIT_ASSERT(pPdfDocument);
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile();
std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0);
// Without the accompanying fix in place, this test would have failed, the field was not
// clickable (while it was clickable on the UI).
@@ -349,6 +349,90 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakLeft)
assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "2837");
}
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakLeftRTL)
+{
+ // Given a document with an anchored object in an RTL para and a clearing break (type=left):
+ loadURL("private:factory/swriter", nullptr);
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ uno::Reference<beans::XPropertySet> xCursorProps(xCursor, uno::UNO_QUERY);
+ xCursorProps->setPropertyValue("WritingMode", uno::Any(text::WritingMode2::RL_TB));
+ {
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(5000, 5000));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ xShapeProps->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+ uno::Reference<text::XTextContent> xShapeContent(xShape, uno::UNO_QUERY);
+ xText->insertTextContent(xCursor, xShapeContent, /*bAbsorb=*/false);
+ }
+ uno::Reference<text::XTextContent> xLineBreak(
+ xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY);
+ auto eClear = static_cast<sal_Int16>(SwLineBreakClear::RIGHT);
+ xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear));
+ xText->insertString(xCursor, "foo", /*bAbsorb=*/false);
+ xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false);
+ xText->insertString(xCursor, "bar", /*bAbsorb=*/false);
+
+ // When laying out that document:
+ calcLayout();
+
+ // Then make sure the "bar" does not jump down (due to type=left && RTL):
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 276
+ // - Actual : 2837
+ // i.e. left/right was not ignored in the RTL case.
+ assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "276");
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakVertical)
+{
+ // Given a document with an anchored object in a vertical page and a clearing break (type=all):
+ loadURL("private:factory/swriter", nullptr);
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ uno::Reference<beans::XPropertySet> xStandard(getStyles("PageStyles")->getByName("Standard"),
+ uno::UNO_QUERY);
+ xStandard->setPropertyValue("WritingMode", uno::Any(text::WritingMode2::TB_RL));
+ {
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(5000, 5000));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ xShapeProps->setPropertyValue("AnchorType",
+ uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+ uno::Reference<text::XTextContent> xShapeContent(xShape, uno::UNO_QUERY);
+ xText->insertTextContent(xCursor, xShapeContent, /*bAbsorb=*/false);
+ }
+ uno::Reference<text::XTextContent> xLineBreak(
+ xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY);
+ auto eClear = static_cast<sal_Int16>(SwLineBreakClear::ALL);
+ xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear));
+ xText->insertString(xCursor, "foo", /*bAbsorb=*/false);
+ xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false);
+ xText->insertString(xCursor, "bar", /*bAbsorb=*/false);
+
+ // When laying out that document:
+ calcLayout();
+
+ // Then make sure the "bar" does jump (logic) down the correct amount:
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2837
+ // - Actual : 7135
+ // i.e. the expected break height is the twips value of the 5cm rectangle size, it was much
+ // more.
+ assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "height", "2837");
+}
+
CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testClearingLineBreakHeader)
{
// Given a document with a shape in the header and a clearing break in the body text:
@@ -449,6 +533,278 @@ CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testRedlineDelete)
pDoc->getIDocumentRedlineAccess().GetRedlineTable().size());
}
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testContentControlPDF)
+{
+ // Given a file with a content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT);
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ sal_Int32 nPlaceHolderLen = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER).getLength();
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, nPlaceHolderLen,
+ /*bBasicCall=*/false);
+ pWrtShell->Insert("mycontent");
+ const SwPosition* pStart = pWrtShell->GetCursor()->Start();
+ SwTextNode* pTextNode = pStart->nNode.GetNode().GetTextNode();
+ sal_Int32 nIndex = pStart->nContent.GetIndex();
+ SwTextAttr* pAttr
+ = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT);
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ // Alias/title, to be mapped to PDF's description.
+ pContentControl->SetAlias("mydesc");
+
+ // When exporting to PDF:
+ StoreToTempFile("writer_pdf_Export");
+
+ // Then make sure that a fillable form widget is emitted:
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. the content control was just exported as normal text.
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
+ std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType());
+
+ // Also verify that the widget description is correct, it was empty:
+ CPPUNIT_ASSERT_EQUAL(OUString("mydesc"),
+ pAnnotation->getFormFieldAlternateName(pPdfDocument.get()));
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testCheckboxContentControlPDF)
+{
+ // Given a file with a checkbox content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);
+
+ // When exporting to PDF:
+ StoreToTempFile("writer_pdf_Export");
+
+ // Then make sure that a checkbox form widget is emitted:
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. the checkbox content control was just exported as normal text.
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
+ std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType());
+ // Also check the form widget type:
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::CheckBox,
+ pAnnotation->getFormFieldType(pPdfDocument.get()));
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testDropdownContentControlPDF)
+{
+ // Given a file with a dropdown content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);
+
+ // When exporting to PDF:
+ StoreToTempFile("writer_pdf_Export");
+
+ // Then make sure that a dropdown form widget is emitted:
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. the dropdown content control was just exported as normal text.
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
+ std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType());
+ // Also check the form widget type (our dropdown is called combo in PDF terms):
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::ComboBox,
+ pAnnotation->getFormFieldType(pPdfDocument.get()));
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testDateContentControlPDF)
+{
+ // Given a file with a date content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::DATE);
+
+ // When exporting to PDF:
+ StoreToTempFile("writer_pdf_Export");
+
+ // Then make sure that a date form widget is emitted:
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. the date content control was just exported as normal text.
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
+ std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType());
+ // Also check the form widget type (our date is a mode of text in PDF terms):
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::TextField,
+ pAnnotation->getFormFieldType(pPdfDocument.get()));
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testContentControlPDFFont)
+{
+ // Given a document with a custom 24pt font size and a content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SfxItemSetFixed<RES_CHRATR_FONTSIZE, RES_CHRATR_FONTSIZE> aSet(pWrtShell->GetAttrPool());
+ SvxFontHeightItem aItem(480, 100, RES_CHRATR_FONTSIZE);
+ aSet.Put(aItem);
+ pWrtShell->SetAttrSet(aSet);
+ pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT);
+
+ // When exporting that document to PDF:
+ StoreToTempFile("writer_pdf_Export");
+
+ // Then make sure that the widget in the PDF result has that custom font size:
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
+ pPage->onAfterLoadPage(pPdfDocument.get());
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
+ std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 24
+ // - Actual : 8
+ // i.e. i.e. the font size was some default, not the 24pt specified in the model.
+ CPPUNIT_ASSERT_EQUAL(24.0f, pAnnotation->getFontSize(pPdfDocument.get()));
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testComboContentControlPDF)
+{
+ // Given a file with a combo box content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::COMBO_BOX);
+
+ // When exporting to PDF:
+ StoreToTempFile("writer_pdf_Export");
+
+ // Then make sure that a combo box form widget is emitted:
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. the combo box content control was exported as plain text.
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
+ std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType());
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::ComboBox,
+ pAnnotation->getFormFieldType(pPdfDocument.get()));
+ // 19th bit: combo box, not dropdown.
+ CPPUNIT_ASSERT(pAnnotation->getFormFieldFlags(pPdfDocument.get()) & 0x00040000);
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testRichContentControlPDF)
+{
+ // Given a file with a rich content control, its value set to "xxx<b>yyy</b>":
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::RICH_TEXT);
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ sal_Int32 nPlaceHolderLen = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER).getLength();
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, nPlaceHolderLen,
+ /*bBasicCall=*/false);
+ pWrtShell->Insert("xxxyyy");
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 3, /*bBasicCall=*/false);
+ SfxItemSetFixed<RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT> aSet(pWrtShell->GetAttrPool());
+ SvxWeightItem aItem(WEIGHT_BOLD, RES_CHRATR_WEIGHT);
+ aSet.Put(aItem);
+ pWrtShell->SetAttrSet(aSet);
+
+ // When exporting to PDF:
+ StoreToTempFile("writer_pdf_Export");
+
+ // Then make sure that a single fillable form widget is emitted:
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 2
+ // i.e. "xxx<b>yyy</b>" was exported as 2 widgets, not 1.
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testNumberPortionFormat)
+{
+ // Given a document with a single paragraph, direct formatting asks 24pt font size for the
+ // numbering and the text portion:
+ createSwDoc(DATA_DIRECTORY, "number-portion-format.odt");
+
+ // When laying out that document:
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+ // Then make sure that the numbering portion has the correct font size:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 480
+ // - Actual : 240
+ // i.e. the numbering portion font size was 12pt, not 24pt (but only when the doc had a
+ // bookmark).
+ assertXPath(pXmlDoc, "//Special[@nType='PortionType::Number']", "nHeight", "480");
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testNumberPortionNoformat)
+{
+ // Given a document with a numbering and a single paragraph, the entire run is red:
+ createSwDoc(DATA_DIRECTORY, "number-portion-noformat.docx");
+
+ // When laying out that document:
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+ // Then make sure that just because the entire run is red, the numbering portion is not red:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: ffffffff (COL_AUTO)
+ // - Actual : 00ff0000 (COL_LIGHTRED)
+ // i.e. the run color affected the color of the number portion in Writer, but not in Word.
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("ffffffff"),
+ getXPath(pXmlDoc, "//Special[@nType='PortionType::Number']/SwFont", "color"));
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTextTest, testCheckedCheckboxContentControlPDF)
+{
+ std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPDFium)
+ return;
+
+ // Given a file with a checked checkbox content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);
+ // Toggle it, so we get a checked one:
+ SwTextContentControl* pTextContentControl = pWrtShell->CursorInsideContentControl();
+ const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
+ pWrtShell->GotoContentControl(rFormatContentControl);
+
+ // When exporting to PDF:
+ StoreToTempFile("writer_pdf_Export");
+
+ // Then make sure that a checked checkbox form widget is emitted:
+ std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument = LoadPdfFromTempFile();
+ std::unique_ptr<vcl::pdf::PDFiumPage> pPage = pPdfDocument->openPage(0);
+ CPPUNIT_ASSERT_EQUAL(1, pPage->getAnnotationCount());
+ std::unique_ptr<vcl::pdf::PDFiumAnnotation> pAnnotation = pPage->getAnnotation(0);
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFAnnotationSubType::Widget, pAnnotation->getSubType());
+ CPPUNIT_ASSERT_EQUAL(vcl::pdf::PDFFormFieldType::CheckBox,
+ pAnnotation->getFormFieldType(pPdfDocument.get()));
+ OUString aActual = pAnnotation->getFormFieldValue(pPdfDocument.get());
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: Yes
+ // - Actual : Off
+ // i.e. the /AP -> /N key of the checkbox widget annotation object didn't have a sub-key that
+ // would match /V, leading to not showing the checked state.
+ CPPUNIT_ASSERT_EQUAL(OUString("Yes"), aActual);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/theme/ThemeTest.cxx b/sw/qa/core/theme/ThemeTest.cxx
new file mode 100644
index 000000000000..8dae2631846f
--- /dev/null
+++ b/sw/qa/core/theme/ThemeTest.cxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <memory>
+#include <docsh.hxx>
+#include <unotxdoc.hxx>
+#include <wrtsh.hxx>
+#include <drawdoc.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <svx/svdpage.hxx>
+#include <docmodel/uno/UnoThemeColor.hxx>
+
+using namespace css;
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/theme/data/";
+
+class SwCoreThemeTest : public SwModelTestBase
+{
+};
+
+CPPUNIT_TEST_FIXTURE(SwCoreThemeTest, testThemeColorInHeading)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "ThemeColorInHeading.docx");
+ CPPUNIT_ASSERT(pDoc);
+
+ auto xThemeColor = getProperty<uno::Reference<util::XThemeColor>>(getParagraph(1),
+ "CharColorThemeReference");
+ model::ThemeColor aThemeColor;
+ model::theme::setFromXThemeColor(aThemeColor, xThemeColor);
+ CPPUNIT_ASSERT_EQUAL(model::ThemeColorType::Accent1, aThemeColor.getType());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreThemeTest, testDrawPageThemeExists)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "ThemeColorInHeading.docx");
+ CPPUNIT_ASSERT(pDoc);
+
+ SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
+ svx::Theme* pTheme = pPage->getSdrPageProperties().GetTheme();
+ CPPUNIT_ASSERT(pTheme);
+ CPPUNIT_ASSERT_EQUAL(OUString(u"Office Theme"), pTheme->GetName());
+
+ svx::ColorSet* pColorSet = pTheme->GetColorSet();
+ CPPUNIT_ASSERT(pColorSet);
+ CPPUNIT_ASSERT_EQUAL(OUString(u"Orange"), pColorSet->getName());
+
+ CPPUNIT_ASSERT_EQUAL(Color(0xE48312), pTheme->GetColor(model::ThemeColorType::Accent1));
+ CPPUNIT_ASSERT_EQUAL(Color(0xBD582C), pTheme->GetColor(model::ThemeColorType::Accent2));
+ CPPUNIT_ASSERT_EQUAL(Color(0x865640), pTheme->GetColor(model::ThemeColorType::Accent3));
+ CPPUNIT_ASSERT_EQUAL(Color(0x9B8357), pTheme->GetColor(model::ThemeColorType::Accent4));
+ CPPUNIT_ASSERT_EQUAL(Color(0xC2BC80), pTheme->GetColor(model::ThemeColorType::Accent5));
+ CPPUNIT_ASSERT_EQUAL(Color(0x94A088), pTheme->GetColor(model::ThemeColorType::Accent6));
+ CPPUNIT_ASSERT_EQUAL(Color(0x000000), pTheme->GetColor(model::ThemeColorType::Dark1));
+ CPPUNIT_ASSERT_EQUAL(Color(0x637052), pTheme->GetColor(model::ThemeColorType::Dark2));
+ CPPUNIT_ASSERT_EQUAL(Color(0xFFFFFF), pTheme->GetColor(model::ThemeColorType::Light1));
+ CPPUNIT_ASSERT_EQUAL(Color(0xCCDDEA), pTheme->GetColor(model::ThemeColorType::Light2));
+
+ svx::FontScheme const& rFontScheme = pTheme->getFontScheme();
+ CPPUNIT_ASSERT_EQUAL(OUString(u"Calibri Light"), rFontScheme.getMajorLatin().maTypeface);
+ CPPUNIT_ASSERT_EQUAL(OUString(u"Calibri"), rFontScheme.getMinorLatin().maTypeface);
+ CPPUNIT_ASSERT_EQUAL(true, rFontScheme.getMajorAsian().maTypeface.isEmpty());
+ CPPUNIT_ASSERT_EQUAL(true, rFontScheme.getMinorAsian().maTypeface.isEmpty());
+ CPPUNIT_ASSERT_EQUAL(true, rFontScheme.getMajorComplex().maTypeface.isEmpty());
+ CPPUNIT_ASSERT_EQUAL(true, rFontScheme.getMinorComplex().maTypeface.isEmpty());
+ CPPUNIT_ASSERT_EQUAL(size_t(47), rFontScheme.getMajorSupplementalFontList().size());
+ CPPUNIT_ASSERT_EQUAL(size_t(47), rFontScheme.getMinorSupplementalFontList().size());
+ CPPUNIT_ASSERT_EQUAL(OUString(u"Angsana New"),
+ rFontScheme.findMajorSupplementalTypeface(u"Thai"));
+ CPPUNIT_ASSERT_EQUAL(OUString(u"Cordia New"),
+ rFontScheme.findMinorSupplementalTypeface(u"Thai"));
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/theme/data/ThemeColorInHeading.docx b/sw/qa/core/theme/data/ThemeColorInHeading.docx
new file mode 100644
index 000000000000..e350c2676d41
--- /dev/null
+++ b/sw/qa/core/theme/data/ThemeColorInHeading.docx
Binary files differ
diff --git a/sw/qa/core/txtnode/txtnode.cxx b/sw/qa/core/txtnode/txtnode.cxx
index ad44a12f7c9b..5a88a2225846 100644
--- a/sw/qa/core/txtnode/txtnode.cxx
+++ b/sw/qa/core/txtnode/txtnode.cxx
@@ -25,6 +25,12 @@
#include <unotxdoc.hxx>
#include <docsh.hxx>
#include <formatcontentcontrol.hxx>
+#include <view.hxx>
+#include <edtwin.hxx>
+#include <txatbase.hxx>
+#include <ndtxt.hxx>
+#include <textcontentcontrol.hxx>
+#include <swdtflvr.hxx>
constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/txtnode/data/";
@@ -220,6 +226,128 @@ CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testInsertDropDownContentControlTwice)
pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);
}
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testCheckboxContentControlKeyboard)
+{
+ // Given an already selected checkbox content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);
+ SwEditWin& rEditWin = pWrtShell->GetView().GetEditWin();
+
+ // When pressing space on the keyboard:
+ KeyEvent aKeyEvent(' ', KEY_SPACE);
+ rEditWin.KeyInput(aKeyEvent);
+
+ // Then make sure the state is toggled:
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+ SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ // Without the accompanying fix in place, this test would have failed, because the state
+ // remained unchanged.
+ CPPUNIT_ASSERT(pContentControl->GetChecked());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDropdownContentControlKeyboard)
+{
+ // Given an already selected dropdown content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);
+
+ // When checking if alt-down should open a popup:
+ SwTextContentControl* pTextContentControl = pWrtShell->CursorInsideContentControl();
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ vcl::KeyCode aKeyCode(KEY_DOWN, KEY_MOD2);
+ bool bShouldOpen = pContentControl->ShouldOpenPopup(aKeyCode);
+
+ // Then make sure that the answer is yes for dropdowns:
+ // Without the accompanying fix in place, this test would have failed, the dropdown popup was
+ // mouse-only.
+ CPPUNIT_ASSERT(bShouldOpen);
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testPictureContentControlKeyboard)
+{
+ // Given an already selected picture content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::PICTURE);
+ pWrtShell->GotoObj(/*bNext=*/true, GotoObjFlags::Any);
+
+ // When checking if enter should trigger the file picker:
+ const SwFrameFormat* pFlyFormat = pWrtShell->GetFlyFrameFormat();
+ const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
+ const SwPosition* pAnchorPos = rFormatAnchor.GetContentAnchor();
+ SwTextNode* pTextNode = pAnchorPos->nNode.GetNode().GetTextNode();
+ SwTextAttr* pAttr = pTextNode->GetTextAttrAt(pAnchorPos->nContent.GetIndex(),
+ RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT);
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ bool bIsInteracting = pContentControl->IsInteractingCharacter('\r');
+
+ // Then make sure that the answer is yes for pictures:
+ // Without the accompanying fix in place, this test would have failed, the picture replacement
+ // file-picker was mouse-only.
+ CPPUNIT_ASSERT(bIsInteracting);
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDateContentControlKeyboard)
+{
+ // Given an already selected date content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::DATE);
+
+ // When checking if alt-down should open a popup:
+ SwTextContentControl* pTextContentControl = pWrtShell->CursorInsideContentControl();
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ vcl::KeyCode aKeyCode(KEY_DOWN, KEY_MOD2);
+ bool bShouldOpen = pContentControl->ShouldOpenPopup(aKeyCode);
+
+ // Then make sure that the answer is yes for date:
+ // Without the accompanying fix in place, this test would have failed, the date popup was
+ // mouse-only.
+ CPPUNIT_ASSERT(bShouldOpen);
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testContentControlCopy)
+{
+ // Given a document with a content control:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);
+
+ // When copying that content control:
+ pWrtShell->SelAll();
+ rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
+ xTransfer->Copy();
+ // Kill the selection, go to the end of the document:
+ pWrtShell->EndOfSection();
+ TransferableDataHelper aHelper(xTransfer);
+ SwTransferable::Paste(*pWrtShell, aHelper);
+
+ // Then make sure that the copy is also a checkbox:
+ SwContentControlManager& rManager = pDoc->GetContentControlManager();
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rManager.GetCount());
+ const SwFormatContentControl& rFormat1 = rManager.Get(0)->GetContentControl();
+ CPPUNIT_ASSERT_EQUAL(SwContentControlType::CHECKBOX, rFormat1.GetContentControl()->GetType());
+ const SwFormatContentControl& rFormat2 = rManager.Get(1)->GetContentControl();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1 (CHECKBOX)
+ // - Actual : 0 (RICH_TEXT)
+ // i.e. properties were not copied from the source to the destination content control.
+ CPPUNIT_ASSERT_EQUAL(SwContentControlType::CHECKBOX, rFormat2.GetContentControl()->GetType());
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/unocore/data/paragraph-marker-formatted-run.docx b/sw/qa/core/unocore/data/paragraph-marker-formatted-run.docx
new file mode 100644
index 000000000000..c0635c157cc9
--- /dev/null
+++ b/sw/qa/core/unocore/data/paragraph-marker-formatted-run.docx
Binary files differ
diff --git a/sw/qa/core/unocore/data/paragraph-marker.docx b/sw/qa/core/unocore/data/paragraph-marker.docx
new file mode 100644
index 000000000000..8dac2d96c76d
--- /dev/null
+++ b/sw/qa/core/unocore/data/paragraph-marker.docx
Binary files differ
diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx
index e7fd560b4370..1566481157e8 100644
--- a/sw/qa/core/unocore/unocore.cxx
+++ b/sw/qa/core/unocore/unocore.cxx
@@ -18,6 +18,7 @@
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <vcl/errinf.hxx>
+#include <editeng/wghtitem.hxx>
#include <wrtsh.hxx>
#include <unotextrange.hxx>
@@ -317,6 +318,15 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlInsert)
= static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
CPPUNIT_ASSERT(pContentControl->GetShowingPlaceHolder());
+
+ // Also verify that setText() and getText() works:
+ uno::Reference<text::XText> xContentControlText(xContentControl, uno::UNO_QUERY);
+ xContentControlText->setString("new");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: new
+ // - Actual :
+ // i.e. getString() always returned an empty string.
+ CPPUNIT_ASSERT_EQUAL(OUString("new"), xContentControlText->getString());
}
CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlTextPortionEnum)
@@ -562,6 +572,11 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDate)
xContentControlProps->setPropertyValue(
"DataBindingStoreItemID", uno::Any(OUString("{241A8A02-7FFD-488D-8827-63FBE74E8BC9}")));
xContentControlProps->setPropertyValue("Color", uno::Any(OUString("008000")));
+ xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("myalias")));
+ xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("mytag")));
+ xContentControlProps->setPropertyValue("Id", uno::Any(static_cast<sal_Int32>(123)));
+ xContentControlProps->setPropertyValue("TabIndex", uno::Any(sal_uInt32(1)));
+ xContentControlProps->setPropertyValue("Lock", uno::Any(OUString("sdtContentLocked")));
xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
// Then make sure that the specified properties are set:
@@ -585,6 +600,204 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDate)
CPPUNIT_ASSERT_EQUAL(OUString("{241A8A02-7FFD-488D-8827-63FBE74E8BC9}"),
pContentControl->GetDataBindingStoreItemID());
CPPUNIT_ASSERT_EQUAL(OUString("008000"), pContentControl->GetColor());
+ CPPUNIT_ASSERT_EQUAL(OUString("myalias"), pContentControl->GetAlias());
+ CPPUNIT_ASSERT_EQUAL(OUString("mytag"), pContentControl->GetTag());
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(123), pContentControl->GetId());
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(1), pContentControl->GetTabIndex());
+ CPPUNIT_ASSERT_EQUAL(OUString("sdtContentLocked"), pContentControl->GetLock());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlPlainText)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting a plain text content control around a text portion:
+ uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ xText->insertString(xCursor, "test", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->gotoEnd(/*bExpand=*/true);
+ uno::Reference<text::XTextContent> xContentControl(
+ xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ xContentControlProps->setPropertyValue("PlainText", uno::Any(true));
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+
+ // Then make sure that the text attribute is inserted:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
+ SwTextNode* pTextNode = pDoc->GetNodes()[nIndex]->GetTextNode();
+ SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
+ CPPUNIT_ASSERT(pAttr);
+ // Also verify that the type if plain text:
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ CPPUNIT_ASSERT(pContentControl->GetPlainText());
+
+ // Now check if the char index range 2-4 is extended to 0-6 when we apply formatting:
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ // Select "es" from "<dummy>test<dummy>".
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 2, /*bBasicCall=*/false);
+ SfxItemSetFixed<RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT> aSet(pWrtShell->GetAttrPool());
+ SvxWeightItem aItem(WEIGHT_BOLD, RES_CHRATR_WEIGHT);
+ aSet.Put(aItem);
+ pWrtShell->SetAttrSet(aSet);
+ pAttr = pTextNode->GetTextAttrAt(2, RES_TXTATR_AUTOFMT);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 2
+ // i.e. the plain text content control now had 3 portions (<dummy>t<b>es</b>t<dummy>), instead
+ // of one (<b><dummy>test<dummy></b>).
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), pAttr->GetStart());
+ CPPUNIT_ASSERT(pAttr->End());
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6), *pAttr->End());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlComboBox)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting a combobox content control:
+ uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ xText->insertString(xCursor, "test", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->gotoEnd(/*bExpand=*/true);
+ uno::Reference<text::XTextContent> xContentControl(
+ xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ {
+ uno::Sequence<beans::PropertyValues> aListItems = {
+ {
+ comphelper::makePropertyValue("DisplayText", uno::Any(OUString("red"))),
+ comphelper::makePropertyValue("Value", uno::Any(OUString("R"))),
+ },
+ {
+ comphelper::makePropertyValue("DisplayText", uno::Any(OUString("green"))),
+ comphelper::makePropertyValue("Value", uno::Any(OUString("G"))),
+ },
+ {
+ comphelper::makePropertyValue("DisplayText", uno::Any(OUString("blue"))),
+ comphelper::makePropertyValue("Value", uno::Any(OUString("B"))),
+ },
+ };
+ xContentControlProps->setPropertyValue("ListItems", uno::Any(aListItems));
+ // Without the accompanying fix in place, this test would have failed with:
+ // An uncaught exception of type com.sun.star.beans.UnknownPropertyException
+ xContentControlProps->setPropertyValue("ComboBox", uno::Any(true));
+ }
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+
+ // Then make sure that the specified properties are set:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPoint()->nNode.GetNode().GetTextNode();
+ SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ std::vector<SwContentControlListItem> aListItems = pContentControl->GetListItems();
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aListItems.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("red"), aListItems[0].m_aDisplayText);
+ CPPUNIT_ASSERT_EQUAL(OUString("R"), aListItems[0].m_aValue);
+ CPPUNIT_ASSERT(pContentControl->GetComboBox());
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControls)
+{
+ // Given an empty document:
+ createSwDoc();
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ uno::Reference<container::XIndexAccess> xContentControls = pXTextDocument->getContentControls();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), xContentControls->getCount());
+
+ // When inserting content controls:
+ uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ // First tag1.
+ xText->insertString(xCursor, "test1", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->gotoEnd(/*bExpand=*/true);
+ {
+ uno::Reference<text::XTextContent> xContentControl(
+ xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("tag1")));
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+ }
+ xCursor->gotoStart(/*bExpand=*/false);
+ // Then tag2 before tag1.
+ xText->insertString(xCursor, "test2", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->goRight(5, /*bExpand=*/true);
+ {
+ uno::Reference<text::XTextContent> xContentControl(
+ xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("tag2")));
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+ }
+
+ // Then make sure that XContentControls contains the items in a correct order:
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), xContentControls->getCount());
+ uno::Reference<beans::XPropertySet> xContentControl;
+ xContentControls->getByIndex(0) >>= xContentControl;
+ OUString aTag;
+ xContentControl->getPropertyValue("Tag") >>= aTag;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: tag2
+ // - Actual : tag1
+ // i.e. the order of the items was sorted by insert time, not by their doc model position.
+ CPPUNIT_ASSERT_EQUAL(OUString("tag2"), aTag);
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testParagraphMarkerODFExport)
+{
+ // Given a document with a red numbering portion, from the paragraph marker's format:
+ load(DATA_DIRECTORY, "paragraph-marker.docx");
+
+ // When saving that as ODT + reload:
+ reload("writer8", nullptr);
+
+ // Then make sure that it still has the correct color:
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 00ff0000 (COL_LIGHTRED)
+ // - Actual : ffffffff (COL_AUTO)
+ // i.e. the custom "red" color was lost as RES_PARATR_LIST_AUTOFMT was not serialized to ODT.
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("00ff0000"),
+ getXPath(pXmlDoc, "//Special[@nType='PortionType::Number']/SwFont", "color"));
+}
+
+CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testParagraphMarkerFormattedRun)
+{
+ // Given a document with a bold run and non-bold paragraph marker:
+ load(DATA_DIRECTORY, "paragraph-marker-formatted-run.docx");
+
+ // When saving that as ODT + reload:
+ reload("writer8", nullptr);
+
+ // Then make sure that the numbering portion is still non-bold, matching Word:
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 5 (WEIGHT_NORMAL)
+ // - Actual : 8 (WEIGHT_BOLD)
+ // i.e. the numbering portion was bold, while its weight should be normal.
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("5"),
+ getXPath(pXmlDoc, "//Special[@nType='PortionType::Number']/SwFont", "weight"));
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 21feaa0b5e73..f5b965b2b94b 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -208,6 +208,13 @@ public:
rStream.Seek(0);
}
+ static void wrapHTMLFragment(const utl::TempFile& rTempFile, SvMemoryStream& rStream)
+ {
+ SvFileStream aFileStream(rTempFile.GetURL(), StreamMode::READ);
+ rStream.WriteStream(aFileStream);
+ rStream.Seek(0);
+ }
+
/// Wraps an RTF fragment into a complete RTF file, so an RTF parser can handle it.
static void wrapRtfFragment(const OUString& rURL, SvMemoryStream& rStream)
{
@@ -284,6 +291,8 @@ public:
void ExportToReqif();
/// Import using the C++ HTML import filter, with xhtmlns=reqif-xhtml.
void ImportFromReqif(const OUString& rUrl);
+ /// Export using the C++ HTML export filter
+ void ExportToHTML();
};
OUString SwHtmlDomExportTest::GetOlePath()
@@ -338,6 +347,15 @@ void SwHtmlDomExportTest::ExportToReqif()
xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
}
+void SwHtmlDomExportTest::ExportToHTML()
+{
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+}
+
void SwHtmlDomExportTest::ImportFromReqif(const OUString& rUrl)
{
uno::Sequence<beans::PropertyValue> aLoadProperties = {
@@ -797,16 +815,24 @@ DECLARE_HTMLEXPORT_TEST(testReqIfJpgImg, "reqif-jpg-img.xhtml")
DECLARE_HTMLEXPORT_TEST(testReqIfTable, "reqif-table.xhtml")
{
- htmlDocUniquePtr pDoc = parseHtml(maTempFile);
+ SvMemoryStream aStream;
+ HtmlExportTest::wrapFragment(maTempFile, aStream);
+ xmlDocUniquePtr pDoc = parseXmlStream(&aStream);
CPPUNIT_ASSERT(pDoc);
// <div> was missing, so the XHTML fragment wasn't a valid
// xhtml.BlkStruct.class type anymore.
- assertXPath(pDoc, "/html/body/div/table/tr/th", 1);
+ assertXPath(pDoc,
+ "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr/reqif-xhtml:th",
+ 1);
// Make sure that the cell background is not written using CSS.
- assertXPathNoAttribute(pDoc, "/html/body/div/table/tr/th", "style");
+ assertXPathNoAttribute(
+ pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr/reqif-xhtml:th",
+ "style");
// The attribute was present, which is not valid in reqif-xhtml.
- assertXPathNoAttribute(pDoc, "/html/body/div/table/tr/th", "bgcolor");
+ assertXPathNoAttribute(
+ pDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr/reqif-xhtml:th",
+ "bgcolor");
}
DECLARE_HTMLEXPORT_TEST(testReqIfTable2, "reqif-table2.odt")
@@ -1535,6 +1561,49 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testPartiallyNumberedList)
"/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol/reqif-xhtml:li/reqif-xhtml:p", 2);
}
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testPartiallyNumberedListHTML)
+{
+ // Given a document with a list, first para is numbered, second is not:
+ loadURL("private:factory/swriter", nullptr);
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("list header");
+ SwDoc* pDoc = pWrtShell->GetDoc();
+ sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName());
+ SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos];
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->nNode.GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ }
+ pWrtShell->Insert2("numbered");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert2("not numbered");
+ {
+ SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->nNode.GetNode();
+ SwTextNode& rTextNode = *rNode.GetTextNode();
+ rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName()));
+ rTextNode.SetCountedInList(false);
+ }
+
+ // When exporting to HTML:
+ ExportToHTML();
+
+ SvMemoryStream aStream;
+ HtmlExportTest::wrapHTMLFragment(maTempFile, aStream);
+
+ xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
+ CPPUNIT_ASSERT(pXmlDoc); // if we have missing closing marks - parse error
+
+ // Without the accompanying fix in place, this test would have failed:
+ // - expected: <li><p>...</p><p>...</p></li>
+ // - actual : <li><p>...</p><p>...</p>
+ // because a <li> without a matching </li> is not well-formed, and the </li> was omitted because
+ // the second para was not numbered.
+
+ assertXPath(pXmlDoc, "/html/body/ol/li/p", 2);
+}
+
CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testListHeaderAndItem)
{
// Given a document with a list, first para is not numbered, but the second is:
@@ -2280,6 +2349,63 @@ CPPUNIT_TEST_FIXTURE(HtmlExportTest, testImageKeepRatio)
assertXPath(pDoc, "/html/body/p/img", "height", "auto");
}
+CPPUNIT_TEST_FIXTURE(HtmlExportTest, testTdf114769)
+{
+ // Create document from scratch since relative urls to filesystem can be replaced
+ // by absolute during save/load
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("Hyperlink1");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("Hyperlink2");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("Hyperlink3");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("Hyperlink4");
+ pWrtShell->SplitNode();
+ pWrtShell->Insert("Hyperlink5");
+ pWrtShell->SplitNode();
+
+ // Normal external URL
+ uno::Reference<beans::XPropertySet> xRun(getRun(getParagraph(1), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString("http://libreoffice.org/")));
+
+ // Bookmark reference
+ xRun.set(getRun(getParagraph(2), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString("#some_bookmark")));
+
+ // Filesystem absolute link
+ xRun.set(getRun(getParagraph(3), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString("C:\\test.txt")));
+
+ // Filesystem relative link
+ xRun.set(getRun(getParagraph(4), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString("..\\..\\test.odt")));
+
+ // Filesystem relative link
+ xRun.set(getRun(getParagraph(5), 1), uno::UNO_QUERY);
+ xRun->setPropertyValue("HyperLinkURL", uno::Any(OUString(".\\another.odt")));
+
+ // Export
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ uno::Sequence<beans::PropertyValue> aStoreProperties
+ = { comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")) };
+ xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
+
+ htmlDocUniquePtr pHtmlDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pHtmlDoc);
+
+ CPPUNIT_ASSERT_EQUAL(OUString("http://libreoffice.org/"),
+ getXPath(pHtmlDoc, "/html/body/p[1]/a", "href"));
+ CPPUNIT_ASSERT_EQUAL(OUString("#some_bookmark"),
+ getXPath(pHtmlDoc, "/html/body/p[2]/a", "href"));
+ CPPUNIT_ASSERT_EQUAL(OUString("C:\\test.txt"), getXPath(pHtmlDoc, "/html/body/p[3]/a", "href"));
+ CPPUNIT_ASSERT_EQUAL(OUString("..\\..\\test.odt"),
+ getXPath(pHtmlDoc, "/html/body/p[4]/a", "href"));
+ CPPUNIT_ASSERT_EQUAL(OUString(".\\another.odt"),
+ getXPath(pHtmlDoc, "/html/body/p[5]/a", "href"));
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/htmlimport/data/green-highlight.html b/sw/qa/extras/htmlimport/data/green-highlight.html
new file mode 100644
index 000000000000..b8986e78ffd8
--- /dev/null
+++ b/sw/qa/extras/htmlimport/data/green-highlight.html
@@ -0,0 +1 @@
+<p><span style="background-color: #5fb23680">Highlight green (transparency: 0.5)</span></p>
diff --git a/sw/qa/extras/htmlimport/data/tdf155011.html b/sw/qa/extras/htmlimport/data/tdf155011.html
new file mode 100644
index 000000000000..b3bc7845b56a
--- /dev/null
+++ b/sw/qa/extras/htmlimport/data/tdf155011.html
@@ -0,0 +1,31 @@
+<html>
+ <body>
+ <table>
+ <tr>
+ <td>
+ <div id="foo1">
+ <table>
+ <tr>
+ <td>
+ <div id="foo2">
+ <form>
+ <table>
+ <tr>
+ <td>
+ <input type="radio"/>
+ </td>
+ </tr>
+ </table>
+ </form>
+ <div id="foo3"/>
+ <div id="foo4"/>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ </table>
+ </body>
+</html> \ No newline at end of file
diff --git a/sw/qa/extras/htmlimport/htmlimport.cxx b/sw/qa/extras/htmlimport/htmlimport.cxx
index 00e2ec99191f..3ed2ce922c68 100644
--- a/sw/qa/extras/htmlimport/htmlimport.cxx
+++ b/sw/qa/extras/htmlimport/htmlimport.cxx
@@ -536,6 +536,24 @@ CPPUNIT_TEST_FIXTURE(HtmlImportTest, testUTF16_nonBMP)
getParagraph(1)->getString());
}
+CPPUNIT_TEST_FIXTURE(HtmlImportTest, testRGBAColor)
+{
+ load(mpTestDocumentPath, "green-highlight.html");
+ const uno::Reference<text::XTextRange> xPara = getParagraph(1);
+ const uno::Reference<beans::XPropertySet> xRun(getRun(xPara,1), uno::UNO_QUERY);
+ const Color nBackColor(0xaed89a);
+
+ // Without the accompanying fix in place, this test would have failed, the backround
+ // color was not imported at all, when it was in hex RGBA format in HTML.
+ CPPUNIT_ASSERT_EQUAL(nBackColor, getProperty<Color>(xRun, "CharBackColor"));
+}
+
+CPPUNIT_TEST_FIXTURE(HtmlImportTest, testTdf155011)
+{
+ load(mpTestDocumentPath, "tdf155011.html");
+ // Must not crash / fail asserts
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/layout/data/tdf155611_table_and_nested_section.fodt b/sw/qa/extras/layout/data/tdf155611_table_and_nested_section.fodt
new file mode 100644
index 000000000000..28c0701ea2fc
--- /dev/null
+++ b/sw/qa/extras/layout/data/tdf155611_table_and_nested_section.fodt
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:section text:name="Outer section">
+ <table:table>
+ <table:table-column table:number-columns-repeated="2"/>
+ <table:table-row>
+ <table:table-cell>
+ <text:p>foo</text:p>
+ </table:table-cell>
+ <table:table-cell>
+ <text:p>bar</text:p>
+ <table:table>
+ <table:table-column/>
+ <table:table-row>
+ <table:table-cell>
+ <text:p>baz</text:p>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:section text:name="Inner section">
+ <text:p>abc</text:p>
+ </text:section>
+ </text:section>
+ <text:p/>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/layout/data/three_sections.fodt b/sw/qa/extras/layout/data/three_sections.fodt
new file mode 100644
index 000000000000..9233fed89085
--- /dev/null
+++ b/sw/qa/extras/layout/data/three_sections.fodt
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:p>Select the text below, copy to clipboard, and paste from clipboard, replacing the selection.</text:p>
+ <text:section text:name="Section1">
+ <text:p>&lt;-- Start selection here. Section1</text:p>
+ </text:section>
+ <text:section text:name="Section2">
+ <text:p>Section2</text:p>
+ </text:section>
+ <text:section text:name="Section3">
+ <text:p>Section3. End selection here --&gt;</text:p>
+ </text:section>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx
index 466f640beeee..70ebd9843ceb 100644
--- a/sw/qa/extras/layout/layout2.cxx
+++ b/sw/qa/extras/layout/layout2.cxx
@@ -19,6 +19,7 @@
#include <i18nlangtag/languagetag.hxx>
#include <editeng/unolingu.hxx>
#include <svx/svdobj.hxx>
+#include <vcl/scheduler.hxx>
#include <unotxdoc.hxx>
#include <rootfrm.hxx>
@@ -1089,7 +1090,7 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf129054)
"/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/push[4]/polyline[1]/point[31]",
"y")
.toInt32();
- CPPUNIT_ASSERT_DOUBLES_EQUAL(4810, nYTop - nYBottom, 5);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(4615, nYTop - nYBottom, 5);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf129173)
@@ -1141,7 +1142,7 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf137116)
// - Actual : -225
// - Delta : 100
// i.e. the second data label appeared inside the pie slice.
- CPPUNIT_ASSERT_DOUBLES_EQUAL(694, nX2 - nX4, 100);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(631, nX2 - nX4, 100);
}
CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf137154)
@@ -1773,6 +1774,75 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testUserFieldTypeLanguage)
"1,234.56");
}
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf154113)
+{
+ createSwDoc(DATA_DIRECTORY, "three_sections.fodt");
+ Scheduler::ProcessEventsToIdle();
+
+ dispatchCommand(mxComponent, ".uno:GoToStartOfDoc", {});
+ dispatchCommand(mxComponent, ".uno:GoToNextPara", {});
+ dispatchCommand(mxComponent, ".uno:EndOfDocumentSel", {}); // to the end of current section!
+ dispatchCommand(mxComponent, ".uno:EndOfDocumentSel", {}); // to the end of the document.
+
+ uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xSelected(xModel->getCurrentSelection(),
+ uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelected->getCount());
+ uno::Reference<text::XTextRange> xRange(xSelected->getByIndex(0), uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(OUString("<-- Start selection here. Section1" SAL_NEWLINE_STRING
+ "Section2" SAL_NEWLINE_STRING "Section3. End selection here -->"),
+ xRange->getString());
+
+ dispatchCommand(mxComponent, ".uno:Cut", {});
+
+ xSelected.set(xModel->getCurrentSelection(), uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelected->getCount());
+ xRange.set(xSelected->getByIndex(0), uno::UNO_QUERY_THROW);
+ CPPUNIT_ASSERT_EQUAL(OUString(), xRange->getString());
+
+ dispatchCommand(mxComponent, ".uno:Paste", {});
+
+ xmlDocUniquePtr pXml = parseLayoutDump();
+
+ // Without the fix in place, this would fail with
+ // - Expected: 3
+ // - Actual : 2
+ assertXPath(pXml, "/root/page/body/section", 3);
+ assertXPath(pXml, "/root/page/body/section[1]/txt/Text", "Portion",
+ "<-- Start selection here. Section1");
+ assertXPath(pXml, "/root/page/body/section[2]/txt/Text", "Portion", "Section2");
+ assertXPath(pXml, "/root/page/body/section[3]/txt/Text", "Portion",
+ "Section3. End selection here -->");
+}
+
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf155611)
+{
+ createSwDoc(DATA_DIRECTORY, "tdf155611_table_and_nested_section.fodt");
+ Scheduler::ProcessEventsToIdle();
+
+ xmlDocUniquePtr pXml = parseLayoutDump();
+ CPPUNIT_ASSERT(pXml);
+
+ // Check the layout: single page, two section frames (no section frames after the one for Inner
+ // section), correct table structure and content in the first section frame, including nested
+ // table in the last cell, and the last section text.
+ assertXPath(pXml, "/root/page");
+ // Without the fix in place, this would fail with
+ // - Expected: 2
+ // - Actual : 3
+ assertXPath(pXml, "/root/page/body/section", 2);
+ assertXPath(pXml, "/root/page/body/section[1]/tab");
+ assertXPath(pXml, "/root/page/body/section[1]/tab/row");
+ assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell", 2);
+ assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell[1]/txt/Text[@Portion='foo']");
+ assertXPath(pXml, "/root/page/body/section[1]/tab/row/cell[2]/txt/Text[@Portion='bar']");
+ assertXPath(pXml,
+ "/root/page/body/section[1]/tab/row/cell[2]/tab/row/cell/txt/Text[@Portion='baz']");
+ assertXPath(pXml, "/root/page/body/section[2]/txt[1]/Text[@Portion='abc']");
+
+ // Also must not crash on close because of a frame that accidentally fell off of the layout
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/odfexport/data/section-columns-separator.fodt b/sw/qa/extras/odfexport/data/section-columns-separator.fodt
new file mode 100644
index 000000000000..b9c97eb9e38e
--- /dev/null
+++ b/sw/qa/extras/odfexport/data/section-columns-separator.fodt
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:style style:name="Sect1" style:family="section">
+ <style:section-properties text:dont-balance-text-columns="false" style:editable="false">
+ <style:columns fo:column-count="2" fo:column-gap="0.6cm">
+ <style:column-sep style:width="0.009cm" style:color="#99AABB" style:height="50%" style:style="dotted" style:vertical-align="bottom"/>
+ <style:column style:rel-width="32767*" fo:start-indent="0cm" fo:end-indent="0.248cm"/>
+ <style:column style:rel-width="32768*" fo:start-indent="0.248cm" fo:end-indent="0cm"/>
+ </style:columns>
+ </style:section-properties>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:section text:style-name="Sect1" text:name="Section1">
+ <text:p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum consequat mi quis pretium semper. Proin luctus orci ac neque venenatis, quis commodo dolor posuere. Curabitur dignissim sapien quis cursus egestas. Donec blandit auctor arcu, nec pellentesque eros molestie eget. In consectetur aliquam hendrerit. Sed cursus mauris vitae ligula pellentesque, non pellentesque urna aliquet. Fusce placerat mauris enim, nec rutrum purus semper vel. Praesent tincidunt neque eu pellentesque pharetra. Fusce pellentesque est orci.</text:p>
+ <text:p>Integer sodales tincidunt tristique. Sed a metus posuere, adipiscing nunc et, viverra odio. Donec auctor molestie sem, sit amet tristique lectus hendrerit sed. Cras sodales nisl sed orci mattis iaculis. Nunc eget dolor accumsan, pharetra risus a, vestibulum mauris. Nunc vulputate lobortis mollis. Vivamus nec tellus faucibus, tempor magna nec, facilisis felis. Donec commodo enim a vehicula pellentesque. Nullam vehicula vestibulum est vel ultricies.</text:p>
+ <text:p>Aliquam velit massa, laoreet vel leo nec, volutpat facilisis eros. Donec consequat arcu ut diam tempor luctus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Praesent vitae lacus vel leo sodales pharetra a a nibh. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nam luctus tempus nibh, fringilla dictum augue consectetur eget. Curabitur at ante sit amet tortor pharetra molestie eu nec ante. Mauris tincidunt, nibh eu sollicitudin molestie, dolor sapien congue tortor, a pulvinar sapien turpis sed ante. Donec nec est elementum, euismod nulla in, mollis nunc.</text:p>
+ </text:section>
+ </office:text>
+ </office:body>
+</office:document> \ No newline at end of file
diff --git a/sw/qa/extras/odfexport/data/table-in-frame-in-table-in-header-base.odt b/sw/qa/extras/odfexport/data/table-in-frame-in-table-in-header-base.odt
new file mode 100644
index 000000000000..44dbf0bdec69
--- /dev/null
+++ b/sw/qa/extras/odfexport/data/table-in-frame-in-table-in-header-base.odt
Binary files differ
diff --git a/sw/qa/extras/odfexport/data/tdf151100.docx b/sw/qa/extras/odfexport/data/tdf151100.docx
new file mode 100644
index 000000000000..e0341bdb9c8c
--- /dev/null
+++ b/sw/qa/extras/odfexport/data/tdf151100.docx
Binary files differ
diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx
index 87e2aead4997..d57712f593bc 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -941,7 +941,7 @@ DECLARE_ODFEXPORT_TEST(testTdf134987, "tdf134987.docx")
OUString aMediaType;
// checking first object (formula)
{
- uno::Reference<document::XEmbeddedObjectSupplier> xEOSupplier(xAccess->getByName("1"), uno::UNO_QUERY);
+ uno::Reference<document::XEmbeddedObjectSupplier> xEOSupplier(xAccess->getByName("Object1"), uno::UNO_QUERY);
uno::Reference<lang::XComponent> xObj(xEOSupplier->getEmbeddedObject());
CPPUNIT_ASSERT(xObj.is());
@@ -955,7 +955,7 @@ DECLARE_ODFEXPORT_TEST(testTdf134987, "tdf134987.docx")
}
// checking second object (chart)
{
- uno::Reference<document::XEmbeddedObjectSupplier> xEOSupplier(xAccess->getByName("2"), uno::UNO_QUERY);
+ uno::Reference<document::XEmbeddedObjectSupplier> xEOSupplier(xAccess->getByName("Object2"), uno::UNO_QUERY);
uno::Reference<lang::XComponent> xObj(xEOSupplier->getEmbeddedObject());
CPPUNIT_ASSERT(xObj.is());
@@ -969,7 +969,7 @@ DECLARE_ODFEXPORT_TEST(testTdf134987, "tdf134987.docx")
}
// checking third object (chart)
{
- uno::Reference<document::XEmbeddedObjectSupplier> xEOSupplier(xAccess->getByName("3"), uno::UNO_QUERY);
+ uno::Reference<document::XEmbeddedObjectSupplier> xEOSupplier(xAccess->getByName("Object3"), uno::UNO_QUERY);
uno::Reference<lang::XComponent> xObj(xEOSupplier->getEmbeddedObject());
CPPUNIT_ASSERT(xObj.is());
@@ -3154,6 +3154,20 @@ DECLARE_ODFEXPORT_EXPORTONLY_TEST(tdf135942, "nestedTableInFooter.odt")
assertXPath(pXmlDoc, "/office:document-styles/office:automatic-styles/style:style[@style:family='table']", 2);
}
+CPPUNIT_TEST_FIXTURE(Test, tdf150927)
+{
+ // Similar to tdf135942
+
+ loadAndReload("table-in-frame-in-table-in-header-base.odt");
+ // All table autostyles should be collected, including nested, and must not crash.
+
+ CPPUNIT_ASSERT_EQUAL(1, getPages());
+
+ xmlDocUniquePtr pXmlDoc = parseExport("styles.xml");
+
+ assertXPath(pXmlDoc, "/office:document-styles/office:automatic-styles/style:style[@style:family='table']", 2);
+}
+
DECLARE_ODFEXPORT_TEST(testGutterLeft, "gutter-left.odt")
{
CPPUNIT_ASSERT_EQUAL(1, getPages());
diff --git a/sw/qa/extras/odfexport/odfexport2.cxx b/sw/qa/extras/odfexport/odfexport2.cxx
index c9eb4cdd18aa..9a1345812f13 100644
--- a/sw/qa/extras/odfexport/odfexport2.cxx
+++ b/sw/qa/extras/odfexport/odfexport2.cxx
@@ -10,6 +10,9 @@
#include <swmodeltestbase.hxx>
#include <unotxdoc.hxx>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <com/sun/star/text/ColumnSeparatorStyle.hpp>
+#include <com/sun/star/text/XTextColumns.hpp>
#include <com/sun/star/text/XTextTable.hpp>
class Test : public SwModelTestBase
@@ -32,6 +35,20 @@ public:
};
+CPPUNIT_TEST_FIXTURE(Test, tdf151100)
+{
+ // Similar to tdf135942
+
+ loadAndReload("tdf151100.docx");
+ // All table autostyles should be collected, including nested, and must not crash.
+
+ CPPUNIT_ASSERT_EQUAL(1, getPages());
+
+ xmlDocUniquePtr pXmlDoc = parseExport("styles.xml");
+
+ assertXPath(pXmlDoc, "/office:document-styles/office:automatic-styles/style:style[@style:family='table']", 1);
+}
+
DECLARE_ODFEXPORT_TEST(testTdf52065_centerTabs, "testTdf52065_centerTabs.odt")
{
CPPUNIT_ASSERT_EQUAL(1, getPages());
@@ -219,5 +236,37 @@ CPPUNIT_TEST_FIXTURE(Test, testStyleLink)
// This test started in LO 7.2. Use the odfexport.cxx if you intend to backport to 7.1.
+DECLARE_ODFEXPORT_TEST(testSectionColumnSeparator, "section-columns-separator.fodt")
+{
+ // tdf#150235: due to wrong types used in column export, 'style:height' and 'style:style'
+ // attributes were exported incorrectly for 'style:column-sep' element
+ auto xSection = getProperty<uno::Reference<uno::XInterface>>(getParagraph(1), "TextSection");
+ auto xColumns = getProperty<uno::Reference<text::XTextColumns>>(xSection, "TextColumns");
+ CPPUNIT_ASSERT(xColumns);
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(2), xColumns->getColumnCount());
+
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 50
+ // - Actual : 100
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(50),
+ getProperty<sal_Int32>(xColumns, "SeparatorLineRelativeHeight"));
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2
+ // - Actual : 0
+ CPPUNIT_ASSERT_EQUAL(css::text::ColumnSeparatorStyle::DOTTED,
+ getProperty<sal_Int16>(xColumns, "SeparatorLineStyle"));
+
+ // Check the rest of the properties, too
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xColumns, "IsAutomatic"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(600), getProperty<sal_Int32>(xColumns, "AutomaticDistance"));
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(9), getProperty<sal_Int32>(xColumns, "SeparatorLineWidth"));
+ CPPUNIT_ASSERT_EQUAL(Color(0x99, 0xAA, 0xBB),
+ getProperty<Color>(xColumns, "SeparatorLineColor"));
+ CPPUNIT_ASSERT_EQUAL(
+ css::style::VerticalAlignment_BOTTOM,
+ getProperty<css::style::VerticalAlignment>(xColumns, "SeparatorLineVerticalAlignment"));
+ CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xColumns, "SeparatorLineIsOn"));
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/odfimport/data/tdf149978.fodt b/sw/qa/extras/odfimport/data/tdf149978.fodt
new file mode 100644
index 000000000000..5c4840c258fc
--- /dev/null
+++ b/sw/qa/extras/odfimport/data/tdf149978.fodt
@@ -0,0 +1,53 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<office:document xmlns:officeooo="http://openoffice.org/2009/office" xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rpt="http://openoffice.org/2005/report" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:xforms="http://www.w3.org/2002/xforms" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:font-face-decls>
+ <style:font-face style:font-family-generic="roman" style:font-pitch="variable" style:name="Times New Roman" svg:font-family="'Times New Roman'"/>
+ <style:font-face style:font-family-generic="system" style:font-pitch="variable" style:name="Lucida Sans Unicode" svg:font-family="'Lucida Sans Unicode'"/>
+ <style:font-face style:font-family-generic="system" style:font-pitch="variable" style:name="Tahoma" svg:font-family="Tahoma"/>
+ </office:font-face-decls>
+ <office:styles>
+ <style:default-style style:family="paragraph">
+ <style:paragraph-properties fo:hyphenation-ladder-count="no-limit" style:line-break="strict" style:punctuation-wrap="hanging" style:tab-stop-distance="1.251cm" style:text-autospace="ideograph-alpha" style:writing-mode="page"/>
+ <style:text-properties fo:country="DE" fo:font-size="12pt" fo:hyphenate="false" fo:hyphenation-push-char-count="2" fo:hyphenation-remain-char-count="2" fo:language="de" style:country-asian="none" style:country-complex="none" style:font-name="Times New Roman" style:font-name-asian="Lucida Sans Unicode" style:font-name-complex="Tahoma" style:font-size-asian="12pt" style:font-size-complex="12pt" style:language-asian="zxx" style:language-complex="zxx" style:letter-kerning="true" style:use-window-font-color="true"/>
+ </style:default-style>
+ </office:styles>
+
+ <office:automatic-styles>
+ <style:style style:family="text" style:name="A25" style:parent-style-name="">
+ <style:text-properties fo:background-color="#d3d3d3"/>
+ </style:style>
+ <style:style style:family="text" style:name="A26" style:parent-style-name="">
+ <style:text-properties fo:background-color="inherit" fo:color="inherit"/>
+ </style:style>
+
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="21.001cm" fo:page-height="29.7cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0cm" loext:margin-gutter="0cm">
+ <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
+ </style:page-layout-properties>
+ <style:header-style/>
+ <style:footer-style/>
+ </style:page-layout>
+ <style:style style:name="dp1" style:family="drawing-page">
+ <style:drawing-page-properties draw:background-size="full"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard" style:page-layout-name="pm1" draw:style-name="dp1"/>
+ </office:master-styles>
+ <office:body>
+ <office:text>
+
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+ <text:p>foo <text:span text:style-name="A25"><text:span text:style-name="A26">bar</text:span></text:span> baz</text:p>
+
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/odfimport/odfimport.cxx b/sw/qa/extras/odfimport/odfimport.cxx
index 9c177f981aa4..b6f242601f5f 100644
--- a/sw/qa/extras/odfimport/odfimport.cxx
+++ b/sw/qa/extras/odfimport/odfimport.cxx
@@ -371,6 +371,18 @@ CPPUNIT_TEST_FIXTURE(Test, testDateFormFormats)
}
}
+CPPUNIT_TEST_FIXTURE(Test, testTdf149978)
+{
+ load(mpTestDocumentPath, "tdf149978.fodt");
+ // on Linux the bug only reproduces if a document has been loaded previously
+ load(mpTestDocumentPath, "tdf149978.fodt");
+ // this was nondeterministic so try 10 times
+ for (int i = 1; i <= 10; ++i)
+ {
+ CPPUNIT_ASSERT_EQUAL(COL_WHITE, getProperty<Color>(getRun(getParagraph(i), 2, "bar"), "CharBackColor"));
+ }
+}
+
CPPUNIT_TEST_FIXTURE(Test, testTdf64038)
{
load(mpTestDocumentPath, "space.odt");
diff --git a/sw/qa/extras/ooxmlexport/data/content-control-grab-bag.docx b/sw/qa/extras/ooxmlexport/data/content-control-grab-bag.docx
new file mode 100644
index 000000000000..33c01f08fd25
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/content-control-grab-bag.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/crop-roundtrip.docx b/sw/qa/extras/ooxmlexport/data/crop-roundtrip.docx
new file mode 100644
index 000000000000..6db60d0e8c60
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/crop-roundtrip.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docx b/sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docx
new file mode 100644
index 000000000000..5ec375adf3ac
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/glossaryWithEmail.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/inline-sdt-header.docx b/sw/qa/extras/ooxmlexport/data/inline-sdt-header.docx
new file mode 100644
index 000000000000..0a6009c2cd1b
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/inline-sdt-header.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/number-portion-format.odt b/sw/qa/extras/ooxmlexport/data/number-portion-format.odt
new file mode 100644
index 000000000000..66f3b175b50a
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/number-portion-format.odt
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/sdt-duplicated-id.docx b/sw/qa/extras/ooxmlexport/data/sdt-duplicated-id.docx
new file mode 100644
index 000000000000..d21894df3007
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/sdt-duplicated-id.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf125338.docm b/sw/qa/extras/ooxmlexport/data/tdf125338.docm
new file mode 100644
index 000000000000..44e943531d30
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf125338.docm
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf141652_fillBitmapName.docx b/sw/qa/extras/ooxmlexport/data/tdf141652_fillBitmapName.docx
deleted file mode 100644
index 4a47a544d6bb..000000000000
--- a/sw/qa/extras/ooxmlexport/data/tdf141652_fillBitmapName.docx
+++ /dev/null
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf146955.odt b/sw/qa/extras/ooxmlexport/data/tdf146955.odt
new file mode 100644
index 000000000000..c7a849f9b756
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf146955.odt
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf147892.fodt b/sw/qa/extras/ooxmlexport/data/tdf147892.fodt
new file mode 100644
index 000000000000..bb3ffc324dc1
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf147892.fodt
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:body>
+ <office:text>
+ <text:tracked-changes text:track-changes="false">
+ <text:changed-region xml:id="ct12345678" text:id="ct12345678">
+ <text:deletion>
+ <office:change-info>
+ <dc:creator>Bob</dc:creator>
+ <dc:date>2023-01-02T00:00:00</dc:date>
+ </office:change-info>
+ </text:deletion>
+ <text:insertion>
+ <office:change-info>
+ <dc:creator>Alice</dc:creator>
+ <dc:date>2023-01-01T00:00:00</dc:date>
+ </office:change-info>
+ </text:insertion>
+ </text:changed-region>
+ </text:tracked-changes>
+ <text:p><text:change-start text:change-id="ct12345678"/></text:p>
+ <text:p><text:change-end text:change-id="ct12345678"/></text:p>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/ooxmlexport/data/tdf150966_regularInset.docx b/sw/qa/extras/ooxmlexport/data/tdf150966_regularInset.docx
new file mode 100644
index 000000000000..0d07a5453e35
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf150966_regularInset.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf151548_activeContentDemo.docm b/sw/qa/extras/ooxmlexport/data/tdf151548_activeContentDemo.docm
new file mode 100644
index 000000000000..80886d864a15
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf151548_activeContentDemo.docm
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf152200-field+textbox.docx b/sw/qa/extras/ooxmlexport/data/tdf152200-field+textbox.docx
new file mode 100644
index 000000000000..606d1346a27a
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf152200-field+textbox.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf152425.docx b/sw/qa/extras/ooxmlexport/data/tdf152425.docx
new file mode 100644
index 000000000000..53a65cc63438
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf152425.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf152636_lostPageBreak2.docx b/sw/qa/extras/ooxmlexport/data/tdf152636_lostPageBreak2.docx
new file mode 100644
index 000000000000..255bf795a5e2
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf152636_lostPageBreak2.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf153613_sdtAfterPgBreak.docx b/sw/qa/extras/ooxmlexport/data/tdf153613_sdtAfterPgBreak.docx
new file mode 100644
index 000000000000..fa62b475cfaa
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf153613_sdtAfterPgBreak.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak14.docx b/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak14.docx
new file mode 100644
index 000000000000..6c57bcfdc8ef
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak14.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak15.docx b/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak15.docx
new file mode 100644
index 000000000000..e4d5c45ed034
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf153964_topMarginAfterBreak15.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/data/tdf157136_TwoContentControls.docx b/sw/qa/extras/ooxmlexport/data/tdf157136_TwoContentControls.docx
new file mode 100644
index 000000000000..f4e898cb057f
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf157136_TwoContentControls.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
index c97acffdc038..4827c8773ebe 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
@@ -1146,6 +1146,12 @@ DECLARE_OOXMLEXPORT_TEST(testTdf95775, "tdf95775.docx")
DECLARE_OOXMLEXPORT_TEST(testTdf92157, "tdf92157.docx")
{
// A graphic with dimensions 0,0 should not fail on load
+
+ // Additionally, the bookmark names should not change (they got a "1" appended when copied)
+ uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XNameAccess> xBookmarksByName = xBookmarksSupplier->getBookmarks();
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("referentiegegevens"));
+ CPPUNIT_ASSERT(xBookmarksByName->hasByName("referentiegegevens_bk"));
}
DECLARE_OOXMLEXPORT_TEST(testTdf97417, "section_break_numbering.docx")
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
index d7d0784e7285..f62571ff57fc 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx
@@ -1403,7 +1403,8 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf88496)
// Switch off repeating header, there is no place for it.
// Now there are only 3 pages with complete table content
// instead of a 51-page long table only with header.
- CPPUNIT_ASSERT_EQUAL(2, getPages());
+ CPPUNIT_ASSERT_EQUAL(3, getPages());
+ // (this appears to have the correct result now?)
// FIXME: this actually has 3 pages but SwWrtShell::SttPg() puts the cursor
// into the single SwTextFrame in the follow-flow-row at the top of the
// table but that SwTextFrame 1105 should not exist and the cursor ends up
@@ -1571,6 +1572,16 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf142387)
assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:ins/w:del/w:r/w:delText", "inserts ");
}
+CPPUNIT_TEST_FIXTURE(Test, testTdf147892)
+{
+ loadAndSave("tdf147892.fodt");
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ // w:del in w:ins is exported correctly
+ // (both w:del and w:ins were exported for para marker)
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:rPr/w:del", 1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:pPr/w:rPr/w:ins", 0);
+}
+
DECLARE_OOXMLEXPORT_TEST(testTdf123054, "tdf123054.docx")
{
CPPUNIT_ASSERT_EQUAL(OUString("No Spacing"),
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
index dd50313e1dae..cd194b5c68f1 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
@@ -58,11 +58,11 @@ DECLARE_SW_EXPORT_TEST(testFlyInFly, "ooo39250-1-min.rtf", nullptr, Test)
// check that anchor of text frame is in other text frame
uno::Reference<text::XTextContent> const xAnchored(getShape(3), uno::UNO_QUERY);
CPPUNIT_ASSERT(xAnchored.is());
- CPPUNIT_ASSERT_EQUAL(OUString(""), uno::Reference<container::XNamed>(xAnchored, uno::UNO_QUERY_THROW)->getName());
+ CPPUNIT_ASSERT_EQUAL(OUString("Frame1")/*generated name*/, uno::Reference<container::XNamed>(xAnchored, uno::UNO_QUERY_THROW)->getName());
uno::Reference<text::XText> const xAnchorText(xAnchored->getAnchor()->getText());
uno::Reference<text::XTextFrame> const xAnchorFrame(xAnchorText, uno::UNO_QUERY);
CPPUNIT_ASSERT(xAnchorFrame.is());
- CPPUNIT_ASSERT_EQUAL(OUString("Frame2"), uno::Reference<container::XNamed>(xAnchorFrame, uno::UNO_QUERY_THROW)->getName());
+ CPPUNIT_ASSERT_EQUAL(OUString("Frame3"), uno::Reference<container::XNamed>(xAnchorFrame, uno::UNO_QUERY_THROW)->getName());
}
DECLARE_OOXMLEXPORT_TEST(testTdf125778_lostPageBreakTOX, "tdf125778_lostPageBreakTOX.docx")
@@ -761,6 +761,10 @@ DECLARE_OOXMLEXPORT_TEST(testTdf123460, "tdf123460.docx")
CPPUNIT_ASSERT_EQUAL(OUString("Delete"),getProperty<OUString>(getRun(getParagraph(2), 2), "RedlineType"));
CPPUNIT_ASSERT_EQUAL(true, getRun( getParagraph( 2 ), 3 )->getString().endsWith("tellus."));
CPPUNIT_ASSERT(hasProperty(getRun(getParagraph(2), 4), "Bookmark"));
+
+ // The paragraph marker's formatting.
+ CPPUNIT_ASSERT_EQUAL(true, getRun(getParagraph(2), 5)->getString().isEmpty());
+
// deleted paragraph mark at the end of the second paragraph
if (mbExported)
{
@@ -768,7 +772,7 @@ DECLARE_OOXMLEXPORT_TEST(testTdf123460, "tdf123460.docx")
bool bCaught = false;
try
{
- getRun( getParagraph( 2 ), 5 );
+ getRun( getParagraph( 2 ), 6 );
}
catch (container::NoSuchElementException&)
{
@@ -1234,8 +1238,8 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf123628)
xmlDocUniquePtr pXmlStyles = parseExport("word/styles.xml");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:hyperlink/w:r/w:rPr/w:rStyle", "val", "InternetLink");
- assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='InternetLink']/w:name", "val", "Hyperlink");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:hyperlink/w:r/w:rPr/w:rStyle", "val", "Hyperlink");
+ assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='Hyperlink']/w:name", "val", "Hyperlink");
}
DECLARE_OOXMLEXPORT_TEST(testTdf127741, "tdf127741.docx")
@@ -1261,7 +1265,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf127925)
loadAndSave("tdf127925.odt");
CPPUNIT_ASSERT_EQUAL(1, getPages());
xmlDocUniquePtr pXmlStyles = parseExport("word/styles.xml");
- assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='VisitedInternetLink']/w:name", "val", "FollowedHyperlink");
+ assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='FollowedHyperlink']/w:name", "val", "FollowedHyperlink");
}
CPPUNIT_TEST_FIXTURE(Test, testTdf127579)
@@ -1269,7 +1273,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf127579)
loadAndSave("tdf127579.odt");
CPPUNIT_ASSERT_EQUAL(1, getPages());
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
- assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:rStyle", "val", "InternetLink");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:hyperlink/w:r/w:rPr/w:rStyle", "val", "Hyperlink");
}
DECLARE_OOXMLEXPORT_TEST(testTdf128304, "tdf128304.odt")
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
index ae8b96c99f66..22c3b75c5e87 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
@@ -984,7 +984,7 @@ DECLARE_OOXMLEXPORT_TEST(testTdf143726, "Simple-TOC.odt")
CPPUNIT_ASSERT(pXmlStyles);
// Without the fix this was "TOA Heading" which belongs to the "Table of Authorities" index in Word
// TOC's heading style should be exported as "TOC Heading" as that's the default Word style name
- assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='ContentsHeading']/w:name", "val", "TOC Heading");
+ assertXPath(pXmlStyles, "/w:styles/w:style[@w:styleId='TOCHeading']/w:name", "val", "TOC Heading");
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
index 9f8c4c0b5c5d..39efb4b0b8fc 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
@@ -13,6 +13,7 @@
#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/text/XBookmarksSupplier.hpp>
+#include <com/sun/star/text/XFootnotesSupplier.hpp>
#include <com/sun/star/text/XTextFieldsSupplier.hpp>
#include <com/sun/star/text/XTextField.hpp>
#include <com/sun/star/util/XRefreshable.hpp>
@@ -202,6 +203,7 @@ CPPUNIT_TEST_FIXTURE(Test, testDropdownContentControlExport)
xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
{
+ xContentControlProps->setPropertyValue("DropDown", uno::Any(true));
uno::Sequence<beans::PropertyValues> aListItems = {
{
comphelper::makePropertyValue("DisplayText", uno::Any(OUString("red"))),
@@ -297,6 +299,13 @@ CPPUNIT_TEST_FIXTURE(Test, testDateContentControlExport)
xContentControlProps->setPropertyValue("DataBindingXpath", uno::Any(OUString("/ns0:employees[1]/ns0:employee[1]/ns0:hireDate[1]")));
xContentControlProps->setPropertyValue("DataBindingStoreItemID", uno::Any(OUString("{241A8A02-7FFD-488D-8827-63FBE74E8BC9}")));
xContentControlProps->setPropertyValue("Color", uno::Any(OUString("008000")));
+ xContentControlProps->setPropertyValue("Appearance", uno::Any(OUString("hidden")));
+ xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("myalias")));
+ xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("mytag")));
+ xContentControlProps->setPropertyValue("Id", uno::Any(static_cast<sal_Int32>(123)));
+ xContentControlProps->setPropertyValue("TabIndex", uno::Any(sal_uInt32(4294967295))); // -1
+ xContentControlProps->setPropertyValue("Lock", uno::Any(OUString("sdtLocked")));
+
xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
// When exporting to DOCX:
@@ -318,6 +327,12 @@ CPPUNIT_TEST_FIXTURE(Test, testDateContentControlExport)
assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dataBinding", "xpath", "/ns0:employees[1]/ns0:employee[1]/ns0:hireDate[1]");
assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dataBinding", "storeItemID", "{241A8A02-7FFD-488D-8827-63FBE74E8BC9}");
assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w15:color", "val", "008000");
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w15:appearance", "val", "hidden");
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:alias", "val", "myalias");
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:tag", "val", "mytag");
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:id", "val", "123");
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:tabIndex", "val", "-1");
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:lock", "val", "sdtLocked");
}
DECLARE_OOXMLEXPORT_TEST(testTdf137466, "tdf137466.docx")
@@ -397,15 +412,26 @@ DECLARE_OOXMLEXPORT_TEST(testTdf123642_BookmarkAtDocEnd, "tdf123642.docx")
DECLARE_OOXMLEXPORT_TEST(testTdf148361, "tdf148361.docx")
{
- // Refresh fields and ensure cross-reference to numbered para is okay
- uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
- uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
+ if (mbExported)
+ {
+ // Block SDT is turned into run SDT on export, so the next import will have this as content
+ // control, not as a field.
+ OUString aActual = getParagraph(1)->getString();
+ // This was "itadmin".
+ CPPUNIT_ASSERT_EQUAL(OUString("itadmin"), aActual);
+ }
+ else
+ {
+ // Refresh fields and ensure cross-reference to numbered para is okay
+ uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
+ uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
- uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
- CPPUNIT_ASSERT(xFields->hasMoreElements());
+ uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
+ CPPUNIT_ASSERT(xFields->hasMoreElements());
- uno::Reference<text::XTextField> xTextField1(xFields->nextElement(), uno::UNO_QUERY);
- CPPUNIT_ASSERT_EQUAL(OUString("itadmin"), xTextField1->getPresentation(false));
+ uno::Reference<text::XTextField> xTextField1(xFields->nextElement(), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(OUString("itadmin"), xTextField1->getPresentation(false));
+ }
OUString aActual = getParagraph(2)->getString();
// This was "itadmin".
@@ -477,6 +503,12 @@ DECLARE_OOXMLEXPORT_TEST(testTdf148111, "tdf148111.docx")
// No more fields
CPPUNIT_ASSERT(!xFields->hasMoreElements());
+
+ if (!mbExported)
+ return;
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ // ShowingPlaceholder should be off for 0, false and "on". (This was 21 before the fix)
+ assertXPath(pXmlDoc,"//w:p/w:sdt/w:sdtPr/w:showingPlcHdr", 12);
}
DECLARE_OOXMLEXPORT_TEST(testTdf81507, "tdf81507.docx")
@@ -553,6 +585,17 @@ DECLARE_OOXMLEXPORT_TEST(testTdf144563, "tdf144563.docx")
}
}
+// broken test document?
+#if !defined(_WIN32)
+DECLARE_OOXMLEXPORT_TEST(testTdf146955, "tdf146955.odt")
+{
+ // import of a (broken?) DOCX export with dozens of frames raised a SAX exception,
+ // when the code tried to access to a non-existent footnote
+ uno::Reference<text::XFootnotesSupplier> xNotes(mxComponent, uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xNotes->getFootnotes()->getCount());
+}
+#endif
+
DECLARE_OOXMLEXPORT_TEST(testTdf144668, "tdf144668.odt")
{
uno::Reference<beans::XPropertySet> xPara1(getParagraph(1, u"level1"), uno::UNO_QUERY);
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
new file mode 100644
index 000000000000..36b492c5d294
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport18.cxx
@@ -0,0 +1,328 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <queue>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/text/GraphicCrop.hpp>
+#include <com/sun/star/text/XFootnotesSupplier.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/util/XRefreshable.hpp>
+
+
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/scopeguard.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <o3tl/string_view.hxx>
+#include <comphelper/propertyvalue.hxx>
+
+#include <unotxdoc.hxx>
+#include <docsh.hxx>
+
+constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/extras/ooxmlexport/data/";
+
+class Test : public SwModelTestBase
+{
+public:
+ Test() : SwModelTestBase(DATA_DIRECTORY, "Office Open XML Text") {}
+};
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf150197_predefinedNumbering)
+{
+ createSwDoc();
+
+ // The exact numbering style doesn't matter - just any non-bullet pre-defined numbering style.
+ uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
+ { "Style", uno::Any(OUString("Numbering 123")) },
+ { "FamilyName", uno::Any(OUString("NumberingStyles")) },
+ });
+ dispatchCommand(mxComponent, ".uno:StyleApply", aPropertyValues);
+
+ CPPUNIT_ASSERT_EQUAL(OUString("1."), getProperty<OUString>(getParagraph(1), "ListLabelString"));
+
+ reload("Office Open XML Text", "");
+ CPPUNIT_ASSERT_EQUAL(OUString("1."), getProperty<OUString>(getParagraph(1), "ListLabelString"));
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testInlineSdtHeader)
+{
+ // Without the accompanying fix in place, this test would have failed with an assertion failure,
+ // we produced not-well-formed XML on save.
+ loadAndSave("inline-sdt-header.docx");
+}
+
+DECLARE_OOXMLEXPORT_TEST(testTdf153613_sdtAfterPgBreak, "tdf153613_sdtAfterPgBreak.docx")
+{
+ CPPUNIT_ASSERT_EQUAL(2, getPages());
+}
+
+DECLARE_OOXMLEXPORT_TEST(testTdf153964_topMarginAfterBreak14, "tdf153964_topMarginAfterBreak14.docx")
+{
+ //The top margin should only apply once in a split paragraph.
+ //In this compat14 (Windows 2010) version, it applies after the break if no prior visible run.
+ uno::Reference<beans::XPropertySet> xPara(getParagraph(2, "a w:br at the start of the document. Does it use 60 point top margin?"), uno::UNO_QUERY);
+ //CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+
+ xPara.set(getParagraph(3, u"60 pt spacing before"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ CPPUNIT_ASSERT_EQUAL(Color(0xfbe4d5), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // The top margin was applied to paragraph 3, so it shouldn't apply here
+ xPara.set(getParagraph(4, u"column break1"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ //CPPUNIT_ASSERT_EQUAL(Color(0xfbe4d5), getProperty<Color>(xPara, "ParaBackColor"));
+
+ xPara.set(getParagraph(5, u"60 pt followed by page break"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ CPPUNIT_ASSERT_EQUAL(Color(0xdeeaf6), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // The top margin was applied to paragraph 5, so it shouldn't apply here
+ xPara.set(getParagraph(6, u"page break1"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ CPPUNIT_ASSERT_EQUAL(Color(0xdeeaf6), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // The top margin was not applied yet, so with compat14 it should apply here.
+ xPara.set(getParagraph(7, u"column break2"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ CPPUNIT_ASSERT_EQUAL(Color(0xe2efd9), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // In an odd twist, the w:br was actually at the end of the previous w:p, so in that case
+ // we ignore the top margin definition this time.
+ xPara.set(getParagraph(9, u"page break2"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+
+ // The top margin was not applied before the column break, so with compat14 it should apply here
+ xPara.set(getParagraph(10, u""), uno::UNO_QUERY); // after column break
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ //CPPUNIT_ASSERT_EQUAL(Color(0xfff2cc), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // In an odd twist, the w:br was actually at the end of the previous w:p, so in that case
+ // we ignore the top margin definition this time.
+ xPara.set(getParagraph(12, u""), uno::UNO_QUERY); // after page break
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+}
+
+DECLARE_OOXMLEXPORT_TEST(testTdf153964_topMarginAfterBreak15, "tdf153964_topMarginAfterBreak15.docx")
+{
+ //The top margin should only apply once (at most) in a split paragraph.
+ //In this compat15 (Windows 2013) version, it never applies after the break.
+ uno::Reference<beans::XPropertySet> xPara(getParagraph(2, "a w:br at the start of the document. Does it use 60 point top margin?"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+
+ xPara.set(getParagraph(3, u"60 pt spacing before"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ CPPUNIT_ASSERT_EQUAL(Color(0xfbe4d5), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // The top margin was applied to paragraph 3, so it shouldn't apply here
+ xPara.set(getParagraph(4, u"column break1"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ //CPPUNIT_ASSERT_EQUAL(Color(0xfbe4d5), getProperty<Color>(xPara, "ParaBackColor"));
+
+ xPara.set(getParagraph(5, u"60 pt followed by page break"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(2117), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ CPPUNIT_ASSERT_EQUAL(Color(0xdeeaf6), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // The top margin was applied to paragraph 5, so it shouldn't apply here
+ xPara.set(getParagraph(6, u"page break1"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ CPPUNIT_ASSERT_EQUAL(Color(0xdeeaf6), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // The top margin was not applied to paragraph 6, and with compat15 it shouldn't apply here.
+ xPara.set(getParagraph(7, u"column break2"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ CPPUNIT_ASSERT_EQUAL(Color(0xe2efd9), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // The top margin not was applied to paragraph 8, and with compat15 it shouldn't apply here.
+ xPara.set(getParagraph(9, u"page break2"), uno::UNO_QUERY);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+
+ // The top margin was not applied to paragraph 9, and with compat15 it shouldn't apply here.
+ xPara.set(getParagraph(10, u""), uno::UNO_QUERY); // after column break
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+ //CPPUNIT_ASSERT_EQUAL(Color(0xfff2cc), getProperty<Color>(xPara, "ParaBackColor"));
+
+ // The top margin was not applied to paragraph 11, and with compat15 it shouldn't apply here.
+ xPara.set(getParagraph(12, u""), uno::UNO_QUERY); // after page break
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(xPara, "ParaTopMargin"));
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf152636_lostPageBreak2)
+{
+ loadAndReload("tdf152636_lostPageBreak2.docx");
+ CPPUNIT_ASSERT_EQUAL(2, getPages());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testSdtDuplicatedId)
+{
+ // Given a document with 2 inline <w:sdt>, with each a <w:id>:
+ // When exporting that back to DOCX:
+ loadAndSave("sdt-duplicated-id.docx");
+
+ // Then make sure we write 2 <w:sdt> and no duplicates:
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 2
+ // - Actual : 4
+ // i.e. grab-bags introduced 2 unwanted duplicates.
+ assertXPath(pXmlDoc, "//w:sdt", 2);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testImageCropping)
+{
+ loadAndReload("crop-roundtrip.docx");
+
+ // the image has no cropping after roundtrip, because it has been physically cropped
+ // NB: this test should be fixed when the core feature to show image cropped when it
+ // has the "GraphicCrop" is set is implemented
+ auto aGraphicCropStruct = getProperty<text::GraphicCrop>(getShape(1), "GraphicCrop");
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aGraphicCropStruct.Left);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aGraphicCropStruct.Right);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aGraphicCropStruct.Top);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(0), aGraphicCropStruct.Bottom);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf152200)
+{
+ // Given a document with a fly anchored after a FORMTEXT in the end of the paragraph:
+ // When exporting that back to DOCX:
+ loadAndSave("tdf152200-field+textbox.docx");
+
+ // Then make sure that fldChar with type 'end' goes prior to the at-char anchored fly.
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ const int nRunsBeforeFldCharEnd = countXPathNodes(pXmlDoc, "//w:fldChar[@w:fldCharType='end']/preceding::w:r");
+ CPPUNIT_ASSERT(nRunsBeforeFldCharEnd);
+ const int nRunsBeforeAlternateContent = countXPathNodes(pXmlDoc, "//mc:AlternateContent/preceding::w:r");
+ CPPUNIT_ASSERT(nRunsBeforeAlternateContent);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected greater than: 6
+ // - Actual : 5
+ CPPUNIT_ASSERT_GREATER(nRunsBeforeFldCharEnd, nRunsBeforeAlternateContent);
+ // Make sure we only have one paragraph in body, and only three field characters overal,
+ // located directly in runs of this paragraph
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p");
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/w:fldChar", 3);
+ assertXPath(pXmlDoc, "//w:fldChar", 3); // no field characters elsewhere
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testNumberPortionFormatFromODT)
+{
+ // Given a document with a single paragraph, direct formatting asks 24pt font size for the
+ // numbering and the text portion:
+ load(DATA_DIRECTORY, "number-portion-format.odt");
+
+ // When saving to DOCX:
+ save("Office Open XML Text", maTempFile);
+ mbExported = true;
+
+ // Then make sure that the paragraph marker's char format has that custom font size:
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // - XPath '//w:pPr/w:rPr/w:sz' number of nodes is incorrect
+ // i.e. <w:sz> was missing under <w:pPr>'s <w:rPr>.
+ assertXPath(pXmlDoc, "//w:pPr/w:rPr/w:sz", "val", "48");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf152425)
+{
+ loadAndReload("tdf152425.docx");
+
+ // Check that "List Number" and "List 5" styles don't get merged
+ const OUString Para3Style = getProperty<OUString>(getParagraph(3), "ParaStyleName");
+ CPPUNIT_ASSERT_EQUAL(OUString("Numbering 1"), Para3Style);
+ const OUString Para4Style = getProperty<OUString>(getParagraph(4), "ParaStyleName");
+ CPPUNIT_ASSERT_EQUAL(OUString("List 5 (WW)"), Para4Style);
+ // Also check that "List 5" and "List Bullet 5" styles don't get merged
+ const OUString Para5Style = getProperty<OUString>(getParagraph(5), "ParaStyleName");
+ CPPUNIT_ASSERT_EQUAL(OUString("List 5"), Para5Style);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf150966_regularInset)
+{
+ // Given a docx document with a rectangular shape with height cy="900000" (EMU), tIns="180000"
+ // and bIns="360000", resulting in 360000EMU text area height.
+ load(DATA_DIRECTORY, "tdf150966_regularInset.docx");
+
+ // The shape is imported as custom shape with attached frame.
+ // The insets are currently imported as margin top="4.99mm" and bottom="10mm".
+ // That should result in tIns="179640" and bIns="360000" on export.
+
+ // Without fix the insets were tIns="359280" and bIns="539640". The text area had 1080Emu height
+ // and Word displayes no text at all.
+ save("Office Open XML Text", maTempFile);
+ mbExported = true;
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ assertXPathAttrs(pXmlDoc, "//wps:bodyPr", { { "tIns", "179640" }, { "bIns", "360000" } });
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testTdf157136)
+{
+ // Given a document with two content controls - one block, one inline
+ load(DATA_DIRECTORY, "tdf157136_TwoContentControls.docx");
+
+ // Both of them must import with the correct character style
+
+ {
+ // 1st paragraph - block content control
+ auto xRun = getRun(getParagraph(1), 1);
+ CPPUNIT_ASSERT_EQUAL(OUString("Click or tap here to enter text.\r"), xRun->getString());
+ // Without the fix in place, this would fail with
+ // - Expected: Placeholder Text
+ // - Actual :
+ CPPUNIT_ASSERT_EQUAL(OUString("Placeholder Text"),
+ getProperty<OUString>(xRun, "CharStyleName"));
+ }
+
+ {
+ // 2nd paragraph - inline content control
+ auto xRun = getRun(getParagraph(2), 1);
+ auto xContentControl
+ = getProperty<css::uno::Reference<css::text::XTextRange>>(xRun, "ContentControl");
+ CPPUNIT_ASSERT_EQUAL(OUString("Click or tap here to enter text."),
+ xContentControl->getString());
+ CPPUNIT_ASSERT_EQUAL(OUString("Placeholder Text"),
+ getProperty<OUString>(xRun, "CharStyleName"));
+ }
+
+ // Test the same after round-trip
+ reload("Office Open XML Text", "");
+
+ {
+ // 1st paragraph - becomes inline content control after roundtrip
+ auto xRun = getRun(getParagraph(1), 1);
+ auto xContentControl
+ = getProperty<css::uno::Reference<css::text::XTextRange>>(xRun, "ContentControl");
+ CPPUNIT_ASSERT_EQUAL(OUString("Click or tap here to enter text."),
+ xContentControl->getString());
+ CPPUNIT_ASSERT_EQUAL(OUString("Placeholder Text"),
+ getProperty<OUString>(xRun, "CharStyleName"));
+ }
+
+ {
+ // 2nd paragraph - inline content control
+ auto xRun = getRun(getParagraph(2), 1);
+ auto xContentControl
+ = getProperty<css::uno::Reference<css::text::XTextRange>>(xRun, "ContentControl");
+ CPPUNIT_ASSERT_EQUAL(OUString("Click or tap here to enter text."),
+ xContentControl->getString());
+ CPPUNIT_ASSERT_EQUAL(OUString("Placeholder Text"),
+ getProperty<OUString>(xRun, "CharStyleName"));
+ }
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx
index 7e4cce4ce6de..a14b0473ae08 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport2.cxx
@@ -854,7 +854,8 @@ DECLARE_OOXMLEXPORT_TEST(testFdo64238_b, "fdo64238_b.docx")
xRunEnum->nextElement();
numOfRuns++;
}
- CPPUNIT_ASSERT_EQUAL(sal_Int32(5), numOfRuns);
+ // "This is the ", "ODD", " [", "LEFT", "] header" and the colored paragraph marker
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(6), numOfRuns);
}
DECLARE_OOXMLEXPORT_TEST(testFdo56679, "fdo56679.docx")
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx
index f9285288b3ae..4e8f58f6294b 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport3.cxx
@@ -1004,6 +1004,21 @@ CPPUNIT_TEST_FIXTURE(Test, testGlossary)
assertXPath(pXmlDoc, "/w:glossaryDocument", "Ignorable", "w14 wp14");
}
+CPPUNIT_TEST_FIXTURE(Test, testGlossaryWithEmail)
+{
+ // tdf#152289
+ loadAndSave("glossaryWithEmail.docx");
+ xmlDocUniquePtr pXmlDoc = parseExport("word/glossary/_rels/document.xml.rels");
+ assertXPath(pXmlDoc, "/rels:Relationships/rels:Relationship[@Id='rId4' "
+ "and @Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink' "
+ "and @Target='mailto:emailgoeshere@example.com' "
+ "and @TargetMode='External']");
+
+ // preserve the ShowingPlaceholder setting on both block SDTs.
+ pXmlDoc = parseExport("word/document.xml");
+ assertXPath(pXmlDoc,"/w:document/w:body/w:p/w:sdt/w:sdtPr/w:showingPlcHdr", 2);
+}
+
DECLARE_OOXMLEXPORT_TEST(testFdo71785, "fdo71785.docx")
{
// crashtest
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
index e0b9db36e980..a32da9cb88ae 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
@@ -1022,6 +1022,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSimpleSdts)
assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:sdt/w:sdtPr/w:text", 1);
assertXPath(pXmlDoc, "//*/w:sdt/w:sdtPr/w:id", 5);
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:lock", 1);
assertXPath(pXmlDoc, "/w:document/w:body/w:sdt[1]/w:sdtPr/w:picture", 1);
assertXPath(pXmlDoc, "/w:document/w:body/w:sdt[2]/w:sdtPr/w:group", 1);
assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:sdt/w:sdtPr/w:citation", 1);
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
index 17fe49c8f8aa..04c9d7e7d927 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport5.cxx
@@ -1105,7 +1105,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSdt2Run)
xmlDocUniquePtr pXmlDoc = parseExport();
// The problem was that <w:sdt> was closed after "first", not after "second", so the second assert failed.
- assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtContent/w:r", 1);
+ assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtContent/w:r/w:t", "firstsecond");
// Make sure the third portion is still outside <w:sdt>.
assertXPathContent(pXmlDoc, "/w:document/w:body/w:p[1]/w:r/w:t", "third");
}
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
index 4429aa58a70d..61372e9e803e 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport6.cxx
@@ -282,16 +282,6 @@ DECLARE_OOXMLEXPORT_TEST(testDMLShapeFillBitmapCrop, "dml-shape-fillbitmapcrop.d
}
-DECLARE_OOXMLEXPORT_TEST(test141652_fillBitmapName, "tdf141652_fillBitmapName.docx")
-{
- text::GraphicCrop aGraphicCropStruct = getProperty<text::GraphicCrop>(getShape(1), "GraphicCrop");
- CPPUNIT_ASSERT_DOUBLES_EQUAL( sal_Int32(-769), aGraphicCropStruct.Right, 10);
-
- CPPUNIT_ASSERT_EQUAL( sal_Int32( 0 ), aGraphicCropStruct.Left );
- CPPUNIT_ASSERT_EQUAL( sal_Int32( 0 ), aGraphicCropStruct.Top );
- CPPUNIT_ASSERT_EQUAL( sal_Int32( 0 ), aGraphicCropStruct.Bottom );
-}
-
DECLARE_OOXMLEXPORT_TEST(testDMLShapeFillPattern, "dml-shape-fillpattern.docx")
{
// Hatching was ignored by the export.
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
index 20c1fc95bdde..431fdb526713 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
@@ -1070,6 +1070,18 @@ DECLARE_OOXMLEXPORT_TEST(testN820509, "n820509.docx")
}
}
+DECLARE_OOXMLEXPORT_TEST(testTdf151548_activeContentDemo, "tdf151548_activeContentDemo.docm")
+{
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
+ SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
+ IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+ for(auto aIter = pMarkAccess->getFieldmarksBegin(); aIter != pMarkAccess->getFieldmarksEnd(); ++aIter)
+ {
+ const OUString sName = (*aIter)->GetName();
+ CPPUNIT_ASSERT(sName == "Check1" || sName == "Text1" || sName == "Dropdown1");
+ }
+}
+
DECLARE_OOXMLEXPORT_TEST(testN830205, "n830205.docx")
{
// Previously import just crashed (due to infinite recursion).
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx
index 99d4b0112a60..1b97e846f1ef 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport9.cxx
@@ -139,7 +139,7 @@ DECLARE_OOXMLEXPORT_TEST(testTdf109063, "tdf109063.docx")
CPPUNIT_ASSERT_EQUAL(0, getShapes());
}
-CPPUNIT_TEST_FIXTURE(Test, testTdf108269)
+CPPUNIT_TEST_FIXTURE(DocmTest, testTdf108269)
{
loadAndReload("tdf108269.docm");
uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), maTempFile.GetURL());
@@ -149,6 +149,14 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf108269)
CPPUNIT_ASSERT(xNameAccess->hasByName("word/vbaData.xml"));
}
+CPPUNIT_TEST_FIXTURE(Test, testTdf125338)
+{
+ loadAndSave("tdf125338.docm");
+ uno::Reference<packages::zip::XZipFileAccess2> xNameAccess = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(m_xSFactory), maTempFile.GetURL());
+ // docm files should not retain macros when saved as docx
+ CPPUNIT_ASSERT(!xNameAccess->hasByName("word/vbaProject.bin"));
+}
+
DECLARE_OOXMLEXPORT_TEST(testTdf92045, "tdf92045.docx")
{
// This was true, <w:effect w:val="none"/> resulted in setting the blinking font effect.
diff --git a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
index ea07a681343c..3747aa399a27 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlfieldexport.cxx
@@ -541,14 +541,16 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testfdo82123, "fdo82123.docx")
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
// make sure there is only one run inside first SDT after RT as in the Original file.
- assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:p/w:sdt[1]/w:sdtContent/w:r",1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:p/w:sdt[1]/w:sdtContent/w:r/w:t", 1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:p/w:r/w:drawing", 1);
}
DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testSdtBeforeField, "sdt-before-field.docx")
{
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
// Make sure the field doesn't sneak inside the SDT: the SDT should contain only a single run (there were 6 ones).
- assertXPath(pXmlDoc, "//w:sdt/w:sdtContent/w:r", 1);
+ assertXPath(pXmlDoc, "//w:p/w:sdt/w:sdtContent/w:r/w:t", 1);
+ assertXPath(pXmlDoc, "//w:p/w:r/w:fldChar", 3);
}
DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testfdo81946, "fdo81946.docx")
@@ -563,7 +565,8 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testfdo82492, "fdo82492.docx")
xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
// make sure there is only one run inside first SDT after RT as in the Original file.
- assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt[1]/w:sdtContent/w:r",1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt[1]/w:sdtContent/w:r/w:t", 1);
+ assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/mc:AlternateContent", 1);
}
DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testSdtHeader, "sdt-header.docx")
@@ -815,42 +818,44 @@ DECLARE_OOXMLEXPORT_TEST( testSdtDatePicker, "test_sdt_datepicker.docx" )
CPPUNIT_ASSERT_EQUAL(OUString("008000"), sColor);
}
+CPPUNIT_TEST_FIXTURE(Test, testContentControlGrabBag)
+{
+ // Given a document with a <w:sdt> tag:
+ OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "content-control-grab-bag.docx";
+ loadURL(aURL, nullptr);
+
+ // When exporting that document back to DOCX:
+ // Then make sure that completes without an assertion failure, which would mean not-well-formed
+ // output was produced:
+ save("Office Open XML Text", maTempFile);
+}
+
CPPUNIT_TEST_FIXTURE(Test, testTdf104823)
{
// Test how we can roundtrip sdt plain text with databindings support
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf104823.docx";
loadURL(aURL, nullptr);
- css::uno::Reference<css::text::XTextFieldsSupplier> xTextFieldsSupplier(
- mxComponent, css::uno::UNO_QUERY_THROW);
- auto xFields(xTextFieldsSupplier->getTextFields()->createEnumeration());
-
- // FIXME: seems order of fields is different than in source document
- // so feel free to modify testcase if order is changed
-
- // First field: content from core properties
- uno::Reference<text::XTextField> xField1(xFields->nextElement(), uno::UNO_QUERY);
- CPPUNIT_ASSERT(xFields->hasMoreElements());
+ // First paragraph: content from core properties
+ uno::Reference<text::XTextRange> xParagraph1 = getParagraph(1);
+ auto xContentControl1 = getProperty<uno::Reference<text::XText>>(getRun(xParagraph1, 2), "ContentControl");
// Check field value (it should be value from data source) and set new
- CPPUNIT_ASSERT_EQUAL(OUString("True Core Property Value"), xField1->getPresentation(false));
- uno::Reference<beans::XPropertySet> xField1Props(xField1, uno::UNO_QUERY);
- xField1Props->setPropertyValue("Content", uno::makeAny(OUString("New Core Property Value")));
+ CPPUNIT_ASSERT_EQUAL(OUString("True Core Property Value"), xContentControl1->getString());
+ xContentControl1->setString("New Core Property Value");
- // Third field: content from custom properties
- uno::Reference<text::XTextField> xField2(xFields->nextElement(), uno::UNO_QUERY);
- CPPUNIT_ASSERT(xFields->hasMoreElements());
+ // Third paragraph: content from custom properties
+ uno::Reference<text::XTextRange> xParagraph3 = getParagraph(3);
+ auto xContentControl3 = getProperty<uno::Reference<text::XText>>(getRun(xParagraph3, 2), "ContentControl");
// Check field value (it should be value from data source) and set new
- CPPUNIT_ASSERT_EQUAL(OUString("True Custom XML Value"), xField2->getPresentation(false));
- uno::Reference<beans::XPropertySet> xField2Props(xField2, uno::UNO_QUERY);
- xField2Props->setPropertyValue("Content", uno::makeAny(OUString("New Custom XML Value")));
+ CPPUNIT_ASSERT_EQUAL(OUString("True Custom XML Value"), xContentControl3->getString());
+ xContentControl3->setString("New Custom XML Value");
- // Second field: content from extended properties
- uno::Reference<text::XTextField> xField3(xFields->nextElement(), uno::UNO_QUERY);
- CPPUNIT_ASSERT(!xFields->hasMoreElements());
+ // Second paragraph: content from extended properties
+ uno::Reference<text::XTextRange> xParagraph2 = getParagraph(2);
+ auto xContentControl2 = getProperty<uno::Reference<text::XText>>(getRun(xParagraph2, 2), "ContentControl");
// Check field value (it should be value from data source) and set new
- CPPUNIT_ASSERT_EQUAL(OUString("True Extended Property Value"), xField3->getPresentation(false));
- uno::Reference<beans::XPropertySet> xField3Props(xField3, uno::UNO_QUERY);
- xField3Props->setPropertyValue("Content", uno::makeAny(OUString("New Extended Property Value")));
+ CPPUNIT_ASSERT_EQUAL(OUString("True Extended Property Value"), xContentControl2->getString());
+ xContentControl2->setString("New Extended Property Value");
// Save and check saved data
save("Office Open XML Text", maTempFile);
diff --git a/sw/qa/extras/ooxmlimport/data/tdf152200-bad_fldChar_end.docx b/sw/qa/extras/ooxmlimport/data/tdf152200-bad_fldChar_end.docx
new file mode 100644
index 000000000000..7f77c8d66b2b
--- /dev/null
+++ b/sw/qa/extras/ooxmlimport/data/tdf152200-bad_fldChar_end.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx b/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx
index afdb0cc27ce1..bf9e298ea4d2 100644
--- a/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx
+++ b/sw/qa/extras/ooxmlimport/ooxmlimport2.cxx
@@ -937,6 +937,12 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf126426)
}
}
+CPPUNIT_TEST_FIXTURE(Test, testTdf152200)
+{
+ load(mpTestDocumentPath, "tdf152200-bad_fldChar_end.docx");
+ // Should not crash/hang because of wrong placement of ending fldChar
+}
+
// tests should only be added to ooxmlIMPORT *if* they fail round-tripping in ooxmlEXPORT
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/qa/extras/tiledrendering/data/content-control.odt b/sw/qa/extras/tiledrendering/data/content-control.odt
deleted file mode 100644
index 624063fbd606..000000000000
--- a/sw/qa/extras/tiledrendering/data/content-control.odt
+++ /dev/null
Binary files differ
diff --git a/sw/qa/extras/tiledrendering/data/multiline.odt b/sw/qa/extras/tiledrendering/data/multiline.odt
new file mode 100644
index 000000000000..4c60b58decb2
--- /dev/null
+++ b/sw/qa/extras/tiledrendering/data/multiline.odt
Binary files differ
diff --git a/sw/qa/extras/tiledrendering/data/savedauthorfield.odt b/sw/qa/extras/tiledrendering/data/savedauthorfield.odt
new file mode 100644
index 000000000000..e4b41d28b92a
--- /dev/null
+++ b/sw/qa/extras/tiledrendering/data/savedauthorfield.odt
Binary files differ
diff --git a/sw/qa/extras/tiledrendering/data/testTableCommentRemoveCallback.odt b/sw/qa/extras/tiledrendering/data/testTableCommentRemoveCallback.odt
new file mode 100644
index 000000000000..09941166a718
--- /dev/null
+++ b/sw/qa/extras/tiledrendering/data/testTableCommentRemoveCallback.odt
Binary files differ
diff --git a/sw/qa/extras/tiledrendering/tiledrendering.cxx b/sw/qa/extras/tiledrendering/tiledrendering.cxx
index 6db7cd57dfdd..cc1dbd4947c2 100644
--- a/sw/qa/extras/tiledrendering/tiledrendering.cxx
+++ b/sw/qa/extras/tiledrendering/tiledrendering.cxx
@@ -19,6 +19,8 @@
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
+#include <com/sun/star/text/XTextField.hpp>
+#include <com/sun/star/text/AuthorDisplayFormat.hpp>
#include <com/sun/star/datatransfer/XTransferable2.hpp>
#include <test/helper/transferable.hxx>
@@ -425,6 +427,46 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testGetTextSelectionLineLimit)
CPPUNIT_ASSERT(sHtmlText.match(sExpectedHtml, nStart));
}
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testGetTextSelectionMultiLine)
+{
+ // Test will check if correct number of new line marks / paragraphs is generated
+ const char sOriginalText[] = u8"Heading\n\
+Let's have text; we need to be able to select the text inside the shape, but also the various individual ones too:\n\
+\n\
+\n\
+\n\
+\n\
+\n\
+And this is all for Writer shape objects\n\
+Heading on second page";
+
+ const char sExpectedHtml[] = u8"Heading</h2>\n\
+<p>Let's have text; we need to be able to select the text inside the shape, but also the various individual ones too:</p>\n\
+<p><br/><br/></p>\n\
+<p><br/><br/></p>\n\
+<p><br/><br/></p>\n\
+<p><br/><br/></p>\n\
+<p><br/><br/></p>\n\
+<h1 class=\"western\">And this is all for Writer shape objects</h1>\n\
+<h2 class=\"western\">Heading on second page</h2>";
+
+ SwXTextDocument* pXTextDocument = createDoc("multiline.odt");
+
+ SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
+ // Create a selection.
+ pWrtShell->SelAll();
+
+ OString sPlainText = apitest::helper::transferable::getTextSelection(pXTextDocument->getSelection(), "text/plain;charset=utf-8");
+
+ CPPUNIT_ASSERT_EQUAL(OString(sOriginalText), sPlainText.trim());
+
+ OString sHtmlText = apitest::helper::transferable::getTextSelection(pXTextDocument->getSelection(), "text/html");
+
+ int nStart = sHtmlText.indexOf(u8"Heading");
+
+ CPPUNIT_ASSERT(sHtmlText.match(sExpectedHtml, nStart));
+}
+
CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testSetGraphicSelection)
{
SwXTextDocument* pXTextDocument = createDoc("shape.fodt");
@@ -1280,6 +1322,48 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testUndoReorderingRedo)
SfxViewShell::Current()->setLibreOfficeKitViewCallback(nullptr);
}
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testUndoReorderingRedo2)
+{
+ // Create two views.
+ SwXTextDocument* pXTextDocument = createDoc();
+ SwWrtShell* pWrtShell1 = pXTextDocument->GetDocShell()->GetWrtShell();
+ int nView1 = SfxLokHelper::getView();
+ int nView2 = SfxLokHelper::createView();
+ pXTextDocument->initializeForTiledRendering(uno::Sequence<beans::PropertyValue>());
+ SwWrtShell* pWrtShell2 = pXTextDocument->GetDocShell()->GetWrtShell();
+
+ // Type in the first view.
+ SfxLokHelper::setView(nView1);
+ pWrtShell1->SttEndDoc(/*bStt=*/true);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'f', 0);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 'f', 0);
+ Scheduler::ProcessEventsToIdle();
+
+ // Type to the same paragraph in the second view.
+ SfxLokHelper::setView(nView2);
+ pWrtShell2->SttEndDoc(/*bStt=*/true);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 's', 0);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 's', 0);
+ Scheduler::ProcessEventsToIdle();
+
+ // Delete in the first view and undo.
+ SfxLokHelper::setView(nView1);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, awt::Key::BACKSPACE);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, awt::Key::BACKSPACE);
+ Scheduler::ProcessEventsToIdle();
+ dispatchCommand(mxComponent, ".uno:Undo", {});
+ Scheduler::ProcessEventsToIdle();
+
+ // Query the undo state, now that a "delete" is on the redo stack and an "insert" belongs to the
+ // view on the undo stack, so the types are different.
+ SwUndoId nUndoId(SwUndoId::EMPTY);
+ // Without the accompanying fix in place, this test would have failed with:
+ // runtime error: downcast which does not point to an object of type 'const SwUndoInsert'
+ // note: object is of type 'SwUndoDelete'
+ // in an UBSan build.
+ pWrtShell1->GetLastUndoInfo(nullptr, &nUndoId, &pWrtShell1->GetView());
+}
+
CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testUndoReorderingMulti)
{
// Create two views and a document of 2 paragraphs.
@@ -3226,6 +3310,29 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testTablePaintInvalidate)
CPPUNIT_ASSERT_EQUAL(0, m_nInvalidations);
}
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testTableCommentRemoveCallback)
+{
+ comphelper::LibreOfficeKit::setActive();
+ comphelper::LibreOfficeKit::setTiledAnnotations(false);
+
+ // Load a document with a comment in a table.
+ SwXTextDocument* pXTextDocument = createDoc("testTableCommentRemoveCallback.odt");
+ SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
+ setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
+ ViewCallback aView;
+
+ // delete all characters
+ comphelper::dispatchCommand(".uno:SelectAll", uno::Sequence<beans::PropertyValue>());
+ Scheduler::ProcessEventsToIdle();
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_DELETE);
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_DELETE);
+ Scheduler::ProcessEventsToIdle();
+
+ //check for comment remove callback
+ OString sAction(aView.m_aComment.get_child("action").get_value<std::string>().c_str());
+ CPPUNIT_ASSERT_EQUAL(OString("Remove"), sAction);
+}
+
CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testSpellOnlineRenderParameter)
{
SwXTextDocument* pXTextDocument = createDoc("dummy.fodt");
@@ -3443,7 +3550,17 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testRedlinePortions)
CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testContentControl)
{
// Given a document with a content control:
- SwXTextDocument* pXTextDocument = createDoc("content-control.odt");
+ SwXTextDocument* pXTextDocument = createDoc();
+ uno::Reference<text::XText> xText = pXTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ xText->insertString(xCursor, "test", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->gotoEnd(/*bExpand=*/true);
+ uno::Reference<text::XTextContent> xContentControl(
+ pXTextDocument->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("my alias")));
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell();
setupLibreOfficeKitViewCallback(pWrtShell->GetSfxViewShell());
pWrtShell->SttEndDoc(/*bStt=*/true);
@@ -3463,6 +3580,11 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testContentControl)
CPPUNIT_ASSERT_EQUAL(OString("show"), sAction);
OString sRectangles = aTree.get_child("rectangles").get_value<std::string>().c_str();
CPPUNIT_ASSERT(!sRectangles.isEmpty());
+ // Without the accompanying fix in place, this test would have failed width:
+ // uncaught exception of type std::exception (or derived).
+ // - No such node (alias)
+ OString sAlias = aTree.get_child("alias").get_value<std::string>().c_str();
+ CPPUNIT_ASSERT_EQUAL(OString("my alias"), sAlias);
}
// And when leaving that content control:
@@ -3672,6 +3794,61 @@ CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testDateContentControl)
CPPUNIT_ASSERT_EQUAL(OUString("2022-05-30"), pTextNode->GetExpandText(pWrtShell->GetLayout()));
}
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testAuthorField)
+{
+ SwXTextDocument* pXTextDocument = createDoc();
+ const OUString sAuthor("Abcd Xyz");
+
+ uno::Sequence<beans::PropertyValue> aPropertyValues1(comphelper::InitPropertySequence(
+ {
+ {".uno:Author", uno::makeAny(sAuthor)},
+ }));
+ pXTextDocument->initializeForTiledRendering(aPropertyValues1);
+
+ auto insertAuthorField = [this]()
+ {
+ uno::Reference<lang::XMultiServiceFactory> const xMSF(mxComponent, uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextDocument> const xTD(mxComponent, uno::UNO_QUERY_THROW);
+
+ auto const xText = xTD->getText();
+ auto const xTextCursor = xText->createTextCursor();
+ CPPUNIT_ASSERT(xTextCursor.is());
+
+ xTextCursor->gotoEnd(false);
+
+ uno::Reference<text::XTextField> const xTextField(
+ xMSF->createInstance("com.sun.star.text.textfield.Author"), uno::UNO_QUERY_THROW);
+
+ uno::Reference<beans::XPropertySet> xTextFieldProps(xTextField, uno::UNO_QUERY_THROW);
+ xTextFieldProps->setPropertyValue("FullName", uno::Any(true));
+
+ xText->insertTextContent(xTextCursor, xTextField, false);
+ };
+
+ insertAuthorField();
+ Scheduler::ProcessEventsToIdle();
+
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", sAuthor);
+}
+
+CPPUNIT_TEST_FIXTURE(SwTiledRenderingTest, testSavedAuthorField)
+{
+ SwXTextDocument* pXTextDocument = createDoc("savedauthorfield.odt");
+ const OUString sAuthor("XYZ ABCD");
+ uno::Sequence<beans::PropertyValue> aPropertyValues1(comphelper::InitPropertySequence(
+ {
+ {".uno:Author", uno::makeAny(sAuthor)},
+ }));
+ pXTextDocument->initializeForTiledRendering(aPropertyValues1);
+
+ Scheduler::ProcessEventsToIdle();
+
+ xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", sAuthor);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/uiwriter/data/HiddenSection.odt b/sw/qa/extras/uiwriter/data/HiddenSection.odt
new file mode 100644
index 000000000000..8358cbc9951a
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/HiddenSection.odt
Binary files differ
diff --git a/sw/qa/extras/uiwriter/data/tdf142715.odt b/sw/qa/extras/uiwriter/data/tdf142715.odt
new file mode 100644
index 000000000000..70682a54056c
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf142715.odt
Binary files differ
diff --git a/sw/qa/extras/uiwriter/data/tdf147507.fodt b/sw/qa/extras/uiwriter/data/tdf147507.fodt
new file mode 100644
index 000000000000..bd579a4b85c7
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf147507.fodt
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text">
+ <office:automatic-styles>
+ <style:style style:name="Table1" style:family="table">
+ <style:table-properties style:width="15.621cm" fo:margin-left="-0.191cm" fo:margin-top="0cm" fo:margin-bottom="0cm" table:align="left" style:writing-mode="page"/>
+ </style:style>
+ <style:style style:name="Table1.A" style:family="table-column">
+ <style:table-column-properties style:column-width="6.765cm"/>
+ </style:style>
+ <style:style style:name="Table1.B" style:family="table-column">
+ <style:table-column-properties style:column-width="8.856cm"/>
+ </style:style>
+ <style:style style:name="Table1.1" style:family="table-row">
+ <style:table-row-properties fo:keep-together="auto"/>
+ </style:style>
+ <style:style style:name="Table1.A1" style:family="table-cell">
+ <style:table-cell-properties fo:padding-left="0.191cm" fo:padding-right="0.191cm" fo:padding-top="0cm" fo:padding-bottom="0cm" fo:border-left="none" fo:border-right="none" fo:border-top="0.5pt solid #000000" fo:border-bottom="0.5pt solid #000000"/>
+ </style:style>
+ <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Block">
+ <style:paragraph-properties fo:orphans="0" fo:widows="0"/>
+ </style:style>
+ <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Caption" style:master-page-name="Standard">
+ <style:paragraph-properties fo:margin-left="1.27cm" fo:margin-right="0cm" fo:text-indent="0cm" style:auto-text-indent="false" style:page-number="1"/>
+ </style:style>
+ <style:page-layout style:name="pm1">
+ <style:page-layout-properties fo:page-width="21.59cm" fo:page-height="27.94cm" style:num-format="i" style:print-orientation="portrait" fo:margin-top="0.847cm" fo:margin-bottom="1.27cm" fo:margin-left="3.81cm" fo:margin-right="2.54cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="36" style:layout-grid-base-height="0.635cm" style:layout-grid-ruby-height="0cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:layout-grid-base-width="0.423cm" style:layout-grid-snap-to="true" style:footnote-max-height="0cm" loext:margin-gutter="0cm">
+ <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/>
+ </style:page-layout-properties>
+ <style:header-style>
+ <style:header-footer-properties fo:min-height="1.27cm" fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-bottom="1.169cm" style:dynamic-spacing="true"/>
+ </style:header-style>
+ <style:footer-style>
+ <style:header-footer-properties fo:min-height="1.27cm" fo:margin-left="0cm" fo:margin-right="0cm" fo:margin-top="1.169cm" style:dynamic-spacing="true"/>
+ </style:footer-style>
+ </style:page-layout>
+ <style:style style:name="dp1" style:family="drawing-page">
+ <style:drawing-page-properties draw:background-size="full"/>
+ </style:style>
+ </office:automatic-styles>
+ <office:body>
+ <office:text>
+ <text:tracked-changes text:track-changes="false">
+ <text:changed-region xml:id="ct94794749170512" text:id="ct94794749170512">
+ <text:insertion>
+ <office:change-info>
+ <dc:creator>Author</dc:creator>
+ <dc:date>2004-01-12T03:00:00</dc:date>
+ </office:change-info>
+ </text:insertion>
+ </text:changed-region>
+ <text:changed-region xml:id="ct94794748244288" text:id="ct94794748244288">
+ <text:deletion>
+ <office:change-info>
+ <dc:creator>Author</dc:creator>
+ <dc:date>2004-01-05T21:45:00</dc:date>
+ </office:change-info>
+ </text:deletion>
+ </text:changed-region>
+ </text:tracked-changes>
+ <text:p text:style-name="P5"><text:change-start text:change-id="ct94794749170512"/>a<text:change-end text:change-id="ct94794749170512"/></text:p>
+ <text:p text:style-name="Contents_20_1"/>
+ <table:table table:name="Table1" table:style-name="Table1">
+ <table:table-column table:style-name="Table1.A"/>
+ <table:table-column table:style-name="Table1.B"/>
+ <table:table-row table:style-name="Table1.1">
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P1"/>
+ </table:table-cell>
+ <table:table-cell table:style-name="Table1.A1" office:value-type="string">
+ <text:p text:style-name="P1"/>
+ </table:table-cell>
+ </table:table-row>
+ </table:table>
+ <text:p text:style-name="Caption"><text:change-start text:change-id="ct94794748244288"/>s<text:change-end text:change-id="ct94794748244288"/></text:p>
+ </office:text>
+ </office:body>
+</office:document>
diff --git a/sw/qa/extras/uiwriter/data/tdf151548_tabNavigation.docm b/sw/qa/extras/uiwriter/data/tdf151548_tabNavigation.docm
new file mode 100644
index 000000000000..1b173e2041c2
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data/tdf151548_tabNavigation.docm
Binary files differ
diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx
index f895b59ba402..6df885ed946c 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -30,10 +30,12 @@
#include <comphelper/propertysequence.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/configuration.hxx>
+#include <unotools/mediadescriptor.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <i18nlangtag/languagetag.hxx>
#include <vcl/scheduler.hxx>
#include <vcl/settings.hxx>
+#include <vcl/filter/PDFiumLibrary.hxx>
#include <ndtxt.hxx>
#include <swdtflvr.hxx>
#include <wrtsh.hxx>
@@ -2070,6 +2072,25 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf144058)
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xTables->getCount());
}
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf147507)
+{
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf147507.fodt");
+
+ // turn on red-lining and show changes
+ pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete
+ | RedlineFlags::ShowInsert);
+ CPPUNIT_ASSERT_MESSAGE("redlining should be on",
+ pDoc->getIDocumentRedlineAccess().IsRedlineOn());
+ CPPUNIT_ASSERT_MESSAGE(
+ "redlines should be visible",
+ IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
+
+ // select all, backspace and reject all crashed
+ dispatchCommand(mxComponent, ".uno:SelectAll", {});
+ dispatchCommand(mxComponent, ".uno:SwBackSpace", {});
+ dispatchCommand(mxComponent, ".uno:RejectAllTrackedChanges", {});
+}
+
CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf119019)
{
// check handling of overlapping redlines
@@ -4061,7 +4082,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf147006)
CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf124261)
{
-#if !defined(_WIN32)
+#if !defined(_WIN32) && !defined(MACOSX)
// Make sure that pressing a key in a btlr cell frame causes an immediate, correct repaint.
SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf124261.docx");
SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
@@ -6069,6 +6090,54 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf126735)
CPPUNIT_ASSERT_EQUAL(OUString("or "), xTextRange->getString());
}
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testConditionalHiddenSectionIssue)
+{
+ // tdf#54703
+ // When exporting the bug document as PDF, the conditional hidden
+ // sections became visible in the PDF and in the document.
+
+ std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPDFium)
+ return;
+
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "HiddenSection.odt");
+
+ // Check section conditional hidden status - all should be hidden (IsCondHidden == true)
+ for (SwNodeOffset i(0); i < pDoc->GetNodes().Count(); ++i)
+ {
+ if (SwSectionNode const* const pNode = pDoc->GetNodes()[i]->GetSectionNode())
+ {
+ CPPUNIT_ASSERT_EQUAL(true, pNode->GetSection().IsCondHidden());
+ }
+ }
+
+ // PDF export
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
+ xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+
+ SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ);
+ SvMemoryStream aMemory;
+ aMemory.WriteStream(aFile);
+ auto pPdfDocument = pPDFium->openDocument(aMemory.GetData(), aMemory.GetSize(), OString());
+ CPPUNIT_ASSERT(pPdfDocument);
+ auto pPdfPage = pPdfDocument->openPage(0);
+ CPPUNIT_ASSERT(pPdfPage);
+
+ // No PDF object should be present in the page - sections remained hidden
+ CPPUNIT_ASSERT_EQUAL(0, pPdfPage->getObjectCount());
+
+ // Check section conditional hidden status - all should remained hidden (IsCondHidden == true)
+ for (SwNodeOffset i(0); i < pDoc->GetNodes().Count(); ++i)
+ {
+ if (SwSectionNode const* const pNode = pDoc->GetNodes()[i]->GetSectionNode())
+ {
+ CPPUNIT_ASSERT_EQUAL(true, pNode->GetSection().IsCondHidden());
+ }
+ }
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/uiwriter/uiwriter3.cxx b/sw/qa/extras/uiwriter/uiwriter3.cxx
index 068a14113a0b..a1a1272ae23d 100644
--- a/sw/qa/extras/uiwriter/uiwriter3.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter3.cxx
@@ -22,6 +22,7 @@
#include <com/sun/star/text/XTextTable.hpp>
#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
#include <com/sun/star/text/XPageCursor.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
#include <comphelper/propertysequence.hxx>
#include <boost/property_tree/json_parser.hpp>
#include <fmtanchr.hxx>
@@ -2471,7 +2472,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf145584)
SvMemoryStream aMemory;
aMemory.WriteStream(aFile);
std::unique_ptr<vcl::pdf::PDFiumDocument> pPdfDocument
- = pPDFium->openDocument(aMemory.GetData(), aMemory.GetSize());
+ = pPDFium->openDocument(aMemory.GetData(), aMemory.GetSize(), OString());
CPPUNIT_ASSERT(pPdfDocument);
CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount());
std::unique_ptr<vcl::pdf::PDFiumPage> pPdfPage = pPdfDocument->openPage(/*nIndex=*/0);
@@ -3920,6 +3921,39 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf103612)
"Text after section");
}
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testCrashOnExit)
+{
+ // Load the bugdoc with a table and a textbox shape inside.
+ CPPUNIT_ASSERT(createSwDoc(DATA_DIRECTORY, "tdf142715.odt"));
+ // Get the textbox selected
+ CPPUNIT_ASSERT_EQUAL(1, getShapes());
+ auto xShape = getShape(1);
+ CPPUNIT_ASSERT(xShape);
+ uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xModel);
+ uno::Reference<frame::XController> xController = xModel->getCurrentController();
+ CPPUNIT_ASSERT(xController);
+ uno::Reference<view::XSelectionSupplier> xSelection(xController, uno::UNO_QUERY);
+ CPPUNIT_ASSERT(xSelection);
+ CPPUNIT_ASSERT(xSelection->select(uno::Any(xShape)));
+ CPPUNIT_ASSERT(xSelection->getSelection().hasValue());
+ uno::Reference<beans::XPropertySet> xProperties(xShape, uno::UNO_QUERY);
+ // Check if the textbox is selected
+ CPPUNIT_ASSERT_EQUAL(true, xProperties->getPropertyValue("TextBox").get<bool>());
+ // Remove the textbox
+ dispatchCommand(mxComponent, ".uno:RemoveTextBox", {});
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(false, xProperties->getPropertyValue("TextBox").get<bool>());
+ // Readd the textbox (to run the textboxhelper::create() method)
+ dispatchCommand(mxComponent, ".uno:AddTextBox", {});
+ Scheduler::ProcessEventsToIdle();
+ CPPUNIT_ASSERT_EQUAL(true, xProperties->getPropertyValue("TextBox").get<bool>());
+ // save and reload
+ reload("writer8", "tdf142715_.odt");
+ // Before the fix this crashed here and could not reopen.
+ CPPUNIT_ASSERT_MESSAGE("Crash on exit, isn't it?", mxComponent);
+}
+
CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf97899)
{
SwDoc* pDoc = createSwDoc();
diff --git a/sw/qa/extras/uiwriter/uiwriter4.cxx b/sw/qa/extras/uiwriter/uiwriter4.cxx
index fc7bd27e3124..575e71681685 100644
--- a/sw/qa/extras/uiwriter/uiwriter4.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter4.cxx
@@ -195,6 +195,7 @@ public:
void testCursorWindows();
void testLandscape();
void testTdf95699();
+ void testTdf151548_tabNavigation();
void testTdf104032();
void testTdf104440();
void testTdf104425();
@@ -323,6 +324,7 @@ public:
CPPUNIT_TEST(testCursorWindows);
CPPUNIT_TEST(testLandscape);
CPPUNIT_TEST(testTdf95699);
+ CPPUNIT_TEST(testTdf151548_tabNavigation);
CPPUNIT_TEST(testTdf104032);
CPPUNIT_TEST(testTdf104440);
CPPUNIT_TEST(testTdf104425);
@@ -1445,11 +1447,50 @@ void SwUiWriterTest4::testTdf95699()
pMarkAccess = aClipboard.getIDocumentMarkAccess();
CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount());
::sw::mark::IFieldmark* pFieldMark
- = pMarkAccess->getFieldmarkAfter(SwPosition(pDoc->GetNodes().GetEndOfExtras()));
+ = pMarkAccess->getFieldmarkAfter(SwPosition(pDoc->GetNodes().GetEndOfExtras()), false);
CPPUNIT_ASSERT_EQUAL(OUString("vnd.oasis.opendocument.field.FORMCHECKBOX"),
pFieldMark->GetFieldname());
}
+void SwUiWriterTest4::testTdf151548_tabNavigation()
+{
+ // given a form-protected doc with 4 unchecked legacy fieldmark checkboxes (and several modern
+ // content controls which all have a tabstop of -1 to disable tabstop navigation to them)
+ // we want to test that tab navigation completes and loops around to continue at the beginning.
+ SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf151548_tabNavigation.docm");
+ SwXTextDocument* pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+
+ IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pMarkAccess->getFieldmarksCount());
+
+ // Tab and toggle 4 times, verifying beforehand that the state was unchecked
+ for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
+ {
+ sw::mark::ICheckboxFieldmark* pCheckBox
+ = dynamic_cast<::sw::mark::ICheckboxFieldmark*>(*it);
+ CPPUNIT_ASSERT(!pCheckBox->IsChecked());
+
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE); // toggle checkbox on
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); // move to next control
+ Scheduler::ProcessEventsToIdle();
+ }
+
+ // Tab 4 more times, verifying beforehand that the checkbox had been toggle on, then toggles off
+ // meaning that looping is working, and no other controls are reacting to the tab key.
+ for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
+ {
+ sw::mark::ICheckboxFieldmark* pCheckBox
+ = dynamic_cast<::sw::mark::ICheckboxFieldmark*>(*it);
+
+ CPPUNIT_ASSERT(pCheckBox->IsChecked());
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE); // toggle checkbox off
+ Scheduler::ProcessEventsToIdle();
+
+ CPPUNIT_ASSERT(!pCheckBox->IsChecked());
+ pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); // move to next control
+ }
+}
+
void SwUiWriterTest4::testTdf104032()
{
// Open the document with FORMCHECKBOX field, select it and copy to clipboard
diff --git a/sw/qa/extras/ww8export/data/tdf151548_formFieldMacros.doc b/sw/qa/extras/ww8export/data/tdf151548_formFieldMacros.doc
new file mode 100644
index 000000000000..4ea915f0afe4
--- /dev/null
+++ b/sw/qa/extras/ww8export/data/tdf151548_formFieldMacros.doc
Binary files differ
diff --git a/sw/qa/extras/ww8export/ww8export4.cxx b/sw/qa/extras/ww8export/ww8export4.cxx
new file mode 100644
index 000000000000..f686cd99d021
--- /dev/null
+++ b/sw/qa/extras/ww8export/ww8export4.cxx
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+
+#include <comphelper/sequenceashashmap.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <docsh.hxx>
+#include <IDocumentMarkAccess.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <unotxdoc.hxx>
+
+class Test : public SwModelTestBase
+{
+public:
+ Test()
+ : SwModelTestBase("/sw/qa/extras/ww8export/data/", "MS Word 97")
+ {
+ }
+
+ bool mustTestImportOf(const char* filename) const override
+ {
+ // If the testcase is stored in some other format, it's pointless to test.
+ return o3tl::ends_with(filename, ".doc");
+ }
+};
+
+
+DECLARE_WW8EXPORT_TEST(testTdf151548_formFieldMacros, "tdf151548_formFieldMacros.doc")
+{
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
+ SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
+ IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+ for(auto aIter = pMarkAccess->getFieldmarksBegin(); aIter != pMarkAccess->getFieldmarksEnd(); ++aIter)
+ {
+ const OUString sName = (*aIter)->GetName();
+ CPPUNIT_ASSERT(sName == "Check1" || sName == "Check2" || sName == "Text1" || sName == "Dropdown1");
+ }
+}
+
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/ww8import/data/tdf120761_zOrder.doc b/sw/qa/extras/ww8import/data/tdf120761_zOrder.dot
index b70a7d840b6d..b70a7d840b6d 100644
--- a/sw/qa/extras/ww8import/data/tdf120761_zOrder.doc
+++ b/sw/qa/extras/ww8import/data/tdf120761_zOrder.dot
Binary files differ
diff --git a/sw/qa/extras/ww8import/ww8import.cxx b/sw/qa/extras/ww8import/ww8import.cxx
index 7eb0c9f6b221..8c77217c7610 100644
--- a/sw/qa/extras/ww8import/ww8import.cxx
+++ b/sw/qa/extras/ww8import/ww8import.cxx
@@ -275,7 +275,7 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf110987)
CPPUNIT_TEST_FIXTURE(Test, testTdf120761_zOrder)
{
- load(mpTestDocumentPath, "tdf120761_zOrder.doc");
+ load(mpTestDocumentPath, "tdf120761_zOrder.dot");
//The blue shape was covering everything (highest zorder = 2) instead of the lowest(0)
uno::Reference<drawing::XShape> xShape(getShapeByName(u"Picture 2"), uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), getProperty<sal_uInt32>(xShape, "ZOrder"));
diff --git a/sw/qa/filter/ww8/ww8.cxx b/sw/qa/filter/ww8/ww8.cxx
new file mode 100644
index 000000000000..3848decc4f46
--- /dev/null
+++ b/sw/qa/filter/ww8/ww8.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <com/sun/star/awt/CharSet.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
+
+#include <docsh.hxx>
+#include <formatcontentcontrol.hxx>
+#include <wrtsh.hxx>
+#include <unotxdoc.hxx>
+
+namespace
+{
+/**
+ * Covers sw/source/filter/ww8/ fixes.
+ *
+ * Note that these tests are meant to be simple: either load a file and assert some result or build
+ * a document model with code, export and assert that result.
+ *
+ * Keep using the various sw_<format>import/export suites for multiple filter calls inside a single
+ * test.
+ */
+class Test : public SwModelTestBase
+{
+};
+
+CPPUNIT_TEST_FIXTURE(Test, testPlainTextContentControlExport)
+{
+ // Given a document with a plain text content control around a text portion:
+ mxComponent = loadFromDesktop("private:factory/swriter");
+ uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ xText->insertString(xCursor, "test", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->gotoEnd(/*bExpand=*/true);
+ uno::Reference<text::XTextContent> xContentControl(
+ xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
+ xContentControlProps->setPropertyValue("PlainText", uno::Any(true));
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+
+ // When exporting to DOCX:
+ save("Office Open XML Text", maTempFile);
+ mbExported = true;
+
+ // Then make sure the expected markup is used:
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // - XPath '//w:sdt/w:sdtPr/w:text' number of nodes is incorrect
+ // i.e. the plain text content control was turned into a rich text one on export.
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:text", 1);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testDocxComboBoxContentControlExport)
+{
+ // Given a document with a combo box content control around a text portion:
+ mxComponent = loadFromDesktop("private:factory/swriter");
+ SwDocShell* pDocShell = dynamic_cast<SwXTextDocument*>(mxComponent.get())->GetDocShell();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::COMBO_BOX);
+
+ // When exporting to DOCX:
+ save("Office Open XML Text", maTempFile);
+ mbExported = true;
+
+ // Then make sure the expected markup is used:
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // - XPath '//w:sdt/w:sdtPr/w:comboBox' number of nodes is incorrect
+ // i.e. the combo box content control was turned into a drop-down one on export.
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:comboBox", 1);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testDocxHyperlinkShape)
+{
+ // Given a document with a hyperlink at char positions 0 -> 6 and a shape with text anchored at
+ // char position 6:
+ mxComponent = loadFromDesktop("private:factory/swriter");
+ uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+ xText->insertString(xCursor, "beforeafter", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->goRight(/*nCount=*/6, /*bExpand=*/true);
+ uno::Reference<beans::XPropertySet> xCursorProps(xCursor, uno::UNO_QUERY);
+ xCursorProps->setPropertyValue("HyperLinkURL", uno::Any(OUString("http://www.example.com/")));
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->goRight(/*nCount=*/6, /*bExpand=*/false);
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<drawing::XShape> xShape(
+ xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
+ xShape->setSize(awt::Size(5000, 5000));
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ xShapeProps->setPropertyValue("AnchorType", uno::Any(text::TextContentAnchorType_AT_CHARACTER));
+ uno::Reference<text::XTextContent> xShapeContent(xShape, uno::UNO_QUERY);
+ xText->insertTextContent(xCursor, xShapeContent, /*bAbsorb=*/false);
+ xShapeProps->setPropertyValue("TextBox", uno::Any(true));
+
+ // When saving this document to DOCX, then make sure we don't crash on export (due to an
+ // assertion failure for not-well-formed XML output):
+ save("Office Open XML Text", maTempFile);
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testDocxSymbolFontExport)
+{
+ // Create document with symbol character and font Wingdings
+ mxComponent = loadFromDesktop("private:factory/swriter");
+ uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XText> xText = xTextDocument->getText();
+ uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
+
+ xText->insertString(xCursor, u"", true);
+
+ uno::Reference<text::XTextRange> xRange = xCursor;
+ uno::Reference<beans::XPropertySet> xTextProps(xRange, uno::UNO_QUERY);
+ xTextProps->setPropertyValue("CharFontName", uno::Any(OUString("Wingdings")));
+ xTextProps->setPropertyValue("CharFontNameAsian", uno::Any(OUString("Wingdings")));
+ xTextProps->setPropertyValue("CharFontNameComplex", uno::Any(OUString("Wingdings")));
+ xTextProps->setPropertyValue("CharFontCharSet", uno::Any(awt::CharSet::SYMBOL));
+
+ // When exporting to DOCX:
+ save("Office Open XML Text", maTempFile);
+ mbExported = true;
+
+ // Then make sure the expected markup is used:
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+
+ assertXPath(pXmlDoc, "//w:p/w:r/w:sym", 1);
+ assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "font", "Wingdings");
+ assertXPath(pXmlDoc, "//w:p/w:r/w:sym[1]", "char", "f0e0");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testDocxContentControlDropdownEmptyDisplayText)
+{
+ // Given a document with a dropdown content control, the only list item has no display text
+ // (only a value):
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);
+
+ // When saving to DOCX:
+ save("Office Open XML Text", maTempFile);
+ mbExported = true;
+
+ // Then make sure that no display text attribute is written:
+ xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - XPath '//w:sdt/w:sdtPr/w:dropDownList/w:listItem' unexpected 'displayText' attribute
+ // i.e. we wrote an empty attribute instead of omitting it.
+ assertXPathNoAttribute(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem", "displayText");
+}
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/inc/swmodeltestbase.hxx b/sw/qa/inc/swmodeltestbase.hxx
index f1e8444c4c52..f3ae9688c64a 100644
--- a/sw/qa/inc/swmodeltestbase.hxx
+++ b/sw/qa/inc/swmodeltestbase.hxx
@@ -102,6 +102,14 @@
CPPUNIT_TEST_SUITE_REGISTRATION(TestName); \
void TestName::verify()
+namespace vcl
+{
+namespace pdf
+{
+class PDFiumDocument;
+}
+}
+
/// Base class for filter tests loading or roundtripping a document, then asserting the document model.
class SWQAHELPER_DLLPUBLIC SwModelTestBase : public test::BootstrapFixture, public unotest::MacrosTest, public XmlTestTools
{
@@ -121,6 +129,7 @@ protected:
sal_uInt32 mnStartTime;
utl::TempFile maTempFile;
+ SvMemoryStream maMemory; ///< Underlying memory for parsed PDF files.
bool mbExported; ///< Does maTempFile already contain something useful?
protected:
@@ -401,6 +410,10 @@ protected:
*/
SwDoc* createSwWebDoc(
std::u16string_view rDataDirectory = std::u16string_view(), const char* pName = nullptr);
+
+ void StoreToTempFile(const OUString& rFilterName);
+
+ std::unique_ptr<vcl::pdf::PDFiumDocument> LoadPdfFromTempFile();
};
/**
diff --git a/sw/qa/uibase/dialog/dialog.cxx b/sw/qa/uibase/dialog/dialog.cxx
new file mode 100644
index 000000000000..5c94ef08e861
--- /dev/null
+++ b/sw/qa/uibase/dialog/dialog.cxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+
+#include <wrtsh.hxx>
+#include <docsh.hxx>
+
+namespace
+{
+/// Covers sw/source/uibase/dialog/ fixes.
+class Test : public SwModelTestBase
+{
+public:
+ Test()
+ : SwModelTestBase("/sw/qa/uibase/dialog/data/")
+ {
+ }
+};
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testInsertSection)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting a section with text:
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue(
+ "RegionName", uno::Any(OUString("ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RNDRfiit6mXBc"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("<p>aaa</p><p>bbb</p>"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertSection", aArgs);
+
+ // Then make sure that we created a section that covers that text:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->EndOfSection(/*bSelect=*/true);
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ OUString aActualResult = pCursor->GetText();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: aaa\nbbb
+ // - Actual :
+ // i.e. the value of the Content parameter was ignored.
+ CPPUNIT_ASSERT_EQUAL(OUString("aaa\nbbb"), aActualResult);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/uibase/fldui/fldui.cxx b/sw/qa/uibase/fldui/fldui.cxx
index b3785f5ee072..b9a69936bd50 100644
--- a/sw/qa/uibase/fldui/fldui.cxx
+++ b/sw/qa/uibase/fldui/fldui.cxx
@@ -19,6 +19,7 @@
#include <wrtsh.hxx>
#include <fldmgr.hxx>
#include <authfld.hxx>
+#include <ndtxt.hxx>
using namespace com::sun::star;
@@ -91,6 +92,32 @@ CPPUNIT_TEST_FIXTURE(Test, testBiblioPageNumberUpdate)
// i.e. the second biblio field's URL was not updated.
CPPUNIT_ASSERT_EQUAL(aNewUrl, pEntry->GetAuthorField(AUTH_FIELD_URL));
}
+
+CPPUNIT_TEST_FIXTURE(Test, testInsertRefmark)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting a refmark with text:
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue(
+ "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} RNDpyJknp173F"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("aaa<b>bbb</b>ccc"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+ // Then make sure that we create a refmark that covers that text:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+ std::vector<SwTextAttr*> aAttrs = pTextNode->GetTextAttrsAt(0, RES_TXTATR_REFMARK);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. no refmark was created, only the hard to read Type=12 created a refmark.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aAttrs.size());
+ CPPUNIT_ASSERT_EQUAL(OUString("aaabbbccc"), pTextNode->GetText());
+}
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index 4bde6eab7ac6..a41bd2299b5f 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -24,6 +24,10 @@
#include <editeng/editobj.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/propertyvalue.hxx>
+#include <xmloff/odffields.hxx>
+#include <comphelper/string.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
#include <IDocumentContentOperations.hxx>
#include <cmdid.h>
@@ -33,6 +37,10 @@
#include <IDocumentDrawModelAccess.hxx>
#include <drawdoc.hxx>
#include <docsh.hxx>
+#include <bookmark.hxx>
+#include <ndtxt.hxx>
+#include <ftnidx.hxx>
+#include <txtftn.hxx>
constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/uibase/shells/data/";
@@ -238,6 +246,690 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testContentControlPageBreak)
CPPUNIT_ASSERT_EQUAL(1, getPages());
}
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertTextFormField)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting an ODF_UNHANDLED fieldmark:
+ OUString aExpectedCommand("ADDIN ZOTERO_BIBL foo bar");
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand", uno::Any(aExpectedCommand)),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("<p>aaa</p><p>bbb</p>"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+
+ // Then make sure that it's type/name is correct:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ pCursor->SttEndDoc(/*bSttDoc=*/true);
+ sw::mark::IFieldmark* pFieldmark
+ = pDoc->getIDocumentMarkAccess()->getFieldmarkAt(*pCursor->GetPoint());
+ CPPUNIT_ASSERT(pFieldmark);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: vnd.oasis.opendocument.field.UNHANDLED
+ // - Actual : vnd.oasis.opendocument.field.FORMTEXT
+ // i.e. the custom type parameter was ignored.
+ CPPUNIT_ASSERT_EQUAL(OUString(ODF_UNHANDLED), pFieldmark->GetFieldname());
+
+ auto it = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
+ CPPUNIT_ASSERT(it != pFieldmark->GetParameters()->end());
+ OUString aActualCommand;
+ it->second >>= aActualCommand;
+ CPPUNIT_ASSERT_EQUAL(aExpectedCommand, aActualCommand);
+
+ SwPaM aPam(pFieldmark->GetMarkStart(), pFieldmark->GetMarkEnd());
+ // Ignore the leading field start + sep.
+ aPam.GetMark()->nContent = aPam.GetMark()->nContent.GetIndex() + 2;
+ // Ignore the trailing field end.
+ aPam.GetPoint()->nContent = aPam.GetPoint()->nContent.GetIndex() - 1;
+ CPPUNIT_ASSERT(aPam.HasMark());
+ OUString aActualResult = aPam.GetText();
+ CPPUNIT_ASSERT_EQUAL(OUString("aaa\nbbb"), aActualResult);
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateFieldmarks)
+{
+ // Given a document with 2 fieldmarks:
+ SwDoc* pDoc = createSwDoc();
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM old command 1"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("old result 1"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+ }
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM old command 2"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("old result 2"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+ }
+
+ // When updating those fieldmarks:
+ uno::Sequence<css::beans::PropertyValue> aField1{
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM new command 1"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("new result 1"))),
+ };
+ uno::Sequence<css::beans::PropertyValue> aField2{
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM new command 2"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("new result 2"))),
+ };
+ uno::Sequence<uno::Sequence<css::beans::PropertyValue>> aFields = { aField1, aField2 };
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommandPrefix",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM"))),
+ comphelper::makePropertyValue("Fields", uno::Any(aFields)),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormFields", aArgs);
+
+ // Then make sure that the document text contains the new field results:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ OUString aActual = pCursor->Start()->nNode.GetNode().GetTextNode()->GetText();
+ static sal_Unicode const aForbidden[]
+ = { CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP, CH_TXT_ATR_FIELDEND, 0 };
+ aActual = comphelper::string::removeAny(aActual, aForbidden);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: new result 1new result 2
+ // - Actual : old result 1old result 2
+ // i.e. the fieldmarks were not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("new result 1new result 2"), aActual);
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertBookmark)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting a bookmark with text:
+ OUString aExpectedBookmarkName("ZOTERO_BREF_GiQ7DAWQYWLy");
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("Bookmark", uno::Any(aExpectedBookmarkName)),
+ comphelper::makePropertyValue("BookmarkText", uno::Any(OUString("<p>aaa</p><p>bbb</p>"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertBookmark", aArgs);
+
+ // Then make sure that we create a bookmark that covers that text:
+ IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), rIDMA.getBookmarksCount());
+ for (auto it = rIDMA.getBookmarksBegin(); it != rIDMA.getBookmarksEnd(); ++it)
+ {
+ sw::mark::IMark* pMark = *it;
+ CPPUNIT_ASSERT_EQUAL(aExpectedBookmarkName, pMark->GetName());
+ SwPaM aPam(pMark->GetMarkStart(), pMark->GetMarkEnd());
+ OUString aActualResult = aPam.GetText();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: aaa\nbbb
+ // - Actual :
+ // i.e. no text was inserted, the bookmark was collapsed.
+ CPPUNIT_ASSERT_EQUAL(OUString("aaa\nbbb"), aActualResult);
+ }
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateBookmarks)
+{
+ // Given a document with 2 bookmarks, first covering "B" and second covering "D":
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("ABCDE");
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
+ pWrtShell->SetBookmark(vcl::KeyCode(), "ZOTERO_BREF_GiQ7DAWQYWLy");
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
+ pWrtShell->SetBookmark(vcl::KeyCode(), "ZOTERO_BREF_PRxDGUb4SWXF");
+
+ // When updating the content of bookmarks:
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "BookmarkNamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_BREF_"
+ },
+ "Bookmarks": {
+ "type": "[][]com.sun.star.beans.PropertyValue",
+ "value": [
+ {
+ "Bookmark": {
+ "type": "string",
+ "value": "ZOTERO_BREF_new1"
+ },
+ "BookmarkText": {
+ "type": "string",
+ "value": "new result 1"
+ }
+ },
+ {
+ "Bookmark": {
+ "type": "string",
+ "value": "ZOTERO_BREF_new2"
+ },
+ "BookmarkText": {
+ "type": "string",
+ "value": "new result 2"
+ }
+ }
+ ]
+ }
+}
+)json");
+ uno::Sequence<beans::PropertyValue> aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:UpdateBookmarks", aArgs);
+
+ // Then make sure that the only paragraph is updated correctly:
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ OUString aActual = pCursor->GetPoint()->nNode.GetNode().GetTextNode()->GetText();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: Anew result 1Cnew result 2E
+ // - Actual : ABCDE
+ // i.e. the content was not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("Anew result 1Cnew result 2E"), aActual);
+
+ // Without the accompanying fix in place, this test would have failed, ZOTERO_BREF_GiQ7DAWQYWLy
+ // was not renamed to ZOTERO_BREF_new1.
+ auto it = pDoc->getIDocumentMarkAccess()->findMark("ZOTERO_BREF_new1");
+ CPPUNIT_ASSERT(it != pDoc->getIDocumentMarkAccess()->getAllMarksEnd());
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertFieldmarkReadonly)
+{
+ // Given a document with a fieldmark, the cursor inside the fieldmark:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand", uno::Any(OUString("my command"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("my result"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ pCursor->SttEndDoc(/*bSttDoc=*/true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+
+ // When trying to insert an inner fieldmark:
+ // Without the accompanying fix in place, this test would have crashed.
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+
+ // Then make sure the read-only content refuses to accept that inner fieldmark, so we still have
+ // just one:
+ size_t nActual = 0;
+ IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
+ for (auto it = rIDMA.getFieldmarksBegin(); it != rIDMA.getFieldmarksEnd(); ++it)
+ {
+ ++nActual;
+ }
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), nActual);
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmarks)
+{
+ // Given a document with two refmarks, one is not interesting the other is a citation:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue("Name", uno::Any(OUString("some other old refmark"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("some other old content"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/false);
+ pWrtShell->SplitNode();
+ pWrtShell->SttEndDoc(/*bStt=*/false);
+ aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue(
+ "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} old refmark"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("old content"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+ // When updating that refmark:
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "TypeName": {
+ "type": "string",
+ "value": "SetRef"
+ },
+ "NamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_ITEM CSL_CITATION"
+ },
+ "Fields": {
+ "type": "[][]com.sun.star.beans.PropertyValue",
+ "value": [
+ {
+ "Name": {
+ "type": "string",
+ "value": "ZOTERO_ITEM CSL_CITATION {} new refmark"
+ },
+ "Content": {
+ "type": "string",
+ "value": "new content"
+ }
+ }
+ ]
+ }
+}
+)json");
+ aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:UpdateFields", aArgs);
+
+ // Then make sure that the document text features the new content:
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: new content
+ // - Actual : old content
+ // i.e. the doc content was not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("new content"), pTextNode->GetText());
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateFieldmark)
+{
+ // Given a document with a fieldmark:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM old command 1"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("old result 1"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+
+ // When updating that fieldmark to have new field command & result:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "FieldType": {
+ "type": "string",
+ "value": "vnd.oasis.opendocument.field.UNHANDLED"
+ },
+ "FieldCommandPrefix": {
+ "type": "string",
+ "value": "ADDIN ZOTERO_ITEM"
+ },
+ "Field": {
+ "type": "[]com.sun.star.beans.PropertyValue",
+ "value": {
+ "FieldType": {
+ "type": "string",
+ "value": "vnd.oasis.opendocument.field.UNHANDLED"
+ },
+ "FieldCommand": {
+ "type": "string",
+ "value": "ADDIN ZOTERO_ITEM new command 1"
+ },
+ "FieldResult": {
+ "type": "string",
+ "value": "new result 1"
+ }
+ }
+ }
+}
+)json");
+ aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:UpdateTextFormField", aArgs);
+
+ // Then make sure that the document text is updated accordingly:
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ OUString aActual = pCursor->Start()->GetNode().GetTextNode()->GetText();
+ static sal_Unicode const aForbidden[]
+ = { CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP, CH_TXT_ATR_FIELDEND, 0 };
+ aActual = comphelper::string::removeAny(aActual, aForbidden);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: new result 1
+ // - Actual : old result 1
+ // i.e. the document text was not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("new result 1"), aActual);
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateSections)
+{
+ // Given a document with a section:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("RegionName",
+ uno::Any(OUString("ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RNDold"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("old content"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertSection", aArgs);
+
+ // When updating that section:
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "SectionNamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_BIBL"
+ },
+ "Sections": {
+ "type": "[][]com.sun.star.beans.PropertyValue",
+ "value": [
+ {
+ "RegionName": {
+ "type": "string",
+ "value": "ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RNDnew"
+ },
+ "Content": {
+ "type": "string",
+ "value": "new content"
+ }
+ }
+ ]
+ }
+}
+)json");
+ aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:UpdateSections", aArgs);
+
+ // Then make sure that the section is updated:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->EndOfSection(/*bSelect=*/true);
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ OUString aActualResult = pCursor->GetText();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: new content
+ // - Actual : old content
+ // i.e. the content wasn't updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("new content"), aActualResult);
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDeleteFieldmarks)
+{
+ // Given a document with 2 fieldmarks:
+ SwDoc* pDoc = createSwDoc();
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM old command 1"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result 1"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+ }
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM old command 2"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result 2"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+ }
+
+ // When deleting those fieldmarks:
+ uno::Sequence<css::beans::PropertyValue> aArgs
+ = { comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommandPrefix",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM"))) };
+ dispatchCommand(mxComponent, ".uno:DeleteTextFormFields", aArgs);
+
+ // Then make sure that the document doesn't contain fields anymore:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 2
+ // i.e. the fieldmarks were not deleted.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0),
+ pDoc->getIDocumentMarkAccess()->getAllMarksCount());
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ OUString aActual = pCursor->Start()->GetNode().GetTextNode()->GetText();
+ CPPUNIT_ASSERT_EQUAL(OUString("result 1result 2"), aActual);
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateBookmark)
+{
+ // Given a document with a bookmarks, covering "BC":
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("ABCD");
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 2, /*bBasicCall=*/false);
+ pWrtShell->SetBookmark(vcl::KeyCode(), "ZOTERO_BREF_old");
+
+ // When updating the content of the bookmark under the cursor:
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "BookmarkNamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_BREF_"
+ },
+ "Bookmark": {
+ "type": "[]com.sun.star.beans.PropertyValue",
+ "value": {
+ "Bookmark": {
+ "type": "string",
+ "value": "ZOTERO_BREF_new"
+ },
+ "BookmarkText": {
+ "type": "string",
+ "value": "new result"
+ }
+ }
+ }
+}
+)json");
+ uno::Sequence<beans::PropertyValue> aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:UpdateBookmark", aArgs);
+
+ // Then make sure that the only paragraph is updated correctly:
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ OUString aActual = pCursor->GetNode().GetTextNode()->GetText();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: Anew resultD
+ // - Actual : ABCD
+ // i.e. it was not possible to update just the bookmark under cursor.
+ CPPUNIT_ASSERT_EQUAL(OUString("Anew resultD"), aActual);
+ auto it = pDoc->getIDocumentMarkAccess()->findMark("ZOTERO_BREF_new");
+ CPPUNIT_ASSERT(it != pDoc->getIDocumentMarkAccess()->getAllMarksEnd());
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmark)
+{
+ // Given a document with a refmark:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue(
+ "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} old refmark"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("old content"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+ // When updating that refmark:
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "TypeName": {
+ "type": "string",
+ "value": "SetRef"
+ },
+ "NamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_ITEM CSL_CITATION"
+ },
+ "Field": {
+ "type": "[]com.sun.star.beans.PropertyValue",
+ "value": {
+ "Name": {
+ "type": "string",
+ "value": "ZOTERO_ITEM CSL_CITATION {} new refmark"
+ },
+ "Content": {
+ "type": "string",
+ "value": "new content"
+ }
+ }
+ }
+}
+)json");
+ aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:UpdateField", aArgs);
+
+ // Then make sure that the document text features the new content:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: new content
+ // - Actual : old content
+ // i.e. the content was not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("new content"), pTextNode->GetText());
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDeleteBookmarks)
+{
+ // Given a document with 2 bookmarks, first covering "B" and second covering "D":
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("ABCDE");
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
+ pWrtShell->SetBookmark(vcl::KeyCode(), "ZOTERO_BREF_GiQ7DAWQYWLy");
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
+ pWrtShell->SetBookmark(vcl::KeyCode(), "other");
+
+ // When deleting 1 matching bookmark:
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "BookmarkNamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_BREF_"
+ }
+}
+)json");
+ uno::Sequence<beans::PropertyValue> aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:DeleteBookmarks", aArgs);
+
+ // Then make sure that only the other bookmark is kept:
+ auto it = pDoc->getIDocumentMarkAccess()->findMark("ZOTERO_BREF_GiQ7DAWQYWLy");
+ // Without the accompanying fix in place, this test would have failed, the matching bookmark was
+ // not removed.
+ CPPUNIT_ASSERT(bool(it == pDoc->getIDocumentMarkAccess()->getAllMarksEnd()));
+ it = pDoc->getIDocumentMarkAccess()->findMark("other");
+ CPPUNIT_ASSERT(it != pDoc->getIDocumentMarkAccess()->getAllMarksEnd());
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDeleteFields)
+{
+ // Given a document with a refmark:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue(
+ "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} RNDpyJknp173F"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("aaa<b>bbb</b>ccc"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+ // When deleting the refmarks:
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "TypeName": {
+ "type": "string",
+ "value": "SetRef"
+ },
+ "NamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_ITEM CSL_CITATION"
+ }
+}
+)json");
+ aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:DeleteFields", aArgs);
+
+ // Then make sure that no refmark is kept:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 1
+ // i.e. the refmark was not deleted.
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(0), pDoc->GetRefMarks());
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertTextFormFieldFootnote)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting an ODF_UNHANDLED fieldmark inside a footnote:
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_BIBL foo bar"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result"))),
+ comphelper::makePropertyValue("Wrapper", uno::Any(OUString("Footnote"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+
+ // Then make sure that the footnote is created:
+ SwFootnoteIdxs& rFootnotes = pDoc->GetFootnoteIdxs();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. no footnote was created.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rFootnotes.size());
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertTextFormFieldEndnote)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting an ODF_UNHANDLED fieldmark inside an endnote:
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_BIBL foo bar"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result"))),
+ comphelper::makePropertyValue("Wrapper", uno::Any(OUString("Endnote"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+
+ // Then make sure that the endnote is created:
+ SwFootnoteIdxs& rFootnotes = pDoc->GetFootnoteIdxs();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. no endnote was inserted.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rFootnotes.size());
+ SwTextFootnote* pEndnote = rFootnotes[0];
+ const SwFormatFootnote& rFormatEndnote = pEndnote->GetFootnote();
+ CPPUNIT_ASSERT(rFormatEndnote.IsEndNote());
+ // Also check that the endnote body contains the fieldmark:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/true);
+ pWrtShell->GotoFootnoteText();
+ pWrtShell->EndOfSection(/*bSelect=*/true);
+ SwCursor* pCursor = pWrtShell->GetCursor();
+ OUString aActual = pCursor->GetText();
+ static sal_Unicode const aForbidden[]
+ = { CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP, CH_TXT_ATR_FIELDEND, 0 };
+ aActual = comphelper::string::removeAny(aActual, aForbidden);
+ // Then this was empty: the fieldmark was inserted before the note anchor, not in the note body.
+ CPPUNIT_ASSERT_EQUAL(OUString("result"), aActual);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/uibase/shells/textfld.cxx b/sw/qa/uibase/shells/textfld.cxx
new file mode 100644
index 000000000000..1ef61b658c4a
--- /dev/null
+++ b/sw/qa/uibase/shells/textfld.cxx
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+
+#include <wrtsh.hxx>
+#include <docsh.hxx>
+#include <ftnidx.hxx>
+#include <txtftn.hxx>
+
+namespace
+{
+/// Covers sw/source/uibase/shells/textfld.cxx fixes.
+class Test : public SwModelTestBase
+{
+public:
+ Test()
+ : SwModelTestBase("/sw/qa/uibase/shells/data/")
+ {
+ }
+};
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testInsertRefmarkFootnote)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting a refmark inside a footnote:
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue("Name", uno::Any(OUString("myref"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("content"))),
+ comphelper::makePropertyValue("Wrapper", uno::Any(OUString("Footnote"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+ // Then make sure that the note body contains the refmark:
+ SwFootnoteIdxs& rNotes = pDoc->GetFootnoteIdxs();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. no note was inserted.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rNotes.size());
+ SwTextFootnote* pNote = rNotes[0];
+ const SwFormatFootnote& rFormatNote = pNote->GetFootnote();
+ CPPUNIT_ASSERT(!rFormatNote.IsEndNote());
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ CPPUNIT_ASSERT_EQUAL(OUString("content"), rFormatNote.GetFootnoteText(*pWrtShell->GetLayout()));
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testInsertRefmarkEndnote)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting a refmark inside an endnote:
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue("Name", uno::Any(OUString("myref"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("content"))),
+ comphelper::makePropertyValue("Wrapper", uno::Any(OUString("Endnote"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+ // Then make sure that the note body contains the refmark:
+ SwFootnoteIdxs& rNotes = pDoc->GetFootnoteIdxs();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 0
+ // i.e. no endnote was inserted.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rNotes.size());
+ SwTextFootnote* pNote = rNotes[0];
+ const SwFormatFootnote& rNote = pNote->GetFootnote();
+ CPPUNIT_ASSERT(rNote.IsEndNote());
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ CPPUNIT_ASSERT_EQUAL(OUString("content"), rNote.GetFootnoteText(*pWrtShell->GetLayout()));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/uibase/shells/textsh.cxx b/sw/qa/uibase/shells/textsh.cxx
new file mode 100644
index 000000000000..f367510b7a2f
--- /dev/null
+++ b/sw/qa/uibase/shells/textsh.cxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <docary.hxx>
+
+namespace
+{
+/// Covers sw/source/uibase/shells/textsh.cxx fixes.
+class Test : public SwModelTestBase
+{
+public:
+ Test()
+ : SwModelTestBase("/sw/qa/uibase/shells/data/")
+ {
+ }
+};
+
+CPPUNIT_TEST_FIXTURE(Test, testDeleteSections)
+{
+ // Given a document with a section:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("RegionName",
+ uno::Any(OUString("ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RND"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("old content"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertSection", aArgs);
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDoc->GetSections().size());
+
+ // When deleting sections:
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "SectionNamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_BIBL"
+ }
+}
+)json");
+ aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:DeleteSections", aArgs);
+
+ // Then make sure that the section is deleted:
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 0
+ // - Actual : 1
+ // i.e. the section was not deleted.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), pDoc->GetSections().size());
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/uibase/uno/uno.cxx b/sw/qa/uibase/uno/uno.cxx
index f4b337d8f9d2..ee6ce3f1ac70 100644
--- a/sw/qa/uibase/uno/uno.cxx
+++ b/sw/qa/uibase/uno/uno.cxx
@@ -9,11 +9,17 @@
#include <swmodeltestbase.hxx>
+#include <boost/property_tree/json_parser.hpp>
+
#include <com/sun/star/frame/XModel2.hpp>
#include <com/sun/star/text/XTextViewTextRangeSupplier.hpp>
#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <vcl/scheduler.hxx>
+#include <tools/json_writer.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <xmloff/odffields.hxx>
#include <docsh.hxx>
#include <edtwin.hxx>
@@ -22,6 +28,7 @@
#include <wrtsh.hxx>
constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/uibase/uno/data/";
+#include <unotxdoc.hxx>
/// Covers sw/source/uibase/uno/ fixes.
class SwUibaseUnoTest : public SwModelTestBase
@@ -90,6 +97,311 @@ CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testCreateTextRangeByPixelPosition)
CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), nActual);
}
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetTextFormFields)
+{
+ // Given a document with 3 fieldmarks: 2 zotero items and a zotero
+ // bibliography:
+ createSwDoc();
+ for (int i = 0; i < 2; ++i)
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM foo bar"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+ }
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_BIBL foo bar"))),
+ comphelper::makePropertyValue("FieldResult",
+ uno::Any(OUString("<p>aaa</p><p>bbb</p>"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+ }
+
+ // When getting the zotero items:
+ tools::JsonWriter aJsonWriter;
+ OString aCommand(".uno:TextFormFields?type=vnd.oasis.opendocument.field.UNHANDLED&"
+ "commandPrefix=ADDIN%20ZOTERO_ITEM");
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+ // Then make sure we find the 2 items and ignore the bibliography:
+ std::unique_ptr<char[], o3tl::free_delete> pJSON(aJsonWriter.extractData());
+ std::stringstream aStream(pJSON.get());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - No such node (fields)
+ // i.e. the returned JSON was just empty.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aTree.get_child("fields").count(""));
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetDocumentProperties)
+{
+ // Given a document with 3 custom properties: 2 zotero ones and an other one:
+ SwDoc* pDoc = createSwDoc();
+ SwDocShell* pDocShell = pDoc->GetDocShell();
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(pDocShell->GetModel(),
+ uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDP = xDPS->getDocumentProperties();
+ uno::Reference<beans::XPropertyContainer> xUDP = xDP->getUserDefinedProperties();
+ xUDP->addProperty("ZOTERO_PREF_1", beans::PropertyAttribute::REMOVABLE,
+ uno::Any(OUString("foo")));
+ xUDP->addProperty("ZOTERO_PREF_2", beans::PropertyAttribute::REMOVABLE,
+ uno::Any(OUString("bar")));
+ xUDP->addProperty("OTHER", beans::PropertyAttribute::REMOVABLE, uno::Any(OUString("baz")));
+
+ // When getting the zotero properties:
+ tools::JsonWriter aJsonWriter;
+ OString aCommand(".uno:SetDocumentProperties?namePrefix=ZOTERO_PREF_");
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+ // Then make sure we find the 2 properties and ignore the other one:
+ std::unique_ptr<char[], o3tl::free_delete> pJSON(aJsonWriter.extractData());
+ std::stringstream aStream(pJSON.get());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - No such node (userDefinedProperties)
+ // i.e. the returned JSON was just empty.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2),
+ aTree.get_child("userDefinedProperties").count(""));
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetBookmarks)
+{
+ // Given a document with 3 bookmarks: 2 zotero references and a zotero bibliography:
+ createSwDoc();
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("Bookmark", uno::Any(OUString("ZOTERO_BREF_1"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertBookmark", aArgs);
+ }
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("Bookmark", uno::Any(OUString("ZOTERO_BREF_2"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertBookmark", aArgs);
+ }
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("Bookmark", uno::Any(OUString("ZOTERO_BIBL"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertBookmark", aArgs);
+ }
+
+ // When getting the reference bookmarks:
+ tools::JsonWriter aJsonWriter;
+ OString aCommand(".uno:Bookmarks?namePrefix=ZOTERO_BREF_");
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+ // Then make sure we get the 2 references but not the bibliography:
+ std::unique_ptr<char[], o3tl::free_delete> pJSON(aJsonWriter.extractData());
+ std::stringstream aStream(pJSON.get());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - No such node (bookmarks)
+ // i.e. the returned JSON was just empty.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), aTree.get_child("bookmarks").count(""));
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetFields)
+{
+ // Given a document with a refmark:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ OUString aName("ZOTERO_ITEM CSL_CITATION {} ");
+ for (int i = 0; i < 5; ++i)
+ {
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue("Name", uno::Any(aName + OUString::number(i + 1))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("mycontent"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+ pWrtShell->SttEndDoc(/*bStt=*/false);
+ pWrtShell->SplitNode();
+ pWrtShell->SttEndDoc(/*bStt=*/false);
+ }
+
+ // When getting the refmarks:
+ tools::JsonWriter aJsonWriter;
+ OString aCommand(".uno:Fields?typeName=SetRef&namePrefix=ZOTERO_ITEM%20CSL_CITATION");
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+ // Then make sure we get the 1 refmark:
+ std::unique_ptr<char[], o3tl::free_delete> pJSON(aJsonWriter.extractData());
+ std::stringstream aStream(pJSON.get());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - No such node (setRefs)
+ // i.e. the returned JSON was just empty.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(5), aTree.get_child("setRefs").count(""));
+ auto it = aTree.get_child("setRefs").begin();
+ boost::property_tree::ptree aRef = (it++)->second;
+ CPPUNIT_ASSERT_EQUAL(std::string("ZOTERO_ITEM CSL_CITATION {} 1"),
+ aRef.get<std::string>("name"));
+ aRef = (it++)->second;
+ CPPUNIT_ASSERT_EQUAL(std::string("ZOTERO_ITEM CSL_CITATION {} 2"),
+ aRef.get<std::string>("name"));
+ aRef = (it++)->second;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: ZOTERO_ITEM CSL_CITATION {} 3
+ // - Actual : ZOTERO_ITEM CSL_CITATION {} 4
+ // i.e. the output was unsorted.
+ CPPUNIT_ASSERT_EQUAL(std::string("ZOTERO_ITEM CSL_CITATION {} 3"),
+ aRef.get<std::string>("name"));
+ aRef = (it++)->second;
+ CPPUNIT_ASSERT_EQUAL(std::string("ZOTERO_ITEM CSL_CITATION {} 4"),
+ aRef.get<std::string>("name"));
+ aRef = (it++)->second;
+ CPPUNIT_ASSERT_EQUAL(std::string("ZOTERO_ITEM CSL_CITATION {} 5"),
+ aRef.get<std::string>("name"));
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetTextFormField)
+{
+ // Given a document with a fieldmark:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))),
+ comphelper::makePropertyValue("FieldCommand",
+ uno::Any(OUString("ADDIN ZOTERO_ITEM foo bar"))),
+ comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result"))),
+ };
+ dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+
+ // When stepping into the fieldmark with the cursor and getting the command value for
+ // uno:TextFormField:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ tools::JsonWriter aJsonWriter;
+ OString aCommand(".uno:TextFormField?type=vnd.oasis.opendocument.field.UNHANDLED&"
+ "commandPrefix=ADDIN%20ZOTERO_ITEM");
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+ // Then make sure we find the inserted fieldmark:
+ std::unique_ptr<char[], o3tl::free_delete> pJSON(aJsonWriter.extractData());
+ std::stringstream aStream(pJSON.get());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - No such node (type)
+ // i.e. the returned JSON was just an empty object.
+ auto field = aTree.get_child("field");
+ CPPUNIT_ASSERT_EQUAL(std::string("vnd.oasis.opendocument.field.UNHANDLED"),
+ field.get<std::string>("type"));
+ CPPUNIT_ASSERT_EQUAL(std::string("ADDIN ZOTERO_ITEM foo bar"),
+ field.get<std::string>("command"));
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetSections)
+{
+ // Given a document with a section:
+ createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue(
+ "RegionName", uno::Any(OUString("ZOTERO_BIBL {} CSL_BIBLIOGRAPHY RNDRfiit6mXBc"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("<p>aaa</p><p>bbb</p>"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertSection", aArgs);
+
+ // When asking for a list of section names:
+ tools::JsonWriter aJsonWriter;
+ OString aCommand(".uno:Sections?namePrefix=ZOTERO_BIBL");
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+ // Make sure we find our just inserted section:
+ std::unique_ptr<char[], o3tl::free_delete> pJSON(aJsonWriter.extractData());
+ std::stringstream aStream(pJSON.get());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - No such node (sections)
+ // i.e. the returned JSON was an empty object.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aTree.get_child("sections").count(""));
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetBookmark)
+{
+ // Given a document with a bookmark:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("Bookmark", uno::Any(OUString("ZOTERO_BREF_1"))),
+ comphelper::makePropertyValue("BookmarkText", uno::Any(OUString("<p>aaa</p><p>bbb</p>"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertBookmark", aArgs);
+
+ // When stepping into the bookmark with the cursor and getting the command value for
+ // .uno:Bookmark:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ tools::JsonWriter aJsonWriter;
+ OString aCommand(".uno:Bookmark?namePrefix=ZOTERO_BREF_");
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+ // Then make sure we find the inserted bookmark:
+ std::unique_ptr<char[], o3tl::free_delete> pJSON(aJsonWriter.extractData());
+ std::stringstream aStream(pJSON.get());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+ boost::property_tree::ptree aBookmark = aTree.get_child("bookmark");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - No such node (bookmark)
+ // i.e. the returned JSON was an empty object.
+ CPPUNIT_ASSERT_EQUAL(std::string("ZOTERO_BREF_1"), aBookmark.get<std::string>("name"));
+}
+
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetField)
+{
+ // Given a document with a refmark:
+ SwDoc* pDoc = createSwDoc();
+ uno::Sequence<css::beans::PropertyValue> aArgs = {
+ comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
+ comphelper::makePropertyValue("Name",
+ uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} refmark"))),
+ comphelper::makePropertyValue("Content", uno::Any(OUString("content"))),
+ };
+ dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+ // When in the refmark with the cursor and getting the command value for .uno:Field:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->SttEndDoc(/*bStt=*/false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ tools::JsonWriter aJsonWriter;
+ OString aCommand(".uno:Field?typeName=SetRef&namePrefix=ZOTERO_ITEM%20CSL_CITATION");
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+ // Then make sure we find the inserted refmark:
+ std::unique_ptr<char[], o3tl::free_delete> pJSON(aJsonWriter.extractData());
+ std::stringstream aStream(pJSON.get());
+ boost::property_tree::ptree aTree;
+ boost::property_tree::read_json(aStream, aTree);
+ boost::property_tree::ptree aBookmark = aTree.get_child("setRef");
+ // Without the accompanying fix in place, this test would have failed with:
+ // - No such node (setRef)
+ // i.e. the returned JSON was an empty object.
+ CPPUNIT_ASSERT_EQUAL(std::string("ZOTERO_ITEM CSL_CITATION {} refmark"),
+ aBookmark.get<std::string>("name"));
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/uibase/wrtsh/wrtsh.cxx b/sw/qa/uibase/wrtsh/wrtsh.cxx
index 7a659c2f0f49..43fb355fa59b 100644
--- a/sw/qa/uibase/wrtsh/wrtsh.cxx
+++ b/sw/qa/uibase/wrtsh/wrtsh.cxx
@@ -367,6 +367,56 @@ CPPUNIT_TEST_FIXTURE(Test, testInsertDateContentControl)
// handling for date content control.
CPPUNIT_ASSERT(pContentControl->GetDate());
}
+
+CPPUNIT_TEST_FIXTURE(Test, testInsertPlainTextContentControl)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting a plain text content control:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->InsertContentControl(SwContentControlType::PLAIN_TEXT);
+
+ // Then make sure that the matching text attribute is added to the document model:
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+ SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ // Without the accompanying fix in place, this test would have failed, there was no special
+ // handling for plain text content controls.
+ CPPUNIT_ASSERT(pContentControl->GetPlainText());
+
+ CPPUNIT_ASSERT(pContentControl->GetShowingPlaceHolder());
+ pWrtShell->GotoContentControl(rFormatContentControl);
+ CPPUNIT_ASSERT(pContentControl->GetShowingPlaceHolder());
+ pWrtShell->Insert("Foo");
+ // No longer showing placeholder text, as it has been changed
+ CPPUNIT_ASSERT(!pContentControl->GetShowingPlaceHolder());
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testInsertComboBoxContentControl)
+{
+ // Given an empty document:
+ SwDoc* pDoc = createSwDoc();
+
+ // When inserting a combo box content control:
+ dispatchCommand(mxComponent, ".uno:InsertComboBoxContentControl", {});
+
+ // Then make sure that the matching text attribute is added to the document model:
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+ // Without the accompanying fix in place, this test would have failed, no content control was
+ // inserted.
+ SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
+ CPPUNIT_ASSERT(pAttr);
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ CPPUNIT_ASSERT(pContentControl->GetComboBox());
+}
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/qa/uitest/ui/misc/misc.py b/sw/qa/uitest/ui/misc/misc.py
new file mode 100644
index 000000000000..2b6307cefb61
--- /dev/null
+++ b/sw/qa/uitest/ui/misc/misc.py
@@ -0,0 +1,62 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+"""Covers sw/source/ui/misc/ fixes."""
+
+from uitest.framework import UITestCase
+from uitest.uihelper.common import get_state_as_dict
+from uitest.uihelper.common import type_text
+
+
+class TestTmpdlg(UITestCase):
+ def test_content_control_dialog(self):
+ with self.ui_test.create_doc_in_start_center("writer") as xComponent:
+ # Insert a dropdown content control, verify that a placeholder item is provided.
+ self.xUITest.executeCommand(".uno:InsertDropdownContentControl")
+ paragraphs = xComponent.Text.createEnumeration()
+ paragraph = paragraphs.nextElement()
+ portions = paragraph.createEnumeration()
+ portion = portions.nextElement()
+ contentControl = portion.ContentControl
+ contentControl.Alias = "my alias"
+ contentControl.Tag = "my tag"
+ listItems = contentControl.ListItems
+ self.assertEqual(len(listItems), 1)
+ self.assertEqual(listItems[0][0].Name, "DisplayText")
+ self.assertEqual(listItems[0][0].Value, "")
+ self.assertEqual(listItems[0][1].Name, "Value")
+ self.assertEqual(listItems[0][1].Value, "Choose an item")
+
+ # Append a new list item.
+ with self.ui_test.execute_dialog_through_command(".uno:ContentControlProperties") as xDialog:
+ xAlias = xDialog.getChild("aliasentry")
+ self.assertEqual(get_state_as_dict(xAlias)['Text'], "my alias")
+ type_text(xAlias, "new alias ")
+ xTag = xDialog.getChild("tagentry")
+ self.assertEqual(get_state_as_dict(xTag)['Text'], "my tag")
+ type_text(xTag, "new tag ")
+ xAdd = xDialog.getChild("add")
+ with self.ui_test.execute_blocking_action(xAdd.executeAction, args=('CLICK', ())) as xSubDialog:
+ xDisplayName = xSubDialog.getChild("displayname")
+ type_text(xDisplayName, "Foo Bar")
+ xValue = xSubDialog.getChild("value")
+ type_text(xValue, "foo-bar")
+
+ # Verify that the UI appended the list item.
+ listItems = contentControl.ListItems
+ self.assertEqual(len(listItems), 2)
+ self.assertEqual(listItems[1][0].Name, "DisplayText")
+ self.assertEqual(listItems[1][0].Value, "Foo Bar")
+ self.assertEqual(listItems[1][1].Name, "Value")
+ self.assertEqual(listItems[1][1].Value, "foo-bar")
+ self.assertEqual(contentControl.Alias, "new alias my alias")
+ self.assertEqual(contentControl.Tag, "new tag my tag")
+
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/qa/uitest/uibase/docvw/docvw.py b/sw/qa/uitest/uibase/docvw/docvw.py
new file mode 100644
index 000000000000..e2640df96343
--- /dev/null
+++ b/sw/qa/uitest/uibase/docvw/docvw.py
@@ -0,0 +1,36 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+from uitest.framework import UITestCase
+
+
+class Test(UITestCase):
+ def testContentControlAliasButton(self):
+ with self.ui_test.create_doc_in_start_center("writer") as xComponent:
+ # Given a document with a content control that has a non-empty alias:
+ self.xUITest.executeCommand(".uno:InsertContentControl")
+ paragraphs = xComponent.Text.createEnumeration()
+ paragraph = paragraphs.nextElement()
+ portions = paragraph.createEnumeration()
+ portion = portions.nextElement()
+ contentControl = portion.ContentControl
+ contentControl.Alias = "myalias"
+
+ # When entering that content control with the cursor:
+ xCursor = xComponent.getCurrentController().getViewCursor()
+ xCursor.gotoStart(False)
+ xCursor.goRight(1, False)
+
+ # Then make sure that the alias button shows up:
+ xWindow = self.xUITest.getTopFocusWindow()
+ # Without the accompanying fix in place, this test would have failed, SwEditWin didn't
+ # have an alias button child.
+ self.assertIn("ContentControlAliasButton", xWindow.getChildren())
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/qa/unit/swmodeltestbase.cxx b/sw/qa/unit/swmodeltestbase.cxx
index fdf25ca3bc11..4926d4bcd639 100644
--- a/sw/qa/unit/swmodeltestbase.cxx
+++ b/sw/qa/unit/swmodeltestbase.cxx
@@ -26,6 +26,7 @@
#include <unotools/mediadescriptor.hxx>
#include <unotools/streamwrap.hxx>
#include <unotools/ucbstreamhelper.hxx>
+#include <vcl/filter/PDFiumLibrary.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <docsh.hxx>
@@ -766,4 +767,24 @@ SwDoc* SwModelTestBase::createSwWebDoc(std::u16string_view rDataDirectory, const
return pTextDoc->GetDocShell()->GetDoc();
}
+void SwModelTestBase::StoreToTempFile(const OUString& rFilterName)
+{
+ uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+ utl::MediaDescriptor aMediaDescriptor;
+ aMediaDescriptor["FilterName"] <<= rFilterName;
+ xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+}
+
+std::unique_ptr<vcl::pdf::PDFiumDocument> SwModelTestBase::LoadPdfFromTempFile()
+{
+ SvFileStream aFile(maTempFile.GetURL(), StreamMode::READ);
+ maMemory.WriteStream(aFile);
+ std::shared_ptr<vcl::pdf::PDFium> pPDFium = vcl::pdf::PDFiumLibrary::get();
+ if (!pPDFium)
+ {
+ return nullptr;
+ }
+ return pPDFium->openDocument(maMemory.GetData(), maMemory.GetSize(), OString());
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/sdi/_basesh.sdi b/sw/sdi/_basesh.sdi
index dd195496d1a8..a1468ffac8b1 100644
--- a/sw/sdi/_basesh.sdi
+++ b/sw/sdi/_basesh.sdi
@@ -154,6 +154,11 @@ interface BaseTextSelection
StateMethod = NoState ;
]
+ FN_UPDATE_FIELD // status(final|play)
+ [
+ ExecMethod = Execute ;
+ ]
+
FN_UPDATE_CHARTS // status(final|play)
[
ExecMethod = Execute ;
@@ -612,4 +617,11 @@ interface BaseTextSelection
StateMethod = GetState;
DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
]
+
+ SID_THEME_DIALOG
+ [
+ ExecMethod = ExecDlg;
+ StateMethod = GetState;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ]
}
diff --git a/sw/sdi/_grfsh.sdi b/sw/sdi/_grfsh.sdi
index 8291745966bb..5475017d448e 100644
--- a/sw/sdi/_grfsh.sdi
+++ b/sw/sdi/_grfsh.sdi
@@ -63,7 +63,6 @@ interface BaseTextGraphic
[
ExecMethod = Execute ;
StateMethod = GetAttrState ;
- DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
]
SID_EXTERNAL_EDIT
diff --git a/sw/sdi/_textsh.sdi b/sw/sdi/_textsh.sdi
index 84750b937715..c22a1571d022 100644
--- a/sw/sdi/_textsh.sdi
+++ b/sw/sdi/_textsh.sdi
@@ -140,6 +140,23 @@ interface BaseText
StateMethod = GetState ;
DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
]
+ FN_UPDATE_BOOKMARKS
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ]
+ FN_UPDATE_BOOKMARK
+ [
+ ExecMethod = Execute ;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ]
+ FN_UPDATE_SECTIONS
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ]
FN_SET_REMINDER
[
ExecMethod = Execute ;
@@ -302,6 +319,18 @@ interface BaseText
StateMethod = NoState ;
DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
]
+ FN_INSERT_PLAIN_TEXT_CONTENT_CONTROL // status(final|play)
+ [
+ ExecMethod = ExecInsert ;
+ StateMethod = NoState ;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ]
+ FN_INSERT_COMBO_BOX_CONTENT_CONTROL // status(final|play)
+ [
+ ExecMethod = ExecInsert ;
+ StateMethod = NoState ;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ]
FN_CONTENT_CONTROL_PROPERTIES // status(final|play)
[
ExecMethod = ExecInsert ;
@@ -906,6 +935,13 @@ interface BaseText
DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
]
+ FN_PGNUMBER_WIZARD
+ [
+ ExecMethod = ExecField ;
+ StateMethod = StateField ;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ReadOnlyDoc = FALSE ;
+ ]
FN_INSERT_FLD_PGNUMBER
[
ExecMethod = ExecField ;
@@ -1760,6 +1796,23 @@ interface BaseText
StateMethod = StateField ;
]
+ FN_UPDATE_TEXT_FORMFIELDS
+ [
+ ExecMethod = ExecField ;
+ StateMethod = StateField ;
+ ]
+
+ FN_UPDATE_TEXT_FORMFIELD
+ [
+ ExecMethod = ExecField ;
+ StateMethod = StateField ;
+ ]
+
+ FN_DELETE_TEXT_FORMFIELDS
+ [
+ ExecMethod = ExecField ;
+ ]
+
FN_PROTECT_FIELDS
[
ExecMethod = Execute ;
@@ -1772,6 +1825,24 @@ interface BaseText
StateMethod = GetState ;
]
+ FN_DELETE_BOOKMARKS
+ [
+ ExecMethod = Execute ;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ]
+
+ FN_DELETE_SECTIONS
+ [
+ ExecMethod = Execute ;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ]
+
+ FN_DELETE_FIELDS
+ [
+ ExecMethod = Execute ;
+ DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
+ ]
+
SID_FM_CTL_PROPERTIES
[
ExecMethod = Execute ;
@@ -1796,5 +1867,11 @@ interface BaseText
StateMethod = GetState ;
]
+ SID_FM_TRANSLATE
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
+
} // end of interface text
diff --git a/sw/sdi/_viewsh.sdi b/sw/sdi/_viewsh.sdi
index 7129c7cd99d4..c9a5056b7759 100644
--- a/sw/sdi/_viewsh.sdi
+++ b/sw/sdi/_viewsh.sdi
@@ -394,6 +394,11 @@ interface BaseTextEditView
ExecMethod = ExecuteStatusLine ;
StateMethod = StateStatusLine ;
]
+ FN_STAT_ACCESSIBILITY_CHECK // status()
+ [
+ ExecMethod = ExecuteStatusLine;
+ StateMethod = StateStatusLine;
+ ]
FN_STAT_BOOKMARK // status()
[
ExecMethod = ExecuteStatusLine ;
@@ -816,10 +821,17 @@ interface BaseTextEditView
StateMethod = GetState ;
DisableFlags="SfxDisableFlags::SwOnProtectedCursor";
]
+
SID_AUTOSPELL_CHECK
[
- ExecMethod = ExecViewOptions ;
- StateMethod = StateViewOptions ;
+ ExecMethod = ExecViewOptions;
+ StateMethod = StateViewOptions;
+ ]
+
+ SID_ACCESSIBILITY_CHECK_ONLINE
+ [
+ ExecMethod = ExecViewOptions;
+ StateMethod = StateViewOptions;
]
//Extra/Options/View
@@ -982,4 +994,3 @@ interface BaseTextEditView
]
}
-
diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi
index 4ef90b62f7d3..8e3db7463783 100644
--- a/sw/sdi/swriter.sdi
+++ b/sw/sdi/swriter.sdi
@@ -2537,7 +2537,7 @@ SfxVoidItem InsertAuthoritiesEntry FN_INSERT_AUTH_ENTRY_DLG
]
SfxVoidItem InsertBookmark FN_INSERT_BOOKMARK
-(SfxStringItem Bookmark FN_INSERT_BOOKMARK)
+(SfxStringItem Bookmark FN_INSERT_BOOKMARK, SfxStringItem BookmarkText FN_PARAM_1)
[
AutoUpdate = FALSE,
FastCall = FALSE,
@@ -2554,6 +2554,90 @@ SfxVoidItem InsertBookmark FN_INSERT_BOOKMARK
GroupId = SfxGroupId::Insert;
]
+SfxVoidItem UpdateBookmarks FN_UPDATE_BOOKMARKS
+(SfxStringItem BookmarkNamePrefix FN_PARAM_1, SfxUnoAnyItem Bookmarks FN_PARAM_2)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem DeleteBookmarks FN_DELETE_BOOKMARKS
+(SfxStringItem BookmarkNamePrefix FN_PARAM_1)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxVoidItem DeleteSections FN_DELETE_SECTIONS
+(SfxStringItem SectionNamePrefix FN_PARAM_1)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxVoidItem DeleteFields FN_DELETE_FIELDS
+(SfxStringItem TypeName FN_PARAM_1, SfxStringItem NamePrefix FN_PARAM_2)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxVoidItem UpdateBookmark FN_UPDATE_BOOKMARK
+(SfxStringItem BookmarkNamePrefix FN_PARAM_1, SfxUnoAnyItem Bookmark FN_PARAM_2)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem UpdateSections FN_UPDATE_SECTIONS
+(SfxStringItem SectionNamePrefix FN_PARAM_1, SfxUnoAnyItem Sections FN_PARAM_2)
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Insert;
+]
+
SfxVoidItem SetReminder FN_SET_REMINDER
[
@@ -2753,7 +2837,7 @@ SfxVoidItem PasteColumnsBefore FN_TABLE_PASTE_COL_BEFORE
]
SfxUInt16Item InsertSection FN_INSERT_REGION
-(SfxUInt16Item Columns SID_ATTR_COLUMNS,SfxStringItem RegionName FN_PARAM_REGION_NAME,SfxStringItem RegionCondition FN_PARAM_REGION_CONDITION,SfxBoolItem RegionHidden FN_PARAM_REGION_HIDDEN,SfxBoolItem RegionProtect FN_PARAM_REGION_PROTECT,SfxStringItem LinkName FN_PARAM_1,SfxStringItem FilterName FN_PARAM_2,SfxStringItem SubRegion FN_PARAM_3)
+(SfxUInt16Item Columns SID_ATTR_COLUMNS,SfxStringItem RegionName FN_PARAM_REGION_NAME,SfxStringItem RegionCondition FN_PARAM_REGION_CONDITION,SfxBoolItem RegionHidden FN_PARAM_REGION_HIDDEN,SfxBoolItem RegionProtect FN_PARAM_REGION_PROTECT,SfxStringItem LinkName FN_PARAM_1,SfxStringItem FilterName FN_PARAM_2,SfxStringItem SubRegion FN_PARAM_3, SfxStringItem Content FN_PARAM_4)
[
AutoUpdate = FALSE,
FastCall = FALSE,
@@ -2841,7 +2925,7 @@ SfxVoidItem InsertEnvelope FN_ENVELOP
]
SfxVoidItem InsertField FN_INSERT_FIELD
-(SfxUInt16Item Type FN_PARAM_FIELD_TYPE,SfxUInt16Item SubType FN_PARAM_FIELD_SUBTYPE,SfxStringItem Name FN_INSERT_FIELD,SfxStringItem Content FN_PARAM_FIELD_CONTENT,SfxUInt32Item Format FN_PARAM_FIELD_FORMAT,SfxStringItem Separator FN_PARAM_3)
+(SfxUInt16Item Type FN_PARAM_FIELD_TYPE,SfxUInt16Item SubType FN_PARAM_FIELD_SUBTYPE,SfxStringItem Name FN_INSERT_FIELD,SfxStringItem Content FN_PARAM_FIELD_CONTENT,SfxUInt32Item Format FN_PARAM_FIELD_FORMAT,SfxStringItem Separator FN_PARAM_3, SfxStringItem TypeName FN_PARAM_4, SfxStringItem Wrapper FN_PARAM_5)
[
AutoUpdate = FALSE,
FastCall = FALSE,
@@ -3117,6 +3201,40 @@ SfxVoidItem InsertDateContentControl FN_INSERT_DATE_CONTENT_CONTROL
GroupId = SfxGroupId::Insert;
]
+SfxVoidItem InsertPlainTextContentControl FN_INSERT_PLAIN_TEXT_CONTENT_CONTROL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
+SfxVoidItem InsertComboBoxContentControl FN_INSERT_COMBO_BOX_CONTENT_CONTROL
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
SfxVoidItem ContentControlProperties FN_CONTENT_CONTROL_PROPERTIES
()
[
@@ -3311,6 +3429,24 @@ SfxVoidItem InsertPageNumberField FN_INSERT_FLD_PGNUMBER
GroupId = SfxGroupId::Insert;
]
+SfxVoidItem PageNumberWizard FN_PGNUMBER_WIZARD
+()
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+ Asynchron;
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Insert;
+]
+
SfxVoidItem InsertPara FN_INSERT_BREAK
()
[
@@ -5922,6 +6058,23 @@ SfxStringItem StateWordCount FN_STAT_WORDCOUNT
GroupId = SfxGroupId::View;
]
+SfxInt32Item StateAccessibilityCheck FN_STAT_ACCESSIBILITY_CHECK
+
+[
+ AutoUpdate = FALSE,
+ FastCall = FALSE,
+ ReadOnlyDoc = TRUE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ AccelConfig = FALSE,
+ MenuConfig = FALSE,
+ ToolBoxConfig = FALSE,
+ GroupId = SfxGroupId::View;
+]
+
SfxBoolItem SubScript FN_SET_SUB_SCRIPT
[
@@ -6417,7 +6570,7 @@ SfxVoidItem UpdateCurIndex FN_UPDATE_CUR_TOX
]
SfxVoidItem UpdateFields FN_UPDATE_FIELDS
-()
+(SfxStringItem TypeName FN_PARAM_1, SfxStringItem NamePrefix FN_PARAM_2, SfxUnoAnyItem Fields FN_PARAM_3)
[
AutoUpdate = FALSE,
FastCall = TRUE,
@@ -6433,6 +6586,20 @@ SfxVoidItem UpdateFields FN_UPDATE_FIELDS
GroupId = SfxGroupId::Edit;
]
+SfxVoidItem UpdateField FN_UPDATE_FIELD
+(SfxStringItem TypeName FN_PARAM_1, SfxStringItem NamePrefix FN_PARAM_2, SfxUnoAnyItem Field FN_PARAM_3)
+[
+ AutoUpdate = FALSE,
+ FastCall = TRUE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Edit;
+]
+
SfxVoidItem UpdateInputFields FN_UPDATE_INPUTFIELDS
()
[
@@ -8169,7 +8336,25 @@ SfxBoolItem ShowInlineTooltips FN_SHOW_INLINETOOLTIPS
]
SfxVoidItem TextFormField FN_INSERT_TEXT_FORMFIELD
+(SfxStringItem FieldType FN_PARAM_1, SfxStringItem FieldCommand FN_PARAM_2, SfxStringItem FieldResult FN_PARAM_3, SfxStringItem Wrapper FN_PARAM_4)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+
+ AccelConfig = TRUE,
+ MenuConfig = TRUE,
+ ToolBoxConfig = TRUE,
+ GroupId = SfxGroupId::Controls;
+]
+SfxVoidItem TextFormFields FN_UPDATE_TEXT_FORMFIELDS
+(SfxStringItem FieldType FN_PARAM_1, SfxStringItem FieldCommandPrefix FN_PARAM_2, SfxUnoAnyItem Fields FN_PARAM_3)
[
AutoUpdate = TRUE,
FastCall = FALSE,
@@ -8186,6 +8371,34 @@ SfxVoidItem TextFormField FN_INSERT_TEXT_FORMFIELD
GroupId = SfxGroupId::Controls;
]
+SfxVoidItem DeleteTextFormFields FN_DELETE_TEXT_FORMFIELDS
+(SfxStringItem FieldType FN_PARAM_1, SfxStringItem FieldCommandPrefix FN_PARAM_2)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Controls;
+]
+
+SfxVoidItem UpdateTextFormField FN_UPDATE_TEXT_FORMFIELD
+(SfxStringItem FieldType FN_PARAM_1, SfxStringItem FieldCommandPrefix FN_PARAM_2, SfxUnoAnyItem Field FN_PARAM_3)
+[
+ AutoUpdate = TRUE,
+ FastCall = FALSE,
+ ReadOnlyDoc = FALSE,
+ Toggle = FALSE,
+ Container = FALSE,
+ RecordAbsolute = FALSE,
+ RecordPerSet;
+
+ GroupId = SfxGroupId::Controls;
+]
+
SfxVoidItem CheckBoxFormField FN_INSERT_CHECKBOX_FORMFIELD
[
diff --git a/sw/sdi/viewsh.sdi b/sw/sdi/viewsh.sdi
index cb02b883ba65..e4f3c0a362e0 100644
--- a/sw/sdi/viewsh.sdi
+++ b/sw/sdi/viewsh.sdi
@@ -464,6 +464,11 @@ interface TextPrintPreview
ExecMethod = Execute ;
StateMethod = GetState ;
]
+ FN_STAT_ACCESSIBILITY_CHECK // status()
+ [
+ ExecMethod = Execute ;
+ StateMethod = GetState ;
+ ]
SID_JUMP_TO_SPECIFIC_PAGE // status()
[
ExecMethod = Execute ;
@@ -477,4 +482,3 @@ shell SwPagePreview
{
import TextPrintPreview;
}
-
diff --git a/sw/secmod.db b/sw/secmod.db
new file mode 100644
index 000000000000..a60d58a29597
--- /dev/null
+++ b/sw/secmod.db
Binary files differ
diff --git a/sw/source/core/access/AccessibilityCheck.cxx b/sw/source/core/access/AccessibilityCheck.cxx
index 986a875327e6..ea3cf4edaaa5 100644
--- a/sw/source/core/access/AccessibilityCheck.cxx
+++ b/sw/source/core/access/AccessibilityCheck.cxx
@@ -11,24 +11,30 @@
#include <AccessibilityCheck.hxx>
#include <AccessibilityIssue.hxx>
#include <AccessibilityCheckStrings.hrc>
+#include <strings.hrc>
#include <ndnotxt.hxx>
#include <ndtxt.hxx>
#include <docsh.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <drawdoc.hxx>
#include <svx/svdpage.hxx>
+#include <sortedobjs.hxx>
#include <swtable.hxx>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/text/XTextContent.hpp>
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <unoparagraph.hxx>
+#include <unotools/intlwrapper.hxx>
#include <tools/urlobj.hxx>
#include <editeng/langitem.hxx>
+#include <calbck.hxx>
#include <charatr.hxx>
#include <svx/xfillit0.hxx>
#include <svx/xflclit.hxx>
#include <ftnidx.hxx>
#include <txtftn.hxx>
+#include <txtfrm.hxx>
#include <svl/itemiter.hxx>
#include <o3tl/vector_utils.hxx>
#include <svx/swframetypes.hxx>
@@ -41,6 +47,26 @@ namespace sw
{
namespace
{
+SwTextNode* lclSearchNextTextNode(SwNode* pCurrent)
+{
+ SwTextNode* pTextNode = nullptr;
+
+ auto nIndex = pCurrent->GetIndex();
+ auto nCount = pCurrent->GetNodes().Count();
+
+ nIndex++; // go to next node
+
+ while (pTextNode == nullptr && nIndex < nCount)
+ {
+ auto pNode = pCurrent->GetNodes()[nIndex];
+ if (pNode->IsTextNode())
+ pTextNode = pNode->GetTextNode();
+ nIndex++;
+ }
+
+ return pTextNode;
+}
+
std::shared_ptr<sw::AccessibilityIssue>
lclAddIssue(sfx::AccessibilityIssueCollection& rIssueCollection, OUString const& rText,
sfx::AccessibilityIssueID eIssue = sfx::AccessibilityIssueID::UNSPECIFIED)
@@ -51,19 +77,6 @@ lclAddIssue(sfx::AccessibilityIssueCollection& rIssueCollection, OUString const&
return pIssue;
}
-class BaseCheck
-{
-protected:
- sfx::AccessibilityIssueCollection& m_rIssueCollection;
-
-public:
- BaseCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
- : m_rIssueCollection(rIssueCollection)
- {
- }
- virtual ~BaseCheck() {}
-};
-
class NodeCheck : public BaseCheck
{
public:
@@ -210,11 +223,53 @@ public:
}
};
-class NumberingCheck : public NodeCheck
+class TableFormattingCheck : public NodeCheck
{
private:
- SwTextNode* m_pPreviousTextNode;
+ void checkTableNode(SwTableNode* pTableNode)
+ {
+ if (!pTableNode)
+ return;
+ const SwTable& rTable = pTableNode->GetTable();
+ if (!rTable.IsTableComplex())
+ {
+ size_t nEmptyBoxes = 0;
+ size_t nBoxCount = 0;
+ for (const SwTableLine* pTableLine : rTable.GetTabLines())
+ {
+ nBoxCount += pTableLine->GetTabBoxes().size();
+ for (const SwTableBox* pBox : pTableLine->GetTabBoxes())
+ if (pBox->IsEmpty())
+ ++nEmptyBoxes;
+ }
+ // If more than half of the boxes are empty we can assume that it is used for formatting
+ if (nEmptyBoxes > nBoxCount / 2)
+ lclAddIssue(m_rIssueCollection, SwResId(STR_TABLE_FORMATTING),
+ sfx::AccessibilityIssueID::TABLE_FORMATTING);
+ }
+ }
+
+public:
+ TableFormattingCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
+ : NodeCheck(rIssueCollection)
+ {
+ }
+
+ void check(SwNode* pCurrent) override
+ {
+ if (pCurrent->GetNodeType() & SwNodeType::Table)
+ {
+ SwTableNode* pTableNode = pCurrent->GetTableNode();
+ if (pTableNode)
+ checkTableNode(pTableNode);
+ }
+ }
+};
+
+class NumberingCheck : public NodeCheck
+{
+private:
const std::vector<std::pair<OUString, OUString>> m_aNumberingCombinations{
{ "1.", "2." }, { "(1)", "(2)" }, { "1)", "2)" }, { "a.", "b." }, { "(a)", "(b)" },
{ "a)", "b)" }, { "A.", "B." }, { "(A)", "(B)" }, { "A)", "B)" }
@@ -223,7 +278,6 @@ private:
public:
NumberingCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
: NodeCheck(rIssueCollection)
- , m_pPreviousTextNode(nullptr)
{
}
@@ -232,28 +286,32 @@ public:
if (!pCurrent->IsTextNode())
return;
- if (m_pPreviousTextNode)
+ SwTextNode* pCurrentTextNode = pCurrent->GetTextNode();
+ SwTextNode* pNextTextNode = lclSearchNextTextNode(pCurrent);
+
+ if (!pNextTextNode)
+ return;
+
+ for (auto& rPair : m_aNumberingCombinations)
{
- for (auto& rPair : m_aNumberingCombinations)
+ if (pCurrentTextNode->GetText().startsWith(rPair.first)
+ && pNextTextNode->GetText().startsWith(rPair.second))
{
- if (pCurrent->GetTextNode()->GetText().startsWith(rPair.second)
- && m_pPreviousTextNode->GetText().startsWith(rPair.first))
- {
- OUString sNumbering = rPair.first + " " + rPair.second + "...";
- OUString sIssueText
- = SwResId(STR_FAKE_NUMBERING).replaceAll("%NUMBERING%", sNumbering);
- lclAddIssue(m_rIssueCollection, sIssueText);
- }
+ OUString sNumbering = rPair.first + " " + rPair.second + "...";
+ OUString sIssueText
+ = SwResId(STR_FAKE_NUMBERING).replaceAll("%NUMBERING%", sNumbering);
+ lclAddIssue(m_rIssueCollection, sIssueText,
+ sfx::AccessibilityIssueID::MANUAL_NUMBERING);
}
}
- m_pPreviousTextNode = pCurrent->GetTextNode();
}
};
class HyperlinkCheck : public NodeCheck
{
private:
- void checkTextRange(uno::Reference<text::XTextRange> const& xTextRange)
+ void checkTextRange(uno::Reference<text::XTextRange> const& xTextRange, SwTextNode* pTextNode,
+ sal_Int32 nStart)
{
uno::Reference<beans::XPropertySet> xProperties(xTextRange, uno::UNO_QUERY);
if (!xProperties->getPropertySetInfo()->hasPropertyByName("HyperLinkURL"))
@@ -268,7 +326,19 @@ private:
{
OUString sIssueText
= SwResId(STR_HYPERLINK_TEXT_IS_LINK).replaceFirst("%LINK%", sHyperlink);
- lclAddIssue(m_rIssueCollection, sIssueText);
+ lclAddIssue(m_rIssueCollection, sIssueText,
+ sfx::AccessibilityIssueID::HYPERLINK_IS_TEXT);
+ }
+ else if (sText.getLength() <= 5)
+ {
+ auto pIssue = lclAddIssue(m_rIssueCollection, SwResId(STR_HYPERLINK_TEXT_IS_SHORT),
+ sfx::AccessibilityIssueID::HYPERLINK_SHORT);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pTextNode);
+ SwDoc& rDocument = pTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ pIssue->setStart(nStart);
+ pIssue->setEnd(nStart + sText.getLength());
}
}
}
@@ -292,12 +362,14 @@ public:
uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph, uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
+ sal_Int32 nStart = 0;
while (xRunEnum->hasMoreElements())
{
uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
if (xRun.is())
{
- checkTextRange(xRun);
+ checkTextRange(xRun, pTextNode, nStart);
+ nStart += xRun->getString().getLength();
}
}
}
@@ -340,8 +412,8 @@ class TextContrastCheck : public NodeCheck
{
private:
void checkTextRange(uno::Reference<text::XTextRange> const& xTextRange,
- uno::Reference<text::XTextContent> const& xParagraph,
- const SwTextNode* pTextNode)
+ uno::Reference<text::XTextContent> const& xParagraph, SwTextNode* pTextNode,
+ sal_Int32 nTextStart)
{
Color nParaBackColor(COL_AUTO);
uno::Reference<beans::XPropertySet> xParagraphProperties(xParagraph, uno::UNO_QUERY);
@@ -362,9 +434,6 @@ private:
SAL_WARN("sw.a11y", "CharColor void");
return;
}
- Color aForegroundColor(ColorTransparency, nCharColor);
- if (aForegroundColor == COL_AUTO)
- return;
const SwPageDesc* pPageDescription = pTextNode->FindPageDesc();
const SwFrameFormat& rPageFormat = pPageDescription->GetMaster();
@@ -395,6 +464,22 @@ private:
// If not character background color, try paragraph background color
if (aBackgroundColor == COL_AUTO)
aBackgroundColor = nParaBackColor;
+ else
+ {
+ auto pIssue
+ = lclAddIssue(m_rIssueCollection, SwResId(STR_TEXT_FORMATTING_CONVEYS_MEANING),
+ sfx::AccessibilityIssueID::TEXT_FORMATTING);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pTextNode);
+ SwDoc& rDocument = pTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ pIssue->setStart(nTextStart);
+ pIssue->setEnd(nTextStart + xTextRange->getString().getLength());
+ }
+
+ Color aForegroundColor(ColorTransparency, nCharColor);
+ if (aForegroundColor == COL_AUTO)
+ return;
// If not paragraph background color, try page color
if (aBackgroundColor == COL_AUTO)
@@ -430,18 +515,21 @@ public:
uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph, uno::UNO_QUERY);
uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
+ sal_Int32 nStart = 0;
while (xRunEnum->hasMoreElements())
{
uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
if (xRun.is())
- checkTextRange(xRun, xParagraph, pTextNode);
+ {
+ checkTextRange(xRun, xParagraph, pTextNode, nStart);
+ nStart += xRun->getString().getLength();
+ }
}
}
};
class TextFormattingCheck : public NodeCheck
{
-private:
public:
TextFormattingCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
: NodeCheck(rIssueCollection)
@@ -533,6 +621,7 @@ public:
pIssue->setStart(pTextAttr->GetStart());
pIssue->setEnd(pTextAttr->GetAnyEnd());
}
+
void check(SwNode* pCurrent) override
{
if (!pCurrent->IsTextNode())
@@ -551,6 +640,334 @@ public:
}
}
}
+ else if (pTextNode->HasSwAttrSet())
+ {
+ // Paragraph doesn't have hints but the entire paragraph might have char attributes
+ auto& aSwAttrSet = pTextNode->GetSwAttrSet();
+ auto nParagraphLength = pTextNode->GetText().getLength();
+ if (nParagraphLength == 0)
+ return;
+ if (aSwAttrSet.HasItem(RES_CHRATR_WEIGHT) || aSwAttrSet.HasItem(RES_CHRATR_CJK_WEIGHT)
+ || aSwAttrSet.HasItem(RES_CHRATR_CTL_WEIGHT)
+ || aSwAttrSet.HasItem(RES_CHRATR_POSTURE)
+ || aSwAttrSet.HasItem(RES_CHRATR_CJK_POSTURE)
+ || aSwAttrSet.HasItem(RES_CHRATR_CTL_POSTURE)
+ || aSwAttrSet.HasItem(RES_CHRATR_SHADOWED) || aSwAttrSet.HasItem(RES_CHRATR_COLOR)
+ || aSwAttrSet.HasItem(RES_CHRATR_EMPHASIS_MARK)
+ || aSwAttrSet.HasItem(RES_CHRATR_UNDERLINE)
+ || aSwAttrSet.HasItem(RES_CHRATR_OVERLINE)
+ || aSwAttrSet.HasItem(RES_CHRATR_CROSSEDOUT)
+ || aSwAttrSet.HasItem(RES_CHRATR_RELIEF) || aSwAttrSet.HasItem(RES_CHRATR_CONTOUR))
+ {
+ auto pIssue
+ = lclAddIssue(m_rIssueCollection, SwResId(STR_TEXT_FORMATTING_CONVEYS_MEANING),
+ sfx::AccessibilityIssueID::TEXT_FORMATTING);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pTextNode);
+ SwDoc& rDocument = pTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ pIssue->setEnd(nParagraphLength);
+ }
+ }
+ }
+};
+
+class NewlineSpacingCheck : public NodeCheck
+{
+private:
+ static SwTextNode* getNextTextNode(SwNode* pCurrent)
+ {
+ SwTextNode* pTextNode = nullptr;
+
+ auto nIndex = pCurrent->GetIndex();
+ auto nCount = pCurrent->GetNodes().Count();
+
+ nIndex++; // go to next node
+
+ while (pTextNode == nullptr && nIndex < nCount)
+ {
+ auto pNode = pCurrent->GetNodes()[nIndex];
+ if (pNode->IsTextNode())
+ pTextNode = pNode->GetTextNode();
+ nIndex++;
+ }
+
+ return pTextNode;
+ }
+
+public:
+ NewlineSpacingCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
+ : NodeCheck(rIssueCollection)
+ {
+ }
+ void check(SwNode* pCurrent) override
+ {
+ if (!pCurrent->IsTextNode())
+ return;
+
+ // Don't count empty table box text nodes
+ if (pCurrent->GetTableBox())
+ return;
+
+ SwTextNode* pTextNode = pCurrent->GetTextNode();
+ auto nParagraphLength = pTextNode->GetText().getLength();
+ if (nParagraphLength == 0)
+ {
+ SwTextNode* pNextTextNode = getNextTextNode(pCurrent);
+ if (!pNextTextNode)
+ return;
+ if (pNextTextNode->GetText().getLength() == 0)
+ {
+ auto pIssue = lclAddIssue(m_rIssueCollection, SwResId(STR_AVOID_NEWLINES_SPACE),
+ sfx::AccessibilityIssueID::TEXT_FORMATTING);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pNextTextNode);
+ SwDoc& rDocument = pNextTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ }
+ }
+ else
+ {
+ // Check for excess lines inside this paragraph
+ const OUString& sParagraphText = pTextNode->GetText();
+ int nLineCount = 0;
+ for (sal_Int32 i = 0; i < nParagraphLength; i++)
+ {
+ auto aChar = sParagraphText[i];
+ if (aChar == '\n')
+ {
+ nLineCount++;
+ // Looking for 2 newline characters and above as one can be part of the line
+ // break after a sentence
+ if (nLineCount > 2)
+ {
+ auto pIssue
+ = lclAddIssue(m_rIssueCollection, SwResId(STR_AVOID_NEWLINES_SPACE),
+ sfx::AccessibilityIssueID::TEXT_FORMATTING);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pTextNode);
+ SwDoc& rDocument = pTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ pIssue->setStart(i);
+ pIssue->setEnd(i);
+ }
+ }
+ // Don't count carriage return as normal character
+ else if (aChar != '\r')
+ {
+ nLineCount = 0;
+ }
+ }
+ }
+ }
+};
+
+class SpaceSpacingCheck : public NodeCheck
+{
+public:
+ SpaceSpacingCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
+ : NodeCheck(rIssueCollection)
+ {
+ }
+ void check(SwNode* pCurrent) override
+ {
+ if (!pCurrent->IsTextNode())
+ return;
+ SwTextNode* pTextNode = pCurrent->GetTextNode();
+ auto nParagraphLength = pTextNode->GetText().getLength();
+ const OUString& sParagraphText = pTextNode->GetText();
+ sal_Int32 nSpaceCount = 0;
+ sal_Int32 nSpaceStart = 0;
+ sal_Int32 nTabCount = 0;
+ bool bNonSpaceFound = false;
+ bool bPreviousWasChar = false;
+ for (sal_Int32 i = 0; i < nParagraphLength; i++)
+ {
+ switch (sParagraphText[i])
+ {
+ case ' ':
+ {
+ if (bNonSpaceFound)
+ {
+ nSpaceCount++;
+ if (nSpaceCount == 2)
+ nSpaceStart = i;
+ }
+ break;
+ }
+ case '\t':
+ {
+ if (bPreviousWasChar)
+ {
+ ++nTabCount;
+ bPreviousWasChar = false;
+ if (nTabCount == 2)
+ {
+ auto pIssue = lclAddIssue(m_rIssueCollection,
+ SwResId(STR_AVOID_TABS_FORMATTING),
+ sfx::AccessibilityIssueID::TEXT_FORMATTING);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pTextNode);
+ SwDoc& rDocument = pTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ pIssue->setStart(0);
+ pIssue->setEnd(nParagraphLength);
+ }
+ }
+ break;
+ }
+ default:
+ {
+ if (nSpaceCount >= 2)
+ {
+ auto pIssue
+ = lclAddIssue(m_rIssueCollection, SwResId(STR_AVOID_SPACES_SPACE),
+ sfx::AccessibilityIssueID::TEXT_FORMATTING);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pTextNode);
+ SwDoc& rDocument = pTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ pIssue->setStart(nSpaceStart);
+ pIssue->setEnd(nSpaceStart + nSpaceCount - 1);
+ }
+ bNonSpaceFound = true;
+ bPreviousWasChar = true;
+ nSpaceCount = 0;
+ break;
+ }
+ }
+ }
+ }
+};
+
+class FakeFootnoteCheck : public NodeCheck
+{
+private:
+ void checkAutoFormat(SwTextNode* pTextNode, const SwTextAttr* pTextAttr)
+ {
+ const SwFormatAutoFormat& rAutoFormat = pTextAttr->GetAutoFormat();
+ SfxItemIter aItemIter(*rAutoFormat.GetStyleHandle());
+ const SfxPoolItem* pItem = aItemIter.GetCurItem();
+ while (pItem)
+ {
+ if (pItem->Which() == RES_CHRATR_ESCAPEMENT)
+ {
+ auto pEscapementItem = static_cast<const SvxEscapementItem*>(pItem);
+ if (pEscapementItem->GetEscapement() == SvxEscapement::Superscript
+ && pTextAttr->GetStart() == 0 && pTextAttr->GetAnyEnd() == 1)
+ {
+ auto pIssue = lclAddIssue(m_rIssueCollection, SwResId(STR_AVOID_FAKE_FOOTNOTES),
+ sfx::AccessibilityIssueID::FAKE_FOOTNOTE);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pTextNode);
+ SwDoc& rDocument = pTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ pIssue->setStart(0);
+ pIssue->setEnd(pTextNode->GetText().getLength());
+ break;
+ }
+ }
+ pItem = aItemIter.NextItem();
+ }
+ }
+
+public:
+ FakeFootnoteCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
+ : NodeCheck(rIssueCollection)
+ {
+ }
+ void check(SwNode* pCurrent) override
+ {
+ if (!pCurrent->IsTextNode())
+ return;
+ SwTextNode* pTextNode = pCurrent->GetTextNode();
+ if (pTextNode->GetText().getLength() == 0)
+ return;
+
+ if (pTextNode->GetText()[0] == '*')
+ {
+ auto pIssue = lclAddIssue(m_rIssueCollection, SwResId(STR_AVOID_FAKE_FOOTNOTES),
+ sfx::AccessibilityIssueID::FAKE_FOOTNOTE);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pTextNode);
+ SwDoc& rDocument = pTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ pIssue->setStart(0);
+ pIssue->setEnd(pTextNode->GetText().getLength());
+ }
+ else if (pTextNode->HasHints())
+ {
+ SwpHints& rHints = pTextNode->GetSwpHints();
+ for (size_t i = 0; i < rHints.Count(); ++i)
+ {
+ const SwTextAttr* pTextAttr = rHints.Get(i);
+ if (pTextAttr->Which() == RES_TXTATR_AUTOFMT)
+ {
+ checkAutoFormat(pTextNode, pTextAttr);
+ }
+ }
+ }
+ }
+};
+
+class FakeCaptionCheck : public NodeCheck
+{
+public:
+ FakeCaptionCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
+ : NodeCheck(rIssueCollection)
+ {
+ }
+ void check(SwNode* pCurrent) override
+ {
+ if (!pCurrent->IsTextNode())
+ return;
+
+ SwTextNode* pTextNode = pCurrent->GetTextNode();
+ const OUString& sText = pTextNode->GetText();
+
+ if (sText.getLength() == 0)
+ return;
+
+ // Check if it's a real caption
+ const SwNode* aStartFly = pCurrent->FindFlyStartNode();
+ if (aStartFly
+ && aStartFly->GetFlyFormat()->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
+ return;
+
+ auto aIter = SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti>(*pTextNode);
+ auto nCount = 0;
+ for (auto aTextFrame = aIter.First(); aTextFrame; aTextFrame = aIter.Next())
+ {
+ auto aObjects = aTextFrame->GetDrawObjs();
+ if (aObjects)
+ nCount += aObjects->size();
+
+ if (nCount > 1)
+ return;
+ }
+
+ // Check that there's exactly 1 image anchored in this node
+ if (nCount == 1)
+ {
+ OString sTemp;
+ sText.convertToString(&sTemp, RTL_TEXTENCODING_ASCII_US, 0);
+ if (sText.startsWith(SwResId(STR_POOLCOLL_LABEL))
+ || sText.startsWith(SwResId(STR_POOLCOLL_LABEL_ABB))
+ || sText.startsWith(SwResId(STR_POOLCOLL_LABEL_TABLE))
+ || sText.startsWith(SwResId(STR_POOLCOLL_LABEL_FRAME))
+ || sText.startsWith(SwResId(STR_POOLCOLL_LABEL_DRAWING))
+ || sText.startsWith(SwResId(STR_POOLCOLL_LABEL_FIGURE)))
+ {
+ auto pIssue = lclAddIssue(m_rIssueCollection, SwResId(STR_AVOID_FAKE_CAPTIONS),
+ sfx::AccessibilityIssueID::FAKE_CAPTION);
+ pIssue->setIssueObject(IssueObject::TEXT);
+ pIssue->setNode(pTextNode);
+ SwDoc& rDocument = pTextNode->GetDoc();
+ pIssue->setDoc(rDocument);
+ pIssue->setStart(0);
+ pIssue->setEnd(sText.getLength());
+ }
+ }
}
};
@@ -869,6 +1286,46 @@ public:
}
};
+class BackgroundImageCheck : public DocumentCheck
+{
+public:
+ BackgroundImageCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
+ : DocumentCheck(rIssueCollection)
+ {
+ }
+ void check(SwDoc* pDoc) override
+ {
+ uno::Reference<lang::XComponent> xDoc = pDoc->GetDocShell()->GetBaseModel();
+ uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(xDoc, uno::UNO_QUERY);
+ if (!xStyleFamiliesSupplier.is())
+ return;
+ uno::Reference<container::XNameAccess> xStyleFamilies
+ = xStyleFamiliesSupplier->getStyleFamilies();
+ uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName("PageStyles"),
+ uno::UNO_QUERY);
+ if (!xStyleFamily.is())
+ return;
+ const uno::Sequence<OUString>& xStyleFamilyNames = xStyleFamily->getElementNames();
+ for (const OUString& rStyleFamilyName : xStyleFamilyNames)
+ {
+ uno::Reference<beans::XPropertySet> xPropertySet(
+ xStyleFamily->getByName(rStyleFamilyName), uno::UNO_QUERY);
+ if (!xPropertySet.is())
+ continue;
+ auto aFillStyleContainer = xPropertySet->getPropertyValue("FillStyle");
+ if (aFillStyleContainer.has<drawing::FillStyle>())
+ {
+ drawing::FillStyle aFillStyle = aFillStyleContainer.get<drawing::FillStyle>();
+ if (aFillStyle == drawing::FillStyle_BITMAP)
+ {
+ lclAddIssue(m_rIssueCollection, SwResId(STR_AVOID_BACKGROUND_IMAGES),
+ sfx::AccessibilityIssueID::DOCUMENT_BACKGROUND);
+ }
+ }
+ }
+ }
+};
+
} // end anonymous namespace
// Check Shapes, TextBox
@@ -906,34 +1363,76 @@ void AccessibilityCheck::checkObject(SdrObject* pObject)
}
}
-void AccessibilityCheck::check()
+void AccessibilityCheck::init()
+{
+ if (m_aDocumentChecks.empty())
+ {
+ m_aDocumentChecks.emplace_back(new DocumentDefaultLanguageCheck(m_aIssueCollection));
+ m_aDocumentChecks.emplace_back(new DocumentTitleCheck(m_aIssueCollection));
+ m_aDocumentChecks.emplace_back(new FootnoteEndnoteCheck(m_aIssueCollection));
+ m_aDocumentChecks.emplace_back(new BackgroundImageCheck(m_aIssueCollection));
+ }
+
+ if (m_aNodeChecks.empty())
+ {
+ m_aNodeChecks.emplace_back(new NoTextNodeAltTextCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new TableNodeMergeSplitCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new TableFormattingCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new NumberingCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new HyperlinkCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new TextContrastCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new BlinkingTextCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new HeaderCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new TextFormattingCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new NonInteractiveFormCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new FloatingTextCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new TableHeadingCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new HeadingOrderCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new NewlineSpacingCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new SpaceSpacingCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new FakeFootnoteCheck(m_aIssueCollection));
+ m_aNodeChecks.emplace_back(new FakeCaptionCheck(m_aIssueCollection));
+ }
+}
+
+void AccessibilityCheck::checkNode(SwNode* pNode)
+{
+ if (m_pDoc == nullptr || pNode == nullptr)
+ return;
+
+ init();
+
+ for (std::shared_ptr<BaseCheck>& rpNodeCheck : m_aNodeChecks)
+ {
+ auto pNodeCheck = dynamic_cast<NodeCheck*>(rpNodeCheck.get());
+ if (pNodeCheck)
+ pNodeCheck->check(pNode);
+ }
+}
+
+void AccessibilityCheck::checkDocumentProperties()
{
if (m_pDoc == nullptr)
return;
- std::vector<std::unique_ptr<DocumentCheck>> aDocumentChecks;
- aDocumentChecks.push_back(std::make_unique<DocumentDefaultLanguageCheck>(m_aIssueCollection));
- aDocumentChecks.push_back(std::make_unique<DocumentTitleCheck>(m_aIssueCollection));
- aDocumentChecks.push_back(std::make_unique<FootnoteEndnoteCheck>(m_aIssueCollection));
+ init();
- for (std::unique_ptr<DocumentCheck>& rpDocumentCheck : aDocumentChecks)
+ for (std::shared_ptr<BaseCheck>& rpDocumentCheck : m_aDocumentChecks)
{
- rpDocumentCheck->check(m_pDoc);
+ auto pDocumentCheck = dynamic_cast<DocumentCheck*>(rpDocumentCheck.get());
+ if (pDocumentCheck)
+ pDocumentCheck->check(m_pDoc);
}
+}
+
+void AccessibilityCheck::check()
+{
+ if (m_pDoc == nullptr)
+ return;
+
+ init();
- std::vector<std::unique_ptr<NodeCheck>> aNodeChecks;
- aNodeChecks.push_back(std::make_unique<NoTextNodeAltTextCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<TableNodeMergeSplitCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<NumberingCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<HyperlinkCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<TextContrastCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<BlinkingTextCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<HeaderCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<TextFormattingCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<NonInteractiveFormCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<FloatingTextCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<TableHeadingCheck>(m_aIssueCollection));
- aNodeChecks.push_back(std::make_unique<HeadingOrderCheck>(m_aIssueCollection));
+ checkDocumentProperties();
auto const& pNodes = m_pDoc->GetNodes();
SwNode* pNode = nullptr;
@@ -942,9 +1441,11 @@ void AccessibilityCheck::check()
pNode = pNodes[n];
if (pNode)
{
- for (std::unique_ptr<NodeCheck>& rpNodeCheck : aNodeChecks)
+ for (std::shared_ptr<BaseCheck>& rpNodeCheck : m_aNodeChecks)
{
- rpNodeCheck->check(pNode);
+ auto pNodeCheck = dynamic_cast<NodeCheck*>(rpNodeCheck.get());
+ if (pNodeCheck)
+ pNodeCheck->check(pNode);
}
}
}
diff --git a/sw/source/core/crsr/bookmark.cxx b/sw/source/core/crsr/bookmark.cxx
index 417558aad130..1cd5752e2bf1 100644
--- a/sw/source/core/crsr/bookmark.cxx
+++ b/sw/source/core/crsr/bookmark.cxx
@@ -33,6 +33,7 @@
#include <xmloff/odffields.hxx>
#include <libxml/xmlwriter.h>
#include <comphelper/random.hxx>
+#include <comphelper/sequence.hxx>
#include <comphelper/anytostring.hxx>
#include <sal/log.hxx>
#include <svl/numformat.hxx>
@@ -46,6 +47,7 @@
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <rtl/strbuf.hxx>
#include <strings.hrc>
+#include <tools/json_writer.hxx>
using namespace ::sw::mark;
using namespace ::com::sun::star;
@@ -413,6 +415,27 @@ namespace sw::mark
m_aName = rName;
}
+ Bookmark::~Bookmark()
+ {
+ if (!comphelper::LibreOfficeKit::isActive() || GetMarkPos().GetDoc().IsClipBoard())
+ return;
+
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (!pViewShell)
+ return;
+
+ OUString fieldCommand = GetName();
+ tools::JsonWriter aJson;
+ aJson.put("commandName", ".uno:DeleteBookmark");
+ aJson.put("success", true);
+ {
+ auto result = aJson.startNode("result");
+ aJson.put("DeleteBookmark", fieldCommand);
+ }
+
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.extractData());
+ }
+
void Bookmark::InitDoc(SwDoc& io_rDoc,
sw::mark::InsertMode const, SwPosition const*const)
{
@@ -558,14 +581,38 @@ namespace sw::mark
TextFieldmark::TextFieldmark(const SwPaM& rPaM, const OUString& rName)
: Fieldmark(rPaM)
+ , m_pDocumentContentOperationsManager(nullptr)
{
if ( !rName.isEmpty() )
m_aName = rName;
}
+ TextFieldmark::~TextFieldmark()
+ {
+ if (!comphelper::LibreOfficeKit::isActive() || GetMarkPos().GetDoc().IsClipBoard())
+ return;
+
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (!pViewShell)
+ return;
+
+ OUString fieldCommand;
+ (*GetParameters())[OUString(ODF_CODE_PARAM)] >>= fieldCommand;
+ tools::JsonWriter aJson;
+ aJson.put("commandName", ".uno:DeleteTextFormField");
+ aJson.put("success", true);
+ {
+ auto result = aJson.startNode("result");
+ aJson.put("DeleteTextFormField", fieldCommand);
+ }
+
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.extractData());
+ }
+
void TextFieldmark::InitDoc(SwDoc& io_rDoc,
sw::mark::InsertMode const eMode, SwPosition const*const pSepPos)
{
+ m_pDocumentContentOperationsManager = &io_rDoc.GetDocumentContentOperationsManager();
if (eMode == sw::mark::InsertMode::New)
{
lcl_SetFieldMarks(*this, io_rDoc, CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND, pSepPos);
@@ -590,6 +637,45 @@ namespace sw::mark
sw::UpdateFramesForRemoveDeleteRedline(rDoc, tmp);
}
+ OUString TextFieldmark::GetContent() const
+ {
+ const SwTextNode& rTextNode = *GetMarkEnd().nNode.GetNode().GetTextNode();
+ SwPosition const sepPos(sw::mark::FindFieldSep(*this));
+ const sal_Int32 nStart(sepPos.nContent.GetIndex());
+ const sal_Int32 nEnd(GetMarkEnd().nContent.GetIndex());
+
+ OUString sContent;
+ const sal_Int32 nLen = rTextNode.GetText().getLength();
+ if (nStart + 1 < nLen && nEnd <= nLen && nEnd > nStart + 2)
+ sContent = rTextNode.GetText().copy(nStart + 1, nEnd - nStart - 2);
+
+ return sContent;
+ }
+
+ void TextFieldmark::ReplaceContent(const OUString& sNewContent)
+ {
+ if (!m_pDocumentContentOperationsManager)
+ return;
+
+ SwPosition const sepPos(sw::mark::FindFieldSep(*this));
+ const sal_Int32 nStart(sepPos.nContent.GetIndex());
+ const sal_Int32 nEnd(GetMarkEnd().nContent.GetIndex());
+
+ const sal_Int32 nLen = GetMarkEnd().nNode.GetNode().GetTextNode()->GetText().getLength();
+ if (nStart + 1 < nLen && nEnd <= nLen && nEnd > nStart + 2)
+ {
+ SwPaM aFieldPam(GetMarkStart().nNode.GetNode(), nStart + 1,
+ GetMarkStart().nNode.GetNode(), nEnd - 1);
+ m_pDocumentContentOperationsManager->ReplaceRange(aFieldPam, sNewContent, false);
+ }
+ else
+ {
+ SwPaM aFieldStartPam(GetMarkStart().nNode.GetNode(), nStart + 1);
+ m_pDocumentContentOperationsManager->InsertString(aFieldStartPam, sNewContent);
+ }
+ Invalidate();
+ }
+
NonTextFieldmark::NonTextFieldmark(const SwPaM& rPaM)
: Fieldmark(rPaM)
{ }
@@ -621,9 +707,12 @@ namespace sw::mark
}
- CheckboxFieldmark::CheckboxFieldmark(const SwPaM& rPaM)
+ CheckboxFieldmark::CheckboxFieldmark(const SwPaM& rPaM, const OUString& rName)
: NonTextFieldmark(rPaM)
- { }
+ {
+ if (!rName.isEmpty())
+ m_aName = rName;
+ }
void CheckboxFieldmark::SetChecked(bool checked)
{
@@ -645,6 +734,17 @@ namespace sw::mark
return bResult;
}
+ OUString CheckboxFieldmark::GetContent() const
+ {
+ return IsChecked() ? "1" : "0";
+ }
+
+ void CheckboxFieldmark::ReplaceContent(const OUString& sNewContent)
+ {
+ SetChecked(sNewContent.toBoolean());
+ Invalidate();
+ }
+
FieldmarkWithDropDownButton::FieldmarkWithDropDownButton(const SwPaM& rPaM)
: NonTextFieldmark(rPaM)
, m_pButton(nullptr)
@@ -662,9 +762,20 @@ namespace sw::mark
m_pButton.disposeAndClear();
}
- DropDownFieldmark::DropDownFieldmark(const SwPaM& rPaM)
+ void FieldmarkWithDropDownButton::LaunchPopup()
+ {
+ if (!m_pButton)
+ return
+
+ m_pButton->Invalidate();
+ m_pButton->LaunchPopup();
+ }
+
+ DropDownFieldmark::DropDownFieldmark(const SwPaM& rPaM, const OUString& rName)
: FieldmarkWithDropDownButton(rPaM)
{
+ if (!rName.isEmpty())
+ m_aName = rName;
}
DropDownFieldmark::~DropDownFieldmark()
@@ -687,6 +798,182 @@ namespace sw::mark
FieldmarkWithDropDownButton::RemoveButton();
}
+ /** GetContent
+ * @param pIndex The zero-based index to retrieve
+ * [in] if pIndex is null or negative, return the listbox's chosen result,
+ * else return the indicated entry (or last entry for invalid choice).
+ * [out] the index of the returned result or -1 if error
+ */
+ OUString DropDownFieldmark::GetContent(sal_Int32* pIndex) const
+ {
+ sal_Int32 nIndex = pIndex ? *pIndex : -1;
+ auto rParameters = *GetParameters();
+ if (nIndex < 0)
+ rParameters[ODF_FORMDROPDOWN_RESULT] >>= nIndex;
+
+ uno::Sequence<OUString> aSeq;
+ rParameters[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq;
+ nIndex = std::min(nIndex, aSeq.getLength() - 1);
+
+ if (nIndex < 0)
+ {
+ if (pIndex)
+ *pIndex = -1;
+ return OUString();
+ }
+
+ if (pIndex)
+ *pIndex = nIndex;
+
+ return aSeq[nIndex];
+ }
+
+ OUString DropDownFieldmark::GetContent() const
+ {
+ return GetContent(nullptr);
+ }
+
+ /** AddContent : INSERTS a new choice
+ * @param rText: The choice to add to the list choices.
+ *
+ * @param pIndex [optional]
+ * [in] If pIndex is null or invalid, append to the end of the list.
+ * [out] Modified to point to the position of the choice if it already exists.
+ */
+ void DropDownFieldmark::AddContent(const OUString& rText, sal_Int32* pIndex)
+ {
+ uno::Sequence<OUString> aSeq;
+ sw::mark::IFieldmark::parameter_map_t* pParameters = GetParameters();
+ (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq;
+
+ // no duplicates: if it already exists, modify the given index to point to it
+ const sal_Int32 nCurrentTextPos = comphelper::findValue(aSeq, rText);
+ if (nCurrentTextPos != -1)
+ {
+ if (pIndex)
+ *pIndex = nCurrentTextPos;
+ return;
+ }
+
+ const sal_Int32 nLen = aSeq.getLength();
+ const sal_Int32 nNewPos = pIndex && *pIndex > -1 ? std::min(*pIndex, nLen) : nLen;
+
+ // need to shift list result index up if adding new entry before it
+ sal_Int32 nResultIndex = -1;
+ (*pParameters)[ODF_FORMDROPDOWN_RESULT] >>= nResultIndex;
+ if (nNewPos <= nResultIndex)
+ (*pParameters)[ODF_FORMDROPDOWN_RESULT] <<= nResultIndex + 1;
+
+ auto aList = comphelper::sequenceToContainer<std::vector<OUString>>(aSeq);
+ if (nNewPos < nLen)
+ aList.insert(aList.begin() + nNewPos, rText);
+ else
+ {
+ *pIndex = nLen;
+ aList.push_back(rText);
+ }
+
+ (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] <<= comphelper::containerToSequence(aList);
+ Invalidate();
+ }
+
+ /**
+ * ReplaceContent : changes the list result index or renames the existing choices
+ * @param pText
+ * [in] If pIndex is null, change the list result index to this provided choice
+ * (but do nothing if pText is an invalid choice)
+ * else rename that entry.
+ *
+ * @param pIndex
+ * [in] If pText is null, change the list result index to this provided Index
+ * (or the last position if it is an invalid choice)
+ * else rename this entry (doing nothing for invalid indexes).
+ * [out] If pIndex is invalid, it is modified to use the last position.
+ *
+ * This function allows duplicate entries - which is also allowed in MS Word.
+ */
+ void DropDownFieldmark::ReplaceContent(const OUString* pText, sal_Int32* pIndex)
+ {
+ if (!pIndex && !pText)
+ return;
+
+ uno::Sequence<OUString> aSeq;
+ sw::mark::IFieldmark::parameter_map_t* pParameters = GetParameters();
+ (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq;
+ const sal_Int32 nLen = aSeq.getLength();
+
+ if (!pText)
+ {
+ if (*pIndex < 0 || *pIndex >= nLen)
+ *pIndex = nLen - 1;
+
+ // select pIndex as the new value for the list box
+ (*pParameters)[ODF_FORMDROPDOWN_RESULT] <<= *pIndex;
+ Invalidate();
+ return;
+ }
+
+ if (!pIndex)
+ {
+ const sal_Int32 nNewPos = comphelper::findValue(aSeq, *pText);
+ if (nNewPos != -1)
+ {
+ (*pParameters)[ODF_FORMDROPDOWN_RESULT] <<= nNewPos;
+ Invalidate();
+ }
+ return;
+ }
+
+ if (*pIndex > -1 && *pIndex < nLen)
+ {
+ auto aList = comphelper::sequenceToContainer<std::vector<OUString>>(aSeq);
+ aList[*pIndex] = *pText;
+ (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] <<= comphelper::containerToSequence(aList);
+ Invalidate();
+ }
+ }
+
+ void DropDownFieldmark::ReplaceContent(const OUString& rNewContent)
+ {
+ ReplaceContent(&rNewContent, nullptr);
+ }
+
+ /**
+ * Remove everything if the given index is negative, else remove the given index (if valid).
+ * If deleting the currently selected choice, reset the selection to the first choice.
+ */
+ void DropDownFieldmark::DelContent(sal_Int32 nDelIndex)
+ {
+ sw::mark::IFieldmark::parameter_map_t* pParameters = GetParameters();
+ uno::Sequence<OUString> aSeq;
+ if (nDelIndex < 0)
+ {
+ pParameters->erase(ODF_FORMDROPDOWN_RESULT);
+ (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] <<= aSeq;
+ Invalidate();
+ return;
+ }
+
+ (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq;
+ if (nDelIndex >= aSeq.getLength())
+ return;
+
+ // If deleting the current choice, select the first entry instead
+ // else need to shift list result index down if deleting an entry before it
+ sal_Int32 nResultIndex = -1;
+ (*pParameters)[ODF_FORMDROPDOWN_RESULT] >>= nResultIndex;
+ if (nDelIndex == nResultIndex)
+ nResultIndex = 0;
+ else if (nDelIndex < nResultIndex)
+ --nResultIndex;
+
+ comphelper::removeElementAt(aSeq, nDelIndex);
+ if (nResultIndex != -1)
+ (*pParameters)[ODF_FORMDROPDOWN_RESULT] <<= nResultIndex;
+ (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] <<= aSeq;
+ Invalidate();
+ }
+
void DropDownFieldmark::SetPortionPaintArea(const SwRect& rPortionPaintArea)
{
m_aPortionPaintArea = rPortionPaintArea;
diff --git a/sw/source/core/crsr/callnk.cxx b/sw/source/core/crsr/callnk.cxx
index 50a1fc99eec9..c4f2ccdff10e 100644
--- a/sw/source/core/crsr/callnk.cxx
+++ b/sw/source/core/crsr/callnk.cxx
@@ -31,6 +31,7 @@
#include <ndtxt.hxx>
#include <flyfrm.hxx>
#include <breakit.hxx>
+#include <UndoTable.hxx>
SwCallLink::SwCallLink( SwCursorShell & rSh )
: m_rShell( rSh )
@@ -60,24 +61,36 @@ SwCallLink::SwCallLink( SwCursorShell & rSh )
}
}
-static void lcl_notifyRow(const SwContentNode* pNode, SwCursorShell & rShell)
+namespace sw {
+
+/**
+ An empty paragraph inside a table with a nested table preceding it
+ should be hidden, unless the cursor is positioned in the paragraph.
+
+ If the cursor is now (or was previously) inside such a paragraph,
+ send a size change notification on the row frame to force reformatting.
+ */
+void NotifyTableCollapsedParagraph(const SwContentNode *const pNode, SwCursorShell *const pShell)
{
if ( !pNode )
return;
- SwFrame *const pMyFrame = pNode->getLayoutFrame( rShell.GetLayout() );
+ SwFrame *const pMyFrame = pNode->getLayoutFrame(pShell ? pShell->GetLayout() : nullptr);
if ( !pMyFrame )
return;
- // We need to emulated a change of the row height in order
- // to have the complete row redrawn
+ // important: only invalidate layout if something is actually hidden or
+ // shown! Otherwise performance is going to suffer with "difficult" tables.
+ if (!pMyFrame->IsCollapse())
+ return;
+
SwRowFrame *const pRow = pMyFrame->FindRowFrame();
if ( !pRow )
return;
const SwTableLine* pLine = pRow->GetTabLine( );
- if (rShell.IsTableMode() || (rShell.StartsWithTable() && rShell.ExtendedSelectedAll()))
+ if (pShell && (pShell->IsTableMode() || (pShell->StartsWithTable() && pShell->ExtendedSelectedAll())))
{
// If we have a table selection, then avoid the notification: it's not necessary (the text
// cursor needs no updating) and the notification may kill the selection overlay, leading to
@@ -86,10 +99,13 @@ static void lcl_notifyRow(const SwContentNode* pNode, SwCursorShell & rShell)
return;
}
+ // notify a change in frame size to force reformatting of the row
const SwFormatFrameSize aSize = pLine->GetFrameFormat()->GetFrameSize();
pRow->OnFrameSize(aSize);
}
+} // namespace sw
+
SwCallLink::~SwCallLink() COVERITY_NOEXCEPT_FALSE
{
if( m_nNodeType == SwNodeType::NONE || !m_rShell.m_bCallChgLnk ) // see ctor
@@ -102,15 +118,17 @@ SwCallLink::~SwCallLink() COVERITY_NOEXCEPT_FALSE
if( !pCNd )
return;
- lcl_notifyRow(pCNd, m_rShell);
-
- const SwDoc *pDoc=m_rShell.GetDoc();
- const SwContentNode *pNode = nullptr;
- if ( pDoc && sal_Int32(m_nNode) < sal_Int32(pDoc->GetNodes( ).Count( )) )
+ if (pCNd->GetIndex() != m_nNode) // only if moved to different node
{
- pNode = pDoc->GetNodes()[m_nNode]->GetContentNode();
+ ::sw::NotifyTableCollapsedParagraph(pCNd, &m_rShell);
+
+ const SwDoc *pDoc=m_rShell.GetDoc();
+ if (sal_Int32(m_nNode) < sal_Int32(pDoc->GetNodes().Count()))
+ {
+ const SwContentNode *const pNode = pDoc->GetNodes()[m_nNode]->GetContentNode();
+ ::sw::NotifyTableCollapsedParagraph(pNode, &m_rShell);
+ }
}
- lcl_notifyRow(pNode, m_rShell);
sal_Int32 nCmp, nCurrentContent = pCurrentCursor->GetPoint()->nContent.GetIndex();
SwNodeType nNdWhich = pCNd->GetNodeType();
diff --git a/sw/source/core/crsr/contentcontrolbutton.cxx b/sw/source/core/crsr/contentcontrolbutton.cxx
index 00deb260981c..108a6fe7eade 100644
--- a/sw/source/core/crsr/contentcontrolbutton.cxx
+++ b/sw/source/core/crsr/contentcontrolbutton.cxx
@@ -11,8 +11,10 @@
#include <vcl/weldutils.hxx>
#include <vcl/event.hxx>
+#include <vcl/decoview.hxx>
#include <edtwin.hxx>
+#include <dview.hxx>
SwContentControlButton::SwContentControlButton(
SwEditWin* pEditWin, const std::shared_ptr<SwContentControl>& pContentControl)
@@ -77,7 +79,9 @@ void SwContentControlButton::CalcPosAndSize(const SwRect& rPortionPaintArea)
}
}
-void SwContentControlButton::MouseButtonDown(const MouseEvent&)
+void SwContentControlButton::MouseButtonDown(const MouseEvent&) { StartPopup(); }
+
+void SwContentControlButton::StartPopup()
{
LaunchPopup();
Invalidate();
@@ -107,7 +111,7 @@ void SwContentControlButton::Paint(vcl::RenderContext& rRenderContext, const too
// Draw the button next to the frame
Point aButtonPos(aFrameRect.TopLeft());
- aButtonPos.AdjustX(aFrameRect.GetSize().getWidth() - 1);
+ aButtonPos.AdjustX(aFrameRect.GetSize().getWidth() - nPadding * 2);
Size aButtonSize(aFrameRect.GetSize());
aButtonSize.setWidth(GetSizePixel().getWidth() - aFrameRect.getWidth() - nPadding);
const tools::Rectangle aButtonRect(tools::Rectangle(aButtonPos, aButtonSize));
@@ -118,21 +122,26 @@ void SwContentControlButton::Paint(vcl::RenderContext& rRenderContext, const too
rRenderContext.DrawRect(aButtonRect);
// the arrowhead
- rRenderContext.SetLineColor(aLineColor);
- rRenderContext.SetFillColor(aLineColor);
-
- Point aCenter(aButtonPos.X() + (aButtonSize.Width() / 2),
- aButtonPos.Y() + (aButtonSize.Height() / 2));
- tools::Long nMinWidth = 4;
- tools::Long nMinHeight = 2;
- Size aArrowSize(std::max(aButtonSize.Width() / 4, nMinWidth),
- std::max(aButtonSize.Height() / 10, nMinHeight));
-
- tools::Polygon aPoly(3);
- aPoly.SetPoint(Point(aCenter.X() - aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 0);
- aPoly.SetPoint(Point(aCenter.X() + aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 1);
- aPoly.SetPoint(Point(aCenter.X(), aCenter.Y() + aArrowSize.Height()), 2);
- rRenderContext.DrawPolygon(aPoly);
+ DecorationView aDecoView(&rRenderContext);
+ tools::Rectangle aSymbolRect(aButtonRect);
+ // 20% distance to the left and right button border
+ const tools::Long nBorderDistanceLeftAndRight = aSymbolRect.GetWidth() / 4;
+ aSymbolRect.AdjustLeft(nBorderDistanceLeftAndRight);
+ aSymbolRect.AdjustRight(-nBorderDistanceLeftAndRight);
+ // 20% distance to the top and bottom button border
+ const tools::Long nBorderDistanceTopAndBottom = aSymbolRect.GetHeight() / 4;
+ aSymbolRect.AdjustTop(nBorderDistanceTopAndBottom);
+ aSymbolRect.AdjustBottom(-nBorderDistanceTopAndBottom);
+ AntialiasingFlags eAntialiasing = rRenderContext.GetAntialiasing();
+ if (SwDrawView::IsAntiAliasing())
+ {
+ rRenderContext.SetAntialiasing(eAntialiasing | AntialiasingFlags::Enable);
+ }
+ aDecoView.DrawSymbol(aSymbolRect, SymbolType::SPIN_DOWN, GetTextColor(), DrawSymbolFlags::NONE);
+ if (SwDrawView::IsAntiAliasing())
+ {
+ rRenderContext.SetAntialiasing(eAntialiasing);
+ }
}
WindowHitTest SwContentControlButton::ImplHitTest(const Point& rFramePos)
diff --git a/sw/source/core/crsr/crbm.cxx b/sw/source/core/crsr/crbm.cxx
index 02f554014568..d171b1d52be1 100644
--- a/sw/source/core/crsr/crbm.cxx
+++ b/sw/source/core/crsr/crbm.cxx
@@ -286,20 +286,20 @@ bool SwCursorShell::IsFormProtected()
::sw::mark::IFieldmark* SwCursorShell::GetCurrentFieldmark()
{
// TODO: Refactor
- SwPosition pos(*GetCursor()->GetPoint());
+ SwPosition pos(*GetCursor()->Start());
return getIDocumentMarkAccess()->getFieldmarkFor(pos);
}
-::sw::mark::IFieldmark* SwCursorShell::GetFieldmarkAfter()
+sw::mark::IFieldmark* SwCursorShell::GetFieldmarkAfter(bool bLoop)
{
SwPosition pos(*GetCursor()->GetPoint());
- return getIDocumentMarkAccess()->getFieldmarkAfter(pos);
+ return getIDocumentMarkAccess()->getFieldmarkAfter(pos, bLoop);
}
-::sw::mark::IFieldmark* SwCursorShell::GetFieldmarkBefore()
+sw::mark::IFieldmark* SwCursorShell::GetFieldmarkBefore(bool bLoop)
{
SwPosition pos(*GetCursor()->GetPoint());
- return getIDocumentMarkAccess()->getFieldmarkBefore(pos);
+ return getIDocumentMarkAccess()->getFieldmarkBefore(pos, bLoop);
}
bool SwCursorShell::GotoFieldmark(::sw::mark::IFieldmark const * const pMark)
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index 4e9f54aab2e8..936a343b4886 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -54,7 +54,8 @@
#include <unotextrange.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
-#include <IGrammarContact.hxx>
+#include <GrammarContact.hxx>
+#include <OnlineAccessibilityCheck.hxx>
#include <comphelper/flagguard.hxx>
#include <strings.hrc>
#include <IDocumentLayoutAccess.hxx>
@@ -1502,9 +1503,13 @@ void SwCursorShell::UpdateCursorPos()
&aTmpState );
pShellCursor->DeleteMark();
}
- IGrammarContact *pGrammarContact = GetDoc() ? GetDoc()->getGrammarContact() : nullptr;
- if( pGrammarContact )
- pGrammarContact->updateCursorPosition( *m_pCurrentCursor->GetPoint() );
+ auto* pDoc = GetDoc();
+ if (pDoc)
+ {
+ pDoc->getGrammarContact()->updateCursorPosition(*m_pCurrentCursor->GetPoint());
+ pDoc->getOnlineAccessibilityCheck()->update(*m_pCurrentCursor->GetPoint());
+ }
+
--mnStartAction;
if( aOldSz != GetDocSize() )
SizeChgNotify();
@@ -2260,7 +2265,14 @@ void SwCursorShell::Push()
*/
bool SwCursorShell::Pop(PopMode const eDelete)
{
- SwCallLink aLk( *this ); // watch Cursor-Moves; call Link if needed
+ ::std::unique_ptr<SwCallLink> pLink(::std::make_unique<SwCallLink>(*this)); // watch Cursor-Moves; call Link if needed
+ return Pop(eDelete, ::std::move(pLink));
+}
+
+bool SwCursorShell::Pop(PopMode const eDelete,
+ [[maybe_unused]] ::std::unique_ptr<SwCallLink> const pLink)
+{
+ assert(pLink); // parameter exists only to be deleted before return
// are there any left?
if (nullptr == m_pStackCursor)
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index 73d12ce79c3a..74fe9b15ad57 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -883,9 +883,6 @@ bool SwCursorShell::GotoFormatContentControl(const SwFormatContentControl& rCont
sal_Int32 nEnd = *pTextContentControl->End() - 1;
pCursor->GetMark()->nContent.Assign(pTextNode, nEnd);
- // Assume that once the placeholder is selected, the content is no longer the placeholder.
- pContentControl->SetShowingPlaceHolder(false);
-
bRet = !pCursor->IsSelOvr();
if (bRet)
{
@@ -897,6 +894,132 @@ bool SwCursorShell::GotoFormatContentControl(const SwFormatContentControl& rCont
return bRet;
}
+/**
+ * Go to the next (or previous) form control, based first on tabIndex and then paragraph position,
+ * where a tabIndex of 1 is first, 0 is last, and -1 is excluded.
+ */
+void SwCursorShell::GotoFormControl(bool bNext)
+{
+ // (note: this only applies to modern content controls and legacy fieldmarks,
+ // since activeX richText controls aren't exposed to SW keystrokes)
+
+ struct FormControlSort
+ {
+ bool operator()(std::pair<const SwPosition&, sal_uInt32> rLHS,
+ std::pair<const SwPosition&, sal_uInt32> rRHS) const
+ {
+ assert(rLHS.second && rRHS.second && "tabIndex zero must be changed to SAL_MAX_UINT32");
+ //first compare tabIndexes where 1 has the priority.
+ if (rLHS.second < rRHS.second)
+ return true;
+ if (rLHS.second > rRHS.second)
+ return false;
+
+ // when tabIndexes are equal (and they usually are) then sort by paragraph position
+ return rLHS.first < rRHS.first;
+ }
+ };
+ std::map<std::pair<SwPosition, sal_uInt32>,
+ std::pair<SwTextContentControl*, sw::mark::IFieldmark*>, FormControlSort> aFormMap;
+
+ // add all of the eligible modern Content Controls into a sorted map
+ SwContentControlManager& rManager = GetDoc()->GetContentControlManager();
+ for (size_t i = 0; i < rManager.GetCount(); ++i)
+ {
+ SwTextContentControl* pTCC = rManager.UnsortedGet(i);
+ if (!pTCC || !pTCC->GetTextNode())
+ continue;
+ auto pCC = pTCC->GetContentControl().GetContentControl();
+
+ // -1 indicates the control should not participate in keyboard tab navigation
+ if (pCC && pCC->GetTabIndex() == SAL_MAX_UINT32)
+ continue;
+
+ const SwPosition nPos(*pTCC->GetTextNode(), pTCC->GetStart());
+
+ // since 0 is the lowest priority (1 is the highest), and -1 has already been excluded,
+ // use SAL_MAX_UINT32 as zero's tabIndex so that automatic sorting is correct.
+ sal_uInt32 nTabIndex = pCC && pCC->GetTabIndex() ? pCC->GetTabIndex() : SAL_MAX_UINT32;
+
+ const std::pair<SwTextContentControl*, sw::mark::IFieldmark*> pFormControl(pTCC, nullptr);
+ aFormMap[std::make_pair(nPos, nTabIndex)] = pFormControl;
+ }
+
+ if (aFormMap.begin() == aFormMap.end())
+ {
+ // only legacy fields exist. Avoid reprocessing everything and use legacy code path.
+ GotoFieldmark(bNext ? GetFieldmarkAfter(/*Loop=*/true) : GetFieldmarkBefore(/*Loop=*/true));
+ return;
+ }
+
+ // add all of the legacy form field controls into the sorted map
+ IDocumentMarkAccess* pMarkAccess = GetDoc()->getIDocumentMarkAccess();
+ for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
+ {
+ auto pFieldMark = dynamic_cast<sw::mark::IFieldmark*>(*it);
+ assert(pFieldMark);
+ std::pair<SwTextContentControl*, sw::mark::IFieldmark*> pFormControl(nullptr, pFieldMark);
+ // legacy form fields do not have (functional) tabIndexes - use lowest priority for them
+ aFormMap[std::make_pair((*it)->GetMarkStart(), SAL_MAX_UINT32)] = pFormControl;
+ }
+
+ if (aFormMap.begin() == aFormMap.end())
+ return;
+
+ // Identify the current location in the document, and the current tab index priority
+
+ // A content control could contain a Fieldmark, so check for legacy fieldmarks first
+ sw::mark::IFieldmark* pFieldMark = GetCurrentFieldmark();
+ SwTextContentControl* pTCC = !pFieldMark ? CursorInsideContentControl() : nullptr;
+
+ auto pCC = pTCC ? pTCC->GetContentControl().GetContentControl() : nullptr;
+ const sal_Int32 nCurTabIndex = pCC && pCC->GetTabIndex() ? pCC->GetTabIndex() : SAL_MAX_UINT32;
+
+ SwPosition nCurPos(*GetCursor()->GetPoint());
+ if (pFieldMark)
+ nCurPos = pFieldMark->GetMarkStart();
+ else if (pTCC && pTCC->GetTextNode())
+ nCurPos = SwPosition(*pTCC->GetTextNode(), pTCC->GetStart());
+
+ // Find the previous (or next) tab control and navigate to it
+ const std::pair<SwPosition, sal_uInt32> nOldPos(nCurPos, nCurTabIndex);
+
+ // lower_bound acts like find, and returns a pointer to nFindPos if it exists,
+ // otherwise it will point to the previous entry.
+ auto aNewPos = aFormMap.lower_bound(nOldPos);
+ if (bNext && aNewPos != aFormMap.end())
+ ++aNewPos;
+ else if (!bNext && aNewPos != aFormMap.end() && aNewPos->first == nOldPos)
+ {
+ // Found the current position - need to return previous
+ if (aNewPos == aFormMap.begin())
+ aNewPos = aFormMap.end(); // prepare to loop around
+ else
+ --aNewPos;
+ }
+
+ if (aNewPos == aFormMap.end())
+ {
+ // Loop around to the other side
+ if (bNext)
+ aNewPos = aFormMap.begin();
+ else
+ --aNewPos;
+ }
+
+ // the entry contains a pointer to either a Content Control (first) or Fieldmark (second)
+ if (aNewPos->second.first)
+ {
+ auto& rFCC = static_cast<SwFormatContentControl&>(aNewPos->second.first->GetAttr());
+ GotoFormatContentControl(rFCC);
+ }
+ else
+ {
+ assert(aNewPos->second.second);
+ GotoFieldmark(aNewPos->second.second);
+ }
+}
+
bool SwCursorShell::GotoFormatField( const SwFormatField& rField )
{
bool bRet = false;
@@ -1002,7 +1125,7 @@ bool SwCursorShell::CursorInsideInputField() const
return false;
}
-bool SwCursorShell::CursorInsideContentControl() const
+SwTextContentControl* SwCursorShell::CursorInsideContentControl() const
{
for (SwPaM& rCursor : GetCursor()->GetRingContainer())
{
@@ -1014,13 +1137,13 @@ bool SwCursorShell::CursorInsideContentControl() const
}
sal_Int32 nIndex = pStart->nContent.GetIndex();
- if (pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT))
+ if (SwTextAttr* pAttr = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT))
{
- return true;
+ return static_txtattr_cast<SwTextContentControl*>(pAttr);
}
}
- return false;
+ return nullptr;
}
bool SwCursorShell::PosInsideInputField( const SwPosition& rPos )
diff --git a/sw/source/core/crsr/pam.cxx b/sw/source/core/crsr/pam.cxx
index e376d5042bbb..b2b51958c6cb 100644
--- a/sw/source/core/crsr/pam.cxx
+++ b/sw/source/core/crsr/pam.cxx
@@ -763,6 +763,13 @@ bool SwPaM::HasReadonlySel( bool bFormView ) const
{
// Allow editing when the cursor/selection is fully inside of a legacy form field.
bRet = !( pA != nullptr && !bAtStartA && !bAtStartB && pA == pB );
+
+ if (bRet && rDoc.GetEditShell()->CursorInsideContentControl())
+ {
+ // Also allow editing inside content controls in general, similar to form fields.
+ // Specific types will be disabled below.
+ bRet = false;
+ }
}
if (!bRet)
@@ -833,7 +840,16 @@ bool SwPaM::HasReadonlySel( bool bFormView ) const
= rFormatContentControl.GetContentControl();
if (pContentControl && !pContentControl->GetReadWrite())
{
- bRet = pContentControl->GetCheckbox() || pContentControl->GetPicture();
+ switch (pContentControl->GetType())
+ {
+ case SwContentControlType::CHECKBOX:
+ case SwContentControlType::PICTURE:
+ case SwContentControlType::DROP_DOWN_LIST:
+ bRet = true;
+ break;
+ default:
+ break;
+ }
}
}
}
diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index 79b8ab934b93..0e73555c0c94 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -63,6 +63,7 @@
#include <textcontentcontrol.hxx>
#include <dropdowncontentcontrolbutton.hxx>
#include <datecontentcontrolbutton.hxx>
+#include <FrameControlsManager.hxx>
// Here static members are defined. They will get changed on alteration of the
// MapMode. This is done so that on ShowCursor the same size does not have to be
@@ -270,7 +271,7 @@ void SwVisibleCursor::SetPosAndShow(SfxViewShell const * pViewShell)
m_aTextCursor.Show();
}
-OString SwVisibleCursor::getLOKPayload(int nType, int nViewId, bool*) const
+std::optional<OString> SwVisibleCursor::getLOKPayload(int nType, int nViewId) const
{
assert(nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR || nType == LOK_CALLBACK_INVALIDATE_VIEW_CURSOR);
if (comphelper::LibreOfficeKit::isActive())
@@ -515,7 +516,7 @@ void SwSelPaintRects::Show(std::vector<OString>* pSelectionRectangles)
pSelectionRectangles->push_back(sRect);
}
-OString SwSelPaintRects::getLOKPayload( int nType, int nViewId, bool* ignore ) const
+std::optional<OString> SwSelPaintRects::getLOKPayload(int nType, int nViewId) const
{
switch( nType )
{
@@ -533,24 +534,19 @@ OString SwSelPaintRects::getLOKPayload( int nType, int nViewId, bool* ignore ) c
// no selection rect
if (!size())
- {
- *ignore = true;
- return OString();
- }
+ return {};
if( nType == LOK_CALLBACK_TEXT_SELECTION_START )
{
if (aStartRect.HasArea())
return aStartRect.SVRect().toString();
- *ignore = true;
- return OString();
+ return {};
}
else // LOK_CALLBACK_TEXT_SELECTION_END
{
if (aEndRect.HasArea())
return aEndRect.SVRect().toString();
- *ignore = true;
- return OString();
+ return {};
}
}
break;
@@ -639,6 +635,7 @@ void SwSelPaintRects::HighlightContentControl()
{
std::vector<basegfx::B2DRange> aContentControlRanges;
std::vector<OString> aLOKRectangles;
+ SwRect aFirstPortionPaintArea;
SwRect aLastPortionPaintArea;
std::shared_ptr<SwContentControl> pContentControl;
@@ -683,12 +680,14 @@ void SwSelPaintRects::HighlightContentControl()
if (!pRects->empty())
{
+ aFirstPortionPaintArea = (*pRects)[0];
aLastPortionPaintArea = (*pRects)[pRects->size() - 1];
}
pContentControl = pCurContentControlAtCursor->GetContentControl().GetContentControl();
}
}
+ auto pWrtShell = dynamic_cast<const SwWrtShell*>(GetShell());
if (!aContentControlRanges.empty())
{
if (comphelper::LibreOfficeKit::isActive())
@@ -698,7 +697,7 @@ void SwSelPaintRects::HighlightContentControl()
aJson.put("action", "show");
aJson.put("rectangles", aPayload);
- if (pContentControl && pContentControl->HasListItems())
+ if (pContentControl && (pContentControl->GetComboBox() || pContentControl->GetDropDown()))
{
tools::ScopedJsonWriterArray aItems = aJson.startArray("items");
for (const auto& rItem : pContentControl->GetListItems())
@@ -712,6 +711,11 @@ void SwSelPaintRects::HighlightContentControl()
aJson.put("date", "true");
}
+ if (pContentControl && !pContentControl->GetAlias().isEmpty())
+ {
+ aJson.put("alias", pContentControl->GetAlias());
+ }
+
std::unique_ptr<char, o3tl::free_delete> pJson(aJson.extractData());
GetShell()->GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_CONTENT_CONTROL, pJson.get());
}
@@ -738,9 +742,8 @@ void SwSelPaintRects::HighlightContentControl()
}
}
- if (pContentControl && pContentControl->HasListItems())
+ if (pContentControl && (pContentControl->GetComboBox() || pContentControl->GetDropDown()))
{
- auto pWrtShell = dynamic_cast<const SwWrtShell*>(GetShell());
if (pWrtShell)
{
auto& rEditWin = const_cast<SwEditWin&>(pWrtShell->GetView().GetEditWin());
@@ -760,7 +763,6 @@ void SwSelPaintRects::HighlightContentControl()
}
if (pContentControl && pContentControl->GetDate())
{
- auto pWrtShell = dynamic_cast<const SwWrtShell*>(GetShell());
if (pWrtShell)
{
auto& rEditWin = const_cast<SwEditWin&>(pWrtShell->GetView().GetEditWin());
@@ -778,6 +780,21 @@ void SwSelPaintRects::HighlightContentControl()
m_pContentControlButton->Show();
}
}
+
+ if (pWrtShell)
+ {
+ auto& rEditWin = const_cast<SwEditWin&>(pWrtShell->GetView().GetEditWin());
+ SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
+ if (pContentControl && !pContentControl->GetAlias().isEmpty())
+ {
+ Point aTopLeftPixel = rEditWin.LogicToPixel(aFirstPortionPaintArea.TopLeft());
+ rMngr.SetContentControlAliasButton(pContentControl.get(), aTopLeftPixel);
+ }
+ else
+ {
+ rMngr.HideControls(FrameControlType::ContentControl);
+ }
+ }
}
else
{
@@ -794,9 +811,21 @@ void SwSelPaintRects::HighlightContentControl()
{
m_pContentControlButton.disposeAndClear();
}
+
+ if (pWrtShell)
+ {
+ auto& rEditWin = const_cast<SwEditWin&>(pWrtShell->GetView().GetEditWin());
+ SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
+ rMngr.HideControls(FrameControlType::ContentControl);
+ }
}
}
+VclPtr<SwContentControlButton> SwSelPaintRects::GetContentControlButton() const
+{
+ return m_pContentControlButton;
+}
+
void SwSelPaintRects::Invalidate( const SwRect& rRect )
{
size_type nSz = size();
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index c368ada50194..9e383db67190 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -230,7 +230,7 @@ namespace
namespace sw
{
// TODO: use SaveBookmark (from DelBookmarks)
- void CopyBookmarks(const SwPaM& rPam, const SwPosition& rCpyPam)
+ void CopyBookmarks(const SwPaM& rPam, const SwPosition& rCpyPam, SwCopyFlags flags)
{
const SwDoc& rSrcDoc = rPam.GetDoc();
SwDoc& rDestDoc = rCpyPam.GetDoc();
@@ -293,9 +293,19 @@ namespace sw
lcl_SetCpyPos(pMark->GetOtherMarkPos(), rStt, *pCpyStt, *aTmpPam.GetMark(), nDelCount);
}
+ OUString sRequestedName = pMark->GetName();
+ if (flags & SwCopyFlags::IsMoveToFly)
+ {
+ assert(&rSrcDoc == &rDestDoc);
+ // Ensure the name can be given to NewMark, since this is ultimately a move
+ auto pSoonToBeDeletedMark = const_cast<sw::mark::IMark*>(pMark);
+ rDestDoc.getIDocumentMarkAccess()->renameMark(pSoonToBeDeletedMark,
+ sRequestedName + "COPY_IS_MOVE");
+ }
+
::sw::mark::IMark* const pNewMark = rDestDoc.getIDocumentMarkAccess()->makeMark(
aTmpPam,
- pMark->GetName(),
+ sRequestedName,
IDocumentMarkAccess::GetType(*pMark),
::sw::mark::InsertMode::CopyText);
// Explicitly try to get exactly the same name as in the source
@@ -306,7 +316,7 @@ namespace sw
|| IDocumentMarkAccess::GetType(*pMark) == IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK);
continue; // can't insert duplicate cross reference mark
}
- rDestDoc.getIDocumentMarkAccess()->renameMark(pNewMark, pMark->GetName());
+ rDestDoc.getIDocumentMarkAccess()->renameMark(pNewMark, sRequestedName);
// copying additional attributes for bookmarks or fieldmarks
::sw::mark::IBookmark* const pNewBookmark =
@@ -3683,7 +3693,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly(
targetPos = pCopiedPaM->second;
}
- sw::CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, targetPos);
+ sw::CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, targetPos, flags);
}
if (rRg.aStart != rRg.aEnd)
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx
index 8a9a70ae2bb9..5052e320f216 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -1666,8 +1666,13 @@ DocumentRedlineManager::AppendRedline(SwRangeRedline* pNewRedl, bool const bCall
pNewRedl->SetEnd( *pRStt, pEnd );
break;
- case SwComparePosition::CollideStart:
case SwComparePosition::CollideEnd:
+ if (pRStt->nContent != 0)
+ { // tdf#147466 HACK: don't combine in this case to avoid the tdf#119571 code from *undeleting* section nodes
+ break;
+ }
+ [[fallthrough]];
+ case SwComparePosition::CollideStart:
if( pRedl->IsOwnRedline( *pNewRedl ) &&
pRedl->CanCombine( *pNewRedl ) )
{
diff --git a/sw/source/core/doc/DocumentStylePoolManager.cxx b/sw/source/core/doc/DocumentStylePoolManager.cxx
index 42e05e0a9aad..1dc1885c8e98 100644
--- a/sw/source/core/doc/DocumentStylePoolManager.cxx
+++ b/sw/source/core/doc/DocumentStylePoolManager.cxx
@@ -1951,7 +1951,6 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
aFormat.SetCharFormat( pNumCFormat );
aFormat.SetStart( 1 );
aFormat.SetIncludeUpperLevels( 1 );
- aFormat.SetSuffix( "." );
static const sal_uInt16 aAbsSpace[ MAXLEVEL ] =
{
@@ -1972,6 +1971,7 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
for (sal_uInt16 n = 0; n < MAXLEVEL; ++n, ++pArr)
{
+ aFormat.SetListFormat("", ".", n);
if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
{
aFormat.SetAbsLSpace( *pArr + 357 ); // 357 is indent of 0.63 cm
@@ -2004,7 +2004,6 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
aFormat.SetCharFormat( pNumCFormat );
aFormat.SetStart( 1 );
aFormat.SetIncludeUpperLevels( 1 );
- aFormat.SetSuffix( "." );
if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
{
@@ -2014,6 +2013,7 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
sal_uInt16 nSpace = 357; // indent of 0.63 cm
for (sal_uInt16 n = 0; n < MAXLEVEL; ++n)
{
+ aFormat.SetListFormat("", ".", n);
if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
{
nSpace += pArr[ n ];
@@ -2041,7 +2041,6 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
aFormat.SetCharFormat( pNumCFormat );
aFormat.SetStart( 1 );
aFormat.SetIncludeUpperLevels( 1 );
- aFormat.SetSuffix( "." );
tools::Long const nOffs = 397; // 0.70 cm
@@ -2057,6 +2056,7 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
for (sal_uInt16 n = 0; n < MAXLEVEL; ++n)
{
+ aFormat.SetListFormat("", ".", n);
if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
{
aFormat.SetAbsLSpace( (n+1) * nOffs + 357 ); // 357 is indent of 0.63 cm
@@ -2081,7 +2081,6 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
aFormat.SetCharFormat( pNumCFormat );
aFormat.SetStart( 1 );
aFormat.SetIncludeUpperLevels( 1 );
- aFormat.SetSuffix( "." );
aFormat.SetNumAdjust( SvxAdjust::Right );
static const sal_uInt16 aAbsSpace[ MAXLEVEL ] =
@@ -2103,7 +2102,7 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
for (sal_uInt16 n = 0; n < MAXLEVEL; ++n, ++pArr)
{
-
+ aFormat.SetListFormat("", ".", n);
if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
{
aFormat.SetAbsLSpace( *pArr );
@@ -2135,8 +2134,8 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
aFormat.SetNumberingType(SVX_NUM_ROMAN_LOWER);
aFormat.SetStart( 1 );
aFormat.SetIncludeUpperLevels( 1 );
- aFormat.SetSuffix( "." );
aFormat.SetNumAdjust( SvxAdjust::Right );
+ aFormat.SetListFormat("", ".", 0);
if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_ALIGNMENT )
{
@@ -2160,6 +2159,7 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
aFormat.SetIncludeUpperLevels( 1 );
aFormat.SetStart( 1 );
+ aFormat.SetListFormat("", ".", 1);
if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
{
@@ -2176,9 +2176,9 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
pNewRule->Set( 1, aFormat );
aFormat.SetNumberingType(SVX_NUM_CHARS_LOWER_LETTER);
- aFormat.SetSuffix(OUString(u')'));
aFormat.SetIncludeUpperLevels( 1 );
aFormat.SetStart( 3 );
+ aFormat.SetListFormat("", u")", 2);
if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
{
@@ -2210,10 +2210,10 @@ SwNumRule* DocumentStylePoolManager::GetNumRuleFromPool( sal_uInt16 nId )
aFormat.SetFirstLineIndent( - nOffs );
}
- aFormat.SetSuffix( OUString() );
for (sal_uInt16 n = 3; n < MAXLEVEL; ++n)
{
aFormat.SetStart( n+1 );
+ aFormat.SetListFormat("", "", n);
if ( eNumberFormatPositionAndSpaceMode == SvxNumberFormat::LABEL_WIDTH_AND_POSITION )
{
diff --git a/sw/source/core/doc/dbgoutsw.cxx b/sw/source/core/doc/dbgoutsw.cxx
index 73b0c47462eb..9b038a36de4d 100644
--- a/sw/source/core/doc/dbgoutsw.cxx
+++ b/sw/source/core/doc/dbgoutsw.cxx
@@ -73,7 +73,9 @@ const char * dbg_out(const void * pVoid)
{
char sBuffer[1024];
+ SAL_WNODEPRECATED_DECLARATIONS_PUSH // sprintf (macOS 13 SDK)
sprintf(sBuffer, "%p", pVoid);
+ SAL_WNODEPRECATED_DECLARATIONS_POP
OUString aTmpStr(sBuffer, strlen(sBuffer), RTL_TEXTENCODING_ASCII_US);
@@ -388,7 +390,9 @@ const char * dbg_out(const SwRect & rRect)
static OUString lcl_dbg_out(const SwFrameFormat & rFrameFormat)
{
char sBuffer[256];
+ SAL_WNODEPRECATED_DECLARATIONS_PUSH // sprintf (macOS 13 SDK)
sprintf(sBuffer, "%p", &rFrameFormat);
+ SAL_WNODEPRECATED_DECLARATIONS_POP
OUString aResult = "[ " +
OUString(sBuffer, strlen(sBuffer), RTL_TEXTENCODING_ASCII_US) +
@@ -483,7 +487,9 @@ static OUString lcl_dbg_out_NumType(sal_Int16 nType)
static OUString lcl_dbg_out(const SwNode & rNode)
{
char aBuffer[128];
+ SAL_WNODEPRECATED_DECLARATIONS_PUSH // sprintf (macOS 13 SDK)
sprintf(aBuffer, "%p", &rNode);
+ SAL_WNODEPRECATED_DECLARATIONS_POP
OUString aTmpStr = "<node "
"index=\"" +
@@ -735,7 +741,9 @@ static OUString lcl_dbg_out(const SwNumRuleTable & rTable)
aResult.append(rTable[n]->GetName());
char sBuffer[256];
+ SAL_WNODEPRECATED_DECLARATIONS_PUSH // sprintf (macOS 13 SDK)
sprintf(sBuffer, "(%p)", rTable[n]);
+ SAL_WNODEPRECATED_DECLARATIONS_POP
aResult.appendAscii(sBuffer);
}
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index 800c264588b6..938986058a72 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -68,6 +68,8 @@
#include <pam.hxx>
#include <ndtxt.hxx>
#include <swundo.hxx>
+#include <rolbck.hxx>
+#include <UndoAttribute.hxx>
#include <UndoCore.hxx>
#include <UndoTable.hxx>
#include <pagedesc.hxx>
@@ -130,6 +132,11 @@ sal_Int32 SwDoc::getReferenceCount() const
return *m_pMetaFieldManager;
}
+::SwContentControlManager& SwDoc::GetContentControlManager()
+{
+ return *m_pContentControlManager;
+}
+
::sw::UndoManager & SwDoc::GetUndoManager()
{
return *m_pUndoManager;
@@ -1109,6 +1116,28 @@ sal_uInt16 SwDoc::GetRefMarks( std::vector<OUString>* pNames ) const
return nCount;
}
+void SwDoc::DeleteFormatRefMark(const SwFormatRefMark* pFormatRefMark)
+{
+ const SwTextRefMark* pTextRefMark = pFormatRefMark->GetTextRefMark();
+ SwTextNode& rTextNd = const_cast<SwTextNode&>(pTextRefMark->GetTextNode());
+ std::unique_ptr<SwRegHistory> aRegHistory;
+ if (GetIDocumentUndoRedo().DoesUndo())
+ {
+ SwUndoResetAttr* pUndo = new SwUndoResetAttr(SwPosition(rTextNd, pTextRefMark->GetStart()),
+ RES_TXTATR_REFMARK);
+ GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
+ aRegHistory.reset(new SwRegHistory(rTextNd, &pUndo->GetHistory()));
+ rTextNd.GetpSwpHints()->Register(aRegHistory.get());
+ }
+ rTextNd.DeleteAttribute(const_cast<SwTextRefMark*>(pTextRefMark));
+ if (GetIDocumentUndoRedo().DoesUndo())
+ {
+ if (rTextNd.GetpSwpHints())
+ rTextNd.GetpSwpHints()->DeRegister();
+ }
+ getIDocumentState().SetModified();
+}
+
static bool lcl_SpellAndGrammarAgain( SwNode* pNd, void* pArgs )
{
SwTextNode *pTextNode = pNd->GetTextNode();
@@ -1119,14 +1148,14 @@ static bool lcl_SpellAndGrammarAgain( SwNode* pNd, void* pArgs )
{
if( pTextNode->GetWrong() &&
pTextNode->GetWrong()->InvalidateWrong() )
- pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO);
+ pTextNode->SetWrongDirty(sw::WrongState::TODO);
if( pTextNode->GetGrammarCheck() &&
pTextNode->GetGrammarCheck()->InvalidateWrong() )
pTextNode->SetGrammarCheckDirty( true );
}
else
{
- pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO);
+ pTextNode->SetWrongDirty(sw::WrongState::TODO);
if( pTextNode->GetWrong() )
pTextNode->GetWrong()->SetInvalid( 0, COMPLETE_STRING );
pTextNode->SetGrammarCheckDirty( true );
diff --git a/sw/source/core/doc/docbm.cxx b/sw/source/core/doc/docbm.cxx
index 0b8f5a39d158..4b9a98615868 100644
--- a/sw/source/core/doc/docbm.cxx
+++ b/sw/source/core/doc/docbm.cxx
@@ -314,7 +314,8 @@ namespace
};
- IMark* lcl_getMarkAfter(const MarkManager::container_t& rMarks, const SwPosition& rPos)
+ IMark* lcl_getMarkAfter(const MarkManager::container_t& rMarks, const SwPosition& rPos,
+ bool bLoop)
{
auto const pMarkAfter = upper_bound(
rMarks.begin(),
@@ -322,11 +323,17 @@ namespace
rPos,
CompareIMarkStartsAfter());
if(pMarkAfter == rMarks.end())
+ {
+ if (bLoop && rMarks.begin() != rMarks.end())
+ return *rMarks.begin();
+
return nullptr;
+ }
return *pMarkAfter;
};
- IMark* lcl_getMarkBefore(const MarkManager::container_t& rMarks, const SwPosition& rPos)
+ IMark* lcl_getMarkBefore(const MarkManager::container_t& rMarks, const SwPosition& rPos,
+ bool bLoop)
{
// candidates from which to choose the mark before
MarkManager::container_t vCandidates;
@@ -344,7 +351,13 @@ namespace
back_inserter(vCandidates),
[&rPos] (const ::sw::mark::MarkBase *const pMark) { return !(pMark->GetMarkEnd() < rPos); } );
// no candidate left => we are in front of the first mark or there are none
- if(vCandidates.empty()) return nullptr;
+ if(vCandidates.empty())
+ {
+ if (bLoop && rMarks.begin() != rMarks.end())
+ return *(rMarks.end() - 1);
+
+ return nullptr;
+ }
// return the highest (last) candidate using mark end ordering
return *max_element(vCandidates.begin(), vCandidates.end(), &lcl_MarkOrderingByEnd);
}
@@ -621,10 +634,10 @@ namespace sw::mark
pMark = std::make_unique<TextFieldmark>(rPaM, rName);
break;
case IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK:
- pMark = std::make_unique<CheckboxFieldmark>(rPaM);
+ pMark = std::make_unique<CheckboxFieldmark>(rPaM, rName);
break;
case IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK:
- pMark = std::make_unique<DropDownFieldmark>(rPaM);
+ pMark = std::make_unique<DropDownFieldmark>(rPaM, rName);
break;
case IDocumentMarkAccess::MarkType::DATE_FIELDMARK:
pMark = std::make_unique<DateFieldmark>(rPaM);
@@ -1372,6 +1385,8 @@ namespace sw::mark
IDocumentMarkAccess::const_iterator_t MarkManager::getFieldmarksEnd() const
{ return m_vFieldmarks.end(); }
+ sal_Int32 MarkManager::getFieldmarksCount() const { return m_vFieldmarks.size(); }
+
// finds the first that is starting after
IDocumentMarkAccess::const_iterator_t MarkManager::findFirstBookmarkStartsAfter(const SwPosition& rPos) const
@@ -1421,6 +1436,29 @@ namespace sw::mark
return dynamic_cast<IFieldmark*>(pFieldmark);
}
+ IMark* MarkManager::getBookmarkFor(const SwPosition& rPos) const
+ {
+ auto it = std::find_if(m_vBookmarks.begin(), m_vBookmarks.end(),
+ [&rPos](const sw::mark::MarkBase* pMark)
+ { return pMark->IsCoveringPosition(rPos); });
+ if (it == m_vBookmarks.end())
+ {
+ return nullptr;
+ }
+ sw::mark::IMark* pBookmark = *it;
+ for (; it != m_vBookmarks.end() && (*it)->GetMarkStart() <= rPos; ++it)
+ {
+ // Find the innermost bookmark.
+ if (rPos < (*it)->GetMarkEnd()
+ && (pBookmark->GetMarkStart() < (*it)->GetMarkStart()
+ || (*it)->GetMarkEnd() < pBookmark->GetMarkEnd()))
+ {
+ pBookmark = *it;
+ }
+ }
+ return pBookmark;
+ }
+
void MarkManager::deleteFieldmarkAt(const SwPosition& rPos)
{
auto const pFieldmark = dynamic_cast<Fieldmark*>(getFieldmarkAt(rPos));
@@ -1597,11 +1635,11 @@ namespace sw::mark
return aRet;
}
- IFieldmark* MarkManager::getFieldmarkAfter(const SwPosition& rPos) const
- { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); }
+ IFieldmark* MarkManager::getFieldmarkAfter(const SwPosition& rPos, bool bLoop) const
+ { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos, bLoop)); }
- IFieldmark* MarkManager::getFieldmarkBefore(const SwPosition& rPos) const
- { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); }
+ IFieldmark* MarkManager::getFieldmarkBefore(const SwPosition& rPos, bool bLoop) const
+ { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos, bLoop)); }
IDocumentMarkAccess::const_iterator_t MarkManager::getAnnotationMarksBegin() const
{
diff --git a/sw/source/core/doc/docfld.cxx b/sw/source/core/doc/docfld.cxx
index 652af8a188b9..fb1e71f3b190 100644
--- a/sw/source/core/doc/docfld.cxx
+++ b/sw/source/core/doc/docfld.cxx
@@ -839,6 +839,9 @@ void SwDocUpdateField::MakeFieldList_( SwDoc& rDoc, int eGetMode )
// new version: walk all fields of the attribute pool
m_pFieldSortList.reset(new SetGetExpFields);
+ // remembeer sections that were unhidden and need to be hidden again
+ std::vector<std::reference_wrapper<SwSection>> aUnhiddenSections;
+
// consider and unhide sections
// with hide condition, only in mode GETFLD_ALL (<eGetMode == GETFLD_ALL>)
// notes by OD:
@@ -885,13 +888,27 @@ void SwDocUpdateField::MakeFieldList_( SwDoc& rDoc, int eGetMode )
{
pSectNd = rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode();
OSL_ENSURE( pSectNd, "Where is my SectionNode" );
- pSectNd->GetSection().SetCondHidden( false );
+
+ auto& rSection = pSectNd->GetSection();
+ // unhide and remember the conditionally hidden sections
+ if (rSection.IsHidden() && !rSection.GetCondition().isEmpty() && rSection.IsCondHidden())
+ {
+ aUnhiddenSections.push_back(std::ref(rSection)); // remember to later hide again
+ rSection.SetCondHidden(false);
+ }
}
for (std::vector<sal_uLong>::size_type n = 0; n < nArrStt; ++n)
{
pSectNd = rDoc.GetNodes()[ aTmpArr[ n ] ]->GetSectionNode();
OSL_ENSURE( pSectNd, "Where is my SectionNode" );
- pSectNd->GetSection().SetCondHidden( false );
+
+ auto& rSection = pSectNd->GetSection();
+ // unhide and remember the conditionally hidden sections
+ if (rSection.IsHidden() && !rSection.GetCondition().isEmpty() && rSection.IsCondHidden())
+ {
+ aUnhiddenSections.push_back(std::ref(rSection)); // remember to later hide again
+ rSection.SetCondHidden(false);
+ }
}
// add all to the list so that they are sorted
@@ -1032,6 +1049,13 @@ void SwDocUpdateField::MakeFieldList_( SwDoc& rDoc, int eGetMode )
}
m_nFieldListGetMode = eGetMode;
m_nNodes = rDoc.GetNodes().Count();
+
+ // return the conditional hidden value back to the previous value
+ for (auto& rSectionWrapper : aUnhiddenSections)
+ {
+ auto& rSection = rSectionWrapper.get();
+ rSection.SetCondHidden(true);
+ }
}
void SwDocUpdateField::GetBodyNode( const SwTextField& rTField, SwFieldIds nFieldWhich )
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 42dfd707c556..c2104cd95857 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -76,6 +76,7 @@
#include <modcfg.hxx>
#include <frameformats.hxx>
#include <textboxhelper.hxx>
+#include <textcontentcontrol.hxx>
#include <memory>
using namespace ::com::sun::star::i18n;
@@ -1965,6 +1966,7 @@ void SwDoc::dumpAsXml(xmlTextWriterPtr pWriter) const
m_PageDescs.dumpAsXml(pWriter);
maDBData.dumpAsXml(pWriter);
mpMarkManager->dumpAsXml(pWriter);
+ m_pContentControlManager->dumpAsXml(pWriter);
m_pUndoManager->dumpAsXml(pWriter);
m_pDocumentSettingManager->dumpAsXml(pWriter);
getIDocumentFieldsAccess().GetFieldTypes()->dumpAsXml(pWriter);
diff --git a/sw/source/core/doc/doclay.cxx b/sw/source/core/doc/doclay.cxx
index 7d3ad61e46b4..871b6b2967e7 100644
--- a/sw/source/core/doc/doclay.cxx
+++ b/sw/source/core/doc/doclay.cxx
@@ -161,13 +161,12 @@ SwFlyFrameFormat* SwDoc::MakeFlySection_( const SwPosition& rAnchPos,
pFrameFormat = getIDocumentStylePoolAccess().GetFrameFormatFromPool( RES_POOLFRM_FRAME );
OUString sName;
- if( !mbInReading )
- switch( rNode.GetNodeType() )
- {
+ switch( rNode.GetNodeType() )
+ {
case SwNodeType::Grf: sName = GetUniqueGrfName(); break;
case SwNodeType::Ole: sName = GetUniqueOLEName(); break;
default: sName = GetUniqueFrameName(); break;
- }
+ }
SwFlyFrameFormat* pFormat = MakeFlyFrameFormat( sName, pFrameFormat );
// Create content and connect to the format.
@@ -1419,6 +1418,10 @@ const SwFlyFrameFormat* SwDoc::FindFlyByName( const OUString& rName, SwNodeType
void SwDoc::SetFlyName( SwFlyFrameFormat& rFormat, const OUString& rName )
{
+ if (rFormat.GetName() == rName)
+ {
+ return;
+ }
OUString sName( rName );
if( sName.isEmpty() || FindFlyByName( sName ) )
{
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index da65b2957229..00f1261c4981 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -78,7 +78,8 @@
#include <mvsave.hxx>
#include <istyleaccess.hxx>
#include "swstylemanager.hxx"
-#include <IGrammarContact.hxx>
+#include <GrammarContact.hxx>
+#include <OnlineAccessibilityCheck.hxx>
#include <tblafmt.hxx>
#include <MarkManager.hxx>
#include <UndoManager.hxx>
@@ -108,6 +109,7 @@
#include <sfx2/Metadatable.hxx>
#include <fmtmeta.hxx>
+#include <textcontentcontrol.hxx>
#include <svx/xfillit0.hxx>
#include <unotools/configmgr.hxx>
@@ -207,6 +209,7 @@ SwDoc::SwDoc()
maOLEModifiedIdle( "sw::SwDoc maOLEModifiedIdle" ),
mpMarkManager(new ::sw::mark::MarkManager(*this)),
m_pMetaFieldManager(new ::sw::MetaFieldManager()),
+ m_pContentControlManager(new ::SwContentControlManager()),
m_pDocumentDrawModelManager( new ::sw::DocumentDrawModelManager( *this ) ),
m_pDocumentRedlineManager( new ::sw::DocumentRedlineManager( *this ) ),
m_pDocumentStateManager( new ::sw::DocumentStateManager( *this ) ),
@@ -250,7 +253,8 @@ SwDoc::SwDoc()
mpNumberFormatter( nullptr ),
mpNumRuleTable( new SwNumRuleTable ),
mpExtInputRing( nullptr ),
- mpGrammarContact(createGrammarContact()),
+ mpGrammarContact(new sw::GrammarContact),
+ mpOnlineAccessibilityCheck(new sw::OnlineAccessibilityCheck(*this)),
mpCellStyles(new SwCellStyleTable),
mReferenceCount(0),
mbDtor(false),
@@ -272,7 +276,6 @@ SwDoc::SwDoc()
mbIsPrepareSelAll(false),
meDictionaryMissing( MissingDictionary::Undefined ),
mbContainsAtPageObjWithContentAnchor(false), //#i119292#, fdo#37024
-
meDocType(DOCTYPE_NATIVE)
{
// The DrawingLayer ItemPool which is used as 2nd pool for Writer documents' pool
@@ -407,6 +410,7 @@ SwDoc::~SwDoc()
}
mpGrammarContact.reset();
+ mpOnlineAccessibilityCheck.reset();
getIDocumentTimerAccess().StopIdling(); // stop idle timer
@@ -806,14 +810,6 @@ void SwDoc::WriteLayoutCache( SvStream& rStream )
SwLayoutCache::Write( rStream, *this );
}
-IGrammarContact* getGrammarContact( const SwTextNode& rTextNode )
-{
- const SwDoc& rDoc = rTextNode.GetDoc();
- if (rDoc.IsInDtor())
- return nullptr;
- return rDoc.getGrammarContact();
-}
-
::sfx2::IXmlIdRegistry&
SwDoc::GetXmlIdRegistry()
{
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 35568a615581..1bd30da3836a 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -918,7 +918,11 @@ void SwRedlineExtraData_FormatColl::Reject( SwPaM& rPam ) const
{
aPam.GetPoint()->nNode--;
SwContentNode* pNode = aPam.GetPoint()->nNode.GetNode().GetContentNode();
- aPam.GetPoint()->nContent.Assign( pNode, pNode->Len() );
+ if ( pNode )
+ aPam.GetPoint()->nContent.Assign( pNode, pNode->Len() );
+ else
+ // tdf#147507 set it back to a content node to avoid of crashing
+ aPam.GetPoint()->nNode++;
}
else if (aPam.GetPoint()->nNode < aPam.GetMark()->nNode)
{
diff --git a/sw/source/core/doc/fmtcol.cxx b/sw/source/core/doc/fmtcol.cxx
index e35e523b6a92..531a35548818 100644
--- a/sw/source/core/doc/fmtcol.cxx
+++ b/sw/source/core/doc/fmtcol.cxx
@@ -114,6 +114,19 @@ SwTextFormatColl::~SwTextFormatColl()
{
if(m_bInSwFntCache)
pSwFontCache->Delete( this );
+
+ if (GetDoc()->IsInDtor())
+ {
+ return;
+ }
+
+ for (const auto& pCharFormat : *GetDoc()->GetCharFormats())
+ {
+ if (pCharFormat->GetLinkedParaFormat() == this)
+ {
+ pCharFormat->SetLinkedParaFormat(nullptr);
+ }
+ }
}
void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
{
@@ -325,7 +338,7 @@ void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& rH
SwFormatColl::SwClientNotify(rModify, rHint);
}
-void SwTextFormatColl::SetLinkedCharFormat(SwCharFormat& rLink) { mpLinkedCharFormat = &rLink; }
+void SwTextFormatColl::SetLinkedCharFormat(SwCharFormat* pLink) { mpLinkedCharFormat = pLink; }
const SwCharFormat* SwTextFormatColl::GetLinkedCharFormat() const { return mpLinkedCharFormat; }
diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index 418c69927228..4cfebf732b1c 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -93,17 +93,8 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo
pShape->GetDoc()->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
uno::Reference<text::XTextContentAppend> xTextContentAppend(xTextDocument->getText(),
uno::UNO_QUERY);
- try
- {
- uno::Reference<text::XTextContent> XSourceShape(pObject->getUnoShape(),
- uno::UNO_QUERY_THROW);
- xTextContentAppend->insertTextContentWithProperties(
- xTextFrame, uno::Sequence<beans::PropertyValue>(), XSourceShape->getAnchor());
- }
- catch (uno::Exception&)
- {
- xTextContentAppend->appendTextContent(xTextFrame, uno::Sequence<beans::PropertyValue>());
- }
+ xTextContentAppend->appendTextContent(xTextFrame, uno::Sequence<beans::PropertyValue>());
+
// Link FLY and DRAW formats, so it becomes a text box (needed for syncProperty calls).
uno::Reference<text::XTextFrame> xRealTextFrame(xTextFrame, uno::UNO_QUERY);
auto pTextFrame = dynamic_cast<SwXTextFrame*>(xRealTextFrame.get());
@@ -142,7 +133,8 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo
xPropertySet->setPropertyValue(UNO_NAME_SURROUND, uno::makeAny(text::WrapTextMode_THROUGH));
uno::Reference<container::XNamed> xNamed(xTextFrame, uno::UNO_QUERY);
- xNamed->setName(pShape->GetDoc()->GetUniqueFrameName());
+ assert(!xNamed->getName().isEmpty());
+ (void)xNamed;
// Link its text range to the original shape.
uno::Reference<text::XTextRange> xTextBox(xTextFrame, uno::UNO_QUERY_THROW);
diff --git a/sw/source/core/docnode/ndsect.cxx b/sw/source/core/docnode/ndsect.cxx
index 25669fcd2f76..6b3750447d8d 100644
--- a/sw/source/core/docnode/ndsect.cxx
+++ b/sw/source/core/docnode/ndsect.cxx
@@ -1263,6 +1263,7 @@ SwSectionNode* SwSectionNode::MakeCopy( SwDoc& rDoc, const SwNodeIndex& rIdx ) c
pNewSect->SetType( GetSection().GetType() );
pNewSect->SetCondition( GetSection().GetCondition() );
+ pNewSect->SetCondHidden( GetSection().IsCondHidden() );
pNewSect->SetLinkFileName( GetSection().GetLinkFileName() );
if( !pNewSect->IsHiddenFlag() && GetSection().IsHidden() )
pNewSect->SetHidden();
diff --git a/sw/source/core/docnode/ndtbl1.cxx b/sw/source/core/docnode/ndtbl1.cxx
index 4d0e38b794ab..923999f647cb 100644
--- a/sw/source/core/docnode/ndtbl1.cxx
+++ b/sw/source/core/docnode/ndtbl1.cxx
@@ -1626,7 +1626,8 @@ void SwDoc::AdjustCellWidth( const SwCursor& rCursor,
}
fTotalWish += aWish[i];
}
- const sal_uInt16 nEqualWidth = nSelectedWidth / nCols;
+ assert(nCols);
+ const sal_uInt16 nEqualWidth = nCols ? nSelectedWidth / nCols : 0;
// bBalance: Distribute the width evenly
for (sal_uInt16 & rn : aWish)
if ( rn && bBalance )
diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx
index 12be064f370b..a1a549d25069 100644
--- a/sw/source/core/docnode/node.cxx
+++ b/sw/source/core/docnode/node.cxx
@@ -69,12 +69,22 @@
#include <swcrsr.hxx>
#include <hints.hxx>
#include <frameformats.hxx>
+#include <OnlineAccessibilityCheck.hxx>
#ifdef DBG_UTIL
#include <sal/backtrace.hxx>
#endif
using namespace ::com::sun::star::i18n;
+namespace sw
+{
+
+void AccessibilityCheckStatus::reset()
+{
+ pCollection.reset();
+}
+
+}
/*
* Some local helper functions for the attribute set handle of a content node.
@@ -1266,7 +1276,7 @@ SwFormatColl *SwContentNode::ChgFormatColl( SwFormatColl *pNewColl )
ChkCondColl(static_cast<SwTextFormatColl*>(pNewColl));
SwFormatChg aTmp1( pOldColl );
SwFormatChg aTmp2( pNewColl );
- SwClientNotify( *this, sw::LegacyModifyHint(&aTmp1, &aTmp2) );
+ CallSwClientNotify( sw::LegacyModifyHint(&aTmp1, &aTmp2) );
}
}
InvalidateInSwCache(RES_ATTRSET_CHG);
@@ -2142,4 +2152,10 @@ void SwNode::RemoveAnchoredFly(SwFrameFormat *const pFlyFormat)
m_aAnchoredFlys.erase(it);
}
+void SwNode::resetAndQueueAccessibilityCheck()
+{
+ GetDoc().getOnlineAccessibilityCheck()->resetAndQueue(this);
+}
+
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx
index d352cfb41057..172be29e067d 100644
--- a/sw/source/core/docnode/nodes.cxx
+++ b/sw/source/core/docnode/nodes.cxx
@@ -21,6 +21,10 @@
#include <libxml/xmlwriter.h>
#include <osl/diagnose.h>
+#include <tools/json_writer.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <sfx2/viewsh.hxx>
+#include <comphelper/lok.hxx>
#include <node.hxx>
#include <doc.hxx>
@@ -2296,6 +2300,22 @@ void SwNodes::RemoveNode( SwNodeOffset nDelPos, SwNodeOffset nSz, bool bDel )
// 'Extra Redlines' array
pTableNode->RemoveRedlines();
}
+
+ SwSectionNode* pSectionNode = pNode->GetSectionNode();
+ if (comphelper::LibreOfficeKit::isActive() && pSectionNode && !GetDoc().IsClipBoard() && SfxViewShell::Current())
+ {
+ OUString fieldCommand = pSectionNode->GetSection().GetSectionName();
+ tools::JsonWriter aJson;
+ aJson.put("commandName", ".uno:DeleteSection");
+ aJson.put("success", true);
+ {
+ auto result = aJson.startNode("result");
+ aJson.put("DeleteSection", fieldCommand);
+ }
+
+ SfxViewShell::Current()->libreOfficeKitViewCallback(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.extractData());
+
+ }
}
SwNodeOffset nEnd = nDelPos + nSz;
diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
index 668288dac689..332f82f0f767 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -1939,6 +1939,43 @@ void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
{
// append 'master' drawing object
pAnchorFrameOfMaster = pFrame;
+
+ const SwFrameFormat* pFlyFormat = nullptr;
+ if (!maAnchoredDrawObj.GetDrawObj()->IsGroupObject())
+ {
+ pFlyFormat = SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_DRAWFRMFMT);
+ }
+
+ if (pFlyFormat)
+ {
+ // This is a master draw object and it has an associated fly format.
+ // See if a fly frame is already inserted to the layout: if so, this
+ // master draw object should be ordered directly before the fly one.
+ if (const SwSortedObjs* pObjs = pFrame->GetDrawObjs())
+ {
+ for (const SwAnchoredObject* pAnchoredObj : *pObjs)
+ {
+ if (&pAnchoredObj->GetFrameFormat() == pFlyFormat)
+ {
+ SdrPage* pDrawPage = pAnchoredObj->GetDrawObj()->getSdrPageFromSdrObject();
+ if (pDrawPage)
+ {
+ sal_uInt32 nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
+ if (maAnchoredDrawObj.GetDrawObj()->GetOrdNum() >= nOrdNum)
+ {
+ pDrawPage->SetObjectOrdNum(maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect(), nOrdNum);
+ }
+ else
+ {
+ pDrawPage->SetObjectOrdNum(nOrdNum, maAnchoredDrawObj.GetDrawObj()->GetOrdNumDirect() + 1);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
pFrame->AppendDrawObj( maAnchoredDrawObj );
}
else
@@ -2005,10 +2042,12 @@ void SwDrawContact::ChkPage()
}
// --> #i28701#
+ // tdf#156287: use anchor page, not current bound rectangle's page,
+ // because an object can't move to a page other than its anchor anyway
SwPageFrame* pPg = ( maAnchoredDrawObj.GetAnchorFrame() &&
maAnchoredDrawObj.GetAnchorFrame()->IsPageFrame() )
? GetPageFrame()
- : FindPage( SwRect(GetMaster()->GetCurrentBoundRect()) );
+ : maAnchoredDrawObj.FindPageFrameOfAnchor();
if ( GetPageFrame() == pPg )
return;
@@ -2313,6 +2352,17 @@ void SwDrawVirtObj::AddToDrawingPage(SwFrame const& rAnchorFrame)
if (&pAnchoredObj->GetFrameFormat() == pFlyFormat)
{
assert(dynamic_cast<SwFlyFrame const*>(pAnchoredObj));
+
+ if (pAnchoredObj->GetDrawObj()->GetOrdNum() >= GetReferencedObj().GetOrdNum())
+ {
+ // This virtual draw object has an associated fly one, but the fly's index
+ // is not below the masters, fix it up.
+ if (pDrawPg)
+ {
+ pDrawPg->SetObjectOrdNum(pAnchoredObj->GetDrawObj()->GetOrdNumDirect(), GetReferencedObj().GetOrdNum());
+ }
+ }
+
nOrdNum = pAnchoredObj->GetDrawObj()->GetOrdNum();
// the master SdrObj should have the highest index
assert(nOrdNum < GetReferencedObj().GetOrdNum());
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index 5298f1a296ba..ace00a7da838 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -1294,4 +1294,17 @@ bool SwVirtFlyDrawObj::IsTextBox() const
return SwTextBoxHelper::isTextBox(GetFormat(), RES_FLYFRMFMT, this);
}
+void SwVirtFlyDrawObj::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwVirtFlyDrawObj"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+ (void)xmlTextWriterWriteAttribute(
+ pWriter, BAD_CAST("fly-frame"),
+ BAD_CAST(OString::number(m_pFlyFrame->GetFrameId()).getStr()));
+
+ SdrVirtObj::dumpAsXml(pWriter);
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx
index a3b5d5a5e12d..0e5777e7bf9e 100644
--- a/sw/source/core/fields/docufld.cxx
+++ b/sw/source/core/fields/docufld.cxx
@@ -314,7 +314,16 @@ OUString SwAuthorFieldType::Expand(sal_uLong nFormat)
{
SvtUserOptions& rOpt = SW_MOD()->GetUserOptions();
if((nFormat & 0xff) == AF_NAME)
- return rOpt.GetFullName();
+ {
+ // Prefer the view's redline author name.
+ // (set in SwXTextDocument::initializeForTiledRendering)
+ std::size_t nAuthor = SW_MOD()->GetRedlineAuthor();
+ OUString sAuthor = SW_MOD()->GetRedlineAuthor(nAuthor);
+ if (sAuthor.isEmpty())
+ return rOpt.GetFullName();
+
+ return sAuthor;
+ }
return rOpt.GetID();
}
diff --git a/sw/source/core/fields/fldbas.cxx b/sw/source/core/fields/fldbas.cxx
index ae5a8751ff05..206fc635ea0c 100644
--- a/sw/source/core/fields/fldbas.cxx
+++ b/sw/source/core/fields/fldbas.cxx
@@ -520,6 +520,37 @@ OUString FormatNumber(sal_uInt32 nNum, SvxNumType nFormat, LanguageType nLang)
return aNumber.GetNumStr(nNum, LanguageTag::convertToLocale(nLang));
}
+SwFieldTypesEnum SwFieldTypeFromString(std::u16string_view rString)
+{
+ if (rString == u"Date")
+ return SwFieldTypesEnum::Date;
+ if (rString == u"Time")
+ return SwFieldTypesEnum::Time;
+ if (rString == u"Filename")
+ return SwFieldTypesEnum::Filename;
+ if (rString == u"DatabaseName")
+ return SwFieldTypesEnum::DatabaseName;
+ if (rString == u"Chapter")
+ return SwFieldTypesEnum::Chapter;
+ if (rString == u"PageNumber")
+ return SwFieldTypesEnum::PageNumber;
+ if (rString == u"DocumentStatistics")
+ return SwFieldTypesEnum::DocumentStatistics;
+ if (rString == u"Author")
+ return SwFieldTypesEnum::Author;
+ if (rString == u"Set")
+ return SwFieldTypesEnum::Set;
+ if (rString == u"Get")
+ return SwFieldTypesEnum::Get;
+ if (rString == u"Formel")
+ return SwFieldTypesEnum::Formel;
+ if (rString == u"HiddenText")
+ return SwFieldTypesEnum::HiddenText;
+ if (rString == u"SetRef")
+ return SwFieldTypesEnum::SetRef;
+ return SwFieldTypesEnum::Unknown;
+}
+
SwValueFieldType::SwValueFieldType(SwDoc *const pDoc, SwFieldIds const nWhichId)
: SwFieldType(nWhichId)
, m_pDoc(pDoc)
diff --git a/sw/source/core/frmedt/fetab.cxx b/sw/source/core/frmedt/fetab.cxx
index 678ebfc2fac7..a87e79affbc6 100644
--- a/sw/source/core/frmedt/fetab.cxx
+++ b/sw/source/core/frmedt/fetab.cxx
@@ -282,7 +282,15 @@ bool SwFEShell::DeleteCol()
// search boxes via the layout
bool bRet;
SwSelBoxes aBoxes;
- GetTableSel( *this, aBoxes, SwTableSearchType::Col );
+ SwTableSearchType eSearchType = SwTableSearchType::Col;
+
+ // NewModel tables already ExpandColumnSelection, so don't do it here also.
+ const SwContentNode* pContentNd = getShellCursor(false)->GetNode().GetContentNode();
+ const SwTableNode* pTableNd = pContentNd ? pContentNd->FindTableNode() : nullptr;
+ if (pTableNd && pTableNd->GetTable().IsNewModel())
+ eSearchType = SwTableSearchType::NONE;
+
+ GetTableSel(*this, aBoxes, eSearchType);
if ( !aBoxes.empty() )
{
TableWait aWait( aBoxes.size(), pFrame, *GetDoc()->GetDocShell() );
diff --git a/sw/source/core/inc/AccessibilityCheck.hxx b/sw/source/core/inc/AccessibilityCheck.hxx
index 4bcc56000bc4..c7613e8829a4 100644
--- a/sw/source/core/inc/AccessibilityCheck.hxx
+++ b/sw/source/core/inc/AccessibilityCheck.hxx
@@ -8,19 +8,40 @@
*
*/
-#ifndef INCLUDED_SW_SOURCE_CORE_ACCESSIBILITYCHECK_HXX
-#define INCLUDED_SW_SOURCE_CORE_ACCESSIBILITYCHECK_HXX
+#pragma once
#include <sfx2/AccessibilityCheck.hxx>
#include <doc.hxx>
+#include <node.hxx>
namespace sw
{
+/** Base class for accessibility checks */
+class BaseCheck
+{
+protected:
+ sfx::AccessibilityIssueCollection& m_rIssueCollection;
+
+public:
+ BaseCheck(sfx::AccessibilityIssueCollection& rIssueCollection)
+ : m_rIssueCollection(rIssueCollection)
+ {
+ }
+ virtual ~BaseCheck() {}
+};
+
class SW_DLLPUBLIC AccessibilityCheck final : public sfx::AccessibilityCheck
{
private:
SwDoc* m_pDoc;
+ std::vector<std::shared_ptr<BaseCheck>> m_aDocumentChecks;
+ std::vector<std::shared_ptr<BaseCheck>> m_aNodeChecks;
+
+ AccessibilityCheck() = delete;
+
+ void init();
+
public:
AccessibilityCheck(SwDoc* pDoc)
: m_pDoc(pDoc)
@@ -29,10 +50,10 @@ public:
void check() override;
void checkObject(SdrObject* pObject);
+ void checkNode(SwNode* pNode);
+ void checkDocumentProperties();
};
} // end sw namespace
-#endif
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/AccessibilityIssue.hxx b/sw/source/core/inc/AccessibilityIssue.hxx
index 8823303057a1..870ad2364692 100644
--- a/sw/source/core/inc/AccessibilityIssue.hxx
+++ b/sw/source/core/inc/AccessibilityIssue.hxx
@@ -25,7 +25,7 @@ enum class IssueObject
TEXT,
};
-class AccessibilityIssue final : public sfx::AccessibilityIssue
+class SW_DLLPUBLIC AccessibilityIssue final : public sfx::AccessibilityIssue
{
private:
IssueObject m_eIssueObject;
@@ -58,6 +58,10 @@ public:
bool canGotoIssue() const override;
void gotoIssue() const override;
+
+ sal_Int32 getStart() { return m_nStart; }
+ sal_Int32 getEnd() { return m_nEnd; }
+ SwNode* getNode() { return m_pNode; }
};
} // end sw namespace
diff --git a/sw/source/core/inc/DocumentContentOperationsManager.hxx b/sw/source/core/inc/DocumentContentOperationsManager.hxx
index 5434e43f2a9c..32663cafd2fa 100644
--- a/sw/source/core/inc/DocumentContentOperationsManager.hxx
+++ b/sw/source/core/inc/DocumentContentOperationsManager.hxx
@@ -185,7 +185,8 @@ private:
};
-void CopyBookmarks(const SwPaM& rPam, const SwPosition& rTarget);
+void CopyBookmarks(const SwPaM& rPam, const SwPosition& rTarget,
+ SwCopyFlags flags = SwCopyFlags::Default);
void CalcBreaks(std::vector<std::pair<SwNodeOffset, sal_Int32>> & rBreaks,
SwPaM const & rPam, bool const isOnlyFieldmarks = false);
diff --git a/sw/source/core/inc/MarkManager.hxx b/sw/source/core/inc/MarkManager.hxx
index 0cf40191e3d1..84f92e68a31e 100644
--- a/sw/source/core/inc/MarkManager.hxx
+++ b/sw/source/core/inc/MarkManager.hxx
@@ -84,14 +84,16 @@ namespace sw::mark {
virtual sal_Int32 getBookmarksCount() const override;
virtual const_iterator_t findBookmark(const OUString& rName) const override;
virtual const_iterator_t findFirstBookmarkStartsAfter(const SwPosition& rPos) const override;
+ virtual ::sw::mark::IMark* getBookmarkFor(const SwPosition& rPos) const override;
// Fieldmarks
virtual const_iterator_t getFieldmarksBegin() const override;
virtual const_iterator_t getFieldmarksEnd() const override;
+ virtual sal_Int32 getFieldmarksCount() const override;
virtual ::sw::mark::IFieldmark* getFieldmarkAt(const SwPosition& rPos) const override;
virtual ::sw::mark::IFieldmark* getFieldmarkFor(const SwPosition& rPos) const override;
- virtual ::sw::mark::IFieldmark* getFieldmarkBefore(const SwPosition& rPos) const override;
- virtual ::sw::mark::IFieldmark* getFieldmarkAfter(const SwPosition& rPos) const override;
+ virtual sw::mark::IFieldmark* getFieldmarkBefore(const SwPosition& rPos, bool bLoop) const override;
+ virtual sw::mark::IFieldmark* getFieldmarkAfter(const SwPosition& rPos, bool bLoop) const override;
virtual ::sw::mark::IFieldmark* getDropDownFor(const SwPosition &rPos) const override;
virtual std::vector<::sw::mark::IFieldmark*> getNoTextFieldmarksIn(const SwPaM &rPaM) const override;
diff --git a/sw/source/core/inc/ThemeColorChanger.hxx b/sw/source/core/inc/ThemeColorChanger.hxx
new file mode 100644
index 000000000000..d4ba7a9fcad5
--- /dev/null
+++ b/sw/source/core/inc/ThemeColorChanger.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+#pragma once
+
+#include <docsh.hxx>
+#include <svx/ColorSets.hxx>
+#include <svx/theme/IThemeColorChanger.hxx>
+
+namespace sw
+{
+class ThemeColorChanger : public svx::IThemeColorChanger
+{
+private:
+ SwDocShell* mpDocSh;
+
+public:
+ ThemeColorChanger(SwDocShell* pDocSh)
+ : mpDocSh(pDocSh)
+ {
+ }
+
+ virtual ~ThemeColorChanger() override;
+
+ void apply(svx::ColorSet const& rColorSet) override;
+};
+
+} // end sw namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/UndoAttribute.hxx b/sw/source/core/inc/UndoAttribute.hxx
index ffe4c4f3206d..3ac09d7f9c06 100644
--- a/sw/source/core/inc/UndoAttribute.hxx
+++ b/sw/source/core/inc/UndoAttribute.hxx
@@ -45,7 +45,7 @@ class SwUndoAttr final : public SwUndo, private SwUndRng
OUString m_aChrFormatName;
void RemoveIdx( SwDoc& rDoc );
-
+ void redoAttribute(SwPaM& rPam, sw::UndoRedoContext& rContext);
public:
SwUndoAttr( const SwPaM&, const SfxItemSet &, const SetAttrMode nFlags );
SwUndoAttr( const SwPaM&, const SfxPoolItem&, const SetAttrMode nFlags );
diff --git a/sw/source/core/inc/UndoTable.hxx b/sw/source/core/inc/UndoTable.hxx
index 6591b7e5e6cc..90cb9c945f4a 100644
--- a/sw/source/core/inc/UndoTable.hxx
+++ b/sw/source/core/inc/UndoTable.hxx
@@ -43,6 +43,14 @@ class SwStartNode;
class SwTableNode;
class SwTableAutoFormat;
class SwTableSortBoxes;
+class SwContentNode;
+class SwCursorShell;
+
+namespace sw {
+
+void NotifyTableCollapsedParagraph(const SwContentNode* pNode, SwCursorShell *const pShell);
+
+}
class SwUndoInsTable final : public SwUndo
{
diff --git a/sw/source/core/inc/bookmark.hxx b/sw/source/core/inc/bookmark.hxx
index ed7d5ad82180..334d13c2d663 100644
--- a/sw/source/core/inc/bookmark.hxx
+++ b/sw/source/core/inc/bookmark.hxx
@@ -46,16 +46,16 @@ namespace sw::mark {
{
public:
//getters
- virtual SwPosition& GetMarkPos() const override
+ SwPosition& GetMarkPos() const override
{ return *m_pPos1; }
- virtual const OUString& GetName() const override
+ const OUString& GetName() const override
{ return m_aName; }
- virtual SwPosition& GetOtherMarkPos() const override
+ SwPosition& GetOtherMarkPos() const override
{
OSL_PRECOND(IsExpanded(), "<SwPosition::GetOtherMarkPos(..)> - I have no other Pos set." );
return *m_pPos2;
}
- virtual SwPosition& GetMarkStart() const override
+ SwPosition& GetMarkStart() const override
{
if( !IsExpanded() ) return GetMarkPos( );
if ( GetMarkPos( ) < GetOtherMarkPos( ) )
@@ -63,7 +63,7 @@ namespace sw::mark {
else
return GetOtherMarkPos( );
}
- virtual SwPosition& GetMarkEnd() const override
+ SwPosition& GetMarkEnd() const override
{
if( !IsExpanded() ) return GetMarkPos();
if ( GetMarkPos( ) >= GetOtherMarkPos( ) )
@@ -72,8 +72,8 @@ namespace sw::mark {
return GetOtherMarkPos( );
}
- virtual bool IsCoveringPosition(const SwPosition& rPos) const override;
- virtual bool IsExpanded() const override
+ bool IsCoveringPosition(const SwPosition& rPos) const override;
+ bool IsExpanded() const override
{ return static_cast< bool >(m_pPos2); }
void SetName(const OUString& rName)
@@ -85,8 +85,8 @@ namespace sw::mark {
virtual auto InvalidateFrames() -> void;
- virtual OUString ToString( ) const override;
- virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
+ OUString ToString( ) const override;
+ void dumpAsXml(xmlTextWriterPtr pWriter) const override;
void Swap()
{
@@ -98,7 +98,7 @@ namespace sw::mark {
{
}
- virtual ~MarkBase() override;
+ ~MarkBase() override;
const css::uno::WeakReference< css::text::XTextContent> & GetXBookmark() const
{ return m_wXBookmark; }
@@ -107,7 +107,7 @@ namespace sw::mark {
protected:
// SwClient
- virtual void SwClientNotify(const SwModify&, const SfxHint&) override;
+ void SwClientNotify(const SwModify&, const SfxHint&) override;
MarkBase(const SwPaM& rPaM, const OUString& rName);
std::unique_ptr<SwPosition> m_pPos1;
@@ -146,7 +146,7 @@ namespace sw::mark {
void SetRefObject( SwServerObject* pObj );
virtual void DeregisterFromDoc(SwDoc& rDoc);
- virtual ~DdeBookmark() override;
+ ~DdeBookmark() override;
private:
tools::SvRef<SwServerObject> m_aRefObj;
@@ -161,33 +161,36 @@ namespace sw::mark {
Bookmark(const SwPaM& rPaM,
const vcl::KeyCode& rCode,
const OUString& rName);
- virtual void InitDoc(SwDoc& io_Doc, sw::mark::InsertMode eMode, SwPosition const* pSepPos) override;
- virtual void DeregisterFromDoc(SwDoc& io_rDoc) override;
+ ~Bookmark();
- virtual auto InvalidateFrames() -> void override;
+ void InitDoc(SwDoc& io_Doc, sw::mark::InsertMode eMode, SwPosition const* pSepPos) override;
- virtual const OUString& GetShortName() const override
+ void DeregisterFromDoc(SwDoc& io_rDoc) override;
+
+ auto InvalidateFrames() -> void override;
+
+ const OUString& GetShortName() const override
{ return m_sShortName; }
- virtual const vcl::KeyCode& GetKeyCode() const override
+ const vcl::KeyCode& GetKeyCode() const override
{ return m_aCode; }
- virtual void SetShortName(const OUString& rShortName) override
+ void SetShortName(const OUString& rShortName) override
{ m_sShortName = rShortName; }
- virtual void SetKeyCode(const vcl::KeyCode& rCode) override
+ void SetKeyCode(const vcl::KeyCode& rCode) override
{ m_aCode = rCode; }
- virtual bool IsHidden() const override
+ bool IsHidden() const override
{ return m_bHidden; }
- virtual const OUString& GetHideCondition() const override
+ const OUString& GetHideCondition() const override
{ return m_sHideCondition; }
- virtual void Hide(bool rHide) override;
- virtual void SetHideCondition(const OUString& rHideCondition) override;
+ void Hide(bool rHide) override;
+ void SetHideCondition(const OUString& rHideCondition) override;
// ::sfx2::Metadatable
- virtual ::sfx2::IXmlIdRegistry& GetRegistry() override;
- virtual bool IsInClipboard() const override;
- virtual bool IsInUndo() const override;
- virtual bool IsInContent() const override;
- virtual css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override;
+ ::sfx2::IXmlIdRegistry& GetRegistry() override;
+ bool IsInClipboard() const override;
+ bool IsInUndo() const override;
+ bool IsInContent() const override;
+ css::uno::Reference< css::rdf::XMetadatable > MakeUnoObject() override;
private:
vcl::KeyCode m_aCode;
@@ -203,20 +206,20 @@ namespace sw::mark {
public:
Fieldmark(const SwPaM& rPaM);
- virtual OUString GetFieldname() const override
+ OUString GetFieldname() const override
{ return m_aFieldname; }
- virtual OUString GetFieldHelptext() const override
+ OUString GetFieldHelptext() const override
{ return m_aFieldHelptext; }
- virtual IFieldmark::parameter_map_t* GetParameters() override
+ IFieldmark::parameter_map_t* GetParameters() override
{ return &m_vParams; }
- virtual const IFieldmark::parameter_map_t* GetParameters() const override
+ const IFieldmark::parameter_map_t* GetParameters() const override
{ return &m_vParams; }
- virtual void SetFieldname(const OUString& aFieldname) override
+ void SetFieldname(const OUString& aFieldname) override
{ m_aFieldname = aFieldname; }
- virtual void SetFieldHelptext(const OUString& aFieldHelptext) override
+ void SetFieldHelptext(const OUString& aFieldHelptext) override
{ m_aFieldHelptext = aFieldHelptext; }
virtual void ReleaseDoc(SwDoc&) = 0;
@@ -224,9 +227,9 @@ namespace sw::mark {
void SetMarkStartPos( const SwPosition& rNewStartPos );
void SetMarkEndPos( const SwPosition& rNewEndPos );
- virtual void Invalidate() override;
- virtual OUString ToString() const override;
- virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
+ void Invalidate() override;
+ OUString ToString() const override;
+ void dumpAsXml(xmlTextWriterPtr pWriter) const override;
private:
OUString m_aFieldname;
@@ -239,8 +242,15 @@ namespace sw::mark {
{
public:
TextFieldmark(const SwPaM& rPaM, const OUString& rName);
- virtual void InitDoc(SwDoc& io_rDoc, sw::mark::InsertMode eMode, SwPosition const* pSepPos) override;
- virtual void ReleaseDoc(SwDoc& rDoc) override;
+ ~TextFieldmark();
+ void InitDoc(SwDoc& io_rDoc, sw::mark::InsertMode eMode, SwPosition const* pSepPos) override;
+ void ReleaseDoc(SwDoc& rDoc) override;
+
+ OUString GetContent() const override;
+ void ReplaceContent(const OUString& sNewContent) override;
+
+ private:
+ sw::DocumentContentOperationsManager* m_pDocumentContentOperationsManager;
};
// Non text fieldmarks have no content between the start and end marks.
@@ -249,8 +259,8 @@ namespace sw::mark {
{
public:
NonTextFieldmark(const SwPaM& rPaM);
- virtual void InitDoc(SwDoc& io_rDoc, sw::mark::InsertMode eMode, SwPosition const* pSepPos) override;
- virtual void ReleaseDoc(SwDoc& rDoc) override;
+ void InitDoc(SwDoc& io_rDoc, sw::mark::InsertMode eMode, SwPosition const* pSepPos) override;
+ void ReleaseDoc(SwDoc& rDoc) override;
};
/// Fieldmark representing a checkbox form field.
@@ -259,9 +269,11 @@ namespace sw::mark {
, public NonTextFieldmark
{
public:
- CheckboxFieldmark(const SwPaM& rPaM);
+ CheckboxFieldmark(const SwPaM& rPaM, const OUString& rName);
bool IsChecked() const override;
void SetChecked(bool checked) override;
+ OUString GetContent() const override;
+ void ReplaceContent(const OUString& sNewContent) override;
};
/// Fieldmark with a drop down button (e.g. this button opens the date picker for a date field)
@@ -270,10 +282,11 @@ namespace sw::mark {
{
public:
FieldmarkWithDropDownButton(const SwPaM& rPaM);
- virtual ~FieldmarkWithDropDownButton() override;
+ ~FieldmarkWithDropDownButton() override;
virtual void ShowButton(SwEditWin* pEditWin) = 0;
virtual void RemoveButton();
+ virtual void LaunchPopup();
protected:
VclPtr<FormFieldButton> m_pButton;
@@ -281,14 +294,21 @@ namespace sw::mark {
/// Fieldmark representing a drop-down form field.
class DropDownFieldmark final
- : public FieldmarkWithDropDownButton
+ : virtual public IDropdownFieldmark
+ , public FieldmarkWithDropDownButton
{
public:
- DropDownFieldmark(const SwPaM& rPaM);
- virtual ~DropDownFieldmark() override;
-
- virtual void ShowButton(SwEditWin* pEditWin) override;
- virtual void RemoveButton() override;
+ DropDownFieldmark(const SwPaM& rPaM, const OUString& rName);
+ ~DropDownFieldmark() override;
+
+ void ShowButton(SwEditWin* pEditWin) override;
+ void RemoveButton() override;
+ OUString GetContent(sal_Int32* pIndex) const override;
+ OUString GetContent() const override;
+ void AddContent(const OUString& rText, sal_Int32* pIndex = nullptr) override;
+ void DelContent(sal_Int32 nDelIndex = -1) override;
+ void ReplaceContent(const OUString* pText, sal_Int32* pIndex) override;
+ void ReplaceContent(const OUString& sNewContent) override;
// This method should be called only by the portion so we can now the portion's painting area
void SetPortionPaintArea(const SwRect& rPortionPaintArea);
@@ -307,22 +327,22 @@ namespace sw::mark {
{
public:
DateFieldmark(const SwPaM& rPaM);
- virtual ~DateFieldmark() override;
+ ~DateFieldmark() override;
- virtual void InitDoc(SwDoc& io_rDoc, sw::mark::InsertMode eMode, SwPosition const* pSepPos) override;
- virtual void ReleaseDoc(SwDoc& rDoc) override;
+ void InitDoc(SwDoc& io_rDoc, sw::mark::InsertMode eMode, SwPosition const* pSepPos) override;
+ void ReleaseDoc(SwDoc& rDoc) override;
- virtual void ShowButton(SwEditWin* pEditWin) override;
+ void ShowButton(SwEditWin* pEditWin) override;
void SetPortionPaintAreaStart(const SwRect& rPortionPaintArea);
void SetPortionPaintAreaEnd(const SwRect& rPortionPaintArea);
- virtual OUString GetContent() const override;
- virtual void ReplaceContent(const OUString& sNewContent) override;
+ OUString GetContent() const override;
+ void ReplaceContent(const OUString& sNewContent) override;
- virtual std::pair<bool, double> GetCurrentDate() const override;
- virtual void SetCurrentDate(double fDate) override;
- virtual OUString GetDateInStandardDateFormat(double fDate) const override;
+ std::pair<bool, double> GetCurrentDate() const override;
+ void SetCurrentDate(double fDate) override;
+ OUString GetDateInStandardDateFormat(double fDate) const override;
private:
OUString GetDateInCurrentDateFormat(double fDate) const;
@@ -336,7 +356,7 @@ namespace sw::mark {
};
/// return position of the CH_TXT_ATR_FIELDSEP for rMark
- SwPosition FindFieldSep(IFieldmark const& rMark);
+ SW_DLLPUBLIC SwPosition FindFieldSep(IFieldmark const& rMark);
/// check if rPaM is valid range of new fieldmark
bool IsFieldmarkOverlap(SwPaM const& rPaM);
diff --git a/sw/source/core/inc/contentcontrolbutton.hxx b/sw/source/core/inc/contentcontrolbutton.hxx
index a921680ed7d4..cd63bddd4e69 100644
--- a/sw/source/core/inc/contentcontrolbutton.hxx
+++ b/sw/source/core/inc/contentcontrolbutton.hxx
@@ -29,6 +29,8 @@ public:
virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
DECL_LINK(PopupModeEndHdl, weld::Popover&, void);
+ /// Shared MouseButtonDown() and KeyInput() code.
+ void StartPopup();
virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
virtual WindowHitTest ImplHitTest(const Point& rFramePos) override;
diff --git a/sw/source/core/inc/dflyobj.hxx b/sw/source/core/inc/dflyobj.hxx
index 682a77e84aef..5307cdbf5ad0 100644
--- a/sw/source/core/inc/dflyobj.hxx
+++ b/sw/source/core/inc/dflyobj.hxx
@@ -139,6 +139,7 @@ public:
virtual bool HasLimitedRotation() const override;
virtual bool IsTextBox() const override;
+ void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};
#endif
diff --git a/sw/source/core/inc/layact.hxx b/sw/source/core/inc/layact.hxx
index a0f955aa4099..d32951964dd4 100644
--- a/sw/source/core/inc/layact.hxx
+++ b/sw/source/core/inc/layact.hxx
@@ -185,6 +185,20 @@ public:
};
+enum class IdleJobType
+{
+ ONLINE_SPELLING,
+ AUTOCOMPLETE_WORDS,
+ WORD_COUNT,
+ SMART_TAGS
+};
+
+enum class IdleJobArea
+{
+ ALL,
+ VISIBLE
+};
+
class SwLayIdle
{
SwRootFrame *m_pRoot;
@@ -198,10 +212,10 @@ class SwLayIdle
void ShowIdle( Color eName );
#endif
- enum IdleJobType{ ONLINE_SPELLING, AUTOCOMPLETE_WORDS, WORD_COUNT, SMART_TAGS };
bool DoIdleJob_( const SwContentFrame*, IdleJobType );
- bool DoIdleJob( IdleJobType, bool bVisAreaOnly );
+ bool DoIdleJob(IdleJobType eJobType, IdleJobArea eJobArea);
+ static bool isJobEnabled(IdleJobType eJob, const SwViewShell* pViewShell);
public:
SwLayIdle( SwRootFrame *pRt, SwViewShellImp *pImp );
~SwLayIdle();
diff --git a/sw/source/core/inc/rolbck.hxx b/sw/source/core/inc/rolbck.hxx
index 75554884341e..fb03e76fa8ea 100644
--- a/sw/source/core/inc/rolbck.hxx
+++ b/sw/source/core/inc/rolbck.hxx
@@ -160,7 +160,7 @@ class SwHistorySetRefMark final : public SwHistoryHint
public:
SwHistorySetRefMark( const SwTextRefMark* pTextHt, SwNodeOffset nNode );
virtual void SetInDoc( SwDoc* pDoc, bool bTmpSet ) override;
-
+ const OUString& GetRefName() {return m_RefName;}
};
class SwHistorySetTOXMark final : public SwHistoryHint
diff --git a/sw/source/core/inc/sectfrm.hxx b/sw/source/core/inc/sectfrm.hxx
index 09c742f8da79..e08a9b0a7137 100644
--- a/sw/source/core/inc/sectfrm.hxx
+++ b/sw/source/core/inc/sectfrm.hxx
@@ -109,7 +109,7 @@ public:
* Splits the SectionFrame surrounding the pFrame up in two parts:
* pFrame and the start of the 2nd part
*/
- bool SplitSect( SwFrame* pFrame, bool bApres );
+ SwSectionFrame* SplitSect( SwFrame* pFrameStartAfter, SwFrame* pFramePutAfter );
void DelEmpty( bool bRemove ); // Like Cut(), except for that Follow chaining is maintained
SwFootnoteContFrame* ContainsFootnoteCont( const SwFootnoteContFrame* pCont = nullptr ) const;
bool Growable() const;
diff --git a/sw/source/core/inc/unocontentcontrol.hxx b/sw/source/core/inc/unocontentcontrol.hxx
index 631ccdaf02d3..fef07498abe8 100644
--- a/sw/source/core/inc/unocontentcontrol.hxx
+++ b/sw/source/core/inc/unocontentcontrol.hxx
@@ -34,11 +34,13 @@
#include <cppuhelper/implbase.hxx>
#include <unobaseclass.hxx>
+#include <unocoll.hxx>
typedef std::deque<css::uno::Reference<css::text::XTextRange>> TextRangeList_t;
class SwPaM;
class SwTextNode;
+class SwFormatContentControl;
class SwContentControl;
/**
@@ -155,4 +157,22 @@ public:
const css::uno::Reference<css::beans::XVetoableChangeListener>& xListener) override;
};
+/// UNO wrapper around SwContentControlManager.
+class SwXContentControls final : public cppu::WeakImplHelper<css::container::XIndexAccess>,
+ public SwUnoCollection
+{
+ ~SwXContentControls() override;
+
+public:
+ SwXContentControls(SwDoc* pDoc);
+
+ // XIndexAccess
+ sal_Int32 SAL_CALL getCount() override;
+ css::uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override;
+
+ // XElementAccess
+ css::uno::Type SAL_CALL getElementType() override;
+ sal_Bool SAL_CALL hasElements() override;
+};
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/unoport.hxx b/sw/source/core/inc/unoport.hxx
index 936bc01e0521..4c0098be8681 100644
--- a/sw/source/core/inc/unoport.hxx
+++ b/sw/source/core/inc/unoport.hxx
@@ -76,7 +76,8 @@ enum SwTextPortionType
PORTION_ANNOTATION,
PORTION_ANNOTATION_END,
PORTION_LINEBREAK,
- PORTION_CONTENT_CONTROL
+ PORTION_CONTENT_CONTROL,
+ PORTION_LIST_AUTOFMT
};
class SwXTextPortion : public cppu::WeakImplHelper
@@ -123,6 +124,10 @@ private:
bool m_bIsCollapsed;
+ /// Expose the paragraph's RES_PARATR_LIST_AUTOFMT, not the char props of the underlying (empty)
+ /// text.
+ bool m_bIsListAutoFormat;
+
void init(const SwUnoCursor* pPortionCursor);
protected:
diff --git a/sw/source/core/layout/anchoreddrawobject.cxx b/sw/source/core/layout/anchoreddrawobject.cxx
index 3e37961dffd6..6cc597ef9a64 100644
--- a/sw/source/core/layout/anchoreddrawobject.cxx
+++ b/sw/source/core/layout/anchoreddrawobject.cxx
@@ -30,6 +30,7 @@
#include <tools/fract.hxx>
#include <DocumentSettingManager.hxx>
#include <IDocumentState.hxx>
+#include <IDocumentLayoutAccess.hxx>
#include <txtfly.hxx>
#include <viewimp.hxx>
#include <textboxhelper.hxx>
@@ -512,6 +513,13 @@ void SwAnchoredDrawObject::SetDrawObjAnchor()
DrawObj()->SetAnchorPos( aNewAnchorPos );
// correct object position, caused by setting new anchor position
DrawObj()->Move( aMove );
+ // Sync textbox if it wasn't done at move
+ if ( SwTextBoxHelper::isTextBox(&GetFrameFormat(), RES_DRAWFRMFMT) && GetFrameFormat().GetDoc() &&
+ GetFrameFormat().GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell() &&
+ GetFrameFormat().GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor())
+ {
+ SwTextBoxHelper::changeAnchor(&GetFrameFormat(), GetFrameFormat().FindRealSdrObject());
+ }
// --> #i70122# - missing invalidation
InvalidateObjRectWithSpaces();
}
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index fa246799d547..1fcf14c9f063 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -1112,7 +1112,8 @@ bool SwFormatCol::QueryValue( uno::Any& rVal, sal_uInt8 nMemberId ) const
}
}
uno::Any aVal;
- aVal <<= o3tl::narrowing<sal_Int32>(GetLineWidth());
+ aVal <<= o3tl::narrowing<sal_Int32>(
+ o3tl::convert(GetLineWidth(), o3tl::Length::twip, o3tl::Length::mm100));
xProps->setPropertyValue(UNO_NAME_SEPARATOR_LINE_WIDTH, aVal);
aVal <<= GetLineColor();
xProps->setPropertyValue(UNO_NAME_SEPARATOR_LINE_COLOR, aVal);
@@ -1202,6 +1203,7 @@ bool SwFormatCol::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId )
{
xProps->getPropertyValue(UNO_NAME_IS_AUTOMATIC) >>= m_bOrtho;
xProps->getPropertyValue(UNO_NAME_SEPARATOR_LINE_WIDTH) >>= m_nLineWidth;
+ m_nLineWidth = o3tl::toTwips(m_nLineWidth, o3tl::Length::mm100);
xProps->getPropertyValue(UNO_NAME_SEPARATOR_LINE_COLOR) >>= m_aLineColor;
if (sal_Int32 nHeight;
xProps->getPropertyValue(UNO_NAME_SEPARATOR_LINE_RELATIVE_HEIGHT) >>= nHeight)
diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx
index c53512b2763a..3dde726ec60f 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -1738,6 +1738,11 @@ SwTwips SwFlowFrame::GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid() cons
{
SwTwips nUpperSpaceAmountConsideredForPrevFrameAndPageGrid = 0;
+ if (!m_rThis.GetUpper() || !m_rThis.GetUpper()->GetFormat())
+ {
+ return nUpperSpaceAmountConsideredForPrevFrameAndPageGrid;
+ }
+
if ( !m_rThis.GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::USE_FORMER_OBJECT_POS) )
{
nUpperSpaceAmountConsideredForPrevFrameAndPageGrid =
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index 357f1f3db1a9..c1bb52fc4112 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1727,6 +1727,9 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
nIndex = pNode->EndOfSectionIndex();
else
{
+ if (pActualSection)
+ pActualSection->SetLastPos(pPrv);
+
pFrame = pNode->MakeFrame( pLay );
pActualSection.reset( new SwActualSection( pActualSection.release(),
static_cast<SwSectionFrame*>(pFrame), pNode ) );
@@ -1881,33 +1884,30 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
}
// new section frame
- pFrame = pActualSection->GetSectionNode()->MakeFrame( pLay );
- pFrame->InsertBehind( pLay, pPrv );
- static_cast<SwSectionFrame*>(pFrame)->Init();
-
- // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
- // for setting position at newly inserted frame
- lcl_SetPos( *pFrame, *pLay );
-
- SwSectionFrame* pOuterSectionFrame = pActualSection->GetSectionFrame();
-
- // a follow has to be appended to the new section frame
- SwSectionFrame* pFollow = pOuterSectionFrame ? pOuterSectionFrame->GetFollow() : nullptr;
- if ( pFollow )
+ if (SwSectionFrame* pOuterSectionFrame = pActualSection->GetSectionFrame())
{
- pOuterSectionFrame->SetFollow( nullptr );
- pOuterSectionFrame->InvalidateSize();
- static_cast<SwSectionFrame*>(pFrame)->SetFollow( pFollow );
- }
+ // Splitting moves the trailing content to the next frame
+ pFrame = pOuterSectionFrame->SplitSect(pActualSection->GetLastPos(), pPrv);
- // We don't want to leave empty parts back.
- if (pOuterSectionFrame &&
- ! pOuterSectionFrame->IsColLocked() &&
- ! pOuterSectionFrame->ContainsContent() )
+ // We don't want to leave empty parts back.
+ if (! pOuterSectionFrame->IsColLocked() &&
+ ! pOuterSectionFrame->ContainsContent() )
+ {
+ pOuterSectionFrame->DelEmpty( true );
+ SwFrame::DestroyFrame(pOuterSectionFrame);
+ }
+ }
+ else
{
- pOuterSectionFrame->DelEmpty( true );
- SwFrame::DestroyFrame(pOuterSectionFrame);
+ pFrame = pActualSection->GetSectionNode()->MakeFrame( pLay );
+ pFrame->InsertBehind( pLay, pPrv );
+ static_cast<SwSectionFrame*>(pFrame)->Init();
+
+ // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
+ // for setting position at newly inserted frame
+ lcl_SetPos( *pFrame, *pLay );
}
+
pActualSection->SetSectionFrame( static_cast<SwSectionFrame*>(pFrame) );
pLay = static_cast<SwLayoutFrame*>(pFrame);
@@ -2132,20 +2132,7 @@ void MakeFrames( SwDoc *pDoc, const SwNodeIndex &rSttIdx,
}
else
{
- bool bSplit;
SwFrame* pPrv = bApres ? pFrame : pFrame->GetPrev();
- // If the section frame is inserted into another one, it must be split.
- if( pSct && rSttIdx.GetNode().IsSectionNode() )
- {
- bSplit = pSct->SplitSect( pFrame, bApres );
- if( !bSplit && !bApres )
- {
- pUpper = pSct->GetUpper();
- pPrv = pSct->GetPrev();
- }
- }
- else
- bSplit = false;
::InsertCnt_( pUpper, pDoc, rSttIdx.GetIndex(), false,
nEndIdx, pPrv, eMode );
@@ -2158,10 +2145,6 @@ void MakeFrames( SwDoc *pDoc, const SwNodeIndex &rSttIdx,
AppendAllObjs( pTable, pUpper );
}
- // If nothing was added (e.g. a hidden section), the split must be reversed.
- if( bSplit && pSct && pSct->GetNext()
- && pSct->GetNext()->IsSctFrame() )
- pSct->MergeNext( static_cast<SwSectionFrame*>(pSct->GetNext()) );
if( pFrame->IsInFly() )
pFrame->FindFlyFrame()->Invalidate_();
if( pFrame->IsInTab() )
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index b2b246e5eb2f..4277b6e6c3a3 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -1963,13 +1963,13 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
{
switch ( eJob )
{
- case ONLINE_SPELLING :
+ case IdleJobType::ONLINE_SPELLING:
bProcess = pTextNode->IsWrongDirty(); break;
- case AUTOCOMPLETE_WORDS :
+ case IdleJobType::AUTOCOMPLETE_WORDS:
bProcess = pTextNode->IsAutoCompleteWordDirty(); break;
- case WORD_COUNT :
+ case IdleJobType::WORD_COUNT:
bProcess = pTextNode->IsWordCountDirty(); break;
- case SMART_TAGS :
+ case IdleJobType::SMART_TAGS:
bProcess = pTextNode->IsSmartTagDirty(); break;
}
if (bProcess)
@@ -2024,25 +2024,25 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
switch ( eJob )
{
- case ONLINE_SPELLING :
+ case IdleJobType::ONLINE_SPELLING:
{
SwRect aRepaint( const_cast<SwTextFrame*>(pTextFrame)->AutoSpell_(*pTextNode, nPos) );
// PENDING should stop idle spell checking
- m_bPageValid = m_bPageValid && (SwTextNode::WrongState::TODO != pTextNode->GetWrongDirty());
+ m_bPageValid = m_bPageValid && (sw::WrongState::TODO != pTextNode->GetWrongDirty());
if ( aRepaint.HasArea() )
m_pImp->GetShell()->InvalidateWindows( aRepaint );
if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
return true;
break;
}
- case AUTOCOMPLETE_WORDS :
+ case IdleJobType::AUTOCOMPLETE_WORDS:
const_cast<SwTextFrame*>(pTextFrame)->CollectAutoCmplWrds(*pTextNode, nPos);
// note: bPageValid remains true here even if the cursor
// position is skipped, so no PENDING state needed currently
if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
return true;
break;
- case WORD_COUNT :
+ case IdleJobType::WORD_COUNT:
{
const sal_Int32 nEnd = pTextNode->GetText().getLength();
SwDocStat aStat;
@@ -2051,7 +2051,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
return true;
break;
}
- case SMART_TAGS :
+ case IdleJobType::SMART_TAGS:
{
try {
const SwRect aRepaint( const_cast<SwTextFrame*>(pTextFrame)->SmartTagScan(*pTextNode) );
@@ -2096,40 +2096,52 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
return false;
}
-bool SwLayIdle::DoIdleJob( IdleJobType eJob, bool bVisAreaOnly )
+bool SwLayIdle::isJobEnabled(IdleJobType eJob, const SwViewShell* pViewShell)
{
- // Spellcheck all contents of the pages. Either only the
- // visible ones or all of them.
- const SwViewShell* pViewShell = m_pImp->GetShell();
- const SwViewOption* pViewOptions = pViewShell->GetViewOptions();
- const SwDoc* pDoc = pViewShell->GetDoc();
-
- switch ( eJob )
+ switch (eJob)
{
- case ONLINE_SPELLING :
- if( !pViewOptions->IsOnlineSpell() )
- return false;
- break;
- case AUTOCOMPLETE_WORDS :
- if( !SwViewOption::IsAutoCompleteWords() ||
- SwDoc::GetAutoCompleteWords().IsLockWordLstLocked())
- return false;
- break;
- case WORD_COUNT :
- if ( !pViewShell->getIDocumentStatistics().GetDocStat().bModified )
+ case IdleJobType::ONLINE_SPELLING:
+ {
+ const SwViewOption* pViewOptions = pViewShell->GetViewOptions();
+ return pViewOptions->IsOnlineSpell();
+ }
+
+ case IdleJobType::AUTOCOMPLETE_WORDS:
+ {
+ if (!SwViewOption::IsAutoCompleteWords() || SwDoc::GetAutoCompleteWords().IsLockWordLstLocked())
return false;
- break;
- case SMART_TAGS :
- if ( pDoc->GetDocShell()->IsHelpDocument() ||
- pDoc->isXForms() ||
- !SwSmartTagMgr::Get().IsSmartTagsEnabled() )
+ return true;
+ }
+
+ case IdleJobType::WORD_COUNT:
+ {
+ return pViewShell->getIDocumentStatistics().GetDocStat().bModified;
+ }
+
+ case IdleJobType::SMART_TAGS:
+ {
+ const SwDoc* pDoc = pViewShell->GetDoc();
+ if (!pDoc->GetDocShell()->IsHelpDocument() || pDoc->isXForms() || !SwSmartTagMgr::Get().IsSmartTagsEnabled())
return false;
- break;
- default: OSL_FAIL( "Unknown idle job type" );
+ return true;
+ }
}
+ return false;
+}
+
+bool SwLayIdle::DoIdleJob(IdleJobType eJob, IdleJobArea eJobArea)
+{
+ // Spellcheck all contents of the pages. Either only the
+ // visible ones or all of them.
+ const SwViewShell* pViewShell = m_pImp->GetShell();
+
+ // Check if job ius enabled and can run
+ if (!isJobEnabled(eJob, pViewShell))
+ return false;
+
SwPageFrame *pPage;
- if ( bVisAreaOnly )
+ if (eJobArea == IdleJobArea::VISIBLE)
pPage = m_pImp->GetFirstVisPage(pViewShell->GetOut());
else
pPage = static_cast<SwPageFrame*>(m_pRoot->Lower());
@@ -2140,15 +2152,15 @@ bool SwLayIdle::DoIdleJob( IdleJobType eJob, bool bVisAreaOnly )
while ( pPage )
{
m_bPageValid = true;
- const SwContentFrame *pCnt = pPage->ContainsContent();
- while( pCnt && pPage->IsAnLower( pCnt ) )
+ const SwContentFrame* pContentFrame = pPage->ContainsContent();
+ while (pContentFrame && pPage->IsAnLower(pContentFrame))
{
- if ( DoIdleJob_( pCnt, eJob ) )
+ if (DoIdleJob_(pContentFrame, eJob))
{
- SAL_INFO("sw.idle", "DoIdleJob " << eJob << " interrupted on page " << pPage->GetPhyPageNum());
+ SAL_INFO("sw.idle", "DoIdleJob " << sal_Int32(eJob) << " interrupted on page " << pPage->GetPhyPageNum());
return true;
}
- pCnt = pCnt->GetNextContentFrame();
+ pContentFrame = pContentFrame->GetNextContentFrame();
}
if ( pPage->GetSortedObjs() )
{
@@ -2165,7 +2177,7 @@ bool SwLayIdle::DoIdleJob( IdleJobType eJob, bool bVisAreaOnly )
{
if ( DoIdleJob_( pC, eJob ) )
{
- SAL_INFO("sw.idle", "DoIdleJob " << eJob << " interrupted on page " << pPage->GetPhyPageNum());
+ SAL_INFO("sw.idle", "DoIdleJob " << sal_Int32(eJob) << " interrupted on page " << pPage->GetPhyPageNum());
return true;
}
}
@@ -2177,19 +2189,29 @@ bool SwLayIdle::DoIdleJob( IdleJobType eJob, bool bVisAreaOnly )
if( m_bPageValid )
{
- switch ( eJob )
+ switch (eJob)
{
- case ONLINE_SPELLING : pPage->ValidateSpelling(); break;
- case AUTOCOMPLETE_WORDS : pPage->ValidateAutoCompleteWords(); break;
- case WORD_COUNT : pPage->ValidateWordCount(); break;
- case SMART_TAGS : pPage->ValidateSmartTags(); break;
+ case IdleJobType::ONLINE_SPELLING:
+ pPage->ValidateSpelling();
+ break;
+ case IdleJobType::AUTOCOMPLETE_WORDS:
+ pPage->ValidateAutoCompleteWords();
+ break;
+ case IdleJobType::WORD_COUNT:
+ pPage->ValidateWordCount();
+ break;
+ case IdleJobType::SMART_TAGS:
+ pPage->ValidateSmartTags();
+ break;
}
}
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
- if ( pPage && bVisAreaOnly &&
- !pPage->getFrameArea().Overlaps( m_pImp->GetShell()->VisArea()))
+ if (pPage && eJobArea == IdleJobArea::VISIBLE &&
+ !pPage->getFrameArea().Overlaps( m_pImp->GetShell()->VisArea()))
+ {
break;
+ }
}
return false;
}
@@ -2236,9 +2258,9 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp *pI ) :
// First, spellcheck the visible area. Only if there's nothing
// to do there, we trigger the IdleFormat.
- if ( !DoIdleJob( SMART_TAGS, true ) &&
- !DoIdleJob( ONLINE_SPELLING, true ) &&
- !DoIdleJob( AUTOCOMPLETE_WORDS, true ) )
+ if ( !DoIdleJob(IdleJobType::SMART_TAGS, IdleJobArea::VISIBLE) &&
+ !DoIdleJob(IdleJobType::ONLINE_SPELLING, IdleJobArea::VISIBLE) &&
+ !DoIdleJob(IdleJobType::AUTOCOMPLETE_WORDS, IdleJobArea::VISIBLE) )
{
// Format, then register repaint rectangles with the SwViewShell if necessary.
// This requires running artificial actions, so we don't get undesired
@@ -2275,16 +2297,7 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp *pI ) :
{
--rSh.mnStartAction;
- // When using tiled rendering, idle painting is disabled and paints are done
- // only later by tiled rendering. But paints call SwViewShellImp::DeletePaintRegion()
- // to reset this HasPaintRegion(), and if it's done too late,
- // SwTiledRenderingTest::testTablePaintInvalidate() will end up in an infinite
- // loop, because the idle layout will call this code repeatedly, because there
- // will be no idle paints to reset HasPaintRegion().
- // This code dates back to the initial commit, and I find its purpose unclear,
- // so I'm still leaving it here in case it turns out it serves a purpose.
- static const bool blockOnRepaints = true;
- if (!blockOnRepaints && rSh.Imp()->HasPaintRegion())
+ if ( rSh.Imp()->HasPaintRegion() )
bActions = true;
else
{
@@ -2325,6 +2338,7 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp *pI ) :
bool bUnlock = false;
if ( pViewImp->HasPaintRegion() )
{
+ SAL_INFO("sw.idle", "Disappointing full document invalidation");
pViewImp->DeletePaintRegion();
// Cause a repaint with virtual device.
@@ -2359,10 +2373,10 @@ SwLayIdle::SwLayIdle( SwRootFrame *pRt, SwViewShellImp *pI ) :
if (!bInterrupt)
{
- if ( !DoIdleJob( WORD_COUNT, false ) )
- if ( !DoIdleJob( SMART_TAGS, false ) )
- if ( !DoIdleJob( ONLINE_SPELLING, false ) )
- DoIdleJob( AUTOCOMPLETE_WORDS, false );
+ if (!DoIdleJob(IdleJobType::WORD_COUNT, IdleJobArea::ALL))
+ if (!DoIdleJob(IdleJobType::SMART_TAGS, IdleJobArea::ALL))
+ if (!DoIdleJob(IdleJobType::ONLINE_SPELLING, IdleJobArea::ALL))
+ DoIdleJob(IdleJobType::AUTOCOMPLETE_WORDS, IdleJobArea::ALL);
}
bool bInValid = false;
diff --git a/sw/source/core/layout/layhelp.hxx b/sw/source/core/layout/layhelp.hxx
index 5df151ae7e61..d8a3da0519a5 100644
--- a/sw/source/core/layout/layhelp.hxx
+++ b/sw/source/core/layout/layhelp.hxx
@@ -85,6 +85,7 @@ class SwActualSection
{
SwActualSection *m_pUpper;
SwSectionFrame *m_pSectFrame;
+ SwFrame* m_pLastPos = nullptr; // Split it *after* this child frame
SwSectionNode *m_pSectNode;
public:
SwActualSection( SwActualSection *pUpper,
@@ -96,6 +97,8 @@ public:
SwSectionNode *GetSectionNode() { return m_pSectNode;}
void SetUpper(SwActualSection *p) { m_pUpper = p; }
SwActualSection *GetUpper() { return m_pUpper; }
+ void SetLastPos(SwFrame* p) { m_pLastPos = p; }
+ SwFrame* GetLastPos() const { return m_pLastPos; }
};
/// Helps during the InsertCnt_ function to create new pages.
diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx
index 34e86e51808b..1163e048e64b 100644
--- a/sw/source/core/layout/sectfrm.cxx
+++ b/sw/source/core/layout/sectfrm.cxx
@@ -507,50 +507,67 @@ void SwSectionFrame::MergeNext( SwSectionFrame* pNxt )
}
/**
-|* Divides a SectionFrame into two parts. The second one starts with the
-|* passed frame.
+|* Divides a SectionFrame into two parts. The content of the second one
+|* starts after pFrameStartAfter; the created second section frame itself
+|* is put after pFramePutAfter.
+|* If pFrameStartAfter is nullptr, the split happens at the start.
|* This is required when inserting an inner section, because the MoveFwd
|* cannot have the desired effect within a frame or a table cell.
+|* Splitting at the start/end makes sense, because the empty frame would
+|* be removed after the InsertCnt_ finished.
|*/
-bool SwSectionFrame::SplitSect( SwFrame* pFrame, bool bApres )
+SwSectionFrame* SwSectionFrame::SplitSect( SwFrame* pFrameStartAfter, SwFrame* pFramePutAfter )
{
- assert(pFrame && "SplitSect: Why?");
- SwFrame* pOther = bApres ? pFrame->FindNext() : pFrame->FindPrev();
- if( !pOther )
- return false;
- SwSectionFrame* pSect = pOther->FindSctFrame();
- if( pSect != this )
- return false;
+ assert(!pFrameStartAfter || IsAnLower(pFrameStartAfter));
+ SwFrame* pSav;
+ if (pFrameStartAfter)
+ {
+ pSav = pFrameStartAfter->FindNext();
+ // If pFrameStartAfter is a complex object like table, and it has no next,
+ // its FindNext may return its own last subframe. In this case, assume that
+ // we are at the end.
+ if (pSav && pFrameStartAfter->IsLayoutFrame())
+ if (static_cast<SwLayoutFrame*>(pFrameStartAfter)->IsAnLower(pSav))
+ pSav = nullptr;
+ }
+ else
+ {
+ pSav = ContainsAny();
+ }
+ if (pSav && !IsAnLower(pSav))
+ pSav = nullptr; // we are at the very end
+
// Put the content aside
- SwFrame* pSav = ::SaveContent( this, bApres ? pOther : pFrame );
- OSL_ENSURE( pSav, "SplitSect: What's on?" );
- if( pSav ) // be robust
- { // Create a new SctFrame, not as a Follower/master
- SwSectionFrame* pNew = new SwSectionFrame( *pSect->GetSection(), pSect );
- pNew->InsertBehind( pSect->GetUpper(), pSect );
- pNew->Init();
- SwRectFnSet aRectFnSet(this);
- aRectFnSet.MakePos( *pNew, nullptr, pSect, true );
- // OD 25.03.2003 #108339# - restore content:
- // determine layout frame for restoring content after the initialization
- // of the section frame. In the section initialization the columns are
- // created.
- {
- SwLayoutFrame* pLay = pNew;
- // Search for last layout frame, e.g. for columned sections.
- while( pLay->Lower() && pLay->Lower()->IsLayoutFrame() )
- pLay = static_cast<SwLayoutFrame*>(pLay->Lower());
- ::RestoreContent( pSav, pLay, nullptr );
- }
- InvalidateSize_();
- if( HasFollow() )
- {
- pNew->SetFollow( GetFollow() );
- SetFollow( nullptr );
- }
- return true;
+ if (pSav)
+ pSav = ::SaveContent( this, pSav );
+
+ // Create a new SctFrame, not as a Follower/master
+ if (!pFramePutAfter)
+ pFramePutAfter = this;
+ SwSectionFrame* pNew = new SwSectionFrame( *GetSection(), this );
+ pNew->InsertBehind( pFramePutAfter->GetUpper(), pFramePutAfter );
+ pNew->Init();
+ SwRectFnSet aRectFnSet(this);
+ aRectFnSet.MakePos( *pNew, nullptr, pFramePutAfter, true );
+ // OD 25.03.2003 #108339# - restore content:
+ // determine layout frame for restoring content after the initialization
+ // of the section frame. In the section initialization the columns are
+ // created.
+ if (pSav)
+ {
+ SwLayoutFrame* pLay = pNew;
+ // Search for last layout frame, e.g. for columned sections.
+ while( pLay->Lower() && pLay->Lower()->IsLayoutFrame() )
+ pLay = static_cast<SwLayoutFrame*>(pLay->Lower());
+ ::RestoreContent( pSav, pLay, nullptr );
+ }
+ InvalidateSize_();
+ if( HasFollow() )
+ {
+ pNew->SetFollow( GetFollow() );
+ SetFollow( nullptr );
}
- return false;
+ return pNew;
}
/**
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 43bd9a7037a1..65b9383543eb 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -1222,13 +1222,14 @@ void SwContentFrame::Cut()
// find if there are pages without content following pPage
// and if so request a call to CheckPageDescs()
SwPageFrame const* pNext(pPage);
- if (pRoot->GetCurrShell()->Imp()->IsAction())
+ SwViewShell *pSh = pRoot->GetCurrShell();
+ if (pSh && pSh->Imp()->IsAction())
{
while ((pNext = static_cast<SwPageFrame const*>(pNext->GetNext())))
{
if (!sw::IsPageFrameEmpty(*pNext) && !pNext->IsFootnotePage())
{
- pRoot->GetCurrShell()->Imp()->GetLayAction().SetCheckPageNum(pPage->GetPhyPageNum());
+ pSh->Imp()->GetLayAction().SetCheckPageNum(pPage->GetPhyPageNum());
break;
}
}
diff --git a/sw/source/core/model/ThemeColorChanger.cxx b/sw/source/core/model/ThemeColorChanger.cxx
new file mode 100644
index 000000000000..ee0eb9aa37de
--- /dev/null
+++ b/sw/source/core/model/ThemeColorChanger.cxx
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <ThemeColorChanger.hxx>
+#include <ModelTraverser.hxx>
+#include <txtftn.hxx>
+#include <txtfrm.hxx>
+#include <docstyle.hxx>
+#include <drawdoc.hxx>
+#include <ndnotxt.hxx>
+#include <ndtxt.hxx>
+#include <format.hxx>
+#include <charatr.hxx>
+#include <pam.hxx>
+#include <DocumentContentOperationsManager.hxx>
+#include <IDocumentUndoRedo.hxx>
+
+#include <sal/config.h>
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <docmodel/uno/UnoThemeColor.hxx>
+#include <editeng/unoprnms.hxx>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+namespace sw
+{
+namespace
+{
+/** Handler for ModelTraverser that recalculates and updates the theme colors.
+ *
+ * It checks all the SdrObjects and updates fill, line and text theme colors.
+ * For writer nodes it checks all the text nodes and updates the direct
+ * formatting in all hints.
+ *
+ */
+class ThemeColorHandler : public sw::ModelTraverseHandler
+{
+ SwDoc& mrDocument;
+ svx::ColorSet const& mrColorSet;
+
+public:
+ ThemeColorHandler(SwDoc& rDocument, svx::ColorSet const& rColorSet)
+ : mrDocument(rDocument)
+ , mrColorSet(rColorSet)
+ {
+ }
+
+ /// Updates hints for a text node
+ void updateHints(SwTextNode* pTextNode)
+ {
+ if (!pTextNode->HasHints())
+ return;
+
+ SwpHints& rHints = pTextNode->GetSwpHints();
+ for (size_t i = 0; i < rHints.Count(); ++i)
+ {
+ const SwTextAttr* pTextAttr = rHints.Get(i);
+ if (pTextAttr->Which() == RES_TXTATR_AUTOFMT)
+ {
+ SwFormatAutoFormat const& rAutoFormatPool(pTextAttr->GetAutoFormat());
+ std::shared_ptr<SfxItemSet> pStyleHandle(rAutoFormatPool.GetStyleHandle());
+ if (const SvxColorItem* pItem = pStyleHandle->GetItemIfSet(RES_CHRATR_COLOR))
+ {
+ model::ThemeColor const& rThemeColor = pItem->GetThemeColor();
+ auto eThemeType = rThemeColor.getType();
+ if (eThemeType != model::ThemeColorType::Unknown)
+ {
+ Color aNewColor = mrColorSet.resolveColor(rThemeColor);
+ auto pNew = pItem->Clone();
+ pNew->SetValue(aNewColor);
+
+ SwPaM aPam(*pTextNode, pTextAttr->GetStart(), *pTextNode,
+ pTextAttr->GetAnyEnd());
+ mrDocument.GetDocumentContentOperationsManager().InsertPoolItem(
+ aPam, *pNew, SetAttrMode::APICALL | SetAttrMode::NO_CURSOR_CHANGE);
+ }
+ }
+ }
+ }
+ }
+
+ void handleNode(SwNode* pNode) override
+ {
+ if (!pNode->IsTextNode())
+ return;
+
+ updateHints(pNode->GetTextNode());
+ }
+
+ /// Updates text portion property colors
+ void updateTextPortionColorSet(const uno::Reference<beans::XPropertySet>& xPortion)
+ {
+ if (!xPortion->getPropertySetInfo()->hasPropertyByName(
+ UNO_NAME_EDIT_CHAR_COLOR_THEME_REFERENCE))
+ return;
+
+ uno::Reference<util::XThemeColor> xThemeColor;
+ xPortion->getPropertyValue(UNO_NAME_EDIT_CHAR_COLOR_THEME_REFERENCE) >>= xThemeColor;
+ if (!xThemeColor.is())
+ return;
+
+ model::ThemeColor aThemeColor;
+ model::theme::setFromXThemeColor(aThemeColor, xThemeColor);
+
+ if (aThemeColor.getType() == model::ThemeColorType::Unknown)
+ return;
+
+ Color aColor = mrColorSet.resolveColor(aThemeColor);
+ xPortion->setPropertyValue(UNO_NAME_EDIT_CHAR_COLOR,
+ uno::Any(static_cast<sal_Int32>(aColor)));
+ }
+
+ /// Updates the fill property colors
+ void updateFillColorSet(const uno::Reference<beans::XPropertySet>& xShape)
+ {
+ if (!xShape->getPropertySetInfo()->hasPropertyByName(UNO_NAME_FILLCOLOR_THEME_REFERENCE))
+ return;
+
+ uno::Reference<util::XThemeColor> xThemeColor;
+ xShape->getPropertyValue(UNO_NAME_FILLCOLOR_THEME_REFERENCE) >>= xThemeColor;
+ if (!xThemeColor.is())
+ return;
+
+ model::ThemeColor aThemeColor;
+ model::theme::setFromXThemeColor(aThemeColor, xThemeColor);
+
+ if (aThemeColor.getType() == model::ThemeColorType::Unknown)
+ return;
+
+ Color aColor = mrColorSet.resolveColor(aThemeColor);
+ xShape->setPropertyValue(UNO_NAME_FILLCOLOR, uno::Any(static_cast<sal_Int32>(aColor)));
+ }
+
+ /// Updates the line property colors
+ void updateLineColorSet(const uno::Reference<beans::XPropertySet>& xShape)
+ {
+ if (!xShape->getPropertySetInfo()->hasPropertyByName(UNO_NAME_LINECOLOR_THEME_REFERENCE))
+ return;
+
+ uno::Reference<util::XThemeColor> xThemeColor;
+ xShape->getPropertyValue(UNO_NAME_LINECOLOR_THEME_REFERENCE) >>= xThemeColor;
+ if (!xThemeColor.is())
+ return;
+
+ model::ThemeColor aThemeColor;
+ model::theme::setFromXThemeColor(aThemeColor, xThemeColor);
+
+ if (aThemeColor.getType() == model::ThemeColorType::Unknown)
+ return;
+
+ Color aColor = mrColorSet.resolveColor(aThemeColor);
+ xShape->setPropertyValue(UNO_NAME_LINECOLOR, uno::Any(static_cast<sal_Int32>(aColor)));
+ }
+
+ /// Updates properties of the SdrObject
+ void updateSdrObject(SdrObject* pObject)
+ {
+ uno::Reference<drawing::XShape> xShape = pObject->getUnoShape();
+ uno::Reference<text::XTextRange> xShapeText(xShape, uno::UNO_QUERY);
+ if (xShapeText.is())
+ {
+ // E.g. group shapes have no text.
+ uno::Reference<container::XEnumerationAccess> xText(xShapeText->getText(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xParagraphs = xText->createEnumeration();
+ while (xParagraphs->hasMoreElements())
+ {
+ uno::Reference<container::XEnumerationAccess> xParagraph(xParagraphs->nextElement(),
+ uno::UNO_QUERY);
+ uno::Reference<container::XEnumeration> xPortions = xParagraph->createEnumeration();
+ while (xPortions->hasMoreElements())
+ {
+ uno::Reference<beans::XPropertySet> xPortion(xPortions->nextElement(),
+ uno::UNO_QUERY);
+ updateTextPortionColorSet(xPortion);
+ }
+ }
+ }
+
+ uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
+ updateFillColorSet(xShapeProps);
+ updateLineColorSet(xShapeProps);
+ }
+
+ void handleSdrObject(SdrObject* pObject) override
+ {
+ // update current object
+ updateSdrObject(pObject);
+
+ // update child objects
+ SdrObjList* pList = pObject->GetSubList();
+ if (pList)
+ {
+ SdrObjListIter aIter(pList, SdrIterMode::DeepWithGroups);
+ while (aIter.IsMore())
+ {
+ updateSdrObject(aIter.Next());
+ }
+ }
+ }
+};
+
+void changeColor(SwFormat* pFormat, svx::ColorSet const& rColorSet, SwDoc* pDocument)
+{
+ const SwAttrSet& rAttrSet = pFormat->GetAttrSet();
+ std::unique_ptr<SfxItemSet> pNewSet = rAttrSet.Clone();
+
+ SvxColorItem aColorItem(rAttrSet.GetColor());
+ model::ThemeColor const& rThemeColor = aColorItem.GetThemeColor();
+ auto eThemeType = rThemeColor.getType();
+ if (eThemeType != model::ThemeColorType::Unknown)
+ {
+ Color aColor = rColorSet.getColor(eThemeType);
+ aColor = rThemeColor.applyTransformations(aColor);
+ aColorItem.SetValue(aColor);
+ pNewSet->Put(aColorItem);
+ pDocument->ChgFormat(*pFormat, *pNewSet);
+ }
+}
+
+} // end anonymous namespace
+
+ThemeColorChanger::~ThemeColorChanger() {}
+
+void ThemeColorChanger::apply(svx::ColorSet const& rColorSet)
+{
+ SwDoc* pDocument = mpDocSh->GetDoc();
+ pDocument->GetIDocumentUndoRedo().StartUndo(SwUndoId::EMPTY, nullptr);
+
+ SfxStyleSheetBasePool* pPool = mpDocSh->GetStyleSheetPool();
+ SwDocStyleSheet* pStyle;
+
+ // Paragraph style color change
+ pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Para));
+ while (pStyle)
+ {
+ SwTextFormatColl* pTextFormatCollection = pStyle->GetCollection();
+ if (pTextFormatCollection)
+ changeColor(pTextFormatCollection, rColorSet, pDocument);
+ pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
+ }
+
+ // Character style color change
+ pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Char));
+ while (pStyle)
+ {
+ SwCharFormat* pCharFormat = pStyle->GetCharFormat();
+ if (pCharFormat)
+ changeColor(pCharFormat, rColorSet, pDocument);
+ pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
+ }
+
+ // Direct format change
+ auto pHandler = std::make_shared<ThemeColorHandler>(*pDocument, rColorSet);
+ sw::ModelTraverser aModelTraverser(pDocument);
+ aModelTraverser.addNodeHandler(pHandler);
+ aModelTraverser.traverse();
+
+ pDocument->GetIDocumentUndoRedo().EndUndo(SwUndoId::EMPTY, nullptr);
+}
+
+} // end sw namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx
index d553768db7ce..c7ba5142a9b7 100644
--- a/sw/source/core/ole/ndole.cxx
+++ b/sw/source/core/ole/ndole.cxx
@@ -150,6 +150,8 @@ void SAL_CALL SwOLEListener_Impl::disposing( const lang::EventObject& )
// TODO/LATER: actually SwEmbedObjectLink should be used here, but because different objects are used to control
// embedded object different link objects with the same functionality had to be implemented
+namespace {
+
class SwEmbedObjectLink : public sfx2::SvBaseLink
{
SwOLENode* m_pOleNode;
@@ -212,6 +214,44 @@ void SwEmbedObjectLink::Closed()
SvBaseLink::Closed();
}
+class SwIFrameLink : public sfx2::SvBaseLink
+{
+ SwOLENode* m_pOleNode;
+
+public:
+ explicit SwIFrameLink(SwOLENode* pNode)
+ : ::sfx2::SvBaseLink(::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB)
+ , m_pOleNode(pNode)
+ {
+ SetSynchron( false );
+ }
+
+ ::sfx2::SvBaseLink::UpdateResult DataChanged(
+ const OUString&, const uno::Any& )
+ {
+ uno::Reference<embed::XEmbeddedObject> xObject = m_pOleNode->GetOLEObj().GetOleRef();
+ uno::Reference<embed::XCommonEmbedPersist> xPersObj(xObject, uno::UNO_QUERY);
+ if (xPersObj.is())
+ {
+ // let the IFrameObject reload the link
+ try
+ {
+ xPersObj->reload(uno::Sequence<beans::PropertyValue>(), uno::Sequence<beans::PropertyValue>());
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ m_pOleNode->SetChanged();
+ }
+
+ return SUCCESS;
+ }
+
+};
+
+}
+
SwOLENode::SwOLENode( const SwNodeIndex &rWhere,
const svt::EmbeddedObjectRef& xObj,
SwGrfFormatColl *pGrfColl,
@@ -610,18 +650,49 @@ void SwOLENode::CheckFileLink_Impl()
try
{
- uno::Reference< embed::XLinkageSupport > xLinkSupport( maOLEObj.m_xOLERef.GetObject(), uno::UNO_QUERY_THROW );
- if ( xLinkSupport->isLink() )
+ uno::Reference<embed::XEmbeddedObject> xObject = maOLEObj.m_xOLERef.GetObject();
+ if (!xObject)
+ return;
+
+ bool bIFrame = false;
+
+ OUString aLinkURL;
+ uno::Reference<embed::XLinkageSupport> xLinkSupport(xObject, uno::UNO_QUERY);
+ if (xLinkSupport)
+ {
+ if (xLinkSupport->isLink())
+ aLinkURL = xLinkSupport->getLinkURL();
+ }
+ else
+ {
+ // get IFrame (Floating Frames) listed and updatable from the
+ // manage links dialog
+ SvGlobalName aClassId(xObject->getClassID());
+ if (aClassId == SvGlobalName(SO3_IFRAME_CLASSID))
+ {
+ uno::Reference<beans::XPropertySet> xSet(xObject->getComponent(), uno::UNO_QUERY);
+ if (xSet.is())
+ xSet->getPropertyValue("FrameURL") >>= aLinkURL;
+ bIFrame = true;
+ }
+ }
+
+ if (!aLinkURL.isEmpty()) // this is a file link so the model link manager should handle it
{
- const OUString aLinkURL = xLinkSupport->getLinkURL();
- if ( !aLinkURL.isEmpty() )
+ SwEmbedObjectLink* pEmbedObjectLink = nullptr;
+ if (!bIFrame)
+ {
+ pEmbedObjectLink = new SwEmbedObjectLink(this);
+ mpObjectLink = pEmbedObjectLink;
+ }
+ else
{
- // this is a file link so the model link manager should handle it
- mpObjectLink = new SwEmbedObjectLink( this );
- maLinkURL = aLinkURL;
- GetDoc().getIDocumentLinksAdministration().GetLinkManager().InsertFileLink( *mpObjectLink, sfx2::SvBaseLinkObjectType::ClientOle, aLinkURL );
- mpObjectLink->Connect();
+ mpObjectLink = new SwIFrameLink(this);
}
+ maLinkURL = aLinkURL;
+ GetDoc().getIDocumentLinksAdministration().GetLinkManager().InsertFileLink( *mpObjectLink, sfx2::SvBaseLinkObjectType::ClientOle, aLinkURL );
+ if (pEmbedObjectLink)
+ pEmbedObjectLink->Connect();
}
}
catch( uno::Exception& )
diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx
index da159df14bd2..7992b430328b 100644
--- a/sw/source/core/table/swtable.cxx
+++ b/sw/source/core/table/swtable.cxx
@@ -249,7 +249,8 @@ namespace
template<class T>
T lcl_MulDiv64(sal_uInt64 nA, sal_uInt64 nM, sal_uInt64 nD)
{
- return static_cast<T>((nA*nM)/nD);
+ assert(nD != 0);
+ return nD == 0 ? static_cast<T>(nA*nM) : static_cast<T>((nA*nM)/nD);
}
}
@@ -299,8 +300,7 @@ static void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const tools::Long nOld,
SwFrameFormat *pFormat = rBox.GetFrameFormat();
sal_uInt64 nBox = pFormat->GetFrameSize().GetWidth();
nOriginalSum += nBox;
- nBox *= nNew;
- nBox /= nOld;
+ nBox = lcl_MulDiv64<sal_uInt64>(nBox, nNew, nOld);
const sal_uInt64 nWishedSum = lcl_MulDiv64<sal_uInt64>(nOriginalSum, nNew, nOld) - nSum;
if( nWishedSum > 0 )
{
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 50fdf3f6acf5..fdbd8ef28050 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -55,8 +55,11 @@
#include <IMark.hxx>
#include <IDocumentMarkAccess.hxx>
#include <comphelper/processfactory.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
+#include <comphelper/string.hxx>
#include <docsh.hxx>
#include <unocrsrhelper.hxx>
+#include <textcontentcontrol.hxx>
#include <com/sun/star/rdf/Statement.hpp>
#include <com/sun/star/rdf/URI.hpp>
#include <com/sun/star/rdf/URIs.hpp>
@@ -866,9 +869,13 @@ public:
/// A content control portion is a text portion that is inside RES_TXTATR_CONTENTCONTROL.
class SwContentControlPortion : public SwTextPortion
{
+ SwTextContentControl* m_pTextContentControl;
public:
- SwContentControlPortion() { SetWhichPor(PortionType::ContentControl); }
+ SwContentControlPortion(SwTextContentControl* pTextContentControl);
virtual void Paint(const SwTextPaintInfo& rInf) const override;
+
+ /// Emits a PDF form widget for this portion on success, does nothing on failure.
+ bool DescribePDFControl(const SwTextPaintInfo& rInf) const;
};
}
@@ -886,11 +893,171 @@ void SwMetaPortion::Paint( const SwTextPaintInfo &rInf ) const
}
}
+SwContentControlPortion::SwContentControlPortion(SwTextContentControl* pTextContentControl)
+ : m_pTextContentControl(pTextContentControl)
+{
+ SetWhichPor(PortionType::ContentControl);
+}
+
+bool SwContentControlPortion::DescribePDFControl(const SwTextPaintInfo& rInf) const
+{
+ auto pPDFExtOutDevData = dynamic_cast<vcl::PDFExtOutDevData*>(rInf.GetOut()->GetExtOutDevData());
+ if (!pPDFExtOutDevData)
+ {
+ return false;
+ }
+
+ if (!pPDFExtOutDevData->GetIsExportFormFields())
+ {
+ return false;
+ }
+
+ if (!m_pTextContentControl)
+ {
+ return false;
+ }
+
+ const SwFormatContentControl& rFormatContentControl = m_pTextContentControl->GetContentControl();
+ const std::shared_ptr<SwContentControl>& pContentControl = rFormatContentControl.GetContentControl();
+ if (!pContentControl)
+ {
+ return false;
+ }
+
+ // Check if this is the first content control portion of this content control.
+ SwTextNode* pTextNode = pContentControl->GetTextNode();
+ sal_Int32 nStart = m_pTextContentControl->GetStart();
+ sal_Int32 nEnd = *m_pTextContentControl->GetEnd();
+ TextFrameIndex nViewStart = rInf.GetTextFrame()->MapModelToView(pTextNode, nStart);
+ TextFrameIndex nViewEnd = rInf.GetTextFrame()->MapModelToView(pTextNode, nEnd);
+ // The content control portion starts 1 char after the starting dummy character.
+ if (rInf.GetIdx() != nViewStart + TextFrameIndex(1))
+ {
+ // Ignore: don't process and also don't emit plain text fallback.
+ return true;
+ }
+
+ std::unique_ptr<vcl::PDFWriter::AnyWidget> pDescriptor;
+ switch (pContentControl->GetType())
+ {
+ case SwContentControlType::RICH_TEXT:
+ case SwContentControlType::PLAIN_TEXT:
+ {
+ pDescriptor = std::make_unique<vcl::PDFWriter::EditWidget>();
+ break;
+ }
+ case SwContentControlType::CHECKBOX:
+ {
+ pDescriptor = std::make_unique<vcl::PDFWriter::CheckBoxWidget>();
+ auto pCheckBoxWidget = static_cast<vcl::PDFWriter::CheckBoxWidget*>(pDescriptor.get());
+ pCheckBoxWidget->Checked = pContentControl->GetChecked();
+ // If it is checked already, then leave the default "Yes" OnValue unchanged, so the
+ // appropriate appearance is found by PDF readers.
+ if (!pCheckBoxWidget->Checked)
+ {
+ pCheckBoxWidget->OnValue = pContentControl->GetCheckedState();
+ pCheckBoxWidget->OffValue = pContentControl->GetUncheckedState();
+ }
+ break;
+ }
+ case SwContentControlType::DROP_DOWN_LIST:
+ {
+ pDescriptor = std::make_unique<vcl::PDFWriter::ListBoxWidget>();
+ auto pListWidget = static_cast<vcl::PDFWriter::ListBoxWidget*>(pDescriptor.get());
+ pListWidget->DropDown = true;
+ for (const auto& rItem : pContentControl->GetListItems())
+ {
+ pListWidget->Entries.push_back(rItem.m_aDisplayText);
+ }
+ break;
+ }
+ case SwContentControlType::COMBO_BOX:
+ {
+ pDescriptor = std::make_unique<vcl::PDFWriter::ComboBoxWidget>();
+ auto pComboWidget = static_cast<vcl::PDFWriter::ComboBoxWidget*>(pDescriptor.get());
+ for (const auto& rItem : pContentControl->GetListItems())
+ {
+ pComboWidget->Entries.push_back(rItem.m_aDisplayText);
+ }
+ break;
+ }
+ case SwContentControlType::DATE:
+ {
+ pDescriptor = std::make_unique<vcl::PDFWriter::EditWidget>();
+ auto pEditWidget = static_cast<vcl::PDFWriter::EditWidget*>(pDescriptor.get());
+ pEditWidget->Format = vcl::PDFWriter::Date;
+ // GetDateFormat() uses a syntax that works with SvNumberFormatter::PutEntry(), PDF's
+ // AFDate_FormatEx() uses a similar syntax, but uses lowercase characters in case of
+ // "Y", "M" and "D" at least.
+ pEditWidget->DateFormat = pContentControl->GetDateFormat().toAsciiLowerCase();
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (!pDescriptor)
+ {
+ return false;
+ }
+
+ const SwFont* pFont = rInf.GetFont();
+ if (pFont)
+ {
+ pDescriptor->TextFont = pFont->GetActualFont();
+ }
+
+ // Description for accessibility purposes.
+ if (!pContentControl->GetAlias().isEmpty())
+ {
+ pDescriptor->Description = pContentControl->GetAlias();
+ }
+
+ if (!pContentControl->GetShowingPlaceHolder())
+ {
+ SwPosition aPoint(*pTextNode, nStart);
+ SwPosition aMark(*pTextNode, nEnd);
+ SwPaM aPam(aMark, aPoint);
+ OUString aText = aPam.GetText();
+ static sal_Unicode const aForbidden[] = {
+ CH_TXTATR_BREAKWORD,
+ 0
+ };
+ pDescriptor->Text = comphelper::string::removeAny(aText, aForbidden);
+ }
+
+ // Calculate the bounding rectangle of this content control, which can be one or more layout
+ // portions in one or more lines.
+ SwRect aLocation;
+ auto pTextFrame = const_cast<SwTextFrame*>(rInf.GetTextFrame());
+ SwTextSizeInfo aInf(pTextFrame);
+ SwTextCursor aLine(pTextFrame, &aInf);
+ SwRect aStartRect;
+ aLine.GetCharRect(&aStartRect, nViewStart);
+ aLocation = aStartRect;
+ SwRect aEndRect;
+ aLine.GetCharRect(&aEndRect, nViewEnd);
+ aLocation.Union(aEndRect);
+ pDescriptor->Location = aLocation.SVRect();
+
+ pPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
+ pPDFExtOutDevData->CreateControl(*pDescriptor);
+ pPDFExtOutDevData->EndStructureElement();
+
+ return true;
+}
+
void SwContentControlPortion::Paint(const SwTextPaintInfo& rInf) const
{
if (Width())
{
rInf.DrawViewOpt(*this, PortionType::ContentControl);
+
+ if (DescribePDFControl(rInf))
+ {
+ return;
+ }
+
SwTextPortion::Paint(rInf);
}
}
@@ -1013,7 +1180,19 @@ SwTextPortion *SwTextFormatter::WhichTextPor( SwTextFormatInfo &rInf ) const
}
else if (GetFnt()->IsContentControl())
{
- pPor = new SwContentControlPortion;
+ SwTextFrame const*const pFrame(rInf.GetTextFrame());
+ SwPosition aPosition(pFrame->MapViewToModelPos(rInf.GetIdx()));
+ SwTextNode* pTextNode = aPosition.nNode.GetNode().GetTextNode();
+ SwTextContentControl* pTextContentControl = nullptr;
+ if (pTextNode)
+ {
+ sal_Int32 nIndex = aPosition.nContent.GetIndex();
+ if (SwTextAttr* pAttr = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT))
+ {
+ pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ }
+ }
+ pPor = new SwContentControlPortion(pTextContentControl);
}
else
{
diff --git a/sw/source/core/text/itrtxt.cxx b/sw/source/core/text/itrtxt.cxx
index 8fb8334a83fa..772cf498acf9 100644
--- a/sw/source/core/text/itrtxt.cxx
+++ b/sw/source/core/text/itrtxt.cxx
@@ -27,6 +27,7 @@
#include <pagefrm.hxx>
#include <tgrditem.hxx>
#include "porfld.hxx"
+#include "porrst.hxx"
#include "itrtxt.hxx"
#include <txtfrm.hxx>
@@ -283,7 +284,41 @@ SwTwips SwTextCursor::AdjustBaseLine( const SwLineLayout& rLine,
if (GetInfo().GetTextFrame()->IsVertLR() && !GetInfo().GetTextFrame()->IsVertLRBT())
nOfst += rLine.Height() - ( rLine.Height() - nPorHeight ) / 2 - nPorAscent;
else
- nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
+ {
+ SwTwips nLineHeight = 0;
+ bool bHadClearingBreak = false;
+ if (GetInfo().GetTextFrame()->IsVertical())
+ {
+ // Ignore the height of clearing break portions in the automatic
+ // alignment case.
+ const SwLinePortion* pLinePor = rLine.GetFirstPortion();
+ while (pLinePor)
+ {
+ bool bClearingBreak = false;
+ if (pLinePor->IsBreakPortion())
+ {
+ auto pBreakPortion = static_cast<const SwBreakPortion*>(pLinePor);
+ bClearingBreak = pBreakPortion->GetClear() != SwLineBreakClear::NONE;
+ if (bClearingBreak)
+ {
+ bHadClearingBreak = true;
+ }
+ }
+ if (!bClearingBreak && pLinePor->Height() > nLineHeight)
+ {
+ nLineHeight = pLinePor->Height();
+ }
+ pLinePor = pLinePor->GetNextPortion();
+ }
+ }
+
+ if (!bHadClearingBreak)
+ {
+ nLineHeight = rLine.Height();
+ }
+
+ nOfst += ( nLineHeight - nPorHeight ) / 2 + nPorAscent;
+ }
break;
}
[[fallthrough]];
diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx
index 6ef492c1b9d5..3146e60881dd 100644
--- a/sw/source/core/text/porfld.cxx
+++ b/sw/source/core/text/porfld.cxx
@@ -441,7 +441,7 @@ void SwFieldPortion::Paint( const SwTextPaintInfo &rInf ) const
SwFontSave aSave( rInf, m_pFont.get() );
// OSL_ENSURE(GetLen() <= TextFrameIndex(1), "SwFieldPortion::Paint: rest-portion pollution?");
- if( Width() && ( !m_bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) )
+ if( Width() && ( !m_bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) && !m_bContentControl )
{
// A very liberal use of the background
rInf.DrawViewOpt( *this, PortionType::Field );
@@ -1074,6 +1074,9 @@ void SwTextFrame::StopAnimation( const OutputDevice* pOut )
*/
SwCombinedPortion::SwCombinedPortion( const OUString &rText )
: SwFieldPortion( rText )
+ , m_aWidth{ static_cast<sal_uInt16>(0),
+ static_cast<sal_uInt16>(0),
+ static_cast<sal_uInt16>(0) }
, m_nUpPos(0)
, m_nLowPos(0)
, m_nProportion(55)
diff --git a/sw/source/core/text/porfld.hxx b/sw/source/core/text/porfld.hxx
index 519e56f8f58c..5c01045bbd12 100644
--- a/sw/source/core/text/porfld.hxx
+++ b/sw/source/core/text/porfld.hxx
@@ -52,6 +52,7 @@ protected:
bool m_bReplace : 1; // Used by SwGrfNumPortion
const bool m_bPlaceHolder : 1;
bool m_bNoLength : 1; // HACK for meta suffix (no CH_TXTATR)
+ bool m_bContentControl = false;
void SetFont( std::unique_ptr<SwFont> pNew ) { m_pFont = std::move(pNew); }
bool IsNoLength() const { return m_bNoLength; }
@@ -107,6 +108,8 @@ public:
// Accessibility: pass information about this portion to the PortionHandler
virtual void HandlePortion( SwPortionHandler& rPH ) const override;
+
+ void SetContentControl(bool bContentControl) { m_bContentControl = bContentControl; }
};
/**
@@ -207,7 +210,7 @@ public:
class SwCombinedPortion : public SwFieldPortion
{
sal_uInt16 m_aPos[6]; // up to six X positions
- o3tl::enumarray<SwFontScript,sal_uInt16> m_aWidth = {}; // one width for every scripttype
+ o3tl::enumarray<SwFontScript,sal_uInt16> m_aWidth; // one width for every scripttype
SwFontScript m_aScrType[6]; // scripttype of every character
sal_uInt16 m_nUpPos; // the Y position of the upper baseline
sal_uInt16 m_nLowPos; // the Y position of the lower baseline
diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
index c09aede4c5d6..6cf02c1f075b 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -1033,6 +1033,10 @@ static void InitBookmarks(
break;
}
}
+ if (iter == end)
+ {
+ break; // remaining marks are hidden
+ }
}
}
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
index f2d2b0cdd168..86975f32d6eb 100644
--- a/sw/source/core/text/porrst.cxx
+++ b/sw/source/core/text/porrst.cxx
@@ -130,9 +130,23 @@ void SwBreakPortion::Paint( const SwTextPaintInfo &rInf ) const
// Reduce height to text height for the duration of the print, so the vertical height will look
// correct for the line break character, even for clearing breaks.
SwTwips nHeight = Height();
+ SwTwips nVertPosOffset = (nHeight - m_nTextHeight) / 2;
auto pPortion = const_cast<SwBreakPortion*>(this);
pPortion->Height(m_nTextHeight, false);
- comphelper::ScopeGuard g([pPortion, nHeight] { pPortion->Height(nHeight, false); });
+ if (rInf.GetTextFrame()->IsVertical())
+ {
+ // Compensate for the offset done in SwTextCursor::AdjustBaseLine() for the vertical case.
+ const_cast<SwTextPaintInfo&>(rInf).Y(rInf.Y() + nVertPosOffset);
+ }
+ comphelper::ScopeGuard g(
+ [pPortion, nHeight, &rInf, nVertPosOffset]
+ {
+ if (rInf.GetTextFrame()->IsVertical())
+ {
+ const_cast<SwTextPaintInfo&>(rInf).Y(rInf.Y() - nVertPosOffset);
+ }
+ pPortion->Height(nHeight, false);
+ });
rInf.DrawLineBreak( *this );
@@ -177,7 +191,13 @@ bool SwBreakPortion::Format( SwTextFormatInfo &rInf )
// See if this is a clearing break. If so, calculate how much we need to "jump down" so the next
// line can again use the full text width.
- if (m_eClear != SwLineBreakClear::NONE)
+ SwLineBreakClear eClear = m_eClear;
+ if (rInf.GetTextFrame()->IsRightToLeft() && eClear != SwLineBreakClear::ALL)
+ {
+ // RTL ignores left/right breaks.
+ eClear = SwLineBreakClear::NONE;
+ }
+ if (eClear != SwLineBreakClear::NONE)
{
SwTextFly& rTextFly = rInf.GetTextFly();
if (rTextFly.IsOn())
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 3613469d7703..5b1e30c47018 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -425,7 +425,7 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
}
for (auto const pSectionNode : sections)
{
- pSectionNode->DelFrames(rFrame.getRootFrame());
+ pSectionNode->GetSection().GetFormat()->DelFrames(/*rFrame.getRootFrame()*/);
}
}
auto pRet(std::make_unique<sw::MergedPara>(rFrame, std::move(extents),
diff --git a/sw/source/core/text/txtfld.cxx b/sw/source/core/text/txtfld.cxx
index fc25dc4e9880..3528802dd539 100644
--- a/sw/source/core/text/txtfld.cxx
+++ b/sw/source/core/text/txtfld.cxx
@@ -406,7 +406,12 @@ SwLinePortion *SwTextFormatter::NewExtraPortion( SwTextFormatInfo &rInf )
}
if( !pRet )
{
- pRet = new SwFieldPortion( "" );
+ auto pFieldPortion = new SwFieldPortion( "" );
+ if (pHint->Which() == RES_TXTATR_CONTENTCONTROL)
+ {
+ pFieldPortion->SetContentControl(true);
+ }
+ pRet = pFieldPortion;
rInf.SetLen(TextFrameIndex(1));
}
return pRet;
@@ -747,6 +752,28 @@ SwNumberPortion *SwTextFormatter::NewNumberPortion( SwTextFormatInfo &rInf ) con
// Build a new numbering font basing on the current paragraph font:
std::unique_ptr<SwFont> pNumFnt(new SwFont( &rInf.GetCharAttr(), pIDSA ));
+ const SwTextNode& rTextNode = *rInf.GetTextFrame()->GetTextNodeForParaProps();
+ if (const SwpHints* pHints = rTextNode.GetpSwpHints())
+ {
+ // Also look for an empty character hint that sits at the paragraph end:
+ for (size_t i = 0; i < pHints->Count(); ++i)
+ {
+ const SwTextAttr* pHint = pHints->GetSortedByEnd(i);
+ if (pHint->Which() == RES_TXTATR_AUTOFMT && pHint->GetEnd()
+ && pHint->GetStart() == *pHint->GetEnd()
+ && pHint->GetStart() == rTextNode.GetText().getLength())
+ {
+ std::shared_ptr<SfxItemSet> pSet
+ = pHint->GetAutoFormat().GetStyleHandle();
+ if (pSet)
+ {
+ pNumFnt->SetDiffFnt(pSet.get(), pIDSA);
+ break;
+ }
+ }
+ }
+ }
+
// #i53199#
if ( !pIDSA->get(DocumentSettingId::DO_NOT_RESET_PARA_ATTRS_FOR_NUM_FONT) )
{
diff --git a/sw/source/core/text/txtfly.cxx b/sw/source/core/text/txtfly.cxx
index 88f0687de8c1..ea4b5c472e76 100644
--- a/sw/source/core/text/txtfly.cxx
+++ b/sw/source/core/text/txtfly.cxx
@@ -998,16 +998,17 @@ SwTwips SwTextFly::CalcMinBottom() const
SwTwips SwTextFly::GetMaxBottom(const SwBreakPortion& rPortion, const SwTextFormatInfo& rInfo) const
{
+ // Note that m_pCurrFrame is already swapped at this stage, so it's correct to bypass
+ // SwRectFnSet here.
SwTwips nRet = 0;
size_t nCount(m_bOn ? GetAnchoredObjList()->size() : 0);
- SwRectFnSet aRectFnSet(m_pCurrFrame);
// Get the horizontal position of the break portion in absolute twips. The frame area is in
// absolute twips, the frame's print area is relative to the frame area. Finally the portion's
// position is relative to the frame's print area.
SwTwips nX = rInfo.X();
- nX += aRectFnSet.GetLeft(m_pCurrFrame->getFrameArea());
- nX += aRectFnSet.GetLeft(m_pCurrFrame->getFramePrintArea());
+ nX += m_pCurrFrame->getFrameArea().Left();
+ nX += m_pCurrFrame->getFramePrintArea().Left();
for (size_t i = 0; i < nCount; ++i)
{
@@ -1020,9 +1021,15 @@ SwTwips SwTextFly::GetMaxBottom(const SwBreakPortion& rPortion, const SwTextForm
}
SwRect aRect(pAnchoredObj->GetObjRectWithSpaces());
+
+ if (m_pCurrFrame->IsVertical())
+ {
+ m_pCurrFrame->SwitchVerticalToHorizontal(aRect);
+ }
+
if (rPortion.GetClear() == SwLineBreakClear::LEFT)
{
- if (nX < aRectFnSet.GetLeft(aRect))
+ if (nX < aRect.Left())
{
// Want to jump down to the first line that's unblocked on the left. This object is
// on the right of the break, ignore it.
@@ -1031,14 +1038,14 @@ SwTwips SwTextFly::GetMaxBottom(const SwBreakPortion& rPortion, const SwTextForm
}
if (rPortion.GetClear() == SwLineBreakClear::RIGHT)
{
- if (nX > aRectFnSet.GetRight(aRect))
+ if (nX > aRect.Right())
{
// Want to jump down to the first line that's unblocked on the right. This object is
// on the left of the break, ignore it.
continue;
}
}
- SwTwips nBottom = aRectFnSet.GetBottom(aRect);
+ SwTwips nBottom = aRect.Top() + aRect.Height();
if (nBottom > nRet)
{
nRet = nBottom;
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index fb177841728d..3ed591503bbe 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -66,7 +66,7 @@
#include <fmtflcnt.hxx>
#include <fmtcntnt.hxx>
#include <numrule.hxx>
-#include <IGrammarContact.hxx>
+#include <GrammarContact.hxx>
#include <calbck.hxx>
#include <ftnidx.hxx>
#include <ftnfrm.hxx>
@@ -1802,7 +1802,7 @@ static void lcl_SetWrong( SwTextFrame& rFrame, SwTextNode const& rNode,
if ( !rFrame.IsFollow() )
{
SwTextNode* pTextNode = const_cast<SwTextNode*>(&rNode);
- IGrammarContact* pGrammarContact = getGrammarContact( *pTextNode );
+ sw::GrammarContact* pGrammarContact = sw::getGrammarContactFor(*pTextNode);
SwGrammarMarkUp* pWrongGrammar = pGrammarContact ?
pGrammarContact->getGrammarCheck( *pTextNode, false ) :
pTextNode->GetGrammarCheck();
@@ -1838,7 +1838,7 @@ static void lcl_SetWrong( SwTextFrame& rFrame, SwTextNode const& rNode,
pTextNode->SetSmartTags( std::make_unique<SwWrongList>( WRONGLIST_SMARTTAG ) );
pTextNode->GetSmartTags()->SetInvalid( nPos, nEnd );
}
- pTextNode->SetWrongDirty(SwTextNode::WrongState::TODO);
+ pTextNode->SetWrongDirty(sw::WrongState::TODO);
pTextNode->SetGrammarCheckDirty( true );
pTextNode->SetWordCountDirty( true );
pTextNode->SetAutoCompleteWordDirty( true );
diff --git a/sw/source/core/text/xmldump.cxx b/sw/source/core/text/xmldump.cxx
index 5e1ac0eb002c..7bac72593d6d 100644
--- a/sw/source/core/text/xmldump.cxx
+++ b/sw/source/core/text/xmldump.cxx
@@ -615,6 +615,11 @@ void SwFont::dumpAsXml(xmlTextWriterPtr writer) const
(void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("ptr"), "%p", this);
// do not use Color::AsRGBHexString() as that omits the transparency
(void)xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("color"), "%08" SAL_PRIxUINT32, sal_uInt32(GetColor()));
+ {
+ std::stringstream ss;
+ ss << GetWeight();
+ (void)xmlTextWriterWriteAttribute(writer, BAD_CAST("weight"), BAD_CAST(ss.str().c_str()));
+ }
(void)xmlTextWriterEndElement(writer);
}
diff --git a/sw/source/core/txtnode/SwGrammarContact.cxx b/sw/source/core/txtnode/GrammarContact.cxx
index 0b3b49da48e4..4aceeb5a9be9 100644
--- a/sw/source/core/txtnode/SwGrammarContact.cxx
+++ b/sw/source/core/txtnode/GrammarContact.cxx
@@ -17,64 +17,33 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
-#include <vcl/timer.hxx>
-#include <IGrammarContact.hxx>
+#include <GrammarContact.hxx>
+#include <doc.hxx>
#include <pam.hxx>
#include <ndtxt.hxx>
-#include <SwGrammarMarkUp.hxx>
#include <txtfrm.hxx>
-#include <svl/listener.hxx>
-namespace {
-
-/*
- * This class is responsible for the delayed display of grammar checks when a paragraph is edited
- * It's a client of the paragraph the cursor points to.
- * If the cursor position changes, updateCursorPosition has to be called
- * If the grammar checker wants to set a grammar marker at a paragraph, he has to request
- * the grammar list from this class. If the requested paragraph is not edited, it returns
- * the normal grammar list. But if the paragraph is the active one, a proxy list will be returned and
- * all changes are set in this proxy list. If the cursor leaves the paragraph the proxy list
- * will replace the old list. If the grammar checker has completed the paragraph ('setChecked')
- * then a timer is setup which replaces the old list as well.
- */
-class SwGrammarContact final : public IGrammarContact, public SvtListener
+namespace sw
{
- Timer m_aTimer;
- std::unique_ptr<SwGrammarMarkUp> m_pProxyList;
- bool m_isFinished;
- SwTextNode* m_pTextNode;
- DECL_LINK( TimerRepaint, Timer *, void );
-
-public:
- SwGrammarContact();
- virtual ~SwGrammarContact() override { m_aTimer.Stop(); }
-
- // (pure) virtual functions of IGrammarContact
- virtual void updateCursorPosition( const SwPosition& rNewPos ) override;
- virtual SwGrammarMarkUp* getGrammarCheck( SwTextNode& rTextNode, bool bCreate ) override;
- virtual void finishGrammarCheck( SwTextNode& rTextNode ) override;
- void CheckBroadcaster()
- {
- if(HasBroadcaster())
- return;
- m_pTextNode = nullptr;
- m_pProxyList.reset();
- }
-};
-
-}
-SwGrammarContact::SwGrammarContact()
+GrammarContact::GrammarContact()
: m_aTimer( "sw::SwGrammarContact TimerRepaint" ),
m_isFinished( false ),
m_pTextNode(nullptr)
{
m_aTimer.SetTimeout( 2000 ); // Repaint of grammar check after 'setChecked'
- m_aTimer.SetInvokeHandler( LINK(this, SwGrammarContact, TimerRepaint) );
+ m_aTimer.SetInvokeHandler( LINK(this, GrammarContact, TimerRepaint) );
+}
+
+void GrammarContact::CheckBroadcaster()
+{
+ if (HasBroadcaster())
+ return;
+ m_pTextNode = nullptr;
+ m_pProxyList.reset();
}
-IMPL_LINK( SwGrammarContact, TimerRepaint, Timer *, pTimer, void )
+IMPL_LINK( GrammarContact, TimerRepaint, Timer *, pTimer, void )
{
CheckBroadcaster();
if( pTimer )
@@ -89,7 +58,7 @@ IMPL_LINK( SwGrammarContact, TimerRepaint, Timer *, pTimer, void )
}
/* I'm always a client of the current paragraph */
-void SwGrammarContact::updateCursorPosition( const SwPosition& rNewPos )
+void GrammarContact::updateCursorPosition( const SwPosition& rNewPos )
{
CheckBroadcaster();
SwTextNode* pTextNode = rNewPos.nNode.GetNode().GetTextNode();
@@ -115,7 +84,7 @@ void SwGrammarContact::updateCursorPosition( const SwPosition& rNewPos )
}
/* deliver a grammar check list for the given text node */
-SwGrammarMarkUp* SwGrammarContact::getGrammarCheck( SwTextNode& rTextNode, bool bCreate )
+SwGrammarMarkUp* GrammarContact::getGrammarCheck( SwTextNode& rTextNode, bool bCreate )
{
SwGrammarMarkUp *pRet = nullptr;
CheckBroadcaster();
@@ -155,7 +124,7 @@ SwGrammarMarkUp* SwGrammarContact::getGrammarCheck( SwTextNode& rTextNode, bool
return pRet;
}
-void SwGrammarContact::finishGrammarCheck( SwTextNode& rTextNode )
+void GrammarContact::finishGrammarCheck( SwTextNode& rTextNode )
{
CheckBroadcaster();
if( &rTextNode != m_pTextNode ) // not my paragraph
@@ -175,16 +144,23 @@ void SwGrammarContact::finishGrammarCheck( SwTextNode& rTextNode )
}
}
-IGrammarContact* createGrammarContact()
+sw::GrammarContact* getGrammarContactFor(const SwTextNode& rTextNode)
{
- return new SwGrammarContact();
+ const SwDoc& rDoc = rTextNode.GetDoc();
+ if (rDoc.IsInDtor())
+ return nullptr;
+ return rDoc.getGrammarContact().get();
}
-void finishGrammarCheck( SwTextNode& rTextNode )
+void finishGrammarCheckFor(SwTextNode& rTextNode)
{
- IGrammarContact* pGrammarContact = getGrammarContact( rTextNode );
- if( pGrammarContact )
- pGrammarContact->finishGrammarCheck( rTextNode );
+ sw::GrammarContact* pGrammarContact = getGrammarContactFor(rTextNode);
+ if (pGrammarContact)
+ {
+ pGrammarContact->finishGrammarCheck(rTextNode);
+ }
}
+} // end sw
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/OnlineAccessibilityCheck.cxx b/sw/source/core/txtnode/OnlineAccessibilityCheck.cxx
new file mode 100644
index 000000000000..682fde13cceb
--- /dev/null
+++ b/sw/source/core/txtnode/OnlineAccessibilityCheck.cxx
@@ -0,0 +1,301 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <OnlineAccessibilityCheck.hxx>
+#include <doc.hxx>
+#include <pam.hxx>
+#include <txtfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <docsh.hxx>
+#include <cmdid.h>
+#include <officecfg/Office/Common.hxx>
+
+namespace sw
+{
+WeakNodeContainer::WeakNodeContainer(SwNode* pNode)
+ : m_pNode(pNode)
+{
+ if (m_pNode)
+ {
+ auto* pBroadcast = dynamic_cast<sw::BroadcastingModify*>(pNode);
+ if (pBroadcast)
+ {
+ EndListeningAll();
+ StartListening(pBroadcast->GetNotifier());
+ }
+ }
+}
+
+WeakNodeContainer::~WeakNodeContainer() { EndListeningAll(); }
+
+bool WeakNodeContainer::isAlive()
+{
+ if (!HasBroadcaster())
+ m_pNode = nullptr;
+ return m_pNode;
+}
+
+SwNode* WeakNodeContainer::getNode()
+{
+ if (isAlive())
+ return m_pNode;
+ return nullptr;
+}
+
+OnlineAccessibilityCheck::OnlineAccessibilityCheck(SwDoc& rDocument)
+ : m_rDocument(rDocument)
+ , m_aAccessibilityCheck(&m_rDocument)
+ , m_pPreviousNode(nullptr)
+ , m_nPreviousNodeIndex(-1)
+ , m_nAccessibilityIssues(0)
+ , m_bInitialCheck(false)
+ , m_bOnlineCheckStatus(
+ officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::get())
+{
+}
+
+void OnlineAccessibilityCheck::updateNodeStatus(SwNode* pNode)
+{
+ if (!pNode->IsContentNode() && !pNode->IsTableNode())
+ return;
+
+ m_nAccessibilityIssues = 0;
+
+ auto it = m_aNodes.find(pNode);
+ if (it == m_aNodes.end())
+ {
+ m_aNodes.emplace(pNode, std::make_unique<WeakNodeContainer>(pNode));
+ }
+
+ for (auto iterator = m_aNodes.begin(); iterator != m_aNodes.end();)
+ {
+ auto& pWeakContentNode = iterator->second;
+ if (pWeakContentNode->isAlive())
+ {
+ auto& rStatus = pWeakContentNode->getNode()->getAccessibilityCheckStatus();
+ if (rStatus.pCollection)
+ {
+ m_nAccessibilityIssues += rStatus.pCollection->getIssues().size();
+ ++iterator;
+ }
+ else
+ {
+ iterator = m_aNodes.erase(iterator);
+ }
+ }
+ else
+ {
+ iterator = m_aNodes.erase(iterator);
+ }
+ }
+}
+
+void OnlineAccessibilityCheck::updateStatusbar()
+{
+ SfxBindings* pBindings = m_rDocument.GetDocShell() && m_rDocument.GetDocShell()->GetDispatcher()
+ ? m_rDocument.GetDocShell()->GetDispatcher()->GetBindings()
+ : nullptr;
+ if (pBindings)
+ pBindings->Invalidate(FN_STAT_ACCESSIBILITY_CHECK);
+}
+
+void OnlineAccessibilityCheck::runAccessibilityCheck(SwNode* pNode)
+{
+ m_aAccessibilityCheck.getIssueCollection().clear();
+
+ m_aAccessibilityCheck.checkNode(pNode);
+
+ for (SwFrameFormat* const& pFrameFormat : pNode->GetAnchoredFlys())
+ {
+ SdrObject* pObject = pFrameFormat->FindSdrObject();
+ if (pObject)
+ m_aAccessibilityCheck.checkObject(pObject);
+ }
+
+ auto aCollection = m_aAccessibilityCheck.getIssueCollection();
+
+ pNode->getAccessibilityCheckStatus().pCollection
+ = std::make_unique<sfx::AccessibilityIssueCollection>(aCollection);
+}
+
+void OnlineAccessibilityCheck::runDocumentLevelAccessibilityCheck()
+{
+ m_aAccessibilityCheck.getIssueCollection().clear();
+ m_aAccessibilityCheck.checkDocumentProperties();
+ auto aCollection = m_aAccessibilityCheck.getIssueCollection();
+ m_pDocumentAccessibilityIssues
+ = std::make_unique<sfx::AccessibilityIssueCollection>(aCollection);
+}
+
+void OnlineAccessibilityCheck::initialCheck()
+{
+ if (m_bInitialCheck)
+ return;
+
+ runDocumentLevelAccessibilityCheck();
+
+ auto const& pNodes = m_rDocument.GetNodes();
+ for (SwNodeOffset n(0); n < pNodes.Count(); ++n)
+ {
+ SwNode* pNode = pNodes[n];
+ if (pNode)
+ {
+ runAccessibilityCheck(pNode);
+ updateNodeStatus(pNode);
+ }
+ }
+
+ updateStatusbar();
+
+ m_bInitialCheck = true;
+}
+
+void OnlineAccessibilityCheck::updateCheckerActivity()
+{
+ bool bOnlineCheckStatus
+ = officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::get();
+
+ if (bOnlineCheckStatus != m_bOnlineCheckStatus)
+ {
+ EndListeningAll();
+ m_pPreviousNode = nullptr;
+ m_nPreviousNodeIndex = SwNodeOffset(-1);
+ m_bInitialCheck = false; // force initial check
+
+ if (!bOnlineCheckStatus)
+ {
+ clearAccessibilityIssuesFromAllNodes(); // cleanup all accessibility check data on nodes
+ m_nAccessibilityIssues = -1;
+ }
+ else
+ {
+ m_nAccessibilityIssues = 0;
+ }
+
+ m_bOnlineCheckStatus = bOnlineCheckStatus;
+
+ updateStatusbar();
+ }
+}
+
+void OnlineAccessibilityCheck::update(const SwPosition& rNewPos)
+{
+ updateCheckerActivity();
+
+ if (!m_bOnlineCheckStatus)
+ return;
+
+ initialCheck();
+
+ lookForPreviousNodeAndUpdate(rNewPos);
+}
+
+void OnlineAccessibilityCheck::lookForPreviousNodeAndUpdate(const SwPosition& rNewPos)
+{
+ auto nCurrenNodeIndex = rNewPos.GetNodeIndex();
+ auto* pCurrentNode = &rNewPos.GetNode();
+
+ if (!pCurrentNode->IsContentNode() && !pCurrentNode->IsTableNode())
+ return;
+
+ auto* pCurrentBroadcast = dynamic_cast<sw::BroadcastingModify*>(pCurrentNode);
+ if (!pCurrentBroadcast)
+ return;
+
+ // Check if previous node was deleted
+ if (!HasBroadcaster())
+ {
+ EndListeningAll();
+ StartListening(pCurrentBroadcast->GetNotifier());
+ m_pPreviousNode = pCurrentNode;
+ m_nPreviousNodeIndex = nCurrenNodeIndex;
+ return;
+ }
+
+ // Check if node index changed
+ if (nCurrenNodeIndex == m_nPreviousNodeIndex)
+ return;
+
+ // Check if previous node is valid
+ if (m_nPreviousNodeIndex < SwNodeOffset(0)
+ || m_nPreviousNodeIndex >= pCurrentNode->GetNodes().Count())
+ {
+ EndListeningAll();
+ StartListening(pCurrentBroadcast->GetNotifier());
+ m_pPreviousNode = pCurrentNode;
+ m_nPreviousNodeIndex = nCurrenNodeIndex;
+ return;
+ }
+
+ // Get the real previous node from index
+ SwNode* pNode = pCurrentNode->GetNodes()[m_nPreviousNodeIndex];
+
+ if (pNode && (pNode->IsContentNode() || pNode->IsTableNode()))
+ {
+ runAccessibilityCheck(pNode);
+ updateNodeStatus(pNode);
+ updateStatusbar();
+
+ // Assign previous node and index
+ EndListeningAll();
+ StartListening(pCurrentBroadcast->GetNotifier());
+ m_pPreviousNode = pCurrentNode;
+ m_nPreviousNodeIndex = nCurrenNodeIndex;
+ }
+ else
+ {
+ m_pPreviousNode = nullptr;
+ m_nPreviousNodeIndex = SwNodeOffset(-1);
+ }
+}
+
+void OnlineAccessibilityCheck::clearAccessibilityIssuesFromAllNodes()
+{
+ auto const& pNodes = m_rDocument.GetNodes();
+ for (SwNodeOffset n(0); n < pNodes.Count(); ++n)
+ {
+ SwNode* pNode = pNodes[n];
+ if (pNode)
+ {
+ pNode->getAccessibilityCheckStatus().reset();
+ }
+ }
+
+ m_aNodes.clear();
+ updateStatusbar();
+}
+
+void OnlineAccessibilityCheck::resetAndQueue(SwNode* pNode)
+{
+ bool bOnlineCheckStatus
+ = officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::get();
+ if (!bOnlineCheckStatus)
+ return;
+
+ pNode->getAccessibilityCheckStatus().reset();
+ m_aNodes.erase(pNode);
+ runAccessibilityCheck(pNode);
+ updateNodeStatus(pNode);
+ updateStatusbar();
+}
+
+} // end sw
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/atrref.cxx b/sw/source/core/txtnode/atrref.cxx
index e281803050e3..2d93d834ae7a 100644
--- a/sw/source/core/txtnode/atrref.cxx
+++ b/sw/source/core/txtnode/atrref.cxx
@@ -22,6 +22,12 @@
#include <hintids.hxx>
#include <hints.hxx>
#include <txtrfmrk.hxx>
+#include <sfx2/viewsh.hxx>
+#include <tools/json_writer.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <doc.hxx>
+#include <ndtxt.hxx>
SwFormatRefMark::~SwFormatRefMark( )
{
@@ -94,6 +100,27 @@ SwTextRefMark::SwTextRefMark( SwFormatRefMark& rAttr,
SetOverlapAllowedAttr( true );
}
+SwTextRefMark::~SwTextRefMark()
+{
+ if (!comphelper::LibreOfficeKit::isActive() || GetTextNode().GetDoc().IsClipBoard())
+ return;
+
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (!pViewShell)
+ return;
+
+ OUString fieldCommand = GetRefMark().GetRefName();
+ tools::JsonWriter aJson;
+ aJson.put("commandName", ".uno:DeleteField");
+ aJson.put("success", true);
+ {
+ auto result = aJson.startNode("result");
+ aJson.put("DeleteField", fieldCommand);
+ }
+
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.extractData());
+}
+
const sal_Int32* SwTextRefMark::GetEnd() const
{
return m_pEnd;
diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx b/sw/source/core/txtnode/attrcontentcontrol.cxx
index f70a36b49de2..2b96ddda53ed 100644
--- a/sw/source/core/txtnode/attrcontentcontrol.cxx
+++ b/sw/source/core/txtnode/attrcontentcontrol.cxx
@@ -25,10 +25,12 @@
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequenceashashmap.hxx>
#include <svl/numformat.hxx>
+#include <vcl/keycod.hxx>
#include <ndtxt.hxx>
#include <textcontentcontrol.hxx>
#include <doc.hxx>
+#include <wrtsh.hxx>
using namespace com::sun::star;
@@ -135,6 +137,16 @@ void SwFormatContentControl::NotifyChangeTextNode(SwTextNode* pTextNode)
}
}
+SwTextNode* SwFormatContentControl::GetTextNode() const
+{
+ if (!m_pContentControl)
+ {
+ return nullptr;
+ }
+
+ return m_pContentControl->GetTextNode();
+}
+
// This SwFormatContentControl has been cloned and points at the same SwContentControl as the
// source: this function copies the SwContentControl.
void SwFormatContentControl::DoCopy(SwTextNode& rTargetTextNode)
@@ -170,6 +182,42 @@ SwContentControl::SwContentControl(SwFormatContentControl* pFormat)
, m_pFormat(pFormat)
, m_pTextNode(nullptr)
{
+ if (!pFormat)
+ {
+ return;
+ }
+
+ const std::shared_ptr<SwContentControl>& pOther = pFormat->GetContentControl();
+ if (!pOther)
+ {
+ return;
+ }
+
+ SetShowingPlaceHolder(pOther->m_bShowingPlaceHolder);
+ SetCheckbox(pOther->m_bCheckbox);
+ SetChecked(pOther->m_bChecked);
+ SetCheckedState(pOther->m_aCheckedState);
+ SetUncheckedState(pOther->m_aUncheckedState);
+ SetListItems(pOther->m_aListItems);
+ SetPicture(pOther->m_bPicture);
+ SetDate(pOther->m_bDate);
+ SetDateFormat(pOther->m_aDateFormat);
+ SetDateLanguage(pOther->m_aDateLanguage);
+ SetCurrentDate(pOther->m_aCurrentDate);
+ SetPlainText(pOther->m_bPlainText);
+ SetComboBox(pOther->m_bComboBox);
+ SetDropDown(pOther->m_bDropDown);
+ SetPlaceholderDocPart(pOther->m_aPlaceholderDocPart);
+ SetDataBindingPrefixMappings(pOther->m_aDataBindingPrefixMappings);
+ SetDataBindingXpath(pOther->m_aDataBindingXpath);
+ SetDataBindingStoreItemID(pOther->m_aDataBindingStoreItemID);
+ SetColor(pOther->m_aColor);
+ SetAppearance(pOther->m_aAppearance);
+ SetAlias(pOther->m_aAlias);
+ SetTag(pOther->m_aTag);
+ SetId(pOther->m_nId);
+ SetTabIndex(pOther->m_nTabIndex);
+ SetLock(pOther->m_aLock);
}
SwContentControl::~SwContentControl() {}
@@ -214,6 +262,94 @@ void SwContentControl::SwClientNotify(const SwModify&, const SfxHint& rHint)
}
}
+std::optional<size_t> SwContentControl::GetSelectedListItem(bool bCheckDocModel) const
+{
+ if (!bCheckDocModel || m_oSelectedListItem)
+ return m_oSelectedListItem;
+
+ const size_t nLen = GetListItems().size();
+ if (GetShowingPlaceHolder() || !nLen || !GetTextAttr())
+ return std::nullopt;
+
+ const OUString& rText = GetTextAttr()->ToString();
+ for (size_t i = 0; i < nLen; ++i)
+ {
+ if (GetTextAttr()[i].ToString() == rText)
+ return i;
+ }
+ assert(!GetDropDown() && "DropDowns must always have an associated list item");
+ return std::nullopt;
+}
+
+bool SwContentControl::AddListItem(size_t nZIndex, const OUString& rDisplayText,
+ const OUString& rValue)
+{
+ SwContentControlListItem aListItem;
+ if (rValue.isEmpty())
+ {
+ if (rDisplayText.isEmpty())
+ return false;
+ aListItem.m_aValue = rDisplayText;
+ }
+ else
+ {
+ aListItem.m_aValue = rValue;
+ aListItem.m_aDisplayText = rDisplayText;
+ }
+
+ // Avoid adding duplicates
+ for (auto& rListItem : GetListItems())
+ {
+ if (rListItem == aListItem)
+ return false;
+ }
+
+ const size_t nLen = GetListItems().size();
+ nZIndex = std::min(nZIndex, nLen);
+ const std::optional<size_t> oSelected = GetSelectedListItem();
+ if (oSelected && *oSelected >= nZIndex)
+ {
+ if (*oSelected < nLen)
+ SetSelectedListItem(*oSelected + 1);
+ }
+ std::vector<SwContentControlListItem> vListItems = GetListItems();
+ vListItems.insert(vListItems.begin() + nZIndex, aListItem);
+ SetListItems(vListItems);
+ return true;
+}
+
+void SwContentControl::DeleteListItem(size_t nZIndex)
+{
+ if (nZIndex >= GetListItems().size())
+ return;
+
+ const std::optional<size_t> oSelected = GetSelectedListItem();
+ if (oSelected)
+ {
+ if (*oSelected == nZIndex)
+ {
+ SetSelectedListItem(std::nullopt);
+ if (m_bDropDown && GetTextAttr())
+ GetTextAttr()->Invalidate();
+ }
+ else if (*oSelected < nZIndex)
+ SetSelectedListItem(*oSelected - 1);
+ }
+
+ std::vector<SwContentControlListItem> vListItems = GetListItems();
+ vListItems.erase(vListItems.begin() + nZIndex);
+ SetListItems(vListItems);
+ return;
+}
+
+void SwContentControl::ClearListItems()
+{
+ SetSelectedListItem(std::nullopt);
+ SetListItems(std::vector<SwContentControlListItem>());
+ if (m_bDropDown && GetTextAttr())
+ GetTextAttr()->Invalidate();
+}
+
OUString SwContentControl::GetDateString() const
{
SwDoc& rDoc = m_pTextNode->GetDoc();
@@ -233,9 +369,14 @@ OUString SwContentControl::GetDateString() const
const Color* pColor = nullptr;
OUString aFormatted;
- if (!m_oSelectedDate)
+ double fSelectedDate = 0;
+ if (m_oSelectedDate)
{
- return OUString();
+ fSelectedDate = *m_oSelectedDate;
+ }
+ else
+ {
+ fSelectedDate = GetCurrentDateValue();
}
if (nFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
@@ -243,7 +384,7 @@ OUString SwContentControl::GetDateString() const
return OUString();
}
- pNumberFormatter->GetOutputString(*m_oSelectedDate, nFormat, aFormatted, &pColor, false);
+ pNumberFormatter->GetOutputString(fSelectedDate, nFormat, aFormatted, &pColor, false);
return aFormatted;
}
@@ -301,6 +442,110 @@ double SwContentControl::GetCurrentDateValue() const
return dCurrentDate;
}
+bool SwContentControl::IsInteractingCharacter(sal_Unicode cCh)
+{
+ if (GetCheckbox())
+ {
+ return cCh == ' ';
+ }
+
+ if (GetPicture())
+ {
+ return cCh == '\r';
+ }
+
+ return false;
+}
+
+bool SwContentControl::ShouldOpenPopup(const vcl::KeyCode& rKeyCode)
+{
+ switch (GetType())
+ {
+ case SwContentControlType::DROP_DOWN_LIST:
+ case SwContentControlType::COMBO_BOX:
+ case SwContentControlType::DATE:
+ {
+ // Alt-down opens the popup.
+ return rKeyCode.IsMod2() && rKeyCode.GetCode() == KEY_DOWN;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+// NOTE: call SetReadWrite separately to implement true (un)locking.
+// This is mostly a theoretical function; the lock state is mainly kept for round-tripping purposes.
+// It is implemented here primarily for pointless VBA control, but with the intention that it
+// could be made functionally useful as well for checkboxes/dropdowns/pictures.
+// Returns whether the content (bControl=false) cannot be modified,
+// or if the control cannot be deleted.
+std::optional<bool> SwContentControl::GetLock(bool bControl) const
+{
+ std::optional<bool> oLock;
+ if (m_aLock.isEmpty())
+ return oLock;
+ else if (m_aLock.equalsIgnoreAsciiCase("sdtContentLocked"))
+ oLock = true;
+ else if (m_aLock.equalsIgnoreAsciiCase("unlocked"))
+ oLock = false;
+ else if (m_aLock.equalsIgnoreAsciiCase("sdtLocked"))
+ oLock = bControl;
+ else if (m_aLock.equalsIgnoreAsciiCase("contentLocked"))
+ oLock = !bControl;
+
+ assert(oLock && "invalid or unknown lock state");
+ return oLock;
+}
+
+void SwContentControl::SetLock(bool bLockContent, bool bLockControl)
+{
+ if (!bLockContent && !bLockControl)
+ m_aLock = "unlocked";
+ else if (bLockContent && bLockControl)
+ m_aLock = "sdtContentLocked";
+ else if (bLockContent)
+ m_aLock = "contentLocked";
+ else
+ m_aLock = "sdtLocked";
+}
+
+SwContentControlType SwContentControl::GetType() const
+{
+ if (m_bCheckbox)
+ {
+ return SwContentControlType::CHECKBOX;
+ }
+
+ if (m_bComboBox)
+ {
+ return SwContentControlType::COMBO_BOX;
+ }
+
+ if (m_bDropDown)
+ {
+ return SwContentControlType::DROP_DOWN_LIST;
+ }
+
+ if (m_bPicture)
+ {
+ return SwContentControlType::PICTURE;
+ }
+
+ if (m_bDate)
+ {
+ return SwContentControlType::DATE;
+ }
+
+ if (m_bPlainText)
+ {
+ return SwContentControlType::PLAIN_TEXT;
+ }
+
+ return SwContentControlType::RICH_TEXT;
+}
+
void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwContentControl"));
@@ -326,6 +571,12 @@ void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const
BAD_CAST(m_aDateLanguage.toUtf8().getStr()));
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("current-date"),
BAD_CAST(m_aCurrentDate.toUtf8().getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("plain-text"),
+ BAD_CAST(OString::boolean(m_bPlainText).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("combo-box"),
+ BAD_CAST(OString::boolean(m_bComboBox).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("drop-down"),
+ BAD_CAST(OString::boolean(m_bDropDown).getStr()));
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("placeholder-doc-part"),
BAD_CAST(m_aPlaceholderDocPart.toUtf8().getStr()));
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("data-binding-prefix-mappings"),
@@ -336,6 +587,17 @@ void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const
BAD_CAST(m_aDataBindingStoreItemID.toUtf8().getStr()));
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("color"),
BAD_CAST(m_aColor.toUtf8().getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("appearance"),
+ BAD_CAST(m_aAppearance.toUtf8().getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("alias"),
+ BAD_CAST(m_aAlias.toUtf8().getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("tag"), BAD_CAST(m_aTag.toUtf8().getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("id"),
+ BAD_CAST(OString::number(m_nId).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("tab-index"),
+ BAD_CAST(OString::number(m_nTabIndex).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("lock"),
+ BAD_CAST(m_aLock.toUtf8().getStr()));
if (!m_aListItems.empty())
{
@@ -421,7 +683,8 @@ SwContentControlListItem::ItemsFromAny(const css::uno::Any& rVal)
return aRet;
}
-SwTextContentControl* SwTextContentControl::CreateTextContentControl(SwTextNode* pTargetTextNode,
+SwTextContentControl* SwTextContentControl::CreateTextContentControl(SwDoc& rDoc,
+ SwTextNode* pTargetTextNode,
SwFormatContentControl& rAttr,
sal_Int32 nStart,
sal_Int32 nEnd, bool bIsCopy)
@@ -436,17 +699,21 @@ SwTextContentControl* SwTextContentControl::CreateTextContentControl(SwTextNode*
}
rAttr.DoCopy(*pTargetTextNode);
}
- auto pTextContentControl(new SwTextContentControl(rAttr, nStart, nEnd));
+ SwContentControlManager* pManager = &rDoc.GetContentControlManager();
+ auto pTextContentControl(new SwTextContentControl(pManager, rAttr, nStart, nEnd));
return pTextContentControl;
}
-SwTextContentControl::SwTextContentControl(SwFormatContentControl& rAttr, sal_Int32 nStart,
+SwTextContentControl::SwTextContentControl(SwContentControlManager* pManager,
+ SwFormatContentControl& rAttr, sal_Int32 nStart,
sal_Int32 nEnd)
: SwTextAttr(rAttr, nStart)
, SwTextAttrNesting(rAttr, nStart, nEnd)
+ , m_pManager(pManager)
{
rAttr.SetTextAttr(this);
SetHasDummyChar(true);
+ m_pManager->Insert(this);
}
SwTextContentControl::~SwTextContentControl()
@@ -464,9 +731,72 @@ void SwTextContentControl::ChgTextNode(SwTextNode* pNode)
if (rFormatContentControl.GetTextAttr() == this)
{
rFormatContentControl.NotifyChangeTextNode(pNode);
+
+ if (pNode)
+ {
+ m_pManager = &pNode->GetDoc().GetContentControlManager();
+ }
+ else
+ {
+ if (m_pManager)
+ {
+ m_pManager->Erase(this);
+ }
+ m_pManager = nullptr;
+ }
}
}
+void SwTextContentControl::Delete(bool bSaveContents)
+{
+ if (!GetTextNode())
+ return;
+
+ SwPaM aPaM(*GetTextNode(), GetStart(), *GetTextNode(), *End());
+ if (bSaveContents)
+ GetTextNode()->GetDoc().ResetAttrs(aPaM, /*bTextAttr=*/true, { RES_TXTATR_CONTENTCONTROL });
+ else
+ GetTextNode()->GetDoc().getIDocumentContentOperations().DeleteAndJoin(aPaM);
+}
+
+SwTextNode* SwTextContentControl::GetTextNode() const
+{
+ auto& rFormatContentControl = static_cast<const SwFormatContentControl&>(GetAttr());
+ return rFormatContentControl.GetTextNode();
+}
+
+OUString SwTextContentControl::ToString() const
+{
+ if (!GetTextNode())
+ return OUString();
+
+ // Don't select the text attribute itself at the start.
+ sal_Int32 nStart = GetStart() + 1;
+ // Don't select the CH_TXTATR_BREAKWORD itself at the end.
+ sal_Int32 nEnd = *End() - 1;
+
+ SwPaM aPaM(*GetTextNode(), nStart, *GetTextNode(), nEnd);
+ return aPaM.GetText();
+}
+
+void SwTextContentControl::Invalidate()
+{
+ SwDocShell* pDocShell = GetTextNode() ? GetTextNode()->GetDoc().GetDocShell() : nullptr;
+ if (!pDocShell || !pDocShell->GetWrtShell())
+ return;
+
+ // save the cursor
+ // NOTE: needs further testing to see if this is adequate (i.e. in auto-run macros...)
+ pDocShell->GetWrtShell()->Push();
+
+ // visit the control in the text (which makes any necessary visual changes)
+ // NOTE: simply going to a checkbox causes a toggle, unless bOnlyRefresh
+ auto& rFormatContentControl = static_cast<SwFormatContentControl&>(GetAttr());
+ pDocShell->GetWrtShell()->GotoContentControl(rFormatContentControl, /*bOnlyRefresh=*/true);
+
+ pDocShell->GetWrtShell()->Pop(SwCursorShell::PopMode::DeleteCurrent);
+}
+
void SwTextContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwTextContentControl"));
@@ -476,4 +806,57 @@ void SwTextContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const
(void)xmlTextWriterEndElement(pWriter);
}
+SwContentControlManager::SwContentControlManager() {}
+
+void SwContentControlManager::Insert(SwTextContentControl* pTextContentControl)
+{
+ m_aContentControls.push_back(pTextContentControl);
+}
+
+void SwContentControlManager::Erase(SwTextContentControl* pTextContentControl)
+{
+ m_aContentControls.erase(
+ std::remove(m_aContentControls.begin(), m_aContentControls.end(), pTextContentControl),
+ m_aContentControls.end());
+}
+
+SwTextContentControl* SwContentControlManager::Get(size_t nIndex)
+{
+ // Only sort now: the items may not have an associated text node by the time they are inserted
+ // into the container.
+ std::sort(m_aContentControls.begin(), m_aContentControls.end(),
+ [](SwTextContentControl*& pLhs, SwTextContentControl*& pRhs) -> bool {
+ SwNodeOffset nIdxLHS = pLhs->GetTextNode()->GetIndex();
+ SwNodeOffset nIdxRHS = pRhs->GetTextNode()->GetIndex();
+ if (nIdxLHS == nIdxRHS)
+ {
+ return pLhs->GetStart() < pRhs->GetStart();
+ }
+
+ return nIdxLHS < nIdxRHS;
+ });
+
+ return m_aContentControls[nIndex];
+}
+
+SwTextContentControl* SwContentControlManager::UnsortedGet(size_t nIndex)
+{
+ assert(nIndex < m_aContentControls.size());
+ return m_aContentControls[nIndex];
+}
+
+void SwContentControlManager::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwContentControlManager"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this);
+ for (const auto& pContentControl : m_aContentControls)
+ {
+ (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwTextContentControl"));
+ (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", pContentControl);
+ (void)xmlTextWriterEndElement(pWriter);
+ }
+
+ (void)xmlTextWriterEndElement(pWriter);
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/chrfmt.cxx b/sw/source/core/txtnode/chrfmt.cxx
index d2e01640071d..11a89d6eb92d 100644
--- a/sw/source/core/txtnode/chrfmt.cxx
+++ b/sw/source/core/txtnode/chrfmt.cxx
@@ -21,6 +21,7 @@
#include <charfmt.hxx>
#include <charformats.hxx>
+#include <doc.hxx>
void SwCharFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
{
@@ -38,10 +39,26 @@ void SwCharFormat::dumpAsXml(xmlTextWriterPtr pWriter) const
(void)xmlTextWriterEndElement(pWriter);
}
-void SwCharFormat::SetLinkedParaFormat(SwTextFormatColl& rLink) { mpLinkedParaFormat = &rLink; }
+void SwCharFormat::SetLinkedParaFormat(SwTextFormatColl* pLink) { mpLinkedParaFormat = pLink; }
const SwTextFormatColl* SwCharFormat::GetLinkedParaFormat() const { return mpLinkedParaFormat; }
+SwCharFormat::~SwCharFormat()
+{
+ if (GetDoc()->IsInDtor())
+ {
+ return;
+ }
+
+ for (const auto& pTextFormat : *GetDoc()->GetTextFormatColls())
+ {
+ if (pTextFormat->GetLinkedCharFormat() == this)
+ {
+ pTextFormat->SetLinkedCharFormat(nullptr);
+ }
+ }
+}
+
void SwCharFormats::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwCharFormats"));
diff --git a/sw/source/core/txtnode/modeltoviewhelper.cxx b/sw/source/core/txtnode/modeltoviewhelper.cxx
index 1f35cd1ee614..8f0d5ccd7676 100644
--- a/sw/source/core/txtnode/modeltoviewhelper.cxx
+++ b/sw/source/core/txtnode/modeltoviewhelper.cxx
@@ -140,8 +140,16 @@ ModelToViewHelper::ModelToViewHelper(const SwTextNode &rNode,
// skip it, must be handled in loop below
if (pFieldMark->GetMarkStart().nNode < rNode)
{
- SwPosition const sepPos(::sw::mark::FindFieldSep(*pFieldMark));
- startedFields.emplace_front(pFieldMark, sepPos.nNode < rNode);
+ // this can be a nested field's end - skip over those!
+ if (pFieldMark->GetMarkEnd().nNode < rNode)
+ {
+ assert(cursor.GetPoint()->nNode.GetNode().GetTextNode()->GetText()[cursor.GetPoint()->nContent.GetIndex()] == CH_TXT_ATR_FIELDEND);
+ }
+ else
+ {
+ SwPosition const sepPos(::sw::mark::FindFieldSep(*pFieldMark));
+ startedFields.emplace_front(pFieldMark, sepPos.nNode < rNode);
+ }
*cursor.GetPoint() = pFieldMark->GetMarkStart();
}
if (!cursor.Move(fnMoveBackward, GoInContent))
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 74ae4c2cb0c3..b3880c24fcc2 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -187,7 +187,6 @@ SwTextNode *SwNodes::MakeTextNode( const SwNodeIndex & rWhere,
SwTextNode::SwTextNode( const SwNodeIndex &rWhere, SwTextFormatColl *pTextColl, const SfxItemSet* pAutoAttr )
: SwContentNode( rWhere, SwNodeType::Text, pTextColl ),
- m_pParaIdleData_Impl(nullptr),
m_bContainsHiddenChars(false),
m_bHiddenCharsHidePara(false),
m_bRecalcHiddenCharFlags(false),
@@ -197,7 +196,6 @@ SwTextNode::SwTextNode( const SwNodeIndex &rWhere, SwTextFormatColl *pTextColl,
mbInSetOrResetAttr( false ),
m_bInUndo(false)
{
- InitSwParaStatistics( true );
if( pAutoAttr )
SetAttr( *pAutoAttr );
@@ -249,7 +247,6 @@ SwTextNode::~SwTextNode()
RemoveFromList();
- InitSwParaStatistics( false );
DelFrames(nullptr); // must be called here while it's still a SwTextNode
DelFrames_TextNodePart();
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
@@ -468,7 +465,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
{
pNode->SetWrong( GetWrong()->SplitList( nSplitPos ) );
}
- SetWrongDirty(WrongState::TODO);
+ SetWrongDirty(sw::WrongState::TODO);
if( GetGrammarCheck() )
{
@@ -484,6 +481,9 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
}
SetSmartTagDirty( true );
+ resetAndQueueAccessibilityCheck();
+ pNode->resetAndQueueAccessibilityCheck();
+
if ( pNode->HasHints() )
{
if ( pNode->m_pSwpHints->CanBeDeleted() )
@@ -573,7 +573,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
else
{
std::unique_ptr<SwWrongList> pList = ReleaseWrong();
- SetWrongDirty(WrongState::TODO);
+ SetWrongDirty(sw::WrongState::TODO);
std::unique_ptr<SwGrammarMarkUp> pList3 = ReleaseGrammarCheck();
SetGrammarCheckDirty( true );
@@ -621,6 +621,9 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
SetSmartTags( std::move(pList2) );
}
+ resetAndQueueAccessibilityCheck();
+ pNode->resetAndQueueAccessibilityCheck();
+
if (pContentIndexRestore)
{ // call before making frames and before RegisterToNode
(*pContentIndexRestore)(pNode, sw::mark::RestoreMode::NonFlys, false);
@@ -999,7 +1002,7 @@ SwContentNode *SwTextNode::JoinNext()
if( pList )
{
pList->JoinList( pTextNode->GetWrong(), nOldLen );
- SetWrongDirty(WrongState::TODO);
+ SetWrongDirty(sw::WrongState::TODO);
}
else
{
@@ -1007,7 +1010,7 @@ SwContentNode *SwTextNode::JoinNext()
if( pList )
{
pList->Move( 0, nOldLen );
- SetWrongDirty(WrongState::TODO);
+ SetWrongDirty(sw::WrongState::TODO);
}
}
@@ -1079,6 +1082,8 @@ SwContentNode *SwTextNode::JoinNext()
SetGrammarCheck( std::move(pList3) );
SetSmartTags( std::move(pList2) );
+ resetAndQueueAccessibilityCheck();
+
if (bOldHasNumberingWhichNeedsLayoutUpdate || HasNumberingWhichNeedsLayoutUpdate(*this))
{
// Repaint all text frames that belong to this numbering to avoid outdated generated
@@ -1111,7 +1116,7 @@ void SwTextNode::JoinPrev()
if( pList )
{
pList->JoinList( GetWrong(), Len() );
- SetWrongDirty(WrongState::TODO);
+ SetWrongDirty(sw::WrongState::TODO);
ClearWrong();
}
else
@@ -1120,7 +1125,7 @@ void SwTextNode::JoinPrev()
if( pList )
{
pList->Move( 0, nLen );
- SetWrongDirty(WrongState::TODO);
+ SetWrongDirty(sw::WrongState::TODO);
}
}
@@ -1180,6 +1185,7 @@ void SwTextNode::JoinPrev()
SetWrong( std::move(pList) );
SetGrammarCheck( std::move(pList3) );
SetSmartTags( std::move(pList2) );
+ resetAndQueueAccessibilityCheck();
InvalidateNumRule();
sw::CheckResetRedlineMergeFlag(*this,
eOldMergeFlag == SwNode::Merge::NonFirst
@@ -1775,7 +1781,7 @@ const SwTextInputField* SwTextNode::GetOverlappingInputField( const SwTextAttr&
void SwTextNode::DelFrames_TextNodePart()
{
SetWrong( nullptr );
- SetWrongDirty(WrongState::TODO);
+ SetWrongDirty(sw::WrongState::TODO);
SetGrammarCheck( nullptr );
SetGrammarCheckDirty( true );
diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx
index f5f1a1e7b469..c2d37e058c3b 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -1160,7 +1160,7 @@ SwTextAttr* MakeTextAttr(
break;
case RES_TXTATR_CONTENTCONTROL:
pNew = SwTextContentControl::CreateTextContentControl(
- pTextNode, static_cast<SwFormatContentControl&>(rNew), nStt, nEnd,
+ rDoc, pTextNode, static_cast<SwFormatContentControl&>(rNew), nStt, nEnd,
bIsCopy == CopyOrNewType::Copy);
break;
default:
@@ -1687,6 +1687,32 @@ bool SwTextNode::InsertHint( SwTextAttr * const pAttr, const SetAttrMode nMode )
}
}
+ if (bInsertHint)
+ {
+ // Handle the invariant that a plain text content control has the same character formatting
+ // for all of its content.
+ auto* pTextContentControl = static_txtattr_cast<SwTextContentControl*>(
+ GetTextAttrAt(pAttr->GetStart(), RES_TXTATR_CONTENTCONTROL, PARENT));
+ if (pTextContentControl)
+ {
+ auto& rFormatContentControl
+ = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
+ std::shared_ptr<SwContentControl> pContentControl
+ = rFormatContentControl.GetContentControl();
+ if (pAttr->End() != nullptr && pContentControl->GetPlainText())
+ {
+ if (pAttr->GetStart() > pTextContentControl->GetStart())
+ {
+ pAttr->SetStart(pTextContentControl->GetStart());
+ }
+ if (*pAttr->End() < *pTextContentControl->End())
+ {
+ pAttr->SetEnd(*pTextContentControl->End());
+ }
+ }
+ }
+ }
+
const bool bRet = bInsertHint
&& m_pSwpHints->TryInsertHint( pAttr, *this, nMode );
@@ -3302,13 +3328,12 @@ bool SwpHints::TryInsertHint(
{
// There may be more than one character style at the current position.
// Take care of the sort number.
- // Special case ruby portion: During import, the ruby attribute is set
- // multiple times
- // Special case hyperlink: During import, the ruby attribute is set
- // multiple times
// FME 2007-11-08 #i82989# in NOHINTADJUST mode, we want to insert
// character attributes directly
- if ( RES_TXTATR_CHARFMT == nWhich && !bNoHintAdjustMode )
+ if (!bNoHintAdjustMode
+ && ( (RES_TXTATR_CHARFMT == nWhich)
+ // tdf#149978 also for import of automatic styles, could be produced by non-LO application
+ || (RES_TXTATR_AUTOFMT == nWhich && rNode.GetDoc().IsInXMLImport())))
{
BuildPortions( rNode, *pHint, nMode );
}
diff --git a/sw/source/core/txtnode/txtatr2.cxx b/sw/source/core/txtnode/txtatr2.cxx
index 96c905bb4d76..2b51b45ffbec 100644
--- a/sw/source/core/txtnode/txtatr2.cxx
+++ b/sw/source/core/txtnode/txtatr2.cxx
@@ -131,23 +131,14 @@ SwCharFormat* SwTextINetFormat::GetCharFormat()
// JP 10.02.2000, Bug 72806: don't modify the doc for getting the
// correct charstyle.
- bool bResetMod = !rDoc.getIDocumentState().IsModified();
- Link<bool,void> aOle2Lnk;
- if ( bResetMod )
- {
- aOle2Lnk = rDoc.GetOle2Link();
- rDoc.SetOle2Link( Link<bool,void>() );
- }
+ bool bModifiedEnabled = rDoc.getIDocumentState().IsEnableSetModified();
+ rDoc.getIDocumentState().SetEnableSetModified(false);
pRet = IsPoolUserFormat( nId )
? rDoc.FindCharFormatByName( rStr )
: rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool( nId );
- if ( bResetMod )
- {
- rDoc.getIDocumentState().ResetModified();
- rDoc.SetOle2Link( aOle2Lnk );
- }
+ rDoc.getIDocumentState().SetEnableSetModified(bModifiedEnabled);
}
if ( pRet )
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index 74ae7cf1d3c2..59626eaf6d90 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -97,33 +97,6 @@ namespace
}
}
-struct SwParaIdleData_Impl
-{
- std::unique_ptr<SwWrongList> pWrong; // for spell checking
- std::unique_ptr<SwGrammarMarkUp> pGrammarCheck; // for grammar checking / proof reading
- std::unique_ptr<SwWrongList> pSmartTags;
- sal_uLong nNumberOfWords;
- sal_uLong nNumberOfAsianWords;
- sal_uLong nNumberOfChars;
- sal_uLong nNumberOfCharsExcludingSpaces;
- bool bWordCountDirty;
- SwTextNode::WrongState eWrongDirty; ///< online spell checking needed/done?
- bool bGrammarCheckDirty;
- bool bSmartTagDirty;
- bool bAutoComplDirty; ///< auto complete list dirty
-
- SwParaIdleData_Impl() :
- nNumberOfWords ( 0 ),
- nNumberOfAsianWords ( 0 ),
- nNumberOfChars ( 0 ),
- nNumberOfCharsExcludingSpaces ( 0 ),
- bWordCountDirty ( true ),
- eWrongDirty ( SwTextNode::WrongState::TODO ),
- bGrammarCheckDirty ( true ),
- bSmartTagDirty ( true ),
- bAutoComplDirty ( true ) {};
-};
-
static bool lcl_HasComments(const SwTextNode& rNode)
{
sal_Int32 nPosition = rNode.GetText().indexOf(CH_TXTATR_INWORD);
@@ -1409,14 +1382,14 @@ SwRect SwTextFrame::AutoSpell_(SwTextNode & rNode, sal_Int32 nActPos)
pNode->SetWrongDirty(
(COMPLETE_STRING != pNode->GetWrong()->GetBeginInv())
? (bPending
- ? SwTextNode::WrongState::PENDING
- : SwTextNode::WrongState::TODO)
- : SwTextNode::WrongState::DONE);
+ ? sw::WrongState::PENDING
+ : sw::WrongState::TODO)
+ : sw::WrongState::DONE);
if( !pNode->GetWrong()->Count() && ! pNode->IsWrongDirty() )
pNode->ClearWrong();
}
else
- pNode->SetWrongDirty(SwTextNode::WrongState::DONE);
+ pNode->SetWrongDirty(sw::WrongState::DONE);
if( bAddAutoCmpl )
pNode->SetAutoCompleteWordDirty( false );
@@ -2047,13 +2020,11 @@ bool SwTextNode::CountWords( SwDocStat& rStat,
if ( bCountAll && !IsWordCountDirty() )
{
// accumulate into DocStat record to return the values
- if (m_pParaIdleData_Impl)
- {
- rStat.nWord += m_pParaIdleData_Impl->nNumberOfWords;
- rStat.nAsianWord += m_pParaIdleData_Impl->nNumberOfAsianWords;
- rStat.nChar += m_pParaIdleData_Impl->nNumberOfChars;
- rStat.nCharExcludingSpaces += m_pParaIdleData_Impl->nNumberOfCharsExcludingSpaces;
- }
+
+ rStat.nWord += m_aParagraphIdleData.nNumberOfWords;
+ rStat.nAsianWord += m_aParagraphIdleData.nNumberOfAsianWords;
+ rStat.nChar += m_aParagraphIdleData.nNumberOfChars;
+ rStat.nCharExcludingSpaces += m_aParagraphIdleData.nNumberOfCharsExcludingSpaces;
return false;
}
@@ -2148,13 +2119,10 @@ bool SwTextNode::CountWords( SwDocStat& rStat,
// If counting the whole para then update cached values and mark clean
if ( bCountAll )
{
- if ( m_pParaIdleData_Impl )
- {
- m_pParaIdleData_Impl->nNumberOfWords = nTmpWords;
- m_pParaIdleData_Impl->nNumberOfAsianWords = nTmpAsianWords;
- m_pParaIdleData_Impl->nNumberOfChars = nTmpChars;
- m_pParaIdleData_Impl->nNumberOfCharsExcludingSpaces = nTmpCharsExcludingSpaces;
- }
+ m_aParagraphIdleData.nNumberOfWords = nTmpWords;
+ m_aParagraphIdleData.nNumberOfAsianWords = nTmpAsianWords;
+ m_aParagraphIdleData.nNumberOfChars = nTmpChars;
+ m_aParagraphIdleData.nNumberOfCharsExcludingSpaces = nTmpCharsExcludingSpaces;
SetWordCountDirty( false );
}
// accumulate into DocStat record to return the values
@@ -2166,72 +2134,50 @@ bool SwTextNode::CountWords( SwDocStat& rStat,
return true;
}
-// Paragraph statistics start -->
-
-void SwTextNode::InitSwParaStatistics( bool bNew )
-{
- if ( bNew )
- {
- m_pParaIdleData_Impl = new SwParaIdleData_Impl;
- }
- else if ( m_pParaIdleData_Impl )
- {
- m_pParaIdleData_Impl->pWrong.reset();
- m_pParaIdleData_Impl->pGrammarCheck.reset();
- m_pParaIdleData_Impl->pSmartTags.reset();
- delete m_pParaIdleData_Impl;
- m_pParaIdleData_Impl = nullptr;
- }
-}
-
void SwTextNode::SetWrong( std::unique_ptr<SwWrongList> pNew )
{
- if ( m_pParaIdleData_Impl )
- m_pParaIdleData_Impl->pWrong = std::move(pNew);
+ m_aParagraphIdleData.pWrong = std::move(pNew);
}
void SwTextNode::ClearWrong()
{
- if ( m_pParaIdleData_Impl )
- m_pParaIdleData_Impl->pWrong.reset();
+ m_aParagraphIdleData.pWrong.reset();
}
std::unique_ptr<SwWrongList> SwTextNode::ReleaseWrong()
{
- return m_pParaIdleData_Impl ? std::move(m_pParaIdleData_Impl->pWrong) : nullptr;
+ return std::move(m_aParagraphIdleData.pWrong);
}
SwWrongList* SwTextNode::GetWrong()
{
- return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong.get() : nullptr;
+ return m_aParagraphIdleData.pWrong.get();
}
// #i71360#
const SwWrongList* SwTextNode::GetWrong() const
{
- return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pWrong.get() : nullptr;
+ return m_aParagraphIdleData.pWrong.get();
}
void SwTextNode::SetGrammarCheck( std::unique_ptr<SwGrammarMarkUp> pNew )
{
- if ( m_pParaIdleData_Impl )
- m_pParaIdleData_Impl->pGrammarCheck = std::move(pNew);
+ m_aParagraphIdleData.pGrammarCheck = std::move(pNew);
}
void SwTextNode::ClearGrammarCheck()
{
- if ( m_pParaIdleData_Impl )
- m_pParaIdleData_Impl->pGrammarCheck.reset();
+ m_aParagraphIdleData.pGrammarCheck.reset();
}
std::unique_ptr<SwGrammarMarkUp> SwTextNode::ReleaseGrammarCheck()
{
- return m_pParaIdleData_Impl ? std::move(m_pParaIdleData_Impl->pGrammarCheck) : nullptr;
+ return std::move(m_aParagraphIdleData.pGrammarCheck);
}
SwGrammarMarkUp* SwTextNode::GetGrammarCheck()
{
- return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pGrammarCheck.get() : nullptr;
+ return m_aParagraphIdleData.pGrammarCheck.get();
}
SwWrongList const* SwTextNode::GetGrammarCheck() const
@@ -2244,24 +2190,22 @@ void SwTextNode::SetSmartTags( std::unique_ptr<SwWrongList> pNew )
OSL_ENSURE( !pNew || SwSmartTagMgr::Get().IsSmartTagsEnabled(),
"Weird - we have a smart tag list without any recognizers?" );
- if ( m_pParaIdleData_Impl )
- m_pParaIdleData_Impl->pSmartTags = std::move(pNew);
+ m_aParagraphIdleData.pSmartTags = std::move(pNew);
}
void SwTextNode::ClearSmartTags()
{
- if ( m_pParaIdleData_Impl )
- m_pParaIdleData_Impl->pSmartTags.reset();
+ m_aParagraphIdleData.pSmartTags.reset();
}
std::unique_ptr<SwWrongList> SwTextNode::ReleaseSmartTags()
{
- return m_pParaIdleData_Impl ? std::move(m_pParaIdleData_Impl->pSmartTags) : nullptr;
+ return std::move(m_aParagraphIdleData.pSmartTags);
}
SwWrongList* SwTextNode::GetSmartTags()
{
- return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pSmartTags.get() : nullptr;
+ return m_aParagraphIdleData.pSmartTags.get();
}
SwWrongList const* SwTextNode::GetSmartTags() const
@@ -2271,72 +2215,57 @@ SwWrongList const* SwTextNode::GetSmartTags() const
void SwTextNode::SetWordCountDirty( bool bNew ) const
{
- if ( m_pParaIdleData_Impl )
- {
- m_pParaIdleData_Impl->bWordCountDirty = bNew;
- }
+ m_aParagraphIdleData.bWordCountDirty = bNew;
}
bool SwTextNode::IsWordCountDirty() const
{
- return m_pParaIdleData_Impl && m_pParaIdleData_Impl->bWordCountDirty;
+ return m_aParagraphIdleData.bWordCountDirty;
}
-void SwTextNode::SetWrongDirty(WrongState eNew) const
+void SwTextNode::SetWrongDirty(sw::WrongState eNew) const
{
- if ( m_pParaIdleData_Impl )
- {
- m_pParaIdleData_Impl->eWrongDirty = eNew;
- }
+ m_aParagraphIdleData.eWrongDirty = eNew;
}
-auto SwTextNode::GetWrongDirty() const -> WrongState
+sw::WrongState SwTextNode::GetWrongDirty() const
{
- return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->eWrongDirty : WrongState::DONE;
+ return m_aParagraphIdleData.eWrongDirty;
}
bool SwTextNode::IsWrongDirty() const
{
- return m_pParaIdleData_Impl && m_pParaIdleData_Impl->eWrongDirty != WrongState::DONE;
+ return m_aParagraphIdleData.eWrongDirty != sw::WrongState::DONE;
}
void SwTextNode::SetGrammarCheckDirty( bool bNew ) const
{
- if ( m_pParaIdleData_Impl )
- {
- m_pParaIdleData_Impl->bGrammarCheckDirty = bNew;
- }
+ m_aParagraphIdleData.bGrammarCheckDirty = bNew;
}
bool SwTextNode::IsGrammarCheckDirty() const
{
- return m_pParaIdleData_Impl && m_pParaIdleData_Impl->bGrammarCheckDirty;
+ return m_aParagraphIdleData.bGrammarCheckDirty;
}
void SwTextNode::SetSmartTagDirty( bool bNew ) const
{
- if ( m_pParaIdleData_Impl )
- {
- m_pParaIdleData_Impl->bSmartTagDirty = bNew;
- }
+ m_aParagraphIdleData.bSmartTagDirty = bNew;
}
bool SwTextNode::IsSmartTagDirty() const
{
- return m_pParaIdleData_Impl && m_pParaIdleData_Impl->bSmartTagDirty;
+ return m_aParagraphIdleData.bSmartTagDirty;
}
void SwTextNode::SetAutoCompleteWordDirty( bool bNew ) const
{
- if ( m_pParaIdleData_Impl )
- {
- m_pParaIdleData_Impl->bAutoComplDirty = bNew;
- }
+ m_aParagraphIdleData.bAutoComplDirty = bNew;
}
bool SwTextNode::IsAutoCompleteWordDirty() const
{
- return m_pParaIdleData_Impl && m_pParaIdleData_Impl->bAutoComplDirty;
+ return m_aParagraphIdleData.bAutoComplDirty;
}
// <-- Paragraph statistics end
diff --git a/sw/source/core/undo/docundo.cxx b/sw/source/core/undo/docundo.cxx
index 07998e9404ef..1933741ea971 100644
--- a/sw/source/core/undo/docundo.cxx
+++ b/sw/source/core/undo/docundo.cxx
@@ -29,6 +29,7 @@
#include <pam.hxx>
#include <swundo.hxx>
#include <UndoCore.hxx>
+#include <wrtsh.hxx>
#include <editsh.hxx>
#include <unobaseclass.hxx>
#include <IDocumentDrawModelAccess.hxx>
@@ -415,7 +416,7 @@ bool UndoManager::IsViewUndoActionIndependent(const SwView* pView, sal_uInt16& r
for (size_t i = 0; i < GetRedoActionCount(); ++i)
{
auto pRedoAction = dynamic_cast<const SwUndo*>(GetRedoAction(i));
- if (!pRedoAction || pViewSwAction->GetId() != SwUndoId::TYPING)
+ if (!pRedoAction || pRedoAction->GetId() != SwUndoId::TYPING)
{
return false;
}
@@ -665,8 +666,10 @@ bool UndoManager::impl_DoUndoRedo(UndoOrRedoType undoOrRedo, size_t nUndoOffset)
UnoActionContext c(& rDoc); // exception-safe StartAllAction/EndAllAction
- SwEditShell *const pEditShell( rDoc.GetEditShell() );
-
+ SwView* pViewShell = dynamic_cast<SwView*>(SfxViewShell::Current());
+ SwEditShell *const pEditShell(
+ comphelper::LibreOfficeKit::isActive() && pViewShell ? pViewShell->GetWrtShellPtr()
+ : rDoc.GetEditShell());
OSL_ENSURE(pEditShell, "sw::UndoManager needs a SwEditShell!");
if (!pEditShell)
{
diff --git a/sw/source/core/undo/unattr.cxx b/sw/source/core/undo/unattr.cxx
index 9d279860c086..13977d5479f3 100644
--- a/sw/source/core/undo/unattr.cxx
+++ b/sw/source/core/undo/unattr.cxx
@@ -55,6 +55,7 @@
#include <charfmt.hxx>
#include <calbck.hxx>
#include <frameformats.hxx>
+#include <editsh.hxx>
SwUndoFormatAttrHelper::SwUndoFormatAttrHelper(SwFormat& rFormat, bool bSvDrwPt)
: SwClient(&rFormat)
@@ -575,6 +576,10 @@ void SwUndoResetAttr::UndoImpl(::sw::UndoRedoContext & rContext)
pTNd->DontExpandFormat( aIdx, false );
}
}
+ else if (m_nFormatId == RES_TXTATR_REFMARK)
+ {
+ rDoc.GetEditShell()->SwViewShell::UpdateFields();
+ }
AddUndoRedoPaM(rContext);
}
@@ -626,6 +631,27 @@ void SwUndoResetAttr::RedoImpl(::sw::UndoRedoContext & rContext)
}
}
break;
+ case RES_TXTATR_REFMARK:
+ {
+ SfxItemPool::Item2Range aRange = rDoc.GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK);
+ SwHistoryHint* pHistoryHint = GetHistory()[0];
+ if (pHistoryHint && HSTRY_SETREFMARKHNT == pHistoryHint->Which())
+ {
+ for (const SfxPoolItem* pItem : aRange)
+ {
+ assert(dynamic_cast<const SwFormatRefMark*>(pItem));
+ const auto pFormatRefMark = static_cast<const SwFormatRefMark*>(pItem);
+ if (static_cast<SwHistorySetRefMark*>(pHistoryHint)->GetRefName() ==
+ pFormatRefMark->GetRefName())
+ {
+ rDoc.DeleteFormatRefMark(pFormatRefMark);
+ rDoc.GetEditShell()->SwViewShell::UpdateFields();
+ break;
+ }
+ }
+ }
+ }
+ break;
}
}
@@ -750,7 +776,8 @@ void SwUndoAttr::UndoImpl(::sw::UndoRedoContext & rContext)
m_pHistory->SetTmpEnd( m_pHistory->Count() );
// set cursor onto Undo area
- AddUndoRedoPaM(rContext);
+ if (!(m_nInsertFlags & SetAttrMode::NO_CURSOR_CHANGE))
+ AddUndoRedoPaM(rContext);
}
void SwUndoAttr::RepeatImpl(::sw::RepeatContext & rContext)
@@ -767,10 +794,9 @@ void SwUndoAttr::RepeatImpl(::sw::RepeatContext & rContext)
}
}
-void SwUndoAttr::RedoImpl(::sw::UndoRedoContext & rContext)
+void SwUndoAttr::redoAttribute(SwPaM& rPam, sw::UndoRedoContext & rContext)
{
SwDoc & rDoc = rContext.GetDoc();
- SwPaM & rPam = AddUndoRedoPaM(rContext);
// Restore pointer to char format from name
if (!m_aChrFormatName.isEmpty())
@@ -806,6 +832,21 @@ void SwUndoAttr::RedoImpl(::sw::UndoRedoContext & rContext)
}
}
+void SwUndoAttr::RedoImpl(sw::UndoRedoContext & rContext)
+{
+ if (m_nInsertFlags & SetAttrMode::NO_CURSOR_CHANGE)
+ {
+ SwPaM aPam(rContext.GetDoc().GetNodes().GetEndOfContent());
+ SetPaM(aPam, false);
+ redoAttribute(aPam, rContext);
+ }
+ else
+ {
+ SwPaM& rPam = AddUndoRedoPaM(rContext);
+ redoAttribute(rPam, rContext);
+ }
+}
+
void SwUndoAttr::RemoveIdx( SwDoc& rDoc )
{
if ( SfxItemState::SET != m_AttrSet.GetItemState( RES_TXTATR_FTN, false ))
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index c23aeba3ba51..b2248ee3bcf9 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -653,6 +653,9 @@ OUString GetUndoComment(SwUndoId eId)
case SwUndoId::INSERT_FORM_FIELD:
pId = STR_UNDO_INSERT_FORM_FIELD;
break;
+ case SwUndoId::INSERT_PAGE_NUMBER:
+ pId = STR_UNDO_INSERT_PAGE_NUMBER;
+ break;
}
assert(pId);
diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx
index 848668641769..1e47d7799ef3 100644
--- a/sw/source/core/undo/untbl.cxx
+++ b/sw/source/core/undo/untbl.cxx
@@ -294,6 +294,8 @@ void SwUndoInsTable::UndoImpl(::sw::UndoRedoContext & rContext)
if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK,
false, &pItem ) )
pNextNd->SetAttr( *pItem );
+
+ ::sw::NotifyTableCollapsedParagraph(pNextNd, nullptr);
}
m_sTableName = pTableNd->GetTable().GetFrameFormat()->GetName();
diff --git a/sw/source/core/unocore/unobkm.cxx b/sw/source/core/unocore/unobkm.cxx
index e14df5b3a803..778a2f621af8 100644
--- a/sw/source/core/unocore/unobkm.cxx
+++ b/sw/source/core/unocore/unobkm.cxx
@@ -403,6 +403,8 @@ void SAL_CALL
SwXBookmark::setPropertyValue(const OUString& PropertyName,
const uno::Any& rValue)
{
+ SolarMutexGuard g;
+
if (PropertyName == UNO_NAME_BOOKMARK_HIDDEN)
{
bool bNewValue = false;
diff --git a/sw/source/core/unocore/unocontentcontrol.cxx b/sw/source/core/unocore/unocontentcontrol.cxx
index c84cff5837d0..1c37d5cbfc05 100644
--- a/sw/source/core/unocore/unocontentcontrol.cxx
+++ b/sw/source/core/unocore/unocontentcontrol.cxx
@@ -22,6 +22,7 @@
#include <mutex>
#include <com/sun/star/text/XWordCursor.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <comphelper/interfacecontainer4.hxx>
#include <comphelper/servicehelper.hxx>
@@ -166,11 +167,20 @@ public:
OUString m_aDateFormat;
OUString m_aDateLanguage;
OUString m_aCurrentDate;
+ bool m_bPlainText;
+ bool m_bComboBox;
+ bool m_bDropDown;
OUString m_aPlaceholderDocPart;
OUString m_aDataBindingPrefixMappings;
OUString m_aDataBindingXpath;
OUString m_aDataBindingStoreItemID;
OUString m_aColor;
+ OUString m_aAppearance;
+ OUString m_aAlias;
+ OUString m_aTag;
+ sal_Int32 m_nId;
+ sal_uInt32 m_nTabIndex;
+ OUString m_aLock;
Impl(SwXContentControl& rThis, SwDoc& rDoc, SwContentControl* pContentControl,
const uno::Reference<text::XText>& xParentText,
@@ -186,6 +196,11 @@ public:
, m_bChecked(false)
, m_bPicture(false)
, m_bDate(false)
+ , m_bPlainText(false)
+ , m_bComboBox(false)
+ , m_bDropDown(false)
+ , m_nId(0)
+ , m_nTabIndex(0)
{
if (m_pContentControl)
{
@@ -534,11 +549,20 @@ void SwXContentControl::AttachImpl(const uno::Reference<text::XTextRange>& xText
pContentControl->SetDateFormat(m_pImpl->m_aDateFormat);
pContentControl->SetDateLanguage(m_pImpl->m_aDateLanguage);
pContentControl->SetCurrentDate(m_pImpl->m_aCurrentDate);
+ pContentControl->SetPlainText(m_pImpl->m_bPlainText);
+ pContentControl->SetComboBox(m_pImpl->m_bComboBox);
+ pContentControl->SetDropDown(m_pImpl->m_bDropDown);
pContentControl->SetPlaceholderDocPart(m_pImpl->m_aPlaceholderDocPart);
pContentControl->SetDataBindingPrefixMappings(m_pImpl->m_aDataBindingPrefixMappings);
pContentControl->SetDataBindingXpath(m_pImpl->m_aDataBindingXpath);
pContentControl->SetDataBindingStoreItemID(m_pImpl->m_aDataBindingStoreItemID);
pContentControl->SetColor(m_pImpl->m_aColor);
+ pContentControl->SetAppearance(m_pImpl->m_aAppearance);
+ pContentControl->SetAlias(m_pImpl->m_aAlias);
+ pContentControl->SetTag(m_pImpl->m_aTag);
+ pContentControl->SetId(m_pImpl->m_nId);
+ pContentControl->SetTabIndex(m_pImpl->m_nTabIndex);
+ pContentControl->SetLock(m_pImpl->m_aLock);
SwFormatContentControl aContentControl(pContentControl, nWhich);
bool bSuccess
@@ -772,10 +796,21 @@ void SAL_CALL SwXContentControl::setPropertyValue(const OUString& rPropertyName,
if (m_pImpl->m_bIsDescriptor)
{
m_pImpl->m_aListItems = aItems;
+
+ if (!m_pImpl->m_bComboBox && !m_pImpl->m_bDropDown)
+ {
+ m_pImpl->m_bDropDown = true;
+ }
}
else
{
m_pImpl->m_pContentControl->SetListItems(aItems);
+
+ if (!m_pImpl->m_pContentControl->GetComboBox()
+ && !m_pImpl->m_pContentControl->GetDropDown())
+ {
+ m_pImpl->m_pContentControl->SetDropDown(true);
+ }
}
}
else if (rPropertyName == UNO_NAME_PICTURE)
@@ -853,6 +888,51 @@ void SAL_CALL SwXContentControl::setPropertyValue(const OUString& rPropertyName,
}
}
}
+ else if (rPropertyName == UNO_NAME_PLAIN_TEXT)
+ {
+ bool bValue;
+ if (rValue >>= bValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_bPlainText = bValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetPlainText(bValue);
+ }
+ }
+ }
+ else if (rPropertyName == UNO_NAME_COMBO_BOX)
+ {
+ bool bValue;
+ if (rValue >>= bValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_bComboBox = bValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetComboBox(bValue);
+ }
+ }
+ }
+ else if (rPropertyName == UNO_NAME_DROP_DOWN)
+ {
+ bool bValue;
+ if (rValue >>= bValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_bDropDown = bValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetDropDown(bValue);
+ }
+ }
+ }
else if (rPropertyName == UNO_NAME_PLACEHOLDER_DOC_PART)
{
OUString aValue;
@@ -928,6 +1008,96 @@ void SAL_CALL SwXContentControl::setPropertyValue(const OUString& rPropertyName,
}
}
}
+ else if (rPropertyName == UNO_NAME_APPEARANCE)
+ {
+ OUString aValue;
+ if (rValue >>= aValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_aAppearance = aValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetAppearance(aValue);
+ }
+ }
+ }
+ else if (rPropertyName == UNO_NAME_ALIAS)
+ {
+ OUString aValue;
+ if (rValue >>= aValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_aAlias = aValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetAlias(aValue);
+ }
+ }
+ }
+ else if (rPropertyName == UNO_NAME_TAG)
+ {
+ OUString aValue;
+ if (rValue >>= aValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_aTag = aValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetTag(aValue);
+ }
+ }
+ }
+ else if (rPropertyName == UNO_NAME_ID)
+ {
+ sal_Int32 nValue = 0;
+ if (rValue >>= nValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_nId = nValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetId(nValue);
+ }
+ }
+ }
+ else if (rPropertyName == UNO_NAME_TAB_INDEX)
+ {
+ sal_uInt32 nValue = 0;
+ if (rValue >>= nValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_nTabIndex = nValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetTabIndex(nValue);
+ }
+ }
+ }
+ else if (rPropertyName == UNO_NAME_LOCK)
+ {
+ OUString aValue;
+ if (rValue >>= aValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_aLock = aValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetLock(aValue);
+ }
+ }
+ }
else
{
throw beans::UnknownPropertyException();
@@ -1062,6 +1232,39 @@ uno::Any SAL_CALL SwXContentControl::getPropertyValue(const OUString& rPropertyN
aRet <<= m_pImpl->m_pContentControl->GetCurrentDate();
}
}
+ else if (rPropertyName == UNO_NAME_PLAIN_TEXT)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_bPlainText;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetPlainText();
+ }
+ }
+ else if (rPropertyName == UNO_NAME_COMBO_BOX)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_bComboBox;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetComboBox();
+ }
+ }
+ else if (rPropertyName == UNO_NAME_DROP_DOWN)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_bDropDown;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetDropDown();
+ }
+ }
else if (rPropertyName == UNO_NAME_PLACEHOLDER_DOC_PART)
{
if (m_pImpl->m_bIsDescriptor)
@@ -1117,6 +1320,79 @@ uno::Any SAL_CALL SwXContentControl::getPropertyValue(const OUString& rPropertyN
aRet <<= m_pImpl->m_pContentControl->GetColor();
}
}
+ else if (rPropertyName == UNO_NAME_APPEARANCE)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_aAppearance;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetAppearance();
+ }
+ }
+ else if (rPropertyName == UNO_NAME_ALIAS)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_aAlias;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetAlias();
+ }
+ }
+ else if (rPropertyName == UNO_NAME_TAG)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_aTag;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetTag();
+ }
+ }
+ else if (rPropertyName == UNO_NAME_DATE_STRING)
+ {
+ if (!m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetDateString();
+ }
+ }
+ else if (rPropertyName == UNO_NAME_ID)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_nId;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetId();
+ }
+ }
+ else if (rPropertyName == UNO_NAME_TAB_INDEX)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_nTabIndex;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetTabIndex();
+ }
+ }
+ else if (rPropertyName == UNO_NAME_LOCK)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_aLock;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetLock();
+ }
+ }
else
{
throw beans::UnknownPropertyException();
@@ -1203,4 +1479,61 @@ uno::Reference<container::XEnumeration> SAL_CALL SwXContentControl::createEnumer
}
}
+SwXContentControls::SwXContentControls(SwDoc* pDoc)
+ : SwUnoCollection(pDoc)
+{
+}
+
+SwXContentControls::~SwXContentControls() {}
+
+sal_Int32 SwXContentControls::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ if (!IsValid())
+ {
+ throw uno::RuntimeException();
+ }
+
+ return GetDoc()->GetContentControlManager().GetCount();
+}
+
+uno::Any SwXContentControls::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+
+ if (!IsValid())
+ {
+ throw uno::RuntimeException();
+ }
+
+ SwContentControlManager& rManager = GetDoc()->GetContentControlManager();
+ if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= rManager.GetCount())
+ {
+ throw lang::IndexOutOfBoundsException();
+ }
+
+ SwTextContentControl* pTextContentControl = rManager.Get(nIndex);
+ const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
+ uno::Reference<css::text::XTextContent> xContentControl
+ = SwXContentControl::CreateXContentControl(*rFormatContentControl.GetContentControl());
+ uno::Any aRet;
+ aRet <<= xContentControl;
+ return aRet;
+}
+
+uno::Type SwXContentControls::getElementType() { return cppu::UnoType<text::XTextContent>::get(); }
+
+sal_Bool SwXContentControls::hasElements()
+{
+ SolarMutexGuard aGuard;
+
+ if (!IsValid())
+ {
+ throw uno::RuntimeException();
+ }
+
+ return !GetDoc()->GetContentControlManager().IsEmpty();
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/unocore/unoflatpara.cxx b/sw/source/core/unocore/unoflatpara.cxx
index a04004124dd1..213d851e70a6 100644
--- a/sw/source/core/unocore/unoflatpara.cxx
+++ b/sw/source/core/unocore/unoflatpara.cxx
@@ -41,7 +41,7 @@
#include <rootfrm.hxx>
#include <poolfmt.hxx>
#include <pagedesc.hxx>
-#include <IGrammarContact.hxx>
+#include <GrammarContact.hxx>
#include <viewopt.hxx>
#include <comphelper/servicehelper.hxx>
#include <comphelper/propertysetinfo.hxx>
@@ -182,7 +182,7 @@ void SAL_CALL SwXFlatParagraph::setChecked( ::sal_Int32 nType, sal_Bool bVal )
if ( text::TextMarkupType::SPELLCHECK == nType )
{
GetTextNode()->SetWrongDirty(
- bVal ? SwTextNode::WrongState::DONE : SwTextNode::WrongState::TODO);
+ bVal ? sw::WrongState::DONE : sw::WrongState::TODO);
}
else if ( text::TextMarkupType::SMARTTAG == nType )
GetTextNode()->SetSmartTagDirty( !bVal );
@@ -190,7 +190,7 @@ void SAL_CALL SwXFlatParagraph::setChecked( ::sal_Int32 nType, sal_Bool bVal )
{
GetTextNode()->SetGrammarCheckDirty( !bVal );
if( bVal )
- ::finishGrammarCheck( *GetTextNode() );
+ sw::finishGrammarCheckFor(*GetTextNode());
}
}
diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx
index bfbd1711e68d..abad86f1ce65 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -1507,6 +1507,9 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s
{ u"" UNO_NAME_PARA_ADJUST, RES_PARATR_ADJUST, cppu::UnoType<sal_Int16>::get(),PropertyAttribute::MAYBEVOID, MID_PARA_ADJUST },
// SvxColorItem
{ u"" UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX },
+ { u"" UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE },
+ { u"" UNO_NAME_CHAR_COLOR_THEME_REFERENCE, RES_CHRATR_COLOR, cppu::UnoType<css::uno::XInterface>::get(), PROPERTY_NONE, MID_COLOR_THEME_REFERENCE },
// SvxShadowedItem
{ u"" UNO_NAME_CHAR_SHADOWED, RES_CHRATR_SHADOWED, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 },
// SvxContouredItem
diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx
index fd5cc2e42fbb..a7bba556ab97 100644
--- a/sw/source/core/unocore/unomap1.cxx
+++ b/sw/source/core/unocore/unomap1.cxx
@@ -188,6 +188,9 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetCharStylePropertyMa
{ u"" UNO_NAME_CHAR_HIGHLIGHT, RES_CHRATR_HIGHLIGHT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_BACK_COLOR },
{ u"" UNO_NAME_CHAR_CASE_MAP, RES_CHRATR_CASEMAP, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0},
{ u"" UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0},
+ { u"" UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX },
+ { u"" UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE },
+ { u"" UNO_NAME_CHAR_COLOR_THEME_REFERENCE, RES_CHRATR_COLOR, cppu::UnoType<css::uno::XInterface>::get(), PROPERTY_NONE, MID_COLOR_THEME_REFERENCE },
{ u"" UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_ALPHA},
{ u"" UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_CROSS_OUT},
{ u"" UNO_NAME_CHAR_CROSSED_OUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
@@ -251,6 +254,9 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetAutoCharStyleProper
{ u"" UNO_NAME_CHAR_HIGHLIGHT, RES_CHRATR_HIGHLIGHT, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, MID_BACK_COLOR },
{ u"" UNO_NAME_CHAR_CASE_MAP, RES_CHRATR_CASEMAP, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0},
{ u"" UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0},
+ { u"" UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX },
+ { u"" UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE },
+ { u"" UNO_NAME_CHAR_COLOR_THEME_REFERENCE, RES_CHRATR_COLOR, cppu::UnoType<css::uno::XInterface>::get(), PROPERTY_NONE, MID_COLOR_THEME_REFERENCE },
{ u"" UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_ALPHA},
{ u"" UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_CROSS_OUT},
{ u"" UNO_NAME_CHAR_CROSSED_OUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},
@@ -1037,11 +1043,21 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetContentControlProper
{ u"" UNO_NAME_DATE_FORMAT, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_DATE_LANGUAGE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_CURRENT_DATE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_PLAIN_TEXT, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_COMBO_BOX, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_DROP_DOWN, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_PLACEHOLDER_DOC_PART, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_DATA_BINDING_PREFIX_MAPPINGS, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_DATA_BINDING_XPATH, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_DATA_BINDING_STORE_ITEM_ID, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_COLOR, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_APPEARANCE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_ALIAS, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_TAG, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_ID, 0, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_TAB_INDEX, 0, cppu::UnoType<sal_uInt32>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_LOCK, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_DATE_STRING, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0 },
{ u"", 0, css::uno::Type(), 0, 0 }
};
diff --git a/sw/source/core/unocore/unomapproperties.hxx b/sw/source/core/unocore/unomapproperties.hxx
index c30572f7a92b..7a604e85f791 100644
--- a/sw/source/core/unocore/unomapproperties.hxx
+++ b/sw/source/core/unocore/unomapproperties.hxx
@@ -122,6 +122,9 @@
{ u"" UNO_NAME_PARA_BACK_COLOR, RES_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, MID_BACK_COLOR }, \
{ u"" UNO_NAME_CHAR_CASE_MAP, RES_CHRATR_CASEMAP, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, 0 }, \
{ u"" UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PropertyAttribute::MAYBEVOID, 0 }, \
+ { u"" UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_COLOR_THEME_INDEX }, \
+ { u"" UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_COLOR_TINT_OR_SHADE }, \
+ { u"" UNO_NAME_CHAR_COLOR_THEME_REFERENCE, RES_CHRATR_COLOR, cppu::UnoType<css::uno::XInterface>::get(), PropertyAttribute::MAYBEVOID, MID_COLOR_THEME_REFERENCE }, \
{ u"" UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_COLOR_ALPHA }, \
{ u"" UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_CROSS_OUT }, \
{ u"" UNO_NAME_CHAR_CROSSED_OUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<bool>::get(), PropertyAttribute::MAYBEVOID, MID_CROSSED_OUT }, \
@@ -364,6 +367,9 @@
{ u"" UNO_NAME_PARA_GRAPHIC_LOCATION, RES_BACKGROUND, cppu::UnoType<css::style::GraphicLocation>::get(), PROPERTY_NONE ,MID_GRAPHIC_POSITION}, \
{ u"" UNO_NAME_CHAR_CASE_MAP, RES_CHRATR_CASEMAP, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0},\
{ u"" UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0},\
+ { u"" UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX },\
+ { u"" UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE },\
+ { u"" UNO_NAME_CHAR_COLOR_THEME_REFERENCE, RES_CHRATR_COLOR, cppu::UnoType<css::uno::XInterface>::get(), PropertyAttribute::MAYBEVOID, MID_COLOR_THEME_REFERENCE }, \
{ u"" UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_ALPHA},\
{ u"" UNO_NAME_CHAR_STRIKEOUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<sal_Int16>::get(), PropertyAttribute::MAYBEVOID, MID_CROSS_OUT},\
{ u"" UNO_NAME_CHAR_CROSSED_OUT, RES_CHRATR_CROSSEDOUT, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0},\
@@ -471,6 +477,9 @@
#define COMMON_ACCESSIBILITY_TEXT_ATTRIBUTE \
{ u"" UNO_NAME_CHAR_BACK_COLOR, RES_CHRATR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE ,MID_BACK_COLOR }, \
{ u"" UNO_NAME_CHAR_COLOR, RES_CHRATR_COLOR, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0}, \
+ { u"" UNO_NAME_CHAR_COLOR_THEME, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_THEME_INDEX }, \
+ { u"" UNO_NAME_CHAR_COLOR_TINT_OR_SHADE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_TINT_OR_SHADE}, \
+ { u"" UNO_NAME_CHAR_COLOR_THEME_REFERENCE, RES_CHRATR_COLOR, cppu::UnoType<css::uno::XInterface>::get(), PropertyAttribute::MAYBEVOID, MID_COLOR_THEME_REFERENCE }, \
{ u"" UNO_NAME_CHAR_TRANSPARENCE, RES_CHRATR_COLOR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_COLOR_ALPHA }, \
{ u"" UNO_NAME_CHAR_CONTOURED, RES_CHRATR_CONTOUR, cppu::UnoType<bool>::get() , PROPERTY_NONE, 0}, \
{ u"" UNO_NAME_CHAR_EMPHASIS, RES_CHRATR_EMPHASIS_MARK, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_EMPHASIS}, \
diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx
index 90072ed52b78..252226ca80cc 100644
--- a/sw/source/core/unocore/unoobj.cxx
+++ b/sw/source/core/unocore/unoobj.cxx
@@ -227,6 +227,57 @@ lcl_setAutoStyle(IStyleAccess & rStyleAccess, const uno::Any & rValue,
rSet.Put(aFormat);
};
+/// Tries to map rValue to RES_PARATR_LIST_AUTOFMT on the current paragraph, returns true on
+/// success.
+static bool lcl_setListAutoStyle(SwPaM& rPam, const uno::Any& rValue, SfxItemSet& rItemSet)
+{
+ // See if this is an empty range at the end of a paragraph.
+ if (rPam.Start()->nNode.GetIndex() != rPam.End()->nNode.GetIndex())
+ {
+ return false;
+ }
+
+ if (rPam.Start()->nContent.GetIndex() != rPam.End()->nContent.GetIndex())
+ {
+ return false;
+ }
+
+ SwTextNode* pTextNode = rPam.GetNode().GetTextNode();
+ if (!pTextNode)
+ {
+ return false;
+ }
+
+ if (rPam.Start()->nContent.GetIndex() != pTextNode->Len())
+ {
+ return false;
+ }
+
+ // Look up the style content based on the name.
+ OUString sStyle;
+ if (!(rValue >>= sStyle))
+ {
+ return false;
+ }
+
+ IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess();
+ std::shared_ptr<SfxItemSet> pStyle
+ = rStyleAccess.getByName(sStyle, IStyleAccess::AUTO_STYLE_CHAR);
+ if (!pStyle)
+ {
+ return false;
+ }
+
+ // Set the style on the text node.
+ SwFormatAutoFormat aItem(RES_PARATR_LIST_AUTOFMT);
+ aItem.SetStyleHandle(pStyle);
+ pTextNode->SetAttr(aItem);
+ // Clear the style from the hints array. Without clearing, it would contain some style which
+ // happened to be there previously.
+ rItemSet.ClearItem(RES_TXTATR_AUTOFMT);
+ return true;
+}
+
void
SwUnoCursorHelper::SetTextFormatColl(const uno::Any & rAny, SwPaM & rPaM)
{
@@ -451,6 +502,11 @@ SwUnoCursorHelper::SetCursorPropertyValue(
lcl_setCharStyle(rPam.GetDoc(), rValue, rItemSet);
break;
case RES_TXTATR_AUTOFMT:
+ if (lcl_setListAutoStyle(rPam, rValue, rItemSet))
+ {
+ break;
+ }
+
lcl_setAutoStyle(rPam.GetDoc().GetIStyleAccess(),
rValue, rItemSet, false);
break;
@@ -548,10 +604,13 @@ SwUnoCursorHelper::SetCursorPropertyValue(
rPropSet.setPropertyValue(*pEntry, prop.Value, items);
}
+ IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess();
+ // Add it to the autostyle pool, needed by the ODT export.
+ const std::shared_ptr<SfxItemSet> pAutoStyle
+ = rStyleAccess.getAutomaticStyle(items, IStyleAccess::AUTO_STYLE_CHAR);
SwFormatAutoFormat item(RES_PARATR_LIST_AUTOFMT);
- // TODO: for ODF export we'd need to add it to the autostyle pool
// note: paragraph auto styles have ParaStyleName property for the parent style; character auto styles currently do not because there's a separate hint, but for this it would be a good way to add it in order to export it as style:parent-style-name, see XMLTextParagraphExport::Add()
- item.SetStyleHandle(std::make_shared<SfxItemSet>(items));
+ item.SetStyleHandle(pAutoStyle);
pTextNd->SetAttr(item);
}
}
@@ -748,6 +807,12 @@ namespace {
enum ForceIntoMetaMode { META_CHECK_BOTH, META_INIT_START, META_INIT_END };
+enum ForceIntoContentControlMode
+{
+ CONTENT_CONTROL_CHECK_BOTH,
+ CONTENT_CONTROL_INIT_START,
+ CONTENT_CONTROL_INIT_END
+};
}
static bool
@@ -794,6 +859,61 @@ lcl_ForceIntoMeta(SwPaM & rCursor,
return bRet;
}
+namespace
+{
+bool lcl_ForceIntoContentControl(SwPaM& rCursor, const uno::Reference<text::XText>& xParentText,
+ ForceIntoContentControlMode eMode)
+{
+ bool bRet = true; // means not forced in CONTENT_CONTROL_CHECK_BOTH
+ auto pXContentControl = dynamic_cast<SwXContentControl*>(xParentText.get());
+ if (!pXContentControl)
+ {
+ SAL_WARN("sw.core", "lcl_ForceIntoContentControl: no parent text");
+ throw uno::RuntimeException();
+ }
+
+ SwTextNode* pTextNode;
+ sal_Int32 nStart;
+ sal_Int32 nEnd;
+ bool bSuccess = pXContentControl->SetContentRange(pTextNode, nStart, nEnd);
+ if (!bSuccess)
+ {
+ SAL_WARN("sw.core", "lcl_ForceIntoContentControl: SetContentRange() failed");
+ throw uno::RuntimeException();
+ }
+
+ // Force the cursor back into the content control if it has moved outside.
+ SwPosition aStart(*pTextNode, nStart);
+ SwPosition aEnd(*pTextNode, nEnd);
+ switch (eMode)
+ {
+ case CONTENT_CONTROL_INIT_START:
+ *rCursor.GetPoint() = aStart;
+ break;
+
+ case CONTENT_CONTROL_INIT_END:
+ *rCursor.GetPoint() = aEnd;
+ break;
+
+ case CONTENT_CONTROL_CHECK_BOTH:
+ if (*rCursor.Start() < aStart)
+ {
+ *rCursor.Start() = aStart;
+ bRet = false;
+ }
+
+ if (*rCursor.End() > aEnd)
+ {
+ *rCursor.End() = aEnd;
+ bRet = false;
+ }
+ break;
+ }
+
+ return bRet;
+}
+}
+
bool SwXTextCursor::IsAtEndOfMeta() const
{
if (CursorType::Meta == m_eType)
@@ -958,6 +1078,11 @@ SwXTextCursor::goLeft(sal_Int16 nCount, sal_Bool Expand)
META_CHECK_BOTH)
&& bRet;
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
+ && bRet;
+ }
return bRet;
}
@@ -976,6 +1101,11 @@ SwXTextCursor::goRight(sal_Int16 nCount, sal_Bool Expand)
META_CHECK_BOTH)
&& bRet;
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
+ && bRet;
+ }
return bRet;
}
@@ -1034,6 +1164,10 @@ SwXTextCursor::gotoStart(sal_Bool Expand)
{
lcl_ForceIntoMeta(rUnoCursor, m_xParentText, META_INIT_START);
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_INIT_START);
+ }
}
void SAL_CALL
@@ -1062,6 +1196,10 @@ SwXTextCursor::gotoEnd(sal_Bool Expand)
{
lcl_ForceIntoMeta(rUnoCursor, m_xParentText, META_INIT_END);
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_INIT_END);
+ }
}
void SAL_CALL
@@ -1169,6 +1307,15 @@ SwXTextCursor::gotoRange(
static_cast<text::XWordCursor*>(this));
}
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ SwPaM aPaM(*pPam->GetMark(), *pPam->GetPoint());
+ if (!lcl_ForceIntoContentControl(aPaM, m_xParentText, CONTENT_CONTROL_CHECK_BOTH))
+ {
+ throw uno::RuntimeException("gotoRange: xRange is out of bounds of the content control",
+ static_cast<text::XWordCursor*>(this));
+ }
+ }
// selection has to be expanded here
if(bExpand)
@@ -1272,6 +1419,10 @@ SwXTextCursor::gotoNextWord(sal_Bool Expand)
bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
META_CHECK_BOTH);
}
+ else if (bRet && m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
+ }
return bRet;
}
@@ -1312,6 +1463,10 @@ SwXTextCursor::gotoPreviousWord(sal_Bool Expand)
bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
META_CHECK_BOTH);
}
+ else if (bRet && m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
+ }
return bRet;
}
@@ -1348,6 +1503,10 @@ SwXTextCursor::gotoEndOfWord(sal_Bool Expand)
bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
META_CHECK_BOTH);
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
+ }
return bRet;
}
@@ -1384,6 +1543,10 @@ SwXTextCursor::gotoStartOfWord(sal_Bool Expand)
bRet = lcl_ForceIntoMeta(rUnoCursor, m_xParentText,
META_CHECK_BOTH);
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH);
+ }
return bRet;
}
@@ -1467,6 +1630,11 @@ SwXTextCursor::gotoNextSentence(sal_Bool Expand)
META_CHECK_BOTH)
&& bRet;
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
+ && bRet;
+ }
return bRet;
}
@@ -1495,6 +1663,11 @@ SwXTextCursor::gotoPreviousSentence(sal_Bool Expand)
META_CHECK_BOTH)
&& bRet;
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
+ && bRet;
+ }
return bRet;
}
@@ -1518,6 +1691,11 @@ SwXTextCursor::gotoStartOfSentence(sal_Bool Expand)
META_CHECK_BOTH)
&& bRet;
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
+ && bRet;
+ }
return bRet;
}
@@ -1542,6 +1720,11 @@ SwXTextCursor::gotoEndOfSentence(sal_Bool Expand)
META_CHECK_BOTH)
&& bRet;
}
+ else if (m_eType == CursorType::ContentControl)
+ {
+ bRet = lcl_ForceIntoContentControl(rUnoCursor, m_xParentText, CONTENT_CONTROL_CHECK_BOTH)
+ && bRet;
+ }
return bRet;
}
@@ -1892,7 +2075,8 @@ SwUnoCursorHelper::GetPropertyStates(
if(!pEntry)
{
if (pNames[i] == UNO_NAME_IS_SKIP_HIDDEN_TEXT ||
- pNames[i] == UNO_NAME_IS_SKIP_PROTECTED_TEXT)
+ pNames[i] == UNO_NAME_IS_SKIP_PROTECTED_TEXT ||
+ pNames[i] == UNO_NAME_NO_FORMAT_ATTR)
{
pStates[i] = beans::PropertyState_DEFAULT_VALUE;
continue;
@@ -2085,6 +2269,7 @@ SwXTextCursor::getPropertySetInfo()
{
{ u"" UNO_NAME_IS_SKIP_HIDDEN_TEXT, FN_SKIP_HIDDEN_TEXT, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0},
{ u"" UNO_NAME_IS_SKIP_PROTECTED_TEXT, FN_SKIP_PROTECTED_TEXT, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0},
+ { u"" UNO_NAME_NO_FORMAT_ATTR, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0},
{ u"", 0, css::uno::Type(), 0, 0 }
};
const uno::Reference< beans::XPropertySetInfo > xInfo =
@@ -2133,10 +2318,26 @@ SwXTextCursor::setPropertyValue(
pTextNode->ResetAttr(RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END);
}
}
+ else if (rPropertyName == UNO_NAME_NO_FORMAT_ATTR)
+ {
+ bool bSet(false);
+ if (!(rValue >>= bSet))
+ {
+ throw lang::IllegalArgumentException();
+ }
+ if (bSet)
+ {
+ m_nAttrMode = SetAttrMode::NOFORMATATTR;
+ }
+ else
+ {
+ m_nAttrMode = SetAttrMode::DEFAULT;
+ }
+ }
else
{
SwUnoCursorHelper::SetPropertyValue(rUnoCursor,
- m_rPropSet, rPropertyName, rValue);
+ m_rPropSet, rPropertyName, rValue, m_nAttrMode);
}
}
@@ -2449,7 +2650,8 @@ SwXTextCursor::getPropertyDefaults(
if (!pEntry)
{
if (pNames[i] == UNO_NAME_IS_SKIP_HIDDEN_TEXT ||
- pNames[i] == UNO_NAME_IS_SKIP_PROTECTED_TEXT)
+ pNames[i] == UNO_NAME_IS_SKIP_PROTECTED_TEXT ||
+ pNames[i] == UNO_NAME_NO_FORMAT_ATTR)
{
continue;
}
@@ -2482,7 +2684,7 @@ void SAL_CALL SwXTextCursor::invalidateMarkings(::sal_Int32 nType)
if ( text::TextMarkupType::SPELLCHECK == nType )
{
- txtNode->SetWrongDirty(SwTextNode::WrongState::TODO);
+ txtNode->SetWrongDirty(sw::WrongState::TODO);
txtNode->ClearWrong();
}
else if( text::TextMarkupType::PROOFREADING == nType )
diff --git a/sw/source/core/unocore/unoport.cxx b/sw/source/core/unocore/unoport.cxx
index dd44538edbd1..12459c3cf29c 100644
--- a/sw/source/core/unocore/unoport.cxx
+++ b/sw/source/core/unocore/unoport.cxx
@@ -70,9 +70,14 @@ SwXTextPortion::SwXTextPortion(
: PROPERTY_MAP_TEXTPORTION_EXTENSIONS))
, m_xParentText(rParent)
, m_pFrameFormat(nullptr)
- , m_ePortionType(eType)
+ , m_ePortionType(eType != PORTION_LIST_AUTOFMT ? eType : PORTION_TEXT)
, m_bIsCollapsed(false)
+ , m_bIsListAutoFormat(false)
{
+ if (eType == PORTION_LIST_AUTOFMT)
+ {
+ m_bIsListAutoFormat = true;
+ }
init( pPortionCursor);
}
@@ -86,6 +91,7 @@ SwXTextPortion::SwXTextPortion(
, m_pFrameFormat(&rFormat)
, m_ePortionType(PORTION_FRAME)
, m_bIsCollapsed(false)
+ , m_bIsListAutoFormat(false)
{
StartListening(rFormat.GetNotifier());
init( pPortionCursor);
@@ -107,6 +113,7 @@ SwXTextPortion::SwXTextPortion(
, m_pFrameFormat(nullptr)
, m_ePortionType( bIsEnd ? PORTION_RUBY_END : PORTION_RUBY_START )
, m_bIsCollapsed(false)
+ , m_bIsListAutoFormat(false)
{
init( pPortionCursor);
@@ -362,8 +369,23 @@ void SwXTextPortion::GetPropertyValue(
break;
default:
beans::PropertyState eTemp;
- bool bDone = SwUnoCursorHelper::getCursorPropertyValue(
- rEntry, *pUnoCursor, &rVal, eTemp );
+ bool bDone = false;
+ if (m_bIsListAutoFormat)
+ {
+ SwTextNode* pTextNode = pUnoCursor->GetNode().GetTextNode();
+ std::shared_ptr<SfxItemSet> pListSet
+ = static_cast<const SwFormatAutoFormat&>(pTextNode->GetAttr(RES_PARATR_LIST_AUTOFMT)).GetStyleHandle();
+ if (pListSet)
+ {
+ m_pPropSet->getPropertyValue(rEntry, *pListSet, rVal);
+ bDone = true;
+ }
+ }
+ if (!bDone)
+ {
+ bDone = SwUnoCursorHelper::getCursorPropertyValue(
+ rEntry, *pUnoCursor, &rVal, eTemp );
+ }
if(!bDone)
{
if(!pSet)
@@ -598,11 +620,30 @@ uno::Sequence< beans::GetDirectPropertyTolerantResult > SwXTextPortion::GetPrope
const SfxItemPropertyMap& rPropMap = m_pPropSet->getPropertyMap();
- uno::Sequence< beans::PropertyState > aPropertyStates =
- SwUnoCursorHelper::GetPropertyStates(
- rUnoCursor, *m_pPropSet,
- rPropertyNames,
- SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT );
+ uno::Sequence< beans::PropertyState > aPropertyStates;
+ if (m_bIsListAutoFormat)
+ {
+ SwTextNode* pTextNode = rUnoCursor.GetNode().GetTextNode();
+ std::shared_ptr<SfxItemSet> pListSet
+ = static_cast<const SwFormatAutoFormat&>(pTextNode->GetAttr(RES_PARATR_LIST_AUTOFMT)).GetStyleHandle();
+ if (pListSet)
+ {
+ std::vector<beans::PropertyState> aStates;
+ for (const auto& rPropertyName : rPropertyNames)
+ {
+ aStates.push_back(m_pPropSet->getPropertyState(rPropertyName, *pListSet));
+ }
+ aPropertyStates = comphelper::containerToSequence(aStates);
+ }
+ }
+ if (!aPropertyStates.hasElements())
+ {
+ aPropertyStates =
+ SwUnoCursorHelper::GetPropertyStates(
+ rUnoCursor, *m_pPropSet,
+ rPropertyNames,
+ SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT );
+ }
const beans::PropertyState* pPropertyStates = aPropertyStates.getConstArray();
for (sal_Int32 i = 0; i < nProps; ++i)
diff --git a/sw/source/core/unocore/unoportenum.cxx b/sw/source/core/unocore/unoportenum.cxx
index 465fdefb73df..40b318a0c6fc 100644
--- a/sw/source/core/unocore/unoportenum.cxx
+++ b/sw/source/core/unocore/unoportenum.cxx
@@ -1504,6 +1504,31 @@ static void lcl_CreatePortions(
// text portion because there may be a hyperlink attribute
xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
}
+ else if (bAtEnd && !xRef.is() && pTextNode->GetSwAttrSet().HasItem(RES_PARATR_LIST_AUTOFMT))
+ {
+ // We have explicit paragraph marker formatting, export it.
+ xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_LIST_AUTOFMT);
+ }
+ else if (bAtEnd && !xRef.is() && pHints)
+ {
+ // See if there is an empty autofmt at the paragraph end. If so, export it, since that
+ // affects the formatting of number portions.
+ for (size_t i = 0; i < pHints->Count(); ++i)
+ {
+ const SwTextAttr* pHint = pHints->GetSortedByEnd(i);
+ if (pHint->GetStart() < pTextNode->Len())
+ {
+ break;
+ }
+ if (pHint->Which() == RES_TXTATR_AUTOFMT && pHint->GetEnd()
+ && pHint->GetStart() == *pHint->GetEnd()
+ && pHint->GetStart() == pTextNode->Len())
+ {
+ xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
+ break;
+ }
+ }
+ }
if (xRef.is())
{
diff --git a/sw/source/core/unocore/unostyle.cxx b/sw/source/core/unocore/unostyle.cxx
index a6858ba5d39a..02be2f781e59 100644
--- a/sw/source/core/unocore/unostyle.cxx
+++ b/sw/source/core/unocore/unostyle.cxx
@@ -126,36 +126,6 @@ using namespace css::uno;
namespace {
-class SwXStyle;
-class SwStyleProperties_Impl;
-
- struct StyleFamilyEntry
- {
- using GetCountOrName_t = std::function<sal_Int32 (const SwDoc&, OUString*, sal_Int32)>;
- using CreateStyle_t = std::function<uno::Reference<css::style::XStyle>(SfxStyleSheetBasePool*, SwDocShell*, const OUString&)>;
- using TranslateIndex_t = std::function<sal_uInt16(const sal_uInt16)>;
- SfxStyleFamily m_eFamily;
- sal_uInt16 m_nPropMapType;
- uno::Reference<beans::XPropertySetInfo> m_xPSInfo;
- SwGetPoolIdFromName m_aPoolId;
- OUString m_sName;
- TranslateId m_pResId;
- GetCountOrName_t m_fGetCountOrName;
- CreateStyle_t m_fCreateStyle;
- TranslateIndex_t m_fTranslateIndex;
- StyleFamilyEntry(SfxStyleFamily eFamily, sal_uInt16 nPropMapType, SwGetPoolIdFromName aPoolId, OUString const& sName, TranslateId pResId, GetCountOrName_t const & fGetCountOrName, CreateStyle_t const & fCreateStyle, TranslateIndex_t const & fTranslateIndex)
- : m_eFamily(eFamily)
- , m_nPropMapType(nPropMapType)
- , m_xPSInfo(aSwMapProvider.GetPropertySet(nPropMapType)->getPropertySetInfo())
- , m_aPoolId(aPoolId)
- , m_sName(sName)
- , m_pResId(pResId)
- , m_fGetCountOrName(fGetCountOrName)
- , m_fCreateStyle(fCreateStyle)
- , m_fTranslateIndex(fTranslateIndex)
- { }
- };
- const std::vector<StyleFamilyEntry>* our_pStyleFamilyEntries;
// these should really be constexprs, but MSVC still is apparently too stupid for them
#define nPoolChrNormalRange (RES_POOLCHR_NORMAL_END - RES_POOLCHR_NORMAL_BEGIN)
#define nPoolChrHtmlRange (RES_POOLCHR_HTML_END - RES_POOLCHR_HTML_BEGIN)
@@ -186,119 +156,351 @@ class SwStyleProperties_Impl;
, m_nCollectionBits(nCollectionBits)
{ }
};
- const std::vector<ParagraphStyleCategoryEntry>* our_pParagraphStyleCategoryEntries;
-}
-static const std::vector<StyleFamilyEntry>* lcl_GetStyleFamilyEntries();
-using namespace ::com::sun::star;
+const std::vector<ParagraphStyleCategoryEntry>& lcl_GetParagraphStyleCategoryEntries()
+{
+ static const std::vector<ParagraphStyleCategoryEntry> our_pParagraphStyleCategoryEntries{
+ { style::ParagraphStyleCategory::TEXT, SfxStyleSearchBits::SwText, COLL_TEXT_BITS },
+ { style::ParagraphStyleCategory::CHAPTER, SfxStyleSearchBits::SwChapter, COLL_DOC_BITS },
+ { style::ParagraphStyleCategory::LIST, SfxStyleSearchBits::SwList, COLL_LISTS_BITS },
+ { style::ParagraphStyleCategory::INDEX, SfxStyleSearchBits::SwIndex, COLL_REGISTER_BITS },
+ { style::ParagraphStyleCategory::EXTRA, SfxStyleSearchBits::SwExtra, COLL_EXTRA_BITS },
+ { style::ParagraphStyleCategory::HTML, SfxStyleSearchBits::SwHtml, COLL_HTML_BITS }
+ };
+ return our_pParagraphStyleCategoryEntries;
+}
-namespace sw
+class StyleFamilyEntry
{
- namespace {
+public:
+ template <SfxStyleFamily f> static StyleFamilyEntry Create(sal_uInt16 nPropMapType, SwGetPoolIdFromName aPoolId, OUString sName, TranslateId pResId)
+ {
+ return StyleFamilyEntry(f, nPropMapType, aPoolId, sName, pResId, GetCountOrName<f>, CreateStyle<f>, TranslateIndex<f>);
+ }
- class XStyleFamily : public cppu::WeakImplHelper
- <
- container::XNameContainer,
- lang::XServiceInfo,
- container::XIndexAccess,
- beans::XPropertySet
- >
- , public SfxListener
+ SfxStyleFamily family() const { return m_eFamily; }
+ sal_uInt16 propMapType() const { return m_nPropMapType; }
+ const uno::Reference<beans::XPropertySetInfo>& xPSInfo() const { return m_xPSInfo; }
+ SwGetPoolIdFromName poolId() const { return m_aPoolId; }
+ const OUString& name() const { return m_sName; }
+ const TranslateId& resId() const { return m_pResId; }
+
+ sal_Int32 getCountOrName(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex) const { return m_fGetCountOrName(rDoc, pString, nIndex); }
+ css::uno::Reference<css::style::XStyle> createStyle(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName) const { return m_fCreateStyle(pBasePool, pDocShell, sStyleName); }
+ sal_uInt16 translateIndex(const sal_uInt16 nIndex) const { return m_fTranslateIndex(nIndex); }
+
+private:
+ using GetCountOrName_t = sal_Int32 (*)(const SwDoc&, OUString*, sal_Int32);
+ using CreateStyle_t = uno::Reference<css::style::XStyle>(*)(SfxStyleSheetBasePool*, SwDocShell*, const OUString&);
+ using TranslateIndex_t = sal_uInt16(*)(const sal_uInt16);
+ SfxStyleFamily m_eFamily;
+ sal_uInt16 m_nPropMapType;
+ uno::Reference<beans::XPropertySetInfo> m_xPSInfo;
+ SwGetPoolIdFromName m_aPoolId;
+ OUString m_sName;
+ TranslateId m_pResId;
+ GetCountOrName_t m_fGetCountOrName;
+ CreateStyle_t m_fCreateStyle;
+ TranslateIndex_t m_fTranslateIndex;
+ StyleFamilyEntry(SfxStyleFamily eFamily, sal_uInt16 nPropMapType, SwGetPoolIdFromName aPoolId, OUString sName, TranslateId pResId, GetCountOrName_t fGetCountOrName, CreateStyle_t fCreateStyle, TranslateIndex_t fTranslateIndex)
+ : m_eFamily(eFamily)
+ , m_nPropMapType(nPropMapType)
+ , m_xPSInfo(aSwMapProvider.GetPropertySet(nPropMapType)->getPropertySetInfo())
+ , m_aPoolId(aPoolId)
+ , m_sName(std::move(sName))
+ , m_pResId(pResId)
+ , m_fGetCountOrName(fGetCountOrName)
+ , m_fCreateStyle(fCreateStyle)
+ , m_fTranslateIndex(fTranslateIndex)
+ { }
+ template<SfxStyleFamily> static inline sal_Int32 GetCountOrName(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex);
+ template<SfxStyleFamily> static inline css::uno::Reference<css::style::XStyle> CreateStyle(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName);
+ template<SfxStyleFamily> static inline sal_uInt16 TranslateIndex(const sal_uInt16 nIndex) { return nIndex; }
+};
+
+template<>
+sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Char>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
+{
+ const sal_uInt16 nBaseCount = nPoolChrHtmlRange + nPoolChrNormalRange;
+ nIndex -= nBaseCount;
+ sal_Int32 nCount = 0;
+ for(auto pFormat : *rDoc.GetCharFormats())
{
- const StyleFamilyEntry& m_rEntry;
- SfxStyleSheetBasePool* m_pBasePool;
- SwDocShell* m_pDocShell;
+ if(pFormat->IsDefault() && pFormat != rDoc.GetDfltCharFormat())
+ continue;
+ if(!IsPoolUserFormat(pFormat->GetPoolFormatId()))
+ continue;
+ if(nIndex == nCount)
+ {
+ // the default character format needs to be set to "Default!"
+ if(rDoc.GetDfltCharFormat() == pFormat)
+ *pString = SwResId(STR_POOLCHR_STANDARD);
+ else
+ *pString = pFormat->GetName();
+ break;
+ }
+ ++nCount;
+ }
+ return nCount + nBaseCount;
+}
- SwXStyle* FindStyle(std::u16string_view rStyleName) const;
- sal_Int32 GetCountOrName(OUString* pString, sal_Int32 nIndex = SAL_MAX_INT32)
- { return m_rEntry.m_fGetCountOrName(*m_pDocShell->GetDoc(), pString, nIndex); };
- static const StyleFamilyEntry& InitEntry(SfxStyleFamily eFamily)
+template<>
+sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Para>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
+{
+ const sal_uInt16 nBaseCount = nPoolCollHtmlStackedStart + nPoolCollHtmlRange;
+ nIndex -= nBaseCount;
+ sal_Int32 nCount = 0;
+ for(auto pColl : *rDoc.GetTextFormatColls())
+ {
+ if(pColl->IsDefault())
+ continue;
+ if(!IsPoolUserFormat(pColl->GetPoolFormatId()))
+ continue;
+ if(nIndex == nCount)
{
- auto pEntries = lcl_GetStyleFamilyEntries();
- const auto pEntry = std::find_if(pEntries->begin(), pEntries->end(),
- [eFamily] (const StyleFamilyEntry& e) { return e.m_eFamily == eFamily; });
- assert(pEntry != pEntries->end());
- return *pEntry;
+ *pString = pColl->GetName();
+ break;
}
- public:
- XStyleFamily(SwDocShell* pDocShell, const SfxStyleFamily eFamily)
- : m_rEntry(InitEntry(eFamily))
- , m_pBasePool(pDocShell->GetStyleSheetPool())
- , m_pDocShell(pDocShell)
+ ++nCount;
+ }
+ return nCount + nBaseCount;
+}
+
+template<>
+sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Frame>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
+{
+ nIndex -= nPoolFrameRange;
+ sal_Int32 nCount = 0;
+ for(const auto pFormat : *rDoc.GetFrameFormats())
+ {
+ if(pFormat->IsDefault() || pFormat->IsAuto())
+ continue;
+ if(!IsPoolUserFormat(pFormat->GetPoolFormatId()))
+ continue;
+ if(nIndex == nCount)
{
- if (m_pBasePool) //tdf#124142 html docs can have no styles
- StartListening(*m_pBasePool);
+ *pString = pFormat->GetName();
+ break;
}
+ ++nCount;
+ }
+ return nCount + nPoolFrameRange;
+}
- //XIndexAccess
- virtual sal_Int32 SAL_CALL getCount() override
+template<>
+sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Page>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
+{
+ nIndex -= nPoolPageRange;
+ sal_Int32 nCount = 0;
+ const size_t nArrLen = rDoc.GetPageDescCnt();
+ for(size_t i = 0; i < nArrLen; ++i)
+ {
+ const SwPageDesc& rDesc = rDoc.GetPageDesc(i);
+ if(!IsPoolUserFormat(rDesc.GetPoolFormatId()))
+ continue;
+ if(nIndex == nCount)
{
- SolarMutexGuard aGuard;
- return GetCountOrName(nullptr);
- };
- virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override;
-
- //XElementAccess
- virtual uno::Type SAL_CALL getElementType( ) override
- { return cppu::UnoType<style::XStyle>::get(); };
- virtual sal_Bool SAL_CALL hasElements( ) override
+ *pString = rDesc.GetName();
+ break;
+ }
+ ++nCount;
+ }
+ nCount += nPoolPageRange;
+ return nCount;
+}
+
+template<>
+sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Pseudo>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
+{
+ nIndex -= nPoolNumRange;
+ sal_Int32 nCount = 0;
+ for(const auto pRule : rDoc.GetNumRuleTable())
+ {
+ if(pRule->IsAutoRule())
+ continue;
+ if(!IsPoolUserFormat(pRule->GetPoolFormatId()))
+ continue;
+ if(nIndex == nCount)
{
- if(!m_pBasePool)
- throw uno::RuntimeException();
- return true;
+ *pString = pRule->GetName();
+ break;
}
+ ++nCount;
+ }
+ return nCount + nPoolNumRange;
+}
+
+template<>
+sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Table>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
+{
+ if (!rDoc.HasTableStyles())
+ return 0;
+
+ const auto pAutoFormats = &rDoc.GetTableStyles();
+ const sal_Int32 nCount = pAutoFormats->size();
+ if (0 <= nIndex && nIndex < nCount)
+ *pString = pAutoFormats->operator[](nIndex).GetName();
+
+ return nCount;
+}
- //XNameAccess
- virtual uno::Any SAL_CALL getByName(const OUString& Name) override;
- virtual uno::Sequence< OUString > SAL_CALL getElementNames() override;
- virtual sal_Bool SAL_CALL hasByName(const OUString& Name) override;
-
- //XNameContainer
- virtual void SAL_CALL insertByName(const OUString& Name, const uno::Any& Element) override;
- virtual void SAL_CALL replaceByName(const OUString& Name, const uno::Any& Element) override;
- virtual void SAL_CALL removeByName(const OUString& Name) override;
-
- //XPropertySet
- virtual uno::Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override
- { return {}; };
- virtual void SAL_CALL setPropertyValue( const OUString&, const uno::Any&) override
- { SAL_WARN("sw.uno", "###unexpected!"); };
- virtual uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
- virtual void SAL_CALL addPropertyChangeListener( const OUString&, const uno::Reference<beans::XPropertyChangeListener>&) override
- { SAL_WARN("sw.uno", "###unexpected!"); };
- virtual void SAL_CALL removePropertyChangeListener( const OUString&, const uno::Reference<beans::XPropertyChangeListener>&) override
- { SAL_WARN("sw.uno", "###unexpected!"); };
- virtual void SAL_CALL addVetoableChangeListener(const OUString&, const uno::Reference<beans::XVetoableChangeListener>&) override
- { SAL_WARN("sw.uno", "###unexpected!"); };
- virtual void SAL_CALL removeVetoableChangeListener(const OUString&, const uno::Reference<beans::XVetoableChangeListener>&) override
- { SAL_WARN("sw.uno", "###unexpected!"); };
-
- //SfxListener
- virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override
+template<>
+sal_Int32 StyleFamilyEntry::GetCountOrName<SfxStyleFamily::Cell>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
+{
+ const auto& rAutoFormats = rDoc.GetTableStyles();
+ const auto& rTableTemplateMap = SwTableAutoFormat::GetTableTemplateMap();
+ const sal_Int32 nUsedCellStylesCount = rAutoFormats.size() * rTableTemplateMap.size();
+ const sal_Int32 nCount = nUsedCellStylesCount + rDoc.GetCellStyles().size();
+ if (0 <= nIndex && nIndex < nCount)
+ {
+ if (nUsedCellStylesCount > nIndex)
{
- if(rHint.GetId() == SfxHintId::Dying)
- {
- m_pBasePool = nullptr;
- m_pDocShell = nullptr;
- EndListening(rBC);
- }
+ const sal_Int32 nAutoFormat = nIndex / rTableTemplateMap.size();
+ const sal_Int32 nBoxFormat = rTableTemplateMap[nIndex % rTableTemplateMap.size()];
+ const SwTableAutoFormat& rTableFormat = rAutoFormats[nAutoFormat];
+ SwStyleNameMapper::FillProgName(rTableFormat.GetName(), *pString, SwGetPoolIdFromName::TabStyle);
+ *pString += rTableFormat.GetTableTemplateCellSubName(rTableFormat.GetBoxFormat(nBoxFormat));
}
+ else
+ *pString = rDoc.GetCellStyles()[nIndex-nUsedCellStylesCount].GetName();
+ }
+ return nCount;
+}
- //XServiceInfo
- virtual OUString SAL_CALL getImplementationName() override
- { return {"XStyleFamily"}; };
- virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override
- { return cppu::supportsService(this, rServiceName); };
- virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
- { return { "com.sun.star.style.StyleFamily" }; }
+template<>
+sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Char>(const sal_uInt16 nIndex)
+{
+ static_assert(nPoolChrNormalRange > 0 && nPoolChrHtmlRange > 0, "invalid pool range");
+ if (nIndex < nPoolChrNormalRange)
+ return nIndex + RES_POOLCHR_NORMAL_BEGIN;
+ else if (nIndex < (nPoolChrHtmlRange + nPoolChrNormalRange))
+ return nIndex + RES_POOLCHR_HTML_BEGIN - nPoolChrNormalRange;
+ throw lang::IndexOutOfBoundsException();
+}
+
+template<>
+sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Para>(const sal_uInt16 nIndex)
+{
+ static_assert(nPoolCollTextRange > 0 && nPoolCollListsRange > 0 && nPoolCollExtraRange > 0 && nPoolCollRegisterRange > 0 && nPoolCollDocRange > 0 && nPoolCollHtmlRange > 0, "weird pool range");
+ if (nIndex < nPoolCollListsStackedStart)
+ return nIndex + RES_POOLCOLL_TEXT_BEGIN;
+ else if (nIndex < nPoolCollExtraStackedStart)
+ return nIndex + RES_POOLCOLL_LISTS_BEGIN - nPoolCollListsStackedStart;
+ else if (nIndex < nPoolCollRegisterStackedStart)
+ return nIndex + RES_POOLCOLL_EXTRA_BEGIN - nPoolCollExtraStackedStart;
+ else if (nIndex < nPoolCollDocStackedStart)
+ return nIndex + RES_POOLCOLL_REGISTER_BEGIN - nPoolCollRegisterStackedStart;
+ else if (nIndex < nPoolCollHtmlStackedStart)
+ return nIndex + RES_POOLCOLL_DOC_BEGIN - nPoolCollDocStackedStart;
+ else if (nIndex < nPoolCollHtmlStackedStart + nPoolCollTextRange)
+ return nIndex + RES_POOLCOLL_HTML_BEGIN - nPoolCollHtmlStackedStart;
+ throw lang::IndexOutOfBoundsException();
+}
+
+template<>
+sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Page>(const sal_uInt16 nIndex)
+{
+ if (nIndex < nPoolPageRange)
+ return nIndex + RES_POOLPAGE_BEGIN;
+ throw lang::IndexOutOfBoundsException();
+}
+
+template<>
+sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Frame>(const sal_uInt16 nIndex)
+{
+ if (nIndex < nPoolFrameRange)
+ return nIndex + RES_POOLFRM_BEGIN;
+ throw lang::IndexOutOfBoundsException();
+}
+
+template<>
+sal_uInt16 StyleFamilyEntry::TranslateIndex<SfxStyleFamily::Pseudo>(const sal_uInt16 nIndex)
+{
+ if (nIndex < nPoolNumRange)
+ return nIndex + RES_POOLNUMRULE_BEGIN;
+ throw lang::IndexOutOfBoundsException();
+}
+
+const std::vector<StyleFamilyEntry>& lcl_GetStyleFamilyEntries()
+{
+ static const std::vector<StyleFamilyEntry> our_pStyleFamilyEntries{
+ StyleFamilyEntry::Create<SfxStyleFamily::Char> (PROPERTY_MAP_CHAR_STYLE, SwGetPoolIdFromName::ChrFmt, "CharacterStyles", STR_STYLE_FAMILY_CHARACTER),
+ StyleFamilyEntry::Create<SfxStyleFamily::Para> (PROPERTY_MAP_PARA_STYLE, SwGetPoolIdFromName::TxtColl, "ParagraphStyles", STR_STYLE_FAMILY_PARAGRAPH),
+ StyleFamilyEntry::Create<SfxStyleFamily::Page> (PROPERTY_MAP_PAGE_STYLE, SwGetPoolIdFromName::PageDesc, "PageStyles", STR_STYLE_FAMILY_PAGE),
+ StyleFamilyEntry::Create<SfxStyleFamily::Frame> (PROPERTY_MAP_FRAME_STYLE, SwGetPoolIdFromName::FrmFmt, "FrameStyles", STR_STYLE_FAMILY_FRAME),
+ StyleFamilyEntry::Create<SfxStyleFamily::Pseudo>(PROPERTY_MAP_NUM_STYLE, SwGetPoolIdFromName::NumRule, "NumberingStyles", STR_STYLE_FAMILY_NUMBERING),
+ StyleFamilyEntry::Create<SfxStyleFamily::Table> (PROPERTY_MAP_TABLE_STYLE, SwGetPoolIdFromName::TabStyle, "TableStyles", STR_STYLE_FAMILY_TABLE),
+ StyleFamilyEntry::Create<SfxStyleFamily::Cell> (PROPERTY_MAP_CELL_STYLE, SwGetPoolIdFromName::CellStyle, "CellStyles", STR_STYLE_FAMILY_CELL),
};
+ return our_pStyleFamilyEntries;
+}
+class SwStyleBase_Impl
+{
+private:
+ SwDoc& m_rDoc;
+ const SwPageDesc* m_pOldPageDesc;
+ rtl::Reference<SwDocStyleSheet> m_xNewBase;
+ SfxItemSet* m_pItemSet;
+ std::unique_ptr<SfxItemSet> m_pMyItemSet;
+ OUString m_rStyleName;
+ const SwAttrSet* m_pParentStyle;
+public:
+ SwStyleBase_Impl(SwDoc& rSwDoc, OUString aName, const SwAttrSet* pParentStyle)
+ : m_rDoc(rSwDoc)
+ , m_pOldPageDesc(nullptr)
+ , m_pItemSet(nullptr)
+ , m_rStyleName(std::move(aName))
+ , m_pParentStyle(pParentStyle)
+ { }
+
+ rtl::Reference<SwDocStyleSheet>& getNewBase()
+ {
+ return m_xNewBase;
}
-}
-namespace {
+ void setNewBase(SwDocStyleSheet* pNew)
+ {
+ m_xNewBase = pNew;
+ }
-class SwStyleBase_Impl;
+ bool HasItemSet() const
+ {
+ return m_xNewBase.is();
+ }
+
+ SfxItemSet& GetItemSet()
+ {
+ assert(m_xNewBase.is());
+ if(!m_pItemSet)
+ {
+ m_pMyItemSet.reset(new SfxItemSet(m_xNewBase->GetItemSet()));
+ m_pItemSet = m_pMyItemSet.get();
+
+ // set parent style to have the correct XFillStyle setting as XFILL_NONE
+ if(!m_pItemSet->GetParent() && m_pParentStyle)
+ m_pItemSet->SetParent(m_pParentStyle);
+ }
+ return *m_pItemSet;
+ }
+
+ const SwPageDesc* GetOldPageDesc();
+
+ // still a hack, but a bit more explicit and with a proper scope
+ struct ItemSetOverrider
+ {
+ SwStyleBase_Impl& m_rStyleBase;
+ SfxItemSet* m_pOldSet;
+ ItemSetOverrider(SwStyleBase_Impl& rStyleBase, SfxItemSet* pTemp)
+ : m_rStyleBase(rStyleBase)
+ , m_pOldSet(m_rStyleBase.m_pItemSet)
+ { m_rStyleBase.m_pItemSet = pTemp; }
+ ~ItemSetOverrider()
+ { m_rStyleBase.m_pItemSet = m_pOldSet; };
+ };
+};
+
+class SwStyleProperties_Impl;
class SwXStyle : public cppu::WeakImplHelper
<
css::style::XStyle,
@@ -402,7 +604,7 @@ public:
//SvtListener
virtual void Notify(const SfxHint&) override;
const OUString& GetStyleName() const { return m_sStyleName;}
- SfxStyleFamily GetFamily() const {return m_rEntry.m_eFamily;}
+ SfxStyleFamily GetFamily() const {return m_rEntry.family();}
bool IsDescriptor() const {return m_bIsDescriptor;}
bool IsConditional() const { return m_bIsConditional;}
@@ -469,9 +671,182 @@ public:
virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override;
};
+class SwStyleProperties_Impl
+{
+ const SfxItemPropertyMap& mrMap;
+ std::map<OUString, uno::Any> m_vPropertyValues;
+public:
+ explicit SwStyleProperties_Impl(const SfxItemPropertyMap& rMap)
+ : mrMap(rMap)
+ { }
+
+ bool AllowsKey(std::u16string_view rName)
+ {
+ return mrMap.hasPropertyByName(rName);
+ }
+ bool SetProperty(const OUString& rName, const uno::Any& rValue)
+ {
+ if(!AllowsKey(rName))
+ return false;
+ m_vPropertyValues[rName] = rValue;
+ return true;
+ }
+ void GetProperty(const OUString& rName, const uno::Any*& pAny)
+ {
+ if(!AllowsKey(rName))
+ {
+ pAny = nullptr;
+ return;
+ }
+ pAny = &m_vPropertyValues[rName];
+ return;
+ }
+ bool ClearProperty( const OUString& rName )
+ {
+ if(!AllowsKey(rName))
+ return false;
+ m_vPropertyValues[rName] = uno::Any();
+ return true;
+ }
+ void ClearAllProperties( )
+ { m_vPropertyValues.clear(); }
+ void Apply(SwXStyle& rStyle)
+ {
+ for(const auto& rPropertyPair : m_vPropertyValues)
+ {
+ if(rPropertyPair.second.hasValue())
+ rStyle.setPropertyValue(rPropertyPair.first, rPropertyPair.second);
+ }
+ }
+};
+
+template<SfxStyleFamily eFamily>
+css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName)
+{
+ return pBasePool ? new SwXStyle(pBasePool, eFamily, pDocShell->GetDoc(), sStyleName) : new SwXStyle(pDocShell->GetDoc(), eFamily, false);
+}
+
+template<>
+css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle<SfxStyleFamily::Frame>(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName)
+{
+ return pBasePool ? new SwXFrameStyle(*pBasePool, pDocShell->GetDoc(), sStyleName) : new SwXFrameStyle(pDocShell->GetDoc());
+}
+
+template<>
+css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle<SfxStyleFamily::Page>(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName)
+{
+ return pBasePool ? new SwXPageStyle(*pBasePool, pDocShell, sStyleName) : new SwXPageStyle(pDocShell);
+}
+
+template<>
+css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle<SfxStyleFamily::Table>(SfxStyleSheetBasePool* /*pBasePool*/, SwDocShell* pDocShell, const OUString& sStyleName)
+{
+ return SwXTextTableStyle::CreateXTextTableStyle(pDocShell, sStyleName);
}
-using sw::XStyleFamily;
+template<>
+css::uno::Reference<css::style::XStyle> StyleFamilyEntry::CreateStyle<SfxStyleFamily::Cell>(SfxStyleSheetBasePool* /*pBasePool*/, SwDocShell* pDocShell, const OUString& sStyleName)
+{
+ return SwXTextCellStyle::CreateXTextCellStyle(pDocShell, sStyleName);
+}
+
+class XStyleFamily : public cppu::WeakImplHelper
+<
+ container::XNameContainer,
+ lang::XServiceInfo,
+ container::XIndexAccess,
+ beans::XPropertySet
+>
+, public SfxListener
+{
+ const StyleFamilyEntry& m_rEntry;
+ SfxStyleSheetBasePool* m_pBasePool;
+ SwDocShell* m_pDocShell;
+
+ SwXStyle* FindStyle(std::u16string_view rStyleName) const;
+ sal_Int32 GetCountOrName(OUString* pString, sal_Int32 nIndex = SAL_MAX_INT32)
+ { return m_rEntry.getCountOrName(*m_pDocShell->GetDoc(), pString, nIndex); };
+ static const StyleFamilyEntry& InitEntry(SfxStyleFamily eFamily)
+ {
+ auto& entries = lcl_GetStyleFamilyEntries();
+ const auto pEntry = std::find_if(entries.begin(), entries.end(),
+ [eFamily] (const StyleFamilyEntry& e) { return e.family() == eFamily; });
+ assert(pEntry != entries.end());
+ return *pEntry;
+ }
+public:
+ XStyleFamily(SwDocShell* pDocShell, const SfxStyleFamily eFamily)
+ : m_rEntry(InitEntry(eFamily))
+ , m_pBasePool(pDocShell->GetStyleSheetPool())
+ , m_pDocShell(pDocShell)
+ {
+ if (m_pBasePool) //tdf#124142 html docs can have no styles
+ StartListening(*m_pBasePool);
+ }
+
+ //XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override
+ {
+ SolarMutexGuard aGuard;
+ return GetCountOrName(nullptr);
+ };
+ virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override;
+
+ //XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) override
+ { return cppu::UnoType<style::XStyle>::get(); };
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ if(!m_pBasePool)
+ throw uno::RuntimeException();
+ return true;
+ }
+
+ //XNameAccess
+ virtual uno::Any SAL_CALL getByName(const OUString& Name) override;
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName(const OUString& Name) override;
+
+ //XNameContainer
+ virtual void SAL_CALL insertByName(const OUString& Name, const uno::Any& Element) override;
+ virtual void SAL_CALL replaceByName(const OUString& Name, const uno::Any& Element) override;
+ virtual void SAL_CALL removeByName(const OUString& Name) override;
+
+ //XPropertySet
+ virtual uno::Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override
+ { return {}; };
+ virtual void SAL_CALL setPropertyValue( const OUString&, const uno::Any&) override
+ { SAL_WARN("sw.uno", "###unexpected!"); };
+ virtual uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString&, const uno::Reference<beans::XPropertyChangeListener>&) override
+ { SAL_WARN("sw.uno", "###unexpected!"); };
+ virtual void SAL_CALL removePropertyChangeListener( const OUString&, const uno::Reference<beans::XPropertyChangeListener>&) override
+ { SAL_WARN("sw.uno", "###unexpected!"); };
+ virtual void SAL_CALL addVetoableChangeListener(const OUString&, const uno::Reference<beans::XVetoableChangeListener>&) override
+ { SAL_WARN("sw.uno", "###unexpected!"); };
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString&, const uno::Reference<beans::XVetoableChangeListener>&) override
+ { SAL_WARN("sw.uno", "###unexpected!"); };
+
+ //SfxListener
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override
+ {
+ if(rHint.GetId() == SfxHintId::Dying)
+ {
+ m_pBasePool = nullptr;
+ m_pDocShell = nullptr;
+ EndListening(rBC);
+ }
+ }
+
+ //XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override
+ { return {"XStyleFamily"}; };
+ virtual sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override
+ { return cppu::supportsService(this, rServiceName); };
+ virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
+ { return { "com.sun.star.style.StyleFamily" }; }
+};
+}
OUString SwXStyleFamilies::getImplementationName()
{ return {"SwXStyleFamilies"}; }
@@ -497,44 +872,44 @@ uno::Any SAL_CALL SwXStyleFamilies::getByName(const OUString& Name)
SolarMutexGuard aGuard;
if(!IsValid())
throw uno::RuntimeException();
- auto pEntries(lcl_GetStyleFamilyEntries());
- const auto pEntry = std::find_if(pEntries->begin(), pEntries->end(),
- [&Name] (const StyleFamilyEntry& e) { return e.m_sName == Name; });
- if(pEntry == pEntries->end())
+ auto& entries(lcl_GetStyleFamilyEntries());
+ const auto pEntry = std::find_if(entries.begin(), entries.end(),
+ [&Name] (const StyleFamilyEntry& e) { return e.name() == Name; });
+ if(pEntry == entries.end())
throw container::NoSuchElementException();
- return getByIndex(pEntry-pEntries->begin());
+ return getByIndex(pEntry - entries.begin());
}
uno::Sequence< OUString > SwXStyleFamilies::getElementNames()
{
- auto pEntries(lcl_GetStyleFamilyEntries());
- uno::Sequence<OUString> aNames(pEntries->size());
- std::transform(pEntries->begin(), pEntries->end(),
- aNames.getArray(), [] (const StyleFamilyEntry& e) { return e.m_sName; });
+ auto& entries(lcl_GetStyleFamilyEntries());
+ uno::Sequence<OUString> aNames(entries.size());
+ std::transform(entries.begin(), entries.end(),
+ aNames.getArray(), [] (const StyleFamilyEntry& e) { return e.name(); });
return aNames;
}
sal_Bool SwXStyleFamilies::hasByName(const OUString& Name)
{
- auto pEntries(lcl_GetStyleFamilyEntries());
- return std::any_of(pEntries->begin(), pEntries->end(),
- [&Name] (const StyleFamilyEntry& e) { return e.m_sName == Name; });
+ auto& entries(lcl_GetStyleFamilyEntries());
+ return std::any_of(entries.begin(), entries.end(),
+ [&Name] (const StyleFamilyEntry& e) { return e.name() == Name; });
}
sal_Int32 SwXStyleFamilies::getCount()
{
- return lcl_GetStyleFamilyEntries()->size();
+ return lcl_GetStyleFamilyEntries().size();
}
uno::Any SwXStyleFamilies::getByIndex(sal_Int32 nIndex)
{
- auto pEntries(lcl_GetStyleFamilyEntries());
+ auto& entries(lcl_GetStyleFamilyEntries());
SolarMutexGuard aGuard;
- if(nIndex < 0 || nIndex >= static_cast<sal_Int32>(pEntries->size()))
+ if(nIndex < 0 || nIndex >= static_cast<sal_Int32>(entries.size()))
throw lang::IndexOutOfBoundsException();
if(!IsValid())
throw uno::RuntimeException();
- auto eFamily = (*pEntries)[nIndex].m_eFamily;
+ auto eFamily = entries[nIndex].family();
assert(eFamily != SfxStyleFamily::All);
auto& rxFamily = m_vFamilies[eFamily];
if(!rxFamily.is())
@@ -626,246 +1001,18 @@ static bool lcl_GetHeaderFooterItem(
return SfxItemState::SET == eState;
}
-template<enum SfxStyleFamily>
-static sal_Int32 lcl_GetCountOrName(const SwDoc&, OUString*, sal_Int32);
-
-template<>
-sal_Int32 lcl_GetCountOrName<SfxStyleFamily::Char>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
-{
- const sal_uInt16 nBaseCount = nPoolChrHtmlRange + nPoolChrNormalRange;
- nIndex -= nBaseCount;
- sal_Int32 nCount = 0;
- for(auto pFormat : *rDoc.GetCharFormats())
- {
- if(pFormat->IsDefault() && pFormat != rDoc.GetDfltCharFormat())
- continue;
- if(!IsPoolUserFormat(pFormat->GetPoolFormatId()))
- continue;
- if(nIndex == nCount)
- {
- // the default character format needs to be set to "Default!"
- if(rDoc.GetDfltCharFormat() == pFormat)
- *pString = SwResId(STR_POOLCHR_STANDARD);
- else
- *pString = pFormat->GetName();
- break;
- }
- ++nCount;
- }
- return nCount + nBaseCount;
-}
-
-template<>
-sal_Int32 lcl_GetCountOrName<SfxStyleFamily::Para>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
-{
- const sal_uInt16 nBaseCount = nPoolCollHtmlStackedStart + nPoolCollHtmlRange;
- nIndex -= nBaseCount;
- sal_Int32 nCount = 0;
- for(auto pColl : *rDoc.GetTextFormatColls())
- {
- if(pColl->IsDefault())
- continue;
- if(!IsPoolUserFormat(pColl->GetPoolFormatId()))
- continue;
- if(nIndex == nCount)
- {
- *pString = pColl->GetName();
- break;
- }
- ++nCount;
- }
- return nCount + nBaseCount;
-}
-
-template<>
-sal_Int32 lcl_GetCountOrName<SfxStyleFamily::Frame>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
-{
- nIndex -= nPoolFrameRange;
- sal_Int32 nCount = 0;
- for(const auto pFormat : *rDoc.GetFrameFormats())
- {
- if(pFormat->IsDefault() || pFormat->IsAuto())
- continue;
- if(!IsPoolUserFormat(pFormat->GetPoolFormatId()))
- continue;
- if(nIndex == nCount)
- {
- *pString = pFormat->GetName();
- break;
- }
- ++nCount;
- }
- return nCount + nPoolFrameRange;
-}
-
-template<>
-sal_Int32 lcl_GetCountOrName<SfxStyleFamily::Page>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
-{
- nIndex -= nPoolPageRange;
- sal_Int32 nCount = 0;
- const size_t nArrLen = rDoc.GetPageDescCnt();
- for(size_t i = 0; i < nArrLen; ++i)
- {
- const SwPageDesc& rDesc = rDoc.GetPageDesc(i);
- if(!IsPoolUserFormat(rDesc.GetPoolFormatId()))
- continue;
- if(nIndex == nCount)
- {
- *pString = rDesc.GetName();
- break;
- }
- ++nCount;
- }
- nCount += nPoolPageRange;
- return nCount;
-}
-
-template<>
-sal_Int32 lcl_GetCountOrName<SfxStyleFamily::Pseudo>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
-{
- nIndex -= nPoolNumRange;
- sal_Int32 nCount = 0;
- for(const auto pRule : rDoc.GetNumRuleTable())
- {
- if(pRule->IsAutoRule())
- continue;
- if(!IsPoolUserFormat(pRule->GetPoolFormatId()))
- continue;
- if(nIndex == nCount)
- {
- *pString = pRule->GetName();
- break;
- }
- ++nCount;
- }
- return nCount + nPoolNumRange;
-}
-
-template<>
-sal_Int32 lcl_GetCountOrName<SfxStyleFamily::Table>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
-{
- if (!rDoc.HasTableStyles())
- return 0;
-
- const auto pAutoFormats = &rDoc.GetTableStyles();
- const sal_Int32 nCount = pAutoFormats->size();
- if (0 <= nIndex && nIndex < nCount)
- *pString = pAutoFormats->operator[](nIndex).GetName();
-
- return nCount;
-}
-
-template<>
-sal_Int32 lcl_GetCountOrName<SfxStyleFamily::Cell>(const SwDoc& rDoc, OUString* pString, sal_Int32 nIndex)
-{
- const auto& rAutoFormats = rDoc.GetTableStyles();
- const auto& rTableTemplateMap = SwTableAutoFormat::GetTableTemplateMap();
- const sal_Int32 nUsedCellStylesCount = rAutoFormats.size() * rTableTemplateMap.size();
- const sal_Int32 nCount = nUsedCellStylesCount + rDoc.GetCellStyles().size();
- if (0 <= nIndex && nIndex < nCount)
- {
- if (nUsedCellStylesCount > nIndex)
- {
- const sal_Int32 nAutoFormat = nIndex / rTableTemplateMap.size();
- const sal_Int32 nBoxFormat = rTableTemplateMap[nIndex % rTableTemplateMap.size()];
- const SwTableAutoFormat& rTableFormat = rAutoFormats[nAutoFormat];
- SwStyleNameMapper::FillProgName(rTableFormat.GetName(), *pString, SwGetPoolIdFromName::TabStyle);
- *pString += rTableFormat.GetTableTemplateCellSubName(rTableFormat.GetBoxFormat(nBoxFormat));
- }
- else
- *pString = rDoc.GetCellStyles()[nIndex-nUsedCellStylesCount].GetName();
- }
- return nCount;
-}
-
-template<SfxStyleFamily eFamily>
-static uno::Reference< css::style::XStyle> lcl_CreateStyle(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName)
- { return pBasePool ? new SwXStyle(pBasePool, eFamily, pDocShell->GetDoc(), sStyleName) : new SwXStyle(pDocShell->GetDoc(), eFamily, false); };
-
-template<>
-uno::Reference< css::style::XStyle> lcl_CreateStyle<SfxStyleFamily::Para>(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName)
- { return pBasePool ? new SwXStyle(pBasePool, SfxStyleFamily::Para, pDocShell->GetDoc(), sStyleName) : new SwXStyle(pDocShell->GetDoc(), SfxStyleFamily::Para, false); };
-template<>
-uno::Reference< css::style::XStyle> lcl_CreateStyle<SfxStyleFamily::Frame>(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName)
- { return pBasePool ? new SwXFrameStyle(*pBasePool, pDocShell->GetDoc(), sStyleName) : new SwXFrameStyle(pDocShell->GetDoc()); };
-
-template<>
-uno::Reference< css::style::XStyle> lcl_CreateStyle<SfxStyleFamily::Page>(SfxStyleSheetBasePool* pBasePool, SwDocShell* pDocShell, const OUString& sStyleName)
- { return pBasePool ? new SwXPageStyle(*pBasePool, pDocShell, sStyleName) : new SwXPageStyle(pDocShell); };
-
-template<>
-uno::Reference< css::style::XStyle> lcl_CreateStyle<SfxStyleFamily::Table>(SfxStyleSheetBasePool* /*pBasePool*/, SwDocShell* pDocShell, const OUString& sStyleName)
- { return SwXTextTableStyle::CreateXTextTableStyle(pDocShell, sStyleName); };
-
-template<>
-uno::Reference< css::style::XStyle> lcl_CreateStyle<SfxStyleFamily::Cell>(SfxStyleSheetBasePool* /*pBasePool*/, SwDocShell* pDocShell, const OUString& sStyleName)
- { return SwXTextCellStyle::CreateXTextCellStyle(pDocShell, sStyleName); };
-
uno::Reference<css::style::XStyle> SwXStyleFamilies::CreateStyle(SfxStyleFamily eFamily, SwDoc& rDoc)
{
- auto pEntries(lcl_GetStyleFamilyEntries());
- const auto pEntry = std::find_if(pEntries->begin(), pEntries->end(),
- [eFamily] (const StyleFamilyEntry& e) { return e.m_eFamily == eFamily; });
- return pEntry == pEntries->end() ? nullptr : pEntry->m_fCreateStyle(nullptr, rDoc.GetDocShell(), "");
+ auto& entries(lcl_GetStyleFamilyEntries());
+ const auto pEntry = std::find_if(entries.begin(), entries.end(),
+ [eFamily] (const StyleFamilyEntry& e) { return e.family() == eFamily; });
+ return pEntry == entries.end() ? nullptr : pEntry->createStyle(nullptr, rDoc.GetDocShell(), "");
}
// FIXME: Ugly special casing that should die.
uno::Reference<css::style::XStyle> SwXStyleFamilies::CreateStyleCondParagraph(SwDoc& rDoc)
{ return new SwXStyle(&rDoc, SfxStyleFamily::Para, true); };
-template<enum SfxStyleFamily>
-static sal_uInt16 lcl_TranslateIndex(const sal_uInt16 nIndex);
-
-template<>
-sal_uInt16 lcl_TranslateIndex<SfxStyleFamily::Char>(const sal_uInt16 nIndex)
-{
- static_assert(nPoolChrNormalRange > 0 && nPoolChrHtmlRange > 0, "invalid pool range");
- if(nIndex < nPoolChrNormalRange)
- return nIndex + RES_POOLCHR_NORMAL_BEGIN;
- else if(nIndex < (nPoolChrHtmlRange+nPoolChrNormalRange))
- return nIndex + RES_POOLCHR_HTML_BEGIN - nPoolChrNormalRange;
- throw lang::IndexOutOfBoundsException();
-}
-
-template<>
-sal_uInt16 lcl_TranslateIndex<SfxStyleFamily::Para>(const sal_uInt16 nIndex)
-{
- static_assert(nPoolCollTextRange > 0 && nPoolCollListsRange > 0 && nPoolCollExtraRange > 0 && nPoolCollRegisterRange > 0 && nPoolCollDocRange > 0 && nPoolCollHtmlRange > 0, "weird pool range");
- if(nIndex < nPoolCollListsStackedStart)
- return nIndex + RES_POOLCOLL_TEXT_BEGIN;
- else if(nIndex < nPoolCollExtraStackedStart)
- return nIndex + RES_POOLCOLL_LISTS_BEGIN - nPoolCollListsStackedStart;
- else if(nIndex < nPoolCollRegisterStackedStart)
- return nIndex + RES_POOLCOLL_EXTRA_BEGIN - nPoolCollExtraStackedStart;
- else if(nIndex < nPoolCollDocStackedStart)
- return nIndex + RES_POOLCOLL_REGISTER_BEGIN - nPoolCollRegisterStackedStart;
- else if(nIndex < nPoolCollHtmlStackedStart)
- return nIndex + RES_POOLCOLL_DOC_BEGIN - nPoolCollDocStackedStart;
- else if(nIndex < nPoolCollHtmlStackedStart + nPoolCollTextRange)
- return nIndex + RES_POOLCOLL_HTML_BEGIN - nPoolCollHtmlStackedStart;
- throw lang::IndexOutOfBoundsException();
-}
-
-template<>
-sal_uInt16 lcl_TranslateIndex<SfxStyleFamily::Table>(const sal_uInt16 nIndex)
-{
- return nIndex;
-}
-
-template<>
-sal_uInt16 lcl_TranslateIndex<SfxStyleFamily::Cell>(const sal_uInt16 nIndex)
-{
- return nIndex;
-}
-
-template<sal_uInt16 nRangeBegin, sal_uInt16 nRangeSize>
-static sal_uInt16 lcl_TranslateIndexRange(const sal_uInt16 nIndex)
-{
- if(nIndex < nRangeSize)
- return nIndex + nRangeBegin;
- throw lang::IndexOutOfBoundsException();
-}
-
uno::Any XStyleFamily::getByIndex(sal_Int32 nIndex)
{
SolarMutexGuard aGuard;
@@ -876,7 +1023,7 @@ uno::Any XStyleFamily::getByIndex(sal_Int32 nIndex)
OUString sStyleName;
try
{
- SwStyleNameMapper::FillUIName(m_rEntry.m_fTranslateIndex(nIndex), sStyleName);
+ SwStyleNameMapper::FillUIName(m_rEntry.translateIndex(nIndex), sStyleName);
} catch(...) {}
if (sStyleName.isEmpty())
GetCountOrName(&sStyleName, nIndex);
@@ -889,15 +1036,15 @@ uno::Any XStyleFamily::getByName(const OUString& rName)
{
SolarMutexGuard aGuard;
OUString sStyleName;
- SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.m_aPoolId);
+ SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.poolId());
if(!m_pBasePool)
throw uno::RuntimeException();
- SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.family());
if(!pBase)
throw container::NoSuchElementException(rName);
uno::Reference<style::XStyle> xStyle = FindStyle(sStyleName);
if(!xStyle.is())
- xStyle = m_rEntry.m_fCreateStyle(m_pBasePool, m_pDocShell, m_rEntry.m_eFamily == SfxStyleFamily::Frame ? pBase->GetName() : sStyleName);
+ xStyle = m_rEntry.createStyle(m_pBasePool, m_pDocShell, m_rEntry.family() == SfxStyleFamily::Frame ? pBase->GetName() : sStyleName);
return uno::makeAny(xStyle);
}
@@ -907,11 +1054,11 @@ uno::Sequence<OUString> XStyleFamily::getElementNames()
if(!m_pBasePool)
throw uno::RuntimeException();
std::vector<OUString> vRet;
- std::unique_ptr<SfxStyleSheetIterator> pIt = m_pBasePool->CreateIterator(m_rEntry.m_eFamily);
+ std::unique_ptr<SfxStyleSheetIterator> pIt = m_pBasePool->CreateIterator(m_rEntry.family());
for (SfxStyleSheetBase* pStyle = pIt->First(); pStyle; pStyle = pIt->Next())
{
OUString sName;
- SwStyleNameMapper::FillProgName(pStyle->GetName(), sName, m_rEntry.m_aPoolId);
+ SwStyleNameMapper::FillProgName(pStyle->GetName(), sName, m_rEntry.poolId());
vRet.push_back(sName);
}
return comphelper::containerToSequence(vRet);
@@ -923,8 +1070,8 @@ sal_Bool XStyleFamily::hasByName(const OUString& rName)
if(!m_pBasePool)
throw uno::RuntimeException();
OUString sStyleName;
- SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.m_aPoolId);
- SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.m_eFamily);
+ SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.poolId());
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.family());
return nullptr != pBase;
}
@@ -934,14 +1081,14 @@ void XStyleFamily::insertByName(const OUString& rName, const uno::Any& rElement)
if(!m_pBasePool)
throw uno::RuntimeException();
OUString sStyleName;
- SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.m_aPoolId);
- SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.m_eFamily);
- SfxStyleSheetBase* pUINameBase = m_pBasePool->Find(sStyleName, m_rEntry.m_eFamily);
+ SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.poolId());
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.family());
+ SfxStyleSheetBase* pUINameBase = m_pBasePool->Find(sStyleName, m_rEntry.family());
if(pBase || pUINameBase)
throw container::ElementExistException();
if(rElement.getValueType().getTypeClass() != uno::TypeClass_INTERFACE)
throw lang::IllegalArgumentException();
- if (SwGetPoolIdFromName::CellStyle == m_rEntry.m_aPoolId)
+ if (SwGetPoolIdFromName::CellStyle == m_rEntry.poolId())
{
// handle cell style
uno::Reference<style::XStyle> xStyle = rElement.get<uno::Reference<style::XStyle>>();
@@ -953,7 +1100,7 @@ void XStyleFamily::insertByName(const OUString& rName, const uno::Any& rElement)
m_pDocShell->GetDoc()->GetCellStyles().AddBoxFormat(*pNewStyle->GetBoxFormat(), sStyleName);
pNewStyle->SetPhysical();
}
- else if (SwGetPoolIdFromName::TabStyle == m_rEntry.m_aPoolId)
+ else if (SwGetPoolIdFromName::TabStyle == m_rEntry.poolId())
{
// handle table style
uno::Reference<style::XStyle> xStyle = rElement.get<uno::Reference<style::XStyle>>();
@@ -969,22 +1116,22 @@ void XStyleFamily::insertByName(const OUString& rName, const uno::Any& rElement)
{
uno::Reference<lang::XUnoTunnel> xStyleTunnel = rElement.get<uno::Reference<lang::XUnoTunnel>>();
SwXStyle* pNewStyle = comphelper::getFromUnoTunnel<SwXStyle>(xStyleTunnel);
- if (!pNewStyle || !pNewStyle->IsDescriptor() || pNewStyle->GetFamily() != m_rEntry.m_eFamily)
+ if (!pNewStyle || !pNewStyle->IsDescriptor() || pNewStyle->GetFamily() != m_rEntry.family())
throw lang::IllegalArgumentException();
SfxStyleSearchBits nMask = SfxStyleSearchBits::All;
- if(m_rEntry.m_eFamily == SfxStyleFamily::Para && !pNewStyle->IsConditional())
+ if(m_rEntry.family() == SfxStyleFamily::Para && !pNewStyle->IsConditional())
nMask &= ~SfxStyleSearchBits::SwCondColl;
- m_pBasePool->Make(sStyleName, m_rEntry.m_eFamily, nMask);
+ m_pBasePool->Make(sStyleName, m_rEntry.family(), nMask);
pNewStyle->SetDoc(m_pDocShell->GetDoc(), m_pBasePool);
pNewStyle->SetStyleName(sStyleName);
const OUString sParentStyleName(pNewStyle->GetParentStyleName());
if (!sParentStyleName.isEmpty())
{
- SfxStyleSheetBase* pParentBase = m_pBasePool->Find(sParentStyleName, m_rEntry.m_eFamily);
- if(pParentBase && pParentBase->GetFamily() == m_rEntry.m_eFamily &&
+ SfxStyleSheetBase* pParentBase = m_pBasePool->Find(sParentStyleName, m_rEntry.family());
+ if(pParentBase && pParentBase->GetFamily() == m_rEntry.family() &&
pParentBase->GetPool() == m_pBasePool)
- m_pBasePool->SetParent(m_rEntry.m_eFamily, sStyleName, sParentStyleName);
+ m_pBasePool->SetParent(m_rEntry.family(), sStyleName, sParentStyleName);
}
// after all, we still need to apply the properties of the descriptor
pNewStyle->ApplyDescriptorProperties();
@@ -997,12 +1144,12 @@ void XStyleFamily::replaceByName(const OUString& rName, const uno::Any& rElement
if(!m_pBasePool)
throw uno::RuntimeException();
OUString sStyleName;
- SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.m_aPoolId);
- SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.m_eFamily);
+ SwStyleNameMapper::FillUIName(rName, sStyleName, m_rEntry.poolId());
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(sStyleName, m_rEntry.family());
// replacements only for userdefined styles
if(!pBase)
throw container::NoSuchElementException();
- if (SwGetPoolIdFromName::CellStyle == m_rEntry.m_aPoolId)
+ if (SwGetPoolIdFromName::CellStyle == m_rEntry.poolId())
{
// handle cell styles, don't call on assigned cell styles (TableStyle child)
OUString sParent;
@@ -1019,7 +1166,7 @@ void XStyleFamily::replaceByName(const OUString& rName, const uno::Any& rElement
pStyleToReplaceWith->SetPhysical();
}
}
- else if (SwGetPoolIdFromName::TabStyle == m_rEntry.m_aPoolId)
+ else if (SwGetPoolIdFromName::TabStyle == m_rEntry.poolId())
{
// handle table styles
SwTableAutoFormat* pTableAutoFormat = SwXTextTableStyle::GetTableAutoFormat(m_pDocShell, sStyleName);
@@ -1058,16 +1205,16 @@ void XStyleFamily::removeByName(const OUString& rName)
if(!m_pBasePool)
throw uno::RuntimeException();
OUString sName;
- SwStyleNameMapper::FillUIName(rName, sName, m_rEntry.m_aPoolId);
- SfxStyleSheetBase* pBase = m_pBasePool->Find(sName, m_rEntry.m_eFamily);
+ SwStyleNameMapper::FillUIName(rName, sName, m_rEntry.poolId());
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(sName, m_rEntry.family());
if(!pBase)
throw container::NoSuchElementException();
- if (SwGetPoolIdFromName::CellStyle == m_rEntry.m_aPoolId)
+ if (SwGetPoolIdFromName::CellStyle == m_rEntry.poolId())
{
// handle cell style
m_pDocShell->GetDoc()->GetCellStyles().RemoveBoxFormat(rName);
}
- else if (SwGetPoolIdFromName::TabStyle == m_rEntry.m_aPoolId)
+ else if (SwGetPoolIdFromName::TabStyle == m_rEntry.poolId())
{
// handle table style
m_pDocShell->GetDoc()->GetTableStyles().EraseAutoFormat(rName);
@@ -1081,7 +1228,7 @@ uno::Any SAL_CALL XStyleFamily::getPropertyValue( const OUString& sPropertyName
if(sPropertyName != "DisplayName")
throw beans::UnknownPropertyException( "unknown property: " + sPropertyName, static_cast<OWeakObject *>(this) );
SolarMutexGuard aGuard;
- return uno::makeAny(SwResId(m_rEntry.m_pResId));
+ return uno::makeAny(SwResId(m_rEntry.resId()));
}
@@ -1092,117 +1239,23 @@ SwXStyle* XStyleFamily::FindStyle(std::u16string_view rStyleName) const
{
SfxListener* pListener = m_pBasePool->GetListener(i);
SwXStyle* pTempStyle = dynamic_cast<SwXStyle*>(pListener);
- if(pTempStyle && pTempStyle->GetFamily() == m_rEntry.m_eFamily && pTempStyle->GetStyleName() == rStyleName)
+ if(pTempStyle && pTempStyle->GetFamily() == m_rEntry.family() && pTempStyle->GetStyleName() == rStyleName)
return pTempStyle;
}
return nullptr;
}
-static const std::vector<StyleFamilyEntry>* lcl_GetStyleFamilyEntries()
-{
- if(!our_pStyleFamilyEntries)
- {
- our_pStyleFamilyEntries = new std::vector<StyleFamilyEntry>{
- { SfxStyleFamily::Char, PROPERTY_MAP_CHAR_STYLE, SwGetPoolIdFromName::ChrFmt, "CharacterStyles", STR_STYLE_FAMILY_CHARACTER, &lcl_GetCountOrName<SfxStyleFamily::Char>, &lcl_CreateStyle<SfxStyleFamily::Char>, &lcl_TranslateIndex<SfxStyleFamily::Char> },
- { SfxStyleFamily::Para, PROPERTY_MAP_PARA_STYLE, SwGetPoolIdFromName::TxtColl, "ParagraphStyles", STR_STYLE_FAMILY_PARAGRAPH, &lcl_GetCountOrName<SfxStyleFamily::Para>, &lcl_CreateStyle<SfxStyleFamily::Para>, &lcl_TranslateIndex<SfxStyleFamily::Para> },
- { SfxStyleFamily::Page, PROPERTY_MAP_PAGE_STYLE, SwGetPoolIdFromName::PageDesc, "PageStyles", STR_STYLE_FAMILY_PAGE, &lcl_GetCountOrName<SfxStyleFamily::Page>, &lcl_CreateStyle<SfxStyleFamily::Page>, &lcl_TranslateIndexRange<RES_POOLPAGE_BEGIN, nPoolPageRange> },
- { SfxStyleFamily::Frame, PROPERTY_MAP_FRAME_STYLE, SwGetPoolIdFromName::FrmFmt, "FrameStyles", STR_STYLE_FAMILY_FRAME, &lcl_GetCountOrName<SfxStyleFamily::Frame>, &lcl_CreateStyle<SfxStyleFamily::Frame>, &lcl_TranslateIndexRange<RES_POOLFRM_BEGIN, nPoolFrameRange> },
- { SfxStyleFamily::Pseudo, PROPERTY_MAP_NUM_STYLE, SwGetPoolIdFromName::NumRule, "NumberingStyles", STR_STYLE_FAMILY_NUMBERING, &lcl_GetCountOrName<SfxStyleFamily::Pseudo>, &lcl_CreateStyle<SfxStyleFamily::Pseudo>, &lcl_TranslateIndexRange<RES_POOLNUMRULE_BEGIN, nPoolNumRange> },
- { SfxStyleFamily::Table, PROPERTY_MAP_TABLE_STYLE, SwGetPoolIdFromName::TabStyle, "TableStyles", STR_STYLE_FAMILY_TABLE, &lcl_GetCountOrName<SfxStyleFamily::Table>, &lcl_CreateStyle<SfxStyleFamily::Table>, &lcl_TranslateIndex<SfxStyleFamily::Table> },
- { SfxStyleFamily::Cell, PROPERTY_MAP_CELL_STYLE, SwGetPoolIdFromName::CellStyle,"CellStyles", STR_STYLE_FAMILY_CELL, &lcl_GetCountOrName<SfxStyleFamily::Cell>, &lcl_CreateStyle<SfxStyleFamily::Cell>, &lcl_TranslateIndex<SfxStyleFamily::Cell> }
- };
- }
- return our_pStyleFamilyEntries;
-}
-
-static const std::vector<ParagraphStyleCategoryEntry>* lcl_GetParagraphStyleCategoryEntries()
-{
- if(!our_pParagraphStyleCategoryEntries)
- {
- our_pParagraphStyleCategoryEntries = new std::vector<ParagraphStyleCategoryEntry>{
- { style::ParagraphStyleCategory::TEXT, SfxStyleSearchBits::SwText, COLL_TEXT_BITS },
- { style::ParagraphStyleCategory::CHAPTER, SfxStyleSearchBits::SwChapter, COLL_DOC_BITS },
- { style::ParagraphStyleCategory::LIST, SfxStyleSearchBits::SwList, COLL_LISTS_BITS },
- { style::ParagraphStyleCategory::INDEX, SfxStyleSearchBits::SwIndex, COLL_REGISTER_BITS },
- { style::ParagraphStyleCategory::EXTRA, SfxStyleSearchBits::SwExtra, COLL_EXTRA_BITS },
- { style::ParagraphStyleCategory::HTML, SfxStyleSearchBits::SwHtml, COLL_HTML_BITS }
- };
- }
- return our_pParagraphStyleCategoryEntries;
-}
-
-namespace {
-
-class SwStyleProperties_Impl
-{
- const SfxItemPropertyMap& mrMap;
- std::map<OUString, uno::Any> m_vPropertyValues;
-public:
- explicit SwStyleProperties_Impl(const SfxItemPropertyMap& rMap)
- : mrMap(rMap)
- { }
-
- bool AllowsKey(std::u16string_view rName)
- {
- return mrMap.hasPropertyByName(rName);
- }
- bool SetProperty(const OUString& rName, const uno::Any& rValue)
- {
- if(!AllowsKey(rName))
- return false;
- m_vPropertyValues[rName] = rValue;
- return true;
- }
- void GetProperty(const OUString& rName, const uno::Any*& pAny)
- {
- if(!AllowsKey(rName))
- {
- pAny = nullptr;
- return;
- }
- pAny = &m_vPropertyValues[rName];
- return;
- }
- bool ClearProperty( const OUString& rName )
- {
- if(!AllowsKey(rName))
- return false;
- m_vPropertyValues[rName] = uno::Any();
- return true;
- }
- void ClearAllProperties( )
- { m_vPropertyValues.clear(); }
- void Apply(SwXStyle& rStyle)
- {
- for(const auto& rPropertyPair : m_vPropertyValues)
- {
- if(rPropertyPair.second.hasValue())
- rStyle.setPropertyValue(rPropertyPair.first, rPropertyPair.second);
- }
- }
- static void GetProperty(const OUString &rPropertyName, const uno::Reference < beans::XPropertySet > &rxPropertySet, uno::Any& rAny )
- {
- rAny = rxPropertySet->getPropertyValue( rPropertyName );
- }
-};
-
-}
-
static SwGetPoolIdFromName lcl_GetSwEnumFromSfxEnum(SfxStyleFamily eFamily)
{
- auto pEntries(lcl_GetStyleFamilyEntries());
- const auto pEntry = std::find_if(pEntries->begin(), pEntries->end(),
- [eFamily] (const StyleFamilyEntry& e) { return e.m_eFamily == eFamily; });
- if(pEntry != pEntries->end())
- return pEntry->m_aPoolId;
+ auto& entries(lcl_GetStyleFamilyEntries());
+ const auto pEntry = std::find_if(entries.begin(), entries.end(),
+ [eFamily] (const StyleFamilyEntry& e) { return e.family() == eFamily; });
+ if(pEntry != entries.end())
+ return pEntry->poolId();
SAL_WARN("sw.uno", "someone asking for all styles in unostyle.cxx!" );
return SwGetPoolIdFromName::ChrFmt;
}
-namespace
-{
-}
-
const uno::Sequence<sal_Int8>& SwXStyle::getUnoTunnelId()
{
static const comphelper::UnoIdInit theSwXStyleUnoTunnelId;
@@ -1218,20 +1271,20 @@ sal_Int64 SAL_CALL SwXStyle::getSomething(const uno::Sequence<sal_Int8>& rId)
uno::Sequence< OUString > SwXStyle::getSupportedServiceNames()
{
tools::Long nCount = 1;
- if(SfxStyleFamily::Para == m_rEntry.m_eFamily)
+ if(SfxStyleFamily::Para == m_rEntry.family())
{
nCount = 5;
if(m_bIsConditional)
nCount++;
}
- else if(SfxStyleFamily::Char == m_rEntry.m_eFamily)
+ else if(SfxStyleFamily::Char == m_rEntry.family())
nCount = 5;
- else if(SfxStyleFamily::Page == m_rEntry.m_eFamily)
+ else if(SfxStyleFamily::Page == m_rEntry.family())
nCount = 3;
uno::Sequence< OUString > aRet(nCount);
OUString* pArray = aRet.getArray();
pArray[0] = "com.sun.star.style.Style";
- switch(m_rEntry.m_eFamily)
+ switch(m_rEntry.family())
{
case SfxStyleFamily::Char:
pArray[1] = "com.sun.star.style.CharacterStyle";
@@ -1272,14 +1325,14 @@ static uno::Reference<beans::XPropertySet> lcl_InitStandardStyle(const SfxStyleF
static uno::Reference<container::XNameAccess> lcl_InitStyleFamily(SwDoc* pDoc, const StyleFamilyEntry& rEntry)
{
using return_t = decltype(lcl_InitStyleFamily(pDoc, rEntry));
- if(rEntry.m_eFamily != SfxStyleFamily::Char
- && rEntry.m_eFamily != SfxStyleFamily::Para
- && rEntry.m_eFamily != SfxStyleFamily::Page)
+ if(rEntry.family() != SfxStyleFamily::Char
+ && rEntry.family() != SfxStyleFamily::Para
+ && rEntry.family() != SfxStyleFamily::Page)
return {};
auto xModel(pDoc->GetDocShell()->GetBaseModel());
uno::Reference<style::XStyleFamiliesSupplier> xFamilySupplier(xModel, uno::UNO_QUERY);
auto xFamilies = xFamilySupplier->getStyleFamilies();
- auto aResult(xFamilies->getByName(rEntry.m_sName));
+ auto aResult(xFamilies->getByName(rEntry.name()));
if(!aResult.has<return_t>())
return {};
return aResult.get<return_t>();
@@ -1301,10 +1354,10 @@ static bool lcl_InitConditional(SfxStyleSheetBasePool* pBasePool, const SfxStyle
static const StyleFamilyEntry& lcl_GetStyleEntry(const SfxStyleFamily eFamily)
{
- auto pEntries = lcl_GetStyleFamilyEntries();
- const auto pEntry = std::find_if(pEntries->begin(), pEntries->end(),
- [eFamily] (const StyleFamilyEntry& e) { return e.m_eFamily == eFamily; });
- assert(pEntry != pEntries->end());
+ auto& entries = lcl_GetStyleFamilyEntries();
+ const auto pEntry = std::find_if(entries.begin(), entries.end(),
+ [eFamily] (const StyleFamilyEntry& e) { return e.family() == eFamily; });
+ assert(pEntry != entries.end());
return *pEntry;
}
@@ -1317,11 +1370,11 @@ SwXStyle::SwXStyle(SwDoc* pDoc, SfxStyleFamily eFamily, bool bConditional)
, m_xStyleFamily(lcl_InitStyleFamily(pDoc, m_rEntry))
, m_xStyleData(lcl_InitStandardStyle(eFamily, m_xStyleFamily))
{
- assert(!m_bIsConditional || m_rEntry.m_eFamily == SfxStyleFamily::Para); // only paragraph styles are conditional
+ assert(!m_bIsConditional || m_rEntry.family() == SfxStyleFamily::Para); // only paragraph styles are conditional
// Register ourselves as a listener to the document (via the page descriptor)
SvtListener::StartListening(pDoc->getIDocumentStylePoolAccess().GetPageDescFromPool(RES_POOLPAGE_STANDARD)->GetNotifier());
m_pPropertiesImpl = std::make_unique<SwStyleProperties_Impl>(
- aSwMapProvider.GetPropertySet(m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.m_nPropMapType)->getPropertyMap());
+ aSwMapProvider.GetPropertySet(m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType())->getPropertyMap());
}
SwXStyle::SwXStyle(SfxStyleSheetBasePool* pPool, SfxStyleFamily eFamily, SwDoc* pDoc, const OUString& rStyleName)
@@ -1357,12 +1410,12 @@ OUString SwXStyle::getName()
SolarMutexGuard aGuard;
if(!m_pBasePool)
return m_sStyleName;
- SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family());
SAL_WARN_IF(!pBase, "sw.uno", "where is the style?");
if(!pBase)
throw uno::RuntimeException();
OUString aString;
- SwStyleNameMapper::FillProgName(pBase->GetName(), aString, lcl_GetSwEnumFromSfxEnum ( m_rEntry.m_eFamily ));
+ SwStyleNameMapper::FillProgName(pBase->GetName(), aString, lcl_GetSwEnumFromSfxEnum ( m_rEntry.family()));
return aString;
}
@@ -1374,7 +1427,7 @@ void SwXStyle::setName(const OUString& rName)
m_sStyleName = rName;
return;
}
- SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family());
SAL_WARN_IF(!pBase, "sw.uno", "where is the style?");
if(!pBase || !pBase->IsUserDefined())
throw uno::RuntimeException();
@@ -1389,7 +1442,7 @@ sal_Bool SwXStyle::isUserDefined()
SolarMutexGuard aGuard;
if(!m_pBasePool)
throw uno::RuntimeException();
- SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family());
//if it is not found it must be non user defined
return pBase && pBase->IsUserDefined();
}
@@ -1399,7 +1452,7 @@ sal_Bool SwXStyle::isInUse()
SolarMutexGuard aGuard;
if(!m_pBasePool)
throw uno::RuntimeException();
- SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.m_eFamily, SfxStyleSearchBits::Used);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family(), SfxStyleSearchBits::Used);
return pBase && pBase->IsUsed();
}
@@ -1412,11 +1465,11 @@ OUString SwXStyle::getParentStyle()
throw uno::RuntimeException();
return m_sParentStyleName;
}
- SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family());
OUString aString;
if(pBase)
aString = pBase->GetParent();
- SwStyleNameMapper::FillProgName(aString, aString, lcl_GetSwEnumFromSfxEnum(m_rEntry.m_eFamily));
+ SwStyleNameMapper::FillProgName(aString, aString, lcl_GetSwEnumFromSfxEnum(m_rEntry.family()));
return aString;
}
@@ -1424,7 +1477,7 @@ void SwXStyle::setParentStyle(const OUString& rParentStyle)
{
SolarMutexGuard aGuard;
OUString sParentStyle;
- SwStyleNameMapper::FillUIName(rParentStyle, sParentStyle, lcl_GetSwEnumFromSfxEnum ( m_rEntry.m_eFamily ) );
+ SwStyleNameMapper::FillUIName(rParentStyle, sParentStyle, lcl_GetSwEnumFromSfxEnum ( m_rEntry.family()) );
if(!m_pBasePool)
{
if(!m_bIsDescriptor)
@@ -1439,7 +1492,7 @@ void SwXStyle::setParentStyle(const OUString& rParentStyle)
{ }
return;
}
- SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family());
if(!pBase)
throw uno::RuntimeException();
rtl::Reference<SwDocStyleSheet> xBase(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase)));
@@ -1456,12 +1509,11 @@ uno::Reference<beans::XPropertySetInfo> SwXStyle::getPropertySetInfo()
{
if(m_bIsConditional)
{
- assert(m_rEntry.m_eFamily == SfxStyleFamily::Para);
- static uno::Reference<beans::XPropertySetInfo> xCondParaRef;
- xCondParaRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CONDITIONAL_PARA_STYLE)->getPropertySetInfo();
+ assert(m_rEntry.family() == SfxStyleFamily::Para);
+ static auto xCondParaRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CONDITIONAL_PARA_STYLE)->getPropertySetInfo();
return xCondParaRef;
}
- return m_rEntry.m_xPSInfo;
+ return m_rEntry.xPSInfo();
}
void SwXStyle::ApplyDescriptorProperties()
@@ -1473,72 +1525,6 @@ void SwXStyle::ApplyDescriptorProperties()
}
namespace {
-
-class SwStyleBase_Impl
-{
-private:
- SwDoc& m_rDoc;
- const SwPageDesc* m_pOldPageDesc;
- rtl::Reference<SwDocStyleSheet> m_xNewBase;
- SfxItemSet* m_pItemSet;
- std::unique_ptr<SfxItemSet> m_pMyItemSet;
- OUString m_rStyleName;
- const SwAttrSet* m_pParentStyle;
-public:
- SwStyleBase_Impl(SwDoc& rSwDoc, const OUString& rName, const SwAttrSet* pParentStyle)
- : m_rDoc(rSwDoc)
- , m_pOldPageDesc(nullptr)
- , m_pItemSet(nullptr)
- , m_rStyleName(rName)
- , m_pParentStyle(pParentStyle)
- { }
-
- rtl::Reference<SwDocStyleSheet>& getNewBase()
- {
- return m_xNewBase;
- }
-
- void setNewBase(SwDocStyleSheet* pNew)
- {
- m_xNewBase = pNew;
- }
-
- bool HasItemSet() const
- {
- return m_xNewBase.is();
- }
-
- SfxItemSet& GetItemSet()
- {
- assert(m_xNewBase.is());
- if(!m_pItemSet)
- {
- m_pMyItemSet.reset(new SfxItemSet(m_xNewBase->GetItemSet()));
- m_pItemSet = m_pMyItemSet.get();
-
- // set parent style to have the correct XFillStyle setting as XFILL_NONE
- if(!m_pItemSet->GetParent() && m_pParentStyle)
- m_pItemSet->SetParent(m_pParentStyle);
- }
- return *m_pItemSet;
- }
-
- const SwPageDesc* GetOldPageDesc();
-
- // still a hack, but a bit more explicit and with a proper scope
- struct ItemSetOverrider
- {
- SwStyleBase_Impl& m_rStyleBase;
- SfxItemSet* m_pOldSet;
- ItemSetOverrider(SwStyleBase_Impl& rStyleBase, SfxItemSet* pTemp)
- : m_rStyleBase(rStyleBase)
- , m_pOldSet(m_rStyleBase.m_pItemSet)
- { m_rStyleBase.m_pItemSet = pTemp; }
- ~ItemSetOverrider()
- { m_rStyleBase.m_pItemSet = m_pOldSet; };
- };
-};
-
const TranslateId STR_POOLPAGE_ARY[] =
{
// Page styles
@@ -1786,7 +1772,7 @@ void SwXStyle::SetPropertyValue<FN_UNO_FOLLOW_STYLE>(const SfxItemPropertyMapEnt
return;
const auto sValue(rValue.get<OUString>());
OUString aString;
- SwStyleNameMapper::FillUIName(sValue, aString, m_rEntry.m_aPoolId);
+ SwStyleNameMapper::FillUIName(sValue, aString, m_rEntry.poolId());
o_rStyleBase.getNewBase()->SetFollow(aString);
}
@@ -1800,7 +1786,7 @@ void SwXStyle::SetPropertyValue<FN_UNO_LINK_STYLE>(const SfxItemPropertyMapEntry
return;
const auto sValue(rValue.get<OUString>());
OUString aString;
- SwStyleNameMapper::FillUIName(sValue, aString, m_rEntry.m_aPoolId);
+ SwStyleNameMapper::FillUIName(sValue, aString, m_rEntry.poolId());
o_rStyleBase.getNewBase()->SetLink(aString);
}
@@ -1844,7 +1830,7 @@ void SwXStyle::SetPropertyValue<sal_uInt16(RES_PAGEDESC)>(const SfxItemPropertyM
template<>
void SwXStyle::SetPropertyValue<sal_uInt16(RES_TEXT_VERT_ADJUST)>(const SfxItemPropertyMapEntry& rEntry, const SfxItemPropertySet& rPropSet, const uno::Any& rValue, SwStyleBase_Impl& o_rStyleBase)
{
- if(m_rEntry.m_eFamily != SfxStyleFamily::Page)
+ if(m_rEntry.family() != SfxStyleFamily::Page)
{
SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, rValue, o_rStyleBase);
return;
@@ -1861,9 +1847,9 @@ void SwXStyle::SetPropertyValue<FN_UNO_IS_AUTO_UPDATE>(const SfxItemPropertyMapE
if(!rValue.has<bool>())
throw lang::IllegalArgumentException();
const bool bAuto(rValue.get<bool>());
- if(SfxStyleFamily::Para == m_rEntry.m_eFamily)
+ if(SfxStyleFamily::Para == m_rEntry.family())
o_rStyleBase.getNewBase()->GetCollection()->SetAutoUpdateFormat(bAuto);
- else if(SfxStyleFamily::Frame == m_rEntry.m_eFamily)
+ else if(SfxStyleFamily::Frame == m_rEntry.family())
o_rStyleBase.getNewBase()->GetFrameFormat()->SetAutoUpdateFormat(bAuto);
}
template<>
@@ -1883,7 +1869,7 @@ void SwXStyle::SetPropertyValue<FN_UNO_PARA_STYLE_CONDITIONS>(const SfxItemPrope
const OUString sValue(rNamedValue.Value.get<OUString>());
// get UI style name from programmatic style name
OUString aStyleName;
- SwStyleNameMapper::FillUIName(sValue, aStyleName, lcl_GetSwEnumFromSfxEnum(m_rEntry.m_eFamily));
+ SwStyleNameMapper::FillUIName(sValue, aStyleName, lcl_GetSwEnumFromSfxEnum(m_rEntry.family()));
// check for correct context and style name
const auto nIdx(GetCommandContextIndex(rNamedValue.Name));
@@ -1907,16 +1893,15 @@ void SwXStyle::SetPropertyValue<FN_UNO_CATEGORY>(const SfxItemPropertyMapEntry&,
{
if(!o_rStyleBase.getNewBase()->IsUserDefined() || !rValue.has<paragraphstyle_t>())
throw lang::IllegalArgumentException();
- static std::optional<std::map<paragraphstyle_t, SfxStyleSearchBits>> pUnoToCore;
- if(!pUnoToCore)
- {
- pUnoToCore.emplace();
- auto pEntries = lcl_GetParagraphStyleCategoryEntries();
- std::transform(pEntries->begin(), pEntries->end(), std::inserter(*pUnoToCore, pUnoToCore->end()),
- [] (const ParagraphStyleCategoryEntry& rEntry) { return std::pair<paragraphstyle_t, SfxStyleSearchBits>(rEntry.m_eCategory, rEntry.m_nSwStyleBits); });
- }
- const auto pUnoToCoreIt(pUnoToCore->find(rValue.get<paragraphstyle_t>()));
- if(pUnoToCoreIt == pUnoToCore->end())
+ static const std::map<paragraphstyle_t, SfxStyleSearchBits> aUnoToCore = []{
+ auto& entries = lcl_GetParagraphStyleCategoryEntries();
+ std::map<paragraphstyle_t, SfxStyleSearchBits> map;
+ std::transform(entries.begin(), entries.end(), std::inserter(map, map.end()),
+ [] (const ParagraphStyleCategoryEntry& rEntry) { return std::make_pair(rEntry.m_eCategory, rEntry.m_nSwStyleBits); });
+ return map;
+ }();
+ const auto pUnoToCoreIt(aUnoToCore.find(rValue.get<paragraphstyle_t>()));
+ if (pUnoToCoreIt == aUnoToCore.end())
throw lang::IllegalArgumentException();
o_rStyleBase.getNewBase()->SetMask( pUnoToCoreIt->second|SfxStyleSearchBits::UserDefined );
}
@@ -1995,7 +1980,7 @@ void SwXStyle::SetPropertyValue<sal_uInt16(RES_PARATR_NUMRULE)>(const SfxItemPro
lcl_TranslateMetric(rEntry, m_pDoc, aValue);
SetPropertyValue<HINT_BEGIN>(rEntry, rPropSet, aValue, o_rStyleBase);
// --> OD 2006-10-18 #i70223#
- if(SfxStyleFamily::Para == m_rEntry.m_eFamily &&
+ if(SfxStyleFamily::Para == m_rEntry.family() &&
o_rStyleBase.getNewBase().is() && o_rStyleBase.getNewBase()->GetCollection() &&
//rBase.getNewBase()->GetCollection()->GetOutlineLevel() < MAXLEVEL /* assigned to list level of outline style */) //#outline level,removed by zhaojianwei
o_rStyleBase.getNewBase()->GetCollection()->IsAssignedToListLevelOfOutlineStyle()) ////<-end,add by zhaojianwei
@@ -2011,10 +1996,7 @@ void SwXStyle::SetStyleProperty(const SfxItemPropertyMapEntry& rEntry, const Sfx
{
using propertytype_t = decltype(rEntry.nWID);
using coresetter_t = std::function<void(SwXStyle&, const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, const uno::Any&, SwStyleBase_Impl&)>;
- static std::optional<std::map<propertytype_t, coresetter_t>> pUnoToCore;
- if(!pUnoToCore)
- {
- pUnoToCore = std::map<propertytype_t, coresetter_t> {
+ static const std::map<propertytype_t, coresetter_t> aUnoToCore{
// these explicit std::mem_fn() calls shouldn't be needed, but apparently MSVC is currently too stupid for C++11 again
{ FN_UNO_HIDDEN, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_HIDDEN>) },
{ FN_UNO_STYLE_INTEROP_GRAB_BAG, std::mem_fn(&SwXStyle::SetPropertyValue<FN_UNO_STYLE_INTEROP_GRAB_BAG>) },
@@ -2038,10 +2020,9 @@ void SwXStyle::SetStyleProperty(const SfxItemPropertyMapEntry& rEntry, const Sfx
{ RES_TXTATR_CJK_RUBY, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_TXTATR_CJK_RUBY)>) },
{ RES_PARATR_DROP, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_PARATR_DROP)>) },
{ RES_PARATR_NUMRULE, std::mem_fn(&SwXStyle::SetPropertyValue<sal_uInt16(RES_PARATR_NUMRULE)>) }
- };
- }
- const auto pUnoToCoreIt(pUnoToCore->find(rEntry.nWID));
- if(pUnoToCoreIt != pUnoToCore->end())
+ };
+ const auto pUnoToCoreIt(aUnoToCore.find(rEntry.nWID));
+ if(pUnoToCoreIt != aUnoToCore.end())
pUnoToCoreIt->second(*this, rEntry, rPropSet, rValue, rBase);
else
{
@@ -2057,7 +2038,7 @@ void SwXStyle::SetPropertyValues_Impl(const uno::Sequence<OUString>& rPropertyNa
{
if(!m_pDoc)
throw uno::RuntimeException();
- sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.m_nPropMapType;
+ sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType();
const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId);
const SfxItemPropertyMap &rMap = pPropSet->getPropertyMap();
if(rPropertyNames.getLength() != rValues.getLength())
@@ -2066,7 +2047,7 @@ void SwXStyle::SetPropertyValues_Impl(const uno::Sequence<OUString>& rPropertyNa
SwStyleBase_Impl aBaseImpl(*m_pDoc, m_sStyleName, &GetDoc()->GetDfltTextFormatColl()->GetAttrSet()); // add pDfltTextFormatColl as parent
if(m_pBasePool)
{
- SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family());
SAL_WARN_IF(!pBase, "sw.uno", "where is the style?");
if(!pBase)
throw uno::RuntimeException();
@@ -2116,7 +2097,7 @@ SfxStyleSheetBase* SwXStyle::GetStyleSheetBase()
{
if(!m_pBasePool)
return nullptr;
- SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family());
return pBase;
}
void SwXStyle::PrepareStyleBase(SwStyleBase_Impl& rBase)
@@ -2284,19 +2265,18 @@ template<>
uno::Any SwXStyle::GetStyleProperty<FN_UNO_CATEGORY>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase)
{
PrepareStyleBase(rBase);
- static std::optional<std::map<collectionbits_t, paragraphstyle_t>> pUnoToCore;
- if(!pUnoToCore)
- {
- pUnoToCore.emplace();
- auto pEntries = lcl_GetParagraphStyleCategoryEntries();
- std::transform(pEntries->begin(), pEntries->end(), std::inserter(*pUnoToCore, pUnoToCore->end()),
- [] (const ParagraphStyleCategoryEntry& rEntry) { return std::pair<collectionbits_t, paragraphstyle_t>(rEntry.m_nCollectionBits, rEntry.m_eCategory); });
- }
+ static const std::map<collectionbits_t, paragraphstyle_t> aUnoToCore = []{
+ auto& entries = lcl_GetParagraphStyleCategoryEntries();
+ std::map<collectionbits_t, paragraphstyle_t> map;
+ std::transform(entries.begin(), entries.end(), std::inserter(map, map.end()),
+ [] (const ParagraphStyleCategoryEntry& rEntry) { return std::make_pair(rEntry.m_nCollectionBits, rEntry.m_eCategory); });
+ return map;
+ }();
const sal_uInt16 nPoolId = rBase.getNewBase()->GetCollection()->GetPoolFormatId();
- const auto pUnoToCoreIt(pUnoToCore->find(COLL_GET_RANGE_BITS & nPoolId));
- if(pUnoToCoreIt == pUnoToCore->end())
- return uno::makeAny<sal_Int16>(-1);
- return uno::makeAny(pUnoToCoreIt->second);
+ const auto pUnoToCoreIt(aUnoToCore.find(COLL_GET_RANGE_BITS & nPoolId));
+ if(pUnoToCoreIt == aUnoToCore.end())
+ return uno::Any(sal_Int16(-1));
+ return uno::Any(pUnoToCoreIt->second);
}
template<>
uno::Any SwXStyle::GetStyleProperty<SID_SWREGISTER_COLLECTION>(const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl& rBase)
@@ -2365,10 +2345,7 @@ uno::Any SwXStyle::GetStyleProperty_Impl(const SfxItemPropertyMapEntry& rEntry,
{
using propertytype_t = decltype(rEntry.nWID);
using coresetter_t = std::function<uno::Any(SwXStyle&, const SfxItemPropertyMapEntry&, const SfxItemPropertySet&, SwStyleBase_Impl&)>;
- static std::optional<std::map<propertytype_t, coresetter_t>> pUnoToCore;
- if(!pUnoToCore)
- {
- pUnoToCore = std::map<propertytype_t, coresetter_t> {
+ static const std::map<propertytype_t, coresetter_t> aUnoToCore{
// these explicit std::mem_fn() calls shouldn't be needed, but apparently MSVC is currently too stupid for C++11 again
{ FN_UNO_IS_PHYSICAL, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_IS_PHYSICAL>) },
{ FN_UNO_HIDDEN, std::mem_fn(&SwXStyle::GetStyleProperty<FN_UNO_HIDDEN>) },
@@ -2386,10 +2363,9 @@ uno::Any SwXStyle::GetStyleProperty_Impl(const SfxItemPropertyMapEntry& rEntry,
{ SID_SWREGISTER_COLLECTION, std::mem_fn(&SwXStyle::GetStyleProperty<SID_SWREGISTER_COLLECTION>) },
{ RES_BACKGROUND, std::mem_fn(&SwXStyle::GetStyleProperty<sal_uInt16(RES_BACKGROUND)>) },
{ OWN_ATTR_FILLBMP_MODE, std::mem_fn(&SwXStyle::GetStyleProperty<OWN_ATTR_FILLBMP_MODE>) }
- };
- }
- const auto pUnoToCoreIt(pUnoToCore->find(rEntry.nWID));
- if(pUnoToCoreIt != pUnoToCore->end())
+ };
+ const auto pUnoToCoreIt(aUnoToCore.find(rEntry.nWID));
+ if(pUnoToCoreIt != aUnoToCore.end())
return pUnoToCoreIt->second(*this, rEntry, rPropSet, rBase);
return GetStyleProperty<HINT_BEGIN>(rEntry, rPropSet, rBase);
}
@@ -2407,14 +2383,14 @@ uno::Any SwXStyle::GetPropertyValue_Impl(const SfxItemPropertySet* pPropSet, SwS
if(pAny->hasValue())
return *pAny;
uno::Any aValue;
- switch(m_rEntry.m_eFamily)
+ switch(m_rEntry.family())
{
case SfxStyleFamily::Pseudo:
throw uno::RuntimeException("No default value for: " + rPropertyName);
break;
case SfxStyleFamily::Para:
case SfxStyleFamily::Page:
- SwStyleProperties_Impl::GetProperty(rPropertyName, m_xStyleData, aValue);
+ aValue = m_xStyleData->getPropertyValue(rPropertyName);
break;
case SfxStyleFamily::Char:
case SfxStyleFamily::Frame:
@@ -2422,7 +2398,7 @@ uno::Any SwXStyle::GetPropertyValue_Impl(const SfxItemPropertySet* pPropSet, SwS
if(pEntry->nWID < POOLATTR_BEGIN || pEntry->nWID >= RES_UNKNOWNATR_END)
throw uno::RuntimeException("No default value for: " + rPropertyName);
SwFormat* pFormat;
- if(m_rEntry.m_eFamily == SfxStyleFamily::Char)
+ if(m_rEntry.family() == SfxStyleFamily::Char)
pFormat = m_pDoc->GetDfltCharFormat();
else
pFormat = m_pDoc->GetDfltFrameFormat();
@@ -2444,7 +2420,7 @@ uno::Any SwXStyle::getPropertyValue(const OUString& rPropertyName)
throw uno::RuntimeException();
if(!m_pBasePool && !m_bIsDescriptor)
throw uno::RuntimeException();
- sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.m_nPropMapType;
+ sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType();
const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId);
SwStyleBase_Impl aBase(*m_pDoc, m_sStyleName, &m_pDoc->GetDfltTextFormatColl()->GetAttrSet()); // add pDfltTextFormatColl as parent
return GetPropertyValue_Impl(pPropSet, aBase, rPropertyName);
@@ -2457,7 +2433,7 @@ uno::Sequence<uno::Any> SwXStyle::getPropertyValues(const uno::Sequence<OUString
throw uno::RuntimeException();
if(!m_pBasePool && !m_bIsDescriptor)
throw uno::RuntimeException();
- sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.m_nPropMapType;
+ sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType();
const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId);
SwStyleBase_Impl aBase(*m_pDoc, m_sStyleName, &m_pDoc->GetDfltTextFormatColl()->GetAttrSet()); // add pDfltTextFormatColl as parent
uno::Sequence<uno::Any> aValues(rPropertyNames.getLength());
@@ -2521,7 +2497,7 @@ uno::Sequence<beans::PropertyState> SwXStyle::getPropertyStates(const uno::Seque
if(!m_pBasePool)
throw uno::RuntimeException();
- SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pBase = m_pBasePool->Find(m_sStyleName, m_rEntry.family());
SAL_WARN_IF(!pBase, "sw.uno", "where is the style?");
if(!pBase)
@@ -2529,7 +2505,7 @@ uno::Sequence<beans::PropertyState> SwXStyle::getPropertyStates(const uno::Seque
const OUString* pNames = rPropertyNames.getConstArray();
rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase)));
- sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.m_nPropMapType;
+ sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType();
const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId);
const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap();
@@ -2550,7 +2526,7 @@ uno::Sequence<beans::PropertyState> SwXStyle::getPropertyStates(const uno::Seque
pStates[i] = beans::PropertyState_DIRECT_VALUE;
continue;
}
- const SfxItemSet* pSourceSet = lcl_GetItemsetForProperty(rSet, m_rEntry.m_eFamily, sPropName);
+ const SfxItemSet* pSourceSet = lcl_GetItemsetForProperty(rSet, m_rEntry.family(), sPropName);
if(!pSourceSet)
{
// if no SetItem, value is ambiguous and we are done
@@ -2592,7 +2568,7 @@ uno::Sequence<beans::PropertyState> SwXStyle::getPropertyStates(const uno::Seque
{
pStates[i] = pPropSet->getPropertyState(*pEntry, *pSourceSet);
- if(SfxStyleFamily::Page == m_rEntry.m_eFamily && SID_ATTR_PAGE_SIZE == pEntry->nWID && beans::PropertyState_DIRECT_VALUE == pStates[i])
+ if(SfxStyleFamily::Page == m_rEntry.family() && SID_ATTR_PAGE_SIZE == pEntry->nWID && beans::PropertyState_DIRECT_VALUE == pStates[i])
{
const SvxSizeItem& rSize = rSet.Get(SID_ATTR_PAGE_SIZE);
sal_uInt8 nMemberId = pEntry->nMemberId & 0x7f;
@@ -2640,7 +2616,7 @@ void SAL_CALL SwXStyle::setPropertiesToDefault(const uno::Sequence<OUString>& aP
{
SolarMutexGuard aGuard;
const rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(GetStyleSheetBase())));
- SwFormat* pTargetFormat = lcl_GetFormatForStyle(m_pDoc, xStyle, m_rEntry.m_eFamily);
+ SwFormat* pTargetFormat = lcl_GetFormatForStyle(m_pDoc, xStyle, m_rEntry.family());
if(!pTargetFormat)
{
if(!m_bIsDescriptor)
@@ -2649,7 +2625,7 @@ void SAL_CALL SwXStyle::setPropertiesToDefault(const uno::Sequence<OUString>& aP
m_pPropertiesImpl->ClearProperty(rName);
return;
}
- const sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.m_nPropMapType;
+ const sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType();
const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId);
const SfxItemPropertyMap &rMap = pPropSet->getPropertyMap();
for(const auto& rName : aPropertyNames)
@@ -2696,7 +2672,7 @@ void SAL_CALL SwXStyle::setAllPropertiesToDefault()
const rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(GetStyleSheetBase())));
if(!xStyle.is())
throw uno::RuntimeException();
- if(SfxStyleFamily::Page == m_rEntry.m_eFamily)
+ if(SfxStyleFamily::Page == m_rEntry.family())
{
size_t nPgDscPos(0);
SwPageDesc* pDesc = m_pDoc->FindPageDesc(xStyle->GetPageDesc()->GetName(), &nPgDscPos);
@@ -2707,7 +2683,7 @@ void SAL_CALL SwXStyle::setAllPropertiesToDefault()
pDesc->SetUseOn(UseOnPage::All);
}
else
- pPageFormat = lcl_GetFormatForStyle(m_pDoc, xStyle, m_rEntry.m_eFamily);
+ pPageFormat = lcl_GetFormatForStyle(m_pDoc, xStyle, m_rEntry.family());
SwPageDesc& rPageDesc = m_pDoc->GetPageDesc(nPgDscPos);
rPageDesc.ResetAllMasterAttr();
@@ -2745,12 +2721,12 @@ void SAL_CALL SwXStyle::setAllPropertiesToDefault()
m_pDoc->ChgPageDesc(nPgDscPos, m_pDoc->GetPageDesc(nPgDscPos));
return;
}
- if(SfxStyleFamily::Para == m_rEntry.m_eFamily)
+ if(SfxStyleFamily::Para == m_rEntry.family())
{
if(xStyle->GetCollection())
xStyle->GetCollection()->DeleteAssignmentToListLevelOfOutlineStyle();
}
- SwFormat* const pTargetFormat = lcl_GetFormatForStyle(m_pDoc, xStyle, m_rEntry.m_eFamily);
+ SwFormat* const pTargetFormat = lcl_GetFormatForStyle(m_pDoc, xStyle, m_rEntry.family());
if(!pTargetFormat)
return;
pTargetFormat->ResetAllFormatAttr();
@@ -2768,7 +2744,7 @@ uno::Sequence<uno::Any> SAL_CALL SwXStyle::getPropertyDefaults(const uno::Sequen
if(!pBase)
throw uno::RuntimeException();
rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*static_cast<SwDocStyleSheet*>(pBase)));
- const sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.m_nPropMapType;
+ const sal_Int8 nPropSetId = m_bIsConditional ? PROPERTY_MAP_CONDITIONAL_PARA_STYLE : m_rEntry.propMapType();
const SfxItemPropertySet* pPropSet = aSwMapProvider.GetPropertySet(nPropSetId);
const SfxItemPropertyMap& rMap = pPropSet->getPropertyMap();
@@ -2813,7 +2789,7 @@ void SwXStyle::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
else if(rHint.GetId() == SfxHintId::StyleSheetChanged)
{
SfxStyleSheetBasePool& rBP = static_cast<SfxStyleSheetBasePool&>(rBC);
- SfxStyleSheetBase* pOwnBase = rBP.Find(m_sStyleName, m_rEntry.m_eFamily);
+ SfxStyleSheetBase* pOwnBase = rBP.Find(m_sStyleName, m_rEntry.family());
if(!pOwnBase)
{
SfxListener::EndListening(rBC);
@@ -3118,7 +3094,7 @@ uno::Sequence<uno::Any> SwXPageStyle::GetPropertyValues_Impl(const uno::Sequence
const uno::Any* pAny = nullptr;
m_pPropertiesImpl->GetProperty(rPropertyNames[nProp], pAny);
if (!pAny->hasValue())
- SwStyleProperties_Impl::GetProperty(rPropertyNames[nProp], m_xStyleData, aRetRange[nProp]);
+ aRetRange[nProp] = m_xStyleData->getPropertyValue(rPropertyNames[nProp]);
else
aRetRange[nProp] = *pAny;
}
@@ -3907,33 +3883,19 @@ uno::Reference< beans::XPropertySetInfo > SwXAutoStyle::getPropertySetInfo( )
{
case IStyleAccess::AUTO_STYLE_CHAR:
{
- static uno::Reference< beans::XPropertySetInfo > xCharRef;
- if(!xCharRef.is())
- {
- xCharRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE)->getPropertySetInfo();
- }
+ static const auto xCharRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE)->getPropertySetInfo();
xRet = xCharRef;
}
break;
case IStyleAccess::AUTO_STYLE_RUBY:
{
- static uno::Reference< beans::XPropertySetInfo > xRubyRef;
- if(!xRubyRef.is())
- {
- const sal_uInt16 nMapId = PROPERTY_MAP_RUBY_AUTO_STYLE;
- xRubyRef = aSwMapProvider.GetPropertySet(nMapId)->getPropertySetInfo();
- }
+ static const auto xRubyRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_RUBY_AUTO_STYLE)->getPropertySetInfo();
xRet = xRubyRef;
}
break;
case IStyleAccess::AUTO_STYLE_PARA:
{
- static uno::Reference< beans::XPropertySetInfo > xParaRef;
- if(!xParaRef.is())
- {
- const sal_uInt16 nMapId = PROPERTY_MAP_PARA_AUTO_STYLE;
- xParaRef = aSwMapProvider.GetPropertySet(nMapId)->getPropertySetInfo();
- }
+ static const auto xParaRef = aSwMapProvider.GetPropertySet(PROPERTY_MAP_PARA_AUTO_STYLE)->getPropertySetInfo();
xRet = xParaRef;
}
break;
diff --git a/sw/source/core/unocore/unotext.cxx b/sw/source/core/unocore/unotext.cxx
index 8b0f605640e6..9add198df938 100644
--- a/sw/source/core/unocore/unotext.cxx
+++ b/sw/source/core/unocore/unotext.cxx
@@ -61,6 +61,7 @@
#include <doc.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentUndoRedo.hxx>
+#include <bookmark.hxx>
#include <redline.hxx>
#include <swundo.hxx>
#include <section.hxx>
@@ -1603,6 +1604,8 @@ SwXText::convertToTextFrame(
}
bool bParaAfterInserted = false;
bool bParaBeforeInserted = false;
+ ::std::optional<SwPaM> oAnchorCheckPam;
+ oAnchorCheckPam.emplace(*pStartPam->Start(), *pEndPam->End());
if (
pStartStartNode && pEndStartNode &&
(pStartStartNode != pEndStartNode || pStartStartNode != GetStartNode())
@@ -1683,6 +1686,7 @@ SwXText::convertToTextFrame(
bParaAfterInserted = GetDoc()->getIDocumentContentOperations().AppendTextNode( aEnd );
pEndPam->DeleteMark();
*pEndPam->GetPoint() = aEnd;
+ *oAnchorCheckPam->End() = aEnd;
}
pStartPam->SetMark();
*pStartPam->End() = *pEndPam->End();
@@ -1697,10 +1701,17 @@ SwXText::convertToTextFrame(
{
const SwFrameFormat* pFrameFormat = (*m_pImpl->m_pDoc->GetSpzFrameFormats())[i];
const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
- if ( !isGraphicNode(pFrameFormat) &&
- (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId() || RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()) &&
- pStartPam->Start()->nNode.GetIndex() <= rAnchor.GetContentAnchor()->nNode.GetIndex() &&
- pStartPam->End()->nNode.GetIndex() >= rAnchor.GetContentAnchor()->nNode.GetIndex())
+ // note: Word can do at-char anchors in text frames - sometimes!
+ // see testFlyInFly for why this checks only the edges of the selection,
+ // and testFloatingTablesAnchor for why it excludes pre/post table
+ // added nodes
+ if (!isGraphicNode(pFrameFormat)
+ && ( (RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()
+ && ( oAnchorCheckPam->Start()->nNode.GetIndex() == rAnchor.GetContentAnchor()->nNode.GetIndex()
+ || oAnchorCheckPam->End()->nNode.GetIndex() == rAnchor.GetContentAnchor()->nNode.GetIndex()))
+ || (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()
+ && ( *oAnchorCheckPam->Start() == *rAnchor.GetContentAnchor()
+ || *oAnchorCheckPam->End() == *rAnchor.GetContentAnchor()))))
{
if (pFrameFormat->GetName().isEmpty())
{
@@ -1712,6 +1723,7 @@ SwXText::convertToTextFrame(
}
}
}
+ oAnchorCheckPam.reset(); // clear SwIndex before deleting nodes
const uno::Reference<text::XTextFrame> xNewFrame(
SwXTextFrame::CreateXTextFrame(*m_pImpl->m_pDoc, nullptr));
@@ -1729,7 +1741,7 @@ SwXText::convertToTextFrame(
new SwXTextRange(*pStartPam, this);
assert(rNewFrame.IsDescriptor());
rNewFrame.attachToRange(xInsertTextRange, pStartPam.get());
- rNewFrame.setName(m_pImpl->m_pDoc->GetUniqueFrameName());
+ assert(!rNewFrame.getName().isEmpty());
}
SwTextNode *const pTextNode(pStartPam->GetNode().GetTextNode());
@@ -2008,6 +2020,65 @@ void SwXText::Impl::ConvertCell(
SwNodeRange aCellRange(aStartCellPam.Start()->nNode,
aEndCellPam.End()->nNode);
rRowNodes.push_back(aCellRange); // note: invalidates pLastCell!
+
+ // tdf#149649 delete any fieldmarks overlapping the cell
+ IDocumentMarkAccess & rIDMA(*m_pDoc->getIDocumentMarkAccess());
+ while (::sw::mark::IFieldmark *const pMark = rIDMA.getFieldmarkFor(*aStartCellPam.Start()))
+ {
+ if (pMark->GetMarkEnd() <= *aEndCellPam.End())
+ {
+ if (pMark->GetMarkStart() < *aStartCellPam.Start())
+ {
+ SAL_INFO("sw.uno", "deleting fieldmark overlapping table cell");
+ rIDMA.deleteMark(pMark);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ SwPosition const sepPos(::sw::mark::FindFieldSep(*pMark));
+ if (*aStartCellPam.Start() <= sepPos && sepPos <= *aEndCellPam.End())
+ {
+ SAL_INFO("sw.uno", "deleting fieldmark with separator in table cell");
+ rIDMA.deleteMark(pMark);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ while (::sw::mark::IFieldmark *const pMark = rIDMA.getFieldmarkFor(*aEndCellPam.End()))
+ {
+ if (*aStartCellPam.Start() <= pMark->GetMarkStart())
+ {
+ if (*aEndCellPam.End() < pMark->GetMarkEnd())
+ {
+ SAL_INFO("sw.uno", "deleting fieldmark overlapping table cell");
+ rIDMA.deleteMark(pMark);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ SwPosition const sepPos(::sw::mark::FindFieldSep(*pMark));
+ if (*aStartCellPam.Start() <= sepPos && sepPos <= *aEndCellPam.End())
+ {
+ SAL_INFO("sw.uno", "deleting fieldmark with separator in table cell");
+ rIDMA.deleteMark(pMark);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
}
typedef uno::Sequence< text::TableColumnSeparator > TableColumnSeparators;
diff --git a/sw/source/core/unocore/unotextmarkup.cxx b/sw/source/core/unocore/unotextmarkup.cxx
index ae5e05181224..fb7e50596af6 100644
--- a/sw/source/core/unocore/unotextmarkup.cxx
+++ b/sw/source/core/unocore/unotextmarkup.cxx
@@ -32,8 +32,7 @@
#include <ndtxt.hxx>
#include <SwGrammarMarkUp.hxx>
#include <TextCursorHelper.hxx>
-
-#include <IGrammarContact.hxx>
+#include <GrammarContact.hxx>
#include <com/sun/star/lang/XUnoTunnel.hpp>
#include <com/sun/star/text/XTextRange.hpp>
@@ -160,7 +159,7 @@ void SAL_CALL SwXTextMarkup::commitStringMarkup(
}
else if ( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE )
{
- IGrammarContact *pGrammarContact = getGrammarContact(*m_pImpl->m_pTextNode);
+ sw::GrammarContact* pGrammarContact = sw::getGrammarContactFor(*m_pImpl->m_pTextNode);
if( pGrammarContact )
{
pWList = pGrammarContact->getGrammarCheck(*m_pImpl->m_pTextNode, true);
@@ -284,7 +283,7 @@ void SAL_CALL SwXTextMarkup::commitStringMarkup(
}
if( bRepaint )
- finishGrammarCheck(*m_pImpl->m_pTextNode);
+ sw::finishGrammarCheckFor(*m_pImpl->m_pTextNode);
}
static void lcl_commitGrammarMarkUp(
@@ -414,7 +413,7 @@ void SAL_CALL SwXTextMarkup::commitMultiTextMarkup(
// get appropriate list to use...
SwGrammarMarkUp* pWList = nullptr;
bool bRepaint = false;
- IGrammarContact *pGrammarContact = getGrammarContact(*m_pImpl->m_pTextNode);
+ sw::GrammarContact* pGrammarContact = sw::getGrammarContactFor(*m_pImpl->m_pTextNode);
if( pGrammarContact )
{
pWList = pGrammarContact->getGrammarCheck(*m_pImpl->m_pTextNode, true);
@@ -459,7 +458,7 @@ void SAL_CALL SwXTextMarkup::commitMultiTextMarkup(
}
if( bRepaint )
- finishGrammarCheck(*m_pImpl->m_pTextNode);
+ sw::finishGrammarCheckFor(*m_pImpl->m_pTextNode);
}
void SwXTextMarkup::Impl::Notify(const SfxHint& rHint)
diff --git a/sw/source/core/view/viewimp.cxx b/sw/source/core/view/viewimp.cxx
index f08c3305e5d6..07d42473aac3 100644
--- a/sw/source/core/view/viewimp.cxx
+++ b/sw/source/core/view/viewimp.cxx
@@ -36,6 +36,7 @@
#include <IDocumentDrawModelAccess.hxx>
#include <drawdoc.hxx>
#include <prevwpage.hxx>
+#include <sfx2/viewsh.hxx>
void SwViewShellImp::Init( const SwViewOption *pNewOpt )
{
@@ -161,8 +162,10 @@ bool SwViewShellImp::AddPaintRect( const SwRect &rRect )
void SwViewShellImp::AddPendingLOKInvalidation( const SwRect& rRect )
{
- // These are often repeated, so check first for duplicates.
std::vector<SwRect>& l = m_pendingLOKInvalidations;
+ if(l.empty() && m_pShell && m_pShell->GetSfxViewShell()) // Announce that these invalidations will need flushing.
+ m_pShell->GetSfxViewShell()->libreOfficeKitViewAddPendingInvalidateTiles();
+ // These are often repeated, so check first for duplicates.
if( std::find( l.begin(), l.end(), rRect ) == l.end())
l.push_back( rRect );
}
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index b16b2d042727..30218dceead1 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -468,7 +468,7 @@ void SwViewShell::ImplStartAction()
void SwViewShell::ImplLockPaint()
{
- if ( GetWin() && GetWin()->IsVisible() )
+ if ( GetWin() && GetWin()->IsVisible() && !comphelper::LibreOfficeKit::isActive())
GetWin()->EnablePaint( false ); //Also cut off the controls.
Imp()->LockPaint();
}
diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx
index f3d9a22c5140..44833c00e6a7 100644
--- a/sw/source/filter/html/css1atr.cxx
+++ b/sw/source/filter/html/css1atr.cxx
@@ -94,6 +94,7 @@
#include <o3tl/unit_conversion.hxx>
#include <rtl/strbuf.hxx>
+#include <rtl/xmlencode.hxx>
#include <osl/diagnose.h>
using namespace css;
@@ -1075,7 +1076,7 @@ void SwHTMLWriter::PrepareFontList( const SvxFontItem& rFontItem,
while( nStrPos != -1 )
{
OUString aName = rName.getToken( 0, ';', nStrPos );
- aName = comphelper::string::strip(aName, ' ');
+ aName = rtl::encodeForXml(comphelper::string::strip(aName, ' '));
if( aName.isEmpty() )
continue;
diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx
index 51f059d5a2cc..9b6c5b5d8155 100644
--- a/sw/source/filter/html/htmlatr.cxx
+++ b/sw/source/filter/html/htmlatr.cxx
@@ -770,6 +770,7 @@ static void OutHTML_SwFormat( Writer& rWrt, const SwFormat& rFormat,
if( rInfo.bInNumberBulletList && bNumberedForListItem )
{
HtmlWriter html(rWrt.Strm(), rHWrt.maNamespace);
+ html.prettyPrint(rHWrt.m_bPrettyPrint);
html.start(OOO_STRING_SVTOOLS_HTML_li);
if( USHRT_MAX != nNumStart )
html.attribute(OOO_STRING_SVTOOLS_HTML_O_value, OString::number(nNumStart));
@@ -1000,7 +1001,7 @@ static void OutHTML_SwFormatOff( Writer& rWrt, const SwHTMLTextCollOutputInfo& r
if( rInfo.ShouldOutputToken() )
{
- if( rHWrt.m_bLFPossible )
+ if( rHWrt.m_bPrettyPrint && rHWrt.m_bLFPossible )
rHWrt.OutNewLine( true );
// if necessary, for BLOCKQUOTE, ADDRESS and DD another paragraph token
@@ -2039,6 +2040,7 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode )
rHTMLWrt.m_bLFPossible = true;
HtmlWriter aHtml(rWrt.Strm(), rHTMLWrt.maNamespace);
+ aHtml.prettyPrint(rHTMLWrt.m_bPrettyPrint);
aHtml.start(OOO_STRING_SVTOOLS_HTML_horzrule);
const SfxItemSet* pItemSet = pNd->GetpSwAttrSet();
@@ -2231,8 +2233,8 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode )
// now it's a good opportunity again for an LF - if it is still allowed
// FIXME: for LOK case we set rHTMLWrt.m_nWishLineLen as -1, for now keep old flow
// when LOK side will be fixed - don't insert new line at the beginning
- if( rHTMLWrt.m_bLFPossible &&
- rHTMLWrt.GetLineLen() >= (rHTMLWrt.m_nWishLineLen >= 0 ? rHTMLWrt.m_nWishLineLen : 70 ) )
+ if( rHTMLWrt.m_bLFPossible && rHTMLWrt.m_bPrettyPrint && rHTMLWrt.m_nWishLineLen >= 0 &&
+ rHTMLWrt.GetLineLen() >= rHTMLWrt.m_nWishLineLen )
{
rHTMLWrt.OutNewLine();
}
@@ -2472,7 +2474,7 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode )
nWordLen = nEnd;
nWordLen -= nStrPos;
- if( rHTMLWrt.m_nWishLineLen >= 0 &&
+ if( rHTMLWrt.m_bPrettyPrint && rHTMLWrt.m_nWishLineLen >= 0 &&
(nLineLen >= rHTMLWrt.m_nWishLineLen ||
(nLineLen+nWordLen) >= rHTMLWrt.m_nWishLineLen ) )
{
@@ -2488,6 +2490,7 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode )
{
HTMLOutFuncs::FlushToAscii( rWrt.Strm(), aContext );
HtmlWriter aHtml(rWrt.Strm(), rHTMLWrt.maNamespace);
+ aHtml.prettyPrint(rHTMLWrt.m_bPrettyPrint);
aHtml.single(OOO_STRING_SVTOOLS_HTML_linebreak);
}
else if (c == CH_TXT_ATR_FORMELEMENT)
@@ -2541,6 +2544,7 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode )
else
{
HtmlWriter aHtml(rHTMLWrt.Strm(), rHTMLWrt.maNamespace);
+ aHtml.prettyPrint(rHTMLWrt.m_bPrettyPrint);
aHtml.single(OOO_STRING_SVTOOLS_HTML_linebreak);
const SvxULSpaceItem& rULSpace = pNd->GetSwAttrSet().Get(RES_UL_SPACE);
if (rULSpace.GetLower() > 0 && !bEndOfCell)
@@ -2567,6 +2571,7 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode )
}
HtmlWriter aHtml(rHTMLWrt.Strm(), rHTMLWrt.maNamespace);
+ aHtml.prettyPrint(rHTMLWrt.m_bPrettyPrint);
aHtml.start(OOO_STRING_SVTOOLS_HTML_linebreak);
aHtml.attribute(OOO_STRING_SVTOOLS_HTML_O_clear, pString);
aHtml.end();
diff --git a/sw/source/filter/html/htmlfldw.cxx b/sw/source/filter/html/htmlfldw.cxx
index dbe4fe8d9092..fa069112a13d 100644
--- a/sw/source/filter/html/htmlfldw.cxx
+++ b/sw/source/filter/html/htmlfldw.cxx
@@ -21,6 +21,7 @@
#include <comphelper/string.hxx>
#include <svtools/htmlkywd.hxx>
#include <svtools/htmlout.hxx>
+#include <rtl/xmlencode.hxx>
#include <osl/diagnose.h>
#include <fmtfld.hxx>
#include <doc.hxx>
@@ -510,7 +511,7 @@ Writer& OutHTML_SwFormatField( Writer& rWrt, const SfxPoolItem& rHt )
OString sOut =
"<" OOO_STRING_SVTOOLS_HTML_comment
" " +
- OUStringToOString(sComment, static_cast<SwHTMLWriter&>(rWrt).m_eDestEnc) +
+ OUStringToOString(rtl::encodeForXml(sComment), static_cast<SwHTMLWriter&>(rWrt).m_eDestEnc) +
" -->";
rWrt.Strm().WriteOString( sOut );
}
diff --git a/sw/source/filter/html/htmlnumwriter.cxx b/sw/source/filter/html/htmlnumwriter.cxx
index f41ac73929f9..0144e2d0315b 100644
--- a/sw/source/filter/html/htmlnumwriter.cxx
+++ b/sw/source/filter/html/htmlnumwriter.cxx
@@ -324,7 +324,7 @@ Writer& OutHTML_NumberBulletListEnd( SwHTMLWriter& rWrt,
bool bListEnd = !bSameRule || rNextInfo.GetDepth() < rInfo.GetDepth() || rNextInfo.IsRestart();
std::optional<bool> oAtLeastOneNumbered;
- if (rWrt.mbXHTML && !rInfo.IsNumbered())
+ if (!rInfo.IsNumbered())
{
oAtLeastOneNumbered = false;
SwNodeOffset nPos = rWrt.m_pCurrentPam->GetPoint()->nNode.GetIndex() - 1;
@@ -354,18 +354,15 @@ Writer& OutHTML_NumberBulletListEnd( SwHTMLWriter& rWrt,
}
}
- if (rWrt.mbXHTML)
+ // The list is numbered if the previous text node is numbered or any other previous text
+ // node is numbered.
+ bool bPrevIsNumbered = rInfo.IsNumbered() || *oAtLeastOneNumbered;
+ // XHTML </li> for the list item content, if there is an open <li>.
+ if ((bListEnd && bPrevIsNumbered) || (!bListEnd && rNextInfo.IsNumbered()))
{
- // The list is numbered if the previous text node is numbered or any other previous text
- // node is numbered.
- bool bPrevIsNumbered = rInfo.IsNumbered() || *oAtLeastOneNumbered;
- // XHTML </li> for the list item content, if there is an open <li>.
- if ((bListEnd && bPrevIsNumbered) || (!bListEnd && rNextInfo.IsNumbered()))
- {
- HTMLOutFuncs::Out_AsciiTag(
- rWrt.Strm(), OStringConcatenation(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_li),
- false);
- }
+ HTMLOutFuncs::Out_AsciiTag(
+ rWrt.Strm(), OStringConcatenation(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_li),
+ false);
}
if (!bListEnd)
diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx
index fdd7bd675954..ab2f04a43471 100644
--- a/sw/source/filter/html/htmlplug.cxx
+++ b/sw/source/filter/html/htmlplug.cxx
@@ -444,6 +444,9 @@ bool SwHTMLParser::InsertEmbed()
u"image/svg+xml",
u"image/tiff",
u"image/x-emf",
+ u"image/bmp",
+ u"image/tif",
+ u"image/wmf",
};
if (vAllowlist.find(aType) != vAllowlist.end() && m_aEmbeds.empty())
@@ -1100,7 +1103,12 @@ void SwHTMLParser::InsertFloatingFrame()
bool bHasBorder = aFrameDesc.HasFrameBorder();
Size aMargin = aFrameDesc.GetMargin();
- xSet->setPropertyValue("FrameURL", uno::makeAny( aFrameDesc.GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
+ OUString sHRef = aFrameDesc.GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ if (INetURLObject(sHRef).IsExoticProtocol())
+ NotifyMacroEventRead();
+
+ xSet->setPropertyValue("FrameURL", uno::makeAny( sHRef ) );
xSet->setPropertyValue("FrameName", uno::makeAny( aName ) );
if ( eScroll == ScrollingMode::Auto )
diff --git a/sw/source/filter/html/parcss1.cxx b/sw/source/filter/html/parcss1.cxx
index e0b20ef4168e..518604bc1bc5 100644
--- a/sw/source/filter/html/parcss1.cxx
+++ b/sw/source/filter/html/parcss1.cxx
@@ -529,11 +529,11 @@ CSS1Token CSS1Parser::GetNextToken()
bool bEOFSave = m_bEOF;
// first try to parse a hex digit
- OUStringBuffer sTmpBuffer(6);
+ OUStringBuffer sTmpBuffer(8);
do {
sTmpBuffer.append( m_cNextCh );
m_cNextCh = GetNextChar();
- } while( sTmpBuffer.getLength() < 7 &&
+ } while( sTmpBuffer.getLength() < 9 &&
( ('0'<=m_cNextCh && '9'>=m_cNextCh) ||
('A'<=m_cNextCh && 'F'>=m_cNextCh) ||
('a'<=m_cNextCh && 'f'>=m_cNextCh) ) &&
@@ -541,7 +541,7 @@ CSS1Token CSS1Parser::GetNextToken()
if( sTmpBuffer.getLength()==6 || sTmpBuffer.getLength()==3 )
{
- // we found a color in hex
+ // we found a color in hex (RGB)
m_aToken += sTmpBuffer;
nRet = CSS1_HEXCOLOR;
bNextCh = false;
@@ -549,6 +549,26 @@ CSS1Token CSS1Parser::GetNextToken()
break;
}
+ if( sTmpBuffer.getLength()==8 )
+ {
+ // we found a color in hex (RGBA)
+ // we convert it to RGB assuming white background
+ sal_uInt32 nColor = sTmpBuffer.makeStringAndClear().toUInt32(16);
+ sal_uInt32 nRed = (nColor & 0xff000000) >> 24;
+ sal_uInt32 nGreen = (nColor & 0xff0000) >> 16;
+ sal_uInt32 nBlue = (nColor & 0xff00) >> 8;
+ double nAlpha = (nColor & 0xff) / 255.0;
+ nRed = (1 - nAlpha) * 255 + nAlpha * nRed;
+ nGreen = (1 - nAlpha) * 255 + nAlpha * nGreen;
+ nBlue = (1 - nAlpha) * 255 + nAlpha * nBlue;
+ nColor = (nRed << 16) + (nGreen << 8) + nBlue;
+ m_aToken += OUString::number(nColor, 16);
+ nRet = CSS1_HEXCOLOR;
+ bNextCh = false;
+
+ break;
+ }
+
// otherwise we try a number
m_nInPos = nInPosSave;
m_cNextCh = cNextChSave;
diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx
index 0d6aa170c0ad..605dc7dd2f64 100644
--- a/sw/source/filter/html/wrthtml.cxx
+++ b/sw/source/filter/html/wrthtml.cxx
@@ -152,6 +152,7 @@ SwHTMLWriter::SwHTMLWriter( const OUString& rBaseURL, const OUString& rFilterOpt
, mbEmbedImages(false)
, m_bCfgPrintLayout( false )
, m_bParaDotLeaders( false )
+ , m_bPrettyPrint( true )
{
SetBaseURL(rBaseURL);
@@ -232,9 +233,10 @@ void SwHTMLWriter::SetupFilterOptions(const OUString& rFilterOptions)
}
// this option can be "on" together with any of above
- if (rFilterOptions.indexOf("NoLineLimit") >= 0)
+ if (rFilterOptions.indexOf("NoPrettyPrint") >= 0)
{
m_nWishLineLen = -1;
+ m_bPrettyPrint = false;
}
const uno::Sequence<OUString> aOptionSeq = comphelper::string::convertCommaSeparated(rFilterOptions);
@@ -1271,7 +1273,8 @@ OUString SwHTMLWriter::convertHyperlinkHRefValue(const OUString& rURL)
{
// Link is not started from "#", so looks like external link. Encode this URL.
INetURLObject aURL(sURL);
- sURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ if (!aURL.HasError())
+ sURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
}
return URIHelper::simpleNormalizedMakeRelative( GetBaseURL(), sURL );
}
diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx
index 22a386bcee7c..53f3b6b5846b 100644
--- a/sw/source/filter/html/wrthtml.hxx
+++ b/sw/source/filter/html/wrthtml.hxx
@@ -416,7 +416,8 @@ public:
#define sCSS2_P_CLASS_leaders "leaders"
bool m_bCfgPrintLayout : 1; // PrintLayout option for TOC dot leaders
bool m_bParaDotLeaders : 1; // for TOC dot leaders
- // 25
+ bool m_bPrettyPrint : 1; // Allows to add new lines to make it more readable
+ // 26
/// Tracks which text portion attributes are currently open: a which id -> open count map.
std::map<sal_uInt16, int> maStartedAttributes;
diff --git a/sw/source/filter/inc/wwstyles.hxx b/sw/source/filter/inc/wwstyles.hxx
index 32dce11e3692..7a253d87c508 100644
--- a/sw/source/filter/inc/wwstyles.hxx
+++ b/sw/source/filter/inc/wwstyles.hxx
@@ -24,6 +24,7 @@
namespace ww
{
+ // When changing, make sure to update GetStiNames in sw/source/filter/ww8/styles.cxx accordingly
enum sti : sal_uInt16
{
stiNormal = 0, // 0x0000
diff --git a/sw/source/filter/ww8/WW8TableInfo.cxx b/sw/source/filter/ww8/WW8TableInfo.cxx
index 907e4131cec0..314a03bf14c2 100644
--- a/sw/source/filter/ww8/WW8TableInfo.cxx
+++ b/sw/source/filter/ww8/WW8TableInfo.cxx
@@ -1278,7 +1278,9 @@ std::string WW8TableCellGrid::toString()
static char sBuffer[1024];
while (aTopsIt != getRowTopsEnd())
{
+ SAL_WNODEPRECATED_DECLARATIONS_PUSH // sprintf (macOS 13 SDK)
sprintf(sBuffer, "<row y=\"%" SAL_PRIdINT64 "\">", sal_Int64(*aTopsIt));
+ SAL_WNODEPRECATED_DECLARATIONS_POP
sResult += sBuffer;
CellInfoMultiSet::const_iterator aCellIt = getCellsBegin(*aTopsIt);
diff --git a/sw/source/filter/ww8/attributeoutputbase.hxx b/sw/source/filter/ww8/attributeoutputbase.hxx
index a9331c9b628b..3a07acbde185 100644
--- a/sw/source/filter/ww8/attributeoutputbase.hxx
+++ b/sw/source/filter/ww8/attributeoutputbase.hxx
@@ -172,7 +172,7 @@ public:
virtual void StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, bool bSingleEmptyRun = false ) = 0;
/// End of the text run.
- virtual void EndRun( const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun = false ) = 0;
+ virtual void EndRun( const SwTextNode* pNode, sal_Int32 nPos, sal_Int32 nLen, bool bLastRun = false ) = 0;
/// Called before we start outputting the attributes.
virtual void StartRunProperties() = 0;
@@ -190,7 +190,7 @@ public:
virtual void WritePostitFieldReference() {};
/// Output text (inside a run).
- virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8 ) = 0;
+ virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8, const OUString& rSymbolFont = OUString() ) = 0;
/// Output text (without markup).
virtual void RawText(const OUString& rText, rtl_TextEncoding eCharSet) = 0;
@@ -274,7 +274,7 @@ public:
/// Start of a style in the styles table.
virtual void StartStyle( const OUString& rName, StyleType eType,
- sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 nLink, sal_uInt16 nWwId, sal_uInt16 nId,
+ sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 nLink, sal_uInt16 nWwId, sal_uInt16 nSlot,
bool bAutoUpdate ) = 0;
/// End of a style in the styles table.
@@ -369,12 +369,6 @@ public:
const OUString &rNumberingString,
const SvxBrushItem* pBrush) = 0; // #i120928 export graphic of bullet
- /// Output content control start.
- virtual void StartContentControl(const SwFormatContentControl& /*rFormatContentControl*/) {}
-
- /// Output content control end.
- virtual void EndContentControl() {}
-
protected:
static void GetNumberPara( OUString& rStr, const SwField& rField );
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index e74ea397c40a..2d6ed05c3247 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -137,6 +137,7 @@
#include <frmatr.hxx>
#include <txtatr.hxx>
#include <frameformats.hxx>
+#include <textcontentcontrol.hxx>
#include <o3tl/string_view.hxx>
#include <o3tl/unit_conversion.hxx>
@@ -363,16 +364,6 @@ void DocxAttributeOutput::WriteFloatingTable(ww8::Frame const* pParentFrame)
m_rExport.SetFloatingTableFrame(nullptr);
}
-void DocxAttributeOutput::StartContentControl(const SwFormatContentControl& rFormatContentControl)
-{
- m_pContentControl = rFormatContentControl.GetContentControl();
-}
-
-void DocxAttributeOutput::EndContentControl()
-{
- ++m_nCloseContentControlInThisRun;
-}
-
static void checkAndWriteFloatingTables(DocxAttributeOutput& rDocxAttributeOutput)
{
const auto& rExport = rDocxAttributeOutput.GetExport();
@@ -624,16 +615,24 @@ void SdtBlockHelper::DeleteAndResetTheLists()
m_pTextAttrs.clear();
if (!m_aAlias.isEmpty())
m_aAlias.clear();
+ if (!m_aTag.isEmpty())
+ m_aTag.clear();
+ if (!m_aLock.isEmpty())
+ m_aLock.clear();
if (!m_aPlaceHolderDocPart.isEmpty())
m_aPlaceHolderDocPart.clear();
if (!m_aColor.isEmpty())
m_aColor.clear();
- m_bHasId = false;
+ if (!m_aAppearance.isEmpty())
+ m_aAppearance.clear();
+ m_bShowingPlaceHolder = false;
+ m_nId = 0;
+ m_nTabIndex = 0;
}
void SdtBlockHelper::WriteSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer, bool bRunTextIsOn, bool bParagraphHasDrawing)
{
- if (m_nSdtPrToken <= 0 && !m_pDataBindingAttrs.is() && !m_bHasId)
+ if (m_nSdtPrToken <= 0 && !m_pDataBindingAttrs.is() && !m_nId)
return;
// sdt start mark
@@ -688,19 +687,15 @@ void SdtBlockHelper::WriteSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer, b
// clear sdt status
m_nSdtPrToken = 0;
- m_pTokenChildren.clear();
- m_pDataBindingAttrs.clear();
- m_pTextAttrs.clear();
- m_aAlias.clear();
- m_bHasId = false;
+ DeleteAndResetTheLists();
}
void SdtBlockHelper::WriteExtraParams(::sax_fastparser::FSHelperPtr& pSerializer)
{
- if (m_nSdtPrToken == FSNS(XML_w, XML_id) || m_bHasId)
- //Word won't open a document with an empty id tag, we fill it with a random number
- pSerializer->singleElementNS(XML_w, XML_id, FSNS(XML_w, XML_val),
- OString::number(comphelper::rng::uniform_int_distribution(0, std::numeric_limits<int>::max())));
+ if (m_nId)
+ {
+ pSerializer->singleElementNS(XML_w, XML_id, FSNS(XML_w, XML_val), OString::number(m_nId));
+ }
if (m_pDataBindingAttrs.is())
{
@@ -720,13 +715,32 @@ void SdtBlockHelper::WriteExtraParams(::sax_fastparser::FSHelperPtr& pSerializer
pSerializer->singleElementNS(XML_w, XML_docPart, FSNS(XML_w, XML_val), m_aPlaceHolderDocPart);
pSerializer->endElementNS(XML_w, XML_placeholder);
}
+
+ if (m_bShowingPlaceHolder)
+ pSerializer->singleElementNS(XML_w, XML_showingPlcHdr);
+
if (!m_aColor.isEmpty())
{
pSerializer->singleElementNS(XML_w15, XML_color, FSNS(XML_w, XML_val), m_aColor);
}
+ if (!m_aAppearance.isEmpty())
+ {
+ pSerializer->singleElementNS(XML_w15, XML_appearance, FSNS(XML_w15, XML_val), m_aAppearance);
+ }
+
if (!m_aAlias.isEmpty())
pSerializer->singleElementNS(XML_w, XML_alias, FSNS(XML_w, XML_val), m_aAlias);
+
+ if (!m_aTag.isEmpty())
+ pSerializer->singleElementNS(XML_w, XML_tag, FSNS(XML_w, XML_val), m_aTag);
+
+ if (m_nTabIndex)
+ pSerializer->singleElementNS(XML_w, XML_tabIndex, FSNS(XML_w, XML_val),
+ OString::number(m_nTabIndex));
+
+ if (!m_aLock.isEmpty())
+ pSerializer->singleElementNS(XML_w, XML_lock, FSNS(XML_w, XML_val), m_aLock);
}
void SdtBlockHelper::EndSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer)
@@ -826,13 +840,41 @@ void SdtBlockHelper::GetSdtParamsFromGrabBag(const uno::Sequence<beans::Property
m_aColor = sValue;
}
}
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_appearance")
+ {
+ if (!(aPropertyValue.Value >>= m_aAppearance))
+ SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt appearance value");
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_showingPlcHdr")
+ {
+ if (!(aPropertyValue.Value >>= m_bShowingPlaceHolder))
+ SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt ShowingPlcHdr");
+ }
else if (aPropertyValue.Name == "ooxml:CT_SdtPr_alias" && m_aAlias.isEmpty())
{
if (!(aPropertyValue.Value >>= m_aAlias))
SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt alias value");
}
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_tag" && m_aTag.isEmpty())
+ {
+ if (!(aPropertyValue.Value >>= m_aTag))
+ SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt tag value");
+ }
else if (aPropertyValue.Name == "ooxml:CT_SdtPr_id")
- m_bHasId = true;
+ {
+ if (!(aPropertyValue.Value >>= m_nId))
+ SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt id value");
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_tabIndex" && !m_nTabIndex)
+ {
+ if (!(aPropertyValue.Value >>= m_nTabIndex))
+ SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt tabIndex value");
+ }
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_lock" && m_aLock.isEmpty())
+ {
+ if (!(aPropertyValue.Value >>= m_aLock))
+ SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt lock value");
+ }
else if (aPropertyValue.Name == "ooxml:CT_SdtPr_citation")
m_nSdtPrToken = FSNS(XML_w, XML_citation);
else if (aPropertyValue.Name == "ooxml:CT_SdtPr_docPartObj" ||
@@ -1094,7 +1136,6 @@ void DocxAttributeOutput::EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t pT
//These should be written out to the actual Node and not to the anchor.
//Clear them as they will be repopulated when the node is processed.
m_aParagraphSdt.m_nSdtPrToken = 0;
- m_aParagraphSdt.m_bHasId = false;
m_aParagraphSdt.DeleteAndResetTheLists();
}
@@ -1466,13 +1507,13 @@ void DocxAttributeOutput::EndParagraphProperties(const SfxItemSet& rParagraphMar
if ( pRedlineParagraphMarkerDeleted )
{
- StartRedline( pRedlineParagraphMarkerDeleted );
- EndRedline( pRedlineParagraphMarkerDeleted );
+ StartRedline( pRedlineParagraphMarkerDeleted, /*bLastRun=*/true );
+ EndRedline( pRedlineParagraphMarkerDeleted, /*bLastRun=*/true );
}
if ( pRedlineParagraphMarkerInserted )
{
- StartRedline( pRedlineParagraphMarkerInserted );
- EndRedline( pRedlineParagraphMarkerInserted );
+ StartRedline( pRedlineParagraphMarkerInserted, /*bLastRun=*/true );
+ EndRedline( pRedlineParagraphMarkerInserted, /*bLastRun=*/true );
}
// mergeTopMarks() after paragraph mark properties child elements.
@@ -1510,7 +1551,8 @@ void DocxAttributeOutput::EndParagraphProperties(const SfxItemSet& rParagraphMar
m_pSerializer->endElementNS(XML_w, XML_smartTag);
}
- if ( m_nColBreakStatus == COLBRK_WRITE || m_nColBreakStatus == COLBRK_WRITEANDPOSTPONE )
+ if ((m_nColBreakStatus == COLBRK_WRITE || m_nColBreakStatus == COLBRK_WRITEANDPOSTPONE)
+ && !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen())
{
m_pSerializer->startElementNS(XML_w, XML_r);
m_pSerializer->singleElementNS(XML_w, XML_br, FSNS(XML_w, XML_type), "column");
@@ -1522,7 +1564,8 @@ void DocxAttributeOutput::EndParagraphProperties(const SfxItemSet& rParagraphMar
m_nColBreakStatus = COLBRK_NONE;
}
- if ( m_bPostponedPageBreak && !m_bWritingHeaderFooter )
+ if (m_bPostponedPageBreak && !m_bWritingHeaderFooter
+ && !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen())
{
m_pSerializer->startElementNS(XML_w, XML_r);
m_pSerializer->singleElementNS(XML_w, XML_br, FSNS(XML_w, XML_type), "page");
@@ -1575,7 +1618,7 @@ void DocxAttributeOutput::StartRun( const SwRedlineData* pRedlineData, sal_Int32
m_pSerializer->mark(Tag_StartRun_3); // let's call it "postponed text"
}
-void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /*bLastRun*/)
+void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_Int32 nLen, bool bLastRun)
{
int nFieldsInPrevHyperlink = m_nFieldsInHyperlink;
// Reset m_nFieldsInHyperlink if a new hyperlink is about to start
@@ -1632,12 +1675,6 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
m_bEndCharSdt = false;
}
- for (; m_nCloseContentControlInPreviousRun > 0; --m_nCloseContentControlInPreviousRun)
- {
- // Not the last run of this paragraph.
- WriteContentControlEnd();
- }
-
if ( m_closeHyperlinkInPreviousRun )
{
if ( m_startedHyperlink )
@@ -1665,9 +1702,9 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
// InputField with extra grabbag params - it is sdt field
(pIt->eType == ww::eFILLIN && static_cast<const SwInputField*>(pIt->pField.get())->getGrabBagParams().hasElements())))
{
- StartRedline( m_pRedlineData );
+ StartRedline( m_pRedlineData, bLastRun );
StartField_Impl( pNode, nPos, *pIt, true );
- EndRedline( m_pRedlineData );
+ EndRedline( m_pRedlineData, bLastRun );
if (m_startedHyperlink)
++m_nFieldsInHyperlink;
@@ -1735,10 +1772,8 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
m_nHyperLinkCount++;
}
- WriteContentControlStart();
-
// if there is some redlining in the document, output it
- StartRedline( m_pRedlineData );
+ StartRedline( m_pRedlineData, bLastRun );
// XML_r node should be surrounded with bookmark-begin and bookmark-end nodes if it has bookmarks.
// The same is applied for permission ranges.
@@ -1782,6 +1817,17 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
DoWriteBookmarkStartIfExist(nPos);
+ if (nLen != -1)
+ {
+ SwTextAttr* pAttr = pNode->GetTextAttrAt(nPos, RES_TXTATR_CONTENTCONTROL, SwTextNode::DEFAULT);
+ if (pAttr && pAttr->GetStart() == nPos)
+ {
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ m_pContentControl = pTextContentControl->GetContentControl().GetContentControl();
+ WriteContentControlStart();
+ }
+ }
+
m_pSerializer->startElementNS(XML_w, XML_r);
if(GetExport().m_bTabInTOC && m_pHyperlinkAttrList.is())
{
@@ -1800,9 +1846,19 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
// append the actual run end
m_pSerializer->endElementNS( XML_w, XML_r );
+ if (nLen != -1)
+ {
+ sal_Int32 nEnd = nPos + nLen;
+ SwTextAttr* pAttr = pNode->GetTextAttrAt(nPos, RES_TXTATR_CONTENTCONTROL, SwTextNode::DEFAULT);
+ if (pAttr && *pAttr->GetEnd() == nEnd)
+ {
+ WriteContentControlEnd();
+ }
+ }
+
// if there is some redlining in the document, output it
// (except in the case of fields with multiple runs)
- EndRedline( m_pRedlineData );
+ EndRedline( m_pRedlineData, bLastRun );
// enclose in a sdt block, if necessary: if one is already started, then don't do it for now
// (so on export sdt blocks are never nested ATM)
@@ -1847,12 +1903,6 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
m_pRedlineData = nullptr;
}
- for (; m_nCloseContentControlInThisRun > 0; --m_nCloseContentControlInThisRun)
- {
- // Last run of this paragraph.
- WriteContentControlEnd();
- }
-
if ( m_closeHyperlinkInThisRun )
{
if ( m_startedHyperlink )
@@ -1912,7 +1962,7 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool /
if ( m_pRedlineData )
{
- EndRedline( m_pRedlineData );
+ EndRedline( m_pRedlineData, bLastRun );
m_pRedlineData = nullptr;
}
@@ -2218,11 +2268,9 @@ void DocxAttributeOutput::WriteFFData( const FieldInfos& rInfos )
}
else if ( rInfos.eType == ww::eFORMCHECKBOX )
{
- OUString sName;
+ const OUString sName = params.getName();
bool bChecked = false;
- params.extractParam( ODF_FORMCHECKBOX_NAME, sName );
-
const sw::mark::ICheckboxFieldmark* pCheckboxFm = dynamic_cast<const sw::mark::ICheckboxFieldmark*>(&rFieldmark);
if ( pCheckboxFm && pCheckboxFm->IsChecked() )
bChecked = true;
@@ -2336,6 +2384,11 @@ void DocxAttributeOutput::WriteContentControlStart()
return;
}
+ if (m_bAnchorLinkedToNode)
+ {
+ return;
+ }
+
m_pSerializer->startElementNS(XML_w, XML_sdt);
m_pSerializer->startElementNS(XML_w, XML_sdtPr);
if (!m_pContentControl->GetPlaceholderDocPart().isEmpty())
@@ -2360,6 +2413,44 @@ void DocxAttributeOutput::WriteContentControlStart()
m_pContentControl->GetColor());
}
+ if (!m_pContentControl->GetAppearance().isEmpty())
+ {
+ m_pSerializer->singleElementNS(XML_w15, XML_appearance, FSNS(XML_w15, XML_val),
+ m_pContentControl->GetAppearance());
+ }
+
+ if (!m_pContentControl->GetAlias().isEmpty())
+ {
+ m_pSerializer->singleElementNS(XML_w, XML_alias, FSNS(XML_w, XML_val),
+ m_pContentControl->GetAlias());
+ }
+
+ if (!m_pContentControl->GetTag().isEmpty())
+ {
+ m_pSerializer->singleElementNS(XML_w, XML_tag, FSNS(XML_w, XML_val),
+ m_pContentControl->GetTag());
+ }
+
+ if (m_pContentControl->GetId())
+ {
+ m_pSerializer->singleElementNS(XML_w, XML_id, FSNS(XML_w, XML_val),
+ OString::number(m_pContentControl->GetId()));
+ }
+
+ if (m_pContentControl->GetTabIndex())
+ {
+ // write the unsigned value as as if it were signed since that is all we can import
+ const sal_Int32 nTabIndex = static_cast<sal_Int32>(m_pContentControl->GetTabIndex());
+ m_pSerializer->singleElementNS(XML_w, XML_tabIndex, FSNS(XML_w, XML_val),
+ OString::number(nTabIndex));
+ }
+
+ if (!m_pContentControl->GetLock().isEmpty())
+ {
+ m_pSerializer->singleElementNS(XML_w, XML_lock, FSNS(XML_w, XML_val),
+ m_pContentControl->GetLock());
+ }
+
if (m_pContentControl->GetShowingPlaceHolder())
{
m_pSerializer->singleElementNS(XML_w, XML_showingPlcHdr);
@@ -2390,16 +2481,35 @@ void DocxAttributeOutput::WriteContentControlStart()
m_pSerializer->endElementNS(XML_w14, XML_checkbox);
}
- if (m_pContentControl->HasListItems())
+ if (m_pContentControl->GetComboBox() || m_pContentControl->GetDropDown())
{
- m_pSerializer->startElementNS(XML_w, XML_dropDownList);
+ if (m_pContentControl->GetComboBox())
+ {
+ m_pSerializer->startElementNS(XML_w, XML_comboBox);
+ }
+ else
+ {
+ m_pSerializer->startElementNS(XML_w, XML_dropDownList);
+ }
for (const auto& rItem : m_pContentControl->GetListItems())
{
- m_pSerializer->singleElementNS(XML_w, XML_listItem,
- FSNS(XML_w, XML_displayText), rItem.m_aDisplayText,
- FSNS(XML_w, XML_value), rItem.m_aValue);
+ rtl::Reference<FastAttributeList> xAttributes = FastSerializerHelper::createAttrList();
+ if (!rItem.m_aDisplayText.isEmpty())
+ {
+ // If there is no display text, need to omit the attribute, not write an empty one.
+ xAttributes->add(FSNS(XML_w, XML_displayText), rItem.m_aDisplayText);
+ }
+ xAttributes->add(FSNS(XML_w, XML_value), rItem.m_aValue);
+ m_pSerializer->singleElementNS(XML_w, XML_listItem, xAttributes);
+ }
+ if (m_pContentControl->GetComboBox())
+ {
+ m_pSerializer->endElementNS(XML_w, XML_comboBox);
+ }
+ else
+ {
+ m_pSerializer->endElementNS(XML_w, XML_dropDownList);
}
- m_pSerializer->endElementNS(XML_w, XML_dropDownList);
}
if (m_pContentControl->GetDate())
@@ -2428,8 +2538,33 @@ void DocxAttributeOutput::WriteContentControlStart()
m_pSerializer->endElementNS(XML_w, XML_date);
}
+ if (m_pContentControl->GetPlainText())
+ {
+ m_pSerializer->singleElementNS(XML_w, XML_text);
+ }
+
m_pSerializer->endElementNS(XML_w, XML_sdtPr);
m_pSerializer->startElementNS(XML_w, XML_sdtContent);
+
+ const OUString& rPrefixMapping = m_pContentControl->GetDataBindingPrefixMappings();
+ const OUString& rXpath = m_pContentControl->GetDataBindingXpath();
+ if (!rXpath.isEmpty())
+ {
+ // This content control has a data binding, update the data source.
+ SwTextContentControl* pTextAttr = m_pContentControl->GetTextAttr();
+ SwTextNode* pTextNode = m_pContentControl->GetTextNode();
+ SwPosition aPoint(*pTextNode, pTextAttr->GetStart());
+ SwPosition aMark(*pTextNode, *pTextAttr->GetEnd());
+ SwPaM aPam(aMark, aPoint);
+ OUString aSnippet = aPam.GetText();
+ static sal_Unicode const aForbidden[] = {
+ CH_TXTATR_BREAKWORD,
+ 0
+ };
+ aSnippet = comphelper::string::removeAny(aSnippet, aForbidden);
+ m_rExport.AddSdtData(rPrefixMapping, rXpath, aSnippet);
+ }
+
m_pContentControl = nullptr;
}
@@ -3337,7 +3472,8 @@ bool DocxAttributeOutput::FootnoteEndnoteRefTag()
the switch in DocxAttributeOutput::RunText() nicer ;-)
*/
static bool impl_WriteRunText( FSHelperPtr const & pSerializer, sal_Int32 nTextToken,
- const sal_Unicode* &rBegin, const sal_Unicode* pEnd, bool bMove = true )
+ const sal_Unicode* &rBegin, const sal_Unicode* pEnd, bool bMove = true,
+ const OUString& rSymbolFont = OUString() )
{
const sal_Unicode *pBegin = rBegin;
@@ -3348,32 +3484,39 @@ static bool impl_WriteRunText( FSHelperPtr const & pSerializer, sal_Int32 nTextT
if ( pBegin >= pEnd )
return false; // we want to write at least one character
- // we have to add 'preserve' when starting/ending with space
- if ( *pBegin == ' ' || *( pEnd - 1 ) == ' ' )
+ bool bIsSymbol = !rSymbolFont.isEmpty();
+
+ std::u16string_view aView( pBegin, pEnd - pBegin );
+ if (bIsSymbol)
{
- pSerializer->startElementNS(XML_w, nTextToken, FSNS(XML_xml, XML_space), "preserve");
+ for (char16_t aChar : aView)
+ {
+ pSerializer->singleElementNS(XML_w, XML_sym,
+ FSNS(XML_w, XML_font), rSymbolFont,
+ FSNS(XML_w, XML_char), OString::number(aChar, 16));
+ }
}
else
- pSerializer->startElementNS(XML_w, nTextToken);
-
- pSerializer->writeEscaped( std::u16string_view( pBegin, pEnd - pBegin ) );
+ {
+ // we have to add 'preserve' when starting/ending with space
+ if ( *pBegin == ' ' || *( pEnd - 1 ) == ' ' )
+ pSerializer->startElementNS(XML_w, nTextToken, FSNS(XML_xml, XML_space), "preserve");
+ else
+ pSerializer->startElementNS(XML_w, nTextToken);
- pSerializer->endElementNS( XML_w, nTextToken );
+ pSerializer->writeEscaped( aView );
+ pSerializer->endElementNS( XML_w, nTextToken );
+ }
return true;
}
-void DocxAttributeOutput::RunText( const OUString& rText, rtl_TextEncoding /*eCharSet*/ )
+void DocxAttributeOutput::RunText( const OUString& rText, rtl_TextEncoding /*eCharSet*/, const OUString& rSymbolFont )
{
if( m_closeHyperlinkInThisRun )
{
m_closeHyperlinkInPreviousRun = true;
}
- if (m_nCloseContentControlInThisRun > 0)
- {
- ++m_nCloseContentControlInPreviousRun;
- --m_nCloseContentControlInThisRun;
- }
m_bRunTextIsOn = true;
// one text can be split into more <w:t>blah</w:t>'s by line breaks etc.
const sal_Unicode *pBegin = rText.getStr();
@@ -3428,7 +3571,7 @@ void DocxAttributeOutput::RunText( const OUString& rText, rtl_TextEncoding /*eCh
}
}
- impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pEnd, false );
+ impl_WriteRunText( m_pSerializer, nTextToken, pBegin, pEnd, false, rSymbolFont );
}
void DocxAttributeOutput::RawText(const OUString& rText, rtl_TextEncoding /*eCharSet*/)
@@ -3440,7 +3583,7 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, co
{
WW8Ruby aWW8Ruby( rNode, rRuby, GetExport() );
SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::StartRuby( const SwTextNode& rNode, const SwFormatRuby& rRuby )" );
- EndRun( &rNode, nPos ); // end run before starting ruby to avoid nested runs, and overlap
+ EndRun( &rNode, nPos, -1 ); // end run before starting ruby to avoid nested runs, and overlap
assert(!m_closeHyperlinkInThisRun); // check that no hyperlink overlaps ruby
assert(!m_closeHyperlinkInPreviousRun);
m_pSerializer->startElementNS(XML_w, XML_r);
@@ -3484,7 +3627,7 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, co
EndRunProperties( nullptr );
RunText( rRuby.GetText( ) );
- EndRun( &rNode, nPos );
+ EndRun( &rNode, nPos, -1 );
m_pSerializer->endElementNS( XML_w, XML_rt );
m_pSerializer->startElementNS(XML_w, XML_rubyBase);
@@ -3494,7 +3637,7 @@ void DocxAttributeOutput::StartRuby( const SwTextNode& rNode, sal_Int32 nPos, co
void DocxAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
{
SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::EndRuby()" );
- EndRun( &rNode, nPos );
+ EndRun( &rNode, nPos, -1 );
m_pSerializer->endElementNS( XML_w, XML_rubyBase );
m_pSerializer->endElementNS( XML_w, XML_ruby );
m_pSerializer->endElementNS( XML_w, XML_r );
@@ -3725,7 +3868,12 @@ void DocxAttributeOutput::Redline( const SwRedlineData* pRedlineData)
m_pSerializer->startElementNS(XML_w, XML_pPr);
- OString sStyleName = MSWordStyles::CreateStyleId( sParaStyleName );
+ OString sStyleName;
+ if (auto format = m_rExport.m_rDoc.FindTextFormatCollByName(sParaStyleName))
+ if (auto slot = m_rExport.m_pStyles->GetSlot(format); slot != 0xfff)
+ sStyleName = m_rExport.m_pStyles->GetStyleId(slot);
+ if (sStyleName.isEmpty())
+ sStyleName = MSWordStyles::CreateStyleId(sParaStyleName);
if ( !sStyleName.isEmpty() )
m_pSerializer->singleElementNS(XML_w, XML_pStyle, FSNS(XML_w, XML_val), sStyleName);
@@ -3768,13 +3916,14 @@ void DocxAttributeOutput::Redline( const SwRedlineData* pRedlineData)
// The difference between 'Redline' and 'StartRedline'+'EndRedline' is that:
// 'Redline' is used for tracked changes of formatting information of a run like Bold, Underline. (the '<w:rPrChange>' is inside the 'run' node)
// 'StartRedline' is used to output tracked changes of run insertion and deletion (the run is inside the '<w:ins>' node)
-void DocxAttributeOutput::StartRedline( const SwRedlineData * pRedlineData )
+void DocxAttributeOutput::StartRedline( const SwRedlineData * pRedlineData, bool bLastRun )
{
if ( !pRedlineData )
return;
// write out stack of this redline recursively (first the oldest)
- StartRedline( pRedlineData->Next() );
+ if ( !bLastRun )
+ StartRedline( pRedlineData->Next(), false );
OString aId( OString::number( m_nRedlineId++ ) );
@@ -3817,7 +3966,7 @@ void DocxAttributeOutput::StartRedline( const SwRedlineData * pRedlineData )
}
}
-void DocxAttributeOutput::EndRedline( const SwRedlineData * pRedlineData )
+void DocxAttributeOutput::EndRedline( const SwRedlineData * pRedlineData, bool bLastRun )
{
if ( !pRedlineData || m_bWritingField )
return;
@@ -3841,7 +3990,8 @@ void DocxAttributeOutput::EndRedline( const SwRedlineData * pRedlineData )
}
// write out stack of this redline recursively (first the newest)
- EndRedline( pRedlineData->Next() );
+ if ( !bLastRun )
+ EndRedline( pRedlineData->Next(), false );
}
void DocxAttributeOutput::FormatDrop( const SwTextNode& /*rNode*/, const SwFormatDrop& /*rSwFormatDrop*/, sal_uInt16 /*nStyle*/, ww8::WW8TableNodeInfo::Pointer_t /*pTextNodeInfo*/, ww8::WW8TableNodeInfoInner::Pointer_t )
@@ -6879,6 +7029,11 @@ void DocxAttributeOutput::pushToTableExportContext(DocxTableExportContext& rCont
rContext.m_bStartedParaSdt = m_aParagraphSdt.m_bStartedSdt;
m_aParagraphSdt.m_bStartedSdt = false;
+ rContext.m_bStartedRunSdt = m_aRunSdt.m_bStartedSdt;
+ m_aRunSdt.m_bStartedSdt = false;
+
+ rContext.m_nHyperLinkCount = m_nHyperLinkCount;
+ m_nHyperLinkCount = 0;
}
void DocxAttributeOutput::popFromTableExportContext(DocxTableExportContext const & rContext)
@@ -6887,6 +7042,8 @@ void DocxAttributeOutput::popFromTableExportContext(DocxTableExportContext const
m_tableReference->m_bTableCellOpen = rContext.m_bTableCellOpen;
m_tableReference->m_nTableDepth = rContext.m_nTableDepth;
m_aParagraphSdt.m_bStartedSdt = rContext.m_bStartedParaSdt;
+ m_aRunSdt.m_bStartedSdt = rContext.m_bStartedRunSdt;
+ m_nHyperLinkCount = rContext.m_nHyperLinkCount;
}
void DocxAttributeOutput::WriteTextBox(uno::Reference<drawing::XShape> xShape)
@@ -7021,7 +7178,7 @@ static bool lcl_guessQFormat(const OUString& rName, sal_uInt16 nWwId)
}
void DocxAttributeOutput::StartStyle( const OUString& rName, StyleType eType,
- sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 nLink, sal_uInt16 nWwId, sal_uInt16 nId, bool bAutoUpdate )
+ sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 nLink, sal_uInt16 nWwId, sal_uInt16 nSlot, bool bAutoUpdate )
{
bool bQFormat = false, bUnhideWhenUsed = false, bSemiHidden = false, bLocked = false, bDefault = false, bCustomStyle = false;
OUString aRsid, aUiPriority;
@@ -7029,12 +7186,12 @@ void DocxAttributeOutput::StartStyle( const OUString& rName, StyleType eType,
uno::Any aAny;
if (eType == STYLE_TYPE_PARA || eType == STYLE_TYPE_CHAR)
{
- const SwFormat* pFormat = m_rExport.m_pStyles->GetSwFormat(nId);
+ const SwFormat* pFormat = m_rExport.m_pStyles->GetSwFormat(nSlot);
pFormat->GetGrabBagItem(aAny);
}
else
{
- const SwNumRule* pRule = m_rExport.m_pStyles->GetSwNumRule(nId);
+ const SwNumRule* pRule = m_rExport.m_pStyles->GetSwNumRule(nSlot);
pRule->GetGrabBagItem(aAny);
}
const uno::Sequence<beans::PropertyValue>& rGrabBag = aAny.get< uno::Sequence<beans::PropertyValue> >();
@@ -7061,28 +7218,25 @@ void DocxAttributeOutput::StartStyle( const OUString& rName, StyleType eType,
SAL_WARN("sw.ww8", "Unhandled style property: " << rProp.Name);
}
- // MSO exports English names and writerfilter only recognize them.
- const char *pEnglishName = nullptr;
const char* pType = nullptr;
switch (eType)
{
case STYLE_TYPE_PARA:
pType = "paragraph";
- if ( nWwId < ww::stiMax)
- pEnglishName = ww::GetEnglishNameFromSti( static_cast<ww::sti>(nWwId ) );
break;
- case STYLE_TYPE_CHAR: pType = "character"; break;
+ case STYLE_TYPE_CHAR:
+ pType = "character";
+ break;
case STYLE_TYPE_LIST: pType = "numbering"; break;
}
pStyleAttributeList->add(FSNS( XML_w, XML_type ), pType);
- pStyleAttributeList->add(FSNS(XML_w, XML_styleId), m_rExport.m_pStyles->GetStyleId(nId));
+ pStyleAttributeList->add(FSNS(XML_w, XML_styleId), m_rExport.m_pStyles->GetStyleId(nSlot));
if (bDefault)
pStyleAttributeList->add(FSNS(XML_w, XML_default), "1");
if (bCustomStyle)
pStyleAttributeList->add(FSNS(XML_w, XML_customStyle), "1");
m_pSerializer->startElementNS( XML_w, XML_style, pStyleAttributeList);
- m_pSerializer->singleElementNS( XML_w, XML_name,
- FSNS( XML_w, XML_val ), pEnglishName ? pEnglishName : rName.toUtf8() );
+ m_pSerializer->singleElementNS(XML_w, XML_name, FSNS(XML_w, XML_val), rName);
if ( nBase != 0x0FFF && eType != STYLE_TYPE_LIST)
{
@@ -7090,7 +7244,7 @@ void DocxAttributeOutput::StartStyle( const OUString& rName, StyleType eType,
FSNS( XML_w, XML_val ), m_rExport.m_pStyles->GetStyleId(nBase) );
}
- if ( nNext != nId && eType != STYLE_TYPE_LIST)
+ if ( nNext != nSlot && eType != STYLE_TYPE_LIST)
{
m_pSerializer->singleElementNS( XML_w, XML_next,
FSNS( XML_w, XML_val ), m_rExport.m_pStyles->GetStyleId(nNext) );
@@ -7703,10 +7857,16 @@ void DocxAttributeOutput::EmbedFont( std::u16string_view name, FontFamily family
{
if( !m_rExport.m_rDoc.getIDocumentSettingAccess().get( DocumentSettingId::EMBED_FONTS ))
return; // no font embedding with this document
- EmbedFontStyle( name, XML_embedRegular, family, ITALIC_NONE, WEIGHT_NORMAL, pitch );
- EmbedFontStyle( name, XML_embedBold, family, ITALIC_NONE, WEIGHT_BOLD, pitch );
- EmbedFontStyle( name, XML_embedItalic, family, ITALIC_NORMAL, WEIGHT_NORMAL, pitch );
- EmbedFontStyle( name, XML_embedBoldItalic, family, ITALIC_NORMAL, WEIGHT_BOLD, pitch );
+ bool foundFont
+ = EmbedFontStyle(name, XML_embedRegular, family, ITALIC_NONE, WEIGHT_NORMAL, pitch);
+ foundFont
+ = EmbedFontStyle(name, XML_embedBold, family, ITALIC_NONE, WEIGHT_BOLD, pitch) || foundFont;
+ foundFont = EmbedFontStyle(name, XML_embedItalic, family, ITALIC_NORMAL, WEIGHT_NORMAL, pitch)
+ || foundFont;
+ foundFont = EmbedFontStyle(name, XML_embedBoldItalic, family, ITALIC_NORMAL, WEIGHT_BOLD, pitch)
+ || foundFont;
+ if (!foundFont)
+ EmbedFontStyle(name, XML_embedRegular, family, ITALIC_NONE, WEIGHT_DONTKNOW, pitch);
}
static char toHexChar( int value )
@@ -7714,21 +7874,21 @@ static char toHexChar( int value )
return value >= 10 ? value + 'A' - 10 : value + '0';
}
-void DocxAttributeOutput::EmbedFontStyle( std::u16string_view name, int tag, FontFamily family, FontItalic italic,
- FontWeight weight, FontPitch pitch )
+bool DocxAttributeOutput::EmbedFontStyle(std::u16string_view name, int tag, FontFamily family,
+ FontItalic italic, FontWeight weight, FontPitch pitch)
{
// Embed font if at least viewing is allowed (in which case the opening app must check
// the font license rights too and open either read-only or not use the font for editing).
OUString fontUrl = EmbeddedFontsHelper::fontFileUrl( name, family, italic, weight, pitch,
EmbeddedFontsHelper::FontRights::ViewingAllowed );
if( fontUrl.isEmpty())
- return;
+ return false;
// TODO IDocumentSettingAccess::EMBED_SYSTEM_FONTS
if( !fontFilesMap.count( fontUrl ))
{
osl::File file( fontUrl );
if( file.open( osl_File_OpenFlag_Read ) != osl::File::E_None )
- return;
+ return false;
uno::Reference< css::io::XOutputStream > xOutStream = m_rExport.GetFilter().openFragmentStream(
"word/fonts/font" + OUString::number(m_nextFontId) + ".odttf",
"application/vnd.openxmlformats-officedocument.obfuscatedFont" );
@@ -7747,7 +7907,7 @@ void DocxAttributeOutput::EmbedFontStyle( std::u16string_view name, int tag, Fon
{
SAL_WARN( "sw.ww8", "Font file size too small (" << fontUrl << ")" );
xOutStream->closeOutput();
- return;
+ return false;
}
for( int i = 0;
i < 16;
@@ -7764,7 +7924,7 @@ void DocxAttributeOutput::EmbedFontStyle( std::u16string_view name, int tag, Fon
{
SAL_WARN( "sw.ww8", "Error reading font file " << fontUrl );
xOutStream->closeOutput();
- return;
+ return false;
}
if( eof )
break;
@@ -7772,7 +7932,7 @@ void DocxAttributeOutput::EmbedFontStyle( std::u16string_view name, int tag, Fon
{
SAL_WARN( "sw.ww8", "Error reading font file " << fontUrl );
xOutStream->closeOutput();
- return;
+ return false;
}
if( readSize == 0 )
break;
@@ -7792,6 +7952,7 @@ void DocxAttributeOutput::EmbedFontStyle( std::u16string_view name, int tag, Fon
m_pSerializer->singleElementNS( XML_w, tag,
FSNS( XML_r, XML_id ), fontFilesMap[ fontUrl ].relId,
FSNS( XML_w, XML_fontKey ), fontFilesMap[ fontUrl ].fontKey );
+ return true;
}
OString DocxAttributeOutput::TransHighlightColor( sal_uInt8 nIco )
@@ -8589,9 +8750,13 @@ void DocxAttributeOutput::CharHighlight( const SvxBrushItem& rHighlight )
void DocxAttributeOutput::TextINetFormat( const SwFormatINetFormat& rLink )
{
- OString aStyleId = MSWordStyles::CreateStyleId(rLink.GetINetFormat());
- if (!aStyleId.isEmpty() && !aStyleId.equalsIgnoreAsciiCase("DefaultStyle"))
- m_pSerializer->singleElementNS(XML_w, XML_rStyle, FSNS(XML_w, XML_val), aStyleId);
+ const SwCharFormat* pFormat = m_rExport.m_rDoc.FindCharFormatByName(rLink.GetINetFormat());
+ if (pFormat)
+ {
+ OString aStyleId(m_rExport.m_pStyles->GetStyleId(m_rExport.GetId(pFormat)));
+ if (!aStyleId.equalsIgnoreAsciiCase("DefaultStyle"))
+ m_pSerializer->singleElementNS(XML_w, XML_rStyle, FSNS(XML_w, XML_val), aStyleId);
+ }
}
void DocxAttributeOutput::TextCharFormat( const SwFormatCharFormat& rCharFormat )
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index a264b879fd9b..9efd51a9af93 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -128,20 +128,27 @@ class SdtBlockHelper
{
public:
SdtBlockHelper()
- : m_bHasId(false)
+ : m_nId(0)
, m_bStartedSdt(false)
+ , m_bShowingPlaceHolder(false)
+ , m_nTabIndex(0)
, m_nSdtPrToken(0)
{}
- bool m_bHasId;
+ sal_Int32 m_nId;
bool m_bStartedSdt;
rtl::Reference<sax_fastparser::FastAttributeList> m_pTokenChildren;
rtl::Reference<sax_fastparser::FastAttributeList> m_pTokenAttributes;
rtl::Reference<sax_fastparser::FastAttributeList> m_pTextAttrs;
rtl::Reference<sax_fastparser::FastAttributeList> m_pDataBindingAttrs;
OUString m_aColor;
+ OUString m_aAppearance;
OUString m_aPlaceHolderDocPart;
+ bool m_bShowingPlaceHolder;
OUString m_aAlias;
+ OUString m_aTag;
+ sal_Int32 m_nTabIndex;
+ OUString m_aLock;
sal_Int32 m_nSdtPrToken;
void DeleteAndResetTheLists();
@@ -185,7 +192,7 @@ public:
virtual void StartRun( const SwRedlineData* pRedlineData, sal_Int32 nPos, bool bSingleEmptyRun = false ) override;
/// End of the text run.
- virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun = false) override;
+ virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_Int32 nLen, bool bLastRun = false) override;
/// Called before we start outputting the attributes.
virtual void StartRunProperties() override;
@@ -200,7 +207,7 @@ public:
virtual void WritePostitFieldReference() override;
/// Output text (inside a run).
- virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8 ) override;
+ virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8, const OUString& rSymbolFont = OUString() ) override;
/// Output text (without markup).
virtual void RawText(const OUString& rText, rtl_TextEncoding eCharSet) override;
@@ -228,12 +235,12 @@ public:
///
/// Start of the tag that encloses the run, fills the info according to
/// the value of pRedlineData.
- void StartRedline( const SwRedlineData * pRedlineData );
+ void StartRedline( const SwRedlineData * pRedlineData, bool bLastRun );
/// Output redlining.
///
/// End of the tag that encloses the run.
- void EndRedline( const SwRedlineData * pRedlineData );
+ void EndRedline( const SwRedlineData * pRedlineData, bool bLastRun );
virtual void SetStateOfFlyFrame( FlyProcessingState nStateOfFlyFrame ) override;
virtual void SetAnchorIsLinkedToNode( bool bAnchorLinkedToNode ) override;
@@ -286,7 +293,7 @@ public:
/// Start of a style in the styles table.
virtual void StartStyle( const OUString& rName, StyleType eType,
- sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 nLink, sal_uInt16 nWwId, sal_uInt16 nId,
+ sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 nLink, sal_uInt16 nWwId, sal_uInt16 nSlot,
bool bAutoUpdate ) override;
/// End of a style in the styles table.
@@ -405,12 +412,6 @@ public:
void WriteFloatingTable(ww8::Frame const* pParentFrame);
- /// See AttributeOutputBase::StartContentControl().
- void StartContentControl(const SwFormatContentControl& rFormatContentControl) override;
-
- /// See AttributeOutputBase::EndContentControl().
- void EndContentControl() override;
-
private:
/// Initialize the structures where we are going to collect some of the paragraph properties.
///
@@ -477,7 +478,7 @@ private:
void WriteFFData( const FieldInfos& rInfos );
void WritePendingPlaceholder();
- void EmbedFontStyle( std::u16string_view name, int tag, FontFamily family, FontItalic italic, FontWeight weight,
+ bool EmbedFontStyle( std::u16string_view name, int tag, FontFamily family, FontItalic italic, FontWeight weight,
FontPitch pitch );
/**
@@ -912,9 +913,6 @@ private:
o3tl::sorted_vector<const SwFrameFormat*> m_aFloatingTablesOfParagraph;
sal_Int32 m_nTextFrameLevel;
- sal_Int32 m_nCloseContentControlInThisRun = 0;
- sal_Int32 m_nCloseContentControlInPreviousRun = 0;
-
// close of hyperlink needed
bool m_closeHyperlinkInThisRun;
bool m_closeHyperlinkInPreviousRun;
@@ -1112,7 +1110,9 @@ struct DocxTableExportContext
ww8::WW8TableInfo::Pointer_t m_pTableInfo;
bool m_bTableCellOpen;
bool m_bStartedParaSdt;
+ bool m_bStartedRunSdt;
sal_uInt32 m_nTableDepth;
+ sal_Int32 m_nHyperLinkCount = 0;
DocxTableExportContext(DocxAttributeOutput& rOutput) : m_rOutput(rOutput) { m_rOutput.pushToTableExportContext(*this); }
~DocxTableExportContext() { m_rOutput.popFromTableExportContext(*this); }
};
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 6a4ba2dd58cd..3d2ea628b594 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -393,6 +393,7 @@ OString DocxExport::OutputChart( uno::Reference< frame::XModel > const & xModel,
// tdf#134973: the model could get modified: e.g., calling XChartDocument::getSubTitle(),
// which creates the object if absent, and sets the modified state.
xModifiable->setModified(bOldModified);
+ pChartFS->endDocument();
return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
}
@@ -489,6 +490,8 @@ std::pair<OString, OString> DocxExport::WriteActiveXObject(const uno::Reference<
sXMLFileName.subView(sBinaryFileName.indexOf("/") + 1)),
RTL_TEXTENCODING_UTF8);
+ pActiveXFS->endDocument();
+
return std::pair<OString, OString>(sXMLId, sName);
}
@@ -538,7 +541,8 @@ ErrCode DocxExport::ExportDocument_Impl()
WriteEmbeddings();
- WriteVBA();
+ if (m_bDocm)
+ WriteVBA();
m_aLinkedTextboxesHelper.clear(); //final cleanup
m_pStyles.reset();
@@ -663,6 +667,8 @@ void DocxExport::InitStyles()
// switch the serializer back
m_pAttrOutput->SetSerializer( m_pDocumentFS );
+
+ pStylesFS->endDocument();
}
void DocxExport::WriteFootnotesEndnotes()
@@ -692,6 +698,8 @@ void DocxExport::WriteFootnotesEndnotes()
m_pVMLExport->SetFS(m_pDocumentFS);
m_pSdrExport->setSerializer( m_pDocumentFS );
m_pAttrOutput->SetSerializer( m_pDocumentFS );
+
+ pFootnotesFS->endDocument();
}
if ( !m_pAttrOutput->HasEndnotes() )
@@ -720,6 +728,8 @@ void DocxExport::WriteFootnotesEndnotes()
m_pVMLExport->SetFS(m_pDocumentFS);
m_pSdrExport->setSerializer( m_pDocumentFS );
m_pAttrOutput->SetSerializer( m_pDocumentFS );
+
+ pEndnotesFS->endDocument();
}
void DocxExport::WritePostitFields()
@@ -740,6 +750,7 @@ void DocxExport::WritePostitFields()
const auto eHasResolved = m_pAttrOutput->WritePostitFields();
m_pAttrOutput->SetSerializer( m_pDocumentFS );
pPostitFS->endElementNS( XML_w, XML_comments );
+ pPostitFS->endDocument();
if (eHasResolved != DocxAttributeOutput::hasResolved::yes)
return;
@@ -760,6 +771,7 @@ void DocxExport::WritePostitFields()
m_pAttrOutput->WritePostItFieldsResolved();
m_pAttrOutput->SetSerializer(m_pDocumentFS);
pPostitFS->endElementNS(XML_w15, XML_commentsEx);
+ pPostitFS->endDocument();
}
void DocxExport::WriteNumbering()
@@ -798,6 +810,8 @@ void DocxExport::WriteNumbering()
// switch the serializer back
m_pDrawingML->SetFS( m_pDocumentFS );
m_pAttrOutput->SetSerializer( m_pDocumentFS );
+
+ pNumberingFS->endDocument();
}
void DocxExport::WriteHeaderFooter( const SwFormat* pFormat, bool bHeader, const char* pType )
@@ -870,6 +884,8 @@ void DocxExport::WriteHeaderFooter( const SwFormat* pFormat, bool bHeader, const
m_pDocumentFS->singleElementNS( XML_w, nReference,
FSNS( XML_w, XML_type ), pType,
FSNS( XML_r, XML_id ), aRelId );
+
+ pFS->endDocument();
}
void DocxExport::WriteFonts()
@@ -896,6 +912,8 @@ void DocxExport::WriteFonts()
m_pAttrOutput->SetSerializer( m_pDocumentFS );
pFS->endElementNS( XML_w, XML_fonts );
+
+ pFS->endDocument();
}
void DocxExport::WriteProperties( )
@@ -1417,6 +1435,8 @@ void DocxExport::WriteSettings()
// finish settings.xml
pFS->endElementNS( XML_w, XML_settings );
+
+ pFS->endDocument();
}
void DocxExport::WriteTheme()
@@ -1452,6 +1472,7 @@ void DocxExport::WriteTheme()
uno::Sequence< beans::StringPair >() );
}
+// See OOXMLDocumentImpl::resolveGlossaryStream
void DocxExport::WriteGlossary()
{
uno::Reference< beans::XPropertySet > xPropSet( m_rDoc.GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
@@ -1462,7 +1483,7 @@ void DocxExport::WriteGlossary()
return;
uno::Reference<xml::dom::XDocument> glossaryDocDom;
- uno::Sequence< uno::Sequence< uno::Any> > glossaryDomList;
+ uno::Sequence< uno::Sequence<beans::NamedValue> > glossaryDomList;
uno::Sequence< beans::PropertyValue > propList;
xPropSet->getPropertyValue( aName ) >>= propList;
sal_Int32 collectedProperties = 0;
@@ -1500,20 +1521,43 @@ void DocxExport::WriteGlossary()
serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
uno::Sequence< beans::StringPair >() );
- for ( const uno::Sequence< uno::Any>& glossaryElement : std::as_const(glossaryDomList))
+ for (const uno::Sequence<beans::NamedValue>& glossaryElement : glossaryDomList)
{
- OUString gTarget, gType, gId, contentType;
+ OUString gTarget, gType, gId, contentType, targetMode;
uno::Reference<xml::dom::XDocument> xDom;
- glossaryElement[0] >>= xDom;
- glossaryElement[1] >>= gId;
- glossaryElement[2] >>= gType;
- glossaryElement[3] >>= gTarget;
- glossaryElement[4] >>= contentType;
+ for (const auto& [name, value] : glossaryElement)
+ {
+ if (name == "Id")
+ value >>= gId;
+ else if (name == "Type")
+ value >>= gType;
+ else if (name == "Target")
+ value >>= gTarget;
+ else if (name == "TargetMode")
+ value >>= targetMode;
+ else if (name == "_contentType")
+ value >>= contentType;
+ else if (name == "_relDom")
+ value >>= xDom;
+ }
+ if (gId.isEmpty() || gType.isEmpty() || gTarget.isEmpty())
+ continue;
+ const bool bExternal = targetMode == "External";
+ if (!bExternal && !xDom)
+ {
+ // Some internal relation, but we didn't create a DOM for it
+ // in OOXMLDocumentImpl::resolveGlossaryStream?
+ SAL_WARN("sw.ww8", "Glossary internal relation without DOM: Id=\"" + gId
+ + "\" Type=\"" + gType + "\" Target=\"" + gTarget + "\"");
+ continue;
+ }
gId = gId.copy(3); //"rId" only save the numeric value
PropertySet aProps(xOutputStream);
aProps.setAnyProperty( PROP_RelId, uno::makeAny( gId.toInt32() ));
- m_rFilter.addRelation( xOutputStream, gType, gTarget);
+ m_rFilter.addRelation(xOutputStream, gType, gTarget, bExternal);
+ if (!xDom)
+ continue; // External relation, no stream to write
uno::Reference< xml::sax::XSAXSerializable > gserializer( xDom, uno::UNO_QUERY );
writer->setOutputStream(GetFilter().openFragmentStream( "word/glossary/" + gTarget, contentType ) );
gserializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
@@ -1949,7 +1993,7 @@ sal_Int32 DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt
eChrSet = eNextChrSet;
aAttrIter.NextPos();
- AttrOutput().EndRun( nullptr, 0 );
+ AttrOutput().EndRun( nullptr, 0, -1 );
} while( nCurrentPos < nEnd );
// aAttrIter.OutParaAttr(false);
@@ -2082,6 +2126,7 @@ DocxExport::DocxExport(DocxExportFilter& rFilter, SwDoc& rDocument,
DocxExport::~DocxExport()
{
+ m_pDocumentFS->endDocument();
}
DocxSettingsData::DocxSettingsData()
diff --git a/sw/source/filter/ww8/docxexportfilter.cxx b/sw/source/filter/ww8/docxexportfilter.cxx
index 08308ca9398c..5ffd32f4c25b 100644
--- a/sw/source/filter/ww8/docxexportfilter.cxx
+++ b/sw/source/filter/ww8/docxexportfilter.cxx
@@ -63,6 +63,37 @@ bool DocxExportFilter::exportDocument()
pViewShell->GetPostItMgr()->UpdateDataOnActiveSidebarWin();
}
+ OUString aFilterName;
+ auto& rMediaDescriptor = getMediaDescriptor();
+ rMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] >>= aFilterName;
+ bool bDocm = aFilterName.endsWith("VBA");
+
+ if (!bDocm)
+ {
+ // Check whether application is in headless mode
+ if (!Application::IsHeadlessModeEnabled())
+ {
+ uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(
+ pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
+ if (xStorageBasedDocument.is())
+ {
+ uno::Reference<embed::XStorage> xDocumentStorage =
+ xStorageBasedDocument->getDocumentStorage();
+ if (xDocumentStorage.is() && xDocumentStorage->hasByName(u"_MS_VBA_Macros"))
+ {
+ // Let user know that macros won't be saved in this format
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
+ nullptr,
+ VclMessageType::Warning, VclButtonsType::OkCancel,
+ SwResId(STR_CANT_SAVE_MACROS))
+ );
+ if (xBox->run() == RET_CANCEL)
+ return false;
+ }
+ }
+ }
+ }
+
// get SwPaM*
// FIXME so far we get SwPaM for the entire document; probably we should
// be able to output just the selection as well - though no idea how to
@@ -75,10 +106,6 @@ bool DocxExportFilter::exportDocument()
pCurPam->SetMark();
*pCurPam->GetPoint() = *aPam.Start();
- OUString aFilterName;
- getMediaDescriptor()[utl::MediaDescriptor::PROP_FILTERNAME] >>= aFilterName;
- bool bDocm = aFilterName.endsWith("VBA");
-
// export the document
// (in a separate block so that it's destructed before the commit)
{
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index d7c8bef9b41a..82013d3cbf0c 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -406,7 +406,8 @@ void RtfAttributeOutput::StartRun(const SwRedlineData* pRedlineData, sal_Int32 /
OSL_ENSURE(m_aRunText.getLength() == 0, "m_aRunText is not empty");
}
-void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/, bool /*bLastRun*/)
+void RtfAttributeOutput::EndRun(const SwTextNode* /*pNode*/, sal_Int32 /*nPos*/, sal_Int32 /*nLen*/,
+ bool /*bLastRun*/)
{
m_aRun->append(SAL_NEWLINE_STRING);
m_aRun.appendAndClear(m_aRunText);
@@ -501,7 +502,8 @@ OString RtfAttributeOutput::MoveCharacterProperties(bool aAutoWriteRtlLtr)
return aBuf.makeStringAndClear();
}
-void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding /*eCharSet*/)
+void RtfAttributeOutput::RunText(const OUString& rText, rtl_TextEncoding /*eCharSet*/,
+ const OUString& /*rSymbolFont*/)
{
SAL_INFO("sw.rtf", __func__ << ", rText: " << rText);
RawText(rText, m_rExport.GetCurrentEncoding());
@@ -1151,7 +1153,7 @@ void RtfAttributeOutput::DefaultStyle() { /* noop, the default style is always 0
void RtfAttributeOutput::StartStyle(const OUString& rName, StyleType eType, sal_uInt16 nBase,
sal_uInt16 nNext, sal_uInt16 /*nLink*/, sal_uInt16 /*nWwId*/,
- sal_uInt16 nId, bool bAutoUpdate)
+ sal_uInt16 nSlot, bool bAutoUpdate)
{
SAL_INFO("sw.rtf", __func__ << ", rName = '" << rName << "'");
@@ -1160,7 +1162,7 @@ void RtfAttributeOutput::StartStyle(const OUString& rName, StyleType eType, sal_
m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_S);
else
m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_IGNORE OOO_STRING_SVTOOLS_RTF_CS);
- m_aStylesheet.append(static_cast<sal_Int32>(nId));
+ m_aStylesheet.append(static_cast<sal_Int32>(nSlot));
if (nBase != 0x0FFF)
{
@@ -1175,7 +1177,7 @@ void RtfAttributeOutput::StartStyle(const OUString& rName, StyleType eType, sal_
m_aStylesheet.append(OOO_STRING_SVTOOLS_RTF_SAUTOUPD);
m_rStyleName = rName;
- m_nStyleId = nId;
+ m_nStyleId = nSlot;
}
void RtfAttributeOutput::EndStyle()
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index aedef264b7d2..9cc36440a9d4 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -74,7 +74,8 @@ public:
bool bSingleEmptyRun = false) override;
/// End of the text run.
- void EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun = false) override;
+ void EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_Int32 nLen,
+ bool bLastRun = false) override;
/// Called before we start outputting the attributes.
void StartRunProperties() override;
@@ -83,7 +84,8 @@ public:
void EndRunProperties(const SwRedlineData* pRedlineData) override;
/// Output text (inside a run).
- void RunText(const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8) override;
+ void RunText(const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8,
+ const OUString& rSymbolFont = OUString()) override;
// Access to (anyway) private buffers, used by the sdr exporter
OStringBuffer& RunText();
@@ -147,7 +149,8 @@ public:
/// Start of a style in the styles table.
void StartStyle(const OUString& rName, StyleType eType, sal_uInt16 nBase, sal_uInt16 nNext,
- sal_uInt16 nLink, sal_uInt16 nWwId, sal_uInt16 nId, bool bAutoUpdate) override;
+ sal_uInt16 nLink, sal_uInt16 nWwId, sal_uInt16 nSlot,
+ bool bAutoUpdate) override;
/// End of a style in the styles table.
void EndStyle() override;
diff --git a/sw/source/filter/ww8/styles.cxx b/sw/source/filter/ww8/styles.cxx
index 6f613b40fad6..33d0ad3dec5f 100644
--- a/sw/source/filter/ww8/styles.cxx
+++ b/sw/source/filter/ww8/styles.cxx
@@ -23,104 +23,106 @@
namespace
{
+ // Keep in sync with StyleSheetTable::ConvertStyleName
const char **GetStiNames() noexcept
{
+ // Matches enum ww::sti in sw/source/filter/inc/wwstyles.hxx
static const char *stiName[] =
{
- "Normal",
- "Heading 1",
- "Heading 2",
- "Heading 3",
- "Heading 4",
- "Heading 5",
- "Heading 6",
- "Heading 7",
- "Heading 8",
- "Heading 9",
- "Index 1",
- "Index 2",
- "Index 3",
- "Index 4",
- "Index 5",
- "Index 6",
- "Index 7",
- "Index 8",
- "Index 9",
- "TOC 1",
- "TOC 2",
- "TOC 3",
- "TOC 4",
- "TOC 5",
- "TOC 6",
- "TOC 7",
- "TOC 8",
- "TOC 9",
- "Normal Indent",
- "Footnote Text",
- "Annotation Text",
- "Header",
- "Footer",
- "Index Heading",
- "Caption",
- "Table of Figures",
- "Envelope Address",
- "Envelope Return",
- "Footnote Reference",
- "Annotation Reference",
- "Line Number",
- "Page Number",
- "Endnote Reference",
- "Endnote Text",
- "Table of Authorities",
- "Macro Text",
- "TOC Heading",
- "List",
- "List 2",
- "List 3",
- "List 4",
- "List 5",
- "List Bullet",
- "List Bullet 2",
- "List Bullet 3",
- "List Bullet 4",
- "List Bullet 5",
- "List Number",
- "List Number 2",
- "List Number 3",
- "List Number 4",
- "List Number 5",
- "Title",
- "Closing",
- "Signature",
- "Default Paragraph Font",
- "Body Text",
- "Body Text Indent",
- "List Continue",
- "List Continue 2",
- "List Continue 3",
- "List Continue 4",
- "List Continue 5",
- "Message Header",
- "Subtitle",
- "Salutation",
- "Date",
- "Body Text First Indent",
- "Body Text First Indent 2",
- "Note Heading",
- "Body Text 2",
- "Body Text 3",
- "Body Text Indent 2",
- "Body Text Indent 3",
- "Block Text",
- "Hyperlink",
- "Followed Hyperlink",
- "Strong",
- "Emphasis",
- "Document Map",
- "Plain Text"
+ "Normal", // stiNormal
+ "Heading 1", // stiLev1
+ "Heading 2", // stiLev2
+ "Heading 3", // stiLev3
+ "Heading 4", // stiLev4
+ "Heading 5", // stiLev5
+ "Heading 6", // stiLev6
+ "Heading 7", // stiLev7
+ "Heading 8", // stiLev8
+ "Heading 9", // stiLev9
+ "Index 1", // stiIndex1
+ "Index 2", // stiIndex2
+ "Index 3", // stiIndex3
+ "Index 4", // stiIndex4
+ "Index 5", // stiIndex5
+ "Index 6", // stiIndex6
+ "Index 7", // stiIndex7
+ "Index 8", // stiIndex8
+ "Index 9", // stiIndex9
+ "TOC 1", // stiToc1
+ "TOC 2", // stiToc2
+ "TOC 3", // stiToc3
+ "TOC 4", // stiToc4
+ "TOC 5", // stiToc5
+ "TOC 6", // stiToc6
+ "TOC 7", // stiToc7
+ "TOC 8", // stiToc8
+ "TOC 9", // stiToc9
+ "Normal Indent", // stiNormIndent
+ "Footnote Text", // stiFootnoteText
+ "Annotation Text", // stiAtnText
+ "Header", // stiHeader
+ "Footer", // stiFooter
+ "Index Heading", // stiIndexHeading
+ "Caption", // stiCaption
+ "Table of Figures", // stiToCaption
+ "Envelope Address", // stiEnvAddr
+ "Envelope Return", // stiEnvRet
+ "Footnote Reference", // stiFootnoteRef
+ "Annotation Reference", // stiAtnRef
+ "Line Number", // stiLnn
+ "Page Number", // stiPgn
+ "Endnote Reference", // stiEdnRef
+ "Endnote Text", // stiEdnText
+ "Table of Authorities", // stiToa
+ "Macro Text", // stiMacro
+ "TOC Heading", // stiToaHeading - tdf143726
+ "List", // stiList
+ "List Bullet", // stiListBullet
+ "List Number", // stiListNumber
+ "List 2", // stiList2
+ "List 3", // stiList3
+ "List 4", // stiList4
+ "List 5", // stiList5
+ "List Bullet 2", // stiListBullet2
+ "List Bullet 3", // stiListBullet3
+ "List Bullet 4", // stiListBullet4
+ "List Bullet 5", // stiListBullet5
+ "List Number 2", // stiListNumber2
+ "List Number 3", // stiListNumber3
+ "List Number 4", // stiListNumber4
+ "List Number 5", // stiListNumber5
+ "Title", // stiTitle
+ "Closing", // stiClosing
+ "Signature", // stiSignature
+ "Default Paragraph Font", // stiNormalChar
+ "Body Text", // stiBodyText
+ "Body Text Indent", // stiBodyTextInd1
+ "List Continue", // stiListCont
+ "List Continue 2", // stiListCont2
+ "List Continue 3", // stiListCont3
+ "List Continue 4", // stiListCont4
+ "List Continue 5", // stiListCont5
+ "Message Header", // stiMsgHeader
+ "Subtitle", // stiSubtitle
+ "Salutation", // stiSalutation
+ "Date", // stiDate
+ "Body Text First Indent", // stiBodyText1I
+ "Body Text First Indent 2", // stiBodyText1I2
+ "Note Heading", // stiNoteHeading
+ "Body Text 2", // stiBodyText2
+ "Body Text 3", // stiBodyText3
+ "Body Text Indent 2", // stiBodyTextInd2
+ "Body Text Indent 3", // stiBodyTextInd3
+ "Block Text", // stiBlockQuote
+ "Hyperlink", // stiHyperlink
+ "FollowedHyperlink", // stiHyperlinkFollowed
+ "Strong", // stiStrong
+ "Emphasis", // stiEmphasis
+ "Document Map", // stiNavPane
+ "Plain Text", // stiPlainText
};
- OSL_ENSURE( SAL_N_ELEMENTS(stiName) == ww::stiMax, "WrongSizeOfArray" );
+ static_assert(SAL_N_ELEMENTS(stiName) == ww::stiMax, "WrongSizeOfArray");
return stiName;
}
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx
index 805ab17a7464..89fe95801f85 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -1412,14 +1412,6 @@ int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos)
--nRet;
}
break;
- case RES_TXTATR_CONTENTCONTROL:
- pEnd = pHt->End();
- if (nPos == *pEnd && nPos != pHt->GetStart())
- {
- m_rExport.AttrOutput().EndContentControl();
- --nRet;
- }
- break;
}
if (nPos < pHt->GetAnyEnd())
break; // sorted by end
@@ -1474,17 +1466,6 @@ int SwWW8AttrIter::OutAttrWithRange(const SwTextNode& rNode, sal_Int32 nPos)
--nRet;
}
break;
- case RES_TXTATR_CONTENTCONTROL:
- if (nPos == pHt->GetStart())
- {
- auto pFormatContentControl
- = static_cast<const SwFormatContentControl*>(pItem);
- m_rExport.AttrOutput().StartContentControl(*pFormatContentControl);
- ++nRet;
- }
- // We know that the content control is never empty as it has a dummy character
- // at least.
- break;
}
if (nPos < pHt->GetStart())
break; // sorted by start
@@ -2260,6 +2241,23 @@ bool MSWordExportBase::NeedTextNodeSplit( const SwTextNode& rNd, SwSoftPageBreak
return pList.size() > 2 && NeedSectionBreak( rNd );
}
+OUString lcl_GetSymbolFont(SwAttrPool& rPool, const SwTextNode* pTextNode, int nStart, int nEnd)
+{
+ SfxItemSetFixed<RES_CHRATR_FONT, RES_CHRATR_FONT> aSet( rPool );
+ if ( pTextNode && pTextNode->GetParaAttr(aSet, nStart, nEnd) )
+ {
+ SfxPoolItem const* pPoolItem = aSet.GetItem(RES_CHRATR_FONT);
+ if (pPoolItem)
+ {
+ const SvxFontItem* pFontItem = static_cast<const SvxFontItem*>(pPoolItem);
+ if (pFontItem->GetCharSet() == RTL_TEXTENCODING_SYMBOL)
+ return pFontItem->GetFamilyName();
+ }
+ }
+
+ return OUString();
+}
+
void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
{
SAL_INFO( "sw.ww8", "<OutWW8_SwTextNode>" );
@@ -2441,7 +2439,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
{
if( AttrOutput().FootnoteEndnoteRefTag() )
{
- AttrOutput().EndRun( &rNode, nCurrentPos, nNextAttr == nEnd );
+ AttrOutput().EndRun( &rNode, nCurrentPos, -1, nNextAttr == nEnd );
AttrOutput().StartRun( pRedlineData, nCurrentPos, bSingleEmptyRun );
}
}
@@ -2479,6 +2477,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
bool bTextAtr = aAttrIter.IsTextAttr( nCurrentPos );
nOpenAttrWithRange += aAttrIter.OutAttrWithRange( rNode, nCurrentPos );
+ OUString aSymbolFont;
sal_Int32 nLen = nNextAttr - nCurrentPos;
if ( !bTextAtr && nLen )
{
@@ -2495,7 +2494,7 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
&& nStateOfFlyFrame == FLY_PROCESSED)
{
// write flys in a separate run before field character
- AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
+ AttrOutput().EndRun(&rNode, nCurrentPos, -1, nNextAttr == nEnd);
AttrOutput().StartRun(pRedlineData, nCurrentPos, bSingleEmptyRun);
}
@@ -2645,12 +2644,13 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
assert(0 <= nLen);
OUString aSnippet( aAttrIter.GetSnippet( aStr, nCurrentPos + ofs, nLen ) );
+ const SwTextNode* pTextNode( rNode.GetTextNode() );
if ( ( m_nTextTyp == TXT_EDN || m_nTextTyp == TXT_FTN ) && nCurrentPos == 0 && nLen > 0 )
{
// Allow MSO to emulate LO footnote text starting at left margin - only meaningful with hanging indent
sal_Int32 nFirstLineIndent=0;
SfxItemSetFixed<RES_LR_SPACE, RES_LR_SPACE> aSet( m_rDoc.GetAttrPool() );
- const SwTextNode* pTextNode( rNode.GetTextNode() );
+
if ( pTextNode && pTextNode->GetAttr(aSet) )
{
const SvxLRSpaceItem* pLRSpace = aSet.GetItem<SvxLRSpaceItem>(RES_LR_SPACE);
@@ -2664,6 +2664,8 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
m_bAddFootnoteTab = false;
}
+ aSymbolFont = lcl_GetSymbolFont(m_rDoc.GetAttrPool(), pTextNode, nCurrentPos + ofs, nCurrentPos + ofs + nLen);
+
if ( bPostponeWritingText && ( FLY_POSTPONED != nStateOfFlyFrame ) )
{
aSavedSnippet = aSnippet ;
@@ -2671,7 +2673,15 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
else
{
bPostponeWritingText = false ;
- AttrOutput().RunText( aSnippet, eChrSet );
+ AttrOutput().RunText( aSnippet, eChrSet, aSymbolFont );
+ }
+
+ if (ofs == 1 && nNextAttr == nEnd)
+ {
+ // tdf#152200: There could be flys anchored after the last position; make sure
+ // to provide a separate run after field character to write them
+ AttrOutput().EndRun(&rNode, nCurrentPos, -1, nNextAttr == nEnd);
+ AttrOutput().StartRun(pRedlineData, nCurrentPos, bSingleEmptyRun);
}
}
@@ -2787,10 +2797,12 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
AttrOutput().WritePostitFieldReference();
+ aSymbolFont = lcl_GetSymbolFont(m_rDoc.GetAttrPool(), &rNode, nCurrentPos, nCurrentPos + nLen);
+
if (bPostponeWritingText
&& (FLY_PROCESSED == nStateOfFlyFrame || FLY_NONE == nStateOfFlyFrame))
{
- AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
+ AttrOutput().EndRun(&rNode, nCurrentPos, -1, nNextAttr == nEnd);
//write the postponed text run
AttrOutput().StartRun( pRedlineData, nCurrentPos, bSingleEmptyRun );
AttrOutput().SetAnchorIsLinkedToNode( false );
@@ -2801,17 +2813,17 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode )
aAttrIter.OutAttr( nCurrentPos, false );
AttrOutput().EndRunProperties( pRedlineData );
}
- AttrOutput().RunText( aSavedSnippet, eChrSet );
- AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
+ AttrOutput().RunText( aSavedSnippet, eChrSet, aSymbolFont );
+ AttrOutput().EndRun(&rNode, nCurrentPos, nLen, nNextAttr == nEnd);
}
else if( bPostponeWritingText && !aSavedSnippet.isEmpty() )
{
//write the postponed text run
- AttrOutput().RunText( aSavedSnippet, eChrSet );
+ AttrOutput().RunText( aSavedSnippet, eChrSet, aSymbolFont );
AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
}
else
- AttrOutput().EndRun(&rNode, nCurrentPos, nNextAttr == nEnd);
+ AttrOutput().EndRun(&rNode, nCurrentPos, nLen, nNextAttr == nEnd);
nCurrentPos = nNextAttr;
UpdatePosition( &aAttrIter, nCurrentPos );
diff --git a/sw/source/filter/ww8/wrtw8sty.cxx b/sw/source/filter/ww8/wrtw8sty.cxx
index 4126b9f88a50..5fdc76c55aac 100644
--- a/sw/source/filter/ww8/wrtw8sty.cxx
+++ b/sw/source/filter/ww8/wrtw8sty.cxx
@@ -119,14 +119,15 @@ public:
// Styles
-#define WW8_RESERVED_SLOTS 15
+// Immediately after reserved slots, character styles begin
+#define WW8_RESERVED_SLOTS 10
// GetId( SwCharFormat ) for use in text -> zero is not allowed,
// use "Default Char Style" instead
sal_uInt16 MSWordExportBase::GetId( const SwCharFormat* pFormat ) const
{
sal_uInt16 nRet = m_pStyles->GetSlot( pFormat );
- return ( nRet != 0x0fff ) ? nRet : 10; // Default Char Style
+ return ( nRet != 0x0fff ) ? nRet : WW8_RESERVED_SLOTS; // Default Char Style
}
// GetId( SwTextFormatColl ) for use in TextNodes -> zero is not allowed,
@@ -151,16 +152,11 @@ MSWordStyles::MSWordStyles( MSWordExportBase& rExport, bool bListStyles )
m_rExport.m_rDoc.GetFootnoteInfo().GetAnchorCharFormat( m_rExport.m_rDoc );
m_rExport.m_rDoc.GetFootnoteInfo().GetCharFormat( m_rExport.m_rDoc );
}
- sal_uInt32 nAlloc = WW8_RESERVED_SLOTS + m_rExport.m_rDoc.GetCharFormats()->size() - 1 +
- m_rExport.m_rDoc.GetTextFormatColls()->size() - 1 +
- (bListStyles ? m_rExport.m_rDoc.GetNumRuleTable().size() - 1 : 0);
- nAlloc = std::min<sal_uInt32>(nAlloc, MSWORD_MAX_STYLES_LIMIT);
- // somewhat generous ( free for up to 15 )
- m_aFormatA.resize(nAlloc, nullptr);
memset( m_aHeadingParagraphStyles, -1 , MAXLEVEL * sizeof( sal_uInt16));
BuildStylesTable();
+ BuildWwNames();
BuildStyleIds();
}
@@ -171,21 +167,19 @@ MSWordStyles::~MSWordStyles()
// Sty_SetWWSlot() dependencies for the styles -> zero is allowed
sal_uInt16 MSWordStyles::GetSlot( const SwFormat* pFormat ) const
{
- sal_uInt16 n;
- for ( n = 0; n < m_nUsedSlots; n++ )
- if ( m_aFormatA[n] == pFormat )
- return n;
+ for (size_t slot = 0; slot < m_aStyles.size(); ++slot)
+ if (m_aStyles[slot].format == pFormat)
+ return slot;
return 0xfff; // 0xfff: WW: zero
}
-sal_uInt16 MSWordStyles::BuildGetSlot( const SwFormat& rFormat )
+/// Get reserved slot number during building the style table.
+static sal_uInt16 BuildGetSlot(const SwFormat& rFormat)
{
- sal_uInt16 nRet = rFormat.GetPoolFormatId();
- switch ( nRet )
+ switch (sal_uInt16 nRet = rFormat.GetPoolFormatId())
{
case RES_POOLCOLL_STANDARD:
- nRet = 0;
- break;
+ return 0;
case RES_POOLCOLL_HEADLINE1:
case RES_POOLCOLL_HEADLINE2:
@@ -197,110 +191,117 @@ sal_uInt16 MSWordStyles::BuildGetSlot( const SwFormat& rFormat )
case RES_POOLCOLL_HEADLINE8:
case RES_POOLCOLL_HEADLINE9:
nRet -= RES_POOLCOLL_HEADLINE1-1;
- break;
-
- default:
- nRet = m_nUsedSlots++;
- break;
+ assert(nRet < WW8_RESERVED_SLOTS);
+ return nRet;
}
- return nRet;
+ return 0xfff;
}
+// Keep in sync with StyleSheetTable::ConvertStyleName
sal_uInt16 MSWordStyles::GetWWId( const SwFormat& rFormat )
{
sal_uInt16 nRet = ww::stiUser; // user style as default
sal_uInt16 nPoolId = rFormat.GetPoolFormatId();
if( nPoolId == RES_POOLCOLL_STANDARD )
- nRet = 0;
+ nRet = ww::stiNormal;
else if( nPoolId >= RES_POOLCOLL_HEADLINE1 &&
nPoolId <= RES_POOLCOLL_HEADLINE9 )
- nRet = static_cast< sal_uInt16 >(nPoolId + 1 - RES_POOLCOLL_HEADLINE1);
+ nRet = static_cast< sal_uInt16 >(nPoolId + ww::stiLevFirst - RES_POOLCOLL_HEADLINE1);
else if( nPoolId >= RES_POOLCOLL_TOX_IDX1 &&
nPoolId <= RES_POOLCOLL_TOX_IDX3 )
- nRet = static_cast< sal_uInt16 >(nPoolId + 10 - RES_POOLCOLL_TOX_IDX1);
+ nRet = static_cast< sal_uInt16 >(nPoolId + ww::stiIndexFirst - RES_POOLCOLL_TOX_IDX1);
else if( nPoolId >= RES_POOLCOLL_TOX_CNTNT1 &&
nPoolId <= RES_POOLCOLL_TOX_CNTNT5 )
- nRet = static_cast< sal_uInt16 >(nPoolId + 19 - RES_POOLCOLL_TOX_CNTNT1);
+ nRet = static_cast< sal_uInt16 >(nPoolId + ww::stiToc1 - RES_POOLCOLL_TOX_CNTNT1);
else if( nPoolId >= RES_POOLCOLL_TOX_CNTNT6 &&
nPoolId <= RES_POOLCOLL_TOX_CNTNT9 )
- nRet = static_cast< sal_uInt16 >(nPoolId + 24 - RES_POOLCOLL_TOX_CNTNT6);
+ nRet = static_cast< sal_uInt16 >(nPoolId + ww::stiToc6 - RES_POOLCOLL_TOX_CNTNT6);
else
switch( nPoolId )
{
- case RES_POOLCOLL_FOOTNOTE: nRet = 29; break;
- case RES_POOLCOLL_MARGINAL: nRet = 30; break;
- case RES_POOLCOLL_HEADER: nRet = 31; break;
- case RES_POOLCOLL_FOOTER: nRet = 32; break;
- case RES_POOLCOLL_TOX_IDXH: nRet = 33; break;
- case RES_POOLCOLL_LABEL: nRet = 34; break;
- case RES_POOLCOLL_LABEL_DRAWING: nRet = 35; break;
- case RES_POOLCOLL_ENVELOPE_ADDRESS: nRet = 36; break;
- case RES_POOLCOLL_SEND_ADDRESS: nRet = 37; break;
- case RES_POOLCOLL_ENDNOTE: nRet = 43; break;
- case RES_POOLCOLL_TOX_AUTHORITIESH: nRet = 44; break;
- case RES_POOLCOLL_TOX_CNTNTH: nRet = 46; break;
- case RES_POOLCOLL_BULLET_LEVEL1: nRet = 48; break;
- case RES_POOLCOLL_LISTS_BEGIN: nRet = 47; break;
- case RES_POOLCOLL_NUM_LEVEL1: nRet = 49; break;
- case RES_POOLCOLL_BULLET_LEVEL2: nRet = 54; break;
- case RES_POOLCOLL_BULLET_LEVEL3: nRet = 55; break;
- case RES_POOLCOLL_BULLET_LEVEL4: nRet = 56; break;
- case RES_POOLCOLL_BULLET_LEVEL5: nRet = 57; break;
- case RES_POOLCOLL_NUM_LEVEL2: nRet = 58; break;
- case RES_POOLCOLL_NUM_LEVEL3: nRet = 59; break;
- case RES_POOLCOLL_NUM_LEVEL4: nRet = 60; break;
- case RES_POOLCOLL_NUM_LEVEL5: nRet = 61; break;
- case RES_POOLCOLL_DOC_TITLE: nRet = 62; break;
- case RES_POOLCOLL_DOC_APPENDIX: nRet = 63; break;
- case RES_POOLCOLL_SIGNATURE: nRet = 64; break;
- case RES_POOLCOLL_TEXT: nRet = 66; break;
- case RES_POOLCOLL_TEXT_MOVE: nRet = 67; break;
- case RES_POOLCOLL_BULLET_NONUM1: nRet = 68; break;
- case RES_POOLCOLL_BULLET_NONUM2: nRet = 69; break;
- case RES_POOLCOLL_BULLET_NONUM3: nRet = 70; break;
- case RES_POOLCOLL_BULLET_NONUM4: nRet = 71; break;
- case RES_POOLCOLL_BULLET_NONUM5: nRet = 72; break;
- case RES_POOLCOLL_DOC_SUBTITLE: nRet = 74; break;
- case RES_POOLCOLL_GREETING: nRet = 75; break;
- case RES_POOLCOLL_TEXT_IDENT: nRet = 77; break;
-
- case RES_POOLCHR_FOOTNOTE_ANCHOR: nRet = 38; break;
- case RES_POOLCHR_ENDNOTE_ANCHOR: nRet = 42; break;
- case RES_POOLCHR_INET_NORMAL: nRet = 85; break;
- case RES_POOLCHR_INET_VISIT: nRet = 86; break;
- case RES_POOLCHR_HTML_STRONG: nRet = 87; break;
- case RES_POOLCHR_HTML_EMPHASIS: nRet = 88; break;
- case RES_POOLCHR_LINENUM: nRet = 40; break;
- case RES_POOLCHR_PAGENO: nRet = 41; break;
+ case RES_POOLCOLL_FOOTNOTE: nRet = ww::stiFootnoteText; break;
+ case RES_POOLCOLL_MARGINAL: nRet = ww::stiAtnText; break;
+ case RES_POOLCOLL_HEADER: nRet = ww::stiHeader; break;
+ case RES_POOLCOLL_FOOTER: nRet = ww::stiFooter; break;
+ case RES_POOLCOLL_TOX_IDXH: nRet = ww::stiIndexHeading; break;
+ case RES_POOLCOLL_LABEL: nRet = ww::stiCaption; break;
+ case RES_POOLCOLL_LABEL_DRAWING: nRet = ww::stiToCaption; break;
+ case RES_POOLCOLL_ENVELOPE_ADDRESS: nRet = ww::stiEnvAddr; break;
+ case RES_POOLCOLL_SEND_ADDRESS: nRet = ww::stiEnvRet; break;
+ case RES_POOLCHR_FOOTNOTE_ANCHOR: nRet = ww::stiFootnoteRef; break;
+ case RES_POOLCHR_LINENUM: nRet = ww::stiLnn; break;
+ case RES_POOLCHR_PAGENO: nRet = ww::stiPgn; break;
+ case RES_POOLCHR_ENDNOTE_ANCHOR: nRet = ww::stiEdnRef; break;
+ case RES_POOLCOLL_ENDNOTE: nRet = ww::stiEdnText; break;
+ case RES_POOLCOLL_TOX_AUTHORITIESH: nRet = ww::stiToa; break;
+ case RES_POOLCOLL_TOX_CNTNTH: nRet = ww::stiToaHeading; break;
+ case RES_POOLCOLL_LISTS_BEGIN: nRet = ww::stiList; break;
+ case RES_POOLCOLL_BULLET_LEVEL1: nRet = ww::stiListBullet; break;
+ case RES_POOLCOLL_NUM_LEVEL1: nRet = ww::stiListNumber; break;
+ case RES_POOLCOLL_BULLET_LEVEL2: nRet = ww::stiListBullet2; break;
+ case RES_POOLCOLL_BULLET_LEVEL3: nRet = ww::stiListBullet3; break;
+ case RES_POOLCOLL_BULLET_LEVEL4: nRet = ww::stiListBullet4; break;
+ case RES_POOLCOLL_BULLET_LEVEL5: nRet = ww::stiListBullet5; break;
+ case RES_POOLCOLL_NUM_LEVEL2: nRet = ww::stiListNumber2; break;
+ case RES_POOLCOLL_NUM_LEVEL3: nRet = ww::stiListNumber3; break;
+ case RES_POOLCOLL_NUM_LEVEL4: nRet = ww::stiListNumber4; break;
+ case RES_POOLCOLL_NUM_LEVEL5: nRet = ww::stiListNumber5; break;
+ case RES_POOLCOLL_DOC_TITLE: nRet = ww::stiTitle; break;
+ case RES_POOLCOLL_DOC_APPENDIX: nRet = ww::stiClosing; break;
+ case RES_POOLCOLL_SIGNATURE: nRet = ww::stiSignature; break;
+ case RES_POOLCOLL_TEXT: nRet = ww::stiBodyText; break;
+ case RES_POOLCOLL_TEXT_MOVE: nRet = ww::stiBodyTextInd1; break;
+ case RES_POOLCOLL_BULLET_NONUM1: nRet = ww::stiListCont; break;
+ case RES_POOLCOLL_BULLET_NONUM2: nRet = ww::stiListCont2; break;
+ case RES_POOLCOLL_BULLET_NONUM3: nRet = ww::stiListCont3; break;
+ case RES_POOLCOLL_BULLET_NONUM4: nRet = ww::stiListCont4; break;
+ case RES_POOLCOLL_BULLET_NONUM5: nRet = ww::stiListCont5; break;
+ case RES_POOLCOLL_DOC_SUBTITLE: nRet = ww::stiSubtitle; break;
+ case RES_POOLCOLL_GREETING: nRet = ww::stiSalutation; break;
+ case RES_POOLCOLL_TEXT_IDENT: nRet = ww::stiBodyText1I; break;
+ case RES_POOLCHR_INET_NORMAL: nRet = ww::stiHyperlink; break;
+ case RES_POOLCHR_INET_VISIT: nRet = ww::stiHyperlinkFollowed; break;
+ case RES_POOLCHR_HTML_STRONG: nRet = ww::stiStrong; break;
+ case RES_POOLCHR_HTML_EMPHASIS: nRet = ww::stiEmphasis; break;
}
return nRet;
}
void MSWordStyles::BuildStylesTable()
{
- m_nUsedSlots = WW8_RESERVED_SLOTS; // reserved slots for standard, headingX, and others
+ assert(m_aStyles.empty());
+ // Put reserved slots first, then character styles, then paragraph styles
+ m_aStyles.resize(WW8_RESERVED_SLOTS);
const SwCharFormats& rArr = *m_rExport.m_rDoc.GetCharFormats(); // first CharFormat
// the default character style ( 0 ) will not be outputted !
- for( size_t n = 1; n < rArr.size() && m_nUsedSlots < MSWORD_MAX_STYLES_LIMIT; n++ )
- {
- SwCharFormat* pFormat = rArr[n];
- m_aFormatA[ BuildGetSlot( *pFormat ) ] = pFormat;
- }
+ for (size_t n = 1; n < rArr.size() && m_aStyles.size() < MSWORD_MAX_STYLES_LIMIT; ++n)
+ m_aStyles.emplace_back(rArr[n]);
const SwTextFormatColls& rArr2 = *m_rExport.m_rDoc.GetTextFormatColls(); // then TextFormatColls
- // the default character style ( 0 ) will not be outputted !
- for( size_t n = 1; n < rArr2.size() && m_nUsedSlots < MSWORD_MAX_STYLES_LIMIT; n++ )
+ // the default paragraph style ( 0 ) will not be outputted !
+ for (size_t n = 1; n < rArr2.size(); ++n)
{
SwTextFormatColl* pFormat = rArr2[n];
- sal_uInt16 nId = BuildGetSlot( *pFormat ) ;
- m_aFormatA[ nId ] = pFormat;
+
+ sal_uInt16 nSlot = BuildGetSlot(*pFormat);
+ if (nSlot != 0xfff)
+ {
+ m_aStyles[nSlot] = { pFormat };
+ }
+ else
+ {
+ if (m_aStyles.size() >= MSWORD_MAX_STYLES_LIMIT)
+ continue;
+ m_aStyles.emplace_back(pFormat);
+ nSlot = m_aStyles.size() - 1;
+ }
if ( pFormat->IsAssignedToListLevelOfOutlineStyle() )
{
int nLvl = pFormat->GetAssignedOutlineStyleLevel() ;
if (nLvl >= 0 && nLvl < MAXLEVEL)
- m_aHeadingParagraphStyles[nLvl] = nId ;
+ m_aHeadingParagraphStyles[nLvl] = nSlot;
}
}
@@ -308,17 +309,77 @@ void MSWordStyles::BuildStylesTable()
return;
const SwNumRuleTable& rNumRuleTable = m_rExport.m_rDoc.GetNumRuleTable();
- for (size_t i = 0; i < rNumRuleTable.size() && m_nUsedSlots < MSWORD_MAX_STYLES_LIMIT; ++i)
+ for (size_t i = 0; i < rNumRuleTable.size() && m_aStyles.size() < MSWORD_MAX_STYLES_LIMIT; ++i)
{
const SwNumRule* pNumRule = rNumRuleTable[i];
if (pNumRule->IsAutoRule() || pNumRule->GetName().startsWith("WWNum"))
continue;
- sal_uInt16 nSlot = BuildGetSlot(*pNumRule);
- m_aNumRules[nSlot] = pNumRule;
+ m_aStyles.emplace_back(pNumRule);
+ }
+}
+
+// StyleSheetTable::ConvertStyleName appends the suffix do disambiguate conflicting style names
+static OUString StripWWSuffix(const OUString& s)
+{
+ OUString ret = s;
+ ret.endsWith(" (WW)", &ret);
+ return ret;
+}
+
+void MSWordStyles::BuildWwNames()
+{
+ std::unordered_set<OUString> aUsed;
+
+ auto makeUniqueName = [&aUsed](OUString& name) {
+ // toAsciiLowerCase rules out e.g. user's "normal"; no problem if there are non-ASCII chars
+ OUString lower(name.toAsciiLowerCase());
+ if (!aUsed.insert(lower).second)
+ {
+ int nFree = 1;
+ while (!aUsed.insert(lower + OUString::number(nFree)).second)
+ ++nFree;
+
+ name += OUString::number(nFree);
+ }
+ };
+
+ // We want to map LO's default style to Word's "Normal" style.
+ // Word looks for this specific style name when reading docx files.
+ // (It must be the English word regardless of language settings)
+ assert(!m_aStyles.empty());
+ assert(!m_aStyles[0].format || m_aStyles[0].ww_id == ww::stiNormal);
+ m_aStyles[0].ww_name = "Normal";
+ aUsed.insert("normal");
+
+ // 1. Handle styles having special wwIds, and thus pre-defined names
+ for (auto& entry : m_aStyles)
+ {
+ if (!entry.ww_name.isEmpty())
+ continue; // "Normal" is already added
+ if (entry.ww_id >= ww::stiMax)
+ continue; // Not a format with special name
+ assert(entry.format);
+
+ entry.ww_name = OUString::createFromAscii(ww::GetEnglishNameFromSti(static_cast<ww::sti>(entry.ww_id)));
+ makeUniqueName(entry.ww_name);
+ }
+
+ // 2. Now handle other styles
+ for (auto& entry : m_aStyles)
+ {
+ if (!entry.ww_name.isEmpty())
+ continue;
+ if (entry.format)
+ entry.ww_name = StripWWSuffix(entry.format->GetName());
+ else if (entry.num_rule)
+ entry.ww_name = StripWWSuffix(entry.num_rule->GetName());
+ else
+ continue;
+ makeUniqueName(entry.ww_name);
}
}
-OString MSWordStyles::CreateStyleId(const OUString &rName)
+OString MSWordStyles::CreateStyleId(const OUString& rName)
{
OStringBuffer aStyleIdBuf(rName.getLength());
for (int i = 0; i < rName.getLength(); ++i)
@@ -342,18 +403,9 @@ void MSWordStyles::BuildStyleIds()
{
std::unordered_set<OString> aUsed;
- m_aStyleIds.emplace_back("Normal");
- aUsed.insert("normal");
-
- for (sal_uInt16 n = 1; n < m_nUsedSlots; ++n)
+ for (auto& entry : m_aStyles)
{
- OUString aName;
- if (m_aFormatA[n])
- aName = m_aFormatA[n]->GetName();
- else if (m_aNumRules.find(n) != m_aNumRules.end())
- aName = m_aNumRules[n]->GetName();
-
- OString aStyleId = CreateStyleId(aName);
+ OString aStyleId = CreateStyleId(entry.ww_name);
if (aStyleId.isEmpty())
aStyleId = "Style";
@@ -361,24 +413,22 @@ void MSWordStyles::BuildStyleIds()
OString aLower(aStyleId.toAsciiLowerCase());
// check for uniqueness & construct something unique if we have to
- if (aUsed.insert(aLower).second)
- {
- m_aStyleIds.push_back(aStyleId);
- }
- else
+ if (!aUsed.insert(aLower).second)
{
int nFree = 1;
while (!aUsed.insert(aLower + OString::number(nFree)).second)
++nFree;
- m_aStyleIds.emplace_back(aStyleId + OString::number(nFree));
+ aStyleId += OString::number(nFree);
}
+ entry.style_id = aStyleId;
}
}
-OString const & MSWordStyles::GetStyleId(sal_uInt16 nId) const
+OString const & MSWordStyles::GetStyleId(sal_uInt16 nSlot) const
{
- return m_aStyleIds[nId];
+ assert(!m_aStyles[nSlot].style_id.isEmpty());
+ return m_aStyles[nSlot].style_id;
}
/// For WW8 only - extend pO so that the size of pTableStrm is even.
@@ -403,7 +453,7 @@ void WW8AttributeOutput::EndStyle()
}
void WW8AttributeOutput::StartStyle( const OUString& rName, StyleType eType, sal_uInt16 nWwBase,
- sal_uInt16 nWwNext, sal_uInt16 /*nWwLink*/, sal_uInt16 nWwId, sal_uInt16 /*nId*/, bool bAutoUpdate )
+ sal_uInt16 nWwNext, sal_uInt16 /*nWwLink*/, sal_uInt16 nWwId, sal_uInt16 /*nSlot*/, bool bAutoUpdate )
{
sal_uInt8 aWW8_STD[ sizeof( WW8_STD ) ] = {};
sal_uInt8* pData = aWW8_STD;
@@ -549,7 +599,7 @@ void WW8AttributeOutput::EndStyleProperties( bool /*bParProp*/ )
ShortToSVBT16( nLen, pUpxLen ); // add default length
}
-void MSWordStyles::GetStyleData( SwFormat* pFormat, bool& bFormatColl, sal_uInt16& nBase, sal_uInt16& nNext, sal_uInt16& nLink )
+void MSWordStyles::GetStyleData( const SwFormat* pFormat, bool& bFormatColl, sal_uInt16& nBase, sal_uInt16& nNext, sal_uInt16& nLink )
{
bFormatColl = pFormat->Which() == RES_TXTFMTCOLL || pFormat->Which() == RES_CONDTXTFMTCOLL;
@@ -560,18 +610,18 @@ void MSWordStyles::GetStyleData( SwFormat* pFormat, bool& bFormatColl, sal_uInt1
if ( !pFormat->IsDefault() )
nBase = GetSlot( pFormat->DerivedFrom() );
- SwFormat* pNext;
+ const SwFormat* pNext;
const SwFormat* pLink = nullptr;
if ( bFormatColl )
{
- auto pFormatColl = static_cast<SwTextFormatColl*>(pFormat);
+ auto pFormatColl = static_cast<const SwTextFormatColl*>(pFormat);
pNext = &pFormatColl->GetNextTextFormatColl();
pLink = pFormatColl->GetLinkedCharFormat();
}
else
{
pNext = pFormat; // CharFormat: next CharFormat == self
- auto pCharFormat = static_cast<SwCharFormat*>(pFormat);
+ auto pCharFormat = static_cast<const SwCharFormat*>(pFormat);
pLink = pCharFormat->GetLinkedParaFormat();
}
@@ -588,81 +638,45 @@ void WW8AttributeOutput::DefaultStyle()
m_rWW8Export.pTableStrm->WriteUInt16(0); // empty Style
}
-void MSWordStyles::OutputStyle(const SwNumRule* pNumRule, sal_uInt16 nPos)
+void MSWordStyles::OutputStyle(sal_uInt16 nSlot)
{
- m_rExport.AttrOutput().StartStyle( pNumRule->GetName(), STYLE_TYPE_LIST,
- /*nBase =*/ 0, /*nWwNext =*/ 0, /*nWwLink =*/ 0, /*nWWId =*/ 0, nPos,
- /*bAutoUpdateFormat =*/ false );
+ const auto& entry = m_aStyles[nSlot];
- m_rExport.AttrOutput().EndStyle();
-}
+ if (entry.num_rule)
+ {
+ m_rExport.AttrOutput().StartStyle( entry.ww_name, STYLE_TYPE_LIST,
+ /*nBase =*/ 0, /*nWwNext =*/ 0, /*nWwLink =*/ 0, /*nWWId =*/ 0, nSlot,
+ /*bAutoUpdateFormat =*/ false );
-// OutputStyle applies for TextFormatColls and CharFormats
-void MSWordStyles::OutputStyle( SwFormat* pFormat, sal_uInt16 nPos )
-{
- if ( !pFormat )
+ m_rExport.AttrOutput().EndStyle();
+ }
+ else if (!entry.format)
+ {
m_rExport.AttrOutput().DefaultStyle();
+ }
else
{
bool bFormatColl;
sal_uInt16 nBase, nWwNext;
sal_uInt16 nWwLink = 0x0FFF;
- GetStyleData(pFormat, bFormatColl, nBase, nWwNext, nWwLink);
+ GetStyleData(entry.format, bFormatColl, nBase, nWwNext, nWwLink);
- OUString aName = pFormat->GetName();
- // We want to map LO's default style to Word's "Normal" style.
- // Word looks for this specific style name when reading docx files.
- // (It must be the English word regardless of language settings)
- if ( nPos == 0 )
- {
- assert( pFormat->GetPoolFormatId() == RES_POOLCOLL_STANDARD );
- aName = "Normal";
- }
- else if (aName.equalsIgnoreAsciiCase("Normal"))
- {
- // If LO has a style named "Normal"(!) rename it to something unique
- const OUString aBaseName = "LO-" + aName;
- aName = aBaseName;
- // Check if we still have a clash, in which case we add a suffix
- for ( int nSuffix = 0; ; ++nSuffix ) {
- bool clash=false;
- for ( sal_uInt16 n = 1; n < m_nUsedSlots; ++n )
- if ( m_aFormatA[n] &&
- m_aFormatA[n]->GetName().equalsIgnoreAsciiCase(aName) )
- {
- clash = true;
- break;
- }
- if (!clash)
- break;
- // TODO: verify if we really need to increment nSuffix in 2 places
- aName = aBaseName + OUString::number(++nSuffix);
- }
- }
- else if (!bFormatColl && m_rExport.GetExportFormat() == MSWordExportBase::DOCX &&
- m_rExport.m_pStyles->GetStyleId(nPos).startsWith("ListLabel"))
+ if (!bFormatColl && m_rExport.GetExportFormat() == MSWordExportBase::DOCX &&
+ entry.style_id.startsWith("ListLabel"))
{
// tdf#92335 don't export redundant DOCX import style "ListLabel"
return;
}
- else if (aName.equalsIgnoreAsciiCase("Internet Link"))
- {
- aName = "Hyperlink";
- }
- else if (aName.equalsIgnoreAsciiCase("Visited Internet Link"))
- {
- aName = "FollowedHyperlink";
- }
- m_rExport.AttrOutput().StartStyle( aName, (bFormatColl ? STYLE_TYPE_PARA : STYLE_TYPE_CHAR),
- nBase, nWwNext, nWwLink, GetWWId( *pFormat ), nPos,
- pFormat->IsAutoUpdateFormat() );
+ m_rExport.AttrOutput().StartStyle(entry.ww_name, (bFormatColl ? STYLE_TYPE_PARA : STYLE_TYPE_CHAR),
+ nBase, nWwNext, nWwLink, m_aStyles[nSlot].ww_id, nSlot,
+ entry.format->IsAutoUpdateFormat() );
if ( bFormatColl )
- WriteProperties( pFormat, true, nPos, nBase==0xfff ); // UPX.papx
+ WriteProperties( entry.format, true, nSlot, nBase==0xfff ); // UPX.papx
- WriteProperties( pFormat, false, nPos, bFormatColl && nBase==0xfff ); // UPX.chpx
+ WriteProperties( entry.format, false, nSlot, bFormatColl && nBase==0xfff ); // UPX.chpx
m_rExport.AttrOutput().EndStyle();
}
@@ -704,35 +718,20 @@ void MSWordStyles::OutputStylesTable()
m_rExport.AttrOutput().StartStyles();
- sal_uInt16 n;
// HACK
// Ms Office seems to have an internal limitation of 4091 styles
// and refuses to load .docx with more, even though the spec seems to allow that;
// so simply if there are more styles, don't export those
// Implementing check for all exports DOCX, DOC, RTF
- sal_uInt16 const nLimit = MSWORD_MAX_STYLES_LIMIT;
- m_nUsedSlots = std::min(nLimit, m_nUsedSlots);
-
- for ( n = 0; n < m_nUsedSlots; n++ )
- {
- if (m_aNumRules.find(n) != m_aNumRules.end())
- OutputStyle(m_aNumRules[n], n);
- else
- OutputStyle(m_aFormatA[n], n);
- }
+ assert(m_aStyles.size() <= MSWORD_MAX_STYLES_LIMIT);
+ for (size_t slot = 0; slot < m_aStyles.size(); ++slot)
+ OutputStyle(slot);
- m_rExport.AttrOutput().EndStyles( m_nUsedSlots );
+ m_rExport.AttrOutput().EndStyles(m_aStyles.size());
m_rExport.m_bStyDef = false;
}
-const SwNumRule* MSWordStyles::GetSwNumRule(sal_uInt16 nId) const
-{
- std::map<sal_uInt16, const SwNumRule*>::const_iterator it = m_aNumRules.find(nId);
- assert(it != m_aNumRules.end());
- return it->second;
-}
-
// Fonts
wwFont::wwFont(const OUString &rFamilyName, FontPitch ePitch, FontFamily eFamily,
@@ -1649,12 +1648,15 @@ void MSWordExportBase::SectionProperties( const WW8_SepInfo& rSepInfo, WW8_PdAtt
// 0xfff -> Section terminated
nBreakCode = 0; // consecutive section
- if ( rSepInfo.pPDNd && rSepInfo.pPDNd->IsContentNode() )
+ if (rSepInfo.pPDNd && (rSepInfo.pPDNd->IsContentNode() || rSepInfo.pPDNd->IsTableNode()))
{
- if ( !NoPageBreakSection( &rSepInfo.pPDNd->GetContentNode()->GetSwAttrSet() ) )
- {
+ const SfxItemSet* pSet
+ = rSepInfo.pPDNd->IsContentNode()
+ ? &rSepInfo.pPDNd->GetContentNode()->GetSwAttrSet()
+ : &rSepInfo.pPDNd->GetTableNode()->GetTable().GetFrameFormat()->GetAttrSet();
+
+ if (!NoPageBreakSection(pSet))
nBreakCode = 2;
- }
}
if ( reinterpret_cast<SwSectionFormat*>(sal_IntPtr(-1)) == rSepInfo.pSectionFormat )
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index d179858fd3f3..1eba84327404 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -4095,15 +4095,9 @@ void WW8Export::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
if ( rFieldmark.GetFieldname() == ODF_FORMDROPDOWN )
type=2;
- ::sw::mark::IFieldmark::parameter_map_t::const_iterator pParameter = rFieldmark.GetParameters()->find("name");
- OUString ffname;
- if ( pParameter != rFieldmark.GetParameters()->end() )
- {
- OUString aName;
- pParameter->second >>= aName;
- const sal_Int32 nLen = std::min( sal_Int32(20), aName.getLength() );
- ffname = aName.copy(0, nLen);
- }
+ OUString ffname = rFieldmark.GetName();
+ if (ffname.getLength() > 20)
+ ffname = ffname.copy(0, 20);
sal_uInt64 nDataStt = pDataStrm->Tell();
m_pChpPlc->AppendFkpEntry(Strm().Tell());
@@ -4155,10 +4149,12 @@ void WW8Export::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
OUString ffstattext;
OUString ffentrymcr;
OUString ffexitmcr;
+
+ ::sw::mark::IFieldmark::parameter_map_t::const_iterator pParameter
+ = rFieldmark.GetParameters()->find("Type");
if (type == 0) // iTypeText
{
sal_uInt16 nType = 0;
- pParameter = rFieldmark.GetParameters()->find("Type");
if ( pParameter != rFieldmark.GetParameters()->end() )
{
OUString aType;
diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx
index ef10e2a9a384..2c79ae8e70c8 100644
--- a/sw/source/filter/ww8/wrtww8.hxx
+++ b/sw/source/filter/ww8/wrtww8.hxx
@@ -1571,26 +1571,34 @@ class MSWordStyles
{
MSWordExportBase& m_rExport;
sal_uInt16 m_aHeadingParagraphStyles[MAXLEVEL];
- std::vector<SwFormat*> m_aFormatA; ///< Slot <-> Character and paragraph style array (0 for list styles).
- sal_uInt16 m_nUsedSlots;
- bool m_bListStyles; ///< If list styles are requested to be exported as well.
- std::map<sal_uInt16, const SwNumRule*> m_aNumRules; ///< Slot <-> List style map.
- /// We need to build style id's for DOCX export; ideally we should roundtrip that, but this is good enough.
- std::vector<OString> m_aStyleIds;
+ struct MapEntry
+ {
+ const SwFormat* format = nullptr;
+ const SwNumRule* num_rule = nullptr;
+ /// We need to build style id's for DOCX export; ideally we should roundtrip that, but this is good enough.
+ sal_uInt16 ww_id = ww::stiUser;
+ OUString ww_name;
+ OString style_id;
+
+ MapEntry() = default;
+ MapEntry(const SwFormat* f) : format(f) { if (f) ww_id = GetWWId(*f); }
+ MapEntry(const SwNumRule* r) : num_rule(r) {}
+ };
+ std::vector<MapEntry> m_aStyles; ///< Slot <-> Character/paragraph/list style array.
+ bool m_bListStyles; ///< If list styles are requested to be exported as well.
/// Create the style table, called from the constructor.
void BuildStylesTable();
- /// Based on pFormatA, fill in m_aStyleIds with unique, MS-like names.
- void BuildStyleIds();
+ /// Generate proper Word names, taking mapping between special types into account
+ void BuildWwNames();
- /// Get slot number during building the style table.
- sal_uInt16 BuildGetSlot( const SwFormat& rFormat );
- sal_uInt16 BuildGetSlot( const SwNumRule& /*rNumRule*/ ) { return m_nUsedSlots++;}
+ /// Based on style names, fill in unique, MS-like names.
+ void BuildStyleIds();
/// Return information about one style.
- void GetStyleData( SwFormat* pFormat, bool& bFormatColl, sal_uInt16& nBase, sal_uInt16& nNext, sal_uInt16& nLink );
+ void GetStyleData( const SwFormat* pFormat, bool& bFormatColl, sal_uInt16& nBase, sal_uInt16& nNext, sal_uInt16& nLink );
/// Outputs attributes of one style.
void WriteProperties( const SwFormat* pFormat, bool bPap, sal_uInt16 nPos, bool bInsDefCharSiz );
@@ -1600,8 +1608,7 @@ class MSWordStyles
void SetStyleDefaults( const SwFormat& rFormat, bool bPap );
/// Outputs one style - called (in a loop) from OutputStylesTable().
- void OutputStyle( SwFormat* pFormat, sal_uInt16 nPos );
- void OutputStyle( const SwNumRule* pNumRule, sal_uInt16 nPos );
+ void OutputStyle( sal_uInt16 nSlot );
MSWordStyles( const MSWordStyles& ) = delete;
MSWordStyles& operator=( const MSWordStyles& ) = delete;
@@ -1613,18 +1620,18 @@ public:
/// Output the styles table.
void OutputStylesTable();
- /// Get id of the style (rFormat).
+ /// Get slot of the style (rFormat).
sal_uInt16 GetSlot( const SwFormat* pFormat ) const;
/// create style id using only ASCII characters of the style name
static OString CreateStyleId(const OUString &rName);
- /// Get styleId of the nId-th style (nId is its position in pFormatA).
- OString const & GetStyleId(sal_uInt16 nId) const;
+ /// Get styleId of the nSlot-th style (nSlot is its position in m_aStyles).
+ OString const & GetStyleId(sal_uInt16 nSlot) const;
- const SwFormat* GetSwFormat(sal_uInt16 nId) const { return m_aFormatA[nId]; }
- /// Get numbering rule of the nId-th style
- const SwNumRule* GetSwNumRule(sal_uInt16 nId) const;
+ const SwFormat* GetSwFormat(sal_uInt16 nSlot) const { return m_aStyles[nSlot].format; }
+ /// Get numbering rule of the nSlot-th style
+ const SwNumRule* GetSwNumRule(sal_uInt16 nSlot) const { return m_aStyles[nSlot].num_rule; }
sal_uInt16 GetHeadingParagraphStyleId(sal_uInt16 nLevel) const { return m_aHeadingParagraphStyles[ nLevel ]; }
};
diff --git a/sw/source/filter/ww8/ww8atr.cxx b/sw/source/filter/ww8/ww8atr.cxx
index 1b6c22f26d00..b406a1149150 100644
--- a/sw/source/filter/ww8/ww8atr.cxx
+++ b/sw/source/filter/ww8/ww8atr.cxx
@@ -1087,7 +1087,7 @@ void WW8AttributeOutput::OnTOXEnding()
mbOnTOXEnding = true;
}
-void WW8AttributeOutput::EndRun( const SwTextNode* /*pNode*/, sal_Int32 nPos, bool bLastRun )
+void WW8AttributeOutput::EndRun( const SwTextNode* /*pNode*/, sal_Int32 nPos, sal_Int32 /*nLen*/, bool bLastRun )
{
/// Insert bookmarks ended after this run
auto aRange = m_aBookmarksOfParagraphEnd.equal_range(nPos);
@@ -1121,7 +1121,7 @@ void WW8AttributeOutput::EndRunProperties( const SwRedlineData* pRedlineData )
m_rWW8Export.pO->clear();
}
-void WW8AttributeOutput::RunText( const OUString& rText, rtl_TextEncoding eCharSet )
+void WW8AttributeOutput::RunText( const OUString& rText, rtl_TextEncoding eCharSet, const OUString& /*rSymbolFont*/ )
{
RawText(rText, eCharSet);
}
@@ -2561,7 +2561,7 @@ void AttributeOutputBase::StartTOX( const SwSection& rSect )
FieldFlags::CmdEnd );
if (GetExport().GetExportFormat() == MSWordExportBase::ExportFormat::RTF)
{
- EndRun(nullptr, -42, true);
+ EndRun(nullptr, -42, -1, true);
}
}
}
diff --git a/sw/source/filter/ww8/ww8attributeoutput.hxx b/sw/source/filter/ww8/ww8attributeoutput.hxx
index f459a7bf8a9c..5b8d434c9d42 100644
--- a/sw/source/filter/ww8/ww8attributeoutput.hxx
+++ b/sw/source/filter/ww8/ww8attributeoutput.hxx
@@ -58,7 +58,7 @@ public:
/// End of the text run.
///
/// No-op for binary filters.
- virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, bool bLastRun = false) override;
+ virtual void EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_Int32 nLen, bool bLastRun = false) override;
/// Before we start outputting the attributes.
virtual void StartRunProperties() override;
@@ -67,7 +67,7 @@ public:
virtual void EndRunProperties( const SwRedlineData* pRedlineData ) override;
/// Output text.
- virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8 ) override;
+ virtual void RunText( const OUString& rText, rtl_TextEncoding eCharSet = RTL_TEXTENCODING_UTF8, const OUString& rSymbolFont = OUString() ) override;
/// Output text (without markup).
virtual void RawText(const OUString& rText, rtl_TextEncoding eCharSet) override;
@@ -126,7 +126,7 @@ public:
/// Start of a style in the styles table.
virtual void StartStyle( const OUString& rName, StyleType eType,
- sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 nLink, sal_uInt16 nWwIdi, sal_uInt16 nId,
+ sal_uInt16 nBase, sal_uInt16 nNext, sal_uInt16 nLink, sal_uInt16 nWwIdi, sal_uInt16 nSlot,
bool bAutoUpdate ) override;
/// End of a style in the styles table.
diff --git a/sw/source/filter/ww8/ww8par3.cxx b/sw/source/filter/ww8/ww8par3.cxx
index aab719c99d7d..89eb9833491c 100644
--- a/sw/source/filter/ww8/ww8par3.cxx
+++ b/sw/source/filter/ww8/ww8par3.cxx
@@ -231,7 +231,6 @@ eF_ResT SwWW8ImplReader::Read_F_FormCheckBox( WW8FieldDesc* pF, OUString& rStr )
if (pFieldmark!=nullptr) {
IFieldmark::parameter_map_t* const pParameters = pFieldmark->GetParameters();
ICheckboxFieldmark* pCheckboxFm = dynamic_cast<ICheckboxFieldmark*>(pFieldmark);
- (*pParameters)[ODF_FORMCHECKBOX_NAME] <<= aFormula.msTitle;
(*pParameters)[ODF_FORMCHECKBOX_HELPTEXT] <<= aFormula.msToolTip;
if(pCheckboxFm)
diff --git a/sw/source/filter/xml/xmlexp.hxx b/sw/source/filter/xml/xmlexp.hxx
index 53ab4431c645..86b919ac95a7 100644
--- a/sw/source/filter/xml/xmlexp.hxx
+++ b/sw/source/filter/xml/xmlexp.hxx
@@ -24,6 +24,7 @@
#include "xmlitmap.hxx"
#include <xmloff/xmltoken.hxx>
+#include <optional>
#include <string_view>
#include <vector>
@@ -75,7 +76,8 @@ class SwXMLExport : public SvXMLExport
SwXMLTableInfo_Impl& rTableInfo,
bool bTop=false );
- void ExportFormat( const SwFormat& rFormat, enum ::xmloff::token::XMLTokenEnum eClass );
+ void ExportFormat(const SwFormat& rFormat, enum ::xmloff::token::XMLTokenEnum eClass,
+ ::std::optional<OUString> const oStyleName);
void ExportTableFormat( const SwFrameFormat& rFormat, sal_uInt32 nAbsWidth );
void ExportTableColumnStyle( const SwXMLTableColumn_Impl& rCol );
diff --git a/sw/source/filter/xml/xmlfmte.cxx b/sw/source/filter/xml/xmlfmte.cxx
index f7866c5290f8..0f38de983519 100644
--- a/sw/source/filter/xml/xmlfmte.cxx
+++ b/sw/source/filter/xml/xmlfmte.cxx
@@ -46,7 +46,8 @@ using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::lang;
using namespace ::xmloff::token;
-void SwXMLExport::ExportFormat( const SwFormat& rFormat, enum XMLTokenEnum eFamily )
+void SwXMLExport::ExportFormat(const SwFormat& rFormat, enum XMLTokenEnum eFamily,
+ ::std::optional<OUString> const oStyleName)
{
// <style:style ...>
CheckAttrList();
@@ -57,11 +58,14 @@ void SwXMLExport::ExportFormat( const SwFormat& rFormat, enum XMLTokenEnum eFami
return;
OSL_ENSURE( eFamily != XML_TOKEN_INVALID, "family must be specified" );
// style:name="..."
+ assert(oStyleName || (eFamily != XML_TABLE_ROW && eFamily != XML_TABLE_CELL));
bool bEncoded = false;
- AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, EncodeStyleName(
- rFormat.GetName(), &bEncoded ) );
+ OUString const name(oStyleName ? *oStyleName : rFormat.GetName());
+ AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, EncodeStyleName(name, &bEncoded));
if( bEncoded )
- AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, rFormat.GetName() );
+ {
+ AddAttribute(XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, name);
+ }
if( eFamily != XML_TOKEN_INVALID )
AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, eFamily );
diff --git a/sw/source/filter/xml/xmliteme.cxx b/sw/source/filter/xml/xmliteme.cxx
index d60cc12b7d12..5102b2462af8 100644
--- a/sw/source/filter/xml/xmliteme.cxx
+++ b/sw/source/filter/xml/xmliteme.cxx
@@ -245,7 +245,7 @@ void SwXMLExport::ExportTableFormat( const SwFrameFormat& rFormat, sal_uInt32 nA
{
static_cast<SwXMLTableItemMapper_Impl *>(m_pTableItemMapper.get())
->SetAbsWidth( nAbsWidth );
- ExportFormat( rFormat, XML_TABLE );
+ ExportFormat(rFormat, XML_TABLE, {});
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/xml/xmltble.cxx b/sw/source/filter/xml/xmltble.cxx
index 3a3409cd1b46..fae84d9be2c8 100644
--- a/sw/source/filter/xml/xmltble.cxx
+++ b/sw/source/filter/xml/xmltble.cxx
@@ -185,13 +185,18 @@ class SwXMLTableFrameFormatsSort_Impl
{
private:
SwXMLFrameFormats_Impl m_aFormatList;
+ SwXMLTextParagraphExport::FormatMap & m_rFormatMap;
+
public:
- bool AddRow( SwFrameFormat& rFrameFormat, std::u16string_view rNamePrefix, sal_uInt32 nLine );
- bool AddCell( SwFrameFormat& rFrameFormat, std::u16string_view rNamePrefix,
+ SwXMLTableFrameFormatsSort_Impl(SwXMLTextParagraphExport::FormatMap & rFormatMap)
+ : m_rFormatMap(rFormatMap)
+ {}
+ ::std::optional<OUString> AddRow(SwFrameFormat& rFrameFormat, std::u16string_view rNamePrefix, sal_uInt32 nLine );
+ ::std::optional<OUString> AddCell(SwFrameFormat& rFrameFormat, std::u16string_view rNamePrefix,
sal_uInt32 nCol, sal_uInt32 nRow, bool bTop );
};
-bool SwXMLTableFrameFormatsSort_Impl::AddRow( SwFrameFormat& rFrameFormat,
+::std::optional<OUString> SwXMLTableFrameFormatsSort_Impl::AddRow(SwFrameFormat& rFrameFormat,
std::u16string_view rNamePrefix,
sal_uInt32 nLine )
{
@@ -216,10 +221,12 @@ bool SwXMLTableFrameFormatsSort_Impl::AddRow( SwFrameFormat& rFrameFormat,
// empty styles have not to be exported
if( !pFrameSize && !pBrush && !pRowSplit && !pHasTextChangesOnly )
- return false;
+ {
+ m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>()); // empty just to enable assert
+ return {};
+ }
// order is: -/brush, size/-, size/brush
- bool bInsert = true;
SwXMLFrameFormats_Impl::iterator i;
for( i = m_aFormatList.begin(); i < m_aFormatList.end(); ++i )
{
@@ -300,19 +307,19 @@ bool SwXMLTableFrameFormatsSort_Impl::AddRow( SwFrameFormat& rFrameFormat,
continue;
// found!
- rFrameFormat.SetName( pTestFormat->GetName() );
- bInsert = false;
- break;
+ auto const oName(m_rFormatMap.find(pTestFormat)->second);
+ assert(oName);
+ m_rFormatMap.emplace(&rFrameFormat, oName);
+ return {};
}
- if( bInsert )
{
- rFrameFormat.SetName( OUString::Concat(rNamePrefix) + "." + OUString::number(nLine+1) );
+ OUString const name(OUString::Concat(rNamePrefix) + "." + OUString::number(nLine+1));
+ m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>(name));
if ( i != m_aFormatList.end() ) ++i;
m_aFormatList.insert( i, &rFrameFormat );
+ return ::std::optional<OUString>(name);
}
-
- return bInsert;
}
static OUString lcl_xmltble_appendBoxPrefix(std::u16string_view rNamePrefix,
@@ -329,7 +336,7 @@ static OUString lcl_xmltble_appendBoxPrefix(std::u16string_view rNamePrefix,
+ "." + OUString::number(nRow + 1);
}
-bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat& rFrameFormat,
+::std::optional<OUString> SwXMLTableFrameFormatsSort_Impl::AddCell(SwFrameFormat& rFrameFormat,
std::u16string_view rNamePrefix,
sal_uInt32 nCol, sal_uInt32 nRow, bool bTop )
{
@@ -364,7 +371,10 @@ bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat& rFrameFormat,
// empty styles have not to be exported
if( !pVertOrient && !pBrush && !pBox && !pNumFormat && !pFrameDir && !pAttCnt )
- return false;
+ {
+ m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>()); // empty just to enable assert
+ return {};
+ }
// order is: -/-/-/num,
// -/-/box/-, -/-/box/num,
@@ -372,7 +382,6 @@ bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat& rFrameFormat,
// vert/-/-/-, vert/-/-/num, vert/-/box/-, ver/-/box/num,
// vert/brush/-/-, vert/brush/-/num, vert/brush/box/-,
// vert/brush/box/num
- bool bInsert = true;
SwXMLFrameFormats_Impl::iterator i;
for( i = m_aFormatList.begin(); i < m_aFormatList.end(); ++i )
{
@@ -490,19 +499,19 @@ bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat& rFrameFormat,
continue;
// found!
- rFrameFormat.SetName( pTestFormat->GetName() );
- bInsert = false;
- break;
+ auto const oName(m_rFormatMap.find(pTestFormat)->second);
+ assert(oName);
+ m_rFormatMap.emplace(&rFrameFormat, oName);
+ return {};
}
- if( bInsert )
{
- rFrameFormat.SetName( lcl_xmltble_appendBoxPrefix( rNamePrefix, nCol, nRow, bTop ) );
+ OUString const name(lcl_xmltble_appendBoxPrefix(rNamePrefix, nCol, nRow, bTop));
+ m_rFormatMap.emplace(&rFrameFormat, ::std::optional<OUString>(name));
if ( i != m_aFormatList.end() ) ++i;
m_aFormatList.insert( i, &rFrameFormat );
+ return ::std::optional<OUString>(name);
}
-
- return bInsert;
}
class SwXMLTableInfo_Impl
@@ -511,10 +520,21 @@ class SwXMLTableInfo_Impl
Reference<XTextSection> m_xBaseSection;
bool m_bBaseSectionValid;
sal_uInt32 m_nPrefix;
+ SwXMLTextParagraphExport::FormatMap const& m_rLineFormats;
+ SwXMLTextParagraphExport::FormatMap const& m_rBoxFormats;
public:
- inline SwXMLTableInfo_Impl( const SwTable *pTable, sal_uInt16 nPrefix );
+ inline SwXMLTableInfo_Impl( const SwTable *pTable, sal_uInt16 nPrefix,
+ SwXMLTextParagraphExport::FormatMap const& rLineFormats,
+ SwXMLTextParagraphExport::FormatMap const& rBoxFormats)
+ : m_pTable(pTable)
+ , m_bBaseSectionValid(false)
+ , m_nPrefix(nPrefix)
+ , m_rLineFormats(rLineFormats)
+ , m_rBoxFormats(rBoxFormats)
+ {
+ }
const SwTable *GetTable() const { return m_pTable; }
const SwFrameFormat *GetTableFormat() const { return m_pTable->GetFrameFormat(); }
@@ -524,15 +544,10 @@ public:
inline void SetBaseSection( const Reference < XTextSection >& rBase );
/// The namespace (table or loext) that should be used for the elements.
sal_uInt16 GetPrefix() const { return m_nPrefix; }
+ SwXMLTextParagraphExport::FormatMap const& GetLineFormats() const { return m_rLineFormats; }
+ SwXMLTextParagraphExport::FormatMap const& GetBoxFormats() const { return m_rBoxFormats; }
};
-inline SwXMLTableInfo_Impl::SwXMLTableInfo_Impl(const SwTable *pTable, sal_uInt16 nPrefix) :
- m_pTable(pTable),
- m_bBaseSectionValid(false),
- m_nPrefix(nPrefix)
-{
-}
-
inline void SwXMLTableInfo_Impl::SetBaseSection(
const Reference < XTextSection >& rBaseSection )
{
@@ -667,8 +682,10 @@ void SwXMLExport::ExportTableLinesAutoStyles( const SwTableLines& rLines,
SwTableLine *pLine = rLines[nLine];
SwFrameFormat *pFrameFormat = pLine->GetFrameFormat();
- if( rExpRows.AddRow( *pFrameFormat, rNamePrefix, nLine ) )
- ExportFormat( *pFrameFormat, XML_TABLE_ROW );
+ if (auto oNew = rExpRows.AddRow(*pFrameFormat, rNamePrefix, nLine))
+ {
+ ExportFormat(*pFrameFormat, XML_TABLE_ROW, oNew);
+ }
const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
const size_t nBoxes = rBoxes.size();
@@ -695,9 +712,11 @@ void SwXMLExport::ExportTableLinesAutoStyles( const SwTableLines& rLines,
if( pBoxSttNd )
{
SwFrameFormat *pFrameFormat2 = pBox->GetFrameFormat();
- if( rExpCells.AddCell( *pFrameFormat2, rNamePrefix, nOldCol, nLine,
+ if (auto oNew = rExpCells.AddCell(*pFrameFormat2, rNamePrefix, nOldCol, nLine,
bTop) )
- ExportFormat( *pFrameFormat2, XML_TABLE_CELL );
+ {
+ ExportFormat(*pFrameFormat2, XML_TABLE_CELL, oNew);
+ }
Reference < XCell > xCell = SwXCell::CreateXCell(
const_cast<SwFrameFormat *>(rTableInfo.GetTableFormat()),
@@ -743,8 +762,13 @@ void SwXMLExport::ExportTableLinesAutoStyles( const SwTableLines& rLines,
}
}
-void SwXMLExport::ExportTableAutoStyles( const SwTableNode& rTableNd )
+void SwXMLExport::ExportTableAutoStyles(const SwTableNode& rTableNd)
{
+ auto & rFormats(static_cast<SwXMLTextParagraphExport *>(GetTextParagraphExport().get())->GetTableFormats());
+ auto const it(rFormats.find(&rTableNd));
+ assert(it != rFormats.end());
+ SwXMLTextParagraphExport::FormatMap & rRowFormats(it->second.first);
+ SwXMLTextParagraphExport::FormatMap & rBoxFormats(it->second.second);
const SwTable& rTable = rTableNd.GetTable();
const SwFrameFormat *pTableFormat = rTable.GetFrameFormat();
@@ -772,9 +796,9 @@ void SwXMLExport::ExportTableAutoStyles( const SwTableNode& rTableNd )
ExportTableFormat( *pTableFormat, nAbsWidth );
SwXMLTableColumnsSortByWidth_Impl aExpCols;
- SwXMLTableFrameFormatsSort_Impl aExpRows;
- SwXMLTableFrameFormatsSort_Impl aExpCells;
- SwXMLTableInfo_Impl aTableInfo( &rTable, XML_NAMESPACE_TABLE );
+ SwXMLTableFrameFormatsSort_Impl aExpRows(rRowFormats);
+ SwXMLTableFrameFormatsSort_Impl aExpCells(rBoxFormats);
+ SwXMLTableInfo_Impl aTableInfo(&rTable, XML_NAMESPACE_TABLE, rRowFormats, rBoxFormats);
ExportTableLinesAutoStyles( rTable.GetTabLines(), nAbsWidth, nBaseWidth,
pTableFormat->GetName(), aExpCols, aExpRows, aExpCells,
aTableInfo, true);
@@ -792,10 +816,12 @@ void SwXMLExport::ExportTableBox( const SwTableBox& rBox,
const SwFrameFormat *pFrameFormat = rBox.GetFrameFormat();
if( pFrameFormat )
{
- const OUString& sName = pFrameFormat->GetName();
- if( !sName.isEmpty() )
+ auto const it(rTableInfo.GetBoxFormats().find(pFrameFormat));
+ assert(it != rTableInfo.GetBoxFormats().end());
+ if (it->second)
{
- AddAttribute( XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(sName) );
+ assert(!it->second->isEmpty());
+ AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(*it->second));
}
}
}
@@ -925,10 +951,12 @@ void SwXMLExport::ExportTableLine( const SwTableLine& rLine,
const SwFrameFormat *pFrameFormat = rLine.GetFrameFormat();
if( pFrameFormat )
{
- const OUString& sName = pFrameFormat->GetName();
- if( !sName.isEmpty() )
+ auto const it(rTableInfo.GetLineFormats().find(pFrameFormat));
+ assert(it != rTableInfo.GetLineFormats().end());
+ if (it->second)
{
- AddAttribute( XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(sName) );
+ assert(!it->second->isEmpty());
+ AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(*it->second));
}
}
@@ -951,10 +979,12 @@ void SwXMLExport::ExportTableLine( const SwTableLine& rLine,
const SwFrameFormat* pFormat = pBox->GetFrameFormat();
if (pFormat)
{
- const OUString& sName = pFormat->GetName();
- if (!sName.isEmpty())
+ auto const it(rTableInfo.GetBoxFormats().find(pFormat));
+ assert(it != rTableInfo.GetBoxFormats().end());
+ if (it->second)
{
- AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(sName));
+ assert(!it->second->isEmpty());
+ AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(*it->second));
}
}
@@ -1091,29 +1121,6 @@ void SwXMLExport::ExportTableLines( const SwTableLines& rLines,
delete pLines;
}
-static void lcl_xmltble_ClearName_Line( SwTableLine* pLine );
-
-static void lcl_xmltble_ClearName_Box( SwTableBox* pBox )
-{
- if( !pBox->GetSttNd() )
- {
- for( SwTableLine* pLine : pBox->GetTabLines() )
- lcl_xmltble_ClearName_Line( pLine );
- }
- else
- {
- SwFrameFormat *pFrameFormat = pBox->GetFrameFormat();
- if( pFrameFormat && !pFrameFormat->GetName().isEmpty() )
- pFrameFormat->SetName( OUString() );
- }
-}
-
-void lcl_xmltble_ClearName_Line( SwTableLine* pLine )
-{
- for( SwTableBox* pBox : pLine->GetTabBoxes() )
- lcl_xmltble_ClearName_Box( pBox );
-}
-
void SwXMLExport::ExportTable( const SwTableNode& rTableNd )
{
::std::optional<sal_uInt16> oPrefix = XML_NAMESPACE_TABLE;
@@ -1187,20 +1194,45 @@ void SwXMLExport::ExportTable( const SwTableNode& rTableNd )
XML_DDE_SOURCE, true, false);
}
- SwXMLTableInfo_Impl aTableInfo(&rTable, *oPrefix);
+ auto const& rFormats(static_cast<SwXMLTextParagraphExport const*>(GetTextParagraphExport().get())->GetTableFormats());
+ auto const it(rFormats.find(&rTableNd));
+ assert(it != rFormats.end());
+ SwXMLTableInfo_Impl aTableInfo(&rTable, *oPrefix, it->second.first, it->second.second);
ExportTableLines( rTable.GetTabLines(), aTableInfo, rTable.GetRowsToRepeat() );
-
- for( SwTableLine *pLine : const_cast<SwTable &>(rTable).GetTabLines() )
- lcl_xmltble_ClearName_Line( pLine );
}
void SwXMLTextParagraphExport::exportTableAutoStyles() {
+ // note: maTableNodes is used here only to keep the iteration order as before
for (const auto* pTableNode : maTableNodes)
{
static_cast<SwXMLExport&>(GetExport()).ExportTableAutoStyles(*pTableNode);
}
}
+void SwXMLTextParagraphExport::CollectTableLinesAutoStyles(const SwTableLines& rLines,
+ SwFrameFormat& rFormat, bool _bProgress)
+{
+ // Follow SwXMLExport::ExportTableLines/ExportTableLine/ExportTableBox
+ for (const SwTableLine* pLine : rLines)
+ {
+ for (SwTableBox* pBox : pLine->GetTabBoxes())
+ {
+ if (pBox->getRowSpan() <= 0)
+ continue;
+ if (pBox->GetSttNd())
+ {
+ if (rtl::Reference<SwXCell> xCell = SwXCell::CreateXCell(&rFormat, pBox))
+ exportText(xCell, true /*bAutoStyles*/, _bProgress, true /*bExportParagraph*/);
+ }
+ else
+ {
+ // no start node -> merged cells: export subtable in cell
+ CollectTableLinesAutoStyles(pBox->GetTabLines(), rFormat, _bProgress);
+ }
+ }
+ }
+}
+
void SwXMLTextParagraphExport::exportTable(
const Reference < XTextContent > & rTextContent,
bool bAutoStyles, bool _bProgress )
@@ -1235,22 +1267,9 @@ void SwXMLTextParagraphExport::exportTable(
&& (bExportStyles || !pFormat->GetDoc()->IsInHeaderFooter(aIdx)))
{
maTableNodes.push_back(pTableNd);
+ m_TableFormats.emplace(pTableNd, ::std::make_pair(SwXMLTextParagraphExport::FormatMap(), SwXMLTextParagraphExport::FormatMap()));
// Collect all tables inside cells of this table, too
- const auto aCellNames = pXTable->getCellNames();
- for (const OUString& rCellName : aCellNames)
- {
- css::uno::Reference<css::container::XEnumerationAccess> xCell(
- pXTable->getCellByName(rCellName), css::uno::UNO_QUERY);
- if (!xCell)
- continue;
- auto xEnumeration = xCell->createEnumeration();
- while (xEnumeration->hasMoreElements())
- {
- if (css::uno::Reference<css::text::XTextTable> xInnerTable{
- xEnumeration->nextElement(), css::uno::UNO_QUERY })
- exportTable(xInnerTable, bAutoStyles, _bProgress);
- }
- }
+ CollectTableLinesAutoStyles(pTable->GetTabLines(), *pFormat, _bProgress);
}
}
else
diff --git a/sw/source/filter/xml/xmltexte.hxx b/sw/source/filter/xml/xmltexte.hxx
index e1041b7d666a..09ce6c46f4ca 100644
--- a/sw/source/filter/xml/xmltexte.hxx
+++ b/sw/source/filter/xml/xmltexte.hxx
@@ -23,12 +23,16 @@
#include <xmloff/txtparae.hxx>
#include <tools/globname.hxx>
+#include <optional>
+#include <unordered_map>
+
#define XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE "vnd.sun.star.GraphicObject:"
class SwXMLExport;
class SvXMLAutoStylePoolP;
class SwNoTextNode;
class SwTableNode;
+class SwTableLines;
namespace com::sun::star::style { class XStyle; }
class SwXMLTextParagraphExport : public XMLTextParagraphExport
@@ -39,10 +43,17 @@ class SwXMLTextParagraphExport : public XMLTextParagraphExport
// Collected autostyles for use in exportTextAutoStyles
std::vector<const SwTableNode*> maTableNodes;
+public:
+ typedef ::std::unordered_map<SwFrameFormat const*, ::std::optional<OUString>> FormatMap;
+private:
+ ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, FormatMap>> m_TableFormats;
static SwNoTextNode *GetNoTextNode(
const css::uno::Reference < css::beans::XPropertySet >& rPropSet );
+ void CollectTableLinesAutoStyles(const SwTableLines& rLines, SwFrameFormat& rFormat,
+ bool bProgress);
+
protected:
virtual void _collectTextEmbeddedAutoStyles(
const css::uno::Reference< css::beans::XPropertySet > & rPropSet ) override;
@@ -61,6 +72,11 @@ public:
SwXMLExport& rExp,
SvXMLAutoStylePoolP& rAutoStylePool );
virtual ~SwXMLTextParagraphExport() override;
+
+ ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, FormatMap>> const&
+ GetTableFormats() const { return m_TableFormats; }
+ ::std::unordered_map<SwTableNode const*, ::std::pair<FormatMap, FormatMap>> &
+ GetTableFormats() { return m_TableFormats; }
};
#endif // INCLUDED_SW_SOURCE_FILTER_XML_XMLTEXTE_HXX
diff --git a/sw/source/filter/xml/xmltexti.cxx b/sw/source/filter/xml/xmltexti.cxx
index 779a63015b7e..9a34b547f5af 100644
--- a/sw/source/filter/xml/xmltexti.cxx
+++ b/sw/source/filter/xml/xmltexti.cxx
@@ -823,9 +823,14 @@ uno::Reference< XPropertySet > SwXMLTextImportHelper::createAndInsertFloatingFra
uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY );
if ( xSet.is() )
{
+ OUString sHRef = URIHelper::SmartRel2Abs(
+ INetURLObject( GetXMLImport().GetBaseURL() ), rHRef );
+
+ if (INetURLObject(sHRef).IsExoticProtocol())
+ GetXMLImport().NotifyMacroEventRead();
+
xSet->setPropertyValue("FrameURL",
- makeAny( URIHelper::SmartRel2Abs(
- INetURLObject( GetXMLImport().GetBaseURL() ), rHRef ) ) );
+ makeAny( rHRef ) );
xSet->setPropertyValue("FrameName",
makeAny( rName ) );
diff --git a/sw/source/ui/chrdlg/numpara.cxx b/sw/source/ui/chrdlg/numpara.cxx
index 205bcacadb6f..272c7161e869 100644
--- a/sw/source/ui/chrdlg/numpara.cxx
+++ b/sw/source/ui/chrdlg/numpara.cxx
@@ -307,10 +307,15 @@ IMPL_LINK_NOARG(SwParagraphNumTabPage, EditNumStyleHdl_Impl, weld::Button&, void
}
// Internal: Perform functions through the Dispatcher
-bool SwParagraphNumTabPage::ExecuteEditNumStyle_Impl(
+void SwParagraphNumTabPage::ExecuteEditNumStyle_Impl(
sal_uInt16 nId, const OUString &rStr, SfxStyleFamily nFamily)
{
- SfxDispatcher &rDispatcher = *SfxViewShell::Current()->GetDispatcher();
+ SfxViewShell* pViewShell = SfxViewShell::Current();
+
+ if( !pViewShell)
+ return;
+
+ SfxDispatcher* pDispatcher = pViewShell->GetDispatcher();
SfxStringItem aItem(nId, rStr);
SfxUInt16Item aFamily(SID_STYLE_FAMILY, static_cast<sal_uInt16>(nFamily));
const SfxPoolItem* pItems[ 3 ];
@@ -329,12 +334,9 @@ bool SwParagraphNumTabPage::ExecuteEditNumStyle_Impl(
pInternalItems[ 0 ] = &aDialogParent;
pInternalItems[ 1 ] = nullptr;
- const SfxPoolItem* pItem = rDispatcher.Execute(
+ pDispatcher->Execute(
nId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
pItems, 0, pInternalItems);
-
- return pItem != nullptr;
-
}
IMPL_LINK(SwParagraphNumTabPage, StyleHdl_Impl, weld::ComboBox&, rBox, void)
diff --git a/sw/source/ui/chrdlg/pardlg.cxx b/sw/source/ui/chrdlg/pardlg.cxx
index 232b9f8154df..2ab307113343 100644
--- a/sw/source/ui/chrdlg/pardlg.cxx
+++ b/sw/source/ui/chrdlg/pardlg.cxx
@@ -94,9 +94,7 @@ SwParaDlg::SwParaDlg(weld::Window *pParent,
else
RemoveTabPage("labelTP_PARA_ASIAN");
- const sal_uInt16 nWhich(rCoreSet.GetPool()->GetWhich(SID_ATTR_LRSPACE));
- bool bLRValid = SfxItemState::DEFAULT <= rCoreSet.GetItemState(nWhich);
- if(bHtmlMode || !bLRValid)
+ if(bHtmlMode)
RemoveTabPage("labelTP_TABULATOR");
else
{
diff --git a/sw/source/ui/chrdlg/tblnumfm.cxx b/sw/source/ui/chrdlg/tblnumfm.cxx
index 1576602143be..dd3f575e2bdc 100644
--- a/sw/source/ui/chrdlg/tblnumfm.cxx
+++ b/sw/source/ui/chrdlg/tblnumfm.cxx
@@ -28,13 +28,14 @@
SwNumFormatDlg::SwNumFormatDlg(weld::Widget* pParent, const SfxItemSet& rSet)
: SfxSingleTabDialogController(pParent, &rSet, "cui/ui/formatnumberdialog.ui", "FormatNumberDialog")
+ , m_xContent( m_xBuilder->weld_container("content") )
{
// Create TabPage
SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc(RID_SVXPAGE_NUMBERFORMAT);
if ( fnCreatePage )
{
- std::unique_ptr<SfxTabPage> xNewPage = (*fnCreatePage)(get_content_area(), this, &rSet);
+ std::unique_ptr<SfxTabPage> xNewPage = (*fnCreatePage)(m_xContent.get(), this, &rSet);
SfxAllItemSet aSet(*(rSet.GetPool()));
aSet.Put(xNewPage->GetItemSet().Get( SID_ATTR_NUMBERFORMAT_INFO));
xNewPage->PageCreated(aSet);
diff --git a/sw/source/ui/dialog/swdlgfact.cxx b/sw/source/ui/dialog/swdlgfact.cxx
index 17f0ed1d3a03..eda2be389ae8 100644
--- a/sw/source/ui/dialog/swdlgfact.cxx
+++ b/sw/source/ui/dialog/swdlgfact.cxx
@@ -35,6 +35,7 @@
#include <colwd.hxx>
#include <contentcontroldlg.hxx>
#include <contentcontrollistitemdlg.hxx>
+#include <pagenumberdlg.hxx>
#include <convert.hxx>
#include <cption.hxx>
#include <dbinsdlg.hxx>
@@ -90,6 +91,7 @@
#include <uiborder.hxx>
#include <mmresultdialogs.hxx>
#include <formatlinebreak.hxx>
+#include <translatelangselect.hxx>
using namespace ::com::sun::star;
using namespace css::frame;
@@ -110,6 +112,16 @@ short SwAbstractSfxController_Impl::Execute()
return m_xDlg->run();
}
+short AbstractNumFormatDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractNumFormatDlg_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return SfxSingleTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
short AbstractSwAsciiFilterDlg_Impl::Execute()
{
return m_xDlg->run();
@@ -120,6 +132,11 @@ short AbstractSplitTableDialog_Impl::Execute()
return m_xDlg->run();
}
+bool AbstractSplitTableDialog_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return weld::GenericDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
short AbstractSwTableWidthDlg_Impl::Execute()
{
return m_xDlg->run();
@@ -135,6 +152,16 @@ short AbstractSwMergeTableDlg_Impl::Execute()
return m_xDlg->run();
}
+short AbstractSwPageNumberDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractSwPageNumberDlg_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return weld::GenericDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
short AbstractGenericDialog_Impl::Execute()
{
return m_xDlg->run();
@@ -210,6 +237,11 @@ short AbstractSwRenameXNamedDlg_Impl::Execute()
return m_xDlg->run();
}
+bool AbstractSwContentControlListItemDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext& rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
short AbstractSwContentControlListItemDlg_Impl::Execute()
{
return m_xDlg->run();
@@ -351,11 +383,21 @@ const SfxItemSet* SwAbstractSfxController_Impl::GetOutputItemSet() const
return m_xDlg->GetOutputItemSet();
}
+const SfxItemSet* AbstractNumFormatDlg_Impl::GetOutputItemSet() const
+{
+ return m_xDlg->GetOutputItemSet();
+}
+
void SwAbstractSfxController_Impl::SetText(const OUString& rStr)
{
m_xDlg->set_title(rStr);
}
+void AbstractNumFormatDlg_Impl::SetText(const OUString& rStr)
+{
+ m_xDlg->set_title(rStr);
+}
+
void AbstractSwAsciiFilterDlg_Impl::FillOptions( SwAsciiOptions& rOptions )
{
m_xDlg->FillOptions(rOptions);
@@ -595,6 +637,16 @@ OUString AbstractInsFootNoteDlg_Impl::GetFontName()
return m_xDlg->GetFontName();
}
+int AbstractSwPageNumberDlg_Impl::GetPageNumberPosition() const
+{
+ return m_xDlg->GetPageNumberPosition();
+}
+
+int AbstractSwPageNumberDlg_Impl::GetPageNumberAlignment() const
+{
+ return m_xDlg->GetPageNumberAlignment();
+}
+
bool AbstractInsFootNoteDlg_Impl::IsEndNote()
{
return m_xDlg->IsEndNote();
@@ -802,6 +854,12 @@ sal_uInt16 AbstractMailMergeWizard_Impl::GetRestartPage() const
return m_xDlg->GetRestartPage();
}
+std::optional<SwLanguageListItem> AbstractSwTranslateLangSelectDlg_Impl::GetSelectedLanguage()
+{
+ SwTranslateLangSelectDlg* pDlg = dynamic_cast<SwTranslateLangSelectDlg*>(m_xDlg.get());
+ return pDlg->GetSelectedLanguage();
+}
+
VclPtr<AbstractSwInsertAbstractDlg> SwAbstractDialogFactory_Impl::CreateSwInsertAbstractDlg(weld::Window* pParent)
{
return VclPtr<AbstractSwInsertAbstractDlg_Impl>::Create(std::make_unique<SwInsertAbstractDlg>(pParent));
@@ -827,7 +885,7 @@ VclPtr<SfxAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwBackgroundDialog
VclPtr<SfxAbstractDialog> SwAbstractDialogFactory_Impl::CreateNumFormatDialog(weld::Widget* pParent, const SfxItemSet& rSet)
{
- return VclPtr<SwAbstractSfxController_Impl>::Create(std::make_unique<SwNumFormatDlg>(pParent, rSet));
+ return VclPtr<AbstractNumFormatDlg_Impl>::Create(std::make_shared<SwNumFormatDlg>(pParent, rSet));
}
VclPtr<AbstractSwAsciiFilterDlg> SwAbstractDialogFactory_Impl::CreateSwAsciiFilterDlg(weld::Window* pParent,
@@ -853,7 +911,7 @@ SwAbstractDialogFactory_Impl::CreateSwContentControlListItemDlg(weld::Window* pP
SwContentControlListItem& rItem)
{
return VclPtr<AbstractSwContentControlListItemDlg_Impl>::Create(
- std::make_unique<SwContentControlListItemDlg>(pParent, rItem));
+ std::make_shared<SwContentControlListItemDlg>(pParent, rItem));
}
std::shared_ptr<AbstractSwBreakDlg> SwAbstractDialogFactory_Impl::CreateSwBreakDlg(weld::Window* pParent, SwWrtShell &rSh)
@@ -861,6 +919,11 @@ std::shared_ptr<AbstractSwBreakDlg> SwAbstractDialogFactory_Impl::CreateSwBreakD
return std::make_shared<AbstractSwBreakDlg_Impl>(std::make_unique<SwBreakDlg>(pParent, rSh));
}
+std::shared_ptr<AbstractSwTranslateLangSelectDlg> SwAbstractDialogFactory_Impl::CreateSwTranslateLangSelectDlg(weld::Window* pParent, SwWrtShell &rSh)
+{
+ return std::make_shared<AbstractSwTranslateLangSelectDlg_Impl>(std::make_unique<SwTranslateLangSelectDlg>(pParent, rSh));
+}
+
VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwChangeDBDlg(SwView& rVw)
{
#if HAVE_FEATURE_DBCONNECTIVITY && !ENABLE_FUZZERS
@@ -972,7 +1035,7 @@ VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateSwSortingDialog(we
VclPtr<AbstractSplitTableDialog> SwAbstractDialogFactory_Impl::CreateSplitTableDialog(weld::Window *pParent, SwWrtShell &rSh)
{
- return VclPtr<AbstractSplitTableDialog_Impl>::Create(std::make_unique<SwSplitTableDlg>(pParent, rSh));
+ return VclPtr<AbstractSplitTableDialog_Impl>::Create(std::make_shared<SwSplitTableDlg>(pParent, rSh));
}
VclPtr<AbstractSwSelGlossaryDlg> SwAbstractDialogFactory_Impl::CreateSwSelGlossaryDlg(weld::Window *pParent, const OUString &rShortName)
@@ -1031,6 +1094,11 @@ VclPtr<AbstractSwModalRedlineAcceptDlg> SwAbstractDialogFactory_Impl::CreateSwMo
return VclPtr<AbstractSwModalRedlineAcceptDlg_Impl>::Create(std::make_unique<SwModalRedlineAcceptDlg>(pParent));
}
+VclPtr<AbstractSwPageNumberDlg> SwAbstractDialogFactory_Impl::CreateSwPageNumberDlg(weld::Window *pParent)
+{
+ return VclPtr<AbstractSwPageNumberDlg_Impl>::Create(std::make_shared<SwPageNumberDlg>(pParent));
+}
+
VclPtr<VclAbstractDialog> SwAbstractDialogFactory_Impl::CreateTableMergeDialog(weld::Window* pParent, bool& rWithPrev)
{
return VclPtr<AbstractSwMergeTableDlg_Impl>::Create(std::make_unique<SwMergeTableDlg>(pParent, rWithPrev));
diff --git a/sw/source/ui/dialog/swdlgfact.hxx b/sw/source/ui/dialog/swdlgfact.hxx
index 8690d9db8129..a08a8af26318 100644
--- a/sw/source/ui/dialog/swdlgfact.hxx
+++ b/sw/source/ui/dialog/swdlgfact.hxx
@@ -55,6 +55,7 @@
#include <itabenum.hxx>
#include <optional>
#include <o3tl/deleter.hxx>
+#include <pagenumberdlg.hxx>
class SwInsertAbstractDlg;
@@ -125,6 +126,20 @@ public:
virtual void SetText(const OUString& rStr) override;
};
+class AbstractNumFormatDlg_Impl : public SfxAbstractDialog
+{
+ std::shared_ptr<SfxSingleTabDialogController> m_xDlg;
+public:
+ explicit AbstractNumFormatDlg_Impl(std::shared_ptr<SfxSingleTabDialogController> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &rCtx) override;
+ virtual const SfxItemSet* GetOutputItemSet() const override;
+ virtual void SetText(const OUString& rStr) override;
+};
+
class AbstractSwAsciiFilterDlg_Impl : public AbstractSwAsciiFilterDlg
{
std::unique_ptr<SwAsciiFilterDlg> m_xDlg;
@@ -137,6 +152,20 @@ public:
virtual void FillOptions( SwAsciiOptions& rOptions ) override;
};
+class AbstractSwPageNumberDlg_Impl : public AbstractSwPageNumberDlg
+{
+ std::shared_ptr<SwPageNumberDlg> m_xDlg;
+public:
+ explicit AbstractSwPageNumberDlg_Impl(std::shared_ptr<SwPageNumberDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &rCtx) override;
+ virtual int GetPageNumberPosition() const override;
+ virtual int GetPageNumberAlignment() const override;
+};
+
class AbstractGenericDialog_Impl : public VclAbstractDialog
{
std::shared_ptr<weld::GenericDialogController> m_xDlg;
@@ -187,6 +216,19 @@ public:
virtual std::shared_ptr<weld::DialogController> getDialogController() override { return m_xDlg; }
};
+class AbstractSwTranslateLangSelectDlg_Impl : public AbstractSwTranslateLangSelectDlg
+{
+ std::shared_ptr<weld::DialogController> m_xDlg;
+public:
+ explicit AbstractSwTranslateLangSelectDlg_Impl(std::shared_ptr<weld::DialogController> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+
+ virtual std::shared_ptr<weld::DialogController> getDialogController() override { return m_xDlg; }
+ virtual std::optional<SwLanguageListItem> GetSelectedLanguage() override;
+};
+
class AbstractSwTableWidthDlg_Impl : public VclAbstractDialog
{
std::unique_ptr<SwTableWidthDlg> m_xDlg;
@@ -222,13 +264,14 @@ public:
class AbstractSplitTableDialog_Impl : public AbstractSplitTableDialog // add for
{
- std::unique_ptr<SwSplitTableDlg> m_xDlg;
+ std::shared_ptr<SwSplitTableDlg> m_xDlg;
public:
- explicit AbstractSplitTableDialog_Impl(std::unique_ptr<SwSplitTableDlg> p)
+ explicit AbstractSplitTableDialog_Impl(std::shared_ptr<SwSplitTableDlg> p)
: m_xDlg(std::move(p))
{
}
virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &rCtx) override;
virtual SplitTable_HeadlineOption GetSplitMode() override;
};
@@ -416,16 +459,17 @@ public:
*/
class AbstractSwContentControlListItemDlg_Impl : public AbstractSwContentControlListItemDlg
{
- std::unique_ptr<SwContentControlListItemDlg> m_xDlg;
+ std::shared_ptr<SwContentControlListItemDlg> m_xDlg;
public:
explicit AbstractSwContentControlListItemDlg_Impl(
- std::unique_ptr<SwContentControlListItemDlg> xDlg)
+ std::shared_ptr<SwContentControlListItemDlg> xDlg)
: m_xDlg(std::move(xDlg))
{
}
short Execute() override;
+ bool StartExecuteAsync(VclAbstractDialog::AsyncContext &) override;
};
class AbstractSwModalRedlineAcceptDlg_Impl : public AbstractSwModalRedlineAcceptDlg
@@ -678,12 +722,14 @@ public:
SvStream* pStream) override;
virtual VclPtr<VclAbstractDialog> CreateSwInsertBookmarkDlg(weld::Window *pParent, SwWrtShell &rSh) override;
virtual VclPtr<VclAbstractDialog> CreateSwContentControlDlg(weld::Window *pParent, SwWrtShell &rSh) override;
+ virtual VclPtr<AbstractSwPageNumberDlg> CreateSwPageNumberDlg(weld::Window *pParent) override;
VclPtr<AbstractSwContentControlListItemDlg>
CreateSwContentControlListItemDlg(weld::Window* pParent,
SwContentControlListItem& rItem) override;
virtual std::shared_ptr<AbstractSwBreakDlg> CreateSwBreakDlg(weld::Window *pParent, SwWrtShell &rSh) override;
+ virtual std::shared_ptr<AbstractSwTranslateLangSelectDlg> CreateSwTranslateLangSelectDlg(weld::Window *pParent, SwWrtShell &rSh) override;
virtual VclPtr<VclAbstractDialog> CreateSwChangeDBDlg(SwView& rVw) override;
virtual VclPtr<SfxAbstractTabDialog> CreateSwCharDlg(weld::Window* pParent, SwView& pVw, const SfxItemSet& rCoreSet,
SwCharDlgMode nDialogMode, const OUString* pFormatStr = nullptr) override;
diff --git a/sw/source/ui/dialog/uiregionsw.cxx b/sw/source/ui/dialog/uiregionsw.cxx
index 9ff77c893263..e5cb5c1945d2 100644
--- a/sw/source/ui/dialog/uiregionsw.cxx
+++ b/sw/source/ui/dialog/uiregionsw.cxx
@@ -35,6 +35,7 @@
#include <editeng/sizeitem.hxx>
#include <svtools/htmlcfg.hxx>
#include <osl/diagnose.h>
+#include <comphelper/lok.hxx>
#include <uitool.hxx>
#include <IMark.hxx>
@@ -396,6 +397,15 @@ SwEditRegionDlg::SwEditRegionDlg(weld::Window* pParent, SwWrtShell& rWrtSh)
m_xTree->show();
bDontCheckPasswd = false;
+
+ if(comphelper::LibreOfficeKit::isActive())
+ {
+ m_xDDECB->hide();
+ m_xDDECommandFT->hide();
+ m_xFileNameFT->hide();
+ m_xFileNameED->hide();
+ m_xFilePB->hide();
+ }
}
bool SwEditRegionDlg::CheckPasswd(weld::Toggleable* pBox)
@@ -1158,7 +1168,8 @@ IMPL_LINK(SwEditRegionDlg, DDEHdl, weld::Toggleable&, rButton, void)
{
m_xDDECommandFT->hide();
m_xFileNameFT->set_sensitive(bFile);
- m_xFileNameFT->show();
+ if(!comphelper::LibreOfficeKit::isActive())
+ m_xFileNameFT->show();
m_xSubRegionED->show();
m_xSubRegionFT->show();
m_xSubRegionED->set_sensitive(bFile);
@@ -1477,6 +1488,21 @@ SwInsertSectionTabPage::SwInsertSectionTabPage(weld::Container* pPage, weld::Dia
m_xDDECB->connect_toggled( LINK( this, SwInsertSectionTabPage, DDEHdl ));
ChangeProtectHdl(*m_xProtectCB);
m_xSubRegionED->set_entry_completion(true, true);
+
+ // Hide Link section. In general it makes no sense to insert a file from the jail,
+ // because it does not contain any usable files (documents).
+ if(comphelper::LibreOfficeKit::isActive())
+ {
+ m_xBuilder->weld_label("label1")->hide(); // Link
+ m_xFileCB->hide();
+ m_xDDECB->hide();
+ m_xDDECommandFT->hide();
+ m_xFileNameFT->hide();
+ m_xFileNameED->hide();
+ m_xFilePB->hide();
+ m_xSubRegionFT->hide();
+ m_xSubRegionED->hide();
+ }
}
SwInsertSectionTabPage::~SwInsertSectionTabPage()
@@ -1712,7 +1738,8 @@ IMPL_LINK( SwInsertSectionTabPage, DDEHdl, weld::Toggleable&, rButton, void )
{
m_xDDECommandFT->hide();
m_xFileNameFT->set_sensitive(bFile);
- m_xFileNameFT->show();
+ if(!comphelper::LibreOfficeKit::isActive())
+ m_xFileNameFT->show();
m_xSubRegionFT->show();
m_xSubRegionED->show();
m_xSubRegionED->set_sensitive(bFile);
diff --git a/sw/source/ui/frmdlg/cption.cxx b/sw/source/ui/frmdlg/cption.cxx
index 867e16fa56dc..f22e881a0210 100644
--- a/sw/source/ui/frmdlg/cption.cxx
+++ b/sw/source/ui/frmdlg/cption.cxx
@@ -137,6 +137,7 @@ SwCaptionDialog::SwCaptionDialog(weld::Window *pParent, SwView &rV)
m_xSepEdit->connect_changed(aLk);
m_xFormatBox->connect_changed(LINK(this, SwCaptionDialog, SelectListBoxHdl));
+ m_xOKButton->connect_clicked(LINK(this, SwCaptionDialog, OKHdl));
m_xOptionButton->connect_clicked(LINK(this, SwCaptionDialog, OptionHdl));
m_xAutoCaptionButton->connect_clicked(LINK(this, SwCaptionDialog, CaptionHdl));
@@ -265,6 +266,12 @@ SwCaptionDialog::SwCaptionDialog(weld::Window *pParent, SwView &rV)
DrawSample();
}
+IMPL_LINK_NOARG(SwCaptionDialog, OKHdl, weld::Button&, void)
+{
+ Apply();
+ m_xDialog->response(RET_OK);
+}
+
void SwCaptionDialog::Apply()
{
InsCaptionOpt aOpt;
@@ -304,21 +311,25 @@ IMPL_LINK_NOARG(SwCaptionDialog, OptionHdl, weld::Button&, void)
OUString sFieldTypeName = m_xCategoryBox->get_active_text();
if(sFieldTypeName == m_sNone)
sFieldTypeName.clear();
- SwSequenceOptionDialog aDlg(m_xDialog.get(), rView, sFieldTypeName);
- aDlg.SetApplyBorderAndShadow(bCopyAttributes);
- aDlg.SetCharacterStyle( sCharacterStyle );
- aDlg.SetOrderNumberingFirst( bOrderNumberingFirst );
- aDlg.run();
- bCopyAttributes = aDlg.IsApplyBorderAndShadow();
- sCharacterStyle = aDlg.GetCharacterStyle();
- //#i61007# order of captions
- if( bOrderNumberingFirst != aDlg.IsOrderNumberingFirst() )
- {
- bOrderNumberingFirst = aDlg.IsOrderNumberingFirst();
- SW_MOD()->GetModuleConfig()->SetCaptionOrderNumberingFirst(bOrderNumberingFirst);
- ApplyCaptionOrder();
- }
- DrawSample();
+ auto pDlg = std::make_shared<SwSequenceOptionDialog>(m_xDialog.get(), rView, sFieldTypeName);
+ pDlg->SetApplyBorderAndShadow(bCopyAttributes);
+ pDlg->SetCharacterStyle( sCharacterStyle );
+ pDlg->SetOrderNumberingFirst( bOrderNumberingFirst );
+
+ GenericDialogController::runAsync(pDlg, [pDlg, this](sal_Int32 nResult){
+ if (nResult == RET_OK) {
+ bCopyAttributes = pDlg->IsApplyBorderAndShadow();
+ sCharacterStyle = pDlg->GetCharacterStyle();
+ //#i61007# order of captions
+ if( bOrderNumberingFirst != pDlg->IsOrderNumberingFirst() )
+ {
+ bOrderNumberingFirst = pDlg->IsOrderNumberingFirst();
+ SW_MOD()->GetModuleConfig()->SetCaptionOrderNumberingFirst(bOrderNumberingFirst);
+ ApplyCaptionOrder();
+ }
+ DrawSample();
+ }
+ });
}
IMPL_LINK_NOARG(SwCaptionDialog, SelectListBoxHdl, weld::ComboBox&, void)
diff --git a/sw/source/ui/index/cnttab.cxx b/sw/source/ui/index/cnttab.cxx
index 25d1d33ceaab..dc31fdd5d156 100644
--- a/sw/source/ui/index/cnttab.cxx
+++ b/sw/source/ui/index/cnttab.cxx
@@ -484,6 +484,7 @@ class SwAddStylesDlg_Impl : public SfxDialogController
DECL_LINK(KeyInput, const KeyEvent&, bool);
DECL_LINK(TreeSizeAllocHdl, const Size&, void);
DECL_LINK(RadioToggleOnHdl, const weld::TreeView::iter_col&, void);
+ DECL_LINK(HeaderBarClick, int, void);
public:
SwAddStylesDlg_Impl(weld::Window* pParent, SwWrtShell const & rWrtSh, OUString rStringArr[]);
@@ -507,6 +508,7 @@ SwAddStylesDlg_Impl::SwAddStylesDlg_Impl(weld::Window* pParent,
m_xHeaderTree->connect_size_allocate(LINK(this, SwAddStylesDlg_Impl, TreeSizeAllocHdl));
m_xHeaderTree->enable_toggle_buttons(weld::ColumnToggleType::Radio);
m_xHeaderTree->connect_toggled(LINK(this, SwAddStylesDlg_Impl, RadioToggleOnHdl));
+ m_xHeaderTree->connect_column_clicked(LINK(this, SwAddStylesDlg_Impl, HeaderBarClick));
std::vector<int> aWidths
{
@@ -578,11 +580,34 @@ SwAddStylesDlg_Impl::SwAddStylesDlg_Impl(weld::Window* pParent,
}
}
}
+
m_xHeaderTree->make_sorted();
+ m_xHeaderTree->set_sort_column(0);
+ m_xHeaderTree->set_sort_order(true);
+ m_xHeaderTree->set_sort_indicator(TRISTATE_TRUE, 0);
+
m_xHeaderTree->select(0);
m_xHeaderTree->connect_key_release(LINK(this, SwAddStylesDlg_Impl, KeyInput));
}
+IMPL_LINK(SwAddStylesDlg_Impl, HeaderBarClick, int, nColumn, void)
+{
+ bool bSortAtoZ = m_xHeaderTree->get_sort_order();
+
+ //set new arrow positions in headerbar
+ if (nColumn == m_xHeaderTree->get_sort_column())
+ {
+ bSortAtoZ = !bSortAtoZ;
+ m_xHeaderTree->set_sort_order(bSortAtoZ);
+ }
+
+ if (nColumn != -1)
+ {
+ //sort lists
+ m_xHeaderTree->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
+ }
+}
+
IMPL_LINK(SwAddStylesDlg_Impl, TreeSizeAllocHdl, const Size&, rSize, void)
{
auto nWidth = rSize.Width() - Application::GetSettings().GetStyleSettings().GetScrollBarSize();
diff --git a/sw/source/ui/misc/contentcontroldlg.cxx b/sw/source/ui/misc/contentcontroldlg.cxx
index 5e4347e62afb..9d14a0427941 100644
--- a/sw/source/ui/misc/contentcontroldlg.cxx
+++ b/sw/source/ui/misc/contentcontroldlg.cxx
@@ -38,6 +38,8 @@ SwContentControlDlg::SwContentControlDlg(weld::Window* pParent, SwWrtShell& rWrt
"ContentControlDialog")
, m_rWrtShell(rWrtShell)
, m_xShowingPlaceHolderCB(m_xBuilder->weld_check_button("showing_place_holder"))
+ , m_xAlias(m_xBuilder->weld_entry("aliasentry"))
+ , m_xTag(m_xBuilder->weld_entry("tagentry"))
, m_xCheckboxFrame(m_xBuilder->weld_frame("checkboxframe"))
, m_xCheckedState(m_xBuilder->weld_entry("checkboxcheckedentry"))
, m_xCheckedStateBtn(m_xBuilder->weld_button("btncheckboxchecked"))
@@ -94,6 +96,18 @@ SwContentControlDlg::SwContentControlDlg(weld::Window* pParent, SwWrtShell& rWrt
m_xShowingPlaceHolderCB->set_state(eShowingPlaceHolder);
m_xShowingPlaceHolderCB->save_state();
+ if (!m_pContentControl->GetAlias().isEmpty())
+ {
+ m_xAlias->set_text(m_pContentControl->GetAlias());
+ m_xAlias->save_value();
+ }
+
+ if (!m_pContentControl->GetTag().isEmpty())
+ {
+ m_xTag->set_text(m_pContentControl->GetTag());
+ m_xTag->save_value();
+ }
+
if (m_pContentControl->GetCheckbox())
{
m_xCheckedState->set_text(m_pContentControl->GetCheckedState());
@@ -106,7 +120,7 @@ SwContentControlDlg::SwContentControlDlg(weld::Window* pParent, SwWrtShell& rWrt
m_xCheckboxFrame->set_visible(false);
}
- if (m_pContentControl->HasListItems())
+ if (m_pContentControl->GetComboBox() || m_pContentControl->GetDropDown())
{
for (const auto& rListItem : m_pContentControl->GetListItems())
{
@@ -159,7 +173,11 @@ SwContentControlDlg::SwContentControlDlg(weld::Window* pParent, SwWrtShell& rWrt
}
}
-SwContentControlDlg::~SwContentControlDlg() {}
+SwContentControlDlg::~SwContentControlDlg()
+{
+ if (m_xListItemDialog)
+ m_xListItemDialog.disposeAndClear();
+}
IMPL_LINK_NOARG(SwContentControlDlg, OkHdl, weld::Button&, void)
{
@@ -176,6 +194,18 @@ IMPL_LINK_NOARG(SwContentControlDlg, OkHdl, weld::Button&, void)
bChanged = true;
}
+ if (m_xAlias->get_value_changed_from_saved())
+ {
+ m_pContentControl->SetAlias(m_xAlias->get_text());
+ bChanged = true;
+ }
+
+ if (m_xTag->get_value_changed_from_saved())
+ {
+ m_pContentControl->SetTag(m_xTag->get_text());
+ bChanged = true;
+ }
+
if (m_xCheckedState->get_value_changed_from_saved())
{
m_pContentControl->SetCheckedState(m_xCheckedState->get_text());
@@ -265,29 +295,30 @@ IMPL_LINK(SwContentControlDlg, SelectCharHdl, weld::Button&, rButton, void)
IMPL_LINK_NOARG(SwContentControlDlg, InsertHdl, weld::Button&, void)
{
- SwContentControlListItem aItem;
+ std::shared_ptr<SwContentControlListItem> aItem = std::make_shared<SwContentControlListItem>();
SwAbstractDialogFactory& rFact = swui::GetFactory();
- ScopedVclPtr<VclAbstractDialog> pDlg(
- rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), aItem));
- if (!pDlg->Execute())
- {
- return;
- }
+ m_xListItemDialog = rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), *aItem);
+ m_xListItemDialog->StartExecuteAsync([this, aItem](sal_Int32 nResult) {
+ if (nResult == RET_OK)
+ {
+ if (aItem->m_aDisplayText.isEmpty() && aItem->m_aValue.isEmpty())
+ {
+ // Maintain the invariant that value can't be empty.
+ return;
+ }
- if (aItem.m_aDisplayText.isEmpty() && aItem.m_aValue.isEmpty())
- {
- // Maintain the invariant that value can't be empty.
- return;
- }
+ if (aItem->m_aValue.isEmpty())
+ {
+ aItem->m_aValue = aItem->m_aDisplayText;
+ }
- if (aItem.m_aValue.isEmpty())
- {
- aItem.m_aValue = aItem.m_aDisplayText;
- }
+ int nRow = m_xListItems->n_children();
+ m_xListItems->append_text(aItem->m_aDisplayText);
+ m_xListItems->set_text(nRow, aItem->m_aValue, 1);
+ }
- int nRow = m_xListItems->n_children();
- m_xListItems->append_text(aItem.m_aDisplayText);
- m_xListItems->set_text(nRow, aItem.m_aValue, 1);
+ m_xListItemDialog.disposeAndClear();
+ });
}
IMPL_LINK_NOARG(SwContentControlDlg, RenameHdl, weld::Button&, void)
@@ -298,30 +329,31 @@ IMPL_LINK_NOARG(SwContentControlDlg, RenameHdl, weld::Button&, void)
return;
}
- SwContentControlListItem aItem;
- aItem.m_aDisplayText = m_xListItems->get_text(nRow, 0);
- aItem.m_aValue = m_xListItems->get_text(nRow, 1);
+ std::shared_ptr<SwContentControlListItem> aItem = std::make_shared<SwContentControlListItem>();
+ aItem->m_aDisplayText = m_xListItems->get_text(nRow, 0);
+ aItem->m_aValue = m_xListItems->get_text(nRow, 1);
SwAbstractDialogFactory& rFact = swui::GetFactory();
- ScopedVclPtr<VclAbstractDialog> pDlg(
- rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), aItem));
- if (!pDlg->Execute())
- {
- return;
- }
+ m_xListItemDialog = rFact.CreateSwContentControlListItemDlg(m_xDialog.get(), *aItem);
+ m_xListItemDialog->StartExecuteAsync([this, aItem, nRow](sal_Int32 nResult) {
+ if (nResult == RET_OK)
+ {
+ if (aItem->m_aDisplayText.isEmpty() && aItem->m_aValue.isEmpty())
+ {
+ // Maintain the invariant that value can't be empty.
+ return;
+ }
- if (aItem.m_aDisplayText.isEmpty() && aItem.m_aValue.isEmpty())
- {
- // Maintain the invariant that value can't be empty.
- return;
- }
+ if (aItem->m_aValue.isEmpty())
+ {
+ aItem->m_aValue = aItem->m_aDisplayText;
+ }
- if (aItem.m_aValue.isEmpty())
- {
- aItem.m_aValue = aItem.m_aDisplayText;
- }
+ m_xListItems->set_text(nRow, aItem->m_aDisplayText, 0);
+ m_xListItems->set_text(nRow, aItem->m_aValue, 1);
+ }
- m_xListItems->set_text(nRow, aItem.m_aDisplayText, 0);
- m_xListItems->set_text(nRow, aItem.m_aValue, 1);
+ m_xListItemDialog.disposeAndClear();
+ });
}
IMPL_LINK_NOARG(SwContentControlDlg, DeleteHdl, weld::Button&, void)
diff --git a/sw/source/ui/misc/pagenumberdlg.cxx b/sw/source/ui/misc/pagenumberdlg.cxx
new file mode 100644
index 000000000000..47e532e18ae6
--- /dev/null
+++ b/sw/source/ui/misc/pagenumberdlg.cxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <pagenumberdlg.hxx>
+#include <vcl/bitmap.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/BitmapTools.hxx>
+#include <vcl/virdev.hxx>
+
+SwPageNumberDlg::SwPageNumberDlg(weld::Window* pParent)
+ : SfxDialogController(pParent, "modules/swriter/ui/pagenumberdlg.ui", "PageNumberDialog")
+ , m_xOk(m_xBuilder->weld_button("ok"))
+ , m_xCancel(m_xBuilder->weld_button("cancel"))
+ , m_xPageNumberPosition(m_xBuilder->weld_combo_box("positionCombo"))
+ , m_xPageNumberAlignment(m_xBuilder->weld_combo_box("alignmentCombo"))
+ , m_xPreviewImage(m_xBuilder->weld_image("previewImage"))
+ , m_aPageNumberPosition(1)
+ , m_aPageNumberAlignment(0)
+{
+ m_xOk->connect_clicked(LINK(this, SwPageNumberDlg, OkHdl));
+ m_xPageNumberPosition->connect_changed(LINK(this, SwPageNumberDlg, PositionSelectHdl));
+ m_xPageNumberAlignment->connect_changed(LINK(this, SwPageNumberDlg, AlignmentSelectHdl));
+ m_xPageNumberPosition->set_active(m_aPageNumberPosition);
+ m_xPageNumberAlignment->set_active(m_aPageNumberAlignment);
+ updateImage();
+}
+
+IMPL_LINK_NOARG(SwPageNumberDlg, OkHdl, weld::Button&, void) { m_xDialog->response(RET_OK); }
+
+IMPL_LINK_NOARG(SwPageNumberDlg, CancelHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(SwPageNumberDlg, PositionSelectHdl, weld::ComboBox&, void)
+{
+ m_aPageNumberPosition = m_xPageNumberPosition->get_active();
+ updateImage();
+}
+
+IMPL_LINK_NOARG(SwPageNumberDlg, AlignmentSelectHdl, weld::ComboBox&, void)
+{
+ m_aPageNumberAlignment = m_xPageNumberAlignment->get_active();
+ updateImage();
+}
+
+void SwPageNumberDlg::updateImage()
+{
+ int nBackgroundWidth = 75;
+ int nBackgroundHeight = 105;
+
+ int nSpriteWidth = 10;
+ int nSpriteHeight = 14;
+
+ ScopedVclPtrInstance<VirtualDevice> pVirtualDev;
+ Size aVDSize(nBackgroundWidth, nBackgroundHeight);
+ pVirtualDev->SetOutputSizePixel(aVDSize);
+ pVirtualDev->SetBackground(Color(0xF0, 0xF0, 0xF0));
+ pVirtualDev->Erase();
+
+ int y = m_aPageNumberPosition ? (nBackgroundHeight - nSpriteHeight - 5) : 5;
+ int x = 5;
+ if (m_aPageNumberAlignment == 1)
+ {
+ x = (nBackgroundWidth - nSpriteWidth) / 2;
+ }
+ else if (m_aPageNumberAlignment == 2)
+ {
+ x = nBackgroundWidth - nSpriteWidth - 5;
+ }
+ pVirtualDev->DrawText(Point(x, y), "#");
+
+ m_xPreviewImage->set_image(pVirtualDev);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/misc/pggrid.cxx b/sw/source/ui/misc/pggrid.cxx
index 875bee7ad331..e59e4112f439 100644
--- a/sw/source/ui/misc/pggrid.cxx
+++ b/sw/source/ui/misc/pggrid.cxx
@@ -318,10 +318,13 @@ void SwTextGridPage::UpdatePageSize(const SfxItemSet& rSet)
{
sal_Int32 nCharsPerLine = m_aPageSize.Width() / nTextSize;
m_xCharsPerLineNF->set_max(nCharsPerLine);
+ m_xCharsPerLineNF->set_sensitive(nCharsPerLine != 0);
m_xCharsPerLineNF->set_value(nCharsPerLine);
- m_xLinesPerPageNF->set_max(m_aPageSize.Height() /
+ sal_Int32 nMaxLines = m_aPageSize.Height() /
( m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP)) +
- m_xRubySizeMF->denormalize(m_xRubySizeMF->get_value(FieldUnit::TWIP))));
+ m_xRubySizeMF->denormalize(m_xRubySizeMF->get_value(FieldUnit::TWIP)));
+ m_xLinesPerPageNF->set_max(nMaxLines);
+ m_xLinesPerPageNF->set_sensitive(nMaxLines != 0);
SetLinesOrCharsRanges( *m_xCharsRangeFT , m_xCharsPerLineNF->get_max() );
SetLinesOrCharsRanges( *m_xLinesRangeFT , m_xLinesPerPageNF->get_max() );
}
@@ -371,6 +374,7 @@ IMPL_LINK(SwTextGridPage, CharorLineChangedHdl, weld::SpinButton&, rField, void)
( m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP)) +
m_xRubySizeMF->denormalize(m_xRubySizeMF->get_value(FieldUnit::TWIP))));
m_xLinesPerPageNF->set_max(nMaxLines);
+ m_xLinesPerPageNF->set_sensitive(nMaxLines != 0);
}
SetLinesOrCharsRanges( *m_xLinesRangeFT , m_xLinesPerPageNF->get_max() );
SetLinesOrCharsRanges( *m_xCharsRangeFT , m_xCharsPerLineNF->get_max() );
@@ -417,6 +421,7 @@ IMPL_LINK(SwTextGridPage, TextSizeChangedHdl, weld::MetricSpinButton&, rField, v
sal_Int32 nMaxChars = m_aPageSize.Width() / nTextSize;
m_xCharsPerLineNF->set_value(nMaxChars);
m_xCharsPerLineNF->set_max(nMaxChars);
+ m_xCharsPerLineNF->set_sensitive(nMaxChars != 0);
SetLinesOrCharsRanges( *m_xCharsRangeFT , m_xCharsPerLineNF->get_max() );
}
}
@@ -426,6 +431,7 @@ IMPL_LINK(SwTextGridPage, TextSizeChangedHdl, weld::MetricSpinButton&, rField, v
( m_xTextSizeMF->denormalize(m_xTextSizeMF->get_value(FieldUnit::TWIP)) +
m_xRubySizeMF->denormalize(m_xRubySizeMF->get_value(FieldUnit::TWIP))));
m_xLinesPerPageNF->set_max(nMaxLines);
+ m_xLinesPerPageNF->set_sensitive(nMaxLines != 0);
SetLinesOrCharsRanges( *m_xLinesRangeFT , m_xLinesPerPageNF->get_max() );
}
}
@@ -454,15 +460,18 @@ IMPL_LINK(SwTextGridPage, TextSizeChangedHdl, weld::MetricSpinButton&, rField, v
IMPL_LINK(SwTextGridPage, GridTypeHdl, weld::Toggleable&, rButton, void)
{
- bool bEnable = m_xNoGridRB.get() != &rButton;
- m_xLayoutFL->set_sensitive(bEnable);
- m_xDisplayFL->set_sensitive(bEnable);
+ if (!rButton.get_active())
+ return;
+
+ const bool bNoGrid = m_xNoGridRB.get() == &rButton;
+ m_xLayoutFL->set_sensitive(!bNoGrid);
+ m_xDisplayFL->set_sensitive(!bNoGrid);
//one special case
- if (bEnable)
+ if (!bNoGrid)
DisplayGridHdl(*m_xDisplayCB);
- bEnable = m_xCharsGridRB.get() == &rButton;
+ bool bEnable = m_xCharsGridRB.get() == &rButton;
m_xSnapToCharsCB->set_sensitive(bEnable);
bEnable = m_xLinesGridRB.get() == &rButton;
@@ -475,6 +484,10 @@ IMPL_LINK(SwTextGridPage, GridTypeHdl, weld::Toggleable&, rButton, void)
m_xCharWidthMF->set_sensitive(false);
}
+ //recalc which dependencies are sensitive
+ if (!bNoGrid)
+ TextSizeChangedHdl(*m_xTextSizeMF);
+
GridModifyHdl();
}
diff --git a/sw/source/ui/misc/translatelangselect.cxx b/sw/source/ui/misc/translatelangselect.cxx
new file mode 100644
index 000000000000..9ec510947923
--- /dev/null
+++ b/sw/source/ui/misc/translatelangselect.cxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+#include <uitool.hxx>
+#include <swtypes.hxx>
+#include <wrtsh.hxx>
+#include <view.hxx>
+#include <viewopt.hxx>
+#include <translatelangselect.hxx>
+#include <pagedesc.hxx>
+#include <poolfmt.hxx>
+#include <sal/log.hxx>
+#include <ndtxt.hxx>
+#include <shellio.hxx>
+#include <svtools/deeplcfg.hxx>
+#include <vcl/idle.hxx>
+#include <mdiexp.hxx>
+#include <strings.hrc>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <sfx2/viewfrm.hxx>
+#include <com/sun/star/task/XStatusIndicatorFactory.hpp>
+#include <linguistic/translate.hxx>
+
+int SwTranslateLangSelectDlg::selectedLangIdx = -1;
+SwTranslateLangSelectDlg::SwTranslateLangSelectDlg(weld::Window* pParent, SwWrtShell& rSh)
+ : GenericDialogController(pParent, "modules/swriter/ui/translationdialog.ui",
+ "LanguageSelectDialog")
+ , rWrtSh(rSh)
+ , m_xLanguageListBox(m_xBuilder->weld_combo_box("combobox1"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xBtnTranslate(m_xBuilder->weld_button("translate"))
+ , m_xLanguageVec({
+ SwLanguageListItem("BG", "Bulgarian"),
+ SwLanguageListItem("CS", "Czech"),
+ SwLanguageListItem("DA", "Danish"),
+ SwLanguageListItem("DE", "German"),
+ SwLanguageListItem("EL", "Greek"),
+ SwLanguageListItem("EN-GB", "English (British)"),
+ SwLanguageListItem("EN-US", "English (American)"),
+ SwLanguageListItem("ES", "Spanish"),
+ SwLanguageListItem("ET", "Estonian"),
+ SwLanguageListItem("FI", "Finnish"),
+ SwLanguageListItem("FR", "French"),
+ SwLanguageListItem("HU", "Hungarian"),
+ SwLanguageListItem("ID", "Indonesian"),
+ SwLanguageListItem("IT", "Italian"),
+ SwLanguageListItem("JA", "Japanese"),
+ SwLanguageListItem("LT", "Lithuanian"),
+ SwLanguageListItem("LV", "Latvian"),
+ SwLanguageListItem("NL", "Dutch"),
+ SwLanguageListItem("PL", "Polish"),
+ SwLanguageListItem("PT-BR", "Portuguese (Brazilian)"),
+ SwLanguageListItem("PT-PT", "Portuguese (European)"),
+ SwLanguageListItem("RO", "Romanian"),
+ SwLanguageListItem("RU", "Russian"),
+ SwLanguageListItem("SK", "Slovak"),
+ SwLanguageListItem("SL", "Slovenian"),
+ SwLanguageListItem("SV", "Swedish"),
+ SwLanguageListItem("TR", "Turkish"),
+ SwLanguageListItem("ZH", "Chinese (simplified)"),
+ })
+ , m_bTranslationStarted(false)
+ , m_bCancelTranslation(false)
+{
+ m_xLanguageListBox->connect_changed(LINK(this, SwTranslateLangSelectDlg, LangSelectHdl));
+ m_xBtnCancel->connect_clicked(LINK(this, SwTranslateLangSelectDlg, LangSelectCancelHdl));
+ m_xBtnTranslate->connect_clicked(LINK(this, SwTranslateLangSelectDlg, LangSelectTranslateHdl));
+
+ for (const auto& item : m_xLanguageVec)
+ {
+ m_xLanguageListBox->append_text(OStringToOUString(item.getName(), RTL_TEXTENCODING_UTF8));
+ }
+
+ if (SwTranslateLangSelectDlg::selectedLangIdx != -1)
+ {
+ m_xLanguageListBox->set_active(SwTranslateLangSelectDlg::selectedLangIdx);
+ }
+}
+
+std::optional<SwLanguageListItem> SwTranslateLangSelectDlg::GetSelectedLanguage()
+{
+ if (SwTranslateLangSelectDlg::selectedLangIdx != -1)
+ {
+ return m_xLanguageVec.at(SwTranslateLangSelectDlg::selectedLangIdx);
+ }
+
+ return {};
+}
+
+IMPL_LINK(SwTranslateLangSelectDlg, LangSelectHdl, weld::ComboBox&, rBox, void)
+{
+ const auto selected = rBox.get_active();
+ SwTranslateLangSelectDlg::selectedLangIdx = selected;
+}
+
+IMPL_LINK(SwTranslateLangSelectDlg, LangSelectCancelHdl, weld::Button&, rButton, void)
+{
+ (void)rButton;
+
+ // stop translation first
+ if (m_bTranslationStarted)
+ m_bCancelTranslation = true;
+ else
+ m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK(SwTranslateLangSelectDlg, LangSelectTranslateHdl, weld::Button&, rButton, void)
+{
+ (void)rButton;
+
+ if (SwTranslateLangSelectDlg::selectedLangIdx == -1)
+ {
+ m_xDialog->response(RET_CANCEL);
+ return;
+ }
+
+ SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+ if (rDeeplOptions.getAPIUrl().isEmpty() || rDeeplOptions.getAuthKey().isEmpty())
+ {
+ SAL_WARN("langselectdlg", "API options are not set");
+ m_xDialog->response(RET_CANCEL);
+ return;
+ }
+
+ const OString aAPIUrl
+ = OUStringToOString(OUString(rDeeplOptions.getAPIUrl() + "?tag_handling=html"),
+ RTL_TEXTENCODING_UTF8)
+ .trim();
+ const OString aAuthKey
+ = OUStringToOString(rDeeplOptions.getAuthKey(), RTL_TEXTENCODING_UTF8).trim();
+ const auto aTargetLang
+ = m_xLanguageVec.at(SwTranslateLangSelectDlg::selectedLangIdx).getLanguage();
+
+ m_bTranslationStarted = true;
+
+ SwTranslateHelper::TranslateAPIConfig aConfig({ aAPIUrl, aAuthKey, aTargetLang });
+ SwTranslateHelper::TranslateDocumentCancellable(rWrtSh, aConfig, m_bCancelTranslation);
+ m_xDialog->response(RET_OK);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/table/splittbl.cxx b/sw/source/ui/table/splittbl.cxx
index 0deb5d03093c..0af89a160121 100644
--- a/sw/source/ui/table/splittbl.cxx
+++ b/sw/source/ui/table/splittbl.cxx
@@ -28,21 +28,12 @@ SwSplitTableDlg::SwSplitTableDlg(weld::Window* pParent, SwWrtShell& rSh)
, m_xBoxAttrCopyNoParaRB(m_xBuilder->weld_radio_button("customheading"))
, m_xBorderCopyRB(m_xBuilder->weld_radio_button("noheading"))
, rShell(rSh)
- , m_nSplit(SplitTable_HeadlineOption::ContentCopy)
{
}
void SwSplitTableDlg::Apply()
{
- m_nSplit = SplitTable_HeadlineOption::ContentCopy;
- if (m_xBoxAttrCopyWithParaRB->get_active())
- m_nSplit = SplitTable_HeadlineOption::BoxAttrAllCopy;
- else if (m_xBoxAttrCopyNoParaRB->get_active())
- m_nSplit = SplitTable_HeadlineOption::BoxAttrCopy;
- else if (m_xBorderCopyRB->get_active())
- m_nSplit = SplitTable_HeadlineOption::BorderCopy;
-
- rShell.SplitTable(m_nSplit);
+ rShell.SplitTable(GetSplitMode());
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/uno/swdetect.cxx b/sw/source/ui/uno/swdetect.cxx
index 9e354dedaf6b..83b7162ae2a0 100644
--- a/sw/source/ui/uno/swdetect.cxx
+++ b/sw/source/ui/uno/swdetect.cxx
@@ -24,6 +24,7 @@
#include <com/sun/star/uno/XComponentContext.hpp>
#include <sfx2/docfile.hxx>
#include <sot/storage.hxx>
+#include <tools/urlobj.hxx>
#include <unotools/mediadescriptor.hxx>
using namespace ::com::sun::star;
@@ -102,19 +103,29 @@ OUString SAL_CALL SwFilterDetect::detect( Sequence< PropertyValue >& lDescriptor
// mis-detect it.
if ( bIsDetected && aTypeName == "writer_MS_Word_97_Vorlage" )
{
+ // It is common practice to rename a .doc to .dot to make it a template.
+ // Since we have detected a.doc-ish format, always accept .dot-named-files
+ // as valid templates to avoid flagging this as an invalid .dot format..
+ INetURLObject aParser(aMediaDesc.getUnpackedValueOrDefault(
+ utl::MediaDescriptor::PROP_URL, OUString()));
+
// Super ugly hack, but we don't want to use the whole WW8Fib thing here in
// the swd library, apparently. We know (do we?) that the "aBits1" byte, as
// the variable is called in WW8Fib::WW8Fib(SvStream&,sal_uInt8,sal_uInt32),
// is at offset 10 in the WordDocument stream. The fDot bit is bit 0x01 of
// that byte.
- tools::SvRef<SotStorageStream> xWordDocument = aStorage->OpenSotStream("WordDocument", StreamMode::STD_READ);
- xWordDocument->Seek( 10 );
- if ( xWordDocument->Tell() == 10 )
+ if (aParser.getExtension().toAsciiLowerCase() != "dot")
{
- sal_uInt8 aBits1;
- xWordDocument->ReadUChar( aBits1 );
- // Check fDot bit
- bIsDetected = ((aBits1 & 0x01) == 0x01);
+ tools::SvRef<SotStorageStream> xWordDocument
+ = aStorage->OpenSotStream("WordDocument", StreamMode::STD_READ);
+ xWordDocument->Seek(10);
+ if (xWordDocument->Tell() == 10)
+ {
+ sal_uInt8 aBits1;
+ xWordDocument->ReadUChar(aBits1);
+ // Check fDot bit
+ bIsDetected = ((aBits1 & 0x01) == 0x01);
+ }
}
}
}
diff --git a/sw/source/ui/vba/vbaapplication.cxx b/sw/source/ui/vba/vbaapplication.cxx
index 7aa61e93cef2..a9e4231f3eec 100644
--- a/sw/source/ui/vba/vbaapplication.cxx
+++ b/sw/source/ui/vba/vbaapplication.cxx
@@ -36,6 +36,7 @@
#include "vbaaddins.hxx"
#include "vbamailmerge.hxx"
#include "vbadialogs.hxx"
+#include "vbawordbasic.hxx"
#include <ooo/vba/XConnectionPoint.hpp>
#include <ooo/vba/word/WdEnableCancelKey.hpp>
#include <ooo/vba/word/WdWindowState.hpp>
@@ -68,69 +69,6 @@ public:
void SAL_CALL Unadvise( sal_uInt32 Cookie ) override;
};
-class SwWordBasic : public cppu::WeakImplHelper<word::XWordBasic>
-{
-private:
- SwVbaApplication* mpApp;
-
-public:
- SwWordBasic( SwVbaApplication* pApp );
-
- // XWordBasic
- virtual sal_Int32 SAL_CALL getMailMergeMainDocumentType() override;
- virtual void SAL_CALL setMailMergeMainDocumentType( sal_Int32 _mailmergemaindocumenttype ) override;
-
- virtual void SAL_CALL FileOpen( const OUString& Name, const uno::Any& ConfirmConversions, const uno::Any& ReadOnly, const uno::Any& AddToMru, const uno::Any& PasswordDoc, const uno::Any& PasswordDot, const uno::Any& Revert, const uno::Any& WritePasswordDoc, const uno::Any& WritePasswordDot ) override;
- virtual void SAL_CALL FileSave() override;
- virtual void SAL_CALL FileSaveAs( const css::uno::Any& Name,
- const css::uno::Any& Format,
- const css::uno::Any& LockAnnot,
- const css::uno::Any& Password,
- const css::uno::Any& AddToMru,
- const css::uno::Any& WritePassword,
- const css::uno::Any& RecommendReadOnly,
- const css::uno::Any& EmbedFonts,
- const css::uno::Any& NativePictureFormat,
- const css::uno::Any& FormsData,
- const css::uno::Any& SaveAsAOCELetter ) override;
- virtual void SAL_CALL FileClose( const css::uno::Any& Save ) override;
- virtual void SAL_CALL ToolsOptionsView( const css::uno::Any& DraftFont,
- const css::uno::Any& WrapToWindow,
- const css::uno::Any& PicturePlaceHolders,
- const css::uno::Any& FieldCodes,
- const css::uno::Any& BookMarks,
- const css::uno::Any& FieldShading,
- const css::uno::Any& StatusBar,
- const css::uno::Any& HScroll,
- const css::uno::Any& VScroll,
- const css::uno::Any& StyleAreaWidth,
- const css::uno::Any& Tabs,
- const css::uno::Any& Spaces,
- const css::uno::Any& Paras,
- const css::uno::Any& Hyphens,
- const css::uno::Any& Hidden,
- const css::uno::Any& ShowAll,
- const css::uno::Any& Drawings,
- const css::uno::Any& Anchors,
- const css::uno::Any& TextBoundaries,
- const css::uno::Any& VRuler,
- const css::uno::Any& Highlight ) override;
- virtual css::uno::Any SAL_CALL WindowName( const css::uno::Any& Number ) override;
- virtual css::uno::Any SAL_CALL ExistingBookmark( const OUString& Name ) override;
- virtual void SAL_CALL MailMergeOpenDataSource(const OUString& Name, const css::uno::Any& Format,
- const css::uno::Any& ConfirmConversions, const css::uno::Any& ReadOnly,
- const css::uno::Any& LinkToSource, const css::uno::Any& AddToRecentFiles,
- const css::uno::Any& PasswordDocument, const css::uno::Any& PasswordTemplate,
- const css::uno::Any& Revert, const css::uno::Any& WritePasswordDocument,
- const css::uno::Any& WritePasswordTemplate, const css::uno::Any& Connection,
- const css::uno::Any& SQLStatement, const css::uno::Any& SQLStatement1,
- const css::uno::Any& OpenExclusive, const css::uno::Any& SubType) override;
- virtual css::uno::Any SAL_CALL AppMaximize( const css::uno::Any& WindowName, const css::uno::Any& State ) override;
- virtual css::uno::Any SAL_CALL DocMaximize( const css::uno::Any& State ) override;
- virtual void SAL_CALL AppShow( const css::uno::Any& WindowName ) override;
- virtual css::uno::Any SAL_CALL AppCount() override;
-};
-
}
SwVbaApplication::SwVbaApplication( uno::Reference<uno::XComponentContext >& xContext ):
@@ -241,7 +179,7 @@ SwVbaApplication::Documents( const uno::Any& index )
uno::Reference< XCollection > xCol( new SwVbaDocuments( this, mxContext ) );
if ( index.hasValue() )
return xCol->Item( index, uno::Any() );
- return uno::makeAny( xCol );
+ return uno::Any( xCol );
}
uno::Any SAL_CALL
@@ -250,7 +188,7 @@ SwVbaApplication::Addins( const uno::Any& index )
static uno::Reference< XCollection > xCol( new SwVbaAddins( this, mxContext ) );
if ( index.hasValue() )
return xCol->Item( index, uno::Any() );
- return uno::makeAny( xCol );
+ return uno::Any( xCol );
}
uno::Any SAL_CALL
@@ -259,7 +197,7 @@ SwVbaApplication::Dialogs( const uno::Any& index )
uno::Reference< word::XDialogs > xCol( new SwVbaDialogs( this, mxContext, getCurrentDocument() ));
if ( index.hasValue() )
return xCol->Item( index );
- return uno::makeAny( xCol );
+ return uno::Any( xCol );
}
uno::Any SAL_CALL
@@ -269,7 +207,7 @@ SwVbaApplication::ListGalleries( const uno::Any& index )
uno::Reference< XCollection > xCol( new SwVbaListGalleries( this, mxContext, xTextDoc ) );
if ( index.hasValue() )
return xCol->Item( index, uno::Any() );
- return uno::makeAny( xCol );
+ return uno::Any( xCol );
}
sal_Bool SAL_CALL SwVbaApplication::getDisplayAutoCompleteTips()
@@ -528,247 +466,4 @@ SwVbaApplicationOutgoingConnectionPoint::Unadvise( sal_uInt32 Cookie )
mpApp->RemoveSink( Cookie );
}
-// SwWordBasic
-
-SwWordBasic::SwWordBasic( SwVbaApplication* pApp ) :
- mpApp(pApp)
-{
-}
-
-// XWordBasic
-sal_Int32 SAL_CALL
-SwWordBasic::getMailMergeMainDocumentType()
-{
- return SwVbaMailMerge::get( mpApp->getParent(), mpApp->getContext() )->getMainDocumentType();
-}
-
-// XWordBasic
-void SAL_CALL
-SwWordBasic::setMailMergeMainDocumentType( sal_Int32 _mailmergemaindocumenttype )
-{
- SwVbaMailMerge::get( mpApp->getParent(), mpApp->getContext() )->setMainDocumentType( _mailmergemaindocumenttype );
-}
-
-void SAL_CALL
-SwWordBasic::FileOpen( const OUString& Name, const uno::Any& ConfirmConversions, const uno::Any& ReadOnly, const uno::Any& AddToMru, const uno::Any& PasswordDoc, const uno::Any& PasswordDot, const uno::Any& Revert, const uno::Any& WritePasswordDoc, const uno::Any& WritePasswordDot )
-{
- uno::Any aDocuments = mpApp->Documents( uno::Any() );
-
- uno::Reference<word::XDocuments> rDocuments;
-
- if (aDocuments >>= rDocuments)
- rDocuments->Open( Name, ConfirmConversions, ReadOnly, AddToMru, PasswordDoc, PasswordDot, Revert, WritePasswordDoc, WritePasswordDot, uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any() );
-}
-
-void SAL_CALL
-SwWordBasic::FileSave()
-{
- uno::Reference< frame::XModel > xModel( mpApp->getCurrentDocument(), uno::UNO_SET_THROW );
- dispatchRequests(xModel,".uno:Save");
-}
-
-void SAL_CALL
-SwWordBasic::FileSaveAs( const css::uno::Any& Name,
- const css::uno::Any& Format,
- const css::uno::Any& /*LockAnnot*/,
- const css::uno::Any& /*Password*/,
- const css::uno::Any& /*AddToMru*/,
- const css::uno::Any& /*WritePassword*/,
- const css::uno::Any& /*RecommendReadOnly*/,
- const css::uno::Any& /*EmbedFonts*/,
- const css::uno::Any& /*NativePictureFormat*/,
- const css::uno::Any& /*FormsData*/,
- const css::uno::Any& /*SaveAsAOCELetter*/ )
-{
- SAL_INFO("sw.vba", "WordBasic.FileSaveAs(Name:=" << Name << ",Format:=" << Format << ")");
-
- uno::Reference< frame::XModel > xModel( mpApp->getCurrentDocument(), uno::UNO_SET_THROW );
-
- // Based on SwVbaDocument::SaveAs2000.
-
- OUString sFileName;
- Name >>= sFileName;
-
- OUString sURL;
- osl::FileBase::getFileURLFromSystemPath( sFileName, sURL );
-
- // Detect if there is no path then we need to use the current folder.
- INetURLObject aURL( sURL );
- sURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
- if( sURL.isEmpty() )
- {
- // Need to add cur dir ( of this document ) or else the 'Work' dir
- sURL = xModel->getURL();
-
- if ( sURL.isEmpty() )
- {
- // Not path available from 'this' document. Need to add the 'document'/work directory then.
- // Based on SwVbaOptions::getValueEvent()
- uno::Reference< util::XPathSettings > xPathSettings = util::thePathSettings::get( comphelper::getProcessComponentContext() );
- OUString sPathUrl;
- xPathSettings->getPropertyValue( "Work" ) >>= sPathUrl;
- // Path could be a multipath, Microsoft doesn't support this feature in Word currently.
- // Only the last path is from interest.
- // No idea if this crack is relevant for WordBasic or not.
- sal_Int32 nIndex = sPathUrl.lastIndexOf( ';' );
- if( nIndex != -1 )
- {
- sPathUrl = sPathUrl.copy( nIndex + 1 );
- }
-
- aURL.SetURL( sPathUrl );
- }
- else
- {
- aURL.SetURL( sURL );
- aURL.Append( sFileName );
- }
- sURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
-
- }
- sal_Int32 nFileFormat = word::WdSaveFormat::wdFormatDocument;
- Format >>= nFileFormat;
-
- uno::Sequence aProps{ comphelper::makePropertyValue("FilterName", css::uno::Any()),
- comphelper::makePropertyValue("FileName", sURL) };
-
- setFilterPropsFromFormat( nFileFormat, aProps );
-
- dispatchRequests(xModel,".uno:SaveAs",aProps);
-}
-
-void SAL_CALL
-SwWordBasic::FileClose( const css::uno::Any& Save )
-{
- uno::Reference< frame::XModel > xModel( mpApp->getCurrentDocument(), uno::UNO_SET_THROW );
-
- sal_Int16 nSave = 0;
- if (Save.hasValue() && (Save >>= nSave) && (nSave == 0 || nSave == 1))
- FileSave();
-
- // FIXME: Here I would much prefer to call VbaDocumentBase::Close() but not sure how to get at
- // the VbaDocumentBase of the current document. (Probably it is easy and I haven't looked hard
- // enough.)
- //
- // FIXME: Error handling. If there is no current document, return some kind of error? But for
- // now, just ignore errors. This code is written to work for a very specific customer use case
- // anyway, not for an arbitrary sequence of COM calls to the "VBA" API.
- dispatchRequests(xModel,".uno:CloseDoc");
-}
-
-void SAL_CALL
-SwWordBasic::ToolsOptionsView( const css::uno::Any& DraftFont,
- const css::uno::Any& WrapToWindow,
- const css::uno::Any& PicturePlaceHolders,
- const css::uno::Any& FieldCodes,
- const css::uno::Any& BookMarks,
- const css::uno::Any& FieldShading,
- const css::uno::Any& StatusBar,
- const css::uno::Any& HScroll,
- const css::uno::Any& VScroll,
- const css::uno::Any& StyleAreaWidth,
- const css::uno::Any& Tabs,
- const css::uno::Any& Spaces,
- const css::uno::Any& Paras,
- const css::uno::Any& Hyphens,
- const css::uno::Any& Hidden,
- const css::uno::Any& ShowAll,
- const css::uno::Any& Drawings,
- const css::uno::Any& Anchors,
- const css::uno::Any& TextBoundaries,
- const css::uno::Any& VRuler,
- const css::uno::Any& Highlight )
-{
- SAL_INFO("sw.vba", "WordBasic.ToolsOptionsView("
- "DraftFont:=" << DraftFont
- << ", WrapToWindow:=" << WrapToWindow
- << ", PicturePlaceHolders:=" << PicturePlaceHolders
- << ", FieldCodes:=" << FieldCodes
- << ", BookMarks:=" << BookMarks
- << ", FieldShading:=" << FieldShading
- << ", StatusBar:=" << StatusBar
- << ", HScroll:=" << HScroll
- << ", VScroll:=" << VScroll
- << ", StyleAreaWidth:=" << StyleAreaWidth
- << ", Tabs:=" << Tabs
- << ", Spaces:=" << Spaces
- << ", Paras:=" << Paras
- << ", Hyphens:=" << Hyphens
- << ", Hidden:=" << Hidden
- << ", ShowAll:=" << ShowAll
- << ", Drawings:=" << Drawings
- << ", Anchors:=" << Anchors
- << ", TextBoundaries:=" << TextBoundaries
- << ", VRuler:=" << VRuler
- << ", Highlight:=" << Highlight
- << ")");
-}
-
-css::uno::Any SAL_CALL
-SwWordBasic::WindowName( const css::uno::Any& /*Number*/ )
-{
- return css::uno::makeAny( mpApp->getActiveSwVbaWindow()->getCaption() );
-}
-
-css::uno::Any SAL_CALL
-SwWordBasic::ExistingBookmark( const OUString& Name )
-{
- uno::Reference< word::XBookmarks > xBookmarks( mpApp->getActiveDocument()->Bookmarks( uno::Any() ), uno::UNO_QUERY );
- return css::uno::makeAny( xBookmarks.is() && xBookmarks->Exists( Name ) );
-}
-
-void SAL_CALL
-SwWordBasic::MailMergeOpenDataSource( const OUString& Name, const css::uno::Any& Format,
- const css::uno::Any& ConfirmConversions, const css::uno::Any& ReadOnly,
- const css::uno::Any& LinkToSource, const css::uno::Any& AddToRecentFiles,
- const css::uno::Any& PasswordDocument, const css::uno::Any& PasswordTemplate,
- const css::uno::Any& Revert, const css::uno::Any& WritePasswordDocument,
- const css::uno::Any& WritePasswordTemplate, const css::uno::Any& Connection,
- const css::uno::Any& SQLStatement, const css::uno::Any& SQLStatement1,
- const css::uno::Any& OpenExclusive, const css::uno::Any& SubType )
-{
- mpApp->getActiveDocument()->getMailMerge()->OpenDataSource( Name, Format, ConfirmConversions, ReadOnly,
- LinkToSource, AddToRecentFiles,
- PasswordDocument, PasswordTemplate,
- Revert, WritePasswordDocument,
- WritePasswordTemplate, Connection,
- SQLStatement, SQLStatement1,
- OpenExclusive, SubType );
-}
-
-css::uno::Any SAL_CALL
-SwWordBasic::AppMaximize( const css::uno::Any& WindowName, const css::uno::Any& State )
-{
- SAL_INFO("sw.vba", "WordBasic.AppMaximize( WindowName:=" << WindowName << ", State:=" << State);
-
- // FIXME: Implement if necessary
- return css::uno::makeAny( sal_Int32(0) );
-}
-
-css::uno::Any SAL_CALL
-SwWordBasic::DocMaximize( const css::uno::Any& State )
-{
- SAL_INFO("sw.vba", "WordBasic.DocMaximize(State:=" << State << ")");
-
- // FIXME: Implement if necessary
- return css::uno::makeAny( sal_Int32(0) );
-}
-
-void SAL_CALL
-SwWordBasic::AppShow( const css::uno::Any& WindowName )
-{
- SAL_INFO("sw.vba", "WordBasic.AppShow(WindowName:=" << WindowName << ")");
-
- // FIXME: Implement if necessary
-}
-
-css::uno::Any SAL_CALL
-SwWordBasic::AppCount()
-{
- SAL_INFO("sw.vba", "WordBasic.AppCount()");
-
- // FIXME: Implement if necessary. Return a random number for now.
- return css::uno::makeAny( sal_Int32(2) );
-}
-
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbacontentcontrol.cxx b/sw/source/ui/vba/vbacontentcontrol.cxx
new file mode 100644
index 000000000000..8e8d8a12382b
--- /dev/null
+++ b/sw/source/ui/vba/vbacontentcontrol.cxx
@@ -0,0 +1,753 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <ooo/vba/word/WdColor.hpp>
+#include <ooo/vba/word/WdCalendarType.hpp>
+#include <ooo/vba/word/WdContentControlType.hpp>
+#include <ooo/vba/word/WdLanguageID.hpp>
+
+#include <sal/log.hxx>
+
+#include <ndtxt.hxx>
+#include <unotextrange.hxx>
+
+#include "vbacontentcontrol.hxx"
+#include "vbacontentcontrollistentries.hxx"
+#include "vbarange.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+/**
+ * Content controls are the modern version of FormFields, providing inline functionality similar
+ * to that of ActiveX form controls. Individual content controls may contain contents
+ * such as dates, lists, or paragraphs of formatted text.
+ *
+ * Not all functions are applicable to each type of control, so use getType verification liberally.
+ */
+SwVbaContentControl::SwVbaContentControl(const uno::Reference<XHelperInterface>& rParent,
+ const uno::Reference<uno::XComponentContext>& rContext,
+ const uno::Reference<text::XTextDocument>& xTextDocument,
+ std::shared_ptr<SwContentControl> pContentControl)
+ : SwVbaContentControl_BASE(rParent, rContext)
+ , mxTextDocument(xTextDocument)
+ , m_pCC(pContentControl)
+{
+ assert(m_pCC && "SwVbaContentControl created without a shared_ptr. Why would you do that?");
+}
+
+SwVbaContentControl::~SwVbaContentControl() {}
+
+sal_Bool SwVbaContentControl::getAllowInsertDeleteSection()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getAllowInsertDeleteSection stub");
+ return false;
+}
+
+void SwVbaContentControl::setAllowInsertDeleteSection(sal_Bool /*bSet*/)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setAllowInsertDeleteSection stub");
+}
+
+sal_Int32 SwVbaContentControl::getAppearance()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getAppearance stub");
+ // wdContentControlBoundingBox / wdContentControlHidden / wdContentControlTags
+ return 0;
+}
+
+void SwVbaContentControl::setAppearance(sal_Int32 nSet)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setAppearance[" << nSet << "] stub");
+}
+
+OUString SwVbaContentControl::getBuildingBlockCategory()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getBuildingBlockCategory stub");
+ return OUString();
+}
+
+void SwVbaContentControl::setBuildingBlockCategory(const OUString& sSet)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setBuildingBlockCategory[" << sSet << "] stub");
+}
+
+sal_Int32 SwVbaContentControl::getBuildingBlockType()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getBuildingBlockType stub");
+ // returns a WdBuildingBlockTypes that represents the type of building block
+ return 0;
+}
+
+void SwVbaContentControl::setBuildingBlockType(sal_Int32 nSet)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setBuildingBlockType[" << nSet << "] stub");
+}
+
+sal_Bool SwVbaContentControl::getChecked() { return m_pCC->GetCheckbox() && m_pCC->GetChecked(); }
+
+void SwVbaContentControl::setChecked(sal_Bool bSet)
+{
+ // Word 2010: if locked, then the checked status is changed, but not the underlying text.
+ // Do we really want to do that? That is pretty bizarre behaviour...
+ // For now, just implement what seems to be a more logical response.
+ // TODO: test with modern versions.
+ if (getLockContents())
+ return;
+
+ if (m_pCC->GetCheckbox() && m_pCC->GetChecked() != static_cast<bool>(bSet))
+ {
+ m_pCC->SetChecked(bSet);
+ m_pCC->SetShowingPlaceHolder(false);
+ if (m_pCC->GetTextAttr())
+ m_pCC->GetTextAttr()->Invalidate();
+ }
+}
+
+sal_Int32 SwVbaContentControl::getColor()
+{
+ //This is just an assumed implementation - I have no testing environment to confirm.
+ OUString sColor = m_pCC->GetColor();
+ if (sColor == "wdColorAutomatic")
+ return word::WdColor::wdColorAutomatic;
+ if (sColor == "wdColorBlack")
+ return word::WdColor::wdColorBlack;
+ if (sColor == "wdColorBlue")
+ return word::WdColor::wdColorBlue;
+ if (sColor == "wdColorBlueGray")
+ return word::WdColor::wdColorBlueGray;
+ if (sColor == "wdColorBrightGreen")
+ return word::WdColor::wdColorBrightGreen;
+ if (sColor == "wdColorBrown")
+ return word::WdColor::wdColorBrown;
+ if (sColor == "wdColorDarkBlue")
+ return word::WdColor::wdColorDarkBlue;
+ if (sColor == "wdColorDarkGreen")
+ return word::WdColor::wdColorDarkGreen;
+ if (sColor == "wdColorDarkRed")
+ return word::WdColor::wdColorDarkRed;
+ if (sColor == "wdColorDarkTeal")
+ return word::WdColor::wdColorDarkTeal;
+ if (sColor == "wdColorDarkYellow")
+ return word::WdColor::wdColorDarkYellow;
+ if (sColor == "wdColorGold")
+ return word::WdColor::wdColorGold;
+ if (sColor == "wdColorGray05")
+ return word::WdColor::wdColorGray05;
+ if (sColor == "wdColorGray10")
+ return word::WdColor::wdColorGray10;
+ if (sColor == "wdColorGray125")
+ return word::WdColor::wdColorGray125;
+ if (sColor == "wdColorGray15")
+ return word::WdColor::wdColorGray15;
+ if (sColor == "wdColorGray20")
+ return word::WdColor::wdColorGray20;
+ if (sColor == "wdColorGray25")
+ return word::WdColor::wdColorGray25;
+ if (sColor == "wdColorGray30")
+ return word::WdColor::wdColorGray30;
+ if (sColor == "wdColorGray35")
+ return word::WdColor::wdColorGray35;
+ if (sColor == "wdColorGray375")
+ return word::WdColor::wdColorGray375;
+ if (sColor == "wdColorGray40")
+ return word::WdColor::wdColorGray40;
+ if (sColor == "wdColorGray45")
+ return word::WdColor::wdColorGray45;
+ if (sColor == "wdColorGray50")
+ return word::WdColor::wdColorGray50;
+ if (sColor == "wdColorGray55")
+ return word::WdColor::wdColorGray55;
+ if (sColor == "wdColorGray60")
+ return word::WdColor::wdColorGray60;
+ if (sColor == "wdColorGray625")
+ return word::WdColor::wdColorGray625;
+ if (sColor == "wdColorGray65")
+ return word::WdColor::wdColorGray65;
+ if (sColor == "wdColorGray70")
+ return word::WdColor::wdColorGray70;
+ if (sColor == "wdColorGray75")
+ return word::WdColor::wdColorGray75;
+ if (sColor == "wdColorGray80")
+ return word::WdColor::wdColorGray80;
+ if (sColor == "wdColorGray85")
+ return word::WdColor::wdColorGray85;
+ if (sColor == "wdColorGray875")
+ return word::WdColor::wdColorGray875;
+ if (sColor == "wdColorGray90")
+ return word::WdColor::wdColorGray90;
+ if (sColor == "wdColorGray95")
+ return word::WdColor::wdColorGray95;
+ if (sColor == "wdColorGreen")
+ return word::WdColor::wdColorGreen;
+ if (sColor == "wdColorIndigo")
+ return word::WdColor::wdColorIndigo;
+ if (sColor == "wdColorLavender")
+ return word::WdColor::wdColorLavender;
+ if (sColor == "wdColorLightBlue")
+ return word::WdColor::wdColorLightBlue;
+ if (sColor == "wdColorLightGreen")
+ return word::WdColor::wdColorLightGreen;
+ if (sColor == "wdColorLightOrange")
+ return word::WdColor::wdColorLightOrange;
+ if (sColor == "wdColorLightTurquoise")
+ return word::WdColor::wdColorLightTurquoise;
+ if (sColor == "wdColorLightYellow")
+ return word::WdColor::wdColorLightYellow;
+ if (sColor == "wdColorLime")
+ return word::WdColor::wdColorLime;
+ if (sColor == "wdColorOliveGreen")
+ return word::WdColor::wdColorOliveGreen;
+ if (sColor == "wdColorOrange")
+ return word::WdColor::wdColorOrange;
+ if (sColor == "wdColorPaleBlue")
+ return word::WdColor::wdColorPaleBlue;
+ if (sColor == "wdColorPink")
+ return word::WdColor::wdColorPink;
+ if (sColor == "wdColorPlum")
+ return word::WdColor::wdColorPlum;
+ if (sColor == "wdColorRed")
+ return word::WdColor::wdColorRed;
+ if (sColor == "wdColorRose")
+ return word::WdColor::wdColorRose;
+ if (sColor == "wdColorSeaGreen")
+ return word::WdColor::wdColorSeaGreen;
+ if (sColor == "wdColorSkyBlue")
+ return word::WdColor::wdColorSkyBlue;
+ if (sColor == "wdColorTan")
+ return word::WdColor::wdColorTan;
+ if (sColor == "wdColorTeal")
+ return word::WdColor::wdColorTeal;
+ if (sColor == "wdColorTurquoise")
+ return word::WdColor::wdColorTurquoise;
+ if (sColor == "wdColorViolet")
+ return word::WdColor::wdColorViolet;
+ if (sColor == "wdColorWhite")
+ return word::WdColor::wdColorWhite;
+ if (sColor == "wdColorYellow")
+ return word::WdColor::wdColorYellow;
+
+ return word::WdColor::wdColorBlack;
+}
+
+void SwVbaContentControl::setColor(sal_Int32 nWdColor)
+{
+ switch (nWdColor)
+ {
+ case word::WdColor::wdColorAqua:
+ m_pCC->SetColor("wdColorAqua");
+ break;
+ case word::WdColor::wdColorAutomatic:
+ m_pCC->SetColor("wdColorAutomatic");
+ break;
+ case word::WdColor::wdColorBlack:
+ m_pCC->SetColor("wdColorBlack");
+ break;
+ case word::WdColor::wdColorBlue:
+ m_pCC->SetColor("wdColorBlue");
+ break;
+ case word::WdColor::wdColorBlueGray:
+ m_pCC->SetColor("wdColorBlueGray");
+ break;
+ case word::WdColor::wdColorBrightGreen:
+ m_pCC->SetColor("wdColorBrightGreen");
+ break;
+ case word::WdColor::wdColorBrown:
+ m_pCC->SetColor("wdColorBrown");
+ break;
+ case word::WdColor::wdColorDarkBlue:
+ m_pCC->SetColor("wdColorDarkBlue");
+ break;
+ case word::WdColor::wdColorDarkGreen:
+ m_pCC->SetColor("wdColorDarkGreen");
+ break;
+ case word::WdColor::wdColorDarkRed:
+ m_pCC->SetColor("wdColorDarkRed");
+ break;
+ case word::WdColor::wdColorDarkTeal:
+ m_pCC->SetColor("wdColorDarkTeal");
+ break;
+ case word::WdColor::wdColorDarkYellow:
+ m_pCC->SetColor("wdColorDarkYellow");
+ break;
+ case word::WdColor::wdColorGold:
+ m_pCC->SetColor("wdColorGold");
+ break;
+ case word::WdColor::wdColorGray05:
+ m_pCC->SetColor("wdColorGray05");
+ break;
+ case word::WdColor::wdColorGray10:
+ m_pCC->SetColor("wdColorGray10");
+ break;
+ case word::WdColor::wdColorGray125:
+ m_pCC->SetColor("wdColorGray125");
+ break;
+ case word::WdColor::wdColorGray15:
+ m_pCC->SetColor("wdColorGray15");
+ break;
+ case word::WdColor::wdColorGray20:
+ m_pCC->SetColor("wdColorGray20");
+ break;
+ case word::WdColor::wdColorGray25:
+ m_pCC->SetColor("wdColorGray25");
+ break;
+ case word::WdColor::wdColorGray30:
+ m_pCC->SetColor("wdColorGray30");
+ break;
+ case word::WdColor::wdColorGray35:
+ m_pCC->SetColor("wdColorGray35");
+ break;
+ case word::WdColor::wdColorGray375:
+ m_pCC->SetColor("wdColorGray375");
+ break;
+ case word::WdColor::wdColorGray40:
+ m_pCC->SetColor("wdColorGray40");
+ break;
+ case word::WdColor::wdColorGray45:
+ m_pCC->SetColor("wdColorGray45");
+ break;
+ case word::WdColor::wdColorGray50:
+ m_pCC->SetColor("wdColorGray50");
+ break;
+ case word::WdColor::wdColorGray55:
+ m_pCC->SetColor("wdColorGray55");
+ break;
+ case word::WdColor::wdColorGray60:
+ m_pCC->SetColor("wdColorGray60");
+ break;
+ case word::WdColor::wdColorGray625:
+ m_pCC->SetColor("wdColorGray625");
+ break;
+ case word::WdColor::wdColorGray65:
+ m_pCC->SetColor("wdColorGray65");
+ break;
+ case word::WdColor::wdColorGray70:
+ m_pCC->SetColor("wdColorGray70");
+ break;
+ case word::WdColor::wdColorGray75:
+ m_pCC->SetColor("wdColorGray75");
+ break;
+ case word::WdColor::wdColorGray80:
+ m_pCC->SetColor("wdColorGray80");
+ break;
+ case word::WdColor::wdColorGray85:
+ m_pCC->SetColor("wdColorGray85");
+ break;
+ case word::WdColor::wdColorGray875:
+ m_pCC->SetColor("wdColorGray875");
+ break;
+ case word::WdColor::wdColorGray90:
+ m_pCC->SetColor("wdColorGray90");
+ break;
+ case word::WdColor::wdColorGray95:
+ m_pCC->SetColor("wdColorGray95");
+ break;
+ case word::WdColor::wdColorGreen:
+ m_pCC->SetColor("wdColorGreen");
+ break;
+ case word::WdColor::wdColorIndigo:
+ m_pCC->SetColor("wdColorIndigo");
+ break;
+ case word::WdColor::wdColorLavender:
+ m_pCC->SetColor("wdColorLavender");
+ break;
+ case word::WdColor::wdColorLightBlue:
+ m_pCC->SetColor("wdColorLightBlue");
+ break;
+ case word::WdColor::wdColorLightGreen:
+ m_pCC->SetColor("wdColorLightGreen");
+ break;
+ case word::WdColor::wdColorLightOrange:
+ m_pCC->SetColor("wdColorLightOrange");
+ break;
+ case word::WdColor::wdColorLightTurquoise:
+ m_pCC->SetColor("wdColorLightTurquoise");
+ break;
+ case word::WdColor::wdColorLightYellow:
+ m_pCC->SetColor("wdColorLightYellow");
+ break;
+ case word::WdColor::wdColorLime:
+ m_pCC->SetColor("wdColorLime");
+ break;
+ case word::WdColor::wdColorOliveGreen:
+ m_pCC->SetColor("wdColorOliveGreen");
+ break;
+ case word::WdColor::wdColorOrange:
+ m_pCC->SetColor("wdColorOrange");
+ break;
+ case word::WdColor::wdColorPaleBlue:
+ m_pCC->SetColor("wdColorPaleBlue");
+ break;
+ case word::WdColor::wdColorPink:
+ m_pCC->SetColor("wdColorPink");
+ break;
+ case word::WdColor::wdColorPlum:
+ m_pCC->SetColor("wdColorPlum");
+ break;
+ case word::WdColor::wdColorRed:
+ m_pCC->SetColor("wdColorRed");
+ break;
+ case word::WdColor::wdColorRose:
+ m_pCC->SetColor("wdColorRose");
+ break;
+ case word::WdColor::wdColorSeaGreen:
+ m_pCC->SetColor("wdColorSeaGreen");
+ break;
+ case word::WdColor::wdColorSkyBlue:
+ m_pCC->SetColor("wdColorSkyBlue");
+ break;
+ case word::WdColor::wdColorTan:
+ m_pCC->SetColor("wdColorTan");
+ break;
+ case word::WdColor::wdColorTeal:
+ m_pCC->SetColor("wdColorTeal");
+ break;
+ case word::WdColor::wdColorTurquoise:
+ m_pCC->SetColor("wdColorTurquoise");
+ break;
+ case word::WdColor::wdColorViolet:
+ m_pCC->SetColor("wdColorViolet");
+ break;
+ case word::WdColor::wdColorWhite:
+ m_pCC->SetColor("wdColorWhite");
+ break;
+ default:;
+ }
+}
+
+sal_Int32 SwVbaContentControl::getDateCalendarType()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getDateCalendarType stub");
+ // returns a WdCalendarTypes that represents the type of building block
+ return word::WdCalendarType::wdCalendarWestern;
+}
+
+void SwVbaContentControl::setDateCalendarType(sal_Int32 nSet)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setDateCalendarType[" << nSet << "] stub");
+}
+
+OUString SwVbaContentControl::getDateDisplayFormat() { return m_pCC->GetDateFormat(); }
+
+void SwVbaContentControl::setDateDisplayFormat(const OUString& sSet) { m_pCC->SetDateFormat(sSet); }
+
+sal_Int32 SwVbaContentControl::getDateStorageFormat()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getDateStorageFormat stub");
+ // returns a WdContentControlDateStorageFormat when bound to the XML data store.
+ return 0;
+}
+
+void SwVbaContentControl::setDateStorageFormat(sal_Int32 nSet)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setDateStorageFormat[" << nSet << "] stub");
+}
+
+sal_Int32 SwVbaContentControl::getDateDisplayLocale()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getDateDisplayLocale stub");
+ // returns a WdLanguageID that represents the language format for a date content control.
+ return word::WdLanguageID::wdEnglishUS;
+}
+
+uno::Any SwVbaContentControl::getDropdownListEntries()
+{
+ if (!m_pCC->GetDropDown() && !m_pCC->GetComboBox())
+ return uno::Any();
+
+ return uno::Any(
+ uno::Reference<XCollection>(new SwVbaContentControlListEntries(this, mxContext, m_pCC)));
+}
+
+OUString SwVbaContentControl::getID()
+{
+ // This signed integer is treated in VBA as if it was an unsigned int.
+ return OUString::number(static_cast<sal_uInt32>(m_pCC->GetId()));
+}
+
+sal_Int32 SwVbaContentControl::getLevel()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getLevel stub");
+ // returns a WdContentControlLevel
+ return 0;
+}
+
+sal_Bool SwVbaContentControl::getLockContentControl()
+{
+ std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/true);
+ return oLock && *oLock;
+}
+
+void SwVbaContentControl::setLockContentControl(sal_Bool bSet)
+{
+ std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/false);
+ m_pCC->SetLock(/*bContents=*/oLock && *oLock, /*bControl=*/bSet);
+}
+
+sal_Bool SwVbaContentControl::getLockContents()
+{
+ // If the theoretical design model says it is locked, then report as locked.
+ std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/false);
+ if (oLock && *oLock)
+ return true;
+
+ // Now check the real implementation.
+ // Checkbox/DropDown/Picture are normally locked - but not in this sense. Report as unlocked.
+ if (m_pCC->GetType() == SwContentControlType::CHECKBOX
+ || m_pCC->GetType() == SwContentControlType::DROP_DOWN_LIST
+ || m_pCC->GetType() == SwContentControlType::PICTURE)
+ {
+ return false;
+ }
+
+ return m_pCC->GetReadWrite();
+}
+
+void SwVbaContentControl::setLockContents(sal_Bool bSet)
+{
+ // Set the lock both theoretically and actually.
+ std::optional<bool> oLock = m_pCC->GetLock(/*bControl=*/true);
+ m_pCC->SetLock(/*bContents=*/bSet, /*bControl=*/oLock && *oLock);
+
+ // Checkbox/DropDown/Picture are normally locked in LO implementation - don't unlock them.
+ if (m_pCC->GetType() == SwContentControlType::CHECKBOX
+ || m_pCC->GetType() == SwContentControlType::DROP_DOWN_LIST
+ || m_pCC->GetType() == SwContentControlType::PICTURE)
+ {
+ return;
+ }
+ m_pCC->SetReadWrite(bSet);
+}
+
+sal_Bool SwVbaContentControl::getMultiLine()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getMultiLine stub");
+ return false;
+}
+
+void SwVbaContentControl::setMultiLine(sal_Bool /*bSet*/)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setMultiLine stub");
+}
+
+OUString SwVbaContentControl::getPlaceholderText()
+{
+ // return m_pCC->GetPlaceholderDocPart(); // This is not correct. Much more complex than this...
+ SAL_INFO("sw.vba", "SwVbaContentControl::getPlaceholderText stub");
+ return OUString();
+}
+
+sal_Bool SwVbaContentControl::getShowingPlaceholderText() { return m_pCC->GetShowingPlaceHolder(); }
+
+uno::Reference<word::XRange> SwVbaContentControl::getRange()
+{
+ uno::Reference<word::XRange> xRet;
+ SwTextNode* pTextNode = m_pCC->GetTextNode();
+ if (pTextNode && m_pCC->GetTextAttr())
+ {
+ // Don't select the text attribute itself at the start.
+ SwPosition aStart(*pTextNode, m_pCC->GetTextAttr()->GetStart() + 1);
+ // Don't select the CH_TXTATR_BREAKWORD itself at the end.
+ SwPosition aEnd(*pTextNode, *m_pCC->GetTextAttr()->End() - 1);
+ uno::Reference<text::XTextRange> xText(
+ SwXTextRange::CreateXTextRange(pTextNode->GetDoc(), aStart, &aEnd));
+ if (xText.is())
+ xRet = new SwVbaRange(mxParent, mxContext, mxTextDocument, xText->getStart(),
+ xText->getEnd());
+ }
+ return xRet;
+}
+
+OUString SwVbaContentControl::getRepeatingSectionItemTitle()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getRepeatingSectionItemTitle stub");
+ return OUString();
+}
+
+void SwVbaContentControl::setRepeatingSectionItemTitle(const OUString& rSet)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setRepeatingSectionItemTitle[" << rSet << "] stub");
+}
+
+OUString SwVbaContentControl::getTag() { return m_pCC->GetTag(); }
+
+void SwVbaContentControl::setTag(const OUString& rSet) { return m_pCC->SetTag(rSet); }
+
+sal_Bool SwVbaContentControl::getTemporary()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::getTemporary stub");
+ // Is content control removed when user edits (one time use)? Not implemented in LO.
+ return false;
+}
+
+void SwVbaContentControl::setTemporary(sal_Bool /*bSet*/)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setTemporary stub");
+}
+
+OUString SwVbaContentControl::getTitle() { return m_pCC->GetAlias(); }
+
+void SwVbaContentControl::setTitle(const OUString& rSet) { return m_pCC->SetAlias(rSet); }
+
+sal_Int32 SwVbaContentControl::getType()
+{
+ SwContentControlType eType = m_pCC->GetType();
+ sal_Int32 eVbaType = word::WdContentControlType::wdContentControlRichText;
+
+ switch (eType)
+ {
+ case SwContentControlType::CHECKBOX:
+ eVbaType = word::WdContentControlType::wdContentControlCheckbox;
+ break;
+ case SwContentControlType::DROP_DOWN_LIST:
+ eVbaType = word::WdContentControlType::wdContentControlDropdownList;
+ break;
+ case SwContentControlType::PICTURE:
+ eVbaType = word::WdContentControlType::wdContentControlPicture;
+ break;
+ case SwContentControlType::DATE:
+ eVbaType = word::WdContentControlType::wdContentControlDate;
+ break;
+ case SwContentControlType::PLAIN_TEXT:
+ eVbaType = word::WdContentControlType::wdContentControlText;
+ break;
+ case SwContentControlType::COMBO_BOX:
+ eVbaType = word::WdContentControlType::wdContentControlComboBox;
+ break;
+ case SwContentControlType::RICH_TEXT:
+ default:;
+ }
+ return eVbaType;
+}
+
+void SwVbaContentControl::setType(sal_Int32 nSet)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::setType[" << nSet << "] stub");
+ // SwContentControlType eType = SwContentControlType::RICH_TEXT;
+ // switch(nSet)
+ // {
+ // case word::WdContentControlType::wdContentControlCheckbox:
+ // eType = SwContentControlType::CHECKBOX;
+ // break;
+ // case word::WdContentControlType::wdContentControlDropdownList:
+ // eType = SwContentControlType::DROP_DOWN_LIST;
+ // break;
+ // case word::WdContentControlType::wdContentControlPicture:
+ // eType = SwContentControlType::PICTURE;
+ // break;
+ // case word::WdContentControlType::wdContentControlDate:
+ // eType = SwContentControlType::DATE;
+ // break;
+ // case word::WdContentControlType::wdContentControlText:
+ // eType = SwContentControlType::PLAIN_TEXT;
+ // break;
+ // case word::WdContentControlType::wdContentControlComboBox:
+ // eType = SwContentControlType::COMBO_BOX;
+ // break;
+ // case word::WdContentControlType::wdContentControlRichText:
+ // default:;
+ // }
+ // m_pCC->SetType(eType);
+}
+
+void SwVbaContentControl::Copy()
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::Copy[" << getID() << "] stub");
+}
+
+void SwVbaContentControl::Cut()
+{
+ if (getLockContentControl() || !m_pCC->GetTextAttr())
+ return;
+
+ SAL_INFO("sw.vba",
+ "SwVbaContentControl::Cut[" << getID() << "], but missing sending to clipboard");
+
+ m_pCC->GetTextAttr()->Delete(/*bSaveContents=*/getLockContents());
+}
+
+void SwVbaContentControl::Delete(const uno::Any& DeleteContents)
+{
+ if (getLockContentControl() || !m_pCC->GetTextAttr())
+ return;
+
+ bool bDeleteContents = false;
+ DeleteContents >>= bDeleteContents;
+
+ m_pCC->GetTextAttr()->Delete(/*bSaveContents=*/!bDeleteContents || getLockContents());
+}
+
+void SwVbaContentControl::SetCheckedSymbol(sal_Int32 Character, const uno::Any& Font)
+{
+ if (!m_pCC->GetTextAttr())
+ return;
+
+ SAL_INFO_IF(Font.hasValue(), "sw.vba", "SetCheckedSymbol Font[" << Font << "] stub");
+ if (Character < 31 || Character > SAL_MAX_UINT16)
+ return; // unsupported character. Would such a thing exist in VBA?
+
+ m_pCC->SetCheckedState(OUString(static_cast<sal_Unicode>(Character)));
+
+ if (m_pCC->GetCheckbox() && m_pCC->GetChecked() && !m_pCC->GetShowingPlaceHolder())
+ m_pCC->GetTextAttr()->Invalidate();
+}
+
+void SwVbaContentControl::SetUnCheckedSymbol(sal_Int32 Character, const uno::Any& Font)
+{
+ if (!m_pCC->GetTextAttr())
+ return;
+
+ SAL_INFO_IF(Font.hasValue(), "sw.vba", "SetUnCheckedSymbol Font[" << Font << "] stub");
+ if (Character < 31 || Character > SAL_MAX_UINT16)
+ return; // unsupported character. Would such a thing exist in VBA?
+
+ m_pCC->SetUncheckedState(OUString(static_cast<sal_Unicode>(Character)));
+
+ if (m_pCC->GetCheckbox() && !m_pCC->GetChecked() && !m_pCC->GetShowingPlaceHolder())
+ m_pCC->GetTextAttr()->Invalidate();
+}
+
+void SwVbaContentControl::SetPlaceholderText(const uno::Any& BuildingBlock, const uno::Any& Range,
+ const uno::Any& Text)
+{
+ SAL_INFO("sw.vba", "SwVbaContentControl::SetPlaceholderText stub");
+ if (BuildingBlock.hasValue())
+ {
+ // Set placeholder text to the building block - whatever that is.
+ }
+ else if (Range.hasValue())
+ {
+ // Set placeholder text to the contents of the Range, however you do that.
+ }
+ else if (Text.hasValue())
+ {
+ // Set placeholder text to the provided string
+ }
+ else
+ {
+ // Remove placeholder text.
+ m_pCC->SetPlaceholderDocPart("");
+ }
+ if (m_pCC->GetShowingPlaceHolder() && !getLockContents() && m_pCC->GetTextAttr())
+ {
+ //replace the text and ensure showing placeholder is still set
+ }
+}
+
+void SwVbaContentControl::Ungroup() { SAL_INFO("sw.vba", "SwVbaContentControl::UnGroup stub"); }
+
+OUString SwVbaContentControl::getServiceImplName() { return "SwVbaContentControl"; }
+
+uno::Sequence<OUString> SwVbaContentControl::getServiceNames()
+{
+ static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.ContentControl" };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbacontentcontrol.hxx b/sw/source/ui/vba/vbacontentcontrol.hxx
new file mode 100644
index 000000000000..9f98b92468b5
--- /dev/null
+++ b/sw/source/ui/vba/vbacontentcontrol.hxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <ooo/vba/word/XContentControl.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+#include <textcontentcontrol.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XContentControl> SwVbaContentControl_BASE;
+
+class SwVbaContentControl : public SwVbaContentControl_BASE
+{
+private:
+ css::uno::Reference<css::text::XTextDocument> mxTextDocument;
+ std::shared_ptr<SwContentControl> m_pCC;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaContentControl(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const css::uno::Reference<css::uno::XComponentContext>& rContext,
+ const css::uno::Reference<css::text::XTextDocument>& xTextDocument,
+ std::shared_ptr<SwContentControl> pContentControl);
+ ~SwVbaContentControl() override;
+
+ // XContentControl Properties
+ sal_Bool SAL_CALL getAllowInsertDeleteSection() override;
+ void SAL_CALL setAllowInsertDeleteSection(sal_Bool bSet) override;
+
+ sal_Int32 SAL_CALL getAppearance() override;
+ void SAL_CALL setAppearance(sal_Int32 nSet) override;
+
+ OUString SAL_CALL getBuildingBlockCategory() override;
+ void SAL_CALL setBuildingBlockCategory(const OUString& sSet) override;
+
+ sal_Int32 SAL_CALL getBuildingBlockType() override;
+ void SAL_CALL setBuildingBlockType(sal_Int32 nSet) override;
+
+ sal_Bool SAL_CALL getChecked() override;
+ void SAL_CALL setChecked(sal_Bool bSet) override;
+
+ // returns or sets a WdColor (@since after 2010 I assume)
+ sal_Int32 SAL_CALL getColor() override;
+ void SAL_CALL setColor(sal_Int32 nSet) override;
+
+ sal_Int32 SAL_CALL getDateCalendarType() override;
+ void SAL_CALL setDateCalendarType(sal_Int32 nSet) override;
+
+ OUString SAL_CALL getDateDisplayFormat() override;
+ void SAL_CALL setDateDisplayFormat(const OUString& sSet) override;
+
+ sal_Int32 SAL_CALL getDateDisplayLocale() override;
+
+ sal_Int32 SAL_CALL getDateStorageFormat() override;
+ void SAL_CALL setDateStorageFormat(sal_Int32 nSet) override;
+
+ css::uno::Any SAL_CALL getDropdownListEntries() override;
+
+ // This is an integer used as a unique identifier string
+ OUString SAL_CALL getID() override;
+
+ sal_Int32 SAL_CALL getLevel() override;
+
+ // returns or sets if the user can delete the control
+ sal_Bool SAL_CALL getLockContentControl() override;
+ void SAL_CALL setLockContentControl(sal_Bool bSet) override;
+
+ // returns or sets if the user can edit the contents (i.e. read-only flag)
+ sal_Bool SAL_CALL getLockContents() override;
+ void SAL_CALL setLockContents(sal_Bool bSet) override;
+
+ sal_Bool SAL_CALL getMultiLine() override;
+ void SAL_CALL setMultiLine(sal_Bool bSet) override;
+
+ // WRONG- THIS SHOULD RETURN XBUILDINGBLOCK
+ OUString SAL_CALL getPlaceholderText() override;
+
+ sal_Bool SAL_CALL getShowingPlaceholderText() override;
+
+ OUString SAL_CALL getRepeatingSectionItemTitle() override;
+ void SAL_CALL setRepeatingSectionItemTitle(const OUString& rSet) override;
+
+ css::uno::Reference<ooo::vba::word::XRange> SAL_CALL getRange() override;
+
+ OUString SAL_CALL getTag() override;
+ void SAL_CALL setTag(const OUString& rSet) override;
+
+ // returns or sets if the control is removed after accepting user change (i.e. control -> text)
+ sal_Bool SAL_CALL getTemporary() override;
+ void SAL_CALL setTemporary(sal_Bool bSet) override;
+
+ OUString SAL_CALL getTitle() override;
+ void SAL_CALL setTitle(const OUString& rSet) override;
+
+ // returns or sets a WdContentControlType that represents the type for a content control.
+ sal_Int32 SAL_CALL getType() override;
+ void SAL_CALL setType(sal_Int32 nSet) override;
+
+ // XContentControl Methods
+
+ // Copies the content control from the active document to the Clipboard.
+ // Retrieve from the clipboard using the Paste method of the Selection object
+ // or of the Range object, or use the Paste function from within Microsoft Word.
+ void SAL_CALL Copy() override;
+
+ // Removes the control from the active document and moves it to the Clipboard.
+ void SAL_CALL Cut() override;
+
+ // Specifies whether to delete the contents of the content control. The default value is False.
+ // True removes both the content control and its contents.
+ // False removes the control but leaves the contents of the content control in the document.
+ void SAL_CALL Delete(const css::uno::Any& bDeleteContents) override;
+
+ // Set the Unicode character used to display the checked state.
+ void SAL_CALL SetCheckedSymbol(sal_Int32 Character, const css::uno::Any& sFont) override;
+
+ // Set the Unicode character used to display the unchecked state.
+ void SAL_CALL SetUnCheckedSymbol(sal_Int32 Character, const css::uno::Any& sFont) override;
+
+ // Sets the placeholder text that displays until a user enters their own text.
+ // Only one of the parameters is used when specifying placeholder text.
+ // If more than one parameter is provided, use the text specified in the first parameter.
+ // If all parameters are omitted, the placeholder text is blank.
+ void SAL_CALL SetPlaceholderText(const css::uno::Any& BuildingBlock, const css::uno::Any& Range,
+ const css::uno::Any& sText) override;
+
+ void SAL_CALL Ungroup() override;
+
+ // XHelperInterface
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbacontentcontrollistentries.cxx b/sw/source/ui/vba/vbacontentcontrollistentries.cxx
new file mode 100644
index 000000000000..996df011a149
--- /dev/null
+++ b/sw/source/ui/vba/vbacontentcontrollistentries.cxx
@@ -0,0 +1,166 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "vbacontentcontrollistentries.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+namespace
+{
+class ContentControlListEntriesEnumWrapper : public EnumerationHelper_BASE
+{
+ uno::Reference<container::XIndexAccess> mxIndexAccess;
+ sal_Int32 nIndex;
+
+public:
+ explicit ContentControlListEntriesEnumWrapper(
+ uno::Reference<container::XIndexAccess> xIndexAccess)
+ : mxIndexAccess(xIndexAccess)
+ , nIndex(0)
+ {
+ }
+
+ virtual sal_Bool SAL_CALL hasMoreElements() override
+ {
+ return (nIndex < mxIndexAccess->getCount());
+ }
+
+ virtual uno::Any SAL_CALL nextElement() override
+ {
+ if (nIndex < mxIndexAccess->getCount())
+ {
+ return mxIndexAccess->getByIndex(nIndex++);
+ }
+ throw container::NoSuchElementException();
+ }
+};
+
+class ContentControlListEntryCollectionHelper
+ : public ::cppu::WeakImplHelper<container::XIndexAccess, container::XEnumerationAccess>
+{
+private:
+ uno::Reference<XHelperInterface> mxParent;
+ uno::Reference<uno::XComponentContext> mxContext;
+ std::shared_ptr<SwContentControl> m_pCC;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ContentControlListEntryCollectionHelper(uno::Reference<ov::XHelperInterface> xParent,
+ uno::Reference<uno::XComponentContext> xContext,
+ std::shared_ptr<SwContentControl> pCC)
+ : mxParent(xParent)
+ , mxContext(xContext)
+ , m_pCC(pCC)
+ {
+ }
+
+ sal_Int32 SAL_CALL getCount() override { return m_pCC->GetListItems().size(); }
+
+ uno::Any SAL_CALL getByIndex(sal_Int32 Index) override
+ {
+ if (Index < 0 || Index >= getCount())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(uno::Reference<word::XContentControlListEntry>(
+ new SwVbaContentControlListEntry(mxParent, mxContext, m_pCC, Index)));
+ }
+
+ uno::Type SAL_CALL getElementType() override
+ {
+ return cppu::UnoType<word::XContentControlListEntry>::get();
+ }
+
+ sal_Bool SAL_CALL hasElements() override { return getCount() != 0; }
+
+ // XEnumerationAccess
+ uno::Reference<container::XEnumeration> SAL_CALL createEnumeration() override
+ {
+ return new ContentControlListEntriesEnumWrapper(this);
+ }
+};
+}
+
+/**
+ * DropDownLists and ComboBoxes contain a list of name/value pairs to choose from.
+ * Use of DropDownListEntries from any other control is invalid.
+ */
+SwVbaContentControlListEntries::SwVbaContentControlListEntries(
+ const uno::Reference<XHelperInterface>& xParent,
+ const uno::Reference<uno::XComponentContext>& xContext, std::shared_ptr<SwContentControl> pCC)
+ : SwVbaContentControlListEntries_BASE(
+ xParent, xContext,
+ uno::Reference<container::XIndexAccess>(
+ new ContentControlListEntryCollectionHelper(xParent, xContext, pCC)))
+ , m_pCC(pCC)
+{
+}
+
+uno::Reference<word::XContentControlListEntry>
+SwVbaContentControlListEntries::Add(const OUString& rName, const uno::Any& rValue,
+ const uno::Any& rIndex)
+{
+ // No duplicate Names allowed in VBA
+ for (auto& rListItem : m_pCC->GetListItems())
+ {
+ if (rListItem.ToString() == rName)
+ return uno::Reference<word::XContentControlListEntry>();
+ }
+
+ sal_Int32 nZIndex = SAL_MAX_INT32;
+ rIndex >>= nZIndex;
+ // rIndex is 1-based, nZIndex is 0-based. If rIndex is not given, then add as the last choice.
+ assert(nZIndex > 0);
+ --nZIndex;
+ nZIndex = std::min(static_cast<size_t>(nZIndex), m_pCC->GetListItems().size());
+
+ OUString sValue;
+ rValue >>= sValue;
+ if (m_pCC->AddListItem(nZIndex, rName, sValue))
+ {
+ return uno::Reference<word::XContentControlListEntry>(
+ new SwVbaContentControlListEntry(mxParent, mxContext, m_pCC, nZIndex));
+ }
+
+ return uno::Reference<word::XContentControlListEntry>();
+}
+
+void SwVbaContentControlListEntries::Clear() { m_pCC->ClearListItems(); }
+
+sal_Int32 SwVbaContentControlListEntries::getCount() { return m_pCC->GetListItems().size(); }
+
+// XEnumerationAccess
+uno::Type SwVbaContentControlListEntries::getElementType()
+{
+ return cppu::UnoType<word::XContentControlListEntry>::get();
+}
+
+uno::Reference<container::XEnumeration> SwVbaContentControlListEntries::createEnumeration()
+{
+ return new ContentControlListEntriesEnumWrapper(m_xIndexAccess);
+}
+
+// SwVbaContentControlListEntries_BASE
+uno::Any SwVbaContentControlListEntries::createCollectionObject(const uno::Any& aSource)
+{
+ return aSource;
+}
+
+OUString SwVbaContentControlListEntries::getServiceImplName()
+{
+ return "SwVbaContentControlListEntries";
+}
+
+uno::Sequence<OUString> SwVbaContentControlListEntries::getServiceNames()
+{
+ static uno::Sequence<OUString> const sNames{ "ooo.vba.word.ContentControlListEntries" };
+ return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbacontentcontrollistentries.hxx b/sw/source/ui/vba/vbacontentcontrollistentries.hxx
new file mode 100644
index 000000000000..dc32203179dc
--- /dev/null
+++ b/sw/source/ui/vba/vbacontentcontrollistentries.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <ooo/vba/word/XContentControlListEntries.hpp>
+#include <ooo/vba/word/XContentControlListEntry.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+#include <textcontentcontrol.hxx>
+
+#include "vbacontentcontrollistentries.hxx"
+#include "vbacontentcontrollistentry.hxx"
+
+typedef CollTestImplHelper<ooo::vba::word::XContentControlListEntries>
+ SwVbaContentControlListEntries_BASE;
+
+class SwVbaContentControlListEntries : public SwVbaContentControlListEntries_BASE
+{
+private:
+ std::shared_ptr<SwContentControl> m_pCC;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaContentControlListEntries(const css::uno::Reference<ov::XHelperInterface>& xParent,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ std::shared_ptr<SwContentControl> pCC);
+
+ // XContentControlListEntries
+ css::uno::Reference<ooo::vba::word::XContentControlListEntry> SAL_CALL
+ Add(const OUString& rName, const css::uno::Any& rValue, const css::uno::Any& rIndex) override;
+ void SAL_CALL Clear() override;
+ sal_Int32 SAL_CALL getCount() override;
+
+ // XEnumerationAccess
+ css::uno::Type SAL_CALL getElementType() override;
+ css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override;
+
+ // SwVbaContentControlListEntries_BASE
+ css::uno::Any createCollectionObject(const css::uno::Any& aSource) override;
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbacontentcontrollistentry.cxx b/sw/source/ui/vba/vbacontentcontrollistentry.cxx
new file mode 100644
index 000000000000..727092e083f8
--- /dev/null
+++ b/sw/source/ui/vba/vbacontentcontrollistentry.cxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "vbacontentcontrollistentry.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+SwVbaContentControlListEntry::SwVbaContentControlListEntry(
+ const uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const uno::Reference<uno::XComponentContext>& rContext, std::shared_ptr<SwContentControl> pCC,
+ size_t nZIndex)
+ : SwVbaContentControlListEntry_BASE(rParent, rContext)
+ , m_pCC(pCC)
+ , m_nZIndex(nZIndex)
+{
+}
+
+SwVbaContentControlListEntry::~SwVbaContentControlListEntry() {}
+
+sal_Int32 SwVbaContentControlListEntry::getIndex() { return m_nZIndex + 1; }
+
+void SwVbaContentControlListEntry::setIndex(sal_Int32 nSet)
+{
+ if (nSet < 1 || static_cast<size_t>(nSet) == m_nZIndex + 1)
+ return;
+
+ // Given a one-based index to set to
+ size_t nIndex = std::min(static_cast<size_t>(nSet), m_pCC->GetListItems().size());
+ // change to zero-based index
+ --nIndex;
+ while (nIndex < m_nZIndex)
+ MoveUp();
+ while (m_nZIndex < nIndex)
+ MoveDown();
+}
+
+OUString SwVbaContentControlListEntry::getText()
+{
+ assert(m_nZIndex < m_pCC->GetListItems().size());
+ // Xcode 14.2 is really fussy so create a temporary vector before fetching
+ // one of the list items
+ std::vector<SwContentControlListItem> aListItems(m_pCC->GetListItems());
+ const SwContentControlListItem& rListItem = aListItems[m_nZIndex];
+ return rListItem.ToString();
+}
+
+void SwVbaContentControlListEntry::setText(const OUString& rSet)
+{
+ std::vector<SwContentControlListItem> vListItems = m_pCC->GetListItems();
+ assert(m_nZIndex < vListItems.size());
+
+ // prevent duplicates
+ for (size_t i = 0; i < vListItems.size(); ++i)
+ {
+ if (vListItems[i].ToString() == rSet)
+ return;
+ }
+
+ const std::optional<size_t> oSel(m_pCC->GetSelectedListItem(/*bCheckDocModel=*/true));
+ const bool bNeedsInvalidation = m_pCC->GetDropDown() && oSel && *oSel == m_nZIndex;
+
+ vListItems[m_nZIndex].m_aDisplayText = rSet;
+ m_pCC->SetListItems(vListItems);
+
+ if (bNeedsInvalidation)
+ {
+ m_pCC->SetSelectedListItem(m_nZIndex);
+ if (m_pCC->GetTextAttr())
+ m_pCC->GetTextAttr()->Invalidate();
+ }
+}
+
+OUString SwVbaContentControlListEntry::getValue()
+{
+ assert(m_nZIndex < m_pCC->GetListItems().size());
+ // Xcode 14.2 is really fussy so create a temporary vector before fetching
+ // one of the list items
+ std::vector<SwContentControlListItem> aListItems(m_pCC->GetListItems());
+ const SwContentControlListItem& rListItem = aListItems[m_nZIndex];
+
+ return rListItem.m_aValue;
+}
+
+void SwVbaContentControlListEntry::setValue(const OUString& rSet)
+{
+ assert(m_nZIndex < m_pCC->GetListItems().size());
+ std::vector<SwContentControlListItem> vListItems = m_pCC->GetListItems();
+
+ // LO may pull the display text from Value. Ensure changing Value doesn't alter display text.
+ if (vListItems[m_nZIndex].m_aDisplayText.isEmpty())
+ vListItems[m_nZIndex].m_aDisplayText = vListItems[m_nZIndex].ToString();
+
+ vListItems[m_nZIndex].m_aValue = rSet;
+ m_pCC->SetListItems(vListItems);
+}
+
+void SwVbaContentControlListEntry::Delete() { m_pCC->DeleteListItem(m_nZIndex); }
+
+void SwVbaContentControlListEntry::MoveDown()
+{
+ // if already at last position, can't move down
+ if (m_nZIndex >= m_pCC->GetListItems().size() - 1)
+ return;
+
+ const std::optional<size_t> oSelected = m_pCC->GetSelectedListItem(/*bCheckDocModel=*/false);
+ if (oSelected)
+ {
+ if (*oSelected == m_nZIndex)
+ m_pCC->SetSelectedListItem(m_nZIndex + 1);
+ else if (*oSelected == m_nZIndex + 1)
+ m_pCC->SetSelectedListItem(*oSelected - 1);
+ }
+ std::vector<SwContentControlListItem> vListItems = m_pCC->GetListItems();
+ std::swap(vListItems[m_nZIndex], vListItems[m_nZIndex + 1]);
+ m_pCC->SetListItems(vListItems);
+ ++m_nZIndex;
+}
+
+void SwVbaContentControlListEntry::MoveUp()
+{
+ // if already at position 0, can't move up
+ if (!m_nZIndex || m_nZIndex >= m_pCC->GetListItems().size())
+ return;
+
+ const std::optional<size_t> oSelected = m_pCC->GetSelectedListItem(/*bCheckDocModel=*/false);
+ if (oSelected)
+ {
+ if (*oSelected == m_nZIndex)
+ m_pCC->SetSelectedListItem(m_nZIndex - 1);
+ else if (*oSelected == m_nZIndex - 1)
+ m_pCC->SetSelectedListItem(*oSelected + 1);
+ }
+ std::vector<SwContentControlListItem> vListItems = m_pCC->GetListItems();
+ std::swap(vListItems[m_nZIndex], vListItems[m_nZIndex - 1]);
+ m_pCC->SetListItems(vListItems);
+ --m_nZIndex;
+}
+
+void SwVbaContentControlListEntry::Select()
+{
+ assert(m_nZIndex < m_pCC->GetListItems().size());
+ m_pCC->SetSelectedListItem(m_nZIndex);
+ m_pCC->SetShowingPlaceHolder(false);
+ if (m_pCC->GetTextAttr())
+ m_pCC->GetTextAttr()->Invalidate();
+}
+
+// XHelperInterface
+OUString SwVbaContentControlListEntry::getServiceImplName()
+{
+ return "SwVbaContentControlListEntry";
+}
+
+uno::Sequence<OUString> SwVbaContentControlListEntry::getServiceNames()
+{
+ static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.ContentControlListEntry" };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbacontentcontrollistentry.hxx b/sw/source/ui/vba/vbacontentcontrollistentry.hxx
new file mode 100644
index 000000000000..bb55eade34d5
--- /dev/null
+++ b/sw/source/ui/vba/vbacontentcontrollistentry.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <ooo/vba/word/XContentControlListEntry.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+#include <textcontentcontrol.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XContentControlListEntry>
+ SwVbaContentControlListEntry_BASE;
+
+class SwVbaContentControlListEntry : public SwVbaContentControlListEntry_BASE
+{
+private:
+ std::shared_ptr<SwContentControl> m_pCC;
+ // All LO and internal UNO functions are 0-based. Convert to 1-based when sending to VBA
+ size_t m_nZIndex;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaContentControlListEntry(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const css::uno::Reference<css::uno::XComponentContext>& rContext,
+ std::shared_ptr<SwContentControl> pCC, size_t nZIndex);
+ ~SwVbaContentControlListEntry() override;
+
+ // XContentControlListEntry
+ sal_Int32 SAL_CALL getIndex() override;
+ void SAL_CALL setIndex(sal_Int32 nSet) override;
+
+ OUString SAL_CALL getText() override;
+ void SAL_CALL setText(const OUString& sSet) override;
+
+ OUString SAL_CALL getValue() override;
+ void SAL_CALL setValue(const OUString& sSet) override;
+
+ void SAL_CALL Delete() override;
+ void SAL_CALL MoveDown() override;
+ void SAL_CALL MoveUp() override;
+ void SAL_CALL Select() override;
+
+ // XHelperInterface
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbacontentcontrols.cxx b/sw/source/ui/vba/vbacontentcontrols.cxx
new file mode 100644
index 000000000000..3886fe76968f
--- /dev/null
+++ b/sw/source/ui/vba/vbacontentcontrols.cxx
@@ -0,0 +1,268 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <comphelper/sequence.hxx>
+#include <sal/log.hxx>
+
+#include <doc.hxx>
+#include <docsh.hxx>
+#include <textcontentcontrol.hxx>
+
+#include "vbacontentcontrol.hxx"
+#include "vbacontentcontrols.hxx"
+#include "wordvbahelper.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+// Helper function to access the content controls
+// @param rIndex
+// [in] negative indexes indicate the need to search by name, otherwise get by index,
+// using SAL_MAX_INT32 to indicate the need to just get the total count.
+// [out] rIndex indicates the found index, or the total number of content controls
+static std::shared_ptr<SwContentControl>
+lcl_getContentControl(std::u16string_view sName, std::u16string_view sTag,
+ std::u16string_view sTitle, sal_Int32& rIndex,
+ const uno::Reference<text::XTextDocument>& xTextDocument,
+ uno::Sequence<OUString>* pElementNames = nullptr)
+{
+ SwDoc* pDoc = word::getDocShell(xTextDocument)->GetDoc();
+ if (!pDoc)
+ return nullptr;
+
+ assert(sTag.empty() || sTitle.empty()); // only one grouping at a time is allowed
+
+ std::shared_ptr<SwContentControl> pControl;
+ std::vector<OUString> vElementNames;
+ SwContentControlManager& rManager = pDoc->GetContentControlManager();
+ const size_t nLen = rManager.GetCount();
+ if (!pElementNames && rIndex > 0 && sName.empty() && sTag.empty() && sTitle.empty())
+ {
+ size_t i = static_cast<size_t>(rIndex);
+ // This is the normal get-by-index/getCount mode - no need for fancy filtering.
+ if (i < nLen)
+ pControl = rManager.Get(i)->GetContentControl().GetContentControl();
+ else
+ rIndex = nLen;
+ }
+ else
+ {
+ // loop through everything collecting names, filtering by Tag/Title
+ sal_Int32 nCounter = 0;
+ for (size_t i = 0; i < nLen; ++i)
+ {
+ pControl = rManager.Get(i)->GetContentControl().GetContentControl();
+ if (!sTag.empty() && sTag != pControl->GetTag())
+ {
+ pControl = nullptr;
+ continue;
+ }
+ if (!sTitle.empty() && sTitle != pControl->GetAlias())
+ {
+ pControl = nullptr;
+ continue;
+ }
+
+ // When treated as a name, consider the integer ID to be unsigned
+ const OUString sID = OUString::number(static_cast<sal_uInt32>(pControl->GetId()));
+ if (!sName.empty() && sName != sID)
+ {
+ pControl = nullptr;
+ continue;
+ }
+
+ if (pElementNames)
+ vElementNames.push_back(sID);
+
+ if (rIndex == nCounter || !sName.empty())
+ break;
+
+ pControl = nullptr;
+ ++nCounter;
+ }
+ rIndex = nCounter;
+ }
+ if (pElementNames)
+ *pElementNames = comphelper::containerToSequence(vElementNames);
+ return pControl;
+}
+
+namespace
+{
+class ContentControlsEnumWrapper : public EnumerationHelper_BASE
+{
+ uno::Reference<container::XIndexAccess> mxIndexAccess;
+ sal_Int32 nIndex;
+
+public:
+ explicit ContentControlsEnumWrapper(uno::Reference<container::XIndexAccess> xIndexAccess)
+ : mxIndexAccess(std::move(xIndexAccess))
+ , nIndex(0)
+ {
+ }
+
+ sal_Bool SAL_CALL hasMoreElements() override { return (nIndex < mxIndexAccess->getCount()); }
+
+ uno::Any SAL_CALL nextElement() override
+ {
+ if (nIndex < mxIndexAccess->getCount())
+ {
+ return mxIndexAccess->getByIndex(nIndex++);
+ }
+ throw container::NoSuchElementException();
+ }
+};
+
+class ContentControlCollectionHelper
+ : public ::cppu::WeakImplHelper<container::XNameAccess, container::XIndexAccess,
+ container::XEnumerationAccess>
+{
+private:
+ uno::Reference<XHelperInterface> mxParent;
+ uno::Reference<uno::XComponentContext> mxContext;
+ uno::Reference<text::XTextDocument> mxTextDocument;
+ const OUString m_sTag;
+ const OUString m_sTitle;
+ std::shared_ptr<SwContentControl> m_pCache;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ContentControlCollectionHelper(uno::Reference<ov::XHelperInterface> xParent,
+ uno::Reference<uno::XComponentContext> xContext,
+ uno::Reference<text::XTextDocument> xTextDocument,
+ const OUString& rTag, const OUString& rTitle)
+
+ : mxParent(std::move(xParent))
+ , mxContext(std::move(xContext))
+ , mxTextDocument(std::move(xTextDocument))
+ , m_sTag(rTag)
+ , m_sTitle(rTitle)
+ {
+ }
+
+ // XIndexAccess
+ sal_Int32 SAL_CALL getCount() override
+ {
+ sal_Int32 nCount = SAL_MAX_INT32;
+ lcl_getContentControl(u"", m_sTag, m_sTitle, nCount, mxTextDocument);
+ return nCount == SAL_MAX_INT32 || nCount < 0 ? 0 : nCount;
+ }
+
+ uno::Any SAL_CALL getByIndex(sal_Int32 Index) override
+ {
+ m_pCache = lcl_getContentControl(u"", m_sTag, m_sTitle, Index, mxTextDocument);
+ if (!m_pCache)
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(uno::Reference<word::XContentControl>(
+ new SwVbaContentControl(mxParent, mxContext, mxTextDocument, m_pCache)));
+ }
+
+ // XNameAccess
+ uno::Sequence<OUString> SAL_CALL getElementNames() override
+ {
+ sal_Int32 nCount = SAL_MAX_INT32;
+ uno::Sequence<OUString> aSeq;
+ lcl_getContentControl(u"", m_sTag, m_sTitle, nCount, mxTextDocument, &aSeq);
+ return aSeq;
+ }
+
+ uno::Any SAL_CALL getByName(const OUString& aName) override
+ {
+ if (!hasByName(aName))
+ throw container::NoSuchElementException();
+
+ return uno::Any(uno::Reference<word::XContentControl>(
+ new SwVbaContentControl(mxParent, mxContext, mxTextDocument, m_pCache)));
+ }
+
+ sal_Bool SAL_CALL hasByName(const OUString& aName) override
+ {
+ sal_Int32 nCount = -1;
+ m_pCache = lcl_getContentControl(aName, m_sTag, m_sTitle, nCount, mxTextDocument);
+ return m_pCache != nullptr;
+ }
+
+ // XElementAccess
+ uno::Type SAL_CALL getElementType() override
+ {
+ return cppu::UnoType<word::XContentControl>::get();
+ }
+
+ sal_Bool SAL_CALL hasElements() override { return getCount() != 0; }
+
+ // XEnumerationAccess
+ uno::Reference<container::XEnumeration> SAL_CALL createEnumeration() override
+ {
+ return new ContentControlsEnumWrapper(this);
+ }
+};
+}
+
+/**
+ * Content Controls can be accessed and filtered in many different ways.
+ * Surprisingly however, there is no clear, descriptive "by name" access.
+ * Instead, each content control (probably) has a unique _signed-integer_ identifier,
+ * which can be passed to Item() as a float or _unsigned-integer_ string
+ * (to differentiate it from getByIndex).
+ *
+ * Index access can be filtered by Tag, Title, Range, and XML link.
+ * TODO: add filtering for Range, SelectLinkedControls, SelectUnlinkedControls
+ */
+SwVbaContentControls::SwVbaContentControls(const uno::Reference<XHelperInterface>& xParent,
+ const uno::Reference<uno::XComponentContext>& xContext,
+ const uno::Reference<text::XTextDocument>& xTextDocument,
+ const OUString& rTag, const OUString& rTitle)
+ : SwVbaContentControls_BASE(
+ xParent, xContext,
+ uno::Reference<container::XIndexAccess>(
+ new ContentControlCollectionHelper(xParent, xContext, xTextDocument, rTag, rTitle)))
+{
+}
+
+// uno::Reference<ooo::vba::word::XContentControl> SwVbaContentControls::Add(const uno::Any& Range,
+// sal_Int32 Type)
+// {
+// sw::mark::IFieldmark* pFieldmark = nullptr;
+// switch (Type)
+// {
+// case ooo::vba::word::WdFieldType::wdFieldFormCheckBox:
+// break;
+// case ooo::vba::word::WdFieldType::wdFieldFormDropDown:
+// break;
+// case ooo::vba::word::WdFieldType::wdFieldFormTextInput:
+// default:;
+// }
+//
+// return uno::Reference<ooo::vba::word::XContentControl>(
+// new SwVbaContentControl(mxParent, mxContext, m_xTextDocument, pFieldmark));
+// }
+
+// XEnumerationAccess
+uno::Type SwVbaContentControls::getElementType()
+{
+ return cppu::UnoType<word::XContentControl>::get();
+}
+
+uno::Reference<container::XEnumeration> SwVbaContentControls::createEnumeration()
+{
+ return new ContentControlsEnumWrapper(m_xIndexAccess);
+}
+
+uno::Any SwVbaContentControls::createCollectionObject(const uno::Any& aSource) { return aSource; }
+
+OUString SwVbaContentControls::getServiceImplName() { return "SwVbaContentControls"; }
+
+uno::Sequence<OUString> SwVbaContentControls::getServiceNames()
+{
+ static uno::Sequence<OUString> const sNames{ "ooo.vba.word.ContentControls" };
+ return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbacontentcontrols.hxx b/sw/source/ui/vba/vbacontentcontrols.hxx
new file mode 100644
index 000000000000..20ff65ae8943
--- /dev/null
+++ b/sw/source/ui/vba/vbacontentcontrols.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <ooo/vba/word/XContentControls.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+typedef CollTestImplHelper<ooo::vba::word::XContentControls> SwVbaContentControls_BASE;
+
+class SwVbaContentControls : public SwVbaContentControls_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaContentControls(const css::uno::Reference<ov::XHelperInterface>& xParent,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ const css::uno::Reference<css::text::XTextDocument>& xTextDocument,
+ const OUString& rTag, const OUString& rTitle);
+
+ // XContentControls
+ //css::uno::Reference<ooo::vba::word::XContentControl> SAL_CALL Add(const css::uno::Any& Type, const css::uno::Any& Range) override;
+
+ // XEnumerationAccess
+ css::uno::Type SAL_CALL getElementType() override;
+ css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override;
+
+ // SwVbaContentControls_BASE
+ css::uno::Any createCollectionObject(const css::uno::Any& aSource) override;
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbadocument.cxx b/sw/source/ui/vba/vbadocument.cxx
index 656a2bb942e5..502636b33530 100644
--- a/sw/source/ui/vba/vbadocument.cxx
+++ b/sw/source/ui/vba/vbadocument.cxx
@@ -21,7 +21,9 @@
#include <sal/log.hxx>
#include "vbafilterpropsfromformat.hxx"
+#include "vbacontentcontrols.hxx"
#include "vbadocument.hxx"
+#include "vbaformfields.hxx"
#include "vbarange.hxx"
#include "vbarangehelper.hxx"
#include "vbadocumentproperties.hxx"
@@ -201,6 +203,32 @@ SwVbaDocument::Bookmarks( const uno::Any& rIndex )
return xBookmarksVba->Item( rIndex, uno::Any() );
}
+uno::Any SAL_CALL SwVbaDocument::ContentControls(const uno::Any& index)
+{
+ uno::Reference<XCollection> xContentControls(
+ new SwVbaContentControls(this, mxContext, mxTextDocument, "", ""));
+ if (index.hasValue())
+ return xContentControls->Item(index, uno::Any());
+
+ return uno::Any(xContentControls);
+}
+
+uno::Any SAL_CALL SwVbaDocument::SelectContentControlsByTag(const uno::Any& index)
+{
+ OUString sTag;
+ index >>= sTag;
+ return uno::Any(uno::Reference<XCollection>(
+ new SwVbaContentControls(this, mxContext, mxTextDocument, sTag, "")));
+}
+
+uno::Any SAL_CALL SwVbaDocument::SelectContentControlsByTitle(const uno::Any& index)
+{
+ OUString sTitle;
+ index >>= sTitle;
+ return uno::Any(uno::Reference<XCollection>(
+ new SwVbaContentControls(this, mxContext, mxTextDocument, "", sTitle)));
+}
+
uno::Any SAL_CALL
SwVbaDocument::Variables( const uno::Any& rIndex )
{
@@ -273,11 +301,12 @@ SwVbaDocument::TablesOfContents( const uno::Any& index )
return uno::makeAny( xCol );
}
-uno::Any SAL_CALL
-SwVbaDocument::FormFields( const uno::Any& /*index*/ )
+uno::Any SAL_CALL SwVbaDocument::FormFields(const uno::Any& index)
{
- uno::Reference< XCollection > xCol;
- return uno::makeAny( xCol );
+ uno::Reference<XCollection> xCol(new SwVbaFormFields(this, mxContext, mxTextDocument));
+ if (index.hasValue())
+ return xCol->Item(index, uno::Any());
+ return uno::Any(xCol);
}
uno::Any SAL_CALL
diff --git a/sw/source/ui/vba/vbadocument.hxx b/sw/source/ui/vba/vbadocument.hxx
index 0d213690a982..aa71de23688d 100644
--- a/sw/source/ui/vba/vbadocument.hxx
+++ b/sw/source/ui/vba/vbadocument.hxx
@@ -55,6 +55,9 @@ public:
virtual css::uno::Any SAL_CALL BuiltInDocumentProperties( const css::uno::Any& index ) override;
virtual css::uno::Any SAL_CALL CustomDocumentProperties( const css::uno::Any& index ) override;
virtual css::uno::Any SAL_CALL Bookmarks( const css::uno::Any& rIndex ) override;
+ css::uno::Any SAL_CALL ContentControls(const css::uno::Any& index) override;
+ css::uno::Any SAL_CALL SelectContentControlsByTag(const css::uno::Any& index) override;
+ css::uno::Any SAL_CALL SelectContentControlsByTitle(const css::uno::Any& index) override;
virtual css::uno::Any SAL_CALL Variables( const css::uno::Any& rIndex ) override;
virtual css::uno::Any SAL_CALL getAttachedTemplate() override;
virtual void SAL_CALL setAttachedTemplate( const css::uno::Any& _attachedtemplate ) override;
diff --git a/sw/source/ui/vba/vbaformfield.cxx b/sw/source/ui/vba/vbaformfield.cxx
new file mode 100644
index 000000000000..cde8d5e5c337
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfield.cxx
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <ooo/vba/word/WdFieldType.hpp>
+
+#include <sal/log.hxx>
+
+#include <doc.hxx>
+#include <docsh.hxx>
+#include <unotextrange.hxx>
+
+#include "vbaformfield.hxx"
+#include "vbaformfieldcheckbox.hxx"
+#include "vbaformfielddropdown.hxx"
+#include "vbaformfieldtextinput.hxx"
+#include "vbarange.hxx"
+#include "wordvbahelper.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+/**
+ * Information about the method and properties of FormFields was gathered from
+ * https://www.codevba.com/Word/FormField.htm
+ *
+ * FormFields are inline text objects that are only found in MS Word.
+ * They cannot be created in Excel or in Calc.
+ *
+ * There are three specific kinds of FormFields: CheckBox, DropDown, and TextInput.
+ */
+SwVbaFormField::SwVbaFormField(const uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const uno::Reference<uno::XComponentContext>& rContext,
+ const uno::Reference<text::XTextDocument>& xTextDocument,
+ sw::mark::IFieldmark& rFormField)
+ : SwVbaFormField_BASE(rParent, rContext)
+ , m_xTextDocument(xTextDocument)
+ , m_rFormField(rFormField)
+{
+}
+
+SwVbaFormField::~SwVbaFormField() {}
+
+uno::Any SAL_CALL SwVbaFormField::CheckBox()
+{
+ return uno::Any(uno::Reference<word::XCheckBox>(
+ new SwVbaFormFieldCheckBox(mxParent, mxContext, m_rFormField)));
+}
+
+uno::Any SAL_CALL SwVbaFormField::DropDown()
+{
+ return uno::Any(uno::Reference<word::XDropDown>(
+ new SwVbaFormFieldDropDown(mxParent, mxContext, m_rFormField)));
+}
+
+uno::Any SAL_CALL SwVbaFormField::TextInput()
+{
+ return uno::Any(uno::Reference<word::XTextInput>(
+ new SwVbaFormFieldTextInput(mxParent, mxContext, m_rFormField)));
+}
+
+uno::Any SAL_CALL SwVbaFormField::Previous()
+{
+ SwDoc* pDoc = word::getDocShell(m_xTextDocument)->GetDoc();
+ if (!pDoc)
+ return uno::Any();
+
+ const IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+ if (!pMarkAccess)
+ return uno::Any();
+
+ sw::mark::IFieldmark* pFieldMark = pMarkAccess->getFieldmarkBefore(m_rFormField.GetMarkPos(),
+ /*bLoop=*/false);
+
+ // DateFields are a LO specialty, and do not exist natively in MS documents. Ignore if added...
+ auto pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark);
+ while (pDateField)
+ {
+ pFieldMark = pMarkAccess->getFieldmarkBefore(pDateField->GetMarkPos(), /*bLoop=*/false);
+ pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark);
+ }
+
+ if (!pFieldMark)
+ return uno::Any();
+
+ return uno::Any(uno::Reference<word::XFormField>(
+ new SwVbaFormField(mxParent, mxContext, m_xTextDocument, *pFieldMark)));
+}
+
+uno::Any SAL_CALL SwVbaFormField::Next()
+{
+ SwDoc* pDoc = word::getDocShell(m_xTextDocument)->GetDoc();
+ if (!pDoc)
+ return uno::Any();
+
+ const IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+ if (!pMarkAccess)
+ return uno::Any();
+
+ sw::mark::IFieldmark* pFieldMark = pMarkAccess->getFieldmarkAfter(m_rFormField.GetMarkPos(),
+ /*bLoop=*/false);
+
+ // DateFields are a LO specialty, and do not exist natively in MS documents. Ignore if added...
+ auto pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark);
+ while (pDateField)
+ {
+ pFieldMark = pMarkAccess->getFieldmarkAfter(pDateField->GetMarkPos(), /*bLoop=*/false);
+ pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark);
+ }
+
+ if (!pFieldMark)
+ return uno::Any();
+
+ return uno::Any(uno::Reference<word::XFormField>(
+ new SwVbaFormField(mxParent, mxContext, m_xTextDocument, *pFieldMark)));
+}
+
+uno::Reference<word::XRange> SwVbaFormField::Range()
+{
+ uno::Reference<word::XRange> xRet;
+ SwDoc* pDoc = word::getDocShell(m_xTextDocument)->GetDoc();
+ if (pDoc)
+ {
+ uno::Reference<text::XTextRange> xText(SwXTextRange::CreateXTextRange(
+ *pDoc, m_rFormField.GetMarkStart(), &m_rFormField.GetMarkEnd()));
+ if (xText.is())
+ xRet = new SwVbaRange(mxParent, mxContext, m_xTextDocument, xText->getStart(),
+ xText->getEnd());
+ }
+ return xRet;
+}
+
+OUString SwVbaFormField::getDefaultPropertyName() { return "Type"; }
+
+sal_Int32 SwVbaFormField::getType()
+{
+ IDocumentMarkAccess::MarkType aType = IDocumentMarkAccess::GetType(m_rFormField);
+ if (aType == IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK)
+ return ooo::vba::word::WdFieldType::wdFieldFormCheckBox;
+ else if (aType == IDocumentMarkAccess::MarkType::TEXT_FIELDMARK)
+ return ooo::vba::word::WdFieldType::wdFieldFormTextInput;
+ return ooo::vba::word::WdFieldType::wdFieldFormDropDown;
+}
+
+sal_Bool SwVbaFormField::getCalculateOnExit()
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::getCalculateOnExit stub");
+ return false;
+}
+
+void SwVbaFormField::setCalculateOnExit(sal_Bool /*bSet*/)
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::setCalculateOnExit stub");
+}
+
+sal_Bool SwVbaFormField::getEnabled()
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::getEnabled stub");
+ return true;
+}
+
+void SwVbaFormField::setEnabled(sal_Bool /*bSet*/)
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::setEnabled stub");
+}
+
+OUString SwVbaFormField::getEntryMacro()
+{
+ OUString sMacro;
+ (*m_rFormField.GetParameters())["EntryMacro"] >>= sMacro;
+ return sMacro;
+}
+
+void SwVbaFormField::setEntryMacro(const OUString& rSet)
+{
+ (*m_rFormField.GetParameters())["EntryMacro"] <<= rSet;
+}
+
+OUString SwVbaFormField::getExitMacro()
+{
+ OUString sMacro;
+ (*m_rFormField.GetParameters())["ExitMacro"] >>= sMacro;
+ return sMacro;
+}
+
+void SwVbaFormField::setExitMacro(const OUString& rSet)
+{
+ (*m_rFormField.GetParameters())["ExitMacro"] <<= rSet;
+}
+
+OUString SwVbaFormField::getHelpText() { return m_rFormField.GetFieldHelptext(); }
+
+void SwVbaFormField::setHelpText(const OUString& rSet) { m_rFormField.SetFieldHelptext(rSet); }
+
+sal_Bool SwVbaFormField::getOwnHelp()
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::getOwnHelp stub");
+ return true;
+}
+
+void SwVbaFormField::setOwnHelp(sal_Bool /*bSet*/)
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::setOwnHelp stub");
+}
+
+OUString SwVbaFormField::getName() { return m_rFormField.GetName(); }
+
+void SwVbaFormField::setName(const OUString& rSet)
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::setName[" << rSet << "] stub");
+}
+
+OUString SwVbaFormField::getResult() { return m_rFormField.GetContent(); }
+
+void SwVbaFormField::setResult(const OUString& rSet)
+{
+ if (dynamic_cast<sw::mark::ICheckboxFieldmark*>(&m_rFormField))
+ m_rFormField.ReplaceContent("false");
+ else
+ m_rFormField.ReplaceContent(rSet);
+}
+
+OUString SwVbaFormField::getStatusText()
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::getStatusText stub");
+ return OUString();
+}
+
+void SwVbaFormField::setStatusText(const OUString& rSet)
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::setStatusText[" << rSet << "] stub");
+}
+
+sal_Bool SwVbaFormField::getOwnStatus()
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::getOwnStatus stub");
+ return true;
+}
+
+void SwVbaFormField::setOwnStatus(sal_Bool /*bSet*/)
+{
+ SAL_INFO("sw.vba", "SwVbaFormField::setOwnStatus stub");
+}
+
+OUString SwVbaFormField::getServiceImplName() { return "SwVbaFormField"; }
+
+uno::Sequence<OUString> SwVbaFormField::getServiceNames()
+{
+ static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.FormField" };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfield.hxx b/sw/source/ui/vba/vbaformfield.hxx
new file mode 100644
index 000000000000..260e79093589
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfield.hxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <ooo/vba/word/XFormField.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+#include <IDocumentMarkAccess.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XFormField> SwVbaFormField_BASE;
+
+class SwVbaFormField : public SwVbaFormField_BASE
+{
+private:
+ css::uno::Reference<css::text::XTextDocument> m_xTextDocument;
+ sw::mark::IFieldmark& m_rFormField;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaFormField(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const css::uno::Reference<css::uno::XComponentContext>& rContext,
+ const uno::Reference<text::XTextDocument>& xTextDocument,
+ sw::mark::IFieldmark& rFormField);
+ ~SwVbaFormField() override;
+
+ // XFormField Methods
+ OUString SAL_CALL getDefaultPropertyName() override;
+
+ css::uno::Any SAL_CALL CheckBox() override;
+ css::uno::Any SAL_CALL DropDown() override;
+ css::uno::Any SAL_CALL TextInput() override;
+ css::uno::Any SAL_CALL Previous() override;
+ css::uno::Any SAL_CALL Next() override;
+ css::uno::Reference<ooo::vba::word::XRange> SAL_CALL Range() override;
+
+ // Indicates which of the three form fields this is: oovbaapi/ooo/vba/word/WdFieldType.idl
+ sal_Int32 SAL_CALL getType() override;
+ // True if references to the specified form field
+ // are automatically updated whenever the field is exited
+ sal_Bool SAL_CALL getCalculateOnExit() override;
+ void SAL_CALL setCalculateOnExit(sal_Bool bSet) override;
+ sal_Bool SAL_CALL getEnabled() override;
+ void SAL_CALL setEnabled(sal_Bool bSet) override;
+ OUString SAL_CALL getEntryMacro() override;
+ void SAL_CALL setEntryMacro(const OUString& rSet) override;
+ OUString SAL_CALL getExitMacro() override;
+ void SAL_CALL setExitMacro(const OUString& rSet) override;
+ /*
+ * If the OwnHelp property is set to True,
+ * HelpText specifies the text string value.
+ * If OwnHelp is set to False, HelpText specifies the name of an AutoText entry
+ * that contains help text for the form field.
+ */
+ OUString SAL_CALL getHelpText() override;
+ void SAL_CALL setHelpText(const OUString& rSet) override;
+ sal_Bool SAL_CALL getOwnHelp() override;
+ void SAL_CALL setOwnHelp(sal_Bool bSet) override;
+
+ OUString SAL_CALL getName() override;
+ void SAL_CALL setName(const OUString& rSet) override;
+ OUString SAL_CALL getResult() override;
+ void SAL_CALL setResult(const OUString& rSet) override;
+ /*
+ * If the OwnStatus property is set to True,
+ * StatusText specifies the status bar value.
+ * If OwnStatus is set to False, StatusText specifies the name of an AutoText entry
+ * that contains status bar text for the form field.
+ */
+ OUString SAL_CALL getStatusText() override;
+ void SAL_CALL setStatusText(const OUString& rSet) override;
+ sal_Bool SAL_CALL getOwnStatus() override;
+ void SAL_CALL setOwnStatus(sal_Bool bSet) override;
+
+ // XHelperInterface
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfieldcheckbox.cxx b/sw/source/ui/vba/vbaformfieldcheckbox.cxx
new file mode 100644
index 000000000000..5a32e7e426a4
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfieldcheckbox.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/log.hxx>
+
+#include "vbaformfieldcheckbox.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+/**
+ * CheckBoxes are inline text objects that are only found in MS Word.
+ * They cannot be created in Excel or in Calc.
+ *
+ * Note that VBA might call this a Checkbox, but it might not actually be one,
+ * so make good use of getValid()
+ */
+SwVbaFormFieldCheckBox::SwVbaFormFieldCheckBox(
+ const uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const uno::Reference<uno::XComponentContext>& rContext, sw::mark::IFieldmark& rFormField)
+ : SwVbaFormFieldCheckBox_BASE(rParent, rContext)
+ , m_pCheckBox(dynamic_cast<sw::mark::ICheckboxFieldmark*>(&rFormField))
+{
+}
+
+SwVbaFormFieldCheckBox::~SwVbaFormFieldCheckBox() {}
+
+OUString SwVbaFormFieldCheckBox::getDefaultPropertyName() { return "Valid"; }
+
+sal_Bool SwVbaFormFieldCheckBox::getValid()
+{
+ return m_pCheckBox
+ && IDocumentMarkAccess::GetType(*m_pCheckBox)
+ == IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK;
+}
+
+sal_Bool SwVbaFormFieldCheckBox::getAutoSize()
+{
+ if (!getValid())
+ return false;
+
+ SAL_INFO("sw.vba", "SwVbaFormFieldCheckBox::getAutoSize stub");
+ return true;
+}
+
+void SwVbaFormFieldCheckBox::setAutoSize(sal_Bool /*bSet*/)
+{
+ if (!getValid())
+ return;
+
+ SAL_INFO("sw.vba", "SwVbaFormFieldCheckBox::setAutoSize stub");
+}
+
+sal_Bool SwVbaFormFieldCheckBox::getDefault()
+{
+ if (!getValid())
+ return false;
+
+ return getValue();
+}
+
+void SwVbaFormFieldCheckBox::setDefault(sal_Bool bSet)
+{
+ if (!getValid())
+ return;
+
+ // Hard to know what to do here, since LO doesn't have a default property for checkboxes.
+ // Setting this really only makes sense when macro-adding a checkbox.
+ // In that case, we want it to affect the actual checkbox.
+ // However, if the checkbox has already been set by the user, then this shouldn't do anything.
+ // Assuming this is only ever called when adding a checkbox seems the sanest approach.
+ setValue(bSet);
+}
+
+// Returns the size of a check box, in points
+sal_Int32 SwVbaFormFieldCheckBox::getSize()
+{
+ if (!getValid())
+ return 0;
+
+ SAL_INFO("sw.vba", "SwVbaFormFieldCheckBox::getSize stub");
+ return 11;
+}
+
+void SwVbaFormFieldCheckBox::setSize(sal_Int32 nSet)
+{
+ if (!getValid())
+ return;
+
+ SAL_INFO("sw.vba", "SwVbaFormFieldCheckBox::setSize[" << nSet << "] stub");
+}
+
+sal_Bool SwVbaFormFieldCheckBox::getValue() { return getValid() && m_pCheckBox->IsChecked(); }
+
+void SwVbaFormFieldCheckBox::setValue(sal_Bool bSet)
+{
+ if (!getValid() || !getValue() == !bSet)
+ return;
+
+ m_pCheckBox->SetChecked(bSet);
+}
+
+OUString SwVbaFormFieldCheckBox::getServiceImplName() { return "SwVbaFormFieldCheckBox"; }
+
+uno::Sequence<OUString> SwVbaFormFieldCheckBox::getServiceNames()
+{
+ static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.CheckBox" };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfieldcheckbox.hxx b/sw/source/ui/vba/vbaformfieldcheckbox.hxx
new file mode 100644
index 000000000000..c62549585b4e
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfieldcheckbox.hxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <ooo/vba/word/XCheckBox.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+#include <IDocumentMarkAccess.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XCheckBox> SwVbaFormFieldCheckBox_BASE;
+
+class SwVbaFormFieldCheckBox : public SwVbaFormFieldCheckBox_BASE
+{
+private:
+ sw::mark::ICheckboxFieldmark* m_pCheckBox;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaFormFieldCheckBox(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const css::uno::Reference<css::uno::XComponentContext>& rContext,
+ sw::mark::IFieldmark& rFormField);
+ ~SwVbaFormFieldCheckBox() override;
+
+ // XCheckBox
+ OUString SAL_CALL getDefaultPropertyName() override;
+
+ // Default member: True if the specified form field object is a valid check box form field
+ sal_Bool SAL_CALL getValid() override;
+
+ sal_Bool SAL_CALL getAutoSize() override;
+ void SAL_CALL setAutoSize(sal_Bool bSet) override;
+ // Returns the default check box value
+ sal_Bool SAL_CALL getDefault() override;
+ void SAL_CALL setDefault(sal_Bool bSet) override;
+ // Returns the size of a check box, in points
+ sal_Int32 SAL_CALL getSize() override;
+ void SAL_CALL setSize(sal_Int32 nSet) override;
+
+ sal_Bool SAL_CALL getValue() override;
+ void SAL_CALL setValue(sal_Bool bSet) override;
+
+ // XHelperInterface
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfielddropdown.cxx b/sw/source/ui/vba/vbaformfielddropdown.cxx
new file mode 100644
index 000000000000..f1edc8140357
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfielddropdown.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <ooo/vba/word/WdTextFormFieldType.hpp>
+
+#include "vbaformfielddropdown.hxx"
+#include "vbaformfielddropdownlistentries.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+/**
+ * DropDown formfields are inline text objects that are only found in MS Word.
+ * They cannot be created in Excel or in Calc.
+ *
+ * Note that VBA might call this a DropDown, but it might not actually be one,
+ * so make good use of getValid()
+ */
+SwVbaFormFieldDropDown::SwVbaFormFieldDropDown(
+ const uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const uno::Reference<uno::XComponentContext>& rContext, ::sw::mark::IFieldmark& rFormField)
+ : SwVbaFormFieldDropDown_BASE(rParent, rContext)
+ , m_pDropDown(dynamic_cast<sw::mark::IDropdownFieldmark*>(&rFormField))
+{
+}
+
+SwVbaFormFieldDropDown::~SwVbaFormFieldDropDown() {}
+
+OUString SwVbaFormFieldDropDown::getDefaultPropertyName() { return "Valid"; }
+
+sal_Bool SwVbaFormFieldDropDown::getValid()
+{
+ return m_pDropDown
+ && IDocumentMarkAccess::GetType(*m_pDropDown)
+ == IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK;
+}
+
+sal_Int32 SwVbaFormFieldDropDown::getDefault() { return getValue(); }
+
+void SwVbaFormFieldDropDown::setDefault(sal_Int32 nSet)
+{
+ // Hard to know what to do here, since LO doesn't have a default property for DropDowns.
+ // Setting this really only makes sense when macro-adding a DropDown.
+ // In that case, we want it to affect the actual text content.
+ // However, if an item has already been selected by the user, then this shouldn't do anything.
+ // Assuming this is only ever set when adding a DropDown seems the sanest approach.
+ setValue(nSet);
+}
+
+sal_Int32 SwVbaFormFieldDropDown::getValue()
+{
+ sal_Int32 nRet = 0;
+ if (!getValid())
+ return nRet;
+
+ --nRet; // send -1, which requests being changed to the selected DropDown's zero-based index
+ m_pDropDown->GetContent(&nRet);
+ return nRet + 1;
+}
+
+void SwVbaFormFieldDropDown::setValue(sal_Int32 nIndex)
+{
+ if (!getValid() || nIndex == getValue())
+ return;
+
+ // switch to zero-based index for implementation
+ --nIndex;
+ m_pDropDown->ReplaceContent(/*pText=*/nullptr, &nIndex);
+}
+
+uno::Any SwVbaFormFieldDropDown::ListEntries(const uno::Any& rIndex)
+{
+ if (!getValid())
+ return uno::Any();
+
+ uno::Reference<XCollection> xCol(
+ new SwVbaFormFieldDropDownListEntries(this, mxContext, *m_pDropDown));
+
+ if (rIndex.hasValue())
+ return xCol->Item(rIndex, uno::Any());
+
+ return uno::Any(xCol);
+}
+
+OUString SwVbaFormFieldDropDown::getServiceImplName() { return "SwVbaFormFieldDropDown"; }
+
+uno::Sequence<OUString> SwVbaFormFieldDropDown::getServiceNames()
+{
+ static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.DropDown" };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfielddropdown.hxx b/sw/source/ui/vba/vbaformfielddropdown.hxx
new file mode 100644
index 000000000000..e92caa2f8e8c
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfielddropdown.hxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <ooo/vba/word/XDropDown.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+#include <IDocumentMarkAccess.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XDropDown> SwVbaFormFieldDropDown_BASE;
+
+class SwVbaFormFieldDropDown : public SwVbaFormFieldDropDown_BASE
+{
+private:
+ sw::mark::IDropdownFieldmark* m_pDropDown;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaFormFieldDropDown(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const css::uno::Reference<css::uno::XComponentContext>& rContext,
+ sw::mark::IFieldmark& rFormField);
+ ~SwVbaFormFieldDropDown() override;
+
+ // XDropDown
+ OUString SAL_CALL getDefaultPropertyName() override;
+
+ // Default member: True if the specified form field object is a valid listbox field
+ sal_Bool SAL_CALL getValid() override;
+
+ // Returns and sets the index for the default listbox entry
+ sal_Int32 SAL_CALL getDefault() override;
+ void SAL_CALL setDefault(sal_Int32 nSet) override;
+ // Returns and sets the index of the selected listbox entry
+ sal_Int32 SAL_CALL getValue() override;
+ void SAL_CALL setValue(sal_Int32 nIndex) override;
+
+ // Returns a ListEntries collection that represents all the available entries
+ css::uno::Any SAL_CALL ListEntries(const css::uno::Any& rIndex) override;
+
+ // XHelperInterface
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentries.cxx b/sw/source/ui/vba/vbaformfielddropdownlistentries.cxx
new file mode 100644
index 000000000000..61dbd573637b
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfielddropdownlistentries.cxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <xmloff/odffields.hxx>
+
+#include "vbaformfielddropdownlistentries.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+static uno::Sequence<OUString> lcl_getListEntries(sw::mark::IDropdownFieldmark& rDropDown)
+{
+ uno::Sequence<OUString> aSeq;
+ (*rDropDown.GetParameters())[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq;
+ return aSeq;
+}
+
+namespace
+{
+class ListEntriesEnumWrapper : public EnumerationHelper_BASE
+{
+ uno::Reference<container::XIndexAccess> mxIndexAccess;
+ sal_Int32 nIndex;
+
+public:
+ explicit ListEntriesEnumWrapper(uno::Reference<container::XIndexAccess> xIndexAccess)
+ : mxIndexAccess(xIndexAccess)
+ , nIndex(0)
+ {
+ }
+
+ sal_Bool SAL_CALL hasMoreElements() override { return (nIndex < mxIndexAccess->getCount()); }
+
+ uno::Any SAL_CALL nextElement() override
+ {
+ if (nIndex < mxIndexAccess->getCount())
+ {
+ return mxIndexAccess->getByIndex(nIndex++);
+ }
+ throw container::NoSuchElementException();
+ }
+};
+
+class ListEntryCollectionHelper
+ : public ::cppu::WeakImplHelper<container::XIndexAccess, container::XEnumerationAccess>
+{
+private:
+ uno::Reference<XHelperInterface> mxParent;
+ uno::Reference<uno::XComponentContext> mxContext;
+ sw::mark::IDropdownFieldmark& m_rDropDown;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ListEntryCollectionHelper(uno::Reference<ov::XHelperInterface> xParent,
+ uno::Reference<uno::XComponentContext> xContext,
+ sw::mark::IDropdownFieldmark& rFormField)
+ : mxParent(xParent)
+ , mxContext(xContext)
+ , m_rDropDown(rFormField)
+ {
+ }
+
+ sal_Int32 SAL_CALL getCount() override { return lcl_getListEntries(m_rDropDown).getLength(); }
+
+ uno::Any SAL_CALL getByIndex(sal_Int32 Index) override
+ {
+ if (Index < 0 || Index >= getCount())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(uno::Reference<word::XListEntry>(
+ new SwVbaFormFieldDropDownListEntry(mxParent, mxContext, m_rDropDown, Index)));
+ }
+
+ uno::Type SAL_CALL getElementType() override { return cppu::UnoType<word::XListEntry>::get(); }
+
+ sal_Bool SAL_CALL hasElements() override { return getCount() != 0; }
+
+ // XEnumerationAccess
+ uno::Reference<container::XEnumeration> SAL_CALL createEnumeration() override
+ {
+ return new ListEntriesEnumWrapper(this);
+ }
+};
+}
+
+SwVbaFormFieldDropDownListEntries::SwVbaFormFieldDropDownListEntries(
+ const uno::Reference<XHelperInterface>& xParent,
+ const uno::Reference<uno::XComponentContext>& xContext,
+ sw::mark::IDropdownFieldmark& rFormField)
+ : SwVbaFormFieldDropDownListEntries_BASE(
+ xParent, xContext,
+ uno::Reference<container::XIndexAccess>(
+ new ListEntryCollectionHelper(xParent, xContext, rFormField)))
+ , m_rDropDown(rFormField)
+{
+}
+
+// XListEntries
+uno::Reference<word::XListEntry> SwVbaFormFieldDropDownListEntries::Add(const OUString& rName,
+ const uno::Any& rIndex)
+{
+ sal_Int32 nZIndex = 0;
+ rIndex >>= nZIndex;
+ // rIndex is 1-based, nZIndex is 0-based. If rIndex is not given, then add as the last choice.
+
+ // In testing with Word 2010, this gives a compile error: 'ListEntries.Add("Name", 2)'
+ // This compiles, but gets an unsupported runtime error: 'ListEntries.Add("Name", 2) = "Choice'
+ // So the only thing that actually works is to simply append: 'ListEntires.Add("Name")'
+ // but I'll still keep the expected implementation for the broken case.
+ if (!nZIndex)
+ nZIndex = SAL_MAX_INT32;
+ else
+ --nZIndex;
+ m_rDropDown.AddContent(rName + "__allowDuplicates", &nZIndex);
+ m_rDropDown.ReplaceContent(&rName, &nZIndex);
+
+ return uno::Reference<word::XListEntry>(
+ new SwVbaFormFieldDropDownListEntry(mxParent, mxContext, m_rDropDown, nZIndex));
+}
+
+void SwVbaFormFieldDropDownListEntries::Clear() { m_rDropDown.DelContent(); }
+
+sal_Int32 SwVbaFormFieldDropDownListEntries::getCount()
+{
+ return lcl_getListEntries(m_rDropDown).getLength();
+}
+
+// XEnumerationAccess
+uno::Type SwVbaFormFieldDropDownListEntries::getElementType()
+{
+ return cppu::UnoType<word::XListEntry>::get();
+}
+
+uno::Reference<container::XEnumeration> SwVbaFormFieldDropDownListEntries::createEnumeration()
+{
+ return new ListEntriesEnumWrapper(m_xIndexAccess);
+}
+
+// SwVbadropDownListEntries_BASE
+uno::Any SwVbaFormFieldDropDownListEntries::createCollectionObject(const uno::Any& aSource)
+{
+ return aSource;
+}
+
+OUString SwVbaFormFieldDropDownListEntries::getServiceImplName()
+{
+ return "SwVbaFormFieldDropDownListEntries";
+}
+
+uno::Sequence<OUString> SwVbaFormFieldDropDownListEntries::getServiceNames()
+{
+ static uno::Sequence<OUString> const sNames{ "ooo.vba.word.ListEntries" };
+ return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentries.hxx b/sw/source/ui/vba/vbaformfielddropdownlistentries.hxx
new file mode 100644
index 000000000000..ef1339127021
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfielddropdownlistentries.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <ooo/vba/word/XListEntries.hpp>
+#include <ooo/vba/word/XListEntry.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+#include "vbaformfielddropdownlistentries.hxx"
+#include "vbaformfielddropdownlistentry.hxx"
+
+typedef CollTestImplHelper<ooo::vba::word::XListEntries> SwVbaFormFieldDropDownListEntries_BASE;
+
+class SwVbaFormFieldDropDownListEntries : public SwVbaFormFieldDropDownListEntries_BASE
+{
+private:
+ sw::mark::IDropdownFieldmark& m_rDropDown;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaFormFieldDropDownListEntries(
+ const css::uno::Reference<ov::XHelperInterface>& xParent,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ sw::mark::IDropdownFieldmark& m_rDropDown);
+
+ // XListEntries
+ css::uno::Reference<ooo::vba::word::XListEntry>
+ SAL_CALL Add(const OUString& rName, const css::uno::Any& rIndex) override;
+ void SAL_CALL Clear() override;
+ sal_Int32 SAL_CALL getCount() override;
+
+ // XEnumerationAccess
+ css::uno::Type SAL_CALL getElementType() override;
+ css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override;
+
+ // SwVbaFormFieldDropDownListEntries_BASE
+ css::uno::Any createCollectionObject(const css::uno::Any& aSource) override;
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentry.cxx b/sw/source/ui/vba/vbaformfielddropdownlistentry.cxx
new file mode 100644
index 000000000000..dd9c94dc727e
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfielddropdownlistentry.cxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "vbaformfielddropdownlistentry.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+SwVbaFormFieldDropDownListEntry::SwVbaFormFieldDropDownListEntry(
+ const uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const uno::Reference<uno::XComponentContext>& rContext,
+ sw::mark::IDropdownFieldmark& rFormField, sal_Int32 nZIndex)
+ : SwVbaFormFieldDropDownListEntry_BASE(rParent, rContext)
+ , m_rDropDown(rFormField)
+ , m_nZIndex(nZIndex)
+{
+}
+
+SwVbaFormFieldDropDownListEntry::~SwVbaFormFieldDropDownListEntry() {}
+
+// XListEntry
+sal_Int32 SAL_CALL SwVbaFormFieldDropDownListEntry::getIndex() { return m_nZIndex + 1; }
+
+OUString SAL_CALL SwVbaFormFieldDropDownListEntry::getName()
+{
+ sal_Int32 nZIndex = m_nZIndex;
+ return m_rDropDown.GetContent(&nZIndex);
+}
+
+void SAL_CALL SwVbaFormFieldDropDownListEntry::setName(const OUString& rSet)
+{
+ sal_Int32 nZIndex = m_nZIndex;
+ m_rDropDown.ReplaceContent(&rSet, &nZIndex);
+}
+
+void SwVbaFormFieldDropDownListEntry::Delete() { m_rDropDown.DelContent(m_nZIndex); }
+
+// XHelperInterface
+OUString SwVbaFormFieldDropDownListEntry::getServiceImplName()
+{
+ return "SwVbaFormFieldDropDownListEntry";
+}
+
+uno::Sequence<OUString> SwVbaFormFieldDropDownListEntry::getServiceNames()
+{
+ static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.ListEntry" };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentry.hxx b/sw/source/ui/vba/vbaformfielddropdownlistentry.hxx
new file mode 100644
index 000000000000..4ded080e632e
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfielddropdownlistentry.hxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <ooo/vba/word/XListEntry.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+#include <IDocumentMarkAccess.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XListEntry>
+ SwVbaFormFieldDropDownListEntry_BASE;
+
+class SwVbaFormFieldDropDownListEntry : public SwVbaFormFieldDropDownListEntry_BASE
+{
+private:
+ sw::mark::IDropdownFieldmark& m_rDropDown;
+ // All LO and internal UNO functions are 0-based. Convert to 1-based when sending to VBA
+ const sal_Int32 m_nZIndex;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaFormFieldDropDownListEntry(
+ const css::uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const css::uno::Reference<css::uno::XComponentContext>& rContext,
+ sw::mark::IDropdownFieldmark& rFormField, sal_Int32 nZIndex);
+ ~SwVbaFormFieldDropDownListEntry() override;
+
+ // XListEntry
+ sal_Int32 SAL_CALL getIndex() override;
+
+ OUString SAL_CALL getName() override;
+ void SAL_CALL setName(const OUString& sSet) override;
+
+ void SAL_CALL Delete() override;
+
+ // XHelperInterface
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfields.cxx b/sw/source/ui/vba/vbaformfields.cxx
new file mode 100644
index 000000000000..187f41f3b4f7
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfields.cxx
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <comphelper/sequence.hxx>
+#include <sal/log.hxx>
+
+#include <doc.hxx>
+#include <docsh.hxx>
+#include <IDocumentMarkAccess.hxx>
+
+#include "vbaformfield.hxx"
+#include "vbaformfields.hxx"
+#include "wordvbahelper.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+// Helper function to access the fieldmarks
+// @param rIndex serves multiple purposes
+// [in] -1 to indicate searching using the provided name, SAL_MAX_INT32 for totals
+// [out] rIndex indicates the found index, or the total number of fieldmarks
+static sw::mark::IFieldmark* lcl_getFieldmark(std::string_view rName, sal_Int32& rIndex,
+ const uno::Reference<frame::XModel>& xModel,
+ uno::Sequence<OUString>* pElementNames = nullptr)
+
+{
+ SwDoc* pDoc = word::getDocShell(xModel)->GetDoc();
+ if (!pDoc)
+ return nullptr;
+
+ IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+ if (!pMarkAccess)
+ return nullptr;
+
+ sal_Int32 nCounter = 0;
+ std::vector<OUString> vElementNames;
+ IDocumentMarkAccess::iterator aIter = pMarkAccess->getFieldmarksBegin();
+ while (aIter != pMarkAccess->getFieldmarksEnd())
+ {
+ switch (IDocumentMarkAccess::GetType(**aIter))
+ {
+ case IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK:
+ case IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK:
+ case IDocumentMarkAccess::MarkType::TEXT_FIELDMARK:
+ {
+ if (rIndex < 0
+ && (*aIter)->GetName().equalsIgnoreAsciiCase(OUString::fromUtf8(rName)))
+ {
+ rIndex = nCounter;
+ return dynamic_cast<sw::mark::IFieldmark*>(*aIter);
+ }
+ else if (rIndex == nCounter)
+ return dynamic_cast<sw::mark::IFieldmark*>(*aIter);
+
+ ++nCounter;
+ if (pElementNames)
+ vElementNames.push_back((*aIter)->GetName());
+ break;
+ }
+ default:;
+ }
+ aIter++;
+ }
+ rIndex = nCounter;
+ if (pElementNames)
+ *pElementNames = comphelper::containerToSequence(vElementNames);
+ return nullptr;
+}
+
+namespace
+{
+class FormFieldsEnumWrapper : public EnumerationHelper_BASE
+{
+ uno::Reference<container::XIndexAccess> mxIndexAccess;
+ sal_Int32 nIndex;
+
+public:
+ explicit FormFieldsEnumWrapper(uno::Reference<container::XIndexAccess> xIndexAccess)
+ : mxIndexAccess(xIndexAccess)
+ , nIndex(0)
+ {
+ }
+ sal_Bool SAL_CALL hasMoreElements() override { return (nIndex < mxIndexAccess->getCount()); }
+
+ uno::Any SAL_CALL nextElement() override
+ {
+ if (nIndex < mxIndexAccess->getCount())
+ {
+ return mxIndexAccess->getByIndex(nIndex++);
+ }
+ throw container::NoSuchElementException();
+ }
+};
+
+class FormFieldCollectionHelper
+ : public ::cppu::WeakImplHelper<container::XNameAccess, container::XIndexAccess,
+ container::XEnumerationAccess>
+{
+private:
+ uno::Reference<XHelperInterface> mxParent;
+ uno::Reference<uno::XComponentContext> mxContext;
+ uno::Reference<text::XTextDocument> mxTextDocument;
+ sw::mark::IFieldmark* m_pCache;
+
+public:
+ /// @throws css::uno::RuntimeException
+ FormFieldCollectionHelper(uno::Reference<ov::XHelperInterface> xParent,
+ uno::Reference<uno::XComponentContext> xContext,
+ uno::Reference<text::XTextDocument> xTextDocument)
+ : mxParent(std::move(xParent))
+ , mxContext(std::move(xContext))
+ , mxTextDocument(std::move(xTextDocument))
+ , m_pCache(nullptr)
+ {
+ }
+
+ // XIndexAccess
+ sal_Int32 SAL_CALL getCount() override
+ {
+ sal_Int32 nCount = SAL_MAX_INT32;
+ lcl_getFieldmark("", nCount, mxTextDocument);
+ return nCount == SAL_MAX_INT32 ? 0 : nCount;
+ }
+
+ uno::Any SAL_CALL getByIndex(sal_Int32 Index) override
+ {
+ m_pCache = lcl_getFieldmark("", Index, mxTextDocument);
+ if (!m_pCache)
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(uno::Reference<word::XFormField>(
+ new SwVbaFormField(mxParent, mxContext, mxTextDocument, *m_pCache)));
+ }
+
+ // XNameAccess
+ uno::Sequence<OUString> SAL_CALL getElementNames() override
+ {
+ sal_Int32 nCount = SAL_MAX_INT32;
+ uno::Sequence<OUString> aSeq;
+ lcl_getFieldmark("", nCount, mxTextDocument, &aSeq);
+ return aSeq;
+ }
+
+ uno::Any SAL_CALL getByName(const OUString& aName) override
+ {
+ if (!hasByName(aName))
+ throw container::NoSuchElementException();
+
+ return uno::Any(uno::Reference<word::XFormField>(
+ new SwVbaFormField(mxParent, mxContext, mxTextDocument, *m_pCache)));
+ }
+
+ sal_Bool SAL_CALL hasByName(const OUString& aName) override
+ {
+ sal_Int32 nCount = -1;
+ m_pCache = lcl_getFieldmark(aName.toUtf8(), nCount, mxTextDocument);
+ return m_pCache != nullptr;
+ }
+
+ // XElementAccess
+ uno::Type SAL_CALL getElementType() override { return cppu::UnoType<word::XFormField>::get(); }
+
+ sal_Bool SAL_CALL hasElements() override { return getCount() != 0; }
+
+ // XEnumerationAccess
+ uno::Reference<container::XEnumeration> SAL_CALL createEnumeration() override
+ {
+ return new FormFieldsEnumWrapper(this);
+ }
+};
+}
+
+SwVbaFormFields::SwVbaFormFields(const uno::Reference<XHelperInterface>& xParent,
+ const uno::Reference<uno::XComponentContext>& xContext,
+ const uno::Reference<text::XTextDocument>& xTextDocument)
+ : SwVbaFormFields_BASE(xParent, xContext,
+ uno::Reference<container::XIndexAccess>(
+ new FormFieldCollectionHelper(xParent, xContext, xTextDocument)))
+{
+}
+
+sal_Bool SwVbaFormFields::getShaded()
+{
+ SAL_INFO("sw.vba", "SwVbaFormFields::getShaded stub");
+ return false;
+}
+
+void SwVbaFormFields::setShaded(sal_Bool /*bSet*/)
+{
+ SAL_INFO("sw.vba", "SwVbaFormFields::setShaded stub");
+}
+
+// uno::Reference<ooo::vba::word::XFormField> SwVbaFormFields::Add(const uno::Any& Range,
+// sal_Int32 Type)
+// {
+// sw::mark::IFieldmark* pFieldmark = nullptr;
+// switch (Type)
+// {
+// case ooo::vba::word::WdFieldType::wdFieldFormCheckBox:
+// break;
+// case ooo::vba::word::WdFieldType::wdFieldFormDropDown:
+// break;
+// case ooo::vba::word::WdFieldType::wdFieldFormTextInput:
+// default:;
+// }
+//
+// return uno::Reference<ooo::vba::word::XFormField>(
+// new SwVbaFormField(mxParent, mxContext, m_xTextDocument, *pFieldmark));
+// }
+
+// XEnumerationAccess
+uno::Type SwVbaFormFields::getElementType() { return cppu::UnoType<word::XFormField>::get(); }
+
+uno::Reference<container::XEnumeration> SwVbaFormFields::createEnumeration()
+{
+ return new FormFieldsEnumWrapper(m_xIndexAccess);
+}
+
+uno::Any SwVbaFormFields::createCollectionObject(const uno::Any& aSource) { return aSource; }
+
+OUString SwVbaFormFields::getServiceImplName() { return "SwVbaFormFields"; }
+
+uno::Sequence<OUString> SwVbaFormFields::getServiceNames()
+{
+ static uno::Sequence<OUString> const sNames{ "ooo.vba.word.FormFields" };
+ return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfields.hxx b/sw/source/ui/vba/vbaformfields.hxx
new file mode 100644
index 000000000000..2dfa9e76b0c4
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfields.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <ooo/vba/word/XFormFields.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+typedef CollTestImplHelper<ooo::vba::word::XFormFields> SwVbaFormFields_BASE;
+
+class SwVbaFormFields : public SwVbaFormFields_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaFormFields(const css::uno::Reference<ov::XHelperInterface>& xParent,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ const css::uno::Reference<css::text::XTextDocument>& xTextDocument);
+
+ // XFormFields
+ sal_Bool SAL_CALL getShaded() override;
+ void SAL_CALL setShaded(sal_Bool bSet) override;
+ //css::uno::Reference<ooo::vba::word::XFormField> SAL_CALL Add(const css::uno::Any& Range, sal_Int32 Type) override;
+
+ // XEnumerationAccess
+ css::uno::Type SAL_CALL getElementType() override;
+ css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override;
+
+ // SwVbaFormFields_BASE
+ css::uno::Any createCollectionObject(const css::uno::Any& aSource) override;
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfieldtextinput.cxx b/sw/source/ui/vba/vbaformfieldtextinput.cxx
new file mode 100644
index 000000000000..4f78761f4eb1
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfieldtextinput.cxx
@@ -0,0 +1,130 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <ooo/vba/word/WdTextFormFieldType.hpp>
+
+#include <sal/log.hxx>
+
+#include "vbaformfieldtextinput.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+/**
+ * TextInput formfields are inline text objects that are only found in MS Word.
+ * They cannot be created in Excel or in Calc.
+ *
+ * Note that VBA might call this a TextInput, but it might not actually be one,
+ * so make good use of getValid()
+ */
+SwVbaFormFieldTextInput::SwVbaFormFieldTextInput(
+ const uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const uno::Reference<uno::XComponentContext>& rContext, sw::mark::IFieldmark& rFormField)
+ : SwVbaFormFieldTextInput_BASE(rParent, rContext)
+ , m_rTextInput(rFormField)
+{
+}
+
+SwVbaFormFieldTextInput::~SwVbaFormFieldTextInput() {}
+
+OUString SwVbaFormFieldTextInput::getDefaultPropertyName() { return "Valid"; }
+
+sal_Bool SwVbaFormFieldTextInput::getValid()
+{
+ return IDocumentMarkAccess::GetType(m_rTextInput)
+ == IDocumentMarkAccess::MarkType::TEXT_FIELDMARK;
+}
+
+OUString SwVbaFormFieldTextInput::getDefault()
+{
+ if (!getValid())
+ return OUString();
+
+ return m_rTextInput.GetContent();
+}
+
+void SwVbaFormFieldTextInput::setDefault(const OUString& sSet)
+{
+ // Hard to know what to do here, since LO doesn't have a default property for text input.
+ // This really only makes sense when macro-adding a text input.
+ // In that case, we want it to affect the actual text content.
+ // However, if the text has already been set by the user, then this shouldn't do anything.
+ // Assuming this is only ever set when adding a text input seems the sanest approach.
+ if (!getValid() || getDefault() == sSet)
+ return;
+
+ m_rTextInput.ReplaceContent(sSet);
+}
+
+OUString SwVbaFormFieldTextInput::getFormat()
+{
+ if (!getValid())
+ return OUString();
+
+ SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::getFormat stub");
+ return OUString();
+}
+
+sal_Int32 SwVbaFormFieldTextInput::getType()
+{
+ if (!getValid())
+ return word::WdTextFormFieldType::wdRegularText;
+
+ SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::getType stub");
+ return word::WdTextFormFieldType::wdRegularText;
+}
+
+sal_Int32 SwVbaFormFieldTextInput::getWidth()
+{
+ if (!getValid())
+ return 0;
+
+ SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::getWidth stub");
+ return 11 * 50;
+}
+
+void SwVbaFormFieldTextInput::setWidth(sal_Int32 nWidth)
+{
+ if (!getValid())
+ return;
+
+ SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::setWidth[" << nWidth << "] stub");
+}
+
+void SwVbaFormFieldTextInput::Clear()
+{
+ if (!getValid() || m_rTextInput.GetContent().isEmpty())
+ return;
+
+ m_rTextInput.ReplaceContent("");
+}
+
+void SwVbaFormFieldTextInput::EditType(sal_Int32 nType, const uno::Any& rDefault,
+ const uno::Any& rFormat, const uno::Any& rEnabled)
+{
+ OUString sDefault;
+ OUString sFormat;
+ bool bEnabled = true;
+ rDefault >>= sDefault;
+ rFormat >>= sFormat;
+ rEnabled >>= bEnabled;
+ SAL_INFO("sw.vba", "SwVbaFormFieldTextInput::EditType["
+ << nType << "] sDefault[" << sDefault << "] sFormat[" << sFormat
+ << "] bEnabled[" << bEnabled << "] stub");
+}
+
+OUString SwVbaFormFieldTextInput::getServiceImplName() { return "SwVbaFormFieldTextInput"; }
+
+uno::Sequence<OUString> SwVbaFormFieldTextInput::getServiceNames()
+{
+ static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.TextInput" };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfieldtextinput.hxx b/sw/source/ui/vba/vbaformfieldtextinput.hxx
new file mode 100644
index 000000000000..513cac64defd
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfieldtextinput.hxx
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <ooo/vba/word/XTextInput.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+#include <IDocumentMarkAccess.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XTextInput> SwVbaFormFieldTextInput_BASE;
+
+class SwVbaFormFieldTextInput : public SwVbaFormFieldTextInput_BASE
+{
+private:
+ sw::mark::IFieldmark& m_rTextInput;
+
+public:
+ /// @throws css::uno::RuntimeException
+ SwVbaFormFieldTextInput(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent,
+ const css::uno::Reference<css::uno::XComponentContext>& rContext,
+ sw::mark::IFieldmark& rFormField);
+ ~SwVbaFormFieldTextInput() override;
+
+ // XTextInput
+ OUString SAL_CALL getDefaultPropertyName() override;
+
+ // default member: True if the specified form field object is a valid text form field
+ sal_Bool SAL_CALL getValid() override;
+
+ // Returns and sets the default text string of the input box
+ OUString SAL_CALL getDefault() override;
+ void SAL_CALL setDefault(const OUString& bSet) override;
+ // Returns the format string for the current text
+ OUString SAL_CALL getFormat() override;
+ /*
+ * Returns the type of text form field.
+ * Possible return values are:
+ * wdCalculationText - Calculation text field,
+ * wdCurrentDateText - Current date text field,
+ * wdCurrentTimeText - Current time text field,
+ * wdDateText - Date text field,
+ * wdNumberText - Number text field,
+ * wdRegularText - Regular text field.
+ */
+ sal_Int32 SAL_CALL getType() override;
+ // Returns and sets the width, in points
+ sal_Int32 SAL_CALL getWidth() override;
+ void SAL_CALL setWidth(sal_Int32 nSet) override;
+
+ // Deletes the text from the text form field.
+ void SAL_CALL Clear() override;
+ // Sets the type, default text string, format string, and enabled status
+ void SAL_CALL EditType(sal_Int32 nType, const css::uno::Any& rDefault,
+ const css::uno::Any& rFormat, const css::uno::Any& rEnabled) override;
+
+ // XHelperInterface
+ OUString getServiceImplName() override;
+ css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaglobals.cxx b/sw/source/ui/vba/vbaglobals.cxx
index 0e5db3802895..457cefb56462 100644
--- a/sw/source/ui/vba/vbaglobals.cxx
+++ b/sw/source/ui/vba/vbaglobals.cxx
@@ -17,6 +17,7 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "vbaglobals.hxx"
+#include "vbawordbasic.hxx"
#include <sal/log.hxx>
#include <com/sun/star/beans/PropertyValue.hpp>
@@ -124,6 +125,14 @@ SwVbaGlobals::getSelection()
return getApplication()->getSelection();
}
+uno::Reference<word::XWordBasic> SAL_CALL SwVbaGlobals::getWordBasic()
+{
+ assert(dynamic_cast<SwVbaApplication*>(getApplication().get()));
+ SwVbaApplication* pVbaApp = static_cast<SwVbaApplication*>(getApplication().get());
+ uno::Reference<word::XWordBasic> xWB(new SwWordBasic(pVbaApp));
+ return xWB;
+}
+
float SAL_CALL SwVbaGlobals::CentimetersToPoints( float Centimeters )
{
return getApplication()->CentimetersToPoints( Centimeters );
diff --git a/sw/source/ui/vba/vbaglobals.hxx b/sw/source/ui/vba/vbaglobals.hxx
index 1d8c0b4f8a2a..ad39de12f765 100644
--- a/sw/source/ui/vba/vbaglobals.hxx
+++ b/sw/source/ui/vba/vbaglobals.hxx
@@ -50,6 +50,7 @@ public:
virtual css::uno::Reference<ov::word::XWindow> SAL_CALL getActiveWindow() override;
virtual css::uno::Reference<ooo::vba::word::XOptions> SAL_CALL getOptions() override;
virtual css::uno::Reference<ooo::vba::word::XSelection> SAL_CALL getSelection() override;
+ virtual css::uno::Reference<ooo::vba::word::XWordBasic> SAL_CALL getWordBasic() override;
virtual css::uno::Any SAL_CALL CommandBars(const css::uno::Any& aIndex) override;
virtual css::uno::Any SAL_CALL Documents(const css::uno::Any& aIndex) override;
virtual css::uno::Any SAL_CALL Addins(const css::uno::Any& aIndex) override;
diff --git a/sw/source/ui/vba/vbawordbasic.cxx b/sw/source/ui/vba/vbawordbasic.cxx
new file mode 100644
index 000000000000..f08ed4e0daa8
--- /dev/null
+++ b/sw/source/ui/vba/vbawordbasic.cxx
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column:100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbaapplication.hxx"
+#include "vbafilterpropsfromformat.hxx"
+#include "vbamailmerge.hxx"
+#include "vbawordbasic.hxx"
+
+#include <basic/sbx.hxx>
+#include <basic/sbxvar.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <osl/file.hxx>
+#include <sal/log.hxx>
+#include <tools/urlobj.hxx>
+
+#include <com/sun/star/text/XTextDocument.hpp>
+#include <com/sun/star/util/thePathSettings.hpp>
+#include <ooo/vba/word/XBookmarks.hpp>
+#include <ooo/vba/word/XDocuments.hpp>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+SwWordBasic::SwWordBasic(SwVbaApplication* pApp)
+ : mpApp(pApp)
+{
+}
+
+sal_Int32 SAL_CALL SwWordBasic::getMailMergeMainDocumentType()
+{
+ return SwVbaMailMerge::get(mpApp->getParent(), mpApp->getContext())->getMainDocumentType();
+}
+
+void SAL_CALL SwWordBasic::setMailMergeMainDocumentType(sal_Int32 _mailmergemaindocumenttype)
+{
+ SwVbaMailMerge::get(mpApp->getParent(), mpApp->getContext())
+ ->setMainDocumentType(_mailmergemaindocumenttype);
+}
+
+void SAL_CALL SwWordBasic::FileOpen(const OUString& Name, const uno::Any& ConfirmConversions,
+ const uno::Any& ReadOnly, const uno::Any& AddToMru,
+ const uno::Any& PasswordDoc, const uno::Any& PasswordDot,
+ const uno::Any& Revert, const uno::Any& WritePasswordDoc,
+ const uno::Any& WritePasswordDot)
+{
+ uno::Any aDocuments = mpApp->Documents(uno::Any());
+
+ uno::Reference<word::XDocuments> rDocuments;
+
+ if (aDocuments >>= rDocuments)
+ rDocuments->Open(Name, ConfirmConversions, ReadOnly, AddToMru, PasswordDoc, PasswordDot,
+ Revert, WritePasswordDoc, WritePasswordDot, uno::Any(), uno::Any(),
+ uno::Any(), uno::Any(), uno::Any(), uno::Any(), uno::Any());
+}
+
+void SAL_CALL SwWordBasic::FileSave()
+{
+ uno::Reference<frame::XModel> xModel(mpApp->getCurrentDocument(), uno::UNO_SET_THROW);
+ dispatchRequests(xModel, ".uno:Save");
+}
+
+void SAL_CALL SwWordBasic::FileSaveAs(
+ const css::uno::Any& Name, const css::uno::Any& Format, const css::uno::Any& /*LockAnnot*/,
+ const css::uno::Any& /*Password*/, const css::uno::Any& /*AddToMru*/,
+ const css::uno::Any& /*WritePassword*/, const css::uno::Any& /*RecommendReadOnly*/,
+ const css::uno::Any& /*EmbedFonts*/, const css::uno::Any& /*NativePictureFormat*/,
+ const css::uno::Any& /*FormsData*/, const css::uno::Any& /*SaveAsAOCELetter*/)
+{
+ SAL_INFO("sw.vba", "WordBasic.FileSaveAs(Name:=" << Name << ",Format:=" << Format << ")");
+
+ uno::Reference<frame::XModel> xModel(mpApp->getCurrentDocument(), uno::UNO_SET_THROW);
+
+ // Based on SwVbaDocument::SaveAs2000.
+
+ OUString sFileName;
+ Name >>= sFileName;
+
+ OUString sURL;
+ osl::FileBase::getFileURLFromSystemPath(sFileName, sURL);
+
+ // Detect if there is no path then we need to use the current folder.
+ INetURLObject aURL(sURL);
+ sURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
+ if (sURL.isEmpty())
+ {
+ // Need to add cur dir ( of this document ) or else the 'Work' dir
+ sURL = xModel->getURL();
+
+ if (sURL.isEmpty())
+ {
+ // Not path available from 'this' document. Need to add the 'document'/work directory then.
+ // Based on SwVbaOptions::getValueEvent()
+ uno::Reference<util::XPathSettings> xPathSettings
+ = util::thePathSettings::get(comphelper::getProcessComponentContext());
+ OUString sPathUrl;
+ xPathSettings->getPropertyValue("Work") >>= sPathUrl;
+ // Path could be a multipath, Microsoft doesn't support this feature in Word currently.
+ // Only the last path is from interest.
+ // No idea if this crack is relevant for WordBasic or not.
+ sal_Int32 nIndex = sPathUrl.lastIndexOf(';');
+ if (nIndex != -1)
+ {
+ sPathUrl = sPathUrl.copy(nIndex + 1);
+ }
+
+ aURL.SetURL(sPathUrl);
+ }
+ else
+ {
+ aURL.SetURL(sURL);
+ aURL.Append(sFileName);
+ }
+ sURL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
+ }
+ sal_Int32 nFileFormat = word::WdSaveFormat::wdFormatDocument;
+ Format >>= nFileFormat;
+
+ uno::Sequence aProps{ comphelper::makePropertyValue("FilterName", css::uno::Any()),
+ comphelper::makePropertyValue("FileName", sURL) };
+
+ setFilterPropsFromFormat(nFileFormat, aProps);
+
+ dispatchRequests(xModel, ".uno:SaveAs", aProps);
+}
+
+void SAL_CALL SwWordBasic::FileClose(const css::uno::Any& Save)
+{
+ uno::Reference<frame::XModel> xModel(mpApp->getCurrentDocument(), uno::UNO_SET_THROW);
+
+ sal_Int16 nSave = 0;
+ if (Save.hasValue() && (Save >>= nSave) && (nSave == 0 || nSave == 1))
+ FileSave();
+
+ // FIXME: Here I would much prefer to call VbaDocumentBase::Close() but not sure how to get at
+ // the VbaDocumentBase of the current document. (Probably it is easy and I haven't looked hard
+ // enough.)
+ //
+ // FIXME: Error handling. If there is no current document, return some kind of error? But for
+ // now, just ignore errors. This code is written to work for a very specific customer use case
+ // anyway, not for an arbitrary sequence of COM calls to the "VBA" API.
+ dispatchRequests(xModel, ".uno:CloseDoc");
+}
+
+void SAL_CALL SwWordBasic::ToolsOptionsView(
+ const css::uno::Any& DraftFont, const css::uno::Any& WrapToWindow,
+ const css::uno::Any& PicturePlaceHolders, const css::uno::Any& FieldCodes,
+ const css::uno::Any& BookMarks, const css::uno::Any& FieldShading,
+ const css::uno::Any& StatusBar, const css::uno::Any& HScroll, const css::uno::Any& VScroll,
+ const css::uno::Any& StyleAreaWidth, const css::uno::Any& Tabs, const css::uno::Any& Spaces,
+ const css::uno::Any& Paras, const css::uno::Any& Hyphens, const css::uno::Any& Hidden,
+ const css::uno::Any& ShowAll, const css::uno::Any& Drawings, const css::uno::Any& Anchors,
+ const css::uno::Any& TextBoundaries, const css::uno::Any& VRuler,
+ const css::uno::Any& Highlight)
+{
+ SAL_INFO("sw.vba", "WordBasic.ToolsOptionsView("
+ "DraftFont:="
+ << DraftFont << ", WrapToWindow:=" << WrapToWindow
+ << ", PicturePlaceHolders:=" << PicturePlaceHolders
+ << ", FieldCodes:=" << FieldCodes << ", BookMarks:=" << BookMarks
+ << ", FieldShading:=" << FieldShading << ", StatusBar:=" << StatusBar
+ << ", HScroll:=" << HScroll << ", VScroll:=" << VScroll
+ << ", StyleAreaWidth:=" << StyleAreaWidth << ", Tabs:=" << Tabs
+ << ", Spaces:=" << Spaces << ", Paras:=" << Paras
+ << ", Hyphens:=" << Hyphens << ", Hidden:=" << Hidden
+ << ", ShowAll:=" << ShowAll << ", Drawings:=" << Drawings
+ << ", Anchors:=" << Anchors << ", TextBoundaries:=" << TextBoundaries
+ << ", VRuler:=" << VRuler << ", Highlight:=" << Highlight << ")");
+}
+
+css::uno::Any SAL_CALL SwWordBasic::WindowName(const css::uno::Any& /*Number*/)
+{
+ return css::uno::Any(mpApp->getActiveSwVbaWindow()->getCaption());
+}
+
+css::uno::Any SAL_CALL SwWordBasic::ExistingBookmark(const OUString& Name)
+{
+ uno::Reference<word::XBookmarks> xBookmarks(mpApp->getActiveDocument()->Bookmarks(uno::Any()),
+ uno::UNO_QUERY);
+ return css::uno::Any(xBookmarks.is() && xBookmarks->Exists(Name));
+}
+
+void SAL_CALL SwWordBasic::MailMergeOpenDataSource(
+ const OUString& Name, const css::uno::Any& Format, const css::uno::Any& ConfirmConversions,
+ const css::uno::Any& ReadOnly, const css::uno::Any& LinkToSource,
+ const css::uno::Any& AddToRecentFiles, const css::uno::Any& PasswordDocument,
+ const css::uno::Any& PasswordTemplate, const css::uno::Any& Revert,
+ const css::uno::Any& WritePasswordDocument, const css::uno::Any& WritePasswordTemplate,
+ const css::uno::Any& Connection, const css::uno::Any& SQLStatement,
+ const css::uno::Any& SQLStatement1, const css::uno::Any& OpenExclusive,
+ const css::uno::Any& SubType)
+{
+ mpApp->getActiveDocument()->getMailMerge()->OpenDataSource(
+ Name, Format, ConfirmConversions, ReadOnly, LinkToSource, AddToRecentFiles,
+ PasswordDocument, PasswordTemplate, Revert, WritePasswordDocument, WritePasswordTemplate,
+ Connection, SQLStatement, SQLStatement1, OpenExclusive, SubType);
+}
+
+css::uno::Any SAL_CALL SwWordBasic::AppMaximize(const css::uno::Any& WindowName,
+ const css::uno::Any& State)
+{
+ SAL_INFO("sw.vba", "WordBasic.AppMaximize( WindowName:=" << WindowName << ", State:=" << State);
+
+ // FIXME: Implement if necessary
+ return css::uno::Any(sal_Int32(0));
+}
+
+css::uno::Any SAL_CALL SwWordBasic::DocMaximize(const css::uno::Any& State)
+{
+ SAL_INFO("sw.vba", "WordBasic.DocMaximize(State:=" << State << ")");
+
+ // FIXME: Implement if necessary
+ return css::uno::Any(sal_Int32(0));
+}
+
+void SAL_CALL SwWordBasic::AppShow(const css::uno::Any& WindowName)
+{
+ SAL_INFO("sw.vba", "WordBasic.AppShow(WindowName:=" << WindowName << ")");
+
+ // FIXME: Implement if necessary
+}
+
+css::uno::Any SAL_CALL SwWordBasic::AppCount()
+{
+ SAL_INFO("sw.vba", "WordBasic.AppCount()");
+
+ // FIXME: Implement if necessary. Return a random number for now.
+ return css::uno::Any(sal_Int32(2));
+}
+
+void SAL_CALL SwWordBasic::MsgBox(const OUString& sPrompt)
+{
+ SbxArrayRef pArgs = new SbxArray;
+ SbxVariable* pVar = new SbxVariable();
+ pVar->PutString(sPrompt);
+ pArgs->Put(pVar, 1);
+
+ if (!executeRunTimeLibrary(u"MsgBox", pArgs.get()))
+ SAL_WARN("sw.vba", "failed to execute runtime library function MsgBox (" << sPrompt << ")");
+}
+
+void SAL_CALL SwWordBasic::ScreenUpdating(const uno::Any& On)
+{
+ sal_Int32 nOn;
+ if (On >>= nOn)
+ mpApp->setScreenUpdating(nOn != 0);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbawordbasic.hxx b/sw/source/ui/vba/vbawordbasic.hxx
new file mode 100644
index 000000000000..8c63bee3619b
--- /dev/null
+++ b/sw/source/ui/vba/vbawordbasic.hxx
@@ -0,0 +1,83 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBAWORDBASIC_HXX
+#define INCLUDED_SW_SOURCE_UI_VBA_VBAWORDBASIC_HXX
+
+class SwVbaApplication;
+
+class SwWordBasic : public cppu::WeakImplHelper<ooo::vba::word::XWordBasic>
+{
+private:
+ SwVbaApplication* mpApp;
+
+public:
+ SwWordBasic(SwVbaApplication* pApp);
+
+ // XWordBasic
+ virtual sal_Int32 SAL_CALL getMailMergeMainDocumentType() override;
+ virtual void SAL_CALL
+ setMailMergeMainDocumentType(sal_Int32 _mailmergemaindocumenttype) override;
+
+ virtual void SAL_CALL FileOpen(const OUString& Name, const css::uno::Any& ConfirmConversions,
+ const css::uno::Any& ReadOnly, const css::uno::Any& AddToMru,
+ const css::uno::Any& PasswordDoc,
+ const css::uno::Any& PasswordDot, const css::uno::Any& Revert,
+ const css::uno::Any& WritePasswordDoc,
+ const css::uno::Any& WritePasswordDot) override;
+ virtual void SAL_CALL FileSave() override;
+ virtual void SAL_CALL FileSaveAs(
+ const css::uno::Any& Name, const css::uno::Any& Format, const css::uno::Any& LockAnnot,
+ const css::uno::Any& Password, const css::uno::Any& AddToMru,
+ const css::uno::Any& WritePassword, const css::uno::Any& RecommendReadOnly,
+ const css::uno::Any& EmbedFonts, const css::uno::Any& NativePictureFormat,
+ const css::uno::Any& FormsData, const css::uno::Any& SaveAsAOCELetter) override;
+ virtual void SAL_CALL FileClose(const css::uno::Any& Save) override;
+ virtual void SAL_CALL ToolsOptionsView(
+ const css::uno::Any& DraftFont, const css::uno::Any& WrapToWindow,
+ const css::uno::Any& PicturePlaceHolders, const css::uno::Any& FieldCodes,
+ const css::uno::Any& BookMarks, const css::uno::Any& FieldShading,
+ const css::uno::Any& StatusBar, const css::uno::Any& HScroll, const css::uno::Any& VScroll,
+ const css::uno::Any& StyleAreaWidth, const css::uno::Any& Tabs, const css::uno::Any& Spaces,
+ const css::uno::Any& Paras, const css::uno::Any& Hyphens, const css::uno::Any& Hidden,
+ const css::uno::Any& ShowAll, const css::uno::Any& Drawings, const css::uno::Any& Anchors,
+ const css::uno::Any& TextBoundaries, const css::uno::Any& VRuler,
+ const css::uno::Any& Highlight) override;
+ virtual css::uno::Any SAL_CALL WindowName(const css::uno::Any& Number) override;
+ virtual css::uno::Any SAL_CALL ExistingBookmark(const OUString& Name) override;
+ virtual void SAL_CALL MailMergeOpenDataSource(
+ const OUString& Name, const css::uno::Any& Format, const css::uno::Any& ConfirmConversions,
+ const css::uno::Any& ReadOnly, const css::uno::Any& LinkToSource,
+ const css::uno::Any& AddToRecentFiles, const css::uno::Any& PasswordDocument,
+ const css::uno::Any& PasswordTemplate, const css::uno::Any& Revert,
+ const css::uno::Any& WritePasswordDocument, const css::uno::Any& WritePasswordTemplate,
+ const css::uno::Any& Connection, const css::uno::Any& SQLStatement,
+ const css::uno::Any& SQLStatement1, const css::uno::Any& OpenExclusive,
+ const css::uno::Any& SubType) override;
+ virtual css::uno::Any SAL_CALL AppMaximize(const css::uno::Any& WindowName,
+ const css::uno::Any& State) override;
+ virtual css::uno::Any SAL_CALL DocMaximize(const css::uno::Any& State) override;
+ virtual void SAL_CALL AppShow(const css::uno::Any& WindowName) override;
+ virtual css::uno::Any SAL_CALL AppCount() override;
+ virtual void SAL_CALL MsgBox(const OUString& sPrompt) override;
+ virtual void SAL_CALL ScreenUpdating(const css::uno::Any& On) override;
+};
+
+#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAWORDBASIC_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/app/docst.cxx b/sw/source/uibase/app/docst.cxx
index 44e42d6f58c3..65859c303d0d 100644
--- a/sw/source/uibase/app/docst.cxx
+++ b/sw/source/uibase/app/docst.cxx
@@ -1185,7 +1185,7 @@ SfxStyleFamily SwDocShell::ApplyStyles(const OUString &rName, SfxStyleFamily nFa
// reset indent attribute on applying list style
// continue list of list style
const SwNumRule* pNumRule = pStyle->GetNumRule();
- if (pNumRule->GetName() == "No List")
+ if (pNumRule->GetName() == SwResId(STR_POOLNUMRULE_NOLIST))
{
SfxViewFrame::Current()->GetDispatcher()->Execute(FN_NUM_BULLET_OFF);
break;
diff --git a/sw/source/uibase/app/docstyle.cxx b/sw/source/uibase/app/docstyle.cxx
index 398f8775ba47..374b3eb79ca1 100644
--- a/sw/source/uibase/app/docstyle.cxx
+++ b/sw/source/uibase/app/docstyle.cxx
@@ -745,7 +745,7 @@ void SwDocStyleSheet::SetLink(const OUString& rStr)
SwCharFormat* pLink = lcl_FindCharFormat(m_rDoc, rStr);
if (pLink)
{
- m_pColl->SetLinkedCharFormat(*pLink);
+ m_pColl->SetLinkedCharFormat(pLink);
}
}
break;
@@ -757,7 +757,7 @@ void SwDocStyleSheet::SetLink(const OUString& rStr)
SwTextFormatColl* pLink = lcl_FindParaFormat(m_rDoc, rStr);
if (pLink)
{
- m_pCharFormat->SetLinkedParaFormat(*pLink);
+ m_pCharFormat->SetLinkedParaFormat(pLink);
}
}
break;
@@ -1986,8 +1986,10 @@ bool SwDocStyleSheet::FillStyleSheet(
{
nPoolId = m_pDesc->GetPoolFormatId();
nHelpId = m_pDesc->GetPoolHelpId();
- if( m_pDesc->GetPoolHlpFileId() != UCHAR_MAX )
- aHelpFile = *m_rDoc.GetDocPattern( m_pDesc->GetPoolHlpFileId() );
+ if (const OUString* pattern = m_pDesc->GetPoolHlpFileId() != UCHAR_MAX
+ ? m_rDoc.GetDocPattern(m_pDesc->GetPoolHlpFileId())
+ : nullptr)
+ aHelpFile = *pattern;
else
aHelpFile.clear();
}
@@ -2015,8 +2017,10 @@ bool SwDocStyleSheet::FillStyleSheet(
{
nPoolId = m_pNumRule->GetPoolFormatId();
nHelpId = m_pNumRule->GetPoolHelpId();
- if( m_pNumRule->GetPoolHlpFileId() != UCHAR_MAX )
- aHelpFile = *m_rDoc.GetDocPattern( m_pNumRule->GetPoolHlpFileId() );
+ if (const OUString* pattern = m_pNumRule->GetPoolHlpFileId() != UCHAR_MAX
+ ? m_rDoc.GetDocPattern(m_pNumRule->GetPoolHlpFileId())
+ : nullptr)
+ aHelpFile = *pattern;
else
aHelpFile.clear();
}
@@ -2071,8 +2075,10 @@ bool SwDocStyleSheet::FillStyleSheet(
OSL_ENSURE( m_bPhysical, "Format not found" );
nHelpId = pFormat->GetPoolHelpId();
- if( pFormat->GetPoolHlpFileId() != UCHAR_MAX )
- aHelpFile = *m_rDoc.GetDocPattern( pFormat->GetPoolHlpFileId() );
+ if (const OUString* pattern = pFormat->GetPoolHlpFileId() != UCHAR_MAX
+ ? m_rDoc.GetDocPattern(pFormat->GetPoolHlpFileId())
+ : nullptr)
+ aHelpFile = *pattern;
else
aHelpFile.clear();
diff --git a/sw/source/uibase/app/swmodule.cxx b/sw/source/uibase/app/swmodule.cxx
index 51052b8f82b6..dfa2c4562b2a 100644
--- a/sw/source/uibase/app/swmodule.cxx
+++ b/sw/source/uibase/app/swmodule.cxx
@@ -82,6 +82,7 @@
#include <svx/zoomsliderctrl.hxx>
#include <zoomctrl.hxx>
#include <wordcountctrl.hxx>
+#include <AccessibilityStatusBarControl.hxx>
#include <workctrl.hxx>
#include <fldwrap.hxx>
#include <redlndlg.hxx>
@@ -280,6 +281,7 @@ void SwDLL::RegisterControls()
SvxSelectionModeControl::RegisterControl(FN_STAT_SELMODE, pMod );
XmlSecStatusBarControl::RegisterControl( SID_SIGNATURE, pMod );
SwWordCountStatusBarControl::RegisterControl(FN_STAT_WORDCOUNT, pMod);
+ sw::AccessibilityStatusBarControl::RegisterControl(FN_STAT_ACCESSIBILITY_CHECK, pMod);
SwBookmarkControl::RegisterControl(FN_STAT_PAGE, pMod );
SwTemplateControl::RegisterControl(FN_STAT_TEMPLATE, pMod );
diff --git a/sw/source/uibase/dbui/dbmgr.cxx b/sw/source/uibase/dbui/dbmgr.cxx
index 9323c52770b2..aa9937065325 100644
--- a/sw/source/uibase/dbui/dbmgr.cxx
+++ b/sw/source/uibase/dbui/dbmgr.cxx
@@ -136,6 +136,21 @@ void lcl_emitEvent(SfxEventHintId nEventId, sal_Int32 nStrId, SfxObjectShell* pD
pDocShell));
}
+// Construct vnd.sun.star.pkg:// URL
+OUString ConstructVndSunStarPkgUrl(const OUString& rMainURL, std::u16string_view rStreamRelPath)
+{
+ auto xContext(comphelper::getProcessComponentContext());
+ auto xUri = css::uri::UriReferenceFactory::create(xContext)->parse(rMainURL);
+ assert(xUri.is());
+ xUri = css::uri::VndSunStarPkgUrlReferenceFactory::create(xContext)
+ ->createVndSunStarPkgUrlReference(xUri);
+ assert(xUri.is());
+ return xUri->getUriReference() + "/"
+ + INetURLObject::encode(
+ rStreamRelPath, INetURLObject::PART_FPATH,
+ INetURLObject::EncodeMechanism::All);
+}
+
}
std::vector<std::pair<SwDocShell*, OUString>> SwDBManager::s_aUncommittedRegistrations;
@@ -256,10 +271,9 @@ void SAL_CALL SwDataSourceRemovedListener::revokedDatabaseLocation(const sdb::Da
if (!pDocShell)
return;
- OUString aOwnURL = pDocShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::WithCharset);
- OUString sTmpName = "vnd.sun.star.pkg://" +
- INetURLObject::encode(aOwnURL, INetURLObject::PART_AUTHORITY, INetURLObject::EncodeMechanism::All);
- sTmpName += "/" + m_pDBManager->getEmbeddedName();
+ const OUString sTmpName = ConstructVndSunStarPkgUrl(
+ pDocShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ m_pDBManager->getEmbeddedName());
if (sTmpName != rEvent.OldLocation)
return;
@@ -2760,21 +2774,6 @@ OUString LoadAndRegisterDataSource_Impl(DBConnURIType type, const uno::Reference
}
return sFind;
}
-
-// Construct vnd.sun.star.pkg:// URL
-OUString ConstructVndSunStarPkgUrl(const OUString& rMainURL, std::u16string_view rStreamRelPath)
-{
- auto xContext(comphelper::getProcessComponentContext());
- auto xUri = css::uri::UriReferenceFactory::create(xContext)->parse(rMainURL);
- assert(xUri.is());
- xUri = css::uri::VndSunStarPkgUrlReferenceFactory::create(xContext)
- ->createVndSunStarPkgUrlReference(xUri);
- assert(xUri.is());
- return xUri->getUriReference() + "/"
- + INetURLObject::encode(
- rStreamRelPath, INetURLObject::PART_FPATH,
- INetURLObject::EncodeMechanism::All);
-}
}
OUString SwDBManager::LoadAndRegisterDataSource(weld::Window* pParent, SwDocShell* pDocShell)
diff --git a/sw/source/uibase/dialog/regionsw.cxx b/sw/source/uibase/dialog/regionsw.cxx
index 73c7bd725dc4..5bbea6262da5 100644
--- a/sw/source/uibase/dialog/regionsw.cxx
+++ b/sw/source/uibase/dialog/regionsw.cxx
@@ -32,6 +32,9 @@
#include <fmtfsize.hxx>
#include <cmdid.h>
#include <swabstdlg.hxx>
+#include <IDocumentContentOperations.hxx>
+#include <translatehelper.hxx>
+#include <IDocumentUndoRedo.hxx>
void SwBaseShell::InsertRegionDialog(SfxRequest& rReq)
{
@@ -146,7 +149,31 @@ void SwBaseShell::InsertRegionDialog(SfxRequest& rReq)
aSection.SetType( SectionType::FileLink );
aSection.SetLinkFileName(sLinkFileName);
}
+ rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSSECTION, nullptr);
+ rSh.StartAction();
rSh.InsertSection(aSection, aSet.Count() ? &aSet : nullptr);
+
+ const SfxStringItem* pSectionContent = rReq.GetArg<SfxStringItem>(FN_PARAM_4);
+ if (pSectionContent)
+ {
+ OUString aSectionContent = pSectionContent->GetValue();
+ SwPaM* pCursorPos = rSh.GetCursor();
+ pCursorPos->Move(fnMoveBackward, GoInContent);
+ // Paste HTML content.
+ SwTranslateHelper::PasteHTMLToPaM(rSh, pCursorPos, aSectionContent.toUtf8(),
+ /*bSetSelection=*/true);
+ if (pCursorPos->GetPoint()->nContent.GetIndex() == 0)
+ {
+ // The paste created a last empty text node, remove it.
+ SwPaM aPam(*pCursorPos->GetPoint());
+ aPam.SetMark();
+ aPam.Move(fnMoveBackward, GoInContent);
+ rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPam);
+ }
+ }
+ rSh.EndAction();
+ rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSSECTION, nullptr);
+
rReq.Done();
}
}
diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx
index 1ad8d67d6433..b1869255697e 100644
--- a/sw/source/uibase/dochdl/swdtflvr.cxx
+++ b/sw/source/uibase/dochdl/swdtflvr.cxx
@@ -787,7 +787,7 @@ bool SwTransferable::WriteObject( tools::SvRef<SotTempStream>& xStream,
case SWTRANSFER_OBJECTTYPE_HTML:
{
// LOK is interested in getting images embedded for copy/paste support.
- GetHTMLWriter( comphelper::LibreOfficeKit::isActive() ? OUString("EmbedImages;NoLineLimit") : OUString(), OUString(), xWrt );
+ GetHTMLWriter( comphelper::LibreOfficeKit::isActive() ? OUString("EmbedImages;NoPrettyPrint") : OUString(), OUString(), xWrt );
break;
}
diff --git a/sw/source/uibase/docvw/FrameControlsManager.cxx b/sw/source/uibase/docvw/FrameControlsManager.cxx
index 1e1387020baa..bcc8b774d456 100644
--- a/sw/source/uibase/docvw/FrameControlsManager.cxx
+++ b/sw/source/uibase/docvw/FrameControlsManager.cxx
@@ -24,6 +24,7 @@
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weldutils.hxx>
+#include <contentcontrolaliasbutton.hxx>
SwFrameControlsManager::SwFrameControlsManager( SwEditWin* pEditWin ) :
m_pEditWin( pEditWin )
@@ -176,6 +177,32 @@ void SwFrameControlsManager::SetUnfloatTableButton( const SwFlyFrame* pFlyFrame,
pControl->ShowAll( bShow );
}
+void SwFrameControlsManager::SetContentControlAliasButton(SwContentControl* pContentControl,
+ Point aTopLeftPixel)
+{
+ SwFrameControlPtr pControl;
+ SwFrameControlPtrMap& rControls = m_aControls[FrameControlType::ContentControl];
+ // We don't really have a key, the SwPaM's mark decides what is the single content control in
+ // this view that can have an alias button.
+ SwFrameControlPtrMap::iterator it = rControls.find(nullptr);
+ if (it != rControls.end())
+ pControl = it->second;
+ else
+ {
+ pControl = std::make_shared<SwFrameControl>(
+ VclPtr<SwContentControlAliasButton>::Create(m_pEditWin, pContentControl).get());
+ const SwViewOption* pViewOpt = m_pEditWin->GetView().GetWrtShell().GetViewOptions();
+ pControl->SetReadonly(pViewOpt->IsReadonly());
+ rControls[nullptr] = pControl;
+ }
+
+ auto pButton = dynamic_cast<SwContentControlAliasButton*>(pControl->GetWindow());
+ assert(pButton);
+ pButton->SetOffset(aTopLeftPixel);
+ pButton->SetContentControl(pContentControl);
+ pControl->ShowAll(true);
+}
+
SwFrameMenuButtonBase::SwFrameMenuButtonBase(SwEditWin* pEditWin, const SwFrame* pFrame,
const OUString& rUIXMLDescription, const OString& rID)
: InterimItemWindow(pEditWin, rUIXMLDescription, rID)
diff --git a/sw/source/uibase/docvw/PageBreakWin.cxx b/sw/source/uibase/docvw/PageBreakWin.cxx
index 2db9b5141cec..d0e08356dc40 100644
--- a/sw/source/uibase/docvw/PageBreakWin.cxx
+++ b/sw/source/uibase/docvw/PageBreakWin.cxx
@@ -486,6 +486,7 @@ IMPL_LINK_NOARG(SwPageBreakWin, FadeHandler, Timer *, void)
{
Hide();
m_pLine->DestroyWin();
+ return;
}
else
{
diff --git a/sw/source/uibase/docvw/PostItMgr.cxx b/sw/source/uibase/docvw/PostItMgr.cxx
index 234b6c5db0c5..4a6e62e6f5c4 100644
--- a/sw/source/uibase/docvw/PostItMgr.cxx
+++ b/sw/source/uibase/docvw/PostItMgr.cxx
@@ -247,11 +247,22 @@ bool SwPostItMgr::CheckForRemovedPostIts()
if (!(*it)->UseElement(*mpWrtShell->GetLayout(), rIDRA))
{
EndListening(const_cast<SfxBroadcaster&>(*(*it)->GetBroadcaster()));
+
+ if((*it)->mpPostIt && (*it)->mpPostIt->GetPostItField())
+ lcl_CommentNotification(mpView, CommentNotificationType::Remove, nullptr, (*it)->mpPostIt->GetPostItField()->GetPostItId());
+
std::unique_ptr<SwSidebarItem> p = std::move(*it);
it = mvPostItFields.erase(it);
if (GetActiveSidebarWin() == p->mpPostIt)
SetActiveSidebarWin(nullptr);
p->mpPostIt.disposeAndClear();
+
+ if (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations())
+ {
+ const SwPostItField* pPostItField = static_cast<const SwPostItField*>(p->GetFormatField().GetField());
+ lcl_CommentNotification(mpView, CommentNotificationType::Remove, nullptr, pPostItField->GetPostItId());
+ }
+
bRemoved = true;
}
else
diff --git a/sw/source/uibase/docvw/contentcontrolaliasbutton.cxx b/sw/source/uibase/docvw/contentcontrolaliasbutton.cxx
new file mode 100644
index 000000000000..f55de23b05ca
--- /dev/null
+++ b/sw/source/uibase/docvw/contentcontrolaliasbutton.cxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <contentcontrolaliasbutton.hxx>
+
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/vector/b2dvector.hxx>
+#include <drawinglayer/attribute/fontattribute.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
+#include <vcl/metric.hxx>
+
+#include <HeaderFooterWin.hxx>
+#include <edtwin.hxx>
+#include <formatcontentcontrol.hxx>
+#include <swabstdlg.hxx>
+#include <view.hxx>
+#include <viewopt.hxx>
+#include <wrtsh.hxx>
+
+#define TEXT_PADDING 3
+#define BOX_DISTANCE 3
+#define BUTTON_WIDTH 12
+
+SwContentControlAliasButton::SwContentControlAliasButton(SwEditWin* pEditWin,
+ SwContentControl* pContentControl)
+ : SwFrameMenuButtonBase(pEditWin, nullptr, "modules/swriter/ui/contentcontrolaliasbutton.ui",
+ "ContentControlAliasButton")
+ , m_xPushButton(m_xBuilder->weld_button("button"))
+ , m_sLabel(pContentControl->GetAlias())
+{
+ m_xPushButton->set_accessible_name(m_sLabel);
+ m_xPushButton->connect_clicked(LINK(this, SwContentControlAliasButton, ClickHdl));
+ m_xVirDev = m_xPushButton->create_virtual_device();
+ SetVirDevFont();
+}
+
+SwContentControlAliasButton::~SwContentControlAliasButton() { disposeOnce(); }
+
+void SwContentControlAliasButton::dispose()
+{
+ m_xPushButton.reset();
+ m_xVirDev.disposeAndClear();
+ SwFrameMenuButtonBase::dispose();
+}
+
+void SwContentControlAliasButton::SetOffset(Point aTopLeftPixel)
+{
+ // Compute the text size and get the box position & size from it.
+ tools::Rectangle aTextRect;
+ m_xVirDev->GetTextBoundRect(aTextRect, m_sLabel);
+ tools::Rectangle aTextPxRect = m_xVirDev->LogicToPixel(aTextRect);
+ FontMetric aFontMetric = m_xVirDev->GetFontMetric(m_xVirDev->GetFont());
+ Size aBoxSize(aTextPxRect.GetWidth() + BUTTON_WIDTH + TEXT_PADDING * 2,
+ aFontMetric.GetLineHeight() + TEXT_PADDING * 2);
+ Point aBoxPos(aTopLeftPixel.X() + BOX_DISTANCE, aTopLeftPixel.Y() - aBoxSize.Height());
+
+ // Set the position & size of the window.
+ SetPosSizePixel(aBoxPos, aBoxSize);
+ m_xVirDev->SetOutputSizePixel(aBoxSize);
+
+ PaintButton();
+}
+
+IMPL_LINK_NOARG(SwContentControlAliasButton, ClickHdl, weld::Button&, void)
+{
+ if (m_bReadOnly)
+ {
+ return;
+ }
+
+ SwView& rView = GetEditWin()->GetView();
+ SwWrtShell& rWrtSh = rView.GetWrtShell();
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDlg(
+ pFact->CreateSwContentControlDlg(GetEditWin()->GetFrameWeld(), rWrtSh));
+ VclAbstractDialog::AsyncContext aContext;
+ aContext.maEndDialogFn = [](sal_Int32) {};
+ pDlg->StartExecuteAsync(aContext);
+}
+
+void SwContentControlAliasButton::PaintButton()
+{
+ if (!m_xVirDev)
+ {
+ return;
+ }
+
+ m_xVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
+ drawinglayer::primitive2d::Primitive2DContainer aSeq;
+ tools::Rectangle aRect(Point(0, 0), m_xVirDev->PixelToLogic(GetSizePixel()));
+
+ // Create button
+ SwFrameButtonPainter::PaintButton(aSeq, aRect, /*bOnTop=*/false);
+
+ // Create the text primitive
+ basegfx::BColor aLineColor = SwViewOption::GetHeaderFooterMarkColor().getBColor();
+ basegfx::B2DVector aFontSize;
+ drawinglayer::attribute::FontAttribute aFontAttr
+ = drawinglayer::primitive2d::getFontAttributeFromVclFont(aFontSize, m_xVirDev->GetFont(),
+ false, false);
+
+ FontMetric aFontMetric = m_xVirDev->GetFontMetric(m_xVirDev->GetFont());
+ double nTextOffsetY = aFontMetric.GetAscent() + TEXT_PADDING;
+ double nTextOffsetX = std::abs(aRect.GetWidth() - m_xVirDev->GetTextWidth(m_sLabel)) / 2.0;
+ Point aTextPos(nTextOffsetX, nTextOffsetY);
+
+ basegfx::B2DHomMatrix aTextMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(
+ aFontSize.getX(), aFontSize.getY(), static_cast<double>(aTextPos.X()),
+ static_cast<double>(aTextPos.Y()));
+
+ aSeq.push_back(drawinglayer::primitive2d::Primitive2DReference(
+ new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aTextMatrix, m_sLabel, 0, m_sLabel.getLength(), std::vector<double>(), aFontAttr,
+ css::lang::Locale(), aLineColor)));
+
+ // Create the processor and process the primitives
+ drawinglayer::geometry::ViewInformation2D aViewInfo;
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor
+ = drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(*m_xVirDev, aViewInfo);
+
+ pProcessor->process(aSeq);
+
+ m_xPushButton->set_custom_button(m_xVirDev.get());
+}
+
+void SwContentControlAliasButton::ShowAll(bool bShow) { Show(bShow); }
+
+bool SwContentControlAliasButton::Contains(const Point& rDocPt) const
+{
+ tools::Rectangle aRect(GetPosPixel(), GetSizePixel());
+ return aRect.Contains(rDocPt);
+}
+
+void SwContentControlAliasButton::SetReadonly(bool bReadonly) { m_bReadOnly = bReadonly; }
+
+void SwContentControlAliasButton::SetContentControl(SwContentControl* pContentControl)
+{
+ m_sLabel = pContentControl->GetAlias();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx
index a85d93c2f05f..6d2ea5c6a1fd 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -65,6 +65,7 @@
#include <sfx2/lokhelper.hxx>
#include <editeng/acorrcfg.hxx>
+#include <bookmark.hxx>
#include <SwSmartTagMgr.hxx>
#include <edtdd.hxx>
#include <edtwin.hxx>
@@ -140,12 +141,14 @@
#include <sfx2/event.hxx>
#include <memory>
+#include "../../core/crsr/callnk.hxx"
#include <IDocumentOutlineNodes.hxx>
#include <ndtxt.hxx>
#include <cntfrm.hxx>
#include <txtfrm.hxx>
#include <strings.hrc>
#include <textcontentcontrol.hxx>
+#include <contentcontrolbutton.hxx>
using namespace sw::mark;
using namespace ::com::sun::star;
@@ -1518,7 +1521,59 @@ void SwEditWin::KeyInput(const KeyEvent &rKEvt)
return;
}
+ if (SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl())
+ {
+ // Check if this combination of rKeyCode and pTextContentControl should open a popup.
+ const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ if (pContentControl->ShouldOpenPopup(rKeyCode))
+ {
+ SwShellCursor* pCursor = rSh.GetCursor_();
+ if (pCursor)
+ {
+ VclPtr<SwContentControlButton> pContentControlButton = pCursor->GetContentControlButton();
+ if (pContentControlButton)
+ {
+ pContentControlButton->StartPopup();
+ return;
+ }
+ }
+ }
+ }
+
const SwFrameFormat* pFlyFormat = rSh.GetFlyFrameFormat();
+
+ if (pFlyFormat)
+ {
+ // See if the fly frame's anchor is in a content control. If so,
+ // try to interact with it.
+ const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
+ const SwPosition* pAnchorPos = rFormatAnchor.GetContentAnchor();
+ if (pAnchorPos)
+ {
+ SwTextNode* pTextNode = pAnchorPos->nNode.GetNode().GetTextNode();
+ if (pTextNode)
+ {
+ SwTextAttr* pAttr = pTextNode->GetTextAttrAt(
+ pAnchorPos->nContent.GetIndex(), RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT);
+ if (pAttr)
+ {
+ SwTextContentControl* pTextContentControl
+ = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ const SwFormatContentControl& rFormatContentControl
+ = pTextContentControl->GetContentControl();
+ std::shared_ptr<SwContentControl> pContentControl
+ = rFormatContentControl.GetContentControl();
+ if (pContentControl->IsInteractingCharacter(aCh))
+ {
+ rSh.GotoContentControl(rFormatContentControl);
+ return;
+ }
+ }
+ }
+ }
+ }
+
if( pFlyFormat )
{
SvMacroItemId nEvent;
@@ -1814,6 +1869,13 @@ KEYINPUT_CHECKTABLE:
bool bMod1 = 0 != (rKeyCode.GetModifier() & KEY_MOD1);
if(!bMod1)
{
+ ::sw::mark::IFieldmark* pMark = rSh.GetCurrentFieldmark();
+ if (auto pDropDown = dynamic_cast<FieldmarkWithDropDownButton*>(pMark))
+ {
+ pDropDown->LaunchPopup();
+ eKeyState = SwKeyState::End;
+ break;
+ }
eFlyState = SwKeyState::Fly_Change;
nDir = MOVE_DOWN_BIG;
}
@@ -2017,8 +2079,11 @@ KEYINPUT_CHECKTABLE_INSDEL:
}
case KEY_TAB:
{
-
- if (rSh.IsFormProtected() || rSh.GetCurrentFieldmark() || rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
+ // Rich text contentControls accept tabs and fieldmarks and other rich text,
+ // so first act on cases that are not a content control
+ SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
+ if ((rSh.IsFormProtected() && !pTextContentControl) ||
+ rSh.GetCurrentFieldmark() || rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
{
eKeyState = SwKeyState::GotoNextFieldMark;
}
@@ -2066,6 +2131,21 @@ KEYINPUT_CHECKTABLE_INSDEL:
eNextKeyState = SwKeyState::NextCell;
}
}
+ else if (pTextContentControl)
+ {
+ auto pCC = pTextContentControl->GetContentControl().GetContentControl();
+ if (pCC)
+ {
+ switch (pCC->GetType())
+ {
+ case SwContentControlType::RICH_TEXT:
+ eKeyState = SwKeyState::InsTab;
+ break;
+ default:
+ eKeyState = SwKeyState::GotoNextFieldMark;
+ }
+ }
+ }
else
{
eKeyState = SwKeyState::InsTab;
@@ -2083,7 +2163,9 @@ KEYINPUT_CHECKTABLE_INSDEL:
break;
case KEY_TAB | KEY_SHIFT:
{
- if (rSh.IsFormProtected() || rSh.GetCurrentFieldmark()|| rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
+ SwTextContentControl* pTextContentControl = rSh.CursorInsideContentControl();
+ if ((rSh.IsFormProtected() && !pTextContentControl) ||
+ rSh.GetCurrentFieldmark()|| rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
{
eKeyState = SwKeyState::GotoPrevFieldMark;
}
@@ -2122,6 +2204,10 @@ KEYINPUT_CHECKTABLE_INSDEL:
eNextKeyState = SwKeyState::PrevCell;
}
}
+ else if (pTextContentControl)
+ {
+ eKeyState = SwKeyState::GotoPrevFieldMark;
+ }
else
{
eKeyState = SwKeyState::End;
@@ -2398,6 +2484,29 @@ KEYINPUT_CHECKTABLE_INSDEL:
aCh = '\t';
[[fallthrough]];
case SwKeyState::InsChar:
+ if (rSh.CursorInsideContentControl())
+ {
+ const SwPosition* pStart = rSh.GetCursor()->Start();
+ SwTextNode* pTextNode = pStart->nNode.GetNode().GetTextNode();
+ if (pTextNode)
+ {
+ sal_Int32 nIndex = pStart->nContent.GetIndex();
+ SwTextAttr* pAttr = pTextNode->GetTextAttrAt(nIndex, RES_TXTATR_CONTENTCONTROL, SwTextNode::PARENT);
+ if (pAttr)
+ {
+ auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
+ const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
+ std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
+ if (pContentControl->IsInteractingCharacter(aCh))
+ {
+ rSh.GotoContentControl(rFormatContentControl);
+ eKeyState = SwKeyState::End;
+ break;
+ }
+ }
+ }
+ }
+
if (rSh.GetChar(false)==CH_TXT_ATR_FORMELEMENT)
{
::sw::mark::ICheckboxFieldmark* pFieldmark =
@@ -2533,16 +2642,13 @@ KEYINPUT_CHECKTABLE_INSDEL:
case SwKeyState::GotoNextFieldMark:
{
- ::sw::mark::IFieldmark const * const pFieldmark = rSh.GetFieldmarkAfter();
- if(pFieldmark) rSh.GotoFieldmark(pFieldmark);
+ rSh.GotoFormControl(/*bNext=*/true);
}
break;
case SwKeyState::GotoPrevFieldMark:
{
- ::sw::mark::IFieldmark const * const pFieldmark = rSh.GetFieldmarkBefore();
- if( pFieldmark )
- rSh.GotoFieldmark(pFieldmark);
+ rSh.GotoFormControl(/*bNext=*/false);
}
break;
@@ -2707,7 +2813,7 @@ KEYINPUT_CHECKTABLE_INSDEL:
/**
* MouseEvents
*/
-void SwEditWin::RstMBDownFlags()
+void SwEditWin::ResetMouseButtonDownFlags()
{
// Not on all systems a MouseButtonUp is used ahead
// of the modal dialog (like on WINDOWS).
@@ -3305,7 +3411,7 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
switch ( rSh.GetSelectionType() & ~SelectionType( SelectionType::FontWork | SelectionType::ExtrudedCustomShape ) )
{
case SelectionType::Graphic:
- RstMBDownFlags();
+ ResetMouseButtonDownFlags();
if (!comphelper::LibreOfficeKit::isActive())
{
GetView().GetViewFrame()->GetBindings().Execute(
@@ -3316,12 +3422,12 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
// double click on OLE object --> OLE-InPlace
case SelectionType::Ole:
- RstMBDownFlags();
+ ResetMouseButtonDownFlags();
rSh.LaunchOLEObj();
return;
case SelectionType::Frame:
- RstMBDownFlags();
+ ResetMouseButtonDownFlags();
if (!comphelper::LibreOfficeKit::isActive())
{
GetView().GetViewFrame()->GetBindings().Execute(
@@ -3331,7 +3437,7 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
return;
case SelectionType::DrawObject:
- RstMBDownFlags();
+ ResetMouseButtonDownFlags();
EnterDrawTextMode(aDocPos);
if ( auto pSwDrawTextShell = dynamic_cast< SwDrawTextShell *>( m_rView.GetCurShell() ) )
pSwDrawTextShell->Init();
@@ -3353,7 +3459,7 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
(nullptr != (pField = rSh.GetCurField(true)) ||
( bFootnote = rSh.GetCurFootnote() ) ) )
{
- RstMBDownFlags();
+ ResetMouseButtonDownFlags();
if( bFootnote )
GetView().GetViewFrame()->GetBindings().Execute( FN_EDIT_FOOTNOTE );
else
@@ -3414,7 +3520,7 @@ void SwEditWin::MouseButtonDown(const MouseEvent& _rMEvt)
IFieldmark *pFieldBM = const_cast< IFieldmark* > ( aContentAtPos.aFnd.pFieldmark );
if ( pFieldBM->GetFieldname( ) == ODF_FORMDROPDOWN || pFieldBM->GetFieldname( ) == ODF_FORMDATE )
{
- RstMBDownFlags();
+ ResetMouseButtonDownFlags();
rSh.getIDocumentMarkAccess()->ClearFieldActivation();
GetView().GetViewFrame()->GetBindings().Execute(SID_FM_CTL_PROPERTIES);
return;
@@ -5180,7 +5286,7 @@ void SwEditWin::SetApplyTemplate(const SwApplyTemplate &rTempl)
* Ctor
*/
SwEditWin::SwEditWin(vcl::Window *pParent, SwView &rMyView):
- Window(pParent, WinBits(WB_CLIPCHILDREN | WB_DIALOGCONTROL)),
+ DocWindow(pParent, WinBits(WB_CLIPCHILDREN | WB_DIALOGCONTROL)),
DropTargetHelper( this ),
DragSourceHelper( this ),
@@ -6517,13 +6623,15 @@ Selection SwEditWin::GetSurroundingTextSelection() const
// around the visible cursor.
TextFrameIndex const nPos(rSh.GetCursorPointAsViewIndex());
+ // store shell state *before* Push
+ ::std::unique_ptr<SwCallLink> pLink(::std::make_unique<SwCallLink>(rSh));
rSh.Push();
rSh.HideCursor();
rSh.GoStartSentence();
TextFrameIndex const nStartPos(rSh.GetCursorPointAsViewIndex());
- rSh.Pop(SwCursorShell::PopMode::DeleteCurrent);
+ rSh.Pop(SwCursorShell::PopMode::DeleteCurrent, ::std::move(pLink));
rSh.ShowCursor();
if (bUnLockView)
@@ -6567,45 +6675,6 @@ void SwEditWin::LogicInvalidate(const tools::Rectangle* pRectangle)
SfxLokHelper::notifyInvalidation(&m_rView, pRectangle);
}
-void SwEditWin::LogicMouseButtonDown(const MouseEvent& rMouseEvent)
-{
- // When we're not doing tiled rendering, then positions must be passed as pixels.
- assert(comphelper::LibreOfficeKit::isActive());
-
- Point aPoint = GetPointerPosPixel();
- SetLastMousePos(rMouseEvent.GetPosPixel());
-
- MouseButtonDown(rMouseEvent);
-
- SetPointerPosPixel(aPoint);
-}
-
-void SwEditWin::LogicMouseButtonUp(const MouseEvent& rMouseEvent)
-{
- // When we're not doing tiled rendering, then positions must be passed as pixels.
- assert(comphelper::LibreOfficeKit::isActive());
-
- Point aPoint = GetPointerPosPixel();
- SetLastMousePos(rMouseEvent.GetPosPixel());
-
- MouseButtonUp(rMouseEvent);
-
- SetPointerPosPixel(aPoint);
-}
-
-void SwEditWin::LogicMouseMove(const MouseEvent& rMouseEvent)
-{
- // When we're not doing tiled rendering, then positions must be passed as pixels.
- assert(comphelper::LibreOfficeKit::isActive());
-
- Point aPoint = GetPointerPosPixel();
- SetLastMousePos(rMouseEvent.GetPosPixel());
-
- MouseMove(rMouseEvent);
-
- SetPointerPosPixel(aPoint);
-}
-
void SwEditWin::SetCursorTwipPosition(const Point& rPosition, bool bPoint, bool bClearMark)
{
if (SdrView* pSdrView = m_rView.GetWrtShell().GetDrawView())
diff --git a/sw/source/uibase/fldui/fldmgr.cxx b/sw/source/uibase/fldui/fldmgr.cxx
index 90fdaad22a1d..bddc1904df77 100644
--- a/sw/source/uibase/fldui/fldmgr.cxx
+++ b/sw/source/uibase/fldui/fldmgr.cxx
@@ -71,6 +71,8 @@
#include <viewopt.hxx>
#include <txmsrt.hxx>
#include <unotools/useroptions.hxx>
+#include <IDocumentContentOperations.hxx>
+#include <translatehelper.hxx>
using namespace com::sun::star::uno;
using namespace com::sun::star::container;
@@ -1070,7 +1072,40 @@ bool SwFieldMgr::InsertField(
{
if( !rData.m_sPar1.isEmpty() && CanInsertRefMark( rData.m_sPar1 ) )
{
+ const OUString& rRefmarkText = rData.m_sPar2;
+ SwPaM* pCursorPos = pCurShell->GetCursor();
+ pCurShell->StartAction();
+ if (!rRefmarkText.isEmpty())
+ {
+ // Split node to remember where the start position is.
+ bool bSuccess = pCurShell->GetDoc()->getIDocumentContentOperations().SplitNode(
+ *pCursorPos->GetPoint(), /*bChkTableStart=*/false);
+ if (bSuccess)
+ {
+ SwPaM aRefmarkPam(*pCursorPos->GetPoint());
+ aRefmarkPam.Move(fnMoveBackward, GoInContent);
+
+ // Paste HTML content.
+ SwTranslateHelper::PasteHTMLToPaM(
+ *pCurShell, pCursorPos, rRefmarkText.toUtf8(), /*bSetSelection=*/true);
+
+ // Undo the above SplitNode().
+ aRefmarkPam.SetMark();
+ aRefmarkPam.Move(fnMoveForward, GoInContent);
+ pCurShell->GetDoc()->getIDocumentContentOperations().DeleteAndJoin(
+ aRefmarkPam);
+ *aRefmarkPam.GetMark() = *pCursorPos->GetPoint();
+ *pCursorPos = aRefmarkPam;
+ }
+ }
+
pCurShell->SetAttrItem( SwFormatRefMark( rData.m_sPar1 ) );
+
+ if (!rRefmarkText.isEmpty())
+ {
+ pCursorPos->DeleteMark();
+ }
+ pCurShell->EndAction();
return true;
}
return false;
diff --git a/sw/source/uibase/inc/AccessibilityStatusBarControl.hxx b/sw/source/uibase/inc/AccessibilityStatusBarControl.hxx
new file mode 100644
index 000000000000..72940cdbce8a
--- /dev/null
+++ b/sw/source/uibase/inc/AccessibilityStatusBarControl.hxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <sfx2/stbitem.hxx>
+#include <vcl/image.hxx>
+
+namespace sw
+{
+class AccessibilityStatusBarControl final : public SfxStatusBarControl
+{
+ sal_Int32 mnIssues;
+ Image maImageIssuesFound;
+ Image maImageIssuesNotFound;
+
+public:
+ SFX_DECL_STATUSBAR_CONTROL();
+
+ AccessibilityStatusBarControl(sal_uInt16 nSlotId, sal_uInt16 nId, StatusBar& rStb);
+ virtual ~AccessibilityStatusBarControl() override;
+
+ void StateChangedAtStatusBarControl(sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pState) override;
+ void Paint(const UserDrawEvent& rEvent) override;
+};
+
+} // end sw
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/FrameControlsManager.hxx b/sw/source/uibase/inc/FrameControlsManager.hxx
index f73f226b36d7..945534fcd31c 100644
--- a/sw/source/uibase/inc/FrameControlsManager.hxx
+++ b/sw/source/uibase/inc/FrameControlsManager.hxx
@@ -20,6 +20,7 @@ class SwPageFrame;
class SwEditWin;
class SwContentFrame;
class SwTextNode;
+class SwContentControl;
typedef std::shared_ptr< SwFrameControl > SwFrameControlPtr;
@@ -49,6 +50,7 @@ class SwFrameControlsManager
void SetPageBreakControl( const SwPageFrame* pPageFrame );
void SetUnfloatTableButton( const SwFlyFrame* pFlyFrame, bool bShow, Point aTopRightPixel = Point() );
void SetOutlineContentVisibilityButton(const SwContentFrame* pContentFrame);
+ void SetContentControlAliasButton( SwContentControl* pContentControl, Point aTopLeftPixel );
};
#endif
diff --git a/sw/source/uibase/inc/contentcontrolaliasbutton.hxx b/sw/source/uibase/inc/contentcontrolaliasbutton.hxx
new file mode 100644
index 000000000000..818a4415b937
--- /dev/null
+++ b/sw/source/uibase/inc/contentcontrolaliasbutton.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "FrameControl.hxx"
+
+class SwEditWin;
+class SwContentControl;
+
+/// In case the content control has an alias/title, this widget shows it above the top left corner
+/// of the content control till the cursor is inside the content control.
+class SwContentControlAliasButton final : public SwFrameMenuButtonBase
+{
+ std::unique_ptr<weld::Button> m_xPushButton;
+ OUString m_sLabel;
+ bool m_bReadOnly = false;
+
+public:
+ SwContentControlAliasButton(SwEditWin* pEditWin, SwContentControl* pContentControl);
+ ~SwContentControlAliasButton() override;
+
+ bool Contains(const Point& rDocPt) const override;
+ void SetReadonly(bool bReadonly) override;
+ void ShowAll(bool bShow) override;
+ void dispose() override;
+
+ void SetContentControl(SwContentControl* pContentControl);
+ void SetOffset(Point aTopLeftPixel);
+
+private:
+ DECL_LINK(ClickHdl, weld::Button&, void);
+ void PaintButton();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/contentcontroldlg.hxx b/sw/source/uibase/inc/contentcontroldlg.hxx
index 7654e3d6befb..efeadbfa76b8 100644
--- a/sw/source/uibase/inc/contentcontroldlg.hxx
+++ b/sw/source/uibase/inc/contentcontroldlg.hxx
@@ -19,6 +19,7 @@
#pragma once
#include <sfx2/basedlgs.hxx>
+#include <vcl/abstdlg.hxx>
#include <vcl/weld.hxx>
class SwWrtShell;
@@ -37,6 +38,8 @@ class SwContentControlDlg final : public SfxDialogController
std::vector<SwContentControlListItem> m_aSavedListItems;
std::unique_ptr<weld::CheckButton> m_xShowingPlaceHolderCB;
+ std::unique_ptr<weld::Entry> m_xAlias;
+ std::unique_ptr<weld::Entry> m_xTag;
std::unique_ptr<weld::Frame> m_xCheckboxFrame;
std::unique_ptr<weld::Entry> m_xCheckedState;
std::unique_ptr<weld::Button> m_xCheckedStateBtn;
@@ -55,6 +58,8 @@ class SwContentControlDlg final : public SfxDialogController
std::unique_ptr<weld::Button> m_xOk;
+ VclPtr<VclAbstractDialog> m_xListItemDialog;
+
DECL_LINK(InsertHdl, weld::Button&, void);
DECL_LINK(RenameHdl, weld::Button&, void);
DECL_LINK(DeleteHdl, weld::Button&, void);
diff --git a/sw/source/uibase/inc/cption.hxx b/sw/source/uibase/inc/cption.hxx
index b442857a44b8..f5640d2b877b 100644
--- a/sw/source/uibase/inc/cption.hxx
+++ b/sw/source/uibase/inc/cption.hxx
@@ -64,6 +64,7 @@ class SwCaptionDialog final : public SfxDialogController
DECL_LINK(ModifyComboHdl, weld::ComboBox&, void);
DECL_LINK(OptionHdl, weld::Button&, void);
DECL_LINK(CaptionHdl, weld::Button&, void);
+ DECL_LINK(OKHdl, weld::Button&, void);
void Apply();
diff --git a/sw/source/uibase/inc/edtwin.hxx b/sw/source/uibase/inc/edtwin.hxx
index 5ec1942a17fd..56d0bc57815c 100644
--- a/sw/source/uibase/inc/edtwin.hxx
+++ b/sw/source/uibase/inc/edtwin.hxx
@@ -24,7 +24,7 @@
#include <svx/svdobj.hxx>
#include <tools/link.hxx>
#include <vcl/timer.hxx>
-#include <vcl/window.hxx>
+#include <vcl/DocWindow.hxx>
#include <vcl/transfer.hxx>
#include <swevent.hxx>
#include <swtypes.hxx>
@@ -56,7 +56,7 @@ class SwTextFrame;
To translate the pixel positions from the buffer OutputDevice to the real
pixel positions, use the PixelToLogic methods of this class.
*/
-class SW_DLLPUBLIC SwEditWin final : public vcl::Window,
+class SW_DLLPUBLIC SwEditWin final : public vcl::DocWindow,
public DropTargetHelper, public DragSourceHelper
{
static QuickHelpData* m_pQuickHlpData;
@@ -134,7 +134,7 @@ class SW_DLLPUBLIC SwEditWin final : public vcl::Window,
void JustifyAreaTimer();
inline void EnterArea();
- void RstMBDownFlags();
+ void ResetMouseButtonDownFlags();
void ChangeFly( sal_uInt8 nDir, bool bWeb );
void ChangeDrawing( sal_uInt8 nDir );
@@ -281,12 +281,6 @@ public:
/// @see Window::LogicInvalidate().
void LogicInvalidate(const tools::Rectangle* pRectangle) override;
- /// Same as MouseButtonDown(), but coordinates are in logic unit.
- virtual void LogicMouseButtonDown(const MouseEvent& rMouseEvent) override;
- /// Same as MouseButtonUp(), but coordinates are in logic unit.
- virtual void LogicMouseButtonUp(const MouseEvent& rMouseEvent) override;
- /// Same as MouseMove(), but coordinates are in logic unit.
- virtual void LogicMouseMove(const MouseEvent& rMouseEvent) override;
/// Allows adjusting the point or mark of the selection to a document coordinate.
void SetCursorTwipPosition(const Point& rPosition, bool bPoint, bool bClearMark);
/// Allows starting or ending a graphic move or resize action.
diff --git a/sw/source/uibase/inc/numpara.hxx b/sw/source/uibase/inc/numpara.hxx
index cf43a1b6b155..19fea5b15b94 100644
--- a/sw/source/uibase/inc/numpara.hxx
+++ b/sw/source/uibase/inc/numpara.hxx
@@ -58,7 +58,7 @@ class SwParagraphNumTabPage final : public SfxTabPage
static const WhichRangesContainer aPageRg;
- bool ExecuteEditNumStyle_Impl(sal_uInt16 nId, const OUString& rStr,
+ void ExecuteEditNumStyle_Impl(sal_uInt16 nId, const OUString& rStr,
SfxStyleFamily nFamily);
public:
diff --git a/sw/source/uibase/inc/pagenumberdlg.hxx b/sw/source/uibase/inc/pagenumberdlg.hxx
new file mode 100644
index 000000000000..23a3c1423462
--- /dev/null
+++ b/sw/source/uibase/inc/pagenumberdlg.hxx
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/basedlgs.hxx>
+
+class SwWrtShell;
+
+/// Page number wizard for easy header/footer page number insertion
+class SwPageNumberDlg : public SfxDialogController
+{
+ std::unique_ptr<weld::Button> m_xOk;
+ std::unique_ptr<weld::Button> m_xCancel;
+ std::unique_ptr<weld::ComboBox> m_xPageNumberPosition;
+ std::unique_ptr<weld::ComboBox> m_xPageNumberAlignment;
+ std::unique_ptr<weld::Image> m_xPreviewImage;
+
+ int m_aPageNumberPosition;
+ int m_aPageNumberAlignment;
+
+ DECL_LINK(OkHdl, weld::Button&, void);
+ DECL_LINK(CancelHdl, weld::Button&, void);
+ DECL_LINK(PositionSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(AlignmentSelectHdl, weld::ComboBox&, void);
+
+ void updateImage();
+
+public:
+ SwPageNumberDlg(weld::Window* pParent);
+ int GetPageNumberPosition() const { return m_aPageNumberPosition; }
+ int GetPageNumberAlignment() const { return m_aPageNumberAlignment; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/splittbl.hxx b/sw/source/uibase/inc/splittbl.hxx
index 99e61f7d4075..b826914e4720 100644
--- a/sw/source/uibase/inc/splittbl.hxx
+++ b/sw/source/uibase/inc/splittbl.hxx
@@ -34,7 +34,6 @@ private:
std::unique_ptr<weld::RadioButton> m_xBorderCopyRB;
SwWrtShell& rShell;
- SplitTable_HeadlineOption m_nSplit;
void Apply();
@@ -49,7 +48,16 @@ public:
return nRet;
}
- SplitTable_HeadlineOption GetSplitMode() const { return m_nSplit; }
+ SplitTable_HeadlineOption GetSplitMode() const {
+ auto nSplit = SplitTable_HeadlineOption::ContentCopy;
+ if (m_xBoxAttrCopyWithParaRB->get_active())
+ nSplit = SplitTable_HeadlineOption::BoxAttrAllCopy;
+ else if (m_xBoxAttrCopyNoParaRB->get_active())
+ nSplit = SplitTable_HeadlineOption::BoxAttrCopy;
+ else if (m_xBorderCopyRB->get_active())
+ nSplit = SplitTable_HeadlineOption::BorderCopy;
+ return nSplit;
+ }
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/tblnumfm.hxx b/sw/source/uibase/inc/tblnumfm.hxx
index 8e0f32f3eabb..81f065265d1d 100644
--- a/sw/source/uibase/inc/tblnumfm.hxx
+++ b/sw/source/uibase/inc/tblnumfm.hxx
@@ -24,11 +24,14 @@
namespace weld
{
class Window;
+class Container;
}
class SfxItemSet;
class SwNumFormatDlg final : public SfxSingleTabDialogController
{
+ std::unique_ptr<weld::Container> m_xContent;
+
public:
SwNumFormatDlg(weld::Widget* pParent, const SfxItemSet& rSet);
};
diff --git a/sw/source/uibase/inc/translatehelper.hxx b/sw/source/uibase/inc/translatehelper.hxx
new file mode 100644
index 000000000000..d8298b7a289a
--- /dev/null
+++ b/sw/source/uibase/inc/translatehelper.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include "swtypes.hxx"
+
+class SwWrtShell;
+class SwPaM;
+class SwNode;
+class SwTextNode;
+
+namespace SwTranslateHelper
+{
+struct SW_DLLPUBLIC TranslateAPIConfig final
+{
+ const OString m_xAPIUrl;
+ const OString m_xAuthKey;
+ const OString m_xTargetLanguage;
+};
+SW_DLLPUBLIC OString ExportPaMToHTML(SwPaM* pCursor, bool bReplacePTag);
+SW_DLLPUBLIC void PasteHTMLToPaM(SwWrtShell& rWrtSh, SwPaM* pCursor, const OString& rData,
+ bool bSetSelection);
+SW_DLLPUBLIC void TranslateDocument(SwWrtShell& rWrtSh, const TranslateAPIConfig& rConfig);
+SW_DLLPUBLIC void TranslateDocumentCancellable(SwWrtShell& rWrtSh,
+ const TranslateAPIConfig& rConfig,
+ bool& rCancelTranslation);
+} \ No newline at end of file
diff --git a/sw/source/uibase/inc/translatelangselect.hxx b/sw/source/uibase/inc/translatelangselect.hxx
new file mode 100644
index 000000000000..d0f034b58d34
--- /dev/null
+++ b/sw/source/uibase/inc/translatelangselect.hxx
@@ -0,0 +1,69 @@
+
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include <vcl/weld.hxx>
+#include <rtl/string.h>
+#include <vector>
+#include <optional>
+#include <translatehelper.hxx>
+
+class SwWrtShell;
+
+// SwLanguageListItem Helper class for displaying available languages with their names and tags on the listbox.
+class SwLanguageListItem final
+{
+public:
+ SwLanguageListItem(const OString& sLanguage, const OString& sName)
+ : m_sLanguage(sLanguage)
+ , m_sName(sName)
+ {
+ }
+ const OString& getLanguage() const { return m_sLanguage; }
+ const OString& getName() const { return m_sName; }
+
+private:
+ const OString m_sLanguage;
+ const OString m_sName;
+};
+
+// SwTranslateLangSelectDlg Language selection dialog for translation API.
+class SwTranslateLangSelectDlg final : public weld::GenericDialogController
+{
+public:
+ static int selectedLangIdx;
+ SwTranslateLangSelectDlg(weld::Window* pParent, SwWrtShell& rSh);
+ std::optional<SwLanguageListItem> GetSelectedLanguage();
+
+private:
+ SwWrtShell& rWrtSh;
+ std::unique_ptr<weld::ComboBox> m_xLanguageListBox;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+ std::unique_ptr<weld::Button> m_xBtnTranslate;
+ std::vector<SwLanguageListItem> m_xLanguageVec;
+
+ bool m_bTranslationStarted;
+ bool m_bCancelTranslation;
+
+ DECL_LINK(LangSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(LangSelectCancelHdl, weld::Button&, void);
+ DECL_LINK(LangSelectTranslateHdl, weld::Button&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index 134c7dc5dbf6..bd46da908876 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -146,6 +146,7 @@ public:
// is there a text- or frameselection?
bool HasSelection() const { return SwCursorShell::HasSelection() ||
IsMultiSelection() || IsSelFrameMode() || IsObjSelected(); }
+ bool Pop(SwCursorShell::PopMode, ::std::unique_ptr<SwCallLink> const pLink);
bool Pop(SwCursorShell::PopMode = SwCursorShell::PopMode::DeleteStack);
void EnterStdMode();
@@ -427,7 +428,12 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
bool GotoField( const SwFormatField& rField );
- bool GotoContentControl(const SwFormatContentControl& rContentControl);
+ /** @param bOnlyRefresh:
+ * false: run default actions (e.g. toggle checkbox, remove placeholder content)
+ * true: do not alter the content control, just refresh the doc model
+ */
+ bool GotoContentControl(const SwFormatContentControl& rContentControl,
+ bool bOnlyRefresh = false);
// jump to the next / previous hyperlink - inside text and also
// on graphics
@@ -505,7 +511,7 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
void InvalidateOutlineContentVisibility();
bool GetAttrOutlineContentVisible(const size_t nPos);
- OString getLOKPayload(int nType, int nViewId, bool* ignore) const;
+ std::optional<OString> getLOKPayload(int nType, int nViewId) const;
private:
diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx
index a5ea0e6b1012..b05afd9a92e0 100644
--- a/sw/source/uibase/shells/basesh.cxx
+++ b/sw/source/uibase/shells/basesh.cxx
@@ -79,8 +79,11 @@
#include <strings.hrc>
#include <unotxdoc.hxx>
#include <doc.hxx>
+#include <drawdoc.hxx>
#include <IDocumentSettingAccess.hxx>
+#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentUndoRedo.hxx>
+#include <ThemeColorChanger.hxx>
#include <swabstdlg.hxx>
#include <modcfg.hxx>
#include <svx/fmshell.hxx>
@@ -89,20 +92,26 @@
#include <svx/galleryitem.hxx>
#include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
#include <com/sun/star/gallery/GalleryItemType.hpp>
+#include <com/sun/star/beans/PropertyValues.hpp>
#include <memory>
#include <svx/unobrushitemhelper.hxx>
+#include <svx/dialog/ThemeDialog.hxx>
#include <comphelper/scopeguard.hxx>
#include <comphelper/lok.hxx>
#include <osl/diagnose.h>
#include <svx/svxdlg.hxx>
+#include <comphelper/sequenceashashmap.hxx>
#include <shellres.hxx>
#include <UndoTable.hxx>
#include <ndtxt.hxx>
#include <UndoManager.hxx>
+#include <fmtrfmrk.hxx>
+#include <txtrfmrk.hxx>
+#include <translatehelper.hxx>
FlyMode SwBaseShell::eFrameMode = FLY_DRAG_END;
@@ -763,6 +772,221 @@ void SwBaseShell::StateUndo(SfxItemSet &rSet)
}
}
+namespace
+{
+/// Searches for the specified field type and field name prefix and update the matching fields to
+/// have the provided new name and content.
+bool UpdateFieldContents(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ const SfxStringItem* pTypeName = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (!pTypeName || pTypeName->GetValue() != "SetRef")
+ {
+ // This is implemented so far only for reference marks.
+ return false;
+ }
+
+ const SfxStringItem* pNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (!pNamePrefix)
+ {
+ return false;
+ }
+ const OUString& rNamePrefix = pNamePrefix->GetValue();
+
+ const SfxUnoAnyItem* pFields = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3);
+ if (!pFields)
+ {
+ return false;
+ }
+ uno::Sequence<beans::PropertyValues> aFields;
+ pFields->GetValue() >>= aFields;
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+
+ std::vector<const SwFormatRefMark*> aRefMarks;
+
+ for (sal_uInt16 i = 0; i < pDoc->GetRefMarks(); ++i)
+ {
+ aRefMarks.push_back(pDoc->GetRefMark(i));
+ }
+
+ std::sort(aRefMarks.begin(), aRefMarks.end(),
+ [](const SwFormatRefMark* pMark1, const SwFormatRefMark* pMark2) -> bool {
+ const SwTextRefMark* pTextRefMark1 = pMark1->GetTextRefMark();
+ const SwTextRefMark* pTextRefMark2 = pMark2->GetTextRefMark();
+ SwPosition aPos1(const_cast<SwTextNode&>(pTextRefMark1->GetTextNode()),
+ pTextRefMark1->GetStart());
+ SwPosition aPos2(const_cast<SwTextNode&>(pTextRefMark2->GetTextNode()),
+ pTextRefMark2->GetStart());
+ return aPos1 < aPos2;
+ });
+
+ sal_uInt16 nFieldIndex = 0;
+ for (auto& pIntermediateRefMark : aRefMarks)
+ {
+ auto pRefMark = const_cast<SwFormatRefMark*>(pIntermediateRefMark);
+ if (!pRefMark->GetRefName().startsWith(rNamePrefix))
+ {
+ continue;
+ }
+
+ if (nFieldIndex >= aFields.getLength())
+ {
+ break;
+ }
+ comphelper::SequenceAsHashMap aMap(aFields[nFieldIndex++]);
+ auto aName = aMap["Name"].get<OUString>();
+ pRefMark->GetRefName() = aName;
+
+ OUString aContent = aMap["Content"].get<OUString>();
+ auto pTextRefMark = const_cast<SwTextRefMark*>(pRefMark->GetTextRefMark());
+ if (!pTextRefMark->End())
+ {
+ continue;
+ }
+
+ // Insert markers to remember where the paste positions are.
+ const SwTextNode& rTextNode = pTextRefMark->GetTextNode();
+ SwPaM aMarkers(SwPosition(const_cast<SwTextNode&>(rTextNode), *pTextRefMark->End()));
+ IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations();
+ pTextRefMark->SetDontExpand(false);
+ bool bSuccess = rIDCO.InsertString(aMarkers, "XY");
+ if (bSuccess)
+ {
+ SwPaM aPasteEnd(SwPosition(const_cast<SwTextNode&>(rTextNode), *pTextRefMark->End()));
+ aPasteEnd.Move(fnMoveBackward, GoInContent);
+
+ // Paste HTML content.
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
+ *pCursorPos = aPasteEnd;
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aContent.toUtf8(), true);
+
+ // Update the refmark to point to the new content.
+ sal_Int32 nOldStart = pTextRefMark->GetStart();
+ sal_Int32 nNewStart = *pTextRefMark->End();
+ // First grow it to include text till the end of the paste position.
+ pTextRefMark->SetEnd(aPasteEnd.GetPoint()->nContent.GetIndex());
+ // Then shrink it to only start at the paste start: we know that the refmark was
+ // truncated to the paste start, as the refmark has to stay inside a single text node
+ pTextRefMark->SetStart(nNewStart);
+ rTextNode.GetSwpHints().SortIfNeedBe();
+ SwPaM aEndMarker(*aPasteEnd.GetPoint());
+ aEndMarker.SetMark();
+ aEndMarker.GetMark()->nContent += 1;
+ SwPaM aStartMarker(SwPosition(const_cast<SwTextNode&>(rTextNode), nOldStart), SwPosition(const_cast<SwTextNode&>(rTextNode), nNewStart));
+
+ // Remove markers. The start marker includes the old content as well.
+ rIDCO.DeleteAndJoin(aStartMarker);
+ rIDCO.DeleteAndJoin(aEndMarker);
+ }
+ }
+
+ rWrtSh.EndAction();
+ pDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSBOOKMARK, nullptr);
+ return true;
+}
+
+/// Searches for the specified field type and field name prefix under cursor and update the matching
+/// field to have the provided new name and content.
+void UpdateFieldContent(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ const SfxStringItem* pTypeName = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (!pTypeName || pTypeName->GetValue() != "SetRef")
+ {
+ // This is implemented so far only for reference marks.
+ return;
+ }
+
+ const SfxStringItem* pNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (!pNamePrefix)
+ {
+ return;
+ }
+ const OUString& rNamePrefix = pNamePrefix->GetValue();
+
+ const SfxUnoAnyItem* pField = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3);
+ if (!pField)
+ {
+ return;
+ }
+ uno::Sequence<beans::PropertyValue> aField;
+ pField->GetValue() >>= aField;
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSBOOKMARK, nullptr);
+ });
+
+ SwPosition& rCursor = *rWrtSh.GetCursor()->GetPoint();
+ SwTextNode* pTextNode = rCursor.GetNode().GetTextNode();
+ std::vector<SwTextAttr*> aAttrs
+ = pTextNode->GetTextAttrsAt(rCursor.nContent.GetIndex(), RES_TXTATR_REFMARK);
+ if (aAttrs.empty())
+ {
+ return;
+ }
+
+ auto& rRefmark = const_cast<SwFormatRefMark&>(aAttrs[0]->GetRefMark());
+ if (!rRefmark.GetRefName().startsWith(rNamePrefix))
+ {
+ return;
+ }
+
+ comphelper::SequenceAsHashMap aMap(aField);
+ auto aName = aMap["Name"].get<OUString>();
+ rRefmark.GetRefName() = aName;
+
+ OUString aContent = aMap["Content"].get<OUString>();
+ auto pTextRefMark = const_cast<SwTextRefMark*>(rRefmark.GetTextRefMark());
+ if (!pTextRefMark->End())
+ {
+ return;
+ }
+
+ // Insert markers to remember where the paste positions are.
+ auto& rTextNode = const_cast<SwTextNode&>(pTextRefMark->GetTextNode());
+ SwPaM aMarkers(SwPosition(rTextNode, *pTextRefMark->End()));
+ IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations();
+ pTextRefMark->SetDontExpand(false);
+ if (!rIDCO.InsertString(aMarkers, "XY"))
+ {
+ return;
+ }
+
+ SwPaM aPasteEnd(SwPosition(rTextNode, *pTextRefMark->End()));
+ aPasteEnd.Move(fnMoveBackward, GoInContent);
+
+ // Paste HTML content.
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
+ *pCursorPos = aPasteEnd;
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aContent.toUtf8(), true);
+
+ // Update the refmark to point to the new content.
+ sal_Int32 nOldStart = pTextRefMark->GetStart();
+ sal_Int32 nNewStart = *pTextRefMark->End();
+ // First grow it to include text till the end of the paste position.
+ pTextRefMark->SetEnd(aPasteEnd.GetPoint()->nContent.GetIndex());
+ // Then shrink it to only start at the paste start: we know that the refmark was
+ // truncated to the paste start, as the refmark has to stay inside a single text node
+ pTextRefMark->SetStart(nNewStart);
+ rTextNode.GetSwpHints().SortIfNeedBe();
+ SwPaM aEndMarker(*aPasteEnd.GetPoint());
+ aEndMarker.SetMark();
+ aEndMarker.GetMark()->nContent += 1;
+ SwPaM aStartMarker(SwPosition(rTextNode, nOldStart), SwPosition(rTextNode, nNewStart));
+
+ // Remove markers. The start marker includes the old content as well.
+ rIDCO.DeleteAndJoin(aStartMarker);
+ rIDCO.DeleteAndJoin(aEndMarker);
+}
+}
+
// Evaluate respectively dispatching the slot Id
void SwBaseShell::Execute(SfxRequest &rReq)
@@ -785,6 +1009,13 @@ void SwBaseShell::Execute(SfxRequest &rReq)
break;
case FN_UPDATE_FIELDS:
{
+ if (UpdateFieldContents(rReq, rSh))
+ {
+ // Parameters indicated that the name / content of fields has to be updated to
+ // the provided values, don't do an actual fields update.
+ break;
+ }
+
rSh.UpdateDocStat();
rSh.EndAllTableBoxEdit();
rSh.SwViewShell::UpdateFields(true);
@@ -798,6 +1029,11 @@ void SwBaseShell::Execute(SfxRequest &rReq)
}
}
break;
+ case FN_UPDATE_FIELD:
+ {
+ UpdateFieldContent(rReq, rSh);
+ }
+ break;
case FN_UPDATE_CHARTS:
{
SwWait aWait( *m_rView.GetDocShell(), true );
@@ -1970,6 +2206,10 @@ void SwBaseShell::GetState( SfxItemSet &rSet )
rSet.DisableItem(nWhich);
}
break;
+ case SID_THEME_DIALOG:
+ {
+ }
+ break;
}
nWhich = aIter.NextWhich();
}
@@ -2801,6 +3041,24 @@ void SwBaseShell::ExecDlg(SfxRequest &rReq)
}
break;
+ case SID_THEME_DIALOG:
+ {
+ auto* pDocument = rSh.GetDoc();
+ auto* pDocumentShell = pDocument->GetDocShell();
+ if (pDocumentShell)
+ {
+ SdrPage* pPage = pDocument->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
+ svx::Theme* pTheme = pPage->getSdrPageProperties().GetTheme();
+ if (pTheme)
+ {
+ std::shared_ptr<svx::IThemeColorChanger> pChanger(new sw::ThemeColorChanger(pDocumentShell));
+ auto pDialog = std::make_shared<svx::ThemeDialog>(pMDI, pTheme, pChanger);
+ weld::DialogController::runAsync(pDialog, [](int) {});
+ }
+ }
+ }
+ break;
+
default:OSL_FAIL("wrong Dispatcher (basesh.cxx)");
}
if(!bDone)
diff --git a/sw/source/uibase/shells/drwtxtex.cxx b/sw/source/uibase/shells/drwtxtex.cxx
index e94dbae0b0b8..87592d255f76 100644
--- a/sw/source/uibase/shells/drwtxtex.cxx
+++ b/sw/source/uibase/shells/drwtxtex.cxx
@@ -528,12 +528,8 @@ void SwDrawTextShell::Execute( SfxRequest &rReq )
const SvxFieldData* pField = pOLV->GetFieldAtCursor();
if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
{
- SfxStringItem aUrl(SID_FILE_NAME, pURLField->GetURL());
- SfxStringItem aTarget(SID_TARGETNAME, pURLField->GetTargetFrame());
- SfxBoolItem aNewView(SID_OPEN_NEW_VIEW, false);
- SfxBoolItem aBrowsing(SID_BROWSE, true);
- GetView().GetViewFrame()->GetDispatcher()->ExecuteList(
- SID_OPENDOC, SfxCallMode::SYNCHRON, { &aUrl, &aTarget, &aNewView, &aBrowsing });
+ ::LoadURL(GetShell(), pURLField->GetURL(), LoadUrlFlags::NONE,
+ pURLField->GetTargetFrame());
}
}
break;
diff --git a/sw/source/uibase/shells/olesh.cxx b/sw/source/uibase/shells/olesh.cxx
index acddd3eb6975..28e8e153eeb1 100644
--- a/sw/source/uibase/shells/olesh.cxx
+++ b/sw/source/uibase/shells/olesh.cxx
@@ -34,11 +34,11 @@ using namespace sfx2::sidebar;
namespace {
-bool inChartContext(const SwView& rViewShell)
+bool inChartOrMathContext(const SwView& rViewShell)
{
SidebarController* pSidebar = SidebarController::GetSidebarControllerForView(&rViewShell);
if (pSidebar)
- return pSidebar->hasChartContextCurrently();
+ return pSidebar->hasChartOrMathContextCurrently();
return false;
}
@@ -56,11 +56,11 @@ void SwOleShell::InitInterface_Impl()
void SwOleShell::Activate(bool bMDI)
{
- if(!inChartContext(GetView()))
+ if(!inChartOrMathContext(GetView()))
SwFrameShell::Activate(bMDI);
else
{
- // Avoid context changes for chart during activation / deactivation.
+ // Avoid context changes for chart/math during activation / deactivation.
const bool bIsContextBroadcasterEnabled (SfxShell::SetContextBroadcasterEnabled(false));
SwFrameShell::Activate(bMDI);
@@ -71,11 +71,11 @@ void SwOleShell::Activate(bool bMDI)
void SwOleShell::Deactivate(bool bMDI)
{
- if(!inChartContext(GetView()))
+ if(!inChartOrMathContext(GetView()))
SwFrameShell::Deactivate(bMDI);
else
{
- // Avoid context changes for chart during activation / deactivation.
+ // Avoid context changes for chart/math during activation / deactivation.
const bool bIsContextBroadcasterEnabled (SfxShell::SetContextBroadcasterEnabled(false));
SwFrameShell::Deactivate(bMDI);
diff --git a/sw/source/uibase/shells/tabsh.cxx b/sw/source/uibase/shells/tabsh.cxx
index 84a090b111fd..9fbd241f3f20 100644
--- a/sw/source/uibase/shells/tabsh.cxx
+++ b/sw/source/uibase/shells/tabsh.cxx
@@ -695,57 +695,61 @@ void SwTableShell::Execute(SfxRequest &rReq)
FieldUnit eMetric = ::GetDfltMetric(dynamic_cast<SwWebView*>( pView) != nullptr );
SW_MOD()->PutItem(SfxUInt16Item(SID_ATTR_METRIC, static_cast< sal_uInt16 >(eMetric)));
SvNumberFormatter* pFormatter = rSh.GetNumberFormatter();
- SfxItemSetFixed<SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO>
- aCoreSet( GetPool() );
+ auto pCoreSet = std::make_shared<SfxItemSetFixed<SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO>>( GetPool() );
SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_FORMAT,
RES_BOXATR_VALUE, RES_BOXATR_VALUE>
- aBoxSet( *aCoreSet.GetPool() );
+ aBoxSet( *pCoreSet->GetPool() );
rSh.GetTableBoxFormulaAttrs( aBoxSet );
SfxItemState eState = aBoxSet.GetItemState(RES_BOXATR_FORMAT);
if(eState == SfxItemState::DEFAULT)
{
- aCoreSet.Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE,
+ pCoreSet->Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE,
pFormatter->GetFormatIndex(NF_TEXT, LANGUAGE_SYSTEM)));
}
else
- aCoreSet.Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE,
+ pCoreSet->Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE,
aBoxSet.Get(
RES_BOXATR_FORMAT ).GetValue() ));
OUString sCurText( rSh.GetTableBoxText() );
- aCoreSet.Put( SvxNumberInfoItem( pFormatter,
+ pCoreSet->Put( SvxNumberInfoItem( pFormatter,
aBoxSet.Get(
RES_BOXATR_VALUE).GetValue(),
sCurText, SID_ATTR_NUMBERFORMAT_INFO ));
+ SwWrtShell* pSh = &rSh;
SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
- ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateNumFormatDialog(GetView().GetFrameWeld(), aCoreSet));
-
- if (RET_OK == pDlg->Execute())
- {
- const SvxNumberInfoItem* pNumberFormatItem
- = GetView().GetDocShell()->GetItem( SID_ATTR_NUMBERFORMAT_INFO );
+ VclPtr<SfxAbstractDialog> pDlg(pFact->CreateNumFormatDialog(GetView().GetFrameWeld(), *pCoreSet));
- if( pNumberFormatItem )
+ pDlg->StartExecuteAsync([pDlg, pCoreSet, pSh](sal_uInt32 nResult){
+ if (RET_OK == nResult)
{
- for ( sal_uInt32 key : pNumberFormatItem->GetDelFormats() )
- pNumberFormatItem->GetNumberFormatter()->DeleteEntry( key );
+ const SvxNumberInfoItem* pNumberFormatItem
+ = pSh->GetView().GetDocShell()->GetItem( SID_ATTR_NUMBERFORMAT_INFO );
+
+ if( pNumberFormatItem )
+ {
+ for ( sal_uInt32 key : pNumberFormatItem->GetDelFormats() )
+ pNumberFormatItem->GetNumberFormatter()->DeleteEntry( key );
+ }
+
+ const SfxPoolItem* pNumberFormatValueItem = nullptr;
+ if( SfxItemState::SET == pDlg->GetOutputItemSet()->GetItemState(
+ SID_ATTR_NUMBERFORMAT_VALUE, false, &pNumberFormatValueItem ))
+ {
+ SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_FORMAT>
+ aBoxFormatSet( *pCoreSet->GetPool() );
+ aBoxFormatSet.Put( SwTableBoxNumFormat(
+ static_cast<const SfxUInt32Item*>(pNumberFormatValueItem)->GetValue() ));
+ pSh->SetTableBoxFormulaAttrs( aBoxFormatSet );
+
+ }
}
- const SfxPoolItem* pNumberFormatValueItem = nullptr;
- if( SfxItemState::SET == pDlg->GetOutputItemSet()->GetItemState(
- SID_ATTR_NUMBERFORMAT_VALUE, false, &pNumberFormatValueItem ))
- {
- SfxItemSetFixed<RES_BOXATR_FORMAT, RES_BOXATR_FORMAT>
- aBoxFormatSet( *aCoreSet.GetPool() );
- aBoxFormatSet.Put( SwTableBoxNumFormat(
- static_cast<const SfxUInt32Item*>(pNumberFormatValueItem)->GetValue() ));
- rSh.SetTableBoxFormulaAttrs( aBoxFormatSet );
-
- }
- }
+ pDlg->disposeOnce();
+ });
}
break;
}
@@ -1081,10 +1085,20 @@ void SwTableShell::Execute(SfxRequest &rReq)
else
{
SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
- ScopedVclPtr<AbstractSplitTableDialog> pDlg(pFact->CreateSplitTableDialog(GetView().GetFrameWeld(), rSh));
- pDlg->Execute();
- rReq.AppendItem( SfxUInt16Item( FN_PARAM_1, static_cast<sal_uInt16>(pDlg->GetSplitMode()) ) );
- bCallDone = true;
+ VclPtr<AbstractSplitTableDialog> pDlg(pFact->CreateSplitTableDialog(GetView().GetFrameWeld(), rSh));
+
+ SwWrtShell* pSh = &rSh;
+
+ pDlg->StartExecuteAsync([pDlg, pSh](int nResult) {
+ if (nResult == RET_OK)
+ {
+ const auto aSplitMode = pDlg->GetSplitMode();
+ pSh->SplitTable( aSplitMode );
+ }
+
+ pDlg->disposeOnce();
+ });
+ rReq.Ignore(); // We're already handling the request in our async bit
}
break;
}
diff --git a/sw/source/uibase/shells/textfld.cxx b/sw/source/uibase/shells/textfld.cxx
index 9a1cbe76e040..a59a5616ffcf 100644
--- a/sw/source/uibase/shells/textfld.cxx
+++ b/sw/source/uibase/shells/textfld.cxx
@@ -17,6 +17,7 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <com/sun/star/beans/PropertyValues.hpp>
#include <AnnotationWin.hxx>
#include <comphelper/lok.hxx>
#include <hintids.hxx>
@@ -60,9 +61,12 @@
#include <IDocumentUndoRedo.hxx>
#include <svl/zforlist.hxx>
#include <svl/zformat.hxx>
+#include <comphelper/sequenceashashmap.hxx>
#include <IMark.hxx>
#include <officecfg/Office/Compatibility.hxx>
#include <ndtxt.hxx>
+#include <translatehelper.hxx>
+#include <sfx2/dispatch.hxx>
using namespace nsSwDocInfoSubType;
@@ -265,6 +269,11 @@ void SwTextShell::ExecField(SfxRequest &rReq)
if( SfxItemState::SET == pArgs->GetItemState( FN_PARAM_FIELD_TYPE,
false, &pItem ))
nType = static_cast<SwFieldTypesEnum>(static_cast<const SfxUInt16Item *>(pItem)->GetValue());
+ else if (pArgs->GetItemState(FN_PARAM_4, false, &pItem) == SfxItemState::SET)
+ {
+ const OUString& rTypeName = static_cast<const SfxStringItem *>(pItem)->GetValue();
+ nType = SwFieldTypeFromString(rTypeName);
+ }
if( SfxItemState::SET == pArgs->GetItemState( FN_PARAM_FIELD_SUBTYPE,
false, &pItem ))
nSubType = static_cast<const SfxUInt16Item *>(pItem)->GetValue();
@@ -281,6 +290,20 @@ void SwTextShell::ExecField(SfxRequest &rReq)
if(!sTmp.isEmpty())
cSeparator = sTmp[0];
}
+ if (pArgs->GetItemState(FN_PARAM_5, false, &pItem) == SfxItemState::SET)
+ {
+ // Wrap the field in the requested container instead of inserting it
+ // directly at the cursor position.
+ const OUString& rWrapper = static_cast<const SfxStringItem *>(pItem)->GetValue();
+ if (rWrapper == "Footnote")
+ {
+ GetShellPtr()->InsertFootnote(OUString());
+ }
+ else if (rWrapper == "Endnote")
+ {
+ GetShellPtr()->InsertFootnote(OUString(), /*bEndNote=*/true);
+ }
+ }
SwInsertField_Data aData(nType, nSubType, aPar1, aPar2, nFormat, GetShellPtr(), cSeparator );
bRes = aFieldMgr.InsertField( aData );
}
@@ -686,6 +709,32 @@ FIELD_INSERT:
case FN_INSERT_TEXT_FORMFIELD:
{
+ OUString aFieldType(ODF_FORMTEXT);
+ const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pFieldType)
+ {
+ // Allow overwriting the default type.
+ aFieldType = pFieldType->GetValue();
+ }
+
+ OUString aFieldCode;
+ const SfxStringItem* pFieldCode = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (pFieldCode)
+ {
+ // Allow specifying a field code/command.
+ aFieldCode = pFieldCode->GetValue();
+ }
+
+ if (rSh.HasReadonlySel())
+ {
+ // Inform the user that the request has been ignored.
+ auto xInfo = std::make_shared<weld::GenericDialogController>(
+ GetView().GetFrameWeld(), "modules/swriter/ui/inforeadonlydialog.ui",
+ "InfoReadonlyDialog");
+ weld::DialogController::runAsync(xInfo, [](sal_Int32 /*nResult*/) {});
+ break;
+ }
+
rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
SwPaM* pCursorPos = rSh.GetCursor();
@@ -693,15 +742,80 @@ FIELD_INSERT:
{
// Insert five En Space into the text field so the field has extent
static constexpr OUStringLiteral vEnSpaces = u"\u2002\u2002\u2002\u2002\u2002";
- bool bSuccess = rSh.GetDoc()->getIDocumentContentOperations().InsertString(*pCursorPos, vEnSpaces);
+ OUString aFieldResult(vEnSpaces);
+ const SfxStringItem* pFieldResult = rReq.GetArg<SfxStringItem>(FN_PARAM_3);
+ if (pFieldResult)
+ {
+ // Allow specifying a field result / expanded value.
+ aFieldResult = pFieldResult->GetValue();
+ }
+
+ const SfxStringItem* pWrapper = rReq.GetArg<SfxStringItem>(FN_PARAM_4);
+ if (pWrapper)
+ {
+ // Wrap the fieldmark in the requested container instead of inserting it
+ // directly at the cursor position.
+ OUString aWrapper = pWrapper->GetValue();
+ if (aWrapper == "Footnote")
+ {
+ rSh.InsertFootnote(OUString());
+ }
+ else if (aWrapper == "Endnote")
+ {
+ // It's important that there is no Start/EndAction() around this, so the
+ // inner EndAction() triggers a layout update and the cursor can jump to the
+ // created SwFootnoteFrame.
+ rSh.InsertFootnote(OUString(), /*bEndNote=*/true);
+ }
+ }
+
+ // Don't update the layout after inserting content and before deleting temporary
+ // text nodes.
+ rSh.StartAction();
+
+ // Split node to remember where the start position is.
+ bool bSuccess = rSh.GetDoc()->getIDocumentContentOperations().SplitNode(
+ *pCursorPos->GetPoint(), false);
if(bSuccess)
{
+ SwPaM aFieldPam(*pCursorPos->GetPoint());
+ aFieldPam.Move(fnMoveBackward, GoInContent);
+ if (pFieldResult)
+ {
+ // Paste HTML content.
+ SwTranslateHelper::PasteHTMLToPaM(rSh, pCursorPos, aFieldResult.toUtf8(),
+ true);
+ if (pCursorPos->GetPoint()->nContent.GetIndex() == 0)
+ {
+ // The paste created a last empty text node, remove it.
+ SwPaM aPam(*pCursorPos->GetPoint());
+ aPam.SetMark();
+ aPam.Move(fnMoveBackward, GoInContent);
+ rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPam);
+ }
+ }
+ else
+ {
+ // Insert default placeholder.
+ rSh.GetDoc()->getIDocumentContentOperations().InsertString(*pCursorPos,
+ aFieldResult);
+ }
+ // Undo the above SplitNode().
+ aFieldPam.SetMark();
+ aFieldPam.Move(fnMoveForward, GoInContent);
+ rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aFieldPam);
+ *aFieldPam.GetMark() = *pCursorPos->GetPoint();
+
IDocumentMarkAccess* pMarksAccess = rSh.GetDoc()->getIDocumentMarkAccess();
- SwPaM aFieldPam(pCursorPos->GetPoint()->nNode, pCursorPos->GetPoint()->nContent.GetIndex() - vEnSpaces.getLength(),
- pCursorPos->GetPoint()->nNode, pCursorPos->GetPoint()->nContent.GetIndex());
- pMarksAccess->makeFieldBookmark(aFieldPam, OUString(), ODF_FORMTEXT,
- aFieldPam.Start());
+ sw::mark::IFieldmark* pFieldmark = pMarksAccess->makeFieldBookmark(
+ aFieldPam, OUString(), aFieldType, aFieldPam.Start());
+ if (pFieldmark && !aFieldCode.isEmpty())
+ {
+ pFieldmark->GetParameters()->insert(
+ std::pair<OUString, uno::Any>(ODF_CODE_PARAM, uno::Any(aFieldCode)));
+ }
}
+ rSh.EndAction();
}
rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
@@ -771,6 +885,280 @@ FIELD_INSERT:
rSh.GetView().GetViewFrame()->GetBindings().Invalidate( SID_UNDO );
}
break;
+ case FN_UPDATE_TEXT_FORMFIELDS:
+ {
+ // This updates multiple fieldmarks in a document, based on their field name & field command
+ // prefix.
+ OUString aFieldType;
+ const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pFieldType)
+ {
+ aFieldType = pFieldType->GetValue();
+ }
+ OUString aFieldCommandPrefix;
+ const SfxStringItem* pFieldCommandPrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (pFieldCommandPrefix)
+ {
+ aFieldCommandPrefix = pFieldCommandPrefix->GetValue();
+ }
+ uno::Sequence<beans::PropertyValues> aFields;
+ const SfxUnoAnyItem* pFields = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3);
+ if (pFields)
+ {
+ pFields->GetValue() >>= aFields;
+ }
+
+ rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
+ rSh.StartAction();
+
+ IDocumentMarkAccess* pMarkAccess = rSh.GetDoc()->getIDocumentMarkAccess();
+ sal_Int32 nFieldIndex = 0;
+ for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
+ {
+ auto pFieldmark = dynamic_cast<sw::mark::IFieldmark*>(*it);
+ assert(pFieldmark);
+ if (pFieldmark->GetFieldname() != aFieldType)
+ {
+ continue;
+ }
+
+ auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
+ if (itParam == pFieldmark->GetParameters()->end())
+ {
+ continue;
+ }
+
+ OUString aCommand;
+ itParam->second >>= aCommand;
+ if (!aCommand.startsWith(aFieldCommandPrefix))
+ {
+ continue;
+ }
+
+ if (aFields.getLength() <= nFieldIndex)
+ {
+ continue;
+ }
+
+ comphelper::SequenceAsHashMap aMap(aFields[nFieldIndex++]);
+ itParam->second = aMap["FieldCommand"];
+ SwPaM aPaM(pFieldmark->GetMarkPos(), pFieldmark->GetOtherMarkPos());
+ aPaM.Normalize();
+ // Skip field start & separator.
+ aPaM.GetPoint()->nContent += 2;
+ // Skip field end.
+ aPaM.GetMark()->nContent -= 1;
+ rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPaM);
+ OUString aFieldResult;
+ aMap["FieldResult"] >>= aFieldResult;
+ SwTranslateHelper::PasteHTMLToPaM(rSh, &aPaM, aFieldResult.toUtf8(), true);
+ }
+
+ rSh.EndAction();
+ rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
+ }
+ break;
+ case FN_DELETE_TEXT_FORMFIELDS:
+ {
+ // This deletes all fieldmarks that match the provided field type & field command prefix.
+ OUString aFieldType;
+ const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pFieldType)
+ {
+ aFieldType = pFieldType->GetValue();
+ }
+ OUString aFieldCommandPrefix;
+ const SfxStringItem* pFieldCommandPrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (pFieldCommandPrefix)
+ {
+ aFieldCommandPrefix = pFieldCommandPrefix->GetValue();
+ }
+ rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
+ rSh.StartAction();
+
+ IDocumentMarkAccess* pMarkAccess = rSh.GetDoc()->getIDocumentMarkAccess();
+ std::vector<sw::mark::IMark*> aRemovals;
+ for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
+ {
+ auto pFieldmark = dynamic_cast<sw::mark::IFieldmark*>(*it);
+ assert(pFieldmark);
+ if (pFieldmark->GetFieldname() != aFieldType)
+ {
+ continue;
+ }
+
+ auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
+ if (itParam == pFieldmark->GetParameters()->end())
+ {
+ continue;
+ }
+
+ OUString aCommand;
+ itParam->second >>= aCommand;
+ if (!aCommand.startsWith(aFieldCommandPrefix))
+ {
+ continue;
+ }
+
+ aRemovals.push_back(pFieldmark);
+ }
+
+ for (const auto& pMark : aRemovals)
+ {
+ pMarkAccess->deleteMark(pMark);
+ }
+
+ rSh.EndAction();
+ rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
+ }
+ break;
+ case FN_PGNUMBER_WIZARD:
+ {
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ VclPtr<AbstractSwPageNumberDlg> pDlg(
+ pFact->CreateSwPageNumberDlg(GetView().GetFrameWeld()));
+ auto pShell = GetShellPtr();
+ pDlg->StartExecuteAsync([pShell, &rSh, pDlg](int nResult) {
+ if ( nResult == RET_OK )
+ {
+ auto rDoc = rSh.GetDoc();
+
+ rSh.LockView(true);
+ rSh.StartAllAction();
+ rSh.SwCursorShell::Push();
+ rDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_PAGE_NUMBER, nullptr);
+
+ // Insert header/footer
+ bool bFooter = (pDlg->GetPageNumberPosition() == 1);
+ sal_uInt16 nPageNumberPosition = bFooter ?
+ FN_INSERT_PAGEFOOTER : FN_INSERT_PAGEHEADER;
+ SfxBoolItem aItem(FN_PARAM_1, true);
+ rSh.GetView().GetDispatcher().ExecuteList(
+ nPageNumberPosition,
+ SfxCallMode::API | SfxCallMode::SYNCHRON,
+ {&aItem}
+ );
+
+ SwTextNode* pTextNode = rSh.GetCursor()->GetPoint()->GetNode().GetTextNode();
+
+ // Insert new line if there is already text in header/footer
+ if (pTextNode && !pTextNode->GetText().isEmpty())
+ {
+ rDoc->getIDocumentContentOperations().SplitNode(*rSh.GetCursor()->GetPoint(), false);
+ }
+
+ // Go back to start of header/footer
+ if (bFooter)
+ rSh.GotoFooterText();
+ else
+ rSh.GotoHeaderText();
+
+ // Set alignment for the new line
+ switch (pDlg->GetPageNumberAlignment())
+ {
+ case 0:
+ {
+ SvxAdjustItem aAdjustItem(SvxAdjust::Left, RES_PARATR_ADJUST);
+ rSh.SetAttrItem(aAdjustItem);
+ break;
+ }
+ case 1:
+ {
+ SvxAdjustItem aAdjustItem(SvxAdjust::Center, RES_PARATR_ADJUST);
+ rSh.SetAttrItem(aAdjustItem);
+ break;
+ }
+ case 2:
+ {
+ SvxAdjustItem aAdjustItem(SvxAdjust::Right, RES_PARATR_ADJUST);
+ rSh.SetAttrItem(aAdjustItem);
+ break;
+ }
+ }
+
+ // Insert page number
+ SwFieldMgr aMgr(pShell);
+ SwInsertField_Data aData(SwFieldTypesEnum::PageNumber, 0,
+ OUString(), OUString(), SVX_NUM_PAGEDESC);
+ aMgr.InsertField(aData);
+
+ rSh.SwCursorShell::Pop(SwCursorShell::PopMode::DeleteCurrent);
+ rSh.EndAllAction();
+ rSh.LockView(false);
+ rDoc->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_PAGE_NUMBER, nullptr);
+ }
+ pDlg->disposeOnce();
+ });
+ rReq.Done();
+ }
+ break;
+ case FN_UPDATE_TEXT_FORMFIELD:
+ {
+ // This updates a single fieldmarks under the current cursor.
+ OUString aFieldType;
+ const SfxStringItem* pFieldType = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pFieldType)
+ {
+ aFieldType = pFieldType->GetValue();
+ }
+ OUString aFieldCommandPrefix;
+ const SfxStringItem* pFieldCommandPrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (pFieldCommandPrefix)
+ {
+ aFieldCommandPrefix = pFieldCommandPrefix->GetValue();
+ }
+ uno::Sequence<beans::PropertyValue> aField;
+ const SfxUnoAnyItem* pFields = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_3);
+ if (pFields)
+ {
+ pFields->GetValue() >>= aField;
+ }
+
+ IDocumentMarkAccess& rIDMA = *rSh.getIDocumentMarkAccess();
+ SwPosition& rCursor = *rSh.GetCursor()->GetPoint();
+ sw::mark::IFieldmark* pFieldmark = rIDMA.getFieldmarkFor(rCursor);
+ if (!pFieldmark)
+ {
+ break;
+ }
+
+ if (pFieldmark->GetFieldname() != aFieldType)
+ {
+ break;
+ }
+
+ auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
+ if (itParam == pFieldmark->GetParameters()->end())
+ {
+ break;
+ }
+
+ OUString aCommand;
+ itParam->second >>= aCommand;
+ if (!aCommand.startsWith(aFieldCommandPrefix))
+ {
+ break;
+ }
+
+ rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
+ rSh.StartAction();
+ comphelper::SequenceAsHashMap aMap(aField);
+ itParam->second = aMap["FieldCommand"];
+ SwPaM aPaM(pFieldmark->GetMarkPos(), pFieldmark->GetOtherMarkPos());
+ aPaM.Normalize();
+ // Skip field start & separator.
+ aPaM.GetPoint()->nContent += 2;
+ // Skip field end.
+ aPaM.GetMark()->nContent -= 1;
+ rSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPaM);
+ OUString aFieldResult;
+ aMap["FieldResult"] >>= aFieldResult;
+ SwTranslateHelper::PasteHTMLToPaM(rSh, &aPaM, aFieldResult.toUtf8(), true);
+
+ rSh.EndAction();
+ rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr);
+ }
+ break;
default:
OSL_FAIL("wrong dispatcher");
return;
@@ -976,6 +1364,7 @@ void SwTextShell::InsertHyperlink(const SvxHyperlinkItem& rHlnkItem)
const OUString& rName = rHlnkItem.GetName();
const OUString& rURL = rHlnkItem.GetURL();
const OUString& rTarget = rHlnkItem.GetTargetFrame();
+ const OUString& rReplacementText = rHlnkItem.GetReplacementText();
sal_uInt16 nType = o3tl::narrowing<sal_uInt16>(rHlnkItem.GetInsertMode());
nType &= ~HLINK_HTMLMODE;
const SvxMacroTableDtor* pMacroTable = rHlnkItem.GetMacroTable();
@@ -1015,7 +1404,19 @@ void SwTextShell::InsertHyperlink(const SvxHyperlinkItem& rHlnkItem)
aINetFormat.SetMacro(SvMacroItemId::OnMouseOut, *pMacro);
}
rSh.SttSelect();
- rSh.InsertURL( aINetFormat, rName, true );
+ // inserting mention
+ if (comphelper::LibreOfficeKit::isActive() && !rReplacementText.isEmpty())
+ {
+ SwPaM* pCursorPos = rSh.GetCursor();
+ // move cursor backwards to select @mention
+ for(int i=0; i < rReplacementText.getLength(); i++)
+ pCursorPos->Move(fnMoveBackward);
+ rSh.InsertURL( aINetFormat, rName, false );
+ }
+ else
+ {
+ rSh.InsertURL( aINetFormat, rName, true );
+ }
rSh.EndSelect();
}
break;
diff --git a/sw/source/uibase/shells/textsh.cxx b/sw/source/uibase/shells/textsh.cxx
index 032545b3cf45..d81c32245445 100644
--- a/sw/source/uibase/shells/textsh.cxx
+++ b/sw/source/uibase/shells/textsh.cxx
@@ -244,6 +244,16 @@ void SwTextShell::ExecInsert(SfxRequest &rReq)
rReq.Done();
break;
+ case FN_INSERT_PLAIN_TEXT_CONTENT_CONTROL:
+ rSh.InsertContentControl(SwContentControlType::PLAIN_TEXT);
+ rReq.Done();
+ break;
+
+ case FN_INSERT_COMBO_BOX_CONTENT_CONTROL:
+ rSh.InsertContentControl(SwContentControlType::COMBO_BOX);
+ rReq.Done();
+ break;
+
case FN_CONTENT_CONTROL_PROPERTIES:
{
SwWrtShell& rWrtSh = GetShell();
diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx
index 8d7c07e104ca..6f51980d6d0d 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -102,7 +102,16 @@
#include <xmloff/odffields.hxx>
#include <bookmark.hxx>
#include <linguistic/misc.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/scopeguard.hxx>
#include <authfld.hxx>
+#include <translatelangselect.hxx>
+#include <svtools/deeplcfg.hxx>
+#include <translatehelper.hxx>
+#include <IDocumentContentOperations.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <fmtcntnt.hxx>
+#include <fmtrfmrk.hxx>
using namespace ::com::sun::star;
using namespace com::sun::star::beans;
@@ -375,6 +384,373 @@ OUString GetLocalURL(const SwWrtShell& rSh)
return rLocalURL;
}
+void UpdateSections(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ OUString aSectionNamePrefix;
+ const SfxStringItem* pSectionNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pSectionNamePrefix)
+ {
+ aSectionNamePrefix = pSectionNamePrefix->GetValue();
+ }
+
+ uno::Sequence<beans::PropertyValues> aSections;
+ const SfxUnoAnyItem* pSections = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_2);
+ if (pSections)
+ {
+ pSections->GetValue() >>= aSections;
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSSECTION, nullptr);
+ rWrtSh.StartAction();
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ sal_Int32 nSectionIndex = 0;
+ const SwSectionFormats& rFormats = pDoc->GetSections();
+ IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations();
+ for (size_t i = 0; i < rFormats.size(); ++i)
+ {
+ const SwSectionFormat* pFormat = rFormats[i];
+ if (!pFormat->GetName().startsWith(aSectionNamePrefix))
+ {
+ continue;
+ }
+
+ if (nSectionIndex >= aSections.getLength())
+ {
+ break;
+ }
+
+ comphelper::SequenceAsHashMap aMap(aSections[nSectionIndex++]);
+ OUString aSectionName = aMap["RegionName"].get<OUString>();
+ if (aSectionName != pFormat->GetName())
+ {
+ const_cast<SwSectionFormat*>(pFormat)->SetName(aSectionName, /*bBroadcast=*/true);
+ SwSectionData aSectionData(*pFormat->GetSection());
+ aSectionData.SetSectionName(aSectionName);
+ pDoc->UpdateSection(i, aSectionData);
+ }
+
+ const SwFormatContent& rContent = pFormat->GetContent();
+ const SwNodeIndex* pContentNodeIndex = rContent.GetContentIdx();
+ if (pContentNodeIndex)
+ {
+ SwPaM aSectionStart(SwPosition{*pContentNodeIndex});
+ aSectionStart.Move(fnMoveForward, GoInContent);
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
+ *pCursorPos = aSectionStart;
+ rWrtSh.EndOfSection(/*bSelect=*/true);
+ rIDCO.DeleteAndJoin(*pCursorPos);
+ rWrtSh.EndSelect();
+
+ OUString aSectionText = aMap["Content"].get<OUString>();
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aSectionText.toUtf8(), true);
+ }
+ }
+
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSSECTION, nullptr);
+}
+
+void DeleteSections(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ OUString aSectionNamePrefix;
+ const SfxStringItem* pSectionNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pSectionNamePrefix)
+ {
+ aSectionNamePrefix = pSectionNamePrefix->GetValue();
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELSECTION, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELSECTION, nullptr);
+ });
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ SwSectionFormats& rFormats = pDoc->GetSections();
+ std::vector<SwSectionFormat*> aRemovals;
+ for (size_t i = 0; i < rFormats.size(); ++i)
+ {
+ SwSectionFormat* pFormat = rFormats[i];
+
+ if (!aSectionNamePrefix.isEmpty())
+ {
+ if (!pFormat->GetName().startsWith(aSectionNamePrefix))
+ {
+ continue;
+ }
+ }
+
+ aRemovals.push_back(pFormat);
+ }
+
+ for (const auto& pFormat : aRemovals)
+ {
+ // Just delete the format, not the content of the section.
+ pDoc->DelSectionFormat(pFormat);
+ }
+}
+
+void UpdateBookmarks(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ if (rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
+ {
+ return;
+ }
+
+ OUString aBookmarkNamePrefix;
+ const SfxStringItem* pBookmarkNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pBookmarkNamePrefix)
+ {
+ aBookmarkNamePrefix = pBookmarkNamePrefix->GetValue();
+ }
+
+ uno::Sequence<beans::PropertyValues> aBookmarks;
+ const SfxUnoAnyItem* pBookmarks = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_2);
+ if (pBookmarks)
+ {
+ pBookmarks->GetValue() >>= aBookmarks;
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+
+ IDocumentMarkAccess& rIDMA = *rWrtSh.GetDoc()->getIDocumentMarkAccess();
+ sal_Int32 nBookmarkIndex = 0;
+ bool bSortMarks = false;
+ for (auto it = rIDMA.getBookmarksBegin(); it != rIDMA.getBookmarksEnd(); ++it)
+ {
+ auto pMark = dynamic_cast<sw::mark::Bookmark*>(*it);
+ assert(pMark);
+ if (!pMark->GetName().startsWith(aBookmarkNamePrefix))
+ {
+ continue;
+ }
+
+ if (aBookmarks.getLength() <= nBookmarkIndex)
+ {
+ continue;
+ }
+
+ comphelper::SequenceAsHashMap aMap(aBookmarks[nBookmarkIndex++]);
+ if (aMap["Bookmark"].get<OUString>() != pMark->GetName())
+ {
+ rIDMA.renameMark(pMark, aMap["Bookmark"].get<OUString>());
+ }
+
+ OUString aBookmarkText = aMap["BookmarkText"].get<OUString>();
+
+ // Insert markers to remember where the paste positions are.
+ SwPaM aMarkers(pMark->GetMarkEnd());
+ IDocumentContentOperations& rIDCO = rWrtSh.GetDoc()->getIDocumentContentOperations();
+ bool bSuccess = rIDCO.InsertString(aMarkers, "XY");
+ if (bSuccess)
+ {
+ SwPaM aPasteEnd(pMark->GetMarkEnd());
+ aPasteEnd.Move(fnMoveForward, GoInContent);
+
+ // Paste HTML content.
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
+ *pCursorPos = aPasteEnd;
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aBookmarkText.toUtf8(), true);
+
+ // Update the bookmark to point to the new content.
+ SwPaM aPasteStart(pMark->GetMarkEnd());
+ aPasteStart.Move(fnMoveForward, GoInContent);
+ SwPaM aStartMarker(pMark->GetMarkStart(), *aPasteStart.GetPoint());
+ SwPaM aEndMarker(*aPasteEnd.GetPoint(), *aPasteEnd.GetPoint());
+ aEndMarker.GetMark()->nContent += 1;
+ pMark->SetMarkPos(*aPasteStart.GetPoint());
+ pMark->SetOtherMarkPos(*aPasteEnd.GetPoint());
+ bSortMarks = true;
+
+ // Remove markers. the start marker includes the old content as well.
+ rIDCO.DeleteAndJoin(aStartMarker);
+ rIDCO.DeleteAndJoin(aEndMarker);
+ }
+ }
+ if (bSortMarks)
+ {
+ rIDMA.assureSortedMarkContainers();
+ }
+
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSBOOKMARK, nullptr);
+}
+
+void UpdateBookmark(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ if (rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
+ {
+ return;
+ }
+
+ OUString aBookmarkNamePrefix;
+ const SfxStringItem* pBookmarkNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pBookmarkNamePrefix)
+ {
+ aBookmarkNamePrefix = pBookmarkNamePrefix->GetValue();
+ }
+
+ uno::Sequence<beans::PropertyValue> aBookmark;
+ const SfxUnoAnyItem* pBookmarks = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_2);
+ if (pBookmarks)
+ {
+ pBookmarks->GetValue() >>= aBookmark;
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSBOOKMARK, nullptr);
+ });
+
+ IDocumentMarkAccess& rIDMA = *rWrtSh.GetDoc()->getIDocumentMarkAccess();
+ SwPosition& rCursor = *rWrtSh.GetCursor()->GetPoint();
+ auto pBookmark = dynamic_cast<sw::mark::Bookmark*>(rIDMA.getBookmarkFor(rCursor));
+ if (!pBookmark || !pBookmark->GetName().startsWith(aBookmarkNamePrefix))
+ {
+ return;
+ }
+
+ comphelper::SequenceAsHashMap aMap(aBookmark);
+ if (aMap["Bookmark"].get<OUString>() != pBookmark->GetName())
+ {
+ rIDMA.renameMark(pBookmark, aMap["Bookmark"].get<OUString>());
+ }
+
+ OUString aBookmarkText = aMap["BookmarkText"].get<OUString>();
+
+ // Insert markers to remember where the paste positions are.
+ SwPaM aMarkers(pBookmark->GetMarkEnd());
+ IDocumentContentOperations& rIDCO = rWrtSh.GetDoc()->getIDocumentContentOperations();
+ if (!rIDCO.InsertString(aMarkers, "XY"))
+ {
+ return;
+ }
+
+ SwPaM aPasteEnd(pBookmark->GetMarkEnd());
+ aPasteEnd.Move(fnMoveForward, GoInContent);
+
+ // Paste HTML content.
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
+ *pCursorPos = aPasteEnd;
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aBookmarkText.toUtf8(), true);
+
+ // Update the bookmark to point to the new content.
+ SwPaM aPasteStart(pBookmark->GetMarkEnd());
+ aPasteStart.Move(fnMoveForward, GoInContent);
+ SwPaM aStartMarker(pBookmark->GetMarkStart(), *aPasteStart.GetPoint());
+ SwPaM aEndMarker(*aPasteEnd.GetPoint(), *aPasteEnd.GetPoint());
+ aEndMarker.GetMark()->nContent += 1;
+ pBookmark->SetMarkPos(*aPasteStart.GetPoint());
+ pBookmark->SetOtherMarkPos(*aPasteEnd.GetPoint());
+
+ // Remove markers. the start marker includes the old content as well.
+ rIDCO.DeleteAndJoin(aStartMarker);
+ rIDCO.DeleteAndJoin(aEndMarker);
+ rIDMA.assureSortedMarkContainers();
+}
+
+void DeleteBookmarks(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ if (rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
+ {
+ return;
+ }
+
+ OUString aBookmarkNamePrefix;
+ const SfxStringItem* pBookmarkNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pBookmarkNamePrefix)
+ {
+ aBookmarkNamePrefix = pBookmarkNamePrefix->GetValue();
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELBOOKMARK, nullptr);
+ });
+
+ IDocumentMarkAccess* pMarkAccess = rWrtSh.GetDoc()->getIDocumentMarkAccess();
+ std::vector<sw::mark::IMark*> aRemovals;
+ for (auto it = pMarkAccess->getBookmarksBegin(); it != pMarkAccess->getBookmarksEnd(); ++it)
+ {
+ auto pBookmark = dynamic_cast<sw::mark::Bookmark*>(*it);
+ assert(pBookmark);
+
+ if (!aBookmarkNamePrefix.isEmpty())
+ {
+ if (!pBookmark->GetName().startsWith(aBookmarkNamePrefix))
+ {
+ continue;
+ }
+ }
+
+ aRemovals.push_back(pBookmark);
+ }
+
+ for (const auto& pMark : aRemovals)
+ {
+ pMarkAccess->deleteMark(pMark);
+ }
+}
+
+void DeleteFields(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ const SfxStringItem* pTypeName = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (!pTypeName || pTypeName->GetValue() != "SetRef")
+ {
+ // This is implemented so far only for reference marks.
+ return;
+ }
+
+ OUString aNamePrefix;
+ const SfxStringItem* pNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (pNamePrefix)
+ {
+ aNamePrefix = pNamePrefix->GetValue();
+ }
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELBOOKMARK, nullptr);
+ });
+
+ std::vector<const SwFormatRefMark*> aRemovals;
+ for (sal_uInt16 i = 0; i < pDoc->GetRefMarks(); ++i)
+ {
+ const SwFormatRefMark* pRefMark = pDoc->GetRefMark(i);
+ if (!aNamePrefix.isEmpty())
+ {
+ if (!pRefMark->GetRefName().startsWith(aNamePrefix))
+ {
+ continue;
+ }
+ }
+
+ aRemovals.push_back(pRefMark);
+ }
+
+ for (const auto& pMark : aRemovals)
+ {
+ pDoc->DeleteFormatRefMark(pMark);
+ }
+}
}
void SwTextShell::Execute(SfxRequest &rReq)
@@ -690,10 +1066,52 @@ void SwTextShell::Execute(SfxRequest &rReq)
}
case FN_INSERT_BOOKMARK:
{
+ const SfxStringItem* pBookmarkText = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
if ( pItem )
{
+ rWrtSh.StartAction();
OUString sName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ if (pBookmarkText)
+ {
+ OUString aBookmarkText = pBookmarkText->GetValue();
+ // Split node to remember where the start position is.
+ bool bSuccess = rWrtSh.GetDoc()->getIDocumentContentOperations().SplitNode(
+ *pCursorPos->GetPoint(), /*bChkTableStart=*/false);
+ if (bSuccess)
+ {
+ SwPaM aBookmarkPam(*pCursorPos->GetPoint());
+ aBookmarkPam.Move(fnMoveBackward, GoInContent);
+
+ // Paste HTML content.
+ SwTranslateHelper::PasteHTMLToPaM(
+ rWrtSh, pCursorPos, aBookmarkText.toUtf8(), /*bSetSelection=*/true);
+ if (pCursorPos->GetPoint()->nContent == 0)
+ {
+ // The paste created a last empty text node, remove it.
+ SwPaM aPam(*pCursorPos->GetPoint());
+ aPam.SetMark();
+ aPam.Move(fnMoveBackward, GoInContent);
+ rWrtSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPam);
+ }
+
+ // Undo the above SplitNode().
+ aBookmarkPam.SetMark();
+ aBookmarkPam.Move(fnMoveForward, GoInContent);
+ rWrtSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(
+ aBookmarkPam);
+ *aBookmarkPam.GetMark() = *pCursorPos->GetPoint();
+ *pCursorPos = aBookmarkPam;
+ }
+ }
+
rWrtSh.SetBookmark( vcl::KeyCode(), sName );
+ if (pBookmarkText)
+ {
+ pCursorPos->DeleteMark();
+ }
+ rWrtSh.EndAction();
}
else
{
@@ -706,8 +1124,22 @@ void SwTextShell::Execute(SfxRequest &rReq)
break;
}
+ case FN_UPDATE_BOOKMARKS:
+ {
+ // This updates all bookmarks in the document that match the conditions specified in
+ // rReq.
+ UpdateBookmarks(rReq, rWrtSh);
+ break;
+ }
+ case FN_UPDATE_BOOKMARK:
+ {
+ // This updates the bookmark under the cursor.
+ UpdateBookmark(rReq, rWrtSh);
+ break;
+ }
case FN_DELETE_BOOKMARK:
{
+ // This deletes a bookmark with the specified name.
if (pItem && !rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
{
IDocumentMarkAccess* const pMarkAccess = rWrtSh.getIDocumentMarkAccess();
@@ -715,6 +1147,30 @@ void SwTextShell::Execute(SfxRequest &rReq)
}
break;
}
+ case FN_DELETE_BOOKMARKS:
+ {
+ // This deletes all bookmarks in the document matching a specified prefix.
+ DeleteBookmarks(rReq, rWrtSh);
+ break;
+ }
+ case FN_DELETE_FIELDS:
+ {
+ // This deletes all fields in the document matching a specified type & prefix.
+ DeleteFields(rReq, rWrtSh);
+ break;
+ }
+ case FN_UPDATE_SECTIONS:
+ {
+ UpdateSections(rReq, rWrtSh);
+ break;
+ }
+ case FN_DELETE_SECTIONS:
+ {
+ // This deletes all sections in the document matching a specified prefix. Note that the
+ // section is deleted, but not its contents.
+ DeleteSections(rReq, rWrtSh);
+ break;
+ }
case FN_SET_REMINDER:
{
// collect and sort navigator reminder names
@@ -1503,6 +1959,32 @@ void SwTextShell::Execute(SfxRequest &rReq)
}
}
break;
+ case SID_FM_TRANSLATE:
+ {
+ const SfxPoolItem* pTargetLangStringItem = nullptr;
+ if (pArgs && SfxItemState::SET == pArgs->GetItemState(SID_ATTR_TARGETLANG_STR, false, &pTargetLangStringItem))
+ {
+ SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+ if (rDeeplOptions.getAPIUrl().isEmpty() || rDeeplOptions.getAuthKey().isEmpty())
+ {
+ SAL_WARN("translate", "API options are not set");
+ break;
+ }
+ const OString aAPIUrl = OUStringToOString(OUString(rDeeplOptions.getAPIUrl() + "?tag_handling=html"), RTL_TEXTENCODING_UTF8).trim();
+ const OString aAuthKey = OUStringToOString(rDeeplOptions.getAuthKey(), RTL_TEXTENCODING_UTF8).trim();
+ OString aTargetLang = OUStringToOString(static_cast<const SfxStringItem*>(pTargetLangStringItem)->GetValue(), RTL_TEXTENCODING_UTF8);
+ SwTranslateHelper::TranslateAPIConfig aConfig({aAPIUrl, aAuthKey, aTargetLang});
+ SwTranslateHelper::TranslateDocument(rWrtSh, aConfig);
+ }
+ else
+ {
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ std::shared_ptr<AbstractSwTranslateLangSelectDlg> pAbstractDialog(pFact->CreateSwTranslateLangSelectDlg(GetView().GetFrameWeld(), rWrtSh));
+ std::shared_ptr<weld::DialogController> pDialogController(pAbstractDialog->getDialogController());
+ weld::DialogController::runAsync(pDialogController, [] (sal_Int32 /*nResult*/) { });
+ }
+ }
+ break;
case SID_SPELLCHECK_IGNORE:
{
SwPaM *pPaM = rWrtSh.GetCursor();
@@ -1536,9 +2018,12 @@ void SwTextShell::Execute(SfxRequest &rReq)
SwPaM *pPaM = rWrtSh.GetCursor();
if (pPaM)
SwEditShell::IgnoreGrammarErrorAt( *pPaM );
- // refresh the layout of all paragraphs (workaround to launch a dictionary event)
- xDictionary->setActive(false);
- xDictionary->setActive(true);
+ if (xDictionary.is())
+ {
+ // refresh the layout of all paragraphs (workaround to launch a dictionary event)
+ xDictionary->setActive(false);
+ xDictionary->setActive(true);
+ }
}
catch( const uno::Exception& )
{
@@ -1973,6 +2458,16 @@ void SwTextShell::GetState( SfxItemSet &rSet )
}
break;
+ case SID_FM_TRANSLATE:
+ {
+ const SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+ if (rDeeplOptions.getAPIUrl().isEmpty() || rDeeplOptions.getAuthKey().isEmpty())
+ {
+ rSet.DisableItem(nWhich);
+ }
+ }
+ break;
+
case SID_HYPERLINK_DIALOG:
if( GetView().GetDocShell()->IsReadOnly()
|| ( !GetView().GetViewFrame()->HasChildWindow(nWhich)
diff --git a/sw/source/uibase/shells/translatehelper.cxx b/sw/source/uibase/shells/translatehelper.cxx
new file mode 100644
index 000000000000..36ae57d177f6
--- /dev/null
+++ b/sw/source/uibase/shells/translatehelper.cxx
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <wrtsh.hxx>
+#include <pam.hxx>
+#include <node.hxx>
+#include <ndtxt.hxx>
+#include <translatehelper.hxx>
+#include <sal/log.hxx>
+#include <rtl/string.h>
+#include <shellio.hxx>
+#include <vcl/scheduler.hxx>
+#include <vcl/svapp.hxx>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <vcl/htmltransferable.hxx>
+#include <vcl/transfer.hxx>
+#include <swdtflvr.hxx>
+#include <linguistic/translate.hxx>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <sfx2/viewfrm.hxx>
+#include <com/sun/star/task/XStatusIndicatorFactory.hpp>
+#include <strings.hrc>
+
+namespace SwTranslateHelper
+{
+OString ExportPaMToHTML(SwPaM* pCursor, bool bReplacePTag)
+{
+ SolarMutexGuard gMutex;
+ OString aResult;
+ WriterRef xWrt;
+ GetHTMLWriter(OUString("NoLineLimit,SkipHeaderFooter,NoPrettyPrint"), OUString(), xWrt);
+ if (pCursor != nullptr)
+ {
+ SvMemoryStream aMemoryStream;
+ SwWriter aWriter(aMemoryStream, *pCursor);
+ ErrCode nError = aWriter.Write(xWrt);
+ if (nError.IsError())
+ {
+ SAL_WARN("translatehelper", "failed to export selection to HTML");
+ return {};
+ }
+ aResult
+ = OString(static_cast<const char*>(aMemoryStream.GetData()), aMemoryStream.GetSize());
+ if (bReplacePTag)
+ {
+ aResult = aResult.replaceAll("<p", "<span");
+ aResult = aResult.replaceAll("</p>", "</span>");
+ }
+
+ // HTML has for that <br> and <p> also does new line
+ aResult = aResult.replaceAll("<ul>", "");
+ aResult = aResult.replaceAll("</ul>", "");
+ aResult = aResult.replaceAll("<ol>", "");
+ aResult = aResult.replaceAll("</ol>", "");
+ aResult = aResult.replaceAll("\n", "").trim();
+ return aResult;
+ }
+ return {};
+}
+
+void PasteHTMLToPaM(SwWrtShell& rWrtSh, SwPaM* pCursor, const OString& rData, bool bSetSelection)
+{
+ SolarMutexGuard gMutex;
+ rtl::Reference<vcl::unohelper::HtmlTransferable> pHtmlTransferable
+ = new vcl::unohelper::HtmlTransferable(rData);
+ if (pHtmlTransferable.is())
+ {
+ TransferableDataHelper aDataHelper(pHtmlTransferable);
+ if (aDataHelper.GetXTransferable().is()
+ && SwTransferable::IsPasteSpecial(rWrtSh, aDataHelper))
+ {
+ if (bSetSelection)
+ {
+ rWrtSh.SetSelection(*pCursor);
+ }
+ SwTransferable::Paste(rWrtSh, aDataHelper);
+ rWrtSh.KillSelection(nullptr, false);
+ }
+ }
+}
+
+void TranslateDocument(SwWrtShell& rWrtSh, const TranslateAPIConfig& rConfig)
+{
+ bool bCancel = false;
+ TranslateDocumentCancellable(rWrtSh, rConfig, bCancel);
+}
+
+void TranslateDocumentCancellable(SwWrtShell& rWrtSh, const TranslateAPIConfig& rConfig,
+ bool& rCancelTranslation)
+{
+ auto m_pCurrentPam = rWrtSh.GetCursor();
+ bool bHasSelection = rWrtSh.HasSelection();
+
+ if (bHasSelection)
+ {
+ // iteration will start top to bottom
+ if (m_pCurrentPam->GetPoint()->nNode > m_pCurrentPam->GetMark()->nNode)
+ m_pCurrentPam->Exchange();
+ }
+
+ auto const& pNodes = rWrtSh.GetNodes();
+ auto pPoint = SwPosition(*m_pCurrentPam->GetPoint());
+ auto pMark = SwPosition(*m_pCurrentPam->GetMark());
+ auto startNode = bHasSelection ? pPoint.nNode.GetIndex() : SwNodeOffset(0);
+ auto endNode = bHasSelection ? pMark.nNode.GetIndex() : pNodes.Count() - 1;
+
+ sal_Int32 nCount(0);
+ sal_Int32 nProgress(0);
+
+ for (SwNodeOffset n(startNode); n <= endNode; ++n)
+ {
+ if (pNodes[n] && pNodes[n]->IsTextNode())
+ {
+ if (pNodes[n]->GetTextNode()->GetText().isEmpty())
+ continue;
+ nCount++;
+ }
+ }
+
+ SfxViewFrame* pFrame = SfxViewFrame::Current();
+ uno::Reference<frame::XFrame> xFrame = pFrame->GetFrame().GetFrameInterface();
+ uno::Reference<task::XStatusIndicatorFactory> xProgressFactory(xFrame, uno::UNO_QUERY);
+ uno::Reference<task::XStatusIndicator> xStatusIndicator;
+
+ if (xProgressFactory.is())
+ {
+ xStatusIndicator = xProgressFactory->createStatusIndicator();
+ }
+
+ if (xStatusIndicator.is())
+ xStatusIndicator->start(SwResId(STR_STATSTR_SWTRANSLATE), nCount);
+
+ for (SwNodeOffset n(startNode); n <= endNode; ++n)
+ {
+ if (rCancelTranslation)
+ break;
+
+ if (n >= rWrtSh.GetNodes().Count())
+ break;
+
+ if (!pNodes[n])
+ break;
+
+ SwNode* pNode = pNodes[n];
+ if (pNode->IsTextNode())
+ {
+ if (pNode->GetTextNode()->GetText().isEmpty())
+ continue;
+
+ auto cursor
+ = Writer::NewUnoCursor(*rWrtSh.GetDoc(), pNode->GetIndex(), pNode->GetIndex());
+
+ // set edges (start, end) for nodes inside the selection.
+ if (bHasSelection)
+ {
+ if (startNode == endNode)
+ {
+ cursor->SetMark();
+ cursor->GetPoint()->nContent = pPoint.nContent;
+ cursor->GetMark()->nContent = pMark.nContent;
+ }
+ else if (n == startNode)
+ {
+ cursor->SetMark();
+ cursor->GetPoint()->nContent = std::min(pPoint.nContent, pMark.nContent);
+ }
+ else if (n == endNode)
+ {
+ cursor->SetMark();
+ cursor->GetMark()->nContent = pMark.nContent;
+ cursor->GetPoint()->nContent = 0;
+ }
+ }
+
+ const auto aOut = SwTranslateHelper::ExportPaMToHTML(cursor.get(), true);
+ const auto aTranslatedOut = linguistic::Translate(
+ rConfig.m_xTargetLanguage, rConfig.m_xAPIUrl, rConfig.m_xAuthKey, aOut);
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, cursor.get(), aTranslatedOut, true);
+
+ if (xStatusIndicator.is())
+ xStatusIndicator->setValue((100 * ++nProgress) / nCount);
+
+ Idle aIdle("ProgressBar::SetValue aIdle");
+ aIdle.SetPriority(TaskPriority::POST_PAINT);
+ aIdle.Start();
+
+ rWrtSh.LockView(true);
+ while (aIdle.IsActive() && !Application::IsQuit())
+ {
+ Application::Yield();
+ }
+ rWrtSh.LockView(false);
+ }
+ }
+
+ if (xStatusIndicator.is())
+ xStatusIndicator->end();
+}
+} \ No newline at end of file
diff --git a/sw/source/uibase/sidebar/ThemePanel.cxx b/sw/source/uibase/sidebar/ThemePanel.cxx
index 974f32cb0fa6..7f2dd73fdbf2 100644
--- a/sw/source/uibase/sidebar/ThemePanel.cxx
+++ b/sw/source/uibase/sidebar/ThemePanel.cxx
@@ -8,6 +8,7 @@
*
*/
+#include "ThemePanel.hxx"
#include <sal/config.h>
#include "ThemePanel.hxx"
@@ -24,402 +25,20 @@
#include <vcl/virdev.hxx>
#include <charatr.hxx>
#include <charfmt.hxx>
+#include <doc.hxx>
#include <docsh.hxx>
-#include <docstyle.hxx>
-#include <fmtcol.hxx>
-#include <format.hxx>
-
-namespace
-{
-
-class FontSet
-{
-public:
- OUString maName;
- OUString msMonoFont;
- OUString msHeadingFont;
- OUString msBaseFont;
-};
-
-class ColorVariable
-{
-public:
- tools::Long mnIndex;
- sal_Int16 mnTintShade;
-
- ColorVariable()
- : mnIndex(-1)
- , mnTintShade()
- {}
-
- ColorVariable(tools::Long nIndex, sal_Int16 nTintShade)
- : mnIndex(nIndex)
- , mnTintShade(nTintShade)
- {}
-};
-
-class StyleRedefinition
-{
- ColorVariable maVariable;
-
-public:
- OUString maElementName;
-
-public:
- explicit StyleRedefinition(const OUString& aElementName)
- : maElementName(aElementName)
- {}
-
- void setColorVariable(ColorVariable aVariable)
- {
- maVariable = aVariable;
- }
-
- Color getColor(svx::ColorSet const & rColorSet)
- {
- Color aColor;
- if (maVariable.mnIndex > -1)
- {
- aColor = rColorSet.getColor(maVariable.mnIndex);
- aColor.ApplyTintOrShade(maVariable.mnTintShade);
- }
- else
- {
- aColor = COL_BLACK;
- }
- return aColor;
- }
-};
-
-class StyleSet
-{
- std::vector<StyleRedefinition> maStyles;
-
-public:
- explicit StyleSet()
- {}
-
- void add(StyleRedefinition const & aRedefinition)
- {
- maStyles.push_back(aRedefinition);
- }
-
- StyleRedefinition* get(std::u16string_view aString)
- {
- for (StyleRedefinition & rStyle : maStyles)
- {
- if (rStyle.maElementName == aString)
- {
- return &rStyle;
- }
- }
- return nullptr;
- }
-};
-
-StyleSet setupThemes()
-{
- StyleSet aSet;
-
- {
- StyleRedefinition aRedefinition("Heading 1");
- aRedefinition.setColorVariable(ColorVariable(10, -1000));
- aSet.add(aRedefinition);
- }
-
- {
- StyleRedefinition aRedefinition("Heading 2");
- aRedefinition.setColorVariable(ColorVariable(7, -500));
- aSet.add(aRedefinition);
- }
-
- {
- StyleRedefinition aRedefinition("Heading 3");
- aRedefinition.setColorVariable(ColorVariable(5, 0));
- aSet.add(aRedefinition);
- }
-
- {
- StyleRedefinition aRedefinition("Heading 4");
- aRedefinition.setColorVariable(ColorVariable(6, -1000));
- aSet.add(aRedefinition);
- }
-
- {
- StyleRedefinition aRedefinition("Heading 5");
- aRedefinition.setColorVariable(ColorVariable(4, -1500));
- aSet.add(aRedefinition);
- }
-
- {
- StyleRedefinition aRedefinition("Heading 6");
- aRedefinition.setColorVariable(ColorVariable(3, -2500));
- aSet.add(aRedefinition);
- }
-
- {
- StyleRedefinition aRedefinition("Heading 7");
- aRedefinition.setColorVariable(ColorVariable(3, -2500));
- aSet.add(aRedefinition);
- }
-
- {
- StyleRedefinition aRedefinition("Heading 8");
- aRedefinition.setColorVariable(ColorVariable(2, 0));
- aSet.add(aRedefinition);
- }
-
- {
- StyleRedefinition aRedefinition("Heading 9");
- aRedefinition.setColorVariable(ColorVariable(2, 0));
- aSet.add(aRedefinition);
- }
-
- {
- StyleRedefinition aRedefinition("Heading 10");
- aRedefinition.setColorVariable(ColorVariable(0, 0));
- aSet.add(aRedefinition);
- }
-
- return aSet;
-}
-
-void changeFont(SwFormat* pFormat, SwDocStyleSheet const * pStyle, FontSet const & rFontSet)
-{
- if (pStyle->GetName() != "Default Style" && pFormat->GetAttrSet().GetItem(RES_CHRATR_FONT, false) == nullptr)
- {
- return;
- }
-
- SvxFontItem aFontItem(pFormat->GetFont(false));
-
- FontPitch ePitch = aFontItem.GetPitch();
-
- if (ePitch == PITCH_FIXED)
- {
- aFontItem.SetFamilyName(rFontSet.msMonoFont);
- }
- else
- {
- if (pStyle->GetName() == "Heading")
- {
- aFontItem.SetFamilyName(rFontSet.msHeadingFont);
- }
- else
- {
- aFontItem.SetFamilyName(rFontSet.msBaseFont);
- }
- }
-
- pFormat->SetFormatAttr(aFontItem);
-}
-
-/*void changeBorder(SwTextFormatColl* pCollection, SwDocStyleSheet* pStyle, StyleSet& rStyleSet)
-{
- if (pStyle->GetName() == "Heading")
- {
- SvxBoxItem aBoxItem(pCollection->GetBox());
- editeng::SvxBorderLine aBorderLine;
- aBorderLine.SetWidth(40); //20 = 1pt
- aBorderLine.SetColor(rColorSet.mBaseColors[0]);
- aBoxItem.SetLine(&aBorderLine, SvxBoxItemLine::BOTTOM);
-
- pCollection->SetFormatAttr(aBoxItem);
- }
-}*/
-
-void changeColor(SwTextFormatColl* pCollection, svx::ColorSet const & rColorSet, StyleRedefinition* pRedefinition)
-{
- Color aColor = pRedefinition->getColor(rColorSet);
-
- SvxColorItem aColorItem(pCollection->GetColor());
- aColorItem.SetValue(aColor);
- pCollection->SetFormatAttr(aColorItem);
-}
-
-std::vector<FontSet> initFontSets()
-{
- std::vector<FontSet> aFontSets;
- {
- FontSet aFontSet;
- aFontSet.maName = "Liberation Family";
- aFontSet.msHeadingFont = "Liberation Sans";
- aFontSet.msBaseFont = "Liberation Serif";
- aFontSet.msMonoFont = "Liberation Mono";
- aFontSets.push_back(aFontSet);
- }
- {
- FontSet aFontSet;
- aFontSet.maName = "DejaVu Family";
- aFontSet.msHeadingFont = "DejaVu Sans";
- aFontSet.msBaseFont = "DejaVu Serif";
- aFontSet.msMonoFont = "DejaVu Sans Mono";
- aFontSets.push_back(aFontSet);
- }
- {
- FontSet aFontSet;
- aFontSet.maName = "Croscore Modern";
- aFontSet.msHeadingFont = "Caladea";
- aFontSet.msBaseFont = "Carlito";
- aFontSet.msMonoFont = "Liberation Mono";
- aFontSets.push_back(aFontSet);
- }
- {
- FontSet aFontSet;
- aFontSet.maName = "Carlito";
- aFontSet.msHeadingFont = "Carlito";
- aFontSet.msBaseFont = "Carlito";
- aFontSet.msMonoFont = "Liberation Mono";
- aFontSets.push_back(aFontSet);
- }
- {
- FontSet aFontSet;
- aFontSet.maName = "Source Sans Family";
- aFontSet.msHeadingFont = "Source Sans Pro";
- aFontSet.msBaseFont = "Source Sans Pro";
- aFontSet.msMonoFont = "Source Code Pro";
- aFontSets.push_back(aFontSet);
- }
- {
- FontSet aFontSet;
- aFontSet.maName = "Source Sans Family 2";
- aFontSet.msHeadingFont = "Source Sans Pro";
- aFontSet.msBaseFont = "Source Sans Pro Light";
- aFontSet.msMonoFont = "Source Code Pro";
- aFontSets.push_back(aFontSet);
- }
- {
- FontSet aFontSet;
- aFontSet.maName = "Libertine Family";
- aFontSet.msHeadingFont = "Linux Biolinum G";
- aFontSet.msBaseFont = "Linux Libertine G";
- aFontSet.msMonoFont = "Liberation Mono";
- aFontSets.push_back(aFontSet);
- }
- {
- FontSet aFontSet;
- aFontSet.maName = "Open Sans";
- aFontSet.msHeadingFont = "Open Sans";
- aFontSet.msBaseFont = "Open Sans";
- aFontSet.msMonoFont = "Droid Sans Mono";
- aFontSets.push_back(aFontSet);
- }
- {
- FontSet aFontSet;
- aFontSet.maName = "Droid Sans";
- aFontSet.msHeadingFont = "Droid Sans";
- aFontSet.msBaseFont = "Droid Sans";
- aFontSet.msMonoFont = "Droid Sans Mono";
- aFontSets.push_back(aFontSet);
- }
- return aFontSets;
-}
-
-FontSet getFontSet(std::u16string_view rFontVariant, std::vector<FontSet>& aFontSets)
-{
- for (const FontSet & rFontSet : aFontSets)
- {
- if (rFontSet.maName == rFontVariant)
- return rFontSet;
- }
- return aFontSets[0];
-}
-
-void applyTheme(SfxStyleSheetBasePool* pPool, std::u16string_view sFontSetName, std::u16string_view sColorSetName,
- StyleSet& rStyleSet, svx::ColorSets& rColorSets)
-{
- SwDocStyleSheet* pStyle;
-
- std::vector<FontSet> aFontSets = initFontSets();
- FontSet aFontSet = getFontSet(sFontSetName, aFontSets);
-
- svx::ColorSet aColorSet = rColorSets.getColorSet(sColorSetName);
-
- pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Para));
- while (pStyle)
- {
- SwTextFormatColl* pCollection = pStyle->GetCollection();
-
- changeFont(pCollection, pStyle, aFontSet);
-
- StyleRedefinition* pRedefinition = rStyleSet.get(pStyle->GetName());
-
- if (pRedefinition)
- {
- changeColor(pCollection, aColorSet, pRedefinition);
- }
-
- pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
- }
-
- pStyle = static_cast<SwDocStyleSheet*>(pPool->First(SfxStyleFamily::Char));
- while (pStyle)
- {
- SwCharFormat* pCharFormat = pStyle->GetCharFormat();
-
- changeFont(static_cast<SwFormat*>(pCharFormat), pStyle, aFontSet);
-
- pStyle = static_cast<SwDocStyleSheet*>(pPool->Next());
- }
-}
+#include <drawdoc.hxx>
+#include <IDocumentDrawModelAccess.hxx>
+#include <ThemeColorChanger.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/ColorSets.hxx>
+#include <svx/dialog/ThemeColorValueSet.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
-BitmapEx GenerateColorPreview(const svx::ColorSet& rColorSet)
+namespace sw::sidebar
{
- ScopedVclPtrInstance<VirtualDevice> pVirtualDev(*Application::GetDefaultDevice());
- float fScaleFactor = pVirtualDev->GetDPIScaleFactor();
- tools::Long BORDER = 3 * fScaleFactor;
- tools::Long SIZE = 14 * fScaleFactor;
- tools::Long LABEL_HEIGHT = 16 * fScaleFactor;
- tools::Long LABEL_TEXT_HEIGHT = 14 * fScaleFactor;
-
- Size aSize(BORDER * 7 + SIZE * 6 + BORDER * 2, BORDER * 3 + SIZE * 2 + LABEL_HEIGHT);
- pVirtualDev->SetOutputSizePixel(aSize);
- pVirtualDev->SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetFaceColor()));
- pVirtualDev->Erase();
-
- tools::Long x = BORDER;
- tools::Long y1 = BORDER + LABEL_HEIGHT;
- tools::Long y2 = y1 + SIZE + BORDER;
-
- pVirtualDev->SetLineColor(COL_LIGHTGRAY);
- pVirtualDev->SetFillColor(COL_LIGHTGRAY);
- tools::Rectangle aNameRect(Point(0, 0), Size(aSize.Width(), LABEL_HEIGHT));
- pVirtualDev->DrawRect(aNameRect);
-
- vcl::Font aFont;
- OUString aName = rColorSet.getName();
- aFont.SetFontHeight(LABEL_TEXT_HEIGHT);
- pVirtualDev->SetFont(aFont);
-
- Size aTextSize(pVirtualDev->GetTextWidth(aName), pVirtualDev->GetTextHeight());
-
- Point aPoint((aNameRect.GetWidth() / 2.0) - (aTextSize.Width() / 2.0),
- (aNameRect.GetHeight() / 2.0) - (aTextSize.Height() / 2.0));
-
- pVirtualDev->DrawText(aPoint, aName);
-
- pVirtualDev->SetLineColor(COL_LIGHTGRAY);
- pVirtualDev->SetFillColor();
-
- for (sal_uInt32 i = 0; i < 12; i += 2)
- {
- pVirtualDev->SetFillColor(rColorSet.getColor(i));
- pVirtualDev->DrawRect(tools::Rectangle(x, y1, x + SIZE, y1 + SIZE));
-
- pVirtualDev->SetFillColor(rColorSet.getColor(i + 1));
- pVirtualDev->DrawRect(tools::Rectangle(x, y2, x + SIZE, y2 + SIZE));
-
- x += SIZE + BORDER;
- if (i == 2 || i == 8)
- x += BORDER;
- }
-
- return pVirtualDev->GetBitmapEx(Point(), aSize);
-}
-
-} // end anonymous namespace
-
-namespace sw::sidebar {
std::unique_ptr<PanelLayout> ThemePanel::Create(weld::Widget* pParent)
{
@@ -431,8 +50,7 @@ std::unique_ptr<PanelLayout> ThemePanel::Create(weld::Widget* pParent)
ThemePanel::ThemePanel(weld::Widget* pParent)
: PanelLayout(pParent, "ThemePanel", "modules/swriter/ui/sidebartheme.ui")
- , mxListBoxFonts(m_xBuilder->weld_tree_view("listbox_fonts"))
- , mxValueSetColors(new ValueSet(nullptr))
+ , mxValueSetColors(new svx::ThemeColorValueSet)
, mxValueSetColorsWin(new weld::CustomWeld(*m_xBuilder, "valueset_colors", *mxValueSetColors))
, mxApplyButton(m_xBuilder->weld_button("apply"))
{
@@ -441,26 +59,25 @@ ThemePanel::ThemePanel(weld::Widget* pParent)
mxValueSetColors->SetColor(Application::GetSettings().GetStyleSettings().GetFaceColor());
mxApplyButton->connect_clicked(LINK(this, ThemePanel, ClickHdl));
- mxListBoxFonts->connect_row_activated(LINK(this, ThemePanel, DoubleClickHdl));
mxValueSetColors->SetDoubleClickHdl(LINK(this, ThemePanel, DoubleClickValueSetHdl));
- std::vector<FontSet> aFontSets = initFontSets();
- for (const FontSet & rFontSet : aFontSets)
- mxListBoxFonts->append_text(rFontSet.maName);
- mxListBoxFonts->set_size_request(-1, mxListBoxFonts->get_height_rows(aFontSets.size()));
-
maColorSets.init();
+ SwDocShell* pDocSh = static_cast<SwDocShell*>(SfxObjectShell::Current());
+ SwDoc* pDocument = pDocSh->GetDoc();
+ if (pDocument)
+ {
+ SdrPage* pPage = pDocument->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
+ svx::Theme* pTheme = pPage->getSdrPageProperties().GetTheme();
+ if (pTheme)
+ maColorSets.insert(*pTheme->GetColorSet());
+ }
+
const std::vector<svx::ColorSet>& aColorSets = maColorSets.getColorSets();
for (size_t i = 0; i < aColorSets.size(); ++i)
{
const svx::ColorSet& rColorSet = aColorSets[i];
-
- const OUString& aName = rColorSet.getName();
- BitmapEx aPreview = GenerateColorPreview(rColorSet);
-
- sal_uInt16 nId = i + 1;
- mxValueSetColors->InsertItem(nId, Image(aPreview), aName);
+ mxValueSetColors->insert(rColorSet);
}
mxValueSetColors->SetOptimalSize();
@@ -471,7 +88,6 @@ ThemePanel::ThemePanel(weld::Widget* pParent)
ThemePanel::~ThemePanel()
{
- mxListBoxFonts.reset();
mxValueSetColorsWin.reset();
mxValueSetColors.reset();
mxApplyButton.reset();
@@ -502,13 +118,12 @@ void ThemePanel::DoubleClickHdl()
sal_uInt32 nItemId = mxValueSetColors->GetSelectedItemId();
if (!nItemId)
return;
- OUString sEntryFonts = mxListBoxFonts->get_selected_text();
sal_uInt32 nIndex = nItemId - 1;
- OUString sEntryColors = maColorSets.getColorSet(nIndex).getName();
- StyleSet aStyleSet = setupThemes();
+ svx::ColorSet const& rColorSet = maColorSets.getColorSet(nIndex);
- applyTheme(pDocSh->GetStyleSheetPool(), sEntryFonts, sEntryColors, aStyleSet, maColorSets);
+ ThemeColorChanger aChanger(pDocSh);
+ aChanger.apply(rColorSet);
}
void ThemePanel::NotifyItemUpdate(const sal_uInt16 /*nSId*/,
diff --git a/sw/source/uibase/sidebar/ThemePanel.hxx b/sw/source/uibase/sidebar/ThemePanel.hxx
index 14af479e664a..848d022ee0c6 100644
--- a/sw/source/uibase/sidebar/ThemePanel.hxx
+++ b/sw/source/uibase/sidebar/ThemePanel.hxx
@@ -15,7 +15,10 @@
#include <svtools/valueset.hxx>
#include <svx/ColorSets.hxx>
-namespace sw::sidebar {
+namespace svx { class ThemeColorValueSet; }
+
+namespace sw::sidebar
+{
class ThemePanel : public PanelLayout,
public sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
@@ -36,7 +39,7 @@ public:
private:
std::unique_ptr<weld::TreeView> mxListBoxFonts;
- std::unique_ptr<ValueSet> mxValueSetColors;
+ std::unique_ptr<svx::ThemeColorValueSet> mxValueSetColors;
std::unique_ptr<weld::CustomWeld> mxValueSetColorsWin;
std::unique_ptr<weld::Button> mxApplyButton;
diff --git a/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
index 09c773a1d28a..6c13581bc183 100644
--- a/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
+++ b/sw/source/uibase/sidebar/WriterInspectorTextPanel.cxx
@@ -557,7 +557,12 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
UNO_NAME_PARA_CONTINUEING_PREVIOUS_SUB_TREE,
UNO_NAME_CHAR_STYLE_NAME,
UNO_NAME_NUMBERING_LEVEL,
- UNO_NAME_PARRSID };
+ UNO_NAME_PARRSID,
+ UNO_NAME_CHAR_COLOR_THEME,
+ UNO_NAME_CHAR_COLOR_TINT_OR_SHADE };
+
+ const std::vector<OUString> aHiddenCharacterProperties{ UNO_NAME_CHAR_COLOR_THEME,
+ UNO_NAME_CHAR_COLOR_TINT_OR_SHADE };
InsertValues(xRange, aIsDefined, aCharDFNode, false, aHiddenProperties, aFieldsNode);
@@ -580,7 +585,8 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
aCurrentChild.sNodeName = sDisplayName;
aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
- InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, false, {}, aFieldsNode);
+ InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, false, aHiddenCharacterProperties,
+ aFieldsNode);
aCharNode.children.push_back(aCurrentChild);
}
@@ -610,8 +616,8 @@ static void UpdateTree(SwDocShell* pDocSh, std::vector<svx::sidebar::TreeNode>&
aCurrentChild.sNodeName = sDisplayName;
aCurrentChild.NodeType = svx::sidebar::TreeNode::ComplexProperty;
- InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, aParentParaStyle.isEmpty(), {},
- aFieldsNode);
+ InsertValues(xPropertiesSet, aIsDefined, aCurrentChild, aParentParaStyle.isEmpty(),
+ aHiddenCharacterProperties, aFieldsNode);
aParaNode.children.push_back(aCurrentChild);
sCurrentParaStyle = aParentParaStyle;
diff --git a/sw/source/uibase/uiview/formatclipboard.cxx b/sw/source/uibase/uiview/formatclipboard.cxx
index 2bf4dd036fef..c9c2a01b995c 100644
--- a/sw/source/uibase/uiview/formatclipboard.cxx
+++ b/sw/source/uibase/uiview/formatclipboard.cxx
@@ -542,6 +542,12 @@ void SwFormatClipboard::Paste( SwWrtShell& rWrtShell, SfxStyleSheetBasePool* pPo
// copy the stored automatic text attributes in a temporary SfxItemSet
pTemplateItemSet->Put( *m_pItemSet_TextAttr );
+ // reset all direct formatting
+ o3tl::sorted_vector<sal_uInt16> aAttrs;
+ for( sal_uInt16 nWhich = RES_CHRATR_BEGIN; nWhich < RES_CHRATR_END; nWhich++ )
+ aAttrs.insert( nWhich );
+ rWrtShell.ResetAttr( { aAttrs } );
+
// only attributes that were not apply by named style attributes and automatic
// paragraph attributes should be applied
lcl_RemoveEqualItems( *pTemplateItemSet, aItemVector );
@@ -550,7 +556,9 @@ void SwFormatClipboard::Paste( SwWrtShell& rWrtShell, SfxStyleSheetBasePool* pPo
if( nSelectionType & (SelectionType::Frame | SelectionType::Ole | SelectionType::Graphic) )
rWrtShell.SetFlyFrameAttr(*pTemplateItemSet);
else if ( !bNoCharacterFormats )
+ {
rWrtShell.SetAttrSet(*pTemplateItemSet);
+ }
}
}
}
diff --git a/sw/source/uibase/uiview/view.cxx b/sw/source/uibase/uiview/view.cxx
index 8a05bbb61444..9b69515637d6 100644
--- a/sw/source/uibase/uiview/view.cxx
+++ b/sw/source/uibase/uiview/view.cxx
@@ -503,6 +503,11 @@ IMPL_LINK_NOARG(SwView, AttrChangedNotify, LinkParamNone*, void)
if ( GetEditWin().IsChainMode() )
GetEditWin().SetChainMode( false );
+ if (!m_pWrtShell || !GetDocShell())
+ {
+ return;
+ }
+
//Opt: Not if PaintLocked. During unlock a notify will be once more triggered.
if( !m_pWrtShell->IsPaintLocked() && !g_bNoInterrupt &&
GetDocShell()->IsReadOnly() )
@@ -596,7 +601,8 @@ void SwView::CheckReadonlyState()
FN_INSERT_BREAK, FN_INSERT_LINEBREAK, FN_INSERT_COLUMN_BREAK,
FN_INSERT_BREAK_DLG, FN_INSERT_CONTENT_CONTROL, FN_INSERT_CHECKBOX_CONTENT_CONTROL,
FN_INSERT_DROPDOWN_CONTENT_CONTROL, FN_INSERT_PICTURE_CONTENT_CONTROL,
- FN_INSERT_DATE_CONTENT_CONTROL,
+ FN_INSERT_DATE_CONTENT_CONTROL, FN_INSERT_PLAIN_TEXT_CONTENT_CONTROL,
+ FN_INSERT_COMBO_BOX_CONTENT_CONTROL,
FN_DELETE_SENT, FN_DELETE_BACK_SENT, FN_DELETE_WORD,
FN_DELETE_BACK_WORD, FN_DELETE_LINE, FN_DELETE_BACK_LINE,
FN_DELETE_PARA, FN_DELETE_BACK_PARA, FN_DELETE_WHOLE_LINE,
@@ -1918,11 +1924,11 @@ void SwView::flushPendingLOKInvalidateTiles()
pSh->FlushPendingLOKInvalidateTiles();
}
-OString SwView::getLOKPayload(int nType, int nViewId, bool* ignore) const
+std::optional<OString> SwView::getLOKPayload(int nType, int nViewId) const
{
SwWrtShell* pSh = GetWrtShellPtr();
assert(pSh);
- return pSh->getLOKPayload(nType, nViewId, ignore);
+ return pSh->getLOKPayload(nType, nViewId);
}
OUString SwView::GetDataSourceName() const
diff --git a/sw/source/uibase/uiview/view0.cxx b/sw/source/uibase/uiview/view0.cxx
index b9d04202d607..06dca639f718 100644
--- a/sw/source/uibase/uiview/view0.cxx
+++ b/sw/source/uibase/uiview/view0.cxx
@@ -24,6 +24,7 @@
#include <unotools/configmgr.hxx>
#include <unotools/linguprops.hxx>
#include <unotools/lingucfg.hxx>
+#include <officecfg/Office/Common.hxx>
#include <viewopt.hxx>
#include <globals.h>
#include <sfx2/infobar.hxx>
@@ -32,6 +33,7 @@
#include <svx/srchdlg.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
#include <sfx2/sidebar/SidebarChildWindow.hxx>
#include <uivwimp.hxx>
#include <avmedia/mediaplayer.hxx>
@@ -49,6 +51,7 @@
#include <cmdid.h>
#include <globdoc.hxx>
#include <wview.hxx>
+#include <OnlineAccessibilityCheck.hxx>
#define ShellClass_SwView
#define ShellClass_Text
@@ -324,6 +327,12 @@ void SwView::StateViewOptions(SfxItemSet &rSet)
case SID_AUTOSPELL_CHECK:
aBool.SetValue( pOpt->IsOnlineSpell() );
break;
+ case SID_ACCESSIBILITY_CHECK_ONLINE:
+ {
+ bool bOnlineAccessibilityCheck = officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::get();
+ aBool.SetValue(bOnlineAccessibilityCheck);
+ }
+ break;
case FN_SHADOWCURSOR:
if ( pOpt->getBrowseMode() )
{
@@ -572,6 +581,28 @@ void SwView::ExecViewOptions(SfxRequest &rReq)
}
break;
+ case SID_ACCESSIBILITY_CHECK_ONLINE:
+ {
+ if (pArgs && pArgs->HasItem(FN_PARAM_1, &pItem))
+ {
+ bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ }
+ else if (STATE_TOGGLE == eState)
+ {
+ bool bOnlineCheck = officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::get();
+ bSet = !bOnlineCheck;
+ }
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::set(bSet, batch);
+ batch->commit();
+
+ SwDocShell *pDocSh = GetDocShell();
+ SwDoc* pDocument = pDocSh? pDocSh->GetDoc() : nullptr;
+ if (pDocument)
+ pDocument->getOnlineAccessibilityCheck()->updateCheckerActivity();
+ }
+ break;
+
case FN_SHADOWCURSOR:
if( STATE_TOGGLE == eState )
{
diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx
index 60c2395293b6..a5cdc27fd059 100644
--- a/sw/source/uibase/uiview/view2.cxx
+++ b/sw/source/uibase/uiview/view2.cxx
@@ -127,6 +127,7 @@
#include <unotextrange.hxx>
#include <docstat.hxx>
#include <wordcountdialog.hxx>
+#include <OnlineAccessibilityCheck.hxx>
#include <sfx2/sidebar/Sidebar.hxx>
#include <vcl/GraphicNativeTransform.hxx>
@@ -1611,6 +1612,16 @@ void SwView::StateStatusLine(SfxItemSet &rSet)
pWrdCnt->SetCounts(selectionStats, documentStats);
}
break;
+ case FN_STAT_ACCESSIBILITY_CHECK:
+ {
+ std::unique_ptr<sw::OnlineAccessibilityCheck> const& rOnlineAccessibilityCheck = rShell.GetDoc()->getOnlineAccessibilityCheck();
+ if (rOnlineAccessibilityCheck)
+ {
+ sal_Int32 nIssues = rOnlineAccessibilityCheck->getNumberOfAccessibilityIssues();
+ rSet.Put(SfxInt32Item(FN_STAT_ACCESSIBILITY_CHECK, nIssues));
+ }
+ }
+ break;
case FN_STAT_TEMPLATE:
{
diff --git a/sw/source/uibase/uiview/viewdlg2.cxx b/sw/source/uibase/uiview/viewdlg2.cxx
index dd0da7acef95..c1131f1f590b 100644
--- a/sw/source/uibase/uiview/viewdlg2.cxx
+++ b/sw/source/uibase/uiview/viewdlg2.cxx
@@ -46,15 +46,18 @@
using namespace css;
-void SwView::ExecDlgExt(SfxRequest const &rReq)
+void SwView::ExecDlgExt(SfxRequest const& rReq)
{
- switch ( rReq.GetSlot() )
+ switch (rReq.GetSlot())
{
case FN_INSERT_CAPTION:
{
SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
- ScopedVclPtr<VclAbstractDialog> pDialog(pFact->CreateSwCaptionDialog(GetFrameWeld(), *this ));
- pDialog->Execute();
+ VclPtr<VclAbstractDialog> pDialog(
+ pFact->CreateSwCaptionDialog(GetFrameWeld(), *this));
+ pDialog->StartExecuteAsync([pDialog](sal_Int32) {
+ pDialog->disposeOnce();
+ });
break;
}
case SID_INSERT_SIGNATURELINE:
diff --git a/sw/source/uibase/uno/loktxdoc.cxx b/sw/source/uibase/uno/loktxdoc.cxx
new file mode 100644
index 000000000000..2780e39a1686
--- /dev/null
+++ b/sw/source/uibase/uno/loktxdoc.cxx
@@ -0,0 +1,494 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <unotxdoc.hxx>
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <o3tl/string_view.hxx>
+#include <tools/json_writer.hxx>
+#include <tools/urlobj.hxx>
+#include <xmloff/odffields.hxx>
+
+#include <IDocumentMarkAccess.hxx>
+#include <doc.hxx>
+#include <docsh.hxx>
+#include <fmtrfmrk.hxx>
+#include <wrtsh.hxx>
+#include <txtrfmrk.hxx>
+#include <ndtxt.hxx>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Implements getCommandValues(".uno:TextFormFields").
+///
+/// Parameters:
+///
+/// - type: e.g. ODF_UNHANDLED
+/// - commandPrefix: field command prefix to not return all fieldmarks
+void GetTextFormFields(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+ const std::map<OUString, OUString>& rArguments)
+{
+ OUString aType;
+ OUString aCommandPrefix;
+ {
+ auto it = rArguments.find("type");
+ if (it != rArguments.end())
+ {
+ aType = it->second;
+ }
+
+ it = rArguments.find("commandPrefix");
+ if (it != rArguments.end())
+ {
+ aCommandPrefix = it->second;
+ }
+ }
+
+ SwDoc* pDoc = pDocShell->GetDoc();
+ IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+ tools::ScopedJsonWriterArray aFields = rJsonWriter.startArray("fields");
+ for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
+ {
+ auto pFieldmark = dynamic_cast<sw::mark::IFieldmark*>(*it);
+ assert(pFieldmark);
+ if (pFieldmark->GetFieldname() != aType)
+ {
+ continue;
+ }
+
+ auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
+ if (itParam == pFieldmark->GetParameters()->end())
+ {
+ continue;
+ }
+
+ OUString aCommand;
+ itParam->second >>= aCommand;
+ if (!aCommand.startsWith(aCommandPrefix))
+ {
+ continue;
+ }
+
+ tools::ScopedJsonWriterStruct aField = rJsonWriter.startStruct();
+ rJsonWriter.put("type", aType);
+ rJsonWriter.put("command", aCommand);
+ }
+}
+
+/// Implements getCommandValues(".uno:TextFormField").
+///
+/// Parameters:
+///
+/// - type: e.g. ODF_UNHANDLED
+/// - commandPrefix: field command prefix to not return all fieldmarks
+void GetTextFormField(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+ const std::map<OUString, OUString>& rArguments)
+{
+ OUString aType;
+ OUString aCommandPrefix;
+ auto it = rArguments.find("type");
+ if (it != rArguments.end())
+ {
+ aType = it->second;
+ }
+
+ it = rArguments.find("commandPrefix");
+ if (it != rArguments.end())
+ {
+ aCommandPrefix = it->second;
+ }
+
+ IDocumentMarkAccess& rIDMA = *pDocShell->GetDoc()->getIDocumentMarkAccess();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ SwPosition& rCursor = *pWrtShell->GetCursor()->GetPoint();
+ sw::mark::IFieldmark* pFieldmark = rIDMA.getFieldmarkFor(rCursor);
+ auto typeNode = rJsonWriter.startNode("field");
+ if (!pFieldmark)
+ {
+ return;
+ }
+
+ if (pFieldmark->GetFieldname() != aType)
+ {
+ return;
+ }
+
+ auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
+ if (itParam == pFieldmark->GetParameters()->end())
+ {
+ return;
+ }
+
+ OUString aCommand;
+ itParam->second >>= aCommand;
+ if (!aCommand.startsWith(aCommandPrefix))
+ {
+ return;
+ }
+
+ rJsonWriter.put("type", aType);
+ rJsonWriter.put("command", aCommand);
+}
+
+/// Implements getCommandValues(".uno:SetDocumentProperties").
+///
+/// Parameters:
+///
+/// - namePrefix: field name prefix to not return all user-defined properties
+void GetDocumentProperties(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+ const std::map<OUString, OUString>& rArguments)
+{
+ OUString aNamePrefix;
+ auto it = rArguments.find("namePrefix");
+ if (it != rArguments.end())
+ {
+ aNamePrefix = it->second;
+ }
+
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(pDocShell->GetModel(),
+ uno::UNO_QUERY);
+ uno::Reference<document::XDocumentProperties> xDP = xDPS->getDocumentProperties();
+ uno::Reference<beans::XPropertyAccess> xUDP(xDP->getUserDefinedProperties(), uno::UNO_QUERY);
+ auto aUDPs = comphelper::sequenceToContainer<std::vector<beans::PropertyValue>>(
+ xUDP->getPropertyValues());
+ tools::ScopedJsonWriterArray aProperties = rJsonWriter.startArray("userDefinedProperties");
+ for (const auto& rUDP : aUDPs)
+ {
+ if (!rUDP.Name.startsWith(aNamePrefix))
+ {
+ continue;
+ }
+
+ if (rUDP.Value.getValueTypeClass() != uno::TypeClass_STRING)
+ {
+ continue;
+ }
+
+ OUString aValue;
+ rUDP.Value >>= aValue;
+
+ tools::ScopedJsonWriterStruct aProperty = rJsonWriter.startStruct();
+ rJsonWriter.put("name", rUDP.Name);
+ rJsonWriter.put("type", "string");
+ rJsonWriter.put("value", aValue);
+ }
+}
+
+/// Implements getCommandValues(".uno:Bookmarks").
+///
+/// Parameters:
+///
+/// - namePrefix: bookmark name prefix to not return all bookmarks
+void GetBookmarks(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+ const std::map<OUString, OUString>& rArguments)
+{
+ OUString aNamePrefix;
+ {
+ auto it = rArguments.find("namePrefix");
+ if (it != rArguments.end())
+ {
+ aNamePrefix = it->second;
+ }
+ }
+
+ IDocumentMarkAccess& rIDMA = *pDocShell->GetDoc()->getIDocumentMarkAccess();
+ tools::ScopedJsonWriterArray aBookmarks = rJsonWriter.startArray("bookmarks");
+ for (auto it = rIDMA.getBookmarksBegin(); it != rIDMA.getBookmarksEnd(); ++it)
+ {
+ sw::mark::IMark* pMark = *it;
+ if (!pMark->GetName().startsWith(aNamePrefix))
+ {
+ continue;
+ }
+
+ tools::ScopedJsonWriterStruct aProperty = rJsonWriter.startStruct();
+ rJsonWriter.put("name", pMark->GetName());
+ }
+}
+
+/// Implements getCommandValues(".uno:Bookmark").
+///
+/// Parameters:
+///
+/// - namePrefix: bookmark name prefix to not return all bookmarks
+void GetBookmark(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+ const std::map<OUString, OUString>& rArguments)
+{
+ OUString aNamePrefix;
+ {
+ auto it = rArguments.find("namePrefix");
+ if (it != rArguments.end())
+ {
+ aNamePrefix = it->second;
+ }
+ }
+
+ IDocumentMarkAccess& rIDMA = *pDocShell->GetDoc()->getIDocumentMarkAccess();
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ SwPosition& rCursor = *pWrtShell->GetCursor()->GetPoint();
+ sw::mark::IMark* pBookmark = rIDMA.getBookmarkFor(rCursor);
+ tools::ScopedJsonWriterNode aBookmark = rJsonWriter.startNode("bookmark");
+ if (!pBookmark)
+ {
+ return;
+ }
+
+ if (!pBookmark->GetName().startsWith(aNamePrefix))
+ {
+ return;
+ }
+
+ rJsonWriter.put("name", pBookmark->GetName());
+}
+
+/// Implements getCommandValues(".uno:Fields").
+///
+/// Parameters:
+///
+/// - typeName: field type condition to not return all fields
+/// - namePrefix: field name prefix to not return all fields
+void GetFields(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+ const std::map<OUString, OUString>& rArguments)
+{
+ OUString aTypeName;
+ {
+ auto it = rArguments.find("typeName");
+ if (it != rArguments.end())
+ {
+ aTypeName = it->second;
+ }
+ }
+ // See SwFieldTypeFromString().
+ if (aTypeName != "SetRef")
+ {
+ return;
+ }
+
+ OUString aNamePrefix;
+ {
+ auto it = rArguments.find("namePrefix");
+ if (it != rArguments.end())
+ {
+ aNamePrefix = it->second;
+ }
+ }
+
+ SwDoc* pDoc = pDocShell->GetDoc();
+ tools::ScopedJsonWriterArray aBookmarks = rJsonWriter.startArray("setRefs");
+ std::vector<const SwFormatRefMark*> aRefMarks;
+ for (sal_uInt16 i = 0; i < pDoc->GetRefMarks(); ++i)
+ {
+ aRefMarks.push_back(pDoc->GetRefMark(i));
+ }
+ // Sort the refmarks based on their start position.
+ std::sort(aRefMarks.begin(), aRefMarks.end(),
+ [](const SwFormatRefMark* pMark1, const SwFormatRefMark* pMark2) -> bool {
+ const SwTextRefMark* pTextRefMark1 = pMark1->GetTextRefMark();
+ const SwTextRefMark* pTextRefMark2 = pMark2->GetTextRefMark();
+ SwPosition aPos1(const_cast<SwTextNode&>(pTextRefMark1->GetTextNode()),
+ pTextRefMark1->GetStart());
+ SwPosition aPos2(const_cast<SwTextNode&>(pTextRefMark2->GetTextNode()),
+ pTextRefMark2->GetStart());
+ return aPos1 < aPos2;
+ });
+
+ for (const auto& pRefMark : aRefMarks)
+ {
+ if (!pRefMark->GetRefName().startsWith(aNamePrefix))
+ {
+ continue;
+ }
+
+ tools::ScopedJsonWriterStruct aProperty = rJsonWriter.startStruct();
+ rJsonWriter.put("name", pRefMark->GetRefName());
+ }
+}
+
+/// Implements getCommandValues(".uno:Field").
+///
+/// Parameters:
+///
+/// - typeName: field type condition to not return all fields
+/// - namePrefix: field name prefix to not return all fields
+void GetField(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+ const std::map<OUString, OUString>& rArguments)
+{
+ OUString aTypeName;
+ {
+ auto it = rArguments.find("typeName");
+ if (it != rArguments.end())
+ {
+ aTypeName = it->second;
+ }
+ }
+ // See SwFieldTypeFromString().
+ if (aTypeName != "SetRef")
+ {
+ return;
+ }
+
+ OUString aNamePrefix;
+ {
+ auto it = rArguments.find("namePrefix");
+ if (it != rArguments.end())
+ {
+ aNamePrefix = it->second;
+ }
+ }
+
+ SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+ SwPosition& rCursor = *pWrtShell->GetCursor()->GetPoint();
+ SwTextNode* pTextNode = rCursor.GetNode().GetTextNode();
+ std::vector<SwTextAttr*> aAttrs
+ = pTextNode->GetTextAttrsAt(rCursor.nContent.GetIndex(), RES_TXTATR_REFMARK);
+ tools::ScopedJsonWriterNode aRefmark = rJsonWriter.startNode("setRef");
+ if (aAttrs.empty())
+ {
+ return;
+ }
+
+ const SwFormatRefMark& rRefmark = aAttrs[0]->GetRefMark();
+ if (!rRefmark.GetRefName().startsWith(aNamePrefix))
+ {
+ return;
+ }
+
+ rJsonWriter.put("name", rRefmark.GetRefName());
+}
+
+/// Implements getCommandValues(".uno:Sections").
+///
+/// Parameters:
+///
+/// - namePrefix: field name prefix to not return all sections
+void GetSections(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+ const std::map<OUString, OUString>& rArguments)
+{
+ OUString aNamePrefix;
+ {
+ auto it = rArguments.find("namePrefix");
+ if (it != rArguments.end())
+ {
+ aNamePrefix = it->second;
+ }
+ }
+
+ SwDoc* pDoc = pDocShell->GetDoc();
+ tools::ScopedJsonWriterArray aBookmarks = rJsonWriter.startArray("sections");
+ for (const auto& pSection : pDoc->GetSections())
+ {
+ if (!pSection->GetName().startsWith(aNamePrefix))
+ {
+ continue;
+ }
+
+ tools::ScopedJsonWriterStruct aProperty = rJsonWriter.startStruct();
+ rJsonWriter.put("name", pSection->GetName());
+ }
+}
+}
+
+bool SwXTextDocument::supportsCommand(const OUString& rCommand)
+{
+ static const std::initializer_list<std::u16string_view> vForward
+ = { u"TextFormFields", u"TextFormField", u"SetDocumentProperties",
+ u"Bookmarks", u"Fields", u"Sections",
+ u"Bookmark", u"Field" };
+
+ return std::find(vForward.begin(), vForward.end(), rCommand) != vForward.end();
+}
+
+void SwXTextDocument::getCommandValues(tools::JsonWriter& rJsonWriter, const OString& rCommand)
+{
+ std::map<OUString, OUString> aMap;
+
+ static constexpr OStringLiteral aTextFormFields(".uno:TextFormFields");
+ static constexpr OStringLiteral aTextFormField(".uno:TextFormField");
+ static constexpr OStringLiteral aSetDocumentProperties(".uno:SetDocumentProperties");
+ static constexpr OStringLiteral aBookmarks(".uno:Bookmarks");
+ static constexpr OStringLiteral aFields(".uno:Fields");
+ static constexpr OStringLiteral aSections(".uno:Sections");
+ static constexpr OStringLiteral aBookmark(".uno:Bookmark");
+ static constexpr OStringLiteral aField(".uno:Field");
+
+ INetURLObject aParser(OUString::fromUtf8(rCommand));
+ OUString aArguments = aParser.GetParam();
+ sal_Int32 nParamIndex = 0;
+ do
+ {
+ OUString aParam = aArguments.getToken(0, '&', nParamIndex);
+ sal_Int32 nIndex = 0;
+ OUString aKey;
+ OUString aValue;
+ do
+ {
+ OUString aToken = aParam.getToken(0, '=', nIndex);
+ if (aKey.isEmpty())
+ aKey = aToken;
+ else
+ aValue = aToken;
+ } while (nIndex >= 0);
+ OUString aDecodedValue
+ = INetURLObject::decode(aValue, INetURLObject::DecodeMechanism::WithCharset);
+ aMap[aKey] = aDecodedValue;
+ } while (nParamIndex >= 0);
+
+ if (o3tl::starts_with(rCommand, aTextFormFields))
+ {
+ GetTextFormFields(rJsonWriter, m_pDocShell, aMap);
+ }
+ if (o3tl::starts_with(rCommand, aTextFormField))
+ {
+ GetTextFormField(rJsonWriter, m_pDocShell, aMap);
+ }
+ else if (o3tl::starts_with(rCommand, aSetDocumentProperties))
+ {
+ GetDocumentProperties(rJsonWriter, m_pDocShell, aMap);
+ }
+ else if (o3tl::starts_with(rCommand, aBookmarks))
+ {
+ GetBookmarks(rJsonWriter, m_pDocShell, aMap);
+ }
+ else if (o3tl::starts_with(rCommand, aFields))
+ {
+ GetFields(rJsonWriter, m_pDocShell, aMap);
+ }
+ else if (o3tl::starts_with(rCommand, aSections))
+ {
+ GetSections(rJsonWriter, m_pDocShell, aMap);
+ }
+ else if (o3tl::starts_with(rCommand, aBookmark))
+ {
+ GetBookmark(rJsonWriter, m_pDocShell, aMap);
+ }
+ else if (o3tl::starts_with(rCommand, aField))
+ {
+ GetField(rJsonWriter, m_pDocShell, aMap);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index 1d68e037d949..8deb51ad0e3f 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -30,12 +30,13 @@
#include <sfx2/bindings.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/lokhelper.hxx>
+#include <sfx2/LokControlHandler.hxx>
#include <sfx2/docfile.hxx>
#include <sfx2/printer.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <toolkit/awt/vclxdevice.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
-#include <sfx2/lokcharthelper.hxx>
+#include <sfx2/lokcomponenthelpers.hxx>
#include <sfx2/ipclient.hxx>
#include <editeng/svxacorr.hxx>
#include <editeng/acorrcfg.hxx>
@@ -85,6 +86,7 @@
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
#include <com/sun/star/document/RedlineDisplayType.hpp>
#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
#include <com/sun/star/frame/XController.hpp>
@@ -163,10 +165,13 @@
#include <tools/json_writer.hxx>
#include <svx/svdpage.hxx>
+#include <o3tl/string_view.hxx>
+#include <comphelper/sequenceashashmap.hxx>
#include <IDocumentOutlineNodes.hxx>
#include <SearchResultLocator.hxx>
#include <textcontentcontrol.hxx>
+#include <unocontentcontrol.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::text;
@@ -660,6 +665,18 @@ Reference< XPropertySet > SwXTextDocument::getEndnoteSettings()
return mxXEndnoteSettings;
}
+Reference< XIndexAccess > SwXTextDocument::getContentControls()
+{
+ SolarMutexGuard aGuard;
+ if(!IsValid())
+ throw DisposedException("", static_cast< XTextDocument* >(this));
+ if(!mxXContentControls.is())
+ {
+ mxXContentControls = new SwXContentControls(m_pDocShell->GetDoc());
+ }
+ return mxXContentControls;
+}
+
Reference< util::XReplaceDescriptor > SwXTextDocument::createReplaceDescriptor()
{
SolarMutexGuard aGuard;
@@ -1489,6 +1506,13 @@ void SwXTextDocument::InitNewDoc()
mxXEndnotes.clear();
}
+ if(mxXContentControls.is())
+ {
+ XIndexAccess* pContentControls = mxXContentControls.get();
+ static_cast<SwXContentControls*>(pContentControls)->Invalidate();
+ mxXContentControls.clear();
+ }
+
if(mxXDocumentIndexes.is())
{
XIndexAccess* pIdxs = mxXDocumentIndexes.get();
@@ -3086,6 +3110,17 @@ void SwXTextDocument::paintTile( VirtualDevice &rDevice,
LokChartHelper::PaintAllChartsOnTile(rDevice, nOutputWidth, nOutputHeight,
nTilePosX, nTilePosY, nTileWidth, nTileHeight);
+
+ // Draw Form controls
+ comphelper::LibreOfficeKit::setTiledPainting(true);
+ SwDrawModel* pDrawLayer = m_pDocShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
+ SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(0));
+ SdrView* pDrawView = pViewShell->GetDrawView();
+ SwEditWin& rEditWin = m_pDocShell->GetView()->GetEditWin();
+ tools::Rectangle aTileRect(Point(nTilePosX, nTilePosY), Size(nTileWidth, nTileHeight));
+ Size aOutputSize(nOutputWidth, nOutputHeight);
+ LokControlHandler::paintControlTile(pPage, pDrawView, rEditWin, rDevice, aOutputSize, aTileRect);
+ comphelper::LibreOfficeKit::setTiledPainting(false);
}
Size SwXTextDocument::getDocumentSize()
@@ -3397,7 +3432,7 @@ void SwXTextDocument::executeContentControlEvent(const StringMap& rArguments)
auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
- if (!pContentControl->HasListItems())
+ if (!pContentControl->GetComboBox() && !pContentControl->GetDropDown())
{
return;
}
@@ -3428,7 +3463,7 @@ void SwXTextDocument::executeContentControlEvent(const StringMap& rArguments)
// The current placeholder is selected, so this will replace, not insert.
SfxStringItem aItem(SID_INSERT_GRAPHIC, it->second);
- pView->GetViewFrame()->GetDispatcher()->ExecuteList(SID_INSERT_GRAPHIC,
+ pView->GetViewFrame()->GetDispatcher()->ExecuteList(SID_CHANGE_PICTURE,
SfxCallMode::SYNCHRON, { &aItem });
}
else if (it->second == "date")
@@ -3518,17 +3553,14 @@ OUString SwXTextDocument::getPartHash(int nPart)
VclPtr<vcl::Window> SwXTextDocument::getDocWindow()
{
SolarMutexGuard aGuard;
- VclPtr<vcl::Window> pWindow;
SwView* pView = m_pDocShell->GetView();
- if (pView)
- pWindow = &(pView->GetEditWin());
+ if (!pView)
+ return {};
- LokChartHelper aChartHelper(pView);
- VclPtr<vcl::Window> pChartWindow = aChartHelper.GetWindow();
- if (pChartWindow)
- pWindow = pChartWindow;
+ if (VclPtr<vcl::Window> pWindow = SfxLokHelper::getInPlaceDocWindow(pView))
+ return pWindow;
- return pWindow;
+ return &(pView->GetEditWin());
}
void SwXTextDocument::initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments)
@@ -3550,6 +3582,9 @@ void SwXTextDocument::initializeForTiledRendering(const css::uno::Sequence<css::
// Disable field shadings: the result would depend on the cursor position.
SwViewOption::SetAppearanceFlag(ViewOptFlags::FieldShadings, false);
+ OUString sOrigAuthor = SW_MOD()->GetRedlineAuthor(SW_MOD()->GetRedlineAuthor());
+ OUString sAuthor;
+
for (const beans::PropertyValue& rValue : rArguments)
{
if (rValue.Name == ".uno:HideWhitespace" && rValue.Value.has<bool>())
@@ -3558,8 +3593,9 @@ void SwXTextDocument::initializeForTiledRendering(const css::uno::Sequence<css::
SwViewOption::SetAppearanceFlag(ViewOptFlags::Shadow , rValue.Value.get<bool>());
else if (rValue.Name == ".uno:Author" && rValue.Value.has<OUString>())
{
+ sAuthor = rValue.Value.get<OUString>();
// Store the author name in the view.
- pView->SetRedlineAuthor(rValue.Value.get<OUString>());
+ pView->SetRedlineAuthor(sAuthor);
// Let the actual author name pick up the value from the current
// view, which would normally happen only during the next view
// switch.
@@ -3569,6 +3605,19 @@ void SwXTextDocument::initializeForTiledRendering(const css::uno::Sequence<css::
aViewOption.SetOnlineSpell(rValue.Value.get<bool>());
}
+ if (!sAuthor.isEmpty() && sAuthor != sOrigAuthor)
+ {
+ SwView* pFirstView = static_cast<SwView*>(SfxViewShell::GetFirst());
+ if (pFirstView && SfxViewShell::GetNext(*pFirstView) == nullptr)
+ {
+ if (SwEditShell* pShell = &pFirstView->GetWrtShell())
+ {
+ pShell->SwViewShell::UpdateFields(true);
+ pShell->ResetModified();
+ }
+ }
+ }
+
// Set the initial zoom value to 1; usually it is set in setClientZoom and
// SwViewShell::PaintTile; zoom value is used for chart in place
// editing, see postMouseEvent and setGraphicSelection methods.
@@ -3623,23 +3672,20 @@ void SwXTextDocument::postMouseEvent(int nType, int nX, int nY, int nCount, int
SwViewOption aOption(*(pWrtViewShell->GetViewOptions()));
double fScale = aOption.GetZoom() / o3tl::convert(100.0, o3tl::Length::px, o3tl::Length::twip);
- // check if the user hit a chart which is being edited by this view
- SfxViewShell* pViewShell = m_pDocShell->GetView();
- LokChartHelper aChartHelper(pViewShell);
- if (aChartHelper.postMouseEvent(nType, nX, nY,
- nCount, nButtons, nModifier,
- fScale, fScale))
+ if (SfxLokHelper::testInPlaceComponentMouseEventHit(
+ m_pDocShell->GetView(), nType, nX, nY, nCount, nButtons, nModifier, fScale, fScale))
return;
- // check if the user hit a chart which is being edited by someone else
- // and, if so, skip current mouse event
- if (nType != LOK_MOUSEEVENT_MOUSEMOVE)
- {
- if (LokChartHelper::HitAny(Point(nX, nY)))
+ // try to forward mouse event to controls
+ SwDrawModel* pDrawLayer = m_pDocShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
+ SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(0));
+ SdrView* pDrawView = pWrtViewShell->GetDrawView();
+ SwEditWin& rEditWin = m_pDocShell->GetView()->GetEditWin();
+ Point aPointTwip(nX, nY);
+ Point aPointHMMDraw = o3tl::convert(aPointTwip, o3tl::Length::twip, o3tl::Length::mm100);
+ if (LokControlHandler::postMouseEvent(pPage, pDrawView, rEditWin, nType, aPointHMMDraw, nCount, nButtons, nModifier))
return;
- }
- SwEditWin& rEditWin = m_pDocShell->GetView()->GetEditWin();
LokMouseEventData aMouseEventData(nType, Point(nX, nY), nCount,
MouseEventModifiers::SIMPLECLICK,
nButtons, nModifier);
diff --git a/sw/source/uibase/utlui/AccessibilityStatusBarControl.cxx b/sw/source/uibase/utlui/AccessibilityStatusBarControl.cxx
new file mode 100644
index 000000000000..d0ce67fc2349
--- /dev/null
+++ b/sw/source/uibase/utlui/AccessibilityStatusBarControl.cxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <swtypes.hxx>
+#include <strings.hrc>
+#include <AccessibilityStatusBarControl.hxx>
+#include <svl/intitem.hxx>
+#include <vcl/status.hxx>
+#include <vcl/event.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <bitmaps.hlst>
+
+SFX_IMPL_STATUSBAR_CONTROL(sw::AccessibilityStatusBarControl, SfxInt32Item);
+
+namespace sw
+{
+AccessibilityStatusBarControl::AccessibilityStatusBarControl(sal_uInt16 _nSlotId, sal_uInt16 _nId,
+ StatusBar& rStb)
+ : SfxStatusBarControl(_nSlotId, _nId, rStb)
+ , mnIssues(0)
+ , maImageIssuesFound(Image(StockImage::Yes, RID_BMP_A11Y_CHECK_ISSUES_FOUND))
+ , maImageIssuesNotFound(Image(StockImage::Yes, RID_BMP_A11Y_CHECK_ISSUES_NOT_FOUND))
+{
+}
+
+AccessibilityStatusBarControl::~AccessibilityStatusBarControl() = default;
+
+void AccessibilityStatusBarControl::StateChangedAtStatusBarControl(sal_uInt16 /*nSID*/,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ mnIssues = -1;
+
+ bool bOnlineCheckStatus
+ = officecfg::Office::Common::Accessibility::OnlineAccessibilityCheck::get();
+
+ if (eState == SfxItemState::DEFAULT && bOnlineCheckStatus)
+ {
+ if (auto pItem = dynamic_cast<const SfxInt32Item*>(pState))
+ mnIssues = pItem->GetValue();
+ OUString aString = SwResId(STR_ACCESSIBILITY_CHECK_HINT)
+ .replaceFirst("%issues%", OUString::number(mnIssues));
+ GetStatusBar().SetQuickHelpText(GetId(), aString);
+ }
+ else
+ {
+ GetStatusBar().SetQuickHelpText(GetId(), u"");
+ }
+
+ GetStatusBar().Invalidate();
+}
+
+void AccessibilityStatusBarControl::Paint(const UserDrawEvent& rUserEvent)
+{
+ if (mnIssues < 0)
+ return;
+
+ vcl::RenderContext* pRenderContext = rUserEvent.GetRenderContext();
+
+ tools::Rectangle aRect = rUserEvent.GetRect();
+ const tools::Rectangle aControlRect = getControlRect();
+
+ Image aImage = mnIssues > 0 ? maImageIssuesFound : maImageIssuesNotFound;
+
+ Size aSize(aImage.GetSizePixel());
+
+ auto aPosition = Point(aRect.Left() + (aControlRect.GetWidth() - aSize.Width()) / 2,
+ aRect.Top() + (aControlRect.GetHeight() - aSize.Height()) / 2);
+
+ pRenderContext->DrawImage(aPosition, aImage);
+}
+
+} // end sw
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx
index f9af1b3fc55d..ee6dd8b806cc 100644
--- a/sw/source/uibase/wrtsh/wrtsh1.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -107,6 +107,7 @@
#include <svl/zformat.hxx>
#include <memory>
+#include "../../core/crsr/callnk.hxx"
#include <frmtool.hxx>
#include <viewopt.hxx>
@@ -115,6 +116,7 @@
#include <UndoCore.hxx>
#include <formatlinebreak.hxx>
#include <formatcontentcontrol.hxx>
+#include <textcontentcontrol.hxx>
using namespace sw::mark;
using namespace com::sun::star;
@@ -260,6 +262,19 @@ void SwWrtShell::Insert( const OUString &rStr )
bCallIns ?
SwEditShell::Insert2( rStr, bDeleted ) : SwEditShell::Overwrite( rStr );
+ // Check whether node is content control
+ SwTextContentControl* pTextContentControl = CursorInsideContentControl();
+ if (pTextContentControl)
+ {
+ std::shared_ptr<SwContentControl> pContentControl =
+ pTextContentControl->GetContentControl().GetContentControl();
+ if (pContentControl)
+ {
+ // Set showingPlcHdr to false as node has been edited
+ pContentControl->SetShowingPlaceHolder(false);
+ }
+ }
+
if( bStarted )
{
EndUndo();
@@ -646,8 +661,12 @@ void SwWrtShell::LaunchOLEObj(sal_Int32 nVerb)
// LOK: we don't want to handle any other embedded objects than
// charts, there are too many problems with eg. embedded spreadsheets
// (like it creates a separate view for the calc sheet)
- if (comphelper::LibreOfficeKit::isActive() && !SotExchange::IsChart(xRef->getClassID()))
- return;
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ const auto classId = xRef->getClassID();
+ if (!SotExchange::IsChart(classId) && !SotExchange::IsMath(classId))
+ return;
+ }
SfxInPlaceClient* pCli = GetView().FindIPClient( xRef.GetObject(), &GetView().GetEditWin() );
if ( !pCli )
@@ -1029,8 +1048,13 @@ void SwWrtShell::InsertContentControl(SwContentControlType eType)
switch (eType)
{
case SwContentControlType::RICH_TEXT:
+ case SwContentControlType::PLAIN_TEXT:
{
pContentControl->SetShowingPlaceHolder(true);
+ if (eType == SwContentControlType::PLAIN_TEXT)
+ {
+ pContentControl->SetPlainText(true);
+ }
if (!HasSelection())
{
aPlaceholder = SwResId(STR_CONTENT_CONTROL_PLACEHOLDER);
@@ -1047,8 +1071,18 @@ void SwWrtShell::InsertContentControl(SwContentControlType eType)
aPlaceholder = u"\u2610";
break;
}
+ case SwContentControlType::COMBO_BOX:
case SwContentControlType::DROP_DOWN_LIST:
{
+ if (eType == SwContentControlType::COMBO_BOX)
+ {
+ pContentControl->SetComboBox(true);
+ }
+ else if (eType == SwContentControlType::DROP_DOWN_LIST)
+ {
+ pContentControl->SetDropDown(true);
+ }
+
pContentControl->SetShowingPlaceHolder(true);
if (!HasSelection())
{
@@ -1970,7 +2004,7 @@ SwWrtShell::SwWrtShell( SwWrtShell& rSh, vcl::Window *_pWin, SwView &rShell )
// place the cursor on the first field...
IFieldmark *pBM = nullptr;
- if ( IsFormProtected() && ( pBM = GetFieldmarkAfter( ) ) !=nullptr ) {
+ if (IsFormProtected() && (pBM = GetFieldmarkAfter(/*bLoop=*/false)) !=nullptr) {
GotoFieldmark(pBM);
}
}
@@ -1988,7 +2022,7 @@ SwWrtShell::SwWrtShell( SwDoc& rDoc, vcl::Window *_pWin, SwView &rShell,
// place the cursor on the first field...
IFieldmark *pBM = nullptr;
- if ( IsFormProtected() && ( pBM = GetFieldmarkAfter( ) ) !=nullptr ) {
+ if (IsFormProtected() && (pBM = GetFieldmarkAfter(/*bLoop=*/false)) !=nullptr) {
GotoFieldmark(pBM);
}
}
@@ -2005,7 +2039,13 @@ SwWrtShell::~SwWrtShell()
bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete)
{
- bool bRet = SwCursorShell::Pop(eDelete);
+ ::std::unique_ptr<SwCallLink> pLink(::std::make_unique<SwCallLink>(*this));
+ return Pop(eDelete, ::std::move(pLink));
+}
+
+bool SwWrtShell::Pop(SwCursorShell::PopMode const eDelete, ::std::unique_ptr<SwCallLink> pLink)
+{
+ bool bRet = SwCursorShell::Pop(eDelete, ::std::move(pLink));
if( bRet && IsSelection() )
{
if (!IsAddMode())
diff --git a/sw/source/uibase/wrtsh/wrtsh2.cxx b/sw/source/uibase/wrtsh/wrtsh2.cxx
index e53580e6a746..b6d6a89535ef 100644
--- a/sw/source/uibase/wrtsh/wrtsh2.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh2.cxx
@@ -501,30 +501,24 @@ bool SwWrtShell::ClickToINetGrf( const Point& rDocPt, LoadUrlFlags nFilter )
return bRet;
}
-void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
- const OUString& rTargetFrameName )
+static void LoadURL(SwView& rView, const OUString& rURL, LoadUrlFlags nFilter,
+ const OUString& rTargetFrameName)
{
- OSL_ENSURE( !rURL.isEmpty(), "what should be loaded here?" );
- if( rURL.isEmpty() )
- return ;
+ SwDocShell* pDShell = rView.GetDocShell();
+ OSL_ENSURE( pDShell, "No DocShell?!");
+ SfxViewFrame* pViewFrame = rView.GetViewFrame();
- // The shell could be 0 also!!!!!
- if ( dynamic_cast<const SwCursorShell*>( &rVSh) == nullptr )
+ if (!SfxObjectShell::AllowedLinkProtocolFromDocument(rURL, pDShell, pViewFrame->GetFrameWeld()))
return;
// We are doing tiledRendering, let the client handles the URL loading,
// unless we are jumping to a TOC mark.
if (comphelper::LibreOfficeKit::isActive() && !rURL.startsWith("#"))
{
- rVSh.GetSfxViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, rURL.toUtf8().getStr());
+ rView.libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, rURL.toUtf8().getStr());
return;
}
- //A CursorShell is always a WrtShell
- SwWrtShell &rSh = static_cast<SwWrtShell&>(rVSh);
-
- SwDocShell* pDShell = rSh.GetView().GetDocShell();
- OSL_ENSURE( pDShell, "No DocShell?!");
OUString sTargetFrame(rTargetFrameName);
if (sTargetFrame.isEmpty() && pDShell)
{
@@ -539,7 +533,6 @@ void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
OUString sReferer;
if( pDShell && pDShell->GetMedium() )
sReferer = pDShell->GetMedium()->GetName();
- SfxViewFrame* pViewFrame = rSh.GetView().GetViewFrame();
SfxFrameItem aView( SID_DOCFRAME, pViewFrame );
SfxStringItem aName( SID_FILE_NAME, rURL );
SfxStringItem aTargetFrameName( SID_TARGETNAME, sTargetFrame );
@@ -565,6 +558,23 @@ void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
SfxCallMode::ASYNCHRON|SfxCallMode::RECORD );
}
+void LoadURL( SwViewShell& rVSh, const OUString& rURL, LoadUrlFlags nFilter,
+ const OUString& rTargetFrameName )
+{
+ OSL_ENSURE( !rURL.isEmpty(), "what should be loaded here?" );
+ if( rURL.isEmpty() )
+ return ;
+
+ // The shell could be 0 also!!!!!
+ if ( dynamic_cast<const SwCursorShell*>( &rVSh) == nullptr )
+ return;
+
+ //A CursorShell is always a WrtShell
+ SwWrtShell &rSh = static_cast<SwWrtShell&>(rVSh);
+
+ ::LoadURL(rSh.GetView(), rURL, nFilter, rTargetFrameName);
+}
+
void SwWrtShell::NavigatorPaste( const NaviContentBookmark& rBkmk,
const sal_uInt16 nAction )
{
diff --git a/sw/source/uibase/wrtsh/wrtsh3.cxx b/sw/source/uibase/wrtsh/wrtsh3.cxx
index 27ca0353bac1..4e80bfc1e3d1 100644
--- a/sw/source/uibase/wrtsh/wrtsh3.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh3.cxx
@@ -93,7 +93,8 @@ bool SwWrtShell::GotoField( const SwFormatField& rField )
return bRet;
}
-bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentControl)
+bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentControl,
+ bool bOnlyRefresh)
{
std::shared_ptr<SwContentControl> pContentControl = rContentControl.GetContentControl();
if (IsFrameSelected() && pContentControl && pContentControl->GetPicture())
@@ -129,18 +130,15 @@ bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentContro
{
// Checkbox: GotoFormatContentControl() selected the old state.
LockView(/*bViewLocked=*/true);
- OUString aOldState;
+ OUString aOldState = GetCursorDescr();
OUString aNewState;
if (pContentControl->GetChecked())
- {
- aOldState = pContentControl->GetCheckedState();
- aNewState = pContentControl->GetUncheckedState();
- }
+ aNewState = bOnlyRefresh ? pContentControl->GetCheckedState()
+ : pContentControl->GetUncheckedState();
else
- {
- aOldState = pContentControl->GetUncheckedState();
- aNewState = pContentControl->GetCheckedState();
- }
+ aNewState = bOnlyRefresh ? pContentControl->GetUncheckedState()
+ : pContentControl->GetCheckedState();
+
SwRewriter aRewriter;
aRewriter.AddRule(UndoArg1, aOldState);
aRewriter.AddRule(UndoArg2, SwResId(STR_YIELDS));
@@ -150,7 +148,8 @@ bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentContro
// Toggle the state.
pContentControl->SetReadWrite(true);
DelLeft();
- pContentControl->SetChecked(!pContentControl->GetChecked());
+ if (!bOnlyRefresh)
+ pContentControl->SetChecked(!pContentControl->GetChecked());
Insert(aNewState);
pContentControl->SetReadWrite(false);
@@ -172,9 +171,11 @@ bool SwWrtShell::GotoContentControl(const SwFormatContentControl& rContentContro
GetIDocumentUndoRedo().StartUndo(SwUndoId::REPLACE, &aRewriter);
// Update the content.
+ pContentControl->SetReadWrite(true);
DelLeft();
pContentControl->SetSelectedListItem(std::nullopt);
Insert(aNewState);
+ pContentControl->SetReadWrite(false);
GetIDocumentUndoRedo().EndUndo(SwUndoId::REPLACE, &aRewriter);
LockView(/*bViewLocked=*/false);
diff --git a/sw/source/uibase/wrtsh/wrtsh4.cxx b/sw/source/uibase/wrtsh/wrtsh4.cxx
index 36cec11cc09c..b3fb83c15bb8 100644
--- a/sw/source/uibase/wrtsh/wrtsh4.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh4.cxx
@@ -234,18 +234,18 @@ bool SwWrtShell::BwdPara_()
return bRet;
}
-OString SwWrtShell::getLOKPayload(int nType, int nViewId, bool* ignore) const
+std::optional<OString> SwWrtShell::getLOKPayload(int nType, int nViewId) const
{
switch(nType)
{
case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
- return GetVisibleCursor()->getLOKPayload(nType, nViewId, ignore);
+ return GetVisibleCursor()->getLOKPayload(nType, nViewId);
case LOK_CALLBACK_TEXT_SELECTION:
case LOK_CALLBACK_TEXT_SELECTION_START:
case LOK_CALLBACK_TEXT_SELECTION_END:
case LOK_CALLBACK_TEXT_VIEW_SELECTION:
- return GetCursor_()->getLOKPayload( nType, nViewId, ignore );
+ return GetCursor_()->getLOKPayload(nType, nViewId);
}
abort();
}
diff --git a/sw/uiconfig/sglobal/menubar/menubar.xml b/sw/uiconfig/sglobal/menubar/menubar.xml
index 38f6708c1a55..2b3a47bd8633 100644
--- a/sw/uiconfig/sglobal/menubar/menubar.xml
+++ b/sw/uiconfig/sglobal/menubar/menubar.xml
@@ -443,6 +443,7 @@
<menu:menuitem menu:id=".uno:FontDialog"/>
<menu:menuitem menu:id=".uno:ParagraphDialog"/>
<menu:menuitem menu:id=".uno:OutlineBullet"/>
+ <menu:menuitem menu:id=".uno:ThemeDialog"/>
<menu:menuseparator/>
<menu:menuitem menu:id=".uno:PageDialog"/>
<menu:menuitem menu:id=".uno:TitlePageDialog" menu:style="text"/>
@@ -719,6 +720,9 @@
</menu:menu>
<menu:menuitem menu:id=".uno:WordCountDialog" menu:style="text"/>
<menu:menuitem menu:id=".uno:AccessibilityCheck"/>
+ <menu:menuitem menu:id=".uno:AccessibilityCheckOnline"/>
+ <menu:menuseparator/>
+ <menu:menuitem menu:id=".uno:Translate" menu:style="text"/>
<menu:menuseparator/>
<menu:menu menu:id=".uno:AutoFormatMenu">
<menu:menupopup>
diff --git a/sw/uiconfig/sglobal/statusbar/statusbar.xml b/sw/uiconfig/sglobal/statusbar/statusbar.xml
index f85f07daa068..18f6871a3ac6 100644
--- a/sw/uiconfig/sglobal/statusbar/statusbar.xml
+++ b/sw/uiconfig/sglobal/statusbar/statusbar.xml
@@ -20,6 +20,7 @@
<statusbar:statusbar xmlns:statusbar="http://openoffice.org/2001/statusbar" xmlns:xlink="http://www.w3.org/1999/xlink">
<statusbar:statusbaritem xlink:href=".uno:StatePageNumber" statusbar:align="left" statusbar:autosize="true" statusbar:mandatory="true" statusbar:width="54"/>
<statusbar:statusbaritem xlink:href=".uno:StateWordCount" statusbar:align="left" statusbar:autosize="true"/>
+ <statusbar:statusbaritem xlink:href=".uno:StateAccessibilityCheck" statusbar:align="left" statusbar:ownerdraw="true" statusbar:width="32"/>
<statusbar:statusbaritem xlink:href=".uno:PageStyleName" statusbar:align="left" statusbar:autosize="true" statusbar:width="79"/>
<statusbar:statusbaritem xlink:href=".uno:LanguageStatus" statusbar:align="center" statusbar:autosize="true" statusbar:mandatory="false" statusbar:width="100"/>
<statusbar:statusbaritem xlink:href=".uno:InsertMode" statusbar:align="center" statusbar:mandatory="false" statusbar:width="55"/>
diff --git a/sw/uiconfig/swriter/menubar/menubar.xml b/sw/uiconfig/swriter/menubar/menubar.xml
index 3f257b9f0ebf..96406c02ce32 100644
--- a/sw/uiconfig/swriter/menubar/menubar.xml
+++ b/sw/uiconfig/swriter/menubar/menubar.xml
@@ -347,7 +347,7 @@
</menu:menupopup>
</menu:menu>
<menu:menuseparator/>
- <menu:menuitem menu:id=".uno:InsertPageNumberField"/>
+ <menu:menuitem menu:id=".uno:PageNumberWizard"/>
<menu:menuitem menu:id=".uno:InsertFieldCtrl" menu:style="text"/>
<menu:menu menu:id=".uno:InsertHeaderFooterMenu">
<menu:menupopup>
@@ -454,6 +454,7 @@
</menu:menupopup>
</menu:menu>
<menu:menuitem menu:id=".uno:OutlineBullet"/>
+ <menu:menuitem menu:id=".uno:ThemeDialog"/>
<menu:menuseparator/>
<menu:menuitem menu:id=".uno:PageDialog"/>
<menu:menuitem menu:id=".uno:TitlePageDialog"/>
@@ -713,8 +714,10 @@
<menu:menu menu:id=".uno:ContentControlsMenu">
<menu:menupopup>
<menu:menuitem menu:id=".uno:InsertContentControl"/>
+ <menu:menuitem menu:id=".uno:InsertPlainTextContentControl"/>
<menu:menuitem menu:id=".uno:InsertPictureContentControl"/>
<menu:menuitem menu:id=".uno:InsertCheckboxContentControl"/>
+ <menu:menuitem menu:id=".uno:InsertComboBoxContentControl"/>
<menu:menuitem menu:id=".uno:InsertDropdownContentControl"/>
<menu:menuitem menu:id=".uno:InsertDateContentControl"/>
<menu:menuitem menu:id=".uno:ContentControlProperties"/>
@@ -742,6 +745,9 @@
</menu:menu>
<menu:menuitem menu:id=".uno:WordCountDialog"/>
<menu:menuitem menu:id=".uno:AccessibilityCheck"/>
+ <menu:menuitem menu:id=".uno:AccessibilityCheckOnline"/>
+ <menu:menuseparator/>
+ <menu:menuitem menu:id=".uno:Translate"/>
<menu:menuseparator/>
<menu:menu menu:id=".uno:AutoFormatMenu">
<menu:menupopup>
diff --git a/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml b/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml
index 1e66cd782a8f..00a4b58ff94d 100644
--- a/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml
+++ b/sw/uiconfig/swriter/menubar/mscompatibleformsmenu.xml
@@ -16,8 +16,10 @@
<menu:menu menu:id=".uno:MSCompatContentControls">
<menu:menupopup>
<menu:menuitem menu:id=".uno:InsertContentControl"/>
+ <menu:menuitem menu:id=".uno:InsertPlainTextContentControl"/>
<menu:menuitem menu:id=".uno:InsertPictureContentControl"/>
<menu:menuitem menu:id=".uno:InsertCheckboxContentControl"/>
+ <menu:menuitem menu:id=".uno:InsertComboBoxContentControl"/>
<menu:menuitem menu:id=".uno:InsertDropdownContentControl"/>
<menu:menuitem menu:id=".uno:InsertDateContentControl"/>
<menu:menuitem menu:id=".uno:ContentControlProperties"/>
diff --git a/sw/uiconfig/swriter/statusbar/statusbar.xml b/sw/uiconfig/swriter/statusbar/statusbar.xml
index cc20c57fa81e..09a7f76abb98 100644
--- a/sw/uiconfig/swriter/statusbar/statusbar.xml
+++ b/sw/uiconfig/swriter/statusbar/statusbar.xml
@@ -21,6 +21,7 @@
<statusbar:statusbaritem xlink:href=".uno:ModifiedStatus" statusbar:align="center" statusbar:ownerdraw="true" statusbar:mandatory="true" statusbar:width="16"/>
<statusbar:statusbaritem xlink:href=".uno:StatePageNumber" statusbar:align="left" statusbar:autosize="true" statusbar:mandatory="true" statusbar:width="54"/>
<statusbar:statusbaritem xlink:href=".uno:StateWordCount" statusbar:align="left" statusbar:autosize="true"/>
+ <statusbar:statusbaritem xlink:href=".uno:StateAccessibilityCheck" statusbar:align="left" statusbar:ownerdraw="true" statusbar:width="32"/>
<statusbar:statusbaritem xlink:href=".uno:PageStyleName" statusbar:align="left" statusbar:autosize="true" statusbar:width="79"/>
<statusbar:statusbaritem xlink:href=".uno:LanguageStatus" statusbar:align="center" statusbar:autosize="true" statusbar:mandatory="false" statusbar:width="100"/>
<statusbar:statusbaritem xlink:href=".uno:InsertMode" statusbar:align="center" statusbar:mandatory="false" statusbar:width="55"/>
diff --git a/sw/uiconfig/swriter/ui/assignstylesdialog.ui b/sw/uiconfig/swriter/ui/assignstylesdialog.ui
index 1ed5cbb56e65..1e9f52faf87f 100644
--- a/sw/uiconfig/swriter/ui/assignstylesdialog.ui
+++ b/sw/uiconfig/swriter/ui/assignstylesdialog.ui
@@ -266,11 +266,10 @@
</child>
<child>
<object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <property name="clickable">True</property>
<property name="resizable">True</property>
<property name="spacing">6</property>
<property name="title" translatable="yes" context="assignstylesdialog|stylecolumn">Style</property>
- <property name="sort_indicator">True</property>
- <property name="sort_column_id">0</property>
<child>
<object class="GtkCellRendererText" id="cellrenderer1"/>
<attributes>
diff --git a/sw/uiconfig/swriter/ui/contentcontrolaliasbutton.ui b/sw/uiconfig/swriter/ui/contentcontrolaliasbutton.ui
new file mode 100644
index 000000000000..e61ec634693e
--- /dev/null
+++ b/sw/uiconfig/swriter/ui/contentcontrolaliasbutton.ui
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.1 -->
+<interface domain="sw">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkBox" id="ContentControlAliasButton">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkButton" id="button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/sw/uiconfig/swriter/ui/contentcontroldlg.ui b/sw/uiconfig/swriter/ui/contentcontroldlg.ui
index ef6b2081426c..e0f829758855 100644
--- a/sw/uiconfig/swriter/ui/contentcontroldlg.ui
+++ b/sw/uiconfig/swriter/ui/contentcontroldlg.ui
@@ -87,11 +87,11 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">3</property>
+ <property name="position">5</property>
</packing>
</child>
<child>
- <!-- n-columns=1 n-rows=1 -->
+ <!-- n-columns=2 n-rows=3 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
@@ -111,6 +111,55 @@
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
+ <property name="width">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="aliaslabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="contentcontroldlg|aliaslabel">Title:</property>
+ <property name="mnemonic-widget">aliasentry</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="taglabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="contentcontroldlg|taglabel">Tag:</property>
+ <property name="mnemonic-widget">tagentry</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="aliasentry">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="tagentry">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="truncate-multiline">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="top-attach">2</property>
</packing>
</child>
</object>
diff --git a/sw/uiconfig/swriter/ui/pagenumberdlg.ui b/sw/uiconfig/swriter/ui/pagenumberdlg.ui
new file mode 100644
index 000000000000..4f46767d9491
--- /dev/null
+++ b/sw/uiconfig/swriter/ui/pagenumberdlg.ui
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0 -->
+<interface domain="sw">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="PageNumberDialog">
+ <property name="can-focus">False</property>
+ <property name="title" translatable="yes" context="pagenumberdlg|PageNumberDialog">Page Number Wizard</property>
+ <property name="resizable">False</property>
+ <property name="default-width">0</property>
+ <property name="default-height">0</property>
+ <property name="type-hint">dialog</property>
+ <property name="gravity">north-east</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="mainVBox">
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="buttonBox">
+ <property name="can-focus">False</property>
+ <property name="layout-style">end</property>
+ <child>
+ <object class="GtkButton" id="ok">
+ <property name="label" translatable="yes" context="stock">_OK</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label" translatable="yes" context="stock">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="HBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">29</property>
+ <child>
+ <object class="GtkBox" id="leftVBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-end">10</property>
+ <property name="margin-bottom">10</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="positionLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="xpad">7</property>
+ <property name="ypad">7</property>
+ <property name="label" translatable="yes" context="pagenumberdlg|positionLabel">Position:</property>
+ <accessibility>
+ <relation type="label-for" target="positionCombo"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="positionLabel-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="pagenumberdlg|positionLabel-atkobject">Position</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="positionCombo">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="active">1</property>
+ <items>
+ <item translatable="yes" context="pagenumberdlg|liststore2">Top of page (Header)</item>
+ <item translatable="yes" context="pagenumberdlg|liststore2">Bottom of page (Footer)</item>
+ </items>
+ <accessibility>
+ <relation type="labelled-by" target="positionLabel"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="alignmentLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <property name="xpad">7</property>
+ <property name="ypad">7</property>
+ <property name="label" translatable="yes" context="pagenumberdlg|alignmentLabel">Alignment:</property>
+ <accessibility>
+ <relation type="label-for" target="alignmentCombo"/>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="alignmentLabel-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes" context="pagenumberdlg|alignmentLabel-atkobject">Alignment</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="alignmentCombo">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="active">0</property>
+ <items>
+ <item translatable="yes" context="pagenumberdlg|liststore1">Left</item>
+ <item translatable="yes" context="pagenumberdlg|liststore1">Center</item>
+ <item translatable="yes" context="pagenumberdlg|liststore1">Right</item>
+ </items>
+ <accessibility>
+ <relation type="labelled-by" target="alignmentLabel"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="rightVBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-end">10</property>
+ <property name="margin-bottom">10</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="previewLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="xpad">7</property>
+ <property name="ypad">7</property>
+ <property name="label" translatable="yes" context="pagenumberdlg|previewLabel">Preview</property>
+ <property name="justify">center</property>
+ <accessibility>
+ <relation type="label-for" target="previewImage"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="previewImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <accessibility>
+ <relation type="labelled-by" target="previewLabel"/>
+ </accessibility>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-5">ok</action-widget>
+ <action-widget response="-6">cancel</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/sw/uiconfig/swriter/ui/sidebartheme.ui b/sw/uiconfig/swriter/ui/sidebartheme.ui
index fd436e149e43..4af29d4d7b64 100644
--- a/sw/uiconfig/swriter/ui/sidebartheme.ui
+++ b/sw/uiconfig/swriter/ui/sidebartheme.ui
@@ -1,144 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
+<!-- Generated with glade 3.40.0 -->
<interface domain="sw">
<requires lib="gtk+" version="3.20"/>
- <object class="GtkTreeStore" id="liststore1">
- <columns>
- <!-- column-name text -->
- <column type="gchararray"/>
- <!-- column-name id -->
- <column type="gchararray"/>
- </columns>
- </object>
- <!-- n-columns=1 n-rows=1 -->
+ <!-- n-columns=1 n-rows=3 -->
<object class="GtkGrid" id="ThemePanel">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
+ <property name="can-focus">True</property>
+ <property name="row-spacing">6</property>
+ <property name="column-spacing">6</property>
<child>
- <!-- n-columns=1 n-rows=1 -->
- <object class="GtkGrid" id="grid1">
+ <object class="GtkLabel" id="label2">
<property name="visible">True</property>
- <property name="can_focus">False</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes" context="sidebartheme|label2">Colors</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">valueset_colors</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="apply">
+ <property name="label" translatable="yes" context="stock">_Apply</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="use-underline">True</property>
+ </object>
+ <packing>
+ <property name="left-attach">0</property>
+ <property name="top-attach">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="valuesetwin">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">6</property>
- <child>
- <object class="GtkLabel" id="label1">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes" context="sidebartheme|label1">Fonts</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">listbox_fonts</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
- </child>
+ <property name="hscrollbar-policy">never</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
<child>
- <object class="GtkScrolledWindow">
+ <object class="GtkViewport">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="shadow_type">in</property>
+ <property name="can-focus">False</property>
<child>
- <object class="GtkTreeView" id="listbox_fonts">
+ <object class="GtkDrawingArea" id="valueset_colors">
<property name="visible">True</property>
- <property name="can_focus">True</property>
+ <property name="can-focus">True</property>
+ <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
- <property name="model">liststore1</property>
- <property name="headers_visible">False</property>
- <property name="headers_clickable">False</property>
- <property name="search_column">0</property>
- <property name="show_expanders">False</property>
- <child internal-child="selection">
- <object class="GtkTreeSelection"/>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn1">
- <child>
- <object class="GtkCellRendererText" id="cellrenderertext1"/>
- <attributes>
- <attribute name="text">0</attribute>
- </attributes>
- </child>
- </object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="label2">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes" context="sidebartheme|label2">Colors</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">valueset_colors</property>
- <property name="xalign">0</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="apply">
- <property name="label" translatable="yes" context="stock">_Apply</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="use-underline">True</property>
- </object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">4</property>
- </packing>
- </child>
- <child>
- <object class="GtkScrolledWindow" id="valuesetwin">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">never</property>
- <property name="shadow_type">in</property>
- <child>
- <object class="GtkViewport">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkDrawingArea" id="valueset_colors">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- </object>
- </child>
</object>
</child>
</object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">3</property>
- </packing>
</child>
</object>
<packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
</packing>
</child>
</object>
diff --git a/sw/uiconfig/swriter/ui/sidebarwrap.ui b/sw/uiconfig/swriter/ui/sidebarwrap.ui
index 37c3a6af8d8a..1707e746fa7a 100644
--- a/sw/uiconfig/swriter/ui/sidebarwrap.ui
+++ b/sw/uiconfig/swriter/ui/sidebarwrap.ui
@@ -1,78 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
+<!-- Generated with glade 3.40.0 -->
<interface domain="sw">
<requires lib="gtk+" version="3.20"/>
<!-- n-columns=1 n-rows=1 -->
<object class="GtkGrid" id="WrapPropertyPanel">
<property name="visible">True</property>
- <property name="can_focus">False</property>
+ <property name="can-focus">False</property>
<child>
- <!-- n-columns=1 n-rows=1 -->
- <object class="GtkGrid">
+ <!-- n-columns=2 n-rows=2 -->
+ <object class="GtkGrid" id="grid1">
<property name="visible">True</property>
- <property name="can_focus">False</property>
+ <property name="can-focus">False</property>
<property name="hexpand">True</property>
- <property name="border_width">6</property>
- <property name="row_spacing">3</property>
- <property name="column_spacing">6</property>
+ <property name="border-width">6</property>
+ <property name="row-spacing">3</property>
+ <property name="column-spacing">6</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
- <property name="can_focus">False</property>
+ <property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes" context="sidebarwrap|label1">Spacing:</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">spacingLB</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">spacingLB</property>
<property name="xalign">0</property>
</object>
<packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
+ <property name="left-attach">0</property>
+ <property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkComboBoxText" id="spacingLB">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="tooltip_text" translatable="yes" context="sidebarwrap|spacingLB|tooltip_text">Set the amount of space between the image and surrounding text</property>
+ <property name="can-focus">False</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarwrap|spacingLB|tooltip_text">Set the amount of space between the image and surrounding text</property>
+ <property name="hexpand">True</property>
</object>
<packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
+ <property name="left-attach">1</property>
+ <property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
+ <property name="can-focus">False</property>
<property name="label" translatable="yes" context="sidebarwrap|label2">Wrap:</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">spacingLB</property>
+ <property name="use-underline">True</property>
+ <property name="mnemonic-widget">spacingLB</property>
<property name="xalign">0</property>
</object>
<packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">end</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
<child>
<object class="GtkToolbar" id="wrapoptions">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="toolbar_style">icons</property>
- <property name="show_arrow">False</property>
+ <property name="can-focus">True</property>
+ <property name="toolbar-style">icons</property>
+ <property name="show-arrow">False</property>
<property name="icon_size">2</property>
<child>
<object class="GtkRadioToolButton" id=".uno:WrapOff">
<property name="visible">True</property>
- <property name="tooltip_text" translatable="yes" context="sidebarwrap|wrapoff|tooltip_text">None</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">False</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarwrap|wrapoff|tooltip_text">None</property>
+ <property name="use-underline">True</property>
<property name="active">True</property>
</object>
<packing>
@@ -83,8 +84,9 @@
<child>
<object class="GtkRadioToolButton" id=".uno:WrapOn">
<property name="visible">True</property>
- <property name="tooltip_text" translatable="yes" context="sidebarwrap|wrapon|tooltip_text">Parallel</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">False</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarwrap|wrapon|tooltip_text">Parallel</property>
+ <property name="use-underline">True</property>
<property name="group">.uno:WrapOff</property>
</object>
<packing>
@@ -95,8 +97,9 @@
<child>
<object class="GtkRadioToolButton" id=".uno:WrapIdeal">
<property name="visible">True</property>
- <property name="tooltip_text" translatable="yes" context="sidebarwrap|wrapideal|tooltip_text">Optimal</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">False</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarwrap|wrapideal|tooltip_text">Optimal</property>
+ <property name="use-underline">True</property>
<property name="group">.uno:WrapOff</property>
</object>
<packing>
@@ -107,8 +110,9 @@
<child>
<object class="GtkRadioToolButton" id=".uno:WrapLeft">
<property name="visible">True</property>
- <property name="tooltip_text" translatable="yes" context="sidebarwrap|wrapbefore|tooltip_text">Before</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">False</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarwrap|wrapbefore|tooltip_text">Before</property>
+ <property name="use-underline">True</property>
<property name="group">.uno:WrapOff</property>
</object>
<packing>
@@ -119,8 +123,9 @@
<child>
<object class="GtkRadioToolButton" id=".uno:WrapRight">
<property name="visible">True</property>
- <property name="tooltip_text" translatable="yes" context="sidebarwrap|wrapafter|tooltip_text">After</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">False</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarwrap|wrapafter|tooltip_text">After</property>
+ <property name="use-underline">True</property>
<property name="group">.uno:WrapOff</property>
</object>
<packing>
@@ -131,8 +136,9 @@
<child>
<object class="GtkRadioToolButton" id=".uno:WrapThrough">
<property name="visible">True</property>
- <property name="tooltip_text" translatable="yes" context="sidebarwrap|wrapthrough|tooltip_text">Through</property>
- <property name="use_underline">True</property>
+ <property name="can-focus">False</property>
+ <property name="tooltip-text" translatable="yes" context="sidebarwrap|wrapthrough|tooltip_text">Through</property>
+ <property name="use-underline">True</property>
<property name="group">.uno:WrapOff</property>
</object>
<packing>
@@ -149,14 +155,14 @@
</child>
</object>
<packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
+ <property name="left-attach">1</property>
+ <property name="top-attach">0</property>
</packing>
</child>
</object>
<packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
+ <property name="left-attach">0</property>
+ <property name="top-attach">0</property>
</packing>
</child>
</object>
diff --git a/sw/uiconfig/swriter/ui/translationdialog.ui b/sw/uiconfig/swriter/ui/translationdialog.ui
new file mode 100644
index 000000000000..a6aff92ab00c
--- /dev/null
+++ b/sw/uiconfig/swriter/ui/translationdialog.ui
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="sw">
+ <requires lib="gtk+" version="3.20"/>
+ <object class="GtkDialog" id="LanguageSelectDialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">6</property>
+ <property name="title" translatable="yes" context="LanguageSelectDialog">Language Selection</property>
+ <property name="resizable">False</property>
+ <property name="modal">True</property>
+ <property name="default_width">0</property>
+ <property name="default_height">0</property>
+ <property name="type_hint">dialog</property>
+ <child type="titlebar">
+ <placeholder/>
+ </child>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="action-area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel">
+ <property name="label">_Cancel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="translate">
+ <property name="label">_OK</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_underline">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="row_spacing">5</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label" translatable="yes" context="LanguageSelectDialog">Select the target language for translation</property>
+ <property name="mnemonic_widget">combobox1</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBoxText" id="combobox1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="-6">cancel</action-widget>
+ <action-widget response="-5">translate</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/sw/uiwriter_setup.mk b/sw/uiwriter_setup.mk
index a4def8e80120..88571a9640e3 100644
--- a/sw/uiwriter_setup.mk
+++ b/sw/uiwriter_setup.mk
@@ -13,6 +13,7 @@ define sw_uiwriter_libraries
comphelper \
cppu \
cppuhelper \
+ docmodel \
editeng \
i18nlangtag \
msword \
diff --git a/sw/ww8export_setup.mk b/sw/ww8export_setup.mk
index f2fdd0a5aa9c..6df79b02011d 100644
--- a/sw/ww8export_setup.mk
+++ b/sw/ww8export_setup.mk
@@ -24,6 +24,7 @@ $(eval $(call gb_CppunitTest_use_libraries,sw_ww8export$(1), \
comphelper \
cppu \
cppuhelper \
+ docmodel \
editeng \
emboleobj \
sal \