From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- xmloff/source/chart/ColorPropertySet.cxx | 156 + xmloff/source/chart/ColorPropertySet.hxx | 82 + xmloff/source/chart/MultiPropertySetHandler.hxx | 244 + xmloff/source/chart/PropertyMap.hxx | 89 + xmloff/source/chart/PropertyMaps.cxx | 1040 ++++ xmloff/source/chart/SchXMLAutoStylePoolP.cxx | 77 + xmloff/source/chart/SchXMLAxisContext.cxx | 900 ++++ xmloff/source/chart/SchXMLAxisContext.hxx | 77 + .../chart/SchXMLCalculationSettingsContext.cxx | 73 + .../chart/SchXMLCalculationSettingsContext.hxx | 39 + xmloff/source/chart/SchXMLChartContext.cxx | 1235 +++++ xmloff/source/chart/SchXMLChartContext.hxx | 148 + xmloff/source/chart/SchXMLEnumConverter.cxx | 76 + xmloff/source/chart/SchXMLEnumConverter.hxx | 30 + xmloff/source/chart/SchXMLExport.cxx | 4067 +++++++++++++++ xmloff/source/chart/SchXMLImport.cxx | 377 ++ xmloff/source/chart/SchXMLLegendContext.cxx | 172 + xmloff/source/chart/SchXMLLegendContext.hxx | 39 + xmloff/source/chart/SchXMLParagraphContext.cxx | 107 + xmloff/source/chart/SchXMLParagraphContext.hxx | 53 + xmloff/source/chart/SchXMLPlotAreaContext.cxx | 1280 +++++ xmloff/source/chart/SchXMLPlotAreaContext.hxx | 304 ++ .../source/chart/SchXMLPropertyMappingContext.cxx | 115 + .../source/chart/SchXMLPropertyMappingContext.hxx | 45 + .../chart/SchXMLRegressionCurveObjectContext.cxx | 181 + .../chart/SchXMLRegressionCurveObjectContext.hxx | 74 + xmloff/source/chart/SchXMLSeries2Context.cxx | 1307 +++++ xmloff/source/chart/SchXMLSeries2Context.hxx | 133 + xmloff/source/chart/SchXMLSeriesHelper.cxx | 218 + xmloff/source/chart/SchXMLTableContext.cxx | 1048 ++++ xmloff/source/chart/SchXMLTableContext.hxx | 172 + xmloff/source/chart/SchXMLTextListContext.cxx | 108 + xmloff/source/chart/SchXMLTextListContext.hxx | 46 + xmloff/source/chart/SchXMLTools.cxx | 858 ++++ xmloff/source/chart/SchXMLTools.hxx | 136 + xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx | 134 + xmloff/source/chart/XMLAxisPositionPropertyHdl.hxx | 36 + xmloff/source/chart/XMLChartPropertyContext.cxx | 63 + xmloff/source/chart/XMLChartPropertyContext.hxx | 44 + xmloff/source/chart/XMLChartStyleContext.cxx | 139 + .../source/chart/XMLErrorBarStylePropertyHdl.cxx | 61 + .../source/chart/XMLErrorBarStylePropertyHdl.hxx | 33 + .../source/chart/XMLErrorIndicatorPropertyHdl.cxx | 103 + .../source/chart/XMLErrorIndicatorPropertyHdl.hxx | 37 + xmloff/source/chart/XMLLabelSeparatorContext.cxx | 66 + xmloff/source/chart/XMLLabelSeparatorContext.hxx | 40 + xmloff/source/chart/XMLSymbolImageContext.cxx | 112 + xmloff/source/chart/XMLSymbolImageContext.hxx | 48 + xmloff/source/chart/XMLSymbolTypePropertyHdl.cxx | 166 + xmloff/source/chart/XMLSymbolTypePropertyHdl.hxx | 36 + xmloff/source/chart/XMLTextOrientationHdl.cxx | 72 + xmloff/source/chart/XMLTextOrientationHdl.hxx | 37 + xmloff/source/chart/contexts.cxx | 169 + xmloff/source/chart/contexts.hxx | 85 + xmloff/source/chart/transporttypes.cxx | 30 + xmloff/source/chart/transporttypes.hxx | 231 + xmloff/source/core/DocumentSettingsContext.cxx | 760 +++ xmloff/source/core/DomBuilderContext.cxx | 321 ++ xmloff/source/core/DomExport.cxx | 249 + xmloff/source/core/ProgressBarHelper.cxx | 107 + xmloff/source/core/PropertySetMerger.cxx | 231 + xmloff/source/core/RDFaExportHelper.cxx | 180 + xmloff/source/core/RDFaImportHelper.cxx | 449 ++ xmloff/source/core/SettingsExportHelper.cxx | 518 ++ xmloff/source/core/SvXMLAttr.cxx | 38 + xmloff/source/core/SvXMLAttr.hxx | 34 + xmloff/source/core/SvXMLAttrCollection.cxx | 180 + xmloff/source/core/SvXMLAttrCollection.hxx | 66 + xmloff/source/core/XMLBase64Export.cxx | 84 + xmloff/source/core/XMLBase64ImportContext.cxx | 63 + xmloff/source/core/XMLBasicExportFilter.cxx | 86 + .../source/core/XMLEmbeddedObjectExportFilter.cxx | 147 + .../source/core/XMLEmbeddedObjectImportContext.cxx | 263 + xmloff/source/core/attrlist.cxx | 192 + xmloff/source/core/fasttokenhandler.cxx | 110 + xmloff/source/core/i18nmap.cxx | 41 + xmloff/source/core/namespacemap.cxx | 560 +++ xmloff/source/core/unoatrcn.cxx | 242 + .../core/unointerfacetouniqueidentifiermapper.cxx | 196 + xmloff/source/core/xmlcnimp.cxx | 167 + xmloff/source/core/xmlenums.hxx | 47 + xmloff/source/core/xmlerror.cxx | 208 + xmloff/source/core/xmlexp.cxx | 2475 ++++++++++ xmloff/source/core/xmlictxt.cxx | 98 + xmloff/source/core/xmlimp.cxx | 2278 +++++++++ xmloff/source/core/xmlmultiimagehelper.cxx | 175 + xmloff/source/core/xmltkmap.cxx | 88 + xmloff/source/core/xmltoken.cxx | 3611 ++++++++++++++ xmloff/source/core/xmluconv.cxx | 949 ++++ xmloff/source/draw/EnhancedCustomShapeToken.cxx | 214 + xmloff/source/draw/QRCodeContext.cxx | 91 + xmloff/source/draw/QRCodeContext.hxx | 26 + xmloff/source/draw/SignatureLineContext.cxx | 136 + xmloff/source/draw/SignatureLineContext.hxx | 25 + xmloff/source/draw/XMLGraphicsDefaultStyle.cxx | 189 + xmloff/source/draw/XMLImageMapContext.cxx | 542 ++ xmloff/source/draw/XMLImageMapExport.cxx | 339 ++ xmloff/source/draw/XMLNumberStyles.cxx | 711 +++ xmloff/source/draw/XMLNumberStylesExport.hxx | 40 + xmloff/source/draw/XMLReplacementImageContext.cxx | 99 + xmloff/source/draw/XMLShapePropertySetContext.cxx | 91 + xmloff/source/draw/XMLShapeStyleContext.cxx | 323 ++ xmloff/source/draw/animationexport.cxx | 1743 +++++++ xmloff/source/draw/animationimport.cxx | 1357 +++++ xmloff/source/draw/animexp.cxx | 512 ++ xmloff/source/draw/animimp.cxx | 598 +++ xmloff/source/draw/descriptionimp.cxx | 76 + xmloff/source/draw/descriptionimp.hxx | 46 + xmloff/source/draw/eventimp.cxx | 454 ++ xmloff/source/draw/eventimp.hxx | 68 + xmloff/source/draw/layerexp.cxx | 128 + xmloff/source/draw/layerexp.hxx | 30 + xmloff/source/draw/layerimp.cxx | 197 + xmloff/source/draw/layerimp.hxx | 41 + xmloff/source/draw/numithdl.cxx | 52 + xmloff/source/draw/numithdl.hxx | 43 + xmloff/source/draw/propimp0.cxx | 263 + xmloff/source/draw/sdpropls.cxx | 1883 +++++++ xmloff/source/draw/sdpropls.hxx | 131 + xmloff/source/draw/sdxmlexp.cxx | 2905 +++++++++++ xmloff/source/draw/sdxmlexp_impl.hxx | 179 + xmloff/source/draw/sdxmlimp.cxx | 663 +++ xmloff/source/draw/sdxmlimp_impl.hxx | 135 + xmloff/source/draw/shapeexport.cxx | 5196 ++++++++++++++++++++ xmloff/source/draw/shapeimport.cxx | 950 ++++ xmloff/source/draw/xexptran.cxx | 1057 ++++ xmloff/source/draw/ximp3dobject.cxx | 369 ++ xmloff/source/draw/ximp3dobject.hxx | 136 + xmloff/source/draw/ximp3dscene.cxx | 441 ++ xmloff/source/draw/ximp3dscene.hxx | 52 + xmloff/source/draw/ximpbody.cxx | 346 ++ xmloff/source/draw/ximpbody.hxx | 59 + xmloff/source/draw/ximpcustomshape.cxx | 1421 ++++++ xmloff/source/draw/ximpcustomshape.hxx | 66 + xmloff/source/draw/ximpgrp.cxx | 100 + xmloff/source/draw/ximpgrp.hxx | 49 + xmloff/source/draw/ximplink.cxx | 66 + xmloff/source/draw/ximplink.hxx | 47 + xmloff/source/draw/ximpnote.cxx | 92 + xmloff/source/draw/ximpnote.hxx | 36 + xmloff/source/draw/ximppage.cxx | 600 +++ xmloff/source/draw/ximppage.hxx | 77 + xmloff/source/draw/ximpshap.cxx | 3940 +++++++++++++++ xmloff/source/draw/ximpshap.hxx | 640 +++ xmloff/source/draw/ximpshow.cxx | 244 + xmloff/source/draw/ximpshow.hxx | 49 + xmloff/source/draw/ximpstyl.cxx | 1600 ++++++ xmloff/source/draw/ximpstyl.hxx | 247 + xmloff/source/forms/callbacks.hxx | 79 + xmloff/source/forms/controlelement.cxx | 87 + xmloff/source/forms/controlelement.hxx | 88 + xmloff/source/forms/controlpropertyhdl.cxx | 343 ++ xmloff/source/forms/controlpropertymap.cxx | 119 + xmloff/source/forms/controlpropertymap.hxx | 51 + xmloff/source/forms/elementexport.cxx | 2185 ++++++++ xmloff/source/forms/elementexport.hxx | 311 ++ xmloff/source/forms/elementimport.cxx | 2073 ++++++++ xmloff/source/forms/elementimport.hxx | 674 +++ xmloff/source/forms/eventexport.cxx | 126 + xmloff/source/forms/eventexport.hxx | 71 + xmloff/source/forms/eventimport.cxx | 135 + xmloff/source/forms/eventimport.hxx | 77 + xmloff/source/forms/formattributes.cxx | 405 ++ xmloff/source/forms/formattributes.hxx | 414 ++ xmloff/source/forms/formcellbinding.cxx | 433 ++ xmloff/source/forms/formcellbinding.hxx | 260 + xmloff/source/forms/formenums.cxx | 191 + xmloff/source/forms/formenums.hxx | 54 + xmloff/source/forms/formevents.cxx | 70 + xmloff/source/forms/formevents.hxx | 30 + xmloff/source/forms/formlayerexport.cxx | 121 + xmloff/source/forms/formlayerimport.cxx | 90 + xmloff/source/forms/gridcolumnproptranslator.cxx | 299 ++ xmloff/source/forms/gridcolumnproptranslator.hxx | 66 + .../source/forms/handler/form_handler_factory.cxx | 65 + xmloff/source/forms/handler/vcl_date_handler.cxx | 93 + xmloff/source/forms/handler/vcl_date_handler.hxx | 40 + xmloff/source/forms/handler/vcl_time_handler.cxx | 96 + xmloff/source/forms/handler/vcl_time_handler.hxx | 40 + xmloff/source/forms/layerexport.cxx | 727 +++ xmloff/source/forms/layerexport.hxx | 299 ++ xmloff/source/forms/layerimport.cxx | 553 +++ xmloff/source/forms/layerimport.hxx | 175 + xmloff/source/forms/logging.cxx | 41 + xmloff/source/forms/logging.hxx | 59 + xmloff/source/forms/officeforms.cxx | 177 + xmloff/source/forms/officeforms.hxx | 92 + xmloff/source/forms/property_description.hxx | 103 + xmloff/source/forms/property_meta_data.cxx | 156 + xmloff/source/forms/property_meta_data.hxx | 42 + xmloff/source/forms/propertyexport.cxx | 683 +++ xmloff/source/forms/propertyexport.hxx | 413 ++ xmloff/source/forms/propertyimport.cxx | 524 ++ xmloff/source/forms/propertyimport.hxx | 226 + xmloff/source/forms/strings.hxx | 209 + xmloff/source/forms/valueproperties.cxx | 180 + xmloff/source/forms/valueproperties.hxx | 67 + xmloff/source/meta/MetaExportComponent.cxx | 181 + xmloff/source/meta/MetaImportComponent.cxx | 97 + xmloff/source/meta/xmlmetae.cxx | 479 ++ xmloff/source/meta/xmlmetai.cxx | 318 ++ xmloff/source/meta/xmlversion.cxx | 429 ++ xmloff/source/script/XMLEventExport.cxx | 320 ++ xmloff/source/script/XMLEventImportHelper.cxx | 147 + xmloff/source/script/XMLEventsImportContext.cxx | 179 + xmloff/source/script/XMLScriptContextFactory.cxx | 69 + xmloff/source/script/XMLScriptExportHandler.cxx | 75 + .../source/script/XMLStarBasicContextFactory.cxx | 101 + xmloff/source/script/XMLStarBasicExportHandler.cxx | 95 + xmloff/source/script/xmlbasicscript.cxx | 316 ++ xmloff/source/script/xmlbasicscript.hxx | 111 + xmloff/source/script/xmlscripti.cxx | 129 + xmloff/source/style/AttributeContainerHandler.cxx | 86 + xmloff/source/style/DashStyle.cxx | 275 ++ xmloff/source/style/DrawAspectHdl.cxx | 61 + xmloff/source/style/DrawAspectHdl.hxx | 36 + xmloff/source/style/EnumPropertyHdl.cxx | 82 + xmloff/source/style/FillStyleContext.cxx | 317 ++ xmloff/source/style/FillStyleContext.hxx | 144 + xmloff/source/style/GradientStyle.cxx | 238 + xmloff/source/style/HatchStyle.cxx | 178 + xmloff/source/style/ImageStyle.cxx | 135 + xmloff/source/style/MarkerStyle.cxx | 193 + xmloff/source/style/MultiPropertySetHelper.cxx | 169 + xmloff/source/style/NamedBoolPropertyHdl.cxx | 67 + xmloff/source/style/PageHeaderFooterContext.cxx | 71 + xmloff/source/style/PageHeaderFooterContext.hxx | 48 + xmloff/source/style/PageMasterExportPropMapper.cxx | 650 +++ xmloff/source/style/PageMasterExportPropMapper.hxx | 66 + xmloff/source/style/PageMasterImportContext.cxx | 434 ++ xmloff/source/style/PageMasterImportPropMapper.cxx | 521 ++ xmloff/source/style/PageMasterImportPropMapper.hxx | 53 + xmloff/source/style/PageMasterPropHdl.cxx | 398 ++ xmloff/source/style/PageMasterPropHdl.hxx | 158 + xmloff/source/style/PageMasterPropHdlFactory.cxx | 170 + xmloff/source/style/PageMasterPropMapper.cxx | 48 + xmloff/source/style/PageMasterStyleMap.cxx | 305 ++ xmloff/source/style/PagePropertySetContext.cxx | 119 + xmloff/source/style/PagePropertySetContext.hxx | 54 + xmloff/source/style/SinglePropertySetInfoCache.cxx | 54 + xmloff/source/style/StyleMap.cxx | 32 + xmloff/source/style/TransGradientStyle.cxx | 246 + xmloff/source/style/WordWrapPropertyHdl.cxx | 88 + xmloff/source/style/XMLBackgroundImageContext.cxx | 397 ++ xmloff/source/style/XMLBackgroundImageExport.cxx | 165 + .../style/XMLBitmapLogicalSizePropertyHandler.cxx | 53 + .../style/XMLBitmapRepeatOffsetPropertyHandler.cxx | 94 + xmloff/source/style/XMLClipPropertyHandler.cxx | 141 + .../source/style/XMLConstantsPropertyHandler.cxx | 91 + xmloff/source/style/XMLElementPropertyContext.cxx | 44 + .../style/XMLFillBitmapSizePropertyHandler.cxx | 88 + xmloff/source/style/XMLFontAutoStylePool.cxx | 680 +++ xmloff/source/style/XMLFontStylesContext.cxx | 352 ++ xmloff/source/style/XMLFontStylesContext_impl.hxx | 122 + xmloff/source/style/XMLFootnoteSeparatorExport.cxx | 179 + xmloff/source/style/XMLFootnoteSeparatorExport.hxx | 50 + xmloff/source/style/XMLFootnoteSeparatorImport.cxx | 198 + xmloff/source/style/XMLFootnoteSeparatorImport.hxx | 61 + .../style/XMLIsPercentagePropertyHandler.cxx | 50 + xmloff/source/style/XMLPageExport.cxx | 319 ++ .../style/XMLPercentOrMeasurePropertyHandler.cxx | 75 + xmloff/source/style/XMLRectangleMembersHandler.cxx | 112 + .../source/style/XMLRtlGutterPropertyHandler.cxx | 51 + xmloff/source/style/adjushdl.cxx | 121 + xmloff/source/style/adjushdl.hxx | 48 + xmloff/source/style/backhdl.cxx | 285 ++ xmloff/source/style/backhdl.hxx | 43 + xmloff/source/style/bordrhdl.cxx | 351 ++ xmloff/source/style/bordrhdl.hxx | 45 + xmloff/source/style/breakhdl.cxx | 179 + xmloff/source/style/breakhdl.hxx | 48 + xmloff/source/style/cdouthdl.cxx | 305 ++ xmloff/source/style/cdouthdl.hxx | 63 + xmloff/source/style/chrhghdl.cxx | 150 + xmloff/source/style/chrhghdl.hxx | 54 + xmloff/source/style/chrlohdl.cxx | 423 ++ xmloff/source/style/chrlohdl.hxx | 71 + xmloff/source/style/csmaphdl.cxx | 120 + xmloff/source/style/csmaphdl.hxx | 45 + xmloff/source/style/durationhdl.cxx | 71 + xmloff/source/style/durationhdl.hxx | 36 + xmloff/source/style/escphdl.cxx | 156 + xmloff/source/style/escphdl.hxx | 45 + xmloff/source/style/fonthdl.cxx | 291 ++ xmloff/source/style/fonthdl.hxx | 73 + xmloff/source/style/impastpl.cxx | 716 +++ xmloff/source/style/impastpl.hxx | 180 + xmloff/source/style/kernihdl.cxx | 78 + xmloff/source/style/kernihdl.hxx | 36 + xmloff/source/style/lspachdl.cxx | 173 + xmloff/source/style/lspachdl.hxx | 54 + xmloff/source/style/numehelp.cxx | 510 ++ xmloff/source/style/opaquhdl.cxx | 61 + xmloff/source/style/opaquhdl.hxx | 36 + xmloff/source/style/postuhdl.cxx | 81 + xmloff/source/style/postuhdl.hxx | 36 + xmloff/source/style/prhdlfac.cxx | 475 ++ xmloff/source/style/prstylecond.cxx | 91 + xmloff/source/style/prstylei.cxx | 664 +++ xmloff/source/style/shadwhdl.cxx | 167 + xmloff/source/style/shadwhdl.hxx | 36 + xmloff/source/style/shdwdhdl.cxx | 67 + xmloff/source/style/shdwdhdl.hxx | 36 + xmloff/source/style/styleexp.cxx | 592 +++ xmloff/source/style/tabsthdl.cxx | 65 + xmloff/source/style/tabsthdl.hxx | 39 + xmloff/source/style/undlihdl.cxx | 365 ++ xmloff/source/style/undlihdl.hxx | 54 + xmloff/source/style/weighhdl.cxx | 154 + xmloff/source/style/weighhdl.hxx | 37 + xmloff/source/style/xmlaustp.cxx | 384 ++ xmloff/source/style/xmlbahdl.cxx | 904 ++++ xmloff/source/style/xmlbahdl.hxx | 314 ++ xmloff/source/style/xmlexppr.cxx | 1129 +++++ xmloff/source/style/xmlimppr.cxx | 762 +++ xmloff/source/style/xmlnume.cxx | 832 ++++ xmloff/source/style/xmlnumfe.cxx | 2026 ++++++++ xmloff/source/style/xmlnumfi.cxx | 2231 +++++++++ xmloff/source/style/xmlnumi.cxx | 1081 ++++ xmloff/source/style/xmlprcon.cxx | 89 + xmloff/source/style/xmlprhdl.cxx | 33 + xmloff/source/style/xmlprmap.cxx | 361 ++ xmloff/source/style/xmlstyle.cxx | 806 +++ xmloff/source/style/xmltabe.cxx | 120 + xmloff/source/style/xmltabi.cxx | 186 + xmloff/source/table/XMLTableExport.cxx | 707 +++ xmloff/source/table/XMLTableImport.cxx | 808 +++ xmloff/source/table/table.hxx | 38 + xmloff/source/text/XMLAnchorTypePropHdl.hxx | 43 + xmloff/source/text/XMLAutoMarkFileContext.cxx | 83 + xmloff/source/text/XMLAutoMarkFileContext.hxx | 48 + .../text/XMLAutoTextContainerEventImport.cxx | 65 + .../text/XMLAutoTextContainerEventImport.hxx | 58 + xmloff/source/text/XMLAutoTextEventExport.cxx | 217 + xmloff/source/text/XMLAutoTextEventExport.hxx | 88 + xmloff/source/text/XMLAutoTextEventImport.cxx | 94 + xmloff/source/text/XMLAutoTextEventImport.hxx | 59 + .../source/text/XMLCalculationSettingsContext.cxx | 73 + .../source/text/XMLCalculationSettingsContext.hxx | 38 + .../source/text/XMLChangeElementImportContext.cxx | 94 + .../source/text/XMLChangeElementImportContext.hxx | 80 + xmloff/source/text/XMLChangeImportContext.cxx | 84 + xmloff/source/text/XMLChangeImportContext.hxx | 67 + xmloff/source/text/XMLChangeInfoContext.cxx | 84 + xmloff/source/text/XMLChangeInfoContext.hxx | 68 + .../source/text/XMLChangedRegionImportContext.cxx | 176 + .../source/text/XMLChangedRegionImportContext.hxx | 81 + .../source/text/XMLFootnoteBodyImportContext.cxx | 48 + .../source/text/XMLFootnoteBodyImportContext.hxx | 49 + .../text/XMLFootnoteConfigurationImportContext.cxx | 335 ++ xmloff/source/text/XMLFootnoteImportContext.cxx | 169 + xmloff/source/text/XMLFootnoteImportContext.hxx | 72 + .../text/XMLIndexAlphabeticalSourceContext.cxx | 214 + .../text/XMLIndexAlphabeticalSourceContext.hxx | 73 + .../XMLIndexBibliographyConfigurationContext.cxx | 216 + .../text/XMLIndexBibliographyEntryContext.cxx | 157 + .../text/XMLIndexBibliographyEntryContext.hxx | 70 + .../text/XMLIndexBibliographySourceContext.cxx | 82 + .../text/XMLIndexBibliographySourceContext.hxx | 57 + xmloff/source/text/XMLIndexBodyContext.cxx | 53 + xmloff/source/text/XMLIndexBodyContext.hxx | 63 + .../text/XMLIndexChapterInfoEntryContext.cxx | 186 + .../text/XMLIndexChapterInfoEntryContext.hxx | 67 + .../text/XMLIndexIllustrationSourceContext.cxx | 69 + .../text/XMLIndexIllustrationSourceContext.hxx | 55 + xmloff/source/text/XMLIndexMarkExport.cxx | 228 + xmloff/source/text/XMLIndexMarkExport.hxx | 92 + xmloff/source/text/XMLIndexObjectSourceContext.cxx | 139 + xmloff/source/text/XMLIndexObjectSourceContext.hxx | 63 + xmloff/source/text/XMLIndexSimpleEntryContext.cxx | 124 + xmloff/source/text/XMLIndexSimpleEntryContext.hxx | 79 + xmloff/source/text/XMLIndexSourceBaseContext.cxx | 123 + xmloff/source/text/XMLIndexSourceBaseContext.hxx | 72 + xmloff/source/text/XMLIndexSpanEntryContext.cxx | 63 + xmloff/source/text/XMLIndexSpanEntryContext.hxx | 57 + xmloff/source/text/XMLIndexTOCContext.cxx | 344 ++ xmloff/source/text/XMLIndexTOCContext.hxx | 82 + xmloff/source/text/XMLIndexTOCSourceContext.cxx | 150 + xmloff/source/text/XMLIndexTOCSourceContext.hxx | 62 + xmloff/source/text/XMLIndexTOCStylesContext.cxx | 128 + xmloff/source/text/XMLIndexTOCStylesContext.hxx | 73 + xmloff/source/text/XMLIndexTabStopEntryContext.cxx | 156 + xmloff/source/text/XMLIndexTabStopEntryContext.hxx | 66 + xmloff/source/text/XMLIndexTableSourceContext.cxx | 148 + xmloff/source/text/XMLIndexTableSourceContext.hxx | 63 + xmloff/source/text/XMLIndexTemplateContext.cxx | 422 ++ xmloff/source/text/XMLIndexTemplateContext.hxx | 125 + .../source/text/XMLIndexTitleTemplateContext.cxx | 97 + .../source/text/XMLIndexTitleTemplateContext.hxx | 71 + xmloff/source/text/XMLIndexUserSourceContext.cxx | 160 + xmloff/source/text/XMLIndexUserSourceContext.hxx | 65 + xmloff/source/text/XMLLineNumberingExport.cxx | 185 + xmloff/source/text/XMLLineNumberingExport.hxx | 35 + .../source/text/XMLLineNumberingImportContext.cxx | 234 + .../XMLLineNumberingSeparatorImportContext.cxx | 80 + .../XMLLineNumberingSeparatorImportContext.hxx | 59 + xmloff/source/text/XMLPropertyBackpatcher.cxx | 207 + xmloff/source/text/XMLPropertyBackpatcher.hxx | 97 + xmloff/source/text/XMLRedlineExport.cxx | 646 +++ xmloff/source/text/XMLRedlineExport.hxx | 163 + xmloff/source/text/XMLSectionExport.cxx | 1821 +++++++ xmloff/source/text/XMLSectionExport.hxx | 262 + .../source/text/XMLSectionFootnoteConfigExport.cxx | 179 + .../source/text/XMLSectionFootnoteConfigExport.hxx | 52 + .../source/text/XMLSectionFootnoteConfigImport.cxx | 170 + .../source/text/XMLSectionFootnoteConfigImport.hxx | 61 + xmloff/source/text/XMLSectionImportContext.cxx | 325 ++ xmloff/source/text/XMLSectionImportContext.hxx | 80 + .../text/XMLSectionSourceDDEImportContext.cxx | 108 + .../text/XMLSectionSourceDDEImportContext.hxx | 48 + .../source/text/XMLSectionSourceImportContext.cxx | 98 + .../source/text/XMLSectionSourceImportContext.hxx | 46 + .../source/text/XMLStringBufferImportContext.cxx | 62 + .../text/XMLTextCharStyleNamesElementExport.cxx | 75 + .../text/XMLTextCharStyleNamesElementExport.hxx | 46 + xmloff/source/text/XMLTextColumnsContext.cxx | 372 ++ xmloff/source/text/XMLTextColumnsExport.cxx | 196 + xmloff/source/text/XMLTextFrameContext.cxx | 1719 +++++++ xmloff/source/text/XMLTextFrameContext.hxx | 92 + .../source/text/XMLTextFrameHyperlinkContext.cxx | 183 + .../source/text/XMLTextFrameHyperlinkContext.hxx | 62 + xmloff/source/text/XMLTextHeaderFooterContext.cxx | 190 + xmloff/source/text/XMLTextListAutoStylePool.cxx | 276 ++ xmloff/source/text/XMLTextListBlockContext.cxx | 269 + xmloff/source/text/XMLTextListBlockContext.hxx | 76 + xmloff/source/text/XMLTextListItemContext.cxx | 152 + xmloff/source/text/XMLTextListItemContext.hxx | 69 + xmloff/source/text/XMLTextMarkImportContext.cxx | 584 +++ xmloff/source/text/XMLTextMarkImportContext.hxx | 106 + xmloff/source/text/XMLTextMasterPageContext.cxx | 301 ++ xmloff/source/text/XMLTextMasterPageExport.cxx | 237 + xmloff/source/text/XMLTextMasterStylesContext.cxx | 67 + xmloff/source/text/XMLTextNumRuleInfo.cxx | 226 + xmloff/source/text/XMLTextNumRuleInfo.hxx | 157 + xmloff/source/text/XMLTextPropertySetContext.cxx | 131 + xmloff/source/text/XMLTextPropertySetContext.hxx | 51 + xmloff/source/text/XMLTextShapeImportHelper.cxx | 149 + xmloff/source/text/XMLTextShapeStyleContext.cxx | 215 + xmloff/source/text/XMLTextTableContext.cxx | 35 + .../source/text/XMLTrackedChangesImportContext.cxx | 84 + .../source/text/XMLTrackedChangesImportContext.hxx | 48 + xmloff/source/text/txtdrope.cxx | 87 + xmloff/source/text/txtdrope.hxx | 41 + xmloff/source/text/txtdropi.cxx | 122 + xmloff/source/text/txtdropi.hxx | 46 + xmloff/source/text/txtexppr.cxx | 1199 +++++ xmloff/source/text/txtexppr.hxx | 88 + xmloff/source/text/txtflde.cxx | 3550 +++++++++++++ xmloff/source/text/txtfldi.cxx | 3628 ++++++++++++++ xmloff/source/text/txtftne.cxx | 344 ++ xmloff/source/text/txtimp.cxx | 2450 +++++++++ xmloff/source/text/txtimppr.cxx | 848 ++++ xmloff/source/text/txtlists.cxx | 499 ++ xmloff/source/text/txtparae.cxx | 4123 ++++++++++++++++ xmloff/source/text/txtparai.cxx | 2107 ++++++++ xmloff/source/text/txtparai.hxx | 145 + xmloff/source/text/txtparaimphint.hxx | 240 + xmloff/source/text/txtprhdl.cxx | 1468 ++++++ xmloff/source/text/txtprhdl.hxx | 31 + xmloff/source/text/txtprmap.cxx | 1154 +++++ xmloff/source/text/txtsecte.cxx | 204 + xmloff/source/text/txtstyle.cxx | 164 + xmloff/source/text/txtstyli.cxx | 634 +++ xmloff/source/text/txtvfldi.cxx | 1247 +++++ xmloff/source/text/xmlcontentcontrolcontext.cxx | 273 + xmloff/source/text/xmlcontentcontrolcontext.hxx | 84 + xmloff/source/text/xmllinebreakcontext.cxx | 59 + xmloff/source/text/xmllinebreakcontext.hxx | 31 + xmloff/source/token/tokens.hxx.head | 15 + xmloff/source/token/tokens.hxx.tail | 6 + xmloff/source/token/tokens.txt | 3251 ++++++++++++ xmloff/source/transform/ActionMapTypesOASIS.hxx | 87 + xmloff/source/transform/ActionMapTypesOOo.hxx | 84 + xmloff/source/transform/AttrTransformerAction.hxx | 126 + xmloff/source/transform/ChartOASISTContext.cxx | 131 + xmloff/source/transform/ChartOASISTContext.hxx | 34 + xmloff/source/transform/ChartOOoTContext.cxx | 133 + xmloff/source/transform/ChartOOoTContext.hxx | 34 + .../transform/ChartPlotAreaOASISTContext.cxx | 234 + .../transform/ChartPlotAreaOASISTContext.hxx | 46 + .../source/transform/ChartPlotAreaOOoTContext.cxx | 211 + .../source/transform/ChartPlotAreaOOoTContext.hxx | 55 + xmloff/source/transform/ControlOASISTContext.cxx | 150 + xmloff/source/transform/ControlOASISTContext.hxx | 39 + xmloff/source/transform/ControlOOoTContext.cxx | 87 + xmloff/source/transform/ControlOOoTContext.hxx | 46 + xmloff/source/transform/CreateElemTContext.cxx | 114 + xmloff/source/transform/CreateElemTContext.hxx | 36 + xmloff/source/transform/DeepTContext.cxx | 159 + xmloff/source/transform/DeepTContext.hxx | 71 + xmloff/source/transform/DlgOASISTContext.cxx | 98 + xmloff/source/transform/DlgOASISTContext.hxx | 34 + xmloff/source/transform/DocumentTContext.cxx | 128 + xmloff/source/transform/DocumentTContext.hxx | 40 + xmloff/source/transform/ElemTransformerAction.hxx | 87 + xmloff/source/transform/EventMap.cxx | 103 + xmloff/source/transform/EventMap.hxx | 34 + xmloff/source/transform/EventOASISTContext.cxx | 334 ++ xmloff/source/transform/EventOASISTContext.hxx | 44 + xmloff/source/transform/EventOOoTContext.cxx | 235 + xmloff/source/transform/EventOOoTContext.hxx | 52 + xmloff/source/transform/FamilyType.hxx | 49 + xmloff/source/transform/FlatTContext.cxx | 57 + xmloff/source/transform/FlatTContext.hxx | 58 + xmloff/source/transform/FormPropOASISTContext.cxx | 211 + xmloff/source/transform/FormPropOASISTContext.hxx | 43 + xmloff/source/transform/FormPropOOoTContext.cxx | 250 + xmloff/source/transform/FormPropOOoTContext.hxx | 57 + xmloff/source/transform/FrameOASISTContext.cxx | 187 + xmloff/source/transform/FrameOASISTContext.hxx | 54 + xmloff/source/transform/FrameOOoTContext.cxx | 157 + xmloff/source/transform/FrameOOoTContext.hxx | 46 + xmloff/source/transform/IgnoreTContext.cxx | 92 + xmloff/source/transform/IgnoreTContext.hxx | 71 + xmloff/source/transform/MergeElemTContext.cxx | 280 ++ xmloff/source/transform/MergeElemTContext.hxx | 55 + xmloff/source/transform/MetaTContext.cxx | 131 + xmloff/source/transform/MetaTContext.hxx | 66 + xmloff/source/transform/MutableAttrList.cxx | 163 + xmloff/source/transform/MutableAttrList.hxx | 76 + xmloff/source/transform/NotesTContext.cxx | 217 + xmloff/source/transform/NotesTContext.hxx | 49 + xmloff/source/transform/OOo2Oasis.cxx | 2098 ++++++++ xmloff/source/transform/OOo2Oasis.hxx | 102 + xmloff/source/transform/Oasis2OOo.cxx | 1984 ++++++++ xmloff/source/transform/Oasis2OOo.hxx | 59 + xmloff/source/transform/PersAttrListTContext.cxx | 174 + xmloff/source/transform/PersAttrListTContext.hxx | 103 + .../source/transform/PersMixedContentTContext.cxx | 139 + .../source/transform/PersMixedContentTContext.hxx | 54 + xmloff/source/transform/ProcAddAttrTContext.cxx | 66 + xmloff/source/transform/ProcAddAttrTContext.hxx | 44 + xmloff/source/transform/ProcAttrTContext.cxx | 65 + xmloff/source/transform/ProcAttrTContext.hxx | 50 + xmloff/source/transform/PropType.hxx | 41 + xmloff/source/transform/PropertyActionsOASIS.cxx | 545 ++ xmloff/source/transform/PropertyActionsOASIS.hxx | 63 + xmloff/source/transform/PropertyActionsOOo.cxx | 1058 ++++ xmloff/source/transform/PropertyActionsOOo.hxx | 67 + xmloff/source/transform/RenameElemTContext.cxx | 80 + xmloff/source/transform/RenameElemTContext.hxx | 61 + xmloff/source/transform/StyleOASISTContext.cxx | 973 ++++ xmloff/source/transform/StyleOASISTContext.hxx | 63 + xmloff/source/transform/StyleOOoTContext.cxx | 1342 +++++ xmloff/source/transform/StyleOOoTContext.hxx | 63 + xmloff/source/transform/Transformer.hxx | 36 + xmloff/source/transform/TransformerAction.hxx | 25 + xmloff/source/transform/TransformerActionInit.hxx | 42 + xmloff/source/transform/TransformerActions.cxx | 84 + xmloff/source/transform/TransformerActions.hxx | 131 + xmloff/source/transform/TransformerBase.cxx | 1409 ++++++ xmloff/source/transform/TransformerBase.hxx | 179 + xmloff/source/transform/TransformerContext.cxx | 92 + xmloff/source/transform/TransformerContext.hxx | 99 + xmloff/source/transform/TransformerTokenMap.cxx | 38 + xmloff/source/transform/TransformerTokenMap.hxx | 32 + xmloff/source/transform/xof.component | 143 + xmloff/source/transform/xof.component.chart | 11 + xmloff/source/xforms/SchemaContext.cxx | 62 + xmloff/source/xforms/SchemaContext.hxx | 53 + xmloff/source/xforms/SchemaRestrictionContext.cxx | 335 ++ xmloff/source/xforms/SchemaRestrictionContext.hxx | 60 + xmloff/source/xforms/SchemaSimpleTypeContext.cxx | 74 + xmloff/source/xforms/SchemaSimpleTypeContext.hxx | 54 + xmloff/source/xforms/TokenContext.cxx | 90 + xmloff/source/xforms/TokenContext.hxx | 74 + xmloff/source/xforms/XFormsBindContext.cxx | 155 + xmloff/source/xforms/XFormsBindContext.hxx | 59 + xmloff/source/xforms/XFormsInstanceContext.cxx | 162 + xmloff/source/xforms/XFormsInstanceContext.hxx | 69 + xmloff/source/xforms/XFormsModelContext.cxx | 110 + xmloff/source/xforms/XFormsModelContext.hxx | 54 + xmloff/source/xforms/XFormsModelExport.hxx | 33 + xmloff/source/xforms/XFormsSubmissionContext.cxx | 137 + xmloff/source/xforms/XFormsSubmissionContext.hxx | 54 + xmloff/source/xforms/xformsapi.cxx | 296 ++ xmloff/source/xforms/xformsapi.hxx | 83 + xmloff/source/xforms/xformsexport.cxx | 802 +++ xmloff/source/xforms/xformsimport.cxx | 184 + 579 files changed, 176945 insertions(+) create mode 100644 xmloff/source/chart/ColorPropertySet.cxx create mode 100644 xmloff/source/chart/ColorPropertySet.hxx create mode 100644 xmloff/source/chart/MultiPropertySetHandler.hxx create mode 100644 xmloff/source/chart/PropertyMap.hxx create mode 100644 xmloff/source/chart/PropertyMaps.cxx create mode 100644 xmloff/source/chart/SchXMLAutoStylePoolP.cxx create mode 100644 xmloff/source/chart/SchXMLAxisContext.cxx create mode 100644 xmloff/source/chart/SchXMLAxisContext.hxx create mode 100644 xmloff/source/chart/SchXMLCalculationSettingsContext.cxx create mode 100644 xmloff/source/chart/SchXMLCalculationSettingsContext.hxx create mode 100644 xmloff/source/chart/SchXMLChartContext.cxx create mode 100644 xmloff/source/chart/SchXMLChartContext.hxx create mode 100644 xmloff/source/chart/SchXMLEnumConverter.cxx create mode 100644 xmloff/source/chart/SchXMLEnumConverter.hxx create mode 100644 xmloff/source/chart/SchXMLExport.cxx create mode 100644 xmloff/source/chart/SchXMLImport.cxx create mode 100644 xmloff/source/chart/SchXMLLegendContext.cxx create mode 100644 xmloff/source/chart/SchXMLLegendContext.hxx create mode 100644 xmloff/source/chart/SchXMLParagraphContext.cxx create mode 100644 xmloff/source/chart/SchXMLParagraphContext.hxx create mode 100644 xmloff/source/chart/SchXMLPlotAreaContext.cxx create mode 100644 xmloff/source/chart/SchXMLPlotAreaContext.hxx create mode 100644 xmloff/source/chart/SchXMLPropertyMappingContext.cxx create mode 100644 xmloff/source/chart/SchXMLPropertyMappingContext.hxx create mode 100644 xmloff/source/chart/SchXMLRegressionCurveObjectContext.cxx create mode 100644 xmloff/source/chart/SchXMLRegressionCurveObjectContext.hxx create mode 100644 xmloff/source/chart/SchXMLSeries2Context.cxx create mode 100644 xmloff/source/chart/SchXMLSeries2Context.hxx create mode 100644 xmloff/source/chart/SchXMLSeriesHelper.cxx create mode 100644 xmloff/source/chart/SchXMLTableContext.cxx create mode 100644 xmloff/source/chart/SchXMLTableContext.hxx create mode 100644 xmloff/source/chart/SchXMLTextListContext.cxx create mode 100644 xmloff/source/chart/SchXMLTextListContext.hxx create mode 100644 xmloff/source/chart/SchXMLTools.cxx create mode 100644 xmloff/source/chart/SchXMLTools.hxx create mode 100644 xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx create mode 100644 xmloff/source/chart/XMLAxisPositionPropertyHdl.hxx create mode 100644 xmloff/source/chart/XMLChartPropertyContext.cxx create mode 100644 xmloff/source/chart/XMLChartPropertyContext.hxx create mode 100644 xmloff/source/chart/XMLChartStyleContext.cxx create mode 100644 xmloff/source/chart/XMLErrorBarStylePropertyHdl.cxx create mode 100644 xmloff/source/chart/XMLErrorBarStylePropertyHdl.hxx create mode 100644 xmloff/source/chart/XMLErrorIndicatorPropertyHdl.cxx create mode 100644 xmloff/source/chart/XMLErrorIndicatorPropertyHdl.hxx create mode 100644 xmloff/source/chart/XMLLabelSeparatorContext.cxx create mode 100644 xmloff/source/chart/XMLLabelSeparatorContext.hxx create mode 100644 xmloff/source/chart/XMLSymbolImageContext.cxx create mode 100644 xmloff/source/chart/XMLSymbolImageContext.hxx create mode 100644 xmloff/source/chart/XMLSymbolTypePropertyHdl.cxx create mode 100644 xmloff/source/chart/XMLSymbolTypePropertyHdl.hxx create mode 100644 xmloff/source/chart/XMLTextOrientationHdl.cxx create mode 100644 xmloff/source/chart/XMLTextOrientationHdl.hxx create mode 100644 xmloff/source/chart/contexts.cxx create mode 100644 xmloff/source/chart/contexts.hxx create mode 100644 xmloff/source/chart/transporttypes.cxx create mode 100644 xmloff/source/chart/transporttypes.hxx create mode 100644 xmloff/source/core/DocumentSettingsContext.cxx create mode 100644 xmloff/source/core/DomBuilderContext.cxx create mode 100644 xmloff/source/core/DomExport.cxx create mode 100644 xmloff/source/core/ProgressBarHelper.cxx create mode 100644 xmloff/source/core/PropertySetMerger.cxx create mode 100644 xmloff/source/core/RDFaExportHelper.cxx create mode 100644 xmloff/source/core/RDFaImportHelper.cxx create mode 100644 xmloff/source/core/SettingsExportHelper.cxx create mode 100644 xmloff/source/core/SvXMLAttr.cxx create mode 100644 xmloff/source/core/SvXMLAttr.hxx create mode 100644 xmloff/source/core/SvXMLAttrCollection.cxx create mode 100644 xmloff/source/core/SvXMLAttrCollection.hxx create mode 100644 xmloff/source/core/XMLBase64Export.cxx create mode 100644 xmloff/source/core/XMLBase64ImportContext.cxx create mode 100644 xmloff/source/core/XMLBasicExportFilter.cxx create mode 100644 xmloff/source/core/XMLEmbeddedObjectExportFilter.cxx create mode 100644 xmloff/source/core/XMLEmbeddedObjectImportContext.cxx create mode 100644 xmloff/source/core/attrlist.cxx create mode 100644 xmloff/source/core/fasttokenhandler.cxx create mode 100644 xmloff/source/core/i18nmap.cxx create mode 100644 xmloff/source/core/namespacemap.cxx create mode 100644 xmloff/source/core/unoatrcn.cxx create mode 100644 xmloff/source/core/unointerfacetouniqueidentifiermapper.cxx create mode 100644 xmloff/source/core/xmlcnimp.cxx create mode 100644 xmloff/source/core/xmlenums.hxx create mode 100644 xmloff/source/core/xmlerror.cxx create mode 100644 xmloff/source/core/xmlexp.cxx create mode 100644 xmloff/source/core/xmlictxt.cxx create mode 100644 xmloff/source/core/xmlimp.cxx create mode 100644 xmloff/source/core/xmlmultiimagehelper.cxx create mode 100644 xmloff/source/core/xmltkmap.cxx create mode 100644 xmloff/source/core/xmltoken.cxx create mode 100644 xmloff/source/core/xmluconv.cxx create mode 100644 xmloff/source/draw/EnhancedCustomShapeToken.cxx create mode 100644 xmloff/source/draw/QRCodeContext.cxx create mode 100644 xmloff/source/draw/QRCodeContext.hxx create mode 100644 xmloff/source/draw/SignatureLineContext.cxx create mode 100644 xmloff/source/draw/SignatureLineContext.hxx create mode 100644 xmloff/source/draw/XMLGraphicsDefaultStyle.cxx create mode 100644 xmloff/source/draw/XMLImageMapContext.cxx create mode 100644 xmloff/source/draw/XMLImageMapExport.cxx create mode 100644 xmloff/source/draw/XMLNumberStyles.cxx create mode 100644 xmloff/source/draw/XMLNumberStylesExport.hxx create mode 100644 xmloff/source/draw/XMLReplacementImageContext.cxx create mode 100644 xmloff/source/draw/XMLShapePropertySetContext.cxx create mode 100644 xmloff/source/draw/XMLShapeStyleContext.cxx create mode 100644 xmloff/source/draw/animationexport.cxx create mode 100644 xmloff/source/draw/animationimport.cxx create mode 100644 xmloff/source/draw/animexp.cxx create mode 100644 xmloff/source/draw/animimp.cxx create mode 100644 xmloff/source/draw/descriptionimp.cxx create mode 100644 xmloff/source/draw/descriptionimp.hxx create mode 100644 xmloff/source/draw/eventimp.cxx create mode 100644 xmloff/source/draw/eventimp.hxx create mode 100644 xmloff/source/draw/layerexp.cxx create mode 100644 xmloff/source/draw/layerexp.hxx create mode 100644 xmloff/source/draw/layerimp.cxx create mode 100644 xmloff/source/draw/layerimp.hxx create mode 100644 xmloff/source/draw/numithdl.cxx create mode 100644 xmloff/source/draw/numithdl.hxx create mode 100644 xmloff/source/draw/propimp0.cxx create mode 100644 xmloff/source/draw/sdpropls.cxx create mode 100644 xmloff/source/draw/sdpropls.hxx create mode 100644 xmloff/source/draw/sdxmlexp.cxx create mode 100644 xmloff/source/draw/sdxmlexp_impl.hxx create mode 100644 xmloff/source/draw/sdxmlimp.cxx create mode 100644 xmloff/source/draw/sdxmlimp_impl.hxx create mode 100644 xmloff/source/draw/shapeexport.cxx create mode 100644 xmloff/source/draw/shapeimport.cxx create mode 100644 xmloff/source/draw/xexptran.cxx create mode 100644 xmloff/source/draw/ximp3dobject.cxx create mode 100644 xmloff/source/draw/ximp3dobject.hxx create mode 100644 xmloff/source/draw/ximp3dscene.cxx create mode 100644 xmloff/source/draw/ximp3dscene.hxx create mode 100644 xmloff/source/draw/ximpbody.cxx create mode 100644 xmloff/source/draw/ximpbody.hxx create mode 100644 xmloff/source/draw/ximpcustomshape.cxx create mode 100644 xmloff/source/draw/ximpcustomshape.hxx create mode 100644 xmloff/source/draw/ximpgrp.cxx create mode 100644 xmloff/source/draw/ximpgrp.hxx create mode 100644 xmloff/source/draw/ximplink.cxx create mode 100644 xmloff/source/draw/ximplink.hxx create mode 100644 xmloff/source/draw/ximpnote.cxx create mode 100644 xmloff/source/draw/ximpnote.hxx create mode 100644 xmloff/source/draw/ximppage.cxx create mode 100644 xmloff/source/draw/ximppage.hxx create mode 100644 xmloff/source/draw/ximpshap.cxx create mode 100644 xmloff/source/draw/ximpshap.hxx create mode 100644 xmloff/source/draw/ximpshow.cxx create mode 100644 xmloff/source/draw/ximpshow.hxx create mode 100644 xmloff/source/draw/ximpstyl.cxx create mode 100644 xmloff/source/draw/ximpstyl.hxx create mode 100644 xmloff/source/forms/callbacks.hxx create mode 100644 xmloff/source/forms/controlelement.cxx create mode 100644 xmloff/source/forms/controlelement.hxx create mode 100644 xmloff/source/forms/controlpropertyhdl.cxx create mode 100644 xmloff/source/forms/controlpropertymap.cxx create mode 100644 xmloff/source/forms/controlpropertymap.hxx create mode 100644 xmloff/source/forms/elementexport.cxx create mode 100644 xmloff/source/forms/elementexport.hxx create mode 100644 xmloff/source/forms/elementimport.cxx create mode 100644 xmloff/source/forms/elementimport.hxx create mode 100644 xmloff/source/forms/eventexport.cxx create mode 100644 xmloff/source/forms/eventexport.hxx create mode 100644 xmloff/source/forms/eventimport.cxx create mode 100644 xmloff/source/forms/eventimport.hxx create mode 100644 xmloff/source/forms/formattributes.cxx create mode 100644 xmloff/source/forms/formattributes.hxx create mode 100644 xmloff/source/forms/formcellbinding.cxx create mode 100644 xmloff/source/forms/formcellbinding.hxx create mode 100644 xmloff/source/forms/formenums.cxx create mode 100644 xmloff/source/forms/formenums.hxx create mode 100644 xmloff/source/forms/formevents.cxx create mode 100644 xmloff/source/forms/formevents.hxx create mode 100644 xmloff/source/forms/formlayerexport.cxx create mode 100644 xmloff/source/forms/formlayerimport.cxx create mode 100644 xmloff/source/forms/gridcolumnproptranslator.cxx create mode 100644 xmloff/source/forms/gridcolumnproptranslator.hxx create mode 100644 xmloff/source/forms/handler/form_handler_factory.cxx create mode 100644 xmloff/source/forms/handler/vcl_date_handler.cxx create mode 100644 xmloff/source/forms/handler/vcl_date_handler.hxx create mode 100644 xmloff/source/forms/handler/vcl_time_handler.cxx create mode 100644 xmloff/source/forms/handler/vcl_time_handler.hxx create mode 100644 xmloff/source/forms/layerexport.cxx create mode 100644 xmloff/source/forms/layerexport.hxx create mode 100644 xmloff/source/forms/layerimport.cxx create mode 100644 xmloff/source/forms/layerimport.hxx create mode 100644 xmloff/source/forms/logging.cxx create mode 100644 xmloff/source/forms/logging.hxx create mode 100644 xmloff/source/forms/officeforms.cxx create mode 100644 xmloff/source/forms/officeforms.hxx create mode 100644 xmloff/source/forms/property_description.hxx create mode 100644 xmloff/source/forms/property_meta_data.cxx create mode 100644 xmloff/source/forms/property_meta_data.hxx create mode 100644 xmloff/source/forms/propertyexport.cxx create mode 100644 xmloff/source/forms/propertyexport.hxx create mode 100644 xmloff/source/forms/propertyimport.cxx create mode 100644 xmloff/source/forms/propertyimport.hxx create mode 100644 xmloff/source/forms/strings.hxx create mode 100644 xmloff/source/forms/valueproperties.cxx create mode 100644 xmloff/source/forms/valueproperties.hxx create mode 100644 xmloff/source/meta/MetaExportComponent.cxx create mode 100644 xmloff/source/meta/MetaImportComponent.cxx create mode 100644 xmloff/source/meta/xmlmetae.cxx create mode 100644 xmloff/source/meta/xmlmetai.cxx create mode 100644 xmloff/source/meta/xmlversion.cxx create mode 100644 xmloff/source/script/XMLEventExport.cxx create mode 100644 xmloff/source/script/XMLEventImportHelper.cxx create mode 100644 xmloff/source/script/XMLEventsImportContext.cxx create mode 100644 xmloff/source/script/XMLScriptContextFactory.cxx create mode 100644 xmloff/source/script/XMLScriptExportHandler.cxx create mode 100644 xmloff/source/script/XMLStarBasicContextFactory.cxx create mode 100644 xmloff/source/script/XMLStarBasicExportHandler.cxx create mode 100644 xmloff/source/script/xmlbasicscript.cxx create mode 100644 xmloff/source/script/xmlbasicscript.hxx create mode 100644 xmloff/source/script/xmlscripti.cxx create mode 100644 xmloff/source/style/AttributeContainerHandler.cxx create mode 100644 xmloff/source/style/DashStyle.cxx create mode 100644 xmloff/source/style/DrawAspectHdl.cxx create mode 100644 xmloff/source/style/DrawAspectHdl.hxx create mode 100644 xmloff/source/style/EnumPropertyHdl.cxx create mode 100644 xmloff/source/style/FillStyleContext.cxx create mode 100644 xmloff/source/style/FillStyleContext.hxx create mode 100644 xmloff/source/style/GradientStyle.cxx create mode 100644 xmloff/source/style/HatchStyle.cxx create mode 100644 xmloff/source/style/ImageStyle.cxx create mode 100644 xmloff/source/style/MarkerStyle.cxx create mode 100644 xmloff/source/style/MultiPropertySetHelper.cxx create mode 100644 xmloff/source/style/NamedBoolPropertyHdl.cxx create mode 100644 xmloff/source/style/PageHeaderFooterContext.cxx create mode 100644 xmloff/source/style/PageHeaderFooterContext.hxx create mode 100644 xmloff/source/style/PageMasterExportPropMapper.cxx create mode 100644 xmloff/source/style/PageMasterExportPropMapper.hxx create mode 100644 xmloff/source/style/PageMasterImportContext.cxx create mode 100644 xmloff/source/style/PageMasterImportPropMapper.cxx create mode 100644 xmloff/source/style/PageMasterImportPropMapper.hxx create mode 100644 xmloff/source/style/PageMasterPropHdl.cxx create mode 100644 xmloff/source/style/PageMasterPropHdl.hxx create mode 100644 xmloff/source/style/PageMasterPropHdlFactory.cxx create mode 100644 xmloff/source/style/PageMasterPropMapper.cxx create mode 100644 xmloff/source/style/PageMasterStyleMap.cxx create mode 100644 xmloff/source/style/PagePropertySetContext.cxx create mode 100644 xmloff/source/style/PagePropertySetContext.hxx create mode 100644 xmloff/source/style/SinglePropertySetInfoCache.cxx create mode 100644 xmloff/source/style/StyleMap.cxx create mode 100644 xmloff/source/style/TransGradientStyle.cxx create mode 100644 xmloff/source/style/WordWrapPropertyHdl.cxx create mode 100644 xmloff/source/style/XMLBackgroundImageContext.cxx create mode 100644 xmloff/source/style/XMLBackgroundImageExport.cxx create mode 100644 xmloff/source/style/XMLBitmapLogicalSizePropertyHandler.cxx create mode 100644 xmloff/source/style/XMLBitmapRepeatOffsetPropertyHandler.cxx create mode 100644 xmloff/source/style/XMLClipPropertyHandler.cxx create mode 100644 xmloff/source/style/XMLConstantsPropertyHandler.cxx create mode 100644 xmloff/source/style/XMLElementPropertyContext.cxx create mode 100644 xmloff/source/style/XMLFillBitmapSizePropertyHandler.cxx create mode 100644 xmloff/source/style/XMLFontAutoStylePool.cxx create mode 100644 xmloff/source/style/XMLFontStylesContext.cxx create mode 100644 xmloff/source/style/XMLFontStylesContext_impl.hxx create mode 100644 xmloff/source/style/XMLFootnoteSeparatorExport.cxx create mode 100644 xmloff/source/style/XMLFootnoteSeparatorExport.hxx create mode 100644 xmloff/source/style/XMLFootnoteSeparatorImport.cxx create mode 100644 xmloff/source/style/XMLFootnoteSeparatorImport.hxx create mode 100644 xmloff/source/style/XMLIsPercentagePropertyHandler.cxx create mode 100644 xmloff/source/style/XMLPageExport.cxx create mode 100644 xmloff/source/style/XMLPercentOrMeasurePropertyHandler.cxx create mode 100644 xmloff/source/style/XMLRectangleMembersHandler.cxx create mode 100644 xmloff/source/style/XMLRtlGutterPropertyHandler.cxx create mode 100644 xmloff/source/style/adjushdl.cxx create mode 100644 xmloff/source/style/adjushdl.hxx create mode 100644 xmloff/source/style/backhdl.cxx create mode 100644 xmloff/source/style/backhdl.hxx create mode 100644 xmloff/source/style/bordrhdl.cxx create mode 100644 xmloff/source/style/bordrhdl.hxx create mode 100644 xmloff/source/style/breakhdl.cxx create mode 100644 xmloff/source/style/breakhdl.hxx create mode 100644 xmloff/source/style/cdouthdl.cxx create mode 100644 xmloff/source/style/cdouthdl.hxx create mode 100644 xmloff/source/style/chrhghdl.cxx create mode 100644 xmloff/source/style/chrhghdl.hxx create mode 100644 xmloff/source/style/chrlohdl.cxx create mode 100644 xmloff/source/style/chrlohdl.hxx create mode 100644 xmloff/source/style/csmaphdl.cxx create mode 100644 xmloff/source/style/csmaphdl.hxx create mode 100644 xmloff/source/style/durationhdl.cxx create mode 100644 xmloff/source/style/durationhdl.hxx create mode 100644 xmloff/source/style/escphdl.cxx create mode 100644 xmloff/source/style/escphdl.hxx create mode 100644 xmloff/source/style/fonthdl.cxx create mode 100644 xmloff/source/style/fonthdl.hxx create mode 100644 xmloff/source/style/impastpl.cxx create mode 100644 xmloff/source/style/impastpl.hxx create mode 100644 xmloff/source/style/kernihdl.cxx create mode 100644 xmloff/source/style/kernihdl.hxx create mode 100644 xmloff/source/style/lspachdl.cxx create mode 100644 xmloff/source/style/lspachdl.hxx create mode 100644 xmloff/source/style/numehelp.cxx create mode 100644 xmloff/source/style/opaquhdl.cxx create mode 100644 xmloff/source/style/opaquhdl.hxx create mode 100644 xmloff/source/style/postuhdl.cxx create mode 100644 xmloff/source/style/postuhdl.hxx create mode 100644 xmloff/source/style/prhdlfac.cxx create mode 100644 xmloff/source/style/prstylecond.cxx create mode 100644 xmloff/source/style/prstylei.cxx create mode 100644 xmloff/source/style/shadwhdl.cxx create mode 100644 xmloff/source/style/shadwhdl.hxx create mode 100644 xmloff/source/style/shdwdhdl.cxx create mode 100644 xmloff/source/style/shdwdhdl.hxx create mode 100644 xmloff/source/style/styleexp.cxx create mode 100644 xmloff/source/style/tabsthdl.cxx create mode 100644 xmloff/source/style/tabsthdl.hxx create mode 100644 xmloff/source/style/undlihdl.cxx create mode 100644 xmloff/source/style/undlihdl.hxx create mode 100644 xmloff/source/style/weighhdl.cxx create mode 100644 xmloff/source/style/weighhdl.hxx create mode 100644 xmloff/source/style/xmlaustp.cxx create mode 100644 xmloff/source/style/xmlbahdl.cxx create mode 100644 xmloff/source/style/xmlbahdl.hxx create mode 100644 xmloff/source/style/xmlexppr.cxx create mode 100644 xmloff/source/style/xmlimppr.cxx create mode 100644 xmloff/source/style/xmlnume.cxx create mode 100644 xmloff/source/style/xmlnumfe.cxx create mode 100644 xmloff/source/style/xmlnumfi.cxx create mode 100644 xmloff/source/style/xmlnumi.cxx create mode 100644 xmloff/source/style/xmlprcon.cxx create mode 100644 xmloff/source/style/xmlprhdl.cxx create mode 100644 xmloff/source/style/xmlprmap.cxx create mode 100644 xmloff/source/style/xmlstyle.cxx create mode 100644 xmloff/source/style/xmltabe.cxx create mode 100644 xmloff/source/style/xmltabi.cxx create mode 100644 xmloff/source/table/XMLTableExport.cxx create mode 100644 xmloff/source/table/XMLTableImport.cxx create mode 100644 xmloff/source/table/table.hxx create mode 100644 xmloff/source/text/XMLAnchorTypePropHdl.hxx create mode 100644 xmloff/source/text/XMLAutoMarkFileContext.cxx create mode 100644 xmloff/source/text/XMLAutoMarkFileContext.hxx create mode 100644 xmloff/source/text/XMLAutoTextContainerEventImport.cxx create mode 100644 xmloff/source/text/XMLAutoTextContainerEventImport.hxx create mode 100644 xmloff/source/text/XMLAutoTextEventExport.cxx create mode 100644 xmloff/source/text/XMLAutoTextEventExport.hxx create mode 100644 xmloff/source/text/XMLAutoTextEventImport.cxx create mode 100644 xmloff/source/text/XMLAutoTextEventImport.hxx create mode 100644 xmloff/source/text/XMLCalculationSettingsContext.cxx create mode 100644 xmloff/source/text/XMLCalculationSettingsContext.hxx create mode 100644 xmloff/source/text/XMLChangeElementImportContext.cxx create mode 100644 xmloff/source/text/XMLChangeElementImportContext.hxx create mode 100644 xmloff/source/text/XMLChangeImportContext.cxx create mode 100644 xmloff/source/text/XMLChangeImportContext.hxx create mode 100644 xmloff/source/text/XMLChangeInfoContext.cxx create mode 100644 xmloff/source/text/XMLChangeInfoContext.hxx create mode 100644 xmloff/source/text/XMLChangedRegionImportContext.cxx create mode 100644 xmloff/source/text/XMLChangedRegionImportContext.hxx create mode 100644 xmloff/source/text/XMLFootnoteBodyImportContext.cxx create mode 100644 xmloff/source/text/XMLFootnoteBodyImportContext.hxx create mode 100644 xmloff/source/text/XMLFootnoteConfigurationImportContext.cxx create mode 100644 xmloff/source/text/XMLFootnoteImportContext.cxx create mode 100644 xmloff/source/text/XMLFootnoteImportContext.hxx create mode 100644 xmloff/source/text/XMLIndexAlphabeticalSourceContext.cxx create mode 100644 xmloff/source/text/XMLIndexAlphabeticalSourceContext.hxx create mode 100644 xmloff/source/text/XMLIndexBibliographyConfigurationContext.cxx create mode 100644 xmloff/source/text/XMLIndexBibliographyEntryContext.cxx create mode 100644 xmloff/source/text/XMLIndexBibliographyEntryContext.hxx create mode 100644 xmloff/source/text/XMLIndexBibliographySourceContext.cxx create mode 100644 xmloff/source/text/XMLIndexBibliographySourceContext.hxx create mode 100644 xmloff/source/text/XMLIndexBodyContext.cxx create mode 100644 xmloff/source/text/XMLIndexBodyContext.hxx create mode 100644 xmloff/source/text/XMLIndexChapterInfoEntryContext.cxx create mode 100644 xmloff/source/text/XMLIndexChapterInfoEntryContext.hxx create mode 100644 xmloff/source/text/XMLIndexIllustrationSourceContext.cxx create mode 100644 xmloff/source/text/XMLIndexIllustrationSourceContext.hxx create mode 100644 xmloff/source/text/XMLIndexMarkExport.cxx create mode 100644 xmloff/source/text/XMLIndexMarkExport.hxx create mode 100644 xmloff/source/text/XMLIndexObjectSourceContext.cxx create mode 100644 xmloff/source/text/XMLIndexObjectSourceContext.hxx create mode 100644 xmloff/source/text/XMLIndexSimpleEntryContext.cxx create mode 100644 xmloff/source/text/XMLIndexSimpleEntryContext.hxx create mode 100644 xmloff/source/text/XMLIndexSourceBaseContext.cxx create mode 100644 xmloff/source/text/XMLIndexSourceBaseContext.hxx create mode 100644 xmloff/source/text/XMLIndexSpanEntryContext.cxx create mode 100644 xmloff/source/text/XMLIndexSpanEntryContext.hxx create mode 100644 xmloff/source/text/XMLIndexTOCContext.cxx create mode 100644 xmloff/source/text/XMLIndexTOCContext.hxx create mode 100644 xmloff/source/text/XMLIndexTOCSourceContext.cxx create mode 100644 xmloff/source/text/XMLIndexTOCSourceContext.hxx create mode 100644 xmloff/source/text/XMLIndexTOCStylesContext.cxx create mode 100644 xmloff/source/text/XMLIndexTOCStylesContext.hxx create mode 100644 xmloff/source/text/XMLIndexTabStopEntryContext.cxx create mode 100644 xmloff/source/text/XMLIndexTabStopEntryContext.hxx create mode 100644 xmloff/source/text/XMLIndexTableSourceContext.cxx create mode 100644 xmloff/source/text/XMLIndexTableSourceContext.hxx create mode 100644 xmloff/source/text/XMLIndexTemplateContext.cxx create mode 100644 xmloff/source/text/XMLIndexTemplateContext.hxx create mode 100644 xmloff/source/text/XMLIndexTitleTemplateContext.cxx create mode 100644 xmloff/source/text/XMLIndexTitleTemplateContext.hxx create mode 100644 xmloff/source/text/XMLIndexUserSourceContext.cxx create mode 100644 xmloff/source/text/XMLIndexUserSourceContext.hxx create mode 100644 xmloff/source/text/XMLLineNumberingExport.cxx create mode 100644 xmloff/source/text/XMLLineNumberingExport.hxx create mode 100644 xmloff/source/text/XMLLineNumberingImportContext.cxx create mode 100644 xmloff/source/text/XMLLineNumberingSeparatorImportContext.cxx create mode 100644 xmloff/source/text/XMLLineNumberingSeparatorImportContext.hxx create mode 100644 xmloff/source/text/XMLPropertyBackpatcher.cxx create mode 100644 xmloff/source/text/XMLPropertyBackpatcher.hxx create mode 100644 xmloff/source/text/XMLRedlineExport.cxx create mode 100644 xmloff/source/text/XMLRedlineExport.hxx create mode 100644 xmloff/source/text/XMLSectionExport.cxx create mode 100644 xmloff/source/text/XMLSectionExport.hxx create mode 100644 xmloff/source/text/XMLSectionFootnoteConfigExport.cxx create mode 100644 xmloff/source/text/XMLSectionFootnoteConfigExport.hxx create mode 100644 xmloff/source/text/XMLSectionFootnoteConfigImport.cxx create mode 100644 xmloff/source/text/XMLSectionFootnoteConfigImport.hxx create mode 100644 xmloff/source/text/XMLSectionImportContext.cxx create mode 100644 xmloff/source/text/XMLSectionImportContext.hxx create mode 100644 xmloff/source/text/XMLSectionSourceDDEImportContext.cxx create mode 100644 xmloff/source/text/XMLSectionSourceDDEImportContext.hxx create mode 100644 xmloff/source/text/XMLSectionSourceImportContext.cxx create mode 100644 xmloff/source/text/XMLSectionSourceImportContext.hxx create mode 100644 xmloff/source/text/XMLStringBufferImportContext.cxx create mode 100644 xmloff/source/text/XMLTextCharStyleNamesElementExport.cxx create mode 100644 xmloff/source/text/XMLTextCharStyleNamesElementExport.hxx create mode 100644 xmloff/source/text/XMLTextColumnsContext.cxx create mode 100644 xmloff/source/text/XMLTextColumnsExport.cxx create mode 100644 xmloff/source/text/XMLTextFrameContext.cxx create mode 100644 xmloff/source/text/XMLTextFrameContext.hxx create mode 100644 xmloff/source/text/XMLTextFrameHyperlinkContext.cxx create mode 100644 xmloff/source/text/XMLTextFrameHyperlinkContext.hxx create mode 100644 xmloff/source/text/XMLTextHeaderFooterContext.cxx create mode 100644 xmloff/source/text/XMLTextListAutoStylePool.cxx create mode 100644 xmloff/source/text/XMLTextListBlockContext.cxx create mode 100644 xmloff/source/text/XMLTextListBlockContext.hxx create mode 100644 xmloff/source/text/XMLTextListItemContext.cxx create mode 100644 xmloff/source/text/XMLTextListItemContext.hxx create mode 100644 xmloff/source/text/XMLTextMarkImportContext.cxx create mode 100644 xmloff/source/text/XMLTextMarkImportContext.hxx create mode 100644 xmloff/source/text/XMLTextMasterPageContext.cxx create mode 100644 xmloff/source/text/XMLTextMasterPageExport.cxx create mode 100644 xmloff/source/text/XMLTextMasterStylesContext.cxx create mode 100644 xmloff/source/text/XMLTextNumRuleInfo.cxx create mode 100644 xmloff/source/text/XMLTextNumRuleInfo.hxx create mode 100644 xmloff/source/text/XMLTextPropertySetContext.cxx create mode 100644 xmloff/source/text/XMLTextPropertySetContext.hxx create mode 100644 xmloff/source/text/XMLTextShapeImportHelper.cxx create mode 100644 xmloff/source/text/XMLTextShapeStyleContext.cxx create mode 100644 xmloff/source/text/XMLTextTableContext.cxx create mode 100644 xmloff/source/text/XMLTrackedChangesImportContext.cxx create mode 100644 xmloff/source/text/XMLTrackedChangesImportContext.hxx create mode 100644 xmloff/source/text/txtdrope.cxx create mode 100644 xmloff/source/text/txtdrope.hxx create mode 100644 xmloff/source/text/txtdropi.cxx create mode 100644 xmloff/source/text/txtdropi.hxx create mode 100644 xmloff/source/text/txtexppr.cxx create mode 100644 xmloff/source/text/txtexppr.hxx create mode 100644 xmloff/source/text/txtflde.cxx create mode 100644 xmloff/source/text/txtfldi.cxx create mode 100644 xmloff/source/text/txtftne.cxx create mode 100644 xmloff/source/text/txtimp.cxx create mode 100644 xmloff/source/text/txtimppr.cxx create mode 100644 xmloff/source/text/txtlists.cxx create mode 100644 xmloff/source/text/txtparae.cxx create mode 100644 xmloff/source/text/txtparai.cxx create mode 100644 xmloff/source/text/txtparai.hxx create mode 100644 xmloff/source/text/txtparaimphint.hxx create mode 100644 xmloff/source/text/txtprhdl.cxx create mode 100644 xmloff/source/text/txtprhdl.hxx create mode 100644 xmloff/source/text/txtprmap.cxx create mode 100644 xmloff/source/text/txtsecte.cxx create mode 100644 xmloff/source/text/txtstyle.cxx create mode 100644 xmloff/source/text/txtstyli.cxx create mode 100644 xmloff/source/text/txtvfldi.cxx create mode 100644 xmloff/source/text/xmlcontentcontrolcontext.cxx create mode 100644 xmloff/source/text/xmlcontentcontrolcontext.hxx create mode 100644 xmloff/source/text/xmllinebreakcontext.cxx create mode 100644 xmloff/source/text/xmllinebreakcontext.hxx create mode 100644 xmloff/source/token/tokens.hxx.head create mode 100644 xmloff/source/token/tokens.hxx.tail create mode 100644 xmloff/source/token/tokens.txt create mode 100644 xmloff/source/transform/ActionMapTypesOASIS.hxx create mode 100644 xmloff/source/transform/ActionMapTypesOOo.hxx create mode 100644 xmloff/source/transform/AttrTransformerAction.hxx create mode 100644 xmloff/source/transform/ChartOASISTContext.cxx create mode 100644 xmloff/source/transform/ChartOASISTContext.hxx create mode 100644 xmloff/source/transform/ChartOOoTContext.cxx create mode 100644 xmloff/source/transform/ChartOOoTContext.hxx create mode 100644 xmloff/source/transform/ChartPlotAreaOASISTContext.cxx create mode 100644 xmloff/source/transform/ChartPlotAreaOASISTContext.hxx create mode 100644 xmloff/source/transform/ChartPlotAreaOOoTContext.cxx create mode 100644 xmloff/source/transform/ChartPlotAreaOOoTContext.hxx create mode 100644 xmloff/source/transform/ControlOASISTContext.cxx create mode 100644 xmloff/source/transform/ControlOASISTContext.hxx create mode 100644 xmloff/source/transform/ControlOOoTContext.cxx create mode 100644 xmloff/source/transform/ControlOOoTContext.hxx create mode 100644 xmloff/source/transform/CreateElemTContext.cxx create mode 100644 xmloff/source/transform/CreateElemTContext.hxx create mode 100644 xmloff/source/transform/DeepTContext.cxx create mode 100644 xmloff/source/transform/DeepTContext.hxx create mode 100644 xmloff/source/transform/DlgOASISTContext.cxx create mode 100644 xmloff/source/transform/DlgOASISTContext.hxx create mode 100644 xmloff/source/transform/DocumentTContext.cxx create mode 100644 xmloff/source/transform/DocumentTContext.hxx create mode 100644 xmloff/source/transform/ElemTransformerAction.hxx create mode 100644 xmloff/source/transform/EventMap.cxx create mode 100644 xmloff/source/transform/EventMap.hxx create mode 100644 xmloff/source/transform/EventOASISTContext.cxx create mode 100644 xmloff/source/transform/EventOASISTContext.hxx create mode 100644 xmloff/source/transform/EventOOoTContext.cxx create mode 100644 xmloff/source/transform/EventOOoTContext.hxx create mode 100644 xmloff/source/transform/FamilyType.hxx create mode 100644 xmloff/source/transform/FlatTContext.cxx create mode 100644 xmloff/source/transform/FlatTContext.hxx create mode 100644 xmloff/source/transform/FormPropOASISTContext.cxx create mode 100644 xmloff/source/transform/FormPropOASISTContext.hxx create mode 100644 xmloff/source/transform/FormPropOOoTContext.cxx create mode 100644 xmloff/source/transform/FormPropOOoTContext.hxx create mode 100644 xmloff/source/transform/FrameOASISTContext.cxx create mode 100644 xmloff/source/transform/FrameOASISTContext.hxx create mode 100644 xmloff/source/transform/FrameOOoTContext.cxx create mode 100644 xmloff/source/transform/FrameOOoTContext.hxx create mode 100644 xmloff/source/transform/IgnoreTContext.cxx create mode 100644 xmloff/source/transform/IgnoreTContext.hxx create mode 100644 xmloff/source/transform/MergeElemTContext.cxx create mode 100644 xmloff/source/transform/MergeElemTContext.hxx create mode 100644 xmloff/source/transform/MetaTContext.cxx create mode 100644 xmloff/source/transform/MetaTContext.hxx create mode 100644 xmloff/source/transform/MutableAttrList.cxx create mode 100644 xmloff/source/transform/MutableAttrList.hxx create mode 100644 xmloff/source/transform/NotesTContext.cxx create mode 100644 xmloff/source/transform/NotesTContext.hxx create mode 100644 xmloff/source/transform/OOo2Oasis.cxx create mode 100644 xmloff/source/transform/OOo2Oasis.hxx create mode 100644 xmloff/source/transform/Oasis2OOo.cxx create mode 100644 xmloff/source/transform/Oasis2OOo.hxx create mode 100644 xmloff/source/transform/PersAttrListTContext.cxx create mode 100644 xmloff/source/transform/PersAttrListTContext.hxx create mode 100644 xmloff/source/transform/PersMixedContentTContext.cxx create mode 100644 xmloff/source/transform/PersMixedContentTContext.hxx create mode 100644 xmloff/source/transform/ProcAddAttrTContext.cxx create mode 100644 xmloff/source/transform/ProcAddAttrTContext.hxx create mode 100644 xmloff/source/transform/ProcAttrTContext.cxx create mode 100644 xmloff/source/transform/ProcAttrTContext.hxx create mode 100644 xmloff/source/transform/PropType.hxx create mode 100644 xmloff/source/transform/PropertyActionsOASIS.cxx create mode 100644 xmloff/source/transform/PropertyActionsOASIS.hxx create mode 100644 xmloff/source/transform/PropertyActionsOOo.cxx create mode 100644 xmloff/source/transform/PropertyActionsOOo.hxx create mode 100644 xmloff/source/transform/RenameElemTContext.cxx create mode 100644 xmloff/source/transform/RenameElemTContext.hxx create mode 100644 xmloff/source/transform/StyleOASISTContext.cxx create mode 100644 xmloff/source/transform/StyleOASISTContext.hxx create mode 100644 xmloff/source/transform/StyleOOoTContext.cxx create mode 100644 xmloff/source/transform/StyleOOoTContext.hxx create mode 100644 xmloff/source/transform/Transformer.hxx create mode 100644 xmloff/source/transform/TransformerAction.hxx create mode 100644 xmloff/source/transform/TransformerActionInit.hxx create mode 100644 xmloff/source/transform/TransformerActions.cxx create mode 100644 xmloff/source/transform/TransformerActions.hxx create mode 100644 xmloff/source/transform/TransformerBase.cxx create mode 100644 xmloff/source/transform/TransformerBase.hxx create mode 100644 xmloff/source/transform/TransformerContext.cxx create mode 100644 xmloff/source/transform/TransformerContext.hxx create mode 100644 xmloff/source/transform/TransformerTokenMap.cxx create mode 100644 xmloff/source/transform/TransformerTokenMap.hxx create mode 100644 xmloff/source/transform/xof.component create mode 100644 xmloff/source/transform/xof.component.chart create mode 100644 xmloff/source/xforms/SchemaContext.cxx create mode 100644 xmloff/source/xforms/SchemaContext.hxx create mode 100644 xmloff/source/xforms/SchemaRestrictionContext.cxx create mode 100644 xmloff/source/xforms/SchemaRestrictionContext.hxx create mode 100644 xmloff/source/xforms/SchemaSimpleTypeContext.cxx create mode 100644 xmloff/source/xforms/SchemaSimpleTypeContext.hxx create mode 100644 xmloff/source/xforms/TokenContext.cxx create mode 100644 xmloff/source/xforms/TokenContext.hxx create mode 100644 xmloff/source/xforms/XFormsBindContext.cxx create mode 100644 xmloff/source/xforms/XFormsBindContext.hxx create mode 100644 xmloff/source/xforms/XFormsInstanceContext.cxx create mode 100644 xmloff/source/xforms/XFormsInstanceContext.hxx create mode 100644 xmloff/source/xforms/XFormsModelContext.cxx create mode 100644 xmloff/source/xforms/XFormsModelContext.hxx create mode 100644 xmloff/source/xforms/XFormsModelExport.hxx create mode 100644 xmloff/source/xforms/XFormsSubmissionContext.cxx create mode 100644 xmloff/source/xforms/XFormsSubmissionContext.hxx create mode 100644 xmloff/source/xforms/xformsapi.cxx create mode 100644 xmloff/source/xforms/xformsapi.hxx create mode 100644 xmloff/source/xforms/xformsexport.cxx create mode 100644 xmloff/source/xforms/xformsimport.cxx (limited to 'xmloff/source') diff --git a/xmloff/source/chart/ColorPropertySet.cxx b/xmloff/source/chart/ColorPropertySet.cxx new file mode 100644 index 000000000..76050be40 --- /dev/null +++ b/xmloff/source/chart/ColorPropertySet.cxx @@ -0,0 +1,156 @@ +/* -*- 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 "ColorPropertySet.hxx" + +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +class lcl_ColorPropertySetInfo : public ::cppu::WeakImplHelper< + XPropertySetInfo > +{ +public: + explicit lcl_ColorPropertySetInfo(); + +protected: + // ____ XPropertySetInfo ____ + virtual Sequence< Property > SAL_CALL getProperties() override; + virtual Property SAL_CALL getPropertyByName( const OUString& aName ) override; + virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override; + +private: + static constexpr OUStringLiteral g_aColorPropName = u"FillColor"; + Property m_aColorProp; +}; + +lcl_ColorPropertySetInfo::lcl_ColorPropertySetInfo() : + m_aColorProp( g_aColorPropName, -1, + cppu::UnoType::get(), 0) +{} + +Sequence< Property > SAL_CALL lcl_ColorPropertySetInfo::getProperties() +{ + + return Sequence< Property >( & m_aColorProp, 1 ); +} + +Property SAL_CALL lcl_ColorPropertySetInfo::getPropertyByName( const OUString& aName ) +{ + if( aName == g_aColorPropName ) + return m_aColorProp; + throw UnknownPropertyException( g_aColorPropName, static_cast< uno::XWeak * >( this )); +} + +sal_Bool SAL_CALL lcl_ColorPropertySetInfo::hasPropertyByName( const OUString& Name ) +{ + return Name == g_aColorPropName; +} + +} // anonymous namespace + +namespace xmloff::chart +{ + +ColorPropertySet::ColorPropertySet( ::Color nColor ) : + m_nColor( nColor ), + m_nDefaultColor( 0x0099ccff ) // blue 8 +{} + +ColorPropertySet::~ColorPropertySet() +{} + +// ____ XPropertySet ____ + +Reference< XPropertySetInfo > SAL_CALL ColorPropertySet::getPropertySetInfo() +{ + if( ! m_xInfo.is()) + m_xInfo.set( new lcl_ColorPropertySetInfo ); + + return m_xInfo; +} + +void SAL_CALL ColorPropertySet::setPropertyValue( const OUString& /* aPropertyName */, const uno::Any& aValue ) +{ + aValue >>= m_nColor; +} + +uno::Any SAL_CALL ColorPropertySet::getPropertyValue( const OUString& /* PropertyName */ ) +{ + return uno::Any( m_nColor ); +} + +void SAL_CALL ColorPropertySet::addPropertyChangeListener( const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* xListener */ ) +{ + OSL_FAIL( "Not Implemented" ); +} + +void SAL_CALL ColorPropertySet::removePropertyChangeListener( const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* aListener */ ) +{ + OSL_FAIL( "Not Implemented" ); +} + +void SAL_CALL ColorPropertySet::addVetoableChangeListener( const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL( "Not Implemented" ); +} + +void SAL_CALL ColorPropertySet::removeVetoableChangeListener( const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ ) +{ + OSL_FAIL( "Not Implemented" ); +} + +// ____ XPropertyState ____ + +PropertyState SAL_CALL ColorPropertySet::getPropertyState( const OUString& /* PropertyName */ ) +{ + return PropertyState_DIRECT_VALUE; +} + +Sequence< PropertyState > SAL_CALL ColorPropertySet::getPropertyStates( const Sequence< OUString >& /* aPropertyName */ ) +{ + PropertyState aState = PropertyState_DIRECT_VALUE; + // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence + return Sequence(&aState, 1); +} + +void SAL_CALL ColorPropertySet::setPropertyToDefault( const OUString& PropertyName ) +{ + if( PropertyName == g_aColorPropName ) + m_nColor = m_nDefaultColor; +} + +uno::Any SAL_CALL ColorPropertySet::getPropertyDefault( const OUString& aPropertyName ) +{ + if( aPropertyName == g_aColorPropName ) + return uno::Any( m_nDefaultColor ); + return uno::Any(); +} + +} // namespace xmloff::chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/ColorPropertySet.hxx b/xmloff/source/chart/ColorPropertySet.hxx new file mode 100644 index 000000000..d5b42e39d --- /dev/null +++ b/xmloff/source/chart/ColorPropertySet.hxx @@ -0,0 +1,82 @@ +/* -*- 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 . + */ +#ifndef XMLOFF_COLORPROPERTYSET_HXX +#define XMLOFF_COLORPROPERTYSET_HXX + +#include +#include + +#include +#include + +namespace xmloff::chart +{ + +class ColorPropertySet : public ::cppu::WeakImplHelper< + css::beans::XPropertySet, + css::beans::XPropertyState > +{ +public: + explicit ColorPropertySet( ::Color nColor ); + virtual ~ColorPropertySet() override; + +protected: + // ____ XPropertySet ____ + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + virtual void SAL_CALL setPropertyValue( + const OUString& aPropertyName, + const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( + const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( + const OUString& aPropertyName, + const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( + const OUString& PropertyName, + const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + // ____ XPropertyState ____ + virtual css::beans::PropertyState SAL_CALL getPropertyState( + const OUString& PropertyName ) override; + virtual css::uno::Sequence< css::beans::PropertyState > SAL_CALL getPropertyStates( + const css::uno::Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( + const OUString& PropertyName ) override; + virtual css::uno::Any SAL_CALL getPropertyDefault( + const OUString& aPropertyName ) override; + +private: + css::uno::Reference< css::beans::XPropertySetInfo > m_xInfo; + static constexpr OUStringLiteral g_aColorPropName = u"FillColor"; + Color m_nColor; + Color m_nDefaultColor; +}; + +} // namespace xmloff::chart + +// XMLOFF_COLORPROPERTYSET_HXX +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/MultiPropertySetHandler.hxx b/xmloff/source/chart/MultiPropertySetHandler.hxx new file mode 100644 index 000000000..d47b942f0 --- /dev/null +++ b/xmloff/source/chart/MultiPropertySetHandler.hxx @@ -0,0 +1,244 @@ +/* -*- 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 +#include +#include + +#include +#include +#include + +/** @descr MultiPropertySetHandler handles the two slightly different + interfaces XPropertySet and XMultiPropertySet for accessing + properties of an object. + + It uses the classes PropertyWrapperBase and the template + PropertyWrapper for a type safe access to single properties. + + The function class OUStringComparison is used by a STL map to + sort the properties by names. +*/ + +/** @descr Base class for the templated property wrappers. + Having a common base class allows to set a variable to the + property's value without explicit knowledge of its type. +*/ +class PropertyWrapperBase +{ +public: + /** @descr Create a class instance and store the given name. + @param rName The name of the property. + */ + explicit PropertyWrapperBase (const OUString & rName) + : msName (rName) + {} + virtual ~PropertyWrapperBase() + {} + + /** @descr Abstract interface of a method for setting a variables + value to that of the property. + */ + virtual void SetValue (const css::uno::Any & rValue) = 0; + + const OUString msName; +}; + +/** @descr For every property type there will be one instantiation of this + template class with its own and type specific version of SetValue. +*/ +template class PropertyWrapper : public PropertyWrapperBase +{ +public: + /** @descr Create a wrapper for a property of type T. + */ + PropertyWrapper (const OUString & rName, T & rValue) + : PropertyWrapperBase (rName), + mrValue (rValue) + {} + + /** descr Set the given value inside an Any to the variable referenced + by the data member. + */ + virtual void SetValue (const css::uno::Any & rValue) override + { + rValue >>= mrValue; + } + +private: + /// Reference to a variable. Its value can be modified by a call to SetValue. + T & mrValue; +}; + +/** @descr Function object for comparing two OUStrings. +*/ +class OUStringComparison +{ +public: + /// Compare two strings. Returns true if the first is before the second. + bool operator() (std::u16string_view a, std::u16string_view b) const + { + return (a.compare (b) < 0); + } +}; + +/** @descr This class lets you get the values from an object that either + supports the interface XPropertySet or XMultiPropertySet. If it + supports both interfaces then XMultiPropertySet is preferred. + + Using it works in three steps. + 1. Create an instance and pass a reference to the object from which to + get the property values. + 2. Make all properties whose values you want to get known to the object + by using the Add method. This creates instances of a template class + that stores the properties name and a reference to the variable in + which to store its value. + 3. Finally call GetProperties to store the properties values into the + variables specified in step 2. This uses either the XPropertySet or + (preferred) the XMultiPropertySet interface. +*/ +class MultiPropertySetHandler +{ +public: + /** @descr Create a handler of the property set of the given + object. + @param xObject A reference to any of the object's interfaces. + not necessarily XPropertySet or XMultiPropertySet. It + is casted later to one of the two of them. + */ + explicit MultiPropertySetHandler (css::uno::Reference< + css::uno::XInterface> const & xObject); + /** @descr Add a property to handle. The type given implicitly by the + reference to a variable is used to create an instance of + the PropertyWrapper template class. + @param sName Name of the property. + @param rValue Reference to a variable whose value is set by the + call to GetProperties to the property's value. + */ + template void Add (const OUString & sName, T& rValue) + { + aPropertyList[sName] = std::make_unique>(sName, rValue); + } + + /** @descr Try to get the values for all properties added with the Add + method. If possible it uses the XMultiPropertySet. If that fails + (i.e. for an UnknownPropertyExcption) or if the interface is not + supported it uses the XPropertySet interface. + @return If none of the two interfaces is supported or using them both + fails then sal_False is returned. Else True is returned. + */ + inline bool GetProperties(); + +private: + /** @descr Try to use the XMultiPropertySet interface to get the property + values. + @param rNameList A precomputed and sorted sequence of OUStrings + containing the properties names. + @return True if values could be derived. + */ + inline bool MultiGet (const css::uno::Sequence< + OUString> & rNameList); + + /** @descr Try to use the XPropertySet interface to get the property + values. + @param rNameList A precomputed and sorted sequence of OUStrings + containing the properties names. + @return True if values could be derived. + */ + inline bool SingleGet (const css::uno::Sequence< + OUString> & rNameList); + + /** @descr STL map that maps from property names to polymorphic instances of + PropertyWrapper. It uses OUStringComparison for sorting + the property names. + */ + ::std::map< OUString, std::unique_ptr, OUStringComparison> aPropertyList; + + /// The object from which to get the property values. + css::uno::Reference< css::uno::XInterface> mxObject; +}; + +MultiPropertySetHandler::MultiPropertySetHandler (css::uno::Reference< + css::uno::XInterface> const & xObject) + : mxObject (xObject) +{ +} + +bool MultiPropertySetHandler::GetProperties() +{ + css::uno::Sequence< OUString> aNameList (aPropertyList.size()); + auto aNameListRange = asNonConstRange(aNameList); + int i = 0; + for (const auto& rProperty : aPropertyList) + aNameListRange[i++] = rProperty.second->msName; + if ( ! MultiGet(aNameList)) + if ( ! SingleGet(aNameList)) + return false; + return true; +} + +bool MultiPropertySetHandler::MultiGet (const css::uno::Sequence< + OUString> & rNameList) +{ + css::uno::Reference< css::beans::XMultiPropertySet> xMultiSet ( + mxObject, css::uno::UNO_QUERY); + if (xMultiSet.is()) + try + { + int i = 0; + css::uno::Sequence< css::uno::Any> aValueList = + xMultiSet->getPropertyValues (rNameList); + for (auto& rProperty : aPropertyList) + rProperty.second->SetValue (aValueList[i++]); + } + catch (const css::beans::UnknownPropertyException&) + { + return false; + } + else + return false; + + return true; +} + +bool MultiPropertySetHandler::SingleGet (const css::uno::Sequence< + OUString> & rNameList) +{ + css::uno::Reference< css::beans::XPropertySet> xSingleSet ( + mxObject, css::uno::UNO_QUERY); + if (xSingleSet.is()) + try + { + int i = 0; + for (auto& rProperty : aPropertyList) + rProperty.second->SetValue (xSingleSet->getPropertyValue (rNameList[i++])); + } + catch (const css::beans::UnknownPropertyException&) + { + return false; + } + else + return false; + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/PropertyMap.hxx b/xmloff/source/chart/PropertyMap.hxx new file mode 100644 index 000000000..f9a3dc4e3 --- /dev/null +++ b/xmloff/source/chart/PropertyMap.hxx @@ -0,0 +1,89 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// custom types +#define XML_SCH_TYPE_AXIS_ARRANGEMENT ( XML_SCH_TYPES_START + 0 ) +#define XML_SCH_TYPE_ERROR_BAR_STYLE ( XML_SCH_TYPES_START + 1 ) +// free +#define XML_SCH_TYPE_SOLID_TYPE ( XML_SCH_TYPES_START + 3 ) +#define XML_SCH_TYPE_ERROR_INDICATOR_UPPER ( XML_SCH_TYPES_START + 4 ) +#define XML_SCH_TYPE_ERROR_INDICATOR_LOWER ( XML_SCH_TYPES_START + 5 ) +#define XML_SCH_TYPE_DATAROWSOURCE ( XML_SCH_TYPES_START + 6 ) +#define XML_SCH_TYPE_TEXT_ORIENTATION ( XML_SCH_TYPES_START + 7 ) +#define XML_SCH_TYPE_INTERPOLATION ( XML_SCH_TYPES_START + 8 ) +#define XML_SCH_TYPE_SYMBOL_TYPE ( XML_SCH_TYPES_START + 9 ) +#define XML_SCH_TYPE_NAMED_SYMBOL ( XML_SCH_TYPES_START + 10 ) +#define XML_SCH_TYPE_LABEL_PLACEMENT_TYPE ( XML_SCH_TYPES_START + 11 ) +#define XML_SCH_TYPE_MISSING_VALUE_TREATMENT ( XML_SCH_TYPES_START + 12 ) +#define XML_SCH_TYPE_AXIS_POSITION ( XML_SCH_TYPES_START + 13 ) +#define XML_SCH_TYPE_AXIS_POSITION_VALUE ( XML_SCH_TYPES_START + 14 ) +#define XML_SCH_TYPE_AXIS_LABEL_POSITION ( XML_SCH_TYPES_START + 15 ) +#define XML_SCH_TYPE_TICK_MARK_POSITION ( XML_SCH_TYPES_START + 16 ) +#define XML_SCH_TYPE_LABEL_BORDER_STYLE ( XML_SCH_TYPES_START + 17 ) +#define XML_SCH_TYPE_LABEL_BORDER_OPACITY ( XML_SCH_TYPES_START + 18 ) +#define XML_SCH_TYPE_LABEL_FILL_STYLE ( XML_SCH_TYPES_START + 19 ) + +// context ids +#define XML_SCH_CONTEXT_USER_SYMBOL ( XML_SCH_CTF_START + 0 ) +#define XML_SCH_CONTEXT_MIN ( XML_SCH_CTF_START + 1 ) +#define XML_SCH_CONTEXT_MAX ( XML_SCH_CTF_START + 2 ) +#define XML_SCH_CONTEXT_STEP_MAIN ( XML_SCH_CTF_START + 3 ) +#define XML_SCH_CONTEXT_STEP_HELP_COUNT ( XML_SCH_CTF_START + 4 ) +#define XML_SCH_CONTEXT_ORIGIN ( XML_SCH_CTF_START + 5 ) +#define XML_SCH_CONTEXT_LOGARITHMIC ( XML_SCH_CTF_START + 6 ) +#define XML_SCH_CONTEXT_STOCK_WITH_VOLUME ( XML_SCH_CTF_START + 7 ) +#define XML_SCH_CONTEXT_LINES_USED ( XML_SCH_CTF_START + 8 ) + +#define XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_INNER ( XML_SCH_CTF_START + 10 ) +#define XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_OUTER ( XML_SCH_CTF_START + 11 ) +#define XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_INNER ( XML_SCH_CTF_START + 12 ) +#define XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_OUTER ( XML_SCH_CTF_START + 13 ) +#define XML_SCH_CONTEXT_SPECIAL_TEXT_ROTATION ( XML_SCH_CTF_START + 14 ) +#define XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_NUMBER ( XML_SCH_CTF_START + 15 ) +#define XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_TEXT ( XML_SCH_CTF_START + 16 ) +#define XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SYMBOL ( XML_SCH_CTF_START + 17 ) +#define XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT ( XML_SCH_CTF_START + 18 ) +#define XML_SCH_CONTEXT_SPECIAL_DATA_ROW_SOURCE ( XML_SCH_CTF_START + 19 ) +#define XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH ( XML_SCH_CTF_START + 20 ) +#define XML_SCH_CONTEXT_SPECIAL_SYMBOL_HEIGHT ( XML_SCH_CTF_START + 21 ) +#define XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE_NAME ( XML_SCH_CTF_START + 22 ) +#define XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE ( XML_SCH_CTF_START + 23 ) +#define XML_SCH_CONTEXT_SPECIAL_LABEL_SEPARATOR ( XML_SCH_CTF_START + 24 ) +#define XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE ( XML_SCH_CTF_START + 25 ) +#define XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE ( XML_SCH_CTF_START + 26 ) +#define XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SERIES ( XML_SCH_CTF_START + 27 ) +#define XML_SCH_CONTEXT_SPECIAL_MOVING_AVERAGE_TYPE ( XML_SCH_CTF_START + 28 ) + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/PropertyMaps.cxx b/xmloff/source/chart/PropertyMaps.cxx new file mode 100644 index 000000000..e40ac207a --- /dev/null +++ b/xmloff/source/chart/PropertyMaps.cxx @@ -0,0 +1,1040 @@ +/* -*- 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 "PropertyMap.hxx" + +#include + +#include "SchXMLTools.hxx" +#include +#include "XMLErrorIndicatorPropertyHdl.hxx" +#include "XMLErrorBarStylePropertyHdl.hxx" +#include "XMLTextOrientationHdl.hxx" +#include "XMLSymbolTypePropertyHdl.hxx" +#include "XMLAxisPositionPropertyHdl.hxx" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SCH_XML_SETFLAG( status, flag ) (status)|= (flag) +#define SCH_XML_UNSETFLAG( status, flag ) (status) = ((status) | (flag)) - (flag) + +using namespace com::sun::star; +using namespace ::xmloff::token; +using namespace css::chart2; + + +#define MAP_FULL( ApiName, NameSpace, XMLTokenName, XMLType, ContextId, EarliestODFVersionForExport ) { ApiName, XML_NAMESPACE_##NameSpace, xmloff::token::XMLTokenName, XMLType|XML_TYPE_PROP_CHART, ContextId, EarliestODFVersionForExport, false } +#define MAP_ENTRY( a, ns, nm, t ) { a, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_010, false } +#define MAP_ENTRY_ODF12( a, ns, nm, t ) { a, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_012, false } +#define MAP_ENTRY_ODF13( a, ns, nm, t ) { a, ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_013, false } +#define MAP_ENTRY_ODF_EXT( a, ns, nm, t ) { a, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false } +#define MAP_ENTRY_ODF_EXT_IMPORT( a, ns, nm, t ) { a, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, true } +#define MAP_CONTEXT( a, ns, nm, t, c ) { a, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART, c, SvtSaveOptions::ODFSVER_010, false } +#define MAP_SPECIAL( a, ns, nm, t, c ) { a, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART | MID_FLAG_SPECIAL_ITEM, c, SvtSaveOptions::ODFSVER_010, false } +#define MAP_SPECIAL_ODF12( a, ns, nm, t, c ) { a, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART | MID_FLAG_SPECIAL_ITEM, c, SvtSaveOptions::ODFSVER_012, false } +#define MAP_SPECIAL_ODF13( a, ns, nm, t, c ) { a, XML_NAMESPACE_##ns, xmloff::token::nm, t|XML_TYPE_PROP_CHART | MID_FLAG_SPECIAL_ITEM, c, SvtSaveOptions::ODFSVER_013, false } +#define MAP_ENTRY_END { nullptr,0,xmloff::token::XML_TOKEN_INVALID,0,0,SvtSaveOptions::ODFSVER_010, false } + +// PropertyMap for Chart properties drawing- and +// textproperties are added later using the chaining +// mechanism + +const XMLPropertyMapEntry aXMLChartPropMap[] = +{ + // chart subtypes + MAP_ENTRY( "UpDown", CHART, XML_JAPANESE_CANDLE_STICK, XML_TYPE_BOOL ), // formerly XML_STOCK_UPDOWN_BARS + MAP_CONTEXT( "Volume", CHART, XML_STOCK_WITH_VOLUME, XML_TYPE_BOOL, XML_SCH_CONTEXT_STOCK_WITH_VOLUME ), + MAP_ENTRY( "Dim3D", CHART, XML_THREE_DIMENSIONAL, XML_TYPE_BOOL ), + MAP_ENTRY( "Deep", CHART, XML_DEEP, XML_TYPE_BOOL ), + MAP_ENTRY( "Lines", CHART, XML_LINES, XML_TYPE_BOOL ), + MAP_ENTRY( "Percent", CHART, XML_PERCENTAGE, XML_TYPE_BOOL ), + MAP_ENTRY( "SolidType", CHART, XML_SOLID_TYPE, XML_SCH_TYPE_SOLID_TYPE ), + // ODF 1.3 OFFICE-3662 added values + MAP_ENTRY( "SplineType", CHART, XML_INTERPOLATION, XML_SCH_TYPE_INTERPOLATION ), + MAP_ENTRY( "Stacked", CHART, XML_STACKED, XML_TYPE_BOOL ), + // type: "none", "automatic", "named-symbol" or "image" + MAP_ENTRY( "SymbolType", CHART, XML_SYMBOL_TYPE, XML_SCH_TYPE_SYMBOL_TYPE | MID_FLAG_MULTI_PROPERTY ), + // if type=="named-symbol" => name of symbol (square, diamond, ...) + MAP_ENTRY( "SymbolType", CHART, XML_SYMBOL_NAME, XML_SCH_TYPE_NAMED_SYMBOL | MID_FLAG_MULTI_PROPERTY ), + // if type=="image" => an xlink:href element with a linked (package) URI + MAP_SPECIAL( "SymbolBitmap", CHART, XML_SYMBOL_IMAGE, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE ), + MAP_SPECIAL( "SymbolSize", CHART, XML_SYMBOL_WIDTH, XML_TYPE_MEASURE | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH ), + MAP_SPECIAL( "SymbolSize", CHART, XML_SYMBOL_HEIGHT, XML_TYPE_MEASURE | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_SYMBOL_HEIGHT ), + MAP_ENTRY( "Vertical", CHART, XML_VERTICAL, XML_TYPE_BOOL ), + // #i32368# property should no longer be used as XML-property (in OASIS + // format), but is still ex-/imported for compatibility with the OOo file format + MAP_CONTEXT( "NumberOfLines", CHART, XML_LINES_USED, XML_TYPE_NUMBER, XML_SCH_CONTEXT_LINES_USED ), + MAP_ENTRY( "StackedBarsConnected", CHART, XML_CONNECT_BARS, XML_TYPE_BOOL ), + + MAP_ENTRY_ODF12( "GroupBarsPerAxis", CHART, XML_GROUP_BARS_PER_AXIS, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "IncludeHiddenCells", CHART, XML_INCLUDE_HIDDEN_CELLS, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "AutomaticPosition", CHART, XML_AUTOMATIC_POSITION, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "AutomaticSize", CHART, XML_AUTOMATIC_SIZE, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "StartingAngle", CHART, XML_ANGLE_OFFSET, XML_TYPE_NUMBER ), + MAP_ENTRY_ODF12( "MissingValueTreatment", CHART, XML_TREAT_EMPTY_CELLS, XML_SCH_TYPE_MISSING_VALUE_TREATMENT ), + // #72304 Chart data table flags + MAP_ENTRY_ODF_EXT( "DataTableHBorder", LO_EXT, XML_DATA_TABLE_SHOW_HORZ_BORDER, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "DataTableVBorder", LO_EXT, XML_DATA_TABLE_SHOW_VERT_BORDER, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "DataTableOutline", LO_EXT, XML_DATA_TABLE_SHOW_OUTLINE, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT_IMPORT( "DataTableHBorder", CHART, XML_DATA_TABLE_SHOW_HORZ_BORDER, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT_IMPORT( "DataTableVBorder", CHART, XML_DATA_TABLE_SHOW_VERT_BORDER, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT_IMPORT( "DataTableOutline", CHART, XML_DATA_TABLE_SHOW_OUTLINE, XML_TYPE_BOOL ), + // Chart display units flags + MAP_ENTRY_ODF_EXT( "DisplayUnits", LO_EXT, XML_CHART_DUNITS_DISPLAYUNITS, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "BuiltInUnit", LO_EXT, XML_CHART_DUNITS_BUILTINUNIT, XML_TYPE_STRING ), + MAP_ENTRY_ODF_EXT( "ExternalData", LO_EXT, XML_EXTERNALDATA, XML_TYPE_STRING), + + MAP_ENTRY_ODF_EXT( "LabelBorderColor", LO_EXT, XML_LABEL_STROKE_COLOR, XML_TYPE_COLOR ), + MAP_ENTRY_ODF_EXT( "LabelBorderStyle", LO_EXT, XML_LABEL_STROKE, XML_SCH_TYPE_LABEL_BORDER_STYLE ), + MAP_ENTRY_ODF_EXT( "LabelBorderTransparency", LO_EXT, XML_LABEL_STROKE_OPACITY, XML_SCH_TYPE_LABEL_BORDER_OPACITY ), + MAP_ENTRY_ODF_EXT( "LabelBorderWidth", LO_EXT, XML_LABEL_STROKE_WIDTH, XML_TYPE_MEASURE ), + + MAP_ENTRY_ODF_EXT( "LabelFillColor", LO_EXT, XML_LABEL_FILL_COLOR, XML_TYPE_COLOR ), + MAP_ENTRY_ODF_EXT( "LabelFillStyle", LO_EXT, XML_LABEL_FILL, XML_SCH_TYPE_LABEL_FILL_STYLE ), + MAP_ENTRY_ODF_EXT( "LabelFillBackground", LO_EXT, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "LabelFillHatchName", LO_EXT, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME), + + MAP_ENTRY( "ScaleText", CHART, XML_SCALE_TEXT, XML_TYPE_BOOL ), + + // spline settings + MAP_ENTRY( "SplineOrder", CHART, XML_SPLINE_ORDER, XML_TYPE_NUMBER ), + MAP_ENTRY( "SplineResolution", CHART, XML_SPLINE_RESOLUTION, XML_TYPE_NUMBER ), + + // plot-area properties + MAP_ENTRY( "DataRowSource", CHART, XML_SERIES_SOURCE, XML_SCH_TYPE_DATAROWSOURCE ), + MAP_ENTRY_ODF12( "SortByXValues", CHART, XML_SORT_BY_X_VALUES, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "RightAngledAxes", CHART, XML_RIGHT_ANGLED_AXES, XML_TYPE_BOOL ), + + // axis properties + MAP_ENTRY( "DisplayLabels", CHART, XML_DISPLAY_LABEL, XML_TYPE_BOOL ), + MAP_SPECIAL( "Marks", CHART, XML_TICK_MARKS_MAJOR_INNER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_INNER ), // convert one constant + MAP_SPECIAL( "Marks", CHART, XML_TICK_MARKS_MAJOR_OUTER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_OUTER ), // to two bools + MAP_SPECIAL( "HelpMarks", CHART, XML_TICK_MARKS_MINOR_INNER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_INNER ), // see above + MAP_SPECIAL( "HelpMarks", CHART, XML_TICK_MARKS_MINOR_OUTER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_OUTER ), + MAP_CONTEXT( "Logarithmic", CHART, XML_LOGARITHMIC, XML_TYPE_BOOL, XML_SCH_CONTEXT_LOGARITHMIC ), + MAP_CONTEXT( "Min", CHART, XML_MINIMUM, XML_TYPE_DOUBLE, XML_SCH_CONTEXT_MIN ), + MAP_CONTEXT( "Max", CHART, XML_MAXIMUM, XML_TYPE_DOUBLE, XML_SCH_CONTEXT_MAX ), + MAP_CONTEXT( "Origin", CHART, XML_ORIGIN, XML_TYPE_DOUBLE, XML_SCH_CONTEXT_ORIGIN ), + MAP_CONTEXT( "StepMain", CHART, XML_INTERVAL_MAJOR, XML_TYPE_DOUBLE, XML_SCH_CONTEXT_STEP_MAIN ), + MAP_CONTEXT( "StepHelpCount", CHART, XML_INTERVAL_MINOR_DIVISOR, XML_TYPE_NUMBER, XML_SCH_CONTEXT_STEP_HELP_COUNT ), + MAP_ENTRY( "GapWidth", CHART, XML_GAP_WIDTH, XML_TYPE_NUMBER ), + MAP_ENTRY( "Overlap", CHART, XML_OVERLAP, XML_TYPE_NUMBER ), + MAP_ENTRY( "TextCanOverlap", CHART, XML_TEXT_OVERLAP, XML_TYPE_BOOL ), + MAP_ENTRY_ODF12( "ReverseDirection", CHART, XML_REVERSE_DIRECTION, XML_TYPE_BOOL ), + MAP_ENTRY( "TextBreak", TEXT, XML_LINE_BREAK, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "TryStaggeringFirst", LO_EXT, XML_TRY_STAGGERING_FIRST, XML_TYPE_BOOL ), + MAP_ENTRY( "ArrangeOrder", CHART, XML_LABEL_ARRANGEMENT, XML_SCH_TYPE_AXIS_ARRANGEMENT ), + MAP_SPECIAL( "NumberFormat", STYLE, XML_DATA_STYLE_NAME, XML_TYPE_NUMBER, XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT ), + MAP_ENTRY( "LinkNumberFormatToSource", CHART, XML_LINK_DATA_STYLE_TO_SOURCE, XML_TYPE_BOOL ), + MAP_ENTRY( "Visible", CHART, XML_VISIBLE, XML_TYPE_BOOL ), + MAP_ENTRY_ODF_EXT( "MajorOrigin", LO_EXT, XML_MAJOR_ORIGIN, XML_TYPE_DOUBLE ), + + MAP_FULL( "CrossoverPosition", CHART, XML_AXIS_POSITION, XML_SCH_TYPE_AXIS_POSITION|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0, SvtSaveOptions::ODFSVER_012 ), + MAP_FULL( "CrossoverValue", CHART, XML_AXIS_POSITION, XML_SCH_TYPE_AXIS_POSITION_VALUE|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0, SvtSaveOptions::ODFSVER_012 ), + MAP_FULL( "LabelPosition", CHART, XML_AXIS_LABEL_POSITION, XML_SCH_TYPE_AXIS_LABEL_POSITION, 0, SvtSaveOptions::ODFSVER_012 ), + MAP_FULL( "MarkPosition", CHART, XML_TICK_MARK_POSITION, XML_SCH_TYPE_TICK_MARK_POSITION, 0, SvtSaveOptions::ODFSVER_012 ), + + // statistical properties + + MAP_ENTRY( "MeanValue", CHART, XML_MEAN_VALUE, XML_TYPE_BOOL ), + MAP_ENTRY( "ErrorMargin", CHART, XML_ERROR_MARGIN, XML_TYPE_DOUBLE ), + MAP_ENTRY( "PositiveError", CHART, XML_ERROR_LOWER_LIMIT, XML_TYPE_DOUBLE), + MAP_ENTRY( "NegativeError", CHART, XML_ERROR_UPPER_LIMIT, XML_TYPE_DOUBLE), + MAP_ENTRY( "ShowPositiveError", CHART, XML_ERROR_UPPER_INDICATOR, XML_TYPE_BOOL), + MAP_ENTRY( "ShowNegativeError", CHART, XML_ERROR_LOWER_INDICATOR, XML_TYPE_BOOL), + MAP_ENTRY( "ErrorBarStyle", CHART, XML_ERROR_CATEGORY, XML_SCH_TYPE_ERROR_BAR_STYLE ), + MAP_ENTRY( "PercentageError", CHART, XML_ERROR_PERCENTAGE, XML_TYPE_DOUBLE ), + + // regression curve properties + MAP_SPECIAL( "RegressionType", CHART, XML_REGRESSION_TYPE, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE ), + MAP_SPECIAL_ODF13( "MovingAverageType", LO_EXT, XML_REGRESSION_MOVING_TYPE, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_MOVING_AVERAGE_TYPE ), + MAP_SPECIAL_ODF13( "MovingAverageType", CHART, XML_REGRESSION_MOVING_TYPE, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_MOVING_AVERAGE_TYPE ), + + // ODF 1.3 OFFICE-3958 + MAP_ENTRY_ODF13( "CurveName", XML_NAMESPACE_LO_EXT, XML_REGRESSION_CURVE_NAME, XML_TYPE_STRING ), + MAP_ENTRY_ODF13( "CurveName", XML_NAMESPACE_CHART, XML_REGRESSION_CURVE_NAME, XML_TYPE_STRING ), + MAP_ENTRY_ODF13( "PolynomialDegree", XML_NAMESPACE_LO_EXT, XML_REGRESSION_MAX_DEGREE, XML_TYPE_NUMBER ), + MAP_ENTRY_ODF13( "PolynomialDegree", XML_NAMESPACE_CHART, XML_REGRESSION_MAX_DEGREE, XML_TYPE_NUMBER ), + MAP_ENTRY_ODF13( "ForceIntercept", XML_NAMESPACE_LO_EXT, XML_REGRESSION_FORCE_INTERCEPT, XML_TYPE_BOOL ), + MAP_ENTRY_ODF13( "ForceIntercept", XML_NAMESPACE_CHART, XML_REGRESSION_FORCE_INTERCEPT, XML_TYPE_BOOL ), + MAP_ENTRY_ODF13( "InterceptValue", XML_NAMESPACE_LO_EXT, XML_REGRESSION_INTERCEPT_VALUE, XML_TYPE_DOUBLE ), + MAP_ENTRY_ODF13( "InterceptValue", XML_NAMESPACE_CHART, XML_REGRESSION_INTERCEPT_VALUE, XML_TYPE_DOUBLE ), + + // ODF 1.3 OFFICE-3959 + MAP_ENTRY_ODF13( "MovingAveragePeriod", XML_NAMESPACE_LO_EXT, XML_REGRESSION_PERIOD, XML_TYPE_NUMBER ), + MAP_ENTRY_ODF13( "MovingAveragePeriod", XML_NAMESPACE_CHART, XML_REGRESSION_PERIOD, XML_TYPE_NUMBER ), + + MAP_ENTRY_ODF_EXT( "ExtrapolateForward", LO_EXT, XML_REGRESSION_EXTRAPOLATE_FORWARD, XML_TYPE_DOUBLE ), + MAP_ENTRY_ODF_EXT( "ExtrapolateBackward", LO_EXT, XML_REGRESSION_EXTRAPOLATE_BACKWARD, XML_TYPE_DOUBLE ), + MAP_ENTRY_ODF_EXT_IMPORT( "ExtrapolateForward", CHART, XML_REGRESSION_EXTRAPOLATE_FORWARD, XML_TYPE_DOUBLE ), + MAP_ENTRY_ODF_EXT_IMPORT( "ExtrapolateBackward", CHART, XML_REGRESSION_EXTRAPOLATE_BACKWARD, XML_TYPE_DOUBLE ), + + MAP_ENTRY_ODF_EXT( "XName", LO_EXT, XML_REGRESSION_X_NAME, XML_TYPE_STRING ), + MAP_ENTRY_ODF_EXT( "YName", LO_EXT, XML_REGRESSION_Y_NAME, XML_TYPE_STRING ), + + MAP_SPECIAL_ODF12( "ErrorBarRangePositive", CHART, XML_ERROR_UPPER_RANGE, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE ), // export only + MAP_SPECIAL_ODF12( "ErrorBarRangeNegative", CHART, XML_ERROR_LOWER_RANGE, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE ), // export only + + // errorbars properties (chart2) + MAP_ENTRY_ODF_EXT( "Weight", LO_EXT, XML_ERROR_STANDARD_WEIGHT, XML_TYPE_DOUBLE), + MAP_ENTRY_ODF_EXT_IMPORT( "Weight", CHART, XML_ERROR_STANDARD_WEIGHT, XML_TYPE_DOUBLE), + + // series/data-point properties + MAP_SPECIAL( "DataCaption", CHART, XML_DATA_LABEL_NUMBER, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_NUMBER ), // convert one constant + MAP_SPECIAL( "DataCaption", CHART, XML_DATA_LABEL_TEXT, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_TEXT ), // to 'tristate' and two bools + MAP_SPECIAL( "DataCaption", CHART, XML_DATA_LABEL_SYMBOL, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SYMBOL ), + MAP_SPECIAL_ODF13( "DataCaption", CHART, XML_DATA_LABEL_SERIES, XML_TYPE_NUMBER | MID_FLAG_MERGE_PROPERTY, XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SERIES ), + MAP_SPECIAL_ODF12( "LabelSeparator", CHART, XML_LABEL_SEPARATOR, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, XML_SCH_CONTEXT_SPECIAL_LABEL_SEPARATOR ), + MAP_ENTRY_ODF12( "LabelPlacement", CHART, XML_LABEL_POSITION, XML_SCH_TYPE_LABEL_PLACEMENT_TYPE ), + MAP_ENTRY( "SegmentOffset", CHART, XML_PIE_OFFSET, XML_TYPE_NUMBER ), + MAP_SPECIAL_ODF12( "PercentageNumberFormat", STYLE, XML_PERCENTAGE_DATA_STYLE_NAME, XML_TYPE_NUMBER, XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT ), + MAP_ENTRY_ODF_EXT( "ShowCustomLeaderLines", LO_EXT, XML_CUSTOM_LEADERLINES, XML_TYPE_BOOL ), + + // text properties for titles + MAP_SPECIAL( "TextRotation", STYLE, XML_ROTATION_ANGLE, XML_TYPE_NUMBER, XML_SCH_CONTEXT_SPECIAL_TEXT_ROTATION ), // convert 1/100th degrees to degrees + MAP_ENTRY( "StackedText", STYLE, XML_DIRECTION, XML_SCH_TYPE_TEXT_ORIENTATION ), + + // for compatibility to pre 6.0beta documents +// MAP_SPECIAL( "SymbolBitmap", CHART, XML_SYMBOL_IMAGE_NAME, XML_TYPE_STRING, XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE_NAME ), + + MAP_ENTRY( "ChartUserDefinedAttributes", TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM ), + + MAP_ENTRY_END +}; + +// maps for enums to XML attributes + +const SvXMLEnumMapEntry aXMLChartAxisLabelPositionEnumMap[] = +{ + { ::xmloff::token::XML_NEAR_AXIS, css::chart::ChartAxisLabelPosition_NEAR_AXIS }, + { ::xmloff::token::XML_NEAR_AXIS_OTHER_SIDE, css::chart::ChartAxisLabelPosition_NEAR_AXIS_OTHER_SIDE }, + { ::xmloff::token::XML_OUTSIDE_START, css::chart::ChartAxisLabelPosition_OUTSIDE_START }, + { ::xmloff::token::XML_OUTSIDE_END, css::chart::ChartAxisLabelPosition_OUTSIDE_END }, + { ::xmloff::token::XML_OUTSIDE_MINIMUM, css::chart::ChartAxisLabelPosition_OUTSIDE_START },//#i114142# + { ::xmloff::token::XML_OUTSIDE_MAXIMUM, css::chart::ChartAxisLabelPosition_OUTSIDE_END },//#i114142# + { ::xmloff::token::XML_TOKEN_INVALID, css::chart::ChartAxisLabelPosition(0) } +}; + +const SvXMLEnumMapEntry aXMLChartAxisMarkPositionEnumMap[] = +{ + { ::xmloff::token::XML_AT_LABELS, css::chart::ChartAxisMarkPosition_AT_LABELS }, + { ::xmloff::token::XML_AT_AXIS, css::chart::ChartAxisMarkPosition_AT_AXIS }, + { ::xmloff::token::XML_AT_LABELS_AND_AXIS, css::chart::ChartAxisMarkPosition_AT_LABELS_AND_AXIS }, + { ::xmloff::token::XML_TOKEN_INVALID, css::chart::ChartAxisMarkPosition(0) } +}; + +const SvXMLEnumMapEntry aXMLChartAxisArrangementEnumMap[] = +{ + { ::xmloff::token::XML_SIDE_BY_SIDE, css::chart::ChartAxisArrangeOrderType_SIDE_BY_SIDE }, + { ::xmloff::token::XML_STAGGER_EVEN, css::chart::ChartAxisArrangeOrderType_STAGGER_EVEN }, + { ::xmloff::token::XML_STAGGER_ODD, css::chart::ChartAxisArrangeOrderType_STAGGER_ODD }, + { ::xmloff::token::XML_TOKEN_INVALID, css::chart::ChartAxisArrangeOrderType(0) } +}; + +const SvXMLEnumMapEntry aXMLChartErrorBarStyleEnumMap[] = +{ + { ::xmloff::token::XML_NONE, css::chart::ErrorBarStyle::NONE }, + { ::xmloff::token::XML_VARIANCE, css::chart::ErrorBarStyle::VARIANCE }, + { ::xmloff::token::XML_STANDARD_DEVIATION, css::chart::ErrorBarStyle::STANDARD_DEVIATION }, + { ::xmloff::token::XML_CONSTANT, css::chart::ErrorBarStyle::ABSOLUTE }, + { ::xmloff::token::XML_PERCENTAGE, css::chart::ErrorBarStyle::RELATIVE }, + { ::xmloff::token::XML_ERROR_MARGIN, css::chart::ErrorBarStyle::ERROR_MARGIN }, + { ::xmloff::token::XML_STANDARD_ERROR, css::chart::ErrorBarStyle::STANDARD_ERROR }, + { ::xmloff::token::XML_CELL_RANGE, css::chart::ErrorBarStyle::FROM_DATA }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry aXMLChartSolidTypeEnumMap[] = +{ + { ::xmloff::token::XML_CUBOID, css::chart::ChartSolidType::RECTANGULAR_SOLID }, + { ::xmloff::token::XML_CYLINDER, css::chart::ChartSolidType::CYLINDER }, + { ::xmloff::token::XML_CONE, css::chart::ChartSolidType::CONE }, + { ::xmloff::token::XML_PYRAMID, css::chart::ChartSolidType::PYRAMID }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry aXMLChartDataRowSourceTypeEnumMap[] = +{ + { ::xmloff::token::XML_COLUMNS, css::chart::ChartDataRowSource_COLUMNS }, + { ::xmloff::token::XML_ROWS, css::chart::ChartDataRowSource_ROWS }, + { ::xmloff::token::XML_TOKEN_INVALID, css::chart::ChartDataRowSource(0) } +}; + +const SvXMLEnumMapEntry g_XMLChartInterpolationTypeEnumMap_ODF12[] = +{ + // this is neither an enum nor a constants group, but just a + // documented long property + { ::xmloff::token::XML_NONE, 0 }, + { ::xmloff::token::XML_CUBIC_SPLINE, 1 }, + { ::xmloff::token::XML_B_SPLINE, 2 }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry g_XMLChartInterpolationTypeEnumMap[] = +{ + // this is neither an enum nor a constants group, but just a + // documented long property + { ::xmloff::token::XML_NONE, 0 }, + { ::xmloff::token::XML_CUBIC_SPLINE, 1 }, + { ::xmloff::token::XML_B_SPLINE, 2 }, + { ::xmloff::token::XML_STEP_START, 3 }, + { ::xmloff::token::XML_STEP_END, 4 }, + { ::xmloff::token::XML_STEP_CENTER_X, 5 }, + { ::xmloff::token::XML_STEP_CENTER_Y, 6 }, + // the GNM values should only be used for reading Gnumeric ods files + // they should never be used for writing ods file + { ::xmloff::token::XML_GNM_STEP_START, 3 }, + { ::xmloff::token::XML_GNM_STEP_END, 4 }, + { ::xmloff::token::XML_GNM_STEP_CENTER_X, 5 }, + { ::xmloff::token::XML_GNM_STEP_CENTER_Y, 6 }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry aXMLChartDataLabelPlacementEnumMap[] = +{ + { ::xmloff::token::XML_AVOID_OVERLAP, css::chart::DataLabelPlacement::AVOID_OVERLAP }, + { ::xmloff::token::XML_CENTER, css::chart::DataLabelPlacement::CENTER }, + { ::xmloff::token::XML_TOP, css::chart::DataLabelPlacement::TOP }, + { ::xmloff::token::XML_TOP_LEFT, css::chart::DataLabelPlacement::TOP_LEFT }, + { ::xmloff::token::XML_LEFT, css::chart::DataLabelPlacement::LEFT }, + { ::xmloff::token::XML_BOTTOM_LEFT, css::chart::DataLabelPlacement::BOTTOM_LEFT }, + { ::xmloff::token::XML_BOTTOM, css::chart::DataLabelPlacement::BOTTOM }, + { ::xmloff::token::XML_BOTTOM_RIGHT, css::chart::DataLabelPlacement::BOTTOM_RIGHT }, + { ::xmloff::token::XML_RIGHT, css::chart::DataLabelPlacement::RIGHT }, + { ::xmloff::token::XML_TOP_RIGHT, css::chart::DataLabelPlacement::TOP_RIGHT }, + { ::xmloff::token::XML_INSIDE, css::chart::DataLabelPlacement::INSIDE }, + { ::xmloff::token::XML_OUTSIDE, css::chart::DataLabelPlacement::OUTSIDE }, + { ::xmloff::token::XML_NEAR_ORIGIN, css::chart::DataLabelPlacement::NEAR_ORIGIN }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } +}; + +const SvXMLEnumMapEntry aXMLChartMissingValueTreatmentEnumMap[] = +{ + { ::xmloff::token::XML_LEAVE_GAP, css::chart::MissingValueTreatment::LEAVE_GAP }, + { ::xmloff::token::XML_USE_ZERO, css::chart::MissingValueTreatment::USE_ZERO }, + { ::xmloff::token::XML_IGNORE, css::chart::MissingValueTreatment::CONTINUE }, + { ::xmloff::token::XML_TOKEN_INVALID,0 }, +}; + +namespace { + +SvXMLEnumMapEntry const aLineStyleMap[] = +{ + { XML_NONE, drawing::LineStyle_NONE }, + { XML_SOLID, drawing::LineStyle_SOLID }, + { XML_DASH, drawing::LineStyle_DASH }, + { XML_TOKEN_INVALID, drawing::LineStyle(0) } +}; + +SvXMLEnumMapEntry const aFillStyleMap[] = +{ + { XML_NONE, drawing::FillStyle_NONE }, + { XML_SOLID, drawing::FillStyle_SOLID }, + { XML_HATCH, drawing::FillStyle_HATCH } +}; + +} + +// the following class implementations are in this file: + +// * XMLChartPropHdlFactory +// * XMLChartPropertySetMapper +// * XMLChartExportPropertyMapper +// * XMLChartImportPropertyMapper +// * SchXMLStyleExport + +XMLChartPropHdlFactory::XMLChartPropHdlFactory(SvXMLExport const*const pExport) + : m_pExport(pExport) +{ +} + +XMLChartPropHdlFactory::~XMLChartPropHdlFactory() +{ +} + +const XMLPropertyHandler* XMLChartPropHdlFactory::GetPropertyHandler( sal_Int32 nType ) const +{ + const XMLPropertyHandler* pHdl = XMLPropertyHandlerFactory::GetPropertyHandler( nType ); + if( ! pHdl ) + { + switch( nType ) + { + case XML_SCH_TYPE_AXIS_POSITION: + pHdl = new XMLAxisPositionPropertyHdl( false ); + break; + case XML_SCH_TYPE_AXIS_POSITION_VALUE: + pHdl = new XMLAxisPositionPropertyHdl( true ); + break; + + case XML_SCH_TYPE_AXIS_LABEL_POSITION: + pHdl = new XMLEnumPropertyHdl( aXMLChartAxisLabelPositionEnumMap); + break; + + case XML_SCH_TYPE_TICK_MARK_POSITION: + pHdl = new XMLEnumPropertyHdl( aXMLChartAxisMarkPositionEnumMap); + break; + + case XML_SCH_TYPE_AXIS_ARRANGEMENT: + pHdl = new XMLEnumPropertyHdl( aXMLChartAxisArrangementEnumMap); + break; + + case XML_SCH_TYPE_ERROR_BAR_STYLE: + // here we have a constant rather than an enum + pHdl = new XMLErrorBarStylePropertyHdl( aXMLChartErrorBarStyleEnumMap ); + break; + + case XML_SCH_TYPE_ERROR_INDICATOR_LOWER: + pHdl = new XMLErrorIndicatorPropertyHdl( false ); + break; + case XML_SCH_TYPE_ERROR_INDICATOR_UPPER: + pHdl = new XMLErrorIndicatorPropertyHdl( true ); + break; + + case XML_SCH_TYPE_SOLID_TYPE: + // here we have a constant rather than an enum + pHdl = new XMLEnumPropertyHdl( aXMLChartSolidTypeEnumMap ); + break; + case XML_SCH_TYPE_LABEL_PLACEMENT_TYPE: + // here we have a constant rather than an enum + pHdl = new XMLEnumPropertyHdl( aXMLChartDataLabelPlacementEnumMap ); + break; + case XML_SCH_TYPE_DATAROWSOURCE: + pHdl = new XMLEnumPropertyHdl( aXMLChartDataRowSourceTypeEnumMap); + break; + case XML_SCH_TYPE_TEXT_ORIENTATION: + pHdl = new XMLTextOrientationHdl; + break; + + case XML_SCH_TYPE_INTERPOLATION: + if (m_pExport && m_pExport->getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_013) + { + pHdl = new XMLEnumPropertyHdl(g_XMLChartInterpolationTypeEnumMap_ODF12); + } + else // ODF 1.3 OFFICE-3662 + { + pHdl = new XMLEnumPropertyHdl(g_XMLChartInterpolationTypeEnumMap); + } + break; + case XML_SCH_TYPE_SYMBOL_TYPE: + pHdl = new XMLSymbolTypePropertyHdl( false ); + break; + + case XML_SCH_TYPE_NAMED_SYMBOL: + pHdl = new XMLSymbolTypePropertyHdl( true ); + break; + + case XML_SCH_TYPE_MISSING_VALUE_TREATMENT: + pHdl = new XMLEnumPropertyHdl( aXMLChartMissingValueTreatmentEnumMap ); + break; + case XML_SCH_TYPE_LABEL_BORDER_STYLE: + pHdl = new XMLEnumPropertyHdl( aLineStyleMap ); + break; + case XML_SCH_TYPE_LABEL_BORDER_OPACITY: + pHdl = new XMLOpacityPropertyHdl(nullptr); + break; + case XML_SCH_TYPE_LABEL_FILL_STYLE: + pHdl = new XMLEnumPropertyHdl( aFillStyleMap ); + break; + default: + ; + } + if( pHdl ) + PutHdlCache( nType, pHdl ); + } + + return pHdl; +} + +XMLChartPropertySetMapper::XMLChartPropertySetMapper(SvXMLExport const*const pExport) + : XMLPropertySetMapper(aXMLChartPropMap, new XMLChartPropHdlFactory(pExport), pExport != nullptr) +{ +} + +XMLChartPropertySetMapper::~XMLChartPropertySetMapper() +{ +} + +XMLChartExportPropertyMapper::XMLChartExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExport) : + SvXMLExportPropertyMapper( rMapper ), + mrExport( rExport ) +{ + // chain draw properties + ChainExportMapper( XMLShapeExport::CreateShapePropMapper( rExport )); + + // chain text properties + ChainExportMapper( XMLTextParagraphExport::CreateParaExtPropMapper( rExport )); +} + +XMLChartExportPropertyMapper::~XMLChartExportPropertyMapper() +{ +} + +void XMLChartExportPropertyMapper::ContextFilter( + bool bEnableFoFontFamily, + std::vector< XMLPropertyState >& rProperties, + const uno::Reference< beans::XPropertySet >& rPropSet ) const +{ + OUString aAutoPropName; + bool bCheckAuto = false; + + // filter properties + for( auto& rProperty : rProperties ) + { + // find properties with context + // to prevent writing this property set mnIndex member to -1 + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex )) + { + // if Auto... is set the corresponding properties mustn't be exported + case XML_SCH_CONTEXT_MIN: + bCheckAuto = true; + aAutoPropName = "AutoMin"; + break; + case XML_SCH_CONTEXT_MAX: + bCheckAuto = true; + aAutoPropName = "AutoMax"; + break; + case XML_SCH_CONTEXT_STEP_MAIN: + bCheckAuto = true; + aAutoPropName = "AutoStepMain"; + break; + case XML_SCH_CONTEXT_STEP_HELP_COUNT: + bCheckAuto = true; + aAutoPropName = "AutoStepHelp"; + break; + + case XML_SCH_CONTEXT_ORIGIN: + bCheckAuto = true; + aAutoPropName = "AutoOrigin"; + break; + + // the following property is deprecated + // element-item symbol-image is used now + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE_NAME: + rProperty.mnIndex = -1; + break; + + case XML_SCH_CONTEXT_STOCK_WITH_VOLUME: + case XML_SCH_CONTEXT_LINES_USED: + // note this avoids export of the properties in OASIS format, + // but also for the OOo XML Flat format (used by binfilter), + // because there, the transformation to OOo is done after the + // complete export of the chart in OASIS format. + if( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) + rProperty.mnIndex = -1; + break; + } + + if( bCheckAuto ) + { + if( rPropSet.is()) + { + try + { + bool bAuto = false; + uno::Any aAny = rPropSet->getPropertyValue( aAutoPropName ); + aAny >>= bAuto; + if( bAuto ) + rProperty.mnIndex = -1; + } + catch(const beans::UnknownPropertyException&) + { + } + } + bCheckAuto = false; + } + } + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +void XMLChartExportPropertyMapper::handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex )) + { + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE: + { + uno::Reference xGraphic; + rProperty.maValue >>= xGraphic; + + OUString sInternalURL; + // export as XLink reference into the package + // if embedding is off + if (xGraphic.is()) + { + OUString aOutMimeType; + sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, aOutMimeType); + } + if (!sInternalURL.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + } + + { + sal_uInt32 nPropIndex = rProperty.mnIndex; + // this is the element that has to live until the next statement + SvXMLElementExport aElem( mrExport, + getPropertySetMapper()->GetEntryNameSpace( nPropIndex ), + getPropertySetMapper()->GetEntryXMLName( nPropIndex ), + true, true ); + + // export as Base64 embedded graphic + // if embedding is on + if (xGraphic.is()) + mrExport.AddEmbeddedXGraphicAsBase64(xGraphic); + } + } + break; + + case XML_SCH_CONTEXT_SPECIAL_LABEL_SEPARATOR: + { + OUString aSeparator; + rProperty.maValue >>= aSeparator; + + if( !aSeparator.isEmpty() ) + { + sal_uInt32 nPropIndex = rProperty.mnIndex; + SvXMLElementExport aElem( mrExport, + getPropertySetMapper()->GetEntryNameSpace( nPropIndex ), + getPropertySetMapper()->GetEntryXMLName( nPropIndex ), + true, true ); + + SchXMLTools::exportText( mrExport, aSeparator, true ); + } + } + break; + + default: + // call parent + SvXMLExportPropertyMapper::handleElementItem( rExport, rProperty, + nFlags, pProperties, nIdx ); + break; + } +} + +namespace { + +OUString convertRange( const OUString & rRange, const uno::Reference< chart2::XChartDocument > & xDoc ) +{ + OUString aResult = rRange; + if( !xDoc.is() ) + return aResult; + uno::Reference< chart2::data::XRangeXMLConversion > xConversion( + xDoc->getDataProvider(), uno::UNO_QUERY ); + try + { + if( xConversion.is()) + aResult = xConversion->convertRangeToXML( rRange ); + } + catch (css::lang::IllegalArgumentException&) + { + } + + return aResult; +} + +} + +void XMLChartExportPropertyMapper::handleSpecialItem( + SvXMLAttributeList& rAttrList, const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + bool bHandled = false; + + sal_Int32 nContextId = getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ); + + if( nContextId ) + { + bHandled = true; + + OUString sAttrName = getPropertySetMapper()->GetEntryXMLName( rProperty.mnIndex ); + sal_uInt16 nNameSpace = getPropertySetMapper()->GetEntryNameSpace( rProperty.mnIndex ); + OUStringBuffer sValueBuffer; + + sal_Int32 nValue = 0; + bool bValue = false; + + switch( nContextId ) + { + case XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_INNER: + case XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_INNER: + rProperty.maValue >>= nValue; + bValue = (( nValue & chart::ChartAxisMarks::INNER ) == chart::ChartAxisMarks::INNER ); + ::sax::Converter::convertBool( sValueBuffer, bValue ); + break; + case XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_OUTER: + case XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_OUTER: + rProperty.maValue >>= nValue; + bValue = (( nValue & chart::ChartAxisMarks::OUTER ) == chart::ChartAxisMarks::OUTER ); + ::sax::Converter::convertBool( sValueBuffer, bValue ); + break; + case XML_SCH_CONTEXT_SPECIAL_TEXT_ROTATION: + { + // convert from 100th degrees to degrees (double) + rProperty.maValue >>= nValue; + double fVal = static_cast(nValue) / 100.0; + ::sax::Converter::convertDouble( sValueBuffer, fVal ); + } + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_NUMBER: + { + rProperty.maValue >>= nValue; + if( ( nValue & chart::ChartDataCaption::VALUE ) == chart::ChartDataCaption::VALUE ) + { + if( ( nValue & chart::ChartDataCaption::PERCENT ) == chart::ChartDataCaption::PERCENT ) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion( + mrExport.getSaneDefaultVersion()); + if (nCurrentVersion < SvtSaveOptions::ODFSVER_012) + sValueBuffer.append( GetXMLToken( XML_PERCENTAGE )); + else + sValueBuffer.append( GetXMLToken( XML_VALUE_AND_PERCENTAGE )); + } + else + sValueBuffer.append( GetXMLToken( XML_VALUE )); + } + else if(( nValue & chart::ChartDataCaption::PERCENT ) == chart::ChartDataCaption::PERCENT ) + sValueBuffer.append( GetXMLToken( XML_PERCENTAGE )); + else + sValueBuffer.append( GetXMLToken( XML_NONE )); + } + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_TEXT: + rProperty.maValue >>= nValue; + bValue = (( nValue & chart::ChartDataCaption::TEXT ) == chart::ChartDataCaption::TEXT ); + ::sax::Converter::convertBool( sValueBuffer, bValue ); + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SYMBOL: + rProperty.maValue >>= nValue; + bValue = (( nValue & chart::ChartDataCaption::SYMBOL ) == chart::ChartDataCaption::SYMBOL ); + ::sax::Converter::convertBool( sValueBuffer, bValue ); + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SERIES: + rProperty.maValue >>= nValue; + bValue = (( nValue & chart::ChartDataCaption::DATA_SERIES ) == chart::ChartDataCaption::DATA_SERIES ); + ::sax::Converter::convertBool( sValueBuffer, bValue ); + break; + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH: + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_HEIGHT: + { + awt::Size aSize; + rProperty.maValue >>= aSize; + rUnitConverter.convertMeasureToXML( sValueBuffer, + nContextId == XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH + ? aSize.Width + : aSize.Height ); + } + break; + + case XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT: + { + // just for import + break; + } + + case XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE: + { + OUString aRangeStr; + rProperty.maValue >>= aRangeStr; + sValueBuffer.append(convertRange(aRangeStr, mxChartDoc)); + } + break; + case XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE: + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion( + mrExport.getSaneDefaultVersion()); + + OUString aServiceName; + rProperty.maValue >>= aServiceName; + if (aServiceName == "com.sun.star.chart2.LinearRegressionCurve") + sValueBuffer.append( GetXMLToken( XML_LINEAR )); + else if (aServiceName == "com.sun.star.chart2.LogarithmicRegressionCurve") + sValueBuffer.append( GetXMLToken( XML_LOGARITHMIC )); + else if (aServiceName == "com.sun.star.chart2.ExponentialRegressionCurve") + sValueBuffer.append( GetXMLToken( XML_EXPONENTIAL )); + else if (aServiceName == "com.sun.star.chart2.PotentialRegressionCurve") + sValueBuffer.append( GetXMLToken( XML_POWER )); + else if (nCurrentVersion >= SvtSaveOptions::ODFSVER_013 && aServiceName == "com.sun.star.chart2.PolynomialRegressionCurve") + { // ODF 1.3 OFFICE-3958 + sValueBuffer.append( GetXMLToken( XML_POLYNOMIAL )); + } + else if (nCurrentVersion >= SvtSaveOptions::ODFSVER_013 && aServiceName == "com.sun.star.chart2.MovingAverageRegressionCurve") + { // ODF 1.3 OFFICE-3959 + sValueBuffer.append( GetXMLToken( XML_MOVING_AVERAGE )); + } + } + break; + + case XML_SCH_CONTEXT_SPECIAL_MOVING_AVERAGE_TYPE: + { + rProperty.maValue >>= nValue; + if (nValue == MovingAverageType::Prior) + sValueBuffer.append( GetXMLToken( XML_PRIOR )); + else if (nValue == MovingAverageType::Central) + sValueBuffer.append( GetXMLToken( XML_CENTRAL )); + else if (nValue == MovingAverageType::AveragedAbscissa) + sValueBuffer.append( GetXMLToken( XML_AVERAGED_ABSCISSA )); + else // default + sValueBuffer.append( GetXMLToken( XML_PRIOR )); + } + break; + + default: + bHandled = false; + break; + } + + if( !sValueBuffer.isEmpty()) + { + OUString sValue = sValueBuffer.makeStringAndClear(); + sAttrName = rNamespaceMap.GetQNameByKey( nNameSpace, sAttrName ); + rAttrList.AddAttribute( sAttrName, sValue ); + } + } + + if( !bHandled ) + { + // call parent + SvXMLExportPropertyMapper::handleSpecialItem( rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx ); + } +} + +void XMLChartExportPropertyMapper::setChartDoc( const uno::Reference< chart2::XChartDocument >& xChartDoc ) +{ + mxChartDoc = xChartDoc; +} + +XMLChartImportPropertyMapper::XMLChartImportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, + const SvXMLImport& _rImport ) : + SvXMLImportPropertyMapper( rMapper, const_cast< SvXMLImport & >( _rImport )), + mrImport( const_cast< SvXMLImport & > ( _rImport )) +{ + // chain shape mapper for drawing properties + + // give an empty model. It is only used for numbering rules that don't exist in chart + uno::Reference< frame::XModel > xEmptyModel; + ChainImportMapper( XMLShapeImportHelper::CreateShapePropMapper( xEmptyModel, mrImport )); + + //#i14365# save and load writing-mode for chart elements + //The property TextWritingMode is mapped wrongly in the underlying draw mapper, but for draw it is necessary + //We remove that property here only for chart thus the chart can use the correct mapping from the writer paragraph settings (attribute 'writing-mode' <-> property 'WritingMode') + sal_Int32 nUnwantedWrongEntry = maPropMapper->FindEntryIndex( "TextWritingMode", XML_NAMESPACE_STYLE, GetXMLToken(XML_WRITING_MODE) ); + maPropMapper->RemoveEntry(nUnwantedWrongEntry); + + // do not chain text properties: on import this is done by shape mapper + // to import old documents +} + +XMLChartImportPropertyMapper::~XMLChartImportPropertyMapper() +{ +} + +bool XMLChartImportPropertyMapper::handleSpecialItem( + XMLPropertyState& rProperty, + ::std::vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const +{ + sal_Int32 nContextId = maPropMapper->GetEntryContextId( rProperty.mnIndex ); + bool bRet = (nContextId != 0); + + if( nContextId ) + { + sal_Int32 nValue = 0; + bool bValue = false; + + switch( nContextId ) + { + case XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_INNER: + case XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_INNER: + (void)::sax::Converter::convertBool( bValue, rValue ); + // modify old value + rProperty.maValue >>= nValue; + if( bValue ) + SCH_XML_SETFLAG( nValue, chart::ChartAxisMarks::INNER ); + else + SCH_XML_UNSETFLAG( nValue, chart::ChartAxisMarks::INNER ); + rProperty.maValue <<= nValue; + break; + case XML_SCH_CONTEXT_SPECIAL_TICKS_MAJ_OUTER: + case XML_SCH_CONTEXT_SPECIAL_TICKS_MIN_OUTER: + (void)::sax::Converter::convertBool( bValue, rValue ); + // modify old value + rProperty.maValue >>= nValue; + if( bValue ) + SCH_XML_SETFLAG( nValue, chart::ChartAxisMarks::OUTER ); + else + SCH_XML_UNSETFLAG( nValue, chart::ChartAxisMarks::OUTER ); + rProperty.maValue <<= nValue; + break; + case XML_SCH_CONTEXT_SPECIAL_TEXT_ROTATION: + { + // convert from degrees (double) to 100th degrees (integer) + double fVal; + ::sax::Converter::convertDouble( fVal, rValue ); + nValue = static_cast( fVal * 100.0 ); + rProperty.maValue <<= nValue; + } + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_NUMBER: + { + // modify old value + rProperty.maValue >>= nValue; + if( IsXMLToken( rValue, XML_NONE )) + SCH_XML_UNSETFLAG( nValue, chart::ChartDataCaption::VALUE | chart::ChartDataCaption::PERCENT ); + else if( IsXMLToken( rValue, XML_VALUE_AND_PERCENTAGE ) ) + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::VALUE | chart::ChartDataCaption::PERCENT ); + else if( IsXMLToken( rValue, XML_VALUE ) ) + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::VALUE ); + else // must be XML_PERCENTAGE + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::PERCENT ); + rProperty.maValue <<= nValue; + } + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_TEXT: + rProperty.maValue >>= nValue; + (void)::sax::Converter::convertBool( bValue, rValue ); + if( bValue ) + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::TEXT ); + else + SCH_XML_UNSETFLAG( nValue, chart::ChartDataCaption::TEXT ); + rProperty.maValue <<= nValue; + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SYMBOL: + rProperty.maValue >>= nValue; + (void)::sax::Converter::convertBool( bValue, rValue ); + if( bValue ) + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::SYMBOL ); + else + SCH_XML_UNSETFLAG( nValue, chart::ChartDataCaption::SYMBOL ); + rProperty.maValue <<= nValue; + break; + case XML_SCH_CONTEXT_SPECIAL_DATA_LABEL_SERIES: + rProperty.maValue >>= nValue; + (void)::sax::Converter::convertBool( bValue, rValue ); + if( bValue ) + SCH_XML_SETFLAG( nValue, chart::ChartDataCaption::DATA_SERIES ); + else + SCH_XML_UNSETFLAG( nValue, chart::ChartDataCaption::DATA_SERIES ); + rProperty.maValue <<= nValue; + break; + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH: + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_HEIGHT: + { + awt::Size aSize; + rProperty.maValue >>= aSize; + rUnitConverter.convertMeasureToCore( + (nContextId == XML_SCH_CONTEXT_SPECIAL_SYMBOL_WIDTH) + ? aSize.Width + : aSize.Height, + rValue ); + rProperty.maValue <<= aSize; + } + break; + + case XML_SCH_CONTEXT_SPECIAL_ERRORBAR_RANGE: + { + rProperty.maValue <<= rValue; + } + break; + + // deprecated from 6.0 beta on + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE_NAME: + rProperty.maValue <<= mrImport.loadGraphicByURL(rValue); + break; + + case XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE: + { + if (IsXMLToken( rValue, XML_LINEAR )) + rProperty.maValue <<= OUString("com.sun.star.chart2.LinearRegressionCurve"); + else if (IsXMLToken( rValue, XML_LOGARITHMIC)) + rProperty.maValue <<= OUString("com.sun.star.chart2.LogarithmicRegressionCurve"); + else if (IsXMLToken( rValue, XML_EXPONENTIAL)) + rProperty.maValue <<= OUString("com.sun.star.chart2.ExponentialRegressionCurve"); + else if (IsXMLToken( rValue, XML_POWER)) + rProperty.maValue <<= OUString("com.sun.star.chart2.PotentialRegressionCurve"); + else if (IsXMLToken( rValue, XML_POLYNOMIAL)) + rProperty.maValue <<= OUString("com.sun.star.chart2.PolynomialRegressionCurve"); + else if (IsXMLToken( rValue, XML_MOVING_AVERAGE)) + rProperty.maValue <<= OUString("com.sun.star.chart2.MovingAverageRegressionCurve"); + } + break; + + case XML_SCH_CONTEXT_SPECIAL_MOVING_AVERAGE_TYPE: + { + if (IsXMLToken( rValue, XML_PRIOR )) + rProperty.maValue <<= MovingAverageType::Prior; + else if (IsXMLToken( rValue, XML_CENTRAL)) + rProperty.maValue <<= MovingAverageType::Central; + else if (IsXMLToken( rValue, XML_AVERAGED_ABSCISSA)) + rProperty.maValue <<= MovingAverageType::AveragedAbscissa; + else // default + rProperty.maValue <<= MovingAverageType::Prior; + } + break; + + default: + bRet = false; + break; + } + } + + // if we didn't handle it, the parent should + if( !bRet ) + { + // call parent + bRet = SvXMLImportPropertyMapper::handleSpecialItem( rProperty, rProperties, rValue, rUnitConverter, rNamespaceMap ); + } + + return bRet; +} + +void XMLChartImportPropertyMapper::finished( ::std::vector< XMLPropertyState >& /*rProperties*/, sal_Int32 /*nStartIndex*/, sal_Int32 /*nEndIndex*/ ) const +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLAutoStylePoolP.cxx b/xmloff/source/chart/SchXMLAutoStylePoolP.cxx new file mode 100644 index 000000000..d60b3de72 --- /dev/null +++ b/xmloff/source/chart/SchXMLAutoStylePoolP.cxx @@ -0,0 +1,77 @@ +/* -*- 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 +#include "PropertyMap.hxx" +#include +#include +#include + + +SchXMLAutoStylePoolP::SchXMLAutoStylePoolP( SchXMLExport& rSchXMLExport ) : + SvXMLAutoStylePoolP( rSchXMLExport ), + mrSchXMLExport( rSchXMLExport ) +{} + +SchXMLAutoStylePoolP::~SchXMLAutoStylePoolP() +{} + +void SchXMLAutoStylePoolP::exportStyleAttributes( + SvXMLAttributeList& rAttrList, + XmlStyleFamily nFamily, + const ::std::vector< XMLPropertyState >& rProperties, + const SvXMLExportPropertyMapper& rPropExp + , const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap + ) const +{ + SvXMLAutoStylePoolP::exportStyleAttributes( rAttrList, nFamily, rProperties, + rPropExp, rUnitConverter, rNamespaceMap ); + + if( nFamily != XmlStyleFamily::SCH_CHART_ID ) + return; + + for( const auto& rProp : rProperties ) + { + if( rProp.mnIndex == -1 ) + continue; + + rtl::Reference< XMLPropertySetMapper > aPropMapper = + mrSchXMLExport.GetPropertySetMapper(); + sal_Int16 nContextID = aPropMapper->GetEntryContextId( rProp.mnIndex ); + if( nContextID == XML_SCH_CONTEXT_SPECIAL_NUMBER_FORMAT ) + { + sal_Int32 nNumberFormat = -1; + if( ( rProp.maValue >>= nNumberFormat ) && + ( nNumberFormat != -1 )) + { + OUString sAttrValue = mrSchXMLExport.getDataStyleName( nNumberFormat ); + if( !sAttrValue.isEmpty() ) + { + mrSchXMLExport.AddAttribute( + aPropMapper->GetEntryNameSpace( rProp.mnIndex ), + aPropMapper->GetEntryXMLName( rProp.mnIndex ), + sAttrValue ); + } + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLAxisContext.cxx b/xmloff/source/chart/SchXMLAxisContext.cxx new file mode 100644 index 000000000..ad8b187f8 --- /dev/null +++ b/xmloff/source/chart/SchXMLAxisContext.cxx @@ -0,0 +1,900 @@ +/* -*- 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 + +#include "SchXMLAxisContext.hxx" +#include "SchXMLChartContext.hxx" +#include "SchXMLTools.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::xmloff::token; +using namespace com::sun::star; + +using com::sun::star::uno::Reference; + +const SvXMLEnumMapEntry aXMLAxisDimensionMap[] = +{ + { XML_X, SCH_XML_AXIS_X }, + { XML_Y, SCH_XML_AXIS_Y }, + { XML_Z, SCH_XML_AXIS_Z }, + { XML_TOKEN_INVALID, SchXMLAxisDimension(0) } +}; + +const SvXMLEnumMapEntry aXMLAxisTypeMap[] = +{ + { XML_AUTO, css::chart::ChartAxisType::AUTOMATIC }, + { XML_TEXT, css::chart::ChartAxisType::CATEGORY }, + { XML_DATE, css::chart::ChartAxisType::DATE }, + { XML_TOKEN_INVALID, 0 } +}; + +namespace { + +class SchXMLCategoriesContext : public SvXMLImportContext +{ +private: + OUString& mrAddress; + +public: + SchXMLCategoriesContext( SvXMLImport& rImport, + OUString& rAddress ); + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +class DateScaleContext : public SvXMLImportContext +{ +public: + DateScaleContext( SvXMLImport& rImport, + const Reference< beans::XPropertySet >& rAxisProps ); + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +private: + Reference< beans::XPropertySet > m_xAxisProps; +}; + +} + +SchXMLAxisContext::SchXMLAxisContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + Reference< chart::XDiagram > const & xDiagram, + std::vector< SchXMLAxis >& rAxes, + OUString & rCategoriesAddress, + bool bAddMissingXAxisForNetCharts, + bool bAdaptWrongPercentScaleValues, + bool bAdaptXAxisOrientationForOld2DBarCharts, + bool& rbAxisPositionAttributeImported ) : + SvXMLImportContext( rImport ), + m_rImportHelper( rImpHelper ), + m_xDiagram( xDiagram ), + m_rAxes( rAxes ), + m_rCategoriesAddress( rCategoriesAddress ), + m_nAxisType(chart::ChartAxisType::AUTOMATIC), + m_bAxisTypeImported(false), + m_bDateScaleImported(false), + m_bAddMissingXAxisForNetCharts( bAddMissingXAxisForNetCharts ), + m_bAdaptWrongPercentScaleValues( bAdaptWrongPercentScaleValues ), + m_bAdaptXAxisOrientationForOld2DBarCharts( bAdaptXAxisOrientationForOld2DBarCharts ), + m_rbAxisPositionAttributeImported( rbAxisPositionAttributeImported ) +{ +} + +SchXMLAxisContext::~SchXMLAxisContext() +{} + +static Reference< chart::XAxis > lcl_getChartAxis(const SchXMLAxis& rCurrentAxis, const Reference< chart::XDiagram >& rDiagram ) +{ + Reference< chart::XAxis > xAxis; + Reference< chart::XAxisSupplier > xAxisSuppl( rDiagram, uno::UNO_QUERY ); + if( !xAxisSuppl.is() ) + return xAxis; + if( rCurrentAxis.nAxisIndex == 0 ) + xAxis = xAxisSuppl->getAxis(rCurrentAxis.eDimension); + else + xAxis = xAxisSuppl->getSecondaryAxis(rCurrentAxis.eDimension); + return xAxis; +} + +/* returns a shape for the current axis's title. The property + "Has...AxisTitle" is set to "True" to get the shape + */ +Reference< drawing::XShape > SchXMLAxisContext::getTitleShape() const +{ + Reference< drawing::XShape > xResult; + Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY ); + Reference< chart::XAxis > xAxis( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ) ); + if( !xDiaProp.is() || !xAxis.is() ) + return xResult; + + OUString aPropName; + switch( m_aCurrentAxis.eDimension ) + { + case SCH_XML_AXIS_X: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasXAxisTitle"; + else + aPropName = "HasSecondaryXAxisTitle"; + break; + case SCH_XML_AXIS_Y: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasYAxisTitle"; + else + aPropName = "HasSecondaryYAxisTitle"; + break; + case SCH_XML_AXIS_Z: + aPropName = "HasZAxisTitle"; + break; + case SCH_XML_AXIS_UNDEF: + SAL_INFO("xmloff.chart", "Invalid axis" ); + break; + } + xDiaProp->setPropertyValue( aPropName, uno::Any(true) ); + xResult.set( xAxis->getAxisTitle(), uno::UNO_QUERY ); + return xResult; +} + +void SchXMLAxisContext::CreateGrid( const OUString& sAutoStyleName, bool bIsMajor ) +{ + Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY ); + Reference< chart::XAxis > xAxis( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ) ); + if( !xDiaProp.is() || !xAxis.is() ) + return; + + OUString aPropName; + switch( m_aCurrentAxis.eDimension ) + { + case SCH_XML_AXIS_X: + if( bIsMajor ) + aPropName = "HasXAxisGrid"; + else + aPropName = "HasXAxisHelpGrid"; + break; + case SCH_XML_AXIS_Y: + if( bIsMajor ) + aPropName = "HasYAxisGrid"; + else + aPropName = "HasYAxisHelpGrid"; + break; + case SCH_XML_AXIS_Z: + if( bIsMajor ) + aPropName = "HasZAxisGrid"; + else + aPropName = "HasZAxisHelpGrid"; + break; + case SCH_XML_AXIS_UNDEF: + SAL_INFO("xmloff.chart", "Invalid axis" ); + break; + } + xDiaProp->setPropertyValue( aPropName, uno::Any(true) ); + + Reference< beans::XPropertySet > xGridProp; + if( bIsMajor ) + xGridProp = xAxis->getMajorGrid(); + else + xGridProp = xAxis->getMinorGrid(); + + // set properties + if( xGridProp.is()) + { + // the line color is black as default, in the model it is a light gray + xGridProp->setPropertyValue("LineColor", + uno::Any( COL_BLACK )); + if (!sAutoStyleName.isEmpty()) + m_rImportHelper.FillAutoStyle(sAutoStyleName, xGridProp); + } +} + +void SchXMLAxisContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // parse attributes + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(CHART, XML_DIMENSION): + { + SchXMLAxisDimension nEnumVal; + if( SvXMLUnitConverter::convertEnum( nEnumVal, aIter.toView(), aXMLAxisDimensionMap )) + m_aCurrentAxis.eDimension = nEnumVal; + } + break; + case XML_ELEMENT(CHART, XML_NAME): + m_aCurrentAxis.aName = aIter.toString(); + break; + case XML_ELEMENT(CHART, XML_AXIS_TYPE): + case XML_ELEMENT(CHART_EXT, XML_AXIS_TYPE): + sal_uInt16 nEnumVal; + if( SvXMLUnitConverter::convertEnum( nEnumVal, aIter.toView(), aXMLAxisTypeMap )) + { + m_nAxisType = nEnumVal; + m_bAxisTypeImported = true; + } + break; + case XML_ELEMENT(CHART, XML_STYLE_NAME): + m_aAutoStyleName = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // check for number of axes with same dimension + m_aCurrentAxis.nAxisIndex = 0; + sal_Int32 nNumOfAxes = m_rAxes.size(); + for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ ) + { + if( m_rAxes[ nCurrent ].eDimension == m_aCurrentAxis.eDimension ) + m_aCurrentAxis.nAxisIndex++; + } + CreateAxis(); +} +namespace +{ + +Reference< chart2::XAxis > lcl_getAxis( const Reference< frame::XModel >& xChartModel, + sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + Reference< chart2::XAxis > xAxis; + + try + { + Reference< chart2::XChartDocument > xChart2Document( xChartModel, uno::UNO_QUERY ); + if( xChart2Document.is() ) + { + Reference< chart2::XDiagram > xDiagram( xChart2Document->getFirstDiagram()); + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); + uno::Sequence< Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + sal_Int32 nCooSysIndex = 0; + if( nCooSysIndex < aCooSysSeq.getLength() ) + { + Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIndex] ); + if( xCooSys.is() && nDimensionIndex < xCooSys->getDimension() ) + { + const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + if( nAxisIndex <= nMaxAxisIndex ) + xAxis = xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ); + } + } + } + } + catch( uno::Exception & ) + { + SAL_INFO("xmloff.chart", "Couldn't get axis" ); + } + + return xAxis; +} + +bool lcl_divideBy100( uno::Any& rDoubleAny ) +{ + bool bChanged = false; + double fValue=0.0; + if( (rDoubleAny>>=fValue) && (fValue!=0.0) ) + { + fValue/=100.0; + rDoubleAny <<= fValue; + bChanged = true; + } + return bChanged; +} + +bool lcl_AdaptWrongPercentScaleValues(chart2::ScaleData& rScaleData) +{ + bool bChanged = lcl_divideBy100( rScaleData.Minimum ); + bChanged = lcl_divideBy100( rScaleData.Maximum ) || bChanged; + bChanged = lcl_divideBy100( rScaleData.Origin ) || bChanged; + bChanged = lcl_divideBy100( rScaleData.IncrementData.Distance ) || bChanged; + return bChanged; +} + +}//end anonymous namespace + +void SchXMLAxisContext::CreateAxis() +{ + m_rAxes.push_back( m_aCurrentAxis ); + + Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY ); + if( !xDiaProp.is() ) + return; + OUString aPropName; + switch( m_aCurrentAxis.eDimension ) + { + case SCH_XML_AXIS_X: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasXAxis"; + else + aPropName = "HasSecondaryXAxis"; + break; + case SCH_XML_AXIS_Y: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasYAxis"; + else + aPropName = "HasSecondaryYAxis"; + break; + case SCH_XML_AXIS_Z: + if( m_aCurrentAxis.nAxisIndex == 0 ) + aPropName = "HasZAxis"; + break; + case SCH_XML_AXIS_UNDEF: + SAL_INFO("xmloff.chart", "Invalid axis" ); + break; + } + try + { + xDiaProp->setPropertyValue( aPropName, uno::Any(true) ); + } + catch( beans::UnknownPropertyException & ) + { + SAL_INFO("xmloff.chart", "Couldn't turn on axis" ); + } + if( m_aCurrentAxis.eDimension==SCH_XML_AXIS_Z ) + { + bool bSettingZAxisSucceeded = false; + try + { + xDiaProp->getPropertyValue( aPropName ) >>= bSettingZAxisSucceeded; + } + catch( beans::UnknownPropertyException & ) + { + SAL_INFO("xmloff.chart", "Couldn't turn on z axis" ); + } + if( !bSettingZAxisSucceeded ) + return; + } + + m_xAxisProps.set( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ), uno::UNO_QUERY ); + + if( m_bAddMissingXAxisForNetCharts && m_aCurrentAxis.eDimension==SCH_XML_AXIS_Y && m_aCurrentAxis.nAxisIndex==0 ) + { + try + { + xDiaProp->setPropertyValue("HasXAxis", uno::Any(true) ); + } + catch( beans::UnknownPropertyException & ) + { + SAL_INFO("xmloff.chart", "Couldn't turn on x axis" ); + } + } + + // set properties + if( !m_xAxisProps.is()) + return; + + uno::Any aTrueBool( uno::Any( true )); + uno::Any aFalseBool( uno::Any( false )); + + // #i109879# the line color is black as default, in the model it is a light gray + m_xAxisProps->setPropertyValue("LineColor", + uno::Any( COL_BLACK )); + + m_xAxisProps->setPropertyValue("DisplayLabels", aFalseBool ); + + // Compatibility option: starting from LibreOffice 5.1 the rotated + // layout is preferred to staggering for axis labels. + // So the import default value for having compatibility with ODF + // documents created with earlier LibreOffice versions is `true`. + if( GetImport().getGeneratorVersion() != SvXMLImport::ProductVersionUnknown ) + m_xAxisProps->setPropertyValue("TryStaggeringFirst", aTrueBool ); + + // #88077# AutoOrigin 'on' is default + m_xAxisProps->setPropertyValue("AutoOrigin", aTrueBool ); + + if( m_bAxisTypeImported ) + m_xAxisProps->setPropertyValue("AxisType", uno::Any(m_nAxisType) ); + + if( !m_aAutoStyleName.isEmpty()) + { + const SvXMLStylesContext* pStylesCtxt = m_rImportHelper.GetAutoStylesContext(); + if (pStylesCtxt) + { + SvXMLStyleContext* pStyle = const_cast(pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(), m_aAutoStyleName)); + + if (XMLPropStyleContext * pPropStyleContext = dynamic_cast(pStyle)) + { + pPropStyleContext->FillPropertySet(m_xAxisProps); + + if( m_bAdaptWrongPercentScaleValues && m_aCurrentAxis.eDimension==SCH_XML_AXIS_Y ) + { + //set scale data of added x axis back to default + Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(), + m_aCurrentAxis.eDimension, m_aCurrentAxis.nAxisIndex ) ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData()); + if( lcl_AdaptWrongPercentScaleValues(aScaleData) ) + xAxis->setScaleData( aScaleData ); + } + } + + if( m_bAddMissingXAxisForNetCharts ) + { + //copy style from y axis to added x axis: + + Reference< chart::XAxisSupplier > xAxisSuppl( xDiaProp, uno::UNO_QUERY ); + if( xAxisSuppl.is() ) + { + Reference< beans::XPropertySet > xXAxisProp( xAxisSuppl->getAxis(0), uno::UNO_QUERY ); + pPropStyleContext->FillPropertySet(xXAxisProp); + } + + //set scale data of added x axis back to default + Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(), + 0 /*nDimensionIndex*/, 0 /*nAxisIndex*/ ) ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData; + aScaleData.AxisType = chart2::AxisType::CATEGORY; + aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL; + xAxis->setScaleData( aScaleData ); + } + + //set line style of added x axis to invisible + Reference< beans::XPropertySet > xNewAxisProp( xAxis, uno::UNO_QUERY ); + if( xNewAxisProp.is() ) + { + xNewAxisProp->setPropertyValue("LineStyle" + , uno::Any(drawing::LineStyle_NONE)); + } + } + + if( m_bAdaptXAxisOrientationForOld2DBarCharts && m_aCurrentAxis.eDimension == SCH_XML_AXIS_X ) + { + bool bIs3DChart = false; + if( xDiaProp.is() && ( xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart ) + && !bIs3DChart ) + { + Reference< chart2::XChartDocument > xChart2Document( GetImport().GetModel(), uno::UNO_QUERY ); + if( xChart2Document.is() ) + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChart2Document->getFirstDiagram(), uno::UNO_QUERY ); + if( xCooSysCnt.is() ) + { + uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() ); + if( aCooSysSeq.hasElements() ) + { + bool bSwapXandYAxis = false; + Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] ); + Reference< beans::XPropertySet > xCooSysProp( xCooSys, uno::UNO_QUERY ); + if( xCooSysProp.is() && ( xCooSysProp->getPropertyValue("SwapXAndYAxis") >>= bSwapXandYAxis ) + && bSwapXandYAxis ) + { + Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( 0, m_aCurrentAxis.nAxisIndex ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + aScaleData.Orientation = chart2::AxisOrientation_REVERSE; + xAxis->setScaleData( aScaleData ); + } + } + } + } + } + } + } + + m_rbAxisPositionAttributeImported = m_rbAxisPositionAttributeImported || SchXMLTools::getPropertyFromContext( + u"CrossoverPosition", pPropStyleContext, pStylesCtxt ).hasValue(); + } + } + } + + if (m_aCurrentAxis.eDimension != SCH_XML_AXIS_X) + return; + + Reference xAxis(lcl_getAxis(GetImport().GetModel(), m_aCurrentAxis.eDimension, m_aCurrentAxis.nAxisIndex)); + if (!xAxis.is()) + return; + + chart2::ScaleData aScaleData(xAxis->getScaleData()); + bool bIs3DChart = false; + double fMajorOrigin = -1; + OUString sChartType = m_xDiagram->getDiagramType(); + if ((xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart) && bIs3DChart + && (sChartType == "com.sun.star.chart.BarDiagram" || sChartType == "com.sun.star.chart.StockDiagram")) + { + aScaleData.ShiftedCategoryPosition = true; + xAxis->setScaleData(aScaleData); + } + else if ((m_xAxisProps->getPropertyValue("MajorOrigin") >>= fMajorOrigin) + && (rtl::math::approxEqual(fMajorOrigin, 0.0) || rtl::math::approxEqual(fMajorOrigin, 0.5))) + { + aScaleData.ShiftedCategoryPosition = rtl::math::approxEqual(fMajorOrigin, 0.5); + xAxis->setScaleData(aScaleData); + } +} + +void SchXMLAxisContext::SetAxisTitle() +{ + if( m_aCurrentAxis.aTitle.isEmpty() ) + return; + + Reference< chart::XAxis > xAxis( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ) ); + if( !xAxis.is() ) + return; + + Reference< beans::XPropertySet > xTitleProp( xAxis->getAxisTitle() ); + if( xTitleProp.is() ) + { + try + { + xTitleProp->setPropertyValue("String", uno::Any(m_aCurrentAxis.aTitle) ); + } + catch( beans::UnknownPropertyException & ) + { + SAL_INFO("xmloff.chart", "Property String for Title not available" ); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLAxisContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + switch( nElement ) + { + case XML_ELEMENT(CHART, XML_TITLE): + { + Reference< drawing::XShape > xTitleShape = getTitleShape(); + return new SchXMLTitleContext( m_rImportHelper, GetImport(), + m_aCurrentAxis.aTitle, + xTitleShape ); + } + break; + + case XML_ELEMENT(CHART, XML_CATEGORIES): + m_aCurrentAxis.bHasCategories = true; + return new SchXMLCategoriesContext( GetImport(), + m_rCategoriesAddress ); + break; + + case XML_ELEMENT(CHART, XML_DATE_SCALE): + case XML_ELEMENT(CHART_EXT, XML_DATE_SCALE): + m_bDateScaleImported = true; + return new DateScaleContext( GetImport(), m_xAxisProps ); + + case XML_ELEMENT(CHART, XML_GRID): + { + bool bIsMajor = true; // default value for class is "major" + OUString sAutoStyleName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(CHART, XML_CLASS): + if( IsXMLToken( aIter, XML_MINOR ) ) + bIsMajor = false; + break; + case XML_ELEMENT(CHART, XML_STYLE_NAME): + sAutoStyleName = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + CreateGrid( sAutoStyleName, bIsMajor ); + + // don't create a context => use default context. grid elements are empty + } + break; + + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + break; + } + + return nullptr; +} + +void SchXMLAxisContext::endFastElement(sal_Int32 ) +{ + if( !m_bDateScaleImported && m_nAxisType==chart::ChartAxisType::AUTOMATIC ) + { + Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(), m_aCurrentAxis.eDimension, m_aCurrentAxis.nAxisIndex ) ); + if( xAxis.is() ) + { + chart2::ScaleData aScaleData( xAxis->getScaleData()); + aScaleData.AutoDateAxis = false;//different default for older documents + xAxis->setScaleData( aScaleData ); + } + } + + SetAxisTitle(); +} + +namespace +{ + +Reference< chart2::XAxis > lcl_getAxis( const Reference< chart2::XCoordinateSystem >& rCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex ) +{ + Reference< chart2::XAxis > xAxis; + try + { + xAxis = rCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ); + } + catch( uno::Exception & ) + { + } + return xAxis; +} + +} // anonymous namespace + +void SchXMLAxisContext::CorrectAxisPositions( const Reference< chart2::XChartDocument >& xNewDoc, + std::u16string_view rChartTypeServiceName, + std::u16string_view rODFVersionOfFile, + bool bAxisPositionAttributeImported ) +{ + if( !(rODFVersionOfFile.empty() || rODFVersionOfFile == u"1.0" || rODFVersionOfFile == u"1.1" + || ( rODFVersionOfFile == u"1.2" && !bAxisPositionAttributeImported )) ) + return; + + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDoc->getFirstDiagram(), uno::UNO_QUERY_THROW ); + uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + if( aCooSysSeq.hasElements() ) + { + Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] ); + if( xCooSys.is() ) + { + Reference< chart2::XAxis > xMainXAxis = lcl_getAxis( xCooSys, 0, 0 ); + Reference< chart2::XAxis > xMainYAxis = lcl_getAxis( xCooSys, 1, 0 ); + //Reference< chart2::XAxis > xMajorZAxis = lcl_getAxis( xCooSys, 2, 0 ); + Reference< chart2::XAxis > xSecondaryXAxis = lcl_getAxis( xCooSys, 0, 1 ); + Reference< chart2::XAxis > xSecondaryYAxis = lcl_getAxis( xCooSys, 1, 1 ); + + Reference< beans::XPropertySet > xMainXAxisProp( xMainXAxis, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xMainYAxisProp( xMainYAxis, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xSecondaryXAxisProp( xSecondaryXAxis, uno::UNO_QUERY ); + Reference< beans::XPropertySet > xSecondaryYAxisProp( xSecondaryYAxis, uno::UNO_QUERY ); + + if( xMainXAxisProp.is() && xMainYAxisProp.is() ) + { + chart2::ScaleData aMainXScale = xMainXAxis->getScaleData(); + if( rChartTypeServiceName == u"com.sun.star.chart2.ScatterChartType" ) + { + xMainYAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_VALUE) ); + double fCrossoverValue = 0.0; + aMainXScale.Origin >>= fCrossoverValue; + xMainYAxisProp->setPropertyValue("CrossoverValue" + , uno::Any( fCrossoverValue ) ); + + if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE ) + { + xMainYAxisProp->setPropertyValue("LabelPosition" + , uno::Any( css::chart::ChartAxisLabelPosition_OUTSIDE_END) ); + xMainYAxisProp->setPropertyValue("MarkPosition" + , uno::Any( css::chart::ChartAxisMarkPosition_AT_LABELS) ); + if( xSecondaryYAxisProp.is() ) + xSecondaryYAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_START) ); + } + else + { + xMainYAxisProp->setPropertyValue("LabelPosition" + , uno::Any( css::chart::ChartAxisLabelPosition_OUTSIDE_START) ); + xMainYAxisProp->setPropertyValue("MarkPosition" + , uno::Any( css::chart::ChartAxisMarkPosition_AT_LABELS) ); + if( xSecondaryYAxisProp.is() ) + xSecondaryYAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_END) ); + } + } + else + { + if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE ) + { + xMainYAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_END) ); + if( xSecondaryYAxisProp.is() ) + xSecondaryYAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_START) ); + } + else + { + xMainYAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_START) ); + if( xSecondaryYAxisProp.is() ) + xSecondaryYAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_END) ); + } + } + + chart2::ScaleData aMainYScale = xMainYAxis->getScaleData(); + xMainXAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_VALUE) ); + double fCrossoverValue = 0.0; + aMainYScale.Origin >>= fCrossoverValue; + xMainXAxisProp->setPropertyValue("CrossoverValue" + , uno::Any( fCrossoverValue ) ); + + if( aMainYScale.Orientation == chart2::AxisOrientation_REVERSE ) + { + xMainXAxisProp->setPropertyValue("LabelPosition" + , uno::Any( css::chart::ChartAxisLabelPosition_OUTSIDE_END) ); + xMainXAxisProp->setPropertyValue("MarkPosition" + , uno::Any( css::chart::ChartAxisMarkPosition_AT_LABELS) ); + if( xSecondaryXAxisProp.is() ) + xSecondaryXAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_START) ); + } + else + { + xMainXAxisProp->setPropertyValue("LabelPosition" + , uno::Any( css::chart::ChartAxisLabelPosition_OUTSIDE_START) ); + xMainXAxisProp->setPropertyValue("MarkPosition" + , uno::Any( css::chart::ChartAxisMarkPosition_AT_LABELS) ); + if( xSecondaryXAxisProp.is() ) + xSecondaryXAxisProp->setPropertyValue("CrossoverPosition" + , uno::Any( css::chart::ChartAxisPosition_END) ); + } + } + } + } + } + catch( uno::Exception & ) + { + } +} + +SchXMLCategoriesContext::SchXMLCategoriesContext( + SvXMLImport& rImport, + OUString& rAddress ) : + SvXMLImportContext( rImport ), + mrAddress( rAddress ) +{ +} + +void SchXMLCategoriesContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TABLE, XML_CELL_RANGE_ADDRESS) ) + mrAddress = aIter.toString(); + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +DateScaleContext::DateScaleContext( + SvXMLImport& rImport, + const Reference< beans::XPropertySet >& rAxisProps ) : + SvXMLImportContext( rImport ), + m_xAxisProps( rAxisProps ) +{ +} + +namespace +{ +sal_Int32 lcl_getTimeUnit( const sax_fastparser::FastAttributeList::FastAttributeIter& rValue ) +{ + sal_Int32 nTimeUnit = css::chart::TimeUnit::DAY; + if( IsXMLToken( rValue, XML_DAYS ) ) + nTimeUnit = css::chart::TimeUnit::DAY; + else if( IsXMLToken( rValue, XML_MONTHS ) ) + nTimeUnit = css::chart::TimeUnit::MONTH; + else if( IsXMLToken( rValue, XML_YEARS ) ) + nTimeUnit = css::chart::TimeUnit::YEAR; + return nTimeUnit; +} + +} + +void DateScaleContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( !m_xAxisProps.is() ) + return; + + // parse attributes + bool bSetNewIncrement=false; + chart::TimeIncrement aIncrement; + m_xAxisProps->getPropertyValue("TimeIncrement") >>= aIncrement; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(CHART, XML_BASE_TIME_UNIT): + { + aIncrement.TimeResolution <<= lcl_getTimeUnit(aIter); + bSetNewIncrement = true; + } + break; + case XML_ELEMENT(CHART, XML_MAJOR_INTERVAL_VALUE): + { + chart::TimeInterval aInterval(1,0); + aIncrement.MajorTimeInterval >>= aInterval; + ::sax::Converter::convertNumber( aInterval.Number, aIter.toView() ); + aIncrement.MajorTimeInterval <<= aInterval; + bSetNewIncrement = true; + } + break; + case XML_ELEMENT(CHART, XML_MAJOR_INTERVAL_UNIT): + { + chart::TimeInterval aInterval(1,0); + aIncrement.MajorTimeInterval >>= aInterval; + aInterval.TimeUnit = lcl_getTimeUnit(aIter); + aIncrement.MajorTimeInterval <<= aInterval; + bSetNewIncrement = true; + } + break; + case XML_ELEMENT(CHART, XML_MINOR_INTERVAL_VALUE): + { + chart::TimeInterval aInterval(1,0); + aIncrement.MinorTimeInterval >>= aInterval; + ::sax::Converter::convertNumber( aInterval.Number, aIter.toView() ); + aIncrement.MinorTimeInterval <<= aInterval; + bSetNewIncrement = true; + } + break; + case XML_ELEMENT(CHART, XML_MINOR_INTERVAL_UNIT): + { + chart::TimeInterval aInterval(1,0); + aIncrement.MinorTimeInterval >>= aInterval; + aInterval.TimeUnit = lcl_getTimeUnit(aIter); + aIncrement.MinorTimeInterval <<= aInterval; + bSetNewIncrement = true; + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( bSetNewIncrement ) + m_xAxisProps->setPropertyValue("TimeIncrement", uno::Any( aIncrement ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLAxisContext.hxx b/xmloff/source/chart/SchXMLAxisContext.hxx new file mode 100644 index 000000000..f128edeab --- /dev/null +++ b/xmloff/source/chart/SchXMLAxisContext.hxx @@ -0,0 +1,77 @@ +/* -*- 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 +#include + +#include "transporttypes.hxx" + +#include +#include + +class SchXMLAxisContext : public SvXMLImportContext +{ +public: + SchXMLAxisContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + css::uno::Reference< css::chart::XDiagram > const & xDiagram, + std::vector< SchXMLAxis >& aAxes, + OUString& rCategoriesAddress, + bool bAddMissingXAxisForNetCharts, + bool bAdaptWrongPercentScaleValues, + bool bAdaptXAxisOrientationForOld2DBarCharts, + bool& rbAxisPositionAttributeImported ); + virtual ~SchXMLAxisContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + static void CorrectAxisPositions( const css::uno::Reference< css::chart2::XChartDocument >& xNewDoc, + std::u16string_view rChartTypeServiceName, + std::u16string_view rODFVersionOfFile, + bool bAxisPositionAttributeImported ); + +private: + SchXMLImportHelper& m_rImportHelper; + css::uno::Reference< css::chart::XDiagram > m_xDiagram; + SchXMLAxis m_aCurrentAxis; + std::vector< SchXMLAxis >& m_rAxes; + css::uno::Reference< css::beans::XPropertySet > m_xAxisProps; + OUString m_aAutoStyleName; + OUString& m_rCategoriesAddress; + sal_Int32 m_nAxisType;//css::chart::ChartAxisType + bool m_bAxisTypeImported; + bool m_bDateScaleImported; + bool m_bAddMissingXAxisForNetCharts; //to correct errors from older versions + bool m_bAdaptWrongPercentScaleValues; //to correct errors from older versions + bool m_bAdaptXAxisOrientationForOld2DBarCharts; //to correct different behaviour from older versions + bool& m_rbAxisPositionAttributeImported; + + css::uno::Reference< css::drawing::XShape > getTitleShape() const; + void CreateGrid( const OUString& sAutoStyleName, bool bIsMajor ); + void CreateAxis(); + void SetAxisTitle(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLCalculationSettingsContext.cxx b/xmloff/source/chart/SchXMLCalculationSettingsContext.cxx new file mode 100644 index 000000000..fbe54c96d --- /dev/null +++ b/xmloff/source/chart/SchXMLCalculationSettingsContext.cxx @@ -0,0 +1,73 @@ +/* -*- 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 "SchXMLCalculationSettingsContext.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SchXMLCalculationSettingsContext::SchXMLCalculationSettingsContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +: SvXMLImportContext ( rImport ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TABLE, XML_DATE_VALUE) ) + { + util::DateTime aNullDate; + if (::sax::Converter::parseDateTime(aNullDate, aIter.toView())) + m_aNullDate <<= aNullDate; + else + SAL_WARN("xmloff", "SchXMLCalculationSettingsContext: broken DateTime '" << aIter.toView() << "'"); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLCalculationSettingsContext::createFastChildContext( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new SchXMLCalculationSettingsContext(GetImport(),xAttrList); +} + +void SchXMLCalculationSettingsContext::endFastElement(sal_Int32 ) +{ + if ( m_aNullDate.hasValue() ) + { + Reference < XPropertySet > xPropSet ( GetImport().GetModel(), UNO_QUERY ); + xPropSet->setPropertyValue ( "NullDate", m_aNullDate ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLCalculationSettingsContext.hxx b/xmloff/source/chart/SchXMLCalculationSettingsContext.hxx new file mode 100644 index 000000000..b10f1545d --- /dev/null +++ b/xmloff/source/chart/SchXMLCalculationSettingsContext.hxx @@ -0,0 +1,39 @@ +/* -*- 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 + +class SchXMLCalculationSettingsContext : public SvXMLImportContext +{ + css::uno::Any m_aNullDate; +public: + SchXMLCalculationSettingsContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLChartContext.cxx b/xmloff/source/chart/SchXMLChartContext.cxx new file mode 100644 index 000000000..23ea2f780 --- /dev/null +++ b/xmloff/source/chart/SchXMLChartContext.cxx @@ -0,0 +1,1235 @@ +/* -*- 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 "SchXMLChartContext.hxx" +#include +#include "SchXMLLegendContext.hxx" +#include "SchXMLPlotAreaContext.hxx" +#include "SchXMLParagraphContext.hxx" +#include "SchXMLTableContext.hxx" +#include "SchXMLSeries2Context.hxx" +#include "SchXMLTools.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; +using com::sun::star::uno::Reference; +using namespace ::SchXMLTools; + +namespace +{ + +void lcl_setRoleAtLabeledSequence( + const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq, + const OUString &rRole ) +{ + // set role of sequence + uno::Reference< chart2::data::XDataSequence > xValues( xLSeq->getValues()); + if( xValues.is()) + { + uno::Reference< beans::XPropertySet > xProp( xValues, uno::UNO_QUERY ); + if( xProp.is()) + xProp->setPropertyValue("Role", uno::Any( rRole )); + } +} + +void lcl_MoveDataToCandleStickSeries( + const uno::Reference< chart2::data::XDataSource > & xDataSource, + const uno::Reference< chart2::XDataSeries > & xDestination, + const OUString & rRole ) +{ + try + { + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledSeq( + xDataSource->getDataSequences()); + if( aLabeledSeq.hasElements()) + { + lcl_setRoleAtLabeledSequence( aLabeledSeq[0], rRole ); + + // add to data series + uno::Reference< chart2::data::XDataSource > xSource( xDestination, uno::UNO_QUERY_THROW ); + // @todo: realloc only once outside this function + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aData( xSource->getDataSequences()); + aData.realloc( aData.getLength() + 1); + aData.getArray()[ aData.getLength() - 1 ] = aLabeledSeq[0]; + uno::Reference< chart2::data::XDataSink > xSink( xDestination, uno::UNO_QUERY_THROW ); + xSink->setData( aData ); + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception caught while moving data to candlestick series" ); + } +} + +void lcl_setRoleAtFirstSequence( + const uno::Reference< chart2::XDataSeries > & xSeries, + const OUString & rRole ) +{ + uno::Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); + if( xSource.is()) + { + uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSeq( xSource->getDataSequences()); + if( aSeq.hasElements()) + lcl_setRoleAtLabeledSequence( aSeq[0], rRole ); + } +} + +void lcl_removeEmptyChartTypeGroups( const uno::Reference< chart2::XChartDocument > & xDoc ) +{ + if( ! xDoc.is()) + return; + + uno::Reference< chart2::XDiagram > xDia( xDoc->getFirstDiagram()); + if( ! xDia.is()) + return; + + try + { + // count all charttype groups to be able to leave at least one + sal_Int32 nRemainingGroups = 0; + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW ); + const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + for( auto const & i : aCooSysSeq ) + { + uno::Reference< chart2::XChartTypeContainer > xCTCnt( i, uno::UNO_QUERY_THROW ); + nRemainingGroups += xCTCnt->getChartTypes().getLength(); + } + + // delete all empty groups, but leave at least group (empty or not) + for( sal_Int32 nI = aCooSysSeq.getLength(); nI-- && (nRemainingGroups > 1); ) + { + uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes()); + for( sal_Int32 nJ=aCTSeq.getLength(); nJ-- && (nRemainingGroups > 1); ) + { + uno::Reference< chart2::XDataSeriesContainer > xDSCnt( aCTSeq[nJ], uno::UNO_QUERY_THROW ); + if( !xDSCnt->getDataSeries().hasElements() ) + { + // note: iterator stays valid as we have a local sequence + xCTCnt->removeChartType( aCTSeq[nJ] ); + --nRemainingGroups; + } + } + } + } + catch(const uno::Exception&) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught while removing empty chart types"); + } +} + +uno::Sequence< sal_Int32 > lcl_getNumberSequenceFromString( const OUString& rStr, bool bAddOneToEachOldIndex ) +{ + const sal_Unicode aSpace( ' ' ); + + // count number of entries + ::std::vector< sal_Int32 > aVec; + sal_Int32 nLastPos = 0; + sal_Int32 nPos = 0; + while( nPos != -1 ) + { + nPos = rStr.indexOf( aSpace, nLastPos ); + if( nPos > nLastPos ) + { + aVec.push_back( o3tl::toInt32(rStr.subView( nLastPos, (nPos - nLastPos) )) ); + } + if( nPos != -1 ) + nLastPos = nPos + 1; + } + // last entry + if( nLastPos != 0 && + rStr.getLength() > nLastPos ) + { + aVec.push_back( o3tl::toInt32(rStr.subView( nLastPos )) ); + } + + const sal_Int32 nVecSize = aVec.size(); + uno::Sequence< sal_Int32 > aSeq( nVecSize ); + + if(!bAddOneToEachOldIndex) + { + sal_Int32* pSeqArr = aSeq.getArray(); + for( nPos = 0; nPos < nVecSize; ++nPos ) + { + pSeqArr[ nPos ] = aVec[ nPos ]; + } + } + else if( bAddOneToEachOldIndex ) + { + aSeq.realloc( nVecSize+1 ); + auto pSeqArr = aSeq.getArray(); + pSeqArr[0]=0; + + for( nPos = 0; nPos < nVecSize; ++nPos ) + { + pSeqArr[ nPos+1 ] = aVec[ nPos ]+1; + } + } + + return aSeq; +} + +} // anonymous namespace + +SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ), + m_bHasRangeAtPlotArea( false ), + m_bHasTableElement( false ), + mbAllRangeAddressesAvailable( true ), + mbColHasLabels( false ), + mbRowHasLabels( false ), + meDataRowSource( chart::ChartDataRowSource_COLUMNS ), + mbIsStockChart( false ) +{ +} + +SchXMLChartContext::~SchXMLChartContext() +{} + +static bool lcl_hasServiceName(Reference const & xFactory, OUString const & rServiceName) +{ + const uno::Sequence aServiceNames(xFactory->getAvailableServiceNames()); + + return std::find(aServiceNames.begin(), aServiceNames.end(), rServiceName) != aServiceNames.end(); +} + +void setDataProvider(uno::Reference const & xChartDoc, OUString const & sDataPilotSource) +{ + if (!xChartDoc.is()) + return; + + try + { + uno::Reference xChild(xChartDoc, uno::UNO_QUERY); + uno::Reference xDataReceiver(xChartDoc, uno::UNO_QUERY); + if (xChild.is() && xDataReceiver.is()) + { + bool bHasOwnData = true; + + Reference xFact(xChild->getParent(), uno::UNO_QUERY); + if (xFact.is()) + { + if (!xChartDoc->getDataProvider().is()) + { + bool bHasDataPilotSource = !sDataPilotSource.isEmpty(); + OUString aDataProviderServiceName("com.sun.star.chart2.data.DataProvider"); + if (bHasDataPilotSource) + aDataProviderServiceName = "com.sun.star.chart2.data.PivotTableDataProvider"; + + if (lcl_hasServiceName(xFact, aDataProviderServiceName)) + { + Reference xProvider(xFact->createInstance(aDataProviderServiceName), uno::UNO_QUERY); + + if (xProvider.is()) + { + if (bHasDataPilotSource) + { + Reference xPivotTableDataProvider(xProvider, uno::UNO_QUERY); + xPivotTableDataProvider->setPivotTableName(sDataPilotSource); + xDataReceiver->attachDataProvider(xProvider); + bHasOwnData = !xPivotTableDataProvider->hasPivotTable(); + } + else + { + xDataReceiver->attachDataProvider(xProvider); + bHasOwnData = false; + } + } + } + } + else + bHasOwnData = false; + } + // else we have no parent => we have our own data + + if (bHasOwnData && ! xChartDoc->hasInternalDataProvider()) + xChartDoc->createInternalDataProvider(false); + } + } + catch (const uno::Exception &) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "SchXMLChartContext::StartElement()"); + } +} + +void SchXMLChartContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // parse attributes + + uno::Reference< embed::XVisualObject > xVisualObject( mrImportHelper.GetChartDocument(), uno::UNO_QUERY); + SAL_WARN_IF(!xVisualObject.is(), "xmloff.chart", "need xVisualObject for page size"); + if( xVisualObject.is() ) + maChartSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); //#i103460# take the size given from the parent frame as default + + OUString sAutoStyleName; + OUString aOldChartTypeName; + bool bHasAddin = false; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(LO_EXT, XML_DATA_PILOT_SOURCE): + msDataPilotSource = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + m_aXLinkHRefAttributeToIndicateDataProvider = aIter.toString(); + break; + case XML_ELEMENT(CHART, XML_CLASS): + { + OUString aValue = aIter.toString(); + OUString sClassName; + sal_uInt16 nClassPrefix = + GetImport().GetNamespaceMap().GetKeyByAttrValueQName( + aValue, &sClassName ); + if( XML_NAMESPACE_CHART == nClassPrefix ) + { + SchXMLChartTypeEnum eChartTypeEnum = SchXMLTools::GetChartTypeEnum( sClassName ); + if( eChartTypeEnum != XML_CHART_CLASS_UNKNOWN ) + { + aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( sClassName, true /* bUseOldNames */ ); + maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( sClassName, false /* bUseOldNames */ ); + switch( eChartTypeEnum ) + { + case XML_CHART_CLASS_STOCK: + mbIsStockChart = true; + break; + default: + break; + } + } + } + else if( XML_NAMESPACE_OOO == nClassPrefix ) + { + // service is taken from add-in-name attribute + bHasAddin = true; + + aOldChartTypeName = sClassName; + maChartTypeServiceName = sClassName; + } + } + break; + + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maChartSize.Width, aIter.toView() ); + break; + + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maChartSize.Height, aIter.toView() ); + break; + + case XML_ELEMENT(CHART, XML_STYLE_NAME): + sAutoStyleName = aIter.toString(); + break; + + case XML_ELEMENT(CHART, XML_COLUMN_MAPPING): + msColTrans = aIter.toString(); + break; + case XML_ELEMENT(CHART, XML_ROW_MAPPING): + msRowTrans = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + uno::Reference xDoc = mrImportHelper.GetChartDocument(); + uno::Reference xNewDoc(xDoc, uno::UNO_QUERY); + + setDataProvider(xNewDoc, msDataPilotSource); + + if( aOldChartTypeName.isEmpty() ) + { + SAL_WARN("xmloff.chart", "need a charttype to create a diagram" ); + //set a fallback value: + const OUString& aChartClass_Bar( GetXMLToken(XML_BAR ) ); + aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, true /* bUseOldNames */ ); + maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, false /* bUseOldNames */ ); + } + + // Set the size of the draw page. + if( xVisualObject.is() ) + xVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, maChartSize ); + + InitChart( aOldChartTypeName); + + if( bHasAddin ) + { + //correct charttype service name when having an addin + //and don't refresh addin during load + uno::Reference< beans::XPropertySet > xDocProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); + if( xDocProp.is() ) + { + try + { + xDocProp->getPropertyValue("BaseDiagram") >>= aOldChartTypeName; + maChartTypeServiceName = SchXMLTools::GetNewChartTypeName( aOldChartTypeName ); + xDocProp->setPropertyValue("RefreshAddInAllowed", uno::Any( false) ); + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception during import SchXMLChartContext::StartElement" ); + } + } + } + + // set auto-styles for Area + uno::Reference xProp = mrImportHelper.GetChartDocument()->getArea(); + mrImportHelper.FillAutoStyle(sAutoStyleName, xProp); +} + +namespace +{ + +struct NewDonutSeries +{ + css::uno::Reference< css::chart2::XDataSeries > m_xSeries; + OUString msStyleName; + sal_Int32 mnAttachedAxis; + + ::std::vector< OUString > m_aSeriesStyles; + ::std::vector< OUString > m_aPointStyles; + + NewDonutSeries( const css::uno::Reference< css::chart2::XDataSeries >& xSeries, sal_Int32 nPointCount ) + : m_xSeries( xSeries ) + , mnAttachedAxis( 1 ) + { + m_aPointStyles.resize(nPointCount); + m_aSeriesStyles.resize(nPointCount); + } + + void setSeriesStyleNameToPoint( const OUString& rStyleName, sal_Int32 nPointIndex ) + { + SAL_WARN_IF(nPointIndex >= static_cast(m_aSeriesStyles.size()), "xmloff.chart", "donut point <-> series count mismatch"); + if( nPointIndex < static_cast(m_aSeriesStyles.size()) ) + m_aSeriesStyles[nPointIndex]=rStyleName; + } + + void setPointStyleNameToPoint( const OUString& rStyleName, sal_Int32 nPointIndex ) + { + SAL_WARN_IF(nPointIndex >= static_cast(m_aPointStyles.size()), "xmloff.chart", "donut point <-> series count mismatch"); + if( nPointIndex < static_cast(m_aPointStyles.size()) ) + m_aPointStyles[nPointIndex]=rStyleName; + } + + ::std::vector< DataRowPointStyle > creatStyleVector() + { + ::std::vector< DataRowPointStyle > aRet; + + DataRowPointStyle aSeriesStyle( DataRowPointStyle::DATA_SERIES + , m_xSeries, -1, 1, msStyleName, mnAttachedAxis ); + aRet.push_back( aSeriesStyle ); + + sal_Int32 nPointIndex=0; + for (auto const& pointStyle : m_aPointStyles) + { + DataRowPointStyle aPointStyle( DataRowPointStyle::DATA_POINT + , m_xSeries, nPointIndex, 1, pointStyle, mnAttachedAxis ); + if( nPointIndex < static_cast(m_aSeriesStyles.size()) ) + { + aPointStyle.msSeriesStyleNameForDonuts = m_aSeriesStyles[nPointIndex]; + } + if( !aPointStyle.msSeriesStyleNameForDonuts.isEmpty() + || !aPointStyle.msStyleName.isEmpty() ) + aRet.push_back( aPointStyle ); + ++nPointIndex; + } + + return aRet; + } +}; + +void lcl_swapPointAndSeriesStylesForDonutCharts( ::std::vector< DataRowPointStyle >& rStyleVector + , ::std::map< css::uno::Reference< css::chart2::XDataSeries> , sal_Int32 >&& aSeriesMap ) +{ + //detect old series count + //and add old series to aSeriesMap + sal_Int32 nOldSeriesCount = 0; + { + sal_Int32 nMaxOldSeriesIndex = 0; + sal_Int32 nOldSeriesIndex = 0; + for (auto const& style : rStyleVector) + { + DataRowPointStyle aStyle(style); + if(aStyle.meType == DataRowPointStyle::DATA_SERIES && + aStyle.m_xSeries.is() ) + { + nMaxOldSeriesIndex = nOldSeriesIndex; + + if( aSeriesMap.end() == aSeriesMap.find(aStyle.m_xSeries) ) + aSeriesMap[aStyle.m_xSeries] = nOldSeriesIndex; + + nOldSeriesIndex++; + } + } + nOldSeriesCount = nMaxOldSeriesIndex+1; + } + + //initialize new series styles + ::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapEnd( aSeriesMap.end() ); + + //sort by index + ::std::vector< NewDonutSeries > aNewSeriesVector; + { + ::std::map< sal_Int32, Reference< chart2::XDataSeries > > aIndexSeriesMap; + for (auto const& series : aSeriesMap) + aIndexSeriesMap[series.second] = series.first; + + for (auto const& indexSeries : aIndexSeriesMap) + aNewSeriesVector.emplace_back(indexSeries.second,nOldSeriesCount ); + } + + //overwrite attached axis information according to old series styles + for (auto const& style : rStyleVector) + { + DataRowPointStyle aStyle(style); + if(aStyle.meType == DataRowPointStyle::DATA_SERIES ) + { + auto aSeriesMapIt = aSeriesMap.find( aStyle.m_xSeries ); + if( aSeriesMapIt != aSeriesMapEnd && aSeriesMapIt->second < static_cast(aNewSeriesVector.size()) ) + aNewSeriesVector[aSeriesMapIt->second].mnAttachedAxis = aStyle.mnAttachedAxis; + } + } + + //overwrite new series style names with old series style name information + for (auto const& style : rStyleVector) + { + DataRowPointStyle aStyle(style); + if( aStyle.meType == DataRowPointStyle::DATA_SERIES ) + { + auto aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries); + if( aSeriesMapEnd != aSeriesMapIt ) + { + sal_Int32 nNewPointIndex = aSeriesMapIt->second; + + for (auto & newSeries : aNewSeriesVector) + newSeries.setSeriesStyleNameToPoint( aStyle.msStyleName, nNewPointIndex ); + } + } + } + + //overwrite new series style names with point style name information + for (auto const& style : rStyleVector) + { + DataRowPointStyle aStyle(style); + if( aStyle.meType == DataRowPointStyle::DATA_POINT ) + { + auto aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries); + if( aSeriesMapEnd != aSeriesMapIt ) + { + sal_Int32 nNewPointIndex = aSeriesMapIt->second; + sal_Int32 nNewSeriesIndex = aStyle.m_nPointIndex; + sal_Int32 nRepeatCount = aStyle.m_nPointRepeat; + + while( nRepeatCount && (nNewSeriesIndex>=0) && (o3tl::make_unsigned(nNewSeriesIndex)< aNewSeriesVector.size() ) ) + { + NewDonutSeries& rNewSeries( aNewSeriesVector[nNewSeriesIndex] ); + rNewSeries.setPointStyleNameToPoint( aStyle.msStyleName, nNewPointIndex ); + + nRepeatCount--; + nNewSeriesIndex++; + } + } + } + } + + //put information from aNewSeriesVector to output parameter rStyleVector + rStyleVector.clear(); + + for (auto & newSeries : aNewSeriesVector) + { + ::std::vector< DataRowPointStyle > aVector( newSeries.creatStyleVector() ); + rStyleVector.insert(rStyleVector.end(),aVector.begin(),aVector.end()); + } +} + +bool lcl_SpecialHandlingForDonutChartNeeded( + std::u16string_view rServiceName, + const SvXMLImport & rImport ) +{ + bool bResult = false; + if( rServiceName == u"com.sun.star.chart2.DonutChartType" ) + { + bResult = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( rImport.GetModel() ); + } + return bResult; +} + +} // anonymous namespace + +static void lcl_ApplyDataFromRectangularRangeToDiagram( + const uno::Reference< chart2::XChartDocument >& xNewDoc + , const OUString& rRectangularRange + , css::chart::ChartDataRowSource eDataRowSource + , bool bRowHasLabels, bool bColHasLabels + , bool bSwitchOnLabelsAndCategoriesForOwnData + , const OUString& sColTrans + , const OUString& sRowTrans ) +{ + if( !xNewDoc.is() ) + return; + + uno::Reference< chart2::XDiagram > xNewDia( xNewDoc->getFirstDiagram()); + uno::Reference< chart2::data::XDataProvider > xDataProvider( xNewDoc->getDataProvider() ); + if( !xNewDia.is() || !xDataProvider.is() ) + return; + + bool bFirstCellAsLabel = + (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bRowHasLabels : bColHasLabels; + bool bHasCateories = + (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bColHasLabels : bRowHasLabels; + + if( bSwitchOnLabelsAndCategoriesForOwnData ) + { + bFirstCellAsLabel = true; + bHasCateories = true; + } + + uno::Sequence< beans::PropertyValue > aArgs{ + beans::PropertyValue( + "CellRangeRepresentation", + -1, uno::Any( rRectangularRange ), + beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "DataRowSource", + -1, uno::Any( eDataRowSource ), + beans::PropertyState_DIRECT_VALUE ), + beans::PropertyValue( + "FirstCellAsLabel", + -1, uno::Any( bFirstCellAsLabel ), + beans::PropertyState_DIRECT_VALUE ) + }; + + if( !sColTrans.isEmpty() || !sRowTrans.isEmpty() ) + { + aArgs.realloc( aArgs.getLength() + 1 ); + aArgs.getArray()[ sal::static_int_cast(aArgs.getLength()) - 1 ] = beans::PropertyValue( + "SequenceMapping", + -1, uno::Any( !sColTrans.isEmpty() + ? lcl_getNumberSequenceFromString( sColTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) + : lcl_getNumberSequenceFromString( sRowTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) ), + beans::PropertyState_DIRECT_VALUE ); + } + + //work around wrong writer ranges ( see Issue 58464 ) + { + OUString aChartOleObjectName; + if( xNewDoc.is() ) + { + utl::MediaDescriptor aMediaDescriptor( xNewDoc->getArgs() ); + + utl::MediaDescriptor::const_iterator aIt( + aMediaDescriptor.find( OUString( "HierarchicalDocumentName" ))); + if( aIt != aMediaDescriptor.end() ) + { + aChartOleObjectName = (*aIt).second.get< OUString >(); + } + } + if( !aChartOleObjectName.isEmpty() ) + { + aArgs.realloc( aArgs.getLength() + 1 ); + aArgs.getArray()[ sal::static_int_cast(aArgs.getLength()) - 1 ] = beans::PropertyValue( + "ChartOleObjectName", + -1, uno::Any( aChartOleObjectName ), + beans::PropertyState_DIRECT_VALUE ); + } + } + + uno::Reference< chart2::data::XDataSource > xDataSource( + xDataProvider->createDataSource( aArgs )); + + aArgs.realloc( aArgs.getLength() + 2 ); + auto pArgs = aArgs.getArray(); + pArgs[ sal::static_int_cast(aArgs.getLength()) - 2 ] = beans::PropertyValue( + "HasCategories", + -1, uno::Any( bHasCateories ), + beans::PropertyState_DIRECT_VALUE ); + pArgs[ sal::static_int_cast(aArgs.getLength()) - 1 ] = beans::PropertyValue( + "UseCategoriesAsX", + -1, uno::Any( false ),//categories in ODF files are not to be used as x values (independent from what is offered in our ui) + beans::PropertyState_DIRECT_VALUE ); + + xNewDia->setDiagramData( xDataSource, aArgs ); +} + +void SchXMLChartContext::endFastElement(sal_Int32 ) +{ + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY ); + uno::Reference< chart2::XChartDocument > xNewDoc( xDoc, uno::UNO_QUERY ); + + if( xProp.is()) + { + if( !maMainTitle.isEmpty()) + { + uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + try + { + xTitleProp->setPropertyValue("String", uno::Any(maMainTitle) ); + } + catch(const beans::UnknownPropertyException&) + { + SAL_WARN("xmloff.chart", "Property String for Title not available" ); + } + } + } + if( !maSubTitle.isEmpty()) + { + uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getSubTitle(), uno::UNO_QUERY ); + if( xTitleProp.is()) + { + try + { + xTitleProp->setPropertyValue("String", uno::Any(maSubTitle) ); + } + catch(const beans::UnknownPropertyException&) + { + SAL_WARN("xmloff.chart", "Property String for Title not available" ); + } + } + } + } + + // cleanup: remove empty chart type groups + lcl_removeEmptyChartTypeGroups( xNewDoc ); + + // set stack mode before a potential chart type detection (in case we have a rectangular range) + uno::Reference< chart::XDiagram > xDiagram( xDoc->getDiagram() ); + uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY ); + if( xDiaProp.is()) + { + if( maSeriesDefaultsAndStyles.maStackedDefault.hasValue()) + xDiaProp->setPropertyValue("Stacked",maSeriesDefaultsAndStyles.maStackedDefault); + if( maSeriesDefaultsAndStyles.maPercentDefault.hasValue()) + xDiaProp->setPropertyValue("Percent",maSeriesDefaultsAndStyles.maPercentDefault); + if( maSeriesDefaultsAndStyles.maDeepDefault.hasValue()) + xDiaProp->setPropertyValue("Deep",maSeriesDefaultsAndStyles.maDeepDefault); + if( maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault.hasValue()) + xDiaProp->setPropertyValue("StackedBarsConnected",maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault); + } + + //the OOo 2.0 implementation and older has a bug with donuts + bool bSpecialHandlingForDonutChart = lcl_SpecialHandlingForDonutChartNeeded( + maChartTypeServiceName, GetImport()); + + // apply data + if(!xNewDoc.is()) + return; + + bool bHasOwnData = false; + if( m_aXLinkHRefAttributeToIndicateDataProvider == "." ) //data comes from the chart itself + bHasOwnData = true; + else if( m_aXLinkHRefAttributeToIndicateDataProvider == ".." ) //data comes from the parent application + bHasOwnData = false; + else if( !m_aXLinkHRefAttributeToIndicateDataProvider.isEmpty() ) //not supported so far to get the data by sibling objects -> fall back to chart itself if data are available + bHasOwnData = m_bHasTableElement; + else + bHasOwnData = !m_bHasRangeAtPlotArea; + + if( xNewDoc->hasInternalDataProvider()) + { + if( !m_bHasTableElement && m_aXLinkHRefAttributeToIndicateDataProvider != "." ) + { + //#i103147# ODF, workaround broken files with a missing table:cell-range-address at the plot-area + bool bSwitchSuccessful = SchXMLTools::switchBackToDataProviderFromParent( xNewDoc, maLSequencesPerIndex ); + bHasOwnData = !bSwitchSuccessful; + } + else + bHasOwnData = true;//e.g. in case of copy->paste from calc to impress + } + else if( bHasOwnData ) + { + xNewDoc->createInternalDataProvider( false /* bCloneExistingData */ ); + } + if( bHasOwnData ) + msChartAddress = "all"; + + bool bSwitchRangesFromOuterToInternalIfNecessary = false; + if( !bHasOwnData && mbAllRangeAddressesAvailable ) + { + // special handling for stock chart (merge series together) + if( mbIsStockChart ) + MergeSeriesForStockChart(); + } + else if( !msChartAddress.isEmpty() ) + { + //own data or only rectangular range available + + if( xNewDoc->hasInternalDataProvider() ) + SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc ); + + bool bOlderThan2_3 = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( xNewDoc ); + bool bOldFileWithOwnDataFromRows = (bOlderThan2_3 && bHasOwnData && (meDataRowSource==chart::ChartDataRowSource_ROWS)); // in this case there are range addresses that are simply wrong. + + if( mbAllRangeAddressesAvailable && !bSpecialHandlingForDonutChart && !mbIsStockChart && + !bOldFileWithOwnDataFromRows ) + { + //bHasOwnData is true in this case! + //e.g. for normal files with own data or also in case of copy paste scenario (e.g. calc to impress) + bSwitchRangesFromOuterToInternalIfNecessary = true; + } + else + { + //apply data from rectangular range + + // create datasource from data provider with rectangular range parameters and change the diagram setDiagramData + try + { + if( bOlderThan2_3 && xDiaProp.is() )//for older charts the hidden cells were removed by calc on the fly + xDiaProp->setPropertyValue("IncludeHiddenCells",uno::Any(false)); + + // note: mbRowHasLabels means the first row contains labels, that means we have "column-descriptions", + // (analogously mbColHasLabels means we have "row-descriptions") + lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans ); + } + catch(const uno::Exception&) + { + //try to fallback to internal data + TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram try to fallback to internal data" ); + if(!bHasOwnData) + { + bHasOwnData = true; + msChartAddress = "all"; + if( !xNewDoc->hasInternalDataProvider() ) + { + xNewDoc->createInternalDataProvider( false /* bCloneExistingData */ ); + SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc ); + try + { + lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans ); + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram fallback to internal data failed also" ); + } + } + } + } + } + } + else + { + SAL_WARN("xmloff.chart", "Must not get here" ); + } + + // now all series and data point properties are available and can be set + { + if( bSpecialHandlingForDonutChart ) + { + uno::Reference< chart2::XDiagram > xNewDiagram( xNewDoc->getFirstDiagram() ); + lcl_swapPointAndSeriesStylesForDonutCharts( maSeriesDefaultsAndStyles.maSeriesStyleVector + , SchXMLSeriesHelper::getDataSeriesIndexMapFromDiagram(xNewDiagram) ); + } + + SchXMLSeries2Context::initSeriesPropertySets( maSeriesDefaultsAndStyles, xDoc ); + + //set defaults from diagram to the new series: + //check whether we need to remove lines from symbol only charts + bool bSwitchOffLinesForScatter = false; + { + bool bLinesOn = true; + if( (maSeriesDefaultsAndStyles.maLinesOnProperty >>= bLinesOn) && !bLinesOn ) + { + if( maChartTypeServiceName == "com.sun.star.chart2.ScatterChartType" ) + { + bSwitchOffLinesForScatter = true; + SchXMLSeries2Context::switchSeriesLinesOff( maSeriesDefaultsAndStyles.maSeriesStyleVector ); + } + } + } + SchXMLSeries2Context::setDefaultsToSeries( maSeriesDefaultsAndStyles ); + + // set autostyles for series and data points + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + const SvXMLStyleContext* pStyle = nullptr; + OUString sCurrStyleName; + + if( pStylesCtxt ) + { + //iterate over data-series first + //don't set series styles for donut charts + if( !bSpecialHandlingForDonutChart ) + { + SchXMLSeries2Context::setStylesToSeries( + maSeriesDefaultsAndStyles, pStylesCtxt, pStyle, + sCurrStyleName, mrImportHelper, GetImport(), + mbIsStockChart, maLSequencesPerIndex ); + // ... then set attributes for statistics (after their existence was set in the series) + SchXMLSeries2Context::setStylesToStatisticsObjects( + maSeriesDefaultsAndStyles, pStylesCtxt, + pStyle, sCurrStyleName ); + + SchXMLSeries2Context::setStylesToRegressionCurves( + maSeriesDefaultsAndStyles, pStylesCtxt, + pStyle, sCurrStyleName ); + } + } + + //#i98319# call switchRangesFromOuterToInternalIfNecessary before the data point styles are applied, otherwise in copy->paste scenario the data point styles do get lost + if( bSwitchRangesFromOuterToInternalIfNecessary ) + { + if( xNewDoc->hasInternalDataProvider() ) + SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( maTable, maLSequencesPerIndex, xNewDoc, meDataRowSource ); + } + + if( pStylesCtxt ) + { + // ... then iterate over data-point attributes, so the latter are not overwritten + SchXMLSeries2Context::setStylesToDataPoints( maSeriesDefaultsAndStyles + , pStylesCtxt, pStyle, sCurrStyleName, mrImportHelper, GetImport(), mbIsStockChart, bSpecialHandlingForDonutChart, bSwitchOffLinesForScatter ); + } + } + + if( xProp.is()) + xProp->setPropertyValue("RefreshAddInAllowed", uno::Any( true) ); +} + +void SchXMLChartContext::MergeSeriesForStockChart() +{ + OSL_ASSERT( mbIsStockChart ); + try + { + uno::Reference< chart::XChartDocument > xOldDoc( mrImportHelper.GetChartDocument()); + uno::Reference< chart2::XChartDocument > xDoc( xOldDoc, uno::UNO_QUERY_THROW ); + uno::Reference< chart2::XDiagram > xDiagram( xDoc->getFirstDiagram()); + if( ! xDiagram.is()) + return; + + bool bHasJapaneseCandlestick = true; + uno::Reference< chart2::XDataSeriesContainer > xDSContainer; + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW ); + const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + for( const auto& rCooSys : aCooSysSeq ) + { + uno::Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY_THROW ); + const uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); + auto pChartType = std::find_if(aChartTypes.begin(), aChartTypes.end(), + [](const auto& rChartType) { return rChartType->getChartType() == "com.sun.star.chart2.CandleStickChartType"; }); + if (pChartType != aChartTypes.end()) + { + xDSContainer.set( *pChartType, uno::UNO_QUERY_THROW ); + uno::Reference< beans::XPropertySet > xCTProp( *pChartType, uno::UNO_QUERY_THROW ); + xCTProp->getPropertyValue("Japanese") >>= bHasJapaneseCandlestick; + } + } + + if( xDSContainer.is()) + { + // with japanese candlesticks: open, low, high, close + // otherwise: low, high, close + uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesSeq( xDSContainer->getDataSeries()); + const sal_Int32 nSeriesCount( aSeriesSeq.getLength()); + const sal_Int32 nSeriesPerCandleStick = bHasJapaneseCandlestick ? 4: 3; + sal_Int32 nCandleStickCount = nSeriesCount / nSeriesPerCandleStick; + OSL_ASSERT( nSeriesPerCandleStick * nCandleStickCount == nSeriesCount ); + uno::Sequence< uno::Reference< chart2::XDataSeries > > aNewSeries( nCandleStickCount ); + auto aNewSeriesRange = asNonConstRange(aNewSeries); + for( sal_Int32 i=0; i( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), + aNewSeries[i], "values-min"); + } + else + { + // low values + lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], "values-min"); + aNewSeriesRange[i] = aSeriesSeq[ nSeriesIndex ]; + } + // high values + lcl_MoveDataToCandleStickSeries( + uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), + aNewSeries[i], "values-max"); + // close values + lcl_MoveDataToCandleStickSeries( + uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ), + aNewSeries[i], "values-last"); + } + xDSContainer->setDataSeries( aNewSeries ); + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception while merging series for stock chart" ); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLChartContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY ); + + switch(nElement) + { + case XML_ELEMENT(CHART, XML_PLOT_AREA): + pContext = new SchXMLPlotAreaContext( mrImportHelper, GetImport(), + m_aXLinkHRefAttributeToIndicateDataProvider, + msCategoriesAddress, + msChartAddress, m_bHasRangeAtPlotArea, mbAllRangeAddressesAvailable, + mbColHasLabels, mbRowHasLabels, + meDataRowSource, + maSeriesDefaultsAndStyles, + maChartTypeServiceName, + maLSequencesPerIndex, maChartSize ); + break; + case XML_ELEMENT(CHART, XML_TITLE): + if( xDoc.is()) + { + if( xProp.is()) + { + xProp->setPropertyValue("HasMainTitle", uno::Any(true) ); + } + uno::Reference< drawing::XShape > xTitleShape = xDoc->getTitle(); + pContext = new SchXMLTitleContext( mrImportHelper, GetImport(), + maMainTitle, xTitleShape ); + } + break; + case XML_ELEMENT(CHART, XML_SUBTITLE): + if( xDoc.is()) + { + if( xProp.is()) + { + xProp->setPropertyValue("HasSubTitle", uno::Any(true) ); + } + uno::Reference< drawing::XShape > xTitleShape = xDoc->getSubTitle(); + pContext = new SchXMLTitleContext( mrImportHelper, GetImport(), + maSubTitle, xTitleShape ); + } + break; + case XML_ELEMENT(CHART, XML_LEGEND): + pContext = new SchXMLLegendContext( mrImportHelper, GetImport() ); + break; + case XML_ELEMENT(TABLE, XML_TABLE): + { + SchXMLTableContext * pTableContext = + new SchXMLTableContext( GetImport(), maTable ); + m_bHasTableElement = true; + // #i85913# take into account column- and row- mapping for + // charts with own data only for those which were not copied + // from a place where they got data from the container. Note, + // that this requires the plot-area been read before the table + // (which is required in the ODF spec) + // Note: For stock charts and donut charts with special handling + // the mapping must not be applied! + if( msChartAddress.isEmpty() && !mbIsStockChart && + !lcl_SpecialHandlingForDonutChartNeeded( + maChartTypeServiceName, GetImport())) + { + if( !msColTrans.isEmpty() ) + { + OSL_ASSERT( msRowTrans.isEmpty() ); + pTableContext->setColumnPermutation( lcl_getNumberSequenceFromString( msColTrans, true )); + msColTrans.clear(); + } + else if( !msRowTrans.isEmpty() ) + { + pTableContext->setRowPermutation( lcl_getNumberSequenceFromString( msRowTrans, true )); + msRowTrans.clear(); + } + } + pContext = pTableContext; + } + break; + + default: + // try importing as an additional shape + if( ! mxDrawPage.is()) + { + uno::Reference< drawing::XDrawPageSupplier > xSupp( xDoc, uno::UNO_QUERY ); + if( xSupp.is()) + mxDrawPage = xSupp->getDrawPage(); + + SAL_WARN_IF( !mxDrawPage.is(), "xmloff.chart", "Invalid Chart Page" ); + } + if( mxDrawPage.is()) + pContext = XMLShapeImportHelper::CreateGroupChildContext( + GetImport(), nElement, xAttrList, mxDrawPage ); + break; + } + + return pContext; +} + +/* + With a locked controller the following is done here: + 1. Hide title, subtitle, and legend. + 2. Set the size of the draw page. + 3. Set a (logically) empty data set. + 4. Set the chart type. +*/ +void SchXMLChartContext::InitChart( + const OUString & rChartTypeServiceName // currently the old service name + ) +{ + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + SAL_WARN_IF( !xDoc.is(), "xmloff.chart", "No valid document!" ); + + // Remove Title and Diagram ("De-InitNew") + uno::Reference< chart2::XChartDocument > xNewDoc( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); + if( xNewDoc.is()) + { + xNewDoc->setFirstDiagram( nullptr ); + uno::Reference< chart2::XTitled > xTitled( xNewDoc, uno::UNO_QUERY ); + if( xTitled.is()) + xTitled->setTitleObject( nullptr ); + } + + // Set the chart type via setting the diagram. + if( !rChartTypeServiceName.isEmpty() && xDoc.is()) + { + uno::Reference< lang::XMultiServiceFactory > xFact( xDoc, uno::UNO_QUERY ); + if( xFact.is()) + { + uno::Reference< chart::XDiagram > xDia( xFact->createInstance( rChartTypeServiceName ), uno::UNO_QUERY ); + if( xDia.is()) + xDoc->setDiagram( xDia ); + } + } +} + +SchXMLTitleContext::SchXMLTitleContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport, + OUString& rTitle, + uno::Reference< drawing::XShape > const & xTitleShape ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ), + mrTitle( rTitle ), + mxTitleShape( xTitleShape ) +{ +} + +SchXMLTitleContext::~SchXMLTitleContext() +{} + +void SchXMLTitleContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + css::awt::Point aPosition; + bool bHasXPosition=false; + bool bHasYPosition=false; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aPosition.X, aIter.toView() ); + bHasXPosition = true; + break; + } + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aPosition.Y, aIter.toView() ); + bHasYPosition = true; + break; + } + case XML_ELEMENT(CHART, XML_STYLE_NAME): + msAutoStyleName = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( mxTitleShape.is()) + { + if( bHasXPosition && bHasYPosition ) + mxTitleShape->setPosition( aPosition ); + + uno::Reference xProp(mxTitleShape, uno::UNO_QUERY); + mrImportHelper.FillAutoStyle(msAutoStyleName, xProp); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLTitleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContext* pContext = nullptr; + + if( nElement == XML_ELEMENT(TEXT, XML_P) || + nElement == XML_ELEMENT(LO_EXT, XML_P) ) + { + pContext = new SchXMLParagraphContext( GetImport(), mrTitle ); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLChartContext.hxx b/xmloff/source/chart/SchXMLChartContext.hxx new file mode 100644 index 000000000..53402168b --- /dev/null +++ b/xmloff/source/chart/SchXMLChartContext.hxx @@ -0,0 +1,148 @@ +/* -*- 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 +#include +#include +#include + +#include "transporttypes.hxx" + +#include + +class SchXMLImportHelper; + +namespace com::sun::star { + namespace chart { + class XChartDocument; + struct ChartSeriesAddress; + } + namespace xml::sax { + class XAttributeList; + } + namespace drawing { + class XShapes; + } +} + +struct SeriesDefaultsAndStyles +{ + //default values for series: + css::uno::Any maSymbolTypeDefault; + css::uno::Any maDataCaptionDefault; + + css::uno::Any maErrorIndicatorDefault; + css::uno::Any maErrorCategoryDefault; + css::uno::Any maConstantErrorLowDefault; + css::uno::Any maConstantErrorHighDefault; + css::uno::Any maPercentageErrorDefault; + css::uno::Any maErrorMarginDefault; + + css::uno::Any maMeanValueDefault; + css::uno::Any maRegressionCurvesDefault; + + css::uno::Any maStackedDefault; + css::uno::Any maPercentDefault; + css::uno::Any maDeepDefault; + css::uno::Any maStackedBarsConnectedDefault; + + //additional information + css::uno::Any maLinesOnProperty; + + //styles for series and datapoints + ::std::vector< DataRowPointStyle > maSeriesStyleVector; + ::std::vector< RegressionStyle > maRegressionStyleVector; +}; + +class SchXMLChartContext : public SvXMLImportContext +{ +public: + SchXMLChartContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport ); + virtual ~SchXMLChartContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +private: + SchXMLTable maTable; + SchXMLImportHelper& mrImportHelper; + + OUString maMainTitle, maSubTitle; + OUString m_aXLinkHRefAttributeToIndicateDataProvider; + bool m_bHasRangeAtPlotArea; + bool m_bHasTableElement; + bool mbAllRangeAddressesAvailable; + bool mbColHasLabels; + bool mbRowHasLabels; + css::chart::ChartDataRowSource meDataRowSource; + bool mbIsStockChart; + + OUString msCategoriesAddress; + OUString msChartAddress; + + OUString msDataPilotSource; + + SeriesDefaultsAndStyles maSeriesDefaultsAndStyles; + tSchXMLLSequencesPerIndex maLSequencesPerIndex; + + css::uno::Reference< css::drawing::XShapes > mxDrawPage; + OUString msColTrans; + OUString msRowTrans; + OUString maChartTypeServiceName; + + css::awt::Size maChartSize; + + /** @descr This method bundles some settings to the chart model and executes them with + a locked controller. This includes setting the chart type. + @param aServiceName The name of the service the diagram is initialized with. + */ + void InitChart (const OUString & rChartTypeServiceName); + + void MergeSeriesForStockChart(); +}; + +class SchXMLTitleContext : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + OUString& mrTitle; + css::uno::Reference< css::drawing::XShape > mxTitleShape; + OUString msAutoStyleName; + +public: + SchXMLTitleContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + OUString& rTitle, + css::uno::Reference< css::drawing::XShape > const & xTitleShape ); + virtual ~SchXMLTitleContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLEnumConverter.cxx b/xmloff/source/chart/SchXMLEnumConverter.cxx new file mode 100644 index 000000000..7bb888ee0 --- /dev/null +++ b/xmloff/source/chart/SchXMLEnumConverter.cxx @@ -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/. + * + * 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 +#include +#include "SchXMLEnumConverter.hxx" +#include + +using namespace ::xmloff::token; +using namespace ::com::sun::star; + +namespace +{ + +const SvXMLEnumMapEntry aXMLLegendPositionEnumMap[] = +{ + { XML_START, chart::ChartLegendPosition_LEFT }, + { XML_TOP, chart::ChartLegendPosition_TOP }, + { XML_END, chart::ChartLegendPosition_RIGHT }, + { XML_BOTTOM, chart::ChartLegendPosition_BOTTOM }, + { XML_TOKEN_INVALID, chart::ChartLegendPosition(0) } +}; + +class XMLLegendPositionPropertyHdl : public XMLEnumPropertyHdl +{ +public: + XMLLegendPositionPropertyHdl() + : XMLEnumPropertyHdl( aXMLLegendPositionEnumMap) {} +}; + +const SvXMLEnumMapEntry aXMLLegendExpansionEnumMap[] = +{ + { XML_WIDE, chart::ChartLegendExpansion_WIDE }, + { XML_HIGH, chart::ChartLegendExpansion_HIGH }, + { XML_BALANCED, chart::ChartLegendExpansion_BALANCED }, + { XML_CUSTOM, chart::ChartLegendExpansion_CUSTOM }, + { XML_TOKEN_INVALID, chart::ChartLegendExpansion(0) } +}; + +class XMLLegendExpansionPropertyHdl : public XMLEnumPropertyHdl +{ +public: + XMLLegendExpansionPropertyHdl() + : XMLEnumPropertyHdl( aXMLLegendExpansionEnumMap) {} +}; + +}//end anonymous namespace + +XMLEnumPropertyHdl& SchXMLEnumConverter::getLegendPositionConverter() +{ + static XMLLegendPositionPropertyHdl SINGLETON; + return SINGLETON; +} +XMLEnumPropertyHdl& SchXMLEnumConverter::getLegendExpansionConverter() +{ + static XMLLegendExpansionPropertyHdl SINGLETON; + return SINGLETON; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLEnumConverter.hxx b/xmloff/source/chart/SchXMLEnumConverter.hxx new file mode 100644 index 000000000..a61a611b0 --- /dev/null +++ b/xmloff/source/chart/SchXMLEnumConverter.hxx @@ -0,0 +1,30 @@ +/* -*- 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 + +class SchXMLEnumConverter +{ +public: + static XMLEnumPropertyHdl& getLegendPositionConverter(); //returns a singleton + static XMLEnumPropertyHdl& getLegendExpansionConverter(); //returns a singleton +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLExport.cxx b/xmloff/source/chart/SchXMLExport.cxx new file mode 100644 index 000000000..fc0a24a8e --- /dev/null +++ b/xmloff/source/chart/SchXMLExport.cxx @@ -0,0 +1,4067 @@ +/* -*- 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 +#include +#include + +#include + +#include + +#include +#include +#include "ColorPropertySet.hxx" +#include "SchXMLTools.hxx" +#include "SchXMLEnumConverter.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "MultiPropertySetHandler.hxx" +#include "PropertyMap.hxx" + +using namespace com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::std::vector; + + +namespace +{ + /** + * Used to store a data point custom-label's fields and also the helper members that + * indicates whether this label's contents are sourced from a cell[range] and + * the address of the cell[range] with guid of the CELLRANGE field. + */ + struct CustomLabelData + { + CustomLabelData(): + mbDataLabelsRange( false ) + { + } + + /// Label fields. + Sequence> maFields; + /// Are label's contents sourced from a cell[range] ? + bool mbDataLabelsRange; + /// cell[range] from which label's contents are sourced. + OUString maRange; + /// GUID of the CELLRANGE field. + OUString maGuid; + }; + + struct SchXMLDataPointStruct + { + OUString maStyleName; + sal_Int32 mnRepeat; + chart2::RelativePosition mCustomLabelPos; // loext:custom-label-pos-x and -y + + // There is no internal equivalent for . It will be generated on the fly + // on export. All about data label is hold in the data point. + CustomLabelData mCustomLabel; // child element in + OUString msDataLabelStyleName; // chart:style-name attribute in + + SchXMLDataPointStruct() : mnRepeat( 1 ) {} + }; +} + + +class SchXMLExportHelper_Impl +{ +public: + // first: data sequence for label, second: data sequence for values. + typedef ::std::pair< css::uno::Reference< css::chart2::data::XDataSequence >, + css::uno::Reference< css::chart2::data::XDataSequence > > tLabelValuesDataPair; + typedef ::std::vector< tLabelValuesDataPair > tDataSequenceCont; + +public: + SchXMLExportHelper_Impl( SvXMLExport& rExport, + SvXMLAutoStylePoolP& rASPool ); + + SchXMLExportHelper_Impl(const SchXMLExportHelper_Impl&) = delete; + SchXMLExportHelper_Impl& operator=(const SchXMLExportHelper_Impl&) = delete; + + // auto-styles + /// parse chart and collect all auto-styles used in current pool + void collectAutoStyles( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc ); + + /// write the styles collected into the current pool as elements + void exportAutoStyles(); + + /** export the element corresponding to rChartDoc + if bIncludeTable is true, the chart data is exported as + element (inside the chart element). + + Otherwise the external references stored in the chart document are used + for writing the corresponding attributes at series + + All attributes contained in xAttrList are written at the chart element, + which is the outer element of a chart. So these attributes can easily + be parsed again by the container + */ + void exportChart( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc, + bool bIncludeTable ); + + const rtl::Reference& GetPropertySetMapper() const; + + void SetChartRangeAddress( const OUString& rAddress ) + { msChartAddress = rAddress; } + + void InitRangeSegmentationProperties( + const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc ); + + static css::awt::Size getPageSize( + const css::uno::Reference< css::chart2::XChartDocument > & xChartDoc ); + + /** first parseDocument: collect autostyles and store names in this queue + second parseDocument: export content and use names from this queue + */ + ::std::queue< OUString > maAutoStyleNameQueue; + void CollectAutoStyle( + std::vector< XMLPropertyState >&& aStates ); + void AddAutoStyleAttribute( + const std::vector< XMLPropertyState >& aStates ); + + /// if bExportContent is false the auto-styles are collected + void parseDocument( css::uno::Reference< css::chart::XChartDocument > const & rChartDoc, + bool bExportContent, + bool bIncludeTable = false ); + void exportTable(); + void exportPlotArea( + const css::uno::Reference< css::chart::XDiagram >& xDiagram, + const css::uno::Reference< css::chart2::XDiagram >& xNewDiagram, + const css::awt::Size & rPageSize, + bool bExportContent, + bool bIncludeTable ); + void exportCoordinateRegion( const css::uno::Reference< css::chart::XDiagram >& xDiagram ); + void exportAxes( const css::uno::Reference< css::chart::XDiagram > & xDiagram, + const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram, + bool bExportContent ); + void exportAxis( enum XMLTokenEnum eDimension, enum XMLTokenEnum eAxisName, + const Reference< beans::XPropertySet >& rAxisProps, const Reference< chart2::XAxis >& rChart2Axis, + const OUString& rCategoriesRanges, + bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid, bool bExportContent, std::u16string_view sChartType ); + void exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent ); + void exportDateScale( const Reference< beans::XPropertySet >& rAxisProps ); + void exportAxisTitle( const Reference< beans::XPropertySet >& rTitleProps, bool bExportContent ); + + void exportSeries( + const css::uno::Reference< css::chart2::XDiagram > & xNewDiagram, + const css::awt::Size & rPageSize, + bool bExportContent, + bool bHasTwoYAxes ); + + void exportPropertyMapping( + const css::uno::Reference< css::chart2::data::XDataSource > & xSource, + const Sequence< OUString >& rSupportedMappings ); + + void exportCandleStickSeries( + const css::uno::Sequence< + css::uno::Reference< css::chart2::XDataSeries > > & aSeriesSeq, + const css::uno::Reference< css::chart2::XDiagram > & xDiagram, + bool bJapaneseCandleSticks, + bool bExportContent ); + void exportDataPoints( + const css::uno::Reference< css::beans::XPropertySet > & xSeriesProperties, + sal_Int32 nSeriesLength, + const css::uno::Reference< css::chart2::XDiagram > & xDiagram, + bool bExportContent ); + + void exportCustomLabel(const SchXMLDataPointStruct& rPoint); + void exportCustomLabelPosition(const chart2::RelativePosition& xCustomLabelPosition); + + void exportRegressionCurve( + const css::uno::Reference& xSeries, + const css::awt::Size& rPageSize, + bool bExportContent ); + + void exportErrorBar ( + const css::uno::Reference &xSeriesProp, bool bYError, + bool bExportContent ); + + /// add svg position as attribute for current element + void addPosition( const css::awt::Point & rPosition ); + void addPosition( const css::uno::Reference< css::drawing::XShape >& xShape ); + /// add svg size as attribute for current element + void addSize( const css::awt::Size & rSize, bool bIsOOoNamespace = false ); + void addSize( const css::uno::Reference< css::drawing::XShape >& xShape ); + /// exports a string as a paragraph element + void exportText( const OUString& rText ); + +public: + SvXMLExport& mrExport; + SvXMLAutoStylePoolP& mrAutoStylePool; + rtl::Reference< XMLPropertySetMapper > mxPropertySetMapper; + rtl::Reference< XMLChartExportPropertyMapper > mxExpPropMapper; + + static constexpr OUStringLiteral gsTableName = u"local-table"; + OUStringBuffer msStringBuffer; + OUString msString; + + // members filled by InitRangeSegmentationProperties (retrieved from DataProvider) + bool mbHasCategoryLabels; //if the categories are only automatically generated this will be false + bool mbRowSourceColumns; + OUString msChartAddress; + css::uno::Sequence< sal_Int32 > maSequenceMapping; + + OUString msCLSID; + + OUString maSrcShellID; + OUString maDestShellID; + + css::uno::Reference< css::drawing::XShapes > mxAdditionalShapes; + + tDataSequenceCont m_aDataSequencesToExport; + OUString maCategoriesRange; +}; + +namespace +{ +CustomLabelData lcl_getCustomLabelField(SvXMLExport const& rExport, + sal_Int32 nDataPointIndex, + const uno::Reference< chart2::XDataSeries >& rSeries) +{ + if (!rSeries.is()) + return CustomLabelData(); + + // Custom data label text will be written to the child element of a + // element. That exists only since ODF 1.2. + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + rExport.getSaneDefaultVersion()); + if (nCurrentODFVersion < SvtSaveOptions::ODFSVER_012) + return CustomLabelData(); + + if(Reference xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is()) + { + if(Any aAny = xLabels->getPropertyValue("CustomLabelFields"); aAny.hasValue()) + { + CustomLabelData aData; + Sequence> aCustomLabels; + aAny >>= aCustomLabels; + for (const auto& rField: std::as_const(aCustomLabels)) + { + if (rField->getFieldType() == chart2::DataPointCustomLabelFieldType_CELLRANGE) + { + if (rField->getDataLabelsRange()) + aData.mbDataLabelsRange = true; + aData.maRange = rField->getCellRange(); + aData.maGuid = rField->getGuid(); + } + } + + aData.maFields = aCustomLabels; + return aData; + } + } + return CustomLabelData(); +} + +css::chart2::RelativePosition lcl_getCustomLabelPosition( + SvXMLExport const& rExport, + sal_Int32 const nDataPointIndex, + const uno::Reference< chart2::XDataSeries >& rSeries) +{ + if (!rSeries.is()) + return chart2::RelativePosition(); + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + rExport.getSaneDefaultVersion()); + + if ((nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) == 0) // do not export to ODF 1.3 or older + return chart2::RelativePosition(); + + if (Reference xLabels = rSeries->getDataPointByIndex(nDataPointIndex); xLabels.is()) + { + if (Any aAny = xLabels->getPropertyValue("CustomLabelPosition"); aAny.hasValue()) + { + chart2::RelativePosition aCustomLabelPos; + aAny >>= aCustomLabelPos; + return aCustomLabelPos; + } + } + return chart2::RelativePosition(); +} + +class lcl_MatchesRole +{ +public: + explicit lcl_MatchesRole( const OUString & aRole ) : + m_aRole( aRole ) + {} + + bool operator () ( const Reference< chart2::data::XLabeledDataSequence > & xSeq ) const + { + if( !xSeq.is() ) + return false; + Reference< beans::XPropertySet > xProp( xSeq->getValues(), uno::UNO_QUERY ); + OUString aRole; + + return ( xProp.is() && + (xProp->getPropertyValue( "Role" ) >>= aRole ) && + m_aRole == aRole ); + } + +private: + OUString m_aRole; +}; + +Reference< chart2::data::XLabeledDataSequence > lcl_getCategories( const Reference< chart2::XDiagram > & xDiagram ) +{ + Reference< chart2::data::XLabeledDataSequence > xResult; + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( + xDiagram, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XCoordinateSystem > xCooSys( rCooSys ); + SAL_WARN_IF( !xCooSys.is(), "xmloff.chart", "xCooSys is NULL" ); + for( sal_Int32 nN = xCooSys->getDimension(); nN--; ) + { + const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nN); + for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI) + { + Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( nN, nI ); + SAL_WARN_IF( !xAxis.is(), "xmloff.chart", "xAxis is NULL"); + if( xAxis.is()) + { + chart2::ScaleData aScaleData = xAxis->getScaleData(); + if( aScaleData.Categories.is()) + { + xResult.set( aScaleData.Categories ); + break; + } + } + } + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + + return xResult; +} + +Reference< chart2::data::XDataSource > lcl_createDataSource( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aData ) +{ + Reference< uno::XComponentContext > xContext( + comphelper::getProcessComponentContext() ); + Reference< chart2::data::XDataSink > xSink( + xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.chart2.data.DataSource", xContext ), + uno::UNO_QUERY_THROW ); + xSink->setData( aData ); + + return Reference< chart2::data::XDataSource >( xSink, uno::UNO_QUERY ); +} + +Sequence< Reference< chart2::data::XLabeledDataSequence > > lcl_getAllSeriesSequences( const Reference< chart2::XChartDocument >& xChartDoc ) +{ + ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aContainer; + if( xChartDoc.is() ) + { + Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram()); + ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram )); + for( const auto& rSeries : aSeriesVector ) + { + Reference< chart2::data::XDataSource > xDataSource( rSeries, uno::UNO_QUERY ); + if( !xDataSource.is() ) + continue; + const uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aDataSequences( xDataSource->getDataSequences() ); + aContainer.insert( aContainer.end(), aDataSequences.begin(), aDataSequences.end() ); + } + } + + return comphelper::containerToSequence( aContainer ); +} + +Reference< chart2::data::XLabeledDataSequence > + lcl_getDataSequenceByRole( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aLabeledSeq, + const OUString & rRole ) +{ + Reference< chart2::data::XLabeledDataSequence > aNoResult; + + const Reference< chart2::data::XLabeledDataSequence > * pBegin = aLabeledSeq.getConstArray(); + const Reference< chart2::data::XLabeledDataSequence > * pEnd = pBegin + aLabeledSeq.getLength(); + const Reference< chart2::data::XLabeledDataSequence > * pMatch = + ::std::find_if( pBegin, pEnd, lcl_MatchesRole( rRole )); + + if( pMatch != pEnd ) + return *pMatch; + + return aNoResult; +} + +Reference< chart2::data::XDataSource > lcl_pressUsedDataIntoRectangularFormat( const Reference< chart2::XChartDocument >& xChartDoc, bool& rOutSourceHasCategoryLabels ) +{ + ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aLabeledSeqVector; + + //categories are always the first sequence + Reference< chart2::XDiagram > xDiagram( xChartDoc->getFirstDiagram()); + Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xDiagram ) ); + if( xCategories.is() ) + aLabeledSeqVector.push_back( xCategories ); + rOutSourceHasCategoryLabels = xCategories.is(); + + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeriesSeqVector( + lcl_getAllSeriesSequences( xChartDoc ) ); + + //the first x-values is always the next sequence //todo ... other x-values get lost for old format + Reference< chart2::data::XLabeledDataSequence > xXValues( + lcl_getDataSequenceByRole( aSeriesSeqVector, "values-x" ) ); + if( xXValues.is() ) + aLabeledSeqVector.push_back( xXValues ); + + //add all other sequences now without x-values + lcl_MatchesRole aHasXValues( "values-x" ); + std::copy_if(aSeriesSeqVector.begin(), aSeriesSeqVector.end(), std::back_inserter(aLabeledSeqVector), + [&aHasXValues](const auto& rSeriesSeq) { return !aHasXValues( rSeriesSeq ); }); + + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( comphelper::containerToSequence(aLabeledSeqVector) ); + + return lcl_createDataSource( aSeq ); +} + +bool lcl_isSeriesAttachedToFirstAxis( + const Reference< chart2::XDataSeries > & xDataSeries ) +{ + bool bResult=true; + + try + { + sal_Int32 nAxisIndex = 0; + Reference< beans::XPropertySet > xProp( xDataSeries, uno::UNO_QUERY_THROW ); + xProp->getPropertyValue("AttachedAxisIndex") >>= nAxisIndex; + bResult = (0==nAxisIndex); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + + return bResult; +} + +OUString lcl_ConvertRange( const OUString & rRange, const Reference< chart2::XChartDocument > & xDoc ) +{ + OUString aResult = rRange; + if( !xDoc.is() ) + return aResult; + Reference< chart2::data::XRangeXMLConversion > xConversion( + xDoc->getDataProvider(), uno::UNO_QUERY ); + if( xConversion.is()) + aResult = xConversion->convertRangeToXML( rRange ); + return aResult; +} + +typedef ::std::pair< OUString, OUString > tLabelAndValueRange; + +tLabelAndValueRange lcl_getLabelAndValueRangeByRole( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt, + const OUString & rRole, + const Reference< chart2::XChartDocument > & xDoc, + SchXMLExportHelper_Impl::tDataSequenceCont & rOutSequencesToExport ) +{ + tLabelAndValueRange aResult; + + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + lcl_getDataSequenceByRole( aSeqCnt, rRole )); + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xLabelSeq( xLabeledSeq->getLabel()); + if( xLabelSeq.is()) + aResult.first = lcl_ConvertRange( xLabelSeq->getSourceRangeRepresentation(), xDoc ); + + Reference< chart2::data::XDataSequence > xValueSeq( xLabeledSeq->getValues()); + if( xValueSeq.is()) + aResult.second = lcl_ConvertRange( xValueSeq->getSourceRangeRepresentation(), xDoc ); + + if( xLabelSeq.is() || xValueSeq.is()) + rOutSequencesToExport.emplace_back( xLabelSeq, xValueSeq ); + } + + return aResult; +} + +sal_Int32 lcl_getSequenceLengthByRole( + const Sequence< Reference< chart2::data::XLabeledDataSequence > > & aSeqCnt, + const OUString & rRole ) +{ + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + lcl_getDataSequenceByRole( aSeqCnt, rRole )); + if( xLabeledSeq.is()) + { + Reference< chart2::data::XDataSequence > xSeq( xLabeledSeq->getValues()); + return xSeq->getData().getLength(); + } + return 0; +} + +OUString lcl_flattenStringSequence( const Sequence< OUString > & rSequence ) +{ + OUStringBuffer aResult; + bool bPrecedeWithSpace = false; + for( const auto& rString : rSequence ) + { + if( !rString.isEmpty()) + { + if( bPrecedeWithSpace ) + aResult.append( ' ' ); + aResult.append( rString ); + bPrecedeWithSpace = true; + } + } + return aResult.makeStringAndClear(); +} + +void lcl_getLabelStringSequence( Sequence< OUString >& rOutLabels, const Reference< chart2::data::XDataSequence > & xLabelSeq ) +{ + uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xLabelSeq, uno::UNO_QUERY ); + if( xTextualDataSequence.is()) + { + rOutLabels = xTextualDataSequence->getTextualData(); + } + else if( xLabelSeq.is()) + { + Sequence< uno::Any > aAnies( xLabelSeq->getData()); + rOutLabels.realloc( aAnies.getLength()); + auto pOutLabels = rOutLabels.getArray(); + for( sal_Int32 i=0; i>= pOutLabels[i]; + } +} + +sal_Int32 lcl_getMaxSequenceLength( + const SchXMLExportHelper_Impl::tDataSequenceCont & rContainer ) +{ + sal_Int32 nResult = 0; + for( const auto& rDataSequence : rContainer ) + { + if( rDataSequence.second.is()) + { + sal_Int32 nSeqLength = rDataSequence.second->getData().getLength(); + if( nSeqLength > nResult ) + nResult = nSeqLength; + } + } + return nResult; +} + +uno::Sequence< OUString > lcl_DataSequenceToStringSequence( + const uno::Reference< chart2::data::XDataSequence >& xDataSequence ) +{ + uno::Sequence< OUString > aResult; + if(!xDataSequence.is()) + return aResult; + + uno::Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY ); + if( xTextualDataSequence.is() ) + { + aResult = xTextualDataSequence->getTextualData(); + } + else + { + uno::Sequence< uno::Any > aValues = xDataSequence->getData(); + aResult.realloc(aValues.getLength()); + auto pResult = aResult.getArray(); + + for(sal_Int32 nN=aValues.getLength();nN--;) + aValues[nN] >>= pResult[nN]; + } + + return aResult; +} +::std::vector< double > lcl_getAllValuesFromSequence( const Reference< chart2::data::XDataSequence > & xSeq ) +{ + ::std::vector< double > aResult; + if(!xSeq.is()) + return aResult; + + uno::Sequence< double > aValuesSequence; + Reference< chart2::data::XNumericalDataSequence > xNumSeq( xSeq, uno::UNO_QUERY ); + if( xNumSeq.is() ) + { + aValuesSequence = xNumSeq->getNumericalData(); + } + else + { + Sequence< uno::Any > aAnies( xSeq->getData() ); + aValuesSequence.realloc( aAnies.getLength() ); + auto pValuesSequence = aValuesSequence.getArray(); + for( sal_Int32 i=0; i>= pValuesSequence[i]; + } + + //special handling for x-values (if x-values do point to categories, indices are used instead ) + Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY ); + if( xProp.is() ) + { + OUString aRole; + xProp->getPropertyValue("Role") >>= aRole; + if( aRole.match("values-x") ) + { + //lcl_clearIfNoValuesButTextIsContained - replace by indices if the values are not appropriate + bool bHasValue = std::any_of(std::cbegin(aValuesSequence), std::cend(aValuesSequence), + [](double fValue) { return !std::isnan( fValue ); }); + if(!bHasValue) + { + //no double value is contained + //is there any text? + const uno::Sequence< OUString > aStrings( lcl_DataSequenceToStringSequence( xSeq ) ); + bool bHasText = std::any_of(aStrings.begin(), aStrings.end(), + [](const OUString& rString) { return !rString.isEmpty(); }); + if( bHasText ) + { + auto [begin, end] = asNonConstRange(aValuesSequence); + std::iota(begin, end, 1); + } + } + } + } + + aResult.insert( aResult.end(), std::cbegin(aValuesSequence), std::cend(aValuesSequence) ); + return aResult; +} + +bool lcl_SequenceHasUnhiddenData( const uno::Reference< chart2::data::XDataSequence >& xDataSequence ) +{ + if( !xDataSequence.is() ) + return false; + uno::Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY ); + if( xProp.is() ) + { + uno::Sequence< sal_Int32 > aHiddenValues; + try + { + xProp->getPropertyValue("HiddenValues") >>= aHiddenValues; + if( !aHiddenValues.hasElements() ) + return true; + } + catch( const uno::Exception& ) + { + return true; + } + } + return xDataSequence->getData().hasElements(); +} + +typedef vector< OUString > tStringVector; +typedef vector< vector< double > > t2DNumberContainer; + +struct lcl_TableData +{ + t2DNumberContainer aDataInRows; + tStringVector aDataRangeRepresentations; + + tStringVector aColumnDescriptions; + tStringVector aColumnDescriptions_Ranges; + + tStringVector aRowDescriptions; + tStringVector aRowDescriptions_Ranges; + + Sequence< Sequence< uno::Any > > aComplexColumnDescriptions;//outer index is columns - inner index is level + Sequence< Sequence< uno::Any > > aComplexRowDescriptions;//outer index is rows - inner index is level + + ::std::vector< sal_Int32 > aHiddenColumns; +}; + +typedef ::std::map< sal_Int32, SchXMLExportHelper_Impl::tLabelValuesDataPair > + lcl_DataSequenceMap; + +struct lcl_SequenceToMapElement +{ + std::pair + operator() (const SchXMLExportHelper_Impl::tLabelValuesDataPair& rContent) + { + sal_Int32 nIndex = -1; + if( rContent.second.is()) //has values + { + OUString aRangeRep( rContent.second->getSourceRangeRepresentation()); + nIndex = aRangeRep.toInt32(); + } + else if( rContent.first.is()) //has labels + nIndex = o3tl::toInt32(rContent.first->getSourceRangeRepresentation().subView( sizeof("label "))); + return std::make_pair(nIndex, rContent); + } +}; + +void lcl_ReorderInternalSequencesAccordingToTheirRangeName( + SchXMLExportHelper_Impl::tDataSequenceCont & rInOutSequences ) +{ + lcl_DataSequenceMap aIndexSequenceMap; + ::std::transform( rInOutSequences.begin(), rInOutSequences.end(), + ::std::inserter( aIndexSequenceMap, aIndexSequenceMap.begin()), + lcl_SequenceToMapElement()); + + rInOutSequences.clear(); + sal_Int32 nIndex = 0; + for( const auto& rEntry : aIndexSequenceMap ) + { + if( rEntry.first >= 0 ) + { + // fill empty columns + rInOutSequences.insert( + rInOutSequences.end(), + rEntry.first - nIndex, + SchXMLExportHelper_Impl::tDataSequenceCont::value_type( + uno::Reference< chart2::data::XDataSequence >(), + uno::Reference< chart2::data::XDataSequence >() )); + nIndex = rEntry.first; + rInOutSequences.push_back( rEntry.second ); + } + + ++nIndex; + } +} + +lcl_TableData lcl_getDataForLocalTable( + const SchXMLExportHelper_Impl::tDataSequenceCont & aSequencesToExport, + const Reference< chart2::XAnyDescriptionAccess >& xAnyDescriptionAccess, + const OUString& rCategoriesRange, + bool bSeriesFromColumns, + const Reference< chart2::data::XRangeXMLConversion > & xRangeConversion ) +{ + lcl_TableData aResult; + + try + { + Sequence< OUString > aSimpleCategories; + if( xAnyDescriptionAccess.is() ) + { + //categories + if( bSeriesFromColumns ) + { + aSimpleCategories = xAnyDescriptionAccess->getRowDescriptions(); + aResult.aComplexRowDescriptions = xAnyDescriptionAccess->getAnyRowDescriptions(); + } + else + { + aSimpleCategories = xAnyDescriptionAccess->getColumnDescriptions(); + aResult.aComplexColumnDescriptions = xAnyDescriptionAccess->getAnyColumnDescriptions(); + } + } + + //series values and series labels + SchXMLExportHelper_Impl::tDataSequenceCont::size_type nNumSequences = aSequencesToExport.size(); + + auto nMaxSequenceLength( lcl_getMaxSequenceLength( aSequencesToExport )); + if( aSimpleCategories.getLength() > nMaxSequenceLength ) + { + aSimpleCategories.realloc(nMaxSequenceLength);//#i110617# + } + size_t nNumColumns( bSeriesFromColumns ? nNumSequences : nMaxSequenceLength ); + size_t nNumRows( bSeriesFromColumns ? nMaxSequenceLength : nNumSequences ); + + // resize data + aResult.aDataInRows.resize( nNumRows ); + + for (auto& aData: aResult.aDataInRows) + aData.resize(nNumColumns, std::numeric_limits::quiet_NaN()); + aResult.aColumnDescriptions.resize( nNumColumns ); + aResult.aComplexColumnDescriptions.realloc( nNumColumns ); + aResult.aRowDescriptions.resize( nNumRows ); + aResult.aComplexRowDescriptions.realloc( nNumRows ); + + tStringVector& rCategories = bSeriesFromColumns ? aResult.aRowDescriptions : aResult.aColumnDescriptions; + tStringVector& rLabels = bSeriesFromColumns ? aResult.aColumnDescriptions : aResult.aRowDescriptions; + + //categories + rCategories.clear(); + rCategories.insert( rCategories.begin(), std::cbegin(aSimpleCategories), std::cend(aSimpleCategories) ); + if( !rCategoriesRange.isEmpty() ) + { + OUString aRange(rCategoriesRange); + if( xRangeConversion.is()) + aRange = xRangeConversion->convertRangeToXML( aRange ); + if( bSeriesFromColumns ) + aResult.aRowDescriptions_Ranges.push_back( aRange ); + else + aResult.aColumnDescriptions_Ranges.push_back( aRange ); + } + + // iterate over all sequences + size_t nSeqIdx = 0; + Sequence< Sequence< OUString > > aComplexLabels(nNumSequences); + auto aComplexLabelsRange = asNonConstRange(aComplexLabels); + for( const auto& rDataSequence : aSequencesToExport ) + { + OUString aRange; + Sequence< OUString >& rCurrentComplexLabel = aComplexLabelsRange[nSeqIdx]; + if( rDataSequence.first.is()) + { + lcl_getLabelStringSequence( rCurrentComplexLabel, rDataSequence.first ); + rLabels[nSeqIdx] = lcl_flattenStringSequence( rCurrentComplexLabel ); + aRange = rDataSequence.first->getSourceRangeRepresentation(); + if( xRangeConversion.is()) + aRange = xRangeConversion->convertRangeToXML( aRange ); + } + else if( rDataSequence.second.is()) + { + rCurrentComplexLabel.realloc(1); + rLabels[nSeqIdx] = rCurrentComplexLabel.getArray()[0] = lcl_flattenStringSequence( + rDataSequence.second->generateLabel( chart2::data::LabelOrigin_SHORT_SIDE )); + } + if( bSeriesFromColumns ) + aResult.aColumnDescriptions_Ranges.push_back( aRange ); + else + aResult.aRowDescriptions_Ranges.push_back( aRange ); + + ::std::vector< double > aNumbers( lcl_getAllValuesFromSequence( rDataSequence.second )); + if( bSeriesFromColumns ) + { + const sal_Int32 nSize( static_cast< sal_Int32 >( aNumbers.size())); + for( sal_Int32 nIdx=0; nIdxgetSourceRangeRepresentation(); + if( xRangeConversion.is()) + aRange = xRangeConversion->convertRangeToXML( aRange ); + } + aResult.aDataRangeRepresentations.push_back( aRange ); + + //is column hidden? + if( !lcl_SequenceHasUnhiddenData(rDataSequence.first) && !lcl_SequenceHasUnhiddenData(rDataSequence.second) ) + aResult.aHiddenColumns.push_back(nSeqIdx); + + ++nSeqIdx; + } + Sequence< Sequence< Any > >& rComplexAnyLabels = bSeriesFromColumns ? aResult.aComplexColumnDescriptions : aResult.aComplexRowDescriptions;//#i116544# + rComplexAnyLabels.realloc(aComplexLabels.getLength()); + auto pComplexAnyLabels = rComplexAnyLabels.getArray(); + for( sal_Int32 nN=0; nN& rSource = aComplexLabelsRange[nN]; + Sequence< Any >& rTarget = pComplexAnyLabels[nN]; + rTarget.realloc( rSource.getLength() ); + auto pTarget = rTarget.getArray(); + for( sal_Int32 i=0; i& xPropSet, + SvXMLExport& rExport ) +{ + if( xPropSet.is()) + { + sal_Int32 nNumberFormat = 0; + Any aNumAny = xPropSet->getPropertyValue( rPropertyName ); + if( (aNumAny >>= nNumberFormat) && (nNumberFormat != -1) ) + rExport.addDataStyle( nNumberFormat ); + } +} + +::std::vector< Reference< chart2::data::XDataSequence > > + lcl_getErrorBarSequences( const Reference< beans::XPropertySet > & xErrorBarProp ) +{ + ::std::vector< Reference< chart2::data::XDataSequence > > aResult; + Reference< chart2::data::XDataSource > xErrorBarDataSource( xErrorBarProp, uno::UNO_QUERY ); + if( !xErrorBarDataSource.is()) + return aResult; + + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( + xErrorBarDataSource->getDataSequences()); + for( const auto& rSequence : aSequences ) + { + try + { + if( rSequence.is()) + { + Reference< chart2::data::XDataSequence > xSequence( rSequence->getValues()); + Reference< beans::XPropertySet > xSeqProp( xSequence, uno::UNO_QUERY_THROW ); + OUString aRole; + if( ( xSeqProp->getPropertyValue( "Role" ) >>= aRole ) && + aRole.match( "error-bars-" )) + { + aResult.push_back( xSequence ); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exporting error bar ranges" ); + } + } + + return aResult; +} + +bool lcl_exportDomainForThisSequence( const Reference< chart2::data::XDataSequence >& rValues, OUString& rFirstRangeForThisDomainIndex, SvXMLExport& rExport ) +{ + bool bDomainExported = false; + if( rValues.is()) + { + Reference< chart2::XChartDocument > xNewDoc( rExport.GetModel(), uno::UNO_QUERY ); + OUString aRange( lcl_ConvertRange( rValues->getSourceRangeRepresentation(), xNewDoc ) ); + + //work around error in OOo 2.0 (problems with multiple series having a domain element) + if( rFirstRangeForThisDomainIndex.isEmpty() || aRange != rFirstRangeForThisDomainIndex ) + { + rExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, aRange); + SvXMLElementExport aDomain( rExport, XML_NAMESPACE_CHART, XML_DOMAIN, true, true ); + bDomainExported = true; + } + + if( rFirstRangeForThisDomainIndex.isEmpty() ) + rFirstRangeForThisDomainIndex = aRange; + } + return bDomainExported; +} + +} // anonymous namespace + + +SchXMLExportHelper::SchXMLExportHelper( SvXMLExport& rExport, SvXMLAutoStylePoolP& rASPool ) + : m_pImpl( new SchXMLExportHelper_Impl( rExport, rASPool ) ) +{ +} + +SchXMLExportHelper::~SchXMLExportHelper() +{ +} + +const OUString& SchXMLExportHelper::getChartCLSID() const +{ + return m_pImpl->msCLSID; +} + +void SchXMLExportHelper::SetSourceShellID( const OUString& rShellID ) +{ + m_pImpl->maSrcShellID = rShellID; +} + +void SchXMLExportHelper::SetDestinationShellID( const OUString& rShellID ) +{ + m_pImpl->maDestShellID = rShellID; +} + +const rtl::Reference< XMLPropertySetMapper >& SchXMLExportHelper_Impl::GetPropertySetMapper() const +{ + return mxPropertySetMapper; +} + +void SchXMLExportHelper_Impl::exportAutoStyles() +{ + if( !mxExpPropMapper.is()) + return; + + //ToDo: when embedded in calc/writer this is not necessary because the + // numberformatter is shared between both documents + mrExport.exportAutoDataStyles(); + + // export chart auto styles + mrAutoStylePool.exportXML( XmlStyleFamily::SCH_CHART_ID ); + + // export auto styles for additional shapes + mrExport.GetShapeExport()->exportAutoStyles(); + // and for text in additional shapes + mrExport.GetTextParagraphExport()->exportTextAutoStyles(); +} + +// private methods + +SchXMLExportHelper_Impl::SchXMLExportHelper_Impl( + SvXMLExport& rExport, + SvXMLAutoStylePoolP& rASPool ) : + mrExport( rExport ), + mrAutoStylePool( rASPool ), + mxPropertySetMapper( new XMLChartPropertySetMapper(&rExport) ), + mxExpPropMapper( new XMLChartExportPropertyMapper( mxPropertySetMapper, rExport ) ), + mbHasCategoryLabels( false ), + mbRowSourceColumns( true ), + msCLSID( SvGlobalName( SO3_SCH_CLASSID ).GetHexName() ) +{ + // register chart auto-style family + mrAutoStylePool.AddFamily( + XmlStyleFamily::SCH_CHART_ID, + OUString( XML_STYLE_FAMILY_SCH_CHART_NAME ), + mxExpPropMapper.get(), + OUString( XML_STYLE_FAMILY_SCH_CHART_PREFIX )); + + // register shape family + mrAutoStylePool.AddFamily( + XmlStyleFamily::SD_GRAPHICS_ID, + OUString( XML_STYLE_FAMILY_SD_GRAPHICS_NAME ), + mxExpPropMapper.get(), + OUString( XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX )); + // register paragraph family also for shapes + mrAutoStylePool.AddFamily( + XmlStyleFamily::TEXT_PARAGRAPH, + GetXMLToken( XML_PARAGRAPH ), + mxExpPropMapper.get(), + OUString( 'P' )); + // register text family also for shapes + mrAutoStylePool.AddFamily( + XmlStyleFamily::TEXT_TEXT, + GetXMLToken( XML_TEXT ), + mxExpPropMapper.get(), + OUString( 'T' )); +} + +void SchXMLExportHelper_Impl::collectAutoStyles( Reference< chart::XChartDocument > const & rChartDoc ) +{ + parseDocument( rChartDoc, false ); +} + +void SchXMLExportHelper_Impl::exportChart( Reference< chart::XChartDocument > const & rChartDoc, + bool bIncludeTable ) +{ + parseDocument( rChartDoc, true, bIncludeTable ); + SAL_WARN_IF( !maAutoStyleNameQueue.empty(), "xmloff.chart", "There are still remaining autostyle names in the queue" ); +} + +static OUString lcl_GetStringFromNumberSequence( const css::uno::Sequence< sal_Int32 >& rSequenceMapping, bool bRemoveOneFromEachIndex /*should be true if having categories*/ ) +{ + OUStringBuffer aBuf; + bool bHasPredecessor = false; + for( sal_Int32 nIndex : rSequenceMapping ) + { + if( bRemoveOneFromEachIndex ) + --nIndex; + if(nIndex>=0) + { + if(bHasPredecessor) + aBuf.append( ' ' ); + aBuf.append( nIndex ); + bHasPredecessor = true; + } + } + return aBuf.makeStringAndClear(); +} + +/// if bExportContent is false the auto-styles are collected +void SchXMLExportHelper_Impl::parseDocument( Reference< chart::XChartDocument > const & rChartDoc, + bool bExportContent, + bool bIncludeTable ) +{ + Reference< chart2::XChartDocument > xNewDoc( rChartDoc, uno::UNO_QUERY ); + if( !rChartDoc.is() || !xNewDoc.is() ) + { + SAL_WARN("xmloff.chart", "No XChartDocument was given for export." ); + return; + } + + mxExpPropMapper->setChartDoc(xNewDoc); + + awt::Size aPageSize( getPageSize( xNewDoc )); + if( bExportContent ) + addSize( aPageSize ); + Reference< chart::XDiagram > xDiagram = rChartDoc->getDiagram(); + Reference< chart2::XDiagram > xNewDiagram; + if( xNewDoc.is()) + xNewDiagram.set( xNewDoc->getFirstDiagram()); + + //todo remove if model changes are notified and view is updated automatically + if( bExportContent ) + { + Reference< util::XRefreshable > xRefreshable( xNewDoc, uno::UNO_QUERY ); + if( xRefreshable.is() ) + xRefreshable->refresh(); + } + + // get Properties of ChartDocument + bool bHasMainTitle = false; + bool bHasSubTitle = false; + bool bHasLegend = false; + util::DateTime aNullDate(0,0,0,0,30,12,1899, false); + + std::vector< XMLPropertyState > aPropertyStates; + + Reference< beans::XPropertySet > xDocPropSet( rChartDoc, uno::UNO_QUERY ); + if( xDocPropSet.is()) + { + try + { + Any aAny = xDocPropSet->getPropertyValue("HasMainTitle"); + aAny >>= bHasMainTitle; + aAny = xDocPropSet->getPropertyValue("HasSubTitle"); + aAny >>= bHasSubTitle; + aAny = xDocPropSet->getPropertyValue("HasLegend"); + aAny >>= bHasLegend; + if ( bIncludeTable ) + { + aAny = xDocPropSet->getPropertyValue("NullDate"); + if ( !aAny.hasValue() ) + { + Reference xChild(rChartDoc, uno::UNO_QUERY ); + if ( xChild.is() ) + { + Reference< beans::XPropertySet > xParentDoc( xChild->getParent(),uno::UNO_QUERY); + if ( xParentDoc.is() && xParentDoc->getPropertySetInfo()->hasPropertyByName("NullDate") ) + aAny = xParentDoc->getPropertyValue("NullDate"); + } + } + + aAny >>= aNullDate; + } + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Required property not found in ChartDocument" ); + } + } + + if ( bIncludeTable && (aNullDate.Day != 30 || aNullDate.Month != 12 || aNullDate.Year != 1899 ) ) + { + SvXMLElementExport aSet( mrExport, XML_NAMESPACE_TABLE, XML_CALCULATION_SETTINGS, true, true ); + { + OUStringBuffer sBuffer; + ::sax::Converter::convertDateTime(sBuffer, aNullDate, nullptr); + mrExport.AddAttribute( XML_NAMESPACE_TABLE,XML_DATE_VALUE,sBuffer.makeStringAndClear()); + SvXMLElementExport aNull( mrExport, XML_NAMESPACE_TABLE, XML_NULL_DATE, true, true ); + } + } + + // chart element + std::unique_ptr xElChart; + + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet = rChartDoc->getArea(); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + } + + if( bExportContent ) + { + //export data provider in xlink:href attribute + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + OUString aDataProviderURL( ".." ); + if( xNewDoc->hasInternalDataProvider() ) + aDataProviderURL = "."; + else //special handling for data base data provider necessary + { + Reference< chart2::data::XDatabaseDataProvider > xDBDataProvider( xNewDoc->getDataProvider(), uno::UNO_QUERY ); + if( xDBDataProvider.is() ) + aDataProviderURL = "."; + } + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aDataProviderURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + } + + Reference xPivotTableDataProvider(xNewDoc->getDataProvider(), uno::UNO_QUERY); + if (xPivotTableDataProvider.is() && nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + OUString sPivotTableName = xPivotTableDataProvider->getPivotTableName(); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_PILOT_SOURCE, sPivotTableName); + } + + OUString sChartType( xDiagram->getDiagramType() ); + + // attributes + // determine class + if( !sChartType.isEmpty()) + { + enum XMLTokenEnum eXMLChartType = SchXMLTools::getTokenByChartType( sChartType, true /* bUseOldNames */ ); + + SAL_WARN_IF( eXMLChartType == XML_TOKEN_INVALID, "xmloff.chart", "invalid chart class" ); + if( eXMLChartType == XML_TOKEN_INVALID ) + eXMLChartType = XML_BAR; + + if( eXMLChartType == XML_ADD_IN ) + { + // sChartType is the service-name of the add-in + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, sChartType) ); + } + else if( eXMLChartType != XML_TOKEN_INVALID ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken(eXMLChartType )) ); + } + + //column-mapping or row-mapping + if( maSequenceMapping.hasElements() ) + { + enum XMLTokenEnum eTransToken = ::xmloff::token::XML_ROW_MAPPING; + if( mbRowSourceColumns ) + eTransToken = ::xmloff::token::XML_COLUMN_MAPPING; + OUString aSequenceMappingStr( lcl_GetStringFromNumberSequence( + maSequenceMapping, mbHasCategoryLabels && !xNewDoc->hasInternalDataProvider() ) ); + + mrExport.AddAttribute( XML_NAMESPACE_CHART, + ::xmloff::token::GetXMLToken( eTransToken ), + aSequenceMappingStr ); + } + } + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + //element + xElChart.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_CHART, true, true )); + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + // remove property states for autostyles + aPropertyStates.clear(); + + // title element + if( bHasMainTitle ) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getTitle(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + } + if( bExportContent ) + { + Reference< drawing::XShape > xShape = rChartDoc->getTitle(); + if( xShape.is()) // && "hasTitleBeenMoved" + addPosition( xShape ); + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element + SvXMLElementExport aElTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true ); + + // content (text:p) + Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); + if( xPropSet.is()) + { + Any aAny( xPropSet->getPropertyValue( "String" )); + OUString aText; + aAny >>= aText; + exportText( aText ); + } + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + + // subtitle element + if( bHasSubTitle ) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getSubTitle(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + } + + if( bExportContent ) + { + Reference< drawing::XShape > xShape = rChartDoc->getSubTitle(); + if( xShape.is()) + addPosition( xShape ); + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element (has no subelements) + SvXMLElementExport aElSubTitle( mrExport, XML_NAMESPACE_CHART, XML_SUBTITLE, true, true ); + + // content (text:p) + Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); + if( xPropSet.is()) + { + Any aAny( xPropSet->getPropertyValue( "String" )); + OUString aText; + aAny >>= aText; + exportText( aText ); + } + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + + // legend element + if( bHasLegend ) + { + // get property states for autostyles + if( mxExpPropMapper.is()) + { + Reference< beans::XPropertySet > xPropSet( rChartDoc->getLegend(), uno::UNO_QUERY ); + if( xPropSet.is()) + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + } + + if( bExportContent ) + { + Reference< beans::XPropertySet > xProp( rChartDoc->getLegend(), uno::UNO_QUERY ); + if( xProp.is()) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + + // export legend anchor position + try + { + Any aAny( xProp->getPropertyValue("Alignment")); + if( SchXMLEnumConverter::getLegendPositionConverter().exportXML( msString, aAny, mrExport.GetMM100UnitConverter() ) ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LEGEND_POSITION, msString ); + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property Align not found in ChartLegend" ); + } + + // export legend overlay + try + { + if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + Any aAny( xProp->getPropertyValue("Overlay")); + if(aAny.get()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_OVERLAY, OUString::boolean(true)); + } + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property Overlay not found in ChartLegend" ); + } + + // export absolute legend position + Reference< drawing::XShape > xLegendShape( xProp, uno::UNO_QUERY ); + addPosition( xLegendShape ); + + // export legend size + if (xLegendShape.is() && nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + try + { + chart::ChartLegendExpansion nLegendExpansion = chart::ChartLegendExpansion_HIGH; + OUString aExpansionString; + Any aAny( xProp->getPropertyValue("Expansion")); + bool bHasExpansion = (aAny >>= nLegendExpansion); + if( bHasExpansion && SchXMLEnumConverter::getLegendExpansionConverter().exportXML( aExpansionString, aAny, mrExport.GetMM100UnitConverter() ) ) + { + mrExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION, aExpansionString ); + if( nLegendExpansion == chart::ChartLegendExpansion_CUSTOM) + { + awt::Size aSize( xLegendShape->getSize() ); + // tdf#131966: chart legend attributes width and height shouldn't be exported to ODF 1.2 (strict) + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_013) + { // ODF 1.3 OFFICE-3883 + addSize( aSize, false ); + } + else if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + addSize( aSize, true ); + } + OUStringBuffer aAspectRatioString; + ::sax::Converter::convertDouble( + aAspectRatioString, + (aSize.Height == 0 + ? 1.0 + : double(aSize.Width)/double(aSize.Height))); + mrExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEGEND_EXPANSION_ASPECT_RATIO, aAspectRatioString.makeStringAndClear() ); + } + } + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property Expansion not found in ChartLegend" ); + } + } + } + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + // element + SvXMLElementExport aLegend( mrExport, XML_NAMESPACE_CHART, XML_LEGEND, true, true ); + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + + // plot-area element + if( xDiagram.is()) + exportPlotArea( xDiagram, xNewDiagram, aPageSize, bExportContent, bIncludeTable ); + + // export additional shapes + if( xDocPropSet.is() ) + { + if( bExportContent ) + { + if( mxAdditionalShapes.is()) + { + // can't call exportShapes with all shapes because the + // initialisation happened with the complete draw page and not + // the XShapes object used here. Thus the shapes have to be + // exported one by one + rtl::Reference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport(); + Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount( mxAdditionalShapes->getCount()); + for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ ) + { + mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape; + SAL_WARN_IF( !xShape.is(), "xmloff.chart", "Shape without an XShape?" ); + if( ! xShape.is()) + continue; + + rShapeExport->exportShape( xShape ); + } + // this would be the easier way if it worked: + //mrExport.GetShapeExport()->exportShapes( mxAdditionalShapes ); + } + } + else + { + // get a sequence of non-chart shapes (inserted via clipboard) + try + { + Any aShapesAny = xDocPropSet->getPropertyValue("AdditionalShapes"); + aShapesAny >>= mxAdditionalShapes; + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "AdditionalShapes not found" ); + } + + if( mxAdditionalShapes.is()) + { + // seek shapes has to be called for the whole page because in + // the shape export the vector of shapes is accessed via the + // ZOrder which might be (actually is) larger than the number of + // shapes in mxAdditionalShapes + Reference< drawing::XDrawPageSupplier > xSupplier( rChartDoc, uno::UNO_QUERY ); + SAL_WARN_IF( !xSupplier.is(), "xmloff.chart", "Cannot retrieve draw page to initialize shape export" ); + if( xSupplier.is() ) + { + Reference< drawing::XShapes > xDrawPage = xSupplier->getDrawPage(); + SAL_WARN_IF( !xDrawPage.is(), "xmloff.chart", "Invalid draw page for initializing shape export" ); + if( xDrawPage.is()) + mrExport.GetShapeExport()->seekShapes( xDrawPage ); + } + + // can't call collectShapesAutoStyles with all shapes because + // the initialisation happened with the complete draw page and + // not the XShapes object used here. Thus the shapes have to be + // exported one by one + rtl::Reference< XMLShapeExport > rShapeExport = mrExport.GetShapeExport(); + Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount( mxAdditionalShapes->getCount()); + for( sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++ ) + { + mxAdditionalShapes->getByIndex( nShapeId ) >>= xShape; + SAL_WARN_IF( !xShape.is(), "xmloff.chart", "Shape without an XShape?" ); + if( ! xShape.is()) + continue; + + rShapeExport->collectShapeAutoStyles( xShape ); + } + } + } + } + + // table element + // (is included as subelement of chart) + if( bExportContent ) + { + // #85929# always export table, otherwise clipboard may lose data + exportTable(); + } +} + +static void lcl_exportComplexLabel( const Sequence< uno::Any >& rComplexLabel, SvXMLExport& rExport ) +{ + sal_Int32 nLength = rComplexLabel.getLength(); + if( nLength<=1 ) + return; + SvXMLElementExport aTextList( rExport, XML_NAMESPACE_TEXT, XML_LIST, true, true ); + for(const auto& rElem : rComplexLabel) + { + SvXMLElementExport aListItem( rExport, XML_NAMESPACE_TEXT, XML_LIST_ITEM, true, true ); + OUString aString; + if( !(rElem >>= aString) ) + { + double aNum; + if (rElem >>= aNum) + { + aString = OUString::number(aNum); + } + } + SchXMLTools::exportText( rExport, aString, false /*bConvertTabsLFs*/ ); + } +} + +void SchXMLExportHelper_Impl::exportTable() +{ + // table element + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NAME, gsTableName ); + + try + { + bool bProtected = false; + Reference< beans::XPropertySet > xProps( mrExport.GetModel(), uno::UNO_QUERY_THROW ); + if ( ( xProps->getPropertyValue("DisableDataTableDialog") >>= bProtected ) && + bProtected ) + { + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TRUE ); + } + } + catch ( const uno::Exception& ) + { + } + + SvXMLElementExport aTable( mrExport, XML_NAMESPACE_TABLE, XML_TABLE, true, true ); + + bool bHasOwnData = false; + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + Reference< chart2::data::XRangeXMLConversion > xRangeConversion; + if( xNewDoc.is()) + { + bHasOwnData = xNewDoc->hasInternalDataProvider(); + xRangeConversion.set( xNewDoc->getDataProvider(), uno::UNO_QUERY ); + } + + Reference< chart2::XAnyDescriptionAccess > xAnyDescriptionAccess; + { + Reference< chart::XChartDocument > xChartDoc( mrExport.GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is() ) + xAnyDescriptionAccess.set( xChartDoc->getData(), uno::UNO_QUERY ); + } + + if( bHasOwnData ) + lcl_ReorderInternalSequencesAccordingToTheirRangeName( m_aDataSequencesToExport ); + lcl_TableData aData( lcl_getDataForLocalTable( m_aDataSequencesToExport + , xAnyDescriptionAccess, maCategoriesRange + , mbRowSourceColumns, xRangeConversion )); + + tStringVector::const_iterator aDataRangeIter( aData.aDataRangeRepresentations.begin()); + const tStringVector::const_iterator aDataRangeEndIter( aData.aDataRangeRepresentations.end()); + + tStringVector::const_iterator aRowDescriptions_RangeIter( aData.aRowDescriptions_Ranges.begin()); + const tStringVector::const_iterator aRowDescriptions_RangeEnd( aData.aRowDescriptions_Ranges.end()); + + // declare columns + { + SvXMLElementExport aHeaderColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS, true, true ); + SvXMLElementExport aHeaderColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); + } + { + SvXMLElementExport aColumns( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS, true, true ); + + sal_Int32 nNextIndex = 0; + for(sal_Int32 nHiddenIndex : aData.aHiddenColumns) + { + //i91578 display of hidden values (copy paste scenario; export hidden flag thus it can be used during migration to locale table upon paste ) + if( nHiddenIndex > nNextIndex ) + { + sal_Int64 nRepeat = static_cast< sal_Int64 >( nHiddenIndex - nNextIndex ); + if(nRepeat>1) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, + OUString::number( nRepeat )); + SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); + } + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_VISIBILITY, GetXMLToken( XML_COLLAPSE ) ); + SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); + nNextIndex = nHiddenIndex+1; + } + + sal_Int32 nEndIndex = aData.aColumnDescriptions.size()-1; + if( nEndIndex >= nNextIndex ) + { + sal_Int64 nRepeat = static_cast< sal_Int64 >( nEndIndex - nNextIndex + 1 ); + if(nRepeat>1) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, + OUString::number( nRepeat )); + SvXMLElementExport aColumn( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); + } + } + + // export rows with content + //export header row + { + SvXMLElementExport aHeaderRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS, true, true ); + SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true ); + + //first one empty cell for the row descriptions + { + SvXMLElementExport aEmptyCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true ); + SvXMLElementExport aEmptyParagraph( mrExport, XML_NAMESPACE_TEXT, XML_P, true, true ); + } + + //export column descriptions + tStringVector::const_iterator aColumnDescriptions_RangeIter( aData.aColumnDescriptions_Ranges.begin()); + const tStringVector::const_iterator aColumnDescriptions_RangeEnd( aData.aColumnDescriptions_Ranges.end()); + const Sequence< Sequence< uno::Any > >& rComplexColumnDescriptions = aData.aComplexColumnDescriptions; + sal_Int32 nComplexCount = rComplexColumnDescriptions.getLength(); + sal_Int32 nC = 0; + for( const auto& rDesc : aData.aColumnDescriptions ) + { + bool bExportString = true; + if( nC < nComplexCount ) + { + const Sequence< uno::Any >& rComplexLabel = rComplexColumnDescriptions[nC]; + if( rComplexLabel.hasElements() ) + { + double fValue=0.0; + if( rComplexLabel[0] >>=fValue ) + { + bExportString = false; + + ::sax::Converter::convertDouble( + msStringBuffer, fValue); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT ); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString ); + } + } + } + if( bExportString ) + { + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING ); + } + + SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true ); + exportText( rDesc ); + if( nC < nComplexCount ) + lcl_exportComplexLabel( rComplexColumnDescriptions[nC], mrExport ); + if( !bHasOwnData && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd ) + { + // remind the original range to allow a correct re-association when copying via clipboard + if (!(*aColumnDescriptions_RangeIter).isEmpty()) + SchXMLTools::exportRangeToSomewhere( mrExport, *aColumnDescriptions_RangeIter ); + ++aColumnDescriptions_RangeIter; + } + + nC++; + } + SAL_WARN_IF( !bHasOwnData && (aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aColumnDescriptions_RangeIter != aColumnDescriptions_RangeEnd" ); + } // closing row and header-rows elements + + // export value rows + { + SvXMLElementExport aRows( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROWS, true, true ); + tStringVector::const_iterator aRowDescriptionsIter( aData.aRowDescriptions.begin()); + const Sequence< Sequence< uno::Any > >& rComplexRowDescriptions = aData.aComplexRowDescriptions; + sal_Int32 nComplexCount = rComplexRowDescriptions.getLength(); + sal_Int32 nC = 0; + + for( const auto& rRow : aData.aDataInRows ) + { + SvXMLElementExport aRow( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true ); + + //export row descriptions + { + bool bExportString = true; + if( nC < nComplexCount ) + { + const Sequence< uno::Any >& rComplexLabel = rComplexRowDescriptions[nC]; + if( rComplexLabel.hasElements() ) + { + double fValue=0.0; + if( rComplexLabel[0] >>=fValue ) + { + bExportString = false; + + ::sax::Converter::convertDouble(msStringBuffer, fValue); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT ); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString ); + } + } + } + if( bExportString ) + { + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING ); + } + + SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true ); + if( aRowDescriptionsIter != aData.aRowDescriptions.end()) + { + exportText( *aRowDescriptionsIter ); + if( nC < nComplexCount ) + lcl_exportComplexLabel( rComplexRowDescriptions[nC], mrExport ); + if( !bHasOwnData && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd ) + { + // remind the original range to allow a correct re-association when copying via clipboard + SchXMLTools::exportRangeToSomewhere( mrExport, *aRowDescriptions_RangeIter ); + ++aRowDescriptions_RangeIter; + } + ++aRowDescriptionsIter; + } + } + + //export row values + for( t2DNumberContainer::value_type::const_iterator aColIt( rRow.begin()); + aColIt != rRow.end(); ++aColIt ) + { + ::sax::Converter::convertDouble( msStringBuffer, *aColIt ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT ); + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_VALUE, msString ); + SvXMLElementExport aCell( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_CELL, true, true ); + exportText( msString ); // do not convert tabs and lfs + if( ( !bHasOwnData && aDataRangeIter != aDataRangeEndIter ) && + ( mbRowSourceColumns || (aColIt == rRow.begin()) ) ) + { + // remind the original range to allow a correct re-association when copying via clipboard + if (!(*aDataRangeIter).isEmpty()) + SchXMLTools::exportRangeToSomewhere( mrExport, *aDataRangeIter ); + ++aDataRangeIter; + } + } + + ++nC; + } + } + + // if range iterator was used it should have reached its end + SAL_WARN_IF( !bHasOwnData && (aDataRangeIter != aDataRangeEndIter), "xmloff.chart", "bHasOwnData == false && aDataRangeIter != aDataRangeEndIter" ); + SAL_WARN_IF( !bHasOwnData && (aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd), "xmloff.chart", "bHasOwnData == false && aRowDescriptions_RangeIter != aRowDescriptions_RangeEnd" ); +} + +namespace +{ + +Reference< chart2::XCoordinateSystem > lcl_getCooSys( const Reference< chart2::XDiagram > & xNewDiagram ) +{ + Reference< chart2::XCoordinateSystem > xCooSys; + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDiagram, uno::UNO_QUERY ); + if(xCooSysCnt.is()) + { + Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() ); + if(aCooSysSeq.hasElements()) + xCooSys = aCooSysSeq[0]; + } + return xCooSys; +} + +Reference< chart2::XAxis > lcl_getAxis( const Reference< chart2::XCoordinateSystem >& xCooSys, + enum XMLTokenEnum eDimension, bool bPrimary=true ) +{ + Reference< chart2::XAxis > xNewAxis; + try + { + if( xCooSys.is() ) + { + sal_Int32 nDimensionIndex=0; + switch( eDimension ) + { + case XML_X: + nDimensionIndex=0; + break; + case XML_Y: + nDimensionIndex=1; + break; + case XML_Z: + nDimensionIndex=2; + break; + default: + break; + } + + xNewAxis = xCooSys->getAxisByDimension( nDimensionIndex, bPrimary ? 0 : 1 ); + } + } + catch( const uno::Exception & ) + { + } + return xNewAxis; +} + +} + +void SchXMLExportHelper_Impl::exportPlotArea( + const Reference< chart::XDiagram >& xDiagram, + const Reference< chart2::XDiagram >& xNewDiagram, + const awt::Size & rPageSize, + bool bExportContent, + bool bIncludeTable ) +{ + SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" ); + if( ! xDiagram.is()) + return; + + // variables for autostyles + Reference< beans::XPropertySet > xPropSet; + std::vector< XMLPropertyState > aPropertyStates; + + msStringBuffer.setLength( 0 ); + + // plot-area element + + std::unique_ptr xElPlotArea; + // get property states for autostyles + xPropSet.set( xDiagram, uno::UNO_QUERY ); + if( xPropSet.is()) + { + if( mxExpPropMapper.is()) + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + } + if( bExportContent ) + { + rtl::Reference< XMLShapeExport > rShapeExport; + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + if( !msChartAddress.isEmpty() ) + { + if( !bIncludeTable ) + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, msChartAddress ); + + Reference< chart::XChartDocument > xDoc( mrExport.GetModel(), uno::UNO_QUERY ); + if( xDoc.is() ) + { + Reference< beans::XPropertySet > xDocProp( xDoc, uno::UNO_QUERY ); + if( xDocProp.is()) + { + Any aAny; + + try + { + bool bFirstCol = false, bFirstRow = false; + + aAny = xDocProp->getPropertyValue( "DataSourceLabelsInFirstColumn" ); + aAny >>= bFirstCol; + aAny = xDocProp->getPropertyValue( "DataSourceLabelsInFirstRow" ); + aAny >>= bFirstRow; + + if( bFirstCol || bFirstRow ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DATA_SOURCE_HAS_LABELS ), + ( bFirstCol + ? ( bFirstRow + ? ::xmloff::token::GetXMLToken( ::xmloff::token::XML_BOTH ) + : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_COLUMN )) + : ::xmloff::token::GetXMLToken( ::xmloff::token::XML_ROW ))); + } + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Properties missing" ); + } + } + } + } + + // attributes + if( xDiagram.is()) + { + addPosition( xDiagram ); + addSize( xDiagram ); + } + + bool bIs3DChart = false; + + if( xPropSet.is()) + { + Any aAny; + + // 3d attributes + try + { + aAny = xPropSet->getPropertyValue("Dim3D"); + aAny >>= bIs3DChart; + + if( bIs3DChart ) + { + rShapeExport = mrExport.GetShapeExport(); + if( rShapeExport.is()) + rShapeExport->export3DSceneAttributes( xPropSet ); + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "chart:exportPlotAreaException caught"); + } + } + + // plot-area element + xElPlotArea.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_PLOT_AREA, true, true )); + + //inner position rectangle element + exportCoordinateRegion( xDiagram ); + + // light sources (inside plot area element) + if( bIs3DChart && + rShapeExport.is()) + rShapeExport->export3DLamps( xPropSet ); + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + // remove property states for autostyles + aPropertyStates.clear(); + + // axis elements + exportAxes( xDiagram, xNewDiagram, bExportContent ); + + // series elements + Reference< chart2::XAxis > xSecondYAxis = lcl_getAxis( lcl_getCooSys( xNewDiagram ), XML_Y, false ); + exportSeries( xNewDiagram, rPageSize, bExportContent, xSecondYAxis.is() ); + + // stock-chart elements + OUString sChartType ( xDiagram->getDiagramType()); + if( sChartType == "com.sun.star.chart.StockDiagram" ) + { + Reference< chart::XStatisticDisplay > xStockPropProvider( xDiagram, uno::UNO_QUERY ); + if( xStockPropProvider.is()) + { + // stock-gain-marker + Reference< beans::XPropertySet > xStockPropSet = xStockPropProvider->getUpBar(); + if( xStockPropSet.is()) + { + aPropertyStates.clear(); + aPropertyStates = mxExpPropMapper->Filter(mrExport, xStockPropSet); + + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_GAIN_MARKER, true, true ); + } + else + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + } + } + + // stock-loss-marker + xStockPropSet = xStockPropProvider->getDownBar(); + if( xStockPropSet.is()) + { + aPropertyStates.clear(); + aPropertyStates = mxExpPropMapper->Filter(mrExport, xStockPropSet); + + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_LOSS_MARKER, true, true ); + } + else + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + } + } + + // stock-range-line + xStockPropSet = xStockPropProvider->getMinMaxLine(); + if( xStockPropSet.is()) + { + aPropertyStates.clear(); + aPropertyStates = mxExpPropMapper->Filter(mrExport, xStockPropSet); + + if( !aPropertyStates.empty() ) + { + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aGain( mrExport, XML_NAMESPACE_CHART, XML_STOCK_RANGE_LINE, true, true ); + } + else + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + } + } + } + } + + // wall and floor element + Reference< chart::X3DDisplay > xWallFloorSupplier( xDiagram, uno::UNO_QUERY ); + if( !(mxExpPropMapper.is() && + xWallFloorSupplier.is())) + return; + + // remove property states for autostyles + aPropertyStates.clear(); + + Reference< beans::XPropertySet > xWallPropSet = xWallFloorSupplier->getWall(); + if( xWallPropSet.is()) + { + aPropertyStates = mxExpPropMapper->Filter(mrExport, xWallPropSet); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aWall( mrExport, XML_NAMESPACE_CHART, XML_WALL, true, true ); + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + } + } + + // floor element + // remove property states for autostyles + aPropertyStates.clear(); + + Reference< beans::XPropertySet > xFloorPropSet = xWallFloorSupplier->getFloor(); + if( !xFloorPropSet.is()) + return; + + aPropertyStates = mxExpPropMapper->Filter(mrExport, xFloorPropSet); + + if( aPropertyStates.empty() ) + return; + + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport aFloor( mrExport, XML_NAMESPACE_CHART, XML_FLOOR, true, true ); + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } +} + +void SchXMLExportHelper_Impl::exportCoordinateRegion( const uno::Reference< chart::XDiagram >& xDiagram ) +{ + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + if (nCurrentODFVersion <= SvtSaveOptions::ODFSVER_012) //do not export to ODF 1.2 or older + return; + + Reference< chart::XDiagramPositioning > xDiaPos( xDiagram, uno::UNO_QUERY ); + SAL_WARN_IF( !xDiaPos.is(), "xmloff.chart", "Invalid xDiaPos as parameter" ); + if( !xDiaPos.is() ) + return; + + awt::Rectangle aRect( xDiaPos->calculateDiagramPositionExcludingAxes() ); + addPosition( awt::Point(aRect.X,aRect.Y) ); + addSize( awt::Size(aRect.Width,aRect.Height) ); + + // ODF 1.3 OFFICE-3928 + SvXMLElementExport aCoordinateRegion( mrExport, + (SvtSaveOptions::ODFSVER_013 <= nCurrentODFVersion) ? XML_NAMESPACE_CHART : XML_NAMESPACE_CHART_EXT, + XML_COORDINATE_REGION, true, true ); +} + +namespace +{ + XMLTokenEnum lcl_getTimeUnitToken( sal_Int32 nTimeUnit ) + { + XMLTokenEnum eToken = XML_DAYS; + switch( nTimeUnit ) + { + case css::chart::TimeUnit::YEAR: + eToken = XML_YEARS; + break; + case css::chart::TimeUnit::MONTH: + eToken = XML_MONTHS; + break; + default://days + break; + } + return eToken; + } +} + +void SchXMLExportHelper_Impl::exportDateScale( const Reference< beans::XPropertySet >& rAxisProps ) +{ + if( !rAxisProps.is() ) + return; + + chart::TimeIncrement aIncrement; + if( !(rAxisProps->getPropertyValue("TimeIncrement") >>= aIncrement) ) + return; + + sal_Int32 nTimeResolution = css::chart::TimeUnit::DAY; + if( aIncrement.TimeResolution >>= nTimeResolution ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_BASE_TIME_UNIT, lcl_getTimeUnitToken( nTimeResolution ) ); + + chart::TimeInterval aInterval; + if( aIncrement.MajorTimeInterval >>= aInterval ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_VALUE, OUString::number(aInterval.Number) ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) ); + } + if( aIncrement.MinorTimeInterval >>= aInterval ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_VALUE, OUString::number(aInterval.Number) ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_UNIT, lcl_getTimeUnitToken( aInterval.TimeUnit ) ); + } + + SvXMLElementExport aDateScale( mrExport, XML_NAMESPACE_CHART_EXT, XML_DATE_SCALE, true, true );//#i25706#todo: change namespace for next ODF version +} + +void SchXMLExportHelper_Impl::exportAxisTitle( const Reference< beans::XPropertySet >& rTitleProps, bool bExportContent ) +{ + if( !rTitleProps.is() ) + return; + std::vector aPropertyStates = mxExpPropMapper->Filter(mrExport, rTitleProps); + if( bExportContent ) + { + OUString aText; + Any aAny( rTitleProps->getPropertyValue( "String" )); + aAny >>= aText; + + Reference< drawing::XShape > xShape( rTitleProps, uno::UNO_QUERY ); + if( xShape.is()) + addPosition( xShape ); + + AddAutoStyleAttribute( aPropertyStates ); + SvXMLElementExport aTitle( mrExport, XML_NAMESPACE_CHART, XML_TITLE, true, true ); + + // paragraph containing title + exportText( aText ); + } + else + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + aPropertyStates.clear(); +} + +void SchXMLExportHelper_Impl::exportGrid( const Reference< beans::XPropertySet >& rGridProperties, bool bMajor, bool bExportContent ) +{ + if( !rGridProperties.is() ) + return; + std::vector aPropertyStates = mxExpPropMapper->Filter(mrExport, rGridProperties); + if( bExportContent ) + { + AddAutoStyleAttribute( aPropertyStates ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, bMajor ? XML_MAJOR : XML_MINOR ); + SvXMLElementExport aGrid( mrExport, XML_NAMESPACE_CHART, XML_GRID, true, true ); + } + else + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + aPropertyStates.clear(); +} + +namespace +{ + +//returns true if a date scale needs to be exported +bool lcl_exportAxisType( const Reference< chart2::XAxis >& rChart2Axis, SvXMLExport& rExport) +{ + bool bExportDateScale = false; + if( !rChart2Axis.is() ) + return bExportDateScale; + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + rExport.getSaneDefaultVersion()); + if ((nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) == 0) //do not export to ODF 1.3 or older + return bExportDateScale; + + chart2::ScaleData aScale( rChart2Axis->getScaleData() ); + //#i25706#todo: change namespace for next ODF version + sal_uInt16 nNameSpace = XML_NAMESPACE_CHART_EXT; + + switch(aScale.AxisType) + { + case chart2::AxisType::CATEGORY: + if( aScale.AutoDateAxis ) + { + rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO ); + bExportDateScale = true; + } + else + rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_TEXT ); + break; + case chart2::AxisType::DATE: + rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_DATE ); + bExportDateScale = true; + break; + default: //AUTOMATIC + rExport.AddAttribute( nNameSpace, XML_AXIS_TYPE, XML_AUTO ); + break; + } + + return bExportDateScale; +} + +void disableLinkedNumberFormat( + std::vector& rPropStates, const rtl::Reference& rMapper ) +{ + for (XMLPropertyState & rState : rPropStates) + { + if (rState.mnIndex < 0 || rMapper->GetEntryCount() <= rState.mnIndex) + continue; + + OUString aXMLName = rMapper->GetEntryXMLName(rState.mnIndex); + + if (aXMLName != "link-data-style-to-source") + continue; + + // Entry found. Set the value to false and bail out. + rState.maValue <<= false; + return; + } + + // Entry not found. Insert a new entry for this. + sal_Int32 nIndex = rMapper->GetEntryIndex(XML_NAMESPACE_CHART, u"link-data-style-to-source", 0); + XMLPropertyState aState(nIndex); + aState.maValue <<= false; + rPropStates.push_back(aState); +} + +} + +void SchXMLExportHelper_Impl::exportAxis( + enum XMLTokenEnum eDimension, + enum XMLTokenEnum eAxisName, + const Reference< beans::XPropertySet >& rAxisProps, + const Reference< chart2::XAxis >& rChart2Axis, + const OUString& rCategoriesRange, + bool bHasTitle, bool bHasMajorGrid, bool bHasMinorGrid, + bool bExportContent, std::u16string_view sChartType ) +{ + std::vector< XMLPropertyState > aPropertyStates; + std::unique_ptr pAxis; + + // get property states for autostyles + if( rAxisProps.is() && mxExpPropMapper.is() ) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED + && eDimension == XML_X) + { + chart2::ScaleData aScaleData(rChart2Axis->getScaleData()); + bool bShiftedCatPos = aScaleData.ShiftedCategoryPosition; + if (sChartType == u"com.sun.star.chart.BarDiagram" || sChartType == u"com.sun.star.chart.StockDiagram") + { + if (!bShiftedCatPos) + rAxisProps->setPropertyValue("MajorOrigin", uno::Any(0.0)); + } + else if (bShiftedCatPos) + rAxisProps->setPropertyValue("MajorOrigin", uno::Any(0.5)); + } + + lcl_exportNumberFormat( "NumberFormat", rAxisProps, mrExport ); + aPropertyStates = mxExpPropMapper->Filter(mrExport, rAxisProps); + + if (!maSrcShellID.isEmpty() && !maDestShellID.isEmpty() && maSrcShellID != maDestShellID) + { + // Disable link to source number format property when pasting to + // a different doc shell. These shell ID's should be both empty + // during real ODF export. + disableLinkedNumberFormat(aPropertyStates, mxExpPropMapper->getPropertySetMapper()); + } + } + + bool bExportDateScale = false; + if( bExportContent ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, eDimension ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_NAME, eAxisName ); + AddAutoStyleAttribute( aPropertyStates ); // write style name + if( !rCategoriesRange.isEmpty() ) + bExportDateScale = lcl_exportAxisType( rChart2Axis, mrExport ); + + // open axis element + pAxis.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_AXIS, true, true )); + } + else + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + aPropertyStates.clear(); + + //date scale + if( bExportDateScale ) + exportDateScale( rAxisProps ); + + Reference< beans::XPropertySet > xTitleProps; + Reference< beans::XPropertySet > xMajorGridProps; + Reference< beans::XPropertySet > xMinorGridProps; + Reference< chart::XAxis > xAxis( rAxisProps, uno::UNO_QUERY ); + if( xAxis.is() ) + { + xTitleProps = bHasTitle ? xAxis->getAxisTitle() : nullptr; + xMajorGridProps = bHasMajorGrid ? xAxis->getMajorGrid() : nullptr; + xMinorGridProps = bHasMinorGrid ? xAxis->getMinorGrid() : nullptr; + } + + // axis-title + exportAxisTitle( xTitleProps , bExportContent ); + + // categories if we have a categories chart + if( bExportContent && !rCategoriesRange.isEmpty() ) + { + mrExport.AddAttribute( XML_NAMESPACE_TABLE, XML_CELL_RANGE_ADDRESS, rCategoriesRange ); + SvXMLElementExport aCategories( mrExport, XML_NAMESPACE_CHART, XML_CATEGORIES, true, true ); + } + + // grid + exportGrid( xMajorGridProps, true, bExportContent ); + exportGrid( xMinorGridProps, false, bExportContent ); +} + +void SchXMLExportHelper_Impl::exportAxes( + const Reference< chart::XDiagram > & xDiagram, + const Reference< chart2::XDiagram > & xNewDiagram, + bool bExportContent ) +{ + SAL_WARN_IF( !xDiagram.is(), "xmloff.chart", "Invalid XDiagram as parameter" ); + if( ! xDiagram.is()) + return; + + // get some properties from document first + bool bHasXAxis = false, + bHasYAxis = false, + bHasZAxis = false, + bHasSecondaryXAxis = false, + bHasSecondaryYAxis = false; + bool bHasXAxisTitle = false, + bHasYAxisTitle = false, + bHasZAxisTitle = false, + bHasSecondaryXAxisTitle = false, + bHasSecondaryYAxisTitle = false; + bool bHasXAxisMajorGrid = false, + bHasXAxisMinorGrid = false, + bHasYAxisMajorGrid = false, + bHasYAxisMinorGrid = false, + bHasZAxisMajorGrid = false, + bHasZAxisMinorGrid = false; + + // get multiple properties using XMultiPropertySet + MultiPropertySetHandler aDiagramProperties (xDiagram); + + aDiagramProperties.Add ("HasXAxis", bHasXAxis); + aDiagramProperties.Add ("HasYAxis", bHasYAxis); + aDiagramProperties.Add ("HasZAxis", bHasZAxis); + aDiagramProperties.Add ("HasSecondaryXAxis", bHasSecondaryXAxis); + aDiagramProperties.Add ("HasSecondaryYAxis", bHasSecondaryYAxis); + + aDiagramProperties.Add ("HasXAxisTitle", bHasXAxisTitle); + aDiagramProperties.Add ("HasYAxisTitle", bHasYAxisTitle); + aDiagramProperties.Add ("HasZAxisTitle", bHasZAxisTitle); + aDiagramProperties.Add ("HasSecondaryXAxisTitle", bHasSecondaryXAxisTitle); + aDiagramProperties.Add ("HasSecondaryYAxisTitle", bHasSecondaryYAxisTitle); + + aDiagramProperties.Add ("HasXAxisGrid", bHasXAxisMajorGrid); + aDiagramProperties.Add ("HasYAxisGrid", bHasYAxisMajorGrid); + aDiagramProperties.Add ("HasZAxisGrid", bHasZAxisMajorGrid); + + aDiagramProperties.Add ("HasXAxisHelpGrid", bHasXAxisMinorGrid); + aDiagramProperties.Add ("HasYAxisHelpGrid", bHasYAxisMinorGrid); + aDiagramProperties.Add ("HasZAxisHelpGrid", bHasZAxisMinorGrid); + + if ( ! aDiagramProperties.GetProperties ()) + { + SAL_INFO("xmloff.chart", "Required properties not found in Chart diagram"); + } + + Reference< chart2::XCoordinateSystem > xCooSys( lcl_getCooSys(xNewDiagram) ); + + // write an axis element also if the axis itself is not visible, but a grid or a title + + OUString aCategoriesRange; + Reference< chart::XAxisSupplier > xAxisSupp( xDiagram, uno::UNO_QUERY ); + OUString sChartType = xDiagram->getDiagramType(); + + // x axis + + Reference< css::chart2::XAxis > xNewAxis = lcl_getAxis( xCooSys, XML_X ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(0) : nullptr, uno::UNO_QUERY ); + if( mbHasCategoryLabels && bExportContent ) + { + Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) ); + if( xCategories.is() ) + { + Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() ); + if( xValues.is() ) + { + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + maCategoriesRange = xValues->getSourceRangeRepresentation(); + aCategoriesRange = lcl_ConvertRange( maCategoriesRange, xNewDoc ); + } + } + } + exportAxis( XML_X, XML_PRIMARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasXAxisTitle, bHasXAxisMajorGrid, bHasXAxisMinorGrid, bExportContent, sChartType ); + aCategoriesRange.clear(); + } + + // secondary x axis + + xNewAxis = lcl_getAxis( xCooSys, XML_X, false ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(0) : nullptr, uno::UNO_QUERY ); + exportAxis( XML_X, XML_SECONDARY_X, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryXAxisTitle, false, false, bExportContent, sChartType ); + } + + // y axis + + xNewAxis = lcl_getAxis( xCooSys, XML_Y ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(1) : nullptr, uno::UNO_QUERY ); + exportAxis( XML_Y, XML_PRIMARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasYAxisTitle, bHasYAxisMajorGrid, bHasYAxisMinorGrid, bExportContent, sChartType ); + } + + // secondary y axis + + xNewAxis = lcl_getAxis( xCooSys, XML_Y, false ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getSecondaryAxis(1) : nullptr, uno::UNO_QUERY ); + exportAxis( XML_Y, XML_SECONDARY_Y, xAxisProps, xNewAxis, aCategoriesRange, bHasSecondaryYAxisTitle, false, false, bExportContent, sChartType ); + } + + // z axis + + xNewAxis = lcl_getAxis( xCooSys, XML_Z ); + if( xNewAxis.is() ) + { + Reference< beans::XPropertySet > xAxisProps( xAxisSupp.is() ? xAxisSupp->getAxis(2) : nullptr, uno::UNO_QUERY ); + exportAxis( XML_Z, XML_PRIMARY_Z, xAxisProps, xNewAxis, aCategoriesRange, bHasZAxisTitle, bHasZAxisMajorGrid, bHasZAxisMinorGrid, bExportContent, sChartType ); + } +} + +namespace +{ + bool lcl_hasNoValuesButText( const uno::Reference< chart2::data::XDataSequence >& xDataSequence ) + { + if( !xDataSequence.is() ) + return false;//have no data + + Sequence< uno::Any > aData; + Reference< chart2::data::XNumericalDataSequence > xNumericalDataSequence( xDataSequence, uno::UNO_QUERY ); + if( xNumericalDataSequence.is() ) + { + const Sequence< double > aDoubles( xNumericalDataSequence->getNumericalData() ); + if (std::any_of(aDoubles.begin(), aDoubles.end(), [](double fDouble) { return !std::isnan( fDouble ); })) + return false;//have double value + } + else + { + aData = xDataSequence->getData(); + double fDouble = 0.0; + bool bHaveDouble = std::any_of(std::cbegin(aData), std::cend(aData), + [&fDouble](const uno::Any& rData) { return (rData >>= fDouble) && !std::isnan( fDouble ); }); + if (bHaveDouble) + return false;//have double value + } + //no values found + + Reference< chart2::data::XTextualDataSequence > xTextualDataSequence( xDataSequence, uno::UNO_QUERY ); + if( xTextualDataSequence.is() ) + { + const uno::Sequence< OUString > aStrings( xTextualDataSequence->getTextualData() ); + if (std::any_of(aStrings.begin(), aStrings.end(), [](const OUString& rString) { return !rString.isEmpty(); })) + return true;//have text + } + else + { + if( !aData.hasElements() ) + aData = xDataSequence->getData(); + OUString aString; + bool bHaveText = std::any_of(std::cbegin(aData), std::cend(aData), + [&aString](const uno::Any& rData) { return (rData >>= aString) && !aString.isEmpty(); }); + if (bHaveText) + return true;//have text + } + //no doubles and no texts + return false; + } + +// ODF has the line and fill properties in a element, which is referenced by the +// element. But LibreOffice has them as special label properties of the series +// or point respectively. The following method generates ODF from internal API name. +void lcl_createDataLabelProperties( + std::vector& rDataLabelPropertyStates, + const Reference& xPropSet, + const rtl::Reference& xExpPropMapper) +{ + if (!xExpPropMapper.is() || !xPropSet.is()) + return; + + const uno::Reference xInfo(xPropSet->getPropertySetInfo()); + const uno::Reference xPropState(xPropSet, uno::UNO_QUERY); + const rtl::Reference& rPropertySetMapper( + xExpPropMapper->getPropertySetMapper()); + if (!xInfo.is() || !xPropState.is() || !rPropertySetMapper.is()) + return; + + struct API2ODFMapItem + { + OUString sAPIName; + sal_uInt16 nNameSpace; // from include/xmloff/xmlnamespace.hxx + OUString sLocalName; + API2ODFMapItem(const OUString& sAPI, const sal_uInt16 nNS, const OUString& sLocal) + : sAPIName(sAPI) + , nNameSpace(nNS) + , sLocalName(sLocal) + { + } + }; + + const API2ODFMapItem aLabelFoo2ODFArray[] + = { API2ODFMapItem("LabelBorderStyle", XML_NAMESPACE_DRAW, "stroke"), + API2ODFMapItem("LabelBorderWidth", XML_NAMESPACE_SVG, "stroke-width"), + API2ODFMapItem("LabelBorderColor", XML_NAMESPACE_SVG, "stroke-color"), + API2ODFMapItem("LabelBorderDashName", XML_NAMESPACE_DRAW, "stroke-dash"), + API2ODFMapItem("LabelBorderTransparency", XML_NAMESPACE_SVG, "stroke-opacity"), + API2ODFMapItem("LabelFillStyle", XML_NAMESPACE_DRAW, "fill"), + API2ODFMapItem("LabelFillBackground", XML_NAMESPACE_DRAW, "fill-hatch-solid"), + API2ODFMapItem("LabelFillHatchName", XML_NAMESPACE_DRAW, "fill-hatch-name"), + API2ODFMapItem("LabelFillColor", XML_NAMESPACE_DRAW, "fill-color") }; + + for (const auto& rIt : aLabelFoo2ODFArray) + { + if (!xInfo->hasPropertyByName(rIt.sAPIName) + || xPropState->getPropertyState(rIt.sAPIName) != beans::PropertyState_DIRECT_VALUE) + continue; + sal_Int32 nTargetIndex + = rPropertySetMapper->GetEntryIndex(rIt.nNameSpace, rIt.sLocalName, 0); + if (nTargetIndex < 0) + continue; + XMLPropertyState aDataLabelStateItem(nTargetIndex, + xPropSet->getPropertyValue(rIt.sAPIName)); + rDataLabelPropertyStates.emplace_back(aDataLabelStateItem); + } +} +} // anonymous namespace + +void SchXMLExportHelper_Impl::exportSeries( + const Reference< chart2::XDiagram > & xNewDiagram, + const awt::Size & rPageSize, + bool bExportContent, + bool bHasTwoYAxes ) +{ + Reference< chart2::XCoordinateSystemContainer > xBCooSysCnt( xNewDiagram, uno::UNO_QUERY ); + if( ! xBCooSysCnt.is()) + return; + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + + OUString aFirstXDomainRange; + OUString aFirstYDomainRange; + + std::vector< XMLPropertyState > aPropertyStates; + std::vector< XMLPropertyState > aDataLabelPropertyStates; + + const Sequence< Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xBCooSysCnt->getCoordinateSystems()); + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY ); + if( ! xCTCnt.is()) + continue; + const Sequence< Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes()); + for( const auto& rChartType : aCTSeq ) + { + Reference< chart2::XDataSeriesContainer > xDSCnt( rChartType, uno::UNO_QUERY ); + if( ! xDSCnt.is()) + continue; + // note: if xDSCnt.is() then also aCTSeq[nCTIdx] + OUString aChartType( rChartType->getChartType()); + OUString aLabelRole = rChartType->getRoleOfSequenceForSeriesLabel(); + + // special export for stock charts + if ( aChartType == "com.sun.star.chart2.CandleStickChartType" ) + { + bool bJapaneseCandleSticks = false; + Reference< beans::XPropertySet > xCTProp( rChartType, uno::UNO_QUERY ); + if( xCTProp.is()) + xCTProp->getPropertyValue("Japanese") >>= bJapaneseCandleSticks; + exportCandleStickSeries( + xDSCnt->getDataSeries(), xNewDiagram, bJapaneseCandleSticks, bExportContent ); + continue; + } + + // export dataseries for current chart-type + Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries()); + for( sal_Int32 nSeriesIdx=0; nSeriesIdx xSource( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ); + if( xSource.is()) + { + std::unique_ptr pSeries; + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt( + xSource->getDataSequences()); + sal_Int32 nMainSequenceIndex = -1; + sal_Int32 nSeriesLength = 0; + bool bHasMeanValueLine = false; + Reference< beans::XPropertySet > xPropSet; + tLabelValuesDataPair aSeriesLabelValuesPair; + + // search for main sequence and create a series element + { + Reference< chart2::data::XDataSequence > xValuesSeq; + Reference< chart2::data::XDataSequence > xLabelSeq; + sal_Int32 nSeqIdx=0; + for( ; nSeqIdx xTempValueSeq( aSeqCnt[nSeqIdx]->getValues() ); + if( nMainSequenceIndex==-1 ) + { + OUString aRole; + Reference< beans::XPropertySet > xSeqProp( xTempValueSeq, uno::UNO_QUERY ); + if( xSeqProp.is()) + xSeqProp->getPropertyValue("Role") >>= aRole; + // "main" sequence + if( aRole == aLabelRole ) + { + xValuesSeq.set( xTempValueSeq ); + xLabelSeq.set( aSeqCnt[nSeqIdx]->getLabel()); + nMainSequenceIndex = nSeqIdx; + } + } + sal_Int32 nSequenceLength = (xTempValueSeq.is()? xTempValueSeq->getData().getLength() : sal_Int32(0)); + if( nSeriesLength < nSequenceLength ) + nSeriesLength = nSequenceLength; + } + + // have found the main sequence, then xValuesSeq and + // xLabelSeq contain those. Otherwise both are empty + { + sal_Int32 nAttachedAxis = chart::ChartAxisAssign::PRIMARY_Y; + // get property states for autostyles + try + { + xPropSet = SchXMLSeriesHelper::createOldAPISeriesPropertySet( + aSeriesSeq[nSeriesIdx], mrExport.GetModel() ); + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Series not found or no XPropertySet" ); + continue; + } + if( xPropSet.is()) + { + // determine attached axis + try + { + Any aAny( xPropSet->getPropertyValue( "Axis" )); + aAny >>= nAttachedAxis; + + aAny = xPropSet->getPropertyValue( "MeanValue" ); + aAny >>= bHasMeanValueLine; + } + catch( const beans::UnknownPropertyException & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" ); + } + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport ); + lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport ); + } + + if( mxExpPropMapper.is()) + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + } + + if( bExportContent ) + { + if( bHasTwoYAxes ) + { + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + } + + // write style name + AddAutoStyleAttribute( aPropertyStates ); + + if( xValuesSeq.is()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, + lcl_ConvertRange( + xValuesSeq->getSourceRangeRepresentation(), + xNewDoc )); + else + // #i75297# allow empty series, export empty range to have all ranges on import + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, OUString()); + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) // do not export to ODF 1.3 or older + { + if (xPropSet.is()) + { + Any aAny = xPropSet->getPropertyValue("ShowLegendEntry"); + if (!aAny.get()) + { + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true)); + } + } + } + + if (xLabelSeq.is()) + { + // Check if the label is direct string value rather than a reference. + bool bHasString = false; + uno::Reference xLSProp(xLabelSeq, uno::UNO_QUERY); + if (xLSProp.is()) + { + try + { + xLSProp->getPropertyValue("HasStringLabel") >>= bHasString; + } + catch (const beans::UnknownPropertyException&) {} + } + + OUString aRange = xLabelSeq->getSourceRangeRepresentation(); + + if (bHasString) + { + mrExport.AddAttribute( + XML_NAMESPACE_LO_EXT, XML_LABEL_STRING, aRange); + } + else + { + mrExport.AddAttribute( + XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, + lcl_ConvertRange( + xLabelSeq->getSourceRangeRepresentation(), xNewDoc)); + } + } + + if( xLabelSeq.is() || xValuesSeq.is() ) + aSeriesLabelValuesPair = tLabelValuesDataPair( xLabelSeq, xValuesSeq ); + + // chart-type for mixed types + enum XMLTokenEnum eCTToken( + SchXMLTools::getTokenByChartType( aChartType, false /* bUseOldNames */ )); + //@todo: get token for current charttype + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_CLASS, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( eCTToken ))); + + // open series element until end of for loop + pSeries.reset(new SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true )); + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + // remove property states for autostyles + aPropertyStates.clear(); + } + } + + // export domain elements if we have a series parent element + if( pSeries ) + { + // domain elements + if( bExportContent ) + { + bool bIsScatterChart = aChartType == "com.sun.star.chart2.ScatterChartType"; + bool bIsBubbleChart = aChartType == "com.sun.star.chart2.BubbleChartType"; + Reference< chart2::data::XDataSequence > xYValuesForBubbleChart; + if( bIsBubbleChart ) + { + Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-y" ) ); + if( xSequence.is() ) + { + xYValuesForBubbleChart = xSequence->getValues(); + if( !lcl_exportDomainForThisSequence( xYValuesForBubbleChart, aFirstYDomainRange, mrExport ) ) + xYValuesForBubbleChart = nullptr; + } + } + if( bIsScatterChart || bIsBubbleChart ) + { + Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, "values-x" ) ); + if( xSequence.is() ) + { + Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() ); + if( lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport ) ) + m_aDataSequencesToExport.emplace_back( + uno::Reference< chart2::data::XDataSequence >(), xValues ); + } + else if( nSeriesIdx==0 ) + { + //might be that the categories are used as x-values (e.g. for date axis) -> export them accordingly + Reference< chart2::data::XLabeledDataSequence > xCategories( lcl_getCategories( xNewDiagram ) ); + if( xCategories.is() ) + { + Reference< chart2::data::XDataSequence > xValues( xCategories->getValues() ); + if( !lcl_hasNoValuesButText( xValues ) ) + lcl_exportDomainForThisSequence( xValues, aFirstXDomainRange, mrExport ); + } + } + } + if( xYValuesForBubbleChart.is() ) + m_aDataSequencesToExport.emplace_back( + uno::Reference< chart2::data::XDataSequence >(), xYValuesForBubbleChart ); + } + } + + // add sequences for main sequence after domain sequences, + // so that the export of the local table has the correct order + if( bExportContent && + (aSeriesLabelValuesPair.first.is() || aSeriesLabelValuesPair.second.is())) + m_aDataSequencesToExport.push_back( aSeriesLabelValuesPair ); + + // statistical objects: + // regression curves and mean value lines + if( bHasMeanValueLine && + xPropSet.is() && + mxExpPropMapper.is() ) + { + Reference< beans::XPropertySet > xStatProp; + try + { + Any aPropAny( xPropSet->getPropertyValue( "DataMeanValueProperties" )); + aPropAny >>= xStatProp; + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of series - optional DataMeanValueProperties not available" ); + } + + if( xStatProp.is() ) + { + aPropertyStates = mxExpPropMapper->Filter(mrExport, xStatProp); + + if( !aPropertyStates.empty() ) + { + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_MEAN_VALUE, true, true ); + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + } + } + } + + if( xPropSet.is() && + mxExpPropMapper.is() ) + { + exportRegressionCurve( aSeriesSeq[nSeriesIdx], rPageSize, bExportContent ); + } + + exportErrorBar( xPropSet,false, bExportContent ); // X ErrorBar + exportErrorBar( xPropSet,true, bExportContent ); // Y ErrorBar + + exportDataPoints( + uno::Reference< beans::XPropertySet >( aSeriesSeq[nSeriesIdx], uno::UNO_QUERY ), + nSeriesLength, xNewDiagram, bExportContent ); + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + + // create child element if needed. + if (xPropSet.is() && mxExpPropMapper.is()) + { + // Generate style for child element + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + lcl_createDataLabelProperties(aDataLabelPropertyStates, xPropSet, + mxExpPropMapper); + } + } + if (bExportContent) + { + if (!aDataLabelPropertyStates.empty()) + { + // write style name + AddAutoStyleAttribute(aDataLabelPropertyStates); + // Further content does currently not exist for a + // element as child of a . + SvXMLElementExport(mrExport, XML_NAMESPACE_CHART, XML_DATA_LABEL, true, + true); + } + } + else + { + // add the style for the to be too + if (!aDataLabelPropertyStates.empty()) + CollectAutoStyle(std::move(aDataLabelPropertyStates)); + } + aDataLabelPropertyStates.clear(); + + if (bExportContent && nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) // do not export to ODF 1.3 or older + { + Sequence< OUString > aSupportedMappings = rChartType->getSupportedPropertyRoles(); + exportPropertyMapping( xSource, aSupportedMappings ); + } + + // close series element + pSeries.reset(); + } + } + aPropertyStates.clear(); + aDataLabelPropertyStates.clear(); + } + } +} + +void SchXMLExportHelper_Impl::exportPropertyMapping( + const Reference< chart2::data::XDataSource > & xSource, const Sequence< OUString >& rSupportedMappings ) +{ + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt( + xSource->getDataSequences()); + + for(const auto& rSupportedMapping : rSupportedMappings) + { + Reference< chart2::data::XLabeledDataSequence > xSequence( lcl_getDataSequenceByRole( aSeqCnt, rSupportedMapping ) ); + if(xSequence.is()) + { + Reference< chart2::data::XDataSequence > xValues( xSequence->getValues() ); + if( xValues.is()) + { + mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_PROPERTY, rSupportedMapping); + mrExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_CELL_RANGE_ADDRESS, + lcl_ConvertRange( + xValues->getSourceRangeRepresentation(), + xNewDoc )); + SvXMLElementExport( mrExport, XML_NAMESPACE_LO_EXT, XML_PROPERTY_MAPPING, true, true ); + + // register range for data table export + m_aDataSequencesToExport.emplace_back( + uno::Reference< chart2::data::XDataSequence >(), xValues ); + } + } + } +} + +void SchXMLExportHelper_Impl::exportRegressionCurve( + const Reference< chart2::XDataSeries >& xSeries, + const awt::Size& rPageSize, + bool bExportContent ) +{ + OSL_ASSERT( mxExpPropMapper.is()); + + Reference< chart2::XRegressionCurveContainer > xRegressionCurveContainer( xSeries, uno::UNO_QUERY ); + if( !xRegressionCurveContainer.is() ) + return; + + const Sequence< Reference< chart2::XRegressionCurve > > aRegCurveSeq = xRegressionCurveContainer->getRegressionCurves(); + + for( const auto& xRegCurve : aRegCurveSeq ) + { + std::vector< XMLPropertyState > aEquationPropertyStates; + if (!xRegCurve.is()) + continue; + + Reference< beans::XPropertySet > xProperties( xRegCurve , uno::UNO_QUERY ); + if( !xProperties.is() ) + continue; + + Reference< lang::XServiceName > xServiceName( xProperties, uno::UNO_QUERY ); + if( !xServiceName.is() ) + continue; + + bool bShowEquation = false; + bool bShowRSquared = false; + bool bExportEquation = false; + + OUString aService = xServiceName->getServiceName(); + + std::vector aPropertyStates = mxExpPropMapper->Filter(mrExport, xProperties); + + // Add service name (which is regression type) + sal_Int32 nIndex = GetPropertySetMapper()->FindEntryIndex(XML_SCH_CONTEXT_SPECIAL_REGRESSION_TYPE); + XMLPropertyState property(nIndex, uno::Any(aService)); + aPropertyStates.push_back(property); + + Reference< beans::XPropertySet > xEquationProperties; + xEquationProperties.set( xRegCurve->getEquationProperties() ); + if( xEquationProperties.is()) + { + xEquationProperties->getPropertyValue( "ShowEquation") >>= bShowEquation; + xEquationProperties->getPropertyValue( "ShowCorrelationCoefficient") >>= bShowRSquared; + + bExportEquation = ( bShowEquation || bShowRSquared ); + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion( + mrExport.getSaneDefaultVersion()); + if (nCurrentVersion < SvtSaveOptions::ODFSVER_012) + { + bExportEquation=false; + } + if( bExportEquation ) + { + // number format + sal_Int32 nNumberFormat = 0; + if( (xEquationProperties->getPropertyValue("NumberFormat") >>= nNumberFormat ) && + nNumberFormat != -1 ) + { + mrExport.addDataStyle( nNumberFormat ); + } + aEquationPropertyStates = mxExpPropMapper->Filter(mrExport, xEquationProperties); + } + } + + if( !aPropertyStates.empty() || bExportEquation ) + { + // write element + if( bExportContent ) + { + // add style name attribute + if( !aPropertyStates.empty()) + { + AddAutoStyleAttribute( aPropertyStates ); + } + + SvXMLElementExport aRegressionExport( mrExport, XML_NAMESPACE_CHART, XML_REGRESSION_CURVE, true, true ); + if( bExportEquation ) + { + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_EQUATION, (bShowEquation ? XML_TRUE : XML_FALSE) ); + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DISPLAY_R_SQUARE, (bShowRSquared ? XML_TRUE : XML_FALSE) ); + + // export position + chart2::RelativePosition aRelativePosition; + if( xEquationProperties->getPropertyValue( "RelativePosition" ) >>= aRelativePosition ) + { + double fX = aRelativePosition.Primary * rPageSize.Width; + double fY = aRelativePosition.Secondary * rPageSize.Height; + awt::Point aPos; + aPos.X = static_cast< sal_Int32 >( ::rtl::math::round( fX )); + aPos.Y = static_cast< sal_Int32 >( ::rtl::math::round( fY )); + addPosition( aPos ); + } + + if( !aEquationPropertyStates.empty()) + { + AddAutoStyleAttribute( aEquationPropertyStates ); + } + + SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_EQUATION, true, true ); + } + } + else // autostyles + { + if( !aPropertyStates.empty()) + { + CollectAutoStyle( std::move(aPropertyStates) ); + } + if( bExportEquation && !aEquationPropertyStates.empty()) + { + CollectAutoStyle( std::move(aEquationPropertyStates) ); + } + } + } + } +} + +void SchXMLExportHelper_Impl::exportErrorBar( const Reference &xSeriesProp, + bool bYError, bool bExportContent ) +{ + assert(mxExpPropMapper.is()); + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion( + mrExport.getSaneDefaultVersion()); + + /// Don't export X ErrorBars for older ODF versions. + if (!bYError && nCurrentVersion < SvtSaveOptions::ODFSVER_012) + return; + + if (!xSeriesProp.is()) + return; + + bool bNegative = false, bPositive = false; + sal_Int32 nErrorBarStyle = chart::ErrorBarStyle::NONE; + Reference< beans::XPropertySet > xErrorBarProp; + + try + { + Any aAny = xSeriesProp->getPropertyValue( bYError ? OUString("ErrorBarY") : OUString("ErrorBarX") ); + aAny >>= xErrorBarProp; + + if ( xErrorBarProp.is() ) + { + aAny = xErrorBarProp->getPropertyValue("ShowNegativeError" ); + aAny >>= bNegative; + + aAny = xErrorBarProp->getPropertyValue("ShowPositiveError" ); + aAny >>= bPositive; + + aAny = xErrorBarProp->getPropertyValue("ErrorBarStyle" ); + aAny >>= nErrorBarStyle; + } + } + catch( const beans::UnknownPropertyException & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Required property not found in DataRowProperties" ); + } + + if( !(nErrorBarStyle != chart::ErrorBarStyle::NONE && (bNegative || bPositive))) + return; + + if( bExportContent && nErrorBarStyle == chart::ErrorBarStyle::FROM_DATA ) + { + // register data ranges for error bars for export in local table + ::std::vector< Reference< chart2::data::XDataSequence > > aErrorBarSequences( + lcl_getErrorBarSequences( xErrorBarProp )); + for( const auto& rErrorBarSequence : aErrorBarSequences ) + { + m_aDataSequencesToExport.emplace_back( + uno::Reference< chart2::data::XDataSequence >(), rErrorBarSequence ); + } + } + + std::vector aPropertyStates = mxExpPropMapper->Filter(mrExport, xErrorBarProp); + + if( aPropertyStates.empty() ) + return; + + // write element + if( bExportContent ) + { + // add style name attribute + AddAutoStyleAttribute( aPropertyStates ); + + if (nCurrentVersion >= SvtSaveOptions::ODFSVER_012) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_DIMENSION, bYError ? XML_Y : XML_X );//#i114149# + SvXMLElementExport( mrExport, XML_NAMESPACE_CHART, XML_ERROR_INDICATOR, true, true ); + } + else // autostyles + { + CollectAutoStyle( std::move(aPropertyStates) ); + } +} + +void SchXMLExportHelper_Impl::exportCandleStickSeries( + const Sequence< Reference< chart2::XDataSeries > > & aSeriesSeq, + const Reference< chart2::XDiagram > & xDiagram, + bool bJapaneseCandleSticks, + bool bExportContent ) +{ + + for( const auto& xSeries : aSeriesSeq ) + { + sal_Int32 nAttachedAxis = lcl_isSeriesAttachedToFirstAxis( xSeries ) + ? chart::ChartAxisAssign::PRIMARY_Y + : chart::ChartAxisAssign::SECONDARY_Y; + + Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY ); + if( xSource.is()) + { + // export series in correct order (as we don't store roles) + // with japanese candlesticks: open, low, high, close + // otherwise: low, high, close + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeqCnt( + xSource->getDataSequences()); + + sal_Int32 nSeriesLength = + lcl_getSequenceLengthByRole( aSeqCnt, "values-last"); + + if( bExportContent ) + { + Reference< chart2::XChartDocument > xNewDoc( mrExport.GetModel(), uno::UNO_QUERY ); + //@todo: export data points + + //TODO: moggi: same code three times + // open + if( bJapaneseCandleSticks ) + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, "values-first", xNewDoc, m_aDataSequencesToExport )); + if( !aRanges.second.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( !aRanges.first.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aOpenSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ); + // export empty data points + exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent ); + } + + // low + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, "values-min", xNewDoc, m_aDataSequencesToExport )); + if( !aRanges.second.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( !aRanges.first.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aLowSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ); + // export empty data points + exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent ); + } + + // high + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, "values-max", xNewDoc, m_aDataSequencesToExport )); + if( !aRanges.second.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( !aRanges.first.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aHighSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ); + // export empty data points + exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent ); + } + + // close + { + tLabelAndValueRange aRanges( lcl_getLabelAndValueRangeByRole( + aSeqCnt, "values-last", xNewDoc, m_aDataSequencesToExport )); + if( !aRanges.second.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_VALUES_CELL_RANGE_ADDRESS, aRanges.second ); + if( !aRanges.first.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_LABEL_CELL_ADDRESS, aRanges.first ); + if( nAttachedAxis == chart::ChartAxisAssign::SECONDARY_Y ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_SECONDARY_Y ); + else + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_ATTACHED_AXIS, XML_PRIMARY_Y ); + SvXMLElementExport aCloseSeries( mrExport, XML_NAMESPACE_CHART, XML_SERIES, true, true ); + // export empty data points + exportDataPoints( nullptr, nSeriesLength, xDiagram, bExportContent ); + } + } + else // autostyles + { + // for close series + } + // remove property states for autostyles + } + } +} + +void SchXMLExportHelper_Impl::exportDataPoints( + const uno::Reference< beans::XPropertySet > & xSeriesProperties, + sal_Int32 nSeriesLength, + const uno::Reference< chart2::XDiagram > & xDiagram, + bool bExportContent ) +{ + // data-points + + // write data-points only if they contain autostyles + // objects with equal autostyles are grouped using the attribute + // repeat="number" + + // Note: if only the nth data-point has autostyles there is an element + // without style and repeat="n-1" attribute written in advance. + + // the sequence aDataPointSeq contains indices of data-points that + // do have own attributes. This increases the performance substantially. + + // more performant version for #93600# + if (!mxExpPropMapper.is()) + return; + + uno::Reference< chart2::XDataSeries > xSeries( xSeriesProperties, uno::UNO_QUERY ); + + std::vector< XMLPropertyState > aPropertyStates; + std::vector aDataLabelPropertyStates; + + bool bVaryColorsByPoint = false; + Sequence< sal_Int32 > aDataPointSeq; + Sequence deletedLegendEntriesSeq; + if( xSeriesProperties.is()) + { + xSeriesProperties->getPropertyValue("AttributedDataPoints") >>= aDataPointSeq; + xSeriesProperties->getPropertyValue("VaryColorsByPoint") >>= bVaryColorsByPoint; + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) // do not export to ODF 1.3 or older + xSeriesProperties->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq; + } + + sal_Int32 nSize = aDataPointSeq.getLength(); + SAL_WARN_IF( nSize > nSeriesLength, "xmloff.chart", "Too many point attributes" ); + + const sal_Int32 * pPoints = aDataPointSeq.getConstArray(); + sal_Int32 nElement; + Reference< chart2::XColorScheme > xColorScheme; + if( xDiagram.is()) + xColorScheme.set( xDiagram->getDefaultColorScheme()); + + ::std::vector< SchXMLDataPointStruct > aDataPointVector; + + sal_Int32 nLastIndex = -1; + + // collect elements + if( bVaryColorsByPoint && xColorScheme.is() ) + { + o3tl::sorted_vector< sal_Int32 > aAttrPointSet; + aAttrPointSet.reserve(aDataPointSeq.getLength()); + for (auto p = pPoints; p < pPoints + aDataPointSeq.getLength(); ++p) + aAttrPointSet.insert( *p ); + const auto aEndIt = aAttrPointSet.end(); + for( nElement = 0; nElement < nSeriesLength; ++nElement ) + { + aPropertyStates.clear(); + aDataLabelPropertyStates.clear(); + uno::Reference< beans::XPropertySet > xPropSet; + bool bExportNumFmt = false; + if( aAttrPointSet.find( nElement ) != aEndIt ) + { + try + { + xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet( + xSeries, nElement, mrExport.GetModel() ); + bExportNumFmt = true; + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" ); + } + } + else + { + // property set only containing the color + xPropSet.set( new ::xmloff::chart::ColorPropertySet( + ::Color(ColorTransparency, xColorScheme->getColorByIndex( nElement )))); + } + SAL_WARN_IF( !xPropSet.is(), "xmloff.chart", "Pie Segments should have properties" ); + if( xPropSet.is()) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012 && bExportNumFmt) + { + lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport ); + lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport ); + } + + // Generate style for child element + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + lcl_createDataLabelProperties(aDataLabelPropertyStates, xPropSet, + mxExpPropMapper); + } + + if (nCurrentODFVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + sal_Int32 nPlacement = 0; + xPropSet->getPropertyValue("LabelPlacement") >>= nPlacement; + if (nPlacement == chart::DataLabelPlacement::CUSTOM) + { + xPropSet->setPropertyValue("LabelPlacement", + uno::Any(chart::DataLabelPlacement::OUTSIDE)); + } + } + + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + if (!aPropertyStates.empty() || !aDataLabelPropertyStates.empty()) + { + if (bExportContent) + { + // write data-point with style + SchXMLDataPointStruct aPoint; + if (!aPropertyStates.empty()) + { + SAL_WARN_IF(maAutoStyleNameQueue.empty(), "xmloff.chart", + "Autostyle queue empty!"); + aPoint.maStyleName = maAutoStyleNameQueue.front(); + maAutoStyleNameQueue.pop(); + } + if (!aDataLabelPropertyStates.empty()) + { + SAL_WARN_IF(maAutoStyleNameQueue.empty(), "xmloff.chart", + "Autostyle queue empty!"); + aPoint.msDataLabelStyleName = maAutoStyleNameQueue.front(); + maAutoStyleNameQueue.pop(); + } + if(bExportNumFmt) + aPoint.mCustomLabel = lcl_getCustomLabelField(mrExport, nElement, xSeries); + aPoint.mCustomLabelPos = lcl_getCustomLabelPosition(mrExport, nElement, xSeries); + + aDataPointVector.push_back( aPoint ); + } + else + { + if (!aPropertyStates.empty()) + CollectAutoStyle(std::move(aPropertyStates)); + if (!aDataLabelPropertyStates.empty()) + CollectAutoStyle(std::move(aDataLabelPropertyStates)); + } + } + } + } + SAL_WARN_IF( bExportContent && (static_cast(aDataPointVector.size()) != nSeriesLength), "xmloff.chart", "not enough data points on content export" ); + } + else + { + for( sal_Int32 nCurrIndex : std::as_const(aDataPointSeq) ) + { + aPropertyStates.clear(); + aDataLabelPropertyStates.clear(); + //assuming sorted indices in pPoints + + if( nCurrIndex<0 || nCurrIndex>=nSeriesLength ) + break; + + // write leading empty data points + if( nCurrIndex - nLastIndex > 1 ) + { + SchXMLDataPointStruct aPoint; + aPoint.mnRepeat = nCurrIndex - nLastIndex - 1; + aDataPointVector.push_back( aPoint ); + } + + uno::Reference< beans::XPropertySet > xPropSet; + // get property states + try + { + xPropSet = SchXMLSeriesHelper::createOldAPIDataPointPropertySet( + xSeries, nCurrIndex, mrExport.GetModel() ); + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during Export of data point" ); + } + if( xPropSet.is()) + { + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + mrExport.getSaneDefaultVersion()); + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + lcl_exportNumberFormat( "NumberFormat", xPropSet, mrExport ); + lcl_exportNumberFormat( "PercentageNumberFormat", xPropSet, mrExport ); + } + + // Generate style for child element + if (nCurrentODFVersion >= SvtSaveOptions::ODFSVER_012) + { + lcl_createDataLabelProperties(aDataLabelPropertyStates, xPropSet, + mxExpPropMapper); + } + + aPropertyStates = mxExpPropMapper->Filter(mrExport, xPropSet); + + if (!aPropertyStates.empty() || !aDataLabelPropertyStates.empty()) + { + if( bExportContent ) + { + // write data-point with style + SchXMLDataPointStruct aPoint; + if (!aPropertyStates.empty()) + { + SAL_WARN_IF(maAutoStyleNameQueue.empty(), "xmloff.chart", + "Autostyle queue empty!"); + aPoint.maStyleName = maAutoStyleNameQueue.front(); + maAutoStyleNameQueue.pop(); + } + aPoint.mCustomLabel = lcl_getCustomLabelField(mrExport, nCurrIndex, xSeries); + aPoint.mCustomLabelPos = lcl_getCustomLabelPosition(mrExport, nCurrIndex, xSeries); + if (!aDataLabelPropertyStates.empty()) + { + SAL_WARN_IF(maAutoStyleNameQueue.empty(), "xmloff.chart", + "Autostyle queue empty!"); + aPoint.msDataLabelStyleName = maAutoStyleNameQueue.front(); + maAutoStyleNameQueue.pop(); + } + + aDataPointVector.push_back( aPoint ); + nLastIndex = nCurrIndex; + } + else + { + if (!aPropertyStates.empty()) + CollectAutoStyle(std::move(aPropertyStates)); + if (!aDataLabelPropertyStates.empty()) + CollectAutoStyle(std::move(aDataLabelPropertyStates)); + } + continue; + } + } + + // if we get here the property states are empty + SchXMLDataPointStruct aPoint; + aDataPointVector.push_back( aPoint ); + + nLastIndex = nCurrIndex; + } + // final empty elements + sal_Int32 nRepeat = nSeriesLength - nLastIndex - 1; + if( nRepeat > 0 ) + { + SchXMLDataPointStruct aPoint; + aPoint.mnRepeat = nRepeat; + aDataPointVector.push_back( aPoint ); + } + } + + if (!bExportContent) + return; + + // write elements (merge equal ones) + SchXMLDataPointStruct aPoint; + SchXMLDataPointStruct aLastPoint; + + // initialize so that it doesn't matter if + // the element is counted in the first iteration + aLastPoint.mnRepeat = 0; + sal_Int32 nIndex = 0; + for( const auto& rPoint : aDataPointVector ) + { + aPoint = rPoint; + + if (aPoint.maStyleName == aLastPoint.maStyleName + && aLastPoint.mCustomLabel.maFields.getLength() < 1 + && aLastPoint.mCustomLabelPos.Primary == 0.0 + && aLastPoint.mCustomLabelPos.Secondary == 0.0 + && aPoint.msDataLabelStyleName == aLastPoint.msDataLabelStyleName) + aPoint.mnRepeat += aLastPoint.mnRepeat; + else if( aLastPoint.mnRepeat > 0 ) + { + // write last element + if( !aLastPoint.maStyleName.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName ); + + if( aLastPoint.mnRepeat > 1 ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED, + OUString::number( aLastPoint.mnRepeat )); + + for (const auto& deletedLegendEntry : std::as_const(deletedLegendEntriesSeq)) + { + if (nIndex == deletedLegendEntry) + { + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true)); + break; + } + } + nIndex++; + exportCustomLabelPosition(aLastPoint.mCustomLabelPos); // adds attributes + SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true ); + exportCustomLabel(aLastPoint); + } + aLastPoint = aPoint; + } + // write last element if it hasn't been written in last iteration + if( aPoint.maStyleName != aLastPoint.maStyleName ) + return; + + if( !aLastPoint.maStyleName.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, aLastPoint.maStyleName ); + + if( aLastPoint.mnRepeat > 1 ) + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_REPEATED, + OUString::number( aLastPoint.mnRepeat )); + + for (const auto& deletedLegendEntry : std::as_const(deletedLegendEntriesSeq)) + { + if (nIndex == deletedLegendEntry) + { + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDE_LEGEND, OUString::boolean(true)); + break; + } + } + + exportCustomLabelPosition(aLastPoint.mCustomLabelPos); // adds attributes + SvXMLElementExport aPointElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_POINT, true, true ); + exportCustomLabel(aLastPoint); +} + +void SchXMLExportHelper_Impl::exportCustomLabel(const SchXMLDataPointStruct& rPoint) +{ + if (rPoint.mCustomLabel.maFields.getLength() < 1 && rPoint.msDataLabelStyleName.isEmpty()) + return; // nothing to export + + if (!rPoint.msDataLabelStyleName.isEmpty()) + mrExport.AddAttribute(XML_NAMESPACE_CHART, XML_STYLE_NAME, rPoint.msDataLabelStyleName); + + if (rPoint.mCustomLabel.mbDataLabelsRange) + { + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_LABELS_CELL_RANGE, rPoint.mCustomLabel.maRange); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATA_LABEL_GUID, rPoint.mCustomLabel.maGuid); + } + // TODO svg:x and svg:y for + SvXMLElementExport aLabelElem( mrExport, XML_NAMESPACE_CHART, XML_DATA_LABEL, true, true); + SvXMLElementExport aPara( mrExport, XML_NAMESPACE_TEXT, XML_P, true, false ); + + for (const Reference& label : rPoint.mCustomLabel.maFields) + { + // TODO add style + SvXMLElementExport aSpan( mrExport, XML_NAMESPACE_TEXT, XML_SPAN, true, false); + mrExport.GetDocHandler()->characters(label->getString()); + } +} + +void SchXMLExportHelper_Impl::exportCustomLabelPosition( const chart2::RelativePosition & xCustomLabelPosition) +{ + if( xCustomLabelPosition.Primary == 0.0 && xCustomLabelPosition.Secondary == 0.0 ) + return; // nothing to export + + OUStringBuffer aCustomLabelPosString; + ::sax::Converter::convertDouble(aCustomLabelPosString, xCustomLabelPosition.Primary); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_POS_X, aCustomLabelPosString.makeStringAndClear()); + + ::sax::Converter::convertDouble(aCustomLabelPosString, xCustomLabelPosition.Secondary); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CUSTOM_LABEL_POS_Y, aCustomLabelPosString.makeStringAndClear()); +} + +void SchXMLExportHelper_Impl::addPosition( const awt::Point & rPosition ) +{ + mrExport.GetMM100UnitConverter().convertMeasureToXML( + msStringBuffer, rPosition.X ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, msString ); + + mrExport.GetMM100UnitConverter().convertMeasureToXML( + msStringBuffer, rPosition.Y ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, msString ); +} + +void SchXMLExportHelper_Impl::addPosition( const Reference< drawing::XShape >& xShape ) +{ + if( xShape.is()) + addPosition( xShape->getPosition()); +} + +void SchXMLExportHelper_Impl::addSize( const awt::Size & rSize, bool bIsOOoNamespace) +{ + mrExport.GetMM100UnitConverter().convertMeasureToXML( + msStringBuffer, rSize.Width ); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( bIsOOoNamespace ? XML_NAMESPACE_CHART_EXT : XML_NAMESPACE_SVG , XML_WIDTH, msString ); + + mrExport.GetMM100UnitConverter().convertMeasureToXML( + msStringBuffer, rSize.Height); + msString = msStringBuffer.makeStringAndClear(); + mrExport.AddAttribute( bIsOOoNamespace ? XML_NAMESPACE_CHART_EXT : XML_NAMESPACE_SVG, XML_HEIGHT, msString ); +} + +void SchXMLExportHelper_Impl::addSize( const Reference< drawing::XShape >& xShape ) +{ + if( xShape.is()) + addSize( xShape->getSize() ); +} + +awt::Size SchXMLExportHelper_Impl::getPageSize( const Reference< chart2::XChartDocument > & xChartDoc ) +{ + awt::Size aSize( 8000, 7000 ); + uno::Reference< embed::XVisualObject > xVisualObject( xChartDoc, uno::UNO_QUERY ); + SAL_WARN_IF( !xVisualObject.is(), "xmloff.chart", "need XVisualObject for page size" ); + if( xVisualObject.is() ) + aSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); + + return aSize; +} + +void SchXMLExportHelper_Impl::CollectAutoStyle( std::vector< XMLPropertyState >&& aStates ) +{ + if( !aStates.empty() ) + maAutoStyleNameQueue.push( mrAutoStylePool.Add( XmlStyleFamily::SCH_CHART_ID, std::move(aStates) )); +} + +void SchXMLExportHelper_Impl::AddAutoStyleAttribute( const std::vector< XMLPropertyState >& aStates ) +{ + if( !aStates.empty() ) + { + SAL_WARN_IF( maAutoStyleNameQueue.empty(), "xmloff.chart", "Autostyle queue empty!" ); + + mrExport.AddAttribute( XML_NAMESPACE_CHART, XML_STYLE_NAME, maAutoStyleNameQueue.front() ); + maAutoStyleNameQueue.pop(); + } +} + +void SchXMLExportHelper_Impl::exportText( const OUString& rText ) +{ + SchXMLTools::exportText( mrExport, rText, false/*bConvertTabsLFs*/ ); +} + + +SchXMLExport::SchXMLExport(const Reference& xContext, + OUString const& implementationName, SvXMLExportFlags nExportFlags) + : SvXMLExport(xContext, implementationName, util::MeasureUnit::CM, ::xmloff::token::XML_CHART, + nExportFlags) + , maAutoStylePool(new SchXMLAutoStylePoolP(*this)) + , maExportHelper(new SchXMLExportHelper(*this, *maAutoStylePool)) +{ + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + GetNamespaceMap_().Add( GetXMLToken(XML_NP_CHART_EXT), GetXMLToken(XML_N_CHART_EXT), XML_NAMESPACE_CHART_EXT); +} + +SchXMLExport::~SchXMLExport() +{ +} + +ErrCode SchXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass ) +{ + maExportHelper->SetSourceShellID(GetSourceShellID()); + maExportHelper->SetDestinationShellID(GetDestinationShellID()); + + Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + maExportHelper->m_pImpl->InitRangeSegmentationProperties( xChartDoc ); + return SvXMLExport::exportDoc( eClass ); +} + +void SchXMLExport::ExportMasterStyles_() +{ + // not available in chart + SAL_INFO("xmloff.chart", "Master Style Export requested. Not available for Chart" ); +} + +void SchXMLExport::collectAutoStyles() +{ + SvXMLExport::collectAutoStyles(); + + if (mbAutoStylesCollected) + return; + + // there are no styles that require their own autostyles + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is()) + { + maExportHelper->m_pImpl->collectAutoStyles( xChartDoc ); + } + else + { + SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" ); + } + } + mbAutoStylesCollected = true; +} + +void SchXMLExport::ExportAutoStyles_() +{ + collectAutoStyles(); + + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is()) + { + maExportHelper->m_pImpl->exportAutoStyles(); + } + else + { + SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel (must be XChartDocument)" ); + } + } +} + +void SchXMLExport::ExportContent_() +{ + Reference< chart::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is()) + { + // determine if data comes from the outside + bool bIncludeTable = true; + + Reference< chart2::XChartDocument > xNewDoc( xChartDoc, uno::UNO_QUERY ); + if( xNewDoc.is()) + { + // check if we have own data. If so we must not export the complete + // range string, as this is our only indicator for having own or + // external data. @todo: fix this in the file format! + Reference< lang::XServiceInfo > xDPServiceInfo( xNewDoc->getDataProvider(), uno::UNO_QUERY ); + if( ! (xDPServiceInfo.is() && xDPServiceInfo->getImplementationName() == "com.sun.star.comp.chart.InternalDataProvider" )) + { + bIncludeTable = false; + } + } + else + { + Reference< lang::XServiceInfo > xServ( xChartDoc, uno::UNO_QUERY ); + if( xServ.is()) + { + if( xServ->supportsService( "com.sun.star.chart.ChartTableAddressSupplier" )) + { + Reference< beans::XPropertySet > xProp( xServ, uno::UNO_QUERY ); + if( xProp.is()) + { + Any aAny; + try + { + OUString sChartAddress; + aAny = xProp->getPropertyValue( "ChartRangeAddress" ); + aAny >>= sChartAddress; + maExportHelper->m_pImpl->SetChartRangeAddress( sChartAddress ); + + // do not include own table if there are external addresses + bIncludeTable = sChartAddress.isEmpty(); + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property ChartRangeAddress not supported by ChartDocument" ); + } + } + } + } + } + maExportHelper->m_pImpl->exportChart( xChartDoc, bIncludeTable ); + } + else + { + SAL_WARN("xmloff.chart", "Couldn't export chart due to wrong XModel" ); + } +} + +rtl::Reference< XMLPropertySetMapper > const & SchXMLExport::GetPropertySetMapper() const +{ + return maExportHelper->m_pImpl->GetPropertySetMapper(); +} + +void SchXMLExportHelper_Impl::InitRangeSegmentationProperties( const Reference< chart2::XChartDocument > & xChartDoc ) +{ + if( !xChartDoc.is()) + return; + + try + { + Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); + SAL_WARN_IF( !xDataProvider.is(), "xmloff.chart", "No DataProvider" ); + if( xDataProvider.is()) + { + Reference< chart2::data::XDataSource > xDataSource( lcl_pressUsedDataIntoRectangularFormat( xChartDoc, mbHasCategoryLabels )); + const Sequence< beans::PropertyValue > aArgs( xDataProvider->detectArguments( xDataSource )); + OUString sCellRange, sBrokenRange; + bool bBrokenRangeAvailable = false; + for( const auto& rArg : aArgs ) + { + if ( rArg.Name == "CellRangeRepresentation" ) + rArg.Value >>= sCellRange; + else if ( rArg.Name == "BrokenCellRangeForExport" ) + { + if( rArg.Value >>= sBrokenRange ) + bBrokenRangeAvailable = true; + } + else if ( rArg.Name == "DataRowSource" ) + { + chart::ChartDataRowSource eRowSource; + rArg.Value >>= eRowSource; + mbRowSourceColumns = ( eRowSource == chart::ChartDataRowSource_COLUMNS ); + } + else if ( rArg.Name == "SequenceMapping" ) + rArg.Value >>= maSequenceMapping; + } + + // #i79009# For Writer we have to export a broken version of the + // range, where every row number is not too large, so that older + // version can correctly read those files. + msChartAddress = (bBrokenRangeAvailable ? sBrokenRange : sCellRange); + if( !msChartAddress.isEmpty() ) + { + // convert format to XML-conform one + Reference< chart2::data::XRangeXMLConversion > xConversion( xDataProvider, uno::UNO_QUERY ); + if( xConversion.is()) + msChartAddress = xConversion->convertRangeToXML( msChartAddress ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } +} + +// first version: everything goes in one storage + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SchXMLExport(pCtx, "SchXMLExport.Compact", + SvXMLExportFlags::ALL + ^ (SvXMLExportFlags::SETTINGS | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::SCRIPTS))); +} + +// Oasis format +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SchXMLExport(pCtx, "SchXMLExport.Oasis.Compact", + (SvXMLExportFlags::ALL + ^ (SvXMLExportFlags::SETTINGS | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::SCRIPTS)) + | SvXMLExportFlags::OASIS)); +} + +// multiple storage version: one for content / styles / meta + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLStylesExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Styles", SvXMLExportFlags::STYLES)); +} + +// Oasis format +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisStylesExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Oasis.Styles", + SvXMLExportFlags::STYLES | SvXMLExportFlags::OASIS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLContentExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Content", + SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT + | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisContentExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Oasis.Content", + SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT + | SvXMLExportFlags::FONTDECLS + | SvXMLExportFlags::OASIS)); +} + +// Oasis format + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisMetaExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLExport(pCtx, "SchXMLExport.Oasis.Meta", + SvXMLExportFlags::META | SvXMLExportFlags::OASIS)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLImport.cxx b/xmloff/source/chart/SchXMLImport.cxx new file mode 100644 index 000000000..a39f82245 --- /dev/null +++ b/xmloff/source/chart/SchXMLImport.cxx @@ -0,0 +1,377 @@ +/* -*- 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 +#include "SchXMLChartContext.hxx" +#include "contexts.hxx" +#include "SchXMLTools.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +class lcl_MatchesChartType +{ +public: + explicit lcl_MatchesChartType( const OUString & aChartTypeName ) : + m_aChartTypeName( aChartTypeName ) + {} + + bool operator () ( const Reference< chart2::XChartType > & xChartType ) const + { + return (xChartType.is() && + xChartType->getChartType() == m_aChartTypeName ); + } + +private: + OUString m_aChartTypeName; +}; +} // anonymous namespace + + // TokenMaps for distinguishing different + // tokens in different contexts + +// element maps + +// attribute maps + +SchXMLImportHelper::SchXMLImportHelper() : + mpAutoStyles( nullptr ) +{ +} + +SvXMLImportContext* SchXMLImportHelper::CreateChartContext( + SvXMLImport& rImport, + const Reference< frame::XModel >& rChartModel ) +{ + SvXMLImportContext* pContext = nullptr; + + Reference< chart::XChartDocument > xDoc( rChartModel, uno::UNO_QUERY ); + if( xDoc.is()) + { + mxChartDoc = xDoc; + pContext = new SchXMLChartContext( *this, rImport ); + } + else + { + SAL_WARN("xmloff.chart", "No valid XChartDocument given as XModel" ); + } + + return pContext; +} + +void SchXMLImportHelper::FillAutoStyle(const OUString& rAutoStyleName, const uno::Reference& rProp) +{ + if (!rProp.is()) + return; + + const SvXMLStylesContext* pStylesCtxt = GetAutoStylesContext(); + if (pStylesCtxt) + { + SvXMLStyleContext* pStyle = const_cast(pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(), rAutoStyleName)); + + if (XMLPropStyleContext* pPropStyle = dynamic_cast(pStyle)) + pPropStyle->FillPropertySet(rProp); + } +} + +// get various token maps + + +//static +void SchXMLImportHelper::DeleteDataSeries( + const Reference< chart2::XDataSeries > & xSeries, + const Reference< chart2::XChartDocument > & xDoc ) +{ + if( !xDoc.is() ) + return; + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( + xDoc->getFirstDiagram(), uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); + + for( const auto& rChartType : aChartTypes ) + { + Reference< chart2::XDataSeriesContainer > xSeriesCnt( rChartType, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xSeriesCnt->getDataSeries()); + + if (std::find(aSeriesSeq.begin(), aSeriesSeq.end(), xSeries) != aSeriesSeq.end()) + { + xSeriesCnt->removeDataSeries(xSeries); + return; + } + } + } + } + catch( const uno::Exception &) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } +} + +// static +Reference< chart2::XDataSeries > SchXMLImportHelper::GetNewDataSeries( + const Reference< chart2::XChartDocument > & xDoc, + sal_Int32 nCoordinateSystemIndex, + const OUString & rChartTypeName, + bool bPushLastChartType /* = false */ ) +{ + Reference< chart2::XDataSeries > xResult; + if(!xDoc.is()) + return xResult; + + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( + xDoc->getFirstDiagram(), uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + Reference< uno::XComponentContext > xContext( + comphelper::getProcessComponentContext() ); + + if( nCoordinateSystemIndex < aCooSysSeq.getLength()) + { + Reference< chart2::XChartType > xCurrentType; + { + Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[ nCoordinateSystemIndex ], uno::UNO_QUERY_THROW ); + Sequence< Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes()); + // find matching chart type group + const Reference< chart2::XChartType > * pBegin = aChartTypes.getConstArray(); + const Reference< chart2::XChartType > * pEnd = pBegin + aChartTypes.getLength(); + const Reference< chart2::XChartType > * pIt = + ::std::find_if( pBegin, pEnd, lcl_MatchesChartType( rChartTypeName )); + if( pIt != pEnd ) + xCurrentType.set( *pIt ); + // if chart type is set at series and differs from current one, + // create a new chart type + if( !xCurrentType.is()) + { + xCurrentType.set( + xContext->getServiceManager()->createInstanceWithContext( rChartTypeName, xContext ), + uno::UNO_QUERY ); + if( xCurrentType.is()) + { + if( bPushLastChartType && aChartTypes.hasElements()) + { + sal_Int32 nIndex( aChartTypes.getLength() - 1 ); + aChartTypes.realloc( aChartTypes.getLength() + 1 ); + auto pChartTypes = aChartTypes.getArray(); + pChartTypes[ nIndex + 1 ] = aChartTypes[ nIndex ]; + pChartTypes[ nIndex ] = xCurrentType; + xCTCnt->setChartTypes( aChartTypes ); + } + else + xCTCnt->addChartType( xCurrentType ); + } + } + } + + if( xCurrentType.is()) + { + Reference< chart2::XDataSeriesContainer > xSeriesCnt( xCurrentType, uno::UNO_QUERY_THROW ); + + if( xContext.is() ) + { + xResult.set( + xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.chart2.DataSeries", + xContext ), uno::UNO_QUERY_THROW ); + } + if( xResult.is() ) + xSeriesCnt->addDataSeries( xResult ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + return xResult; +} + +SchXMLImport::SchXMLImport( + const Reference< uno::XComponentContext >& xContext, + OUString const & implementationName, SvXMLImportFlags nImportFlags ) : + SvXMLImport( xContext, implementationName, nImportFlags ), + maImportHelper(new SchXMLImportHelper) +{ + GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK ); + GetNamespaceMap().Add( GetXMLToken(XML_NP_CHART_EXT), GetXMLToken(XML_N_CHART_EXT), XML_NAMESPACE_CHART_EXT); +} + +SchXMLImport::~SchXMLImport() noexcept +{ + uno::Reference< chart2::XChartDocument > xChartDoc( GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is() && xChartDoc->hasControllersLocked() ) + xChartDoc->unlockControllers(); +} + +// create the main context (subcontexts are created +// by the one created here) +SvXMLImportContext *SchXMLImport::CreateFastContext( sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContext* pContext = nullptr; + + switch (nElement) + { + case XML_ELEMENT( OFFICE, XML_DOCUMENT ): + case XML_ELEMENT( OFFICE, XML_DOCUMENT_META ): + { + uno::Reference xDPS( + GetModel(), uno::UNO_QUERY); + // mst@: right now, this seems to be not supported, so it is untested + if (xDPS.is()) { + pContext = (nElement == XML_ELEMENT(OFFICE, XML_DOCUMENT_META)) + ? new SvXMLMetaDocumentContext(*this, xDPS->getDocumentProperties()) + // flat OpenDocument file format + : new SchXMLFlatDocContext_Impl(*maImportHelper, *this, nElement, + xDPS->getDocumentProperties()); + } + } + break; + // accept + case XML_ELEMENT(OFFICE, XML_DOCUMENT_STYLES): + case XML_ELEMENT(OFFICE, XML_DOCUMENT_CONTENT): + pContext = new SchXMLDocContext(*maImportHelper, *this, nElement); + break; + } + return pContext; +} + +SvXMLImportContext* SchXMLImport::CreateStylesContext() +{ + //#i103287# make sure that the version information is set before importing all the properties (especially stroke-opacity!) + SchXMLTools::setBuildIDAtImportInfo( GetModel(), getImportInfo() ); + + SvXMLStylesContext* pStylesCtxt = new SvXMLStylesContext( *this ); + + // set context at base class, so that all auto-style classes are imported + SetAutoStyles( pStylesCtxt ); + maImportHelper->SetAutoStylesContext( pStylesCtxt ); + + return pStylesCtxt; +} + +void SAL_CALL SchXMLImport::setTargetDocument(const uno::Reference& xDoc) +{ + uno::Reference xOldDoc(GetModel(), uno::UNO_QUERY); + if (xOldDoc.is() && xOldDoc->hasControllersLocked()) + xOldDoc->unlockControllers(); + + SvXMLImport::setTargetDocument(xDoc); + + uno::Reference xChartDoc(GetModel(), uno::UNO_QUERY); + + if (!xChartDoc.is()) + return; + try + { + // prevent rebuild of view during load (necessary especially if loaded not + // via load api, which is the case for example if binary files are loaded) + xChartDoc->lockControllers(); + + uno::Reference xChild(xChartDoc, uno::UNO_QUERY); + uno::Reference xDataReceiver(xChartDoc, uno::UNO_QUERY); + if (xChild.is() && xDataReceiver.is()) + { + Reference xFact(xChild->getParent(), uno::UNO_QUERY); + if (xFact.is()) + { + //if the parent has a number formatter we will use the numberformatter of the parent + Reference xNumberFormatsSupplier(xFact, uno::UNO_QUERY); + xDataReceiver->attachNumberFormatsSupplier(xNumberFormatsSupplier); + } + } + } + catch (const uno::Exception &) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "SchXMLChartContext::StartElement(): Exception caught"); + } +} + +// first version: everything comes from one storage + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisImporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLImport(pCtx, "SchXMLImport", SvXMLImportFlags::ALL)); +} + +// multiple storage version: one for content / styles / meta + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisMetaImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLImport(pCtx, "SchXMLImport.Meta", SvXMLImportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisStylesImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLImport(pCtx, "SchXMLImport.Styles", SvXMLImportFlags::STYLES)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Chart_XMLOasisContentImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SchXMLImport(pCtx, "SchXMLImport.Content", + SvXMLImportFlags::CONTENT | SvXMLImportFlags::AUTOSTYLES + | SvXMLImportFlags::FONTDECLS)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLLegendContext.cxx b/xmloff/source/chart/SchXMLLegendContext.cxx new file mode 100644 index 000000000..b9e652b18 --- /dev/null +++ b/xmloff/source/chart/SchXMLLegendContext.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/. + * + * 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 "SchXMLLegendContext.hxx" +#include "SchXMLEnumConverter.hxx" + +#include +#include +#include +#include + +#include + +#include +#include +#include + +using namespace ::xmloff::token; +using namespace com::sun::star; + +SchXMLLegendContext::SchXMLLegendContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ) +{ +} + +void SchXMLLegendContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument(); + if( !xDoc.is() ) + return; + + // turn on legend + uno::Reference< beans::XPropertySet > xDocProp( xDoc, uno::UNO_QUERY ); + if( xDocProp.is() ) + { + try + { + xDocProp->setPropertyValue("HasLegend", uno::Any( true ) ); + } + catch(const beans::UnknownPropertyException&) + { + SAL_INFO("xmloff.chart", "Property HasLegend not found" ); + } + } + + uno::Reference< drawing::XShape > xLegendShape = xDoc->getLegend(); + uno::Reference< beans::XPropertySet > xLegendProps( xLegendShape, uno::UNO_QUERY ); + if( !xLegendShape.is() || !xLegendProps.is() ) + { + SAL_INFO("xmloff.chart", "legend could not be created" ); + return; + } + + // parse attributes + awt::Point aLegendPos; + bool bOverlay = false; + bool bHasXPosition=false; + bool bHasYPosition=false; + awt::Size aLegendSize; + bool bHasWidth=false; + bool bHasHeight=false; + chart::ChartLegendExpansion nLegendExpansion = chart::ChartLegendExpansion_HIGH; + bool bHasExpansion=false; + + OUString sAutoStyleName; + uno::Any aAny; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(CHART, XML_LEGEND_POSITION): + try + { + if( SchXMLEnumConverter::getLegendPositionConverter().importXML( aIter.toString(), aAny, GetImport().GetMM100UnitConverter() ) ) + xLegendProps->setPropertyValue("Alignment", aAny ); + } + catch(const beans::UnknownPropertyException&) + { + SAL_INFO("xmloff.chart", "Property Alignment (legend) not found" ); + } + break; + case XML_ELEMENT(LO_EXT, XML_OVERLAY): + try + { + bOverlay = aIter.toBoolean(); + xLegendProps->setPropertyValue("Overlay", uno::Any(bOverlay)); + } + catch(const beans::UnknownPropertyException&) + { + SAL_INFO("xmloff.chart", "Property Overlay (legend) not found" ); + } + break; + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aLegendPos.X, aIter.toView() ); + bHasXPosition = true; + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aLegendPos.Y, aIter.toView() ); + bHasYPosition = true; + break; + case XML_ELEMENT(CHART, XML_STYLE_NAME): + sAutoStyleName = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_LEGEND_EXPANSION): + SchXMLEnumConverter::getLegendPositionConverter().importXML( aIter.toString(), aAny, GetImport().GetMM100UnitConverter() ); + bHasExpansion = (aAny>>=nLegendExpansion); + break; + case XML_ELEMENT(STYLE, XML_LEGEND_EXPANSION_ASPECT_RATIO): + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + case XML_ELEMENT(CHART_EXT, XML_WIDTH): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aLegendSize.Width, aIter.toView() ); + bHasWidth = true; + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + case XML_ELEMENT(CHART_EXT, XML_HEIGHT): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aLegendSize.Height, aIter.toView() ); + bHasHeight = true; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } + + if( bHasExpansion && nLegendExpansion!= chart::ChartLegendExpansion_CUSTOM ) + xLegendProps->setPropertyValue("Expansion", uno::Any(nLegendExpansion) ); + else if( bHasHeight && bHasWidth ) + xLegendShape->setSize( aLegendSize ); + + if( bHasXPosition && bHasYPosition ) + xLegendShape->setPosition( aLegendPos ); + + // the fill style has the default "none" in XML, but "solid" in the model. + xLegendProps->setPropertyValue("FillStyle", uno::Any( drawing::FillStyle_NONE )); + + // set auto-styles for Legend + mrImportHelper.FillAutoStyle(sAutoStyleName, xLegendProps); +} + +SchXMLLegendContext::~SchXMLLegendContext() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLLegendContext.hxx b/xmloff/source/chart/SchXMLLegendContext.hxx new file mode 100644 index 000000000..9477e45b7 --- /dev/null +++ b/xmloff/source/chart/SchXMLLegendContext.hxx @@ -0,0 +1,39 @@ +/* -*- 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 + +#include +#include + +class SchXMLLegendContext : public SvXMLImportContext +{ +public: + SchXMLLegendContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport ); + virtual ~SchXMLLegendContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +private: + SchXMLImportHelper& mrImportHelper; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLParagraphContext.cxx b/xmloff/source/chart/SchXMLParagraphContext.cxx new file mode 100644 index 000000000..84e22c5a5 --- /dev/null +++ b/xmloff/source/chart/SchXMLParagraphContext.cxx @@ -0,0 +1,107 @@ +/* -*- 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 "SchXMLParagraphContext.hxx" + +#include +#include +#include +#include +#include + +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +SchXMLParagraphContext::SchXMLParagraphContext( SvXMLImport& rImport, + OUString& rText, + OUString * pOutId /* = 0 */ ) : + SvXMLImportContext( rImport ), + mrText( rText ), + mpId( pOutId ) +{ +} + +SchXMLParagraphContext::~SchXMLParagraphContext() +{} + +void SchXMLParagraphContext::startFastElement( + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + // remember the id. It is used for storing the original cell range string in + // a local table (cached data) + if( !mpId ) + return; + + bool bHaveXmlId( false ); + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(XML, XML_ID): + (*mpId) = aIter.toString(); + bHaveXmlId = true; + break; + case XML_ELEMENT(TEXT, XML_ID): + { // text:id shall be ignored if xml:id exists + if (!bHaveXmlId) + { + (*mpId) = aIter.toString(); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +void SchXMLParagraphContext::endFastElement(sal_Int32 ) +{ + mrText = maBuffer.makeStringAndClear(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLParagraphContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( nElement == XML_ELEMENT(TEXT, XML_TAB_STOP) ) + { + maBuffer.append( u'\x0009'); // tabulator + } + else if( nElement == XML_ELEMENT(TEXT, XML_LINE_BREAK) ) + { + maBuffer.append( u'\x000A'); // linefeed + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +void SchXMLParagraphContext::characters( const OUString& rChars ) +{ + maBuffer.append( rChars ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLParagraphContext.hxx b/xmloff/source/chart/SchXMLParagraphContext.hxx new file mode 100644 index 000000000..65e90522e --- /dev/null +++ b/xmloff/source/chart/SchXMLParagraphContext.hxx @@ -0,0 +1,53 @@ +/* -*- 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 +#include +#include + +namespace com::sun::star::xml::sax { + class XAttributeList; +} + +class SchXMLParagraphContext : public SvXMLImportContext +{ +private: + OUString& mrText; + OUString* mpId; + OUStringBuffer maBuffer; + +public: + SchXMLParagraphContext( SvXMLImport& rImport, + OUString& rText, + OUString * pOutId = nullptr ); + virtual ~SchXMLParagraphContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLPlotAreaContext.cxx b/xmloff/source/chart/SchXMLPlotAreaContext.cxx new file mode 100644 index 000000000..7418b92fa --- /dev/null +++ b/xmloff/source/chart/SchXMLPlotAreaContext.cxx @@ -0,0 +1,1280 @@ +/* -*- 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 "SchXMLPlotAreaContext.hxx" +#include +#include "SchXMLAxisContext.hxx" +#include "SchXMLSeries2Context.hxx" +#include "SchXMLTools.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +using com::sun::star::uno::Reference; + +namespace +{ + +struct lcl_AxisHasCategories +{ + bool operator() ( const SchXMLAxis & rAxis ) + { + return rAxis.bHasCategories; + } +}; + +OUString lcl_ConvertRange( const OUString & rRange, const uno::Reference< chart2::XChartDocument > & xDoc ) +{ + OUString aResult = rRange; + if(!xDoc.is()) + return aResult; + uno::Reference< chart2::data::XRangeXMLConversion > xConversion( + xDoc->getDataProvider(), uno::UNO_QUERY ); + if( xConversion.is()) + aResult = xConversion->convertRangeFromXML( rRange ); + return aResult; +} + +} // anonymous namespace + +SchXML3DSceneAttributesHelper::SchXML3DSceneAttributesHelper( SvXMLImport& rImporter ) + : SdXML3DSceneAttributesHelper( rImporter ) +{ +} + +void SchXML3DSceneAttributesHelper::getCameraDefaultFromDiagram( const uno::Reference< chart::XDiagram >& xDiagram ) +{ + //different defaults for camera geometry necessary to workaround wrong behaviour in old chart + //in future make this version dependent if we have versioning (metastream) for ole objects + + try + { + uno::Reference< beans::XPropertySet > xProp( xDiagram, uno::UNO_QUERY ); + if( xProp.is() ) + { + drawing::CameraGeometry aCamGeo; + xProp->getPropertyValue("D3DCameraGeometry") >>= aCamGeo; + maVRP.setX( aCamGeo.vrp.PositionX ); + maVRP.setY( aCamGeo.vrp.PositionY ); + maVRP.setZ( aCamGeo.vrp.PositionZ ); + maVPN.setX( aCamGeo.vpn.DirectionX ); + maVPN.setY( aCamGeo.vpn.DirectionY ); + maVPN.setZ( aCamGeo.vpn.DirectionZ ); + maVUP.setX( aCamGeo.vup.DirectionX ); + maVUP.setY( aCamGeo.vup.DirectionY ); + maVUP.setZ( aCamGeo.vup.DirectionZ ); + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught for property NumberOfLines"); + } +} + +SchXML3DSceneAttributesHelper::~SchXML3DSceneAttributesHelper() +{ +} + +SchXMLPlotAreaContext::SchXMLPlotAreaContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString& rXLinkHRefAttributeToIndicateDataProvider, + OUString& rCategoriesAddress, + OUString& rChartAddress, + bool & rbHasRangeAtPlotArea, + bool & rAllRangeAddressesAvailable, + bool & rColHasLabels, + bool & rRowHasLabels, + chart::ChartDataRowSource & rDataRowSource, + SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles, + const OUString& aChartTypeServiceName, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + const awt::Size & rChartSize ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ), + mrCategoriesAddress( rCategoriesAddress ), + mrSeriesDefaultsAndStyles( rSeriesDefaultsAndStyles ), + mnNumOfLinesProp( 0 ), + mbStockHasVolume( false ), + mnSeries( 0 ), + m_aGlobalSeriesImportInfo( rAllRangeAddressesAvailable ), + maSceneImportHelper( rImport ), + m_aOuterPositioning( rImport ), + m_aInnerPositioning( rImport ), + mbPercentStacked(false), + m_bAxisPositionAttributeImported(false), + m_rXLinkHRefAttributeToIndicateDataProvider(rXLinkHRefAttributeToIndicateDataProvider), + mrChartAddress( rChartAddress ), + m_rbHasRangeAtPlotArea( rbHasRangeAtPlotArea ), + mrColHasLabels( rColHasLabels ), + mrRowHasLabels( rRowHasLabels ), + mrDataRowSource( rDataRowSource ), + maChartTypeServiceName( aChartTypeServiceName ), + mrLSequencesPerIndex( rLSequencesPerIndex ), + mbGlobalChartTypeUsedBySeries( false ), + maChartSize( rChartSize ) +{ + m_rbHasRangeAtPlotArea = false; + + // get Diagram + uno::Reference< chart::XChartDocument > xDoc = rImpHelper.GetChartDocument(); + if( xDoc.is()) + { + mxDiagram = xDoc->getDiagram(); + mxNewDoc.set( xDoc, uno::UNO_QUERY ); + + maSceneImportHelper.getCameraDefaultFromDiagram( mxDiagram ); + } + SAL_WARN_IF( !mxDiagram.is(),"xmloff.chart", "Couldn't get XDiagram" ); + + // turn off all axes initially + uno::Any aFalseBool; + aFalseBool <<= false; + + uno::Reference< lang::XServiceInfo > xInfo( mxDiagram, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xProp( mxDiagram, uno::UNO_QUERY ); + if( !xInfo.is() || !xProp.is() ) + return; + + try + { + xProp->setPropertyValue("HasXAxis", aFalseBool ); + xProp->setPropertyValue("HasXAxisGrid", aFalseBool ); + xProp->setPropertyValue("HasXAxisDescription", aFalseBool ); + xProp->setPropertyValue("HasSecondaryXAxis", aFalseBool ); + xProp->setPropertyValue("HasSecondaryXAxisDescription", aFalseBool ); + + xProp->setPropertyValue("HasYAxis", aFalseBool ); + xProp->setPropertyValue("HasYAxisGrid", aFalseBool ); + xProp->setPropertyValue("HasYAxisDescription", aFalseBool ); + xProp->setPropertyValue("HasSecondaryYAxis", aFalseBool ); + xProp->setPropertyValue("HasSecondaryYAxisDescription", aFalseBool ); + + xProp->setPropertyValue("HasZAxis", aFalseBool ); + xProp->setPropertyValue("HasZAxisDescription", aFalseBool ); + + xProp->setPropertyValue("DataRowSource", uno::Any(chart::ChartDataRowSource_COLUMNS) ); + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Property required by service not supported" ); + } +} + +SchXMLPlotAreaContext::~SchXMLPlotAreaContext() +{} + +void SchXMLPlotAreaContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // parse attributes + uno::Reference< chart2::XChartDocument > xNewDoc( GetImport().GetModel(), uno::UNO_QUERY ); + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + m_aOuterPositioning.readPositioningAttribute( aIter.getToken(), aIter.toView() ); + break; + case XML_ELEMENT(CHART, XML_STYLE_NAME): + msAutoStyleName = aIter.toString(); + break; + case XML_ELEMENT(TABLE, XML_CELL_RANGE_ADDRESS): + mrChartAddress = lcl_ConvertRange( aIter.toString(), xNewDoc ); + // indicator for getting data from the outside + m_rbHasRangeAtPlotArea = true; + break; + case XML_ELEMENT(CHART, XML_DATA_SOURCE_HAS_LABELS): + { + if( IsXMLToken(aIter, XML_BOTH) ) + mrColHasLabels = mrRowHasLabels = true; + else if( IsXMLToken(aIter, XML_ROW) ) + mrRowHasLabels = true; + else if( IsXMLToken(aIter, XML_COLUMN) ) + mrColHasLabels = true; + } + break; + case XML_ELEMENT(DR3D, XML_TRANSFORM): + case XML_ELEMENT(DR3D, XML_VRP): + case XML_ELEMENT(DR3D, XML_VPN): + case XML_ELEMENT(DR3D, XML_VUP): + case XML_ELEMENT(DR3D, XML_PROJECTION): + case XML_ELEMENT(DR3D, XML_DISTANCE): + case XML_ELEMENT(DR3D, XML_FOCAL_LENGTH): + case XML_ELEMENT(DR3D, XML_SHADOW_SLANT): + case XML_ELEMENT(DR3D, XML_SHADE_MODE): + case XML_ELEMENT(DR3D, XML_AMBIENT_COLOR): + case XML_ELEMENT(DR3D, XML_LIGHTING_MODE): + maSceneImportHelper.processSceneAttribute( aIter ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( ! mxNewDoc.is()) + { + uno::Reference< beans::XPropertySet > xDocProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ); + if( xDocProp.is()) + { + try + { + xDocProp->setPropertyValue("DataSourceLabelsInFirstColumn", uno::Any(mrColHasLabels) ); + xDocProp->setPropertyValue("DataSourceLabelsInFirstRow", uno::Any(mrRowHasLabels) ); + } + catch( const beans::UnknownPropertyException & ) + { + SAL_WARN("xmloff.chart", "Properties missing" ); + } + } + } + + // set properties + uno::Reference< beans::XPropertySet > xProp( mxDiagram, uno::UNO_QUERY ); + if( !msAutoStyleName.isEmpty()) + { + if( xProp.is()) + { + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + if( pStylesCtxt ) + { + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), msAutoStyleName ); + + XMLPropStyleContext* pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( pStyle ) ); + if( pPropStyleContext ) + { + pPropStyleContext->FillPropertySet( xProp ); + + // get the data row source that was set without having data + xProp->getPropertyValue("DataRowSource") + >>= mrDataRowSource; + + //lines on/off + //this old property is not supported fully anymore with the new chart, so we need to get the information a little bit different from similar properties + mrSeriesDefaultsAndStyles.maLinesOnProperty = SchXMLTools::getPropertyFromContext( + u"Lines", pPropStyleContext, pStylesCtxt ); + + //handle automatic position and size + m_aOuterPositioning.readAutomaticPositioningProperties( pPropStyleContext, pStylesCtxt ); + + //correct default starting angle for old 3D pies + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan3_0( GetImport().GetModel() ) ) + { + bool bIs3d = false; + if( xProp.is() && ( xProp->getPropertyValue("Dim3D") >>= bIs3d ) && + bIs3d ) + { + if( maChartTypeServiceName == "com.sun.star.chart2.PieChartType" || maChartTypeServiceName == "com.sun.star.chart2.DonutChartType" ) + { + OUString aPropName( "StartingAngle" ); + uno::Any aAStartingAngle( SchXMLTools::getPropertyFromContext( aPropName, pPropStyleContext, pStylesCtxt ) ); + if( !aAStartingAngle.hasValue() ) + xProp->setPropertyValue( aPropName, uno::Any(sal_Int32(0)) ) ; + } + } + } + } + } + } + } + + //remember default values for dataseries + if(xProp.is()) + { + try + { + mrSeriesDefaultsAndStyles.maSymbolTypeDefault = xProp->getPropertyValue("SymbolType"); + mrSeriesDefaultsAndStyles.maDataCaptionDefault = xProp->getPropertyValue("DataCaption"); + + mrSeriesDefaultsAndStyles.maMeanValueDefault = xProp->getPropertyValue("MeanValue"); + mrSeriesDefaultsAndStyles.maRegressionCurvesDefault = xProp->getPropertyValue("RegressionCurves"); + + bool bStacked = false; + mrSeriesDefaultsAndStyles.maStackedDefault = xProp->getPropertyValue("Stacked"); + mrSeriesDefaultsAndStyles.maStackedDefault >>= bStacked; + mrSeriesDefaultsAndStyles.maPercentDefault = xProp->getPropertyValue("Percent"); + mrSeriesDefaultsAndStyles.maPercentDefault >>= mbPercentStacked; + mrSeriesDefaultsAndStyles.maStackedBarsConnectedDefault = xProp->getPropertyValue("StackedBarsConnected"); + + // deep + uno::Any aDeepProperty( xProp->getPropertyValue("Deep")); + // #124488# old versions store a 3d area and 3D line deep chart with Deep==false => workaround for this + if( ! (bStacked || mbPercentStacked )) + { + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) + { + bool bIs3d = false; + if( ( xProp->getPropertyValue("Dim3D") >>= bIs3d ) && + bIs3d ) + { + if( maChartTypeServiceName == "com.sun.star.chart2.AreaChartType" || maChartTypeServiceName == "com.sun.star.chart2.LineChartType" ) + { + aDeepProperty <<= true; + } + } + } + } + mrSeriesDefaultsAndStyles.maDeepDefault = aDeepProperty; + + xProp->getPropertyValue("NumberOfLines") >>= mnNumOfLinesProp; + xProp->getPropertyValue("Volume") >>= mbStockHasVolume; + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "PlotAreaContext:EndElement(): Exception caught"); + } + } // if + + bool bCreateInternalDataProvider = false; + if( m_rXLinkHRefAttributeToIndicateDataProvider == "." ) //data comes from the chart itself + bCreateInternalDataProvider = true; + else if( m_rXLinkHRefAttributeToIndicateDataProvider == ".." ) //data comes from the parent application + bCreateInternalDataProvider = false; + else if( !m_rXLinkHRefAttributeToIndicateDataProvider.isEmpty() ) //not supported so far to get the data by sibling objects -> fall back to chart itself + bCreateInternalDataProvider = true; + else if( !m_rbHasRangeAtPlotArea ) + bCreateInternalDataProvider = true; + + if( bCreateInternalDataProvider && mxNewDoc.is() ) + { + // we have no complete range => we have own data, so switch the data + // provider to internal. Clone is not necessary, as we don't have any + // data yet. + mxNewDoc->createInternalDataProvider( false /* bCloneExistingData */ ); + if( xProp.is() && mrDataRowSource!=chart::ChartDataRowSource_COLUMNS ) + xProp->setPropertyValue("DataRowSource", uno::Any(mrDataRowSource) ); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLPlotAreaContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + + switch(nElement) + { + case XML_ELEMENT(CHART_EXT, XML_COORDINATE_REGION): + case XML_ELEMENT(CHART, XML_COORDINATE_REGION): + { + pContext = new SchXMLCoordinateRegionContext( GetImport(), m_aInnerPositioning ); + } + break; + + case XML_ELEMENT(CHART, XML_AXIS): + { + bool bAddMissingXAxisForNetCharts = false; + bool bAdaptWrongPercentScaleValues = false; + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) + { + //correct errors from older versions + + // for NetCharts there were no xAxis exported to older files + // so we need to add the x axis here for those old NetChart files + if ( maChartTypeServiceName == "com.sun.star.chart2.NetChartType" ) + bAddMissingXAxisForNetCharts = true; + + //Issue 59288 + if( mbPercentStacked ) + bAdaptWrongPercentScaleValues = true; + } + + bool bAdaptXAxisOrientationForOld2DBarCharts = false; + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_4( GetImport().GetModel() ) ) + { + //issue74660 + if ( maChartTypeServiceName == "com.sun.star.chart2.ColumnChartType" ) + bAdaptXAxisOrientationForOld2DBarCharts = true; + } + + pContext = new SchXMLAxisContext( mrImportHelper, GetImport(), mxDiagram, maAxes, mrCategoriesAddress, + bAddMissingXAxisForNetCharts, bAdaptWrongPercentScaleValues, bAdaptXAxisOrientationForOld2DBarCharts, m_bAxisPositionAttributeImported ); + } + break; + + case XML_ELEMENT(CHART, XML_SERIES): + { + if( mxNewDoc.is()) + { + pContext = new SchXMLSeries2Context( + mrImportHelper, GetImport(), + mxNewDoc, maAxes, + mrSeriesDefaultsAndStyles.maSeriesStyleVector, + mrSeriesDefaultsAndStyles.maRegressionStyleVector, + mnSeries, + mbStockHasVolume, + m_aGlobalSeriesImportInfo, + maChartTypeServiceName, + mrLSequencesPerIndex, + mbGlobalChartTypeUsedBySeries, maChartSize ); + } + mnSeries++; + } + break; + + case XML_ELEMENT(CHART, XML_WALL): + pContext = new SchXMLWallFloorContext( mrImportHelper, GetImport(), mxDiagram, + SchXMLWallFloorContext::CONTEXT_TYPE_WALL ); + break; + case XML_ELEMENT(CHART, XML_FLOOR): + pContext = new SchXMLWallFloorContext( mrImportHelper, GetImport(), mxDiagram, + SchXMLWallFloorContext::CONTEXT_TYPE_FLOOR ); + break; + + case XML_ELEMENT(DR3D, XML_LIGHT): + pContext = maSceneImportHelper.create3DLightContext( xAttrList ); + break; + + // elements for stock charts + case XML_ELEMENT(CHART, XML_STOCK_GAIN_MARKER): + pContext = new SchXMLStockContext( mrImportHelper, GetImport(), mxDiagram, + SchXMLStockContext::CONTEXT_TYPE_GAIN ); + break; + case XML_ELEMENT(CHART, XML_STOCK_LOSS_MARKER): + pContext = new SchXMLStockContext( mrImportHelper, GetImport(), mxDiagram, + SchXMLStockContext::CONTEXT_TYPE_LOSS ); + break; + case XML_ELEMENT(CHART, XML_STOCK_RANGE_LINE): + pContext = new SchXMLStockContext( mrImportHelper, GetImport(), mxDiagram, + SchXMLStockContext::CONTEXT_TYPE_RANGE ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return pContext; +} + +void SchXMLPlotAreaContext::endFastElement(sal_Int32 ) +{ + // set categories + if( !mrCategoriesAddress.isEmpty() && mxNewDoc.is()) + { + uno::Reference< chart2::data::XDataProvider > xDataProvider( + mxNewDoc->getDataProvider() ); + // @todo: correct coordinate system index + sal_Int32 nDimension( 0 ); + ::std::vector< SchXMLAxis >::const_iterator aIt( + ::std::find_if( maAxes.begin(), maAxes.end(), lcl_AxisHasCategories())); + if( aIt != maAxes.end()) + nDimension = static_cast< sal_Int32 >( (*aIt).eDimension ); + SchXMLTools::CreateCategories( + xDataProvider, mxNewDoc, mrCategoriesAddress, + 0 /* nCooSysIndex */, + nDimension, &mrLSequencesPerIndex ); + } + + uno::Reference< beans::XPropertySet > xDiaProp( mxDiagram, uno::UNO_QUERY ); + if( xDiaProp.is()) + { + bool bIsThreeDim = false; + uno::Any aAny = xDiaProp->getPropertyValue("Dim3D"); + aAny >>= bIsThreeDim; + + // set 3d scene attributes + if( bIsThreeDim ) + { + // set scene attributes at diagram + maSceneImportHelper.setSceneAttributes( xDiaProp ); + } + + // set correct number of lines at series + if( ! m_aGlobalSeriesImportInfo.rbAllRangeAddressesAvailable && mnNumOfLinesProp > 0 && maChartTypeServiceName == "com.sun.star.chart2.ColumnChartType" ) + { + try + { + xDiaProp->setPropertyValue("NumberOfLines", + uno::Any( mnNumOfLinesProp )); + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught for property NumberOfLines"); + } + } + + // #i32366# stock has volume + if( mxDiagram->getDiagramType() == "com.sun.star.chart.StockDiagram" && + mbStockHasVolume ) + { + try + { + xDiaProp->setPropertyValue("Volume", + uno::Any( true )); + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught for property Volume"); + } + } + } + + // set changed size and position after properties (esp. 3d) + + uno::Reference< chart::XDiagramPositioning > xDiaPos( mxDiagram, uno::UNO_QUERY ); + if( xDiaPos.is()) + { + if( !m_aOuterPositioning.isAutomatic() ) + { + if( m_aInnerPositioning.hasPosSize() ) + xDiaPos->setDiagramPositionExcludingAxes( m_aInnerPositioning.getRectangle() ); + else if( m_aOuterPositioning.hasPosSize() ) + { + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan3_3( GetImport().GetModel() ) ) //old version of OOo did write a wrong rectangle for the diagram size + xDiaPos->setDiagramPositionIncludingAxesAndAxisTitles( m_aOuterPositioning.getRectangle() ); + else + xDiaPos->setDiagramPositionIncludingAxes( m_aOuterPositioning.getRectangle() ); + } + } + } + + SchXMLAxisContext::CorrectAxisPositions( uno::Reference< chart2::XChartDocument >( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ), maChartTypeServiceName, GetImport().GetODFVersion(), m_bAxisPositionAttributeImported ); +} + +SchXMLDataLabelSpanContext::SchXMLDataLabelSpanContext( SvXMLImport& rImport, ::std::vector& rLabels): + SvXMLImportContext( rImport ), + mrLabels(rLabels) +{ +} + +void SchXMLDataLabelSpanContext::characters(const OUString& rChars) +{ + maCharBuffer.append(rChars); +} + +void SchXMLDataLabelSpanContext::endFastElement(sal_Int32 ) +{ + mrLabels.push_back(maCharBuffer.makeStringAndClear()); +} + +SchXMLDataLabelParaContext::SchXMLDataLabelParaContext( SvXMLImport& rImport, ::std::vector& rLabels): + SvXMLImportContext( rImport ), + mrLabels(rLabels) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLDataLabelParaContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_SPAN) ) + return new SchXMLDataLabelSpanContext(GetImport(), mrLabels); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +SchXMLDataLabelContext::SchXMLDataLabelContext(SvXMLImport& rImport, + CustomLabelsInfo& rLabels, + DataRowPointStyle& rDataLabelStyle) + : SvXMLImportContext(rImport) + , mrLabels(rLabels) + , mrDataLabelStyle(rDataLabelStyle) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLDataLabelContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_P) ) + return new SchXMLDataLabelParaContext(GetImport(), mrLabels.mLabels); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SchXMLDataLabelContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + { + sal_Int32 nResultValue; + GetImport().GetMM100UnitConverter().convertMeasureToCore(nResultValue, aIter.toView()); + mrDataLabelStyle.mo_nLabelAbsolutePosX = nResultValue; + break; + } + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + { + sal_Int32 nResultValue; + GetImport().GetMM100UnitConverter().convertMeasureToCore(nResultValue, aIter.toView()); + mrDataLabelStyle.mo_nLabelAbsolutePosY = nResultValue; + break; + } + case XML_ELEMENT(CHART, XML_STYLE_NAME): + mrDataLabelStyle.msStyleName = aIter.toString(); + break; + case XML_ELEMENT(LO_EXT, XML_DATA_LABEL_GUID): + mrLabels.msLabelGuid = aIter.toString(); + mrLabels.mbDataLabelsRange = true; + break; + case XML_ELEMENT(LO_EXT, XML_DATA_LABELS_CELL_RANGE): + mrLabels.msLabelsCellRange = aIter.toString(); + mrLabels.mbDataLabelsRange = true; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + + +SchXMLDataPointContext::SchXMLDataPointContext( SvXMLImport& rImport, + ::std::vector< DataRowPointStyle >& rStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + sal_Int32& rIndex, + bool bSymbolSizeForSeriesIsMissingInFile ) : + SvXMLImportContext( rImport ), + mrStyleVector( rStyleVector ), + mrIndex( rIndex ), + mDataPoint(DataRowPointStyle::DATA_POINT, xSeries, rIndex, 1, OUString{}), + mDataLabel(DataRowPointStyle::DATA_LABEL_POINT, xSeries, rIndex, 1, OUString{}) +{ + mDataPoint.mbSymbolSizeForSeriesIsMissingInFile = bSymbolSizeForSeriesIsMissingInFile; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLDataPointContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + switch(nElement) + { + case XML_ELEMENT(CHART, XML_DATA_LABEL): + mbHasLabelParagraph = true; + pContext = new SchXMLDataLabelContext(GetImport(), mDataPoint.mCustomLabels, + mDataLabel); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + return pContext; +} + +SchXMLDataPointContext::~SchXMLDataPointContext() +{ +} + +void SchXMLDataPointContext::startFastElement (sal_Int32 /*Element*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + OUString sAutoStyleName; + sal_Int32 nRepeat = 1; + OUString sCustomLabelField; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(CHART, XML_STYLE_NAME): + { + sAutoStyleName = aIter.toString(); + mDataPoint.msStyleName = sAutoStyleName; + mDataLabel.msStyleNameOfParent = sAutoStyleName; + break; + } + case XML_ELEMENT(CHART, XML_REPEATED): + { + nRepeat = aIter.toInt32(); + mDataPoint.m_nPointRepeat = nRepeat; + mDataLabel.m_nPointRepeat = nRepeat; + break; + } + // Deprecated. New documents use the chart:data-label element + // instead in order to store custom label text. + case XML_ELEMENT(LO_EXT, XML_CUSTOM_LABEL_FIELD): + if (!mbHasLabelParagraph) + { + sCustomLabelField = aIter.toString(); + mDataPoint.mCustomLabels.mLabels.push_back(sCustomLabelField); + } + break; + case XML_ELEMENT(LO_EXT, XML_HIDE_LEGEND): + { + bool bHideLegend = aIter.toBoolean(); + if (bHideLegend) + { + uno::Sequence deletedLegendEntriesSeq; + Reference xSeriesProp(mDataPoint.m_xSeries, uno::UNO_QUERY); + xSeriesProp->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq; + std::vector deletedLegendEntries; + for (const auto& deletedLegendEntry : std::as_const(deletedLegendEntriesSeq)) + { + deletedLegendEntries.push_back(deletedLegendEntry); + } + deletedLegendEntries.push_back(mDataPoint.m_nPointIndex); + xSeriesProp->setPropertyValue("DeletedLegendEntries", uno::Any(comphelper::containerToSequence(deletedLegendEntries))); + } + break; + } + case XML_ELEMENT(LO_EXT, XML_CUSTOM_LABEL_POS_X): + { + mDataPoint.mCustomLabelPos[0] = aIter.toDouble(); + break; + } + case XML_ELEMENT(LO_EXT, XML_CUSTOM_LABEL_POS_Y): + { + mDataPoint.mCustomLabelPos[1] = aIter.toDouble(); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + mrIndex += nRepeat; +} + +void SchXMLDataPointContext::endFastElement(sal_Int32 ) +{ + if(!mDataPoint.msStyleName.isEmpty() || mDataPoint.mCustomLabels.mLabels.size() > 0) + { + mrStyleVector.push_back(mDataPoint); + } + if (!mDataLabel.msStyleName.isEmpty() || mDataLabel.mo_nLabelAbsolutePosX.has_value() + || mDataLabel.mo_nLabelAbsolutePosY.has_value()) + { + mrStyleVector.push_back(mDataLabel); + } +} + +SchXMLPositionAttributesHelper::SchXMLPositionAttributesHelper( SvXMLImport& rImporter ) + : m_rImport( rImporter ) + , m_aPosition(0,0) + , m_aSize(0,0) + , m_bHasSizeWidth( false ) + , m_bHasSizeHeight( false ) + , m_bHasPositionX( false ) + , m_bHasPositionY( false ) + , m_bAutoSize( false ) + , m_bAutoPosition( false ) +{ +} + +bool SchXMLPositionAttributesHelper::hasPosSize() const +{ + return (m_bHasPositionX && m_bHasPositionY) && (m_bHasSizeWidth && m_bHasSizeHeight); +} + +bool SchXMLPositionAttributesHelper::isAutomatic() const +{ + return m_bAutoSize || m_bAutoPosition; +} + +void SchXMLPositionAttributesHelper::readPositioningAttribute( sal_Int32 nAttributeToken, std::string_view rValue ) +{ + if( !IsTokenInNamespace(nAttributeToken, XML_NAMESPACE_SVG) && !IsTokenInNamespace(nAttributeToken, XML_NAMESPACE_SVG_COMPAT) ) + return; + + switch (nAttributeToken & TOKEN_MASK) + { + case XML_X: + { + m_rImport.GetMM100UnitConverter().convertMeasureToCore( + m_aPosition.X, rValue ); + m_bHasPositionX = true; + break; + } + case XML_Y: + { + m_rImport.GetMM100UnitConverter().convertMeasureToCore( + m_aPosition.Y, rValue ); + m_bHasPositionY = true; + break; + } + case XML_WIDTH: + { + m_rImport.GetMM100UnitConverter().convertMeasureToCore( + m_aSize.Width, rValue ); + m_bHasSizeWidth = true; + break; + } + case XML_HEIGHT: + { + m_rImport.GetMM100UnitConverter().convertMeasureToCore( + m_aSize.Height, rValue ); + m_bHasSizeHeight = true; + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttributeToken, OUString::fromUtf8(rValue)); + } +} + +void SchXMLPositionAttributesHelper::readAutomaticPositioningProperties( XMLPropStyleContext const * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ) +{ + if( pPropStyleContext && pStylesCtxt ) + { + //handle automatic position and size + SchXMLTools::getPropertyFromContext( + u"AutomaticSize", pPropStyleContext, pStylesCtxt ) >>= m_bAutoSize; + SchXMLTools::getPropertyFromContext( + u"AutomaticPosition", pPropStyleContext, pStylesCtxt ) >>= m_bAutoPosition; + } +} + +SchXMLCoordinateRegionContext::SchXMLCoordinateRegionContext( + SvXMLImport& rImport + , SchXMLPositionAttributesHelper& rPositioning ) + : SvXMLImportContext( rImport ) + , m_rPositioning( rPositioning ) +{ +} + +SchXMLCoordinateRegionContext::~SchXMLCoordinateRegionContext() +{ +} + +void SchXMLCoordinateRegionContext::startFastElement (sal_Int32 /*Element*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // parse attributes + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + m_rPositioning.readPositioningAttribute( aIter.getToken(), aIter.toView() ); +} + +SchXMLWallFloorContext::SchXMLWallFloorContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + uno::Reference< chart::XDiagram > const & xDiagram, + ContextType eContextType ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ), + mxWallFloorSupplier( xDiagram, uno::UNO_QUERY ), + meContextType( eContextType ) +{ +} + +SchXMLWallFloorContext::~SchXMLWallFloorContext() +{ +} + +void SchXMLWallFloorContext::startFastElement (sal_Int32 /*Element*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + if( !mxWallFloorSupplier.is()) + return; + + OUString sAutoStyleName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(CHART, XML_STYLE_NAME) ) + sAutoStyleName = aIter.toString(); + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + + // set properties + uno::Reference< beans::XPropertySet > xProp = ( meContextType == CONTEXT_TYPE_WALL ) + ? mxWallFloorSupplier->getWall() + : mxWallFloorSupplier->getFloor(); + + if (!sAutoStyleName.isEmpty()) + mrImportHelper.FillAutoStyle(sAutoStyleName, xProp); +} + +SchXMLStockContext::SchXMLStockContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + uno::Reference< chart::XDiagram > const & xDiagram, + ContextType eContextType ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ), + mxStockPropProvider( xDiagram, uno::UNO_QUERY ), + meContextType( eContextType ) +{ +} + +SchXMLStockContext::~SchXMLStockContext() +{ +} + +void SchXMLStockContext::startFastElement (sal_Int32 /*Element*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + if( !mxStockPropProvider.is()) + return; + + OUString sAutoStyleName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(CHART, XML_STYLE_NAME) ) + sAutoStyleName = aIter.toString(); + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + + if( sAutoStyleName.isEmpty()) + return; + + // set properties + uno::Reference< beans::XPropertySet > xProp; + switch( meContextType ) + { + case CONTEXT_TYPE_GAIN: + xProp = mxStockPropProvider->getUpBar(); + break; + case CONTEXT_TYPE_LOSS: + xProp = mxStockPropProvider->getDownBar(); + break; + case CONTEXT_TYPE_RANGE: + xProp = mxStockPropProvider->getMinMaxLine(); + break; + } + + mrImportHelper.FillAutoStyle(sAutoStyleName, xProp); +} + +static void lcl_setErrorBarSequence ( const uno::Reference< chart2::XChartDocument > &xDoc, + const uno::Reference< beans::XPropertySet > &xBarProp, + const OUString &aXMLRange, + bool bPositiveValue, bool bYError, + tSchXMLLSequencesPerIndex& rSequences) +{ + uno::Reference< css::chart2::data::XDataProvider > xDataProvider(xDoc->getDataProvider()); + uno::Reference< css::chart2::data::XDataSource > xDataSource( xBarProp, uno::UNO_QUERY ); + uno::Reference< css::chart2::data::XDataSink > xDataSink( xDataSource, uno::UNO_QUERY ); + + assert( xDataSink.is() && xDataSource.is() && xDataProvider.is() ); + + OUString aRange(lcl_ConvertRange(aXMLRange,xDoc)); + + uno::Reference< chart2::data::XDataSequence > xNewSequence( + xDataProvider->createDataSequenceByRangeRepresentation( aRange )); + + if( !xNewSequence.is()) + return; + + SchXMLTools::setXMLRangePropertyAtDataSequence(xNewSequence,aXMLRange); + + OUStringBuffer aRoleBuffer("error-bars-"); + if( bYError ) + aRoleBuffer.append( 'y' ); + else + aRoleBuffer.append( 'x'); + + aRoleBuffer.append( '-' ); + + if( bPositiveValue ) + aRoleBuffer = aRoleBuffer.append( "positive" ); + else + aRoleBuffer = aRoleBuffer.append( "negative" ); + + OUString aRole = aRoleBuffer.makeStringAndClear(); + + Reference< beans::XPropertySet > xSeqProp( xNewSequence, uno::UNO_QUERY ); + + xSeqProp->setPropertyValue("Role", uno::Any( aRole )); + + Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + + Reference< chart2::data::XLabeledDataSequence > xLabelSeq( chart2::data::LabeledDataSequence::create(xContext), + uno::UNO_QUERY_THROW ); + + rSequences.emplace( tSchXMLIndexWithPart( -2, SCH_XML_PART_ERROR_BARS ), xLabelSeq ); + + xLabelSeq->setValues( xNewSequence ); + + uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( + xDataSource->getDataSequences()); + + aSequences.realloc( aSequences.getLength() + 1 ); + aSequences.getArray()[ aSequences.getLength() - 1 ] = xLabelSeq; + xDataSink->setData( aSequences ); + +} + +SchXMLStatisticsObjectContext::SchXMLStatisticsObjectContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString &rSeriesStyleName, + ::std::vector< DataRowPointStyle >& rStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + ContextType eContextType, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex) : + + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ), + mrStyleVector( rStyleVector ), + m_xSeries( xSeries ), + meContextType( eContextType ), + maSeriesStyleName( rSeriesStyleName), + mrLSequencesPerIndex(rLSequencesPerIndex) +{} + +SchXMLStatisticsObjectContext::~SchXMLStatisticsObjectContext() +{ +} + +namespace { + +void SetErrorBarStyleProperties( const OUString& rStyleName, const uno::Reference< beans::XPropertySet >& xBarProp, + SchXMLImportHelper const & rImportHelper ) +{ + const SvXMLStylesContext* pStylesCtxt = rImportHelper.GetAutoStylesContext(); + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(), + rStyleName); + + XMLPropStyleContext &rSeriesStyleContext = + const_cast< XMLPropStyleContext& >( dynamic_cast< const XMLPropStyleContext& >( *pStyle )); + + rSeriesStyleContext.FillPropertySet( xBarProp ); +} + +void SetErrorBarPropertiesFromStyleName( const OUString& aStyleName, const uno::Reference< beans::XPropertySet>& xBarProp, + SchXMLImportHelper const & rImportHelper, OUString& aPosRange, OUString& aNegRange) +{ + const SvXMLStylesContext* pStylesCtxt = rImportHelper.GetAutoStylesContext(); + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(), + aStyleName); + + XMLPropStyleContext * pSeriesStyleContext = + const_cast< XMLPropStyleContext * >( dynamic_cast< const XMLPropStyleContext * >( pStyle )); + + uno::Any aAny = SchXMLTools::getPropertyFromContext(u"ErrorBarStyle", + pSeriesStyleContext,pStylesCtxt); + + if ( !aAny.hasValue() ) + return; + + sal_Int32 aBarStyle = css::chart::ErrorBarStyle::NONE; + aAny >>= aBarStyle; + xBarProp->setPropertyValue("ErrorBarStyle", aAny); + + aAny = SchXMLTools::getPropertyFromContext(u"ShowPositiveError", + pSeriesStyleContext,pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("ShowPositiveError",aAny); + + aAny = SchXMLTools::getPropertyFromContext(u"ShowNegativeError", + pSeriesStyleContext,pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("ShowNegativeError",aAny); + + aAny = SchXMLTools::getPropertyFromContext(u"PositiveError", + pSeriesStyleContext, pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("PositiveError", aAny); + else + { + aAny = SchXMLTools::getPropertyFromContext(u"ConstantErrorHigh", + pSeriesStyleContext, pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("PositiveError", aAny); + } + + aAny = SchXMLTools::getPropertyFromContext(u"NegativeError", + pSeriesStyleContext, pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("NegativeError", aAny); + else + { + aAny = SchXMLTools::getPropertyFromContext(u"ConstantErrorLow", + pSeriesStyleContext, pStylesCtxt); + + if(aAny.hasValue()) + xBarProp->setPropertyValue("NegativeError", aAny); + } + + aAny = SchXMLTools::getPropertyFromContext(u"ErrorBarRangePositive", + pSeriesStyleContext, pStylesCtxt); + if( aAny.hasValue() ) + { + aAny >>= aPosRange; + } + + aAny = SchXMLTools::getPropertyFromContext(u"ErrorBarRangeNegative", + pSeriesStyleContext, pStylesCtxt); + if( aAny.hasValue() ) + { + aAny >>= aNegRange; + } + + aAny = SchXMLTools::getPropertyFromContext(u"Weight", + pSeriesStyleContext, pStylesCtxt); + if( aAny.hasValue() ) + { + xBarProp->setPropertyValue("Weight", aAny); + } + + aAny = SchXMLTools::getPropertyFromContext(u"PercentageError", + pSeriesStyleContext, pStylesCtxt); + if( aAny.hasValue() && aBarStyle == css::chart::ErrorBarStyle::RELATIVE ) + { + xBarProp->setPropertyValue("PositiveError", aAny); + xBarProp->setPropertyValue("NegativeError", aAny); + } + + switch(aBarStyle) + { + case css::chart::ErrorBarStyle::ERROR_MARGIN: + { + aAny = SchXMLTools::getPropertyFromContext(u"NegativeError", + pSeriesStyleContext,pStylesCtxt); + + xBarProp->setPropertyValue("NegativeError",aAny); + + aAny = SchXMLTools::getPropertyFromContext(u"PositiveError", + pSeriesStyleContext,pStylesCtxt); + + xBarProp->setPropertyValue("PositiveError",aAny); + } + break; + default: + break; + } + +} + +} + +void SchXMLStatisticsObjectContext::startFastElement (sal_Int32 /*Element*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + OUString sAutoStyleName; + OUString aPosRange; + OUString aNegRange; + bool bYError = true; /// Default errorbar, to be backward compatible with older files! + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(CHART, XML_STYLE_NAME): + sAutoStyleName = aIter.toString(); + break; + case XML_ELEMENT(CHART, XML_DIMENSION): + bYError = aIter.toView() == "y"; + break; + case XML_ELEMENT(CHART, XML_ERROR_UPPER_RANGE): + aPosRange = aIter.toString(); + break; + case XML_ELEMENT(CHART, XML_ERROR_LOWER_RANGE): + aNegRange = aIter.toString(); + break; + } + } + + if( sAutoStyleName.isEmpty() ) + return; + + DataRowPointStyle aStyle( DataRowPointStyle::MEAN_VALUE, m_xSeries, -1, 1, sAutoStyleName ); + + switch( meContextType ) + { + case CONTEXT_TYPE_MEAN_VALUE_LINE: + aStyle.meType = DataRowPointStyle::MEAN_VALUE; + break; + case CONTEXT_TYPE_ERROR_INDICATOR: + { + aStyle.meType = DataRowPointStyle::ERROR_INDICATOR; + + uno::Reference< lang::XMultiServiceFactory > xFact = comphelper::getProcessServiceFactory(); + + uno::Reference< beans::XPropertySet > xBarProp( xFact->createInstance("com.sun.star.chart2.ErrorBar" ), + uno::UNO_QUERY ); + + xBarProp->setPropertyValue("ErrorBarStyle",uno::Any(css::chart::ErrorBarStyle::NONE)); + xBarProp->setPropertyValue("PositiveError",uno::Any(0.0)); + xBarProp->setPropertyValue("NegativeError",uno::Any(0.0)); + xBarProp->setPropertyValue("Weight",uno::Any(1.0)); + xBarProp->setPropertyValue("ShowPositiveError",uno::Any(true)); + xBarProp->setPropertyValue("ShowNegativeError",uno::Any(true)); + + // first import defaults from parent style + SetErrorBarStyleProperties( maSeriesStyleName, xBarProp, mrImportHelper ); + SetErrorBarStyleProperties( sAutoStyleName, xBarProp, mrImportHelper ); + SetErrorBarPropertiesFromStyleName( maSeriesStyleName, xBarProp, mrImportHelper, aPosRange, aNegRange ); + SetErrorBarPropertiesFromStyleName( sAutoStyleName, xBarProp, mrImportHelper, aPosRange, aNegRange ); + + uno::Reference< chart2::XChartDocument > xDoc(GetImport().GetModel(),uno::UNO_QUERY); + + if (!aPosRange.isEmpty()) + lcl_setErrorBarSequence(xDoc,xBarProp,aPosRange,true,bYError, mrLSequencesPerIndex); + + if (!aNegRange.isEmpty()) + lcl_setErrorBarSequence(xDoc,xBarProp,aNegRange,false,bYError, mrLSequencesPerIndex); + + if ( !bYError ) + { + aStyle.m_xErrorXProperties.set( xBarProp ); + } + else + { + aStyle.m_xErrorYProperties.set( xBarProp ); + } + } + break; + } + + mrStyleVector.push_back( aStyle ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLPlotAreaContext.hxx b/xmloff/source/chart/SchXMLPlotAreaContext.hxx new file mode 100644 index 000000000..a1de29e18 --- /dev/null +++ b/xmloff/source/chart/SchXMLPlotAreaContext.hxx @@ -0,0 +1,304 @@ +/* -*- 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 "SchXMLChartContext.hxx" +#include +#include +#include +#include +#include +#include + +#include "transporttypes.hxx" + +class SvXMLImport; + +namespace com::sun::star { + namespace chart { + class XDiagram; + class X3DDisplay; + class XStatisticDisplay; + } + namespace chart2 { + class XChartDocument; + } + namespace xml::sax { + class XAttributeList; + } +} + +class SchXML3DSceneAttributesHelper : public SdXML3DSceneAttributesHelper +{ +public: + explicit SchXML3DSceneAttributesHelper( SvXMLImport& rImporter ); + virtual ~SchXML3DSceneAttributesHelper(); + + void getCameraDefaultFromDiagram( const css::uno::Reference< css::chart::XDiagram >& xDiagram ); +}; + +class SchXMLPositionAttributesHelper +{ +public: + explicit SchXMLPositionAttributesHelper( SvXMLImport& rImporter ); + + void readPositioningAttribute( sal_Int32 nAttributeToken, std::string_view rValue ); + void readAutomaticPositioningProperties( XMLPropStyleContext const * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ); + + bool hasPosSize() const; + bool isAutomatic() const; + css::awt::Rectangle getRectangle() const { return css::awt::Rectangle( m_aPosition.X, m_aPosition.Y, m_aSize.Width, m_aSize.Height );} + +private: + SvXMLImport& m_rImport; + + css::awt::Point m_aPosition; + css::awt::Size m_aSize; + + bool m_bHasSizeWidth; + bool m_bHasSizeHeight; + bool m_bHasPositionX; + bool m_bHasPositionY; + bool m_bAutoSize; + bool m_bAutoPosition; +}; + +class SchXMLPlotAreaContext : public SvXMLImportContext +{ +public: + SchXMLPlotAreaContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const OUString& rXLinkHRefAttributeToIndicateDataProvider, + OUString& rCategoriesAddress, + OUString& rChartAddress, + bool& bHasRangeAtPlotArea, + bool & rAllRangeAddressesAvailable, + bool & rColHasLabels, + bool & rRowHasLabels, + css::chart::ChartDataRowSource & rDataRowSource, + SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles, + const OUString& aChartTypeServiceName, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + const css::awt::Size & rChartSize ); + virtual ~SchXMLPlotAreaContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +private: + SchXMLImportHelper& mrImportHelper; + css::uno::Reference< css::chart::XDiagram > mxDiagram; + css::uno::Reference< css::chart2::XChartDocument > mxNewDoc; + ::std::vector< SchXMLAxis > maAxes; + OUString& mrCategoriesAddress; + SeriesDefaultsAndStyles& mrSeriesDefaultsAndStyles; + sal_Int32 mnNumOfLinesProp; + bool mbStockHasVolume; + sal_Int32 mnSeries; + GlobalSeriesImportInfo m_aGlobalSeriesImportInfo; + + SchXML3DSceneAttributesHelper maSceneImportHelper; + SchXMLPositionAttributesHelper m_aOuterPositioning;//including axes and axes titles + SchXMLPositionAttributesHelper m_aInnerPositioning;//excluding axes and axes titles + bool mbPercentStacked; + bool m_bAxisPositionAttributeImported; + OUString msAutoStyleName; + const OUString& m_rXLinkHRefAttributeToIndicateDataProvider; + OUString& mrChartAddress; + bool& m_rbHasRangeAtPlotArea; + bool & mrColHasLabels; + bool & mrRowHasLabels; + css::chart::ChartDataRowSource & mrDataRowSource; + OUString maChartTypeServiceName; + + tSchXMLLSequencesPerIndex & mrLSequencesPerIndex; + + bool mbGlobalChartTypeUsedBySeries; + css::awt::Size maChartSize; +}; + +class SchXMLDataLabelSpanContext: public SvXMLImportContext +{ +private: + ::std::vector& mrLabels; + OUStringBuffer maCharBuffer; +public: + SchXMLDataLabelSpanContext( SvXMLImport& rImport, ::std::vector& rLabels); + virtual void SAL_CALL characters( const OUString& rChars ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class SchXMLDataLabelParaContext: public SvXMLImportContext +{ +private: + ::std::vector& mrLabels; +public: + SchXMLDataLabelParaContext( SvXMLImport& rImport, ::std::vector& rLabels); + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +class SchXMLDataLabelContext: public SvXMLImportContext +{ +private: + CustomLabelsInfo& mrLabels; + DataRowPointStyle& mrDataLabelStyle; +public: + SchXMLDataLabelContext(SvXMLImport& rImport, + CustomLabelsInfo& rLabels, DataRowPointStyle& rDataLabel); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +class SchXMLDataPointContext : public SvXMLImportContext +{ +private: + ::std::vector& mrStyleVector; + bool mbHasLabelParagraph = false; + sal_Int32& mrIndex; + DataRowPointStyle mDataPoint; + // We let the data point manage the DataRowPointStyle-struct of its data label + DataRowPointStyle mDataLabel; + +public: + SchXMLDataPointContext( SvXMLImport& rImport, + ::std::vector< DataRowPointStyle >& rStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + sal_Int32& rIndex, + bool bSymbolSizeForSeriesIsMissingInFile ); + virtual ~SchXMLDataPointContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class SchXMLCoordinateRegionContext : public SvXMLImportContext +{ +public: + SchXMLCoordinateRegionContext( + SvXMLImport& rImport + , SchXMLPositionAttributesHelper& rPositioning ); + virtual ~SchXMLCoordinateRegionContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +private: + SchXMLPositionAttributesHelper& m_rPositioning; +}; + +class SchXMLWallFloorContext : public SvXMLImportContext +{ +public: + enum ContextType + { + CONTEXT_TYPE_WALL, + CONTEXT_TYPE_FLOOR + }; + +private: + SchXMLImportHelper& mrImportHelper; + css::uno::Reference< css::chart::X3DDisplay > mxWallFloorSupplier; + ContextType meContextType; + +public: + SchXMLWallFloorContext( SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + css::uno::Reference< css::chart::XDiagram > const & xDiagram, + ContextType eContextType ); + virtual ~SchXMLWallFloorContext() override; + virtual void SAL_CALL startFastElement (sal_Int32 Element, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs) override; +}; + +class SchXMLStockContext : public SvXMLImportContext +{ +public: + enum ContextType + { + CONTEXT_TYPE_GAIN, + CONTEXT_TYPE_LOSS, + CONTEXT_TYPE_RANGE + }; + +private: + SchXMLImportHelper& mrImportHelper; + css::uno::Reference< css::chart::XStatisticDisplay > mxStockPropProvider; + ContextType meContextType; + +public: + SchXMLStockContext( SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + css::uno::Reference< css::chart::XDiagram > const & xDiagram, + ContextType eContextType ); + virtual ~SchXMLStockContext() override; + virtual void SAL_CALL startFastElement (sal_Int32 Element, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs) override; +}; + +class SchXMLStatisticsObjectContext : public SvXMLImportContext +{ +public: + enum ContextType + { + CONTEXT_TYPE_MEAN_VALUE_LINE, + CONTEXT_TYPE_ERROR_INDICATOR + }; + + SchXMLStatisticsObjectContext( + SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + const OUString &rSeriesStyleName, + ::std::vector< DataRowPointStyle >& rStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + ContextType eContextType, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex ); + + virtual ~SchXMLStatisticsObjectContext() override; + + virtual void SAL_CALL startFastElement (sal_Int32 Element, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs) override; + +private: + SchXMLImportHelper & mrImportHelper; + ::std::vector< DataRowPointStyle > & mrStyleVector; + css::uno::Reference< css::chart2::XDataSeries > m_xSeries; + ContextType meContextType; + OUString maSeriesStyleName; + tSchXMLLSequencesPerIndex& mrLSequencesPerIndex; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLPropertyMappingContext.cxx b/xmloff/source/chart/SchXMLPropertyMappingContext.cxx new file mode 100644 index 000000000..40c3d0452 --- /dev/null +++ b/xmloff/source/chart/SchXMLPropertyMappingContext.cxx @@ -0,0 +1,115 @@ +/* -*- 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 "SchXMLPropertyMappingContext.hxx" +#include "SchXMLTools.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace ::xmloff::token; + +namespace { + +Reference< chart2::data::XLabeledDataSequence2 > createAndAddSequenceToSeries( const OUString& rRole + , const OUString& rRange + , const Reference< chart2::XChartDocument >& xChartDoc + , const Reference< chart2::XDataSeries >& xSeries ) +{ + Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq; + + Reference< chart2::data::XDataSource > xSeriesSource( xSeries,uno::UNO_QUERY ); + + if( !(!rRange.isEmpty() && xChartDoc.is() && xSeriesSource.is()) ) + return xLabeledSeq; + + // create a new sequence + xLabeledSeq = SchXMLTools::GetNewLabeledDataSequence(); + + // set values at the new sequence + Reference< chart2::data::XDataSequence > xSeq = SchXMLTools::CreateDataSequence( rRange, xChartDoc ); + Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY ); + if( xSeqProp.is()) + xSeqProp->setPropertyValue("Role", uno::Any( rRole)); + xLabeledSeq->setValues( xSeq ); + + Reference< chart2::data::XDataSink > xSink( xSeriesSource, uno::UNO_QUERY ); + if( xSink.is()) + { + Sequence< Reference< chart2::data::XLabeledDataSequence > > aData( xSeriesSource->getDataSequences()); + aData.realloc( aData.getLength() + 1 ); + aData.getArray()[ aData.getLength() - 1 ] = xLabeledSeq; + xSink->setData( aData ); + } + + return xLabeledSeq; +} + +} + +SchXMLPropertyMappingContext::SchXMLPropertyMappingContext( + SvXMLImport& rImport, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + uno::Reference< + chart2::XDataSeries > const & xSeries ): + SvXMLImportContext( rImport ), + mxDataSeries(xSeries), + mrLSequencesPerIndex(rLSequencesPerIndex) +{ + +} + +SchXMLPropertyMappingContext::~SchXMLPropertyMappingContext() +{ +} + +void SchXMLPropertyMappingContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + OUString aRange; + OUString aRole; + // parse attributes + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString aValue = aIter.toString(); + switch( aIter.getToken() ) + { + case XML_ELEMENT(LO_EXT, XML_PROPERTY): + aRole = aValue; + break; + case XML_ELEMENT(LO_EXT, XML_CELL_RANGE_ADDRESS): + aRange = aValue; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !aRange.isEmpty() && !aRole.isEmpty() ) + { + Reference< chart2::XChartDocument > xChartDoc( GetImport().GetModel(), uno::UNO_QUERY ); + Reference< chart2::data::XLabeledDataSequence2 > xSeq = + createAndAddSequenceToSeries(aRole, aRange, xChartDoc, mxDataSeries); + mrLSequencesPerIndex.emplace( + tSchXMLIndexWithPart( 0, SCH_XML_PART_VALUES), + xSeq); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLPropertyMappingContext.hxx b/xmloff/source/chart/SchXMLPropertyMappingContext.hxx new file mode 100644 index 000000000..1696a32f3 --- /dev/null +++ b/xmloff/source/chart/SchXMLPropertyMappingContext.hxx @@ -0,0 +1,45 @@ +/* -*- 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 "transporttypes.hxx" +#include +#include + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + class XDataSeries; + } +} + +class SchXMLPropertyMappingContext : public SvXMLImportContext +{ +public: + + SchXMLPropertyMappingContext( + SvXMLImport& rImport, + tSchXMLLSequencesPerIndex& rLSequencesPerIndex, + css::uno::Reference< + css::chart2::XDataSeries > const & xSeries ); + + virtual ~SchXMLPropertyMappingContext() override; + + virtual void SAL_CALL startFastElement (sal_Int32 Element, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs) override; +private: + + css::uno::Reference< css::chart2::XDataSeries > mxDataSeries; + + tSchXMLLSequencesPerIndex& mrLSequencesPerIndex; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLRegressionCurveObjectContext.cxx b/xmloff/source/chart/SchXMLRegressionCurveObjectContext.cxx new file mode 100644 index 000000000..16bec57fe --- /dev/null +++ b/xmloff/source/chart/SchXMLRegressionCurveObjectContext.cxx @@ -0,0 +1,181 @@ +/* -*- 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 "SchXMLRegressionCurveObjectContext.hxx" + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace xmloff::token; + +SchXMLRegressionCurveObjectContext::SchXMLRegressionCurveObjectContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + std::vector< RegressionStyle >& rRegressionStyleVector, + const css::uno::Reference< + css::chart2::XDataSeries >& xSeries, + const awt::Size & rChartSize) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ), + mxSeries( xSeries ), + maChartSize( rChartSize ), + mrRegressionStyleVector( rRegressionStyleVector ) +{ +} + +SchXMLRegressionCurveObjectContext::~SchXMLRegressionCurveObjectContext() +{ +} + +void SchXMLRegressionCurveObjectContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + OUString sAutoStyleName; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(CHART, XML_STYLE_NAME) ) + sAutoStyleName = aIter.toString(); + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + + RegressionStyle aStyle( mxSeries, sAutoStyleName ); + mrRegressionStyleVector.push_back( aStyle ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLRegressionCurveObjectContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( nElement == XML_ELEMENT(CHART, XML_EQUATION) ) + { + return new SchXMLEquationContext( + mrImportHelper, GetImport(), maChartSize, mrRegressionStyleVector.back()); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +SchXMLEquationContext::SchXMLEquationContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const awt::Size& rChartSize, + RegressionStyle& rRegressionStyle ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ), + mrRegressionStyle( rRegressionStyle ), + maChartSize( rChartSize ) +{} + +SchXMLEquationContext::~SchXMLEquationContext() +{} + +void SchXMLEquationContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // parse attributes + SchXMLImport& rImport = static_cast< SchXMLImport& >(GetImport()); + OUString sAutoStyleName; + bool bShowEquation = true; + bool bShowRSquare = false; + awt::Point aPosition; + bool bHasXPos = false; + bool bHasYPos = false; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + rImport.GetMM100UnitConverter().convertMeasureToCore( + aPosition.X, aIter.toView() ); + bHasXPos = true; + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + rImport.GetMM100UnitConverter().convertMeasureToCore( + aPosition.Y, aIter.toView() ); + bHasYPos = true; + break; + case XML_ELEMENT(CHART, XML_DISPLAY_EQUATION): + (void)::sax::Converter::convertBool(bShowEquation, aIter.toView()); + break; + case XML_ELEMENT(CHART, XML_DISPLAY_R_SQUARE): + (void)::sax::Converter::convertBool(bShowRSquare, aIter.toView()); + break; + case XML_ELEMENT(CHART, XML_STYLE_NAME): + sAutoStyleName = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( sAutoStyleName.isEmpty() && !bShowEquation && !bShowRSquare ) + return; + + uno::Reference< beans::XPropertySet > xEquationProperties = chart2::RegressionEquation::create( comphelper::getProcessComponentContext() ); + + if( !sAutoStyleName.isEmpty() ) + { + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + if( pStylesCtxt ) + { + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), sAutoStyleName ); + + XMLPropStyleContext* pPropStyleContext = + const_cast< XMLPropStyleContext* >( dynamic_cast< const XMLPropStyleContext* >( pStyle )); + + if( pPropStyleContext ) + pPropStyleContext->FillPropertySet( xEquationProperties ); + } + } + xEquationProperties->setPropertyValue( "ShowEquation", uno::Any( bShowEquation )); + xEquationProperties->setPropertyValue( "ShowCorrelationCoefficient", uno::Any( bShowRSquare )); + + if( bHasXPos && bHasYPos ) + { + chart2::RelativePosition aRelPos; + aRelPos.Primary = static_cast< double >( aPosition.X ) / static_cast< double >( maChartSize.Width ); + aRelPos.Secondary = static_cast< double >( aPosition.Y ) / static_cast< double >( maChartSize.Height ); + xEquationProperties->setPropertyValue( "RelativePosition", uno::Any( aRelPos )); + } + mrRegressionStyle.m_xEquationProperties.set( xEquationProperties ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLRegressionCurveObjectContext.hxx b/xmloff/source/chart/SchXMLRegressionCurveObjectContext.hxx new file mode 100644 index 000000000..13b796cd2 --- /dev/null +++ b/xmloff/source/chart/SchXMLRegressionCurveObjectContext.hxx @@ -0,0 +1,74 @@ +/* -*- 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 +#include +#include + +#include "transporttypes.hxx" + +class SchXMLRegressionCurveObjectContext : public SvXMLImportContext +{ +public: + SchXMLRegressionCurveObjectContext( + SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + std::vector< RegressionStyle >& rRegressionStyleVector, + const css::uno::Reference< css::chart2::XDataSeries >& xSeries, + const css::awt::Size & rChartSize ); + + virtual ~SchXMLRegressionCurveObjectContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +private: + + SchXMLImportHelper& mrImportHelper; + css::uno::Reference mxSeries; + css::awt::Size maChartSize; + std::vector< RegressionStyle >& mrRegressionStyleVector; +}; + +class SchXMLEquationContext : public SvXMLImportContext +{ +public: + SchXMLEquationContext( + SchXMLImportHelper& rImportHelper, + SvXMLImport& rImport, + const css::awt::Size & rChartSize, + RegressionStyle & rRegressionStyle ); + + virtual ~SchXMLEquationContext() override; + + virtual void SAL_CALL startFastElement (sal_Int32 Element, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs) override; + +private: + SchXMLImportHelper& mrImportHelper; + RegressionStyle& mrRegressionStyle; + css::awt::Size maChartSize; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLSeries2Context.cxx b/xmloff/source/chart/SchXMLSeries2Context.cxx new file mode 100644 index 000000000..56b983048 --- /dev/null +++ b/xmloff/source/chart/SchXMLSeries2Context.cxx @@ -0,0 +1,1307 @@ +/* -*- 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 "SchXMLSeries2Context.hxx" +#include "SchXMLPlotAreaContext.hxx" +#include "SchXMLRegressionCurveObjectContext.hxx" +#include "SchXMLPropertyMappingContext.hxx" +#include "SchXMLTools.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include // std::find_if + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +class SchXMLDomain2Context : public SvXMLImportContext +{ +private: + ::std::vector< OUString > & mrAddresses; + +public: + SchXMLDomain2Context( SvXMLImport& rImport, + ::std::vector< OUString > & rAddresses ); + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +SchXMLDomain2Context::SchXMLDomain2Context( + SvXMLImport& rImport, + ::std::vector< OUString > & rAddresses ) : + SvXMLImportContext( rImport ), + mrAddresses( rAddresses ) +{ +} + +void SchXMLDomain2Context::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(TABLE, XML_CELL_RANGE_ADDRESS) ) + mrAddresses.push_back( aIter.toString() ); + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +void lcl_setAutomaticSymbolSize( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport ) +{ + awt::Size aSymbolSize(140,140);//old default for standard sized charts 7cm height + + uno::Reference< chart::XChartDocument > xChartDoc( rImport.GetModel(), uno::UNO_QUERY ); + if( xChartDoc.is() ) + { + double fScale = 1; + uno::Reference< beans::XPropertySet > xLegendProp( xChartDoc->getLegend(), uno::UNO_QUERY ); + chart::ChartLegendPosition aLegendPosition = chart::ChartLegendPosition_NONE; + if( xLegendProp.is() && (xLegendProp->getPropertyValue("Alignment") >>= aLegendPosition) + && chart::ChartLegendPosition_NONE != aLegendPosition ) + { + + double fFontHeight = 6.0; + if( xLegendProp->getPropertyValue("CharHeight") >>= fFontHeight ) + fScale = 0.75*fFontHeight/6.0; + } + else + { + uno::Reference< embed::XVisualObject > xVisualObject( rImport.GetModel(), uno::UNO_QUERY ); + if( xVisualObject.is() ) + { + awt::Size aPageSize( xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) ); + fScale = aPageSize.Height/7000.0; + } + } + if( fScale>0 ) + { + aSymbolSize.Height = static_cast( fScale * aSymbolSize.Height ); + aSymbolSize.Width = aSymbolSize.Height; + } + } + xSeriesOrPointProp->setPropertyValue("SymbolSize",uno::Any( aSymbolSize )); +} + +void lcl_setSymbolSizeIfNeeded( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport ) +{ + if( !xSeriesOrPointProp.is() ) + return; + + sal_Int32 nSymbolType = chart::ChartSymbolType::NONE; + if( !(xSeriesOrPointProp.is() && ( xSeriesOrPointProp->getPropertyValue("SymbolType") >>= nSymbolType)) ) + return; + + if(chart::ChartSymbolType::NONE!=nSymbolType) + { + if( chart::ChartSymbolType::BITMAPURL==nSymbolType ) + { + //set special size for graphics to indicate to use the bitmap size itself + xSeriesOrPointProp->setPropertyValue("SymbolSize",uno::Any( awt::Size(-1,-1) )); + } + else + { + lcl_setAutomaticSymbolSize( xSeriesOrPointProp, rImport ); + } + } +} + +void lcl_resetSymbolSizeForPointsIfNecessary( const uno::Reference< beans::XPropertySet >& xPointProp, const SvXMLImport& rImport + , const XMLPropStyleContext * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ) +{ + uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize", pPropStyleContext, pStylesCtxt ) ); + if( !aASymbolSize.hasValue() ) + lcl_setSymbolSizeIfNeeded( xPointProp, rImport ); +} + +void lcl_setLinkNumberFormatToSourceIfNeeded( const uno::Reference< beans::XPropertySet >& xPointProp + , const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ) +{ + uno::Any aAny( SchXMLTools::getPropertyFromContext(u"LinkNumberFormatToSource", pPropStyleContext, pStylesCtxt) ); + if( aAny.hasValue() ) + return; + + if( !xPointProp.is() ) + return; + + bool bLinkToSource = false; + if( xPointProp.is() && (xPointProp->getPropertyValue("LinkNumberFormatToSource") >>= bLinkToSource) ) + { + if( bLinkToSource ) + { + xPointProp->setPropertyValue("LinkNumberFormatToSource", uno::Any(false)); + } + } +} + +void lcl_insertErrorBarLSequencesToMap( + tSchXMLLSequencesPerIndex & rInOutMap, + const uno::Reference< beans::XPropertySet > & xSeriesProp ) +{ + Reference< chart2::data::XDataSource > xErrorBarSource; + if( ( xSeriesProp->getPropertyValue( "ErrorBarY" ) >>= xErrorBarSource ) && + xErrorBarSource.is() ) + { + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSequences( + xErrorBarSource->getDataSequences()); + for( const auto& rLSequence : aLSequences ) + { + // use "0" as data index. This is ok, as it is not used for error bars + rInOutMap.emplace( + tSchXMLIndexWithPart( 0, SCH_XML_PART_ERROR_BARS ), rLSequence ); + } + } +} + +Reference< chart2::data::XLabeledDataSequence2 > lcl_createAndAddSequenceToSeries( const OUString& rRole + , const OUString& rRange + , const Reference< chart2::XChartDocument >& xChartDoc + , const Reference< chart2::XDataSeries >& xSeries ) +{ + Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq; + + Reference< chart2::data::XDataSource > xSeriesSource( xSeries,uno::UNO_QUERY ); + Reference< chart2::data::XDataSink > xSeriesSink( xSeries, uno::UNO_QUERY ); + + if( !(!rRange.isEmpty() && xChartDoc.is() && xSeriesSource.is() && xSeriesSink.is()) ) + return xLabeledSeq; + + // create a new sequence + xLabeledSeq = SchXMLTools::GetNewLabeledDataSequence(); + + // set values at the new sequence + Reference< chart2::data::XDataSequence > xSeq = SchXMLTools::CreateDataSequence( rRange, xChartDoc ); + Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY ); + if( xSeqProp.is()) + xSeqProp->setPropertyValue("Role", uno::Any( rRole)); + xLabeledSeq->setValues( xSeq ); + + // add new sequence to data series / push to front to have the correct sequence order if charttype is changed afterwards + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aOldSeq( xSeriesSource->getDataSequences()); + sal_Int32 nOldCount = aOldSeq.getLength(); + Sequence< Reference< chart2::data::XLabeledDataSequence > > aNewSeq( nOldCount + 1 ); + auto pNewSeq = aNewSeq.getArray(); + pNewSeq[0].set(xLabeledSeq, uno::UNO_QUERY_THROW); + std::copy(aOldSeq.begin(), aOldSeq.end(), std::next(pNewSeq)); + xSeriesSink->setData( aNewSeq ); + + return xLabeledSeq; +} + +XMLPropStyleContext* lcl_GetStylePropContext( + const SvXMLStylesContext* pStylesCtxt, + const SvXMLStyleContext*& rpStyle, + OUString const & rStyleName ) +{ + rpStyle = pStylesCtxt->FindStyleChildContext( SchXMLImportHelper::GetChartFamilyID(), rStyleName ); + XMLPropStyleContext* pPropStyleContext = + const_cast< XMLPropStyleContext* >(dynamic_cast< const XMLPropStyleContext* >( rpStyle )); + return pPropStyleContext; +} + +} // anonymous namespace + +SchXMLSeries2Context::SchXMLSeries2Context( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const Reference< chart2::XChartDocument > & xNewDoc, + std::vector< SchXMLAxis >& rAxes, + ::std::vector< DataRowPointStyle >& rStyleVector, + ::std::vector< RegressionStyle >& rRegressionStyleVector, + sal_Int32 nSeriesIndex, + bool bStockHasVolume, + GlobalSeriesImportInfo& rGlobalSeriesImportInfo, + const OUString & aGlobalChartTypeName, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + bool& rGlobalChartTypeUsedBySeries, + const awt::Size & rChartSize ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ), + mxNewDoc( xNewDoc ), + mrAxes( rAxes ), + mrStyleVector( rStyleVector ), + mrRegressionStyleVector( rRegressionStyleVector ), + mnSeriesIndex( nSeriesIndex ), + mnDataPointIndex( 0 ), + m_bStockHasVolume( bStockHasVolume ), + m_rGlobalSeriesImportInfo(rGlobalSeriesImportInfo), + mpAttachedAxis( nullptr ), + mnAttachedAxis( 0 ), + maGlobalChartTypeName( aGlobalChartTypeName ), + maSeriesChartTypeName( aGlobalChartTypeName ), + m_bHasDomainContext(false), + mrLSequencesPerIndex( rLSequencesPerIndex ), + mrGlobalChartTypeUsedBySeries( rGlobalChartTypeUsedBySeries ), + mbSymbolSizeIsMissingInFile(false), + maChartSize( rChartSize ), + // A series manages the DataRowPointStyle-struct of a data-label child element. + mDataLabel(DataRowPointStyle::DATA_LABEL_SERIES, OUString{}) +{ + if( aGlobalChartTypeName == "com.sun.star.chart2.DonutChartType" ) + { + maSeriesChartTypeName = "com.sun.star.chart2.PieChartType"; + maGlobalChartTypeName = maSeriesChartTypeName; + } +} + +SchXMLSeries2Context::~SchXMLSeries2Context() +{ + SAL_WARN_IF( !maPostponedSequences.empty(), "xmloff.chart", "maPostponedSequences is NULL"); +} + +void SchXMLSeries2Context::startFastElement (sal_Int32 /*Element*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // parse attributes + mnAttachedAxis = 1; + + bool bHasRange = false; + OUString aSeriesLabelRange; + OUString aSeriesLabelString; + bool bHideLegend = false; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString aValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(CHART, XML_VALUES_CELL_RANGE_ADDRESS): + m_aSeriesRange = aValue; + bHasRange = true; + break; + case XML_ELEMENT(CHART, XML_LABEL_CELL_ADDRESS): + aSeriesLabelRange = aValue; + break; + case XML_ELEMENT(LO_EXT, XML_LABEL_STRING): + aSeriesLabelString = aValue; + break; + case XML_ELEMENT(CHART, XML_ATTACHED_AXIS): + { + sal_Int32 nNumOfAxes = mrAxes.size(); + for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ ) + { + if( aValue == mrAxes[ nCurrent ].aName && + mrAxes[ nCurrent ].eDimension == SCH_XML_AXIS_Y ) + { + mpAttachedAxis = &( mrAxes[ nCurrent ] ); + } + } + } + break; + case XML_ELEMENT(CHART, XML_STYLE_NAME): + msAutoStyleName = aValue; + break; + case XML_ELEMENT(CHART, XML_CLASS): + { + OUString aClassName; + sal_uInt16 nClassPrefix = + GetImport().GetNamespaceMap().GetKeyByAttrValueQName( + aValue, &aClassName ); + if( XML_NAMESPACE_CHART == nClassPrefix ) + maSeriesChartTypeName = SchXMLTools::GetChartTypeByClassName( aClassName, false /* bUseOldNames */ ); + + if( maSeriesChartTypeName.isEmpty()) + maSeriesChartTypeName = aClassName; + } + break; + case XML_ELEMENT(LO_EXT, XML_HIDE_LEGEND): + bHideLegend = aValue.toBoolean(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( mpAttachedAxis ) + { + if( mpAttachedAxis->nAxisIndex > 0 ) + { + // secondary axis => property has to be set (primary is default) + mnAttachedAxis = 2; + } + } + + try + { + SAL_WARN_IF( !mxNewDoc.is(), "xmloff.chart", "mxNewDoc is NULL"); + if( m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable && ! bHasRange ) + m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable = false; + + bool bIsCandleStick = maGlobalChartTypeName == "com.sun.star.chart2.CandleStickChartType"; + if( !maSeriesChartTypeName.isEmpty() ) + { + bIsCandleStick = maSeriesChartTypeName == "com.sun.star.chart2.CandleStickChartType"; + } + else + { + if( bIsCandleStick + && m_bStockHasVolume + && mnSeriesIndex == 0 ) + { + maSeriesChartTypeName = "com.sun.star.chart2.ColumnChartType"; + bIsCandleStick = false; + } + else + { + maSeriesChartTypeName = maGlobalChartTypeName; + } + } + if( ! mrGlobalChartTypeUsedBySeries ) + mrGlobalChartTypeUsedBySeries = (maSeriesChartTypeName == maGlobalChartTypeName); + sal_Int32 const nCoordinateSystemIndex = 0;//so far we can only import one coordinate system + m_xSeries.set( + SchXMLImportHelper::GetNewDataSeries( mxNewDoc, nCoordinateSystemIndex, maSeriesChartTypeName, ! mrGlobalChartTypeUsedBySeries )); + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( SchXMLTools::GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW ); + + Reference< beans::XPropertySet > xSeriesProp( m_xSeries, uno::UNO_QUERY ); + if (xSeriesProp.is()) + { + if (bHideLegend) + xSeriesProp->setPropertyValue("ShowLegendEntry", uno::Any(false)); + + if( bIsCandleStick ) + { + // set default color for range-line to black (before applying styles) + xSeriesProp->setPropertyValue("Color", + uno::Any( sal_Int32( 0x000000 ))); // black + } + else if ( maSeriesChartTypeName == "com.sun.star.chart2.PieChartType" ) + { + //@todo: this property should be saved + xSeriesProp->setPropertyValue("VaryColorsByPoint", + uno::Any( true )); + } + + } + + Reference xDataProvider(mxNewDoc->getDataProvider()); + Reference xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY); + + Reference xSequenceValues; + + // values + if (xPivotTableDataProvider.is()) // is pivot chart + { + xSequenceValues.set(xPivotTableDataProvider->createDataSequenceOfValuesByIndex(mnSeriesIndex)); + } + else + { + if (bHasRange && !m_aSeriesRange.isEmpty()) + xSequenceValues = SchXMLTools::CreateDataSequence(m_aSeriesRange, mxNewDoc); + } + + Reference xSeqProp(xSequenceValues, uno::UNO_QUERY); + if (xSeqProp.is()) + { + OUString aMainRole("values-y"); + if (maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType") + aMainRole = "values-size"; + xSeqProp->setPropertyValue("Role", uno::Any(aMainRole)); + } + xLabeledSeq->setValues(xSequenceValues); + + // register for setting local data if external data provider is not present + maPostponedSequences.emplace( + tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_VALUES ), xLabeledSeq ); + + // label + Reference xSequenceLabel; + + if (xPivotTableDataProvider.is()) + { + xSequenceLabel.set(xPivotTableDataProvider->createDataSequenceOfLabelsByIndex(mnSeriesIndex)); + } + else + { + if (!aSeriesLabelRange.isEmpty()) + { + xSequenceLabel.set(SchXMLTools::CreateDataSequence(aSeriesLabelRange, mxNewDoc)); + } + else if (!aSeriesLabelString.isEmpty()) + { + xSequenceLabel.set(SchXMLTools::CreateDataSequenceWithoutConvert(aSeriesLabelString, mxNewDoc)); + } + } + + //Labels should always include hidden cells + Reference xSeqLabelProp(xSequenceLabel, uno::UNO_QUERY); + if (xSeqLabelProp.is() && xSeqLabelProp->getPropertySetInfo()->hasPropertyByName("IncludeHiddenCells")) + { + xSeqLabelProp->setPropertyValue( "IncludeHiddenCells", uno::Any(true)); + } + + xLabeledSeq->setLabel(xSequenceLabel); + + // Note: Even if we have no label, we have to register the label + // for creation, because internal data always has labels. If + // they don't exist in the original, auto-generated labels are + // used for the internal data. + maPostponedSequences.emplace( + tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_LABEL ), xLabeledSeq ); + + Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( &xLabeledSeq, 1 ); + Reference< chart2::data::XDataSink > xSink( m_xSeries, uno::UNO_QUERY_THROW ); + xSink->setData( aSeq ); + } + catch( const uno::Exception &) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + + //init mbSymbolSizeIsMissingInFile: + try + { + if( !msAutoStyleName.isEmpty() ) + { + const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext(); + if( pStylesCtxt ) + { + const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), msAutoStyleName ); + + const XMLPropStyleContext* pPropStyleContext = dynamic_cast< const XMLPropStyleContext * >( pStyle ); + + uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize" + , pPropStyleContext, pStylesCtxt ) ); + mbSymbolSizeIsMissingInFile = !aASymbolSize.hasValue(); + } + } + } + catch( const uno::Exception & ) + { + } +} + +namespace { + +struct DomainInfo +{ + DomainInfo( const OUString& rRole, const OUString& rRange, sal_Int32 nIndex ) + : aRole(rRole), aRange(rRange), nIndexForLocalData(nIndex) + {} + + OUString aRole; + OUString aRange; + sal_Int32 nIndexForLocalData; +}; + +} + +void SchXMLSeries2Context::endFastElement(sal_Int32 ) +{ + // special handling for different chart types. This is necessary as the + // roles are not yet saved in the file format + sal_Int32 nDomainCount = maDomainAddresses.size(); + bool bIsScatterChart = maSeriesChartTypeName == "com.sun.star.chart2.ScatterChartType"; + bool bIsBubbleChart = maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType"; + bool bDeleteSeries = false; + std::vector< DomainInfo > aDomainInfos; + + //different handling for different chart types necessary + if( bIsScatterChart || ( nDomainCount==1 && !bIsBubbleChart ) ) + { + DomainInfo aDomainInfo( "values-x", m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ; + bool bCreateXValues = true; + if( !maDomainAddresses.empty() ) + { + if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() ) + { + m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front(); + m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex; + } + aDomainInfo.aRange = maDomainAddresses.front(); + aDomainInfo.nIndexForLocalData = m_rGlobalSeriesImportInfo.nCurrentDataIndex; + m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + } + else if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() && !m_bHasDomainContext && mnSeriesIndex==0 ) + { + if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) //wrong old chart files: + { + //for xy charts the first series needs to have a domain + //if this by error iss not the case the first series is taken s x values + //needed for wrong files created while having an addin (e.g. BoxPlot) + m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = m_aSeriesRange; + m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + bDeleteSeries = true; + bCreateXValues = false;//they will be created for the next series + } + } + if( bCreateXValues ) + aDomainInfos.push_back( aDomainInfo ); + } + else if( bIsBubbleChart ) + { + if( nDomainCount>1 ) + { + DomainInfo aDomainInfo( "values-x", maDomainAddresses[1], m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ; + if( m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() ) + { + //for bubble chart the second domain contains the x values which should become an index smaller than y values for own data table + //->so second first + m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress = maDomainAddresses[1]; + m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex; + } + aDomainInfos.push_back( aDomainInfo ); + m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + } + else if( !m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() ) + { + DomainInfo aDomainInfo( "values-x", m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress, m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex ) ; + aDomainInfos.push_back( aDomainInfo ); + } + if( nDomainCount>0) + { + DomainInfo aDomainInfo( "values-y", maDomainAddresses.front(), m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ; + if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() ) + { + m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front(); + m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex; + } + aDomainInfos.push_back( aDomainInfo ); + m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + } + else if( !m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() ) + { + DomainInfo aDomainInfo( "values-y", m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ; + aDomainInfos.push_back( aDomainInfo ); + } + } + + if( bDeleteSeries ) + { + //delete created series + SchXMLImportHelper::DeleteDataSeries( + m_xSeries, Reference< chart2::XChartDocument >( GetImport().GetModel(), uno::UNO_QUERY ) ); + } + else + { + //add style + if( !msAutoStyleName.isEmpty() || mnAttachedAxis != 1 ) + { + DataRowPointStyle aStyle( + DataRowPointStyle::DATA_SERIES, + m_xSeries, + -1, 1, + msAutoStyleName, mnAttachedAxis ); + aStyle.mbSymbolSizeForSeriesIsMissingInFile=mbSymbolSizeIsMissingInFile; + mrStyleVector.push_back( aStyle ); + } + // And styles for a data-label child element too. In contrast to data-labels as child of data points, + // an information about absolute position is useless here. We need only style information. + if (!mDataLabel.msStyleName.isEmpty()) + { + mDataLabel.msStyleNameOfParent = msAutoStyleName; + mDataLabel.m_xSeries = m_xSeries; + mDataLabel.mnAttachedAxis = mnAttachedAxis; // not needed, but be consistent with its parent + mrStyleVector.push_back(mDataLabel); + } + } + + for( std::vector< DomainInfo >::reverse_iterator aIt( aDomainInfos.rbegin() ); aIt!= aDomainInfos.rend(); ++aIt ) + { + DomainInfo aDomainInfo( *aIt ); + Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq = + lcl_createAndAddSequenceToSeries( aDomainInfo.aRole, aDomainInfo.aRange, mxNewDoc, m_xSeries ); + if( xLabeledSeq.is() ) + { + // register for setting local data if external data provider is not present + mrLSequencesPerIndex.emplace( + tSchXMLIndexWithPart( aDomainInfo.nIndexForLocalData, SCH_XML_PART_VALUES ), + Reference< chart2::data::XLabeledDataSequence >(xLabeledSeq, uno::UNO_QUERY_THROW) ); + } + } + + if( !bDeleteSeries ) + { + for (auto const& postponedSequence : maPostponedSequences) + { + sal_Int32 nNewIndex = postponedSequence.first.first + nDomainCount; + mrLSequencesPerIndex.emplace( tSchXMLIndexWithPart( nNewIndex, postponedSequence.first.second ), postponedSequence.second ); + } + m_rGlobalSeriesImportInfo.nCurrentDataIndex++; + } + maPostponedSequences.clear(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLSeries2Context::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + switch(nElement) + { + case XML_ELEMENT(CHART, XML_DOMAIN): + if( m_xSeries.is()) + { + m_bHasDomainContext = true; + pContext = new SchXMLDomain2Context( + GetImport(), maDomainAddresses ); + } + break; + + case XML_ELEMENT(CHART, XML_MEAN_VALUE): + pContext = new SchXMLStatisticsObjectContext( + mrImportHelper, GetImport(), + msAutoStyleName, + mrStyleVector, m_xSeries, + SchXMLStatisticsObjectContext::CONTEXT_TYPE_MEAN_VALUE_LINE, + mrLSequencesPerIndex ); + break; + case XML_ELEMENT(CHART, XML_REGRESSION_CURVE): + pContext = new SchXMLRegressionCurveObjectContext( + mrImportHelper, GetImport(), + mrRegressionStyleVector, + m_xSeries, maChartSize ); + break; + case XML_ELEMENT(CHART, XML_ERROR_INDICATOR): + pContext = new SchXMLStatisticsObjectContext( + mrImportHelper, GetImport(), + msAutoStyleName, + mrStyleVector, m_xSeries, + SchXMLStatisticsObjectContext::CONTEXT_TYPE_ERROR_INDICATOR, + mrLSequencesPerIndex ); + break; + + case XML_ELEMENT(CHART, XML_DATA_POINT): + pContext = new SchXMLDataPointContext( GetImport(), + mrStyleVector, m_xSeries, mnDataPointIndex, mbSymbolSizeIsMissingInFile ); + break; + case XML_ELEMENT(CHART, XML_DATA_LABEL): + // CustomLabels are useless for a data label element as child of a series, because it serves as default + // for all data labels. But the ctor expects it, so use that of the mDataLabel struct as ersatz. + pContext = new SchXMLDataLabelContext(GetImport(), mDataLabel.mCustomLabels, + mDataLabel); + break; + + case XML_ELEMENT(LO_EXT, XML_PROPERTY_MAPPING): + pContext = new SchXMLPropertyMappingContext( + GetImport(), + mrLSequencesPerIndex, m_xSeries ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return pContext; +} + +//static +void SchXMLSeries2Context::initSeriesPropertySets( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const uno::Reference< frame::XModel >& xChartModel ) +{ + // iterate over series first and remind propertysets in map + // new api <-> old api wrapper + ::std::map< Reference< chart2::XDataSeries >, Reference< beans::XPropertySet > > aSeriesMap; + for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES ) + continue; + + if( !seriesStyle.m_xOldAPISeries.is() ) + seriesStyle.m_xOldAPISeries = SchXMLSeriesHelper::createOldAPISeriesPropertySet( seriesStyle.m_xSeries, xChartModel ); + + aSeriesMap[seriesStyle.m_xSeries] = seriesStyle.m_xOldAPISeries; + + } + + //initialize m_xOldAPISeries for all other styles also + for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType == DataRowPointStyle::DATA_SERIES ) + continue; + seriesStyle.m_xOldAPISeries = aSeriesMap[seriesStyle.m_xSeries]; + } +} + +//static +void SchXMLSeries2Context::setDefaultsToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles ) +{ + // iterate over series + // call initSeriesPropertySets first + + for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES ) + continue; + + try + { + uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries ); + if( !xSeries.is() ) + continue; + + if( rSeriesDefaultsAndStyles.maSymbolTypeDefault.hasValue() ) + xSeries->setPropertyValue("SymbolType",rSeriesDefaultsAndStyles.maSymbolTypeDefault); + if( rSeriesDefaultsAndStyles.maDataCaptionDefault.hasValue() ) + xSeries->setPropertyValue("DataCaption",rSeriesDefaultsAndStyles.maDataCaptionDefault); + + if( rSeriesDefaultsAndStyles.maErrorIndicatorDefault.hasValue() ) + xSeries->setPropertyValue("ErrorIndicator",rSeriesDefaultsAndStyles.maErrorIndicatorDefault); + if( rSeriesDefaultsAndStyles.maErrorCategoryDefault.hasValue() ) + xSeries->setPropertyValue("ErrorCategory",rSeriesDefaultsAndStyles.maErrorCategoryDefault); + if( rSeriesDefaultsAndStyles.maConstantErrorLowDefault.hasValue() ) + xSeries->setPropertyValue("ConstantErrorLow",rSeriesDefaultsAndStyles.maConstantErrorLowDefault); + if( rSeriesDefaultsAndStyles.maConstantErrorHighDefault.hasValue() ) + xSeries->setPropertyValue("ConstantErrorHigh",rSeriesDefaultsAndStyles.maConstantErrorHighDefault); + if( rSeriesDefaultsAndStyles.maPercentageErrorDefault.hasValue() ) + xSeries->setPropertyValue("PercentageError",rSeriesDefaultsAndStyles.maPercentageErrorDefault); + if( rSeriesDefaultsAndStyles.maErrorMarginDefault.hasValue() ) + xSeries->setPropertyValue("ErrorMargin",rSeriesDefaultsAndStyles.maErrorMarginDefault); + + if( rSeriesDefaultsAndStyles.maMeanValueDefault.hasValue() ) + xSeries->setPropertyValue("MeanValue",rSeriesDefaultsAndStyles.maMeanValueDefault); + if( rSeriesDefaultsAndStyles.maRegressionCurvesDefault.hasValue() ) + xSeries->setPropertyValue("RegressionCurves",rSeriesDefaultsAndStyles.maRegressionCurvesDefault); + } + catch( uno::Exception & ) + { + //end of series reached + } + } +} + +// ODF has the line and fill properties in a element, which is referenced by the +// element. But LibreOffice has them as special label properties of the series +// or point respectively. The following array maps the API name of the ODF property to the name of +// the internal property. Those are of kind "LabelFoo". +// The array is used in methods setStylesToSeries and setStylesToDataPoints. +const std::pair aApiToLabelFooPairs[] + = { { "LineStyle", "LabelBorderStyle" }, + { "LineWidth", "LabelBorderWidth" }, + { "LineColor", "LabelBorderColor" }, + // The name "LabelBorderDash" is defined, but the associated API name "LineDash" belongs to + // the element and is not used directly as line property. + //{"LineDash", "LabelBorderDash"}, + { "LineDashName", "LabelBorderDashName" }, + { "LineTransparence", "LabelBorderTransparency" }, + { "FillStyle", "LabelFillStyle" }, + { "FillBackground", "LabelFillBackground" }, + { "FillHatchName", "LabelFillHatchName" }, + { "FillColor", "LabelFillColor" } }; + + +//static +void SchXMLSeries2Context::setStylesToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName + , const SchXMLImportHelper& rImportHelper + , const SvXMLImport& rImport + , bool bIsStockChart + , tSchXMLLSequencesPerIndex & rInOutLSequencesPerIndex ) +{ + // iterate over series + for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if (seriesStyle.meType != DataRowPointStyle::DATA_SERIES) + continue; + try + { + uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries ); + if( !xSeriesProp.is() ) + continue; + + if( seriesStyle.mnAttachedAxis != 1 ) + { + xSeriesProp->setPropertyValue("Axis" + , uno::Any(chart::ChartAxisAssign::SECONDARY_Y) ); + } + + if( seriesStyle.msStyleName.isEmpty()) + continue; + + if( rCurrStyleName != seriesStyle.msStyleName ) + { + rCurrStyleName = seriesStyle.msStyleName; + rpStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName ); + } + + //set style to series + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext * pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( rpStyle )); + + if (!pPropStyleContext) + continue; + + // error bar style must be set before the other error + // bar properties (which may be alphabetically before + // this property) + bool bHasErrorBarRangesFromData = false; + { + static const OUStringLiteral aErrorBarStylePropName( u"ErrorBarStyle"); + uno::Any aErrorBarStyle( + SchXMLTools::getPropertyFromContext( aErrorBarStylePropName, pPropStyleContext, pStylesCtxt )); + if( aErrorBarStyle.hasValue()) + { + xSeriesProp->setPropertyValue( aErrorBarStylePropName, aErrorBarStyle ); + sal_Int32 eEBStyle = chart::ErrorBarStyle::NONE; + bHasErrorBarRangesFromData = + ( ( aErrorBarStyle >>= eEBStyle ) && + eEBStyle == chart::ErrorBarStyle::FROM_DATA ); + } + } + + //don't set the style to the min max line series of a stock chart + //otherwise the min max line properties gets overwritten and the series becomes invisible typically + if (bIsStockChart) + { + if (SchXMLSeriesHelper::isCandleStickSeries( + seriesStyle.m_xSeries, + rImportHelper.GetChartDocument())) + continue; + } + + // Has the series a data-label child element? + auto pItLabel + = std::find_if(rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(), + rSeriesDefaultsAndStyles.maSeriesStyleVector.end(), + [&seriesStyle](const DataRowPointStyle& rStyle) { + return rStyle.meType == DataRowPointStyle::DATA_LABEL_SERIES + && rStyle.msStyleNameOfParent == seriesStyle.msStyleName; + }); + if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end()) + { + // Bring the information from the data-label to the series + const SvXMLStyleContext* pLabelStyleContext(pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName)); + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext* pLabelPropStyleContext = const_cast( + dynamic_cast(pLabelStyleContext)); + if (pLabelPropStyleContext) + { + // Test each to be mapped property whether the data-label has a value for it. + // If found, set it at series. + uno::Reference xSeriesPropInfo( + xSeriesProp->getPropertySetInfo()); + for (const auto& rPropPair : aApiToLabelFooPairs) + { + uno::Any aPropValue(SchXMLTools::getPropertyFromContext( + rPropPair.first, pLabelPropStyleContext, pStylesCtxt)); + if (aPropValue.hasValue() + && xSeriesPropInfo->hasPropertyByName(rPropPair.second)) + xSeriesProp->setPropertyValue(rPropPair.second, aPropValue); + } + } + } + + pPropStyleContext->FillPropertySet( xSeriesProp ); + if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile ) + lcl_setSymbolSizeIfNeeded( xSeriesProp, rImport ); + if( bHasErrorBarRangesFromData ) + lcl_insertErrorBarLSequencesToMap( rInOutLSequencesPerIndex, xSeriesProp ); + + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" ); + } + } +} + +// static +void SchXMLSeries2Context::setStylesToRegressionCurves( + SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles, + const SvXMLStylesContext* pStylesCtxt, + const SvXMLStyleContext*& rpStyle, + OUString const & rCurrentStyleName ) +{ + // iterate over regression etc + for (auto const& regressionStyle : rSeriesDefaultsAndStyles.maRegressionStyleVector) + { + try + { + OUString aServiceName; + XMLPropStyleContext* pPropStyleContext = nullptr; + + if (!rCurrentStyleName.isEmpty()) + { + XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, rCurrentStyleName); + if( pCurrent ) + { + pPropStyleContext = pCurrent; + uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt); + if ( aAny.hasValue() ) + { + aAny >>= aServiceName; + } + } + } + + if (!regressionStyle.msStyleName.isEmpty()) + { + XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, regressionStyle.msStyleName); + if( pCurrent ) + { + pPropStyleContext = pCurrent; + uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt); + if ( aAny.hasValue() ) + { + aAny >>= aServiceName; + } + } + } + + if( !aServiceName.isEmpty() ) + { + Reference< lang::XMultiServiceFactory > xMSF = comphelper::getProcessServiceFactory(); + Reference< chart2::XRegressionCurve > xRegCurve( xMSF->createInstance( aServiceName ), uno::UNO_QUERY_THROW ); + Reference< chart2::XRegressionCurveContainer > xRegCurveCont( regressionStyle.m_xSeries, uno::UNO_QUERY_THROW ); + + Reference< beans::XPropertySet > xCurveProperties( xRegCurve, uno::UNO_QUERY ); + if( pPropStyleContext != nullptr) + pPropStyleContext->FillPropertySet( xCurveProperties ); + + xRegCurve->setEquationProperties( regressionStyle.m_xEquationProperties ); + + xRegCurveCont->addRegressionCurve( xRegCurve ); + } + } + catch( const uno::Exception& ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" ); + } + + } +} + +// static +void SchXMLSeries2Context::setStylesToStatisticsObjects( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName ) +{ + // iterate over regression etc + for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR || + seriesStyle.meType == DataRowPointStyle::MEAN_VALUE ) + { + if ( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR ) + { + uno::Reference< beans::XPropertySet > xNewSeriesProp(seriesStyle.m_xSeries,uno::UNO_QUERY); + + if (seriesStyle.m_xErrorXProperties.is()) + xNewSeriesProp->setPropertyValue("ErrorBarX",uno::Any(seriesStyle.m_xErrorXProperties)); + + if (seriesStyle.m_xErrorYProperties.is()) + xNewSeriesProp->setPropertyValue("ErrorBarY",uno::Any(seriesStyle.m_xErrorYProperties)); + } + + try + { + uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries ); + if( !xSeriesProp.is() ) + continue; + + if( !seriesStyle.msStyleName.isEmpty()) + { + if( rCurrStyleName != seriesStyle.msStyleName ) + { + rCurrStyleName = seriesStyle.msStyleName; + rpStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName ); + } + + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext * pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( rpStyle )); + if( pPropStyleContext ) + { + Reference< beans::XPropertySet > xStatPropSet; + switch( seriesStyle.meType ) + { + case DataRowPointStyle::MEAN_VALUE: + xSeriesProp->getPropertyValue("DataMeanValueProperties") >>= xStatPropSet; + break; + case DataRowPointStyle::ERROR_INDICATOR: + xSeriesProp->getPropertyValue("DataErrorProperties") >>= xStatPropSet; + break; + default: + break; + } + if( xStatPropSet.is()) + pPropStyleContext->FillPropertySet( xStatPropSet ); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" ); + } + } + } +} + +//static +void SchXMLSeries2Context::setStylesToDataPoints( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName + , const SchXMLImportHelper& rImportHelper + , const SvXMLImport& rImport + , bool bIsStockChart, bool bIsDonutChart, bool bSwitchOffLinesForScatter ) +{ + for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector) + { + if( seriesStyle.meType != DataRowPointStyle::DATA_POINT ) + continue; + + if( seriesStyle.m_nPointIndex == -1 ) + continue; + + uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries ); + if(!xSeriesProp.is()) + continue; + + //ignore datapoint properties for stock charts + //... todo ... + if( bIsStockChart ) + { + if( SchXMLSeriesHelper::isCandleStickSeries( seriesStyle.m_xSeries, rImportHelper.GetChartDocument() ) ) + continue; + } + + // data point style + for( sal_Int32 i = 0; i < seriesStyle.m_nPointRepeat; i++ ) + { + try + { + uno::Reference< beans::XPropertySet > xPointProp( + SchXMLSeriesHelper::createOldAPIDataPointPropertySet( seriesStyle.m_xSeries, seriesStyle.m_nPointIndex + i + , rImportHelper.GetChartDocument() ) ); + + if( !xPointProp.is() ) + continue; + + if( bIsDonutChart ) + { + //set special series styles for donut charts first + if( rCurrStyleName != seriesStyle.msSeriesStyleNameForDonuts ) + { + rCurrStyleName = seriesStyle.msSeriesStyleNameForDonuts; + rpStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName ); + } + + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext * pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( rpStyle )); + if( pPropStyleContext ) + pPropStyleContext->FillPropertySet( xPointProp ); + } + + try + { + //need to set this explicitly here for old files as the new api does not support this property fully anymore + if( bSwitchOffLinesForScatter ) + xPointProp->setPropertyValue("Lines",uno::Any(false)); + } + catch( const uno::Exception & ) + { + } + + if( rCurrStyleName != seriesStyle.msStyleName ) + { + rCurrStyleName = seriesStyle.msStyleName; + rpStyle = pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName ); + } + + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext * pPropStyleContext = + const_cast< XMLPropStyleContext * >( + dynamic_cast< const XMLPropStyleContext * >( rpStyle )); + if (pPropStyleContext) + { + // Has the point a data-label child element? + auto pItLabel = std::find_if( + rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(), + rSeriesDefaultsAndStyles.maSeriesStyleVector.end(), + [&seriesStyle](const DataRowPointStyle& rStyle) { + return rStyle.meType == DataRowPointStyle::DATA_LABEL_POINT + && rStyle.msStyleNameOfParent == seriesStyle.msStyleName; + }); + if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end()) + { + // Bring the information from the data-label to the point + const SvXMLStyleContext* pLabelStyleContext( + pStylesCtxt->FindStyleChildContext( + SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName)); + // note: SvXMLStyleContext::FillPropertySet is not const + XMLPropStyleContext* pLabelPropStyleContext + = const_cast( + dynamic_cast(pLabelStyleContext)); + if (pLabelPropStyleContext) + { + // Test each to be mapped property whether the data-label has a value for it. + // If found, set it at the point. + uno::Reference xPointPropInfo( + xPointProp->getPropertySetInfo()); + for (const auto& rPropPair : aApiToLabelFooPairs) + { + uno::Any aPropValue(SchXMLTools::getPropertyFromContext( + rPropPair.first, pLabelPropStyleContext, pStylesCtxt)); + if (aPropValue.hasValue() + && xPointPropInfo->hasPropertyByName(rPropPair.second)) + xPointProp->setPropertyValue(rPropPair.second, aPropValue); + } + } + } + + pPropStyleContext->FillPropertySet( xPointProp ); + if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile ) + lcl_resetSymbolSizeForPointsIfNecessary( xPointProp, rImport, pPropStyleContext, pStylesCtxt ); + if( !pPropStyleContext->isEmptyDataStyleName() ) + lcl_setLinkNumberFormatToSourceIfNeeded( xPointProp, pPropStyleContext, pStylesCtxt ); + } + + // Custom labels might be passed as property + if(const size_t nLabelCount = seriesStyle.mCustomLabels.mLabels.size(); nLabelCount > 0) + { + auto& rCustomLabels = seriesStyle.mCustomLabels; + + Sequence< Reference> xLabels(nLabelCount); + auto pxLabels = xLabels.getArray(); + Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); + for( size_t j = 0; j < nLabelCount; ++j ) + { + Reference< chart2::XDataPointCustomLabelField > xCustomLabel = chart2::DataPointCustomLabelField::create(xContext); + pxLabels[j] = xCustomLabel; + xCustomLabel->setString(rCustomLabels.mLabels[j]); + if ( j == 0 && rCustomLabels.mbDataLabelsRange) + { + xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLRANGE); + xCustomLabel->setGuid(rCustomLabels.msLabelGuid); + xCustomLabel->setCellRange(rCustomLabels.msLabelsCellRange); + xCustomLabel->setDataLabelsRange(true); + } + else + { + xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT); + } + + // Restore character properties on the text span manually, till + // SchXMLExportHelper_Impl::exportCustomLabel() does not write the style. + uno::Reference xPointPropInfo + = xPointProp->getPropertySetInfo(); + if (xPointPropInfo.is()) + { + uno::Sequence aProperties = xPointPropInfo->getProperties(); + for (const auto& rProperty : std::as_const(aProperties)) + { + if (!rProperty.Name.startsWith("Char") + || rProperty.Name.startsWith("Chart")) + { + continue; + } + + xCustomLabel->setPropertyValue( + rProperty.Name, xPointProp->getPropertyValue(rProperty.Name)); + } + } + } + + xPointProp->setPropertyValue("CustomLabelFields", uno::Any(xLabels)); + xPointProp->setPropertyValue("DataCaption", uno::Any(chart::ChartDataCaption::CUSTOM)); + } + + if( seriesStyle.mCustomLabelPos[0] != 0.0 || seriesStyle.mCustomLabelPos[1] != 0.0 ) + { + chart2::RelativePosition aCustomlabelPosition; + aCustomlabelPosition.Primary = seriesStyle.mCustomLabelPos[0]; + aCustomlabelPosition.Secondary = seriesStyle.mCustomLabelPos[1]; + xPointProp->setPropertyValue("CustomLabelPosition", uno::Any(aCustomlabelPosition)); + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to data points" ); + } + } + } // styles iterator +} + +//static +void SchXMLSeries2Context::switchSeriesLinesOff( ::std::vector< DataRowPointStyle >& rSeriesStyleVector ) +{ + // iterate over series + for (auto const& seriesStyle : rSeriesStyleVector) + { + if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES ) + continue; + + try + { + uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries ); + if( !xSeries.is() ) + continue; + + xSeries->setPropertyValue("Lines",uno::Any(false)); + } + catch( uno::Exception & ) + { + //end of series reached + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLSeries2Context.hxx b/xmloff/source/chart/SchXMLSeries2Context.hxx new file mode 100644 index 000000000..4996ecf8b --- /dev/null +++ b/xmloff/source/chart/SchXMLSeries2Context.hxx @@ -0,0 +1,133 @@ +/* -*- 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 "transporttypes.hxx" +#include "SchXMLChartContext.hxx" +#include +#include +#include + +#include + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + class XDataSeries; + } + namespace awt { + struct Size; + } +} + +// class for child contexts: series, data point and statistics objects +class SchXMLSeries2Context : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + css::uno::Reference< css::chart2::XChartDocument > mxNewDoc; + ::std::vector< SchXMLAxis >& mrAxes; + ::std::vector< DataRowPointStyle >& mrStyleVector; + ::std::vector< RegressionStyle >& mrRegressionStyleVector; + css::uno::Reference< css::chart2::XDataSeries > m_xSeries; + sal_Int32 mnSeriesIndex; + sal_Int32 mnDataPointIndex; + bool m_bStockHasVolume; + + GlobalSeriesImportInfo& m_rGlobalSeriesImportInfo; + + SchXMLAxis* mpAttachedAxis; + sal_Int32 mnAttachedAxis; + OUString msAutoStyleName; + ::std::vector< OUString > maDomainAddresses; + OUString maGlobalChartTypeName; + OUString maSeriesChartTypeName; + OUString m_aSeriesRange; + bool m_bHasDomainContext; + tSchXMLLSequencesPerIndex & mrLSequencesPerIndex; + tSchXMLLSequencesPerIndex maPostponedSequences; + bool& mrGlobalChartTypeUsedBySeries; + bool mbSymbolSizeIsMissingInFile; + css::awt::Size maChartSize; + // We let the series manage the DataRowPointStyle-struct of its data label + DataRowPointStyle mDataLabel; + +public: + SchXMLSeries2Context( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + const css::uno::Reference< css::chart2::XChartDocument > & xNewDoc, + std::vector< SchXMLAxis >& rAxes, + ::std::vector< DataRowPointStyle >& rStyleVector, + ::std::vector< RegressionStyle >& rRegressionStyleVector, + sal_Int32 nSeriesIndex, + bool bStockHasVolume, + GlobalSeriesImportInfo& rGlobalSeriesImportInfo, + const OUString & aGlobalChartTypeName, + tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + bool& rGlobalChartTypeUsedBySeries, + const css::awt::Size & rChartSize ); + virtual ~SchXMLSeries2Context() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + static void initSeriesPropertySets( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const css::uno::Reference< css::frame::XModel >& xChartModel ); + + static void setDefaultsToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles ); + + static void setStylesToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName + , const SchXMLImportHelper& rImportHelper + , const SvXMLImport& rImport + , bool bIsStockChart + , tSchXMLLSequencesPerIndex & rInOutLSequencesPerIndex ); + + static void setStylesToStatisticsObjects( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString &rCurrStyleName ); + + static void setStylesToRegressionCurves( + SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles, + const SvXMLStylesContext* pStylesCtxt, + const SvXMLStyleContext*& rpStyle, + OUString const &rCurrStyleName ); + + static void setStylesToDataPoints( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles + , const SvXMLStylesContext* pStylesCtxt + , const SvXMLStyleContext*& rpStyle + , OUString& rCurrStyleName + , const SchXMLImportHelper& rImportHelper + , const SvXMLImport& rImport + , bool bIsStockChart, bool bIsDonutChart, bool bSwitchOffLinesForScatter ); + + static void switchSeriesLinesOff( ::std::vector< DataRowPointStyle >& rSeriesStyleVector ); +}; + +// INCLUDED_XMLOFF_SOURCE_CHART_SCHXMLSERIES2CONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLSeriesHelper.cxx b/xmloff/source/chart/SchXMLSeriesHelper.cxx new file mode 100644 index 000000000..31a197596 --- /dev/null +++ b/xmloff/source/chart/SchXMLSeriesHelper.cxx @@ -0,0 +1,218 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +::std::vector< Reference< chart2::XDataSeries > > + SchXMLSeriesHelper::getDataSeriesFromDiagram( + const Reference< chart2::XDiagram > & xDiagram ) +{ + ::std::vector< Reference< chart2::XDataSeries > > aResult; + + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( + xDiagram, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( + xCooSysCnt->getCoordinateSystems()); + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XChartTypeContainer > xCTCnt( rCooSys, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XChartType > > aChartTypeSeq( xCTCnt->getChartTypes()); + for( const auto& rChartType : aChartTypeSeq ) + { + Reference< chart2::XDataSeriesContainer > xDSCnt( rChartType, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xDSCnt->getDataSeries() ); + aResult.insert( aResult.end(), aSeriesSeq.begin(), aSeriesSeq.end() ); + } + } + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + + return aResult; +} + +::std::map< Reference< chart2::XDataSeries >, sal_Int32 > SchXMLSeriesHelper::getDataSeriesIndexMapFromDiagram( + const Reference< chart2::XDiagram > & xDiagram ) +{ + ::std::map< Reference< chart2::XDataSeries >, sal_Int32 > aRet; + + sal_Int32 nIndex=0; + + ::std::vector< Reference< chart2::XDataSeries > > aSeriesVector( SchXMLSeriesHelper::getDataSeriesFromDiagram( xDiagram )); + for( const Reference< chart2::XDataSeries >& xSeries : aSeriesVector ) + { + if( xSeries.is() ) + { + if( aRet.end() == aRet.find(xSeries) ) + aRet[xSeries]=nIndex; + } + nIndex++; + } + return aRet; +} + +namespace { +uno::Reference< chart2::XChartType > lcl_getChartTypeOfSeries( + const uno::Reference< chart2::XDiagram >& xDiagram + , const Reference< chart2::XDataSeries >& xSeries ) +{ + if(!xDiagram.is()) + return nullptr; + + //iterate through the model to find the given xSeries + //the found parent indicates the charttype + + //iterate through all coordinate systems + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY ); + if( !xCooSysContainer.is()) + return nullptr; + + const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() ); + for( const auto& xCooSys : aCooSysList ) + { + //iterate through all chart types in the current coordinate system + uno::Reference< chart2::XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY ); + SAL_WARN_IF( !xChartTypeContainer.is(), "xmloff.chart", "xChartTypeContainer is NULL"); + if( !xChartTypeContainer.is() ) + continue; + const uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() ); + for( const auto& xChartType : aChartTypeList ) + { + //iterate through all series in this chart type + uno::Reference< chart2::XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY ); + SAL_WARN_IF( !xDataSeriesContainer.is(), "xmloff.chart", "xDataSeriesContainer is NULL"); + if( !xDataSeriesContainer.is() ) + continue; + + const uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() ); + if (std::find(aSeriesList.begin(), aSeriesList.end(), xSeries) != aSeriesList.end()) + return xChartType; + } + } + return nullptr; +} +} + +bool SchXMLSeriesHelper::isCandleStickSeries( + const Reference< chart2::XDataSeries >& xSeries + , const Reference< frame::XModel >& xChartModel ) +{ + bool bRet = false; + + uno::Reference< chart2::XChartDocument > xNewDoc( xChartModel, uno::UNO_QUERY ); + if( xNewDoc.is() ) + { + uno::Reference< chart2::XDiagram > xNewDiagram( xNewDoc->getFirstDiagram() ); + if( xNewDiagram.is() ) + { + uno::Reference< chart2::XChartType > xChartType( lcl_getChartTypeOfSeries( + xNewDiagram, xSeries ) ); + if( xChartType.is() ) + { + OUString aServiceName( xChartType->getChartType() ); + if( aServiceName == "com.sun.star.chart2.CandleStickChartType" ) + bRet = true; + } + } + } + return bRet; +} + +//static +uno::Reference< beans::XPropertySet > SchXMLSeriesHelper::createOldAPISeriesPropertySet( + const uno::Reference< chart2::XDataSeries >& xSeries + , const uno::Reference< frame::XModel >& xChartModel ) +{ + uno::Reference< beans::XPropertySet > xRet; + + if( xSeries.is() ) + { + try + { + uno::Reference< lang::XMultiServiceFactory > xFactory( xChartModel, uno::UNO_QUERY ); + if( xFactory.is() ) + { + xRet.set( xFactory->createInstance( "com.sun.star.comp.chart2.DataSeriesWrapper" ), uno::UNO_QUERY ); + Reference< lang::XInitialization > xInit( xRet, uno::UNO_QUERY ); + if(xInit.is()) + { + xInit->initialize( { uno::Any(xSeries) }); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught SchXMLSeriesHelper::createOldAPISeriesPropertySet" ); + } + } + + return xRet; +} + +//static +uno::Reference< beans::XPropertySet > SchXMLSeriesHelper::createOldAPIDataPointPropertySet( + const uno::Reference< chart2::XDataSeries >& xSeries + , sal_Int32 nPointIndex + , const uno::Reference< frame::XModel >& xChartModel ) +{ + uno::Reference< beans::XPropertySet > xRet; + + if( xSeries.is() ) + { + try + { + uno::Reference< lang::XMultiServiceFactory > xFactory( xChartModel, uno::UNO_QUERY ); + if( xFactory.is() ) + { + xRet.set( xFactory->createInstance( "com.sun.star.comp.chart2.DataSeriesWrapper" ), uno::UNO_QUERY ); + Reference< lang::XInitialization > xInit( xRet, uno::UNO_QUERY ); + if(xInit.is()) + { + xInit->initialize({ uno::Any(xSeries), uno::Any(nPointIndex) }); + } + } + } + catch( const uno::Exception & ) + { + TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught SchXMLSeriesHelper::createOldAPIDataPointPropertySet" ); + } + } + + return xRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTableContext.cxx b/xmloff/source/chart/SchXMLTableContext.cxx new file mode 100644 index 000000000..27ae73113 --- /dev/null +++ b/xmloff/source/chart/SchXMLTableContext.cxx @@ -0,0 +1,1048 @@ +/* -*- 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 + +#include "SchXMLTableContext.hxx" +#include "SchXMLParagraphContext.hxx" +#include "SchXMLTextListContext.hxx" +#include +#include "SchXMLTools.hxx" +#include "transporttypes.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; + +namespace +{ + +constexpr OUStringLiteral aCategoriesRange = u"categories"; + +typedef ::std::multimap< OUString, OUString > + lcl_tOriginalRangeToInternalRangeMap; + +struct lcl_ApplyCellToData +{ + explicit lcl_ApplyCellToData( Sequence< double > & rOutData ) : + m_rData( rOutData ), + m_nIndex( 0 ), + m_nSize( rOutData.getLength()) + { + } + + void operator() ( const SchXMLCell & rCell ) + { + if( m_nIndex < m_nSize ) + { + auto pData = m_rData.getArray(); + if( rCell.eType == SCH_CELL_TYPE_FLOAT ) + pData[m_nIndex] = rCell.fValue; + else + pData[m_nIndex] = std::numeric_limits::quiet_NaN(); + } + ++m_nIndex; + } + + sal_Int32 getCurrentIndex() const + { + return m_nIndex; + } + +private: + Sequence< double > & m_rData; + sal_Int32 m_nIndex; + sal_Int32 m_nSize; +}; + +void lcl_fillRangeMapping( + const SchXMLTable & rTable, + lcl_tOriginalRangeToInternalRangeMap & rOutRangeMap, + chart::ChartDataRowSource eDataRowSource ) +{ + sal_Int32 nRowOffset = ( rTable.bHasHeaderRow ? 1 : 0 ); + sal_Int32 nColOffset = ( rTable.bHasHeaderColumn ? 1 : 0 ); + + const OUString lcl_aCategoriesRange(aCategoriesRange); + static const OUStringLiteral lcl_aLabelPrefix(u"label "); + + // Fill range mapping + const size_t nTableRowCount( rTable.aData.size()); + for( size_t nRow = 0; nRow < nTableRowCount; ++nRow ) + { + const ::std::vector< SchXMLCell > & rRow( rTable.aData[nRow] ); + const size_t nTableColCount( rRow.size()); + for( size_t nCol = 0; nCol < nTableColCount; ++nCol ) + { + const OUString aRangeId( rRow[nCol].aRangeId ); + if( !aRangeId.isEmpty()) + { + if( eDataRowSource == chart::ChartDataRowSource_COLUMNS ) + { + if( nCol == 0 && rTable.bHasHeaderColumn ) + { + SAL_WARN_IF( static_cast< sal_Int32 >( nRow ) != nRowOffset, "xmloff.chart", "nRow != nRowOffset" ); + rOutRangeMap.emplace(aRangeId, lcl_aCategoriesRange); + } + else + { + OUString aColNumStr = OUString::number( nCol - nColOffset); + if( nRow == 0 && rTable.bHasHeaderRow ) + rOutRangeMap.emplace( aRangeId, lcl_aLabelPrefix + aColNumStr ); + else + rOutRangeMap.emplace( aRangeId, aColNumStr ); + } + } + else // eDataRowSource == chart::ChartDataRowSource_ROWS + { + if( nRow == 0 && rTable.bHasHeaderRow ) + { + SAL_WARN_IF( static_cast< sal_Int32 >( nCol ) != nColOffset, "xmloff.chart", "nCol != nColOffset" ); + rOutRangeMap.emplace( aRangeId, lcl_aCategoriesRange ); + } + else + { + OUString aRowNumStr = OUString::number( nRow - nRowOffset); + if( nCol == 0 && rTable.bHasHeaderColumn ) + rOutRangeMap.emplace( aRangeId, lcl_aLabelPrefix + aRowNumStr ); + else + rOutRangeMap.emplace( aRangeId, aRowNumStr ); + } + } + } + } + } +} + +Reference< chart2::data::XDataSequence > + lcl_reassignDataSequence( + const Reference< chart2::data::XDataSequence > & xSequence, + const Reference< chart2::data::XDataProvider > & xDataProvider, + lcl_tOriginalRangeToInternalRangeMap & rRangeMap, + const OUString & rRange ) +{ + Reference< chart2::data::XDataSequence > xResult( xSequence ); + lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange )); + if( aIt != rRangeMap.end()) + { + // set sequence with correct data + xResult.set( xDataProvider->createDataSequenceByRangeRepresentation( aIt->second )); + // remove translation, because it was used + rRangeMap.erase( aIt ); + } + + return xResult; +} + +bool lcl_mapContainsRange( + lcl_tOriginalRangeToInternalRangeMap & rRangeMap, + const OUString & rRange ) +{ + lcl_tOriginalRangeToInternalRangeMap::iterator aIt( rRangeMap.find( rRange )); + return ( aIt != rRangeMap.end()); +} + +bool lcl_tableOfRangeMatches( + std::u16string_view rRange, + std::u16string_view rTableName ) +{ + // both strings are non-empty and the table name is part of the range + return ( !rRange.empty() && + !rTableName.empty() && + (rRange.find( rTableName ) != std::u16string_view::npos )); +} + +} // anonymous namespace + +// class SchXMLTableContext +SchXMLTableContext::SchXMLTableContext( SvXMLImport& rImport, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport ), + mrTable( aTable ), + mbHasRowPermutation( false ), + mbHasColumnPermutation( false ) +{ + mrTable.nColumnIndex = -1; + mrTable.nMaxColumnIndex = -1; + mrTable.nRowIndex = -1; + mrTable.aData.clear(); +} + +SchXMLTableContext::~SchXMLTableContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLTableContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + switch(nElement) + { + case XML_ELEMENT(TABLE, XML_TABLE_HEADER_COLUMNS): + mrTable.bHasHeaderColumn = true; + [[fallthrough]]; + case XML_ELEMENT(TABLE, XML_TABLE_COLUMNS): + pContext = new SchXMLTableColumnsContext( GetImport(), mrTable ); + break; + + case XML_ELEMENT(TABLE, XML_TABLE_COLUMN): + pContext = new SchXMLTableColumnContext( GetImport(), mrTable ); + break; + + case XML_ELEMENT(TABLE, XML_TABLE_HEADER_ROWS): + mrTable.bHasHeaderRow = true; + [[fallthrough]]; + case XML_ELEMENT(TABLE, XML_TABLE_ROWS): + pContext = new SchXMLTableRowsContext( GetImport(), mrTable ); + break; + + case XML_ELEMENT(TABLE, XML_TABLE_ROW): + pContext = new SchXMLTableRowContext( GetImport(), mrTable ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return pContext; +} + +void SchXMLTableContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // get table-name + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TABLE, XML_NAME): + mrTable.aTableNameOfFile = aIter.toString(); + break; + case XML_ELEMENT(TABLE, XML_PROTECTED): + if ( IsXMLToken( aIter, XML_TRUE ) ) + { + mrTable.bProtected = true; + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +void SchXMLTableContext::endFastElement(sal_Int32 ) +{ + if( mbHasColumnPermutation ) + { + SAL_WARN_IF( mbHasRowPermutation, "xmloff.chart", "mbHasColumnPermutation is true" ); + const auto & aPermutation( maColumnPermutation ); + SAL_WARN_IF( !aPermutation.hasElements(), "xmloff.chart", "aPermutation is NULL"); + if( !aPermutation.hasElements()) + return; + + // permute the values of all rows according to aPermutation + for( auto& rRow : mrTable.aData ) + { + bool bModified = false; + ::std::vector< SchXMLCell > aModifiedRow; + const size_t nPermSize = aPermutation.size(); + SAL_WARN_IF( static_cast< sal_Int32 >( nPermSize ) - 1 != *(::std::max_element( aPermutation.begin(), aPermutation.end())), "xmloff.chart", "nPermSize - 1 != *(::std::max_element( aPermutation.begin(), aPermutation.end())"); + const size_t nRowSize = rRow.size(); + const size_t nDestSize = ::std::min( nPermSize, nRowSize ); + for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex ) + { + const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] ); + if( nSourceIndex != nDestinationIndex && + nSourceIndex < nRowSize ) + { + // copy original on first real permutation + if( !bModified ) + { + SAL_WARN_IF( !aModifiedRow.empty(), "xmloff.chart", "aModifiedRow is NOT NULL"); + aModifiedRow.insert( aModifiedRow.end(), rRow.begin(), rRow.end() ); + SAL_WARN_IF( aModifiedRow.empty(), "xmloff.chart", "aModifiedRow is NULL"); + } + SAL_WARN_IF( nDestinationIndex >= aModifiedRow.size(), "xmloff.chart", "nDestinationIndex >= aModifiedRow.size()"); + aModifiedRow[ nDestinationIndex ] = rRow[ nSourceIndex ]; + bModified = true; + } + } + // copy back + if( bModified ) + ::std::copy( aModifiedRow.begin(), aModifiedRow.end(), rRow.begin()); + } + } + else if( mbHasRowPermutation ) + { + const auto & aPermutation( maRowPermutation ); + SAL_WARN_IF( !aPermutation.hasElements(), "xmloff.chart", "aPermutation is NULL"); + if( !aPermutation.hasElements()) + return; + + bool bModified = false; + const size_t nPermSize = aPermutation.size(); + SAL_WARN_IF( static_cast< sal_Int32 >( nPermSize ) - 1 != *(::std::max_element( aPermutation.begin(), aPermutation.end())), "xmloff.chart", "nPermSize - 1 != *(::std::max_element( aPermutation.begin(), aPermutation.end())"); + const size_t nTableRowCount = mrTable.aData.size(); + const size_t nDestSize = ::std::min( nPermSize, nTableRowCount ); + ::std::vector< ::std::vector< SchXMLCell > > aDestination; + for( size_t nDestinationIndex = 0; nDestinationIndex < nDestSize; ++nDestinationIndex ) + { + const size_t nSourceIndex = static_cast< size_t >( aPermutation[ nDestinationIndex ] ); + if( nSourceIndex != nDestinationIndex && + nSourceIndex < nTableRowCount ) + { + // copy original on first real permutation + if( !bModified ) + { + SAL_WARN_IF( !aDestination.empty(), "xmloff.chart", "aDestination is NOT NULL"); + aDestination.insert( aDestination.end(), mrTable.aData.begin(), mrTable.aData.end()); + SAL_WARN_IF( aDestination.empty(), "xmloff.chart", "aDestination is NULL"); + } + SAL_WARN_IF( nDestinationIndex >= aDestination.size(), "xmloff.chart", "nDestinationIndex >= aDestination.size()"); + aDestination[ nDestinationIndex ] = mrTable.aData[ nSourceIndex ]; + bModified = true; + } + } + if( bModified ) + { + // copy back + ::std::copy( aDestination.begin(), aDestination.end(), mrTable.aData.begin()); + } + } +} + +void SchXMLTableContext::setRowPermutation( const uno::Sequence< sal_Int32 > & rPermutation ) +{ + maRowPermutation = rPermutation; + mbHasRowPermutation = rPermutation.hasElements(); + + if( mbHasRowPermutation && mbHasColumnPermutation ) + { + mbHasColumnPermutation = false; + maColumnPermutation.realloc( 0 ); + } +} + +void SchXMLTableContext::setColumnPermutation( const uno::Sequence< sal_Int32 > & rPermutation ) +{ + maColumnPermutation = rPermutation; + mbHasColumnPermutation = rPermutation.hasElements(); + + if( mbHasColumnPermutation && mbHasRowPermutation ) + { + mbHasRowPermutation = false; + maRowPermutation.realloc( 0 ); + } +} + +// classes for columns +// class SchXMLTableColumnsContext +SchXMLTableColumnsContext::SchXMLTableColumnsContext( + SvXMLImport& rImport, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport ), + mrTable( aTable ) +{ +} + +SchXMLTableColumnsContext::~SchXMLTableColumnsContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLTableColumnsContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + if( nElement == XML_ELEMENT(TABLE, XML_TABLE_COLUMN) ) + pContext = new SchXMLTableColumnContext( GetImport(), mrTable ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return pContext; +} + +// class SchXMLTableColumnContext +SchXMLTableColumnContext::SchXMLTableColumnContext( + SvXMLImport& rImport, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport ), + mrTable( aTable ) +{ +} + +void SchXMLTableColumnContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // get number-columns-repeated attribute + sal_Int32 nRepeated = 1; + bool bHidden = false; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED): + { + if( !aIter.isEmpty()) + nRepeated = aIter.toInt32(); + break; + } + case XML_ELEMENT(TABLE, XML_VISIBILITY): + { + OUString aVisibility = aIter.toString(); + bHidden = aVisibility == GetXMLToken( XML_COLLAPSE ); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + sal_Int32 nOldCount = mrTable.nNumberOfColsEstimate; + sal_Int32 nNewCount = nOldCount + nRepeated; + mrTable.nNumberOfColsEstimate = nNewCount; + + if( bHidden ) + { + //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste ) + sal_Int32 nColOffset = ( mrTable.bHasHeaderColumn ? 1 : 0 ); + for( sal_Int32 nN = nOldCount; nN=0 ) + mrTable.aHiddenColumns.push_back(nHiddenColumnIndex); + } + } +} + +SchXMLTableColumnContext::~SchXMLTableColumnContext() +{ +} + +// classes for rows +// class SchXMLTableRowsContext +SchXMLTableRowsContext::SchXMLTableRowsContext( + SvXMLImport& rImport, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport ), + mrTable( aTable ) +{ +} + +SchXMLTableRowsContext::~SchXMLTableRowsContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLTableRowsContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + if( nElement == XML_ELEMENT(TABLE, XML_TABLE_ROW) ) + pContext = new SchXMLTableRowContext( GetImport(), mrTable ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return pContext; +} + +// class SchXMLTableRowContext +SchXMLTableRowContext::SchXMLTableRowContext( + SvXMLImport& rImport, + SchXMLTable& aTable ) : + SvXMLImportContext( rImport ), + mrTable( aTable ) +{ + mrTable.nColumnIndex = -1; + mrTable.nRowIndex++; + + std::vector< SchXMLCell > aNewRow; + aNewRow.reserve( mrTable.nNumberOfColsEstimate ); + while( mrTable.aData.size() <= o3tl::make_unsigned(mrTable.nRowIndex) ) + mrTable.aData.push_back( aNewRow ); +} + +SchXMLTableRowContext::~SchXMLTableRowContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLTableRowContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + // element + if( nElement == XML_ELEMENT(TABLE, XML_TABLE_CELL) ) + { + pContext = new SchXMLTableCellContext( GetImport(), mrTable ); + } + else + { + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + assert(false); + } + + return pContext; +} + +namespace { + +class SchXMLRangeSomewhereContext : public SvXMLImportContext +{ +//#i113950# previously the range was exported to attribute text:id, +//but that attribute does not allow arbitrary strings anymore +//so we need to find an alternative to save that range info for copy/paste scenario ... +//-> use description at an empty group element for now + +private: + OUString& mrRangeString; + OUStringBuffer maRangeStringBuffer; + +public: + SchXMLRangeSomewhereContext( SvXMLImport& rImport, + OUString& rRangeString ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +} + +// classes for cells and their content +// class SchXMLTableCellContext +SchXMLTableCellContext::SchXMLTableCellContext( + SvXMLImport& rImport, + SchXMLTable& aTable) + : SvXMLImportContext(rImport) + , mrTable(aTable) + , mbReadText(false) +{ +} + +SchXMLTableCellContext::~SchXMLTableCellContext() +{ +} + +void SchXMLTableCellContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + OUString aCellContent; + SchXMLCellType eValueType = SCH_CELL_TYPE_UNKNOWN; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(OFFICE, XML_VALUE_TYPE): + if( IsXMLToken( aIter, XML_FLOAT ) ) + eValueType = SCH_CELL_TYPE_FLOAT; + else if( IsXMLToken( aIter, XML_STRING ) ) + eValueType = SCH_CELL_TYPE_STRING; + break; + + case XML_ELEMENT(OFFICE, XML_VALUE): + aCellContent = aIter.toString(); + break; + + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + mbReadText = true; + SchXMLCell aCell; + aCell.eType = eValueType; + + if( eValueType == SCH_CELL_TYPE_FLOAT ) + { + double fData; + // the result may be false if a NaN is read, but that's ok + ::sax::Converter::convertDouble( fData, aCellContent ); + + aCell.fValue = fData; + // don't read text from following or element + mbReadText = false; + } + + mrTable.aData[ mrTable.nRowIndex ].push_back( aCell ); + mrTable.nColumnIndex++; + if( mrTable.nMaxColumnIndex < mrTable.nColumnIndex ) + mrTable.nMaxColumnIndex = mrTable.nColumnIndex; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLTableCellContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + // element + if( nElement == XML_ELEMENT(TEXT, XML_LIST ) && mbReadText ) + { + SchXMLCell& rCell = mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ]; + rCell.aComplexString = Sequence< OUString >(); + rCell.eType = SCH_CELL_TYPE_COMPLEX_STRING; + pContext = new SchXMLTextListContext( GetImport(), rCell.aComplexString ); + mbReadText = false;//don't apply text from + } + // element - read text (and range from text:id old version) + else if( nElement == XML_ELEMENT(TEXT, XML_P) || + nElement == XML_ELEMENT(LO_EXT, XML_P) ) + { + pContext = new SchXMLParagraphContext( GetImport(), maCellContent, &maRangeId ); + } + // element - read range + else if( nElement == XML_ELEMENT(DRAW, XML_G) ) + { + //#i113950# previously the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore + //so we need to find an alternative to save that range info for copy/paste scenario ... -> use description at an empty group element for now + pContext = new SchXMLRangeSomewhereContext( GetImport(), maRangeId ); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return pContext; +} + +void SchXMLTableCellContext::endFastElement(sal_Int32 ) +{ + if( mbReadText && !maCellContent.isEmpty() ) //apply text from element + mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aString = maCellContent; + if( !maRangeId.isEmpty()) + mrTable.aData[ mrTable.nRowIndex ][ mrTable.nColumnIndex ].aRangeId = maRangeId; +} + +static void lcl_ApplyCellToComplexLabel( const SchXMLCell& rCell, Sequence< uno::Any >& rComplexLabel ) +{ + if( rCell.eType == SCH_CELL_TYPE_STRING ) + { + rComplexLabel = { uno::Any(rCell.aString) }; + } + else if( rCell.aComplexString.hasElements() && rCell.eType == SCH_CELL_TYPE_COMPLEX_STRING ) + { + sal_Int32 nCount = rCell.aComplexString.getLength(); + rComplexLabel.realloc( nCount ); + auto pComplexLabel = rComplexLabel.getArray(); + for( sal_Int32 nN=0; nN& xChartDoc ) +{ + // apply all data read from the local table to the internal data provider + if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() ) + return; + Reference< chart2::data::XDataProvider > xDataProv( xChartDoc->getDataProvider() ); + if( !xDataProv.is() ) + return; + + //prepare the read local table data + sal_Int32 nNumRows( static_cast< sal_Int32 >( rTable.aData.size())); + sal_Int32 nRowOffset = 0; + if( rTable.bHasHeaderRow ) + { + --nNumRows; + nRowOffset = 1; + } + sal_Int32 nNumColumns( rTable.nMaxColumnIndex + 1 ); + sal_Int32 nColOffset = 0; + if( rTable.bHasHeaderColumn ) + { + --nNumColumns; + nColOffset = 1; + } + + Sequence< Sequence< double > > aDataInRows( nNumRows ); + auto aDataInRowsRange = asNonConstRange(aDataInRows); + Sequence< Sequence< uno::Any > > aComplexRowDescriptions( nNumRows ); + auto aComplexRowDescriptionsRange = asNonConstRange(aComplexRowDescriptions); + Sequence< Sequence< uno::Any > > aComplexColumnDescriptions( nNumColumns ); + auto aComplexColumnDescriptionsRange = asNonConstRange(aComplexColumnDescriptions); + for( sal_Int32 i=0; i& rFirstRow = rTable.aData.front(); + const sal_Int32 nColumnLabelsSize = aComplexColumnDescriptions.getLength(); + const sal_Int32 nMax = ::std::min< sal_Int32 >( nColumnLabelsSize, static_cast< sal_Int32 >( rFirstRow.size()) - nColOffset ); + SAL_WARN_IF( nMax != nColumnLabelsSize, "xmloff.chart", "nMax != nColumnLabelsSize"); + for( sal_Int32 i=0; i >::const_iterator aRowIter( rTable.aData.begin() + nRowOffset ); + std::vector< ::std::vector< SchXMLCell > >::const_iterator aEnd( rTable.aData.end() ); + for( sal_Int32 nRow = 0; aRowIter != aEnd && nRow < nNumRows; ++aRowIter, ++nRow ) + { + const ::std::vector< SchXMLCell >& rRow = *aRowIter; + if( !rRow.empty() ) + { + // row label + if( rTable.bHasHeaderColumn ) + lcl_ApplyCellToComplexLabel( rRow.front(), aComplexRowDescriptionsRange[nRow] ); + + // values + Sequence< double >& rTargetRow = aDataInRowsRange[nRow]; + auto pTargetRow = rTargetRow.getArray(); + lcl_ApplyCellToData aApplyCellToData = ::std::for_each( rRow.begin() + nColOffset, rRow.end(), lcl_ApplyCellToData( rTargetRow ) ); + for( sal_Int32 nCurrentIndex = aApplyCellToData.getCurrentIndex(); nCurrentIndex::quiet_NaN();//#i110615# + } + } + } + + //apply the collected data to the chart + Reference< chart2::XAnyDescriptionAccess > xDataAccess( xDataProv, uno::UNO_QUERY ); + if( !xDataAccess.is() ) + return; + + xDataAccess->setData( aDataInRows ); + if( rTable.bHasHeaderColumn ) + xDataAccess->setAnyRowDescriptions( aComplexRowDescriptions ); + if( rTable.bHasHeaderRow ) + xDataAccess->setAnyColumnDescriptions( aComplexColumnDescriptions ); + + if ( rTable.bProtected ) + { + try + { + Reference< beans::XPropertySet > xProps( xChartDoc, uno::UNO_QUERY_THROW ); + xProps->setPropertyValue( "DisableDataTableDialog", uno::Any( true ) ); + xProps->setPropertyValue( "DisableComplexChartTypes", uno::Any( true ) ); + } + catch ( uno::Exception& ) + { + } + } +} + +void SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( + const SchXMLTable& rTable, + const tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + const uno::Reference< chart2::XChartDocument >& xChartDoc, + chart::ChartDataRowSource eDataRowSource ) +{ + if( ! (xChartDoc.is() && xChartDoc->hasInternalDataProvider())) + return; + + // If the range-strings are valid (starting with "local-table") they should + // be interpreted like given, otherwise (when the ranges refer to Calc- or + // Writer-ranges, but the container is not available like when pasting a + // chart from Calc to Impress) the range is ignored, and every object gets + // one table column in the order of appearance, which is: 1. categories, + // 2. data series: 2.a) domains, 2.b) values (main-role, usually y-values) + + Reference< chart2::data::XDataProvider > xDataProv( xChartDoc->getDataProvider()); + + // create a mapping from original ranges to new ranges + lcl_tOriginalRangeToInternalRangeMap aRangeMap; + + lcl_fillRangeMapping( rTable, aRangeMap, eDataRowSource ); + + const OUString lcl_aCategoriesRange(aCategoriesRange); + + bool bCategoriesApplied = false; + // translate ranges (using the map created before) + for( const auto& rLSeq : rLSequencesPerIndex ) + { + if( rLSeq.second.is()) + { + // values/error bars/categories + if( rLSeq.first.second == SCH_XML_PART_VALUES || + rLSeq.first.second == SCH_XML_PART_ERROR_BARS ) + { + Reference< chart2::data::XDataSequence > xSeq( rLSeq.second->getValues()); + + OUString aRange; + if( xSeq.is() && + SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) && + lcl_mapContainsRange( aRangeMap, aRange )) + { + Reference< chart2::data::XDataSequence > xNewSeq( + lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange )); + if( xNewSeq != xSeq ) + { + SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY )); + rLSeq.second->setValues( xNewSeq ); + } + } + else + { + if( lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile )) + { + if( rLSeq.first.first == SCH_XML_CATEGORIES_INDEX ) + bCategoriesApplied = true; + } + else + { + if( rLSeq.first.first == SCH_XML_CATEGORIES_INDEX ) + { + Reference< beans::XPropertySet > xOldSequenceProp( rLSeq.second->getValues(), uno::UNO_QUERY ); + Reference< chart2::data::XDataSequence > xNewSequence( + xDataProv->createDataSequenceByRangeRepresentation("categories")); + SchXMLTools::copyProperties( + xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY )); + rLSeq.second->setValues( xNewSequence ); + bCategoriesApplied = true; + } + else + { + Reference< beans::XPropertySet > xOldSequenceProp( rLSeq.second->getValues(), uno::UNO_QUERY ); + OUString aRep( OUString::number( rLSeq.first.first )); + Reference< chart2::data::XDataSequence > xNewSequence( + xDataProv->createDataSequenceByRangeRepresentation( aRep )); + SchXMLTools::copyProperties( + xOldSequenceProp, Reference< beans::XPropertySet >( xNewSequence, uno::UNO_QUERY )); + rLSeq.second->setValues( xNewSequence ); + } + } + } + } + else // labels + { + SAL_WARN_IF( rLSeq.first.second != SCH_XML_PART_LABEL, "xmloff.chart", "rLSeq.first.second != SCH_XML_PART_LABEL" ); + // labels + Reference< chart2::data::XDataSequence > xSeq( rLSeq.second->getLabel()); + OUString aRange; + if( xSeq.is() && + SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) && + lcl_mapContainsRange( aRangeMap, aRange )) + { + Reference< chart2::data::XDataSequence > xNewSeq( + lcl_reassignDataSequence( xSeq, xDataProv, aRangeMap, aRange )); + if( xNewSeq != xSeq ) + { + SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY )); + rLSeq.second->setLabel( xNewSeq ); + } + } + else if( ! lcl_tableOfRangeMatches( aRange, rTable.aTableNameOfFile )) + { + OUString aRep = "label " + OUString::number( rLSeq.first.first ); + + Reference< chart2::data::XDataSequence > xNewSeq( + xDataProv->createDataSequenceByRangeRepresentation( aRep )); + SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xNewSeq, uno::UNO_QUERY )); + rLSeq.second->setLabel( xNewSeq ); + } + } + } + } + + // there exist files with own data without a categories element but with row + // descriptions. The row descriptions were used as categories even without + // the categories element + if( ! bCategoriesApplied ) + { + SchXMLTools::CreateCategories( + xDataProv, xChartDoc, "categories", + 0 /* nCooSysIndex */, 0 /* nDimension */ ); + } + + //i91578 display of hidden values (copy paste scenario; use hidden flag during migration to locale table upon paste ) + //remove series that consist only of hidden columns + Reference< chart2::XInternalDataProvider > xInternalDataProvider( xDataProv, uno::UNO_QUERY ); + if( !xInternalDataProvider.is() || rTable.aHiddenColumns.empty() ) + return; + + try + { + Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChartDoc->getFirstDiagram(), uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() ); + for( const auto& rCooSys : aCooSysSeq ) + { + Reference< chart2::XChartTypeContainer > xCooSysContainer( rCooSys, uno::UNO_QUERY_THROW ); + const Sequence< Reference< chart2::XChartType > > aChartTypeSeq( xCooSysContainer->getChartTypes()); + for( const auto& rChartType : aChartTypeSeq ) + { + Reference< chart2::XDataSeriesContainer > xSeriesContainer( rChartType, uno::UNO_QUERY ); + if(!xSeriesContainer.is()) + continue; + const Sequence< Reference< chart2::XDataSeries > > aSeriesSeq( xSeriesContainer->getDataSeries() ); + std::vector< Reference< chart2::XDataSeries > > aRemainingSeries; + + for( const auto& rSeries : aSeriesSeq ) + { + Reference< chart2::data::XDataSource > xDataSource( rSeries, uno::UNO_QUERY ); + if( xDataSource.is() ) + { + bool bHasUnhiddenColumns = false; + OUString aRange; + const uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences() ); + for( const auto& xLabeledSequence : aSequences ) + { + if(!xLabeledSequence.is()) + continue; + Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() ); + if( xValues.is() ) + { + aRange = xValues->getSourceRangeRepresentation(); + if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), aRange.toInt32() ) == rTable.aHiddenColumns.end() ) + bHasUnhiddenColumns = true; + } + if( !bHasUnhiddenColumns ) + { + Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() ); + if( xLabel.is() ) + { + aRange = xLabel->getSourceRangeRepresentation(); + const sal_Int32 nId = o3tl::toInt32(o3tl::getToken(aRange, 1, ' ')); + if( ::std::find( rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), nId ) == rTable.aHiddenColumns.end() ) + bHasUnhiddenColumns = true; + } + } + } + if( bHasUnhiddenColumns ) + aRemainingSeries.push_back( rSeries ); + } + } + + if( aRemainingSeries.size() != o3tl::make_unsigned(aSeriesSeq.getLength()) ) + { + //remove the series that have only hidden data + xSeriesContainer->setDataSeries( comphelper::containerToSequence(aRemainingSeries) ); + + //remove unused sequences + Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY ); + if( xDataSource.is() ) + { + //first detect which columns are really used + std::map< sal_Int32, bool > aUsageMap; + OUString aRange; + const Sequence< Reference< chart2::data::XLabeledDataSequence > > aUsedSequences( xDataSource->getDataSequences() ); + for( const auto& xLabeledSequence : aUsedSequences ) + { + if(!xLabeledSequence.is()) + continue; + Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues() ); + if( xValues.is() ) + { + aRange = xValues->getSourceRangeRepresentation(); + sal_Int32 nIndex = aRange.toInt32(); + if( nIndex!=0 || aRange != lcl_aCategoriesRange ) + aUsageMap[nIndex] = true; + } + Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel() ); + if( xLabel.is() ) + { + aRange = xLabel->getSourceRangeRepresentation(); + std::u16string_view aSecondToken = o3tl::getToken(aRange, 1, ' '); + if( !aSecondToken.empty() ) + aUsageMap[o3tl::toInt32(aSecondToken)] = true; + } + } + + ::std::vector< sal_Int32 > aSequenceIndexesToDelete; + std::copy_if(rTable.aHiddenColumns.begin(), rTable.aHiddenColumns.end(), + std::back_inserter(aSequenceIndexesToDelete), + [&aUsageMap](sal_Int32 nSequenceIndex) { return aUsageMap.find(nSequenceIndex) == aUsageMap.end(); }); + + // delete unnecessary sequences of the internal data + // iterate using greatest index first, so that deletion does not + // shift other sequences that will be deleted later + ::std::sort( aSequenceIndexesToDelete.begin(), aSequenceIndexesToDelete.end()); + for( ::std::vector< sal_Int32 >::reverse_iterator aIt( + aSequenceIndexesToDelete.rbegin()); aIt != aSequenceIndexesToDelete.rend(); ++aIt ) + { + if( *aIt != -1 ) + xInternalDataProvider->deleteSequence( *aIt ); + } + } + } + } + } + } + catch( const uno::Exception & ) + { + } +} + +SchXMLRangeSomewhereContext::SchXMLRangeSomewhereContext( SvXMLImport& rImport, + OUString& rRangeString ) : + SvXMLImportContext( rImport ), + mrRangeString( rRangeString ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLRangeSomewhereContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( nElement == XML_ELEMENT(SVG, XML_DESC) + || nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC) ) + { + return new XMLStringBufferImportContext( GetImport(), maRangeStringBuffer ); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SchXMLRangeSomewhereContext::endFastElement(sal_Int32 ) +{ + mrRangeString = maRangeStringBuffer.makeStringAndClear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTableContext.hxx b/xmloff/source/chart/SchXMLTableContext.hxx new file mode 100644 index 000000000..cd8a6443b --- /dev/null +++ b/xmloff/source/chart/SchXMLTableContext.hxx @@ -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/. + * + * 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 +#include +#include + +#include + +#include "transporttypes.hxx" + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } + namespace chart { + class XChartDocument; + } +} + +class SchXMLTableContext : public SvXMLImportContext +{ +private: + SchXMLTable& mrTable; + + bool mbHasRowPermutation; + bool mbHasColumnPermutation; + css::uno::Sequence< sal_Int32 > maRowPermutation; + css::uno::Sequence< sal_Int32 > maColumnPermutation; + +public: + SchXMLTableContext( SvXMLImport& rImport, + SchXMLTable& aTable ); + virtual ~SchXMLTableContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + void setRowPermutation( const css::uno::Sequence< sal_Int32 > & rPermutation ); + void setColumnPermutation( const css::uno::Sequence< sal_Int32 > & rPermutation ); +}; + +class SchXMLTableHelper +{ +public: + static void applyTableToInternalDataProvider( const SchXMLTable& rTable, + const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc ); + + /** This function reorders local data to fit the correct data structure. + Call it after the data series got their styles set. + */ + static void switchRangesFromOuterToInternalIfNecessary( const SchXMLTable& rTable, + const tSchXMLLSequencesPerIndex & rLSequencesPerIndex, + const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc, + css::chart::ChartDataRowSource eDataRowSource ); +}; + +// classes for columns + +/** With this context all column elements are parsed to + determine the index of the column containing + the row descriptions and probably get an estimate + for the altogether number of columns + */ +class SchXMLTableColumnsContext : public SvXMLImportContext +{ +private: + SchXMLTable& mrTable; + +public: + SchXMLTableColumnsContext( SvXMLImport& rImport, + SchXMLTable& aTable ); + virtual ~SchXMLTableColumnsContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +class SchXMLTableColumnContext : public SvXMLImportContext +{ +private: + SchXMLTable& mrTable; + +public: + SchXMLTableColumnContext( SvXMLImport& rImport, + SchXMLTable& aTable ); + virtual ~SchXMLTableColumnContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// classes for rows + +class SchXMLTableRowsContext : public SvXMLImportContext +{ +private: + SchXMLTable& mrTable; + +public: + SchXMLTableRowsContext( SvXMLImport& rImport, + SchXMLTable& aTable ); + virtual ~SchXMLTableRowsContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +class SchXMLTableRowContext : public SvXMLImportContext +{ +private: + SchXMLTable& mrTable; + +public: + SchXMLTableRowContext( SvXMLImport& rImport, + SchXMLTable& aTable ); + virtual ~SchXMLTableRowContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +// classes for cells and their content + +class SchXMLTableCellContext : public SvXMLImportContext +{ +private: + SchXMLTable& mrTable; + OUString maCellContent; + OUString maRangeId; + bool mbReadText; + +public: + SchXMLTableCellContext( SvXMLImport& rImport, + SchXMLTable& aTable ); + virtual ~SchXMLTableCellContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTextListContext.cxx b/xmloff/source/chart/SchXMLTextListContext.cxx new file mode 100644 index 000000000..da70c24ed --- /dev/null +++ b/xmloff/source/chart/SchXMLTextListContext.cxx @@ -0,0 +1,108 @@ +/* -*- 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 "SchXMLTextListContext.hxx" +#include "SchXMLParagraphContext.hxx" + +#include +#include +#include +#include +#include + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using namespace com::sun::star; +using namespace ::xmloff::token; + +namespace { + +class SchXMLListItemContext : public SvXMLImportContext +{ +public: + SchXMLListItemContext( SvXMLImport& rImport, OUString& rText ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +private: + OUString& m_rText; +}; + +} + +SchXMLListItemContext::SchXMLListItemContext( + SvXMLImport& rImport + , OUString& rText ) + : SvXMLImportContext( rImport ) + , m_rText( rText ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLListItemContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + if( nElement == XML_ELEMENT(TEXT, XML_P) || + nElement == XML_ELEMENT(LO_EXT, XML_P) ) + pContext = new SchXMLParagraphContext( GetImport(), m_rText ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return pContext; +} + +SchXMLTextListContext::SchXMLTextListContext( + SvXMLImport& rImport + , Sequence< OUString>& rTextList ) + : SvXMLImportContext( rImport ) + , m_rTextList( rTextList ) +{ +} + +SchXMLTextListContext::~SchXMLTextListContext() +{ +} + +void SchXMLTextListContext::endFastElement(sal_Int32 ) +{ + sal_Int32 nCount = m_aTextVector.size(); + m_rTextList.realloc(nCount); + auto pTextList = m_rTextList.getArray(); + for( sal_Int32 nN=0; nN SchXMLTextListContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + if( nElement == XML_ELEMENT(TEXT, XML_LIST_ITEM) ) + { + m_aTextVector.emplace_back( ); + pContext = new SchXMLListItemContext( GetImport(), m_aTextVector.back() ); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTextListContext.hxx b/xmloff/source/chart/SchXMLTextListContext.hxx new file mode 100644 index 000000000..32d9bd3e3 --- /dev/null +++ b/xmloff/source/chart/SchXMLTextListContext.hxx @@ -0,0 +1,46 @@ +/* -*- 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 +#include +#include + +namespace com::sun::star::xml::sax { + class XAttributeList; +} + +class SchXMLTextListContext : public SvXMLImportContext +{ +public: + SchXMLTextListContext( SvXMLImport& rImport, + css::uno::Sequence< OUString>& rTextList ); + virtual ~SchXMLTextListContext() override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +private: + css::uno::Sequence< OUString>& m_rTextList; + std::vector< OUString> m_aTextVector; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTools.cxx b/xmloff/source/chart/SchXMLTools.cxx new file mode 100644 index 000000000..8fbf4aad7 --- /dev/null +++ b/xmloff/source/chart/SchXMLTools.cxx @@ -0,0 +1,858 @@ +/* -*- 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 "SchXMLTools.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ + +OUString lcl_getGeneratorFromModel( const uno::Reference< frame::XModel >& xChartModel ) +{ + OUString aGenerator; + uno::Reference< document::XDocumentPropertiesSupplier> xChartDocumentPropertiesSupplier( xChartModel, uno::UNO_QUERY ); + if( xChartDocumentPropertiesSupplier.is() ) + { + uno::Reference< document::XDocumentProperties > xChartDocumentProperties( + xChartDocumentPropertiesSupplier->getDocumentProperties()); + if( xChartDocumentProperties.is() ) + aGenerator = xChartDocumentProperties->getGenerator(); + } + return aGenerator; +} + +OUString lcl_getGeneratorFromModelOrItsParent( const uno::Reference< frame::XModel >& xChartModel ) +{ + OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( aGenerator.isEmpty() ) //try to get the missing info from the parent document + { + uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY ); + if( xChild.is() ) + aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) ); + } + return aGenerator; +} + +sal_Int32 lcl_getBuildIDFromGenerator( std::u16string_view rGenerator ) +{ + //returns -1 if nothing found + sal_Int32 nBuildId = -1; + static const OUStringLiteral sBuildCompare( u"$Build-" ); + size_t nBegin = rGenerator.find( sBuildCompare ); + if( nBegin != std::u16string_view::npos ) + { + std::u16string_view sBuildId = rGenerator.substr( nBegin + sBuildCompare.getLength() ); + nBuildId = o3tl::toInt32(sBuildId); + } + return nBuildId; +} + +OUString lcl_ConvertRange( const OUString & rRange, const Reference< chart2::data::XDataProvider >& xDataProvider ) +{ + OUString aResult = rRange; + Reference< chart2::data::XRangeXMLConversion > xRangeConversion( xDataProvider, uno::UNO_QUERY ); + if( xRangeConversion.is()) + aResult = xRangeConversion->convertRangeFromXML( rRange ); + return aResult; +} + +Reference< chart2::data::XDataSequence > lcl_createNewSequenceFromCachedXMLRange( const Reference< chart2::data::XDataSequence >& xSeq, const Reference< chart2::data::XDataProvider >& xDataProvider ) +{ + Reference< chart2::data::XDataSequence > xRet; + OUString aRange; + if( xSeq.is() && SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) ) + { + xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( + lcl_ConvertRange( aRange, xDataProvider )) ); + SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ), + Reference< beans::XPropertySet >( xRet, uno::UNO_QUERY )); + } + return xRet; +} + +} // anonymous namespace + +namespace SchXMLTools +{ + +const SvXMLEnumMapEntry aXMLChartClassMap[] = +{ + { XML_LINE, XML_CHART_CLASS_LINE }, + { XML_AREA, XML_CHART_CLASS_AREA }, + { XML_CIRCLE, XML_CHART_CLASS_CIRCLE }, + { XML_RING, XML_CHART_CLASS_RING }, + { XML_SCATTER, XML_CHART_CLASS_SCATTER }, + { XML_RADAR, XML_CHART_CLASS_RADAR }, + { XML_FILLED_RADAR, XML_CHART_CLASS_FILLED_RADAR }, + { XML_BAR, XML_CHART_CLASS_BAR }, + { XML_STOCK, XML_CHART_CLASS_STOCK }, + { XML_BUBBLE, XML_CHART_CLASS_BUBBLE }, + { XML_SURFACE, XML_CHART_CLASS_BAR }, //@todo change this if a surface chart is available + { XML_ADD_IN, XML_CHART_CLASS_ADDIN }, + { XML_TOKEN_INVALID, XML_CHART_CLASS_UNKNOWN } +}; + +SchXMLChartTypeEnum GetChartTypeEnum( std::u16string_view rClassName ) +{ + SchXMLChartTypeEnum nEnumVal = XML_CHART_CLASS_UNKNOWN; + SvXMLUnitConverter::convertEnum( nEnumVal, rClassName, aXMLChartClassMap ); + return nEnumVal; +} + +typedef std::map< OUString, OUString > tMakeStringStringMap; +//static +static const tMakeStringStringMap& lcl_getChartTypeNameMap() +{ + //shape property -- chart model object property + static const tMakeStringStringMap g_aChartTypeNameMap{ + {"com.sun.star.chart.LineDiagram", + "com.sun.star.chart2.LineChartType"}, + {"com.sun.star.chart.AreaDiagram", + "com.sun.star.chart2.AreaChartType"}, + {"com.sun.star.chart.BarDiagram", + "com.sun.star.chart2.ColumnChartType"}, + {"com.sun.star.chart.PieDiagram", + "com.sun.star.chart2.PieChartType"}, + {"com.sun.star.chart.DonutDiagram", + "com.sun.star.chart2.DonutChartType"}, + {"com.sun.star.chart.XYDiagram", + "com.sun.star.chart2.ScatterChartType"}, + {"com.sun.star.chart.NetDiagram", + "com.sun.star.chart2.NetChartType"}, + {"com.sun.star.chart.FilledNetDiagram", + "com.sun.star.chart2.FilledNetChartType"}, + {"com.sun.star.chart.StockDiagram", + "com.sun.star.chart2.CandleStickChartType"}, + {"com.sun.star.chart.BubbleDiagram", + "com.sun.star.chart2.BubbleChartType"}}; + return g_aChartTypeNameMap; +} + +OUString GetNewChartTypeName( const OUString & rOldChartTypeName ) +{ + OUString aNew(rOldChartTypeName); + + const tMakeStringStringMap& rMap = lcl_getChartTypeNameMap(); + tMakeStringStringMap::const_iterator aIt( rMap.find( rOldChartTypeName )); + if( aIt != rMap.end()) + { + aNew = aIt->second; + } + return aNew; +} + +OUString GetChartTypeByClassName( + std::u16string_view rClassName, bool bUseOldNames ) +{ + OUStringBuffer aResultBuffer; + bool bInternalType = false; + + if( bUseOldNames ) + aResultBuffer.append( "com.sun.star.chart."); + else + aResultBuffer.append( "com.sun.star.chart2."); + + bInternalType = true; + + if( IsXMLToken( rClassName, XML_LINE )) + aResultBuffer.append("Line"); + else if( IsXMLToken( rClassName, XML_AREA )) + aResultBuffer.append("Area"); + else if( IsXMLToken( rClassName, XML_BAR )) + { + if( bUseOldNames ) + aResultBuffer.append("Bar"); + else + { + aResultBuffer.append("Column"); + // @todo: might be Bar + } + } + else if( IsXMLToken( rClassName, XML_CIRCLE )) + aResultBuffer.append("Pie"); + else if( IsXMLToken( rClassName, XML_RING )) + aResultBuffer.append("Donut"); + else if( IsXMLToken( rClassName, XML_SCATTER )) + { + if( bUseOldNames ) + aResultBuffer.append("XY"); + else + aResultBuffer.append("Scatter"); + } + + else if( IsXMLToken( rClassName, XML_BUBBLE )) + aResultBuffer.append("Bubble"); + else if( IsXMLToken( rClassName, XML_RADAR )) + aResultBuffer.append("Net"); + else if( IsXMLToken( rClassName, XML_FILLED_RADAR )) + aResultBuffer.append("FilledNet"); + else if( IsXMLToken( rClassName, XML_STOCK )) + { + if( bUseOldNames ) + aResultBuffer.append("Stock"); + else + aResultBuffer.append("CandleStick"); + } + else if( IsXMLToken( rClassName, XML_SURFACE )) + { + //@todo change this if a surface chart is available + if( bUseOldNames ) + aResultBuffer.append("Bar"); + else + aResultBuffer.append("Column"); + } + else + bInternalType = false; + + if( ! bInternalType ) + return OUString(); + + if( bUseOldNames ) + aResultBuffer.append("Diagram"); + else + aResultBuffer.append("ChartType"); + + return aResultBuffer.makeStringAndClear(); + +} + +XMLTokenEnum getTokenByChartType( + const OUString & rChartTypeService, bool bUseOldNames ) +{ + XMLTokenEnum eResult = XML_TOKEN_INVALID; + OUString aPrefix, aPostfix; + + if( bUseOldNames ) + { + aPrefix = "com.sun.star.chart."; + aPostfix = "Diagram"; + } + else + { + aPrefix = "com.sun.star.chart2."; + aPostfix = "ChartType"; + } + + if( rChartTypeService.match( aPrefix )) + { + sal_Int32 nSkip = aPrefix.getLength(); + SAL_WARN_IF( rChartTypeService.getLength() < nSkip, "xmloff.chart", "ChartTypeService.getLength() < nSkip" ); + sal_Int32 nTypeLength = rChartTypeService.getLength() - nSkip - aPostfix.getLength(); + // if postfix matches and leaves a non-empty type + if( nTypeLength > 0 && rChartTypeService.match( aPostfix, nSkip + nTypeLength )) + { + std::u16string_view aServiceName( rChartTypeService.subView( nSkip, nTypeLength )); + + if ( aServiceName == u"Line" ) + eResult = XML_LINE; + else if ( aServiceName == u"Area" ) + eResult = XML_AREA; + else if( aServiceName == u"Bar" || + (!bUseOldNames && aServiceName == u"Column")) + eResult = XML_BAR; + else if ( aServiceName == u"Pie" ) + eResult = XML_CIRCLE; + else if ( aServiceName == u"Donut" ) + eResult = XML_RING; + else if( (bUseOldNames && aServiceName == u"XY") || + (!bUseOldNames && aServiceName == u"Scatter")) + eResult = XML_SCATTER; + else if ( aServiceName == u"Bubble" ) + eResult = XML_BUBBLE; + else if ( aServiceName == u"Net" ) + eResult = XML_RADAR; + else if ( aServiceName == u"FilledNet" ) + eResult = XML_FILLED_RADAR; + else if( (bUseOldNames && aServiceName == u"Stock") || + (!bUseOldNames && aServiceName == u"CandleStick")) + eResult = XML_STOCK; + } + } + + if( eResult == XML_TOKEN_INVALID && !rChartTypeService.isEmpty() ) + eResult = XML_ADD_IN; + + return eResult; +} + +Reference< chart2::data::XLabeledDataSequence2 > GetNewLabeledDataSequence() +{ + Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() ); + Reference< chart2::data::XLabeledDataSequence2 > xResult = chart2::data::LabeledDataSequence::create(xContext); + return xResult; +} + +Reference< chart2::data::XDataSequence > CreateDataSequence( + const OUString & rRange, + const Reference< chart2::XChartDocument >& xChartDoc ) +{ + Reference< chart2::data::XDataSequence > xRet; + + if( !xChartDoc.is() ) + { + SAL_WARN("xmloff.chart", "need a chart document" ); + return xRet; + } + + Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); + if( !xDataProvider.is() ) + { + SAL_WARN("xmloff.chart", "need a data provider" ); + return xRet; + } + + bool bUseInternal = false; + uno::Reference xPropSet(xDataProvider, uno::UNO_QUERY); + if (xPropSet.is()) + { + try + { + bool bVal = false; + uno::Any any = xPropSet->getPropertyValue("UseInternalDataProvider"); + if (any >>= bVal) + bUseInternal = bVal; + } + catch (const beans::UnknownPropertyException&) + { + // Do nothing + } + } + + if (!bUseInternal) + { + try + { + xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider ))); + SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange ); + } + catch( const lang::IllegalArgumentException & ) + { + SAL_WARN("xmloff.chart", "could not create data sequence" ); + } + } + + if( !xRet.is() && !xChartDoc->hasInternalDataProvider() && !rRange.isEmpty() ) + { + //#i103911# switch to internal data in case the parent cannot provide the requested data + xChartDoc->createInternalDataProvider( true /* bCloneExistingData */ ); + xDataProvider = xChartDoc->getDataProvider(); + try + { + xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider ))); + SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange ); + } + catch( const lang::IllegalArgumentException & ) + { + SAL_WARN("xmloff.chart", "could not create data sequence" ); + } + } + return xRet; +} + +Reference< chart2::data::XDataSequence > CreateDataSequenceWithoutConvert( + const OUString & rRange, + const Reference< chart2::XChartDocument >& xChartDoc ) +{ + Reference< chart2::data::XDataSequence > xRet; + + if( !xChartDoc.is() ) + { + SAL_WARN("xmloff.chart", "need a chart document" ); + return xRet; + } + + Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() ); + if( !xDataProvider.is() ) + { + SAL_WARN("xmloff.chart", "need a data provider" ); + return xRet; + } + + try + { + xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( rRange ) ); + SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange ); + } + catch( const lang::IllegalArgumentException & ) + { + SAL_WARN("xmloff.chart", "could not create data sequence" ); + } + + return xRet; +} + +void CreateCategories( + const uno::Reference< chart2::data::XDataProvider > & xDataProvider, + const uno::Reference< chart2::XChartDocument > & xNewDoc, + const OUString & rRangeAddress, + sal_Int32 nCooSysIndex, + sal_Int32 nDimensionIndex, + tSchXMLLSequencesPerIndex * pLSequencesPerIndex ) +{ + try + { + if( xNewDoc.is() && !rRangeAddress.isEmpty()) + { + if( xDataProvider.is()) + { + uno::Reference< chart2::XDiagram > xDia( xNewDoc->getFirstDiagram()); + if( !xDia.is()) + return; + + uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW ); + uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > + aCooSysSeq( xCooSysCnt->getCoordinateSystems()); + if( nCooSysIndex < aCooSysSeq.getLength()) + { + uno::Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIndex] ); + SAL_WARN_IF( !xCooSys.is(), "xmloff.chart", "xCooSys is NULL"); + if( nDimensionIndex < xCooSys->getDimension() ) + { + const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex); + for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI) + { + uno::Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nI )); + if( xAxis.is() ) + { + chart2::ScaleData aData( xAxis->getScaleData()); + uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( + GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW); + try + { + OUString aConvertedRange( rRangeAddress ); + bool bRangeConverted = false; + if( ! (xNewDoc->hasInternalDataProvider() && aConvertedRange == "categories")) + { + Reference< chart2::data::XRangeXMLConversion > xXMLConv( xDataProvider, uno::UNO_QUERY ); + if( xXMLConv.is()) + { + aConvertedRange = xXMLConv->convertRangeFromXML( rRangeAddress ); + bRangeConverted = true; + } + } + + Reference xSequence; + Reference xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY); + if (xPivotTableDataProvider.is()) + { + xSequence.set(xPivotTableDataProvider->createDataSequenceOfCategories()); + } + else + { + xSequence.set(xDataProvider->createDataSequenceByRangeRepresentation(aConvertedRange)); + if (bRangeConverted) + setXMLRangePropertyAtDataSequence(xSequence, rRangeAddress); + } + xLabeledSeq->setValues(xSequence); + + } + catch( const lang::IllegalArgumentException & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + aData.Categories.set( xLabeledSeq ); + if( pLSequencesPerIndex ) + { + // register for setting local data if external data provider is not present + pLSequencesPerIndex->emplace( + tSchXMLIndexWithPart( SCH_XML_CATEGORIES_INDEX, SCH_XML_PART_VALUES ), xLabeledSeq ); + } + xAxis->setScaleData( aData ); + } + } + } + } + } + } + } + catch( uno::Exception & ) + { + TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception caught while creating Categories" ); + } +} + +uno::Any getPropertyFromContext( std::u16string_view rPropertyName, const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ) +{ + uno::Any aRet; + if( !pPropStyleContext || !pStylesCtxt ) + return aRet; + const ::std::vector< XMLPropertyState >& rProperties = pPropStyleContext->GetProperties(); + const rtl::Reference< XMLPropertySetMapper >& rMapper = pStylesCtxt->GetImportPropertyMapper( pPropStyleContext->GetFamily()/*XML_STYLE_FAMILY_SCH_CHART_ID*/ )->getPropertySetMapper(); + for( const auto& rProp : rProperties ) + { + sal_Int32 nIdx = rProp.mnIndex; + if( nIdx == -1 ) + continue; + OUString aPropName = rMapper->GetEntryAPIName( nIdx ); + if(rPropertyName == aPropName) + return rProp.maValue; + } + return aRet; +} + +void exportText( SvXMLExport& rExport, const OUString& rText, bool bConvertTabsLFs ) +{ + SvXMLElementExport aPara( rExport, XML_NAMESPACE_TEXT, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_P ), + true, false ); + + if( bConvertTabsLFs ) + { + sal_Int32 nStartPos = 0; + sal_Int32 nEndPos = rText.getLength(); + sal_Unicode cChar; + + for( sal_Int32 nPos = 0; nPos < nEndPos; nPos++ ) + { + cChar = rText[ nPos ]; + switch( cChar ) + { + case 0x0009: // tabulator + { + if( nPos > nStartPos ) + rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) ); + nStartPos = nPos + 1; + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_TAB_STOP ), + false, false ); + } + break; + + case 0x000A: // linefeed + { + if( nPos > nStartPos ) + rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) ); + nStartPos = nPos + 1; + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_LINE_BREAK ), + false, false ); + } + break; + } + } + if( nEndPos > nStartPos ) + { + if( nStartPos == 0 ) + rExport.GetDocHandler()->characters( rText ); + else + rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nEndPos - nStartPos)) ); + } + } + else // do not convert tabs and linefeeds (eg for numbers coming from unit converter) + { + rExport.GetDocHandler()->characters( rText ); + } +} + +void exportRangeToSomewhere( SvXMLExport& rExport, const OUString& rValue ) +{ + //with issue #i366# and CWS chart20 ranges for error bars were introduced + //to keep them during copy paste from calc to impress for example it + //was necessary to introduce a mapping between the used ranges within calc and the data written to the local table + //this is why we write this ranges here + + //#i113950# first the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore within ODF 1.2 + //as an alternative the range info is now saved into the description at an empty group element (not very nice, but ODF conform) + + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion( + rExport.getSaneDefaultVersion()); + if (nCurrentODFVersion == SvtSaveOptions::ODFSVER_010 || nCurrentODFVersion == SvtSaveOptions::ODFSVER_011) + return;//svg:desc is not allowed at draw:g in ODF1.0; but as the ranges for error bars are anyhow not allowed within ODF1.0 nor ODF1.1 we do not need the information + + SvXMLElementExport aEmptyShapeGroup( rExport, XML_NAMESPACE_DRAW, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_G ), + true, false ); + SvXMLElementExport aDescription( rExport, XML_NAMESPACE_SVG, + ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DESC ), + true, false ); + rExport.GetDocHandler()->characters( rValue ); +} + +void setXMLRangePropertyAtDataSequence( + const Reference< chart2::data::XDataSequence > & xDataSequence, + const OUString & rXMLRange ) +{ + if( !xDataSequence.is()) + return; + try + { + static const OUStringLiteral aXMLRangePropName( u"CachedXMLRange" ); + Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW ); + Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo()); + if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName )) + xProp->setPropertyValue( aXMLRangePropName, uno::Any( rXMLRange )); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } +} + +bool getXMLRangePropertyFromDataSequence( + const Reference< chart2::data::XDataSequence > & xDataSequence, + OUString & rOutXMLRange, + bool bClearProp /* = false */) +{ + bool bResult = false; + if( xDataSequence.is()) + { + try + { + static const OUStringLiteral aXMLRangePropName( u"CachedXMLRange" ); + Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW ); + Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo()); + bResult = + ( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ) && + ( xProp->getPropertyValue( aXMLRangePropName ) >>= rOutXMLRange ) && + !rOutXMLRange.isEmpty()); + // clear the property after usage + if( bClearProp && bResult ) + xProp->setPropertyValue( aXMLRangePropName, uno::Any( OUString())); + } + catch( const uno::Exception & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.chart"); + } + } + return bResult; +} + +void copyProperties( + const Reference< beans::XPropertySet > & xSource, + const Reference< beans::XPropertySet > & xDestination ) +{ + if( ! (xSource.is() && xDestination.is()) ) + return; + + try + { + Reference< beans::XPropertySetInfo > xSrcInfo( xSource->getPropertySetInfo(), uno::UNO_SET_THROW ); + Reference< beans::XPropertySetInfo > xDestInfo( xDestination->getPropertySetInfo(), uno::UNO_SET_THROW ); + const Sequence< beans::Property > aProperties( xSrcInfo->getProperties()); + for( const auto& rProperty : aProperties ) + { + OUString aName( rProperty.Name); + if( xDestInfo->hasPropertyByName( aName )) + { + beans::Property aProp( xDestInfo->getPropertyByName( aName )); + if( (aProp.Attributes & beans::PropertyAttribute::READONLY) == 0 ) + xDestination->setPropertyValue( + aName, xSource->getPropertyValue( aName )); + } + } + } + catch( const uno::Exception & ) + { + SAL_WARN("xmloff.chart", "Copying property sets failed!" ); + } +} + +bool switchBackToDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc, const tSchXMLLSequencesPerIndex & rLSequencesPerIndex ) +{ + //return whether the switch is successful + if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() ) + return false; + Reference< chart2::data::XDataProvider > xDataProviderFromParent( SchXMLTools::getDataProviderFromParent( xChartDoc ) ); + if( !xDataProviderFromParent.is() ) + return false; + uno::Reference< chart2::data::XDataReceiver > xDataReceiver( xChartDoc, uno::UNO_QUERY ); + if( !xDataReceiver.is() ) + return false; + + xDataReceiver->attachDataProvider( xDataProviderFromParent ); + + for( const auto& rLSeq : rLSequencesPerIndex ) + { + Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( rLSeq.second ); + if( !xLabeledSeq.is() ) + continue; + Reference< chart2::data::XDataSequence > xNewSeq; + xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getValues(), xDataProviderFromParent ); + if( xNewSeq.is() ) + xLabeledSeq->setValues( xNewSeq ); + xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getLabel(), xDataProviderFromParent ); + if( xNewSeq.is() ) + xLabeledSeq->setLabel( xNewSeq ); + } + return true; +} + +void setBuildIDAtImportInfo( const uno::Reference< frame::XModel >& xModel, const Reference< beans::XPropertySet >& xImportInfo ) +{ + OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xModel) ); + if( !aGenerator.isEmpty() ) + SvXMLMetaDocumentContext::setBuildId( aGenerator, xImportInfo ); +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const uno::Reference< frame::XModel >& xChartModel ) +{ + bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel ); + if( !bResult ) + { + OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( aGenerator.indexOf( "OpenOffice.org_project/3" ) != -1 ) + { + if( aGenerator.indexOf( "OpenOffice.org_project/300m" ) != -1 ) + { + sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( nBuilId>0 && nBuilId<9491 ) //9491 is build id of dev300m76 + bResult= true; + } + else if( aGenerator.indexOf( "OpenOffice.org_project/310m" ) != -1 ) + bResult= true; + else if( aGenerator.indexOf( "OpenOffice.org_project/320m" ) != -1 ) + bResult= true; + } + } + return bResult; +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const uno::Reference< frame::XModel >& xChartModel ) +{ + bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel ); + if( !bResult ) + { + OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( aGenerator.indexOf( "OpenOffice.org_project/680m" ) != -1 ) + bResult= true; + } + return bResult; +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const uno::Reference< frame::XModel >& xChartModel ) +{ + if( isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel ) ) + return true; + + if( isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel ) ) + { + sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) ); + if( nBuilId>0 && nBuilId<=9238 ) //9238 is build id of OpenOffice.org 2.3.1 + return true; + } + return false; +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const uno::Reference< frame::XModel >& xChartModel ) +{ + bool bResult = false; + OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) ); + //if there is a meta stream at the chart object it was not written with an older OpenOffice version < 2.3 + if( aGenerator.isEmpty() ) + { + //if there is no meta stream at the chart object we need to check whether the parent document is OpenOffice at all + uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY ); + if( xChild.is() ) + { + aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) ); + if( aGenerator.indexOf( "OpenOffice.org_project" ) != -1 ) + { + //the chart application has not created files without a meta stream since OOo 2.3 (OOo 2.3 has written a metastream already) + //only the report builder extension has created some files with OOo 3.1 that do not have a meta stream + if( aGenerator.indexOf( "OpenOffice.org_project/31" ) != -1 ) + bResult = false;//#i100102# probably generated with OOo 3.1 by the report designer + else + bResult= true; //in this case the OLE chart was created by an older version, as OLE objects are sometimes stream copied the version can differ from the parents version, so the parents version is not a reliable indicator + } + else if( isDocumentGeneratedWithOpenOfficeOlderThan2_0(xChartModel) ) + bResult= true; + } + } + return bResult; +} + +bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const css::uno::Reference< css::frame::XModel >& xChartModel) +{ + bool bResult = false; + OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xChartModel) ); + if( aGenerator.startsWith( "OpenOffice.org 1" ) + || aGenerator.startsWith( "StarOffice 6" ) + || aGenerator.startsWith( "StarOffice 7" ) + || aGenerator.startsWith( "StarSuite 6" ) + || aGenerator.startsWith( "StarSuite 7" ) + ) + bResult= true; + return bResult; +} + +Reference< chart2::data::XDataProvider > getDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc ) +{ + Reference< chart2::data::XDataProvider > xRet; + uno::Reference< container::XChild > xChild( xChartDoc, uno::UNO_QUERY ); + if( xChild.is() ) + { + Reference< lang::XMultiServiceFactory > xFact( xChild->getParent(), uno::UNO_QUERY ); + if( xFact.is() ) + { + static const OUStringLiteral aDataProviderServiceName( u"com.sun.star.chart2.data.DataProvider"); + const uno::Sequence< OUString > aServiceNames( xFact->getAvailableServiceNames()); + const OUString * pBegin = aServiceNames.getConstArray(); + const OUString * pEnd = pBegin + aServiceNames.getLength(); + if( ::std::find( pBegin, pEnd, aDataProviderServiceName ) != pEnd ) + { + xRet.set( xFact->createInstance( aDataProviderServiceName ), uno::UNO_QUERY ); + } + } + } + return xRet; +} + +} // namespace SchXMLTools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/SchXMLTools.hxx b/xmloff/source/chart/SchXMLTools.hxx new file mode 100644 index 000000000..885e57aef --- /dev/null +++ b/xmloff/source/chart/SchXMLTools.hxx @@ -0,0 +1,136 @@ +/* -*- 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 +#include +#include "transporttypes.hxx" + +#include +#include + +namespace com::sun::star { + namespace chart2 { + class XChartDocument; + class XRegressionCurve; + namespace data { + class XDataProvider; + } + } +} + +class XMLPropStyleContext; +class SvXMLStylesContext; +class SvXMLExport; + +namespace SchXMLTools +{ + bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const css::uno::Reference< css::frame::XModel >& xChartModel); + bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const css::uno::Reference< css::frame::XModel >& xChartModel); + bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const css::uno::Reference< css::frame::XModel >& xChartModel); + bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const css::uno::Reference< css::frame::XModel >& xChartModel); + bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const css::uno::Reference< css::frame::XModel >& xChartModel); + + void setBuildIDAtImportInfo( const css::uno::Reference< css::frame::XModel >& xModel + , const css::uno::Reference< css::beans::XPropertySet >& xImportInfo ); + + enum SchXMLChartTypeEnum + { + XML_CHART_CLASS_LINE, + XML_CHART_CLASS_AREA, + XML_CHART_CLASS_CIRCLE, + XML_CHART_CLASS_RING, + XML_CHART_CLASS_SCATTER, + XML_CHART_CLASS_RADAR, + XML_CHART_CLASS_FILLED_RADAR, + XML_CHART_CLASS_BAR, + XML_CHART_CLASS_STOCK, + XML_CHART_CLASS_BUBBLE, + XML_CHART_CLASS_ADDIN, + XML_CHART_CLASS_UNKNOWN + }; + + SchXMLChartTypeEnum GetChartTypeEnum( std::u16string_view rClassName ); + + OUString GetChartTypeByClassName( + std::u16string_view rClassName, bool bUseOldNames ); + + ::xmloff::token::XMLTokenEnum getTokenByChartType( + const OUString & rChartTypeService, bool bUseOldNames ); + + OUString GetNewChartTypeName( const OUString & rOldChartTypeName ); + + css::uno::Reference< + css::chart2::data::XLabeledDataSequence2 > GetNewLabeledDataSequence(); + + css::uno::Reference< css::chart2::data::XDataSequence > CreateDataSequence( + const OUString& rRange, + const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc ); + + css::uno::Reference< css::chart2::data::XDataSequence > CreateDataSequenceWithoutConvert( + const OUString& rRange, + const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc ); + + void CreateCategories( + const css::uno::Reference< css::chart2::data::XDataProvider > & xDataProvider, + const css::uno::Reference< css::chart2::XChartDocument > & xNewDoc, + const OUString & rRangeAddress, + sal_Int32 nCooSysIndex, + sal_Int32 nDimensionIndex, + tSchXMLLSequencesPerIndex * pLSequencesPerIndex = nullptr ); + + css::uno::Any getPropertyFromContext( std::u16string_view rPropertyName, const XMLPropStyleContext * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt ); + + void exportText( SvXMLExport& rExport, const OUString& rText, bool bConvertTabsLFs ); + + void exportRangeToSomewhere( SvXMLExport& rExport, const OUString& rValue ); + + /** checks if the data sequence has the property "CachedXMLRange" (true for + internal data sequences), and if so sets this property to the range + given in rXMLRange + */ + void setXMLRangePropertyAtDataSequence( + const css::uno::Reference< css::chart2::data::XDataSequence > & xDataSequence, + const OUString & rXMLRange ); + + /** checks if the data sequence has the property "CachedXMLRange" (true for + internal data sequences), and if so retrieves this property and applies + it to the range given in rOutXMLRange. + + @param bClearProp If true, the property is reset to its default after it + was assigned to rOutXMLRange + + @return true, if the property was found, assigned and is non-empty + */ + bool getXMLRangePropertyFromDataSequence( + const css::uno::Reference< css::chart2::data::XDataSequence > & xDataSequence, + OUString & rOutXMLRange, + bool bClearProp ); + + css::uno::Reference< css::chart2::data::XDataProvider > getDataProviderFromParent( const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc ); + + bool switchBackToDataProviderFromParent( const css::uno::Reference< css::chart2::XChartDocument >& xChartDoc + , const tSchXMLLSequencesPerIndex & rLSequencesPerIndex ); + + void copyProperties( + const css::uno::Reference< css::beans::XPropertySet > & xSource, + const css::uno::Reference< css::beans::XPropertySet > & xDestination ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx b/xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx new file mode 100644 index 000000000..6508031ba --- /dev/null +++ b/xmloff/source/chart/XMLAxisPositionPropertyHdl.cxx @@ -0,0 +1,134 @@ +/* -*- 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 "XMLAxisPositionPropertyHdl.hxx" + +#include + +#include +#include + +#include + +#include + + +using namespace ::xmloff::token; + +using namespace com::sun::star; + +XMLAxisPositionPropertyHdl::XMLAxisPositionPropertyHdl( bool bCrossingValue ) + : m_bCrossingValue( bCrossingValue ) +{} + +XMLAxisPositionPropertyHdl::~XMLAxisPositionPropertyHdl() +{} + +bool XMLAxisPositionPropertyHdl::importXML( const OUString& rStrImpValue, + uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bResult = false; + + if( rStrImpValue == GetXMLToken(XML_START) ) + { + if( !m_bCrossingValue ) + { + rValue <<= css::chart::ChartAxisPosition_START; + bResult = true; + } + } + else if( rStrImpValue == GetXMLToken(XML_END) ) + { + if( !m_bCrossingValue ) + { + rValue <<= css::chart::ChartAxisPosition_END; + bResult = true; + } + } + else if( rStrImpValue == GetXMLToken(XML_0) ) + { + if( !m_bCrossingValue ) + { + rValue <<= css::chart::ChartAxisPosition_ZERO; + bResult = true; + } + } + else + { + if( !m_bCrossingValue ) + { + rValue <<= css::chart::ChartAxisPosition_VALUE; + bResult = true; + } + else + { + double fDblValue=0.0; + bResult = ::sax::Converter::convertDouble(fDblValue, rStrImpValue); + rValue <<= fDblValue; + } + } + + return bResult; +} + +bool XMLAxisPositionPropertyHdl::exportXML( OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bResult = false; + + OUStringBuffer sValueBuffer; + if( m_bCrossingValue ) + { + if(rStrExpValue.isEmpty()) + { + double fValue = 0.0; + rValue >>= fValue; + ::sax::Converter::convertDouble( sValueBuffer, fValue ); + rStrExpValue = sValueBuffer.makeStringAndClear(); + bResult = true; + } + } + else + { + css::chart::ChartAxisPosition ePosition( css::chart::ChartAxisPosition_ZERO ); + rValue >>= ePosition; + switch(ePosition) + { + case css::chart::ChartAxisPosition_START: + rStrExpValue = GetXMLToken( XML_START ); + bResult = true; + break; + case css::chart::ChartAxisPosition_END: + rStrExpValue = GetXMLToken( XML_END ); + bResult = true; + break; + case css::chart::ChartAxisPosition_ZERO: + ::sax::Converter::convertDouble( sValueBuffer, 0.0 ); + rStrExpValue = sValueBuffer.makeStringAndClear(); + bResult = true; + break; + default: + break; + } + } + return bResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLAxisPositionPropertyHdl.hxx b/xmloff/source/chart/XMLAxisPositionPropertyHdl.hxx new file mode 100644 index 000000000..dd779c11d --- /dev/null +++ b/xmloff/source/chart/XMLAxisPositionPropertyHdl.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/. + * + * 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 + +class XMLAxisPositionPropertyHdl : public XMLPropertyHandler +{ +public: + explicit XMLAxisPositionPropertyHdl( bool bCrossingValue ); + virtual ~XMLAxisPositionPropertyHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + +private: + bool m_bCrossingValue; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLChartPropertyContext.cxx b/xmloff/source/chart/XMLChartPropertyContext.cxx new file mode 100644 index 000000000..a06cad478 --- /dev/null +++ b/xmloff/source/chart/XMLChartPropertyContext.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/. + * + * 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 "XMLChartPropertyContext.hxx" +#include "PropertyMap.hxx" + +#include "XMLSymbolImageContext.hxx" +#include "XMLLabelSeparatorContext.hxx" +#include +#include + +using namespace ::com::sun::star; + +XMLChartPropertyContext::XMLChartPropertyContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList > & xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState >& rProps, + const rtl::Reference< SvXMLImportPropertyMapper >& rMapper ) : + SvXMLPropertySetContext( rImport, nElement, xAttrList, nFamily, rProps, rMapper ) +{ +} + +XMLChartPropertyContext::~XMLChartPropertyContext() +{} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChartPropertyContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + switch( mxMapper->getPropertySetMapper()->GetEntryContextId( rProp.mnIndex ) ) + { + case XML_SCH_CONTEXT_SPECIAL_SYMBOL_IMAGE: + return new XMLSymbolImageContext( GetImport(), nElement, rProp, rProperties ); + case XML_SCH_CONTEXT_SPECIAL_LABEL_SEPARATOR: + return new XMLLabelSeparatorContext( GetImport(), nElement, rProp, rProperties ); + } + + // default / no context yet: create child context by base class + return SvXMLPropertySetContext::createFastChildContext( + nElement, xAttrList, rProperties, rProp ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLChartPropertyContext.hxx b/xmloff/source/chart/XMLChartPropertyContext.hxx new file mode 100644 index 000000000..d0fa489d3 --- /dev/null +++ b/xmloff/source/chart/XMLChartPropertyContext.hxx @@ -0,0 +1,44 @@ +/* -*- 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 + +class XMLChartPropertyContext : public SvXMLPropertySetContext +{ +public: + + XMLChartPropertyContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState >& rProps, + const rtl::Reference< SvXMLImportPropertyMapper >& rMapper ); + virtual ~XMLChartPropertyContext() override; + + using SvXMLPropertySetContext::createFastChildContext; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; + +private: +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLChartStyleContext.cxx b/xmloff/source/chart/XMLChartStyleContext.cxx new file mode 100644 index 000000000..b17bf5d82 --- /dev/null +++ b/xmloff/source/chart/XMLChartStyleContext.cxx @@ -0,0 +1,139 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "XMLChartPropertyContext.hxx" + +using namespace com::sun::star; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_DATA_STYLE_NAME; +using ::xmloff::token::XML_PERCENTAGE_DATA_STYLE_NAME; +using ::xmloff::token::XML_TEXT_PROPERTIES; +using ::xmloff::token::XML_PARAGRAPH_PROPERTIES; +using ::xmloff::token::XML_GRAPHIC_PROPERTIES; +using ::xmloff::token::XML_CHART_PROPERTIES; + + +void XMLChartStyleContext::SetAttribute( + sal_Int32 nElement, + const OUString& rValue ) +{ + switch (nElement & TOKEN_MASK) + { + case XML_DATA_STYLE_NAME: + msDataStyleName = rValue; + break; + case XML_PERCENTAGE_DATA_STYLE_NAME: + msPercentageDataStyleName = rValue; + break; + default: + XMLShapeStyleContext::SetAttribute( nElement, rValue ); + } +} + +XMLChartStyleContext::XMLChartStyleContext( + SvXMLImport& rImport, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily ) : + XMLShapeStyleContext( rImport, rStyles, nFamily ), + mrStyles( rStyles ) +{} + +XMLChartStyleContext::~XMLChartStyleContext() +{} + +namespace +{ + +void lcl_NumberFormatStyleToProperty( const OUString& rStyleName, const OUString& rPropertyName, + const SvXMLStylesContext& rStylesContext, + const uno::Reference< beans::XPropertySet >& rPropSet ) +{ + if( !rStyleName.isEmpty()) + { + const SvXMLNumFormatContext* pStyle = static_cast(rStylesContext.FindStyleChildContext( + XmlStyleFamily::DATA_STYLE, rStyleName, true )); + if( pStyle ) + { + sal_Int32 nNumberFormat = const_cast(pStyle)->GetKey(); + rPropSet->setPropertyValue( rPropertyName, uno::Any(nNumberFormat) ); + } + } +} + +} + +void XMLChartStyleContext::FillPropertySet( + const uno::Reference< beans::XPropertySet > & rPropSet ) +{ + try + { + XMLShapeStyleContext::FillPropertySet( rPropSet ); + } + catch( beans::UnknownPropertyException& ) + { + TOOLS_WARN_EXCEPTION( "xmloff", "unknown property exception -> shape style not completely imported for chart style" ); + } + + lcl_NumberFormatStyleToProperty( msDataStyleName, "NumberFormat", mrStyles, rPropSet ); + lcl_NumberFormatStyleToProperty( msPercentageDataStyleName, "PercentageNumberFormat", mrStyles, rPropSet ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChartStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) || + IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + sal_uInt32 nFamily = 0; + if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_GRAPHIC_PROPERTIES ) + nFamily = XML_TYPE_PROP_GRAPHIC; + else if( nLocalName == XML_CHART_PROPERTIES ) + nFamily = XML_TYPE_PROP_CHART; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new XMLChartPropertyContext( + GetImport(), nElement, xAttrList, nFamily, + GetProperties(), xImpPrMap ); + } + } + + return XMLShapeStyleContext::createFastChildContext( nElement, xAttrList ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLErrorBarStylePropertyHdl.cxx b/xmloff/source/chart/XMLErrorBarStylePropertyHdl.cxx new file mode 100644 index 000000000..c50450740 --- /dev/null +++ b/xmloff/source/chart/XMLErrorBarStylePropertyHdl.cxx @@ -0,0 +1,61 @@ +/* -*- 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 "XMLErrorBarStylePropertyHdl.hxx" + +#include +#include + +#include +#include + +using namespace com::sun::star; + +XMLErrorBarStylePropertyHdl::XMLErrorBarStylePropertyHdl( const SvXMLEnumMapEntry* pEnumMap ) + : XMLEnumPropertyHdl( pEnumMap ) +{ +} + +XMLErrorBarStylePropertyHdl::~XMLErrorBarStylePropertyHdl() +{ +} + +bool XMLErrorBarStylePropertyHdl::exportXML( OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter) const +{ + uno::Any aValue(rValue); + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(rUnitConverter.getSaneDefaultVersion()); + if (nCurrentVersion < SvtSaveOptions::ODFSVER_012) + { + sal_Int32 nValue = 0; + if(rValue >>= nValue ) + { + if( nValue == css::chart::ErrorBarStyle::STANDARD_ERROR + || nValue == css::chart::ErrorBarStyle::FROM_DATA ) + { + nValue = css::chart::ErrorBarStyle::NONE; + aValue <<= nValue; + } + } + } + + return XMLEnumPropertyHdl::exportXML( rStrExpValue, aValue, rUnitConverter ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLErrorBarStylePropertyHdl.hxx b/xmloff/source/chart/XMLErrorBarStylePropertyHdl.hxx new file mode 100644 index 000000000..2a006f0e3 --- /dev/null +++ b/xmloff/source/chart/XMLErrorBarStylePropertyHdl.hxx @@ -0,0 +1,33 @@ +/* -*- 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 + +class XMLErrorBarStylePropertyHdl : public XMLEnumPropertyHdl +{ +public: + XMLErrorBarStylePropertyHdl(const SvXMLEnumMapEntry* pEnumMap); + virtual ~XMLErrorBarStylePropertyHdl() override; + + virtual bool exportXML(OUString& rStrExpValue, const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.cxx b/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.cxx new file mode 100644 index 000000000..65f39a9b6 --- /dev/null +++ b/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.cxx @@ -0,0 +1,103 @@ +/* -*- 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 "XMLErrorIndicatorPropertyHdl.hxx" + +#include + +#include +#include + +#include + + +using namespace com::sun::star; + +XMLErrorIndicatorPropertyHdl::~XMLErrorIndicatorPropertyHdl() +{} + +bool XMLErrorIndicatorPropertyHdl::importXML( const OUString& rStrImpValue, + uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bValue(false); + (void)::sax::Converter::convertBool( bValue, rStrImpValue ); + + // modify existing value + chart::ChartErrorIndicatorType eType = chart::ChartErrorIndicatorType_NONE; + if( rValue.hasValue()) + rValue >>= eType; + + if( bValue ) // enable flag + { + if( eType != chart::ChartErrorIndicatorType_TOP_AND_BOTTOM ) + { + if( mbUpperIndicator ) + eType = ( eType == chart::ChartErrorIndicatorType_LOWER ) + ? chart::ChartErrorIndicatorType_TOP_AND_BOTTOM + : chart::ChartErrorIndicatorType_UPPER; + else + eType = ( eType == chart::ChartErrorIndicatorType_UPPER ) + ? chart::ChartErrorIndicatorType_TOP_AND_BOTTOM + : chart::ChartErrorIndicatorType_LOWER; + } + } + else // disable flag + { + if( eType != chart::ChartErrorIndicatorType_NONE ) + { + if( mbUpperIndicator ) + eType = ( eType == chart::ChartErrorIndicatorType_UPPER ) + ? chart::ChartErrorIndicatorType_NONE + : chart::ChartErrorIndicatorType_LOWER; + else + eType = ( eType == chart::ChartErrorIndicatorType_LOWER ) + ? chart::ChartErrorIndicatorType_NONE + : chart::ChartErrorIndicatorType_UPPER; + } + } + + rValue <<= eType; + + return true; +} + +bool XMLErrorIndicatorPropertyHdl::exportXML( OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + chart::ChartErrorIndicatorType eType; + + rValue >>= eType; + bool bValue = ( eType == chart::ChartErrorIndicatorType_TOP_AND_BOTTOM || + ( mbUpperIndicator + ? ( eType == chart::ChartErrorIndicatorType_UPPER ) + : ( eType == chart::ChartErrorIndicatorType_LOWER ))); + + if( bValue ) + { + OUStringBuffer aBuffer; + ::sax::Converter::convertBool( aBuffer, bValue ); + rStrExpValue = aBuffer.makeStringAndClear(); + } + + // only export if set to true + return bValue; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.hxx b/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.hxx new file mode 100644 index 000000000..d33e66413 --- /dev/null +++ b/xmloff/source/chart/XMLErrorIndicatorPropertyHdl.hxx @@ -0,0 +1,37 @@ +/* -*- 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 + +class XMLErrorIndicatorPropertyHdl : public XMLPropertyHandler +{ +private: + bool mbUpperIndicator; + +public: + explicit XMLErrorIndicatorPropertyHdl( bool bUpper ) : mbUpperIndicator( bUpper ) + {} + virtual ~XMLErrorIndicatorPropertyHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLLabelSeparatorContext.cxx b/xmloff/source/chart/XMLLabelSeparatorContext.cxx new file mode 100644 index 000000000..93beff46c --- /dev/null +++ b/xmloff/source/chart/XMLLabelSeparatorContext.cxx @@ -0,0 +1,66 @@ +/* -*- 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 "XMLLabelSeparatorContext.hxx" + +#include "SchXMLParagraphContext.hxx" +#include +#include +#include + + +using namespace ::com::sun::star; + +XMLLabelSeparatorContext::XMLLabelSeparatorContext( + SvXMLImport& rImport, sal_Int32 nElement, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ) : + XMLElementPropertyContext( + rImport, nElement, rProp, rProps ) +{ +} + +XMLLabelSeparatorContext::~XMLLabelSeparatorContext() +{} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLLabelSeparatorContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + if( (nElement & TOKEN_MASK) == xmloff::token::XML_P ) + { + return new SchXMLParagraphContext( GetImport(), m_aSeparator ); + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLLabelSeparatorContext::endFastElement(sal_Int32 nElement) +{ + if( !m_aSeparator.isEmpty() ) + { + // aProp is a member of XMLElementPropertyContext + aProp.maValue <<= m_aSeparator; + SetInsert( true ); + } + + XMLElementPropertyContext::endFastElement(nElement); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLLabelSeparatorContext.hxx b/xmloff/source/chart/XMLLabelSeparatorContext.hxx new file mode 100644 index 000000000..83e69f01a --- /dev/null +++ b/xmloff/source/chart/XMLLabelSeparatorContext.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/. + * + * 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 + +class XMLLabelSeparatorContext : public XMLElementPropertyContext +{ +public: + XMLLabelSeparatorContext(SvXMLImport& rImport, sal_Int32 nElement, + const XMLPropertyState& rProp, + ::std::vector& rProps); + virtual ~XMLLabelSeparatorContext() override; + + virtual css::uno::Reference SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference& AttrList) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +private: + OUString m_aSeparator; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLSymbolImageContext.cxx b/xmloff/source/chart/XMLSymbolImageContext.cxx new file mode 100644 index 000000000..646f1b8c0 --- /dev/null +++ b/xmloff/source/chart/XMLSymbolImageContext.cxx @@ -0,0 +1,112 @@ +/* -*- 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 "XMLSymbolImageContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace css; +using namespace xmloff::token; + +XMLSymbolImageContext::XMLSymbolImageContext( + SvXMLImport& rImport, sal_Int32 nElement, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ) : + XMLElementPropertyContext( + rImport, nElement, rProp, rProps ) +{ +} + +XMLSymbolImageContext::~XMLSymbolImageContext() +{} + +void XMLSymbolImageContext::startFastElement( + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + const OUString sValue = aIter.toString(); + + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + msURL = sValue; + break; + case XML_ELEMENT(XLINK, XML_ACTUATE): + case XML_ELEMENT(XLINK, XML_TYPE): + case XML_ELEMENT(XLINK, XML_SHOW): + // these values are currently not interpreted + // it is always assumed 'actuate=onLoad', 'type=simple', 'show=embed' + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLSymbolImageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + if( (nElement & TOKEN_MASK) == xmloff::token::XML_BINARY_DATA ) + { + if( msURL.isEmpty() && ! mxBase64Stream.is() ) + { + mxBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( mxBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), mxBase64Stream ); + } + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLSymbolImageContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference xGraphic; + + if (!msURL.isEmpty()) + { + xGraphic = GetImport().loadGraphicByURL(msURL); + } + else if (mxBase64Stream.is()) + { + xGraphic = GetImport().loadGraphicFromBase64(mxBase64Stream); + mxBase64Stream = nullptr; + } + + if (xGraphic.is()) + { + // aProp is a member of XMLElementPropertyContext + aProp.maValue <<= xGraphic; + SetInsert( true ); + } + + XMLElementPropertyContext::endFastElement(nElement); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLSymbolImageContext.hxx b/xmloff/source/chart/XMLSymbolImageContext.hxx new file mode 100644 index 000000000..a4796775c --- /dev/null +++ b/xmloff/source/chart/XMLSymbolImageContext.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/. + * + * 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 + +namespace com::sun::star { + namespace io { class XOutputStream; } +} + +class XMLSymbolImageContext : public XMLElementPropertyContext +{ +public: + + XMLSymbolImageContext( SvXMLImport& rImport, sal_Int32 nElement, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ); + virtual ~XMLSymbolImageContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +private: + OUString msURL; + css::uno::Reference < css::io::XOutputStream > mxBase64Stream; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLSymbolTypePropertyHdl.cxx b/xmloff/source/chart/XMLSymbolTypePropertyHdl.cxx new file mode 100644 index 000000000..dd24c1340 --- /dev/null +++ b/xmloff/source/chart/XMLSymbolTypePropertyHdl.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/. + * + * 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 "XMLSymbolTypePropertyHdl.hxx" +#include +#include + +using namespace ::xmloff::token; + +namespace +{ +struct SvXMLSignedEnumMapEntry +{ + ::xmloff::token::XMLTokenEnum eToken; + sal_Int32 nValue; +}; + +const SvXMLSignedEnumMapEntry aXMLChartSymbolTypeEnumMap[] = +{ + { XML_NONE, -3 }, + { XML_AUTOMATIC, -2 }, + { XML_IMAGE, -1 }, + { XML_TOKEN_INVALID, 0 } +}; + +const SvXMLSignedEnumMapEntry aXMLChartSymbolNameMap[] = +{ + { XML_GRADIENTSTYLE_SQUARE, 0 }, // "square" + { XML_DIAMOND, 1 }, + { XML_ARROW_DOWN, 2 }, + { XML_ARROW_UP, 3 }, + { XML_ARROW_RIGHT, 4 }, + { XML_ARROW_LEFT, 5 }, + { XML_BOW_TIE, 6 }, + { XML_HOURGLASS, 7 }, + { XML_CIRCLE, 8 }, + { XML_STAR, 9 }, + { XML_X, 10 }, + { XML_PLUS, 11 }, + { XML_ASTERISK, 12 }, + { XML_HORIZONTAL_BAR, 13 }, + { XML_VERTICAL_BAR, 14 }, + { XML_TOKEN_INVALID, 0 } +}; + +bool lcl_convertEnum( + OUStringBuffer & rBuffer, + sal_Int32 nValue, + const SvXMLSignedEnumMapEntry *pMap ) +{ + enum XMLTokenEnum eTok = XML_TOKEN_INVALID; + + while( pMap->eToken != XML_TOKEN_INVALID ) + { + if( pMap->nValue == nValue ) + { + eTok = pMap->eToken; + break; + } + pMap++; + } + + if( eTok != XML_TOKEN_INVALID ) + rBuffer.append( GetXMLToken(eTok) ); + + return (eTok != XML_TOKEN_INVALID); +} + +bool lcl_convertEnum( + sal_Int32 & rEnum, + std::u16string_view rValue, + const SvXMLSignedEnumMapEntry *pMap ) +{ + while( pMap->eToken != XML_TOKEN_INVALID ) + { + if( IsXMLToken( rValue, pMap->eToken ) ) + { + rEnum = pMap->nValue; + return true; + } + pMap++; + } + return false; +} + +} // anonymous namespace + +using namespace com::sun::star; + +XMLSymbolTypePropertyHdl::XMLSymbolTypePropertyHdl( bool bIsNamedSymbol ) + : m_bIsNamedSymbol( bIsNamedSymbol ) +{} + +XMLSymbolTypePropertyHdl::~XMLSymbolTypePropertyHdl() +{} + +bool XMLSymbolTypePropertyHdl::importXML( const OUString& rStrImpValue, + uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bResult = false; + + if( m_bIsNamedSymbol ) + { + sal_Int32 nValue = -3; // NONE + bResult = lcl_convertEnum( nValue, rStrImpValue, aXMLChartSymbolNameMap ); + rValue <<= nValue; + } + else + { + sal_Int32 nValue = -3; // NONE + bResult = lcl_convertEnum( nValue, rStrImpValue, aXMLChartSymbolTypeEnumMap ); + rValue <<= nValue; + } + + return bResult; +} + +bool XMLSymbolTypePropertyHdl::exportXML( OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bResult = false; + + sal_Int32 nType = -3; // NONE + rValue >>= nType; + + if( m_bIsNamedSymbol ) + { + OUStringBuffer aBuf; + bResult = lcl_convertEnum( aBuf, nType, aXMLChartSymbolNameMap ); + rStrExpValue = aBuf.makeStringAndClear(); + } + else + { + if( nType < 0 ) + { + OUStringBuffer aBuf; + bResult = lcl_convertEnum( aBuf, nType, aXMLChartSymbolTypeEnumMap ); + rStrExpValue = aBuf.makeStringAndClear(); + } + else + { + bResult = true; + rStrExpValue = GetXMLToken( XML_NAMED_SYMBOL ); + } + } + + return bResult; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLSymbolTypePropertyHdl.hxx b/xmloff/source/chart/XMLSymbolTypePropertyHdl.hxx new file mode 100644 index 000000000..78d2be686 --- /dev/null +++ b/xmloff/source/chart/XMLSymbolTypePropertyHdl.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/. + * + * 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 + +class XMLSymbolTypePropertyHdl : public XMLPropertyHandler +{ +public: + explicit XMLSymbolTypePropertyHdl( bool bIsNamedSymbol ); + virtual ~XMLSymbolTypePropertyHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + +private: + bool m_bIsNamedSymbol; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLTextOrientationHdl.cxx b/xmloff/source/chart/XMLTextOrientationHdl.cxx new file mode 100644 index 000000000..7f23e58c1 --- /dev/null +++ b/xmloff/source/chart/XMLTextOrientationHdl.cxx @@ -0,0 +1,72 @@ +/* -*- 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 "XMLTextOrientationHdl.hxx" +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +XMLTextOrientationHdl::~XMLTextOrientationHdl() +{ +} + +bool XMLTextOrientationHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bRetval( false ); + + if( IsXMLToken( rStrImpValue, XML_LTR )) + { + rValue <<= false; + bRetval = true; + } + else if( IsXMLToken( rStrImpValue, XML_TTB )) + { + rValue <<= true; + bRetval = true; + } + + return bRetval; +} + +bool XMLTextOrientationHdl::exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bVal (false ); + bool bRetval( false ); + + if( rValue >>= bVal ) + { + if( bVal ) + rStrExpValue = GetXMLToken( XML_TTB ); + else + rStrExpValue = GetXMLToken( XML_LTR ); + bRetval = true; + } + + return bRetval; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/XMLTextOrientationHdl.hxx b/xmloff/source/chart/XMLTextOrientationHdl.hxx new file mode 100644 index 000000000..e84dcb909 --- /dev/null +++ b/xmloff/source/chart/XMLTextOrientationHdl.hxx @@ -0,0 +1,37 @@ +/* -*- 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 + +class XMLTextOrientationHdl : public XMLPropertyHandler +{ +private: +public: + virtual ~XMLTextOrientationHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/contexts.cxx b/xmloff/source/chart/contexts.cxx new file mode 100644 index 000000000..b11790df7 --- /dev/null +++ b/xmloff/source/chart/contexts.cxx @@ -0,0 +1,169 @@ +/* -*- 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 +#include +#include +#include +#include +#include "SchXMLCalculationSettingsContext.hxx" + +#include "contexts.hxx" + +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +namespace { + +class SchXMLBodyContext_Impl : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + +public: + + SchXMLBodyContext_Impl( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +} + +SchXMLBodyContext_Impl::SchXMLBodyContext_Impl( + SchXMLImportHelper& rImpHelper, SvXMLImport& rImport ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ) +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SchXMLBodyContext_Impl::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + return new SchXMLBodyContext( mrImportHelper, GetImport(), nElement ); +} + +SchXMLDocContext::SchXMLDocContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_Int32 nElement ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ) +{ + SAL_WARN_IF(( nElement != XML_ELEMENT( OFFICE, XML_DOCUMENT ) && + nElement != XML_ELEMENT( OFFICE, XML_DOCUMENT_META ) && + nElement != XML_ELEMENT( OFFICE, XML_DOCUMENT_STYLES ) && + nElement != XML_ELEMENT( OFFICE, XML_DOCUMENT_CONTENT ) ), "xmloff.chart", "SchXMLDocContext instantiated with no element" ); +} + +SchXMLDocContext::~SchXMLDocContext() +{} + + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SchXMLDocContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportFlags nFlags = GetImport().getImportFlags(); + switch (nElement) + { + case XML_ELEMENT(OFFICE, XML_BODY): + if( nFlags & SvXMLImportFlags::CONTENT ) + return new SchXMLBodyContext_Impl( mrImportHelper, GetImport() ); + break; + case XML_ELEMENT(OFFICE, XML_STYLES): + // for draw styles containing gradients/hatches/markers and dashes + if( nFlags & SvXMLImportFlags::STYLES ) + return new SvXMLStylesContext( GetImport() ); + break; + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES): + if( nFlags & SvXMLImportFlags::AUTOSTYLES ) + // not nice, but this is safe, as the SchXMLDocContext class can only by + // instantiated by the chart import class SchXMLImport (header is not exported) + return + static_cast< SchXMLImport& >( GetImport() ).CreateStylesContext(); + break; + case XML_ELEMENT(OFFICE, XML_META): + // we come here in the flat ODF file format, + // if XDocumentPropertiesSupplier is not supported at the model + break; + } + return nullptr; +} + +SchXMLFlatDocContext_Impl::SchXMLFlatDocContext_Impl( + SchXMLImportHelper& i_rImpHelper, + SchXMLImport& i_rImport, + sal_Int32 i_nElement, + const uno::Reference& i_xDocProps) : + SvXMLImportContext(i_rImport), + SchXMLDocContext(i_rImpHelper, i_rImport, i_nElement), + SvXMLMetaDocumentContext(i_rImport, i_xDocProps) +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SchXMLFlatDocContext_Impl::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + // behave like meta base class iff we encounter office:meta + if ( nElement == XML_ELEMENT( OFFICE, XML_META ) ) { + return SvXMLMetaDocumentContext::createFastChildContext( + nElement, xAttrList ); + } else { + return SchXMLDocContext::createFastChildContext( + nElement, xAttrList ); + } +} + +SchXMLBodyContext::SchXMLBodyContext( SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_Int32 nElement ) : + SvXMLImportContext( rImport ), + mrImportHelper( rImpHelper ) +{ + SAL_WARN_IF( nElement != XML_ELEMENT(OFFICE, XML_CHART), "xmloff.chart", "SchXMLBodyContext instantiated with no element" ); +} + +SchXMLBodyContext::~SchXMLBodyContext() +{} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLBodyContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + + // element + if( nElement == XML_ELEMENT(CHART, XML_CHART) ) + { + xContext = mrImportHelper.CreateChartContext( GetImport(), GetImport().GetModel() ); + } + else if(nElement == XML_ELEMENT(TABLE, XML_CALCULATION_SETTINGS )) + { + // i99104 handle null date correctly + xContext = new SchXMLCalculationSettingsContext ( GetImport(), xAttrList); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/contexts.hxx b/xmloff/source/chart/contexts.hxx new file mode 100644 index 000000000..4a710bcc5 --- /dev/null +++ b/xmloff/source/chart/contexts.hxx @@ -0,0 +1,85 @@ +/* -*- 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 +#include + +#include + +namespace com::sun::star::xml::sax { + class XAttributeList; +} + +/* + These contexts are only needed by + SchXMLImport not by the SchXMLImportHelper + that is also used by other applications +*/ + +class SchXMLDocContext : public virtual SvXMLImportContext +{ +protected: + SchXMLImportHelper& mrImportHelper; + +public: + SchXMLDocContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_Int32 nElement ); + + virtual ~SchXMLDocContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// context for flat file xml format +class SchXMLFlatDocContext_Impl + : public SchXMLDocContext, public SvXMLMetaDocumentContext +{ +public: + SchXMLFlatDocContext_Impl( + SchXMLImportHelper& i_rImpHelper, + SchXMLImport& i_rImport, + sal_Int32 i_nElement, + const css::uno::Reference& i_xDocProps); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +class SchXMLBodyContext : public SvXMLImportContext +{ +private: + SchXMLImportHelper& mrImportHelper; + +public: + SchXMLBodyContext( + SchXMLImportHelper& rImpHelper, + SvXMLImport& rImport, + sal_Int32 nElement ); + virtual ~SchXMLBodyContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/transporttypes.cxx b/xmloff/source/chart/transporttypes.cxx new file mode 100644 index 000000000..c648413be --- /dev/null +++ b/xmloff/source/chart/transporttypes.cxx @@ -0,0 +1,30 @@ +/* -*- 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 "transporttypes.hxx" + +bool operator < ( const tSchXMLIndexWithPart & rFirst, const tSchXMLIndexWithPart & rSecond ) +{ + if( rFirst.first == rSecond.first ) + return (static_cast< int >( rFirst.second ) < static_cast< int >( rSecond.second )); + return (rFirst.first < rSecond.first); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/chart/transporttypes.hxx b/xmloff/source/chart/transporttypes.hxx new file mode 100644 index 000000000..7053d20c8 --- /dev/null +++ b/xmloff/source/chart/transporttypes.hxx @@ -0,0 +1,231 @@ +/* -*- 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 +#include + +#include +#include +#include + +enum SchXMLCellType +{ + SCH_CELL_TYPE_UNKNOWN, + SCH_CELL_TYPE_FLOAT, + SCH_CELL_TYPE_STRING, + SCH_CELL_TYPE_COMPLEX_STRING +}; + +struct SchXMLCell +{ + OUString aString; + css::uno::Sequence< OUString > aComplexString; + double fValue; + SchXMLCellType eType; + OUString aRangeId; + + SchXMLCell(): fValue( 0.0 ), eType( SCH_CELL_TYPE_UNKNOWN ) + {} +}; + +struct SchXMLTable +{ + std::vector< std::vector< SchXMLCell > > aData; /// an array of rows containing the table contents + + sal_Int32 nRowIndex; /// reflects the index of the row currently parsed + sal_Int32 nColumnIndex; /// reflects the index of the column currently parsed + sal_Int32 nMaxColumnIndex; /// the greatest number of columns detected + + sal_Int32 nNumberOfColsEstimate; /// parsing column-elements may yield an estimate + + bool bHasHeaderRow; + bool bHasHeaderColumn; + + OUString aTableNameOfFile; /// the table name read at the table:table element + + ::std::vector< sal_Int32 > aHiddenColumns; + + bool bProtected; + + SchXMLTable() : nRowIndex( -1 ), + nColumnIndex( -1 ), + nMaxColumnIndex( -1 ), + nNumberOfColsEstimate( 0 ), + bHasHeaderRow( false ), + bHasHeaderColumn( false ), + bProtected( false ) + {} +}; + +typedef sal_Int32 tSchXMLIndex; +#define SCH_XML_CATEGORIES_INDEX (static_cast(-1)) +enum SchXMLLabeledSequencePart +{ + SCH_XML_PART_LABEL, + SCH_XML_PART_VALUES, + SCH_XML_PART_ERROR_BARS +}; +typedef ::std::pair< tSchXMLIndex, SchXMLLabeledSequencePart > tSchXMLIndexWithPart; +typedef ::std::multimap< tSchXMLIndexWithPart, + css::uno::Reference< css::chart2::data::XLabeledDataSequence > > + tSchXMLLSequencesPerIndex; + +bool operator < ( const tSchXMLIndexWithPart & rFirst, const tSchXMLIndexWithPart & rSecond ); + +enum SchXMLAxisDimension +{ + SCH_XML_AXIS_X = 0, + SCH_XML_AXIS_Y, + SCH_XML_AXIS_Z, + SCH_XML_AXIS_UNDEF +}; + +struct SchXMLAxis +{ + enum SchXMLAxisDimension eDimension; + sal_Int8 nAxisIndex;//0->primary axis; 1->secondary axis + OUString aName; + OUString aTitle; + bool bHasCategories; + + SchXMLAxis() : eDimension( SCH_XML_AXIS_UNDEF ), nAxisIndex( 0 ), bHasCategories( false ) {} +}; + +struct GlobalSeriesImportInfo +{ + explicit GlobalSeriesImportInfo( bool& rAllRangeAddressesAvailable ) + : rbAllRangeAddressesAvailable( rAllRangeAddressesAvailable ) + , nCurrentDataIndex( 0 ) + , nFirstFirstDomainIndex( -1 ) + , nFirstSecondDomainIndex( -1 ) + {} + + bool& rbAllRangeAddressesAvailable; + + sal_Int32 nCurrentDataIndex; + + OUString aFirstFirstDomainAddress; + sal_Int32 nFirstFirstDomainIndex; + + OUString aFirstSecondDomainAddress; + sal_Int32 nFirstSecondDomainIndex; +}; + +struct RegressionStyle +{ + css::uno::Reference< + css::chart2::XDataSeries > m_xSeries; + css::uno::Reference< + css::beans::XPropertySet > m_xEquationProperties; + + OUString msStyleName; + + RegressionStyle(const css::uno::Reference< + css::chart2::XDataSeries >& xSeries, + const OUString& sStyleName) : + m_xSeries ( xSeries ), + msStyleName ( sStyleName ) + {} +}; + +/** + * Used to store text content of a data point custom-label's fields and also + * the helper members that indicates whether this label's contents are sourced + * from a cell[range] and the address of the cell[range] with GUID of + * the CELLRANGE field. + */ +struct CustomLabelsInfo +{ + /// Text content of each field. + ::std::vector mLabels; + /// Are label's contents sourced from a cell[range] ? + bool mbDataLabelsRange = false; + /// GUID of the CELLRANGE field. + OUString msLabelGuid; + /// cell[range] from which label's contents are sourced. + OUString msLabelsCellRange; +}; + +struct DataRowPointStyle +{ + enum StyleType + { + DATA_POINT, + DATA_SERIES, + MEAN_VALUE, + ERROR_INDICATOR, + DATA_LABEL_POINT, + DATA_LABEL_SERIES + }; + + StyleType meType; + css::uno::Reference< css::chart2::XDataSeries > m_xSeries; + + css::uno::Reference< css::beans::XPropertySet > m_xOldAPISeries; + + css::uno::Reference< css::beans::XPropertySet > m_xErrorXProperties; + + css::uno::Reference< css::beans::XPropertySet > m_xErrorYProperties; + + sal_Int32 m_nPointIndex; + sal_Int32 m_nPointRepeat; + OUString msStyleName; + OUString msStyleNameOfParent; // e.g. target of line and fill styles of data-labels + CustomLabelsInfo mCustomLabels; + double mCustomLabelPos[2] = { 0.0, 0.0 }; + // for svg:x and svg:y attribute (in core unit), of element + std::optional mo_nLabelAbsolutePosX; + std::optional mo_nLabelAbsolutePosY; + OUString msSeriesStyleNameForDonuts; + + sal_Int32 mnAttachedAxis; + bool mbSymbolSizeForSeriesIsMissingInFile; + + DataRowPointStyle( StyleType eType + , const css::uno::Reference< css::chart2::XDataSeries >& xSeries + , sal_Int32 nPointIndex + , sal_Int32 nPointRepeat + , const OUString& sStyleName + , sal_Int32 nAttachedAxis = 0 ) : + meType( eType ), + m_xSeries( xSeries ), + m_nPointIndex( nPointIndex ), + m_nPointRepeat( nPointRepeat ), + msStyleName( sStyleName ), + mnAttachedAxis( nAttachedAxis ), + mbSymbolSizeForSeriesIsMissingInFile( false ) + {} + + // ctor for use in import of as child of + DataRowPointStyle(StyleType eType, const OUString& sStyleName, sal_Int32 nAttachedAxis = 0) + : meType(eType) + , m_nPointIndex(0) + , m_nPointRepeat(0) + , msStyleName(sStyleName) + , mnAttachedAxis(nAttachedAxis) + , mbSymbolSizeForSeriesIsMissingInFile(false) + { + } +}; + +typedef ::std::multimap< OUString, css::uno::Reference< + css::chart2::data::XDataSequence > > tSchXMLRangeSequenceMap; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/DocumentSettingsContext.cxx b/xmloff/source/core/DocumentSettingsContext.cxx new file mode 100644 index 000000000..9052a8dba --- /dev/null +++ b/xmloff/source/core/DocumentSettingsContext.cxx @@ -0,0 +1,760 @@ +/* -*- 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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xmlenums.hxx" + +using namespace com::sun::star; +using namespace ::xmloff::token; + +namespace { + +class XMLMyList +{ + std::vector aProps; + sal_uInt32 nCount; + + css::uno::Reference< css::uno::XComponentContext > m_xContext; + +public: + explicit XMLMyList(const uno::Reference& rxContext); + + void push_back(beans::PropertyValue const & aProp) { aProps.push_back(aProp); nCount++; } + uno::Sequence GetSequence(); + uno::Reference GetNameContainer(); + uno::Reference GetIndexContainer(); +}; + +} + +XMLMyList::XMLMyList(const uno::Reference& rxContext) +: nCount(0), + m_xContext(rxContext) +{ + assert(m_xContext.is()); +} + +uno::Sequence XMLMyList::GetSequence() +{ + uno::Sequence aSeq; + if(nCount) + { + assert(nCount == aProps.size()); + aSeq.realloc(nCount); + beans::PropertyValue* pProps = aSeq.getArray(); + for (auto const& prop : aProps) + { + *pProps = prop; + ++pProps; + } + } + return aSeq; +} + +uno::Reference XMLMyList::GetNameContainer() +{ + uno::Reference xNameContainer = document::NamedPropertyValues::create(m_xContext); + for (auto const& prop : aProps) + { + xNameContainer->insertByName(prop.Name, prop.Value); + } + + return xNameContainer; +} + +uno::Reference XMLMyList::GetIndexContainer() +{ + rtl::Reference< comphelper::IndexedPropertyValuesContainer > xIndexContainer = new comphelper::IndexedPropertyValuesContainer(); + sal_uInt32 i(0); + for (auto const& prop : aProps) + { + xIndexContainer->insertByIndex(i, prop.Value); + ++i; + } + + return xIndexContainer; +} + +namespace { + +class XMLConfigBaseContext : public SvXMLImportContext +{ +protected: + XMLMyList maProps; + beans::PropertyValue maProp; + css::uno::Any& mrAny; + XMLConfigBaseContext* mpBaseContext; +public: + XMLConfigBaseContext(SvXMLImport& rImport, + css::uno::Any& rAny, + XMLConfigBaseContext* pBaseContext); + + void AddPropertyValue() { maProps.push_back(maProp); } +}; + +class XMLConfigItemContext : public SvXMLImportContext +{ + OUString msType; + css::uno::Any& mrAny; + const OUString mrItemName; + XMLConfigBaseContext* mpBaseContext; + OUStringBuffer maCharBuffer; + +public: + XMLConfigItemContext(SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Any& rAny, + const OUString& rItemName, + XMLConfigBaseContext* pBaseContext); + + virtual void SAL_CALL characters( const OUString& rChars ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + void ManipulateConfigItem(); +}; + +class XMLConfigItemSetContext : public XMLConfigBaseContext +{ +public: + XMLConfigItemSetContext(SvXMLImport& rImport, + css::uno::Any& rAny, + XMLConfigBaseContext* pBaseContext); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class XMLConfigItemMapNamedContext : public XMLConfigBaseContext +{ +public: + XMLConfigItemMapNamedContext(SvXMLImport& rImport, + css::uno::Any& rAny, + XMLConfigBaseContext* pBaseContext); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class XMLConfigItemMapIndexedContext : public XMLConfigBaseContext +{ +private: + OUString maConfigItemName; + +public: + XMLConfigItemMapIndexedContext(SvXMLImport& rImport, + css::uno::Any& rAny, + const OUString& rConfigItemName, + XMLConfigBaseContext* pBaseContext); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +} + +static SvXMLImportContext *CreateSettingsContext(SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference& xAttrList, + beans::PropertyValue& rProp, XMLConfigBaseContext* pBaseContext) +{ + SvXMLImportContext *pContext = nullptr; + + rProp.Name.clear(); + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if (aIter.getToken() == XML_ELEMENT(CONFIG, XML_NAME)) + rProp.Name = aIter.toString(); + } + + if (nElement == XML_ELEMENT(CONFIG, XML_CONFIG_ITEM)) + pContext = new XMLConfigItemContext(rImport, xAttrList, rProp.Value, rProp.Name, pBaseContext); + else if(nElement == XML_ELEMENT(CONFIG, XML_CONFIG_ITEM_SET) || + nElement == XML_ELEMENT(CONFIG, XML_CONFIG_ITEM_MAP_ENTRY) ) + pContext = new XMLConfigItemSetContext(rImport, rProp.Value, pBaseContext); + else if(nElement == XML_ELEMENT(CONFIG, XML_CONFIG_ITEM_MAP_NAMED)) + pContext = new XMLConfigItemMapNamedContext(rImport, rProp.Value, pBaseContext); + else if(nElement == XML_ELEMENT(CONFIG, XML_CONFIG_ITEM_MAP_INDEXED)) + pContext = new XMLConfigItemMapIndexedContext(rImport, rProp.Value, rProp.Name, pBaseContext); + + return pContext; +} + +XMLDocumentSettingsContext::XMLDocumentSettingsContext(SvXMLImport& rImport) + : SvXMLImportContext( rImport ) +{ + // here are no attributes +} + +XMLDocumentSettingsContext::~XMLDocumentSettingsContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLDocumentSettingsContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + OUString sName; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if (aIter.getToken() == XML_ELEMENT(CONFIG, XML_NAME)) + sName = aIter.toString(); + } + + if (nElement == XML_ELEMENT(CONFIG, XML_CONFIG_ITEM_SET)) + { + OUString aLocalConfigName; + sal_uInt16 nConfigPrefix = + GetImport().GetNamespaceMap().GetKeyByAttrValueQName( + sName, &aLocalConfigName ); + + if( XML_NAMESPACE_OOO == nConfigPrefix ) + { + if (IsXMLToken(aLocalConfigName, XML_VIEW_SETTINGS)) + pContext = new XMLConfigItemSetContext(GetImport(), + maViewProps, nullptr); + else if (IsXMLToken(aLocalConfigName, + XML_CONFIGURATION_SETTINGS)) + pContext = new XMLConfigItemSetContext(GetImport(), + maConfigProps, nullptr); + else + { + maDocSpecificSettings.push_back( {aLocalConfigName, uno::Any()} ); + + pContext = new XMLConfigItemSetContext(GetImport(), + maDocSpecificSettings.back().aSettings, nullptr); + } + } + } + + return pContext; +} + +void XMLDocumentSettingsContext::endFastElement(sal_Int32 ) +{ + uno::Sequence aSeqViewProps; + if (maViewProps >>= aSeqViewProps) + { + GetImport().SetViewSettings(aSeqViewProps); + sal_Int32 i(aSeqViewProps.getLength() - 1); + bool bFound(false); + while((i >= 0) && !bFound) + { + if (aSeqViewProps[i].Name == "Views") + { + bFound = true; + uno::Reference xIndexAccess; + if (aSeqViewProps[i].Value >>= xIndexAccess) + { + uno::Reference xViewDataSupplier(GetImport().GetModel(), uno::UNO_QUERY); + if (xViewDataSupplier.is()) + xViewDataSupplier->setViewData(xIndexAccess); + } + } + else + i--; + } + } + + uno::Sequence aSeqConfigProps; + if ( maConfigProps >>= aSeqConfigProps ) + { + if (!utl::ConfigManager::IsFuzzing() && !officecfg::Office::Common::Save::Document::LoadPrinter::get()) + { + auto aSeqConfigPropsRange = asNonConstRange(aSeqConfigProps); + sal_Int32 i = aSeqConfigProps.getLength() - 1; + int nFound = 0; + + while ( ( i >= 0 ) && nFound < 2 ) + { + OUString sProp( aSeqConfigProps[i].Name ); + + if ( sProp == "PrinterName" ) + { + aSeqConfigPropsRange[i].Value <<= OUString(); + nFound++; + } + else if ( sProp == "PrinterSetup" ) + { + uno::Sequence< sal_Int8 > aEmpty; + aSeqConfigPropsRange[i].Value <<= aEmpty; + nFound++; + } + + i--; + } + } + + GetImport().SetConfigurationSettings( aSeqConfigProps ); + } + + for (auto const& settings : maDocSpecificSettings) + { + uno::Sequence< beans::PropertyValue > aDocSettings; + OSL_VERIFY( settings.aSettings >>= aDocSettings ); + GetImport().SetDocumentSpecificSettings( settings.sGroupName, aDocSettings ); + } +} + +XMLConfigBaseContext::XMLConfigBaseContext(SvXMLImport& rImport, + css::uno::Any& rTempAny, + XMLConfigBaseContext* pTempBaseContext) + : SvXMLImportContext( rImport ), + maProps( rImport.GetComponentContext() ), + mrAny(rTempAny), + mpBaseContext(pTempBaseContext) +{ +} + +XMLConfigItemSetContext::XMLConfigItemSetContext(SvXMLImport& rImport, + css::uno::Any& rAny, + XMLConfigBaseContext* pBaseContext) + : XMLConfigBaseContext( rImport, rAny, pBaseContext ) +{ + // here are no attributes +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLConfigItemSetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return CreateSettingsContext(GetImport(), nElement, xAttrList, maProp, this); +} + +void XMLConfigItemSetContext::endFastElement(sal_Int32 ) +{ + mrAny <<= maProps.GetSequence(); + if (mpBaseContext) + mpBaseContext->AddPropertyValue(); +} + +XMLConfigItemContext::XMLConfigItemContext(SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Any& rTempAny, + const OUString& rTempItemName, + XMLConfigBaseContext* pTempBaseContext) + : SvXMLImportContext(rImport), + mrAny(rTempAny), + mrItemName(rTempItemName), + mpBaseContext(pTempBaseContext) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if (aIter.getToken() == XML_ELEMENT(CONFIG, XML_TYPE)) + msType = aIter.toString(); + } +} + +void XMLConfigItemContext::characters( const OUString& rChars ) +{ + maCharBuffer.append(rChars); +} + +void XMLConfigItemContext::endFastElement(sal_Int32 ) +{ + OUString sValue; + uno::Sequence aDecoded; + if (IsXMLToken(msType, XML_BASE64BINARY)) + { + std::u16string_view sChars = o3tl::trim(maCharBuffer); + if( !sChars.empty() ) + ::comphelper::Base64::decodeSomeChars( aDecoded, sChars ); + maCharBuffer.setLength(0); + } + else + sValue = maCharBuffer.makeStringAndClear(); + + if (mpBaseContext) + { + if (IsXMLToken(msType, XML_BOOLEAN)) + { + bool bValue(false); + if (IsXMLToken(sValue, XML_TRUE)) + bValue = true; + mrAny <<= bValue; + } + else if (IsXMLToken(msType, XML_BYTE)) + { + sal_Int32 nValue(0); + ::sax::Converter::convertNumber(nValue, sValue); + mrAny <<= static_cast(nValue); + } + else if (IsXMLToken(msType, XML_SHORT)) + { + sal_Int32 nValue(0); + ::sax::Converter::convertNumber(nValue, sValue); + mrAny <<= static_cast(nValue); + } + else if (IsXMLToken(msType, XML_INT)) + { + sal_Int32 nValue(0); + ::sax::Converter::convertNumber(nValue, sValue); + mrAny <<= nValue; + } + else if (IsXMLToken(msType, XML_LONG)) + { + sal_Int64 nValue(sValue.toInt64()); + mrAny <<= nValue; + } + else if (IsXMLToken(msType, XML_DOUBLE)) + { + double fValue(0.0); + ::sax::Converter::convertDouble(fValue, sValue); + mrAny <<= fValue; + } + else if (IsXMLToken(msType, XML_STRING)) + { + mrAny <<= sValue; + } + else if (IsXMLToken(msType, XML_DATETIME)) + { + util::DateTime aDateTime; + if (::sax::Converter::parseDateTime(aDateTime, sValue)) + mrAny <<= aDateTime; + else + SAL_WARN("xmloff.core", "XMLConfigItemContext: broken DateTime '" << sValue << "'"); + } + else if (IsXMLToken(msType, XML_BASE64BINARY)) + { + mrAny <<= aDecoded; + } + else { + SAL_INFO("xmloff.core", + "XMLConfigItemContext: unknown type: " << msType); + } + + ManipulateConfigItem(); + + mpBaseContext->AddPropertyValue(); + } + else { + assert(false && "no BaseContext"); + } +} + +/** There are some instances where there is a mismatch between API and + * XML mapping of a setting. In this case, this method allows us to + * manipulate the values accordingly. */ +void XMLConfigItemContext::ManipulateConfigItem() +{ + if( mrItemName == "PrinterIndependentLayout" ) + { + OUString sValue; + mrAny >>= sValue; + + sal_Int16 nTmp = document::PrinterIndependentLayout::HIGH_RESOLUTION; + + if( sValue == "enabled" || sValue == "low-resolution" ) + { + nTmp = document::PrinterIndependentLayout::LOW_RESOLUTION; + } + else if ( sValue == "disabled" ) + { + nTmp = document::PrinterIndependentLayout::DISABLED; + } + // else: default to high_resolution + + mrAny <<= nTmp; + } + else if( (mrItemName == "ColorTableURL") || (mrItemName == "LineEndTableURL") || (mrItemName == "HatchTableURL") + || (mrItemName == "DashTableURL") || (mrItemName == "GradientTableURL") || (mrItemName == "BitmapTableURL") ) + { + try + { + uno::Reference< uno::XComponentContext > xContext( GetImport().GetComponentContext() ); + uno::Reference< util::XStringSubstitution > xStringSubstitution( util::PathSubstitution::create(xContext) ); + + OUString aURL; + mrAny >>= aURL; + aURL = xStringSubstitution->substituteVariables( aURL, false ); + mrAny <<= aURL; + } + catch( uno::Exception& ) + { + } + } +} + +XMLConfigItemMapNamedContext::XMLConfigItemMapNamedContext(SvXMLImport& rImport, + css::uno::Any& rAny, + XMLConfigBaseContext* pBaseContext) + : XMLConfigBaseContext(rImport, rAny, pBaseContext) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLConfigItemMapNamedContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return CreateSettingsContext(GetImport(), nElement, xAttrList, maProp, this); +} + +void XMLConfigItemMapNamedContext::endFastElement(sal_Int32 ) +{ + if (mpBaseContext) + { + mrAny <<= maProps.GetNameContainer(); + mpBaseContext->AddPropertyValue(); + } + else { + assert(false && "no BaseContext"); + } +} + +XMLConfigItemMapIndexedContext::XMLConfigItemMapIndexedContext(SvXMLImport& rImport, + css::uno::Any& rAny, + const OUString& rConfigItemName, + XMLConfigBaseContext* pBaseContext) + : XMLConfigBaseContext(rImport, rAny, pBaseContext), + maConfigItemName( rConfigItemName ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLConfigItemMapIndexedContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return CreateSettingsContext(GetImport(), nElement, xAttrList, maProp, this); +} + +void XMLConfigItemMapIndexedContext::endFastElement(sal_Int32 ) +{ + if (mpBaseContext) + { + if ( maConfigItemName == "ForbiddenCharacters" ) + { + uno::Reference< i18n::XForbiddenCharacters > xForbChars; + + // get the forbidden characters from the document + uno::Reference< lang::XMultiServiceFactory > xFac( GetImport().GetModel(), uno::UNO_QUERY ); + if( xFac.is() ) + { + uno::Reference< beans::XPropertySet > xProps( xFac->createInstance( "com.sun.star.document.Settings" ), uno::UNO_QUERY ); + if( xProps.is() && xProps->getPropertySetInfo()->hasPropertyByName( maConfigItemName ) ) + { + xProps->getPropertyValue( maConfigItemName ) >>= xForbChars; + } + } + + if( xForbChars.is() ) + { + + uno::Reference< container::XIndexAccess > xIndex = maProps.GetIndexContainer(); + + const sal_Int32 nCount = xIndex->getCount(); + uno::Sequence < beans::PropertyValue > aProps; + for (sal_Int32 i = 0; i < nCount; i++) + { + if ((xIndex->getByIndex( i ) >>= aProps) && (aProps.getLength() == XML_FORBIDDEN_CHARACTER_MAX ) ) + { + /* FIXME-BCP47: this stupid and counterpart in + * xmloff/source/core/SettingsExportHelper.cxx + * XMLSettingsExportHelper::exportForbiddenCharacters() + * */ + + beans::PropertyValue *pForChar = aProps.getArray(); + i18n::ForbiddenCharacters aForbid; + lang::Locale aLocale; + bool bHaveLanguage = false, bHaveCountry = false, bHaveVariant = false, + bHaveBegin = false, bHaveEnd = false; + + for ( sal_Int32 j = 0 ; j < XML_FORBIDDEN_CHARACTER_MAX ; j++ ) + { + if (pForChar->Name == "Language") + { + pForChar->Value >>= aLocale.Language; + bHaveLanguage = true; + } + else if (pForChar->Name == "Country") + { + pForChar->Value >>= aLocale.Country; + bHaveCountry = true; + } + else if (pForChar->Name == "Variant") + { + pForChar->Value >>= aLocale.Variant; + bHaveVariant = true; + } + else if (pForChar->Name == "BeginLine") + { + pForChar->Value >>= aForbid.beginLine; + bHaveBegin = true; + } + else if (pForChar->Name == "EndLine") + { + pForChar->Value >>= aForbid.endLine; + bHaveEnd = true; + } + pForChar++; + } + + if ( bHaveLanguage && bHaveCountry && bHaveVariant && bHaveBegin && bHaveEnd ) + { + try + { + xForbChars->setForbiddenCharacters( aLocale, aForbid ); + } + catch (uno::Exception const&) + { + TOOLS_WARN_EXCEPTION("xmloff.core", + "Exception while importing forbidden characters"); + } + } + } + } + } + else + { + SAL_WARN("xmloff.core", "could not get the XForbiddenCharacters from document!"); + mrAny <<= maProps.GetIndexContainer(); + } + } + else if ( maConfigItemName == "Symbols" ) + { + uno::Reference< container::XIndexAccess > xIndex = maProps.GetIndexContainer(); + + const sal_Int32 nCount = xIndex->getCount(); + uno::Sequence < beans::PropertyValue > aProps; + uno::Sequence < formula::SymbolDescriptor > aSymbolList ( nCount ); + + formula::SymbolDescriptor *pDescriptor = aSymbolList.getArray(); + + sal_Int16 nNumFullEntries = 0; + + for ( sal_Int32 i = 0; i < nCount; i++ ) + { + if ((xIndex->getByIndex( i ) >>= aProps) && (aProps.getLength() == XML_SYMBOL_DESCRIPTOR_MAX ) ) + { + bool bHaveName = false, bHaveExportName = false, bHaveCharSet = false, + bHaveFontName = false, bHaveFamily = false, bHavePitch = false, + bHaveWeight = false, bHaveItalic = false, bHaveSymbolSet = false, + bHaveCharacter = false; + beans::PropertyValue *pSymbol = aProps.getArray(); + + for ( sal_Int32 j = 0 ; j < XML_SYMBOL_DESCRIPTOR_MAX ; j++ ) + { + if (pSymbol->Name == "Name") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].sName; + bHaveName = true; + } + else if (pSymbol->Name == "ExportName") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].sExportName; + bHaveExportName = true; + } + else if (pSymbol->Name == "FontName") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].sFontName; + bHaveFontName = true; + } + else if (pSymbol->Name == "CharSet") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].nCharSet; + bHaveCharSet = true; + } + else if (pSymbol->Name == "Family") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].nFamily; + bHaveFamily = true; + } + else if (pSymbol->Name == "Pitch") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].nPitch; + bHavePitch = true; + } + else if (pSymbol->Name == "Weight") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].nWeight; + bHaveWeight = true; + } + else if (pSymbol->Name == "Italic") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].nItalic; + bHaveItalic = true; + } + else if (pSymbol->Name == "SymbolSet") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].sSymbolSet; + bHaveSymbolSet = true; + } + else if (pSymbol->Name == "Character") + { + pSymbol->Value >>= pDescriptor[nNumFullEntries].nCharacter; + bHaveCharacter = true; + } + pSymbol++; + } + if ( bHaveName && bHaveExportName && bHaveCharSet && bHaveFontName && bHaveCharacter + && bHaveFamily && bHavePitch && bHaveWeight && bHaveItalic && bHaveSymbolSet) + nNumFullEntries++; + } + } + aSymbolList.realloc (nNumFullEntries); + mrAny <<= aSymbolList; + } + else + { + mrAny <<= maProps.GetIndexContainer(); + } + mpBaseContext->AddPropertyValue(); + } + else { + assert(false && "no BaseContext"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/DomBuilderContext.cxx b/xmloff/source/core/DomBuilderContext.cxx new file mode 100644 index 000000000..066d8e603 --- /dev/null +++ b/xmloff/source/core/DomBuilderContext.cxx @@ -0,0 +1,321 @@ +/* -*- 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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +using com::sun::star::uno::XComponentContext; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::xml::dom::DocumentBuilder; +using com::sun::star::xml::dom::XDocument; +using com::sun::star::xml::dom::XDocumentBuilder; +using com::sun::star::xml::dom::XNode; +using com::sun::star::xml::dom::XElement; +using com::sun::star::xml::sax::XAttributeList; +using com::sun::star::xml::dom::NodeType_ELEMENT_NODE; + + +// helper functions; implemented below +static Reference lcl_createDomInstance(); +static Reference lcl_createElement( SvXMLImport& rImport, + sal_Int32 nElement, + const Reference& xParent); +static Reference lcl_createElement( + const OUString & rNamespace, const OUString & rName, + const Reference& xParent); + +DomBuilderContext::DomBuilderContext( SvXMLImport& rImport, + sal_Int32 nElement ) : + SvXMLImportContext( rImport ), + mxNode( lcl_createElement( rImport, nElement, + lcl_createDomInstance() ) ) +{ + SAL_WARN_IF( !mxNode.is(), "xmloff", "empty XNode not allowed" ); + SAL_WARN_IF( !Reference( mxNode, UNO_QUERY ).is(), "xmloff", "need element" ); + SAL_WARN_IF( mxNode->getNodeType() != NodeType_ELEMENT_NODE, "xmloff", "need element" ); +} + +DomBuilderContext::DomBuilderContext( SvXMLImport& rImport, + const OUString & rNamespace, const OUString & rName ) : + SvXMLImportContext( rImport ), + mxNode( lcl_createElement( rNamespace, rName, + lcl_createDomInstance() ) ) +{ + SAL_WARN_IF( !mxNode.is(), "xmloff", "empty XNode not allowed" ); + SAL_WARN_IF( !Reference( mxNode, UNO_QUERY ).is(), "xmloff", "need element" ); + SAL_WARN_IF( mxNode->getNodeType() != NodeType_ELEMENT_NODE, "xmloff", "need element" ); +} + +DomBuilderContext::DomBuilderContext( SvXMLImport& rImport, + sal_Int32 nElement, + Reference const & xParent ) : + SvXMLImportContext( rImport ), + mxNode( lcl_createElement( rImport, nElement, xParent ) ) +{ + SAL_WARN_IF( !mxNode.is(), "xmloff", "empty XNode not allowed" ); + SAL_WARN_IF( !Reference( mxNode, UNO_QUERY ).is(), "xmloff", "need element" ); + SAL_WARN_IF( mxNode->getNodeType() != NodeType_ELEMENT_NODE, "xmloff", "need element" ); +} + +DomBuilderContext::DomBuilderContext( SvXMLImport& rImport, + const OUString & rNamespace, const OUString & rName, + Reference const & xParent ) : + SvXMLImportContext( rImport ), + mxNode( lcl_createElement( rNamespace, rName, xParent ) ) +{ + SAL_WARN_IF( !mxNode.is(), "xmloff", "empty XNode not allowed" ); + SAL_WARN_IF( !Reference( mxNode, UNO_QUERY ).is(), "xmloff", "need element" ); + SAL_WARN_IF( mxNode->getNodeType() != NodeType_ELEMENT_NODE, "xmloff", "need element" ); +} + +DomBuilderContext::~DomBuilderContext() +{ +} + +Reference DomBuilderContext::getTree() +{ + SAL_WARN_IF( !mxNode.is(), "xmloff", "empty XNode not allowed" ); + return mxNode->getOwnerDocument(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > DomBuilderContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + // create DomBuilder for subtree + return new DomBuilderContext( GetImport(), nElement, mxNode ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > DomBuilderContext::createUnknownChildContext( + const OUString & rNamespace, const OUString &rName, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + // create DomBuilder for subtree + return new DomBuilderContext( GetImport(), rNamespace, rName, mxNode ); +} + +void SAL_CALL DomBuilderContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SAL_WARN_IF( !mxNode.is(), "xmloff", "empty XNode not allowed" ); + SAL_WARN_IF( !mxNode->getOwnerDocument().is(), "xmloff", "XNode must have XDocument" ); + + HandleAttributes(xAttrList); +} + +void SAL_CALL DomBuilderContext::startUnknownElement( + const OUString & /*rNamespace*/, const OUString & /*rName*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SAL_WARN_IF( !mxNode.is(), "xmloff", "empty XNode not allowed" ); + SAL_WARN_IF( !mxNode->getOwnerDocument().is(), "xmloff", "XNode must have XDocument" ); + HandleAttributes(xAttrList); +} + +void DomBuilderContext::HandleAttributes( + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // add attribute nodes to new node + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + sal_Int32 nAttrToken = aIter.getToken(); + // get name & value for attribute + sal_uInt16 nNamespace = (nAttrToken >> NMSP_SHIFT) - 1; + const OUString& rPrefix = SvXMLImport::getNamespacePrefixFromToken(nAttrToken, &GetImport().GetNamespaceMap()); + const OUString& rLocalName = SvXMLImport::getNameFromToken( nAttrToken ); + OUString aValue = aIter.toString(); + + // create attribute node and set value + Reference xElement( mxNode, UNO_QUERY_THROW ); + switch( nNamespace ) + { + case XML_NAMESPACE_NONE: + // no namespace: create a non-namespaced attribute + xElement->setAttribute( rLocalName, aValue ); + break; + case XML_NAMESPACE_XMLNS: + // namespace declaration: ignore, since the DOM tree handles these + // declarations implicitly + break; + case XML_NAMESPACE_UNKNOWN: + // unknown namespace: illegal input. Raise Warning. + { + GetImport().SetError( + XMLERROR_FLAG_WARNING | XMLERROR_NAMESPACE_TROUBLE, { rLocalName, aValue } ); + } + break; + default: + { + // a real and proper namespace: create namespaced attribute + OUString namespaceURI = SvXMLImport::getNamespaceURIFromToken(aIter.getToken()); + OUString qualifiedName = rPrefix.isEmpty() ? rLocalName : rPrefix + SvXMLImport::aNamespaceSeparator + rLocalName; + xElement->setAttributeNS( namespaceURI, qualifiedName, aValue ); + } + break; + } + } + const css::uno::Sequence< css::xml::Attribute > unknownAttribs = xAttrList->getUnknownAttributes(); + for ( const auto& rUnknownAttrib : unknownAttribs ) + { + // create attribute node and set value + Reference xElement( mxNode, UNO_QUERY_THROW ); + + if (!rUnknownAttrib.NamespaceURL.isEmpty()) + { + // unknown namespace: illegal input. Raise Warning. + GetImport().SetError( + XMLERROR_FLAG_WARNING | XMLERROR_NAMESPACE_TROUBLE, { rUnknownAttrib.Name, rUnknownAttrib.Value } ); + } + else + { + // no namespace: create a non-namespaced attribute + xElement->setAttribute( rUnknownAttrib.Name, rUnknownAttrib.Value ); + } + } +} + +void DomBuilderContext::characters( const OUString& rCharacters ) +{ + SAL_WARN_IF( !mxNode.is(), "xmloff", "empty XNode not allowed" ); + + // TODO: I assume adjacent text nodes should be joined, to preserve + // processing model? (I.e., if the SAX parser breaks a string into 2 + // Characters(..) calls, the DOM model would still see only one child.) + + // create text node and append to parent + Reference xNew( + mxNode->getOwnerDocument()->createTextNode( rCharacters ), + UNO_QUERY_THROW ); + mxNode->appendChild( xNew ); +} + + +// helper function implementations + + +static Reference lcl_createDomInstance() +{ + Reference xContext = comphelper::getProcessComponentContext(); + SAL_WARN_IF( !xContext.is(), "xmloff", "can't get service factory" ); + + Reference xBuilder( DocumentBuilder::create(xContext) ); + + return Reference( xBuilder->newDocument(), UNO_QUERY_THROW ); +} + +static Reference lcl_createElement( SvXMLImport& rImport, + sal_Int32 nElement, + const Reference& xParent) +{ + SAL_WARN_IF( !xParent.is(), "xmloff", "need parent node" ); + + Reference xDocument = xParent->getOwnerDocument(); + SAL_WARN_IF( !xDocument.is(), "xmloff", "no XDocument found!" ); + + // TODO: come up with proper way of handling namespaces; re-creating the + // namespace from the key is NOT a good idea, and will not work for + // multiple prefixes for the same namespace. Fortunately, those are rare. + + Reference xElement; + sal_uInt16 nNamespace = (nElement >> NMSP_SHIFT) - 1; + const OUString& rPrefix = SvXMLImport::getNamespacePrefixFromToken(nElement, &rImport.GetNamespaceMap()); + const OUString& rLocalName = SvXMLImport::getNameFromToken( nElement ); + switch( nNamespace ) + { + case XML_NAMESPACE_NONE: + // no namespace: use local name + xElement = xDocument->createElement( rLocalName ); + break; + case XML_NAMESPACE_XMLNS: + case XML_NAMESPACE_UNKNOWN: + // both cases are illegal; raise warning (and use only local name) + xElement = xDocument->createElement( rLocalName ); + { + Sequence aSeq { rLocalName }; + rImport.SetError( + XMLERROR_FLAG_WARNING | XMLERROR_NAMESPACE_TROUBLE, aSeq ); + } + break; + default: + // We are only given the prefix and the local name; thus we have to ask + // the namespace map to create a qualified name for us. Technically, + // this is a bug, since this will fail for multiple prefixes used for + // the same namespace. + OUString namespaceURI = SvXMLImport::getNamespaceURIFromToken(nElement); + OUString qualifiedName = rPrefix.isEmpty() ? rLocalName : rPrefix + SvXMLImport::aNamespaceSeparator + rLocalName; + xElement = xDocument->createElementNS(namespaceURI, qualifiedName); + break; + } + SAL_WARN_IF( !xElement.is(), "xmloff", "can't create element" ); + + // add new element to parent and return + xParent->appendChild( xElement ); + return xElement; +} + +static Reference lcl_createElement( + const OUString & rNamespace, const OUString & rName, + const Reference& xParent) +{ + SAL_WARN_IF( !xParent.is(), "xmloff", "need parent node" ); + + Reference xDocument = xParent->getOwnerDocument(); + SAL_WARN_IF( !xDocument.is(), "xmloff", "no XDocument found!" ); + + // TODO: come up with proper way of handling namespaces; re-creating the + // namespace from the key is NOT a good idea, and will not work for + // multiple prefixes for the same namespace. Fortunately, those are rare. + + Reference xElement; + if (rNamespace.isEmpty()) + { + // no namespace: use local name + xElement = xDocument->createElement( rName ); + } + else + { + xElement = xDocument->createElementNS(rNamespace, rName); + } + + // add new element to parent and return + xParent->appendChild( xElement ); + return xElement; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/DomExport.cxx b/xmloff/source/core/DomExport.cxx new file mode 100644 index 000000000..9d26d68b1 --- /dev/null +++ b/xmloff/source/core/DomExport.cxx @@ -0,0 +1,249 @@ +/* -*- 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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +#include + + +using com::sun::star::uno::Reference; +using com::sun::star::uno::UNO_QUERY_THROW; +using std::vector; + +using namespace com::sun::star::xml::dom; + +namespace { + +class DomVisitor +{ +public: + DomVisitor() {} + virtual ~DomVisitor() {} + virtual void element( const Reference& ) {} + virtual void character( const Reference& ) {} + virtual void endElement( const Reference& ) {} +}; + +} + +static void visit( DomVisitor&, const Reference& ); +static void visit( DomVisitor&, const Reference& ); + + +static void visitNode( DomVisitor& rVisitor, const Reference& xNode ) +{ + switch( xNode->getNodeType() ) + { + case NodeType_ATTRIBUTE_NODE: + break; + case NodeType_CDATA_SECTION_NODE: + break; + case NodeType_COMMENT_NODE: + break; + case NodeType_DOCUMENT_FRAGMENT_NODE: + break; + case NodeType_DOCUMENT_NODE: + break; + case NodeType_DOCUMENT_TYPE_NODE: + break; + case NodeType_ELEMENT_NODE: + rVisitor.element( Reference( xNode, UNO_QUERY_THROW ) ); + break; + case NodeType_ENTITY_NODE: + break; + case NodeType_ENTITY_REFERENCE_NODE: + break; + case NodeType_NOTATION_NODE: + break; + case NodeType_PROCESSING_INSTRUCTION_NODE: + break; + case NodeType_TEXT_NODE: + rVisitor.character( Reference( xNode, UNO_QUERY_THROW ) ); + break; + default: + OSL_FAIL( "unknown DOM node type" ); + break; + } +} + +void visit( DomVisitor& rVisitor, const Reference& xDocument ) +{ + visit( rVisitor, Reference( xDocument, UNO_QUERY_THROW ) ); +} + +void visit( DomVisitor& rVisitor, const Reference& xNode ) +{ + visitNode( rVisitor, xNode ); + for( Reference xChild = xNode->getFirstChild(); + xChild.is(); + xChild = xChild->getNextSibling() ) + { + visit( rVisitor, xChild ); + } + if( xNode->getNodeType() == NodeType_ELEMENT_NODE ) + rVisitor.endElement( Reference( xNode, UNO_QUERY_THROW ) ); +} + +namespace { + +class DomExport: public DomVisitor +{ + SvXMLExport& mrExport; + vector maNamespaces; + + void pushNamespace(); + void addNamespace( const OUString& sPrefix, const OUString& sURI ); + OUString qualifiedName( const OUString& sPrefix, const OUString& sURI, + std::u16string_view sLocalName ); + OUString qualifiedName( const Reference& ); + OUString qualifiedName( const Reference& ); + void addAttribute( const Reference& ); + +public: + + explicit DomExport( SvXMLExport& rExport ); + virtual ~DomExport() override; + + virtual void element( const Reference& ) override; + virtual void endElement( const Reference& ) override; + virtual void character( const Reference& ) override; +}; + +} + +DomExport::DomExport( SvXMLExport& rExport ) : + mrExport( rExport ) +{ + maNamespaces.push_back( rExport.GetNamespaceMap() ); +} + +DomExport::~DomExport() +{ + SAL_WARN_IF( maNamespaces.size() != 1, "xmloff", "namespace missing" ); + maNamespaces.clear(); +} + +void DomExport::pushNamespace() +{ + SvXMLNamespaceMap const aMap(maNamespaces.back()); + maNamespaces.push_back(aMap); +} + +void DomExport::addNamespace( const OUString& sPrefix, const OUString& sURI ) +{ + SvXMLNamespaceMap& rMap = maNamespaces.back(); + sal_uInt16 nKey = rMap.GetKeyByPrefix( sPrefix ); + + // we need to register the namespace, if either the prefix isn't known or + // is used for a different namespace + if( nKey == XML_NAMESPACE_UNKNOWN || + rMap.GetNameByKey( nKey ) != sURI ) + { + // add prefix to map, and add declaration + rMap.Add( sPrefix, sURI ); + mrExport.AddAttribute( "xmlns:" + sPrefix, sURI ); + } +} + +OUString DomExport::qualifiedName( const OUString& sPrefix, + const OUString& sURI, + std::u16string_view sLocalName ) +{ + OUStringBuffer sBuffer; + if( !sPrefix.isEmpty() && !sURI.isEmpty() ) + { + addNamespace( sPrefix, sURI ); + sBuffer.append( sPrefix ); + sBuffer.append( ':' ); + } + sBuffer.append( sLocalName ); + return sBuffer.makeStringAndClear(); +} + +OUString DomExport::qualifiedName( const Reference& xElement ) +{ + return qualifiedName( xElement->getPrefix(), xElement->getNamespaceURI(), + xElement->getNodeName() ); +} + +OUString DomExport::qualifiedName( const Reference& xAttr ) +{ + return qualifiedName( xAttr->getPrefix(), xAttr->getNamespaceURI(), + xAttr->getNodeName() ); +} + +void DomExport::addAttribute( const Reference& xAttribute ) +{ + mrExport.AddAttribute( qualifiedName( xAttribute ), + xAttribute->getNodeValue() ); +} + +void DomExport::element( const Reference& xElement ) +{ + pushNamespace(); + + // write attributes + Reference xAttributes = xElement->getAttributes(); + sal_Int32 nLength = xAttributes.is() ? xAttributes->getLength() : 0; + for( sal_Int32 n = 0; n < nLength; n++ ) + { + addAttribute( Reference( xAttributes->item( n ), UNO_QUERY_THROW ) ); + } + + // write name + mrExport.StartElement( qualifiedName( xElement ), false ); +} + +void DomExport::endElement( const Reference& xElement ) +{ + mrExport.EndElement( qualifiedName( xElement ), false ); + maNamespaces.pop_back(); +} + +void DomExport::character( const Reference& xChars ) +{ + mrExport.Characters( xChars->getNodeValue() ); +} + + +void exportDom( SvXMLExport& rExport, const Reference& xDocument ) +{ + DomExport aDomExport( rExport ); + visit( aDomExport, xDocument ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/ProgressBarHelper.cxx b/xmloff/source/core/ProgressBarHelper.cxx new file mode 100644 index 000000000..fd5c295a6 --- /dev/null +++ b/xmloff/source/core/ProgressBarHelper.cxx @@ -0,0 +1,107 @@ +/* -*- 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 + +#include + +using namespace ::com::sun::star; + +const sal_Int32 nDefaultProgressBarRange = 1000000; +const float fProgressStep = 0.5; + +ProgressBarHelper::ProgressBarHelper(const css::uno::Reference < css::task::XStatusIndicator>& xTempStatusIndicator, + const bool bTempStrict) +: xStatusIndicator(xTempStatusIndicator) +, nRange(nDefaultProgressBarRange) +, nReference(100) +, nValue(0) +, fOldPercent(0.0) +, bStrict(bTempStrict) +, bRepeat(true) +#ifdef DBG_UTIL +, bFailure(false) +#endif +{ +} + +ProgressBarHelper::~ProgressBarHelper() +{ +} + +void ProgressBarHelper::ChangeReference(sal_Int32 nNewReference) +{ + if((nNewReference <= 0) || (nNewReference == nReference)) + return; + + if (nReference) + { + double fPercent(static_cast(nNewReference) / nReference); + double fValue(nValue * fPercent); + nValue = static_cast(fValue); + nReference = nNewReference; + } + else + { + nReference = nNewReference; + nValue = 0; + } +} + +void ProgressBarHelper::SetValue(sal_Int32 nTempValue) +{ + if (!xStatusIndicator.is() || (nReference <= 0)) + return; + + if ((nTempValue >= nValue) && (!bStrict || (nTempValue <= nReference))) + { + // #91317# no progress bar with values > 100% + if (nTempValue > nReference) + { + if (!bRepeat) + nValue = nReference; + else + { + xStatusIndicator->reset(); + nValue = 0; + } + } + else + nValue = nTempValue; + + double fValue(nValue); + double fNewValue ((fValue * nRange) / nReference); + + double fPercent((fNewValue * 100) / nRange); + if (fPercent >= (fOldPercent + fProgressStep) || fPercent < fOldPercent) + { + xStatusIndicator->setValue(static_cast(fNewValue)); + fOldPercent = fPercent; + } + } +#ifdef DBG_UTIL + else if (!bFailure) + { + OSL_FAIL("tried to set a wrong value on the progressbar"); + bFailure = true; + } +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/PropertySetMerger.cxx b/xmloff/source/core/PropertySetMerger.cxx new file mode 100644 index 000000000..7663aef63 --- /dev/null +++ b/xmloff/source/core/PropertySetMerger.cxx @@ -0,0 +1,231 @@ +/* -*- 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 +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +#include +#include + +namespace { + +class PropertySetMergerImpl : public ::cppu::WeakAggImplHelper3< XPropertySet, XPropertyState, XPropertySetInfo > +{ +private: + Reference< XPropertySet > mxPropSet1; + Reference< XPropertyState > mxPropSet1State; + Reference< XPropertySetInfo > mxPropSet1Info; + + Reference< XPropertySet > mxPropSet2; + Reference< XPropertyState > mxPropSet2State; + Reference< XPropertySetInfo > mxPropSet2Info; + +public: + PropertySetMergerImpl( const Reference< XPropertySet > & rPropSet1, const Reference< XPropertySet > & rPropSet2 ); + + // XPropertySet + virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) override; + virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) override; + + // XPropertyState + virtual PropertyState SAL_CALL getPropertyState( const OUString& PropertyName ) override; + virtual Sequence< PropertyState > SAL_CALL getPropertyStates( const Sequence< OUString >& aPropertyName ) override; + virtual void SAL_CALL setPropertyToDefault( const OUString& PropertyName ) override; + virtual Any SAL_CALL getPropertyDefault( const OUString& aPropertyName ) override; + + // XPropertySetInfo + virtual Sequence< Property > SAL_CALL getProperties( ) override; + virtual Property SAL_CALL getPropertyByName( const OUString& aName ) override; + virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override; +}; + +} + +// Interface implementation + +PropertySetMergerImpl::PropertySetMergerImpl( Reference< XPropertySet > const & rPropSet1, Reference< XPropertySet > const & rPropSet2 ) +: mxPropSet1( rPropSet1 ) +, mxPropSet1State( rPropSet1, UNO_QUERY ) +, mxPropSet1Info( rPropSet1->getPropertySetInfo() ) +, mxPropSet2( rPropSet2 ) +, mxPropSet2State( rPropSet2, UNO_QUERY ) +, mxPropSet2Info( rPropSet2->getPropertySetInfo() ) +{ +} + +// XPropertySet +Reference< XPropertySetInfo > SAL_CALL PropertySetMergerImpl::getPropertySetInfo( ) +{ + return this; +} + +void SAL_CALL PropertySetMergerImpl::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) +{ + if( mxPropSet1Info->hasPropertyByName( aPropertyName ) ) + { + mxPropSet1->setPropertyValue( aPropertyName, aValue ); + } + else + { + mxPropSet2->setPropertyValue( aPropertyName, aValue ); + } +} + +Any SAL_CALL PropertySetMergerImpl::getPropertyValue( const OUString& PropertyName ) +{ + if( mxPropSet1Info->hasPropertyByName( PropertyName ) ) + { + return mxPropSet1->getPropertyValue( PropertyName ); + } + else + { + return mxPropSet2->getPropertyValue( PropertyName ); + } +} + +void SAL_CALL PropertySetMergerImpl::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ ) +{ +} + +void SAL_CALL PropertySetMergerImpl::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*aListener*/ ) +{ +} + +void SAL_CALL PropertySetMergerImpl::addVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ ) +{ +} + +void SAL_CALL PropertySetMergerImpl::removeVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ ) +{ +} + +// XPropertyState +PropertyState SAL_CALL PropertySetMergerImpl::getPropertyState( const OUString& PropertyName ) +{ + if( mxPropSet1Info->hasPropertyByName( PropertyName ) ) + { + if( mxPropSet1State.is() ) + { + return mxPropSet1State->getPropertyState( PropertyName ); + } + else + { + return PropertyState_DIRECT_VALUE; + } + } + else + { + if( mxPropSet2State.is() ) + { + return mxPropSet2State->getPropertyState( PropertyName ); + } + else + { + return PropertyState_DIRECT_VALUE; + } + } +} + +Sequence< PropertyState > SAL_CALL PropertySetMergerImpl::getPropertyStates( const Sequence< OUString >& aPropertyName ) +{ + const sal_Int32 nCount = aPropertyName.getLength(); + Sequence< PropertyState > aPropStates( nCount ); + + std::transform(aPropertyName.begin(), aPropertyName.end(), aPropStates.getArray(), + [this](const OUString& rPropName) -> PropertyState { return getPropertyState(rPropName); }); + + return aPropStates; +} + +void SAL_CALL PropertySetMergerImpl::setPropertyToDefault( const OUString& PropertyName ) +{ + if( mxPropSet1State.is() && mxPropSet1Info->hasPropertyByName( PropertyName ) ) + { + mxPropSet1State->setPropertyToDefault( PropertyName ); + } + else + { + if( mxPropSet2State.is() ) + { + mxPropSet2State->setPropertyToDefault( PropertyName ); + } + } +} + +Any SAL_CALL PropertySetMergerImpl::getPropertyDefault( const OUString& aPropertyName ) +{ + if( mxPropSet1State.is() && mxPropSet1Info->hasPropertyByName( aPropertyName ) ) + { + return mxPropSet1State->getPropertyDefault( aPropertyName ); + } + else + { + if( mxPropSet2State.is() ) + { + return mxPropSet2State->getPropertyDefault( aPropertyName ); + } + else + { + Any aAny; + return aAny; + } + } +} + +// XPropertySetInfo +Sequence< Property > SAL_CALL PropertySetMergerImpl::getProperties() +{ + Sequence< Property > aProps1( mxPropSet1Info->getProperties() ); + Sequence< Property > aProps2( mxPropSet2Info->getProperties() ); + + return comphelper::concatSequences(aProps1, aProps2); +} + +Property SAL_CALL PropertySetMergerImpl::getPropertyByName( const OUString& aName ) +{ + if( mxPropSet1Info->hasPropertyByName( aName ) ) + return mxPropSet1Info->getPropertyByName( aName ); + + return mxPropSet2Info->getPropertyByName( aName ); +} + +sal_Bool SAL_CALL PropertySetMergerImpl::hasPropertyByName( const OUString& Name ) +{ + if(mxPropSet1Info->hasPropertyByName( Name ) ) + return true; + + return mxPropSet2Info->hasPropertyByName( Name ); +} + +Reference< XPropertySet > PropertySetMerger_CreateInstance( const Reference< XPropertySet >& rPropSet1, const Reference< XPropertySet >& rPropSet2 ) noexcept +{ + return new PropertySetMergerImpl( rPropSet1, rPropSet2 ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/RDFaExportHelper.cxx b/xmloff/source/core/RDFaExportHelper.cxx new file mode 100644 index 000000000..25238d5fa --- /dev/null +++ b/xmloff/source/core/RDFaExportHelper.cxx @@ -0,0 +1,180 @@ +/* -*- 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 + +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +using namespace ::com::sun::star; + +namespace xmloff { + +static OUString +makeCURIE(SvXMLExport * i_pExport, + uno::Reference const & i_xURI) +{ + OSL_ENSURE(i_xURI.is(), "makeCURIE: null URI"); + if (!i_xURI.is()) throw uno::RuntimeException(); + + const OUString Namespace( i_xURI->getNamespace() ); + OSL_ENSURE(!Namespace.isEmpty(), "makeCURIE: no namespace"); + if (Namespace.isEmpty()) throw uno::RuntimeException(); + + // N.B.: empty LocalName is valid! + return i_pExport->EnsureNamespace(Namespace) + ":" + i_xURI->getLocalName(); +} + +// #i112473# SvXMLExport::GetRelativeReference() not right for RDF on SaveAs +// because the URIs in the repository are not rewritten on SaveAs, the +// URI of the loaded document has to be used, not the URI of the target doc. +static OUString +getRelativeReference(SvXMLExport const& rExport, OUString const& rURI) +{ + uno::Reference< rdf::XURI > const xModelURI( + rExport.GetModel(), uno::UNO_QUERY_THROW ); + OUString const baseURI( xModelURI->getStringValue() ); + + uno::Reference xContext( comphelper::getProcessComponentContext() ); + uno::Reference const xUriFactory = + uri::UriReferenceFactory::create( xContext ); + + uno::Reference< uri::XUriReference > const xBaseURI( + xUriFactory->parse(baseURI), uno::UNO_SET_THROW ); + uno::Reference< uri::XUriReference > const xAbsoluteURI( + xUriFactory->parse(rURI), uno::UNO_SET_THROW ); + uno::Reference< uri::XUriReference > const xRelativeURI( + xUriFactory->makeRelative(xBaseURI, xAbsoluteURI, true, true, false), + uno::UNO_SET_THROW ); + OUString const relativeURI(xRelativeURI->getUriReference()); + + return relativeURI; +} + +RDFaExportHelper::RDFaExportHelper(SvXMLExport & i_rExport) + : m_rExport(i_rExport), m_Counter(0) +{ + const uno::Reference xRS( m_rExport.GetModel(), + uno::UNO_QUERY_THROW); + m_xRepository.set(xRS->getRDFRepository(), uno::UNO_QUERY_THROW); +} + +OUString +RDFaExportHelper::LookupBlankNode( + uno::Reference const & i_xBlankNode) +{ + OSL_ENSURE(i_xBlankNode.is(), "null BlankNode?"); + if (!i_xBlankNode.is()) throw uno::RuntimeException(); + OUString & rEntry( + m_BlankNodeMap[ i_xBlankNode->getStringValue() ] ); + if (rEntry.isEmpty()) + { + rEntry = "_:b" + OUString::number(++m_Counter); + } + return rEntry; +} + +void +RDFaExportHelper::AddRDFa( + uno::Reference const & i_xMetadatable) +{ + try + { + beans::Pair< uno::Sequence, sal_Bool > const + RDFaResult( m_xRepository->getStatementRDFa(i_xMetadatable) ); + + uno::Sequence const & rStatements( RDFaResult.First ); + + if (!rStatements.hasElements()) + { + return; // no RDFa + } + + // all stmts have the same subject, so we only handle first one + const uno::Reference xSubjectURI(rStatements[0].Subject, + uno::UNO_QUERY); + const uno::Reference xSubjectBNode( + rStatements[0].Subject, uno::UNO_QUERY); + if (!xSubjectURI.is() && !xSubjectBNode.is()) + { + throw uno::RuntimeException(); + } + const OUString about( xSubjectURI.is() + ? getRelativeReference(m_rExport, xSubjectURI->getStringValue()) + : "[" + LookupBlankNode(xSubjectBNode) + "]" + ); + + const uno::Reference xContent( + rStatements[0].Object, uno::UNO_QUERY_THROW ); + const uno::Reference xDatatype(xContent->getDatatype()); + if (xDatatype.is()) + { + const OUString datatype( + makeCURIE(&m_rExport, xDatatype) ); + m_rExport.AddAttribute(XML_NAMESPACE_XHTML, + token::XML_DATATYPE, datatype); + } + if (RDFaResult.Second) // there is xhtml:content + { + m_rExport.AddAttribute(XML_NAMESPACE_XHTML, token::XML_CONTENT, + xContent->getValue()); + } + + ::std::vector curies; + for (rdf::Statement const& rStatement : rStatements) + { + curies.push_back(makeCURIE(&m_rExport, rStatement.Predicate)); + } + OUStringBuffer property; + ::comphelper::intersperse(curies.begin(), curies.end(), + ::comphelper::OUStringBufferAppender(property), + OUString(" ")); + + m_rExport.AddAttribute(XML_NAMESPACE_XHTML, token::XML_PROPERTY, + property.makeStringAndClear()); + + m_rExport.AddAttribute(XML_NAMESPACE_XHTML, token::XML_ABOUT, about); + } + catch (uno::Exception &) + { + TOOLS_WARN_EXCEPTION("xmloff.core", ""); + } +} + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/RDFaImportHelper.cxx b/xmloff/source/core/RDFaImportHelper.cxx new file mode 100644 index 000000000..0dddb8822 --- /dev/null +++ b/xmloff/source/core/RDFaImportHelper.cxx @@ -0,0 +1,449 @@ +/* -*- 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 + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +using namespace ::com::sun::star; + +namespace xmloff { + +namespace { + +/** a bit of context for parsing RDFa attributes */ +class RDFaReader +{ + const SvXMLImport & m_rImport; + + const SvXMLImport & GetImport() const { return m_rImport; } + + //FIXME: this is an ugly hack to workaround buggy SvXMLImport::GetAbsolute + OUString GetAbsoluteReference(OUString const & i_rURI) const + { + if (i_rURI.isEmpty() || i_rURI[0] == '#') + { + return GetImport().GetBaseURL() + i_rURI; + } + else + { + return GetImport().GetAbsoluteReference(i_rURI); + } + } + +public: + explicit RDFaReader(SvXMLImport const & i_rImport) + : m_rImport(i_rImport) + { } + + // returns URI or blank node! + OUString ReadCURIE(OUString const & i_rCURIE) const; + + std::vector< OUString > + ReadCURIEs(OUString const & i_rCURIEs) const; + + OUString + ReadURIOrSafeCURIE( OUString const & i_rURIOrSafeCURIE) const; +}; + +/** helper to insert RDFa statements into the RDF repository */ +class RDFaInserter +{ + const uno::Reference m_xContext; + uno::Reference< rdf::XDocumentRepository > m_xRepository; + + typedef ::std::map< OUString, uno::Reference< rdf::XBlankNode > > + BlankNodeMap_t; + + BlankNodeMap_t m_BlankNodeMap; + +public: + RDFaInserter(uno::Reference const & i_xContext, + uno::Reference< rdf::XDocumentRepository > const & i_xRepository) + : m_xContext(i_xContext) + , m_xRepository(i_xRepository) + {} + + uno::Reference< rdf::XBlankNode > + LookupBlankNode(OUString const & i_rNodeId ); + + uno::Reference< rdf::XURI > + MakeURI( OUString const & i_rURI) const; + + uno::Reference< rdf::XResource> + MakeResource( OUString const & i_rResource); + + void InsertRDFaEntry(struct RDFaEntry const & i_rEntry); +}; + +} + +/** store parsed RDFa attributes */ +struct ParsedRDFaAttributes +{ + OUString m_About; + ::std::vector< OUString > m_Properties; + OUString m_Content; + OUString m_Datatype; + + ParsedRDFaAttributes( + OUString const & i_rAbout, + ::std::vector< OUString >&& i_rProperties, + OUString const & i_rContent, + OUString const & i_rDatatype) + : m_About(i_rAbout) + , m_Properties(std::move(i_rProperties)) + , m_Content(i_rContent) + , m_Datatype(i_rDatatype) + { } +}; + +/** store metadatable object and its RDFa attributes */ +struct RDFaEntry +{ + uno::Reference m_xObject; + std::shared_ptr m_xRDFaAttributes; + + RDFaEntry(uno::Reference const & i_xObject, + std::shared_ptr const& i_pRDFaAttributes) + : m_xObject(i_xObject) + , m_xRDFaAttributes(i_pRDFaAttributes) + { } +}; + +static bool isWS(const sal_Unicode i_Char) +{ + return ('\t' == i_Char) || ('\n' == i_Char) || ('\r' == i_Char) + || (' ' == i_Char); +} + +static OUString splitAtWS(OUString & io_rString) +{ + const sal_Int32 len( io_rString.getLength() ); + sal_Int32 idxstt(0); + while ((idxstt < len) && ( isWS(io_rString[idxstt]))) + ++idxstt; // skip leading ws + sal_Int32 idxend(idxstt); + while ((idxend < len) && (!isWS(io_rString[idxend]))) + ++idxend; // the CURIE + const OUString ret(io_rString.copy(idxstt, idxend - idxstt)); + io_rString = io_rString.copy(idxend); // rest + return ret; +} + +OUString +RDFaReader::ReadCURIE(OUString const & i_rCURIE) const +{ + // the RDFa spec says that a prefix is required (it may be empty: ":foo") + const sal_Int32 idx( i_rCURIE.indexOf(':') ); + if (idx >= 0) + { + OUString Prefix; + OUString LocalName; + OUString Namespace; + // LocalName may contain ':', see "ipchar" in RFC 3987 + sal_uInt16 nKey( GetImport().GetNamespaceMap().GetKeyByQName( + i_rCURIE, &Prefix, &LocalName, &Namespace, SvXMLNamespaceMap::QNameMode::AttrValue) ); + if ( Prefix == "_" ) + { + // eeek, it's a bnode! + // "_" is not a valid URI scheme => we can identify bnodes + return i_rCURIE; + } + else + { + SAL_WARN_IF(XML_NAMESPACE_NONE == nKey, "xmloff.core", "no namespace?"); + if ((XML_NAMESPACE_UNKNOWN != nKey) && + (XML_NAMESPACE_XMLNS != nKey)) + { + // N.B.: empty LocalName is valid! + const OUString URI(Namespace + LocalName); + return GetAbsoluteReference(URI); + } + else + { + SAL_INFO("xmloff.core", "ReadCURIE: invalid CURIE: invalid prefix" ); + return OUString(); + } + } + } + SAL_INFO("xmloff.core", "ReadCURIE: invalid CURIE: no prefix" ); + return OUString(); +} + +::std::vector< OUString > +RDFaReader::ReadCURIEs(OUString const & i_rCURIEs) const +{ + std::vector< OUString > vec; + OUString CURIEs(i_rCURIEs); + do { + OUString curie( splitAtWS(CURIEs) ); + if (!curie.isEmpty()) + { + const OUString uri(ReadCURIE(curie)); + if (!uri.isEmpty()) + { + vec.push_back(uri); + } + } + } + while (!CURIEs.isEmpty()); + if (vec.empty()) + { + SAL_INFO("xmloff.core", "ReadCURIEs: invalid CURIEs" ); + } + return vec; +} + +OUString +RDFaReader::ReadURIOrSafeCURIE(OUString const & i_rURIOrSafeCURIE) const +{ + const sal_Int32 len(i_rURIOrSafeCURIE.getLength()); + if (len && (i_rURIOrSafeCURIE[0] == '[')) + { + if ((len >= 2) && (i_rURIOrSafeCURIE[len - 1] == ']')) + { + return ReadCURIE(i_rURIOrSafeCURIE.copy(1, len - 2)); + } + else + { + SAL_INFO("xmloff.core", "ReadURIOrSafeCURIE: invalid SafeCURIE" ); + return OUString(); + } + } + else + { + if (i_rURIOrSafeCURIE.startsWith("_:")) // blank node + { + SAL_INFO("xmloff.core", "ReadURIOrSafeCURIE: invalid URI: scheme is _" ); + return OUString(); + } + else + { + return GetAbsoluteReference(i_rURIOrSafeCURIE); + } + } +} + +uno::Reference< rdf::XBlankNode > +RDFaInserter::LookupBlankNode(OUString const & i_rNodeId ) +{ + uno::Reference< rdf::XBlankNode > & rEntry( m_BlankNodeMap[ i_rNodeId ] ); + if (!rEntry.is()) + { + rEntry = m_xRepository->createBlankNode(); + } + return rEntry; +} + +uno::Reference< rdf::XURI > +RDFaInserter::MakeURI( OUString const & i_rURI) const +{ + if (i_rURI.startsWith("_:")) // blank node + { + SAL_INFO("xmloff.core", "MakeURI: cannot create URI for blank node"); + return nullptr; + } + else + { + try + { + return rdf::URI::create( m_xContext, i_rURI ); + } + catch (uno::Exception &) + { + SAL_WARN("xmloff.core", "MakeURI: cannot create URI"); + return nullptr; + } + } +} + +uno::Reference +RDFaInserter::MakeResource( OUString const & i_rResource) +{ + if (i_rResource.startsWith("_:")) // blank node + { + // we cannot use the blank node label as-is: it must be distinct + // from labels in other graphs, so create fresh ones per XML stream + // N.B.: content.xml and styles.xml are distinct graphs + OUString name( i_rResource.copy(2) ); + const uno::Reference< rdf::XBlankNode > xBNode( LookupBlankNode(name) ); + SAL_WARN_IF(!xBNode.is(), "xmloff.core", "no blank node?"); + return xBNode; + } + else + { + return MakeURI( i_rResource ); + } +} + +void RDFaInserter::InsertRDFaEntry( + struct RDFaEntry const & i_rEntry) +{ + SAL_WARN_IF(!i_rEntry.m_xObject.is(), "xmloff.core", "InsertRDFaEntry: invalid arg: null object"); + if (!i_rEntry.m_xObject.is()) return; + + const uno::Reference< rdf::XResource > xSubject( + MakeResource( i_rEntry.m_xRDFaAttributes->m_About ) ); + if (!xSubject.is()) + { + return; // invalid + } + + ::std::vector< uno::Reference< rdf::XURI > > predicates; + + predicates.reserve(i_rEntry.m_xRDFaAttributes->m_Properties.size()); + + for (OUString const& prop : i_rEntry.m_xRDFaAttributes->m_Properties) + { + auto const xURI(MakeURI(prop)); + if (xURI.is()) + { + predicates.push_back(xURI); + } + } + + if (predicates.empty()) + { + return; // invalid + } + + uno::Reference xDatatype; + if (!i_rEntry.m_xRDFaAttributes->m_Datatype.isEmpty()) + { + xDatatype = MakeURI( i_rEntry.m_xRDFaAttributes->m_Datatype ); + } + + try + { + // N.B.: this will call xMeta->ensureMetadataReference, which is why + // this must be done _after_ importing the whole XML file, + // to prevent collision between generated ids and ids in the file + m_xRepository->setStatementRDFa(xSubject, comphelper::containerToSequence(predicates), + i_rEntry.m_xObject, + i_rEntry.m_xRDFaAttributes->m_Content, xDatatype); + } + catch (uno::Exception &) + { + SAL_WARN("xmloff.core", "InsertRDFaEntry: setStatementRDFa failed?"); + } +} + +RDFaImportHelper::RDFaImportHelper(const SvXMLImport & i_rImport) + : m_rImport(i_rImport) +{ +} + +RDFaImportHelper::~RDFaImportHelper() +{ +} + +std::shared_ptr +RDFaImportHelper::ParseRDFa( + OUString const & i_rAbout, + OUString const & i_rProperty, + OUString const & i_rContent, + OUString const & i_rDatatype) +{ + if (i_rProperty.isEmpty()) + { + SAL_INFO("xmloff.core", "AddRDFa: invalid input: xhtml:property empty"); + return std::shared_ptr(); + } + // must parse CURIEs here: need namespace declaration context + RDFaReader reader(GetImport()); + const OUString about( reader.ReadURIOrSafeCURIE(i_rAbout) ); + if (about.isEmpty()) { + return std::shared_ptr(); + } + ::std::vector< OUString > properties( + reader.ReadCURIEs(i_rProperty) ); + if (properties.empty()) { + return std::shared_ptr(); + } + const OUString datatype( !i_rDatatype.isEmpty() + ? reader.ReadCURIE(i_rDatatype) + : OUString() ); + return std::make_shared( + about, std::move(properties), i_rContent, datatype); +} + +void +RDFaImportHelper::AddRDFa( + uno::Reference const & i_xObject, + std::shared_ptr const & i_pRDFaAttributes) +{ + if (!i_xObject.is()) + { + SAL_WARN("xmloff.core", "AddRDFa: invalid arg: null textcontent"); + return; + } + if (!i_pRDFaAttributes) + { + SAL_WARN("xmloff.core", "AddRDFa: invalid arg: null RDFa attributes"); + return; + } + m_RDFaEntries.emplace_back(i_xObject, i_pRDFaAttributes); +} + +void +RDFaImportHelper::ParseAndAddRDFa( + uno::Reference const & i_xObject, + OUString const & i_rAbout, + OUString const & i_rProperty, + OUString const & i_rContent, + OUString const & i_rDatatype) +{ + std::shared_ptr pAttributes( + ParseRDFa(i_rAbout, i_rProperty, i_rContent, i_rDatatype) ); + if (pAttributes) + { + AddRDFa(i_xObject, pAttributes); + } +} + +void RDFaImportHelper::InsertRDFa( + uno::Reference< rdf::XRepositorySupplier> const & i_xModel) +{ + SAL_WARN_IF(!i_xModel.is(), "xmloff.core", "InsertRDFa: invalid arg: model null"); + if (!i_xModel.is()) return; + const uno::Reference< rdf::XDocumentRepository > xRepository( + i_xModel->getRDFRepository(), uno::UNO_QUERY); + SAL_WARN_IF(!xRepository.is(), "xmloff.core", "InsertRDFa: no DocumentRepository?"); + if (!xRepository.is()) return; + RDFaInserter inserter(GetImport().GetComponentContext(), xRepository); + for (const auto& RDFaEntry : m_RDFaEntries) + inserter.InsertRDFaEntry(RDFaEntry); +} + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/SettingsExportHelper.cxx b/xmloff/source/core/SettingsExportHelper.cxx new file mode 100644 index 000000000..9f0444d8f --- /dev/null +++ b/xmloff/source/core/SettingsExportHelper.cxx @@ -0,0 +1,518 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xmlenums.hxx" + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +constexpr OUStringLiteral gsPrinterIndependentLayout( u"PrinterIndependentLayout" ); +constexpr OUStringLiteral gsColorTableURL( u"ColorTableURL" ); +constexpr OUStringLiteral gsLineEndTableURL( u"LineEndTableURL" ); +constexpr OUStringLiteral gsHatchTableURL( u"HatchTableURL" ); +constexpr OUStringLiteral gsDashTableURL( u"DashTableURL" ); +constexpr OUStringLiteral gsGradientTableURL( u"GradientTableURL" ); +constexpr OUStringLiteral gsBitmapTableURL( u"BitmapTableURL" ); + +XMLSettingsExportHelper::XMLSettingsExportHelper( ::xmloff::XMLSettingsExportContext& i_rContext ) +: m_rContext( i_rContext ) +{ +} + +XMLSettingsExportHelper::~XMLSettingsExportHelper() +{ +} + +void XMLSettingsExportHelper::CallTypeFunction(const uno::Any& rAny, + const OUString& rName) const +{ + uno::Any aAny( rAny ); + ManipulateSetting( aAny, rName ); + + uno::TypeClass eClass = aAny.getValueTypeClass(); + switch (eClass) + { + case uno::TypeClass_VOID: + { + /* + * This assertion pops up when exporting values which are set to: + * PropertyAttribute::MAYBEVOID, and thus are _supposed_ to have + * a VOID value...so I'm removing it ...mtg + * OSL_FAIL("no type"); + */ + } + break; + case uno::TypeClass_BOOLEAN: + { + exportBool(::cppu::any2bool(aAny), rName); + } + break; + case uno::TypeClass_BYTE: + { + exportByte(); + } + break; + case uno::TypeClass_SHORT: + { + sal_Int16 nInt16 = 0; + aAny >>= nInt16; + exportShort(nInt16, rName); + } + break; + case uno::TypeClass_LONG: + { + sal_Int32 nInt32 = 0; + aAny >>= nInt32; + exportInt(nInt32, rName); + } + break; + case uno::TypeClass_HYPER: + { + sal_Int64 nInt64 = 0; + aAny >>= nInt64; + exportLong(nInt64, rName); + } + break; + case uno::TypeClass_DOUBLE: + { + double fDouble = 0.0; + aAny >>= fDouble; + exportDouble(fDouble, rName); + } + break; + case uno::TypeClass_STRING: + { + OUString sString; + aAny >>= sString; + exportString(sString, rName); + } + break; + default: + { + const uno::Type& aType = aAny.getValueType(); + if (aType.equals(cppu::UnoType>::get() ) ) + { + uno::Sequence< beans::PropertyValue> aProps; + aAny >>= aProps; + exportSequencePropertyValue(aProps, rName); + } + else if( aType.equals(cppu::UnoType>::get() ) ) + { + uno::Sequence< sal_Int8 > aProps; + aAny >>= aProps; + exportbase64Binary(aProps, rName); + } + else if (aType.equals(cppu::UnoType::get()) || + aType.equals(cppu::UnoType::get())) + { + uno::Reference< container::XNameAccess> aNamed; + aAny >>= aNamed; + exportNameAccess(aNamed, rName); + } + else if (aType.equals(cppu::UnoType::get()) || + aType.equals(cppu::UnoType::get()) ) + { + uno::Reference aIndexed; + aAny >>= aIndexed; + exportIndexAccess(aIndexed, rName); + } + else if (aType.equals(cppu::UnoType::get()) ) + { + util::DateTime aDateTime; + aAny >>= aDateTime; + exportDateTime(aDateTime, rName); + } + else if( aType.equals(cppu::UnoType::get()) ) + { + exportForbiddenCharacters( aAny, rName ); + } + else if( aType.equals(cppu::UnoType>::get() ) ) + { + uno::Sequence< formula::SymbolDescriptor > aProps; + aAny >>= aProps; + exportSymbolDescriptors(aProps, rName); + } + else { + OSL_FAIL("this type is not implemented now"); + } + } + break; + } +} + +void XMLSettingsExportHelper::exportBool(const bool bValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_BOOLEAN ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + OUString sValue; + if (bValue) + sValue = GetXMLToken(XML_TRUE); + else + sValue = GetXMLToken(XML_FALSE); + m_rContext.Characters( sValue ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportByte() +{ + OSL_ENSURE(false, "XMLSettingsExportHelper::exportByte(): #i114162#:\n" + "config-items of type \"byte\" are not valid ODF, " + "so storing them is disabled!\n" + "Use a different type instead (e.g. \"short\")."); +} +void XMLSettingsExportHelper::exportShort(const sal_Int16 nValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_SHORT ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + m_rContext.Characters( OUString::number(nValue) ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportInt(const sal_Int32 nValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_INT ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + m_rContext.Characters( OUString::number(nValue) ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportLong(const sal_Int64 nValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_LONG ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + m_rContext.Characters( OUString::number(nValue) ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportDouble(const double fValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_DOUBLE ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + OUStringBuffer sBuffer; + ::sax::Converter::convertDouble(sBuffer, fValue); + m_rContext.Characters( sBuffer.makeStringAndClear() ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportString(const OUString& sValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_STRING ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + if (!sValue.isEmpty()) + m_rContext.Characters( sValue ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportDateTime(const util::DateTime& aValue, const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_DATETIME ); + OUStringBuffer sBuffer; + ::sax::Converter::convertDateTime(sBuffer, aValue, nullptr); + m_rContext.StartElement( XML_CONFIG_ITEM ); + m_rContext.Characters( sBuffer.makeStringAndClear() ); + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportSequencePropertyValue( + const uno::Sequence& aProps, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + if(aProps.hasElements()) + { + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.StartElement( XML_CONFIG_ITEM_SET ); + for (const auto& rProp : aProps) + CallTypeFunction(rProp.Value, rProp.Name); + m_rContext.EndElement( true ); + } +} +void XMLSettingsExportHelper::exportSymbolDescriptors( + const uno::Sequence < formula::SymbolDescriptor > &rProps, + const OUString& rName) const +{ + rtl::Reference< comphelper::IndexedPropertyValuesContainer > xBox = new comphelper::IndexedPropertyValuesContainer(); + + static const OUStringLiteral sName ( u"Name" ); + static const OUStringLiteral sExportName ( u"ExportName" ); + static const OUStringLiteral sSymbolSet ( u"SymbolSet" ); + static const OUStringLiteral sCharacter ( u"Character" ); + static const OUStringLiteral sFontName ( u"FontName" ); + static const OUStringLiteral sCharSet ( u"CharSet" ); + static const OUStringLiteral sFamily ( u"Family" ); + static const OUStringLiteral sPitch ( u"Pitch" ); + static const OUStringLiteral sWeight ( u"Weight" ); + static const OUStringLiteral sItalic ( u"Italic" ); + + sal_Int32 nCount = rProps.getLength(); + const formula::SymbolDescriptor *pDescriptor = rProps.getConstArray(); + + for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++, pDescriptor++ ) + { + uno::Sequence < beans::PropertyValue > aSequence ( XML_SYMBOL_DESCRIPTOR_MAX ); + beans::PropertyValue *pSymbol = aSequence.getArray(); + + pSymbol[XML_SYMBOL_DESCRIPTOR_NAME].Name = sName; + pSymbol[XML_SYMBOL_DESCRIPTOR_NAME].Value <<= pDescriptor->sName; + pSymbol[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME].Name = sExportName; + pSymbol[XML_SYMBOL_DESCRIPTOR_EXPORT_NAME].Value<<= pDescriptor->sExportName; + pSymbol[XML_SYMBOL_DESCRIPTOR_FONT_NAME].Name = sFontName; + pSymbol[XML_SYMBOL_DESCRIPTOR_FONT_NAME].Value <<= pDescriptor->sFontName; + pSymbol[XML_SYMBOL_DESCRIPTOR_CHAR_SET].Name = sCharSet; + pSymbol[XML_SYMBOL_DESCRIPTOR_CHAR_SET].Value <<= pDescriptor->nCharSet; + pSymbol[XML_SYMBOL_DESCRIPTOR_FAMILY].Name = sFamily; + pSymbol[XML_SYMBOL_DESCRIPTOR_FAMILY].Value <<= pDescriptor->nFamily; + pSymbol[XML_SYMBOL_DESCRIPTOR_PITCH].Name = sPitch; + pSymbol[XML_SYMBOL_DESCRIPTOR_PITCH].Value <<= pDescriptor->nPitch; + pSymbol[XML_SYMBOL_DESCRIPTOR_WEIGHT].Name = sWeight; + pSymbol[XML_SYMBOL_DESCRIPTOR_WEIGHT].Value <<= pDescriptor->nWeight; + pSymbol[XML_SYMBOL_DESCRIPTOR_ITALIC].Name = sItalic; + pSymbol[XML_SYMBOL_DESCRIPTOR_ITALIC].Value <<= pDescriptor->nItalic; + pSymbol[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET].Name = sSymbolSet; + pSymbol[XML_SYMBOL_DESCRIPTOR_SYMBOL_SET].Value <<= pDescriptor->sSymbolSet; + pSymbol[XML_SYMBOL_DESCRIPTOR_CHARACTER].Name = sCharacter; + pSymbol[XML_SYMBOL_DESCRIPTOR_CHARACTER].Value <<= pDescriptor->nCharacter; + + xBox->insertByIndex(nIndex, uno::Any( aSequence )); + } + + exportIndexAccess( xBox, rName ); +} +void XMLSettingsExportHelper::exportbase64Binary( + const uno::Sequence& aProps, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.AddAttribute( XML_TYPE, XML_BASE64BINARY ); + m_rContext.StartElement( XML_CONFIG_ITEM ); + if(aProps.hasElements()) + { + OUStringBuffer sBuffer; + ::comphelper::Base64::encode(sBuffer, aProps); + m_rContext.Characters( sBuffer.makeStringAndClear() ); + } + m_rContext.EndElement( false ); +} + +void XMLSettingsExportHelper::exportMapEntry(const uno::Any& rAny, + const OUString& rName, + const bool bNameAccess) const +{ + DBG_ASSERT((bNameAccess && !rName.isEmpty()) || !bNameAccess, "no name"); + uno::Sequence aProps; + rAny >>= aProps; + if (aProps.hasElements()) + { + if (bNameAccess) + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.StartElement( XML_CONFIG_ITEM_MAP_ENTRY ); + for (const auto& rProp : std::as_const(aProps)) + CallTypeFunction(rProp.Value, rProp.Name); + m_rContext.EndElement( true ); + } +} + +void XMLSettingsExportHelper::exportNameAccess( + const uno::Reference& aNamed, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + DBG_ASSERT(aNamed->getElementType().equals(cppu::UnoType>::get() ), + "wrong NameAccess" ); + if(aNamed->hasElements()) + { + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.StartElement( XML_CONFIG_ITEM_MAP_NAMED ); + const uno::Sequence< OUString > aNames(aNamed->getElementNames()); + for (const auto& rElementName : aNames) + exportMapEntry(aNamed->getByName(rElementName), rElementName, true); + m_rContext.EndElement( true ); + } +} + +void XMLSettingsExportHelper::exportIndexAccess( + const uno::Reference& rIndexed, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + DBG_ASSERT(rIndexed->getElementType().equals(cppu::UnoType>::get() ), + "wrong IndexAccess" ); + if (rIndexed->hasElements()) + { + m_rContext.AddAttribute( XML_NAME, rName ); + m_rContext.StartElement( XML_CONFIG_ITEM_MAP_INDEXED ); + sal_Int32 nCount = rIndexed->getCount(); + for (sal_Int32 i = 0; i < nCount; i++) + { + exportMapEntry(rIndexed->getByIndex(i), "", false); + } + m_rContext.EndElement( true ); + } +} + +void XMLSettingsExportHelper::exportForbiddenCharacters( + const uno::Any &rAny, + const OUString& rName) const +{ + uno::Reference xForbChars; + uno::Reference xLocales; + + rAny >>= xForbChars; + rAny >>= xLocales; + + SAL_WARN_IF( !(xForbChars.is() && xLocales.is()), "xmloff","XMLSettingsExportHelper::exportForbiddenCharacters: got illegal forbidden characters!" ); + + if( !xForbChars.is() || !xLocales.is() ) + return; + + rtl::Reference< comphelper::IndexedPropertyValuesContainer > xBox = new comphelper::IndexedPropertyValuesContainer(); + const uno::Sequence< lang::Locale > aLocales( xLocales->getLocales() ); + + /* FIXME-BCP47: this stupid and counterpart in + * xmloff/source/core/DocumentSettingsContext.cxx + * XMLConfigItemMapIndexedContext::EndElement() */ + + static const OUStringLiteral sLanguage ( u"Language" ); + static const OUStringLiteral sCountry ( u"Country" ); + static const OUStringLiteral sVariant ( u"Variant" ); + static const OUStringLiteral sBeginLine ( u"BeginLine" ); + static const OUStringLiteral sEndLine ( u"EndLine" ); + + sal_Int32 nPos = 0; + for( const auto& rLocale : aLocales ) + { + if( xForbChars->hasForbiddenCharacters( rLocale ) ) + { + const i18n::ForbiddenCharacters aChars( xForbChars->getForbiddenCharacters( rLocale ) ); + + + uno::Sequence < beans::PropertyValue > aSequence ( XML_FORBIDDEN_CHARACTER_MAX ); + beans::PropertyValue *pForChar = aSequence.getArray(); + + pForChar[XML_FORBIDDEN_CHARACTER_LANGUAGE].Name = sLanguage; + pForChar[XML_FORBIDDEN_CHARACTER_LANGUAGE].Value <<= rLocale.Language; + pForChar[XML_FORBIDDEN_CHARACTER_COUNTRY].Name = sCountry; + pForChar[XML_FORBIDDEN_CHARACTER_COUNTRY].Value <<= rLocale.Country; + pForChar[XML_FORBIDDEN_CHARACTER_VARIANT].Name = sVariant; + pForChar[XML_FORBIDDEN_CHARACTER_VARIANT].Value <<= rLocale.Variant; + pForChar[XML_FORBIDDEN_CHARACTER_BEGIN_LINE].Name = sBeginLine; + pForChar[XML_FORBIDDEN_CHARACTER_BEGIN_LINE].Value <<= aChars.beginLine; + pForChar[XML_FORBIDDEN_CHARACTER_END_LINE].Name = sEndLine; + pForChar[XML_FORBIDDEN_CHARACTER_END_LINE].Value <<= aChars.endLine; + xBox->insertByIndex(nPos++, uno::Any( aSequence )); + } + } + + exportIndexAccess( xBox, rName ); +} + +void XMLSettingsExportHelper::exportAllSettings( + const uno::Sequence& aProps, + const OUString& rName) const +{ + DBG_ASSERT(!rName.isEmpty(), "no name"); + exportSequencePropertyValue(aProps, rName); +} + + +/** For some settings we may want to change their API representation + * from their XML settings representation. This is your chance to do + * so! + */ +void XMLSettingsExportHelper::ManipulateSetting( uno::Any& rAny, std::u16string_view rName ) const +{ + if( rName == gsPrinterIndependentLayout ) + { + sal_Int16 nTmp = sal_Int16(); + if( rAny >>= nTmp ) + { + if( nTmp == document::PrinterIndependentLayout::LOW_RESOLUTION ) + rAny <<= OUString("low-resolution"); + else if( nTmp == document::PrinterIndependentLayout::DISABLED ) + rAny <<= OUString("disabled"); + else if( nTmp == document::PrinterIndependentLayout::HIGH_RESOLUTION ) + rAny <<= OUString("high-resolution"); + } + } + else if( (rName == gsColorTableURL) || (rName == gsLineEndTableURL) || (rName == gsHatchTableURL) || + (rName == gsDashTableURL) || (rName == gsGradientTableURL) || (rName == gsBitmapTableURL ) ) + { + if( !mxStringSubstitution.is() ) + { + try + { + const_cast< XMLSettingsExportHelper* >(this)->mxStringSubstitution = + util::PathSubstitution::create( m_rContext.GetComponentContext() ); + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.core"); + } + } + + if( mxStringSubstitution.is() ) + { + OUString aURL; + rAny >>= aURL; + aURL = mxStringSubstitution->reSubstituteVariables( aURL ); + rAny <<= aURL; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/SvXMLAttr.cxx b/xmloff/source/core/SvXMLAttr.cxx new file mode 100644 index 000000000..5fa0f5ce5 --- /dev/null +++ b/xmloff/source/core/SvXMLAttr.cxx @@ -0,0 +1,38 @@ +/* -*- 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 +#include "SvXMLAttr.hxx" + +SvXMLAttr::SvXMLAttr( const OUString& rLName, + const OUString& rValue ) : + aPrefixPos(USHRT_MAX), + aLName(rLName), + aValue(rValue) +{ +} + +SvXMLAttr::SvXMLAttr( const sal_uInt16 nPos, + const OUString& rLName, + const OUString& rValue ) : + aPrefixPos(nPos), + aLName(rLName), + aValue(rValue) +{ +} + +bool SvXMLAttr::operator== (const SvXMLAttr &rCmp) const +{ + return ( rCmp.aPrefixPos == aPrefixPos ) && + ( rCmp.aLName == aLName ) && + ( rCmp.aValue == aValue ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/SvXMLAttr.hxx b/xmloff/source/core/SvXMLAttr.hxx new file mode 100644 index 000000000..bdfc27983 --- /dev/null +++ b/xmloff/source/core/SvXMLAttr.hxx @@ -0,0 +1,34 @@ +/* -*- 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 + +class SvXMLAttr { +private: + sal_uInt16 aPrefixPos; + OUString aLName; + OUString aValue; +public: + // Assuming OUString is well behaved, the default copy constructor and + // assignment operator are fine. + SvXMLAttr( const OUString& rLName, + const OUString& rValue ); + SvXMLAttr( const sal_uInt16 nPos, + const OUString& rLName, + const OUString& rValue ); + bool operator== (const SvXMLAttr &rCmp) const; + + sal_uInt16 getPrefixPos() const { return aPrefixPos;} + const OUString& getLName() const { return aLName;} + const OUString& getValue() const { return aValue;} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/SvXMLAttrCollection.cxx b/xmloff/source/core/SvXMLAttrCollection.cxx new file mode 100644 index 000000000..466008b9f --- /dev/null +++ b/xmloff/source/core/SvXMLAttrCollection.cxx @@ -0,0 +1,180 @@ +/* -*- 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 "SvXMLAttrCollection.hxx" +#include +#include + +bool SvXMLAttrCollection::operator ==( const SvXMLAttrCollection& rCmp ) const +{ + return (rCmp.aNamespaceMap == aNamespaceMap) && + (rCmp.aAttrs == aAttrs); +} + +bool SvXMLAttrCollection::AddAttr( const OUString& rLName, + const OUString& rValue ) +{ + assert(!rLName.isEmpty()); + aAttrs.emplace_back(rLName, rValue ); + return true; +} + +bool SvXMLAttrCollection::AddAttr( const OUString& rPrefix, + const OUString& rNamespace, + const OUString& rLName, + const OUString& rValue ) +{ + assert(!rPrefix.isEmpty()); + assert(!rNamespace.isEmpty()); + assert(!rLName.isEmpty()); + sal_uInt16 nPos = aNamespaceMap.Add( rPrefix, rNamespace ); + aAttrs.emplace_back(nPos, rLName, rValue ); + return true; +} + +bool SvXMLAttrCollection::AddAttr( const OUString& rPrefix, + const OUString& rLName, + const OUString& rValue ) +{ + assert(!rPrefix.isEmpty()); + assert(!rLName.isEmpty()); + sal_uInt16 nPos = aNamespaceMap.GetIndexByPrefix( rPrefix ); + if( USHRT_MAX == nPos ) + return false; + aAttrs.emplace_back(nPos, rLName, rValue ); + return true; +} + +bool SvXMLAttrCollection::SetAt( size_t i, + const OUString& rLName, + const OUString& rValue ) +{ + assert(!rLName.isEmpty()); + if( i >= GetAttrCount() ) + return false; + aAttrs[i] = SvXMLAttr(rLName, rValue); + return true; +} + +bool SvXMLAttrCollection::SetAt( size_t i, + const OUString& rPrefix, + const OUString& rNamespace, + const OUString& rLName, + const OUString& rValue ) +{ + assert(!rPrefix.isEmpty()); + assert(!rNamespace.isEmpty()); + assert(!rLName.isEmpty()); + if( i >= GetAttrCount() ) + return false; + + sal_uInt16 nPos = aNamespaceMap.Add( rPrefix, rNamespace ); + if( USHRT_MAX == nPos ) + return false; + + aAttrs[i] = SvXMLAttr(nPos, rLName, rValue); + return true; +} + +bool SvXMLAttrCollection::SetAt( size_t i, + const OUString& rPrefix, + const OUString& rLName, + const OUString& rValue ) +{ + assert(!rPrefix.isEmpty()); + assert(!rLName.isEmpty()); + if( i >= GetAttrCount() ) + return false; + + sal_uInt16 nPos = aNamespaceMap.GetIndexByPrefix( rPrefix ); + if( USHRT_MAX == nPos ) + return false; + + aAttrs[i] = SvXMLAttr(nPos, rLName, rValue); + return true; +} + +void SvXMLAttrCollection::Remove( size_t i ) +{ + if( i < GetAttrCount() ) + { + aAttrs.erase( aAttrs.begin() + i ); + } + else + { + OSL_FAIL( "illegal index" ); + } +} + +size_t SvXMLAttrCollection::GetAttrCount() const +{ + return aAttrs.size(); +} + +const OUString& SvXMLAttrCollection::GetAttrLName(size_t i) const +{ + OSL_ENSURE( i < aAttrs.size(), "SvXMLAttrContainerData::GetLName: illegal index" ); + return aAttrs[i].getLName(); +} + +const OUString& SvXMLAttrCollection::GetAttrValue(size_t i) const +{ + OSL_ENSURE( i < aAttrs.size(), "SvXMLAttrContainerData::GetValue: illegal index" ); + return aAttrs[i].getValue(); +} + +OUString SvXMLAttrCollection::GetAttrNamespace( size_t i ) const +{ + OUString sRet; + sal_uInt16 nPos = GetPrefixPos( i ); + //Does this point to a valid namespace entry? + if( USHRT_MAX != nPos ) + sRet = aNamespaceMap.GetNameByIndex( nPos ); + return sRet; +} + +OUString SvXMLAttrCollection::GetAttrPrefix( size_t i ) const +{ + OUString sRet; + sal_uInt16 nPos = GetPrefixPos( i ); + //Does this point to a valid namespace entry? + if( USHRT_MAX != nPos ) + sRet = aNamespaceMap.GetPrefixByIndex( nPos ); + return sRet; +} + +const OUString& SvXMLAttrCollection::GetNamespace( sal_uInt16 i ) const +{ + return aNamespaceMap.GetNameByIndex( i ); +} + +const OUString& SvXMLAttrCollection::GetPrefix( sal_uInt16 i ) const +{ + return aNamespaceMap.GetPrefixByIndex( i ); +} + +sal_uInt16 SvXMLAttrCollection::GetFirstNamespaceIndex() const +{ + return aNamespaceMap.GetFirstIndex(); +} + +sal_uInt16 SvXMLAttrCollection::GetNextNamespaceIndex( sal_uInt16 nIdx ) const +{ + return aNamespaceMap.GetNextIndex( nIdx ); +} + +sal_uInt16 SvXMLAttrCollection::GetPrefixPos( size_t i ) const +{ +// SAL_WARN_IF( i < 0 || i >= aAttrs.size()), "xmloff", +// "SvXMLAttrCollection::GetPrefixPos: illegal index" ); + return aAttrs[i].getPrefixPos(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ + diff --git a/xmloff/source/core/SvXMLAttrCollection.hxx b/xmloff/source/core/SvXMLAttrCollection.hxx new file mode 100644 index 000000000..a99b14965 --- /dev/null +++ b/xmloff/source/core/SvXMLAttrCollection.hxx @@ -0,0 +1,66 @@ +/* -*- 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 "SvXMLAttr.hxx" + +#include +#include +#include +#include + +class SvXMLAttrCollection +{ +public: + SvXMLNamespaceMap aNamespaceMap; + std::vector aAttrs; + + bool operator==(const SvXMLAttrCollection &rCmp) const; + bool AddAttr( const OUString& rLName, + const OUString& rValue ); + bool AddAttr( const OUString& rPrefix, + const OUString& rNamespace, + const OUString& rLName, + const OUString& rValue ); + bool AddAttr( const OUString& rPrefix, + const OUString& rLName, + const OUString& rValue ); + + bool SetAt( size_t i, + const OUString& rLName, + const OUString& rValue ); + bool SetAt( size_t i, + const OUString& rPrefix, + const OUString& rNamespace, + const OUString& rLName, + const OUString& rValue ); + bool SetAt( size_t i, + const OUString& rPrefix, + const OUString& rLName, + const OUString& rValue ); + + void Remove( size_t i ); + + size_t GetAttrCount() const; + const OUString& GetAttrLName(size_t i) const; + const OUString& GetAttrValue(size_t i) const; + OUString GetAttrNamespace( size_t i ) const; + OUString GetAttrPrefix( size_t i ) const; + const OUString& GetNamespace( sal_uInt16 i ) const; + const OUString& GetPrefix( sal_uInt16 i ) const; + sal_uInt16 GetFirstNamespaceIndex() const; + sal_uInt16 GetNextNamespaceIndex( sal_uInt16 nIdx ) const; + +private: + sal_uInt16 GetPrefixPos( size_t i ) const; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ + diff --git a/xmloff/source/core/XMLBase64Export.cxx b/xmloff/source/core/XMLBase64Export.cxx new file mode 100644 index 000000000..0ea8f3af3 --- /dev/null +++ b/xmloff/source/core/XMLBase64Export.cxx @@ -0,0 +1,84 @@ +/* -*- 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 + +#include + +#include + +#include +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; + +#define INPUT_BUFFER_SIZE 54 +#define OUTPUT_BUFFER_SIZE 72 + +XMLBase64Export::XMLBase64Export( SvXMLExport& rExp ) : + rExport( rExp ){ +} + +bool XMLBase64Export::exportXML( const Reference < XInputStream> & rIn ) +{ + bool bRet = true; + try + { + Sequence < sal_Int8 > aInBuff( INPUT_BUFFER_SIZE ); + OUStringBuffer aOutBuff( OUTPUT_BUFFER_SIZE ); + sal_Int32 nRead; + do + { + nRead = rIn->readBytes( aInBuff, INPUT_BUFFER_SIZE ); + if( nRead > 0 ) + { + ::comphelper::Base64::encode( aOutBuff, aInBuff ); + GetExport().Characters( aOutBuff.makeStringAndClear() ); + if( nRead == INPUT_BUFFER_SIZE ) + GetExport().IgnorableWhitespace(); + } + } + while( nRead == INPUT_BUFFER_SIZE ); + } + catch( ... ) + { + bRet = false; + } + + return bRet; +} + +bool XMLBase64Export::exportElement( + const Reference < XInputStream > & rIn, + enum ::xmloff::token::XMLTokenEnum eName ) +{ + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_OFFICE, eName, true, true ); + return exportXML( rIn ); +} + +bool XMLBase64Export::exportOfficeBinaryDataElement( + const Reference < XInputStream > & rIn ) +{ + return exportElement( rIn, ::xmloff::token::XML_BINARY_DATA ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/XMLBase64ImportContext.cxx b/xmloff/source/core/XMLBase64ImportContext.cxx new file mode 100644 index 000000000..81d2498bb --- /dev/null +++ b/xmloff/source/core/XMLBase64ImportContext.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/. + * + * 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 + +#include +#include + +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::io; + + +XMLBase64ImportContext::XMLBase64ImportContext( + SvXMLImport& rImport, + const Reference< XOutputStream >& rOut ) : + SvXMLImportContext( rImport ), + xOut( rOut ) +{ +} + +XMLBase64ImportContext::~XMLBase64ImportContext() +{ +} + +void XMLBase64ImportContext::endFastElement(sal_Int32 ) +{ + std::u16string_view sChars = o3tl::trim(maCharBuffer); + if( !sChars.empty() ) + { + Sequence< sal_Int8 > aBuffer( (sChars.size() / 4) * 3 ); + ::comphelper::Base64::decodeSomeChars( aBuffer, sChars ); + xOut->writeBytes( aBuffer ); + } + maCharBuffer.setLength(0); + xOut->closeOutput(); +} + +void XMLBase64ImportContext::characters( const OUString& rChars ) +{ + maCharBuffer.append(rChars); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/XMLBasicExportFilter.cxx b/xmloff/source/core/XMLBasicExportFilter.cxx new file mode 100644 index 000000000..6b9393819 --- /dev/null +++ b/xmloff/source/core/XMLBasicExportFilter.cxx @@ -0,0 +1,86 @@ +/* -*- 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 + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +// XMLBasicExportFilter + +XMLBasicExportFilter::XMLBasicExportFilter( const Reference< xml::sax::XDocumentHandler >& rxHandler ) + :m_xHandler( rxHandler ) +{ +} + +XMLBasicExportFilter::~XMLBasicExportFilter() +{ +} + +// XDocumentHandler + +void XMLBasicExportFilter::startDocument() +{ + // do nothing, filter this +} + +void XMLBasicExportFilter::endDocument() +{ + // do nothing, filter this +} + +void XMLBasicExportFilter::startElement( const OUString& aName, + const Reference< xml::sax::XAttributeList >& xAttribs ) +{ + if ( m_xHandler.is() ) + m_xHandler->startElement( aName, xAttribs ); +} + +void XMLBasicExportFilter::endElement( const OUString& aName ) +{ + if ( m_xHandler.is() ) + m_xHandler->endElement( aName ); +} + +void XMLBasicExportFilter::characters( const OUString& aChars ) +{ + if ( m_xHandler.is() ) + m_xHandler->characters( aChars ); +} + +void XMLBasicExportFilter::ignorableWhitespace( const OUString& aWhitespaces ) +{ + if ( m_xHandler.is() ) + m_xHandler->ignorableWhitespace( aWhitespaces ); +} + +void XMLBasicExportFilter::processingInstruction( const OUString& aTarget, + const OUString& aData ) +{ + if ( m_xHandler.is() ) + m_xHandler->processingInstruction( aTarget, aData ); +} + +void XMLBasicExportFilter::setDocumentLocator( const Reference< xml::sax::XLocator >& xLocator ) +{ + if ( m_xHandler.is() ) + m_xHandler->setDocumentLocator( xLocator ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/XMLEmbeddedObjectExportFilter.cxx b/xmloff/source/core/XMLEmbeddedObjectExportFilter.cxx new file mode 100644 index 000000000..78f302db2 --- /dev/null +++ b/xmloff/source/core/XMLEmbeddedObjectExportFilter.cxx @@ -0,0 +1,147 @@ +/* -*- 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 +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + + +XMLEmbeddedObjectExportFilter::XMLEmbeddedObjectExportFilter( + const Reference< XDocumentHandler > & rHandler ) noexcept : + xHandler( rHandler ), + xExtHandler( rHandler, UNO_QUERY ) +{ +} + +XMLEmbeddedObjectExportFilter::~XMLEmbeddedObjectExportFilter () noexcept +{ +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::startDocument() +{ + // do nothing, filter this +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::endDocument() +{ + // do nothing, filter this +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::startElement( + const OUString& rName, + const Reference< XAttributeList >& xAttrList ) +{ + xHandler->startElement( rName, xAttrList ); +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::endElement( const OUString& rName ) +{ + xHandler->endElement( rName ); +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::characters( const OUString& rChars ) +{ + xHandler->characters( rChars ); +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::ignorableWhitespace( + const OUString& rWhitespaces ) +{ + xHandler->ignorableWhitespace( rWhitespaces ); +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::processingInstruction( + const OUString& rTarget, + const OUString& rData ) +{ + xHandler->processingInstruction( rTarget, rData ); +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::setDocumentLocator( + const Reference< XLocator >& rLocator ) +{ + xHandler->setDocumentLocator( rLocator ); +} + +// XExtendedDocumentHandler +void SAL_CALL XMLEmbeddedObjectExportFilter::startCDATA() +{ + if( xExtHandler.is() ) + xExtHandler->startCDATA(); +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::endCDATA() +{ + if( xExtHandler.is() ) + xExtHandler->endCDATA(); +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::comment( const OUString& rComment ) +{ + if( xExtHandler.is() ) + xExtHandler->comment( rComment ); +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::allowLineBreak() +{ + if( xExtHandler.is() ) + xExtHandler->allowLineBreak(); +} + +void SAL_CALL XMLEmbeddedObjectExportFilter::unknown( const OUString& rString ) +{ + if( xExtHandler.is() ) + xExtHandler->unknown( rString ); +} + +// XInitialize +void SAL_CALL XMLEmbeddedObjectExportFilter::initialize( + const Sequence< Any >& aArguments ) +{ + for( const auto& rAny : aArguments ) + { + if( rAny.getValueType() == + cppu::UnoType::get()) + { + rAny >>= xHandler; + rAny >>= xExtHandler; + } + } +} + +// XServiceInfo +OUString SAL_CALL XMLEmbeddedObjectExportFilter::getImplementationName() +{ + return OUString(); +} + +sal_Bool SAL_CALL XMLEmbeddedObjectExportFilter::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL XMLEmbeddedObjectExportFilter::getSupportedServiceNames( ) +{ + Sequence< OUString > aSeq; + return aSeq; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/XMLEmbeddedObjectImportContext.cxx b/xmloff/source/core/XMLEmbeddedObjectImportContext.cxx new file mode 100644 index 000000000..29c9f67c1 --- /dev/null +++ b/xmloff/source/core/XMLEmbeddedObjectImportContext.cxx @@ -0,0 +1,263 @@ +/* -*- 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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +namespace { + +class XMLEmbeddedObjectImportContext_Impl : public SvXMLImportContext +{ + css::uno::Reference< css::xml::sax::XFastDocumentHandler > mxFastHandler; + +public: + + XMLEmbeddedObjectImportContext_Impl( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastDocumentHandler >& rHandler ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +} + +XMLEmbeddedObjectImportContext_Impl::XMLEmbeddedObjectImportContext_Impl( + SvXMLImport& rImport, + const Reference< XFastDocumentHandler >& rHandler ) : + SvXMLImportContext( rImport ), + mxFastHandler( rHandler ) +{ + assert(mxFastHandler); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLEmbeddedObjectImportContext_Impl::createFastChildContext( + sal_Int32 , + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + return new XMLEmbeddedObjectImportContext_Impl(GetImport(), mxFastHandler); +} + +void XMLEmbeddedObjectImportContext_Impl::startFastElement( + sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList ) +{ + mxFastHandler->startFastElement( nElement, xAttrList ); +} + +void XMLEmbeddedObjectImportContext_Impl::endFastElement(sal_Int32 nElement) +{ + mxFastHandler->endFastElement( nElement ); +} + +void XMLEmbeddedObjectImportContext_Impl::characters( const OUString& rChars ) +{ + mxFastHandler->characters( rChars ); +} + + +void XMLEmbeddedObjectImportContext::SetComponent( Reference< XComponent > const & rComp ) +{ + if( !rComp.is() || sFilterService.isEmpty() ) + return; + + Sequence aArgs( 0 ); + + Reference< XComponentContext > xContext( GetImport().GetComponentContext() ); + + Reference xFilter = + xContext->getServiceManager()->createInstanceWithArgumentsAndContext(sFilterService, aArgs, xContext); + SAL_WARN_IF(!xFilter, "xmloff", "could not create filter " << sFilterService); + if( !xFilter.is() ) + return; + + assert(dynamic_cast(xFilter.get())); + SvXMLImport *pFastHandler = dynamic_cast(xFilter.get()); + mxFastHandler = pFastHandler; + + try + { + Reference < XModifiable2 > xModifiable2( rComp, UNO_QUERY_THROW ); + xModifiable2->disableSetModified(); + } + catch( Exception& ) + { + } + + Reference < XImporter > xImporter( mxFastHandler, UNO_QUERY ); + xImporter->setTargetDocument( rComp ); + + xComp = rComp; // keep ref to component only if there is a handler + + // #i34042: copy namespace declarations + // We created a new instance of XMLImport, so we need to propagate the namespace + // declarations to it. + pFastHandler->GetNamespaceMap() = GetImport().GetNamespaceMap(); +} + +XMLEmbeddedObjectImportContext::XMLEmbeddedObjectImportContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList ) : + SvXMLImportContext( rImport ) +{ + SvGlobalName aName; + + if( nElement == XML_ELEMENT(MATH, XML_MATH) ) + { + sFilterService = XML_IMPORT_FILTER_MATH; + aName = SvGlobalName(SO3_SM_CLASSID); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_DOCUMENT) ) + { + OUString sMime; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(OFFICE, XML_MIMETYPE): + sMime = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + OUString sClass; + static std::u16string_view const prefixes[] = { + u"application/vnd.oasis.openoffice.", + u"application/x-vnd.oasis.openoffice.", + u"application/vnd.oasis.opendocument.", + u"application/x-vnd.oasis.opendocument."}; + for (auto const & p: prefixes) + { + if (sMime.startsWith(p, &sClass)) + { + break; + } + } + + if( !sClass.isEmpty() ) + { + static const std::tuple aServiceMap[] = { + { XML_TEXT, XML_IMPORT_FILTER_WRITER, { SO3_SW_CLASSID } }, + { XML_ONLINE_TEXT, XML_IMPORT_FILTER_WRITER, { SO3_SWWEB_CLASSID } }, + { XML_SPREADSHEET, XML_IMPORT_FILTER_CALC, { SO3_SC_CLASSID } }, + { XML_DRAWING, XML_IMPORT_FILTER_DRAW, { SO3_SDRAW_CLASSID } }, + { XML_GRAPHICS, XML_IMPORT_FILTER_DRAW, { SO3_SDRAW_CLASSID } }, + { XML_PRESENTATION, XML_IMPORT_FILTER_IMPRESS, { SO3_SIMPRESS_CLASSID } }, + { XML_CHART, XML_IMPORT_FILTER_CHART, { SO3_SCH_CLASSID } }, + }; + for (auto const& [eClass, sMatchingFilterService, rCLASSID] : aServiceMap) + { + if (IsXMLToken(sClass, eClass)) + { + sFilterService = sMatchingFilterService; + aName = SvGlobalName(rCLASSID); + break; + } + } + } + } + + sCLSID = aName.GetHexName(); +} + +XMLEmbeddedObjectImportContext::~XMLEmbeddedObjectImportContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLEmbeddedObjectImportContext::createFastChildContext( + sal_Int32 , + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( mxFastHandler.is() ) + return new XMLEmbeddedObjectImportContext_Impl( GetImport(), mxFastHandler ); + return nullptr; +} + +void XMLEmbeddedObjectImportContext::startFastElement( + sal_Int32 nElement, + const Reference< XFastAttributeList >& rAttrList ) +{ + if( !mxFastHandler.is() ) + return; + + mxFastHandler->startDocument(); + mxFastHandler->startFastElement( nElement, rAttrList ); +} + +void XMLEmbeddedObjectImportContext::endFastElement(sal_Int32 nElement) +{ + if( !mxFastHandler.is() ) + return; + + mxFastHandler->endFastElement( nElement ); + mxFastHandler->endDocument(); + + try + { + Reference < XModifiable2 > xModifiable2( xComp, UNO_QUERY_THROW ); + xModifiable2->enableSetModified(); + xModifiable2->setModified( true ); // trigger new replacement image generation + } + catch( Exception& ) + { + } +} + +void XMLEmbeddedObjectImportContext::characters( const OUString& rChars ) +{ + if( mxFastHandler.is() ) + mxFastHandler->characters( rChars ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/attrlist.cxx b/xmloff/source/core/attrlist.cxx new file mode 100644 index 000000000..3f9fbb6a8 --- /dev/null +++ b/xmloff/source/core/attrlist.cxx @@ -0,0 +1,192 @@ +/* -*- 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 + +#include +#include +#include +#include + +#include + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +sal_Int16 SAL_CALL SvXMLAttributeList::getLength() +{ + return sal::static_int_cast< sal_Int16 >(vecAttribute.size()); +} + + +SvXMLAttributeList::SvXMLAttributeList( const SvXMLAttributeList &r ) : + cppu::WeakImplHelper(r), + vecAttribute( r.vecAttribute ) +{ +} + +SvXMLAttributeList::SvXMLAttributeList( const uno::Reference< xml::sax::XAttributeList> & rAttrList ) +{ + SvXMLAttributeList* pImpl = + comphelper::getFromUnoTunnel( rAttrList ); + + if( pImpl ) + vecAttribute = pImpl->vecAttribute; + else + AppendAttributeList( rAttrList ); +} + +OUString SAL_CALL SvXMLAttributeList::getNameByIndex(sal_Int16 i) +{ + assert( o3tl::make_unsigned(i) < vecAttribute.size() ); + return ( o3tl::make_unsigned( i ) < vecAttribute.size() ) ? vecAttribute[i].sName : OUString(); +} + + +OUString SAL_CALL SvXMLAttributeList::getTypeByIndex(sal_Int16) +{ + return "CDATA"; +} + +OUString SAL_CALL SvXMLAttributeList::getValueByIndex(sal_Int16 i) +{ + assert( o3tl::make_unsigned(i) < vecAttribute.size() ); + return ( o3tl::make_unsigned( i ) < vecAttribute.size() ) ? vecAttribute[i].sValue : OUString(); +} + +OUString SAL_CALL SvXMLAttributeList::getTypeByName( const OUString& ) +{ + return "CDATA"; +} + +OUString SAL_CALL SvXMLAttributeList::getValueByName(const OUString& sName) +{ + auto ii = std::find_if(vecAttribute.begin(), vecAttribute.end(), + [&sName](SvXMLTagAttribute_Impl& rAttr) { return rAttr.sName == sName; }); + + if (ii != vecAttribute.end()) + return (*ii).sValue; + + return OUString(); +} + + +uno::Reference< css::util::XCloneable > SvXMLAttributeList::createClone() +{ + uno::Reference< css::util::XCloneable > r = new SvXMLAttributeList( *this ); + return r; +} + + +SvXMLAttributeList::SvXMLAttributeList() +{ + vecAttribute.reserve(20); // performance improvement during adding +} + + +SvXMLAttributeList::~SvXMLAttributeList() +{ +} + + +void SvXMLAttributeList::AddAttribute( const OUString &sName , + const OUString &sValue ) +{ + assert( !sName.isEmpty() && "empty attribute name is invalid"); + assert( std::count(sName.getStr(), sName.getStr() + sName.getLength(), u':') <= 1 && "too many colons"); + vecAttribute.emplace_back( SvXMLTagAttribute_Impl { sName , sValue } ); +} + +void SvXMLAttributeList::Clear() +{ + vecAttribute.clear(); +} + +void SvXMLAttributeList::RemoveAttribute( const OUString& sName ) +{ + auto ii = std::find_if(vecAttribute.begin(), vecAttribute.end(), + [&sName](SvXMLTagAttribute_Impl& rAttr) { return rAttr.sName == sName; }); + + if (ii != vecAttribute.end()) + vecAttribute.erase( ii ); +} + +void SvXMLAttributeList::AppendAttributeList( const uno::Reference< css::xml::sax::XAttributeList > &r ) +{ + OSL_ASSERT( r.is() ); + + sal_Int16 nMax = r->getLength(); + sal_Int16 nTotalSize = vecAttribute.size() + nMax; + vecAttribute.reserve( nTotalSize ); + + for( sal_Int16 i = 0 ; i < nMax ; ++i ) { + OUString sName = r->getNameByIndex( i ); + assert( !sName.isEmpty() && "empty attribute name is invalid"); + assert( std::count(sName.getStr(), sName.getStr() + sName.getLength(), u':') <= 1 && "too many colons"); + vecAttribute.emplace_back(SvXMLTagAttribute_Impl { sName, r->getValueByIndex( i ) }); + } + + OSL_ASSERT( nTotalSize == getLength() ); +} + +void SvXMLAttributeList::SetValueByIndex( sal_Int16 i, + const OUString& rValue ) +{ + assert( o3tl::make_unsigned(i) < vecAttribute.size() ); + if( o3tl::make_unsigned( i ) < vecAttribute.size() ) + { + vecAttribute[i].sValue = rValue; + } +} + +void SvXMLAttributeList::RemoveAttributeByIndex( sal_Int16 i ) +{ + assert( o3tl::make_unsigned(i) < vecAttribute.size() ); + if( o3tl::make_unsigned( i ) < vecAttribute.size() ) + vecAttribute.erase( vecAttribute.begin() + i ); +} + +void SvXMLAttributeList::RenameAttributeByIndex( sal_Int16 i, + const OUString& rNewName ) +{ + assert( o3tl::make_unsigned(i) < vecAttribute.size() ); + if( o3tl::make_unsigned( i ) < vecAttribute.size() ) + { + vecAttribute[i].sName = rNewName; + } +} + +sal_Int16 SvXMLAttributeList::GetIndexByName( const OUString& rName ) const +{ + auto ii = std::find_if(vecAttribute.begin(), vecAttribute.end(), + [&rName](const SvXMLTagAttribute_Impl& rAttr) { return rAttr.sName == rName; }); + + if (ii != vecAttribute.end()) + return static_cast(std::distance(vecAttribute.begin(), ii)); + + return -1; +} + +// XUnoTunnel & co +UNO3_GETIMPLEMENTATION_IMPL(SvXMLAttributeList) + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/fasttokenhandler.cxx b/xmloff/source/core/fasttokenhandler.cxx new file mode 100644 index 000000000..9efdf8f15 --- /dev/null +++ b/xmloff/source/core/fasttokenhandler.cxx @@ -0,0 +1,110 @@ +/* -*- 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 + +#include + +namespace xmloff { + +namespace { +// include auto-generated Perfect_Hash +#if defined __clang__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#if __has_warning("-Wdeprecated-register") +#pragma GCC diagnostic ignored "-Wdeprecated-register" +#endif +#endif +#include +#if defined __clang__ +#pragma GCC diagnostic pop +#endif +} // namespace + +namespace token { + +using namespace css; + +TokenMap& StaticTokenMap() +{ + static TokenMap SINGLETON; + return SINGLETON; +} + +const css::uno::Sequence< sal_Int8 > TokenMap::EMPTY_BYTE_SEQ; +const OUString TokenMap::EMPTY_STRING; + +TokenMap::TokenMap() : + maTokenNamesUtf8( static_cast< size_t >( XML_TOKEN_COUNT ) ), + maTokenNames( static_cast< size_t >( XML_TOKEN_COUNT ) ) +{ + static const char* sppcTokenNames[] = + { +#include + "" + }; + + const char* const* ppcTokenName = sppcTokenNames; + int i = 0; + for( auto& rTokenName : maTokenNamesUtf8 ) + { + OString aUtf8Token( *ppcTokenName ); + rTokenName = uno::Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( + aUtf8Token.getStr() ), aUtf8Token.getLength() ); + maTokenNames[i++] = OUString( aUtf8Token.getStr(), aUtf8Token.getLength(), RTL_TEXTENCODING_UTF8 ); + ++ppcTokenName; + } +} + +TokenMap::~TokenMap() +{ +} + +sal_Int32 TokenMap::getTokenPerfectHash( const char *pStr, sal_Int32 nLength ) +{ + const struct xmltoken *pToken = Perfect_Hash::in_word_set( pStr, nLength ); + return pToken ? pToken->nToken : xmloff::XML_TOKEN_INVALID; +} + +FastTokenHandler::FastTokenHandler() : + mrTokenMap( StaticTokenMap() ) +{ +} + +FastTokenHandler::~FastTokenHandler() +{ +} + +// XFastTokenHandler +uno::Sequence< sal_Int8 > FastTokenHandler::getUTF8Identifier( sal_Int32 nToken ) +{ + return mrTokenMap.getUtf8TokenName( nToken ); +} + +const OUString& FastTokenHandler::getIdentifier( sal_Int32 nToken ) const +{ + return mrTokenMap.getTokenName( nToken ); +} + +sal_Int32 FastTokenHandler::getTokenFromUTF8( const uno::Sequence< sal_Int8 >& rIdentifier ) +{ + return TokenMap::getTokenFromUtf8( rIdentifier ); +} + +// Much faster direct C++ shortcut +sal_Int32 FastTokenHandler::getTokenDirect( const char* pToken, sal_Int32 nLength ) const +{ + return TokenMap::getTokenFromUTF8( pToken, nLength ); +} + +} // namespace token +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/i18nmap.cxx b/xmloff/source/core/i18nmap.cxx new file mode 100644 index 000000000..db760ca1d --- /dev/null +++ b/xmloff/source/core/i18nmap.cxx @@ -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/. + * + * 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 +#include +#include + +void SvI18NMap::Add( sal_uInt16 nKind, const OUString& rName, + const OUString& rNewName ) +{ + SvI18NMapEntry_Key aKey(nKind, rName); + bool bIsNewInsertion = m_aMap.emplace(aKey, rNewName).second; + SAL_INFO_IF(!bIsNewInsertion, "xmloff.core", "SvI18NMap::Add: item with key \"" << rName << "\" registered already, likely invalid input file"); +} + +const OUString& SvI18NMap::Get( sal_uInt16 nKind, const OUString& rName ) const +{ + SvI18NMapEntry_Key aKey(nKind, rName); + SvI18NMap_Impl::const_iterator aI = m_aMap.find(aKey); + if (aI != m_aMap.end()) + return aI->second; + return rName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/namespacemap.cxx b/xmloff/source/core/namespacemap.cxx new file mode 100644 index 000000000..c6fbb1d5d --- /dev/null +++ b/xmloff/source/core/namespacemap.cxx @@ -0,0 +1,560 @@ +/* -*- 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 + +#include +#include +#include + +#include +#include + +#include +#include + + +using namespace ::xmloff::token; + +/* The basic idea of this class is that we have two ways to search our + * data, by prefix and by key. We use an unordered_map for fast prefix + * searching and an STL map for fast key searching. + * + * The references to an 'Index' refer to an earlier implementation of the + * name space map and remain to support code which uses these interfaces. + * + * In this implementation, key and index should always be the same number. + * + * All references to Indices are now deprecated and the corresponding + * 'Key' methods should be used instead + * + * Martin 13/06/01 + */ + +const OUString sEmpty; + +SvXMLNamespaceMap::SvXMLNamespaceMap() +: sXMLNS( GetXMLToken ( XML_XMLNS ) ) +{ + // approx worst-case size + aNameHash.reserve(20); + maKeyToNamespaceMap.reserve(20); +} + +SvXMLNamespaceMap::SvXMLNamespaceMap( const SvXMLNamespaceMap& rMap ) +: sXMLNS( GetXMLToken ( XML_XMLNS ) ) +{ + aNameHash = rMap.aNameHash; + maKeyToNamespaceMap = rMap.maKeyToNamespaceMap; +} + +SvXMLNamespaceMap& SvXMLNamespaceMap::operator=( const SvXMLNamespaceMap& rMap ) +{ + aNameHash = rMap.aNameHash; + maKeyToNamespaceMap = rMap.maKeyToNamespaceMap; + return *this; +} + +SvXMLNamespaceMap::~SvXMLNamespaceMap() +{ +} + +void SvXMLNamespaceMap::Clear() +{ + aNameHash.clear(); + aNameCache.clear(); + maKeyToNamespaceMap.clear(); + aQNameCache.clear(); +} + + +bool SvXMLNamespaceMap::operator ==( const SvXMLNamespaceMap& rCmp ) const +{ + return aNameHash == rCmp.aNameHash; +} + +sal_uInt16 SvXMLNamespaceMap::Add_( const OUString& rPrefix, const OUString &rName, sal_uInt16 nKey ) +{ + if( XML_NAMESPACE_UNKNOWN == nKey ) + { + // create a new unique key with UNKNOWN flag set + nKey = XML_NAMESPACE_UNKNOWN_FLAG; + do + { + auto aIter = maKeyToNamespaceMap.find ( nKey ); + if( aIter == maKeyToNamespaceMap.end() ) + break; + nKey++; + } + while ( true ); + } + aNameHash.insert_or_assign( rPrefix, NameSpaceEntry{ rName, rPrefix, nKey} ); + maKeyToNamespaceMap.insert_or_assign( nKey, KeyToNameSpaceMapEntry{ rName, rPrefix} ); + return nKey; +} + +sal_uInt16 SvXMLNamespaceMap::Add( const OUString& rPrefix, const OUString& rName, + sal_uInt16 nKey ) +{ + if( XML_NAMESPACE_UNKNOWN == nKey ) + nKey = GetKeyByName( rName ); + +#ifdef NDEBUG + if( XML_NAMESPACE_NONE == nKey ) + return USHRT_MAX; +#else + assert(XML_NAMESPACE_NONE != nKey); +#endif + + if ( aNameHash.find ( rPrefix ) == aNameHash.end() ) + nKey = Add_( rPrefix, rName, nKey ); + + return nKey; +} + +sal_uInt16 SvXMLNamespaceMap::AddIfKnown( const OUString& rPrefix, const OUString& rName ) +{ + sal_uInt16 nKey = GetKeyByName( rName ); + +#ifdef NDEBUG + if( XML_NAMESPACE_NONE == nKey ) + return XML_NAMESPACE_UNKNOWN; +#else + assert(nKey != XML_NAMESPACE_NONE); +#endif + + if( XML_NAMESPACE_UNKNOWN != nKey ) + { + NameSpaceHash::const_iterator aIter = aNameHash.find( rPrefix ); + if( aIter == aNameHash.end() || (*aIter).second.sName != rName ) + nKey = Add_( rPrefix, rName, nKey ); + } + + return nKey; +} + + +sal_uInt16 SvXMLNamespaceMap::GetKeyByPrefix( const OUString& rPrefix ) const +{ + NameSpaceHash::const_iterator aIter = aNameHash.find(rPrefix); + return (aIter != aNameHash.end()) ? (*aIter).second.nKey : USHRT_MAX; +} + +sal_uInt16 SvXMLNamespaceMap::GetKeyByName( const OUString& rName ) const +{ + sal_uInt16 nKey = XML_NAMESPACE_UNKNOWN; + auto aIter = std::find_if(aNameHash.cbegin(), aNameHash.cend(), + [&rName](const NameSpaceHash::value_type& rEntry) { return rEntry.second.sName == rName; }); + + if (aIter != aNameHash.cend()) + nKey = (*aIter).second.nKey; + + return nKey; +} + +const OUString& SvXMLNamespaceMap::GetPrefixByKey( sal_uInt16 nKey ) const +{ + auto aIter = maKeyToNamespaceMap.find (nKey); + return (aIter != maKeyToNamespaceMap.end()) ? (*aIter).second.sPrefix : sEmpty; +} + +const OUString& SvXMLNamespaceMap::GetNameByKey( sal_uInt16 nKey ) const +{ + auto aIter = maKeyToNamespaceMap.find (nKey); + return (aIter != maKeyToNamespaceMap.end()) ? (*aIter).second.sName : sEmpty; +} + +OUString SvXMLNamespaceMap::GetAttrNameByKey( sal_uInt16 nKey ) const +{ + auto aIter = maKeyToNamespaceMap.find ( nKey ); + if (aIter == maKeyToNamespaceMap.end()) + return OUString(); + + const OUString & prefix( (*aIter).second.sPrefix ); + if (prefix.isEmpty()) // default namespace + return sXMLNS; + + return sXMLNS + ":" + prefix; +} + +OUString SvXMLNamespaceMap::GetQNameByKey( sal_uInt16 nKey, + const OUString& rLocalName, + bool bCache) const +{ + // We always want to return at least the rLocalName... + + switch ( nKey ) + { + case XML_NAMESPACE_UNKNOWN: + // ...if it's a completely unknown namespace, assert and return the local name + SAL_WARN("xmloff.core", "unknown namespace, probable missing xmlns: declaration"); + [[fallthrough]]; + case XML_NAMESPACE_NONE: + // ...if there isn't one, return the local name + return rLocalName; + case XML_NAMESPACE_XMLNS: + { + // ...if it's in the xmlns namespace, make the prefix + // don't bother caching this, it rarely happens + OUStringBuffer sQName; + sQName.append ( sXMLNS ); + if (!rLocalName.isEmpty()) // not default namespace + { + sQName.append ( ':' ); + sQName.append ( rLocalName ); + } + return sQName.makeStringAndClear(); + } + case XML_NAMESPACE_XML: + { + // this namespace is reserved, and needs not to be declared + return GetXMLToken(XML_XML) + ":" + rLocalName; + } + default: + { + QNameCache::const_iterator aQCacheIter; + if (bCache) + aQCacheIter = aQNameCache.find ( QNamePair ( nKey, rLocalName ) ); + else + aQCacheIter = aQNameCache.end(); + if ( aQCacheIter != aQNameCache.end() ) + return (*aQCacheIter).second; + else + { + auto aIter = maKeyToNamespaceMap.find ( nKey ); + if ( aIter != maKeyToNamespaceMap.end() ) + { + // ...if it's in our map, make the prefix + const OUString & prefix( (*aIter).second.sPrefix ); + OUStringBuffer sQName(prefix.getLength() + 1 + rLocalName.getLength()); + if (!prefix.isEmpty()) // not default namespace + { + sQName.append( prefix ); + sQName.append( ':' ); + } + sQName.append ( rLocalName ); + if (bCache) + { + OUString sString(sQName.makeStringAndClear()); + aQNameCache.emplace(QNamePair(nKey, rLocalName), sString); + return sString; + } + else + return sQName.makeStringAndClear(); + } + else + { + // ... if it isn't, this is a Bad Thing, assert and return the local name + assert(false); + return rLocalName; + } + } + } + } +} + +sal_uInt16 SvXMLNamespaceMap::GetKeyByAttrValueQName( + const OUString& rAttrValue, + OUString *pLocalName) const +{ + return GetKeyByQName(rAttrValue, nullptr, pLocalName, nullptr, QNameMode::AttrValue); +} + +/** + @param rQName either attribute name or qualified/namespaced attribute value + @param bCacheAttrName true: rQName is element or attribute name, cache it + false: rQName is attribute value, may contain extra ':', don't cache it + */ +sal_uInt16 SvXMLNamespaceMap::GetKeyByQName(const OUString& rQName, + OUString *pPrefix, + OUString *pLocalName, + OUString *pNamespace, + QNameMode const eMode) const +{ + sal_uInt16 nKey; + + NameSpaceHash::const_iterator it; + if (eMode == QNameMode::AttrNameCached) + it = aNameCache.find ( rQName ); + else + it = aNameCache.end(); + if ( it != aNameCache.end() ) + { + const NameSpaceEntry &rEntry = (*it).second; + if ( pPrefix ) + *pPrefix = rEntry.sPrefix; + if ( pLocalName ) + *pLocalName = rEntry.sName; + nKey = rEntry.nKey; + if ( pNamespace ) + { + auto aMapIter = maKeyToNamespaceMap.find (nKey); + *pNamespace = aMapIter != maKeyToNamespaceMap.end() ? (*aMapIter).second.sName : OUString(); + } + } + else + { + OUString sEntryPrefix, sEntryName; + + sal_Int32 nColonPos = rQName.indexOf( ':' ); + if( -1 == nColonPos ) + { + // case: no ':' found -> default namespace + sEntryName = rQName; + } + else + { + // normal case: ':' found -> get prefix/suffix + sEntryPrefix = rQName.copy( 0, nColonPos ); + sEntryName = rQName.copy( nColonPos + 1 ); + } + + if (eMode == QNameMode::AttrNameCached && sEntryName.indexOf(':') != -1) + { + SAL_INFO("xmloff", "invalid attribute name with multiple ':'"); + assert(false); + return XML_NAMESPACE_UNKNOWN; + } + + if( pPrefix ) + *pPrefix = sEntryPrefix; + if( pLocalName ) + *pLocalName = sEntryName; + + NameSpaceHash::const_iterator aIter = aNameHash.find( sEntryPrefix ); + if ( aIter != aNameHash.end() ) + { + // found: retrieve namespace key + nKey = (*aIter).second.nKey; + if ( pNamespace ) + *pNamespace = (*aIter).second.sName; + } + else if ( sEntryPrefix == sXMLNS ) + // not found, but xmlns prefix: return xmlns 'namespace' + nKey = XML_NAMESPACE_XMLNS; + else if( nColonPos == -1 ) + // not found, and no namespace: 'namespace' none + nKey = XML_NAMESPACE_NONE; + else + nKey = XML_NAMESPACE_UNKNOWN; + + if (eMode == QNameMode::AttrNameCached) + { + aNameCache.insert_or_assign(rQName, NameSpaceEntry{std::move(sEntryName), std::move(sEntryPrefix), nKey}); + } + } + + return nKey; +} + +sal_uInt16 SvXMLNamespaceMap::GetFirstKey() const +{ + return maKeyToNamespaceMap.empty() ? USHRT_MAX : (*maKeyToNamespaceMap.begin()).first; +} + +sal_uInt16 SvXMLNamespaceMap::GetNextKey( sal_uInt16 nLastKey ) const +{ + auto aIter = maKeyToNamespaceMap.find ( nLastKey ); + return (++aIter == maKeyToNamespaceMap.end()) ? USHRT_MAX : (*aIter).first; +} + + +// All methods after this are deprecated... + +sal_uInt16 SvXMLNamespaceMap::GetIndexByKey( sal_uInt16 nKey ) +{ + return nKey; +} +sal_uInt16 SvXMLNamespaceMap::GetFirstIndex() const +{ + return maKeyToNamespaceMap.empty() ? USHRT_MAX : (*maKeyToNamespaceMap.begin()).first; +} + +sal_uInt16 SvXMLNamespaceMap::GetNextIndex( sal_uInt16 nOldIdx ) const +{ + auto aIter = maKeyToNamespaceMap.find ( nOldIdx ); + return (++aIter == maKeyToNamespaceMap.end()) ? USHRT_MAX : (*aIter).first; +} + +void SvXMLNamespaceMap::AddAtIndex( const OUString& rPrefix, + const OUString& rName, sal_uInt16 nKey ) +{ + if( XML_NAMESPACE_UNKNOWN == nKey ) + nKey = GetKeyByName( rName ); + + assert(XML_NAMESPACE_NONE != nKey); + if( XML_NAMESPACE_NONE != nKey && ! ( aNameHash.count ( rPrefix ) ) ) + { + Add_( rPrefix, rName, nKey ); + } +} + +OUString SvXMLNamespaceMap::GetAttrNameByIndex( sal_uInt16 nIdx ) const +{ + return GetAttrNameByKey( nIdx ); +} + +const OUString& SvXMLNamespaceMap::GetPrefixByIndex( sal_uInt16 nIdx ) const +{ + auto aIter = maKeyToNamespaceMap.find (nIdx); + return (aIter != maKeyToNamespaceMap.end()) ? (*aIter).second.sPrefix : sEmpty; +} + +const OUString& SvXMLNamespaceMap::GetNameByIndex( sal_uInt16 nIdx ) const +{ + auto aIter = maKeyToNamespaceMap.find (nIdx); + return (aIter != maKeyToNamespaceMap.end()) ? (*aIter).second.sName : sEmpty; +} + +sal_uInt16 SvXMLNamespaceMap::GetIndexByPrefix( const OUString& rPrefix ) const +{ + NameSpaceHash::const_iterator aIter = aNameHash.find(rPrefix); + return (aIter != aNameHash.end()) ? (*aIter).second.nKey : USHRT_MAX; +} +sal_uInt16 SvXMLNamespaceMap::GetKeyByAttrName( + const OUString& rAttrName, + OUString *pLocalName) const +{ + return GetKeyByQName(rAttrName, nullptr, pLocalName, nullptr, QNameMode::AttrNameCached); +} + +sal_uInt16 SvXMLNamespaceMap::GetKeyByAttrName( const OUString& rAttrName, + OUString *pPrefix, + OUString *pLocalName, + OUString *pNamespace ) const +{ + return GetKeyByQName(rAttrName, pPrefix, pLocalName, pNamespace, QNameMode::AttrNameCached); +} + +bool SvXMLNamespaceMap::NormalizeURI( OUString& rName ) +{ + // try OASIS + W3 URI normalization + bool bSuccess = NormalizeOasisURN( rName ); + if( ! bSuccess ) + bSuccess = NormalizeW3URI( rName ); + return bSuccess; +} + +bool SvXMLNamespaceMap::NormalizeW3URI( OUString& rName ) +{ + // check if URI matches: + // http://www.w3.org/[0-9]*/[:letter:]* + // (year)/(WG name) + // For the following WG/standards names: + // - xforms + + bool bSuccess = false; + const OUString& sURIPrefix = GetXMLToken( XML_URI_W3_PREFIX ); + if( rName.startsWith( sURIPrefix ) ) + { + const OUString& sURISuffix = GetXMLToken( XML_URI_XFORMS_SUFFIX ); + sal_Int32 nCompareFrom = rName.getLength() - sURISuffix.getLength(); + if( rName.subView( nCompareFrom ) == sURISuffix ) + { + // found W3 prefix, and xforms suffix + rName = GetXMLToken( XML_N_XFORMS_1_0 ); + bSuccess = true; + } + } + return bSuccess; +} + +bool SvXMLNamespaceMap::NormalizeOasisURN( OUString& rName ) +{ + // #i38644# + // we exported the wrong namespace for smil, so we correct this here on load + // for older documents + if( IsXMLToken( rName, ::xmloff::token::XML_N_SVG ) ) + { + rName = GetXMLToken( ::xmloff::token::XML_N_SVG_COMPAT ); + return true; + } + else if( IsXMLToken( rName, ::xmloff::token::XML_N_FO ) ) + { + rName = GetXMLToken( ::xmloff::token::XML_N_FO_COMPAT ); + return true; + } + else if( IsXMLToken( rName, ::xmloff::token::XML_N_SMIL ) || + IsXMLToken( rName, ::xmloff::token::XML_N_SMIL_OLD ) ) + { + rName = GetXMLToken( ::xmloff::token::XML_N_SMIL_COMPAT ); + return true; + } + + + // Check if URN matches + // :urn:oasis:names:tc:[^:]*:xmlns:[^:]*:1.[^:]* + // |---| |---| |-----| + // TC-Id Sub-Id Version + + sal_Int32 nNameLen = rName.getLength(); + // :urn:oasis:names:tc.* + const OUString& rOasisURN = GetXMLToken( XML_URN_OASIS_NAMES_TC ); + if( !rName.startsWith( rOasisURN ) ) + return false; + + // :urn:oasis:names:tc:.* + sal_Int32 nPos = rOasisURN.getLength(); + if( nPos >= nNameLen || rName[nPos] != ':' ) + return false; + + // :urn:oasis:names:tc:[^:]:.* + sal_Int32 nTCIdStart = nPos+1; + sal_Int32 nTCIdEnd = rName.indexOf( ':', nTCIdStart ); + if( -1 == nTCIdEnd ) + return false; + + // :urn:oasis:names:tc:[^:]:xmlns.* + nPos = nTCIdEnd + 1; + std::u16string_view sTmp( rName.subView( nPos ) ); + const OUString& rXMLNS = GetXMLToken( XML_XMLNS ); + if( !o3tl::starts_with(sTmp, rXMLNS ) ) + return false; + + // :urn:oasis:names:tc:[^:]:xmlns:.* + nPos += rXMLNS.getLength(); + if( nPos >= nNameLen || rName[nPos] != ':' ) + return false; + + // :urn:oasis:names:tc:[^:]:xmlns:[^:]*:.* + nPos = rName.indexOf( ':', nPos+1 ); + if( -1 == nPos ) + return false; + + // :urn:oasis:names:tc:[^:]:xmlns:[^:]*:[^:][^:][^:][^:]* + sal_Int32 nVersionStart = nPos+1; + if( nVersionStart+2 >= nNameLen || + -1 != rName.indexOf( ':', nVersionStart ) ) + return false; + + // :urn:oasis:names:tc:[^:]:xmlns:[^:]*:1\.[^:][^:]* + if( rName[nVersionStart] != '1' || rName[nVersionStart+1] != '.' ) + return false; + + // replace [tcid] with current TCID and version with current version. + + rName = rName.subView( 0, nTCIdStart ) + + GetXMLToken( XML_OPENDOCUMENT ) + + rName.subView( nTCIdEnd, nVersionStart-nTCIdEnd ) + + GetXMLToken( XML_1_0 ); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/unoatrcn.cxx b/xmloff/source/core/unoatrcn.cxx new file mode 100644 index 000000000..354cd47b4 --- /dev/null +++ b/xmloff/source/core/unoatrcn.cxx @@ -0,0 +1,242 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace ::com::sun::star; + +// Interface implementation + +uno::Reference< uno::XInterface > SvUnoAttributeContainer_CreateInstance() +{ + return *(new SvUnoAttributeContainer); +} + +SvUnoAttributeContainer::SvUnoAttributeContainer( std::unique_ptr pContainer) +: mpContainer( std::move( pContainer ) ) +{ + if( !mpContainer ) + mpContainer = std::make_unique(); +} + +// container::XElementAccess +uno::Type SAL_CALL SvUnoAttributeContainer::getElementType() +{ + return cppu::UnoType::get(); +} + +sal_Bool SAL_CALL SvUnoAttributeContainer::hasElements() +{ + return mpContainer->GetAttrCount() != 0; +} + +sal_uInt16 SvUnoAttributeContainer::getIndexByName(std::u16string_view aName ) const +{ + const sal_uInt16 nAttrCount = mpContainer->GetAttrCount(); + + size_t nPos = aName.find( ':' ); + if( nPos == std::u16string_view::npos ) + { + for( sal_uInt16 nAttr = 0; nAttr < nAttrCount; nAttr++ ) + { + if( mpContainer->GetAttrLName(nAttr) == aName && + mpContainer->GetAttrPrefix(nAttr).isEmpty() ) + return nAttr; + } + } + else + { + const std::u16string_view aPrefix( aName.substr( 0L, nPos ) ); + const std::u16string_view aLName( aName.substr( nPos+1 ) ); + + for( sal_uInt16 nAttr = 0; nAttr < nAttrCount; nAttr++ ) + { + if( mpContainer->GetAttrLName(nAttr) == aLName && + mpContainer->GetAttrPrefix(nAttr) == aPrefix ) + return nAttr; + } + } + + return USHRT_MAX; +} + +const css::uno::Sequence< sal_Int8 > & SvUnoAttributeContainer::getUnoTunnelId() noexcept +{ + static const comphelper::UnoIdInit theSvUnoAttributeContainerUnoTunnelId; + return theSvUnoAttributeContainerUnoTunnelId.getSeq(); +} + +sal_Int64 SAL_CALL SvUnoAttributeContainer::getSomething( const css::uno::Sequence< sal_Int8 >& rId ) +{ + return comphelper::getSomethingImpl(rId, this); +} + +// container::XNameAccess +uno::Any SAL_CALL SvUnoAttributeContainer::getByName(const OUString& aName) +{ + sal_uInt16 nAttr = getIndexByName(aName ); + + if( nAttr == USHRT_MAX ) + throw container::NoSuchElementException(); + + xml::AttributeData aData; + aData.Namespace = mpContainer->GetAttrNamespace(nAttr); + aData.Type = "CDATA"; + aData.Value = mpContainer->GetAttrValue(nAttr); + + return uno::Any(aData); +} + +uno::Sequence< OUString > SAL_CALL SvUnoAttributeContainer::getElementNames() +{ + const sal_uInt16 nAttrCount = mpContainer->GetAttrCount(); + + uno::Sequence< OUString > aElementNames( static_cast(nAttrCount) ); + OUString *pNames = aElementNames.getArray(); + + for( sal_uInt16 nAttr = 0; nAttr < nAttrCount; nAttr++ ) + { + OUStringBuffer sBuffer( mpContainer->GetAttrPrefix(nAttr) ); + if( !sBuffer.isEmpty() ) + sBuffer.append( ':' ); + sBuffer.append( mpContainer->GetAttrLName(nAttr) ); + *pNames++ = sBuffer.makeStringAndClear(); + } + + return aElementNames; +} + +sal_Bool SAL_CALL SvUnoAttributeContainer::hasByName(const OUString& aName) +{ + return getIndexByName(aName ) != USHRT_MAX; +} + +// container::XNameReplace +void SAL_CALL SvUnoAttributeContainer::replaceByName(const OUString& aName, const uno::Any& aElement) +{ + if( auto pData = o3tl::tryAccess(aElement) ) + { + sal_uInt16 nAttr = getIndexByName(aName ); + if( nAttr == USHRT_MAX ) + throw container::NoSuchElementException(); + + sal_Int32 nPos = aName.indexOf( ':' ); + if( nPos != -1 ) + { + const OUString aPrefix( aName.copy( 0L, nPos )); + const OUString aLName( aName.copy( nPos+1 )); + + if( pData->Namespace.isEmpty() ) + { + if( mpContainer->SetAt( nAttr, aPrefix, aLName, pData->Value ) ) + return; + } + else + { + if( mpContainer->SetAt( nAttr, aPrefix, pData->Namespace, aLName, pData->Value ) ) + return; + } + } + else + { + if( pData->Namespace.isEmpty() ) + { + if( mpContainer->SetAt( nAttr, aName, pData->Value ) ) + return; + } + } + } + + throw lang::IllegalArgumentException(); +} + +// container::XNameContainer +void SAL_CALL SvUnoAttributeContainer::insertByName(const OUString& aName, const uno::Any& aElement) +{ + auto pData = o3tl::tryAccess(aElement); + if( !pData ) + throw lang::IllegalArgumentException(); + + sal_uInt16 nAttr = getIndexByName(aName ); + if( nAttr != USHRT_MAX ) + throw container::ElementExistException(); + + sal_Int32 nPos = aName.indexOf( ':' ); + if( nPos != -1 ) + { + const OUString aPrefix( aName.copy( 0L, nPos )); + const OUString aLName( aName.copy( nPos+1 )); + + if( pData->Namespace.isEmpty() ) + { + if( mpContainer->AddAttr( aPrefix, aLName, pData->Value ) ) + return; + } + else + { + if( mpContainer->AddAttr( aPrefix, pData->Namespace, aLName, pData->Value ) ) + return; + } + } + else + { + if( pData->Namespace.isEmpty() ) + { + if( mpContainer->AddAttr( aName, pData->Value ) ) + return; + } + } +} + +void SAL_CALL SvUnoAttributeContainer::removeByName(const OUString& Name) +{ + sal_uInt16 nAttr = getIndexByName(Name); + if( nAttr == USHRT_MAX ) + throw container::NoSuchElementException(); + + mpContainer->Remove( nAttr ); +} + +//XServiceInfo +OUString SAL_CALL SvUnoAttributeContainer::getImplementationName() +{ + return "SvUnoAttributeContainer"; +} + +uno::Sequence< OUString > SvUnoAttributeContainer::getSupportedServiceNames() +{ + return { "com.sun.star.xml.AttributeContainer" }; +} + +sal_Bool SvUnoAttributeContainer::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/unointerfacetouniqueidentifiermapper.cxx b/xmloff/source/core/unointerfacetouniqueidentifiermapper.cxx new file mode 100644 index 000000000..e7e765132 --- /dev/null +++ b/xmloff/source/core/unointerfacetouniqueidentifiermapper.cxx @@ -0,0 +1,196 @@ +/* -*- 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 + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using css::uno::Reference; +using css::uno::XInterface; + +namespace comphelper +{ + +UnoInterfaceToUniqueIdentifierMapper::UnoInterfaceToUniqueIdentifierMapper() +: mnNextId( 1 ) +{ +} + +const OUString& UnoInterfaceToUniqueIdentifierMapper::registerReference( const Reference< XInterface >& rInterface ) +{ + // Be certain that the references we store in our table are to the + // leading / primary XInterface - cf. findReference + uno::Reference< uno::XInterface > xRef( rInterface, uno::UNO_QUERY ); + + IdMap_t::const_iterator aIter; + if( findReference( xRef, aIter ) ) + { + return (*aIter).first; + } + else + { + OUString aId = "id" + OUString::number( mnNextId++ ); + return (*maEntries.emplace( aId, xRef ).first).first; + } +} + +bool UnoInterfaceToUniqueIdentifierMapper::registerReference( const OUString& rIdentifier, const Reference< XInterface >& rInterface ) +{ + IdMap_t::const_iterator aIter; + + // Be certain that the references we store in our table are to the + // leading / primary XInterface - cf. findReference + uno::Reference< uno::XInterface > xRef( rInterface, uno::UNO_QUERY ); + + if( findReference( xRef, aIter ) ) + { + return rIdentifier != (*aIter).first; + } + else if( findIdentifier( rIdentifier, aIter ) || findReserved( rIdentifier ) ) + { + return false; + } + else + { + maEntries.insert( IdMap_t::value_type( rIdentifier, xRef ) ); + + // see if this is a reference like something we would generate in the future + const sal_Unicode *p = rIdentifier.getStr(); + sal_Int32 nLength = rIdentifier.getLength(); + + // see if the identifier is 'id' followed by a pure integer value + if( nLength < 2 || p[0] != 'i' || p[1] != 'd' ) + return true; + + nLength -= 2; + p += 2; + + while(nLength--) + { + if( (*p < '0') || (*p > '9') ) + return true; // a custom id, that will never conflict with generated id's + p++; + } + + // the identifier is a pure integer value + // so we make sure we will never generate + // an integer value like this one + sal_Int32 nId = o3tl::toInt32(rIdentifier.subView(2)); + if (nId > 0 && mnNextId <= o3tl::make_unsigned(nId)) + mnNextId = nId + 1; + + return true; + } +} + +const OUString& UnoInterfaceToUniqueIdentifierMapper::getIdentifier( const Reference< XInterface >& rInterface ) const +{ + IdMap_t::const_iterator aIter; + if( findReference( rInterface, aIter ) ) + { + return (*aIter).first; + } + else + { + static const OUString aEmpty; + return aEmpty; + } +} + +const Reference< XInterface >& UnoInterfaceToUniqueIdentifierMapper::getReference( const OUString& rIdentifier ) const +{ + IdMap_t::const_iterator aIter; + if( findIdentifier( rIdentifier, aIter ) ) + { + return (*aIter).second; + } + else + { + static const Reference< XInterface > aEmpty; + return aEmpty; + } +} + +bool UnoInterfaceToUniqueIdentifierMapper::findReference( const Reference< XInterface >& rInterface, IdMap_t::const_iterator& rIter ) const +{ + uno::Reference< uno::XInterface > xRef( rInterface, uno::UNO_QUERY ); + + const IdMap_t::const_iterator aEnd( maEntries.end() ); + rIter = std::find_if(maEntries.begin(), aEnd, [&xRef](const IdMap_t::value_type& rItem) { + // The Reference == operator, does a repeated queryInterface on + // this to ensure we got the right XInterface base-class. However, + // we can be sure that this has been done already by the time we + // get to here. + return rItem.second.get() == xRef.get(); + }); + + return rIter != aEnd; +} + +bool UnoInterfaceToUniqueIdentifierMapper::findIdentifier( const OUString& rIdentifier, IdMap_t::const_iterator& rIter ) const +{ + rIter = maEntries.find( rIdentifier ); + return rIter != maEntries.end(); +} + +bool UnoInterfaceToUniqueIdentifierMapper::reserveIdentifier( const OUString& rIdentifier ) +{ + if ( findReserved( rIdentifier ) ) + return false; + + maReserved.push_back( rIdentifier ); + return true; +} + +bool UnoInterfaceToUniqueIdentifierMapper::registerReservedReference( + const OUString& rIdentifier, + const css::uno::Reference< css::uno::XInterface >& rInterface ) +{ + Reserved_t::const_iterator aIt; + if ( !findReserved( rIdentifier, aIt ) ) + return false; + + Reserved_t::iterator aRemoveIt( maReserved.begin() + ( aIt - maReserved.begin() ) ); + maReserved.erase( aRemoveIt ); + registerReference( rIdentifier, rInterface ); + + return true; +} + +bool UnoInterfaceToUniqueIdentifierMapper::findReserved( const OUString& rIdentifier ) const +{ + Reserved_t::const_iterator aDummy; + return findReserved( rIdentifier, aDummy ); +} + +bool UnoInterfaceToUniqueIdentifierMapper::findReserved( + const OUString& rIdentifier, + Reserved_t::const_iterator& rIter ) const +{ + rIter = std::find( maReserved.begin(), maReserved.end(), rIdentifier ); + return rIter != maReserved.end(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmlcnimp.cxx b/xmloff/source/core/xmlcnimp.cxx new file mode 100644 index 000000000..0a7ab2018 --- /dev/null +++ b/xmloff/source/core/xmlcnimp.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/. + * + * 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 "SvXMLAttrCollection.hxx" +#include +#include + +SvXMLAttrContainerData::SvXMLAttrContainerData() : pimpl( new SvXMLAttrCollection ) +{ +} + +SvXMLAttrContainerData::SvXMLAttrContainerData(const SvXMLAttrContainerData &rCopy) : + pimpl( new SvXMLAttrCollection( *(rCopy.pimpl) ) ) +{ +} + +SvXMLAttrContainerData& SvXMLAttrContainerData::operator=(const SvXMLAttrContainerData &rCopy) +{ + pimpl.reset( new SvXMLAttrCollection( *rCopy.pimpl ) ); + return *this; +} + +SvXMLAttrContainerData& SvXMLAttrContainerData::operator=(SvXMLAttrContainerData&& rCopy) noexcept +{ + pimpl = std::move( rCopy.pimpl ); + return *this; +} + +// Need destructor defined (despite it being empty) to avoid "checked_delete" +// compiler errors. +SvXMLAttrContainerData::~SvXMLAttrContainerData() +{ +} + +bool SvXMLAttrContainerData::operator ==( const SvXMLAttrContainerData& rCmp ) const +{ + return ( *(rCmp.pimpl) == *pimpl ); +} + +bool SvXMLAttrContainerData::AddAttr( const OUString& rLName, + const OUString& rValue ) +{ + assert( !rLName.isEmpty() && "empty attribute name is invalid"); + assert( rLName.indexOf(':') == -1 && "colon in name?"); + return pimpl->AddAttr(rLName, rValue); +} + +bool SvXMLAttrContainerData::AddAttr( const OUString& rPrefix, + const OUString& rNamespace, + const OUString& rLName, + const OUString& rValue ) +{ + assert( !rLName.isEmpty() && "empty attribute name is invalid"); + assert( rPrefix.indexOf(':') == -1 && "colon in prefix?"); + assert( rLName.indexOf(':') == -1 && "colon in name?"); + return pimpl->AddAttr(rPrefix, rNamespace, rLName, rValue); +} + +bool SvXMLAttrContainerData::AddAttr( const OUString& rPrefix, + const OUString& rLName, + const OUString& rValue ) +{ + assert( !rLName.isEmpty() && "empty attribute name is invalid"); + assert( rPrefix.indexOf(':') == -1 && "colon in prefix?"); + assert( rLName.indexOf(':') == -1 && "colon in name?"); + return pimpl->AddAttr(rPrefix, rLName, rValue); +} + +bool SvXMLAttrContainerData::SetAt( size_t i, + const OUString& rLName, + const OUString& rValue ) +{ + assert( !rLName.isEmpty() && "empty attribute name is invalid"); + assert( rLName.indexOf(':') == -1 && "colon in name?"); + return pimpl->SetAt(i, rLName, rValue); +} + +bool SvXMLAttrContainerData::SetAt( size_t i, + const OUString& rPrefix, + const OUString& rNamespace, + const OUString& rLName, + const OUString& rValue ) +{ + assert( !rLName.isEmpty() && "empty attribute name is invalid"); + assert( rPrefix.indexOf(':') == -1 && "colon in prefix?"); + assert( rLName.indexOf(':') == -1 && "colon in name?"); + return pimpl->SetAt(i, rPrefix, rNamespace, rLName, rValue); +} + +bool SvXMLAttrContainerData::SetAt( size_t i, + const OUString& rPrefix, + const OUString& rLName, + const OUString& rValue ) +{ + assert( !rLName.isEmpty() && "empty attribute name is invalid"); + assert( rPrefix.indexOf(':') == -1 && "colon in prefix?"); + assert( rLName.indexOf(':') == -1 && "colon in name?"); + return pimpl->SetAt(i, rPrefix, rLName, rValue); +} + +void SvXMLAttrContainerData::Remove( size_t i ) +{ + pimpl->Remove(i); +} + +size_t SvXMLAttrContainerData::GetAttrCount() const +{ + return pimpl->GetAttrCount(); +} + +const OUString& SvXMLAttrContainerData::GetAttrLName(size_t i) const +{ + return pimpl->GetAttrLName(i); +} + +const OUString& SvXMLAttrContainerData::GetAttrValue(size_t i) const +{ + return pimpl->GetAttrValue(i); +} + +OUString SvXMLAttrContainerData::GetAttrNamespace( size_t i ) const +{ + return pimpl->GetAttrNamespace(i); +} + +OUString SvXMLAttrContainerData::GetAttrPrefix( size_t i ) const +{ + return pimpl->GetAttrPrefix(i); +} + +const OUString& SvXMLAttrContainerData::GetNamespace( sal_uInt16 i ) const +{ + return pimpl->GetNamespace(i); +} + +const OUString& SvXMLAttrContainerData::GetPrefix( sal_uInt16 i ) const +{ + return pimpl->GetPrefix(i); +} + +sal_uInt16 SvXMLAttrContainerData::GetFirstNamespaceIndex() const +{ + return pimpl->GetFirstNamespaceIndex(); +} + +sal_uInt16 SvXMLAttrContainerData::GetNextNamespaceIndex( sal_uInt16 nIdx ) const +{ + return pimpl->GetNextNamespaceIndex( nIdx ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmlenums.hxx b/xmloff/source/core/xmlenums.hxx new file mode 100644 index 000000000..b331dd1ae --- /dev/null +++ b/xmloff/source/core/xmlenums.hxx @@ -0,0 +1,47 @@ +/* -*- 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 + +enum XMLForbiddenCharactersEnum +{ + XML_FORBIDDEN_CHARACTER_LANGUAGE, + XML_FORBIDDEN_CHARACTER_COUNTRY, + XML_FORBIDDEN_CHARACTER_VARIANT, + XML_FORBIDDEN_CHARACTER_BEGIN_LINE, + XML_FORBIDDEN_CHARACTER_END_LINE, + XML_FORBIDDEN_CHARACTER_MAX +}; + +enum XMLSymbolDescriptorsEnum +{ + XML_SYMBOL_DESCRIPTOR_NAME, + XML_SYMBOL_DESCRIPTOR_EXPORT_NAME, + XML_SYMBOL_DESCRIPTOR_SYMBOL_SET, + XML_SYMBOL_DESCRIPTOR_CHARACTER, + XML_SYMBOL_DESCRIPTOR_FONT_NAME, + XML_SYMBOL_DESCRIPTOR_CHAR_SET, + XML_SYMBOL_DESCRIPTOR_FAMILY, + XML_SYMBOL_DESCRIPTOR_PITCH, + XML_SYMBOL_DESCRIPTOR_WEIGHT, + XML_SYMBOL_DESCRIPTOR_ITALIC, + XML_SYMBOL_DESCRIPTOR_MAX +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmlerror.cxx b/xmloff/source/core/xmlerror.cxx new file mode 100644 index 000000000..8b070c7f5 --- /dev/null +++ b/xmloff/source/core/xmlerror.cxx @@ -0,0 +1,208 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XLocator; +using ::com::sun::star::xml::sax::SAXParseException; + + +/// ErrorRecord: contains all information for one error + + +class ErrorRecord +{ +public: + + ErrorRecord( sal_Int32 nId, + const Sequence& rParams, + const OUString& rExceptionMessage, + sal_Int32 nRow, + sal_Int32 nColumn, + const OUString& rPublicId, + const OUString& rSystemId); + + sal_Int32 nId; /// error ID + + OUString sExceptionMessage;/// message of original exception (if available) + + // XLocator information: + sal_Int32 nRow; /// row number where error occurred (or -1 for unknown) + sal_Int32 nColumn; /// column number where error occurred (or -1) + OUString sPublicId; /// public identifier + OUString sSystemId; /// public identifier + + /// message Parameters + Sequence aParams; +}; + + +ErrorRecord::ErrorRecord( sal_Int32 nID, const Sequence& rParams, + const OUString& rExceptionMessage, sal_Int32 nRowNumber, sal_Int32 nCol, + const OUString& rPublicId, const OUString& rSystemId) : + nId(nID), + sExceptionMessage(rExceptionMessage), + nRow(nRowNumber), + nColumn(nCol), + sPublicId(rPublicId), + sSystemId(rSystemId), + aParams(rParams) +{ +} + +XMLErrors::XMLErrors() +{ +} + +XMLErrors::~XMLErrors() +{ +} + +void XMLErrors::AddRecord( + sal_Int32 nId, + const Sequence & rParams, + const OUString& rExceptionMessage, + sal_Int32 nRow, + sal_Int32 nColumn, + const OUString& rPublicId, + const OUString& rSystemId ) +{ + aErrors.emplace_back( nId, rParams, rExceptionMessage, + nRow, nColumn, rPublicId, rSystemId ); + +#ifdef DBG_UTIL + + // give detailed assertion on this message + + OUStringBuffer sMessage; + + sMessage.append( "An error or a warning has occurred during XML import/export!\n" ); + + // ID & flags + sMessage.append( "Error-Id: 0x"); + sMessage.append( nId, 16 ); + sMessage.append( "\n Flags: " ); + sal_Int32 nFlags = (nId & XMLERROR_MASK_FLAG); + sMessage.append( nFlags >> 28, 16 ); + if( (nFlags & XMLERROR_FLAG_WARNING) != 0 ) + sMessage.append( " WARNING" ); + if( (nFlags & XMLERROR_FLAG_ERROR) != 0 ) + sMessage.append( " ERROR" ); + if( (nFlags & XMLERROR_FLAG_SEVERE) != 0 ) + sMessage.append( " SEVERE" ); + sMessage.append( "\n Class: " ); + sal_Int32 nClass = (nId & XMLERROR_MASK_CLASS); + sMessage.append( nClass >> 16, 16 ); + if( (nClass & XMLERROR_CLASS_IO) != 0 ) + sMessage.append( " IO" ); + if( (nClass & XMLERROR_CLASS_FORMAT) != 0 ) + sMessage.append( " FORMAT" ); + if( (nClass & XMLERROR_CLASS_API) != 0 ) + sMessage.append( " API" ); + if( (nClass & XMLERROR_CLASS_OTHER) != 0 ) + sMessage.append( " OTHER" ); + sMessage.append( "\n Number: " ); + sal_Int32 nNumber = (nId & XMLERROR_MASK_NUMBER); + sMessage.append( nNumber, 16 ); + sMessage.append( "\n"); + + // the parameters + sMessage.append( "Parameters:\n" ); + sal_Int32 nLength = rParams.getLength(); + const OUString* pParams = rParams.getConstArray(); + for( sal_Int32 i = 0; i < nLength; i++ ) + { + sMessage.append( " " ); + sMessage.append( i ); + sMessage.append( ": " ); + sMessage.append( pParams[i] ); + sMessage.append( "\n" ); + } + + // the exception message + sMessage.append( "Exception-Message: " ); + sMessage.append( rExceptionMessage ); + sMessage.append( "\n" ); + + // position (if given) + if( (nRow != -1) || (nColumn != -1) ) + { + sMessage.append( "Position:\n Public Identifier: " ); + sMessage.append( rPublicId ); + sMessage.append( "\n System Identifier: " ); + sMessage.append( rSystemId ); + sMessage.append( "\n Row, Column: " ); + sMessage.append( nRow ); + sMessage.append( "," ); + sMessage.append( nColumn ); + sMessage.append( "\n" ); + } + + SAL_WARN( "xmloff", sMessage.makeStringAndClear() ); +#endif +} + +void XMLErrors::AddRecord( + sal_Int32 nId, + const Sequence & rParams, + const OUString& rExceptionMessage, + const Reference & rLocator) +{ + if ( rLocator.is() ) + { + AddRecord( nId, rParams, rExceptionMessage, + rLocator->getLineNumber(), rLocator->getColumnNumber(), + rLocator->getPublicId(), rLocator->getSystemId() ); + } + else + { + AddRecord( nId, rParams, rExceptionMessage, + -1, -1, "", "" ); + } +} + +void XMLErrors::ThrowErrorAsSAXException(sal_Int32 nIdMask) +{ + // search first error/warning that matches the nIdMask + for( const auto& rError : aErrors ) + { + if ( (rError.nId & nIdMask) != 0 ) + { + // we throw the error + ErrorRecord& rErr = aErrors[0]; + throw SAXParseException( + rErr.sExceptionMessage, nullptr, Any(rErr.aParams), + rErr.sPublicId, rErr.sSystemId, rErr.nRow, rErr.nColumn ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmlexp.cxx b/xmloff/source/core/xmlexp.cxx new file mode 100644 index 000000000..55e9b1956 --- /dev/null +++ b/xmloff/source/core/xmlexp.cxx @@ -0,0 +1,2475 @@ +/* -*- 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 + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::io; +using namespace ::xmloff::token; + +constexpr OUStringLiteral XML_MODEL_SERVICE_WRITER = u"com.sun.star.text.TextDocument"; +constexpr OUStringLiteral XML_MODEL_SERVICE_CALC = u"com.sun.star.sheet.SpreadsheetDocument"; +constexpr OUStringLiteral XML_MODEL_SERVICE_DRAW = u"com.sun.star.drawing.DrawingDocument"; +constexpr OUStringLiteral XML_MODEL_SERVICE_IMPRESS = u"com.sun.star.presentation.PresentationDocument"; +constexpr OUStringLiteral XML_MODEL_SERVICE_MATH = u"com.sun.star.formula.FormulaProperties"; +constexpr OUStringLiteral XML_MODEL_SERVICE_CHART = u"com.sun.star.chart.ChartDocument"; + +constexpr OUStringLiteral XML_USEPRETTYPRINTING = u"UsePrettyPrinting"; + +constexpr OUStringLiteral XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE = u"vnd.sun.star.GraphicObject:"; +constexpr OUStringLiteral XML_EMBEDDEDOBJECT_URL_BASE = u"vnd.sun.star.EmbeddedObject:"; + +const std::pair aServiceMap[] = { + { XML_MODEL_SERVICE_WRITER, XML_EXPORT_FILTER_WRITER }, + { XML_MODEL_SERVICE_CALC, XML_EXPORT_FILTER_CALC }, + { XML_MODEL_SERVICE_IMPRESS, XML_EXPORT_FILTER_IMPRESS }, // Impress supports DrawingDocument, + { XML_MODEL_SERVICE_DRAW, XML_EXPORT_FILTER_DRAW }, // too, so it must appear before Draw + { XML_MODEL_SERVICE_MATH, XML_EXPORT_FILTER_MATH }, + { XML_MODEL_SERVICE_CHART, XML_EXPORT_FILTER_CHART }, +}; + +namespace { + +class SettingsExportFacade : public ::xmloff::XMLSettingsExportContext +{ +public: + explicit SettingsExportFacade( SvXMLExport& i_rExport ) + :m_rExport( i_rExport ) + { + } + + virtual ~SettingsExportFacade() + { + } + + virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, + const OUString& i_rValue ) override; + virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, + enum ::xmloff::token::XMLTokenEnum i_eValue ) override; + + virtual void StartElement( enum ::xmloff::token::XMLTokenEnum i_eName ) override; + virtual void EndElement( const bool i_bIgnoreWhitespace ) override; + + virtual void Characters( const OUString& i_rCharacters ) override; + + virtual css::uno::Reference< css::uno::XComponentContext > + GetComponentContext() const override; +private: + SvXMLExport& m_rExport; + ::std::stack< OUString > m_aElements; +}; + +} + +void SettingsExportFacade::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, const OUString& i_rValue ) +{ + m_rExport.AddAttribute( XML_NAMESPACE_CONFIG, i_eName, i_rValue ); +} + +void SettingsExportFacade::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, enum ::xmloff::token::XMLTokenEnum i_eValue ) +{ + m_rExport.AddAttribute( XML_NAMESPACE_CONFIG, i_eName, i_eValue ); +} + +void SettingsExportFacade::StartElement( enum ::xmloff::token::XMLTokenEnum i_eName ) +{ + const OUString sElementName( m_rExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_CONFIG, GetXMLToken( i_eName ) ) ); + m_rExport.StartElement( sElementName, true/*i_bIgnoreWhitespace*/ ); + m_aElements.push( sElementName ); +} + +void SettingsExportFacade::EndElement( const bool i_bIgnoreWhitespace ) +{ + const OUString sElementName( m_aElements.top() ); + m_rExport.EndElement( sElementName, i_bIgnoreWhitespace ); + m_aElements.pop(); +} + +void SettingsExportFacade::Characters( const OUString& i_rCharacters ) +{ + m_rExport.GetDocHandler()->characters( i_rCharacters ); +} + +Reference< XComponentContext > SettingsExportFacade::GetComponentContext() const +{ + return m_rExport.getComponentContext(); +} + +namespace { + +class SvXMLExportEventListener : public cppu::WeakImplHelper< + css::lang::XEventListener > +{ +private: + SvXMLExport* pExport; + +public: + explicit SvXMLExportEventListener(SvXMLExport* pExport); + + // XEventListener + virtual void SAL_CALL disposing(const lang::EventObject& rEventObject) override; +}; + +} + +SvXMLExportEventListener::SvXMLExportEventListener(SvXMLExport* pTempExport) + : pExport(pTempExport) +{ +} + +// XEventListener +void SAL_CALL SvXMLExportEventListener::disposing( const lang::EventObject& ) +{ + if (pExport) + { + pExport->DisposingModel(); + pExport = nullptr; + } +} + +class SvXMLExport_Impl +{ +public: + SvXMLExport_Impl(); + + ::comphelper::UnoInterfaceToUniqueIdentifierMapper maInterfaceToIdentifierMapper; + uno::Reference< uri::XUriReferenceFactory > mxUriReferenceFactory; + OUString msPackageURI; + OUString msPackageURIScheme; + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + bool mbOutlineStyleAsNormalListStyle; + + uno::Reference< embed::XStorage > mxTargetStorage; + + std::optional m_oOverrideODFVersion; + + /// name of stream in package, e.g., "content.xml" + OUString mStreamName; + + OUString maSrcShellID; + OUString maDestShellID; + + /// stack of backed up namespace maps + /// long: depth at which namespace map has been backed up into the stack + ::std::stack< ::std::pair< std::unique_ptr, tools::Long > > mNamespaceMaps; + /// counts depth (number of open elements/start tags) + tools::Long mDepth; + + ::std::unique_ptr< ::xmloff::RDFaExportHelper> mpRDFaHelper; + + bool mbExportTextNumberElement; + bool mbNullDateInitialized; + + void SetSchemeOf( std::u16string_view rOrigFileName ) + { + size_t nSep = rOrigFileName.find(':'); + if( nSep != std::u16string_view::npos ) + msPackageURIScheme = rOrigFileName.substr( 0, nSep ); + } +}; + +SvXMLExport_Impl::SvXMLExport_Impl() +: mxUriReferenceFactory( uri::UriReferenceFactory::create(comphelper::getProcessComponentContext()) ), + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + mbOutlineStyleAsNormalListStyle( false ), + mDepth( 0 ), + mbExportTextNumberElement( false ), + mbNullDateInitialized( false ) +{ +} + +void SvXMLExport::SetDocHandler( const uno::Reference< xml::sax::XDocumentHandler > &rHandler ) +{ + mxHandler = rHandler; + mxExtHandler.set( mxHandler, UNO_QUERY ); +} + +void SvXMLExport::InitCtor_() +{ + // note: it is not necessary to add XML_NP_XML (it is declared implicitly) + if( getExportFlags() & ~SvXMLExportFlags::OASIS ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_OOO), GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO ); + } + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_FO), GetXMLToken(XML_N_FO_COMPAT), XML_NAMESPACE_FO ); + } + if( getExportFlags() & (SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::SETTINGS) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK ); + } + if( getExportFlags() & SvXMLExportFlags::SETTINGS ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_CONFIG), GetXMLToken(XML_N_CONFIG), XML_NAMESPACE_CONFIG ); + } + + if( getExportFlags() & (SvXMLExportFlags::META|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_DC), GetXMLToken(XML_N_DC), XML_NAMESPACE_DC ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_META), GetXMLToken(XML_N_META), XML_NAMESPACE_META ); + } + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::FONTDECLS) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE ); + } + + // namespaces for documents + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_DC), GetXMLToken(XML_N_DC), XML_NAMESPACE_DC ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_TEXT), GetXMLToken(XML_N_TEXT), XML_NAMESPACE_TEXT ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_DRAW), GetXMLToken(XML_N_DRAW), XML_NAMESPACE_DRAW ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_DR3D), GetXMLToken(XML_N_DR3D), XML_NAMESPACE_DR3D ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG_COMPAT), XML_NAMESPACE_SVG ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_CHART), GetXMLToken(XML_N_CHART), XML_NAMESPACE_CHART ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_RPT), GetXMLToken(XML_N_RPT), XML_NAMESPACE_REPORT ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_TABLE), GetXMLToken(XML_N_TABLE), XML_NAMESPACE_TABLE ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_NUMBER),GetXMLToken(XML_N_NUMBER), XML_NAMESPACE_NUMBER ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_OOOW), GetXMLToken(XML_N_OOOW), XML_NAMESPACE_OOOW ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_OOOC), GetXMLToken(XML_N_OOOC), XML_NAMESPACE_OOOC ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_OF), GetXMLToken(XML_N_OF), XML_NAMESPACE_OF ); + + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + mpNamespaceMap->Add( + GetXMLToken(XML_NP_TABLE_EXT), GetXMLToken(XML_N_TABLE_EXT), XML_NAMESPACE_TABLE_EXT); + mpNamespaceMap->Add( + GetXMLToken(XML_NP_CALC_EXT), GetXMLToken(XML_N_CALC_EXT), XML_NAMESPACE_CALC_EXT); + mpNamespaceMap->Add( + GetXMLToken(XML_NP_DRAW_EXT), GetXMLToken(XML_N_DRAW_EXT), XML_NAMESPACE_DRAW_EXT); + mpNamespaceMap->Add( + GetXMLToken(XML_NP_LO_EXT), GetXMLToken(XML_N_LO_EXT), + XML_NAMESPACE_LO_EXT); + mpNamespaceMap->Add( GetXMLToken(XML_NP_FIELD), GetXMLToken(XML_N_FIELD), XML_NAMESPACE_FIELD ); + } + } + if( getExportFlags() & (SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_MATH), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_FORM), GetXMLToken(XML_N_FORM), XML_NAMESPACE_FORM ); + } + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_SCRIPT), GetXMLToken(XML_N_SCRIPT), XML_NAMESPACE_SCRIPT ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_DOM), GetXMLToken(XML_N_DOM), XML_NAMESPACE_DOM ); + } + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_XFORMS_1_0), GetXMLToken(XML_N_XFORMS_1_0), XML_NAMESPACE_XFORMS ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_XSD), GetXMLToken(XML_N_XSD), XML_NAMESPACE_XSD ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_XSI), GetXMLToken(XML_N_XSI), XML_NAMESPACE_XSI ); + mpNamespaceMap->Add( GetXMLToken(XML_NP_FORMX), GetXMLToken(XML_N_FORMX), XML_NAMESPACE_FORMX ); + } + + // RDFa: needed for content and header/footer styles + if( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_XHTML), + GetXMLToken(XML_N_XHTML), XML_NAMESPACE_XHTML ); + } + // GRDDL: to convert RDFa and meta.xml to RDF + if( getExportFlags() & (SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::CONTENT) ) + { + mpNamespaceMap->Add( GetXMLToken(XML_NP_GRDDL), + GetXMLToken(XML_N_GRDDL), XML_NAMESPACE_GRDDL ); + } + // CSS Text Level 3 for distributed text justification. + if ( getExportFlags() & (SvXMLExportFlags::STYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::MASTERSTYLES) ) + { + mpNamespaceMap->Add( + GetXMLToken(XML_NP_CSS3TEXT), GetXMLToken(XML_N_CSS3TEXT), XML_NAMESPACE_CSS3TEXT ); + } + + if (mxModel.is() && !mxEventListener.is()) + { + mxEventListener.set( new SvXMLExportEventListener(this)); + mxModel->addEventListener(mxEventListener); + } + + // Determine model type (#i51726#) + DetermineModelType_(); +} + +// Shapes in Writer cannot be named via context menu (#i51726#) +void SvXMLExport::DetermineModelType_() +{ + meModelType = SvtModuleOptions::EFactory::UNKNOWN_FACTORY; + + if ( !mxModel.is() ) + return; + + meModelType = SvtModuleOptions::ClassifyFactoryByModel( mxModel ); + + // note: MATH documents will throw NotInitializedException; maybe unit test problem + if (meModelType == SvtModuleOptions::EFactory::WRITER) + { + uno::Reference const xModule(mxModel, uno::UNO_QUERY); + bool const isBaseForm(xModule.is() && + xModule->getIdentifier() == "com.sun.star.sdb.FormDesign"); + if (isBaseForm) + { + switch (GetODFSaneDefaultVersion()) + { + case SvtSaveOptions::ODFSVER_013_EXTENDED: + SAL_INFO("xmloff.core", "tdf#138209 force form export to ODF 1.2"); + mpImpl->m_oOverrideODFVersion = SvtSaveOptions::ODFSVER_012_EXTENDED; + maUnitConv.overrideSaneDefaultVersion(SvtSaveOptions::ODFSVER_012_EXTENDED); + break; + case SvtSaveOptions::ODFSVER_013: + SAL_INFO("xmloff.core", "tdf#138209 force form export to ODF 1.2"); + mpImpl->m_oOverrideODFVersion = SvtSaveOptions::ODFSVER_012; + maUnitConv.overrideSaneDefaultVersion(SvtSaveOptions::ODFSVER_012); + break; + default: + break; + } + } + } +} + +SvXMLExport::SvXMLExport( + const uno::Reference< uno::XComponentContext >& xContext, + OUString const & implementationName, + sal_Int16 const eDefaultMeasureUnit /*css::util::MeasureUnit*/, + const enum XMLTokenEnum eClass, SvXMLExportFlags nExportFlags ) +: mpImpl( new SvXMLExport_Impl ), + m_xContext(xContext), m_implementationName(implementationName), + mxAttrList( new SvXMLAttributeList ), + mpNamespaceMap( new SvXMLNamespaceMap ), + mpAuthorIDs( new SvtSecurityMapPersonalInfo ), + maUnitConv(xContext, util::MeasureUnit::MM_100TH, eDefaultMeasureUnit, getSaneDefaultVersion()), + meClass( eClass ), + mnExportFlags( nExportFlags ), + mnErrorFlags( SvXMLErrorFlags::NO ), + msWS( GetXMLToken(XML_WS) ), + mbSaveLinkedSections(true), + mbAutoStylesCollected(false) +{ + SAL_WARN_IF( !xContext.is(), "xmloff.core", "got no service manager" ); + InitCtor_(); +} + +SvXMLExport::SvXMLExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + const OUString &rFileName, + sal_Int16 const eDefaultMeasureUnit /*css::util::MeasureUnit*/, + const uno::Reference< xml::sax::XDocumentHandler > & rHandler) +: mpImpl( new SvXMLExport_Impl ), + m_xContext(xContext), m_implementationName(implementationName), + mxHandler( rHandler ), + mxExtHandler( rHandler, uno::UNO_QUERY ), + mxAttrList( new SvXMLAttributeList ), + msOrigFileName( rFileName ), + mpNamespaceMap( new SvXMLNamespaceMap ), + mpAuthorIDs( new SvtSecurityMapPersonalInfo ), + maUnitConv(xContext, util::MeasureUnit::MM_100TH, eDefaultMeasureUnit, getSaneDefaultVersion()), + meClass( XML_TOKEN_INVALID ), + mnExportFlags( SvXMLExportFlags::NONE ), + mnErrorFlags( SvXMLErrorFlags::NO ), + msWS( GetXMLToken(XML_WS) ), + mbSaveLinkedSections(true), + mbAutoStylesCollected(false) +{ + SAL_WARN_IF( !xContext.is(), "xmloff.core", "got no service manager" ); + mpImpl->SetSchemeOf( msOrigFileName ); + InitCtor_(); + + if (mxNumberFormatsSupplier.is()) + mpNumExport.reset( new SvXMLNumFmtExport(*this, mxNumberFormatsSupplier) ); +} + +SvXMLExport::SvXMLExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + const OUString &rFileName, + const uno::Reference< xml::sax::XDocumentHandler > & rHandler, + const Reference< XModel >& rModel, + FieldUnit const eDefaultFieldUnit, + SvXMLExportFlags nExportFlag) +: mpImpl( new SvXMLExport_Impl ), + m_xContext(xContext), m_implementationName(implementationName), + mxModel( rModel ), + mxHandler( rHandler ), + mxExtHandler( rHandler, uno::UNO_QUERY ), + mxNumberFormatsSupplier (rModel, uno::UNO_QUERY), + mxAttrList( new SvXMLAttributeList ), + msOrigFileName( rFileName ), + mpNamespaceMap( new SvXMLNamespaceMap ), + mpAuthorIDs( new SvtSecurityMapPersonalInfo ), + maUnitConv( xContext, + util::MeasureUnit::MM_100TH, + SvXMLUnitConverter::GetMeasureUnit(eDefaultFieldUnit), + getSaneDefaultVersion()), + meClass( XML_TOKEN_INVALID ), + mnExportFlags( nExportFlag ), + mnErrorFlags( SvXMLErrorFlags::NO ), + msWS( GetXMLToken(XML_WS) ), + mbSaveLinkedSections(true), + mbAutoStylesCollected(false) +{ + SAL_WARN_IF(!xContext.is(), "xmloff.core", "got no service manager" ); + mpImpl->SetSchemeOf( msOrigFileName ); + InitCtor_(); + + if (mxNumberFormatsSupplier.is()) + mpNumExport.reset( new SvXMLNumFmtExport(*this, mxNumberFormatsSupplier) ); +} + +SvXMLExport::~SvXMLExport() +{ + mpXMLErrors.reset(); + mpImageMapExport.reset(); + mpEventExport.reset(); + mpNamespaceMap.reset(); + if (mpProgressBarHelper || mpNumExport) + { + if (mxExportInfo.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxExportInfo->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + if (mpProgressBarHelper) + { + static constexpr OUStringLiteral sProgressMax(XML_PROGRESSMAX); + static constexpr OUStringLiteral sProgressCurrent(XML_PROGRESSCURRENT); + static constexpr OUStringLiteral sRepeat(XML_PROGRESSREPEAT); + if (xPropertySetInfo->hasPropertyByName(sProgressMax) && + xPropertySetInfo->hasPropertyByName(sProgressCurrent)) + { + sal_Int32 nProgressMax(mpProgressBarHelper->GetReference()); + sal_Int32 nProgressCurrent(mpProgressBarHelper->GetValue()); + mxExportInfo->setPropertyValue(sProgressMax, uno::Any(nProgressMax)); + mxExportInfo->setPropertyValue(sProgressCurrent, uno::Any(nProgressCurrent)); + } + if (xPropertySetInfo->hasPropertyByName(sRepeat)) + mxExportInfo->setPropertyValue(sRepeat, css::uno::Any(mpProgressBarHelper->GetRepeat())); + } + if (mpNumExport && (mnExportFlags & (SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::STYLES))) + { + static constexpr OUStringLiteral sWrittenNumberFormats(XML_WRITTENNUMBERSTYLES); + if (xPropertySetInfo->hasPropertyByName(sWrittenNumberFormats)) + { + mxExportInfo->setPropertyValue(sWrittenNumberFormats, Any(mpNumExport->GetWasUsed())); + } + } + } + } + mpProgressBarHelper.reset(); + mpNumExport.reset(); + } + + if (mxEventListener.is() && mxModel.is()) + mxModel->removeEventListener(mxEventListener); +} + +// XExporter +void SAL_CALL SvXMLExport::setSourceDocument( const uno::Reference< lang::XComponent >& xDoc ) +{ + mxModel.set( xDoc, UNO_QUERY ); + if( !mxModel.is() ) + throw lang::IllegalArgumentException(); + if (mxModel.is() && ! mxEventListener.is()) + { + mxEventListener.set( new SvXMLExportEventListener(this)); + mxModel->addEventListener(mxEventListener); + } + + if(!mxNumberFormatsSupplier.is() ) + { + mxNumberFormatsSupplier.set(mxModel, css::uno::UNO_QUERY); + if(mxNumberFormatsSupplier.is() && mxHandler.is()) + mpNumExport.reset( new SvXMLNumFmtExport(*this, mxNumberFormatsSupplier) ); + } + if (mxExportInfo.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxExportInfo->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + OUString sUsePrettyPrinting(XML_USEPRETTYPRINTING); + if (xPropertySetInfo->hasPropertyByName(sUsePrettyPrinting)) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sUsePrettyPrinting); + if (::cppu::any2bool(aAny)) + mnExportFlags |= SvXMLExportFlags::PRETTY; + else + mnExportFlags &= ~SvXMLExportFlags::PRETTY; + } + + if (mpNumExport && (mnExportFlags & (SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::STYLES))) + { + OUString sWrittenNumberFormats(XML_WRITTENNUMBERSTYLES); + if (xPropertySetInfo->hasPropertyByName(sWrittenNumberFormats)) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sWrittenNumberFormats); + uno::Sequence aWasUsed; + if(aAny >>= aWasUsed) + mpNumExport->SetWasUsed(aWasUsed); + } + } + } + } + + // namespaces for user defined attributes + Reference< XMultiServiceFactory > xFactory( mxModel, UNO_QUERY ); + if( xFactory.is() ) + { + try + { + Reference < XInterface > xIfc = + xFactory->createInstance("com.sun.star.xml.NamespaceMap"); + if( xIfc.is() ) + { + Reference< XNameAccess > xNamespaceMap( xIfc, UNO_QUERY ); + if( xNamespaceMap.is() ) + { + const Sequence< OUString > aPrefixes( xNamespaceMap->getElementNames() ); + for( OUString const & prefix : aPrefixes ) + { + OUString aURL; + if( xNamespaceMap->getByName( prefix ) >>= aURL ) + GetNamespaceMap_().Add( prefix, aURL ); + } + } + } + } + catch(const css::uno::Exception&) + { + } + } + + // Determine model type (#i51726#) + DetermineModelType_(); +} + +// XInitialize +void SAL_CALL SvXMLExport::initialize( const uno::Sequence< uno::Any >& aArguments ) +{ + // #93186# we need to queryInterface every single Any with any expected outcome. This variable hold the queryInterface results. + + for( const auto& rAny : aArguments ) + { + Reference xValue; + rAny >>= xValue; + + // status indicator + uno::Reference xTmpStatus( xValue, UNO_QUERY ); + if ( xTmpStatus.is() ) + mxStatusIndicator = xTmpStatus; + + // graphic storage handler + uno::Reference xGraphicStorageHandler(xValue, UNO_QUERY); + if (xGraphicStorageHandler.is()) + mxGraphicStorageHandler = xGraphicStorageHandler; + + // object resolver + uno::Reference xTmpObjectResolver( + xValue, UNO_QUERY ); + if ( xTmpObjectResolver.is() ) + mxEmbeddedResolver = xTmpObjectResolver; + + // document handler + uno::Reference xTmpDocHandler( + xValue, UNO_QUERY ); + if( xTmpDocHandler.is() ) + { + mxHandler = xTmpDocHandler; + rAny >>= mxExtHandler; + + if (mxNumberFormatsSupplier.is() && mpNumExport == nullptr) + mpNumExport.reset( new SvXMLNumFmtExport(*this, mxNumberFormatsSupplier) ); + } + + // property set to transport data across + uno::Reference xTmpPropertySet( + xValue, UNO_QUERY ); + if( xTmpPropertySet.is() ) + mxExportInfo = xTmpPropertySet; + } + + if( !mxExportInfo.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = + mxExportInfo->getPropertySetInfo(); + static constexpr OUStringLiteral sBaseURI = u"BaseURI"; + if( xPropertySetInfo->hasPropertyByName(sBaseURI) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sBaseURI); + aAny >>= msOrigFileName; + mpImpl->msPackageURI = msOrigFileName; + mpImpl->SetSchemeOf( msOrigFileName ); + } + OUString sRelPath; + static constexpr OUStringLiteral sStreamRelPath = u"StreamRelPath"; + if( xPropertySetInfo->hasPropertyByName(sStreamRelPath) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sStreamRelPath); + aAny >>= sRelPath; + } + OUString sName; + static constexpr OUStringLiteral sStreamName = u"StreamName"; + if( xPropertySetInfo->hasPropertyByName(sStreamName) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sStreamName); + aAny >>= sName; + } + if( !msOrigFileName.isEmpty() && !sName.isEmpty() ) + { + INetURLObject aBaseURL( msOrigFileName ); + if( !sRelPath.isEmpty() ) + aBaseURL.insertName( sRelPath ); + aBaseURL.insertName( sName ); + msOrigFileName = aBaseURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + } + mpImpl->mStreamName = sName; // Note: may be empty (XSLT) + + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + static const OUStringLiteral sOutlineStyleAsNormalListStyle( + u"OutlineStyleAsNormalListStyle" ); + if( xPropertySetInfo->hasPropertyByName( sOutlineStyleAsNormalListStyle ) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue( sOutlineStyleAsNormalListStyle ); + aAny >>= mpImpl->mbOutlineStyleAsNormalListStyle; + } + + OUString sTargetStorage( "TargetStorage" ); + if( xPropertySetInfo->hasPropertyByName( sTargetStorage ) ) + mxExportInfo->getPropertyValue( sTargetStorage ) >>= mpImpl->mxTargetStorage; + + static const OUStringLiteral sExportTextNumberElement( + u"ExportTextNumberElement" ); + if( xPropertySetInfo->hasPropertyByName( sExportTextNumberElement ) ) + { + uno::Any aAny = mxExportInfo->getPropertyValue( sExportTextNumberElement ); + aAny >>= mpImpl->mbExportTextNumberElement; + } +} + +// XFilter +sal_Bool SAL_CALL SvXMLExport::filter( const uno::Sequence< beans::PropertyValue >& aDescriptor ) +{ + // check for xHandler first... should have been supplied in initialize + if( !mxHandler.is() ) + return false; + + try + { + const SvXMLExportFlags nTest = + SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SETTINGS; + if( (mnExportFlags & nTest) == nTest && msOrigFileName.isEmpty() ) + { + // evaluate descriptor only for flat files and if a base URI + // has not been provided already + + for( const auto& rProp : aDescriptor ) + { + const OUString& rPropName = rProp.Name; + const Any& rValue = rProp.Value; + + if ( rPropName == "FileName" ) + { + if( !(rValue >>= msOrigFileName ) ) + return false; + } + else if ( rPropName == "FilterName" ) + { + if( !(rValue >>= msFilterName ) ) + return false; + } + } + } + + for( const auto& rProp : aDescriptor ) + { + const OUString& rPropName = rProp.Name; + const Any& rValue = rProp.Value; + + if (rPropName == "SourceShellID") + { + if (!(rValue >>= mpImpl->maSrcShellID)) + return false; + } + else if (rPropName == "DestinationShellID") + { + if (!(rValue >>= mpImpl->maDestShellID)) + return false; + } + else if( rPropName == "ImageFilter") + { + if (!(rValue >>= msImgFilterName)) + return false; + } + } + + + exportDoc( meClass ); + } + catch(const uno::Exception& e) + { + // We must catch exceptions, because according to the + // API definition export must not throw one! + css::uno::Any ex(cppu::getCaughtException()); + OUString sMessage( ex.getValueTypeName() + ": \"" + e.Message + "\""); + if (e.Context.is()) + { + const char* pContext = typeid(*e.Context).name(); + sMessage += " (context: " + OUString::createFromAscii(pContext) + " )"; + } + SetError( XMLERROR_FLAG_ERROR | XMLERROR_FLAG_SEVERE | XMLERROR_API, + Sequence(), sMessage, nullptr ); + } + + // return true only if no error occurred + return (mnErrorFlags & (SvXMLErrorFlags::DO_NOTHING|SvXMLErrorFlags::ERROR_OCCURRED)) == SvXMLErrorFlags::NO; +} + +void SAL_CALL SvXMLExport::cancel() +{ + // stop export + Sequence aEmptySeq; + SetError(XMLERROR_CANCEL|XMLERROR_FLAG_SEVERE, aEmptySeq); +} + +OUString SAL_CALL SvXMLExport::getName( ) +{ + return msFilterName; +} + +void SAL_CALL SvXMLExport::setName( const OUString& ) +{ + // do nothing, because it is not possible to set the FilterName +} + +// XServiceInfo +OUString SAL_CALL SvXMLExport::getImplementationName( ) +{ + return m_implementationName; +} + +sal_Bool SAL_CALL SvXMLExport::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SvXMLExport::getSupportedServiceNames( ) +{ + return { "com.sun.star.document.ExportFilter", "com.sun.star.xml.XMLExportFilter" }; +} + +OUString +SvXMLExport::EnsureNamespace(OUString const & i_rNamespace) +{ + OUString const aPreferredPrefix("gen"); + OUString sPrefix; + sal_uInt16 nKey( GetNamespaceMap_().GetKeyByName( i_rNamespace ) ); + if( XML_NAMESPACE_UNKNOWN == nKey ) + { + // There is no prefix for the namespace, so + // we have to generate one and have to add it. + sPrefix = aPreferredPrefix; + nKey = GetNamespaceMap_().GetKeyByPrefix( sPrefix ); + sal_Int32 n( 0 ); + OUStringBuffer buf; + while( nKey != USHRT_MAX ) + { + buf.append( aPreferredPrefix ); + buf.append( ++n ); + sPrefix = buf.makeStringAndClear(); + nKey = GetNamespaceMap_().GetKeyByPrefix( sPrefix ); + } + + if (mpImpl->mNamespaceMaps.empty() + || (mpImpl->mNamespaceMaps.top().second != mpImpl->mDepth)) + { + // top was created for lower depth... need a new namespace map! + auto pNew = new SvXMLNamespaceMap( *mpNamespaceMap ); + mpImpl->mNamespaceMaps.push( + ::std::make_pair(std::move(mpNamespaceMap), mpImpl->mDepth) ); + mpNamespaceMap.reset( pNew ); + } + + // add the namespace to the map and as attribute + mpNamespaceMap->Add( sPrefix, i_rNamespace ); + AddAttribute( GetXMLToken(XML_XMLNS) + ":" + sPrefix, i_rNamespace ); + } + else + { + // If there is a prefix for the namespace, reuse that. + sPrefix = GetNamespaceMap_().GetPrefixByKey( nKey ); + } + return sPrefix; +} + +void SvXMLExport::AddAttribute( sal_uInt16 nPrefixKey, const OUString& rName, + const OUString& rValue ) +{ + AddAttribute(GetNamespaceMap_().GetQNameByKey(nPrefixKey, rName), rValue); +} + +void SvXMLExport::AddAttribute( sal_uInt16 nPrefixKey, + enum XMLTokenEnum eName, + const OUString& rValue ) +{ + AddAttribute(nPrefixKey, GetXMLToken(eName), rValue); +} + +void SvXMLExport::AddAttribute( sal_uInt16 nPrefixKey, + enum XMLTokenEnum eName, + enum XMLTokenEnum eValue) +{ + AddAttribute(nPrefixKey, eName, GetXMLToken(eValue)); +} + +void SvXMLExport::AddAttribute( const OUString& rQName, + const OUString& rValue ) +{ + mxAttrList->AddAttribute( + rQName, + rValue ); +} + +void SvXMLExport::AddAttribute( const OUString& rQName, + enum ::xmloff::token::XMLTokenEnum eValue ) +{ + AddAttribute(rQName, GetXMLToken(eValue)); +} + +void SvXMLExport::AddLanguageTagAttributes( sal_uInt16 nPrefix, sal_uInt16 nPrefixRfc, + const css::lang::Locale& rLocale, bool bWriteEmpty ) +{ + if (rLocale.Variant.isEmpty()) + { + // Per convention The BCP 47 string is always stored in Variant, if + // that is empty we have a plain language-country combination, no need + // to convert to LanguageTag first. Also catches the case of empty + // locale denoting system locale. + xmloff::token::XMLTokenEnum eLanguage, eCountry; + eLanguage = XML_LANGUAGE; + eCountry = XML_COUNTRY; + if (bWriteEmpty || !rLocale.Language.isEmpty()) + AddAttribute( nPrefix, eLanguage, rLocale.Language); + if (bWriteEmpty || !rLocale.Country.isEmpty()) + AddAttribute( nPrefix, eCountry, rLocale.Country); + } + else + { + LanguageTag aLanguageTag( rLocale); + AddLanguageTagAttributes( nPrefix, nPrefixRfc, aLanguageTag, bWriteEmpty); + } +} + +void SvXMLExport::AddLanguageTagAttributes( sal_uInt16 nPrefix, sal_uInt16 nPrefixRfc, + const LanguageTag& rLanguageTag, bool bWriteEmpty ) +{ + if (rLanguageTag.isIsoODF()) + { + if (bWriteEmpty || !rLanguageTag.isSystemLocale()) + { + AddAttribute( nPrefix, XML_LANGUAGE, rLanguageTag.getLanguage()); + if (rLanguageTag.hasScript() && getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + AddAttribute( nPrefix, XML_SCRIPT, rLanguageTag.getScript()); + if (bWriteEmpty || !rLanguageTag.getCountry().isEmpty()) + AddAttribute( nPrefix, XML_COUNTRY, rLanguageTag.getCountry()); + } + } + else + { + if (getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + AddAttribute( nPrefixRfc, XML_RFC_LANGUAGE_TAG, rLanguageTag.getBcp47()); + // Also in case of non-pure-ISO tag store best matching fo: attributes + // for consumers not handling *:rfc-language-tag, ensuring that only + // valid ISO codes are stored. Here the bWriteEmpty parameter has no + // meaning. + OUString aLanguage, aScript, aCountry; + rLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry); + if (!aLanguage.isEmpty()) + { + AddAttribute( nPrefix, XML_LANGUAGE, aLanguage); + if (!aScript.isEmpty() && getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + AddAttribute( nPrefix, XML_SCRIPT, aScript); + if (!aCountry.isEmpty()) + AddAttribute( nPrefix, XML_COUNTRY, aCountry); + } + } +} + +void SvXMLExport::AddAttributeList( const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + if( xAttrList.is()) + mxAttrList->AppendAttributeList( xAttrList ); +} + +void SvXMLExport::ClearAttrList() +{ + mxAttrList->Clear(); +} + +#ifdef DBG_UTIL +void SvXMLExport::CheckAttrList() +{ + SAL_WARN_IF( mxAttrList->getLength(), "xmloff.core", "XMLExport::CheckAttrList: list is not empty" ); +} +#endif + +void SvXMLExport::ImplExportMeta() +{ + CheckAttrList(); + + ExportMeta_(); +} + +void SvXMLExport::ImplExportSettings() +{ + CheckAttrList(); + + ::std::vector< SettingsGroup > aSettings; + sal_Int32 nSettingsCount = 0; + + // view settings + uno::Sequence< beans::PropertyValue > aViewSettings; + GetViewSettingsAndViews( aViewSettings ); + aSettings.emplace_back( XML_VIEW_SETTINGS, aViewSettings ); + nSettingsCount += aViewSettings.getLength(); + + // configuration settings + uno::Sequence aConfigSettings; + GetConfigurationSettings( aConfigSettings ); + aSettings.emplace_back( XML_CONFIGURATION_SETTINGS, aConfigSettings ); + nSettingsCount += aConfigSettings.getLength(); + + // any document specific settings + nSettingsCount += GetDocumentSpecificSettings( aSettings ); + + { + SvXMLElementExport aElem( *this, + nSettingsCount != 0, + XML_NAMESPACE_OFFICE, XML_SETTINGS, + true, true ); + + SettingsExportFacade aSettingsExportContext( *this ); + XMLSettingsExportHelper aSettingsExportHelper( aSettingsExportContext ); + + for (auto const& settings : aSettings) + { + if ( !settings.aSettings.hasElements() ) + continue; + + const OUString& sSettingsName( GetXMLToken( settings.eGroupName ) ); + OUString sQName = GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OOO, sSettingsName ); + aSettingsExportHelper.exportAllSettings( settings.aSettings, sQName ); + } + } +} + +void SvXMLExport::ImplExportStyles() +{ + CheckAttrList(); + + { + // + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, XML_STYLES, + true, true ); + + ExportStyles_( false ); + } + + // transfer style names (+ families) TO other components (if appropriate) + if( ( mnExportFlags & SvXMLExportFlags::CONTENT ) || !mxExportInfo.is() ) + return; + + static constexpr OUStringLiteral sStyleNames( u"StyleNames" ); + static constexpr OUStringLiteral sStyleFamilies( u"StyleFamilies" ); + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxExportInfo->getPropertySetInfo(); + if ( xPropertySetInfo->hasPropertyByName( sStyleNames ) && xPropertySetInfo->hasPropertyByName( sStyleFamilies ) ) + { + Sequence aStyleFamilies; + Sequence aStyleNames; + mxAutoStylePool->GetRegisteredNames( aStyleFamilies, aStyleNames ); + mxExportInfo->setPropertyValue( sStyleNames, Any( aStyleNames ) ); + mxExportInfo->setPropertyValue( sStyleFamilies, + Any( aStyleFamilies ) ); + } +} + +void SvXMLExport::ImplExportAutoStyles() +{ + // transfer style names (+ families) FROM other components (if appropriate) + OUString sStyleNames( "StyleNames" ); + OUString sStyleFamilies( "StyleFamilies" ); + if( ( !( mnExportFlags & SvXMLExportFlags::STYLES ) ) + && mxExportInfo.is() + && mxExportInfo->getPropertySetInfo()->hasPropertyByName( sStyleNames ) + && mxExportInfo->getPropertySetInfo()->hasPropertyByName( sStyleFamilies ) ) + { + Sequence aStyleFamilies; + mxExportInfo->getPropertyValue( sStyleFamilies ) >>= aStyleFamilies; + Sequence aStyleNames; + mxExportInfo->getPropertyValue( sStyleNames ) >>= aStyleNames; + mxAutoStylePool->RegisterNames( aStyleFamilies, aStyleNames ); + } + + { + // + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, + XML_AUTOMATIC_STYLES, true, true ); + + ExportAutoStyles_(); + } +} + +void SvXMLExport::ImplExportMasterStyles() +{ + // + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, XML_MASTER_STYLES, + true, true ); + + ExportMasterStyles_(); +} + +void SvXMLExport::ImplExportContent() +{ + CheckAttrList(); + + { + SvXMLElementExport aElement( *this, XML_NAMESPACE_OFFICE, XML_BODY, + true, true ); + { + XMLTokenEnum eClass = meClass; + if( XML_TEXT_GLOBAL == eClass ) + { + AddAttribute( XML_NAMESPACE_TEXT, XML_GLOBAL, + GetXMLToken( XML_TRUE ) ); + eClass = XML_TEXT; + } + if ( XML_GRAPHICS == eClass ) + eClass = XML_DRAWING; + // + SetBodyAttributes(); + SvXMLElementExport aElem( *this, meClass != XML_TOKEN_INVALID, + XML_NAMESPACE_OFFICE, eClass, + true, true ); + + ExportContent_(); + } + } +} + +void SvXMLExport::SetBodyAttributes() +{ +} + +static void +lcl_AddGrddl(SvXMLExport const & rExport, const SvXMLExportFlags /*nExportMode*/) +{ + // check version >= 1.2 + switch (rExport.getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: return; + default: break; + } + + // #i115030#: disabled, the XSLT is not finished, and not available via HTTP +#if 0 + if (SvXMLExportFlags::SETTINGS != nExportMode) // meta, content, styles + { + rExport.AddAttribute( XML_NAMESPACE_GRDDL, XML_TRANSFORMATION, + OUString("http://FIXME") ); + } +#endif +} + +void SvXMLExport::addChaffWhenEncryptedStorage() +{ + uno::Reference< embed::XEncryptionProtectedSource2 > xEncr(mpImpl->mxTargetStorage, uno::UNO_QUERY); + + if (xEncr.is() && xEncr->hasEncryptionData() && mxExtHandler.is()) + { + mxExtHandler->comment(OStringToOUString(comphelper::xml::makeXMLChaff(), RTL_TEXTENCODING_ASCII_US)); + } +} + +auto SvXMLExport::GetODFVersionAttributeValue() const -> char const* +{ + char const* pVersion(nullptr); + switch (getSaneDefaultVersion()) + { + case SvtSaveOptions::ODFSVER_013_EXTENDED: [[fallthrough]]; + case SvtSaveOptions::ODFSVER_013: pVersion = "1.3"; break; + case SvtSaveOptions::ODFSVER_012_EXTENDED: [[fallthrough]]; + case SvtSaveOptions::ODFSVER_012_EXT_COMPAT: [[fallthrough]]; + case SvtSaveOptions::ODFSVER_012: pVersion = "1.2"; break; + case SvtSaveOptions::ODFSVER_011: pVersion = "1.1"; break; + case SvtSaveOptions::ODFSVER_010: break; + + default: + assert(!"xmloff::SvXMLExport::exportDoc(), unexpected odf default version!"); + } + return pVersion; +} + +ErrCode SvXMLExport::exportDoc( enum ::xmloff::token::XMLTokenEnum eClass ) +{ + bool bOwnGraphicResolver = false; + bool bOwnEmbeddedResolver = false; + + if (!mxGraphicStorageHandler.is() || !mxEmbeddedResolver.is()) + { + Reference< XMultiServiceFactory > xFactory( mxModel, UNO_QUERY ); + if( xFactory.is() ) + { + try + { + if (!mxGraphicStorageHandler.is()) + { + mxGraphicStorageHandler.set(xFactory->createInstance( "com.sun.star.document.ExportGraphicStorageHandler"), UNO_QUERY); + bOwnGraphicResolver = mxGraphicStorageHandler.is(); + } + + if( !mxEmbeddedResolver.is() ) + { + mxEmbeddedResolver.set( + xFactory->createInstance( "com.sun.star.document.ExportEmbeddedObjectResolver" ), UNO_QUERY); + bOwnEmbeddedResolver = mxEmbeddedResolver.is(); + } + } + catch(const css::uno::Exception&) + { + } + } + } + if( (getExportFlags() & SvXMLExportFlags::OASIS) == SvXMLExportFlags::NONE ) + { + try + { + static ::comphelper::PropertyMapEntry const aInfoMap[] = + { + { OUString("Class"), 0, + ::cppu::UnoType::get(), + PropertyAttribute::MAYBEVOID, 0}, + }; + Reference< XPropertySet > xConvPropSet( + ::comphelper::GenericPropertySet_CreateInstance( + new ::comphelper::PropertySetInfo( aInfoMap ) ) ); + + xConvPropSet->setPropertyValue( "Class", Any(GetXMLToken( eClass )) ); + + Reference< XPropertySet > xPropSet = + mxExportInfo.is() + ? PropertySetMerger_CreateInstance( mxExportInfo, + xConvPropSet ) + : xConvPropSet; + + Sequence aArgs{ Any(mxHandler), Any(xPropSet), Any(mxModel) }; + // get filter component + Reference< xml::sax::XDocumentHandler > xTmpDocHandler( + m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.comp.Oasis2OOoTransformer", aArgs, m_xContext), + UNO_QUERY); + SAL_WARN_IF(!xTmpDocHandler.is(), "xmloff.core", "can't instantiate OASIS transformer component" ); + if( xTmpDocHandler.is() ) + { + mxHandler = xTmpDocHandler; + mxExtHandler.set( mxHandler, UNO_QUERY ); + } + } + catch(const css::uno::Exception&) + { + } + } + + mxHandler->startDocument(); + + addChaffWhenEncryptedStorage(); + + // + CheckAttrList(); + + // namespace attributes + // ( The namespace decls should be first attributes in the element; + // some faulty XML parsers (JAXP1.1) have a problem with this, + // also it's more elegant ) + sal_uInt16 nPos = mpNamespaceMap->GetFirstKey(); + while( USHRT_MAX != nPos ) + { + mxAttrList->AddAttribute( mpNamespaceMap->GetAttrNameByKey( nPos ), + mpNamespaceMap->GetNameByKey( nPos ) ); + nPos = mpNamespaceMap->GetNextKey( nPos ); + } + + // office:version = ... + const char*const pVersion = GetODFVersionAttributeValue(); + + if (pVersion) + { + AddAttribute( XML_NAMESPACE_OFFICE, XML_VERSION, + OUString::createFromAscii(pVersion) ); + } + + { + enum XMLTokenEnum eRootService = XML_TOKEN_INVALID; + const SvXMLExportFlags nExportMode = mnExportFlags & (SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SETTINGS); + + lcl_AddGrddl(*this, nExportMode); + + if( SvXMLExportFlags::META == nExportMode ) + { + // export only meta + eRootService = XML_DOCUMENT_META; + } + else if ( SvXMLExportFlags::SETTINGS == nExportMode ) + { + // export only settings + eRootService = XML_DOCUMENT_SETTINGS; + } + else if( SvXMLExportFlags::STYLES == nExportMode ) + { + // export only styles + eRootService = XML_DOCUMENT_STYLES; + } + else if( SvXMLExportFlags::CONTENT == nExportMode ) + { + // export only content + eRootService = XML_DOCUMENT_CONTENT; + } + else + { + // the god'ol one4all element + eRootService = XML_DOCUMENT; + // office:mimetype = ... (only for stream containing the content) + if( eClass != XML_TOKEN_INVALID ) + { + OUString aTmp = "application/vnd.oasis.opendocument." + GetXMLToken( eClass ); + AddAttribute( XML_NAMESPACE_OFFICE, XML_MIMETYPE, aTmp ); + } + } + + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, eRootService, true, true ); + + // meta information + if( mnExportFlags & SvXMLExportFlags::META ) + ImplExportMeta(); + + // settings + if( mnExportFlags & SvXMLExportFlags::SETTINGS ) + ImplExportSettings(); + + // scripts + if( mnExportFlags & SvXMLExportFlags::SCRIPTS ) + ExportScripts_(); + + // font declarations + if( mnExportFlags & SvXMLExportFlags::FONTDECLS ) + ExportFontDecls_(); + + // styles + if( mnExportFlags & SvXMLExportFlags::STYLES ) + ImplExportStyles(); + + // autostyles + if( mnExportFlags & SvXMLExportFlags::AUTOSTYLES ) + ImplExportAutoStyles(); + + // masterstyles + if( mnExportFlags & SvXMLExportFlags::MASTERSTYLES ) + ImplExportMasterStyles(); + + // content + if( mnExportFlags & SvXMLExportFlags::CONTENT ) + ImplExportContent(); + } + + mxHandler->endDocument(); + + if( bOwnGraphicResolver ) + { + uno::Reference xComp(mxGraphicStorageHandler, UNO_QUERY); + xComp->dispose(); + } + + if( bOwnEmbeddedResolver ) + { + Reference< XComponent > xComp( mxEmbeddedResolver, UNO_QUERY ); + xComp->dispose(); + } + + return ERRCODE_NONE; +} + +void SvXMLExport::ResetNamespaceMap() +{ + mpNamespaceMap->Clear(); +} + +OUString const & SvXMLExport::GetSourceShellID() const +{ + return mpImpl->maSrcShellID; +} + +OUString const & SvXMLExport::GetDestinationShellID() const +{ + return mpImpl->maDestShellID; +} + +void SvXMLExport::ExportMeta_() +{ + OUString generator( ::utl::DocInfoHelper::GetGeneratorString() ); + Reference< XDocumentPropertiesSupplier > xDocPropsSupplier(mxModel, + UNO_QUERY); + if (xDocPropsSupplier.is()) { + Reference xDocProps( + xDocPropsSupplier->getDocumentProperties()); + if (!xDocProps.is()) throw; + // update generator here + xDocProps->setGenerator(generator); + rtl::Reference pMeta = new SvXMLMetaExport(*this, xDocProps); + pMeta->Export(); + } else { + // office:meta + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, XML_META, + true, true ); + { + // BM: #i60323# export generator even if xInfoProp is empty (which is the + // case for charts). The generator does not depend on xInfoProp + SvXMLElementExport anElem( *this, XML_NAMESPACE_META, XML_GENERATOR, + true, true ); + Characters(generator); + } + } +} + +void SvXMLExport::ExportScripts_() +{ + SvXMLElementExport aElement( *this, XML_NAMESPACE_OFFICE, XML_SCRIPTS, true, true ); + + // export Basic macros (only for FlatXML) + if ( mnExportFlags & SvXMLExportFlags::EMBEDDED ) + { + OUString aValue( GetNamespaceMap().GetPrefixByKey( XML_NAMESPACE_OOO ) + ":Basic" ); + AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, aValue ); + + SvXMLElementExport aElem( *this, XML_NAMESPACE_OFFICE, XML_SCRIPT, true, true ); + + // initialize Basic + if ( mxModel.is() ) + { + Reference< beans::XPropertySet > xPSet( mxModel, UNO_QUERY ); + if ( xPSet.is() ) + xPSet->getPropertyValue("BasicLibraries"); + } + + Reference < XDocumentHandler > xHdl( new XMLBasicExportFilter( mxHandler ) ); + Reference< document::XXMLBasicExporter > xExporter = document::XMLOasisBasicExporter::createWithHandler( m_xContext, xHdl ); + + xExporter->setSourceDocument( mxModel ); + Sequence< PropertyValue > aMediaDesc( 0 ); + xExporter->filter( aMediaDesc ); + } + + // export document events + Reference< document::XEventsSupplier > xEvents( GetModel(), UNO_QUERY ); + GetEventExport().Export( xEvents ); +} + +void SvXMLExport::ExportFontDecls_() +{ + if( mxFontAutoStylePool.is() ) + mxFontAutoStylePool->exportXML(); +} + +void SvXMLExport::ExportStyles_( bool ) +{ + uno::Reference< lang::XMultiServiceFactory > xFact( GetModel(), uno::UNO_QUERY ); + if( !xFact.is()) + return; + + // export (fill-)gradient-styles + try + { + uno::Reference< container::XNameAccess > xGradient( xFact->createInstance("com.sun.star.drawing.GradientTable"), uno::UNO_QUERY ); + if( xGradient.is() ) + { + XMLGradientStyleExport aGradientStyle( *this ); + + if( xGradient->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xGradient->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xGradient->getByName( rStrName ); + + aGradientStyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export (fill-)hatch-styles + try + { + uno::Reference< container::XNameAccess > xHatch( xFact->createInstance("com.sun.star.drawing.HatchTable"), uno::UNO_QUERY ); + if( xHatch.is() ) + { + XMLHatchStyleExport aHatchStyle( *this ); + + if( xHatch->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xHatch->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xHatch->getByName( rStrName ); + + aHatchStyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + {} + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export (fill-)bitmap-styles + try + { + uno::Reference< container::XNameAccess > xBitmap( xFact->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY ); + if( xBitmap.is() ) + { + if( xBitmap->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xBitmap->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xBitmap->getByName( rStrName ); + + XMLImageStyle::exportXML( rStrName, aValue, *this ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export transparency-gradient -styles + try + { + uno::Reference< container::XNameAccess > xTransGradient( xFact->createInstance("com.sun.star.drawing.TransparencyGradientTable"), uno::UNO_QUERY ); + if( xTransGradient.is() ) + { + XMLTransGradientStyleExport aTransGradientstyle( *this ); + + if( xTransGradient->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xTransGradient->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xTransGradient->getByName( rStrName ); + + aTransGradientstyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export marker-styles + try + { + uno::Reference< container::XNameAccess > xMarker( xFact->createInstance("com.sun.star.drawing.MarkerTable"), uno::UNO_QUERY ); + if( xMarker.is() ) + { + XMLMarkerStyleExport aMarkerStyle( *this ); + + if( xMarker->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xMarker->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xMarker->getByName( rStrName ); + + aMarkerStyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } + + // export dash-styles + try + { + uno::Reference< container::XNameAccess > xDashes( xFact->createInstance("com.sun.star.drawing.DashTable"), uno::UNO_QUERY ); + if( xDashes.is() ) + { + XMLDashStyleExport aDashStyle( *this ); + + if( xDashes->hasElements() ) + { + const uno::Sequence< OUString > aNamesSeq ( xDashes->getElementNames() ); + for( const OUString& rStrName : aNamesSeq ) + { + try + { + uno::Any aValue = xDashes->getByName( rStrName ); + + aDashStyle.exportXML( rStrName, aValue ); + } + catch(const container::NoSuchElementException&) + { + } + } + } + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } +} + +XMLTextParagraphExport* SvXMLExport::CreateTextParagraphExport() +{ + return new XMLTextParagraphExport( *this, *GetAutoStylePool() ); +} + +XMLShapeExport* SvXMLExport::CreateShapeExport() +{ + return new XMLShapeExport(*this); +} + +SvXMLAutoStylePoolP* SvXMLExport::CreateAutoStylePool() +{ + return new SvXMLAutoStylePoolP(*this); +} + +void SvXMLExport::collectAutoStyles() +{ +} + +XMLPageExport* SvXMLExport::CreatePageExport() +{ + return new XMLPageExport( *this ); +} + +SchXMLExportHelper* SvXMLExport::CreateChartExport() +{ +// WASM_CHART change +// TODO: With Chart extracted this cannot really happen since +// no Chart could've been added at all +#if !ENABLE_WASM_STRIP_CHART + return new SchXMLExportHelper(*this, *GetAutoStylePool()); +#else + return nullptr; +#endif +} + +XMLFontAutoStylePool* SvXMLExport::CreateFontAutoStylePool() +{ + return new XMLFontAutoStylePool( *this ); +} + +xmloff::OFormLayerXMLExport* SvXMLExport::CreateFormExport() +{ + return new xmloff::OFormLayerXMLExport(*this); +} + +void SvXMLExport::GetViewSettingsAndViews(uno::Sequence& rProps) +{ + GetViewSettings(rProps); + uno::Reference xViewDataSupplier(GetModel(), uno::UNO_QUERY); + if(!xViewDataSupplier.is()) + return; + + uno::Reference xIndexAccess; + xViewDataSupplier->setViewData( xIndexAccess ); // make sure we get a newly created sequence + { + // tdf#130559: don't export preview view data if active + static constexpr OUStringLiteral sNoPreviewData = u"NoPreviewData"; + css::uno::ContextLayer layer(comphelper::NewFlagContext(sNoPreviewData)); + xIndexAccess = xViewDataSupplier->getViewData(); + } + bool bAdd = false; + uno::Any aAny; + if(xIndexAccess.is() && xIndexAccess->hasElements() ) + { + sal_Int32 nCount = xIndexAccess->getCount(); + for (sal_Int32 i = 0; i < nCount; i++) + { + aAny = xIndexAccess->getByIndex(i); + uno::Sequence aProps; + if( aAny >>= aProps ) + { + if( aProps.hasElements() ) + { + bAdd = true; + break; + } + } + } + } + + if( bAdd ) + { + sal_Int32 nOldLength(rProps.getLength()); + rProps.realloc(nOldLength + 1); + rProps.getArray()[nOldLength] = comphelper::makePropertyValue("Views", xIndexAccess); + } +} + +void SvXMLExport::GetViewSettings(uno::Sequence&) +{ +} + +void SvXMLExport::GetConfigurationSettings(uno::Sequence&) +{ +} + +sal_Int32 SvXMLExport::GetDocumentSpecificSettings( ::std::vector< SettingsGroup >& ) +{ + return 0; +} + +void SvXMLExport::collectDataStyles(bool bFromUsedStyles) +{ + Reference xStyleFamiliesSupplier(GetModel(), uno::UNO_QUERY); + if (!xStyleFamiliesSupplier.is()) + return; + + Reference xStylesFamilies(xStyleFamiliesSupplier->getStyleFamilies()); + if (!xStylesFamilies.is()) + return; + + Reference xCellStyles(xStylesFamilies->getByName("CellStyles"), uno::UNO_QUERY); + if (!xCellStyles.is()) + return; + + sal_Int32 nCount(xCellStyles->getCount()); + for (sal_Int32 i = 0; i < nCount; ++i) + { + Reference xStyle(xCellStyles->getByIndex(i), uno::UNO_QUERY); + if (bFromUsedStyles && !xStyle->isInUse()) + continue; + + Reference xCellProperties(xStyle, uno::UNO_QUERY); + if (xCellProperties.is()) + { + sal_Int32 nNumberFormat = 0; + if (xCellProperties->getPropertyValue("NumberFormat") >>= nNumberFormat) + addDataStyle(nNumberFormat); + } + } +} + +void SvXMLExport::addDataStyle(const sal_Int32 nNumberFormat, bool /*bTimeFormat*/ ) +{ + if(mpNumExport) + mpNumExport->SetUsed(nNumberFormat); +} + +void SvXMLExport::exportDataStyles() +{ + if(mpNumExport) + mpNumExport->Export(false); +} + +void SvXMLExport::exportAutoDataStyles() +{ + if(mpNumExport) + mpNumExport->Export(true); + + if (mxFormExport.is()) + mxFormExport->exportAutoControlNumberStyles(); +} + +OUString SvXMLExport::getDataStyleName(const sal_Int32 nNumberFormat, bool /*bTimeFormat*/ ) const +{ + OUString sTemp; + if(mpNumExport) + sTemp = mpNumExport->GetStyleName(nNumberFormat); + return sTemp; +} + +void SvXMLExport::exportAnnotationMeta(const uno::Reference&) +{ +} + +sal_Int32 SvXMLExport::dataStyleForceSystemLanguage(sal_Int32 nFormat) const +{ + return ( mpNumExport != nullptr ) + ? mpNumExport->ForceSystemLanguage( nFormat ) : nFormat; +} + +OUString SvXMLExport::AddEmbeddedXGraphic(uno::Reference const & rxGraphic, OUString & rOutMimeType, OUString const & rRequestedName) +{ + OUString sURL; + + Graphic aGraphic(rxGraphic); + OUString aOriginURL = aGraphic.getOriginURL(); + + if (!aOriginURL.isEmpty()) + { + sURL = GetRelativeReference(aOriginURL); + } + else + { + if (mxGraphicStorageHandler.is()) + { + if (!(getExportFlags() & SvXMLExportFlags::EMBEDDED)) + sURL = mxGraphicStorageHandler->saveGraphicByName(rxGraphic, rOutMimeType, rRequestedName); + } + } + return sURL; +} + +bool SvXMLExport::GetGraphicMimeTypeFromStream(uno::Reference const & rxGraphic, OUString & rOutMimeType) +{ + if (mxGraphicStorageHandler.is()) + { + Reference xInputStream(mxGraphicStorageHandler->createInputStream(rxGraphic)); + if (xInputStream.is()) + { + rOutMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForImageStream(xInputStream); + return true; + } + } + + return false; +} + +bool SvXMLExport::AddEmbeddedXGraphicAsBase64(uno::Reference const & rxGraphic) +{ + if ((getExportFlags() & SvXMLExportFlags::EMBEDDED) && + mxGraphicStorageHandler.is()) + { + Reference xInputStream(mxGraphicStorageHandler->createInputStream(rxGraphic)); + if (xInputStream.is()) + { + Graphic aGraphic(rxGraphic); + if (aGraphic.getOriginURL().isEmpty()) // don't add the base64 if the origin URL is set (image is from an external URL) + { + XMLBase64Export aBase64Exp(*this); + return aBase64Exp.exportOfficeBinaryDataElement(xInputStream); + } + } + } + + return false; +} + +OUString SvXMLExport::AddEmbeddedObject( const OUString& rEmbeddedObjectURL ) +{ + OUString sRet; + bool bSupportedURL = rEmbeddedObjectURL.startsWith(XML_EMBEDDEDOBJECT_URL_BASE) || + rEmbeddedObjectURL.startsWith(XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE); + if (bSupportedURL && mxEmbeddedResolver.is()) + { + sRet = mxEmbeddedResolver->resolveEmbeddedObjectURL(rEmbeddedObjectURL); + } + else + sRet = GetRelativeReference( rEmbeddedObjectURL ); + + return sRet; +} + +bool SvXMLExport::AddEmbeddedObjectAsBase64( const OUString& rEmbeddedObjectURL ) +{ + bool bRet = false; + bool bSupportedURL = rEmbeddedObjectURL.startsWith(XML_EMBEDDEDOBJECT_URL_BASE) || + rEmbeddedObjectURL.startsWith(XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE); + if (bSupportedURL && mxEmbeddedResolver.is()) + { + Reference < XNameAccess > xNA( mxEmbeddedResolver, UNO_QUERY ); + if( xNA.is() ) + { + Any aAny = xNA->getByName( rEmbeddedObjectURL ); + Reference < XInputStream > xIn; + aAny >>= xIn; + if( xIn.is() ) + { + XMLBase64Export aBase64Exp( *this ); + bRet = aBase64Exp.exportOfficeBinaryDataElement( xIn ); + } + } + } + + return bRet; +} + +OUString SvXMLExport::EncodeStyleName( + const OUString& rName, + bool *pEncoded ) const +{ + return GetMM100UnitConverter().encodeStyleName( rName, pEncoded ); +} + +ProgressBarHelper* SvXMLExport::GetProgressBarHelper() +{ + if (!mpProgressBarHelper) + { + mpProgressBarHelper.reset( new ProgressBarHelper(mxStatusIndicator, true) ); + + if (mxExportInfo.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxExportInfo->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + OUString sProgressRange(XML_PROGRESSRANGE); + OUString sProgressMax(XML_PROGRESSMAX); + OUString sProgressCurrent(XML_PROGRESSCURRENT); + OUString sRepeat(XML_PROGRESSREPEAT); + if (xPropertySetInfo->hasPropertyByName(sProgressMax) && + xPropertySetInfo->hasPropertyByName(sProgressCurrent) && + xPropertySetInfo->hasPropertyByName(sProgressRange)) + { + uno::Any aAny; + sal_Int32 nProgressMax(0); + sal_Int32 nProgressCurrent(0); + sal_Int32 nProgressRange(0); + aAny = mxExportInfo->getPropertyValue(sProgressRange); + if (aAny >>= nProgressRange) + mpProgressBarHelper->SetRange(nProgressRange); + aAny = mxExportInfo->getPropertyValue(sProgressMax); + if (aAny >>= nProgressMax) + mpProgressBarHelper->SetReference(nProgressMax); + aAny = mxExportInfo->getPropertyValue(sProgressCurrent); + if (aAny >>= nProgressCurrent) + mpProgressBarHelper->SetValue(nProgressCurrent); + } + if (xPropertySetInfo->hasPropertyByName(sRepeat)) + { + uno::Any aAny = mxExportInfo->getPropertyValue(sRepeat); + if (aAny.getValueType() == cppu::UnoType::get()) + mpProgressBarHelper->SetRepeat(::cppu::any2bool(aAny)); + else { + SAL_WARN("xmloff.core", "why is it no boolean?" ); + } + } + } + } + } + return mpProgressBarHelper.get(); +} + +XMLEventExport& SvXMLExport::GetEventExport() +{ + if( nullptr == mpEventExport) + { + // create EventExport on demand + mpEventExport.reset( new XMLEventExport(*this) ); + + // and register standard handlers + names + mpEventExport->AddHandler("StarBasic", std::make_unique()); + mpEventExport->AddHandler("Script", std::make_unique()); + mpEventExport->AddTranslationTable(aStandardEventTable); + } + + return *mpEventExport; +} + +XMLImageMapExport& SvXMLExport::GetImageMapExport() +{ + // image map export, create on-demand + if( nullptr == mpImageMapExport ) + { + mpImageMapExport.reset( new XMLImageMapExport(*this) ); + } + + return *mpImageMapExport; +} + +// XUnoTunnel & co +UNO3_GETIMPLEMENTATION_IMPL(SvXMLExport); + +void SvXMLExport::ExportEmbeddedOwnObject( Reference< XComponent > const & rComp ) +{ + OUString sFilterService; + + Reference < lang::XServiceInfo > xServiceInfo( rComp, UNO_QUERY ); + if( xServiceInfo.is() ) + { + for (const auto& [sModelService, sMatchingFilterService] : aServiceMap) + { + if( xServiceInfo->supportsService( sModelService ) ) + { + sFilterService = sMatchingFilterService; + break; + } + } + } + + SAL_WARN_IF( !sFilterService.getLength(), "xmloff.core", "no export filter for own object" ); + + if( sFilterService.isEmpty() ) + return; + + Reference < XDocumentHandler > xHdl = + new XMLEmbeddedObjectExportFilter( mxHandler ); + + Sequence < Any > aArgs{ Any(xHdl) }; + Reference< document::XExporter > xExporter( + m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(sFilterService, aArgs, m_xContext), + UNO_QUERY); + SAL_WARN_IF( !xExporter.is(), "xmloff.core", "can't instantiate export filter component for own object" ); + if( !xExporter.is() ) + return; + + xExporter->setSourceDocument( rComp ); + + Reference xFilter( xExporter, UNO_QUERY ); + + Sequence < PropertyValue > aMediaDesc( 0 ); + xFilter->filter( aMediaDesc ); +} + +OUString SvXMLExport::GetRelativeReference(const OUString& rValue) +{ + OUString sValue( rValue ); + // #i65474# handling of fragment URLs ("#...") is undefined + // they are stored 'as is' + uno::Reference< uri::XUriReference > xUriRef; + if(!sValue.isEmpty() && sValue[0] != '#') + { + try + { + xUriRef = mpImpl->mxUriReferenceFactory->parse( rValue ); + if( xUriRef.is() && !xUriRef->isAbsolute() ) + { + //#i61943# relative URLs need special handling + INetURLObject aTemp( mpImpl->msPackageURI ); + bool bWasAbsolute = false; + sValue = aTemp.smartRel2Abs(sValue, bWasAbsolute ).GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + } + } + catch(const uno::Exception&) + { + } + } + if( xUriRef.is() )//no conversion for empty values or for fragments + { + //conversion for matching schemes only + if( xUriRef->getScheme() == mpImpl->msPackageURIScheme ) + { + sValue = INetURLObject::GetRelURL( msOrigFileName, sValue ); + } + } + return sValue; +} + +void SvXMLExport::StartElement(sal_uInt16 nPrefix, + enum ::xmloff::token::XMLTokenEnum eName, + bool bIgnWSOutside ) +{ + StartElement(GetNamespaceMap_().GetQNameByKey( nPrefix, + GetXMLToken(eName) ), bIgnWSOutside); +} + +void SvXMLExport::StartElement(const OUString& rName, + bool bIgnWSOutside ) +{ + if ((mnErrorFlags & SvXMLErrorFlags::DO_NOTHING) != SvXMLErrorFlags::DO_NOTHING) + { + try + { + if( bIgnWSOutside && ((mnExportFlags & SvXMLExportFlags::PRETTY) == SvXMLExportFlags::PRETTY)) + mxHandler->ignorableWhitespace( msWS ); + mxHandler->startElement( rName, GetXAttrList() ); + } + catch (const SAXInvalidCharacterException& e) + { + Sequence aPars { rName }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_WARNING, aPars, e.Message, nullptr ); + } + catch (const SAXException& e) + { + Sequence aPars { rName }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_ERROR|XMLERROR_FLAG_SEVERE, + aPars, e.Message, nullptr ); + } + } + ClearAttrList(); + ++mpImpl->mDepth; // increment nesting depth counter +} + +void SvXMLExport::Characters(const OUString& rChars) +{ + if ((mnErrorFlags & SvXMLErrorFlags::DO_NOTHING) == SvXMLErrorFlags::DO_NOTHING) + return; + + try + { + mxHandler->characters(rChars); + } + catch (const SAXInvalidCharacterException& e) + { + Sequence aPars { rChars }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_WARNING, aPars, e.Message, nullptr ); + } + catch (const SAXException& e) + { + Sequence aPars { rChars }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_ERROR|XMLERROR_FLAG_SEVERE, + aPars, e.Message, nullptr ); + } +} + +void SvXMLExport::EndElement(sal_uInt16 nPrefix, + enum ::xmloff::token::XMLTokenEnum eName, + bool bIgnWSInside ) +{ + EndElement(GetNamespaceMap_().GetQNameByKey( nPrefix, GetXMLToken(eName) ), + bIgnWSInside); +} + +void SvXMLExport::EndElement(const OUString& rName, + bool bIgnWSInside ) +{ + // decrement nesting depth counter & (maybe) restore namespace map + --mpImpl->mDepth; + if (!mpImpl->mNamespaceMaps.empty() && + (mpImpl->mNamespaceMaps.top().second == mpImpl->mDepth)) + { + mpNamespaceMap = std::move(mpImpl->mNamespaceMaps.top().first); + mpImpl->mNamespaceMaps.pop(); + } + SAL_WARN_IF(!mpImpl->mNamespaceMaps.empty() && + (mpImpl->mNamespaceMaps.top().second >= mpImpl->mDepth), "xmloff.core", "SvXMLExport: NamespaceMaps corrupted"); + + if ((mnErrorFlags & SvXMLErrorFlags::DO_NOTHING) == SvXMLErrorFlags::DO_NOTHING) + return; + + try + { + if( bIgnWSInside && ((mnExportFlags & SvXMLExportFlags::PRETTY) == SvXMLExportFlags::PRETTY)) + mxHandler->ignorableWhitespace( msWS ); + mxHandler->endElement( rName ); + } + catch (const SAXException& e) + { + Sequence aPars { rName }; + SetError( XMLERROR_SAX|XMLERROR_FLAG_ERROR|XMLERROR_FLAG_SEVERE, + aPars, e.Message, nullptr ); + } +} + +void SvXMLExport::IgnorableWhitespace() +{ + if ((mnExportFlags & SvXMLExportFlags::PRETTY) != SvXMLExportFlags::PRETTY) + return; + + if ((mnErrorFlags & SvXMLErrorFlags::DO_NOTHING) == SvXMLErrorFlags::DO_NOTHING) + return; + + try + { + mxHandler->ignorableWhitespace( msWS ); + } + catch (const SAXException& e) + { + SetError( XMLERROR_SAX|XMLERROR_FLAG_ERROR|XMLERROR_FLAG_SEVERE, + {}, e.Message, nullptr ); + } +} + +void SvXMLExport::SetError( + sal_Int32 nId, + const Sequence& rMsgParams, + const OUString& rExceptionMessage, + const Reference& rLocator ) +{ + // allow multi-threaded access to the cancel() method + static std::mutex aMutex; + std::scoped_lock aGuard(aMutex); + + // maintain error flags + if ( ( nId & XMLERROR_FLAG_ERROR ) != 0 ) + mnErrorFlags |= SvXMLErrorFlags::ERROR_OCCURRED; + if ( ( nId & XMLERROR_FLAG_WARNING ) != 0 ) + mnErrorFlags |= SvXMLErrorFlags::WARNING_OCCURRED; + if ( ( nId & XMLERROR_FLAG_SEVERE ) != 0 ) + mnErrorFlags |= SvXMLErrorFlags::DO_NOTHING; + + // create error list on demand + if ( mpXMLErrors == nullptr ) + mpXMLErrors.reset( new XMLErrors() ); + + // save error information + mpXMLErrors->AddRecord( nId, rMsgParams, rExceptionMessage, rLocator ); +} + +void SvXMLExport::SetError( + sal_Int32 nId, + const Sequence& rMsgParams) +{ + SetError( nId, rMsgParams, "", nullptr ); +} + +void SvXMLExport::DisposingModel() +{ + mxModel.clear(); + // Shapes in Writer cannot be named via context menu (#i51726#) + meModelType = SvtModuleOptions::EFactory::UNKNOWN_FACTORY; + mxEventListener.clear(); +} + + +::comphelper::UnoInterfaceToUniqueIdentifierMapper& SvXMLExport::getInterfaceToIdentifierMapper() +{ + return mpImpl->maInterfaceToIdentifierMapper; +} + +// Written OpenDocument file format doesn't fit to the created text document (#i69627#) +bool SvXMLExport::writeOutlineStyleAsNormalListStyle() const +{ + return mpImpl->mbOutlineStyleAsNormalListStyle; +} + +uno::Reference< embed::XStorage > const & SvXMLExport::GetTargetStorage() const +{ + return mpImpl->mxTargetStorage; +} + +SvtSaveOptions::ODFSaneDefaultVersion SvXMLExport::getSaneDefaultVersion() const +{ + if (mpImpl->m_oOverrideODFVersion) + { + return *mpImpl->m_oOverrideODFVersion; + } + return GetODFSaneDefaultVersion(); +} + +void +SvXMLExport::AddAttributeIdLegacy( + sal_uInt16 const nLegacyPrefix, OUString const& rValue) +{ + switch (getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: break; + default: // ODF 1.2: xml:id + AddAttribute(XML_NAMESPACE_XML, XML_ID, rValue); + } + // in ODF 1.1 this was form:id, anim:id, draw:id, or text:id + // backward compatibility: in ODF 1.2 write _both_ id attrs + AddAttribute(nLegacyPrefix, XML_ID, rValue); + // FIXME: this function simply assumes that rValue is unique +} + +void +SvXMLExport::AddAttributeXmlId(uno::Reference const & i_xIfc) +{ + // check version >= 1.2 + switch (getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: return; + default: break; + } + const uno::Reference xMeta(i_xIfc, + uno::UNO_QUERY); +//FIXME not yet... + if ( !xMeta.is() ) + return; + + const beans::StringPair mdref( xMeta->getMetadataReference() ); + if ( mdref.Second.isEmpty() ) + return; + + const OUString streamName = mpImpl->mStreamName; + if ( !streamName.isEmpty() ) + { + if ( streamName == mdref.First ) + { + AddAttribute( XML_NAMESPACE_XML, XML_ID, mdref.Second ); + } + else + { + SAL_WARN("xmloff.core","SvXMLExport::AddAttributeXmlId: invalid stream name"); + } + } + else + { + // FIXME: this is ugly + // there is no stream name (e.g. XSLT, flat-xml format)! + // but how do we ensure uniqueness in this case? + // a) just omit styles.xml ids -- they are unlikely anyway... + // b) somehow find out whether we are currently exporting styles + // or content, and prefix "s" or "c" => unique + if ( mdref.First == "content.xml" ) + { + AddAttribute( XML_NAMESPACE_XML, XML_ID, mdref.Second ); + } + else + { + SAL_INFO("xmloff.core", "SvXMLExport::AddAttributeXmlId: no stream name given: dropping styles.xml xml:id"); + } + } +} + +void +SvXMLExport::AddAttributesRDFa( + uno::Reference const & i_xTextContent) +{ + // check version >= 1.2 + switch (getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: return; + default: break; + } + + const uno::Reference xMeta( + i_xTextContent, uno::UNO_QUERY); + if (!xMeta.is() || xMeta->getMetadataReference().Second.isEmpty()) + { + return; // no xml:id => no RDFa + } + + if (!mpImpl->mpRDFaHelper) + { + mpImpl->mpRDFaHelper.reset( new ::xmloff::RDFaExportHelper(*this) ); + } + mpImpl->mpRDFaHelper->AddRDFa(xMeta); +} + +bool SvXMLExport::exportTextNumberElement() const +{ + return mpImpl->mbExportTextNumberElement; +} + +bool SvXMLExport::SetNullDateOnUnitConverter() +{ + // if the null date has already been set, don't set it again (performance) + if (!mpImpl->mbNullDateInitialized) + mpImpl->mbNullDateInitialized = GetMM100UnitConverter().setNullDate(GetModel()); + + return mpImpl->mbNullDateInitialized; +} + +OUString const & SvXMLExport::GetImageFilterName() const +{ + return msImgFilterName; +} + +void SvXMLElementExport::StartElement( + const sal_uInt16 nPrefixKey, + const OUString& rLName, + const bool bIgnoreWhitespaceOutside ) +{ + maElementName = mrExport.GetNamespaceMap().GetQNameByKey(nPrefixKey, rLName); + mrExport.StartElement(maElementName, bIgnoreWhitespaceOutside); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + sal_uInt16 nPrefixKey, + const char *pLName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( true ) +{ + const OUString sLName( OUString::createFromAscii( pLName ) ); + StartElement( nPrefixKey, sLName, bIWSOutside ); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + sal_uInt16 nPrefixKey, + const OUString& rLName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( true ) +{ + StartElement( nPrefixKey, rLName, bIWSOutside ); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + sal_uInt16 nPrefixKey, + enum XMLTokenEnum eLName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( true ) +{ + StartElement( nPrefixKey, GetXMLToken(eLName), bIWSOutside ); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + bool bDoSth, + sal_uInt16 nPrefixKey, + enum XMLTokenEnum eLName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( bDoSth ) +{ + if ( mbDoSomething ) + StartElement( nPrefixKey, GetXMLToken( eLName ), bIWSOutside ); +} + +SvXMLElementExport::SvXMLElementExport( + SvXMLExport& rExp, + const OUString& rQName, + bool bIWSOutside, + bool bIWSInside ) + : mrExport( rExp ) + , mbIgnoreWhitespaceInside( bIWSInside ) + , mbDoSomething( true ) +{ + maElementName = rQName; + rExp.StartElement( rQName, bIWSOutside ); +} + +SvXMLElementExport::~SvXMLElementExport() +{ + if ( mbDoSomething ) + { + mrExport.EndElement( maElementName, mbIgnoreWhitespaceInside ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmlictxt.cxx b/xmloff/source/core/xmlictxt.cxx new file mode 100644 index 000000000..360763349 --- /dev/null +++ b/xmloff/source/core/xmlictxt.cxx @@ -0,0 +1,98 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +SvXMLImportContext::SvXMLImportContext( SvXMLImport& rImp ) + : mrImport(rImp) + , m_nRefCount(0) +{ +} + +SvXMLImportContext::~SvXMLImportContext() +{ +} + +void SvXMLImportContext::endFastElement(sal_Int32 ) +{ +} + +// css::xml::sax::XFastContextHandler: +void SAL_CALL SvXMLImportContext::startFastElement(sal_Int32 /*nElement*/, const uno::Reference< xml::sax::XFastAttributeList > & ) +{ +} + +void SAL_CALL SvXMLImportContext::startUnknownElement(const OUString & /*rNamespace*/, const OUString & /*rElementName*/, + const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/) +{ +} + +void SAL_CALL SvXMLImportContext::endUnknownElement (const OUString & /*rNamespace*/, const OUString & /*rElementName*/) +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SvXMLImportContext::createFastChildContext + (sal_Int32 /*Element*/, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/) +{ + return nullptr; +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SvXMLImportContext::createUnknownChildContext + (const OUString & /*rNamespace*/, const OUString & /*rName*/, const uno::Reference< xml::sax::XFastAttributeList > & /*Attribs*/) +{ + return nullptr; +} + +void SAL_CALL SvXMLImportContext::characters(const OUString &/*rChars*/) +{ +} + +// XInterface +css::uno::Any SAL_CALL SvXMLImportContext::queryInterface( const css::uno::Type& aType ) +{ + css::uno::Any a = ::cppu::queryInterface( + aType, + static_cast< XFastContextHandler* >(this), + static_cast< XTypeProvider* >(this), + static_cast< css::uno::XInterface* >(static_cast< XFastContextHandler* >(this))); + + return a; +} + +// XTypeProvider +css::uno::Sequence< css::uno::Type > SAL_CALL SvXMLImportContext::getTypes() +{ + return { cppu::UnoType::get(), + cppu::UnoType::get() }; +} + +css::uno::Sequence< sal_Int8 > SAL_CALL SvXMLImportContext::getImplementationId() +{ + return css::uno::Sequence(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx new file mode 100644 index 000000000..3d9cb9f1e --- /dev/null +++ b/xmloff/source/core/xmlimp.cxx @@ -0,0 +1,2278 @@ +/* -*- 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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using ::com::sun::star::beans::XPropertySetInfo; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::document; +using namespace ::xmloff::token; + +rtl::Reference< FastTokenHandler > SvXMLImport::xTokenHandler( new FastTokenHandler() ); +std::unordered_map< sal_Int32, std::pair< OUString, OUString > > SvXMLImport::aNamespaceMap; +std::unordered_map< OUString, OUString > SvXMLImport::aNamespaceURIPrefixMap; +bool SvXMLImport::bIsNSMapsInitialized = false; + +namespace { + +class SvXMLImportEventListener : public cppu::WeakImplHelper< css::lang::XEventListener > +{ +private: + SvXMLImport* pImport; + +public: + explicit SvXMLImportEventListener(SvXMLImport* pImport); + + // XEventListener + virtual void SAL_CALL disposing(const lang::EventObject& rEventObject) override; +}; + +} + +SvXMLImportEventListener::SvXMLImportEventListener(SvXMLImport* pTempImport) + : pImport(pTempImport) +{ +} + +// XEventListener +void SAL_CALL SvXMLImportEventListener::disposing( const lang::EventObject& ) +{ + if (pImport) + { + pImport->DisposingModel(); + pImport = nullptr; + } +} + +namespace +{ + +OUString +getBuildIdsProperty(uno::Reference const& xImportInfo) +{ + if (xImportInfo.is()) + { + try + { + Reference< XPropertySetInfo > const xSetInfo( + xImportInfo->getPropertySetInfo()); + if (xSetInfo.is() && xSetInfo->hasPropertyByName("BuildId")) + { + OUString aBuildId; + xImportInfo->getPropertyValue("BuildId") >>= aBuildId; + return aBuildId; + } + } + catch (Exception const&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.core", "exception getting BuildId"); + } + } + return OUString(); +} + +class DocumentInfo +{ +private: + sal_uInt16 mnGeneratorVersion; + +public: + explicit DocumentInfo( const SvXMLImport& rImport ) + : mnGeneratorVersion( SvXMLImport::ProductVersionUnknown ) + { + OUString const buildIds( + getBuildIdsProperty(rImport.getImportInfo())); + if (!buildIds.isEmpty()) + { + sal_Int32 const ix = buildIds.indexOf(';'); + if (-1 != ix) + { + OUString const loVersion(buildIds.copy(ix + 1)); + if (!loVersion.isEmpty()) + { + if ('3' == loVersion[0]) + { + mnGeneratorVersion = SvXMLImport::LO_3x; + } + else if ('4' == loVersion[0]) + { + if (loVersion.getLength() > 1 + && (loVersion[1] == '0' || loVersion[1] == '1')) + { + mnGeneratorVersion = SvXMLImport::LO_41x; // 4.0/4.1 + } + else if (loVersion.getLength() > 1 && '2' == loVersion[1]) + { + mnGeneratorVersion = SvXMLImport::LO_42x; // 4.2 + } + else if (loVersion.getLength() > 1 && '3' == loVersion[1]) + { + mnGeneratorVersion = SvXMLImport::LO_43x; // 4.3 + } + else if (loVersion.getLength() > 1 && '4' == loVersion[1]) + { + mnGeneratorVersion = SvXMLImport::LO_44x; // 4.4 + } + } + else if ('5' == loVersion[0]) + { + mnGeneratorVersion = SvXMLImport::LO_5x; + } + else if ('6' == loVersion[0]) + { + if (loVersion.getLength() > 1 + && (loVersion[1] == '0' || loVersion[1] == '1' + || loVersion[1] == '2')) + { + mnGeneratorVersion = SvXMLImport::LO_6x; // 6.0/6.1/6.2 + } + else + { + mnGeneratorVersion = SvXMLImport::LO_63x; // 6.3/6.4 + } + } + else if ('7' == loVersion[0]) + { + mnGeneratorVersion = SvXMLImport::LO_7x; + } + else + { + SAL_INFO("xmloff.core", "unknown LO version: " << loVersion); + } + return; // ignore buildIds + } + } + } + sal_Int32 nUPD, nBuild; + if ( !rImport.getBuildIds( nUPD, nBuild ) ) + return; + + if ( nUPD >= 640 && nUPD <= 645 ) + { + mnGeneratorVersion = SvXMLImport::OOo_1x; + } + else if ( nUPD == 680 ) + { + mnGeneratorVersion = SvXMLImport::OOo_2x; + } + else if ( nUPD == 300 && nBuild <= 9379 ) + { + mnGeneratorVersion = SvXMLImport::OOo_30x; + } + else if ( nUPD == 310 ) + { + mnGeneratorVersion = SvXMLImport::OOo_31x; + } + else if ( nUPD == 320 ) + { + mnGeneratorVersion = SvXMLImport::OOo_32x; + } + else if ( nUPD == 330 ) + { + mnGeneratorVersion = SvXMLImport::OOo_33x; + } + else if ( nUPD == 340 ) + { + mnGeneratorVersion = SvXMLImport::OOo_34x; + } + else if (nUPD == 400 || nUPD == 401) + { + mnGeneratorVersion = SvXMLImport::AOO_40x; + } + else if (nUPD >= 410) + { + // effectively this means "latest", see use + // in XMLGraphicsDefaultStyle::SetDefaults()! + mnGeneratorVersion = SvXMLImport::AOO_4x; + } + } + + sal_uInt16 getGeneratorVersion() const + { + return mnGeneratorVersion; + } +}; + +} + +class SvXMLImport_Impl +{ +public: + FontToSubsFontConverter hBatsFontConv; + FontToSubsFontConverter hMathFontConv; + + bool mbOwnGraphicResolver; + bool mbOwnEmbeddedResolver; + INetURLObject aBaseURL; + INetURLObject aDocBase; + + /// name of stream in package, e.g., "content.xml" + OUString mStreamName; + + std::optional mxODFVersion; + + bool mbIsOOoXML; + + std::optional mbIsMSO; + + // Boolean, indicating that position attributes + // of shapes are given in horizontal left-to-right layout. This is the case + // for the OpenOffice.org file format. (#i28749#) + bool mbShapePositionInHoriL2R; + bool mbTextDocInOOoFileFormat; + + const uno::Reference< uno::XComponentContext > mxComponentContext; + OUString implementationName; + css::uno::Sequence< OUString > maSupportedServiceNames; + + uno::Reference< embed::XStorage > mxSourceStorage; + + std::unique_ptr< xmloff::RDFaImportHelper > mpRDFaHelper; + + std::unique_ptr< DocumentInfo > mpDocumentInfo; + + SvXMLImport_Impl( const uno::Reference< uno::XComponentContext >& rxContext, + OUString const & theImplementationName, + const css::uno::Sequence< OUString > & sSupportedServiceNames = {}) + : hBatsFontConv( nullptr ) + , hMathFontConv( nullptr ) + , mbOwnGraphicResolver( false ) + , mbOwnEmbeddedResolver( false ) + , mbIsOOoXML(false) + // Convert drawing object positions from OOo file format to OASIS (#i28749#) + , mbShapePositionInHoriL2R( false ) + , mbTextDocInOOoFileFormat( false ) + , mxComponentContext( rxContext ) + , implementationName(theImplementationName) + , maSupportedServiceNames(sSupportedServiceNames) + { + SAL_WARN_IF(!mxComponentContext.is(), "xmloff.core", "SvXMLImport: no ComponentContext"); + if (!mxComponentContext.is()) throw uno::RuntimeException(); + if (!maSupportedServiceNames.hasElements()) + maSupportedServiceNames = { "com.sun.star.document.ImportFilter", "com.sun.star.xml.XMLImportFilter" }; + } + + sal_uInt16 getGeneratorVersion( const SvXMLImport& rImport ) + { + if (!mpDocumentInfo) + { + mpDocumentInfo.reset( new DocumentInfo( rImport ) ); + } + + return mpDocumentInfo->getGeneratorVersion(); + } + + ::comphelper::UnoInterfaceToUniqueIdentifierMapper maInterfaceToIdentifierMapper; +}; + +SvXMLImportContext *SvXMLImport::CreateFastContext( sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + assert(false); + SAL_WARN( "xmloff.core", "CreateFastContext should be overridden, for element " << nElement); + return new SvXMLImportContext( *this ); +} + +void SvXMLImport::InitCtor_() +{ + if( mnImportFlags != SvXMLImportFlags::NONE ) + { + // implicit "xml" namespace prefix + mxNamespaceMap->Add( GetXMLToken(XML_XML), GetXMLToken(XML_N_XML), XML_NAMESPACE_XML ); + mxNamespaceMap->Add( "_office", GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE ); + mxNamespaceMap->Add( "_office_ooo", GetXMLToken(XML_N_OFFICE_EXT), XML_NAMESPACE_OFFICE_EXT ); + mxNamespaceMap->Add( "_ooo", GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO ); + mxNamespaceMap->Add( "_style", GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE ); + mxNamespaceMap->Add( "_text", GetXMLToken(XML_N_TEXT), XML_NAMESPACE_TEXT ); + mxNamespaceMap->Add( "_table", GetXMLToken(XML_N_TABLE), XML_NAMESPACE_TABLE ); + mxNamespaceMap->Add( "_table_ooo", GetXMLToken(XML_N_TABLE_EXT), XML_NAMESPACE_TABLE_EXT ); + mxNamespaceMap->Add( "_draw", GetXMLToken(XML_N_DRAW), XML_NAMESPACE_DRAW ); + mxNamespaceMap->Add( "_draw_ooo", GetXMLToken(XML_N_DRAW_EXT), XML_NAMESPACE_DRAW_EXT ); + mxNamespaceMap->Add( "_dr3d", GetXMLToken(XML_N_DR3D), XML_NAMESPACE_DR3D ); + mxNamespaceMap->Add( "_fo", GetXMLToken(XML_N_FO_COMPAT), XML_NAMESPACE_FO ); + mxNamespaceMap->Add( "_xlink", GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK ); + mxNamespaceMap->Add( "_dc", GetXMLToken(XML_N_DC), XML_NAMESPACE_DC ); + mxNamespaceMap->Add( "_dom", GetXMLToken(XML_N_DOM), XML_NAMESPACE_DOM ); + mxNamespaceMap->Add( "_meta", GetXMLToken(XML_N_META), XML_NAMESPACE_META ); + mxNamespaceMap->Add( "_number", GetXMLToken(XML_N_NUMBER), XML_NAMESPACE_NUMBER ); + mxNamespaceMap->Add( "_svg", GetXMLToken(XML_N_SVG_COMPAT), XML_NAMESPACE_SVG ); + mxNamespaceMap->Add( "_chart", GetXMLToken(XML_N_CHART), XML_NAMESPACE_CHART ); + mxNamespaceMap->Add( "_math", GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH ); + mxNamespaceMap->Add( "_form", GetXMLToken(XML_N_FORM), XML_NAMESPACE_FORM ); + mxNamespaceMap->Add( "_script", GetXMLToken(XML_N_SCRIPT), XML_NAMESPACE_SCRIPT ); + mxNamespaceMap->Add( "_config", GetXMLToken(XML_N_CONFIG), XML_NAMESPACE_CONFIG ); + mxNamespaceMap->Add( "_xforms", GetXMLToken(XML_N_XFORMS_1_0), XML_NAMESPACE_XFORMS ); + mxNamespaceMap->Add( "_formx", GetXMLToken( XML_N_FORMX ), XML_NAMESPACE_FORMX ); + mxNamespaceMap->Add( "_xsd", GetXMLToken(XML_N_XSD), XML_NAMESPACE_XSD ); + mxNamespaceMap->Add( "_xsi", GetXMLToken(XML_N_XSI), XML_NAMESPACE_XFORMS ); + mxNamespaceMap->Add( "_ooow", GetXMLToken(XML_N_OOOW), XML_NAMESPACE_OOOW ); + mxNamespaceMap->Add( "_oooc", GetXMLToken(XML_N_OOOC), XML_NAMESPACE_OOOC ); + mxNamespaceMap->Add( "_field", GetXMLToken(XML_N_FIELD), XML_NAMESPACE_FIELD ); + mxNamespaceMap->Add( "_of", GetXMLToken(XML_N_OF), XML_NAMESPACE_OF ); + mxNamespaceMap->Add( "_xhtml", GetXMLToken(XML_N_XHTML), XML_NAMESPACE_XHTML ); + mxNamespaceMap->Add( "_css3text", GetXMLToken(XML_N_CSS3TEXT), XML_NAMESPACE_CSS3TEXT ); + + mxNamespaceMap->Add( "_calc_libo", GetXMLToken(XML_N_CALC_EXT), XML_NAMESPACE_CALC_EXT); + mxNamespaceMap->Add( "_office_libo", + GetXMLToken(XML_N_LO_EXT), XML_NAMESPACE_LO_EXT); + } + + if (mxNumberFormatsSupplier.is()) + mpNumImport = std::make_unique(mxNumberFormatsSupplier, GetComponentContext()); + + if (mxModel.is() && !mxEventListener.is()) + { + mxEventListener.set(new SvXMLImportEventListener(this)); + mxModel->addEventListener(mxEventListener); + } +} + +SvXMLImport::SvXMLImport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + SvXMLImportFlags nImportFlags, + const css::uno::Sequence< OUString > & sSupportedServiceNames ) +: mpImpl( new SvXMLImport_Impl(xContext, implementationName, sSupportedServiceNames) ), + mxNamespaceMap( SvXMLNamespaceMap() ), + + mpUnitConv( new SvXMLUnitConverter( xContext, + util::MeasureUnit::MM_100TH, util::MeasureUnit::MM_100TH, + SvtSaveOptions::ODFSVER_LATEST_EXTENDED) ), + + mnImportFlags( nImportFlags ), + maNamespaceHandler( new SvXMLImportFastNamespaceHandler() ), + mbIsFormsSupported( true ), + mbIsTableShapeSupported( false ), + mbNotifyMacroEventRead( false ) +{ + SAL_WARN_IF( !xContext.is(), "xmloff.core", "got no service manager" ); + InitCtor_(); + mxParser = xml::sax::FastParser::create( xContext ); + setNamespaceHandler( maNamespaceHandler ); + setTokenHandler( xTokenHandler ); + if ( !bIsNSMapsInitialized ) + { + initializeNamespaceMaps(); + bIsNSMapsInitialized = true; + } + registerNamespaces(); + maNamespaceAttrList = new comphelper::AttributeList; +} + +void SvXMLImport::cleanup() noexcept +{ + if (mxEventListener.is() && mxModel.is()) + mxModel->removeEventListener(mxEventListener); + // clear context stacks first in case of parse error because the context + // class dtors are full of application logic + while (!maContexts.empty()) + { + if (SvXMLStylesContext* pStylesContext = dynamic_cast(maContexts.top().get())) + pStylesContext->dispose(); + maContexts.pop(); + } + if( mxTextImport ) + mxTextImport->dispose(); + mxTextImport.clear(); // XMLRedlineImportHelper needs model + DisposingModel(); +} + +SvXMLImport::~SvXMLImport() noexcept +{ + cleanup(); +} + +bool SvXMLImport::addEmbeddedFont(const css::uno::Reference< css::io::XInputStream >& stream, + const OUString& fontName, const char* extra, + std::vector const & key, bool eot) +{ + if (!mxEmbeddedFontHelper) + mxEmbeddedFontHelper.reset(new EmbeddedFontsHelper); + return mxEmbeddedFontHelper->addEmbeddedFont(stream, fontName, extra, key, eot); +} + +const css::uno::Sequence& SvXMLImport::getUnoTunnelId() noexcept +{ + static const comphelper::UnoIdInit theSvXMLImportUnoTunnelId; + return theSvXMLImportUnoTunnelId.getSeq(); +} + +// XUnoTunnel +sal_Int64 SAL_CALL SvXMLImport::getSomething( const uno::Sequence< sal_Int8 >& rId ) +{ + return comphelper::getSomethingImpl(rId, this); +} + +namespace +{ + class setFastDocumentHandlerGuard + { + private: + css::uno::Reference mxParser; + public: + setFastDocumentHandlerGuard(const css::uno::Reference& Parser, + const css::uno::Reference& Handler) + : mxParser(Parser) + { + mxParser->setFastDocumentHandler(Handler); + } + //guarantee restoration of null document handler + ~setFastDocumentHandlerGuard() + { + mxParser->setFastDocumentHandler(nullptr); + } + }; +} + +// XFastParser +void SAL_CALL SvXMLImport::parseStream( const xml::sax::InputSource& aInputSource ) +{ + setFastDocumentHandlerGuard aDocumentHandlerGuard(mxParser, mxFastDocumentHandler.is() ? mxFastDocumentHandler : this); + mxParser->parseStream(aInputSource); +} + +void SAL_CALL SvXMLImport::setFastDocumentHandler( const uno::Reference< xml::sax::XFastDocumentHandler >& Handler ) +{ + mxFastDocumentHandler = Handler; +} + +void SAL_CALL SvXMLImport::setTokenHandler( const uno::Reference< xml::sax::XFastTokenHandler >& Handler ) +{ + mxParser->setTokenHandler( Handler ); +} + +void SAL_CALL SvXMLImport::registerNamespace( const OUString& NamespaceURL, sal_Int32 NamespaceToken ) +{ + mxParser->registerNamespace( NamespaceURL, NamespaceToken ); +} + +OUString SAL_CALL SvXMLImport::getNamespaceURL( const OUString& rPrefix ) +{ + return mxParser->getNamespaceURL( rPrefix ); +} + +void SAL_CALL SvXMLImport::setErrorHandler( const uno::Reference< xml::sax::XErrorHandler >& Handler ) +{ + mxParser->setErrorHandler( Handler ); +} + +void SAL_CALL SvXMLImport::setEntityResolver( const uno::Reference< xml::sax::XEntityResolver >& Resolver ) +{ + mxParser->setEntityResolver( Resolver ); +} + +void SAL_CALL SvXMLImport::setLocale( const lang::Locale& rLocale ) +{ + mxParser->setLocale( rLocale ); +} + +void SAL_CALL SvXMLImport::setNamespaceHandler( const uno::Reference< xml::sax::XFastNamespaceHandler >& Handler) +{ + mxParser->setNamespaceHandler( Handler ); +} + +void SAL_CALL SvXMLImport::setCustomEntityNames( const ::css::uno::Sequence< ::css::beans::Pair<::rtl::OUString, ::rtl::OUString> >& replacements ) +{ + mxParser->setCustomEntityNames( replacements ); +} + +void SAL_CALL SvXMLImport::startDocument() +{ + SAL_INFO( "xmloff.core", "{ SvXMLImport::startDocument" ); + if (mxGraphicStorageHandler.is() && mxEmbeddedResolver.is()) + return; + + Reference< lang::XMultiServiceFactory > xFactory( mxModel, UNO_QUERY ); + if( !xFactory.is() ) + return; + + try + { + if (!mxGraphicStorageHandler.is()) + { + // #99870# Import... instead of Export... + mxGraphicStorageHandler.set( + xFactory->createInstance("com.sun.star.document.ImportGraphicStorageHandler"), + UNO_QUERY); + mpImpl->mbOwnGraphicResolver = mxGraphicStorageHandler.is(); + } + + if( !mxEmbeddedResolver.is() ) + { + // #99870# Import... instead of Export... + mxEmbeddedResolver.set( + xFactory->createInstance("com.sun.star.document.ImportEmbeddedObjectResolver"), + UNO_QUERY); + mpImpl->mbOwnEmbeddedResolver = mxEmbeddedResolver.is(); + } + } + catch( css::uno::Exception& ) + { + } +} + +void SAL_CALL SvXMLImport::endDocument() +{ + SAL_INFO( "xmloff.core", "} SvXMLImport::endDocument" ); + // #i9518# All the stuff that accesses the document has to be done here, not in the dtor, + // because the SvXMLImport dtor might not be called until after the document has been closed. + + GetTextImport()->MapCrossRefHeadingFieldsHorribly(); + + if (mpImpl->mpRDFaHelper) + { + const uno::Reference xRS(mxModel, + uno::UNO_QUERY); + if (xRS.is()) + { + mpImpl->mpRDFaHelper->InsertRDFa( xRS ); + } + } + + mpNumImport.reset(); + if (mxImportInfo.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxImportInfo->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + if (bool(mpProgressBarHelper)) + { + OUString sProgressMax(XML_PROGRESSMAX); + OUString sProgressCurrent(XML_PROGRESSCURRENT); + OUString sRepeat(XML_PROGRESSREPEAT); + if (xPropertySetInfo->hasPropertyByName(sProgressMax) && + xPropertySetInfo->hasPropertyByName(sProgressCurrent)) + { + sal_Int32 nProgressMax(mpProgressBarHelper->GetReference()); + sal_Int32 nProgressCurrent(mpProgressBarHelper->GetValue()); + mxImportInfo->setPropertyValue(sProgressMax, uno::Any(nProgressMax)); + mxImportInfo->setPropertyValue(sProgressCurrent, uno::Any(nProgressCurrent)); + } + if (xPropertySetInfo->hasPropertyByName(sRepeat)) + mxImportInfo->setPropertyValue(sRepeat, css::uno::Any(mpProgressBarHelper->GetRepeat())); + // pProgressBarHelper is deleted in dtor + } + OUString sNumberStyles(XML_NUMBERSTYLES); + if (mxNumberStyles.is() && xPropertySetInfo->hasPropertyByName(sNumberStyles)) + { + mxImportInfo->setPropertyValue(sNumberStyles, Any(mxNumberStyles)); + } + } + } + + if( mxFontDecls.is() ) + mxFontDecls->dispose(); + if( mxStyles.is() ) + mxStyles->dispose(); + if( mxAutoStyles.is() ) + mxAutoStyles->dispose(); + if( mxMasterStyles.is() ) + mxMasterStyles->dispose(); + + // possible form-layer related knittings which can only be done when + // the whole document exists + if ( mxFormImport.is() ) + mxFormImport->documentDone(); + + // The shape import helper does the z-order sorting in the dtor, + // so it must be deleted here, too. + mxShapeImport = nullptr; + + if( mpImpl->mbOwnGraphicResolver ) + { + Reference xComp(mxGraphicStorageHandler, UNO_QUERY); + xComp->dispose(); + } + + if( mpImpl->mbOwnEmbeddedResolver ) + { + Reference< lang::XComponent > xComp( mxEmbeddedResolver, UNO_QUERY ); + xComp->dispose(); + } + mpStyleMap.clear(); + + if ( bool( mpXMLErrors ) ) + { + mpXMLErrors->ThrowErrorAsSAXException( XMLERROR_FLAG_SEVERE ); + } +} + +std::optional SvXMLImport::processNSAttributes( + std::optional & rpNamespaceMap, + SvXMLImport *const pImport, // TODO??? + const uno::Reference< xml::sax::XAttributeList >& xAttrList) +{ + std::optional pRewindMap; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + if (pImport && rAttrName == "office:version" && !pImport->mpImpl->mxODFVersion) + { + pImport->mpImpl->mxODFVersion = xAttrList->getValueByIndex( i ); + + // the ODF version in content.xml and manifest.xml must be the same starting from ODF1.2 + if (pImport->mpImpl->mStreamName == "content.xml" + && !pImport->IsODFVersionConsistent(*pImport->mpImpl->mxODFVersion)) + { + throw xml::sax::SAXException("Inconsistent ODF versions in content.xml and manifest.xml!", + uno::Reference< uno::XInterface >(), + uno::Any( + packages::zip::ZipIOException("Inconsistent ODF versions in content.xml and manifest.xml!" ) ) ); + } + } + else if( ( rAttrName.getLength() >= 5 ) && + ( rAttrName.startsWith( GetXMLToken(XML_XMLNS) ) ) && + ( rAttrName.getLength() == 5 || ':' == rAttrName[5] ) ) + { + if( !pRewindMap ) + { + pRewindMap = std::move(rpNamespaceMap); + rpNamespaceMap.emplace(*pRewindMap); + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + + OUString aPrefix( ( rAttrName.getLength() == 5 ) + ? OUString() + : rAttrName.copy( 6 ) ); + // Add namespace, but only if it is known. + sal_uInt16 nKey = rpNamespaceMap->AddIfKnown( aPrefix, rAttrValue ); + // If namespace is unknown, try to match a name with similar + // TC Id and version + if( XML_NAMESPACE_UNKNOWN == nKey ) + { + OUString aTestName( rAttrValue ); + if( SvXMLNamespaceMap::NormalizeURI( aTestName ) ) + nKey = rpNamespaceMap->AddIfKnown( aPrefix, aTestName ); + } + // If that namespace is not known, too, add it as unknown + if( XML_NAMESPACE_UNKNOWN == nKey ) + rpNamespaceMap->Add( aPrefix, rAttrValue ); + + } + } + return pRewindMap; +} + + +void SAL_CALL SvXMLImport::characters( const OUString& rChars ) +{ + maContexts.top()->characters( rChars ); +} + +void SAL_CALL SvXMLImport::processingInstruction( const OUString&, + const OUString& ) +{ +} + +void SAL_CALL SvXMLImport::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& rLocator ) +{ + mxLocator = rLocator; +} + +// XFastContextHandler +void SAL_CALL SvXMLImport::startFastElement (sal_Int32 Element, + const uno::Reference< xml::sax::XFastAttributeList > & Attribs) +{ + SAL_INFO("xmloff.core", "startFastElement " << SvXMLImport::getNameFromToken( Element )); + if ( Attribs.is() && !mpImpl->mxODFVersion) + { + sax_fastparser::FastAttributeList& rAttribList = + sax_fastparser::castToFastAttributeList( Attribs ); + auto aIter( rAttribList.find( XML_ELEMENT( OFFICE, XML_VERSION ) ) ); + if( aIter != rAttribList.end() ) + { + mpImpl->mxODFVersion = aIter.toString(); + + // the ODF version in content.xml and manifest.xml must be the same starting from ODF1.2 + if ( mpImpl->mStreamName == "content.xml" && !IsODFVersionConsistent( *mpImpl->mxODFVersion ) ) + { + throw xml::sax::SAXException("Inconsistent ODF versions in content.xml and manifest.xml!", + uno::Reference< uno::XInterface >(), + uno::Any( + packages::zip::ZipIOException("Inconsistent ODF versions in content.xml and manifest.xml!" ) ) ); + } + } + } + + maNamespaceAttrList->Clear(); + + maNamespaceHandler->addNSDeclAttributes( maNamespaceAttrList ); + std::optional pRewindMap = processNSAttributes(mxNamespaceMap, this, maNamespaceAttrList); + + SvXMLImportContextRef xContext; + const bool bRootContext = maContexts.empty(); + if (!maContexts.empty()) + { + const SvXMLImportContextRef & pHandler = maContexts.top(); + SAL_INFO("xmloff.core", "calling createFastChildContext on " << typeid(*pHandler.get()).name()); + auto tmp = pHandler->createFastChildContext( Element, Attribs ); + xContext = static_cast(tmp.get()); + assert((tmp && xContext) || (!tmp && !xContext)); + } + else + xContext.set( CreateFastContext( Element, Attribs ) ); + + SAL_INFO_IF(!xContext.is(), "xmloff.core", "No fast context for element " << getNameFromToken(Element)); + if (bRootContext && !xContext) + { + OUString aName = getNameFromToken(Element); + SetError( XMLERROR_FLAG_SEVERE | XMLERROR_UNKNOWN_ROOT, + { aName }, "Root element " + aName + " unknown", Reference() ); + } + if ( !xContext ) + xContext.set( new SvXMLImportContext( *this ) ); + + // Remember old namespace map. + if( pRewindMap ) + xContext->PutRewindMap(std::move(pRewindMap)); + + // Call a startElement at the new context. + xContext->startFastElement( Element, Attribs ); + + // Push context on stack. + maContexts.push(xContext); +} + +void SAL_CALL SvXMLImport::startUnknownElement (const OUString & rNamespace, const OUString & rName, + const uno::Reference< xml::sax::XFastAttributeList > & Attribs) +{ + SAL_INFO("xmloff.core", "startUnknownElement " << rNamespace << " " << rName); + SvXMLImportContextRef xContext; + const bool bRootContext = maContexts.empty(); + if (!maContexts.empty()) + { + const SvXMLImportContextRef & pHandler = maContexts.top(); + SAL_INFO("xmloff.core", "calling createUnknownChildContext on " << typeid(*pHandler.get()).name()); + auto tmp = pHandler->createUnknownChildContext( rNamespace, rName, Attribs ); + xContext = static_cast(tmp.get()); + assert((tmp && xContext) || (!tmp && !xContext)); + } + else + xContext.set( CreateFastContext( -1, Attribs ) ); + + SAL_WARN_IF(!xContext.is(), "xmloff.core", "No context for unknown-element " << rNamespace << " " << rName); + if (bRootContext && !xContext) + { + SetError( XMLERROR_FLAG_SEVERE | XMLERROR_UNKNOWN_ROOT, + { rName }, "Root element " + rName + " unknown", Reference() ); + } + if (!xContext) + { + if (!maContexts.empty()) + // This is pretty weird, but it's what the code did before I simplified it, and some parts of the + // code rely on this behaviour e.g. DocumentBuilderContext + xContext = maContexts.top(); + else + xContext = new SvXMLImportContext( *this ); + } + + xContext->startUnknownElement( rNamespace, rName, Attribs ); + maContexts.push(xContext); +} + +void SAL_CALL SvXMLImport::endFastElement (sal_Int32 Element) +{ + SAL_INFO("xmloff.core", "endFastElement " << SvXMLImport::getNameFromToken( Element )); + if (maContexts.empty()) + { + SAL_WARN("xmloff.core", "SvXMLImport::endFastElement: no context left"); + assert(false); + return; + } + SvXMLImportContextRef xContext = std::move(maContexts.top()); + // Get a namespace map to rewind. + std::optional pRewindMap = xContext->TakeRewindMap(); + maContexts.pop(); + xContext->endFastElement( Element ); + // Rewind a namespace map. + if (pRewindMap) + mxNamespaceMap = std::move(pRewindMap); +} + +void SAL_CALL SvXMLImport::endUnknownElement (const OUString & rPrefix, const OUString & rLocalName) +{ + SAL_INFO("xmloff.core", "endUnknownElement " << rPrefix << " " << rLocalName); + if (maContexts.empty()) + { + SAL_WARN("xmloff.core", "SvXMLImport::endUnknownElement: no context left"); + assert(false); + return; + } + SvXMLImportContextRef xContext = std::move(maContexts.top()); + maContexts.pop(); + xContext->endUnknownElement( rPrefix, rLocalName ); +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL + SvXMLImport::createFastChildContext (sal_Int32, + const uno::Reference< xml::sax::XFastAttributeList > &) +{ + return this; +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL + SvXMLImport::createUnknownChildContext (const OUString &, const OUString &, + const uno::Reference< xml::sax::XFastAttributeList > &) +{ + return this; +} + +void SvXMLImport::SetStatistics(const uno::Sequence< beans::NamedValue> &) +{ + GetProgressBarHelper()->SetRepeat(false); + GetProgressBarHelper()->SetReference(0); +} + +// XImporter +void SAL_CALL SvXMLImport::setTargetDocument( const uno::Reference< lang::XComponent >& xDoc ) +{ + mxModel.set( xDoc, UNO_QUERY ); + if( !mxModel.is() ) + throw lang::IllegalArgumentException(); + + try + { + uno::Reference const xSBDoc(mxModel, uno::UNO_QUERY); + uno::Reference const xStor(xSBDoc.is() ? xSBDoc->getDocumentStorage() + : nullptr); + if (xStor.is()) + { + mpImpl->mbIsOOoXML = + ::comphelper::OStorageHelper::GetXStorageFormat(xStor) + < SOFFICE_FILEFORMAT_8; + } + } + catch (uno::Exception const&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.core"); + } + if (!mxEventListener.is()) + { + mxEventListener.set(new SvXMLImportEventListener(this)); + mxModel->addEventListener(mxEventListener); + } + + SAL_WARN_IF( bool(mpNumImport), "xmloff.core", "number format import already exists." ); + mpNumImport.reset(); +} + +// XFilter +sal_Bool SAL_CALL SvXMLImport::filter( const uno::Sequence< beans::PropertyValue >& ) +{ + return false; +} + +void SAL_CALL SvXMLImport::cancel( ) +{ +} + +// XInitialize +void SAL_CALL SvXMLImport::initialize( const uno::Sequence< uno::Any >& aArguments ) +{ + for( const auto& rAny : aArguments ) + { + Reference xValue; + rAny >>= xValue; + + uno::Reference xTmpStatusIndicator( + xValue, UNO_QUERY ); + if( xTmpStatusIndicator.is() ) + mxStatusIndicator = xTmpStatusIndicator; + + uno::Reference xGraphicStorageHandler(xValue, UNO_QUERY); + if (xGraphicStorageHandler.is()) + mxGraphicStorageHandler = xGraphicStorageHandler; + + uno::Reference xTmpObjectResolver( + xValue, UNO_QUERY ); + if( xTmpObjectResolver.is() ) + mxEmbeddedResolver = xTmpObjectResolver; + + uno::Reference xTmpPropSet( xValue, UNO_QUERY ); + if( xTmpPropSet.is() ) + { + mxImportInfo = xTmpPropSet; + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxImportInfo->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + OUString sPropName(XML_NUMBERSTYLES); + if (xPropertySetInfo->hasPropertyByName(sPropName)) + { + uno::Any aAny = mxImportInfo->getPropertyValue(sPropName); + aAny >>= mxNumberStyles; + } + + sPropName = "PrivateData"; + if (xPropertySetInfo->hasPropertyByName(sPropName)) + { + Reference < XInterface > xIfc; + uno::Any aAny = mxImportInfo->getPropertyValue(sPropName); + aAny >>= xIfc; + + StyleMap *pSMap = comphelper::getFromUnoTunnel( xIfc ); + if( pSMap ) + { + mpStyleMap = pSMap; + } + } + OUString sBaseURI; + sPropName = "BaseURI"; + if (xPropertySetInfo->hasPropertyByName(sPropName)) + { + uno::Any aAny = mxImportInfo->getPropertyValue(sPropName); + aAny >>= sBaseURI; + mpImpl->aBaseURL.SetURL( sBaseURI ); + mpImpl->aDocBase.SetURL( sBaseURI ); + } + OUString sRelPath; + sPropName = "StreamRelPath"; + if( xPropertySetInfo->hasPropertyByName(sPropName) ) + { + uno::Any aAny = mxImportInfo->getPropertyValue(sPropName); + aAny >>= sRelPath; + } + OUString sName; + sPropName = "StreamName"; + if( xPropertySetInfo->hasPropertyByName(sPropName) ) + { + uno::Any aAny = mxImportInfo->getPropertyValue(sPropName); + aAny >>= sName; + } + if( !sBaseURI.isEmpty() && !sName.isEmpty() ) + { + if( !sRelPath.isEmpty() ) + mpImpl->aBaseURL.insertName( sRelPath ); + mpImpl->aBaseURL.insertName( sName ); + } + mpImpl->mStreamName = sName; // Note: may be empty (XSLT) + // Retrieve property (#i28749#) + sPropName = "ShapePositionInHoriL2R"; + if( xPropertySetInfo->hasPropertyByName(sPropName) ) + { + uno::Any aAny = mxImportInfo->getPropertyValue(sPropName); + aAny >>= mpImpl->mbShapePositionInHoriL2R; + } + sPropName = "TextDocInOOoFileFormat"; + if( xPropertySetInfo->hasPropertyByName(sPropName) ) + { + uno::Any aAny = mxImportInfo->getPropertyValue(sPropName); + aAny >>= mpImpl->mbTextDocInOOoFileFormat; + } + + sPropName = "SourceStorage"; + if( xPropertySetInfo->hasPropertyByName(sPropName) ) + mxImportInfo->getPropertyValue(sPropName) >>= mpImpl->mxSourceStorage; + } + } + } + + uno::Reference const xInit(mxParser, uno::UNO_QUERY_THROW); + xInit->initialize( { Any(OUString("IgnoreMissingNSDecl")) }); +} + +// XServiceInfo +OUString SAL_CALL SvXMLImport::getImplementationName() +{ + return mpImpl->implementationName; +} + +sal_Bool SAL_CALL SvXMLImport::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SAL_CALL SvXMLImport::getSupportedServiceNames( ) +{ + return mpImpl->maSupportedServiceNames; +} + +XMLTextImportHelper* SvXMLImport::CreateTextImport() +{ + return new XMLTextImportHelper( mxModel, *this ); +} + +XMLShapeImportHelper* SvXMLImport::CreateShapeImport() +{ + return new XMLShapeImportHelper( *this, mxModel ); +} + +SchXMLImportHelper* SvXMLImport::CreateChartImport() +{ +// WASM_CHART change +// TODO: Instead of importing the ChartModel an alternative may be +// added to convert not to Chart/OLE SdrObejct, but to GraphicObject +// with the Chart visualization. There should be a preview available +// in the imported chart data +#if !ENABLE_WASM_STRIP_CHART + return new SchXMLImportHelper(); +#else + return nullptr; +#endif +} + +::xmloff::OFormLayerXMLImport* SvXMLImport::CreateFormImport() +{ + return new ::xmloff::OFormLayerXMLImport(*this); +} + + +// Get or create fill/line/lineend-style-helper + + +const Reference< container::XNameContainer > & SvXMLImport::GetGradientHelper() +{ + if( !mxGradientHelper.is() ) + { + if( mxModel.is() ) + { + Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY); + if( xServiceFact.is() ) + { + try + { + mxGradientHelper.set( xServiceFact->createInstance( + "com.sun.star.drawing.GradientTable" ), UNO_QUERY); + } + catch( lang::ServiceNotRegisteredException& ) + {} + } + } + } + + return mxGradientHelper; +} + +const Reference< container::XNameContainer > & SvXMLImport::GetHatchHelper() +{ + if( !mxHatchHelper.is() ) + { + if( mxModel.is() ) + { + Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY); + if( xServiceFact.is() ) + { + try + { + mxHatchHelper.set( xServiceFact->createInstance( + "com.sun.star.drawing.HatchTable" ), UNO_QUERY); + } + catch( lang::ServiceNotRegisteredException& ) + {} + } + } + } + + return mxHatchHelper; +} + +const Reference< container::XNameContainer > & SvXMLImport::GetBitmapHelper() +{ + if( !mxBitmapHelper.is() ) + { + if( mxModel.is() ) + { + Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY); + if( xServiceFact.is() ) + { + try + { + mxBitmapHelper.set( xServiceFact->createInstance( + "com.sun.star.drawing.BitmapTable" ), UNO_QUERY); + } + catch( lang::ServiceNotRegisteredException& ) + {} + } + } + } + + return mxBitmapHelper; +} + +const Reference< container::XNameContainer > & SvXMLImport::GetTransGradientHelper() +{ + if( !mxTransGradientHelper.is() ) + { + if( mxModel.is() ) + { + Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY); + if( xServiceFact.is() ) + { + try + { + mxTransGradientHelper.set( xServiceFact->createInstance( + "com.sun.star.drawing.TransparencyGradientTable" ), UNO_QUERY); + } + catch( lang::ServiceNotRegisteredException& ) + {} + } + } + } + + return mxTransGradientHelper; +} + +const Reference< container::XNameContainer > & SvXMLImport::GetMarkerHelper() +{ + if( !mxMarkerHelper.is() ) + { + if( mxModel.is() ) + { + Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY); + if( xServiceFact.is() ) + { + try + { + mxMarkerHelper.set( xServiceFact->createInstance( "com.sun.star.drawing.MarkerTable" ), UNO_QUERY); + } + catch( lang::ServiceNotRegisteredException& ) + {} + } + } + } + + return mxMarkerHelper; +} + +const Reference< container::XNameContainer > & SvXMLImport::GetDashHelper() +{ + if( !mxDashHelper.is() && mxModel.is() ) + { + Reference< lang::XMultiServiceFactory > xServiceFact( mxModel, UNO_QUERY); + if( xServiceFact.is() ) + { + try + { + mxDashHelper.set( xServiceFact->createInstance( "com.sun.star.drawing.DashTable" ), UNO_QUERY); + } + catch( lang::ServiceNotRegisteredException& ) + {} + } + } + + return mxDashHelper; +} + +bool SvXMLImport::IsPackageURL( const OUString& rURL ) const +{ + + // if, and only if, only parts are imported, then we're in a package + const SvXMLImportFlags nTest = SvXMLImportFlags::META|SvXMLImportFlags::STYLES|SvXMLImportFlags::CONTENT|SvXMLImportFlags::SETTINGS; + if( (mnImportFlags & nTest) == nTest ) + return false; + + // TODO: from this point extract to own static function + + // Some quick tests: Some may rely on the package structure! + sal_Int32 nLen = rURL.getLength(); + if( nLen > 0 && '/' == rURL[0] ) + // RFC2396 net_path or abs_path + return false; + else if( nLen > 1 && '.' == rURL[0] ) + { + if( '.' == rURL[1] ) + // ../: We are never going up one level, so we know + // it's not an external URI + return false; + else if( '/' == rURL[1] ) + // we are remaining on a level, so it's a package URI + return true; + } + + // Now check for a RFC2396 schema + sal_Int32 nPos = 1; + while( nPos < nLen ) + { + switch( rURL[nPos] ) + { + case '/': + // a relative path segment + return true; + case ':': + // a schema + return false; + default: + break; + // we don't care about any other characters + } + ++nPos; + } + + return true; +} + +uno::Reference SvXMLImport::loadGraphicByURL(OUString const & rURL) +{ + uno::Reference xGraphic; + + if (mxGraphicStorageHandler.is()) + { + if (IsPackageURL(rURL)) + { + xGraphic = mxGraphicStorageHandler->loadGraphic(rURL); + } + else + { + OUString const & rAbsoluteURL = GetAbsoluteReference(rURL); + GraphicExternalLink aExternalLink(rAbsoluteURL); + Graphic aGraphic(aExternalLink); + xGraphic = aGraphic.GetXGraphic(); + } + } + + return xGraphic; +} + +uno::Reference SvXMLImport::loadGraphicFromBase64(uno::Reference const & rxOutputStream) +{ + uno::Reference xGraphic; + + if (mxGraphicStorageHandler.is()) + { + xGraphic = mxGraphicStorageHandler->loadGraphicFromOutputStream(rxOutputStream); + } + + return xGraphic; +} + +Reference< XOutputStream > SvXMLImport::GetStreamForGraphicObjectURLFromBase64() const +{ + Reference< XOutputStream > xOStm; + Reference< document::XBinaryStreamResolver > xStmResolver(mxGraphicStorageHandler, UNO_QUERY); + + if( xStmResolver.is() ) + xOStm = xStmResolver->createOutputStream(); + + return xOStm; +} + +OUString SvXMLImport::ResolveEmbeddedObjectURL( + const OUString& rURL, + std::u16string_view rClassId ) +{ + OUString sRet; + + if( IsPackageURL( rURL ) ) + { + if ( mxEmbeddedResolver.is() ) + { + OUString sURL( rURL ); + if( !rClassId.empty() ) + { + sURL += OUString::Concat("!") + rClassId; + } + sRet = mxEmbeddedResolver->resolveEmbeddedObjectURL( sURL ); + } + } + else + sRet = GetAbsoluteReference( rURL ); + + return sRet; +} + +Reference< embed::XStorage > const & SvXMLImport::GetSourceStorage() const +{ + return mpImpl->mxSourceStorage; +} + +Reference < XOutputStream > + SvXMLImport::GetStreamForEmbeddedObjectURLFromBase64() const +{ + Reference < XOutputStream > xOLEStream; + + if( mxEmbeddedResolver.is() ) + { + Reference< XNameAccess > xNA( mxEmbeddedResolver, UNO_QUERY ); + if( xNA.is() ) + { + Any aAny = xNA->getByName( "Obj12345678" ); + aAny >>= xOLEStream; + } + } + + return xOLEStream; +} + +OUString SvXMLImport::ResolveEmbeddedObjectURLFromBase64() +{ + OUString sRet; + + if( mxEmbeddedResolver.is() ) + { + sRet = mxEmbeddedResolver->resolveEmbeddedObjectURL( "Obj12345678" ); + } + + return sRet; +} + +void SvXMLImport::AddStyleDisplayName( XmlStyleFamily nFamily, + const OUString& rName, + const OUString& rDisplayName ) +{ + if( !mpStyleMap.is() ) + { + mpStyleMap = new StyleMap; + if( mxImportInfo.is() ) + { + OUString sPrivateData( "PrivateData" ); + Reference< beans::XPropertySetInfo > xPropertySetInfo = + mxImportInfo->getPropertySetInfo(); + if( xPropertySetInfo.is() && + xPropertySetInfo->hasPropertyByName(sPrivateData) ) + { + Reference < XInterface > xIfc( + static_cast< XUnoTunnel *>( mpStyleMap.get() ) ); + mxImportInfo->setPropertyValue( sPrivateData, Any(xIfc) ); + } + } + } + + StyleMap::key_type aKey( nFamily, rName ); + StyleMap::value_type aValue( aKey, rDisplayName ); + ::std::pair aRes( mpStyleMap->insert( aValue ) ); + SAL_WARN_IF( !aRes.second, + "xmloff.core", + "duplicate style name of family " << static_cast(nFamily) << ": \"" << rName << "\""); + +} + +OUString SvXMLImport::GetStyleDisplayName( XmlStyleFamily nFamily, + const OUString& rName ) const +{ + OUString sName( rName ); + if( mpStyleMap.is() && !rName.isEmpty() ) + { + StyleMap::key_type aKey( nFamily, rName ); + StyleMap::const_iterator aIter = mpStyleMap->find( aKey ); + if( aIter != mpStyleMap->end() ) + sName = (*aIter).second; + } + return sName; +} + +void SvXMLImport::SetViewSettings(const css::uno::Sequence&) +{ +} + +void SvXMLImport::SetConfigurationSettings(const css::uno::Sequence&) +{ +} + +void SvXMLImport::SetDocumentSpecificSettings(const OUString&, const uno::Sequence&) +{ +} + +ProgressBarHelper* SvXMLImport::GetProgressBarHelper() +{ + if (!mpProgressBarHelper) + { + mpProgressBarHelper = std::make_unique(mxStatusIndicator, false); + + if (mxImportInfo.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = mxImportInfo->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + OUString sProgressRange(XML_PROGRESSRANGE); + OUString sProgressMax(XML_PROGRESSMAX); + OUString sProgressCurrent(XML_PROGRESSCURRENT); + OUString sRepeat(XML_PROGRESSREPEAT); + if (xPropertySetInfo->hasPropertyByName(sProgressMax) && + xPropertySetInfo->hasPropertyByName(sProgressCurrent) && + xPropertySetInfo->hasPropertyByName(sProgressRange)) + { + uno::Any aAny; + sal_Int32 nProgressMax(0); + sal_Int32 nProgressCurrent(0); + sal_Int32 nProgressRange(0); + aAny = mxImportInfo->getPropertyValue(sProgressRange); + if (aAny >>= nProgressRange) + mpProgressBarHelper->SetRange(nProgressRange); + aAny = mxImportInfo->getPropertyValue(sProgressMax); + if (aAny >>= nProgressMax) + mpProgressBarHelper->SetReference(nProgressMax); + aAny = mxImportInfo->getPropertyValue(sProgressCurrent); + if (aAny >>= nProgressCurrent) + mpProgressBarHelper->SetValue(nProgressCurrent); + } + if (xPropertySetInfo->hasPropertyByName(sRepeat)) + { + uno::Any aAny = mxImportInfo->getPropertyValue(sRepeat); + if (aAny.getValueType() == cppu::UnoType::get()) + mpProgressBarHelper->SetRepeat(::cppu::any2bool(aAny)); + else { + SAL_WARN( "xmloff.core", "why is it no boolean?" ); + } + } + } + } + } + return mpProgressBarHelper.get(); +} + +void SvXMLImport::AddNumberStyle(sal_Int32 nKey, const OUString& rName) +{ + if (!mxNumberStyles.is()) + mxNumberStyles.set( comphelper::NameContainer_createInstance( ::cppu::UnoType::get()) ); + if (mxNumberStyles.is()) + { + try + { + mxNumberStyles->insertByName(rName, Any(nKey)); + } + catch ( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "xmloff.core", "Numberformat could not be inserted"); + } + } + else { + SAL_WARN( "xmloff.core", "not possible to create NameContainer"); + } +} + +XMLEventImportHelper& SvXMLImport::GetEventImport() +{ + if (!mpEventImportHelper) + { + // construct event helper and register StarBasic handler and standard + // event tables + mpEventImportHelper = std::make_unique(); + const OUString& sStarBasic(GetXMLToken(XML_STARBASIC)); + mpEventImportHelper->RegisterFactory(sStarBasic, + std::make_unique()); + const OUString& sScript(GetXMLToken(XML_SCRIPT)); + mpEventImportHelper->RegisterFactory(sScript, + std::make_unique()); + mpEventImportHelper->AddTranslationTable(aStandardEventTable); + + // register StarBasic event handler with capitalized spelling + mpEventImportHelper->RegisterFactory("StarBasic", + std::make_unique()); + } + + return *mpEventImportHelper; +} + +void SvXMLImport::SetFontDecls( XMLFontStylesContext *pFontDecls ) +{ + if (mxFontDecls.is()) + mxFontDecls->dispose(); + mxFontDecls = pFontDecls; +} + +void SvXMLImport::SetStyles( SvXMLStylesContext *pStyles ) +{ + if (mxStyles.is()) + mxStyles->dispose(); + mxStyles = pStyles; +} + +void SvXMLImport::SetAutoStyles( SvXMLStylesContext *pAutoStyles ) +{ + if (pAutoStyles && mxNumberStyles.is()) + { + uno::Reference xAttrList = new sax_fastparser::FastAttributeList(nullptr); + const uno::Sequence aStyleNames = mxNumberStyles->getElementNames(); + for (const auto& name : aStyleNames) + { + uno::Any aAny(mxNumberStyles->getByName(name)); + sal_Int32 nKey(0); + if (aAny >>= nKey) + { + SvXMLStyleContext* pContext = new SvXMLNumFormatContext( + *this, name, xAttrList, nKey, + GetDataStylesImport()->GetLanguageForKey(nKey), *pAutoStyles); + pAutoStyles->AddStyle(*pContext); + } + } + } + if (mxAutoStyles.is()) + mxAutoStyles->dispose(); + mxAutoStyles = pAutoStyles; + GetTextImport()->SetAutoStyles( pAutoStyles ); + GetShapeImport()->SetAutoStylesContext( pAutoStyles ); +#if !ENABLE_WASM_STRIP_CHART + GetChartImport()->SetAutoStylesContext( pAutoStyles ); +#endif + GetFormImport()->setAutoStyleContext( pAutoStyles ); +} + +void SvXMLImport::SetMasterStyles( SvXMLStylesContext *pMasterStyles ) +{ + if (mxMasterStyles.is()) + mxMasterStyles->dispose(); + mxMasterStyles = pMasterStyles; +} + +XMLFontStylesContext *SvXMLImport::GetFontDecls() +{ + return mxFontDecls.get(); +} + +SvXMLStylesContext *SvXMLImport::GetStyles() +{ + return mxStyles.get(); +} + +SvXMLStylesContext *SvXMLImport::GetAutoStyles() +{ + return mxAutoStyles.get(); +} + +const XMLFontStylesContext *SvXMLImport::GetFontDecls() const +{ + return mxFontDecls.get(); +} + +const SvXMLStylesContext *SvXMLImport::GetStyles() const +{ + return mxStyles.get(); +} + +const SvXMLStylesContext *SvXMLImport::GetAutoStyles() const +{ + return mxAutoStyles.get(); +} + +OUString SvXMLImport::GetAbsoluteReference(const OUString& rValue) const +{ + if( rValue.isEmpty() || rValue[0] == '#' ) + return rValue; + + INetURLObject aAbsURL; + if( mpImpl->aBaseURL.GetNewAbsURL( rValue, &aAbsURL ) ) + return aAbsURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri ); + else + return rValue; +} + +bool SvXMLImport::IsODFVersionConsistent( const OUString& aODFVersion ) +{ + // the check returns false only if the storage version could be retrieved + bool bResult = true; + + if ( !aODFVersion.isEmpty() && aODFVersion.compareTo( ODFVER_012_TEXT ) >= 0 ) + { + // check the consistency only for the ODF1.2 and later ( according to content.xml ) + // manifest.xml might have no version, it should be checked here and the correct version should be set + try + { // don't use getDocumentStorage(), it's temporary and latest version + uno::Reference const xStor(GetSourceStorage()); + if (!xStor.is()) + return bResult; + uno::Reference< beans::XPropertySet > xStorProps( xStor, uno::UNO_QUERY_THROW ); + + // the check should be done only for OASIS format + if (!IsOOoXML()) + { + bool bRepairPackage = false; + try + { + xStorProps->getPropertyValue( "RepairPackage" ) + >>= bRepairPackage; + } catch ( uno::Exception& ) + {} + + // check only if not in Repair mode + if ( !bRepairPackage ) + { + OUString aStorVersion; + xStorProps->getPropertyValue( "Version" ) + >>= aStorVersion; + + // if the storage version is set in manifest.xml, it must be the same as in content.xml + // if not, set it explicitly to be used further ( it will work even for readonly storage ) + // This workaround is not nice, but I see no other way to handle it, since there are + // ODF1.2 documents without version in manifest.xml + if ( !aStorVersion.isEmpty() ) + bResult = aODFVersion == aStorVersion; + else + xStorProps->setPropertyValue( "Version", + uno::Any( aODFVersion ) ); + + if ( bResult ) + { + bool bInconsistent = false; + xStorProps->getPropertyValue( "IsInconsistent" ) + >>= bInconsistent; + bResult = !bInconsistent; + } + } + } + } + catch( uno::Exception& ) + {} + } + + return bResult; +} + +void SvXMLImport::CreateNumberFormatsSupplier_() +{ + SAL_WARN_IF( mxNumberFormatsSupplier.is(), "xmloff.core", "number formats supplier already exists!" ); + if(mxModel.is()) + mxNumberFormatsSupplier = + uno::Reference< util::XNumberFormatsSupplier> (mxModel, uno::UNO_QUERY); +} + +void SvXMLImport::CreateDataStylesImport_() +{ + SAL_WARN_IF( bool(mpNumImport), "xmloff.core", "data styles import already exists!" ); + uno::Reference xNum = + GetNumberFormatsSupplier(); + if ( xNum.is() ) + mpNumImport = std::make_unique(xNum, GetComponentContext() ); +} + +sal_Unicode SvXMLImport::ConvStarBatsCharToStarSymbol( sal_Unicode c ) +{ + sal_Unicode cNew = c; + if( !mpImpl->hBatsFontConv ) + { + mpImpl->hBatsFontConv = CreateFontToSubsFontConverter( u"StarBats", + FontToSubsFontFlags::IMPORT ); + SAL_WARN_IF( !mpImpl->hBatsFontConv, "xmloff.core", "Got no symbol font converter" ); + } + if( mpImpl->hBatsFontConv ) + { + cNew = ConvertFontToSubsFontChar( mpImpl->hBatsFontConv, c ); + } + + return cNew; +} + +sal_Unicode SvXMLImport::ConvStarMathCharToStarSymbol( sal_Unicode c ) +{ + sal_Unicode cNew = c; + if( !mpImpl->hMathFontConv ) + { + mpImpl->hMathFontConv = CreateFontToSubsFontConverter( u"StarMath", + FontToSubsFontFlags::IMPORT ); + SAL_WARN_IF( !mpImpl->hMathFontConv, "xmloff.core", "Got no symbol font converter" ); + } + if( mpImpl->hMathFontConv ) + { + cNew = ConvertFontToSubsFontChar( mpImpl->hMathFontConv, c ); + } + + return cNew; +} + +void SvXMLImport::SetError( + sal_Int32 nId, + const Sequence& rMsgParams, + const OUString& rExceptionMessage, + const Reference& rLocator ) +{ + // create error list on demand + if ( !mpXMLErrors ) + mpXMLErrors = std::make_unique(); + + // save error information + // use document locator (if none supplied) + mpXMLErrors->AddRecord( nId, rMsgParams, rExceptionMessage, + rLocator.is() ? rLocator : mxLocator ); +} + +void SvXMLImport::SetError( + sal_Int32 nId, + const Sequence& rMsgParams) +{ + SetError( nId, rMsgParams, "", nullptr ); +} + +void SvXMLImport::SetError( + sal_Int32 nId, + const OUString& rMsg1) +{ + Sequence aSeq { rMsg1 }; + SetError( nId, aSeq ); +} + +void SvXMLImport::DisposingModel() +{ + if( mxFontDecls.is() ) + mxFontDecls->dispose(); + if( mxStyles.is() ) + mxStyles->dispose(); + if( mxAutoStyles.is() ) + mxAutoStyles->dispose(); + if( mxMasterStyles.is() ) + mxMasterStyles->dispose(); + + mxModel.set(nullptr); + mxEventListener.set(nullptr); +} + +::comphelper::UnoInterfaceToUniqueIdentifierMapper& SvXMLImport::getInterfaceToIdentifierMapper() +{ + return mpImpl->maInterfaceToIdentifierMapper; +} + +uno::Reference< uno::XComponentContext > const & +SvXMLImport::GetComponentContext() const +{ + return mpImpl->mxComponentContext; +} + +OUString SvXMLImport::GetBaseURL() const +{ + return mpImpl->aBaseURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); +} + +OUString SvXMLImport::GetDocumentBase() const +{ + return mpImpl->aDocBase.GetMainURL( INetURLObject::DecodeMechanism::NONE ); +} + +// Convert drawing object positions from OOo file format to OASIS (#i28749#) +bool SvXMLImport::IsShapePositionInHoriL2R() const +{ + return mpImpl->mbShapePositionInHoriL2R; +} + +bool SvXMLImport::IsTextDocInOOoFileFormat() const +{ + return mpImpl->mbTextDocInOOoFileFormat; +} + +void SvXMLImport::initXForms() +{ + // dummy method; to be implemented by derived classes supporting XForms +} + +bool SvXMLImport::getBuildIds( sal_Int32& rUPD, sal_Int32& rBuild ) const +{ + bool bRet = false; + OUString const aBuildId(getBuildIdsProperty(mxImportInfo)); + if (!aBuildId.isEmpty()) + { + sal_Int32 nIndex = aBuildId.indexOf('$'); + if (nIndex != -1) + { + rUPD = o3tl::toInt32(aBuildId.subView( 0, nIndex )); + sal_Int32 nIndexEnd = aBuildId.indexOf(';', nIndex); + rBuild = (nIndexEnd == -1) + ? o3tl::toInt32(aBuildId.subView(nIndex + 1)) + : o3tl::toInt32(aBuildId.subView(nIndex + 1, nIndexEnd - nIndex - 1)); + bRet = true; + } + } + return bRet; +} + +sal_uInt16 SvXMLImport::getGeneratorVersion() const +{ + // --> ORW + return mpImpl->getGeneratorVersion( *this ); + // <-- +} + +bool SvXMLImport::isGeneratorVersionOlderThan( + sal_uInt16 const nOOoVersion, sal_uInt16 const nLOVersion) +{ + assert( (nLOVersion & LO_flag)); + assert(!(nOOoVersion & LO_flag)); + const sal_uInt16 nGeneratorVersion(getGeneratorVersion()); + return (nGeneratorVersion & LO_flag) + ? nGeneratorVersion < nLOVersion + : nGeneratorVersion < nOOoVersion; +} + + +OUString SvXMLImport::GetODFVersion() const +{ + return mpImpl->mxODFVersion ? *mpImpl->mxODFVersion : OUString(); +} + +bool SvXMLImport::IsOOoXML() const +{ + return mpImpl->mbIsOOoXML; +} + +bool SvXMLImport::IsMSO() const +{ + if (!mpImpl->mbIsMSO.has_value()) + { + uno::Reference xSupplier(GetModel(), uno::UNO_QUERY); + if (xSupplier.is()) + { + uno::Reference xProps + = xSupplier->getDocumentProperties(); + if (xProps.is()) + { + mpImpl->mbIsMSO = xProps->getGenerator().startsWith("MicrosoftOffice"); + } + } + } + + return mpImpl->mbIsMSO.has_value() ? *mpImpl->mbIsMSO : false; +} + +// xml:id for RDF metadata +void SvXMLImport::SetXmlId(uno::Reference const & i_xIfc, + OUString const & i_rXmlId) +{ + if (i_rXmlId.isEmpty()) + return; + + try { + const uno::Reference xMeta(i_xIfc, + uno::UNO_QUERY); +//FIXME: not yet + if (xMeta.is()) { + const beans::StringPair mdref( mpImpl->mStreamName, i_rXmlId ); + try { + xMeta->setMetadataReference(mdref); + } catch (lang::IllegalArgumentException &) { + // probably duplicate; ignore + SAL_INFO("xmloff.core", "SvXMLImport::SetXmlId: cannot set xml:id"); + } + } + } catch (uno::Exception &) { + TOOLS_WARN_EXCEPTION("xmloff.core","SvXMLImport::SetXmlId"); + } +} + +::xmloff::RDFaImportHelper & +SvXMLImport::GetRDFaImportHelper() +{ + if (!mpImpl->mpRDFaHelper) + { + mpImpl->mpRDFaHelper.reset( new ::xmloff::RDFaImportHelper(*this) ); + } + return *mpImpl->mpRDFaHelper; +} + +void +SvXMLImport::AddRDFa(const uno::Reference& i_xObject, + OUString const & i_rAbout, + OUString const & i_rProperty, + OUString const & i_rContent, + OUString const & i_rDatatype) +{ + // N.B.: we only get called if i_xObject had xhtml:about attribute + // (an empty attribute value is valid) + ::xmloff::RDFaImportHelper & rRDFaHelper( GetRDFaImportHelper() ); + rRDFaHelper.ParseAndAddRDFa(i_xObject, + i_rAbout, i_rProperty, i_rContent, i_rDatatype); +} + +bool SvXMLImport::embeddedFontAlreadyProcessed( const OUString& url ) +{ + if( embeddedFontUrlsKnown.count( url ) != 0 ) + return true; + embeddedFontUrlsKnown.insert( url ); + return false; +} + +const OUString & SvXMLImport::getNameFromToken( sal_Int32 nToken ) +{ + return xTokenHandler->getIdentifier( nToken & TOKEN_MASK ); +} + +OUString SvXMLImport::getPrefixAndNameFromToken( sal_Int32 nToken ) +{ + OUString rv; + sal_Int32 nNamespaceToken = ( nToken & NMSP_MASK ) >> NMSP_SHIFT; + auto aIter( aNamespaceMap.find( nNamespaceToken ) ); + if( aIter != aNamespaceMap.end() ) + rv = (*aIter).second.second + " " + aIter->second.first + ":"; + return rv + xTokenHandler->getIdentifier( nToken & TOKEN_MASK ); +} + +OUString SvXMLImport::getNamespacePrefixFromToken(sal_Int32 nToken, const SvXMLNamespaceMap* pMap) +{ + sal_Int32 nNamespaceToken = ( nToken & NMSP_MASK ) >> NMSP_SHIFT; + auto aIter( aNamespaceMap.find( nNamespaceToken ) ); + if( aIter != aNamespaceMap.end() ) + { + if (pMap) + { + OUString sRet = pMap->GetPrefixByKey(pMap->GetKeyByName((*aIter).second.second)); + if (!sRet.isEmpty()) + return sRet; + } + return (*aIter).second.first; + } + else + return OUString(); +} + +OUString SvXMLImport::getNamespaceURIFromToken( sal_Int32 nToken ) +{ + sal_Int32 nNamespaceToken = ( nToken & NMSP_MASK ) >> NMSP_SHIFT; + auto aIter( aNamespaceMap.find( nNamespaceToken ) ); + if( aIter != aNamespaceMap.end() ) + return (*aIter).second.second; + else + return OUString(); +} + +OUString SvXMLImport::getNamespacePrefixFromURI( const OUString& rURI ) +{ + auto aIter( aNamespaceURIPrefixMap.find(rURI) ); + if( aIter != aNamespaceURIPrefixMap.end() ) + return (*aIter).second; + else + return OUString(); +} + +sal_Int32 SvXMLImport::getTokenFromName( const OUString& rName ) +{ + Sequence< sal_Int8 > aLocalNameSeq( reinterpret_cast( + OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr()), rName.getLength() ); + return xTokenHandler->getTokenFromUTF8( aLocalNameSeq ); +} + +void SvXMLImport::initializeNamespaceMaps() +{ + auto mapTokenToNamespace = []( sal_Int32 nToken, sal_Int32 nPrefix, sal_Int32 nNamespace ) + { + if ( nToken >= 0 ) + { + const OUString& sNamespace = GetXMLToken( static_cast( nNamespace ) ); + const OUString& sPrefix = GetXMLToken( static_cast( nPrefix ) ); + assert( aNamespaceMap.find(nToken +1) == aNamespaceMap.end() && "cannot map two namespaces to the same token here"); + aNamespaceMap[ nToken + 1 ] = std::make_pair( sPrefix, sNamespace ); + aNamespaceURIPrefixMap.emplace( sNamespace, sPrefix ); + } + }; + + mapTokenToNamespace( XML_NAMESPACE_XML, XML_XML, XML_N_XML ); // implicit "xml" namespace prefix + mapTokenToNamespace( XML_NAMESPACE_OFFICE, XML_NP_OFFICE, XML_N_OFFICE ); + mapTokenToNamespace( XML_NAMESPACE_OFFICE_SO52, XML_NP_OFFICE, XML_N_OFFICE_OLD ); + mapTokenToNamespace( XML_NAMESPACE_OFFICE_OOO, XML_NP_OFFICE, XML_N_OFFICE_OOO ); + mapTokenToNamespace( XML_NAMESPACE_STYLE, XML_NP_STYLE, XML_N_STYLE ); + mapTokenToNamespace( XML_NAMESPACE_STYLE_SO52, XML_NP_STYLE, XML_N_STYLE_OLD ); + mapTokenToNamespace( XML_NAMESPACE_STYLE_OOO, XML_NP_STYLE, XML_N_STYLE_OOO ); + mapTokenToNamespace( XML_NAMESPACE_TEXT, XML_NP_TEXT, XML_N_TEXT ); + mapTokenToNamespace( XML_NAMESPACE_TEXT_SO52, XML_NP_TEXT, XML_N_TEXT_OLD ); + mapTokenToNamespace( XML_NAMESPACE_TEXT_OOO, XML_NP_TEXT, XML_N_TEXT_OOO ); + mapTokenToNamespace( XML_NAMESPACE_TABLE, XML_NP_TABLE, XML_N_TABLE ); + mapTokenToNamespace( XML_NAMESPACE_TABLE_SO52, XML_NP_TABLE, XML_N_TABLE_OLD ); + mapTokenToNamespace( XML_NAMESPACE_TABLE_OOO, XML_NP_TABLE, XML_N_TABLE_OOO ); + mapTokenToNamespace( XML_NAMESPACE_DRAW, XML_NP_DRAW, XML_N_DRAW ); + mapTokenToNamespace( XML_NAMESPACE_DRAW_SO52, XML_NP_DRAW, XML_N_DRAW_OLD ); + mapTokenToNamespace( XML_NAMESPACE_DRAW_OOO, XML_NP_DRAW, XML_N_DRAW_OOO ); + mapTokenToNamespace( XML_NAMESPACE_FO, XML_NP_FO, XML_N_FO ); + mapTokenToNamespace( XML_NAMESPACE_FO_SO52, XML_NP_FO, XML_N_FO_OLD ); + mapTokenToNamespace( XML_NAMESPACE_FO_COMPAT, XML_NP_FO, XML_N_FO_COMPAT ); + mapTokenToNamespace( XML_NAMESPACE_XLINK, XML_NP_XLINK, XML_N_XLINK ); + mapTokenToNamespace( XML_NAMESPACE_XLINK_SO52, XML_NP_XLINK, XML_N_XLINK_OLD ); + mapTokenToNamespace( XML_NAMESPACE_DC, XML_NP_DC, XML_N_DC ); + mapTokenToNamespace( XML_NAMESPACE_META, XML_NP_META, XML_N_META ); + mapTokenToNamespace( XML_NAMESPACE_META_SO52, XML_NP_META, XML_N_META_OLD ); + mapTokenToNamespace( XML_NAMESPACE_META_OOO, XML_NP_META, XML_N_META_OOO ); + mapTokenToNamespace( XML_NAMESPACE_NUMBER, XML_NP_NUMBER, XML_N_NUMBER ); + mapTokenToNamespace( XML_NAMESPACE_NUMBER_SO52, XML_NP_NUMBER, XML_N_NUMBER_OLD ); + mapTokenToNamespace( XML_NAMESPACE_NUMBER_OOO, XML_NP_NUMBER, XML_N_NUMBER_OOO ); + mapTokenToNamespace( XML_NAMESPACE_PRESENTATION, XML_NP_PRESENTATION, XML_N_PRESENTATION ); + mapTokenToNamespace( XML_NAMESPACE_PRESENTATION_SO52,XML_NP_PRESENTATION, XML_N_PRESENTATION_OLD ); + mapTokenToNamespace( XML_NAMESPACE_PRESENTATION_OOO, XML_NP_PRESENTATION, XML_N_PRESENTATION_OOO ); + mapTokenToNamespace( XML_NAMESPACE_PRESENTATION_OASIS, XML_NP_PRESENTATION, XML_N_PRESENTATION_OASIS ); + mapTokenToNamespace( XML_NAMESPACE_SVG, XML_NP_SVG, XML_N_SVG ); + mapTokenToNamespace( XML_NAMESPACE_SVG_COMPAT, XML_NP_SVG, XML_N_SVG_COMPAT ); + mapTokenToNamespace( XML_NAMESPACE_CHART, XML_NP_CHART, XML_N_CHART ); + mapTokenToNamespace( XML_NAMESPACE_CHART_SO52, XML_NP_CHART, XML_N_CHART_OLD ); + mapTokenToNamespace( XML_NAMESPACE_CHART_OOO, XML_NP_CHART, XML_N_CHART_OOO ); + mapTokenToNamespace( XML_NAMESPACE_DR3D, XML_NP_DR3D, XML_N_DR3D ); + mapTokenToNamespace( XML_NAMESPACE_DR3D_OOO, XML_NP_DR3D, XML_N_DR3D_OOO ); + mapTokenToNamespace( XML_NAMESPACE_MATH, XML_NP_MATH, XML_N_MATH ); + mapTokenToNamespace( XML_NAMESPACE_VERSIONS_LIST, XML_NP_VERSIONS_LIST, XML_N_VERSIONS_LIST ); + mapTokenToNamespace( XML_NAMESPACE_FORM, XML_NP_FORM, XML_N_FORM ); + mapTokenToNamespace( XML_NAMESPACE_FORM_OOO, XML_NP_FORM, XML_N_FORM_OOO ); + mapTokenToNamespace( XML_NAMESPACE_SCRIPT, XML_NP_SCRIPT, XML_N_SCRIPT ); + mapTokenToNamespace( XML_NAMESPACE_SCRIPT_OOO, XML_NP_SCRIPT, XML_N_SCRIPT_OOO ); + mapTokenToNamespace( XML_NAMESPACE_BLOCKLIST, XML_NP_BLOCK_LIST, XML_N_BLOCK_LIST ); + mapTokenToNamespace( XML_NAMESPACE_CONFIG, XML_NP_CONFIG, XML_N_CONFIG ); + mapTokenToNamespace( XML_NAMESPACE_CONFIG_OOO, XML_NP_CONFIG, XML_N_CONFIG_OOO ); + mapTokenToNamespace( XML_NAMESPACE_OOO, XML_NP_OOO, XML_N_OOO ); + mapTokenToNamespace( XML_NAMESPACE_OOOW, XML_NP_OOOW, XML_N_OOOW ); + mapTokenToNamespace( XML_NAMESPACE_OOOC, XML_NP_OOOC, XML_N_OOOC ); + mapTokenToNamespace( XML_NAMESPACE_DOM, XML_NP_DOM, XML_N_DOM ); + mapTokenToNamespace( XML_NAMESPACE_DB, XML_NP_DB, XML_N_DB ); + mapTokenToNamespace( XML_NAMESPACE_DB_OASIS, XML_NP_DB, XML_N_DB_OASIS ); + mapTokenToNamespace( XML_NAMESPACE_DLG, XML_NP_DLG, XML_N_DLG ); + mapTokenToNamespace( XML_NAMESPACE_XFORMS, XML_NP_XFORMS_1_0, XML_N_XFORMS_1_0 ); + mapTokenToNamespace( XML_NAMESPACE_XSD, XML_NP_XSD, XML_N_XSD ); + mapTokenToNamespace( XML_NAMESPACE_XSI, XML_NP_XSI, XML_N_XSI ); + mapTokenToNamespace( XML_NAMESPACE_SMIL, XML_NP_SMIL, XML_N_SMIL ); + mapTokenToNamespace( XML_NAMESPACE_SMIL_SO52, XML_NP_SMIL, XML_N_SMIL_OLD ); + mapTokenToNamespace( XML_NAMESPACE_SMIL_COMPAT, XML_NP_SMIL, XML_N_SMIL_COMPAT ); + mapTokenToNamespace( XML_NAMESPACE_ANIMATION, XML_NP_ANIMATION, XML_N_ANIMATION ); + mapTokenToNamespace( XML_NAMESPACE_ANIMATION_OOO, XML_NP_ANIMATION, XML_N_ANIMATION_OOO ); + mapTokenToNamespace( XML_NAMESPACE_REPORT, XML_NP_RPT, XML_N_RPT ); + mapTokenToNamespace( XML_NAMESPACE_REPORT_OASIS, XML_NP_RPT, XML_N_RPT_OASIS ); + mapTokenToNamespace( XML_NAMESPACE_OF, XML_NP_OF, XML_N_OF ); + mapTokenToNamespace( XML_NAMESPACE_XHTML, XML_NP_XHTML, XML_N_XHTML ); + mapTokenToNamespace( XML_NAMESPACE_GRDDL, XML_NP_GRDDL, XML_N_GRDDL ); + mapTokenToNamespace( XML_NAMESPACE_OFFICE_EXT, XML_NP_OFFICE_EXT, XML_N_OFFICE_EXT ); + mapTokenToNamespace( XML_NAMESPACE_TABLE_EXT, XML_NP_TABLE_EXT, XML_N_TABLE_EXT ); + mapTokenToNamespace( XML_NAMESPACE_CHART_EXT, XML_NP_CHART_EXT, XML_N_CHART_EXT ); + mapTokenToNamespace( XML_NAMESPACE_DRAW_EXT, XML_NP_DRAW_EXT, XML_N_DRAW_EXT ); + mapTokenToNamespace( XML_NAMESPACE_CALC_EXT, XML_NP_CALC_EXT, XML_N_CALC_EXT ); + mapTokenToNamespace( XML_NAMESPACE_LO_EXT, XML_NP_LO_EXT, XML_N_LO_EXT ); + mapTokenToNamespace( XML_NAMESPACE_CSS3TEXT, XML_NP_CSS3TEXT, XML_N_CSS3TEXT ); + mapTokenToNamespace( XML_NAMESPACE_FIELD, XML_NP_FIELD, XML_N_FIELD ); + mapTokenToNamespace( XML_NAMESPACE_FORMX, XML_NP_FORMX, XML_N_FORMX ); +} + +void SvXMLImport::registerNamespaces() +{ + for( auto const &aNamespaceEntry : aNamespaceMap ) + { + // aNamespaceMap = { Token : ( NamespacePrefix, NamespaceURI ) } + registerNamespace( aNamespaceEntry.second.second, aNamespaceEntry.first << NMSP_SHIFT ); + } +} + +void SvXMLImport::NotifyMacroEventRead() +{ + if (mbNotifyMacroEventRead) + return; + + comphelper::DocumentInfo::notifyMacroEventRead(mxModel); + + mbNotifyMacroEventRead = true; +} + +SvXMLImportFastNamespaceHandler::SvXMLImportFastNamespaceHandler() +{ +} + +void SvXMLImportFastNamespaceHandler::addNSDeclAttributes( rtl::Reference < comphelper::AttributeList > const & rAttrList ) +{ + for(const auto& aNamespaceDefine : m_aNamespaceDefines) + { + const OUString& rPrefix = aNamespaceDefine.m_aPrefix; + const OUString& rNamespaceURI = aNamespaceDefine.m_aNamespaceURI; + OUString sDecl; + if ( rPrefix.isEmpty() ) + sDecl = "xmlns"; + else + sDecl = "xmlns:" + rPrefix; + rAttrList->AddAttribute( sDecl, "CDATA", rNamespaceURI ); + } + m_aNamespaceDefines.clear(); +} + +void SvXMLImportFastNamespaceHandler::registerNamespace( const OUString& rNamespacePrefix, const OUString& rNamespaceURI ) +{ + // Elements with default namespace parsed by FastParser have namespace prefix. + // A default namespace needs to be registered with the prefix, to maintain the compatibility. + if ( rNamespacePrefix.isEmpty() ) + m_aNamespaceDefines.push_back( NamespaceDefine( + SvXMLImport::getNamespacePrefixFromURI( rNamespaceURI ), rNamespaceURI) ); + + m_aNamespaceDefines.push_back( NamespaceDefine( + rNamespacePrefix, rNamespaceURI) ); +} + +OUString SvXMLImportFastNamespaceHandler::getNamespaceURI( const OUString&/* rNamespacePrefix */ ) +{ + return OUString(); +} + +SvXMLLegacyToFastDocHandler::SvXMLLegacyToFastDocHandler( const rtl::Reference< SvXMLImport > & rImport ) +: mrImport( rImport ), + mxFastAttributes( new sax_fastparser::FastAttributeList( SvXMLImport::xTokenHandler.get() ) ) +{ +} + +void SAL_CALL SvXMLLegacyToFastDocHandler::setTargetDocument( const uno::Reference< lang::XComponent >& xDoc ) +{ + mrImport->setTargetDocument( xDoc ); +} + +void SAL_CALL SvXMLLegacyToFastDocHandler::startDocument() +{ + mrImport->startDocument(); +} + +void SAL_CALL SvXMLLegacyToFastDocHandler::endDocument() +{ + mrImport->endDocument(); +} + +void SAL_CALL SvXMLLegacyToFastDocHandler::startElement( const OUString& rName, + const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + sal_uInt16 nDefaultNamespace = XML_NAMESPACE_UNKNOWN; + if (!maDefaultNamespaces.empty()) + nDefaultNamespace = maDefaultNamespaces.top(); + SvXMLImport::processNSAttributes(mrImport->mxNamespaceMap, mrImport.get(), xAttrList); + OUString aLocalName; + sal_uInt16 nPrefix = mrImport->mxNamespaceMap->GetKeyByAttrName( rName, &aLocalName ); + sal_Int32 mnElement = NAMESPACE_TOKEN( nPrefix ) | SvXMLImport::getTokenFromName( aLocalName ); + mxFastAttributes->clear(); + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + if (rAttrName == "xmlns") + { + sal_uInt16 nNamespaceKey = mrImport->mxNamespaceMap->GetKeyByName(rAttrValue); + if (nNamespaceKey != XML_NAMESPACE_UNKNOWN) + { + nDefaultNamespace = nNamespaceKey; + continue; + } + assert(false && "unknown namespace"); + } + else if (rAttrName.indexOf(":") == -1 && nDefaultNamespace != XML_NAMESPACE_UNKNOWN) + { + auto const nToken = SvXMLImport::getTokenFromName(rAttrName); + if (nToken == xmloff::XML_TOKEN_INVALID) + { + mxFastAttributes->addUnknown(mrImport->mxNamespaceMap->GetNameByKey(nDefaultNamespace), + OUStringToOString(rAttrName, RTL_TEXTENCODING_UTF8), + OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8)); + } + else + { + sal_Int32 const nAttr = NAMESPACE_TOKEN(nDefaultNamespace) | nToken; + mxFastAttributes->add(nAttr, OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8)); + } + continue; + } + + OUString aLocalAttrName; + OUString aNamespace; + // don't add unknown namespaces to the map + sal_uInt16 const nAttrPrefix = mrImport->mxNamespaceMap->GetKeyByQName( + rAttrName, nullptr, &aLocalAttrName, &aNamespace, SvXMLNamespaceMap::QNameMode::AttrValue); + if( XML_NAMESPACE_XMLNS == nAttrPrefix ) + continue; // ignore + auto const nToken = SvXMLImport::getTokenFromName(aLocalAttrName); + if (XML_NAMESPACE_UNKNOWN == nAttrPrefix || nToken == xmloff::XML_TOKEN_INVALID) + { + mxFastAttributes->addUnknown(aNamespace, + OUStringToOString(rAttrName, RTL_TEXTENCODING_UTF8), + OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8)); + } + else + { + sal_Int32 const nAttr = NAMESPACE_TOKEN(nAttrPrefix) | nToken; + mxFastAttributes->add(nAttr, OUStringToOString(rAttrValue, RTL_TEXTENCODING_UTF8)); + } + } + mrImport->startFastElement( mnElement, mxFastAttributes ); + maDefaultNamespaces.push(nDefaultNamespace); +} + +void SAL_CALL SvXMLLegacyToFastDocHandler::endElement( const OUString& rName ) +{ + OUString aLocalName; + sal_uInt16 nPrefix = mrImport->mxNamespaceMap->GetKeyByAttrName( rName, &aLocalName ); + sal_Int32 mnElement = NAMESPACE_TOKEN( nPrefix ) | SvXMLImport::getTokenFromName(aLocalName); + mrImport->endFastElement( mnElement ); + maDefaultNamespaces.pop(); +} + +void SAL_CALL SvXMLLegacyToFastDocHandler::characters( const OUString& aChars ) +{ + mrImport->characters( aChars ); +} + +void SAL_CALL SvXMLLegacyToFastDocHandler::ignorableWhitespace( const OUString& ) +{ +} + +void SAL_CALL SvXMLLegacyToFastDocHandler::processingInstruction( const OUString& aTarget, + const OUString& aData) +{ + mrImport->processingInstruction( aTarget, aData ); +} + +void SAL_CALL SvXMLLegacyToFastDocHandler::setDocumentLocator( const uno::Reference< xml::sax::XLocator >& rLocator ) +{ + mrImport->setDocumentLocator( rLocator ); +} + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmlmultiimagehelper.cxx b/xmloff/source/core/xmlmultiimagehelper.cxx new file mode 100644 index 000000000..000c6151e --- /dev/null +++ b/xmloff/source/core/xmlmultiimagehelper.cxx @@ -0,0 +1,175 @@ +/* -*- 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 +#include +#include +#include + +using namespace ::com::sun::star; + +namespace +{ + OUString getMimeTypeForURL(std::u16string_view rString) + { + OUString sMimeType; + if (o3tl::starts_with(rString, u"vnd.sun.star.Package")) + { + OString aExtension = OUStringToOString(rString.substr(rString.rfind('.') + 1), RTL_TEXTENCODING_ASCII_US); + sMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForExtension(aExtension); + } + return sMimeType; + } + + sal_uInt32 getQualityIndex(std::u16string_view rMimeType) + { + // pixel formats first + if (rMimeType == u"image/bmp") + { + return 10; + } + if (rMimeType == u"image/gif") + { + return 20; + } + if (rMimeType == u"image/jpeg") + { + return 30; + } + if (rMimeType == u"image/png") + { + return 40; + } + + // vector formats, prefer always + if (rMimeType == u"image/x-vclgraphic") // MIMETYPE_VCLGRAPHIC + { + return 990; + } + if (rMimeType == u"image/x-svm") + { + return 1000; + } + if (rMimeType == u"image/x-wmf") + { + return 1010; + } + if (rMimeType == u"image/x-emf") + { + return 1020; + } + if (rMimeType == u"image/x-eps") + { + return 1025; + } + if (rMimeType == u"application/pdf") + { + return 1030; + } + if (rMimeType == u"image/svg+xml") + { + return 1040; + } + + return 0; + } +} + +MultiImageImportHelper::MultiImageImportHelper() +: mbSupportsMultipleContents(false) +{ +} + +MultiImageImportHelper::~MultiImageImportHelper() +{ +} + +SvXMLImportContextRef MultiImageImportHelper::solveMultipleImages() +{ + SvXMLImportContextRef pContext; + if(maImplContextVector.size() > 1) + { + // multiple child contexts were imported, decide which is the most valuable one + // and remove the rest + std::vector::size_type nIndexOfPreferred(maImplContextVector.size()); + sal_uInt32 nBestQuality(0); + + for(std::vector::size_type a = 0; a < maImplContextVector.size(); a++) + { + const SvXMLImportContext& rContext = *maImplContextVector[a]; + + + OUString sMimeType; + + const OUString aStreamURL(getGraphicPackageURLFromImportContext(rContext)); + if (!aStreamURL.isEmpty()) + { + sMimeType = getMimeTypeForURL(aStreamURL); + } + else + { + uno::Reference xGraphic(getGraphicFromImportContext(rContext)); + if (xGraphic.is()) + sMimeType = comphelper::GraphicMimeTypeHelper::GetMimeTypeForXGraphic(xGraphic); + } + + sal_uInt32 nNewQuality = getQualityIndex(sMimeType); + if (nNewQuality > nBestQuality) + { + nBestQuality = nNewQuality; + nIndexOfPreferred = a; + } + } + + // correct if needed, default is to use the last entry + if(nIndexOfPreferred >= maImplContextVector.size()) + { + nIndexOfPreferred = maImplContextVector.size() - 1; + } + + // Take out the most valuable one + const std::vector< SvXMLImportContextRef >::iterator aRemove(maImplContextVector.begin() + nIndexOfPreferred); + pContext = *aRemove; + maImplContextVector.erase(aRemove); + + // remove the rest from parent + for(std::vector::size_type a = 0; a < maImplContextVector.size(); a++) + { + SvXMLImportContext& rCandidate = *maImplContextVector[a]; + + removeGraphicFromImportContext(rCandidate); + } + // re-insert it so that solveMultipleImages is idempotent + maImplContextVector.clear(); + maImplContextVector.push_back(pContext); + } + else if (maImplContextVector.size() == 1) + { + pContext = maImplContextVector.front(); + } + + return pContext; +} + +void MultiImageImportHelper::addContent(const SvXMLImportContext& rSvXMLImportContext) +{ + maImplContextVector.emplace_back(const_cast< SvXMLImportContext* >(&rSvXMLImportContext)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmltkmap.cxx b/xmloff/source/core/xmltkmap.cxx new file mode 100644 index 000000000..5e95afc44 --- /dev/null +++ b/xmloff/source/core/xmltkmap.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/. + * + * 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 +#include +#include +#include + +#include +#include + +using namespace ::xmloff::token; + +class SvXMLTokenMap_Impl +{ +private: + struct PairHash + { + std::size_t operator()(const std::pair &pair) const + { + std::size_t seed = 0; + o3tl::hash_combine(seed, pair.first); + o3tl::hash_combine(seed, pair.second.hashCode()); + return seed; + } + }; + std::unordered_map< std::pair, + sal_uInt16, PairHash> m_aPrefixAndNameToTokenMap; + +public: + void insert( const SvXMLTokenMapEntry& rEntry ); + sal_uInt16 get( sal_uInt16 nKeyPrefix, const OUString& rLName ) const; +}; + +void SvXMLTokenMap_Impl::insert( const SvXMLTokenMapEntry& rEntry ) +{ + bool inserted = m_aPrefixAndNameToTokenMap.insert( std::make_pair( std::make_pair( rEntry.nPrefixKey, + GetXMLToken( rEntry.eLocalName ) ), rEntry.nToken ) ).second; + assert(inserted && "duplicate token"); + (void)inserted; +} + +sal_uInt16 SvXMLTokenMap_Impl::get( sal_uInt16 nKeyPrefix, const OUString& rLName ) const +{ + auto aIter( m_aPrefixAndNameToTokenMap.find( std::make_pair( nKeyPrefix, rLName ) ) ); + if ( aIter != m_aPrefixAndNameToTokenMap.end() ) + return (*aIter).second; + else + return XML_TOK_UNKNOWN; +} + +SvXMLTokenMap::SvXMLTokenMap( const SvXMLTokenMapEntry *pMap ) + : m_pImpl( new SvXMLTokenMap_Impl ) +{ + while( pMap->eLocalName != XML_TOKEN_INVALID ) + { + m_pImpl->insert( *pMap ); + pMap++; + } +} + +SvXMLTokenMap::~SvXMLTokenMap() +{ +} + +sal_uInt16 SvXMLTokenMap::Get( sal_uInt16 nKeyPrefix, + const OUString& rLName ) const +{ + return m_pImpl->get( nKeyPrefix, rLName ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx new file mode 100644 index 000000000..1606dbc68 --- /dev/null +++ b/xmloff/source/core/xmltoken.cxx @@ -0,0 +1,3611 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + + +namespace xmloff::token { + + // keep the tokens (and their length) + namespace + { + struct XMLTokenEntry + { + const char* pChar; + std::optional xOUString; + sal_Int32 nLength; +#if OSL_DEBUG_LEVEL > 0 + XMLTokenEnum eToken; +#endif +#if OSL_DEBUG_LEVEL > 0 + XMLTokenEntry(sal_Int32 nLen, const char* p, std::optional xStr, XMLTokenEnum eTok) + : pChar(p), xOUString(std::move(xStr)), nLength(nLen), eToken(eTok) {} +#else + XMLTokenEntry(sal_Int32 nLen, const char* p, std::optional xStr) + : pChar(p), xOUString(std::move(xStr)), nLength(nLen) {} +#endif + }; + } + + +#if OSL_DEBUG_LEVEL > 0 + #define TOKEN( s, e ) { sizeof(s)-1, s, std::nullopt, e } +#else + #define TOKEN( s, e ) { sizeof(s)-1, s, std::nullopt } +#endif + + // IMPORTANT! aTokenList order MUST be in synch with XMLTokenEnum in include/xmloff/xmltoken.hxx + // and with xmloff/source/token/tokens.txt. + + struct XMLTokenEntry aTokenList[] = + { +#if OSL_DEBUG_LEVEL > 0 + { 0, nullptr, std::nullopt, XML_TOKEN_START }, +#else + { 0, nullptr, std::nullopt }, // XML_TOKEN_START +#endif + + // common XML + TOKEN( "CDATA", XML_CDATA ), + TOKEN( " ", XML_WS ), + TOKEN( "xml", XML_XML ), + TOKEN( "xmlns", XML_XMLNS ), + TOKEN( "version=\"1.0\" encoding=\"UTF-8\"", XML_XML_PI ), + TOKEN( "", XML_XML_DOCTYPE_SUFFIX ), + + // namespace prefixes and names + TOKEN( "http://www.w3.org/XML/1998/namespace", XML_N_XML ), + TOKEN( "office", XML_NP_OFFICE ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:office:1.0", XML_N_OFFICE ), + TOKEN( "http://sun.com/xmlns/staroffice/office", XML_N_OFFICE_OLD ), + TOKEN( "meta", XML_NP_META ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:meta:1.0", XML_N_META ), + TOKEN( "http://sun.com/xmlns/staroffice/meta", XML_N_META_OLD ), + TOKEN( "style", XML_NP_STYLE ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:style:1.0", XML_N_STYLE ), + TOKEN( "http://sun.com/xmlns/staroffice/style", XML_N_STYLE_OLD ), + TOKEN( "number", XML_NP_NUMBER ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0", XML_N_NUMBER ), + TOKEN( "http://sun.com/xmlns/staroffice/number", XML_N_NUMBER_OLD ), + TOKEN( "text", XML_NP_TEXT ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:text:1.0", XML_N_TEXT ), + TOKEN( "http://sun.com/xmlns/staroffice/text", XML_N_TEXT_OLD ), + TOKEN( "table", XML_NP_TABLE ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:table:1.0", XML_N_TABLE ), + TOKEN( "http://sun.com/xmlns/staroffice/table", XML_N_TABLE_OLD ), + TOKEN( "draw", XML_NP_DRAW ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", XML_N_DRAW ), + TOKEN( "dr3d", XML_NP_DR3D ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0", XML_N_DR3D ), + TOKEN( "http://sun.com/xmlns/staroffice/draw", XML_N_DRAW_OLD ), + TOKEN( "presentation", XML_NP_PRESENTATION ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0", XML_N_PRESENTATION ), + TOKEN( "http://sun.com/xmlns/staroffice/presentation", XML_N_PRESENTATION_OLD ), + TOKEN( "chart", XML_NP_CHART ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:chart:1.0", XML_N_CHART ), + TOKEN( "config", XML_NP_CONFIG ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:config:1.0", XML_N_CONFIG ), + TOKEN( "http://sun.com/xmlns/staroffice/chart", XML_N_CHART_OLD ), + TOKEN( "fo", XML_NP_FO ), + TOKEN( "http://www.w3.org/1999/XSL/Format/", XML_N_FO_OLD ), + TOKEN( "http://www.w3.org/1999/XSL/Format", XML_N_FO ), + TOKEN( "xlink", XML_NP_XLINK ), + TOKEN( "http://www.w3.org/1999/xlink", XML_N_XLINK ), + TOKEN( "http://www.w3.org/1999/xlink/namespace", XML_N_XLINK_OLD ), + TOKEN( "dc", XML_NP_DC ), + TOKEN( "http://purl.org/dc/elements/1.1/", XML_N_DC ), + TOKEN( "svg", XML_NP_SVG ), + TOKEN( "http://www.w3.org/2000/svg", XML_N_SVG ), + TOKEN( "form", XML_NP_FORM ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:form:1.0", XML_N_FORM ), + TOKEN( "script", XML_NP_SCRIPT ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:script:1.0", XML_N_SCRIPT ), + TOKEN( "tcd", XML_NP_TCD ), + TOKEN( "http://openoffice.org/2003/text-conversion-dictionary", XML_N_TCD ), + TOKEN( "xforms", XML_NP_XFORMS_1_0 ), + TOKEN( "http://www.w3.org/2002/xforms", XML_N_XFORMS_1_0 ), + TOKEN( "xsd", XML_NP_XSD ), + TOKEN( "http://www.w3.org/2001/XMLSchema", XML_N_XSD ), + TOKEN( "xsi", XML_NP_XSI ), + TOKEN( "http://www.w3.org/2001/XMLSchema-instance", XML_N_XSI ), + + TOKEN( "block-list", XML_NP_BLOCK_LIST ), + TOKEN( "http://openoffice.org/2001/block-list", XML_N_BLOCK_LIST ), + + TOKEN( "math", XML_NP_MATH ), + TOKEN( "http://www.w3.org/1998/Math/MathML", XML_N_MATH ), + + TOKEN( "VL", XML_NP_VERSIONS_LIST ), + TOKEN( "http://openoffice.org/2001/versions-list", XML_N_VERSIONS_LIST ), + + // erAck: 2008-04-09T20:12+0200 OpenFormula aka ODFF + TOKEN( "of", XML_NP_OF ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:of:1.2", XML_N_OF ), + + // ODF 1.2 metadata: RDFa and GRDDL + TOKEN( "xhtml", XML_NP_XHTML ), + TOKEN( "http://www.w3.org/1999/xhtml", XML_N_XHTML ), + TOKEN( "grddl", XML_NP_GRDDL ), + TOKEN( "http://www.w3.org/2003/g/data-view#", XML_N_GRDDL ), + + // OOo extension digital signatures, used in ODF 1.1 + TOKEN( "dsigooo", XML_NP_DSIG_OOO ), + TOKEN( "http://openoffice.org/2004/documentsignatures", XML_N_DSIG_OOO ), + // ODF 1.2 digital signature namespaces + TOKEN( "dsig", XML_NP_DSIG ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0", XML_N_DSIG ), + TOKEN( "ds", XML_NP_DS ), + TOKEN( "http://www.w3.org/2000/09/xmldsig#", XML_N_DS ), + TOKEN( "xades132", XML_NP_XADES132 ), + TOKEN( "http://uri.etsi.org/01903/v1.3.2#", XML_N_XADES132 ), + TOKEN( "xades141", XML_NP_XADES141 ), + TOKEN( "http://uri.etsi.org/01903/v1.4.1#", XML_N_XADES141 ), + + // ODF Enhanced namespaces + TOKEN( "officeooo", XML_NP_OFFICE_EXT ), + TOKEN( "http://openoffice.org/2009/office", XML_N_OFFICE_EXT ), + + // jonp: 2008-09-24 Excel Interop + TOKEN( "formx", XML_NP_FORMX ), + TOKEN( "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0", XML_N_FORMX ), + TOKEN( "tableooo", XML_NP_TABLE_EXT ), + TOKEN( "http://openoffice.org/2009/table", XML_N_TABLE_EXT ), + + TOKEN( "drawooo", XML_NP_DRAW_EXT ), + TOKEN( "http://openoffice.org/2010/draw", XML_N_DRAW_EXT ), + + TOKEN( "css3t", XML_NP_CSS3TEXT ), + TOKEN( "http://www.w3.org/TR/css3-text/", XML_N_CSS3TEXT ), + + // extension namespace for calc extensions + TOKEN( "calcext", XML_NP_CALC_EXT ), + TOKEN( "urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0", XML_N_CALC_EXT ), + TOKEN( "loext", XML_NP_LO_EXT ), + TOKEN( "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0", XML_N_LO_EXT ), + + TOKEN( "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0", XML_N_FIELD ), + TOKEN( "field", XML_NP_FIELD ), + + // units + TOKEN( "m", XML_UNIT_M ), + TOKEN( "cm", XML_UNIT_CM ), + TOKEN( "pt", XML_UNIT_PT ), + TOKEN( "pc", XML_UNIT_PC ), + TOKEN( "ft", XML_UNIT_FOOT ), + + // any other + TOKEN( "1", XML_1 ), + TOKEN( "10", XML_10 ), + TOKEN( "2", XML_2 ), + TOKEN( "3", XML_3 ), + TOKEN( "4", XML_4 ), + TOKEN( "5", XML_5 ), + TOKEN( "6", XML_6 ), + TOKEN( "7", XML_7 ), + TOKEN( "8", XML_8 ), + TOKEN( "9", XML_9 ), + TOKEN( "A", XML_A_UPCASE ), + TOKEN( "I", XML_I_UPCASE ), + TOKEN( "IBM437", XML_IBM437 ), + TOKEN( "IBM850", XML_IBM850 ), + TOKEN( "IBM860", XML_IBM860 ), + TOKEN( "IBM861", XML_IBM861 ), + TOKEN( "IBM863", XML_IBM863 ), + TOKEN( "IBM865", XML_IBM865 ), + TOKEN( "ISO-8859-1", XML_ISO_8859_1 ), + TOKEN( "ole2", XML_OLE2 ), + TOKEN( ":", XML__COLON ), + TOKEN( "", XML__EMPTY ), + TOKEN( "_unknown_", XML__UNKNOWN_ ), + + TOKEN( "a", XML_A ), + TOKEN( "abbreviated-name", XML_ABBREVIATED_NAME ), + TOKEN( "above", XML_ABOVE ), + TOKEN( "abs", XML_ABS ), + TOKEN( "accent", XML_ACCENT ), + TOKEN( "accentunder", XML_ACCENTUNDER ), + TOKEN( "acceptance-state", XML_ACCEPTANCE_STATE ), + TOKEN( "accepted", XML_ACCEPTED ), + TOKEN( "action", XML_ACTION ), + TOKEN( "active", XML_ACTIVE ), + TOKEN( "active-split-range", XML_ACTIVE_SPLIT_RANGE ), + TOKEN( "active-table", XML_ACTIVE_TABLE ), + TOKEN( "actuate", XML_ACTUATE ), + TOKEN( "add-in", XML_ADD_IN ), + TOKEN( "add-in-name", XML_ADD_IN_NAME ), + TOKEN( "address", XML_ADDRESS ), + TOKEN( "adjustment", XML_ADJUSTMENT ), + TOKEN( "algorithm", XML_ALGORITHM ), + TOKEN( "align", XML_ALIGN ), + TOKEN( "all", XML_ALL ), + TOKEN( "allow-empty-cell", XML_ALLOW_EMPTY_CELL ), + TOKEN( "allow-deletes", XML_ALLOW_DELETES ), + TOKEN( "allow-inserts", XML_ALLOW_INSERTS ), + TOKEN( "allow-updates", XML_ALLOW_UPDATES ), + TOKEN( "alphabetical-index", XML_ALPHABETICAL_INDEX ), + TOKEN( "alphabetical-index-auto-mark-file", XML_ALPHABETICAL_INDEX_AUTO_MARK_FILE ), + TOKEN( "alphabetical-index-entry-template", XML_ALPHABETICAL_INDEX_ENTRY_TEMPLATE ), + TOKEN( "alphabetical-index-mark", XML_ALPHABETICAL_INDEX_MARK ), + TOKEN( "alphabetical-index-mark-end", XML_ALPHABETICAL_INDEX_MARK_END ), + TOKEN( "alphabetical-index-mark-start", XML_ALPHABETICAL_INDEX_MARK_START ), + TOKEN( "alphabetical-index-source", XML_ALPHABETICAL_INDEX_SOURCE ), + TOKEN( "alphabetical-separators", XML_ALPHABETICAL_SEPARATORS ), + TOKEN( "alternate", XML_ALTERNATE ), + TOKEN( "am-pm", XML_AM_PM ), + TOKEN( "ambient-color", XML_AMBIENT_COLOR ), + TOKEN( "anchor-page-number", XML_ANCHOR_PAGE_NUMBER ), + TOKEN( "anchor-type", XML_ANCHOR_TYPE ), + TOKEN( "and", XML_AND ), + TOKEN( "animation", XML_ANIMATION ), + TOKEN( "animation-delay", XML_ANIMATION_DELAY ), + TOKEN( "animation-direction", XML_ANIMATION_DIRECTION ), + TOKEN( "animation-repeat", XML_ANIMATION_REPEAT ), + TOKEN( "animation-start-inside", XML_ANIMATION_START_INSIDE ), + TOKEN( "animation-steps", XML_ANIMATION_STEPS ), + TOKEN( "animation-stop-inside", XML_ANIMATION_STOP_INSIDE ), + TOKEN( "animations", XML_ANIMATIONS ), + TOKEN( "annotation", XML_ANNOTATION ), + TOKEN( "annotation-end", XML_ANNOTATION_END ), + TOKEN( "annotations", XML_ANNOTATIONS ), + TOKEN( "annote", XML_ANNOTE ), + TOKEN( "appear", XML_APPEAR ), + TOKEN( "applet", XML_APPLET ), + TOKEN( "applet-name", XML_APPLET_NAME ), + TOKEN( "application-data", XML_APPLICATION_DATA ), + TOKEN( "application-xml", XML_APPLICATION_XML ), + TOKEN( "apply", XML_APPLY ), + TOKEN( "apply-design-mode", XML_APPLY_DESIGN_MODE ), + TOKEN( "apply-style-name", XML_APPLY_STYLE_NAME ), + TOKEN( "aqua", XML_AQUA ), + TOKEN( "arc", XML_ARC ), + TOKEN( "arccos", XML_ARCCOS ), + TOKEN( "archive", XML_ARCHIVE ), + TOKEN( "arcsin", XML_ARCSIN ), + TOKEN( "arctan", XML_ARCTAN ), + TOKEN( "area", XML_AREA ), + TOKEN( "area-circle", XML_AREA_CIRCLE ), + TOKEN( "area-polygon", XML_AREA_POLYGON ), + TOKEN( "area-rectangle", XML_AREA_RECTANGLE ), + TOKEN( "article", XML_ARTICLE ), + TOKEN( "as-char", XML_AS_CHAR ), + TOKEN( "ascending", XML_ASCENDING ), + TOKEN( "attached-axis", XML_ATTACHED_AXIS ), + TOKEN( "attractive", XML_ATTRACTIVE ), + TOKEN( "author", XML_AUTHOR ), + TOKEN( "author-initials", XML_AUTHOR_INITIALS ), + TOKEN( "author-name", XML_AUTHOR_NAME ), + TOKEN( "auto", XML_AUTO ), + TOKEN( "auto-complete", XML_AUTO_COMPLETE ), + TOKEN( "auto-grow-height", XML_AUTO_GROW_HEIGHT ), + TOKEN( "auto-grow-width", XML_AUTO_GROW_WIDTH ), + TOKEN( "auto-reload", XML_AUTO_RELOAD ), + TOKEN( "auto-text", XML_AUTO_TEXT ), + TOKEN( "auto-text-events", XML_AUTO_TEXT_EVENTS ), + TOKEN( "auto-text-group", XML_AUTO_TEXT_GROUP ), + TOKEN( "auto-text-indent", XML_AUTO_TEXT_INDENT ), + TOKEN( "auto-update", XML_AUTO_UPDATE ), + TOKEN( "automatic", XML_AUTOMATIC ), + TOKEN( "automatic-find-labels", XML_AUTOMATIC_FIND_LABELS ), + TOKEN( "automatic-focus", XML_AUTOMATIC_FOCUS ), + TOKEN( "automatic-order", XML_AUTOMATIC_ORDER ), + TOKEN( "automatic-styles", XML_AUTOMATIC_STYLES ), + TOKEN( "automatic-update", XML_AUTOMATIC_UPDATE ), + TOKEN( "autosize", XML_AUTOSIZE ), + TOKEN( "average", XML_AVERAGE ), + TOKEN( "averaged-abscissa", XML_AVERAGED_ABSCISSA ), + TOKEN( "axis", XML_AXIS ), + TOKEN( "axis-color", XML_AXIS_COLOR ), + TOKEN( "back-scale", XML_BACK_SCALE ), + TOKEN( "backface-culling", XML_BACKFACE_CULLING ), + TOKEN( "background", XML_BACKGROUND ), + TOKEN( "background-color", XML_BACKGROUND_COLOR ), + TOKEN( "background-image", XML_BACKGROUND_IMAGE ), + TOKEN( "no-repeat", XML_BACKGROUND_NO_REPEAT ), + TOKEN( "bar", XML_BAR ), + TOKEN( "base64Binary", XML_BASE64BINARY ), + TOKEN( "base-cell-address", XML_BASE_CELL_ADDRESS ), + TOKEN( "baseline", XML_BASELINE ), + TOKEN( "before-date-time", XML_BEFORE_DATE_TIME ), + TOKEN( "below", XML_BELOW ), + TOKEN( "between-date-times", XML_BETWEEN_DATE_TIMES ), + TOKEN( "bevel", XML_BEVEL ), + TOKEN( "bevelled", XML_BEVELLED ), + TOKEN( "bibiliographic-type", XML_BIBILIOGRAPHIC_TYPE ), + TOKEN( "bibliography", XML_BIBLIOGRAPHY ), + TOKEN( "bibliography-configuration", XML_BIBLIOGRAPHY_CONFIGURATION ), + TOKEN( "bibliography-data-field", XML_BIBLIOGRAPHY_DATA_FIELD ), + TOKEN( "bibliography-entry-template", XML_BIBLIOGRAPHY_ENTRY_TEMPLATE ), + TOKEN( "bibliography-mark", XML_BIBLIOGRAPHY_MARK ), + TOKEN( "bibliography-source", XML_BIBLIOGRAPHY_SOURCE ), + TOKEN( "bibliography-type", XML_BIBLIOGRAPHY_TYPE ), + TOKEN( "bind-styles-to-content", XML_BIND_STYLES_TO_CONTENT ), + TOKEN( "bitmap", XML_BITMAP ), + TOKEN( "bitmap-table", XML_BITMAP_TABLE ), + TOKEN( "black", XML_BLACK ), + TOKEN( "blend", XML_BLEND ), + TOKEN( "blinking", XML_BLINKING ), + TOKEN( "block", XML_BLOCK ), + TOKEN( "block-list", XML_BLOCK_LIST ), + TOKEN( "blue", XML_BLUE ), + TOKEN( "body", XML_BODY ), + TOKEN( "bold", XML_BOLD ), + TOKEN( "book", XML_BOOK ), + TOKEN( "booklet", XML_BOOKLET ), + TOKEN( "bookmark", XML_BOOKMARK ), + TOKEN( "bookmark-end", XML_BOOKMARK_END ), + TOKEN( "bookmark-ref", XML_BOOKMARK_REF ), + TOKEN( "bookmark-start", XML_BOOKMARK_START ), + TOKEN( "booktitle", XML_BOOKTITLE ), + TOKEN( "boolean", XML_BOOLEAN ), + TOKEN( "boolean-style", XML_BOOLEAN_STYLE ), + TOKEN( "boolean-value", XML_BOOLEAN_VALUE ), + TOKEN( "border", XML_BORDER ), + TOKEN( "border-bottom", XML_BORDER_BOTTOM ), + TOKEN( "border-color", XML_BORDER_COLOR ), + TOKEN( "border-left", XML_BORDER_LEFT ), + TOKEN( "border-line-width", XML_BORDER_LINE_WIDTH ), + TOKEN( "border-line-width-bottom", XML_BORDER_LINE_WIDTH_BOTTOM ), + TOKEN( "border-line-width-left", XML_BORDER_LINE_WIDTH_LEFT ), + TOKEN( "border-line-width-right", XML_BORDER_LINE_WIDTH_RIGHT ), + TOKEN( "border-line-width-top", XML_BORDER_LINE_WIDTH_TOP ), + TOKEN( "border-right", XML_BORDER_RIGHT ), + TOKEN( "border-top", XML_BORDER_TOP ), + TOKEN( "both", XML_BOTH ), + TOKEN( "bottom", XML_BOTTOM ), + TOKEN( "bottom-left", XML_BOTTOM_LEFT ), + TOKEN( "bottom percent", XML_BOTTOM_PERCENT ), + TOKEN( "bottom-right", XML_BOTTOM_RIGHT ), + TOKEN( "bottom values", XML_BOTTOM_VALUES ), + TOKEN( "bottom-arc", XML_BOTTOMARC ), + TOKEN( "bottom-circle", XML_BOTTOMCIRCLE ), + TOKEN( "bound-column", XML_BOUND_COLUMN ), + TOKEN( "break-after", XML_BREAK_AFTER ), + TOKEN( "break-before", XML_BREAK_BEFORE ), + TOKEN( "break-inside", XML_BREAK_INSIDE ), + TOKEN( "bubble", XML_BUBBLE ), + TOKEN( "bullet-char", XML_BULLET_CHAR ), + TOKEN( "bullet-relative-size", XML_BULLET_RELATIVE_SIZE ), + TOKEN( "butt", XML_BUTT ), + TOKEN( "button1", XML_BUTTON1 ), + TOKEN( "button2", XML_BUTTON2 ), + TOKEN( "button3", XML_BUTTON3 ), + TOKEN( "button4", XML_BUTTON4 ), + TOKEN( "buttons", XML_BUTTONS ), + TOKEN( "button-type", XML_BUTTON_TYPE ), + TOKEN( "bvar", XML_BVAR ), + TOKEN( "c", XML_C ), + TOKEN( "calculation-settings", XML_CALCULATION_SETTINGS ), + TOKEN( "calendar", XML_CALENDAR ), + TOKEN( "capitalize-entries", XML_CAPITALIZE_ENTRIES ), + TOKEN( "can-add-comment", XML_CAN_ADD_COMMENT ), + TOKEN( "caption", XML_CAPTION ), + TOKEN( "caption-point-x", XML_CAPTION_POINT_X ), + TOKEN( "caption-point-y", XML_CAPTION_POINT_Y ), + TOKEN( "caption-sequence-format", XML_CAPTION_SEQUENCE_FORMAT ), + TOKEN( "caption-sequence-name", XML_CAPTION_SEQUENCE_NAME ), + TOKEN( "case-sensitive", XML_CASE_SENSITIVE ), + TOKEN( "capitalize", XML_CASEMAP_CAPITALIZE ), + TOKEN( "lowercase", XML_CASEMAP_LOWERCASE ), + TOKEN( "small-caps", XML_CASEMAP_SMALL_CAPS ), + TOKEN( "uppercase", XML_CASEMAP_UPPERCASE ), + TOKEN( "categories", XML_CATEGORIES ), + TOKEN( "category", XML_CATEGORY ), + TOKEN( "category-and-value", XML_CATEGORY_AND_VALUE ), + TOKEN( "cell-address", XML_CELL_ADDRESS ), + TOKEN( "cell-content-change", XML_CELL_CONTENT_CHANGE ), + TOKEN( "cell-content-deletion", XML_CELL_CONTENT_DELETION ), + TOKEN( "cell-count", XML_CELL_COUNT ), + TOKEN( "cell-protect", XML_CELL_PROTECT ), + TOKEN( "cell-range-address", XML_CELL_RANGE_ADDRESS ), + TOKEN( "cell-range-address-list", XML_CELL_RANGE_ADDRESS_LIST ), + TOKEN( "cell-range-source", XML_CELL_RANGE_SOURCE ), + TOKEN( "center", XML_CENTER ), + TOKEN( "central", XML_CENTRAL ), + TOKEN( "chain-next-name", XML_CHAIN_NEXT_NAME ), + TOKEN( "change", XML_CHANGE ), + TOKEN( "change-deletion", XML_CHANGE_DELETION ), + TOKEN( "change-end", XML_CHANGE_END ), + TOKEN( "change-id", XML_CHANGE_ID ), + TOKEN( "change-info", XML_CHANGE_INFO ), + TOKEN( "change-start", XML_CHANGE_START ), + TOKEN( "change-track-table-cell", XML_CHANGE_TRACK_TABLE_CELL ), + TOKEN( "change-view-conditions", XML_CHANGE_VIEW_CONDITIONS ), + TOKEN( "change-view-settings", XML_CHANGE_VIEW_SETTINGS ), + TOKEN( "changed-region", XML_CHANGED_REGION ), + TOKEN( "chapter", XML_CHAPTER ), + TOKEN( "char", XML_CHAR ), + TOKEN( "char-shading-value", XML_CHAR_SHADING_VALUE ), + TOKEN( "character-count", XML_CHARACTER_COUNT ), + TOKEN( "chart", XML_CHART ), + TOKEN( "charts", XML_CHARTS ), + TOKEN( "checkerboard", XML_CHECKERBOARD ), + TOKEN( "chg-author", XML_CHG_AUTHOR ), + TOKEN( "chg-comment", XML_CHG_COMMENT ), + TOKEN( "chg-date-time", XML_CHG_DATE_TIME ), + TOKEN( "ci", XML_CI ), + TOKEN( "circle", XML_CIRCLE ), + TOKEN( "citation-body-style-name", XML_CITATION_BODY_STYLE_NAME ), + TOKEN( "citation-style-name", XML_CITATION_STYLE_NAME ), + TOKEN( "class", XML_CLASS ), + TOKEN( "class-id", XML_CLASS_ID ), + TOKEN( "clip", XML_CLIP ), + TOKEN( "clockwise", XML_CLOCKWISE ), + TOKEN( "close", XML_CLOSE ), + TOKEN( "close-horizontal", XML_CLOSE_HORIZONTAL ), + TOKEN( "close-vertical", XML_CLOSE_VERTICAL ), + TOKEN( "cn", XML_CN ), + TOKEN( "code", XML_CODE ), + TOKEN( "codebase", XML_CODEBASE ), + TOKEN( "collapse", XML_COLLAPSE ), + TOKEN( "color", XML_COLOR ), + TOKEN( "color-axis", XML_COLOR_AXIS ), + TOKEN( "color-first", XML_COLOR_FIRST ), + TOKEN( "color-high", XML_COLOR_HIGH ), + TOKEN( "color-inversion", XML_COLOR_INVERSION ), + TOKEN( "color-last", XML_COLOR_LAST ), + TOKEN( "color-low", XML_COLOR_LOW ), + TOKEN( "color-markers", XML_COLOR_MARKERS ), + TOKEN( "color-mode", XML_COLOR_MODE ), + TOKEN( "color-negative", XML_COLOR_NEGATIVE ), + TOKEN( "color-series", XML_COLOR_SERIES ), + TOKEN( "color-scale", XML_COLOR_SCALE ), + TOKEN( "color-scale-entry", XML_COLOR_SCALE_ENTRY ), + TOKEN( "color-table", XML_COLOR_TABLE ), + TOKEN( "column", XML_COLUMN ), + TOKEN( "column-count", XML_COLUMN_COUNT ), + TOKEN( "column-gap", XML_COLUMN_GAP ), + TOKEN( "column-name", XML_COLUMN_NAME ), + TOKEN( "column-sep", XML_COLUMN_SEP ), + TOKEN( "column-width", XML_COLUMN_WIDTH ), + TOKEN( "columnalign", XML_COLUMNALIGN ), + TOKEN( "columns", XML_COLUMNS ), + TOKEN( "avoid", XML_COLUMNSPLIT_AVOID ), + TOKEN( "combine-entries", XML_COMBINE_ENTRIES ), + TOKEN( "combine-entries-with-dash", XML_COMBINE_ENTRIES_WITH_DASH ), + TOKEN( "combine-entries-with-pp", XML_COMBINE_ENTRIES_WITH_PP ), + TOKEN( "comma-separated", XML_COMMA_SEPARATED ), + TOKEN( "command", XML_COMMAND ), + TOKEN( "comment", XML_COMMENT ), + TOKEN( "compose", XML_COMPOSE ), + TOKEN( "cond-style-name", XML_COND_STYLE_NAME ), + TOKEN( "condition", XML_CONDITION ), + TOKEN( "condition-source", XML_CONDITION_SOURCE ), + TOKEN( "condition-source-range-address", XML_CONDITION_SOURCE_RANGE_ADDRESS ), + TOKEN( "conditional-text", XML_CONDITIONAL_TEXT ), + TOKEN( "conditional-format", XML_CONDITIONAL_FORMAT ), + TOKEN( "conditional-formats", XML_CONDITIONAL_FORMATS ), + TOKEN( "cone", XML_CONE ), + TOKEN( "conference", XML_CONFERENCE ), + TOKEN( "config-item", XML_CONFIG_ITEM ), + TOKEN( "config-item-map-entry", XML_CONFIG_ITEM_MAP_ENTRY ), + TOKEN( "config-item-map-indexed", XML_CONFIG_ITEM_MAP_INDEXED ), + TOKEN( "config-item-map-named", XML_CONFIG_ITEM_MAP_NAMED ), + TOKEN( "config-item-set", XML_CONFIG_ITEM_SET ), + TOKEN( "configuration-settings", XML_CONFIGURATION_SETTINGS ), + TOKEN( "conjugate", XML_CONJUGATE ), + TOKEN( "connect-bars", XML_CONNECT_BARS ), + TOKEN( "connection-name", XML_CONNECTION_NAME ), + TOKEN( "connector", XML_CONNECTOR ), + TOKEN( "consecutive-numbering", XML_CONSECUTIVE_NUMBERING ), + TOKEN( "consolidation", XML_CONSOLIDATION ), + TOKEN( "constant", XML_CONSTANT ), + TOKEN( "contains-error", XML_CONTAINS_ERROR ), + TOKEN( "contains-header", XML_CONTAINS_HEADER ), + TOKEN( "content", XML_CONTENT ), + TOKEN( "content-validation", XML_CONTENT_VALIDATION ), + TOKEN( "content-validation-name", XML_CONTENT_VALIDATION_NAME ), + TOKEN( "content-validations", XML_CONTENT_VALIDATIONS ), + TOKEN( "contextual-spacing", XML_CONTEXTUAL_SPACING ), + TOKEN( "continue", XML_CONTINUE ), + TOKEN( "continue-numbering", XML_CONTINUE_NUMBERING ), + TOKEN( "contour-path", XML_CONTOUR_PATH ), + TOKEN( "contour-polygon", XML_CONTOUR_POLYGON ), + TOKEN( "contrast", XML_CONTRAST ), + TOKEN( "control", XML_CONTROL ), + TOKEN( "conversion-mode", XML_CONVERSION_MODE ), + TOKEN( "conversion-type", XML_CONVERSION_TYPE ), + TOKEN( "convert-empty-to-null", XML_CONVERT_EMPTY_TO_NULL ), + TOKEN( "copy-back", XML_COPY_BACK ), + TOKEN( "copy-formulas", XML_COPY_FORMULAS ), + TOKEN( "copy-outline-levels", XML_COPY_OUTLINE_LEVELS ), + TOKEN( "copy-results-only", XML_COPY_RESULTS_ONLY ), + TOKEN( "copy-styles", XML_COPY_STYLES ), + TOKEN( "corner-radius", XML_CORNER_RADIUS ), + TOKEN( "correct", XML_CORRECT ), + TOKEN( "cos", XML_COS ), + TOKEN( "cosh", XML_COSH ), + TOKEN( "cot", XML_COT ), + TOKEN( "coth", XML_COTH ), + TOKEN( "count", XML_COUNT ), + TOKEN( "count-empty-lines", XML_COUNT_EMPTY_LINES ), + TOKEN( "count-in-floating-frames", XML_COUNT_IN_FLOATING_FRAMES ), + TOKEN( "counter-clockwise", XML_COUNTER_CLOCKWISE ), + TOKEN( "counterclockwise", XML_COUNTERCLOCKWISE ), + TOKEN( "countnums", XML_COUNTNUMS ), + TOKEN( "country", XML_COUNTRY ), + TOKEN( "country-asian", XML_COUNTRY_ASIAN ), + TOKEN( "country-complex", XML_COUNTRY_COMPLEX ), + TOKEN( "covered-table-cell", XML_COVERED_TABLE_CELL ), + TOKEN( "create-date", XML_CREATE_DATE ), + TOKEN( "create-date-string", XML_CREATE_DATE_STRING ), + TOKEN( "creation-date", XML_CREATION_DATE ), + TOKEN( "creation-time", XML_CREATION_TIME ), + TOKEN( "creator", XML_CREATOR ), + TOKEN( "csc", XML_CSC ), + TOKEN( "csch", XML_CSCH ), + TOKEN( "cube", XML_CUBE ), + TOKEN( "cuboid", XML_CUBOID ), + TOKEN( "currency", XML_CURRENCY ), + TOKEN( "currency-style", XML_CURRENCY_STYLE ), + TOKEN( "currency-symbol", XML_CURRENCY_SYMBOL ), + TOKEN( "current", XML_CURRENT ), + TOKEN( "current-value", XML_CURRENT_VALUE ), + TOKEN( "cursor-position", XML_CURSOR_POSITION ), + TOKEN( "cursor-position-x", XML_CURSOR_POSITION_X ), + TOKEN( "cursor-position-y", XML_CURSOR_POSITION_Y ), + TOKEN( "curve", XML_CURVE ), + TOKEN( "custom1", XML_CUSTOM1 ), + TOKEN( "custom2", XML_CUSTOM2 ), + TOKEN( "custom3", XML_CUSTOM3 ), + TOKEN( "custom4", XML_CUSTOM4 ), + TOKEN( "custom5", XML_CUSTOM5 ), + TOKEN( "custom-iconset", XML_CUSTOM_ICONSET ), + TOKEN( "custom-iconset-index", XML_CUSTOM_ICONSET_INDEX ), + TOKEN( "custom-iconset-name", XML_CUSTOM_ICONSET_NAME ), + TOKEN( "custom-label-field", XML_CUSTOM_LABEL_FIELD ), + TOKEN( "custom-label-pos-x", XML_CUSTOM_LABEL_POS_X ), + TOKEN( "custom-label-pos-y", XML_CUSTOM_LABEL_POS_Y ), + TOKEN( "custom-leader-lines", XML_CUSTOM_LEADERLINES ), + TOKEN( "cut", XML_CUT ), + TOKEN( "cut-offs", XML_CUT_OFFS ), + TOKEN( "cut_offs", XML_CUT_OFFS2 ), + TOKEN( "cx", XML_CX ), + TOKEN( "cy", XML_CY ), + TOKEN( "cylinder", XML_CYLINDER ), + TOKEN( "d", XML_D ), + TOKEN( "dash", XML_DASH ), + TOKEN( "dash-dot", XML_DASH_DOT ), + TOKEN( "dash-dot-dot", XML_DASH_DOT_DOT ), + TOKEN( "dash-table", XML_DASH_TABLE ), + TOKEN( "dashed", XML_DASHED ), + TOKEN( "data", XML_DATA ), + TOKEN( "data-bar", XML_DATA_BAR ), + TOKEN( "data-bar-entry", XML_DATA_BAR_ENTRY ), + TOKEN( "data-cell-range-address", XML_DATA_CELL_RANGE_ADDRESS ), + TOKEN( "data-label", XML_DATA_LABEL ), + TOKEN( "data-label-guid", XML_DATA_LABEL_GUID ), + TOKEN( "data-label-number", XML_DATA_LABEL_NUMBER ), + TOKEN( "data-label-symbol", XML_DATA_LABEL_SYMBOL ), + TOKEN( "data-label-text", XML_DATA_LABEL_TEXT ), + TOKEN( "data-label-series", XML_DATA_LABEL_SERIES ), + TOKEN( "data-labels-cell-range", XML_DATA_LABELS_CELL_RANGE ), + TOKEN( "data-pilot-source", XML_DATA_PILOT_SOURCE ), + TOKEN( "data-pilot-field", XML_DATA_PILOT_FIELD ), + TOKEN( "data-pilot-grand-total", XML_DATA_PILOT_GRAND_TOTAL ), + TOKEN( "data-pilot-level", XML_DATA_PILOT_LEVEL ), + TOKEN( "data-pilot-member", XML_DATA_PILOT_MEMBER ), + TOKEN( "data-pilot-members", XML_DATA_PILOT_MEMBERS ), + TOKEN( "data-pilot-subtotal", XML_DATA_PILOT_SUBTOTAL ), + TOKEN( "data-pilot-subtotals", XML_DATA_PILOT_SUBTOTALS ), + TOKEN( "data-pilot-table", XML_DATA_PILOT_TABLE ), + TOKEN( "data-pilot-tables", XML_DATA_PILOT_TABLES ), + TOKEN( "data-point", XML_DATA_POINT ), + TOKEN( "data-range", XML_DATA_RANGE ), + TOKEN( "data-stream-source", XML_DATA_STREAM_SOURCE ), + TOKEN( "data-style", XML_DATA_STYLE ), + TOKEN( "data-style-name", XML_DATA_STYLE_NAME ), + TOKEN( "data-type", XML_DATA_TYPE ), + TOKEN( "database-display", XML_DATABASE_DISPLAY ), + TOKEN( "database-name", XML_DATABASE_NAME ), + TOKEN( "database-next", XML_DATABASE_NEXT ), + TOKEN( "database-range", XML_DATABASE_RANGE ), + TOKEN( "database-ranges", XML_DATABASE_RANGES ), + TOKEN( "database-row-number", XML_DATABASE_ROW_NUMBER ), + TOKEN( "database-select", XML_DATABASE_SELECT ), + TOKEN( "database-source-query", XML_DATABASE_SOURCE_QUERY ), + TOKEN( "database-source-sql", XML_DATABASE_SOURCE_SQL ), + TOKEN( "database-source-table", XML_DATABASE_SOURCE_TABLE ), + TOKEN( "database-table-name", XML_DATABASE_TABLE_NAME ), + TOKEN( "date", XML_DATE ), + TOKEN( "date-axis", XML_DATE_AXIS ), + TOKEN( "date-is", XML_DATE_IS ), + TOKEN( "date-adjust", XML_DATE_ADJUST ), + TOKEN( "date-style", XML_DATE_STYLE ), + TOKEN( "date-time", XML_DATE_TIME ), + TOKEN( "date-time-update", XML_DATE_TIME_UPDATE ), + TOKEN( "date-time-visible", XML_DATE_TIME_VISIBLE ), + TOKEN( "date-value", XML_DATE_VALUE ), + TOKEN( "datetime", XML_DATETIME ), + TOKEN( "day", XML_DAY ), + TOKEN( "day-of-week", XML_DAY_OF_WEEK ), + TOKEN( "dde-application", XML_DDE_APPLICATION ), + TOKEN( "dde-connection", XML_DDE_CONNECTION ), + TOKEN( "dde-connection-decl", XML_DDE_CONNECTION_DECL ), + TOKEN( "dde-connection-decls", XML_DDE_CONNECTION_DECLS ), + TOKEN( "dde-item", XML_DDE_ITEM ), + TOKEN( "dde-link", XML_DDE_LINK ), + TOKEN( "dde-links", XML_DDE_LINKS ), + TOKEN( "dde-source", XML_DDE_SOURCE ), + TOKEN( "dde-topic", XML_DDE_TOPIC ), + TOKEN( "decimal-places", XML_DECIMAL_PLACES ), + TOKEN( "decimal-replacement", XML_DECIMAL_REPLACEMENT ), + TOKEN( "declare", XML_DECLARE ), + TOKEN( "decorate-words-only", XML_DECORATE_WORDS_ONLY ), + TOKEN( "decorative", XML_DECORATIVE ), + TOKEN( "deep", XML_DEEP ), + TOKEN( "default", XML_DEFAULT ), + TOKEN( "default-button", XML_DEFAULT_BUTTON ), + TOKEN( "default-cell-style-name", XML_DEFAULT_CELL_STYLE_NAME ), + TOKEN( "default-style", XML_DEFAULT_STYLE ), + TOKEN( "default-style-name", XML_DEFAULT_STYLE_NAME ), + TOKEN( "degree", XML_DEGREE ), + TOKEN( "delay", XML_DELAY ), + TOKEN( "delay-for-repeat", XML_DELAY_FOR_REPEAT ), + TOKEN( "delete-columns", XML_DELETE_COLUMNS ), + TOKEN( "delete-rows", XML_DELETE_ROWS ), + TOKEN( "deletion", XML_DELETION ), + TOKEN( "deletions", XML_DELETIONS ), + TOKEN( "denomalign" , XML_DENOMALIGN ), + TOKEN( "denominator-value", XML_DENOMINATOR_VALUE ), + TOKEN( "dependence", XML_DEPENDENCE ), + TOKEN( "dependences", XML_DEPENDENCES ), + TOKEN( "dependencies", XML_DEPENDENCIES ), + TOKEN( "depth", XML_DEPTH ), + TOKEN( "desc", XML_DESC ), + TOKEN( "descending", XML_DESCENDING ), + TOKEN( "description", XML_DESCRIPTION ), + TOKEN( "detective", XML_DETECTIVE ), + TOKEN( "determinant", XML_DETERMINANT ), + TOKEN( "diff", XML_DIFF ), + TOKEN( "diffuse-color", XML_DIFFUSE_COLOR ), + TOKEN( "dim", XML_DIM ), + TOKEN( "direction", XML_DIRECTION ), + TOKEN( "disabled", XML_DISABLED ), + TOKEN( "disc", XML_DISC ), + TOKEN( "display", XML_DISPLAY ), + TOKEN( "display-border", XML_DISPLAY_BORDER ), + TOKEN( "display-details", XML_DISPLAY_DETAILS ), + TOKEN( "display-duplicates", XML_DISPLAY_DUPLICATES ), + TOKEN( "display-empty", XML_DISPLAY_EMPTY ), + TOKEN( "display-empty-cells-as", XML_DISPLAY_EMPTY_CELLS_AS ), + TOKEN( "display-filter-buttons", XML_DISPLAY_FILTER_BUTTONS ), + TOKEN( "display-formula", XML_DISPLAY_FORMULA ), + TOKEN( "display-hidden", XML_DISPLAY_HIDDEN ), + TOKEN( "display-label", XML_DISPLAY_LABEL ), + TOKEN( "display-levels", XML_DISPLAY_LEVELS ), + TOKEN( "display-name", XML_DISPLAY_NAME ), + TOKEN( "display-outline-level", XML_DISPLAY_OUTLINE_LEVEL ), + TOKEN( "display-x-axis", XML_DISPLAY_X_AXIS ), + TOKEN( "dissolve", XML_DISSOLVE ), + TOKEN( "distance", XML_DISTANCE ), + TOKEN( "distance-after-sep", XML_DISTANCE_AFTER_SEP ), + TOKEN( "distance-before-sep", XML_DISTANCE_BEFORE_SEP ), + TOKEN( "distribute", XML_DISTRIBUTE ), + TOKEN( "distribute-letter", XML_DISTRIBUTE_LETTER ), + TOKEN( "distribute-space", XML_DISTRIBUTE_SPACE ), + TOKEN( "divide", XML_DIVIDE ), + TOKEN( "document", XML_DOCUMENT ), + TOKEN( "document-content", XML_DOCUMENT_CONTENT ), + TOKEN( "document-meta", XML_DOCUMENT_META ), + TOKEN( "document-settings", XML_DOCUMENT_SETTINGS ), + TOKEN( "document-statistic", XML_DOCUMENT_STATISTIC ), + TOKEN( "document-styles", XML_DOCUMENT_STYLES ), + TOKEN( "domain", XML_DOMAIN ), + TOKEN( "dot", XML_DOT ), + TOKEN( "dots1", XML_DOTS1 ), + TOKEN( "dots1-length", XML_DOTS1_LENGTH ), + TOKEN( "dots2", XML_DOTS2 ), + TOKEN( "dots2-length", XML_DOTS2_LENGTH ), + TOKEN( "dotted", XML_DOTTED ), + TOKEN( "double", XML_DOUBLE ), + TOKEN( "double-sided", XML_DOUBLE_SIDED ), + TOKEN( "double-thin", XML_DOUBLE_THIN ), + TOKEN( "down", XML_DOWN ), + TOKEN( "draft", XML_DRAFT ), + TOKEN( "draw", XML_DRAW ), + TOKEN( "ole-draw-aspect", XML_DRAW_ASPECT ), + TOKEN( "drawing", XML_DRAWING ), + TOKEN( "drawings", XML_DRAWINGS ), + TOKEN( "drawpool", XML_DRAWPOOL ), + TOKEN( "dropdown", XML_DROPDOWN ), + TOKEN( "drop-cap", XML_DROP_CAP ), + TOKEN( "dynamic", XML_DYNAMIC ), + TOKEN( "echo-char", XML_ECHO_CHAR ), + TOKEN( "edge-rounding", XML_EDGE_ROUNDING ), + TOKEN( "editable", XML_EDITABLE ), + TOKEN( "editing-cycles", XML_EDITING_CYCLES ), + TOKEN( "editing-duration", XML_EDITING_DURATION ), + TOKEN( "edition", XML_EDITION ), + TOKEN( "editor", XML_EDITOR ), + TOKEN( "effect", XML_EFFECT ), + TOKEN( "ellipse", XML_ELLIPSE ), + TOKEN( "email", XML_EMAIL ), + TOKEN( "embed", XML_EMBED ), + TOKEN( "embedded-visible-area", XML_EMBEDDED_VISIBLE_AREA ), + TOKEN( "embossed", XML_EMBOSSED ), + TOKEN( "emissive-color", XML_EMISSIVE_COLOR ), + TOKEN( "empty", XML_EMPTY ), + TOKEN( "empty-line-refresh", XML_EMPTY_LINE_REFRESH ), + TOKEN( "enable-numbering", XML_ENABLE_NUMBERING ), + TOKEN( "enabled", XML_ENABLED ), + TOKEN( "encoding", XML_ENCODING ), + TOKEN( "enctype", XML_ENCTYPE ), + TOKEN( "end", XML_END ), + TOKEN( "end-angle", XML_END_ANGLE ), + TOKEN( "end-cell-address", XML_END_CELL_ADDRESS ), + TOKEN( "end-color", XML_END_COLOR ), + TOKEN( "end-column", XML_END_COLUMN ), + TOKEN( "end-glue-point", XML_END_GLUE_POINT ), + TOKEN( "end-guide", XML_END_GUIDE ), + TOKEN( "end-intensity", XML_END_INTENSITY ), + TOKEN( "end-line-spacing-horizontal", XML_END_LINE_SPACING_HORIZONTAL ), + TOKEN( "end-line-spacing-vertical", XML_END_LINE_SPACING_VERTICAL ), + TOKEN( "end-position", XML_END_POSITION ), + TOKEN( "end-row", XML_END_ROW ), + TOKEN( "end-shape", XML_END_SHAPE ), + TOKEN( "end-table", XML_END_TABLE ), + TOKEN( "end-x", XML_END_X ), + TOKEN( "end-y", XML_END_Y ), + TOKEN( "endless", XML_ENDLESS ), + TOKEN( "endnote", XML_ENDNOTE ), + TOKEN( "endnote-body", XML_ENDNOTE_BODY ), + TOKEN( "endnote-citation", XML_ENDNOTE_CITATION ), + TOKEN( "endnote-ref", XML_ENDNOTE_REF ), + TOKEN( "endnotes-configuration", XML_ENDNOTES_CONFIGURATION ), + TOKEN( "engraved", XML_ENGRAVED ), + TOKEN( "entry", XML_ENTRY ), + TOKEN( "eq", XML_EQ ), + TOKEN( "equal-author", XML_EQUAL_AUTHOR ), + TOKEN( "equal-comment", XML_EQUAL_COMMENT ), + TOKEN( "equal-date", XML_EQUAL_DATE ), + TOKEN( "era", XML_ERA ), + TOKEN( "ergo-sum", XML_ERGO_SUM ), + TOKEN( "error-category", XML_ERROR_CATEGORY ), + TOKEN( "error-lower-indicator", XML_ERROR_LOWER_INDICATOR ), + TOKEN( "error-lower-limit", XML_ERROR_LOWER_LIMIT ), + TOKEN( "error-macro", XML_ERROR_MACRO ), + TOKEN( "error-margin", XML_ERROR_MARGIN ), + TOKEN( "error-message", XML_ERROR_MESSAGE ), + TOKEN( "error-percentage", XML_ERROR_PERCENTAGE ), + TOKEN( "error-upper-indicator", XML_ERROR_UPPER_INDICATOR ), + TOKEN( "error-upper-limit", XML_ERROR_UPPER_LIMIT ), + TOKEN( "sub", XML_ESCAPEMENT_SUB ), + TOKEN( "super", XML_ESCAPEMENT_SUPER ), + TOKEN( "even-page", XML_EVEN_PAGE ), + TOKEN( "event", XML_EVENT ), + TOKEN( "event-name", XML_EVENT_NAME ), + TOKEN( "events", XML_EVENTS ), + TOKEN( "execute", XML_EXECUTE ), + TOKEN( "execute-macro", XML_EXECUTE_MACRO ), + TOKEN( "exists", XML_EXISTS ), + TOKEN( "exp", XML_EXP ), + TOKEN( "exponential", XML_EXPONENTIAL ), + TOKEN( "expression", XML_EXPRESSION ), + TOKEN( "extra", XML_EXTRA ), + TOKEN( "extrude", XML_EXTRUDE ), + TOKEN( "factorial", XML_FACTORIAL ), + TOKEN( "fade", XML_FADE ), + TOKEN( "fade-from-bottom", XML_FADE_FROM_BOTTOM ), + TOKEN( "fade-from-center", XML_FADE_FROM_CENTER ), + TOKEN( "fade-from-left", XML_FADE_FROM_LEFT ), + TOKEN( "fade-from-lowerleft", XML_FADE_FROM_LOWERLEFT ), + TOKEN( "fade-from-lowerright", XML_FADE_FROM_LOWERRIGHT ), + TOKEN( "fade-from-right", XML_FADE_FROM_RIGHT ), + TOKEN( "fade-from-top", XML_FADE_FROM_TOP ), + TOKEN( "fade-from-upperleft", XML_FADE_FROM_UPPERLEFT ), + TOKEN( "fade-from-upperright", XML_FADE_FROM_UPPERRIGHT ), + TOKEN( "fade-out", XML_FADE_OUT ), + TOKEN( "fade-to-center", XML_FADE_TO_CENTER ), + TOKEN( "false", XML_FALSE ), + TOKEN( "family", XML_FAMILY ), + TOKEN( "fast", XML_FAST ), + TOKEN( "fence", XML_FENCE ), + TOKEN( "field-number", XML_FIELD_NUMBER ), + TOKEN( "file-name", XML_FILE_NAME ), + TOKEN( "fill", XML_FILL ), + TOKEN( "fill-character", XML_FILL_CHARACTER ), + TOKEN( "fill-color", XML_FILL_COLOR ), + TOKEN( "fill-gradient-name", XML_FILL_GRADIENT_NAME ), + TOKEN( "fill-hatch-name", XML_FILL_HATCH_NAME ), + TOKEN( "fill-hatch-solid", XML_FILL_HATCH_SOLID ), + TOKEN( "fill-image", XML_FILL_IMAGE ), + TOKEN( "fill-image-height", XML_FILL_IMAGE_HEIGHT ), + TOKEN( "fill-image-name", XML_FILL_IMAGE_NAME ), + TOKEN( "fill-image-ref-point", XML_FILL_IMAGE_REF_POINT ), + TOKEN( "fill-image-ref-point-x", XML_FILL_IMAGE_REF_POINT_X ), + TOKEN( "fill-image-ref-point-y", XML_FILL_IMAGE_REF_POINT_Y ), + TOKEN( "fill-image-width", XML_FILL_IMAGE_WIDTH ), + TOKEN( "fill-rule", XML_FILL_RULE ), + TOKEN( "filter", XML_FILTER ), + TOKEN( "filter-and", XML_FILTER_AND ), + TOKEN( "filter-condition", XML_FILTER_CONDITION ), + TOKEN( "filter-name", XML_FILTER_NAME ), + TOKEN( "filter-options", XML_FILTER_OPTIONS ), + TOKEN( "filter-or", XML_FILTER_OR ), + TOKEN( "filter-set-item", XML_FILTER_SET_ITEM ), + TOKEN( "fine-dashed", XML_FINE_DASHED ), + TOKEN( "first-date-time", XML_FIRST_DATE_TIME ), + TOKEN( "first-page", XML_FIRST_PAGE ), + TOKEN( "first-page-number", XML_FIRST_PAGE_NUMBER ), + TOKEN( "fit-to-contour", XML_FIT_TO_CONTOUR ), + TOKEN( "fit-to-size", XML_FIT_TO_SIZE ), + TOKEN( "fix", XML_FIX ), + TOKEN( "fixed", XML_FIXED ), + TOKEN( "flat", XML_FLAT ), + TOKEN( "float", XML_FLOAT ), + TOKEN( "floating-frame", XML_FLOATING_FRAME ), + TOKEN( "floor", XML_FLOOR ), + TOKEN( "fn", XML_FN ), + TOKEN( "focal-length", XML_FOCAL_LENGTH ), + TOKEN( "focus-on-click", XML_FOCUS_ON_CLICK ), + TOKEN( "font-char-width", XML_FONT_CHAR_WIDTH ), + TOKEN( "font-charset", XML_FONT_CHARSET ), + TOKEN( "font-charset-asian", XML_FONT_CHARSET_ASIAN ), + TOKEN( "font-charset-complex", XML_FONT_CHARSET_COMPLEX ), + TOKEN( "font-color", XML_FONT_COLOR ), + TOKEN( "font-decl", XML_FONT_DECL ), + TOKEN( "font-decls", XML_FONT_DECLS ), + TOKEN( "font-family", XML_FONT_FAMILY ), + TOKEN( "font-family-asian", XML_FONT_FAMILY_ASIAN ), + TOKEN( "font-family-complex", XML_FONT_FAMILY_COMPLEX ), + TOKEN( "font-family-generic", XML_FONT_FAMILY_GENERIC ), + TOKEN( "font-family-generic-asian", XML_FONT_FAMILY_GENERIC_ASIAN ), + TOKEN( "font-family-generic-complex", XML_FONT_FAMILY_GENERIC_COMPLEX ), + TOKEN( "font-kerning", XML_FONT_KERNING ), + TOKEN( "font-name", XML_FONT_NAME ), + TOKEN( "font-name-asian", XML_FONT_NAME_ASIAN ), + TOKEN( "font-name-complex", XML_FONT_NAME_COMPLEX ), + TOKEN( "font-pitch", XML_FONT_PITCH ), + TOKEN( "font-pitch-asian", XML_FONT_PITCH_ASIAN ), + TOKEN( "font-pitch-complex", XML_FONT_PITCH_COMPLEX ), + TOKEN( "font-relief", XML_FONT_RELIEF ), + TOKEN( "font-size", XML_FONT_SIZE ), + TOKEN( "font-size-asian", XML_FONT_SIZE_ASIAN ), + TOKEN( "font-size-complex", XML_FONT_SIZE_COMPLEX ), + TOKEN( "font-size-rel", XML_FONT_SIZE_REL ), + TOKEN( "font-size-rel-asian", XML_FONT_SIZE_REL_ASIAN ), + TOKEN( "font-size-rel-complex", XML_FONT_SIZE_REL_COMPLEX ), + TOKEN( "font-style", XML_FONT_STYLE ), + TOKEN( "font-style-asian", XML_FONT_STYLE_ASIAN ), + TOKEN( "font-style-complex", XML_FONT_STYLE_COMPLEX ), + TOKEN( "font-style-name", XML_FONT_STYLE_NAME ), + TOKEN( "font-style-name-asian", XML_FONT_STYLE_NAME_ASIAN ), + TOKEN( "font-style-name-complex", XML_FONT_STYLE_NAME_COMPLEX ), + TOKEN( "font-variant", XML_FONT_VARIANT ), + TOKEN( "font-weight", XML_FONT_WEIGHT ), + TOKEN( "font-weight-asian", XML_FONT_WEIGHT_ASIAN ), + TOKEN( "font-weight-complex", XML_FONT_WEIGHT_COMPLEX ), + TOKEN( "font-width", XML_FONT_WIDTH ), + TOKEN( "font-word-line-mode", XML_FONT_WORD_LINE_MODE ), + TOKEN( "fontfamily", XML_FONTFAMILY ), + TOKEN( "fontsize", XML_FONTSIZE ), + TOKEN( "fontstyle", XML_FONTSTYLE ), + TOKEN( "fontweight", XML_FONTWEIGHT ), + TOKEN( "fontwork-adjust", XML_FONTWORK_ADJUST ), + TOKEN( "fontwork-distance", XML_FONTWORK_DISTANCE ), + TOKEN( "fontwork-form", XML_FONTWORK_FORM ), + TOKEN( "fontwork-hide-form", XML_FONTWORK_HIDE_FORM ), + TOKEN( "fontwork-mirror", XML_FONTWORK_MIRROR ), + TOKEN( "fontwork-outline", XML_FONTWORK_OUTLINE ), + TOKEN( "fontwork-shadow", XML_FONTWORK_SHADOW ), + TOKEN( "fontwork-shadow-color", XML_FONTWORK_SHADOW_COLOR ), + TOKEN( "fontwork-shadow-offset-x", XML_FONTWORK_SHADOW_OFFSET_X ), + TOKEN( "fontwork-shadow-offset-y", XML_FONTWORK_SHADOW_OFFSET_Y ), + TOKEN( "fontwork-shadow-transparence", XML_FONTWORK_SHADOW_TRANSPARENCE ), + TOKEN( "fontwork-start", XML_FONTWORK_START ), + TOKEN( "fontwork-style", XML_FONTWORK_STYLE ), + TOKEN( "footer", XML_FOOTER ), + TOKEN( "footer-first", XML_FOOTER_FIRST ), + TOKEN( "footer-left", XML_FOOTER_LEFT ), + TOKEN( "footer-style", XML_FOOTER_STYLE ), + TOKEN( "footer-visible", XML_FOOTER_VISIBLE ), + TOKEN( "footnote", XML_FOOTNOTE ), + TOKEN( "footnote-body", XML_FOOTNOTE_BODY ), + TOKEN( "footnote-citation", XML_FOOTNOTE_CITATION ), + TOKEN( "footnote-continuation-notice-backward", XML_FOOTNOTE_CONTINUATION_NOTICE_BACKWARD ), + TOKEN( "footnote-continuation-notice-forward", XML_FOOTNOTE_CONTINUATION_NOTICE_FORWARD ), + TOKEN( "footnote-max-height", XML_FOOTNOTE_MAX_HEIGHT ), + TOKEN( "footnote-ref", XML_FOOTNOTE_REF ), + TOKEN( "footnote-sep", XML_FOOTNOTE_SEP ), + TOKEN( "footnotes-configuration", XML_FOOTNOTES_CONFIGURATION ), + TOKEN( "footnotes-position", XML_FOOTNOTES_POSITION ), + TOKEN( "for", XML_FOR ), + TOKEN( "forall", XML_FORALL ), + TOKEN( "force-manual", XML_FORCE_MANUAL ), + TOKEN( "foreground", XML_FOREGROUND ), + TOKEN( "foreign-object", XML_FOREIGN_OBJECT ), + TOKEN( "format-change", XML_FORMAT_CHANGE ), + TOKEN( "format-source", XML_FORMAT_SOURCE ), + TOKEN( "formatting-entry", XML_FORMATTING_ENTRY ), + TOKEN( "forms", XML_FORMS ), + TOKEN( "formula", XML_FORMULA ), + TOKEN( "formula-hidden", XML_FORMULA_HIDDEN ), + TOKEN( "formulas", XML_FORMULAS ), + TOKEN( "fraction", XML_FRACTION ), + TOKEN( "frame", XML_FRAME ), + TOKEN( "frame-content", XML_FRAME_CONTENT ), + TOKEN( "frame-display-border", XML_FRAME_DISPLAY_BORDER ), + TOKEN( "frame-display-scrollbar", XML_FRAME_DISPLAY_SCROLLBAR ), + TOKEN( "frame-end-margin", XML_FRAME_END_MARGIN ), + TOKEN( "frame-margin-horizontal", XML_FRAME_MARGIN_HORIZONTAL ), + TOKEN( "frame-margin-vertical", XML_FRAME_MARGIN_VERTICAL ), + TOKEN( "frame-name", XML_FRAME_NAME ), + TOKEN( "frame-start-margin", XML_FRAME_START_MARGIN ), + TOKEN( "freeze", XML_FREEZE ), + TOKEN( "freeze-position", XML_FREEZE_POSITION ), + TOKEN( "from-another-table", XML_FROM_ANOTHER_TABLE ), + TOKEN( "from-bottom", XML_FROM_BOTTOM ), + TOKEN( "from-center", XML_FROM_CENTER ), + TOKEN( "from-inside", XML_FROM_INSIDE ), + TOKEN( "from-left", XML_FROM_LEFT ), + TOKEN( "from-lower-left", XML_FROM_LOWER_LEFT ), + TOKEN( "from-lower-right", XML_FROM_LOWER_RIGHT ), + TOKEN( "from-right", XML_FROM_RIGHT ), + TOKEN( "from-same-table", XML_FROM_SAME_TABLE ), + TOKEN( "from-top", XML_FROM_TOP ), + TOKEN( "from-upper-left", XML_FROM_UPPER_LEFT ), + TOKEN( "from-upper-right", XML_FROM_UPPER_RIGHT ), + TOKEN( "fuchsia", XML_FUCHSIA ), + TOKEN( "full", XML_FULL ), + TOKEN( "full-screen", XML_FULL_SCREEN ), + TOKEN( "function", XML_FUNCTION ), + TOKEN( "fx", XML_FX ), + TOKEN( "fy", XML_FY ), + TOKEN( "g", XML_G ), + TOKEN( "gamma", XML_GAMMA ), + TOKEN( "gap", XML_GAP ), + TOKEN( "gap-width", XML_GAP_WIDTH ), + TOKEN( "gcd", XML_GCD ), + TOKEN( "generator", XML_GENERATOR ), + TOKEN( "geq", XML_GEQ ), + TOKEN( "glow-radius", XML_GLOW_RADIUS ), + TOKEN( "glow-color", XML_GLOW_COLOR ), + TOKEN( "glow-transparency", XML_GLOW_TRANSPARENCY ), + TOKEN( "gouraud", XML_GOURAUD ), + TOKEN( "gradient", XML_GRADIENT ), + TOKEN( "angle", XML_GRADIENT_ANGLE ), + TOKEN( "gradient-step-count", XML_GRADIENT_STEP_COUNT ), + TOKEN( "gradient-style", XML_GRADIENT_STYLE ), + TOKEN( "gradient-table", XML_GRADIENT_TABLE ), + TOKEN( "axial", XML_GRADIENTSTYLE_AXIAL ), + TOKEN( "ellipsoid", XML_GRADIENTSTYLE_ELLIPSOID ), + TOKEN( "radial", XML_GRADIENTSTYLE_RADIAL ), + TOKEN( "rectangular", XML_GRADIENTSTYLE_RECTANGULAR ), + TOKEN( "square", XML_GRADIENTSTYLE_SQUARE ), + TOKEN( "gradientTransform", XML_GRADIENTTRANSFORM ), + TOKEN( "grand-total", XML_GRAND_TOTAL ), + TOKEN( "graphic", XML_GRAPHIC ), + TOKEN( "gray", XML_GRAY ), + TOKEN( "green", XML_GREEN ), + TOKEN( "greyscale", XML_GREYSCALE ), + TOKEN( "grid", XML_GRID ), + TOKEN( "groove", XML_GROOVE ), + TOKEN( "group-by-field-number", XML_GROUP_BY_FIELD_NUMBER ), + TOKEN( "group-name", XML_GROUP_NAME ), + TOKEN( "grouping", XML_GROUPING ), + TOKEN( "gt", XML_GT ), + TOKEN( "guide-distance", XML_GUIDE_DISTANCE ), + TOKEN( "guide-overhang", XML_GUIDE_OVERHANG ), + TOKEN( "h", XML_H ), + TOKEN( "hanging", XML_HANGING ), + TOKEN( "has-persistent-data", XML_HAS_PERSISTENT_DATA ), + TOKEN( "hatch", XML_HATCH ), + TOKEN( "hatch-table", XML_HATCH_TABLE ), + TOKEN( "triple", XML_HATCHSTYLE_TRIPLE ), + TOKEN( "header", XML_HEADER ), + TOKEN( "header-first", XML_HEADER_FIRST ), + TOKEN( "header-left", XML_HEADER_LEFT ), + TOKEN( "header-style", XML_HEADER_STYLE ), + TOKEN( "headers", XML_HEADERS ), + TOKEN( "height", XML_HEIGHT ), + TOKEN( "help", XML_HELP), + TOKEN( "help-file-name", XML_HELP_FILE_NAME ), + TOKEN( "help-id", XML_HELP_ID ), + TOKEN( "help-message", XML_HELP_MESSAGE ), + TOKEN( "hidden", XML_HIDDEN ), + TOKEN( "hidden-and-protected", XML_HIDDEN_AND_PROTECTED ), + TOKEN( "hidden-paragraph", XML_HIDDEN_PARAGRAPH ), + TOKEN( "hidden-text", XML_HIDDEN_TEXT ), + TOKEN( "hide", XML_HIDE ), + TOKEN( "hide-legend", XML_HIDE_LEGEND ), + TOKEN( "hide-shape", XML_HIDE_SHAPE ), + TOKEN( "hide-text", XML_HIDE_TEXT ), + TOKEN( "highlighted-range", XML_HIGHLIGHTED_RANGE ), + TOKEN( "hint", XML_HINT), + TOKEN( "horizontal", XML_HORIZONTAL ), + TOKEN( "horizontalstrike", XML_HORIZONTALSTRIKE ), + TOKEN( "horizontal-lines", XML_HORIZONTAL_LINES ), + /* XML_HORIZONTAL_ON_LEFT_PAGES and XML_HORIZONTAL_ON_RIGHT_PAGES + are replaced by XML_HORIZONTAL_ON_EVEN and XML_HORIZONTAL_ON_ODD. + Usage is deprecated, but the old token are needed for the + OpenOffice.org file format import/export filter for the renaming (#i49139#) + */ + TOKEN( "horizontal-on-left-pages", XML_HORIZONTAL_ON_LEFT_PAGES ), + TOKEN( "horizontal-on-right-pages", XML_HORIZONTAL_ON_RIGHT_PAGES ), + TOKEN( "horizontal-pos", XML_HORIZONTAL_POS ), + TOKEN( "horizontal-rel", XML_HORIZONTAL_REL ), + TOKEN( "horizontal-scrollbar-width", XML_HORIZONTAL_SCROLLBAR_WIDTH ), + TOKEN( "horizontal-segments", XML_HORIZONTAL_SEGMENTS ), + TOKEN( "horizontal-split-mode", XML_HORIZONTAL_SPLIT_MODE ), + TOKEN( "horizontal-split-position", XML_HORIZONTAL_SPLIT_POSITION ), + TOKEN( "horizontal-stripes", XML_HORIZONTAL_STRIPES ), + TOKEN( "hours", XML_HOURS ), + TOKEN( "howpublished", XML_HOWPUBLISHED ), + TOKEN( "href", XML_HREF ), + TOKEN( "html", XML_HTML ), + TOKEN( "hyperlink", XML_HYPERLINK ), + TOKEN( "hyperlink-behaviour", XML_HYPERLINK_BEHAVIOUR ), + TOKEN( "hyphenate", XML_HYPHENATE ), + TOKEN( "hyphenation-keep", XML_HYPHENATION_KEEP ), + TOKEN( "hyphenation-ladder-count", XML_HYPHENATION_LADDER_COUNT ), + TOKEN( "hyphenation-push-char-count", XML_HYPHENATION_PUSH_CHAR_COUNT ), + TOKEN( "hyphenation-remain-char-count", XML_HYPHENATION_REMAIN_CHAR_COUNT ), + TOKEN( "hyphenation-no-caps", XML_HYPHENATION_NO_CAPS ), + TOKEN( "hyphenation-no-last-word", XML_HYPHENATION_NO_LAST_WORD ), + TOKEN( "hyphenation-word-char-count", XML_HYPHENATION_WORD_CHAR_COUNT ), + TOKEN( "hyphenation-zone", XML_HYPHENATION_ZONE ), + TOKEN( "i", XML_I ), + TOKEN( "icon", XML_ICON ), + TOKEN( "icon-set", XML_ICON_SET ), + TOKEN( "icon-set-type", XML_ICON_SET_TYPE ), + TOKEN( "id", XML_ID ), + TOKEN( "ident", XML_IDENT ), + TOKEN( "identifier", XML_IDENTIFIER ), + TOKEN( "identify-categories", XML_IDENTIFY_CATEGORIES ), + TOKEN( "ideograph-alpha", XML_IDEOGRAPH_ALPHA ), + TOKEN( "ignore-case", XML_IGNORE_CASE ), + TOKEN( "ignore-empty-rows", XML_IGNORE_EMPTY_ROWS ), + TOKEN( "ignore-result", XML_IGNORE_RESULT ), + TOKEN( "ignore-selected-page", XML_IGNORE_SELECTED_PAGE ), + TOKEN( "illustration-index", XML_ILLUSTRATION_INDEX ), + TOKEN( "illustration-index-entry-template", XML_ILLUSTRATION_INDEX_ENTRY_TEMPLATE ), + TOKEN( "illustration-index-source", XML_ILLUSTRATION_INDEX_SOURCE ), + TOKEN( "image", XML_IMAGE ), + TOKEN( "image-count", XML_IMAGE_COUNT ), + TOKEN( "image-map", XML_IMAGE_MAP ), + TOKEN( "implies", XML_IMPLIES ), + TOKEN( "in", XML_IN ), + TOKEN( "in-range", XML_IN_RANGE ), + TOKEN( "inbook", XML_INBOOK ), + TOKEN( "incollection", XML_INCOLLECTION ), + TOKEN( "increment", XML_INCREMENT ), + TOKEN( "index", XML_INDEX ), + TOKEN( "index-body", XML_INDEX_BODY ), + TOKEN( "index-entry-bibliography", XML_INDEX_ENTRY_BIBLIOGRAPHY ), + TOKEN( "index-entry-chapter", XML_INDEX_ENTRY_CHAPTER ), + TOKEN( "index-entry-chapter-number", XML_INDEX_ENTRY_CHAPTER_NUMBER ), + TOKEN( "index-entry-link-end", XML_INDEX_ENTRY_LINK_END ), + TOKEN( "index-entry-link-start", XML_INDEX_ENTRY_LINK_START ), + TOKEN( "index-entry-page-number", XML_INDEX_ENTRY_PAGE_NUMBER ), + TOKEN( "index-entry-span", XML_INDEX_ENTRY_SPAN ), + TOKEN( "index-entry-tab-stop", XML_INDEX_ENTRY_TAB_STOP ), + TOKEN( "index-entry-template", XML_INDEX_ENTRY_TEMPLATE ), + TOKEN( "index-entry-text", XML_INDEX_ENTRY_TEXT ), + TOKEN( "index-name", XML_INDEX_NAME ), + TOKEN( "index-scope", XML_INDEX_SCOPE ), + TOKEN( "index-source-style", XML_INDEX_SOURCE_STYLE ), + TOKEN( "index-source-styles", XML_INDEX_SOURCE_STYLES ), + TOKEN( "index-title", XML_INDEX_TITLE ), + TOKEN( "index-title-template", XML_INDEX_TITLE_TEMPLATE ), + TOKEN( "information", XML_INFORMATION ), + TOKEN( "initial-creator", XML_INITIAL_CREATOR ), + TOKEN( "inproceedings", XML_INPROCEEDINGS ), + TOKEN( "input-required", XML_INPUT_REQUIRED ), + TOKEN( "insert-columns", XML_INSERT_COLUMNS ), + TOKEN( "insert-rows", XML_INSERT_ROWS ), + TOKEN( "insertion", XML_INSERTION ), + TOKEN( "insertion-cut-off", XML_INSERTION_CUT_OFF ), + TOKEN( "insertion-position", XML_INSERTION_POSITION ), + TOKEN( "inset", XML_INSET ), + TOKEN( "inside", XML_INSIDE ), + TOKEN( "institution", XML_INSTITUTION ), + TOKEN( "int", XML_INT ), + TOKEN( "intensity", XML_INTENSITY ), + TOKEN( "inter-character", XML_INTER_CHARACTER ), + TOKEN( "intersect", XML_INTERSECT ), + TOKEN( "interval", XML_INTERVAL ), + TOKEN( "interval-major", XML_INTERVAL_MAJOR ), + TOKEN( "interval-minor", XML_INTERVAL_MINOR ), + TOKEN( "into-english-number", XML_INTO_ENGLISH_NUMBER ), + TOKEN( "inverse", XML_INVERSE ), + TOKEN( "is-active", XML_IS_ACTIVE ), + TOKEN( "is-data-layout-field", XML_IS_DATA_LAYOUT_FIELD ), + TOKEN( "is-hidden", XML_IS_HIDDEN ), + TOKEN( "is-selection", XML_IS_SELECTION ), + TOKEN( "isbn", XML_ISBN ), + TOKEN( "italic", XML_ITALIC ), + TOKEN( "item", XML_ITEM ), + TOKEN( "iteration", XML_ITERATION ), + TOKEN( "journal", XML_JOURNAL ), + TOKEN( "justified", XML_JUSTIFIED ), + TOKEN( "justify", XML_JUSTIFY ), + TOKEN( "justify-single-word", XML_JUSTIFY_SINGLE_WORD ), + TOKEN( "keep-with-next", XML_KEEP_WITH_NEXT ), + TOKEN( "key", XML_KEY ), + TOKEN( "key1", XML_KEY1 ), + TOKEN( "key2", XML_KEY2 ), + TOKEN( "keyword", XML_KEYWORD ), + TOKEN( "keywords", XML_KEYWORDS ), + TOKEN( "kind", XML_KIND ), + TOKEN( "km", XML_KM ), + TOKEN( "label", XML_LABEL ), + TOKEN( "label-arrangement", XML_LABEL_ARRANGEMENT ), + TOKEN( "label-cell-address", XML_LABEL_CELL_ADDRESS ), + TOKEN( "label-cell-range-address", XML_LABEL_CELL_RANGE_ADDRESS ), + TOKEN( "label-fill", XML_LABEL_FILL ), + TOKEN( "label-fill-color", XML_LABEL_FILL_COLOR ), + TOKEN( "label-range", XML_LABEL_RANGE ), + TOKEN( "label-ranges", XML_LABEL_RANGES ), + TOKEN( "label-string", XML_LABEL_STRING ), + TOKEN( "label-stroke", XML_LABEL_STROKE ), + TOKEN( "label-stroke-color", XML_LABEL_STROKE_COLOR ), + TOKEN( "label-stroke-opacity", XML_LABEL_STROKE_OPACITY ), + TOKEN( "label-stroke-width", XML_LABEL_STROKE_WIDTH ), + TOKEN( "lambda", XML_LAMBDA ), + TOKEN( "landscape", XML_LANDSCAPE ), + TOKEN( "lang", XML_LANG ), + TOKEN( "language", XML_LANGUAGE ), + TOKEN( "language-asian", XML_LANGUAGE_ASIAN ), + TOKEN( "language-complex", XML_LANGUAGE_COMPLEX ), + TOKEN( "laser", XML_LASER ), + TOKEN( "last-column-spanned", XML_LAST_COLUMN_SPANNED ), + TOKEN( "last-page", XML_LAST_PAGE ), + TOKEN( "last-row-spanned", XML_LAST_ROW_SPANNED ), + TOKEN( "layer", XML_LAYER ), + TOKEN( "layer-set", XML_LAYER_SET ), + TOKEN( "leader-char", XML_LEADER_CHAR ), + TOKEN( "left", XML_LEFT ), + TOKEN( "left-outside", XML_LEFT_OUTSIDE ), + TOKEN( "left-text", XML_LEFT_TEXT ), + TOKEN( "left-top-position", XML_LEFT_TOP_POSITION ), + TOKEN( "left-arc", XML_LEFTARC ), + TOKEN( "left-circle", XML_LEFTCIRCLE ), + TOKEN( "legend", XML_LEGEND ), + TOKEN( "legend-position", XML_LEGEND_POSITION ), + TOKEN( "length", XML_LENGTH ), + TOKEN( "leq", XML_LEQ ), + TOKEN( "let-text", XML_LET_TEXT ), + TOKEN( "keep-text", XML_KEEP_TEXT ), + TOKEN( "letter-kerning", XML_LETTER_KERNING ), + TOKEN( "letter-spacing", XML_LETTER_SPACING ), + TOKEN( "letters", XML_LETTERS ), + TOKEN( "level", XML_LEVEL ), + TOKEN( "library", XML_LIBRARY ), + TOKEN( "library-embedded", XML_LIBRARY_EMBEDDED ), + TOKEN( "library-linked", XML_LIBRARY_LINKED ), + TOKEN( "light", XML_LIGHT ), + TOKEN( "lighting-mode", XML_LIGHTING_MODE ), + TOKEN( "lime", XML_LIME ), + TOKEN( "limit", XML_LIMIT ), + TOKEN( "line", XML_LINE ), + TOKEN( "line-break", XML_LINE_BREAK ), + TOKEN( "clear", XML_CLEAR ), + TOKEN( "line-distance", XML_LINE_DISTANCE ), + TOKEN( "line-height", XML_LINE_HEIGHT ), + TOKEN( "line-height-at-least", XML_LINE_HEIGHT_AT_LEAST ), + TOKEN( "line-number", XML_LINE_NUMBER ), + TOKEN( "line-skew", XML_LINE_SKEW ), + TOKEN( "line-spacing", XML_LINE_SPACING ), + TOKEN( "line-style", XML_LINE_STYLE ), + TOKEN( "line-width", XML_LINE_WIDTH ), + TOKEN( "linear", XML_LINEAR ), + TOKEN( "linearGradient", XML_LINEARGRADIENT ), + TOKEN( "linenumbering-configuration", XML_LINENUMBERING_CONFIGURATION ), + TOKEN( "linenumbering-separator", XML_LINENUMBERING_SEPARATOR ), + TOKEN( "lines", XML_LINES ), + TOKEN( "lines-used", XML_LINES_USED ), + TOKEN( "linked-cell", XML_LINKED_CELL ), + TOKEN( "link-to-source-data", XML_LINK_TO_SOURCE_DATA ), + TOKEN( "list", XML_LIST ), + TOKEN( "list-block", XML_LIST_BLOCK ), + TOKEN( "list-header", XML_LIST_HEADER ), + TOKEN( "list-info", XML_LIST_INFO ), + TOKEN( "list-item", XML_LIST_ITEM ), + TOKEN( "list-level", XML_LIST_LEVEL ), + TOKEN( "list-level-style-bullet", XML_LIST_LEVEL_STYLE_BULLET ), + TOKEN( "list-level-style-image", XML_LIST_LEVEL_STYLE_IMAGE ), + TOKEN( "list-level-style-number", XML_LIST_LEVEL_STYLE_NUMBER ), + TOKEN( "list-linkage-type", XML_LIST_LINKAGE_TYPE ), + TOKEN( "list-name", XML_LIST_NAME ), + TOKEN( "list-style", XML_LIST_STYLE ), + TOKEN( "list-style-name", XML_LIST_STYLE_NAME ), + TOKEN( "ln", XML_LN ), + TOKEN( "locked", XML_LOCKED ), + TOKEN( "log", XML_LOG ), + TOKEN( "logarithmic", XML_LOGARITHMIC ), + TOKEN( "logbase", XML_LOGBASE ), + TOKEN( "long", XML_LONG ), + TOKEN( "low", XML_LOW ), + TOKEN( "lowlimit", XML_LOWLIMIT ), + TOKEN( "lr-tb", XML_LR_TB ), + TOKEN( "lt", XML_LT ), + TOKEN( "ltr", XML_LTR ), + TOKEN( "luminance", XML_LUMINANCE ), + TOKEN( "macro-name", XML_MACRO_NAME ), + TOKEN( "maction", XML_MACTION ), + TOKEN( "main-entry-style-name", XML_MAIN_ENTRY_STYLE_NAME ), + TOKEN( "major", XML_MAJOR ), + TOKEN( "major-origin", XML_MAJOR_ORIGIN ), + TOKEN( "maligngroup", XML_MALIGNGROUP ), + TOKEN( "malignmark", XML_MALIGNMARK ), + TOKEN( "manual", XML_MANUAL ), + TOKEN( "manual-min", XML_MANUAL_MIN ), + TOKEN( "manual-max", XML_MANUAL_MAX ), + TOKEN( "map", XML_MAP ), + TOKEN( "margin-bottom", XML_MARGIN_BOTTOM ), + TOKEN( "margin-left", XML_MARGIN_LEFT ), + TOKEN( "margin-right", XML_MARGIN_RIGHT ), + TOKEN( "margin-top", XML_MARGIN_TOP ), + TOKEN( "margins", XML_MARGINS ), + TOKEN( "marker", XML_MARKER ), + TOKEN( "markers", XML_MARKERS ), + TOKEN( "marker-end", XML_MARKER_END ), + TOKEN( "marker-end-center", XML_MARKER_END_CENTER ), + TOKEN( "marker-end-width", XML_MARKER_END_WIDTH ), + TOKEN( "marker-start", XML_MARKER_START ), + TOKEN( "marker-start-center", XML_MARKER_START_CENTER ), + TOKEN( "marker-start-width", XML_MARKER_START_WIDTH ), + TOKEN( "marker-table", XML_MARKER_TABLE ), + TOKEN( "maroon", XML_MAROON ), + TOKEN( "master-page", XML_MASTER_PAGE ), + TOKEN( "master-page-name", XML_MASTER_PAGE_NAME ), + TOKEN( "master-styles", XML_MASTER_STYLES ), + TOKEN( "mastersthesis", XML_MASTERSTHESIS ), + TOKEN( "match", XML_MATCH ), + TOKEN( "math", XML_MATH ), + TOKEN( "matrix", XML_MATRIX ), + TOKEN( "matrix-covered", XML_MATRIX_COVERED ), + TOKEN( "matrixrow", XML_MATRIXROW ), + TOKEN( "max", XML_MAX ), + TOKEN( "max-axis-type", XML_MAX_AXIS_TYPE ), + TOKEN( "max-edge", XML_MAX_EDGE ), + TOKEN( "max-height", XML_MAX_HEIGHT ), + TOKEN( "max-length", XML_MAX_LENGTH ), + TOKEN( "max-width", XML_MAX_WIDTH ), + TOKEN( "maximum", XML_MAXIMUM ), + TOKEN( "maximum-difference", XML_MAXIMUM_DIFFERENCE ), + TOKEN( "may-break-between-rows", XML_MAY_BREAK_BETWEEN_ROWS ), + TOKEN( "may-script", XML_MAY_SCRIPT ), + TOKEN( "mean", XML_MEAN ), + TOKEN( "mean-value", XML_MEAN_VALUE ), + TOKEN( "measure", XML_MEASURE ), + TOKEN( "measure-align", XML_MEASURE_ALIGN ), + TOKEN( "measure-vertical-align", XML_MEASURE_VERTICAL_ALIGN ), + TOKEN( "median", XML_MEDIAN ), + TOKEN( "medium", XML_MEDIUM ), + TOKEN( "menclose", XML_MENCLOSE ), + TOKEN( "merror", XML_MERROR ), + TOKEN( "message-type", XML_MESSAGE_TYPE ), + TOKEN( "meta", XML_META ), + TOKEN( "mfenced", XML_MFENCED ), + TOKEN( "mfrac", XML_MFRAC ), + TOKEN( "mi", XML_MI ), + TOKEN( "middle", XML_MIDDLE ), + TOKEN( "mime-type", XML_MIME_TYPE ), + TOKEN( "min", XML_MIN ), + TOKEN( "min-axis-type", XML_MIN_AXIS_TYPE ), + TOKEN( "min-denominator-digits", XML_MIN_DENOMINATOR_DIGITS ), + TOKEN( "min-edge", XML_MIN_EDGE ), + TOKEN( "min-exponent-digits", XML_MIN_EXPONENT_DIGITS ), + TOKEN( "min-height", XML_MIN_HEIGHT ), + TOKEN( "min-integer-digits", XML_MIN_INTEGER_DIGITS ), + TOKEN( "min-label-distance", XML_MIN_LABEL_DISTANCE ), + TOKEN( "min-label-width", XML_MIN_LABEL_WIDTH ), + TOKEN( "min-length", XML_MIN_LENGTH ), + TOKEN( "min-line-height", XML_MIN_LINE_HEIGHT ), + TOKEN( "min-numerator-digits", XML_MIN_NUMERATOR_DIGITS ), + TOKEN( "min-row-height", XML_MIN_ROW_HEIGHT ), + TOKEN( "min-width", XML_MIN_WIDTH ), + TOKEN( "minimum", XML_MINIMUM ), + TOKEN( "minor", XML_MINOR ), + TOKEN( "minus", XML_MINUS ), + TOKEN( "minutes", XML_MINUTES ), + TOKEN( "mirror", XML_MIRROR ), + TOKEN( "mirrored", XML_MIRRORED ), + TOKEN( "misc", XML_MISC ), + TOKEN( "miter", XML_MITER ), + TOKEN( "mm", XML_MM ), + TOKEN( "mmultiscripts", XML_MMULTISCRIPTS ), + TOKEN( "mn", XML_MN ), + TOKEN( "mo", XML_MO ), + TOKEN( "mode", XML_MODE ), + TOKEN( "modern", XML_MODERN ), + TOKEN( "modification-date", XML_MODIFICATION_DATE ), + TOKEN( "modification-time", XML_MODIFICATION_TIME ), + TOKEN( "modulate", XML_MODULATE ), + TOKEN( "module", XML_MODULE ), + TOKEN( "moment", XML_MOMENT ), + TOKEN( "mono", XML_MONO ), + TOKEN( "month", XML_MONTH ), + TOKEN( "mouse-as-pen", XML_MOUSE_AS_PEN ), + TOKEN( "mouse-visible", XML_MOUSE_VISIBLE ), + TOKEN( "move", XML_MOVE ), + TOKEN( "move-from-bottom", XML_MOVE_FROM_BOTTOM ), + TOKEN( "move-from-left", XML_MOVE_FROM_LEFT ), + TOKEN( "move-from-right", XML_MOVE_FROM_RIGHT ), + TOKEN( "move-from-top", XML_MOVE_FROM_TOP ), + TOKEN( "move-protect", XML_MOVE_PROTECT ), + TOKEN( "move-short", XML_MOVE_SHORT ), + TOKEN( "movement", XML_MOVEMENT ), + TOKEN( "movement-cut-off", XML_MOVEMENT_CUT_OFF ), + TOKEN( "mover", XML_MOVER ), + TOKEN( "moving-average", XML_MOVING_AVERAGE ), + TOKEN( "mpadded", XML_MPADDED ), + TOKEN( "mphantom", XML_MPHANTOM ), + TOKEN( "mprescripts", XML_MPRESCRIPTS ), + TOKEN( "mroot", XML_MROOT ), + TOKEN( "mrow", XML_MROW ), + TOKEN( "ms", XML_MS ), + TOKEN( "mspace", XML_MSPACE ), + TOKEN( "msqrt", XML_MSQRT ), + TOKEN( "mstyle", XML_MSTYLE ), + TOKEN( "msub", XML_MSUB ), + TOKEN( "msubsup", XML_MSUBSUP ), + TOKEN( "msup", XML_MSUP ), + TOKEN( "mtable", XML_MTABLE ), + TOKEN( "mtd", XML_MTD ), + TOKEN( "mtext", XML_MTEXT ), + TOKEN( "mtr", XML_MTR ), + TOKEN( "multi-deletion-spanned", XML_MULTI_DELETION_SPANNED ), + TOKEN( "multi-line", XML_MULTI_LINE ), + TOKEN( "multiple", XML_MULTIPLE ), + TOKEN( "munder", XML_MUNDER ), + TOKEN( "munderover", XML_MUNDEROVER ), + TOKEN( "name", XML_NAME ), + TOKEN( "name-and-extension", XML_NAME_AND_EXTENSION ), + TOKEN( "named-expression", XML_NAMED_EXPRESSION ), + TOKEN( "named-expressions", XML_NAMED_EXPRESSIONS ), + TOKEN( "named-range", XML_NAMED_RANGE ), + TOKEN( "navigation-mode", XML_NAVIGATION_MODE ), + TOKEN( "navy", XML_NAVY ), + TOKEN( "negative", XML_NEGATIVE ), + TOKEN( "negative-color", XML_NEGATIVE_COLOR ), + TOKEN( "neq", XML_NEQ ), + TOKEN( "new", XML_NEW ), + TOKEN( "next", XML_NEXT ), + TOKEN( "next-page", XML_NEXT_PAGE ), + TOKEN( "next-style-name", XML_NEXT_STYLE_NAME ), + TOKEN( "no-limit", XML_NO_LIMIT ), + TOKEN( "no-wrap", XML_NO_WRAP ), + TOKEN( "!empty", XML_NOEMPTY ), + TOKEN( "nohref", XML_NOHREF ), + TOKEN( "!match", XML_NOMATCH ), + TOKEN( "non-whitespace-character-count", XML_NON_WHITESPACE_CHARACTER_COUNT ), + TOKEN( "none", XML_NONE ), + TOKEN( "normal", XML_NORMAL ), + TOKEN( "normals-direction", XML_NORMALS_DIRECTION ), + TOKEN( "normals-kind", XML_NORMALS_KIND ), + TOKEN( "not", XML_NOT ), + TOKEN( "not-equal-date", XML_NOT_EQUAL_DATE ), + TOKEN( "notation", XML_NOTATION ), + TOKEN( "note", XML_NOTE ), + TOKEN( "notes", XML_NOTES ), + TOKEN( "notin", XML_NOTIN ), + TOKEN( "notprsubset", XML_NOTPRSUBSET ), + TOKEN( "notsubset", XML_NOTSUBSET ), + TOKEN( "null-date", XML_NULL_DATE ), + TOKEN( "null-year", XML_NULL_YEAR ), + TOKEN( "num-format", XML_NUM_FORMAT ), + TOKEN( "num-letter-sync", XML_NUM_LETTER_SYNC ), + TOKEN( "num-list-format", XML_NUM_LIST_FORMAT ), + TOKEN( "num-prefix", XML_NUM_PREFIX ), + TOKEN( "num-suffix", XML_NUM_SUFFIX ), + TOKEN( "numalign", XML_NUMALIGN ), + TOKEN( "number", XML_NUMBER ), + TOKEN( "number-and-name", XML_NUMBER_AND_NAME ), + TOKEN( "number-columns-repeated", XML_NUMBER_COLUMNS_REPEATED ), + TOKEN( "number-columns-spanned", XML_NUMBER_COLUMNS_SPANNED ), + TOKEN( "number-lines", XML_NUMBER_LINES ), + TOKEN( "number-matrix-columns-spanned", XML_NUMBER_MATRIX_COLUMNS_SPANNED ), + TOKEN( "number-matrix-rows-spanned", XML_NUMBER_MATRIX_ROWS_SPANNED ), + TOKEN( "number-position", XML_NUMBER_POSITION ), + TOKEN( "number-rows-repeated", XML_NUMBER_ROWS_REPEATED ), + TOKEN( "number-rows-spanned", XML_NUMBER_ROWS_SPANNED ), + TOKEN( "number-style", XML_NUMBER_STYLE ), + TOKEN( "number-wrapped-paragraphs", XML_NUMBER_WRAPPED_PARAGRAPHS ), + TOKEN( "numbered-entries", XML_NUMBERED_ENTRIES ), + TOKEN( "object", XML_OBJECT ), + TOKEN( "object-count", XML_OBJECT_COUNT ), + TOKEN( "object-index", XML_OBJECT_INDEX ), + TOKEN( "object-index-entry-template", XML_OBJECT_INDEX_ENTRY_TEMPLATE ), + TOKEN( "object-index-source", XML_OBJECT_INDEX_SOURCE ), + TOKEN( "object-name", XML_OBJECT_NAME ), + TOKEN( "object-ole", XML_OBJECT_OLE ), + TOKEN( "objects", XML_OBJECTS ), + TOKEN( "odd-page", XML_ODD_PAGE ), + TOKEN( "offset", XML_OFFSET ), + TOKEN( "olive", XML_OLIVE ), + TOKEN( "onLoad", XML_ONLOAD ), + TOKEN( "onRequest", XML_ONREQUEST ), + TOKEN( "on-update-keep-size", XML_ON_UPDATE_KEEP_SIZE ), + TOKEN( "on-update-keep-styles", XML_ON_UPDATE_KEEP_STYLES ), + TOKEN( "online", XML_ONLINE ), + TOKEN( "online-text", XML_ONLINE_TEXT ), + TOKEN( "open", XML_OPEN ), + TOKEN( "open-horizontal", XML_OPEN_HORIZONTAL ), + TOKEN( "open-vertical", XML_OPEN_VERTICAL ), + TOKEN( "operation", XML_OPERATION ), + TOKEN( "operator", XML_OPERATOR ), + TOKEN( "optimal", XML_OPTIMAL ), + TOKEN( "option", XML_OPTION ), + TOKEN( "or", XML_OR ), + TOKEN( "order", XML_ORDER ), + TOKEN( "ordered-list", XML_ORDERED_LIST ), + TOKEN( "organizations", XML_ORGANIZATIONS ), + TOKEN( "orientation", XML_ORIENTATION ), + TOKEN( "orientation-landscape", XML_ORIENTATION_LANDSCAPE ), + TOKEN( "orientation-portrait", XML_ORIENTATION_PORTRAIT ), + TOKEN( "origin", XML_ORIGIN ), + TOKEN( "orphans", XML_ORPHANS ), + TOKEN( "outline-content-visible", XML_OUTLINE_CONTENT_VISIBLE ), + TOKEN( "outline-level", XML_OUTLINE_LEVEL ), + TOKEN( "outline-level-style", XML_OUTLINE_LEVEL_STYLE ), + TOKEN( "outline-style", XML_OUTLINE_STYLE ), + TOKEN( "outset", XML_OUTSET ), + TOKEN( "outside", XML_OUTSIDE ), + TOKEN( "overlap", XML_OVERLAP ), + TOKEN( "overlay", XML_OVERLAY ), + TOKEN( "p", XML_P ), + TOKEN( "package-name", XML_PACKAGE_NAME ), + TOKEN( "padding", XML_PADDING ), + TOKEN( "padding-bottom", XML_PADDING_BOTTOM ), + TOKEN( "padding-left", XML_PADDING_LEFT ), + TOKEN( "padding-right", XML_PADDING_RIGHT ), + TOKEN( "padding-top", XML_PADDING_TOP ), + TOKEN( "page", XML_PAGE ), + TOKEN( "page-adjust", XML_PAGE_ADJUST ), + TOKEN( "page-breaks-on-group-change", XML_PAGE_BREAKS_ON_GROUP_CHANGE ), + TOKEN( "page-content", XML_PAGE_CONTENT ), + TOKEN( "page-continuation-string", XML_PAGE_CONTINUATION_STRING ), + TOKEN( "page-count", XML_PAGE_COUNT ), + TOKEN( "page-end-margin", XML_PAGE_END_MARGIN ), + TOKEN( "page-height", XML_PAGE_HEIGHT ), + TOKEN( "page-master", XML_PAGE_MASTER ), + TOKEN( "page-master-name", XML_PAGE_MASTER_NAME ), + TOKEN( "page-name", XML_PAGE_NAME ), + TOKEN( "page-number", XML_PAGE_NUMBER ), + TOKEN( "page-number-visible", XML_PAGE_NUMBER_VISIBLE ), + TOKEN( "page-start-margin", XML_PAGE_START_MARGIN ), + TOKEN( "page-step-size", XML_PAGE_STEP_SIZE ), + TOKEN( "page-style-name", XML_PAGE_STYLE_NAME ), + TOKEN( "page-thumbnail", XML_PAGE_THUMBNAIL ), + TOKEN( "page-usage", XML_PAGE_USAGE ), + TOKEN( "page-variable-get", XML_PAGE_VARIABLE_GET ), + TOKEN( "page-variable-set", XML_PAGE_VARIABLE_SET ), + TOKEN( "page-view-zoom-value", XML_PAGE_VIEW_ZOOM_VALUE ), + TOKEN( "page-width", XML_PAGE_WIDTH ), + TOKEN( "pages", XML_PAGES ), + TOKEN( "paper-tray-number", XML_PAPER_TRAY_NUMBER ), + TOKEN( "paragraph", XML_PARAGRAPH ), + TOKEN( "paragraph-content", XML_PARAGRAPH_CONTENT ), + TOKEN( "paragraph-count", XML_PARAGRAPH_COUNT ), + TOKEN( "paragraph-end-margin", XML_PARAGRAPH_END_MARGIN ), + TOKEN( "paragraph-start-margin", XML_PARAGRAPH_START_MARGIN ), + TOKEN( "parallel", XML_PARALLEL ), + TOKEN( "param", XML_PARAM ), + TOKEN( "parent-style-name", XML_PARENT_STYLE_NAME ), + TOKEN( "parse-sql-statement", XML_PARSE_SQL_STATEMENT ), + TOKEN( "parsed", XML_PARSED ), + TOKEN( "partialdiff", XML_PARTIALDIFF ), + TOKEN( "password", XML_PASSWORD ), + TOKEN( "passwort", XML_PASSWORT ), + TOKEN( "path", XML_PATH ), + TOKEN( "path-id", XML_PATH_ID ), + TOKEN( "pause", XML_PAUSE ), + TOKEN( "pending", XML_PENDING ), + TOKEN( "percentage", XML_PERCENTAGE ), + TOKEN( "percentage-style", XML_PERCENTAGE_STYLE ), + TOKEN( "perspective", XML_PERSPECTIVE ), + TOKEN( "phdthesis", XML_PHDTHESIS ), + TOKEN( "phong", XML_PHONG ), + TOKEN( "velocity-x", XML_PHYSICS_ANIMATION_START_VELOCITY_X ), + TOKEN( "velocity-y", XML_PHYSICS_ANIMATION_START_VELOCITY_Y ), + TOKEN( "density", XML_PHYSICS_ANIMATION_DENSITY ), + TOKEN( "bounciness", XML_PHYSICS_ANIMATION_BOUNCINESS ), + TOKEN( "pie-offset", XML_PIE_OFFSET ), + TOKEN( "placeholder", XML_PLACEHOLDER ), + TOKEN( "placeholder-type", XML_PLACEHOLDER_TYPE ), + TOKEN( "placing", XML_PLACING ), + TOKEN( "plain-number", XML_PLAIN_NUMBER ), + TOKEN( "plain-number-and-name", XML_PLAIN_NUMBER_AND_NAME ), + TOKEN( "play-full", XML_PLAY_FULL ), + TOKEN( "plot-area", XML_PLOT_AREA ), + TOKEN( "plugin", XML_PLUGIN ), + TOKEN( "plus", XML_PLUS ), + TOKEN( "points", XML_POINTS ), + TOKEN( "polygon", XML_POLYGON ), + TOKEN( "polyline", XML_POLYLINE ), + TOKEN( "polynomial", XML_POLYNOMIAL ), + TOKEN( "pool-id", XML_POOL_ID ), + TOKEN( "portrait", XML_PORTRAIT ), + TOKEN( "position", XML_POSITION ), + TOKEN( "position-bottom", XML_POSITION_BOTTOM ), + TOKEN( "position-left", XML_POSITION_LEFT ), + TOKEN( "position-right", XML_POSITION_RIGHT ), + TOKEN( "position-top", XML_POSITION_TOP ), + TOKEN( "positive-color", XML_POSITIVE_COLOR ), + TOKEN( "oblique", XML_POSTURE_OBLIQUE ), + TOKEN( "power", XML_POWER ), + TOKEN( "precision-as-shown", XML_PRECISION_AS_SHOWN ), + TOKEN( "prefix", XML_PREFIX ), + TOKEN( "infix", XML_INFIX ), + TOKEN( "postfix", XML_POSTFIX ), + TOKEN( "presentation", XML_PRESENTATION ), + TOKEN( "orgchart", XML_PRESENTATION_ORGCHART ), + TOKEN( "outline", XML_PRESENTATION_OUTLINE ), + TOKEN( "presentation-page-layout", XML_PRESENTATION_PAGE_LAYOUT ), + TOKEN( "presentation-page-layout-name", XML_PRESENTATION_PAGE_LAYOUT_NAME ), + TOKEN( "previous", XML_PREVIOUS ), + TOKEN( "previous-page", XML_PREVIOUS_PAGE ), + TOKEN( "print", XML_PRINT ), + TOKEN( "print-content", XML_PRINT_CONTENT ), + TOKEN( "print-date", XML_PRINT_DATE ), + TOKEN( "print-orientation", XML_PRINT_ORIENTATION ), + TOKEN( "print-page-order", XML_PRINT_PAGE_ORDER ), + TOKEN( "print-range", XML_PRINT_RANGE ), + TOKEN( "print-ranges", XML_PRINT_RANGES ), + TOKEN( "print-time", XML_PRINT_TIME ), + TOKEN( "printable", XML_PRINTABLE ), + TOKEN( "printed-by", XML_PRINTED_BY ), + TOKEN( "prior", XML_PRIOR ), + TOKEN( "proceedings", XML_PROCEEDINGS ), + TOKEN( "product", XML_PRODUCT ), + TOKEN( "projection", XML_PROJECTION ), + TOKEN( "properties", XML_PROPERTIES ), + TOKEN( "protect", XML_PROTECT ), + TOKEN( "protected", XML_PROTECTED ), + TOKEN( "protection-key", XML_PROTECTION_KEY ), + TOKEN( "protection-key-digest-algorithm", XML_PROTECTION_KEY_DIGEST_ALGORITHM ), + TOKEN( "protection-key-digest-algorithm-2", XML_PROTECTION_KEY_DIGEST_ALGORITHM_2 ), + TOKEN( "prsubset", XML_PRSUBSET ), + TOKEN( "publisher", XML_PUBLISHER ), + TOKEN( "punctuation-wrap", XML_PUNCTUATION_WRAP ), + TOKEN( "purple", XML_PURPLE ), + TOKEN( "pyramid", XML_PYRAMID ), + TOKEN( "qrcode", XML_QRCODE ), + TOKEN( "qrcode-border", XML_QRCODE_BORDER ), + TOKEN( "qrcode-errorcorrection", XML_QRCODE_ERROR_CORRECTION ), + TOKEN( "qrcode-type", XML_QRCODE_TYPE ), + TOKEN( "quarter", XML_QUARTER ), + TOKEN( "query-name", XML_QUERY_NAME ), + TOKEN( "quo-vadis", XML_QUO_VADIS ), + TOKEN( "quotient", XML_QUOTIENT ), + TOKEN( "r", XML_R ), + TOKEN( "radar", XML_RADAR ), + TOKEN( "random", XML_RANDOM ), + TOKEN( "range-address", XML_RANGE_ADDRESS ), + TOKEN( "range-usable-as", XML_RANGE_USABLE_AS ), + TOKEN( "recreate-on-edit", XML_RECREATE_ON_EDIT ), + TOKEN( "rect", XML_RECT ), + TOKEN( "red", XML_RED ), + TOKEN( "ref-name", XML_REF_NAME ), + TOKEN( "reference", XML_REFERENCE ), + TOKEN( "reference-end", XML_REFERENCE_END ), + TOKEN( "reference-format", XML_REFERENCE_FORMAT ), + TOKEN( "reference-mark", XML_REFERENCE_MARK ), + TOKEN( "reference-mark-end", XML_REFERENCE_MARK_END ), + TOKEN( "reference-mark-start", XML_REFERENCE_MARK_START ), + TOKEN( "reference-ref", XML_REFERENCE_REF ), + TOKEN( "reference-start", XML_REFERENCE_START ), + TOKEN( "reference-type", XML_REFERENCE_TYPE ), + TOKEN( "refresh-delay", XML_REFRESH_DELAY ), + TOKEN( "region-center", XML_REGION_CENTER ), + TOKEN( "region-left", XML_REGION_LEFT ), + TOKEN( "region-right", XML_REGION_RIGHT ), + TOKEN( "register-true", XML_REGISTER_TRUE ), + TOKEN( "register-truth-ref-style-name", XML_REGISTER_TRUTH_REF_STYLE_NAME ), + TOKEN( "rejected", XML_REJECTED ), + TOKEN( "rejecting-change-id", XML_REJECTING_CHANGE_ID ), + TOKEN( "rejection", XML_REJECTION ), + TOKEN( "rel-column-width", XML_REL_COLUMN_WIDTH ), + TOKEN( "rel-height", XML_REL_HEIGHT ), + TOKEN( "rel-height-rel", XML_REL_HEIGHT_REL ), + TOKEN( "rel-width", XML_REL_WIDTH ), + TOKEN( "rel-width-rel", XML_REL_WIDTH_REL ), + TOKEN( "relative", XML_RELATIVE ), + TOKEN( "relative-tab-stop-position", XML_RELATIVE_TAB_STOP_POSITION ), + TOKEN( "reln", XML_RELN ), + TOKEN( "rem", XML_REM ), + TOKEN( "remove-dependents", XML_REMOVE_DEPENDENTS ), + TOKEN( "remove-precedents", XML_REMOVE_PRECEDENTS ), + TOKEN( "repeat", XML_REPEAT ), + TOKEN( "repeat-column", XML_REPEAT_COLUMN ), + TOKEN( "repeat-row", XML_REPEAT_ROW ), + TOKEN( "repeated", XML_REPEATED ), + TOKEN( "replace", XML_REPLACE ), + TOKEN( "report-type", XML_REPORT_TYPE ), + TOKEN( "restart-on-page", XML_RESTART_ON_PAGE ), + TOKEN( "revision", XML_REVISION ), + TOKEN( "ridge", XML_RIDGE ), + TOKEN( "right", XML_RIGHT ), + TOKEN( "right-outside", XML_RIGHT_OUTSIDE ), + TOKEN( "right-text", XML_RIGHT_TEXT ), + TOKEN( "right-to-left", XML_RIGHT_TO_LEFT ), + TOKEN( "right-arc", XML_RIGHTARC ), + TOKEN( "right-circle", XML_RIGHTCIRCLE ), + TOKEN( "ring", XML_RING ), + TOKEN( "role", XML_ROLE ), + TOKEN( "roll-from-bottom", XML_ROLL_FROM_BOTTOM ), + TOKEN( "roll-from-left", XML_ROLL_FROM_LEFT ), + TOKEN( "roll-from-right", XML_ROLL_FROM_RIGHT ), + TOKEN( "roman", XML_ROMAN ), + TOKEN( "root", XML_ROOT ), + TOKEN( "rotate", XML_ROTATE ), + TOKEN( "rotation", XML_ROTATION ), + TOKEN( "rotation-align", XML_ROTATION_ALIGN ), + TOKEN( "rotation-angle", XML_ROTATION_ANGLE ), + TOKEN( "round", XML_ROUND ), + TOKEN( "row", XML_ROW ), + TOKEN( "row-height", XML_ROW_HEIGHT ), + TOKEN( "row-number", XML_ROW_NUMBER ), + TOKEN( "rows", XML_ROWS ), + TOKEN( "rsid", XML_RSID ), + TOKEN( "paragraph-rsid", XML_PARRSID ), + TOKEN( "ruby", XML_RUBY ), + TOKEN( "ruby-align", XML_RUBY_ALIGN ), + TOKEN( "ruby-base", XML_RUBY_BASE ), + TOKEN( "ruby-position", XML_RUBY_POSITION ), + TOKEN( "ruby-text", XML_RUBY_TEXT ), + TOKEN( "run-through", XML_RUN_THROUGH ), + TOKEN( "rx", XML_RX ), + TOKEN( "ry", XML_RY ), + TOKEN( "s", XML_S ), + TOKEN( "scale", XML_SCALE ), + TOKEN( "scale-min", XML_SCALE_MIN ), + TOKEN( "scale-text", XML_SCALE_TEXT ), + TOKEN( "scale-to", XML_SCALE_TO ), + TOKEN( "scale-to-pages", XML_SCALE_TO_PAGES ), + TOKEN( "scatter", XML_SCATTER ), + TOKEN( "scenario", XML_SCENARIO ), + TOKEN( "scenario-ranges", XML_SCENARIO_RANGES ), + TOKEN( "scene", XML_SCENE ), + TOKEN( "school", XML_SCHOOL ), + TOKEN( "scientific-number", XML_SCIENTIFIC_NUMBER ), + TOKEN( "score-spaces", XML_SCORE_SPACES ), + TOKEN( "script", XML_SCRIPT ), + TOKEN( "script-asian", XML_SCRIPT_ASIAN ), + TOKEN( "script-complex", XML_SCRIPT_COMPLEX ), + TOKEN( "scroll", XML_SCROLL ), + TOKEN( "sdev", XML_SDEV ), + TOKEN( "search-criteria-must-apply-to-whole-cell", XML_SEARCH_CRITERIA_MUST_APPLY_TO_WHOLE_CELL ), + TOKEN( "sec", XML_SEC ), + TOKEN( "sech", XML_SECH ), + TOKEN( "second-date-time", XML_SECOND_DATE_TIME ), + TOKEN( "seconds", XML_SECONDS ), + TOKEN( "section", XML_SECTION ), + TOKEN( "section-desc", XML_SECTION_DESC ), + TOKEN( "section-name", XML_SECTION_NAME ), + TOKEN( "section-source", XML_SECTION_SOURCE ), + TOKEN( "select-page", XML_SELECT_PAGE ), + TOKEN( "select-protected-cells", XML_SELECT_PROTECTED_CELLS ), + TOKEN( "select-unprotected-cells", XML_SELECT_UNPROTECTED_CELLS ), + TOKEN( "selector", XML_SELECTOR ), + TOKEN( "semantics", XML_SEMANTICS ), + TOKEN( "semi-automatic", XML_SEMI_AUTOMATIC ), + TOKEN( "sender-city", XML_SENDER_CITY ), + TOKEN( "sender-company", XML_SENDER_COMPANY ), + TOKEN( "sender-country", XML_SENDER_COUNTRY ), + TOKEN( "sender-email", XML_SENDER_EMAIL ), + TOKEN( "sender-fax", XML_SENDER_FAX ), + TOKEN( "sender-firstname", XML_SENDER_FIRSTNAME ), + TOKEN( "sender-initials", XML_SENDER_INITIALS ), + TOKEN( "sender-lastname", XML_SENDER_LASTNAME ), + TOKEN( "sender-phone-private", XML_SENDER_PHONE_PRIVATE ), + TOKEN( "sender-phone-work", XML_SENDER_PHONE_WORK ), + TOKEN( "sender-position", XML_SENDER_POSITION ), + TOKEN( "sender-postal-code", XML_SENDER_POSTAL_CODE ), + TOKEN( "sender-state-or-province", XML_SENDER_STATE_OR_PROVINCE ), + TOKEN( "sender-street", XML_SENDER_STREET ), + TOKEN( "sender-title", XML_SENDER_TITLE ), + TOKEN( "sep", XML_SEP ), + TOKEN( "separation-character", XML_SEPARATION_CHARACTER ), + TOKEN( "separator", XML_SEPARATOR ), + TOKEN( "sequence", XML_SEQUENCE ), + TOKEN( "sequence-decl", XML_SEQUENCE_DECL ), + TOKEN( "sequence-decls", XML_SEQUENCE_DECLS ), + TOKEN( "sequence-ref", XML_SEQUENCE_REF ), + TOKEN( "series", XML_SERIES ), + TOKEN( "series-source", XML_SERIES_SOURCE ), + TOKEN( "server-map", XML_SERVER_MAP ), + TOKEN( "set", XML_SET ), + TOKEN( "setdiff", XML_SETDIFF ), + TOKEN( "settings", XML_SETTINGS ), + TOKEN( "shade-mode", XML_SHADE_MODE ), + TOKEN( "shadow", XML_SHADOW ), + TOKEN( "shadow-color", XML_SHADOW_COLOR ), + TOKEN( "shadow-offset-x", XML_SHADOW_OFFSET_X ), + TOKEN( "shadow-offset-y", XML_SHADOW_OFFSET_Y ), + TOKEN( "shadow-slant", XML_SHADOW_SLANT ), + TOKEN( "shadow-transparency", XML_SHADOW_TRANSPARENCY ), + TOKEN( "shadow-blur", XML_SHADOW_BLUR ), + TOKEN( "shape", XML_SHAPE ), + TOKEN( "shape-id", XML_SHAPE_ID ), + TOKEN( "shapes", XML_SHAPES ), + TOKEN( "sheet-name", XML_SHEET_NAME ), + TOKEN( "shininess", XML_SHININESS ), + TOKEN( "short", XML_SHORT ), + TOKEN( "show", XML_SHOW ), + TOKEN( "show-accepted-changes", XML_SHOW_ACCEPTED_CHANGES ), + TOKEN( "show-changes", XML_SHOW_CHANGES ), + TOKEN( "show-changes-by-author", XML_SHOW_CHANGES_BY_AUTHOR ), + TOKEN( "show-changes-by-author-name", XML_SHOW_CHANGES_BY_AUTHOR_NAME ), + TOKEN( "show-changes-by-comment", XML_SHOW_CHANGES_BY_COMMENT ), + TOKEN( "show-changes-by-comment-text", XML_SHOW_CHANGES_BY_COMMENT_TEXT ), + TOKEN( "show-changes-by-datetime", XML_SHOW_CHANGES_BY_DATETIME ), + TOKEN( "show-changes-by-datetime-first-datetime", XML_SHOW_CHANGES_BY_DATETIME_FIRST_DATETIME ), + TOKEN( "show-changes-by-datetime-mode", XML_SHOW_CHANGES_BY_DATETIME_MODE ), + TOKEN( "show-changes-by-datetime-second-datetime", XML_SHOW_CHANGES_BY_DATETIME_SECOND_DATETIME ), + TOKEN( "show-changes-by-ranges", XML_SHOW_CHANGES_BY_RANGES ), + TOKEN( "show-changes-by-ranges-list", XML_SHOW_CHANGES_BY_RANGES_LIST ), + TOKEN( "show-logo", XML_SHOW_LOGO ), + TOKEN( "show-rejected-changes", XML_SHOW_REJECTED_CHANGES ), + TOKEN( "show-shape", XML_SHOW_SHAPE ), + TOKEN( "show-text", XML_SHOW_TEXT ), + TOKEN( "show-unit", XML_SHOW_UNIT ), + TOKEN( "show-value", XML_SHOW_VALUE ), + TOKEN( "shows", XML_SHOWS ), + TOKEN( "side-by-side", XML_SIDE_BY_SIDE ), + TOKEN( "silver", XML_SILVER ), + TOKEN( "simple", XML_SIMPLE ), + TOKEN( "sin", XML_SIN ), + TOKEN( "since-date-time", XML_SINCE_DATE_TIME ), + TOKEN( "since-save", XML_SINCE_SAVE ), + TOKEN( "sinh", XML_SINH ), + TOKEN( "size", XML_SIZE ), + TOKEN( "size-protect", XML_SIZE_PROTECT ), + TOKEN( "slant", XML_SLANT ), + TOKEN( "slant-x", XML_SLANT_X ), + TOKEN( "slant-y", XML_SLANT_Y ), + TOKEN( "slide", XML_SLIDE ), + TOKEN( "slow", XML_SLOW ), + TOKEN( "softedge-radius", XML_SOFTEDGE_RADIUS ), + TOKEN( "solid", XML_SOLID ), + TOKEN( "solid-type", XML_SOLID_TYPE ), + TOKEN( "sort", XML_SORT ), + TOKEN( "sort-ascending", XML_SORT_ASCENDING ), + TOKEN( "sort-by", XML_SORT_BY ), + TOKEN( "sort-by-position", XML_SORT_BY_POSITION ), + TOKEN( "sort-groups", XML_SORT_GROUPS ), + TOKEN( "sort-key", XML_SORT_KEY ), + TOKEN( "sound", XML_SOUND ), + TOKEN( "source-cell-range", XML_SOURCE_CELL_RANGE ), + TOKEN( "source-cell-range-addresses", XML_SOURCE_CELL_RANGE_ADDRESSES ), + TOKEN( "source-field-name", XML_SOURCE_FIELD_NAME ), + TOKEN( "source-name", XML_SOURCE_NAME ), + TOKEN( "source-range-address", XML_SOURCE_RANGE_ADDRESS ), + TOKEN( "source-service", XML_SOURCE_SERVICE ), + TOKEN( "space-before", XML_SPACE_BEFORE ), + TOKEN( "sparkline-groups", XML_SPARKLINE_GROUPS ), + TOKEN( "sparkline-group", XML_SPARKLINE_GROUP ), + TOKEN( "sparklines", XML_SPARKLINES ), + TOKEN( "sparkline", XML_SPARKLINE ), + TOKEN( "span", XML_SPAN ), + TOKEN( "specular", XML_SPECULAR ), + TOKEN( "specular-color", XML_SPECULAR_COLOR ), + TOKEN( "speed", XML_SPEED ), + TOKEN( "sphere", XML_SPHERE ), + TOKEN( "spiral", XML_SPIRAL ), + TOKEN( "spiral-in", XML_SPIRAL_IN ), + TOKEN( "spiral-inward-left", XML_SPIRAL_INWARD_LEFT ), + TOKEN( "spiral-inward-right", XML_SPIRAL_INWARD_RIGHT ), + TOKEN( "spiral-out", XML_SPIRAL_OUT ), + TOKEN( "spiral-outward-left", XML_SPIRAL_OUTWARD_LEFT ), + TOKEN( "spiral-outward-right", XML_SPIRAL_OUTWARD_RIGHT ), + TOKEN( "spiralin-left", XML_SPIRALIN_LEFT ), + TOKEN( "spiralin-right", XML_SPIRALIN_RIGHT ), + TOKEN( "spiralout-left", XML_SPIRALOUT_LEFT ), + TOKEN( "spiralout-right", XML_SPIRALOUT_RIGHT ), + TOKEN( "splines", XML_SPLINES ), + TOKEN( "split", XML_SPLIT ), + TOKEN( "split-column", XML_SPLIT_COLUMN ), + TOKEN( "split-position", XML_SPLIT_POSITION ), + TOKEN( "split-row", XML_SPLIT_ROW ), + TOKEN( "spreadsheet", XML_SPREADSHEET ), + TOKEN( "spreadMethod", XML_SPREADMETHOD ), + TOKEN( "sql-statement", XML_SQL_STATEMENT ), + TOKEN( "stacked", XML_STACKED ), + TOKEN( "stagger-even", XML_STAGGER_EVEN ), + TOKEN( "stagger-odd", XML_STAGGER_ODD ), + TOKEN( "standard", XML_STANDARD ), + TOKEN( "standard-deviation", XML_STANDARD_DEVIATION ), + TOKEN( "starbasic", XML_STARBASIC ), + TOKEN( "start", XML_START ), + TOKEN( "start-angle", XML_START_ANGLE ), + TOKEN( "start-color", XML_START_COLOR ), + TOKEN( "start-column", XML_START_COLUMN ), + TOKEN( "start-glue-point", XML_START_GLUE_POINT ), + TOKEN( "start-guide", XML_START_GUIDE ), + TOKEN( "start-intensity", XML_START_INTENSITY ), + TOKEN( "start-line-spacing-horizontal", XML_START_LINE_SPACING_HORIZONTAL ), + TOKEN( "start-line-spacing-vertical", XML_START_LINE_SPACING_VERTICAL ), + TOKEN( "start-numbering-at", XML_START_NUMBERING_AT ), + TOKEN( "start-page", XML_START_PAGE ), + TOKEN( "start-position", XML_START_POSITION ), + TOKEN( "start-row", XML_START_ROW ), + TOKEN( "start-scale", XML_START_SCALE ), + TOKEN( "start-shape", XML_START_SHAPE ), + TOKEN( "start-table", XML_START_TABLE ), + TOKEN( "start-value", XML_START_VALUE ), + TOKEN( "start-with-navigator", XML_START_WITH_NAVIGATOR ), + TOKEN( "state", XML_STATE ), + TOKEN( "statistics", XML_STATISTICS ), + TOKEN( "status", XML_STATUS ), + TOKEN( "stay-on-top", XML_STAY_ON_TOP ), + TOKEN( "stdev", XML_STDEV ), + TOKEN( "stdevp", XML_STDEVP ), + TOKEN( "steps", XML_STEPS ), + TOKEN( "step-size", XML_STEP_SIZE ), + TOKEN( "stock", XML_STOCK ), + TOKEN( "stock-updown-bars", XML_STOCK_UPDOWN_BARS ), + TOKEN( "stock-with-volume", XML_STOCK_WITH_VOLUME ), + TOKEN( "stop", XML_STOP ), + TOKEN( "stop-color", XML_STOP_COLOR ), + TOKEN( "stop-opacity", XML_STOP_OPACITY ), + TOKEN( "stretch", XML_STRETCH ), + TOKEN( "stretch-from-bottom", XML_STRETCH_FROM_BOTTOM ), + TOKEN( "stretch-from-left", XML_STRETCH_FROM_LEFT ), + TOKEN( "stretch-from-right", XML_STRETCH_FROM_RIGHT ), + TOKEN( "stretch-from-top", XML_STRETCH_FROM_TOP ), + TOKEN( "stretchy", XML_STRETCHY ), + TOKEN( "strict", XML_STRICT ), + TOKEN( "string", XML_STRING ), + TOKEN( "string-value", XML_STRING_VALUE ), + TOKEN( "string-value-if-false", XML_STRING_VALUE_IF_FALSE ), + TOKEN( "string-value-if-true", XML_STRING_VALUE_IF_TRUE ), + TOKEN( "stripes", XML_STRIPES ), + TOKEN( "stroke", XML_STROKE ), + TOKEN( "stroke-color", XML_STROKE_COLOR ), + TOKEN( "stroke-dash", XML_STROKE_DASH ), + TOKEN( "stroke-linecap", XML_STROKE_LINECAP ), + TOKEN( "stroke-linejoin", XML_STROKE_LINEJOIN ), + TOKEN( "stroke-opacity", XML_STROKE_OPACITY ), + TOKEN( "stroke-width", XML_STROKE_WIDTH ), + TOKEN( "structure-protected", XML_STRUCTURE_PROTECTED ), + TOKEN( "style", XML_STYLE ), + TOKEN( "style-name", XML_STYLE_NAME ), + TOKEN( "styles", XML_STYLES ), + TOKEN( "stylesheet", XML_STYLESHEET ), + TOKEN( "sub-table", XML_SUB_TABLE ), + TOKEN( "subject", XML_SUBJECT ), + TOKEN( "subset", XML_SUBSET ), + TOKEN( "subtitle", XML_SUBTITLE ), + TOKEN( "subtotal-field", XML_SUBTOTAL_FIELD ), + TOKEN( "subtotal-rule", XML_SUBTOTAL_RULE ), + TOKEN( "subtotal-rules", XML_SUBTOTAL_RULES ), + TOKEN( "sub-view-size", XML_SUB_VIEW_SIZE ), + TOKEN( "suffix", XML_SUFFIX ), + TOKEN( "sum", XML_SUM ), + TOKEN( "swiss", XML_SWISS ), + TOKEN( "symbol", XML_SYMBOL ), + TOKEN( "symbol-height", XML_SYMBOL_HEIGHT ), + TOKEN( "symbol-image-name", XML_SYMBOL_IMAGE_NAME ), + TOKEN( "symbol-width", XML_SYMBOL_WIDTH ), + TOKEN( "system", XML_SYSTEM ), + TOKEN( "tab-color", XML_TAB_COLOR ), + TOKEN( "tab-cycle", XML_TAB_CYCLE ), + TOKEN( "tab-index", XML_TAB_INDEX ), + TOKEN( "tab-stop", XML_TAB_STOP ), + TOKEN( "tab-stop-distance", XML_TAB_STOP_DISTANCE ), + TOKEN( "tab-stops", XML_TAB_STOPS ), + TOKEN( "table", XML_TABLE ), + TOKEN( "table-background", XML_TABLE_BACKGROUND ), + TOKEN( "table-cell", XML_TABLE_CELL ), + TOKEN( "table-centering", XML_TABLE_CENTERING ), + TOKEN( "table-column", XML_TABLE_COLUMN ), + TOKEN( "table-column-group", XML_TABLE_COLUMN_GROUP ), + TOKEN( "table-columns", XML_TABLE_COLUMNS ), + TOKEN( "table-count", XML_TABLE_COUNT ), + TOKEN( "table-header", XML_TABLE_HEADER ), + TOKEN( "table-header-columns", XML_TABLE_HEADER_COLUMNS ), + TOKEN( "table-header-rows", XML_TABLE_HEADER_ROWS ), + TOKEN( "table-index", XML_TABLE_INDEX ), + TOKEN( "table-index-entry-template", XML_TABLE_INDEX_ENTRY_TEMPLATE ), + TOKEN( "table-index-source", XML_TABLE_INDEX_SOURCE ), + TOKEN( "table-name", XML_TABLE_NAME ), + TOKEN( "table-of-content", XML_TABLE_OF_CONTENT ), + TOKEN( "table-of-content-entry-template", XML_TABLE_OF_CONTENT_ENTRY_TEMPLATE ), + TOKEN( "table-of-content-source", XML_TABLE_OF_CONTENT_SOURCE ), + TOKEN( "table-page", XML_TABLE_PAGE ), + TOKEN( "table-protection", XML_TABLE_PROTECTION ), + TOKEN( "table-row", XML_TABLE_ROW ), + TOKEN( "table-row-group", XML_TABLE_ROW_GROUP ), + TOKEN( "table-rows", XML_TABLE_ROWS ), + TOKEN( "table-source", XML_TABLE_SOURCE ), + TOKEN( "table-view", XML_TABLE_VIEW ), + TOKEN( "tables", XML_TABLES ), + TOKEN( "tan", XML_TAN ), + TOKEN( "tanh", XML_TANH ), + TOKEN( "target-cell-address", XML_TARGET_CELL_ADDRESS ), + TOKEN( "target-frame", XML_TARGET_FRAME ), + TOKEN( "target-frame-name", XML_TARGET_FRAME_NAME ), + TOKEN( "target-range-address", XML_TARGET_RANGE_ADDRESS ), + TOKEN( "tb-rl", XML_TB_RL ), + TOKEN( "teal", XML_TEAL ), + TOKEN( "techreport", XML_TECHREPORT ), + TOKEN( "template", XML_TEMPLATE ), + TOKEN( "template-name", XML_TEMPLATE_NAME ), + TOKEN( "tendsto", XML_TENDSTO ), + TOKEN( "texture-filter", XML_TEX_FILTER ), + TOKEN( "texture-generation-mode-x", XML_TEX_GENERATION_MODE_X ), + TOKEN( "texture-generation-mode-y", XML_TEX_GENERATION_MODE_Y ), + TOKEN( "texture-kind", XML_TEX_KIND ), + TOKEN( "texture-mode", XML_TEX_MODE ), + TOKEN( "text", XML_TEXT ), + TOKEN( "text-align", XML_TEXT_ALIGN ), + TOKEN( "text-align-last", XML_TEXT_ALIGN_LAST ), + TOKEN( "text-align-source", XML_TEXT_ALIGN_SOURCE ), + TOKEN( "text-autospace", XML_TEXT_AUTOSPACE ), + TOKEN( "text-background-color", XML_TEXT_BACKGROUND_COLOR ), + TOKEN( "text-blinking", XML_TEXT_BLINKING ), + TOKEN( "text-box", XML_TEXT_BOX ), + TOKEN( "text-changes-only", XML_TEXT_CHANGES_ONLY ), + TOKEN( "text-color", XML_TEXT_COLOR ), + TOKEN( "text-combine", XML_TEXT_COMBINE ), + TOKEN( "text-combine-end-char", XML_TEXT_COMBINE_END_CHAR ), + TOKEN( "text-combine-start-char", XML_TEXT_COMBINE_START_CHAR ), + TOKEN( "text-content", XML_TEXT_CONTENT ), + TOKEN( "text-conversion-dictionary", XML_TEXT_CONVERSION_DICTIONARY ), + TOKEN( "text-crossing-out", XML_TEXT_CROSSING_OUT ), + TOKEN( "text-emphasize", XML_TEXT_EMPHASIZE ), + TOKEN( "text-global", XML_TEXT_GLOBAL ), + TOKEN( "text-indent", XML_TEXT_INDENT ), + TOKEN( "text-input", XML_TEXT_INPUT ), + TOKEN( "text-justify", XML_TEXT_JUSTIFY ), + TOKEN( "text-outline", XML_TEXT_OUTLINE ), + TOKEN( "text-only", XML_TEXT_ONLY ), + TOKEN( "text-position", XML_TEXT_POSITION ), + TOKEN( "text-rotation-angle", XML_TEXT_ROTATION_ANGLE ), + TOKEN( "text-rotation-scale", XML_TEXT_ROTATION_SCALE ), + TOKEN( "text-scale", XML_TEXT_SCALE ), + TOKEN( "text-shadow", XML_TEXT_SHADOW ), + TOKEN( "text-style", XML_TEXT_STYLE ), + TOKEN( "text-transform", XML_TEXT_TRANSFORM ), + TOKEN( "text-underline", XML_TEXT_UNDERLINE ), + TOKEN( "text-underline-color", XML_TEXT_UNDERLINE_COLOR ), + TOKEN( "textarea-horizontal-align", XML_TEXTAREA_HORIZONTAL_ALIGN ), + TOKEN( "textarea-vertical-align", XML_TEXTAREA_VERTICAL_ALIGN ), + TOKEN( "textual", XML_TEXTUAL ), + TOKEN( "thick", XML_THICK ), + TOKEN( "thin", XML_THIN ), + TOKEN( "three-dimensional", XML_THREE_DIMENSIONAL ), + TOKEN( "thumbnail", XML_THUMBNAIL ), + TOKEN( "tick-marks-major-inner", XML_TICK_MARKS_MAJOR_INNER ), + TOKEN( "tick-marks-major-outer", XML_TICK_MARKS_MAJOR_OUTER ), + TOKEN( "tick-marks-minor-inner", XML_TICK_MARKS_MINOR_INNER ), + TOKEN( "tick-marks-minor-outer", XML_TICK_MARKS_MINOR_OUTER ), + TOKEN( "tile-repeat-offset", XML_TILE_REPEAT_OFFSET ), + TOKEN( "time", XML_TIME ), + TOKEN( "time-adjust", XML_TIME_ADJUST ), + TOKEN( "time-style", XML_TIME_STYLE ), + TOKEN( "time-value", XML_TIME_VALUE ), + TOKEN( "times", XML_TIMES ), + TOKEN( "title", XML_TITLE ), + TOKEN( "to-another-table", XML_TO_ANOTHER_TABLE ), + TOKEN( "to-bottom", XML_TO_BOTTOM ), + TOKEN( "to-center", XML_TO_CENTER ), + TOKEN( "to-left", XML_TO_LEFT ), + TOKEN( "to-lower-left", XML_TO_LOWER_LEFT ), + TOKEN( "to-lower-right", XML_TO_LOWER_RIGHT ), + TOKEN( "to-right", XML_TO_RIGHT ), + TOKEN( "to-top", XML_TO_TOP ), + TOKEN( "to-upper-left", XML_TO_UPPER_LEFT ), + TOKEN( "to-upper-right", XML_TO_UPPER_RIGHT ), + TOKEN( "toc-mark", XML_TOC_MARK ), + TOKEN( "toc-mark-end", XML_TOC_MARK_END ), + TOKEN( "toc-mark-start", XML_TOC_MARK_START ), + TOKEN( "toggle", XML_TOGGLE ), + TOKEN( "top", XML_TOP ), + TOKEN( "top-left", XML_TOP_LEFT ), + TOKEN( "top percent", XML_TOP_PERCENT ), + TOKEN( "top-right", XML_TOP_RIGHT ), + TOKEN( "top values", XML_TOP_VALUES ), + TOKEN( "top-arc", XML_TOPARC ), + TOKEN( "top-circle", XML_TOPCIRCLE ), + TOKEN( "trace-dependents", XML_TRACE_DEPENDENTS ), + TOKEN( "trace-errors", XML_TRACE_ERRORS ), + TOKEN( "trace-precedents", XML_TRACE_PRECEDENTS ), + TOKEN( "track-changes", XML_TRACK_CHANGES ), + TOKEN( "tracked-changes", XML_TRACKED_CHANGES ), + TOKEN( "tracked-changes-view-settings", XML_TRACKED_CHANGES_VIEW_SETTINGS ), + TOKEN( "transform", XML_TRANSFORM ), + TOKEN( "transition-on-click", XML_TRANSITION_ON_CLICK ), + TOKEN( "transparency", XML_TRANSPARENCY ), + TOKEN( "transparency-name", XML_TRANSPARENCY_NAME ), + TOKEN( "transparent", XML_TRANSPARENT ), + TOKEN( "transpose", XML_TRANSPOSE ), + TOKEN( "true", XML_TRUE ), + TOKEN( "truncate-on-overflow", XML_TRUNCATE_ON_OVERFLOW ), + TOKEN( "try-staggering-first", XML_TRY_STAGGERING_FIRST ), + TOKEN( "tspan", XML_TSPAN ), + TOKEN( "ttb", XML_TTB ), + TOKEN( "type", XML_TYPE ), + TOKEN( "dot-dash", XML_DOT_DASH ), + TOKEN( "dot-dot-dash", XML_DOT_DOT_DASH ), + TOKEN( "long-dash", XML_LONG_DASH ), + TOKEN( "show-sign-date", XML_SHOW_SIGN_DATE ), + TOKEN( "signatureline", XML_SIGNATURELINE ), + TOKEN( "signing-instructions", XML_SIGNING_INSTRUCTIONS ), + TOKEN( "single", XML_SINGLE ), + TOKEN( "small-wave", XML_SMALL_WAVE ), + TOKEN( "suggested-signer-email", XML_SUGGESTED_SIGNER_EMAIL ), + TOKEN( "suggested-signer-name", XML_SUGGESTED_SIGNER_NAME ), + TOKEN( "suggested-signer-title", XML_SUGGESTED_SIGNER_TITLE ), + TOKEN( "wave", XML_WAVE ), + TOKEN( "unformatted-text", XML_UNFORMATTED_TEXT ), + TOKEN( "union", XML_UNION ), + TOKEN( "unit", XML_UNIT ), + TOKEN( "unordered-list", XML_UNORDERED_LIST ), + TOKEN( "unpublished", XML_UNPUBLISHED ), + TOKEN( "up", XML_UP ), + TOKEN( "uplimit", XML_UPLIMIT ), + TOKEN( "upright", XML_UPRIGHT ), + TOKEN( "url", XML_URL ), + TOKEN( "use", XML_USE ), + TOKEN( "use-caption", XML_USE_CAPTION ), + TOKEN( "use-cell-protection", XML_USE_CELL_PROTECTION ), + TOKEN( "use-chart-objects", XML_USE_CHART_OBJECTS ), + TOKEN( "use-condition", XML_USE_CONDITION ), + TOKEN( "use-draw-objects", XML_USE_DRAW_OBJECTS ), + TOKEN( "use-floating-frames", XML_USE_FLOATING_FRAMES ), + TOKEN( "use-graphics", XML_USE_GRAPHICS ), + TOKEN( "use-image-objects", XML_USE_IMAGE_OBJECTS ), + TOKEN( "use-index-marks", XML_USE_INDEX_MARKS ), + TOKEN( "use-index-source-styles", XML_USE_INDEX_SOURCE_STYLES ), + TOKEN( "use-keys-as-entries", XML_USE_KEYS_AS_ENTRIES ), + TOKEN( "use-label", XML_USE_LABEL ), + TOKEN( "use-math-objects", XML_USE_MATH_OBJECTS ), + TOKEN( "use-objects", XML_USE_OBJECTS ), + TOKEN( "use-optimal-column-width", XML_USE_OPTIMAL_COLUMN_WIDTH ), + TOKEN( "use-optimal-row-height", XML_USE_OPTIMAL_ROW_HEIGHT ), + TOKEN( "use-other-objects", XML_USE_OTHER_OBJECTS ), + TOKEN( "use-spreadsheet-objects", XML_USE_SPREADSHEET_OBJECTS ), + TOKEN( "use-styles", XML_USE_STYLES ), + TOKEN( "use-tables", XML_USE_TABLES ), + TOKEN( "use-window-font-color", XML_USE_WINDOW_FONT_COLOR ), + TOKEN( "used-hierarchy", XML_USED_HIERARCHY ), + TOKEN( "user-defined", XML_USER_DEFINED ), + TOKEN( "user-field-decl", XML_USER_FIELD_DECL ), + TOKEN( "user-field-decls", XML_USER_FIELD_DECLS ), + TOKEN( "user-field-get", XML_USER_FIELD_GET ), + TOKEN( "user-field-input", XML_USER_FIELD_INPUT ), + TOKEN( "user-index", XML_USER_INDEX ), + TOKEN( "user-index-entry-template", XML_USER_INDEX_ENTRY_TEMPLATE ), + TOKEN( "user-index-mark", XML_USER_INDEX_MARK ), + TOKEN( "user-index-mark-end", XML_USER_INDEX_MARK_END ), + TOKEN( "user-index-mark-start", XML_USER_INDEX_MARK_START ), + TOKEN( "user-index-source", XML_USER_INDEX_SOURCE ), + TOKEN( "user-transformed", XML_USER_TRANSFORMED ), + TOKEN( "username", XML_USERNAME ), + TOKEN( "validation", XML_VALIDATION ), + TOKEN( "value", XML_VALUE ), + TOKEN( "value-type", XML_VALUE_TYPE ), + TOKEN( "values-cell-range-address", XML_VALUES_CELL_RANGE_ADDRESS ), + TOKEN( "var", XML_VAR ), + TOKEN( "variable", XML_VARIABLE ), + TOKEN( "variable-decl", XML_VARIABLE_DECL ), + TOKEN( "variable-decls", XML_VARIABLE_DECLS ), + TOKEN( "variable-get", XML_VARIABLE_GET ), + TOKEN( "variable-input", XML_VARIABLE_INPUT ), + TOKEN( "variable-set", XML_VARIABLE_SET ), + TOKEN( "variance", XML_VARIANCE ), + TOKEN( "varp", XML_VARP ), + TOKEN( "vector", XML_VECTOR ), + TOKEN( "verb", XML_VERB ), + TOKEN( "version", XML_VERSION ), + TOKEN( "version-entry", XML_VERSION_ENTRY ), + TOKEN( "version-list", XML_VERSION_LIST ), + TOKEN( "vertical", XML_VERTICAL ), + TOKEN( "vertical-align", XML_VERTICAL_ALIGN ), + TOKEN( "vertical-justify", XML_VERTICAL_JUSTIFY ), + TOKEN( "vertical-lines", XML_VERTICAL_LINES ), + TOKEN( "vertical-pos", XML_VERTICAL_POS ), + TOKEN( "vertical-rel", XML_VERTICAL_REL ), + TOKEN( "vertical-segments", XML_VERTICAL_SEGMENTS ), + TOKEN( "vertical-split-mode", XML_VERTICAL_SPLIT_MODE ), + TOKEN( "vertical-split-position", XML_VERTICAL_SPLIT_POSITION ), + TOKEN( "vertical-stripes", XML_VERTICAL_STRIPES ), + TOKEN( "view", XML_VIEW ), + TOKEN( "viewBox", XML_VIEWBOX ), + TOKEN( "view-id", XML_VIEW_ID ), + TOKEN( "view-settings", XML_VIEW_SETTINGS ), + TOKEN( "visibility", XML_VISIBILITY ), + TOKEN( "visible", XML_VISIBLE ), + TOKEN( "visible-area", XML_VISIBLE_AREA ), + TOKEN( "visible-area-height", XML_VISIBLE_AREA_HEIGHT ), + TOKEN( "visible-area-left", XML_VISIBLE_AREA_LEFT ), + TOKEN( "visible-area-top", XML_VISIBLE_AREA_TOP ), + TOKEN( "visible-area-width", XML_VISIBLE_AREA_WIDTH ), + TOKEN( "visited-style-name", XML_VISITED_STYLE_NAME ), + TOKEN( "visual-effect", XML_VISUAL_EFFECT ), + TOKEN( "volatile", XML_VOLATILE ), + TOKEN( "volume", XML_VOLUME ), + TOKEN( "vpn", XML_VPN ), + TOKEN( "vrp", XML_VRP ), + TOKEN( "vup", XML_VUP ), + TOKEN( "wall", XML_WALL ), + TOKEN( "warning", XML_WARNING ), + TOKEN( "watermark", XML_WATERMARK ), + TOKEN( "wavyline", XML_WAVYLINE ), + TOKEN( "wavyline-from-bottom", XML_WAVYLINE_FROM_BOTTOM ), + TOKEN( "wavyline-from-left", XML_WAVYLINE_FROM_LEFT ), + TOKEN( "wavyline-from-right", XML_WAVYLINE_FROM_RIGHT ), + TOKEN( "wavyline-from-top", XML_WAVYLINE_FROM_TOP ), + TOKEN( "week-of-year", XML_WEEK_OF_YEAR ), + TOKEN( "white", XML_WHITE ), + TOKEN( "whole-page", XML_WHOLE_PAGE ), + TOKEN( "widows", XML_WIDOWS ), + TOKEN( "width", XML_WIDTH ), + TOKEN( "window-font-color", XML_WINDOW_FONT_COLOR ), + TOKEN( "word", XML_WORD ), + TOKEN( "word-count", XML_WORD_COUNT ), + TOKEN( "wrap", XML_WRAP ), + TOKEN( "wrap-contour", XML_WRAP_CONTOUR ), + TOKEN( "wrap-contour-mode", XML_WRAP_CONTOUR_MODE ), + TOKEN( "wrap-option", XML_WRAP_OPTION ), + TOKEN( "writing-mode", XML_WRITING_MODE ), + TOKEN( "www", XML_WWW ), + TOKEN( "x", XML_X ), + TOKEN( "x1", XML_X1 ), + TOKEN( "x2", XML_X2 ), + TOKEN( "x-mac-roman", XML_X_MAC_ROMAN ), + TOKEN( "x-symbol", XML_X_SYMBOL ), + TOKEN( "x-system", XML_X_SYSTEM ), + TOKEN( "xor", XML_XOR ), + TOKEN( "y", XML_Y ), + TOKEN( "y1", XML_Y1 ), + TOKEN( "y2", XML_Y2 ), + TOKEN( "year", XML_YEAR ), + TOKEN( "yellow", XML_YELLOW ), + TOKEN( "zero-values", XML_ZERO_VALUES ), + TOKEN( "z-index", XML_ZINDEX ), + TOKEN( "zoom-type", XML_ZOOM_TYPE ), + TOKEN( "zoom-value", XML_ZOOM_VALUE ), + + TOKEN( "enable", XML_ENABLE ), + TOKEN( "use-regular-expressions", XML_USE_REGULAR_EXPRESSIONS ), + TOKEN( "use-wildcards", XML_USE_WILDCARDS ), + TOKEN( "data-source-has-labels", XML_DATA_SOURCE_HAS_LABELS ), + TOKEN( "link-data-style-to-source", XML_LINK_DATA_STYLE_TO_SOURCE ), + TOKEN( "sort-algorithm", XML_SORT_ALGORITHM ), + TOKEN( "straight-line", XML_STRAIGHT_LINE ), + TOKEN( "angled-line", XML_ANGLED_LINE ), + TOKEN( "angled-connector-line", XML_ANGLED_CONNECTOR_LINE ), + + TOKEN( "application/x-www-form-urlencoded", XML_APPLICATION_X_WWW_FORM_URLENCODED ), + TOKEN( "multipart/formdata", XML_MULTIPART_FORMDATA ), + TOKEN( "application/text", XML_APPLICATION_TEXT ), + TOKEN( "get", XML_GET ), + TOKEN( "post", XML_POST ), + TOKEN( "query", XML_QUERY ), + TOKEN( "parent", XML_PARENT ), + TOKEN( "records", XML_RECORDS ), + TOKEN( "push", XML_PUSH ), + TOKEN( "submit", XML_SUBMIT ), + TOKEN( "reset", XML_RESET ), + TOKEN( "value-list", XML_VALUE_LIST ), + TOKEN( "sql", XML_SQL ), + TOKEN( "sql-pass-through", XML_SQL_PASS_THROUGH ), + TOKEN( "table-fields", XML_TABLE_FIELDS ), + TOKEN( "unchecked", XML_UNCHECKED ), + TOKEN( "checked", XML_CHECKED ), + TOKEN( "unknown", XML_UNKNOWN ), + + TOKEN( "roll-from-top", XML_ROLL_FROM_TOP ), + + TOKEN( "binary-data", XML_BINARY_DATA ), + TOKEN( "notify-on-update-of-table", XML_NOTIFY_ON_UPDATE_OF_TABLE ), + + TOKEN( "0", XML_0 ), + TOKEN( "play", XML_PLAY ), + TOKEN( "handout-master", XML_HANDOUT_MASTER ), + TOKEN( "text-style-name", XML_TEXT_STYLE_NAME ), + TOKEN( "escape-direction", XML_ESCAPE_DIRECTION ), + TOKEN( "glue-point", XML_GLUE_POINT ), + TOKEN( "primary-x", XML_PRIMARY_X ), + TOKEN( "secondary-x", XML_SECONDARY_X ), + TOKEN( "primary-y", XML_PRIMARY_Y ), + TOKEN( "secondary-y", XML_SECONDARY_Y ), + TOKEN( "primary-z", XML_PRIMARY_Z ), + + TOKEN( "caption-type", XML_CAPTION_TYPE ), + TOKEN( "caption-angle-type", XML_CAPTION_ANGLE_TYPE ), + TOKEN( "caption-angle", XML_CAPTION_ANGLE ), + TOKEN( "caption-gap", XML_CAPTION_GAP ), + TOKEN( "caption-escape-direction", XML_CAPTION_ESCAPE_DIRECTION ), + TOKEN( "caption-escape", XML_CAPTION_ESCAPE ), + TOKEN( "caption-line-length", XML_CAPTION_LINE_LENGTH ), + TOKEN( "caption-fit-line-length", XML_CAPTION_FIT_LINE_LENGTH ), + TOKEN( "free", XML_FREE ), + TOKEN( "transition-type", XML_TRANSITION_TYPE ), + TOKEN( "transition-style", XML_TRANSITION_STYLE ), + TOKEN( "transition-speed", XML_TRANSITION_SPEED ), + TOKEN( "duration", XML_DURATION ), + TOKEN( "background-size", XML_BACKGROUND_SIZE ), + TOKEN( "background-objects-visible", XML_BACKGROUND_OBJECTS_VISIBLE ), + TOKEN( "background-visible", XML_BACKGROUND_VISIBLE ), + + TOKEN( "move-from-upperleft", XML_MOVE_FROM_UPPERLEFT ), + TOKEN( "move-from-upperright", XML_MOVE_FROM_UPPERRIGHT ), + TOKEN( "move-from-lowerright", XML_MOVE_FROM_LOWERRIGHT ), + TOKEN( "move-from-lowerleft", XML_MOVE_FROM_LOWERLEFT ), + TOKEN( "uncover-to-left", XML_UNCOVER_TO_LEFT ), + TOKEN( "uncover-to-upperleft", XML_UNCOVER_TO_UPPERLEFT ), + TOKEN( "uncover-to-top", XML_UNCOVER_TO_TOP ), + TOKEN( "uncover-to-upperright", XML_UNCOVER_TO_UPPERRIGHT ), + TOKEN( "uncover-to-right", XML_UNCOVER_TO_RIGHT ), + TOKEN( "uncover-to-lowerright", XML_UNCOVER_TO_LOWERRIGHT ), + TOKEN( "uncover-to-bottom", XML_UNCOVER_TO_BOTTOM ), + TOKEN( "uncover-to-lowerleft", XML_UNCOVER_TO_LOWERLEFT ), + TOKEN( "vertical-checkerboard", XML_VERTICAL_CHECKERBOARD ), + TOKEN( "horizontal-checkerboard", XML_HORIZONTAL_CHECKERBOARD ), + + TOKEN( "notify-on-update-of-ranges", XML_NOTIFY_ON_UPDATE_OF_RANGES ), + + TOKEN( "byte", XML_BYTE ), + TOKEN( "macro", XML_MACRO ), + TOKEN( "location", XML_LOCATION ), + TOKEN( "application", XML_APPLICATION ), + + TOKEN( "symbol-image", XML_SYMBOL_IMAGE ), + TOKEN( "text-overlap", XML_TEXT_OVERLAP ), + TOKEN( "spline-order", XML_SPLINE_ORDER ), + TOKEN( "spline-resolution", XML_SPLINE_RESOLUTION ), + TOKEN( "paper-tray-name", XML_PAPER_TRAY_NAME ), + + TOKEN( "column-mapping", XML_COLUMN_MAPPING ), + TOKEN( "row-mapping", XML_ROW_MAPPING ), + + TOKEN( "table-formula", XML_TABLE_FORMULA ), + + TOKEN( "embedded-text", XML_EMBEDDED_TEXT ), + + TOKEN( "merge-last-paragraph", XML_MERGE_LAST_PARAGRAPH ), + + TOKEN( "stock-loss-marker", XML_STOCK_LOSS_MARKER ), + TOKEN( "stock-gain-marker", XML_STOCK_GAIN_MARKER ), + TOKEN( "stock-range-line", XML_STOCK_RANGE_LINE ), + + TOKEN( "rl-tb", XML_RL_TB ), + TOKEN( "tb-lr", XML_TB_LR ), + TOKEN( "bt-lr", XML_BT_LR ), + TOKEN( "lr", XML_LR ), + TOKEN( "rl", XML_RL ), + TOKEN( "tb", XML_TB ), + + TOKEN( "layout-grid-color", XML_LAYOUT_GRID_COLOR ), + TOKEN( "layout-grid-lines", XML_LAYOUT_GRID_LINES ), + TOKEN( "layout-grid-base-height", XML_LAYOUT_GRID_BASE_HEIGHT ), + TOKEN( "layout-grid-ruby-height", XML_LAYOUT_GRID_RUBY_HEIGHT ), + TOKEN( "layout-grid-mode", XML_LAYOUT_GRID_MODE ), + TOKEN( "layout-grid-ruby-below", XML_LAYOUT_GRID_RUBY_BELOW ), + TOKEN( "layout-grid-print", XML_LAYOUT_GRID_PRINT ), + TOKEN( "layout-grid-display", XML_LAYOUT_GRID_DISPLAY ), + + //text grid enhancement for better CJK support + TOKEN( "default-page-layout", XML_DEFAULT_PAGE_LAYOUT ), + TOKEN( "layout-grid-standard-mode", XML_LAYOUT_GRID_STANDARD_MODE ), + TOKEN( "layout-grid-base-width", XML_LAYOUT_GRID_BASE_WIDTH ), + TOKEN( "layout-grid-snap-to-characters", XML_LAYOUT_GRID_SNAP_TO_CHARS ), + TOKEN( "layout-grid-snap-to", XML_LAYOUT_GRID_SNAP_TO ), + + TOKEN( "snap-to-layout-grid", XML_SNAP_TO_LAYOUT_GRID ), + + TOKEN( "dont-balance-text-columns", XML_DONT_BALANCE_TEXT_COLUMNS ), + + TOKEN( "glyph-orientation-vertical", XML_GLYPH_ORIENTATION_VERTICAL ), + + TOKEN( "marked-invalid", XML_MARKED_INVALID ), + + // Regression curve & properties + TOKEN( "regression-curve", XML_REGRESSION_CURVE ), + TOKEN( "regression-type", XML_REGRESSION_TYPE ), + // Extended regression curve properties - ODF 1.2 extended + TOKEN( "regression-name", XML_REGRESSION_CURVE_NAME ), + TOKEN( "regression-extrapolate-forward", XML_REGRESSION_EXTRAPOLATE_FORWARD ), + TOKEN( "regression-extrapolate-backward", XML_REGRESSION_EXTRAPOLATE_BACKWARD ), + TOKEN( "regression-max-degree", XML_REGRESSION_MAX_DEGREE ), + TOKEN( "regression-min-degree", XML_REGRESSION_MIN_DEGREE ), + TOKEN( "regression-moving-type", XML_REGRESSION_MOVING_TYPE ), + TOKEN( "regression-period", XML_REGRESSION_PERIOD ), + TOKEN( "regression-force-intercept", XML_REGRESSION_FORCE_INTERCEPT ), + TOKEN( "regression-intercept-value", XML_REGRESSION_INTERCEPT_VALUE ), + TOKEN( "regression-x-name", XML_REGRESSION_X_NAME ), + TOKEN( "regression-y-name", XML_REGRESSION_Y_NAME ), + + TOKEN( "error-indicator", XML_ERROR_INDICATOR ), + + TOKEN( "table-type", XML_TABLE_TYPE ), + + TOKEN( "display-factor", XML_DISPLAY_FACTOR ), + + TOKEN( "transliteration-format", XML_TRANSLITERATION_FORMAT ), + TOKEN( "transliteration-language", XML_TRANSLITERATION_LANGUAGE ), + TOKEN( "transliteration-country", XML_TRANSLITERATION_COUNTRY ), + TOKEN( "transliteration-style", XML_TRANSLITERATION_STYLE ), + + TOKEN( "key1-phonetic", XML_KEY1_PHONETIC ), + TOKEN( "key2-phonetic", XML_KEY2_PHONETIC ), + TOKEN( "string-value-phonetic", XML_STRING_VALUE_PHONETIC ), + + TOKEN( "background-transparency", XML_BACKGROUND_TRANSPARENCY ), + TOKEN( "background-image-transparency", XML_BACKGROUND_IMAGE_TRANSPARENCY ), + + TOKEN( "dynamic-spacing", XML_DYNAMIC_SPACING ), + + TOKEN( "main-entry", XML_MAIN_ENTRY ), + + TOKEN( "use-outline-level", XML_USE_OUTLINE_LEVEL ), + + // #107245# New 3D properties which are possible for lathe and extrude 3d objects + TOKEN( "close-front", XML_CLOSE_FRONT ), + TOKEN( "close-back", XML_CLOSE_BACK ), + + TOKEN( "drop-down", XML_DROP_DOWN ), + TOKEN( "current-selected", XML_CURRENT_SELECTED ), + + TOKEN( "join-border", XML_JOIN_BORDER ), + + TOKEN( "display-list", XML_DISPLAY_LIST ), + TOKEN( "no", XML_NO ), + TOKEN( "unsorted", XML_UNSORTED ), + TOKEN( "font-independent-line-spacing", XML_FONT_INDEPENDENT_LINE_SPACING ), + + // Wrong! Do not write, use XML_SORT_ASCENDING instead. Only read. fdo#72548 + TOKEN( "sorted-ascending", XML_SORTED_ASCENDING ), + + TOKEN( "database", XML_DATABASE ), + TOKEN( "datasource", XML_DATASOURCE ), + TOKEN( "data-source", XML_DATA_SOURCE ), + TOKEN( "queries", XML_QUERIES ), + TOKEN( "reports", XML_REPORTS ), + TOKEN( "report", XML_REPORT ), + TOKEN( "as-template", XML_AS_TEMPLATE ), + + TOKEN( "connection-resource", XML_CONNECTION_RESOURCE ), + TOKEN( "suppress-version-columns", XML_SUPPRESS_VERSION_COLUMNS ), + TOKEN( "java-driver-class", XML_JAVA_DRIVER_CLASS ), + TOKEN( "extension", XML_EXTENSION ), + TOKEN( "is-first-row-header-line", XML_IS_FIRST_ROW_HEADER_LINE ), + TOKEN( "show-deleted", XML_SHOW_DELETED ), + TOKEN( "is-table-name-length-limited", XML_IS_TABLE_NAME_LENGTH_LIMITED ), + TOKEN( "system-driver-settings", XML_SYSTEM_DRIVER_SETTINGS ), + TOKEN( "enable-sql92-check", XML_ENABLE_SQL92_CHECK ), + TOKEN( "append-table-alias-name", XML_APPEND_TABLE_ALIAS_NAME ), + TOKEN( "parameter-name-substitution", XML_PARAMETER_NAME_SUBSTITUTION ), + TOKEN( "ignore-driver-privileges", XML_IGNORE_DRIVER_PRIVILEGES ), + TOKEN( "boolean-comparison-mode", XML_BOOLEAN_COMPARISON_MODE ), + TOKEN( "use-catalog", XML_USE_CATALOG ), + TOKEN( "base-dn", XML_BASE_DN ), + TOKEN( "max-row-count", XML_MAX_ROW_COUNT ), + TOKEN( "login", XML_LOGIN ), + TOKEN( "user-name", XML_USER_NAME ), + TOKEN( "is-password-required", XML_IS_PASSWORD_REQUIRED ), + TOKEN( "login-timeout", XML_LOGIN_TIMEOUT ), + TOKEN( "delimiter", XML_DELIMITER ), + TOKEN( "field", XML_FIELD ), + TOKEN( "decimal", XML_DECIMAL ), + TOKEN( "thousand", XML_THOUSAND ), + TOKEN( "table-filter", XML_TABLE_FILTER ), + TOKEN( "table-filter-pattern", XML_TABLE_FILTER_PATTERN ), + TOKEN( "table-type-filter", XML_TABLE_TYPE_FILTER ), + TOKEN( "auto-increment", XML_AUTO_INCREMENT ), + TOKEN( "additional-column-statement", XML_ADDITIONAL_COLUMN_STATEMENT ), + TOKEN( "row-retrieving-statement", XML_ROW_RETRIEVING_STATEMENT ), + TOKEN( "data-source-settings", XML_DATA_SOURCE_SETTINGS ), + TOKEN( "data-source-setting", XML_DATA_SOURCE_SETTING ), + TOKEN( "data-source-setting-value", XML_DATA_SOURCE_SETTING_VALUE ), + TOKEN( "data-source-setting-is-list", XML_DATA_SOURCE_SETTING_IS_LIST ), + TOKEN( "data-source-setting-type", XML_DATA_SOURCE_SETTING_TYPE ), + TOKEN( "data-source-setting-name", XML_DATA_SOURCE_SETTING_NAME ), + TOKEN( "component", XML_COMPONENT ), + TOKEN( "component-collection", XML_COMPONENT_COLLECTION ), + TOKEN( "query-collection", XML_QUERY_COLLECTION ), + TOKEN( "update-table", XML_UPDATE_TABLE ), + TOKEN( "filter-statement", XML_FILTER_STATEMENT ), + TOKEN( "order-statement", XML_ORDER_STATEMENT ), + TOKEN( "escape-processing", XML_ESCAPE_PROCESSING ), + TOKEN( "keys", XML_KEYS ), + TOKEN( "indices", XML_INDICES ), + TOKEN( "type-name", XML_TYPE_NAME ), + TOKEN( "precision", XML_PRECISION ), + TOKEN( "is-nullable", XML_IS_NULLABLE ), + TOKEN( "is-autoincrement", XML_IS_AUTOINCREMENT ), + TOKEN( "default-value", XML_DEFAULT_VALUE ), + TOKEN( "referenced-table-name", XML_REFERENCED_TABLE_NAME ), + TOKEN( "update-rule", XML_UPDATE_RULE ), + TOKEN( "delete-rule", XML_DELETE_RULE ), + TOKEN( "key-columns", XML_KEY_COLUMNS ), + TOKEN( "key-column", XML_KEY_COLUMN ), + TOKEN( "related-column-name", XML_RELATED_COLUMN_NAME ), + TOKEN( "catalog-name", XML_CATALOG_NAME ), + TOKEN( "is-unique", XML_IS_UNIQUE ), + TOKEN( "is-clustered", XML_IS_CLUSTERED ), + TOKEN( "index-columns", XML_INDEX_COLUMNS ), + TOKEN( "index-column", XML_INDEX_COLUMN ), + TOKEN( "is-ascending", XML_IS_ASCENDING ), + TOKEN( "schema-name", XML_SCHEMA_NAME ), + TOKEN( "db", XML_NP_DB ), + TOKEN( "http://openoffice.org/2004/database", XML_N_DB ), + TOKEN( "apply-filter", XML_APPLY_FILTER ), + TOKEN( "apply-order", XML_APPLY_ORDER ), + TOKEN( "automatic-print-range", XML_AUTOMATIC_PRINT_RANGE ), + + TOKEN( "selection", XML_SELECTION ), + TOKEN( "selection-indexes", XML_SELECTION_INDEXES ), + + TOKEN( "scale-to-X", XML_SCALE_TO_X ), + TOKEN( "scale-to-Y", XML_SCALE_TO_Y ), + + TOKEN( "keep-together", XML_KEEP_TOGETHER ), + + TOKEN( "use-header-name", XML_USE_HEADER_NAME ), + TOKEN( "use-footer-name", XML_USE_FOOTER_NAME ), + TOKEN( "use-date-time-name", XML_USE_DATE_TIME_NAME ), + TOKEN( "display-header", XML_DISPLAY_HEADER ), + TOKEN( "display-footer", XML_DISPLAY_FOOTER ), + TOKEN( "display-page-number", XML_DISPLAY_PAGE_NUMBER ), + TOKEN( "display-date-time", XML_DISPLAY_DATE_TIME ), + TOKEN( "source" , XML_SOURCE ), + TOKEN( "current-date", XML_CURRENT_DATE ), + + TOKEN( "header-decl", XML_HEADER_DECL ), + TOKEN( "footer-decl", XML_FOOTER_DECL ), + TOKEN( "date-time-decl", XML_DATE_TIME_DECL ), + + TOKEN( "selected-page", XML_SELECTED_PAGE ), + + // DVO, OD 01.10.2003 #i18732# + TOKEN( "flow-with-text", XML_FLOW_WITH_TEXT ), + TOKEN( "with-tab", XML_WITH_TAB ), // #i21237# + + TOKEN( "custom-shape" , XML_CUSTOM_SHAPE ), + TOKEN( "engine" , XML_ENGINE ), + TOKEN( "enhanced-geometry" , XML_ENHANCED_GEOMETRY ), + TOKEN( "text-rotate-angle" , XML_TEXT_ROTATE_ANGLE ), + TOKEN( "mirror-vertical" , XML_MIRROR_VERTICAL ), + TOKEN( "mirror-horizontal" , XML_MIRROR_HORIZONTAL ), + TOKEN( "extrusion-allowed" , XML_EXTRUSION_ALLOWED ), + TOKEN( "text-path-allowed" , XML_TEXT_PATH_ALLOWED ), + TOKEN( "concentric-gradient-fill-allowed" , XML_CONCENTRIC_GRADIENT_FILL_ALLOWED ), + TOKEN( "extrusion" , XML_EXTRUSION ), + TOKEN( "extrusion-brightness" , XML_EXTRUSION_BRIGHTNESS ), + TOKEN( "extrusion-depth" , XML_EXTRUSION_DEPTH ), + TOKEN( "extrusion-diffusion" , XML_EXTRUSION_DIFFUSION ), + TOKEN( "extrusion-number-of-line-segments" , XML_EXTRUSION_NUMBER_OF_LINE_SEGMENTS ), + TOKEN( "extrusion-light-face" , XML_EXTRUSION_LIGHT_FACE ), + TOKEN( "extrusion-first-light-harsh" , XML_EXTRUSION_FIRST_LIGHT_HARSH ), + TOKEN( "extrusion-second-light-harsh" , XML_EXTRUSION_SECOND_LIGHT_HARSH ), + TOKEN( "extrusion-first-light-level" , XML_EXTRUSION_FIRST_LIGHT_LEVEL ), + TOKEN( "extrusion-second-light-level" , XML_EXTRUSION_SECOND_LIGHT_LEVEL ), + TOKEN( "extrusion-first-light-direction" , XML_EXTRUSION_FIRST_LIGHT_DIRECTION ), + TOKEN( "extrusion-second-light-direction" , XML_EXTRUSION_SECOND_LIGHT_DIRECTION ), + TOKEN( "extrusion-metal" , XML_EXTRUSION_METAL ), + TOKEN( "extrusion-metal-type" , XML_EXTRUSION_METAL_TYPE ), + TOKEN( "extrusion-rotation-angle" , XML_EXTRUSION_ROTATION_ANGLE ), + TOKEN( "extrusion-rotation-center" , XML_EXTRUSION_ROTATION_CENTER ), + TOKEN( "extrusion-shininess" , XML_EXTRUSION_SHININESS ), + TOKEN( "extrusion-skew" , XML_EXTRUSION_SKEW ), + TOKEN( "extrusion-specularity" , XML_EXTRUSION_SPECULARITY ), + TOKEN( "extrusion-specularity-loext", XML_EXTRUSION_SPECULARITY_LOEXT ), + TOKEN( "extrusion-projection-mode" , XML_EXTRUSION_PROJECTION_MODE ), + TOKEN( "extrusion-viewpoint" , XML_EXTRUSION_VIEWPOINT ), + TOKEN( "extrusion-origin" , XML_EXTRUSION_ORIGIN ), + TOKEN( "extrusion-color" , XML_EXTRUSION_COLOR ), + TOKEN( "secondary-fill-color" , XML_SECONDARY_FILL_COLOR ), + TOKEN( "enhanced-path" , XML_ENHANCED_PATH ), + TOKEN( "path-stretchpoint-x" , XML_PATH_STRETCHPOINT_X ), + TOKEN( "path-stretchpoint-y" , XML_PATH_STRETCHPOINT_Y ), + TOKEN( "text-areas" , XML_TEXT_AREAS ), + TOKEN( "glue-points" , XML_GLUE_POINTS ), + TOKEN( "glue-point-type" , XML_GLUE_POINT_TYPE ), + TOKEN( "glue-point-leaving-direction" , XML_GLUE_POINT_LEAVING_DIRECTIONS ), + TOKEN( "text-path" , XML_TEXT_PATH ), + TOKEN( "text-path-mode" , XML_TEXT_PATH_MODE ), + TOKEN( "text-path-scale" , XML_TEXT_PATH_SCALE ), + TOKEN( "text-path-same-letter-heights" , XML_TEXT_PATH_SAME_LETTER_HEIGHTS ), + TOKEN( "modifiers" , XML_MODIFIERS ), + TOKEN( "equation" , XML_EQUATION ), + TOKEN( "xstretch", XML_XSTRETCH ), + TOKEN( "ystretch", XML_YSTRETCH ), + TOKEN( "hasstroke", XML_HASSTROKE ), + TOKEN( "hasfill", XML_HASFILL ), + TOKEN( "logwidth", XML_LOGWIDTH ), + TOKEN( "logheight", XML_LOGHEIGHT ), + TOKEN( "handle" , XML_HANDLE ), + TOKEN( "handle-mirror-vertical" , XML_HANDLE_MIRROR_VERTICAL ), + TOKEN( "handle-mirror-horizontal" , XML_HANDLE_MIRROR_HORIZONTAL ), + TOKEN( "handle-switched" , XML_HANDLE_SWITCHED ), + TOKEN( "handle-position" , XML_HANDLE_POSITION ), + TOKEN( "handle-range-x-minimum" , XML_HANDLE_RANGE_X_MINIMUM ), + TOKEN( "handle-range-x-maximum" , XML_HANDLE_RANGE_X_MAXIMUM ), + TOKEN( "handle-range-y-minimum" , XML_HANDLE_RANGE_Y_MINIMUM ), + TOKEN( "handle-range-y-maximum" , XML_HANDLE_RANGE_Y_MAXIMUM ), + TOKEN( "handle-polar" , XML_HANDLE_POLAR ), + TOKEN( "handle-radius-range-minimum" , XML_HANDLE_RADIUS_RANGE_MINIMUM ), + TOKEN( "handle-radius-range-maximum" , XML_HANDLE_RADIUS_RANGE_MAXIMUM ), + TOKEN( "rectangle" , XML_RECTANGLE ), + TOKEN( "roundrectangle" , XML_ROUNDRECTANGLE ), + TOKEN( "oval" , XML_OVAL ), + TOKEN( "cloud" , XML_CLOUD ), + TOKEN( "boundingcube" , XML_BOUNDINGCUBE ), + TOKEN( "wireframe" , XML_WIREFRAME ), + TOKEN( "segments" , XML_SEGMENTS ), + TOKEN( "word-wrap" , XML_WORD_WRAP ), + TOKEN( "collapsing" , XML_COLLAPSING ), + TOKEN( "separating" , XML_SEPARATING ), + TOKEN( "border-model" , XML_BORDER_MODEL ), + TOKEN( "data-pilot-field-reference", XML_DATA_PILOT_FIELD_REFERENCE ), + TOKEN( "member-difference", XML_MEMBER_DIFFERENCE ), + TOKEN( "member-percentage", XML_MEMBER_PERCENTAGE ), + TOKEN( "member-percentage-difference", XML_MEMBER_PERCENTAGE_DIFFERENCE ), + TOKEN( "running-total", XML_RUNNING_TOTAL ), + TOKEN( "row-percentage", XML_ROW_PERCENTAGE ), + TOKEN( "column-percentage", XML_COLUMN_PERCENTAGE ), + TOKEN( "total-percentage", XML_TOTAL_PERCENTAGE ), + TOKEN( "field-name", XML_FIELD_NAME ), + TOKEN( "member-type", XML_MEMBER_TYPE ), + TOKEN( "named", XML_NAMED ), + TOKEN( "member-name", XML_MEMBER_NAME ), + TOKEN( "display-member-mode", XML_DISPLAY_MEMBER_MODE ), + TOKEN( "member-count", XML_MEMBER_COUNT ), + TOKEN( "data-field", XML_DATA_FIELD ), + TOKEN( "data-pilot-display-info", XML_DATA_PILOT_DISPLAY_INFO ), + TOKEN( "sort-mode", XML_SORT_MODE ), + TOKEN( "data-pilot-sort-info", XML_DATA_PILOT_SORT_INFO ), + TOKEN( "add-empty-lines", XML_ADD_EMPTY_LINES ), + TOKEN( "tabular-layout", XML_TABULAR_LAYOUT ), + TOKEN( "outline-subtotals-top", XML_OUTLINE_SUBTOTALS_TOP ), + TOKEN( "outline-subtotals-bottom", XML_OUTLINE_SUBTOTALS_BOTTOM ), + TOKEN( "layout-mode", XML_LAYOUT_MODE ), + TOKEN( "data-pilot-layout-info", XML_DATA_PILOT_LAYOUT_INFO ), + TOKEN( "symbol-color", XML_SYMBOL_COLOR ), + TOKEN( "3d" , XML_3D ), + TOKEN( "image-position" , XML_IMAGE_POSITION ), + TOKEN( "image-align" , XML_IMAGE_ALIGN ), + TOKEN( "diagonal-bl-tr", XML_DIAGONAL_BL_TR ), + TOKEN( "diagonal-bl-tr-width", XML_DIAGONAL_BL_TR_WIDTH ), + TOKEN( "diagonal-tl-br", XML_DIAGONAL_TL_BR ), + TOKEN( "diagonal-tl-br-width", XML_DIAGONAL_TL_BR_WIDTH ), + TOKEN( "repeat-content", XML_REPEAT_CONTENT ), + TOKEN( "shrink-to-fit", XML_SHRINK_TO_FIT ), + + // OD 2004-05-05 #i28701# + TOKEN( "wrap-influence-on-position", XML_WRAP_INFLUENCE_ON_POSITION ), + // Tokens have been renamed and has been added (#i35017#) + TOKEN( "once-successive", XML_ONCE_SUCCESSIVE ), + TOKEN( "once-concurrent", XML_ONCE_CONCURRENT ), + TOKEN( "allow-overlap", XML_ALLOW_OVERLAP ), + + // Names for OOo format only + TOKEN( "http://openoffice.org/2000/office", XML_N_OFFICE_OOO ), + TOKEN( "http://openoffice.org/2000/meta", XML_N_META_OOO ), + TOKEN( "http://openoffice.org/2000/style", XML_N_STYLE_OOO ), + TOKEN( "http://openoffice.org/2000/datastyle", XML_N_NUMBER_OOO ), + TOKEN( "http://openoffice.org/2000/text", XML_N_TEXT_OOO ), + TOKEN( "http://openoffice.org/2000/table", XML_N_TABLE_OOO ), + TOKEN( "http://openoffice.org/2000/drawing", XML_N_DRAW_OOO ), + TOKEN( "http://openoffice.org/2000/dr3d", XML_N_DR3D_OOO ), + TOKEN( "http://openoffice.org/2000/presentation",XML_N_PRESENTATION_OOO ), + TOKEN( "urn:oasis:names:tc:openoffice:xmlns:presentation:1.0",XML_N_PRESENTATION_OASIS ), + TOKEN( "http://openoffice.org/2000/chart", XML_N_CHART_OOO ), + TOKEN( "http://openoffice.org/2001/config", XML_N_CONFIG_OOO ), + TOKEN( "http://openoffice.org/2000/form", XML_N_FORM_OOO ), + TOKEN( "http://openoffice.org/2000/script", XML_N_SCRIPT_OOO ), + + TOKEN( "global", XML_GLOBAL ), + + TOKEN( "note-class", XML_NOTE_CLASS ), + TOKEN( "note-citation", XML_NOTE_CITATION ), + TOKEN( "note-body", XML_NOTE_BODY ), + TOKEN( "notes-configuration", XML_NOTES_CONFIGURATION ), + TOKEN( "note-ref", XML_NOTE_REF ), + TOKEN( "is-sub-table", XML_IS_SUB_TABLE ), + TOKEN( "page-layout", XML_PAGE_LAYOUT ), + TOKEN( "page-layout-name", XML_PAGE_LAYOUT_NAME ), + TOKEN( "graphic-properties", XML_GRAPHIC_PROPERTIES ), + TOKEN( "drawing-page-properties", XML_DRAWING_PAGE_PROPERTIES ), + TOKEN( "page-layout-properties", XML_PAGE_LAYOUT_PROPERTIES ), + TOKEN( "header-footer-properties", XML_HEADER_FOOTER_PROPERTIES ), + TOKEN( "text-properties", XML_TEXT_PROPERTIES ), + TOKEN( "paragraph-properties", XML_PARAGRAPH_PROPERTIES ), + TOKEN( "ruby-properties", XML_RUBY_PROPERTIES ), + TOKEN( "section-properties", XML_SECTION_PROPERTIES ), + TOKEN( "table-properties", XML_TABLE_PROPERTIES ), + TOKEN( "table-column-properties", XML_TABLE_COLUMN_PROPERTIES ), + TOKEN( "table-row-properties", XML_TABLE_ROW_PROPERTIES ), + TOKEN( "table-cell-properties", XML_TABLE_CELL_PROPERTIES ), + TOKEN( "list-level-properties", XML_LIST_LEVEL_PROPERTIES ), + TOKEN( "chart-properties", XML_CHART_PROPERTIES ), + TOKEN( "drawing-page", XML_DRAWING_PAGE ), + TOKEN( "graphics", XML_GRAPHICS ), + TOKEN( "tab", XML_TAB ), + TOKEN( "text-underline-mode", XML_TEXT_UNDERLINE_MODE ), + TOKEN( "text-line-through-mode", XML_TEXT_LINE_THROUGH_MODE ), + TOKEN( "continuous", XML_CONTINUOUS ), + TOKEN( "skip-white-space", XML_SKIP_WHITE_SPACE ), + TOKEN( "scripts", XML_SCRIPTS ), + TOKEN( "font-face-decls", XML_FONT_FACE_DECLS ), + TOKEN( "font-face", XML_FONT_FACE ), + TOKEN( "font-face-src", XML_FONT_FACE_SRC ), + TOKEN( "font-face-uri", XML_FONT_FACE_URI ), + TOKEN( "font-face-format", XML_FONT_FACE_FORMAT ), + TOKEN( "font-adornments", XML_FONT_ADORNMENTS ), + TOKEN( "inch", XML_INCH ), + TOKEN( "space-after", XML_SPACE_AFTER ), + TOKEN( "start-indent", XML_START_INDENT ), + TOKEN( "end-indent", XML_END_INDENT ), + + // chart Oasis format additions + TOKEN( "interval-minor-divisor", XML_INTERVAL_MINOR_DIVISOR ), + TOKEN( "date-string", XML_DATE_STRING ), + + TOKEN( "text-underline-style", XML_TEXT_UNDERLINE_STYLE ), + TOKEN( "text-underline-type", XML_TEXT_UNDERLINE_TYPE ), + TOKEN( "text-underline-width", XML_TEXT_UNDERLINE_WIDTH ), + + TOKEN( "text-overline-type", XML_TEXT_OVERLINE_TYPE ), + TOKEN( "text-overline-style", XML_TEXT_OVERLINE_STYLE ), + TOKEN( "text-overline-width", XML_TEXT_OVERLINE_WIDTH ), + TOKEN( "text-overline-color", XML_TEXT_OVERLINE_COLOR ), + TOKEN( "text-overline-mode", XML_TEXT_OVERLINE_MODE ), + + TOKEN( "text-line-through-style", XML_TEXT_LINE_THROUGH_STYLE ), + TOKEN( "text-line-through-type", XML_TEXT_LINE_THROUGH_TYPE ), + TOKEN( "text-line-through-width", XML_TEXT_LINE_THROUGH_WIDTH ), + TOKEN( "text-line-through-text", XML_TEXT_LINE_THROUGH_TEXT ), + + TOKEN( "leader-style", XML_LEADER_STYLE ), + TOKEN( "leader-text", XML_LEADER_TEXT ), + + TOKEN( "bold-dotted", XML_BOLD_DOTTED ), + TOKEN( "bold-dash", XML_BOLD_DASH ), + TOKEN( "bold-long-dash", XML_BOLD_LONG_DASH ), + TOKEN( "bold-dot-dash", XML_BOLD_DOT_DASH ), + TOKEN( "bold-dot-dot-dash", XML_BOLD_DOT_DOT_DASH ), + TOKEN( "bold-wave", XML_BOLD_WAVE ), + TOKEN( "double-wave", XML_DOUBLE_WAVE ), + TOKEN( "double-line", XML_DOUBLE_LINE ), + TOKEN( "thick-line", XML_THICK_LINE ), + TOKEN( "single-line", XML_SINGLE_LINE ), + TOKEN( "slash", XML_SLASH ), + TOKEN( "text-line-through-color", XML_TEXT_LINE_THROUGH_COLOR ), + TOKEN( "text-line-through-text-style", XML_TEXT_LINE_THROUGH_TEXT_STYLE ), + TOKEN( "leader-color", XML_LEADER_COLOR ), + TOKEN( "leader-type", XML_LEADER_TYPE ), + TOKEN( "leader-width", XML_LEADER_WIDTH ), + TOKEN( "leader-text-style", XML_LEADER_TEXT_STYLE ), + + TOKEN( "opacity", XML_OPACITY ), + TOKEN( "opacity-name", XML_OPACITY_NAME ), + TOKEN( "shadow-opacity", XML_SHADOW_OPACITY ), + TOKEN( "always", XML_ALWAYS ), + TOKEN( "count-in-text-boxes", XML_COUNT_IN_TEXT_BOXES ), + + TOKEN( "ooo", XML_NP_OOO ), + TOKEN( "http://openoffice.org/2004/office", XML_N_OOO ), + TOKEN( "ooow", XML_NP_OOOW ), + TOKEN( "http://openoffice.org/2004/writer", XML_N_OOOW ), + TOKEN( "oooc", XML_NP_OOOC ), + TOKEN( "http://openoffice.org/2004/calc", XML_N_OOOC ), + TOKEN( "dom", XML_NP_DOM ), + TOKEN( "http://www.w3.org/2001/xml-events", XML_N_DOM ), + + TOKEN( "event-listeners", XML_EVENT_LISTENERS ), + TOKEN( "event-listener", XML_EVENT_LISTENER ), + + TOKEN( "form", XML_FORM ), + TOKEN( "void", XML_VOID ), + TOKEN( "property", XML_PROPERTY ), + TOKEN( "property-name", XML_PROPERTY_NAME ), + TOKEN( "list-property", XML_LIST_PROPERTY ), + TOKEN( "list-value", XML_LIST_VALUE ), + TOKEN( "column-style-name", XML_COLUMN_STYLE_NAME ), + TOKEN( "textarea", XML_TEXTAREA ), + TOKEN( "fixed-text", XML_FIXED_TEXT ), + TOKEN( "file", XML_FILE ), + TOKEN( "formatted-text", XML_FORMATTED_TEXT ), + TOKEN( "button", XML_BUTTON ), + TOKEN( "checkbox", XML_CHECKBOX ), + TOKEN( "radio", XML_RADIO ), + TOKEN( "listbox", XML_LISTBOX ), + TOKEN( "combobox", XML_COMBOBOX ), + TOKEN( "image-frame", XML_IMAGE_FRAME ), + TOKEN( "value-range", XML_VALUE_RANGE ), + TOKEN( "generic-control", XML_GENERIC_CONTROL ), + TOKEN( "service-name", XML_SERVICE_NAME ), + TOKEN( "property-type", XML_PROPERTY_TYPE ), + TOKEN( "integer", XML_INTEGER ), + TOKEN( "property-is-void", XML_PROPERTY_IS_VOID ), + TOKEN( "property-is-list", XML_PROPERTY_IS_LIST ), + TOKEN( "property-value", XML_PROPERTY_VALUE ), + TOKEN( "mimetype", XML_MIMETYPE ), + TOKEN( "database-row-select", XML_DATABASE_ROW_SELECT ), + TOKEN( "control-implementation", XML_CONTROL_IMPLEMENTATION ), + TOKEN( "interpolation", XML_INTERPOLATION ), + TOKEN( "cubic-spline", XML_CUBIC_SPLINE ), + TOKEN( "b-spline", XML_B_SPLINE ), + TOKEN( "step-start", XML_STEP_START ), + TOKEN( "step-end", XML_STEP_END ), + TOKEN( "step-center-x", XML_STEP_CENTER_X ), + TOKEN( "step-center-y", XML_STEP_CENTER_Y ), + // the gnm: values should only used for reading Gnumeric ods file + // these values should never be written + TOKEN( "gnm:step-start", XML_GNM_STEP_START ), + TOKEN( "gnm:step-end", XML_GNM_STEP_END ), + TOKEN( "gnm:step-center-x", XML_GNM_STEP_CENTER_X ), + TOKEN( "gnm:step-center-y", XML_GNM_STEP_CENTER_Y ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:database:1.0", XML_N_DB_OASIS ), + + TOKEN( "show-filter-button", XML_SHOW_FILTER_BUTTON ), + TOKEN( "drill-down-on-double-click", XML_DRILL_DOWN_ON_DOUBLE_CLICK ), + TOKEN( "header-grid-layout", XML_HEADER_GRID_LAYOUT ), + TOKEN( "grouped-by", XML_GROUPED_BY ), + TOKEN( "days", XML_DAYS ), + TOKEN( "months", XML_MONTHS ), + TOKEN( "quarters", XML_QUARTERS ), + TOKEN( "years", XML_YEARS ), + TOKEN( "date-start", XML_DATE_START ), + TOKEN( "date-end", XML_DATE_END ), + TOKEN( "step", XML_STEP ), + TOKEN( "data-pilot-groups", XML_DATA_PILOT_GROUPS ), + TOKEN( "data-pilot-group", XML_DATA_PILOT_GROUP ), + TOKEN( "data-pilot-group-member", XML_DATA_PILOT_GROUP_MEMBER ), + TOKEN( "japanese-candle-stick", XML_JAPANESE_CANDLE_STICK ), + TOKEN( "named-symbol", XML_NAMED_SYMBOL ), + TOKEN( "diamond", XML_DIAMOND ), + TOKEN( "arrow-down", XML_ARROW_DOWN ), + TOKEN( "arrow-up", XML_ARROW_UP ), + TOKEN( "arrow-right", XML_ARROW_RIGHT ), + TOKEN( "arrow-left", XML_ARROW_LEFT ), + TOKEN( "bow-tie", XML_BOW_TIE ), + TOKEN( "hourglass", XML_HOURGLASS ), + TOKEN( "symbol-name", XML_SYMBOL_NAME ), + TOKEN( "symbol-type", XML_SYMBOL_TYPE ), + TOKEN( "image-opacity", XML_IMAGE_OPACITY ), // #i25616# + + TOKEN( "default-outline-level", XML_DEFAULT_OUTLINE_LEVEL ), + TOKEN( "show-details", XML_SHOW_DETAILS ), + TOKEN( "show-empty", XML_SHOW_EMPTY ), + TOKEN( "repeat-item-labels", XML_REPEAT_ITEM_LABELS ), + TOKEN( "iterative", XML_ITERATIVE ), + + TOKEN( "X", XML_uX ), + TOKEN( "dlg", XML_NP_DLG ), + TOKEN( "http://openoffice.org/2000/dialog", XML_N_DLG ), + TOKEN( "script-data", XML_SCRIPT_DATA ), + TOKEN( "libraries", XML_LIBRARIES ), + TOKEN( "source-code", XML_SOURCE_CODE ), + TOKEN( "readonly", XML_READONLY ), + TOKEN( "z", XML_Z ), + TOKEN( "dimension", XML_DIMENSION ), + TOKEN( "validation-name", XML_VALIDATION_NAME ), + + TOKEN( "screen", XML_SCREEN ), + TOKEN( "printer", XML_PRINTER ), + + // XForms token + TOKEN( "model", XML_MODEL ), + TOKEN( "schema", XML_SCHEMA ), + TOKEN( "bind", XML_BIND ), + TOKEN( "instance", XML_INSTANCE ), + TOKEN( "submission", XML_SUBMISSION ), + TOKEN( "ref", XML_REF ), + TOKEN( "src", XML_SRC ), + TOKEN( "method", XML_METHOD ), + TOKEN( "nodeset", XML_NODESET ), + TOKEN( "indent", XML_INDENT ), + TOKEN( "omit-xml-declaration", XML_OMIT_XML_DECLARATION ), + TOKEN( "standalone", XML_STANDALONE ), + TOKEN( "cdata-section-elements", XML_CDATA_SECTION_ELEMENTS ), + TOKEN( "required", XML_REQUIRED ), + TOKEN( "relevant", XML_RELEVANT ), + TOKEN( "calculate", XML_CALCULATE ), + TOKEN( "constraint", XML_CONSTRAINT ), + TOKEN( "maxOccurs", XML_MAXOCCURS /* (maxOccurs) */ ), + TOKEN( "minOccurs", XML_MINOCCURS /* (minOccurs) */ ), + TOKEN( "p3ptype", XML_P3PTYPE ), + TOKEN( "mediatype", XML_MEDIATYPE ), + TOKEN( "includenamespaceprefixes", XML_INCLUDENAMESPACEPREFIXES ), + + // XForms/XSD Schema tokens + TOKEN( "base", XML_BASE ), + TOKEN( "targetNamespace", XML_TARGETNAMESPACE ), + TOKEN( "simpleType", XML_SIMPLETYPE ), + TOKEN( "restriction", XML_RESTRICTION ), + TOKEN( "maxLength", XML_MAXLENGTH ), + TOKEN( "minLength", XML_MINLENGTH ), + TOKEN( "minInclusive", XML_MININCLUSIVE ), + TOKEN( "minExclusive", XML_MINEXCLUSIVE ), + TOKEN( "maxInclusive", XML_MAXINCLUSIVE ), + TOKEN( "maxExclusive", XML_MAXEXCLUSIVE ), + TOKEN( "pattern", XML_PATTERN ), + TOKEN( "enumeration", XML_ENUMERATION ), + TOKEN( "whiteSpace", XML_WHITESPACE ), + TOKEN( "totalDigits", XML_TOTALDIGITS ), + TOKEN( "fractionDigits", XML_FRACTIONDIGITS ), + TOKEN( "preserve", XML_PRESERVE ), + TOKEN( "anyURI", XML_ANYURI ), + TOKEN( "dateTime", XML_DATETIME_XSD ), + TOKEN( "main-etry", XML_MAIN_ETRY), + + TOKEN( "remove", XML_REMOVE ), + TOKEN( "hold", XML_HOLD ), + TOKEN( "transition", XML_TRANSITION ), + TOKEN( "inherit", XML_INHERIT ), + TOKEN( "fillDefault", XML_FILLDEFAULT ), + TOKEN( "restart", XML_RESTART ), + TOKEN( "restartDefault", XML_RESTARTDEFAULT ), + TOKEN( "whenNotActive", XML_WHENNOTACTIVE ), + TOKEN( "never", XML_NEVER ), + TOKEN( "accelerate", XML_ACCELERATE ), + TOKEN( "decelerate", XML_DECELERATE ), + TOKEN( "autoReverse", XML_AUTOREVERSE ), + TOKEN( "indefinite", XML_INDEFINITE ), + TOKEN( "repeatCount", XML_REPEATCOUNT ), + TOKEN( "repeatDur", XML_REPEATDUR ), + TOKEN( "endsync", XML_ENDSYNC ), + TOKEN( "first", XML_FIRST ), + TOKEN( "last", XML_LAST ), + TOKEN( "media", XML_MEDIA ), + TOKEN( "dur", XML_DUR ), + TOKEN( "begin", XML_BEGIN ), + TOKEN( "whole", XML_WHOLE ), + TOKEN( "from", XML_FROM ), + TOKEN( "to", XML_TO ), + TOKEN( "by", XML_BY ), + TOKEN( "values", XML_VALUES ), + TOKEN( "keyTimes", XML_KEYTIMES ), + TOKEN( "keySplines", XML_KEYSPLINES ), + TOKEN( "calcMode", XML_CALCMODE ), + TOKEN( "discrete", XML_DISCRETE ), + TOKEN( "paced", XML_PACED ), + TOKEN( "spline", XML_SPLINE ), + TOKEN( "accumulate", XML_ACCUMULATE ), + TOKEN( "additive", XML_ADDITIVE ), + TOKEN( "multiply", XML_MULTIPLY ), + TOKEN( "animate", XML_ANIMATE ), + TOKEN( "animateMotion", XML_ANIMATEMOTION ), + TOKEN( "animatePhysics", XML_ANIMATEPHYSICS ), + TOKEN( "animateTransform", XML_ANIMATETRANSFORM ), + TOKEN( "animateColor", XML_ANIMATECOLOR ), + TOKEN( "transitionFilter", XML_TRANSITIONFILTER ), + TOKEN( "attributeName", XML_ATTRIBUTENAME ), + + TOKEN( "smil", XML_NP_SMIL ), + TOKEN( "http://www.w3.org/2001/SMIL20/", XML_N_SMIL ), + + TOKEN( "anim", XML_NP_ANIMATION ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:animation:1.0", XML_N_ANIMATION ), + TOKEN( "urn:oasis:names:tc:openoffice:xmlns:animation:1.0", XML_N_ANIMATION_OOO ), + + TOKEN( "par", XML_PAR ), + TOKEN( "seq", XML_SEQ ), + + TOKEN( "translate", XML_TRANSLATE ), + TOKEN( "skewX", XML_SKEWX ), + TOKEN( "skewY", XML_SKEWY ), + + TOKEN( "audio", XML_AUDIO ), + + TOKEN( "color-interpolation", XML_COLOR_INTERPOLATION ), + TOKEN( "color-interpolation-direction", XML_COLOR_INTERPOLATION_DIRECTION ), + TOKEN( "hsl", XML_HSL ), + TOKEN( "rgb", XML_RGB ), + + TOKEN( "barWipe", XML_BARWIPE ), + TOKEN( "boxWipe", XML_BOXWIPE ), + TOKEN( "fourBoxWipe", XML_FOURBOXWIPE ), + TOKEN( "barnDoorWipe", XML_BARNDOORWIPE ), + TOKEN( "diagonalWipe", XML_DIAGONALWIPE ), + TOKEN( "bowTieWipe", XML_BOWTIEWIPE ), + TOKEN( "miscDiagonalWipe", XML_MISCDIAGONALWIPE ), + TOKEN( "veeWipe", XML_VEEWIPE ), + TOKEN( "barnVeeWipe", XML_BARNVEEWIPE ), + TOKEN( "zigZagWipe", XML_ZIGZAGWIPE ), + TOKEN( "barnZigZagWipe", XML_BARNZIGZAGWIPE ), + TOKEN( "irisWipe", XML_IRISWIPE ), + TOKEN( "triangleWipe", XML_TRIANGLEWIPE ), + TOKEN( "arrowHeadWipe", XML_ARROWHEADWIPE ), + TOKEN( "pentagonWipe", XML_PENTAGONWIPE ), + TOKEN( "hexagonWipe", XML_HEXAGONWIPE ), + TOKEN( "ellipseWipe", XML_ELLIPSEWIPE ), + TOKEN( "eyeWipe", XML_EYEWIPE ), + TOKEN( "roundRectWipe", XML_ROUNDRECTWIPE ), + TOKEN( "starWipe", XML_STARWIPE ), + TOKEN( "miscShapeWipe", XML_MISCSHAPEWIPE ), + TOKEN( "clockWipe", XML_CLOCKWIPE ), + TOKEN( "pinWheelWipe", XML_PINWHEELWIPE ), + TOKEN( "singleSweepWipe", XML_SINGLESWEEPWIPE ), + TOKEN( "fanWipe", XML_FANWIPE ), + TOKEN( "doubleFanWipe", XML_DOUBLEFANWIPE ), + TOKEN( "doubleSweepWipe", XML_DOUBLESWEEPWIPE ), + TOKEN( "saloonDoorWipe", XML_SALOONDOORWIPE ), + TOKEN( "windshieldWipe", XML_WINDSHIELDWIPE ), + TOKEN( "snakeWipe", XML_SNAKEWIPE ), + TOKEN( "spiralWipe", XML_SPIRALWIPE ), + TOKEN( "parallelSnakesWipe", XML_PARALLELSNAKESWIPE ), + TOKEN( "boxSnakesWipe", XML_BOXSNAKESWIPE ), + TOKEN( "waterfallWipe", XML_WATERFALLWIPE ), + TOKEN( "pushWipe", XML_PUSHWIPE ), + TOKEN( "slideWipe", XML_SLIDEWIPE ), + TOKEN( "blindsWipe", XML_BLINDSWIPE ), + TOKEN( "randomBarWipe", XML_RANDOMBARWIPE ), + TOKEN( "checkerBoardWipe", XML_CHECKERBOARDWIPE ), + TOKEN( "zoom", XML_ZOOM ), + + TOKEN( "leftToRight", XML_LEFTTORIGHT ), + TOKEN( "topToBottom", XML_TOPTOBOTTOM ), + TOKEN( "topLeft", XML_TOPLEFT ), + TOKEN( "topRight", XML_TOPRIGHT ), + TOKEN( "bottomRight", XML_BOTTOMRIGHT ), + TOKEN( "bottomLeft", XML_BOTTOMLEFT ), + TOKEN( "topCenter", XML_TOPCENTER ), + TOKEN( "rightCenter", XML_RIGHTCENTER ), + TOKEN( "bottomCenter", XML_BOTTOMCENTER ), + TOKEN( "leftCenter", XML_LEFTCENTER ), + TOKEN( "cornersIn", XML_CORNERSIN ), + TOKEN( "cornersOut", XML_CORNERSOUT ), + TOKEN( "diagonalBottomLeft", XML_DIAGONALBOTTOMLEFT ), + TOKEN( "diagonalTopLeft", XML_DIAGONALTOPLEFT ), + TOKEN( "doubleBarnDoor", XML_DOUBLEBARNDOOR ), + TOKEN( "doubleDiamond", XML_DOUBLEDIAMOND ), + TOKEN( "fourPoint", XML_FOURPOINT ), + TOKEN( "fivePoint", XML_FIVEPOINT ), + TOKEN( "sixPoint", XML_SIXPOINT ), + TOKEN( "heart", XML_HEART ), + TOKEN( "keyhole", XML_KEYHOLE ), + TOKEN( "clockwiseTwelve", XML_CLOCKWISETWELVE ), + TOKEN( "clockwiseThree", XML_CLOCKWISETHREE ), + TOKEN( "clockwiseSix", XML_CLOCKWISESIX ), + TOKEN( "clockwiseNine", XML_CLOCKWISENINE ), + TOKEN( "twoBladeVertical", XML_TWOBLADEVERTICAL ), + TOKEN( "twoBladeHorizontal", XML_TWOBLADEHORIZONTAL ), + TOKEN( "fourBlade", XML_FOURBLADE ), + TOKEN( "clockwiseTop", XML_CLOCKWISETOP ), + TOKEN( "clockwiseRight", XML_CLOCKWISERIGHT ), + TOKEN( "clockwiseBottom", XML_CLOCKWISEBOTTOM ), + TOKEN( "clockwiseLeft", XML_CLOCKWISELEFT ), + TOKEN( "clockwiseTopLeft", XML_CLOCKWISETOPLEFT ), + TOKEN( "counterClockwiseBottomLeft", XML_COUNTERCLOCKWISEBOTTOMLEFT ), + TOKEN( "clockwiseBottomRight", XML_CLOCKWISEBOTTOMRIGHT ), + TOKEN( "counterClockwiseTopRight", XML_COUNTERCLOCKWISETOPRIGHT ), + TOKEN( "centerTop", XML_CENTERTOP ), + TOKEN( "centerRight", XML_CENTERRIGHT ), + TOKEN( "fanOutVertical", XML_FANOUTVERTICAL ), + TOKEN( "fanOutHorizontal", XML_FANOUTHORIZONTAL ), + TOKEN( "fanInVertical", XML_FANINVERTICAL ), + TOKEN( "fanInHorizontal", XML_FANINHORIZONTAL ), + TOKEN( "parallelVertical", XML_PARALLELVERTICAL ), + TOKEN( "parallelDiagonal", XML_PARALLELDIAGONAL ), + TOKEN( "oppositeVertical", XML_OPPOSITEVERTICAL ), + TOKEN( "oppositeHorizontal", XML_OPPOSITEHORIZONTAL ), + TOKEN( "parallelDiagonalTopLeft", XML_PARALLELDIAGONALTOPLEFT ), + TOKEN( "parallelDiagonalBottomLeft", XML_PARALLELDIAGONALBOTTOMLEFT ), + TOKEN( "topLeftHorizontal", XML_TOPLEFTHORIZONTAL ), + TOKEN( "topLeftDiagonal", XML_TOPLEFTDIAGONAL ), + TOKEN( "topLeftVertical", XML_TOPLEFTVERTICAL ), + TOKEN( "topRightDiagonal", XML_TOPRIGHTDIAGONAL ), + TOKEN( "bottomRightDiagonal", XML_BOTTOMRIGHTDIAGONAL ), + TOKEN( "bottomLeftDiagonal", XML_BOTTOMLEFTDIAGONAL ), + TOKEN( "topLeftClockwise", XML_TOPLEFTCLOCKWISE ), + TOKEN( "topRightClockwise", XML_TOPRIGHTCLOCKWISE ), + TOKEN( "bottomRightClockwise", XML_BOTTOMRIGHTCLOCKWISE ), + TOKEN( "bottomLeftClockwise", XML_BOTTOMLEFTCLOCKWISE ), + TOKEN( "topLeftCounterClockwise", XML_TOPLEFTCOUNTERCLOCKWISE ), + TOKEN( "topRightCounterClockwise", XML_TOPRIGHTCOUNTERCLOCKWISE ), + TOKEN( "bottomRightCounterClockwise", XML_BOTTOMRIGHTCOUNTERCLOCKWISE ), + TOKEN( "bottomLeftCounterClockwise", XML_BOTTOMLEFTCOUNTERCLOCKWISE ), + TOKEN( "verticalTopSame", XML_VERTICALTOPSAME ), + TOKEN( "verticalBottomSame", XML_VERTICALBOTTOMSAME ), + TOKEN( "verticalTopLeftOpposite", XML_VERTICALTOPLEFTOPPOSITE ), + TOKEN( "verticalBottomLeftOpposite", XML_VERTICALBOTTOMLEFTOPPOSITE ), + TOKEN( "horizontalLeftSame", XML_HORIZONTALLEFTSAME ), + TOKEN( "horizontalRightSame", XML_HORIZONTALRIGHTSAME ), + TOKEN( "horizontalTopLeftOpposite", XML_HORIZONTALTOPLEFTOPPOSITE ), + TOKEN( "horizontalTopRightOpposite", XML_HORIZONTALTOPRIGHTOPPOSITE ), + TOKEN( "diagonalBottomLeftOpposite", XML_DIAGONALBOTTOMLEFTOPPOSITE ), + TOKEN( "diagonalTopLeftOpposite", XML_DIAGONALTOPLEFTOPPOSITE ), + TOKEN( "twoBoxTop", XML_TWOBOXTOP ), + TOKEN( "twoBoxBottom", XML_TWOBOXBOTTOM ), + TOKEN( "twoBoxLeft", XML_TWOBOXLEFT ), + TOKEN( "twoBoxRight", XML_TWOBOXRIGHT ), + TOKEN( "fourBoxVertical", XML_FOURBOXVERTICAL ), + TOKEN( "fourBoxHorizontal", XML_FOURBOXHORIZONTAL ), + TOKEN( "verticalLeft", XML_VERTICALLEFT ), + TOKEN( "verticalRight", XML_VERTICALRIGHT ), + TOKEN( "horizontalLeft", XML_HORIZONTALLEFT ), + TOKEN( "horizontalRight", XML_HORIZONTALRIGHT ), + TOKEN( "fromLeft", XML_FROMLEFT ), + TOKEN( "fromTop", XML_FROMTOP ), + TOKEN( "fromRight", XML_FROMRIGHT ), + TOKEN( "fromBottom", XML_FROMBOTTOM ), + TOKEN( "crossfade", XML_CROSSFADE ), + TOKEN( "fadeToColor", XML_FADETOCOLOR ), + TOKEN( "fadeFromColor", XML_FADEFROMCOLOR ), + TOKEN( "fadeOverColor", XML_FADEOVERCOLOR ), + TOKEN( "threeBlade", XML_THREEBLADE ), + TOKEN( "eightBlade", XML_EIGHTBLADE ), + TOKEN( "oneBlade", XML_ONEBLADE ), + TOKEN( "across", XML_ACROSS ), + TOKEN( "combHorizontal", XML_COMBHORIZONTAL ), + TOKEN( "combVertical", XML_COMBVERTICAL ), + TOKEN( "rotateIn", XML_ROTATEIN ), + TOKEN( "rotateOut", XML_ROTATEOUT ), + TOKEN( "fromTopLeft", XML_FROMTOPLEFT ), + TOKEN( "fromTopRight", XML_FROMTOPRIGHT ), + TOKEN( "fromBottomLeft", XML_FROMBOTTOMLEFT ), + TOKEN( "fromBottomRight", XML_FROMBOTTOMRIGHT ), + + TOKEN( "subtype", XML_SUBTYPE ), + TOKEN( "out", XML_OUT ), + + TOKEN( "forward", XML_FORWARD ), + TOKEN( "reverse", XML_REVERSE ), + + TOKEN( "fadeColor", XML_FADECOLOR ), + + TOKEN( "onbegin", XML_ONBEGIN ), + TOKEN( "onend", XML_ONEND ), + TOKEN( "click", XML_CLICK ), + TOKEN( "doubleclick", XML_DOUBLECLICK ), + TOKEN( "mouseover", XML_MOUSEOVER ), + TOKEN( "mouseout", XML_MOUSEOUT ), + + TOKEN( "node-type", XML_NODE_TYPE ), + TOKEN( "preset-id", XML_PRESET_ID ), + TOKEN( "preset-sub-type", XML_PRESET_SUB_TYPE ), + TOKEN( "preset-class", XML_PRESET_CLASS ), + TOKEN( "preset-property", XML_PRESET_PROPERTY ), + TOKEN( "custom", XML_CUSTOM ), + TOKEN( "entrance", XML_ENTRANCE ), + TOKEN( "exit", XML_EXIT ), + TOKEN( "emphasis", XML_EMPHASIS ), + TOKEN( "motion-path", XML_MOTION_PATH ), + TOKEN( "ole-action", XML_OLE_ACTION ), + TOKEN( "media-call", XML_MEDIA_CALL ), + TOKEN( "on-click", XML_ON_CLICK ), + TOKEN( "with-previous", XML_WITH_PREVIOUS ), + TOKEN( "after-previous", XML_AFTER_PREVIOUS ), + TOKEN( "main-sequence", XML_MAIN_SEQUENCE ), + TOKEN( "timing-root", XML_TIMING_ROOT ), + TOKEN( "interactive-sequence",XML_INTERACTIVE_SEQUENCE ), + + TOKEN( "sub-item", XML_SUB_ITEM ), + TOKEN( "iterate-type", XML_ITERATE_TYPE ), + TOKEN( "iterate-interval", XML_ITERATE_INTERVAL ), + TOKEN( "iterate", XML_ITERATE ), + TOKEN( "by-paragraph", XML_BY_PARAGRAPH ), + TOKEN( "by-word", XML_BY_WORD ), + TOKEN( "by-letter", XML_BY_LETTER ), + + TOKEN( "after-effect", XML_AFTER_EFFECT ), + TOKEN( "master", XML_MASTER ), + + TOKEN( "group-id", XML_GROUP_ID ), + TOKEN( "targetElement", XML_TARGETELEMENT ), + TOKEN( "toggle-pause", XML_TOGGLE_PAUSE ), + TOKEN( "master-element", XML_MASTER_ELEMENT ), + TOKEN( "stop-audio", XML_STOP_AUDIO ), + + TOKEN( "audio-level", XML_AUDIO_LEVEL ), + + TOKEN( "urn:oasis:names:tc", XML_URN_OASIS_NAMES_TC ), + TOKEN( "opendocument", XML_OPENDOCUMENT), + TOKEN( "1.0", XML_1_0 ), + + TOKEN( "is-list-header", XML_IS_LIST_HEADER ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0", XML_N_SVG_COMPAT ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0", XML_N_FO_COMPAT ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0", XML_N_SMIL_COMPAT ), + TOKEN( "http://www.w3.org/2001/SMIL20", XML_N_SMIL_OLD ), + TOKEN( "xforms-submission", XML_XFORMS_SUBMISSION ), + TOKEN( "xforms-list-source", XML_XFORMS_LIST_SOURCE ), + + TOKEN( "http://www.w3.org/", XML_URI_W3_PREFIX ), + TOKEN( "/xforms", XML_URI_XFORMS_SUFFIX ), + /* XML_HORIZONTAL_ON_LEFT_PAGES and XML_HORIZONTAL_ON_RIGHT_PAGES + are replaced by XML_HORIZONTAL_ON_EVEN and XML_HORIZONTAL_ON_ODD. (#i49139#) + */ + TOKEN( "horizontal-on-even", XML_HORIZONTAL_ON_EVEN ), + TOKEN( "urn:oasis:names:tc:opendocument:xmlns:report:1.0", XML_N_RPT_OASIS ), + TOKEN( "http://openoffice.org/2005/report", XML_N_RPT ), + TOKEN( "group", XML_GROUP ), + TOKEN( "groups", XML_GROUPS ), + TOKEN( "report-header", XML_REPORT_HEADER ), + TOKEN( "page-header", XML_PAGE_HEADER ), + TOKEN( "detail", XML_DETAIL ), + TOKEN( "page-footer", XML_PAGE_FOOTER ), + TOKEN( "report-footer", XML_REPORT_FOOTER ), + TOKEN( "start-new-column", XML_START_NEW_COLUMN ), + TOKEN( "reset-page-number", XML_RESET_PAGE_NUMBER ), + TOKEN( "print-header-on-each-page", XML_PRINT_HEADER_ON_EACH_PAGE ), + TOKEN( "sort-expression", XML_SORT_EXPRESSION ), + TOKEN( "group-expression", XML_GROUP_EXPRESSION ), + TOKEN( "group-header", XML_GROUP_HEADER ), + TOKEN( "group-footer", XML_GROUP_FOOTER ), + TOKEN( "header-on-new-page", XML_HEADER_ON_NEW_PAGE), + TOKEN( "footer-on-new-page", XML_FOOTER_ON_NEW_PAGE), + TOKEN( "page-print-option", XML_PAGE_PRINT_OPTION ), + TOKEN( "pre-evaluated", XML_PRE_EVALUATED), + TOKEN( "command-type", XML_COMMAND_TYPE ), + TOKEN( "master-fields", XML_MASTER_FIELDS ), + TOKEN( "detail-fields", XML_DETAIL_FIELDS ), + TOKEN( "conditional-print-expression", XML_CONDITIONAL_PRINT_EXPRESSION ), + TOKEN( "report-component", XML_REPORT_COMPONENT ), + TOKEN( "print-repeated-values", XML_PRINT_REPEATED_VALUES ), + TOKEN( "repeat-section", XML_REPEAT_SECTION ), + TOKEN( "force-new-column", XML_FORCE_NEW_COLUMN ), + TOKEN( "group-on", XML_GROUP_ON), + TOKEN( "force-new-page", XML_FORCE_NEW_PAGE), + TOKEN( "group-interval", XML_GROUP_INTERVAL), + TOKEN( "print-when-group-change", XML_PRINT_WHEN_GROUP_CHANGE), + TOKEN( "report-element", XML_REPORT_ELEMENT), + TOKEN( "list-source", XML_LIST_SOURCE), + TOKEN( "list-source-type", XML_LIST_SOURCE_TYPE), + TOKEN( "image-data", XML_IMAGE_DATA), + TOKEN( "selected", XML_SELECTED), + TOKEN( "current-state", XML_CURRENT_STATE), + TOKEN( "is-tristate", XML_IS_TRISTATE), + TOKEN( "all-pages", XML_ALL_PAGES), + TOKEN( "not-with-report-header", XML_NOT_WITH_REPORT_HEADER ), + TOKEN( "not-with-report-footer", XML_NOT_WITH_REPORT_FOOTER ), + TOKEN( "not-with-report-header-nor-footer", XML_NOT_WITH_REPORT_HEADER_NOR_FOOTER ), + TOKEN( "before-section", XML_BEFORE_SECTION ), + TOKEN( "after-section", XML_AFTER_SECTION ), + TOKEN( "before-after-section", XML_BEFORE_AFTER_SECTION), + TOKEN( "prefix-characters", XML_PREFIX_CHARACTERS ), + TOKEN( "quartal", XML_QUARTAL ), + TOKEN( "week", XML_WEEK ), + TOKEN( "whole-group", XML_WHOLE_GROUP ), + TOKEN( "with-first-detail", XML_WITH_FIRST_DETAIL ), + TOKEN( "top-down", XML_TOP_DOWN ), + TOKEN( "bottom-up", XML_BOTTOM_UP ), + TOKEN( "hour", XML_HOUR ), + TOKEN( "minute", XML_MINUTE ), + TOKEN( "rpt", XML_NP_RPT ), + TOKEN( "format-condition", XML_FORMAT_CONDITION ), + TOKEN( "expression1", XML_EXPRESSION1 ), + TOKEN( "expression2", XML_EXPRESSION2 ), + TOKEN( "equal", XML_EQUAL ), + TOKEN( "not_equal", XML_NOT_EQUAL ), + TOKEN( "less", XML_LESS ), + TOKEN( "greater", XML_GREATER ), + TOKEN( "less_equal", XML_LESS_EQUAL ), + TOKEN( "greater_equal", XML_GREATER_EQUAL ), + TOKEN( "between", XML_BETWEEN ), + TOKEN( "not_between", XML_NOT_BETWEEN ), + TOKEN( "table-template", XML_TABLE_TEMPLATE ), + TOKEN( "first-row", XML_FIRST_ROW ), + TOKEN( "last-row", XML_LAST_ROW ), + TOKEN( "first-column", XML_FIRST_COLUMN ), + TOKEN( "last-column", XML_LAST_COLUMN ), + TOKEN( "even-rows", XML_EVEN_ROWS ), + TOKEN( "odd-rows", XML_ODD_ROWS ), + TOKEN( "even-columns", XML_EVEN_COLUMNS ), + TOKEN( "odd-columns", XML_ODD_COLUMNS ), + // table styles + TOKEN( "first-row-even-column", XML_FIRST_ROW_EVEN_COLUMN ), + TOKEN( "last-row-even-column", XML_LAST_ROW_EVEN_COLUMN ), + TOKEN( "first-row-end-column", XML_FIRST_ROW_END_COLUMN ), + TOKEN( "first-row-start-column", XML_FIRST_ROW_START_COLUMN ), + TOKEN( "last-row-end-column", XML_LAST_ROW_END_COLUMN ), + TOKEN( "last-row-start-column", XML_LAST_ROW_START_COLUMN ), + + TOKEN( "horizontal-on-odd", XML_HORIZONTAL_ON_ODD ), + // Password error from 1.4 to 2.0 Beta (#i45874#) + TOKEN( "restart-numbering", XML_RESTART_NUMBERING), + // OpenDocument element not supported on OpenDocument import (#i52127#) + TOKEN( "numbered-paragraph", XML_NUMBERED_PARAGRAPH), + TOKEN( "master-detail-fields", XML_MASTER_DETAIL_FIELDS), + TOKEN( "master-detail-field", XML_MASTER_DETAIL_FIELD), + TOKEN( "sub-document", XML_SUB_DOCUMENT), + TOKEN( "fixed-content", XML_FIXED_CONTENT), + TOKEN( "initial-formula", XML_INITIAL_FORMULA), + TOKEN( "deep-traversing", XML_DEEP_TRAVERSING), + TOKEN( "preserve-IRI", XML_PRESERVE_IRI), + TOKEN( "sort-by-x-values", XML_SORT_BY_X_VALUES ), + TOKEN( "page-continuation", XML_PAGE_CONTINUATION ), + TOKEN( "right-angled-axes", XML_RIGHT_ANGLED_AXES ), + TOKEN( "soft-page-break", XML_SOFT_PAGE_BREAK ), + TOKEN( "use-soft-page-breaks", XML_USE_SOFT_PAGE_BREAKS ), + TOKEN( "percentage-data-style-name", XML_PERCENTAGE_DATA_STYLE_NAME ), + TOKEN( "value-and-percentage", XML_VALUE_AND_PERCENTAGE ), + TOKEN( "group-bars-per-axis", XML_GROUP_BARS_PER_AXIS ), + TOKEN( "include-hidden-cells", XML_INCLUDE_HIDDEN_CELLS ), + TOKEN( "auto-position", XML_AUTOMATIC_POSITION ), + TOKEN( "auto-size", XML_AUTOMATIC_SIZE ), + TOKEN( "reverse-direction", XML_REVERSE_DIRECTION ), + TOKEN( "label-separator", XML_LABEL_SEPARATOR ), + TOKEN( "label-position", XML_LABEL_POSITION ), + TOKEN( "avoid-overlap", XML_AVOID_OVERLAP ), + TOKEN( "near-origin", XML_NEAR_ORIGIN ), + TOKEN( "dependency", XML_DEPENDENCY ), + TOKEN( "nav-order", XML_NAV_ORDER ), + + TOKEN( "use-first-row-styles", XML_USE_FIRST_ROW_STYLES ), + TOKEN( "use-last-row-styles", XML_USE_LAST_ROW_STYLES ), + TOKEN( "use-first-column-styles", XML_USE_FIRST_COLUMN_STYLES ), + TOKEN( "use-last-column-styles", XML_USE_LAST_COLUMN_STYLES ), + TOKEN( "use-banding-rows-styles", XML_USE_BANDING_ROWS_STYLES ), + TOKEN( "use-banding-columns-styles", XML_USE_BANDING_COLUMNS_STYLES ), + + TOKEN( "automatic-content", XML_AUTOMATIC_CONTENT ), + TOKEN( "display-r-square", XML_DISPLAY_R_SQUARE ), + TOKEN( "display-equation", XML_DISPLAY_EQUATION ), + // db odf 12 + TOKEN( "table-representations", XML_TABLE_REPRESENTATIONS ), + TOKEN( "table-representation", XML_TABLE_REPRESENTATION ), + TOKEN( "schema-definition", XML_SCHEMA_DEFINITION ), + TOKEN( "connection-data", XML_CONNECTION_DATA ), + TOKEN( "database-description", XML_DATABASE_DESCRIPTION ), + TOKEN( "compound-database", XML_COMPOUND_DATABASE ), + TOKEN( "file-based-database", XML_FILE_BASED_DATABASE ), + TOKEN( "server-database", XML_SERVER_DATABASE ), + TOKEN( "media-type", XML_MEDIA_TYPE ), + TOKEN( "hostname", XML_HOSTNAME ), + TOKEN( "port", XML_PORT ), + TOKEN( "local-socket", XML_LOCAL_SOCKET ), + TOKEN( "use-system-user", XML_USE_SYSTEM_USER ), + TOKEN( "driver-settings", XML_DRIVER_SETTINGS ), + TOKEN( "java-classpath", XML_JAVA_CLASSPATH ), + TOKEN( "character-set", XML_CHARACTER_SET ), + TOKEN( "application-connection-settings", XML_APPLICATION_CONNECTION_SETTINGS ), + TOKEN( "table-include-filter", XML_TABLE_INCLUDE_FILTER ), + TOKEN( "default-row-style-name", XML_DEFAULT_ROW_STYLE_NAME), + TOKEN( "angle-offset", XML_ANGLE_OFFSET ), + // Core implementation for direct cross-references (#i81002#) + TOKEN( "number-no-superior", XML_NUMBER_NO_SUPERIOR ), + TOKEN( "number-all-superior", XML_NUMBER_ALL_SUPERIOR ), + TOKEN( "list-level-position-and-space-mode", XML_LIST_LEVEL_POSITION_AND_SPACE_MODE ), + TOKEN( "label-width-and-position", XML_LABEL_WIDTH_AND_POSITION ), + TOKEN( "label-alignment", XML_LABEL_ALIGNMENT ), + TOKEN( "list-level-label-alignment", XML_LIST_LEVEL_LABEL_ALIGNMENT ), + TOKEN( "label-followed-by", XML_LABEL_FOLLOWED_BY ), + TOKEN( "listtab", XML_LISTTAB ), + TOKEN( "space", XML_SPACE ), + TOKEN( "nothing", XML_NOTHING ), + TOKEN( "list-tab-stop-position", XML_LIST_TAB_STOP_POSITION ), + + // bm: chart error bar extensions (ODF 1.2) + TOKEN( "standard-error", XML_STANDARD_ERROR ), + TOKEN( "cell-range" , XML_CELL_RANGE ), + TOKEN( "error-lower-range", XML_ERROR_LOWER_RANGE ), + TOKEN( "error-upper-range", XML_ERROR_UPPER_RANGE ), + + TOKEN( "continue-list", XML_CONTINUE_LIST ), + TOKEN( "style-override", XML_STYLE_OVERRIDE ), + + // XForms: Changes to model should optionally set document's modified state. (#i90243#) + TOKEN( "xforms-settings", XML_XFORM_MODEL_SETTINGS ), + + // ODF 1.2 metadata + TOKEN( "meta-field", XML_META_FIELD ), + TOKEN( "about", XML_ABOUT ), + TOKEN( "datatype", XML_DATATYPE ), + TOKEN( "transformation", XML_TRANSFORMATION ), + + // ODF 1.2 numbered-paragraph + TOKEN( "list-id", XML_LIST_ID ), + + TOKEN( "treat-empty-cells", XML_TREAT_EMPTY_CELLS ), + TOKEN( "leave-gap", XML_LEAVE_GAP ), + TOKEN( "use-zero", XML_USE_ZERO ), + TOKEN( "ignore", XML_IGNORE ), + + // enhanced fields + TOKEN( "fieldmark", XML_FIELDMARK ), + TOKEN( "fieldmark-start", XML_FIELDMARK_START ), + TOKEN( "fieldmark-separator", XML_FIELDMARK_SEPARATOR ), + TOKEN( "fieldmark-end", XML_FIELDMARK_END ), + + TOKEN( "image-scale", XML_IMAGE_SCALE ), + TOKEN( "isotropic", XML_ISOTROPIC ), + TOKEN( "anisotropic", XML_ANISOTROPIC ), + + TOKEN( "axis-position", XML_AXIS_POSITION ), + TOKEN( "axis-label-position", XML_AXIS_LABEL_POSITION ), + TOKEN( "near-axis", XML_NEAR_AXIS ), + TOKEN( "near-axis-other-side", XML_NEAR_AXIS_OTHER_SIDE ), + TOKEN( "outside-start", XML_OUTSIDE_START ), + TOKEN( "outside-end", XML_OUTSIDE_END ), + TOKEN( "tick-mark-position", XML_TICK_MARK_POSITION ), + TOKEN( "at-labels", XML_AT_LABELS ), + TOKEN( "at-axis", XML_AT_AXIS ), + TOKEN( "at-labels-and-axis", XML_AT_LABELS_AND_AXIS ), + TOKEN( "filled-radar", XML_FILLED_RADAR ), + TOKEN( "surface", XML_SURFACE ), + + TOKEN( "mathvariant", XML_MATHVARIANT ), + TOKEN( "mathsize", XML_MATHSIZE ), + TOKEN( "mathweight", XML_MATHWEIGHT ), + TOKEN( "mathcolor", XML_MATHCOLOR ), + + TOKEN( "contains", XML_CONTAINS ), + TOKEN( "does-not-contain", XML_DOES_NOT_CONTAIN ), + TOKEN( "begins-with", XML_BEGINS_WITH ), + TOKEN( "does-not-begin-with", XML_DOES_NOT_BEGIN_WITH ), + TOKEN( "ends-with", XML_ENDS_WITH ), + TOKEN( "does-not-end-with", XML_DOES_NOT_END_WITH ), + + TOKEN( "chartooo", XML_NP_CHART_EXT ), + TOKEN( "http://openoffice.org/2010/chart", XML_N_CHART_EXT ), + TOKEN( "coordinate-region", XML_COORDINATE_REGION ), + + TOKEN( "diagonal-bl-tr-widths", XML_DIAGONAL_BL_TR_WIDTHS ), + TOKEN( "diagonal-tl-br-widths", XML_DIAGONAL_TL_BR_WIDTHS ), + + TOKEN( "outside-minimum", XML_OUTSIDE_MINIMUM ), + TOKEN( "outside-maximum", XML_OUTSIDE_MAXIMUM ), + + TOKEN( "legend-expansion", XML_LEGEND_EXPANSION), + TOKEN( "legend-expansion-aspect-ratio", XML_LEGEND_EXPANSION_ASPECT_RATIO), + TOKEN( "balanced", XML_BALANCED), + TOKEN( "high", XML_HIGH), + TOKEN( "wide", XML_WIDE), + + TOKEN( "axis-type", XML_AXIS_TYPE ), //#i25706# + TOKEN( "date-scale", XML_DATE_SCALE ), + TOKEN( "base-time-unit", XML_BASE_TIME_UNIT ), + TOKEN( "major-interval-value", XML_MAJOR_INTERVAL_VALUE ), + TOKEN( "minor-interval-value", XML_MINOR_INTERVAL_VALUE ), + TOKEN( "major-interval-unit", XML_MAJOR_INTERVAL_UNIT ), + TOKEN( "minor-interval-unit", XML_MINOR_INTERVAL_UNIT ), + + TOKEN( "min-value", XML_MIN_VALUE ), + TOKEN( "max-value", XML_MAX_VALUE ), + + TOKEN( "margin", XML_MARGIN), + + TOKEN( "propertry-mapping", XML_PROPERTY_MAPPING), + TOKEN( "provider", XML_PROVIDER), + TOKEN( "data-mappings", XML_DATA_MAPPINGS), + TOKEN( "data-mapping", XML_DATA_MAPPING), + TOKEN( "frequency", XML_DATA_FREQUENCY), + TOKEN( "data-transformations", XML_DATA_TRANSFORMATIONS), + TOKEN( "column-remove-transformation", XML_COLUMN_REMOVE_TRANSFORMATION), + TOKEN( "column-split-transformation", XML_COLUMN_SPLIT_TRANSFORMATION), + TOKEN( "column-merge-transformation", XML_COLUMN_MERGE_TRANSFORMATION), + TOKEN( "column-sort-transformation", XML_COLUMN_SORT_TRANSFORMATION), + TOKEN( "column-text-transformation", XML_COLUMN_TEXT_TRANSFORMATION), + TOKEN( "column-aggregate-transformation", XML_COLUMN_AGGREGATE_TRANSFORMATION), + TOKEN( "column-number-transformation", XML_COLUMN_NUMBER_TRANSFORMATION), + + TOKEN( "sort-param", XML_SORT_PARAM ), + TOKEN( "merge-string", XML_MERGE_STRING ), + TOKEN( "trim", XML_TRIM ), + TOKEN( "round-up", XML_ROUND_UP ), + TOKEN( "round-down", XML_ROUND_DOWN ), + TOKEN( "log-base-10", XML_LOG_10 ), + TOKEN( "number-square", XML_SQUARE ), + TOKEN( "square-root", XML_SQUARE_ROOT ), + TOKEN( "even", XML_EVEN ), + TOKEN( "odd", XML_ODD ), + TOKEN( "sign", XML_SIGN ), + TOKEN( "replace-string", XML_REPLACE_STRING ), + TOKEN( "column-replacenull-transformation", XML_COLUMN_REPLACENULL_TRANSFORMATION ), + TOKEN( "column-datetime-transformation", XML_COLUMN_DATETIME_TRANSFORMATION ), + TOKEN( "start-of-year", XML_START_OF_YEAR ), + TOKEN( "end-of-year", XML_END_OF_YEAR ), + TOKEN( "month-name", XML_MONTH_NAME ), + TOKEN( "start-of-month", XML_START_OF_MONTH ), + TOKEN( "end-of-month", XML_END_OF_MONTH ), + TOKEN( "day-of-year", XML_DAY_OF_YEAR ), + TOKEN( "start-of-quarter", XML_START_OF_QUARTER ), + TOKEN( "end-of-quarter", XML_END_OF_QUARTER ), + + // regina, ODF1.2 additional symbols in charts + TOKEN( "star", XML_STAR ), + TOKEN( "asterisk", XML_ASTERISK ), + TOKEN( "horizontal-bar", XML_HORIZONTAL_BAR ), + TOKEN( "vertical-bar", XML_VERTICAL_BAR ), + + TOKEN( "std-weight", XML_ERROR_STANDARD_WEIGHT ), + + // erAck: 2013-07-02 BCP 47 language tags + TOKEN( "rfc-language-tag", XML_RFC_LANGUAGE_TAG ), + TOKEN( "rfc-language-tag-asian", XML_RFC_LANGUAGE_TAG_ASIAN ), + TOKEN( "rfc-language-tag-complex", XML_RFC_LANGUAGE_TAG_COMPLEX ), + TOKEN( "data-table-show-horz-border", XML_DATA_TABLE_SHOW_HORZ_BORDER ), + TOKEN( "data-table-show-vert-border", XML_DATA_TABLE_SHOW_VERT_BORDER ), + TOKEN( "data-table-show-outline", XML_DATA_TABLE_SHOW_OUTLINE ), + TOKEN( "display-units", XML_CHART_DUNITS_DISPLAYUNITS ), + TOKEN( "display-units-built-in-unit", XML_CHART_DUNITS_BUILTINUNIT ), + TOKEN( "external-data", XML_EXTERNALDATA), + + TOKEN( "exponent-interval", XML_EXPONENT_INTERVAL ), + TOKEN( "forced-exponent-sign", XML_FORCED_EXPONENT_SIGN ), + TOKEN( "min-decimal-places", XML_MIN_DECIMAL_PLACES ), + TOKEN( "max-denominator-value", XML_MAX_DENOMINATOR_VALUE ), + TOKEN( "max-numerator-digits", XML_MAX_NUMERATOR_DIGITS ), + TOKEN( "zeros-numerator-digits", XML_ZEROS_NUMERATOR_DIGITS ), + TOKEN( "zeros-denominator-digits", XML_ZEROS_DENOMINATOR_DIGITS ), + TOKEN( "integer-fraction-delimiter", XML_INTEGER_FRACTION_DELIMITER ), + + // for optional language-dependent reference formats + TOKEN( "reference-language", XML_REFERENCE_LANGUAGE ), + TOKEN( "newline", XML_NEWLINE ), + TOKEN( "creator-initials", XML_CREATOR_INITIALS ), + + // tdf#115007 spell out numbers, dates, money amounts and cross references + TOKEN( "transliteration-spellout", XML_TRANSLITERATION_SPELLOUT ), + + // For recording whether comments/annotations are resolved + TOKEN( "resolved", XML_RESOLVED ), + + TOKEN( "page-content-top", XML_PAGE_CONTENT_TOP ), + + TOKEN( "page-content-bottom", XML_PAGE_CONTENT_BOTTOM ), + TOKEN("margin-gutter", XML_MARGIN_GUTTER), + + TOKEN("local-url", XML_LOCAL_URL), + + TOKEN("dir", XML_DIR ), + TOKEN("displaystyle", XML_DISPLAYSTYLE ), + TOKEN("infinity", XML_INFINITY ), + TOKEN("lspace", XML_LSPACE ), + TOKEN("mathbackground", XML_MATHBACKGROUND ), + TOKEN("maxsize", XML_MAXSIZE ), + TOKEN("minsize", XML_MINSIZE ), + TOKEN("movablelimits", XML_MOVABLELIMITS ), + TOKEN("rspace", XML_RSPACE ), + TOKEN("rtl", XML_RTL ), + TOKEN("symmetric", XML_SYMMETRIC ), + + TOKEN("linked-style-name", XML_LINKED_STYLE_NAME ), + + TOKEN("theme", XML_THEME ), + TOKEN("theme-color", XML_THEME_COLOR ), + TOKEN("fill-theme-color", XML_FILL_THEME_COLOR ), + TOKEN("dk1", XML_DK1 ), + TOKEN("lt1", XML_LT1 ), + TOKEN("dk2", XML_DK2 ), + TOKEN("lt2", XML_LT2 ), + TOKEN("accent1", XML_ACCENT1 ), + TOKEN("accent2", XML_ACCENT2 ), + TOKEN("accent3", XML_ACCENT3 ), + TOKEN("accent4", XML_ACCENT4 ), + TOKEN("accent5", XML_ACCENT5 ), + TOKEN("accent6", XML_ACCENT6 ), + TOKEN("hlink", XML_HLINK ), + TOKEN("folHlink", XML_FOLHLINK ), + TOKEN("color-lum-mod", XML_COLOR_LUM_MOD ), + TOKEN("color-lum-off", XML_COLOR_LUM_OFF ), + TOKEN("fill-color-lum-mod", XML_FILL_COLOR_LUM_MOD ), + TOKEN("fill-color-lum-off", XML_FILL_COLOR_LUM_OFF ), + + TOKEN("content-control", XML_CONTENT_CONTROL ), + TOKEN("showing-place-holder", XML_SHOWING_PLACE_HOLDER ), + TOKEN("checked-state", XML_CHECKED_STATE), + TOKEN("unchecked-state", XML_UNCHECKED_STATE), + TOKEN("display-text", XML_DISPLAY_TEXT), + TOKEN("picture", XML_PICTURE), + TOKEN("date-format", XML_DATE_FORMAT), + TOKEN("date-rfc-language-tag", XML_DATE_RFC_LANGUAGE_TAG), + + TOKEN("fill-use-slide-background", XML_FILL_USE_SLIDE_BACKGROUND), + +#if OSL_DEBUG_LEVEL > 0 + { 0, nullptr, std::nullopt, XML_TOKEN_END } +#else + { 0, nullptr, std::nullopt /* XML_TOKEN_END */ } +#endif + }; + + // get OUString representation of token + const OUString& GetXMLToken( enum XMLTokenEnum eToken ) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + static bool s_bChecked = false; + if (!s_bChecked) + { + // check the consistency of the token list. Below, we use the + // ordinal value of the token as index into the token list, so we + // should make sure that every entry is at the proper position + std::set tokenSet; + bool foundDuplicate = false; + const XMLTokenEntry* pEntry = aTokenList; + const XMLTokenEntry* pEntryEnd = + pEntry + SAL_N_ELEMENTS(aTokenList); + sal_uInt16 nPos = 0; + while (pEntry < pEntryEnd) + { + SAL_WARN_IF(nPos != static_cast(pEntry->eToken), "xmloff", + "inconsistency at pos " << nPos << " for token " + << OUString( pEntry->pChar, pEntry->nLength, RTL_TEXTENCODING_ASCII_US )); + assert(nPos == static_cast(pEntry->eToken)); + // Inconsistency in the token list! + // The positions in xmltoken.hxx and xmltoken.cxx need to match. + + // verify that we have no duplicates, which can mess us up when doing fast-parser import + if (pEntry->nLength && nPos >= XML_MM) + // ignoring the zero-length fake entries and the namespace prefix entries + { + auto pair = tokenSet.insert(OString(pEntry->pChar, pEntry->nLength)); + if (!pair.second) + { + SAL_WARN("xmloff", "duplicate token string " + << OUString( pEntry->pChar, pEntry->nLength, RTL_TEXTENCODING_ASCII_US )); + foundDuplicate = true; + } + } + ++pEntry; + ++nPos; + } + assert(!foundDuplicate && "duplicate token string"); + + s_bChecked = true; // it's all static, checking once is enough + } +#endif + assert(XML_TOKEN_INVALID < eToken); + assert(eToken < XML_TOKEN_END); + assert(sal_uInt16(eToken) < SAL_N_ELEMENTS(aTokenList)); + + XMLTokenEntry* pToken = &aTokenList[static_cast(eToken)]; + if (!pToken->xOUString) + pToken->xOUString = OUString( pToken->pChar, pToken->nLength, + RTL_TEXTENCODING_ASCII_US ); + return *pToken->xOUString; + } + + // does rString represent eToken? + bool IsXMLToken( + std::u16string_view rString, + enum XMLTokenEnum eToken ) + { + assert(XML_TOKEN_INVALID < eToken); + assert(eToken < XML_TOKEN_END); + + const XMLTokenEntry* pToken = &aTokenList[static_cast(eToken)]; + return static_cast(rString.size()) == pToken->nLength && + rtl_ustr_asciil_reverseEquals_WithLength( + rString.data(), pToken->pChar, pToken->nLength ); + } + + bool IsXMLToken( + const sax_fastparser::FastAttributeList::FastAttributeIter& aIter, + enum XMLTokenEnum eToken ) + { + assert(XML_TOKEN_INVALID < eToken); + assert(eToken < XML_TOKEN_END); + + const XMLTokenEntry* pToken = &aTokenList[static_cast(eToken)]; + return aIter.isString( pToken->pChar ); + } + + // does aStr represent eToken? + bool IsXMLToken( + std::string_view aStr, + enum XMLTokenEnum eToken ) + { + assert(XML_TOKEN_INVALID < eToken); + assert(eToken < XML_TOKEN_END); + + const XMLTokenEntry* pToken = &aTokenList[static_cast(eToken)]; + return aStr == std::string_view(pToken->pChar, pToken->nLength); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/core/xmluconv.cxx b/xmloff/source/core/xmluconv.cxx new file mode 100644 index 000000000..07e0e0c0b --- /dev/null +++ b/xmloff/source/core/xmluconv.cxx @@ -0,0 +1,949 @@ +/* -*- 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 + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::text; +using namespace com::sun::star::style; +using namespace ::com::sun::star::i18n; +using namespace ::xmloff::token; + + +const sal_Int8 XML_MAXDIGITSCOUNT_TIME = 11; +constexpr OUStringLiteral XML_NULLDATE = u"NullDate"; + +struct SvXMLUnitConverter::Impl +{ + sal_Int16 m_eCoreMeasureUnit; /*css::util::MeasureUnit*/ + sal_Int16 m_eXMLMeasureUnit; /*css::util::MeasureUnit*/ + SvtSaveOptions::ODFSaneDefaultVersion m_eODFVersion; + util::Date m_aNullDate; + mutable uno::Reference< text::XNumberingTypeInfo > m_xNumTypeInfo; + mutable uno::Reference< i18n::XCharacterClassification > m_xCharClass; + uno::Reference< uno::XComponentContext > m_xContext; + + Impl(uno::Reference const& xContext, + sal_Int16 const eCoreMeasureUnit, + sal_Int16 const eXMLMeasureUnit, + SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion) + : m_eCoreMeasureUnit(eCoreMeasureUnit) + , m_eXMLMeasureUnit(eXMLMeasureUnit) + , m_eODFVersion(nODFVersion) + , m_aNullDate(30, 12, 1899) + , m_xContext(xContext) + { + OSL_ENSURE( m_xContext.is(), "got no service manager" ); + } + + void createNumTypeInfo() const; +}; + + +void SvXMLUnitConverter::Impl::createNumTypeInfo() const +{ + Reference xDefNum = DefaultNumberingProvider::create(m_xContext); + m_xNumTypeInfo.set(xDefNum, uno::UNO_QUERY); +} + +const uno::Reference< text::XNumberingTypeInfo >& +SvXMLUnitConverter::getNumTypeInfo() const +{ + if (!m_pImpl->m_xNumTypeInfo.is()) + { + m_pImpl->createNumTypeInfo(); + } + return m_pImpl->m_xNumTypeInfo; +} + +void SvXMLUnitConverter::SetCoreMeasureUnit(sal_Int16 const eCoreMeasureUnit/*css::util::MeasureUnit*/) +{ + m_pImpl->m_eCoreMeasureUnit = eCoreMeasureUnit; +} + +void SvXMLUnitConverter::SetXMLMeasureUnit(sal_Int16 const eXMLMeasureUnit/*css::util::MeasureUnit*/) +{ + m_pImpl->m_eXMLMeasureUnit = eXMLMeasureUnit; +} + +sal_Int16 SvXMLUnitConverter::GetXMLMeasureUnit() const +{ + return m_pImpl->m_eXMLMeasureUnit; +} + +SvtSaveOptions::ODFSaneDefaultVersion SvXMLUnitConverter::getSaneDefaultVersion() const +{ + return m_pImpl->m_eODFVersion; +} + +void SvXMLUnitConverter::overrideSaneDefaultVersion( + SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion) +{ + m_pImpl->m_eODFVersion = nODFVersion; +} + +/** constructs a SvXMLUnitConverter. The core measure unit is the + default unit for numerical measures, the XML measure unit is + the default unit for textual measures +*/ + +SvXMLUnitConverter::SvXMLUnitConverter( + const uno::Reference& xContext, + sal_Int16 const eCoreMeasureUnit, + sal_Int16 const eXMLMeasureUnit, + SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion) +: m_pImpl(new Impl(xContext, eCoreMeasureUnit, eXMLMeasureUnit, nODFVersion)) +{ +} + +SvXMLUnitConverter::~SvXMLUnitConverter() +{ +} + +sal_Int16 SvXMLUnitConverter::GetMeasureUnit(FieldUnit const nFieldUnit) +{ + sal_Int16 eUnit = util::MeasureUnit::INCH; + switch( nFieldUnit ) + { + case FieldUnit::MM: + eUnit = util::MeasureUnit::MM; + break; + case FieldUnit::CM: + case FieldUnit::M: + case FieldUnit::KM: + eUnit = util::MeasureUnit::CM; + break; + case FieldUnit::TWIP: + eUnit = util::MeasureUnit::TWIP; + break; + case FieldUnit::POINT: + case FieldUnit::PICA: + eUnit = util::MeasureUnit::POINT; + break; + case FieldUnit::MM_100TH: + eUnit = util::MeasureUnit::MM_100TH; + break; + case FieldUnit::INCH: + eUnit = util::MeasureUnit::INCH; + break; + default: + assert(false); + break; + } + return eUnit; +} + +/** convert string to measure using optional min and max values*/ +bool SvXMLUnitConverter::convertMeasureToCore( sal_Int32& nValue, + std::u16string_view rString, + sal_Int32 nMin, sal_Int32 nMax ) const +{ + return ::sax::Converter::convertMeasure( nValue, rString, + m_pImpl->m_eCoreMeasureUnit, + nMin, nMax ); +} + +/** convert string to measure using optional min and max values*/ +bool SvXMLUnitConverter::convertMeasureToCore( sal_Int32& nValue, + std::string_view rString, + sal_Int32 nMin, sal_Int32 nMax ) const +{ + return ::sax::Converter::convertMeasure( nValue, rString, + m_pImpl->m_eCoreMeasureUnit, + nMin, nMax ); +} + +/** convert measure to string */ +void SvXMLUnitConverter::convertMeasureToXML( OUStringBuffer& rString, + sal_Int32 nMeasure ) const +{ + ::sax::Converter::convertMeasure( rString, nMeasure, + m_pImpl->m_eCoreMeasureUnit, + m_pImpl->m_eXMLMeasureUnit ); +} + +/** convert measure to string */ +OUString SvXMLUnitConverter::convertMeasureToXML( sal_Int32 nMeasure ) const +{ + OUStringBuffer s; + ::sax::Converter::convertMeasure( s, nMeasure, + m_pImpl->m_eCoreMeasureUnit, + m_pImpl->m_eXMLMeasureUnit ); + return s.makeStringAndClear(); +} + +/** convert string to enum using given enum map, if the enum is + not found in the map, this method will return false +*/ +bool SvXMLUnitConverter::convertEnumImpl( sal_uInt16& rEnum, + std::u16string_view rValue, + const SvXMLEnumStringMapEntry *pMap ) +{ + while( pMap->GetName() ) + { + auto nameLength = pMap->GetNameLength(); + if( static_cast(rValue.size()) == nameLength && + rtl_ustr_asciil_reverseEquals_WithLength( + rValue.data(), pMap->GetName(), nameLength ) ) + { + rEnum = pMap->GetValue(); + return true; + } + ++pMap; + } + + return false; +} + +/** convert string to enum using given token map, if the enum is + not found in the map, this method will return false */ +bool SvXMLUnitConverter::convertEnumImpl( + sal_uInt16& rEnum, + std::u16string_view rValue, + const SvXMLEnumMapEntry *pMap ) +{ + while( pMap->GetToken() != XML_TOKEN_INVALID ) + { + if( IsXMLToken( rValue, pMap->GetToken() ) ) + { + rEnum = pMap->GetValue(); + return true; + } + ++pMap; + } + return false; +} + +/** convert string to enum using given token map, if the enum is + not found in the map, this method will return false */ +bool SvXMLUnitConverter::convertEnumImpl( + sal_uInt16& rEnum, + std::string_view rValue, + const SvXMLEnumMapEntry *pMap ) +{ + while( pMap->GetToken() != XML_TOKEN_INVALID ) + { + if( IsXMLToken( rValue, pMap->GetToken() ) ) + { + rEnum = pMap->GetValue(); + return true; + } + ++pMap; + } + return false; +} + +/** convert enum to string using given token map with an optional + default token. If the enum is not found in the map, + this method will either use the given default or return + false if no default is set */ +bool SvXMLUnitConverter::convertEnumImpl( + OUStringBuffer& rBuffer, + sal_uInt16 nValue, + const SvXMLEnumMapEntry *pMap, + enum XMLTokenEnum eDefault) +{ + enum XMLTokenEnum eTok = eDefault; + + while( pMap->GetToken() != XML_TOKEN_INVALID ) + { + if( pMap->GetValue() == nValue ) + { + eTok = pMap->GetToken(); + break; + } + ++pMap; + } + + // the map may have contained XML_TOKEN_INVALID + if( eTok == XML_TOKEN_INVALID ) + eTok = eDefault; + + if( eTok != XML_TOKEN_INVALID ) + rBuffer.append( GetXMLToken(eTok) ); + + return (eTok != XML_TOKEN_INVALID); +} + +static int lcl_gethex( int nChar ) +{ + if( nChar >= '0' && nChar <= '9' ) + return nChar - '0'; + else if( nChar >= 'a' && nChar <= 'f' ) + return nChar - 'a' + 10; + else if( nChar >= 'A' && nChar <= 'F' ) + return nChar - 'A' + 10; + else + return 0; +} + +const char aHexTab[] = "0123456789abcdef"; + + +/** convert double number to string (using ::rtl::math) */ +void SvXMLUnitConverter::convertDouble(OUStringBuffer& rBuffer, + double fNumber) const +{ + ::sax::Converter::convertDouble(rBuffer, fNumber, + true/*bWriteUnits*/, m_pImpl->m_eCoreMeasureUnit, m_pImpl->m_eXMLMeasureUnit); +} + +/** convert string to double number (using ::rtl::math) */ +bool SvXMLUnitConverter::convertDouble(double& rValue, + std::u16string_view rString) const +{ + sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString( + rString, m_pImpl->m_eCoreMeasureUnit); + + return ::sax::Converter::convertDouble(rValue, rString, + eSrcUnit, m_pImpl->m_eCoreMeasureUnit); +} + +/** convert string to double number (using ::rtl::math) */ +bool SvXMLUnitConverter::convertDouble(double& rValue, + std::string_view rString) const +{ + sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString( + rString, m_pImpl->m_eCoreMeasureUnit); + + return ::sax::Converter::convertDouble(rValue, rString, + eSrcUnit, m_pImpl->m_eCoreMeasureUnit); +} + +/** get the Null Date of the XModel and set it to the UnitConverter */ +bool SvXMLUnitConverter::setNullDate(const css::uno::Reference & xModel) +{ + css::uno::Reference xNumberFormatsSupplier (xModel, css::uno::UNO_QUERY); + if (xNumberFormatsSupplier.is()) + { + const css::uno::Reference xPropertySet = xNumberFormatsSupplier->getNumberFormatSettings(); + return xPropertySet.is() && (xPropertySet->getPropertyValue(XML_NULLDATE) >>= m_pImpl->m_aNullDate); + } + return false; +} + +/** convert double to ISO Date Time String */ +void SvXMLUnitConverter::convertDateTime(OUStringBuffer& rBuffer, + const double& fDateTime, bool const bAddTimeIf0AM) +{ + convertDateTime(rBuffer, fDateTime, m_pImpl->m_aNullDate, bAddTimeIf0AM); +} + +/** convert ISO Date Time String to double */ +bool SvXMLUnitConverter::convertDateTime(double& fDateTime, + std::u16string_view rString) const +{ + return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate); +} + +/** convert ISO Date Time String to double */ +bool SvXMLUnitConverter::convertDateTime(double& fDateTime, + std::string_view rString) const +{ + return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate); +} + +/** convert double to ISO Date Time String */ +void SvXMLUnitConverter::convertDateTime( OUStringBuffer& rBuffer, + const double& fDateTime, + const css::util::Date& aTempNullDate, + bool bAddTimeIf0AM ) +{ + double fValue = fDateTime; + const sal_Int32 nDays = static_cast (::rtl::math::approxFloor (fValue)); + Date aDate (aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year); + aDate.AddDays( nDays); + fValue -= nDays; + const bool bHasTime = (fValue > 0.0); + + sal_Int16 nTempYear = aDate.GetYear(); + assert(nTempYear != 0); + if (nTempYear < 0) + { + rBuffer.append( '-'); + nTempYear = -nTempYear; + } + if (nTempYear < 1000) + rBuffer.append( '0'); + if (nTempYear < 100) + rBuffer.append( '0'); + if (nTempYear < 10) + rBuffer.append( '0'); + rBuffer.append( sal_Int32( nTempYear)); + rBuffer.append( '-'); + sal_uInt16 nTemp = aDate.GetMonth(); + assert(1 <= nTemp && nTemp <= 12); + if (nTemp < 10) + rBuffer.append( '0'); + rBuffer.append( sal_Int32( nTemp)); + rBuffer.append( '-'); + nTemp = aDate.GetDay(); + assert(1 <= nTemp && nTemp <= 31); + if (nTemp < 10) + rBuffer.append( '0'); + rBuffer.append( sal_Int32( nTemp)); + if (!(bHasTime || bAddTimeIf0AM)) + return; + + double fCount; + if (nDays > 0) + fCount = ::rtl::math::approxFloor (log10(static_cast(nDays))) + 1; + else if (nDays < 0) + fCount = ::rtl::math::approxFloor (log10(static_cast(nDays * -1))) + 1; + else + fCount = 0.0; + const int nDigits = sal_Int16(fCount) + 4; // +4 for *86400 in seconds + const int nFractionDecimals = std::max( XML_MAXDIGITSCOUNT_TIME - nDigits, 0); + + sal_uInt16 nHour, nMinute, nSecond; + double fFractionOfSecond; + // Pass the original date+time value for proper scaling and rounding. + tools::Time::GetClock( fDateTime, nHour, nMinute, nSecond, fFractionOfSecond, nFractionDecimals); + + rBuffer.append( 'T'); + if (nHour < 10) + rBuffer.append( '0'); + rBuffer.append( sal_Int32( nHour)); + rBuffer.append( ':'); + if (nMinute < 10) + rBuffer.append( '0'); + rBuffer.append( sal_Int32( nMinute)); + rBuffer.append( ':'); + if (nSecond < 10) + rBuffer.append( '0'); + rBuffer.append( sal_Int32( nSecond)); + if (!nFractionDecimals) + return; + + // nFractionDecimals+1 to not round up what GetClock() carefully + // truncated. + OUString aFraction( ::rtl::math::doubleToUString( fFractionOfSecond, + rtl_math_StringFormat_F, + nFractionDecimals + 1, '.', true)); + const sal_Int32 nLen = aFraction.getLength(); + if ( nLen > 2 ) + { + // Truncate nFractionDecimals+1 digit if it was not rounded to zero. + const sal_Int32 nCount = nLen - 2 - static_cast(nLen > nFractionDecimals + 2); + rBuffer.append( '.'); + rBuffer.append( aFraction.subView(2, nCount)); // strip 0. + } +} + +/** convert ISO Date Time String to double */ +template +static bool lcl_convertDateTime( double& fDateTime, + V rString, const css::util::Date& aTempNullDate) +{ + css::util::DateTime aDateTime; + bool bSuccess = ::sax::Converter::parseDateTime(aDateTime, rString); + + if (bSuccess) + { + const Date aTmpNullDate(aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year); + const Date aTempDate(aDateTime.Day, aDateTime.Month, aDateTime.Year); + const sal_Int32 nTage = aTempDate - aTmpNullDate; + double fTempDateTime = nTage; + double Hour = aDateTime.Hours; + double Min = aDateTime.Minutes; + double Sec = aDateTime.Seconds; + double NanoSec = aDateTime.NanoSeconds; + fTempDateTime += Hour / ::tools::Time::hourPerDay; + fTempDateTime += Min / ::tools::Time::minutePerDay; + fTempDateTime += Sec / ::tools::Time::secondPerDay; + fTempDateTime += NanoSec / ::tools::Time::nanoSecPerDay; + fDateTime = fTempDateTime; + } + return bSuccess; +} + +bool SvXMLUnitConverter::convertDateTime( double& fDateTime, + std::u16string_view rString, const css::util::Date& aTempNullDate) +{ + return lcl_convertDateTime(fDateTime, rString, aTempNullDate); +} +/** convert ISO Date Time String to double */ +bool SvXMLUnitConverter::convertDateTime( double& fDateTime, + std::string_view rString, const css::util::Date& aTempNullDate) +{ + return lcl_convertDateTime(fDateTime, rString, aTempNullDate); +} + + +SvXMLTokenEnumerator::SvXMLTokenEnumerator( std::u16string_view rString, sal_Unicode cSeparator /* = ' ' */ ) +: maTokenString( rString ), mnNextTokenPos(0), mcSeparator( cSeparator ) +{ +} + +bool SvXMLTokenEnumerator::getNextToken( std::u16string_view& rToken ) +{ + if( std::u16string_view::npos == mnNextTokenPos ) + return false; + + size_t nTokenEndPos = maTokenString.find( mcSeparator, mnNextTokenPos ); + if( nTokenEndPos != std::u16string_view::npos ) + { + rToken = maTokenString.substr( mnNextTokenPos, + nTokenEndPos - mnNextTokenPos ); + mnNextTokenPos = nTokenEndPos + 1; + + // if the mnNextTokenPos is at the end of the string, we have + // to deliver an empty token + if( mnNextTokenPos > maTokenString.size() ) + mnNextTokenPos = std::u16string_view::npos; + } + else + { + rToken = maTokenString.substr( mnNextTokenPos ); + mnNextTokenPos = std::u16string_view::npos; + } + + return true; +} + +static bool lcl_getPositions(std::string_view _sValue, std::string_view& _rContentX, std::string_view& _rContentY, std::string_view& _rContentZ) +{ + if(_sValue.empty() || _sValue[0] != '(') + return false; + + size_t nPos(1); + size_t nFound = _sValue.find(' ', nPos); + + if(nFound == std::string_view::npos || nFound <= nPos) + return false; + + _rContentX = _sValue.substr(nPos, nFound - nPos); + + nPos = nFound + 1; + nFound = _sValue.find(' ', nPos); + + if(nFound == std::string_view::npos || nFound <= nPos) + return false; + + _rContentY = _sValue.substr(nPos, nFound - nPos); + + nPos = nFound + 1; + nFound = _sValue.find(')', nPos); + + if(nFound == std::string_view::npos || nFound <= nPos) + return false; + + _rContentZ = _sValue.substr(nPos, nFound - nPos); + return true; + +} + +/** convert string to ::basegfx::B3DVector */ +bool SvXMLUnitConverter::convertB3DVector( ::basegfx::B3DVector& rVector, std::string_view rValue ) +{ + std::string_view aContentX,aContentY,aContentZ; + if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) ) + return false; + + rtl_math_ConversionStatus eStatus; + + rVector.setX(::rtl::math::stringToDouble(aContentX, '.', + ',', &eStatus)); + + if( eStatus != rtl_math_ConversionStatus_Ok ) + return false; + + rVector.setY(::rtl::math::stringToDouble(aContentY, '.', + ',', &eStatus)); + + if( eStatus != rtl_math_ConversionStatus_Ok ) + return false; + + rVector.setZ(::rtl::math::stringToDouble(aContentZ, '.', + ',', &eStatus)); + + + return ( eStatus == rtl_math_ConversionStatus_Ok ); +} + +/** convert ::basegfx::B3DVector to string */ +void SvXMLUnitConverter::convertB3DVector( OUStringBuffer &rBuffer, const ::basegfx::B3DVector& rVector ) +{ + rBuffer.append('('); + ::sax::Converter::convertDouble(rBuffer, rVector.getX()); + rBuffer.append(' '); + ::sax::Converter::convertDouble(rBuffer, rVector.getY()); + rBuffer.append(' '); + ::sax::Converter::convertDouble(rBuffer, rVector.getZ()); + rBuffer.append(')'); +} + +/** convert string to Position3D */ +bool SvXMLUnitConverter::convertPosition3D( drawing::Position3D& rPosition, + std::string_view rValue ) const +{ + std::string_view aContentX,aContentY,aContentZ; + if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) ) + return false; + + if ( !convertDouble( rPosition.PositionX, aContentX ) ) + return false; + if ( !convertDouble( rPosition.PositionY, aContentY ) ) + return false; + return convertDouble( rPosition.PositionZ, aContentZ ); +} + +/** convert Position3D to string */ +void SvXMLUnitConverter::convertPosition3D( OUStringBuffer &rBuffer, + const drawing::Position3D& rPosition ) +{ + rBuffer.append( '(' ); + convertDouble( rBuffer, rPosition.PositionX ); + rBuffer.append( ' ' ); + convertDouble( rBuffer, rPosition.PositionY ); + rBuffer.append( ' ' ); + convertDouble( rBuffer, rPosition.PositionZ ); + rBuffer.append( ')' ); +} + +bool SvXMLUnitConverter::convertNumFormat( + sal_Int16& rType, + const OUString& rNumFmt, + std::u16string_view rNumLetterSync, + bool bNumberNone ) const +{ + bool bRet = true; + bool bExt = false; + + sal_Int32 nLen = rNumFmt.getLength(); + if( 0 == nLen ) + { + if( bNumberNone ) + rType = NumberingType::NUMBER_NONE; + else + bRet = false; + } + else if( 1 == nLen ) + { + switch( rNumFmt[0] ) + { + case '1': rType = NumberingType::ARABIC; break; + case 'a': rType = NumberingType::CHARS_LOWER_LETTER; break; + case 'A': rType = NumberingType::CHARS_UPPER_LETTER; break; + case 'i': rType = NumberingType::ROMAN_LOWER; break; + case 'I': rType = NumberingType::ROMAN_UPPER; break; + default: bExt = true; break; + } + if( !bExt && IsXMLToken( rNumLetterSync, XML_TRUE ) ) + { + switch( rType ) + { + case NumberingType::CHARS_LOWER_LETTER: + rType = NumberingType::CHARS_LOWER_LETTER_N; + break; + case NumberingType::CHARS_UPPER_LETTER: + rType = NumberingType::CHARS_UPPER_LETTER_N; + break; + } + } + } + else + { + bExt = true; + } + if( bExt ) + { + Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo(); + if( xInfo.is() && xInfo->hasNumberingType( rNumFmt ) ) + { + rType = xInfo->getNumberingType( rNumFmt ); + } + else + { + rType = NumberingType::ARABIC; + } + } + + return bRet; +} + +void SvXMLUnitConverter::convertNumFormat( OUStringBuffer& rBuffer, + sal_Int16 nType ) const +{ + enum XMLTokenEnum eFormat = XML_TOKEN_INVALID; + switch( nType ) + { + case NumberingType::CHARS_UPPER_LETTER: eFormat = XML_A_UPCASE; break; + case NumberingType::CHARS_LOWER_LETTER: eFormat = XML_A; break; + case NumberingType::ROMAN_UPPER: eFormat = XML_I_UPCASE; break; + case NumberingType::ROMAN_LOWER: eFormat = XML_I; break; + case NumberingType::ARABIC: eFormat = XML_1; break; + case NumberingType::CHARS_UPPER_LETTER_N: eFormat = XML_A_UPCASE; break; + case NumberingType::CHARS_LOWER_LETTER_N: eFormat = XML_A; break; + case NumberingType::NUMBER_NONE: eFormat = XML__EMPTY; break; + + case NumberingType::CHAR_SPECIAL: + case NumberingType::PAGE_DESCRIPTOR: + case NumberingType::BITMAP: + SAL_WARN_IF( eFormat == XML_TOKEN_INVALID, "xmloff", "invalid number format" ); + break; + default: + break; + } + + if( eFormat != XML_TOKEN_INVALID ) + { + rBuffer.append( GetXMLToken(eFormat) ); + } + else + { + Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo(); + if( xInfo.is() ) + rBuffer.append( xInfo->getNumberingIdentifier( nType ) ); + } +} + +void SvXMLUnitConverter::convertNumLetterSync( OUStringBuffer& rBuffer, + sal_Int16 nType ) +{ + enum XMLTokenEnum eSync = XML_TOKEN_INVALID; + switch( nType ) + { + case NumberingType::CHARS_UPPER_LETTER: + case NumberingType::CHARS_LOWER_LETTER: + case NumberingType::ROMAN_UPPER: + case NumberingType::ROMAN_LOWER: + case NumberingType::ARABIC: + case NumberingType::NUMBER_NONE: + break; + + case NumberingType::CHARS_UPPER_LETTER_N: + case NumberingType::CHARS_LOWER_LETTER_N: + eSync = XML_TRUE; + break; + + case NumberingType::CHAR_SPECIAL: + case NumberingType::PAGE_DESCRIPTOR: + case NumberingType::BITMAP: + SAL_WARN_IF( eSync == XML_TOKEN_INVALID, "xmloff", "invalid number format" ); + break; + } + if( eSync != XML_TOKEN_INVALID ) + rBuffer.append( GetXMLToken(eSync) ); +} + +void SvXMLUnitConverter::convertPropertySet(uno::Sequence& rProps, + const uno::Reference& aProperties) +{ + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = aProperties->getPropertySetInfo(); + if (!xPropertySetInfo.is()) + return; + + const uno::Sequence< beans::Property > aProps = xPropertySetInfo->getProperties(); + if (aProps.hasElements()) + { + rProps.realloc(aProps.getLength()); + beans::PropertyValue* pProps = rProps.getArray(); + for (const auto& rProp : aProps) + { + pProps->Name = rProp.Name; + pProps->Value = aProperties->getPropertyValue(rProp.Name); + ++pProps; + } + } +} + +void SvXMLUnitConverter::convertPropertySet(uno::Reference const & rProperties, + const uno::Sequence& aProps) +{ + if (aProps.hasElements()) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = rProperties->getPropertySetInfo(); + if (xPropertySetInfo.is()) + { + for (const auto& rProp : aProps) + { + if (xPropertySetInfo->hasPropertyByName(rProp.Name)) + rProperties->setPropertyValue(rProp.Name, rProp.Value); + } + } + } +} + + +OUString SvXMLUnitConverter::encodeStyleName( + const OUString& rName, + bool *pEncoded ) const +{ + if( pEncoded ) + *pEncoded = false; + + sal_Int32 nLen = rName.getLength(); + OUStringBuffer aBuffer( nLen*2 ); + + for( sal_Int32 i = 0; i < nLen; i++ ) + { + sal_Unicode c = rName[i]; + bool bValidChar = false; + if( c < 0x00ffU ) + { + bValidChar = + (c >= 0x0041 && c <= 0x005a) || + (c >= 0x0061 && c <= 0x007a) || + (c >= 0x00c0 && c <= 0x00d6) || + (c >= 0x00d8 && c <= 0x00f6) || + (c >= 0x00f8 && c <= 0x00ff) || + ( i > 0 && ( (c >= 0x0030 && c <= 0x0039) || + c == 0x00b7 || c == '-' || c == '.') ); + } + else + { + if( (c >= 0xf900U && c <= 0xfffeU) || + (c >= 0x20ddU && c <= 0x20e0U)) + { + bValidChar = false; + } + else if( (c >= 0x02bbU && c <= 0x02c1U) || c == 0x0559 || + c == 0x06e5 || c == 0x06e6 ) + { + bValidChar = true; + } + else if( c == 0x0387 ) + { + bValidChar = i > 0; + } + else + { + if (!m_pImpl->m_xCharClass.is()) + { + m_pImpl->m_xCharClass = CharacterClassification::create( m_pImpl->m_xContext ); + } + sal_Int16 nType = m_pImpl->m_xCharClass->getType(rName, i); + + switch( nType ) + { + case UnicodeType::UPPERCASE_LETTER: // Lu + case UnicodeType::LOWERCASE_LETTER: // Ll + case UnicodeType::TITLECASE_LETTER: // Lt + case UnicodeType::OTHER_LETTER: // Lo + case UnicodeType::LETTER_NUMBER: // Nl + bValidChar = true; + break; + case UnicodeType::NON_SPACING_MARK: // Ms + case UnicodeType::ENCLOSING_MARK: // Me + case UnicodeType::COMBINING_SPACING_MARK: //Mc + case UnicodeType::MODIFIER_LETTER: // Lm + case UnicodeType::DECIMAL_DIGIT_NUMBER: // Nd + bValidChar = i > 0; + break; + } + } + } + if( bValidChar ) + { + aBuffer.append( c ); + } + else + { + aBuffer.append( '_' ); + if( c > 0x0fff ) + aBuffer.append( static_cast< sal_Unicode >( + aHexTab[ (c >> 12) & 0x0f ] ) ); + if( c > 0x00ff ) + aBuffer.append( static_cast< sal_Unicode >( + aHexTab[ (c >> 8) & 0x0f ] ) ); + if( c > 0x000f ) + aBuffer.append( static_cast< sal_Unicode >( + aHexTab[ (c >> 4) & 0x0f ] ) ); + aBuffer.append( static_cast< sal_Unicode >( + aHexTab[ c & 0x0f ] ) ); + aBuffer.append( '_' ); + if( pEncoded ) + *pEncoded = true; + } + } + + // check for length + if( aBuffer.getLength() > ((1<<15)-1) ) + { + aBuffer = rName; + if( pEncoded ) + *pEncoded = false; + } + + + return aBuffer.makeStringAndClear(); +} + +/** convert string (hex) to number (sal_uInt32) */ +bool SvXMLUnitConverter::convertHex( sal_uInt32& nVal, std::u16string_view rValue ) +{ + if( rValue.size() != 8 ) + return false; + + nVal = 0; + for ( int i = 0; i < 8; i++ ) + { + nVal = ( nVal << 4 ) + | sal::static_int_cast< sal_uInt32 >( lcl_gethex( rValue[i] ) ); + } + + return true; +} + +/** convert number (sal_uInt32) to string (hex) */ +void SvXMLUnitConverter::convertHex( OUStringBuffer& rBuffer, + sal_uInt32 nVal ) +{ + for ( int i = 0; i < 8; i++ ) + { + rBuffer.append( sal_Unicode( aHexTab[ nVal >> 28 ] ) ); + nVal <<= 4; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/EnhancedCustomShapeToken.cxx b/xmloff/source/draw/EnhancedCustomShapeToken.cxx new file mode 100644 index 000000000..bd0613e9e --- /dev/null +++ b/xmloff/source/draw/EnhancedCustomShapeToken.cxx @@ -0,0 +1,214 @@ +/* -*- 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 +#include +#include +#include + +namespace xmloff::EnhancedCustomShapeToken { + + +namespace { + +struct TokenTable +{ + const char* pS; + EnhancedCustomShapeTokenEnum pE; +}; + +} + +const TokenTable pTokenTableArray[] = +{ + { "type", EAS_type }, + { "name", EAS_name }, + { "mirror-horizontal", EAS_mirror_horizontal }, + { "mirror-vertical", EAS_mirror_vertical }, + { "viewBox", EAS_viewBox }, + { "text-rotate-angle", EAS_text_rotate_angle }, + { "extrusion-allowed", EAS_extrusion_allowed }, + { "extrusion-text-path-allowed", EAS_text_path_allowed }, + { "extrusion-concentric-gradient-fill", EAS_concentric_gradient_fill_allowed }, + { "extrusion", EAS_extrusion }, + { "extrusion-brightness", EAS_extrusion_brightness }, + { "extrusion-depth", EAS_extrusion_depth }, + { "extrusion-diffusion", EAS_extrusion_diffusion }, + { "extrusion-number-of-line-segments", EAS_extrusion_number_of_line_segments }, + { "extrusion-light-face", EAS_extrusion_light_face }, + { "extrusion-first-light-harsh", EAS_extrusion_first_light_harsh }, + { "extrusion-second-light-harsh", EAS_extrusion_second_light_harsh }, + { "extrusion-first-light-level", EAS_extrusion_first_light_level }, + { "extrusion-second-light-level", EAS_extrusion_second_light_level }, + { "extrusion-first-light-direction", EAS_extrusion_first_light_direction }, + { "extrusion-second-light-direction", EAS_extrusion_second_light_direction }, + { "extrusion-metal", EAS_extrusion_metal }, + { "extrusion-metal-type", EAS_extrusion_metal_type }, + { "shade-mode", EAS_shade_mode }, + { "extrusion-rotation-angle", EAS_extrusion_rotation_angle }, + { "extrusion-rotation-center", EAS_extrusion_rotation_center }, + { "extrusion-shininess", EAS_extrusion_shininess }, + { "extrusion-skew", EAS_extrusion_skew }, + { "extrusion-specularity", EAS_extrusion_specularity }, + { "extrusion-specularity-loext", EAS_extrusion_specularity_loext }, + { "projection", EAS_projection }, + { "extrusion-viewpoint", EAS_extrusion_viewpoint }, + { "extrusion-origin", EAS_extrusion_origin }, + { "extrusion-color", EAS_extrusion_color }, + { "enhanced-path", EAS_enhanced_path }, + { "path-stretchpoint-x", EAS_path_stretchpoint_x }, + { "path-stretchpoint-y", EAS_path_stretchpoint_y }, + { "text-areas", EAS_text_areas }, + { "glue-points", EAS_glue_points }, + { "glue-point-type", EAS_glue_point_type }, + { "glue-point-leaving-directions", EAS_glue_point_leaving_directions }, + { "text-path", EAS_text_path }, + { "text-path-mode", EAS_text_path_mode }, + { "text-path-scale", EAS_text_path_scale }, + { "text-path-same-letter-heights", EAS_text_path_same_letter_heights }, + { "modifiers", EAS_modifiers }, + { "equation", EAS_equation }, + { "formula", EAS_formula }, + { "handle", EAS_handle }, + { "handle-mirror-horizontal", EAS_handle_mirror_horizontal }, + { "handle-mirror-vertical", EAS_handle_mirror_vertical }, + { "handle-switched", EAS_handle_switched }, + { "handle-position", EAS_handle_position }, + { "handle-range-x-minimum", EAS_handle_range_x_minimum }, + { "handle-range-x-maximum", EAS_handle_range_x_maximum }, + { "handle-range-y-minimum", EAS_handle_range_y_minimum }, + { "handle-range-y-maximum", EAS_handle_range_y_maximum }, + { "handle-polar", EAS_handle_polar }, + { "handle-radius-range-minimum", EAS_handle_radius_range_minimum }, + { "handle-radius-range-maximum", EAS_handle_radius_range_maximum }, + { "sub-view-size", EAS_sub_view_size }, + + { "CustomShapeEngine", EAS_CustomShapeEngine }, + { "CustomShapeData", EAS_CustomShapeData }, + { "Type", EAS_Type }, + { "MirroredX", EAS_MirroredX }, + { "MirroredY", EAS_MirroredY }, + { "ViewBox", EAS_ViewBox }, + { "TextRotateAngle", EAS_TextRotateAngle }, + { "TextPreRotateAngle", EAS_TextPreRotateAngle }, + { "ExtrusionAllowed", EAS_ExtrusionAllowed }, + { "TextPathAllowed", EAS_TextPathAllowed }, + { "ConcentricGradientFillAllowed", EAS_ConcentricGradientFillAllowed }, + { "Extrusion", EAS_Extrusion }, + { "Equations", EAS_Equations }, + { "Equation", EAS_Equation }, + { "Path", EAS_Path }, + { "TextPath", EAS_TextPath }, + { "Handles", EAS_Handles }, + { "Handle", EAS_Handle }, + { "Brightness", EAS_Brightness }, + { "Depth", EAS_Depth }, + { "Diffusion", EAS_Diffusion }, + { "NumberOfLineSegments", EAS_NumberOfLineSegments }, + { "LightFace", EAS_LightFace }, + { "FirstLightHarsh", EAS_FirstLightHarsh }, + { "SecondLightHarsh", EAS_SecondLightHarsh }, + { "FirstLightLevel", EAS_FirstLightLevel }, + { "SecondLightLevel", EAS_SecondLightLevel }, + { "FirstLightDirection", EAS_FirstLightDirection }, + { "SecondLightDirection", EAS_SecondLightDirection }, + { "Metal", EAS_Metal }, + { "MetalType", EAS_MetalType }, + { "ShadeMode", EAS_ShadeMode }, + { "RotateAngle", EAS_RotateAngle }, + { "RotationCenter", EAS_RotationCenter }, + { "Shininess", EAS_Shininess }, + { "Skew", EAS_Skew }, + { "Specularity", EAS_Specularity }, + { "ProjectionMode", EAS_ProjectionMode }, + { "ViewPoint", EAS_ViewPoint }, + { "Origin", EAS_Origin }, + { "Color", EAS_Color }, + { "Switched", EAS_Switched }, + { "Polar", EAS_Polar }, + { "RangeXMinimum", EAS_RangeXMinimum }, + { "RangeXMaximum", EAS_RangeXMaximum }, + { "RangeYMinimum", EAS_RangeYMinimum }, + { "RangeYMaximum", EAS_RangeYMaximum }, + { "RadiusRangeMinimum", EAS_RadiusRangeMinimum }, + { "RadiusRangeMaximum", EAS_RadiusRangeMaximum }, + { "Coordinates", EAS_Coordinates }, + { "Segments", EAS_Segments }, + { "StretchX", EAS_StretchX }, + { "StretchY", EAS_StretchY }, + { "TextFrames", EAS_TextFrames }, + { "GluePoints", EAS_GluePoints }, + { "GluePointLeavingDirections", EAS_GluePointLeavingDirections }, + { "GluePointType", EAS_GluePointType }, + { "TextPathMode", EAS_TextPathMode }, + { "ScaleX", EAS_ScaleX }, + { "SameLetterHeights", EAS_SameLetterHeights }, + { "Position", EAS_Position }, + { "AdjustmentValues", EAS_AdjustmentValues }, + { "SubViewSize", EAS_SubViewSize }, + + { "Last", EAS_Last }, + { "NotFound", EAS_NotFound } +}; + +typedef std::unordered_map< const char*, EnhancedCustomShapeTokenEnum, rtl::CStringHash, rtl::CStringEqual> TypeNameHashMap; +static const TypeNameHashMap& GetNameHashMap() +{ + static TypeNameHashMap aHashMap = []() + { // init hash map + TypeNameHashMap res; + for (auto const & pair : pTokenTableArray) + res[pair.pS] = pair.pE; + return res; + }(); + + return aHashMap; +} + +EnhancedCustomShapeTokenEnum EASGet( const OUString& rShapeType ) +{ + EnhancedCustomShapeTokenEnum eRetValue = EAS_NotFound; + int i, nLen = rShapeType.getLength(); + std::unique_ptr pBuf(new char[ nLen + 1 ]); + for ( i = 0; i < nLen; i++ ) + pBuf[ i ] = static_cast(rShapeType[ i ]); + pBuf[ i ] = 0; + auto& rHashMap = GetNameHashMap(); + TypeNameHashMap::const_iterator aHashIter( rHashMap.find( pBuf.get() ) ); + if ( aHashIter != rHashMap.end() ) + eRetValue = (*aHashIter).second; + return eRetValue; +} + +EnhancedCustomShapeTokenEnum EASGet( sal_Int32 nToken ) +{ + return EASGet(SvXMLImport::getNameFromToken(nToken)); +} + +OUString EASGet( const EnhancedCustomShapeTokenEnum eToken ) +{ + sal_uInt32 i = eToken >= EAS_Last + ? sal_uInt32(EAS_NotFound) + : static_cast(eToken); + return OUString::createFromAscii( pTokenTableArray[ i ].pS ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/QRCodeContext.cxx b/xmloff/source/draw/QRCodeContext.cxx new file mode 100644 index 000000000..597838f78 --- /dev/null +++ b/xmloff/source/draw/QRCodeContext.cxx @@ -0,0 +1,91 @@ +/* -*- 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 "QRCodeContext.hxx" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace css; +using namespace css::xml::sax; +using namespace css::uno; +using namespace css::drawing; +using namespace css::embed; +using namespace css::frame; +using namespace css::io; +using namespace css::graphic; +using namespace xmloff::token; + +QRCodeContext::QRCodeContext(SvXMLImport& rImport, sal_Int32 /*nElement*/, + const Reference& xAttrList, + const Reference& rxShape) + : SvXMLImportContext(rImport) +{ + Reference xPropSet(rxShape, UNO_QUERY_THROW); + + css::drawing::BarCode aBarCode; + + for (auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_QRCODE_ERROR_CORRECTION): + { + OUString aErrorCorrValue = aIter.toString(); + + if (aErrorCorrValue == "low") + aBarCode.ErrorCorrection = css::drawing::BarCodeErrorCorrection::LOW; + else if (aErrorCorrValue == "medium") + aBarCode.ErrorCorrection = css::drawing::BarCodeErrorCorrection::MEDIUM; + else if (aErrorCorrValue == "quartile") + aBarCode.ErrorCorrection = css::drawing::BarCodeErrorCorrection::QUARTILE; + else + aBarCode.ErrorCorrection = css::drawing::BarCodeErrorCorrection::HIGH; + break; + } + case XML_ELEMENT(LO_EXT, XML_QRCODE_BORDER): + { + sal_Int32 nAttrVal; + if (sax::Converter::convertNumber(nAttrVal, aIter.toView(), 0)) + aBarCode.Border = nAttrVal; + break; + } + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + { + aBarCode.Payload = aIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_QRCODE_TYPE): + { + sal_Int32 nAttrVal; + if (sax::Converter::convertNumber(nAttrVal, aIter.toView(), 0)) + aBarCode.Type = nAttrVal; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + xPropSet->setPropertyValue("BarCodeProperties", Any(aBarCode)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmloff/source/draw/QRCodeContext.hxx b/xmloff/source/draw/QRCodeContext.hxx new file mode 100644 index 000000000..c35c6f9bd --- /dev/null +++ b/xmloff/source/draw/QRCodeContext.hxx @@ -0,0 +1,26 @@ +/* -*- 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 +#include + +// Used to import QR code properties from a QR code in ODF document +// @see ximpshap + +class QRCodeContext : public SvXMLImportContext +{ +public: + QRCodeContext(SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference& xAttrList, + const css::uno::Reference& rxShape); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmloff/source/draw/SignatureLineContext.cxx b/xmloff/source/draw/SignatureLineContext.cxx new file mode 100644 index 000000000..0217156e3 --- /dev/null +++ b/xmloff/source/draw/SignatureLineContext.cxx @@ -0,0 +1,136 @@ +/* -*- 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 "SignatureLineContext.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using namespace css; +using namespace css::xml::sax; +using namespace css::uno; +using namespace css::drawing; +using namespace css::embed; +using namespace css::frame; +using namespace css::io; +using namespace css::graphic; +using namespace css::security; +using namespace xmloff::token; + +SignatureLineContext::SignatureLineContext(SvXMLImport& rImport, sal_Int32 /*nElement*/, + const Reference& xAttrList, + const Reference& rxShape) + : SvXMLImportContext(rImport) +{ + Reference xPropSet(rxShape, UNO_QUERY_THROW); + + xPropSet->setPropertyValue("IsSignatureLine", Any(true)); + + xPropSet->setPropertyValue("SignatureLineId", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_ID)))); + xPropSet->setPropertyValue( + "SignatureLineSuggestedSignerName", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SUGGESTED_SIGNER_NAME)))); + xPropSet->setPropertyValue( + "SignatureLineSuggestedSignerTitle", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SUGGESTED_SIGNER_TITLE)))); + xPropSet->setPropertyValue( + "SignatureLineSuggestedSignerEmail", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SUGGESTED_SIGNER_EMAIL)))); + xPropSet->setPropertyValue( + "SignatureLineSigningInstructions", + Any(xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SIGNING_INSTRUCTIONS)))); + + bool bShowSignDate = xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_SHOW_SIGN_DATE)) + == GetXMLToken(XML_TRUE); + bool bCanAddComment = xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_CAN_ADD_COMMENT)) + == GetXMLToken(XML_TRUE); + xPropSet->setPropertyValue("SignatureLineShowSignDate", Any(bShowSignDate)); + xPropSet->setPropertyValue("SignatureLineCanAddComment", Any(bCanAddComment)); + + // Save unsigned graphic (need it when exporting) + Reference xUnsignedGraphic; + xPropSet->getPropertyValue("Graphic") >>= xUnsignedGraphic; + if (xUnsignedGraphic.is()) + xPropSet->setPropertyValue("SignatureLineUnsignedImage", Any(xUnsignedGraphic)); + + Reference xGraphic; + try + { + // Get the document signatures + css::uno::Reference xStorable(GetImport().GetModel(), UNO_QUERY_THROW); + Reference xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL( + ZIP_STORAGE_FORMAT_STRING, xStorable->getLocation(), ElementModes::READ); + + if (!xStorage.is()) + { + SAL_WARN("xmloff", "No xStorage!"); + return; + } + + OUString const aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(xStorage)); + Reference xSignatures( + security::DocumentDigitalSignatures::createWithVersion( + comphelper::getProcessComponentContext(), aODFVersion)); + + const Sequence xSignatureInfo + = xSignatures->verifyDocumentContentSignatures(xStorage, Reference()); + + // Try to find matching signature line image - if none exists that is fine, + // then the signature line is not digitally signed. + auto pSignatureInfo + = std::find_if(xSignatureInfo.begin(), xSignatureInfo.end(), + [&xAttrList](const DocumentSignatureInformation& rSignatureInfo) { + return rSignatureInfo.SignatureLineId + == xAttrList->getOptionalValue(XML_ELEMENT(LO_EXT, XML_ID)); + }); + bool bIsSigned(false); + if (pSignatureInfo != xSignatureInfo.end()) + { + bIsSigned = true; + if (pSignatureInfo->SignatureIsValid) + { + // Signature is valid, use the 'valid' image + SAL_WARN_IF(!pSignatureInfo->ValidSignatureLineImage.is(), "xmloff", + "No ValidSignatureLineImage!"); + xGraphic = pSignatureInfo->ValidSignatureLineImage; + } + else + { + // Signature is invalid, use the 'invalid' image + SAL_WARN_IF(!pSignatureInfo->InvalidSignatureLineImage.is(), "xmloff", + "No InvalidSignatureLineImage!"); + xGraphic = pSignatureInfo->InvalidSignatureLineImage; + } + + xPropSet->setPropertyValue("Graphic", Any(xGraphic)); + } + xPropSet->setPropertyValue("SignatureLineIsSigned", Any(bIsSigned)); + } + catch (css::uno::Exception&) + { + // DocumentDigitalSignatures service not available. + // We render the "unsigned" shape instead. + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmloff/source/draw/SignatureLineContext.hxx b/xmloff/source/draw/SignatureLineContext.hxx new file mode 100644 index 000000000..68a9373ae --- /dev/null +++ b/xmloff/source/draw/SignatureLineContext.hxx @@ -0,0 +1,25 @@ +/* -*- 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 +#include + +// signatureline inside a shape + +class SignatureLineContext : public SvXMLImportContext +{ +public: + SignatureLineContext(SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference& xAttrList, + const css::uno::Reference& rxShape); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/xmloff/source/draw/XMLGraphicsDefaultStyle.cxx b/xmloff/source/draw/XMLGraphicsDefaultStyle.cxx new file mode 100644 index 000000000..4f9799c48 --- /dev/null +++ b/xmloff/source/draw/XMLGraphicsDefaultStyle.cxx @@ -0,0 +1,189 @@ +/* -*- 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 + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::xml::sax; + +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_TEXT_PROPERTIES; +using ::xmloff::token::XML_GRAPHIC_PROPERTIES; +using ::xmloff::token::XML_PARAGRAPH_PROPERTIES; + + +XMLGraphicsDefaultStyle::XMLGraphicsDefaultStyle( SvXMLImport& rImport, SvXMLStylesContext& rStyles ) +: XMLPropStyleContext( rImport, rStyles, XmlStyleFamily::SD_GRAPHICS_ID, true ) +{ +} + +XMLGraphicsDefaultStyle::~XMLGraphicsDefaultStyle() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLGraphicsDefaultStyle::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) || + IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + sal_uInt32 nFamily = 0; + if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_GRAPHIC_PROPERTIES ) + nFamily = XML_TYPE_PROP_GRAPHIC; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new XMLShapePropertySetContext( GetImport(), nElement, xAttrList, nFamily, GetProperties(), xImpPrMap ); + } + } + + return XMLPropStyleContext::createFastChildContext( nElement, xAttrList ); +} + +namespace { + +struct XMLPropertyByIndex { + sal_Int32 const m_nIndex; + explicit XMLPropertyByIndex(sal_Int32 const nIndex) : m_nIndex(nIndex) {} + bool operator()(XMLPropertyState const& rProp) { + return m_nIndex == rProp.mnIndex; + } +}; + +} + +// This method is called for every default style +void XMLGraphicsDefaultStyle::SetDefaults() +{ + Reference< XMultiServiceFactory > xFact( GetImport().GetModel(), UNO_QUERY ); + if( !xFact.is() ) + return; + + Reference< XPropertySet > xDefaults( xFact->createInstance( "com.sun.star.drawing.Defaults" ), UNO_QUERY ); + if( !xDefaults.is() ) + return; + // SJ: #i114750# + bool bWordWrapDefault = true; // initializing with correct ODF fo:wrap-option default + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); + if ( bBuildIdFound && ( + ((nUPD >= 600) && (nUPD < 700)) + || + ((nUPD == 300) && (nBuild <= 9535)) + || + ((nUPD > 300) && (nUPD <= 330)) + ) ) + bWordWrapDefault = false; + + static const OUStringLiteral sTextWordWrap( u"TextWordWrap" ); + Reference< XPropertySetInfo > xInfo( xDefaults->getPropertySetInfo() ); + if ( xInfo->hasPropertyByName( sTextWordWrap ) ) + xDefaults->setPropertyValue( sTextWordWrap, Any( bWordWrapDefault ) ); + + if (GetImport().IsOOoXML() + && xInfo->hasPropertyByName("IsFollowingTextFlow")) + { + // OOo 1.x only supported "true" so that is the more appropriate + // default for OOoXML format documents. + xDefaults->setPropertyValue("IsFollowingTextFlow", uno::Any(true)); + } + + // NOTE: the only reason why it's legal to check "==" (not "<") against + // arbitrary versions here is that the default value of these attributes + // is not defined by ODF, therefore it is implementation-defined + // (and we of course must not override any attributes that are actually + // in the document, so check for that) + bool const bIsAOO4( + GetImport().getGeneratorVersion() >= SvXMLImport::AOO_40x + && GetImport().getGeneratorVersion() <= SvXMLImport::AOO_4x); + + // fdo#75872: backward compatibility for pool defaults change + if (GetImport().isGeneratorVersionOlderThan( + SvXMLImport::AOO_40x, SvXMLImport::LO_42x) + // argh... it turns out that LO has also changed defaults for these + // since LO 4.0, and so even the _new_ AOO 4.0+ default needs + // special handling since AOO still does _not_ write it into the file + || bIsAOO4) + { + rtl::Reference const pImpPrMap( + GetStyles()->GetImportPropertyMapper(GetFamily()) + ->getPropertySetMapper()); + sal_Int32 const nStrokeIndex( + pImpPrMap->GetEntryIndex(XML_NAMESPACE_SVG, u"stroke-color", 0)); + if (std::none_of(GetProperties().begin(), GetProperties().end(), + XMLPropertyByIndex(nStrokeIndex))) + { + Color const nStroke( + bIsAOO4 ? Color(128, 128, 128) : COL_BLACK); + xDefaults->setPropertyValue("LineColor", Any(nStroke)); + } + Color const nFillColor( bIsAOO4 + ? Color(0xCF, 0xE7, 0xF5) : Color(153, 204, 255)); + sal_Int32 const nFillIndex( + pImpPrMap->GetEntryIndex(XML_NAMESPACE_DRAW, u"fill-color", 0)); + if (std::none_of(GetProperties().begin(), GetProperties().end(), + XMLPropertyByIndex(nFillIndex))) + { + xDefaults->setPropertyValue("FillColor", Any(nFillColor)); + } + if (xInfo->hasPropertyByName("FillColor2")) + { + sal_Int32 const nFill2Index(pImpPrMap->GetEntryIndex( + XML_NAMESPACE_DRAW, u"secondary-fill-color", 0)); + if (std::none_of(GetProperties().begin(), GetProperties().end(), + XMLPropertyByIndex(nFill2Index))) + { + xDefaults->setPropertyValue("FillColor2", Any(sal_Int32(nFillColor))); + } + } + } + + FillPropertySet( xDefaults ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLImageMapContext.cxx b/xmloff/source/draw/XMLImageMapContext.cxx new file mode 100644 index 000000000..1b9c295d0 --- /dev/null +++ b/xmloff/source/draw/XMLImageMapContext.cxx @@ -0,0 +1,542 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XPropertySetInfo; +using ::com::sun::star::container::XIndexContainer; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::uno::Any; +using ::com::sun::star::document::XEventsSupplier; + +namespace { + +class XMLImageMapObjectContext : public SvXMLImportContext +{ + +protected: + + Reference xImageMap; /// the image map + Reference xMapEntry; /// one map-entry (one area) + + OUString sUrl; + OUString sTargt; + OUStringBuffer sDescriptionBuffer; + OUStringBuffer sTitleBuffer; + OUString sNam; + bool bIsActive; + + bool bValid; + +public: + + XMLImageMapObjectContext( + SvXMLImport& rImport, + css::uno::Reference const & xMap, + const char* pServiceName); + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &); + + virtual void Prepare( + css::uno::Reference & rPropertySet); +}; + +} + +XMLImageMapObjectContext::XMLImageMapObjectContext( + SvXMLImport& rImport, + Reference const & xMap, + const char* pServiceName) : + SvXMLImportContext(rImport), + xImageMap(xMap), + bIsActive(true), + bValid(false) +{ + DBG_ASSERT(nullptr != pServiceName, + "Please supply the image map object service name"); + + Reference xFactory(GetImport().GetModel(),UNO_QUERY); + if( !xFactory.is() ) + return; + + Reference xIfc = xFactory->createInstance( + OUString::createFromAscii(pServiceName)); + DBG_ASSERT(xIfc.is(), "can't create image map object!"); + if( xIfc.is() ) + { + Reference xPropertySet( xIfc, UNO_QUERY ); + + xMapEntry = xPropertySet; + } + // else: can't create service -> ignore + // else: can't even get factory -> ignore +} + +void XMLImageMapObjectContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + ProcessAttribute(aIter); +} + +void XMLImageMapObjectContext::endFastElement(sal_Int32 ) +{ + // only create and insert image map object if validity flag is set + // (and we actually have an image map) + if ( bValid && xImageMap.is() && xMapEntry.is() ) + { + // set values + Prepare( xMapEntry ); + + // insert into image map + xImageMap->insertByIndex( xImageMap->getCount(), Any(xMapEntry) ); + } + // else: not valid -> don't create and insert +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImageMapObjectContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + switch (nElement) + { + case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS): + { + Reference xEvents( xMapEntry, UNO_QUERY ); + return new XMLEventsImportContext( + GetImport(), xEvents); + } + case XML_ELEMENT(SVG, XML_TITLE): + case XML_ELEMENT(SVG_COMPAT, XML_TITLE): + return new XMLStringBufferImportContext( + GetImport(), sTitleBuffer); + case XML_ELEMENT(SVG, XML_DESC): + case XML_ELEMENT(SVG_COMPAT, XML_DESC): + return new XMLStringBufferImportContext( + GetImport(), sDescriptionBuffer); + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLImageMapObjectContext::ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + sUrl = GetImport().GetAbsoluteReference(aIter.toString()); + break; + + case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME): + sTargt = aIter.toString(); + break; + + case XML_ELEMENT(DRAW, XML_NOHREF): + bIsActive = ! IsXMLToken(aIter, XML_NOHREF); + break; + + case XML_ELEMENT(OFFICE, XML_NAME): + sNam = aIter.toString(); + break; + default: + // do nothing + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } +} + +void XMLImageMapObjectContext::Prepare( + Reference & rPropertySet) +{ + rPropertySet->setPropertyValue( "URL", Any( sUrl ) ); + rPropertySet->setPropertyValue( "Title", Any( sTitleBuffer.makeStringAndClear() ) ); + rPropertySet->setPropertyValue( "Description", Any( sDescriptionBuffer.makeStringAndClear() ) ); + rPropertySet->setPropertyValue( "Target", Any( sTargt ) ); + rPropertySet->setPropertyValue( "IsActive", Any( bIsActive ) ); + rPropertySet->setPropertyValue( "Name", Any( sNam ) ); +} + +namespace { + +class XMLImageMapRectangleContext : public XMLImageMapObjectContext +{ + awt::Rectangle aRectangle; + + bool bXOK; + bool bYOK; + bool bWidthOK; + bool bHeightOK; + +public: + + XMLImageMapRectangleContext( + SvXMLImport& rImport, + css::uno::Reference const & xMap); + +protected: + virtual void ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter &) override; + + virtual void Prepare( + css::uno::Reference & rPropertySet) override; +}; + +} + +XMLImageMapRectangleContext::XMLImageMapRectangleContext( + SvXMLImport& rImport, + Reference const & xMap) : + XMLImageMapObjectContext(rImport, xMap, + "com.sun.star.image.ImageMapRectangleObject"), + bXOK(false), + bYOK(false), + bWidthOK(false), + bHeightOK(false) +{ +} + +void XMLImageMapRectangleContext::ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + sal_Int32 nTmp; + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aRectangle.X = nTmp; + bXOK = true; + } + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aRectangle.Y = nTmp; + bYOK = true; + } + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aRectangle.Width = nTmp; + bWidthOK = true; + } + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aRectangle.Height = nTmp; + bHeightOK = true; + } + break; + default: + XMLImageMapObjectContext::ProcessAttribute(aIter); + } + + bValid = bHeightOK && bXOK && bYOK && bWidthOK; +} + +void XMLImageMapRectangleContext::Prepare( + Reference & rPropertySet) +{ + rPropertySet->setPropertyValue( "Boundary", uno::Any(aRectangle) ); + + // common properties handled by super class + XMLImageMapObjectContext::Prepare(rPropertySet); +} + +namespace { + +class XMLImageMapPolygonContext : public XMLImageMapObjectContext +{ + OUString sViewBoxString; + OUString sPointsString; + + bool bViewBoxOK; + bool bPointsOK; + +public: + + XMLImageMapPolygonContext( + SvXMLImport& rImport, + css::uno::Reference const & xMap); + +protected: + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter &) override; + + virtual void Prepare( + css::uno::Reference & rPropertySet) override; +}; + +} + +XMLImageMapPolygonContext::XMLImageMapPolygonContext( + SvXMLImport& rImport, + Reference const & xMap) : + XMLImageMapObjectContext(rImport, xMap, + "com.sun.star.image.ImageMapPolygonObject"), + bViewBoxOK(false), + bPointsOK(false) +{ +} + +void XMLImageMapPolygonContext::ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_POINTS): + sPointsString = aIter.toString(); + bPointsOK = true; + break; + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + sViewBoxString = aIter.toString(); + bViewBoxOK = true; + break; + default: + XMLImageMapObjectContext::ProcessAttribute(aIter); + break; + } + + bValid = bViewBoxOK && bPointsOK; +} + +void XMLImageMapPolygonContext::Prepare(Reference & rPropertySet) +{ + // process view box + SdXMLImExViewBox aViewBox(sViewBoxString, GetImport().GetMM100UnitConverter()); + + // get polygon sequence + basegfx::B2DPolygon aPolygon; + + if(basegfx::utils::importFromSvgPoints(aPolygon, sPointsString)) + { + if(aPolygon.count()) + { + css::drawing::PointSequence aPointSequence; + basegfx::utils::B2DPolygonToUnoPointSequence(aPolygon, aPointSequence); + rPropertySet->setPropertyValue("Polygon", Any(aPointSequence)); + } + } + + // parent properties + XMLImageMapObjectContext::Prepare(rPropertySet); +} + +namespace { + +class XMLImageMapCircleContext : public XMLImageMapObjectContext +{ + awt::Point aCenter; + sal_Int32 nRadius; + + bool bXOK; + bool bYOK; + bool bRadiusOK; + +public: + + XMLImageMapCircleContext( + SvXMLImport& rImport, + css::uno::Reference const & xMap); + +protected: + virtual void ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter &) override; + + virtual void Prepare( + css::uno::Reference & rPropertySet) override; +}; + +} + +XMLImageMapCircleContext::XMLImageMapCircleContext( + SvXMLImport& rImport, + Reference const & xMap) + : XMLImageMapObjectContext(rImport, xMap, + "com.sun.star.image.ImageMapCircleObject") + , nRadius(0) + , bXOK(false) + , bYOK(false) + , bRadiusOK(false) +{ +} + +void XMLImageMapCircleContext::ProcessAttribute( + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + sal_Int32 nTmp; + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_CX): + case XML_ELEMENT(SVG_COMPAT, XML_CX): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aCenter.X = nTmp; + bXOK = true; + } + break; + case XML_ELEMENT(SVG, XML_CY): + case XML_ELEMENT(SVG_COMPAT, XML_CY): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + aCenter.Y = nTmp; + bYOK = true; + } + break; + case XML_ELEMENT(SVG, XML_R): + case XML_ELEMENT(SVG_COMPAT, XML_R): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore(nTmp, + aIter.toView())) + { + nRadius = nTmp; + bRadiusOK = true; + } + break; + default: + XMLImageMapObjectContext::ProcessAttribute(aIter); + } + + bValid = bRadiusOK && bXOK && bYOK; +} + +void XMLImageMapCircleContext::Prepare( + Reference & rPropertySet) +{ + // center (x,y) + rPropertySet->setPropertyValue( "Center", uno::Any(aCenter) ); + // radius + rPropertySet->setPropertyValue( "Radius", uno::Any(nRadius) ); + + // common properties handled by super class + XMLImageMapObjectContext::Prepare(rPropertySet); +} + + +constexpr OUStringLiteral gsImageMap(u"ImageMap"); + +XMLImageMapContext::XMLImageMapContext( + SvXMLImport& rImport, + Reference const & rPropertySet) : + SvXMLImportContext(rImport), + xPropertySet(rPropertySet) +{ + try + { + Reference < XPropertySetInfo > xInfo = + xPropertySet->getPropertySetInfo(); + if( xInfo.is() && xInfo->hasPropertyByName( gsImageMap ) ) + xPropertySet->getPropertyValue(gsImageMap) >>= xImageMap; + } + catch(const css::uno::Exception& e) + { + rImport.SetError( XMLERROR_FLAG_WARNING | XMLERROR_API, {}, e.Message, nullptr ); + } +} + +XMLImageMapContext::~XMLImageMapContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImageMapContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + switch (nElement) + { + case XML_ELEMENT(DRAW, XML_AREA_RECTANGLE): + return new XMLImageMapRectangleContext( + GetImport(), xImageMap); + case XML_ELEMENT(DRAW, XML_AREA_POLYGON): + return new XMLImageMapPolygonContext( + GetImport(), xImageMap); + case XML_ELEMENT(DRAW, XML_AREA_CIRCLE): + return new XMLImageMapCircleContext( + GetImport(), xImageMap); + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return nullptr; +} + +void XMLImageMapContext::endFastElement(sal_Int32 ) +{ + Reference < XPropertySetInfo > xInfo = + xPropertySet->getPropertySetInfo(); + if( xInfo.is() && xInfo->hasPropertyByName( gsImageMap ) ) + xPropertySet->setPropertyValue(gsImageMap, uno::Any( xImageMap ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLImageMapExport.cxx b/xmloff/source/draw/XMLImageMapExport.cxx new file mode 100644 index 000000000..918d13ad0 --- /dev/null +++ b/xmloff/source/draw/XMLImageMapExport.cxx @@ -0,0 +1,339 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::container::XIndexContainer; +using ::com::sun::star::document::XEventsSupplier; +using ::com::sun::star::lang::XServiceInfo; +using ::com::sun::star::drawing::PointSequence; + +constexpr OUStringLiteral gsBoundary(u"Boundary"); +constexpr OUStringLiteral gsCenter(u"Center"); +constexpr OUStringLiteral gsDescription(u"Description"); +constexpr OUStringLiteral gsImageMap(u"ImageMap"); +constexpr OUStringLiteral gsIsActive(u"IsActive"); +constexpr OUStringLiteral gsName(u"Name"); +constexpr OUStringLiteral gsPolygon(u"Polygon"); +constexpr OUStringLiteral gsRadius(u"Radius"); +constexpr OUStringLiteral gsTarget(u"Target"); +constexpr OUStringLiteral gsURL(u"URL"); +constexpr OUStringLiteral gsTitle(u"Title"); + +XMLImageMapExport::XMLImageMapExport(SvXMLExport& rExp) : + mrExport(rExp) +{ +} + +void XMLImageMapExport::Export( + const Reference & rPropertySet) +{ + if (rPropertySet->getPropertySetInfo()->hasPropertyByName(gsImageMap)) + { + Any aAny = rPropertySet->getPropertyValue(gsImageMap); + Reference aContainer; + aAny >>= aContainer; + + Export(aContainer); + } + // else: no ImageMap property -> nothing to do +} + +void XMLImageMapExport::Export( + const Reference & rContainer) +{ + if (!rContainer.is()) + return; + + if (!rContainer->hasElements()) + return; + + // image map container element + SvXMLElementExport aImageMapElement( + mrExport, XML_NAMESPACE_DRAW, XML_IMAGE_MAP, + true/*bWhiteSpace*/, true/*bWhiteSpace*/); + + // iterate over image map elements and call ExportMapEntry(...) + // for each + sal_Int32 nLength = rContainer->getCount(); + for(sal_Int32 i = 0; i < nLength; i++) + { + Any aAny = rContainer->getByIndex(i); + Reference rElement; + aAny >>= rElement; + + DBG_ASSERT(rElement.is(), "Image map element is empty!"); + if (rElement.is()) + { + ExportMapEntry(rElement); + } + } + // else: container is empty -> nothing to do + // else: no container -> nothing to do +} + + +void XMLImageMapExport::ExportMapEntry( + const Reference & rPropertySet) +{ + Reference xServiceInfo(rPropertySet, UNO_QUERY); + if (!xServiceInfo.is()) + return; + + enum XMLTokenEnum eType = XML_TOKEN_INVALID; + + // distinguish map entries by their service name + const Sequence sServiceNames = + xServiceInfo->getSupportedServiceNames(); + for( const OUString& rName : sServiceNames ) + { + if ( rName == "com.sun.star.image.ImageMapRectangleObject" ) + { + eType = XML_AREA_RECTANGLE; + break; + } + else if ( rName == "com.sun.star.image.ImageMapCircleObject" ) + { + eType = XML_AREA_CIRCLE; + break; + } + else if ( rName == "com.sun.star.image.ImageMapPolygonObject" ) + { + eType = XML_AREA_POLYGON; + break; + } + } + + // return from method if no proper service is found! + DBG_ASSERT(XML_TOKEN_INVALID != eType, + "Image map element doesn't support appropriate service!"); + if (XML_TOKEN_INVALID == eType) + return; + + // now: handle ImageMapObject properties (those for all types) + + // XLINK (URL property) + Any aAny = rPropertySet->getPropertyValue(gsURL); + OUString sHref; + aAny >>= sHref; + if (!sHref.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, mrExport.GetRelativeReference(sHref)); + } + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + + // Target property (and xlink:show) + aAny = rPropertySet->getPropertyValue(gsTarget); + OUString sTargt; + aAny >>= sTargt; + if (!sTargt.isEmpty()) + { + mrExport.AddAttribute( + XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, sTargt); + + mrExport.AddAttribute( + XML_NAMESPACE_XLINK, XML_SHOW, + sTargt == "_blank" ? XML_NEW : XML_REPLACE ); + } + + // name + aAny = rPropertySet->getPropertyValue(gsName); + OUString sItemName; + aAny >>= sItemName; + if (!sItemName.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, sItemName); + } + + // is-active + aAny = rPropertySet->getPropertyValue(gsIsActive); + if (! *o3tl::doAccess(aAny)) + { + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NOHREF, XML_NOHREF); + } + + // call specific rectangle/circle/... method + // also prepare element name + switch (eType) + { + case XML_AREA_RECTANGLE: + ExportRectangle(rPropertySet); + break; + case XML_AREA_CIRCLE: + ExportCircle(rPropertySet); + break; + case XML_AREA_POLYGON: + ExportPolygon(rPropertySet); + break; + default: + break; + } + + // write element + DBG_ASSERT(XML_TOKEN_INVALID != eType, + "No name?! How did this happen?"); + SvXMLElementExport aAreaElement(mrExport, XML_NAMESPACE_DRAW, eType, + true/*bWhiteSpace*/, true/*bWhiteSpace*/); + + // title property (as element) + OUString sTitle; + rPropertySet->getPropertyValue(gsTitle) >>= sTitle; + if(!sTitle.isEmpty()) + { + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true/*bWhiteSpace*/, false); + mrExport.Characters(sTitle); + } + + // description property (as element) + OUString sDescription; + rPropertySet->getPropertyValue(gsDescription) >>= sDescription; + if (!sDescription.isEmpty()) + { + SvXMLElementExport aDesc(mrExport, XML_NAMESPACE_SVG, XML_DESC, true/*bWhiteSpace*/, false); + mrExport.Characters(sDescription); + } + + // export events attached to this + Reference xSupplier(rPropertySet, UNO_QUERY); + mrExport.GetEventExport().Export(xSupplier); + + // else: no service info -> can't determine type -> ignore entry +} + +void XMLImageMapExport::ExportRectangle( + const Reference & rPropertySet) +{ + // get boundary rectangle + Any aAny = rPropertySet->getPropertyValue(gsBoundary); + awt::Rectangle aRectangle; + aAny >>= aRectangle; + + // parameters svg:x, svg:y, svg:width, svg:height + OUStringBuffer aBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aRectangle.X); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, + aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aRectangle.Y); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, + aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, + aRectangle.Width); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, + aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, + aRectangle.Height); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, + aBuffer.makeStringAndClear() ); +} + +void XMLImageMapExport::ExportCircle( + const Reference & rPropertySet) +{ + // get boundary rectangle + Any aAny = rPropertySet->getPropertyValue(gsCenter); + awt::Point aCenter; + aAny >>= aCenter; + + // parameters svg:cx, svg:cy + OUStringBuffer aBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aCenter.X); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_CX, + aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, aCenter.Y); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_CY, + aBuffer.makeStringAndClear() ); + + // radius + aAny = rPropertySet->getPropertyValue(gsRadius); + sal_Int32 nRadius = 0; + aAny >>= nRadius; + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, nRadius); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_R, + aBuffer.makeStringAndClear() ); +} + +void XMLImageMapExport::ExportPolygon(const Reference & rPropertySet) +{ + // polygons get exported as bounding box, viewbox, and coordinate + // pair sequence. The bounding box is always the entire image. + + // get polygon point sequence + Any aAny = rPropertySet->getPropertyValue(gsPolygon); + PointSequence aPoly; + aAny >>= aPoly; + + const basegfx::B2DPolygon aPolygon( + basegfx::utils::UnoPointSequenceToB2DPolygon( + aPoly)); + const basegfx::B2DRange aPolygonRange(aPolygon.getB2DRange()); + + // parameters svg:x, svg:y, svg:width, svg:height + OUStringBuffer aBuffer; + + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, 0); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_X, aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, 0); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_Y, aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, basegfx::fround(aPolygonRange.getWidth())); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, aBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(aBuffer, basegfx::fround(aPolygonRange.getHeight())); + mrExport.AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, aBuffer.makeStringAndClear() ); + + // svg:viewbox + SdXMLImExViewBox aViewBox(0.0, 0.0, aPolygonRange.getWidth(), aPolygonRange.getHeight()); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + + // export point sequence + const OUString aPointString( + basegfx::utils::exportToSvgPoints( + aPolygon)); + + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLNumberStyles.cxx b/xmloff/source/draw/XMLNumberStyles.cxx new file mode 100644 index 000000000..48bf04c82 --- /dev/null +++ b/xmloff/source/draw/XMLNumberStyles.cxx @@ -0,0 +1,711 @@ +/* -*- 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 "XMLNumberStylesExport.hxx" +#include +#include +#include +#include +#include + +#include +#include + +#include "sdxmlexp_impl.hxx" +#include "sdxmlimp_impl.hxx" + +using namespace ::xmloff::token; + +namespace { + +struct SdXMLDataStyleNumber +{ + enum XMLTokenEnum meNumberStyle; + bool mbLong; + bool mbTextual; + bool mbDecimal02; + const char* mpText; +}; + +} + +SdXMLDataStyleNumber const aSdXMLDataStyleNumbers[] = +{ + { XML_DAY, false, false, false, nullptr }, + { XML_DAY, true, false, false, nullptr }, + { XML_MONTH, true, false, false, nullptr }, + { XML_MONTH, false, true, false, nullptr }, + { XML_MONTH, true, true, false, nullptr }, + { XML_YEAR, false, false, false, nullptr }, + { XML_YEAR, true, false, false, nullptr }, + { XML_DAY_OF_WEEK, false, false, false, nullptr }, + { XML_DAY_OF_WEEK, true, false, false, nullptr }, + { XML_TEXT, false, false, false, "." }, + { XML_TEXT, false, false, false, " " }, + { XML_TEXT, false, false, false, ", " }, + { XML_TEXT, false, false, false, ". " }, + { XML_HOURS, false, false, false, nullptr }, + { XML_MINUTES, false, false, false, nullptr }, + { XML_TEXT, false, false, false, ":" }, + { XML_AM_PM, false, false, false, nullptr }, + { XML_SECONDS, false, false, false, nullptr }, + { XML_SECONDS, false, false, true, nullptr }, + { XML_TOKEN_INVALID, false, false, false, nullptr } +}; + +// date +enum class DataStyleNumber : sal_uInt8 +{ + NONE = 0, + Day = 1, // + DayLong = 2, // + MonthLong = 3, // + MonthText = 4, // + MonthLongText = 5, // + Year = 6, // + YearLong = 7, // + DayOfWeek = 8, // + DayOfWeekLong = 9, // + TextPoint = 10, // . + TextSpace = 11, // + TextCommaSpace = 12, // , + TextPointSpace = 13, // . + Hours = 14, // + Minutes = 15, // + TextColon = 16, // : + AmPm = 17, // + Seconds = 18, // + Seconds_02 = 19, // +}; + +struct SdXMLFixedDataStyle +{ + const char* mpName; + bool mbAutomatic; + bool mbDateStyle; + DataStyleNumber mpFormat[8]; +}; + +const SdXMLFixedDataStyle aSdXML_Standard_Short = +{ + "D1", true, true, + { + DataStyleNumber::DayLong, + DataStyleNumber::TextPoint, + DataStyleNumber::MonthLong, + DataStyleNumber::TextPoint, + DataStyleNumber::YearLong, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_Standard_Long = +{ + "D2", true, true, + { + DataStyleNumber::DayOfWeekLong, + DataStyleNumber::TextCommaSpace, + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthLongText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_1 = +{ + "D3", false, true, + { + DataStyleNumber::DayLong, + DataStyleNumber::TextPoint, + DataStyleNumber::MonthLong, + DataStyleNumber::TextPoint, + DataStyleNumber::Year, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_2 = +{ + "D4", false, true, + { + DataStyleNumber::DayLong, + DataStyleNumber::TextPoint, + DataStyleNumber::MonthLong, + DataStyleNumber::TextPoint, + DataStyleNumber::YearLong, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_3 = +{ + "D5", false, true, + { + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_4 = +{ + "D6", false, true, + { + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthLongText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_5 = +{ + "D7", false, true, + { + DataStyleNumber::DayOfWeek, + DataStyleNumber::TextCommaSpace, + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthLongText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_DateStyle_6 = +{ + "D8", false, true, + { + DataStyleNumber::DayOfWeekLong, + DataStyleNumber::TextCommaSpace, + DataStyleNumber::Day, + DataStyleNumber::TextPointSpace, + DataStyleNumber::MonthLongText, + DataStyleNumber::TextSpace, + DataStyleNumber::YearLong, + DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_1 = +{ "T1", true, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds, + DataStyleNumber::AmPm, + DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_2 = +{ "T2", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_3 = +{ "T3", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_4 = +{ "T4", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds_02, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_5 = +{ "T5", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::AmPm, + DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_6 = +{ "T6", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds, + DataStyleNumber::AmPm, + DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle aSdXML_TimeStyle_7 = +{ "T7", false, false, + { + DataStyleNumber::Hours, + DataStyleNumber::TextColon, + DataStyleNumber::Minutes, + DataStyleNumber::TextColon, + DataStyleNumber::Seconds_02, + DataStyleNumber::AmPm, + DataStyleNumber::NONE, DataStyleNumber::NONE + } +}; + +const SdXMLFixedDataStyle* const aSdXMLFixedDateFormats[SdXMLDateFormatCount] = +{ + &aSdXML_Standard_Short, + &aSdXML_Standard_Long, + &aSdXML_DateStyle_1, + &aSdXML_DateStyle_2, + &aSdXML_DateStyle_3, + &aSdXML_DateStyle_4, + &aSdXML_DateStyle_5, + &aSdXML_DateStyle_6, +}; + +const SdXMLFixedDataStyle* const aSdXMLFixedTimeFormats[SdXMLTimeFormatCount] = +{ + &aSdXML_TimeStyle_1, + &aSdXML_TimeStyle_2, + &aSdXML_TimeStyle_3, + &aSdXML_TimeStyle_4, + &aSdXML_TimeStyle_5, + &aSdXML_TimeStyle_6, + &aSdXML_TimeStyle_7 +}; + +// export + +static void SdXMLExportDataStyleNumber( SdXMLExport& rExport, SdXMLDataStyleNumber const & rElement ) +{ + if( rElement.mbDecimal02 ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, XML_2 ); + } + + if( rElement.mbLong ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_STYLE, XML_LONG ); + } + + if( rElement.mbTextual ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TRUE ); + } + + SvXMLElementExport aNumberStyle( rExport, XML_NAMESPACE_NUMBER, rElement.meNumberStyle, true, false ); + if( rElement.mpText ) + { + OUString sAttrValue( OUString::createFromAscii( rElement.mpText ) ); + rExport.GetDocHandler()->characters( sAttrValue ); + } +} + +static void SdXMLExportStyle( SdXMLExport& rExport, const SdXMLFixedDataStyle* pStyle, const SdXMLFixedDataStyle* pStyle2 = nullptr ) +{ + // name + OUString sAttrValue = OUString::createFromAscii( pStyle->mpName ); + if( pStyle2 ) + sAttrValue += OUString::createFromAscii( pStyle2->mpName ); + + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, sAttrValue ); + + if( pStyle->mbAutomatic ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER, XML_TRUE ); + } + + SvXMLElementExport aElement( rExport, XML_NAMESPACE_NUMBER, pStyle->mbDateStyle ? XML_DATE_STYLE : XML_TIME_STYLE, true, true ); + + do + { + + const DataStyleNumber* pElements = &pStyle->mpFormat[0]; + + while( *pElements != DataStyleNumber::NONE ) + { + SdXMLDataStyleNumber const & rElement = aSdXMLDataStyleNumbers[ static_cast(*pElements++) - 1 ]; + SdXMLExportDataStyleNumber( rExport, rElement ); + } + + if( pStyle2 ) + { + SdXMLDataStyleNumber const & rElement = aSdXMLDataStyleNumbers[ static_cast(DataStyleNumber::TextSpace) - 1 ]; + SdXMLExportDataStyleNumber( rExport, rElement ); + } + + pStyle = pStyle2; + pStyle2 = nullptr; + } + while( pStyle ); +} + +void SdXMLNumberStylesExporter::exportTimeStyle( SdXMLExport& rExport, sal_Int32 nStyle ) +{ + SAL_WARN_IF( (nStyle < 0) || (nStyle >= SdXMLTimeFormatCount), "xmloff", "Unknown time style!" ); + if( (nStyle >= 0) && (nStyle < SdXMLTimeFormatCount) ) + SdXMLExportStyle( rExport, aSdXMLFixedTimeFormats[ nStyle ] ); +} + +void SdXMLNumberStylesExporter::exportDateStyle( SdXMLExport& rExport, sal_Int32 nStyle ) +{ + if( nStyle > 0x0f ) + { + int nDateStyle = nStyle & 0x0f; + bool bHasDate = nDateStyle != 0; + + if( nDateStyle > 1 ) + nDateStyle -= 2; + + SAL_WARN_IF(nDateStyle >= SdXMLDateFormatCount, "xmloff", "unknown date style!"); + + int nTimeStyle = (nStyle >> 4) & 0x0f; + bool bHasTime = nTimeStyle != 0; + + if( nTimeStyle > 1 ) + nTimeStyle -= 2; + + SAL_WARN_IF(nTimeStyle >= SdXMLTimeFormatCount, "xmloff", "Unknown time style!"); + + if ((nDateStyle < SdXMLDateFormatCount) && (nTimeStyle < SdXMLTimeFormatCount)) + { + if( bHasDate ) + { + if( bHasTime ) + { + SdXMLExportStyle( rExport, aSdXMLFixedDateFormats[ nDateStyle ], aSdXMLFixedTimeFormats[ nTimeStyle ] ); + } + else + { + SdXMLExportStyle( rExport, aSdXMLFixedDateFormats[ nDateStyle ] ); + } + } + else if( bHasTime ) + { + SdXMLExportStyle( rExport, aSdXMLFixedTimeFormats[ nTimeStyle ] ); + } + } + } + else + { + SAL_WARN_IF( (nStyle < 0) || (nStyle >= SdXMLDateFormatCount), "xmloff", "unknown date style!" ); + if( (nStyle >= 0) && (nStyle < SdXMLDateFormatCount) ) + SdXMLExportStyle( rExport, aSdXMLFixedDateFormats[ nStyle ] ); + } +} + +OUString SdXMLNumberStylesExporter::getTimeStyleName(const sal_Int32 nTimeFormat ) +{ + sal_Int32 nFormat = nTimeFormat; + if( nFormat > 1 ) + nFormat -= 2; + + if( (nFormat >= 0) && (nFormat < SdXMLTimeFormatCount) ) + { + return OUString::createFromAscii(aSdXMLFixedTimeFormats[nFormat]->mpName ); + } + else + { + return OUString(); + } +} + +OUString SdXMLNumberStylesExporter::getDateStyleName(const sal_Int32 nDateFormat ) +{ + sal_Int32 nFormat = nDateFormat; + + if( nFormat > 0x0f ) + { + OUString aStr; + if( nFormat & 0x0f ) + aStr = getDateStyleName( nFormat & 0x0f ); + aStr += getTimeStyleName( (nFormat >> 4) & 0x0f ); + return aStr; + } + + if( nFormat > 1 ) + nFormat -= 2; + + if( (nFormat >= 0) && (nFormat < SdXMLDateFormatCount) ) + { + return OUString::createFromAscii(aSdXMLFixedDateFormats[nFormat]->mpName ); + } + else + { + return OUString(); + } +} + +// import + +class SdXMLNumberFormatMemberImportContext : public SvXMLImportContext +{ +private: + SdXMLNumberFormatImportContext* mpParent; + + OUString maNumberStyle; + bool mbLong; + bool mbTextual; + bool mbDecimal02; + OUString maText; + SvXMLImportContextRef mxSlaveContext; + +public: + + SdXMLNumberFormatMemberImportContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + SdXMLNumberFormatImportContext* pParent, + const SvXMLImportContextRef& rSlaveContext ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + + +SdXMLNumberFormatMemberImportContext::SdXMLNumberFormatMemberImportContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + SdXMLNumberFormatImportContext* pParent, + const SvXMLImportContextRef& rSlaveContext ) +: SvXMLImportContext(rImport), + mpParent( pParent ), + maNumberStyle( SvXMLImport::getNameFromToken(nElement) ), + mxSlaveContext( rSlaveContext ) +{ + mbLong = false; + mbTextual = false; + mbDecimal02 = false; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(NUMBER, XML_DECIMAL_PLACES): + mbDecimal02 = IsXMLToken( aIter, XML_2 ); + break; + case XML_ELEMENT(NUMBER, XML_STYLE): + mbLong = IsXMLToken( aIter, XML_LONG ); + break; + case XML_ELEMENT(NUMBER, XML_TEXTUAL): + mbTextual = IsXMLToken( aIter, XML_TRUE ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLNumberFormatMemberImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return mxSlaveContext->createFastChildContext( nElement, xAttrList ); +} + +void SdXMLNumberFormatMemberImportContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + mxSlaveContext->startFastElement( nElement, xAttrList ); +} + +void SdXMLNumberFormatMemberImportContext::endFastElement(sal_Int32 nElement) +{ + mxSlaveContext->endFastElement(nElement); + + if( mpParent ) + mpParent->add( maNumberStyle, mbLong, mbTextual, mbDecimal02, maText ); +} + +void SdXMLNumberFormatMemberImportContext::characters( const OUString& rChars ) +{ + mxSlaveContext->characters( rChars ); + maText += rChars; +} + + +SdXMLNumberFormatImportContext::SdXMLNumberFormatImportContext( SdXMLImport& rImport, sal_Int32 nElement, SvXMLNumImpData* pNewData, SvXMLStylesTokens nNewType, const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, SvXMLStylesContext& rStyles) +: SvXMLNumFormatContext(rImport, nElement, pNewData, nNewType, xAttrList, rStyles), + mbAutomatic( false ), + mnElements{}, + mnIndex(0), + mnKey( -1 ) +{ + mbTimeStyle = (nElement & TOKEN_MASK) == XML_TIME_STYLE; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(NUMBER, XML_AUTOMATIC_ORDER) ) + mbAutomatic = IsXMLToken( aIter, XML_TRUE ); + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +SdXMLNumberFormatImportContext::~SdXMLNumberFormatImportContext() +{ +} + +void SdXMLNumberFormatImportContext::add( std::u16string_view rNumberStyle, bool bLong, bool bTextual, bool bDecimal02, std::u16string_view rText ) +{ + if (mnIndex == 16) + return; + + const SdXMLDataStyleNumber* pStyleMember = aSdXMLDataStyleNumbers; + for( sal_uInt8 nIndex = 0; pStyleMember->meNumberStyle != XML_TOKEN_INVALID; nIndex++, pStyleMember++ ) + { + if( IsXMLToken(rNumberStyle, pStyleMember->meNumberStyle) && + (pStyleMember->mbLong == bLong) && + (pStyleMember->mbTextual == bTextual) && + (pStyleMember->mbDecimal02 == bDecimal02) && + ( ( (pStyleMember->mpText == nullptr) && (rText.empty()) ) || + ( pStyleMember->mpText && (o3tl::equalsAscii( rText, pStyleMember->mpText ) ) ) ) ) + { + mnElements[mnIndex++] = static_cast(nIndex + 1); + return; + } + } +} + +bool SdXMLNumberFormatImportContext::compareStyle( const SdXMLFixedDataStyle* pStyle, sal_Int16& nIndex ) const +{ + if( (pStyle->mbAutomatic != mbAutomatic) && (nIndex == 0)) + return false; + + sal_Int16 nCompareIndex; + for( nCompareIndex = 0; nCompareIndex < 8; nIndex++, nCompareIndex++ ) + { + if( pStyle->mpFormat[nCompareIndex] != mnElements[nIndex] ) + return false; + } + + return true; +} + +void SdXMLNumberFormatImportContext::endFastElement(sal_Int32 ) +{ + for( ; mnIndex < 16; mnIndex++ ) + { + mnElements[mnIndex] = DataStyleNumber::NONE; + } + + if( mbTimeStyle ) + { + // compare import with all time styles + for( sal_Int16 nFormat = 0; nFormat < SdXMLTimeFormatCount; nFormat++ ) + { + sal_Int16 nIndex = 0; + if( compareStyle( aSdXMLFixedTimeFormats[nFormat], nIndex ) ) + { + mnKey = nFormat + 2; + break; + } + } + } + else + { + // compare import with all date styles + for( sal_Int16 nFormat = 0; nFormat < SdXMLDateFormatCount; nFormat++ ) + { + sal_Int16 nIndex = 0; + if( compareStyle( aSdXMLFixedDateFormats[nFormat], nIndex ) ) + { + mnKey = nFormat + 2; + break; + } + else if( mnElements[nIndex] == DataStyleNumber::TextSpace ) + { + // if it's a valid date ending with a space, see if a time style follows + for( sal_Int16 nTimeFormat = 0; nTimeFormat < SdXMLTimeFormatCount; nTimeFormat++ ) + { + sal_Int16 nIndex2 = nIndex + 1; + if( compareStyle( aSdXMLFixedTimeFormats[nTimeFormat], nIndex2 ) ) + { + mnKey = (nFormat + 2) | ((nTimeFormat + 2) << 4); + break; + } + } + } + } + + // no date style found? maybe it's an extended time style + if( mnKey == -1 ) + { + // compare import with all time styles + for( sal_Int16 nFormat = 0; nFormat < SdXMLTimeFormatCount; nFormat++ ) + { + sal_Int16 nIndex = 0; + if( compareStyle( aSdXMLFixedTimeFormats[nFormat], nIndex ) ) + { + mnKey = (nFormat + 2) << 4; + break; + } + } + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLNumberFormatImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new SdXMLNumberFormatMemberImportContext( GetImport(), nElement, xAttrList, + this, static_cast(SvXMLNumFormatContext::createFastChildContext( nElement, xAttrList ).get()) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLNumberStylesExport.hxx b/xmloff/source/draw/XMLNumberStylesExport.hxx new file mode 100644 index 000000000..8b4f39dc5 --- /dev/null +++ b/xmloff/source/draw/XMLNumberStylesExport.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/. + * + * 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 +#include + +class SdXMLExport; + +const sal_Int16 SdXMLDateFormatCount = 8; +const sal_Int16 SdXMLTimeFormatCount = 7; + +class SdXMLNumberStylesExporter +{ +public: + static void exportTimeStyle(SdXMLExport& rExport, sal_Int32 nStyle); + static void exportDateStyle(SdXMLExport& rExport, sal_Int32 nStyle); + + static OUString getTimeStyleName(const sal_Int32 nTimeFormat); + static OUString getDateStyleName(const sal_Int32 nDateFormat); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLReplacementImageContext.cxx b/xmloff/source/draw/XMLReplacementImageContext.cxx new file mode 100644 index 000000000..5321d5578 --- /dev/null +++ b/xmloff/source/draw/XMLReplacementImageContext.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/. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::com::sun::star::uno::Reference; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::beans; +using namespace css; +using namespace ::xmloff::token; + +XMLReplacementImageContext::XMLReplacementImageContext( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & rAttrList, + const Reference< XPropertySet > & rPropSet ) : + SvXMLImportContext( rImport ), + m_xPropSet( rPropSet ) +{ + m_sHRef = rAttrList->getOptionalValue(XML_ELEMENT(XLINK, XML_HREF)); +} + +XMLReplacementImageContext::~XMLReplacementImageContext() +{ +} + +void XMLReplacementImageContext::endFastElement(sal_Int32 ) +{ + OSL_ENSURE( !m_sHRef.isEmpty() || m_xBase64Stream.is(), + "neither URL nor base64 image data given" ); + uno::Reference xGraphic; + + try + { + if( !m_sHRef.isEmpty() ) + { + xGraphic = GetImport().loadGraphicByURL(m_sHRef); + } + else if( m_xBase64Stream.is() ) + { + xGraphic = GetImport().loadGraphicFromBase64(m_xBase64Stream); + m_xBase64Stream = nullptr; + } + } + catch (uno::Exception const &) + {} + + Reference < XPropertySetInfo > xPropSetInfo = m_xPropSet->getPropertySetInfo(); + + if (xGraphic.is() && xPropSetInfo->hasPropertyByName("Graphic")) + { + m_xPropSet->setPropertyValue("Graphic", uno::Any(xGraphic)); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLReplacementImageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) && + !m_xBase64Stream.is() ) + { + m_xBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( m_xBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), + m_xBase64Stream ); + } + + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLShapePropertySetContext.cxx b/xmloff/source/draw/XMLShapePropertySetContext.cxx new file mode 100644 index 000000000..c702bccf9 --- /dev/null +++ b/xmloff/source/draw/XMLShapePropertySetContext.cxx @@ -0,0 +1,91 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLShapePropertySetContext::XMLShapePropertySetContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + sal_uInt32 nFam, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ) : + SvXMLPropertySetContext( rImport, nElement, xAttrList, nFam, + rProps, rMap ), + mnBulletIndex(-1) +{ +} + +XMLShapePropertySetContext::~XMLShapePropertySetContext() +{ +} + +void XMLShapePropertySetContext::endFastElement(sal_Int32 ) +{ + Reference< container::XIndexReplace > xNumRule; + if( mxBulletStyle.is() ) + { + SvxXMLListStyleContext* pBulletStyle = static_cast(mxBulletStyle.get()); + xNumRule = SvxXMLListStyleContext::CreateNumRule( GetImport().GetModel() ); + if( xNumRule.is() ) + pBulletStyle->FillUnoNumRule(xNumRule); + } + + XMLPropertyState aPropState( mnBulletIndex, Any(xNumRule) ); + mrProperties.push_back( aPropState ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapePropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + switch( mxMapper->getPropertySetMapper()->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_NUMBERINGRULES: + mnBulletIndex = rProp.mnIndex; + mxBulletStyle = new SvxXMLListStyleContext( GetImport() ); + return mxBulletStyle; + case CTF_TABSTOP: + return new SvxXMLTabStopImportContext( GetImport(), nElement, + rProp, + rProperties ); + case CTF_TEXTCOLUMNS: + return new XMLTextColumnsContext(GetImport(), nElement, xAttrList, rProp, rProperties); + } + + return SvXMLPropertySetContext::createFastChildContext( nElement, + xAttrList, + rProperties, rProp ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/XMLShapeStyleContext.cxx b/xmloff/source/draw/XMLShapeStyleContext.cxx new file mode 100644 index 000000000..da4341731 --- /dev/null +++ b/xmloff/source/draw/XMLShapeStyleContext.cxx @@ -0,0 +1,323 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::drawing; +using namespace ::xmloff::token; + + +XMLShapeStyleContext::XMLShapeStyleContext( + SvXMLImport& rImport, + SvXMLStylesContext& rStyles, + XmlStyleFamily nFamily) +: XMLPropStyleContext(rImport, rStyles, nFamily ), + m_bIsNumRuleAlreadyConverted( false ) +{ +} + +XMLShapeStyleContext::~XMLShapeStyleContext() +{ +} + +void XMLShapeStyleContext::SetAttribute( sal_Int32 nElement, const OUString& rValue ) +{ + if (m_sControlDataStyleName.isEmpty() && (nElement & TOKEN_MASK) == XML_DATA_STYLE_NAME) + { + m_sControlDataStyleName = rValue; + } + else if( nElement == XML_ELEMENT(STYLE, XML_LIST_STYLE_NAME) ) + { + m_sListStyleName = rValue; + } + else + { + XMLPropStyleContext::SetAttribute( nElement, rValue ); + + if( nElement == XML_ELEMENT(STYLE, XML_NAME) || nElement == XML_ELEMENT(STYLE, XML_DISPLAY_NAME) ) + { + if( !GetName().isEmpty() && !GetDisplayName().isEmpty() && GetName() != GetDisplayName() ) + { + GetImport(). + AddStyleDisplayName( GetFamily(), GetName(), GetDisplayName() ); + } + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapeStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) || + IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + sal_uInt32 nFamily = 0; + if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_GRAPHIC_PROPERTIES ) + nFamily = XML_TYPE_PROP_GRAPHIC; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new XMLShapePropertySetContext( GetImport(), nElement, xAttrList, + nFamily, + GetProperties(), + xImpPrMap ); + } + } + + return XMLPropStyleContext::createFastChildContext( nElement, xAttrList ); +} + +void XMLShapeStyleContext::FillPropertySet( const Reference< beans::XPropertySet > & rPropSet ) +{ + if( !m_bIsNumRuleAlreadyConverted ) + { + m_bIsNumRuleAlreadyConverted = true; + + // for compatibility to beta files, search for CTF_SD_NUMBERINGRULES_NAME to + // import numbering rules from the style:properties element + const rtl::Reference< XMLPropertySetMapper >&rMapper = GetStyles()->GetImportPropertyMapper( GetFamily() )->getPropertySetMapper(); + + ::std::vector< XMLPropertyState > &rProperties = GetProperties(); + ::std::vector< XMLPropertyState >::iterator end( rProperties.end() ); + + // first, look for the old format, where we had a text:list-style-name + // attribute in the style:properties element + auto property = std::find_if(rProperties.begin(), end, [&rMapper](XMLPropertyState& rProp) { + // find properties with context + return (rProp.mnIndex != -1) && (rMapper->GetEntryContextId( rProp.mnIndex ) == CTF_SD_NUMBERINGRULES_NAME); }); + + // if we did not find an old list-style-name in the properties, and we need one + // because we got a style:list-style attribute in the style-style element + // we generate one + if( (property == end) && ( !m_sListStyleName.isEmpty() ) ) + { + sal_Int32 nIndex = rMapper->FindEntryIndex( CTF_SD_NUMBERINGRULES_NAME ); + SAL_WARN_IF( -1 == nIndex, "xmloff", "can't find numbering rules property entry, can't set numbering rule!" ); + + XMLPropertyState aNewState( nIndex ); + rProperties.push_back( aNewState ); + end = rProperties.end(); + property = end - 1; + } + + // so, if we have an old or a new list style name, we set its value to + // a numbering rule + if( property != end ) + { + if( m_sListStyleName.isEmpty() ) + { + property->maValue >>= m_sListStyleName; + } + + const SvxXMLListStyleContext *pListStyle = GetImport().GetTextImport()->FindAutoListStyle( m_sListStyleName ); + + SAL_WARN_IF( !pListStyle, "xmloff", "list-style not found for shape style" ); + if( pListStyle ) + { + uno::Reference< container::XIndexReplace > xNumRule( SvxXMLListStyleContext::CreateNumRule( GetImport().GetModel() ) ); + pListStyle->FillUnoNumRule(xNumRule); + property->maValue <<= xNumRule; + } + else + { + property->mnIndex = -1; + } + } + } + + struct ContextID_Index_Pair aContextIDs[] = + { + { CTF_DASHNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_LINESTARTNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_LINEENDNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + { CTF_SD_OLE_VIS_AREA_IMPORT_LEFT, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_SD_OLE_VIS_AREA_IMPORT_TOP, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { -1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE } + }; + static const XmlStyleFamily aFamilies[] = + { + XmlStyleFamily::SD_STROKE_DASH_ID, + XmlStyleFamily::SD_MARKER_ID, + XmlStyleFamily::SD_MARKER_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID + }; + + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + SAL_WARN_IF( !xImpPrMap.is(), "xmloff", "There is the import prop mapper" ); + if( xImpPrMap.is() ) + xImpPrMap->FillPropertySet( GetProperties(), rPropSet, aContextIDs ); + + Reference< XPropertySetInfo > xInfo; + // get property set mapper + rtl::Reference xPropMapper( xImpPrMap->getPropertySetMapper() ); + + for( sal_uInt16 i=0; aContextIDs[i].nContextID != -1; i++ ) + { + sal_Int32 nIndex = aContextIDs[i].nIndex; + if( nIndex != -1 ) switch( aContextIDs[i].nContextID ) + { + case CTF_DASHNAME: + case CTF_LINESTARTNAME: + case CTF_LINEENDNAME: + case CTF_FILLGRADIENTNAME: + case CTF_FILLTRANSNAME: + case CTF_FILLHATCHNAME: + case CTF_FILLBITMAPNAME: + { + struct XMLPropertyState& rState = GetProperties()[nIndex]; + OUString sStyleName; + rState.maValue >>= sStyleName; + sStyleName = GetImport().GetStyleDisplayName( aFamilies[i], sStyleName ); + // All of these attributes refer to something with draw:name + // of type styleName = NCName which is non-empty. + // tdf#89802: for Writer frames there would be no exception here but + // it will fail later on attach() and take out the entire frame + if (sStyleName.isEmpty() && + ( CTF_FILLGRADIENTNAME == aContextIDs[i].nContextID + || CTF_FILLTRANSNAME == aContextIDs[i].nContextID + || CTF_FILLHATCHNAME == aContextIDs[i].nContextID + || CTF_FILLBITMAPNAME == aContextIDs[i].nContextID)) + { + Sequence const seq{ sStyleName }; + GetImport().SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, + seq, "empty style name reference", nullptr ); + break; + } + + if (::xmloff::IsIgnoreFillStyleNamedItem(rPropSet, aContextIDs[i].nExpectedFillStyle)) + { + SAL_INFO("xmloff.style", "ShapeStyleContext: dropping fill named item: " << sStyleName); + break; // ignore it, it's not used + } + + try + { + + // set property + const OUString& rPropertyName = xPropMapper->GetEntryAPIName(rState.mnIndex); + if( !xInfo.is() ) + xInfo = rPropSet->getPropertySetInfo(); + if ( xInfo->hasPropertyByName( rPropertyName ) ) + { + rPropSet->setPropertyValue( rPropertyName, Any( sStyleName ) ); + } + } + catch ( const css::lang::IllegalArgumentException& e ) + { + Sequence aSeq { sStyleName }; + GetImport().SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, + aSeq, e.Message, nullptr ); + } + break; + } + case CTF_SD_OLE_VIS_AREA_IMPORT_LEFT: + case CTF_SD_OLE_VIS_AREA_IMPORT_TOP: + case CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH: + case CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT: + { + struct XMLPropertyState& rState = GetProperties()[nIndex]; + const OUString& rPropertyName = xPropMapper->GetEntryAPIName(rState.mnIndex); + try + { + if( !xInfo.is() ) + xInfo = rPropSet->getPropertySetInfo(); + if ( xInfo->hasPropertyByName( rPropertyName ) ) + { + rPropSet->setPropertyValue( rPropertyName, rState.maValue ); + } + } + catch ( const css::lang::IllegalArgumentException& e ) + { + Sequence aSeq; + GetImport().SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, + aSeq, e.Message, nullptr ); + } + break; + } + } + } + + if (m_sControlDataStyleName.isEmpty()) + return; + + // we had a data-style-name attribute + + // set the formatting on the control model of the control shape + uno::Reference< drawing::XControlShape > xControlShape(rPropSet, uno::UNO_QUERY); + DBG_ASSERT(xControlShape.is(), "XMLShapeStyleContext::FillPropertySet: data style for a non-control shape!"); + if (xControlShape.is()) + { + uno::Reference< beans::XPropertySet > xControlModel(xControlShape->getControl(), uno::UNO_QUERY); + DBG_ASSERT(xControlModel.is(), "XMLShapeStyleContext::FillPropertySet: no control model for the shape!"); + if (xControlModel.is()) + { + GetImport().GetFormImport()->applyControlNumberStyle(xControlModel, m_sControlDataStyleName); + } + } +} + +void XMLShapeStyleContext::Finish( bool /*bOverwrite*/ ) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/animationexport.cxx b/xmloff/source/draw/animationexport.cxx new file mode 100644 index 000000000..2a48e16c3 --- /dev/null +++ b/xmloff/source/draw/animationexport.cxx @@ -0,0 +1,1743 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "sdpropls.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace css; +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star::animations; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::beans::NamedValue; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; + +namespace xmloff +{ + +const SvXMLEnumMapEntry aAnimations_EnumMap_Fill[] = +{ + { XML_DEFAULT, AnimationFill::DEFAULT }, + { XML_REMOVE, AnimationFill::REMOVE }, + { XML_FREEZE, AnimationFill::FREEZE }, + { XML_HOLD, AnimationFill::HOLD }, + { XML_TRANSITION, AnimationFill::TRANSITION }, + { XML_AUTO, AnimationFill::AUTO }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_FillDefault[] = +{ + { XML_INHERIT, AnimationFill::INHERIT }, + { XML_REMOVE, AnimationFill::REMOVE }, + { XML_FREEZE, AnimationFill::FREEZE }, + { XML_HOLD, AnimationFill::HOLD }, + { XML_TRANSITION, AnimationFill::TRANSITION }, + { XML_AUTO, AnimationFill::AUTO }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_Restart[] = +{ + { XML_DEFAULT, AnimationRestart::DEFAULT }, + { XML_ALWAYS, AnimationRestart::ALWAYS }, + { XML_WHENNOTACTIVE,AnimationRestart::WHEN_NOT_ACTIVE }, + { XML_NEVER, AnimationRestart::NEVER }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_RestartDefault[] = +{ + { XML_INHERIT, AnimationRestart::INHERIT }, + { XML_ALWAYS, AnimationRestart::ALWAYS }, + { XML_WHENNOTACTIVE,AnimationRestart::WHEN_NOT_ACTIVE }, + { XML_NEVER, AnimationRestart::NEVER }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_Endsync[] = +{ + { XML_FIRST, AnimationEndSync::FIRST }, + { XML_LAST, AnimationEndSync::LAST }, + { XML_ALL, AnimationEndSync::ALL }, + { XML_MEDIA, AnimationEndSync::MEDIA }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_CalcMode[] = +{ + { XML_DISCRETE, AnimationCalcMode::DISCRETE }, + { XML_LINEAR, AnimationCalcMode::LINEAR }, + { XML_PACED, AnimationCalcMode::PACED }, + { XML_SPLINE, AnimationCalcMode::SPLINE }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_AdditiveMode[] = +{ + { XML_BASE, AnimationAdditiveMode::BASE }, + { XML_SUM, AnimationAdditiveMode::SUM }, + { XML_REPLACE, AnimationAdditiveMode::REPLACE }, + { XML_MULTIPLY, AnimationAdditiveMode::MULTIPLY }, + { XML_NONE, AnimationAdditiveMode::NONE }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_TransformType[] = +{ + { XML_TRANSLATE, AnimationTransformType::TRANSLATE }, + { XML_SCALE, AnimationTransformType::SCALE }, + { XML_ROTATE, AnimationTransformType::ROTATE }, + { XML_SKEWX, AnimationTransformType::SKEWX }, + { XML_SKEWY, AnimationTransformType::SKEWY }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_TransitionType[] = +{ + { XML_BARWIPE, TransitionType::BARWIPE }, + { XML_BOXWIPE, TransitionType::BOXWIPE }, + { XML_FOURBOXWIPE, TransitionType::FOURBOXWIPE }, + { XML_BARNDOORWIPE, TransitionType::BARNDOORWIPE }, + { XML_DIAGONALWIPE, TransitionType::DIAGONALWIPE }, + { XML_BOWTIEWIPE, TransitionType::BOWTIEWIPE }, + { XML_MISCDIAGONALWIPE, TransitionType::MISCDIAGONALWIPE }, + { XML_VEEWIPE, TransitionType::VEEWIPE }, + { XML_BARNVEEWIPE, TransitionType::BARNVEEWIPE }, + { XML_ZIGZAGWIPE, TransitionType::ZIGZAGWIPE }, + { XML_BARNZIGZAGWIPE, TransitionType::BARNZIGZAGWIPE }, + { XML_IRISWIPE, TransitionType::IRISWIPE }, + { XML_TRIANGLEWIPE, TransitionType::TRIANGLEWIPE }, + { XML_ARROWHEADWIPE, TransitionType::ARROWHEADWIPE }, + { XML_PENTAGONWIPE, TransitionType::PENTAGONWIPE }, + { XML_HEXAGONWIPE, TransitionType::HEXAGONWIPE }, + { XML_ELLIPSEWIPE, TransitionType::ELLIPSEWIPE }, + { XML_EYEWIPE, TransitionType::EYEWIPE }, + { XML_ROUNDRECTWIPE, TransitionType::ROUNDRECTWIPE }, + { XML_STARWIPE, TransitionType::STARWIPE }, + { XML_MISCSHAPEWIPE, TransitionType::MISCSHAPEWIPE }, + { XML_CLOCKWIPE, TransitionType::CLOCKWIPE }, + { XML_PINWHEELWIPE, TransitionType::PINWHEELWIPE }, + { XML_SINGLESWEEPWIPE, TransitionType::SINGLESWEEPWIPE }, + { XML_FANWIPE, TransitionType::FANWIPE }, + { XML_DOUBLEFANWIPE, TransitionType::DOUBLEFANWIPE }, + { XML_DOUBLESWEEPWIPE, TransitionType::DOUBLESWEEPWIPE }, + { XML_SALOONDOORWIPE, TransitionType::SALOONDOORWIPE }, + { XML_WINDSHIELDWIPE, TransitionType::WINDSHIELDWIPE }, + { XML_SNAKEWIPE, TransitionType::SNAKEWIPE }, + { XML_SPIRALWIPE, TransitionType::SPIRALWIPE }, + { XML_PARALLELSNAKESWIPE,TransitionType::PARALLELSNAKESWIPE }, + { XML_BOXSNAKESWIPE, TransitionType::BOXSNAKESWIPE }, + { XML_WATERFALLWIPE, TransitionType::WATERFALLWIPE }, + { XML_PUSHWIPE, TransitionType::PUSHWIPE }, + { XML_SLIDEWIPE, TransitionType::SLIDEWIPE }, + { XML_FADE, TransitionType::FADE }, + { XML_RANDOMBARWIPE, TransitionType::RANDOMBARWIPE }, + { XML_CHECKERBOARDWIPE, TransitionType::CHECKERBOARDWIPE }, + { XML_DISSOLVE, TransitionType::DISSOLVE }, + { XML_BLINDSWIPE, TransitionType::BLINDSWIPE }, + { XML_RANDOM, TransitionType::RANDOM }, + { XML_ZOOM, TransitionType::ZOOM }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_TransitionSubType[] = +{ + { XML_DEFAULT, TransitionSubType::DEFAULT }, + { XML_LEFTTORIGHT, TransitionSubType::LEFTTORIGHT }, + { XML_TOPTOBOTTOM, TransitionSubType::TOPTOBOTTOM }, + { XML_TOPLEFT, TransitionSubType::TOPLEFT }, + { XML_TOPRIGHT, TransitionSubType::TOPRIGHT }, + { XML_BOTTOMRIGHT, TransitionSubType::BOTTOMRIGHT }, + { XML_BOTTOMLEFT, TransitionSubType::BOTTOMLEFT }, + { XML_TOPCENTER, TransitionSubType::TOPCENTER }, + { XML_RIGHTCENTER, TransitionSubType::RIGHTCENTER }, + { XML_BOTTOMCENTER, TransitionSubType::BOTTOMCENTER }, + { XML_LEFTCENTER, TransitionSubType::LEFTCENTER }, + { XML_CORNERSIN, TransitionSubType::CORNERSIN }, + { XML_CORNERSOUT, TransitionSubType::CORNERSOUT }, + { XML_VERTICAL, TransitionSubType::VERTICAL }, + { XML_HORIZONTAL, TransitionSubType::HORIZONTAL }, + { XML_DIAGONALBOTTOMLEFT, TransitionSubType::DIAGONALBOTTOMLEFT }, + { XML_DIAGONALTOPLEFT, TransitionSubType::DIAGONALTOPLEFT }, + { XML_DOUBLEBARNDOOR, TransitionSubType::DOUBLEBARNDOOR }, + { XML_DOUBLEDIAMOND, TransitionSubType::DOUBLEDIAMOND }, + { XML_DOWN, TransitionSubType::DOWN }, + { XML_LEFT, TransitionSubType::LEFT }, + { XML_UP, TransitionSubType::UP }, + { XML_RIGHT, TransitionSubType::RIGHT }, + { XML_RECTANGLE, TransitionSubType::RECTANGLE }, + { XML_DIAMOND, TransitionSubType::DIAMOND }, + { XML_CIRCLE, TransitionSubType::CIRCLE }, + { XML_FOURPOINT, TransitionSubType::FOURPOINT }, + { XML_FIVEPOINT, TransitionSubType::FIVEPOINT }, + { XML_SIXPOINT, TransitionSubType::SIXPOINT }, + { XML_HEART, TransitionSubType::HEART }, + { XML_KEYHOLE, TransitionSubType::KEYHOLE }, + { XML_CLOCKWISETWELVE, TransitionSubType::CLOCKWISETWELVE }, + { XML_CLOCKWISETHREE, TransitionSubType::CLOCKWISETHREE }, + { XML_CLOCKWISESIX, TransitionSubType::CLOCKWISESIX }, + { XML_CLOCKWISENINE, TransitionSubType::CLOCKWISENINE }, + { XML_TWOBLADEVERTICAL, TransitionSubType::TWOBLADEVERTICAL }, + { XML_TWOBLADEHORIZONTAL, TransitionSubType::TWOBLADEHORIZONTAL }, + { XML_FOURBLADE, TransitionSubType::FOURBLADE }, + { XML_CLOCKWISETOP, TransitionSubType::CLOCKWISETOP }, + { XML_CLOCKWISERIGHT, TransitionSubType::CLOCKWISERIGHT }, + { XML_CLOCKWISEBOTTOM, TransitionSubType::CLOCKWISEBOTTOM }, + { XML_CLOCKWISELEFT, TransitionSubType::CLOCKWISELEFT }, + { XML_CLOCKWISETOPLEFT, TransitionSubType::CLOCKWISETOPLEFT }, + { XML_COUNTERCLOCKWISEBOTTOMLEFT,TransitionSubType::COUNTERCLOCKWISEBOTTOMLEFT }, + { XML_CLOCKWISEBOTTOMRIGHT, TransitionSubType::CLOCKWISEBOTTOMRIGHT }, + { XML_COUNTERCLOCKWISETOPRIGHT,TransitionSubType::COUNTERCLOCKWISETOPRIGHT }, + { XML_CENTERTOP, TransitionSubType::CENTERTOP }, + { XML_CENTERRIGHT, TransitionSubType::CENTERRIGHT }, + { XML_TOP, TransitionSubType::TOP }, + { XML_BOTTOM, TransitionSubType::BOTTOM }, + { XML_FANOUTVERTICAL, TransitionSubType::FANOUTVERTICAL }, + { XML_FANOUTHORIZONTAL, TransitionSubType::FANOUTHORIZONTAL }, + { XML_FANINVERTICAL, TransitionSubType::FANINVERTICAL }, + { XML_FANINHORIZONTAL, TransitionSubType::FANINHORIZONTAL }, + { XML_PARALLELVERTICAL, TransitionSubType::PARALLELVERTICAL }, + { XML_PARALLELDIAGONAL, TransitionSubType::PARALLELDIAGONAL }, + { XML_OPPOSITEVERTICAL, TransitionSubType::OPPOSITEVERTICAL }, + { XML_OPPOSITEHORIZONTAL, TransitionSubType::OPPOSITEHORIZONTAL }, + { XML_PARALLELDIAGONALTOPLEFT,TransitionSubType::PARALLELDIAGONALTOPLEFT }, + { XML_PARALLELDIAGONALBOTTOMLEFT,TransitionSubType::PARALLELDIAGONALBOTTOMLEFT }, + { XML_TOPLEFTHORIZONTAL, TransitionSubType::TOPLEFTHORIZONTAL }, + { XML_TOPLEFTDIAGONAL, TransitionSubType::TOPLEFTDIAGONAL }, + { XML_TOPRIGHTDIAGONAL, TransitionSubType::TOPRIGHTDIAGONAL }, + { XML_BOTTOMRIGHTDIAGONAL, TransitionSubType::BOTTOMRIGHTDIAGONAL }, + { XML_BOTTOMLEFTDIAGONAL, TransitionSubType::BOTTOMLEFTDIAGONAL }, + { XML_TOPLEFTCLOCKWISE, TransitionSubType::TOPLEFTCLOCKWISE }, + { XML_TOPRIGHTCLOCKWISE, TransitionSubType::TOPRIGHTCLOCKWISE }, + { XML_BOTTOMRIGHTCLOCKWISE, TransitionSubType::BOTTOMRIGHTCLOCKWISE }, + { XML_BOTTOMLEFTCLOCKWISE, TransitionSubType::BOTTOMLEFTCLOCKWISE }, + { XML_TOPLEFTCOUNTERCLOCKWISE,TransitionSubType::TOPLEFTCOUNTERCLOCKWISE }, + { XML_TOPRIGHTCOUNTERCLOCKWISE,TransitionSubType::TOPRIGHTCOUNTERCLOCKWISE }, + { XML_BOTTOMRIGHTCOUNTERCLOCKWISE,TransitionSubType::BOTTOMRIGHTCOUNTERCLOCKWISE }, + { XML_BOTTOMLEFTCOUNTERCLOCKWISE,TransitionSubType::BOTTOMLEFTCOUNTERCLOCKWISE }, + { XML_VERTICALTOPSAME, TransitionSubType::VERTICALTOPSAME }, + { XML_VERTICALBOTTOMSAME, TransitionSubType::VERTICALBOTTOMSAME }, + { XML_VERTICALTOPLEFTOPPOSITE,TransitionSubType::VERTICALTOPLEFTOPPOSITE }, + { XML_VERTICALBOTTOMLEFTOPPOSITE,TransitionSubType::VERTICALBOTTOMLEFTOPPOSITE }, + { XML_HORIZONTALLEFTSAME, TransitionSubType::HORIZONTALLEFTSAME }, + { XML_HORIZONTALRIGHTSAME, TransitionSubType::HORIZONTALRIGHTSAME }, + { XML_HORIZONTALTOPLEFTOPPOSITE,TransitionSubType::HORIZONTALTOPLEFTOPPOSITE }, + { XML_HORIZONTALTOPRIGHTOPPOSITE,TransitionSubType::HORIZONTALTOPRIGHTOPPOSITE }, + { XML_DIAGONALBOTTOMLEFTOPPOSITE,TransitionSubType::DIAGONALBOTTOMLEFTOPPOSITE }, + { XML_DIAGONALTOPLEFTOPPOSITE,TransitionSubType::DIAGONALTOPLEFTOPPOSITE }, + { XML_TWOBOXTOP, TransitionSubType::TWOBOXTOP }, + { XML_TWOBOXBOTTOM, TransitionSubType::TWOBOXBOTTOM }, + { XML_TWOBOXLEFT, TransitionSubType::TWOBOXLEFT }, + { XML_TWOBOXRIGHT, TransitionSubType::TWOBOXRIGHT }, + { XML_FOURBOXVERTICAL, TransitionSubType::FOURBOXVERTICAL }, + { XML_FOURBOXHORIZONTAL, TransitionSubType::FOURBOXHORIZONTAL }, + { XML_VERTICALLEFT, TransitionSubType::VERTICALLEFT }, + { XML_VERTICALRIGHT, TransitionSubType::VERTICALRIGHT }, + { XML_HORIZONTALLEFT, TransitionSubType::HORIZONTALLEFT }, + { XML_HORIZONTALRIGHT, TransitionSubType::HORIZONTALRIGHT }, + { XML_FROMLEFT, TransitionSubType::FROMLEFT }, + { XML_FROMTOP, TransitionSubType::FROMTOP }, + { XML_FROMRIGHT, TransitionSubType::FROMRIGHT }, + { XML_FROMBOTTOM, TransitionSubType::FROMBOTTOM }, + { XML_CROSSFADE, TransitionSubType::CROSSFADE }, + { XML_FADETOCOLOR, TransitionSubType::FADETOCOLOR }, + { XML_FADEFROMCOLOR, TransitionSubType::FADEFROMCOLOR }, + { XML_FADEOVERCOLOR, TransitionSubType::FADEOVERCOLOR }, + { XML_THREEBLADE, TransitionSubType::THREEBLADE }, + { XML_EIGHTBLADE, TransitionSubType::EIGHTBLADE }, + { XML_ONEBLADE, TransitionSubType::ONEBLADE }, + { XML_ACROSS, TransitionSubType::ACROSS }, + { XML_TOPLEFTVERTICAL, TransitionSubType::TOPLEFTVERTICAL }, + { XML_COMBHORIZONTAL, TransitionSubType::COMBHORIZONTAL }, + { XML_COMBVERTICAL, TransitionSubType::COMBVERTICAL }, + { XML_IN, TransitionSubType::IN }, + { XML_OUT, TransitionSubType::OUT }, + { XML_ROTATEIN, TransitionSubType::ROTATEIN }, + { XML_ROTATEOUT, TransitionSubType::ROTATEOUT }, + { XML_FROMTOPLEFT, TransitionSubType::FROMTOPLEFT }, + { XML_FROMTOPRIGHT, TransitionSubType::FROMTOPRIGHT }, + { XML_FROMBOTTOMLEFT, TransitionSubType::FROMBOTTOMLEFT }, + { XML_FROMBOTTOMRIGHT, TransitionSubType::FROMBOTTOMRIGHT }, + + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_EventTrigger[] = +{ + { XML_ONBEGIN, EventTrigger::ON_BEGIN }, + { XML_ONEND, EventTrigger::ON_END }, + { XML_BEGIN, EventTrigger::BEGIN_EVENT }, + { XML_END, EventTrigger::END_EVENT }, + { XML_CLICK, EventTrigger::ON_CLICK }, + { XML_DOUBLECLICK, EventTrigger::ON_DBL_CLICK }, + { XML_MOUSEOVER, EventTrigger::ON_MOUSE_ENTER }, + { XML_MOUSEOUT, EventTrigger::ON_MOUSE_LEAVE }, + { XML_NEXT, EventTrigger::ON_NEXT }, + { XML_PREVIOUS, EventTrigger::ON_PREV }, + { XML_STOP_AUDIO, EventTrigger::ON_STOP_AUDIO }, + { XML_REPEAT, EventTrigger::REPEAT }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_EffectPresetClass[] = +{ + { XML_CUSTOM, EffectPresetClass::CUSTOM }, + { XML_ENTRANCE, EffectPresetClass::ENTRANCE }, + { XML_EXIT, EffectPresetClass::EXIT }, + { XML_EMPHASIS, EffectPresetClass::EMPHASIS }, + { XML_MOTION_PATH, EffectPresetClass::MOTIONPATH }, + { XML_OLE_ACTION, EffectPresetClass::OLEACTION }, + { XML_MEDIA_CALL, EffectPresetClass::MEDIACALL }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_EffectNodeType[] = +{ + { XML_DEFAULT, EffectNodeType::DEFAULT }, + { XML_ON_CLICK, EffectNodeType::ON_CLICK }, + { XML_WITH_PREVIOUS, EffectNodeType::WITH_PREVIOUS }, + { XML_AFTER_PREVIOUS, EffectNodeType::AFTER_PREVIOUS }, + { XML_MAIN_SEQUENCE, EffectNodeType::MAIN_SEQUENCE }, + { XML_TIMING_ROOT, EffectNodeType::TIMING_ROOT }, + { XML_INTERACTIVE_SEQUENCE, EffectNodeType::INTERACTIVE_SEQUENCE }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_SubItem[] = +{ + { XML_WHOLE, ShapeAnimationSubType::AS_WHOLE }, + { XML_BACKGROUND, ShapeAnimationSubType::ONLY_BACKGROUND }, + { XML_TEXT, ShapeAnimationSubType::ONLY_TEXT }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_IterateType[] = +{ + { XML_BY_PARAGRAPH, TextAnimationType::BY_PARAGRAPH }, + { XML_BY_WORD, TextAnimationType::BY_WORD }, + { XML_BY_LETTER, TextAnimationType::BY_LETTER }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aAnimations_EnumMap_Command[] = +{ + { XML_CUSTOM, EffectCommands::CUSTOM }, + { XML_VERB, EffectCommands::VERB }, + { XML_PLAY, EffectCommands::PLAY }, + { XML_TOGGLE_PAUSE, EffectCommands::TOGGLEPAUSE }, + { XML_STOP, EffectCommands::STOP }, + { XML_STOP_AUDIO, EffectCommands::STOPAUDIO }, + { XML_TOKEN_INVALID, 0 } +}; + +const struct ImplAttributeNameConversion* getAnimationAttributeNamesConversionList() +{ + static const struct ImplAttributeNameConversion gImplConversionList[] = + { + { XML_X, "X" }, + { XML_Y, "Y" }, + { XML_WIDTH, "Width" }, + { XML_HEIGHT, "Height" }, + { XML_ROTATE, "Rotate" }, + { XML_SKEWX, "SkewX" }, + { XML_FILL_COLOR, "FillColor" }, + { XML_FILL, "FillStyle" }, + { XML_STROKE_COLOR, "LineColor" }, + { XML_STROKE, "LineStyle" }, + { XML_COLOR, "CharColor" }, + { XML_TEXT_ROTATION_ANGLE, "CharRotation" }, + { XML_FONT_WEIGHT, "CharWeight" }, + { XML_TEXT_UNDERLINE, "CharUnderline" }, + { XML_FONT_FAMILY, "CharFontName" }, + { XML_FONT_SIZE, "CharHeight" }, + { XML_FONT_STYLE, "CharPosture" }, + { XML_VISIBILITY, "Visibility" }, + { XML_OPACITY, "Opacity" }, + { XML_DIM, "DimColor" }, + { XML_TOKEN_INVALID, nullptr } + }; + + return gImplConversionList; +} + + +class AnimationsExporterImpl +{ +public: + AnimationsExporterImpl( SvXMLExport& rExport, const Reference< XPropertySet >& xPageProps ); + + void prepareNode( const Reference< XAnimationNode >& xNode ); + void exportNode( const Reference< XAnimationNode >& xNode ); + + void exportContainer( const Reference< XTimeContainer >& xNode, sal_Int16 nContainerNodeType ); + void exportAnimate( const Reference< XAnimate >& xNode ); + void exportAudio( const Reference< XAudio >& xAudio ); + void exportCommand( const Reference< XCommand >& xCommand ); + + static Reference< XInterface > getParagraphTarget( const ParagraphTarget& pTarget ); + + static void convertPath( OUStringBuffer& sTmp, const Any& rPath ); + void convertValue( XMLTokenEnum eAttributeName, OUStringBuffer& sTmp, const Any& rValue ) const; + void convertTiming( OUStringBuffer& sTmp, const Any& rTiming ) const; + void convertTarget( OUStringBuffer& sTmp, const Any& rTarget ) const; + + void prepareValue( const Any& rValue ); + + void exportTransitionNode(); + void prepareTransitionNode(); + + bool mbHasTransition; +private: + rtl::Reference mxExport; + Reference< XPropertySet > mxPageProps; + rtl::Reference mxSdPropHdlFactory; +}; + +AnimationsExporterImpl::AnimationsExporterImpl( SvXMLExport& rExport, const Reference< XPropertySet >& xPageProps ) +: mbHasTransition(false) +, mxExport( &rExport ) +, mxPageProps( xPageProps ) +, mxSdPropHdlFactory(new XMLSdPropHdlFactory( rExport.GetModel(), rExport )) +{ +} + + +/** split a uri hierarchy into first segment and rest */ +static bool splitPath(OUString const & i_rPath, + OUString & o_rDir, OUString& o_rRest) +{ + const sal_Int32 idx(i_rPath.indexOf(u'/')); + if (idx < 0 || idx >= i_rPath.getLength()) { + o_rDir = OUString(); + o_rRest = i_rPath; + return true; + } else if (idx == 0 || idx == i_rPath.getLength() - 1) { + // input must not start or end with '/' + return false; + } else { + o_rDir = i_rPath.copy(0, idx); + o_rRest = i_rPath.copy(idx+1); + return true; + } +} + +static void lcl_CopyStream( + uno::Reference const& xSource, + uno::Reference const& xTarget, + OUString const& rPath) +{ + OUString dir; + OUString rest; + if (!splitPath(rPath, dir, rest)) + throw uno::RuntimeException(); + + if (dir.getLength() == 0) + xSource->copyElementTo(rPath, xTarget, rPath); + else + { + uno::Reference const xSubSource( + xSource->openStorageElement(dir, embed::ElementModes::READ)); + uno::Reference const xSubTarget( + xTarget->openStorageElement(dir, embed::ElementModes::WRITE)); + lcl_CopyStream(xSubSource, xSubTarget, rest); + } + uno::Reference const xTransaction(xTarget, uno::UNO_QUERY); + if (xTransaction.is()) + xTransaction->commit(); +} + +char const s_PkgScheme[] = "vnd.sun.star.Package:"; + +static OUString lcl_StoreMediaAndGetURL(SvXMLExport & rExport, OUString const& rURL) +{ + OUString urlPath; + if (rURL.startsWithIgnoreAsciiCase(s_PkgScheme, &urlPath)) + { + try // video is embedded + { + // copy the media stream from document storage to target storage + // (not sure if this is the best way to store these?) + uno::Reference const xSBD( + rExport.GetModel(), uno::UNO_QUERY_THROW); + uno::Reference const xSource( + xSBD->getDocumentStorage(), uno::UNO_SET_THROW); + uno::Reference const xTarget( + rExport.GetTargetStorage(), uno::UNO_SET_THROW); + + urlPath = rURL.copy(SAL_N_ELEMENTS(s_PkgScheme)-1); + + lcl_CopyStream(xSource, xTarget, urlPath); + + return urlPath; + } + catch (uno::Exception const&) + { + TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media"); + } + return OUString(); + } + else + { + return rExport.GetRelativeReference(rURL); // linked + } +} + +void AnimationsExporterImpl::exportTransitionNode() +{ + if( !(mbHasTransition && mxPageProps.is()) ) + return; + + sal_Int16 nTransition = 0; + mxPageProps->getPropertyValue("TransitionType") >>= nTransition; + + Any aSound( mxPageProps->getPropertyValue("Sound") ); + OUString sSoundURL; + aSound >>= sSoundURL; + bool bStopSound = false; + if( !(aSound >>= bStopSound) ) + bStopSound = false; + + + OUStringBuffer sTmp; + if( !((nTransition != 0) || !sSoundURL.isEmpty() || bStopSound) ) + return; + + Reference< XInterface > xSource( mxPageProps ); + Event aEvent; + aEvent.Source <<= xSource; + aEvent.Trigger = EventTrigger::BEGIN_EVENT; + aEvent.Repeat = 0; + + convertTiming( sTmp, Any( aEvent ) ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_BEGIN, sTmp.makeStringAndClear() ); + + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, XML_PAR, true, true ); + + if( nTransition != 0 ) + { + sal_Int16 nSubtype = 0; + bool bDirection = false; + sal_Int32 nFadeColor = 0; + double fDuration = 0.0; + mxPageProps->getPropertyValue("TransitionSubtype") >>= nSubtype; + mxPageProps->getPropertyValue("TransitionDirection") >>= bDirection; + mxPageProps->getPropertyValue("TransitionFadeColor") >>= nFadeColor; + mxPageProps->getPropertyValue("TransitionDuration") >>= fDuration; + + ::sax::Converter::convertDouble( sTmp, fDuration ); + sTmp.append( 's'); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DUR, sTmp.makeStringAndClear() ); + + SvXMLUnitConverter::convertEnum( sTmp, nTransition, aAnimations_EnumMap_TransitionType ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TYPE, sTmp.makeStringAndClear() ); + + if( nSubtype != TransitionSubType::DEFAULT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nSubtype, aAnimations_EnumMap_TransitionSubType ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_SUBTYPE, sTmp.makeStringAndClear() ); + } + + if( !bDirection ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DIRECTION, XML_REVERSE ); + + if( (nTransition == TransitionType::FADE) + && ((nSubtype == TransitionSubType::FADETOCOLOR) || (nSubtype == TransitionSubType::FADEFROMCOLOR) + || (nSubtype == TransitionSubType::FADEOVERCOLOR))) + { + ::sax::Converter::convertColor( sTmp, nFadeColor ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FADECOLOR, sTmp.makeStringAndClear() ); + } + SvXMLElementExport aElement2( *mxExport, XML_NAMESPACE_ANIMATION, XML_TRANSITIONFILTER, true, true ); + } + + if( bStopSound ) + { + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_COMMAND, XML_STOP_AUDIO ); + SvXMLElementExport aElement2( *mxExport, XML_NAMESPACE_ANIMATION, XML_COMMAND, true, true ); + } + else if( !sSoundURL.isEmpty()) + { + sSoundURL = lcl_StoreMediaAndGetURL(*mxExport, sSoundURL); + mxExport->AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sSoundURL ); + + bool bLoopSound = false; + mxPageProps->getPropertyValue("LoopSound") >>= bLoopSound; + + if( bLoopSound ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATCOUNT, XML_INDEFINITE ); + SvXMLElementExport aElement2( *mxExport, XML_NAMESPACE_ANIMATION, XML_AUDIO, true, true ); + } +} + +void AnimationsExporterImpl::prepareTransitionNode() +{ + if( !mxPageProps.is() ) + return; + + try + { + sal_Int16 nTransition = 0; + mxPageProps->getPropertyValue("TransitionType") >>= nTransition; + + bool bStopSound = false; + OUString sSoundURL; + + if( nTransition == 0 ) + { + Any aSound( mxPageProps->getPropertyValue("Sound") ); + aSound >>= sSoundURL; + + if( !(aSound >>= bStopSound) ) + bStopSound = false; + } + + if( (nTransition != 0) || !sSoundURL.isEmpty() || bStopSound ) + { + mbHasTransition = true; + Reference< XInterface > xInt( mxPageProps ); + mxExport->getInterfaceToIdentifierMapper().registerReference( xInt ); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::prepareNode( const Reference< XAnimationNode >& xNode ) +{ + try + { + prepareValue( xNode->getBegin() ); + prepareValue( xNode->getEnd() ); + + sal_Int16 nNodeType = xNode->getType(); + switch( nNodeType ) + { + case AnimationNodeType::ITERATE: + { + Reference< XIterateContainer > xIter( xNode, UNO_QUERY_THROW ); + prepareValue( xIter->getTarget() ); + [[fallthrough]]; + } + case AnimationNodeType::PAR: + case AnimationNodeType::SEQ: + { + Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + while( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + prepareNode( xChildNode ); + } + } + break; + + case AnimationNodeType::ANIMATE: + case AnimationNodeType::SET: + case AnimationNodeType::ANIMATEMOTION: + case AnimationNodeType::ANIMATEPHYSICS: + case AnimationNodeType::ANIMATECOLOR: + case AnimationNodeType::ANIMATETRANSFORM: + case AnimationNodeType::TRANSITIONFILTER: + { + Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW ); + prepareValue( xAnimate->getTarget() ); + } + break; + + case AnimationNodeType::COMMAND: + { + Reference< XCommand > xCommand( xNode, UNO_QUERY_THROW ); + prepareValue( xCommand->getTarget() ); + } + break; + + case AnimationNodeType::AUDIO: + { + Reference< XAudio > xAudio( xNode, UNO_QUERY_THROW ); + prepareValue( xAudio->getSource() ); + } + break; + } + + const Sequence< NamedValue > aUserData( xNode->getUserData() ); + for( const auto& rValue : aUserData ) + { + if( IsXMLToken( rValue.Name, XML_MASTER_ELEMENT ) ) + { + Reference< XInterface > xMaster; + rValue.Value >>= xMaster; + if( xMaster.is() ) + mxExport->getInterfaceToIdentifierMapper().registerReference( xMaster ); + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::exportNode( const Reference< XAnimationNode >& xNode ) +{ + try + { + OUStringBuffer sTmp; + + const OUString& rExportIdentifier = mxExport->getInterfaceToIdentifierMapper().getIdentifier( xNode ); + if( !rExportIdentifier.isEmpty() ) + { + mxExport->AddAttributeIdLegacy( + XML_NAMESPACE_ANIMATION, rExportIdentifier); + } + + Any aTemp( xNode->getBegin() ); + if( aTemp.hasValue() ) + { + convertTiming( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_BEGIN, sTmp.makeStringAndClear() ); + } + + double fTemp = 0; + sal_Int16 nTemp; + + aTemp = xNode->getDuration(); + if( aTemp.hasValue() ) + { + if( aTemp >>= fTemp ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + sTmp.append( 's'); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DUR, sTmp.makeStringAndClear() ); + } + else + { + Timing eTiming; + if( aTemp >>= eTiming ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DUR, eTiming == Timing_INDEFINITE ? XML_INDEFINITE : XML_MEDIA ); + } + } + + aTemp = xNode->getEnd(); + if( aTemp.hasValue() ) + { + convertTiming( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_END, sTmp.makeStringAndClear() ); + } + + nTemp = xNode->getFill(); + if( nTemp != AnimationFill::DEFAULT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_Fill ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FILL, sTmp.makeStringAndClear() ); + } + + nTemp = xNode->getFillDefault(); + if( nTemp != AnimationFill::INHERIT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_FillDefault ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FILLDEFAULT, sTmp.makeStringAndClear() ); + } + + nTemp = xNode->getRestart(); + if( nTemp != AnimationRestart::DEFAULT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_Restart ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_RESTART, sTmp.makeStringAndClear() ); + } + + nTemp = xNode->getRestartDefault(); + if( nTemp != AnimationRestart::INHERIT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_RestartDefault ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_RESTARTDEFAULT, sTmp.makeStringAndClear() ); + } + + fTemp = xNode->getAcceleration(); + if( fTemp != 0.0 ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ACCELERATE, sTmp.makeStringAndClear() ); + } + + fTemp = xNode->getDecelerate(); + if( fTemp != 0.0 ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DECELERATE, sTmp.makeStringAndClear() ); + } + + bool bTemp = xNode->getAutoReverse(); + if( bTemp ) + { + ::sax::Converter::convertBool( sTmp, bTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_AUTOREVERSE, sTmp.makeStringAndClear() ); + } + + aTemp = xNode->getRepeatCount(); + if( aTemp.hasValue() ) + { + Timing eTiming; + if( (aTemp >>= eTiming ) && (eTiming == Timing_INDEFINITE ) ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATCOUNT, XML_INDEFINITE ); + else if( aTemp >>= fTemp ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATCOUNT, sTmp.makeStringAndClear() ); + } + } + + aTemp = xNode->getRepeatDuration(); + if( aTemp.hasValue() ) + { + Timing eTiming; + if( ( aTemp >>= eTiming ) && (eTiming == Timing_INDEFINITE) ) + { + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATDUR, XML_INDEFINITE ); + } + else if( aTemp >>= fTemp ) + { + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_REPEATDUR, sTmp.makeStringAndClear() ); + } + } + + aTemp = xNode->getEndSync(); + if( aTemp.hasValue() && (aTemp >>= nTemp) ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_Endsync ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ENDSYNC, sTmp.makeStringAndClear() ); + } + + sal_Int16 nContainerNodeType = EffectNodeType::DEFAULT; + OUString aPresetId; + const Sequence< NamedValue > aUserData( xNode->getUserData() ); + for( const auto& rValue : aUserData ) + { + if( IsXMLToken( rValue.Name, XML_NODE_TYPE ) ) + { + if( (rValue.Value >>= nContainerNodeType) && (nContainerNodeType != EffectNodeType::DEFAULT) ) + { + SvXMLUnitConverter::convertEnum( sTmp, nContainerNodeType, aAnimations_EnumMap_EffectNodeType ); + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_NODE_TYPE, sTmp.makeStringAndClear() ); + } + } + else if( IsXMLToken( rValue.Name, XML_PRESET_ID ) ) + { + if( rValue.Value >>= aPresetId ) + { + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PRESET_ID, aPresetId ); + } + } + else if( IsXMLToken( rValue.Name, XML_PRESET_SUB_TYPE ) ) + { + OUString aPresetSubType; + if( rValue.Value >>= aPresetSubType ) + { + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PRESET_SUB_TYPE, aPresetSubType ); + } + } + else if( IsXMLToken( rValue.Name, XML_PRESET_CLASS ) ) + { + sal_Int16 nEffectPresetClass = sal_uInt16(); + if( rValue.Value >>= nEffectPresetClass ) + { + SvXMLUnitConverter::convertEnum( sTmp, nEffectPresetClass, aAnimations_EnumMap_EffectPresetClass ); + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PRESET_CLASS, sTmp.makeStringAndClear() ); + } + } + else if( IsXMLToken( rValue.Name, XML_MASTER_ELEMENT ) ) + { + Reference< XInterface > xMaster; + rValue.Value >>= xMaster; + if( xMaster.is() ) + { + const OUString& rIdentifier = mxExport->getInterfaceToIdentifierMapper().getIdentifier(xMaster); + if( !rIdentifier.isEmpty() ) + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_MASTER_ELEMENT, rIdentifier ); + } + } + else if( IsXMLToken( rValue.Name, XML_GROUP_ID ) ) + { + sal_Int32 nGroupId = 0; + if( rValue.Value >>= nGroupId ) + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, XML_GROUP_ID, OUString::number( nGroupId ) ); + } + else + { + OUString aTmp; + if( rValue.Value >>= aTmp ) + mxExport->AddAttribute( XML_NAMESPACE_PRESENTATION, rValue.Name, aTmp ); + } + } + + nTemp = xNode->getType(); + switch( nTemp ) + { + case AnimationNodeType::PAR: + case AnimationNodeType::SEQ: + case AnimationNodeType::ITERATE: + { + Reference< XTimeContainer > xContainer( xNode, UNO_QUERY_THROW ); + exportContainer( xContainer, nContainerNodeType ); + } + break; + + case AnimationNodeType::ANIMATE: + case AnimationNodeType::SET: + case AnimationNodeType::ANIMATEMOTION: + case AnimationNodeType::ANIMATEPHYSICS: + case AnimationNodeType::ANIMATECOLOR: + case AnimationNodeType::ANIMATETRANSFORM: + case AnimationNodeType::TRANSITIONFILTER: + { + Reference< XAnimate > xAnimate( xNode, UNO_QUERY_THROW ); + exportAnimate( xAnimate ); + } + break; + case AnimationNodeType::AUDIO: + { + Reference< XAudio > xAudio( xNode, UNO_QUERY_THROW ); + exportAudio( xAudio ); + } + break; + case AnimationNodeType::COMMAND: + { + Reference< XCommand > xCommand( xNode, UNO_QUERY_THROW ); + exportCommand( xCommand ); + } + break; + default: + OSL_FAIL( "xmloff::AnimationsExporterImpl::exportNode(), invalid AnimationNodeType!" ); + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + + // if something goes wrong, its always a good idea to clear the attribute list + mxExport->ClearAttrList(); +} + +void AnimationsExporterImpl::exportContainer( const Reference< XTimeContainer >& xContainer, sal_Int16 nContainerNodeType ) +{ + try + { + const sal_Int32 nNodeType = xContainer->getType(); + + if( nNodeType == AnimationNodeType::ITERATE ) + { + OUStringBuffer sTmp; + Reference< XIterateContainer > xIter( xContainer, UNO_QUERY_THROW ); + + Any aTemp( xIter->getTarget() ); + if( aTemp.hasValue() ) + { + convertTarget( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TARGETELEMENT, sTmp.makeStringAndClear() ); + } + + sal_Int16 nTemp = xIter->getSubItem(); + if( nTemp ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_SubItem ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_SUB_ITEM, sTmp.makeStringAndClear() ); + } + + nTemp = xIter->getIterateType(); + if( nTemp ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_IterateType ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_ITERATE_TYPE, sTmp.makeStringAndClear() ); + } + + double fTemp = xIter->getIterateInterval(); + if( fTemp ) + { + OUStringBuffer buf; + ::sax::Converter::convertDuration(buf, fTemp / (24*60*60)); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, + XML_ITERATE_INTERVAL, buf.makeStringAndClear()); + } + } + + XMLTokenEnum eElementToken; + switch( nNodeType ) + { + case AnimationNodeType::PAR: eElementToken = XML_PAR; break; + case AnimationNodeType::SEQ: eElementToken = XML_SEQ; break; + case AnimationNodeType::ITERATE:eElementToken = XML_ITERATE; break; + default: + OSL_FAIL( "xmloff::AnimationsExporterImpl::exportContainer(), invalid TimeContainerType!" ); + return; + } + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, eElementToken, true, true ); + + if( nContainerNodeType == EffectNodeType::TIMING_ROOT ) + exportTransitionNode(); + + Reference< XEnumerationAccess > xEnumerationAccess( xContainer, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + while( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + exportNode( xChildNode ); + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::exportAnimate( const Reference< XAnimate >& xAnimate ) +{ + try + { + const sal_Int16 nNodeType = xAnimate->getType(); + + OUStringBuffer sTmp; + sal_Int16 nTemp; + bool bTemp; + + Any aTemp( xAnimate->getTarget() ); + if( aTemp.hasValue() ) + { + convertTarget( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TARGETELEMENT, sTmp.makeStringAndClear() ); + } + + nTemp = xAnimate->getSubItem(); + if( nTemp ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_SubItem ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_SUB_ITEM, sTmp.makeStringAndClear() ); + } + + XMLTokenEnum eAttributeName = XML_TOKEN_INVALID; + + if( nNodeType == AnimationNodeType::TRANSITIONFILTER ) + { + eAttributeName = XML_TRANSITIONFILTER; + } + else if( nNodeType == AnimationNodeType::ANIMATETRANSFORM ) + { + eAttributeName = XML_ANIMATETRANSFORM; + } + else if( nNodeType == AnimationNodeType::ANIMATEMOTION ) + { + eAttributeName = XML_ANIMATEMOTION; + } + else if( nNodeType == AnimationNodeType::ANIMATEPHYSICS ) + { + eAttributeName = XML_ANIMATEPHYSICS; + } + else + { + OUString sTemp( xAnimate->getAttributeName() ); + if( !sTemp.isEmpty() ) + { + const struct ImplAttributeNameConversion* p = getAnimationAttributeNamesConversionList(); + while( p->mpAPIName ) + { + if( sTemp.equalsAscii( p->mpAPIName ) ) + { + sTemp = GetXMLToken( p->meXMLToken ); + eAttributeName = p->meXMLToken; + break; + } + + p++; + } + + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ATTRIBUTENAME, sTemp ); + } + else + { + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ATTRIBUTENAME, "invalid" ); + } + } + + Sequence< Any > aValues( xAnimate->getValues() ); + if( aValues.hasElements() ) + { + aTemp <<= aValues; + convertValue( eAttributeName, sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_VALUES, sTmp.makeStringAndClear() ); + } + else + { + aTemp = xAnimate->getFrom(); + if( aTemp.hasValue() ) + { + convertValue( eAttributeName, sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FROM, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimate->getBy(); + if( aTemp.hasValue() ) + { + convertValue( eAttributeName, sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_BY, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimate->getTo(); + if( aTemp.hasValue() ) + { + convertValue( eAttributeName, sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TO, sTmp.makeStringAndClear() ); + } + } + + if(nNodeType != AnimationNodeType::SET) + { + const Sequence< double > aKeyTimes( xAnimate->getKeyTimes() ); + if( aKeyTimes.hasElements() ) + { + for( const auto& rKeyTime : aKeyTimes ) + { + if( !sTmp.isEmpty() ) + sTmp.append( ';' ); + + sTmp.append( rKeyTime ); + } + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_KEYTIMES, sTmp.makeStringAndClear() ); + } + + OUString sTemp( xAnimate->getFormula() ); + if( !sTemp.isEmpty() ) + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_FORMULA, sTemp ); + + if( (nNodeType != AnimationNodeType::TRANSITIONFILTER) && + (nNodeType != AnimationNodeType::AUDIO ) ) + { + // calcMode = "discrete | linear | paced | spline" + nTemp = xAnimate->getCalcMode(); + if( ((nNodeType == AnimationNodeType::ANIMATEMOTION ) && (nTemp != AnimationCalcMode::PACED)) || + ((nNodeType != AnimationNodeType::ANIMATEMOTION ) && (nTemp != AnimationCalcMode::LINEAR)) ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_CalcMode ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_CALCMODE, sTmp.makeStringAndClear() ); + } + + bTemp = xAnimate->getAccumulate(); + if( bTemp ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ACCUMULATE, XML_SUM ); + + nTemp = xAnimate->getAdditive(); + if( nTemp != AnimationAdditiveMode::REPLACE ) + { + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_AdditiveMode ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ADDITIVE, sTmp.makeStringAndClear() ); + } + } + + const Sequence< TimeFilterPair > aTimeFilter( xAnimate->getTimeFilter() ); + if( aTimeFilter.hasElements() ) + { + for( const auto& rPair : aTimeFilter ) + { + if( !sTmp.isEmpty() ) + sTmp.append( ';' ); + + sTmp.append(OUString::number(rPair.Time) + "," + OUString::number(rPair.Progress)); + } + + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_KEYSPLINES, sTmp.makeStringAndClear() ); + } + } + + XMLTokenEnum eElementToken = XML_ANIMATE; + + switch( nNodeType ) + { + case AnimationNodeType::ANIMATE: + eElementToken = XML_ANIMATE; + break; + + case AnimationNodeType::SET: + eElementToken = XML_SET; + break; + + case AnimationNodeType::ANIMATEMOTION: + { + eElementToken = XML_ANIMATEMOTION; + + Reference< XAnimateMotion > xAnimateMotion( xAnimate, UNO_QUERY_THROW ); + + aTemp = xAnimateMotion->getPath(); + if( aTemp.hasValue() ) + { + convertPath( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SVG, XML_PATH, sTmp.makeStringAndClear() ); + } + + // TODO: origin = ( parent | layout ) + aTemp = xAnimateMotion->getOrigin(); + } + break; + + case AnimationNodeType::ANIMATEPHYSICS: + { + eElementToken = XML_ANIMATEPHYSICS; + double fTemp = 0; + + Reference< XAnimatePhysics > xAnimatePhysics( xAnimate, UNO_QUERY_THROW ); + aTemp = xAnimatePhysics->getStartVelocityX(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_X, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimatePhysics->getStartVelocityY(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_Y, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimatePhysics->getDensity(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_DENSITY, sTmp.makeStringAndClear() ); + } + + aTemp = xAnimatePhysics->getBounciness(); + if( aTemp.hasValue() ) + { + aTemp >>= fTemp; + ::sax::Converter::convertDouble( sTmp, fTemp ); + mxExport->AddAttribute( XML_NAMESPACE_LO_EXT, XML_PHYSICS_ANIMATION_BOUNCINESS, sTmp.makeStringAndClear() ); + } + } + break; + + case AnimationNodeType::ANIMATECOLOR: + { + eElementToken = XML_ANIMATECOLOR; + + Reference< XAnimateColor > xAnimateColor( xAnimate, UNO_QUERY_THROW ); + + nTemp = xAnimateColor->getColorInterpolation(); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_COLOR_INTERPOLATION, (nTemp == AnimationColorSpace::RGB) ? XML_RGB : XML_HSL ); + + bTemp = xAnimateColor->getDirection(); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_COLOR_INTERPOLATION_DIRECTION, bTemp ? XML_CLOCKWISE : XML_COUNTER_CLOCKWISE ); + } + break; + + case AnimationNodeType::ANIMATETRANSFORM: + { + eElementToken = XML_ANIMATETRANSFORM; + + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_ATTRIBUTENAME, XML_TRANSFORM ); + + Reference< XAnimateTransform > xTransform( xAnimate, UNO_QUERY_THROW ); + nTemp = xTransform->getTransformType(); + SvXMLUnitConverter::convertEnum( sTmp, nTemp, aAnimations_EnumMap_TransformType ); + mxExport->AddAttribute( XML_NAMESPACE_SVG, XML_TYPE, sTmp.makeStringAndClear() ); + } + break; + + case AnimationNodeType::TRANSITIONFILTER: + { + Reference< XTransitionFilter > xTransitionFilter( xAnimate, UNO_QUERY ); + eElementToken = XML_TRANSITIONFILTER; + + sal_Int16 nTransition = xTransitionFilter->getTransition(); + SvXMLUnitConverter::convertEnum( sTmp, nTransition, aAnimations_EnumMap_TransitionType ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TYPE, sTmp.makeStringAndClear() ); + + sal_Int16 nSubtype = xTransitionFilter->getSubtype(); + if( nSubtype != TransitionSubType::DEFAULT ) + { + SvXMLUnitConverter::convertEnum( sTmp, nSubtype, aAnimations_EnumMap_TransitionSubType ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_SUBTYPE, sTmp.makeStringAndClear() ); + } + + bTemp = xTransitionFilter->getMode(); + if( !bTemp ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_MODE, XML_OUT ); + + bTemp = xTransitionFilter->getDirection(); + if( !bTemp ) + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_DIRECTION, XML_REVERSE ); + + if( (nTransition == TransitionType::FADE) && ((nSubtype == TransitionSubType::FADETOCOLOR) || (nSubtype == TransitionSubType::FADEFROMCOLOR) )) + { + nTemp = xTransitionFilter->getFadeColor(); + ::sax::Converter::convertColor( sTmp, nTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_FADECOLOR, sTmp.makeStringAndClear() ); + } + } + break; + } + + if( eElementToken == XML_ANIMATEPHYSICS ) // not a standard should use the extension namespace + { + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_LO_EXT, eElementToken, true, true ); + } + else + { + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, eElementToken, true, true ); + } + + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::exportAudio( const Reference< XAudio >& xAudio ) +{ + if( !xAudio.is() ) + return; + + try + { + OUString aSourceURL; + xAudio->getSource() >>= aSourceURL; + if( !aSourceURL.isEmpty() ) + mxExport->AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, mxExport->GetRelativeReference( aSourceURL ) ); + + const double fVolume = xAudio->getVolume(); + if( fVolume != 1.0 ) + { + OUStringBuffer sTmp; + ::sax::Converter::convertDouble( sTmp, fVolume ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_AUDIO_LEVEL, sTmp.makeStringAndClear() ); + } + + /* todo? + sal_Int32 nEndAfterSlide = 0; + xAudio->getEndAfterSlide() >>= nEndAfterSlide; + if( nEndAfterSlide != 0 ) + mxExport->AddAttribute( ); + */ + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, XML_AUDIO, true, true ); + + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporterImpl::exportCommand( const Reference< XCommand >& xCommand ) +{ + if( !xCommand.is() ) + return; + + try + { + OUStringBuffer sTmp; + Any aTemp( xCommand->getTarget() ); + if( aTemp.hasValue() ) + { + convertTarget( sTmp, aTemp ); + mxExport->AddAttribute( XML_NAMESPACE_SMIL, XML_TARGETELEMENT, sTmp.makeStringAndClear() ); + } + + sal_Int16 nCommand = xCommand->getCommand(); + SvXMLUnitConverter::convertEnum( sTmp, nCommand, aAnimations_EnumMap_Command ); + mxExport->AddAttribute( XML_NAMESPACE_ANIMATION, XML_COMMAND, sTmp.makeStringAndClear() ); + + // todo virtual css::uno::Any SAL_CALL getParameter() throw (css::uno::RuntimeException) = 0; + + SvXMLElementExport aElement( *mxExport, XML_NAMESPACE_ANIMATION, XML_COMMAND, true, true ); + + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +Reference< XInterface > AnimationsExporterImpl::getParagraphTarget( const ParagraphTarget& pTarget ) +{ + try + { + Reference< XEnumerationAccess > xParaEnumAccess( pTarget.Shape, UNO_QUERY_THROW ); + + Reference< XEnumeration > xEnumeration( xParaEnumAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + sal_Int32 nParagraph = pTarget.Paragraph; + + while( xEnumeration->hasMoreElements() ) + { + Reference< XInterface > xRef( xEnumeration->nextElement(), UNO_QUERY ); + if( nParagraph-- == 0 ) + return xRef; + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + + Reference< XInterface > xRef; + return xRef; +} + +void AnimationsExporterImpl::convertPath( OUStringBuffer& sTmp, const Any& rPath ) +{ + OUString aStr; + rPath >>= aStr; + + sTmp = aStr; +} + +void AnimationsExporterImpl::convertValue( XMLTokenEnum eAttributeName, OUStringBuffer& sTmp, const Any& rValue ) const +{ + if( !rValue.hasValue() ) + return; + + if( auto pValuePair = o3tl::tryAccess(rValue) ) + { + OUStringBuffer sTmp2; + convertValue( eAttributeName, sTmp, pValuePair->First ); + sTmp.append( ',' ); + convertValue( eAttributeName, sTmp2, pValuePair->Second ); + sTmp.append( sTmp2 ); + } + else if( auto pSequence = o3tl::tryAccess>(rValue) ) + { + const sal_Int32 nLength = pSequence->getLength(); + sal_Int32 nElement; + const Any* pAny = pSequence->getConstArray(); + + OUStringBuffer sTmp2; + + for( nElement = 0; nElement < nLength; nElement++, pAny++ ) + { + if( !sTmp.isEmpty() ) + sTmp.append( ';' ); + convertValue( eAttributeName, sTmp2, *pAny ); + sTmp.append( sTmp2 ); + sTmp2.setLength(0); + } + } + else + { + sal_Int32 nType; + + switch( eAttributeName ) + { + case XML_X: + case XML_Y: + case XML_WIDTH: + case XML_HEIGHT: + case XML_ANIMATETRANSFORM: + case XML_ANIMATEMOTION: + case XML_ANIMATEPHYSICS: + { + if( auto aString = o3tl::tryAccess(rValue) ) + { + sTmp.append( *aString ); + } + else if( auto x = o3tl::tryAccess(rValue) ) + { + sTmp.append( *x ); + } + else + { + OSL_FAIL( "xmloff::AnimationsExporterImpl::convertValue(), invalid value type!" ); + } + return; + } + + case XML_SKEWX: + case XML_ROTATE: nType = XML_TYPE_DOUBLE; break; + case XML_TEXT_ROTATION_ANGLE: nType = XML_TYPE_NUMBER16; break; + case XML_FILL_COLOR: + case XML_STROKE_COLOR: + case XML_DIM: + case XML_COLOR: nType = XML_TYPE_COLOR; break; + case XML_FILL: nType = XML_SD_TYPE_FILLSTYLE; break; + case XML_STROKE: nType = XML_SD_TYPE_STROKE; break; + case XML_FONT_WEIGHT: nType = XML_TYPE_TEXT_WEIGHT; break; + case XML_FONT_STYLE: nType = XML_TYPE_TEXT_POSTURE; break; + case XML_TEXT_UNDERLINE: nType = XML_TYPE_TEXT_UNDERLINE_STYLE; break; + case XML_FONT_SIZE: nType = XML_TYPE_DOUBLE_PERCENT; break; + case XML_VISIBILITY: nType = XML_SD_TYPE_PRESPAGE_VISIBILITY; break; + case XML_OPACITY: + case XML_TRANSITIONFILTER: nType = XML_TYPE_DOUBLE; break; + default: + OSL_FAIL( "xmloff::AnimationsExporterImpl::convertValue(), invalid AttributeName!" ); + nType = XML_TYPE_STRING; + } + + //const XMLPropertyHandler* pHandler = static_cast(&mrExport)->GetSdPropHdlFactory()->GetPropertyHandler( nType ); + const XMLPropertyHandler* pHandler = mxSdPropHdlFactory->GetPropertyHandler( nType ); + if( pHandler ) + { + OUString aString; + pHandler->exportXML( aString, rValue, mxExport->GetMM100UnitConverter() ); + sTmp.append( aString ); + } + } +} + +void AnimationsExporterImpl::convertTiming( OUStringBuffer& sTmp, const Any& rValue ) const +{ + if( !rValue.hasValue() ) + return; + + if( auto pSequence = o3tl::tryAccess>(rValue) ) + { + const sal_Int32 nLength = pSequence->getLength(); + sal_Int32 nElement; + const Any* pAny = pSequence->getConstArray(); + + OUStringBuffer sTmp2; + + for( nElement = 0; nElement < nLength; nElement++, pAny++ ) + { + if( !sTmp.isEmpty() ) + sTmp.append( ';' ); + convertTiming( sTmp2, *pAny ); + sTmp.append( sTmp2 ); + sTmp2.setLength(0); + } + } + else if( auto x = o3tl::tryAccess(rValue) ) + { + sTmp.append( *x ); + sTmp.append( 's'); + } + else if( auto pTiming = o3tl::tryAccess(rValue) ) + { + sTmp.append( GetXMLToken( (*pTiming == Timing_MEDIA) ? XML_MEDIA : XML_INDEFINITE ) ); + } + else if( auto pEvent = o3tl::tryAccess(rValue) ) + { + OUStringBuffer sTmp2; + + if( pEvent->Trigger != EventTrigger::NONE ) + { + if( pEvent->Source.hasValue() ) + { + convertTarget( sTmp, pEvent->Source ); + sTmp.append( '.' ); + } + + SvXMLUnitConverter::convertEnum( sTmp2, pEvent->Trigger, aAnimations_EnumMap_EventTrigger ); + + sTmp.append( sTmp2 ); + sTmp2.setLength(0); + } + + if( pEvent->Offset.hasValue() ) + { + convertTiming( sTmp2, pEvent->Offset ); + + if( !sTmp.isEmpty() ) + sTmp.append( '+' ); + + sTmp.append( sTmp2 ); + sTmp2.setLength(0); + } + } + else + { + OSL_FAIL( "xmloff::AnimationsExporterImpl::convertTiming(), invalid value type!" ); + } +} + +void AnimationsExporterImpl::convertTarget( OUStringBuffer& sTmp, const Any& rTarget ) const +{ + if( !rTarget.hasValue() ) + return; + + Reference< XInterface > xRef; + + if( !(rTarget >>= xRef) ) + { + if( auto pt = o3tl::tryAccess(rTarget) ) + { + xRef = getParagraphTarget( *pt ); + } + } + + SAL_WARN_IF( !xRef.is(), "xmloff", "xmloff::AnimationsExporterImpl::convertTarget(), invalid target type!" ); + if( xRef.is() ) + { + const OUString& rIdentifier = mxExport->getInterfaceToIdentifierMapper().getIdentifier(xRef); + if( !rIdentifier.isEmpty() ) + sTmp.append( rIdentifier ); + } +} + +void AnimationsExporterImpl::prepareValue( const Any& rValue ) +{ + if( !rValue.hasValue() ) + return; + + if( auto pValuePair = o3tl::tryAccess(rValue) ) + { + prepareValue( pValuePair->First ); + prepareValue( pValuePair->Second ); + } + else if( auto pSequence = o3tl::tryAccess>(rValue) ) + { + const sal_Int32 nLength = pSequence->getLength(); + sal_Int32 nElement; + const Any* pAny = pSequence->getConstArray(); + + for( nElement = 0; nElement < nLength; nElement++, pAny++ ) + prepareValue( *pAny ); + } + else if( rValue.getValueTypeClass() == css::uno::TypeClass_INTERFACE ) + { + Reference< XInterface> xRef( rValue, UNO_QUERY ); + if( xRef.is() ) + mxExport->getInterfaceToIdentifierMapper().registerReference( xRef ); + } + else if( auto pt = o3tl::tryAccess(rValue) ) + { + Reference< XInterface> xRef( getParagraphTarget( *pt ) ); + if( xRef.is() ) + mxExport->getInterfaceToIdentifierMapper().registerReference( xRef ); + } + else if( auto pEvent = o3tl::tryAccess(rValue) ) + { + prepareValue( pEvent->Source ); + } +} + +AnimationsExporter::AnimationsExporter( SvXMLExport& rExport, const Reference< XPropertySet >& xPageProps ) + : mpImpl( new AnimationsExporterImpl( rExport, xPageProps ) ) +{ +} + +AnimationsExporter::~AnimationsExporter() +{ +} + +void AnimationsExporter::prepare( const Reference< XAnimationNode >& xRootNode ) +{ + try + { + if( xRootNode.is() ) + { + mpImpl->prepareTransitionNode(); + mpImpl->prepareNode( xRootNode ); + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationsExporter::exportAnimations( const Reference< XAnimationNode >& xRootNode ) +{ + try + { + if( xRootNode.is() ) + { + bool bHasEffects = mpImpl->mbHasTransition; + + if( !bHasEffects ) + { + // first check if there are no animations + Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + if( xEnumeration->hasMoreElements() ) + { + // first child node may be an empty main sequence, check this + Reference< XAnimationNode > xMainNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + Reference< XEnumerationAccess > xMainEnumerationAccess( xMainNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xMainEnumeration( xMainEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW ); + + // only export if the main sequence is not empty or if there are additional + // trigger sequences + bHasEffects = xMainEnumeration->hasMoreElements() || xEnumeration->hasMoreElements(); + } + } + + if( bHasEffects ) + mpImpl->exportNode( xRootNode ); + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/animationimport.cxx b/xmloff/source/draw/animationimport.cxx new file mode 100644 index 000000000..826b4b0a0 --- /dev/null +++ b/xmloff/source/draw/animationimport.cxx @@ -0,0 +1,1357 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include "sdpropls.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::animations; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::beans::NamedValue; +using ::com::sun::star::text::XTextRange; +using ::com::sun::star::text::XTextCursor; +using ::com::sun::star::text::XTextRangeCompare; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; +using ::com::sun::star::lang::XInitialization; + +static OUString +lcl_GetMediaReference(SvXMLImport const& rImport, OUString const& rURL) +{ + if (rImport.IsPackageURL(rURL)) + return "vnd.sun.star.Package:" + rURL; + + return rImport.GetAbsoluteReference(rURL); +} + +namespace xmloff +{ + +class AnimationsImportHelperImpl +{ +private: + SvXMLImport& mrImport; + +public: + explicit AnimationsImportHelperImpl( SvXMLImport& rImport ); + + Any convertValue( XMLTokenEnum eAttributeName, const OUString& rValue ); + Sequence< Any > convertValueSequence( XMLTokenEnum eAttributeName, std::u16string_view rValue ); + + Any convertTarget( const OUString& rValue ); + static Any convertPath( const OUString& rValue ); + Any convertTiming( const OUString& rValue ); + static Sequence< double > convertKeyTimes( std::string_view rValue ); + static Sequence< TimeFilterPair > convertTimeFilter( std::string_view rValue ); +}; + +AnimationsImportHelperImpl::AnimationsImportHelperImpl( SvXMLImport& rImport ) +: mrImport( rImport ) +{ +} + +static bool isDouble( std::string_view rValue ) +{ + sal_Int32 nLength = rValue.size(); + const char * pStr = rValue.data(); + while( nLength ) + { + if( (*pStr >= '0' && *pStr <= '9') || *pStr == '-' || *pStr == '.' || *pStr == '+' || *pStr == 'e' || *pStr == 'E' ) + { + pStr++; + nLength--; + } + else + { + return false; + } + } + + return true; +} + +static bool isTime( const OUString& rValue ) +{ + sal_Int32 nLength = rValue.getLength(); + const sal_Unicode * pStr; + for( pStr = rValue.getStr(); nLength; pStr++, nLength-- ) + { + if( !( (*pStr >= '0' && *pStr <= '9') || *pStr == '-' || *pStr == '.' || *pStr == '+' || *pStr == 'e' || *pStr == 'E' ) ) + break; + } + + // return true if this is a double (if someone forgot the 's' we silently ignore it) + // or if it's a double that ends with a 's' or 'S' + return (nLength == 0) || ((*pStr == 's' || *pStr == 'S') && (nLength == 1)); +} + +Any AnimationsImportHelperImpl::convertTarget( const OUString& rValue ) +{ + try + { + Reference< XInterface > xRef( mrImport.getInterfaceToIdentifierMapper().getReference( rValue ) ); + + Reference< XShape > _xShape( xRef, UNO_QUERY ); + if( _xShape.is() ) + return Any( _xShape ); + + Reference< XTextCursor > xTextCursor( xRef, UNO_QUERY ); + if( xTextCursor.is() ) + { + Reference< XTextRange > xStart( xTextCursor->getStart() ), xRange; + Reference< XShape > xShape( xTextCursor->getText(), UNO_QUERY_THROW ); + Reference< XTextRangeCompare > xTextRangeCompare( xShape, UNO_QUERY_THROW ); + + Reference< XEnumerationAccess > xParaEnumAccess( xShape, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xParaEnumAccess->createEnumeration(), UNO_SET_THROW ); + sal_Int16 nParagraph = 0; + + while( xEnumeration->hasMoreElements() ) + { + xEnumeration->nextElement() >>= xRange; + + // break if start of selection is prior to end of current paragraph + if( xRange.is() && (xTextRangeCompare->compareRegionEnds( xStart, xRange ) >= 0 ) ) + { + return Any( ParagraphTarget( xShape, nParagraph ) ); + } + + nParagraph++; + } + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + + Any aAny; + return aAny; +} + +Any AnimationsImportHelperImpl::convertValue( XMLTokenEnum eAttributeName, const OUString& rValue ) +{ + sal_Int32 nCommaPos = -1, nPos; + sal_Int32 nOpenBrackets = 0; + for( nPos = 0; (nPos < rValue.getLength()) && (nCommaPos == -1); nPos++ ) + { + switch( rValue[nPos] ) + { + case ',': + if( nOpenBrackets == 0 ) + nCommaPos = nPos; + break; + case '(': + case '[': + case '{': + nOpenBrackets++; + break; + case ')': + case ']': + case '}': + nOpenBrackets--; + break; + } + } + + if( nCommaPos >= 0 ) + { + ValuePair aPair; + aPair.First = convertValue( eAttributeName, rValue.copy( 0, nCommaPos ) ); + aPair.Second = convertValue( eAttributeName, rValue.copy( nCommaPos+1 ) ); + return Any( aPair ); + } + else + { + Any aAny; + sal_Int32 nType = XML_TYPE_STRING; + + if( rValue.getLength() ) switch( eAttributeName ) + { + case XML_X: + case XML_Y: + case XML_WIDTH: + case XML_HEIGHT: + case XML_TRANSLATE: + { + return Any( rValue ); + } + + case XML_SCALE: + case XML_SKEWY: + case XML_SKEWX: + case XML_OPACITY: + case XML_ROTATE: nType = XML_TYPE_DOUBLE; break; + case XML_TEXT_ROTATION_ANGLE:nType = XML_TYPE_TEXT_ROTATION_ANGLE; break; + case XML_FILL_COLOR: + case XML_STROKE_COLOR: + case XML_DIM: + case XML_COLOR: nType = XML_TYPE_COLOR; break; + case XML_FILL: nType = XML_SD_TYPE_FILLSTYLE; break; + case XML_STROKE: nType = XML_SD_TYPE_STROKE; break; + case XML_FONT_WEIGHT: nType = XML_TYPE_TEXT_WEIGHT; break; + case XML_FONT_STYLE: nType = XML_TYPE_TEXT_POSTURE; break; + case XML_TEXT_UNDERLINE: nType = XML_TYPE_TEXT_UNDERLINE_STYLE; break; + case XML_FONT_SIZE: nType = XML_TYPE_DOUBLE_PERCENT; break; + case XML_VISIBILITY: nType = XML_SD_TYPE_PRESPAGE_VISIBILITY; break; + + default: + if( !rValue.isEmpty() ) + aAny <<= rValue; + return aAny; + } + + const XMLPropertyHandler* pHandler = mrImport.GetShapeImport()->GetSdPropHdlFactory()->GetPropertyHandler( nType ); + if( pHandler ) + pHandler->importXML( rValue, aAny, mrImport.GetMM100UnitConverter() ); + + return aAny; + } +} + +Sequence< Any > AnimationsImportHelperImpl::convertValueSequence( XMLTokenEnum eAttributeName, std::u16string_view rValue ) +{ + Sequence< Any > aValues; + + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + if ( nElements>0 ) + { + // prepare the sequence + aValues.realloc( nElements ); + + // fill the sequence + Any* pValues = aValues.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + *pValues++ = convertValue( eAttributeName, OUString(o3tl::getToken(rValue, 0, ';', nIndex )) ); + } + + return aValues; +} + +Any AnimationsImportHelperImpl::convertTiming( const OUString& rValue ) +{ + Any aAny; + + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + if ( nElements>0 ) + { + if( nElements == 1 ) + { + if( IsXMLToken( rValue, XML_MEDIA ) ) + { + aAny <<= Timing_MEDIA; + } + else if( IsXMLToken( rValue, XML_INDEFINITE ) ) + { + aAny <<= Timing_INDEFINITE; + } + else if( isTime( rValue ) ) + { + aAny <<= rValue.toDouble(); + } + else + { + Event aEvent; + aEvent.Repeat = 0; + aEvent.Trigger = 0; + + OUString aEventTrigger; + + sal_Int32 nPos = rValue.indexOf( '+' ); + if( nPos == -1 ) + { + aEventTrigger = rValue; + } + else + { + aEventTrigger = rValue.copy( 0, nPos ); + + // convert offset + aEvent.Offset = convertTiming( rValue.copy( nPos + 1 ) ); + } + + nPos = aEventTrigger.indexOf( '.' ); + if( nPos != -1 ) + { + aEvent.Source <<= mrImport.getInterfaceToIdentifierMapper().getReference( aEventTrigger.copy( 0, nPos ) ); + aEventTrigger = aEventTrigger.copy( nPos + 1 ); + } + + sal_Int16 nEnum; + if( SvXMLUnitConverter::convertEnum( nEnum, aEventTrigger, aAnimations_EnumMap_EventTrigger ) ) + { + aEvent.Trigger = nEnum; + } + else + { + OSL_FAIL("AnimationsImportHelperImpl::convertTiming(), unknown event trigger!"); + } + + aAny <<= aEvent; + } + } + else + { + // fill the sequence + Sequence< Any > aValues( nElements ); + Any* pValues = aValues.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + *pValues++ = convertTiming( rValue.getToken( 0, ';', nIndex ) ); + + aAny <<= aValues; + } + } + return aAny; +} + +Sequence< double > AnimationsImportHelperImpl::convertKeyTimes( std::string_view rValue ) +{ + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + + Sequence< double > aKeyTimes( nElements ); + + if( nElements ) + { + double* pValues = aKeyTimes.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + *pValues++ = o3tl::toDouble(o3tl::getToken(rValue, 0, ';', nIndex )); + } + + return aKeyTimes; +} + +Sequence< TimeFilterPair > AnimationsImportHelperImpl::convertTimeFilter( std::string_view rValue ) +{ + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + + Sequence< TimeFilterPair > aTimeFilter( nElements ); + + if( nElements ) + { + TimeFilterPair* pValues = aTimeFilter.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + { + const std::string_view aToken( o3tl::getToken(rValue, 0, ';', nIndex ) ); + + size_t nPos = aToken.find( ',' ); + if( nPos != std::string_view::npos ) + { + pValues->Time = rtl_math_stringToDouble( + aToken.data(), aToken.data() + nPos, '.', 0, nullptr, nullptr); + pValues->Progress = rtl_math_stringToDouble( + aToken.data() + nPos + 1, aToken.data() + aToken.size(), '.', 0, + nullptr, nullptr); + } + pValues++; + } + } + + return aTimeFilter; +} + +Any AnimationsImportHelperImpl::convertPath( const OUString& rValue ) +{ + return Any( rValue ); +} + + +AnimationNodeContext::AnimationNodeContext( + const Reference< XAnimationNode >& xParentNode, + SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + const std::shared_ptr& pHelper ) +: SvXMLImportContext(rImport), + mpHelper( pHelper ) +{ + bool bRootContext = !pHelper; + try + { + if( bRootContext ) + { + mpHelper = std::make_shared( rImport ); + mxNode = xParentNode; + } + else + { + sal_Int16 nPresetClass = EffectPresetClass::CUSTOM; + + const char* pServiceName = nullptr; + + // we see namespace ANIMATION and ANIMATION_OOO and PRESENTATION_OASIS and PRESENTATION_SO52 and PRESENTATION_OOO + switch( nElement & TOKEN_MASK ) + { + case XML_SEQ: + pServiceName = "com.sun.star.animations.SequenceTimeContainer"; break; + case XML_ITERATE: + pServiceName = "com.sun.star.animations.IterateContainer"; break; + case XML_ANIMATE: + pServiceName = "com.sun.star.animations.Animate"; break; + case XML_SET: + pServiceName = "com.sun.star.animations.AnimateSet"; break; + case XML_ANIMATEMOTION: + pServiceName = "com.sun.star.animations.AnimateMotion"; break; + case XML_ANIMATEPHYSICS: + pServiceName = "com.sun.star.animations.AnimatePhysics"; break; + case XML_ANIMATECOLOR: + pServiceName = "com.sun.star.animations.AnimateColor"; break; + case XML_ANIMATETRANSFORM: + pServiceName = "com.sun.star.animations.AnimateTransform"; break; + case XML_TRANSITIONFILTER: + pServiceName = "com.sun.star.animations.TransitionFilter"; break; + case XML_AUDIO: + pServiceName = "com.sun.star.animations.Audio"; break; + case XML_COMMAND: + pServiceName = "com.sun.star.animations.Command"; break; + case XML_PAR: + { + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( (aIter.getToken() & TOKEN_MASK) == XML_PRESET_ID) + { + const OUString& rValue = aIter.toString(); + if ( rValue == "ooo-entrance-random" ) + { + nPresetClass = EffectPresetClass::ENTRANCE; + } + else if ( rValue == "ooo-exit-random" ) + { + nPresetClass = EffectPresetClass::EXIT; + } + + if( nPresetClass != EffectPresetClass::CUSTOM ) + { + pServiceName = "com.sun.star.comp.sd.RandomAnimationNode"; + break; + } + } + } + if( !pServiceName ) + pServiceName = "com.sun.star.animations.ParallelTimeContainer"; + } + break; + default: + SAL_WARN("xmloff", "unexpected token '" + SvXMLImport::getNameFromToken(nElement) + << "' 0x" << std::hex << nElement); + break; + } + + if( pServiceName ) + { + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + + mxNode.set( + xContext->getServiceManager()->createInstanceWithContext(OUString::createFromAscii(pServiceName), xContext), + UNO_QUERY_THROW ); + + if( nPresetClass != EffectPresetClass::CUSTOM ) + { + Reference< XInitialization > xInit( mxNode, UNO_QUERY_THROW ); + const Any aAny( nPresetClass ); + Sequence< Any > aArgs( &aAny, 1 ) ; + xInit->initialize( aArgs ); + } + + init_node( xAttrList ); + + Reference< XTimeContainer > xParentContainer( xParentNode, UNO_QUERY_THROW ); + xParentContainer->appendChild( mxNode ); + } + } + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void AnimationNodeContext::init_node( const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( !mxNode.is() ) + return; + + try + { + const sal_Int16 nNodeType = mxNode->getType(); + + // query for optional interfaces that are often used later + Reference< XAnimate > xAnimate( mxNode, UNO_QUERY ); + Reference< XCommand > xCommand( mxNode, UNO_QUERY ); + Reference< XTransitionFilter > xTransitionFilter( mxNode, UNO_QUERY ); + Reference< XIterateContainer > xIter( mxNode, UNO_QUERY ); + + std::vector< NamedValue > aUserData; + XMLTokenEnum meAttributeName = XML_TOKEN_INVALID; + OUString aFrom, aBy, aTo, aValues; + bool bHaveXmlId( false ); + OUString sXmlId; + + sal_Int16 nEnum; + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + auto nToken = aIter.getToken(); + switch( nToken ) + { + case XML_ELEMENT(SMIL, XML_BEGIN): + case XML_ELEMENT(SMIL_COMPAT, XML_BEGIN): + case XML_ELEMENT(SMIL_SO52, XML_BEGIN): + { + mxNode->setBegin( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_DUR): + case XML_ELEMENT(SMIL_COMPAT, XML_DUR): + case XML_ELEMENT(SMIL_SO52, XML_DUR): + { + mxNode->setDuration( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_END): + case XML_ELEMENT(SMIL_COMPAT, XML_END): + case XML_ELEMENT(SMIL_SO52, XML_END): + { + mxNode->setEnd( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_FILL): + case XML_ELEMENT(SMIL_COMPAT, XML_FILL): + case XML_ELEMENT(SMIL_SO52, XML_FILL): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_Fill ) ) + mxNode->setFill( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_FILLDEFAULT): + case XML_ELEMENT(SMIL_COMPAT, XML_FILLDEFAULT): + case XML_ELEMENT(SMIL_SO52, XML_FILLDEFAULT): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_FillDefault ) ) + mxNode->setFillDefault( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_RESTART): + case XML_ELEMENT(SMIL_COMPAT, XML_RESTART): + case XML_ELEMENT(SMIL_SO52, XML_RESTART): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_Restart ) ) + mxNode->setRestart( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_RESTARTDEFAULT): + case XML_ELEMENT(SMIL_COMPAT, XML_RESTARTDEFAULT): + case XML_ELEMENT(SMIL_SO52, XML_RESTARTDEFAULT): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_RestartDefault ) ) + mxNode->setRestartDefault( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_ACCELERATE): + case XML_ELEMENT(SMIL_COMPAT, XML_ACCELERATE): + case XML_ELEMENT(SMIL_SO52, XML_ACCELERATE): + { + if( isDouble( aIter.toView() ) ) + mxNode->setAcceleration( aIter.toDouble() ); + } + break; + case XML_ELEMENT(SMIL, XML_DECELERATE): + case XML_ELEMENT(SMIL_COMPAT, XML_DECELERATE): + case XML_ELEMENT(SMIL_SO52, XML_DECELERATE): + { + if( isDouble( aIter.toView() ) ) + mxNode->setDecelerate( aIter.toDouble() ); + } + break; + case XML_ELEMENT(SMIL, XML_AUTOREVERSE): + case XML_ELEMENT(SMIL_COMPAT, XML_AUTOREVERSE): + case XML_ELEMENT(SMIL_SO52, XML_AUTOREVERSE): + { + bool bTemp; + if (::sax::Converter::convertBool( bTemp, aIter.toView() )) + mxNode->setAutoReverse( bTemp ); + } + break; + case XML_ELEMENT(SMIL, XML_REPEATCOUNT): + case XML_ELEMENT(SMIL_COMPAT, XML_REPEATCOUNT): + case XML_ELEMENT(SMIL_SO52, XML_REPEATCOUNT): + { + mxNode->setRepeatCount( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_REPEATDUR): + case XML_ELEMENT(SMIL_COMPAT, XML_REPEATDUR): + case XML_ELEMENT(SMIL_SO52, XML_REPEATDUR): + { + mxNode->setRepeatDuration( mpHelper->convertTiming( aIter.toString() ) ); + } + break; + case XML_ELEMENT(SMIL, XML_ENDSYNC): + case XML_ELEMENT(SMIL_COMPAT, XML_ENDSYNC): + case XML_ELEMENT(SMIL_SO52, XML_ENDSYNC): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_Endsync ) ) + mxNode->setEndSync( Any( nEnum ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_NODE_TYPE): + case XML_ELEMENT(PRESENTATION_SO52, XML_NODE_TYPE): + case XML_ELEMENT(PRESENTATION_OOO, XML_NODE_TYPE): + case XML_ELEMENT(PRESENTATION_OASIS, XML_NODE_TYPE): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_EffectNodeType ) ) + aUserData.emplace_back( GetXMLToken( XML_NODE_TYPE ), Any( nEnum ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_PRESET_ID): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESET_ID): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESET_ID): + case XML_ELEMENT(PRESENTATION_OASIS, XML_PRESET_ID): + { + aUserData.emplace_back( GetXMLToken( XML_PRESET_ID ), Any( aIter.toString() ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_PRESET_SUB_TYPE): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESET_SUB_TYPE): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESET_SUB_TYPE): + case XML_ELEMENT(PRESENTATION_OASIS, XML_PRESET_SUB_TYPE): + { + aUserData.emplace_back( GetXMLToken( XML_PRESET_SUB_TYPE ), Any( aIter.toString() ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_PRESET_CLASS): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESET_CLASS): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESET_CLASS): + case XML_ELEMENT(PRESENTATION_OASIS, XML_PRESET_CLASS): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_EffectPresetClass ) ) + aUserData.emplace_back( GetXMLToken( XML_PRESET_CLASS ), Any( nEnum ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_AFTER_EFFECT): + case XML_ELEMENT(PRESENTATION_SO52, XML_AFTER_EFFECT): + case XML_ELEMENT(PRESENTATION_OOO, XML_AFTER_EFFECT): + { + bool bTemp; + if (::sax::Converter::convertBool( bTemp, aIter.toView() )) + aUserData.emplace_back( GetXMLToken( XML_AFTER_EFFECT ), Any( bTemp ) ); + } + break; + case XML_ELEMENT(XLINK, XML_HREF): + { + if( nNodeType == AnimationNodeType::AUDIO ) + { + Reference< XAudio > xAudio( mxNode, UNO_QUERY_THROW ); + xAudio->setSource( Any(lcl_GetMediaReference(GetImport(), aIter.toString())) ); + break; + } + [[fallthrough]]; + } + case XML_ELEMENT(SMIL, XML_TARGETELEMENT): + case XML_ELEMENT(SMIL_COMPAT, XML_TARGETELEMENT): + case XML_ELEMENT(SMIL_SO52, XML_TARGETELEMENT): + { + Any aTarget( mpHelper->convertTarget( aIter.toString() ) ); + + if( xAnimate.is() ) + { + xAnimate->setTarget( aTarget ); + } + else if( xIter.is() ) + { + xIter->setTarget( aTarget ); + } + else if( xCommand.is() ) + { + xCommand->setTarget( aTarget ); + } + } + break; + + case XML_ELEMENT(ANIMATION, XML_AUDIO_LEVEL): + case XML_ELEMENT(ANIMATION_OOO, XML_AUDIO_LEVEL): + { + if( nNodeType == AnimationNodeType::AUDIO ) + { + if( isDouble( aIter.toView() ) ) + { + Reference< XAudio > xAudio( mxNode, UNO_QUERY_THROW ); + xAudio->setVolume( aIter.toDouble() ); + } + } + } + break; + + case XML_ELEMENT(PRESENTATION, XML_MASTER_ELEMENT): + case XML_ELEMENT(PRESENTATION_SO52, XML_MASTER_ELEMENT): + case XML_ELEMENT(PRESENTATION_OOO, XML_MASTER_ELEMENT): + { + Reference< XAnimationNode > xMaster( GetImport().getInterfaceToIdentifierMapper().getReference( aIter.toString() ), UNO_QUERY ); + aUserData.emplace_back( GetXMLToken( XML_MASTER_ELEMENT ), Any( xMaster ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_SUB_ITEM): + case XML_ELEMENT(ANIMATION_OOO, XML_SUB_ITEM): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_SubItem ) ) + { + if( xAnimate.is() ) + { + xAnimate->setSubItem( nEnum ); + } + else if( xIter.is() ) + { + xIter->setSubItem( nEnum ); + } + } + } + break; + + case XML_ELEMENT(SMIL, XML_ATTRIBUTENAME): + case XML_ELEMENT(SMIL_COMPAT, XML_ATTRIBUTENAME): + case XML_ELEMENT(SMIL_SO52, XML_ATTRIBUTENAME): + { + if( xAnimate.is() ) + { + OUString aName( aIter.toString() ); + + const struct ImplAttributeNameConversion* p = getAnimationAttributeNamesConversionList(); + while( p->mpAPIName ) + { + if( IsXMLToken( aIter, p->meXMLToken ) ) + { + aName = OUString::createFromAscii( p->mpAPIName ); + meAttributeName = p->meXMLToken; + break; + } + + p++; + } + + xAnimate->setAttributeName( aName ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_VALUES): + case XML_ELEMENT(SMIL_COMPAT, XML_VALUES): + case XML_ELEMENT(SMIL_SO52, XML_VALUES): + { + aValues = aIter.toString(); + } + break; + + case XML_ELEMENT(SMIL, XML_FROM): + case XML_ELEMENT(SMIL_COMPAT, XML_FROM): + case XML_ELEMENT(SMIL_SO52, XML_FROM): + { + aFrom = aIter.toString(); + } + break; + + case XML_ELEMENT(SMIL, XML_BY): + case XML_ELEMENT(SMIL_COMPAT, XML_BY): + case XML_ELEMENT(SMIL_SO52, XML_BY): + { + aBy = aIter.toString(); + } + break; + + case XML_ELEMENT(SMIL, XML_TO): + case XML_ELEMENT(SMIL_COMPAT, XML_TO): + case XML_ELEMENT(SMIL_SO52, XML_TO): + { + aTo = aIter.toString(); + } + break; + + case XML_ELEMENT(SMIL, XML_KEYTIMES): + case XML_ELEMENT(SMIL_COMPAT, XML_KEYTIMES): + case XML_ELEMENT(SMIL_SO52, XML_KEYTIMES): + { + if( xAnimate.is() ) + xAnimate->setKeyTimes( AnimationsImportHelperImpl::convertKeyTimes( aIter.toView() ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_FORMULA): + case XML_ELEMENT(ANIMATION_OOO, XML_FORMULA): + { + if( xAnimate.is() ) + xAnimate->setFormula( aIter.toString() ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_ID): + case XML_ELEMENT(ANIMATION_OOO, XML_ID): + { + if (!bHaveXmlId) { sXmlId = aIter.toString(); } + } + break; + case XML_ELEMENT(XML, XML_ID): + { + sXmlId = aIter.toString(); + bHaveXmlId = true; + } + break; + + case XML_ELEMENT(SMIL, XML_CALCMODE): + case XML_ELEMENT(SMIL_COMPAT, XML_CALCMODE): + case XML_ELEMENT(SMIL_SO52, XML_CALCMODE): + { + if( xAnimate.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_CalcMode ) ) + xAnimate->setCalcMode( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_ACCUMULATE): + case XML_ELEMENT(SMIL_COMPAT, XML_ACCUMULATE): + case XML_ELEMENT(SMIL_SO52, XML_ACCUMULATE): + { + if( xAnimate.is() ) + xAnimate->setAccumulate( IsXMLToken( aIter, XML_SUM ) ); + } + break; + + case XML_ELEMENT(PRESENTATION, XML_ADDITIVE): + case XML_ELEMENT(PRESENTATION_SO52, XML_ADDITIVE): + case XML_ELEMENT(PRESENTATION_OOO, XML_ADDITIVE): + case XML_ELEMENT(SMIL, XML_ADDITIVE): + case XML_ELEMENT(SMIL_COMPAT, XML_ADDITIVE): + case XML_ELEMENT(SMIL_SO52, XML_ADDITIVE): + { + if( xAnimate.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_AdditiveMode ) ) + xAnimate->setAdditive( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_KEYSPLINES): + case XML_ELEMENT(SMIL_COMPAT, XML_KEYSPLINES): + case XML_ELEMENT(SMIL_SO52, XML_KEYSPLINES): + { + if( xAnimate.is() ) + xAnimate->setTimeFilter( AnimationsImportHelperImpl::convertTimeFilter( aIter.toView() ) ); + } + break; + + case XML_ELEMENT(SVG, XML_PATH): + case XML_ELEMENT(SVG_COMPAT, XML_PATH): + { + Reference< XAnimateMotion > xAnimateMotion( mxNode, UNO_QUERY ); + if( xAnimateMotion.is() ) + xAnimateMotion->setPath( AnimationsImportHelperImpl::convertPath( aIter.toString() ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_PHYSICS_ANIMATION_START_VELOCITY_X): + case XML_ELEMENT(ANIMATION_OOO, XML_PHYSICS_ANIMATION_START_VELOCITY_X): + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_X): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setStartVelocityX( Any(aIter.toDouble()) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_PHYSICS_ANIMATION_START_VELOCITY_Y): + case XML_ELEMENT(ANIMATION_OOO, XML_PHYSICS_ANIMATION_START_VELOCITY_Y): + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_START_VELOCITY_Y): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setStartVelocityY( Any(aIter.toDouble()) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_PHYSICS_ANIMATION_DENSITY): + case XML_ELEMENT(ANIMATION_OOO, XML_PHYSICS_ANIMATION_DENSITY): + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_DENSITY): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setDensity( Any(aIter.toDouble()) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_PHYSICS_ANIMATION_BOUNCINESS): + case XML_ELEMENT(ANIMATION_OOO, XML_PHYSICS_ANIMATION_BOUNCINESS): + case XML_ELEMENT(LO_EXT, XML_PHYSICS_ANIMATION_BOUNCINESS): + { + Reference< XAnimatePhysics > xAnimatePhysics( mxNode, UNO_QUERY ); + if( xAnimatePhysics.is() ) + xAnimatePhysics->setBounciness( Any(aIter.toDouble()) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_COLOR_INTERPOLATION): + case XML_ELEMENT(ANIMATION_OOO, XML_COLOR_INTERPOLATION): + { + Reference< XAnimateColor > xAnimateColor( mxNode, UNO_QUERY ); + if( xAnimateColor.is() ) + xAnimateColor->setColorInterpolation( IsXMLToken( aIter, XML_HSL ) ? AnimationColorSpace::HSL : AnimationColorSpace::RGB ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_COLOR_INTERPOLATION_DIRECTION): + case XML_ELEMENT(ANIMATION_OOO, XML_COLOR_INTERPOLATION_DIRECTION): + { + Reference< XAnimateColor > xAnimateColor( mxNode, UNO_QUERY ); + if( xAnimateColor.is() ) + xAnimateColor->setDirection( IsXMLToken( aIter, XML_CLOCKWISE ) ); + } + break; + + case XML_ELEMENT(SVG, XML_TYPE): + case XML_ELEMENT(SVG_COMPAT, XML_TYPE): + { + Reference< XAnimateTransform > xTransform( mxNode, UNO_QUERY ); + if( xTransform.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_TransformType ) ) + { + xTransform->setTransformType( nEnum ); + switch( nEnum ) + { + case AnimationTransformType::SCALE: meAttributeName = XML_SCALE; break; + case AnimationTransformType::ROTATE: meAttributeName = XML_ROTATE; break; + case AnimationTransformType::SKEWX: meAttributeName = XML_SKEWX; break; + case AnimationTransformType::SKEWY: meAttributeName = XML_SKEWY; break; + //case AnimationTransformType::TRANSLATE: + default: + meAttributeName = XML_TRANSLATE; break; + } + } + } + } + break; + + case XML_ELEMENT(SMIL, XML_TYPE): + case XML_ELEMENT(SMIL_COMPAT, XML_TYPE): + case XML_ELEMENT(SMIL_SO52, XML_TYPE): + { + if( xTransitionFilter.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_TransitionType ) ) + xTransitionFilter->setTransition( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_SUBTYPE): + case XML_ELEMENT(SMIL_COMPAT, XML_SUBTYPE): + case XML_ELEMENT(SMIL_SO52, XML_SUBTYPE): + { + if( xTransitionFilter.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_TransitionSubType ) ) + xTransitionFilter->setSubtype( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_MODE): + case XML_ELEMENT(SMIL_COMPAT, XML_MODE): + case XML_ELEMENT(SMIL_SO52, XML_MODE): + { + if( xTransitionFilter.is() ) + xTransitionFilter->setMode( IsXMLToken( aIter, XML_IN ) ); + } + break; + + case XML_ELEMENT(SMIL, XML_DIRECTION): + case XML_ELEMENT(SMIL_COMPAT, XML_DIRECTION): + case XML_ELEMENT(SMIL_SO52, XML_DIRECTION): + { + if( xTransitionFilter.is() ) + xTransitionFilter->setDirection( IsXMLToken( aIter, XML_FORWARD ) ); + } + break; + + case XML_ELEMENT(SMIL, XML_FADECOLOR): + case XML_ELEMENT(SMIL_COMPAT, XML_FADECOLOR): + case XML_ELEMENT(SMIL_SO52, XML_FADECOLOR): + { + if( xTransitionFilter.is() ) + { + sal_Int32 nColor(0); + ::sax::Converter::convertColor(nColor, aIter.toView()); + xTransitionFilter->setFadeColor(nColor); + } + } + break; + + case XML_ELEMENT(ANIMATION, XML_ITERATE_TYPE): + case XML_ELEMENT(ANIMATION_OOO, XML_ITERATE_TYPE): + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_IterateType ) ) + { + if( xIter.is() ) + xIter->setIterateType( nEnum ); + } + } + break; + + case XML_ELEMENT(ANIMATION, XML_ITERATE_INTERVAL): + case XML_ELEMENT(ANIMATION_OOO, XML_ITERATE_INTERVAL): + { + if( xIter.is() ) + { + OUString rValue = aIter.toString(); + double fInterval = 0.0; + if( rValue.match("P") ) + { + css::util::Duration aDuration; + if (::sax::Converter::convertDuration(aDuration, rValue)) + { + fInterval = ((((aDuration.Hours * 60) + + aDuration.Minutes) * 60) + aDuration.Seconds) + + (aDuration.NanoSeconds / 1000000000.0); + } + } + else + { + fInterval = aIter.toDouble(); + } + + xIter->setIterateInterval( fInterval ); + } + } + break; + + case XML_ELEMENT(PRESENTATION, XML_GROUP_ID): + case XML_ELEMENT(PRESENTATION_SO52, XML_GROUP_ID): + case XML_ELEMENT(PRESENTATION_OOO, XML_GROUP_ID): + { + aUserData.emplace_back( "group-id", Any( aIter.toInt32() ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_COMMAND): + case XML_ELEMENT(ANIMATION_OOO, XML_COMMAND): + { + if( xCommand.is() && nNodeType == AnimationNodeType::COMMAND ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, aIter.toView(), aAnimations_EnumMap_Command ) ) + { + xCommand->setCommand( nEnum ); + } + } + } + break; + + default: + { + // push all unknown attributes within the presentation namespace as user data + if (IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION) + || IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION_SO52) + || IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION_OASIS) + || IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION_OOO)) + { + aUserData.emplace_back( SvXMLImport::getNameFromToken(aIter.getToken()), Any( aIter.toString() ) ); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + } + + if (!sXmlId.isEmpty()) + { + Reference< XInterface > const xRef( mxNode, UNO_QUERY ); + GetImport().getInterfaceToIdentifierMapper().registerReference( + sXmlId, xRef ); + } + + sal_Int32 nUserDataCount = aUserData.size(); + if( nUserDataCount ) + { + Sequence< NamedValue > aUnoUserData( nUserDataCount ); + NamedValue* pData = aUnoUserData.getArray(); + for (auto const& item : aUserData) + *pData++ = item; + + mxNode->setUserData( aUnoUserData ); + } + + // convert values + if( xAnimate.is() ) + { + if( !aFrom.isEmpty() ) + xAnimate->setFrom( mpHelper->convertValue( meAttributeName, aFrom ) ); + + if( !aBy.isEmpty() ) + xAnimate->setBy( mpHelper->convertValue( meAttributeName, aBy ) ); + + if( !aTo.isEmpty() ) + xAnimate->setTo( mpHelper->convertValue( meAttributeName, aTo ) ); + + if( !aValues.isEmpty() ) + xAnimate->setValues( mpHelper->convertValueSequence( meAttributeName, aValues ) ); + + if (xAnimate->getValues().getLength() != xAnimate->getKeyTimes().getLength()) + throw css::io::WrongFormatException(); + } + } + catch (const css::io::WrongFormatException&) + { + throw; + } + catch (const RuntimeException&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > AnimationNodeContext::createFastChildContext(sal_Int32 nElement, + const css::uno::Reference& xAttrList) +{ + if( mxNode.is()) + return new AnimationNodeContext( mxNode, GetImport(), nElement, xAttrList, mpHelper ); + return nullptr; +} + +namespace { + +class AnimationsImport: public SvXMLImport, public XAnimationNodeSupplier +{ +public: + explicit AnimationsImport( const Reference< XComponentContext > & rxContext ); + + SvXMLImportContext* CreateFastContext(sal_Int32 nElement, + const Reference& xAttrList) override; + + // XInterface + virtual Any SAL_CALL queryInterface( const Type& aType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + // XAnimationNodeSupplier + Reference< XAnimationNode > SAL_CALL getAnimationNode() override; + +private: + Reference< XAnimationNode > mxRootNode; +}; + +} + +AnimationsImport::AnimationsImport( const Reference< XComponentContext > & rxContext ) +: SvXMLImport( rxContext, "xmloff::AnimationsImport", SvXMLImportFlags::META ) + //FIXME: the above "IMPORT_META" used to be a nonsensical "true", question + // remains whether this should be IMPORT_META (same numerical value as + // true) or default IMPORT_ALL +{ + mxRootNode.set( SequenceTimeContainer::create(rxContext), UNO_QUERY_THROW ); +} + +// XInterface +Any SAL_CALL AnimationsImport::queryInterface( const Type& aType ) +{ + if ( aType == cppu::UnoType::get()) + { + return Any( Reference( this ) ); + } + else + { + return SvXMLImport::queryInterface( aType ); + } +} + +void SAL_CALL AnimationsImport::acquire() noexcept +{ + SvXMLImport::acquire(); +} + +void SAL_CALL AnimationsImport::release() noexcept +{ + SvXMLImport::release(); +} + +SvXMLImportContext *AnimationsImport::CreateFastContext( + sal_Int32 nElement, + const Reference& xAttrList) +{ + SvXMLImportContext* pContext = nullptr; + + if( nElement == XML_ELEMENT(ANIMATION, XML_SEQ) || nElement == XML_ELEMENT(ANIMATION_OOO, XML_SEQ) ) + { + pContext = new AnimationNodeContext( mxRootNode, *this, nElement, xAttrList ); + } + + return pContext; +} + +// XAnimationNodeSupplier +Reference< XAnimationNode > SAL_CALL AnimationsImport::getAnimationNode() +{ + return mxRootNode; +} + +void AnimationNodeContext::postProcessRootNode( const Reference< XAnimationNode >& xRootNode, Reference< XPropertySet > const & xPageProps ) +{ + if( !(xRootNode.is() && xPageProps.is()) ) + return; + + try + { + Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW ); + if( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + if( xNode->getType() == AnimationNodeType::PAR ) + { + Event aEvent; + if( (xNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::BEGIN_EVENT) ) + { + // found transition node + Reference< XEnumerationAccess > xChildEnumerationAccess( xNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xChildEnumeration( xChildEnumerationAccess->createEnumeration(), UNO_SET_THROW ); + while( xChildEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xChildEnumeration->nextElement(), UNO_QUERY_THROW ); + switch( xChildNode->getType() ) + { + case AnimationNodeType::TRANSITIONFILTER: + { + Reference< XTransitionFilter > xTransFilter( xChildNode, UNO_QUERY_THROW ); + + xPageProps->setPropertyValue("TransitionType", Any( xTransFilter->getTransition() ) ); + xPageProps->setPropertyValue("TransitionSubtype", Any( xTransFilter->getSubtype() ) ); + xPageProps->setPropertyValue("TransitionDirection", Any( xTransFilter->getDirection() ) ); + xPageProps->setPropertyValue("TransitionFadeColor", Any( xTransFilter->getFadeColor() ) ); + + double fDuration; + if( xTransFilter->getDuration() >>= fDuration ) + xPageProps->setPropertyValue("TransitionDuration", Any( fDuration ) ); + + } + break; + + case AnimationNodeType::COMMAND: + { + Reference< XCommand > xCommand( xChildNode, UNO_QUERY_THROW ); + if( xCommand->getCommand() == EffectCommands::STOPAUDIO ) + { + xPageProps->setPropertyValue("Sound", Any(true) ); + } + } + break; + + case AnimationNodeType::AUDIO: + { + Reference< XAudio > xAudio( xChildNode, UNO_QUERY_THROW ); + OUString sSoundURL; + if( (xAudio->getSource() >>= sSoundURL) && !sSoundURL.isEmpty() ) + { + xPageProps->setPropertyValue("Sound", Any(sSoundURL) ); + + Timing eTiming; + if( (xAudio->getRepeatCount() >>= eTiming) && (eTiming == Timing_INDEFINITE) ) + xPageProps->setPropertyValue("LoopSound", Any( true ) ); + } + } + break; + + } + } + + Reference< XTimeContainer > xRootContainer( xRootNode, UNO_QUERY_THROW ); + xRootContainer->removeChild( xNode ); + } + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +} // namespace xmloff + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Xmloff_AnimationsImport(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new xmloff::AnimationsImport(pCtx)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/animexp.cxx b/xmloff/source/draw/animexp.cxx new file mode 100644 index 000000000..f839506db --- /dev/null +++ b/xmloff/source/draw/animexp.cxx @@ -0,0 +1,512 @@ +/* -*- 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 +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::presentation; +using namespace ::xmloff::token; + +namespace { + +struct Effect +{ + XMLEffect meKind; + XMLEffectDirection meDirection; + sal_Int16 mnStartScale; + bool mbIn; +}; + +} + +const Effect AnimationEffectMap[] = +{ + { EK_none, ED_none, -1, true }, // AnimationEffect_NONE + { EK_fade, ED_from_left, -1, true }, // AnimationEffect_FADE_FROM_LEFT + { EK_fade, ED_from_top, -1, true }, // AnimationEffect_FADE_FROM_TOP + { EK_fade, ED_from_right, -1, true }, // AnimationEffect_FADE_FROM_RIGHT + { EK_fade, ED_from_bottom, -1, true }, // AnimationEffect_FADE_FROM_BOTTOM + { EK_fade, ED_to_center, -1, true }, // AnimationEffect_FADE_TO_CENTER + { EK_fade, ED_from_center, -1, true }, // AnimationEffect_FADE_FROM_CENTER + { EK_move, ED_from_left, -1, true }, // AnimationEffect_MOVE_FROM_LEFT + { EK_move, ED_from_top, -1, true }, // AnimationEffect_MOVE_FROM_TOP + { EK_move, ED_from_right, -1, true }, // AnimationEffect_MOVE_FROM_RIGHT + { EK_move, ED_from_bottom, -1, true }, // AnimationEffect_MOVE_FROM_BOTTOM + { EK_stripes, ED_vertical, -1, true }, // AnimationEffect_VERTICAL_STRIPES + { EK_stripes, ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_STRIPES + { EK_fade, ED_clockwise, -1, true }, // AnimationEffect_CLOCKWISE + { EK_fade, ED_cclockwise, -1, true }, // AnimationEffect_COUNTERCLOCKWISE + { EK_fade, ED_from_upperleft, -1, true }, // AnimationEffect_FADE_FROM_UPPERLEFT + { EK_fade, ED_from_upperright, -1, true }, // AnimationEffect_FADE_FROM_UPPERRIGHT + { EK_fade, ED_from_lowerleft, -1, true }, // AnimationEffect_FADE_FROM_LOWERLEFT + { EK_fade, ED_from_lowerright, -1, true }, // AnimationEffect_FADE_FROM_LOWERRIGHT + { EK_close,ED_vertical, -1, true }, // AnimationEffect_CLOSE_VERTICAL + { EK_close,ED_horizontal, -1, true }, // AnimationEffect_CLOSE_HORIZONTAL + { EK_open, ED_vertical, -1, true }, // AnimationEffect_OPEN_VERTICAL + { EK_open, ED_horizontal, -1, true }, // AnimationEffect_OPEN_HORIZONTAL + { EK_move, ED_path, -1, true }, // AnimationEffect_PATH + { EK_move, ED_to_left, -1, false },// AnimationEffect_MOVE_TO_LEFT + { EK_move, ED_to_top, -1, false },// AnimationEffect_MOVE_TO_TOP + { EK_move, ED_to_right, -1, false },// AnimationEffect_MOVE_TO_RIGHT + { EK_move, ED_to_bottom, -1, false },// AnimationEffect_MOVE_TO_BOTTOM + { EK_fade, ED_spiral_inward_left, -1, true }, // AnimationEffect_SPIRALIN_LEFT + { EK_fade, ED_spiral_inward_right, -1, true }, // AnimationEffect_SPIRALIN_RIGHT + { EK_fade, ED_spiral_outward_left, -1, true }, // AnimationEffect_SPIRALOUT_LEFT + { EK_fade, ED_spiral_outward_right, -1, true }, // AnimationEffect_SPIRALOUT_RIGHT + { EK_dissolve, ED_none, -1, true }, // AnimationEffect_DISSOLVE + { EK_wavyline, ED_from_left, -1, true }, // AnimationEffect_WAVYLINE_FROM_LEFT + { EK_wavyline, ED_from_top, -1, true }, // AnimationEffect_WAVYLINE_FROM_TOP + { EK_wavyline, ED_from_right, -1, true }, // AnimationEffect_WAVYLINE_FROM_RIGHT + { EK_wavyline, ED_from_bottom, -1, true }, // AnimationEffect_WAVYLINE_FROM_BOTTOM + { EK_random, ED_none, -1, true }, // AnimationEffect_RANDOM + { EK_lines, ED_vertical, -1, true }, // AnimationEffect_VERTICAL_LINES + { EK_lines, ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_LINES + { EK_laser, ED_from_left, -1, true }, // AnimationEffect_LASER_FROM_LEFT + { EK_laser, ED_from_top, -1, true }, // AnimationEffect_LASER_FROM_TOP + { EK_laser, ED_from_right, -1, true }, // AnimationEffect_LASER_FROM_RIGHT + { EK_laser, ED_from_bottom, -1, true }, // AnimationEffect_LASER_FROM_BOTTOM + { EK_laser, ED_from_upperleft, -1, true }, // AnimationEffect_LASER_FROM_UPPERLEFT + { EK_laser, ED_from_upperright, -1, true }, // AnimationEffect_LASER_FROM_UPPERRIGHT + { EK_laser, ED_from_lowerleft, -1, true }, // AnimationEffect_LASER_FROM_LOWERLEFT + { EK_laser, ED_from_lowerright, -1, true }, // AnimationEffect_LASER_FROM_LOWERRIGHT + { EK_appear,ED_none, -1, true }, // AnimationEffect_APPEAR + { EK_hide, ED_none, -1, false },// AnimationEffect_HIDE + { EK_move, ED_from_upperleft, -1, true }, // AnimationEffect_MOVE_FROM_UPPERLEFT + { EK_move, ED_from_upperright, -1, true }, // AnimationEffect_MOVE_FROM_UPPERRIGHT + { EK_move, ED_from_lowerright, -1, true }, // AnimationEffect_MOVE_FROM_LOWERRIGHT + { EK_move, ED_from_lowerleft, -1, true }, // AnimationEffect_MOVE_FROM_LOWERLEFT + { EK_move, ED_to_upperleft, -1, false },// AnimationEffect_MOVE_TO_UPPERLEFT + { EK_move, ED_to_upperright, -1, false },// AnimationEffect_MOVE_TO_UPPERRIGHT + { EK_move, ED_to_lowerright, -1, false },// AnimationEffect_MOVE_TO_LOWERRIGHT + { EK_move, ED_to_lowerleft, -1, false },// AnimationEffect_MOVE_TO_LOWERLEFT + { EK_move_short, ED_from_left, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_LEFT + { EK_move_short, ED_from_upperleft, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_UPPERLEFT + { EK_move_short, ED_from_top, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_TOP + { EK_move_short, ED_from_upperright,-1, true }, // AnimationEffect_MOVE_SHORT_FROM_UPPERRIGHT + { EK_move_short, ED_from_right, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_RIGHT + { EK_move_short, ED_from_lowerright,-1, true }, // AnimationEffect_MOVE_SHORT_FROM_LOWERRIGHT + { EK_move_short, ED_from_bottom, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_BOTTOM + { EK_move_short, ED_from_lowerleft, -1, true }, // AnimationEffect_MOVE_SHORT_FROM_LOWERLEFT + { EK_move_short, ED_to_left, -1, false },// AnimationEffect_MOVE_SHORT_TO_LEFT + { EK_move_short, ED_to_upperleft, -1, false },// AnimationEffect_MOVE_SHORT_TO_UPPERLEFT + { EK_move_short, ED_to_top, -1, false },// AnimationEffect_MOVE_SHORT_TO_TOP + { EK_move_short, ED_to_upperright, -1, false },// AnimationEffect_MOVE_SHORT_TO_UPPERRIGHT + { EK_move_short, ED_to_right, -1, false },// AnimationEffect_MOVE_SHORT_TO_RIGHT + { EK_move_short, ED_to_lowerright, -1, false },// AnimationEffect_MOVE_SHORT_TO_LOWERRIGHT + { EK_move_short, ED_to_bottom, -1, false },// AnimationEffect_MOVE_SHORT_TO_BOTTOM + { EK_move_short, ED_to_lowerleft, -1, false },// AnimationEffect_MOVE_SHORT_TO_LOWERLEFT + { EK_checkerboard, ED_vertical, -1, true }, // AnimationEffect_VERTICAL_CHECKERBOARD + { EK_checkerboard, ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_CHECKERBOARD + { EK_rotate, ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_ROTATE + { EK_rotate, ED_vertical, -1, true }, // AnimationEffect_VERTICAL_ROTATE + { EK_stretch,ED_horizontal, -1, true }, // AnimationEffect_HORIZONTAL_STRETCH + { EK_stretch,ED_vertical, -1, true }, // AnimationEffect_VERTICAL_STRETCH + { EK_stretch,ED_from_left, -1, true }, // AnimationEffect_STRETCH_FROM_LEFT + { EK_stretch,ED_from_upperleft, -1, true }, // AnimationEffect_STRETCH_FROM_UPPERLEFT + { EK_stretch,ED_from_top, -1, true }, // AnimationEffect_STRETCH_FROM_TOP + { EK_stretch,ED_from_upperright,-1, true }, // AnimationEffect_STRETCH_FROM_UPPERRIGHT + { EK_stretch,ED_from_right, -1, true }, // AnimationEffect_STRETCH_FROM_RIGHT + { EK_stretch,ED_from_lowerright,-1, true }, // AnimationEffect_STRETCH_FROM_LOWERRIGHT + { EK_stretch,ED_from_bottom, -1, true }, // AnimationEffect_STRETCH_FROM_BOTTOM + { EK_stretch,ED_from_lowerleft, -1, true }, // AnimationEffect_STRETCH_FROM_LOWERLEFT + { EK_move, ED_none, 0, true }, // AnimationEffect_ZOOM_IN + { EK_move, ED_none, 50, true }, // AnimationEffect_ZOOM_IN_SMALL + { EK_move, ED_spiral_inward_left, 0, true }, // AnimationEffect_ZOOM_IN_SPIRAL + { EK_move, ED_none, 400, true }, // AnimationEffect_ZOOM_OUT + { EK_move, ED_none, 200, true }, // AnimationEffect_ZOOM_OUT_SMALL + { EK_move, ED_spiral_inward_left, 400, true }, // AnimationEffect_ZOOM_OUT_SPIRAL + { EK_move, ED_from_left, 0, true }, // AnimationEffect_ZOOM_IN_FROM_LEFT + { EK_move, ED_from_upperleft, 0, true }, // AnimationEffect_ZOOM_IN_FROM_UPPERLEFT + { EK_move, ED_from_top, 0, true }, // AnimationEffect_ZOOM_IN_FROM_TOP + { EK_move, ED_from_upperright, 0, true }, // AnimationEffect_ZOOM_IN_FROM_UPPERRIGHT + { EK_move, ED_from_right, 0, true }, // AnimationEffect_ZOOM_IN_FROM_RIGHT + { EK_move, ED_from_lowerright, 0, true }, // AnimationEffect_ZOOM_IN_FROM_LOWERRIGHT + { EK_move, ED_from_bottom, 0, true }, // AnimationEffect_ZOOM_IN_FROM_BOTTOM + { EK_move, ED_from_lowerleft, 0, true }, // AnimationEffect_ZOOM_IN_FROM_LOWERLEFT + { EK_move, ED_from_center, 0, true }, // AnimationEffect_ZOOM_IN_FROM_CENTER + { EK_move, ED_from_left, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_LEFT + { EK_move, ED_from_upperleft, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_UPPERLEFT + { EK_move, ED_from_top, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_TOP + { EK_move, ED_from_upperright,400, true }, // AnimationEffect_ZOOM_OUT_FROM_UPPERRIGHT + { EK_move, ED_from_right, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_RIGHT + { EK_move, ED_from_lowerright,400, true }, // AnimationEffect_ZOOM_OUT_FROM_LOWERRIGHT + { EK_move, ED_from_bottom, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_BOTTOM + { EK_move, ED_from_lowerleft, 400, true }, // AnimationEffect_ZOOM_OUT_FROM_LOWERLEFT + { EK_move, ED_from_center, 400, true } // AnimationEffect_ZOOM_OUT_FROM_CENTER +}; + +void SdXMLImplSetEffect( AnimationEffect eEffect, XMLEffect& eKind, XMLEffectDirection& eDirection, sal_Int16& nStartScale, bool& bIn ) +{ + if( eEffect < AnimationEffect_NONE || eEffect > AnimationEffect_ZOOM_OUT_FROM_CENTER ) + { + OSL_FAIL( "unknown animation effect!" ); + eEffect = AnimationEffect_NONE; + } + + const Effect& rEffect = AnimationEffectMap[static_cast(eEffect)]; + eKind = rEffect.meKind; + eDirection = rEffect.meDirection; + nStartScale = rEffect.mnStartScale; + bIn = rEffect.mbIn; +} + +namespace { + +enum XMLActionKind : sal_Int8 +{ + XMLE_SHOW, + XMLE_HIDE, + XMLE_DIM, + XMLE_PLAY +}; + +struct XMLEffectHint +{ + Reference mxShape; + XMLActionKind meKind; + bool mbTextEffect; + + XMLEffect meEffect; + XMLEffectDirection meDirection; + sal_Int16 mnStartScale; + + AnimationSpeed meSpeed; + OUString maSoundURL; + sal_Int32 maDimColor; + sal_Int32 mnPresId; + bool mbPlayFull; + + bool operator<(const XMLEffectHint& rComp) const { return mnPresId < rComp.mnPresId; } + + XMLEffectHint() + : meKind( XMLE_SHOW ), mbTextEffect( false ), + meEffect( EK_none ), meDirection( ED_none ), mnStartScale( -1 ), + meSpeed( AnimationSpeed_SLOW ), maDimColor(0), + mnPresId( 0 ), mbPlayFull( false ) + {} +}; + +} + +class AnimExpImpl +{ +public: + list maEffects; + + static constexpr OUStringLiteral gsDimColor = u"DimColor"; + static constexpr OUStringLiteral gsDimHide = u"DimHide"; + static constexpr OUStringLiteral gsDimPrev = u"DimPrevious"; + static constexpr OUStringLiteral gsEffect = u"Effect"; + static constexpr OUStringLiteral gsPlayFull = u"PlayFull"; + static constexpr OUStringLiteral gsPresOrder = u"PresentationOrder"; + static constexpr OUStringLiteral gsSound = u"Sound"; + static constexpr OUStringLiteral gsSoundOn = u"SoundOn"; + static constexpr OUStringLiteral gsSpeed = u"Speed"; + static constexpr OUStringLiteral gsTextEffect = u"TextEffect"; + static constexpr OUStringLiteral gsIsAnimation = u"IsAnimation"; + static constexpr OUStringLiteral gsAnimPath = u"AnimationPath"; +}; + +XMLAnimationsExporter::XMLAnimationsExporter() + : mpImpl( new AnimExpImpl ) +{ +} + +XMLAnimationsExporter::~XMLAnimationsExporter() +{ +} + +void XMLAnimationsExporter::prepare( const Reference< XShape >& xShape ) +{ + try + { + // check for presentation shape service + { + Reference< XServiceInfo > xServiceInfo( xShape, UNO_QUERY ); + if( !xServiceInfo.is() || !xServiceInfo->supportsService("com.sun.star.presentation.Shape") ) + return; + } + + Reference< XPropertySet > xProps( xShape, UNO_QUERY ); + if( xProps.is() ) + { + AnimationEffect eEffect; + xProps->getPropertyValue( AnimExpImpl::gsEffect ) >>= eEffect; + if( eEffect == AnimationEffect_PATH ) + { + Reference< XShape > xPath; + xProps->getPropertyValue( AnimExpImpl::gsAnimPath ) >>= xPath; + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "exception caught while collection animation information!"); + } +} + +void XMLAnimationsExporter::collect( const Reference< XShape >& xShape, SvXMLExport& rExport ) +{ + try + { + // check for presentation shape service + { + Reference< XServiceInfo > xServiceInfo( xShape, UNO_QUERY ); + if( !xServiceInfo.is() || !xServiceInfo->supportsService("com.sun.star.presentation.Shape") ) + return; + } + + Reference< XPropertySet > xProps( xShape, UNO_QUERY ); + if( xProps.is() ) + { + XMLEffectHint aEffect; + + if( any2bool( xProps->getPropertyValue( AnimExpImpl::gsSoundOn ) ) ) + { + xProps->getPropertyValue( AnimExpImpl::gsSound ) >>= aEffect.maSoundURL; + xProps->getPropertyValue( AnimExpImpl::gsPlayFull ) >>= aEffect.mbPlayFull; + } + + xProps->getPropertyValue( AnimExpImpl::gsPresOrder ) >>= aEffect.mnPresId; + xProps->getPropertyValue( AnimExpImpl::gsSpeed ) >>= aEffect.meSpeed; + + + bool bIsAnimation = false; + xProps->getPropertyValue( AnimExpImpl::gsIsAnimation ) >>= bIsAnimation; + if( bIsAnimation ) + { + aEffect.meKind = XMLE_PLAY; + + if( !aEffect.mxShape.is() ) + { + rExport.getInterfaceToIdentifierMapper().registerReference( xShape ); + aEffect.mxShape = xShape; + } + + mpImpl->maEffects.push_back( aEffect ); + } + + { + AnimationEffect eEffect; + xProps->getPropertyValue( AnimExpImpl::gsEffect ) >>= eEffect; + if( eEffect != AnimationEffect_NONE ) + { + bool bIn = true; + SdXMLImplSetEffect( eEffect, aEffect.meEffect, aEffect.meDirection, aEffect.mnStartScale, bIn ); + + aEffect.meKind = bIn ? XMLE_SHOW : XMLE_HIDE; + + if( !aEffect.mxShape.is() ) + { + rExport.getInterfaceToIdentifierMapper().registerReference( xShape ); + aEffect.mxShape = xShape; + } + + if( eEffect == AnimationEffect_PATH ) + { + Reference< XShape > xPath; + xProps->getPropertyValue( AnimExpImpl::gsAnimPath ) >>= xPath; + if( xPath.is() ) + { +// strip mpImpl->mxShapeExp->createShapeId( xPath ); +// strip aEffect.mnPathShapeId = mpImpl->mxShapeExp->getShapeId( xPath ); + } + } + mpImpl->maEffects.push_back( aEffect ); + + aEffect.maSoundURL.clear(); + } + + xProps->getPropertyValue( AnimExpImpl::gsTextEffect ) >>= eEffect; + if( eEffect != AnimationEffect_NONE ) + { + bool bIn = true; + SdXMLImplSetEffect( eEffect, aEffect.meEffect, aEffect.meDirection, aEffect.mnStartScale, bIn ); + aEffect.meKind = bIn ? XMLE_SHOW : XMLE_HIDE; + aEffect.mbTextEffect = true; + + if( !aEffect.mxShape.is() ) + { + rExport.getInterfaceToIdentifierMapper().registerReference( xShape ); + aEffect.mxShape = xShape; + } + + mpImpl->maEffects.push_back( aEffect ); + aEffect.mbTextEffect = false; + aEffect.maSoundURL.clear(); + } + + bool bDimPrev = false; + bool bDimHide = false; + xProps->getPropertyValue( AnimExpImpl::gsDimPrev ) >>= bDimPrev; + xProps->getPropertyValue( AnimExpImpl::gsDimHide ) >>= bDimHide; + if( bDimPrev || bDimHide ) + { + aEffect.meKind = bDimPrev ? XMLE_DIM : XMLE_HIDE; + aEffect.meEffect = EK_none; + aEffect.meDirection = ED_none; + aEffect.meSpeed = AnimationSpeed_MEDIUM; + if( bDimPrev ) + { + xProps->getPropertyValue( AnimExpImpl::gsDimColor ) + >>= aEffect.maDimColor; + } + + if( !aEffect.mxShape.is() ) + { + rExport.getInterfaceToIdentifierMapper().registerReference( xShape ); + aEffect.mxShape = xShape; + } + + mpImpl->maEffects.push_back( aEffect ); + aEffect.maSoundURL.clear(); + } + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "exception caught while collection animation information!"); + } +} + +void XMLAnimationsExporter::exportAnimations( SvXMLExport& rExport ) +{ + mpImpl->maEffects.sort(); + + OUStringBuffer sTmp; + + if( !mpImpl->maEffects.empty() ) + { + SvXMLElementExport aElement( rExport, XML_NAMESPACE_PRESENTATION, XML_ANIMATIONS, true, true ); + + for (const auto& rEffect : mpImpl->maEffects) + { + SAL_WARN_IF( !rEffect.mxShape.is(), "xmloff", "shape id creation failed for animation effect?" ); + + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_SHAPE_ID, rExport.getInterfaceToIdentifierMapper().getIdentifier( rEffect.mxShape ) ); + + if( rEffect.meKind == XMLE_DIM ) + { + // export a dim action; + + ::sax::Converter::convertColor( sTmp, rEffect.maDimColor ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_COLOR, sTmp.makeStringAndClear() ); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_PRESENTATION, XML_DIM, true, true ); + } + else if( rEffect.meKind == XMLE_PLAY ) + { + if( rEffect.meSpeed != AnimationSpeed_MEDIUM ) + { + SvXMLUnitConverter::convertEnum( sTmp, rEffect.meSpeed, aXML_AnimationSpeed_EnumMap ); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, sTmp.makeStringAndClear() ); + } + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_PRESENTATION, XML_PLAY, true, true ); + } + else + { + + if( rEffect.meEffect != EK_none ) + { + SvXMLUnitConverter::convertEnum( sTmp, rEffect.meEffect, aXML_AnimationEffect_EnumMap ); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, sTmp.makeStringAndClear() ); + } + + if( rEffect.meDirection != ED_none ) + { + SvXMLUnitConverter::convertEnum( sTmp, rEffect.meDirection, aXML_AnimationDirection_EnumMap ); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, sTmp.makeStringAndClear() ); + } + + if( rEffect.mnStartScale != -1 ) + { + ::sax::Converter::convertPercent(sTmp, rEffect.mnStartScale); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, sTmp.makeStringAndClear() ); + } + + if( rEffect.meSpeed != AnimationSpeed_MEDIUM ) + { + SvXMLUnitConverter::convertEnum( sTmp, rEffect.meSpeed, aXML_AnimationSpeed_EnumMap ); + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, sTmp.makeStringAndClear() ); + } + + enum XMLTokenEnum eLocalName; + if( rEffect.meKind == XMLE_SHOW ) + { + if( rEffect.mbTextEffect ) + eLocalName = XML_SHOW_TEXT; + else + eLocalName = XML_SHOW_SHAPE; + } + else + { + if( rEffect.mbTextEffect ) + eLocalName = XML_HIDE_TEXT; + else + eLocalName = XML_HIDE_SHAPE; + } + + SvXMLElementExport aEle( rExport, XML_NAMESPACE_PRESENTATION, eLocalName, true, true ); + if( !rEffect.maSoundURL.isEmpty() ) + { + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(rEffect.maSoundURL) ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + if( rEffect.mbPlayFull ) + rExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE ); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true ); + } + } + } + } + + mpImpl->maEffects.clear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/animimp.cxx b/xmloff/source/draw/animimp.cxx new file mode 100644 index 000000000..ffdd3bef7 --- /dev/null +++ b/xmloff/source/draw/animimp.cxx @@ -0,0 +1,598 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::presentation; +using namespace ::xmloff::token; + +const SvXMLEnumMapEntry aXML_AnimationEffect_EnumMap[] = +{ + { XML_NONE, EK_none }, + { XML_FADE, EK_fade }, + { XML_MOVE, EK_move }, + { XML_STRIPES, EK_stripes }, + { XML_OPEN, EK_open }, + { XML_CLOSE, EK_close }, + { XML_DISSOLVE, EK_dissolve }, + { XML_WAVYLINE, EK_wavyline }, + { XML_RANDOM, EK_random }, + { XML_LINES, EK_lines }, + { XML_LASER, EK_laser }, + { XML_APPEAR, EK_appear }, + { XML_HIDE, EK_hide }, + { XML_MOVE_SHORT, EK_move_short }, + { XML_CHECKERBOARD, EK_checkerboard }, + { XML_ROTATE, EK_rotate }, + { XML_STRETCH, EK_stretch }, + { XML_TOKEN_INVALID, XMLEffect(0) } +}; + +const SvXMLEnumMapEntry aXML_AnimationDirection_EnumMap[] = +{ + { XML_NONE, ED_none }, + { XML_FROM_LEFT, ED_from_left }, + { XML_FROM_TOP, ED_from_top }, + { XML_FROM_RIGHT, ED_from_right }, + { XML_FROM_BOTTOM, ED_from_bottom }, + { XML_FROM_CENTER, ED_from_center }, + { XML_FROM_UPPER_LEFT, ED_from_upperleft }, + { XML_FROM_UPPER_RIGHT, ED_from_upperright }, + { XML_FROM_LOWER_LEFT, ED_from_lowerleft }, + { XML_FROM_LOWER_RIGHT, ED_from_lowerright }, + { XML_TO_LEFT, ED_to_left }, + { XML_TO_TOP, ED_to_top }, + { XML_TO_RIGHT, ED_to_right }, + { XML_TO_BOTTOM, ED_to_bottom }, + { XML_TO_UPPER_LEFT, ED_to_upperleft }, + { XML_TO_UPPER_RIGHT, ED_to_upperright }, + { XML_TO_LOWER_RIGHT, ED_to_lowerright }, + { XML_TO_LOWER_LEFT, ED_to_lowerleft }, + { XML_PATH, ED_path }, + { XML_SPIRAL_INWARD_LEFT, ED_spiral_inward_left }, + { XML_SPIRAL_INWARD_RIGHT,ED_spiral_inward_right }, + { XML_SPIRAL_OUTWARD_LEFT, ED_spiral_outward_left }, + { XML_SPIRAL_OUTWARD_RIGHT, ED_spiral_outward_right }, + { XML_VERTICAL, ED_vertical }, + { XML_HORIZONTAL, ED_horizontal }, + { XML_TO_CENTER, ED_to_center }, + { XML_CLOCKWISE, ED_clockwise }, + { XML_COUNTER_CLOCKWISE,ED_cclockwise }, + { XML_TOKEN_INVALID, XMLEffectDirection(0) } +}; + +const SvXMLEnumMapEntry aXML_AnimationSpeed_EnumMap[] = +{ + { XML_SLOW, AnimationSpeed_SLOW }, + { XML_MEDIUM, AnimationSpeed_MEDIUM }, + { XML_FAST, AnimationSpeed_FAST }, + { XML_TOKEN_INVALID, AnimationSpeed(0) } +}; + +AnimationEffect ImplSdXMLgetEffect( XMLEffect eKind, XMLEffectDirection eDirection, sal_Int16 nStartScale, bool /*bIn*/ ) +{ + switch( eKind ) + { + case EK_fade: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_FADE_FROM_LEFT; + case ED_from_top: return AnimationEffect_FADE_FROM_TOP; + case ED_from_right: return AnimationEffect_FADE_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_FADE_FROM_BOTTOM; + case ED_from_center: return AnimationEffect_FADE_FROM_CENTER; + case ED_from_upperleft: return AnimationEffect_FADE_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_FADE_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_FADE_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_FADE_FROM_LOWERRIGHT; + case ED_to_center: return AnimationEffect_FADE_TO_CENTER; + case ED_clockwise: return AnimationEffect_CLOCKWISE; + case ED_cclockwise: return AnimationEffect_COUNTERCLOCKWISE; + case ED_spiral_inward_left: return AnimationEffect_SPIRALIN_LEFT; + case ED_spiral_inward_right:return AnimationEffect_SPIRALIN_RIGHT; + case ED_spiral_outward_left:return AnimationEffect_SPIRALOUT_LEFT; + case ED_spiral_outward_right:return AnimationEffect_SPIRALOUT_RIGHT; + default: return AnimationEffect_FADE_FROM_LEFT; + } + case EK_move: + if( nStartScale == 200 ) + { + return AnimationEffect_ZOOM_OUT_SMALL; + } + else if( nStartScale == 50 ) + { + return AnimationEffect_ZOOM_IN_SMALL; + } + else if( nStartScale < 100 ) + { + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_ZOOM_IN_FROM_LEFT; + case ED_from_top: return AnimationEffect_ZOOM_IN_FROM_TOP; + case ED_from_right: return AnimationEffect_ZOOM_IN_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_ZOOM_IN_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_ZOOM_IN_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_ZOOM_IN_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_ZOOM_IN_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_ZOOM_IN_FROM_LOWERRIGHT; + case ED_from_center: return AnimationEffect_ZOOM_IN_FROM_CENTER; + case ED_spiral_inward_left: return AnimationEffect_ZOOM_IN_SPIRAL; + case ED_to_left: return AnimationEffect_MOVE_TO_LEFT; + case ED_to_top: return AnimationEffect_MOVE_TO_TOP; + case ED_to_right: return AnimationEffect_MOVE_TO_RIGHT; + case ED_to_bottom: return AnimationEffect_MOVE_TO_BOTTOM; + case ED_to_upperleft: return AnimationEffect_MOVE_TO_UPPERLEFT; + case ED_to_upperright: return AnimationEffect_MOVE_TO_UPPERRIGHT; + case ED_to_lowerright: return AnimationEffect_MOVE_TO_LOWERRIGHT; + case ED_to_lowerleft: return AnimationEffect_MOVE_TO_LOWERLEFT; + default: return AnimationEffect_ZOOM_IN; + } + } + else if( nStartScale > 100 ) + { + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_ZOOM_OUT_FROM_LEFT; + case ED_from_top: return AnimationEffect_ZOOM_OUT_FROM_TOP; + case ED_from_right: return AnimationEffect_ZOOM_OUT_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_ZOOM_OUT_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_ZOOM_OUT_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_ZOOM_OUT_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_ZOOM_OUT_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_ZOOM_OUT_FROM_LOWERRIGHT; + case ED_from_center: return AnimationEffect_ZOOM_OUT_FROM_CENTER; + case ED_spiral_inward_left: return AnimationEffect_ZOOM_OUT_SPIRAL; + default: return AnimationEffect_ZOOM_OUT; + } + } + else + { + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_MOVE_FROM_LEFT; + case ED_from_top: return AnimationEffect_MOVE_FROM_TOP; + case ED_from_right: return AnimationEffect_MOVE_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_MOVE_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_MOVE_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_MOVE_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_MOVE_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_MOVE_FROM_LOWERRIGHT; + case ED_path: return AnimationEffect_PATH; + case ED_to_top: return AnimationEffect_MOVE_TO_TOP; + case ED_to_right: return AnimationEffect_MOVE_TO_RIGHT; + case ED_to_bottom: return AnimationEffect_MOVE_TO_BOTTOM; + case ED_to_upperleft: return AnimationEffect_MOVE_TO_UPPERLEFT; + case ED_to_upperright: return AnimationEffect_MOVE_TO_UPPERRIGHT; + case ED_to_lowerright: return AnimationEffect_MOVE_TO_LOWERRIGHT; + case ED_to_lowerleft: return AnimationEffect_MOVE_TO_LOWERLEFT; + default: + break; + } + } + return AnimationEffect_MOVE_FROM_LEFT; + case EK_stripes: + if( eDirection == ED_vertical ) + return AnimationEffect_VERTICAL_STRIPES; + else + return AnimationEffect_HORIZONTAL_STRIPES; + case EK_open: + if( eDirection == ED_vertical ) + return AnimationEffect_OPEN_VERTICAL; + else + return AnimationEffect_OPEN_HORIZONTAL; + case EK_close: + if( eDirection == ED_vertical ) + return AnimationEffect_CLOSE_VERTICAL; + else + return AnimationEffect_CLOSE_HORIZONTAL; + case EK_dissolve: + return AnimationEffect_DISSOLVE; + case EK_wavyline: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_WAVYLINE_FROM_LEFT; + case ED_from_top: return AnimationEffect_WAVYLINE_FROM_TOP; + case ED_from_right: return AnimationEffect_WAVYLINE_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_WAVYLINE_FROM_BOTTOM; + default: return AnimationEffect_WAVYLINE_FROM_LEFT; + } + case EK_random: + return AnimationEffect_RANDOM; + case EK_lines: + if( eDirection == ED_vertical ) + return AnimationEffect_VERTICAL_LINES; + else + return AnimationEffect_HORIZONTAL_LINES; + case EK_laser: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_LASER_FROM_LEFT; + case ED_from_top: return AnimationEffect_LASER_FROM_TOP; + case ED_from_right: return AnimationEffect_LASER_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_LASER_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_LASER_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_LASER_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_LASER_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_LASER_FROM_LOWERRIGHT; + default: return AnimationEffect_LASER_FROM_LEFT; + } + case EK_appear: + return AnimationEffect_APPEAR; + case EK_hide: + return AnimationEffect_HIDE; + case EK_move_short: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_MOVE_SHORT_FROM_LEFT; + case ED_from_top: return AnimationEffect_MOVE_SHORT_FROM_TOP; + case ED_from_right: return AnimationEffect_MOVE_SHORT_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_MOVE_SHORT_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_MOVE_SHORT_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_MOVE_SHORT_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_MOVE_SHORT_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_MOVE_SHORT_FROM_LOWERRIGHT; + case ED_to_left: return AnimationEffect_MOVE_SHORT_TO_LEFT; + case ED_to_upperleft: return AnimationEffect_MOVE_SHORT_TO_UPPERLEFT; + case ED_to_top: return AnimationEffect_MOVE_SHORT_TO_TOP; + case ED_to_upperright: return AnimationEffect_MOVE_SHORT_TO_UPPERRIGHT; + case ED_to_right: return AnimationEffect_MOVE_SHORT_TO_RIGHT; + case ED_to_lowerright: return AnimationEffect_MOVE_SHORT_TO_LOWERRIGHT; + case ED_to_bottom: return AnimationEffect_MOVE_SHORT_TO_BOTTOM; + case ED_to_lowerleft: return AnimationEffect_MOVE_SHORT_TO_LOWERLEFT; + default: return AnimationEffect_MOVE_SHORT_FROM_LEFT; + } + case EK_checkerboard: + if( eDirection == ED_vertical ) + return AnimationEffect_VERTICAL_CHECKERBOARD; + else + return AnimationEffect_HORIZONTAL_CHECKERBOARD; + case EK_rotate: + if( eDirection == ED_vertical ) + return AnimationEffect_VERTICAL_ROTATE; + else + return AnimationEffect_HORIZONTAL_ROTATE; + case EK_stretch: + switch( eDirection ) + { + case ED_from_left: return AnimationEffect_STRETCH_FROM_LEFT; + case ED_from_top: return AnimationEffect_STRETCH_FROM_TOP; + case ED_from_right: return AnimationEffect_STRETCH_FROM_RIGHT; + case ED_from_bottom: return AnimationEffect_STRETCH_FROM_BOTTOM; + case ED_from_upperleft: return AnimationEffect_STRETCH_FROM_UPPERLEFT; + case ED_from_upperright: return AnimationEffect_STRETCH_FROM_UPPERRIGHT; + case ED_from_lowerleft: return AnimationEffect_STRETCH_FROM_LOWERLEFT; + case ED_from_lowerright: return AnimationEffect_STRETCH_FROM_LOWERRIGHT; + case ED_vertical: return AnimationEffect_VERTICAL_STRETCH; + case ED_horizontal: return AnimationEffect_HORIZONTAL_STRETCH; + default: + break; + } + return AnimationEffect_STRETCH_FROM_LEFT; + default: + return AnimationEffect_NONE; + } +} + +namespace +{ + constexpr OUStringLiteral gsDimColor = u"DimColor"; + constexpr OUStringLiteral gsDimHide = u"DimHide"; + constexpr OUStringLiteral gsDimPrev = u"DimPrevious"; + constexpr OUStringLiteral gsEffect = u"Effect"; + constexpr OUStringLiteral gsPlayFull = u"PlayFull"; + constexpr OUStringLiteral gsSound = u"Sound"; + constexpr OUStringLiteral gsSoundOn = u"SoundOn"; + constexpr OUStringLiteral gsSpeed = u"Speed"; + constexpr OUStringLiteral gsTextEffect = u"TextEffect"; + constexpr OUStringLiteral gsPresShapeService = u"com.sun.star.presentation.Shape"; + constexpr OUStringLiteral gsAnimPath = u"AnimationPath"; + constexpr OUStringLiteral gsIsAnimation = u"IsAnimation"; +}; + +namespace { + +enum XMLActionKind +{ + XMLE_SHOW, + XMLE_HIDE, + XMLE_DIM, + XMLE_PLAY +}; + +class XMLAnimationsEffectContext : public SvXMLImportContext +{ +public: + rtl::Reference mxAnimationsContext; + + XMLActionKind meKind; + bool mbTextEffect; + OUString maShapeId; + + XMLEffect meEffect; + XMLEffectDirection meDirection; + sal_Int16 mnStartScale; + + AnimationSpeed meSpeed; + sal_Int32 maDimColor; + OUString maSoundURL; + bool mbPlayFull; + OUString maPathShapeId; + +public: + + XMLAnimationsEffectContext( SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList, + XMLAnimationsContext& rAnimationsContext); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +class XMLAnimationsSoundContext : public SvXMLImportContext +{ +public: + + XMLAnimationsSoundContext( SvXMLImport& rImport, sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList, XMLAnimationsEffectContext* pParent ); +}; + +} + +XMLAnimationsSoundContext::XMLAnimationsSoundContext( SvXMLImport& rImport, sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList, XMLAnimationsEffectContext* pParent ) +: SvXMLImportContext( rImport ) +{ + if( !pParent || nElement != XML_ELEMENT(PRESENTATION, XML_SOUND) ) + return; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + pParent->maSoundURL = rImport.GetAbsoluteReference(aIter.toString()); + break; + case XML_ELEMENT(PRESENTATION, XML_PLAY_FULL): + pParent->mbPlayFull = IsXMLToken( aIter, XML_TRUE ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +XMLAnimationsEffectContext::XMLAnimationsEffectContext( SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList, + XMLAnimationsContext& rAnimationsContext ) +: SvXMLImportContext(rImport), + mxAnimationsContext( &rAnimationsContext ), + meKind( XMLE_SHOW ), mbTextEffect( false ), + meEffect( EK_none ), meDirection( ED_none ), mnStartScale( 100 ), + meSpeed( AnimationSpeed_MEDIUM ), maDimColor(0), mbPlayFull( false ) +{ + switch(nElement & TOKEN_MASK) + { + case XML_SHOW_SHAPE: + meKind = XMLE_SHOW; + break; + case XML_SHOW_TEXT: + meKind = XMLE_SHOW; + mbTextEffect = true; + break; + case XML_HIDE_SHAPE: + meKind = XMLE_HIDE; + break; + case XML_HIDE_TEXT: + meKind = XMLE_HIDE; + mbTextEffect = true; + break; + case XML_DIM: + meKind = XMLE_DIM; + break; + case XML_PLAY: + meKind = XMLE_PLAY; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + // unknown action, overread + return; + } + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_SHAPE_ID): + maShapeId = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_COLOR): + ::sax::Converter::convertColor(maDimColor, aIter.toView()); + break; + + case XML_ELEMENT(PRESENTATION, XML_EFFECT): + SvXMLUnitConverter::convertEnum( meEffect, aIter.toView(), aXML_AnimationEffect_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_DIRECTION): + SvXMLUnitConverter::convertEnum( meDirection, aIter.toView(), aXML_AnimationDirection_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_START_SCALE): + { + sal_Int32 nScale; + if (::sax::Converter::convertPercent( nScale, aIter.toView() )) + mnStartScale = static_cast(nScale); + break; + } + case XML_ELEMENT(PRESENTATION, XML_SPEED): + SvXMLUnitConverter::convertEnum( meSpeed, aIter.toView(), aXML_AnimationSpeed_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_PATH_ID): + maPathShapeId = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLAnimationsEffectContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new XMLAnimationsSoundContext( GetImport(), nElement, xAttrList, this ); +} + +void XMLAnimationsEffectContext::endFastElement(sal_Int32 ) +{ + // set effect on shape + + try + { + if( !maShapeId.isEmpty() ) + { + Reference< XPropertySet > xSet; + if( mxAnimationsContext->maLastShapeId != maShapeId ) + { + xSet.set( GetImport().getInterfaceToIdentifierMapper().getReference( maShapeId ), UNO_QUERY ); + if( xSet.is() ) + { + // check for presentation shape service + { + Reference< XServiceInfo > xServiceInfo( xSet, UNO_QUERY ); + if( !xServiceInfo.is() || !xServiceInfo->supportsService( gsPresShapeService ) ) + return; + } + + mxAnimationsContext->maLastShapeId = maShapeId; + mxAnimationsContext->mxLastShape = xSet; + } + } + else + { + xSet = mxAnimationsContext->mxLastShape; + } + + if( xSet.is() ) + { + if( meKind == XMLE_DIM ) + { + xSet->setPropertyValue( gsDimPrev, Any(true) ); + + xSet->setPropertyValue( gsDimColor, Any(maDimColor) ); + } + else if( meKind == XMLE_PLAY ) + { + xSet->setPropertyValue( gsIsAnimation, Any(true) ); + + // #i42894# speed is not supported for the old group animation fallback, so no need to set it + // aAny <<= meSpeed; + // xSet->setPropertyValue( mpImpl->msSpeed, aAny ); + } + else + { + if( meKind == XMLE_HIDE && !mbTextEffect && meEffect == EK_none ) + { + xSet->setPropertyValue( gsDimHide, Any(true) ); + } + else + { + const AnimationEffect eEffect = ImplSdXMLgetEffect( meEffect, meDirection, mnStartScale, meKind == XMLE_SHOW ); + + if (mbTextEffect) + xSet->setPropertyValue( gsTextEffect, Any( eEffect ) ); + else + xSet->setPropertyValue( gsEffect, Any( eEffect ) ); + xSet->setPropertyValue( gsSpeed, Any( meSpeed ) ); + + if( eEffect == AnimationEffect_PATH && !maPathShapeId.isEmpty() ) + { + Reference< XShape > xPath( GetImport().getInterfaceToIdentifierMapper().getReference( maPathShapeId ), UNO_QUERY ); + if( xPath.is() ) + xSet->setPropertyValue( gsAnimPath, Any( xPath ) ); + } + } + } + } + if( !maSoundURL.isEmpty() ) + { + if( xSet.is() ) + { + xSet->setPropertyValue( gsSound, Any(maSoundURL) ); + xSet->setPropertyValue( gsPlayFull, Any(mbPlayFull) ); + xSet->setPropertyValue( gsSoundOn, Any(true) ); + } + else + { + OSL_FAIL("XMLAnimationsEffectContext::EndElement - Sound URL without a XPropertySet!"); + } + } + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "exception caught while importing animation information!"); + } +} + + +XMLAnimationsContext::XMLAnimationsContext( SvXMLImport& rImport ) +: SvXMLImportContext(rImport) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLAnimationsContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new XMLAnimationsEffectContext( GetImport(), nElement, xAttrList, *this ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/descriptionimp.cxx b/xmloff/source/draw/descriptionimp.cxx new file mode 100644 index 000000000..738f47dd2 --- /dev/null +++ b/xmloff/source/draw/descriptionimp.cxx @@ -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/. + * + * 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 +#include +#include +#include + +#include "descriptionimp.hxx" + +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + + +SdXMLDescriptionContext::SdXMLDescriptionContext( SvXMLImport& rImport, sal_Int32 nElement, const Reference< XShape >& rxShape) +: SvXMLImportContext(rImport), mxShape( rxShape ), mnElement(nElement) +{ +} + +SdXMLDescriptionContext::~SdXMLDescriptionContext() +{ +} + +void SdXMLDescriptionContext::endFastElement(sal_Int32 ) +{ + if( msText.isEmpty() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY_THROW); + if( (mnElement & TOKEN_MASK) == XML_TITLE) + { + xPropSet->setPropertyValue("Title", Any(msText)); + } + else + { + xPropSet->setPropertyValue("Description", Any(msText)); + } + } + catch( uno::Exception& ) + { + } +} + +// This method is called for all characters that are contained in the +// current element. The default is to ignore them. +void SdXMLDescriptionContext::characters( const OUString& rChars ) +{ + msText += rChars; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/descriptionimp.hxx b/xmloff/source/draw/descriptionimp.hxx new file mode 100644 index 000000000..cc9450772 --- /dev/null +++ b/xmloff/source/draw/descriptionimp.hxx @@ -0,0 +1,46 @@ +/* -*- 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 +#include + +// office:events inside a shape + +class SdXMLDescriptionContext final : public SvXMLImportContext +{ +private: + css::uno::Reference< css::drawing::XShape > mxShape; + OUString msText; + sal_Int32 mnElement; +public: + + SdXMLDescriptionContext( SvXMLImport& rImport, sal_Int32 mnElement, + const css::uno::Reference< css::drawing::XShape >& rxShape ); + virtual ~SdXMLDescriptionContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + // This method is called for all characters that are contained in the + // current element. The default is to ignore them. + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/eventimp.cxx b/xmloff/source/draw/eventimp.cxx new file mode 100644 index 000000000..29fc94fda --- /dev/null +++ b/xmloff/source/draw/eventimp.cxx @@ -0,0 +1,454 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include "eventimp.hxx" + +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::presentation; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const aXML_EventActions_EnumMap[] = +{ + { XML_NONE, ClickAction_NONE }, + { XML_PREVIOUS_PAGE, ClickAction_PREVPAGE }, + { XML_NEXT_PAGE, ClickAction_NEXTPAGE }, + { XML_FIRST_PAGE, ClickAction_FIRSTPAGE }, + { XML_LAST_PAGE, ClickAction_LASTPAGE }, + { XML_HIDE, ClickAction_INVISIBLE }, + { XML_STOP, ClickAction_STOPPRESENTATION }, + { XML_EXECUTE, ClickAction_PROGRAM }, + { XML_SHOW, ClickAction_BOOKMARK }, + { XML_SHOW, ClickAction_DOCUMENT }, + { XML_EXECUTE_MACRO, ClickAction_MACRO }, + { XML_VERB, ClickAction_VERB }, + { XML_FADE_OUT, ClickAction_VANISH }, + { XML_SOUND, ClickAction_SOUND }, + { XML_TOKEN_INVALID, ClickAction(0) } +}; + +SdXMLEventContextData::SdXMLEventContextData(const Reference< XShape >& rxShape) + : mxShape(rxShape), mbValid(false), mbScript(false) + , meClickAction(ClickAction_NONE), meEffect(EK_none) + , meDirection(ED_none), mnStartScale(100), meSpeed(AnimationSpeed_MEDIUM) + , mnVerb(0), mbPlayFull(false) +{ +} + +namespace { + +class SdXMLEventContext : public SvXMLImportContext +{ +public: + SdXMLEventContextData maData; + +public: + + SdXMLEventContext( SvXMLImport& rImport, sal_Int32 nElement, const Reference< XFastAttributeList>& xAttrList, const Reference< XShape >& rxShape ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class XMLEventSoundContext : public SvXMLImportContext +{ +public: + + XMLEventSoundContext( SvXMLImport& rImport, const Reference< XFastAttributeList >& xAttrList, SdXMLEventContext* pParent ); +}; + +} + +XMLEventSoundContext::XMLEventSoundContext( SvXMLImport& rImp, const Reference< XFastAttributeList >& xAttrList, SdXMLEventContext* pParent ) +: SvXMLImportContext( rImp ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + pParent->maData.msSoundURL = rImp.GetAbsoluteReference(aIter.toString()); + break; + case XML_ELEMENT(PRESENTATION, XML_PLAY_FULL): + pParent->maData.mbPlayFull = IsXMLToken( aIter, XML_TRUE ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXMLEventContext::SdXMLEventContext( SvXMLImport& rImp, + sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList, const Reference< XShape >& rxShape ) + : SvXMLImportContext(rImp) + , maData(rxShape) +{ + if( nElement == XML_ELEMENT(PRESENTATION, XML_EVENT_LISTENER) ) + { + maData.mbValid = true; + } + else if( nElement == XML_ELEMENT(SCRIPT, XML_EVENT_LISTENER) ) + { + maData.mbScript = true; + maData.mbValid = true; + } + else + { + return; + } + + // read attributes + OUString sEventName; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(PRESENTATION, XML_ACTION): + SvXMLUnitConverter::convertEnum( maData.meClickAction, aIter.toView(), aXML_EventActions_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_EFFECT): + SvXMLUnitConverter::convertEnum( maData.meEffect, aIter.toView(), aXML_AnimationEffect_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_DIRECTION): + SvXMLUnitConverter::convertEnum( maData.meDirection, aIter.toView(), aXML_AnimationDirection_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_START_SCALE): + { + sal_Int32 nScale; + if (::sax::Converter::convertPercent( nScale, aIter.toView() )) + maData.mnStartScale = static_cast(nScale); + } + break; + case XML_ELEMENT(PRESENTATION, XML_SPEED): + SvXMLUnitConverter::convertEnum( maData.meSpeed, aIter.toView(), aXML_AnimationSpeed_EnumMap ); + break; + case XML_ELEMENT(PRESENTATION, XML_VERB): + ::sax::Converter::convertNumber( maData.mnVerb, aIter.toView() ); + break; + case XML_ELEMENT(SCRIPT, XML_EVENT_NAME): + { + sEventName = aIter.toString(); + sal_uInt16 nScriptPrefix = + GetImport().GetNamespaceMap().GetKeyByAttrValueQName(sEventName, &sEventName); + maData.mbValid = XML_NAMESPACE_DOM == nScriptPrefix && sEventName == "click"; + } + break; + case XML_ELEMENT(SCRIPT, XML_LANGUAGE): + { + // language is not evaluated! + OUString aScriptLanguage; + maData.msLanguage = aIter.toString(); + sal_uInt16 nScriptPrefix = rImp.GetNamespaceMap(). + GetKeyByAttrValueQName(maData.msLanguage, &aScriptLanguage); + if( XML_NAMESPACE_OOO == nScriptPrefix ) + maData.msLanguage = aScriptLanguage; + } + break; + case XML_ELEMENT(SCRIPT, XML_MACRO_NAME): + maData.msMacroName = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + { + if ( maData.mbScript ) + { + maData.msMacroName = aIter.toString(); + } + else + { + const OUString &rTmp = + rImp.GetAbsoluteReference(aIter.toString()); + INetURLObject::translateToInternal( rTmp, maData.msBookmark, + INetURLObject::DecodeMechanism::Unambiguous ); + } + } + break; + } + } + + if( maData.mbValid ) + maData.mbValid = !sEventName.isEmpty(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLEventContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(PRESENTATION, XML_SOUND) ) + return new XMLEventSoundContext( GetImport(), xAttrList, this ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SdXMLEventContext::endFastElement(sal_Int32 ) +{ + GetImport().GetShapeImport()->addShapeEvents(maData); +} + +void SdXMLEventContextData::ApplyProperties() +{ + if( !mbValid ) + return; + + do + { + Reference< XEventsSupplier > xEventsSupplier( mxShape, UNO_QUERY ); + if( !xEventsSupplier.is() ) + break; + + Reference< XNameReplace > xEvents( xEventsSupplier->getEvents() ); + SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" ); + if( !xEvents.is() ) + break; + + OUString sAPIEventName; + uno::Sequence< beans::PropertyValue > aProperties; + + sAPIEventName = "OnClick"; + + if( mbScript ) + meClickAction = ClickAction_MACRO; + + sal_Int32 nPropertyCount = 2; + switch( meClickAction ) + { + case ClickAction_NONE: + case ClickAction_PREVPAGE: + case ClickAction_NEXTPAGE: + case ClickAction_FIRSTPAGE: + case ClickAction_LASTPAGE: + case ClickAction_INVISIBLE: + case ClickAction_STOPPRESENTATION: + break; + case ClickAction_PROGRAM: + case ClickAction_VERB: + case ClickAction_BOOKMARK: + case ClickAction_DOCUMENT: + nPropertyCount += 1; + break; + case ClickAction_MACRO: + if ( msLanguage.equalsIgnoreAsciiCase("starbasic") ) + nPropertyCount += 1; + break; + + case ClickAction_SOUND: + nPropertyCount += 2; + break; + + case ClickAction_VANISH: + nPropertyCount += 4; + break; + default: + break; + } + + aProperties.realloc( nPropertyCount ); + beans::PropertyValue* pProperties = aProperties.getArray(); + + if( ClickAction_MACRO == meClickAction ) + { + if ( msLanguage.equalsIgnoreAsciiCase("starbasic") ) + { + OUString sLibrary; + const OUString& rApp = GetXMLToken( XML_APPLICATION ); + const OUString& rDoc = GetXMLToken( XML_DOCUMENT ); + if( msMacroName.getLength() > rApp.getLength()+1 && + o3tl::equalsIgnoreAsciiCase(msMacroName.subView(0,rApp.getLength()), rApp) && + ':' == msMacroName[rApp.getLength()] ) + { + sLibrary = "StarOffice"; + msMacroName = msMacroName.copy( rApp.getLength()+1 ); + } + else if( msMacroName.getLength() > rDoc.getLength()+1 && + o3tl::equalsIgnoreAsciiCase(msMacroName.subView(0,rDoc.getLength()), rDoc) && + ':' == msMacroName[rDoc.getLength()] ) + { + sLibrary = rDoc; + msMacroName = msMacroName.copy( rDoc.getLength()+1 ); + } + + pProperties->Name = "EventType"; + pProperties->Handle = -1; + pProperties->Value <<= OUString( "StarBasic" ); + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "MacroName"; + pProperties->Handle = -1; + pProperties->Value <<= msMacroName; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "Library"; + pProperties->Handle = -1; + pProperties->Value <<= sLibrary; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + } + else + { + pProperties->Name = "EventType"; + pProperties->Handle = -1; + pProperties->Value <<= OUString( "Script" ); + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "Script"; + pProperties->Handle = -1; + pProperties->Value <<= msMacroName; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + } + } + else + { + pProperties->Name = "EventType"; + pProperties->Handle = -1; + pProperties->Value <<= OUString( "Presentation" ); + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + // ClickAction_BOOKMARK and ClickAction_DOCUMENT share the same xml event + // so check here if it's really a bookmark or maybe a document + if( meClickAction == ClickAction_BOOKMARK ) + { + if( !msBookmark.startsWith( "#" ) ) + meClickAction = ClickAction_DOCUMENT; + } + + pProperties->Name = "ClickAction"; + pProperties->Handle = -1; + pProperties->Value <<= meClickAction; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + switch( meClickAction ) + { + case ClickAction_NONE: + case ClickAction_PREVPAGE: + case ClickAction_NEXTPAGE: + case ClickAction_FIRSTPAGE: + case ClickAction_LASTPAGE: + case ClickAction_INVISIBLE: + case ClickAction_STOPPRESENTATION: + break; + + case ClickAction_BOOKMARK: + msBookmark = msBookmark.copy(1); + + [[fallthrough]]; + + case ClickAction_DOCUMENT: + case ClickAction_PROGRAM: + pProperties->Name = "Bookmark"; + pProperties->Handle = -1; + pProperties->Value <<= msBookmark; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + break; + + case ClickAction_VANISH: + pProperties->Name = "Effect"; + pProperties->Handle = -1; + pProperties->Value <<= ImplSdXMLgetEffect( meEffect, meDirection, mnStartScale, true ); + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "Speed"; + pProperties->Handle = -1; + pProperties->Value <<= meSpeed; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + [[fallthrough]]; + + case ClickAction_SOUND: + pProperties->Name = "SoundURL"; + pProperties->Handle = -1; + pProperties->Value <<= msSoundURL; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + pProperties++; + + pProperties->Name = "PlayFull"; + pProperties->Handle = -1; + pProperties->Value <<= mbPlayFull; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + break; + + case ClickAction_VERB: + pProperties->Name = "Verb"; + pProperties->Handle = -1; + pProperties->Value <<= mnVerb; + pProperties->State = beans::PropertyState_DIRECT_VALUE; + break; + case ClickAction_MACRO: + OSL_FAIL("xmloff::SdXMLEventContext::EndElement(), ClickAction_MACRO must be handled in different if case"); + break; + default: + break; + } + } + xEvents->replaceByName( sAPIEventName, uno::Any( aProperties ) ); + + } while(false); +} + + +SdXMLEventsContext::SdXMLEventsContext( SvXMLImport& rImport, const Reference< XShape >& rxShape) +: SvXMLImportContext(rImport), mxShape( rxShape ) +{ +} + +SdXMLEventsContext::~SdXMLEventsContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLEventsContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new SdXMLEventContext( GetImport(), nElement, xAttrList, mxShape ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/eventimp.hxx b/xmloff/source/draw/eventimp.hxx new file mode 100644 index 000000000..bb14aea5e --- /dev/null +++ b/xmloff/source/draw/eventimp.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/. + * + * 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 +#include +#include +#include +#include + +// office:events inside a shape + +class SdXMLEventsContext : public SvXMLImportContext +{ +private: + css::uno::Reference< css::drawing::XShape > mxShape; + +public: + + SdXMLEventsContext( SvXMLImport& rImport, + const css::uno::Reference< css::drawing::XShape >& rxShape ); + virtual ~SdXMLEventsContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +struct SdXMLEventContextData +{ + SdXMLEventContextData(const css::uno::Reference& rxShape); + void ApplyProperties(); + + css::uno::Reference mxShape; + + bool mbValid; + bool mbScript; + css::presentation::ClickAction meClickAction; + XMLEffect meEffect; + XMLEffectDirection meDirection; + sal_Int16 mnStartScale; + css::presentation::AnimationSpeed meSpeed; + sal_Int32 mnVerb; + OUString msSoundURL; + bool mbPlayFull; + OUString msMacroName; + OUString msBookmark; + OUString msLanguage; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/layerexp.cxx b/xmloff/source/draw/layerexp.cxx new file mode 100644 index 000000000..9ac924e92 --- /dev/null +++ b/xmloff/source/draw/layerexp.cxx @@ -0,0 +1,128 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include "layerexp.hxx" +#include + +using ::com::sun::star::uno::Reference; + +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::xmloff::token; + +void SdXMLayerExporter::exportLayer( SvXMLExport& rExport ) +{ + Reference< XLayerSupplier > xLayerSupplier( rExport.GetModel(), UNO_QUERY ); + if( !xLayerSupplier.is() ) + return; + + Reference< XIndexAccess > xLayerManager( xLayerSupplier->getLayerManager(), UNO_QUERY ); + if( !xLayerManager.is() ) + return; + + const sal_Int32 nCount = xLayerManager->getCount(); + if( nCount == 0 ) + return; + + static const OUStringLiteral strName( u"Name" ); + static const OUStringLiteral strTitle( u"Title" ); + static const OUStringLiteral strDescription( u"Description" ); + static const OUStringLiteral strIsVisible( u"IsVisible"); + static const OUStringLiteral strIsPrintable( u"IsPrintable"); + static const OUStringLiteral strIsLocked( u"IsLocked" ); + + OUString sTmp; + + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_LAYER_SET, true, true ); + + for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ ) + { + try + { + Reference< XPropertySet> xLayer( xLayerManager->getByIndex( nIndex ), UNO_QUERY_THROW ); + xLayer->getPropertyValue( strName ) >>= sTmp; + if(!sTmp.isEmpty()) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, sTmp ); + + bool bTmpVisible( true ); + bool bTmpPrintable( true ); + xLayer->getPropertyValue( strIsVisible) >>= bTmpVisible; + xLayer->getPropertyValue( strIsPrintable) >>= bTmpPrintable; + // only write non-default values, default is "always" + if ( bTmpVisible ) + { + if ( !bTmpPrintable ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY, OUString("screen") ); + } + else + { + if ( bTmpPrintable) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY, OUString("printer") ); + else + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY, OUString("none") ); + } + + bool bTmpLocked( false ); + xLayer->getPropertyValue( strIsLocked ) >>= bTmpLocked; + // only write non-default value, default is "false" + if ( bTmpLocked ) + { + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PROTECTED, OUString("true") ); + } + + SvXMLElementExport aEle( rExport, XML_NAMESPACE_DRAW, XML_LAYER, true, true ); + + // title property (as element) + xLayer->getPropertyValue(strTitle) >>= sTmp; + if(!sTmp.isEmpty()) + { + SvXMLElementExport aEventElemt(rExport, XML_NAMESPACE_SVG, XML_TITLE, true, false); + rExport.Characters(sTmp); + } + + // description property (as element) + xLayer->getPropertyValue(strDescription) >>= sTmp; + if(!sTmp.isEmpty()) + { + SvXMLElementExport aDesc(rExport, XML_NAMESPACE_SVG, XML_DESC, true, false); + rExport.Characters(sTmp); + } + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", "exception caught during export of one layer!"); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/layerexp.hxx b/xmloff/source/draw/layerexp.hxx new file mode 100644 index 000000000..76c04e157 --- /dev/null +++ b/xmloff/source/draw/layerexp.hxx @@ -0,0 +1,30 @@ +/* -*- 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 + +class SvXMLExport; + +class SdXMLayerExporter +{ +public: + static void exportLayer(SvXMLExport& rExport); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/layerimp.cxx b/xmloff/source/draw/layerimp.cxx new file mode 100644 index 000000000..73dab831e --- /dev/null +++ b/xmloff/source/draw/layerimp.cxx @@ -0,0 +1,197 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "layerimp.hxx" + + +#include + +using namespace ::std; +using namespace ::cppu; +using namespace ::xmloff::token; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using ::xmloff::token::IsXMLToken; + +namespace { + +class SdXMLLayerContext : public SvXMLImportContext +{ +public: + SdXMLLayerContext( SvXMLImport& rImport, const Reference< XFastAttributeList >& xAttrList, const Reference< XNameAccess >& xLayerManager ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +private: + css::uno::Reference< css::container::XNameAccess > mxLayerManager; + OUString msName; + OUStringBuffer sDescriptionBuffer; + OUStringBuffer sTitleBuffer; + OUString msDisplay; + OUString msProtected; +}; + +} + +SdXMLLayerContext::SdXMLLayerContext( SvXMLImport& rImport, const Reference< XFastAttributeList >& xAttrList, const Reference< XNameAccess >& xLayerManager ) +: SvXMLImportContext(rImport) +, mxLayerManager( xLayerManager ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_NAME): + msName = sValue; + break; + case XML_ELEMENT(DRAW, XML_DISPLAY): + msDisplay = sValue; + break; + case XML_ELEMENT(DRAW, XML_PROTECTED): + msProtected = sValue; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLLayerContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( nElement == XML_ELEMENT(SVG, XML_TITLE) ) + { + return new XMLStringBufferImportContext( GetImport(), sTitleBuffer); + } + else if( nElement == XML_ELEMENT(SVG, XML_DESC) ) + { + return new XMLStringBufferImportContext( GetImport(), sDescriptionBuffer); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SdXMLLayerContext::endFastElement(sal_Int32 ) +{ + SAL_WARN_IF( msName.isEmpty(), "xmloff", "xmloff::SdXMLLayerContext::EndElement(), draw:layer element without draw:name!" ); + if( msName.isEmpty() ) + return; + + try + { + Reference< XPropertySet > xLayer; + + if( mxLayerManager->hasByName( msName ) ) + { + mxLayerManager->getByName( msName ) >>= xLayer; + SAL_WARN_IF( !xLayer.is(), "xmloff", "xmloff::SdXMLLayerContext::EndElement(), failed to get existing XLayer!" ); + } + else + { + Reference< XLayerManager > xLayerManager( mxLayerManager, UNO_QUERY ); + if( xLayerManager.is() ) + xLayer = xLayerManager->insertNewByIndex( xLayerManager->getCount() ); + SAL_WARN_IF( !xLayer.is(), "xmloff", "xmloff::SdXMLLayerContext::EndElement(), failed to create new XLayer!" ); + + if( xLayer.is() ) + xLayer->setPropertyValue("Name", Any( msName ) ); + } + + if( xLayer.is() ) + { + xLayer->setPropertyValue("Title", Any( sTitleBuffer.makeStringAndClear() ) ); + xLayer->setPropertyValue("Description", Any( sDescriptionBuffer.makeStringAndClear() ) ); + bool bIsVisible( true ); + bool bIsPrintable( true ); + if ( !msDisplay.isEmpty() ) + { + bIsVisible = (msDisplay == "always") || (msDisplay == "screen"); + bIsPrintable = (msDisplay == "always") || (msDisplay == "printer"); + } + xLayer->setPropertyValue("IsVisible", Any( bIsVisible ) ); + xLayer->setPropertyValue("IsPrintable", Any( bIsPrintable ) ); + bool bIsLocked( false ); + if ( !msProtected.isEmpty() ) + bIsLocked = (msProtected == "true"); + xLayer->setPropertyValue("IsLocked", Any( bIsLocked ) ); + + // tdf#129898 repair layer "DrawnInSlideshow", which was wrongly written + // in LO 6.2 to 6.4. It should always have ODF defaults. + if (msName == "DrawnInSlideshow") + { + xLayer->setPropertyValue("IsVisible", Any(true)); + xLayer->setPropertyValue("IsPrintable", Any(true)); + xLayer->setPropertyValue("IsLocked", Any(false)); + } + } + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + + +SdXMLLayerSetContext::SdXMLLayerSetContext( SvXMLImport& rImport ) +: SvXMLImportContext(rImport) +{ + Reference< XLayerSupplier > xLayerSupplier( rImport.GetModel(), UNO_QUERY ); + SAL_WARN_IF( !xLayerSupplier.is(), "xmloff", "xmloff::SdXMLLayerSetContext::SdXMLLayerSetContext(), XModel is not supporting XLayerSupplier!" ); + if( xLayerSupplier.is() ) + mxLayerManager = xLayerSupplier->getLayerManager(); +} + +SdXMLLayerSetContext::~SdXMLLayerSetContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLLayerSetContext::createFastChildContext( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + return new SdXMLLayerContext( GetImport(), xAttrList, mxLayerManager ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/layerimp.hxx b/xmloff/source/draw/layerimp.hxx new file mode 100644 index 000000000..4d3b89941 --- /dev/null +++ b/xmloff/source/draw/layerimp.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/. + * + * 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 +#include + +// presentations:animations + +class SdXMLLayerSetContext : public SvXMLImportContext +{ +private: + css::uno::Reference< css::container::XNameAccess > mxLayerManager; + +public: + SdXMLLayerSetContext( SvXMLImport& rImport ); + virtual ~SdXMLLayerSetContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/numithdl.cxx b/xmloff/source/draw/numithdl.cxx new file mode 100644 index 000000000..078ef4826 --- /dev/null +++ b/xmloff/source/draw/numithdl.cxx @@ -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/. + * + * 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 "numithdl.hxx" + +using namespace ::com::sun::star; + + + + +XMLNumRulePropHdl::XMLNumRulePropHdl( css::uno::Reference< css::ucb::XAnyCompare > const & xNumRuleCompare ) +: mxNumRuleCompare( xNumRuleCompare ) +{ +} + +XMLNumRulePropHdl::~XMLNumRulePropHdl() +{ + // Nothing to do +} + +bool XMLNumRulePropHdl::equals( const uno::Any& r1, const uno::Any& r2 ) const +{ + return mxNumRuleCompare.is() && mxNumRuleCompare->compare( r1, r2 ) == 0; +} + +bool XMLNumRulePropHdl::importXML( const OUString& /*rStrImpValue*/, css::uno::Any& /*rValue*/, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + return false; +} + +bool XMLNumRulePropHdl::exportXML( OUString& /*rStrExpValue*/, const css::uno::Any& /*rValue*/, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/numithdl.hxx b/xmloff/source/draw/numithdl.hxx new file mode 100644 index 000000000..91db9c17e --- /dev/null +++ b/xmloff/source/draw/numithdl.hxx @@ -0,0 +1,43 @@ +/* -*- 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 +#include + +/** + PropertyHandler for the list-style +*/ +class XMLNumRulePropHdl : public XMLPropertyHandler +{ +private: + css::uno::Reference< css::ucb::XAnyCompare > mxNumRuleCompare; +public: + explicit XMLNumRulePropHdl( css::uno::Reference< css::ucb::XAnyCompare > const & xNumRuleCompare ); + virtual ~XMLNumRulePropHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + /// NumRules will be imported/exported as XML-Elements. So the Import/Export-work must be done at another place. + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/propimp0.cxx b/xmloff/source/draw/propimp0.cxx new file mode 100644 index 000000000..961aa406d --- /dev/null +++ b/xmloff/source/draw/propimp0.cxx @@ -0,0 +1,263 @@ +/* -*- 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 +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +using namespace ::com::sun::star; + +// implementation of graphic property Stroke + +// implementation of presentation page property Change + +// implementation of an effect duration property handler + +XMLDurationPropertyHdl::~XMLDurationPropertyHdl() +{ +} + +bool XMLDurationPropertyHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + util::Duration aDuration; + + if (::sax::Converter::convertDuration(aDuration, rStrImpValue)) + { + const double fSeconds = ((aDuration.Days * 24 + aDuration.Hours) * 60 + + aDuration.Minutes) * 60 + + aDuration.Seconds + + aDuration.NanoSeconds / static_cast(::tools::Time::nanoSecPerSec); + rValue <<= fSeconds; + + return true; + } + + SAL_WARN_IF(!rStrImpValue.isEmpty(), "xmloff", "Invalid duration: " << rStrImpValue); + + return false; +} + +bool XMLDurationPropertyHdl::exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + double nVal = 0; + + if(rValue >>= nVal) + { + util::Duration aDuration; + aDuration.Seconds = static_cast(nVal); + aDuration.NanoSeconds = static_cast((nVal - aDuration.Seconds) * ::tools::Time::nanoSecPerSec); + + OUStringBuffer aOut; + ::sax::Converter::convertDuration(aOut, aDuration); + rStrExpValue = aOut.makeStringAndClear(); + return true; + } + + return false; +} + +// implementation of an opacity property handler + +XMLOpacityPropertyHdl::XMLOpacityPropertyHdl( SvXMLImport* pImport ) +: mpImport( pImport ) +{ +} + +XMLOpacityPropertyHdl::~XMLOpacityPropertyHdl() +{ +} + +bool XMLOpacityPropertyHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue = 0; + + if( rStrImpValue.indexOf( '%' ) != -1 ) + { + if (::sax::Converter::convertPercent( nValue, rStrImpValue )) + bRet = true; + } + else + { + nValue = sal_Int32( rStrImpValue.toDouble() * 100.0 ); + bRet = true; + } + + if( bRet ) + { + // check ranges + if( nValue < 0 ) + nValue = 0; + if( nValue > 100 ) + nValue = 100; + + // convert xml opacity to api transparency + nValue = 100 - nValue; + + // #i42959# + if( mpImport ) + { + sal_Int32 nUPD, nBuild; + if( mpImport->getBuildIds( nUPD, nBuild ) ) + { + // correct import of documents written prior to StarOffice 8/OOO 2.0 final + if( (nUPD == 680) && (nBuild < 8951) ) + nValue = 100 - nValue; + } + } + + rValue <<= sal_uInt16(nValue); + } + + return bRet; +} + +bool XMLOpacityPropertyHdl::exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nVal = sal_uInt16(); + + if( rValue >>= nVal ) + { + OUStringBuffer aOut; + + nVal = 100 - nVal; + ::sax::Converter::convertPercent( aOut, nVal ); + rStrExpValue = aOut.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + +// implementation of a text animation step amount + +XMLTextAnimationStepPropertyHdl::~XMLTextAnimationStepPropertyHdl() +{ +} + +bool XMLTextAnimationStepPropertyHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int32 nValue = 0; + + sal_Int32 nPos = rStrImpValue.indexOf( "px" ); + if( nPos != -1 ) + { + if (::sax::Converter::convertNumber(nValue, rStrImpValue.subView(0, nPos))) + { + rValue <<= sal_Int16( -nValue ); + bRet = true; + } + } + else + { + if (rUnitConverter.convertMeasureToCore( nValue, rStrImpValue )) + { + rValue <<= sal_Int16( nValue ); + bRet = true; + } + } + + return bRet; +} + +bool XMLTextAnimationStepPropertyHdl::exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int16 nVal = sal_Int16(); + + if( rValue >>= nVal ) + { + OUStringBuffer aOut; + + if( nVal < 0 ) + { + aOut.append( static_cast(-nVal) ); + aOut.append( "px" ); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, nVal ); + } + + rStrExpValue = aOut.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + +XMLDateTimeFormatHdl::XMLDateTimeFormatHdl( SvXMLExport* pExport ) +: mpExport( pExport ) +{ +} + +XMLDateTimeFormatHdl::~XMLDateTimeFormatHdl() +{ +} + +bool XMLDateTimeFormatHdl::importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + rValue <<= rStrImpValue; + return true; +} + +bool XMLDateTimeFormatHdl::exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nNumberFormat = 0; + if( mpExport && (rValue >>= nNumberFormat) ) + { + mpExport->addDataStyle( nNumberFormat ); + rStrExpValue = mpExport->getDataStyleName( nNumberFormat ); + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdpropls.cxx b/xmloff/source/draw/sdpropls.cxx new file mode 100644 index 000000000..5e68aa175 --- /dev/null +++ b/xmloff/source/draw/sdpropls.cxx @@ -0,0 +1,1883 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "numithdl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sdpropls.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::com::sun::star::uno::Any; + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +#define MAP_(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_010, false } +#define MAPV_(name,prefix,token,type,context,version) { name, prefix, token, type, context, version, false } +#define GMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_GRAPHIC,context) +#define GMAP_D(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_GRAPHIC|MID_FLAG_DEFAULT_ITEM_EXPORT,context) +#define GMAPV(name,prefix,token,type,context,version) MAPV_(name,prefix,token,type|XML_TYPE_PROP_GRAPHIC,context,version) +#define DPMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_DRAWING_PAGE,context) +#define TMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TEXT,context) +#define PMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_PARAGRAPH,context) +#define MAP_END() { nullptr, 0, XML_EMPTY, 0 ,0, SvtSaveOptions::ODFSVER_010, false } + +// entry list for graphic properties + +const XMLPropertyMapEntry aXMLSDProperties[] = +{ + // this entry must be first! this is needed for XMLShapeImportHelper::CreateExternalShapePropMapper + + // ^^^though CreateExternalShapePropMapper is gone now, hmm^^^ + GMAP( "UserDefinedAttributes", XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + + // stroke attributes + GMAP( "LineStyle", XML_NAMESPACE_DRAW, XML_STROKE, XML_SD_TYPE_STROKE, 0 ), + GMAP( "LineDashName", XML_NAMESPACE_DRAW, XML_STROKE_DASH, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT , CTF_DASHNAME ), + GMAP( "LineWidth", XML_NAMESPACE_SVG, XML_STROKE_WIDTH, XML_TYPE_MEASURE, 0 ), + GMAP_D("LineColor", XML_NAMESPACE_SVG, XML_STROKE_COLOR, XML_TYPE_COLOR, 0), + GMAP( "LineStartName", XML_NAMESPACE_DRAW, XML_MARKER_START, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_LINESTARTNAME ), + GMAP( "LineStartWidth", XML_NAMESPACE_DRAW, XML_MARKER_START_WIDTH, XML_TYPE_MEASURE, 0 ), + GMAP( "LineStartCenter", XML_NAMESPACE_DRAW, XML_MARKER_START_CENTER, XML_TYPE_BOOL, 0 ), + GMAP( "LineEndName", XML_NAMESPACE_DRAW, XML_MARKER_END, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_LINEENDNAME ), + GMAP( "LineEndWidth", XML_NAMESPACE_DRAW, XML_MARKER_END_WIDTH, XML_TYPE_MEASURE, 0 ), + GMAP( "LineEndCenter", XML_NAMESPACE_DRAW, XML_MARKER_END_CENTER, XML_TYPE_BOOL, 0 ), + GMAP( "LineTransparence", XML_NAMESPACE_SVG, XML_STROKE_OPACITY, XML_SD_TYPE_OPACITY, 0 ), + GMAP( "LineJoint", XML_NAMESPACE_DRAW, XML_STROKE_LINEJOIN, XML_SD_TYPE_LINEJOIN, 0 ), + GMAP( "LineCap", XML_NAMESPACE_SVG , XML_STROKE_LINECAP, XML_SD_TYPE_LINECAP, 0 ), + + // fill attributes + GMAP( "FillStyle", XML_NAMESPACE_DRAW, XML_FILL, XML_SD_TYPE_FILLSTYLE, CTF_FILLSTYLE ), + GMAP_D("FillColor", XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, CTF_FILLCOLOR ), + GMAP_D("FillColor2", XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0), + GMAPV("FillColorTheme", XML_NAMESPACE_LO_EXT, XML_FILL_THEME_COLOR, XML_TYPE_THEME_COLOR, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FillColorLumMod", XML_NAMESPACE_LO_EXT, XML_FILL_COLOR_LUM_MOD, XML_TYPE_PERCENT100, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FillColorLumOff", XML_NAMESPACE_LO_EXT, XML_FILL_COLOR_LUM_OFF, XML_TYPE_PERCENT100, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAP( "FillGradientName", XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLGRADIENTNAME ), + GMAP( "FillGradientStepCount", XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0 ), + GMAP( "FillHatchName", XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLHATCHNAME ), + GMAP( "FillBackground", XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + GMAPV( "FillUseSlideBackground", XML_NAMESPACE_LO_EXT, XML_FILL_USE_SLIDE_BACKGROUND, XML_TYPE_BOOL, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAP( "FillBitmapName", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLBITMAPNAME ), + GMAP( "FillTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( "FillTransparenceGradientName", XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLTRANSNAME ), + GMAP( "FillBitmapSizeX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SD_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SD_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapSizeY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SD_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SD_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapMode", XML_NAMESPACE_STYLE,XML_REPEAT, XML_SD_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapPositionOffsetX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + GMAP( "FillBitmapPositionOffsetY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + GMAP( "FillBitmapRectanglePoint", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SD_TYPE_BITMAP_REFPOINT, 0 ), + GMAP( "FillBitmapOffsetX", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SD_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_X ), + GMAP( "FillBitmapOffsetY", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SD_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_Y ), + + // text frame attributes + GMAP( "TextHorizontalAdjust", XML_NAMESPACE_DRAW, XML_TEXTAREA_HORIZONTAL_ALIGN, XML_SD_TYPE_TEXT_ALIGN, 0 ), + GMAP( "TextVerticalAdjust", XML_NAMESPACE_DRAW, XML_TEXTAREA_VERTICAL_ALIGN, XML_SD_TYPE_VERTICAL_ALIGN, 0 ), + GMAP( "TextAutoGrowHeight", XML_NAMESPACE_DRAW, XML_AUTO_GROW_HEIGHT, XML_TYPE_BOOL, 0 ), + GMAP( "TextAutoGrowWidth", XML_NAMESPACE_DRAW, XML_AUTO_GROW_WIDTH, XML_TYPE_BOOL, 0 ), + GMAP( "TextFitToSize", XML_NAMESPACE_DRAW, XML_FIT_TO_SIZE, XML_SD_TYPE_FITTOSIZE|MID_FLAG_MERGE_PROPERTY, 0), + GMAPV( "TextFitToSize", XML_NAMESPACE_STYLE, XML_SHRINK_TO_FIT, XML_SD_TYPE_FITTOSIZE_AUTOFIT|MID_FLAG_MERGE_PROPERTY, 0, SvtSaveOptions::ODFSVER_012 ), + GMAP( "TextContourFrame", XML_NAMESPACE_DRAW, XML_FIT_TO_CONTOUR, XML_TYPE_BOOL, 0 ), + GMAP( "TextMaximumFrameHeight", XML_NAMESPACE_FO, XML_MAX_HEIGHT, XML_TYPE_MEASURE, 0 ), + GMAP( "TextMaximumFrameWidth", XML_NAMESPACE_FO, XML_MAX_WIDTH, XML_TYPE_MEASURE, 0 ), + GMAP( "TextMinimumFrameHeight", XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( "TextMinimumFrameWidth", XML_NAMESPACE_FO, XML_MIN_WIDTH, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "TextUpperDistance", XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( "TextLowerDistance", XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( "TextLeftDistance", XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( "TextRightDistance", XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + PMAP( "TextWritingMode", XML_NAMESPACE_STYLE,XML_WRITING_MODE, XML_SD_TYPE_WRITINGMODE|MID_FLAG_MULTI_PROPERTY, CTF_WRITINGMODE ), + GMAP( "NumberingRules", XML_NAMESPACE_TEXT, XML_LIST_STYLE, XML_SD_TYPE_NUMBULLET|MID_FLAG_ELEMENT_ITEM, CTF_NUMBERINGRULES ), + GMAP( "NumberingRules", XML_NAMESPACE_TEXT, XML_LIST_STYLE_NAME, XML_TYPE_STRING, CTF_SD_NUMBERINGRULES_NAME ), + GMAP( "TextWordWrap", XML_NAMESPACE_FO, XML_WRAP_OPTION, XML_TYPE_WRAP_OPTION, 0 ), + GMAP( "TextChainNextName", XML_NAMESPACE_DRAW, XML_CHAIN_NEXT_NAME, XML_TYPE_STRING, 0 ), + + GMAP( "TextColumns", XML_NAMESPACE_STYLE, XML_COLUMNS, XML_TYPE_TEXT_COLUMNS|MID_FLAG_ELEMENT_ITEM, CTF_TEXTCOLUMNS ), + + // shadow attributes + GMAP( "Shadow", XML_NAMESPACE_DRAW, XML_SHADOW, XML_SD_TYPE_VISIBLE_HIDDEN, 0 ), + GMAP( "ShadowXDistance", XML_NAMESPACE_DRAW, XML_SHADOW_OFFSET_X, XML_TYPE_MEASURE, 0 ), + GMAP( "ShadowYDistance", XML_NAMESPACE_DRAW, XML_SHADOW_OFFSET_Y, XML_TYPE_MEASURE, 0 ), + GMAP( "ShadowColor", XML_NAMESPACE_DRAW, XML_SHADOW_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( "ShadowTransparence", XML_NAMESPACE_DRAW, XML_SHADOW_OPACITY, XML_TYPE_NEG_PERCENT, 0 ), + GMAPV( "ShadowBlur", XML_NAMESPACE_LO_EXT, XML_SHADOW_BLUR, XML_TYPE_MEASURE, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + + // glow attributes + GMAPV( "GlowEffectRadius", XML_NAMESPACE_LO_EXT, XML_GLOW_RADIUS, XML_TYPE_MEASURE , 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( "GlowEffectColor", XML_NAMESPACE_LO_EXT, XML_GLOW_COLOR, XML_TYPE_COLOR , 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV( "GlowEffectTransparency", XML_NAMESPACE_LO_EXT, XML_GLOW_TRANSPARENCY, XML_TYPE_PERCENT16, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + + // soft edge attributes + GMAPV( "SoftEdgeRadius", XML_NAMESPACE_LO_EXT, XML_SOFTEDGE_RADIUS, XML_TYPE_MEASURE , 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + + // graphic attributes + GMAP( "GraphicColorMode", XML_NAMESPACE_DRAW, XML_COLOR_MODE, XML_TYPE_COLOR_MODE, 0 ), // exists in SW, too, with same property name + GMAP( "AdjustLuminance", XML_NAMESPACE_DRAW, XML_LUMINANCE, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAP( "AdjustContrast", XML_NAMESPACE_DRAW, XML_CONTRAST, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAP( "Gamma", XML_NAMESPACE_DRAW, XML_GAMMA, XML_TYPE_DOUBLE_PERCENT, 0 ), // signed? exists in SW, too, with same property name + GMAP( "AdjustRed", XML_NAMESPACE_DRAW, XML_RED, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAP( "AdjustGreen", XML_NAMESPACE_DRAW, XML_GREEN, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAP( "AdjustBlue", XML_NAMESPACE_DRAW, XML_BLUE, XML_TYPE_PERCENT16, 0 ), // signed? exists in SW, too, with same property name + GMAPV( "GraphicCrop", XML_NAMESPACE_FO, XML_CLIP, XML_TYPE_TEXT_CLIP, CTF_TEXT_CLIP, SvtSaveOptions::ODFSVER_012), // exists in SW, too, with same property name + GMAP( "GraphicCrop", XML_NAMESPACE_FO, XML_CLIP, XML_TYPE_TEXT_CLIP11, CTF_TEXT_CLIP11 ), // exists in SW, too, with same property name + GMAP( "Transparency", XML_NAMESPACE_DRAW, XML_IMAGE_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too, with same property name // #i25616# + GMAP( "IsMirrored", XML_NAMESPACE_STYLE, XML_MIRROR, XML_TYPE_SD_MIRROR|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too // #i40214# + + // animation text attributes + TMAP( "TextAnimationKind", XML_NAMESPACE_STYLE,XML_TEXT_BLINKING, XML_TYPE_TEXT_ANIMATION_BLINKING, CTF_TEXTANIMATION_BLINKING ), + GMAP( "TextAnimationKind", XML_NAMESPACE_TEXT, XML_ANIMATION, XML_TYPE_TEXT_ANIMATION, CTF_TEXTANIMATION_KIND ), + GMAP( "TextAnimationDirection", XML_NAMESPACE_TEXT, XML_ANIMATION_DIRECTION, XML_TYPE_TEXT_ANIMATION_DIRECTION, 0 ), + GMAP( "TextAnimationStartInside", XML_NAMESPACE_TEXT, XML_ANIMATION_START_INSIDE, XML_TYPE_BOOL, 0 ), + GMAP( "TextAnimationStopInside", XML_NAMESPACE_TEXT, XML_ANIMATION_STOP_INSIDE, XML_TYPE_BOOL, 0 ), + GMAP( "TextAnimationCount", XML_NAMESPACE_TEXT, XML_ANIMATION_REPEAT, XML_TYPE_NUMBER16, 0 ), + GMAP( "TextAnimationDelay", XML_NAMESPACE_TEXT, XML_ANIMATION_DELAY, XML_TYPE_DURATION16_MS, 0 ), + GMAP( "TextAnimationAmount", XML_NAMESPACE_TEXT, XML_ANIMATION_STEPS, XML_TYPE_TEXT_ANIMATION_STEPS, 0 ), + + // connector attributes + GMAP( "EdgeNode1HorzDist", XML_NAMESPACE_DRAW, XML_START_LINE_SPACING_HORIZONTAL, XML_TYPE_MEASURE, 0 ), + GMAP( "EdgeNode1VertDist", XML_NAMESPACE_DRAW, XML_START_LINE_SPACING_VERTICAL, XML_TYPE_MEASURE, 0 ), + GMAP( "EdgeNode2HorzDist", XML_NAMESPACE_DRAW, XML_END_LINE_SPACING_HORIZONTAL, XML_TYPE_MEASURE, 0 ), + GMAP( "EdgeNode2VertDist", XML_NAMESPACE_DRAW, XML_END_LINE_SPACING_VERTICAL, XML_TYPE_MEASURE, 0 ), + + // measure attributes + GMAP( "MeasureLineDistance", XML_NAMESPACE_DRAW, XML_LINE_DISTANCE, XML_TYPE_MEASURE, 0 ), + GMAP( "MeasureHelpLineOverhang", XML_NAMESPACE_DRAW, XML_GUIDE_OVERHANG, XML_TYPE_MEASURE, 0 ), + GMAP( "MeasureHelpLineDistance", XML_NAMESPACE_DRAW, XML_GUIDE_DISTANCE, XML_TYPE_MEASURE, 0 ), + GMAP( "MeasureHelpLine1Length", XML_NAMESPACE_DRAW, XML_START_GUIDE, XML_TYPE_MEASURE, 0 ), + GMAP( "MeasureHelpLine2Length", XML_NAMESPACE_DRAW, XML_END_GUIDE, XML_TYPE_MEASURE, 0 ), + GMAP( "MeasureTextHorizontalPosition", XML_NAMESPACE_DRAW, XML_MEASURE_ALIGN, XML_SD_TYPE_MEASURE_HALIGN, 0 ), + GMAP( "MeasureTextVerticalPosition", XML_NAMESPACE_DRAW, XML_MEASURE_VERTICAL_ALIGN, XML_SD_TYPE_MEASURE_VALIGN, 0 ), + GMAP( "MeasureUnit", XML_NAMESPACE_DRAW, XML_UNIT, XML_SD_TYPE_MEASURE_UNIT, 0 ), + GMAP( "MeasureShowUnit", XML_NAMESPACE_DRAW, XML_SHOW_UNIT, XML_TYPE_BOOL, 0 ), + GMAP( "MeasureBelowReferenceEdge", XML_NAMESPACE_DRAW, XML_PLACING, XML_SD_TYPE_MEASURE_PLACING, 0 ), + GMAP( "MeasureTextRotate90", XML_NAMESPACE_DRAW, XML_PARALLEL, XML_TYPE_BOOL, 0 ), + GMAP( "MeasureDecimalPlaces", XML_NAMESPACE_DRAW, XML_DECIMAL_PLACES, XML_TYPE_NUMBER16, 0 ), + + // 3D geometry attributes + GMAP( "D3DHorizontalSegments", XML_NAMESPACE_DR3D, XML_HORIZONTAL_SEGMENTS, XML_TYPE_NUMBER, 0 ), + GMAP( "D3DVerticalSegments", XML_NAMESPACE_DR3D, XML_VERTICAL_SEGMENTS, XML_TYPE_NUMBER, 0 ), + GMAP( "D3DPercentDiagonal", XML_NAMESPACE_DR3D, XML_EDGE_ROUNDING, XML_TYPE_PERCENT, 0 ), + GMAP( "D3DBackscale", XML_NAMESPACE_DR3D, XML_BACK_SCALE, XML_TYPE_PERCENT, 0 ), + GMAP( "D3DEndAngle", XML_NAMESPACE_DR3D, XML_END_ANGLE, XML_TYPE_NUMBER, 0 ), + GMAP( "D3DDepth", XML_NAMESPACE_DR3D, XML_DEPTH, XML_TYPE_MEASURE, 0 ), + GMAP( "D3DDoubleSided", XML_NAMESPACE_DR3D, XML_BACKFACE_CULLING, XML_SD_TYPE_BACKFACE_CULLING, 0 ), + + // #107245# New 3D properties which are possible for lathe and extrude 3d objects + GMAP( "D3DCloseFront", XML_NAMESPACE_DR3D, XML_CLOSE_FRONT, XML_TYPE_BOOL, 0 ), + GMAP( "D3DCloseBack", XML_NAMESPACE_DR3D, XML_CLOSE_BACK, XML_TYPE_BOOL, 0 ), + + // 3D lighting attributes + GMAP( "D3DNormalsKind", XML_NAMESPACE_DR3D, XML_NORMALS_KIND, XML_SD_TYPE_NORMALS_KIND, 0 ), + GMAP( "D3DNormalsInvert", XML_NAMESPACE_DR3D, XML_NORMALS_DIRECTION, XML_SD_TYPE_NORMALS_DIRECTION, 0 ), + + // 3D texture attributes + GMAP( "D3DTextureProjectionX", XML_NAMESPACE_DR3D, XML_TEX_GENERATION_MODE_X, XML_SD_TYPE_TEX_GENERATION_MODE_X, 0 ), + GMAP( "D3DTextureProjectionY", XML_NAMESPACE_DR3D, XML_TEX_GENERATION_MODE_Y, XML_SD_TYPE_TEX_GENERATION_MODE_Y, 0 ), + GMAP( "D3DTextureKind", XML_NAMESPACE_DR3D, XML_TEX_KIND, XML_SD_TYPE_TEX_KIND, 0 ), + GMAP( "D3DTextureMode", XML_NAMESPACE_DR3D, XML_TEX_MODE, XML_SD_TYPE_TEX_MODE, 0 ), + GMAP( "D3DTextureFilter", XML_NAMESPACE_DR3D, XML_TEX_FILTER, XML_SD_TYPE_BACKFACE_CULLING, 0 ), + + // 3D material attributes + GMAP( "D3DMaterialColor", XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( "D3DMaterialEmission", XML_NAMESPACE_DR3D, XML_EMISSIVE_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( "D3DMaterialSpecular", XML_NAMESPACE_DR3D, XML_SPECULAR_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( "D3DMaterialSpecularIntensity", XML_NAMESPACE_DR3D, XML_SHININESS, XML_TYPE_PERCENT, 0 ), + + // 3D shadow attributes + GMAP( "D3DShadow3D", XML_NAMESPACE_DR3D, XML_SHADOW, XML_SD_TYPE_VISIBLE_HIDDEN, 0 ), + + // #FontWork# attributes + GMAP( "FontWorkStyle", XML_NAMESPACE_DRAW, XML_FONTWORK_STYLE, XML_SD_TYPE_FONTWORK_STYLE| MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_STYLE ), + GMAP( "FontWorkAdjust", XML_NAMESPACE_DRAW, XML_FONTWORK_ADJUST, XML_SD_TYPE_FONTWORK_ADJUST | MID_FLAG_ELEMENT_ITEM_EXPORT,CTF_FONTWORK_ADJUST ), + GMAP( "FontWorkDistance", XML_NAMESPACE_DRAW, XML_FONTWORK_DISTANCE, XML_TYPE_MEASURE | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_DISTANCE ), + GMAP( "FontWorkStart", XML_NAMESPACE_DRAW, XML_FONTWORK_START, XML_TYPE_MEASURE | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_START ), + GMAP( "FontWorkMirror", XML_NAMESPACE_DRAW, XML_FONTWORK_MIRROR, XML_TYPE_BOOL | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_MIRROR ), + GMAP( "FontWorkOutline", XML_NAMESPACE_DRAW, XML_FONTWORK_OUTLINE, XML_TYPE_BOOL | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_OUTLINE ), + GMAP( "FontWorkShadow", XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW, XML_SD_TYPE_FONTWORK_SHADOW | MID_FLAG_ELEMENT_ITEM_EXPORT,CTF_FONTWORK_SHADOW ), + GMAP( "FontWorkShadowColor", XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_COLOR, XML_TYPE_COLOR | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_SHADOWCOLOR ), + GMAP( "FontWorkShadowOffsetX", XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_OFFSET_X, XML_TYPE_MEASURE | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_SHADOWOFFSETX ), + GMAP( "FontWorkShadowOffsetY", XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_OFFSET_Y, XML_TYPE_MEASURE | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_SHADOWOFFSETY ), + GMAP( "FontWorkForm", XML_NAMESPACE_DRAW, XML_FONTWORK_FORM, XML_SD_TYPE_FONTWORK_FORM | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_FORM ), + GMAP( "FontWorkHideForm", XML_NAMESPACE_DRAW, XML_FONTWORK_HIDE_FORM, XML_TYPE_BOOL | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_HIDEFORM ), + GMAP( "FontWorkShadowTransparence", XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_TRANSPARENCE, XML_TYPE_PERCENT | MID_FLAG_ELEMENT_ITEM_EXPORT, CTF_FONTWORK_SHADOWTRANSPARENCE ), + + // #FontWork# attributes + GMAPV("FontWorkStyle", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_STYLE, XML_SD_TYPE_FONTWORK_STYLE, CTF_FONTWORK_STYLE, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkAdjust", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_ADJUST, XML_SD_TYPE_FONTWORK_ADJUST,CTF_FONTWORK_ADJUST, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkDistance", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_DISTANCE, XML_TYPE_MEASURE, CTF_FONTWORK_DISTANCE, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkStart", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_START, XML_TYPE_MEASURE, CTF_FONTWORK_START, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkMirror", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_MIRROR, XML_TYPE_BOOL, CTF_FONTWORK_MIRROR, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkOutline", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_OUTLINE, XML_TYPE_BOOL, CTF_FONTWORK_OUTLINE, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkShadow", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW, XML_SD_TYPE_FONTWORK_SHADOW,CTF_FONTWORK_SHADOW, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkShadowColor", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW_COLOR, XML_TYPE_COLOR, CTF_FONTWORK_SHADOWCOLOR, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkShadowOffsetX", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW_OFFSET_X, XML_TYPE_MEASURE, CTF_FONTWORK_SHADOWOFFSETX, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkShadowOffsetY", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW_OFFSET_Y, XML_TYPE_MEASURE, CTF_FONTWORK_SHADOWOFFSETY, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkForm", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_FORM, XML_SD_TYPE_FONTWORK_FORM, CTF_FONTWORK_FORM, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkHideForm", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_HIDE_FORM, XML_TYPE_BOOL, CTF_FONTWORK_HIDEFORM, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + GMAPV("FontWorkShadowTransparence", XML_NAMESPACE_DRAW_EXT, XML_FONTWORK_SHADOW_TRANSPARENCE, XML_TYPE_PERCENT, CTF_FONTWORK_SHADOWTRANSPARENCE, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + + // control attributes (border exists one more time for the text additions of shapes) + GMAP( "ControlSymbolColor", XML_NAMESPACE_DRAW, XML_SYMBOL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( "ControlBackground", XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "ControlBorder", XML_NAMESPACE_FO, XML_BORDER, XML_SD_TYPE_CONTROL_BORDER|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + GMAP( "ControlBorderColor", XML_NAMESPACE_FO, XML_BORDER, XML_SD_TYPE_CONTROL_BORDER_COLOR|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + GMAP( "ControlDataStyle", XML_NAMESPACE_STYLE,XML_DATA_STYLE_NAME, XML_TYPE_STRING|MID_FLAG_NO_PROPERTY_EXPORT|MID_FLAG_SPECIAL_ITEM, CTF_SD_CONTROL_SHAPE_DATA_STYLE ), + GMAP( "ControlTextEmphasis", XML_NAMESPACE_STYLE,XML_TEXT_EMPHASIZE, XML_TYPE_CONTROL_TEXT_EMPHASIZE, 0 ), + GMAP( "ImageScaleMode", XML_NAMESPACE_STYLE,XML_REPEAT, XML_SD_TYPE_IMAGE_SCALE_MODE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "ControlWritingMode", XML_NAMESPACE_STYLE,XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT|MID_FLAG_MULTI_PROPERTY, CTF_CONTROLWRITINGMODE ), + + // special entries for floating frames + GMAP( "FrameIsAutoScroll", XML_NAMESPACE_DRAW, XML_FRAME_DISPLAY_SCROLLBAR, XML_TYPE_BOOL|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_DISPLAY_SCROLLBAR ), + GMAP( "FrameIsBorder", XML_NAMESPACE_DRAW, XML_FRAME_DISPLAY_BORDER, XML_TYPE_BOOL|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_DISPLAY_BORDER ), + GMAP( "FrameMarginWidth", XML_NAMESPACE_DRAW, XML_FRAME_MARGIN_HORIZONTAL, XML_TYPE_MEASURE_PX|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_MARGIN_HORI ), + GMAP( "FrameMarginHeight", XML_NAMESPACE_DRAW, XML_FRAME_MARGIN_VERTICAL, XML_TYPE_MEASURE_PX|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_MARGIN_VERT ), + GMAP( "VisibleArea", XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_LEFT, XML_TYPE_RECTANGLE_LEFT|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY, CTF_SD_OLE_VIS_AREA_IMPORT_LEFT ), + GMAP( "VisibleArea", XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_TOP, XML_TYPE_RECTANGLE_TOP|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY, CTF_SD_OLE_VIS_AREA_IMPORT_TOP ), + GMAP( "VisibleArea", XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_WIDTH, XML_TYPE_RECTANGLE_WIDTH|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY, CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH ), + GMAP( "VisibleArea", XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_HEIGHT, XML_TYPE_RECTANGLE_HEIGHT|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY, CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT ), + GMAP( "IsInternal", XML_NAMESPACE_DRAW, XML__EMPTY, XML_TYPE_BUILDIN_CMP_ONLY, CTF_SD_OLE_ISINTERNAL ), + GMAP( "IsInternal", XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_LEFT, XML_TYPE_RECTANGLE_LEFT|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_SD_OLE_VIS_AREA_EXPORT_LEFT ), + GMAP( "IsInternal", XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_TOP, XML_TYPE_RECTANGLE_TOP|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_SD_OLE_VIS_AREA_EXPORT_TOP ), + GMAP( "IsInternal", XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_WIDTH, XML_TYPE_RECTANGLE_WIDTH|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_SD_OLE_VIS_AREA_EXPORT_WIDTH ), + GMAP( "IsInternal", XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_HEIGHT, XML_TYPE_RECTANGLE_HEIGHT|MID_FLAG_MERGE_PROPERTY|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_SD_OLE_VIS_AREA_EXPORT_HEIGHT ), + + GMAP( "Aspect", XML_NAMESPACE_DRAW, XML_DRAW_ASPECT, XML_TYPE_TEXT_DRAW_ASPECT|MID_FLAG_MULTI_PROPERTY, CTF_SD_OLE_ASPECT ), + + // caption properties + GMAP( "CaptionType", XML_NAMESPACE_DRAW, XML_CAPTION_TYPE, XML_SD_TYPE_CAPTION_TYPE, 0 ), + GMAP( "CaptionIsFixedAngle", XML_NAMESPACE_DRAW, XML_CAPTION_ANGLE_TYPE, XML_SD_TYPE_CAPTION_ANGLE_TYPE, 0 ), + GMAP( "CaptionAngle", XML_NAMESPACE_DRAW, XML_CAPTION_ANGLE, XML_TYPE_NUMBER, 0 ), + GMAP( "CaptionGap", XML_NAMESPACE_DRAW, XML_CAPTION_GAP, XML_TYPE_MEASURE, 0 ), + GMAP( "CaptionEscapeDirection", XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE_DIRECTION, XML_SD_TYPE_CAPTION_ESC_DIR, 0 ), + GMAP( "CaptionIsEscapeRelative", XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE, XML_SD_TYPE_CAPTION_IS_ESC_REL|MID_FLAG_MULTI_PROPERTY, CTF_CAPTION_ISESCREL ), + GMAP( "CaptionEscapeRelative", XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE, XML_SD_TYPE_CAPTION_ESC_REL|MID_FLAG_MULTI_PROPERTY, CTF_CAPTION_ESCREL ), + GMAP( "CaptionEscapeAbsolute", XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE, XML_SD_TYPE_CAPTION_ESC_ABS|MID_FLAG_MULTI_PROPERTY, CTF_CAPTION_ESCABS ), + GMAP( "CaptionLineLength", XML_NAMESPACE_DRAW, XML_CAPTION_LINE_LENGTH, XML_TYPE_MEASURE, 0 ), + GMAP( "CaptionIsFitLineLength", XML_NAMESPACE_DRAW, XML_CAPTION_FIT_LINE_LENGTH, XML_TYPE_BOOL, 0 ), + + // misc object properties + GMAP( "MoveProtect", XML_NAMESPACE_STYLE, XML_PROTECT, XML_SD_TYPE_MOVE_PROTECT|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, CTF_SD_MOVE_PROTECT ), + GMAP( "SizeProtect", XML_NAMESPACE_STYLE, XML_PROTECT, XML_SD_TYPE_SIZE_PROTECT|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, CTF_SD_SIZE_PROTECT ), + + MAP_END() +}; + +// entry list for presentation page properties + +const XMLPropertyMapEntry aXMLSDPresPageProps[] = +{ + DPMAP( "UserDefinedAttributes", XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + + DPMAP( "Change", XML_NAMESPACE_PRESENTATION, XML_TRANSITION_TYPE, XML_SD_TYPE_PRESPAGE_TYPE, CTF_PAGE_TRANS_TYPE ), + DPMAP( "Effect", XML_NAMESPACE_PRESENTATION, XML_TRANSITION_STYLE, XML_SD_TYPE_PRESPAGE_STYLE, CTF_PAGE_TRANS_STYLE ), + DPMAP( "Speed", XML_NAMESPACE_PRESENTATION, XML_TRANSITION_SPEED, XML_SD_TYPE_PRESPAGE_SPEED, CTF_PAGE_TRANS_SPEED ), + DPMAP( "HighResDuration", XML_NAMESPACE_PRESENTATION, XML_DURATION, XML_SD_TYPE_PRESPAGE_DURATION, CTF_PAGE_TRANS_DURATION ), + DPMAP( "Visible", XML_NAMESPACE_PRESENTATION, XML_VISIBILITY, XML_SD_TYPE_PRESPAGE_VISIBILITY, CTF_PAGE_VISIBLE ), + DPMAP( "Sound", XML_NAMESPACE_PRESENTATION, XML_SOUND, XML_TYPE_STRING|MID_FLAG_ELEMENT_ITEM, CTF_PAGE_SOUND_URL ), + DPMAP( "BackgroundFullSize", XML_NAMESPACE_DRAW, XML_BACKGROUND_SIZE, XML_SD_TYPE_PRESPAGE_BACKSIZE, CTF_PAGE_BACKSIZE ), + + DPMAP( "IsBackgroundVisible", XML_NAMESPACE_PRESENTATION, XML_BACKGROUND_VISIBLE, XML_TYPE_BOOL, 0 ), + DPMAP( "IsBackgroundObjectsVisible", XML_NAMESPACE_PRESENTATION, XML_BACKGROUND_OBJECTS_VISIBLE, XML_TYPE_BOOL, 0 ), + + DPMAP( "FillStyle", XML_NAMESPACE_DRAW, XML_FILL, XML_SD_TYPE_FILLSTYLE, 0 ), + DPMAP( "FillColor", XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0 ), + DPMAP( "FillGradientName", XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLGRADIENTNAME ), + DPMAP( "FillGradientStepCount", XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER, 0 ), + DPMAP( "FillHatchName", XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLHATCHNAME ), + GMAP( "FillBackground", XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + DPMAP( "FillBitmapName", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLBITMAPNAME ), + DPMAP( "FillTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( "FillTransparenceGradientName", XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLTRANSNAME ), + DPMAP( "FillBitmapSizeX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SD_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SD_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( "FillBitmapSizeY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SD_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SD_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + DPMAP( "FillBitmapMode", XML_NAMESPACE_STYLE,XML_REPEAT, XML_SD_TYPE_BITMAP_MODE, 0 ), + DPMAP( "FillBitmapPositionOffsetX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + DPMAP( "FillBitmapPositionOffsetY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + DPMAP( "FillBitmapRectanglePoint", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SD_TYPE_BITMAP_REFPOINT, 0 ), + DPMAP( "FillBitmapOffsetX", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SD_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_X ), + DPMAP( "FillBitmapOffsetY", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SD_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_Y ), + + DPMAP( "IsHeaderVisible", XML_NAMESPACE_PRESENTATION, XML_DISPLAY_HEADER, XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE, CTF_HEADER_VISIBLE ), + DPMAP( "IsFooterVisible", XML_NAMESPACE_PRESENTATION, XML_DISPLAY_FOOTER, XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE, CTF_FOOTER_VISIBLE ), + DPMAP( "IsPageNumberVisible", XML_NAMESPACE_PRESENTATION, XML_DISPLAY_PAGE_NUMBER, XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE, CTF_PAGE_NUMBER_VISIBLE ), + DPMAP( "IsDateTimeVisible", XML_NAMESPACE_PRESENTATION, XML_DISPLAY_DATE_TIME, XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE, CTF_DATE_TIME_VISIBLE ), + + DPMAP( "TransitionType", XML_NAMESPACE_SMIL, XML_TYPE, XML_SD_TYPE_TRANSITION_TYPE, CTF_PAGE_TRANSITION_TYPE ), + DPMAP( "TransitionSubtype", XML_NAMESPACE_SMIL, XML_SUBTYPE, XML_SD_TYPE_TRANSTIION_SUBTYPE, CTF_PAGE_TRANSITION_SUBTYPE ), + DPMAP( "TransitionDirection", XML_NAMESPACE_SMIL, XML_DIRECTION, XML_SD_TYPE_TRANSTIION_DIRECTION, CTF_PAGE_TRANSITION_DIRECTION ), + DPMAP( "TransitionFadeColor", XML_NAMESPACE_SMIL, XML_FADECOLOR, XML_TYPE_COLOR, CTF_PAGE_TRANSITION_FADECOLOR ), + MAP_END() +}; + +/** contains the attribute to property mapping for a drawing layer table + WARNING: if attributes are added, SdXMLTableShapeContext::processAttribute needs to be updated! +*/ +const XMLPropertyMapEntry aXMLTableShapeAttributes[] = +{ + MAP_( "UseFirstRowStyle", XML_NAMESPACE_TABLE, XML_USE_FIRST_ROW_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( "UseLastRowStyle", XML_NAMESPACE_TABLE, XML_USE_LAST_ROW_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( "UseFirstColumnStyle", XML_NAMESPACE_TABLE, XML_USE_FIRST_COLUMN_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( "UseLastColumnStyle", XML_NAMESPACE_TABLE, XML_USE_LAST_COLUMN_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( "UseBandingRowStyle", XML_NAMESPACE_TABLE, XML_USE_BANDING_ROWS_STYLES, XML_TYPE_BOOL, 0 ), + MAP_( "UseBandingColumnStyle", XML_NAMESPACE_TABLE, XML_USE_BANDING_COLUMNS_STYLES, XML_TYPE_BOOL, 0 ), + MAP_END() +}; + +// implementation of factory for own graphic properties + +SvXMLEnumMapEntry const aXML_LineStyle_EnumMap[] = +{ + { XML_NONE, drawing::LineStyle_NONE }, + { XML_SOLID, drawing::LineStyle_SOLID }, + { XML_DASH, drawing::LineStyle_DASH }, + { XML_TOKEN_INVALID, drawing::LineStyle(0) } +}; + +SvXMLEnumMapEntry const aXML_LineJoint_EnumMap[] = +{ + { XML_NONE, drawing::LineJoint_NONE }, + { XML_MITER, drawing::LineJoint_MITER }, + { XML_ROUND, drawing::LineJoint_ROUND }, + { XML_BEVEL, drawing::LineJoint_BEVEL }, + { XML_MIDDLE, drawing::LineJoint_MIDDLE }, + { XML_TOKEN_INVALID, drawing::LineJoint(0) } +}; + +SvXMLEnumMapEntry const aXML_LineCap_EnumMap[] = +{ + { XML_BUTT, drawing::LineCap_BUTT }, + { XML_ROUND, drawing::LineCap_ROUND }, + // use XML_GRADIENTSTYLE_SQUARE as XML_SQUARE, is defined as "square" already + { XML_GRADIENTSTYLE_SQUARE, drawing::LineCap_SQUARE }, + { XML_TOKEN_INVALID, drawing::LineCap(0) } +}; + +SvXMLEnumMapEntry const aXML_FillStyle_EnumMap[] = +{ + { XML_NONE, drawing::FillStyle_NONE }, + { XML_SOLID, drawing::FillStyle_SOLID }, + { XML_BITMAP, drawing::FillStyle_BITMAP }, + { XML_GRADIENT, drawing::FillStyle_GRADIENT }, + { XML_HATCH, drawing::FillStyle_HATCH }, + { XML_TOKEN_INVALID, drawing::FillStyle(0) } +}; + +SvXMLEnumMapEntry const aXML_PresChange_EnumMap[] = +{ + { XML_MANUAL, 0 }, + { XML_AUTOMATIC, 1 }, + { XML_SEMI_AUTOMATIC, 2 }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const aXML_TransSpeed_EnumMap[] = +{ + { XML_FAST, presentation::AnimationSpeed_FAST }, + { XML_MEDIUM, presentation::AnimationSpeed_MEDIUM }, + { XML_SLOW, presentation::AnimationSpeed_SLOW }, + { XML_TOKEN_INVALID, presentation::AnimationSpeed(0) } +}; + +SvXMLEnumMapEntry const aXML_FadeEffect_EnumMap[] = +{ + { XML_NONE, presentation::FadeEffect_NONE }, + { XML_FADE_FROM_LEFT, presentation::FadeEffect_FADE_FROM_LEFT }, + { XML_FADE_FROM_TOP, presentation::FadeEffect_FADE_FROM_TOP }, + { XML_FADE_FROM_RIGHT, presentation::FadeEffect_FADE_FROM_RIGHT }, + { XML_FADE_FROM_BOTTOM, presentation::FadeEffect_FADE_FROM_BOTTOM }, + { XML_FADE_TO_CENTER, presentation::FadeEffect_FADE_TO_CENTER }, + { XML_FADE_FROM_CENTER, presentation::FadeEffect_FADE_FROM_CENTER }, + { XML_MOVE_FROM_LEFT, presentation::FadeEffect_MOVE_FROM_LEFT }, + { XML_MOVE_FROM_TOP, presentation::FadeEffect_MOVE_FROM_TOP }, + { XML_MOVE_FROM_RIGHT, presentation::FadeEffect_MOVE_FROM_RIGHT }, + { XML_MOVE_FROM_BOTTOM, presentation::FadeEffect_MOVE_FROM_BOTTOM }, + { XML_ROLL_FROM_TOP, presentation::FadeEffect_ROLL_FROM_TOP }, + { XML_ROLL_FROM_LEFT, presentation::FadeEffect_ROLL_FROM_LEFT }, + { XML_ROLL_FROM_RIGHT, presentation::FadeEffect_ROLL_FROM_RIGHT }, + { XML_ROLL_FROM_BOTTOM, presentation::FadeEffect_ROLL_FROM_BOTTOM }, + { XML_VERTICAL_STRIPES, presentation::FadeEffect_VERTICAL_STRIPES }, + { XML_HORIZONTAL_STRIPES, presentation::FadeEffect_HORIZONTAL_STRIPES }, + { XML_CLOCKWISE, presentation::FadeEffect_CLOCKWISE }, + { XML_COUNTERCLOCKWISE, presentation::FadeEffect_COUNTERCLOCKWISE }, + { XML_FADE_FROM_UPPERLEFT, presentation::FadeEffect_FADE_FROM_UPPERLEFT }, + { XML_FADE_FROM_UPPERRIGHT, presentation::FadeEffect_FADE_FROM_UPPERRIGHT }, + { XML_FADE_FROM_LOWERLEFT, presentation::FadeEffect_FADE_FROM_LOWERLEFT }, + { XML_FADE_FROM_LOWERRIGHT, presentation::FadeEffect_FADE_FROM_LOWERRIGHT }, + { XML_CLOSE_VERTICAL, presentation::FadeEffect_CLOSE_VERTICAL }, + { XML_CLOSE_HORIZONTAL, presentation::FadeEffect_CLOSE_HORIZONTAL }, + { XML_OPEN_VERTICAL, presentation::FadeEffect_OPEN_VERTICAL }, + { XML_OPEN_HORIZONTAL, presentation::FadeEffect_OPEN_HORIZONTAL }, + { XML_SPIRALIN_LEFT, presentation::FadeEffect_SPIRALIN_LEFT }, + { XML_SPIRALIN_RIGHT, presentation::FadeEffect_SPIRALIN_RIGHT }, + { XML_SPIRALOUT_LEFT, presentation::FadeEffect_SPIRALOUT_LEFT }, + { XML_SPIRALOUT_RIGHT, presentation::FadeEffect_SPIRALOUT_RIGHT }, + { XML_DISSOLVE, presentation::FadeEffect_DISSOLVE }, + { XML_WAVYLINE_FROM_LEFT, presentation::FadeEffect_WAVYLINE_FROM_LEFT }, + { XML_WAVYLINE_FROM_TOP, presentation::FadeEffect_WAVYLINE_FROM_TOP }, + { XML_WAVYLINE_FROM_RIGHT, presentation::FadeEffect_WAVYLINE_FROM_RIGHT }, + { XML_WAVYLINE_FROM_BOTTOM, presentation::FadeEffect_WAVYLINE_FROM_BOTTOM }, + { XML_RANDOM, presentation::FadeEffect_RANDOM }, + { XML_STRETCH_FROM_LEFT, presentation::FadeEffect_STRETCH_FROM_LEFT }, + { XML_STRETCH_FROM_TOP, presentation::FadeEffect_STRETCH_FROM_TOP }, + { XML_STRETCH_FROM_RIGHT, presentation::FadeEffect_STRETCH_FROM_RIGHT }, + { XML_STRETCH_FROM_BOTTOM, presentation::FadeEffect_STRETCH_FROM_BOTTOM }, + { XML_VERTICAL_LINES, presentation::FadeEffect_VERTICAL_LINES }, + { XML_HORIZONTAL_LINES, presentation::FadeEffect_HORIZONTAL_LINES }, + { XML_MOVE_FROM_UPPERLEFT, presentation::FadeEffect_MOVE_FROM_UPPERLEFT }, + { XML_MOVE_FROM_UPPERRIGHT, presentation::FadeEffect_MOVE_FROM_UPPERRIGHT }, + { XML_MOVE_FROM_LOWERRIGHT, presentation::FadeEffect_MOVE_FROM_LOWERRIGHT }, + { XML_MOVE_FROM_LOWERLEFT, presentation::FadeEffect_MOVE_FROM_LOWERLEFT }, + { XML_UNCOVER_TO_LEFT, presentation::FadeEffect_UNCOVER_TO_LEFT }, + { XML_UNCOVER_TO_UPPERLEFT, presentation::FadeEffect_UNCOVER_TO_UPPERLEFT }, + { XML_UNCOVER_TO_TOP, presentation::FadeEffect_UNCOVER_TO_TOP }, + { XML_UNCOVER_TO_UPPERRIGHT,presentation::FadeEffect_UNCOVER_TO_UPPERRIGHT }, + { XML_UNCOVER_TO_RIGHT, presentation::FadeEffect_UNCOVER_TO_RIGHT }, + { XML_UNCOVER_TO_LOWERRIGHT,presentation::FadeEffect_UNCOVER_TO_LOWERRIGHT }, + { XML_UNCOVER_TO_BOTTOM, presentation::FadeEffect_UNCOVER_TO_BOTTOM }, + { XML_UNCOVER_TO_LOWERLEFT, presentation::FadeEffect_UNCOVER_TO_LOWERLEFT }, + { XML_VERTICAL_CHECKERBOARD,presentation::FadeEffect_VERTICAL_CHECKERBOARD }, + { XML_HORIZONTAL_CHECKERBOARD,presentation::FadeEffect_HORIZONTAL_CHECKERBOARD }, + { XML_TOKEN_INVALID, presentation::FadeEffect(0) } +}; + +SvXMLEnumMapEntry const aXML_ConnectionKind_EnumMap[] = +{ + { XML_STANDARD, drawing::ConnectorType_STANDARD }, + { XML_CURVE, drawing::ConnectorType_CURVE }, + { XML_LINE, drawing::ConnectorType_LINE }, + { XML_LINES, drawing::ConnectorType_LINES }, + { XML_TOKEN_INVALID, drawing::ConnectorType(0) } +}; + +SvXMLEnumMapEntry const aXML_BitmapMode_EnumMap[] = +{ + { XML_REPEAT, drawing::BitmapMode_REPEAT }, + { XML_STRETCH, drawing::BitmapMode_STRETCH }, + { XML_BACKGROUND_NO_REPEAT, drawing::BitmapMode_NO_REPEAT }, + { XML_TOKEN_INVALID, drawing::BitmapMode(0) } +}; + +// 3D EnumMaps + +SvXMLEnumMapEntry const aXML_NormalsKind_EnumMap[] = +{ + { XML_OBJECT, drawing::NormalsKind_SPECIFIC }, + { XML_FLAT, drawing::NormalsKind_FLAT }, + { XML_SPHERE, drawing::NormalsKind_SPHERE }, + { XML_TOKEN_INVALID, drawing::NormalsKind(0) } +}; + +SvXMLEnumMapEntry const aXML_TexGenerationX_EnumMap[] = +{ + { XML_OBJECT, drawing::TextureProjectionMode_OBJECTSPECIFIC }, + { XML_PARALLEL, drawing::TextureProjectionMode_PARALLEL }, + { XML_SPHERE, drawing::TextureProjectionMode_SPHERE }, + { XML_TOKEN_INVALID, drawing::TextureProjectionMode(0) } +}; + +SvXMLEnumMapEntry const aXML_TexGenerationY_EnumMap[] = +{ + { XML_OBJECT, drawing::TextureProjectionMode_OBJECTSPECIFIC }, + { XML_PARALLEL, drawing::TextureProjectionMode_PARALLEL }, + { XML_SPHERE, drawing::TextureProjectionMode_SPHERE }, + { XML_TOKEN_INVALID, drawing::TextureProjectionMode(0) } +}; + +SvXMLEnumMapEntry const aXML_TexKind_EnumMap[] = +{ + { XML_LUMINANCE, drawing::TextureKind_LUMINANCE }, + { XML_COLOR, drawing::TextureKind_COLOR }, + { XML_TOKEN_INVALID, drawing::TextureKind(0) } +}; + +SvXMLEnumMapEntry const aXML_TexMode_EnumMap[] = +{ + { XML_REPLACE, drawing::TextureMode_REPLACE }, + { XML_MODULATE, drawing::TextureMode_MODULATE }, + { XML_BLEND, drawing::TextureMode_BLEND }, + { XML_TOKEN_INVALID, drawing::TextureMode(0) } +}; + +SvXMLEnumMapEntry const aXML_RefPoint_EnumMap[] = +{ + { XML_TOP_LEFT, drawing::RectanglePoint_LEFT_TOP }, + { XML_TOP, drawing::RectanglePoint_MIDDLE_TOP }, + { XML_TOP_RIGHT, drawing::RectanglePoint_RIGHT_TOP }, + { XML_LEFT, drawing::RectanglePoint_LEFT_MIDDLE }, + { XML_CENTER, drawing::RectanglePoint_MIDDLE_MIDDLE }, + { XML_RIGHT, drawing::RectanglePoint_RIGHT_MIDDLE }, + { XML_BOTTOM_LEFT, drawing::RectanglePoint_LEFT_BOTTOM }, + { XML_BOTTOM, drawing::RectanglePoint_MIDDLE_BOTTOM }, + { XML_BOTTOM_RIGHT, drawing::RectanglePoint_RIGHT_BOTTOM }, + { XML_TOKEN_INVALID, drawing::RectanglePoint(0) } +}; + +SvXMLEnumMapEntry const aXML_CircleKind_EnumMap[] = +{ + { XML_FULL, drawing::CircleKind_FULL }, + { XML_SECTION, drawing::CircleKind_SECTION }, + { XML_CUT, drawing::CircleKind_CUT }, + { XML_ARC, drawing::CircleKind_ARC }, + { XML_TOKEN_INVALID, drawing::CircleKind(0) } +}; + +SvXMLEnumMapEntry const aXML_WritingMode_EnumMap[] = +{ + { XML_TB_RL, text::WritingMode_TB_RL }, + { XML_LR_TB, text::WritingMode_LR_TB }, + { XML_TOKEN_INVALID, text::WritingMode(0) } +}; + +SvXMLEnumMapEntry const pXML_TextAnimation_Enum[] = +{ + { XML_NONE, drawing::TextAnimationKind_NONE }, + { XML_BLINKING, drawing::TextAnimationKind_BLINK }, // will be filtered + { XML_SCROLL, drawing::TextAnimationKind_SCROLL }, + { XML_ALTERNATE, drawing::TextAnimationKind_ALTERNATE }, + { XML_SLIDE, drawing::TextAnimationKind_SLIDE }, + { XML_TOKEN_INVALID, drawing::TextAnimationKind(0) } +}; + +SvXMLEnumMapEntry const pXML_TextAnimation_Blinking_Enum[] = +{ + { XML_FALSE, drawing::TextAnimationKind_NONE }, + { XML_TRUE, drawing::TextAnimationKind_BLINK }, + { XML_FALSE, drawing::TextAnimationKind_SCROLL }, + { XML_FALSE, drawing::TextAnimationKind_ALTERNATE }, + { XML_FALSE, drawing::TextAnimationKind_SLIDE }, + { XML_TOKEN_INVALID, drawing::TextAnimationKind(0) } +}; + +SvXMLEnumMapEntry const pXML_TextAnimationDirection_Enum[] = +{ + { XML_LEFT, drawing::TextAnimationDirection_LEFT }, + { XML_RIGHT, drawing::TextAnimationDirection_RIGHT }, // will be filtered + { XML_UP, drawing::TextAnimationDirection_UP }, + { XML_DOWN, drawing::TextAnimationDirection_DOWN }, + { XML_TOKEN_INVALID, drawing::TextAnimationDirection(0) } +}; + +SvXMLEnumMapEntry const pXML_TextAlign_Enum[] = +{ + { XML_LEFT, drawing::TextHorizontalAdjust_LEFT }, + { XML_CENTER, drawing::TextHorizontalAdjust_CENTER }, + { XML_RIGHT, drawing::TextHorizontalAdjust_RIGHT }, + { XML_JUSTIFY, drawing::TextHorizontalAdjust_BLOCK }, + { XML_TOKEN_INVALID, drawing::TextHorizontalAdjust(0) } +}; + +SvXMLEnumMapEntry const pXML_VerticalAlign_Enum[] = +{ + { XML_TOP, drawing::TextVerticalAdjust_TOP }, + { XML_MIDDLE, drawing::TextVerticalAdjust_CENTER }, + { XML_BOTTOM, drawing::TextVerticalAdjust_BOTTOM }, + { XML_JUSTIFY, drawing::TextVerticalAdjust_BLOCK }, + { XML_TOKEN_INVALID, drawing::TextVerticalAdjust(0) } +}; + +// note: PROPORTIONAL and ALLLINES are the same thing now! +SvXMLEnumMapEntry const pXML_FitToSize_Enum_Odf12[] = +{ + { XML_FALSE, drawing::TextFitToSizeType_NONE }, + { XML_TRUE, drawing::TextFitToSizeType_PROPORTIONAL }, + { XML_TRUE, drawing::TextFitToSizeType_ALLLINES }, + { XML_FALSE, drawing::TextFitToSizeType_AUTOFIT }, + { XML_TOKEN_INVALID, drawing::TextFitToSizeType(0) } +}; + +SvXMLEnumMapEntry const pXML_FitToSize_Enum[] = +{ + { XML_FALSE, drawing::TextFitToSizeType_NONE }, + { XML_TRUE, drawing::TextFitToSizeType_PROPORTIONAL }, + { XML_ALL, drawing::TextFitToSizeType_ALLLINES }, + { XML_SHRINK_TO_FIT,drawing::TextFitToSizeType_AUTOFIT }, + { XML_TOKEN_INVALID, drawing::TextFitToSizeType(0) } +}; + +SvXMLEnumMapEntry const pXML_ShrinkToFit_Enum[] = +{ + { XML_FALSE, drawing::TextFitToSizeType_NONE }, + { XML_FALSE, drawing::TextFitToSizeType_PROPORTIONAL }, + { XML_FALSE, drawing::TextFitToSizeType_ALLLINES }, + { XML_TRUE, drawing::TextFitToSizeType_AUTOFIT }, + { XML_TOKEN_INVALID, drawing::TextFitToSizeType(0) } +}; + +SvXMLEnumMapEntry const pXML_MeasureUnit_Enum[] = +{ + { XML_AUTOMATIC, 0 }, + { XML_MM, 1 }, + { XML_UNIT_CM, 2 }, + { XML_UNIT_M, 3 }, + { XML_KM, 4 }, + { XML_UNIT_PT, 6 }, + { XML_UNIT_PC, 7 }, + { XML_IN, 8 }, + { XML_UNIT_FOOT, 9 }, + { XML_MI, 10 }, + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry const pXML_Measure_HAlign_Enum[] = +{ + { XML_AUTOMATIC, drawing::MeasureTextHorzPos_AUTO }, + { XML_LEFT_OUTSIDE, drawing::MeasureTextHorzPos_LEFTOUTSIDE }, + { XML_INSIDE, drawing::MeasureTextHorzPos_INSIDE }, + { XML_RIGHT_OUTSIDE, drawing::MeasureTextHorzPos_RIGHTOUTSIDE}, + { XML_TOKEN_INVALID, drawing::MeasureTextHorzPos(0) } +}; + +SvXMLEnumMapEntry const pXML_Measure_VAlign_Enum[] = +{ + { XML_AUTOMATIC, drawing::MeasureTextVertPos_AUTO }, + { XML_ABOVE, drawing::MeasureTextVertPos_EAST }, + { XML_BELOW, drawing::MeasureTextVertPos_WEST }, + { XML_CENTER, drawing::MeasureTextVertPos_CENTERED }, + { XML_TOKEN_INVALID, drawing::MeasureTextVertPos(0) } +}; + +// #FontWork# +SvXMLEnumMapEntry const pXML_Fontwork_Style_Enum[] = +{ + { XML_ROTATE, 0 }, //XFormTextStyle::Rotate, + { XML_UPRIGHT, 1 }, //XFormTextStyle::Upright, + { XML_SLANT_X, 2 }, //XFormTextStyle::SlantX, + { XML_SLANT_Y, 3 }, //XFormTextStyle::SlantY, + { XML_NONE, 4 }, //XFormTextStyle::NONE + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry const pXML_Fontwork_Adjust_Enum[] = +{ + { XML_LEFT, 0 }, //XFormTextAdjust::Left, + { XML_RIGHT, 1 }, //XFormTextAdjust::Right, + { XML_AUTOSIZE, 2 }, //XFormTextAdjust::AutoSize, + { XML_CENTER, 3 }, //XFormTextAdjust::Center + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry const pXML_Fontwork_Shadow_Enum[] = +{ + { XML_NORMAL, 0 }, //XFormTextShadow::Normal, + { XML_SLANT, 1 }, //XFormTextShadow::Slant, + { XML_NONE, 2 }, //XFormTextShadow::NONE + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry const pXML_Fontwork_Form_Enum[] = +{ + { XML_NONE, 0 }, //XFTFORM_NONE, + { XML_TOPCIRCLE, 1 }, //XFTFORM_TOPCIRC, + { XML_BOTTOMCIRCLE, 2 }, //XFTFORM_BOTCIRC, + { XML_LEFTCIRCLE, 3 }, //XFTFORM_LFTCIRC, + { XML_RIGHTCIRCLE, 4 }, //XFTFORM_RGTCIRC, + { XML_TOPARC, 5 }, //XFTFORM_TOPARC, + { XML_BOTTOMARC, 6 }, //XFTFORM_BOTARC, + { XML_LEFTARC, 7 }, //XFTFORM_LFTARC, + { XML_RIGHTARC, 8 }, //XFTFORM_RGTARC, + { XML_BUTTON1, 9 }, //XFTFORM_BUTTON1, + { XML_BUTTON2, 10 }, //XFTFORM_BUTTON2, + { XML_BUTTON3, 11 }, //XFTFORM_BUTTON3, + { XML_BUTTON4, 12 }, //XFTFORM_BUTTON4 + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry const pXML_Caption_Esc_Dir_Enum[] = +{ + { XML_HORIZONTAL, 0 }, //SdrCaptionEscDir::Horizontal, + { XML_VERTICAL, 1 }, //SdrCaptionEscDir::Vertical, + { XML_AUTO, 2 }, //SdrCaptionEscDir::BestFit, + { XML_TOKEN_INVALID,0 } +}; + +SvXMLEnumMapEntry const pXML_Caption_Type_Enum[] = +{ + { XML_STRAIGHT_LINE, 0 }, //SdrCaptionType::Type1, + { XML_ANGLED_LINE, 1 }, //SdrCaptionType::Type2, + { XML_ANGLED_CONNECTOR_LINE, 2 }, //SdrCaptionType::Type3, + { XML_TOKEN_INVALID,0 } +}; + +namespace { + +class XMLCaptionEscapeRelative : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +} + +bool XMLCaptionEscapeRelative::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue; + + if (!::sax::Converter::convertPercent( nValue, rStrImpValue )) + return false; + + nValue *= 100; + rValue <<= nValue; + return true; +} + +bool XMLCaptionEscapeRelative::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + if( !(rValue >>= nValue ) ) + return false; + + nValue /= 100; + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + return true; +} + +namespace { + +class XMLMoveSizeProtectHdl : public XMLPropertyHandler +{ +public: + explicit XMLMoveSizeProtectHdl( sal_Int32 nType ) : mnType( nType ) {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; +private: + const sal_Int32 mnType; +}; + +} + +bool XMLMoveSizeProtectHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + const bool bValue = rStrImpValue.indexOf( GetXMLToken( mnType == XML_SD_TYPE_MOVE_PROTECT ? XML_POSITION : XML_SIZE ) ) != -1; + rValue <<= bValue; + return true; +} + +bool XMLMoveSizeProtectHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue; + if( !(rValue >>= bValue ) ) + return false; + + if( bValue ) + { + if( !rStrExpValue.isEmpty() ) + rStrExpValue += " "; + + rStrExpValue += GetXMLToken( mnType == XML_SD_TYPE_MOVE_PROTECT ? XML_POSITION : XML_SIZE ); + } + + return true; +} + +namespace { + +class XMLSdHeaderFooterVisibilityTypeHdl : public XMLPropertyHandler +{ +public: + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +} + +bool XMLSdHeaderFooterVisibilityTypeHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const +{ + // #i38644# + // attributes with this type where saved with VISIBLE|HIDDEN prior + // to src680m67. So we have to import that correctly + const bool bBool = IsXMLToken(rStrImpValue, XML_TRUE) || IsXMLToken(rStrImpValue, XML_VISIBLE); + rValue <<= bBool; + return bBool || IsXMLToken(rStrImpValue, XML_FALSE) || IsXMLToken(rStrImpValue, XML_HIDDEN); +} + +bool XMLSdHeaderFooterVisibilityTypeHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + OUStringBuffer aOut; + ::sax::Converter::convertBool( aOut, bValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +namespace { + +class XMLSdRotationAngleTypeHdl : public XMLPropertyHandler +{ +public: + virtual bool importXML(const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter) const override; + virtual bool exportXML(OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter) const override; +}; + +} + +bool XMLSdRotationAngleTypeHdl::importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter&) const +{ + sal_Int32 nValue; + bool const bRet = ::sax::Converter::convertNumber(nValue, rStrImpValue); + if (bRet) + { + nValue = (nValue % 360); + if (nValue < 0) + nValue = 360 + nValue; + sal_Int32 nAngle; + if (nValue < 45 || nValue > 315) + nAngle = 0; + else if (nValue < 180) + nAngle = 9000; + else /* if nValue <= 315 ) */ + nAngle = 27000; + + rValue <<= nAngle; + } + return bRet; +} + +bool XMLSdRotationAngleTypeHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter&) const +{ + sal_Int32 nAngle; + bool bRet = (rValue >>= nAngle) && nAngle != 0; + if (bRet) + { + rStrExpValue = OUString::number(nAngle / 100); + } + return bRet; +} + +namespace { + +class XMLFitToSizeEnumPropertyHdl : public XMLEnumPropertyHdl +{ +public: + XMLFitToSizeEnumPropertyHdl( + const SvXMLEnumMapEntry *const pMap) + : XMLEnumPropertyHdl(pMap) {} + + virtual bool importXML(const OUString& rStrImpValue, uno::Any& rValue, + const SvXMLUnitConverter& rUC) const override + { + // we don't know here what the actual attribute name is - + // but we can combine the 2 attributes by just taking the + // "largest" result value; this can never result in ALLLINES + // so the implementation has to interpret PROPORTIONAL as ALLLINES; + // both "true" is invalid anyway. + Any any; + auto const bRet = XMLEnumPropertyHdl::importXML(rStrImpValue, any, rUC); + if (!bRet) + { + return false; + } + assert(any.hasValue()); + if (!rValue.hasValue() || + rValue.get() < any.get()) + { + rValue = any; + } + return true; + } +}; + +} + +XMLSdPropHdlFactory::XMLSdPropHdlFactory( uno::Reference< frame::XModel > const & xModel, SvXMLImport& rImport ) +: mxModel( xModel ), mpExport(nullptr), mpImport( &rImport ) +{ +} + +XMLSdPropHdlFactory::XMLSdPropHdlFactory( uno::Reference< frame::XModel > const & xModel, SvXMLExport& rExport ) +: mxModel( xModel ), mpExport( &rExport ), mpImport(nullptr) +{ +} + +XMLSdPropHdlFactory::~XMLSdPropHdlFactory() +{ +} + +const XMLPropertyHandler* XMLSdPropHdlFactory::GetPropertyHandler( sal_Int32 nType ) const +{ + const XMLPropertyHandler* pHdl = XMLPropertyHandlerFactory::GetPropertyHandler( nType ); + if(!pHdl) + { + switch(nType) + { + case XML_SD_TYPE_STROKE : + { + pHdl = new XMLEnumPropertyHdl( aXML_LineStyle_EnumMap); + break; + } + case XML_SD_TYPE_LINEJOIN : + { + pHdl = new XMLEnumPropertyHdl( aXML_LineJoint_EnumMap); + break; + } + case XML_SD_TYPE_LINECAP : + { + pHdl = new XMLEnumPropertyHdl( aXML_LineCap_EnumMap ); + break; + } + case XML_SD_TYPE_FILLSTYLE : + { + pHdl = new XMLEnumPropertyHdl( aXML_FillStyle_EnumMap ); + break; + } + case XML_SD_TYPE_PRESPAGE_TYPE : + { + pHdl = new XMLEnumPropertyHdl( aXML_PresChange_EnumMap ); + break; + } + case XML_SD_TYPE_VISIBLE_HIDDEN: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_VISIBLE), GetXMLToken(XML_HIDDEN) ); + break; + } + case XML_TYPE_SD_MIRROR: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_HORIZONTAL), GetXMLToken(XML_NONE) ); + break; + } + case XML_SD_TYPE_PRESPAGE_STYLE : + { + pHdl = new XMLEnumPropertyHdl( aXML_FadeEffect_EnumMap ); + break; + } + case XML_SD_TYPE_PRESPAGE_SPEED : + { + pHdl = new XMLEnumPropertyHdl( aXML_TransSpeed_EnumMap ); + break; + } + case XML_SD_TYPE_PRESPAGE_DURATION : + { + pHdl = new XMLDurationPropertyHdl; + break; + } + case XML_SD_TYPE_TEXT_CROSSEDOUT : + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_SOLID), GetXMLToken(XML_NONE) ); + break; + } + case XML_SD_TYPE_OPACITY : + { + pHdl = new XMLOpacityPropertyHdl(mpImport); + break; + } + case XML_SD_TYPE_WRITINGMODE : + { + pHdl = new XMLEnumPropertyHdl( aXML_WritingMode_EnumMap ); + break; + } + case XML_SD_TYPE_PRESPAGE_VISIBILITY : + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_VISIBLE), GetXMLToken(XML_HIDDEN) ); + break; + } + case XML_SD_TYPE_PRESPAGE_BACKSIZE: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_FULL), GetXMLToken(XML_BORDER) ); + break; + } + + // 3D Properties + + case XML_SD_TYPE_BACKFACE_CULLING: + { + // #87922# DoubleSided -> BackfaceCulling + // This sal_Bool needs to be flipped, DoubleSided sal_True -> NO Backface culling + // and vice versa. + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_DISABLED), GetXMLToken(XML_ENABLED) ); + break; + } + + case XML_SD_TYPE_NORMALS_KIND: + { + pHdl = new XMLEnumPropertyHdl( aXML_NormalsKind_EnumMap ); + break; + } + case XML_SD_TYPE_NORMALS_DIRECTION: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_NORMAL), GetXMLToken(XML_INVERSE) ); + break; + } + case XML_SD_TYPE_TEX_GENERATION_MODE_X: + { + pHdl = new XMLEnumPropertyHdl( aXML_TexGenerationX_EnumMap ); + break; + } + case XML_SD_TYPE_TEX_GENERATION_MODE_Y: + { + pHdl = new XMLEnumPropertyHdl( aXML_TexGenerationY_EnumMap ); + break; + } + case XML_SD_TYPE_TEX_KIND: + { + pHdl = new XMLEnumPropertyHdl( aXML_TexKind_EnumMap ); + break; + } + case XML_SD_TYPE_TEX_MODE: + { + pHdl = new XMLEnumPropertyHdl( aXML_TexMode_EnumMap ); + break; + } + case XML_SD_TYPE_NUMBULLET: + { + uno::Reference xCompareFac( mxModel, uno::UNO_QUERY ); + uno::Reference xCompare; + if( xCompareFac.is() ) + xCompare = xCompareFac->createAnyCompareByName( "NumberingRules" ); + + pHdl = new XMLNumRulePropHdl( xCompare ); + break; + } + case XML_SD_TYPE_BITMAP_MODE: + { + pHdl = new XMLEnumPropertyHdl( aXML_BitmapMode_EnumMap ); + break; + } + case XML_SD_TYPE_BITMAPREPOFFSETX: + case XML_SD_TYPE_BITMAPREPOFFSETY: + { + pHdl = new XMLBitmapRepeatOffsetPropertyHandler( nType == XML_SD_TYPE_BITMAPREPOFFSETX ); + break; + } + case XML_SD_TYPE_FILLBITMAPSIZE: + { + pHdl = new XMLFillBitmapSizePropertyHandler(); + break; + } + case XML_SD_TYPE_LOGICAL_SIZE: + { + pHdl = new XMLBitmapLogicalSizePropertyHandler(); + break; + } + case XML_SD_TYPE_BITMAP_REFPOINT: + { + pHdl = new XMLEnumPropertyHdl( aXML_RefPoint_EnumMap); + break; + } + case XML_TYPE_TEXT_ANIMATION: + pHdl = new XMLEnumPropertyHdl( pXML_TextAnimation_Enum); + break; + case XML_TYPE_TEXT_ANIMATION_BLINKING: + pHdl = new XMLEnumPropertyHdl( pXML_TextAnimation_Blinking_Enum); + break; + case XML_TYPE_TEXT_ANIMATION_DIRECTION: + pHdl = new XMLEnumPropertyHdl( pXML_TextAnimationDirection_Enum); + break; + case XML_TYPE_TEXT_ANIMATION_STEPS: + pHdl = new XMLTextAnimationStepPropertyHdl; + break; + case XML_SD_TYPE_TEXT_ALIGN: + pHdl = new XMLEnumPropertyHdl( pXML_TextAlign_Enum); + break; + case XML_SD_TYPE_VERTICAL_ALIGN: + pHdl = new XMLEnumPropertyHdl( pXML_VerticalAlign_Enum); + break; + case XML_SD_TYPE_FITTOSIZE: + { + if (mpExport + && (mpExport->getSaneDefaultVersion() // tdf#97630 + != SvtSaveOptions::ODFSVER_012_EXT_COMPAT)) + { + pHdl = new XMLFitToSizeEnumPropertyHdl(pXML_FitToSize_Enum_Odf12); + } + else + { // import all values written by old LO + pHdl = new XMLFitToSizeEnumPropertyHdl(pXML_FitToSize_Enum); + } + } + break; + case XML_SD_TYPE_FITTOSIZE_AUTOFIT: + { + pHdl = new XMLFitToSizeEnumPropertyHdl(pXML_ShrinkToFit_Enum); + } + break; + case XML_SD_TYPE_MEASURE_UNIT: + pHdl = new XMLEnumPropertyHdl( pXML_MeasureUnit_Enum ); + break; + case XML_SD_TYPE_MEASURE_HALIGN: + pHdl = new XMLEnumPropertyHdl( pXML_Measure_HAlign_Enum); + break; + case XML_SD_TYPE_MEASURE_VALIGN: + pHdl = new XMLEnumPropertyHdl( pXML_Measure_VAlign_Enum); + break; + case XML_SD_TYPE_MEASURE_PLACING: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_BELOW), GetXMLToken(XML_ABOVE) ); + } + break; + case XML_TYPE_TEXT_CLIP11: + pHdl = new XMLClipPropertyHandler( true ); + break; + case XML_TYPE_TEXT_CLIP: + pHdl = new XMLClipPropertyHandler( false ); + break; + + // #FontWork# + case XML_SD_TYPE_FONTWORK_STYLE : + pHdl = new XMLEnumPropertyHdl( pXML_Fontwork_Style_Enum ); + break; + case XML_SD_TYPE_FONTWORK_ADJUST : + pHdl = new XMLEnumPropertyHdl( pXML_Fontwork_Adjust_Enum ); + break; + case XML_SD_TYPE_FONTWORK_SHADOW : + pHdl = new XMLEnumPropertyHdl( pXML_Fontwork_Shadow_Enum ); + break; + case XML_SD_TYPE_FONTWORK_FORM : + pHdl = new XMLEnumPropertyHdl( pXML_Fontwork_Form_Enum ); + break; + + case XML_SD_TYPE_CONTROL_BORDER: + pHdl = new ::xmloff::OControlBorderHandler( ::xmloff::OControlBorderHandler::STYLE ); + break; + case XML_SD_TYPE_CONTROL_BORDER_COLOR: + pHdl = new ::xmloff::OControlBorderHandler( ::xmloff::OControlBorderHandler::COLOR ); + break; + case XML_SD_TYPE_IMAGE_SCALE_MODE: + pHdl = new ::xmloff::ImageScaleModeHandler; + break; + case XML_TYPE_CONTROL_TEXT_EMPHASIZE: + pHdl = new ::xmloff::OControlTextEmphasisHandler; + break; + + case XML_SD_TYPE_CAPTION_ANGLE_TYPE: + { + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_FIXED), GetXMLToken(XML_FREE) ); + break; + } + case XML_SD_TYPE_CAPTION_IS_ESC_REL: + pHdl = new XMLIsPercentagePropertyHandler; + break; + case XML_SD_TYPE_CAPTION_ESC_REL: + pHdl = new XMLCaptionEscapeRelative; + break; + case XML_SD_TYPE_CAPTION_ESC_ABS: + pHdl = new XMLPercentOrMeasurePropertyHandler; + break; + case XML_SD_TYPE_CAPTION_ESC_DIR: + pHdl = new XMLEnumPropertyHdl( pXML_Caption_Esc_Dir_Enum ); + break; + case XML_SD_TYPE_CAPTION_TYPE: + pHdl = new XMLEnumPropertyHdl( pXML_Caption_Type_Enum ); + break; + case XML_SD_TYPE_DATETIMEUPDATE: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_FIXED), GetXMLToken(XML_VARIABLE) ); + break; + case XML_SD_TYPE_DATETIME_FORMAT: + pHdl = new XMLDateTimeFormatHdl( mpExport ); + break; + case XML_SD_TYPE_TRANSITION_TYPE: + pHdl = new XMLEnumPropertyHdl( xmloff::aAnimations_EnumMap_TransitionType ); + break; + case XML_SD_TYPE_TRANSTIION_SUBTYPE: + pHdl = new XMLEnumPropertyHdl( xmloff::aAnimations_EnumMap_TransitionSubType ); + break; + case XML_SD_TYPE_TRANSTIION_DIRECTION: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_FORWARD), GetXMLToken(XML_REVERSE) ); + break; + case XML_TYPE_WRAP_OPTION: + pHdl = new XMLWordWrapPropertyHdl( mpImport ); + break; + + case XML_SD_TYPE_MOVE_PROTECT: + case XML_SD_TYPE_SIZE_PROTECT: + pHdl = new XMLMoveSizeProtectHdl( nType ); + break; + case XML_SD_TYPE_HEADER_FOOTER_VISIBILITY_TYPE: + pHdl = new XMLSdHeaderFooterVisibilityTypeHdl; + break; + case XML_SD_TYPE_CELL_ROTATION_ANGLE: + pHdl = new XMLSdRotationAngleTypeHdl; + break; + case XML_TYPE_TEXT_COLUMNS: + pHdl = new XMLTextColumnsPropertyHandler; + break; + case XML_TYPE_THEME_COLOR: + pHdl = new XMLConstantsPropertyHandler(pXML_ThemeColor_Enum, XML_TOKEN_INVALID); + break; + } + + if(pHdl) + PutHdlCache(nType, pHdl); + } + + return pHdl; +} + +XMLShapePropertySetMapper::XMLShapePropertySetMapper(const rtl::Reference< XMLPropertyHandlerFactory >& rFactoryRef, + bool bForExport) +: XMLPropertySetMapper( aXMLSDProperties, rFactoryRef, bForExport ) +{ +} + +XMLShapePropertySetMapper::~XMLShapePropertySetMapper() +{ +} + +XMLShapeExportPropertyMapper::XMLShapeExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, SvXMLExport& rExport ) +: SvXMLExportPropertyMapper( rMapper ) +, maNumRuleExp( rExport ) +, mbIsInAutoStyles( true ) +{ +} + +XMLShapeExportPropertyMapper::~XMLShapeExportPropertyMapper() +{ +} + +void XMLShapeExportPropertyMapper::ContextFilter( + bool bEnableFoFontFamily, + std::vector< XMLPropertyState >& rProperties, + const uno::Reference< beans::XPropertySet >& rPropSet ) const +{ + XMLPropertyState* pRepeatOffsetX = nullptr; + XMLPropertyState* pRepeatOffsetY = nullptr; + XMLPropertyState* pTextAnimationBlinking = nullptr; + XMLPropertyState* pTextAnimationKind = nullptr; + + // #FontWork# + XMLPropertyState* pFontWorkStyle = nullptr; + XMLPropertyState* pFontWorkAdjust = nullptr; + XMLPropertyState* pFontWorkDistance = nullptr; + XMLPropertyState* pFontWorkStart = nullptr; + XMLPropertyState* pFontWorkMirror = nullptr; + XMLPropertyState* pFontWorkOutline = nullptr; + XMLPropertyState* pFontWorkShadow = nullptr; + XMLPropertyState* pFontWorkShadowColor = nullptr; + XMLPropertyState* pFontWorkShadowOffsetx = nullptr; + XMLPropertyState* pFontWorkShadowOffsety = nullptr; + XMLPropertyState* pFontWorkForm = nullptr; + XMLPropertyState* pFontWorkHideform = nullptr; + XMLPropertyState* pFontWorkShadowTransparence = nullptr; + + // OLE + XMLPropertyState* pOLEVisAreaLeft = nullptr; + XMLPropertyState* pOLEVisAreaTop = nullptr; + XMLPropertyState* pOLEVisAreaWidth = nullptr; + XMLPropertyState* pOLEVisAreaHeight = nullptr; + XMLPropertyState* pOLEIsInternal = nullptr; + + // caption + XMLPropertyState* pCaptionIsEscRel = nullptr; + XMLPropertyState* pCaptionEscRel = nullptr; + XMLPropertyState* pCaptionEscAbs = nullptr; + + // filter fo:clip + XMLPropertyState* pClip11State = nullptr; + XMLPropertyState* pClipState = nullptr; + + XMLPropertyState* pShapeWritingMode = nullptr; + XMLPropertyState* pTextWritingMode = nullptr; + XMLPropertyState* pControlWritingMode = nullptr; + + // filter properties + for( auto& rProp : rProperties ) + { + XMLPropertyState *property = &rProp; + if( property->mnIndex == -1 ) + continue; + + // find properties with context + // to prevent writing this property set mnIndex member to -1 + switch( getPropertySetMapper()->GetEntryContextId( property->mnIndex )) + { + case CTF_NUMBERINGRULES: + { + if( mbIsInAutoStyles ) + property->mnIndex = -1; + } + break; + case CTF_SD_NUMBERINGRULES_NAME: + { + // this property is not exported in the style:properties element + // because it's an XIndexAccess and not a string. + // This will be handled in SvXMLAutoStylePoolP::exportStyleAttributes + // This is suboptimal + if( !mbIsInAutoStyles ) + property->mnIndex = -1; + } + break; + case CTF_WRITINGMODE: + pShapeWritingMode = property; + break; + case CTF_CONTROLWRITINGMODE: + pControlWritingMode = property; + break; + case CTF_TEXTWRITINGMODE: + pTextWritingMode = property; + break; + case CTF_REPEAT_OFFSET_X: + pRepeatOffsetX = property; + break; + + case CTF_REPEAT_OFFSET_Y: + pRepeatOffsetY = property; + break; + + case CTF_DASHNAME: + case CTF_FILLGRADIENTNAME: + case CTF_FILLHATCHNAME: + case CTF_FILLBITMAPNAME: + { + OUString aStr; + if( (property->maValue >>= aStr) && aStr.isEmpty() ) + property->mnIndex = -1; + } + break; + case CTF_TEXTANIMATION_BLINKING: + pTextAnimationBlinking = property; + break; + case CTF_TEXTANIMATION_KIND: + pTextAnimationKind = property; + break; + + // #FontWork# + case CTF_FONTWORK_STYLE: pFontWorkStyle = property; break; + case CTF_FONTWORK_ADJUST: pFontWorkAdjust = property; break; + case CTF_FONTWORK_DISTANCE: pFontWorkDistance = property; break; + case CTF_FONTWORK_START: pFontWorkStart = property; break; + case CTF_FONTWORK_MIRROR: pFontWorkMirror = property; break; + case CTF_FONTWORK_OUTLINE: pFontWorkOutline = property; break; + case CTF_FONTWORK_SHADOW: pFontWorkShadow = property; break; + case CTF_FONTWORK_SHADOWCOLOR: pFontWorkShadowColor = property; break; + case CTF_FONTWORK_SHADOWOFFSETX: pFontWorkShadowOffsetx = property; break; + case CTF_FONTWORK_SHADOWOFFSETY: pFontWorkShadowOffsety = property; break; + case CTF_FONTWORK_FORM: pFontWorkForm = property; break; + case CTF_FONTWORK_HIDEFORM: pFontWorkHideform = property; break; + case CTF_FONTWORK_SHADOWTRANSPARENCE: pFontWorkShadowTransparence = property; break; + + // OLE + case CTF_SD_OLE_VIS_AREA_EXPORT_LEFT: pOLEVisAreaLeft = property; break; + case CTF_SD_OLE_VIS_AREA_EXPORT_TOP: pOLEVisAreaTop = property; break; + case CTF_SD_OLE_VIS_AREA_EXPORT_WIDTH: pOLEVisAreaWidth = property; break; + case CTF_SD_OLE_VIS_AREA_EXPORT_HEIGHT: pOLEVisAreaHeight = property; break; + case CTF_SD_OLE_ISINTERNAL: pOLEIsInternal = property; break; + + case CTF_FRAME_DISPLAY_SCROLLBAR: + { + if( !property->maValue.hasValue() ) + property->mnIndex = -1; + } + break; + case CTF_FRAME_MARGIN_HORI: + case CTF_FRAME_MARGIN_VERT: + { + sal_Int32 nValue = 0; + if( (property->maValue >>= nValue) && (nValue < 0) ) + property->mnIndex = -1; + } + break; + + case CTF_SD_MOVE_PROTECT: + { + bool bProtected; + if( (property->maValue >>= bProtected) && !bProtected ) + property->mnIndex = -1; + } + break; + case CTF_SD_SIZE_PROTECT: + { + bool bProtected; + if( (property->maValue >>= bProtected) && !bProtected ) + property->mnIndex = -1; + } + break; + case CTF_CAPTION_ISESCREL: pCaptionIsEscRel = property; break; + case CTF_CAPTION_ESCREL: pCaptionEscRel = property; break; + case CTF_CAPTION_ESCABS: pCaptionEscAbs = property; break; + case CTF_TEXT_CLIP11: pClip11State = property; break; + case CTF_TEXT_CLIP: pClipState = property; break; + } + } + + // check for duplicate writing mode + if( pShapeWritingMode && (pTextWritingMode || pControlWritingMode) ) + { + if( pTextWritingMode ) + pTextWritingMode->mnIndex = -1; + if( pControlWritingMode ) + pControlWritingMode->mnIndex = -1; + + text::WritingMode eWritingMode; + if( pShapeWritingMode->maValue >>= eWritingMode ) + { + if( text::WritingMode_LR_TB == eWritingMode ) + { + pShapeWritingMode->mnIndex = -1; + pShapeWritingMode = nullptr; + } + } + } + else if( pTextWritingMode && pControlWritingMode ) + { + pControlWritingMode->mnIndex = -1; + + sal_Int32 eWritingMode; + if (pTextWritingMode->maValue >>= eWritingMode) + { + if (text::WritingMode2::LR_TB == eWritingMode) + { + pTextWritingMode->mnIndex = -1; + pTextWritingMode = nullptr; + } + } + } + + // do not export visual area for internal ole objects + if( pOLEIsInternal ) + { + bool bInternal; + if( (pOLEIsInternal->maValue >>= bInternal) && !bInternal ) + { + try + { + awt::Rectangle aRect; + if( rPropSet->getPropertyValue( "VisibleArea" ) >>= aRect ) + { + if( pOLEVisAreaLeft ) + { + pOLEVisAreaLeft->mnIndex = getPropertySetMapper()->FindEntryIndex( CTF_SD_OLE_VIS_AREA_IMPORT_LEFT ); + pOLEVisAreaLeft->maValue <<= aRect; + } + if( pOLEVisAreaTop ) + { + pOLEVisAreaTop->mnIndex = getPropertySetMapper()->FindEntryIndex( CTF_SD_OLE_VIS_AREA_IMPORT_TOP ); + pOLEVisAreaTop->maValue <<= aRect; + } + if( pOLEVisAreaWidth ) + { + pOLEVisAreaWidth->mnIndex = getPropertySetMapper()->FindEntryIndex( CTF_SD_OLE_VIS_AREA_IMPORT_WIDTH ); + pOLEVisAreaWidth->maValue <<= aRect; + } + if( pOLEVisAreaHeight ) + { + pOLEVisAreaHeight->mnIndex = getPropertySetMapper()->FindEntryIndex( CTF_SD_OLE_VIS_AREA_IMPORT_HEIGHT ); + pOLEVisAreaHeight->maValue <<= aRect; + } + } + } + catch( uno::Exception& ) + { + } + } + else + { + if( pOLEVisAreaLeft ) pOLEVisAreaLeft->mnIndex = -1; + if( pOLEVisAreaTop ) pOLEVisAreaTop->mnIndex = -1; + if( pOLEVisAreaWidth ) pOLEVisAreaWidth->mnIndex = -1; + if( pOLEVisAreaHeight ) pOLEVisAreaHeight->mnIndex = -1; + } + + pOLEIsInternal->mnIndex = -1; + } + + if( pTextAnimationBlinking && pTextAnimationKind ) + { + drawing::TextAnimationKind eKind; + if( (pTextAnimationKind->maValue >>= eKind) && eKind != drawing::TextAnimationKind_BLINK ) + { + pTextAnimationBlinking->mnIndex = -1; + } + else + { + pTextAnimationKind->mnIndex = -1; + } + } + + if( pRepeatOffsetX && pRepeatOffsetY ) + { + sal_Int32 nOffset = 0; + if( ( pRepeatOffsetX->maValue >>= nOffset ) && ( nOffset == 0 ) ) + pRepeatOffsetX->mnIndex = -1; + else + pRepeatOffsetY->mnIndex = -1; + } + + if(pFontWorkStyle) + { + // #FontWork# + sal_Int32 nStyle = 0; + + if(pFontWorkStyle->maValue >>= nStyle) + { + if(/*XFormTextStyle::NONE*/4 == nStyle) + { + pFontWorkStyle->mnIndex = -1; + if(pFontWorkAdjust) + pFontWorkAdjust->mnIndex = -1; + if(pFontWorkDistance) + pFontWorkDistance->mnIndex = -1; + if(pFontWorkStart) + pFontWorkStart->mnIndex = -1; + if(pFontWorkMirror) + pFontWorkMirror->mnIndex = -1; + if(pFontWorkOutline) + pFontWorkOutline->mnIndex = -1; + if(pFontWorkShadow) + pFontWorkShadow->mnIndex = -1; + if(pFontWorkShadowColor) + pFontWorkShadowColor->mnIndex = -1; + if(pFontWorkShadowOffsetx) + pFontWorkShadowOffsetx->mnIndex = -1; + if(pFontWorkShadowOffsety) + pFontWorkShadowOffsety->mnIndex = -1; + if(pFontWorkForm) + pFontWorkForm->mnIndex = -1; + if(pFontWorkHideform) + pFontWorkHideform->mnIndex = -1; + if(pFontWorkShadowTransparence) + pFontWorkShadowTransparence->mnIndex = -1; + } + } + } + + if( pCaptionIsEscRel ) + { + bool bIsRel = false; + pCaptionIsEscRel->maValue >>= bIsRel; + + if( bIsRel ) + { + if( pCaptionEscAbs ) + pCaptionEscAbs->mnIndex = -1; + } + else + { + if( pCaptionEscRel ) + pCaptionEscRel->mnIndex = -1; + } + + pCaptionIsEscRel->mnIndex = -1; + } + + if( pClipState != nullptr && pClip11State != nullptr ) + pClip11State->mnIndex = -1; + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +void XMLShapeExportPropertyMapper::handleSpecialItem( + SvXMLAttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_SD_CONTROL_SHAPE_DATA_STYLE: + // not to be handled by the base class + break; + + default: + SvXMLExportPropertyMapper::handleSpecialItem( rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx ); + break; + } +} + +void XMLShapeExportPropertyMapper::handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx) const +{ + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_NUMBERINGRULES: + { + // only export list-styles as elements in styles section + if( !mbIsInAutoStyles ) + { + uno::Reference< container::XIndexReplace > xNumRule( rProperty.maValue, uno::UNO_QUERY ); + if( xNumRule.is() ) + const_cast(this)->maNumRuleExp.exportNumberingRule(GetStyleName(), false, xNumRule); + } + } + break; + default: + SvXMLExportPropertyMapper::handleElementItem( rExport, rProperty, nFlags, pProperties, nIdx ); + break; + } +} + +XMLPageExportPropertyMapper::XMLPageExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, SvXMLExport& rExport ) : + SvXMLExportPropertyMapper( rMapper ), + mrExport( rExport ) +{ +} + +XMLPageExportPropertyMapper::~XMLPageExportPropertyMapper() +{ +} + +void XMLPageExportPropertyMapper::ContextFilter( + bool bEnableFoFontFamily, + std::vector< XMLPropertyState >& rProperties, + const uno::Reference< beans::XPropertySet >& rPropSet ) const +{ + XMLPropertyState* pRepeatOffsetX = nullptr; + XMLPropertyState* pRepeatOffsetY = nullptr; + XMLPropertyState* pTransType = nullptr; + XMLPropertyState* pTransDuration = nullptr; + XMLPropertyState* pDateTimeUpdate = nullptr; + XMLPropertyState* pDateTimeFormat = nullptr; + XMLPropertyState* pTransitionFadeColor = nullptr; + + sal_Int16 nTransitionType = 0; + + // filter properties + for( auto& rProp : rProperties ) + { + XMLPropertyState *property = &rProp; + if( property->mnIndex == -1 ) + continue; + + // find properties with context + // to prevent writing this property set mnIndex member to -1 + switch( getPropertySetMapper()->GetEntryContextId( property->mnIndex )) + { + + case CTF_REPEAT_OFFSET_X: + pRepeatOffsetX = property; + break; + + case CTF_REPEAT_OFFSET_Y: + pRepeatOffsetY = property; + break; + case CTF_PAGE_TRANS_TYPE: + pTransType = property; + break; + case CTF_PAGE_TRANS_STYLE: + if( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) + (*property).mnIndex = -1; + break; + case CTF_PAGE_TRANSITION_TYPE: + { + if( (!(mrExport.getExportFlags() & SvXMLExportFlags::OASIS)) || + (((*property).maValue >>= nTransitionType) && (nTransitionType == 0)) ) + (*property).mnIndex = -1; + } + break; + case CTF_PAGE_TRANSITION_SUBTYPE: + { + sal_Int16 nTransitionSubtype = sal_Int16(); + if( (!(mrExport.getExportFlags() & SvXMLExportFlags::OASIS)) || + (((*property).maValue >>= nTransitionSubtype) && (nTransitionSubtype == 0)) ) + (*property).mnIndex = -1; + + } + break; + case CTF_PAGE_TRANSITION_DIRECTION: + { + bool bDirection; + if( (!(mrExport.getExportFlags() & SvXMLExportFlags::OASIS)) || + (((*property).maValue >>= bDirection) && bDirection) ) + (*property).mnIndex = -1; + } + break; + case CTF_PAGE_TRANSITION_FADECOLOR: + if( !(mrExport.getExportFlags() & SvXMLExportFlags::OASIS) ) + (*property).mnIndex = -1; + else + pTransitionFadeColor = property; + break; + case CTF_PAGE_TRANS_SPEED: + { + presentation::AnimationSpeed aEnum; + if( ((*property).maValue >>= aEnum) && aEnum == presentation::AnimationSpeed_MEDIUM ) + (*property).mnIndex = -1; + } + break; + case CTF_PAGE_VISIBLE: + { + bool bVisible = false; + (*property).maValue >>= bVisible; + if( bVisible ) + (*property).mnIndex = -1; + } + break; + case CTF_PAGE_TRANS_DURATION: + pTransDuration = property; + break; + case CTF_HEADER_TEXT: + case CTF_FOOTER_TEXT: + case CTF_DATE_TIME_TEXT: + { + OUString aValue; + (*property).maValue >>= aValue; + if( aValue.isEmpty() ) + (*property).mnIndex = -1; + } + break; + + case CTF_DATE_TIME_UPDATE: + pDateTimeUpdate = property; + break; + + case CTF_DATE_TIME_FORMAT: + pDateTimeFormat = property; + break; + } + } + + if( pTransitionFadeColor && nTransitionType != css::animations::TransitionType::FADE ) + pTransitionFadeColor->mnIndex = -1; + + if( pDateTimeFormat && pDateTimeUpdate ) + { + bool bIsFixed = false; + pDateTimeUpdate->maValue >>= bIsFixed; + if( bIsFixed ) + pDateTimeFormat->mnIndex = -1; + } + + if( pRepeatOffsetX && pRepeatOffsetY ) + { + sal_Int32 nOffset = 0; + if( ( pRepeatOffsetX->maValue >>= nOffset ) && ( nOffset == 0 ) ) + pRepeatOffsetX->mnIndex = -1; + else + pRepeatOffsetY->mnIndex = -1; + } + + if( pTransType && pTransDuration ) + { + sal_Int32 nChange = 0; + pTransType->maValue >>= nChange; + + // only export duration for automatic + if( nChange != 1 ) + pTransDuration->mnIndex = -1; + + // do not export default transition change + if( nChange == 0 ) + pTransType->mnIndex = -1; + } + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +void XMLPageExportPropertyMapper::handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx) const +{ + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_PAGE_SOUND_URL: + { + OUString aSoundURL; + if( (rProperty.maValue >>= aSoundURL) && !aSoundURL.isEmpty() ) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, mrExport.GetRelativeReference(aSoundURL) ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true ); + } + } + break; + default: + SvXMLExportPropertyMapper::handleElementItem( rExport, rProperty, nFlags, pProperties, nIdx ); + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdpropls.hxx b/xmloff/source/draw/sdpropls.hxx new file mode 100644 index 000000000..c73de5d61 --- /dev/null +++ b/xmloff/source/draw/sdpropls.hxx @@ -0,0 +1,131 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include + +// entry list for graphic properties + +extern const XMLPropertyMapEntry aXMLSDProperties[]; + +// entry list for presentation page properties + +extern const XMLPropertyMapEntry aXMLSDPresPageProps[]; + +// enum maps for attributes + +extern SvXMLEnumMapEntry const aXML_ConnectionKind_EnumMap[]; +extern SvXMLEnumMapEntry const aXML_CircleKind_EnumMap[]; + +/** contains the attribute to property mapping for a drawing layer table */ +extern const XMLPropertyMapEntry aXMLTableShapeAttributes[]; + +// factory for own graphic properties + +class SvXMLExport; +class SvXMLImport; + +class XMLSdPropHdlFactory : public XMLPropertyHandlerFactory +{ +private: + css::uno::Reference< css::frame::XModel > mxModel; + SvXMLExport* mpExport; + SvXMLImport* mpImport; + +public: + XMLSdPropHdlFactory( css::uno::Reference< css::frame::XModel > const & xModel, SvXMLExport& rExport ); + XMLSdPropHdlFactory( css::uno::Reference< css::frame::XModel > const & xModel, SvXMLImport& rImport ); + virtual ~XMLSdPropHdlFactory() override; + virtual const XMLPropertyHandler* GetPropertyHandler( sal_Int32 nType ) const override; +}; + +class XMLShapePropertySetMapper : public XMLPropertySetMapper +{ +public: + XMLShapePropertySetMapper(const rtl::Reference< XMLPropertyHandlerFactory >& rFactoryRef, bool bForExport); + virtual ~XMLShapePropertySetMapper() override; +}; + +class XMLShapeExportPropertyMapper : public SvXMLExportPropertyMapper +{ +private: + SvxXMLNumRuleExport maNumRuleExp; + bool mbIsInAutoStyles; + +protected: + virtual void ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet ) const override; +public: + XMLShapeExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, SvXMLExport& rExport ); + virtual ~XMLShapeExportPropertyMapper() override; + + virtual void handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx + ) const override; + + void SetAutoStyles( bool bIsInAutoStyles ) { mbIsInAutoStyles = bIsInAutoStyles; } + + virtual void handleSpecialItem( + SvXMLAttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const override; +}; + +class XMLPageExportPropertyMapper : public SvXMLExportPropertyMapper +{ +private: + SvXMLExport& mrExport; + +protected: + virtual void ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet ) const override; +public: + XMLPageExportPropertyMapper( const rtl::Reference< XMLPropertySetMapper >& rMapper, SvXMLExport& rExport ); + virtual ~XMLPageExportPropertyMapper() override; + + virtual void handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx + ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdxmlexp.cxx b/xmloff/source/draw/sdxmlexp.cxx new file mode 100644 index 000000000..50a475381 --- /dev/null +++ b/xmloff/source/draw/sdxmlexp.cxx @@ -0,0 +1,2905 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sdxmlexp_impl.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sdpropls.hxx" +#include + +#include +#include "layerexp.hxx" + +#include "XMLNumberStylesExport.hxx" + +#include + +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::office; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::geometry; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +class ImpXMLEXPPageMasterInfo +{ + sal_Int32 mnBorderBottom; + sal_Int32 mnBorderLeft; + sal_Int32 mnBorderRight; + sal_Int32 mnBorderTop; + sal_Int32 mnWidth; + sal_Int32 mnHeight; + view::PaperOrientation meOrientation; + OUString msName; + OUString msMasterPageName; + +public: + ImpXMLEXPPageMasterInfo(const SdXMLExport& rExp, const Reference& xPage); + bool operator==(const ImpXMLEXPPageMasterInfo& rInfo) const; + void SetName(const OUString& rStr); + + const OUString& GetName() const { return msName; } + const OUString& GetMasterPageName() const { return msMasterPageName; } + + sal_Int32 GetBorderBottom() const { return mnBorderBottom; } + sal_Int32 GetBorderLeft() const { return mnBorderLeft; } + sal_Int32 GetBorderRight() const { return mnBorderRight; } + sal_Int32 GetBorderTop() const { return mnBorderTop; } + sal_Int32 GetWidth() const { return mnWidth; } + sal_Int32 GetHeight() const { return mnHeight; } + view::PaperOrientation GetOrientation() const { return meOrientation; } +}; + +ImpXMLEXPPageMasterInfo::ImpXMLEXPPageMasterInfo( + const SdXMLExport& rExp, + const Reference& xPage) +: mnBorderBottom(0), + mnBorderLeft(0), + mnBorderRight(0), + mnBorderTop(0), + mnWidth(0), + mnHeight(0), + meOrientation(rExp.IsDraw() ? view::PaperOrientation_PORTRAIT : view::PaperOrientation_LANDSCAPE) +{ + Reference xPropSet(xPage, UNO_QUERY); + if(xPropSet.is()) + { + Any aAny; + + Reference< beans::XPropertySetInfo > xPropsInfo( xPropSet->getPropertySetInfo() ); + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("BorderBottom")) + { + aAny = xPropSet->getPropertyValue("BorderBottom"); + aAny >>= mnBorderBottom; + + aAny = xPropSet->getPropertyValue("BorderLeft"); + aAny >>= mnBorderLeft; + + aAny = xPropSet->getPropertyValue("BorderRight"); + aAny >>= mnBorderRight; + + aAny = xPropSet->getPropertyValue("BorderTop"); + aAny >>= mnBorderTop; + } + + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("Width")) + { + aAny = xPropSet->getPropertyValue("Width"); + aAny >>= mnWidth; + + aAny = xPropSet->getPropertyValue("Height"); + aAny >>= mnHeight; + } + + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("Orientation")) + { + aAny = xPropSet->getPropertyValue("Orientation"); + aAny >>= meOrientation; + } + } + + Reference xMasterNamed(xPage, UNO_QUERY); + if(xMasterNamed.is()) + { + msMasterPageName = xMasterNamed->getName(); + } +} + +bool ImpXMLEXPPageMasterInfo::operator==(const ImpXMLEXPPageMasterInfo& rInfo) const +{ + return ((mnBorderBottom == rInfo.mnBorderBottom) + && (mnBorderLeft == rInfo.mnBorderLeft) + && (mnBorderRight == rInfo.mnBorderRight) + && (mnBorderTop == rInfo.mnBorderTop) + && (mnWidth == rInfo.mnWidth) + && (mnHeight == rInfo.mnHeight) + && (meOrientation == rInfo.meOrientation)); +} + +void ImpXMLEXPPageMasterInfo::SetName(const OUString& rStr) +{ + msName = rStr; +} + +#define IMP_AUTOLAYOUT_INFO_MAX (35L) + +class ImpXMLAutoLayoutInfo +{ + sal_uInt16 mnType; + ImpXMLEXPPageMasterInfo* mpPageMasterInfo; + OUString msLayoutName; + tools::Rectangle maTitleRect; + tools::Rectangle maPresRect; + sal_Int32 mnGapX; + sal_Int32 mnGapY; + +public: + ImpXMLAutoLayoutInfo(sal_uInt16 nTyp, ImpXMLEXPPageMasterInfo* pInf); + + sal_uInt16 GetLayoutType() const { return mnType; } + ImpXMLEXPPageMasterInfo* GetPageMasterInfo() const { return mpPageMasterInfo; } + sal_Int32 GetGapX() const { return mnGapX; } + sal_Int32 GetGapY() const { return mnGapY; } + + const OUString& GetLayoutName() const { return msLayoutName; } + void SetLayoutName(const OUString& rNew) { msLayoutName = rNew; } + + const tools::Rectangle& GetTitleRectangle() const { return maTitleRect; } + const tools::Rectangle& GetPresRectangle() const { return maPresRect; } + + static bool IsCreateNecessary(sal_uInt16 nTyp); +}; + +bool ImpXMLAutoLayoutInfo::IsCreateNecessary(sal_uInt16 nTyp) +{ + if(nTyp == 5 /* AUTOLAYOUT_ORG */ + || nTyp == 20 /* AUTOLAYOUT_NONE */ + || nTyp >= IMP_AUTOLAYOUT_INFO_MAX) + return false; + return true; +} + +ImpXMLAutoLayoutInfo::ImpXMLAutoLayoutInfo(sal_uInt16 nTyp, ImpXMLEXPPageMasterInfo* pInf) + : mnType(nTyp) + , mpPageMasterInfo(pInf) + , mnGapX(0) + , mnGapY(0) +{ + // create full info (initialize with typical values) + Point aPagePos(0,0); + Size aPageSize(28000, 21000); + Size aPageInnerSize(28000, 21000); + + if(mpPageMasterInfo) + { + aPagePos = Point(mpPageMasterInfo->GetBorderLeft(), mpPageMasterInfo->GetBorderTop()); + aPageSize = Size(mpPageMasterInfo->GetWidth(), mpPageMasterInfo->GetHeight()); + aPageInnerSize = aPageSize; + aPageInnerSize.AdjustWidth(-(mpPageMasterInfo->GetBorderLeft() + mpPageMasterInfo->GetBorderRight())); + aPageInnerSize.AdjustHeight(-(mpPageMasterInfo->GetBorderTop() + mpPageMasterInfo->GetBorderBottom())); + } + + // title rectangle aligning + Point aTitlePos(aPagePos); + Size aTitleSize(aPageInnerSize); + + if(mnType == 21 /* AUTOLAYOUT_NOTES */) + { + aTitleSize.setHeight(static_cast(aTitleSize.Height() / 2.5)); + Point aPos = aTitlePos; + aPos.AdjustY( tools::Long( aTitleSize.Height() * 0.083 ) ); + Size aPartArea = aTitleSize; + Size aSize; + + // scale handout rectangle using actual page size + double fH = static_cast(aPartArea.Width()) / aPageSize.Width(); + double fV = static_cast(aPartArea.Height()) / aPageSize.Height(); + + if ( fH > fV ) + fH = fV; + aSize.setWidth( static_cast(fH * aPageSize.Width()) ); + aSize.setHeight( static_cast(fH * aPageSize.Height()) ); + + aPos.AdjustX((aPartArea.Width() - aSize.Width()) / 2); + aPos.AdjustY((aPartArea.Height()- aSize.Height())/ 2); + + aTitlePos = aPos; + aTitleSize = aSize; + } + else if(mnType == AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT || mnType == AUTOLAYOUT_VTITLE_VCONTENT) + { + Point aClassicTPos( + aTitlePos.X() + tools::Long( aTitleSize.Width() * 0.0735 ), + aTitlePos.Y() + tools::Long( aTitleSize.Height() * 0.083 )); + Size aClassicTSize( + tools::Long( aTitleSize.Width() * 0.854 ), + tools::Long( aTitleSize.Height() * 0.167 )); + Point aLPos(aPagePos); + Size aLSize(aPageInnerSize); + Point aClassicLPos( + aLPos.X() + tools::Long( aLSize.Width() * 0.0735 ), + aLPos.Y() + tools::Long( aLSize.Height() * 0.472 )); + Size aClassicLSize( + tools::Long( aLSize.Width() * 0.854 ), + tools::Long( aLSize.Height() * 0.444 )); + + aTitlePos.setX( (aClassicTPos.X() + aClassicTSize.Width()) - aClassicTSize.Height() ); + aTitlePos.setY( aClassicTPos.Y() ); + aTitleSize.setWidth( aClassicTSize.Height() ); + aTitleSize.setHeight( (aClassicLPos.Y() + aClassicLSize.Height()) - aClassicTPos.Y() ); + } + else + { + aTitlePos.AdjustX( tools::Long( aTitleSize.Width() * 0.0735 ) ); + aTitlePos.AdjustY( tools::Long( aTitleSize.Height() * 0.083 ) ); + aTitleSize.setWidth( tools::Long( aTitleSize.Width() * 0.854 ) ); + aTitleSize.setHeight( tools::Long( aTitleSize.Height() * 0.167 ) ); + } + + maTitleRect.SetPos(aTitlePos); + maTitleRect.SetSize(aTitleSize); + + // layout rectangle aligning + Point aLayoutPos(aPagePos); + Size aLayoutSize(aPageInnerSize); + + if(mnType == 21 /* AUTOLAYOUT_NOTES */) + { + aLayoutPos.AdjustX( tools::Long( aLayoutSize.Width() * 0.0735 ) ); + aLayoutPos.AdjustY( tools::Long( aLayoutSize.Height() * 0.472 ) ); + aLayoutSize.setWidth( tools::Long( aLayoutSize.Width() * 0.854 ) ); + aLayoutSize.setHeight( tools::Long( aLayoutSize.Height() * 0.444 ) ); + } + else if((mnType >= 22 && mnType <= 26) || (mnType == 31)) // AUTOLAYOUT_HANDOUT* + { + // keep info for inner area in maPresRect, put info for gap size + // to maTitleRect position + mnGapX = (aPageSize.Width() - aPageInnerSize.Width()) / 2; + mnGapY = (aPageSize.Height() - aPageInnerSize.Height()) / 2; + + if(!mnGapX) + mnGapX = aPageSize.Width() / 10; + + if(!mnGapY) + mnGapY = aPageSize.Height() / 10; + + if(mnGapX < aPageInnerSize.Width() / 10) + mnGapX = aPageInnerSize.Width() / 10; + + if(mnGapY < aPageInnerSize.Height() / 10) + mnGapY = aPageInnerSize.Height() / 10; + } + else if(mnType == AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT || mnType == AUTOLAYOUT_VTITLE_VCONTENT) + { + Point aClassicTPos( + aTitlePos.X() + tools::Long( aTitleSize.Width() * 0.0735 ), + aTitlePos.Y() + tools::Long( aTitleSize.Height() * 0.083 )); + Size aClassicTSize( + tools::Long( aTitleSize.Width() * 0.854 ), + tools::Long( aTitleSize.Height() * 0.167 )); + Point aClassicLPos( + aLayoutPos.X() + tools::Long( aLayoutSize.Width() * 0.0735 ), + aLayoutPos.Y() + tools::Long( aLayoutSize.Height() * 0.472 )); + Size aClassicLSize( + tools::Long( aLayoutSize.Width() * 0.854 ), + tools::Long( aLayoutSize.Height() * 0.444 )); + + aLayoutPos.setX( aClassicLPos.X() ); + aLayoutPos.setY( aClassicTPos.Y() ); + aLayoutSize.setWidth( (aClassicLPos.X() + aClassicLSize.Width()) + - (aClassicTSize.Height() + (aClassicLPos.Y() - (aClassicTPos.Y() + aClassicTSize.Height())))); + aLayoutSize.setHeight( (aClassicLPos.Y() + aClassicLSize.Height()) - aClassicTPos.Y() ); + } + else if( mnType == AUTOLAYOUT_ONLY_TEXT ) + { + aLayoutPos = aTitlePos; + aLayoutSize.setWidth( aTitleSize.Width() ); + aLayoutSize.setHeight( tools::Long( aLayoutSize.Height() * 0.825 ) ); + } + else + { + aLayoutPos.AdjustX( tools::Long( aLayoutSize.Width() * 0.0735 ) ); + aLayoutPos.AdjustY( tools::Long( aLayoutSize.Height() * 0.278 ) ); + aLayoutSize.setWidth( tools::Long( aLayoutSize.Width() * 0.854 ) ); + aLayoutSize.setHeight( tools::Long( aLayoutSize.Height() * 0.630 ) ); + } + + maPresRect.SetPos(aLayoutPos); + maPresRect.SetSize(aLayoutSize); +} + +constexpr OUStringLiteral gsPageLayoutNames( u"PageLayoutNames" ); + +SdXMLExport::SdXMLExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + bool bIsDraw, SvXMLExportFlags nExportFlags ) +: SvXMLExport( xContext, implementationName, util::MeasureUnit::CM, + bIsDraw ? XML_GRAPHICS : XML_PRESENTATION, nExportFlags ), + mnDocMasterPageCount(0), + mnDocDrawPageCount(0), + mnObjectCount(0), + mpHandoutPageMaster(nullptr), + mbIsDraw(bIsDraw) +{ + +} + +// XExporter +void SAL_CALL SdXMLExport::setSourceDocument( const Reference< lang::XComponent >& xDoc ) +{ + SvXMLExport::setSourceDocument( xDoc ); + + // prepare factory parts + mpSdPropHdlFactory = new XMLSdPropHdlFactory( GetModel(), *this ); + + // construct PropertySetMapper + rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( mpSdPropHdlFactory, true); + + // get or create text paragraph export + GetTextParagraphExport(); + mpPropertySetMapper = new XMLShapeExportPropertyMapper( xMapper, *this ); + + // chain text attributes + mpPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(*this)); + + // construct PresPagePropsMapper + xMapper = new XMLPropertySetMapper(aXMLSDPresPageProps, mpSdPropHdlFactory, true); + + mpPresPagePropsMapper = new XMLPageExportPropertyMapper( xMapper, *this ); + + // add family name + GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_GRAPHICS_ID, + OUString(XML_STYLE_FAMILY_SD_GRAPHICS_NAME), + GetPropertySetMapper(), + OUString(XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX)); + GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_PRESENTATION_ID, + OUString(XML_STYLE_FAMILY_SD_PRESENTATION_NAME), + GetPropertySetMapper(), + OUString(XML_STYLE_FAMILY_SD_PRESENTATION_PREFIX)); + GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_DRAWINGPAGE_ID, + OUString(XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME), + GetPresPagePropsMapper(), + OUString(XML_STYLE_FAMILY_SD_DRAWINGPAGE_PREFIX)); + // prepare access to styles + Reference< style::XStyleFamiliesSupplier > xFamSup( GetModel(), UNO_QUERY ); + if(xFamSup.is()) + { + mxDocStyleFamilies = xFamSup->getStyleFamilies(); + } + + // prepare access to master pages + Reference < drawing::XMasterPagesSupplier > xMasterPagesSupplier(GetModel(), UNO_QUERY); + if(xMasterPagesSupplier.is()) + { + mxDocMasterPages = xMasterPagesSupplier->getMasterPages(); + if(mxDocMasterPages.is()) + { + mnDocMasterPageCount = mxDocMasterPages->getCount(); + maMasterPagesStyleNames.insert( maMasterPagesStyleNames.begin(), mnDocMasterPageCount, "" ); + } + } + + // prepare access to draw pages + Reference xDrawPagesSupplier(GetModel(), UNO_QUERY); + if(xDrawPagesSupplier.is()) + { + mxDocDrawPages = xDrawPagesSupplier->getDrawPages(); + if(mxDocDrawPages.is()) + { + mnDocDrawPageCount = mxDocDrawPages->getCount(); + maDrawPagesStyleNames.insert( maDrawPagesStyleNames.begin(), mnDocDrawPageCount, "" ); + maDrawNotesPagesStyleNames.insert( maDrawNotesPagesStyleNames.begin(), mnDocDrawPageCount, "" ); + if( !mbIsDraw ) + maDrawPagesAutoLayoutNames.realloc( mnDocDrawPageCount + 1 ); + + HeaderFooterPageSettingsImpl aEmptySettings; + maDrawPagesHeaderFooterSettings.insert( maDrawPagesHeaderFooterSettings.begin(), mnDocDrawPageCount, aEmptySettings ); + maDrawNotesPagesHeaderFooterSettings.insert( maDrawNotesPagesHeaderFooterSettings.begin(), mnDocDrawPageCount, aEmptySettings ); + } + } + + // #82003# count all draw objects for use with progress bar. + // #88245# init mnObjectCount once, use counter itself as flag. It + // is initialized to 0. + if(!mnObjectCount) + { + if( IsImpress() ) + { + // #91587# add handout master count + Reference xHandoutSupp(GetModel(), UNO_QUERY); + if(xHandoutSupp.is()) + { + Reference xHandoutPage(xHandoutSupp->getHandoutMasterPage()); + if(xHandoutPage.is() && xHandoutPage->getCount()) + mnObjectCount += ImpRecursiveObjectCount(xHandoutPage); + } + } + + if(mxDocMasterPages.is()) + { + for(sal_Int32 a(0); a < mnDocMasterPageCount; a++) + { + Any aAny(mxDocMasterPages->getByIndex(a)); + Reference< drawing::XShapes > xMasterPage; + + if((aAny >>= xMasterPage) && xMasterPage.is()) + { + mnObjectCount += ImpRecursiveObjectCount(xMasterPage); + } + + if( IsImpress() ) + { + // #91587# take notes pages from master pages into account + Reference xPresPage; + if((aAny >>= xPresPage) && xPresPage.is()) + { + Reference xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is() && xNotesPage->getCount()) + mnObjectCount += ImpRecursiveObjectCount(xNotesPage); + } + } + } + } + + if(mxDocDrawPages.is()) + { + for(sal_Int32 a(0); a < mnDocDrawPageCount; a++) + { + Any aAny(mxDocDrawPages->getByIndex(a)); + Reference< drawing::XShapes > xPage; + + if((aAny >>= xPage) && xPage.is()) + { + mnObjectCount += ImpRecursiveObjectCount(xPage); + } + + if( IsImpress() ) + { + // #91587# take notes pages from draw pages into account + Reference xPresPage; + if((aAny >>= xPresPage) && xPresPage.is()) + { + Reference xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is() && xNotesPage->getCount()) + mnObjectCount += ImpRecursiveObjectCount(xNotesPage); + } + } + } + } + + // #82003# init progress bar + GetProgressBarHelper()->SetReference(mnObjectCount); + } + + // add namespaces + GetNamespaceMap_().Add( + GetXMLToken(XML_NP_PRESENTATION), + GetXMLToken(XML_N_PRESENTATION), + XML_NAMESPACE_PRESENTATION); + + GetNamespaceMap_().Add( + GetXMLToken(XML_NP_SMIL), + GetXMLToken(XML_N_SMIL_COMPAT), + XML_NAMESPACE_SMIL); + + GetNamespaceMap_().Add( + GetXMLToken(XML_NP_ANIMATION), + GetXMLToken(XML_N_ANIMATION), + XML_NAMESPACE_ANIMATION); + + if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + GetNamespaceMap_().Add( + GetXMLToken(XML_NP_OFFICE_EXT), + GetXMLToken(XML_N_OFFICE_EXT), + XML_NAMESPACE_OFFICE_EXT); + } + + GetShapeExport()->enableLayerExport(); + + // #88546# enable progress bar increments + GetShapeExport()->enableHandleProgressBar(); +} + +// #82003# helper function for recursive object count +sal_uInt32 SdXMLExport::ImpRecursiveObjectCount(const Reference< drawing::XShapes >& xShapes) +{ + sal_uInt32 nRetval(0); + + if(xShapes.is()) + { + sal_Int32 nCount = xShapes->getCount(); + + for(sal_Int32 a(0); a < nCount; a++) + { + Any aAny(xShapes->getByIndex(a)); + Reference< drawing::XShapes > xGroup; + + if((aAny >>= xGroup) && xGroup.is()) + { + // #93180# count group objects, too. + nRetval += 1 + ImpRecursiveObjectCount(xGroup); + } + else + { + nRetval++; + } + } + } + + return nRetval; +} + +SdXMLExport::~SdXMLExport() +{ + // cleanup factory, decrease refcount. Should lead to destruction. + mpSdPropHdlFactory.clear(); + + // cleanup mapper, decrease refcount. Should lead to destruction. + mpPropertySetMapper.clear(); + + // cleanup presPage mapper, decrease refcount. Should lead to destruction. + mpPresPagePropsMapper.clear(); + + mvPageMasterInfoList.clear(); + + // clear auto-layout infos + mvAutoLayoutInfoList.clear(); +} + +void SdXMLExport::ImpPrepAutoLayoutInfos() +{ + if(!IsImpress()) + return; + + OUString aStr; + auto DrawPagesAutoLayoutNamesRange = asNonConstRange(maDrawPagesAutoLayoutNames); + Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetModel(), UNO_QUERY ); + if( xHandoutSupp.is() ) + { + Reference< XDrawPage > xHandoutPage( xHandoutSupp->getHandoutMasterPage() ); + if( xHandoutPage.is() ) + { + if(ImpPrepAutoLayoutInfo(xHandoutPage, aStr)) + DrawPagesAutoLayoutNamesRange[0] = aStr; + } + } + + // prepare name creation + for (sal_Int32 nCnt = 0; nCnt < mnDocDrawPageCount; nCnt++) + { + Any aAny(mxDocDrawPages->getByIndex(nCnt)); + Reference xDrawPage; + + if((aAny >>= xDrawPage) && xDrawPage.is()) + { + if(ImpPrepAutoLayoutInfo(xDrawPage, aStr)) + DrawPagesAutoLayoutNamesRange[nCnt+1] = aStr; + } + } +} + +bool SdXMLExport::ImpPrepAutoLayoutInfo(const Reference& xPage, OUString& rName) +{ + rName.clear(); + bool bRetval(false); + + Reference xPropSet(xPage, UNO_QUERY); + if(xPropSet.is()) + { + sal_uInt16 nType = sal_uInt16(); + Any aAny = xPropSet->getPropertyValue("Layout"); + if(aAny >>= nType) + { + if(ImpXMLAutoLayoutInfo::IsCreateNecessary(nType)) + { + ImpXMLEXPPageMasterInfo* pInfo = nullptr; + + // get master-page info + Reference < drawing::XMasterPageTarget > xMasterPageInt(xPage, UNO_QUERY); + if(xMasterPageInt.is()) + { + Reference xUsedMasterPage(xMasterPageInt->getMasterPage()); + if(xUsedMasterPage.is()) + { + Reference < container::XNamed > xMasterNamed(xUsedMasterPage, UNO_QUERY); + if(xMasterNamed.is()) + { + OUString sMasterPageName = xMasterNamed->getName(); + pInfo = ImpGetPageMasterInfoByName(sMasterPageName); + } + } + } + + // create entry and look for existence + ImpXMLAutoLayoutInfo* pNew; + auto it = std::find_if(mvAutoLayoutInfoList.begin(), mvAutoLayoutInfoList.end(), + [=](std::unique_ptr const & rInfo) { return nType == rInfo->GetLayoutType() && pInfo == rInfo->GetPageMasterInfo(); }); + if (it != mvAutoLayoutInfoList.end()) + { + pNew = it->get(); + } + else + { + pNew = new ImpXMLAutoLayoutInfo(nType, pInfo); + mvAutoLayoutInfoList.emplace_back( pNew ); + OUString sNewName = + "AL" + OUString::number(mvAutoLayoutInfoList.size() - 1) + + "T" + OUString::number(nType); + pNew->SetLayoutName(sNewName); + } + + rName = pNew->GetLayoutName(); + bRetval = true; + } + } + } + + return bRetval; +} + +void SdXMLExport::ImpWriteAutoLayoutInfos() +{ + for(const auto & pInfo : mvAutoLayoutInfoList) + { + if(pInfo) + { + // prepare presentation-page layout attributes, style-name + AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, pInfo->GetLayoutName()); + + // write draw-style attributes + SvXMLElementExport aDSE(*this, XML_NAMESPACE_STYLE, XML_PRESENTATION_PAGE_LAYOUT, true, true); + + // write presentation placeholders + switch(pInfo->GetLayoutType()) + { + case AUTOLAYOUT_TITLE : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderSubtitle, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_CONTENT : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_CHART : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderChart, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_2CONTENT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.SetLeft(tools::Long(aRight.Left() + aRight.GetWidth() * 1.05)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TEXTCHART : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.SetLeft( tools::Long(aRight.Left() + aRight.GetWidth() * 1.05) ); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderChart, aRight); + break; + } + case AUTOLAYOUT_TEXTCLIP : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.SetLeft(tools::Long(aRight.Left() + aRight.GetWidth() * 1.05)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aRight); + break; + } + case AUTOLAYOUT_CHARTTEXT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.SetLeft(tools::Long(aRight.Left() + aRight.GetWidth() * 1.05)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderChart, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TAB : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTable, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_CLIPTEXT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.SetLeft(tools::Long(aRight.Left() + aRight.GetWidth() * 1.05)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TEXTOBJ : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.SetLeft(tools::Long(aRight.Left() + aRight.GetWidth() * 1.05)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aRight); + break; + } + case AUTOLAYOUT_OBJ : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_CONTENT_2CONTENT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRightTop(aLeft); + aRightTop.SetLeft(tools::Long(aRightTop.Left() + aRightTop.GetWidth() * 1.05)); + aRightTop.setHeight(tools::Long(aRightTop.GetHeight() * 0.477)); + tools::Rectangle aRightBottom(aRightTop); + aRightBottom.SetTop(tools::Long(aRightBottom.Top() + aRightBottom.GetHeight() * 1.095)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aRightTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aRightBottom); + break; + } + case AUTOLAYOUT_OBJTEXT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.SetLeft(tools::Long(aRight.Left() + aRight.GetWidth() * 1.05)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT : + { + tools::Rectangle aTop(pInfo->GetPresRectangle()); + aTop.setHeight(tools::Long(aTop.GetHeight() * 0.477)); + tools::Rectangle aBottom(aTop); + aBottom.SetTop(tools::Long(aBottom.Top() + aBottom.GetHeight() * 1.095)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aBottom); + break; + } + case AUTOLAYOUT_TITLE_2CONTENT_CONTENT : + { + tools::Rectangle aLeftTop(pInfo->GetPresRectangle()); + aLeftTop.setWidth(tools::Long(aLeftTop.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeftTop); + aRight.SetLeft(tools::Long(aRight.Left() + aRight.GetWidth() * 1.05)); + aLeftTop.setHeight(tools::Long(aLeftTop.GetHeight() * 0.477)); + tools::Rectangle aLeftBottom(aLeftTop); + aLeftBottom.SetTop(tools::Long(aLeftBottom.Top() + aLeftBottom.GetHeight() * 1.095)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aLeftTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aLeftBottom); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aRight); + break; + } + case AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT : + { + tools::Rectangle aTopLeft(pInfo->GetPresRectangle()); + aTopLeft.setHeight(tools::Long(aTopLeft.GetHeight() * 0.477)); + tools::Rectangle aBottom(aTopLeft); + aBottom.SetTop(tools::Long(aBottom.Top() + aBottom.GetHeight() * 1.095)); + aTopLeft.setWidth(tools::Long(aTopLeft.GetWidth() * 0.488)); + tools::Rectangle aTopRight(aTopLeft); + aTopRight.SetLeft(tools::Long(aTopRight.Left() + aTopRight.GetWidth() * 1.05)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTopLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTopRight); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aBottom); + break; + } + case AUTOLAYOUT_TEXTOVEROBJ : + { + tools::Rectangle aTop(pInfo->GetPresRectangle()); + aTop.setHeight(tools::Long(aTop.GetHeight() * 0.477)); + tools::Rectangle aBottom(aTop); + aBottom.SetTop(tools::Long(aBottom.Top() + aBottom.GetHeight() * 1.095)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderOutline, aTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aBottom); + break; + } + case AUTOLAYOUT_TITLE_4CONTENT : + { + tools::Rectangle aTopLeft(pInfo->GetPresRectangle()); + aTopLeft.setHeight(tools::Long(aTopLeft.GetHeight() * 0.477)); + aTopLeft.setWidth(tools::Long(aTopLeft.GetWidth() * 0.488)); + tools::Rectangle aBottomLeft(aTopLeft); + aBottomLeft.SetTop(tools::Long(aBottomLeft.Top() + aBottomLeft.GetHeight() * 1.095)); + tools::Rectangle aTopRight(aTopLeft); + aTopRight.SetLeft(tools::Long(aTopRight.Left() + aTopRight.GetWidth() * 1.05)); + tools::Rectangle aBottomRight(aTopRight); + aBottomRight.SetTop(tools::Long(aBottomRight.Top() + aBottomRight.GetHeight() * 1.095)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTopLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aTopRight); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aBottomLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderObject, aBottomRight); + break; + } + case AUTOLAYOUT_TITLE_ONLY : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + break; + } + case AUTOLAYOUT_NOTES : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderPage, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderNotes, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_HANDOUT1 : + case AUTOLAYOUT_HANDOUT2 : + case AUTOLAYOUT_HANDOUT3 : + case AUTOLAYOUT_HANDOUT4 : + case AUTOLAYOUT_HANDOUT6 : + case AUTOLAYOUT_HANDOUT9 : + { + sal_Int32 nColCnt, nRowCnt; + sal_Int32 nGapX = pInfo->GetGapX(); + sal_Int32 nGapY = pInfo->GetGapY(); + + switch(pInfo->GetLayoutType()) + { + case 22 : nColCnt = 1; nRowCnt = 1; break; + case 23 : nColCnt = 1; nRowCnt = 2; break; + case 24 : nColCnt = 1; nRowCnt = 3; break; + case 25 : nColCnt = 2; nRowCnt = 2; break; + case 26 : nColCnt = 3; nRowCnt = 2; break; + case 31 : nColCnt = 3; nRowCnt = 3; break; + default: nColCnt = 0; nRowCnt = 0; break; // FIXME - What is correct values? + } + + Size aPartSize(pInfo->GetTitleRectangle().GetSize()); + Point aPartPos(pInfo->GetTitleRectangle().TopLeft()); + + if(aPartSize.Width() > aPartSize.Height()) + { + sal_Int32 nZwi(nColCnt); + nColCnt = nRowCnt; + nRowCnt = nZwi; + } + + if (nColCnt == 0 || nRowCnt == 0) + break; + + aPartSize.setWidth( (aPartSize.Width() - ((nColCnt - 1) * nGapX)) / nColCnt ); + aPartSize.setHeight( (aPartSize.Height() - ((nRowCnt - 1) * nGapY)) / nRowCnt ); + + Point aTmpPos(aPartPos); + + for (sal_Int32 a = 0; a < nRowCnt; a++) + { + aTmpPos.setX(aPartPos.X()); + + for (sal_Int32 b = 0; b < nColCnt; b++) + { + tools::Rectangle aTmpRect(aTmpPos, aPartSize); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderHandout, aTmpRect); + aTmpPos.AdjustX( aPartSize.Width() + nGapX ); + } + + aTmpPos.AdjustY( aPartSize.Height() + nGapY ); + } + break; + } + case AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT : + { + tools::Rectangle aTop(pInfo->GetPresRectangle()); + aTop.setHeight(tools::Long(aTop.GetHeight() * 0.488)); + tools::Rectangle aBottom(aTop); + aBottom.SetTop(tools::Long(aBottom.Top() + aBottom.GetHeight() * 1.05)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalOutline, aTop); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderChart, aBottom); + break; + } + case AUTOLAYOUT_VTITLE_VCONTENT : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalOutline, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_VCONTENT : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalOutline, pInfo->GetPresRectangle()); + break; + } + case AUTOLAYOUT_TITLE_2VTEXT : + { + tools::Rectangle aLeft(pInfo->GetPresRectangle()); + aLeft.setWidth(tools::Long(aLeft.GetWidth() * 0.488)); + tools::Rectangle aRight(aLeft); + aRight.SetLeft(tools::Long(aRight.Left() + aRight.GetWidth() * 1.05)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderVerticalOutline, aRight); + break; + } + case AUTOLAYOUT_ONLY_TEXT : + { + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderSubtitle, pInfo->GetPresRectangle()); + break; + } + + case AUTOLAYOUT_4CLIPART : + { + tools::Rectangle aTopLeft(pInfo->GetPresRectangle()); + aTopLeft.setHeight(tools::Long(aTopLeft.GetHeight() * 0.477)); + aTopLeft.setWidth(tools::Long(aTopLeft.GetWidth() * 0.488)); + tools::Rectangle aBottomLeft(aTopLeft); + aBottomLeft.SetTop(tools::Long(aBottomLeft.Top() + aBottomLeft.GetHeight() * 1.095)); + tools::Rectangle aTopRight(aTopLeft); + aTopRight.SetLeft(tools::Long(aTopRight.Left() + aTopRight.GetWidth() * 1.05)); + tools::Rectangle aBottomRight(aTopRight); + aBottomRight.SetTop(tools::Long(aBottomRight.Top() + aBottomRight.GetHeight() * 1.095)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopRight); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomRight); + break; + } + + case AUTOLAYOUT_TITLE_6CONTENT : + { + tools::Rectangle aTopLeft(pInfo->GetPresRectangle()); + aTopLeft.setHeight(tools::Long(aTopLeft.GetHeight() * 0.477)); + aTopLeft.setWidth(tools::Long(aTopLeft.GetWidth() * 0.322)); + tools::Rectangle aTopCenter(aTopLeft); + aTopCenter.SetLeft(tools::Long(aTopCenter.Left() + aTopCenter.GetWidth() * 1.05)); + tools::Rectangle aTopRight(aTopLeft); + aTopRight.SetLeft(tools::Long(aTopRight.Left() + aTopRight.GetWidth() * 2 * 1.05)); + + tools::Rectangle aBottomLeft(aTopLeft); + aBottomLeft.SetTop(tools::Long(aBottomLeft.Top() + aBottomLeft.GetHeight() * 1.095)); + tools::Rectangle aBottomCenter(aTopCenter); + aBottomCenter.SetTop(tools::Long(aBottomCenter.Top() + aBottomCenter.GetHeight() * 1.095)); + tools::Rectangle aBottomRight(aTopRight); + aBottomRight.SetTop(tools::Long(aBottomRight.Top() + aBottomRight.GetHeight() * 1.095)); + + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderTitle, pInfo->GetTitleRectangle()); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopCenter); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aTopRight); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomLeft); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomCenter); + ImpWriteAutoLayoutPlaceholder(XmlPlaceholderGraphic, aBottomRight); + break; + } + default: + { + OSL_FAIL("XMLEXP: unknown autolayout export"); + break; + } + } + } + } +} + +void SdXMLExport::ImpWriteAutoLayoutPlaceholder(XmlPlaceholder ePl, const tools::Rectangle& rRect) +{ + OUString aStr; + OUStringBuffer sStringBuffer; + + // prepare presentation-placeholder attributes, presentation:object + switch(ePl) + { + case XmlPlaceholderTitle: aStr = "title"; break; + case XmlPlaceholderOutline: aStr = "outline"; break; + case XmlPlaceholderSubtitle: aStr = "subtitle"; break; + case XmlPlaceholderGraphic: aStr = "graphic"; break; + case XmlPlaceholderObject: aStr = "object"; break; + case XmlPlaceholderChart: aStr = "chart"; break; + case XmlPlaceholderTable: aStr = "table"; break; + case XmlPlaceholderPage: aStr = "page"; break; + case XmlPlaceholderNotes: aStr = "notes"; break; + case XmlPlaceholderHandout: aStr = "handout"; break; + case XmlPlaceholderVerticalTitle: aStr = "vertical_title"; break; + case XmlPlaceholderVerticalOutline: aStr = "vertical_outline"; break; + } + + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_OBJECT, aStr); + + // svg:x,y,width,height + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, rRect.Left()); + aStr = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, rRect.Top()); + aStr = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + rRect.GetWidth()); + aStr = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + rRect.GetHeight()); + aStr = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr); + + // write presentation-placeholder + SvXMLElementExport aPPL(*this, XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, true, true); +} + +ImpXMLEXPPageMasterInfo* SdXMLExport::ImpGetOrCreatePageMasterInfo( const Reference< XDrawPage >& xMasterPage ) +{ + bool bDoesExist = false; + + ImpXMLEXPPageMasterInfo* pNewInfo = new ImpXMLEXPPageMasterInfo(*this, xMasterPage); + + // compare with prev page-master infos + for( size_t a = 0; !bDoesExist && a < mvPageMasterInfoList.size(); a++) + { + if ( mvPageMasterInfoList.at(a) + && *mvPageMasterInfoList.at(a) == *pNewInfo + ) + { + delete pNewInfo; + pNewInfo = mvPageMasterInfoList.at(a).get(); + bDoesExist = true; + } + } + // add entry when not found same page-master infos + if(!bDoesExist) + mvPageMasterInfoList.emplace_back( pNewInfo ); + + return pNewInfo; +} + +void SdXMLExport::ImpPrepPageMasterInfos() +{ + if( IsImpress() ) + { + // create page master info for handout master page + + Reference< XHandoutMasterSupplier > xHMS( GetModel(), UNO_QUERY ); + if( xHMS.is() ) + { + Reference< XDrawPage > xMasterPage( xHMS->getHandoutMasterPage() ); + if( xMasterPage.is() ) + mpHandoutPageMaster = ImpGetOrCreatePageMasterInfo(xMasterPage); + } + } + + // create page master infos for master pages + if(!mnDocMasterPageCount) + return; + + // look for needed page-masters, create these + for (sal_Int32 nMPageId = 0; nMPageId < mnDocMasterPageCount; nMPageId++) + { + Reference< XDrawPage > xMasterPage( mxDocMasterPages->getByIndex(nMPageId), UNO_QUERY ); + ImpXMLEXPPageMasterInfo* pNewInfo = nullptr; + + if(xMasterPage.is()) + pNewInfo = ImpGetOrCreatePageMasterInfo(xMasterPage); + + mvPageMasterUsageList.push_back( pNewInfo ); + + // look for page master of handout page + if(IsImpress()) + { + pNewInfo = nullptr; + Reference< presentation::XPresentationPage > xPresPage(xMasterPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + pNewInfo = ImpGetOrCreatePageMasterInfo(xNotesPage); + } + } + mvNotesPageMasterUsageList.push_back( pNewInfo ); + } + } +} + +void SdXMLExport::ImpWritePageMasterInfos() +{ + // write created page-masters, create names for these + for( size_t nCnt = 0; nCnt < mvPageMasterInfoList.size(); nCnt++) + { + ImpXMLEXPPageMasterInfo* pInfo = mvPageMasterInfoList.at(nCnt).get(); + if(pInfo) + { + // create name + OUString sNewName = "PM" + OUString::number(nCnt); + pInfo->SetName(sNewName); + + // prepare page-master attributes + OUString sString; + OUStringBuffer sStringBuffer; + + sString = sNewName; + AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, sString); + + // write page-layout + SvXMLElementExport aPME(*this, XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT, true, true); + + // prepare style:properties inside page-master + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetBorderTop()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_MARGIN_TOP, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetBorderBottom()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetBorderLeft()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_MARGIN_LEFT, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetBorderRight()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_MARGIN_RIGHT, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetWidth()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_PAGE_WIDTH, sString); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + pInfo->GetHeight()); + sString = sStringBuffer.makeStringAndClear(); + AddAttribute(XML_NAMESPACE_FO, XML_PAGE_HEIGHT, sString); + + if(pInfo->GetOrientation() == view::PaperOrientation_PORTRAIT) + AddAttribute(XML_NAMESPACE_STYLE, XML_PRINT_ORIENTATION, XML_PORTRAIT); + else + AddAttribute(XML_NAMESPACE_STYLE, XML_PRINT_ORIENTATION, XML_LANDSCAPE); + + // write style:properties + SvXMLElementExport aPMF(*this, XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_PROPERTIES, true, true); + } + } +} + +ImpXMLEXPPageMasterInfo* SdXMLExport::ImpGetPageMasterInfoByName(std::u16string_view rName) +{ + if(!rName.empty()) + { + for(const auto & pInfo : mvPageMasterInfoList) + { + if(pInfo) + { + if(!pInfo->GetMasterPageName().isEmpty() && rName == pInfo->GetMasterPageName()) + { + return pInfo.get(); + } + } + } + } + return nullptr; +} + +void SdXMLExport::ImpPrepDrawPageInfos() +{ + // create draw:style-name entries for page export + // containing presentation page attributes AND background attributes + // fixed family for page-styles is "drawing-page" (XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME) + + sal_Int32 nCnt; + for(nCnt = 0; nCnt < mnDocDrawPageCount; nCnt++) + { + Reference xDrawPage; + mxDocDrawPages->getByIndex(nCnt) >>= xDrawPage; + maDrawPagesStyleNames[nCnt] = ImpCreatePresPageStyleName( xDrawPage ); + + Reference< presentation::XPresentationPage > xPresPage(xDrawPage, UNO_QUERY); + if(xPresPage.is()) + { + maDrawNotesPagesStyleNames[nCnt] = ImpCreatePresPageStyleName( xPresPage->getNotesPage(), false ); + + maDrawPagesHeaderFooterSettings[nCnt] = ImpPrepDrawPageHeaderFooterDecls( xDrawPage ); + maDrawNotesPagesHeaderFooterSettings[nCnt] = ImpPrepDrawPageHeaderFooterDecls( xPresPage->getNotesPage() ); + } + } +} + +static OUString findOrAppendImpl( std::vector< OUString >& rVector, const OUString& rText, std::u16string_view pPrefix ) +{ + // search rVector if there is already a string that equals rText + auto aIter = std::find(rVector.begin(), rVector.end(), rText); + sal_Int32 nIndex = std::distance(rVector.begin(), aIter) + 1; + + // if nothing is found, append the string at the end of rVector + if( aIter == rVector.end() ) + rVector.push_back( rText ); + + // create a reference string with pPrefix and the index of the + // found or created rText + return pPrefix + OUString::number( nIndex ); +} + +static OUString findOrAppendImpl( std::vector< DateTimeDeclImpl >& rVector, const OUString& rText, bool bFixed, sal_Int32 nFormat, std::u16string_view pPrefix ) +{ + // search rVector if there is already a DateTimeDeclImpl with rText,bFixed and nFormat + auto aIter = std::find_if(rVector.begin(), rVector.end(), + [bFixed, &rText, nFormat](const DateTimeDeclImpl& rDecl) { + return (rDecl.mbFixed == bFixed) && + (!bFixed || (rDecl.maStrText == rText)) && + (bFixed || (rDecl.mnFormat == nFormat)); + }); + sal_Int32 nIndex = std::distance(rVector.begin(), aIter) + 1; + + // if nothing is found, append a new DateTimeDeclImpl + if( aIter == rVector.end() ) + { + DateTimeDeclImpl aDecl; + aDecl.maStrText = rText; + aDecl.mbFixed = bFixed; + aDecl.mnFormat = nFormat; + rVector.push_back( aDecl ); + } + + // create a reference string with pPrefix and the index of the + // found or created DateTimeDeclImpl + return pPrefix + OUString::number( nIndex ); +} + +constexpr OUStringLiteral gpStrHeaderTextPrefix = u"hdr"; +constexpr OUStringLiteral gpStrFooterTextPrefix = u"ftr"; +constexpr OUStringLiteral gpStrDateTimeTextPrefix = u"dtd"; + +HeaderFooterPageSettingsImpl SdXMLExport::ImpPrepDrawPageHeaderFooterDecls( const Reference& xDrawPage ) +{ + HeaderFooterPageSettingsImpl aSettings; + + if( xDrawPage.is() ) try + { + Reference< XPropertySet > xSet( xDrawPage, UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xInfo( xSet->getPropertySetInfo() ); + + OUString aStrText; + + static const OUStringLiteral aStrHeaderTextProp( u"HeaderText" ); + if( xInfo->hasPropertyByName( aStrHeaderTextProp ) ) + { + xSet->getPropertyValue( aStrHeaderTextProp ) >>= aStrText; + if( !aStrText.isEmpty() ) + aSettings.maStrHeaderDeclName = findOrAppendImpl( maHeaderDeclsVector, aStrText, gpStrHeaderTextPrefix ); + } + + static const OUStringLiteral aStrFooterTextProp( u"FooterText" ); + if( xInfo->hasPropertyByName( aStrFooterTextProp ) ) + { + xSet->getPropertyValue( aStrFooterTextProp ) >>= aStrText; + if( !aStrText.isEmpty() ) + aSettings.maStrFooterDeclName = findOrAppendImpl( maFooterDeclsVector, aStrText, gpStrFooterTextPrefix ); + } + + static const OUStringLiteral aStrDateTimeTextProp( u"DateTimeText" ); + if( xInfo->hasPropertyByName( aStrDateTimeTextProp ) ) + { + bool bFixed = false; + sal_Int32 nFormat = 0; + xSet->getPropertyValue( aStrDateTimeTextProp ) >>= aStrText; + xSet->getPropertyValue("IsDateTimeFixed") >>= bFixed; + xSet->getPropertyValue("DateTimeFormat") >>= nFormat; + + if( !bFixed || !aStrText.isEmpty() ) + { + aSettings.maStrDateTimeDeclName = findOrAppendImpl( maDateTimeDeclsVector, aStrText, bFixed, nFormat, gpStrDateTimeTextPrefix ); + if( !bFixed ) + addDataStyle( nFormat ); + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + + return aSettings; +} + +void SdXMLExport::ImpWriteHeaderFooterDecls() +{ + OUStringBuffer sBuffer; + + if( !maHeaderDeclsVector.empty() ) + { + // export header decls + const OUString aPrefix( gpStrHeaderTextPrefix ); + sal_Int32 nIndex = 1; + for( const auto& rDecl : maHeaderDeclsVector ) + { + sBuffer.append( aPrefix ); + sBuffer.append( nIndex ); + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_NAME, sBuffer.makeStringAndClear()); + + SvXMLElementExport aElem(*this, XML_NAMESPACE_PRESENTATION, XML_HEADER_DECL, true, true); + Characters(rDecl); + ++nIndex; + } + } + + if( !maFooterDeclsVector.empty() ) + { + // export footer decls + const OUString aPrefix( gpStrFooterTextPrefix ); + sal_Int32 nIndex = 1; + for( const auto& rDecl : maFooterDeclsVector ) + { + sBuffer.append( aPrefix ); + sBuffer.append( nIndex ); + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_NAME, sBuffer.makeStringAndClear()); + + SvXMLElementExport aElem(*this, XML_NAMESPACE_PRESENTATION, XML_FOOTER_DECL, false, false); + Characters(rDecl); + ++nIndex; + } + } + + if( maDateTimeDeclsVector.empty() ) + return; + + // export footer decls + const OUString aPrefix( gpStrDateTimeTextPrefix ); + sal_Int32 nIndex = 1; + for( const auto& rDecl : maDateTimeDeclsVector ) + { + sBuffer.append( aPrefix ); + sBuffer.append( nIndex ); + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_NAME, sBuffer.makeStringAndClear()); + + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SOURCE, rDecl.mbFixed ? XML_FIXED : XML_CURRENT_DATE ); + + if( !rDecl.mbFixed ) + AddAttribute( XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, getDataStyleName( rDecl.mnFormat ) ); + + SvXMLElementExport aElem(*this, XML_NAMESPACE_PRESENTATION, XML_DATE_TIME_DECL, false, false); + if( rDecl.mbFixed ) + Characters(rDecl.maStrText); + + ++nIndex; + } +} + +void SdXMLExport::ImplExportHeaderFooterDeclAttributes( const HeaderFooterPageSettingsImpl& aSettings ) +{ + if( !aSettings.maStrHeaderDeclName.isEmpty() ) + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_USE_HEADER_NAME, aSettings.maStrHeaderDeclName ); + + if( !aSettings.maStrFooterDeclName.isEmpty() ) + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_USE_FOOTER_NAME, aSettings.maStrFooterDeclName ); + + if( !aSettings.maStrDateTimeDeclName.isEmpty() ) + AddAttribute( XML_NAMESPACE_PRESENTATION, XML_USE_DATE_TIME_NAME, aSettings.maStrDateTimeDeclName ); +} + +OUString SdXMLExport::ImpCreatePresPageStyleName( const Reference& xDrawPage, bool bExportBackground /* = true */ ) +{ + // create name + OUString sStyleName; + + // create style for this page and add to auto style pool + + Reference< beans::XPropertySet > xPropSet1(xDrawPage, UNO_QUERY); + if(xPropSet1.is()) + { + Reference< beans::XPropertySet > xPropSet; + + if( bExportBackground ) + { + // since the background items are in a different propertyset + // which itself is a property of the pages property set + // we now merge these two propertysets if possible to simulate + // a single propertyset with all draw page properties + static const OUStringLiteral aBackground(u"Background"); + Reference< beans::XPropertySet > xPropSet2; + Reference< beans::XPropertySetInfo > xInfo( xPropSet1->getPropertySetInfo() ); + if( xInfo.is() && xInfo->hasPropertyByName( aBackground ) ) + { + Any aAny( xPropSet1->getPropertyValue( aBackground ) ); + aAny >>= xPropSet2; + } + + if( xPropSet2.is() ) + xPropSet = PropertySetMerger_CreateInstance( xPropSet1, xPropSet2 ); + else + xPropSet = xPropSet1; + } + else + { + xPropSet = xPropSet1; + } + + const rtl::Reference< SvXMLExportPropertyMapper > aMapperRef( GetPresPagePropsMapper() ); + + std::vector aPropStates(aMapperRef->Filter(*this, xPropSet)); + + if( !aPropStates.empty() ) + { + // there are filtered properties -> hard attributes + // try to find this style in AutoStylePool + sStyleName = GetAutoStylePool()->Find(XmlStyleFamily::SD_DRAWINGPAGE_ID, sStyleName, aPropStates); + + if(sStyleName.isEmpty()) + { + // Style did not exist, add it to AutoStalePool + sStyleName = GetAutoStylePool()->Add(XmlStyleFamily::SD_DRAWINGPAGE_ID, sStyleName, std::move(aPropStates)); + } + } + } + + return sStyleName; +} + +void SdXMLExport::ImpPrepMasterPageInfos() +{ + // create draw:style-name entries for master page export + // containing only background attributes + // fixed family for page-styles is "drawing-page" (XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME) + + sal_Int32 nCnt; + for( nCnt = 0; nCnt < mnDocMasterPageCount; nCnt++) + { + Reference xDrawPage; + mxDocMasterPages->getByIndex(nCnt) >>= xDrawPage; + maMasterPagesStyleNames[nCnt] = ImpCreatePresPageStyleName( xDrawPage ); + } + + if( !IsImpress() ) + return; + + Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetModel(), UNO_QUERY ); + if( xHandoutSupp.is() ) + { + Reference< XDrawPage > xHandoutPage( xHandoutSupp->getHandoutMasterPage() ); + if( xHandoutPage.is() ) + { + maHandoutPageHeaderFooterSettings = ImpPrepDrawPageHeaderFooterDecls( xHandoutPage ); + maHandoutMasterStyleName = ImpCreatePresPageStyleName( xHandoutPage, false ); + } + } +} + +void SdXMLExport::ImpWritePresentationStyles() +{ + if(!IsImpress()) + return; + + for (sal_Int32 nCnt = 0; nCnt < mnDocMasterPageCount; nCnt++) + { + Any aAny(mxDocMasterPages->getByIndex(nCnt)); + Reference xNamed; + + if(aAny >>= xNamed) + { + // write presentation styles (ONLY if presentation) + if(IsImpress() && mxDocStyleFamilies.is() && xNamed.is()) + { + rtl::Reference aStEx(new XMLStyleExport(*this, GetAutoStylePool().get())); + const rtl::Reference< SvXMLExportPropertyMapper > aMapperRef( GetPropertySetMapper() ); + + OUString aPrefix( xNamed->getName() + "-" ); + + aStEx->exportStyleFamily(xNamed->getName(), + OUString(XML_STYLE_FAMILY_SD_PRESENTATION_NAME), + aMapperRef, false, + XmlStyleFamily::SD_PRESENTATION_ID, &aPrefix); + } + } + } +} + +void SdXMLExport::ExportMeta_() +{ + uno::Sequence stats { { "ObjectCount", uno::Any(mnObjectCount) } }; + + // update document statistics at the model + uno::Reference xPropSup(GetModel(), + uno::UNO_QUERY_THROW); + uno::Reference xDocProps( + xPropSup->getDocumentProperties()); + if (xDocProps.is()) { + xDocProps->setDocumentStatistics(stats); + } + + // call parent + SvXMLExport::ExportMeta_(); +} + +void SdXMLExport::ExportFontDecls_() +{ + GetFontAutoStylePool(); // make sure the pool is created + SvXMLExport::ExportFontDecls_(); +} + +void SdXMLExport::ExportContent_() +{ + // export , and elements + ImpWriteHeaderFooterDecls(); + + // page export + for(sal_Int32 nPageInd(0); nPageInd < mnDocDrawPageCount; nPageInd++) + { + uno::Reference xDrawPage( mxDocDrawPages->getByIndex(nPageInd), uno::UNO_QUERY ); + + // set progress view + if(GetStatusIndicator().is()) + GetStatusIndicator()->setValue(((nPageInd + 1) * 100) / mnDocDrawPageCount); + + if(xDrawPage.is()) + { + // prepare page attributes, name of page + Reference < container::XNamed > xNamed(xDrawPage, UNO_QUERY); + if(xNamed.is()) + AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, xNamed->getName()); + + // draw:style-name (presentation page attributes AND background attributes) + if( !maDrawPagesStyleNames[nPageInd].isEmpty() ) + AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, + maDrawPagesStyleNames[nPageInd]); + + // draw:master-page-name + Reference < drawing::XMasterPageTarget > xMasterPageInt(xDrawPage, UNO_QUERY); + if(xMasterPageInt.is()) + { + Reference xUsedMasterPage(xMasterPageInt->getMasterPage()); + if(xUsedMasterPage.is()) + { + Reference < container::XNamed > xMasterNamed(xUsedMasterPage, UNO_QUERY); + if(xMasterNamed.is()) + { + AddAttribute(XML_NAMESPACE_DRAW, XML_MASTER_PAGE_NAME, + EncodeStyleName( xMasterNamed->getName()) ); + } + } + } + + // presentation:page-layout-name + if( IsImpress() && !maDrawPagesAutoLayoutNames[nPageInd+1].isEmpty()) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PRESENTATION_PAGE_LAYOUT_NAME, maDrawPagesAutoLayoutNames[nPageInd+1] ); + } + + Reference< beans::XPropertySet > xProps( xDrawPage, UNO_QUERY ); + if( xProps.is() ) + { + try + { + OUString aBookmarkURL; + xProps->getPropertyValue("BookmarkURL") >>= aBookmarkURL; + + if( !aBookmarkURL.isEmpty() ) + { + sal_Int32 nIndex = aBookmarkURL.lastIndexOf( '#' ); + if( nIndex != -1 ) + { + OUString aFileName( aBookmarkURL.copy( 0, nIndex ) ); + std::u16string_view aBookmarkName( aBookmarkURL.subView( nIndex+1 ) ); + + aBookmarkURL = GetRelativeReference( aFileName ) + "#" + aBookmarkName; + } + + AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, aBookmarkURL); + AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_REPLACE ); + AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + } + } + catch(const Exception&) + { + OSL_FAIL(" no \"BookmarkURL\" property at page?" ); + } + } + + if( IsImpress() ) + ImplExportHeaderFooterDeclAttributes( maDrawPagesHeaderFooterSettings[nPageInd] ); + + OUString sNavigationOrder( getNavigationOrder( xDrawPage ) ); + if( !sNavigationOrder.isEmpty() ) + AddAttribute ( XML_NAMESPACE_DRAW, XML_NAV_ORDER, sNavigationOrder ); + + rtl::Reference< xmloff::AnimationsExporter > xAnimationsExporter; + uno::Reference< css::animations::XAnimationNodeSupplier > xAnimNodeSupplier; + + // prepare animation export + if(IsImpress()) + { + if( getExportFlags() & SvXMLExportFlags::OASIS ) + { + // export new animations for oasis format + xAnimNodeSupplier.set( xDrawPage, UNO_QUERY ); + + // prepare animations exporter if impress + if(xAnimNodeSupplier.is()) + { + xAnimationsExporter = new xmloff::AnimationsExporter( *this, xProps ); + xAnimationsExporter->prepare( xAnimNodeSupplier->getAnimationNode() ); + } + } + else + { + // export old animations for ooo format + rtl::Reference< XMLAnimationsExporter > xAnimExport = new XMLAnimationsExporter(); + GetShapeExport()->setAnimationsExporter( xAnimExport ); + } + } + + // write draw:id + const OUString aPageId = getInterfaceToIdentifierMapper().getIdentifier( xDrawPage ); + if( !aPageId.isEmpty() ) + { + AddAttributeIdLegacy(XML_NAMESPACE_DRAW, aPageId); + } + + // write page + SvXMLElementExport aDPG(*this, XML_NAMESPACE_DRAW, XML_PAGE, true, true); + + // write optional office:forms + exportFormsElement( xDrawPage ); + + // write graphic objects on this page (if any) + if(xDrawPage.is() && xDrawPage->getCount()) + GetShapeExport()->exportShapes( xDrawPage ); + + // write animations and presentation notes (ONLY if presentation) + if(IsImpress()) + { + if(xAnimNodeSupplier.is()) + { + xAnimationsExporter->exportAnimations( xAnimNodeSupplier->getAnimationNode() ); + } + else + { + // animations + rtl::Reference< XMLAnimationsExporter > xAnimExport( GetShapeExport()->getAnimationsExporter() ); + if( xAnimExport.is() ) + xAnimExport->exportAnimations( *this ); + + xAnimExport = nullptr; + GetShapeExport()->setAnimationsExporter( xAnimExport ); + } + + // presentations + Reference< presentation::XPresentationPage > xPresPage(xDrawPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + if( !maDrawNotesPagesStyleNames[nPageInd].isEmpty() ) + AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, maDrawNotesPagesStyleNames[nPageInd]); + + ImplExportHeaderFooterDeclAttributes( maDrawNotesPagesHeaderFooterSettings[nPageInd] ); + + // write presentation notes + SvXMLElementExport aPSY(*this, XML_NAMESPACE_PRESENTATION, XML_NOTES, true, true); + + // write optional office:forms + exportFormsElement( xNotesPage ); + + // write shapes per se + GetShapeExport()->exportShapes( xNotesPage ); + } + } + } + + exportAnnotations( xDrawPage ); + } + } + + if( IsImpress() ) + exportPresentationSettings(); +} + +void SdXMLExport::exportPresentationSettings() +{ + try + { + Reference< XPresentationSupplier > xPresSupplier( GetModel(), UNO_QUERY ); + if( !xPresSupplier.is() ) + return; + + Reference< XPropertySet > xPresProps( xPresSupplier->getPresentation(), UNO_QUERY ); + if( !xPresProps.is() ) + return; + + bool bHasAttr = false; + + bool bTemp = false; + + // export range + xPresProps->getPropertyValue("IsShowAll") >>= bTemp; + if( !bTemp ) + { + OUString aFirstPage; + xPresProps->getPropertyValue("FirstPage") >>= aFirstPage; + if( !aFirstPage.isEmpty() ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_START_PAGE, aFirstPage ); + bHasAttr = true; + } + else + { + OUString aCustomShow; + xPresProps->getPropertyValue("CustomShow") >>= aCustomShow; + if( !aCustomShow.isEmpty() ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_SHOW, aCustomShow ); + bHasAttr = true; + } + } + } + + xPresProps->getPropertyValue("IsEndless") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_ENDLESS, XML_TRUE ); + bHasAttr = true; + + sal_Int32 nPause = 0; + xPresProps->getPropertyValue("Pause") >>= nPause; + + util::Duration aDuration; + aDuration.Seconds = static_cast(nPause); + + OUStringBuffer aOut; + ::sax::Converter::convertDuration(aOut, aDuration); + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PAUSE, aOut.makeStringAndClear() ); + } + + xPresProps->getPropertyValue("AllowAnimations") >>= bTemp; + if( !bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_ANIMATIONS, XML_DISABLED ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsAlwaysOnTop") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_STAY_ON_TOP, XML_TRUE ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsAutomatic") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_FORCE_MANUAL, XML_TRUE ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsFullScreen") >>= bTemp; + if( !bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_FULL_SCREEN, XML_FALSE ); + bHasAttr = true; + } + + // We need to always export this attribute, because the import had the wrong default (tdf#108824) + xPresProps->getPropertyValue("IsMouseVisible") >>= bTemp; + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_MOUSE_VISIBLE, bTemp ? XML_TRUE : XML_FALSE); + bHasAttr = true; + + xPresProps->getPropertyValue("StartWithNavigator") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_START_WITH_NAVIGATOR, XML_TRUE ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("UsePen") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_MOUSE_AS_PEN, XML_TRUE ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsTransitionOnClick") >>= bTemp; + if( !bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_TRANSITION_ON_CLICK, XML_DISABLED ); + bHasAttr = true; + } + + xPresProps->getPropertyValue("IsShowLogo") >>= bTemp; + if( bTemp ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_SHOW_LOGO, XML_TRUE ); + bHasAttr = true; + } + + Reference< container::XNameContainer > xShows; + Sequence< OUString > aShowNames; + bool bHasNames = false; + + Reference< XCustomPresentationSupplier > xSup( GetModel(), UNO_QUERY ); + if( xSup.is() ) + { + xShows = xSup->getCustomPresentations(); + if( xShows.is() ) + { + aShowNames = xShows->getElementNames(); + bHasNames = aShowNames.hasElements(); + } + } + + if( bHasAttr || bHasNames ) + { + SvXMLElementExport aSettings(*this, XML_NAMESPACE_PRESENTATION, XML_SETTINGS, true, true); + + if( !bHasNames ) + return; + + Reference< XIndexContainer > xShow; + Reference< XNamed > xPageName; + + OUStringBuffer sTmp; + + for( const auto& rShowName : std::as_const(aShowNames) ) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_NAME, rShowName ); + + xShows->getByName( rShowName ) >>= xShow; + SAL_WARN_IF( !xShow.is(), "xmloff", "invalid custom show!" ); + if( !xShow.is() ) + continue; + + const sal_Int32 nPageCount = xShow->getCount(); + for( sal_Int32 nPage = 0; nPage < nPageCount; nPage++ ) + { + xShow->getByIndex( nPage ) >>= xPageName; + + if( !xPageName.is() ) + continue; + + if( !sTmp.isEmpty() ) + sTmp.append( ',' ); + sTmp.append( xPageName->getName() ); + + } + + if( !sTmp.isEmpty() ) + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PAGES, sTmp.makeStringAndClear() ); + + SvXMLElementExport aShows(*this, XML_NAMESPACE_PRESENTATION, XML_SHOW, true, true); + } + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", "while exporting "); + } +} + +void SdXMLExport::ExportStyles_(bool bUsed) +{ + GetPropertySetMapper()->SetAutoStyles( false ); + + // export fill styles + SvXMLExport::ExportStyles_( bUsed ); + + // write draw:style-name for object graphic-styles + GetShapeExport()->ExportGraphicDefaults(); + + // do not export in ODF 1.1 or older + if (getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + GetShapeExport()->GetShapeTableExport()->exportTableStyles(); + + // write presentation styles + ImpWritePresentationStyles(); + + // prepare draw:auto-layout-name for page export + ImpPrepAutoLayoutInfos(); + + // write draw:auto-layout-name for page export + ImpWriteAutoLayoutInfos(); + + Reference< beans::XPropertySet > xInfoSet( getExportInfo() ); + if( xInfoSet.is() ) + { + Reference< beans::XPropertySetInfo > xInfoSetInfo( xInfoSet->getPropertySetInfo() ); + + if( xInfoSetInfo->hasPropertyByName( gsPageLayoutNames ) ) + { + xInfoSet->setPropertyValue( gsPageLayoutNames, Any(maDrawPagesAutoLayoutNames) ); + } + } +} + +void SdXMLExport::collectAutoStyles() +{ + SvXMLExport::collectAutoStyles(); + if (mbAutoStylesCollected) + return; + + Reference< beans::XPropertySet > xInfoSet( getExportInfo() ); + if( xInfoSet.is() ) + { + Reference< beans::XPropertySetInfo > xInfoSetInfo( xInfoSet->getPropertySetInfo() ); + + if( xInfoSetInfo->hasPropertyByName( gsPageLayoutNames ) ) + { + xInfoSet->getPropertyValue( gsPageLayoutNames ) >>= maDrawPagesAutoLayoutNames; + } + } + + GetPropertySetMapper()->SetAutoStyles( true ); + + if( getExportFlags() & SvXMLExportFlags::STYLES ) + { + // #80012# PageMaster export moved from _ExportStyles + // prepare page-master infos + ImpPrepPageMasterInfos(); + + // prepare draw:style-name for master page export + ImpPrepMasterPageInfos(); + } + + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + // prepare draw:style-name for page export + ImpPrepDrawPageInfos(); + } + + if( getExportFlags() & SvXMLExportFlags::STYLES ) + { + // create auto style infos for shapes on master handout page + if( IsImpress() ) + { + Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetModel(), UNO_QUERY ); + if( xHandoutSupp.is() ) + { + Reference< XDrawPage > xHandoutPage( xHandoutSupp->getHandoutMasterPage() ); + if( xHandoutPage.is() && xHandoutPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xHandoutPage ); + } + } + + // create auto style infos for objects on master pages + for(sal_Int32 nMPageId(0); nMPageId < mnDocMasterPageCount; nMPageId++) + { + Reference< XDrawPage > xMasterPage(mxDocMasterPages->getByIndex(nMPageId), UNO_QUERY ); + + if( xMasterPage.is() ) + { + // collect layer information + GetFormExport()->examineForms( xMasterPage ); + + // get MasterPage Name + OUString aMasterPageNamePrefix; + Reference < container::XNamed > xNamed(xMasterPage, UNO_QUERY); + if(xNamed.is()) + { + aMasterPageNamePrefix = xNamed->getName(); + } + if(!aMasterPageNamePrefix.isEmpty()) + { + aMasterPageNamePrefix += "-"; + } + GetShapeExport()->setPresentationStylePrefix( aMasterPageNamePrefix ); + + if(xMasterPage.is() && xMasterPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xMasterPage ); + + if(IsImpress()) + { + Reference< presentation::XPresentationPage > xPresPage(xMasterPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + // collect layer information + GetFormExport()->examineForms( xNotesPage ); + + if(xNotesPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xNotesPage ); + } + } + } + collectAnnotationAutoStyles(xMasterPage); + } + } + } + + if( getExportFlags() & SvXMLExportFlags::CONTENT ) + { + // prepare animations exporter if impress + if(IsImpress() && (!(getExportFlags() & SvXMLExportFlags::OASIS)) ) + { + rtl::Reference< XMLAnimationsExporter > xAnimExport = new XMLAnimationsExporter(); + GetShapeExport()->setAnimationsExporter( xAnimExport ); + } + + // create auto style infos for objects on pages + for(sal_Int32 nPageInd(0); nPageInd < mnDocDrawPageCount; nPageInd++) + { + Reference xDrawPage( mxDocDrawPages->getByIndex(nPageInd), UNO_QUERY ); + if( xDrawPage.is() ) + { + // collect layer information + GetFormExport()->examineForms( xDrawPage ); + + // get MasterPage Name + OUString aMasterPageNamePrefix; + Reference < drawing::XMasterPageTarget > xMasterPageInt(xDrawPage, UNO_QUERY); + if(xMasterPageInt.is()) + { + Reference xUsedMasterPage(xMasterPageInt->getMasterPage()); + if(xUsedMasterPage.is()) + { + Reference < container::XNamed > xMasterNamed(xUsedMasterPage, UNO_QUERY); + if(xMasterNamed.is()) + { + aMasterPageNamePrefix = xMasterNamed->getName(); + } + } + } + if(!aMasterPageNamePrefix.isEmpty()) + { + aMasterPageNamePrefix += "-"; + } + + GetShapeExport()->setPresentationStylePrefix( aMasterPageNamePrefix ); + + // prepare object infos + if(xDrawPage.is() && xDrawPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xDrawPage ); + + // prepare presentation notes page object infos (ONLY if presentation) + if(IsImpress()) + { + Reference< presentation::XPresentationPage > xPresPage(xDrawPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + // collect layer information + GetFormExport()->examineForms( xNotesPage ); + + if(xNotesPage->getCount()) + GetShapeExport()->collectShapesAutoStyles( xNotesPage ); + } + } + } + + collectAnnotationAutoStyles( xDrawPage ); + } + } + if (IsImpress()) + { + rtl::Reference< XMLAnimationsExporter > xAnimExport; + GetShapeExport()->setAnimationsExporter( xAnimExport ); + } + } + + mbAutoStylesCollected = true; +} + +void SdXMLExport::ExportAutoStyles_() +{ + collectAutoStyles(); + + if( getExportFlags() & SvXMLExportFlags::STYLES ) + { + // write page-master infos + ImpWritePageMasterInfos(); + } + + // export draw-page styles + GetAutoStylePool()->exportXML( XmlStyleFamily::SD_DRAWINGPAGE_ID ); + + exportAutoDataStyles(); + + GetShapeExport()->exportAutoStyles(); + + SvXMLExportFlags nContentAutostyles = SvXMLExportFlags::CONTENT | SvXMLExportFlags::AUTOSTYLES; + if ( ( getExportFlags() & nContentAutostyles ) == nContentAutostyles ) + GetFormExport()->exportAutoStyles( ); + + // ...for text + GetTextParagraphExport()->exportTextAutoStyles(); +} + +void SdXMLExport::ExportMasterStyles_() +{ + // export layer + SdXMLayerExporter::exportLayer( *this ); + + // export handout master page if impress + if( IsImpress() ) + { + Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetModel(), UNO_QUERY ); + if( xHandoutSupp.is() ) + { + Reference< XDrawPage > xHandoutPage( xHandoutSupp->getHandoutMasterPage() ); + if( xHandoutPage.is() ) + { + // presentation:page-layout-name + if( IsImpress() && !maDrawPagesAutoLayoutNames[0].isEmpty()) + { + AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PRESENTATION_PAGE_LAYOUT_NAME, EncodeStyleName( maDrawPagesAutoLayoutNames[0] )); + } + + ImpXMLEXPPageMasterInfo* pInfo = mpHandoutPageMaster; + if(pInfo) + { + const OUString& sString = pInfo->GetName(); + AddAttribute(XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_NAME, sString ); + } + + // draw:style-name + if( !maHandoutMasterStyleName.isEmpty() ) + AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, maHandoutMasterStyleName); + + ImplExportHeaderFooterDeclAttributes( maHandoutPageHeaderFooterSettings ); + + // write masterpage + SvXMLElementExport aMPG(*this, XML_NAMESPACE_STYLE, XML_HANDOUT_MASTER, true, true); + + // write graphic objects on this master page (if any) + if(xHandoutPage.is() && xHandoutPage->getCount()) + GetShapeExport()->exportShapes( xHandoutPage ); + } + } + } + + // export MasterPages in master-styles section + for (sal_Int32 nMPageId = 0; nMPageId < mnDocMasterPageCount; nMPageId++) + { + Reference< XDrawPage > xMasterPage( mxDocMasterPages->getByIndex(nMPageId), UNO_QUERY ); + if(xMasterPage.is()) + { + // prepare masterpage attributes + Reference < container::XNamed > xNamed(xMasterPage, UNO_QUERY); + if(xNamed.is()) + { + bool bEncoded = false; + OUString sMasterPageName = xNamed->getName(); + AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, + EncodeStyleName( sMasterPageName, &bEncoded )); + if( bEncoded ) + AddAttribute( + XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, + sMasterPageName ); + } + + ImpXMLEXPPageMasterInfo* pInfo = mvPageMasterUsageList.at( nMPageId ); + if(pInfo) + { + const OUString& sString = pInfo->GetName(); + AddAttribute(XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_NAME, sString ); + } + + // draw:style-name (background attributes) + if( !maMasterPagesStyleNames[nMPageId].isEmpty() ) + AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, + maMasterPagesStyleNames[nMPageId]); + + // write masterpage + SvXMLElementExport aMPG(*this, XML_NAMESPACE_STYLE, XML_MASTER_PAGE, true, true); + + // write optional office:forms + exportFormsElement( xMasterPage ); + + // write optional loext:theme + if (IsImpress()) + { + ExportThemeElement(xMasterPage); + } + + // write graphic objects on this master page (if any) + if(xMasterPage.is() && xMasterPage->getCount()) + GetShapeExport()->exportShapes( xMasterPage ); + + // write presentation notes (ONLY if presentation) + if(IsImpress()) + { + Reference< presentation::XPresentationPage > xPresPage(xMasterPage, UNO_QUERY); + if(xPresPage.is()) + { + Reference< XDrawPage > xNotesPage(xPresPage->getNotesPage()); + if(xNotesPage.is()) + { + ImpXMLEXPPageMasterInfo* pMasterInfo = mvNotesPageMasterUsageList.at( nMPageId ); + if(pMasterInfo) + { + const OUString& sString = pMasterInfo->GetName(); + AddAttribute(XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_NAME, sString); + } + + // write presentation notes + SvXMLElementExport aPSY(*this, XML_NAMESPACE_PRESENTATION, XML_NOTES, true, true); + + // write optional office:forms + exportFormsElement( xNotesPage ); + + // write shapes per se + GetShapeExport()->exportShapes( xNotesPage ); + } + } + } + exportAnnotations( xMasterPage ); + } + } +} + +void SdXMLExport::exportFormsElement( const Reference< XDrawPage >& xDrawPage ) +{ + if( !xDrawPage.is() ) + return; + + Reference< form::XFormsSupplier2 > xFormsSupplier( xDrawPage, UNO_QUERY ); + if ( xFormsSupplier.is() && xFormsSupplier->hasForms() ) + { + // write masterpage + ::xmloff::OOfficeFormsExport aForms(*this); + GetFormExport()->exportForms( xDrawPage ); + } + + if(! GetFormExport()->seekPage( xDrawPage ) ) + { + OSL_FAIL( "OFormLayerXMLExport::seekPage failed!" ); + } +} + +void SdXMLExport::ExportThemeElement(const uno::Reference& xDrawPage) +{ + uno::Reference xPropertySet(xDrawPage, uno::UNO_QUERY); + if (!xPropertySet.is()) + return; + + comphelper::SequenceAsHashMap aMap(xPropertySet->getPropertyValue("Theme")); + if (aMap.empty()) + { + return; + } + + if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + { + // Do not export in standard ODF 1.3 or older. + return; + } + + auto it = aMap.find("Name"); + if (it != aMap.end()) + { + OUString aName; + it->second >>= aName; + AddAttribute(XML_NAMESPACE_LO_EXT, XML_NAME, aName); + } + SvXMLElementExport aTheme(*this, XML_NAMESPACE_LO_EXT, XML_THEME, true, true); + + uno::Sequence aColors; + it = aMap.find("ColorScheme"); + if (it != aMap.end()) + { + it->second >>= aColors; + } + if (!aColors.hasElements()) + { + return; + } + + it = aMap.find("ColorSchemeName"); + if (it != aMap.end()) + { + OUString aName; + it->second >>= aName; + AddAttribute(XML_NAMESPACE_LO_EXT, XML_NAME, aName); + } + SvXMLElementExport aColorTable(*this, XML_NAMESPACE_LO_EXT, XML_COLOR_TABLE, true, true); + + static const XMLTokenEnum aColorTokens[] = { + XML_DK1, // Background 1 + XML_LT1, // Text 1 + XML_DK2, // Background 2 + XML_LT2, // Text 2 + XML_ACCENT1, + XML_ACCENT2, + XML_ACCENT3, + XML_ACCENT4, + XML_ACCENT5, + XML_ACCENT6, + XML_HLINK, // Hyperlink + XML_FOLHLINK, // Followed hyperlink + }; + for (size_t nColor = 0; nColor < aColors.size(); ++nColor) + { + // Import goes via svx::Theme::FromAny(), which sanitizes user input. + assert(nColor < SAL_N_ELEMENTS(aColorTokens)); + + AddAttribute(XML_NAMESPACE_LO_EXT, XML_NAME, GetXMLToken(aColorTokens[nColor])); + + OUStringBuffer sValue; + sax::Converter::convertColor(sValue, aColors[nColor]); + AddAttribute(XML_NAMESPACE_LO_EXT, XML_COLOR, sValue.makeStringAndClear()); + + SvXMLElementExport aColor(*this, XML_NAMESPACE_LO_EXT, XML_COLOR, true, true); + } +} + +void SdXMLExport::GetViewSettings(uno::Sequence& rProps) +{ + Reference< beans::XPropertySet > xPropSet( GetModel(), UNO_QUERY ); + if( !xPropSet.is() ) + return; + + awt::Rectangle aVisArea; + xPropSet->getPropertyValue("VisibleArea") >>= aVisArea; + + rProps.realloc(4); + beans::PropertyValue* pProps = rProps.getArray(); + + pProps[0].Name = "VisibleAreaTop"; + pProps[0].Value <<= aVisArea.Y; + pProps[1].Name = "VisibleAreaLeft"; + pProps[1].Value <<= aVisArea.X; + pProps[2].Name = "VisibleAreaWidth"; + pProps[2].Value <<= aVisArea.Width; + pProps[3].Name = "VisibleAreaHeight"; + pProps[3].Value <<= aVisArea.Height; + +} + +void SdXMLExport::GetConfigurationSettings(uno::Sequence& rProps) +{ + Reference< lang::XMultiServiceFactory > xFac( GetModel(), UNO_QUERY ); + if( !xFac.is() ) + return; + + Reference< beans::XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), UNO_QUERY ); + if( xProps.is() ) + SvXMLUnitConverter::convertPropertySet( rProps, xProps ); + DocumentSettingsSerializer *pFilter(dynamic_cast(xProps.get())); + if (!pFilter) + return; + const uno::Reference< embed::XStorage > xStorage(GetTargetStorage()); + if (!xStorage.is()) + return; + rProps = pFilter->filterStreamsToStorage(xStorage, rProps); +} + +void SdXMLExport::addDataStyle(const sal_Int32 nNumberFormat, bool bTimeFormat ) +{ + sal_Int32 nFormat = nNumberFormat; + if( (nNumberFormat > 1) && (nNumberFormat <= 0x0f) ) + nFormat -= 2; + + if( bTimeFormat ) + { + maUsedTimeStyles.insert( nFormat ); + } + else + { + maUsedDateStyles.insert( nFormat ); + } +} + +void SdXMLExport::exportDataStyles() +{ + // there are no data styles to export in draw/impress yet +} + +void SdXMLExport::exportAutoDataStyles() +{ + for( const auto& rUsedDateStyle : maUsedDateStyles ) + SdXMLNumberStylesExporter::exportDateStyle( *this, rUsedDateStyle ); + + for( const auto& rUsedTimeStyle : maUsedTimeStyles ) + SdXMLNumberStylesExporter::exportTimeStyle( *this, rUsedTimeStyle ); + + if(HasFormExport()) + GetFormExport()->exportAutoControlNumberStyles(); +} + +OUString SdXMLExport::getDataStyleName(const sal_Int32 nNumberFormat, bool bTimeFormat ) const +{ + if( bTimeFormat ) + { + return SdXMLNumberStylesExporter::getTimeStyleName( nNumberFormat ); + } + else + { + return SdXMLNumberStylesExporter::getDateStyleName( nNumberFormat ); + } +} + +OUString SdXMLExport::getNavigationOrder( const Reference< XDrawPage >& xDrawPage ) +{ + OUStringBuffer sNavOrder; + try + { + Reference< XPropertySet > xSet( xDrawPage, UNO_QUERY_THROW ); + Reference< XIndexAccess > xNavOrder( xSet->getPropertyValue("NavigationOrder"), UNO_QUERY_THROW ); + + Reference< XIndexAccess > xZOrderAccess = xDrawPage; + + // only export navigation order if it is different from the z-order + if( (xNavOrder.get() != xZOrderAccess.get()) && (xNavOrder->getCount() == xDrawPage->getCount()) ) + { + sal_Int32 nIndex; + const sal_Int32 nCount = xNavOrder->getCount(); + for( nIndex = 0; nIndex < nCount; ++nIndex ) + { + OUString sId( getInterfaceToIdentifierMapper().registerReference( Reference< XInterface >( xNavOrder->getByIndex( nIndex ), UNO_QUERY ) ) ); + if( !sId.isEmpty() ) + { + if( !sNavOrder.isEmpty() ) + sNavOrder.append( ' ' ); + sNavOrder.append( sId ); + } + } + } + } + catch(const Exception&) + { + } + return sNavOrder.makeStringAndClear(); +} + +void SdXMLExport::collectAnnotationAutoStyles( const Reference& xDrawPage ) +{ + Reference< XAnnotationAccess > xAnnotationAccess( xDrawPage, UNO_QUERY ); + if( !xAnnotationAccess.is() ) return; + + try + { + Reference< XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() ); + if( xAnnotationEnumeration.is() ) + { + while( xAnnotationEnumeration->hasMoreElements() ) + { + Reference< XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement(), UNO_SET_THROW ); + Reference< XText > xText( xAnnotation->getTextRange() ); + if(xText.is() && !xText->getString().isEmpty()) + GetTextParagraphExport()->collectTextAutoStyles( xText ); + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "exception caught during export of annotation auto styles"); + } +} + +void SdXMLExport::exportAnnotations( const Reference& xDrawPage ) +{ + // do not export in standard ODF 1.3 or older + if ((getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + { + return; + } + + Reference< XAnnotationAccess > xAnnotationAccess( xDrawPage, UNO_QUERY ); + if( !xAnnotationAccess.is() ) + return; + + try + { + Reference< XAnnotationEnumeration > xAnnotationEnumeration( xAnnotationAccess->createAnnotationEnumeration() ); + if( xAnnotationEnumeration.is() && xAnnotationEnumeration->hasMoreElements() ) + { + bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ); + + OUStringBuffer sStringBuffer; + do + { + Reference< XAnnotation > xAnnotation( xAnnotationEnumeration->nextElement(), UNO_SET_THROW ); + + RealPoint2D aPosition( xAnnotation->getPosition() ); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + static_cast( aPosition.X * 100 ) ); + AddAttribute(XML_NAMESPACE_SVG, XML_X, sStringBuffer.makeStringAndClear()); + + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + static_cast( aPosition.Y * 100 ) ); + AddAttribute(XML_NAMESPACE_SVG, XML_Y, sStringBuffer.makeStringAndClear()); + + RealSize2D aSize( xAnnotation->getSize() ); + + if( aSize.Width || aSize.Height ) + { + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + static_cast( aSize.Width * 100 ) ); + AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, sStringBuffer.makeStringAndClear()); + GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + static_cast( aSize.Height * 100 ) ); + AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, sStringBuffer.makeStringAndClear()); + } + + // annotation element + content + SvXMLElementExport aElem(*this, XML_NAMESPACE_OFFICE_EXT, XML_ANNOTATION, false, true); + + // author + OUString aAuthor( xAnnotation->getAuthor() ); + if( !aAuthor.isEmpty() ) + { + SvXMLElementExport aCreatorElem( *this, XML_NAMESPACE_DC, XML_CREATOR, true, false ); + Characters( bRemovePersonalInfo + ? "Author" + OUString::number( SvXMLExport::GetInfoID(aAuthor) ) + : aAuthor ); + } + + // initials + OUString aInitials( xAnnotation->getInitials() ); + if( !aInitials.isEmpty() ) + { + // OFFICE-3776 export meta:creator-initials for ODF 1.3 + SvXMLElementExport aInitialsElem( *this, + (SvtSaveOptions::ODFSVER_013 <= getSaneDefaultVersion()) + ? XML_NAMESPACE_META + : XML_NAMESPACE_LO_EXT, + (SvtSaveOptions::ODFSVER_013 <= getSaneDefaultVersion()) + ? XML_CREATOR_INITIALS + : XML_SENDER_INITIALS, + true, false ); + Characters( bRemovePersonalInfo + ? OUString::number( SvXMLExport::GetInfoID(aInitials) ) + : aInitials ); + } + + { + // date time + css::util::DateTime aDate( bRemovePersonalInfo + ? css::util::DateTime(0, 0, 0, 0, 1, 1, 1970, true) // Epoch time + : xAnnotation->getDateTime() ); + ::sax::Converter::convertDateTime(sStringBuffer, aDate, nullptr, true); + SvXMLElementExport aDateElem( *this, XML_NAMESPACE_DC, XML_DATE, true, false ); + Characters( sStringBuffer.makeStringAndClear() ); + } + + css::uno::Reference < css::text::XText > xText( xAnnotation->getTextRange() ); + if( xText.is() ) + GetTextParagraphExport()->exportText( xText ); + } + while( xAnnotationEnumeration->hasMoreElements() ); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", "exception caught during export of annotations"); + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLImpressExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::META | SvXMLExportFlags::STYLES + | SvXMLExportFlags::MASTERSTYLES | SvXMLExportFlags::AUTOSTYLES + | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS | SvXMLExportFlags::SETTINGS + | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisStylesExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLImpressStylesExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisContentExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLImpressContentExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::AUTOSTYLES + | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS + | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisMetaExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLImpressMetaExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisSettingsExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLImpressSettingsExportOasis", false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::SETTINGS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLImpressExportOOO", false, + SvXMLExportFlags::META | SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS + | SvXMLExportFlags::SETTINGS | SvXMLExportFlags::FONTDECLS + | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLDrawExportOOO", true, + SvXMLExportFlags::META | SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS + | SvXMLExportFlags::SETTINGS | SvXMLExportFlags::FONTDECLS + | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisSettingsExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLDrawSettingsExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::SETTINGS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisMetaExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLDrawMetaExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisContentExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport(pCtx, "XMLDrawContentExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::AUTOSTYLES + | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS + | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisStylesExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLDrawStylesExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::STYLES | SvXMLExportFlags::MASTERSTYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisExporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLExport( + pCtx, "XMLDrawExportOasis", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::META | SvXMLExportFlags::STYLES + | SvXMLExportFlags::MASTERSTYLES | SvXMLExportFlags::AUTOSTYLES + | SvXMLExportFlags::CONTENT | SvXMLExportFlags::SCRIPTS | SvXMLExportFlags::SETTINGS + | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_DrawingLayer_XMLExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLExport(pCtx, "XMLDrawingLayerExport", true, + SvXMLExportFlags::OASIS | SvXMLExportFlags::STYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT + | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::EMBEDDED)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLClipboardExporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLExport(pCtx, "XMLImpressClipboardExport", /*bIsDraw=*/false, + SvXMLExportFlags::OASIS | SvXMLExportFlags::STYLES + | SvXMLExportFlags::AUTOSTYLES | SvXMLExportFlags::CONTENT + | SvXMLExportFlags::FONTDECLS | SvXMLExportFlags::EMBEDDED)); +} + +XMLFontAutoStylePool* SdXMLExport::CreateFontAutoStylePool() +{ + bool bEmbedFonts = false; + bool bEmbedUsedOnly = false; + bool bEmbedLatinScript = true; + bool bEmbedAsianScript = true; + bool bEmbedComplexScript = true; + + if (getExportFlags() & SvXMLExportFlags::CONTENT) + { + try + { + Reference xFactory(GetModel(), UNO_QUERY); + Reference xProps; + Reference xInfo; + + if (xFactory.is()) + xProps.set(xFactory->createInstance("com.sun.star.document.Settings"), UNO_QUERY); + if (xProps.is()) + xInfo = xProps->getPropertySetInfo(); + if (xInfo.is() && xProps.is()) + { + if (xInfo->hasPropertyByName("EmbedFonts")) + xProps->getPropertyValue("EmbedFonts") >>= bEmbedFonts; + if (xInfo->hasPropertyByName("EmbedOnlyUsedFonts")) + xProps->getPropertyValue("EmbedOnlyUsedFonts") >>= bEmbedUsedOnly; + if (xInfo->hasPropertyByName("EmbedLatinScriptFonts")) + xProps->getPropertyValue("EmbedLatinScriptFonts") >>= bEmbedLatinScript; + if (xInfo->hasPropertyByName("EmbedAsianScriptFonts")) + xProps->getPropertyValue("EmbedAsianScriptFonts") >>= bEmbedAsianScript; + if (xInfo->hasPropertyByName("EmbedComplexScriptFonts")) + xProps->getPropertyValue("EmbedComplexScriptFonts") >>= bEmbedComplexScript; + } + } catch(...) + { + // clipboard document doesn't have shell so throws from getPropertyValue + // gallery elements may not support com.sun.star.document.Settings so throws from createInstance + } + } + + XMLFontAutoStylePool *pPool = new XMLFontAutoStylePool( *this, bEmbedFonts ); + pPool->setEmbedOnlyUsedFonts(bEmbedUsedOnly); + pPool->setEmbedFontScripts(bEmbedLatinScript, bEmbedAsianScript, bEmbedComplexScript); + + Reference< beans::XPropertySet > xProps( GetModel(), UNO_QUERY ); + if ( xProps.is() ) { + Sequence aAnySeq; + if( xProps->getPropertyValue("Fonts") >>= aAnySeq ) + { + if( aAnySeq.getLength() % 5 == 0 ) + { + int nLen = aAnySeq.getLength() / 5; + int nSeqIndex = 0; + for( int i = 0; i < nLen; i++ ) + { + OUString sFamilyName, sStyleName; + sal_Int16 eFamily(FAMILY_DONTKNOW), + ePitch(PITCH_DONTKNOW), + eCharSet(RTL_TEXTENCODING_DONTKNOW); + + aAnySeq[nSeqIndex++] >>= sFamilyName; + aAnySeq[nSeqIndex++] >>= sStyleName; + aAnySeq[nSeqIndex++] >>= eFamily; + aAnySeq[nSeqIndex++] >>= ePitch; + aAnySeq[nSeqIndex++] >>= eCharSet; + + pPool->Add( sFamilyName, sStyleName, FontFamily( eFamily ), FontPitch( ePitch ), rtl_TextEncoding( eCharSet ) ); + } + } + } + } + + return pPool; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdxmlexp_impl.hxx b/xmloff/source/draw/sdxmlexp_impl.hxx new file mode 100644 index 000000000..9808c7381 --- /dev/null +++ b/xmloff/source/draw/sdxmlexp_impl.hxx @@ -0,0 +1,179 @@ +/* -*- 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 + +#include +#include + +#include +#include + +namespace tools { class Rectangle; } + +class ImpXMLEXPPageMasterInfo; +class ImpXMLAutoLayoutInfo; +class XMLSdPropHdlFactory; +class XMLShapeExportPropertyMapper; +class XMLPageExportPropertyMapper; + +typedef ::std::vector< ImpXMLEXPPageMasterInfo* > ImpXMLEXPPageMasterList; + +enum XmlPlaceholder +{ + XmlPlaceholderTitle, + XmlPlaceholderOutline, + XmlPlaceholderSubtitle, + XmlPlaceholderGraphic, + XmlPlaceholderObject, + XmlPlaceholderChart, + XmlPlaceholderTable, + XmlPlaceholderPage, + XmlPlaceholderNotes, + XmlPlaceholderHandout, + XmlPlaceholderVerticalTitle, + XmlPlaceholderVerticalOutline +}; + +typedef o3tl::sorted_vector SdXMLFormatMap; + +struct HeaderFooterPageSettingsImpl +{ + OUString maStrHeaderDeclName; + OUString maStrFooterDeclName; + OUString maStrDateTimeDeclName; +}; + +struct DateTimeDeclImpl +{ + OUString maStrText; + bool mbFixed; + sal_Int32 mnFormat; +}; + +class SdXMLExport : public SvXMLExport +{ + css::uno::Reference< css::container::XNameAccess > mxDocStyleFamilies; + css::uno::Reference< css::container::XIndexAccess > mxDocMasterPages; + css::uno::Reference< css::container::XIndexAccess > mxDocDrawPages; + sal_Int32 mnDocMasterPageCount; + sal_Int32 mnDocDrawPageCount; + sal_uInt32 mnObjectCount; + + // temporary infos + std::vector< std::unique_ptr > mvPageMasterInfoList; + ImpXMLEXPPageMasterList mvPageMasterUsageList; + ImpXMLEXPPageMasterList mvNotesPageMasterUsageList; + ImpXMLEXPPageMasterInfo* mpHandoutPageMaster; + std::vector< std::unique_ptr > mvAutoLayoutInfoList; + + css::uno::Sequence< OUString > maDrawPagesAutoLayoutNames; + + ::std::vector< OUString > maDrawPagesStyleNames; + ::std::vector< OUString > maDrawNotesPagesStyleNames; + ::std::vector< OUString > maMasterPagesStyleNames; + OUString maHandoutMasterStyleName; + ::std::vector< HeaderFooterPageSettingsImpl > maDrawPagesHeaderFooterSettings; + ::std::vector< HeaderFooterPageSettingsImpl > maDrawNotesPagesHeaderFooterSettings; + + ::std::vector< OUString > maHeaderDeclsVector; + ::std::vector< OUString > maFooterDeclsVector; + ::std::vector< DateTimeDeclImpl > maDateTimeDeclsVector; + + HeaderFooterPageSettingsImpl maHandoutPageHeaderFooterSettings; + + rtl::Reference mpSdPropHdlFactory; + rtl::Reference mpPropertySetMapper; + rtl::Reference mpPresPagePropsMapper; + + SdXMLFormatMap maUsedDateStyles; // this is a vector with the used formattings for date fields + SdXMLFormatMap maUsedTimeStyles; // this is a vector with the used formattings for time fields + + bool mbIsDraw; + + virtual void ExportStyles_(bool bUsed) override; + virtual void ExportAutoStyles_() override; + virtual void ExportFontDecls_() override; + virtual void ExportMasterStyles_() override; + virtual void ExportContent_() override; + virtual void ExportMeta_() override; + + ImpXMLEXPPageMasterInfo* ImpGetOrCreatePageMasterInfo( const css::uno::Reference< css::drawing::XDrawPage >& xMasterPage ); + void ImpPrepPageMasterInfos(); + void ImpWritePageMasterInfos(); + void ImpPrepAutoLayoutInfos(); + HeaderFooterPageSettingsImpl ImpPrepDrawPageHeaderFooterDecls( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + ImpXMLEXPPageMasterInfo* ImpGetPageMasterInfoByName(std::u16string_view rName); + + void ImpPrepDrawPageInfos(); + void ImpPrepMasterPageInfos(); + void ImpWritePresentationStyles(); + OUString ImpCreatePresPageStyleName( const css::uno::Reference& xDrawPage, bool bExportBackground = true ); + + bool ImpPrepAutoLayoutInfo(const css::uno::Reference< css::drawing::XDrawPage >& xPage, OUString& rName); + void ImpWriteAutoLayoutInfos(); + void ImpWriteAutoLayoutPlaceholder(XmlPlaceholder ePl, const tools::Rectangle& rRect); + void ImpWriteHeaderFooterDecls(); + void ImplExportHeaderFooterDeclAttributes( const HeaderFooterPageSettingsImpl& aSettings ); + + void exportFormsElement( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + void ExportThemeElement(const css::uno::Reference& xDrawPage); + void exportPresentationSettings(); + + // #82003# helper function for recursive object count + sal_uInt32 ImpRecursiveObjectCount( const css::uno::Reference< css::drawing::XShapes >& xShapes); + + OUString getNavigationOrder( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + + void collectAnnotationAutoStyles( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + void exportAnnotations( const css::uno::Reference< css::drawing::XDrawPage >& xDrawPage ); + +protected: + virtual void GetViewSettings(css::uno::Sequence& aProps) override; + virtual void GetConfigurationSettings(css::uno::Sequence& aProps) override; + virtual XMLFontAutoStylePool* CreateFontAutoStylePool() override; + +public: + SdXMLExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + bool bIsDraw, SvXMLExportFlags nExportFlags ); + virtual ~SdXMLExport() override; + + void collectAutoStyles() override; + + // XExporter + virtual void SAL_CALL setSourceDocument( const css::uno::Reference< css::lang::XComponent >& xDoc ) override; + + // get factories and mappers + XMLShapeExportPropertyMapper* GetPropertySetMapper() const { return mpPropertySetMapper.get(); } + XMLPageExportPropertyMapper* GetPresPagePropsMapper() const { return mpPresPagePropsMapper.get(); } + + bool IsDraw() const { return mbIsDraw; } + bool IsImpress() const { return !mbIsDraw; } + + virtual void addDataStyle(const sal_Int32 nNumberFormat, bool bTimeFormat = false ) override; + virtual void exportDataStyles() override; + virtual void exportAutoDataStyles() override; + virtual OUString getDataStyleName(const sal_Int32 nNumberFormat, bool bTimeFormat = false ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdxmlimp.cxx b/xmloff/source/draw/sdxmlimp.cxx new file mode 100644 index 000000000..6ffc71405 --- /dev/null +++ b/xmloff/source/draw/sdxmlimp.cxx @@ -0,0 +1,663 @@ +/* -*- 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 +#include +#include +#include + +#include +#include "sdxmlimp_impl.hxx" +#include "ximpbody.hxx" + +#include +#include "ximpstyl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +namespace { + +class SdXMLBodyContext_Impl : public SvXMLImportContext +{ + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + +public: + + SdXMLBodyContext_Impl( SdXMLImport& rImport ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +} + +SdXMLBodyContext_Impl::SdXMLBodyContext_Impl( SdXMLImport& rImport ) : + SvXMLImportContext( rImport ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLBodyContext_Impl::createFastChildContext( + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList > & /*xAttrList*/ ) +{ + return new SdXMLBodyContext(GetSdImport()); +} + +namespace { + +// NB: virtually inherit so we can multiply inherit properly +// in SdXMLFlatDocContext_Impl +class SdXMLDocContext_Impl : public virtual SvXMLImportContext +{ +protected: + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + +public: + SdXMLDocContext_Impl( SdXMLImport& rImport ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +} + +SdXMLDocContext_Impl::SdXMLDocContext_Impl( + SdXMLImport& rImport ) +: SvXMLImportContext(rImport) +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SdXMLDocContext_Impl::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + switch (nElement) + { + case XML_ELEMENT(OFFICE, XML_SCRIPTS): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::SCRIPTS ) + { + // office:script inside office:document + return new XMLScriptContext( GetSdImport(), GetSdImport().GetModel() ); + } + break; + } + case XML_ELEMENT(OFFICE, XML_MASTER_STYLES): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::MASTERSTYLES ) + { + // office:master-styles inside office:document + return GetSdImport().CreateMasterStylesContext(); + } + break; + } + case XML_ELEMENT(OFFICE, XML_BODY): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::CONTENT ) + { + // office:body inside office:document + return new SdXMLBodyContext_Impl(GetSdImport()); + } + break; + } + case XML_ELEMENT(OFFICE, XML_SETTINGS): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::SETTINGS ) + { + return new XMLDocumentSettingsContext(GetImport()); + } + break; + } + case XML_ELEMENT(OFFICE, XML_STYLES): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::STYLES ) + { + // office:styles inside office:document + return GetSdImport().CreateStylesContext(); + } + break; + } + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES): + { + if( GetImport().getImportFlags() & SvXMLImportFlags::AUTOSTYLES ) + { + // office:automatic-styles inside office:document + return GetSdImport().CreateAutoStylesContext(); + } + break; + } + case XML_ELEMENT(OFFICE, XML_FONT_FACE_DECLS): + { + return GetSdImport().CreateFontDeclsContext(); + } + case XML_ELEMENT(OFFICE, XML_META): + { + SAL_INFO("xmloff.draw", "XML_ELEMENT(OFFICE, XML_META): should not have come here, maybe document is invalid?"); + break; + } + } + return nullptr; +} + +namespace { + +// context for flat file xml format +class SdXMLFlatDocContext_Impl + : public SdXMLDocContext_Impl, public SvXMLMetaDocumentContext +{ +public: + SdXMLFlatDocContext_Impl( SdXMLImport& i_rImport, + const uno::Reference& i_xDocProps ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +} + +SdXMLFlatDocContext_Impl::SdXMLFlatDocContext_Impl( SdXMLImport& i_rImport, + const uno::Reference& i_xDocProps) : + SvXMLImportContext(i_rImport), + SdXMLDocContext_Impl(i_rImport), + SvXMLMetaDocumentContext(i_rImport, i_xDocProps) +{ +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SdXMLFlatDocContext_Impl::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + // behave like meta base class iff we encounter office:meta + if ( nElement == XML_ELEMENT( OFFICE, XML_META ) ) { + return SvXMLMetaDocumentContext::createFastChildContext( + nElement, xAttrList ); + } else { + return SdXMLDocContext_Impl::createFastChildContext( + nElement, xAttrList ); + } +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLImpressImportOasis", false, SvXMLImportFlags::ALL)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisImporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLDrawImportOasis", true, SvXMLImportFlags::ALL)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisStylesImporter_get_implementation(uno::XComponentContext* pCtx, + uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLDrawStylesImportOasis", true, + SvXMLImportFlags::STYLES | SvXMLImportFlags::AUTOSTYLES + | SvXMLImportFlags::MASTERSTYLES)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisContentImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLDrawContentImportOasis", true, + SvXMLImportFlags::AUTOSTYLES | SvXMLImportFlags::CONTENT + | SvXMLImportFlags::SCRIPTS + | SvXMLImportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisMetaImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLDrawMetaImportOasis", true, SvXMLImportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Draw_XMLOasisSettingsImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLDrawSettingsImportOasis", true, SvXMLImportFlags::SETTINGS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisStylesImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLImpressStylesImportOasis", false, + SvXMLImportFlags::STYLES | SvXMLImportFlags::AUTOSTYLES + | SvXMLImportFlags::MASTERSTYLES)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisContentImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire(new SdXMLImport(pCtx, "XMLImpressContentImportOasis", false, + SvXMLImportFlags::AUTOSTYLES | SvXMLImportFlags::CONTENT + | SvXMLImportFlags::SCRIPTS + | SvXMLImportFlags::FONTDECLS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisMetaImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLImpressMetaImportOasis", false, SvXMLImportFlags::META)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Impress_XMLOasisSettingsImporter_get_implementation( + uno::XComponentContext* pCtx, uno::Sequence const& /*rSeq*/) +{ + return cppu::acquire( + new SdXMLImport(pCtx, "XMLImpressSettingsImportOasis", false, SvXMLImportFlags::SETTINGS)); +} + +SdXMLImport::SdXMLImport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + bool bIsDraw, SvXMLImportFlags nImportFlags ) +: SvXMLImport( xContext, implementationName, nImportFlags ), + mnNewPageCount(0), + mnNewMasterPageCount(0), + mbIsDraw(bIsDraw), + mbLoadDoc(true), + mbPreview(false) +{ + // add namespaces + GetNamespaceMap().Add( + GetXMLToken(XML_NP_PRESENTATION), + GetXMLToken(XML_N_PRESENTATION), + XML_NAMESPACE_PRESENTATION); + + GetNamespaceMap().Add( + GetXMLToken(XML_NP_SMIL), + GetXMLToken(XML_N_SMIL_COMPAT), + XML_NAMESPACE_SMIL); +} + +// XImporter +void SAL_CALL SdXMLImport::setTargetDocument( const uno::Reference< lang::XComponent >& xDoc ) +{ + SvXMLImport::setTargetDocument( xDoc ); + + uno::Reference< lang::XServiceInfo > xDocServices( GetModel(), uno::UNO_QUERY ); + if( !xDocServices.is() ) + throw lang::IllegalArgumentException(); + + mbIsDraw = !xDocServices->supportsService("com.sun.star.presentation.PresentationDocument"); + + // prepare access to styles + uno::Reference< style::XStyleFamiliesSupplier > xFamSup( GetModel(), uno::UNO_QUERY ); + if(xFamSup.is()) + mxDocStyleFamilies = xFamSup->getStyleFamilies(); + + // prepare access to master pages + uno::Reference < drawing::XMasterPagesSupplier > xMasterPagesSupplier(GetModel(), uno::UNO_QUERY); + if(xMasterPagesSupplier.is()) + mxDocMasterPages = xMasterPagesSupplier->getMasterPages(); + + // prepare access to draw pages + uno::Reference xDrawPagesSupplier(GetModel(), uno::UNO_QUERY); + if(!xDrawPagesSupplier.is()) + throw lang::IllegalArgumentException(); + + mxDocDrawPages = xDrawPagesSupplier->getDrawPages(); + if(!mxDocDrawPages.is()) + throw lang::IllegalArgumentException(); + + if( mxDocDrawPages.is() && mxDocDrawPages->getCount() > 0 ) + { + uno::Reference< form::XFormsSupplier > xFormsSupp; + mxDocDrawPages->getByIndex(0) >>= xFormsSupp; + mbIsFormsSupported = xFormsSupp.is(); + } + + // #88546# enable progress bar increments, SdXMLImport is only used for + // draw/impress import + GetShapeImport()->enableHandleProgressBar(); + + uno::Reference< lang::XMultiServiceFactory > xFac( GetModel(), uno::UNO_QUERY ); + if( xFac.is() ) + { + uno::Sequence< OUString > sSNS( xFac->getAvailableServiceNames() ); + if (comphelper::findValue(sSNS, "com.sun.star.drawing.TableShape") != -1) + mbIsTableShapeSupported = true; + } +} + +// XInitialization +void SAL_CALL SdXMLImport::initialize( const uno::Sequence< uno::Any >& aArguments ) +{ + SvXMLImport::initialize( aArguments ); + + uno::Reference< beans::XPropertySet > xInfoSet( getImportInfo() ); + if( !xInfoSet.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xInfoSetInfo( xInfoSet->getPropertySetInfo() ); + + if( xInfoSetInfo->hasPropertyByName( gsPageLayouts ) ) + xInfoSet->getPropertyValue( gsPageLayouts ) >>= mxPageLayouts; + + if( xInfoSetInfo->hasPropertyByName( gsPreview ) ) + xInfoSet->getPropertyValue( gsPreview ) >>= mbPreview; + + OUString const sOrganizerMode( + "OrganizerMode"); + if (xInfoSetInfo->hasPropertyByName(sOrganizerMode)) + { + bool bStyleOnly(false); + if (xInfoSet->getPropertyValue(sOrganizerMode) >>= bStyleOnly) + { + mbLoadDoc = !bStyleOnly; + } + } +} + +SvXMLImportContext *SdXMLImport::CreateFastContext( sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + + switch (nElement) + { + case XML_ELEMENT( OFFICE, XML_DOCUMENT_STYLES ): + case XML_ELEMENT( OFFICE, XML_DOCUMENT_CONTENT ): + case XML_ELEMENT( OFFICE, XML_DOCUMENT_SETTINGS ): + pContext = new SdXMLDocContext_Impl(*this); + break; + case XML_ELEMENT( OFFICE, XML_DOCUMENT_META ): + pContext = CreateMetaContext(nElement, xAttrList); + break; + case XML_ELEMENT( OFFICE, XML_DOCUMENT ): + { + uno::Reference xDPS( + GetModel(), uno::UNO_QUERY_THROW); + // flat OpenDocument file format + pContext = new SdXMLFlatDocContext_Impl( *this, xDPS->getDocumentProperties()); + } + break; + } + return pContext; +} + +SvXMLImportContext *SdXMLImport::CreateMetaContext(const sal_Int32 /*nElement*/, + const uno::Reference&) +{ + SvXMLImportContext* pContext = nullptr; + + if (getImportFlags() & SvXMLImportFlags::META) + { + uno::Reference xDPS( + GetModel(), uno::UNO_QUERY_THROW); + uno::Reference const xDocProps( + !mbLoadDoc ? nullptr : xDPS->getDocumentProperties()); + pContext = new SvXMLMetaDocumentContext(*this, xDocProps); + } + + return pContext; +} + +SvXMLStylesContext *SdXMLImport::CreateStylesContext() +{ + if(GetShapeImport()->GetStylesContext()) + return GetShapeImport()->GetStylesContext(); + + GetShapeImport()->SetStylesContext(new SdXMLStylesContext( + *this, false)); + + return GetShapeImport()->GetStylesContext(); +} + +SvXMLStylesContext *SdXMLImport::CreateAutoStylesContext() +{ + if(GetShapeImport()->GetAutoStylesContext()) + return GetShapeImport()->GetAutoStylesContext(); + + GetShapeImport()->SetAutoStylesContext(new SdXMLStylesContext( + *this, true)); + + return GetShapeImport()->GetAutoStylesContext(); +} + +SvXMLImportContext* SdXMLImport::CreateMasterStylesContext() +{ + if (!mxMasterStylesContext.is()) + mxMasterStylesContext.set(new SdXMLMasterStylesContext(*this)); + return mxMasterStylesContext.get(); +} + +SvXMLImportContext *SdXMLImport::CreateFontDeclsContext() +{ + XMLFontStylesContext *pFSContext = + new XMLFontStylesContext( *this, osl_getThreadTextEncoding() ); + SetFontDecls( pFSContext ); + return pFSContext; +} + +void SdXMLImport::SetViewSettings(const css::uno::Sequence& aViewProps) +{ + uno::Reference< beans::XPropertySet > xPropSet( GetModel(), uno::UNO_QUERY ); + if( !xPropSet.is() ) + return; + + awt::Rectangle aVisArea( 0,0, 28000, 21000 ); + + for( const auto& rViewProp : aViewProps ) + { + const OUString& rName = rViewProp.Name; + const uno::Any rValue = rViewProp.Value; + + if ( rName == "VisibleAreaTop" ) + { + rValue >>= aVisArea.Y; + } + else if ( rName == "VisibleAreaLeft" ) + { + rValue >>= aVisArea.X; + } + else if ( rName == "VisibleAreaWidth" ) + { + rValue >>= aVisArea.Width; + } + else if ( rName == "VisibleAreaHeight" ) + { + rValue >>= aVisArea.Height; + } + } + + try + { + xPropSet->setPropertyValue("VisibleArea", uno::Any( aVisArea ) ); + } + catch(const css::uno::Exception&) + { +/* #i79978# since old documents may contain invalid view settings, this is nothing to worry the user about. + SetError( XMLERROR_FLAG_WARNING | XMLERROR_API, {}, e.Message, NULL ); +*/ + } +} + +void SdXMLImport::SetConfigurationSettings(const css::uno::Sequence& aConfigProps) +{ + uno::Reference< lang::XMultiServiceFactory > xFac( GetModel(), uno::UNO_QUERY ); + if( !xFac.is() ) + return; + + uno::Reference< beans::XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY ); + if( !xProps.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xInfo( xProps->getPropertySetInfo() ); + if( !xInfo.is() ) + return; + + const uno::Sequence* pValues = &aConfigProps; + + DocumentSettingsSerializer *pFilter; + pFilter = dynamic_cast(xProps.get()); + uno::Sequence aFiltered; + if( pFilter ) + { + aFiltered = pFilter->filterStreamsFromStorage( GetDocumentBase(), GetSourceStorage(), aConfigProps ); + pValues = &aFiltered; + } + + for( const auto& rValue : *pValues ) + { + try + { + const OUString& rProperty = rValue.Name; + if( xInfo->hasPropertyByName( rProperty ) ) + xProps->setPropertyValue( rProperty, rValue.Value ); + } + catch(const uno::Exception&) + { + SAL_INFO("xmloff.draw", "#SdXMLImport::SetConfigurationSettings: Exception!" ); + } + } +} + +// #80365# override this method to read and use the hint value from the +// written meta information. If no info is found, guess 10 draw objects +//void SdXMLImport::SetStatisticAttributes(const uno::Reference& xAttrList) +void SdXMLImport::SetStatistics( + const uno::Sequence & i_rStats) +{ + static const char* s_stats[] = + { "ObjectCount", nullptr }; + + SvXMLImport::SetStatistics(i_rStats); + + sal_uInt32 nCount(10); + for (const auto& rStat : i_rStats) { + for (const char** pStat = s_stats; *pStat != nullptr; ++pStat) { + if (rStat.Name.equalsAscii(*pStat)) { + sal_Int32 val = 0; + if (rStat.Value >>= val) { + nCount = val; + } else { + SAL_WARN("xmloff.draw", "SdXMLImport::SetStatistics: invalid entry"); + } + } + } + } + + if(nCount) + { + GetProgressBarHelper()->SetReference(nCount); + GetProgressBarHelper()->SetValue(0); + } +} + +void SdXMLImport::AddHeaderDecl( const OUString& rName, const OUString& rText ) +{ + if( !rName.isEmpty() && !rText.isEmpty() ) + maHeaderDeclsMap[rName] = rText; +} + +void SdXMLImport::AddFooterDecl( const OUString& rName, const OUString& rText ) +{ + if( !rName.isEmpty() && !rText.isEmpty() ) + maFooterDeclsMap[rName] = rText; +} + +void SdXMLImport::AddDateTimeDecl( const OUString& rName, const OUString& rText, bool bFixed, const OUString& rDateTimeFormat ) +{ + if( !rName.isEmpty() && (!rText.isEmpty() || !bFixed) ) + { + DateTimeDeclContextImpl aDecl; + aDecl.maStrText = rText; + aDecl.mbFixed = bFixed; + aDecl.maStrDateTimeFormat = rDateTimeFormat; + maDateTimeDeclsMap[rName] = aDecl; + } +} + +OUString SdXMLImport::GetHeaderDecl( const OUString& rName ) const +{ + OUString aRet; + HeaderFooterDeclMap::const_iterator aIter( maHeaderDeclsMap.find( rName ) ); + if( aIter != maHeaderDeclsMap.end() ) + aRet = (*aIter).second; + + return aRet; +} + +OUString SdXMLImport::GetFooterDecl( const OUString& rName ) const +{ + OUString aRet; + HeaderFooterDeclMap::const_iterator aIter( maFooterDeclsMap.find( rName ) ); + if( aIter != maFooterDeclsMap.end() ) + aRet = (*aIter).second; + + return aRet; +} + +OUString SdXMLImport::GetDateTimeDecl( const OUString& rName, bool& rbFixed, OUString& rDateTimeFormat ) +{ + DateTimeDeclContextImpl aDecl; + + DateTimeDeclMap::const_iterator aIter( maDateTimeDeclsMap.find( rName ) ); + if( aIter != maDateTimeDeclsMap.end() ) + aDecl = (*aIter).second; + + rbFixed = aDecl.mbFixed; + rDateTimeFormat = aDecl.maStrDateTimeFormat; + return aDecl.maStrText; +} + +void SdXMLImport::NotifyContainsEmbeddedFont() +{ + uno::Reference< lang::XMultiServiceFactory > xFac( GetModel(), uno::UNO_QUERY ); + if( xFac.is() ) + { + uno::Reference< beans::XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY ); + if( xProps.is() ) + xProps->setPropertyValue("EmbedFonts", uno::Any( true ) ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdxmlimp_impl.hxx b/xmloff/source/draw/sdxmlimp_impl.hxx new file mode 100644 index 000000000..924f46a5e --- /dev/null +++ b/xmloff/source/draw/sdxmlimp_impl.hxx @@ -0,0 +1,135 @@ +/* -*- 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 +#include +#include +#include + +#include +#include +#include +#include + +class SvXMLUnitConverter; +class SvXMLTokenMap; +class SdXMLMasterStylesContext; + +struct DateTimeDeclContextImpl +{ + OUString maStrText; + bool mbFixed; + OUString maStrDateTimeFormat; + + DateTimeDeclContextImpl() : mbFixed(true) {} +}; + +typedef std::map HeaderFooterDeclMap; +typedef std::map DateTimeDeclMap; + +class SdXMLImport: public SvXMLImport +{ + css::uno::Reference< css::container::XNameAccess > mxDocStyleFamilies; + css::uno::Reference< css::container::XIndexAccess > mxDocMasterPages; + css::uno::Reference< css::container::XIndexAccess > mxDocDrawPages; + css::uno::Reference< css::container::XNameAccess > mxPageLayouts; + + // contexts for Style and AutoStyle import + rtl::Reference mxMasterStylesContext; + + sal_Int32 mnNewPageCount; + sal_Int32 mnNewMasterPageCount; + + bool mbIsDraw; + bool mbLoadDoc; + bool mbPreview; + + static constexpr OUStringLiteral gsPageLayouts = u"PageLayouts"; + static constexpr OUStringLiteral gsPreview = u"Preview"; + + HeaderFooterDeclMap maHeaderDeclsMap; + HeaderFooterDeclMap maFooterDeclsMap; + DateTimeDeclMap maDateTimeDeclsMap; + +protected: + + // This method is called after the namespace map has been updated, but + // before a context for the current element has been pushed. + virtual SvXMLImportContext *CreateFastContext( sal_Int32 nElement, + const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& xAttrList ) override; + +public: + SdXMLImport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, + bool bIsDraw, SvXMLImportFlags nImportFlags ); + + // XImporter + virtual void SAL_CALL setTargetDocument( const css::uno::Reference< css::lang::XComponent >& xDoc ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + virtual void SetViewSettings(const css::uno::Sequence& aViewProps) override; + virtual void SetConfigurationSettings(const css::uno::Sequence& aConfigProps) override; + + // namespace office + // NB: in contrast to other CreateFooContexts, this particular one handles + // the root element (i.e. office:document-meta) + SvXMLImportContext* CreateMetaContext(const sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + SvXMLStylesContext* CreateStylesContext(); + SvXMLStylesContext* CreateAutoStylesContext(); + SvXMLImportContext* CreateMasterStylesContext(); + SvXMLImportContext *CreateFontDeclsContext(); + + // export local parameters concerning page access and similar + const css::uno::Reference< css::container::XNameAccess >& GetLocalDocStyleFamilies() const { return mxDocStyleFamilies; } + const css::uno::Reference< css::container::XIndexAccess >& GetLocalMasterPages() const { return mxDocMasterPages; } + const css::uno::Reference< css::container::XIndexAccess >& GetLocalDrawPages() const { return mxDocDrawPages; } + + sal_Int32 GetNewPageCount() const { return mnNewPageCount; } + void IncrementNewPageCount() { mnNewPageCount++; } + sal_Int32 GetNewMasterPageCount() const { return mnNewMasterPageCount; } + void IncrementNewMasterPageCount() { mnNewMasterPageCount++; } + + const css::uno::Reference< css::container::XNameAccess >& getPageLayouts() const { return mxPageLayouts; } + + bool IsDraw() const { return mbIsDraw; } + bool IsImpress() const { return !mbIsDraw; } + + virtual void SetStatistics( + const css::uno::Sequence< css::beans::NamedValue> & i_rStats) override; + + bool IsPreview() const { return mbPreview; } + + void AddHeaderDecl( const OUString& rName, const OUString& rText ); + void AddFooterDecl( const OUString& rName, const OUString& rText ); + void AddDateTimeDecl( const OUString& rName, const OUString& rText, bool bFixed, const OUString& rDateTimeFormat ); + + OUString GetHeaderDecl( const OUString& rName ) const; + OUString GetFooterDecl( const OUString& rName ) const; + OUString GetDateTimeDecl( const OUString& rName, bool& rbFixed, OUString& rDateTimeFormat ); + + virtual void NotifyContainsEmbeddedFont() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/shapeexport.cxx b/xmloff/source/draw/shapeexport.cxx new file mode 100644 index 000000000..836721478 --- /dev/null +++ b/xmloff/source/draw/shapeexport.cxx @@ -0,0 +1,5196 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "sdpropls.hxx" +#include +#include "ximpshap.hxx" +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::EnhancedCustomShapeToken; +using namespace ::xmloff::token; + +constexpr OUStringLiteral XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE = u"vnd.sun.star.GraphicObject:"; + +namespace { + +bool supportsText(XmlShapeType eShapeType) +{ + return eShapeType != XmlShapeTypePresChartShape && + eShapeType != XmlShapeTypePresOLE2Shape && + eShapeType != XmlShapeTypeDrawSheetShape && + eShapeType != XmlShapeTypePresSheetShape && + eShapeType != XmlShapeTypeDraw3DSceneObject && + eShapeType != XmlShapeTypeDraw3DCubeObject && + eShapeType != XmlShapeTypeDraw3DSphereObject && + eShapeType != XmlShapeTypeDraw3DLatheObject && + eShapeType != XmlShapeTypeDraw3DExtrudeObject && + eShapeType != XmlShapeTypeDrawPageShape && + eShapeType != XmlShapeTypePresPageShape && + eShapeType != XmlShapeTypeDrawGroupShape; + +} + +} + +constexpr OUStringLiteral gsZIndex( u"ZOrder" ); +constexpr OUStringLiteral gsPrintable( u"Printable" ); +constexpr OUStringLiteral gsVisible( u"Visible" ); +constexpr OUStringLiteral gsModel( u"Model" ); +constexpr OUStringLiteral gsStartShape( u"StartShape" ); +constexpr OUStringLiteral gsEndShape( u"EndShape" ); +constexpr OUStringLiteral gsOnClick( u"OnClick" ); +constexpr OUStringLiteral gsEventType( u"EventType" ); +constexpr OUStringLiteral gsPresentation( u"Presentation" ); +constexpr OUStringLiteral gsMacroName( u"MacroName" ); +constexpr OUStringLiteral gsScript( u"Script" ); +constexpr OUStringLiteral gsLibrary( u"Library" ); +constexpr OUStringLiteral gsClickAction( u"ClickAction" ); +constexpr OUStringLiteral gsBookmark( u"Bookmark" ); +constexpr OUStringLiteral gsEffect( u"Effect" ); +constexpr OUStringLiteral gsPlayFull( u"PlayFull" ); +constexpr OUStringLiteral gsVerb( u"Verb" ); +constexpr OUStringLiteral gsSoundURL( u"SoundURL" ); +constexpr OUStringLiteral gsSpeed( u"Speed" ); +constexpr OUStringLiteral gsStarBasic( u"StarBasic" ); +constexpr OUStringLiteral gsHyperlink( u"Hyperlink" ); + +XMLShapeExport::XMLShapeExport(SvXMLExport& rExp, + SvXMLExportPropertyMapper *pExtMapper ) +: mrExport( rExp ), + maCurrentShapesIter(maShapesInfos.end()), + mbExportLayer( false ), + // #88546# init to sal_False + mbHandleProgressBar( false ) +{ + // construct PropertySetMapper + mxPropertySetMapper = CreateShapePropMapper( mrExport ); + if( pExtMapper ) + { + rtl::Reference < SvXMLExportPropertyMapper > xExtMapper( pExtMapper ); + mxPropertySetMapper->ChainExportMapper( xExtMapper ); + } + +/* + // chain text attributes + xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp)); +*/ + + mrExport.GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_GRAPHICS_ID, + XML_STYLE_FAMILY_SD_GRAPHICS_NAME, + GetPropertySetMapper(), + XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX); + mrExport.GetAutoStylePool()->AddFamily( + XmlStyleFamily::SD_PRESENTATION_ID, + XML_STYLE_FAMILY_SD_PRESENTATION_NAME, + GetPropertySetMapper(), + XML_STYLE_FAMILY_SD_PRESENTATION_PREFIX); + + // create table export helper and let him add his families in time + GetShapeTableExport(); +} + +XMLShapeExport::~XMLShapeExport() +{ +} + +// sj: replacing CustomShapes with standard objects that are also supported in OpenOffice.org format +uno::Reference< drawing::XShape > XMLShapeExport::checkForCustomShapeReplacement( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< drawing::XShape > xCustomShapeReplacement; + + if( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) ) + { + OUString aType( xShape->getShapeType() ); + if( aType == "com.sun.star.drawing.CustomShape" ) + { + uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY ); + if( xSet.is() ) + { + OUString aEngine; + xSet->getPropertyValue("CustomShapeEngine") >>= aEngine; + if ( aEngine.isEmpty() ) + { + aEngine = "com.sun.star.drawing.EnhancedCustomShapeEngine"; + } + uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + + if ( !aEngine.isEmpty() ) + { + uno::Sequence< beans::PropertyValue > aPropValues{ + comphelper::makePropertyValue("CustomShape", xShape), + comphelper::makePropertyValue("ForceGroupWithText", true) + }; + uno::Sequence< uno::Any > aArgument = { uno::Any(aPropValues) }; + uno::Reference< uno::XInterface > xInterface( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine, aArgument, xContext) ); + if ( xInterface.is() ) + { + uno::Reference< drawing::XCustomShapeEngine > xCustomShapeEngine( + uno::Reference< drawing::XCustomShapeEngine >( xInterface, uno::UNO_QUERY ) ); + if ( xCustomShapeEngine.is() ) + xCustomShapeReplacement = xCustomShapeEngine->render(); + } + } + } + } + } + return xCustomShapeReplacement; +} + +// This method collects all automatic styles for the given XShape +void XMLShapeExport::collectShapeAutoStyles(const uno::Reference< drawing::XShape >& xShape ) +{ + if( maCurrentShapesIter == maShapesInfos.end() ) + { + OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no call to seekShapes()!" ); + return; + } + sal_Int32 nZIndex = 0; + uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if( xPropSet.is() ) + xPropSet->getPropertyValue(gsZIndex) >>= nZIndex; + + ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second; + + if( static_cast(aShapeInfoVector.size()) <= nZIndex ) + { + OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no shape info allocated for a given shape" ); + return; + } + + ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex]; + + uno::Reference< drawing::XShape > xCustomShapeReplacement = checkForCustomShapeReplacement( xShape ); + if ( xCustomShapeReplacement.is() ) + aShapeInfo.xCustomShapeReplacement = xCustomShapeReplacement; + + // first compute the shapes type + ImpCalcShapeType(xShape, aShapeInfo.meShapeType); + + // #i118485# enabled XmlShapeTypeDrawChartShape and XmlShapeTypeDrawOLE2Shape + // to have text + const bool bObjSupportsText = + supportsText(aShapeInfo.meShapeType); + + const bool bObjSupportsStyle = + aShapeInfo.meShapeType != XmlShapeTypeDrawGroupShape; + + bool bIsEmptyPresObj = false; + + if ( aShapeInfo.xCustomShapeReplacement.is() ) + xPropSet.clear(); + + // prep text styles + if( xPropSet.is() && bObjSupportsText ) + { + uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY); + if (xText.is()) + { + try + { + // tdf#153161: it seems that the call to XTextRange::getString flushes the changes + // for some objects, that otherwise fail to get exported correctly. Maybe at some + // point it would make sense to find a better place for more targeted flush. + xText->getString(); + } + catch (uno::RuntimeException const&) + { + // E.g., SwXTextFrame that contains only a table will throw; this is not an error + } + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject") ) + { + uno::Any aAny = xPropSet->getPropertyValue("IsEmptyPresentationObject"); + aAny >>= bIsEmptyPresObj; + } + + if(!bIsEmptyPresObj) + { + GetExport().GetTextParagraphExport()->collectTextAutoStyles( xText ); + } + } + } + + // compute the shape parent style + if( xPropSet.is() ) + { + uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( xPropSet->getPropertySetInfo() ); + + OUString aParentName; + uno::Reference< style::XStyle > xStyle; + + if( bObjSupportsStyle ) + { + if( xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName("Style") ) + xPropSet->getPropertyValue("Style") >>= xStyle; + + if(xStyle.is()) + { + // get family ID + uno::Reference< beans::XPropertySet > xStylePropSet(xStyle, uno::UNO_QUERY); + SAL_WARN_IF( !xStylePropSet.is(), "xmloff", "style without a XPropertySet?" ); + try + { + if(xStylePropSet.is()) + { + OUString aFamilyName; + xStylePropSet->getPropertyValue("Family") >>= aFamilyName; + if( !aFamilyName.isEmpty() && aFamilyName != "graphics" ) + aShapeInfo.mnFamily = XmlStyleFamily::SD_PRESENTATION_ID; + } + } + catch(const beans::UnknownPropertyException&) + { + // Ignored. + SAL_WARN( "xmloff", + "XMLShapeExport::collectShapeAutoStyles: style has no 'Family' property"); + } + + // get parent-style name + if(XmlStyleFamily::SD_PRESENTATION_ID == aShapeInfo.mnFamily) + { + aParentName = msPresentationStylePrefix; + } + + aParentName += xStyle->getName(); + } + } + + if (aParentName.isEmpty() && xPropertySetInfo->hasPropertyByName("TextBox") && xPropSet->getPropertyValue("TextBox").hasValue() && xPropSet->getPropertyValue("TextBox").get()) + { + // Shapes with a Writer TextBox always have a parent style. + // If there would be none, then assign the default one. + aParentName = "Frame"; + } + + // filter propset + std::vector< XMLPropertyState > aPropStates; + + sal_Int32 nCount = 0; + if( !bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeTypePresPageShape) ) + { + aPropStates = GetPropertySetMapper()->Filter(mrExport, xPropSet); + + if (XmlShapeTypeDrawControlShape == aShapeInfo.meShapeType) + { + // for control shapes, we additionally need the number format style (if any) + uno::Reference< drawing::XControlShape > xControl(xShape, uno::UNO_QUERY); + DBG_ASSERT(xControl.is(), "XMLShapeExport::collectShapeAutoStyles: ShapeType control, but no XControlShape!"); + if (xControl.is()) + { + uno::Reference< beans::XPropertySet > xControlModel(xControl->getControl(), uno::UNO_QUERY); + DBG_ASSERT(xControlModel.is(), "XMLShapeExport::collectShapeAutoStyles: no control model on the control shape!"); + + OUString sNumberStyle = mrExport.GetFormExport()->getControlNumberStyle(xControlModel); + if (!sNumberStyle.isEmpty()) + { + sal_Int32 nIndex = GetPropertySetMapper()->getPropertySetMapper()->FindEntryIndex(CTF_SD_CONTROL_SHAPE_DATA_STYLE); + // TODO : this retrieval of the index could be moved into the ctor, holding the index + // as member, thus saving time. + DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for our context id!"); + + XMLPropertyState aNewState(nIndex, uno::Any(sNumberStyle)); + aPropStates.push_back(aNewState); + } + } + } + + nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(), + [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; }); + } + + if(nCount == 0) + { + // no hard attributes, use parent style name for export + aShapeInfo.msStyleName = aParentName; + } + else + { + // there are filtered properties -> hard attributes + // try to find this style in AutoStylePool + aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Find(aShapeInfo.mnFamily, aParentName, aPropStates); + + if(aShapeInfo.msStyleName.isEmpty()) + { + // Style did not exist, add it to AutoStalePool + aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Add(aShapeInfo.mnFamily, aParentName, std::move(aPropStates)); + } + } + + // optionally generate auto style for text attributes + if( (!bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeTypePresPageShape)) && bObjSupportsText ) + { + aPropStates = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter(mrExport, xPropSet); + + // yet more additionally, we need to care for the ParaAdjust property + if ( XmlShapeTypeDrawControlShape == aShapeInfo.meShapeType ) + { + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + uno::Reference< beans::XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if ( xPropSetInfo.is() && xPropState.is() ) + { + // this is because: + // * if controls shapes have a ParaAdjust property, then this is the Align property of the control model + // * control models are allowed to have an Align of "void" + // * the Default for control model's Align is TextAlign_LEFT + // * defaults for style properties are not written, but we need to write the "left", + // because we need to distinguish this "left" from the case where not align attribute + // is present which means "void" + if ( xPropSetInfo->hasPropertyByName( "ParaAdjust" ) + && ( beans::PropertyState_DEFAULT_VALUE == xPropState->getPropertyState( "ParaAdjust" ) ) + ) + { + sal_Int32 nIndex = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->getPropertySetMapper()->FindEntryIndex( CTF_SD_SHAPE_PARA_ADJUST ); + // TODO : this retrieval of the index should be moved into the ctor, holding the index + // as member, thus saving time. + DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for the ParaAdjust context id!"); + + uno::Any aParaAdjustValue = xPropSet->getPropertyValue( "ParaAdjust" ); + XMLPropertyState aAlignDefaultState( nIndex, aParaAdjustValue ); + + aPropStates.push_back( aAlignDefaultState ); + } + } + } + + nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(), + [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; }); + + if( nCount ) + { + aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Find( XmlStyleFamily::TEXT_PARAGRAPH, "", aPropStates ); + if(aShapeInfo.msTextStyleName.isEmpty()) + { + // Style did not exist, add it to AutoStalePool + aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TEXT_PARAGRAPH, "", std::move(aPropStates)); + } + } + } + } + + // prepare animation information if needed + if( mxAnimationsExporter.is() ) + XMLAnimationsExporter::prepare( xShape ); + + // check for special shapes + + switch( aShapeInfo.meShapeType ) + { + case XmlShapeTypeDrawConnectorShape: + { + uno::Reference< uno::XInterface > xConnection; + + // create shape ids for export later + xPropSet->getPropertyValue( gsStartShape ) >>= xConnection; + if( xConnection.is() ) + mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection ); + + xPropSet->getPropertyValue( gsEndShape ) >>= xConnection; + if( xConnection.is() ) + mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection ); + break; + } + case XmlShapeTypePresTableShape: + case XmlShapeTypeDrawTableShape: + { + try + { + uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW ); + GetShapeTableExport()->collectTableAutoStyles( xRange ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "collecting auto styles for a table" ); + } + break; + } + default: + break; + } + + // check for shape collections (group shape or 3d scene) + // and collect contained shapes style infos + const uno::Reference< drawing::XShape >& xCollection = aShapeInfo.xCustomShapeReplacement.is() + ? aShapeInfo.xCustomShapeReplacement : xShape; + { + uno::Reference< drawing::XShapes > xShapes( xCollection, uno::UNO_QUERY ); + if( xShapes.is() ) + { + collectShapesAutoStyles( xShapes ); + } + } +} + +namespace +{ + class NewTextListsHelper + { + public: + explicit NewTextListsHelper( SvXMLExport& rExp ) + : mrExport( rExp ) + { + mrExport.GetTextParagraphExport()->PushNewTextListsHelper(); + } + + ~NewTextListsHelper() + { + mrExport.GetTextParagraphExport()->PopTextListsHelper(); + } + + private: + SvXMLExport& mrExport; + }; +} +// This method exports the given XShape +void XMLShapeExport::exportShape(const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, + css::awt::Point* pRefPoint /* = NULL */, + SvXMLAttributeList* pAttrList /* = NULL */ ) +{ + SAL_INFO("xmloff", xShape->getShapeType()); + if( maCurrentShapesIter == maShapesInfos.end() ) + { + SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no auto styles where collected before export" ); + return; + } + sal_Int32 nZIndex = 0; + uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY ); + OUString sHyperlink; + try + { + xSet->getPropertyValue(gsHyperlink) >>= sHyperlink; + } + catch (beans::UnknownPropertyException) + { + } + + std::unique_ptr< SvXMLElementExport > pHyperlinkElement; + + // Need to stash the attributes that are pre-loaded for the shape export + // (otherwise they will become attributes of the draw:a element) + uno::Reference xSaveAttribs( + new SvXMLAttributeList(GetExport().GetAttrList())); + GetExport().ClearAttrList(); + if( xSet.is() && (GetExport().GetModelType() == SvtModuleOptions::EFactory::DRAW) ) + { + // export hyperlinks with . Currently only in draw since draw + // does not support document events + try + { + presentation::ClickAction eAction = presentation::ClickAction_NONE; + xSet->getPropertyValue(gsOnClick) >>= eAction; + + if( (eAction == presentation::ClickAction_DOCUMENT) || + (eAction == presentation::ClickAction_BOOKMARK) ) + { + OUString sURL; + xSet->getPropertyValue(gsBookmark) >>= sURL; + + if( !sURL.isEmpty() ) + { + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) ); + } + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff", "XMLShapeExport::exportShape(): exception during hyperlink export"); + } + } + else if (xSet.is() && !sHyperlink.isEmpty()) + { + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sHyperlink ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) ); + } + // re-add stashed attributes + GetExport().AddAttributeList(xSaveAttribs); + + if( xSet.is() ) + xSet->getPropertyValue(gsZIndex) >>= nZIndex; + + ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second; + + if( static_cast(aShapeInfoVector.size()) <= nZIndex ) + { + SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no shape info collected for a given shape" ); + return; + } + + NewTextListsHelper aNewTextListsHelper( mrExport ); + + const ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex]; + +#ifdef DBG_UTIL + // check if this is the correct ShapesInfo + uno::Reference< container::XChild > xChild( xShape, uno::UNO_QUERY ); + if( xChild.is() ) + { + uno::Reference< drawing::XShapes > xParent( xChild->getParent(), uno::UNO_QUERY ); + SAL_WARN_IF( !xParent.is() && xParent.get() == (*maCurrentShapesIter).first.get(), "xmloff", "XMLShapeExport::exportShape(): Wrong call to XMLShapeExport::seekShapes()" ); + } + + // first compute the shapes type + { + XmlShapeType eShapeType(XmlShapeTypeNotYetSet); + ImpCalcShapeType(xShape, eShapeType); + + SAL_WARN_IF( eShapeType != aShapeInfo.meShapeType, "xmloff", "exportShape callings do not correspond to collectShapeAutoStyles calls!: " << xShape->getShapeType() ); + } +#endif + + // collect animation information if needed + if( mxAnimationsExporter.is() ) + mxAnimationsExporter->collect( xShape, mrExport ); + + /* Export shapes name if he has one (#i51726#) + Export of the shape name for text documents only if the OpenDocument + file format is written - exceptions are group shapes. + Note: Writer documents in OpenOffice.org file format doesn't contain + any names for shapes, except for group shapes. + */ + { + if ( ( GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITER && + GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERWEB && + GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERGLOBAL ) || + ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) || + aShapeInfo.meShapeType == XmlShapeTypeDrawGroupShape || + ( aShapeInfo.meShapeType == XmlShapeTypeDrawCustomShape && + aShapeInfo.xCustomShapeReplacement.is() ) ) + { + uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY ); + if( xNamed.is() ) + { + const OUString aName( xNamed->getName() ); + if( !aName.isEmpty() ) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, aName ); + } + } + } + + // export style name + if( !aShapeInfo.msStyleName.isEmpty() ) + { + if(XmlStyleFamily::SD_GRAPHICS_ID == aShapeInfo.mnFamily) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) ); + else + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) ); + } + + // export text style name + if( !aShapeInfo.msTextStyleName.isEmpty() ) + { + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TEXT_STYLE_NAME, aShapeInfo.msTextStyleName ); + } + + // export shapes id if needed + { + uno::Reference< uno::XInterface > xRef( xShape, uno::UNO_QUERY ); + const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRef ); + if( !rShapeId.isEmpty() ) + { + mrExport.AddAttributeIdLegacy(XML_NAMESPACE_DRAW, rShapeId); + } + } + + // export layer information + if( mbExportLayer ) + { + // check for group or scene shape and not export layer if this is one + uno::Reference< drawing::XShapes > xShapes( xShape, uno::UNO_QUERY ); + if( !xShapes.is() ) + { + try + { + uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY ); + OUString aLayerName; + xProps->getPropertyValue("LayerName") >>= aLayerName; + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LAYER, aLayerName ); + + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting layer name for shape" ); + } + } + } + + // export draw:display (do not export in ODF 1.3 or older) + if (xSet.is() && (mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + { + if( aShapeInfo.meShapeType != XmlShapeTypeDrawPageShape && aShapeInfo.meShapeType != XmlShapeTypePresPageShape && + aShapeInfo.meShapeType != XmlShapeTypeHandoutShape && aShapeInfo.meShapeType != XmlShapeTypeDrawChartShape ) + try + { + bool bVisible = true; + bool bPrintable = true; + + xSet->getPropertyValue(gsVisible) >>= bVisible; + xSet->getPropertyValue(gsPrintable) >>= bPrintable; + + XMLTokenEnum eDisplayToken = XML_TOKEN_INVALID; + const unsigned short nDisplay = (bVisible ? 2 : 0) | (bPrintable ? 1 : 0); + switch( nDisplay ) + { + case 0: eDisplayToken = XML_NONE; break; + case 1: eDisplayToken = XML_PRINTER; break; + case 2: eDisplayToken = XML_SCREEN; break; + // case 3: eDisplayToken = XML_ALWAYS break; this is the default + } + + if( eDisplayToken != XML_TOKEN_INVALID ) + mrExport.AddAttribute(XML_NAMESPACE_DRAW_EXT, XML_DISPLAY, eDisplayToken ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + } + + // #82003# test export count + // #91587# ALWAYS increment since now ALL to be exported shapes are counted. + if(mrExport.GetShapeExport()->IsHandleProgressBarEnabled()) + { + mrExport.GetProgressBarHelper()->Increment(); + } + + onExport( xShape ); + + // export shape element + switch(aShapeInfo.meShapeType) + { + case XmlShapeTypeDrawRectangleShape: + { + ImpExportRectangleShape(xShape, nFeatures, pRefPoint ); + break; + } + case XmlShapeTypeDrawEllipseShape: + { + ImpExportEllipseShape(xShape, nFeatures, pRefPoint ); + break; + } + case XmlShapeTypeDrawLineShape: + { + ImpExportLineShape(xShape, nFeatures, pRefPoint ); + break; + } + case XmlShapeTypeDrawPolyPolygonShape: // closed PolyPolygon + case XmlShapeTypeDrawPolyLineShape: // open PolyPolygon + case XmlShapeTypeDrawClosedBezierShape: // closed tools::PolyPolygon containing curves + case XmlShapeTypeDrawOpenBezierShape: // open tools::PolyPolygon containing curves + { + ImpExportPolygonShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawTextShape: + case XmlShapeTypePresTitleTextShape: + case XmlShapeTypePresOutlinerShape: + case XmlShapeTypePresSubtitleShape: + case XmlShapeTypePresNotesShape: + case XmlShapeTypePresHeaderShape: + case XmlShapeTypePresFooterShape: + case XmlShapeTypePresSlideNumberShape: + case XmlShapeTypePresDateTimeShape: + { + ImpExportTextBoxShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawGraphicObjectShape: + case XmlShapeTypePresGraphicObjectShape: + { + ImpExportGraphicObjectShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawChartShape: + case XmlShapeTypePresChartShape: + { + ImpExportChartShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint, pAttrList ); + break; + } + + case XmlShapeTypeDrawControlShape: + { + ImpExportControlShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawConnectorShape: + { + ImpExportConnectorShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawMeasureShape: + { + ImpExportMeasureShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawOLE2Shape: + case XmlShapeTypePresOLE2Shape: + case XmlShapeTypeDrawSheetShape: + case XmlShapeTypePresSheetShape: + { + ImpExportOLE2Shape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypePresTableShape: + case XmlShapeTypeDrawTableShape: + { + ImpExportTableShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawPageShape: + case XmlShapeTypePresPageShape: + case XmlShapeTypeHandoutShape: + { + ImpExportPageShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawCaptionShape: + { + ImpExportCaptionShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDraw3DCubeObject: + case XmlShapeTypeDraw3DSphereObject: + case XmlShapeTypeDraw3DLatheObject: + case XmlShapeTypeDraw3DExtrudeObject: + { + ImpExport3DShape(xShape, aShapeInfo.meShapeType); + break; + } + + case XmlShapeTypeDraw3DSceneObject: + { + ImpExport3DSceneShape( xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawGroupShape: + { + // empty group + ImpExportGroupShape( xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawFrameShape: + { + ImpExportFrameShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawAppletShape: + { + ImpExportAppletShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawPluginShape: + { + ImpExportPluginShape(xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypeDrawCustomShape: + { + if ( aShapeInfo.xCustomShapeReplacement.is() ) + ImpExportGroupShape( aShapeInfo.xCustomShapeReplacement, nFeatures, pRefPoint ); + else + ImpExportCustomShape( xShape, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypePresMediaShape: + case XmlShapeTypeDrawMediaShape: + { + ImpExportMediaShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint ); + break; + } + + case XmlShapeTypePresOrgChartShape: + case XmlShapeTypeUnknown: + case XmlShapeTypeNotYetSet: + default: + { + // this should never happen and is an error + OSL_FAIL("XMLEXP: WriteShape: unknown or unexpected type of shape in export!"); + break; + } + } + + pHyperlinkElement.reset(); + + // #97489# #97111# + // if there was an error and no element for the shape was exported + // we need to clear the attribute list or the attributes will be + // set on the next exported element, which can result in corrupt + // xml files due to duplicate attributes + + mrExport.CheckAttrList(); // asserts in non pro if we have attributes left + mrExport.ClearAttrList(); // clears the attributes +} + +// This method collects all automatic styles for the shapes inside the given XShapes collection +void XMLShapeExport::collectShapesAutoStyles( const uno::Reference < drawing::XShapes >& xShapes ) +{ + ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter; + seekShapes( xShapes ); + + uno::Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount(xShapes->getCount()); + for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++) + { + xShapes->getByIndex(nShapeId) >>= xShape; + SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" ); + if(!xShape.is()) + continue; + + collectShapeAutoStyles( xShape ); + } + + maCurrentShapesIter = aOldCurrentShapesIter; +} + +// This method exports all XShape inside the given XShapes collection +void XMLShapeExport::exportShapes( const uno::Reference < drawing::XShapes >& xShapes, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */ ) +{ + ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter; + seekShapes( xShapes ); + + uno::Reference< drawing::XShape > xShape; + const sal_Int32 nShapeCount(xShapes->getCount()); + for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++) + { + xShapes->getByIndex(nShapeId) >>= xShape; + SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" ); + if(!xShape.is()) + continue; + + exportShape( xShape, nFeatures, pRefPoint ); + } + + maCurrentShapesIter = aOldCurrentShapesIter; +} + +namespace xmloff { + +void FixZOrder(uno::Reference const& xShapes, + std::function const&)> const& rGetLayer) +{ + uno::Reference const xShapes3(xShapes, uno::UNO_QUERY); + assert(xShapes3.is()); + if (!xShapes3.is()) + { + return; // only SvxDrawPage implements this + } + struct Layer { std::vector shapes; sal_Int32 nMin = SAL_MAX_INT32; sal_Int32 nMax = 0; }; + std::vector layers; + // shapes are sorted by ZOrder + sal_Int32 const nCount(xShapes->getCount()); + for (sal_Int32 i = 0; i < nCount; ++i) + { + uno::Reference const xShape(xShapes->getByIndex(i), uno::UNO_QUERY); + if (!xShape.is()) + { + SAL_WARN("xmloff", "FixZOrder: null shape, cannot sort"); + return; + } + unsigned int const nLayer(rGetLayer(xShape)); + if (layers.size() <= nLayer) + { + layers.resize(nLayer + 1); + } + layers[nLayer].shapes.emplace_back(i); + if (i < layers[nLayer].nMin) + { + layers[nLayer].nMin = i; + } + if (layers[nLayer].nMax < i) + { + layers[nLayer].nMax = i; + } + } + layers.erase(std::remove_if(layers.begin(), layers.end(), + [](Layer const& rLayer) { return rLayer.shapes.empty(); }), + layers.end()); + bool isSorted(true); + for (size_t i = 1; i < layers.size(); ++i) + { + assert(layers[i].nMin != layers[i-1].nMax); // unique! + if (layers[i].nMin < layers[i-1].nMax) + { + isSorted = false; + break; + } + } + if (isSorted) + { + return; // nothing to do + } + uno::Sequence aNewOrder(nCount); + auto iterInsert(aNewOrder.getArray()); + for (auto const& rLayer : layers) + { + assert(rLayer.nMin <= rLayer.nMax); // empty layers have been removed + iterInsert = std::copy(rLayer.shapes.begin(), rLayer.shapes.end(), iterInsert); + } + try + { + xShapes3->sort(aNewOrder); + } + catch (uno::Exception const&) + { + SAL_WARN("xmloff", "FixZOrder: exception"); + } +} + +} // namespace xmloff + +void XMLShapeExport::seekShapes( const uno::Reference< drawing::XShapes >& xShapes ) noexcept +{ + if( xShapes.is() ) + { + maCurrentShapesIter = maShapesInfos.find( xShapes ); + if( maCurrentShapesIter == maShapesInfos.end() ) + { + ImplXMLShapeExportInfoVector aNewInfoVector; + aNewInfoVector.resize( static_cast(xShapes->getCount()) ); + maShapesInfos[ xShapes ] = aNewInfoVector; + + maCurrentShapesIter = maShapesInfos.find( xShapes ); + + SAL_WARN_IF( maCurrentShapesIter == maShapesInfos.end(), "xmloff", "XMLShapeExport::seekShapes(): insert into stl::map failed" ); + } + + SAL_WARN_IF( (*maCurrentShapesIter).second.size() != static_cast(xShapes->getCount()), "xmloff", "XMLShapeExport::seekShapes(): XShapes size varied between calls" ); + + } + else + { + maCurrentShapesIter = maShapesInfos.end(); + } +} + +void XMLShapeExport::exportAutoStyles() +{ + // export all autostyle infos + + // ...for graphic + { + GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_GRAPHICS_ID ); + } + + // ...for presentation + { + GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_PRESENTATION_ID ); + } + + if( mxShapeTableExport.is() ) + mxShapeTableExport->exportAutoStyles(); +} + +/// returns the export property mapper for external chaining +SvXMLExportPropertyMapper* XMLShapeExport::CreateShapePropMapper( + SvXMLExport& rExport ) +{ + rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rExport.GetModel(), rExport ); + rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, true ); + rExport.GetTextParagraphExport(); // get or create text paragraph export + SvXMLExportPropertyMapper* pResult = + new XMLShapeExportPropertyMapper( xMapper, rExport ); + // chain text attributes + return pResult; +} + +void XMLShapeExport::ImpCalcShapeType(const uno::Reference< drawing::XShape >& xShape, + XmlShapeType& eShapeType) +{ + // set in every case, so init here + eShapeType = XmlShapeTypeUnknown; + + if(!xShape.is()) + return; + + OUString aType(xShape->getShapeType()); + + if(!aType.match("com.sun.star.")) + return; + + if(aType.match("drawing.", 13)) + { + // drawing shapes + if (aType.match("Rectangle", 21)) { eShapeType = XmlShapeTypeDrawRectangleShape; } + + // #i72177# Note: Correcting CustomShape, CustomShape->Custom, len from 9 (was wrong anyways) to 6. + // As can be seen at the other compares, the appendix "Shape" is left out of the comparison. + else if(aType.match("Custom", 21)) { eShapeType = XmlShapeTypeDrawCustomShape; } + + else if(aType.match("Ellipse", 21)) { eShapeType = XmlShapeTypeDrawEllipseShape; } + else if(aType.match("Control", 21)) { eShapeType = XmlShapeTypeDrawControlShape; } + else if(aType.match("Connector", 21)) { eShapeType = XmlShapeTypeDrawConnectorShape; } + else if(aType.match("Measure", 21)) { eShapeType = XmlShapeTypeDrawMeasureShape; } + else if(aType.match("Line", 21)) { eShapeType = XmlShapeTypeDrawLineShape; } + + // #i72177# Note: This covers two types by purpose, PolyPolygonShape and PolyPolygonPathShape + else if(aType.match("PolyPolygon", 21)) { eShapeType = XmlShapeTypeDrawPolyPolygonShape; } + + // #i72177# Note: This covers two types by purpose, PolyLineShape and PolyLinePathShape + else if(aType.match("PolyLine", 21)) { eShapeType = XmlShapeTypeDrawPolyLineShape; } + + else if(aType.match("OpenBezier", 21)) { eShapeType = XmlShapeTypeDrawOpenBezierShape; } + else if(aType.match("ClosedBezier", 21)) { eShapeType = XmlShapeTypeDrawClosedBezierShape; } + + // #i72177# FreeHand (opened and closed) now supports the types OpenFreeHandShape and + // ClosedFreeHandShape respectively. Represent them as bezier shapes + else if(aType.match("OpenFreeHand", 21)) { eShapeType = XmlShapeTypeDrawOpenBezierShape; } + else if(aType.match("ClosedFreeHand", 21)) { eShapeType = XmlShapeTypeDrawClosedBezierShape; } + + else if(aType.match("GraphicObject", 21)) { eShapeType = XmlShapeTypeDrawGraphicObjectShape; } + else if(aType.match("Group", 21)) { eShapeType = XmlShapeTypeDrawGroupShape; } + else if(aType.match("Text", 21)) { eShapeType = XmlShapeTypeDrawTextShape; } + else if(aType.match("OLE2", 21)) + { + eShapeType = XmlShapeTypeDrawOLE2Shape; + + // get info about presentation shape + uno::Reference xPropSet(xShape, uno::UNO_QUERY); + + if(xPropSet.is()) + { + OUString sCLSID; + if(xPropSet->getPropertyValue("CLSID") >>= sCLSID) + { +#if !ENABLE_WASM_STRIP_CHART + // WASM_CHART change + // TODO: With Chart extracted this cannot really happen since + // no Chart could've been added at all + if (sCLSID == mrExport.GetChartExport()->getChartCLSID() || +#else + if( +#endif + sCLSID == SvGlobalName( SO3_RPTCH_CLASSID ).GetHexName() ) + { + eShapeType = XmlShapeTypeDrawChartShape; + } + else if (sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() ) + { + eShapeType = XmlShapeTypeDrawSheetShape; + } + else + { + // general OLE2 Object + } + } + } + } + else if(aType.match("Page", 21)) { eShapeType = XmlShapeTypeDrawPageShape; } + else if(aType.match("Frame", 21)) { eShapeType = XmlShapeTypeDrawFrameShape; } + else if(aType.match("Caption", 21)) { eShapeType = XmlShapeTypeDrawCaptionShape; } + else if(aType.match("Plugin", 21)) { eShapeType = XmlShapeTypeDrawPluginShape; } + else if(aType.match("Applet", 21)) { eShapeType = XmlShapeTypeDrawAppletShape; } + else if(aType.match("MediaShape", 21)) { eShapeType = XmlShapeTypeDrawMediaShape; } + else if(aType.match("TableShape", 21)) { eShapeType = XmlShapeTypeDrawTableShape; } + + // 3D shapes + else if(aType.match("Scene", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DSceneObject; } + else if(aType.match("Cube", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DCubeObject; } + else if(aType.match("Sphere", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DSphereObject; } + else if(aType.match("Lathe", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DLatheObject; } + else if(aType.match("Extrude", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DExtrudeObject; } + } + else if(aType.match("presentation.", 13)) + { + // presentation shapes + if (aType.match("TitleText", 26)) { eShapeType = XmlShapeTypePresTitleTextShape; } + else if(aType.match("Outliner", 26)) { eShapeType = XmlShapeTypePresOutlinerShape; } + else if(aType.match("Subtitle", 26)) { eShapeType = XmlShapeTypePresSubtitleShape; } + else if(aType.match("GraphicObject", 26)) { eShapeType = XmlShapeTypePresGraphicObjectShape; } + else if(aType.match("Page", 26)) { eShapeType = XmlShapeTypePresPageShape; } + else if(aType.match("OLE2", 26)) + { + eShapeType = XmlShapeTypePresOLE2Shape; + + // get info about presentation shape + uno::Reference xPropSet(xShape, uno::UNO_QUERY); + + if(xPropSet.is()) try + { + OUString sCLSID; + if(xPropSet->getPropertyValue("CLSID") >>= sCLSID) + { + if( sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() ) + { + eShapeType = XmlShapeTypePresSheetShape; + } + } + } + catch(const uno::Exception&) + { + SAL_WARN( "xmloff", "XMLShapeExport::ImpCalcShapeType(), expected ole shape to have the CLSID property?" ); + } + } + else if(aType.match("Chart", 26)) { eShapeType = XmlShapeTypePresChartShape; } + else if(aType.match("OrgChart", 26)) { eShapeType = XmlShapeTypePresOrgChartShape; } + else if(aType.match("CalcShape", 26)) { eShapeType = XmlShapeTypePresSheetShape; } + else if(aType.match("TableShape", 26)) { eShapeType = XmlShapeTypePresTableShape; } + else if(aType.match("Notes", 26)) { eShapeType = XmlShapeTypePresNotesShape; } + else if(aType.match("HandoutShape", 26)) { eShapeType = XmlShapeTypeHandoutShape; } + else if(aType.match("HeaderShape", 26)) { eShapeType = XmlShapeTypePresHeaderShape; } + else if(aType.match("FooterShape", 26)) { eShapeType = XmlShapeTypePresFooterShape; } + else if(aType.match("SlideNumberShape", 26)) { eShapeType = XmlShapeTypePresSlideNumberShape; } + else if(aType.match("DateTimeShape", 26)) { eShapeType = XmlShapeTypePresDateTimeShape; } + else if(aType.match("MediaShape", 26)) { eShapeType = XmlShapeTypePresMediaShape; } + } +} + +/** exports all user defined gluepoints */ +void XMLShapeExport::ImpExportGluePoints( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< drawing::XGluePointsSupplier > xSupplier( xShape, uno::UNO_QUERY ); + if( !xSupplier.is() ) + return; + + uno::Reference< container::XIdentifierAccess > xGluePoints( xSupplier->getGluePoints(), uno::UNO_QUERY ); + if( !xGluePoints.is() ) + return; + + drawing::GluePoint2 aGluePoint; + + const uno::Sequence< sal_Int32 > aIdSequence( xGluePoints->getIdentifiers() ); + + for( const sal_Int32 nIdentifier : aIdSequence ) + { + if( (xGluePoints->getByIdentifier( nIdentifier ) >>= aGluePoint) && aGluePoint.IsUserDefined ) + { + // export only user defined gluepoints + + const OUString sId( OUString::number( nIdentifier ) ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_ID, sId ); + + mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer, + aGluePoint.Position.X); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, msBuffer.makeStringAndClear()); + + mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer, + aGluePoint.Position.Y); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, msBuffer.makeStringAndClear()); + + if( !aGluePoint.IsRelative ) + { + SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.PositionAlignment, aXML_GlueAlignment_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ALIGN, msBuffer.makeStringAndClear() ); + } + + if( aGluePoint.Escape != drawing::EscapeDirection_SMART ) + { + SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.Escape, aXML_GlueEscapeDirection_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ESCAPE_DIRECTION, msBuffer.makeStringAndClear() ); + } + + SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_DRAW, XML_GLUE_POINT, true, true); + } + } +} + +void XMLShapeExport::ImpExportSignatureLine(const uno::Reference& xShape) +{ + uno::Reference xPropSet(xShape, uno::UNO_QUERY); + + bool bIsSignatureLine = false; + xPropSet->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine; + if (!bIsSignatureLine) + return; + + OUString aSignatureLineId; + xPropSet->getPropertyValue("SignatureLineId") >>= aSignatureLineId; + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, aSignatureLineId); + + OUString aSuggestedSignerName; + xPropSet->getPropertyValue("SignatureLineSuggestedSignerName") >>= aSuggestedSignerName; + if (!aSuggestedSignerName.isEmpty()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_NAME, aSuggestedSignerName); + + OUString aSuggestedSignerTitle; + xPropSet->getPropertyValue("SignatureLineSuggestedSignerTitle") >>= aSuggestedSignerTitle; + if (!aSuggestedSignerTitle.isEmpty()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_TITLE, aSuggestedSignerTitle); + + OUString aSuggestedSignerEmail; + xPropSet->getPropertyValue("SignatureLineSuggestedSignerEmail") >>= aSuggestedSignerEmail; + if (!aSuggestedSignerEmail.isEmpty()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_EMAIL, aSuggestedSignerEmail); + + OUString aSigningInstructions; + xPropSet->getPropertyValue("SignatureLineSigningInstructions") >>= aSigningInstructions; + if (!aSigningInstructions.isEmpty()) + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SIGNING_INSTRUCTIONS, aSigningInstructions); + + bool bShowSignDate = false; + xPropSet->getPropertyValue("SignatureLineShowSignDate") >>= bShowSignDate; + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOW_SIGN_DATE, + bShowSignDate ? XML_TRUE : XML_FALSE); + + bool bCanAddComment = false; + xPropSet->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment; + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CAN_ADD_COMMENT, + bCanAddComment ? XML_TRUE : XML_FALSE); + + SvXMLElementExport aSignatureLineElement(mrExport, XML_NAMESPACE_LO_EXT, XML_SIGNATURELINE, true, + true); +} + +void XMLShapeExport::ImpExportQRCode(const uno::Reference& xShape) +{ + uno::Reference xPropSet(xShape, uno::UNO_QUERY); + + uno::Any aAny = xPropSet->getPropertyValue("BarCodeProperties"); + + css::drawing::BarCode aBarCode; + if(!(aAny >>= aBarCode)) + return; + + mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, aBarCode.Payload); + /* Export QR Code as per customised schema, @see OpenDocument-schema-v1.3+libreoffice */ + OUString temp; + switch(aBarCode.ErrorCorrection){ + case css::drawing::BarCodeErrorCorrection::LOW : + temp = "low"; + break; + case css::drawing::BarCodeErrorCorrection::MEDIUM: + temp = "medium"; + break; + case css::drawing::BarCodeErrorCorrection::QUARTILE: + temp = "quartile"; + break; + case css::drawing::BarCodeErrorCorrection::HIGH: + temp = "high"; + break; + } + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_ERROR_CORRECTION, temp); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_BORDER, OUStringBuffer(20).append(aBarCode.Border).makeStringAndClear()); + mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_TYPE, OUStringBuffer(20).append(aBarCode.Type).makeStringAndClear()); + + SvXMLElementExport aBarCodeElement(mrExport, XML_NAMESPACE_LO_EXT, XML_QRCODE, true, + true); +} + +void XMLShapeExport::ExportGraphicDefaults() +{ + rtl::Reference aStEx(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get())); + + // construct PropertySetMapper + rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( CreateShapePropMapper( mrExport ) ); + static_cast(xPropertySetMapper.get())->SetAutoStyles( false ); + + // chain text attributes + xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(mrExport)); + + // chain special Writer/text frame default attributes + xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaDefaultExtPropMapper(mrExport)); + + // write graphic family default style + uno::Reference< lang::XMultiServiceFactory > xFact( mrExport.GetModel(), uno::UNO_QUERY ); + if( !xFact.is() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xDefaults( xFact->createInstance("com.sun.star.drawing.Defaults"), uno::UNO_QUERY ); + if( xDefaults.is() ) + { + aStEx->exportDefaultStyle( xDefaults, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper ); + + // write graphic family styles + aStEx->exportStyleFamily("graphics", OUString(XML_STYLE_FAMILY_SD_GRAPHICS_NAME), xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID); + } + } + catch(const lang::ServiceNotRegisteredException&) + { + } +} + +void XMLShapeExport::onExport( const css::uno::Reference < css::drawing::XShape >& ) +{ +} + +const rtl::Reference< XMLTableExport >& XMLShapeExport::GetShapeTableExport() +{ + if( !mxShapeTableExport.is() ) + { + rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrExport.GetModel(), mrExport ) ); + rtl::Reference < XMLPropertySetMapper > xMapper( new XMLShapePropertySetMapper( xFactory, true ) ); + mrExport.GetTextParagraphExport(); // get or create text paragraph export + rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( new XMLShapeExportPropertyMapper( xMapper, mrExport ) ); + mxShapeTableExport = new XMLTableExport( mrExport, xPropertySetMapper, xFactory ); + } + + return mxShapeTableExport; +} + +void XMLShapeExport::ImpExportNewTrans(const uno::Reference< beans::XPropertySet >& xPropSet, + XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + // get matrix + ::basegfx::B2DHomMatrix aMatrix; + ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet); + + // decompose and correct about pRefPoint + ::basegfx::B2DTuple aTRScale; + double fTRShear(0.0); + double fTRRotate(0.0); + ::basegfx::B2DTuple aTRTranslate; + ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint); + + // use features and write + ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures); +} + +void XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix& rMatrix, + const uno::Reference< beans::XPropertySet >& xPropSet) +{ + /* Get , if it exist + and if the document is exported into the OpenOffice.org file format. + This property only exists at service css::text::Shape - the + Writer UNO service for shapes. + This code is needed, because the positioning attributes in the + OpenOffice.org file format are given in horizontal left-to-right layout + regardless the layout direction the shape is in. In the OASIS Open Office + file format the positioning attributes are correctly given in the layout + direction the shape is in. Thus, this code provides the conversion from + the OASIS Open Office file format to the OpenOffice.org file format. (#i28749#) + */ + uno::Any aAny; + if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + xPropSet->getPropertySetInfo()->hasPropertyByName("TransformationInHoriL2R") ) + { + aAny = xPropSet->getPropertyValue("TransformationInHoriL2R"); + } + else + { + aAny = xPropSet->getPropertyValue("Transformation"); + } + drawing::HomogenMatrix3 aMatrix; + aAny >>= aMatrix; + + rMatrix.set(0, 0, aMatrix.Line1.Column1); + rMatrix.set(0, 1, aMatrix.Line1.Column2); + rMatrix.set(0, 2, aMatrix.Line1.Column3); + rMatrix.set(1, 0, aMatrix.Line2.Column1); + rMatrix.set(1, 1, aMatrix.Line2.Column2); + rMatrix.set(1, 2, aMatrix.Line2.Column3); + rMatrix.set(2, 0, aMatrix.Line3.Column1); + rMatrix.set(2, 1, aMatrix.Line3.Column2); + rMatrix.set(2, 2, aMatrix.Line3.Column3); +} + +void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const ::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale, + double& fTRShear, double& fTRRotate, ::basegfx::B2DTuple& rTRTranslate, css::awt::Point* pRefPoint) +{ + // decompose matrix + rMatrix.decompose(rTRScale, rTRTranslate, fTRRotate, fTRShear); + + // correct translation about pRefPoint + if(pRefPoint) + { + rTRTranslate -= ::basegfx::B2DTuple(pRefPoint->X, pRefPoint->Y); + } +} + +void XMLShapeExport::ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple const & rTRScale, double fTRShear, + double fTRRotate, ::basegfx::B2DTuple const & rTRTranslate, const XMLShapeExportFlags nFeatures) +{ + // always write Size (rTRScale) since this statement carries the union + // of the object + OUString aStr; + OUStringBuffer sStringBuffer; + ::basegfx::B2DTuple aTRScale(rTRScale); + + // svg: width + if(!(nFeatures & XMLShapeExportFlags::WIDTH)) + { + aTRScale.setX(1.0); + } + else + { + if( aTRScale.getX() > 0.0 ) + aTRScale.setX(aTRScale.getX() - 1.0); + else if( aTRScale.getX() < 0.0 ) + aTRScale.setX(aTRScale.getX() + 1.0); + } + + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + FRound(aTRScale.getX())); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr); + + // svg: height + if(!(nFeatures & XMLShapeExportFlags::HEIGHT)) + { + aTRScale.setY(1.0); + } + else + { + if( aTRScale.getY() > 0.0 ) + aTRScale.setY(aTRScale.getY() - 1.0); + else if( aTRScale.getY() < 0.0 ) + aTRScale.setY(aTRScale.getY() + 1.0); + } + + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + FRound(aTRScale.getY())); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr); + + // decide if transformation is necessary + bool bTransformationIsNecessary(fTRShear != 0.0 || fTRRotate != 0.0); + + if(bTransformationIsNecessary) + { + // write transformation, but WITHOUT scale which is exported as size above + SdXMLImExTransform2D aTransform; + + aTransform.AddSkewX(atan(fTRShear)); + + // #i78696# + // fTRRotate is mathematically correct, but due to the error + // we export/import it mirrored. Since the API implementation is fixed and + // uses the correctly oriented angle, it is necessary for compatibility to + // mirror the angle here to stay at the old behaviour. There is a follow-up + // task (#i78698#) to fix this in the next ODF FileFormat version + aTransform.AddRotate(-fTRRotate); + + aTransform.AddTranslate(rTRTranslate); + + // does transformation need to be exported? + if(aTransform.NeedsAction()) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter())); + } + else + { + // no shear, no rotate; just add object position to export and we are done + if(nFeatures & XMLShapeExportFlags::X) + { + // svg: x + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + FRound(rTRTranslate.getX())); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr); + } + + if(nFeatures & XMLShapeExportFlags::Y) + { + // svg: y + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + FRound(rTRTranslate.getY())); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr); + } + } +} + +bool XMLShapeExport::ImpExportPresentationAttributes( const uno::Reference< beans::XPropertySet >& xPropSet, const OUString& rClass ) +{ + bool bIsEmpty = false; + + // write presentation class entry + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, rClass); + + if( xPropSet.is() ) + { + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + + // is empty pres. shape? + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject")) + { + xPropSet->getPropertyValue("IsEmptyPresentationObject") >>= bIsEmpty; + if( bIsEmpty ) + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, XML_TRUE); + } + + // is user-transformed? + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsPlaceholderDependent")) + { + bool bTemp = false; + xPropSet->getPropertyValue("IsPlaceholderDependent") >>= bTemp; + if(!bTemp) + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_USER_TRANSFORMED, XML_TRUE); + } + } + + return bIsEmpty; +} + +void XMLShapeExport::ImpExportText( const uno::Reference< drawing::XShape >& xShape, TextPNS eExtensionNS ) +{ + if (eExtensionNS == TextPNS::EXTENSION) + { + if ((mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + { + return; // do not export to ODF 1.1/1.2/1.3 + } + } + uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY ); + if( xText.is() ) + { + uno::Reference< container::XEnumerationAccess > xEnumAccess( xShape, uno::UNO_QUERY ); + if( xEnumAccess.is() && xEnumAccess->hasElements() ) + mrExport.GetTextParagraphExport()->exportText( xText, false, true, eExtensionNS ); + } +} + +namespace { + +enum class Found { + NONE = 0x0000, + CLICKACTION = 0x0001, + BOOKMARK = 0x0002, + EFFECT = 0x0004, + PLAYFULL = 0x0008, + VERB = 0x0010, + SOUNDURL = 0x0020, + SPEED = 0x0040, + CLICKEVENTTYPE = 0x0080, + MACRO = 0x0100, + LIBRARY = 0x0200, +}; + +} + +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + +void XMLShapeExport::ImpExportEvents( const uno::Reference< drawing::XShape >& xShape ) +{ + uno::Reference< document::XEventsSupplier > xEventsSupplier( xShape, uno::UNO_QUERY ); + if( !xEventsSupplier.is() ) + return; + + uno::Reference< container::XNameAccess > xEvents = xEventsSupplier->getEvents(); + SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" ); + if( !xEvents.is() ) + return; + + Found nFound = Found::NONE; + + OUString aClickEventType; + presentation::ClickAction eClickAction = presentation::ClickAction_NONE; + presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE; + presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_SLOW; + OUString aStrSoundURL; + bool bPlayFull = false; + sal_Int32 nVerb = 0; + OUString aStrMacro; + OUString aStrLibrary; + OUString aStrBookmark; + + uno::Sequence< beans::PropertyValue > aClickProperties; + if( xEvents->hasByName( gsOnClick ) && (xEvents->getByName( gsOnClick ) >>= aClickProperties) ) + { + for( const auto& rProperty : std::as_const(aClickProperties) ) + { + if( !( nFound & Found::CLICKEVENTTYPE ) && rProperty.Name == gsEventType ) + { + if( rProperty.Value >>= aClickEventType ) + nFound |= Found::CLICKEVENTTYPE; + } + else if( !( nFound & Found::CLICKACTION ) && rProperty.Name == gsClickAction ) + { + if( rProperty.Value >>= eClickAction ) + nFound |= Found::CLICKACTION; + } + else if( !( nFound & Found::MACRO ) && ( rProperty.Name == gsMacroName || rProperty.Name == gsScript ) ) + { + if( rProperty.Value >>= aStrMacro ) + nFound |= Found::MACRO; + } + else if( !( nFound & Found::LIBRARY ) && rProperty.Name == gsLibrary ) + { + if( rProperty.Value >>= aStrLibrary ) + nFound |= Found::LIBRARY; + } + else if( !( nFound & Found::EFFECT ) && rProperty.Name == gsEffect ) + { + if( rProperty.Value >>= eEffect ) + nFound |= Found::EFFECT; + } + else if( !( nFound & Found::BOOKMARK ) && rProperty.Name == gsBookmark ) + { + if( rProperty.Value >>= aStrBookmark ) + nFound |= Found::BOOKMARK; + } + else if( !( nFound & Found::SPEED ) && rProperty.Name == gsSpeed ) + { + if( rProperty.Value >>= eSpeed ) + nFound |= Found::SPEED; + } + else if( !( nFound & Found::SOUNDURL ) && rProperty.Name == gsSoundURL ) + { + if( rProperty.Value >>= aStrSoundURL ) + nFound |= Found::SOUNDURL; + } + else if( !( nFound & Found::PLAYFULL ) && rProperty.Name == gsPlayFull ) + { + if( rProperty.Value >>= bPlayFull ) + nFound |= Found::PLAYFULL; + } + else if( !( nFound & Found::VERB ) && rProperty.Name == gsVerb ) + { + if( rProperty.Value >>= nVerb ) + nFound |= Found::VERB; + } + } + } + + // create the XML elements + + if( aClickEventType == gsPresentation ) + { + if( !(nFound & Found::CLICKACTION) || (eClickAction == presentation::ClickAction_NONE) ) + return; + + SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true); + + enum XMLTokenEnum eStrAction; + + switch( eClickAction ) + { + case presentation::ClickAction_PREVPAGE: eStrAction = XML_PREVIOUS_PAGE; break; + case presentation::ClickAction_NEXTPAGE: eStrAction = XML_NEXT_PAGE; break; + case presentation::ClickAction_FIRSTPAGE: eStrAction = XML_FIRST_PAGE; break; + case presentation::ClickAction_LASTPAGE: eStrAction = XML_LAST_PAGE; break; + case presentation::ClickAction_INVISIBLE: eStrAction = XML_HIDE; break; + case presentation::ClickAction_STOPPRESENTATION:eStrAction = XML_STOP; break; + case presentation::ClickAction_PROGRAM: eStrAction = XML_EXECUTE; break; + case presentation::ClickAction_BOOKMARK: eStrAction = XML_SHOW; break; + case presentation::ClickAction_DOCUMENT: eStrAction = XML_SHOW; break; + case presentation::ClickAction_MACRO: eStrAction = XML_EXECUTE_MACRO; break; + case presentation::ClickAction_VERB: eStrAction = XML_VERB; break; + case presentation::ClickAction_VANISH: eStrAction = XML_FADE_OUT; break; + case presentation::ClickAction_SOUND: eStrAction = XML_SOUND; break; + default: + OSL_FAIL( "unknown presentation::ClickAction found!" ); + eStrAction = XML_UNKNOWN; + } + + OUString aEventQName( + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DOM, "click" ) ); + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_ACTION, eStrAction ); + + if( eClickAction == presentation::ClickAction_VANISH ) + { + if( nFound & Found::EFFECT ) + { + XMLEffect eKind; + XMLEffectDirection eDirection; + sal_Int16 nStartScale; + bool bIn; + + SdXMLImplSetEffect( eEffect, eKind, eDirection, nStartScale, bIn ); + + if( eKind != EK_none ) + { + SvXMLUnitConverter::convertEnum( msBuffer, eKind, aXML_AnimationEffect_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, msBuffer.makeStringAndClear() ); + } + + if( eDirection != ED_none ) + { + SvXMLUnitConverter::convertEnum( msBuffer, eDirection, aXML_AnimationDirection_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, msBuffer.makeStringAndClear() ); + } + + if( nStartScale != -1 ) + { + ::sax::Converter::convertPercent( msBuffer, nStartScale ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, msBuffer.makeStringAndClear() ); + } + } + + if( nFound & Found::SPEED && eEffect != presentation::AnimationEffect_NONE ) + { + if( eSpeed != presentation::AnimationSpeed_MEDIUM ) + { + SvXMLUnitConverter::convertEnum( msBuffer, eSpeed, aXML_AnimationSpeed_EnumMap ); + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, msBuffer.makeStringAndClear() ); + } + } + } + + if( eClickAction == presentation::ClickAction_PROGRAM || + eClickAction == presentation::ClickAction_BOOKMARK || + eClickAction == presentation::ClickAction_DOCUMENT ) + { + if( eClickAction == presentation::ClickAction_BOOKMARK ) + msBuffer.append( '#' ); + + msBuffer.append( aStrBookmark ); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(msBuffer.makeStringAndClear()) ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + } + + if( ( nFound & Found::VERB ) && eClickAction == presentation::ClickAction_VERB ) + { + msBuffer.append( nVerb ); + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_VERB, msBuffer.makeStringAndClear()); + } + + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, true, true); + + if( eClickAction == presentation::ClickAction_VANISH || eClickAction == presentation::ClickAction_SOUND ) + { + if( ( nFound & Found::SOUNDURL ) && !aStrSoundURL.isEmpty() ) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStrSoundURL) ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + if( nFound & Found::PLAYFULL && bPlayFull ) + mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE ); + + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true ); + } + } + } + else if( aClickEventType == gsStarBasic ) + { + if( nFound & Found::MACRO ) + { + SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true); + + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, + "starbasic" ) ); + OUString aEventQName( + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DOM, "click" ) ); + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName ); + + if( nFound & Found::LIBRARY ) + { + const OUString& sLocation( GetXMLToken( + (aStrLibrary.equalsIgnoreAsciiCase("StarOffice") || + aStrLibrary.equalsIgnoreAsciiCase("application") ) ? XML_APPLICATION + : XML_DOCUMENT ) ); + mrExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, + sLocation + ":" + aStrMacro); + } + else + { + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, aStrMacro ); + } + + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true); + } + } + else if( aClickEventType == gsScript ) + { + if( nFound & Found::MACRO ) + { + SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true); + + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) ); + OUString aEventQName( + mrExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DOM, "click" ) ); + mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStrMacro ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, "simple" ); + + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true); + } + } +} + +/** #i68101# export shape Title and Description */ +void XMLShapeExport::ImpExportDescription( const uno::Reference< drawing::XShape >& xShape ) +{ + try + { + OUString aTitle; + OUString aDescription; + + uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW ); + xProps->getPropertyValue("Title") >>= aTitle; + xProps->getPropertyValue("Description") >>= aDescription; + + if(!aTitle.isEmpty()) + { + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true, false); + mrExport.Characters( aTitle ); + } + + if(!aDescription.isEmpty()) + { + SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_DESC, true, false ); + mrExport.Characters( aDescription ); + } + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting Title and/or Description for shape" ); + } +} + +void XMLShapeExport::ImpExportGroupShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY); + if(!(xShapes.is() && xShapes->getCount())) + return; + + // write group shape + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aPGR(mrExport, XML_NAMESPACE_DRAW, XML_G, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + + // #89764# if export of position is suppressed for group shape, + // positions of contained objects should be written relative to + // the upper left edge of the group. + awt::Point aUpperLeft; + + if(!(nFeatures & XMLShapeExportFlags::POSITION)) + { + nFeatures |= XMLShapeExportFlags::POSITION; + aUpperLeft = xShape->getPosition(); + pRefPoint = &aUpperLeft; + } + + // write members + exportShapes( xShapes, nFeatures, pRefPoint ); +} + +void XMLShapeExport::ImpExportTextBoxShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // presentation attribute (if presentation) + bool bIsPresShape(false); + bool bIsEmptyPresObj(false); + OUString aStr; + + switch(eShapeType) + { + case XmlShapeTypePresSubtitleShape: + { + aStr = GetXMLToken(XML_SUBTITLE); + bIsPresShape = true; + break; + } + case XmlShapeTypePresTitleTextShape: + { + aStr = GetXMLToken(XML_TITLE); + bIsPresShape = true; + break; + } + case XmlShapeTypePresOutlinerShape: + { + aStr = GetXMLToken(XML_PRESENTATION_OUTLINE); + bIsPresShape = true; + break; + } + case XmlShapeTypePresNotesShape: + { + aStr = GetXMLToken(XML_NOTES); + bIsPresShape = true; + break; + } + case XmlShapeTypePresHeaderShape: + { + aStr = GetXMLToken(XML_HEADER); + bIsPresShape = true; + break; + } + case XmlShapeTypePresFooterShape: + { + aStr = GetXMLToken(XML_FOOTER); + bIsPresShape = true; + break; + } + case XmlShapeTypePresSlideNumberShape: + { + aStr = GetXMLToken(XML_PAGE_NUMBER); + bIsPresShape = true; + break; + } + case XmlShapeTypePresDateTimeShape: + { + aStr = GetXMLToken(XML_DATE_TIME); + bIsPresShape = true; + break; + } + default: + break; + } + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + if(bIsPresShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, aStr ); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // evtl. corner radius? + sal_Int32 nCornerRadius(0); + xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius; + if(nCornerRadius) + { + OUStringBuffer sStringBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nCornerRadius); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear()); + } + + { + // write text-box + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_TEXT_BOX, true, true); + if(!bIsEmptyPresObj) + ImpExportText( xShape ); + } + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + +} + +void XMLShapeExport::ImpExportRectangleShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + // evtl. corner radius? + sal_Int32 nCornerRadius(0); + xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius; + if(nCornerRadius) + { + OUStringBuffer sStringBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nCornerRadius); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear()); + } + + // write rectangle + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_RECT, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); +} + +void XMLShapeExport::ImpExportLineShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + OUString aStr; + OUStringBuffer sStringBuffer; + awt::Point aStart(0,0); + awt::Point aEnd(1,1); + + // #85920# use 'Geometry' to get the points of the line + // since this slot take anchor pos into account. + + // get matrix + ::basegfx::B2DHomMatrix aMatrix; + ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet); + + // decompose and correct about pRefPoint + ::basegfx::B2DTuple aTRScale; + double fTRShear(0.0); + double fTRRotate(0.0); + ::basegfx::B2DTuple aTRTranslate; + ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint); + + // create base position + awt::Point aBasePosition(FRound(aTRTranslate.getX()), FRound(aTRTranslate.getY())); + + if (xPropSet->getPropertySetInfo()->hasPropertyByName("Geometry")) + { + // get the two points + uno::Any aAny(xPropSet->getPropertyValue("Geometry")); + if (auto pSourcePolyPolygon + = o3tl::tryAccess(aAny)) + { + if (pSourcePolyPolygon->getLength() > 0) + { + const drawing::PointSequence& rInnerSequence = (*pSourcePolyPolygon)[0]; + if (rInnerSequence.hasElements()) + { + const awt::Point& rPoint = rInnerSequence[0]; + aStart = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y); + } + if (rInnerSequence.getLength() > 1) + { + const awt::Point& rPoint = rInnerSequence[1]; + aEnd = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y); + } + } + } + } + + if( nFeatures & XMLShapeExportFlags::X ) + { + // svg: x1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr); + } + else + { + aEnd.X -= aStart.X; + } + + if( nFeatures & XMLShapeExportFlags::Y ) + { + // svg: y1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr); + } + else + { + aEnd.Y -= aStart.Y; + } + + // svg: x2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aEnd.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr); + + // svg: y2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aEnd.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr); + + // write line + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_LINE, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); + +} + +void XMLShapeExport::ImpExportEllipseShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // get size to decide between Circle and Ellipse + awt::Size aSize = xShape->getSize(); + sal_Int32 nRx((aSize.Width + 1) / 2); + sal_Int32 nRy((aSize.Height + 1) / 2); + bool bCircle(nRx == nRy); + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + drawing::CircleKind eKind = drawing::CircleKind_FULL; + xPropSet->getPropertyValue("CircleKind") >>= eKind; + if( eKind != drawing::CircleKind_FULL ) + { + OUStringBuffer sStringBuffer; + sal_Int32 nStartAngle = 0; + sal_Int32 nEndAngle = 0; + xPropSet->getPropertyValue("CircleStartAngle") >>= nStartAngle; + xPropSet->getPropertyValue("CircleEndAngle") >>= nEndAngle; + + const double dStartAngle = nStartAngle / 100.0; + const double dEndAngle = nEndAngle / 100.0; + + // export circle kind + SvXMLUnitConverter::convertEnum( sStringBuffer, eKind, aXML_CircleKind_EnumMap ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_KIND, sStringBuffer.makeStringAndClear() ); + + // export start angle + ::sax::Converter::convertDouble( sStringBuffer, dStartAngle ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_ANGLE, sStringBuffer.makeStringAndClear() ); + + // export end angle + ::sax::Converter::convertDouble( sStringBuffer, dEndAngle ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_ANGLE, sStringBuffer.makeStringAndClear() ); + } + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + + // write ellipse or circle + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, + bCircle ? XML_CIRCLE : XML_ELLIPSE, + bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); + +} + +void XMLShapeExport::ImpExportPolygonShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + bool bBezier(eShapeType == XmlShapeTypeDrawClosedBezierShape + || eShapeType == XmlShapeTypeDrawOpenBezierShape); + + // get matrix + ::basegfx::B2DHomMatrix aMatrix; + ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet); + + // decompose and correct about pRefPoint + ::basegfx::B2DTuple aTRScale; + double fTRShear(0.0); + double fTRRotate(0.0); + ::basegfx::B2DTuple aTRTranslate; + ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint); + + // use features and write + ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures); + + // create and export ViewBox + awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY())); + SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + + // prepare name (with most used) + enum ::xmloff::token::XMLTokenEnum eName(XML_PATH); + + if(bBezier) + { + // get PolygonBezier + uno::Any aAny( xPropSet->getPropertyValue("Geometry") ); + auto pSourcePolyPolygon = o3tl::tryAccess(aAny); + if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength()) + { + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + *pSourcePolyPolygon)); + + // complex polygon shape, write as svg:d + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); + } + } + else + { + // get non-bezier polygon + uno::Any aAny( xPropSet->getPropertyValue("Geometry") ); + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*o3tl::doAccess(aAny))); + + if(!aPolyPolygon.areControlPointsUsed() && 1 == aPolyPolygon.count()) + { + // simple polygon shape, can be written as svg:points sequence + const basegfx::B2DPolygon& aPolygon(aPolyPolygon.getB2DPolygon(0)); + const OUString aPointString(basegfx::utils::exportToSvgPoints(aPolygon)); + + // write point array + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); + + // set name + eName = aPolygon.isClosed() ? XML_POLYGON : XML_POLYLINE; + } + else + { + // complex polygon shape, write as svg:d + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); + } + } + + // write object, but after attributes are added since this call will + // consume all of these added attributes and the destructor will close the + // scope. Also before text is added; this may add sub-scopes as needed + SvXMLElementExport aOBJ( + mrExport, + XML_NAMESPACE_DRAW, + eName, + bCreateNewline, + true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); + +} + +namespace +{ + +OUString getNameFromStreamURL(std::u16string_view rURL) +{ + static constexpr std::u16string_view sPackageURL(u"vnd.sun.star.Package:"); + + OUString sResult; + + if (o3tl::starts_with(rURL, sPackageURL)) + { + std::u16string_view sRequestedName = rURL.substr(sPackageURL.size()); + size_t nLastIndex = sRequestedName.rfind('/') + 1; + if ((nLastIndex > 0) && (nLastIndex < sRequestedName.size())) + sRequestedName = sRequestedName.substr(nLastIndex); + nLastIndex = sRequestedName.rfind('.'); + if (nLastIndex != std::u16string_view::npos) + sRequestedName = sRequestedName.substr(0, nLastIndex); + if (!sRequestedName.empty()) + sResult = sRequestedName; + } + + return sResult; +} + +} // end anonymous namespace + +void XMLShapeExport::ImpExportGraphicObjectShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + bool bIsEmptyPresObj = false; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + if(eShapeType == XmlShapeTypePresGraphicObjectShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_GRAPHIC) ); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + if (!bIsEmptyPresObj) + { + uno::Reference xGraphic; + OUString sOutMimeType; + + { + OUString aStreamURL; + xPropSet->getPropertyValue("GraphicStreamURL") >>= aStreamURL; + OUString sRequestedName = getNameFromStreamURL(aStreamURL); + + xPropSet->getPropertyValue("Graphic") >>= xGraphic; + + OUString sInternalURL; + + if (xGraphic.is()) + sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, sOutMimeType, sRequestedName); + + if (!sInternalURL.isEmpty()) + { + // apply possible changed stream URL to embedded image object + if (!sRequestedName.isEmpty()) + { + OUString newStreamURL = "vnd.sun.star.Package:"; + if (sInternalURL[0] == '#') + { + newStreamURL += sInternalURL.subView(1, sInternalURL.getLength() - 1); + } + else + { + newStreamURL += sInternalURL; + } + + if (newStreamURL != aStreamURL) + { + xPropSet->setPropertyValue("GraphicStreamURL", uno::Any(newStreamURL)); + } + } + + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + } + + { + if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + if (sOutMimeType.isEmpty()) + { + GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType); + } + if (!sOutMimeType.isEmpty()) + { // ODF 1.3 OFFICE-3943 + GetExport().AddAttribute( + SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", sOutMimeType); + } + } + + SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true); + + // optional office:binary-data + if (xGraphic.is()) + { + mrExport.AddEmbeddedXGraphicAsBase64(xGraphic); + } + if (!bIsEmptyPresObj) + ImpExportText(xShape); + } + + //Resolves: fdo#62461 put preferred image first above, followed by + //fallback here + const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get(); + if( !bIsEmptyPresObj && bAddReplacementImages) + { + uno::Reference xReplacementGraphic; + xPropSet->getPropertyValue("ReplacementGraphic") >>= xReplacementGraphic; + + // If there is no url, then the graphic is empty + if (xReplacementGraphic.is()) + { + OUString aMimeType; + const OUString aHref = mrExport.AddEmbeddedXGraphic(xReplacementGraphic, aMimeType); + + if (aMimeType.isEmpty()) + mrExport.GetGraphicMimeTypeFromStream(xReplacementGraphic, aMimeType); + + if (!aHref.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + + if (!aMimeType.isEmpty() && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { // ODF 1.3 OFFICE-3943 + mrExport.AddAttribute( + SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", aMimeType); + } + + SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true); + + // optional office:binary-data + mrExport.AddEmbeddedXGraphicAsBase64(xReplacementGraphic); + } + } + } + + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + + // image map + GetExport().GetImageMapExport().Export( xPropSet ); + ImpExportDescription( xShape ); // #i68101# + + // Signature Line, QR Code - needs to be after the images! + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + ImpExportSignatureLine(xShape); + ImpExportQRCode(xShape); + } +} + +void XMLShapeExport::ImpExportChartShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint, + SvXMLAttributeList* pAttrList ) +{ + ImpExportOLE2Shape( xShape, eShapeType, nFeatures, pRefPoint, pAttrList ); +} + +void XMLShapeExport::ImpExportControlShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + } + + uno::Reference< drawing::XControlShape > xControl( xShape, uno::UNO_QUERY ); + SAL_WARN_IF( !xControl.is(), "xmloff", "Control shape is not supporting XControlShape" ); + if( xControl.is() ) + { + uno::Reference< beans::XPropertySet > xControlModel( xControl->getControl(), uno::UNO_QUERY ); + SAL_WARN_IF( !xControlModel.is(), "xmloff", "Control shape has not XControlModel" ); + if( xControlModel.is() ) + { + OUString sControlId = mrExport.GetFormExport()->getControlId( xControlModel ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONTROL, sControlId ); + } + } + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONTROL, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# +} + +void XMLShapeExport::ImpExportConnectorShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */) +{ + uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY ); + + OUString aStr; + OUStringBuffer sStringBuffer; + + // export connection kind + drawing::ConnectorType eType = drawing::ConnectorType_STANDARD; + uno::Any aAny = xProps->getPropertyValue("EdgeKind"); + aAny >>= eType; + + if( eType != drawing::ConnectorType_STANDARD ) + { + SvXMLUnitConverter::convertEnum( sStringBuffer, eType, aXML_ConnectionKind_EnumMap ); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TYPE, aStr); + } + + // export line skew + sal_Int32 nDelta1 = 0, nDelta2 = 0, nDelta3 = 0; + + aAny = xProps->getPropertyValue("EdgeLine1Delta"); + aAny >>= nDelta1; + aAny = xProps->getPropertyValue("EdgeLine2Delta"); + aAny >>= nDelta2; + aAny = xProps->getPropertyValue("EdgeLine3Delta"); + aAny >>= nDelta3; + + if( nDelta1 != 0 || nDelta2 != 0 || nDelta3 != 0 ) + { + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nDelta1); + if( nDelta2 != 0 || nDelta3 != 0 ) + { + sStringBuffer.append( ' ' ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nDelta2); + if( nDelta3 != 0 ) + { + sStringBuffer.append( ' ' ); + mrExport.GetMM100UnitConverter().convertMeasureToXML( + sStringBuffer, nDelta3); + } + } + + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LINE_SKEW, aStr); + } + + // export start and end point + awt::Point aStart(0,0); + awt::Point aEnd(1,1); + + /* Get and + , if they exist and if the document is exported + into the OpenOffice.org file format. + These properties only exist at service css::text::Shape - the + Writer UNO service for shapes. + This code is needed, because the positioning attributes in the + OpenOffice.org file format are given in horizontal left-to-right layout + regardless the layout direction the shape is in. In the OASIS Open Office + file format the positioning attributes are correctly given in the layout + direction the shape is in. Thus, this code provides the conversion from + the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#) + */ + if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") && + xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") ) + { + xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart; + xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd; + } + else + { + xProps->getPropertyValue("StartPosition") >>= aStart; + xProps->getPropertyValue("EndPosition") >>= aEnd; + } + + if( pRefPoint ) + { + aStart.X -= pRefPoint->X; + aStart.Y -= pRefPoint->Y; + aEnd.X -= pRefPoint->X; + aEnd.Y -= pRefPoint->Y; + } + + if( nFeatures & XMLShapeExportFlags::X ) + { + // svg: x1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr); + } + else + { + aEnd.X -= aStart.X; + } + + if( nFeatures & XMLShapeExportFlags::Y ) + { + // svg: y1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr); + } + else + { + aEnd.Y -= aStart.Y; + } + + // svg: x2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr); + + // svg: y2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr); + + // #i39320# + uno::Reference< uno::XInterface > xRefS; + uno::Reference< uno::XInterface > xRefE; + + // export start connection + xProps->getPropertyValue("StartShape") >>= xRefS; + if( xRefS.is() ) + { + const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefS ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_SHAPE, rShapeId); + + aAny = xProps->getPropertyValue("StartGluePointIndex"); + sal_Int32 nGluePointId = 0; + if( aAny >>= nGluePointId ) + { + if( nGluePointId != -1 ) + { + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_GLUE_POINT, OUString::number( nGluePointId )); + } + } + } + + // export end connection + xProps->getPropertyValue("EndShape") >>= xRefE; + if( xRefE.is() ) + { + const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefE ); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_SHAPE, rShapeId); + + aAny = xProps->getPropertyValue("EndGluePointIndex"); + sal_Int32 nGluePointId = 0; + if( aAny >>= nGluePointId ) + { + if( nGluePointId != -1 ) + { + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_GLUE_POINT, OUString::number( nGluePointId )); + } + } + } + + // get PolygonBezier + aAny = xProps->getPropertyValue("PolyPolygonBezier"); + auto pSourcePolyPolygon = o3tl::tryAccess(aAny); + if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength()) + { + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + *pSourcePolyPolygon)); + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); + } + + // get matrix + ::basegfx::B2DHomMatrix aMatrix; + ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xProps); + + // decompose and correct about pRefPoint + ::basegfx::B2DTuple aTRScale; + double fTRShear(0.0); + double fTRRotate(0.0); + ::basegfx::B2DTuple aTRTranslate; + ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, + fTRRotate, aTRTranslate, pRefPoint); + + // fdo#49678: create and export ViewBox + awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY())); + SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + + // write connector shape. Add Export later. + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONNECTOR, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); +} + +void XMLShapeExport::ImpExportMeasureShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point const * pRefPoint /* = NULL */) +{ + uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY ); + + OUString aStr; + OUStringBuffer sStringBuffer; + + // export start and end point + awt::Point aStart(0,0); + awt::Point aEnd(1,1); + + /* Get and + , if they exist and if the document is exported + into the OpenOffice.org file format. + These properties only exist at service css::text::Shape - the + Writer UNO service for shapes. + This code is needed, because the positioning attributes in the + OpenOffice.org file format are given in horizontal left-to-right layout + regardless the layout direction the shape is in. In the OASIS Open Office + file format the positioning attributes are correctly given in the layout + direction the shape is in. Thus, this code provides the conversion from + the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#) + */ + if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") && + xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") ) + { + xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart; + xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd; + } + else + { + xProps->getPropertyValue("StartPosition") >>= aStart; + xProps->getPropertyValue("EndPosition") >>= aEnd; + } + + if( pRefPoint ) + { + aStart.X -= pRefPoint->X; + aStart.Y -= pRefPoint->Y; + aEnd.X -= pRefPoint->X; + aEnd.Y -= pRefPoint->Y; + } + + if( nFeatures & XMLShapeExportFlags::X ) + { + // svg: x1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr); + } + else + { + aEnd.X -= aStart.X; + } + + if( nFeatures & XMLShapeExportFlags::Y ) + { + // svg: y1 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + aStart.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr); + } + else + { + aEnd.Y -= aStart.Y; + } + + // svg: x2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr); + + // svg: y2 + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr); + + // write measure shape + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_MEASURE, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + + uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY ); + if( xText.is() ) + mrExport.GetTextParagraphExport()->exportText( xText ); +} + +void XMLShapeExport::ImpExportOLE2Shape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */, + SvXMLAttributeList* pAttrList /* = NULL */ ) +{ + uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY); + + SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "ole shape is not implementing needed interfaces"); + if(!(xPropSet.is() && xNamed.is())) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bIsEmptyPresObj = false; + + // presentation settings + if(eShapeType == XmlShapeTypePresOLE2Shape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) ); + else if(eShapeType == XmlShapeTypePresChartShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_CHART) ); + else if(eShapeType == XmlShapeTypePresSheetShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) ); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED); + OUString sPersistName; + SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + if (!bIsEmptyPresObj) + { + if (pAttrList) + { + mrExport.AddAttributeList(pAttrList); + } + + OUString sClassId; + OUString sURL; + bool bInternal = false; + xPropSet->getPropertyValue("IsInternal") >>= bInternal; + + { + + if ( bInternal ) + { + // OOo internal links have no storage persistence, URL is stored in the XML file + // the result LinkURL is empty in case the object is not a link + xPropSet->getPropertyValue("LinkURL") >>= sURL; + } + + xPropSet->getPropertyValue("PersistName") >>= sPersistName; + if ( sURL.isEmpty() ) + { + if( !sPersistName.isEmpty() ) + { + sURL = "vnd.sun.star.EmbeddedObject:" + sPersistName; + } + } + + if( !bInternal ) + xPropSet->getPropertyValue("CLSID") >>= sClassId; + + if( !sClassId.isEmpty() ) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CLASS_ID, sClassId ); + + if(!bExportEmbedded) + { + // xlink:href + if( !sURL.isEmpty() ) + { + // #96717# in theorie, if we don't have a URL we shouldn't even + // export this OLE shape. But practically it's too risky right now + // to change this so we better dispose this on load + sURL = mrExport.AddEmbeddedObject( sURL ); + + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + else + { + // tdf#153179 Export the preview graphic of the object if the object is missing. + uno::Reference xGraphic; + xPropSet->getPropertyValue("Graphic") >>= xGraphic; + + if (xGraphic.is()) + { + OUString aMimeType; + const OUString aHref = mrExport.AddEmbeddedXGraphic(xGraphic, aMimeType); + + if (aMimeType.isEmpty()) + mrExport.GetGraphicMimeTypeFromStream(xGraphic, aMimeType); + + if (!aHref.isEmpty()) + { + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + + if (!aMimeType.isEmpty() + && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { // ODF 1.3 OFFICE-3943 + mrExport.AddAttribute(SvtSaveOptions::ODFSVER_013 + <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", aMimeType); + } + + SvXMLElementExport aImageElem(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, + true); + + // optional office:binary-data + mrExport.AddEmbeddedXGraphicAsBase64(xGraphic); + + ImpExportEvents(xShape); + ImpExportGluePoints(xShape); + ImpExportDescription(xShape); + + return; + } + } + } + } + + enum XMLTokenEnum eElem = sClassId.isEmpty() ? XML_OBJECT : XML_OBJECT_OLE ; + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, eElem, true, true ); + + // tdf#112547 export text as child of draw:object, where import expects it + if (!bIsEmptyPresObj && supportsText(eShapeType)) + { + // #i118485# Add text export, the draw OLE shape allows text now + ImpExportText( xShape, TextPNS::EXTENSION ); + } + + if(bExportEmbedded && !bIsEmptyPresObj) + { + if(bInternal) + { + // embedded XML + uno::Reference< lang::XComponent > xComp; + xPropSet->getPropertyValue("Model") >>= xComp; + SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" ); + mrExport.ExportEmbeddedOwnObject( xComp ); + } + else + { + // embed as Base64 + // this is an alien object ( currently MSOLE is the only supported type of such objects ) + // in case it is not an OASIS format the object should be asked to store replacement image if possible + + OUString sURLRequest( sURL ); + if ( !( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) ) + sURLRequest += "?oasis=false"; + mrExport.AddEmbeddedObjectAsBase64( sURLRequest ); + } + } + } + if( !bIsEmptyPresObj ) + { + OUString sURL = XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE + sPersistName; + if( !bExportEmbedded ) + { + sURL = GetExport().AddEmbeddedObject( sURL ); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, + XML_IMAGE, false, true ); + + if( bExportEmbedded ) + GetExport().AddEmbeddedObjectAsBase64( sURL ); + } + + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportDescription( xShape ); // #i68101# + +} + +void XMLShapeExport::ImpExportPageShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // #86163# Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + // export page number used for this page + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + static const OUStringLiteral aPageNumberStr(u"PageNumber"); + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr)) + { + sal_Int32 nPageNumber = 0; + xPropSet->getPropertyValue(aPageNumberStr) >>= nPageNumber; + if( nPageNumber ) + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_PAGE_NUMBER, OUString::number(nPageNumber)); + } + + // a presentation page shape, normally used on notes pages only. If + // it is used not as presentation shape, it may have been created with + // copy-paste exchange between draw and impress (this IS possible...) + if(eShapeType == XmlShapeTypePresPageShape) + { + mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, + XML_PAGE); + } + + // write Page shape + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, bCreateNewline, true); +} + +void XMLShapeExport::ImpExportCaptionShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + // evtl. corner radius? + sal_Int32 nCornerRadius(0); + xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius; + if(nCornerRadius) + { + OUStringBuffer sStringBuffer; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nCornerRadius); + mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear()); + } + + awt::Point aCaptionPoint; + xPropSet->getPropertyValue("CaptionPoint") >>= aCaptionPoint; + + mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer, + aCaptionPoint.X); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_X, msBuffer.makeStringAndClear() ); + mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer, + aCaptionPoint.Y); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_Y, msBuffer.makeStringAndClear() ); + + // write Caption shape. Add export later. + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + bool bAnnotation( (nFeatures & XMLShapeExportFlags::ANNOTATION) == XMLShapeExportFlags::ANNOTATION ); + + SvXMLElementExport aObj( mrExport, + (bAnnotation ? XML_NAMESPACE_OFFICE + : XML_NAMESPACE_DRAW), + (bAnnotation ? XML_ANNOTATION : XML_CAPTION), + bCreateNewline, true ); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + if( bAnnotation ) + mrExport.exportAnnotationMeta( xShape ); + ImpExportText( xShape ); + +} + +void XMLShapeExport::ImpExportFrameShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // export frame url + OUString aStr; + xPropSet->getPropertyValue("FrameURL") >>= aStr; + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + + // export name + xPropSet->getPropertyValue("FrameName") >>= aStr; + if( !aStr.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr ); + + // write floating frame + { + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, true, true); + } + + ImpExportDescription(xShape); +} + +void XMLShapeExport::ImpExportAppletShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // export frame url + OUString aStr; + xPropSet->getPropertyValue("AppletCodeBase") >>= aStr; + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + + // export draw:applet-name + xPropSet->getPropertyValue("AppletName") >>= aStr; + if( !aStr.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr ); + + // export draw:code + xPropSet->getPropertyValue("AppletCode") >>= aStr; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr ); + + // export draw:may-script + bool bIsScript = false; + xPropSet->getPropertyValue("AppletIsScript") >>= bIsScript; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bIsScript ? XML_TRUE : XML_FALSE ); + + { + // write applet + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_APPLET, true, true); + + // export parameters + uno::Sequence< beans::PropertyValue > aCommands; + xPropSet->getPropertyValue("AppletCommands") >>= aCommands; + for( const auto& rCommand : std::as_const(aCommands) ) + { + rCommand.Value >>= aStr; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr ); + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + } + } + + ImpExportDescription(xShape); +} + +void XMLShapeExport::ImpExportPluginShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // export plugin url + OUString aStr; + xPropSet->getPropertyValue("PluginURL") >>= aStr; + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + + // export mime-type + xPropSet->getPropertyValue("PluginMimeType") >>= aStr; + if(!aStr.isEmpty()) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr ); + + { + // write plugin + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, true, true); + + // export parameters + uno::Sequence< beans::PropertyValue > aCommands; + xPropSet->getPropertyValue("PluginCommands") >>= aCommands; + for( const auto& rCommand : std::as_const(aCommands) ) + { + rCommand.Value >>= aStr; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr ); + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + } + } + + ImpExportDescription(xShape); +} + +static void lcl_CopyStream( + uno::Reference const& xInStream, + uno::Reference const& xTarget, + OUString const& rPath, const OUString& rMimeType) +{ + ::comphelper::LifecycleProxy proxy; + uno::Reference const xStream( + ::comphelper::OStorageHelper::GetStreamAtPackageURL(xTarget, rPath, + embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, proxy)); + uno::Reference const xOutStream( + (xStream.is()) ? xStream->getOutputStream() : nullptr); + if (!xOutStream.is()) + { + SAL_WARN("xmloff", "no output stream"); + throw uno::Exception("no output stream",nullptr); + } + uno::Reference< beans::XPropertySet > const xStreamProps(xStream, + uno::UNO_QUERY); + if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage + xStreamProps->setPropertyValue("MediaType", + uno::Any(rMimeType)); + xStreamProps->setPropertyValue( // turn off compression + "Compressed", + uno::Any(false)); + } + ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream); + xOutStream->closeOutput(); + proxy.commitStorages(); +} + +static OUString +lcl_StoreMediaAndGetURL(SvXMLExport & rExport, + uno::Reference const& xPropSet, + OUString const& rURL, const OUString& rMimeType) +{ + OUString urlPath; + if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &urlPath)) + { + try // video is embedded + { + uno::Reference const xTarget( + rExport.GetTargetStorage(), uno::UNO_SET_THROW); + uno::Reference xInStream; + xPropSet->getPropertyValue("PrivateStream") + >>= xInStream; + + if (!xInStream.is()) + { + SAL_WARN("xmloff", "no input stream"); + return OUString(); + } + + lcl_CopyStream(xInStream, xTarget, rURL, rMimeType); + + return urlPath; + } + catch (uno::Exception const&) + { + TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media"); + } + return OUString(); + } + else + { + return rExport.GetRelativeReference(rURL); // linked + } +} + +void XMLShapeExport::ImpExportMediaShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + if(eShapeType == XmlShapeTypePresMediaShape) + { + (void)ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) ); + } + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, + XML_FRAME, bCreateNewline, true ); + + // export media url + OUString aMediaURL; + xPropSet->getPropertyValue("MediaURL") >>= aMediaURL; + OUString sMimeType; + xPropSet->getPropertyValue("MediaMimeType") >>= sMimeType; + + OUString const persistentURL = + lcl_StoreMediaAndGetURL(GetExport(), xPropSet, aMediaURL, sMimeType); + + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, persistentURL ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + + // export mime-type + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType ); + + // write plugin + auto pPluginOBJ = std::make_unique(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true); + + // export parameters + const OUString aFalseStr( "false" ), aTrueStr( "true" ); + + bool bLoop = false; + static const OUStringLiteral aLoopStr( u"Loop" ); + xPropSet->getPropertyValue( aLoopStr ) >>= bLoop; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aLoopStr ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bLoop ? aTrueStr : aFalseStr ); + delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + + bool bMute = false; + static const OUStringLiteral aMuteStr( u"Mute" ); + xPropSet->getPropertyValue( aMuteStr ) >>= bMute; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aMuteStr ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bMute ? aTrueStr : aFalseStr ); + delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + + sal_Int16 nVolumeDB = 0; + xPropSet->getPropertyValue("VolumeDB") >>= nVolumeDB; + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, "VolumeDB" ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, OUString::number( nVolumeDB ) ); + delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + + media::ZoomLevel eZoom; + OUString aZoomValue; + xPropSet->getPropertyValue("Zoom") >>= eZoom; + switch( eZoom ) + { + case media::ZoomLevel_ZOOM_1_TO_4 : aZoomValue = "25%"; break; + case media::ZoomLevel_ZOOM_1_TO_2 : aZoomValue = "50%"; break; + case media::ZoomLevel_ORIGINAL : aZoomValue = "100%"; break; + case media::ZoomLevel_ZOOM_2_TO_1 : aZoomValue = "200%"; break; + case media::ZoomLevel_ZOOM_4_TO_1 : aZoomValue = "400%"; break; + case media::ZoomLevel_FIT_TO_WINDOW: aZoomValue = "fit"; break; + case media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT: aZoomValue = "fixedfit"; break; + case media::ZoomLevel_FULLSCREEN : aZoomValue = "fullscreen"; break; + + default: + break; + } + + if( !aZoomValue.isEmpty() ) + { + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, "Zoom" ); + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aZoomValue ); + delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true ); + } + + pPluginOBJ.reset(); + + uno::Reference xGraphic; + xPropSet->getPropertyValue("Graphic") >>= xGraphic; + Graphic aGraphic(xGraphic); + if (!aGraphic.IsNone()) + { + // The media has a preview, export it. + uno::Reference xPictureStorage; + uno::Reference xStorage; + uno::Reference xPictureStream; + OUString sPictureName; + xStorage.set(GetExport().GetTargetStorage(), uno::UNO_SET_THROW); + xPictureStorage.set( + xStorage->openStorageElement("Pictures", embed::ElementModes::READWRITE), + uno::UNO_SET_THROW); + sal_Int32 nIndex = 0; + while (true) + { + sPictureName = "MediaPreview" + OUString::number(++nIndex) + ".png"; + if (!xPictureStorage->hasByName(sPictureName)) + { + break; + } + } + + xPictureStream.set( + xPictureStorage->openStreamElement(sPictureName, ::embed::ElementModes::READWRITE), + uno::UNO_SET_THROW); + + uno::Reference xContext = GetExport().getComponentContext(); + uno::Reference xProvider( + graphic::GraphicProvider::create(xContext)); + uno::Sequence aArgs{ + comphelper::makePropertyValue("MimeType", OUString("image/png")), + comphelper::makePropertyValue("OutputStream", xPictureStream->getOutputStream()) + }; + xProvider->storeGraphic(xGraphic, aArgs); + if (xPictureStorage.is()) + { + uno::Reference xTrans(xPictureStorage, uno::UNO_QUERY); + if (xTrans.is()) + xTrans->commit(); + } + OUString sURL = "Pictures/" + sPictureName; + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + SvXMLElementExport aImageElem(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, false, true); + } + + ImpExportDescription(xShape); +} + +void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint) +{ + uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY); + if(!(xShapes.is() && xShapes->getCount())) + return; + + uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY ); + SAL_WARN_IF( !xPropSet.is(), "xmloff", "XMLShapeExport::ImpExport3DSceneShape can't export a scene without a propertyset" ); + if( !xPropSet.is() ) + return; + + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + // 3d attributes + export3DSceneAttributes( xPropSet ); + + // write 3DScene shape + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DR3D, XML_SCENE, bCreateNewline, true); + + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + + // write 3DSceneLights + export3DLamps( xPropSet ); + + // #89764# if export of position is suppressed for group shape, + // positions of contained objects should be written relative to + // the upper left edge of the group. + awt::Point aUpperLeft; + + if(!(nFeatures & XMLShapeExportFlags::POSITION)) + { + nFeatures |= XMLShapeExportFlags::POSITION; + aUpperLeft = xShape->getPosition(); + pRefPoint = &aUpperLeft; + } + + // write members + exportShapes( xShapes, nFeatures, pRefPoint ); +} + +void XMLShapeExport::ImpExport3DShape( + const uno::Reference< drawing::XShape >& xShape, + XmlShapeType eShapeType) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + OUString aStr; + OUStringBuffer sStringBuffer; + + // transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix") + uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix"); + drawing::HomogenMatrix aHomMat; + aAny >>= aHomMat; + SdXMLImExTransform3D aTransform; + aTransform.AddHomogenMatrix(aHomMat); + if(aTransform.NeedsAction()) + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter())); + + switch(eShapeType) + { + case XmlShapeTypeDraw3DCubeObject: + { + // minEdge + aAny = xPropSet->getPropertyValue("D3DPosition"); + drawing::Position3D aPosition3D; + aAny >>= aPosition3D; + ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ); + + // maxEdge + aAny = xPropSet->getPropertyValue("D3DSize"); + drawing::Direction3D aDirection3D; + aAny >>= aDirection3D; + ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ); + + // transform maxEdge from distance to pos + aDir3D = aPos3D + aDir3D; + + // write minEdge + if(aPos3D != ::basegfx::B3DVector(-2500.0, -2500.0, -2500.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MIN_EDGE, aStr); + } + + // write maxEdge + if(aDir3D != ::basegfx::B3DVector(2500.0, 2500.0, 2500.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MAX_EDGE, aStr); + } + + // write 3DCube shape + // #i123542# Do this *after* the attributes are added, else these will be lost since opening + // the scope will clear the global attribute list at the exporter + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_CUBE, true, true); + + break; + } + case XmlShapeTypeDraw3DSphereObject: + { + // Center + aAny = xPropSet->getPropertyValue("D3DPosition"); + drawing::Position3D aPosition3D; + aAny >>= aPosition3D; + ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ); + + // Size + aAny = xPropSet->getPropertyValue("D3DSize"); + drawing::Direction3D aDirection3D; + aAny >>= aDirection3D; + ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ); + + // write Center + if(aPos3D != ::basegfx::B3DVector(0.0, 0.0, 0.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_CENTER, aStr); + } + + // write Size + if(aDir3D != ::basegfx::B3DVector(5000.0, 5000.0, 5000.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SIZE, aStr); + } + + // write 3DSphere shape + // #i123542# Do this *after* the attributes are added, else these will be lost since opening + // the scope will clear the global attribute list at the exporter + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_SPHERE, true, true); + + break; + } + case XmlShapeTypeDraw3DLatheObject: + case XmlShapeTypeDraw3DExtrudeObject: + { + // write special 3DLathe/3DExtrude attributes, get 3D tools::PolyPolygon as drawing::PolyPolygonShape3D + aAny = xPropSet->getPropertyValue("D3DPolyPolygon3D"); + drawing::PolyPolygonShape3D aUnoPolyPolygon3D; + aAny >>= aUnoPolyPolygon3D; + + // convert to 3D PolyPolygon + const basegfx::B3DPolyPolygon aPolyPolygon3D( + basegfx::utils::UnoPolyPolygonShape3DToB3DPolyPolygon( + aUnoPolyPolygon3D)); + + // convert to 2D tools::PolyPolygon using identity 3D transformation (just grep X and Y) + const basegfx::B3DHomMatrix aB3DHomMatrixFor2DConversion; + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon( + aPolyPolygon3D, + aB3DHomMatrixFor2DConversion)); + + // get 2D range of it + const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange()); + + // export ViewBox + SdXMLImExViewBox aViewBox( + aPolyPolygonRange.getMinX(), + aPolyPolygonRange.getMinY(), + aPolyPolygonRange.getWidth(), + aPolyPolygonRange.getHeight()); + + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + + // prepare svg:d string + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers TTTT: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); + + if(eShapeType == XmlShapeTypeDraw3DLatheObject) + { + // write 3DLathe shape + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_ROTATE, true, true); + } + else + { + // write 3DExtrude shape + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_EXTRUDE, true, true); + } + break; + } + default: + break; + } +} + +/** helper for chart that adds all attributes of a 3d scene element to the export */ +void XMLShapeExport::export3DSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet ) +{ + OUString aStr; + OUStringBuffer sStringBuffer; + + // world transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix") + uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix"); + drawing::HomogenMatrix aHomMat; + aAny >>= aHomMat; + SdXMLImExTransform3D aTransform; + aTransform.AddHomogenMatrix(aHomMat); + if(aTransform.NeedsAction()) + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter())); + + // VRP, VPN, VUP + aAny = xPropSet->getPropertyValue("D3DCameraGeometry"); + drawing::CameraGeometry aCamGeo; + aAny >>= aCamGeo; + + ::basegfx::B3DVector aVRP(aCamGeo.vrp.PositionX, aCamGeo.vrp.PositionY, aCamGeo.vrp.PositionZ); + if(aVRP != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVRP); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VRP, aStr); + } + + ::basegfx::B3DVector aVPN(aCamGeo.vpn.DirectionX, aCamGeo.vpn.DirectionY, aCamGeo.vpn.DirectionZ); + if(aVPN != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVPN); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VPN, aStr); + } + + ::basegfx::B3DVector aVUP(aCamGeo.vup.DirectionX, aCamGeo.vup.DirectionY, aCamGeo.vup.DirectionZ); + if(aVUP != ::basegfx::B3DVector(0.0, 1.0, 0.0)) // write only when not default + { + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVUP); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VUP, aStr); + } + + // projection "D3DScenePerspective" drawing::ProjectionMode + aAny = xPropSet->getPropertyValue("D3DScenePerspective"); + drawing::ProjectionMode aPrjMode; + aAny >>= aPrjMode; + if(aPrjMode == drawing::ProjectionMode_PARALLEL) + aStr = GetXMLToken(XML_PARALLEL); + else + aStr = GetXMLToken(XML_PERSPECTIVE); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_PROJECTION, aStr); + + // distance + aAny = xPropSet->getPropertyValue("D3DSceneDistance"); + sal_Int32 nDistance = 0; + aAny >>= nDistance; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nDistance); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DISTANCE, aStr); + + // focalLength + aAny = xPropSet->getPropertyValue("D3DSceneFocalLength"); + sal_Int32 nFocalLength = 0; + aAny >>= nFocalLength; + mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, + nFocalLength); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_FOCAL_LENGTH, aStr); + + // shadowSlant + aAny = xPropSet->getPropertyValue("D3DSceneShadowSlant"); + sal_Int16 nShadowSlant = 0; + aAny >>= nShadowSlant; + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADOW_SLANT, OUString::number(static_cast(nShadowSlant))); + + // shadeMode + aAny = xPropSet->getPropertyValue("D3DSceneShadeMode"); + drawing::ShadeMode aShadeMode; + if(aAny >>= aShadeMode) + { + if(aShadeMode == drawing::ShadeMode_FLAT) + aStr = GetXMLToken(XML_FLAT); + else if(aShadeMode == drawing::ShadeMode_PHONG) + aStr = GetXMLToken(XML_PHONG); + else if(aShadeMode == drawing::ShadeMode_SMOOTH) + aStr = GetXMLToken(XML_GOURAUD); + else + aStr = GetXMLToken(XML_DRAFT); + } + else + { + // ShadeMode enum not there, write default + aStr = GetXMLToken(XML_GOURAUD); + } + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr); + + // ambientColor + aAny = xPropSet->getPropertyValue("D3DSceneAmbientColor"); + sal_Int32 nAmbientColor = 0; + aAny >>= nAmbientColor; + ::sax::Converter::convertColor(sStringBuffer, nAmbientColor); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, aStr); + + // lightingMode + aAny = xPropSet->getPropertyValue("D3DSceneTwoSidedLighting"); + bool bTwoSidedLighting = false; + aAny >>= bTwoSidedLighting; + ::sax::Converter::convertBool(sStringBuffer, bTwoSidedLighting); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, aStr); +} + +/** helper for chart that exports all lamps from the propertyset */ +void XMLShapeExport::export3DLamps( const css::uno::Reference< css::beans::XPropertySet >& xPropSet ) +{ + // write lamps 1..8 as content + OUString aStr; + OUStringBuffer sStringBuffer; + + static const OUStringLiteral aColorPropName(u"D3DSceneLightColor"); + static const OUStringLiteral aDirectionPropName(u"D3DSceneLightDirection"); + static const OUStringLiteral aLightOnPropName(u"D3DSceneLightOn"); + + ::basegfx::B3DVector aLightDirection; + drawing::Direction3D aLightDir; + bool bLightOnOff = false; + for(sal_Int32 nLamp = 1; nLamp <= 8; nLamp++) + { + OUString aIndexStr = OUString::number( nLamp ); + + // lightcolor + OUString aPropName = aColorPropName + aIndexStr; + sal_Int32 nLightColor = 0; + xPropSet->getPropertyValue( aPropName ) >>= nLightColor; + ::sax::Converter::convertColor(sStringBuffer, nLightColor); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, aStr); + + // lightdirection + aPropName = aDirectionPropName + aIndexStr; + xPropSet->getPropertyValue(aPropName) >>= aLightDir; + aLightDirection = ::basegfx::B3DVector(aLightDir.DirectionX, aLightDir.DirectionY, aLightDir.DirectionZ); + SvXMLUnitConverter::convertB3DVector(sStringBuffer, aLightDirection); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIRECTION, aStr); + + // lighton + aPropName = aLightOnPropName + aIndexStr; + xPropSet->getPropertyValue(aPropName) >>= bLightOnOff; + ::sax::Converter::convertBool(sStringBuffer, bLightOnOff); + aStr = sStringBuffer.makeStringAndClear(); + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_ENABLED, aStr); + + // specular + mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SPECULAR, + nLamp == 1 ? XML_TRUE : XML_FALSE); + + // write light entry + SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_LIGHT, true, true); + } +} + + +// using namespace css::io; +// using namespace ::xmloff::EnhancedCustomShapeToken; + + +static void ExportParameter( OUStringBuffer& rStrBuffer, const css::drawing::EnhancedCustomShapeParameter& rParameter ) +{ + if ( !rStrBuffer.isEmpty() ) + rStrBuffer.append( ' ' ); + if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE ) + { + double fNumber = 0.0; + rParameter.Value >>= fNumber; + ::rtl::math::doubleToUStringBuffer( rStrBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true ); + } + else + { + sal_Int32 nValue = 0; + rParameter.Value >>= nValue; + + switch( rParameter.Type ) + { + case css::drawing::EnhancedCustomShapeParameterType::EQUATION : + { + rStrBuffer.append( "?f" + OUString::number( nValue ) ); + } + break; + + case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT : + { + rStrBuffer.append( '$' ); + rStrBuffer.append( nValue ); + } + break; + + case css::drawing::EnhancedCustomShapeParameterType::BOTTOM : + rStrBuffer.append( GetXMLToken( XML_BOTTOM ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::RIGHT : + rStrBuffer.append( GetXMLToken( XML_RIGHT ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::TOP : + rStrBuffer.append( GetXMLToken( XML_TOP ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::LEFT : + rStrBuffer.append( GetXMLToken( XML_LEFT ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::XSTRETCH : + rStrBuffer.append( GetXMLToken( XML_XSTRETCH ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::YSTRETCH : + rStrBuffer.append( GetXMLToken( XML_YSTRETCH ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::HASSTROKE : + rStrBuffer.append( GetXMLToken( XML_HASSTROKE ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::HASFILL : + rStrBuffer.append( GetXMLToken( XML_HASFILL ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::WIDTH : + rStrBuffer.append( GetXMLToken( XML_WIDTH ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::HEIGHT : + rStrBuffer.append( GetXMLToken( XML_HEIGHT ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::LOGWIDTH : + rStrBuffer.append( GetXMLToken( XML_LOGWIDTH ) ); break; + case css::drawing::EnhancedCustomShapeParameterType::LOGHEIGHT : + rStrBuffer.append( GetXMLToken( XML_LOGHEIGHT ) ); break; + default : + rStrBuffer.append( nValue ); + } + } +} + +static void ImpExportEquations( SvXMLExport& rExport, const uno::Sequence< OUString >& rEquations ) +{ + sal_Int32 i; + for ( i = 0; i < rEquations.getLength(); i++ ) + { + OUString aStr= "f" + OUString::number( i ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aStr ); + + aStr = rEquations[ i ]; + sal_Int32 nIndex = 0; + do + { + nIndex = aStr.indexOf( '?', nIndex ); + if ( nIndex != -1 ) + { + aStr = OUString::Concat(aStr.subView(0, nIndex + 1)) + "f" + + aStr.subView(nIndex + 1, aStr.getLength() - nIndex - 1); + nIndex++; + } + } while( nIndex != -1 ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FORMULA, aStr ); + SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_EQUATION, true, true ); + } +} + +static void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::PropertyValues >& rHandles ) +{ + if ( !rHandles.hasElements() ) + return; + + OUString aStr; + OUStringBuffer aStrBuffer; + + for ( const uno::Sequence< beans::PropertyValue >& rPropSeq : rHandles ) + { + bool bPosition = false; + for ( const beans::PropertyValue& rPropVal : rPropSeq ) + { + switch( EASGet( rPropVal.Name ) ) + { + case EAS_Position : + { + css::drawing::EnhancedCustomShapeParameterPair aPosition; + if ( rPropVal.Value >>= aPosition ) + { + ExportParameter( aStrBuffer, aPosition.First ); + ExportParameter( aStrBuffer, aPosition.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION, aStr ); + bPosition = true; + } + } + break; + case EAS_MirroredX : + { + bool bMirroredX; + if ( rPropVal.Value >>= bMirroredX ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_HORIZONTAL, + bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_MirroredY : + { + bool bMirroredY; + if ( rPropVal.Value >>= bMirroredY ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_VERTICAL, + bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_Switched : + { + bool bSwitched; + if ( rPropVal.Value >>= bSwitched ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_SWITCHED, + bSwitched ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_Polar : + { + css::drawing::EnhancedCustomShapeParameterPair aPolar; + if ( rPropVal.Value >>= aPolar ) + { + ExportParameter( aStrBuffer, aPolar.First ); + ExportParameter( aStrBuffer, aPolar.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR, aStr ); + } + } + break; + case EAS_RadiusRangeMinimum : + { + css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum; + if ( rPropVal.Value >>= aRadiusRangeMinimum ) + { + ExportParameter( aStrBuffer, aRadiusRangeMinimum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MINIMUM, aStr ); + } + } + break; + case EAS_RadiusRangeMaximum : + { + css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum; + if ( rPropVal.Value >>= aRadiusRangeMaximum ) + { + ExportParameter( aStrBuffer, aRadiusRangeMaximum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MAXIMUM, aStr ); + } + } + break; + case EAS_RangeXMinimum : + { + css::drawing::EnhancedCustomShapeParameter aXRangeMinimum; + if ( rPropVal.Value >>= aXRangeMinimum ) + { + ExportParameter( aStrBuffer, aXRangeMinimum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MINIMUM, aStr ); + } + } + break; + case EAS_RangeXMaximum : + { + css::drawing::EnhancedCustomShapeParameter aXRangeMaximum; + if ( rPropVal.Value >>= aXRangeMaximum ) + { + ExportParameter( aStrBuffer, aXRangeMaximum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MAXIMUM, aStr ); + } + } + break; + case EAS_RangeYMinimum : + { + css::drawing::EnhancedCustomShapeParameter aYRangeMinimum; + if ( rPropVal.Value >>= aYRangeMinimum ) + { + ExportParameter( aStrBuffer, aYRangeMinimum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MINIMUM, aStr ); + } + } + break; + case EAS_RangeYMaximum : + { + css::drawing::EnhancedCustomShapeParameter aYRangeMaximum; + if ( rPropVal.Value >>= aYRangeMaximum ) + { + ExportParameter( aStrBuffer, aYRangeMaximum ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MAXIMUM, aStr ); + } + } + break; + default: + break; + } + } + if ( bPosition ) + SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_HANDLE, true, true ); + else + rExport.ClearAttrList(); + } +} + +static void ImpExportEnhancedPath( SvXMLExport& rExport, + const uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair >& rCoordinates, + const uno::Sequence< css::drawing::EnhancedCustomShapeSegment >& rSegments, + bool bExtended = false ) +{ + + OUString aStr; + OUStringBuffer aStrBuffer; + bool bNeedExtended = false; + + sal_Int32 i, j, k, l; + + sal_Int32 nCoords = rCoordinates.getLength(); + sal_Int32 nSegments = rSegments.getLength(); + bool bSimpleSegments = nSegments == 0; + if ( bSimpleSegments ) + nSegments = 4; + for ( j = i = 0; j < nSegments; j++ ) + { + css::drawing::EnhancedCustomShapeSegment aSegment; + if ( bSimpleSegments ) + { + // if there are not enough segments we will default them + switch( j ) + { + case 0 : + { + aSegment.Count = 1; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO; + } + break; + case 1 : + { + aSegment.Count = static_cast(std::min( nCoords - 1, sal_Int32(32767) )); + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO; + } + break; + case 2 : + { + aSegment.Count = 1; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH; + } + break; + case 3 : + { + aSegment.Count = 1; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH; + } + break; + } + } + else + aSegment = rSegments[ j ]; + + if ( !aStrBuffer.isEmpty() ) + aStrBuffer.append( ' ' ); + + sal_Int32 nParameter = 0; + switch( aSegment.Command ) + { + case css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH : + aStrBuffer.append( 'Z' ); break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH : + aStrBuffer.append( 'N' ); break; + case css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL : + aStrBuffer.append( 'F' ); break; + case css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE : + aStrBuffer.append( 'S' ); break; + + case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO : + aStrBuffer.append( 'M' ); nParameter = 1; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO : + aStrBuffer.append( 'L' ); nParameter = 1; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO : + aStrBuffer.append( 'C' ); nParameter = 3; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO : + aStrBuffer.append( 'T' ); nParameter = 3; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE : + aStrBuffer.append( 'U' ); nParameter = 3; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO : + aStrBuffer.append( 'A' ); nParameter = 4; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ARC : + aStrBuffer.append( 'B' ); nParameter = 4; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO : + aStrBuffer.append( 'W' ); nParameter = 4; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC : + aStrBuffer.append( 'V' ); nParameter = 4; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX : + aStrBuffer.append( 'X' ); nParameter = 1; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY : + aStrBuffer.append( 'Y' ); nParameter = 1; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO : + aStrBuffer.append( 'Q' ); nParameter = 2; break; + case css::drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO : + if ( bExtended ) { + aStrBuffer.append( 'G' ); + nParameter = 2; + } else { + aStrBuffer.setLength( aStrBuffer.getLength() - 1); + bNeedExtended = true; + i += 2; + } + break; + case css::drawing::EnhancedCustomShapeSegmentCommand::DARKEN : + if ( bExtended ) + aStrBuffer.append( 'H' ); + else + bNeedExtended = true; + break; + case css::drawing::EnhancedCustomShapeSegmentCommand::DARKENLESS : + if ( bExtended ) + aStrBuffer.append( 'I' ); + else + bNeedExtended = true; + break; + case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTEN : + if ( bExtended ) + aStrBuffer.append( 'J' ); + else + bNeedExtended = true; + break; + case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTENLESS : + if ( bExtended ) + aStrBuffer.append( 'K' ); + else + bNeedExtended = true; + break; + default : // ups, seems to be something wrong + { + aSegment.Count = 1; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO; + } + break; + } + if ( nParameter ) + { + for ( k = 0; k < aSegment.Count; k++ ) + { + if ( ( i + nParameter ) <= nCoords ) + { + for ( l = 0; l < nParameter; l++ ) + { + ExportParameter( aStrBuffer, rCoordinates[ i ].First ); + ExportParameter( aStrBuffer, rCoordinates[ i++ ].Second ); + } + } + else + { + j = nSegments; // error -> exiting + break; + } + } + } + } + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( bExtended ? XML_NAMESPACE_DRAW_EXT : XML_NAMESPACE_DRAW, XML_ENHANCED_PATH, aStr ); + if (!bExtended && bNeedExtended && (rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + ImpExportEnhancedPath( rExport, rCoordinates, rSegments, true ); +} + +static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Reference< beans::XPropertySet >& xPropSet ) +{ + bool bEquations = false; + uno::Sequence< OUString > aEquations; + + bool bHandles = false; + uno::Sequence< beans::PropertyValues > aHandles; + + uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments; + uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates; + + uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentValues; + + OUString aStr; + OUStringBuffer aStrBuffer; + SvXMLUnitConverter& rUnitConverter = rExport.GetMM100UnitConverter(); + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + // geometry + static const OUStringLiteral sCustomShapeGeometry( u"CustomShapeGeometry" ); + if ( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( sCustomShapeGeometry ) ) + { + uno::Any aGeoPropSet( xPropSet->getPropertyValue( sCustomShapeGeometry ) ); + uno::Sequence< beans::PropertyValue > aGeoPropSeq; + + if ( aGeoPropSet >>= aGeoPropSeq ) + { + bool bCoordinates = false; + OUString aCustomShapeType( "non-primitive" ); + + for ( const beans::PropertyValue& rGeoProp : std::as_const(aGeoPropSeq) ) + { + switch( EASGet( rGeoProp.Name ) ) + { + case EAS_Type : + { + rGeoProp.Value >>= aCustomShapeType; + } + break; + case EAS_MirroredX : + { + bool bMirroredX; + if ( rGeoProp.Value >>= bMirroredX ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_HORIZONTAL, + bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_MirroredY : + { + bool bMirroredY; + if ( rGeoProp.Value >>= bMirroredY ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_VERTICAL, + bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_ViewBox : + { + awt::Rectangle aRect; + if ( rGeoProp.Value >>= aRect ) + { + SdXMLImExViewBox aViewBox( aRect.X, aRect.Y, aRect.Width, aRect.Height ); + rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() ); + } + } + break; + case EAS_TextPreRotateAngle : + case EAS_TextRotateAngle : + { + double fTextRotateAngle = 0; + if ( ( rGeoProp.Value >>= fTextRotateAngle ) && fTextRotateAngle != 0 ) + { + ::sax::Converter::convertDouble( + aStrBuffer, fTextRotateAngle ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_ROTATE_ANGLE, aStr ); + } + } + break; + case EAS_Extrusion : + { + uno::Sequence< beans::PropertyValue > aExtrusionPropSeq; + if ( rGeoProp.Value >>= aExtrusionPropSeq ) + { + bool bSkewValuesProvided = false; + for ( const beans::PropertyValue& rProp : std::as_const(aExtrusionPropSeq) ) + { + switch( EASGet( rProp.Name ) ) + { + case EAS_Extrusion : + { + bool bExtrusionOn; + if ( rProp.Value >>= bExtrusionOn ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION, + bExtrusionOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_Brightness : + { + double fExtrusionBrightness = 0; + if ( rProp.Value >>= fExtrusionBrightness ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionBrightness, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_BRIGHTNESS, aStr ); + } + } + break; + case EAS_Depth : + { + css::drawing::EnhancedCustomShapeParameterPair aDepthParaPair; + if ( rProp.Value >>= aDepthParaPair ) + { + double fDepth = 0; + if ( aDepthParaPair.First.Value >>= fDepth ) + { + rExport.GetMM100UnitConverter().convertDouble( aStrBuffer, fDepth ); + ExportParameter( aStrBuffer, aDepthParaPair.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DEPTH, aStr ); + } + } + } + break; + case EAS_Diffusion : + { + double fExtrusionDiffusion = 0; + if ( rProp.Value >>= fExtrusionDiffusion ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionDiffusion, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DIFFUSION, aStr ); + } + } + break; + case EAS_NumberOfLineSegments : + { + sal_Int32 nExtrusionNumberOfLineSegments = 0; + if ( rProp.Value >>= nExtrusionNumberOfLineSegments ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_NUMBER_OF_LINE_SEGMENTS, OUString::number( nExtrusionNumberOfLineSegments ) ); + } + break; + case EAS_LightFace : + { + bool bExtrusionLightFace; + if ( rProp.Value >>= bExtrusionLightFace ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_LIGHT_FACE, + bExtrusionLightFace ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_FirstLightHarsh : + { + bool bExtrusionFirstLightHarsh; + if ( rProp.Value >>= bExtrusionFirstLightHarsh ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_HARSH, + bExtrusionFirstLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_SecondLightHarsh : + { + bool bExtrusionSecondLightHarsh; + if ( rProp.Value >>= bExtrusionSecondLightHarsh ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_HARSH, + bExtrusionSecondLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_FirstLightLevel : + { + double fExtrusionFirstLightLevel = 0; + if ( rProp.Value >>= fExtrusionFirstLightLevel ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionFirstLightLevel, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_LEVEL, aStr ); + } + } + break; + case EAS_SecondLightLevel : + { + double fExtrusionSecondLightLevel = 0; + if ( rProp.Value >>= fExtrusionSecondLightLevel ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionSecondLightLevel, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_LEVEL, aStr ); + } + } + break; + case EAS_FirstLightDirection : + { + drawing::Direction3D aExtrusionFirstLightDirection; + if ( rProp.Value >>= aExtrusionFirstLightDirection ) + { + ::basegfx::B3DVector aVec3D( aExtrusionFirstLightDirection.DirectionX, aExtrusionFirstLightDirection.DirectionY, + aExtrusionFirstLightDirection.DirectionZ ); + SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_DIRECTION, aStr ); + } + } + break; + case EAS_SecondLightDirection : + { + drawing::Direction3D aExtrusionSecondLightDirection; + if ( rProp.Value >>= aExtrusionSecondLightDirection ) + { + ::basegfx::B3DVector aVec3D( aExtrusionSecondLightDirection.DirectionX, aExtrusionSecondLightDirection.DirectionY, + aExtrusionSecondLightDirection.DirectionZ ); + SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_DIRECTION, aStr ); + } + } + break; + case EAS_Metal : + { + bool bExtrusionMetal; + if ( rProp.Value >>= bExtrusionMetal ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_METAL, + bExtrusionMetal ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_MetalType : + { + // export only if ODF extensions are enabled + sal_Int16 eMetalType; + if (rProp.Value >>= eMetalType) + { + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if (eVersion > SvtSaveOptions::ODFSVER_013 + && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED)) + { + if (eMetalType == drawing::EnhancedCustomShapeMetalType::MetalMSCompatible) + aStr = "loext:MetalMSCompatible"; + else + aStr = "draw:MetalODF"; + rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_EXTRUSION_METAL_TYPE, aStr); + } + } + } + break; + case EAS_ShadeMode : + { + // shadeMode + drawing::ShadeMode eShadeMode; + if( rProp.Value >>= eShadeMode ) + { + if( eShadeMode == drawing::ShadeMode_FLAT ) + aStr = GetXMLToken( XML_FLAT ); + else if( eShadeMode == drawing::ShadeMode_PHONG ) + aStr = GetXMLToken( XML_PHONG ); + else if( eShadeMode == drawing::ShadeMode_SMOOTH ) + aStr = GetXMLToken( XML_GOURAUD ); + else + aStr = GetXMLToken( XML_DRAFT ); + } + else + { + // ShadeMode enum not there, write default + aStr = GetXMLToken( XML_FLAT); + } + rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr ); + } + break; + case EAS_RotateAngle : + { + css::drawing::EnhancedCustomShapeParameterPair aRotateAngleParaPair; + if ( rProp.Value >>= aRotateAngleParaPair ) + { + ExportParameter( aStrBuffer, aRotateAngleParaPair.First ); + ExportParameter( aStrBuffer, aRotateAngleParaPair.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_ANGLE, aStr ); + } + } + break; + case EAS_RotationCenter : + { + drawing::Direction3D aExtrusionRotationCenter; + if ( rProp.Value >>= aExtrusionRotationCenter ) + { + ::basegfx::B3DVector aVec3D( aExtrusionRotationCenter.DirectionX, aExtrusionRotationCenter.DirectionY, + aExtrusionRotationCenter.DirectionZ ); + SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_CENTER, aStr ); + } + } + break; + case EAS_Shininess : + { + double fExtrusionShininess = 0; + if ( rProp.Value >>= fExtrusionShininess ) + { + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionShininess, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SHININESS, aStr ); + } + } + break; + case EAS_Skew : + { + css::drawing::EnhancedCustomShapeParameterPair aSkewParaPair; + if ( rProp.Value >>= aSkewParaPair ) + { + bSkewValuesProvided = true; + ExportParameter( aStrBuffer, aSkewParaPair.First ); + ExportParameter( aStrBuffer, aSkewParaPair.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, aStr ); + } + } + break; + case EAS_Specularity : + { + double fExtrusionSpecularity = 0; + if ( rProp.Value >>= fExtrusionSpecularity ) + { + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if (fExtrusionSpecularity > 100.0 && eVersion >= SvtSaveOptions::ODFSVER_012 + && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED)) + { + // tdf#147580 write values > 100% in loext + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionSpecularity, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_EXTRUSION_SPECULARITY_LOEXT, aStr ); + } + // tdf#147580 ODF 1 allows arbitrary percent, later versions not + if (eVersion >= SvtSaveOptions::ODFSVER_012) + { + fExtrusionSpecularity = std::clamp(fExtrusionSpecularity, 0.0, 100.0); + } + ::sax::Converter::convertDouble( + aStrBuffer, + fExtrusionSpecularity, + false, + util::MeasureUnit::PERCENT, + util::MeasureUnit::PERCENT); + aStrBuffer.append( '%' ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SPECULARITY, aStr ); + } + } + break; + case EAS_ProjectionMode : + { + drawing::ProjectionMode eProjectionMode; + if ( rProp.Value >>= eProjectionMode ) + rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_PROJECTION, + eProjectionMode == drawing::ProjectionMode_PARALLEL ? GetXMLToken( XML_PARALLEL ) : GetXMLToken( XML_PERSPECTIVE ) ); + } + break; + case EAS_ViewPoint : + { + drawing::Position3D aExtrusionViewPoint; + if ( rProp.Value >>= aExtrusionViewPoint ) + { + rUnitConverter.convertPosition3D( aStrBuffer, aExtrusionViewPoint ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_VIEWPOINT, aStr ); + } + } + break; + case EAS_Origin : + { + css::drawing::EnhancedCustomShapeParameterPair aOriginParaPair; + if ( rProp.Value >>= aOriginParaPair ) + { + ExportParameter( aStrBuffer, aOriginParaPair.First ); + ExportParameter( aStrBuffer, aOriginParaPair.Second ); + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ORIGIN, aStr ); + } + } + break; + case EAS_Color : + { + bool bExtrusionColor; + if ( rProp.Value >>= bExtrusionColor ) + { + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_COLOR, + bExtrusionColor ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + } + break; + default: + break; + } + } + // tdf#141301: no specific skew values provided + if (!bSkewValuesProvided) + { + // so we need to export default values explicitly + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, "50 -135"); + } + } + } + break; + case EAS_TextPath : + { + uno::Sequence< beans::PropertyValue > aTextPathPropSeq; + if ( rGeoProp.Value >>= aTextPathPropSeq ) + { + for ( const beans::PropertyValue& rProp : std::as_const(aTextPathPropSeq) ) + { + switch( EASGet( rProp.Name ) ) + { + case EAS_TextPath : + { + bool bTextPathOn; + if ( rProp.Value >>= bTextPathOn ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH, + bTextPathOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_TextPathMode : + { + css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode; + if ( rProp.Value >>= eTextPathMode ) + { + switch ( eTextPathMode ) + { + case css::drawing::EnhancedCustomShapeTextPathMode_NORMAL: aStr = GetXMLToken( XML_NORMAL ); break; + case css::drawing::EnhancedCustomShapeTextPathMode_PATH : aStr = GetXMLToken( XML_PATH ); break; + case css::drawing::EnhancedCustomShapeTextPathMode_SHAPE : aStr = GetXMLToken( XML_SHAPE ); break; + default: + break; + } + if ( !aStr.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_MODE, aStr ); + } + } + break; + case EAS_ScaleX : + { + bool bScaleX; + if ( rProp.Value >>= bScaleX ) + { + aStr = bScaleX ? GetXMLToken( XML_SHAPE ) : GetXMLToken( XML_PATH ); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SCALE, aStr ); + } + } + break; + case EAS_SameLetterHeights : + { + bool bSameLetterHeights; + if ( rProp.Value >>= bSameLetterHeights ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SAME_LETTER_HEIGHTS, + bSameLetterHeights ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + default: + break; + } + } + } + } + break; + case EAS_Path : + { + uno::Sequence< beans::PropertyValue > aPathPropSeq; + if ( rGeoProp.Value >>= aPathPropSeq ) + { + for ( const beans::PropertyValue& rProp : std::as_const(aPathPropSeq) ) + { + switch( EASGet( rProp.Name ) ) + { + case EAS_SubViewSize: + { + // export draw:sub-view-size (do not export in ODF 1.3 or older) + if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0) + { + continue; + } + uno::Sequence< awt::Size > aSubViewSizes; + rProp.Value >>= aSubViewSizes; + + for ( int nIdx = 0; nIdx < aSubViewSizes.getLength(); nIdx++ ) + { + if ( nIdx ) + aStrBuffer.append(' '); + aStrBuffer.append( aSubViewSizes[nIdx].Width ); + aStrBuffer.append(' '); + aStrBuffer.append( aSubViewSizes[nIdx].Height ); + } + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW_EXT, XML_SUB_VIEW_SIZE, aStr ); + } + break; + case EAS_ExtrusionAllowed : + { + bool bExtrusionAllowed; + if ( rProp.Value >>= bExtrusionAllowed ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ALLOWED, + bExtrusionAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_ConcentricGradientFillAllowed : + { + bool bConcentricGradientFillAllowed; + if ( rProp.Value >>= bConcentricGradientFillAllowed ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONCENTRIC_GRADIENT_FILL_ALLOWED, + bConcentricGradientFillAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_TextPathAllowed : + { + bool bTextPathAllowed; + if ( rProp.Value >>= bTextPathAllowed ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_ALLOWED, + bTextPathAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) ); + } + break; + case EAS_GluePoints : + { + css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> aGluePoints; + if ( rProp.Value >>= aGluePoints ) + { + if ( aGluePoints.hasElements() ) + { + for( const auto& rGluePoint : std::as_const(aGluePoints) ) + { + ExportParameter( aStrBuffer, rGluePoint.First ); + ExportParameter( aStrBuffer, rGluePoint.Second ); + } + aStr = aStrBuffer.makeStringAndClear(); + } + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINTS, aStr ); + } + } + break; + case EAS_GluePointType : + { + sal_Int16 nGluePointType = sal_Int16(); + if ( rProp.Value >>= nGluePointType ) + { + switch ( nGluePointType ) + { + case css::drawing::EnhancedCustomShapeGluePointType::NONE : aStr = GetXMLToken( XML_NONE ); break; + case css::drawing::EnhancedCustomShapeGluePointType::SEGMENTS : aStr = GetXMLToken( XML_SEGMENTS ); break; + case css::drawing::EnhancedCustomShapeGluePointType::RECT : aStr = GetXMLToken( XML_RECTANGLE ); break; + } + if ( !aStr.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINT_TYPE, aStr ); + } + } + break; + case EAS_Coordinates : + { + bCoordinates = ( rProp.Value >>= aCoordinates ); + } + break; + case EAS_Segments : + { + rProp.Value >>= aSegments; + } + break; + case EAS_StretchX : + { + sal_Int32 nStretchPoint = 0; + if ( rProp.Value >>= nStretchPoint ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_X, OUString::number( nStretchPoint ) ); + } + break; + case EAS_StretchY : + { + sal_Int32 nStretchPoint = 0; + if ( rProp.Value >>= nStretchPoint ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_Y, OUString::number( nStretchPoint ) ); + } + break; + case EAS_TextFrames : + { + css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aPathTextFrames; + if ( rProp.Value >>= aPathTextFrames ) + { + if ( aPathTextFrames.hasElements() ) + { + for ( const auto& rPathTextFrame : std::as_const(aPathTextFrames) ) + { + ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.First ); + ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.Second ); + ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.First ); + ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.Second ); + } + aStr = aStrBuffer.makeStringAndClear(); + } + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_AREAS, aStr ); + } + } + break; + default: + break; + } + } + } + } + break; + case EAS_Equations : + { + bEquations = ( rGeoProp.Value >>= aEquations ); + } + break; + case EAS_Handles : + { + bHandles = ( rGeoProp.Value >>= aHandles ); + } + break; + case EAS_AdjustmentValues : + { + rGeoProp.Value >>= aAdjustmentValues; + } + break; + default: + break; + } + } // for + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TYPE, aCustomShapeType ); + + // adjustments + sal_Int32 nAdjustmentValues = aAdjustmentValues.getLength(); + if ( nAdjustmentValues ) + { + sal_Int32 i, nValue = 0; + for ( i = 0; i < nAdjustmentValues; i++ ) + { + if ( i ) + aStrBuffer.append( ' ' ); + + const css::drawing::EnhancedCustomShapeAdjustmentValue& rAdj = aAdjustmentValues[ i ]; + if ( rAdj.State == beans::PropertyState_DIRECT_VALUE ) + { + if ( rAdj.Value.getValueTypeClass() == uno::TypeClass_DOUBLE ) + { + double fValue = 0.0; + rAdj.Value >>= fValue; + ::sax::Converter::convertDouble(aStrBuffer, fValue); + } + else + { + rAdj.Value >>= nValue; + aStrBuffer.append(nValue); + } + } + else + { + // this should not be, but better than setting nothing + aStrBuffer.append("0"); + } + } + aStr = aStrBuffer.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MODIFIERS, aStr ); + } + if ( bCoordinates ) + ImpExportEnhancedPath( rExport, aCoordinates, aSegments ); + } + } + SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_ENHANCED_GEOMETRY, true, true ); + if ( bEquations ) + ImpExportEquations( rExport, aEquations ); + if ( bHandles ) + ImpExportHandles( rExport, aHandles ); +} + +void XMLShapeExport::ImpExportCustomShape( + const uno::Reference< drawing::XShape >& xShape, + XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint ) +{ + const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + if ( !xPropSet.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + // Transformation + ImpExportNewTrans( xPropSet, nFeatures, pRefPoint ); + + if ( xPropSetInfo.is() ) + { + OUString aStr; + if ( xPropSetInfo->hasPropertyByName( "CustomShapeEngine" ) ) + { + uno::Any aEngine( xPropSet->getPropertyValue( "CustomShapeEngine" ) ); + if ( ( aEngine >>= aStr ) && !aStr.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ENGINE, aStr ); + } + if ( xPropSetInfo->hasPropertyByName( "CustomShapeData" ) ) + { + uno::Any aData( xPropSet->getPropertyValue( "CustomShapeData" ) ); + if ( ( aData >>= aStr ) && !aStr.isEmpty() ) + mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DATA, aStr ); + } + } + bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210# + SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, bCreateNewline, true ); + ImpExportDescription( xShape ); // #i68101# + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportText( xShape ); + ImpExportEnhancedGeometry( mrExport, xPropSet ); + +} + +void XMLShapeExport::ImpExportTableShape( const uno::Reference< drawing::XShape >& xShape, XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint ) +{ + uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY); + uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY); + + SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "xmloff::XMLShapeExport::ImpExportTableShape(), table shape is not implementing needed interfaces"); + if(!(xPropSet.is() && xNamed.is())) + return; + + try + { + // Transformation + ImpExportNewTrans(xPropSet, nFeatures, pRefPoint); + + bool bIsEmptyPresObj = false; + + // presentation settings + if(eShapeType == XmlShapeTypePresTableShape) + bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) ); + + const bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); + const bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED); + + SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, XML_FRAME, bCreateNewline, true ); + + // do not export in ODF 1.1 or older + if (mrExport.getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + if( !bIsEmptyPresObj ) + { + uno::Reference< container::XNamed > xTemplate( xPropSet->getPropertyValue("TableTemplate"), uno::UNO_QUERY ); + if( xTemplate.is() ) + { + const OUString sTemplate( xTemplate->getName() ); + if( !sTemplate.isEmpty() ) + { + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TEMPLATE_NAME, sTemplate ); + + for( const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; pEntry->msApiName; pEntry++ ) + { + try + { + bool bBool = false; + const OUString sAPIPropertyName( pEntry->msApiName, pEntry->nApiNameLength, RTL_TEXTENCODING_ASCII_US ); + + xPropSet->getPropertyValue( sAPIPropertyName ) >>= bBool; + if( bBool ) + mrExport.AddAttribute(pEntry->mnNameSpace, pEntry->meXMLName, XML_TRUE ); + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + } + } + } + + uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW ); + GetShapeTableExport()->exportTable( xRange ); + } + } + + if( !bIsEmptyPresObj ) + { + uno::Reference< graphic::XGraphic > xGraphic( xPropSet->getPropertyValue("ReplacementGraphic"), uno::UNO_QUERY ); + if( xGraphic.is() ) try + { + uno::Reference< uno::XComponentContext > xContext = GetExport().getComponentContext(); + + uno::Reference< embed::XStorage > xPictureStorage; + uno::Reference< embed::XStorage > xStorage; + uno::Reference< io::XStream > xPictureStream; + + OUString sPictureName; + if( bExportEmbedded ) + { + xPictureStream.set( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.comp.MemoryStream", xContext), uno::UNO_QUERY_THROW ); + } + else + { + xStorage.set( GetExport().GetTargetStorage(), uno::UNO_SET_THROW ); + + xPictureStorage.set( xStorage->openStorageElement( "Pictures" , ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW ); + + sal_Int32 nIndex = 0; + do + { + sPictureName = "TablePreview" + OUString::number( ++nIndex ) + ".svm"; + } + while( xPictureStorage->hasByName( sPictureName ) ); + + xPictureStream.set( xPictureStorage->openStreamElement( sPictureName, ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW ); + } + + uno::Reference< graphic::XGraphicProvider > xProvider( graphic::GraphicProvider::create(xContext) ); + uno::Sequence< beans::PropertyValue > aArgs{ + comphelper::makePropertyValue("MimeType", OUString( "image/x-vclgraphic" )), + comphelper::makePropertyValue("OutputStream", xPictureStream->getOutputStream()) + }; + xProvider->storeGraphic( xGraphic, aArgs ); + + if( xPictureStorage.is() ) + { + uno::Reference< embed::XTransactedObject > xTrans( xPictureStorage, uno::UNO_QUERY ); + if( xTrans.is() ) + xTrans->commit(); + } + + if( !bExportEmbedded ) + { + OUString sURL = "Pictures/" + sPictureName; + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, false, true ); + + if( bExportEmbedded ) + { + uno::Reference< io::XSeekableInputStream > xSeekable( xPictureStream, uno::UNO_QUERY_THROW ); + xSeekable->seek(0); + + XMLBase64Export aBase64Exp( GetExport() ); + aBase64Exp.exportOfficeBinaryDataElement( uno::Reference < io::XInputStream >( xPictureStream, uno::UNO_QUERY_THROW ) ); + } + } + catch( uno::Exception const & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + } + + ImpExportEvents( xShape ); + ImpExportGluePoints( xShape ); + ImpExportDescription( xShape ); // #i68101# + } + catch( uno::Exception const & ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/shapeimport.cxx b/xmloff/source/draw/shapeimport.cxx new file mode 100644 index 000000000..930051b2a --- /dev/null +++ b/xmloff/source/draw/shapeimport.cxx @@ -0,0 +1,950 @@ +/* -*- 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 +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "eventimp.hxx" +#include "ximpshap.hxx" +#include "sdpropls.hxx" +#include +#include "ximp3dscene.hxx" +#include "ximp3dobject.hxx" +#include "ximpgrp.hxx" +#include "ximplink.hxx" + +#include +#include +#include + +namespace { + +class ShapeGroupContext; + +} + +using namespace ::std; +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +namespace { + +struct ConnectionHint +{ + css::uno::Reference< css::drawing::XShape > mxConnector; + OUString aDestShapeId; + sal_Int32 nDestGlueId; + bool bStart; +}; + +} + +/** this map store all gluepoint id mappings for shapes that had user defined gluepoints. This + is needed because on insertion the gluepoints will get a new and unique id */ +typedef std::map GluePointIdMap; +typedef std::unordered_map< css::uno::Reference < css::drawing::XShape >, GluePointIdMap > ShapeGluePointsMap; + +/** this struct is created for each startPage() call and stores information that is needed during + import of shapes for one page. Since pages could be nested ( notes pages inside impress ) there + is a pointer so one can build up a stack of this structs */ +struct XMLShapeImportPageContextImpl +{ + ShapeGluePointsMap maShapeGluePointsMap; + + uno::Reference < drawing::XShapes > mxShapes; + + std::shared_ptr mpNext; +}; + +/** this class is to enable adding members to the XMLShapeImportHelper without getting incompatible */ +struct XMLShapeImportHelperImpl +{ + // context for sorting shapes + std::shared_ptr mpGroupContext; + + std::vector maConnections; + + // #88546# possibility to switch progress bar handling on/off + bool mbHandleProgressBar; + + // stores the capability of the current model to create presentation shapes + bool mbIsPresentationShapesSupported; +}; + +constexpr OUStringLiteral gsStartShape(u"StartShape"); +constexpr OUStringLiteral gsEndShape(u"EndShape"); +constexpr OUStringLiteral gsStartGluePointIndex(u"StartGluePointIndex"); +constexpr OUStringLiteral gsEndGluePointIndex(u"EndGluePointIndex"); + +XMLShapeImportHelper::XMLShapeImportHelper( + SvXMLImport& rImporter, + const uno::Reference< frame::XModel>& rModel, + SvXMLImportPropertyMapper *pExtMapper ) +: mpImpl( new XMLShapeImportHelperImpl ), + mrImporter( rImporter ) +{ + mpImpl->mpGroupContext = nullptr; + + // #88546# init to sal_False + mpImpl->mbHandleProgressBar = false; + + mpSdPropHdlFactory = new XMLSdPropHdlFactory( rModel, rImporter ); + + // construct PropertySetMapper + rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper(mpSdPropHdlFactory, false); + mpPropertySetMapper = new SvXMLImportPropertyMapper( xMapper, rImporter ); + + if( pExtMapper ) + { + rtl::Reference < SvXMLImportPropertyMapper > xExtMapper( pExtMapper ); + mpPropertySetMapper->ChainImportMapper( xExtMapper ); + } + + // chain text attributes + mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImporter)); + mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaDefaultExtPropMapper(rImporter)); + + // construct PresPagePropsMapper + xMapper = new XMLPropertySetMapper(aXMLSDPresPageProps, mpSdPropHdlFactory, false); + mpPresPagePropsMapper = new SvXMLImportPropertyMapper( xMapper, rImporter ); + + uno::Reference< lang::XServiceInfo > xInfo( rImporter.GetModel(), uno::UNO_QUERY ); + mpImpl->mbIsPresentationShapesSupported = xInfo.is() && xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ); +} + +XMLShapeImportHelper::~XMLShapeImportHelper() +{ + SAL_WARN_IF( !mpImpl->maConnections.empty(), "xmloff", "XMLShapeImportHelper::restoreConnections() was not called!" ); + + // cleanup factory, decrease refcount. Should lead to destruction. + mpSdPropHdlFactory.clear(); + + // cleanup mapper, decrease refcount. Should lead to destruction. + mpPropertySetMapper.clear(); + + // cleanup presPage mapper, decrease refcount. Should lead to destruction. + mpPresPagePropsMapper.clear(); + + // Styles or AutoStyles context? + if(mxStylesContext.is()) + mxStylesContext->dispose(); + + if(mxAutoStylesContext.is()) + mxAutoStylesContext->dispose(); +} + + +SvXMLShapeContext* XMLShapeImportHelper::Create3DSceneChildContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +{ + SdXMLShapeContext *pContext = nullptr; + + if(rShapes.is()) + { + switch(nElement) + { + case XML_ELEMENT(DR3D, XML_SCENE): + { + // dr3d:3dscene inside dr3d:3dscene context + pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, false); + break; + } + case XML_ELEMENT(DR3D, XML_CUBE): + { + // dr3d:3dcube inside dr3d:3dscene context + pContext = new SdXML3DCubeObjectShapeContext( rImport, xAttrList, rShapes); + break; + } + case XML_ELEMENT(DR3D, XML_SPHERE): + { + // dr3d:3dsphere inside dr3d:3dscene context + pContext = new SdXML3DSphereObjectShapeContext( rImport, xAttrList, rShapes); + break; + } + case XML_ELEMENT(DR3D, XML_ROTATE): + { + // dr3d:3dlathe inside dr3d:3dscene context + pContext = new SdXML3DLatheObjectShapeContext( rImport, xAttrList, rShapes); + break; + } + case XML_ELEMENT(DR3D, XML_EXTRUDE): + { + // dr3d:3dextrude inside dr3d:3dscene context + pContext = new SdXML3DExtrudeObjectShapeContext( rImport, xAttrList, rShapes); + break; + } + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + } + + if (!pContext) + return nullptr; + + // now parse the attribute list and call the child context for each unknown attribute + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + if (!pContext->processAttribute( aIter )) + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + + } + + return pContext; +} + +void XMLShapeImportHelper::SetStylesContext(SvXMLStylesContext* pNew) +{ + mxStylesContext.set(pNew); +} + +void XMLShapeImportHelper::SetAutoStylesContext(SvXMLStylesContext* pNew) +{ + mxAutoStylesContext.set(pNew); +} + +SvXMLShapeContext* XMLShapeImportHelper::CreateGroupChildContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +{ + SdXMLShapeContext *pContext = nullptr; + switch (nElement) + { + case XML_ELEMENT(DRAW, XML_G): + // draw:g inside group context (RECURSIVE) + pContext = new SdXMLGroupShapeContext( rImport, xAttrList, rShapes, bTemporaryShape); + break; + case XML_ELEMENT(DR3D, XML_SCENE): + { + // dr3d:3dscene inside group context + pContext = new SdXML3DSceneShapeContext( rImport, xAttrList, rShapes, bTemporaryShape); + break; + } + case XML_ELEMENT(DRAW, XML_RECT): + { + // draw:rect inside group context + pContext = new SdXMLRectShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_LINE): + { + // draw:line inside group context + pContext = new SdXMLLineShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CIRCLE): + case XML_ELEMENT(DRAW, XML_ELLIPSE): + { + // draw:circle or draw:ellipse inside group context + pContext = new SdXMLEllipseShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_POLYGON): + case XML_ELEMENT(DRAW, XML_POLYLINE): + { + // draw:polygon or draw:polyline inside group context + pContext = new SdXMLPolygonShapeContext( rImport, xAttrList, rShapes, + nElement == XML_ELEMENT(DRAW, XML_POLYGON), bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_PATH): + { + // draw:path inside group context + pContext = new SdXMLPathShapeContext( rImport, xAttrList, rShapes, bTemporaryShape); + break; + } + case XML_ELEMENT(DRAW, XML_FRAME): + { + // text:text-box inside group context + pContext = new SdXMLFrameShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CONTROL): + { + // draw:control inside group context + pContext = new SdXMLControlShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CONNECTOR): + { + // draw:connector inside group context + pContext = new SdXMLConnectorShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_MEASURE): + { + // draw:measure inside group context + pContext = new SdXMLMeasureShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_PAGE_THUMBNAIL): + { + // draw:page inside group context + pContext = new SdXMLPageShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CAPTION): + case XML_ELEMENT(OFFICE, XML_ANNOTATION): + { + // draw:caption inside group context + pContext = new SdXMLCaptionShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(CHART, XML_CHART): + { + // chart:chart inside group context + pContext = new SdXMLChartShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ); + break; + } + case XML_ELEMENT(DRAW, XML_CUSTOM_SHAPE): + { + // draw:customshape + pContext = new SdXMLCustomShapeContext( rImport, xAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_A): + return new SdXMLShapeLinkContext( rImport, xAttrList, rShapes ); + // add other shapes here... + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return new SvXMLShapeContext( rImport, bTemporaryShape ); + } + + // now parse the attribute list and call the child context for each unknown attribute + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if (!pContext->processAttribute( aIter )) + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + return pContext; +} + +// This method is called from SdXMLFrameShapeContext to create children of draw:frame +SvXMLShapeContext* XMLShapeImportHelper::CreateFrameChildContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& rAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + const uno::Reference< xml::sax::XFastAttributeList>& rFrameAttrList) +{ + SdXMLShapeContext *pContext = nullptr; + + rtl::Reference xCombinedAttrList = new sax_fastparser::FastAttributeList(rAttrList); + if( rFrameAttrList.is() ) + xCombinedAttrList->add(rFrameAttrList); + + switch(nElement) + { + case XML_ELEMENT(DRAW, XML_TEXT_BOX): + { + // text:text-box inside group context + pContext = new SdXMLTextBoxShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_IMAGE): + { + // office:image inside group context + pContext = new SdXMLGraphicObjectShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_OBJECT): + case XML_ELEMENT(DRAW, XML_OBJECT_OLE): + { + // draw:object or draw:object_ole + pContext = new SdXMLObjectShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(TABLE, XML_TABLE): + { + // draw:object or draw:object_ole + if( rImport.IsTableShapeSupported() ) + pContext = new SdXMLTableShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + + } + case XML_ELEMENT(DRAW, XML_PLUGIN): + { + // draw:plugin + pContext = new SdXMLPluginShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_FLOATING_FRAME): + { + // draw:floating-frame + pContext = new SdXMLFloatingFrameShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + case XML_ELEMENT(DRAW, XML_APPLET): + { + // draw:applet + pContext = new SdXMLAppletShapeContext( rImport, xCombinedAttrList, rShapes ); + break; + } + // add other shapes here... + default: + SAL_INFO("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement)); + break; + } + + if( pContext ) + { + // now parse the attribute list and call the child context for each unknown attribute + for(auto& aIter : *xCombinedAttrList) + { + if (!pContext->processAttribute( aIter )) + SAL_INFO("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << " value=" << aIter.toString()); + } + } + + return pContext; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLShapeImportHelper::CreateFrameChildContext( + SvXMLImportContext *pThisContext, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + SdXMLFrameShapeContext *pFrameContext = dynamic_cast( pThisContext ); + if (pFrameContext) + xContext = pFrameContext->createFastChildContext( nElement, xAttrList ); + + if (!xContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return xContext; +} + +/** this function is called whenever the implementation classes like to add this new + shape to the given XShapes. +*/ +void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape, + const uno::Reference< xml::sax::XFastAttributeList >&, + uno::Reference< drawing::XShapes >& rShapes) +{ + if( rShape.is() && rShapes.is() ) + { + // add new shape to parent + rShapes->add( rShape ); + + uno::Reference xPropertySet(rShape, uno::UNO_QUERY); + if (xPropertySet.is()) + { + xPropertySet->setPropertyValue("HandlePathObjScale", uno::Any(true)); + } + } +} + +/** this function is called whenever the implementation classes have finished importing + a shape to the given XShapes. The shape is already inserted into its XShapes and + all properties and styles are set. +*/ +void XMLShapeImportHelper::finishShape( + css::uno::Reference< css::drawing::XShape >& rShape, + const css::uno::Reference< css::xml::sax::XFastAttributeList >&, + css::uno::Reference< css::drawing::XShapes >&) +{ + /* Set property + to , if it exists and the import states that + the shape positioning attributes are in horizontal left-to-right + layout. This is the case for the OpenOffice.org file format. + This setting is done for Writer documents, because the property + only exists at service css::text::Shape - the Writer + UNO service for shapes. + The value indicates that the positioning attributes are given + in horizontal left-to-right layout. The property is evaluated + during the first positioning of the shape in order to convert + the shape position given in the OpenOffice.org file format to + the one for the OASIS Open Office file format. (#i28749#, #i36248#) + */ + uno::Reference< beans::XPropertySet > xPropSet(rShape, uno::UNO_QUERY); + if ( xPropSet.is() ) + { + if ( mrImporter.IsShapePositionInHoriL2R() && + xPropSet->getPropertySetInfo()->hasPropertyByName( + "PositionLayoutDir") ) + { + uno::Any aPosLayoutDir; + aPosLayoutDir <<= text::PositionLayoutDir::PositionInHoriL2R; + xPropSet->setPropertyValue( "PositionLayoutDir", aPosLayoutDir ); + } + } +} + +namespace { + +// helper functions for z-order sorting +struct ZOrderHint +{ + sal_Int32 nIs; + sal_Int32 nShould; + /// The hint is for this shape. + uno::Reference xShape; + + bool operator<(const ZOrderHint& rComp) const { return nShould < rComp.nShould; } +}; + +// a) handle z-order of group contents after it has been imported +// b) apply group events over group contents after it has been imported +class ShapeGroupContext +{ +public: + uno::Reference< drawing::XShapes > mxShapes; + std::vector maEventData; + vector maZOrderList; + vector maUnsortedList; + + sal_Int32 mnCurrentZ; + std::shared_ptr mpParentContext; + + ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr pParentContext ); + + void popGroupAndPostProcess(); +private: + void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos ); +}; + +} + +ShapeGroupContext::ShapeGroupContext( uno::Reference< drawing::XShapes > const & rShapes, std::shared_ptr pParentContext ) +: mxShapes( rShapes ), mnCurrentZ( 0 ), mpParentContext( std::move(pParentContext) ) +{ +} + +void ShapeGroupContext::moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos ) +{ + uno::Any aAny( mxShapes->getByIndex( nSourcePos ) ); + uno::Reference< beans::XPropertySet > xPropSet; + aAny >>= xPropSet; + + if( !(xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName( "ZOrder" )) ) + return; + + xPropSet->setPropertyValue( "ZOrder", uno::Any(nDestPos) ); + + for( ZOrderHint& rHint : maZOrderList ) + { + if( rHint.nIs < nSourcePos ) + { + DBG_ASSERT(rHint.nIs >= nDestPos, "Shape sorting failed" ); + rHint.nIs++; + } + } + + for( ZOrderHint& rHint : maUnsortedList ) + { + if( rHint.nIs < nSourcePos ) + { + SAL_WARN_IF( rHint.nIs < nDestPos, "xmloff", "shape sorting failed" ); + rHint.nIs++; + } + } +} + +// sort shapes +void ShapeGroupContext::popGroupAndPostProcess() +{ + if (!maEventData.empty()) + { + // tdf#127791 wait until a group is popped to set its event data + for (auto& event : maEventData) + event.ApplyProperties(); + maEventData.clear(); + } + + // only do something if we have shapes to sort + if( maZOrderList.empty() ) + return; + + // check if there are more shapes than inserted with ::shapeWithZIndexAdded() + // This can happen if there where already shapes on the page before import + // Since the writer may delete some of this shapes during import, we need + // to do this here and not in our c'tor anymore + + // check if we have more shapes than we know of + sal_Int32 nCount = mxShapes->getCount(); + + nCount -= maZOrderList.size(); + nCount -= maUnsortedList.size(); + + if( nCount > 0 ) + { + // first update offsets of added shapes + for (ZOrderHint& rHint : maZOrderList) + rHint.nIs += nCount; + for (ZOrderHint& rHint : maUnsortedList) + rHint.nIs += nCount; + + // second add the already existing shapes in the unsorted list + ZOrderHint aNewHint; + do + { + nCount--; + + aNewHint.nIs = nCount; + aNewHint.nShould = -1; + + maUnsortedList.insert(maUnsortedList.begin(), aNewHint); + } + while( nCount ); + } + + bool bSorted = std::is_sorted(maZOrderList.begin(), maZOrderList.end(), + [](const ZOrderHint& rLeft, const ZOrderHint& rRight) + { return rLeft.nShould < rRight.nShould; } ); + + if (bSorted) + return; // nothin' to do + + // sort z-ordered shapes by nShould field + std::sort(maZOrderList.begin(), maZOrderList.end()); + + uno::Reference xShapes3(mxShapes, uno::UNO_QUERY); + if( xShapes3.is()) + { + uno::Sequence aNewOrder(maZOrderList.size() + maUnsortedList.size()); + auto pNewOrder = aNewOrder.getArray(); + sal_Int32 nIndex = 0; + + for (const ZOrderHint& rHint : maZOrderList) + { + // fill in the gaps from unordered list + for (vector::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; ) + { + pNewOrder[nIndex++] = (*aIt).nIs; + aIt = maUnsortedList.erase(aIt); + } + + pNewOrder[nIndex] = rHint.nIs; + nIndex++; + } + + try + { + xShapes3->sort(aNewOrder); + maZOrderList.clear(); + return; + } + catch (const css::lang::IllegalArgumentException& /*e*/) + {} + } + + // this is the current index, all shapes before that + // index are finished + sal_Int32 nIndex = 0; + for (const ZOrderHint& rHint : maZOrderList) + { + for (vector::iterator aIt = maUnsortedList.begin(); aIt != maUnsortedList.end() && nIndex < rHint.nShould; ) + { + moveShape( (*aIt).nIs, nIndex++ ); + aIt = maUnsortedList.erase(aIt); + + } + + if(rHint.nIs != nIndex ) + moveShape( rHint.nIs, nIndex ); + + nIndex++; + } + maZOrderList.clear(); +} + +void XMLShapeImportHelper::pushGroupForPostProcessing( uno::Reference< drawing::XShapes >& rShapes ) +{ + mpImpl->mpGroupContext = std::make_shared( rShapes, mpImpl->mpGroupContext ); +} + +void XMLShapeImportHelper::addShapeEvents(SdXMLEventContextData& rData) +{ + if (mpImpl->mpGroupContext && mpImpl->mpGroupContext->mxShapes == rData.mxShape) + { + // tdf#127791 wait until a group is popped to set its event data so + // that the events are applied to all its children, which are not available + // at the start of the group tag + mpImpl->mpGroupContext->maEventData.push_back(rData); + } + else + rData.ApplyProperties(); +} + +void XMLShapeImportHelper::popGroupAndPostProcess() +{ + SAL_WARN_IF( !mpImpl->mpGroupContext, "xmloff", "No context to sort!" ); + if( !mpImpl->mpGroupContext ) + return; + + try + { + mpImpl->mpGroupContext->popGroupAndPostProcess(); + } + catch( const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "exception while sorting shapes, sorting failed"); + } + + // put parent on top and drop current context, we are done + mpImpl->mpGroupContext = mpImpl->mpGroupContext->mpParentContext; +} + +void XMLShapeImportHelper::shapeWithZIndexAdded( css::uno::Reference< css::drawing::XShape > const & xShape, sal_Int32 nZIndex ) +{ + if( !mpImpl->mpGroupContext) + return; + + ZOrderHint aNewHint; + aNewHint.nIs = mpImpl->mpGroupContext->mnCurrentZ++; + aNewHint.nShould = nZIndex; + aNewHint.xShape = xShape; + + if( nZIndex == -1 ) + { + // don't care, so add to unsorted list + mpImpl->mpGroupContext->maUnsortedList.push_back(aNewHint); + } + else + { + // insert into sort list + mpImpl->mpGroupContext->maZOrderList.push_back(aNewHint); + } +} + +void XMLShapeImportHelper::shapeRemoved(const uno::Reference& xShape) +{ + auto it = std::find_if(mpImpl->mpGroupContext->maZOrderList.begin(), mpImpl->mpGroupContext->maZOrderList.end(), [&xShape](const ZOrderHint& rHint) + { + return rHint.xShape == xShape; + }); + if (it == mpImpl->mpGroupContext->maZOrderList.end()) + // Part of the unsorted list, nothing to do. + return; + + sal_Int32 nZIndex = it->nIs; + + for (it = mpImpl->mpGroupContext->maZOrderList.begin(); it != mpImpl->mpGroupContext->maZOrderList.end();) + { + if (it->nIs == nZIndex) + { + // This is xShape: remove it and adjust the max of indexes + // accordingly. + it = mpImpl->mpGroupContext->maZOrderList.erase(it); + mpImpl->mpGroupContext->mnCurrentZ--; + continue; + } + else if (it->nIs > nZIndex) + // On top of xShape: adjust actual index to reflect removal. + it->nIs--; + + // On top of or below xShape. + ++it; + } +} + +void XMLShapeImportHelper::addShapeConnection( css::uno::Reference< css::drawing::XShape > const & rConnectorShape, + bool bStart, + const OUString& rDestShapeId, + sal_Int32 nDestGlueId ) +{ + ConnectionHint aHint; + aHint.mxConnector = rConnectorShape; + aHint.bStart = bStart; + aHint.aDestShapeId = rDestShapeId; + aHint.nDestGlueId = nDestGlueId; + + mpImpl->maConnections.push_back( aHint ); +} + +void XMLShapeImportHelper::restoreConnections() +{ + const vector::size_type nCount = mpImpl->maConnections.size(); + for( vector::size_type i = 0; i < nCount; i++ ) + { + ConnectionHint& rHint = mpImpl->maConnections[i]; + uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY ); + if( xConnector.is() ) + { + // #86637# remember line deltas + uno::Any aLine1Delta; + uno::Any aLine2Delta; + uno::Any aLine3Delta; + OUString aStr1("EdgeLine1Delta"); + OUString aStr2("EdgeLine2Delta"); + OUString aStr3("EdgeLine3Delta"); + aLine1Delta = xConnector->getPropertyValue(aStr1); + aLine2Delta = xConnector->getPropertyValue(aStr2); + aLine3Delta = xConnector->getPropertyValue(aStr3); + + // #86637# simply setting these values WILL force the connector to do + // a new layout promptly. So the line delta values have to be rescued + // and restored around connector changes. + uno::Reference< drawing::XShape > xShape( + mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY ); + if( xShape.is() ) + { + if (rHint.bStart) + xConnector->setPropertyValue( gsStartShape, uno::Any(xShape) ); + else + xConnector->setPropertyValue( gsEndShape, uno::Any(xShape) ); + + sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId ); + if(rHint.bStart) + xConnector->setPropertyValue( gsStartGluePointIndex, uno::Any(nGlueId) ); + else + xConnector->setPropertyValue( gsEndGluePointIndex, uno::Any(nGlueId) ); + } + + // #86637# restore line deltas + xConnector->setPropertyValue(aStr1, aLine1Delta ); + xConnector->setPropertyValue(aStr2, aLine2Delta ); + xConnector->setPropertyValue(aStr3, aLine3Delta ); + } + } + mpImpl->maConnections.clear(); +} + +SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport ) +{ + rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rModel, rImport ); + rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, false ); + SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport ); + + // chain text attributes + pResult->ChainImportMapper( XMLTextImportHelper::CreateParaExtPropMapper( rImport ) ); + return pResult; +} + +/** adds a mapping for a gluepoint identifier from an xml file to the identifier created after inserting + the new gluepoint into the core. The saved mappings can be retrieved by getGluePointId() */ +void XMLShapeImportHelper::addGluePointMapping( css::uno::Reference< css::drawing::XShape > const & xShape, + sal_Int32 nSourceId, sal_Int32 nDestinnationId ) +{ + if( mpPageContext ) + mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId; +} + +/** moves all current DestinationId's by n */ +void XMLShapeImportHelper::moveGluePointMapping( const css::uno::Reference< css::drawing::XShape >& xShape, const sal_Int32 n ) +{ + if( mpPageContext ) + { + ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) ); + if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() ) + { + for ( auto& rShapeId : (*aShapeIter).second ) + { + if ( rShapeId.second != -1 ) + rShapeId.second += n; + } + } + } +} + +/** retrieves a mapping for a gluepoint identifier from the current xml file to the identifier created after + inserting the new gluepoint into the core. The mapping must be initialized first with addGluePointMapping() */ +sal_Int32 XMLShapeImportHelper::getGluePointId( const css::uno::Reference< css::drawing::XShape >& xShape, sal_Int32 nSourceId ) +{ + if( mpPageContext ) + { + ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) ); + if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() ) + { + GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId); + if( aIdIter != (*aShapeIter).second.end() ) + return (*aIdIter).second; + } + } + + return -1; +} + +/** this method must be calling before the first shape is imported for the given page */ +void XMLShapeImportHelper::startPage( css::uno::Reference< css::drawing::XShapes > const & rShapes ) +{ + const std::shared_ptr pOldContext = mpPageContext; + mpPageContext = std::make_shared(); + mpPageContext->mpNext = pOldContext; + mpPageContext->mxShapes = rShapes; +} + +/** this method must be calling after the last shape is imported for the given page */ +void XMLShapeImportHelper::endPage( css::uno::Reference< css::drawing::XShapes > const & rShapes ) +{ + SAL_WARN_IF( !mpPageContext || (mpPageContext->mxShapes != rShapes), "xmloff", "wrong call to endPage(), no startPage called or wrong page" ); + if( nullptr == mpPageContext ) + return; + + restoreConnections(); + + mpPageContext = mpPageContext->mpNext; +} + +/** defines if the import should increment the progress bar or not */ +void XMLShapeImportHelper::enableHandleProgressBar() +{ + mpImpl->mbHandleProgressBar = true; +} + +bool XMLShapeImportHelper::IsHandleProgressBarEnabled() const +{ + return mpImpl->mbHandleProgressBar; +} + +/** queries the capability of the current model to create presentation shapes */ +bool XMLShapeImportHelper::IsPresentationShapesSupported() const +{ + return mpImpl->mbIsPresentationShapesSupported; +} + +const rtl::Reference< XMLTableImport >& XMLShapeImportHelper::GetShapeTableImport() +{ + if( !mxShapeTableImport.is() ) + { + rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrImporter.GetModel(), mrImporter ) ); + rtl::Reference< XMLPropertySetMapper > xPropertySetMapper( new XMLShapePropertySetMapper( xFactory, false ) ); + mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory ); + } + + return mxShapeTableImport; +} + +void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink ) +{ + msHyperlink = rHyperlink; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/xexptran.cxx b/xmloff/source/draw/xexptran.cxx new file mode 100644 index 000000000..776401fb2 --- /dev/null +++ b/xmloff/source/draw/xexptran.cxx @@ -0,0 +1,1057 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using std::make_unique; + +// parsing help functions for simple chars +static void Imp_SkipSpaces(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen) +{ + while(rPos < nLen + && ' ' == rStr[rPos]) + rPos++; +} + +static void Imp_SkipSpacesAndOpeningBraces(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen) +{ + while(rPos < nLen + && (' ' == rStr[rPos] || '(' == rStr[rPos])) + rPos++; +} + +static void Imp_SkipSpacesAndCommas(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen) +{ + while(rPos < nLen + && (' ' == rStr[rPos] || ',' == rStr[rPos])) + rPos++; +} + +static void Imp_SkipSpacesAndClosingBraces(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen) +{ + while(rPos < nLen + && (' ' == rStr[rPos] || ')' == rStr[rPos])) + rPos++; +} + +// parsing help functions for integer numbers + +static bool Imp_IsOnUnitChar(std::u16string_view rStr, const sal_Int32 nPos) +{ + sal_Unicode aChar(rStr[nPos]); + + return ('a' <= aChar && 'z' >= aChar) + || ('A' <= aChar && 'Z' >= aChar) + || '%' == aChar; +} + +static double Imp_GetDoubleChar(std::u16string_view rStr, sal_Int32& rPos, const sal_Int32 nLen, + const SvXMLUnitConverter& rConv, double fRetval, bool bLookForUnits = false) +{ + sal_Unicode aChar(rStr[rPos]); + OUStringBuffer sNumberString(32); + + if('+' == aChar || '-' == aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + } + + while(('0' <= aChar && '9' >= aChar) + || '.' == aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + } + + if('e' == aChar || 'E' == aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + + if('+' == aChar || '-' == aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + } + + while('0' <= aChar && '9' >= aChar) + { + sNumberString.append(rStr[rPos]); + ++rPos; + aChar = rPos >= nLen ? 0 : rStr[rPos]; + } + } + + if(bLookForUnits) + { + Imp_SkipSpaces(rStr, rPos, nLen); + while(rPos < nLen && Imp_IsOnUnitChar(rStr, rPos)) + sNumberString.append(rStr[rPos++]); + } + + if(!sNumberString.isEmpty()) + { + if(bLookForUnits) + rConv.convertDouble(fRetval, sNumberString); + else + { + ::sax::Converter::convertDouble(fRetval, sNumberString); + } + } + + return fRetval; +} + +static void Imp_PutDoubleChar(OUString& rStr, double fValue) +{ + OUStringBuffer sStringBuffer; + ::sax::Converter::convertDouble(sStringBuffer, fValue); + rStr += sStringBuffer; +} + +static void Imp_PutDoubleChar(OUStringBuffer& rStr, const SvXMLUnitConverter& rConv, double fValue, + bool bConvertUnits = false) +{ + OUStringBuffer sStringBuffer; + + if(bConvertUnits) + rConv.convertDouble(sStringBuffer, fValue); + else + { + ::sax::Converter::convertDouble(sStringBuffer, fValue); + } + + rStr.append(sStringBuffer); +} + +// base class of all 2D transform objects + +struct ImpSdXMLExpTransObj2DBase +{ + sal_uInt16 mnType; + explicit ImpSdXMLExpTransObj2DBase(sal_uInt16 nType) + : mnType(nType) {} +}; + +// possible object types for 2D + +#define IMP_SDXMLEXP_TRANSOBJ2D_ROTATE 0x0000 +#define IMP_SDXMLEXP_TRANSOBJ2D_SCALE 0x0001 +#define IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE 0x0002 +#define IMP_SDXMLEXP_TRANSOBJ2D_SKEWX 0x0003 +#define IMP_SDXMLEXP_TRANSOBJ2D_SKEWY 0x0004 +#define IMP_SDXMLEXP_TRANSOBJ2D_MATRIX 0x0005 + +// classes of objects, different sizes + +namespace { + +struct ImpSdXMLExpTransObj2DRotate : public ImpSdXMLExpTransObj2DBase +{ + double mfRotate; + explicit ImpSdXMLExpTransObj2DRotate(double fVal) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_ROTATE), mfRotate(fVal) {} +}; +struct ImpSdXMLExpTransObj2DScale : public ImpSdXMLExpTransObj2DBase +{ + ::basegfx::B2DTuple maScale; + explicit ImpSdXMLExpTransObj2DScale(const ::basegfx::B2DTuple& rNew) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SCALE), maScale(rNew) {} +}; +struct ImpSdXMLExpTransObj2DTranslate : public ImpSdXMLExpTransObj2DBase +{ + ::basegfx::B2DTuple maTranslate; + explicit ImpSdXMLExpTransObj2DTranslate(const ::basegfx::B2DTuple& rNew) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE), maTranslate(rNew) {} +}; +struct ImpSdXMLExpTransObj2DSkewX : public ImpSdXMLExpTransObj2DBase +{ + double mfSkewX; + explicit ImpSdXMLExpTransObj2DSkewX(double fVal) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWX), mfSkewX(fVal) {} +}; +struct ImpSdXMLExpTransObj2DSkewY : public ImpSdXMLExpTransObj2DBase +{ + double mfSkewY; + explicit ImpSdXMLExpTransObj2DSkewY(double fVal) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_SKEWY), mfSkewY(fVal) {} +}; +struct ImpSdXMLExpTransObj2DMatrix : public ImpSdXMLExpTransObj2DBase +{ + ::basegfx::B2DHomMatrix maMatrix; + explicit ImpSdXMLExpTransObj2DMatrix(const ::basegfx::B2DHomMatrix& rNew) + : ImpSdXMLExpTransObj2DBase(IMP_SDXMLEXP_TRANSOBJ2D_MATRIX), maMatrix(rNew) {} +}; + +} + +// add members + +void SdXMLImExTransform2D::AddRotate(double fNew) +{ + if(fNew != 0.0) + maList.push_back(std::make_shared(fNew)); +} + +void SdXMLImExTransform2D::AddTranslate(const ::basegfx::B2DTuple& rNew) +{ + if(!rNew.equalZero()) + maList.push_back(std::make_shared(rNew)); +} + +void SdXMLImExTransform2D::AddSkewX(double fNew) +{ + if(fNew != 0.0) + maList.push_back(std::make_shared(fNew)); +} + +// gen string for export +const OUString& SdXMLImExTransform2D::GetExportString(const SvXMLUnitConverter& rConv) +{ + OUStringBuffer aNewString; + OUString aClosingBrace(")"); + OUString aEmptySpace(" "); + + const sal_uInt32 nCount = maList.size(); + for(sal_uInt32 a(0); a < nCount; a++) + { + ImpSdXMLExpTransObj2DBase* pObj = maList[a].get(); + switch(pObj->mnType) + { + case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE : + { + aNewString.append("rotate ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->mfRotate); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SCALE : + { + aNewString.append("scale ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maScale.getX()); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maScale.getY()); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE : + { + aNewString.append("translate ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maTranslate.getX(), true); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maTranslate.getY(), true); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX : + { + aNewString.append("skewX ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->mfSkewX); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY : + { + aNewString.append("skewY ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->mfSkewY); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX : + { + aNewString.append("matrix ("); + + // a + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(0, 0)); + aNewString.append(aEmptySpace); + + // b + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(1, 0)); + aNewString.append(aEmptySpace); + + // c + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(0, 1)); + aNewString.append(aEmptySpace); + + // d + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(1, 1)); + aNewString.append(aEmptySpace); + + // e + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(0, 2), true); + aNewString.append(aEmptySpace); + + // f + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(1, 2), true); + + aNewString.append(aClosingBrace); + break; + } + default : + { + OSL_FAIL("SdXMLImExTransform2D: impossible entry!"); + break; + } + } + + // if not the last entry, add one space to next tag + if(a + 1 != maList.size()) + { + aNewString.append(aEmptySpace); + } + } + + // fill string form OUString + msString = aNewString.makeStringAndClear(); + + return msString; +} + +// sets new string, parses it and generates entries +void SdXMLImExTransform2D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv) +{ + msString = rNew; + maList.clear(); + + if(msString.isEmpty()) + return; + + const OUString aStr = msString; + const sal_Int32 nLen(aStr.getLength()); + + static const OUStringLiteral aString_rotate( u"rotate" ); + static const OUStringLiteral aString_scale( u"scale" ); + static const OUStringLiteral aString_translate( u"translate" ); + static const OUStringLiteral aString_skewX( u"skewX" ); + static const OUStringLiteral aString_skewY( u"skewY" ); + static const OUStringLiteral aString_matrix( u"matrix" ); + + sal_Int32 nPos(0); + + while(nPos < nLen) + { + // skip spaces + Imp_SkipSpaces(aStr, nPos, nLen); + + // look for tag + if(nPos < nLen) + { + if(nPos == aStr.indexOf(aString_rotate, nPos)) + { + double fValue(0.0); + nPos += 6; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared(fValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_scale, nPos)) + { + ::basegfx::B2DTuple aValue(1.0, 1.0); + nPos += 5; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX())); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY())); + + if(aValue.getX() != 1.0 || aValue.getY() != 1.0) + maList.push_back(std::make_shared(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_translate, nPos)) + { + ::basegfx::B2DTuple aValue; + nPos += 9; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true)); + + if(!aValue.equalZero()) + maList.push_back(std::make_shared(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_skewX, nPos)) + { + double fValue(0.0); + nPos += 5; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared(fValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_skewY, nPos)) + { + double fValue(0.0); + nPos += 5; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared(fValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_matrix, nPos)) + { + ::basegfx::B2DHomMatrix aValue; + + nPos += 6; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + + // a + aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // b + aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // c + aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // d + aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // e + aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // f + aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + if(!aValue.isIdentity()) + maList.push_back(std::make_shared(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else + { + nPos++; + } + } + } +} + +void SdXMLImExTransform2D::GetFullTransform(::basegfx::B2DHomMatrix& rFullTrans) +{ + rFullTrans.identity(); + + const sal_uInt32 nCount = maList.size(); + for(sal_uInt32 a(0); a < nCount; a++) + { + ImpSdXMLExpTransObj2DBase* pObj = maList[a].get(); + switch(pObj->mnType) + { + case IMP_SDXMLEXP_TRANSOBJ2D_ROTATE : + { + // #i78696# + // mfRotate is mathematically wrong oriented since we export/import the angle + // values mirrored. This error is fixed in the API, but not yet in the FileFormat. + // For the FileFormat there is a follow-up task (#i78698#) to fix this in the next + // ODF FileFormat version. For now - to emulate the old behaviour - it is necessary + // to mirror the value here + rFullTrans.rotate(static_cast(pObj)->mfRotate * -1.0); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SCALE : + { + const ::basegfx::B2DTuple& rScale = static_cast(pObj)->maScale; + rFullTrans.scale(rScale.getX(), rScale.getY()); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_TRANSLATE : + { + const ::basegfx::B2DTuple& rTranslate = static_cast(pObj)->maTranslate; + rFullTrans.translate(rTranslate.getX(), rTranslate.getY()); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SKEWX : + { + // For to get a mathematical correct matrix from already existing documents, + // mirror the value here. ODF spec is unclear about direction. + rFullTrans.shearX(-tan(static_cast(pObj)->mfSkewX)); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_SKEWY : + { + // LibreOffice does not write skewY, OOo neither. Such files are foreign documents + // or manually set transformations. OOo had used the value as -tan(value) before + // errors were introduced, Scribus 1.5.4 uses it as -tan(value) too, MS Office does + // not shear at all. ODF spec is unclear about direction. + rFullTrans.shearY(-tan(static_cast(pObj)->mfSkewY)); + break; + } + case IMP_SDXMLEXP_TRANSOBJ2D_MATRIX : + { + rFullTrans *= static_cast(pObj)->maMatrix; + break; + } + default : + { + OSL_FAIL("SdXMLImExTransform2D: impossible entry!"); + break; + } + } + } +} + +// base class of all 3D transform objects + +struct ImpSdXMLExpTransObj3DBase +{ + sal_uInt16 mnType; + explicit ImpSdXMLExpTransObj3DBase(sal_uInt16 nType) + : mnType(nType) {} +}; + +// possible object types for 3D + +#define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X 0x0000 +#define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y 0x0001 +#define IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z 0x0002 +#define IMP_SDXMLEXP_TRANSOBJ3D_SCALE 0x0003 +#define IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE 0x0004 +#define IMP_SDXMLEXP_TRANSOBJ3D_MATRIX 0x0005 + +// classes of objects, different sizes + +namespace { + +struct ImpSdXMLExpTransObj3DRotateX : public ImpSdXMLExpTransObj3DBase +{ + double mfRotateX; + explicit ImpSdXMLExpTransObj3DRotateX(double fVal) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X), mfRotateX(fVal) {} +}; +struct ImpSdXMLExpTransObj3DRotateY : public ImpSdXMLExpTransObj3DBase +{ + double mfRotateY; + explicit ImpSdXMLExpTransObj3DRotateY(double fVal) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y), mfRotateY(fVal) {} +}; +struct ImpSdXMLExpTransObj3DRotateZ : public ImpSdXMLExpTransObj3DBase +{ + double mfRotateZ; + explicit ImpSdXMLExpTransObj3DRotateZ(double fVal) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z), mfRotateZ(fVal) {} +}; +struct ImpSdXMLExpTransObj3DScale : public ImpSdXMLExpTransObj3DBase +{ + ::basegfx::B3DTuple maScale; + explicit ImpSdXMLExpTransObj3DScale(const ::basegfx::B3DTuple& rNew) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_SCALE), maScale(rNew) {} +}; +struct ImpSdXMLExpTransObj3DTranslate : public ImpSdXMLExpTransObj3DBase +{ + ::basegfx::B3DTuple maTranslate; + explicit ImpSdXMLExpTransObj3DTranslate(const ::basegfx::B3DTuple& rNew) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE), maTranslate(rNew) {} +}; +struct ImpSdXMLExpTransObj3DMatrix : public ImpSdXMLExpTransObj3DBase +{ + ::basegfx::B3DHomMatrix maMatrix; + explicit ImpSdXMLExpTransObj3DMatrix(const ::basegfx::B3DHomMatrix& rNew) + : ImpSdXMLExpTransObj3DBase(IMP_SDXMLEXP_TRANSOBJ3D_MATRIX), maMatrix(rNew) {} +}; + +} + +// add members + +void SdXMLImExTransform3D::AddMatrix(const ::basegfx::B3DHomMatrix& rNew) +{ + if(!rNew.isIdentity()) + maList.push_back(std::make_shared(rNew)); +} + +void SdXMLImExTransform3D::AddHomogenMatrix(const drawing::HomogenMatrix& xHomMat) +{ + AddMatrix(basegfx::utils::UnoHomogenMatrixToB3DHomMatrix(xHomMat)); +} + +// gen string for export +const OUString& SdXMLImExTransform3D::GetExportString(const SvXMLUnitConverter& rConv) +{ + OUStringBuffer aNewString; + OUString aClosingBrace(")"); + OUString aEmptySpace(" "); + + const sal_uInt32 nCount = maList.size(); + for(sal_uInt32 a(0); a < nCount; a++) + { + ImpSdXMLExpTransObj3DBase* pObj = maList[a].get(); + switch(pObj->mnType) + { + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X : + { + aNewString.append("rotatex ("); + Imp_PutDoubleChar(aNewString, rConv, basegfx::rad2deg( static_cast(pObj)->mfRotateX) ); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y : + { + aNewString.append("rotatey ("); + Imp_PutDoubleChar(aNewString, rConv, basegfx::rad2deg( static_cast(pObj)->mfRotateY) ); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z : + { + aNewString.append("rotatez ("); + Imp_PutDoubleChar(aNewString, rConv, basegfx::rad2deg( static_cast(pObj)->mfRotateZ) ); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_SCALE : + { + aNewString.append("scale ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maScale.getX()); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maScale.getY()); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maScale.getZ()); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE : + { + aNewString.append("translate ("); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maTranslate.getX(), true); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maTranslate.getY(), true); + aNewString.append(aEmptySpace); + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maTranslate.getZ(), true); + aNewString.append(aClosingBrace); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX : + { + aNewString.append("matrix ("); + + // a + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(0, 0)); + aNewString.append(aEmptySpace); + + // b + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(1, 0)); + aNewString.append(aEmptySpace); + + // c + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(2, 0)); + aNewString.append(aEmptySpace); + + // d + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(0, 1)); + aNewString.append(aEmptySpace); + + // e + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(1, 1)); + aNewString.append(aEmptySpace); + + // f + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(2, 1)); + aNewString.append(aEmptySpace); + + // g + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(0, 2)); + aNewString.append(aEmptySpace); + + // h + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(1, 2)); + aNewString.append(aEmptySpace); + + // i + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(2, 2)); + aNewString.append(aEmptySpace); + + // j + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(0, 3), true); + aNewString.append(aEmptySpace); + + // k + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(1, 3), true); + aNewString.append(aEmptySpace); + + // l + Imp_PutDoubleChar(aNewString, rConv, static_cast(pObj)->maMatrix.get(2, 3), true); + + aNewString.append(aClosingBrace); + break; + } + default : + { + OSL_FAIL("SdXMLImExTransform3D: impossible entry!"); + break; + } + } + + // if not the last entry, add one space to next tag + if(a + 1 != maList.size()) + { + aNewString.append(aEmptySpace); + } + } + + // fill string form OUString + msString = aNewString.makeStringAndClear(); + + return msString; +} + +// for Import: constructor with string, parses it and generates entries +SdXMLImExTransform3D::SdXMLImExTransform3D(const OUString& rNew, const SvXMLUnitConverter& rConv) +{ + SetString(rNew, rConv); +} + +// sets new string, parses it and generates entries +void SdXMLImExTransform3D::SetString(const OUString& rNew, const SvXMLUnitConverter& rConv) +{ + msString = rNew; + maList.clear(); + + if(msString.isEmpty()) + return; + + const OUString aStr = msString; + const sal_Int32 nLen(aStr.getLength()); + + static const OUStringLiteral aString_rotatex( u"rotatex" ); + static const OUStringLiteral aString_rotatey( u"rotatey" ); + static const OUStringLiteral aString_rotatez( u"rotatez" ); + static const OUStringLiteral aString_scale( u"scale" ); + static const OUStringLiteral aString_translate( u"translate" ); + static const OUStringLiteral aString_matrix( u"matrix" ); + + sal_Int32 nPos(0); + + while(nPos < nLen) + { + // skip spaces + Imp_SkipSpaces(aStr, nPos, nLen); + + // look for tag + if(nPos < nLen) + { + if(nPos == aStr.indexOf(aString_rotatex, nPos)) + { + double fValue(0.0); + + nPos += 7; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared(basegfx::deg2rad(fValue))); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_rotatey, nPos)) + { + double fValue(0.0); + + nPos += 7; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared(basegfx::deg2rad(fValue))); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_rotatez, nPos)) + { + double fValue(0.0); + + nPos += 7; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + fValue = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, fValue); + if(fValue != 0.0) + maList.push_back(std::make_shared(basegfx::deg2rad(fValue))); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_scale, nPos)) + { + ::basegfx::B3DTuple aValue(1.0, 1.0, 1.0); + + nPos += 5; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX())); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY())); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ())); + + if(1.0 != aValue.getX() || 1.0 != aValue.getY() || 1.0 != aValue.getZ()) + maList.push_back(std::make_shared(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_translate, nPos)) + { + ::basegfx::B3DTuple aValue; + + nPos += 9; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + aValue.setX(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getX(), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setY(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getY(), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + aValue.setZ(Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.getZ(), true)); + + if(!aValue.equalZero()) + maList.push_back(std::make_shared(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else if(nPos == aStr.indexOf(aString_matrix, nPos)) + { + ::basegfx::B3DHomMatrix aValue; + + nPos += 6; + Imp_SkipSpacesAndOpeningBraces(aStr, nPos, nLen); + + // a + aValue.set(0, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // b + aValue.set(1, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // c + aValue.set(2, 0, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 0))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // d + aValue.set(0, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // e + aValue.set(1, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // f + aValue.set(2, 1, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 1))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // g + aValue.set(0, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 2))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // h + aValue.set(1, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 2))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // i + aValue.set(2, 2, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 2))); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // j + aValue.set(0, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(0, 3), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // k + aValue.set(1, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(1, 3), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // l + aValue.set(2, 3, Imp_GetDoubleChar(aStr, nPos, nLen, rConv, aValue.get(2, 3), true)); + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + if(!aValue.isIdentity()) + maList.push_back(std::make_shared(aValue)); + + Imp_SkipSpacesAndClosingBraces(aStr, nPos, nLen); + } + else + { + nPos++; + } + } + } +} + +bool SdXMLImExTransform3D::GetFullHomogenTransform(css::drawing::HomogenMatrix& xHomMat) +{ + ::basegfx::B3DHomMatrix aFullTransform; + GetFullTransform(aFullTransform); + + if(!aFullTransform.isIdentity()) + { + basegfx::utils::B3DHomMatrixToUnoHomogenMatrix(aFullTransform, xHomMat); + return true; + } + + return false; +} + +void SdXMLImExTransform3D::GetFullTransform(::basegfx::B3DHomMatrix& rFullTrans) +{ + rFullTrans.identity(); + + const sal_uInt32 nCount = maList.size(); + for(sal_uInt32 a(0); a < nCount; a++) + { + ImpSdXMLExpTransObj3DBase* pObj = maList[a].get(); + switch(pObj->mnType) + { + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_X : + { + rFullTrans.rotate(static_cast(pObj)->mfRotateX, 0.0, 0.0); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Y : + { + rFullTrans.rotate(0.0, static_cast(pObj)->mfRotateY, 0.0); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_ROTATE_Z : + { + rFullTrans.rotate(0.0, 0.0, static_cast(pObj)->mfRotateZ); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_SCALE : + { + const ::basegfx::B3DTuple& rScale = static_cast(pObj)->maScale; + rFullTrans.scale(rScale.getX(), rScale.getY(), rScale.getZ()); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_TRANSLATE : + { + const ::basegfx::B3DTuple& rTranslate = static_cast(pObj)->maTranslate; + rFullTrans.translate(rTranslate.getX(), rTranslate.getY(), rTranslate.getZ()); + break; + } + case IMP_SDXMLEXP_TRANSOBJ3D_MATRIX : + { + rFullTrans *= static_cast(pObj)->maMatrix; + break; + } + default : + { + OSL_FAIL("SdXMLImExTransform3D: impossible entry!"); + break; + } + } + } +} + +SdXMLImExViewBox::SdXMLImExViewBox(double fX, double fY, double fW, double fH) +: mfX( fX ), + mfY( fY ), + mfW( fW ), + mfH( fH ) +{ +} + +// #100617# Asked vincent hardy: svg:viewBox values may be double precision. +SdXMLImExViewBox::SdXMLImExViewBox(const OUString& rNew, const SvXMLUnitConverter& rConv) +: msString(rNew), + mfX( 0.0 ), + mfY( 0.0 ), + mfW( 1000.0 ), + mfH( 1000.0 ) +{ + if(msString.isEmpty()) + return; + + const OUString aStr = msString; + const sal_Int32 nLen(aStr.getLength()); + sal_Int32 nPos(0); + + // skip starting spaces + Imp_SkipSpaces(aStr, nPos, nLen); + + // get mX, #100617# be prepared for doubles + mfX = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfX); + + // skip spaces and commas + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // get mY, #100617# be prepared for doubles + mfY = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfY); + + // skip spaces and commas + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // get mW, #100617# be prepared for doubles + mfW = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfW); + + // skip spaces and commas + Imp_SkipSpacesAndCommas(aStr, nPos, nLen); + + // get mH, #100617# be prepared for doubles + mfH = Imp_GetDoubleChar(aStr, nPos, nLen, rConv, mfH); + +} + +const OUString& SdXMLImExViewBox::GetExportString() +{ + OUString aNewString; + OUString aEmptySpace(" "); + + Imp_PutDoubleChar(aNewString, mfX); + aNewString += aEmptySpace; + + Imp_PutDoubleChar(aNewString, mfY); + aNewString += aEmptySpace; + + Imp_PutDoubleChar(aNewString, mfW); + aNewString += aEmptySpace; + + Imp_PutDoubleChar(aNewString, mfH); + + // set new string + msString = aNewString; + + return msString; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dobject.cxx b/xmloff/source/draw/ximp3dobject.cxx new file mode 100644 index 000000000..c17defc24 --- /dev/null +++ b/xmloff/source/draw/ximp3dobject.cxx @@ -0,0 +1,369 @@ +/* -*- 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 "ximp3dobject.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + +SdXML3DObjectContext::SdXML3DObjectContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), + mbSetTransform( false ) +{ + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + const OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + maDrawStyleName = sValue; + break; + } + case XML_ELEMENT(DR3D, XML_TRANSFORM): + { + SdXMLImExTransform3D aTransform(sValue, GetImport().GetMM100UnitConverter()); + if(aTransform.NeedsAction()) + mbSetTransform = aTransform.GetFullHomogenTransform(mxHomMat); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DObjectContext::~SdXML3DObjectContext() +{ +} + +void SdXML3DObjectContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + // set parameters + if(mbSetTransform) + { + xPropSet->setPropertyValue("D3DTransformMatrix", uno::Any(mxHomMat)); + } + + // call parent + SdXMLShapeContext::startFastElement(nElement, xAttrList); + } +} + +SdXML3DCubeObjectShapeContext::SdXML3DCubeObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DObjectContext( rImport, xAttrList, rShapes ), + maMinEdge(-2500.0, -2500.0, -2500.0), + maMaxEdge(2500.0, 2500.0, 2500.0) +{ + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(DR3D, XML_MIN_EDGE): + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maMinEdge) + maMinEdge = aNewVec; + break; + } + case XML_ELEMENT(DR3D, XML_MAX_EDGE): + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maMaxEdge) + maMaxEdge = aNewVec; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DCubeObjectShapeContext::~SdXML3DCubeObjectShapeContext() +{ +} + +void SdXML3DCubeObjectShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create shape + AddShape( "com.sun.star.drawing.Shape3DCubeObject" ); + if(!mxShape.is()) + return; + + // add, set style and properties from base shape + SetStyle(); + SdXML3DObjectContext::startFastElement(nElement, xAttrList); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // set parameters + drawing::Position3D aPosition3D; + drawing::Direction3D aDirection3D; + + // convert from min, max to size to be set + maMaxEdge = maMaxEdge - maMinEdge; + + aPosition3D.PositionX = maMinEdge.getX(); + aPosition3D.PositionY = maMinEdge.getY(); + aPosition3D.PositionZ = maMinEdge.getZ(); + + aDirection3D.DirectionX = maMaxEdge.getX(); + aDirection3D.DirectionY = maMaxEdge.getY(); + aDirection3D.DirectionZ = maMaxEdge.getZ(); + + xPropSet->setPropertyValue("D3DPosition", uno::Any(aPosition3D)); + xPropSet->setPropertyValue("D3DSize", uno::Any(aDirection3D)); +} + +SdXML3DSphereObjectShapeContext::SdXML3DSphereObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DObjectContext( rImport, xAttrList, rShapes ), + maCenter(0.0, 0.0, 0.0), + maSphereSize(5000.0, 5000.0, 5000.0) +{ + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(DR3D, XML_CENTER): + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maCenter) + maCenter = aNewVec; + break; + } + case XML_ELEMENT(DR3D, XML_SIZE): + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maSphereSize) + maSphereSize = aNewVec; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DSphereObjectShapeContext::~SdXML3DSphereObjectShapeContext() +{ +} + +void SdXML3DSphereObjectShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create shape + AddShape( "com.sun.star.drawing.Shape3DSphereObject" ); + if(!mxShape.is()) + return; + + // add, set style and properties from base shape + SetStyle(); + SdXML3DObjectContext::startFastElement(nElement, xAttrList); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + // set parameters + drawing::Position3D aPosition3D; + drawing::Direction3D aDirection3D; + + aPosition3D.PositionX = maCenter.getX(); + aPosition3D.PositionY = maCenter.getY(); + aPosition3D.PositionZ = maCenter.getZ(); + + aDirection3D.DirectionX = maSphereSize.getX(); + aDirection3D.DirectionY = maSphereSize.getY(); + aDirection3D.DirectionZ = maSphereSize.getZ(); + + xPropSet->setPropertyValue("D3DPosition", uno::Any(aPosition3D)); + xPropSet->setPropertyValue("D3DSize", uno::Any(aDirection3D)); +} + +SdXML3DPolygonBasedShapeContext::SdXML3DPolygonBasedShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DObjectContext( rImport, xAttrList, rShapes ) +{ + for(auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + OUString sValue = aIter.toString(); + + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + { + maViewBox = sValue; + break; + } + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + { + maPoints = sValue; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DPolygonBasedShapeContext::~SdXML3DPolygonBasedShapeContext() +{ +} + +void SdXML3DPolygonBasedShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + + if(!xPropSet.is()) + return; + + // set parameters + if(!maPoints.isEmpty() && !maViewBox.isEmpty()) + { + // import 2d tools::PolyPolygon from svg:d + basegfx::B2DPolyPolygon aPolyPolygon; + + if(basegfx::utils::importFromSvgD(aPolyPolygon, maPoints, GetImport().needFixPositionAfterZ(), nullptr)) + { + // convert to 3D PolyPolygon + const basegfx::B3DPolyPolygon aB3DPolyPolygon( + basegfx::utils::createB3DPolyPolygonFromB2DPolyPolygon( + aPolyPolygon)); + + // convert to UNO API class PolyPolygonShape3D + drawing::PolyPolygonShape3D aPolyPolygon3D; + basegfx::utils::B3DPolyPolygonToUnoPolyPolygonShape3D( + aB3DPolyPolygon, + aPolyPolygon3D); + + // set polygon data + xPropSet->setPropertyValue("D3DPolyPolygon3D", uno::Any(aPolyPolygon3D)); + } + else + { + OSL_ENSURE(false, "Error on importing svg:d for 3D tools::PolyPolygon (!)"); + } + } + + // call parent + SdXML3DObjectContext::startFastElement(nElement, xAttrList); +} + + +SdXML3DLatheObjectShapeContext::SdXML3DLatheObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DPolygonBasedShapeContext( rImport, xAttrList, rShapes ) +{ +} + +SdXML3DLatheObjectShapeContext::~SdXML3DLatheObjectShapeContext() +{ +} + +void SdXML3DLatheObjectShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create shape + AddShape( "com.sun.star.drawing.Shape3DLatheObject" ); + if(mxShape.is()) + { + // add, set style and properties from base shape + SetStyle(); + SdXML3DPolygonBasedShapeContext::startFastElement(nElement, xAttrList); + } +} + +SdXML3DExtrudeObjectShapeContext::SdXML3DExtrudeObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXML3DPolygonBasedShapeContext( rImport, xAttrList, rShapes ) +{ +} + +SdXML3DExtrudeObjectShapeContext::~SdXML3DExtrudeObjectShapeContext() +{ +} + +void SdXML3DExtrudeObjectShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + AddShape( "com.sun.star.drawing.Shape3DExtrudeObject" ); + if(mxShape.is()) + { + // add, set style and properties from base shape + SetStyle(); + SdXML3DPolygonBasedShapeContext::startFastElement(nElement, xAttrList); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dobject.hxx b/xmloff/source/draw/ximp3dobject.hxx new file mode 100644 index 000000000..2862d094d --- /dev/null +++ b/xmloff/source/draw/ximp3dobject.hxx @@ -0,0 +1,136 @@ +/* -*- 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 +#include +#include "ximpshap.hxx" + +// common shape context + +class SdXML3DObjectContext : public SdXMLShapeContext +{ + // the shape group this object should be created inside + + css::drawing::HomogenMatrix mxHomMat; + bool mbSetTransform; + +public: + + SdXML3DObjectContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DObjectContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// dr3d:3dcube context + +class SdXML3DCubeObjectShapeContext : public SdXML3DObjectContext +{ + ::basegfx::B3DVector maMinEdge; + ::basegfx::B3DVector maMaxEdge; + +public: + + SdXML3DCubeObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DCubeObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// dr3d:3dsphere context + +class SdXML3DSphereObjectShapeContext : public SdXML3DObjectContext +{ + ::basegfx::B3DVector maCenter; + ::basegfx::B3DVector maSphereSize; + +public: + + SdXML3DSphereObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DSphereObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// polygonbased context + +class SdXML3DPolygonBasedShapeContext : public SdXML3DObjectContext +{ + OUString maPoints; + OUString maViewBox; + +public: + + SdXML3DPolygonBasedShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DPolygonBasedShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// dr3d:3dlathe context + +class SdXML3DLatheObjectShapeContext : public SdXML3DPolygonBasedShapeContext +{ +public: + + SdXML3DLatheObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DLatheObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +// dr3d:3dextrude context + +class SdXML3DExtrudeObjectShapeContext : public SdXML3DPolygonBasedShapeContext +{ +public: + + SdXML3DExtrudeObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXML3DExtrudeObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dscene.cxx b/xmloff/source/draw/ximp3dscene.cxx new file mode 100644 index 000000000..31da3652e --- /dev/null +++ b/xmloff/source/draw/ximp3dscene.cxx @@ -0,0 +1,441 @@ +/* -*- 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 +#include +#include + +#include "ximp3dscene.hxx" +#include +#include +#include +#include +#include +#include +#include +#include "eventimp.hxx" +#include "descriptionimp.hxx" + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +// dr3d:3dlight context + +SdXML3DLightContext::SdXML3DLightContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +: SvXMLImportContext( rImport ), + maDiffuseColor(0x00000000), + maDirection(0.0, 0.0, 1.0), + mbEnabled(false), + mbSpecular(false) +{ + // read attributes for the 3DScene + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(DR3D, XML_DIFFUSE_COLOR): + { + ::sax::Converter::convertColor(maDiffuseColor, aIter.toView()); + break; + } + case XML_ELEMENT(DR3D, XML_DIRECTION): + { + ::basegfx::B3DVector aVal; + SvXMLUnitConverter::convertB3DVector(aVal, aIter.toView()); + if (!std::isnan(aVal.getX()) && !std::isnan(aVal.getY()) && !std::isnan(aVal.getZ())) + { + maDirection = aVal; + } + else + { + SAL_WARN("xmloff", "NaNs found in light direction: " << aIter.toString()); + } + break; + } + case XML_ELEMENT(DR3D, XML_ENABLED): + { + (void)::sax::Converter::convertBool(mbEnabled, aIter.toView()); + break; + } + case XML_ELEMENT(DR3D, XML_SPECULAR): + { + (void)::sax::Converter::convertBool(mbSpecular, aIter.toView()); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXML3DLightContext::~SdXML3DLightContext() +{ +} + + +SdXML3DSceneShapeContext::SdXML3DSceneShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShapes ), SdXML3DSceneAttributesHelper( rImport ) +{ +} + +SdXML3DSceneShapeContext::~SdXML3DSceneShapeContext() +{ +} + +void SdXML3DSceneShapeContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create new 3DScene shape and add it to rShapes, use it + // as base for the new 3DScene import + AddShape( "com.sun.star.drawing.Shape3DSceneObject" ); + if( mxShape.is() ) + { + SetStyle(); + + mxChildren.set( mxShape, uno::UNO_QUERY ); + if( mxChildren.is() ) + GetImport().GetShapeImport()->pushGroupForPostProcessing( mxChildren ); + + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + } + + // read attributes for the 3DScene + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + processSceneAttribute( aIter ); + + // #91047# call parent function is missing here, added it + if(mxShape.is()) + { + // call parent + SdXMLShapeContext::startFastElement(nElement, xAttrList); + } +} + +void SdXML3DSceneShapeContext::endFastElement(sal_Int32 nElement) +{ + if(!mxShape.is()) + return; + + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + setSceneAttributes( xPropSet ); + } + + if( mxChildren.is() ) + GetImport().GetShapeImport()->popGroupAndPostProcess(); + + // call parent + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXML3DSceneShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + switch (nElement) + { + // #i68101# + case XML_ELEMENT(SVG, XML_TITLE): + case XML_ELEMENT(SVG_COMPAT, XML_TITLE): + case XML_ELEMENT(SVG, XML_DESC): + case XML_ELEMENT(SVG_COMPAT, XML_DESC): + xContext = new SdXMLDescriptionContext( GetImport(), nElement, mxShape ); + break; + case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS): + xContext = new SdXMLEventsContext( GetImport(), mxShape ); + break; + // look for local light context first + case XML_ELEMENT(DR3D, XML_LIGHT): + // dr3d:light inside dr3d:scene context + xContext = create3DLightContext( xAttrList ); + break; + default: + // call GroupChildContext function at common ShapeImport + return XMLShapeImportHelper::Create3DSceneChildContext( + GetImport(), nElement, xAttrList, mxChildren); + } + return xContext; +} + +SdXML3DSceneAttributesHelper::SdXML3DSceneAttributesHelper( SvXMLImport& rImporter ) +: mrImport( rImporter ), + mbSetTransform( false ), + mxPrjMode(drawing::ProjectionMode_PERSPECTIVE), + mnDistance(1000), + mnFocalLength(1000), + mnShadowSlant(0), + mxShadeMode(drawing::ShadeMode_SMOOTH), + maAmbientColor(0x00666666), + mbLightingMode(false), + maVRP(0.0, 0.0, 1.0), + maVPN(0.0, 0.0, 1.0), + maVUP(0.0, 1.0, 0.0), + mbVRPUsed(false) +{ +} + +/** creates a 3d light context and adds it to the internal list for later processing */ +SvXMLImportContext * SdXML3DSceneAttributesHelper::create3DLightContext( const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + const rtl::Reference xContext{new SdXML3DLightContext(mrImport, xAttrList)}; + + // remember SdXML3DLightContext for later evaluation + maList.push_back(xContext); + + return xContext.get(); +} + +/** this should be called for each scene attribute */ +void SdXML3DSceneAttributesHelper::processSceneAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + auto nAttributeToken = aIter.getToken(); + if( !IsTokenInNamespace(nAttributeToken, XML_NAMESPACE_DR3D) ) + return; + + switch(nAttributeToken & TOKEN_MASK) + { + case XML_TRANSFORM: + { + SdXMLImExTransform3D aTransform(aIter.toString(), mrImport.GetMM100UnitConverter()); + if(aTransform.NeedsAction()) + mbSetTransform = aTransform.GetFullHomogenTransform(mxHomMat); + return; + } + case XML_VRP: + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maVRP) + { + maVRP = aNewVec; + mbVRPUsed = true; + } + return; + } + case XML_VPN: + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maVPN) + { + maVPN = aNewVec; + } + return; + } + case XML_VUP: + { + ::basegfx::B3DVector aNewVec; + SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); + + if(aNewVec != maVUP) + { + maVUP = aNewVec; + } + return; + } + case XML_PROJECTION: + { + if( IsXMLToken( aIter, XML_PARALLEL ) ) + mxPrjMode = drawing::ProjectionMode_PARALLEL; + else + mxPrjMode = drawing::ProjectionMode_PERSPECTIVE; + return; + } + case XML_DISTANCE: + { + mrImport.GetMM100UnitConverter().convertMeasureToCore(mnDistance, + aIter.toView()); + return; + } + case XML_FOCAL_LENGTH: + { + mrImport.GetMM100UnitConverter().convertMeasureToCore(mnFocalLength, + aIter.toView()); + return; + } + case XML_SHADOW_SLANT: + { + ::sax::Converter::convertNumber(mnShadowSlant, aIter.toView()); + return; + } + case XML_SHADE_MODE: + { + if( IsXMLToken( aIter, XML_FLAT ) ) + mxShadeMode = drawing::ShadeMode_FLAT; + else if( IsXMLToken( aIter, XML_PHONG ) ) + mxShadeMode = drawing::ShadeMode_PHONG; + else if( IsXMLToken( aIter, XML_GOURAUD ) ) + mxShadeMode = drawing::ShadeMode_SMOOTH; + else + mxShadeMode = drawing::ShadeMode_DRAFT; + return; + } + case XML_AMBIENT_COLOR: + { + ::sax::Converter::convertColor(maAmbientColor, aIter.toView()); + return; + } + case XML_LIGHTING_MODE: + { + (void)::sax::Converter::convertBool(mbLightingMode, aIter.toView()); + return; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +/** this sets the scene attributes at this propertyset */ +void SdXML3DSceneAttributesHelper::setSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet ) +{ + uno::Any aAny; + + // world transformation + if(mbSetTransform) + { + xPropSet->setPropertyValue("D3DTransformMatrix", uno::Any(mxHomMat)); + } + + // distance + xPropSet->setPropertyValue("D3DSceneDistance", uno::Any(mnDistance)); + // focalLength + xPropSet->setPropertyValue("D3DSceneFocalLength", uno::Any(mnFocalLength)); + // shadowSlant + xPropSet->setPropertyValue("D3DSceneShadowSlant", uno::Any(static_cast(mnShadowSlant))); + // shadeMode + xPropSet->setPropertyValue("D3DSceneShadeMode", uno::Any(mxShadeMode)); + // ambientColor + xPropSet->setPropertyValue("D3DSceneAmbientColor", uno::Any(maAmbientColor)); + // lightingMode + xPropSet->setPropertyValue("D3DSceneTwoSidedLighting", uno::Any(mbLightingMode)); + + if( !maList.empty() ) + { + uno::Any aAny2; + uno::Any aAny3; + + // set lights + for( size_t a = 0; a < maList.size(); a++) + { + SdXML3DLightContext* pCtx = maList[ a ].get(); + + // set anys + aAny <<= pCtx->GetDiffuseColor(); + drawing::Direction3D aLightDir; + aLightDir.DirectionX = pCtx->GetDirection().getX(); + aLightDir.DirectionY = pCtx->GetDirection().getY(); + aLightDir.DirectionZ = pCtx->GetDirection().getZ(); + aAny2 <<= aLightDir; + aAny3 <<= pCtx->GetEnabled(); + + switch(a) + { + case 0: + { + xPropSet->setPropertyValue("D3DSceneLightColor1", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection1", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn1", aAny3); + break; + } + case 1: + { + xPropSet->setPropertyValue("D3DSceneLightColor2", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection2", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn2", aAny3); + break; + } + case 2: + { + xPropSet->setPropertyValue("D3DSceneLightColor3", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection3", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn3", aAny3); + break; + } + case 3: + { + xPropSet->setPropertyValue("D3DSceneLightColor4", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection4", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn4", aAny3); + break; + } + case 4: + { + xPropSet->setPropertyValue("D3DSceneLightColor5", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection5", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn5", aAny3); + break; + } + case 5: + { + xPropSet->setPropertyValue("D3DSceneLightColor6", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection6", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn6", aAny3); + break; + } + case 6: + { + xPropSet->setPropertyValue("D3DSceneLightColor7", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection7", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn7", aAny3); + break; + } + case 7: + { + xPropSet->setPropertyValue("D3DSceneLightColor8", aAny); + xPropSet->setPropertyValue("D3DSceneLightDirection8", aAny2); + xPropSet->setPropertyValue("D3DSceneLightOn8", aAny3); + break; + } + } + } + } + + // CameraGeometry and camera settings + drawing::CameraGeometry aCamGeo; + aCamGeo.vrp.PositionX = maVRP.getX(); + aCamGeo.vrp.PositionY = maVRP.getY(); + aCamGeo.vrp.PositionZ = maVRP.getZ(); + aCamGeo.vpn.DirectionX = maVPN.getX(); + aCamGeo.vpn.DirectionY = maVPN.getY(); + aCamGeo.vpn.DirectionZ = maVPN.getZ(); + aCamGeo.vup.DirectionX = maVUP.getX(); + aCamGeo.vup.DirectionY = maVUP.getY(); + aCamGeo.vup.DirectionZ = maVUP.getZ(); + xPropSet->setPropertyValue("D3DCameraGeometry", uno::Any(aCamGeo)); + + // #91047# set drawing::ProjectionMode AFTER camera geometry is set + // projection "D3DScenePerspective" drawing::ProjectionMode + xPropSet->setPropertyValue("D3DScenePerspective", uno::Any(mxPrjMode)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dscene.hxx b/xmloff/source/draw/ximp3dscene.hxx new file mode 100644 index 000000000..b0155591e --- /dev/null +++ b/xmloff/source/draw/ximp3dscene.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/. + * + * 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 +#include +#include "ximpshap.hxx" + +// dr3d:3dscene context + +class SdXML3DSceneShapeContext : public SdXMLShapeContext, public SdXML3DSceneAttributesHelper +{ + // the shape group this group is working on + // this is the scene at the same time + css::uno::Reference< css::drawing::XShapes > mxChildren; + +public: + + SdXML3DSceneShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXML3DSceneShapeContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpbody.cxx b/xmloff/source/draw/ximpbody.cxx new file mode 100644 index 000000000..198503eab --- /dev/null +++ b/xmloff/source/draw/ximpbody.cxx @@ -0,0 +1,346 @@ +/* -*- 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 "ximpbody.hxx" +#include +#include "ximpnote.hxx" +#include +#include +#include +#include +#include "ximpstyl.hxx" +#include +#include +#include + +#include +#include +#include "ximpshow.hxx" +#include "layerimp.hxx" +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SdXMLDrawPageContext::SdXMLDrawPageContext( SdXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLGenericPageContext( rImport, xAttrList, rShapes ) +, mbHadSMILNodes( false ) +{ + bool bHaveXmlId( false ); + OUString sXmlId, sStyleName, sContextName, sMasterPageName, sHREF; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_NAME): + { + sContextName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + sStyleName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_MASTER_PAGE_NAME): + { + sMasterPageName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_PRESENTATION_PAGE_LAYOUT_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESENTATION_PAGE_LAYOUT_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESENTATION_PAGE_LAYOUT_NAME): + { + maPageLayoutName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_HEADER_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_HEADER_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_HEADER_NAME): + { + maUseHeaderDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_FOOTER_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_FOOTER_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_FOOTER_NAME): + { + maUseFooterDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_DATE_TIME_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_DATE_TIME_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_DATE_TIME_NAME): + { + maUseDateTimeDeclName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_ID): + { + if (!bHaveXmlId) { sXmlId = sValue; } + } + break; + case XML_ELEMENT(XML, XML_ID): + { + sXmlId = sValue; + bHaveXmlId = true; + } + break; + case XML_ELEMENT(XLINK, XML_HREF): + { + sHREF = sValue; + break; + } + } + } + + if (!sXmlId.isEmpty()) + { + uno::Reference< uno::XInterface > const xRef( rShapes ); + GetImport().getInterfaceToIdentifierMapper().registerReference( + sXmlId, xRef ); + } + GetImport().GetShapeImport()->startPage( rShapes ); + + uno::Reference< drawing::XDrawPage > xShapeDrawPage(rShapes, uno::UNO_QUERY); + + // set PageName? + if(!sContextName.isEmpty()) + { + if(xShapeDrawPage.is()) + { + uno::Reference < container::XNamed > xNamed(xShapeDrawPage, uno::UNO_QUERY); + if(xNamed.is()) + xNamed->setName(sContextName); + } + } + + // set MasterPage? + if(!sMasterPageName.isEmpty()) + { + // #85906# Code for setting masterpage needs complete rework + // since GetSdImport().GetMasterStylesContext() gives always ZERO + // because of content/style file split. Now the mechanism is to + // compare the wanted masterpage-name with the existing masterpages + // which were loaded and created in the styles section loading. + uno::Reference< drawing::XDrawPages > xMasterPages(GetSdImport().GetLocalMasterPages(), uno::UNO_QUERY); + uno::Reference < drawing::XMasterPageTarget > xDrawPage(rShapes, uno::UNO_QUERY); + uno::Reference< drawing::XDrawPage > xMasterPage; + + if(xDrawPage.is() && xMasterPages.is()) + { + bool bDone(false); + OUString sDisplayName( rImport.GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, sMasterPageName ) ); + + for(sal_Int32 a = 0; !bDone && a < xMasterPages->getCount(); a++) + { + uno::Any aAny(xMasterPages->getByIndex(a)); + aAny >>= xMasterPage; + + if(xMasterPage.is()) + { + uno::Reference < container::XNamed > xMasterNamed(xMasterPage, uno::UNO_QUERY); + if(xMasterNamed.is()) + { + OUString sLoopMasterPageName = xMasterNamed->getName(); + + if(!sLoopMasterPageName.isEmpty() && sLoopMasterPageName == sDisplayName) + { + xDrawPage->setMasterPage(xMasterPage); + bDone = true; + } + } + } + } + + SAL_WARN_IF( !bDone, "xmloff", "xmloff::SdXMLDrawPageContext::SdXMLDrawPageContext(), could not find a master slide!" ); + } + } + + SetStyle( sStyleName ); + + if( !sHREF.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xProps( xShapeDrawPage, uno::UNO_QUERY ); + if( xProps.is() ) + { + sal_Int32 nIndex = sHREF.lastIndexOf( '#' ); + if( nIndex != -1 ) + { + OUString aFileName( sHREF.copy( 0, nIndex ) ); + std::u16string_view aBookmarkName( sHREF.subView( nIndex+1 ) ); + + sHREF = GetImport().GetAbsoluteReference( aFileName ) + "#" + + aBookmarkName; + } + + xProps->setPropertyValue("BookmarkURL", uno::Any( sHREF ) ); + } + } + + SetLayout(); + + DeleteAllShapes(); +} + +SdXMLDrawPageContext::~SdXMLDrawPageContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLDrawPageContext::createFastChildContext(sal_Int32 nElement, + const css::uno::Reference& xAttrList) +{ + // some special objects inside draw:page context + switch(nElement) + { + case XML_ELEMENT(PRESENTATION, XML_NOTES): + case XML_ELEMENT(PRESENTATION_SO52, XML_NOTES): + case XML_ELEMENT(PRESENTATION_OOO, XML_NOTES): + { + if( GetSdImport().IsImpress() ) + { + // get notes page + uno::Reference< presentation::XPresentationPage > xPresPage(GetLocalShapesContext(), uno::UNO_QUERY); + if(xPresPage.is()) + { + uno::Reference< drawing::XDrawPage > xNotesDrawPage = xPresPage->getNotesPage(); + if(xNotesDrawPage.is()) + { + // presentation:notes inside draw:page context + return new SdXMLNotesContext( GetSdImport(), xAttrList, xNotesDrawPage); + } + } + } + break; + } + case XML_ELEMENT(ANIMATION, XML_PAR): + case XML_ELEMENT(ANIMATION_OOO, XML_PAR): + case XML_ELEMENT(ANIMATION, XML_SEQ): + case XML_ELEMENT(ANIMATION_OOO, XML_SEQ): + { + if( GetSdImport().IsImpress() ) + { + uno::Reference< animations::XAnimationNodeSupplier > xNodeSupplier(GetLocalShapesContext(), uno::UNO_QUERY); + if(xNodeSupplier.is()) + { + mbHadSMILNodes = true; + return new xmloff::AnimationNodeContext( xNodeSupplier->getAnimationNode(), GetSdImport(), nElement, xAttrList ); + } + } + break; + } + case XML_ELEMENT(DRAW, XML_LAYER_SET): + { + return new SdXMLLayerSetContext( GetSdImport() ); + } + } + + // call parent when no own context was created + return SdXMLGenericPageContext::createFastChildContext(nElement, xAttrList); +} + +void SdXMLDrawPageContext::endFastElement(sal_Int32 nElement) +{ + SdXMLGenericPageContext::endFastElement(nElement); + GetImport().GetShapeImport()->endPage(GetLocalShapesContext()); + + if( mbHadSMILNodes ) + { + uno::Reference< animations::XAnimationNodeSupplier > xNodeSupplier(GetLocalShapesContext(), uno::UNO_QUERY); + uno::Reference< beans::XPropertySet > xPageProps( GetLocalShapesContext(), uno::UNO_QUERY ); + if(xNodeSupplier.is()) + xmloff::AnimationNodeContext::postProcessRootNode( xNodeSupplier->getAnimationNode(), xPageProps ); + } +} + +SdXMLBodyContext::SdXMLBodyContext( SdXMLImport& rImport ) +: SvXMLImportContext( rImport ) +{ +} + +SdXMLBodyContext::~SdXMLBodyContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLBodyContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + switch (nElement) + { + case XML_ELEMENT(PRESENTATION, XML_SETTINGS): + case XML_ELEMENT(PRESENTATION_SO52, XML_SETTINGS): + case XML_ELEMENT(PRESENTATION_OOO, XML_SETTINGS): + { + return new SdXMLShowsContext( GetSdImport(), xAttrList ); + } + case XML_ELEMENT(DRAW, XML_PAGE): + { + // only read the first page in preview mode + if( (GetSdImport().GetNewPageCount() == 0) || !GetSdImport().IsPreview() ) + { + // import this page + uno::Reference< drawing::XDrawPage > xNewDrawPage; + uno::Reference< drawing::XDrawPages > xDrawPages(GetSdImport().GetLocalDrawPages(), uno::UNO_QUERY); + + if( !xDrawPages.is() ) + break; + + if(GetSdImport().GetNewPageCount() + 1 > xDrawPages->getCount()) + { + // new page, create and insert + xNewDrawPage = xDrawPages->insertNewByIndex(xDrawPages->getCount()); + } + else + { + // existing page, use it + uno::Any aAny(xDrawPages->getByIndex(GetSdImport().GetNewPageCount())); + aAny >>= xNewDrawPage; + } + + // increment global import page counter + GetSdImport().IncrementNewPageCount(); + + if(xNewDrawPage.is()) + { + // draw:page inside office:body context + return new SdXMLDrawPageContext(GetSdImport(), xAttrList, xNewDrawPage); + } + } + break; + } + case XML_ELEMENT(PRESENTATION, XML_HEADER_DECL): + case XML_ELEMENT(PRESENTATION, XML_FOOTER_DECL): + case XML_ELEMENT(PRESENTATION, XML_DATE_TIME_DECL): + { + return new SdXMLHeaderFooterDeclContext( GetImport(), xAttrList ); + } + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpbody.hxx b/xmloff/source/draw/ximpbody.hxx new file mode 100644 index 000000000..95d411385 --- /dev/null +++ b/xmloff/source/draw/ximpbody.hxx @@ -0,0 +1,59 @@ +/* -*- 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 +#include "sdxmlimp_impl.hxx" +#include "ximppage.hxx" + +// draw:page context + +class SdXMLDrawPageContext : public SdXMLGenericPageContext +{ + bool mbHadSMILNodes; + +public: + SdXMLDrawPageContext( SdXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLDrawPageContext() override; + + virtual css::uno::Reference< XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 Element, + const css::uno::Reference& Attribs) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +}; + +// office:body context + +class SdXMLBodyContext : public SvXMLImportContext +{ + const SdXMLImport& GetSdImport() const { return static_cast(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + +public: + SdXMLBodyContext( SdXMLImport& rImport ); + virtual ~SdXMLBodyContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpcustomshape.cxx b/xmloff/source/draw/ximpcustomshape.cxx new file mode 100644 index 000000000..fbc32e53e --- /dev/null +++ b/xmloff/source/draw/ximpcustomshape.cxx @@ -0,0 +1,1421 @@ +/* -*- 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 "ximpcustomshape.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::xmloff::EnhancedCustomShapeToken; + + +XMLEnhancedCustomShapeContext::XMLEnhancedCustomShapeContext( SvXMLImport& rImport, + css::uno::Reference< css::drawing::XShape >& rxShape, + std::vector< css::beans::PropertyValue >& rCustomShapeGeometry ) : + SvXMLImportContext( rImport ), + mrUnitConverter( rImport.GetMM100UnitConverter() ), + mrxShape( rxShape ), + mrCustomShapeGeometry( rCustomShapeGeometry ) +{ +} + +const SvXMLEnumMapEntry aXML_GluePointEnumMap[] = +{ + { XML_NONE, 0 }, + { XML_SEGMENTS, 1 }, + { XML_NONE, 2 }, + { XML_RECTANGLE, 3 }, + { XML_TOKEN_INVALID, 0 } +}; +static void GetBool( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + bool bAttrBool; + if (::sax::Converter::convertBool( bAttrBool, rValue )) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= bAttrBool; + rDest.push_back( aProp ); + } +} + +static void GetInt32( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + sal_Int32 nAttrNumber; + if (::sax::Converter::convertNumber( nAttrNumber, rValue )) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= nAttrNumber; + rDest.push_back( aProp ); + } +} + +static void GetDouble( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + double fAttrDouble; + if (::sax::Converter::convertDouble( fAttrDouble, rValue )) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= fAttrDouble; + rDest.push_back( aProp ); + } +} + +static void GetString( std::vector< css::beans::PropertyValue >& rDest, + const OUString& rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= rValue; + rDest.push_back( aProp ); +} + +template +static void GetEnum( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp, + const SvXMLEnumMapEntry& rMap ) +{ + EnumT eKind; + if( SvXMLUnitConverter::convertEnum( eKind, rValue, &rMap ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= static_cast(eKind); + rDest.push_back( aProp ); + } +} + +static void GetDoublePercentage( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString( + rValue, util::MeasureUnit::MM_100TH); + if (util::MeasureUnit::PERCENT != eSrcUnit) + return; + + rtl_math_ConversionStatus eStatus; + double fAttrDouble = rtl_math_stringToDouble(rValue.data(), + rValue.data() + rValue.size(), + '.', ',', &eStatus, nullptr); + if ( eStatus == rtl_math_ConversionStatus_Ok ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= fAttrDouble; + rDest.push_back( aProp ); + } +} + +static void GetB3DVector( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + ::basegfx::B3DVector aB3DVector; + if ( SvXMLUnitConverter::convertB3DVector( aB3DVector, rValue ) ) + { + drawing::Direction3D aDirection3D( aB3DVector.getX(), aB3DVector.getY(), aB3DVector.getZ() ); + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aDirection3D; + rDest.push_back( aProp ); + } +} + +static bool GetEquationName( const OUString& rEquation, const sal_Int32 nStart, OUString& rEquationName ) +{ + sal_Int32 nIndex = nStart; + while( nIndex < rEquation.getLength() ) + { + sal_Unicode nChar = rEquation[ nIndex ]; + if ( + ( ( nChar >= 'a' ) && ( nChar <= 'z' ) ) + || ( ( nChar >= 'A' ) && ( nChar <= 'Z' ) ) + || ( ( nChar >= '0' ) && ( nChar <= '9' ) ) + ) + { + nIndex++; + } + else + break; + } + bool bValid = ( nIndex - nStart ) != 0; + if ( bValid ) + rEquationName = rEquation.copy( nStart, nIndex - nStart ); + return bValid; +} + +static bool GetNextParameter( css::drawing::EnhancedCustomShapeParameter& rParameter, sal_Int32& nIndex, const OUString& rParaString ) +{ + if ( nIndex >= rParaString.getLength() ) + return false; + + bool bValid = true; + bool bNumberRequired = true; + bool bMustBePositiveWholeNumbered = false; + + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::NORMAL; + if ( rParaString[ nIndex ] == '$' ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT; + bMustBePositiveWholeNumbered = true; + nIndex++; + } + else if ( rParaString[ nIndex ] == '?' ) + { + nIndex++; + bNumberRequired = false; + OUString aEquationName; + bValid = GetEquationName( rParaString, nIndex, aEquationName ); + if ( bValid ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::EQUATION; + rParameter.Value <<= aEquationName; + nIndex += aEquationName.getLength(); + } + } + else if ( rParaString[ nIndex ] > '9' ) + { + bNumberRequired = false; + if ( rParaString.matchIgnoreAsciiCase( "left", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::LEFT; + nIndex += 4; + } + else if ( rParaString.matchIgnoreAsciiCase( "top", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::TOP; + nIndex += 3; + } + else if ( rParaString.matchIgnoreAsciiCase( "right", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::RIGHT; + nIndex += 5; + } + else if ( rParaString.matchIgnoreAsciiCase( "bottom", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::BOTTOM; + nIndex += 6; + } + else if ( rParaString.matchIgnoreAsciiCase( "xstretch", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::XSTRETCH; + nIndex += 8; + } + else if ( rParaString.matchIgnoreAsciiCase( "ystretch", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::YSTRETCH; + nIndex += 8; + } + else if ( rParaString.matchIgnoreAsciiCase( "hasstroke", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::HASSTROKE; + nIndex += 9; + } + else if ( rParaString.matchIgnoreAsciiCase( "hasfill", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::HASFILL; + nIndex += 7; + } + else if ( rParaString.matchIgnoreAsciiCase( "width", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::WIDTH; + nIndex += 5; + } + else if ( rParaString.matchIgnoreAsciiCase( "height", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::HEIGHT; + nIndex += 6; + } + else if ( rParaString.matchIgnoreAsciiCase( "logwidth", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::LOGWIDTH; + nIndex += 8; + } + else if ( rParaString.matchIgnoreAsciiCase( "logheight", nIndex ) ) + { + rParameter.Type = css::drawing::EnhancedCustomShapeParameterType::LOGHEIGHT; + nIndex += 9; + } + else + bValid = false; + } + if ( bValid ) + { + if ( bNumberRequired ) + { + sal_Int32 nStartIndex = nIndex; + sal_Int32 nEIndex = 0; // index of "E" in double + + bool bE = false; // set if a double is including a "E" statement + bool bENum = false; // there is at least one number after "E" + bool bDot = false; // set if there is a dot included + bool bEnd = false; // set for each value that can not be part of a double/integer + + while( ( nIndex < rParaString.getLength() ) && bValid ) + { + switch( rParaString[ nIndex ] ) + { + case '.' : + { + if ( bMustBePositiveWholeNumbered ) + bValid = false; + else + { + if ( bDot ) + bValid = false; + else + bDot = true; + } + } + break; + case '-' : + { + if ( bMustBePositiveWholeNumbered ) + bValid = false; + else + { + if ( nStartIndex == nIndex ) + bValid = true; + else if ( bE ) + { + if ( nEIndex + 1 == nIndex ) + bValid = true; + else if ( bENum ) + bEnd = true; + else + bValid = false; + } + } + } + break; + + case 'e' : + case 'E' : + { + if ( bMustBePositiveWholeNumbered ) + bEnd = true; + else + { + if ( !bE ) + { + bE = true; + nEIndex = nIndex; + } + else + bEnd = true; + } + } + break; + case '0' : + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + { + if ( bE && ! bENum ) + bENum = true; + } + break; + default: + bEnd = true; + } + if ( !bEnd ) + nIndex++; + else + break; + } + if ( nIndex == nStartIndex ) + bValid = false; + if ( bValid ) + { + std::u16string_view aNumber( rParaString.subView( nStartIndex, nIndex - nStartIndex ) ); + if ( bE || bDot ) + { + double fAttrDouble; + if (::sax::Converter::convertDouble(fAttrDouble, aNumber)) + rParameter.Value <<= fAttrDouble; + else + bValid = false; + } + else + { + sal_Int32 nValue; + if (::sax::Converter::convertNumber(nValue, aNumber)) + rParameter.Value <<= nValue; + else + bValid = false; + } + } + } + } + if ( bValid ) + { + // skipping white spaces and commas (#i121507#) + const sal_Unicode aSpace(' '); + const sal_Unicode aCommata(','); + + while(nIndex < rParaString.getLength()) + { + const sal_Unicode aCandidate(rParaString[nIndex]); + + if(aSpace == aCandidate || aCommata == aCandidate) + { + nIndex++; + } + else + { + break; + } + } + } + return bValid; +} + +static void GetPosition3D( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:extrusion-viewpoint + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp, + const SvXMLUnitConverter& rUnitConverter ) +{ + drawing::Position3D aPosition3D; + if ( rUnitConverter.convertPosition3D( aPosition3D, rValue ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aPosition3D; + rDest.push_back( aProp ); + } +} + +static void GetDoubleSequence( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:glue-point-leaving-directions + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + std::vector< double > vDirection; + sal_Int32 nIndex = 0; + do + { + double fAttrDouble; + std::string_view aToken( o3tl::getToken(rValue, 0, ',', nIndex ) ); + if (!::sax::Converter::convertDouble( fAttrDouble, aToken )) + break; + else + vDirection.push_back( fAttrDouble ); + } + while ( nIndex >= 0 ); + + if ( !vDirection.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= comphelper::containerToSequence(vDirection); + rDest.push_back( aProp ); + } +} + +static void GetSizeSequence( std::vector< css::beans::PropertyValue >& rDest, + std::string_view rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + std::vector< sal_Int32 > vNum; + sal_Int32 nIndex = 0; + do + { + sal_Int32 n; + std::string_view aToken( o3tl::getToken(rValue, 0, ' ', nIndex ) ); + if (!::sax::Converter::convertNumber( n, aToken )) + break; + else + vNum.push_back( n ); + } + while ( nIndex >= 0 ); + + if ( vNum.empty() ) + return; + + uno::Sequence< awt::Size > aSizeSeq((vNum.size() + 1) / 2); + std::vector< sal_Int32 >::const_iterator aIter = vNum.begin(); + std::vector< sal_Int32 >::const_iterator aEnd = vNum.end(); + awt::Size* pValues = aSizeSeq.getArray(); + + while ( aIter != aEnd ) { + pValues->Width = *aIter++; + if ( aIter != aEnd ) + pValues->Height = *aIter++; + pValues ++; + } + + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aSizeSeq; + rDest.push_back( aProp ); +} + +static void GetEnhancedParameter( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:handle-position + const OUString& rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + sal_Int32 nIndex = 0; + css::drawing::EnhancedCustomShapeParameter aParameter; + if ( GetNextParameter( aParameter, nIndex, rValue ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aParameter; + rDest.push_back( aProp ); + } +} + +static void GetEnhancedParameterPair( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:handle-position + const OUString& rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + sal_Int32 nIndex = 0; + css::drawing::EnhancedCustomShapeParameterPair aParameterPair; + if ( GetNextParameter( aParameterPair.First, nIndex, rValue ) + && GetNextParameter( aParameterPair.Second, nIndex, rValue ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= aParameterPair; + rDest.push_back( aProp ); + } +} + +static sal_Int32 GetEnhancedParameterPairSequence( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:glue-points + const OUString& rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + std::vector< css::drawing::EnhancedCustomShapeParameterPair > vParameter; + css::drawing::EnhancedCustomShapeParameterPair aParameter; + + sal_Int32 nIndex = 0; + while ( GetNextParameter( aParameter.First, nIndex, rValue ) + && GetNextParameter( aParameter.Second, nIndex, rValue ) ) + { + vParameter.push_back( aParameter ); + } + if ( !vParameter.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= comphelper::containerToSequence(vParameter); + rDest.push_back( aProp ); + } + return vParameter.size(); +} + +static void GetEnhancedRectangleSequence( std::vector< css::beans::PropertyValue >& rDest, // e.g. draw:text-areas + const OUString& rValue, const EnhancedCustomShapeTokenEnum eDestProp ) +{ + std::vector< css::drawing::EnhancedCustomShapeTextFrame > vTextFrame; + css::drawing::EnhancedCustomShapeTextFrame aParameter; + + sal_Int32 nIndex = 0; + + while ( GetNextParameter( aParameter.TopLeft.First, nIndex, rValue ) + && GetNextParameter( aParameter.TopLeft.Second, nIndex, rValue ) + && GetNextParameter( aParameter.BottomRight.First, nIndex, rValue ) + && GetNextParameter( aParameter.BottomRight.Second, nIndex, rValue ) ) + { + vTextFrame.push_back( aParameter ); + } + if ( !vTextFrame.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( eDestProp ); + aProp.Value <<= comphelper::containerToSequence(vTextFrame); + rDest.push_back( aProp ); + } +} + +static void +GetEnhancedPath(std::vector& rDest, // e.g. draw:enhanced-path + const OUString& rValue, std::u16string_view rType) +{ + std::vector< css::drawing::EnhancedCustomShapeParameterPair > vCoordinates; + std::vector< css::drawing::EnhancedCustomShapeSegment > vSegments; + + sal_Int32 nIndex = 0; + sal_Int32 nParameterCount = 0; + + sal_Int32 nParametersNeeded = 1; + sal_Int16 nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO; + + bool bValid = true; + + while( bValid && ( nIndex < rValue.getLength() ) ) + { + switch( rValue[ nIndex ] ) + { + case 'M' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO; + nParametersNeeded = 1; + nIndex++; + } + break; + case 'L' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO; + nParametersNeeded = 1; + nIndex++; + } + break; + case 'C' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO; + nParametersNeeded = 3; + nIndex++; + } + break; + case 'Z' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'N' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'F' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'S' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'T' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO; + nParametersNeeded = 3; + nIndex++; + } + break; + case 'U' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE; + nParametersNeeded = 3; + nIndex++; + } + break; + case 'A' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO; + nParametersNeeded = 4; + nIndex++; + } + break; + case 'B' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ARC; + nParametersNeeded = 4; + nIndex++; + } + break; + case 'G' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO; + nParametersNeeded = 2; + nIndex++; + } + break; + case 'H' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::DARKEN; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'I' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::DARKENLESS; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'J' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTEN; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'K' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTENLESS; + nParametersNeeded = 0; + nIndex++; + } + break; + case 'W' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO; + nParametersNeeded = 4; + nIndex++; + } + break; + case 'V' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC; + nParametersNeeded = 4; + nIndex++; + } + break; + case 'X' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX; + nParametersNeeded = 1; + nIndex++; + } + break; + case 'Y' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY; + nParametersNeeded = 1; + nIndex++; + } + break; + case 'Q' : + { + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO; + nParametersNeeded = 2; + nIndex++; + } + break; + case ' ' : + { + nIndex++; + } + break; + + case '$' : + case '?' : + case '0' : + case '1' : + case '2' : + case '3' : + case '4' : + case '5' : + case '6' : + case '7' : + case '8' : + case '9' : + case '.' : + case '-' : + { + css::drawing::EnhancedCustomShapeParameterPair aPair; + if ( GetNextParameter( aPair.First, nIndex, rValue ) && + GetNextParameter( aPair.Second, nIndex, rValue ) ) + { + vCoordinates.push_back( aPair ); + nParameterCount++; + } + else + bValid = false; + } + break; + default: + nIndex++; + break; + } + if ( !nParameterCount && !nParametersNeeded ) + { + css::drawing::EnhancedCustomShapeSegment aSegment; + aSegment.Command = nLatestSegmentCommand; + aSegment.Count = 0; + vSegments.push_back( aSegment ); + nParametersNeeded = 0x7fffffff; + } + else if ( nParameterCount >= nParametersNeeded ) + { + // Special rule for moveto in ODF 1.2 section 19.145 + // "If a moveto is followed by multiple pairs of coordinates, they are treated as lineto." + if ( nLatestSegmentCommand == css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO ) + { + css::drawing::EnhancedCustomShapeSegment aSegment; + aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO; + aSegment.Count = 1; + vSegments.push_back( aSegment ); + nIndex--; + nLatestSegmentCommand = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO; + nParametersNeeded = 1; + } + else + { + // General rule in ODF 1.2. section 19.145 + // "If a command is repeated multiple times, all repeated command characters + // except the first one may be omitted." Thus check if the last command is identical, + // if so, we just need to increment the count + if ( !vSegments.empty() && ( vSegments[ vSegments.size() - 1 ].Command == nLatestSegmentCommand ) ) + vSegments[ vSegments.size() -1 ].Count++; + else + { + css::drawing::EnhancedCustomShapeSegment aSegment; + aSegment.Command = nLatestSegmentCommand; + aSegment.Count = 1; + vSegments.push_back( aSegment ); + } + } + nParameterCount = 0; + } + } + + // Corrections for wrong paths in curvedArrow shapes written by older LO versions + if (!vSegments.empty() + && (rType == u"mso-spt102" || rType == u"mso-spt103" || rType == u"mso-spt104" + || rType == u"mso-spt105") + && vSegments[0].Count == 2) + { + vSegments[0].Count = 1; + css::drawing::EnhancedCustomShapeSegment aSegment; + aSegment.Count = 1; + aSegment.Command + = vSegments[0].Command == css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC + ? css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO + : css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO; + vSegments.insert(vSegments.begin() + 1, aSegment); + } + + // adding the Coordinates property + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_Coordinates ); + aProp.Value <<= comphelper::containerToSequence(vCoordinates); + rDest.push_back( aProp ); + + // adding the Segments property + aProp.Name = EASGet( EAS_Segments ); + aProp.Value <<= comphelper::containerToSequence(vSegments); + rDest.push_back( aProp ); +} + +static void GetAdjustmentValues( std::vector< css::beans::PropertyValue >& rDest, // draw:adjustments + const OUString& rValue ) +{ + std::vector< css::drawing::EnhancedCustomShapeAdjustmentValue > vAdjustmentValue; + css::drawing::EnhancedCustomShapeParameter aParameter; + sal_Int32 nIndex = 0; + while ( GetNextParameter( aParameter, nIndex, rValue ) ) + { + css::drawing::EnhancedCustomShapeAdjustmentValue aAdj; + if ( aParameter.Type == css::drawing::EnhancedCustomShapeParameterType::NORMAL ) + { + aAdj.Value = aParameter.Value; + aAdj.State = beans::PropertyState_DIRECT_VALUE; + } + else + aAdj.State = beans::PropertyState_DEFAULT_VALUE; // this should not be, but better than setting nothing + + vAdjustmentValue.push_back( aAdj ); + } + + sal_Int32 nAdjustmentValues = vAdjustmentValue.size(); + if ( nAdjustmentValues ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_AdjustmentValues ); + aProp.Value <<= comphelper::containerToSequence(vAdjustmentValue); + rDest.push_back( aProp ); + } +} + +void XMLEnhancedCustomShapeContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + sal_Int32 nAttrNumber; + std::optional oSpecularityValue; // for postpone extrusion-specularity + std::optional oPathValue; // for postpone GetEnhancedPath; + OUString sType("non-primitive"); // default in ODF + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( EASGet( aIter.getToken() ) ) + { + case EAS_type : + { + sType = aIter.toString(); + GetString( mrCustomShapeGeometry, sType, EAS_Type ); + } + break; + case EAS_mirror_horizontal : + GetBool( mrCustomShapeGeometry, aIter.toView(), EAS_MirroredX ); + break; + case EAS_mirror_vertical : + GetBool( mrCustomShapeGeometry, aIter.toView(), EAS_MirroredY ); + break; + case EAS_viewBox : + { + SdXMLImExViewBox aViewBox( aIter.toString(), GetImport().GetMM100UnitConverter() ); + awt::Rectangle aRect( aViewBox.GetX(), aViewBox.GetY(), aViewBox.GetWidth(), aViewBox.GetHeight() ); + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_ViewBox ); + aProp.Value <<= aRect; + mrCustomShapeGeometry.push_back( aProp ); + } + break; + case EAS_sub_view_size: + GetSizeSequence( maPath, aIter.toView(), EAS_SubViewSize ); + break; + case EAS_text_rotate_angle : + GetDouble( mrCustomShapeGeometry, aIter.toView(), EAS_TextRotateAngle ); + break; + case EAS_extrusion_allowed : + GetBool( maPath, aIter.toView(), EAS_ExtrusionAllowed ); + break; + case EAS_text_path_allowed : + GetBool( maPath, aIter.toView(), EAS_TextPathAllowed ); + break; + case EAS_concentric_gradient_fill_allowed : + GetBool( maPath, aIter.toView(), EAS_ConcentricGradientFillAllowed ); + break; + case EAS_extrusion : + GetBool( maExtrusion, aIter.toView(), EAS_Extrusion ); + break; + case EAS_extrusion_brightness : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_Brightness ); + break; + case EAS_extrusion_depth : + { + OUString rValue = aIter.toString(); + sal_Int32 nIndex = 0; + css::drawing::EnhancedCustomShapeParameterPair aParameterPair; + css::drawing::EnhancedCustomShapeParameter& rDepth = aParameterPair.First; + if ( GetNextParameter( rDepth, nIndex, rValue ) ) + { + css::drawing::EnhancedCustomShapeParameter& rFraction = aParameterPair.Second; + // try to catch the unit for the depth + sal_Int16 const eSrcUnit( + ::sax::Converter::GetUnitFromString( + rValue, util::MeasureUnit::MM_100TH)); + + OUStringBuffer aUnitStr; + double fFactor = ::sax::Converter::GetConversionFactor( + aUnitStr, util::MeasureUnit::MM_100TH, eSrcUnit); + if ( ( fFactor != 1.0 ) && ( fFactor != 0.0 ) ) + { + double fDepth(0.0); + if ( rDepth.Value >>= fDepth ) + { + fDepth /= fFactor; + rDepth.Value <<= fDepth; + } + } + if ( rValue.matchIgnoreAsciiCase( aUnitStr, nIndex ) ) + nIndex += aUnitStr.getLength(); + + // skipping white spaces + while( ( nIndex < rValue.getLength() ) && rValue[ nIndex ] == ' ' ) + nIndex++; + + if ( GetNextParameter( rFraction, nIndex, rValue ) ) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_Depth ); + aProp.Value <<= aParameterPair; + maExtrusion.push_back( aProp ); + } + } + } + break; + case EAS_extrusion_diffusion : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_Diffusion ); + break; + case EAS_extrusion_number_of_line_segments : + GetInt32( maExtrusion, aIter.toView(), EAS_NumberOfLineSegments ); + break; + case EAS_extrusion_light_face : + GetBool( maExtrusion, aIter.toView(), EAS_LightFace ); + break; + case EAS_extrusion_first_light_harsh : + GetBool( maExtrusion, aIter.toView(), EAS_FirstLightHarsh ); + break; + case EAS_extrusion_second_light_harsh : + GetBool( maExtrusion, aIter.toView(), EAS_SecondLightHarsh ); + break; + case EAS_extrusion_first_light_level : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_FirstLightLevel ); + break; + case EAS_extrusion_second_light_level : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_SecondLightLevel ); + break; + case EAS_extrusion_first_light_direction : + GetB3DVector( maExtrusion, aIter.toView(), EAS_FirstLightDirection ); + break; + case EAS_extrusion_second_light_direction : + GetB3DVector( maExtrusion, aIter.toView(), EAS_SecondLightDirection ); + break; + case EAS_extrusion_metal : + GetBool( maExtrusion, aIter.toView(), EAS_Metal ); + break; + case EAS_extrusion_metal_type : + { + OUString rValue = aIter.toString(); + sal_Int16 eMetalType(drawing::EnhancedCustomShapeMetalType::MetalODF); + if (rValue == "loext:MetalMSCompatible") + eMetalType = drawing::EnhancedCustomShapeMetalType::MetalMSCompatible; + beans::PropertyValue aProp; + aProp.Name = EASGet(EAS_MetalType); + aProp.Value <<= eMetalType; + maExtrusion.push_back(aProp); + } + break; + case EAS_shade_mode : + { + drawing::ShadeMode eShadeMode( drawing::ShadeMode_FLAT ); + if( IsXMLToken( aIter, XML_PHONG ) ) + eShadeMode = drawing::ShadeMode_PHONG; + else if ( IsXMLToken( aIter, XML_GOURAUD ) ) + eShadeMode = drawing::ShadeMode_SMOOTH; + else if ( IsXMLToken( aIter, XML_DRAFT ) ) + eShadeMode = drawing::ShadeMode_DRAFT; + + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_ShadeMode ); + aProp.Value <<= eShadeMode; + maExtrusion.push_back( aProp ); + } + break; + case EAS_extrusion_rotation_angle : + GetEnhancedParameterPair( maExtrusion, aIter.toString(), EAS_RotateAngle ); + break; + case EAS_extrusion_rotation_center : + GetB3DVector( maExtrusion, aIter.toView(), EAS_RotationCenter ); + break; + case EAS_extrusion_shininess : + GetDoublePercentage( maExtrusion, aIter.toView(), EAS_Shininess ); + break; + case EAS_extrusion_skew : + GetEnhancedParameterPair( maExtrusion, aIter.toString(), EAS_Skew ); + break; + case EAS_extrusion_specularity : + if (!oSpecularityValue) + oSpecularityValue = aIter.toView(); + break; + case EAS_extrusion_specularity_loext : + oSpecularityValue = aIter.toView(); + break; + case EAS_projection : + { + drawing::ProjectionMode eProjectionMode( drawing::ProjectionMode_PERSPECTIVE ); + if( IsXMLToken( aIter, XML_PARALLEL ) ) + eProjectionMode = drawing::ProjectionMode_PARALLEL; + + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_ProjectionMode ); + aProp.Value <<= eProjectionMode; + maExtrusion.push_back( aProp ); + } + break; + case EAS_extrusion_viewpoint : + GetPosition3D( maExtrusion, aIter.toView(), EAS_ViewPoint, mrUnitConverter ); + break; + case EAS_extrusion_origin : + GetEnhancedParameterPair( maExtrusion, aIter.toString(), EAS_Origin ); + break; + case EAS_extrusion_color : + GetBool( maExtrusion, aIter.toView(), EAS_Color ); + break; + case EAS_enhanced_path : + oPathValue = aIter.toString(); + break; + case EAS_path_stretchpoint_x : + { + if (::sax::Converter::convertNumber(nAttrNumber, aIter.toView())) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_StretchX ); + aProp.Value <<= nAttrNumber; + maPath.push_back( aProp ); + } + } + break; + case EAS_path_stretchpoint_y : + { + if (::sax::Converter::convertNumber(nAttrNumber, aIter.toView())) + { + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_StretchY ); + aProp.Value <<= nAttrNumber; + maPath.push_back( aProp ); + } + } + break; + case EAS_text_areas : + GetEnhancedRectangleSequence( maPath, aIter.toString(), EAS_TextFrames ); + break; + case EAS_glue_points : + { + sal_Int32 i, nPairs = GetEnhancedParameterPairSequence( maPath, aIter.toString(), EAS_GluePoints ); + GetImport().GetShapeImport()->moveGluePointMapping( mrxShape, nPairs ); + for ( i = 0; i < nPairs; i++ ) + GetImport().GetShapeImport()->addGluePointMapping( mrxShape, i + 4, i + 4 ); + } + break; + case EAS_glue_point_type : + GetEnum( maPath, aIter.toView(), EAS_GluePointType, *aXML_GluePointEnumMap ); + break; + case EAS_glue_point_leaving_directions : + GetDoubleSequence( maPath, aIter.toView(), EAS_GluePointLeavingDirections ); + break; + case EAS_text_path : + GetBool( maTextPath, aIter.toView(), EAS_TextPath ); + break; + case EAS_text_path_mode : + { + css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode( css::drawing::EnhancedCustomShapeTextPathMode_NORMAL ); + if( IsXMLToken( aIter, XML_PATH ) ) + eTextPathMode = css::drawing::EnhancedCustomShapeTextPathMode_PATH; + else if ( IsXMLToken( aIter, XML_SHAPE ) ) + eTextPathMode = css::drawing::EnhancedCustomShapeTextPathMode_SHAPE; + + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_TextPathMode ); + aProp.Value <<= eTextPathMode; + maTextPath.push_back( aProp ); + } + break; + case EAS_text_path_scale : + { + bool bScaleX = IsXMLToken( aIter, XML_SHAPE ); + beans::PropertyValue aProp; + aProp.Name = EASGet( EAS_ScaleX ); + aProp.Value <<= bScaleX; + maTextPath.push_back( aProp ); + } + break; + case EAS_text_path_same_letter_heights : + GetBool( maTextPath, aIter.toView(), EAS_SameLetterHeights ); + break; + case EAS_modifiers : + GetAdjustmentValues( mrCustomShapeGeometry, aIter.toString() ); + break; + default: + break; + } + } + if (oSpecularityValue) + GetDoublePercentage( maExtrusion, *oSpecularityValue, EAS_Specularity ); + if (oPathValue) + GetEnhancedPath(maPath, *oPathValue, sType); +} + +static void SdXMLCustomShapePropertyMerge( std::vector< css::beans::PropertyValue >& rPropVec, + const std::vector< beans::PropertyValues >& rElement, + const OUString& rElementName ) +{ + if ( !rElement.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = rElementName; + aProp.Value <<= comphelper::containerToSequence(rElement); + rPropVec.push_back( aProp ); + } +} + +static void SdXMLCustomShapePropertyMerge( std::vector< css::beans::PropertyValue >& rPropVec, + const std::vector< OUString >& rElement, + const OUString& rElementName ) +{ + if ( !rElement.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = rElementName; + aProp.Value <<= comphelper::containerToSequence(rElement); + rPropVec.push_back( aProp ); + } +} + +static void SdXMLCustomShapePropertyMerge( std::vector< css::beans::PropertyValue >& rPropVec, + const std::vector< css::beans::PropertyValue >& rElement, + const OUString& rElementName ) +{ + if ( !rElement.empty() ) + { + beans::PropertyValue aProp; + aProp.Name = rElementName; + aProp.Value <<= comphelper::containerToSequence(rElement); + rPropVec.push_back( aProp ); + } +} + +typedef std::unordered_map< OUString, sal_Int32 > EquationHashMap; + +/* if rPara.Type is from type EnhancedCustomShapeParameterType::EQUATION, the name of the equation + will be converted from OUString to index */ +static void CheckAndResolveEquationParameter( css::drawing::EnhancedCustomShapeParameter& rPara, EquationHashMap* pH ) +{ + if ( rPara.Type == css::drawing::EnhancedCustomShapeParameterType::EQUATION ) + { + OUString aEquationName; + if ( rPara.Value >>= aEquationName ) + { + sal_Int32 nIndex = 0; + EquationHashMap::iterator aHashIter( pH->find( aEquationName ) ); + if ( aHashIter != pH->end() ) + nIndex = (*aHashIter).second; + rPara.Value <<= nIndex; + } + } +} + +void XMLEnhancedCustomShapeContext::endFastElement(sal_Int32 ) +{ + // resolve properties that are indexing an Equation + if ( !maEquations.empty() ) + { + // creating hash map containing the name and index of each equation + EquationHashMap aH; + std::vector< OUString >::iterator aEquationNameIter = maEquationNames.begin(); + std::vector< OUString >::iterator aEquationNameEnd = maEquationNames.end(); + while( aEquationNameIter != aEquationNameEnd ) + { + aH[ *aEquationNameIter ] = static_cast( aEquationNameIter - maEquationNames.begin() ); + ++aEquationNameIter; + } + + // resolve equation + for( auto& rEquation : maEquations ) + { + sal_Int32 nIndexOf = 0; + do + { + nIndexOf = rEquation.indexOf( '?', nIndexOf ); + if ( nIndexOf != -1 ) + { + OUString aEquationName; + if ( GetEquationName( rEquation, nIndexOf + 1, aEquationName ) ) + { + // copying first characters inclusive '?' + sal_Int32 nIndex = 0; + EquationHashMap::iterator aHashIter( aH.find( aEquationName ) ); + if ( aHashIter != aH.end() ) + nIndex = (*aHashIter).second; + OUString aNew = rEquation.subView( 0, nIndexOf + 1 ) + + OUString::number( nIndex ) + + rEquation.subView( nIndexOf + aEquationName.getLength() + 1 ); + rEquation = aNew; + } + nIndexOf++; + } + } + while( nIndexOf != -1 ); + } + + // Path + for ( const beans::PropertyValue& rPathItem : maPath ) + { + switch( EASGet( rPathItem.Name ) ) + { + case EAS_Coordinates : + case EAS_GluePoints : + { + uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > const & rSeq = + *o3tl::doAccess >( + rPathItem.Value); + for ( const auto& rElem : rSeq ) + { + CheckAndResolveEquationParameter( const_cast(rElem.First), &aH ); + CheckAndResolveEquationParameter( const_cast(rElem.Second), &aH ); + } + } + break; + case EAS_TextFrames : + { + uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > const & rSeq = + *o3tl::doAccess >( + rPathItem.Value); + for ( const auto& rElem : rSeq ) + { + CheckAndResolveEquationParameter( const_cast(rElem.TopLeft.First), &aH ); + CheckAndResolveEquationParameter( const_cast(rElem.TopLeft.Second), &aH ); + CheckAndResolveEquationParameter( const_cast(rElem.BottomRight.First), &aH ); + CheckAndResolveEquationParameter( const_cast(rElem.BottomRight.Second), &aH ); + } + } + break; + default: + break; + } + } + for ( css::beans::PropertyValues const & aHandle : maHandles ) + { + for ( beans::PropertyValue const & propValue : aHandle ) + { + switch( EASGet( propValue.Name ) ) + { + case EAS_RangeYMinimum : + case EAS_RangeYMaximum : + case EAS_RangeXMinimum : + case EAS_RangeXMaximum : + case EAS_RadiusRangeMinimum : + case EAS_RadiusRangeMaximum : + { + CheckAndResolveEquationParameter( const_cast(*o3tl::doAccess( + propValue.Value)), &aH ); + } + break; + + case EAS_Position : + case EAS_Polar : + { + CheckAndResolveEquationParameter( const_cast((*o3tl::doAccess( + propValue.Value)).First), &aH ); + CheckAndResolveEquationParameter( const_cast((*o3tl::doAccess( + propValue.Value)).Second), &aH ); + } + break; + default: + break; + } + } + } + } + + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maExtrusion, EASGet( EAS_Extrusion ) ); + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maPath, EASGet( EAS_Path ) ); + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maTextPath, EASGet( EAS_TextPath ) ); + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maEquations, EASGet( EAS_Equations ) ); + if ( !maHandles.empty() ) + SdXMLCustomShapePropertyMerge( mrCustomShapeGeometry, maHandles, EASGet( EAS_Handles ) ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLEnhancedCustomShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + EnhancedCustomShapeTokenEnum aTokenEnum = EASGet( nElement ); + if ( aTokenEnum == EAS_equation ) + { + OUString aFormula; + OUString aFormulaName; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch( EASGet( aIter.getToken() ) ) + { + case EAS_formula : + aFormula = sValue; + break; + case EAS_name : + aFormulaName = sValue; + break; + default: + break; + } + } + if ( !aFormulaName.isEmpty() || !aFormula.isEmpty() ) + { + maEquations.push_back( aFormula ); + maEquationNames.push_back( aFormulaName ); + } + } + else if ( aTokenEnum == EAS_handle ) + { + std::vector< css::beans::PropertyValue > aHandle; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( EASGet( aIter.getToken() ) ) + { + case EAS_handle_mirror_vertical : + GetBool( aHandle, aIter.toView(), EAS_MirroredY ); + break; + case EAS_handle_mirror_horizontal : + GetBool( aHandle, aIter.toView(), EAS_MirroredX ); + break; + case EAS_handle_switched : + GetBool( aHandle, aIter.toView(), EAS_Switched ); + break; + case EAS_handle_position : + GetEnhancedParameterPair( aHandle, aIter.toString(), EAS_Position ); + break; + case EAS_handle_range_x_minimum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RangeXMinimum ); + break; + case EAS_handle_range_x_maximum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RangeXMaximum ); + break; + case EAS_handle_range_y_minimum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RangeYMinimum ); + break; + case EAS_handle_range_y_maximum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RangeYMaximum ); + break; + case EAS_handle_polar : + GetEnhancedParameterPair( aHandle, aIter.toString(), EAS_Polar ); + break; + case EAS_handle_radius_range_minimum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RadiusRangeMinimum ); + break; + case EAS_handle_radius_range_maximum : + GetEnhancedParameter( aHandle, aIter.toString(), EAS_RadiusRangeMaximum ); + break; + default: + break; + } + } + maHandles.push_back( comphelper::containerToSequence(aHandle) ); + } + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpcustomshape.hxx b/xmloff/source/draw/ximpcustomshape.hxx new file mode 100644 index 000000000..f7e14765a --- /dev/null +++ b/xmloff/source/draw/ximpcustomshape.hxx @@ -0,0 +1,66 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star { + namespace container { class XIndexContainer; } + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + +class XMLEnhancedCustomShapeContext : public SvXMLImportContext +{ + SvXMLUnitConverter& mrUnitConverter; + css::uno::Reference< css::drawing::XShape >& mrxShape; + std::vector< css::beans::PropertyValue >& mrCustomShapeGeometry; + + std::vector< css::beans::PropertyValue > maExtrusion; + std::vector< css::beans::PropertyValue > maPath; + std::vector< css::beans::PropertyValue > maTextPath; + std::vector< css::beans::PropertyValues > maHandles; + std::vector< OUString > maEquations; + std::vector< OUString > maEquationNames; + +public: + + + XMLEnhancedCustomShapeContext( SvXMLImport& rImport, css::uno::Reference< css::drawing::XShape > &, + std::vector< css::beans::PropertyValue >& rCustomShapeGeometry ); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpgrp.cxx b/xmloff/source/draw/ximpgrp.cxx new file mode 100644 index 000000000..c9cf7e218 --- /dev/null +++ b/xmloff/source/draw/ximpgrp.cxx @@ -0,0 +1,100 @@ +/* -*- 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 +#include "ximpgrp.hxx" +#include +#include "ximpshap.hxx" +#include "eventimp.hxx" +#include "descriptionimp.hxx" + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + +SdXMLGroupShapeContext::SdXMLGroupShapeContext( + SvXMLImport& rImport, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +SdXMLGroupShapeContext::~SdXMLGroupShapeContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLGroupShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // #i68101# + if( nElement == XML_ELEMENT(SVG, XML_TITLE) || + nElement == XML_ELEMENT(SVG, XML_DESC ) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC ) ) + { + return new SdXMLDescriptionContext( GetImport(), nElement, mxShape ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + return new SdXMLEventsContext( GetImport(), mxShape ); + } + else if( nElement == XML_ELEMENT(DRAW, XML_GLUE_POINT) ) + { + addGluePoint( xAttrList ); + } + else + { + // call GroupChildContext function at common ShapeImport + return XMLShapeImportHelper::CreateGroupChildContext( + GetImport(), nElement, xAttrList, mxChildren); + } + return nullptr; +} + +void SdXMLGroupShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + // create new group shape and add it to rShapes, use it + // as base for the new group import + AddShape( "com.sun.star.drawing.GroupShape" ); + + if(mxShape.is()) + { + SetStyle( false ); + + mxChildren.set( mxShape, uno::UNO_QUERY ); + if( mxChildren.is() ) + GetImport().GetShapeImport()->pushGroupForPostProcessing( mxChildren ); + } + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +void SdXMLGroupShapeContext::endFastElement(sal_Int32 nElement) +{ + if( mxChildren.is() ) + GetImport().GetShapeImport()->popGroupAndPostProcess(); + + SdXMLShapeContext::endFastElement(nElement); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpgrp.hxx b/xmloff/source/draw/ximpgrp.hxx new file mode 100644 index 000000000..8dda1b9ba --- /dev/null +++ b/xmloff/source/draw/ximpgrp.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/. + * + * 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 +#include +#include "ximpshap.hxx" + +// draw:g context (RECURSIVE) + +class SdXMLGroupShapeContext : public SdXMLShapeContext +{ + // the shape group this group is working on + css::uno::Reference< css::drawing::XShapes > mxChildren; + +public: + + SdXMLGroupShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLGroupShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximplink.cxx b/xmloff/source/draw/ximplink.cxx new file mode 100644 index 000000000..41b236cc8 --- /dev/null +++ b/xmloff/source/draw/ximplink.cxx @@ -0,0 +1,66 @@ +/* -*- 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 +#include +#include +#include "ximplink.hxx" +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + +SdXMLShapeLinkContext::SdXMLShapeLinkContext( SvXMLImport& rImport, const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, uno::Reference< drawing::XShapes > const & rShapes) +: SvXMLShapeContext( rImport, false ) +, mxParent( rShapes ) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(XLINK, XML_HREF) ) + { + assert(msHyperlink.pData); + msHyperlink = aIter.toString(); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +SdXMLShapeLinkContext::~SdXMLShapeLinkContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLShapeLinkContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLShapeContext* pContext = XMLShapeImportHelper::CreateGroupChildContext( GetImport(), nElement, xAttrList, mxParent); + + if( pContext ) + { + pContext->setHyperlink( msHyperlink ); + return pContext; + } + + return nullptr; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximplink.hxx b/xmloff/source/draw/ximplink.hxx new file mode 100644 index 000000000..cd5259154 --- /dev/null +++ b/xmloff/source/draw/ximplink.hxx @@ -0,0 +1,47 @@ +/* -*- 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 +#include +#include + +// draw:a context + +// this should have been a SvXMLImportContext but CreateGroupChildContext() returns +// an unneeded derivation. Should be changed sometime during refactoring. + +class SdXMLShapeLinkContext : public SvXMLShapeContext +{ + // the parent shape group this link is placed in + css::uno::Reference< css::drawing::XShapes > mxParent; + +public: + + SdXMLShapeLinkContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLShapeLinkContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpnote.cxx b/xmloff/source/draw/ximpnote.cxx new file mode 100644 index 000000000..d855e85bf --- /dev/null +++ b/xmloff/source/draw/ximpnote.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 "ximpnote.hxx" +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SdXMLNotesContext::SdXMLNotesContext( + SdXMLImport& rImport, const css::uno::Reference& xAttrList, + uno::Reference const& rShapes) + : SdXMLGenericPageContext(rImport, xAttrList, rShapes) +{ + OUString sStyleName, sPageMasterName; + + for (auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + OUString sValue = aIter.toString(); + switch (aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_NAME): + { + sPageMasterName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + sStyleName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_HEADER_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_HEADER_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_HEADER_NAME): + { + maUseHeaderDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_FOOTER_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_FOOTER_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_FOOTER_NAME): + { + maUseFooterDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_DATE_TIME_NAME): + case XML_ELEMENT(PRESENTATION_SO52, XML_USE_DATE_TIME_NAME): + case XML_ELEMENT(PRESENTATION_OOO, XML_USE_DATE_TIME_NAME): + { + maUseDateTimeDeclName = sValue; + break; + } + } + } + + SetStyle(sStyleName); + + // now delete all up-to-now contained shapes from this notes page + uno::Reference xShape; + while (rShapes->getCount()) + { + rShapes->getByIndex(0) >>= xShape; + if (xShape.is()) + rShapes->remove(xShape); + } + + // set page-master? + if (!sPageMasterName.isEmpty()) + { + SetPageMaster(sPageMasterName); + } +} + +SdXMLNotesContext::~SdXMLNotesContext() {} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpnote.hxx b/xmloff/source/draw/ximpnote.hxx new file mode 100644 index 000000000..d7fe276b8 --- /dev/null +++ b/xmloff/source/draw/ximpnote.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/. + * + * 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 "sdxmlimp_impl.hxx" +#include "ximppage.hxx" + +// presentation:notes context + +class SdXMLNotesContext : public SdXMLGenericPageContext +{ +public: + SdXMLNotesContext( SdXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLNotesContext() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximppage.cxx b/xmloff/source/draw/ximppage.cxx new file mode 100644 index 000000000..3d5cdf006 --- /dev/null +++ b/xmloff/source/draw/ximppage.cxx @@ -0,0 +1,600 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ximppage.hxx" +#include +#include +#include +#include "ximpstyl.hxx" +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::office; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::geometry; + +namespace { + +class DrawAnnotationContext : public SvXMLImportContext +{ + +public: + DrawAnnotationContext( SvXMLImport& rImport, const Reference< xml::sax::XFastAttributeList>& xAttrList, const Reference< XAnnotationAccess >& xAnnotationAccess ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +private: + Reference< XAnnotation > mxAnnotation; + Reference< XTextCursor > mxCursor; + + OUStringBuffer maAuthorBuffer; + OUStringBuffer maInitialsBuffer; + OUStringBuffer maDateBuffer; +}; + +} + +DrawAnnotationContext::DrawAnnotationContext( SvXMLImport& rImport, const Reference< xml::sax::XFastAttributeList>& xAttrList, const Reference< XAnnotationAccess >& xAnnotationAccess ) +: SvXMLImportContext( rImport ) +, mxAnnotation( xAnnotationAccess->createAndInsertAnnotation() ) +{ + if( !mxAnnotation.is() ) + return; + + RealPoint2D aPosition; + RealSize2D aSize; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + { + sal_Int32 x; + GetImport().GetMM100UnitConverter().convertMeasureToCore( + x, aIter.toView()); + aPosition.X = static_cast(x) / 100.0; + break; + } + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + { + sal_Int32 y; + GetImport().GetMM100UnitConverter().convertMeasureToCore( + y, aIter.toView()); + aPosition.Y = static_cast(y) / 100.0; + break; + } + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + { + sal_Int32 w; + GetImport().GetMM100UnitConverter().convertMeasureToCore( + w, aIter.toView()); + aSize.Width = static_cast(w) / 100.0; + break; + } + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + { + sal_Int32 h; + GetImport().GetMM100UnitConverter().convertMeasureToCore( + h, aIter.toView()); + aSize.Height = static_cast(h) / 100.0; + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + mxAnnotation->setPosition( aPosition ); + mxAnnotation->setSize( aSize ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > DrawAnnotationContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( mxAnnotation.is() ) + { + if (nElement == XML_ELEMENT(DC, XML_CREATOR) ) + return new XMLStringBufferImportContext(GetImport(), maAuthorBuffer); + else if( nElement == XML_ELEMENT(DC, XML_DATE) ) + return new XMLStringBufferImportContext(GetImport(), maDateBuffer); + else if ( nElement == XML_ELEMENT(TEXT, XML_SENDER_INITIALS) + || nElement == XML_ELEMENT(LO_EXT, XML_SENDER_INITIALS) + || nElement == XML_ELEMENT(META, XML_CREATOR_INITIALS)) + { + return new XMLStringBufferImportContext(GetImport(), maInitialsBuffer); + } + else + { + // create text cursor on demand + if( !mxCursor.is() ) + { + uno::Reference< text::XText > xText( mxAnnotation->getTextRange() ); + if( xText.is() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport = GetImport().GetTextImport(); + mxCursor = xText->createTextCursor(); + if( mxCursor.is() ) + xTxtImport->SetCursor( mxCursor ); + } + } + + // if we have a text cursor, lets try to import some text + if( mxCursor.is() ) + { + auto p = GetImport().GetTextImport()->CreateTextChildContext( GetImport(), nElement, xAttrList ); + if (p) + return p; + } + } + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void DrawAnnotationContext::endFastElement(sal_Int32) +{ + if(mxCursor.is()) + { + // delete addition newline + mxCursor->gotoEnd( false ); + mxCursor->goLeft( 1, true ); + mxCursor->setString( "" ); + + // reset cursor + GetImport().GetTextImport()->ResetCursor(); + } + + if( mxAnnotation.is() ) + { + mxAnnotation->setAuthor( maAuthorBuffer.makeStringAndClear() ); + mxAnnotation->setInitials( maInitialsBuffer.makeStringAndClear() ); + + util::DateTime aDateTime; + if (::sax::Converter::parseDateTime(aDateTime, maDateBuffer)) + { + mxAnnotation->setDateTime(aDateTime); + } + maDateBuffer.setLength(0); + } +} + + +SdXMLGenericPageContext::SdXMLGenericPageContext( + SvXMLImport& rImport, + const Reference< xml::sax::XFastAttributeList>& xAttrList, + Reference< drawing::XShapes > const & rShapes) +: SvXMLImportContext( rImport ) +, mxShapes( rShapes ) +, mxAnnotationAccess( rShapes, UNO_QUERY ) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_NAV_ORDER) ) + { + msNavOrder = aIter.toString(); + break; + } + } +} + +SdXMLGenericPageContext::~SdXMLGenericPageContext() +{ +} + +void SdXMLGenericPageContext::startFastElement( sal_Int32 /*nElement*/, const Reference< css::xml::sax::XFastAttributeList >& ) +{ + GetImport().GetShapeImport()->pushGroupForPostProcessing( mxShapes ); + + if( GetImport().IsFormsSupported() ) + GetImport().GetFormImport()->startPage( Reference< drawing::XDrawPage >::query( mxShapes ) ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLGenericPageContext::createFastChildContext( + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + if( nElement == XML_ELEMENT(PRESENTATION, XML_ANIMATIONS) ) + { + return new XMLAnimationsContext( GetImport() ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_FORMS) ) + { + if( GetImport().IsFormsSupported() ) + return xmloff::OFormLayerXMLImport::createOfficeFormsContext( GetImport() ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_ANNOTATION) || nElement == XML_ELEMENT(OFFICE_EXT, XML_ANNOTATION) ) + { + if( mxAnnotationAccess.is() ) + return new DrawAnnotationContext( GetImport(), xAttrList, mxAnnotationAccess ); + } + else + { + // call GroupChildContext function at common ShapeImport + auto p = XMLShapeImportHelper::CreateGroupChildContext(GetImport(), nElement, xAttrList, mxShapes); + if (p) + return p; + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SdXMLGenericPageContext::endFastElement(sal_Int32 ) +{ + GetImport().GetShapeImport()->popGroupAndPostProcess(); + + if( GetImport().IsFormsSupported() ) + GetImport().GetFormImport()->endPage(); + + if( !maUseHeaderDeclName.isEmpty() || !maUseFooterDeclName.isEmpty() || !maUseDateTimeDeclName.isEmpty() ) + { + try + { + Reference xSet(mxShapes, uno::UNO_QUERY_THROW ); + Reference< beans::XPropertySetInfo > xInfo( xSet->getPropertySetInfo() ); + + if( !maUseHeaderDeclName.isEmpty() ) + { + static const OUStringLiteral aStrHeaderTextProp( u"HeaderText" ); + if( xInfo->hasPropertyByName( aStrHeaderTextProp ) ) + xSet->setPropertyValue( aStrHeaderTextProp, + Any( GetSdImport().GetHeaderDecl( maUseHeaderDeclName ) ) ); + } + + if( !maUseFooterDeclName.isEmpty() ) + { + static const OUStringLiteral aStrFooterTextProp( u"FooterText" ); + if( xInfo->hasPropertyByName( aStrFooterTextProp ) ) + xSet->setPropertyValue( aStrFooterTextProp, + Any( GetSdImport().GetFooterDecl( maUseFooterDeclName ) ) ); + } + + if( !maUseDateTimeDeclName.isEmpty() ) + { + static const OUStringLiteral aStrDateTimeTextProp( u"DateTimeText" ); + if( xInfo->hasPropertyByName( aStrDateTimeTextProp ) ) + { + bool bFixed; + OUString aDateTimeFormat; + const OUString aText( GetSdImport().GetDateTimeDecl( maUseDateTimeDeclName, bFixed, aDateTimeFormat ) ); + + xSet->setPropertyValue("IsDateTimeFixed", + Any( bFixed ) ); + + if( bFixed ) + { + xSet->setPropertyValue( aStrDateTimeTextProp, Any( aText ) ); + } + else if( !aDateTimeFormat.isEmpty() ) + { + const SdXMLStylesContext* pStyles = dynamic_cast< const SdXMLStylesContext* >( GetSdImport().GetShapeImport()->GetStylesContext() ); + if( !pStyles ) + pStyles = dynamic_cast< const SdXMLStylesContext* >( GetSdImport().GetShapeImport()->GetAutoStylesContext() ); + + if( pStyles ) + { + const SdXMLNumberFormatImportContext* pSdNumStyle = + dynamic_cast< const SdXMLNumberFormatImportContext* >( pStyles->FindStyleChildContext( XmlStyleFamily::DATA_STYLE, aDateTimeFormat, true ) ); + + if( pSdNumStyle ) + { + xSet->setPropertyValue("DateTimeFormat", + Any( pSdNumStyle->GetDrawKey() ) ); + } + } + } + } + } + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } + } + + SetNavigationOrder(); +} + +void SdXMLGenericPageContext::SetStyle( OUString const & rStyleName ) +{ + // set PageProperties? + if(rStyleName.isEmpty()) + return; + + try + { + const SvXMLImportContext* pContext = GetSdImport().GetShapeImport()->GetAutoStylesContext(); + + if (const SdXMLStylesContext* pStyles = dynamic_cast(pContext)) + { + const SvXMLStyleContext* pStyle = pStyles->FindStyleChildContext( + XmlStyleFamily::SD_DRAWINGPAGE_ID, rStyleName); + + if (const XMLPropStyleContext* pPropStyle = dynamic_cast(pStyle)) + { + Reference xPropSet1(mxShapes, uno::UNO_QUERY); + if(xPropSet1.is()) + { + Reference< beans::XPropertySet > xPropSet( xPropSet1 ); + Reference< beans::XPropertySet > xBackgroundSet; + + static const OUStringLiteral aBackground(u"Background"); + if( xPropSet1->getPropertySetInfo()->hasPropertyByName( aBackground ) ) + { + Reference< beans::XPropertySetInfo > xInfo( xPropSet1->getPropertySetInfo() ); + if( xInfo.is() && xInfo->hasPropertyByName( aBackground ) ) + { + Reference< lang::XMultiServiceFactory > xServiceFact(GetSdImport().GetModel(), uno::UNO_QUERY); + if(xServiceFact.is()) + { + xBackgroundSet.set(xServiceFact->createInstance("com.sun.star.drawing.Background"), UNO_QUERY); + } + } + + if( xBackgroundSet.is() ) + xPropSet = PropertySetMerger_CreateInstance( xPropSet1, xBackgroundSet ); + } + + if(xPropSet.is()) + { + const_cast(pPropStyle)->FillPropertySet(xPropSet); + + if( xBackgroundSet.is() ) + xPropSet1->setPropertyValue( aBackground, uno::Any( xBackgroundSet ) ); + } + } + } + } + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void SdXMLGenericPageContext::SetLayout() +{ + // set PresentationPageLayout? + if(!GetSdImport().IsImpress() || maPageLayoutName.isEmpty()) + return; + + sal_Int32 nType = -1; + + const SvXMLImportContext* pContext = GetSdImport().GetShapeImport()->GetStylesContext(); + + if (const SdXMLStylesContext* pStyles = dynamic_cast(pContext)) + { + const SvXMLStyleContext* pStyle = pStyles->FindStyleChildContext( XmlStyleFamily::SD_PRESENTATIONPAGELAYOUT_ID, maPageLayoutName); + + if (const SdXMLPresentationPageLayoutContext* pLayout = dynamic_cast(pStyle)) + { + nType = pLayout->GetTypeId(); + } + } + + if( -1 == nType ) + { + Reference< container::XNameAccess > xPageLayouts( GetSdImport().getPageLayouts() ); + if( xPageLayouts.is() ) + { + if( xPageLayouts->hasByName( maPageLayoutName ) ) + xPageLayouts->getByName( maPageLayoutName ) >>= nType; + } + + } + + if( -1 != nType ) + { + Reference xPropSet(mxShapes, uno::UNO_QUERY); + if(xPropSet.is()) + { + OUString aPropName("Layout"); + Reference< beans::XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() ); + if( xInfo.is() && xInfo->hasPropertyByName( aPropName ) ) + xPropSet->setPropertyValue(aPropName, uno::Any( static_cast(nType) ) ); + } + } +} + +void SdXMLGenericPageContext::DeleteAllShapes() +{ + // now delete all up-to-now contained shapes; they have been created + // when setting the presentation page layout. + while(mxShapes->getCount()) + { + Reference< drawing::XShape > xShape; + uno::Any aAny(mxShapes->getByIndex(0)); + + aAny >>= xShape; + + if(xShape.is()) + { + mxShapes->remove(xShape); + } + } +} + +void SdXMLGenericPageContext::SetPageMaster( OUString const & rsPageMasterName ) +{ + if (!GetSdImport().GetShapeImport()->GetStylesContext()) + return; + + // look for PageMaster with this name + + // #80012# GetStylesContext() replaced with GetAutoStylesContext() + const SvXMLStylesContext* pAutoStyles = GetSdImport().GetShapeImport()->GetAutoStylesContext(); + + const SvXMLStyleContext* pStyle = pAutoStyles ? pAutoStyles->FindStyleChildContext(XmlStyleFamily::SD_PAGEMASTERCONTEXT_ID, rsPageMasterName) : nullptr; + + const SdXMLPageMasterContext* pPageMaster = dynamic_cast(pStyle); + if (!pPageMaster) + return; + + const SdXMLPageMasterStyleContext* pPageMasterContext = pPageMaster->GetPageMasterStyle(); + + if (!pPageMasterContext) + return; + + Reference< drawing::XDrawPage > xMasterPage(GetLocalShapesContext(), uno::UNO_QUERY); + if (!xMasterPage.is()) + return; + + // set sizes for this masterpage + Reference xPropSet(xMasterPage, uno::UNO_QUERY); + if (xPropSet.is()) + { + xPropSet->setPropertyValue("BorderBottom", Any(pPageMasterContext->GetBorderBottom())); + xPropSet->setPropertyValue("BorderLeft", Any(pPageMasterContext->GetBorderLeft())); + xPropSet->setPropertyValue("BorderRight", Any(pPageMasterContext->GetBorderRight())); + xPropSet->setPropertyValue("BorderTop", Any(pPageMasterContext->GetBorderTop())); + xPropSet->setPropertyValue("Width", Any(pPageMasterContext->GetWidth())); + xPropSet->setPropertyValue("Height", Any(pPageMasterContext->GetHeight())); + xPropSet->setPropertyValue("Orientation", Any(pPageMasterContext->GetOrientation())); + } +} + +namespace { + +class XoNavigationOrderAccess : public ::cppu::WeakImplHelper< XIndexAccess > +{ +public: + explicit XoNavigationOrderAccess( std::vector< Reference< XShape > >& rShapes ); + + // XIndexAccess + virtual sal_Int32 SAL_CALL getCount( ) override; + virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override; + + // XElementAccess + virtual Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + +private: + std::vector< Reference< XShape > > maShapes; +}; + +} + +XoNavigationOrderAccess::XoNavigationOrderAccess( std::vector< Reference< XShape > >& rShapes ) +{ + maShapes.swap( rShapes ); +} + +// XIndexAccess +sal_Int32 SAL_CALL XoNavigationOrderAccess::getCount( ) +{ + return static_cast< sal_Int32 >( maShapes.size() ); +} + +Any SAL_CALL XoNavigationOrderAccess::getByIndex( sal_Int32 Index ) +{ + if( (Index < 0) || (Index > getCount()) ) + throw IndexOutOfBoundsException(); + + return Any( maShapes[Index] ); +} + +// XElementAccess +Type SAL_CALL XoNavigationOrderAccess::getElementType( ) +{ + return cppu::UnoType::get(); +} + +sal_Bool SAL_CALL XoNavigationOrderAccess::hasElements( ) +{ + return !maShapes.empty(); +} + +void SdXMLGenericPageContext::SetNavigationOrder() +{ + if( msNavOrder.isEmpty() ) + return; + + try + { + sal_uInt32 nIndex; + const sal_uInt32 nCount = static_cast< sal_uInt32 >( mxShapes->getCount() ); + std::vector< Reference< XShape > > aShapes( nCount ); + + ::comphelper::UnoInterfaceToUniqueIdentifierMapper& rIdMapper = GetSdImport().getInterfaceToIdentifierMapper(); + SvXMLTokenEnumerator aEnumerator( msNavOrder ); + std::u16string_view sId; + for( nIndex = 0; nIndex < nCount; ++nIndex ) + { + if( !aEnumerator.getNextToken(sId) ) + break; + + aShapes[nIndex].set( rIdMapper.getReference( OUString(sId) ), UNO_QUERY ); + } + + for( nIndex = 0; nIndex < nCount; ++nIndex ) + { + if( !aShapes[nIndex].is() ) + { + OSL_FAIL("xmloff::SdXMLGenericPageContext::SetNavigationOrder(), draw:nav-order attribute incomplete!"); + // todo: warning? + return; + } + } + + Reference< XPropertySet > xSet( mxShapes, UNO_QUERY_THROW ); + xSet->setPropertyValue("NavigationOrder", Any( Reference< XIndexAccess >( new XoNavigationOrderAccess( aShapes ) ) ) ); + } + catch(const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", + "unexpected exception caught while importing shape navigation order!"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximppage.hxx b/xmloff/source/draw/ximppage.hxx new file mode 100644 index 000000000..5303458dd --- /dev/null +++ b/xmloff/source/draw/ximppage.hxx @@ -0,0 +1,77 @@ +/* -*- 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 +#include "sdxmlimp_impl.hxx" +#include +#include + +// draw:g context (RECURSIVE) + +class SdXMLGenericPageContext : public SvXMLImportContext +{ + // the shape group this group is working on + css::uno::Reference< css::drawing::XShapes > mxShapes; + css::uno::Reference< css::office::XAnnotationAccess > mxAnnotationAccess; + +protected: + OUString maPageLayoutName; + OUString maUseHeaderDeclName; + OUString maUseFooterDeclName; + OUString maUseDateTimeDeclName; + OUString msNavOrder; + + /** sets the page style on this page */ + void SetStyle( OUString const & rStyleName ); + + /** sets the presentation layout at this page. It is used for drawing pages and for the handout master */ + void SetLayout(); + + /** deletes all shapes on this drawing page */ + void DeleteAllShapes(); + + const SdXMLImport& GetSdImport() const { return static_cast(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + + /** sets the properties from a page master style with the given name on this contexts page */ + void SetPageMaster( OUString const & rsPageMasterName ); + + void SetNavigationOrder(); + +public: + + SdXMLGenericPageContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLGenericPageContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + const css::uno::Reference< css::drawing::XShapes >& GetLocalShapesContext() const + { return mxShapes; } + css::uno::Reference< css::drawing::XShapes >& GetLocalShapesContext() + { return mxShapes; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx new file mode 100644 index 000000000..02fef6949 --- /dev/null +++ b/xmloff/source/draw/ximpshap.cxx @@ -0,0 +1,3940 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ximpshap.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "sdpropls.hxx" +#include "eventimp.hxx" +#include "descriptionimp.hxx" +#include "SignatureLineContext.hxx" +#include "QRCodeContext.hxx" +#include "ximpcustomshape.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::document; +using namespace ::xmloff::token; +using namespace ::xmloff::EnhancedCustomShapeToken; + +SvXMLEnumMapEntry const aXML_GlueAlignment_EnumMap[] = +{ + { XML_TOP_LEFT, drawing::Alignment_TOP_LEFT }, + { XML_TOP, drawing::Alignment_TOP }, + { XML_TOP_RIGHT, drawing::Alignment_TOP_RIGHT }, + { XML_LEFT, drawing::Alignment_LEFT }, + { XML_CENTER, drawing::Alignment_CENTER }, + { XML_RIGHT, drawing::Alignment_RIGHT }, + { XML_BOTTOM_LEFT, drawing::Alignment_BOTTOM_LEFT }, + { XML_BOTTOM, drawing::Alignment_BOTTOM }, + { XML_BOTTOM_RIGHT, drawing::Alignment_BOTTOM_RIGHT }, + { XML_TOKEN_INVALID, drawing::Alignment(0) } +}; + +SvXMLEnumMapEntry const aXML_GlueEscapeDirection_EnumMap[] = +{ + { XML_AUTO, drawing::EscapeDirection_SMART }, + { XML_LEFT, drawing::EscapeDirection_LEFT }, + { XML_RIGHT, drawing::EscapeDirection_RIGHT }, + { XML_UP, drawing::EscapeDirection_UP }, + { XML_DOWN, drawing::EscapeDirection_DOWN }, + { XML_HORIZONTAL, drawing::EscapeDirection_HORIZONTAL }, + { XML_VERTICAL, drawing::EscapeDirection_VERTICAL }, + { XML_TOKEN_INVALID, drawing::EscapeDirection(0) } +}; + +static bool ImpIsEmptyURL( std::u16string_view rURL ) +{ + if( rURL.empty() ) + return true; + + // #i13140# Also compare against 'toplevel' URLs. which also + // result in empty filename strings. + if( rURL == u"#./" ) + return true; + + return false; +} + + +SdXMLShapeContext::SdXMLShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) + : SvXMLShapeContext( rImport, bTemporaryShape ) + , mxShapes( rShapes ) + , mxAttrList(xAttrList) + , mbListContextPushed( false ) + , mnStyleFamily(XmlStyleFamily::SD_GRAPHICS_ID) + , mbIsPlaceholder(false) + , mbClearDefaultAttributes( true ) + , mbIsUserTransformed(false) + , mnZOrder(-1) + , maSize(1, 1) + , mnRelWidth(0) + , mnRelHeight(0) + , maPosition(0, 0) + , mbVisible(true) + , mbPrintable(true) + , mbHaveXmlId(false) + , mbTextBox(false) +{ +} + +SdXMLShapeContext::~SdXMLShapeContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + // #i68101# + if( nElement == XML_ELEMENT(SVG, XML_TITLE) || nElement == XML_ELEMENT(SVG, XML_DESC) + || nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC) ) + { + xContext = new SdXMLDescriptionContext( GetImport(), nElement, mxShape ); + } + else if( nElement == XML_ELEMENT(LO_EXT, XML_SIGNATURELINE) ) + { + xContext = new SignatureLineContext( GetImport(), nElement, xAttrList, mxShape ); + } + else if( nElement == XML_ELEMENT(LO_EXT, XML_QRCODE) ) + { + xContext = new QRCodeContext( GetImport(), nElement, xAttrList, mxShape ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + xContext = new SdXMLEventsContext( GetImport(), mxShape ); + } + else if( nElement == XML_ELEMENT(DRAW, XML_GLUE_POINT) ) + { + addGluePoint( xAttrList ); + } + else if( nElement == XML_ELEMENT(DRAW, XML_THUMBNAIL) ) + { + // search attributes for xlink:href + maThumbnailURL = xAttrList->getOptionalValue(XML_ELEMENT(XLINK, XML_HREF)); + } + else + { + // create text cursor on demand + if( !mxCursor.is() ) + { + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + if( xText.is() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport = + GetImport().GetTextImport(); + mxOldCursor = xTxtImport->GetCursor(); + mxCursor = xText->createTextCursor(); + if( mxCursor.is() ) + { + xTxtImport->SetCursor( mxCursor ); + } + + // remember old list item and block (#91964#) and reset them + // for the text frame + xTxtImport->PushListContext(); + mbListContextPushed = true; + } + } + + // if we have a text cursor, lets try to import some text + if( mxCursor.is() ) + { + xContext = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, + ( mbTextBox ? XMLTextType::TextBox : XMLTextType::Shape ) ); + } + } + + if (!xContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return xContext; +} + +void SdXMLShapeContext::addGluePoint( const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + // get the gluepoints container for this shape if it's not already there + if( !mxGluePoints.is() ) + { + uno::Reference< drawing::XGluePointsSupplier > xSupplier( mxShape, uno::UNO_QUERY ); + if( !xSupplier.is() ) + return; + + mxGluePoints.set( xSupplier->getGluePoints(), UNO_QUERY ); + + if( !mxGluePoints.is() ) + return; + } + + drawing::GluePoint2 aGluePoint; + aGluePoint.IsUserDefined = true; + aGluePoint.Position.X = 0; + aGluePoint.Position.Y = 0; + aGluePoint.Escape = drawing::EscapeDirection_SMART; + aGluePoint.PositionAlignment = drawing::Alignment_CENTER; + aGluePoint.IsRelative = true; + + sal_Int32 nId = -1; + + // read attributes for the 3DScene + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aGluePoint.Position.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aGluePoint.Position.Y, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_ID): + nId = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_ALIGN): + { + drawing::Alignment eKind; + if( SvXMLUnitConverter::convertEnum( eKind, aIter.toView(), aXML_GlueAlignment_EnumMap ) ) + { + aGluePoint.PositionAlignment = eKind; + aGluePoint.IsRelative = false; + } + break; + } + case XML_ELEMENT(DRAW, XML_ESCAPE_DIRECTION): + { + SvXMLUnitConverter::convertEnum( aGluePoint.Escape, aIter.toView(), aXML_GlueEscapeDirection_EnumMap ); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( nId != -1 ) + { + try + { + sal_Int32 nInternalId = mxGluePoints->insert( uno::Any( aGluePoint ) ); + GetImport().GetShapeImport()->addGluePointMapping( mxShape, nId, nInternalId ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "during setting of gluepoints"); + } + } +} + +void SdXMLShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +void SdXMLShapeContext::endFastElement(sal_Int32 ) +{ + if(mxCursor.is()) + { + // tdf#72776 force UpdateData in the EditSource so we will not override text in SdrOutliner + if( mxLockable.is() ) + { + mxLockable->removeActionLock(); + mxLockable->addActionLock(); + } + + // delete addition newline + mxCursor->gotoEnd( false ); + mxCursor->goLeft( 1, true ); + mxCursor->setString( "" ); + + // reset cursor + GetImport().GetTextImport()->ResetCursor(); + } + + if(mxOldCursor.is()) + GetImport().GetTextImport()->SetCursor( mxOldCursor ); + + // reinstall old list item (if necessary) #91964# + if (mbListContextPushed) { + GetImport().GetTextImport()->PopListContext(); + } + + if( !msHyperlink.isEmpty() ) try + { + uno::Reference< beans::XPropertySet > xProp( mxShape, uno::UNO_QUERY ); + + if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName( "Hyperlink" ) ) + xProp->setPropertyValue( "Hyperlink", uno::Any( msHyperlink ) ); + Reference< XEventsSupplier > xEventsSupplier( mxShape, UNO_QUERY ); + + if( xEventsSupplier.is() ) + { + Reference< XNameReplace > xEvents( xEventsSupplier->getEvents(), UNO_SET_THROW ); + + uno::Sequence< beans::PropertyValue > aProperties{ + { /* Name */ "EventType", + /* Handle */ -1, + /* Value */ uno::Any(OUString( "Presentation" )), + /* State */ beans::PropertyState_DIRECT_VALUE }, + + { /* Name */ "ClickAction", + /* Handle */ -1, + /* Value */ uno::Any(css::presentation::ClickAction_DOCUMENT), + /* State */ beans::PropertyState_DIRECT_VALUE }, + + { /* Name */ "Bookmark", + /* Handle */ -1, + /* Value */ uno::Any(msHyperlink), + /* State */ beans::PropertyState_DIRECT_VALUE } + }; + + xEvents->replaceByName( "OnClick", Any( aProperties ) ); + } + else + { + // in draw use the Bookmark property + Reference< beans::XPropertySet > xSet( mxShape, UNO_QUERY_THROW ); + xSet->setPropertyValue( "Bookmark", Any( msHyperlink ) ); + xSet->setPropertyValue("OnClick", Any( css::presentation::ClickAction_DOCUMENT ) ); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "while setting hyperlink"); + } + + if( mxLockable.is() ) + mxLockable->removeActionLock(); +} + +void SdXMLShapeContext::AddShape(uno::Reference< drawing::XShape >& xShape) +{ + if(xShape.is()) + { + // set shape local + mxShape = xShape; + + if(!maShapeName.isEmpty()) + { + uno::Reference< container::XNamed > xNamed( mxShape, uno::UNO_QUERY ); + if( xNamed.is() ) + xNamed->setName( maShapeName ); + } + + rtl::Reference< XMLShapeImportHelper > xImp( GetImport().GetShapeImport() ); + xImp->addShape( xShape, mxAttrList, mxShapes ); + + if( mbClearDefaultAttributes ) + { + uno::Reference xMultiPropertyStates(xShape, uno::UNO_QUERY ); + if (xMultiPropertyStates.is()) + xMultiPropertyStates->setAllPropertiesToDefault(); + } + + if( !mbVisible || !mbPrintable ) try + { + uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY_THROW ); + if( !mbVisible ) + xSet->setPropertyValue("Visible", uno::Any( false ) ); + + if( !mbPrintable ) + xSet->setPropertyValue("Printable", uno::Any( false ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "while setting visible or printable" ); + } + + if(!mbTemporaryShape && (!GetImport().HasTextImport() + || !GetImport().GetTextImport()->IsInsideDeleteContext())) + { + xImp->shapeWithZIndexAdded( xShape, mnZOrder ); + } + + if (mnRelWidth || mnRelHeight) + { + uno::Reference xPropertySet(xShape, uno::UNO_QUERY); + uno::Reference xPropertySetInfo = xPropertySet->getPropertySetInfo(); + if (mnRelWidth && xPropertySetInfo->hasPropertyByName("RelativeWidth")) + xPropertySet->setPropertyValue("RelativeWidth", uno::Any(mnRelWidth)); + if (mnRelHeight && xPropertySetInfo->hasPropertyByName("RelativeHeight")) + xPropertySet->setPropertyValue("RelativeHeight", uno::Any(mnRelHeight)); + } + + if( !maShapeId.isEmpty() ) + { + uno::Reference< uno::XInterface > xRef( static_cast(xShape.get()) ); + GetImport().getInterfaceToIdentifierMapper().registerReference( maShapeId, xRef ); + } + + // #91065# count only if counting for shape import is enabled + if(GetImport().GetShapeImport()->IsHandleProgressBarEnabled()) + { + // #80365# increment progress bar at load once for each draw object + GetImport().GetProgressBarHelper()->Increment(); + } + } + + mxLockable.set( xShape, UNO_QUERY ); + + if( mxLockable.is() ) + mxLockable->addActionLock(); + +} + +void SdXMLShapeContext::AddShape(OUString const & serviceName) +{ + uno::Reference< lang::XMultiServiceFactory > xServiceFact(GetImport().GetModel(), uno::UNO_QUERY); + if(!xServiceFact.is()) + return; + + try + { + /* Since fix for issue i33294 the Writer model doesn't support + com.sun.star.drawing.OLE2Shape anymore. + To handle Draw OLE objects it's decided to import these + objects as com.sun.star.drawing.OLE2Shape and convert these + objects after the import into com.sun.star.drawing.GraphicObjectShape. + */ + uno::Reference< drawing::XShape > xShape; + if ( serviceName == "com.sun.star.drawing.OLE2Shape" && + uno::Reference< text::XTextDocument >(GetImport().GetModel(), uno::UNO_QUERY).is() ) + { + xShape.set(xServiceFact->createInstance("com.sun.star.drawing.temporaryForXMLImportOLE2Shape"), uno::UNO_QUERY); + } + else if (serviceName == "com.sun.star.drawing.GraphicObjectShape" + || serviceName == "com.sun.star.drawing.MediaShape" + || serviceName == "com.sun.star.presentation.MediaShape") + { + xShape.set( xServiceFact->createInstanceWithArguments(serviceName, { css::uno::Any(GetImport().GetDocumentBase()) }), + css::uno::UNO_QUERY); + } + else + { + xShape.set(xServiceFact->createInstance(serviceName), uno::UNO_QUERY); + } + if( xShape.is() ) + AddShape( xShape ); + } + catch(const uno::Exception& e) + { + uno::Sequence aSeq { serviceName }; + GetImport().SetError( XMLERROR_FLAG_ERROR | XMLERROR_API, + aSeq, e.Message, nullptr ); + } +} + +void SdXMLShapeContext::SetTransformation() +{ + if(!mxShape.is()) + return; + + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + maUsedTransformation.identity(); + + if(maSize.Width != 1 || maSize.Height != 1) + { + // take care there are no zeros used by error + if(0 == maSize.Width) + maSize.Width = 1; + if(0 == maSize.Height) + maSize.Height = 1; + + // set global size. This should always be used. + maUsedTransformation.scale(maSize.Width, maSize.Height); + } + + if(maPosition.X != 0 || maPosition.Y != 0) + { + // if global position is used, add it to transformation + maUsedTransformation.translate(maPosition.X, maPosition.Y); + } + + if(mnTransform.NeedsAction()) + { + // transformation is used, apply to object. + // NOTICE: The transformation is applied AFTER evtl. used + // global positioning and scaling is used, so any shear or + // rotate used herein is applied around the (0,0) position + // of the PAGE object !!! + ::basegfx::B2DHomMatrix aMat; + mnTransform.GetFullTransform(aMat); + + // now add to transformation + maUsedTransformation *= aMat; + } + + // now set transformation for this object + + // maUsedTransformtion contains the mathematical correct matrix, which if + // applied to a unit square would generate the transformed shape. But the property + // "Transformation" contains a matrix, which can be used in TRSetBaseGeometry + // and would be created by TRGetBaseGeometry. And those use a mathematically wrong + // sign for the shearing angle. So we need to adapt the matrix here. + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate; + double fShearX; + maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + basegfx::B2DHomMatrix aB2DHomMatrix; + aB2DHomMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( + aScale, + basegfx::fTools::equalZero(fShearX) ? 0.0 : -fShearX, + basegfx::fTools::equalZero(fRotate) ? 0.0 : fRotate, + aTranslate); + drawing::HomogenMatrix3 aUnoMatrix; + + aUnoMatrix.Line1.Column1 = aB2DHomMatrix.get(0, 0); + aUnoMatrix.Line1.Column2 = aB2DHomMatrix.get(0, 1); + aUnoMatrix.Line1.Column3 = aB2DHomMatrix.get(0, 2); + + aUnoMatrix.Line2.Column1 = aB2DHomMatrix.get(1, 0); + aUnoMatrix.Line2.Column2 = aB2DHomMatrix.get(1, 1); + aUnoMatrix.Line2.Column3 = aB2DHomMatrix.get(1, 2); + + aUnoMatrix.Line3.Column1 = aB2DHomMatrix.get(2, 0); + aUnoMatrix.Line3.Column2 = aB2DHomMatrix.get(2, 1); + aUnoMatrix.Line3.Column3 = aB2DHomMatrix.get(2, 2); + + xPropSet->setPropertyValue("Transformation", Any(aUnoMatrix)); +} + +void SdXMLShapeContext::SetStyle( bool bSupportsStyle /* = true */) +{ + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if( !xPropSet.is() ) + return; + + do + { + // set style on shape + if(maDrawStyleName.isEmpty()) + break; + + const SvXMLStyleContext* pStyle = nullptr; + bool bAutoStyle(false); + + if(GetImport().GetShapeImport()->GetAutoStylesContext()) + pStyle = GetImport().GetShapeImport()->GetAutoStylesContext()->FindStyleChildContext(mnStyleFamily, maDrawStyleName); + + if(pStyle) + bAutoStyle = true; + + if(!pStyle && GetImport().GetShapeImport()->GetStylesContext()) + pStyle = GetImport().GetShapeImport()->GetStylesContext()->FindStyleChildContext(mnStyleFamily, maDrawStyleName); + + OUString aStyleName = maDrawStyleName; + uno::Reference< style::XStyle > xStyle; + + XMLPropStyleContext* pDocStyle + = dynamic_cast(const_cast(pStyle)); + if (pDocStyle) + { + if( pDocStyle->GetStyle().is() ) + { + xStyle = pDocStyle->GetStyle(); + } + else + { + aStyleName = pDocStyle->GetParentName(); + } + } + + if( !xStyle.is() && !aStyleName.isEmpty() ) + { + try + { + + uno::Reference< style::XStyleFamiliesSupplier > xFamiliesSupplier( GetImport().GetModel(), uno::UNO_QUERY ); + + if( xFamiliesSupplier.is() ) + { + uno::Reference< container::XNameAccess > xFamilies( xFamiliesSupplier->getStyleFamilies() ); + if( xFamilies.is() ) + { + + uno::Reference< container::XNameAccess > xFamily; + + if( XmlStyleFamily::SD_PRESENTATION_ID == mnStyleFamily ) + { + aStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::SD_PRESENTATION_ID, + aStyleName ); + sal_Int32 nPos = aStyleName.lastIndexOf( '-' ); + if( -1 != nPos ) + { + OUString aFamily( aStyleName.copy( 0, nPos ) ); + + xFamilies->getByName( aFamily ) >>= xFamily; + aStyleName = aStyleName.copy( nPos + 1 ); + } + } + else + { + // get graphics family + xFamilies->getByName("graphics") >>= xFamily; + aStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::SD_GRAPHICS_ID, + aStyleName ); + } + + if( xFamily.is() ) + xFamily->getByName( aStyleName ) >>= xStyle; + } + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "finding style for shape" ); + } + } + + if( bSupportsStyle && xStyle.is() ) + { + try + { + // set style on object + xPropSet->setPropertyValue("Style", Any(xStyle)); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting style for shape" ); + } + } + + // Writer shapes: if this one has a TextBox, set it here. We need to do it before + // pDocStyle->FillPropertySet, because setting some properties depend on the format + // having RES_CNTNT attribute (e.g., UNO_NAME_TEXT_(LEFT|RIGHT|UPPER|LOWER)DIST; see + // SwTextBoxHelper::syncProperty, which indirectly calls SwTextBoxHelper::isTextBox) + uno::Reference xPropertySetInfo + = xPropSet->getPropertySetInfo(); + if (xPropertySetInfo->hasPropertyByName("TextBox")) + xPropSet->setPropertyValue("TextBox", uno::Any(mbTextBox)); + + // if this is an auto style, set its properties + if(bAutoStyle && pDocStyle) + { + // set PropertySet on object + pDocStyle->FillPropertySet(xPropSet); + } + + } while(false); + + // try to set text auto style + do + { + // set style on shape + if( maTextStyleName.isEmpty() ) + break; + + if( nullptr == GetImport().GetShapeImport()->GetAutoStylesContext()) + break; + + const SvXMLStyleContext* pTempStyle = GetImport().GetShapeImport()->GetAutoStylesContext()->FindStyleChildContext(XmlStyleFamily::TEXT_PARAGRAPH, maTextStyleName); + XMLPropStyleContext* pStyle = const_cast(dynamic_cast( pTempStyle ) ); // use temp var, PTR_CAST is a bad macro, FindStyleChildContext will be called twice + if( pStyle == nullptr ) + break; + + // set PropertySet on object + pStyle->FillPropertySet(xPropSet); + + } while(false); + } + catch(const uno::Exception&) + { + } +} + +void SdXMLShapeContext::SetLayer() +{ + if( maLayerName.isEmpty() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is() ) + { + xPropSet->setPropertyValue("LayerName", Any(maLayerName)); + return; + } + } + catch(const uno::Exception&) + { + } +} + +void SdXMLShapeContext::SetThumbnail() +{ + if( maThumbnailURL.isEmpty() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if( !xPropSet.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( "ThumbnailGraphic" ) ) + { + // load the thumbnail graphic and export it to a wmf stream so we can set + // it at the api + + uno::Reference xGraphic = GetImport().loadGraphicByURL(maThumbnailURL); + xPropSet->setPropertyValue("ThumbnailGraphic", uno::Any(xGraphic)); + } + } + catch(const uno::Exception&) + { + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + sal_Int32 nTmp; + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_ZINDEX): + case XML_ELEMENT(DRAW_EXT, XML_ZINDEX): + mnZOrder = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_ID): + case XML_ELEMENT(DRAW_EXT, XML_ID): + if (!mbHaveXmlId) { maShapeId = aIter.toString(); } + break; + case XML_ELEMENT(DRAW, XML_NAME): + case XML_ELEMENT(DRAW_EXT, XML_NAME): + maShapeName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + case XML_ELEMENT(DRAW_EXT, XML_STYLE_NAME): + maDrawStyleName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_TEXT_STYLE_NAME): + case XML_ELEMENT(DRAW_EXT, XML_TEXT_STYLE_NAME): + maTextStyleName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_LAYER): + case XML_ELEMENT(DRAW_EXT, XML_LAYER): + maLayerName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_TRANSFORM): + case XML_ELEMENT(DRAW_EXT, XML_TRANSFORM): + mnTransform.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + break; + case XML_ELEMENT(DRAW, XML_DISPLAY): + case XML_ELEMENT(DRAW_EXT, XML_DISPLAY): + mbVisible = IsXMLToken( aIter, XML_ALWAYS ) || IsXMLToken( aIter, XML_SCREEN ); + mbPrintable = IsXMLToken( aIter, XML_ALWAYS ) || IsXMLToken( aIter, XML_PRINTER ); + break; + case XML_ELEMENT(PRESENTATION, XML_USER_TRANSFORMED): + mbIsUserTransformed = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(PRESENTATION, XML_PLACEHOLDER): + mbIsPlaceholder = IsXMLToken( aIter, XML_TRUE ); + if( mbIsPlaceholder ) + mbClearDefaultAttributes = false; + break; + case XML_ELEMENT(PRESENTATION, XML_CLASS): + maPresentationClass = aIter.toString(); + break; + case XML_ELEMENT(PRESENTATION, XML_STYLE_NAME): + maDrawStyleName = aIter.toString(); + mnStyleFamily = XmlStyleFamily::SD_PRESENTATION_ID; + break; + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maPosition.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maPosition.Y, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maSize.Width, aIter.toView()); + if (maSize.Width > 0) + maSize.Width = o3tl::saturating_add(maSize.Width, 1); + else if (maSize.Width < 0) + maSize.Width = o3tl::saturating_add(maSize.Width, -1); + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maSize.Height, aIter.toView()); + if (maSize.Height > 0) + maSize.Height = o3tl::saturating_add(maSize.Height, 1); + else if (maSize.Height < 0) + maSize.Height = o3tl::saturating_add(maSize.Height, -1); + break; + case XML_ELEMENT(SVG, XML_TRANSFORM): + case XML_ELEMENT(SVG_COMPAT, XML_TRANSFORM): + // because of #85127# take svg:transform into account and handle like + // draw:transform for compatibility + mnTransform.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + break; + case XML_ELEMENT(STYLE, XML_REL_WIDTH): + if (sax::Converter::convertPercent(nTmp, aIter.toView())) + mnRelWidth = static_cast(nTmp); + break; + case XML_ELEMENT(STYLE, XML_REL_HEIGHT): + if (sax::Converter::convertPercent(nTmp, aIter.toView())) + mnRelHeight = static_cast(nTmp); + break; + case XML_ELEMENT(NONE, XML_ID): + case XML_ELEMENT(XML, XML_ID): + maShapeId = aIter.toString(); + mbHaveXmlId = true; + break; + default: + return false; + } + return true; +} + +bool SdXMLShapeContext::isPresentationShape() const +{ + if( !maPresentationClass.isEmpty() && const_cast(this)->GetImport().GetShapeImport()->IsPresentationShapesSupported() ) + { + if(XmlStyleFamily::SD_PRESENTATION_ID == mnStyleFamily) + { + return true; + } + + if( IsXMLToken( maPresentationClass, XML_HEADER ) || IsXMLToken( maPresentationClass, XML_FOOTER ) || + IsXMLToken( maPresentationClass, XML_PAGE_NUMBER ) || IsXMLToken( maPresentationClass, XML_DATE_TIME ) ) + { + return true; + } + } + + return false; +} + +SdXMLRectShapeContext::SdXMLRectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mnRadius( 0 ) +{ +} + +SdXMLRectShapeContext::~SdXMLRectShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLRectShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CORNER_RADIUS): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRadius, aIter.toView()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLRectShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create rectangle shape + AddShape("com.sun.star.drawing.RectangleShape"); + if(!mxShape.is()) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + if(mnRadius) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("CornerRadius", uno::Any( mnRadius ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting corner radius"); + } + } + } + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLLineShapeContext::SdXMLLineShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mnX1( 0 ), + mnY1( 0 ), + mnX2( 1 ), + mnY2( 1 ) +{ +} + +SdXMLLineShapeContext::~SdXMLLineShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLLineShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X1): + case XML_ELEMENT(SVG_COMPAT, XML_X1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnX1, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y1): + case XML_ELEMENT(SVG_COMPAT, XML_Y1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnY1, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_X2): + case XML_ELEMENT(SVG_COMPAT, XML_X2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnX2, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y2): + case XML_ELEMENT(SVG_COMPAT, XML_Y2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnY2, aIter.toView()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLLineShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // #85920# use SetTransformation() to handle import of simple lines. + // This is necessary to take into account all anchor positions and + // other things. All shape imports use the same import schemata now. + // create necessary shape (Line Shape) + AddShape("com.sun.star.drawing.PolyLineShape"); + + if(!mxShape.is()) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + // get sizes and offsets + awt::Point aTopLeft(mnX1, mnY1); + awt::Point aBottomRight(mnX2, mnY2); + + if(mnX1 > mnX2) + { + aTopLeft.X = mnX2; + aBottomRight.X = mnX1; + } + + if(mnY1 > mnY2) + { + aTopLeft.Y = mnY2; + aBottomRight.Y = mnY1; + } + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + drawing::PointSequenceSequence aPolyPoly(1); + drawing::PointSequence* pOuterSequence = aPolyPoly.getArray(); + pOuterSequence->realloc(2); + awt::Point* pInnerSequence = pOuterSequence->getArray(); + + *pInnerSequence = awt::Point(o3tl::saturating_sub(mnX1, aTopLeft.X), o3tl::saturating_sub(mnY1, aTopLeft.Y)); + pInnerSequence++; + *pInnerSequence = awt::Point(o3tl::saturating_sub(mnX2, aTopLeft.X), o3tl::saturating_sub(mnY2, aTopLeft.Y)); + + xPropSet->setPropertyValue("Geometry", Any(aPolyPoly)); + } + + // Size is included in point coordinates + maSize.Width = 1; + maSize.Height = 1; + maPosition.X = aTopLeft.X; + maPosition.Y = aTopLeft.Y; + + // set pos, size, shear and rotate and get copy of matrix + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLEllipseShapeContext::SdXMLEllipseShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mnCX( 0 ), + mnCY( 0 ), + mnRX( 1 ), + mnRY( 1 ), + meKind( drawing::CircleKind_FULL ), + mnStartAngle( 0 ), + mnEndAngle( 0 ) +{ +} + +SdXMLEllipseShapeContext::~SdXMLEllipseShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLEllipseShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_RX): + case XML_ELEMENT(SVG_COMPAT, XML_RX): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRX, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_RY): + case XML_ELEMENT(SVG_COMPAT, XML_RY): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRY, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_CX): + case XML_ELEMENT(SVG_COMPAT, XML_CX): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnCX, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_CY): + case XML_ELEMENT(SVG_COMPAT, XML_CY): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnCY, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_R): + case XML_ELEMENT(SVG_COMPAT, XML_R): + // single radius, it's a circle and both radii are the same + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRX, aIter.toView()); + mnRY = mnRX; + break; + case XML_ELEMENT(DRAW, XML_KIND): + SvXMLUnitConverter::convertEnum( meKind, aIter.toView(), aXML_CircleKind_EnumMap ); + break; + case XML_ELEMENT(DRAW, XML_START_ANGLE): + { + double dStartAngle; + if (::sax::Converter::convertDouble( dStartAngle, aIter.toView() )) + mnStartAngle = static_cast(dStartAngle * 100.0); + break; + } + case XML_ELEMENT(DRAW, XML_END_ANGLE): + { + double dEndAngle; + if (::sax::Converter::convertDouble( dEndAngle, aIter.toView() )) + mnEndAngle = static_cast(dEndAngle * 100.0); + break; + } + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLEllipseShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create rectangle shape + AddShape("com.sun.star.drawing.EllipseShape"); + if(!mxShape.is()) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + if(mnCX != 0 || mnCY != 0 || mnRX != 1 || mnRY != 1) + { + // #i121972# center/radius is used, put to pos and size + maSize.Width = 2 * mnRX; + maSize.Height = 2 * mnRY; + maPosition.X = mnCX - mnRX; + maPosition.Y = mnCY - mnRY; + } + // set pos, size, shear and rotate + SetTransformation(); + + if( meKind != drawing::CircleKind_FULL ) + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + // calculate the correct start and end angle + sal_Int32 mnOldStartAngle = mnStartAngle; + sal_Int32 mnOldEndAngle = mnEndAngle; + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate; + double fShearX; + maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + if (aScale.getX() < 0 || aScale.getY() < 0) + { + // The angle for a horizontal flip is the same as the angle for a + // vertical flip because a vertical flip is treated as a horizontal + // flip plus a rotation. + + // To perform the flip, the start and end angle are switched and we + // use the fact performing a horizontal flip on a shape will change + // the angle that a radius makes with the origin to 180 degrees + // minus that angle (we use 54000 hundredths of a degree to get the + // modulus operation to give a value between 0 and 36000). + + mnStartAngle = (54000 - mnOldEndAngle) % 36000; + mnEndAngle = (54000 - mnOldStartAngle) % 36000; + } + + xPropSet->setPropertyValue("CircleKind", Any( meKind) ); + xPropSet->setPropertyValue("CircleStartAngle", Any(mnStartAngle) ); + xPropSet->setPropertyValue("CircleEndAngle", Any(mnEndAngle) ); + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLPolygonShapeContext::SdXMLPolygonShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, bool bClosed, bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mbClosed( bClosed ) +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPolygonShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + maViewBox = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_POINTS): + maPoints = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter); + } + return true; +} + +SdXMLPolygonShapeContext::~SdXMLPolygonShapeContext() +{ +} + +void SdXMLPolygonShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // Add, set Style and properties from base shape + if(mbClosed) + AddShape("com.sun.star.drawing.PolyPolygonShape"); + else + AddShape("com.sun.star.drawing.PolyLineShape"); + + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + // set polygon + if(!maPoints.isEmpty() && !maViewBox.isEmpty()) + { + const SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DVector aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); + + // Is this correct? It overrides ViewBox stuff; OTOH it makes no + // sense to have the geometry content size different from object size + if(maSize.Width != 0 && maSize.Height != 0) + { + aSize = basegfx::B2DVector(maSize.Width, maSize.Height); + } + + basegfx::B2DPolygon aPolygon; + + if(basegfx::utils::importFromSvgPoints(aPolygon, maPoints)) + { + if(aPolygon.count()) + { + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aSize.getX(), aViewBox.GetY() + aSize.getY()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + css::drawing::PointSequenceSequence aPointSequenceSequence; + basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence(basegfx::B2DPolyPolygon(aPolygon), aPointSequenceSequence); + xPropSet->setPropertyValue("Geometry", Any(aPointSequenceSequence)); + // Size is now contained in the point coordinates, adapt maSize for + // to use the correct transformation matrix in SetTransformation() + maSize.Width = 1; + maSize.Height = 1; + } + } + } + } + + // set pos, size, shear and rotate and get copy of matrix + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLPathShapeContext::SdXMLPathShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +SdXMLPathShapeContext::~SdXMLPathShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPathShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + maViewBox = aIter.toString(); + break; + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + maD = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLPathShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create polygon shape + if(maD.isEmpty()) + return; + + const SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DVector aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); + + // Is this correct? It overrides ViewBox stuff; OTOH it makes no + // sense to have the geometry content size different from object size + if(maSize.Width != 0 && maSize.Height != 0) + { + aSize = basegfx::B2DVector(maSize.Width, maSize.Height); + } + + basegfx::B2DPolyPolygon aPolyPolygon; + + if(!basegfx::utils::importFromSvgD(aPolyPolygon, maD, GetImport().needFixPositionAfterZ(), nullptr)) + return; + + if(!aPolyPolygon.count()) + return; + + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aSize.getX(), aViewBox.GetY() + aSize.getY()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolyPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + // create shape + OUString service; + + if(aPolyPolygon.areControlPointsUsed()) + { + if(aPolyPolygon.isClosed()) + { + service = "com.sun.star.drawing.ClosedBezierShape"; + } + else + { + service = "com.sun.star.drawing.OpenBezierShape"; + } + } + else + { + if(aPolyPolygon.isClosed()) + { + service = "com.sun.star.drawing.PolyPolygonShape"; + } + else + { + service = "com.sun.star.drawing.PolyLineShape"; + } + } + + // Add, set Style and properties from base shape + AddShape(service); + + // #89344# test for mxShape.is() and not for mxShapes.is() to support + // shape import helper classes WITHOUT XShapes (member mxShapes). This + // is used by the writer. + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + + if(xPropSet.is()) + { + uno::Any aAny; + + // set polygon data + if(aPolyPolygon.areControlPointsUsed()) + { + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + aAny <<= aSourcePolyPolygon; + } + else + { + drawing::PointSequenceSequence aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence( + aPolyPolygon, + aSourcePolyPolygon); + aAny <<= aSourcePolyPolygon; + } + + xPropSet->setPropertyValue("Geometry", aAny); + // Size is now contained in the point coordinates, adapt maSize for + // to use the correct transformation matrix in SetTransformation() + maSize.Width = 1; + maSize.Height = 1; + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLTextBoxShapeContext::SdXMLTextBoxShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), + mnRadius(0), + maChainNextName("") +{ +} + +SdXMLTextBoxShapeContext::~SdXMLTextBoxShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLTextBoxShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CORNER_RADIUS): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRadius, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_CHAIN_NEXT_NAME): + maChainNextName = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLTextBoxShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create textbox shape + bool bIsPresShape = false; + bool bClearText = false; + + OUString service; + + if( isPresentationShape() ) + { + // check if the current document supports presentation shapes + if( GetImport().GetShapeImport()->IsPresentationShapesSupported() ) + { + if( IsXMLToken( maPresentationClass, XML_SUBTITLE )) + { + // XmlShapeTypePresSubtitleShape + service = "com.sun.star.presentation.SubtitleShape"; + } + else if( IsXMLToken( maPresentationClass, XML_PRESENTATION_OUTLINE ) ) + { + // XmlShapeTypePresOutlinerShape + service = "com.sun.star.presentation.OutlinerShape"; + } + else if( IsXMLToken( maPresentationClass, XML_NOTES ) ) + { + // XmlShapeTypePresNotesShape + service = "com.sun.star.presentation.NotesShape"; + } + else if( IsXMLToken( maPresentationClass, XML_HEADER ) ) + { + // XmlShapeTypePresHeaderShape + service = "com.sun.star.presentation.HeaderShape"; + bClearText = true; + } + else if( IsXMLToken( maPresentationClass, XML_FOOTER ) ) + { + // XmlShapeTypePresFooterShape + service = "com.sun.star.presentation.FooterShape"; + bClearText = true; + } + else if( IsXMLToken( maPresentationClass, XML_PAGE_NUMBER ) ) + { + // XmlShapeTypePresSlideNumberShape + service = "com.sun.star.presentation.SlideNumberShape"; + bClearText = true; + } + else if( IsXMLToken( maPresentationClass, XML_DATE_TIME ) ) + { + // XmlShapeTypePresDateTimeShape + service = "com.sun.star.presentation.DateTimeShape"; + bClearText = true; + } + else // IsXMLToken( maPresentationClass, XML_TITLE ) ) + { + // XmlShapeTypePresTitleTextShape + service = "com.sun.star.presentation.TitleTextShape"; + } + bIsPresShape = true; + } + } + + if( service.isEmpty() ) + { + // normal text shape + service = "com.sun.star.drawing.TextShape"; + } + + // Add, set Style and properties from base shape + AddShape(service); + + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + if(bIsPresShape) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + if( bClearText ) + { + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + xText->setString( "" ); + } + + // set parameters on shape +//A AW->CL: Eventually You need to strip scale and translate from the transformation +//A to reach the same goal again. +//A if(!bIsPresShape || mbIsUserTransformed) +//A { +//A // set pos and size on shape, this should remove binding +//A // to pres object on masterpage +//A SetSizeAndPosition(); +//A } + + // set pos, size, shear and rotate + SetTransformation(); + + if(mnRadius) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("CornerRadius", uno::Any( mnRadius ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting corner radius"); + } + } + } + + if(!maChainNextName.isEmpty()) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("TextChainNextName", + uno::Any( maChainNextName ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting name of next chain link"); + } + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLControlShapeContext::SdXMLControlShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +SdXMLControlShapeContext::~SdXMLControlShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLControlShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CONTROL): + maFormId = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLControlShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Control shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.ControlShape"); + if( !mxShape.is() ) + return; + + SAL_WARN_IF( !!maFormId.isEmpty(), "xmloff", "draw:control without a form:id attribute!" ); + if( !maFormId.isEmpty() ) + { + if( GetImport().IsFormsSupported() ) + { + uno::Reference< awt::XControlModel > xControlModel( GetImport().GetFormImport()->lookupControl( maFormId ), uno::UNO_QUERY ); + if( xControlModel.is() ) + { + uno::Reference< drawing::XControlShape > xControl( mxShape, uno::UNO_QUERY ); + if( xControl.is() ) + xControl->setControl( xControlModel ); + + } + } + } + + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLConnectorShapeContext::SdXMLConnectorShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + maStart(0,0), + maEnd(1,1), + mnType( drawing::ConnectorType_STANDARD ), + mnStartGlueId(-1), + mnEndGlueId(-1), + mnDelta1(0), + mnDelta2(0), + mnDelta3(0) +{ +} + +SdXMLConnectorShapeContext::~SdXMLConnectorShapeContext() +{ +} + +bool SvXMLImport::needFixPositionAfterZ() const +{ + bool bWrongPositionAfterZ( false ); + sal_Int32 nUPD( 0 ); + sal_Int32 nBuildId( 0 ); + if ( getBuildIds( nUPD, nBuildId ) && // test OOo and old versions of LibO and AOO + ( ( ( nUPD == 641 ) || ( nUPD == 645 ) || ( nUPD == 680 ) || ( nUPD == 300 ) || + ( nUPD == 310 ) || ( nUPD == 320 ) || ( nUPD == 330 ) || ( nUPD == 340 ) || + ( nUPD == 350 && nBuildId < 202 ) ) + || (getGeneratorVersion() == SvXMLImport::AOO_40x))) // test if AOO 4.0.x + // apparently bug was fixed in AOO by i#123433 f15874d8f976f3874bdbcb53429eeefa65c28841 + { + bWrongPositionAfterZ = true; + } + return bWrongPositionAfterZ; +} + + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLConnectorShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_START_SHAPE): + maStartShapeId = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_START_GLUE_POINT): + mnStartGlueId = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_END_SHAPE): + maEndShapeId = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_END_GLUE_POINT): + mnEndGlueId = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_LINE_SKEW): + { + OUString sValue = aIter.toString(); + SvXMLTokenEnumerator aTokenEnum( sValue ); + std::u16string_view aToken; + if( aTokenEnum.getNextToken( aToken ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnDelta1, aToken); + if( aTokenEnum.getNextToken( aToken ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnDelta2, aToken); + if( aTokenEnum.getNextToken( aToken ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnDelta3, aToken); + } + } + } + break; + } + case XML_ELEMENT(DRAW, XML_TYPE): + { + (void)SvXMLUnitConverter::convertEnum( mnType, aIter.toView(), aXML_ConnectionKind_EnumMap ); + break; + } + // #121965# draw:transform may be used in ODF1.2, e.g. exports from MS seem to use these + case XML_ELEMENT(DRAW, XML_TRANSFORM): + mnTransform.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + break; + + case XML_ELEMENT(SVG, XML_X1): + case XML_ELEMENT(SVG_COMPAT, XML_X1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y1): + case XML_ELEMENT(SVG_COMPAT, XML_Y1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.Y, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_X2): + case XML_ELEMENT(SVG_COMPAT, XML_X2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y2): + case XML_ELEMENT(SVG_COMPAT, XML_Y2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.Y, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + { + basegfx::B2DPolyPolygon aPolyPolygon; + + if(basegfx::utils::importFromSvgD(aPolyPolygon, aIter.toString(), GetImport().needFixPositionAfterZ(), nullptr)) + { + if(aPolyPolygon.count()) + { + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + maPath <<= aSourcePolyPolygon; + } + } + break; + } + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLConnectorShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // For security reasons, do not add empty connectors. There may have been an error in EA2 + // that created empty, far set off connectors (e.g. 63 meters below top of document). This + // is not guaranteed, but it's definitely safe to not add empty connectors. + bool bDoAdd(true); + + if( maStartShapeId.isEmpty() + && maEndShapeId.isEmpty() + && maStart.X == maEnd.X + && maStart.Y == maEnd.Y + && 0 == mnDelta1 + && 0 == mnDelta2 + && 0 == mnDelta3 + ) + { + bDoAdd = false; + } + + if(!bDoAdd) + return; + + // create Connector shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.ConnectorShape"); + if(!mxShape.is()) + return; + + // #121965# if draw:transform is used, apply directly to the start + // and end positions before using these + if(mnTransform.NeedsAction()) + { + // transformation is used, apply to object. + ::basegfx::B2DHomMatrix aMat; + mnTransform.GetFullTransform(aMat); + + if(!aMat.isIdentity()) + { + basegfx::B2DPoint aStart(maStart.X, maStart.Y); + basegfx::B2DPoint aEnd(maEnd.X, maEnd.Y); + + aStart = aMat * aStart; + aEnd = aMat * aEnd; + + maStart.X = basegfx::fround(aStart.getX()); + maStart.Y = basegfx::fround(aStart.getY()); + maEnd.X = basegfx::fround(aEnd.getX()); + maEnd.Y = basegfx::fround(aEnd.getY()); + } + } + + // add connection ids + if( !maStartShapeId.isEmpty() ) + GetImport().GetShapeImport()->addShapeConnection( mxShape, true, maStartShapeId, mnStartGlueId ); + if( !maEndShapeId.isEmpty() ) + GetImport().GetShapeImport()->addShapeConnection( mxShape, false, maEndShapeId, mnEndGlueId ); + + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if( xProps.is() ) + { + xProps->setPropertyValue("StartPosition", Any(maStart)); + xProps->setPropertyValue("EndPosition", Any(maEnd) ); + xProps->setPropertyValue("EdgeKind", Any(mnType) ); + xProps->setPropertyValue("EdgeLine1Delta", Any(mnDelta1) ); + xProps->setPropertyValue("EdgeLine2Delta", Any(mnDelta2) ); + xProps->setPropertyValue("EdgeLine3Delta", Any(mnDelta3) ); + } + SetStyle(); + SetLayer(); + + if ( maPath.hasValue() ) + { + // #i115492# + // Ignore svg:d attribute for text documents created by OpenOffice.org + // versions before OOo 3.3, because these OOo versions are storing + // svg:d values not using the correct unit. + bool bApplySVGD( true ); + if ( uno::Reference< text::XTextDocument >(GetImport().GetModel(), uno::UNO_QUERY).is() ) + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); + if ( GetImport().IsTextDocInOOoFileFormat() || + ( bBuildIdFound && + ( ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0 + ( nUPD == 680 ) || // OOo 2.x + ( nUPD == 300 ) || // OOo 3.0 - OOo 3.0.1 + ( nUPD == 310 ) || // OOo 3.1 - OOo 3.1.1 + ( nUPD == 320 ) ) ) ) // OOo 3.2 - OOo 3.2.1 + { + bApplySVGD = false; + } + } + + if ( bApplySVGD ) + { + // tdf#83360 use path data only when redundant data of start and end point coordinates of + // path start/end and connector start/end is equal. This is to avoid using erraneous + // or inconsistent path data at import of foreign formats. Office itself always + // writes out a consistent data set. Not using it when there is inconsistency + // is okay since the path data is redundant, buffered data just to avoid recalculation + // of the connector's layout at load time, no real information would be lost. + // A 'connected' end has prio to direct coordinate data in Start/EndPosition + // to the path data (which should have the start/end redundant in the path) + const drawing::PolyPolygonBezierCoords* pSource = static_cast< const drawing::PolyPolygonBezierCoords* >(maPath.getValue()); + const sal_uInt32 nSequenceCount(pSource->Coordinates.getLength()); + bool bStartEqual(false); + bool bEndEqual(false); + + if(nSequenceCount) + { + const drawing::PointSequence& rStartSeq = pSource->Coordinates[0]; + const sal_uInt32 nStartCount = rStartSeq.getLength(); + + if(nStartCount) + { + const awt::Point& rStartPoint = rStartSeq.getConstArray()[0]; + + if(rStartPoint.X == maStart.X && rStartPoint.Y == maStart.Y) + { + bStartEqual = true; + } + } + + const drawing::PointSequence& rEndSeq = pSource->Coordinates[nSequenceCount - 1]; + const sal_uInt32 nEndCount = rEndSeq.getLength(); + + if(nEndCount) + { + const awt::Point& rEndPoint = rEndSeq.getConstArray()[nEndCount - 1]; + + if(rEndPoint.X == maEnd.X && rEndPoint.Y == maEnd.Y) + { + bEndEqual = true; + } + } + } + + if(!bStartEqual || !bEndEqual) + { + bApplySVGD = false; + } + } + + if ( bApplySVGD ) + { + assert(maPath.getValueType() == cppu::UnoType::get()); + xProps->setPropertyValue("PolyPolygonBezier", maPath); + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLMeasureShapeContext::SdXMLMeasureShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + maStart(0,0), + maEnd(1,1) +{ +} + +SdXMLMeasureShapeContext::~SdXMLMeasureShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLMeasureShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(SVG, XML_X1): + case XML_ELEMENT(SVG_COMPAT, XML_X1): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.X, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_Y1): + case XML_ELEMENT(SVG_COMPAT, XML_Y1): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.Y, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_X2): + case XML_ELEMENT(SVG_COMPAT, XML_X2): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.X, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_Y2): + case XML_ELEMENT(SVG_COMPAT, XML_Y2): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.Y, aIter.toView()); + break; + } + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLMeasureShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Measure shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.MeasureShape"); + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if( xProps.is() ) + { + xProps->setPropertyValue("StartPosition", Any(maStart)); + xProps->setPropertyValue("EndPosition", Any(maEnd) ); + } + + // delete pre created fields + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + if( xText.is() ) + { + xText->setString( " " ); + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +void SdXMLMeasureShapeContext::endFastElement(sal_Int32 nElement) +{ + do + { + // delete pre created fields + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + if( !xText.is() ) + break; + + uno::Reference< text::XTextCursor > xCursor( xText->createTextCursor() ); + if( !xCursor.is() ) + break; + + xCursor->collapseToStart(); + xCursor->goRight( 1, true ); + xCursor->setString( "" ); + } + while(false); + + SdXMLShapeContext::endFastElement(nElement); +} + + +SdXMLPageShapeContext::SdXMLPageShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), mnPageNumber(0) +{ + mbClearDefaultAttributes = false; +} + +SdXMLPageShapeContext::~SdXMLPageShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPageShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_PAGE_NUMBER) ) + mnPageNumber = aIter.toInt32(); + else + return SdXMLShapeContext::processAttribute( aIter ); + return true; +} + +void SdXMLPageShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Page shape + // add, set style and properties from base shape + + // #86163# take into account which type of PageShape needs to + // be constructed. It's a pres shape if presentation:XML_CLASS == XML_PAGE. + bool bIsPresentation = !maPresentationClass.isEmpty() && + GetImport().GetShapeImport()->IsPresentationShapesSupported(); + + uno::Reference< lang::XServiceInfo > xInfo( mxShapes, uno::UNO_QUERY ); + const bool bIsOnHandoutPage = xInfo.is() && xInfo->supportsService("com.sun.star.presentation.HandoutMasterPage"); + + if( bIsOnHandoutPage ) + { + AddShape("com.sun.star.presentation.HandoutShape"); + } + else + { + if(bIsPresentation && !IsXMLToken( maPresentationClass, XML_PAGE ) ) + { + bIsPresentation = false; + } + + if(bIsPresentation) + { + AddShape("com.sun.star.presentation.PageShape"); + } + else + { + AddShape("com.sun.star.drawing.PageShape"); + } + } + + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + static const OUStringLiteral aPageNumberStr(u"PageNumber"); + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr)) + xPropSet->setPropertyValue(aPageNumberStr, uno::Any( mnPageNumber )); + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLCaptionShapeContext::SdXMLCaptionShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + // #86616# for correct edge rounding import mnRadius needs to be initialized + mnRadius( 0 ) +{ +} + +SdXMLCaptionShapeContext::~SdXMLCaptionShapeContext() +{ +} + +void SdXMLCaptionShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Caption shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.CaptionShape"); + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + // SJ: If AutoGrowWidthItem is set, SetTransformation will lead to the wrong SnapRect + // because NbcAdjustTextFrameWidthAndHeight() is called (text is set later and center alignment + // is the default setting, so the top left reference point that is used by the caption point is + // no longer correct) There are two ways to solve this problem, temporarily disabling the + // autogrowwidth as we are doing here or to apply the CaptionPoint after setting text + bool bIsAutoGrowWidth = false; + if ( xProps.is() ) + { + uno::Any aAny( xProps->getPropertyValue("TextAutoGrowWidth") ); + aAny >>= bIsAutoGrowWidth; + + if ( bIsAutoGrowWidth ) + xProps->setPropertyValue("TextAutoGrowWidth", uno::Any( false ) ); + } + + // set pos, size, shear and rotate + SetTransformation(); + if( xProps.is() ) + xProps->setPropertyValue("CaptionPoint", uno::Any( maCaptionPoint ) ); + + if ( bIsAutoGrowWidth ) + xProps->setPropertyValue("TextAutoGrowWidth", uno::Any( true ) ); + + if(mnRadius) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("CornerRadius", uno::Any( mnRadius ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting corner radius"); + } + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLCaptionShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CAPTION_POINT_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maCaptionPoint.X, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_CAPTION_POINT_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maCaptionPoint.Y, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_CORNER_RADIUS): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRadius, aIter.toView()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + + +SdXMLGraphicObjectShapeContext::SdXMLGraphicObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLGraphicObjectShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + if( aIter.getToken() == XML_ELEMENT(XLINK, XML_HREF) ) + maURL = aIter.toString(); + else + return SdXMLShapeContext::processAttribute( aIter ); + return true; +} + +void SdXMLGraphicObjectShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create graphic object shape + OUString service; + + if( IsXMLToken( maPresentationClass, XML_GRAPHIC ) && GetImport().GetShapeImport()->IsPresentationShapesSupported() ) + { + service = "com.sun.star.presentation.GraphicObjectShape"; + } + else + { + service = "com.sun.star.drawing.GraphicObjectShape"; + } + + AddShape(service); + + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + uno::Reference< beans::XPropertySet > xPropset(mxShape, uno::UNO_QUERY); + if(xPropset.is()) + { + // since OOo 1.x had no line or fill style for graphics, but may create + // documents with them, we have to override them here + sal_Int32 nUPD, nBuildId; + if( GetImport().getBuildIds( nUPD, nBuildId ) && (nUPD == 645) ) try + { + xPropset->setPropertyValue("FillStyle", Any( FillStyle_NONE ) ); + xPropset->setPropertyValue("LineStyle", Any( LineStyle_NONE ) ); + } + catch(const Exception&) + { + } + + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xPropset->getPropertySetInfo() ); + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xPropset->setPropertyValue("IsEmptyPresentationObject", css::uno::Any( mbIsPlaceholder ) ); + + if( !mbIsPlaceholder ) + { + if( !maURL.isEmpty() ) + { + uno::Reference xGraphic = GetImport().loadGraphicByURL(maURL); + if (xGraphic.is()) + { + xPropset->setPropertyValue("Graphic", uno::Any(xGraphic)); + } + } + } + } + + if(mbIsUserTransformed) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +void SdXMLGraphicObjectShapeContext::endFastElement(sal_Int32 nElement) +{ + if (mxBase64Stream.is()) + { + uno::Reference xGraphic(GetImport().loadGraphicFromBase64(mxBase64Stream)); + if (xGraphic.is()) + { + uno::Reference xProperties(mxShape, uno::UNO_QUERY); + if (xProperties.is()) + { + xProperties->setPropertyValue("Graphic", uno::Any(xGraphic)); + } + } + } + + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLGraphicObjectShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + + if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) ) + { + if( maURL.isEmpty() && !mxBase64Stream.is() ) + { + mxBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( mxBase64Stream.is() ) + xContext = new XMLBase64ImportContext( GetImport(), + mxBase64Stream ); + } + } + + // delegate to parent class if no context could be created + if (!xContext) + xContext = SdXMLShapeContext::createFastChildContext(nElement, + xAttrList); + + if (!xContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return xContext; +} + +SdXMLGraphicObjectShapeContext::~SdXMLGraphicObjectShapeContext() +{ + +} + + +SdXMLChartShapeContext::SdXMLChartShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +void SdXMLChartShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + const bool bIsPresentation = isPresentationShape(); + + AddShape( + bIsPresentation + ? OUString("com.sun.star.presentation.ChartShape") + : OUString("com.sun.star.drawing.OLE2Shape")); + + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + if( !mbIsPlaceholder ) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + uno::Any aAny; + + xProps->setPropertyValue("CLSID", Any(OUString("12DCAE26-281F-416F-a234-c3086127382e")) ); + + aAny = xProps->getPropertyValue("Model"); + uno::Reference< frame::XModel > xChartModel; + if( aAny >>= xChartModel ) + { +#if !ENABLE_WASM_STRIP_CHART + // WASM_CHART change + // TODO: Maybe use SdXMLGraphicObjectShapeContext completely instead + // or try to create as mbIsPlaceholder object adding a Chart visualization + // that should be available somehow + mxChartContext.set( GetImport().GetChartImport()->CreateChartContext( GetImport(), xChartModel ) ); +#endif + } + } + } + + if(mbIsUserTransformed) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); + + if( mxChartContext.is() ) + mxChartContext->startFastElement( nElement, xAttrList ); +} + +void SdXMLChartShapeContext::endFastElement(sal_Int32 nElement) +{ + if( mxChartContext.is() ) + mxChartContext->endFastElement(nElement); + + SdXMLShapeContext::endFastElement(nElement); +} + +void SdXMLChartShapeContext::characters( const OUString& rChars ) +{ + if( mxChartContext.is() ) + mxChartContext->characters( rChars ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLChartShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( mxChartContext.is() ) + return mxChartContext->createFastChildContext( nElement, xAttrList ); + + return nullptr; +} + + +SdXMLObjectShapeContext::SdXMLObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ +} + +SdXMLObjectShapeContext::~SdXMLObjectShapeContext() +{ +} + +void SdXMLObjectShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + // #96717# in theorie, if we don't have a URL we shouldn't even + // export this OLE shape. But practically it's too risky right now + // to change this so we better dispose this on load + //if( !mbIsPlaceholder && ImpIsEmptyURL(maHref) ) + // return; + + // #100592# this BugFix prevents that a shape is created. CL + // is thinking about an alternative. + // #i13140# Check for more than empty string in maHref, there are + // other possibilities that maHref results in empty container + // storage names + if( !(GetImport().getImportFlags() & SvXMLImportFlags::EMBEDDED) && !mbIsPlaceholder && ImpIsEmptyURL(maHref) ) + return; + + OUString service("com.sun.star.drawing.OLE2Shape"); + + bool bIsPresShape = !maPresentationClass.isEmpty() && GetImport().GetShapeImport()->IsPresentationShapesSupported(); + + if( bIsPresShape ) + { + if( IsXMLToken( maPresentationClass, XML_CHART ) ) + { + service = "com.sun.star.presentation.ChartShape"; + } + else if( IsXMLToken( maPresentationClass, XML_TABLE ) ) + { + service = "com.sun.star.presentation.CalcShape"; + } + else if( IsXMLToken( maPresentationClass, XML_OBJECT ) ) + { + service = "com.sun.star.presentation.OLE2Shape"; + } + } + + AddShape(service); + + if( !mxShape.is() ) + return; + + SetLayer(); + + if(bIsPresShape) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + if( !mbIsPlaceholder && !maHref.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + if( xProps.is() ) + { + OUString aPersistName = GetImport().ResolveEmbeddedObjectURL( maHref, maCLSID ); + + if ( GetImport().IsPackageURL( maHref ) ) + { + static const OUStringLiteral sURL( u"vnd.sun.star.EmbeddedObject:" ); + + if ( aPersistName.startsWith( sURL ) ) + aPersistName = aPersistName.copy( sURL.getLength() ); + + xProps->setPropertyValue("PersistName", + uno::Any( aPersistName ) ); + } + else + { + // this is OOo link object + xProps->setPropertyValue("LinkURL", + uno::Any( aPersistName ) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + + SetStyle(); + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +void SdXMLObjectShapeContext::endFastElement(sal_Int32 nElement) +{ + if (GetImport().isGeneratorVersionOlderThan( + SvXMLImport::OOo_34x, SvXMLImport::LO_41x)) // < LO 4.0 + { + // #i118485# + // If it's an old file from us written before OOo3.4, we need to correct + // FillStyle and LineStyle for OLE2 objects. The error was that the old paint + // implementations just ignored added fill/linestyles completely, thus + // those objects need to be corrected to not show blue and hairline which + // always was the default, but would be shown now + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + + if( xProps.is() ) + { + xProps->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_NONE)); + xProps->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_NONE)); + } + } + + if( mxBase64Stream.is() ) + { + OUString aPersistName( GetImport().ResolveEmbeddedObjectURLFromBase64() ); + static const OUStringLiteral sURL( u"vnd.sun.star.EmbeddedObject:" ); + + aPersistName = aPersistName.copy( sURL.getLength() ); + + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if( xProps.is() ) + xProps->setPropertyValue("PersistName", uno::Any( aPersistName ) ); + } + + SdXMLShapeContext::endFastElement(nElement); +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLObjectShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_CLASS_ID): + maCLSID = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLObjectShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if(nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA)) + { + mxBase64Stream = GetImport().GetStreamForEmbeddedObjectURLFromBase64(); + if( mxBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), mxBase64Stream ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_DOCUMENT) || + nElement == XML_ELEMENT(MATH, XML_MATH) ) + { + rtl::Reference xEContext( + new XMLEmbeddedObjectImportContext(GetImport(), nElement, xAttrList)); + maCLSID = xEContext->GetFilterCLSID(); + if( !maCLSID.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if( xPropSet.is() ) + { + xPropSet->setPropertyValue("CLSID", uno::Any( maCLSID ) ); + + uno::Reference< lang::XComponent > xComp; + xPropSet->getPropertyValue("Model") >>= xComp; + SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" ); + xEContext->SetComponent(xComp); + } + } + return xEContext; + } + + // delegate to parent class if no context could be created + return SdXMLShapeContext::createFastChildContext(nElement, xAttrList); +} + +SdXMLAppletShapeContext::SdXMLAppletShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), + mbIsScript( false ) +{ +} + +SdXMLAppletShapeContext::~SdXMLAppletShapeContext() +{ +} + +void SdXMLAppletShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + AddShape("com.sun.star.drawing.AppletShape"); + + if( mxShape.is() ) + { + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLAppletShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_APPLET_NAME): + maAppletName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_CODE): + maAppletCode = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_MAY_SCRIPT): + mbIsScript = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = GetImport().GetAbsoluteReference(aIter.toString()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLAppletShapeContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if( xProps.is() ) + { + if ( maSize.Width && maSize.Height ) + { + // the visual area for applet must be set on loading + awt::Rectangle aRect( 0, 0, maSize.Width, maSize.Height ); + xProps->setPropertyValue("VisibleArea", Any(aRect) ); + } + + if( maParams.hasElements() ) + { + xProps->setPropertyValue("AppletCommands", Any(maParams) ); + } + + if( !maHref.isEmpty() ) + { + xProps->setPropertyValue("AppletCodeBase", Any(maHref) ); + } + + if( !maAppletName.isEmpty() ) + { + xProps->setPropertyValue("AppletName", Any(maAppletName) ); + } + + if( mbIsScript ) + { + xProps->setPropertyValue("AppletIsScript", Any(mbIsScript) ); + + } + + if( !maAppletCode.isEmpty() ) + { + xProps->setPropertyValue("AppletCode", Any(maAppletCode) ); + } + + xProps->setPropertyValue("AppletDocBase", Any(GetImport().GetDocumentBase()) ); + + SetThumbnail(); + } + + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLAppletShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_PARAM) ) + { + OUString aParamName, aParamValue; + // now parse the attribute list and look for draw:name and draw:value + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_NAME) ) + aParamName = aIter.toString(); + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_VALUE) ) + aParamValue = aIter.toString(); + } + + if( !aParamName.isEmpty() ) + { + sal_Int32 nIndex = maParams.getLength(); + maParams.realloc( nIndex + 1 ); + auto pParams = maParams.getArray(); + pParams[nIndex].Name = aParamName; + pParams[nIndex].Handle = -1; + pParams[nIndex].Value <<= aParamValue; + pParams[nIndex].State = beans::PropertyState_DIRECT_VALUE; + } + + return new SvXMLImportContext( GetImport() ); + } + + return SdXMLShapeContext::createFastChildContext( nElement, xAttrList ); +} + + +SdXMLPluginShapeContext::SdXMLPluginShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) : +SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), +mbMedia( false ) +{ +} + +SdXMLPluginShapeContext::~SdXMLPluginShapeContext() +{ +} + +void SdXMLPluginShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + + // watch for MimeType attribute to see if we have a media object + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_MIME_TYPE) ) + { + if( aIter.toView() == "application/vnd.sun.star.media" ) + mbMedia = true; + // leave this loop + break; + } + } + + OUString service; + + bool bIsPresShape = false; + + if( mbMedia ) + { + service = "com.sun.star.drawing.MediaShape"; + + bIsPresShape = !maPresentationClass.isEmpty() && GetImport().GetShapeImport()->IsPresentationShapesSupported(); + if( bIsPresShape ) + { + if( IsXMLToken( maPresentationClass, XML_OBJECT ) ) + { + service = "com.sun.star.presentation.MediaShape"; + } + } + } + else + service = "com.sun.star.drawing.PluginShape"; + + AddShape(service); + + if( !mxShape.is() ) + return; + + if (mbMedia) + { + // The media may have a crop, apply it. + SetStyle(/*bSupportsStyle=*/false); + } + + SetLayer(); + + if(bIsPresShape) + { + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +static OUString +lcl_GetMediaReference(SvXMLImport const& rImport, OUString const& rURL) +{ + if (rImport.IsPackageURL(rURL)) + { + return "vnd.sun.star.Package:" + rURL; + } + else + { + return rImport.GetAbsoluteReference(rURL); + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPluginShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_MIME_TYPE): + maMimeType = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = lcl_GetMediaReference(GetImport(), aIter.toString()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLPluginShapeContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + if( xProps.is() ) + { + if ( maSize.Width && maSize.Height ) + { + static const OUStringLiteral sVisibleArea( u"VisibleArea" ); + uno::Reference< beans::XPropertySetInfo > aXPropSetInfo( xProps->getPropertySetInfo() ); + if ( !aXPropSetInfo.is() || aXPropSetInfo->hasPropertyByName( sVisibleArea ) ) + { + // the visual area for a plugin must be set on loading + awt::Rectangle aRect( 0, 0, maSize.Width, maSize.Height ); + xProps->setPropertyValue( sVisibleArea, Any(aRect) ); + } + } + + if( !mbMedia ) + { + // in case we have a plugin object + if( maParams.hasElements() ) + { + xProps->setPropertyValue("PluginCommands", Any(maParams) ); + } + + if( !maMimeType.isEmpty() ) + { + xProps->setPropertyValue("PluginMimeType", Any(maMimeType) ); + } + + if( !maHref.isEmpty() ) + { + xProps->setPropertyValue("PluginURL", Any(maHref) ); + } + } + else + { + // in case we have a media object + xProps->setPropertyValue( "MediaURL", uno::Any(maHref)); + + xProps->setPropertyValue("MediaMimeType", uno::Any(maMimeType) ); + + for( const auto& rParam : std::as_const(maParams) ) + { + const OUString& rName = rParam.Name; + + if( rName == "Loop" ) + { + OUString aValueStr; + rParam.Value >>= aValueStr; + xProps->setPropertyValue("Loop", + uno::Any( aValueStr == "true" ) ); + } + else if( rName == "Mute" ) + { + OUString aValueStr; + rParam.Value >>= aValueStr; + xProps->setPropertyValue("Mute", + uno::Any( aValueStr == "true" ) ); + } + else if( rName == "VolumeDB" ) + { + OUString aValueStr; + rParam.Value >>= aValueStr; + xProps->setPropertyValue("VolumeDB", + uno::Any( static_cast< sal_Int16 >( aValueStr.toInt32() ) ) ); + } + else if( rName == "Zoom" ) + { + OUString aZoomStr; + media::ZoomLevel eZoomLevel; + + rParam.Value >>= aZoomStr; + + if( aZoomStr == "25%" ) + eZoomLevel = media::ZoomLevel_ZOOM_1_TO_4; + else if( aZoomStr == "50%" ) + eZoomLevel = media::ZoomLevel_ZOOM_1_TO_2; + else if( aZoomStr == "100%" ) + eZoomLevel = media::ZoomLevel_ORIGINAL; + else if( aZoomStr == "200%" ) + eZoomLevel = media::ZoomLevel_ZOOM_2_TO_1; + else if( aZoomStr == "400%" ) + eZoomLevel = media::ZoomLevel_ZOOM_4_TO_1; + else if( aZoomStr == "fit" ) + eZoomLevel = media::ZoomLevel_FIT_TO_WINDOW; + else if( aZoomStr == "fixedfit" ) + eZoomLevel = media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT; + else if( aZoomStr == "fullscreen" ) + eZoomLevel = media::ZoomLevel_FULLSCREEN; + else + eZoomLevel = media::ZoomLevel_NOT_AVAILABLE; + + xProps->setPropertyValue("Zoom", uno::Any( eZoomLevel ) ); + } + } + } + + SetThumbnail(); + } + + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLPluginShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_PARAM) ) + { + OUString aParamName, aParamValue; + // now parse the attribute list and look for draw:name and draw:value + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_NAME) ) + aParamName = aIter.toString(); + else if( aIter.getToken() == XML_ELEMENT(DRAW, XML_VALUE) ) + aParamValue = aIter.toString(); + } + + if( !aParamName.isEmpty() ) + { + sal_Int32 nIndex = maParams.getLength(); + maParams.realloc( nIndex + 1 ); + auto pParams = maParams.getArray(); + pParams[nIndex].Name = aParamName; + pParams[nIndex].Handle = -1; + pParams[nIndex].Value <<= aParamValue; + pParams[nIndex].State = beans::PropertyState_DIRECT_VALUE; + } + + return new SvXMLImportContext( GetImport() ); + } + + return SdXMLShapeContext::createFastChildContext( nElement, xAttrList ); +} + + +SdXMLFloatingFrameShapeContext::SdXMLFloatingFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ +} + +SdXMLFloatingFrameShapeContext::~SdXMLFloatingFrameShapeContext() +{ +} + +uno::Reference SdXMLFloatingFrameShapeContext::CreateFloatingFrameShape() const +{ + uno::Reference xServiceFact(GetImport().GetModel(), uno::UNO_QUERY); + if (!xServiceFact.is()) + return nullptr; + uno::Reference xShape( + xServiceFact->createInstance("com.sun.star.drawing.FrameShape"), uno::UNO_QUERY); + return xShape; +} + +void SdXMLFloatingFrameShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + uno::Reference xShape(SdXMLFloatingFrameShapeContext::CreateFloatingFrameShape()); + + uno::Reference< beans::XPropertySet > xProps(xShape, uno::UNO_QUERY); + // set FrameURL before AddShape, we have to do it again later because it + // gets cleared when the SdrOle2Obj is attached to the XShape. But we want + // FrameURL to exist when AddShape triggers SetPersistName which itself + // triggers SdrOle2Obj::CheckFileLink_Impl and at that point we want to + // know what URL will end up being used. So bodge this by setting FrameURL + // to the temp pre-SdrOle2Obj attached properties and we can smuggle it + // eventually into SdrOle2Obj::SetPersistName at the right point after + // PersistName is set but before SdrOle2Obj::CheckFileLink_Impl is called + // in order to inform the link manager that this is an IFrame that links to + // a URL + if (xProps && !maHref.isEmpty()) + xProps->setPropertyValue("FrameURL", Any(maHref)); + + AddShape(xShape); + + if( !mxShape.is() ) + return; + + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + if( xProps.is() ) + { + if( !maFrameName.isEmpty() ) + { + xProps->setPropertyValue("FrameName", Any(maFrameName) ); + } + + if( !maHref.isEmpty() ) + { + if (INetURLObject(maHref).GetProtocol() == INetProtocol::Macro) + GetImport().NotifyMacroEventRead(); + + xProps->setPropertyValue("FrameURL", Any(maHref) ); + } + } + + SetStyle(); + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLFloatingFrameShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_FRAME_NAME): + maFrameName = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = GetImport().GetAbsoluteReference(aIter.toString()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLFloatingFrameShapeContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + if( xProps.is() ) + { + if ( maSize.Width && maSize.Height ) + { + // the visual area for a floating frame must be set on loading + awt::Rectangle aRect( 0, 0, maSize.Width, maSize.Height ); + xProps->setPropertyValue("VisibleArea", Any(aRect) ); + } + } + + SetThumbnail(); + SdXMLShapeContext::endFastElement(nElement); +} + + +SdXMLFrameShapeContext::SdXMLFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mbSupportsReplacement( false ) +{ + uno::Reference < util::XCloneable > xClone( xAttrList, uno::UNO_QUERY ); + if( xClone.is() ) + mxAttrList.set( xClone->createClone(), uno::UNO_QUERY ); + else + mxAttrList = new sax_fastparser::FastAttributeList(xAttrList); +} + +SdXMLFrameShapeContext::~SdXMLFrameShapeContext() +{ +} + +void SdXMLFrameShapeContext::removeGraphicFromImportContext(const SvXMLImportContext& rContext) +{ + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast< const SdXMLGraphicObjectShapeContext* >(&rContext); + + if(!pSdXMLGraphicObjectShapeContext) + return; + + try + { + uno::Reference< container::XChild > xChild(pSdXMLGraphicObjectShapeContext->getShape(), uno::UNO_QUERY_THROW); + + uno::Reference< drawing::XShapes > xParent(xChild->getParent(), uno::UNO_QUERY_THROW); + + // remove from parent + xParent->remove(pSdXMLGraphicObjectShapeContext->getShape()); + + // dispose + uno::Reference< lang::XComponent > xComp(pSdXMLGraphicObjectShapeContext->getShape(), UNO_QUERY); + + if(xComp.is()) + { + xComp->dispose(); + } + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "Error in cleanup of multiple graphic object import." ); + } +} + +namespace +{ +uno::Reference getGraphicPropertySetFromImportContext(const SvXMLImportContext& rContext) +{ + uno::Reference aPropertySet; + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast(&rContext); + + if (pSdXMLGraphicObjectShapeContext) + aPropertySet.set(pSdXMLGraphicObjectShapeContext->getShape(), uno::UNO_QUERY); + + return aPropertySet; +} + +} // end anonymous namespace + +uno::Reference SdXMLFrameShapeContext::getGraphicFromImportContext(const SvXMLImportContext& rContext) const +{ + uno::Reference xGraphic; + try + { + const uno::Reference xPropertySet = getGraphicPropertySetFromImportContext(rContext); + + if (xPropertySet.is()) + { + xPropertySet->getPropertyValue("Graphic") >>= xGraphic; + } + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "Error in cleanup of multiple graphic object import."); + } + + return xGraphic; +} + +OUString SdXMLFrameShapeContext::getGraphicPackageURLFromImportContext(const SvXMLImportContext& rContext) const +{ + OUString aRetval; + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast< const SdXMLGraphicObjectShapeContext* >(&rContext); + + if(pSdXMLGraphicObjectShapeContext) + { + try + { + const uno::Reference< beans::XPropertySet > xPropSet(pSdXMLGraphicObjectShapeContext->getShape(), uno::UNO_QUERY_THROW); + + xPropSet->getPropertyValue("GraphicStreamURL") >>= aRetval; + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "Error in cleanup of multiple graphic object import." ); + } + } + + return aRetval; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLFrameShapeContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + SvXMLImportContextRef xContext; + if( !mxImplContext.is() ) + { + SvXMLShapeContext* pShapeContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, mxShapes, mxAttrList ); + + xContext = pShapeContext; + + // propagate the hyperlink to child context + if ( !msHyperlink.isEmpty() ) + pShapeContext->setHyperlink( msHyperlink ); + + auto nToken = nElement & TOKEN_MASK; + bool bMedia = false; + // Ignore gltf model if necessary and so the fallback image will be imported + if( nToken == XML_PLUGIN ) + { + SdXMLPluginShapeContext* pPluginContext = dynamic_cast(pShapeContext); + if( pPluginContext && pPluginContext->getMimeType() == "model/vnd.gltf+json" ) + { + mxImplContext = nullptr; + return new SvXMLImportContext(GetImport()); + } + else if (pPluginContext && pPluginContext->getMimeType() == "application/vnd.sun.star.media") + { + // The media may have a preview, import it. + bMedia = true; + } + } + + mxImplContext = xContext; + mbSupportsReplacement = (nToken == XML_OBJECT ) || (nToken == XML_OBJECT_OLE) || bMedia; + setSupportsMultipleContents(nToken == XML_IMAGE); + + if(getSupportsMultipleContents() && dynamic_cast< SdXMLGraphicObjectShapeContext* >(xContext.get())) + { + if ( !maShapeId.isEmpty() ) + GetImport().getInterfaceToIdentifierMapper().reserveIdentifier( maShapeId ); + + addContent(*mxImplContext); + } + } + else if(getSupportsMultipleContents() && nElement == XML_ELEMENT(DRAW, XML_IMAGE)) + { + // read another image + xContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, mxShapes, mxAttrList); + mxImplContext = xContext; + + if(dynamic_cast< SdXMLGraphicObjectShapeContext* >(xContext.get())) + { + addContent(*mxImplContext); + } + } + else if( mbSupportsReplacement && !mxReplImplContext.is() && + nElement == XML_ELEMENT(DRAW, XML_IMAGE) ) + { + // read replacement image + SvXMLImportContext *pImplContext = mxImplContext.get(); + SdXMLShapeContext *pSContext = + dynamic_cast( pImplContext ); + if( pSContext ) + { + uno::Reference < beans::XPropertySet > xPropSet( + pSContext->getShape(), uno::UNO_QUERY ); + if( xPropSet.is() ) + { + xContext = new XMLReplacementImageContext( GetImport(), + nElement, xAttrList, xPropSet ); + mxReplImplContext = xContext; + } + } + } + else if( nElement == XML_ELEMENT(SVG, XML_TITLE) || // #i68101# + nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || + nElement == XML_ELEMENT(SVG, XML_DESC) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC) || + nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) || + nElement == XML_ELEMENT(DRAW, XML_GLUE_POINT) || + nElement == XML_ELEMENT(DRAW, XML_THUMBNAIL) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + mxImplContext = solveMultipleImages(); + } + SvXMLImportContext *pImplContext = mxImplContext.get(); + xContext = static_cast(dynamic_cast(*pImplContext).createFastChildContext( nElement, + xAttrList ).get()); + } + else if ( nElement == XML_ELEMENT(DRAW, XML_IMAGE_MAP) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + mxImplContext = solveMultipleImages(); + } + SdXMLShapeContext *pSContext = dynamic_cast< SdXMLShapeContext* >( mxImplContext.get() ); + if( pSContext ) + { + uno::Reference < beans::XPropertySet > xPropSet( pSContext->getShape(), uno::UNO_QUERY ); + if (xPropSet.is()) + { + xContext = new XMLImageMapContext(GetImport(), xPropSet); + } + } + } + else if ( nElement == XML_ELEMENT(LO_EXT, XML_SIGNATURELINE) ) + { + SdXMLShapeContext* pSContext = dynamic_cast(mxImplContext.get()); + if (pSContext) + { + uno::Reference xPropSet(pSContext->getShape(), uno::UNO_QUERY); + if (xPropSet.is()) + { + xContext = new SignatureLineContext(GetImport(), nElement, xAttrList, + pSContext->getShape()); + } + } + } + else if ( nElement == XML_ELEMENT(LO_EXT, XML_QRCODE)) + { + SdXMLShapeContext* pSContext = dynamic_cast(mxImplContext.get()); + if (pSContext) + { + uno::Reference xPropSet(pSContext->getShape(), uno::UNO_QUERY); + if (xPropSet.is()) + { + xContext = new QRCodeContext(GetImport(), nElement, xAttrList, + pSContext->getShape()); + } + } + } + + return xContext; +} + +void SdXMLFrameShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + // ignore +} + +void SdXMLFrameShapeContext::endFastElement(sal_Int32 nElement) +{ + // solve if multiple image child contexts were imported + SvXMLImportContextRef const pSelectedContext(solveMultipleImages()); + const SdXMLGraphicObjectShapeContext* pShapeContext( + dynamic_cast(pSelectedContext.get())); + if ( pShapeContext ) + { + assert( mxImplContext.is() ); + const uno::Reference< uno::XInterface > xShape( pShapeContext->getShape() ); + GetImport().getInterfaceToIdentifierMapper().registerReservedReference( maShapeId, xShape ); + } + + if( !mxImplContext.is() ) + { + // now check if this is an empty presentation object + for( auto& aIter : sax_fastparser::castToFastAttributeList(mxAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(PRESENTATION, XML_PLACEHOLDER): + mbIsPlaceholder = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(PRESENTATION, XML_CLASS): + maPresentationClass = aIter.toString(); + break; + default:; + } + } + + if( (!maPresentationClass.isEmpty()) && mbIsPlaceholder ) + { + uno::Reference< xml::sax::XFastAttributeList> xEmpty; + + enum XMLTokenEnum eToken = XML_TEXT_BOX; + + if( IsXMLToken( maPresentationClass, XML_GRAPHIC ) ) + { + eToken = XML_IMAGE; + + } + else if( IsXMLToken( maPresentationClass, XML_PAGE ) ) + { + eToken = XML_PAGE_THUMBNAIL; + } + else if( IsXMLToken( maPresentationClass, XML_CHART ) || + IsXMLToken( maPresentationClass, XML_TABLE ) || + IsXMLToken( maPresentationClass, XML_OBJECT ) ) + { + eToken = XML_OBJECT; + } + + auto x = XML_ELEMENT(DRAW, eToken); + mxImplContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), x, mxAttrList, mxShapes, xEmpty ); + + if( mxImplContext.is() ) + { + mxImplContext->startFastElement( x, mxAttrList ); + mxImplContext->endFastElement(x); + } + } + } + + mxImplContext = nullptr; + SdXMLShapeContext::endFastElement(nElement); +} + +bool SdXMLFrameShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + bool bId( false ); + + switch ( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_ID): + case XML_ELEMENT(DRAW_EXT, XML_ID): + case XML_ELEMENT(NONE, XML_ID): + case XML_ELEMENT(XML, XML_ID) : + bId = true; + break; + default:; + } + + if ( bId ) + return SdXMLShapeContext::processAttribute( aIter ); + return true; // deliberately ignoring other attributes +} + + +SdXMLCustomShapeContext::SdXMLCustomShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ + // See the XMLTextFrameContext ctor, a frame has Writer content (and not + // editeng) if its autostyle has a parent style. Do the same for shapes as well. + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(DRAW, XML_STYLE_NAME)) + { + OUString aStyleName = aIter.toString(); + if(!aStyleName.isEmpty()) + { + rtl::Reference xTxtImport = GetImport().GetTextImport(); + XMLPropStyleContext* pStyle = xTxtImport->FindAutoFrameStyle(aStyleName); + // Note that this an API name, so intentionally not localized. + // Also allow other Frame styles with the same prefix, we just want to reject + // Graphics after all. + if (pStyle && pStyle->GetParentName().startsWith("Frame")) + { + mbTextBox = true; + break; + } + } + } + } +} + +SdXMLCustomShapeContext::~SdXMLCustomShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLCustomShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_ENGINE) ) + { + maCustomShapeEngine = aIter.toString(); + } + else if (aIter.getToken() == XML_ELEMENT(DRAW, XML_DATA) ) + { + maCustomShapeData = aIter.toString(); + } + else + return SdXMLShapeContext::processAttribute( aIter ); + return true; +} + +void SdXMLCustomShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create rectangle shape + AddShape("com.sun.star.drawing.CustomShape"); + if ( !mxShape.is() ) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + try + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + if ( !maCustomShapeEngine.isEmpty() ) + { + xPropSet->setPropertyValue( EASGet( EAS_CustomShapeEngine ), Any(maCustomShapeEngine) ); + } + if ( !maCustomShapeData.isEmpty() ) + { + xPropSet->setPropertyValue( EASGet( EAS_CustomShapeData ), Any(maCustomShapeData) ); + } + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting enhanced customshape geometry" ); + } + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +void SdXMLCustomShapeContext::endFastElement(sal_Int32 nElement) +{ + // Customshapes remember mirror state in its enhanced geometry. + // SetTransformation() in StartElement() may have applied mirroring, but that is not yet + // contained. Merge that information here before writing the property. + if(!maUsedTransformation.isIdentity()) + { + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + + maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + + if (aScale.getX() < 0.0) + { + static const OUStringLiteral sName(u"MirroredX"); + //fdo#84043 Merge, if property exists, otherwise append it + auto aI = std::find_if(maCustomShapeGeometry.begin(), maCustomShapeGeometry.end(), + [](beans::PropertyValue& rValue) { return rValue.Name == sName; }); + if (aI != maCustomShapeGeometry.end()) + { + beans::PropertyValue& rItem = *aI; + bool bMirroredX = *o3tl::doAccess(rItem.Value); + rItem.Value <<= !bMirroredX; + rItem.Handle = -1; + rItem.State = beans::PropertyState_DIRECT_VALUE; + } + else + { + beans::PropertyValue* pItem; + maCustomShapeGeometry.emplace_back(); + pItem = &maCustomShapeGeometry.back(); + pItem->Name = sName; + pItem->Handle = -1; + pItem->Value <<= true; + pItem->State = beans::PropertyState_DIRECT_VALUE; + } + } + + if (aScale.getY() < 0.0) + { + static const OUStringLiteral sName(u"MirroredY"); + //fdo#84043 Merge, if property exists, otherwise append it + auto aI = std::find_if(maCustomShapeGeometry.begin(), maCustomShapeGeometry.end(), + [](beans::PropertyValue& rValue) { return rValue.Name == sName; }); + if (aI != maCustomShapeGeometry.end()) + { + beans::PropertyValue& rItem = *aI; + bool bMirroredY = *o3tl::doAccess(rItem.Value); + rItem.Value <<= !bMirroredY; + rItem.Handle = -1; + rItem.State = beans::PropertyState_DIRECT_VALUE; + } + else + { + beans::PropertyValue* pItem; + maCustomShapeGeometry.emplace_back(); + pItem = &maCustomShapeGeometry.back(); + pItem->Name = sName; + pItem->Handle = -1; + pItem->Value <<= true; + pItem->State = beans::PropertyState_DIRECT_VALUE; + } + } + } + + if ( !maCustomShapeGeometry.empty() ) + { + // converting the vector to a sequence + uno::Sequence< beans::PropertyValue > aSeq( comphelper::containerToSequence(maCustomShapeGeometry) ); + + try + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + xPropSet->setPropertyValue( "CustomShapeGeometry", Any(aSeq) ); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting enhanced customshape geometry" ); + } + + sal_Int32 nUPD; + sal_Int32 nBuild; + if (GetImport().getBuildIds(nUPD, nBuild)) + { + if( ((nUPD >= 640 && nUPD <= 645) || (nUPD == 680)) && (nBuild <= 9221) ) + { + Reference< drawing::XEnhancedCustomShapeDefaulter > xDefaulter( mxShape, UNO_QUERY ); + if( xDefaulter.is() ) + { + xDefaulter->createCustomShapeDefaults( "" ); + } + } + } + } + + SdXMLShapeContext::endFastElement(nElement); + + // tdf#98163 call a custom slot to be able to reset the UNO API + // implementations held on the SdrObjects of type + // SdrObjCustomShape - those tend to linger until the entire file + // is loaded. For large files with a lot of these, 32bit systems + // may crash due to being out of resources after ca. 4200 + // Outliners and VirtualDevices used there as RefDevice + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + + if(xPropSet.is()) + { + xPropSet->setPropertyValue( + "FlushCustomShapeUnoApiObjects", css::uno::Any(true)); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "flushing after load"); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLCustomShapeContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + if ( nElement == XML_ELEMENT(DRAW, XML_ENHANCED_GEOMETRY) ) + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape,uno::UNO_QUERY ); + if ( xPropSet.is() ) + xContext = new XMLEnhancedCustomShapeContext( GetImport(), mxShape, maCustomShapeGeometry ); + } + // delegate to parent class if no context could be created + if (!xContext) + xContext = SdXMLShapeContext::createFastChildContext( nElement, + xAttrList); + return xContext; +} + +SdXMLTableShapeContext::SdXMLTableShapeContext( SvXMLImport& rImport, const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, css::uno::Reference< css::drawing::XShapes > const & rShapes ) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false ) +{ +} + +SdXMLTableShapeContext::~SdXMLTableShapeContext() +{ +} + +void SdXMLTableShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + OUString service("com.sun.star.drawing.TableShape"); + + bool bIsPresShape = !maPresentationClass.isEmpty() && GetImport().GetShapeImport()->IsPresentationShapesSupported(); + if( bIsPresShape ) + { + if( IsXMLToken( maPresentationClass, XML_TABLE ) ) + { + service = "com.sun.star.presentation.TableShape"; + } + } + + AddShape(service); + + if( !mxShape.is() ) + return; + + SetLayer(); + + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + + if(bIsPresShape && xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + + SetStyle(); + + if( xProps.is() ) + { + if( !msTemplateStyleName.isEmpty() ) try + { + Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetImport().GetModel(), UNO_QUERY_THROW ); + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + Reference< XNameAccess > xTableFamily( xFamilies->getByName( "table" ), UNO_QUERY_THROW ); + Reference< XStyle > xTableStyle( xTableFamily->getByName( msTemplateStyleName ), UNO_QUERY_THROW ); + xProps->setPropertyValue("TableTemplate", Any( xTableStyle ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + + const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; + for( int i = 0; pEntry->msApiName && (i < 6); i++, pEntry++ ) + { + try + { + const OUString sAPIPropertyName( pEntry->msApiName, pEntry->nApiNameLength, RTL_TEXTENCODING_ASCII_US ); + xProps->setPropertyValue( sAPIPropertyName, Any( maTemplateStylesUsed[i] ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + } + } + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); + + const rtl::Reference< XMLTableImport >& xTableImport( GetImport().GetShapeImport()->GetShapeTableImport() ); + if( xTableImport.is() && xProps.is() ) + { + uno::Reference< table::XColumnRowRange > xColumnRowRange( + xProps->getPropertyValue("Model"), uno::UNO_QUERY ); + + if( xColumnRowRange.is() ) + mxTableImportContext = xTableImport->CreateTableContext( xColumnRowRange ); + + if( mxTableImportContext.is() ) + mxTableImportContext->startFastElement( nElement, xAttrList ); + } +} + +void SdXMLTableShapeContext::endFastElement(sal_Int32 nElement) +{ + if( mxTableImportContext.is() ) + mxTableImportContext->endFastElement(nElement); + + SdXMLShapeContext::endFastElement(nElement); + + if( mxShape.is() ) + { + // set pos, size, shear and rotate + SetTransformation(); + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLTableShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + auto nElement = aIter.getToken(); + if( IsTokenInNamespace(nElement, XML_NAMESPACE_TABLE) ) + { + if( (nElement & TOKEN_MASK) == XML_TEMPLATE_NAME ) + { + msTemplateStyleName = aIter.toString(); + } + else + { + int i = 0; + const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; + while( pEntry->msApiName && (i < 6) ) + { + if( (nElement & TOKEN_MASK) == pEntry->meXMLName ) + { + if( IsXMLToken( aIter, XML_TRUE ) ) + maTemplateStylesUsed[i] = true; + break; + } + pEntry++; + i++; + } + } + } + return SdXMLShapeContext::processAttribute( aIter ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLTableShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( mxTableImportContext.is() && IsTokenInNamespace(nElement, XML_NAMESPACE_TABLE) ) + return mxTableImportContext->createFastChildContext(nElement, xAttrList); + return SdXMLShapeContext::createFastChildContext(nElement, xAttrList); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpshap.hxx b/xmloff/source/draw/ximpshap.hxx new file mode 100644 index 000000000..e11f1688e --- /dev/null +++ b/xmloff/source/draw/ximpshap.hxx @@ -0,0 +1,640 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template struct SvXMLEnumMapEntry; + +// common shape context + +class SdXMLShapeContext : public SvXMLShapeContext +{ +protected: + // the shape group this object should be created inside + css::uno::Reference< css::drawing::XShapes > mxShapes; + css::uno::Reference< css::text::XTextCursor > mxCursor; + css::uno::Reference< css::text::XTextCursor > mxOldCursor; + css::uno::Reference< css::xml::sax::XFastAttributeList> mxAttrList; + css::uno::Reference< css::container::XIdentifierContainer > mxGluePoints; + css::uno::Reference< css::document::XActionLockable > mxLockable; + + OUString maDrawStyleName; + OUString maTextStyleName; + OUString maPresentationClass; + OUString maShapeName; + OUString maThumbnailURL; + + /// whether to restore list context (#91964#) + bool mbListContextPushed; + + XmlStyleFamily mnStyleFamily; + bool mbIsPlaceholder; + bool mbClearDefaultAttributes; + bool mbIsUserTransformed; + sal_Int32 mnZOrder; + OUString maShapeId; + OUString maLayerName; + + SdXMLImExTransform2D mnTransform; + css::awt::Size maSize; + sal_Int16 mnRelWidth; + sal_Int16 mnRelHeight; + css::awt::Point maPosition; + basegfx::B2DHomMatrix maUsedTransformation; + + bool mbVisible; + bool mbPrintable; + bool mbHaveXmlId; + bool mbTextBox; ///< If the text of this shape is handled by a Writer TextFrame. + + /** if bSupportsStyle is false, auto styles will be set but not a style */ + void SetStyle( bool bSupportsStyle = true ); + void SetLayer(); + void SetThumbnail(); + + void AddShape(css::uno::Reference< css::drawing::XShape >& xShape); + void AddShape(OUString const & serviceName); + void SetTransformation(); + + using SvXMLImportContext::GetImport; + + void addGluePoint( const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + bool isPresentationShape() const; + +public: + + SdXMLShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ); + +}; + +// draw:rect context + +class SdXMLRectShapeContext : public SdXMLShapeContext +{ + sal_Int32 mnRadius; + +public: + + SdXMLRectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLRectShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:line context + +class SdXMLLineShapeContext : public SdXMLShapeContext +{ + sal_Int32 mnX1; + sal_Int32 mnY1; + sal_Int32 mnX2; + sal_Int32 mnY2; + +public: + + SdXMLLineShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLLineShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:ellipse and draw:circle context + +class SdXMLEllipseShapeContext : public SdXMLShapeContext +{ + sal_Int32 mnCX; + sal_Int32 mnCY; + sal_Int32 mnRX; + sal_Int32 mnRY; + + css::drawing::CircleKind meKind; + sal_Int32 mnStartAngle; + sal_Int32 mnEndAngle; +public: + + SdXMLEllipseShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLEllipseShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:polyline and draw:polygon context + +class SdXMLPolygonShapeContext : public SdXMLShapeContext +{ + OUString maPoints; + OUString maViewBox; + bool mbClosed; + +public: + + SdXMLPolygonShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, bool bClosed, bool bTemporaryShape); + virtual ~SdXMLPolygonShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:path context + +class SdXMLPathShapeContext : public SdXMLShapeContext +{ + OUString maD; + OUString maViewBox; + +public: + + SdXMLPathShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLPathShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:text-box context + +class SdXMLTextBoxShapeContext : public SdXMLShapeContext +{ + sal_Int32 mnRadius; + OUString maChainNextName; + +public: + + SdXMLTextBoxShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLTextBoxShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:control context + +class SdXMLControlShapeContext : public SdXMLShapeContext +{ +private: + OUString maFormId; + +public: + + SdXMLControlShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLControlShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:connector context + +class SdXMLConnectorShapeContext : public SdXMLShapeContext +{ +private: + css::awt::Point maStart; + css::awt::Point maEnd; + + css::drawing::ConnectorType + mnType; + + OUString maStartShapeId; + sal_Int32 mnStartGlueId; + OUString maEndShapeId; + sal_Int32 mnEndGlueId; + + sal_Int32 mnDelta1; + sal_Int32 mnDelta2; + sal_Int32 mnDelta3; + + css::uno::Any maPath; + +public: + + SdXMLConnectorShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLConnectorShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:measure context + +class SdXMLMeasureShapeContext : public SdXMLShapeContext +{ +private: + css::awt::Point maStart; + css::awt::Point maEnd; + +public: + + SdXMLMeasureShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLMeasureShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:page context + +class SdXMLPageShapeContext : public SdXMLShapeContext +{ +private: + sal_Int32 mnPageNumber; +public: + + SdXMLPageShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLPageShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:caption context + +class SdXMLCaptionShapeContext : public SdXMLShapeContext +{ +private: + css::awt::Point maCaptionPoint; + sal_Int32 mnRadius; + +public: + + SdXMLCaptionShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLCaptionShapeContext() override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// office:image context + +class SdXMLGraphicObjectShapeContext : public SdXMLShapeContext +{ +private: + OUString maURL; + css::uno::Reference < css::io::XOutputStream > mxBase64Stream; + +public: + + SdXMLGraphicObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLGraphicObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// chart:chart context + +class SdXMLChartShapeContext : public SdXMLShapeContext +{ + SvXMLImportContextRef mxChartContext; + +public: + + SdXMLChartShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +// draw:object and draw:object_ole context + +class SdXMLObjectShapeContext : public SdXMLShapeContext +{ +private: + OUString maCLSID; + OUString maHref; + + css::uno::Reference < css::io::XOutputStream > mxBase64Stream; + +public: + + SdXMLObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLObjectShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:applet + +class SdXMLAppletShapeContext : public SdXMLShapeContext +{ +private: + OUString maAppletName; + OUString maAppletCode; + OUString maHref; + bool mbIsScript; + + css::uno::Sequence< css::beans::PropertyValue > maParams; + +public: + + SdXMLAppletShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLAppletShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:plugin + +class SdXMLPluginShapeContext : public SdXMLShapeContext +{ +private: + OUString maMimeType; + OUString maHref; + bool mbMedia; + + css::uno::Sequence< css::beans::PropertyValue > maParams; + +public: + + SdXMLPluginShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLPluginShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; + + const OUString& getMimeType() const { return maMimeType; } +}; + +// draw:floating-frame + +class SdXMLFloatingFrameShapeContext : public SdXMLShapeContext +{ +private: + OUString maFrameName; + OUString maHref; + + css::uno::Reference CreateFloatingFrameShape() const; + +public: + + SdXMLFloatingFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLFloatingFrameShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:-frame + +class SdXMLFrameShapeContext : public SdXMLShapeContext, public MultiImageImportHelper +{ +private: + bool mbSupportsReplacement; + SvXMLImportContextRef mxImplContext; + SvXMLImportContextRef mxReplImplContext; + +protected: + /// helper to get the created xShape instance, needs to be overridden + void removeGraphicFromImportContext(const SvXMLImportContext& rContext) override; + OUString getGraphicPackageURLFromImportContext(const SvXMLImportContext& rContext) const override; + css::uno::Reference getGraphicFromImportContext(const SvXMLImportContext& rContext) const override; + +public: + + SdXMLFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape); + virtual ~SdXMLFrameShapeContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +class SdXMLCustomShapeContext : public SdXMLShapeContext +{ + OUString maCustomShapeEngine; + OUString maCustomShapeData; + + std::vector< css::beans::PropertyValue > maCustomShapeGeometry; + +public: + + + SdXMLCustomShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLCustomShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; +}; + +// draw:table + +class SdXMLTableShapeContext : public SdXMLShapeContext +{ +public: + + SdXMLTableShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes ); + virtual ~SdXMLTableShapeContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // this is called from the parent group for each unparsed attribute in the attribute list + virtual bool processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & ) override; + +private: + SvXMLImportContextRef mxTableImportContext; + OUString msTemplateStyleName; + bool maTemplateStylesUsed[6] = {}; +}; + +extern SvXMLEnumMapEntry const aXML_GlueAlignment_EnumMap[]; +extern SvXMLEnumMapEntry const aXML_GlueEscapeDirection_EnumMap[]; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpshow.cxx b/xmloff/source/draw/ximpshow.cxx new file mode 100644 index 000000000..f89d4d9fb --- /dev/null +++ b/xmloff/source/draw/ximpshow.cxx @@ -0,0 +1,244 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ximpshow.hxx" + +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::presentation; +using namespace ::xmloff::token; + +SdXMLShowsContext::SdXMLShowsContext( SdXMLImport& rImport, const Reference< XFastAttributeList >& xAttrList ) +: SvXMLImportContext(rImport) +{ + + Reference< XCustomPresentationSupplier > xShowsSupplier( rImport.GetModel(), UNO_QUERY ); + if( xShowsSupplier.is() ) + { + mxShows = xShowsSupplier->getCustomPresentations(); + mxShowFactory.set( mxShows, UNO_QUERY ); + } + + Reference< XDrawPagesSupplier > xDrawPagesSupplier( rImport.GetModel(), UNO_QUERY ); + if( xDrawPagesSupplier.is() ) + mxPages.set( xDrawPagesSupplier->getDrawPages(), UNO_QUERY ); + + Reference< XPresentationSupplier > xPresentationSupplier( rImport.GetModel(), UNO_QUERY ); + if( xPresentationSupplier.is() ) + mxPresProps.set( xPresentationSupplier->getPresentation(), UNO_QUERY ); + + if( !mxPresProps.is() ) + return; + + bool bAll = true; + uno::Any aAny; + // Per ODF this is default, but we did it wrong before LO 6.0 (tdf#108824) + bool bIsMouseVisible = true; + if (rImport.getGeneratorVersion() < SvXMLImport::LO_6x) + bIsMouseVisible = false; + + // read attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(PRESENTATION, XML_START_PAGE): + { + mxPresProps->setPropertyValue("FirstPage", Any(aIter.toString()) ); + bAll = false; + break; + } + case XML_ELEMENT(PRESENTATION, XML_SHOW): + { + maCustomShowName = aIter.toString(); + bAll = false; + break; + } + case XML_ELEMENT(PRESENTATION, XML_PAUSE): + { + Duration aDuration; + if (!::sax::Converter::convertDuration(aDuration, aIter.toView())) + continue; + + const sal_Int32 nMS = (aDuration.Hours * 60 + + aDuration.Minutes) * 60 + aDuration.Seconds; + mxPresProps->setPropertyValue("Pause", Any(nMS) ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_ANIMATIONS): + { + aAny <<= IsXMLToken( aIter, XML_ENABLED ); + mxPresProps->setPropertyValue("AllowAnimations", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_STAY_ON_TOP): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsAlwaysOnTop", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_FORCE_MANUAL): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsAutomatic", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_ENDLESS): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsEndless", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_FULL_SCREEN): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsFullScreen", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_MOUSE_VISIBLE): + { + bIsMouseVisible = IsXMLToken( aIter, XML_TRUE ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_START_WITH_NAVIGATOR): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("StartWithNavigator", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_MOUSE_AS_PEN): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("UsePen", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_TRANSITION_ON_CLICK): + { + aAny <<= IsXMLToken( aIter, XML_ENABLED ); + mxPresProps->setPropertyValue("IsTransitionOnClick", aAny ); + break; + } + case XML_ELEMENT(PRESENTATION, XML_SHOW_LOGO): + { + aAny <<= IsXMLToken( aIter, XML_TRUE ); + mxPresProps->setPropertyValue("IsShowLogo", aAny ); + break; + } + } + } + mxPresProps->setPropertyValue("IsShowAll", Any(bAll) ); + mxPresProps->setPropertyValue("IsMouseVisible", Any(bIsMouseVisible) ); +} + +SdXMLShowsContext::~SdXMLShowsContext() +{ + if( !maCustomShowName.isEmpty() ) + { + uno::Any aAny; + aAny <<= maCustomShowName; + mxPresProps->setPropertyValue("CustomShow", aAny ); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLShowsContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(PRESENTATION, XML_SHOW) ) + { + OUString aName; + OUString aPages; + + // read attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + OUString sValue = aIter.toString(); + + switch( aIter.getToken() ) + { + case XML_ELEMENT(PRESENTATION, XML_NAME): + aName = sValue; + break; + case XML_ELEMENT(PRESENTATION, XML_PAGES): + aPages = sValue; + break; + } + } + + if( !aName.isEmpty() && !aPages.isEmpty() ) + { + Reference< XIndexContainer > xShow( mxShowFactory->createInstance(), UNO_QUERY ); + if( xShow.is() ) + { + SvXMLTokenEnumerator aPageNames( aPages, ',' ); + std::u16string_view sPageNameView; + + while( aPageNames.getNextToken( sPageNameView ) ) + { + OUString sPageName(sPageNameView); + if( !mxPages->hasByName( sPageName ) ) + continue; + + Reference< XDrawPage > xPage; + mxPages->getByName( sPageName ) >>= xPage; + if( xPage.is() ) + { + xShow->insertByIndex( xShow->getCount(), Any(xPage) ); + } + } + + Any aAny; + aAny <<= xShow; + if( mxShows->hasByName( aName ) ) + { + mxShows->replaceByName( aName, aAny ); + } + else + { + mxShows->insertByName( aName, aAny ); + } + } + } + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpshow.hxx b/xmloff/source/draw/ximpshow.hxx new file mode 100644 index 000000000..33948c3a6 --- /dev/null +++ b/xmloff/source/draw/ximpshow.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/. + * + * 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 +#include "sdxmlimp_impl.hxx" +#include +#include +#include +#include + +// presentations:animations + +class SdXMLShowsContext : public SvXMLImportContext +{ +public: + + SdXMLShowsContext( SdXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList); + virtual ~SdXMLShowsContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +private: + css::uno::Reference< css::lang::XSingleServiceFactory > mxShowFactory; + css::uno::Reference< css::container::XNameContainer > mxShows; + css::uno::Reference< css::beans::XPropertySet > mxPresProps; + css::uno::Reference< css::container::XNameAccess > mxPages; + OUString maCustomShowName; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpstyl.cxx b/xmloff/source/draw/ximpstyl.cxx new file mode 100644 index 000000000..4befbb008 --- /dev/null +++ b/xmloff/source/draw/ximpstyl.cxx @@ -0,0 +1,1600 @@ +/* -*- 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 "ximpstyl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include "ximpnote.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "layerimp.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +namespace { + +class SdXMLDrawingPagePropertySetContext : public SvXMLPropertySetContext +{ +public: + + SdXMLDrawingPagePropertySetContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ); + + using SvXMLPropertySetContext::createFastChildContext; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; +}; + +/// Imports . +class XMLThemeContext : public SvXMLImportContext +{ + uno::Reference m_xMasterPage; + comphelper::SequenceAsHashMap m_aTheme; + +public: + XMLThemeContext(SvXMLImport& rImport, + const uno::Reference& xAttrList, + const uno::Reference& xMasterPage); + ~XMLThemeContext(); + + uno::Reference SAL_CALL createFastChildContext( + sal_Int32 nElement, const uno::Reference& xAttribs) override; +}; + +/// Imports inside . +class XMLColorTableContext : public SvXMLImportContext +{ + comphelper::SequenceAsHashMap& m_rTheme; + std::vector m_aColorScheme; + +public: + XMLColorTableContext(SvXMLImport& rImport, + const uno::Reference& xAttrList, + comphelper::SequenceAsHashMap& rTheme); + ~XMLColorTableContext(); + + uno::Reference SAL_CALL createFastChildContext( + sal_Int32 nElement, const uno::Reference& xAttribs) override; +}; + +/// Imports inside . +class XMLColorContext : public SvXMLImportContext +{ +public: + XMLColorContext(SvXMLImport& rImport, + const uno::Reference& xAttrList, + std::vector& rColorScheme); +}; +} + +SdXMLDrawingPagePropertySetContext::SdXMLDrawingPagePropertySetContext( + SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList > & xAttrList, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ) : + SvXMLPropertySetContext( rImport, nElement, xAttrList, + XML_TYPE_PROP_DRAWING_PAGE, rProps, rMap ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLDrawingPagePropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + switch( mxMapper->getPropertySetMapper()->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_PAGE_SOUND_URL: + { + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + if( aIter.getToken() == XML_ELEMENT(XLINK, XML_HREF) ) + { + uno::Any aAny( GetImport().GetAbsoluteReference( aIter.toString() ) ); + XMLPropertyState aPropState( rProp.mnIndex, aAny ); + rProperties.push_back( aPropState ); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + break; + } + } + + return SvXMLPropertySetContext::createFastChildContext( nElement, + xAttrList, + rProperties, rProp ); +} + +namespace { + + +class SdXMLDrawingPageStyleContext : public XMLDrawingPageStyleContext +{ +public: + + SdXMLDrawingPageStyleContext( + SvXMLImport& rImport, + SvXMLStylesContext& rStyles); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void Finish( bool bOverwrite ) override; +}; + +const sal_uInt16 MAX_SPECIAL_DRAW_STYLES = 7; +ContextID_Index_Pair const g_ContextIDs[MAX_SPECIAL_DRAW_STYLES+1] = +{ + { CTF_DASHNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_LINESTARTNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_LINEENDNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT}, + { CTF_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + { -1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE } +}; +XmlStyleFamily const g_Families[MAX_SPECIAL_DRAW_STYLES] = +{ + XmlStyleFamily::SD_STROKE_DASH_ID, + XmlStyleFamily::SD_MARKER_ID, + XmlStyleFamily::SD_MARKER_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID +}; + +} + +XMLDrawingPageStyleContext::XMLDrawingPageStyleContext( + SvXMLImport& rImport, + SvXMLStylesContext& rStyles, + ContextID_Index_Pair const pContextIDs[], + XmlStyleFamily const pFamilies[]) + : XMLPropStyleContext(rImport, rStyles, XmlStyleFamily::SD_DRAWINGPAGE_ID) + , m_pFamilies(pFamilies) +{ + size_t size(1); // for the -1 entry + for (ContextID_Index_Pair const* pTemp(pContextIDs); pTemp->nContextID != -1; ++size, ++pTemp); + m_pContextIDs.reset(new ContextID_Index_Pair[size]); + std::memcpy(m_pContextIDs.get(), pContextIDs, size * sizeof(ContextID_Index_Pair)); +} + +SdXMLDrawingPageStyleContext::SdXMLDrawingPageStyleContext( + SvXMLImport& rImport, + SvXMLStylesContext& rStyles) + : XMLDrawingPageStyleContext(rImport, rStyles, g_ContextIDs, g_Families) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLDrawingPageStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_DRAWING_PAGE_PROPERTIES) ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new SdXMLDrawingPagePropertySetContext( GetImport(), nElement, + xAttrList, + GetProperties(), + xImpPrMap ); + } + + return XMLPropStyleContext::createFastChildContext( nElement, xAttrList ); +} + +void SdXMLDrawingPageStyleContext::Finish( bool bOverwrite ) +{ + XMLPropStyleContext::Finish( bOverwrite ); + + ::std::vector< XMLPropertyState > &rProperties = GetProperties(); + + const rtl::Reference< XMLPropertySetMapper >& rImpPrMap = GetStyles()->GetImportPropertyMapper( GetFamily() )->getPropertySetMapper(); + + for(auto& property : rProperties) + { + if( property.mnIndex == -1 ) + continue; + + sal_Int16 nContextID = rImpPrMap->GetEntryContextId(property.mnIndex); + switch( nContextID ) + { + case CTF_DATE_TIME_FORMAT: + { + OUString sStyleName; + property.maValue >>= sStyleName; + + sal_Int32 nStyle = 0; + + const SdXMLNumberFormatImportContext* pSdNumStyle = + dynamic_cast< const SdXMLNumberFormatImportContext*> ( + GetStyles()->FindStyleChildContext( XmlStyleFamily::DATA_STYLE, sStyleName, true ) ); + + if( pSdNumStyle ) + nStyle = pSdNumStyle->GetDrawKey(); + + property.maValue <<= nStyle; + } + break; + } + } + +} + + +// #i35918# +void XMLDrawingPageStyleContext::FillPropertySet( + const Reference< beans::XPropertySet > & rPropSet ) +{ + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + SAL_WARN_IF( !xImpPrMap.is(), "xmloff", "There is the import prop mapper" ); + if( xImpPrMap.is() ) + xImpPrMap->FillPropertySet(GetProperties(), rPropSet, m_pContextIDs.get()); + + Reference< beans::XPropertySetInfo > xInfo; + for (size_t i=0; m_pContextIDs[i].nContextID != -1; ++i) + { + sal_Int32 nIndex = m_pContextIDs[i].nIndex; + if( nIndex != -1 ) + { + struct XMLPropertyState& rState = GetProperties()[nIndex]; + OUString sStyleName; + rState.maValue >>= sStyleName; + + if (::xmloff::IsIgnoreFillStyleNamedItem(rPropSet, m_pContextIDs[i].nExpectedFillStyle)) + { + SAL_INFO("xmloff.style", "XMLDrawingPageStyleContext: dropping fill named item: " << sStyleName); + break; // ignore it, it's not used + } + + sStyleName = GetImport().GetStyleDisplayName( m_pFamilies[i], + sStyleName ); + // get property set mapper + rtl::Reference rPropMapper = + xImpPrMap->getPropertySetMapper(); + + // set property + const OUString& rPropertyName = + rPropMapper->GetEntryAPIName(rState.mnIndex); + if( !xInfo.is() ) + xInfo = rPropSet->getPropertySetInfo(); + if ( xInfo->hasPropertyByName( rPropertyName ) ) + { + rPropSet->setPropertyValue( rPropertyName, Any( sStyleName ) ); + } + } + } +} + + +SdXMLPageMasterStyleContext::SdXMLPageMasterStyleContext( + SdXMLImport& rImport, + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList) +: SvXMLStyleContext(rImport, XmlStyleFamily::SD_PAGEMASTERSTYLECONTEXT_ID), + mnBorderBottom( 0 ), + mnBorderLeft( 0 ), + mnBorderRight( 0 ), + mnBorderTop( 0 ), + mnWidth( 0 ), + mnHeight( 0 ), + meOrientation(GetSdImport().IsDraw() ? view::PaperOrientation_PORTRAIT : view::PaperOrientation_LANDSCAPE) +{ + // set family to something special at SvXMLStyleContext + // for differences in search-methods + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(FO, XML_MARGIN_TOP): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_TOP): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnBorderTop, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_MARGIN_BOTTOM): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_BOTTOM): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnBorderBottom, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_MARGIN_LEFT): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_LEFT): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnBorderLeft, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_MARGIN_RIGHT): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_RIGHT): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnBorderRight, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_PAGE_WIDTH): + case XML_ELEMENT(FO_COMPAT, XML_PAGE_WIDTH): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnWidth, aIter.toView()); + break; + } + case XML_ELEMENT(FO, XML_PAGE_HEIGHT): + case XML_ELEMENT(FO_COMPAT, XML_PAGE_HEIGHT): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnHeight, aIter.toView()); + break; + } + case XML_ELEMENT(STYLE, XML_PRINT_ORIENTATION): + { + if( IsXMLToken( aIter, XML_PORTRAIT ) ) + meOrientation = view::PaperOrientation_PORTRAIT; + else + meOrientation = view::PaperOrientation_LANDSCAPE; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXMLPageMasterStyleContext::~SdXMLPageMasterStyleContext() +{ +} + + +SdXMLPageMasterContext::SdXMLPageMasterContext( + SdXMLImport& rImport, + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList>& /*xAttrList*/) +: SvXMLStyleContext(rImport, XmlStyleFamily::SD_PAGEMASTERCONTEXT_ID) +{ + // set family to something special at SvXMLStyleContext + // for differences in search-methods + +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLPageMasterContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if(nElement == XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_PROPERTIES)) + { + DBG_ASSERT(!mxPageMasterStyle.is(), "PageMasterStyle is set, there seem to be two of them (!)"); + mxPageMasterStyle.set(new SdXMLPageMasterStyleContext(GetSdImport(), nElement, xAttrList)); + return mxPageMasterStyle; + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +SdXMLPresentationPageLayoutContext::SdXMLPresentationPageLayoutContext( + SdXMLImport& rImport, + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/) +: SvXMLStyleContext(rImport, XmlStyleFamily::SD_PRESENTATIONPAGELAYOUT_ID), + mnTypeId( AUTOLAYOUT_NONE ) +{ + // set family to something special at SvXMLStyleContext + // for differences in search-methods +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLPresentationPageLayoutContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + + if(nElement == XML_ELEMENT(PRESENTATION, XML_PLACEHOLDER)) + { + const rtl::Reference< SdXMLPresentationPlaceholderContext > xLclContext{ + new SdXMLPresentationPlaceholderContext(GetSdImport(), nElement, xAttrList)}; + // presentation:placeholder inside style:presentation-page-layout context + xContext = xLclContext.get(); + + // remember SdXMLPresentationPlaceholderContext for later evaluation + maList.push_back(xLclContext); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return xContext; +} + +void SdXMLPresentationPageLayoutContext::endFastElement(sal_Int32 ) +{ + // build presentation page layout type here + // calc mnTpeId due to content of maList + // at the moment only use number of types used there + if( maList.empty() ) + return; + + SdXMLPresentationPlaceholderContext* pObj0 = maList[ 0 ].get(); + if( pObj0->GetName() == "handout" ) + { + switch( maList.size() ) + { + case 1: + mnTypeId = AUTOLAYOUT_HANDOUT1; + break; + case 2: + mnTypeId = AUTOLAYOUT_HANDOUT2; + break; + case 3: + mnTypeId = AUTOLAYOUT_HANDOUT3; + break; + case 4: + mnTypeId = AUTOLAYOUT_HANDOUT4; + break; + case 9: + mnTypeId = AUTOLAYOUT_HANDOUT9; + break; + default: + mnTypeId = AUTOLAYOUT_HANDOUT6; + } + } + else + { + switch( maList.size() ) + { + case 1: + { + if( pObj0->GetName() == "title" ) + { + mnTypeId = AUTOLAYOUT_TITLE_ONLY; + } + else + { + mnTypeId = AUTOLAYOUT_ONLY_TEXT; + } + break; + } + case 2: + { + SdXMLPresentationPlaceholderContext* pObj1 = maList[ 1 ].get(); + + if( pObj1->GetName() == "subtitle" ) + { + mnTypeId = AUTOLAYOUT_TITLE; + } + else if( pObj1->GetName() == "outline" ) + { + mnTypeId = AUTOLAYOUT_TITLE_CONTENT; + } + else if( pObj1->GetName() == "chart" ) + { + mnTypeId = AUTOLAYOUT_CHART; + } + else if( pObj1->GetName() == "table" ) + { + mnTypeId = AUTOLAYOUT_TAB; + } + else if( pObj1->GetName() == "object" ) + { + mnTypeId = AUTOLAYOUT_OBJ; + } + else if( pObj1->GetName() == "vertical_outline" ) + { + if( pObj0->GetName() == "vertical_title" ) + { + mnTypeId = AUTOLAYOUT_VTITLE_VCONTENT; + } + else + { + mnTypeId = AUTOLAYOUT_TITLE_VCONTENT; + } + } + else + { + mnTypeId = AUTOLAYOUT_NOTES; + } + break; + } + case 3: + { + SdXMLPresentationPlaceholderContext* pObj1 = maList[ 1 ].get(); + SdXMLPresentationPlaceholderContext* pObj2 = maList[ 2 ].get(); + + if( pObj1->GetName() == "outline" ) + { + if( pObj2->GetName() == "outline" ) + { + mnTypeId = AUTOLAYOUT_TITLE_2CONTENT; + } + else if( pObj2->GetName() == "chart" ) + { + mnTypeId = AUTOLAYOUT_TEXTCHART; + } + else if( pObj2->GetName() == "graphic" ) + { + mnTypeId = AUTOLAYOUT_TEXTCLIP; + } + else + { + if(pObj1->GetX() < pObj2->GetX()) + { + mnTypeId = AUTOLAYOUT_TEXTOBJ; // outline left, object right + } + else + { + mnTypeId = AUTOLAYOUT_TEXTOVEROBJ; // outline top, object right + } + } + } + else if( pObj1->GetName() == "chart" ) + { + mnTypeId = AUTOLAYOUT_CHARTTEXT; + } + else if( pObj1->GetName() == "graphic" ) + { + if( pObj2->GetName() == "vertical_outline" ) + { + mnTypeId = AUTOLAYOUT_TITLE_2VTEXT; + } + else + { + mnTypeId = AUTOLAYOUT_CLIPTEXT; + } + } + else if( pObj1->GetName() == "vertical_outline" ) + { + mnTypeId = AUTOLAYOUT_VTITLE_VCONTENT_OVER_VCONTENT; + } + else + { + if(pObj1->GetX() < pObj2->GetX()) + { + mnTypeId = AUTOLAYOUT_OBJTEXT; // left, right + } + else + { + mnTypeId = AUTOLAYOUT_TITLE_CONTENT_OVER_CONTENT; // top, bottom + } + } + break; + } + case 4: + { + SdXMLPresentationPlaceholderContext* pObj1 = maList[ 1 ].get(); + SdXMLPresentationPlaceholderContext* pObj2 = maList[ 2 ].get(); + + if( pObj1->GetName() == "object" ) + { + if(pObj1->GetX() < pObj2->GetX()) + { + mnTypeId = AUTOLAYOUT_TITLE_2CONTENT_OVER_CONTENT; + } + else + { + mnTypeId = AUTOLAYOUT_TITLE_2CONTENT_CONTENT; + } + } + else + { + mnTypeId = AUTOLAYOUT_TITLE_CONTENT_2CONTENT; + } + break; + } + case 5: + { + SdXMLPresentationPlaceholderContext* pObj1 = maList[ 1 ].get(); + + if( pObj1->GetName() == "object" ) + { + mnTypeId = AUTOLAYOUT_TITLE_4CONTENT; + } + else + { + mnTypeId = AUTOLAYOUT_4CLIPART; + } + break; + + } + case 7: + { + mnTypeId = AUTOLAYOUT_TITLE_6CONTENT; // tdf#141978: Apply 6content layout + break; + } + default: + { + mnTypeId = AUTOLAYOUT_NONE; + break; + } + } + } + + // release remembered contexts, they are no longer needed + maList.clear(); +} + +SdXMLPresentationPlaceholderContext::SdXMLPresentationPlaceholderContext( + SdXMLImport& rImport, + sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList) +: SvXMLImportContext( rImport ), + mnX(0) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(PRESENTATION, XML_OBJECT): + { + msName = aIter.toString(); + break; + } + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + { + GetSdImport().GetMM100UnitConverter().convertMeasureToCore( + mnX, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + { + break; + } + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + { + break; + } + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + { + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +SdXMLPresentationPlaceholderContext::~SdXMLPresentationPlaceholderContext() +{ +} + + +SdXMLMasterPageContext::SdXMLMasterPageContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLGenericPageContext( rImport, xAttrList, rShapes ) +{ + const bool bHandoutMaster = (nElement & TOKEN_MASK) == XML_HANDOUT_MASTER; + OUString sStyleName, sPageMasterName; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + const OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_NAME): + { + msName = sValue; + break; + } + case XML_ELEMENT(STYLE, XML_DISPLAY_NAME): + { + msDisplayName = sValue; + break; + } + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_NAME): + { + sPageMasterName = sValue; + break; + } + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + sStyleName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_PRESENTATION_PAGE_LAYOUT_NAME): + { + maPageLayoutName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_HEADER_NAME): + { + maUseHeaderDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_FOOTER_NAME): + { + maUseFooterDeclName = sValue; + break; + } + case XML_ELEMENT(PRESENTATION, XML_USE_DATE_TIME_NAME): + { + maUseDateTimeDeclName = sValue; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( msDisplayName.isEmpty() ) + msDisplayName = msName; + else if( msDisplayName != msName ) + GetImport().AddStyleDisplayName( XmlStyleFamily::MASTER_PAGE, msName, msDisplayName ); + + GetImport().GetShapeImport()->startPage( GetLocalShapesContext() ); + + // set page name? + if(!bHandoutMaster && !msDisplayName.isEmpty() && GetLocalShapesContext().is()) + { + uno::Reference < container::XNamed > xNamed(GetLocalShapesContext(), uno::UNO_QUERY); + if(xNamed.is()) + xNamed->setName(msDisplayName); + } + + // set page-master? + if(!sPageMasterName.isEmpty()) + { + SetPageMaster( sPageMasterName ); + } + + SetStyle( sStyleName ); + + SetLayout(); + + DeleteAllShapes(); +} + +SdXMLMasterPageContext::~SdXMLMasterPageContext() +{ +} + +void SdXMLMasterPageContext::endFastElement(sal_Int32 nElement) +{ + // set styles on master-page + if(!msName.isEmpty() && GetSdImport().GetShapeImport()->GetStylesContext()) + { + SvXMLImportContext* pContext = GetSdImport().GetShapeImport()->GetStylesContext(); + if (SdXMLStylesContext* pSdContext = dynamic_cast(pContext)) + pSdContext->SetMasterPageStyles(*this); + } + + SdXMLGenericPageContext::endFastElement(nElement); + GetImport().GetShapeImport()->endPage(GetLocalShapesContext()); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLMasterPageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + switch (nElement) + { + // some special objects inside style:masterpage context + case XML_ELEMENT(STYLE, XML_STYLE): + { + if(GetSdImport().GetShapeImport()->GetStylesContext()) + { + // style:style inside master-page context -> presentation style + XMLShapeStyleContext* pNew = new XMLShapeStyleContext( + GetSdImport(), + *GetSdImport().GetShapeImport()->GetStylesContext(), + XmlStyleFamily::SD_PRESENTATION_ID); + + // add this style to the outer StylesContext class for later processing + GetSdImport().GetShapeImport()->GetStylesContext()->AddStyle(*pNew); + return pNew; + } + break; + } + case XML_ELEMENT(PRESENTATION, XML_NOTES): + { + if( GetSdImport().IsImpress() ) + { + // get notes page + uno::Reference< presentation::XPresentationPage > xPresPage(GetLocalShapesContext(), uno::UNO_QUERY); + if(xPresPage.is()) + { + uno::Reference< drawing::XDrawPage > xNotesDrawPage = xPresPage->getNotesPage(); + if(xNotesDrawPage.is()) + { + // presentation:notes inside master-page context + return new SdXMLNotesContext( GetSdImport(), xAttrList, xNotesDrawPage); + } + } + } + break; + } + case XML_ELEMENT(LO_EXT, XML_THEME): + { + if (GetSdImport().IsImpress()) + { + uno::Reference xMasterPage(GetLocalShapesContext(), + uno::UNO_QUERY); + return new XMLThemeContext(GetSdImport(), xAttrList, xMasterPage); + } + break; + } + } + return SdXMLGenericPageContext::createFastChildContext(nElement, xAttrList); +} + +SdXMLStylesContext::SdXMLStylesContext( + SdXMLImport& rImport, + bool bIsAutoStyle) +: SvXMLStylesContext(rImport), + mbIsAutoStyle(bIsAutoStyle) +{ + Reference< uno::XComponentContext > xContext = rImport.GetComponentContext(); + mpNumFormatter = std::make_unique( xContext, LANGUAGE_SYSTEM ); + mpNumFmtHelper = std::make_unique( mpNumFormatter.get(), xContext ); +} + +SvXMLStyleContext* SdXMLStylesContext::CreateStyleChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +{ + switch (nElement) + { + case XML_ELEMENT(TABLE, XML_TABLE_TEMPLATE): + { + auto pContext = GetImport().GetShapeImport()->GetShapeTableImport()->CreateTableTemplateContext(nElement, xAttrList ); + if (pContext) + return pContext; + break; + } + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT): + // style:page-master inside office:styles context + return new SdXMLPageMasterContext(GetSdImport(), nElement, xAttrList); + case XML_ELEMENT(STYLE, XML_PRESENTATION_PAGE_LAYOUT): + // style:presentation-page-layout inside office:styles context + return new SdXMLPresentationPageLayoutContext(GetSdImport(), nElement, xAttrList); + case XML_ELEMENT(NUMBER, XML_DATE_STYLE): + // number:date-style or number:time-style + return new SdXMLNumberFormatImportContext( GetSdImport(), nElement, mpNumFmtHelper->getData(), SvXMLStylesTokens::DATE_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_TIME_STYLE): + // number:date-style or number:time-style + return new SdXMLNumberFormatImportContext( GetSdImport(), nElement, mpNumFmtHelper->getData(), SvXMLStylesTokens::TIME_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_NUMBER_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::NUMBER_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_CURRENCY_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::CURRENCY_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_PERCENTAGE_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::PERCENTAGE_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_BOOLEAN_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::BOOLEAN_STYLE, xAttrList, *this ); + case XML_ELEMENT(NUMBER, XML_TEXT_STYLE): + return new SvXMLNumFormatContext( GetSdImport(), nElement, + mpNumFmtHelper->getData(), SvXMLStylesTokens::TEXT_STYLE, xAttrList, *this ); + case XML_ELEMENT(PRESENTATION, XML_HEADER_DECL): + case XML_ELEMENT(PRESENTATION, XML_FOOTER_DECL): + case XML_ELEMENT(PRESENTATION, XML_DATE_TIME_DECL): + return new SdXMLHeaderFooterDeclContext( GetImport(), xAttrList ); + case XML_ELEMENT(STYLE, XML_STYLE): + break; // ignore + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + // call base class + return SvXMLStylesContext::CreateStyleChildContext(nElement, xAttrList); +} + +SvXMLStyleContext* SdXMLStylesContext::CreateStyleStyleChildContext( + XmlStyleFamily nFamily, + sal_Int32 nElement, + const uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + switch( nFamily ) + { + case XmlStyleFamily::SD_DRAWINGPAGE_ID: + return new SdXMLDrawingPageStyleContext(GetSdImport(), *this ); + case XmlStyleFamily::TABLE_CELL: + case XmlStyleFamily::TABLE_COLUMN: + case XmlStyleFamily::TABLE_ROW: + return new XMLShapeStyleContext( GetSdImport(), *this, nFamily ); + default: break; + } + + // call base class + return SvXMLStylesContext::CreateStyleStyleChildContext(nFamily, nElement, xAttrList); +} + +SvXMLStyleContext* SdXMLStylesContext::CreateDefaultStyleStyleChildContext( + XmlStyleFamily nFamily, + sal_Int32 nElement, + const Reference< XFastAttributeList > & xAttrList ) +{ + switch( nFamily ) + { + case XmlStyleFamily::SD_GRAPHICS_ID: + return new XMLGraphicsDefaultStyle(GetSdImport(), *this ); + default: break; + } + + // call base class + return SvXMLStylesContext::CreateDefaultStyleStyleChildContext(nFamily, nElement, xAttrList); +} + +rtl::Reference< SvXMLImportPropertyMapper > SdXMLStylesContext::GetImportPropertyMapper( + XmlStyleFamily nFamily) const +{ + rtl::Reference < SvXMLImportPropertyMapper > xMapper; + + switch( nFamily ) + { + case XmlStyleFamily::SD_DRAWINGPAGE_ID: + { + if(!xPresImpPropMapper.is()) + { + rtl::Reference< XMLShapeImportHelper > aImpHelper = const_cast(GetImport()).GetShapeImport(); + const_cast(this)->xPresImpPropMapper = + aImpHelper->GetPresPagePropsMapper(); + } + xMapper = xPresImpPropMapper; + break; + } + + case XmlStyleFamily::TABLE_COLUMN: + case XmlStyleFamily::TABLE_ROW: + case XmlStyleFamily::TABLE_CELL: + { + const rtl::Reference< XMLTableImport >& xTableImport( const_cast< SvXMLImport& >( GetImport() ).GetShapeImport()->GetShapeTableImport() ); + + switch( nFamily ) + { + case XmlStyleFamily::TABLE_COLUMN: xMapper = xTableImport->GetColumnImportPropertySetMapper().get(); break; + case XmlStyleFamily::TABLE_ROW: xMapper = xTableImport->GetRowImportPropertySetMapper().get(); break; + case XmlStyleFamily::TABLE_CELL: xMapper = xTableImport->GetCellImportPropertySetMapper().get(); break; + default: break; + } + break; + } + default: break; + } + + // call base class + if( !xMapper.is() ) + xMapper = SvXMLStylesContext::GetImportPropertyMapper(nFamily); + return xMapper; +} + +// Process all style and object info + +void SdXMLStylesContext::endFastElement(sal_Int32 ) +{ + if(mbIsAutoStyle) + { + // AutoStyles for text import + GetImport().GetTextImport()->SetAutoStyles( this ); + + // AutoStyles for chart + GetImport().GetChartImport()->SetAutoStylesContext( this ); + + // AutoStyles for forms + GetImport().GetFormImport()->setAutoStyleContext( this ); + + // associate AutoStyles with styles in preparation to setting Styles on shapes + for(sal_uInt32 a(0); a < GetStyleCount(); a++) + { + const SvXMLStyleContext* pStyle = GetStyle(a); + if (const XMLShapeStyleContext* pDocStyle = dynamic_cast(pStyle)) + { + SvXMLStylesContext* pStylesContext = GetSdImport().GetShapeImport()->GetStylesContext(); + if (pStylesContext) + { + pStyle = pStylesContext->FindStyleChildContext(pStyle->GetFamily(), pStyle->GetParentName()); + + if (const XMLShapeStyleContext* pParentStyle = dynamic_cast(pStyle)) + { + if(pParentStyle->GetStyle().is()) + { + const_cast(pDocStyle)->SetStyle(pParentStyle->GetStyle()); + } + } + } + } + } + + FinishStyles( false ); + } + else + { + // Process styles list + ImpSetGraphicStyles(); + ImpSetCellStyles(); + GetImport().GetShapeImport()->GetShapeTableImport()->finishStyles(); + + // put style infos in the info set for other components ( content import f.e. ) + uno::Reference< beans::XPropertySet > xInfoSet( GetImport().getImportInfo() ); + if( xInfoSet.is() ) + { + uno::Reference< beans::XPropertySetInfo > xInfoSetInfo( xInfoSet->getPropertySetInfo() ); + + if( xInfoSetInfo->hasPropertyByName("PageLayouts") ) + xInfoSet->setPropertyValue("PageLayouts", uno::Any( getPageLayouts() ) ); + } + + } +} + +// set master-page styles (all with family="presentation" and a special +// prefix) on given master-page. + +void SdXMLStylesContext::SetMasterPageStyles(SdXMLMasterPageContext const & rMaster) const +{ + const uno::Reference& rStyleFamilies = + GetSdImport().GetLocalDocStyleFamilies(); + + if (!rStyleFamilies.is()) + return; + + if (!rStyleFamilies->hasByName(rMaster.GetDisplayName())) + return; + + try + { + uno::Reference< container::XNameAccess > xMasterPageStyles( rStyleFamilies->getByName(rMaster.GetDisplayName()), UNO_QUERY_THROW ); + OUString sPrefix(rMaster.GetDisplayName() + "-"); + ImpSetGraphicStyles(xMasterPageStyles, XmlStyleFamily::SD_PRESENTATION_ID, sPrefix); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +// Process styles list: +// set graphic styles (all with family="graphics"). Remember xStyle at list element. + +void SdXMLStylesContext::ImpSetGraphicStyles() const +{ + if(GetSdImport().GetLocalDocStyleFamilies().is()) try + { + uno::Reference< container::XNameAccess > xGraphicPageStyles( GetSdImport().GetLocalDocStyleFamilies()->getByName("graphics"), uno::UNO_QUERY_THROW ); + + ImpSetGraphicStyles(xGraphicPageStyles, XmlStyleFamily::SD_GRAPHICS_ID, OUString()); + } + catch( uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +void SdXMLStylesContext::ImpSetCellStyles() const +{ + if(GetSdImport().GetLocalDocStyleFamilies().is()) try + { + uno::Reference< container::XNameAccess > xGraphicPageStyles( GetSdImport().GetLocalDocStyleFamilies()->getByName("cell"), uno::UNO_QUERY_THROW ); + + ImpSetGraphicStyles(xGraphicPageStyles, XmlStyleFamily::TABLE_CELL, OUString()); + } + catch( uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.draw", ""); + } +} + +//Resolves: fdo#34987 if the style's auto height before and after is the same +//then don't reset it back to the underlying default of true for the small +//period before it's going to be reset to false again. Doing this avoids the +//master page shapes from resizing themselves due to autoheight becoming +//enabled before having autoheight turned off again and getting stuck on that +//autosized height +static bool canSkipReset(std::u16string_view rName, const XMLPropStyleContext* pPropStyle, + const uno::Reference< beans::XPropertySet > &rPropSet, const rtl::Reference < XMLPropertySetMapper >& rPrMap) +{ + bool bCanSkipReset = false; + if (pPropStyle && rName == u"TextAutoGrowHeight") + { + bool bOldStyleTextAutoGrowHeight(false); + rPropSet->getPropertyValue("TextAutoGrowHeight") >>= bOldStyleTextAutoGrowHeight; + + sal_Int32 nIndexStyle = rPrMap->GetEntryIndex(XML_NAMESPACE_DRAW, u"auto-grow-height", 0); + if (nIndexStyle != -1) + { + const ::std::vector< XMLPropertyState > &rProperties = pPropStyle->GetProperties(); + auto property = std::find_if(rProperties.cbegin(), rProperties.cend(), + [nIndexStyle](const XMLPropertyState& rProp) { return rProp.mnIndex == nIndexStyle; }); + if (property != rProperties.cend()) + { + bool bNewStyleTextAutoGrowHeight(false); + property->maValue >>= bNewStyleTextAutoGrowHeight; + bCanSkipReset = (bNewStyleTextAutoGrowHeight == bOldStyleTextAutoGrowHeight); + } + } + } + return bCanSkipReset; +} + +// help function used by ImpSetGraphicStyles() and ImpSetMasterPageStyles() + +void SdXMLStylesContext::ImpSetGraphicStyles( uno::Reference< container::XNameAccess > const & xPageStyles, XmlStyleFamily nFamily, const OUString& rPrefix) const +{ + sal_Int32 nPrefLen(rPrefix.getLength()); + + sal_uInt32 a; + + // set defaults + for( a = 0; a < GetStyleCount(); a++) + { + const SvXMLStyleContext* pStyle = GetStyle(a); + + if(nFamily == pStyle->GetFamily() && pStyle->IsDefaultStyle()) + { + const_cast(pStyle)->SetDefaults(); + } + } + + // create all styles and set properties + for( a = 0; a < GetStyleCount(); a++) + { + try + { + const SvXMLStyleContext* pStyle = GetStyle(a); + if(nFamily == pStyle->GetFamily() && !pStyle->IsDefaultStyle()) + { + OUString aStyleName(pStyle->GetDisplayName()); + + if( nPrefLen ) + { + sal_Int32 nStylePrefLen = aStyleName.lastIndexOf( '-' ) + 1; + if( (nPrefLen != nStylePrefLen) || !aStyleName.startsWith(rPrefix) ) + continue; + + aStyleName = aStyleName.copy( nPrefLen ); + } + + XMLPropStyleContext* pPropStyle = dynamic_cast< XMLPropStyleContext* >(const_cast< SvXMLStyleContext* >( pStyle ) ); + + uno::Reference< style::XStyle > xStyle; + if(xPageStyles->hasByName(aStyleName)) + { + xPageStyles->getByName(aStyleName) >>= xStyle; + + // set properties of existing styles to default + uno::Reference< beans::XPropertySet > xPropSet( xStyle, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySetInfo > xPropSetInfo; + if( xPropSet.is() ) + xPropSetInfo = xPropSet->getPropertySetInfo(); + + uno::Reference< beans::XPropertyState > xPropState( xStyle, uno::UNO_QUERY ); + + if( xPropState.is() ) + { + rtl::Reference < XMLPropertySetMapper > xPrMap; + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = GetImportPropertyMapper( nFamily ); + SAL_WARN_IF( !xImpPrMap.is(), "xmloff", "There is the import prop mapper" ); + if( xImpPrMap.is() ) + xPrMap = xImpPrMap->getPropertySetMapper(); + if( xPrMap.is() ) + { + const sal_Int32 nCount = xPrMap->GetEntryCount(); + for( sal_Int32 i = 0; i < nCount; i++ ) + { + const OUString& rName = xPrMap->GetEntryAPIName( i ); + if( xPropSetInfo->hasPropertyByName( rName ) && beans::PropertyState_DIRECT_VALUE == xPropState->getPropertyState( rName ) ) + { + bool bCanSkipReset = canSkipReset(rName, pPropStyle, xPropSet, xPrMap); + if (bCanSkipReset) + continue; + xPropState->setPropertyToDefault( rName ); + } + } + } + } + } + else + { + // graphics style does not exist, create and add it + uno::Reference< lang::XSingleServiceFactory > xServiceFact(xPageStyles, uno::UNO_QUERY); + if(xServiceFact.is()) + { + uno::Reference< style::XStyle > xNewStyle( xServiceFact->createInstance(), uno::UNO_QUERY); + + if(xNewStyle.is()) + { + // remember style + xStyle = xNewStyle; + + // add new style to graphics style pool + uno::Reference< container::XNameContainer > xInsertContainer(xPageStyles, uno::UNO_QUERY); + if(xInsertContainer.is()) + xInsertContainer->insertByName(aStyleName, uno::Any( xStyle ) ); + } + } + } + + if(xStyle.is()) + { + // set properties at style + uno::Reference< beans::XPropertySet > xPropSet(xStyle, uno::UNO_QUERY); + if(xPropSet.is() && pPropStyle) + { + pPropStyle->FillPropertySet(xPropSet); + pPropStyle->SetStyle(xStyle); + } + } + } + } + catch(const Exception& e) + { + const_cast(&GetSdImport())->SetError( XMLERROR_FLAG_WARNING | XMLERROR_API, {}, e.Message, nullptr ); + } + } + + // now set parents for all styles (when necessary) + for(a = 0; a < GetStyleCount(); a++) + { + const SvXMLStyleContext* pStyle = GetStyle(a); + + if(pStyle && !pStyle->GetDisplayName().isEmpty() && (nFamily == pStyle->GetFamily())) try + { + OUString aStyleName(pStyle->GetDisplayName()); + if( nPrefLen ) + { + sal_Int32 nStylePrefLen = aStyleName.lastIndexOf( '-' ) + 1; + if( (nPrefLen != nStylePrefLen) || !aStyleName.startsWith( rPrefix ) ) + continue; + + aStyleName = aStyleName.copy( nPrefLen ); + } + + uno::Reference< style::XStyle > xStyle( xPageStyles->getByName(aStyleName), UNO_QUERY ); + if(xStyle.is()) + { + // set parent style name + OUString sParentStyleDisplayName( GetImport().GetStyleDisplayName( pStyle->GetFamily(), pStyle->GetParentName() ) ); + if( nPrefLen ) + { + sal_Int32 nStylePrefLen = sParentStyleDisplayName.lastIndexOf( '-' ) + 1; + if( (nPrefLen != nStylePrefLen) || !sParentStyleDisplayName.startsWith( rPrefix ) ) + continue; + + sParentStyleDisplayName = sParentStyleDisplayName.copy( nPrefLen ); + } + xStyle->setParentStyle( sParentStyleDisplayName ); + } + } + catch( const Exception& e ) + { + const_cast(&GetSdImport())->SetError( XMLERROR_FLAG_WARNING | XMLERROR_API, {}, e.Message, nullptr ); + } + } +} + +// helper function to create the uno component that hold the mappings from +// xml auto layout name to internal autolayout id + +uno::Reference< container::XNameAccess > SdXMLStylesContext::getPageLayouts() const +{ + uno::Reference< container::XNameContainer > xLayouts( comphelper::NameContainer_createInstance( ::cppu::UnoType::get()) ); + + for(sal_uInt32 a(0); a < GetStyleCount(); a++) + { + const SvXMLStyleContext* pStyle = GetStyle(a); + if (const SdXMLPresentationPageLayoutContext* pContext = dynamic_cast(pStyle)) + { + xLayouts->insertByName(pStyle->GetName(), uno::Any(static_cast(pContext->GetTypeId()))); + } + } + + return xLayouts; +} + + +SdXMLMasterStylesContext::SdXMLMasterStylesContext( + SdXMLImport& rImport) +: SvXMLImportContext( rImport ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLMasterStylesContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_LAYER_SET) ) + { + return new SdXMLLayerSetContext( GetImport() ); + } + else if( nElement == XML_ELEMENT(STYLE, XML_MASTER_PAGE) ) + { + // style:masterpage inside office:styles context + uno::Reference< drawing::XDrawPage > xNewMasterPage; + uno::Reference< drawing::XDrawPages > xMasterPages(GetSdImport().GetLocalMasterPages(), uno::UNO_QUERY); + + if( xMasterPages.is() ) + { + sal_Int32 nNewMasterPageCount = GetSdImport().GetNewMasterPageCount(); + sal_Int32 nMasterPageCount = xMasterPages->getCount(); + if (nNewMasterPageCount + 1 > nMasterPageCount) + { + // arbitrary limit to master pages when fuzzing to avoid deadend timeouts + if (nMasterPageCount >= 64 && utl::ConfigManager::IsFuzzing()) + return nullptr; + + // new page, create and insert + xNewMasterPage = xMasterPages->insertNewByIndex(nMasterPageCount); + } + else + { + // existing page, use it + xMasterPages->getByIndex(nNewMasterPageCount) >>= xNewMasterPage; + } + + // increment global import page counter + GetSdImport().IncrementNewMasterPageCount(); + + if(xNewMasterPage.is()) + { + if(GetSdImport().GetShapeImport()->GetStylesContext()) + { + const rtl::Reference xLclContext{ + new SdXMLMasterPageContext(GetSdImport(), + nElement, xAttrList, xNewMasterPage)}; + maMasterPageList.push_back(xLclContext); + return xLclContext; + } + } + } + } + else if( nElement == XML_ELEMENT(STYLE, XML_HANDOUT_MASTER) ) + { + uno::Reference< presentation::XHandoutMasterSupplier > xHandoutSupp( GetSdImport().GetModel(), uno::UNO_QUERY ); + if( xHandoutSupp.is() ) + { + uno::Reference< drawing::XShapes > xHandoutPage = xHandoutSupp->getHandoutMasterPage(); + if(xHandoutPage.is() && GetSdImport().GetShapeImport()->GetStylesContext()) + { + return new SdXMLMasterPageContext(GetSdImport(), + nElement, xAttrList, xHandoutPage); + } + } + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +SdXMLHeaderFooterDeclContext::SdXMLHeaderFooterDeclContext(SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) + : SvXMLStyleContext( rImport ) + , mbFixed(false) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(PRESENTATION, XML_NAME) ) + { + maStrName = aIter.toString(); + } + else if( aIter.getToken() == XML_ELEMENT(PRESENTATION, XML_SOURCE) ) + { + mbFixed = IsXMLToken( aIter, XML_FIXED ); + } + else if( aIter.getToken() == XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME) ) + { + maStrDateTimeFormat = aIter.toString(); + } + else + { + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +bool SdXMLHeaderFooterDeclContext::IsTransient() const +{ + return true; +} + +void SdXMLHeaderFooterDeclContext::endFastElement(sal_Int32 nToken) +{ + SdXMLImport& rImport = dynamic_cast(GetImport()); + auto nElement = nToken & TOKEN_MASK; + if( nElement == XML_HEADER_DECL ) + { + rImport.AddHeaderDecl( maStrName, maStrText ); + } + else if( nElement == XML_FOOTER_DECL ) + { + rImport.AddFooterDecl( maStrName, maStrText ); + } + else if( nElement == XML_DATE_TIME_DECL ) + { + rImport.AddDateTimeDecl( maStrName, maStrText, mbFixed, maStrDateTimeFormat ); + } + else + { + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nToken); + } +} + +void SdXMLHeaderFooterDeclContext::characters( const OUString& rChars ) +{ + maStrText += rChars; +} + +XMLThemeContext::XMLThemeContext(SvXMLImport& rImport, + const uno::Reference& xAttrList, + const uno::Reference& xMasterPage) + : SvXMLImportContext(rImport) + , m_xMasterPage(xMasterPage) +{ + for (const auto& rAttribute : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (rAttribute.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_NAME): + { + m_aTheme["Name"] <<= rAttribute.toString(); + break; + } + } + } +} + +XMLThemeContext::~XMLThemeContext() +{ + uno::Any aTheme(m_aTheme.getAsConstPropertyValueList()); + m_xMasterPage->setPropertyValue("Theme", aTheme); +} + +uno::Reference SAL_CALL XMLThemeContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference& xAttribs) +{ + if (nElement == XML_ELEMENT(LO_EXT, XML_COLOR_TABLE)) + { + return new XMLColorTableContext(GetImport(), xAttribs, m_aTheme); + } + + return nullptr; +} + +XMLColorTableContext::XMLColorTableContext( + SvXMLImport& rImport, const uno::Reference& xAttrList, + comphelper::SequenceAsHashMap& rTheme) + : SvXMLImportContext(rImport) + , m_rTheme(rTheme) +{ + for (const auto& rAttribute : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (rAttribute.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_NAME): + { + m_rTheme["ColorSchemeName"] <<= rAttribute.toString(); + break; + } + } + } +} + +XMLColorTableContext::~XMLColorTableContext() +{ + m_rTheme["ColorScheme"] <<= comphelper::containerToSequence(m_aColorScheme); +} + +uno::Reference SAL_CALL XMLColorTableContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference& xAttribs) +{ + if (nElement == XML_ELEMENT(LO_EXT, XML_COLOR)) + { + return new XMLColorContext(GetImport(), xAttribs, m_aColorScheme); + } + + return nullptr; +} + +XMLColorContext::XMLColorContext(SvXMLImport& rImport, + const uno::Reference& xAttrList, + std::vector& rColorScheme) + : SvXMLImportContext(rImport) +{ + for (const auto& rAttribute : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (rAttribute.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_COLOR): + { + util::Color nColor; + sax::Converter::convertColor(nColor, rAttribute.toView()); + rColorScheme.push_back(nColor); + break; + } + } + } +} + +namespace xmloff { + +bool IsIgnoreFillStyleNamedItem( + css::uno::Reference const& xProps, + drawing::FillStyle const nExpectedFillStyle) +{ + assert(xProps.is()); + if (nExpectedFillStyle == drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE) + { + return false; + } + + // note: the caller must have called FillPropertySet() previously + drawing::FillStyle fillStyle{drawing::FillStyle_NONE}; + xProps->getPropertyValue("FillStyle") >>= fillStyle; + return fillStyle != nExpectedFillStyle; +} + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximpstyl.hxx b/xmloff/source/draw/ximpstyl.hxx new file mode 100644 index 000000000..00f032e4c --- /dev/null +++ b/xmloff/source/draw/ximpstyl.hxx @@ -0,0 +1,247 @@ +/* -*- 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 +#include +#include +#include +#include "sdxmlimp_impl.hxx" +#include "ximppage.hxx" +#include +#include +#include +#include + +class SvNumberFormatter; +class SvXMLNumFmtHelper; + +// special style:style context inside style:page-master context + +class SdXMLPageMasterStyleContext: public SvXMLStyleContext +{ + sal_Int32 mnBorderBottom; + sal_Int32 mnBorderLeft; + sal_Int32 mnBorderRight; + sal_Int32 mnBorderTop; + sal_Int32 mnWidth; + sal_Int32 mnHeight; + css::view::PaperOrientation meOrientation; + + const SdXMLImport& GetSdImport() const { return static_cast(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + +public: + + SdXMLPageMasterStyleContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + virtual ~SdXMLPageMasterStyleContext() override; + + sal_Int32 GetBorderBottom() const { return mnBorderBottom; } + sal_Int32 GetBorderLeft() const { return mnBorderLeft; } + sal_Int32 GetBorderRight() const { return mnBorderRight; } + sal_Int32 GetBorderTop() const { return mnBorderTop; } + sal_Int32 GetWidth() const { return mnWidth; } + sal_Int32 GetHeight() const { return mnHeight; } + css::view::PaperOrientation GetOrientation() const { return meOrientation; } +}; + +// style:page-master context + +class SdXMLPageMasterContext: public SvXMLStyleContext +{ + rtl::Reference mxPageMasterStyle; + + const SdXMLImport& GetSdImport() const { return static_cast(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + +public: + + SdXMLPageMasterContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + const SdXMLPageMasterStyleContext* GetPageMasterStyle() const { return mxPageMasterStyle.get(); } +}; + +// style:masterpage context + +class SdXMLMasterPageContext: public SdXMLGenericPageContext +{ + OUString msName; + OUString msDisplayName; + +public: + + SdXMLMasterPageContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes); + virtual ~SdXMLMasterPageContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + const OUString& GetDisplayName() const { return msDisplayName; } + +}; + +// presentation:placeholder context + +class SdXMLPresentationPlaceholderContext: public SvXMLImportContext +{ + OUString msName; + sal_Int32 mnX; + + const SdXMLImport& GetSdImport() const { return static_cast(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + +public: + SdXMLPresentationPlaceholderContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + virtual ~SdXMLPresentationPlaceholderContext() override; + + const OUString& GetName() const { return msName; } + sal_Int32 GetX() const { return mnX; } +}; + +// style:presentation-page-layout context + +class SdXMLPresentationPageLayoutContext: public SvXMLStyleContext +{ + std::vector< rtl::Reference< SdXMLPresentationPlaceholderContext > > + maList; + sal_uInt16 mnTypeId; + + const SdXMLImport& GetSdImport() const { return static_cast(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + +public: + + SdXMLPresentationPageLayoutContext( + SdXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + sal_uInt16 GetTypeId() const { return mnTypeId; } +}; + +// office:styles context + +class SdXMLStylesContext : public SvXMLStylesContext +{ + rtl::Reference< SvXMLImportPropertyMapper > xPresImpPropMapper; + bool mbIsAutoStyle; + std::unique_ptr mpNumFmtHelper; + std::unique_ptr mpNumFormatter; + + const SdXMLImport& GetSdImport() const { return static_cast(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + + void ImpSetGraphicStyles() const; + void ImpSetCellStyles() const; + void ImpSetGraphicStyles( css::uno::Reference< css::container::XNameAccess > const & xPageStyles, + XmlStyleFamily nFamily, const OUString& rPrefix) const; + +protected: + using SvXMLStylesContext::CreateStyleChildContext; + virtual SvXMLStyleContext* CreateStyleChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) override; + + using SvXMLStylesContext::CreateStyleStyleChildContext; + virtual SvXMLStyleContext *CreateStyleStyleChildContext( + XmlStyleFamily nFamily, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) override; + + using SvXMLStylesContext::CreateDefaultStyleStyleChildContext; + virtual SvXMLStyleContext *CreateDefaultStyleStyleChildContext( + XmlStyleFamily nFamily, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) override; +public: + + SdXMLStylesContext( + SdXMLImport& rImport, + bool bIsAutoStyle); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual rtl::Reference< SvXMLImportPropertyMapper > GetImportPropertyMapper(XmlStyleFamily nFamily) const override; + + void SetMasterPageStyles(SdXMLMasterPageContext const & rMaster) const; + + css::uno::Reference< css::container::XNameAccess > getPageLayouts() const; +}; + +// office:master-styles context + +class SdXMLMasterStylesContext : public SvXMLImportContext +{ + std::vector< rtl::Reference< SdXMLMasterPageContext > > maMasterPageList; + + const SdXMLImport& GetSdImport() const { return static_cast(GetImport()); } + SdXMLImport& GetSdImport() { return static_cast(GetImport()); } + +public: + + SdXMLMasterStylesContext(SdXMLImport& rImport); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +// , and + +class SdXMLHeaderFooterDeclContext : public SvXMLStyleContext +{ +public: + SdXMLHeaderFooterDeclContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + + virtual bool IsTransient() const override; + virtual void SAL_CALL endFastElement(sal_Int32 ) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; + +private: + OUString maStrName; + OUString maStrText; + OUString maStrDateTimeFormat; + bool mbFixed; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/callbacks.hxx b/xmloff/source/forms/callbacks.hxx new file mode 100644 index 000000000..0134152b8 --- /dev/null +++ b/xmloff/source/forms/callbacks.hxx @@ -0,0 +1,79 @@ +/* -*- 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 +#include +#include +#include + +class SvXMLExport; +class SvXMLExportPropertyMapper; + +namespace xmloff +{ + + //= IFormsExportContext + class IFormsExportContext + { + public: + virtual SvXMLExport& getGlobalContext() = 0; + virtual ::rtl::Reference< SvXMLExportPropertyMapper > getStylePropertyMapper() = 0; + + /** steps through a collection and exports all children of this collection + */ + virtual void exportCollectionElements( + const css::uno::Reference< css::container::XIndexAccess >& _rxCollection) = 0; + + virtual OUString getObjectStyleName( + const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) = 0; + + protected: + ~IFormsExportContext() {} + }; + + //= IEventAttacherManager + class IEventAttacherManager + { + public: + virtual void registerEvents( + const css::uno::Reference< css::beans::XPropertySet >& _rxElement, + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents + ) = 0; + + protected: + ~IEventAttacherManager() {} + }; + + //= IEventAttacher + class IEventAttacher + { + public: + virtual void registerEvents( + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents + ) = 0; + + protected: + ~IEventAttacher() {} + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/controlelement.cxx b/xmloff/source/forms/controlelement.cxx new file mode 100644 index 000000000..af752ae4b --- /dev/null +++ b/xmloff/source/forms/controlelement.cxx @@ -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/. + * + * 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 "controlelement.hxx" +#include + +using namespace ::xmloff::token; + +namespace xmloff +{ + + //= OControlElement + const char* OControlElement::getElementName(ElementType _eType) + { + switch (_eType) + { + case TEXT: return "text"; + case TEXT_AREA: return "textarea"; + case PASSWORD: return "password"; + case FILE: return "file"; + case FORMATTED_TEXT: return "formatted-text"; + case FIXED_TEXT: return "fixed-text"; + case COMBOBOX: return "combobox"; + case LISTBOX: return "listbox"; + case BUTTON: return "button"; + case IMAGE: return "image"; + case CHECKBOX: return "checkbox"; + case RADIO: return "radio"; + case FRAME: return "frame"; + case IMAGE_FRAME: return "image-frame"; + case HIDDEN: return "hidden"; + case GRID: return "grid"; + case VALUERANGE: return "value-range"; + case TIME: return "time"; + case DATE: return "date"; + + default: return "generic-control"; + } + } + + sal_Int32 OControlElement::getElementToken(ElementType _eType) + { + switch (_eType) + { + case TEXT: return XML_TEXT; + case TEXT_AREA: return XML_TEXTAREA; + case PASSWORD: return XML_PASSWORD; + case FILE: return XML_FILE; + case FORMATTED_TEXT: return XML_FORMATTED_TEXT; + case FIXED_TEXT: return XML_FIXED_TEXT; + case COMBOBOX: return XML_COMBOBOX; + case LISTBOX: return XML_LISTBOX; + case BUTTON: return XML_BUTTON; + case IMAGE: return XML_IMAGE; + case CHECKBOX: return XML_CHECKBOX; + case RADIO: return XML_RADIO; + case FRAME: return XML_FRAME; + case IMAGE_FRAME: return XML_IMAGE_FRAME; + case HIDDEN: return XML_HIDDEN; + case GRID: return XML_GRID; + case VALUERANGE: return XML_VALUE_RANGE; + case TIME: return XML_TIME; + case DATE: return XML_DATE; + + default: return XML_GENERIC_CONTROL; + } + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/controlelement.hxx b/xmloff/source/forms/controlelement.hxx new file mode 100644 index 000000000..df7f12a43 --- /dev/null +++ b/xmloff/source/forms/controlelement.hxx @@ -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/. + * + * 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 + +namespace xmloff +{ + + //= OControlElement + /** helper for translating between control types and XML tags + */ + class OControlElement + { + public: + enum ElementType + { + TEXT = 0, + TEXT_AREA, + PASSWORD, + FILE, + FORMATTED_TEXT, + FIXED_TEXT, + COMBOBOX, + LISTBOX, + BUTTON, + IMAGE, + CHECKBOX, + RADIO, + FRAME, + IMAGE_FRAME, + HIDDEN, + GRID, + VALUERANGE, + GENERIC_CONTROL, + TIME, + DATE, + + UNKNOWN // must be the last element + }; + + protected: + /** ctor. +

This default constructor is protected, 'cause this class is not intended to be instantiated + directly. Instead, the derived classes should be used.

+ */ + OControlElement() { } + + public: + /** retrieves the tag name to be used to describe a control of the given type + +

The returned string is the pure element name, without any namespace.

+ + @param _eType + the element type + */ + static const char* getElementName(ElementType _eType); + + /** retrieves the tag name to be used to describe a control of the given type + +

The returned string is the pure token, without any namespace.

+ + @param _eType + the element type + */ + static sal_Int32 getElementToken(ElementType _eType); + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/controlpropertyhdl.cxx b/xmloff/source/forms/controlpropertyhdl.cxx new file mode 100644 index 000000000..cb3badee2 --- /dev/null +++ b/xmloff/source/forms/controlpropertyhdl.cxx @@ -0,0 +1,343 @@ +/* -*- 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 + +#include +#include +#include + +#include + +#include +#include +#include "formenums.hxx" +#include +#include +#include +#include + +namespace xmloff +{ + + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::beans; + using namespace ::xmloff::token; + + //= OControlPropertyHandlerFactory + OControlPropertyHandlerFactory::OControlPropertyHandlerFactory() + { + } + + const XMLPropertyHandler* OControlPropertyHandlerFactory::GetPropertyHandler(sal_Int32 _nType) const + { + const XMLPropertyHandler* pHandler = nullptr; + + switch (_nType) + { + case XML_TYPE_TEXT_ALIGN: + if (!m_pTextAlignHandler) + m_pTextAlignHandler = std::make_unique(aTextAlignMap, XML_TOKEN_INVALID ); + pHandler = m_pTextAlignHandler.get(); + break; + + case XML_TYPE_CONTROL_BORDER: + if (!m_pControlBorderStyleHandler) + m_pControlBorderStyleHandler = std::make_unique( OControlBorderHandler::STYLE ); + pHandler = m_pControlBorderStyleHandler.get(); + break; + + case XML_TYPE_CONTROL_BORDER_COLOR: + if ( !m_pControlBorderColorHandler ) + m_pControlBorderColorHandler = std::make_unique( OControlBorderHandler::COLOR ); + pHandler = m_pControlBorderColorHandler.get(); + break; + + case XML_TYPE_ROTATION_ANGLE: + if (!m_pRotationAngleHandler) + m_pRotationAngleHandler = std::make_unique(); + pHandler = m_pRotationAngleHandler.get(); + break; + + case XML_TYPE_FONT_WIDTH: + if (!m_pFontWidthHandler) + m_pFontWidthHandler = std::make_unique(); + pHandler = m_pFontWidthHandler.get(); + break; + + case XML_TYPE_CONTROL_TEXT_EMPHASIZE: + if (!m_pFontEmphasisHandler) + m_pFontEmphasisHandler = std::make_unique( aFontEmphasisMap, XML_NONE ); + pHandler = m_pFontEmphasisHandler.get(); + break; + + case XML_TYPE_TEXT_FONT_RELIEF: + if (!m_pFontReliefHandler) + m_pFontReliefHandler = std::make_unique( aFontReliefMap, XML_NONE ); + pHandler = m_pFontReliefHandler.get(); + break; + case XML_TYPE_TEXT_LINE_MODE: + if (!m_pTextLineModeHandler) + { + m_pTextLineModeHandler = std::make_unique( + ::xmloff::token::XML_SKIP_WHITE_SPACE, + ::xmloff::token::XML_CONTINUOUS); + } + pHandler = m_pTextLineModeHandler.get(); + break; + } + + if (!pHandler) + pHandler = XMLPropertyHandlerFactory::GetPropertyHandler(_nType); + return pHandler; + } + + //= OControlTextEmphasisHandler + OControlTextEmphasisHandler::OControlTextEmphasisHandler() + { + } + + bool OControlTextEmphasisHandler::exportXML( OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const + { + bool bSuccess = false; + sal_Int16 nFontEmphasis = sal_Int16(); + if (_rValue >>= nFontEmphasis) + { + // the type + sal_uInt16 nType = nFontEmphasis & ~(awt::FontEmphasisMark::ABOVE | awt::FontEmphasisMark::BELOW); + // the position of the mark + bool bBelow = 0 != (nFontEmphasis & awt::FontEmphasisMark::BELOW); + + // convert + OUStringBuffer aReturn; + bSuccess = SvXMLUnitConverter::convertEnum(aReturn, nType, aFontEmphasisMap, XML_NONE); + if (bSuccess) + { + aReturn.append( ' ' ); + aReturn.append( GetXMLToken(bBelow ? XML_BELOW : XML_ABOVE) ); + + _rStrExpValue = aReturn.makeStringAndClear(); + } + } + + return bSuccess; + } + + bool OControlTextEmphasisHandler::importXML( const OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const + { + bool bSuccess = true; + sal_uInt16 nEmphasis = awt::FontEmphasisMark::NONE; + + bool bBelow = false; + bool bHasPos = false, bHasType = false; + + std::u16string_view sToken; + SvXMLTokenEnumerator aTokenEnum(_rStrImpValue); + while (aTokenEnum.getNextToken(sToken)) + { + if (!bHasPos) + { + if (IsXMLToken(sToken, XML_ABOVE)) + { + bBelow = false; + bHasPos = true; + } + else if (IsXMLToken(sToken, XML_BELOW)) + { + bBelow = true; + bHasPos = true; + } + } + if (!bHasType) + { + if (SvXMLUnitConverter::convertEnum(nEmphasis, sToken, aFontEmphasisMap)) + { + bHasType = true; + } + else + { + bSuccess = false; + break; + } + } + } + + if (bSuccess) + { + nEmphasis |= bBelow ? awt::FontEmphasisMark::BELOW : awt::FontEmphasisMark::ABOVE; + _rValue <<= nEmphasis; + } + + return bSuccess; + } + + //= OControlBorderHandlerBase + OControlBorderHandler::OControlBorderHandler( const OControlBorderHandler::BorderFacet _eFacet ) + :m_eFacet( _eFacet ) + { + } + + bool OControlBorderHandler::importXML( const OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const + { + std::u16string_view sToken; + SvXMLTokenEnumerator aTokens(_rStrImpValue); + + sal_uInt16 nStyle = 1; + + while ( aTokens.getNextToken(sToken) // have a new token + && (!sToken.empty()) // really have a new token + ) + { + // try interpreting the token as border style + if ( m_eFacet == STYLE ) + { + // is it a valid enum value? + if ( SvXMLUnitConverter::convertEnum( nStyle, sToken, aBorderTypeMap ) ) + { + _rValue <<= nStyle; + return true; + } + } + + // try interpreting it as color value + if ( m_eFacet == COLOR ) + { + sal_Int32 nColor(0); + if (::sax::Converter::convertColor( nColor, sToken )) + { + _rValue <<= nColor; + return true; + } + } + } + + return false; + } + + bool OControlBorderHandler::exportXML( OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const + { + bool bSuccess = false; + + OUStringBuffer aOut; + switch ( m_eFacet ) + { + case STYLE: + { + sal_uInt16 nBorder = 0; + bSuccess = (_rValue >>= nBorder) + && SvXMLUnitConverter::convertEnum( aOut, nBorder, aBorderTypeMap ); + } + break; + case COLOR: + { + sal_Int32 nBorderColor = 0; + if ( _rValue >>= nBorderColor ) + { + ::sax::Converter::convertColor(aOut, nBorderColor); + bSuccess = true; + } + } + break; + } // switch ( m_eFacet ) + + if ( !bSuccess ) + return false; + + if ( !_rStrExpValue.isEmpty() ) + _rStrExpValue += " "; + _rStrExpValue += aOut; + + return true; + } + + //= OFontWidthHandler + OFontWidthHandler::OFontWidthHandler() + { + } + + bool OFontWidthHandler::importXML( const OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const + { + sal_Int32 nWidth = 0; + bool const bSuccess = ::sax::Converter::convertMeasure( + nWidth, _rStrImpValue, util::MeasureUnit::POINT); + if (bSuccess) + _rValue <<= static_cast(nWidth); + + return bSuccess; + } + + bool OFontWidthHandler::exportXML( OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const + { + sal_Int16 nWidth = 0; + OUStringBuffer aResult; + if (_rValue >>= nWidth) + { + ::sax::Converter::convertMeasure(aResult, nWidth, + util::MeasureUnit::POINT, util::MeasureUnit::POINT); + } + _rStrExpValue = aResult.makeStringAndClear(); + + return !_rStrExpValue.isEmpty(); + } + + //= ORotationAngleHandler + ORotationAngleHandler::ORotationAngleHandler() + { + } + + bool ORotationAngleHandler::importXML( const OUString& _rStrImpValue, Any& _rValue, const SvXMLUnitConverter& ) const + { + double fValue; + bool const bSucces = + ::sax::Converter::convertDouble(fValue, _rStrImpValue); + if (bSucces) + { + fValue *= 10; + _rValue <<= static_cast(fValue); + } + + return bSucces; + } + + bool ORotationAngleHandler::exportXML( OUString& _rStrExpValue, const Any& _rValue, const SvXMLUnitConverter& ) const + { + float fAngle = 0; + bool bSuccess = (_rValue >>= fAngle); + + if (bSuccess) + { + OUStringBuffer sValue; + ::sax::Converter::convertDouble(sValue, static_cast(fAngle) / 10); + _rStrExpValue = sValue.makeStringAndClear(); + } + + return bSuccess; + } + + //= ImageScaleModeHandler + ImageScaleModeHandler::ImageScaleModeHandler() + :XMLConstantsPropertyHandler( aScaleModeMap, XML_STRETCH ) + { + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/controlpropertymap.cxx b/xmloff/source/forms/controlpropertymap.cxx new file mode 100644 index 000000000..d0716bd8d --- /dev/null +++ b/xmloff/source/forms/controlpropertymap.cxx @@ -0,0 +1,119 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include "strings.hxx" +#include +#include "controlpropertymap.hxx" + +#include + +using namespace ::xmloff::token; + +namespace xmloff +{ + +#define MAP_ASCII( name, prefix, token, type, context ) { name, prefix, token, type|XML_TYPE_PROP_TEXT, context, SvtSaveOptions::ODFSVER_010, false } +#define MAP_CONST( name, prefix, token, type, context ) { name, prefix, token, type|XML_TYPE_PROP_TEXT, context, SvtSaveOptions::ODFSVER_010, false } +#define MAP_CONST_P( name, prefix, token, type, context ){ name, prefix, token, type|XML_TYPE_PROP_PARAGRAPH, context, SvtSaveOptions::ODFSVER_010, false } +#define MAP_END() { nullptr, 0, XML_TOKEN_INVALID, 0, 0, SvtSaveOptions::ODFSVER_010, false } + + XMLPropertyMapEntry const aControlStyleProperties[] = + { + MAP_CONST_P( PROPERTY_ALIGN, XML_NAMESPACE_FO, XML_TEXT_ALIGN, XML_TYPE_TEXT_ALIGN, 0 ), + MAP_CONST( PROPERTY_BACKGROUNDCOLOR, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLOR, 0 ), + MAP_CONST( PROPERTY_BORDER, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_CONTROL_BORDER|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + MAP_ASCII( "BorderColor", XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_CONTROL_BORDER_COLOR|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + MAP_ASCII( "FontCharWidth", XML_NAMESPACE_STYLE, XML_FONT_CHAR_WIDTH, XML_TYPE_NUMBER16, 0 ), + MAP_ASCII( "FontCharset", XML_NAMESPACE_STYLE, XML_FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING, 0 ), + MAP_ASCII( "FontEmphasisMark", XML_NAMESPACE_STYLE, XML_TEXT_EMPHASIZE, XML_TYPE_CONTROL_TEXT_EMPHASIZE, 0 ), + MAP_ASCII( "FontFamily", XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC, XML_TYPE_TEXT_FONTFAMILY, 0 ), + MAP_ASCII( "FontHeight", XML_NAMESPACE_FO, XML_FONT_SIZE, XML_TYPE_CHAR_HEIGHT, 0 ), + MAP_ASCII( "FontKerning", XML_NAMESPACE_STYLE, XML_LETTER_KERNING, XML_TYPE_BOOL, 0 ), + MAP_ASCII( "FontName", XML_NAMESPACE_STYLE, XML_FONT_NAME, XML_TYPE_STRING, 0 ), + MAP_ASCII( "FontOrientation", XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_TYPE_ROTATION_ANGLE, 0 ), + MAP_ASCII( "FontPitch", XML_NAMESPACE_STYLE, XML_FONT_PITCH, XML_TYPE_TEXT_FONTPITCH, 0 ), + MAP_ASCII( "FontRelief", XML_NAMESPACE_STYLE, XML_FONT_RELIEF, XML_TYPE_TEXT_FONT_RELIEF|MID_FLAG_MULTI_PROPERTY, 0 ), + MAP_ASCII( "FontSlant", XML_NAMESPACE_FO, XML_FONT_STYLE, XML_TYPE_TEXT_POSTURE, 0 ), + + MAP_ASCII( "FontStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_STYLE, XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY, 0), + MAP_ASCII( "FontStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TYPE, XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY, 0), + MAP_ASCII( "FontStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_WIDTH, XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY, 0), + MAP_ASCII( "FontStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TEXT, XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY, 0), + + MAP_ASCII( "FontStyleName", XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME, XML_TYPE_STRING, 0 ), + MAP_ASCII( "FontUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_STYLE, XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_ASCII( "FontUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_TYPE, XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_ASCII( "FontUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_WIDTH, XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_ASCII( "FontWeight", XML_NAMESPACE_FO, XML_FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + MAP_ASCII( "FontWidth", XML_NAMESPACE_STYLE, XML_FONT_WIDTH, XML_TYPE_FONT_WIDTH, 0 ), + MAP_ASCII( "FontWordLineMode", XML_NAMESPACE_FO, XML_SCORE_SPACES, XML_TYPE_NBOOL, 0 ), + + MAP_CONST( PROPERTY_FORMATKEY, XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, XML_TYPE_STRING | MID_FLAG_NO_PROPERTY_EXPORT | MID_FLAG_SPECIAL_ITEM, CTF_FORMS_DATA_STYLE ), + + MAP_ASCII( "SymbolColor", XML_NAMESPACE_STYLE, XML_COLOR, XML_TYPE_COLOR, 0 ), + MAP_ASCII( "TextColor", XML_NAMESPACE_FO, XML_COLOR, XML_TYPE_COLOR, 0 ), + MAP_ASCII( "TextLineColor", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + MAP_END() + }; + + const XMLPropertyMapEntry* getControlStylePropertyMap( ) + { + return aControlStyleProperties; + } + + void initializePropertyMaps() + { + static bool bSorted = false; + if (!bSorted) + { + XMLPropertyMapEntry const * pEnd; + // determine the last element + for ( pEnd = aControlStyleProperties; pEnd->msApiName; ++pEnd) + ; + assert( ::std::is_sorted(aControlStyleProperties, pEnd, + [](const XMLPropertyMapEntry& _rLeft, const XMLPropertyMapEntry& _rRight) + { return strcmp(_rLeft.msApiName, _rRight.msApiName) < 0; }) ); + bSorted = true; + } + } + + //= OFormComponentStyleExportMapper + OFormComponentStyleExportMapper::OFormComponentStyleExportMapper( const rtl::Reference< XMLPropertySetMapper >& _rMapper ) + :SvXMLExportPropertyMapper( _rMapper ) + { + } + + void OFormComponentStyleExportMapper::handleSpecialItem( SvXMLAttributeList& _rAttrList, const XMLPropertyState& _rProperty, const SvXMLUnitConverter& _rUnitConverter, + const SvXMLNamespaceMap& _rNamespaceMap, const ::std::vector< XMLPropertyState >* _pProperties, + sal_uInt32 _nIdx ) const + { + // ignore the number style of grid columns - this is formatted elsewhere + if ( CTF_FORMS_DATA_STYLE != getPropertySetMapper()->GetEntryContextId( _rProperty.mnIndex ) ) + SvXMLExportPropertyMapper::handleSpecialItem( _rAttrList, _rProperty, _rUnitConverter, _rNamespaceMap, _pProperties, _nIdx ); + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/controlpropertymap.hxx b/xmloff/source/forms/controlpropertymap.hxx new file mode 100644 index 000000000..ff575c137 --- /dev/null +++ b/xmloff/source/forms/controlpropertymap.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 +#include + +struct XMLPropertyMapEntry; +namespace xmloff +{ + + const XMLPropertyMapEntry* getControlStylePropertyMap( ); + + void initializePropertyMaps(); + + //= OFormComponentStyleExportMapper + class OFormComponentStyleExportMapper : public SvXMLExportPropertyMapper + { + public: + explicit OFormComponentStyleExportMapper( const rtl::Reference< XMLPropertySetMapper >& _rMapper ); + + void handleSpecialItem( + SvXMLAttributeList& _rAttrList, + const XMLPropertyState& _rProperty, + const SvXMLUnitConverter& _rUnitConverter, + const SvXMLNamespaceMap& _rNamespaceMap, + const ::std::vector< XMLPropertyState >* _pProperties, + sal_uInt32 _nIdx + ) const override; + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/elementexport.cxx b/xmloff/source/forms/elementexport.cxx new file mode 100644 index 000000000..72cb6e0ef --- /dev/null +++ b/xmloff/source/forms/elementexport.cxx @@ -0,0 +1,2185 @@ +/* -*- 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 "elementexport.hxx" + +#include "strings.hxx" +#include +#include "eventexport.hxx" +#include "formenums.hxx" +#include "formcellbinding.hxx" +#include +#include "property_meta_data.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace xmloff +{ + + #if OSL_DEBUG_LEVEL > 0 + #define RESET_BIT( bitfield, bit ) \ + bitfield = bitfield & ~bit + #else + #define RESET_BIT( bitfield, bit ) + #endif + + using namespace ::xmloff::token; + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::io; + using namespace ::com::sun::star::table; + using namespace ::com::sun::star::text; + using namespace ::com::sun::star::form::binding; + + //= OElementExport + OElementExport::OElementExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxProps, + const Sequence< ScriptEventDescriptor >& _rEvents) + :OPropertyExport(_rContext, _rxProps) + ,m_aEvents(_rEvents) + { + } + + OElementExport::~OElementExport() + { + } + + void OElementExport::doExport() + { + // collect some general information about the element + examine(); + + // first add the attributes necessary for the element + m_rContext.getGlobalContext().ClearAttrList(); + + // add the attributes + exportAttributes(); + + // start the XML element + implStartElement(getXMLElementName()); + + // the sub elements (mostly control type dependent) + exportSubTags(); + + implEndElement(); + } + + void OElementExport::examine() + { + // nothing to do here + } + + void OElementExport::exportAttributes() + { + // nothing to do here + } + + void OElementExport::exportSubTags() + { + // the properties which where not exported 'til now + exportRemainingProperties(); + + // the script:events sub tags + exportEvents(); + } + + void OElementExport::implStartElement(const char* _pName) + { + m_pXMLElement = std::make_unique(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, _pName, true, true); + } + + void OElementExport::implEndElement() + { + m_pXMLElement.reset(); + } + + void OElementExport::exportServiceNameAttribute() + { + Reference< XPersistObject > xPersistence(m_xProps, UNO_QUERY); + if (!xPersistence.is()) + { + OSL_FAIL("OElementExport::exportServiceNameAttribute: no XPersistObject!"); + return; + } + + OUString sServiceName = xPersistence->getServiceName(); + // we don't want to write the old service name directly: it's a name used for compatibility reasons, but + // as we start some kind of new file format here (with this xml export), we don't care about + // compatibility ... + // So we translate the old persistence service name into new ones, if possible + + OUString sToWriteServiceName = sServiceName; +#define CHECK_N_TRANSLATE( name ) \ + else if (sServiceName == SERVICE_PERSISTENT_COMPONENT_##name) \ + sToWriteServiceName = SERVICE_##name + + if (sServiceName == SERVICE_PERSISTENT_COMPONENT_EDIT) + { + // special handling for the edit field: we have two controls using this as persistence service name + sToWriteServiceName = SERVICE_EDIT; + Reference< XServiceInfo > xSI(m_xProps, UNO_QUERY); + if (xSI.is() && xSI->supportsService(SERVICE_FORMATTEDFIELD)) + sToWriteServiceName = SERVICE_FORMATTEDFIELD; + } + CHECK_N_TRANSLATE( FORM ); + CHECK_N_TRANSLATE( LISTBOX ); + CHECK_N_TRANSLATE( COMBOBOX ); + CHECK_N_TRANSLATE( RADIOBUTTON ); + CHECK_N_TRANSLATE( GROUPBOX ); + CHECK_N_TRANSLATE( FIXEDTEXT ); + CHECK_N_TRANSLATE( COMMANDBUTTON ); + CHECK_N_TRANSLATE( CHECKBOX ); + CHECK_N_TRANSLATE( GRID ); + CHECK_N_TRANSLATE( IMAGEBUTTON ); + CHECK_N_TRANSLATE( FILECONTROL ); + CHECK_N_TRANSLATE( TIMEFIELD ); + CHECK_N_TRANSLATE( DATEFIELD ); + CHECK_N_TRANSLATE( NUMERICFIELD ); + CHECK_N_TRANSLATE( CURRENCYFIELD ); + CHECK_N_TRANSLATE( PATTERNFIELD ); + CHECK_N_TRANSLATE( HIDDENCONTROL ); + CHECK_N_TRANSLATE( IMAGECONTROL ); + CHECK_N_TRANSLATE( FORMATTEDFIELD ); +#if OSL_DEBUG_LEVEL > 0 + Reference< XServiceInfo > xSI(m_xProps, UNO_QUERY); + OSL_ENSURE(xSI.is() && xSI->supportsService(sToWriteServiceName), + "OElementExport::exportServiceNameAttribute: wrong service name translation!"); + +#endif + sToWriteServiceName = + m_rContext.getGlobalContext().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, sToWriteServiceName ); + + // now write this + AddAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::ServiceName), + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::ServiceName), + sToWriteServiceName); + } + + void OElementExport::exportEvents() + { + if (!m_aEvents.hasElements()) + // nothing to do + return; + + Reference< XNameReplace > xWrapper = new OEventDescriptorMapper(m_aEvents); + m_rContext.getGlobalContext().GetEventExport().Export(xWrapper); + } + + //= OControlExport + OControlExport::OControlExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxControl, + const OUString& _rControlId, const OUString& _rReferringControls, + const Sequence< ScriptEventDescriptor >& _rEvents) + :OElementExport(_rContext, _rxControl, _rEvents) + ,m_sControlId(_rControlId) + ,m_sReferringControls(_rReferringControls) + ,m_nClassId(FormComponentType::CONTROL) + ,m_eType( UNKNOWN ) + ,m_nIncludeCommon(CCAFlags::NONE) + ,m_nIncludeDatabase(DAFlags::NONE) + ,m_nIncludeSpecial(SCAFlags::NONE) + ,m_nIncludeEvents(EAFlags::NONE) + ,m_nIncludeBindings(BAFlags::NONE) + { + OSL_ENSURE(m_xProps.is(), "OControlExport::OControlExport: invalid arguments!"); + } + + void OControlExport::exportOuterAttributes() + { + // the control id + if (CCAFlags::Name & m_nIncludeCommon) + { + exportStringPropertyAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Name), + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Name), + PROPERTY_NAME + ); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::Name; + #endif + } + + // the service name + if (m_nIncludeCommon & CCAFlags::ServiceName) + { + exportServiceNameAttribute(); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::ServiceName; + #endif + } + } + + void OControlExport::exportInnerAttributes() + { + // the control id + if (CCAFlags::ControlId & m_nIncludeCommon) + { + OSL_ENSURE(!m_sControlId.isEmpty(), "OControlExport::exportInnerAttributes: have no control id for the control!"); + m_rContext.getGlobalContext().AddAttributeIdLegacy( + XML_NAMESPACE_FORM, m_sControlId); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::ControlId; + #endif + } + + // "new-style" properties ... + exportGenericHandlerAttributes(); + + // common control attributes + exportCommonControlAttributes(); + + // common database attributes + exportDatabaseAttributes(); + + // attributes related to external bindings + exportBindingAttributes(); + + // attributes special to the respective control type + exportSpecialAttributes(); + + // add the style references to the attributes + flagStyleProperties(); + } + + void OControlExport::exportAttributes() + { + exportOuterAttributes(); + } + + void OControlExport::exportSubTags() + { + // for the upcoming exportRemainingProperties: + // if a control has the LabelControl property, this is not stored with the control itself, but instead with + // the control which is referenced by this property. As the base class' exportRemainingProperties doesn't + // know anything about this, we need to prevent that it tries to export this property + exportedProperty(PROPERTY_CONTROLLABEL); + + // if it's a control supporting XText, then we need to declare all text-related properties + // as "already exported". This prevents them from being exported as generic "form:property"-tags. + // *If* we would export them this way, they would be completely superfluous, and sometimes even + // disastrous, since they may, at import time, override paragraph properties which already have + // been set before + Reference< XText > xControlText( m_xProps, UNO_QUERY ); + if ( xControlText.is() ) + { + const XMLPropertyMapEntry* pCharAttributeProperties = XMLTextPropertySetMapper::getPropertyMapForType( TextPropMap::TEXT ); + while ( pCharAttributeProperties->msApiName ) + { + exportedProperty( OUString::createFromAscii( pCharAttributeProperties->msApiName ) ); + ++pCharAttributeProperties; + } + + const XMLPropertyMapEntry* pParaAttributeProperties = XMLTextPropertySetMapper::getPropertyMapForType( TextPropMap::SHAPE_PARA ); + while ( pParaAttributeProperties->msApiName ) + { + exportedProperty( OUString::createFromAscii( pParaAttributeProperties->msApiName ) ); + ++pParaAttributeProperties; + } + + // the RichText property is not exported. The presence of the text:p element + // will be used - upon reading - as indicator for the value of the RichText property + exportedProperty( PROPERTY_RICH_TEXT ); + + // strange thing: paragraphs support both a CharStrikeout and a CharCrossedOut property + // The former is a short/enum value, the latter a boolean. The former has a real meaning + // (the strikeout type), the latter hasn't. But, when the CharCrossedOut is exported and + // later on imported, it overwrites anything which has previously been imported for + // CharStrikeout. + // #i27729# + exportedProperty( "CharCrossedOut" ); + } + + if ( m_eType == LISTBOX ) + { + // will be exported in exportListSourceAsElements: + if ( controlHasUserSuppliedListEntries() ) + exportedProperty( PROPERTY_DEFAULT_SELECT_SEQ ); + + // will not be exported in a generic way. Either exportListSourceAsElements cares + // for them, or we don't need them + exportedProperty( PROPERTY_STRING_ITEM_LIST ); + exportedProperty( PROPERTY_VALUE_SEQ ); + exportedProperty( PROPERTY_SELECT_SEQ ); + exportedProperty( PROPERTY_LISTSOURCE ); + } + if ( m_eType == COMBOBOX ) + exportedProperty( PROPERTY_STRING_ITEM_LIST ); + + // let the base class export the remaining properties and the events + OElementExport::exportSubTags(); + + // special sub tags for some controls + switch (m_eType) + { + case LISTBOX: + // don't export the list entries if the are not provided by the user, but obtained implicitly + // from other sources + // #i26944# + if ( controlHasUserSuppliedListEntries() ) + exportListSourceAsElements(); + break; + case GRID: + { // a grid control requires us to store all columns as sub elements + Reference< XIndexAccess > xColumnContainer(m_xProps, UNO_QUERY); + OSL_ENSURE(xColumnContainer.is(), "OControlExport::exportSubTags: a grid control which is no IndexAccess?!!"); + if (xColumnContainer.is()) + m_rContext.exportCollectionElements(xColumnContainer); + } + break; + case COMBOBOX: + { // a combox box description has sub elements: the items + DBG_CHECK_PROPERTY( PROPERTY_STRING_ITEM_LIST, Sequence< OUString > ); + + // don't export the list entries if the are not provided by the user, but obtained implicitly + // from other sources + // #i26944# + if ( controlHasUserSuppliedListEntries() ) + { + // get the item list + Sequence< OUString > aListItems; + m_xProps->getPropertyValue(PROPERTY_STRING_ITEM_LIST) >>= aListItems; + // loop through it and write the sub elements + for (const auto& rListItem : std::as_const(aListItems)) + { + m_rContext.getGlobalContext().ClearAttrList(); + AddAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Label), + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Label), + rListItem); + SvXMLElementExport aFormElement(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, "item", true, true); + } + } + } + break; + + case TEXT_AREA: + { + // if we act as rich text control, we need to export some text:p elements + if ( xControlText.is() ) + { + bool bActingAsRichText = false; + if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_RICH_TEXT ) ) + { + OSL_VERIFY(m_xProps->getPropertyValue( PROPERTY_RICH_TEXT ) >>= bActingAsRichText ); + } + + if ( bActingAsRichText ) + m_rContext.getGlobalContext().GetTextParagraphExport()->exportText( xControlText ); + } + } + break; + default: + // nothing do to + break; + } + } + + void OControlExport::exportGenericHandlerAttributes() + { + const Sequence< Property > aProperties = m_xPropertyInfo->getProperties(); + for ( auto const & prop : aProperties ) + { + try + { + // see if this property can already be handled with an IPropertyHandler (which, on the long + // term, should be the case for most, if not all, properties) + const PropertyDescription* propDescription = metadata::getPropertyDescription( prop.Name ); + if ( propDescription == nullptr ) + continue; + + // let the factory provide the concrete handler. Note that caching, if desired, is the task + // of the factory + PPropertyHandler handler = (*propDescription->factory)( propDescription->propertyId ); + if ( !handler ) + { + SAL_WARN( "xmloff.forms", "OControlExport::exportGenericHandlerAttributes: invalid property handler provided by the factory!" ); + continue; + } + + // that's a property which has a direct mapping to an attribute + if ( !shouldExportProperty( prop.Name ) ) + // TODO: in the future, we surely need a more sophisticated approach to this, involving the property + // handler, or the property description + { + exportedProperty( prop.Name ); + continue; + } + + const Any propValue = m_xProps->getPropertyValue( prop.Name ); + OUString attributeValue = handler->getAttributeValue( propValue ); + + AddAttribute( + propDescription->attribute.namespacePrefix, + token::GetXMLToken( propDescription->attribute.attributeToken ), + attributeValue + ); + + exportedProperty( prop.Name ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.forms"); + } + } + } + + void OControlExport::exportCommonControlAttributes() + { + size_t i=0; + + // I decided to handle all the properties here with some static arrays describing the property-attribute + // relations. This leads to somewhat ugly code :), but the only alternative I can think of right now + // would require maps and O(log n) searches, which seems somewhat expensive as this code is used + // very frequently. + + // the extra indents for the respective blocks are to ensure that there is no copy'n'paste error, using + // map identifiers from the wrong block + + // some string properties + { + // the attribute ids of all properties which are expected to be of type string + static const CCAFlags nStringPropertyAttributeIds[] = + { + CCAFlags::Label, CCAFlags::Title + }; + // the names of all properties which are expected to be of type string + static const char * aStringPropertyNames[] = + { + PROPERTY_LABEL, PROPERTY_TITLE + }; + OSL_ENSURE( SAL_N_ELEMENTS(aStringPropertyNames) == + SAL_N_ELEMENTS(nStringPropertyAttributeIds), + "OControlExport::exportCommonControlAttributes: somebody tampered with the maps (1)!"); + + for (i=0; i 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~nStringPropertyAttributeIds[i]; + #endif + } + } + + // some boolean properties + { + static const CCAFlags nBooleanPropertyAttributeIds[] = + { // attribute flags + CCAFlags::CurrentSelected, CCAFlags::Disabled, CCAFlags::Dropdown, CCAFlags::Printable, CCAFlags::ReadOnly, CCAFlags::Selected, CCAFlags::TabStop, CCAFlags::EnableVisible + }; + static const char * pBooleanPropertyNames[] = + { // property names + PROPERTY_STATE, PROPERTY_ENABLED, + PROPERTY_DROPDOWN, PROPERTY_PRINTABLE, + PROPERTY_READONLY, PROPERTY_DEFAULT_STATE, + PROPERTY_TABSTOP, PROPERTY_ENABLEVISIBLE + }; + static const BoolAttrFlags nBooleanPropertyAttrFlags[] = + { // attribute defaults + BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultFalse | BoolAttrFlags::InverseSemantics, BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultVoid, BoolAttrFlags::DefaultFalse + }; + #if OSL_DEBUG_LEVEL > 0 + static const sal_Int32 nIdCount = SAL_N_ELEMENTS(nBooleanPropertyAttributeIds); + static const sal_Int32 nNameCount = SAL_N_ELEMENTS(pBooleanPropertyNames); + static const sal_Int32 nFlagsCount = SAL_N_ELEMENTS(nBooleanPropertyAttrFlags); + OSL_ENSURE((nIdCount == nNameCount) && (nNameCount == nFlagsCount), + "OControlExport::exportCommonControlAttributes: somebody tampered with the maps (2)!"); + #endif + for (i=0; i 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~nBooleanPropertyAttributeIds[i]; + #endif + } + } + + // some integer properties + { + // now the common handling + static const CCAFlags nIntegerPropertyAttributeIds[] = + { // attribute flags + CCAFlags::Size, CCAFlags::TabIndex + }; + static const char * pIntegerPropertyNames[] = + { // property names + PROPERTY_LINECOUNT, PROPERTY_TABINDEX + }; + static const sal_Int16 nIntegerPropertyAttrDefaults[] = + { // attribute defaults + 5, 0 + }; + + if ( m_nIncludeCommon & CCAFlags::MaxLength ) + exportedProperty(PROPERTY_MAXTEXTLENGTH); + + #if OSL_DEBUG_LEVEL > 0 + static const sal_Int32 nIdCount = SAL_N_ELEMENTS(nIntegerPropertyAttributeIds); + static const sal_Int32 nNameCount = SAL_N_ELEMENTS(pIntegerPropertyNames); + static const sal_Int32 nDefaultCount = SAL_N_ELEMENTS(nIntegerPropertyAttrDefaults); + OSL_ENSURE((nIdCount == nNameCount) && (nNameCount == nDefaultCount), + "OControlExport::exportCommonControlAttributes: somebody tampered with the maps (3)!"); + #endif + for (i=0; i 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~nIntegerPropertyAttributeIds[i]; + #endif + } + + } + + // some enum properties + { + if (m_nIncludeCommon & CCAFlags::ButtonType) + { + exportEnumPropertyAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::ButtonType), + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::ButtonType), + PROPERTY_BUTTONTYPE, + aFormButtonTypeMap, + FormButtonType_PUSH); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::ButtonType; + #endif + } + if ( m_nIncludeCommon & CCAFlags::Orientation ) + { + exportEnumPropertyAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace( CCAFlags::Orientation ), + OAttributeMetaData::getCommonControlAttributeName( CCAFlags::Orientation ), + PROPERTY_ORIENTATION, + aOrientationMap, + ScrollBarOrientation::HORIZONTAL + ); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::Orientation; + #endif + } + + if ( m_nIncludeCommon & CCAFlags::VisualEffect ) + { + exportEnumPropertyAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace( CCAFlags::VisualEffect ), + OAttributeMetaData::getCommonControlAttributeName( CCAFlags::VisualEffect ), + PROPERTY_VISUAL_EFFECT, + aVisualEffectMap, + VisualEffect::LOOK3D + ); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::VisualEffect; + #endif + } + } + + // some properties which require a special handling + + // the target frame + if (m_nIncludeCommon & CCAFlags::TargetFrame) + { + exportTargetFrameAttribute(); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::TargetFrame; + #endif + } + + // max text length + if ( m_nIncludeCommon & CCAFlags::MaxLength ) + { + // normally, the respective property would be "MaxTextLen" + // However, if the model has a property "PersistenceMaxTextLength", then we prefer this + + // determine the name of the property to export + OUString sTextLenPropertyName( PROPERTY_MAXTEXTLENGTH ); + if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_PERSISTENCE_MAXTEXTLENGTH ) ) + sTextLenPropertyName = PROPERTY_PERSISTENCE_MAXTEXTLENGTH; + + // export it + exportInt16PropertyAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace( CCAFlags::MaxLength ), + OAttributeMetaData::getCommonControlAttributeName( CCAFlags::MaxLength ), + sTextLenPropertyName, + 0 + ); + + // in either way, both properties count as "exported" + exportedProperty( PROPERTY_MAXTEXTLENGTH ); + exportedProperty( PROPERTY_PERSISTENCE_MAXTEXTLENGTH ); + + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::MaxLength; + #endif + } + + if (m_nIncludeCommon & CCAFlags::TargetLocation) + { + exportTargetLocationAttribute(false); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::TargetLocation; + #endif + } + + // OJ #99721# + if (m_nIncludeCommon & CCAFlags::ImageData) + { + exportImageDataAttribute(); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::ImageData; + #endif + } + + // the for attribute + // the target frame + if (m_nIncludeCommon & CCAFlags::For) + { + if (!m_sReferringControls.isEmpty()) + { // there is at least one control referring to the one we're handling currently + AddAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::For), + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::For), + m_sReferringControls); + } + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags::For; + #endif + } + + if ((CCAFlags::CurrentValue | CCAFlags::Value) & m_nIncludeCommon) + { + const char* pCurrentValuePropertyName = nullptr; + const char* pValuePropertyName = nullptr; + + // get the property names + getValuePropertyNames(m_eType, m_nClassId, pCurrentValuePropertyName, pValuePropertyName); + + // add the attributes if necessary and possible + if (pCurrentValuePropertyName && (CCAFlags::CurrentValue & m_nIncludeCommon)) + { + static const OUString pCurrentValueAttributeName = OAttributeMetaData::getCommonControlAttributeName(CCAFlags::CurrentValue); + // don't export the current-value if this value originates from a data binding + // #i26944# + if ( controlHasActiveDataBinding() ) + exportedProperty( OUString::createFromAscii( pCurrentValuePropertyName ) ); + else + { + static const sal_uInt16 nCurrentValueAttributeNamespaceKey = OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::CurrentValue); + exportGenericPropertyAttribute( + nCurrentValueAttributeNamespaceKey, + pCurrentValueAttributeName, + pCurrentValuePropertyName + ); + } + } + + if (pValuePropertyName && (CCAFlags::Value & m_nIncludeCommon)) + { + static const OUString pValueAttributeName = OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Value); + static const sal_uInt16 nValueAttributeNamespaceKey = OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Value); + exportGenericPropertyAttribute( + nValueAttributeNamespaceKey, + pValueAttributeName, + pValuePropertyName); + } + + OSL_ENSURE((nullptr == pValuePropertyName) == (CCAFlags::NONE == (CCAFlags::Value & m_nIncludeCommon)), + "OControlExport::exportCommonControlAttributes: no property found for the value attribute!"); + OSL_ENSURE((nullptr == pCurrentValuePropertyName ) == (CCAFlags::NONE == (CCAFlags::CurrentValue & m_nIncludeCommon)), + "OControlExport::exportCommonControlAttributes: no property found for the current-value attribute!"); + + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeCommon = m_nIncludeCommon & ~CCAFlags(CCAFlags::CurrentValue | CCAFlags::Value); + #endif + } + + OSL_ENSURE(CCAFlags::NONE == m_nIncludeCommon, + "OControlExport::exportCommonControlAttributes: forgot some flags!"); + // in the dbg_util version, we should have removed every bit we handled from the mask, so it should + // be 0 now ... + } + + void OControlExport::exportDatabaseAttributes() + { +#if OSL_DEBUG_LEVEL > 0 + DAFlags nIncludeDatabase = m_nIncludeDatabase; +#endif + // the only string property: DataField + if (DAFlags::DataField & m_nIncludeDatabase) + { + exportStringPropertyAttribute( + OAttributeMetaData::getDatabaseAttributeNamespace(), + OAttributeMetaData::getDatabaseAttributeName(DAFlags::DataField), + PROPERTY_DATAFIELD); + RESET_BIT( nIncludeDatabase, DAFlags::DataField ); + } + + // InputRequired + if ( DAFlags::InputRequired & m_nIncludeDatabase ) + { + exportBooleanPropertyAttribute( + OAttributeMetaData::getDatabaseAttributeNamespace(), + OAttributeMetaData::getDatabaseAttributeName( DAFlags::InputRequired ), + PROPERTY_INPUT_REQUIRED, + BoolAttrFlags::DefaultFalse | BoolAttrFlags::DefaultVoid + ); + RESET_BIT( nIncludeDatabase, DAFlags::InputRequired ); + } + + // the only int16 property: BoundColumn + if (DAFlags::BoundColumn & m_nIncludeDatabase) + { + exportInt16PropertyAttribute( + OAttributeMetaData::getDatabaseAttributeNamespace(), + OAttributeMetaData::getDatabaseAttributeName(DAFlags::BoundColumn), + PROPERTY_BOUNDCOLUMN, + 0, + true); + RESET_BIT( nIncludeDatabase, DAFlags::BoundColumn ); + } + + // ConvertEmptyToNull + if (DAFlags::ConvertEmpty & m_nIncludeDatabase) + { + exportBooleanPropertyAttribute( + OAttributeMetaData::getDatabaseAttributeNamespace(), + OAttributeMetaData::getDatabaseAttributeName(DAFlags::ConvertEmpty), + PROPERTY_EMPTY_IS_NULL, + BoolAttrFlags::DefaultFalse + ); + RESET_BIT( nIncludeDatabase, DAFlags::ConvertEmpty ); + } + + // the only enum property: ListSourceType + if (DAFlags::ListSource_TYPE & m_nIncludeDatabase) + { + exportEnumPropertyAttribute( + OAttributeMetaData::getDatabaseAttributeNamespace(), + OAttributeMetaData::getDatabaseAttributeName(DAFlags::ListSource_TYPE), + PROPERTY_LISTSOURCETYPE, + aListSourceTypeMap, + ListSourceType_VALUELIST + ); + RESET_BIT( nIncludeDatabase, DAFlags::ListSource_TYPE ); + } + + if (m_nIncludeDatabase & DAFlags::ListSource) + { + exportListSourceAsAttribute(); + RESET_BIT( nIncludeDatabase, DAFlags::ListSource ); + } + +#if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE(DAFlags::NONE == nIncludeDatabase, + "OControlExport::exportDatabaseAttributes: forgot some flags!"); + // in the dbg_util version, we should have removed every bit we handled from the mask, so it should + // be 0 now ... +#endif + } + + void OControlExport::exportBindingAttributes() + { +#if OSL_DEBUG_LEVEL > 0 + BAFlags nIncludeBinding = m_nIncludeBindings; +#endif + + if ( m_nIncludeBindings & BAFlags::LinkedCell ) + { + exportCellBindingAttributes( bool(m_nIncludeBindings & BAFlags::ListLinkingType) ); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + nIncludeBinding = nIncludeBinding & ~BAFlags( BAFlags::LinkedCell | BAFlags::ListLinkingType ); + #endif + } + + if ( m_nIncludeBindings & BAFlags::ListCellRange ) + { + exportCellListSourceRange(); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + nIncludeBinding = nIncludeBinding & ~BAFlags::ListCellRange; + #endif + } + + if ( m_nIncludeBindings & BAFlags::XFormsBind ) + { + exportXFormsBindAttributes(); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + nIncludeBinding = nIncludeBinding & ~BAFlags::XFormsBind; + #endif + } + + if ( m_nIncludeBindings & BAFlags::XFormsListBind ) + { + exportXFormsListAttributes(); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + nIncludeBinding = nIncludeBinding & ~BAFlags::XFormsListBind; + #endif + } + + if ( m_nIncludeBindings & BAFlags::XFormsSubmission ) + { + exportXFormsSubmissionAttributes(); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + nIncludeBinding = nIncludeBinding & ~BAFlags::XFormsSubmission; + #endif + } + + #if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE( BAFlags::NONE == nIncludeBinding, + "OControlExport::exportBindingAttributes: forgot some flags!"); + // in the debug version, we should have removed every bit we handled from the mask, so it should + // be 0 now ... + #endif + } + + void OControlExport::exportSpecialAttributes() + { + sal_Int32 i=0; + + // the boolean properties + { + static const SCAFlags nBooleanPropertyAttributeIds[] = + { // attribute flags + SCAFlags::Validation, SCAFlags::MultiLine, SCAFlags::AutoCompletion, SCAFlags::Multiple, SCAFlags::DefaultButton, SCAFlags::IsTristate, + SCAFlags::Toggle, SCAFlags::FocusOnClick + }; + static const char * pBooleanPropertyNames[] = + { // property names + PROPERTY_STRICTFORMAT, PROPERTY_MULTILINE, + PROPERTY_AUTOCOMPLETE, + PROPERTY_MULTISELECTION, + PROPERTY_DEFAULTBUTTON, PROPERTY_TRISTATE, + PROPERTY_TOGGLE, PROPERTY_FOCUS_ON_CLICK + }; + static const sal_Int32 nIdCount = SAL_N_ELEMENTS(nBooleanPropertyAttributeIds); + #if OSL_DEBUG_LEVEL > 0 + static const sal_Int32 nNameCount = SAL_N_ELEMENTS(pBooleanPropertyNames); + OSL_ENSURE((nIdCount == nNameCount), + "OControlExport::exportSpecialAttributes: somebody tampered with the maps (1)!"); + #endif + const SCAFlags* pAttributeId = nBooleanPropertyAttributeIds; + for ( i = 0; i < nIdCount; ++i, ++pAttributeId ) + { + if ( *pAttributeId & m_nIncludeSpecial) + { + exportBooleanPropertyAttribute( + OAttributeMetaData::getSpecialAttributeNamespace( *pAttributeId ), + OAttributeMetaData::getSpecialAttributeName( *pAttributeId ), + OUString::createFromAscii(pBooleanPropertyNames[i]), + ( *pAttributeId == SCAFlags::FocusOnClick ) ? BoolAttrFlags::DefaultTrue : BoolAttrFlags::DefaultFalse + ); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeSpecial = m_nIncludeSpecial & ~*pAttributeId; + #endif + } + } + } + + // the integer properties + { + static const SCAFlags nIntegerPropertyAttributeIds[] = + { // attribute flags + SCAFlags::PageStepSize + }; + static const char * pIntegerPropertyNames[] = + { // property names + PROPERTY_BLOCK_INCREMENT + }; + static const sal_Int32 nIntegerPropertyAttrDefaults[] = + { // attribute defaults (XML defaults, not runtime defaults!) + 10 + }; + + static const sal_Int32 nIdCount = SAL_N_ELEMENTS( nIntegerPropertyAttributeIds ); + #if OSL_DEBUG_LEVEL > 0 + static const sal_Int32 nNameCount = SAL_N_ELEMENTS( pIntegerPropertyNames ); + OSL_ENSURE( ( nIdCount == nNameCount ), + "OControlExport::exportSpecialAttributes: somebody tampered with the maps (2)!" ); + static const sal_Int32 nDefaultCount = SAL_N_ELEMENTS( nIntegerPropertyAttrDefaults ); + OSL_ENSURE( ( nIdCount == nDefaultCount ), + "OControlExport::exportSpecialAttributes: somebody tampered with the maps (3)!" ); + #endif + for ( i = 0; i < nIdCount; ++i ) + if ( nIntegerPropertyAttributeIds[i] & m_nIncludeSpecial ) + { + exportInt32PropertyAttribute( + OAttributeMetaData::getSpecialAttributeNamespace( nIntegerPropertyAttributeIds[i] ), + OAttributeMetaData::getSpecialAttributeName( nIntegerPropertyAttributeIds[i] ), + OUString::createFromAscii(pIntegerPropertyNames[i]), + nIntegerPropertyAttrDefaults[i] + ); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeSpecial = m_nIncludeSpecial & ~nIntegerPropertyAttributeIds[i]; + #endif + } + + if ( SCAFlags::StepSize & m_nIncludeSpecial ) + { + OUString sPropertyName; + if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_LINE_INCREMENT ) ) + sPropertyName = PROPERTY_LINE_INCREMENT; + else if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_SPIN_INCREMENT ) ) + sPropertyName = PROPERTY_SPIN_INCREMENT; + else + OSL_FAIL( "OControlExport::exportSpecialAttributes: not property which can be mapped to step-size attribute!" ); + + if ( !sPropertyName.isEmpty() ) + exportInt32PropertyAttribute( + OAttributeMetaData::getSpecialAttributeNamespace( SCAFlags::StepSize ), + OAttributeMetaData::getSpecialAttributeName( SCAFlags::StepSize ), + sPropertyName, + 1 + ); + + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::StepSize; + #endif + } + + } + + // the enum properties + { + if (SCAFlags::State & m_nIncludeSpecial) + { + exportEnumPropertyAttribute( + OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::State), + OAttributeMetaData::getSpecialAttributeName(SCAFlags::State), + PROPERTY_DEFAULT_STATE, + aCheckStateMap, + TRISTATE_FALSE); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::State; + #endif + } + + if (SCAFlags::CurrentState & m_nIncludeSpecial) + { + exportEnumPropertyAttribute( + OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::CurrentState), + OAttributeMetaData::getSpecialAttributeName(SCAFlags::CurrentState), + PROPERTY_STATE, + aCheckStateMap, + TRISTATE_FALSE); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::CurrentState; + #endif + } + } + + // some properties which require a special handling + // the repeat delay + { + if ( m_nIncludeSpecial & SCAFlags::RepeatDelay ) + { + DBG_CHECK_PROPERTY( PROPERTY_REPEAT_DELAY, sal_Int32 ); + + sal_Int32 nRepeatDelay = 0; + m_xProps->getPropertyValue( PROPERTY_REPEAT_DELAY ) >>= nRepeatDelay; + tools::Time aTime( tools::Time::SYSTEM ); + aTime.MakeTimeFromMS( nRepeatDelay ); + util::Duration aDuration; + aDuration.Hours = aTime.GetHour(); + aDuration.Minutes = aTime.GetMin(); + aDuration.Seconds = aTime.GetSec(); + aDuration.NanoSeconds = (nRepeatDelay % 1000) * 1000000; + + OUStringBuffer buf; + ::sax::Converter::convertDuration(buf, aDuration); + AddAttribute(OAttributeMetaData::getSpecialAttributeNamespace( SCAFlags::RepeatDelay ) + ,OAttributeMetaData::getSpecialAttributeName( SCAFlags::RepeatDelay ) + ,buf.makeStringAndClear()); + + exportedProperty( PROPERTY_REPEAT_DELAY ); + + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::RepeatDelay; + #endif + } + } + + // the EchoChar property needs special handling, cause it's a Int16, but must be stored as one-character-string + { + if (SCAFlags::EchoChar & m_nIncludeSpecial) + { + DBG_CHECK_PROPERTY( PROPERTY_ECHO_CHAR, sal_Int16 ); + sal_Int16 nValue(0); + m_xProps->getPropertyValue(PROPERTY_ECHO_CHAR) >>= nValue; + if (nValue) + { + OUString sCharacter(reinterpret_cast(&nValue), 1); + AddAttribute( + OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::EchoChar), + OAttributeMetaData::getSpecialAttributeName(SCAFlags::EchoChar), + sCharacter); + } + exportedProperty(PROPERTY_ECHO_CHAR); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags::EchoChar; + #endif + } + } + + // the string properties + { + static const SCAFlags nStringPropertyAttributeIds[] = + { // attribute flags + SCAFlags::GroupName + }; + static const std::u16string_view pStringPropertyNames[] = + { // property names + u"" PROPERTY_GROUP_NAME + }; + + static const sal_Int32 nIdCount = SAL_N_ELEMENTS( nStringPropertyAttributeIds ); + #if OSL_DEBUG_LEVEL > 0 + static const sal_Int32 nNameCount = SAL_N_ELEMENTS( pStringPropertyNames ); + OSL_ENSURE( ( nIdCount == nNameCount ), + "OControlExport::exportSpecialAttributes: somebody tampered with the maps (2)!" ); + #endif + for ( i = 0; i < nIdCount; ++i ) + if ( nStringPropertyAttributeIds[i] & m_nIncludeSpecial ) + { + exportStringPropertyAttribute( + OAttributeMetaData::getSpecialAttributeNamespace( nStringPropertyAttributeIds[i] ), + OAttributeMetaData::getSpecialAttributeName( nStringPropertyAttributeIds[i] ), + OUString(pStringPropertyNames[i]) + ); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeSpecial = m_nIncludeSpecial & ~nStringPropertyAttributeIds[i]; + #endif + } + } + + if ((SCAFlags::MinValue | SCAFlags::MaxValue) & m_nIncludeSpecial) + { + // need to export the min value and the max value as attributes + // It depends on the real type (FormComponentType) of the control, which properties hold these + // values + const char* pMinValuePropertyName = nullptr; + const char* pMaxValuePropertyName = nullptr; + getValueLimitPropertyNames(m_nClassId, pMinValuePropertyName, pMaxValuePropertyName); + + OSL_ENSURE((nullptr == pMinValuePropertyName) == (SCAFlags::NONE == (SCAFlags::MinValue & m_nIncludeSpecial)), + "OControlExport::exportCommonControlAttributes: no property found for the min value attribute!"); + OSL_ENSURE((nullptr == pMaxValuePropertyName) == (SCAFlags::NONE == (SCAFlags::MaxValue & m_nIncludeSpecial)), + "OControlExport::exportCommonControlAttributes: no property found for the max value attribute!"); + + // add the two attributes + static const OUString pMinValueAttributeName = OAttributeMetaData::getSpecialAttributeName(SCAFlags::MinValue); + static const OUString pMaxValueAttributeName = OAttributeMetaData::getSpecialAttributeName(SCAFlags::MaxValue); + static const sal_uInt16 nMinValueNamespaceKey = OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::MinValue); + static const sal_uInt16 nMaxValueNamespaceKey = OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags::MaxValue); + + if (pMinValuePropertyName && (SCAFlags::MinValue & m_nIncludeSpecial)) + exportGenericPropertyAttribute( + nMinValueNamespaceKey, + pMinValueAttributeName, + pMinValuePropertyName); + + if (pMaxValuePropertyName && (SCAFlags::MaxValue & m_nIncludeSpecial)) + exportGenericPropertyAttribute( + nMaxValueNamespaceKey, + pMaxValueAttributeName, + pMaxValuePropertyName); + #if OSL_DEBUG_LEVEL > 0 + // reset the bit for later checking + m_nIncludeSpecial = m_nIncludeSpecial & ~SCAFlags(SCAFlags::MinValue | SCAFlags::MaxValue); + #endif + } + + if ( SCAFlags::ImagePosition & m_nIncludeSpecial ) + { + exportImagePositionAttributes(); + RESET_BIT( m_nIncludeSpecial, SCAFlags::ImagePosition ); + } + + OSL_ENSURE(SCAFlags::NONE == m_nIncludeSpecial, + "OControlExport::exportSpecialAttributes: forgot some flags!"); + // in the dbg_util version, we should have removed every bit we handled from the mask, so it should + // be 0 now ... + } + + OUString OControlExport::getScalarListSourceValue() const + { + OUString sListSource; + Any aListSource = m_xProps->getPropertyValue( PROPERTY_LISTSOURCE ); + if ( !( aListSource >>= sListSource ) ) + { + Sequence< OUString > aListSourceSequence; + aListSource >>= aListSourceSequence; + if ( aListSourceSequence.hasElements() ) + sListSource = aListSourceSequence[ 0 ]; + } + return sListSource; + } + + void OControlExport::exportListSourceAsAttribute() + { + // DAFlags::ListSource needs some special handling + DBG_CHECK_PROPERTY_NO_TYPE( PROPERTY_LISTSOURCE ); + + OUString sListSource = getScalarListSourceValue(); + if ( !sListSource.isEmpty() ) + { // the ListSource property needs to be exported as attribute, and it is not empty + AddAttribute( + OAttributeMetaData::getDatabaseAttributeNamespace(), + OAttributeMetaData::getDatabaseAttributeName(DAFlags::ListSource), + sListSource); + } + + exportedProperty( PROPERTY_LISTSOURCE ); + } + + void OControlExport::getSequenceInt16PropertyAsSet(const OUString& _rPropertyName, Int16Set& _rOut) + { + Sequence< sal_Int16 > aValueSequence; + DBG_CHECK_PROPERTY(_rPropertyName, Sequence< sal_Int16 >); + m_xProps->getPropertyValue(_rPropertyName) >>= aValueSequence; + + for (const auto& rValue : std::as_const(aValueSequence)) + _rOut.insert(rValue); + } + + void OControlExport::exportListSourceAsElements() + { + // the string lists + Sequence< OUString > aItems, aValues; + DBG_CHECK_PROPERTY( PROPERTY_STRING_ITEM_LIST, Sequence< OUString > ); + m_xProps->getPropertyValue(PROPERTY_STRING_ITEM_LIST) >>= aItems; + + DBG_CHECK_PROPERTY( PROPERTY_LISTSOURCE, Sequence< OUString > ); + if ( DAFlags::NONE == ( m_nIncludeDatabase & DAFlags::ListSource ) ) + m_xProps->getPropertyValue(PROPERTY_LISTSOURCE) >>= aValues; + // if we exported the list source as attribute, we do not repeat it as sub elements + + // the selection lists + Int16Set aSelection, aDefaultSelection; + getSequenceInt16PropertyAsSet(PROPERTY_SELECT_SEQ, aSelection); + getSequenceInt16PropertyAsSet(PROPERTY_DEFAULT_SELECT_SEQ, aDefaultSelection); + + // the string for "true" + OUString sTrue; + OUStringBuffer sBuffer; + ::sax::Converter::convertBool(sBuffer, true); + sTrue = sBuffer.makeStringAndClear(); + + // loop through both lists ('til the maximum of both lengths) + const OUString* pItems = aItems.getConstArray(); + const OUString* pValues = aValues.getConstArray(); + + sal_Int32 nItems = aItems.getLength(); + sal_Int32 nValues = aValues.getLength(); + + sal_Int16 nMaxLen = static_cast(std::max(nItems, nValues)); + + for (sal_Int16 i=0; i= nMaxLen, "OControlExport::exportListSourceAsElements: inconsistence!"); + // if the maximum (selected or default selected) entry number is less than the maximum item count + // in both lists, the entry number should have been removed from the set + + for (sal_Int16 i=nMaxLen; i<=nLastReferredEntry; ++i) + { + if (aSelection.end() != aSelection.find(i)) + { // the (not existent) item at this position is selected + AddAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::CurrentSelected), + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::CurrentSelected), + sTrue + ); + } + + if (aDefaultSelection.end() != aDefaultSelection.find(i)) + { // the (not existent) item at this position is selected as default + AddAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Selected), + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Selected), + sTrue + ); + } + SvXMLElementExport aFormElement(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, "option", true, true); + } + } + + void OControlExport::implStartElement(const char* _pName) + { + // before we let the base class start it's outer element, we add a wrapper element + const char *pOuterElementName = getOuterXMLElementName(); + if (pOuterElementName) + m_pOuterElement = std::make_unique( + m_rContext.getGlobalContext(), + XML_NAMESPACE_FORM, + pOuterElementName, true, + true); + + // add the attributes for the inner element + exportInnerAttributes(); + + // and start the inner element + OElementExport::implStartElement(_pName); + } + + void OControlExport::implEndElement() + { + // end the inner element + OElementExport::implEndElement(); + + // end the outer element if it exists + m_pOuterElement.reset(); + } + + const char* OControlExport::getOuterXMLElementName() const + { + return nullptr; + } + + const char* OControlExport::getXMLElementName() const + { + return getElementName(m_eType); + } + + void OControlExport::examine() + { + OSL_ENSURE( ( m_nIncludeCommon == CCAFlags::NONE ) && ( m_nIncludeSpecial == SCAFlags::NONE ) && ( m_nIncludeDatabase == DAFlags::NONE ) + && ( m_nIncludeEvents == EAFlags::NONE ) && ( m_nIncludeBindings == BAFlags::NONE), + "OControlExport::examine: called me twice? Not initialized?" ); + + // get the class id to decide which kind of element we need in the XML stream + m_nClassId = FormComponentType::CONTROL; + DBG_CHECK_PROPERTY( PROPERTY_CLASSID, sal_Int16 ); + m_xProps->getPropertyValue(PROPERTY_CLASSID) >>= m_nClassId; + bool knownType = false; + switch (m_nClassId) + { + case FormComponentType::DATEFIELD: + m_eType = DATE; + knownType = true; + [[fallthrough]]; + case FormComponentType::TIMEFIELD: + if ( !knownType ) + { + m_eType = TIME; + knownType = true; + } + m_nIncludeSpecial |= SCAFlags::Validation; + [[fallthrough]]; + case FormComponentType::NUMERICFIELD: + case FormComponentType::CURRENCYFIELD: + case FormComponentType::PATTERNFIELD: + if ( !knownType ) + { + m_eType = FORMATTED_TEXT; + knownType = true; + } + [[fallthrough]]; + case FormComponentType::TEXTFIELD: + { // it's some kind of edit. To know which type we need further investigation + + if ( !knownType ) + { + // check if it's a formatted field + if (m_xPropertyInfo->hasPropertyByName(PROPERTY_FORMATKEY)) + { + m_eType = FORMATTED_TEXT; + } + else + { + // all other controls are represented by an ordinary edit control, but which XML control type + // it is depends on the current values of some properties + + // if the EchoChar string is not empty, it is a password field + sal_Int16 nEchoChar = 0; + if (m_xPropertyInfo->hasPropertyByName(PROPERTY_ECHOCHAR)) + // grid columns do not have this property... + m_xProps->getPropertyValue(PROPERTY_ECHOCHAR) >>= nEchoChar; + if (nEchoChar) + { + m_eType = PASSWORD; + m_nIncludeSpecial |= SCAFlags::EchoChar; + } + else + { + // if the MultiLine property is sal_True, it is a TextArea + bool bMultiLine = false; + if (m_xPropertyInfo->hasPropertyByName(PROPERTY_MULTILINE)) + // grid columns do not have this property... + bMultiLine = ::cppu::any2bool(m_xProps->getPropertyValue(PROPERTY_MULTILINE)); + + if ( bMultiLine ) + m_eType = TEXT_AREA; + else + // the only case left is represented by a Text element + m_eType = TEXT; + } + } + } + + // attributes which are common to all the types: + // common attributes + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | + CCAFlags::Printable | CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title; + + if ( ( m_nClassId != FormComponentType::DATEFIELD ) + && ( m_nClassId != FormComponentType::TIMEFIELD ) + ) + // date and time field values are handled differently nowadays + m_nIncludeCommon |= CCAFlags::Value; + + // database attributes + m_nIncludeDatabase = DAFlags::DataField | DAFlags::InputRequired; + + // event attributes + m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange | EAFlags::OnSelect; + + // only text and pattern fields have a ConvertEmptyToNull property + if ( ( m_nClassId == FormComponentType::TEXTFIELD ) + || ( m_nClassId == FormComponentType::PATTERNFIELD ) + ) + m_nIncludeDatabase |= DAFlags::ConvertEmpty; + + // all controls but the file control fields have a readonly property + if ( m_nClassId != FormComponentType::FILECONTROL ) + m_nIncludeCommon |= CCAFlags::ReadOnly; + + // a text field has a max text len + if ( m_nClassId == FormComponentType::TEXTFIELD ) + m_nIncludeCommon |= CCAFlags::MaxLength; + + // max and min values and validation: + if (FORMATTED_TEXT == m_eType) + { // in general all controls represented as formatted-text have these props + if ( FormComponentType::PATTERNFIELD != m_nClassId ) // except the PatternField + m_nIncludeSpecial |= SCAFlags::MaxValue | SCAFlags::MinValue; + + if (FormComponentType::TEXTFIELD != m_nClassId) + // and the FormattedField does not have a validation flag + m_nIncludeSpecial |= SCAFlags::Validation; + } + + // if it's not a password field or rich text control, the CurrentValue needs to be stored, too + if ( ( PASSWORD != m_eType ) + && ( DATE != m_eType ) + && ( TIME != m_eType ) + ) + { + m_nIncludeCommon |= CCAFlags::CurrentValue; + } + } + break; + + case FormComponentType::FILECONTROL: + m_eType = FILE; + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::CurrentValue | CCAFlags::Disabled | + CCAFlags::Printable | CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title | + CCAFlags::Value; + m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange | EAFlags::OnSelect; + break; + + case FormComponentType::FIXEDTEXT: + m_eType = FIXED_TEXT; + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Label | + CCAFlags::Printable | CCAFlags::Title | CCAFlags::For; + m_nIncludeSpecial = SCAFlags::MultiLine; + m_nIncludeEvents = EAFlags::ControlEvents; + break; + + case FormComponentType::COMBOBOX: + m_eType = COMBOBOX; + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::CurrentValue | + CCAFlags::Disabled | CCAFlags::Dropdown | CCAFlags::MaxLength | CCAFlags::Printable | CCAFlags::ReadOnly | CCAFlags::Size | + CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title | CCAFlags::Value; + m_nIncludeSpecial = SCAFlags::AutoCompletion; + m_nIncludeDatabase = DAFlags::ConvertEmpty | DAFlags::DataField | DAFlags::InputRequired | DAFlags::ListSource | DAFlags::ListSource_TYPE; + m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange | EAFlags::OnSelect; + break; + + case FormComponentType::LISTBOX: + m_eType = LISTBOX; + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Dropdown | + CCAFlags::Printable | CCAFlags::Size | CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title; + m_nIncludeSpecial = SCAFlags::Multiple; + m_nIncludeDatabase = DAFlags::BoundColumn | DAFlags::DataField | DAFlags::InputRequired | DAFlags::ListSource_TYPE; + m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange | EAFlags::OnClick | EAFlags::OnDoubleClick; + // check if we need to export the ListSource as attribute + { + // for a list box, if the ListSourceType is VALUE_LIST, no ListSource is stored, but instead + // a sequence of pairs which is build from the StringItemList and the ValueList + ListSourceType eListSourceType = ListSourceType_VALUELIST; + bool bSuccess = + m_xProps->getPropertyValue(PROPERTY_LISTSOURCETYPE) >>= eListSourceType; + OSL_ENSURE(bSuccess, "OControlExport::examineControl: could not retrieve the ListSourceType!"); + if (ListSourceType_VALUELIST != eListSourceType) + { + m_nIncludeDatabase |= DAFlags::ListSource; + } + } + + break; + + case FormComponentType::COMMANDBUTTON: + m_eType = BUTTON; + m_nIncludeCommon |= CCAFlags::TabStop | CCAFlags::Label; + m_nIncludeSpecial = SCAFlags::DefaultButton | SCAFlags::Toggle | SCAFlags::FocusOnClick | SCAFlags::ImagePosition | SCAFlags::RepeatDelay; + [[fallthrough]]; + case FormComponentType::IMAGEBUTTON: + if (BUTTON != m_eType) + { + // not coming from the previous case + m_eType = IMAGE; + } + m_nIncludeCommon |= + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::ButtonType | CCAFlags::Disabled | + CCAFlags::ImageData | CCAFlags::Printable | CCAFlags::TabIndex | CCAFlags::TargetFrame | + CCAFlags::TargetLocation | CCAFlags::Title; + m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnClick | EAFlags::OnDoubleClick; + break; + + case FormComponentType::CHECKBOX: + m_eType = CHECKBOX; + m_nIncludeSpecial = SCAFlags::CurrentState | SCAFlags::IsTristate | SCAFlags::State; + [[fallthrough]]; + case FormComponentType::RADIOBUTTON: + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Label | CCAFlags::Printable | + CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title | CCAFlags::Value | CCAFlags::VisualEffect; + if (CHECKBOX != m_eType) + { // not coming from the previous case + m_eType = RADIO; + m_nIncludeCommon |= CCAFlags::CurrentSelected | CCAFlags::Selected; + } + if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_IMAGE_POSITION ) ) + m_nIncludeSpecial |= SCAFlags::ImagePosition; + if ( m_xPropertyInfo->hasPropertyByName( PROPERTY_GROUP_NAME ) ) + m_nIncludeSpecial |= SCAFlags::GroupName; + m_nIncludeDatabase = DAFlags::DataField | DAFlags::InputRequired; + m_nIncludeEvents = EAFlags::ControlEvents | EAFlags::OnChange; + break; + + case FormComponentType::GROUPBOX: + m_eType = FRAME; + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Label | + CCAFlags::Printable | CCAFlags::Title | CCAFlags::For; + m_nIncludeEvents = EAFlags::ControlEvents; + break; + + case FormComponentType::IMAGECONTROL: + m_eType = IMAGE_FRAME; + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::ImageData | + CCAFlags::Printable | CCAFlags::ReadOnly | CCAFlags::Title; + m_nIncludeDatabase = DAFlags::DataField | DAFlags::InputRequired; + m_nIncludeEvents = EAFlags::ControlEvents; + break; + + case FormComponentType::HIDDENCONTROL: + m_eType = HIDDEN; + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Value; + break; + + case FormComponentType::GRIDCONTROL: + m_eType = GRID; + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Printable | + CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Title; + m_nIncludeEvents = EAFlags::ControlEvents; + break; + + case FormComponentType::SCROLLBAR: + case FormComponentType::SPINBUTTON: + m_eType = VALUERANGE; + m_nIncludeCommon = + CCAFlags::Name | CCAFlags::ServiceName | CCAFlags::Disabled | CCAFlags::Printable | + CCAFlags::Title | CCAFlags::CurrentValue | CCAFlags::Value | CCAFlags::Orientation; + m_nIncludeSpecial = SCAFlags::MaxValue | SCAFlags::StepSize | SCAFlags::MinValue | SCAFlags::RepeatDelay; + + if ( m_nClassId == FormComponentType::SCROLLBAR ) + m_nIncludeSpecial |= SCAFlags::PageStepSize ; + + m_nIncludeEvents = EAFlags::ControlEvents; + break; + + default: + OSL_FAIL("OControlExport::examineControl: unknown control type (class id)!"); + [[fallthrough]]; + + case FormComponentType::NAVIGATIONBAR: + // TODO: should we have an own file format for this? + // NO break + + case FormComponentType::CONTROL: + m_eType = GENERIC_CONTROL; + // unknown control type + m_nIncludeCommon = CCAFlags::Name | CCAFlags::ServiceName; + // at least a name should be there, 'cause without a name the control could never have been + // inserted into its parent container + // In addition, the service name is absolutely necessary to create the control upon reading. + m_nIncludeEvents = EAFlags::ControlEvents; + // we always should be able to export events - this is not control type dependent + break; + } + + // in general, all control types need to export the control id + m_nIncludeCommon |= CCAFlags::ControlId; + + // is it a control bound to a calc cell? + if ( FormCellBindingHelper::livesInSpreadsheetDocument( m_xProps ) ) + { + FormCellBindingHelper aHelper( m_xProps, nullptr ); + { + if ( FormCellBindingHelper::isCellBinding( aHelper.getCurrentBinding( ) ) ) + { + m_nIncludeBindings |= BAFlags::LinkedCell; + if ( m_nClassId == FormComponentType::LISTBOX ) + m_nIncludeBindings |= BAFlags::ListLinkingType; + } + } + + // is it a list-like control which uses a calc cell range as list source? + { + if ( FormCellBindingHelper::isCellRangeListSource( aHelper.getCurrentListSource( ) ) ) + m_nIncludeBindings |= BAFlags::ListCellRange; + } + } + + // is control bound to XForms? + if( !getXFormsBindName( m_xProps ).isEmpty() ) + { + m_nIncludeBindings |= BAFlags::XFormsBind; + } + + // is (list-)control bound to XForms list? + if( !getXFormsListBindName( m_xProps ).isEmpty() ) + { + m_nIncludeBindings |= BAFlags::XFormsListBind; + } + + // does the control have an XForms submission? + if( !getXFormsSubmissionName( m_xProps ).isEmpty() ) + { + m_nIncludeBindings |= BAFlags::XFormsSubmission; + } + } + + void OControlExport::exportCellBindingAttributes( bool _bIncludeListLinkageType ) + { + try + { + FormCellBindingHelper aHelper( m_xProps, nullptr ); + Reference< XValueBinding > xBinding( aHelper.getCurrentBinding() ); + OSL_ENSURE( xBinding.is(), "OControlExport::exportCellBindingAttributes: invalid bindable or invalid binding!" ); + if ( xBinding.is() ) + { + AddAttribute( + OAttributeMetaData::getBindingAttributeNamespace(), + OAttributeMetaData::getBindingAttributeName( BAFlags::LinkedCell ), + aHelper.getStringAddressFromCellBinding( xBinding ) + ); + + if ( _bIncludeListLinkageType ) + { + sal_Int16 nLinkageType = FormCellBindingHelper::isCellIntegerBinding( xBinding ) ? 1 : 0; + + OUStringBuffer sBuffer; + SvXMLUnitConverter::convertEnum( + sBuffer, + nLinkageType, + aListLinkageMap + ); + + AddAttribute( + OAttributeMetaData::getBindingAttributeNamespace(), + OAttributeMetaData::getBindingAttributeName( BAFlags::ListLinkingType ), + sBuffer.makeStringAndClear() + ); + } + + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "xmloff.forms", "OControlExport::exportCellBindingAttributes" ); + } + } + + void OControlExport::exportXFormsBindAttributes() + { + OUString sBindName = getXFormsBindName( m_xProps ); + AddAttribute( XML_NAMESPACE_XFORMS, XML_BIND, sBindName ); + } + void OControlExport::exportXFormsListAttributes() + { + OUString sBindName = getXFormsListBindName( m_xProps ); + AddAttribute( XML_NAMESPACE_FORM, XML_XFORMS_LIST_SOURCE, sBindName ); + } + void OControlExport::exportXFormsSubmissionAttributes() + { + OUString sSubmission = getXFormsSubmissionName( m_xProps ); + AddAttribute( XML_NAMESPACE_FORM, XML_XFORMS_SUBMISSION, sSubmission ); + } + void OControlExport::exportCellListSourceRange( ) + { + try + { + Reference< XListEntrySink > xSink( m_xProps, UNO_QUERY ); + Reference< XListEntrySource > xSource; + if ( xSink.is() ) + xSource = xSink->getListEntrySource(); + OSL_ENSURE( xSource.is(), "OControlExport::exportCellListSourceRange: list source or sink!" ); + if ( xSource.is() ) + { + FormCellBindingHelper aHelper( m_xProps, nullptr ); + + AddAttribute( + OAttributeMetaData::getBindingAttributeNamespace(), + OAttributeMetaData::getBindingAttributeName( BAFlags::ListCellRange ), + aHelper.getStringAddressFromCellListSource( xSource ) + ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "xmloff.forms", "OControlExport::exportCellListSourceRange" ); + } + } + + void OControlExport::exportImagePositionAttributes() + { + try + { + sal_Int16 nImagePosition = ImagePosition::Centered; + OSL_VERIFY( m_xProps->getPropertyValue( PROPERTY_IMAGE_POSITION ) >>= nImagePosition ); + OSL_ENSURE( ( nImagePosition >= ImagePosition::LeftTop ) && ( nImagePosition <= ImagePosition::Centered ), + "OControlExport::exportImagePositionAttributes: don't know this image position!" ); + + if ( ( nImagePosition < ImagePosition::LeftTop ) || ( nImagePosition > ImagePosition::Centered ) ) + // this is important to prevent potential buffer overflows below, so don't optimize + nImagePosition = ImagePosition::Centered; + + if ( nImagePosition == ImagePosition::Centered ) + { + AddAttribute( XML_NAMESPACE_FORM, GetXMLToken( XML_IMAGE_POSITION ), GetXMLToken( XML_CENTER ) ); + } + else + { + const XMLTokenEnum eXmlImagePositions[] = + { + XML_START, XML_END, XML_TOP, XML_BOTTOM + }; + const XMLTokenEnum eXmlImageAligns[] = + { + XML_START, XML_CENTER, XML_END + }; + + XMLTokenEnum eXmlImagePosition = eXmlImagePositions[ nImagePosition / 3 ]; + XMLTokenEnum eXmlImageAlign = eXmlImageAligns [ nImagePosition % 3 ]; + + AddAttribute( XML_NAMESPACE_FORM, GetXMLToken( XML_IMAGE_POSITION ), GetXMLToken( eXmlImagePosition ) ); + AddAttribute( XML_NAMESPACE_FORM, GetXMLToken( XML_IMAGE_ALIGN ), GetXMLToken( eXmlImageAlign ) ); + } + + exportedProperty( PROPERTY_IMAGE_POSITION ); + // some of the controls which have an ImagePosition also have an ImageAlign for compatibility + // reasons. Since the ImageAlign values simply represent a sub set of the ImagePosition values, + // we don't need to export ImageAlign anymore + exportedProperty( PROPERTY_IMAGE_ALIGN ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.forms"); + } + } + + bool OControlExport::controlHasActiveDataBinding() const + { + try + { + // currently exchanging the data with a database column? + OUString sBoundFieldPropertyName( "BoundField" ); + if ( m_xPropertyInfo.is() && m_xPropertyInfo->hasPropertyByName( sBoundFieldPropertyName ) ) + { + Reference< XPropertySet > xBoundField; + m_xProps->getPropertyValue( sBoundFieldPropertyName ) >>= xBoundField; + if ( xBoundField.is() ) + return true; + } + + // currently exchanging data with an external binding? + Reference< XBindableValue > xBindable( m_xProps, UNO_QUERY ); + if ( xBindable.is() && xBindable->getValueBinding().is() ) + return true; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "xmloff.forms", "OColumnExport::controlHasActiveDataBinding" ); + } + + return false; + } + + bool OControlExport::controlHasUserSuppliedListEntries() const + { + try + { + // an external list source? + Reference< XListEntrySink > xEntrySink( m_xProps, UNO_QUERY ); + if ( xEntrySink.is() && xEntrySink->getListEntrySource().is() ) + return false; + + if ( m_xPropertyInfo.is() && m_xPropertyInfo->hasPropertyByName( PROPERTY_LISTSOURCETYPE ) ) + { + ListSourceType eListSourceType = ListSourceType_VALUELIST; + OSL_VERIFY( m_xProps->getPropertyValue( PROPERTY_LISTSOURCETYPE ) >>= eListSourceType ); + if ( eListSourceType == ListSourceType_VALUELIST ) + // for value lists, the list entries as entered by the user are used + return true; + + // for every other type, the list entries are filled with some data obtained + // from a database - if and only if the ListSource property is not empty + return getScalarListSourceValue().isEmpty(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.forms"); + } + + OSL_FAIL( "OControlExport::controlHasUserSuppliedListEntries: unreachable code!" ); + // this method should be called for list and combo boxes only + return true; + } + + //= OColumnExport + OColumnExport::OColumnExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxControl, const OUString& _rControlId, + const Sequence< ScriptEventDescriptor >& _rEvents) + :OControlExport(_rContext, _rxControl, _rControlId, OUString(), _rEvents) + { + } + + OColumnExport::~OColumnExport() + { + } + + void OColumnExport::exportServiceNameAttribute() + { + // the attribute "service name" (which has a slightly different meaning for columns + DBG_CHECK_PROPERTY( PROPERTY_COLUMNSERVICENAME, OUString ); + OUString sColumnServiceName; + m_xProps->getPropertyValue(PROPERTY_COLUMNSERVICENAME) >>= sColumnServiceName; + // the service name is a full qualified one (i.e. com.sun.star.form.TextField), but the + // real service name for the column (for use with the XGridColumnFactory) is only the last + // token of this complete name. + sal_Int32 nLastSep = sColumnServiceName.lastIndexOf('.'); + OSL_ENSURE(-1 != nLastSep, "OColumnExport::startExportElement: invalid service name!"); + sColumnServiceName = sColumnServiceName.copy(nLastSep + 1); + sColumnServiceName = + m_rContext.getGlobalContext().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, sColumnServiceName ); + // add the attribute + AddAttribute( OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::ServiceName) + , OAttributeMetaData::getCommonControlAttributeName(CCAFlags::ServiceName) + , sColumnServiceName); + // flag the property as "handled" + exportedProperty(PROPERTY_COLUMNSERVICENAME); + + } + + const char* OColumnExport::getOuterXMLElementName() const + { + return "column"; + } + + void OColumnExport::exportAttributes() + { + OControlExport::exportAttributes(); + + // the attribute "label" + exportStringPropertyAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::Label), + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Label), + PROPERTY_LABEL); + + // the style attribute + OUString sStyleName = m_rContext.getObjectStyleName( m_xProps ); + if ( !sStyleName.isEmpty() ) + { + AddAttribute( + OAttributeMetaData::getSpecialAttributeNamespace( SCAFlags::ColumnStyleName ), + OAttributeMetaData::getSpecialAttributeName( SCAFlags::ColumnStyleName ), + sStyleName + ); + } + } + + void OColumnExport::examine() + { + OControlExport::examine(); + + // grid columns miss some properties of the controls they're representing + m_nIncludeCommon &= ~CCAFlags(CCAFlags::For | CCAFlags::Printable | CCAFlags::TabIndex | CCAFlags::TabStop | CCAFlags::Label); + m_nIncludeSpecial &= ~SCAFlags(SCAFlags::EchoChar | SCAFlags::AutoCompletion | SCAFlags::Multiple | SCAFlags::MultiLine); + + if (FormComponentType::DATEFIELD != m_nClassId) + // except date fields, no column has the DropDown property + m_nIncludeCommon &= ~CCAFlags::Dropdown; + } + + //= OFormExport + OFormExport::OFormExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxForm, + const Sequence< ScriptEventDescriptor >& _rEvents) + :OElementExport(_rContext, _rxForm, _rEvents) + ,m_bCreateConnectionResourceElement(false) + { + OSL_ENSURE(m_xProps.is(), "OFormExport::OFormExport: invalid arguments!"); + } + + const char* OFormExport::getXMLElementName() const + { + return "form"; + } + + void OFormExport::exportSubTags() + { + if ( m_bCreateConnectionResourceElement && m_xProps.is() ) + { + m_rContext.getGlobalContext().ClearAttrList(); + OUString sPropValue; + m_xProps->getPropertyValue( PROPERTY_DATASOURCENAME ) >>= sPropValue; // if set it is a file url + if ( sPropValue.isEmpty() ) + m_xProps->getPropertyValue( PROPERTY_URL ) >>= sPropValue; + if ( !sPropValue.isEmpty() ) + AddAttribute( + OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::TargetLocation), + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::TargetLocation), + m_rContext.getGlobalContext().GetRelativeReference(sPropValue)); + if ( m_rContext.getGlobalContext().GetAttrList().getLength() ) + { + SvXMLElementExport aFormElement(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, xmloff::token::XML_CONNECTION_RESOURCE, true, true); + } + } + + // let the base class export the remaining properties and the events + OElementExport::exportSubTags(); + // loop through all children + Reference< XIndexAccess > xCollection(m_xProps, UNO_QUERY); + OSL_ENSURE(xCollection.is(), "OFormLayerXMLExport::implExportForm: a form which is not an index access? Suspicious!"); + + if (xCollection.is()) + m_rContext.exportCollectionElements(xCollection); + } + + void OFormExport::exportAttributes() + { + sal_Int32 i=0; + + // the string properties + { + static const FormAttributes eStringPropertyIds[] = + { + faName, /*faAction,*/ faCommand, faFilter, faOrder + }; + static const char * aStringPropertyNames[] = + { + PROPERTY_NAME, /*PROPERTY_TARGETURL,*/ PROPERTY_COMMAND, PROPERTY_FILTER, PROPERTY_ORDER + }; + static const sal_Int32 nIdCount = SAL_N_ELEMENTS(eStringPropertyIds); + #if OSL_DEBUG_LEVEL > 0 + static const sal_Int32 nNameCount = SAL_N_ELEMENTS(aStringPropertyNames); + OSL_ENSURE((nIdCount == nNameCount), + "OFormExport::exportAttributes: somebody tampered with the maps (1)!"); + #endif + for (i=0; igetPropertyValue( PROPERTY_DATASOURCENAME ) >>= sPropValue; + m_bCreateConnectionResourceElement = sPropValue.isEmpty(); + if ( !m_bCreateConnectionResourceElement ) + { + INetURLObject aURL(sPropValue); + m_bCreateConnectionResourceElement = ( aURL.GetProtocol() == INetProtocol::File ); + if ( !m_bCreateConnectionResourceElement ) + exportStringPropertyAttribute( + OAttributeMetaData::getFormAttributeNamespace(faDatasource), + OAttributeMetaData::getFormAttributeName(faDatasource), + PROPERTY_DATASOURCENAME); + } + else + exportedProperty(PROPERTY_URL); + if ( m_bCreateConnectionResourceElement ) + exportedProperty(PROPERTY_DATASOURCENAME); + } + + // the boolean properties + { + static const FormAttributes eBooleanPropertyIds[] = + { + faAllowDeletes, faAllowInserts, faAllowUpdates, faApplyFilter, faEscapeProcessing, faIgnoreResult + }; + static const char * pBooleanPropertyNames[] = + { + PROPERTY_ALLOWDELETES, + PROPERTY_ALLOWINSERTS, + PROPERTY_ALLOWUPDATES, + PROPERTY_APPLYFILTER, + PROPERTY_ESCAPEPROCESSING, + PROPERTY_IGNORERESULT + }; + static const BoolAttrFlags nBooleanPropertyAttrFlags[] = + { + BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultFalse, BoolAttrFlags::DefaultTrue, BoolAttrFlags::DefaultFalse + }; + static const sal_Int32 nIdCount = SAL_N_ELEMENTS(eBooleanPropertyIds); + #if OSL_DEBUG_LEVEL > 0 + static const sal_Int32 nNameCount = SAL_N_ELEMENTS(pBooleanPropertyNames); + static const sal_Int32 nFlagsCount = SAL_N_ELEMENTS(nBooleanPropertyAttrFlags); + OSL_ENSURE((nIdCount == nNameCount) && (nNameCount == nFlagsCount), + "OFormExport::exportAttributes: somebody tampered with the maps (2)!"); + #endif + for (i=0; i + +#include +#include + +#include +#include +#include +#include "propertyexport.hxx" +#include "callbacks.hxx" +#include "controlelement.hxx" +#include "valueproperties.hxx" + +class SvXMLElementExport; +namespace xmloff +{ + + //= OElementExport + class OElementExport : public OPropertyExport + { + protected: + css::uno::Sequence< css::script::ScriptEventDescriptor > + m_aEvents; + + std::unique_ptr m_pXMLElement; // XML element doing the concrete startElement etc. + + public: + OElementExport(IFormsExportContext& _rContext, + const css::uno::Reference< css::beans::XPropertySet >& _rxProps, + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents); + virtual ~OElementExport(); + + void doExport(); + + protected: + /// get the name of the XML element + virtual const char* getXMLElementName() const = 0; + /// examine the element we're exporting + virtual void examine(); + /// export the attributes + virtual void exportAttributes(); + /// export any sub tags + virtual void exportSubTags(); + + /** exports the events (as script:events tag) + */ + void exportEvents(); + + /** add the service-name attribute to the export context + */ + virtual void exportServiceNameAttribute(); + + /// start the XML element + virtual void implStartElement(const char* _pName); + + /// ends the XML element + virtual void implEndElement(); + }; + + //= OControlExport + /** Helper class for handling xml elements representing a form control + */ + class OControlExport + :public OControlElement + ,public OValuePropertiesMetaData + ,public OElementExport + { + protected: + typedef o3tl::sorted_vector Int16Set; + // used below + + OUString m_sControlId; // the control id to use when exporting + OUString m_sReferringControls; // list of referring controls (i.e. their id's) + sal_Int16 m_nClassId; // class id of the control we're representing + ElementType m_eType; // (XML) type of the control we're representing + CCAFlags m_nIncludeCommon; // common control attributes to include + DAFlags m_nIncludeDatabase; // common database attributes to include + SCAFlags m_nIncludeSpecial; // special attributes to include + EAFlags m_nIncludeEvents; // events to include + BAFlags m_nIncludeBindings; // binding attributes to include + + std::unique_ptr m_pOuterElement; // XML element doing the concrete startElement etc. for the outer element + + public: + /** constructs an object capable of exporting controls + +

You need at least two pre-requisites from outside: The control to be exported needs to have a class id + assigned, and you need the list control-ids of all the controls referring to this one as LabelControl.
+ This information can't be collected when known only the control itself and not it's complete context.

+ + @param _rControlId + the control id to use when exporting the control + @param _rReferringControls + the comma-separated list of control-ids of all the controls referring to this one as LabelControl + */ + OControlExport(IFormsExportContext& _rContext, + const css::uno::Reference< css::beans::XPropertySet >& _rxControl, + const OUString& _rControlId, + const OUString& _rReferringControls, + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rxEvents); + + protected: + /// start the XML element + virtual void implStartElement(const char* _pName) override; + + /// ends the XML element + virtual void implEndElement() override; + + /// get the name of the outer XML element + virtual const char* getOuterXMLElementName() const; + + // get the name of the XML element + virtual const char* getXMLElementName() const override; + + /** examine the control. Some kind of CtorImpl. + */ + virtual void examine() override; + + /// exports the attributes for the outer element + void exportOuterAttributes(); + + /// exports the attributes for the inner element + void exportInnerAttributes(); + + /// export the attributes + virtual void exportAttributes() override; + + /** writes everything which needs to be represented as sub tag + */ + void exportSubTags() override; + + /** adds the attributes which are handled via generic IPropertyHandlers + +

In the future, this really should be *all* attributes, instead of this shitload of + hand-crafted code we have currently...

+ */ + void exportGenericHandlerAttributes(); + + /** adds common control attributes to the XMLExport context given + +

The attribute list of the context is not cleared initially, this is the responsibility of the caller.

+ */ + void exportCommonControlAttributes(); + + /** adds database attributes to the XMLExport context given + +

The attribute list of the context is not cleared initially, this is the responsibility of the caller.

+ */ + void exportDatabaseAttributes(); + + /** adds the XML attributes which are related to binding controls to + external values and/or list sources + */ + void exportBindingAttributes(); + + /** adds attributes which are special to a control type to the export context's attribute list + */ + void exportSpecialAttributes(); + + /** exports the ListSource property of a control as attribute + + The ListSource property may be exported in different ways: For a ComboBox, it is an attribute + of the form:combobox element. + + For a ListBox, it's an attribute if the ListSourceType states that the ListBox does not + display a value list. In case of a value list, the ListSource is not exported, and the pairs of + StringItem/ValueItem are exported as sub-elements. + + This method does the attribute part: It exports the ListSource property as attribute, not caring + about whether the object is a ComboBox or a ListBox. + */ + void exportListSourceAsAttribute(); + + /** exports the ListSource property of a control as XML elements + + @see exportListSourceAsAttribute + */ + void exportListSourceAsElements(); + + /** gets a Sequence< sal_Int16 > property value as set of sal_Int16's + @param _rPropertyName + the property name to use + @param _rOut + out parameter. The set of integers. + */ + void getSequenceInt16PropertyAsSet(const OUString& _rPropertyName, Int16Set& _rOut); + + /** exports the attribute which descrives a cell value binding of a control + in a spreadsheet document + */ + void exportCellBindingAttributes( bool _bIncludeListLinkageType ); + + /** exports the attribute(s) which bind this control to XForms */ + void exportXFormsBindAttributes(); + + /** exports the attribute(s) which bind the list of a list + control to XForms */ + void exportXFormsListAttributes(); + + /** exports the attribute(s) for an XForms submission */ + void exportXFormsSubmissionAttributes(); + + /** exports the attribute which descrives a cell range which acts as list source for + a list-like control + */ + void exportCellListSourceRange( ); + + /** exports the attribute(s) for the ImagePosition property + */ + void exportImagePositionAttributes(); + + /** determines whether the control we're exporting has an active data binding. + + Bindings which count here are: +
  • an established connection to a database field
  • +
  • a binding to an external value supplier (XValueBinding)
  • +
+ */ + bool controlHasActiveDataBinding() const; + + /** retrieves the string specifying the ListSource of a list or combo box + */ + OUString getScalarListSourceValue() const; + + /** determines whether the list entries (of a combo or list box) are supplied by the user + + List entries may be +
  • specified by the user
  • +
  • specified by an external list source (XListEntrySource)
  • +
  • obtained from a database query (in various ways)
  • +
+ + In the latter two cases, this method will return + */ + bool controlHasUserSuppliedListEntries() const; + }; + + //= OColumnExport + /** Helper class for exporting a grid column + */ + class OColumnExport : public OControlExport + { + public: + /** ctor + @see OColumnExport::OColumnExport + */ + OColumnExport(IFormsExportContext& _rContext, + const css::uno::Reference< css::beans::XPropertySet >& _rxControl, + const OUString& _rControlId, + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rxEvents); + + virtual ~OColumnExport() override; + + protected: + // OControlExport overridables + virtual const char* getOuterXMLElementName() const override; + virtual void exportServiceNameAttribute() override; + virtual void exportAttributes() override; + + // OElementExport overridables + virtual void examine() override; + }; + + //= OFormExport + /** Helper class for handling xml elements representing a form + +

In opposite to the class OControlExport, OFormExport is unable to export a complete + form. Instead the client has to care for sub elements of the form itself.

+ */ + class OFormExport + :public OControlElement + ,public OElementExport + { + bool m_bCreateConnectionResourceElement; + public: + /** constructs an object capable of exporting controls + */ + OFormExport(IFormsExportContext& _rContext, + const css::uno::Reference< css::beans::XPropertySet >& _rxForm, + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rxEvents + ); + + protected: + virtual const char* getXMLElementName() const override; + virtual void exportSubTags() override; + virtual void exportAttributes() override; + }; +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/elementimport.cxx b/xmloff/source/forms/elementimport.cxx new file mode 100644 index 000000000..19f247aae --- /dev/null +++ b/xmloff/source/forms/elementimport.cxx @@ -0,0 +1,2073 @@ +/* -*- 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 "elementimport.hxx" +#include +#include +#include "strings.hxx" +#include "callbacks.hxx" +#include +#include "eventimport.hxx" +#include +#include "formenums.hxx" +#include +#include "gridcolumnproptranslator.hxx" +#include "property_description.hxx" +#include "property_meta_data.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace xmloff +{ + + using namespace ::xmloff::token; + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::xml; + using namespace ::com::sun::star::xml::sax; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::text; + using namespace ::comphelper; + using ::com::sun::star::xml::sax::XAttributeList; + +#define PROPID_VALUE 1 +#define PROPID_CURRENT_VALUE 2 +#define PROPID_MIN_VALUE 3 +#define PROPID_MAX_VALUE 4 + + namespace { + + struct PropertyValueLess + { + bool operator()(const PropertyValue& _rLeft, const PropertyValue& _rRight) + { + return _rLeft.Name < _rRight.Name; + } + }; + + } + + //= OElementNameMap + std::map OElementNameMap::s_sElementTranslations2; + + const OControlElement::ElementType& operator ++(OControlElement::ElementType& _e) + { + OControlElement::ElementType e = _e; + sal_Int32 nAsInt = static_cast(e); + _e = static_cast( ++nAsInt ); + return _e; + } + + OControlElement::ElementType OElementNameMap::getElementType(sal_Int32 nElement) + { + if ( s_sElementTranslations2.empty() ) + { // initialize + for (ElementType eType=ElementType(0); eTypesecond; + + return UNKNOWN; + } + + //= OElementImport + OElementImport::OElementImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer) + :OPropertyImport(_rImport) + ,m_rFormImport(_rImport) + ,m_rEventManager(_rEventManager) + ,m_pStyleElement( nullptr ) + ,m_xParentContainer(_rxParentContainer) + ,m_bImplicitGenericAttributeHandling( true ) + { + OSL_ENSURE(m_xParentContainer.is(), "OElementImport::OElementImport: invalid parent container!"); + } + + OElementImport::~OElementImport() + { + } + + OUString OElementImport::determineDefaultServiceName() const + { + return OUString(); + } + + void OElementImport::startFastElement(sal_Int32 nElement, const Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) + { + ENTER_LOG_CONTEXT( "xmloff::OElementImport - importing one element" ); + + const OUString sControlImplementation = _rxAttrList->getOptionalValue( XML_ELEMENT(FORM, XML_CONTROL_IMPLEMENTATION) ); + + // retrieve the service name + if ( !sControlImplementation.isEmpty() ) + { + OUString sOOoImplementationName; + const sal_uInt16 nImplPrefix = GetImport().GetNamespaceMap().GetKeyByAttrValueQName( sControlImplementation, &sOOoImplementationName ); + m_sServiceName = ( nImplPrefix == XML_NAMESPACE_OOO ) ? sOOoImplementationName : sControlImplementation; + } + + if ( m_sServiceName.isEmpty() ) + m_sServiceName = determineDefaultServiceName(); + + // create the object *now*. This allows setting properties in the various handleAttribute methods. + // (Though currently not all code is migrated to this pattern, most attributes are still handled + // by remembering the value (via implPushBackPropertyValue), and setting the correct property value + // later (in OControlImport::StartElement).) + m_xElement = createElement(); + if ( m_xElement.is() ) + m_xInfo = m_xElement->getPropertySetInfo(); + + // call the base class + OPropertyImport::startFastElement( nElement, _rxAttrList ); + } + + css::uno::Reference< css::xml::sax::XFastContextHandler > OElementImport::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList ) + { + if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + return new OFormEventsImportContext(m_rFormImport.getGlobalContext(), *this); + + return OPropertyImport::createFastChildContext(nElement, _rxAttrList); + } + + void OElementImport::endFastElement(sal_Int32 ) + { + OSL_ENSURE(m_xElement.is(), "OElementImport::EndElement: invalid element created!"); + if (!m_xElement.is()) + return; + + // apply the non-generic properties + implApplySpecificProperties(); + + // set the generic properties + implApplyGenericProperties(); + + // set the style properties + if ( m_pStyleElement && m_xElement.is() ) + { + Reference< XPropertySet > xPropTranslation = + new OGridColumnPropertyTranslator( Reference< XMultiPropertySet >( m_xElement, UNO_QUERY ) ); + const_cast< XMLTextStyleContext* >( m_pStyleElement )->FillPropertySet( xPropTranslation ); + + const OUString sNumberStyleName = m_pStyleElement->GetDataStyleName( ); + if ( !sNumberStyleName.isEmpty() ) + // the style also has a number (sub) style + m_rContext.applyControlNumberStyle( m_xElement, sNumberStyleName ); + } + + // insert the element into the parent container + if (m_sName.isEmpty()) + { + OSL_FAIL("OElementImport::EndElement: did not find a name attribute!"); + m_sName = implGetDefaultName(); + } + + if (m_xParentContainer.is()) + m_xParentContainer->insertByName(m_sName, Any(m_xElement)); + + LEAVE_LOG_CONTEXT( ); + } + + void OElementImport::implApplySpecificProperties() + { + if ( m_aValues.empty() ) + return; + + // set all the properties we collected +#if OSL_DEBUG_LEVEL > 0 + // check if the object has all the properties + // (We do this in the non-pro version only. Doing it all the time would be too much expensive) + if ( m_xInfo.is() ) + { + for ( const auto& rCheck : m_aValues ) + { + OSL_ENSURE(m_xInfo->hasPropertyByName(rCheck.Name), + OStringBuffer("OElementImport::implApplySpecificProperties: read a property (" + + OUStringToOString(rCheck.Name, RTL_TEXTENCODING_ASCII_US) + + ") which does not exist on the element!").getStr()); + } + } +#endif + + // set the properties + const Reference< XMultiPropertySet > xMultiProps(m_xElement, UNO_QUERY); + bool bSuccess = false; + if (xMultiProps.is()) + { + // translate our properties so that the XMultiPropertySet can handle them + + // sort our property value array so that we can use it in a setPropertyValues + ::std::sort( m_aValues.begin(), m_aValues.end(), PropertyValueLess()); + + // the names + Sequence< OUString > aNames(m_aValues.size()); + OUString* pNames = aNames.getArray(); + // the values + Sequence< Any > aValues(m_aValues.size()); + Any* pValues = aValues.getArray(); + // copy + + for ( const auto& rPropValues : m_aValues ) + { + *pNames = rPropValues.Name; + *pValues = rPropValues.Value; + ++pNames; + ++pValues; + } + + try + { + xMultiProps->setPropertyValues(aNames, aValues); + bSuccess = true; + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.forms"); + OSL_FAIL("OElementImport::implApplySpecificProperties: could not set the properties (using the XMultiPropertySet)!"); + } + } + + if (bSuccess) + return; + + // no XMultiPropertySet or setting all properties at once failed + for ( const auto& rPropValues : m_aValues ) + { + // this try/catch here is expensive, but because this is just a fallback which should normally not be + // used it's acceptable this way ... + try + { + m_xElement->setPropertyValue(rPropValues.Name, rPropValues.Value); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.forms"); + OSL_FAIL(OStringBuffer("OElementImport::implApplySpecificProperties: could not set the property \"" + + OUStringToOString(rPropValues.Name, RTL_TEXTENCODING_ASCII_US) + + "\"!").getStr()); + } + } + } + + void OElementImport::implApplyGenericProperties() + { + if ( m_aGenericValues.empty() ) + return; + + Reference< XPropertyContainer > xDynamicProperties( m_xElement, UNO_QUERY ); + + // PropertyValueArray::iterator aEnd = m_aGenericValues.end(); + for ( auto& rPropValues : m_aGenericValues ) + { + // check property type for numeric types before setting + // the property + try + { + // if such a property does not yet exist at the element, create it if necessary + const bool bExistentProperty = m_xInfo->hasPropertyByName( rPropValues.Name ); + if ( !bExistentProperty ) + { + if ( !xDynamicProperties.is() ) + { + SAL_WARN( "xmloff", "OElementImport::implApplyGenericProperties: encountered an unknown property (" + << rPropValues.Name << "), but component is no PropertyBag!"); + continue; + } + + xDynamicProperties->addProperty( + rPropValues.Name, + PropertyAttribute::BOUND | PropertyAttribute::REMOVABLE, + rPropValues.Value + ); + + // re-fetch the PropertySetInfo + m_xInfo = m_xElement->getPropertySetInfo(); + } + + // determine the type of the value (source for the following conversion) + TypeClass eValueTypeClass = rPropValues.Value.getValueTypeClass(); + const bool bValueIsSequence = TypeClass_SEQUENCE == eValueTypeClass; + if ( bValueIsSequence ) + { + uno::Type aSimpleType( getSequenceElementType( rPropValues.Value.getValueType() ) ); + eValueTypeClass = aSimpleType.getTypeClass(); + } + + // determine the type of the property (target for the following conversion) + const Property aProperty( m_xInfo->getPropertyByName( rPropValues.Name ) ); + TypeClass ePropTypeClass = aProperty.Type.getTypeClass(); + const bool bPropIsSequence = TypeClass_SEQUENCE == ePropTypeClass; + if( bPropIsSequence ) + { + uno::Type aSimpleType( ::comphelper::getSequenceElementType( aProperty.Type ) ); + ePropTypeClass = aSimpleType.getTypeClass(); + } + + if ( bPropIsSequence != bValueIsSequence ) + { + OSL_FAIL( "OElementImport::implImportGenericProperties: either both value and property should be a sequence, or none of them!" ); + continue; + } + + if ( bValueIsSequence ) + { + Sequence< Any > aXMLValueList; + rPropValues.Value >>= aXMLValueList; + // just skip this part if empty sequence + if (!aXMLValueList.getLength()) + continue; + + Sequence< sal_Int16 > aPropertyValueList( aXMLValueList.getLength() ); + + SAL_WARN_IF( eValueTypeClass != TypeClass_ANY, "xmloff", + "OElementImport::implApplyGenericProperties: only ANYs should have been imported as generic list property!" ); + // (OPropertyImport should produce only Sequencer< Any >, since it cannot know the real type + + SAL_WARN_IF( ePropTypeClass != TypeClass_SHORT, "xmloff", + "OElementImport::implApplyGenericProperties: conversion to sequences other than 'sequence< short >' not implemented, yet!" ); + + + std::transform(std::cbegin(aXMLValueList), std::cend(aXMLValueList), aPropertyValueList.getArray(), + [](const Any& rXMLValue) -> sal_Int16 { + // only value sequences of numeric types implemented so far. + double nVal( 0 ); + OSL_VERIFY( rXMLValue >>= nVal ); + return static_cast< sal_Int16 >( nVal ); + }); + + rPropValues.Value <<= aPropertyValueList; + } + else if ( ePropTypeClass != eValueTypeClass ) + { + switch ( eValueTypeClass ) + { + case TypeClass_DOUBLE: + { + double nVal = 0; + rPropValues.Value >>= nVal; + switch( ePropTypeClass ) + { + case TypeClass_BYTE: + rPropValues.Value <<= static_cast< sal_Int8 >( nVal ); + break; + case TypeClass_SHORT: + rPropValues.Value <<= static_cast< sal_Int16 >( nVal ); + break; + case TypeClass_UNSIGNED_SHORT: + rPropValues.Value <<= static_cast< sal_uInt16 >( nVal ); + break; + case TypeClass_LONG: + case TypeClass_ENUM: + rPropValues.Value <<= static_cast< sal_Int32 >( nVal ); + break; + case TypeClass_UNSIGNED_LONG: + rPropValues.Value <<= static_cast< sal_uInt32 >( nVal ); + break; + case TypeClass_UNSIGNED_HYPER: + rPropValues.Value <<= static_cast< sal_uInt64 >( nVal ); + break; + case TypeClass_HYPER: + rPropValues.Value <<= static_cast< sal_Int64 >( nVal ); + break; + default: + OSL_FAIL( "OElementImport::implImportGenericProperties: unsupported value type!" ); + break; + } + } + break; + default: + OSL_FAIL( "OElementImport::implImportGenericProperties: non-double values not supported!" ); + break; + } + } + + m_xElement->setPropertyValue( rPropValues.Name, rPropValues.Value ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.forms"); + OSL_FAIL(OStringBuffer("OElementImport::EndElement: could not set the property \"" + + OUStringToOString(rPropValues.Name, RTL_TEXTENCODING_ASCII_US) + + "\"!").getStr()); + } + } + } + + OUString OElementImport::implGetDefaultName() const + { + // no optimization here. If this method gets called, the XML stream did not contain a name for the + // element, which is a heavy error. So in this case we don't care for performance + static constexpr OUStringLiteral sUnnamedName = u"unnamed"; + OSL_ENSURE(m_xParentContainer.is(), "OElementImport::implGetDefaultName: no parent container!"); + if (!m_xParentContainer.is()) + return sUnnamedName; + Sequence< OUString > aNames = m_xParentContainer->getElementNames(); + + for (sal_Int32 i=0; i<32768; ++i) // the limit is nearly arbitrary... + { + // assemble the new name (suggestion) + OUString sReturn = sUnnamedName + OUString::number(i); + // check the existence (this is the bad performance part...) + if (comphelper::findValue(aNames, sReturn) == -1) + // not found the name + return sReturn; + } + OSL_FAIL("OElementImport::implGetDefaultName: did not find a free name!"); + return sUnnamedName; + } + + PropertyGroups::const_iterator OElementImport::impl_matchPropertyGroup( const PropertyGroups& i_propertyGroups ) const + { + ENSURE_OR_RETURN( m_xInfo.is(), "OElementImport::impl_matchPropertyGroup: no property set info!", i_propertyGroups.end() ); + + return std::find_if(i_propertyGroups.cbegin(), i_propertyGroups.cend(), [&](const PropertyDescriptionList& rGroup) { + return std::all_of(rGroup.cbegin(), rGroup.cend(), [&](const PropertyDescription* prop) { + return m_xInfo->hasPropertyByName( prop->propertyName ); + }); + }); + } + + bool OElementImport::tryGenericAttribute( sal_Int32 nElement, const OUString& _rValue ) + { + // the generic approach (which I hope all props will be migrated to, on the medium term): property handlers + const AttributeDescription attribute( metadata::getAttributeDescription( nElement ) ); + if ( attribute.attributeToken != XML_TOKEN_INVALID ) + { + PropertyGroups propertyGroups; + metadata::getPropertyGroupList( attribute, propertyGroups ); + const PropertyGroups::const_iterator pos = impl_matchPropertyGroup( propertyGroups ); + if ( pos == propertyGroups.end() ) + return false; + + do + { + const PropertyDescriptionList& rProperties( *pos ); + const PropertyDescription* first = *rProperties.begin(); + if ( !first ) + { + SAL_WARN( "xmloff.forms", "OElementImport::handleAttribute: invalid property description!" ); + break; + } + + const PPropertyHandler handler = (*first->factory)( first->propertyId ); + if ( !handler ) + { + SAL_WARN( "xmloff.forms", "OElementImport::handleAttribute: invalid property handler!" ); + break; + } + + PropertyValues aValues; + for ( const auto& propDesc : rProperties ) + { + aValues[ propDesc->propertyId ] = Any(); + } + if ( handler->getPropertyValues( _rValue, aValues ) ) + { + for ( const auto& propDesc : rProperties ) + { + implPushBackPropertyValue( propDesc->propertyName, aValues[ propDesc->propertyId ] ); + } + } + } + while ( false ); + + // handled + return true; + } + return false; + } + + bool OElementImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) + { + auto nLocal = nElement & TOKEN_MASK; + if ( nLocal == XML_CONTROL_IMPLEMENTATION ) + // ignore this, it has already been handled in OElementImport::StartElement + return true; + + if ( nLocal == XML_NAME ) + { + if ( m_sName.isEmpty() ) + // remember the name for later use in EndElement + m_sName = _rValue; + return true; + } + + // maybe it's the style attribute? + if ( nLocal == XML_TEXT_STYLE_NAME ) + { + const SvXMLStyleContext* pStyleContext = m_rContext.getStyleElement( _rValue ); + OSL_ENSURE( pStyleContext, "OElementImport::handleAttribute: do not know the style!" ); + // remember the element for later usage. + m_pStyleElement = dynamic_cast( pStyleContext ); + return true; + } + + if ( m_bImplicitGenericAttributeHandling ) + if ( tryGenericAttribute( nElement, _rValue ) ) + return true; + + // let the base class handle it + return OPropertyImport::handleAttribute( nElement, _rValue); + } + + Reference< XPropertySet > OElementImport::createElement() + { + Reference< XPropertySet > xReturn; + if (!m_sServiceName.isEmpty()) + { + Reference< XComponentContext > xContext = m_rFormImport.getGlobalContext().GetComponentContext(); + Reference< XInterface > xPure = xContext->getServiceManager()->createInstanceWithContext(m_sServiceName, xContext); + OSL_ENSURE(xPure.is(), + OStringBuffer("OElementImport::createElement: service factory gave me no object (service name: " + + OUStringToOString(m_sServiceName, RTL_TEXTENCODING_ASCII_US) + + ")!").getStr()); + xReturn.set(xPure, UNO_QUERY); + } + else + OSL_FAIL("OElementImport::createElement: no service name to create an element!"); + + return xReturn; + } + + void OElementImport::registerEvents(const Sequence< ScriptEventDescriptor >& _rEvents) + { + OSL_ENSURE(m_xElement.is(), "OElementImport::registerEvents: no element to register events for!"); + m_rEventManager.registerEvents(m_xElement, _rEvents); + } + + void OElementImport::simulateDefaultedAttribute(sal_Int32 nElement, const OUString& _rPropertyName, const char* _pAttributeDefault) + { + OSL_ENSURE( m_xInfo.is(), "OPropertyImport::simulateDefaultedAttribute: the component should be more gossipy about it's properties!" ); + + if ( !m_xInfo.is() || m_xInfo->hasPropertyByName( _rPropertyName ) ) + { + if ( !encounteredAttribute( nElement ) ) + OSL_VERIFY( handleAttribute( XML_ELEMENT(FORM, (nElement & TOKEN_MASK)), OUString::createFromAscii( _pAttributeDefault ) ) ); + } + } + + //= OControlImport + OControlImport::OControlImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer) + :OElementImport(_rImport, _rEventManager, _rxParentContainer) + ,m_eElementType(OControlElement::UNKNOWN) + { + disableImplicitGenericAttributeHandling(); + } + + OControlImport::OControlImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType) + :OElementImport(_rImport, _rEventManager, _rxParentContainer) + ,m_eElementType(_eType) + { + disableImplicitGenericAttributeHandling(); + } + + OUString OControlImport::determineDefaultServiceName() const + { + const char* pServiceName = nullptr; + switch ( m_eElementType ) + { + case OControlElement::TEXT: + case OControlElement::TEXT_AREA: + case OControlElement::PASSWORD: pServiceName = "com.sun.star.form.component.TextField"; break; + case OControlElement::FILE: pServiceName = "com.sun.star.form.component.FileControl"; break; + case OControlElement::FORMATTED_TEXT: pServiceName = "com.sun.star.form.component.FormattedField"; break; + case OControlElement::FIXED_TEXT: pServiceName = "com.sun.star.form.component.FixedText"; break; + case OControlElement::COMBOBOX: pServiceName = "com.sun.star.form.component.ComboBox"; break; + case OControlElement::LISTBOX: pServiceName = "com.sun.star.form.component.ListBox"; break; + case OControlElement::BUTTON: pServiceName = "com.sun.star.form.component.CommandButton"; break; + case OControlElement::IMAGE: pServiceName = "com.sun.star.form.component.ImageButton"; break; + case OControlElement::CHECKBOX: pServiceName = "com.sun.star.form.component.CheckBox"; break; + case OControlElement::RADIO: pServiceName = "com.sun.star.form.component.RadioButton"; break; + case OControlElement::FRAME: pServiceName = "com.sun.star.form.component.GroupBox"; break; + case OControlElement::IMAGE_FRAME: pServiceName = "com.sun.star.form.component.DatabaseImageControl"; break; + case OControlElement::HIDDEN: pServiceName = "com.sun.star.form.component.HiddenControl"; break; + case OControlElement::GRID: pServiceName = "com.sun.star.form.component.GridControl"; break; + case OControlElement::VALUERANGE: pServiceName = "com.sun.star.form.component.ScrollBar"; break; + case OControlElement::TIME: pServiceName = "com.sun.star.form.component.TimeField"; break; + case OControlElement::DATE: pServiceName = "com.sun.star.form.component.DateField"; break; + default: break; + } + if ( pServiceName != nullptr ) + return OUString::createFromAscii( pServiceName ); + return OUString(); + } + + void OControlImport::addOuterAttributes(const Reference< XFastAttributeList >& _rxOuterAttribs) + { + OSL_ENSURE(!m_xOuterAttributes.is(), "OControlImport::addOuterAttributes: already have these attributes!"); + m_xOuterAttributes = _rxOuterAttribs; + } + + bool OControlImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) + { + static sal_Int32 nLinkedCellAttributeName = OAttributeMetaData::getBindingAttributeToken(BAFlags::LinkedCell); + + if ((nElement & TOKEN_MASK) == XML_ID) + { // it's the control id + if (IsTokenInNamespace(nElement, XML_NAMESPACE_XML)) + { + m_sControlId = _rValue; + } + else if (IsTokenInNamespace(nElement, XML_NAMESPACE_FORM)) + { + if (m_sControlId.isEmpty()) + { + m_sControlId = _rValue; + } + } + return true; + } + + if ( (nElement & TOKEN_MASK) == nLinkedCellAttributeName ) + { // it's the address of a spreadsheet cell + m_sBoundCellAddress = _rValue; + return true; + } + + if ( nElement == XML_ELEMENT(XFORMS, XML_BIND ) ) + { + m_sBindingID = _rValue; + return true; + } + + if ( nElement == XML_ELEMENT(FORM, XML_XFORMS_LIST_SOURCE) ) + { + m_sListBindingID = _rValue; + return true; + } + + if ( nElement == XML_ELEMENT(FORM, XML_XFORMS_SUBMISSION) + || nElement == XML_ELEMENT(XFORMS, XML_SUBMISSION) ) + { + m_sSubmissionID = _rValue; + return true; + } + + if ( OElementImport::tryGenericAttribute( nElement, _rValue ) ) + return true; + + static const sal_Int32 nValueAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Value); + static const sal_Int32 nCurrentValueAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentValue); + static const sal_Int32 nMinValueAttributeName = OAttributeMetaData::getSpecialAttributeToken(SCAFlags::MinValue); + static const sal_Int32 nMaxValueAttributeName = OAttributeMetaData::getSpecialAttributeToken(SCAFlags::MaxValue); + static const sal_Int32 nRepeatDelayAttributeName = OAttributeMetaData::getSpecialAttributeToken( SCAFlags::RepeatDelay ); + + sal_Int32 nHandle = -1; + if ( (nElement & TOKEN_MASK) == nValueAttributeName ) + nHandle = PROPID_VALUE; + else if ( (nElement & TOKEN_MASK) == nCurrentValueAttributeName ) + nHandle = PROPID_CURRENT_VALUE; + else if ( (nElement & TOKEN_MASK) == nMinValueAttributeName ) + nHandle = PROPID_MIN_VALUE; + else if ( (nElement & TOKEN_MASK) == nMaxValueAttributeName ) + nHandle = PROPID_MAX_VALUE; + if ( nHandle != -1 ) + { + // for the moment, simply remember the name and the value + PropertyValue aProp; + aProp.Name = SvXMLImport::getNameFromToken(nElement); + aProp.Handle = nHandle; + aProp.Value <<= _rValue; + m_aValueProperties.push_back(aProp); + return true; + } + + if ( (nElement & TOKEN_MASK) == nRepeatDelayAttributeName ) + { + util::Duration aDuration; + if (::sax::Converter::convertDuration(aDuration, _rValue)) + { + PropertyValue aProp; + aProp.Name = PROPERTY_REPEAT_DELAY; + sal_Int32 const nMS = + ((aDuration.Hours * 60 + aDuration.Minutes) * 60 + + aDuration.Seconds) * 1000 + aDuration.NanoSeconds/1000000; + aProp.Value <<= nMS; + + implPushBackPropertyValue(aProp); + } + return true; + } + + return OElementImport::handleAttribute( nElement, _rValue ); + } + + void OControlImport::startFastElement(sal_Int32 nElement, const Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) + { + css::uno::Reference< css::xml::sax::XFastAttributeList > xMergedAttributes; + if( m_xOuterAttributes.is() ) + { + // merge the attribute lists, our own one + rtl::Reference xMerger(new sax_fastparser::FastAttributeList(_rxAttrList)); + // and the ones of our enclosing element + xMerger->add(m_xOuterAttributes); + xMergedAttributes = xMerger.get(); + } + else + { + xMergedAttributes = _rxAttrList; + } + + // let the base class handle all the attributes + OElementImport::startFastElement(nElement, xMergedAttributes); + + if ( m_aValueProperties.empty() || !m_xElement.is()) + return; + + // get the property set info + if (!m_xInfo.is()) + { + OSL_FAIL("OControlImport::StartElement: no PropertySetInfo!"); + return; + } + + const char* pValueProperty = nullptr; + const char* pCurrentValueProperty = nullptr; + const char* pMinValueProperty = nullptr; + const char* pMaxValueProperty = nullptr; + + bool bRetrievedValues = false; + bool bRetrievedValueLimits = false; + + // get the class id of our element + sal_Int16 nClassId = FormComponentType::CONTROL; + m_xElement->getPropertyValue(PROPERTY_CLASSID) >>= nClassId; + + // translate the value properties we collected in handleAttributes + for ( auto& rValueProps : m_aValueProperties ) + { + bool bSuccess = false; + switch (rValueProps.Handle) + { + case PROPID_VALUE: + case PROPID_CURRENT_VALUE: + { + // get the property names + if (!bRetrievedValues) + { + getValuePropertyNames(m_eElementType, nClassId, pCurrentValueProperty, pValueProperty); + if ( !pCurrentValueProperty && !pValueProperty ) + { + SAL_WARN( "xmloff.forms", "OControlImport::StartElement: illegal value property names!" ); + break; + } + + bRetrievedValues = true; + } + if ( PROPID_VALUE == rValueProps.Handle && !pValueProperty ) + { + SAL_WARN( "xmloff.forms", "OControlImport::StartElement: the control does not have a value property!"); + break; + } + + if ( PROPID_CURRENT_VALUE == rValueProps.Handle && !pCurrentValueProperty ) + { + SAL_WARN( "xmloff.forms", "OControlImport::StartElement: the control does not have a current-value property!"); + break; + } + + // transfer the name + if (PROPID_VALUE == rValueProps.Handle) + rValueProps.Name = OUString::createFromAscii(pValueProperty); + else + rValueProps.Name = OUString::createFromAscii(pCurrentValueProperty); + bSuccess = true; + } + break; + case PROPID_MIN_VALUE: + case PROPID_MAX_VALUE: + { + // get the property names + if (!bRetrievedValueLimits) + { + getValueLimitPropertyNames(nClassId, pMinValueProperty, pMaxValueProperty); + if ( !pMinValueProperty || !pMaxValueProperty ) + { + SAL_WARN( "xmloff.forms", "OControlImport::StartElement: illegal value limit property names!" ); + break; + } + + bRetrievedValueLimits = true; + } + OSL_ENSURE((PROPID_MIN_VALUE != rValueProps.Handle) || pMinValueProperty, + "OControlImport::StartElement: the control does not have a value property!"); + OSL_ENSURE((PROPID_MAX_VALUE != rValueProps.Handle) || pMaxValueProperty, + "OControlImport::StartElement: the control does not have a current-value property!"); + + // transfer the name + if (PROPID_MIN_VALUE == rValueProps.Handle) + rValueProps.Name = OUString::createFromAscii(pMinValueProperty); + else + rValueProps.Name = OUString::createFromAscii(pMaxValueProperty); + bSuccess = true; + } + break; + } + + if ( !bSuccess ) + continue; + + // translate the value + implTranslateValueProperty(m_xInfo, rValueProps); + // add the property to the base class' array + implPushBackPropertyValue(rValueProps); + } + + } + + void OControlImport::implTranslateValueProperty(const Reference< XPropertySetInfo >& _rxPropInfo, + PropertyValue& _rPropValue) + { + OSL_ENSURE(_rxPropInfo->hasPropertyByName(_rPropValue.Name), + "OControlImport::implTranslateValueProperty: invalid property name!"); + + // retrieve the type of the property + Property aProp = _rxPropInfo->getPropertyByName(_rPropValue.Name); + // the untranslated string value as read in handleAttribute + OUString sValue; + bool bSuccess = _rPropValue.Value >>= sValue; + OSL_ENSURE(bSuccess, "OControlImport::implTranslateValueProperty: supposed to be called with non-translated string values!"); + + if (TypeClass_ANY == aProp.Type.getTypeClass()) + { + // we have exactly 2 properties where this type class is allowed: + SAL_WARN_IF( + _rPropValue.Name != PROPERTY_EFFECTIVE_VALUE + && _rPropValue.Name != PROPERTY_EFFECTIVE_DEFAULT, "xmloff", + "OControlImport::implTranslateValueProperty: invalid property type/name combination, Any and " << _rPropValue.Name); + + // Both properties are allowed to have a double or a string value, + // so first try to convert the string into a number + double nValue; + if (::sax::Converter::convertDouble(nValue, sValue)) + _rPropValue.Value <<= nValue; + else + _rPropValue.Value <<= sValue; + } + else + _rPropValue.Value = PropertyConversion::convertString(aProp.Type, sValue); + } + + void OControlImport::endFastElement(sal_Int32 nElement) + { + OSL_ENSURE(m_xElement.is(), "OControlImport::EndElement: invalid control!"); + if ( !m_xElement.is() ) + return; + + // register our control with its id + if (!m_sControlId.isEmpty()) + m_rFormImport.registerControlId(m_xElement, m_sControlId); + // it's allowed to have no control id. In this case we're importing a column + + // one more pre-work to do: + // when we set default values, then by definition the respective value is set + // to this default value, too. This means if the sequence contains for example + // a DefaultText value, then the Text will be affected by this, too. + // In case the Text is not part of the property sequence (or occurs _before_ + // the DefaultText, which can happen for other value/default-value property names), + // this means that the Text (the value property) is incorrectly imported. + + bool bRestoreValuePropertyValue = false; + Any aValuePropertyValue; + + sal_Int16 nClassId = FormComponentType::CONTROL; + try + { + // get the class id of our element + m_xElement->getPropertyValue(PROPERTY_CLASSID) >>= nClassId; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.forms", + "caught an exception while retrieving the class id!"); + } + + const char* pValueProperty = nullptr; + const char* pDefaultValueProperty = nullptr; + getRuntimeValuePropertyNames(m_eElementType, nClassId, pValueProperty, pDefaultValueProperty); + if ( pDefaultValueProperty && pValueProperty ) + { + bool bNonDefaultValuePropertyValue = false; + // is the "value property" part of the sequence? + + // look up this property in our sequence + for ( const auto& rCheck : m_aValues ) + { + if ( rCheck.Name.equalsAscii( pDefaultValueProperty ) ) + bRestoreValuePropertyValue = true; + else if ( rCheck.Name.equalsAscii( pValueProperty ) ) + { + bNonDefaultValuePropertyValue = true; + // we need to restore the value property we found here, nothing else + aValuePropertyValue = rCheck.Value; + } + } + + if ( bRestoreValuePropertyValue && !bNonDefaultValuePropertyValue ) + { + // found it -> need to remember (and restore) the "value property value", which is not set explicitly + try + { + aValuePropertyValue = m_xElement->getPropertyValue( OUString::createFromAscii( pValueProperty ) ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( + "xmloff.forms", + "caught an exception while retrieving the current value property!"); + } + } + } + + // let the base class set all the values + OElementImport::endFastElement(nElement); + + // restore the "value property value", if necessary + if ( bRestoreValuePropertyValue && pValueProperty ) + { + try + { + m_xElement->setPropertyValue( OUString::createFromAscii( pValueProperty ), aValuePropertyValue ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.forms", + "caught an exception while restoring the value property!"); + } + } + + // the external cell binding, if applicable + if ( m_xElement.is() && !m_sBoundCellAddress.isEmpty() ) + doRegisterCellValueBinding( m_sBoundCellAddress ); + + // XForms binding, if applicable + if ( m_xElement.is() && !m_sBindingID.isEmpty() ) + doRegisterXFormsValueBinding( m_sBindingID ); + + // XForms list binding, if applicable + if ( m_xElement.is() && !m_sListBindingID.isEmpty() ) + doRegisterXFormsListBinding( m_sListBindingID ); + + // XForms submission, if applicable + if ( m_xElement.is() && !m_sSubmissionID.isEmpty() ) + doRegisterXFormsSubmission( m_sSubmissionID ); + } + + void OControlImport::doRegisterCellValueBinding( const OUString& _rBoundCellAddress ) + { + OSL_PRECOND( m_xElement.is(), "OControlImport::doRegisterCellValueBinding: invalid element!" ); + OSL_PRECOND( !_rBoundCellAddress.isEmpty(), + "OControlImport::doRegisterCellValueBinding: invalid address!" ); + + m_rContext.registerCellValueBinding( m_xElement, _rBoundCellAddress ); + } + + void OControlImport::doRegisterXFormsValueBinding( const OUString& _rBindingID ) + { + OSL_PRECOND( m_xElement.is(), "need element" ); + OSL_PRECOND( !_rBindingID.isEmpty(), "binding ID is not valid" ); + + m_rContext.registerXFormsValueBinding( m_xElement, _rBindingID ); + } + + void OControlImport::doRegisterXFormsListBinding( const OUString& _rBindingID ) + { + OSL_PRECOND( m_xElement.is(), "need element" ); + OSL_PRECOND( !_rBindingID.isEmpty(), "binding ID is not valid" ); + + m_rContext.registerXFormsListBinding( m_xElement, _rBindingID ); + } + + void OControlImport::doRegisterXFormsSubmission( const OUString& _rSubmissionID ) + { + OSL_PRECOND( m_xElement.is(), "need element" ); + OSL_PRECOND( !_rSubmissionID.isEmpty(), "binding ID is not valid" ); + + m_rContext.registerXFormsSubmission( m_xElement, _rSubmissionID ); + } + + Reference< XPropertySet > OControlImport::createElement() + { + const Reference xPropSet = OElementImport::createElement(); + if ( xPropSet.is() ) + { + m_xInfo = xPropSet->getPropertySetInfo(); + if ( m_xInfo.is() && m_xInfo->hasPropertyByName(PROPERTY_ALIGN) ) + { + Any aValue; + xPropSet->setPropertyValue(PROPERTY_ALIGN,aValue); + } + } + return xPropSet; + } + + //= OImagePositionImport + OImagePositionImport::OImagePositionImport( OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType ) + :OControlImport( _rImport, _rEventManager, _rxParentContainer, _eType ) + ,m_nImagePosition( -1 ) + ,m_nImageAlign( 0 ) + ,m_bHaveImagePosition( false ) + { + } + + bool OImagePositionImport::handleAttribute( sal_Int32 nElement, + const OUString& _rValue ) + { + static const sal_Int32 s_nImageDataAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::ImageData); + + if ( (nElement & TOKEN_MASK) == s_nImageDataAttributeName) + { + m_xGraphic = m_rContext.getGlobalContext().loadGraphicByURL(_rValue); + return true; + } + else if ( (nElement & TOKEN_MASK) == XML_IMAGE_POSITION ) + { + OSL_VERIFY( PropertyConversion::convertString( + cppu::UnoType::get(), + _rValue, aImagePositionMap + ) >>= m_nImagePosition ); + m_bHaveImagePosition = true; + return true; + } + else if ( (nElement & TOKEN_MASK) == XML_IMAGE_ALIGN ) + { + OSL_VERIFY( PropertyConversion::convertString( + cppu::UnoType::get(), + _rValue, aImageAlignMap + ) >>= m_nImageAlign ); + return true; + } + + return OControlImport::handleAttribute( nElement, _rValue ); + } + + void OImagePositionImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) + { + OControlImport::startFastElement( nElement, _rxAttrList ); + + if (m_xGraphic.is()) + { + PropertyValue aGraphicProperty; + aGraphicProperty.Name = PROPERTY_GRAPHIC; + aGraphicProperty.Value <<= m_xGraphic; + implPushBackPropertyValue(aGraphicProperty); + } + if ( !m_bHaveImagePosition ) + return; + + sal_Int16 nUnoImagePosition = ImagePosition::Centered; + if ( m_nImagePosition >= 0 ) + { + OSL_ENSURE( ( m_nImagePosition <= 3 ) && ( m_nImageAlign >= 0 ) && ( m_nImageAlign < 3 ), + "OImagePositionImport::StartElement: unknown image align and/or position!" ); + nUnoImagePosition = m_nImagePosition * 3 + m_nImageAlign; + } + + PropertyValue aImagePosition; + aImagePosition.Name = PROPERTY_IMAGE_POSITION; + aImagePosition.Value <<= nUnoImagePosition; + implPushBackPropertyValue( aImagePosition ); + } + + //= OReferredControlImport + OReferredControlImport::OReferredControlImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer ) + :OControlImport(_rImport, _rEventManager, _rxParentContainer) + { + } + + void OReferredControlImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) + { + OControlImport::startFastElement(nElement, _rxAttrList); + + // the base class should have created the control, so we can register it + if ( !m_sReferringControls.isEmpty() ) + m_rFormImport.registerControlReferences(m_xElement, m_sReferringControls); + } + + bool OReferredControlImport::handleAttribute(sal_Int32 nElement, + const OUString& _rValue) + { + static const sal_Int32 s_nReferenceAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::For); + if ((nElement & TOKEN_MASK) == s_nReferenceAttributeName) + { + m_sReferringControls = _rValue; + return true; + } + return OControlImport::handleAttribute(nElement, _rValue); + } + + //= OPasswordImport + OPasswordImport::OPasswordImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType) + :OControlImport(_rImport, _rEventManager, _rxParentContainer, _eType) + { + } + + bool OPasswordImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) + { + static const sal_Int32 s_nEchoCharAttributeName = OAttributeMetaData::getSpecialAttributeToken(SCAFlags::EchoChar); + if ((nElement & TOKEN_MASK) == s_nEchoCharAttributeName) + { + // need a special handling for the EchoChar property + PropertyValue aEchoChar; + aEchoChar.Name = PROPERTY_ECHOCHAR; + OSL_ENSURE(_rValue.getLength() == 1, "OPasswordImport::handleAttribute: invalid echo char attribute!"); + // we ourself should not have written values other than of length 1 + if (_rValue.getLength() >= 1) + aEchoChar.Value <<= static_cast(_rValue[0]); + else + aEchoChar.Value <<= sal_Int16(0); + implPushBackPropertyValue(aEchoChar); + return true; + } + return OControlImport::handleAttribute(nElement, _rValue); + } + + //= ORadioImport + ORadioImport::ORadioImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType) + :OImagePositionImport( _rImport, _rEventManager, _rxParentContainer, _eType ) + { + } + + bool ORadioImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) + { + // need special handling for the State & CurrentState properties: + // they're stored as booleans, but expected to be int16 properties + static const sal_Int32 nCurrentSelectedAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentSelected); + static const sal_Int32 nSelectedAttributeName = OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Selected); + if ( (nElement & TOKEN_MASK) == nCurrentSelectedAttributeName + || (nElement & TOKEN_MASK) == nSelectedAttributeName + ) + { + const OAttribute2Property::AttributeAssignment* pProperty = m_rContext.getAttributeMap().getAttributeTranslation(nElement & TOKEN_MASK); + assert(pProperty && "ORadioImport::handleAttribute: invalid property map!"); + if (pProperty) + { + const Any aBooleanValue( PropertyConversion::convertString(pProperty->aPropertyType, _rValue, pProperty->pEnumMap) ); + + // create and store a new PropertyValue + PropertyValue aNewValue; + aNewValue.Name = pProperty->sPropertyName; + aNewValue.Value <<= static_cast(::cppu::any2bool(aBooleanValue)); + + implPushBackPropertyValue(aNewValue); + } + return true; + } + return OImagePositionImport::handleAttribute( nElement, _rValue ); + } + + //= OURLReferenceImport + OURLReferenceImport::OURLReferenceImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType) + :OImagePositionImport(_rImport, _rEventManager, _rxParentContainer, _eType) + { + } + + bool OURLReferenceImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) + { + static const sal_Int32 s_nTargetLocationAttributeName = OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::TargetLocation ); + static const sal_Int32 s_nImageDataAttributeName = OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::ImageData ); + + // need to make the URL absolute if + // * it's the image-data attribute + // * it's the target-location attribute, and we're dealing with an object which has the respective property + bool bMakeAbsolute = + (nElement & TOKEN_MASK) == s_nImageDataAttributeName + || ( (nElement & TOKEN_MASK) == s_nTargetLocationAttributeName + && ( ( OControlElement::BUTTON == m_eElementType ) + || ( OControlElement::IMAGE == m_eElementType ) + ) + ); + + if (bMakeAbsolute && !_rValue.isEmpty()) + { + OUString sAdjustedValue = _rValue; + if ((nElement & TOKEN_MASK) != s_nImageDataAttributeName) + sAdjustedValue = m_rContext.getGlobalContext().GetAbsoluteReference( _rValue ); + return OImagePositionImport::handleAttribute( nElement, sAdjustedValue ); + } + + return OImagePositionImport::handleAttribute( nElement, _rValue ); + } + + //= OButtonImport + OButtonImport::OButtonImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType) + :OURLReferenceImport(_rImport, _rEventManager, _rxParentContainer, _eType) + { + enableTrackAttributes(); + } + + void OButtonImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) + { + OURLReferenceImport::startFastElement(nElement, _rxAttrList); + + // handle the target-frame attribute + simulateDefaultedAttribute(OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetFrame), PROPERTY_TARGETFRAME, "_blank"); + } + + //= OValueRangeImport + OValueRangeImport::OValueRangeImport( OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, OControlElement::ElementType _eType ) + :OControlImport( _rImport, _rEventManager, _rxParentContainer, _eType ) + ,m_nStepSizeValue( 1 ) + { + + } + + bool OValueRangeImport::handleAttribute( sal_Int32 nElement, const OUString& _rValue ) + { + if ( (nElement & TOKEN_MASK) == OAttributeMetaData::getSpecialAttributeToken( SCAFlags::StepSize ) ) + { + ::sax::Converter::convertNumber( m_nStepSizeValue, _rValue ); + return true; + } + return OControlImport::handleAttribute( nElement, _rValue ); + } + + void OValueRangeImport::startFastElement( sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList ) + { + OControlImport::startFastElement( nElement, _rxAttrList ); + + if ( m_xInfo.is() ) + { + if ( m_xInfo->hasPropertyByName( PROPERTY_SPIN_INCREMENT ) ) + m_xElement->setPropertyValue( PROPERTY_SPIN_INCREMENT, Any( m_nStepSizeValue ) ); + else if ( m_xInfo->hasPropertyByName( PROPERTY_LINE_INCREMENT ) ) + m_xElement->setPropertyValue( PROPERTY_LINE_INCREMENT, Any( m_nStepSizeValue ) ); + } + } + + //= OTextLikeImport + OTextLikeImport::OTextLikeImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType) + :OControlImport(_rImport, _rEventManager, _rxParentContainer, _eType) + ,m_bEncounteredTextPara( false ) + { + enableTrackAttributes(); + } + + css::uno::Reference< css::xml::sax::XFastContextHandler > OTextLikeImport::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) + { + if ( nElement == XML_ELEMENT(TEXT, XML_P) ) + { + OSL_ENSURE( m_eElementType == OControlElement::TEXT_AREA, + "OTextLikeImport::CreateChildContext: text paragraphs in a non-text-area?" ); + + if ( m_eElementType == OControlElement::TEXT_AREA ) + { + Reference< XText > xTextElement( m_xElement, UNO_QUERY ); + if ( xTextElement.is() ) + { + rtl::Reference < XMLTextImportHelper > xTextImportHelper( m_rContext.getGlobalContext().GetTextImport() ); + + if ( !m_xCursor.is() ) + { + m_xOldCursor = xTextImportHelper->GetCursor(); + m_xCursor = xTextElement->createTextCursor(); + + if ( m_xCursor.is() ) + xTextImportHelper->SetCursor( m_xCursor ); + } + if ( m_xCursor.is() ) + { + m_bEncounteredTextPara = true; + return xTextImportHelper->CreateTextChildContext( m_rContext.getGlobalContext(), nElement, xAttrList ); + } + } + else + { + // in theory, we could accumulate all the text portions (without formatting), + // and set it as Text property at the model ... + } + } + } + + return OControlImport::createFastChildContext( nElement, xAttrList ); + } + + void OTextLikeImport::startFastElement(sal_Int32 nElement, const Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) + { + OControlImport::startFastElement(nElement, _rxAttrList); + + // handle the convert-empty-to-null attribute, whose default is different from the property default + // unfortunately, different classes are imported by this class ('cause they're represented by the + // same XML element), though not all of them know this property. + // So we have to do a check ... + if (m_xElement.is() && m_xInfo.is() && m_xInfo->hasPropertyByName(PROPERTY_EMPTY_IS_NULL) ) + simulateDefaultedAttribute(OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ConvertEmpty), PROPERTY_EMPTY_IS_NULL, "false"); + } + + namespace { + + struct EqualHandle + { + const sal_Int32 m_nHandle; + explicit EqualHandle( sal_Int32 _nHandle ) : m_nHandle( _nHandle ) { } + + bool operator()( const PropertyValue& _rProp ) + { + return _rProp.Handle == m_nHandle; + } + }; + + } + + void OTextLikeImport::removeRedundantCurrentValue() + { + if ( !m_bEncounteredTextPara ) + return; + + // In case the text is written in the text:p elements, we need to ignore what we read as + // current-value attribute, since it's redundant. + // fortunately, OElementImport tagged the value property with the PROPID_CURRENT_VALUE + // handle, so we do not need to determine the name of our value property here + // (normally, it should be "Text", since no other controls than the edit field should + // have the text:p elements) + PropertyValueArray::iterator aValuePropertyPos = ::std::find_if( + m_aValues.begin(), + m_aValues.end(), + EqualHandle( PROPID_CURRENT_VALUE ) + ); + if ( aValuePropertyPos != m_aValues.end() ) + { + OSL_ENSURE( aValuePropertyPos->Name == PROPERTY_TEXT, "OTextLikeImport::EndElement: text:p was present, but our value property is *not* 'Text'!" ); + if ( aValuePropertyPos->Name == PROPERTY_TEXT ) + { + m_aValues.erase(aValuePropertyPos); + } + } + + // additionally, we need to set the "RichText" property of our element to sal_True + // (the presence of the text:p is used as indicator for the value of the RichText property) + bool bHasRichTextProperty = false; + if ( m_xInfo.is() ) + bHasRichTextProperty = m_xInfo->hasPropertyByName( PROPERTY_RICH_TEXT ); + OSL_ENSURE( bHasRichTextProperty, "OTextLikeImport::EndElement: text:p, but no rich text control?" ); + if ( bHasRichTextProperty ) + m_xElement->setPropertyValue( PROPERTY_RICH_TEXT, Any( true ) ); + // Note that we do *not* set the RichText property (in case our element has one) to sal_False here + // since this is the default of this property, anyway. + } + + namespace { + + struct EqualName + { + const OUString & m_sName; + explicit EqualName( const OUString& _rName ) : m_sName( _rName ) { } + + bool operator()( const PropertyValue& _rProp ) + { + return _rProp.Name == m_sName; + } + }; + + } + + void OTextLikeImport::adjustDefaultControlProperty() + { + // In OpenOffice.org 2.0, we changed the implementation of the css.form.component.TextField (the model of a text field control), + // so that it now uses another default control. So if we encounter a text field where the *old* default + // control property is writing, we are not allowed to use it + PropertyValueArray::iterator aDefaultControlPropertyPos = ::std::find_if( + m_aValues.begin(), + m_aValues.end(), + EqualName( "DefaultControl" ) + ); + if ( aDefaultControlPropertyPos != m_aValues.end() ) + { + OUString sDefaultControl; + OSL_VERIFY( aDefaultControlPropertyPos->Value >>= sDefaultControl ); + if ( sDefaultControl == "stardiv.one.form.control.Edit" ) + { + // complete remove this property value from the array. Today's "default value" of the "DefaultControl" + // property is sufficient + m_aValues.erase(aDefaultControlPropertyPos); + } + } + } + + void OTextLikeImport::endFastElement(sal_Int32 nElement) + { + removeRedundantCurrentValue(); + adjustDefaultControlProperty(); + + // let the base class do the stuff + OControlImport::endFastElement(nElement); + + // some cleanups + rtl::Reference < XMLTextImportHelper > xTextImportHelper( m_rContext.getGlobalContext().GetTextImport() ); + if ( m_xCursor.is() ) + { + // delete the newline which has been imported erroneously + // TODO (fs): stole this code somewhere - why don't we fix the text import?? + m_xCursor->gotoEnd( false ); + m_xCursor->goLeft( 1, true ); + m_xCursor->setString( OUString() ); + + // reset cursor + xTextImportHelper->ResetCursor(); + } + + if ( m_xOldCursor.is() ) + xTextImportHelper->SetCursor( m_xOldCursor ); + + } + + //= OListAndComboImport + OListAndComboImport::OListAndComboImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType) + :OControlImport(_rImport, _rEventManager, _rxParentContainer, _eType) + ,m_nEmptyListItems( 0 ) + ,m_nEmptyValueItems( 0 ) + ,m_bEncounteredLSAttrib( false ) + ,m_bLinkWithIndexes( false ) + { + if (OControlElement::COMBOBOX == m_eElementType) + enableTrackAttributes(); + } + + css::uno::Reference< css::xml::sax::XFastContextHandler > OListAndComboImport::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList ) + { + // is it the "option" sub tag of a listbox ? + if ((nElement & TOKEN_MASK) == XML_OPTION) + return new OListOptionImport(GetImport(), this); + + // is it the "item" sub tag of a combobox ? + if ((nElement & TOKEN_MASK) == XML_ITEM) + return new OComboItemImport(GetImport(), this); + + // everything else + return OControlImport::createFastChildContext(nElement, _rxAttrList); + } + + void OListAndComboImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) + { + m_bLinkWithIndexes = false; + + OControlImport::startFastElement(nElement, _rxAttrList); + + if (OControlElement::COMBOBOX == m_eElementType) + { + // for the auto-completion + // the attribute default does not equal the property default, so in case we did not read this attribute, + // we have to simulate it + simulateDefaultedAttribute( OAttributeMetaData::getSpecialAttributeToken( SCAFlags::AutoCompletion ), PROPERTY_AUTOCOMPLETE, "false"); + + // same for the convert-empty-to-null attribute, which's default is different from the property default + simulateDefaultedAttribute( OAttributeMetaData::getDatabaseAttributeToken( DAFlags::ConvertEmpty ), PROPERTY_EMPTY_IS_NULL, "false"); + } + } + + void OListAndComboImport::endFastElement(sal_Int32 nElement) + { + // append the list source property the properties sequence of our importer + // the string item list + PropertyValue aItemList; + aItemList.Name = PROPERTY_STRING_ITEM_LIST; + aItemList.Value <<= comphelper::containerToSequence(m_aListSource); + implPushBackPropertyValue(aItemList); + + if (OControlElement::LISTBOX == m_eElementType) + { + OSL_ENSURE((m_aListSource.size() + m_nEmptyListItems) == (m_aValueList.size() + m_nEmptyValueItems), + "OListAndComboImport::EndElement: inconsistence between labels and values!"); + + if ( !m_bEncounteredLSAttrib ) + { + // the value sequence + PropertyValue aValueList; + aValueList.Name = PROPERTY_LISTSOURCE; + aValueList.Value <<= comphelper::containerToSequence(m_aValueList); + implPushBackPropertyValue(aValueList); + } + + // the select sequence + PropertyValue aSelected; + aSelected.Name = PROPERTY_SELECT_SEQ; + aSelected.Value <<= comphelper::containerToSequence(m_aSelectedSeq); + implPushBackPropertyValue(aSelected); + + // the default select sequence + PropertyValue aDefaultSelected; + aDefaultSelected.Name = PROPERTY_DEFAULT_SELECT_SEQ; + aDefaultSelected.Value <<= comphelper::containerToSequence(m_aDefaultSelectedSeq); + implPushBackPropertyValue(aDefaultSelected); + } + + OControlImport::endFastElement(nElement); + + // the external list source, if applicable + if ( m_xElement.is() && !m_sCellListSource.isEmpty() ) + m_rContext.registerCellRangeListSource( m_xElement, m_sCellListSource ); + } + + void OListAndComboImport::doRegisterCellValueBinding( const OUString& _rBoundCellAddress ) + { + OUString sBoundCellAddress( _rBoundCellAddress ); + if ( m_bLinkWithIndexes ) + { + // This is a HACK. We register a string which is no valid address, but allows + // (somewhere else) to determine that a non-standard binding should be created. + // This hack is acceptable for OOo 1.1.1, since the file format for value + // bindings of form controls is to be changed afterwards, anyway. + sBoundCellAddress += ":index"; + } + + OControlImport::doRegisterCellValueBinding( sBoundCellAddress ); + } + + bool OListAndComboImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) + { + static const sal_Int32 nListSourceAttributeName = OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ListSource); + if ( (nElement & TOKEN_MASK) == nListSourceAttributeName ) + { + PropertyValue aListSource; + aListSource.Name = PROPERTY_LISTSOURCE; + + // it's the ListSource attribute + m_bEncounteredLSAttrib = true; + if ( OControlElement::COMBOBOX == m_eElementType ) + { + aListSource.Value <<= _rValue; + } + else + { + // a listbox which has a list-source attribute must have a list-source-type of something + // not equal to ValueList. + // In this case, the list-source value is simply the one and only element of the ListSource property. + Sequence aListSourcePropValue { _rValue }; + aListSource.Value <<= aListSourcePropValue; + } + + implPushBackPropertyValue( aListSource ); + return true; + } + + if ( (nElement & TOKEN_MASK) == OAttributeMetaData::getBindingAttributeToken( BAFlags::ListCellRange ) ) + { + m_sCellListSource = _rValue; + return true; + } + + if ( (nElement & TOKEN_MASK) == OAttributeMetaData::getBindingAttributeToken( BAFlags::ListLinkingType ) ) + { + sal_Int16 nLinkageType = 0; + PropertyConversion::convertString( + ::cppu::UnoType::get(), + _rValue, + aListLinkageMap + ) >>= nLinkageType; + + m_bLinkWithIndexes = ( nLinkageType != 0 ); + return true; + } + + return OControlImport::handleAttribute(nElement, _rValue); + } + + void OListAndComboImport::implPushBackLabel(const OUString& _rLabel) + { + OSL_ENSURE(!m_nEmptyListItems, "OListAndComboImport::implPushBackValue: label list is already done!"); + if (!m_nEmptyListItems) + m_aListSource.push_back(_rLabel); + } + + void OListAndComboImport::implPushBackValue(const OUString& _rValue) + { + OSL_ENSURE(!m_nEmptyValueItems, "OListAndComboImport::implPushBackValue: value list is already done!"); + if (!m_nEmptyValueItems) + { + OSL_ENSURE( !m_bEncounteredLSAttrib, "OListAndComboImport::implPushBackValue: invalid structure! Did you save this document with a version prior SRC641 m?" ); + // We already had the list-source attribute, which means that the ListSourceType is + // not ValueList, which means that the ListSource should contain only one string in + // the first element of the sequence + // All other values in the file are invalid + + m_aValueList.push_back( _rValue ); + } + } + + void OListAndComboImport::implEmptyLabelFound() + { + ++m_nEmptyListItems; + } + + void OListAndComboImport::implEmptyValueFound() + { + ++m_nEmptyValueItems; + } + + void OListAndComboImport::implSelectCurrentItem() + { + OSL_ENSURE((m_aListSource.size() + m_nEmptyListItems) == (m_aValueList.size() + m_nEmptyValueItems), + "OListAndComboImport::implSelectCurrentItem: inconsistence between labels and values!"); + + sal_Int16 nItemNumber = static_cast(m_aListSource.size() - 1 + m_nEmptyListItems); + m_aSelectedSeq.push_back(nItemNumber); + } + + void OListAndComboImport::implDefaultSelectCurrentItem() + { + OSL_ENSURE((m_aListSource.size() + m_nEmptyListItems) == (m_aValueList.size() + m_nEmptyValueItems), + "OListAndComboImport::implDefaultSelectCurrentItem: inconsistence between labels and values!"); + + sal_Int16 nItemNumber = static_cast(m_aListSource.size() - 1 + m_nEmptyListItems); + m_aDefaultSelectedSeq.push_back(nItemNumber); + } + + //= OListOptionImport + OListOptionImport::OListOptionImport(SvXMLImport& _rImport, + const OListAndComboImportRef& _rListBox) + :SvXMLImportContext(_rImport) + ,m_xListBoxImport(_rListBox) + { + } + + void OListOptionImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) + { + // the label and the value + const sal_Int32 nLabelAttribute = (nElement & ~TOKEN_MASK) | XML_LABEL; + const sal_Int32 nValueAttribute = (nElement & ~TOKEN_MASK) | XML_VALUE; + + // the label attribute + OUString sValue = _rxAttrList->getOptionalValue(nLabelAttribute); + bool bNonexistentAttribute = !_rxAttrList->hasAttribute(nLabelAttribute); + + if (bNonexistentAttribute) + m_xListBoxImport->implEmptyLabelFound(); + else + m_xListBoxImport->implPushBackLabel( sValue ); + + // the value attribute + sValue = _rxAttrList->getOptionalValue(nValueAttribute); + bNonexistentAttribute = !_rxAttrList->hasAttribute(nValueAttribute); + + if (bNonexistentAttribute) + m_xListBoxImport->implEmptyValueFound(); + else + m_xListBoxImport->implPushBackValue( sValue ); + + // the current-selected and selected + const sal_Int32 nSelectedAttribute = (nElement & ~TOKEN_MASK) | OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentSelected); + const sal_Int32 nDefaultSelectedAttribute = (nElement & ~TOKEN_MASK) | OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Selected); + + // propagate the selected flag + bool bSelected(false); + (void)::sax::Converter::convertBool(bSelected, + _rxAttrList->getOptionalValue(nSelectedAttribute)); + if (bSelected) + m_xListBoxImport->implSelectCurrentItem(); + + // same for the default selected + bool bDefaultSelected(false); + (void)::sax::Converter::convertBool(bDefaultSelected, + _rxAttrList->getOptionalValue(nDefaultSelectedAttribute)); + if (bDefaultSelected) + m_xListBoxImport->implDefaultSelectCurrentItem(); + } + + //= OComboItemImport + OComboItemImport::OComboItemImport(SvXMLImport& _rImport, + const OListAndComboImportRef& _rListBox) + :SvXMLImportContext(_rImport) + ,m_xListBoxImport(_rListBox) + { + } + + void OComboItemImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) + { + const sal_Int32 nLabelAttributeName = (nElement & ~TOKEN_MASK) | + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Label); + m_xListBoxImport->implPushBackLabel(_rxAttrList->getOptionalValue(nLabelAttributeName)); + } + + //= OColumnWrapperImport + OColumnWrapperImport::OColumnWrapperImport(OFormLayerXMLImport_Impl& _rImport, + IEventAttacherManager& _rEventManager, sal_Int32 /*nElement*/, + const Reference< XNameContainer >& _rxParentContainer) + :SvXMLImportContext(_rImport.getGlobalContext()) + ,m_xParentContainer(_rxParentContainer) + ,m_rFormImport(_rImport) + ,m_rEventManager(_rEventManager) + { + } + css::uno::Reference< css::xml::sax::XFastContextHandler > OColumnWrapperImport::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) + { + OControlImport* pReturn = implCreateChildContext(nElement, OElementNameMap::getElementType(nElement & TOKEN_MASK)); + if (pReturn) + { + OSL_ENSURE(m_xOwnAttributes.is(), "OColumnWrapperImport::CreateChildContext: had no form:column element!"); + pReturn->addOuterAttributes(m_xOwnAttributes); + } + return pReturn; + } + void OColumnWrapperImport::startFastElement(sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& _rxAttrList) + { + OSL_ENSURE(!m_xOwnAttributes.is(), "OColumnWrapperImport::StartElement: already have the cloned list!"); + + // clone the attributes + Reference< XCloneable > xCloneList(_rxAttrList, UNO_QUERY_THROW); + m_xOwnAttributes.set(xCloneList->createClone(), UNO_QUERY_THROW); + } + + OControlImport* OColumnWrapperImport::implCreateChildContext( + sal_Int32 /*nElement*/, + OControlElement::ElementType _eType) + { + OSL_ENSURE( (OControlElement::TEXT == _eType) + || (OControlElement::TEXT_AREA == _eType) + || (OControlElement::FORMATTED_TEXT == _eType) + || (OControlElement::CHECKBOX == _eType) + || (OControlElement::LISTBOX == _eType) + || (OControlElement::COMBOBOX == _eType) + || (OControlElement::TIME == _eType) + || (OControlElement::DATE == _eType), + "OColumnWrapperImport::implCreateChildContext: invalid or unrecognized sub element!"); + + switch (_eType) + { + case OControlElement::COMBOBOX: + case OControlElement::LISTBOX: + return new OColumnImport(m_rFormImport, m_rEventManager, m_xParentContainer, _eType ); + + case OControlElement::PASSWORD: + return new OColumnImport(m_rFormImport, m_rEventManager, m_xParentContainer, _eType ); + + case OControlElement::TEXT: + case OControlElement::TEXT_AREA: + case OControlElement::FORMATTED_TEXT: + return new OColumnImport< OTextLikeImport >( m_rFormImport, m_rEventManager, m_xParentContainer, _eType ); + + default: + return new OColumnImport(m_rFormImport, m_rEventManager, m_xParentContainer, _eType ); + } + } + + //= OGridImport + OGridImport::OGridImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType) + :OControlImport(_rImport, _rEventManager, _rxParentContainer) + { + setElementType(_eType); + } + + css::uno::Reference< css::xml::sax::XFastContextHandler > OGridImport::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) + { + // maybe it's a sub control + if ((nElement & TOKEN_MASK) == XML_COLUMN) + { + if (m_xMeAsContainer.is()) + return new OColumnWrapperImport(m_rFormImport, *this, nElement, m_xMeAsContainer); + else + { + OSL_FAIL("OGridImport::CreateChildContext: don't have an element!"); + return nullptr; + } + } + + return OControlImport::createFastChildContext(nElement, xAttrList); + } + + void OGridImport::endFastElement(sal_Int32 nElement) + { + OControlImport::endFastElement(nElement); + + // now that we have all children, attach the events + css::uno::Reference< css::container::XIndexAccess > xIndexContainer(m_xMeAsContainer, css::uno::UNO_QUERY); + if (xIndexContainer.is()) + ODefaultEventAttacherManager::setEvents(xIndexContainer); + } + + css::uno::Reference< css::beans::XPropertySet > OGridImport::createElement() + { + // let the base class create the object + css::uno::Reference< css::beans::XPropertySet > xReturn = OControlImport::createElement(); + if (!xReturn.is()) + return xReturn; + + // ensure that the object is a XNameContainer (we strongly need this for inserting child elements) + m_xMeAsContainer.set(xReturn, css::uno::UNO_QUERY); + if (!m_xMeAsContainer.is()) + { + OSL_FAIL("OContainerImport::createElement: invalid element (no XNameContainer) created!"); + xReturn.clear(); + } + + return xReturn; + } + + //= OFormImport + OFormImport::OFormImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const Reference< XNameContainer >& _rxParentContainer) + :OElementImport(_rImport, _rEventManager, _rxParentContainer) + { + enableTrackAttributes(); + } + + css::uno::Reference< css::xml::sax::XFastContextHandler > OFormImport::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& _rxAttrList ) + { + auto nToken = (nElement & TOKEN_MASK); + if( nToken == XML_FORM ) + return new OFormImport( m_rFormImport, *this, m_xMeAsContainer); + else if ( nToken == XML_CONNECTION_RESOURCE ) + return new OXMLDataSourceImport(GetImport(), _rxAttrList, m_xElement); + else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) || + nToken == XML_PROPERTIES ) + return OElementImport::createFastChildContext( nElement, _rxAttrList ); + else + { + OControlElement::ElementType eType = OElementNameMap::getElementType(nToken); + switch (eType) + { + case OControlElement::TEXT: + case OControlElement::TEXT_AREA: + case OControlElement::FORMATTED_TEXT: + return new OTextLikeImport(m_rFormImport, *this, m_xMeAsContainer, eType); + case OControlElement::GRID: + return new OGridImport(m_rFormImport, *this, m_xMeAsContainer, eType); + case OControlElement::COMBOBOX: + case OControlElement::LISTBOX: + return new OListAndComboImport(m_rFormImport, *this, m_xMeAsContainer, eType); + case OControlElement::PASSWORD: + return new OPasswordImport(m_rFormImport, *this, m_xMeAsContainer, eType); + case OControlElement::BUTTON: + case OControlElement::IMAGE: + case OControlElement::IMAGE_FRAME: + return new OButtonImport( m_rFormImport, *this, m_xMeAsContainer, eType ); + case OControlElement::RADIO: + return new ORadioImport(m_rFormImport, *this, m_xMeAsContainer, eType); + case OControlElement::CHECKBOX: + return new OImagePositionImport(m_rFormImport, *this, m_xMeAsContainer, eType); + case OControlElement::FRAME: + case OControlElement::FIXED_TEXT: + return new OReferredControlImport(m_rFormImport, *this, m_xMeAsContainer); + case OControlElement::VALUERANGE: + return new OValueRangeImport( m_rFormImport, *this, m_xMeAsContainer, eType ); + default: + return new OControlImport(m_rFormImport, *this, m_xMeAsContainer, eType); + } + } + } + + void OFormImport::startFastElement(sal_Int32 nElement, const Reference< XFastAttributeList >& _rxAttrList) + { + m_rFormImport.enterEventContext(); + OElementImport::startFastElement(nElement, _rxAttrList); + + // handle the target-frame attribute + simulateDefaultedAttribute(OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetFrame), PROPERTY_TARGETFRAME, "_blank"); + } + + void OFormImport::endFastElement(sal_Int32 nElement) + { + OElementImport::endFastElement(nElement); + + // now that we have all children, attach the events + css::uno::Reference< css::container::XIndexAccess > xIndexContainer(m_xMeAsContainer, css::uno::UNO_QUERY); + if (xIndexContainer.is()) + ODefaultEventAttacherManager::setEvents(xIndexContainer); + + m_rFormImport.leaveEventContext(); + } + + css::uno::Reference< css::beans::XPropertySet > OFormImport::createElement() + { + // let the base class create the object + css::uno::Reference< css::beans::XPropertySet > xReturn = OElementImport::createElement(); + if (!xReturn.is()) + return xReturn; + + // ensure that the object is a XNameContainer (we strongly need this for inserting child elements) + m_xMeAsContainer.set(xReturn, css::uno::UNO_QUERY); + if (!m_xMeAsContainer.is()) + { + OSL_FAIL("OContainerImport::createElement: invalid element (no XNameContainer) created!"); + xReturn.clear(); + } + + return xReturn; + } + + bool OFormImport::handleAttribute(sal_Int32 nElement, const OUString& _rValue) + { + // handle the master/details field attributes (they're way too special to let the OPropertyImport handle them) + static const sal_Int32 s_nMasterFieldsAttributeName = OAttributeMetaData::getFormAttributeToken(faMasterFields); + static const sal_Int32 s_nDetailFieldsAttributeName = OAttributeMetaData::getFormAttributeToken(faDetailFields); + + if ( (nElement & TOKEN_MASK) == s_nMasterFieldsAttributeName) + { + implTranslateStringListProperty(PROPERTY_MASTERFIELDS, _rValue); + return true; + } + + if ( (nElement & TOKEN_MASK) == s_nDetailFieldsAttributeName) + { + implTranslateStringListProperty(PROPERTY_DETAILFIELDS, _rValue); + return true; + } + + return OElementImport::handleAttribute(nElement, _rValue); + } + + void OFormImport::implTranslateStringListProperty(const OUString& _rPropertyName, const OUString& _rValue) + { + PropertyValue aProp; + aProp.Name = _rPropertyName; + + Sequence< OUString > aList; + + // split up the value string + if (!_rValue.isEmpty()) + { + // For the moment, we build a vector instead of a Sequence. It's easier to handle because of its + // push_back method + ::std::vector< OUString > aElements; + // estimate the number of tokens + sal_Int32 nEstimate = 0, nLength = _rValue.getLength(); + const sal_Unicode* pChars = _rValue.getStr(); + for (sal_Int32 i=0; i(aElements.data(), aElements.size()); + } + else + { + OSL_FAIL("OFormImport::implTranslateStringListProperty: invalid value (empty)!"); + } + + aProp.Value <<= aList; + + // add the property to the base class' array + implPushBackPropertyValue(aProp); + } + //= OXMLDataSourceImport + OXMLDataSourceImport::OXMLDataSourceImport( + SvXMLImport& _rImport + ,const Reference< css::xml::sax::XFastAttributeList > & _xAttrList + ,const css::uno::Reference< css::beans::XPropertySet >& _xElement) : + SvXMLImportContext( _rImport) + { + for( auto& aIter : sax_fastparser::castToFastAttributeList(_xAttrList) ) + { + if ( aIter.getToken() == + XML_ELEMENT(XLINK, OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::TargetLocation ) ) ) + { + OUString sValue = aIter.toString(); + sValue = _rImport.GetAbsoluteReference(sValue); + INetURLObject aURL(sValue); + if ( aURL.GetProtocol() == INetProtocol::File ) + _xElement->setPropertyValue(PROPERTY_DATASOURCENAME,Any(sValue)); + else + _xElement->setPropertyValue(PROPERTY_URL,Any(sValue)); // the url is the "sdbc:" string + break; + } + else + SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + } + + OUString OFormImport::determineDefaultServiceName() const + { + return "com.sun.star.form.component.Form"; + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/elementimport.hxx b/xmloff/source/forms/elementimport.hxx new file mode 100644 index 000000000..dcf4a6043 --- /dev/null +++ b/xmloff/source/forms/elementimport.hxx @@ -0,0 +1,674 @@ +/* -*- 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 + +#include "propertyimport.hxx" +#include "controlelement.hxx" +#include "valueproperties.hxx" +#include "eventimport.hxx" +#include "logging.hxx" +#include "property_description.hxx" + +#include +#include +#include +#include +#include + +#include +#include + +class XMLTextStyleContext; +namespace xmloff +{ + + class OFormLayerXMLImport_Impl; + + //= OElementNameMap + const OControlElement::ElementType& operator ++(OControlElement::ElementType& _e); + + /** helper class which allows fast translation of xml tag names into element types. + */ + class OElementNameMap : public OControlElement + { + typedef std::map MapString2Element; + static std::map s_sElementTranslations2; + + OElementNameMap() = delete; + + public: + static ElementType getElementType(sal_Int32 nToken); + }; + + //= OElementImport + /** implements common behaviour for importing forms, controls and columns + */ + class OElementImport + :public OPropertyImport + ,public IEventAttacher + ,public OStackedLogging + { + protected: + OUString m_sServiceName; // the service name as extracted from the service-name attribute + OUString m_sName; // the name of the object (redundant, already contained in the base class' array) + OFormLayerXMLImport_Impl& m_rFormImport; // the form import context + IEventAttacherManager& m_rEventManager; // the event attacher manager + + const XMLTextStyleContext* m_pStyleElement; // the XML element which describes the style we encountered + // while reading our element + + /// the parent container to insert the new element into + css::uno::Reference< css::container::XNameContainer > + m_xParentContainer; + + /// the element we're creating. Valid after StartElement + css::uno::Reference< css::beans::XPropertySet > + m_xElement; + css::uno::Reference< css::beans::XPropertySetInfo > + m_xInfo; + + bool m_bImplicitGenericAttributeHandling; + + public: + /** ctor + @param _rImport + the importer + @param _rEventManager + the event attacher manager for the control being imported + @param _rAttributeMap + the attribute map to be used for translating attributes into properties + @param _rxParentContainer + the container in which the new element should be inserted + */ + OElementImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer + ); + virtual ~OElementImport() override; + + protected: + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + + // IEventAttacher + virtual void registerEvents( + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents + ) override; + + /** create the (uninitialized) element which is to represent the read data + +

The default implementation uses m_xORB to create an object with m_sServiceName. + */ + virtual css::uno::Reference< css::beans::XPropertySet > + createElement(); + + protected: + /** can be used to handle properties where the attribute default and the property default differ. +

In such case, if the property had the attribute default upon writing, nothing is read, so upon reading, + the property is still at its own default (which is not the attribute default).

+

This method, if told the attribute and the property, and the (implied) attribute default, sets the + property value as if the attribute was encountered.

+ @see encounteredAttribute + */ + void simulateDefaultedAttribute(sal_Int32 nElement, const OUString& _rPropertyName, const char* _pAttributeDefault); + + /** to be called from within handleAttribute, checks whether the given attribute is covered by our generic + attribute handler mechanisms + */ + bool tryGenericAttribute( sal_Int32 nElement, const OUString& _rValue ); + + /** controls whether |handleAttribute| implicitly calls |tryGenericAttribute|, or whether the derived class + must do this explicitly at a suitable place in its own |handleAttribute| + */ + void disableImplicitGenericAttributeHandling() { m_bImplicitGenericAttributeHandling = false; } + + private: + OUString implGetDefaultName() const; + void implApplyGenericProperties(); + void implApplySpecificProperties(); + + PropertyGroups::const_iterator impl_matchPropertyGroup( const PropertyGroups& i_propertyGroups ) const; + + virtual OUString determineDefaultServiceName() const; + }; + + //= OControlImport + /** helper class for importing the description of a single control + */ + class OControlImport + :public OElementImport + ,public OValuePropertiesMetaData + { + protected: + OUString m_sControlId; + OControlElement::ElementType m_eElementType; + + PropertyValueArray m_aValueProperties; + // the value properties (value, current-value, min-value, max-value) require some special + // handling + + // we fake the attributes our base class gets: we add the attributes of the outer wrapper + // element which encloses us + css::uno::Reference< css::xml::sax::XFastAttributeList > + m_xOuterAttributes; + + /** the address of the calc cell which the control model should be bound to, + if applicable + */ + OUString m_sBoundCellAddress; + + /** name of a value binding (xforms:bind attribute) */ + OUString m_sBindingID; + + /** name of a list binding (form:xforms-list-source attribute) */ + OUString m_sListBindingID; + + /** name of a submission (xforms:submission attribute) */ + OUString m_sSubmissionID; + + protected: + // for use by derived classes only + OControlImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer + ); + + public: + OControlImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType + ); + + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + + void addOuterAttributes(const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxOuterAttribs); + + protected: + void setElementType(OControlElement::ElementType _eType) { m_eElementType = _eType; } + + protected: + static void implTranslateValueProperty( + const css::uno::Reference< css::beans::XPropertySetInfo >& _rxPropInfo, + css::beans::PropertyValue& /* [in/out] */ _rPropValue); + + virtual OUString determineDefaultServiceName() const override; + + /** registers the given cell address as value binding address for our element + +

The default implementation simply calls registerCellValueBinding at our import + context, but you may want to override this behaviour.

+ + @param _rBoundCellAddress + the cell address to register for our element. Must not be . + @precond + we have a valid element (m_xElement) + */ + virtual void doRegisterCellValueBinding( const OUString& _rBoundCellAddress ); + + /** register the given XForms binding */ + void doRegisterXFormsValueBinding( const OUString& ); + + /** register the given XForms list binding */ + void doRegisterXFormsListBinding( const OUString& ); + + /** register the given XForms submission */ + void doRegisterXFormsSubmission( const OUString& ); + + protected: + + // OElementImport overridables + virtual css::uno::Reference< css::beans::XPropertySet > + createElement() override; + }; + + // TODO: + // this whole mechanism doesn't scale. Instead of deriving even more classes for every new attribute, + // we should have dedicated attribute handlers + // The rest of xmloff implements it this way - why don't we do, too? + + //= OImagePositionImport + class OImagePositionImport : public OControlImport + { + css::uno::Reference m_xGraphic; + sal_Int16 m_nImagePosition; + sal_Int16 m_nImageAlign; + bool m_bHaveImagePosition; + + public: + OImagePositionImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType + ); + + protected: + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override; + + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + }; + + //= OReferredControlImport + class OReferredControlImport : public OControlImport + { + OUString m_sReferringControls; // the list of ids of controls referring to the one being imported + + public: + OReferredControlImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer + ); + + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override; + + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + }; + + //= OPasswordImport + class OPasswordImport : public OControlImport + { + public: + OPasswordImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType + ); + + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + }; + + //= ORadioImport + class ORadioImport : public OImagePositionImport + { + public: + ORadioImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType + ); + + protected: + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + }; + + //= OURLReferenceImport + /** a specialized version of the OControlImport class, which is able + to handle attributes which denote URLs (and stored relative) + */ + class OURLReferenceImport : public OImagePositionImport + { + public: + OURLReferenceImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType + ); + + protected: + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + }; + + //= OButtonImport + /** A specialized version of the OControlImport class, which handles + the target frame for image and command buttons + */ + class OButtonImport : public OURLReferenceImport + { + public: + OButtonImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType + ); + + protected: + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override; + }; + + //= OValueRangeImport + /** A specialized version of the OControlImport class, which imports + the value-range elements + */ + class OValueRangeImport : public OControlImport + { + private: + sal_Int32 m_nStepSizeValue; + + public: + OValueRangeImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType + ); + + protected: + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList ) override; + + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + }; + + //= OTextLikeImport + /** A specialized version of the OControlImport class, which handles + text like controls which have the convert-empty-to-null attribute

+ */ + class OTextLikeImport : public OControlImport + { + private: + css::uno::Reference< css::text::XTextCursor > m_xCursor; + css::uno::Reference< css::text::XTextCursor > m_xOldCursor; + bool m_bEncounteredTextPara; + + public: + OTextLikeImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType + ); + + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + private: + void adjustDefaultControlProperty(); + void removeRedundantCurrentValue(); + }; + + //= OListAndComboImport + /** A specialized version of the OControlImport class, which handles + attributes / sub elements which are special to list and combo boxes + */ + class OListAndComboImport : public OControlImport + { + friend class OListOptionImport; + friend class OComboItemImport; + + protected: + std::vector + m_aListSource; + std::vector< OUString > + m_aValueList; + + std::vector< sal_Int16 > + m_aSelectedSeq; + std::vector< sal_Int16 > + m_aDefaultSelectedSeq; + + OUString m_sCellListSource; /// the cell range which acts as list source for the control + + sal_Int32 m_nEmptyListItems; /// number of empty list items encountered during reading + sal_Int32 m_nEmptyValueItems; /// number of empty value items encountered during reading + + bool m_bEncounteredLSAttrib; + bool m_bLinkWithIndexes; /** if and only if we should use a cell value binding + which exchanges the selection index (instead of the selection text + */ + + public: + OListAndComboImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType + ); + + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + + // OControlImport overridables + virtual void doRegisterCellValueBinding( const OUString& _rBoundCellAddress ) override; + + protected: + void implPushBackLabel(const OUString& _rLabel); + void implPushBackValue(const OUString& _rValue); + + void implEmptyLabelFound(); + void implEmptyValueFound(); + + void implSelectCurrentItem(); + void implDefaultSelectCurrentItem(); + }; + typedef rtl::Reference OListAndComboImportRef; + + //= OListOptionImport + /** helper class for importing a single <form:option> element. + */ + class OListOptionImport + :public SvXMLImportContext + { + OListAndComboImportRef m_xListBoxImport; + + public: + OListOptionImport(SvXMLImport& _rImport, + const OListAndComboImportRef& _rListBox); + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; + }; + + //= OComboItemImport + /** helper class for importing a single <form:item> element. + */ + class OComboItemImport + :public SvXMLImportContext + { + OListAndComboImportRef m_xListBoxImport; + + public: + OComboItemImport(SvXMLImport& _rImport, + const OListAndComboImportRef& _rListBox); + + protected: + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; + }; + + + //= OColumnImport + /** helper class importing a single grid column (without the <form:column> element wrapping + the column). + +

BASE (the template argument) must be a derivee of OControlImport

+ */ + template + class OColumnImport : public BASE + { + css::uno::Reference< css::form::XGridColumnFactory > + m_xColumnFactory; + + public: + OColumnImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType); + + protected: + // OElementImport overridables + virtual css::uno::Reference< css::beans::XPropertySet > + createElement() override; + }; + + //= OColumnWrapperImport + class OColumnWrapperImport : public SvXMLImportContext + { + css::uno::Reference< css::xml::sax::XFastAttributeList > + m_xOwnAttributes; + css::uno::Reference< css::container::XNameContainer > + m_xParentContainer; + OFormLayerXMLImport_Impl& m_rFormImport; + IEventAttacherManager& m_rEventManager; + + public: + OColumnWrapperImport(OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + sal_Int32 nElement, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer); + + // SvXMLImportContext overridables + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override; + private: + OControlImport* implCreateChildContext( + sal_Int32 nElement, + OControlElement::ElementType _eType); + }; + + /** helper class importing a single <form:grid> element + */ + class OGridImport : public OControlImport, public ODefaultEventAttacherManager + { + public: + OGridImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType); + + // SvXMLImportContext overridables + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + private: + // OElementImport overridables + virtual css::uno::Reference< css::beans::XPropertySet > createElement() override; + + css::uno::Reference< css::container::XNameContainer > m_xMeAsContainer; + }; + + /** helper class importing a single <form:form> element + */ + class OFormImport : public OElementImport, public ODefaultEventAttacherManager + { + public: + OFormImport( + OFormLayerXMLImport_Impl& _rImport, IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer + ); + + private: + // SvXMLImportContext overridables + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // OPropertyImport overridables + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue) override; + + // OElementImport overridables + virtual css::uno::Reference< css::beans::XPropertySet > + createElement() override; + + virtual OUString determineDefaultServiceName() const override; + void implTranslateStringListProperty(const OUString& _rPropertyName, const OUString& _rValue); + + css::uno::Reference< css::container::XNameContainer > m_xMeAsContainer; + }; + + //= OXMLDataSourceImport + class OXMLDataSourceImport : public SvXMLImportContext + { + public: + OXMLDataSourceImport( SvXMLImport& _rImport + ,const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList + ,const css::uno::Reference< css::beans::XPropertySet >& _xElement); + }; + + //= OColumnImport + template + OColumnImport< BASE >::OColumnImport(OFormLayerXMLImport_Impl& _rImport, + IEventAttacherManager& _rEventManager, + const css::uno::Reference< css::container::XNameContainer >& _rxParentContainer, + OControlElement::ElementType _eType) + :BASE(_rImport, _rEventManager, _rxParentContainer, _eType) + ,m_xColumnFactory(_rxParentContainer, css::uno::UNO_QUERY) + { + OSL_ENSURE(m_xColumnFactory.is(), "OColumnImport::OColumnImport: invalid parent container (no factory)!"); + } + + // OElementImport overridables + template + css::uno::Reference< css::beans::XPropertySet > OColumnImport< BASE >::createElement() + { + css::uno::Reference< css::beans::XPropertySet > xReturn; + // no call to the base class' method. We have to use the grid column factory + if (m_xColumnFactory.is()) + { + // create the column + xReturn = m_xColumnFactory->createColumn(this->m_sServiceName); + OSL_ENSURE(xReturn.is(), "OColumnImport::createElement: the factory returned an invalid object!"); + } + return xReturn; + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/eventexport.cxx b/xmloff/source/forms/eventexport.cxx new file mode 100644 index 000000000..25548fb0a --- /dev/null +++ b/xmloff/source/forms/eventexport.cxx @@ -0,0 +1,126 @@ +/* -*- 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 "eventexport.hxx" +#include "strings.hxx" +#include +#include + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + + //= OEventDescriptorMapper + OEventDescriptorMapper::OEventDescriptorMapper(const Sequence< ScriptEventDescriptor >& _rEvents) + { + // translate the events + OUString sLibrary, sLocalMacroName; + for (const auto& rEvent : _rEvents) + { + // the name of the event is build from listener interface and listener method name + OUString sName = rEvent.ListenerType + + EVENT_NAME_SEPARATOR + + rEvent.EventMethod; + + Sequence< PropertyValue >& rMappedEvent = m_aMappedEvents[sName]; + + sLocalMacroName = rEvent.ScriptCode; + sLibrary.clear(); + if (rEvent.ScriptType == EVENT_STARBASIC) + { // for StarBasic, the library name is part of the ScriptCode + sal_Int32 nPrefixLen = sLocalMacroName.indexOf( ':' ); + SAL_WARN_IF( 0 > nPrefixLen, "xmloff", "OEventDescriptorMapper::OEventDescriptorMapper: invalid script code prefix!" ); + if ( 0 <= nPrefixLen ) + { + // the export handler for StarBasic expects "StarOffice", not "application" for application modules ... + sLibrary = sLocalMacroName.copy( 0, nPrefixLen ); + if (sLibrary == EVENT_APPLICATION) + sLibrary = EVENT_STAROFFICE; + + sLocalMacroName = sLocalMacroName.copy( nPrefixLen + 1 ); + } + // tree property values to describe one event ... + rMappedEvent.realloc( sLibrary.isEmpty() ? 2 : 3 ); + auto pMappedEvent = rMappedEvent.getArray(); + + // ... the type + pMappedEvent[0] = PropertyValue(EVENT_TYPE, -1, Any(rEvent.ScriptType), PropertyState_DIRECT_VALUE); + + // and the macro name + pMappedEvent[1] = PropertyValue(EVENT_LOCALMACRONAME, -1, Any(sLocalMacroName), PropertyState_DIRECT_VALUE); + + // the library + if ( !sLibrary.isEmpty() ) + pMappedEvent[2] = PropertyValue(EVENT_LIBRARY, -1, Any(sLibrary), PropertyState_DIRECT_VALUE); + } + else + { + rMappedEvent = { PropertyValue(EVENT_TYPE, -1, Any(rEvent.ScriptType), PropertyState_DIRECT_VALUE), + // and the macro name + PropertyValue(EVENT_SCRIPTURL, -1, Any(rEvent.ScriptCode), PropertyState_DIRECT_VALUE) }; + } + } + } + + void SAL_CALL OEventDescriptorMapper::replaceByName( const OUString&, const Any& ) + { + throw IllegalArgumentException( + "replacing is not implemented for this wrapper class.", static_cast< ::cppu::OWeakObject* >(this), 1); + } + + Any SAL_CALL OEventDescriptorMapper::getByName( const OUString& _rName ) + { + MapString2PropertyValueSequence::const_iterator aPos = m_aMappedEvents.find(_rName); + if (m_aMappedEvents.end() == aPos) + throw NoSuchElementException( + "There is no element named " + _rName, + static_cast< ::cppu::OWeakObject* >(this)); + + return Any(aPos->second); + } + + Sequence< OUString > SAL_CALL OEventDescriptorMapper::getElementNames( ) + { + return comphelper::mapKeysToSequence(m_aMappedEvents); + } + + sal_Bool SAL_CALL OEventDescriptorMapper::hasByName( const OUString& _rName ) + { + MapString2PropertyValueSequence::const_iterator aPos = m_aMappedEvents.find(_rName); + return m_aMappedEvents.end() != aPos; + } + + Type SAL_CALL OEventDescriptorMapper::getElementType( ) + { + return ::cppu::UnoType::get(); + } + + sal_Bool SAL_CALL OEventDescriptorMapper::hasElements( ) + { + return !m_aMappedEvents.empty(); + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/eventexport.hxx b/xmloff/source/forms/eventexport.hxx new file mode 100644 index 000000000..c4bb752c4 --- /dev/null +++ b/xmloff/source/forms/eventexport.hxx @@ -0,0 +1,71 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include + +namespace xmloff +{ + + //= OEventDescriptorMapper + typedef ::cppu::WeakImplHelper < css::container::XNameReplace + > OEventDescriptorMapper_Base; + /** helper class wrapping different script event representations + +

In the form layer, the script events are represented by ScriptEventDescriptor + instances. The office applications, on the other hand, represent their a single script event as sequence + of PropertyValues, where all events of a given object are + accessible through a XNameReplace interface.

+

This class maps the first representation of events of a single object to the second one.

+

This way, we can use the helper classes here in the project.

+ */ + class OEventDescriptorMapper : public OEventDescriptorMapper_Base + { + typedef std::map< OUString, css::uno::Sequence < css::beans::PropertyValue > > MapString2PropertyValueSequence; + MapString2PropertyValueSequence m_aMappedEvents; + + public: + explicit OEventDescriptorMapper( + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents); + + // XNameReplace + virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override; + + // XNameAccess + virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override; + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override; + + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/eventimport.cxx b/xmloff/source/forms/eventimport.cxx new file mode 100644 index 000000000..02bfe7764 --- /dev/null +++ b/xmloff/source/forms/eventimport.cxx @@ -0,0 +1,135 @@ +/* -*- 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 "eventimport.hxx" +#include +#include +#include +#include "strings.hxx" + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::container; + + //= OFormEventsImportContext + OFormEventsImportContext::OFormEventsImportContext(SvXMLImport& _rImport, IEventAttacher& _rEventAttacher) + :XMLEventsImportContext(_rImport) + ,m_rEventAttacher(_rEventAttacher) + { + } + + void OFormEventsImportContext::endFastElement(sal_Int32 ) + { + Sequence< ScriptEventDescriptor > aTranslated(aCollectEvents.size()); + ScriptEventDescriptor* pTranslated = aTranslated.getArray(); + + // loop through the collected events and translate them + sal_Int32 nSeparatorPos = -1; + for ( const auto& rEvent : aCollectEvents ) + { + // the name of the event is built from ListenerType::EventMethod + nSeparatorPos = rEvent.first.indexOf(EVENT_NAME_SEPARATOR); + OSL_ENSURE(-1 != nSeparatorPos, "OFormEventsImportContext::EndElement: invalid (unrecognized) event name!"); + pTranslated->ListenerType = rEvent.first.copy(0, nSeparatorPos); + pTranslated->EventMethod = rEvent.first.copy(nSeparatorPos + sizeof(EVENT_NAME_SEPARATOR) - 1); + + OUString sLibrary; + + // the local macro name and the event type are specified as properties + const PropertyValue* pEventDescription = rEvent.second.getConstArray(); + const PropertyValue* pEventDescriptionEnd = pEventDescription + rEvent.second.getLength(); + for (;pEventDescription != pEventDescriptionEnd; ++pEventDescription) + { + if (pEventDescription->Name == EVENT_LOCALMACRONAME || + pEventDescription->Name == EVENT_SCRIPTURL) + pEventDescription->Value >>= pTranslated->ScriptCode; + else if (pEventDescription->Name == EVENT_TYPE) + pEventDescription->Value >>= pTranslated->ScriptType; + else if (pEventDescription->Name == EVENT_LIBRARY) + pEventDescription->Value >>= sLibrary; + } + + if (pTranslated->ScriptType == EVENT_STARBASIC) + { + if (sLibrary == EVENT_STAROFFICE) + sLibrary = EVENT_APPLICATION; + + if ( !sLibrary.isEmpty() ) + { + // for StarBasic, the library is prepended + sLibrary += ":"; + } + sLibrary += pTranslated->ScriptCode; + pTranslated->ScriptCode = sLibrary; + } + + ++pTranslated; + } + + // register the events + m_rEventAttacher.registerEvents(aTranslated); + } + + //= ODefaultEventAttacherManager + + ODefaultEventAttacherManager::~ODefaultEventAttacherManager() + { + } + + void ODefaultEventAttacherManager::registerEvents(const Reference< XPropertySet >& _rxElement, + const Sequence< ScriptEventDescriptor >& _rEvents) + { + OSL_ENSURE(m_aEvents.end() == m_aEvents.find(_rxElement), + "ODefaultEventAttacherManager::registerEvents: already have events for this object!"); + // for the moment, only remember the script events + m_aEvents[_rxElement] = _rEvents; + } + + void ODefaultEventAttacherManager::setEvents(const Reference< XIndexAccess >& _rxContainer) + { + Reference< XEventAttacherManager > xEventManager(_rxContainer, UNO_QUERY); + if (!xEventManager.is()) + { + OSL_FAIL("ODefaultEventAttacherManager::setEvents: invalid argument!"); + return; + } + + // loop through all elements + sal_Int32 nCount = _rxContainer->getCount(); + Reference< XPropertySet > xCurrent; + MapPropertySet2ScriptSequence::const_iterator aRegisteredEventsPos; + for (sal_Int32 i=0; igetByIndex(i), css::uno::UNO_QUERY); + if (xCurrent.is()) + { + aRegisteredEventsPos = m_aEvents.find(xCurrent); + if (m_aEvents.end() != aRegisteredEventsPos) + xEventManager->registerScriptEvents(i, aRegisteredEventsPos->second); + } + } + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/eventimport.hxx b/xmloff/source/forms/eventimport.hxx new file mode 100644 index 000000000..6e3f686df --- /dev/null +++ b/xmloff/source/forms/eventimport.hxx @@ -0,0 +1,77 @@ +/* -*- 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 + +#include + +#include +#include "callbacks.hxx" +#include + +class SvXMLImport; +namespace xmloff +{ + + //= OFormEventsImportContext + class OFormEventsImportContext : public XMLEventsImportContext + { + IEventAttacher& m_rEventAttacher; + + public: + OFormEventsImportContext(SvXMLImport& _rImport, + IEventAttacher& _rEventAttacher); + + protected: + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + }; + + //= ODefaultEventAttacherManager + class ODefaultEventAttacherManager : public IEventAttacherManager + { + typedef std::map< + css::uno::Reference< css::beans::XPropertySet >, + css::uno::Sequence< css::script::ScriptEventDescriptor >> + MapPropertySet2ScriptSequence; + // usually an event attacher manager will need to collect all script events registered, 'cause + // the _real_ XEventAttacherManager handles it's events by index, but out indices are not fixed + // until _all_ controls have been inserted. + + MapPropertySet2ScriptSequence m_aEvents; + + public: + // IEventAttacherManager + virtual void registerEvents( + const css::uno::Reference< css::beans::XPropertySet >& _rxElement, + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents + ) override; + + protected: + void setEvents( + const css::uno::Reference< css::container::XIndexAccess >& _rxContainer + ); + + virtual ~ODefaultEventAttacherManager(); + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formattributes.cxx b/xmloff/source/forms/formattributes.cxx new file mode 100644 index 000000000..6b7b3fb9f --- /dev/null +++ b/xmloff/source/forms/formattributes.cxx @@ -0,0 +1,405 @@ +/* -*- 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 "formattributes.hxx" + +#include +#include +#include +#include + +using namespace xmloff::token; + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + + //= OAttributeMetaData + OUString OAttributeMetaData::getCommonControlAttributeName(CCAFlags _nId) + { + switch (_nId) + { + case CCAFlags::Name: return "name"; + case CCAFlags::ServiceName: return "control-implementation"; + case CCAFlags::ButtonType: return "button-type"; +// disabled(AddAttributeIdLegacy) case CCAFlags::ControlId: return "id"; + case CCAFlags::CurrentSelected: return "current-selected"; + case CCAFlags::CurrentValue: return "current-value"; + case CCAFlags::Disabled: return "disabled"; + case CCAFlags::EnableVisible: return "visible"; + case CCAFlags::Dropdown: return "dropdown"; + case CCAFlags::For: return "for"; + case CCAFlags::ImageData: return "image-data"; + case CCAFlags::Label: return "label"; + case CCAFlags::MaxLength: return "max-length"; + case CCAFlags::Printable: return "printable"; + case CCAFlags::ReadOnly: return "readonly"; + case CCAFlags::Selected: return "selected"; + case CCAFlags::Size: return "size"; + case CCAFlags::TabIndex: return "tab-index"; + case CCAFlags::TargetFrame: return "target-frame"; + case CCAFlags::TargetLocation: return "href"; // the only special thing here: TargetLocation is represented by an xlink:href attribute + case CCAFlags::TabStop: return "tab-stop"; + case CCAFlags::Title: return "title"; + case CCAFlags::Value: return "value"; + case CCAFlags::Orientation: return "orientation"; + case CCAFlags::VisualEffect: return "visual-effect"; + default: + OSL_FAIL("OAttributeMetaData::getCommonControlAttributeName: invalid id (maybe you or-ed two flags?)!"); + } + return ""; + } + + sal_Int32 OAttributeMetaData::getCommonControlAttributeToken(CCAFlags _nId) + { + switch (_nId) + { + case CCAFlags::Name: return XML_NAME; + case CCAFlags::ServiceName: return XML_CONTROL_IMPLEMENTATION; + case CCAFlags::ButtonType: return XML_BUTTON_TYPE; +// disabled(AddAttributeIdLegacy) case CCAFlags::ControlId: return "id"; + case CCAFlags::CurrentSelected: return XML_CURRENT_SELECTED; + case CCAFlags::CurrentValue: return XML_CURRENT_VALUE; + case CCAFlags::Disabled: return XML_DISABLED; + case CCAFlags::EnableVisible: return XML_VISIBLE; + case CCAFlags::Dropdown: return XML_DROPDOWN; + case CCAFlags::For: return XML_FOR; + case CCAFlags::ImageData: return XML_IMAGE_DATA; + case CCAFlags::Label: return XML_LABEL; + case CCAFlags::MaxLength: return XML_MAX_LENGTH; + case CCAFlags::Printable: return XML_PRINTABLE; + case CCAFlags::ReadOnly: return XML_READONLY; + case CCAFlags::Selected: return XML_SELECTED; + case CCAFlags::Size: return XML_SIZE; + case CCAFlags::TabIndex: return XML_TAB_INDEX; + case CCAFlags::TargetFrame: return XML_TARGET_FRAME; + case CCAFlags::TargetLocation: return XML_HREF; // the only special thing here: TargetLocation is represented by an xlink:href attribute + case CCAFlags::TabStop: return XML_TAB_STOP; + case CCAFlags::Title: return XML_TITLE; + case CCAFlags::Value: return XML_VALUE; + case CCAFlags::Orientation: return XML_ORIENTATION; + case CCAFlags::VisualEffect: return XML_VISUAL_EFFECT; + default: + assert(false && "OAttributeMetaData::getCommonControlAttributeName: invalid id (maybe you or-ed two flags?)!"); + } + return XML_UNKNOWN; + } + + sal_uInt16 OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags _nId) + { + if (CCAFlags::TargetLocation == _nId) + return XML_NAMESPACE_XLINK; + + if (CCAFlags::TargetFrame == _nId) + return XML_NAMESPACE_OFFICE; + + return XML_NAMESPACE_FORM; + } + + OUString OAttributeMetaData::getFormAttributeName(FormAttributes _eAttrib) + { + switch (_eAttrib) + { + case faName: return "name"; + case faAction: return "href"; // the only special thing here: Action is represented by an xlink:href attribute + case faEnctype: return "enctype"; + case faMethod: return "method"; + case faAllowDeletes: return "allow-deletes"; + case faAllowInserts: return "allow-inserts"; + case faAllowUpdates: return "allow-updates"; + case faApplyFilter: return "apply-filter"; + case faCommand: return "command"; + case faCommandType: return "command-type"; + case faEscapeProcessing: return "escape-processing"; + case faDatasource: return "datasource"; + case faDetailFields: return "detail-fields"; + case faFilter: return "filter"; + case faIgnoreResult: return "ignore-result"; + case faMasterFields: return "master-fields"; + case faNavigationMode: return "navigation-mode"; + case faOrder: return "order"; + case faTabbingCycle: return "tab-cycle"; + default: + OSL_FAIL("OAttributeMetaData::getFormAttributeName: invalid id!"); + } + return ""; + } + + sal_Int32 OAttributeMetaData::getFormAttributeToken(FormAttributes _eAttrib) + { + switch (_eAttrib) + { + case faName: return XML_NAME; + case faAction: return XML_HREF; // the only special thing here: Action is represented by an xlink:href attribute + case faEnctype: return XML_ENCTYPE; + case faMethod: return XML_METHOD; + case faAllowDeletes: return XML_ALLOW_DELETES; + case faAllowInserts: return XML_ALLOW_INSERTS; + case faAllowUpdates: return XML_ALLOW_UPDATES; + case faApplyFilter: return XML_APPLY_FILTER; + case faCommand: return XML_COMMAND; + case faCommandType: return XML_COMMAND_TYPE; + case faEscapeProcessing: return XML_ESCAPE_PROCESSING; + case faDatasource: return XML_DATASOURCE; + case faDetailFields: return XML_DETAIL_FIELDS; + case faFilter: return XML_FILTER; + case faIgnoreResult: return XML_IGNORE_RESULT; + case faMasterFields: return XML_MASTER_FIELDS; + case faNavigationMode: return XML_NAVIGATION_MODE; + case faOrder: return XML_ORDER; + case faTabbingCycle: return XML_TAB_CYCLE; + default: + assert(false && "OAttributeMetaData::getFormAttributeName: invalid id!"); + } + return XML_NONE; + } + + sal_uInt16 OAttributeMetaData::getFormAttributeNamespace(FormAttributes _eAttrib) + { + if (faAction == _eAttrib) + return XML_NAMESPACE_XLINK; + + return XML_NAMESPACE_FORM; + } + + OUString OAttributeMetaData::getDatabaseAttributeName(DAFlags _nId) + { + switch (_nId) + { + case DAFlags::BoundColumn: return "bound-column"; + case DAFlags::ConvertEmpty: return "convert-empty-to-null"; + case DAFlags::DataField: return "data-field"; + case DAFlags::ListSource: return "list-source"; + case DAFlags::ListSource_TYPE: return "list-source-type"; + case DAFlags::InputRequired: return "input-required"; + default: + OSL_FAIL("OAttributeMetaData::getDatabaseAttributeName: invalid id (maybe you or-ed two flags?)!"); + } + return ""; + } + + sal_Int32 OAttributeMetaData::getDatabaseAttributeToken(DAFlags _nId) + { + switch (_nId) + { + case DAFlags::BoundColumn: return XML_BOUND_COLUMN; + case DAFlags::ConvertEmpty: return XML_CONVERT_EMPTY_TO_NULL; + case DAFlags::DataField: return XML_DATA_FIELD; + case DAFlags::ListSource: return XML_LIST_SOURCE; + case DAFlags::ListSource_TYPE: return XML_LIST_SOURCE_TYPE; + case DAFlags::InputRequired: return XML_INPUT_REQUIRED; + default: + assert(false && "OAttributeMetaData::getDatabaseAttributeName: invalid id (maybe you or-ed two flags?)!"); + } + return XML_NONE; + } + + OUString OAttributeMetaData::getBindingAttributeName(BAFlags _nId) + { + switch (_nId) + { + case BAFlags::LinkedCell: return "linked-cell"; + case BAFlags::ListLinkingType: return "list-linkage-type"; + case BAFlags::ListCellRange: return "source-cell-range"; + default: + OSL_FAIL("OAttributeMetaData::getBindingAttributeName: invalid id (maybe you or-ed two flags?)!"); + } + return ""; + } + + sal_Int32 OAttributeMetaData::getBindingAttributeToken(BAFlags _nId) + { + switch (_nId) + { + case BAFlags::LinkedCell: return XML_LINKED_CELL; + case BAFlags::ListLinkingType: return XML_LIST_LINKAGE_TYPE; + case BAFlags::ListCellRange: return XML_SOURCE_CELL_RANGE; + default: + assert(false && "OAttributeMetaData::getBindingAttributeName: invalid id (maybe you or-ed two flags?)!"); + } + return XML_UNKNOWN; + } + + OUString OAttributeMetaData::getSpecialAttributeName(SCAFlags _nId) + { + switch (_nId) + { + case SCAFlags::EchoChar: return "echo-char"; + case SCAFlags::MaxValue: return "max-value"; + case SCAFlags::MinValue: return "min-value"; + case SCAFlags::Validation: return "validation"; + case SCAFlags::GroupName: return "group-name"; + case SCAFlags::MultiLine: return "multi-line"; + case SCAFlags::AutoCompletion: return "auto-complete"; + case SCAFlags::Multiple: return "multiple"; + case SCAFlags::DefaultButton: return "default-button"; + case SCAFlags::CurrentState: return "current-state"; + case SCAFlags::IsTristate: return "is-tristate"; + case SCAFlags::State: return "state"; + case SCAFlags::ColumnStyleName: return "text-style-name"; + case SCAFlags::StepSize: return "step-size"; + case SCAFlags::PageStepSize: return "page-step-size"; + case SCAFlags::RepeatDelay: return "delay-for-repeat"; + case SCAFlags::Toggle: return "toggle"; + case SCAFlags::FocusOnClick: return "focus-on-click"; + default: + OSL_FAIL("OAttributeMetaData::getSpecialAttributeName: invalid id (maybe you or-ed two flags?)!"); + } + return ""; + } + + sal_Int32 OAttributeMetaData::getSpecialAttributeToken(SCAFlags _nId) + { + switch (_nId) + { + case SCAFlags::EchoChar: return XML_ECHO_CHAR; + case SCAFlags::MaxValue: return XML_MAX_VALUE; + case SCAFlags::MinValue: return XML_MIN_VALUE; + case SCAFlags::Validation: return XML_VALIDATION; + case SCAFlags::GroupName: return XML_GROUP_NAME; + case SCAFlags::MultiLine: return XML_MULTI_LINE; + case SCAFlags::AutoCompletion: return XML_AUTO_COMPLETE; + case SCAFlags::Multiple: return XML_MULTIPLE; + case SCAFlags::DefaultButton: return XML_DEFAULT_BUTTON; + case SCAFlags::CurrentState: return XML_CURRENT_STATE; + case SCAFlags::IsTristate: return XML_IS_TRISTATE; + case SCAFlags::State: return XML_STATE; + case SCAFlags::ColumnStyleName: return XML_TEXT_STYLE_NAME; + case SCAFlags::StepSize: return XML_STEP_SIZE; + case SCAFlags::PageStepSize: return XML_PAGE_STEP_SIZE; + case SCAFlags::RepeatDelay: return XML_DELAY_FOR_REPEAT; + case SCAFlags::Toggle: return XML_TOGGLE; + case SCAFlags::FocusOnClick: return XML_FOCUS_ON_CLICK; + default: + assert(false && "OAttributeMetaData::getSpecialAttributeName: invalid id (maybe you or-ed two flags?)!"); + } + return XML_UNKNOWN; + } + + sal_uInt16 OAttributeMetaData::getSpecialAttributeNamespace(SCAFlags _nId) + { + switch( _nId ) + { + case SCAFlags::GroupName: return XML_NAMESPACE_FORMX; + default: break; + } + return XML_NAMESPACE_FORM; + } + + OUString OAttributeMetaData::getOfficeFormsAttributeName(OfficeFormsAttributes _eAttrib) + { + switch (_eAttrib) + { + case ofaAutomaticFocus: return "automatic-focus"; + case ofaApplyDesignMode: return "apply-design-mode"; + default: + OSL_FAIL("OAttributeMetaData::getOfficeFormsAttributeName: invalid id!"); + } + return ""; + } + + xmloff::token::XMLTokenEnum OAttributeMetaData::getOfficeFormsAttributeToken(OfficeFormsAttributes _eAttrib) + { + switch (_eAttrib) + { + case ofaAutomaticFocus: return token::XML_AUTOMATIC_FOCUS; + case ofaApplyDesignMode: return token::XML_APPLY_DESIGN_MODE; + default: + assert(false && "OAttributeMetaData::getOfficeFormsAttributeName: invalid id!"); + } + return token::XML_NONE; + } + + //= OAttribute2Property + OAttribute2Property::OAttribute2Property() + { + } + + OAttribute2Property::~OAttribute2Property() + { + } + + const OAttribute2Property::AttributeAssignment* OAttribute2Property::getAttributeTranslation( + sal_Int32 nAttributeToken) + { + auto aPos = m_aKnownProperties.find(nAttributeToken & TOKEN_MASK); + if (m_aKnownProperties.end() != aPos) + return &aPos->second; + return nullptr; + } + + void OAttribute2Property::addStringProperty( + sal_Int32 nAttributeToken, const OUString& _rPropertyName) + { + implAdd(nAttributeToken, _rPropertyName, ::cppu::UnoType::get()); + } + + void OAttribute2Property::addBooleanProperty( + sal_Int32 nAttributeToken, const OUString& _rPropertyName, + const bool /*_bAttributeDefault*/, const bool _bInverseSemantics) + { + AttributeAssignment& aAssignment = implAdd(nAttributeToken, _rPropertyName, cppu::UnoType::get()); + aAssignment.bInverseSemantics = _bInverseSemantics; + } + + void OAttribute2Property::addInt16Property( + sal_Int32 nAttributeToken, const OUString& _rPropertyName) + { + implAdd(nAttributeToken, _rPropertyName, ::cppu::UnoType::get()); + } + + void OAttribute2Property::addInt32Property( + sal_Int32 nAttributeToken, const OUString& _rPropertyName) + { + implAdd( nAttributeToken, _rPropertyName, ::cppu::UnoType::get() ); + } + + void OAttribute2Property::addEnumPropertyImpl( + sal_Int32 nAttributeToken, const OUString& _rPropertyName, + const SvXMLEnumMapEntry* _pValueMap, + const css::uno::Type* _pType) + { + AttributeAssignment& aAssignment = implAdd(nAttributeToken, _rPropertyName, + _pType ? *_pType : ::cppu::UnoType::get()); + aAssignment.pEnumMap = _pValueMap; + } + + OAttribute2Property::AttributeAssignment& OAttribute2Property::implAdd( + sal_Int32 nAttributeToken, const OUString& _rPropertyName, + const css::uno::Type& _rType) + { + nAttributeToken &= TOKEN_MASK; + OSL_ENSURE(m_aKnownProperties.end() == m_aKnownProperties.find(nAttributeToken), + "OAttribute2Property::implAdd: already have this attribute!"); + + AttributeAssignment aAssignment; + aAssignment.sPropertyName = _rPropertyName; + aAssignment.aPropertyType = _rType; + + // redundance, the accessor is stored in aAssignment.sAttributeName, too + m_aKnownProperties[nAttributeToken] = aAssignment; + return m_aKnownProperties[nAttributeToken]; + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formattributes.hxx b/xmloff/source/forms/formattributes.hxx new file mode 100644 index 000000000..ae36fd65d --- /dev/null +++ b/xmloff/source/forms/formattributes.hxx @@ -0,0 +1,414 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include +#include + +template +struct SvXMLEnumMapEntry; + + // flags for common control attributes +enum class CCAFlags { + NONE = 0x00000000, + Name = 0x00000001, + ServiceName = 0x00000002, + ButtonType = 0x00000004, + ControlId = 0x00000008, + CurrentSelected = 0x00000010, + CurrentValue = 0x00000020, + Disabled = 0x00000040, + Dropdown = 0x00000080, + For = 0x00000100, + ImageData = 0x00000200, + Label = 0x00000400, + MaxLength = 0x00000800, + Printable = 0x00001000, + ReadOnly = 0x00002000, + Selected = 0x00004000, + Size = 0x00008000, + TabIndex = 0x00010000, + TargetFrame = 0x00020000, + TargetLocation = 0x00040000, + TabStop = 0x00080000, + Title = 0x00100000, + Value = 0x00200000, + Orientation = 0x00400000, + VisualEffect = 0x00800000, + EnableVisible = 0x01000000, +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + + // flags for database control attributes +enum class DAFlags { + NONE = 0x0000, + BoundColumn = 0x0001, + ConvertEmpty = 0x0002, + DataField = 0x0004, + ListSource = 0x0008, + ListSource_TYPE = 0x0010, + InputRequired = 0x0020, +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + + // flags for binding related control attributes +enum class BAFlags { + NONE = 0x0000, + LinkedCell = 0x0001, + ListLinkingType = 0x0002, + ListCellRange = 0x0004, + XFormsBind = 0x0008, + XFormsListBind = 0x0010, + XFormsSubmission = 0x0020 +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + + // flags for event attributes +enum class EAFlags { + NONE = 0x0000, + ControlEvents = 0x0001, + OnChange = 0x0002, + OnClick = 0x0004, + OnDoubleClick = 0x0008, + OnSelect = 0x0010 +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + + // any other attributes, which are special to some control types +enum class SCAFlags { + NONE = 0x000000, + EchoChar = 0x000001, + MaxValue = 0x000002, + MinValue = 0x000004, + Validation = 0x000008, + GroupName = 0x000010, + MultiLine = 0x000020, + AutoCompletion = 0x000080, + Multiple = 0x000100, + DefaultButton = 0x000200, + CurrentState = 0x000400, + IsTristate = 0x000800, + State = 0x001000, + ColumnStyleName = 0x002000, + StepSize = 0x004000, + PageStepSize = 0x008000, + RepeatDelay = 0x010000, + Toggle = 0x020000, + FocusOnClick = 0x040000, + ImagePosition = 0x080000 +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + + +namespace xmloff +{ + + /// attributes in the xml tag representing a form + enum FormAttributes + { + faName, + faAction, + faEnctype, + faMethod, + faAllowDeletes, + faAllowInserts, + faAllowUpdates, + faApplyFilter, + faCommand, + faCommandType, + faEscapeProcessing, + faDatasource, + faDetailFields, + faFilter, + faIgnoreResult, + faMasterFields, + faNavigationMode, + faOrder, + faTabbingCycle + }; + + // attributes of the office:forms element + enum OfficeFormsAttributes + { + ofaAutomaticFocus, + ofaApplyDesignMode + }; + + //= OAttributeMetaData + /** allows the translation of attribute ids into strings. + +

This class does not allow to connect xml attributes to property names or + something like that, it only deals with the xml side

+ */ + class OAttributeMetaData + { + public: + /** calculates the xml attribute representation of a common control attribute. + @param _nId + the id of the attribute. Has to be one of the CCA_* constants. + */ + static OUString getCommonControlAttributeName(CCAFlags _nId); + + /** calculates the xml attribute representation of a common control attribute. + @param _nId + the id of the attribute. Has to be one of the CCA_* constants. + */ + static sal_Int32 getCommonControlAttributeToken(CCAFlags _nId); + + /** calculates the xml namespace key to use for a common control attribute + @param _nId + the id of the attribute. Has to be one of the CCA_* constants. + */ + static sal_uInt16 getCommonControlAttributeNamespace(CCAFlags _nId); + + /** retrieves the name of an attribute of a form xml representation + @param _eAttrib + enum value specifying the attribute + */ + static OUString getFormAttributeName(FormAttributes _eAttrib); + + /** retrieves the name of an attribute of a form xml representation + @param _eAttrib + enum value specifying the attribute + */ + static sal_Int32 getFormAttributeToken(FormAttributes _eAttrib); + + /** calculates the xml namespace key to use for an attribute of a form xml representation + @param _eAttrib + enum value specifying the attribute + */ + static sal_uInt16 getFormAttributeNamespace(FormAttributes _eAttrib); + + /** calculates the xml attribute representation of a database attribute. + @param _nId + the id of the attribute. Has to be one of the DA_* constants. + */ + static OUString getDatabaseAttributeName(DAFlags _nId); + + /** calculates the xml attribute representation of a database attribute. + @param _nId + the id of the attribute. Has to be one of the DA_* constants. + */ + static sal_Int32 getDatabaseAttributeToken(DAFlags _nId); + + /** calculates the xml namespace key to use for a database attribute. + @param _nId + the id of the attribute. Has to be one of the DA_* constants. + */ + static sal_uInt16 getDatabaseAttributeNamespace() + { + // nothing special here + return XML_NAMESPACE_FORM; + } + + /** calculates the xml attribute representation of a special attribute. + @param _nId + the id of the attribute. Has to be one of the SCA_* constants. + */ + static OUString getSpecialAttributeName(SCAFlags _nId); + + /** calculates the xml attribute representation of a special attribute. + @param _nId + the id of the attribute. Has to be one of the SCA_* constants. + */ + static sal_Int32 getSpecialAttributeToken(SCAFlags _nId); + + /** calculates the xml attribute representation of a binding attribute. + @param _nId + the id of the attribute. Has to be one of the BA_* constants. + */ + static OUString getBindingAttributeName(BAFlags _nId); + + /** calculates the xml attribute representation of a binding attribute. + @param _nId + the id of the attribute. Has to be one of the BA_* constants. + */ + static sal_Int32 getBindingAttributeToken(BAFlags _nId); + + /** calculates the xml namespace key to use for a binding attribute. + @param _nId + the id of the attribute. Has to be one of the BA_* constants. + */ + static sal_uInt16 getBindingAttributeNamespace() + { + // nothing special here + return XML_NAMESPACE_FORM; + } + + /** calculates the xml namespace key to use for a special attribute. + @param _nId + the id of the attribute. Has to be one of the SCA_* constants. + */ + static sal_uInt16 getSpecialAttributeNamespace(SCAFlags _nId); + + /** calculates the xml attribute representation of an attribute of the office:forms element + @param _nId + the id of the attribute + */ + static OUString getOfficeFormsAttributeName(OfficeFormsAttributes _eAttrib); + static xmloff::token::XMLTokenEnum getOfficeFormsAttributeToken(OfficeFormsAttributes _eAttrib); + + /** calculates the xml namedspace key of an attribute of the office:forms element + @param _nId + the id of the attribute + */ + static sal_uInt16 getOfficeFormsAttributeNamespace() + { // nothing special here + return XML_NAMESPACE_FORM; + } + }; + + //= OAttribute2Property + /** some kind of opposite to the OAttributeMetaData class. Able to translate + attributes into property names/types + +

The construction of this class is rather expensive (or at least it's initialization from outside), + so it should be shared

+ */ + class OAttribute2Property final + { + public: + // TODO: maybe the following struct should be used for exports, too. In this case we would not need to + // store it's instances in a map, but in a vector for faster access. + struct AttributeAssignment + { + OUString sPropertyName; // the property name + css::uno::Type aPropertyType; // the property type + + // entries which are special to some value types + const SvXMLEnumMapEntry* + pEnumMap; // the enum map, if applicable + bool bInverseSemantics; // for booleans: attribute and property value have the same or an inverse semantics? + + AttributeAssignment() : pEnumMap(nullptr), bInverseSemantics(false) { } + }; + + private: + std::map m_aKnownProperties; + + public: + OAttribute2Property(); + ~OAttribute2Property(); + + /** return the AttributeAssignment which corresponds to the given attribute + + @return + a pointer to the AttributeAssignment structure as requested, NULL if the attribute + does not represent a property. + */ + const AttributeAssignment* getAttributeTranslation(sal_Int32 nAttributeToken); + + /** add an attribute assignment referring to a string property to the map + @param _pAttributeName + the name of the attribute + @param _rPropertyName + the name of the property assigned to the attribute + */ + void addStringProperty( + sal_Int32 nAttributeToken, const OUString& _rPropertyName); + + /** add an attribute assignment referring to a boolean property to the map + + @param _pAttributeName + the name of the attribute + @param _rPropertyName + the name of the property assigned to the attribute + @param _bAttributeDefault + the default value for the attribute. + @param _bInverseSemantics + if , an attribute value of means a property value of and vice verse.
+ if , the attribute value is used as property value directly + */ + void addBooleanProperty( + sal_Int32 nAttributeToken, const OUString& _rPropertyName, + const bool _bAttributeDefault, const bool _bInverseSemantics = false); + + /** add an attribute assignment referring to an int16 property to the map + + @param _pAttributeName + the name of the attribute + @param _rPropertyName + the name of the property assigned to the attribute + */ + void addInt16Property( + sal_Int32 nAttributeToken, const OUString& _rPropertyName); + + /** add an attribute assignment referring to an int32 property to the map + + @param _pAttributeName + the name of the attribute + @param _rPropertyName + the name of the property assigned to the attribute + */ + void addInt32Property( + sal_Int32 nAttributeToken, const OUString& _rPropertyName ); + + /** add an attribute assignment referring to an enum property to the map + + @param _pAttributeName + the name of the attribute + @param _rPropertyName + the name of the property assigned to the attribute + @param _pValueMap + the map to translate strings into enum values + @param _pType + the type of the property. May be NULL, in this case 32bit integer is assumed. + */ + template + void addEnumProperty( + sal_Int32 nAttributeToken, const OUString& _rPropertyName, + const SvXMLEnumMapEntry* _pValueMap, + const css::uno::Type* _pType = nullptr) + { + addEnumPropertyImpl(nAttributeToken, _rPropertyName, + reinterpret_cast*>(_pValueMap), _pType); + } + + private: + void addEnumPropertyImpl( + sal_Int32 nAttributeToken, const OUString& _rPropertyName, + const SvXMLEnumMapEntry* _pValueMap, + const css::uno::Type* _pType); + /// some common code for the various add*Property methods + AttributeAssignment& implAdd( + sal_Int32 nAttributeToken, const OUString& _rPropertyName, + const css::uno::Type& _rType); + }; +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formcellbinding.cxx b/xmloff/source/forms/formcellbinding.cxx new file mode 100644 index 000000000..e9220fd79 --- /dev/null +++ b/xmloff/source/forms/formcellbinding.cxx @@ -0,0 +1,433 @@ +/* -*- 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 "formcellbinding.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "strings.hxx" +#include +#include + +#include + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::sheet; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::drawing; + using namespace ::com::sun::star::table; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::form::binding; + +namespace +{ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::container::XChild; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::uno::UNO_QUERY; + + template< class TYPE > + Reference< TYPE > getTypedModelNode( const Reference< XInterface >& _rxModelNode ) + { + Reference< TYPE > xTypedNode( _rxModelNode, UNO_QUERY ); + if ( xTypedNode.is() ) + return xTypedNode; + else + { + Reference< XChild > xChild( _rxModelNode, UNO_QUERY ); + if ( xChild.is() ) + return getTypedModelNode< TYPE >( xChild->getParent() ); + else + return nullptr; + } + } + + Reference< XModel > getDocument( const Reference< XInterface >& _rxModelNode ) + { + return getTypedModelNode< XModel >( _rxModelNode ); + } + + struct StringCompare + { + private: + const OUString & m_sReference; + + public: + explicit StringCompare( const OUString& _rReference ) : m_sReference( _rReference ) { } + + bool operator()( std::u16string_view _rCompare ) + { + return ( _rCompare == m_sReference ); + } + }; +} + +//= FormCellBindingHelper +FormCellBindingHelper::FormCellBindingHelper( const Reference< XPropertySet >& _rxControlModel, const Reference< XModel >& _rxDocument ) + :m_xControlModel( _rxControlModel ) + ,m_xDocument( _rxDocument, UNO_QUERY ) +{ + OSL_ENSURE( m_xControlModel.is(), "FormCellBindingHelper::FormCellBindingHelper: invalid control model!" ); + + if ( !m_xDocument.is() ) + m_xDocument.set(getDocument( m_xControlModel ), css::uno::UNO_QUERY); + OSL_ENSURE( m_xDocument.is(), "FormCellBindingHelper::FormCellBindingHelper: Did not find the spreadsheet document!" ); +} + +bool FormCellBindingHelper::livesInSpreadsheetDocument( const Reference< XPropertySet >& _rxControlModel ) +{ + Reference< XSpreadsheetDocument > xDocument( getDocument( _rxControlModel ), UNO_QUERY ); + return xDocument.is(); +} + +bool FormCellBindingHelper::convertStringAddress( const OUString& _rAddressDescription, CellAddress& /* [out] */ _rAddress ) const +{ + Any aAddress; + return doConvertAddressRepresentations( + PROPERTY_FILE_REPRESENTATION, + Any( _rAddressDescription ), + PROPERTY_ADDRESS, + aAddress, + false + ) + && ( aAddress >>= _rAddress ); +} + +bool FormCellBindingHelper::convertStringAddress( const OUString& _rAddressDescription, + CellRangeAddress& /* [out] */ _rAddress ) const +{ + Any aAddress; + return doConvertAddressRepresentations( + PROPERTY_FILE_REPRESENTATION, + Any( _rAddressDescription ), + PROPERTY_ADDRESS, + aAddress, + true + ) + && ( aAddress >>= _rAddress ); +} + +Reference< XValueBinding > FormCellBindingHelper::createCellBindingFromStringAddress( const OUString& _rAddress, bool _bUseIntegerBinding ) const +{ + Reference< XValueBinding > xBinding; + if ( !m_xDocument.is() ) + // very bad ... + return xBinding; + + // get the UNO representation of the address + CellAddress aAddress; + if ( _rAddress.isEmpty() || !convertStringAddress( _rAddress, aAddress ) ) + return xBinding; + + xBinding.set(createDocumentDependentInstance( + _bUseIntegerBinding ? OUString(SERVICE_LISTINDEXCELLBINDING) : OUString(SERVICE_CELLVALUEBINDING), + PROPERTY_BOUND_CELL, + Any( aAddress ) + ), css::uno::UNO_QUERY); + + return xBinding; +} + +Reference< XListEntrySource > FormCellBindingHelper::createCellListSourceFromStringAddress( const OUString& _rAddress ) const +{ + Reference< XListEntrySource > xSource; + + CellRangeAddress aRangeAddress; + if ( !convertStringAddress( _rAddress, aRangeAddress ) ) + return xSource; + + // create a range object for this address + xSource.set(createDocumentDependentInstance( + SERVICE_CELLRANGELISTSOURCE, + PROPERTY_LIST_CELL_RANGE, + Any( aRangeAddress ) + ), css::uno::UNO_QUERY); + + return xSource; +} + +OUString FormCellBindingHelper::getStringAddressFromCellBinding( const Reference< XValueBinding >& _rxBinding ) const +{ + OSL_PRECOND( !_rxBinding.is() || isCellBinding( _rxBinding ), "FormCellBindingHelper::getStringAddressFromCellBinding: this is no cell binding!" ); + + OUString sAddress; + try + { + Reference< XPropertySet > xBindingProps( _rxBinding, UNO_QUERY ); + OSL_ENSURE( xBindingProps.is() || !_rxBinding.is(), "FormCellBindingHelper::getStringAddressFromCellBinding: no property set for the binding!" ); + if ( xBindingProps.is() ) + { + CellAddress aAddress; + xBindingProps->getPropertyValue( PROPERTY_BOUND_CELL ) >>= aAddress; + + Any aStringAddress; + doConvertAddressRepresentations( PROPERTY_ADDRESS, Any( aAddress ), + PROPERTY_FILE_REPRESENTATION, aStringAddress, false ); + + aStringAddress >>= sAddress; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::getStringAddressFromCellBinding" ); + } + + return sAddress; +} + +OUString FormCellBindingHelper::getStringAddressFromCellListSource( const Reference< XListEntrySource >& _rxSource ) const +{ + OSL_PRECOND( !_rxSource.is() || isCellRangeListSource( _rxSource ), "FormCellBindingHelper::getStringAddressFromCellListSource: this is no cell list source!" ); + + OUString sAddress; + try + { + Reference< XPropertySet > xSourceProps( _rxSource, UNO_QUERY ); + OSL_ENSURE( xSourceProps.is() || !_rxSource.is(), "FormCellBindingHelper::getStringAddressFromCellListSource: no property set for the list source!" ); + if ( xSourceProps.is() ) + { + CellRangeAddress aRangeAddress; + xSourceProps->getPropertyValue( PROPERTY_LIST_CELL_RANGE ) >>= aRangeAddress; + + Any aStringAddress; + doConvertAddressRepresentations( PROPERTY_ADDRESS, Any( aRangeAddress ), + PROPERTY_FILE_REPRESENTATION, aStringAddress, true ); + aStringAddress >>= sAddress; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::getStringAddressFromCellListSource" ); + } + + return sAddress; +} + +bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const Reference< XSpreadsheetDocument >& _rxDocument, const OUString& _rService ) +{ + bool bYesItIs = false; + + try + { + Reference< XServiceInfo > xSI( _rxDocument, UNO_QUERY ); + if ( xSI.is() && xSI->supportsService( SERVICE_SPREADSHEET_DOCUMENT ) ) + { + Reference< XMultiServiceFactory > xDocumentFactory( _rxDocument, UNO_QUERY ); + OSL_ENSURE( xDocumentFactory.is(), "FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies: spreadsheet document, but no factory?" ); + + if ( xDocumentFactory.is() ) + { + const Sequence aAvailableServices = xDocumentFactory->getAvailableServiceNames( ); + + bYesItIs = std::any_of( aAvailableServices.begin(), aAvailableServices.end(), StringCompare( _rService ) ); + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies" ); + } + + return bYesItIs; +} + +bool FormCellBindingHelper::isSpreadsheetDocumentWhichSupplies( const OUString& _rService ) const +{ + return isSpreadsheetDocumentWhichSupplies( m_xDocument, _rService ); +} + +bool FormCellBindingHelper::isListCellRangeAllowed( const Reference< XModel >& _rxDocument ) +{ + return isSpreadsheetDocumentWhichSupplies( + Reference< XSpreadsheetDocument >( _rxDocument, UNO_QUERY ), + SERVICE_CELLRANGELISTSOURCE + ); +} + +bool FormCellBindingHelper::isListCellRangeAllowed( ) const +{ + bool bAllow( false ); + + Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); + if ( xSink.is() ) + { + bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_CELLRANGELISTSOURCE ); + } + + return bAllow; +} + +bool FormCellBindingHelper::isCellBindingAllowed( ) const +{ + bool bAllow( false ); + + Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); + if ( xBindable.is() ) + { + // the control can potentially be bound to an external value + // Does it live within a Calc document, and is able to supply CellBindings? + bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_CELLVALUEBINDING ); + } + + return bAllow; +} + +bool FormCellBindingHelper::isCellBindingAllowed( const Reference< XModel >& _rxDocument ) +{ + return isSpreadsheetDocumentWhichSupplies( + Reference< XSpreadsheetDocument >( _rxDocument, UNO_QUERY ), + SERVICE_CELLVALUEBINDING + ); +} + +bool FormCellBindingHelper::isCellBinding( const Reference< XValueBinding >& _rxBinding ) +{ + return doesComponentSupport( _rxBinding, SERVICE_CELLVALUEBINDING ); +} + +bool FormCellBindingHelper::isCellIntegerBinding( const Reference< XValueBinding >& _rxBinding ) +{ + return doesComponentSupport( _rxBinding, SERVICE_LISTINDEXCELLBINDING ); +} + +bool FormCellBindingHelper::isCellRangeListSource( const Reference< XListEntrySource >& _rxSource ) +{ + return doesComponentSupport( _rxSource, SERVICE_CELLRANGELISTSOURCE ); +} + +bool FormCellBindingHelper::doesComponentSupport( const Reference< XInterface >& _rxComponent, const OUString& _rService ) +{ + Reference< XServiceInfo > xSI( _rxComponent, UNO_QUERY ); + bool bDoes = xSI.is() && xSI->supportsService( _rService ); + return bDoes; +} + +Reference< XValueBinding > FormCellBindingHelper::getCurrentBinding( ) const +{ + Reference< XValueBinding > xBinding; + Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); + if ( xBindable.is() ) + xBinding = xBindable->getValueBinding(); + return xBinding; +} + +Reference< XListEntrySource > FormCellBindingHelper::getCurrentListSource( ) const +{ + Reference< XListEntrySource > xSource; + Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); + if ( xSink.is() ) + xSource = xSink->getListEntrySource(); + return xSource; +} + +void FormCellBindingHelper::setBinding( const Reference< XValueBinding >& _rxBinding ) +{ + Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); + OSL_PRECOND( xBindable.is(), "FormCellBindingHelper::setBinding: the object is not bindable!" ); + if ( xBindable.is() ) + xBindable->setValueBinding( _rxBinding ); +} + +void FormCellBindingHelper::setListSource( const Reference< XListEntrySource >& _rxSource ) +{ + Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); + OSL_PRECOND( xSink.is(), "FormCellBindingHelper::setListSource: the object is no list entry sink!" ); + if ( xSink.is() ) + xSink->setListEntrySource( _rxSource ); +} + +Reference< XInterface > FormCellBindingHelper::createDocumentDependentInstance( const OUString& _rService, const OUString& _rArgumentName, + const Any& _rArgumentValue ) const +{ + Reference< XInterface > xReturn; + + Reference< XMultiServiceFactory > xDocumentFactory( m_xDocument, UNO_QUERY ); + OSL_ENSURE( xDocumentFactory.is(), "FormCellBindingHelper::createDocumentDependentInstance: no document service factory!" ); + if ( xDocumentFactory.is() ) + { + try + { + if ( !_rArgumentName.isEmpty() ) + { + NamedValue aArg; + aArg.Name = _rArgumentName; + aArg.Value = _rArgumentValue; + + Sequence< Any > aArgs{ Any(aArg) }; + xReturn = xDocumentFactory->createInstanceWithArguments( _rService, aArgs ); + } + else + { + xReturn = xDocumentFactory->createInstance( _rService ); + } + } + catch ( const Exception& ) + { + OSL_FAIL( "FormCellBindingHelper::createDocumentDependentInstance: could not create the binding at the document!" ); + } + } + return xReturn; +} + +bool FormCellBindingHelper::doConvertAddressRepresentations( const OUString& _rInputProperty, const Any& _rInputValue, + const OUString& _rOutputProperty, Any& _rOutputValue, bool _bIsRange ) const +{ + bool bSuccess = false; + + Reference< XPropertySet > xConverter( + createDocumentDependentInstance( + _bIsRange ? OUString(SERVICE_RANGEADDRESS_CONVERSION) : OUString(SERVICE_ADDRESS_CONVERSION), + OUString(), + Any() + ), + UNO_QUERY + ); + OSL_ENSURE( xConverter.is(), "FormCellBindingHelper::doConvertAddressRepresentations: could not get a converter service!" ); + if ( xConverter.is() ) + { + try + { + xConverter->setPropertyValue( _rInputProperty, _rInputValue ); + _rOutputValue = xConverter->getPropertyValue( _rOutputProperty ); + bSuccess = true; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "xmloff", "FormCellBindingHelper::doConvertAddressRepresentations" ); + } + } + + return bSuccess; +} + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formcellbinding.hxx b/xmloff/source/forms/formcellbinding.hxx new file mode 100644 index 000000000..a05413181 --- /dev/null +++ b/xmloff/source/forms/formcellbinding.hxx @@ -0,0 +1,260 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +namespace xmloff +{ + + //= FormCellBindingHelper + /** encapsulates functionality related to binding a form control to a spreadsheet cell + */ + class FormCellBindingHelper + { + css::uno::Reference< css::beans::XPropertySet > + m_xControlModel; // the model we work for + css::uno::Reference< css::sheet::XSpreadsheetDocument > + m_xDocument; // the document where the model lives + + public: + /** determines whether the given control model lives in a spreadsheet document +

If this method returns , you cannot instantiate a CellBindingHelper with + this model, since then no of its functionality will be available.

+ */ + static bool livesInSpreadsheetDocument( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel + ); + + /** ctor + @param _rxControlModel + the control model which is or will be bound + @param _rxDocument + the document. If this is , the document will be obtained from the model + itself by walk on up the chain of its ancestors.
+ This parameter can be used if the control model is not (yet) part of a document + model. + */ + FormCellBindingHelper( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const css::uno::Reference< css::frame::XModel >& _rxDocument + ); + + /** gets a cell binding for the given address + @precond + isCellBindingAllowed returns + */ + css::uno::Reference< css::form::binding::XValueBinding > + createCellBindingFromStringAddress( + const OUString& _rAddress, + bool _bUseIntegerBinding + ) const; + + /** gets a cell range list source binding for the given address + */ + css::uno::Reference< css::form::binding::XListEntrySource > + createCellListSourceFromStringAddress( const OUString& _rAddress ) const; + + /** creates a string representation for the given value binding's address + +

If the sheet of the bound cell is the same as the sheet which our control belongs + to, then the sheet name is omitted in the resulting string representation.

+ + @precond + The binding is a valid cell binding, or + @see isCellBinding + */ + OUString getStringAddressFromCellBinding( + const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding + ) const; + + /** creates a string representation for the given list source's range address + +

If the sheet of the cell range which acts as list source is the same as the + sheet which our control belongs to, then the sheet name is omitted in the + resulting string representation.

+ + @precond + The object is a valid cell range list source, or + @see isCellRangeListSource + */ + OUString getStringAddressFromCellListSource( + const css::uno::Reference< css::form::binding::XListEntrySource >& _rxSource + ) const; + + /** returns the current binding of our control model, if any. + */ + css::uno::Reference< css::form::binding::XValueBinding > + getCurrentBinding( ) const; + + /** returns the current external list source of the control model, if any + */ + css::uno::Reference< css::form::binding::XListEntrySource > + getCurrentListSource( ) const; + + /** sets a new binding for our control model + @precond + the control model is bindable (which is implied by isCellBindingAllowed + returning ) + */ + void setBinding( + const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding + ); + + /** sets a list source for our control model + @precond + the control model is a list sink (which is implied by isListCellRangeAllowed + returning ) + */ + void setListSource( + const css::uno::Reference< css::form::binding::XListEntrySource >& _rxSource + ); + + /** checks whether it's possible to bind the control model to a spreadsheet cell + */ + bool isCellBindingAllowed( ) const; + + /** checks whether within the given document, it's possible to bind control models to spreadsheet cells + */ + static bool isCellBindingAllowed( + const css::uno::Reference< css::frame::XModel >& _rxDocument + ); + + /** checks whether it's possible to bind the control model to a range of spreadsheet cells + supplying the list entries + */ + bool isListCellRangeAllowed( ) const; + + /** checks whether within the given document, it's possible to bind the control model to a range of + spreadsheet cells supplying the list entries + */ + static bool isListCellRangeAllowed( + const css::uno::Reference< css::frame::XModel >& _rxDocument + ); + + /** checks whether a given binding is a spreadsheet cell binding + */ + static bool isCellBinding( + const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding + ); + + /** checks whether a given binding is a spreadsheet cell binding, exchanging + integer values + */ + static bool isCellIntegerBinding( + const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding + ); + + /** checks whether a given list source is a spreadsheet cell list source + */ + static bool isCellRangeListSource( + const css::uno::Reference< css::form::binding::XListEntrySource >& _rxSource + ); + + private: + /** creates an address object from a string representation of a cell address + */ + bool convertStringAddress( + const OUString& _rAddressDescription, + css::table::CellAddress& /* [out] */ _rAddress + ) const; + + /** creates an address range object from a string representation of a cell range address + */ + bool convertStringAddress( + const OUString& _rAddressDescription, + css::table::CellRangeAddress& /* [out] */ _rAddress + ) const; + + /** determines if our document is a spreadsheet document, *and* can supply + the given service + */ + bool isSpreadsheetDocumentWhichSupplies( const OUString& _rService ) const; + + /** determines if our document is a spreadsheet document, *and* can supply + the given service + */ + static bool isSpreadsheetDocumentWhichSupplies( + const css::uno::Reference< css::sheet::XSpreadsheetDocument >& _rxDocument, + const OUString& _rService + ); + + /** checks whether a given component supports a given service + */ + static bool doesComponentSupport( + const css::uno::Reference< css::uno::XInterface >& _rxComponent, + const OUString& _rService + ); + + /** uses the document (it's factory interface, respectively) to create a component instance + @param _rService + the service name + @param _rArgumentName + the name of the single argument to pass during creation. May be empty, in this case + no arguments are passed + @param _rArgumentValue + the value of the instantiation argument. Not evaluated if _rArgumentName + is empty. + */ + css::uno::Reference< css::uno::XInterface > + createDocumentDependentInstance( + const OUString& _rService, + const OUString& _rArgumentName, + const css::uno::Any& _rArgumentValue + ) const; + + /** converts an address representation into another one + + @param _rInputProperty + the input property name for the conversion service + @param _rInputValue + the input property value for the conversion service + @param _rOutputProperty + the output property name for the conversion service + @param _rOutputValue + the output property value for the conversion service + @param _bIsRange + if , the RangeAddressConversion service will be used, else + the AddressConversion service + + @return + if any only if the conversion was successful + + @see css::table::CellAddressConversion + @see css::table::CellRangeAddressConversion + */ + bool doConvertAddressRepresentations( + const OUString& _rInputProperty, + const css::uno::Any& _rInputValue, + const OUString& _rOutputProperty, + css::uno::Any& _rOutputValue, + bool _bIsRange + ) const; + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formenums.cxx b/xmloff/source/forms/formenums.cxx new file mode 100644 index 000000000..31567ddf7 --- /dev/null +++ b/xmloff/source/forms/formenums.cxx @@ -0,0 +1,191 @@ +/* -*- 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 "formenums.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xmloff +{ + +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +const SvXMLEnumMapEntry aSubmitEncodingMap[] = +{ + { XML_APPLICATION_X_WWW_FORM_URLENCODED, FormSubmitEncoding_URL }, + { XML_MULTIPART_FORMDATA, FormSubmitEncoding_MULTIPART }, + { XML_APPLICATION_TEXT, FormSubmitEncoding_TEXT }, + { XML_TOKEN_INVALID, FormSubmitEncoding(0) } +}; +const SvXMLEnumMapEntry aSubmitMethodMap[] = +{ + { XML_GET, FormSubmitMethod_GET }, + { XML_POST, FormSubmitMethod_POST }, + { XML_TOKEN_INVALID, FormSubmitMethod(0) } +}; +const SvXMLEnumMapEntry aCommandTypeMap[] = +{ + { XML_TABLE, CommandType::TABLE }, + { XML_QUERY, CommandType::QUERY }, + { XML_COMMAND, CommandType::COMMAND }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aNavigationTypeMap[] = +{ + { XML_NONE, NavigationBarMode_NONE }, + { XML_CURRENT, NavigationBarMode_CURRENT }, + { XML_PARENT, NavigationBarMode_PARENT }, + { XML_TOKEN_INVALID, NavigationBarMode(0) } +}; +const SvXMLEnumMapEntry aTabulatorCycleMap[] = +{ + { XML_RECORDS, TabulatorCycle_RECORDS }, + { XML_CURRENT, TabulatorCycle_CURRENT }, + { XML_PAGE, TabulatorCycle_PAGE }, + { XML_TOKEN_INVALID, TabulatorCycle(0) } +}; +const SvXMLEnumMapEntry aFormButtonTypeMap[] = +{ + { XML_PUSH, FormButtonType_PUSH }, + { XML_SUBMIT, FormButtonType_SUBMIT }, + { XML_RESET, FormButtonType_RESET }, + { XML_URL, FormButtonType_URL }, + { XML_TOKEN_INVALID, FormButtonType(0) } +}; +const SvXMLEnumMapEntry aListSourceTypeMap[] = +{ + { XML_VALUE_LIST, ListSourceType_VALUELIST }, + { XML_TABLE, ListSourceType_TABLE }, + { XML_QUERY, ListSourceType_QUERY }, + { XML_SQL, ListSourceType_SQL }, + { XML_SQL_PASS_THROUGH, ListSourceType_SQLPASSTHROUGH }, + { XML_TABLE_FIELDS, ListSourceType_TABLEFIELDS }, + { XML_TOKEN_INVALID, ListSourceType(0) } +}; +// check state of a checkbox +const SvXMLEnumMapEntry aCheckStateMap[] = +{ + { XML_UNCHECKED, TRISTATE_FALSE }, + { XML_CHECKED, TRISTATE_TRUE }, + { XML_UNKNOWN, TRISTATE_INDET }, + { XML_TOKEN_INVALID, TriState(0) } +}; +const SvXMLEnumMapEntry aTextAlignMap[] = +{ + { XML_START, sal_uInt16(awt::TextAlign::LEFT) }, + { XML_CENTER, sal_uInt16(awt::TextAlign::CENTER) }, + { XML_END, sal_uInt16(awt::TextAlign::RIGHT) }, + { XML_JUSTIFY, -1 }, + { XML_JUSTIFIED, -1 }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aBorderTypeMap[] = +{ + { XML_NONE, 0 }, + { XML_HIDDEN, 0 }, + { XML_SOLID, 2 }, + { XML_DOUBLE, 2 }, + { XML_DOTTED, 2 }, + { XML_DASHED, 2 }, + { XML_GROOVE, 1 }, + { XML_RIDGE, 1 }, + { XML_INSET, 1 }, + { XML_OUTSET, 1 }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aFontEmphasisMap[] = +{ + { XML_NONE, awt::FontEmphasisMark::NONE }, + { XML_DOT, awt::FontEmphasisMark::DOT }, + { XML_CIRCLE, awt::FontEmphasisMark::CIRCLE }, + { XML_DISC, awt::FontEmphasisMark::DISC }, + { XML_ACCENT, awt::FontEmphasisMark::ACCENT }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aFontReliefMap[] = +{ + { XML_NONE, FontRelief::NONE }, + { XML_ENGRAVED, FontRelief::ENGRAVED }, + { XML_EMBOSSED, FontRelief::EMBOSSED }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aListLinkageMap[] = +{ + { XML_SELECTION, 0 }, + { XML_SELECTION_INDEXES, 1 }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aOrientationMap[] = +{ + { XML_HORIZONTAL, ScrollBarOrientation::HORIZONTAL }, + { XML_VERTICAL, ScrollBarOrientation::VERTICAL }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aVisualEffectMap[] = +{ + { XML_NONE, VisualEffect::NONE }, + { XML_3D, VisualEffect::LOOK3D }, + { XML_FLAT, VisualEffect::FLAT }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aImagePositionMap[] = +{ + { XML_START, 0 }, + { XML_END, 1 }, + { XML_TOP, 2 }, + { XML_BOTTOM, 3 }, + { XML_CENTER, -1 }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aImageAlignMap[] = +{ + { XML_START, 0 }, + { XML_CENTER, 1 }, + { XML_END, 2 }, + { XML_TOKEN_INVALID, 0 } +}; +const SvXMLEnumMapEntry aScaleModeMap[] = +{ + { XML_BACKGROUND_NO_REPEAT, ImageScaleMode::NONE }, + { XML_REPEAT, ImageScaleMode::NONE }, // repeating the image is not supported + { XML_STRETCH, ImageScaleMode::ANISOTROPIC }, + { XML_SCALE, ImageScaleMode::ISOTROPIC }, + { XML_TOKEN_INVALID, 0 } +}; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formenums.hxx b/xmloff/source/forms/formenums.hxx new file mode 100644 index 000000000..d0d20ff8d --- /dev/null +++ b/xmloff/source/forms/formenums.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/. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +namespace xmloff +{ +extern const SvXMLEnumMapEntry aSubmitEncodingMap[]; +extern const SvXMLEnumMapEntry aSubmitMethodMap[]; +extern const SvXMLEnumMapEntry aCommandTypeMap[]; +extern const SvXMLEnumMapEntry aNavigationTypeMap[]; +extern const SvXMLEnumMapEntry aTabulatorCycleMap[]; +extern const SvXMLEnumMapEntry aFormButtonTypeMap[]; +extern const SvXMLEnumMapEntry aListSourceTypeMap[]; +extern const SvXMLEnumMapEntry aCheckStateMap[]; +extern const SvXMLEnumMapEntry aTextAlignMap[]; +extern const SvXMLEnumMapEntry aBorderTypeMap[]; +extern const SvXMLEnumMapEntry aFontEmphasisMap[]; +extern const SvXMLEnumMapEntry aFontReliefMap[]; +extern const SvXMLEnumMapEntry aListLinkageMap[]; +extern const SvXMLEnumMapEntry aOrientationMap[]; +extern const SvXMLEnumMapEntry aVisualEffectMap[]; +extern const SvXMLEnumMapEntry aImagePositionMap[]; +extern const SvXMLEnumMapEntry aImageAlignMap[]; +extern const SvXMLEnumMapEntry aScaleModeMap[]; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formevents.cxx b/xmloff/source/forms/formevents.cxx new file mode 100644 index 000000000..85e3137cb --- /dev/null +++ b/xmloff/source/forms/formevents.cxx @@ -0,0 +1,70 @@ +/* -*- 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 "formevents.hxx" +#include +#include + +namespace xmloff +{ + + //= event translation table + const XMLEventNameTranslation aEventTranslations[] = + { + { "XApproveActionListener::approveAction", XML_NAMESPACE_FORM, "approveaction" }, // "on-approveaction" + { "XActionListener::actionPerformed", XML_NAMESPACE_FORM, "performaction" }, // "on-performaction" + { "XChangeListener::changed", XML_NAMESPACE_DOM, "change" }, // "on-change" + { "XTextListener::textChanged", XML_NAMESPACE_FORM, "textchange" }, // "on-textchange" + { "XItemListener::itemStateChanged", XML_NAMESPACE_FORM, "itemstatechange" }, // "on-itemstatechange" + { "XFocusListener::focusGained", XML_NAMESPACE_DOM, "DOMFocusIn" }, // "on-focus" + { "XFocusListener::focusLost", XML_NAMESPACE_DOM, "DOMFocusOut" }, // "on-blur" + { "XKeyListener::keyPressed", XML_NAMESPACE_DOM, "keydown" }, // "on-keydown" + { "XKeyListener::keyReleased", XML_NAMESPACE_DOM, "keyup" }, // "on-keyup" + { "XMouseListener::mouseEntered", XML_NAMESPACE_DOM, "mouseover" }, // "on-mouseover" + { "XMouseMotionListener::mouseDragged", XML_NAMESPACE_FORM, "mousedrag" }, // "on-mousedrag" + { "XMouseMotionListener::mouseMoved", XML_NAMESPACE_DOM, "mousemove" }, // "on-mousemove" + { "XMouseListener::mousePressed", XML_NAMESPACE_DOM, "mousedown" }, // "on-mousedown" + { "XMouseListener::mouseReleased", XML_NAMESPACE_DOM, "mouseup" }, // "on-mouseup" + { "XMouseListener::mouseExited", XML_NAMESPACE_DOM, "mouseout" }, // "on-mouseout" + { "XResetListener::approveReset", XML_NAMESPACE_FORM, "approvereset" }, // "on-approvereset" + { "XResetListener::resetted", XML_NAMESPACE_DOM, "reset" }, // "on-reset" + { "XSubmitListener::approveSubmit", XML_NAMESPACE_DOM, "submit" }, // "on-submit" + { "XUpdateListener::approveUpdate", XML_NAMESPACE_FORM, "approveupdate" }, // "on-approveupdate" + { "XUpdateListener::updated", XML_NAMESPACE_FORM, "update" }, // "on-update" + { "XLoadListener::loaded", XML_NAMESPACE_DOM, "load" }, // "on-load" + { "XLoadListener::reloading", XML_NAMESPACE_FORM, "startreload" }, // "on-startreload" + { "XLoadListener::reloaded", XML_NAMESPACE_FORM, "reload" }, // "on-reload" + { "XLoadListener::unloading", XML_NAMESPACE_FORM, "startunload" }, // "on-startunload" + { "XLoadListener::unloaded", XML_NAMESPACE_DOM, "unload" }, // "on-unload" + { "XConfirmDeleteListener::confirmDelete", XML_NAMESPACE_FORM, "confirmdelete" }, // "on-confirmdelete" + { "XRowSetApproveListener::approveRowChange", XML_NAMESPACE_FORM, "approverowchange" }, // "on-approverowchange" + { "XRowSetListener::rowChanged", XML_NAMESPACE_FORM, "rowchange" }, // "on-rowchange" + { "XRowSetApproveListener::approveCursorMove", XML_NAMESPACE_FORM, "approvecursormove" }, // "on-approvecursormove" + { "XRowSetListener::cursorMoved", XML_NAMESPACE_FORM, "cursormove" }, // "on-cursormove" + { "XDatabaseParameterListener::approveParameter",XML_NAMESPACE_FORM, "supplyparameter" }, // "on-supplyparameter" + { "XSQLErrorListener::errorOccured", XML_NAMESPACE_DOM, "error" }, // "on-error" + { "XAdjustmentListener::adjustmentValueChanged",XML_NAMESPACE_FORM, "adjust" }, // "on-adjust" + { nullptr, 0, nullptr } + }; + + const XMLEventNameTranslation* g_pFormsEventTranslation = aEventTranslations; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formevents.hxx b/xmloff/source/forms/formevents.hxx new file mode 100644 index 000000000..7077f7522 --- /dev/null +++ b/xmloff/source/forms/formevents.hxx @@ -0,0 +1,30 @@ +/* -*- 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 + +struct XMLEventNameTranslation; +namespace xmloff +{ +//= event translation table +extern const XMLEventNameTranslation* g_pFormsEventTranslation; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formlayerexport.cxx b/xmloff/source/forms/formlayerexport.cxx new file mode 100644 index 000000000..661e83630 --- /dev/null +++ b/xmloff/source/forms/formlayerexport.cxx @@ -0,0 +1,121 @@ +/* -*- 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 +#include +#include "layerexport.hxx" +#include +#include "officeforms.hxx" + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::drawing; + + //= OFormLayerXMLExport + + OFormLayerXMLExport::OFormLayerXMLExport(SvXMLExport& _rContext) + :m_pImpl(new OFormLayerXMLExport_Impl(_rContext)) + { + } + + OFormLayerXMLExport::~OFormLayerXMLExport() + { + } + + bool OFormLayerXMLExport::seekPage(const Reference< XDrawPage >& _rxDrawPage) + { + return m_pImpl->seekPage(_rxDrawPage); + } + + OUString OFormLayerXMLExport::getControlId(const Reference< XPropertySet >& _rxControl) + { + return m_pImpl->getControlId(_rxControl); + } + + OUString OFormLayerXMLExport::getControlNumberStyle( const Reference< XPropertySet >& _rxControl ) + { + return m_pImpl->getControlNumberStyle(_rxControl); + } + + void OFormLayerXMLExport::examineForms(const Reference< XDrawPage >& _rxDrawPage) + { + try + { + m_pImpl->examineForms(_rxDrawPage); + } + catch(Exception&) + { + OSL_FAIL("OFormLayerXMLExport::examine: could not examine the draw page!"); + } + } + + void OFormLayerXMLExport::exportForms(const Reference< XDrawPage >& _rxDrawPage) + { + m_pImpl->exportForms(_rxDrawPage); + } + + void OFormLayerXMLExport::exportXForms() const + { + m_pImpl->exportXForms(); + } + + bool OFormLayerXMLExport::pageContainsForms( const Reference< XDrawPage >& _rxDrawPage ) + { + return OFormLayerXMLExport_Impl::pageContainsForms( _rxDrawPage ); + } + + bool OFormLayerXMLExport::documentContainsXForms() const + { + return m_pImpl->documentContainsXForms(); + } + + void OFormLayerXMLExport::exportAutoControlNumberStyles() + { + m_pImpl->exportAutoControlNumberStyles(); + } + + void OFormLayerXMLExport::exportAutoStyles() + { + m_pImpl->exportAutoStyles(); + } + + void OFormLayerXMLExport::excludeFromExport( const Reference< XControlModel >& _rxControl ) + { + m_pImpl->excludeFromExport( _rxControl ); + } + + //= OOfficeFormsExport + OOfficeFormsExport::OOfficeFormsExport( SvXMLExport& _rExp ) + :m_pImpl( new OFormsRootExport(_rExp) ) + { + } + + OOfficeFormsExport::~OOfficeFormsExport() + { + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/formlayerimport.cxx b/xmloff/source/forms/formlayerimport.cxx new file mode 100644 index 000000000..400466bfd --- /dev/null +++ b/xmloff/source/forms/formlayerimport.cxx @@ -0,0 +1,90 @@ +/* -*- 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 + +#include + +#include +#include "layerimport.hxx" + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::drawing; + using namespace ::com::sun::star; + + OFormLayerXMLImport::OFormLayerXMLImport(SvXMLImport& _rImporter) + : m_pImpl( new OFormLayerXMLImport_Impl(_rImporter) ) + { + } + + OFormLayerXMLImport::~OFormLayerXMLImport() + { + } + + void OFormLayerXMLImport::setAutoStyleContext(SvXMLStylesContext* _pNewContext) + { + m_pImpl->setAutoStyleContext(_pNewContext); + } + + void OFormLayerXMLImport::startPage(const Reference< XDrawPage >& _rxDrawPage) + { + m_pImpl->startPage(_rxDrawPage); + } + + void OFormLayerXMLImport::endPage() + { + m_pImpl->endPage(); + } + + Reference< XPropertySet > OFormLayerXMLImport::lookupControl(const OUString& _rId) + { + return m_pImpl->lookupControlId(_rId); + } + + SvXMLImportContext* OFormLayerXMLImport::createOfficeFormsContext( + SvXMLImport& _rImport) + { + return OFormLayerXMLImport_Impl::createOfficeFormsContext(_rImport); + } + + SvXMLImportContext* OFormLayerXMLImport::createContext(sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList >& _rxAttribs) + { + return m_pImpl->createContext(nElement, _rxAttribs); + } + + void OFormLayerXMLImport::applyControlNumberStyle(const Reference< XPropertySet >& _rxControlModel, const OUString& _rControlNumberStyleName) + { + m_pImpl->applyControlNumberStyle(_rxControlModel, _rControlNumberStyleName); + } + + void OFormLayerXMLImport::documentDone( ) + { + m_pImpl->documentDone( ); + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/gridcolumnproptranslator.cxx b/xmloff/source/forms/gridcolumnproptranslator.cxx new file mode 100644 index 000000000..aeb1de438 --- /dev/null +++ b/xmloff/source/forms/gridcolumnproptranslator.cxx @@ -0,0 +1,299 @@ +/* -*- 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 "gridcolumnproptranslator.hxx" + +#include +#include +#include +#include +#include + +#include + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::style; + + namespace + { + OUString getParaAlignProperty() + { + return "ParaAdjust"; + } + + OUString getAlignProperty() + { + return "Align"; + } + + sal_Int32 findStringElement( const Sequence< OUString >& _rNames, const OUString& _rName ) + { + const OUString* pPos = ::std::find( _rNames.begin(), _rNames.end(), _rName ); + if ( pPos != _rNames.end() ) + return pPos - _rNames.begin(); + return -1; + } + + struct AlignmentTranslationEntry + { + ParagraphAdjust nParagraphValue; + sal_Int16 nControlValue; + } + const AlignmentTranslations[] = + { + // note that order matters: + // valueAlignToParaAdjust and valueParaAdjustToAlign search this map from the _beginning_ + // and use the first matching entry + { ParagraphAdjust_LEFT, awt::TextAlign::LEFT }, + { ParagraphAdjust_CENTER, awt::TextAlign::CENTER }, + { ParagraphAdjust_RIGHT, awt::TextAlign::RIGHT }, + { ParagraphAdjust_BLOCK, awt::TextAlign::RIGHT }, + { ParagraphAdjust_STRETCH, awt::TextAlign::LEFT }, + { ParagraphAdjust::ParagraphAdjust_MAKE_FIXED_SIZE, awt::TextAlign::LEFT }, + { ParagraphAdjust::ParagraphAdjust_MAKE_FIXED_SIZE, -1 } + }; + + void valueAlignToParaAdjust(Any& rValue) + { + sal_Int16 nValue = 0; + rValue >>= nValue; + const AlignmentTranslationEntry* pTranslation = AlignmentTranslations; + while (-1 != pTranslation->nControlValue) + { + if ( nValue == pTranslation->nControlValue ) + { + rValue <<= pTranslation->nParagraphValue; + return; + } + ++pTranslation; + } + OSL_FAIL( "valueAlignToParaAdjust: unreachable!" ); + } + + void valueParaAdjustToAlign(Any& rValue) + { + sal_Int32 nValue = 0; + rValue >>= nValue; + const AlignmentTranslationEntry* pTranslation = AlignmentTranslations; + while ( ParagraphAdjust::ParagraphAdjust_MAKE_FIXED_SIZE != pTranslation->nParagraphValue) + { + if ( static_cast(nValue) == pTranslation->nParagraphValue) + { + rValue <<= pTranslation->nControlValue; + return; + } + ++pTranslation; + } + OSL_FAIL( "valueParaAdjustToAlign: unreachable!" ); + } + + //= OMergedPropertySetInfo + typedef ::cppu::WeakAggImplHelper1 < XPropertySetInfo + > OMergedPropertySetInfo_Base; + class OMergedPropertySetInfo : public OMergedPropertySetInfo_Base + { + private: + Reference< XPropertySetInfo > m_xMasterInfo; + + public: + explicit OMergedPropertySetInfo( const Reference< XPropertySetInfo >& _rxMasterInfo ); + + protected: + virtual ~OMergedPropertySetInfo() override; + + // XPropertySetInfo + virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties( ) override; + virtual css::beans::Property SAL_CALL getPropertyByName( const OUString& aName ) override; + virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override; + }; + + OMergedPropertySetInfo::OMergedPropertySetInfo( const Reference< XPropertySetInfo >& _rxMasterInfo ) + :m_xMasterInfo( _rxMasterInfo ) + { + OSL_ENSURE( m_xMasterInfo.is(), "OMergedPropertySetInfo::OMergedPropertySetInfo: hmm?" ); + } + + OMergedPropertySetInfo::~OMergedPropertySetInfo() + { + } + + Sequence< Property > SAL_CALL OMergedPropertySetInfo::getProperties( ) + { + // add a "ParaAdjust" property to the master properties + Sequence< Property > aProperties; + if ( m_xMasterInfo.is() ) + aProperties = m_xMasterInfo->getProperties(); + + sal_Int32 nOldLength = aProperties.getLength(); + aProperties.realloc( nOldLength + 1 ); + aProperties.getArray()[ nOldLength ] = getPropertyByName( getParaAlignProperty() ); + + return aProperties; + } + + Property SAL_CALL OMergedPropertySetInfo::getPropertyByName( const OUString& aName ) + { + if ( aName == getParaAlignProperty() ) + return Property( getParaAlignProperty(), -1, + ::cppu::UnoType::get(), 0 ); + + if ( !m_xMasterInfo.is() ) + return Property(); + + return m_xMasterInfo->getPropertyByName( aName ); + } + + sal_Bool SAL_CALL OMergedPropertySetInfo::hasPropertyByName( const OUString& Name ) + { + if ( Name == getParaAlignProperty() ) + return true; + + if ( !m_xMasterInfo.is() ) + return false; + + return m_xMasterInfo->hasPropertyByName( Name ); + } + } + + //= OGridColumnPropertyTranslator + OGridColumnPropertyTranslator::OGridColumnPropertyTranslator( const Reference< XMultiPropertySet >& _rxGridColumn ) + :m_xGridColumn( _rxGridColumn ) + { + OSL_ENSURE( m_xGridColumn.is(), "OGridColumnPropertyTranslator: invalid grid column!" ); + } + + OGridColumnPropertyTranslator::~OGridColumnPropertyTranslator() + { + } + + Reference< XPropertySetInfo > SAL_CALL OGridColumnPropertyTranslator::getPropertySetInfo( ) + { + Reference< XPropertySetInfo > xColumnPropInfo; + if ( m_xGridColumn.is() ) + xColumnPropInfo = m_xGridColumn->getPropertySetInfo(); + return new OMergedPropertySetInfo( xColumnPropInfo ); + } + + void SAL_CALL OGridColumnPropertyTranslator::setPropertyValue( const OUString& _rPropertyName, const Any& aValue ) + { + // we implement this by delegating it to setPropertyValues, which is to ignore unknown properties. On the other hand, our + // contract requires us to throw a UnknownPropertyException for unknown properties, so check this first. + + if ( !getPropertySetInfo()->hasPropertyByName( _rPropertyName ) ) + throw UnknownPropertyException( _rPropertyName, *this ); + + Sequence< OUString > aNames( &_rPropertyName, 1 ); + Sequence< Any > aValues( &aValue, 1 ); + setPropertyValues( aNames, aValues ); + } + + Any SAL_CALL OGridColumnPropertyTranslator::getPropertyValue( const OUString& PropertyName ) + { + Sequence< OUString > aNames( &PropertyName, 1 ); + Sequence< Any > aValues = getPropertyValues( aNames ); + OSL_ENSURE( aValues.getLength() == 1, "OGridColumnPropertyTranslator::getPropertyValue: nonsense!" ); + if ( aValues.getLength() == 1 ) + return aValues[0]; + return Any(); + } + + void SAL_CALL OGridColumnPropertyTranslator::addPropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) + { + OSL_FAIL( "OGridColumnPropertyTranslator::addPropertyChangeListener: not implemented - this should not be needed!" ); + } + + void SAL_CALL OGridColumnPropertyTranslator::removePropertyChangeListener( const OUString&, const Reference< XPropertyChangeListener >& ) + { + OSL_FAIL( "OGridColumnPropertyTranslator::removePropertyChangeListener: not implemented - this should not be needed!" ); + } + + void SAL_CALL OGridColumnPropertyTranslator::addVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) + { + OSL_FAIL( "OGridColumnPropertyTranslator::addVetoableChangeListener: not implemented - this should not be needed!" ); + } + + void SAL_CALL OGridColumnPropertyTranslator::removeVetoableChangeListener( const OUString&, const Reference< XVetoableChangeListener >& ) + { + OSL_FAIL( "OGridColumnPropertyTranslator::removeVetoableChangeListener: not implemented - this should not be needed!" ); + } + + void SAL_CALL OGridColumnPropertyTranslator::setPropertyValues( const Sequence< OUString >& aPropertyNames, const Sequence< Any >& aValues ) + { + if ( !m_xGridColumn.is() ) + return; + + // if there's ever the need for more than one property being translated, then we should + // certainly have a more clever implementation than this ... + + Sequence< OUString > aTranslatedNames( aPropertyNames ); + Sequence< Any > aTranslatedValues( aValues ); + + sal_Int32 nParaAlignPos = findStringElement( aTranslatedNames, getParaAlignProperty() ); + if ( nParaAlignPos != -1 ) + { + aTranslatedNames.getArray()[ nParaAlignPos ] = getAlignProperty(); + valueParaAdjustToAlign( aTranslatedValues.getArray()[ nParaAlignPos ] ); + } + + m_xGridColumn->setPropertyValues( aTranslatedNames, aTranslatedValues ); + } + + Sequence< Any > SAL_CALL OGridColumnPropertyTranslator::getPropertyValues( const Sequence< OUString >& aPropertyNames ) + { + Sequence< Any > aValues( aPropertyNames.getLength() ); + if ( !m_xGridColumn.is() ) + return aValues; + + Sequence< OUString > aTranslatedNames( aPropertyNames ); + sal_Int32 nAlignPos = findStringElement( aTranslatedNames, getParaAlignProperty() ); + if ( nAlignPos != -1 ) + aTranslatedNames.getArray()[ nAlignPos ] = getAlignProperty(); + + aValues = m_xGridColumn->getPropertyValues( aPropertyNames ); + if ( nAlignPos != -1 ) + valueAlignToParaAdjust( aValues.getArray()[ nAlignPos ] ); + + return aValues; + } + + void SAL_CALL OGridColumnPropertyTranslator::addPropertiesChangeListener( const Sequence< OUString >&, const Reference< XPropertiesChangeListener >& ) + { + OSL_FAIL( "OGridColumnPropertyTranslator::addPropertiesChangeListener: not implemented - this should not be needed!" ); + } + + void SAL_CALL OGridColumnPropertyTranslator::removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& ) + { + OSL_FAIL( "OGridColumnPropertyTranslator::removePropertiesChangeListener: not implemented - this should not be needed!" ); + } + + void SAL_CALL OGridColumnPropertyTranslator::firePropertiesChangeEvent( const Sequence< OUString >&, const Reference< XPropertiesChangeListener >& ) + { + OSL_FAIL( "OGridColumnPropertyTranslator::firePropertiesChangeEvent: not implemented - this should not be needed!" ); + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/gridcolumnproptranslator.hxx b/xmloff/source/forms/gridcolumnproptranslator.hxx new file mode 100644 index 000000000..9a49cd9c3 --- /dev/null +++ b/xmloff/source/forms/gridcolumnproptranslator.hxx @@ -0,0 +1,66 @@ +/* -*- 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 +#include +#include + +namespace xmloff +{ + + //= OGridColumnPropertyTranslator + typedef ::cppu::WeakImplHelper < css::beans::XPropertySet + , css::beans::XMultiPropertySet + > OGridColumnPropertyTranslator_Base; + class OGridColumnPropertyTranslator : public OGridColumnPropertyTranslator_Base + { + private: + css::uno::Reference< css::beans::XMultiPropertySet > + m_xGridColumn; + + public: + explicit OGridColumnPropertyTranslator( + const css::uno::Reference< css::beans::XMultiPropertySet >& _rxGridColumn + ); + + protected: + virtual ~OGridColumnPropertyTranslator() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener >& aListener ) override; + virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener >& aListener ) override; + + // XMultiPropertySet + virtual void SAL_CALL setPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Sequence< css::uno::Any >& aValues ) override; + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getPropertyValues( const css::uno::Sequence< OUString >& aPropertyNames ) override; + virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + virtual void SAL_CALL firePropertiesChangeEvent( const css::uno::Sequence< OUString >& aPropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& xListener ) override; + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/handler/form_handler_factory.cxx b/xmloff/source/forms/handler/form_handler_factory.cxx new file mode 100644 index 000000000..2a943aa82 --- /dev/null +++ b/xmloff/source/forms/handler/form_handler_factory.cxx @@ -0,0 +1,65 @@ +/* -*- 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 +#include "vcl_date_handler.hxx" +#include "vcl_time_handler.hxx" +#include + +namespace xmloff +{ + + //= FormHandlerFactory + PPropertyHandler FormHandlerFactory::getFormPropertyHandler( const PropertyId i_propertyId ) + { + PPropertyHandler pHandler; + + switch ( i_propertyId ) + { + case PID_DATE_MIN: + case PID_DATE_MAX: + case PID_DEFAULT_DATE: + case PID_DATE: + { + static PPropertyHandler s_pVCLDateHandler = new VCLDateHandler(); + pHandler = s_pVCLDateHandler; + } + break; + + case PID_TIME_MIN: + case PID_TIME_MAX: + case PID_DEFAULT_TIME: + case PID_TIME: + { + static PPropertyHandler s_pVCLTimeHandler = new VCLTimeHandler(); + pHandler = s_pVCLTimeHandler; + } + break; + + default: + OSL_ENSURE( false, "FormHandlerFactory::getFormPropertyHandler: unknown property ID!" ); + break; + } + + return pHandler; + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/handler/vcl_date_handler.cxx b/xmloff/source/forms/handler/vcl_date_handler.cxx new file mode 100644 index 000000000..1dfaadd61 --- /dev/null +++ b/xmloff/source/forms/handler/vcl_date_handler.cxx @@ -0,0 +1,93 @@ +/* -*- 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_date_handler.hxx" + +#include + +#include +#include + +#include + +#include +#include + +namespace xmloff +{ + + using ::com::sun::star::uno::Any; + using ::com::sun::star::util::DateTime; + using ::com::sun::star::util::Date; + + //= VCLDateHandler + VCLDateHandler::VCLDateHandler() + { + } + + OUString VCLDateHandler::getAttributeValue( const Any& i_propertyValue ) const + { + Date aDate; + OSL_VERIFY( i_propertyValue >>= aDate ); + + DateTime aDateTime; // default-inited to 0 + aDateTime.Day = aDate.Day; + aDateTime.Month = aDate.Month; + aDateTime.Year = aDate.Year; + + OUStringBuffer aBuffer; + ::sax::Converter::convertDateTime( aBuffer, aDateTime, nullptr ); + return aBuffer.makeStringAndClear(); + } + + bool VCLDateHandler::getPropertyValues( const OUString& i_attributeValue, PropertyValues& o_propertyValues ) const + { + DateTime aDateTime; + Date aDate; + if (::sax::Converter::parseDateTime( aDateTime, i_attributeValue )) + { + aDate.Day = aDateTime.Day; + aDate.Month = aDateTime.Month; + aDate.Year = aDateTime.Year; + } + else + { + // compatibility format, before we wrote those values in XML-schema compatible form + sal_Int32 nVCLDate(0); + if (!::sax::Converter::convertNumber(nVCLDate, i_attributeValue)) + { + OSL_ENSURE( false, "VCLDateHandler::getPropertyValues: unknown date format (no XML-schema date, no legacy integer)!" ); + return false; + } + aDate = ::Date(nVCLDate).GetUNODate(); + } + + const Any aPropertyValue( aDate ); + + OSL_ENSURE( o_propertyValues.size() == 1, "VCLDateHandler::getPropertyValues: date strings represent exactly one property - not more, not less!" ); + for ( auto& prop : o_propertyValues ) + { + prop.second = aPropertyValue; + } + return true; + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/handler/vcl_date_handler.hxx b/xmloff/source/forms/handler/vcl_date_handler.hxx new file mode 100644 index 000000000..626ca4c77 --- /dev/null +++ b/xmloff/source/forms/handler/vcl_date_handler.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/. + * + * 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 + +namespace xmloff +{ + + //= VCLDateHandler + class VCLDateHandler : public PropertyHandlerBase + { + public: + VCLDateHandler(); + + // IPropertyHandler + virtual OUString getAttributeValue( const css::uno::Any& i_propertyValue ) const override; + virtual bool getPropertyValues( const OUString& i_attributeValue, PropertyValues& o_propertyValues ) const override; + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/handler/vcl_time_handler.cxx b/xmloff/source/forms/handler/vcl_time_handler.cxx new file mode 100644 index 000000000..6a8c2cba1 --- /dev/null +++ b/xmloff/source/forms/handler/vcl_time_handler.cxx @@ -0,0 +1,96 @@ +/* -*- 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_time_handler.hxx" + +#include + +#include +#include + +#include + +#include +#include + +namespace xmloff +{ + + using ::com::sun::star::uno::Any; + using ::com::sun::star::util::Duration; + using ::com::sun::star::util::Time; + + //= VCLTimeHandler + VCLTimeHandler::VCLTimeHandler() + { + } + + OUString VCLTimeHandler::getAttributeValue( const Any& i_propertyValue ) const + { + css::util::Time aTime; + OSL_VERIFY( i_propertyValue >>= aTime ); + + Duration aDuration; // default-inited to 0 + aDuration.Hours = aTime.Hours; + aDuration.Minutes = aTime.Minutes; + aDuration.Seconds = aTime.Seconds; + aDuration.NanoSeconds = aTime.NanoSeconds; + + OUStringBuffer aBuffer; + ::sax::Converter::convertDuration( aBuffer, aDuration ); + return aBuffer.makeStringAndClear(); + } + + bool VCLTimeHandler::getPropertyValues( const OUString& i_attributeValue, PropertyValues& o_propertyValues ) const + { + Duration aDuration; + css::util::Time aTime; + if (::sax::Converter::convertDuration( aDuration, i_attributeValue )) + { + aTime = Time(aDuration.NanoSeconds, aDuration.Seconds, + aDuration.Minutes, aDuration.Hours, + false); + } + else + { + // compatibility format, before we wrote those values in XML-schema compatible form + sal_Int64 nVCLTime(0); + if (!::sax::Converter::convertNumber64(nVCLTime, i_attributeValue)) + { + OSL_ENSURE( false, "VCLTimeHandler::getPropertyValues: unknown time format (no XML-schema time, no legacy integer)!" ); + return false; + } + // legacy integer was in centiseconds + nVCLTime *= ::tools::Time::nanoPerCenti; + aTime = ::tools::Time(nVCLTime).GetUNOTime(); + } + + const Any aPropertyValue( aTime ); + + OSL_ENSURE( o_propertyValues.size() == 1, "VCLTimeHandler::getPropertyValues: time strings represent exactly one property - not more, not less!" ); + for ( auto& prop : o_propertyValues ) + { + prop.second = aPropertyValue; + } + return true; + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/handler/vcl_time_handler.hxx b/xmloff/source/forms/handler/vcl_time_handler.hxx new file mode 100644 index 000000000..a5b3b14a9 --- /dev/null +++ b/xmloff/source/forms/handler/vcl_time_handler.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/. + * + * 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 + +namespace xmloff +{ + + //= VCLTimeHandler + class VCLTimeHandler : public PropertyHandlerBase + { + public: + VCLTimeHandler(); + + // IPropertyHandler + virtual OUString getAttributeValue( const css::uno::Any& i_propertyValue ) const override; + virtual bool getPropertyValues( const OUString& i_attributeValue, PropertyValues& o_propertyValues ) const override; + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/layerexport.cxx b/xmloff/source/forms/layerexport.cxx new file mode 100644 index 000000000..87c3b5b40 --- /dev/null +++ b/xmloff/source/forms/layerexport.cxx @@ -0,0 +1,727 @@ +/* -*- 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 "layerexport.hxx" +#include "strings.hxx" +#include +#include +#include +#include "elementexport.hxx" +#include +#include +#include +#include +#include +#include +#include "controlpropertymap.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "formevents.hxx" +#include +#include + +#include + +#include +#include + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::drawing; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::text; + + //= OFormLayerXMLExport_Impl + const OUString& OFormLayerXMLExport_Impl::getControlNumberStyleNamePrefix() + { + static const OUString s_sControlNumberStyleNamePrefix("C"); + return s_sControlNumberStyleNamePrefix; + } + + OFormLayerXMLExport_Impl::OFormLayerXMLExport_Impl(SvXMLExport& _rContext) + :m_rContext(_rContext) + ,m_pControlNumberStyles(nullptr) + { + initializePropertyMaps(); + + // add our style family to the export context's style pool + m_xPropertyHandlerFactory = new OControlPropertyHandlerFactory(); + ::rtl::Reference< XMLPropertySetMapper > xStylePropertiesMapper = new XMLPropertySetMapper( getControlStylePropertyMap(), m_xPropertyHandlerFactory, true ); + m_xStyleExportMapper = new OFormComponentStyleExportMapper( xStylePropertiesMapper ); + + // our style family + m_rContext.GetAutoStylePool()->AddFamily( + XmlStyleFamily::CONTROL_ID, token::GetXMLToken(token::XML_PARAGRAPH), + m_xStyleExportMapper.get(), + OUString( XML_STYLE_FAMILY_CONTROL_PREFIX ) + ); + + // add our event translation table + m_rContext.GetEventExport().AddTranslationTable(g_pFormsEventTranslation); + + clear(); + } + + OFormLayerXMLExport_Impl::~OFormLayerXMLExport_Impl() + { + } + + bool OFormLayerXMLExport_Impl::impl_isFormPageContainingForms(const Reference< XDrawPage >& _rxDrawPage, Reference< XIndexAccess >& _rxForms) + { + Reference< XFormsSupplier2 > xFormsSupp(_rxDrawPage, UNO_QUERY); + OSL_ENSURE(xFormsSupp.is(), "OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid draw page (no XFormsSupplier)! Doin' nothing!"); + if (!xFormsSupp.is()) + return false; + + if ( !xFormsSupp->hasForms() ) + // nothing to do at all + return false; + + _rxForms.set(xFormsSupp->getForms(), UNO_QUERY); + Reference< XServiceInfo > xSI(_rxForms, UNO_QUERY); // order is important! + OSL_ENSURE(xSI.is(), "OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid collection (must not be NULL and must have a ServiceInfo)!"); + if (!xSI.is()) + return false; + + if (!xSI->supportsService("com.sun.star.form.Forms")) + { + OSL_FAIL("OFormLayerXMLExport_Impl::impl_isFormPageContainingForms: invalid collection (is no com.sun.star.form.Forms)!"); + // nothing to do + return false; + } + return true; + } + + void OFormLayerXMLExport_Impl::exportGridColumn(const Reference< XPropertySet >& _rxColumn, + const Sequence< ScriptEventDescriptor >& _rEvents) + { + // do the exporting + OColumnExport aExportImpl(*this, _rxColumn, getControlId( _rxColumn ), _rEvents); + aExportImpl.doExport(); + } + + void OFormLayerXMLExport_Impl::exportControl(const Reference< XPropertySet >& _rxControl, + const Sequence< ScriptEventDescriptor >& _rEvents) + { + // the list of the referring controls + OUString sReferringControls; + MapPropertySet2String::const_iterator aReferring = m_aCurrentPageReferring->second.find(_rxControl); + if (aReferring != m_aCurrentPageReferring->second.end()) + sReferringControls = aReferring->second; + + // the control id (should already have been created in examineForms) + OUString sControlId( getControlId( _rxControl ) ); + + // do the exporting + OControlExport aExportImpl(*this, _rxControl, sControlId, sReferringControls, _rEvents); + aExportImpl.doExport(); + } + + void OFormLayerXMLExport_Impl::exportForm(const Reference< XPropertySet >& _rxProps, + const Sequence< ScriptEventDescriptor >& _rEvents) + { + OSL_ENSURE(_rxProps.is(), "OFormLayerXMLExport_Impl::exportForm: invalid property set!"); + OFormExport aAttributeHandler(*this, _rxProps, _rEvents); + aAttributeHandler.doExport(); + } + + ::rtl::Reference< SvXMLExportPropertyMapper > OFormLayerXMLExport_Impl::getStylePropertyMapper() + { + return m_xStyleExportMapper; + } + + SvXMLExport& OFormLayerXMLExport_Impl::getGlobalContext() + { + return m_rContext; + } + + void OFormLayerXMLExport_Impl::exportCollectionElements(const Reference< XIndexAccess >& _rxCollection) + { + // step through all the elements of the collection + sal_Int32 nElements = _rxCollection->getCount(); + + Reference< XEventAttacherManager > xElementEventManager(_rxCollection, UNO_QUERY); + Sequence< ScriptEventDescriptor > aElementEvents; + + Reference< XPropertySetInfo > xPropsInfo; + for (sal_Int32 i=0; i xCurrentProps( _rxCollection->getByIndex(i), UNO_QUERY ); + OSL_ENSURE(xCurrentProps.is(), "OFormLayerXMLExport_Impl::exportCollectionElements: invalid child element, skipping!"); + if (!xCurrentProps.is()) + continue; + + // check if there is a ClassId property on the current element. If so, we assume it to be a control + xPropsInfo = xCurrentProps->getPropertySetInfo(); + OSL_ENSURE(xPropsInfo.is(), "OFormLayerXMLExport_Impl::exportCollectionElements: no property set info!"); + if (!xPropsInfo.is()) + // without this, a lot of stuff in the export routines may fail + continue; + + // if the element is part of an ignore list, we are not allowed to export it + if ( m_aIgnoreList.end() != m_aIgnoreList.find( xCurrentProps ) ) + continue; + + if (xElementEventManager.is()) + aElementEvents = xElementEventManager->getScriptEvents(i); + + if (xPropsInfo->hasPropertyByName(PROPERTY_COLUMNSERVICENAME)) + { + exportGridColumn(xCurrentProps, aElementEvents); + } + else if (xPropsInfo->hasPropertyByName(PROPERTY_CLASSID)) + { + exportControl(xCurrentProps, aElementEvents); + } + else + { + exportForm(xCurrentProps, aElementEvents); + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.forms", + "caught an exception ... skipping the current element!"); + continue; + } + } + } + + OUString OFormLayerXMLExport_Impl::getObjectStyleName( const Reference< XPropertySet >& _rxObject ) + { + OUString aObjectStyle; + + MapPropertySet2String::const_iterator aObjectStylePos = m_aGridColumnStyles.find( _rxObject ); + if ( m_aGridColumnStyles.end() != aObjectStylePos ) + aObjectStyle = aObjectStylePos->second; + return aObjectStyle; + } + + void OFormLayerXMLExport_Impl::clear() + { + m_aControlIds.clear(); + m_aReferringControls.clear(); + m_aCurrentPageIds = m_aControlIds.end(); + m_aCurrentPageReferring = m_aReferringControls.end(); + + m_aControlNumberFormats.clear(); + m_aGridColumnStyles.clear(); + + m_aIgnoreList.clear(); + } + + void OFormLayerXMLExport_Impl::exportAutoControlNumberStyles() + { + if ( m_pControlNumberStyles ) + m_pControlNumberStyles->Export( true ); + } + + void OFormLayerXMLExport_Impl::exportAutoStyles() + { + m_rContext.GetAutoStylePool()->exportXML( XmlStyleFamily::CONTROL_ID ); + } + + void OFormLayerXMLExport_Impl::exportForms(const Reference< XDrawPage >& _rxDrawPage) + { + // get the forms collection of the page + Reference< XIndexAccess > xCollectionIndex; + if (!impl_isFormPageContainingForms(_rxDrawPage, xCollectionIndex)) + { + return; + } + + bool bPageIsKnown = implMoveIterators(_rxDrawPage, false); + OSL_ENSURE(bPageIsKnown, "OFormLayerXMLExport_Impl::exportForms: exporting a page which has not been examined!"); + + // export forms collection + exportCollectionElements(xCollectionIndex); + } + + void OFormLayerXMLExport_Impl::exportXForms() const + { + // export XForms models + ::exportXForms( m_rContext ); + } + + bool OFormLayerXMLExport_Impl::pageContainsForms( const Reference< XDrawPage >& _rxDrawPage ) + { + Reference< XFormsSupplier2 > xFormsSupp( _rxDrawPage, UNO_QUERY ); + SAL_WARN_IF( !xFormsSupp.is(), "xmloff", "OFormLayerXMLExport_Impl::pageContainsForms: no XFormsSupplier2!" ); + return xFormsSupp.is() && xFormsSupp->hasForms(); + } + + bool OFormLayerXMLExport_Impl::documentContainsXForms() const + { + Reference< css::xforms::XFormsSupplier > xXFormSupp( m_rContext.GetModel(), UNO_QUERY ); + Reference< XNameContainer > xForms; + if ( xXFormSupp.is() ) + xForms = xXFormSupp->getXForms(); + return xForms.is() && xForms->hasElements(); + } + + bool OFormLayerXMLExport_Impl::implMoveIterators(const Reference< XDrawPage >& _rxDrawPage, bool _bClear) + { + if (!_rxDrawPage.is()) + return false; + + bool bKnownPage = false; + + // the one for the ids + m_aCurrentPageIds = m_aControlIds.find(_rxDrawPage); + if (m_aControlIds.end() == m_aCurrentPageIds) + { + m_aControlIds[_rxDrawPage] = MapPropertySet2String(); + m_aCurrentPageIds = m_aControlIds.find(_rxDrawPage); + } + else + { + bKnownPage = true; + if (_bClear && !m_aCurrentPageIds->second.empty() ) + m_aCurrentPageIds->second.clear(); + } + + // the one for the ids of the referring controls + m_aCurrentPageReferring = m_aReferringControls.find(_rxDrawPage); + if (m_aReferringControls.end() == m_aCurrentPageReferring) + { + m_aReferringControls[_rxDrawPage] = MapPropertySet2String(); + m_aCurrentPageReferring = m_aReferringControls.find(_rxDrawPage); + } + else + { + bKnownPage = true; + if (_bClear && !m_aCurrentPageReferring->second.empty() ) + m_aCurrentPageReferring->second.clear(); + } + return bKnownPage; + } + + bool OFormLayerXMLExport_Impl::seekPage(const Reference< XDrawPage >& _rxDrawPage) + { + bool bKnownPage = implMoveIterators( _rxDrawPage, false ); + if ( bKnownPage ) + return true; + + // if the page is not yet known, this does not automatically mean that it has + // not been examined. Instead, examineForms returns silently and successfully + // if a page is a XFormsPageSupplier2, but does not have a forms collection + // (This behaviour of examineForms is a performance optimization, to not force + // the page to create a forms container just to see that it's empty.) + + // So, in such a case, seekPage is considered to be successful, too, though the + // page was not yet known + Reference< XFormsSupplier2 > xFormsSupp( _rxDrawPage, UNO_QUERY ); + if ( xFormsSupp.is() && !xFormsSupp->hasForms() ) + return true; + + // anything else means that the page has not been examined before, or it's no + // valid form page. Both cases are Bad (TM). + return false; + } + + OUString OFormLayerXMLExport_Impl::getControlId(const Reference< XPropertySet >& _rxControl) + { + if (m_aCurrentPageIds == m_aControlIds.end()) + return OUString(); + + OSL_ENSURE(m_aCurrentPageIds->second.end() != m_aCurrentPageIds->second.find(_rxControl), + "OFormLayerXMLExport_Impl::getControlId: can not find the control!"); + return m_aCurrentPageIds->second[_rxControl]; + } + + OUString OFormLayerXMLExport_Impl::getImmediateNumberStyle( const Reference< XPropertySet >& _rxObject ) + { + OUString sNumberStyle; + + sal_Int32 nOwnFormatKey = implExamineControlNumberFormat( _rxObject ); + if ( -1 != nOwnFormatKey ) + sNumberStyle = getControlNumberStyleExport()->GetStyleName( nOwnFormatKey ); + + return sNumberStyle; + } + + OUString OFormLayerXMLExport_Impl::getControlNumberStyle( const Reference< XPropertySet >& _rxControl ) + { + OUString sNumberStyle; + + MapPropertySet2Int::const_iterator aControlFormatPos = m_aControlNumberFormats.find(_rxControl); + if (m_aControlNumberFormats.end() != aControlFormatPos) + { + OSL_ENSURE(m_pControlNumberStyles, "OFormLayerXMLExport_Impl::getControlNumberStyle: have a control which has a format style, but no style exporter!"); + sNumberStyle = getControlNumberStyleExport()->GetStyleName(aControlFormatPos->second); + } + // it's allowed to ask for a control which does not have format information. + // (This is for performance reasons) + + return sNumberStyle; + } + + void OFormLayerXMLExport_Impl::examineForms(const Reference< XDrawPage >& _rxDrawPage) + { + // get the forms collection of the page + Reference< XIndexAccess > xCollectionIndex; + if (!impl_isFormPageContainingForms(_rxDrawPage, xCollectionIndex)) + { + return; + } + + // move the iterator which specify the currently handled page + bool bPageIsKnown = implMoveIterators(_rxDrawPage, true); + OSL_ENSURE(!bPageIsKnown, "OFormLayerXMLExport_Impl::examineForms: examining a page twice!"); + + ::std::stack< Reference< XIndexAccess > > aContainerHistory; + ::std::stack< sal_Int32 > aIndexHistory; + + Reference< XIndexAccess > xLoop = xCollectionIndex; + sal_Int32 nChildPos = 0; + do + { + if (nChildPos < xLoop->getCount()) + { + Reference< XPropertySet > xCurrent( xLoop->getByIndex( nChildPos ), UNO_QUERY ); + OSL_ENSURE(xCurrent.is(), "OFormLayerXMLExport_Impl::examineForms: invalid child object"); + if (!xCurrent.is()) + continue; + + if (!checkExamineControl(xCurrent)) + { + // step down + Reference< XIndexAccess > xNextContainer(xCurrent, UNO_QUERY); + OSL_ENSURE(xNextContainer.is(), "OFormLayerXMLExport_Impl::examineForms: what the heck is this ... no control, no container?"); + aContainerHistory.push(xLoop); + aIndexHistory.push(nChildPos); + + xLoop = xNextContainer; + nChildPos = -1; // will be incremented below + } + ++nChildPos; + } + else + { + // step up + while ((nChildPos >= xLoop->getCount()) && !aContainerHistory.empty() ) + { + xLoop = aContainerHistory.top(); + aContainerHistory.pop(); + nChildPos = aIndexHistory.top(); + aIndexHistory.pop(); + + ++nChildPos; + } + if (nChildPos >= xLoop->getCount()) + // exited the loop above because we have no history anymore (0 == aContainerHistory.size()), + // and on the current level there are no more children + // -> leave + break; + } + } + while (xLoop.is()); + } + + namespace + { + struct AccumulateSize + { + size_t operator()( size_t _size, const MapPropertySet2Map::value_type& _map ) const + { + return _size + _map.second.size(); + } + }; + + OUString lcl_findFreeControlId( const MapPropertySet2Map& _rAllPagesControlIds ) + { + OUString sControlId = "control"; + + size_t nKnownControlCount = ::std::accumulate( _rAllPagesControlIds.begin(), _rAllPagesControlIds.end(), size_t(0), AccumulateSize() ); + sControlId += OUString::number( static_cast(nKnownControlCount) + 1 ); + + #ifdef DBG_UTIL + // Check if the id is already used. It shouldn't, as we currently have no mechanism for removing entries + // from the map, so the approach used above (take the accumulated map size) should be sufficient. But if + // somebody changes this (e.g. allows removing entries from the map), the assertion below probably will fail. + for ( const auto& outer : _rAllPagesControlIds ) + for ( const auto& inner : outer.second ) + { + OSL_ENSURE( inner.second != sControlId, + "lcl_findFreeControlId: auto-generated control ID is already used!" ); + } + #endif + return sControlId; + } + } + + bool OFormLayerXMLExport_Impl::checkExamineControl(const Reference< XPropertySet >& _rxObject) + { + Reference< XPropertySetInfo > xCurrentInfo = _rxObject->getPropertySetInfo(); + OSL_ENSURE(xCurrentInfo.is(), "OFormLayerXMLExport_Impl::checkExamineControl: no property set info"); + + bool bIsControl = xCurrentInfo->hasPropertyByName( PROPERTY_CLASSID ); + if (bIsControl) + { + // generate a new control id + + // find a free id + OUString sCurrentId = lcl_findFreeControlId( m_aControlIds ); + // add it to the map + m_aCurrentPageIds->second[_rxObject] = sCurrentId; + + // check if this control has a "LabelControl" property referring another control + if ( xCurrentInfo->hasPropertyByName( PROPERTY_CONTROLLABEL ) ) + { + Reference< XPropertySet > xCurrentReference( _rxObject->getPropertyValue( PROPERTY_CONTROLLABEL ), UNO_QUERY ); + if (xCurrentReference.is()) + { + OUString& sReferencedBy = m_aCurrentPageReferring->second[xCurrentReference]; + if (!sReferencedBy.isEmpty()) + // it's not the first _rxObject referring to the xCurrentReference + // -> separate the id + sReferencedBy += ","; + sReferencedBy += sCurrentId; + } + } + + // check if the control needs a number format style + if ( xCurrentInfo->hasPropertyByName( PROPERTY_FORMATKEY ) ) + { + examineControlNumberFormat(_rxObject); + } + + // check if it's a control providing text + Reference< XText > xControlText( _rxObject, UNO_QUERY ); + if ( xControlText.is() ) + { + m_rContext.GetTextParagraphExport()->collectTextAutoStyles( xControlText ); + } + + // check if it is a grid control - in this case, we need special handling for the columns + sal_Int16 nControlType = FormComponentType::CONTROL; + _rxObject->getPropertyValue( PROPERTY_CLASSID ) >>= nControlType; + if ( FormComponentType::GRIDCONTROL == nControlType ) + { + collectGridColumnStylesAndIds( _rxObject ); + } + } + + return bIsControl; + } + + void OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds( const Reference< XPropertySet >& _rxControl ) + { + // loop through all columns of the grid + try + { + Reference< XIndexAccess > xContainer( _rxControl, UNO_QUERY ); + OSL_ENSURE( xContainer.is(), "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: grid control not being a container?!" ); + if ( !xContainer.is() ) + return; + + Reference< XPropertySetInfo > xColumnPropertiesMeta; + + sal_Int32 nCount = xContainer->getCount(); + for ( sal_Int32 i=0; i xColumnProperties( xContainer->getByIndex( i ), UNO_QUERY ); + OSL_ENSURE( xColumnProperties.is(), "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: invalid grid column encountered!" ); + if ( !xColumnProperties.is() ) + continue; + + // generate a new control id + + // find a free id + OUString sCurrentId = lcl_findFreeControlId( m_aControlIds ); + // add it to the map + m_aCurrentPageIds->second[ xColumnProperties ] = sCurrentId; + + // determine a number style, if needed + xColumnPropertiesMeta = xColumnProperties->getPropertySetInfo(); + // get the styles of the column + ::std::vector aPropertyStates = m_xStyleExportMapper->Filter(m_rContext, xColumnProperties); + + // care for the number format, additionally + OUString sColumnNumberStyle; + if ( xColumnPropertiesMeta.is() && xColumnPropertiesMeta->hasPropertyByName( PROPERTY_FORMATKEY ) ) + sColumnNumberStyle = getImmediateNumberStyle( xColumnProperties ); + + if ( !sColumnNumberStyle.isEmpty() ) + { // the column indeed has a formatting + sal_Int32 nStyleMapIndex = m_xStyleExportMapper->getPropertySetMapper()->FindEntryIndex( CTF_FORMS_DATA_STYLE ); + // TODO: move this to the ctor + OSL_ENSURE ( -1 != nStyleMapIndex, "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: could not obtain the index for our context id!"); + + XMLPropertyState aNumberStyleState( nStyleMapIndex, Any( sColumnNumberStyle ) ); + aPropertyStates.push_back( aNumberStyleState ); + } + + // determine the column style + + if ( !aPropertyStates.empty() ) + { // add to the style pool + OUString sColumnStyleName = m_rContext.GetAutoStylePool()->Add( XmlStyleFamily::CONTROL_ID, std::move(aPropertyStates) ); + + OSL_ENSURE( m_aGridColumnStyles.end() == m_aGridColumnStyles.find( xColumnProperties ), + "OFormLayerXMLExport_Impl::collectGridColumnStylesAndIds: already have a style for this column!" ); + + m_aGridColumnStyles.emplace( xColumnProperties, sColumnStyleName ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.forms"); + } + } + + sal_Int32 OFormLayerXMLExport_Impl::implExamineControlNumberFormat( const Reference< XPropertySet >& _rxObject ) + { + // get the format key relative to our own formats supplier + sal_Int32 nOwnFormatKey = ensureTranslateFormat( _rxObject ); + + if ( -1 != nOwnFormatKey ) + // tell the exporter that we used this format + getControlNumberStyleExport()->SetUsed( nOwnFormatKey ); + + return nOwnFormatKey; + } + + void OFormLayerXMLExport_Impl::examineControlNumberFormat( const Reference< XPropertySet >& _rxControl ) + { + sal_Int32 nOwnFormatKey = implExamineControlNumberFormat( _rxControl ); + + if ( -1 == nOwnFormatKey ) + // nothing to do, the number format of this control is void + return; + + // remember the format key for this control (we'll be asked in getControlNumberStyle for this) + OSL_ENSURE(m_aControlNumberFormats.end() == m_aControlNumberFormats.find(_rxControl), + "OFormLayerXMLExport_Impl::examineControlNumberFormat: already handled this control!"); + m_aControlNumberFormats[_rxControl] = nOwnFormatKey; + } + + sal_Int32 OFormLayerXMLExport_Impl::ensureTranslateFormat(const Reference< XPropertySet >& _rxFormattedControl) + { + ensureControlNumberStyleExport(); + OSL_ENSURE(m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: no own formats supplier!"); + // (should have been created in ensureControlNumberStyleExport) + + sal_Int32 nOwnFormatKey = -1; + + // the format key (relative to the control's supplier) + sal_Int32 nControlFormatKey = -1; + Any aControlFormatKey = _rxFormattedControl->getPropertyValue(PROPERTY_FORMATKEY); + if (aControlFormatKey >>= nControlFormatKey) + { + // the control's number format + Reference< XNumberFormatsSupplier > xControlFormatsSupplier; + _rxFormattedControl->getPropertyValue(PROPERTY_FORMATSSUPPLIER) >>= xControlFormatsSupplier; + Reference< XNumberFormats > xControlFormats; + if (xControlFormatsSupplier.is()) + xControlFormats = xControlFormatsSupplier->getNumberFormats(); + OSL_ENSURE(xControlFormats.is(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: formatted control without supplier!"); + + // obtain the persistent (does not depend on the formats supplier) representation of the control's format + Locale aFormatLocale; + OUString sFormatDescription; + if (xControlFormats.is()) + { + Reference< XPropertySet > xControlFormat = xControlFormats->getByKey(nControlFormatKey); + + xControlFormat->getPropertyValue(PROPERTY_LOCALE) >>= aFormatLocale; + xControlFormat->getPropertyValue(PROPERTY_FORMATSTRING) >>= sFormatDescription; + } + + // check if our own formats collection already knows the format + nOwnFormatKey = m_xControlNumberFormats->queryKey(sFormatDescription, aFormatLocale, false); + if (-1 == nOwnFormatKey) + { // no, we don't + // -> create a new format + nOwnFormatKey = m_xControlNumberFormats->addNew(sFormatDescription, aFormatLocale); + } + OSL_ENSURE(-1 != nOwnFormatKey, "OFormLayerXMLExport_Impl::ensureTranslateFormat: could not translate the controls format key!"); + } + else + OSL_ENSURE(!aControlFormatKey.hasValue(), "OFormLayerXMLExport_Impl::ensureTranslateFormat: invalid number format property value!"); + + return nOwnFormatKey; + } + + void OFormLayerXMLExport_Impl::ensureControlNumberStyleExport() + { + if (m_pControlNumberStyles) + return; + + // create our number formats supplier (if necessary) + Reference< XNumberFormatsSupplier > xFormatsSupplier; + + OSL_ENSURE(!m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::getControlNumberStyleExport: inconsistence!"); + // the m_xControlNumberFormats and m_pControlNumberStyles should be maintained together + + try + { + // create it for en-US (does not really matter, as we will specify a locale for every + // concrete language to use) + Locale aLocale ( "en", "US", OUString() ); + xFormatsSupplier = NumberFormatsSupplier::createWithLocale( m_rContext.getComponentContext(), aLocale ); + m_xControlNumberFormats = xFormatsSupplier->getNumberFormats(); + } + catch(const Exception&) + { + } + + OSL_ENSURE(m_xControlNumberFormats.is(), "OFormLayerXMLExport_Impl::getControlNumberStyleExport: could not obtain my default number formats!"); + + // create the exporter + m_pControlNumberStyles = new SvXMLNumFmtExport(m_rContext, xFormatsSupplier, getControlNumberStyleNamePrefix()); + } + + SvXMLNumFmtExport* OFormLayerXMLExport_Impl::getControlNumberStyleExport() + { + ensureControlNumberStyleExport(); + return m_pControlNumberStyles; + } + + void OFormLayerXMLExport_Impl::excludeFromExport( const Reference< XControlModel >& _rxControl ) + { + Reference< XPropertySet > xProps( _rxControl, UNO_QUERY ); + OSL_ENSURE( xProps.is(), "OFormLayerXMLExport_Impl::excludeFromExport: invalid control model!" ); + ::std::pair< PropertySetBag::const_iterator, bool > aPos = + m_aIgnoreList.insert( xProps ); + OSL_ENSURE( aPos.second, "OFormLayerXMLExport_Impl::excludeFromExport: element already exists in the ignore list!" ); + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/layerexport.hxx b/xmloff/source/forms/layerexport.hxx new file mode 100644 index 000000000..4d19386ef --- /dev/null +++ b/xmloff/source/forms/layerexport.hxx @@ -0,0 +1,299 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include +#include "callbacks.hxx" +#include +#include + +class SvXMLExport; +class SvXMLNumFmtExport; +class XMLPropertyHandlerFactory; +class SvXMLExportPropertyMapper; + +namespace xmloff +{ + + typedef o3tl::sorted_vector< css::uno::Reference< css::beans::XPropertySet > > PropertySetBag; + + // maps objects (property sets) to strings, e.g. control ids. + typedef ::std::unordered_map < css::uno::Reference< css::beans::XPropertySet > + , OUString + > MapPropertySet2String; + + // map pages to maps (of property sets to strings) + typedef ::std::unordered_map < css::uno::Reference< css::drawing::XDrawPage > + , MapPropertySet2String + > MapPropertySet2Map; + + //= OFormLayerXMLExport_Impl + /** the implementation class for OFormLayerXMLExport + */ + class OFormLayerXMLExport_Impl + :public IFormsExportContext + { + friend class OFormLayerXMLExport; + + SvXMLExport& m_rContext; + SvXMLNumFmtExport* m_pControlNumberStyles; + + // ignore list for control models + PropertySetBag m_aIgnoreList; + + // style handling + ::rtl::Reference< XMLPropertyHandlerFactory > m_xPropertyHandlerFactory; + ::rtl::Reference< SvXMLExportPropertyMapper > m_xStyleExportMapper; + + // we need our own number formats supplier: + // Controls which have a number formats do not work with the formats supplier of the document they reside + // in, instead they use the formats of the data source their form is associated with. If there is no + // such form or no such data source, they work with an own formatter. + // Even more, time and date fields do not work with a central formatter at all, they have their own one + // (which is shared internally, but this is a (hidden) implementation detail.) + + // To not contaminate the global (document) number formats supplier (which could be obtained from the context), + // we have an own one. + // (Contaminate means: If a user adds a user-defined format to a formatted field, this format is stored in + // in the data source's formats supplier. To export this _and_ reuse existing structures, we would need to + // add this format to the global (document) formats supplier. + // In case of an export we could do some cleanup afterwards, but in case of an import, there is no such + // chance, as (if other user-defined formats exist in the document as well) we can't distinguish + // between user-defined formats really needed for the doc (i.e. in a calc cell) and formats only added + // to the supplier because the controls needed it. + css::uno::Reference< css::util::XNumberFormats > + m_xControlNumberFormats; + + MapPropertySet2Map m_aControlIds; + // the control ids of all controls on all pages we ever examined + + MapPropertySet2Map m_aReferringControls; + // for a given page (iter->first), and a given control (iter->second->first), this is the comma-separated + // lists of ids of the controls referring to the control given. + + MapPropertySet2Map::iterator + m_aCurrentPageIds; + // the iterator for the control id map for the page being handled + MapPropertySet2Map::iterator + m_aCurrentPageReferring; + // the same for the map of referring controls + + // TODO: To avoid this construct above, and to have a cleaner implementation, a class encapsulating the + // export of a single page should be introduced. + + typedef std::unordered_map, sal_Int32> MapPropertySet2Int; + MapPropertySet2Int m_aControlNumberFormats; + // maps controls to format keys, which are relative to our own formats supplier + + MapPropertySet2String m_aGridColumnStyles; + // style names of grid columns + + public: + explicit OFormLayerXMLExport_Impl(SvXMLExport& _rContext); + virtual ~OFormLayerXMLExport_Impl(); + + private: + /** exports one single grid column + */ + void exportGridColumn( + const css::uno::Reference< css::beans::XPropertySet >& _rxColumn, + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents + ); + + /** exports one single control + */ + void exportControl( + const css::uno::Reference< css::beans::XPropertySet >& _rxControl, + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents + ); + + /** exports one single form + */ + void exportForm(const css::uno::Reference< css::beans::XPropertySet >& _rxProps, + const css::uno::Sequence< css::script::ScriptEventDescriptor >& _rEvents + ); + + /** seek to the page given. + +

This must be called before you can retrieve any ids for controls on the page.

+ + @see + getControlId + */ + bool seekPage( + const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage); + + /** get the id of the given control. + +

You must have sought to the page of the control before calling this.

+ */ + OUString + getControlId(const css::uno::Reference< css::beans::XPropertySet >& _rxControl); + + /** retrieves the style name for the control's number style. + +

For performance reasons, this method is allowed to be called for any controls, even those which + do not have a number style. In this case, an empty string is returned.

+ */ + OUString + getControlNumberStyle( const css::uno::Reference< css::beans::XPropertySet >& _rxControl ); + + // IFormsExportContext + virtual void exportCollectionElements(const css::uno::Reference< css::container::XIndexAccess >& _rxCollection) override; + virtual SvXMLExport& getGlobalContext() override; + virtual OUString getObjectStyleName( + const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) override; + virtual ::rtl::Reference< SvXMLExportPropertyMapper > getStylePropertyMapper() override; + + /** clear any structures which have been build in the recent examine calls. + */ + void clear(); + + /** examine a forms collection. + +

The method will collect control ids and add styles to the export context as necessary.

+ +

Every control in the object hierarchy given will be assigned to a unique id, which is stored for later + use.

+ +

In addition, any references the controls may have between each other, are collected and stored for + later use.

+ +

Upon calling this method, the id map will be cleared before collecting the new ids, so any ids + you collected previously will be lost

+ + @param _rxDrawPage + the draw page which's forms collection should be examined + + @see getControlId + @see exportControl + @see exportForms + */ + void examineForms( + const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage); + + /** export a forms collection of a draw page + +

The method will obtain the forms collection of the page and call + exportCollectionElements.

+ */ + void exportForms( + const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage); + + /** exports the XForms model data + */ + void exportXForms() const; + + /** determines whether the given page contains logical forms + */ + static bool pageContainsForms( const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage ); + + /** determines whether the given page contains XForm instances + */ + bool documentContainsXForms() const; + + /** exports the automatic control number styles + */ + void exportAutoControlNumberStyles(); + + /** exports the auto-styles collected during the examineForms calls + */ + void exportAutoStyles(); + + static bool impl_isFormPageContainingForms( + const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage, + css::uno::Reference< css::container::XIndexAccess >& _rxForms); + + /** moves the m_aCurrentPage* members to the positions specifying the given page. + + @return if there already were structures for the given page + */ + bool implMoveIterators( + const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage, + bool _bClear); + + /** check the object given if it's a control, if so, examine it. + @return if the object has been handled + */ + bool checkExamineControl(const css::uno::Reference< css::beans::XPropertySet >& _rxObject); + + /** examines the control's number format, so later the format style can be referred + +

remembers the format key for the control, so it can later be asked for in getControlNumberStyle

+ */ + void examineControlNumberFormat(const css::uno::Reference< css::beans::XPropertySet >& _rxControl); + + /** examines the control's number format, so later the format style can be referred + +

does not remember the information returned in any way

+ */ + sal_Int32 implExamineControlNumberFormat( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ); + + /** collects AutoStyles for grid columns + */ + void collectGridColumnStylesAndIds( const css::uno::Reference< css::beans::XPropertySet >& _rxControl ); + + /** ensures that the number format of the given control exist in our own formats supplier. + +

The given control is examined for its format (i.e. it's FormatKey/FormatsSupplier properties), + and the format is added (if necessary) to m_xControlNumberFormats

. + + @return + the format key of the control's format relative to our own formats supplier + + */ + sal_Int32 ensureTranslateFormat(const css::uno::Reference< css::beans::XPropertySet >& _rxFormattedControl); + + /// returns the instance exporting our control's number styles + SvXMLNumFmtExport* getControlNumberStyleExport(); + + /// ensures that the instance exporting our control's number styles exists + void ensureControlNumberStyleExport(); + + /** determines the number format style for the given object without remembering it + */ + OUString + getImmediateNumberStyle( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ); + + /** returns the prefix to be used for control number styles + */ + static const OUString& getControlNumberStyleNamePrefix(); + + /** exclude the given control (model) from export. + +

If your document contains form controls which are not to be exported for whatever reason, + you need to announce the models of these controls (can be retrieved from XControlShape::getControl) + to the form layer exporter.
+ Of course you have to do this before calling exportForms

+ */ + void excludeFromExport( const css::uno::Reference< css::awt::XControlModel >& _rxControl ); + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/layerimport.cxx b/xmloff/source/forms/layerimport.cxx new file mode 100644 index 000000000..e5d2c62af --- /dev/null +++ b/xmloff/source/forms/layerimport.cxx @@ -0,0 +1,553 @@ +/* -*- 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 "layerimport.hxx" +#include "formenums.hxx" +#include "elementimport.hxx" +#include "officeforms.hxx" +#include "strings.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "formevents.hxx" +#include "formcellbinding.hxx" +#include +#include +#include +#include +#include +#include + +namespace xmloff +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::awt; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::sdb; +using namespace token; + +//= OFormLayerXMLImport_Impl +OFormLayerXMLImport_Impl::OFormLayerXMLImport_Impl(SvXMLImport& _rImporter) + :m_rImporter(_rImporter) +{ + // build the attribute2property map + // string properties which are exported as attributes + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Name), PROPERTY_NAME); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getSpecialAttributeToken(SCAFlags::GroupName), PROPERTY_GROUP_NAME); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Label), PROPERTY_LABEL); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetLocation), PROPERTY_TARGETURL); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Title), PROPERTY_TITLE); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TargetFrame), PROPERTY_TARGETFRAME); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getDatabaseAttributeToken(DAFlags::DataField), PROPERTY_DATAFIELD); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getFormAttributeToken(faCommand), PROPERTY_COMMAND); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getFormAttributeToken(faDatasource), PROPERTY_DATASOURCENAME); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getFormAttributeToken(faFilter), PROPERTY_FILTER); + m_aAttributeMetaData.addStringProperty( + OAttributeMetaData::getFormAttributeToken(faOrder), PROPERTY_ORDER); + + // properties not added because they're already present in another form + OSL_ENSURE( + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::TargetLocation).equals( + OAttributeMetaData::getFormAttributeName(faAction)), + "OFormLayerXMLImport_Impl::OFormLayerXMLImport_Impl: invalid attribute names (1)!"); + // if this fails, we would have to add a translation from faAction->PROPERTY_TARGETURL + // We did not because we already have one CCAFlags::TargetLocation->PROPERTY_TARGETURL, + // and CCAFlags::TargetLocation and faAction should be represented by the same attribute + + OSL_ENSURE( + OAttributeMetaData::getCommonControlAttributeName(CCAFlags::Name).equals( + OAttributeMetaData::getFormAttributeName(faName)), + "OFormLayerXMLImport_Impl::OFormLayerXMLImport_Impl: invalid attribute names (2)!"); + // the same for faName, CCAFlags::Name and PROPERTY_NAME + + // boolean properties which are exported as attributes + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::CurrentSelected), PROPERTY_STATE, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Disabled), PROPERTY_ENABLED, false, true); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Dropdown), PROPERTY_DROPDOWN, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Printable), PROPERTY_PRINTABLE, true); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::ReadOnly), PROPERTY_READONLY, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Selected), PROPERTY_DEFAULT_STATE, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TabStop), PROPERTY_TABSTOP, true); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ConvertEmpty), PROPERTY_EMPTY_IS_NULL, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getSpecialAttributeToken(SCAFlags::Validation), PROPERTY_STRICTFORMAT, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getSpecialAttributeToken(SCAFlags::MultiLine), PROPERTY_MULTILINE, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getSpecialAttributeToken(SCAFlags::AutoCompletion), PROPERTY_AUTOCOMPLETE, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getSpecialAttributeToken(SCAFlags::Multiple), PROPERTY_MULTISELECTION, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getSpecialAttributeToken(SCAFlags::DefaultButton), PROPERTY_DEFAULTBUTTON, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getSpecialAttributeToken(SCAFlags::IsTristate), PROPERTY_TRISTATE, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getFormAttributeToken(faAllowDeletes), PROPERTY_ALLOWDELETES, true); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getFormAttributeToken(faAllowInserts), PROPERTY_ALLOWINSERTS, true); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getFormAttributeToken(faAllowUpdates), PROPERTY_ALLOWUPDATES, true); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getFormAttributeToken(faApplyFilter), PROPERTY_APPLYFILTER, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getFormAttributeToken(faEscapeProcessing), PROPERTY_ESCAPEPROCESSING, true); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getFormAttributeToken(faIgnoreResult), PROPERTY_IGNORERESULT, false); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getSpecialAttributeToken( SCAFlags::Toggle ), PROPERTY_TOGGLE, false ); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getSpecialAttributeToken( SCAFlags::FocusOnClick ), PROPERTY_FOCUS_ON_CLICK, true ); + m_aAttributeMetaData.addBooleanProperty( + OAttributeMetaData::getDatabaseAttributeToken( DAFlags::InputRequired ), PROPERTY_INPUT_REQUIRED, false ); + + // the int16 attributes + m_aAttributeMetaData.addInt16Property( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::MaxLength), PROPERTY_MAXTEXTLENGTH); + m_aAttributeMetaData.addInt16Property( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::Size), PROPERTY_LINECOUNT); + m_aAttributeMetaData.addInt16Property( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::TabIndex), PROPERTY_TABINDEX); + m_aAttributeMetaData.addInt16Property( + OAttributeMetaData::getDatabaseAttributeToken(DAFlags::BoundColumn), PROPERTY_BOUNDCOLUMN); + + // the int32 attributes + m_aAttributeMetaData.addInt32Property( + OAttributeMetaData::getSpecialAttributeToken( SCAFlags::PageStepSize ), PROPERTY_BLOCK_INCREMENT ); + + // the enum attributes + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::VisualEffect ), PROPERTY_VISUAL_EFFECT, + aVisualEffectMap, + &::cppu::UnoType::get() ); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getCommonControlAttributeToken( CCAFlags::Orientation ), PROPERTY_ORIENTATION, + aOrientationMap, + &::cppu::UnoType::get() ); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getCommonControlAttributeToken(CCAFlags::ButtonType), PROPERTY_BUTTONTYPE, + aFormButtonTypeMap, + &::cppu::UnoType::get()); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getDatabaseAttributeToken(DAFlags::ListSource_TYPE), PROPERTY_LISTSOURCETYPE, + aListSourceTypeMap, + &::cppu::UnoType::get()); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getSpecialAttributeToken(SCAFlags::State), PROPERTY_DEFAULT_STATE, + aCheckStateMap, + &::cppu::UnoType::get()); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getSpecialAttributeToken(SCAFlags::CurrentState), PROPERTY_STATE, + aCheckStateMap, + &::cppu::UnoType::get()); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getFormAttributeToken(faEnctype), PROPERTY_SUBMIT_ENCODING, + aSubmitEncodingMap, + &::cppu::UnoType::get()); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getFormAttributeToken(faMethod), PROPERTY_SUBMIT_METHOD, + aSubmitMethodMap, + &::cppu::UnoType::get()); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getFormAttributeToken(faCommandType), PROPERTY_COMMAND_TYPE, + aCommandTypeMap); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getFormAttributeToken(faNavigationMode), PROPERTY_NAVIGATION, + aNavigationTypeMap, + &::cppu::UnoType::get()); + m_aAttributeMetaData.addEnumProperty( + OAttributeMetaData::getFormAttributeToken(faTabbingCycle), PROPERTY_CYCLE, + aTabulatorCycleMap, + &::cppu::UnoType::get()); + + // 'initialize' + m_aCurrentPageIds = m_aControlIds.end(); +} + +OFormLayerXMLImport_Impl::~OFormLayerXMLImport_Impl() +{} + +void OFormLayerXMLImport_Impl::setAutoStyleContext(SvXMLStylesContext* _pNewContext) +{ + OSL_ENSURE(!m_xAutoStyles.is(), "OFormLayerXMLImport_Impl::setAutoStyleContext: not to be called twice!"); + m_xAutoStyles.set(_pNewContext); +} + +void OFormLayerXMLImport_Impl::applyControlNumberStyle(const Reference< XPropertySet >& _rxControlModel, const OUString& _rControlNumberStyleName) +{ + OSL_ENSURE(_rxControlModel.is() && (!_rControlNumberStyleName.isEmpty()), + "OFormLayerXMLImport_Impl::applyControlNumberStyle: invalid arguments (this will crash)!"); + + OSL_ENSURE(m_xAutoStyles.is(), "OFormLayerXMLImport_Impl::applyControlNumberStyle: have no auto style context!"); + if (!m_xAutoStyles.is()) + { + m_xAutoStyles.set(m_rImporter.GetShapeImport()->GetAutoStylesContext()); + } + + if (!m_xAutoStyles.is()) + return; + + const SvXMLStyleContext* pStyle = m_xAutoStyles->FindStyleChildContext(XmlStyleFamily::DATA_STYLE, _rControlNumberStyleName); + if (pStyle) + { + const SvXMLNumFormatContext* pDataStyle = static_cast(pStyle); + + // set this format at the control model + try + { + // the models number format supplier and formats + Reference< XNumberFormatsSupplier > xFormatsSupplier; + _rxControlModel->getPropertyValue(PROPERTY_FORMATSSUPPLIER) >>= xFormatsSupplier; + Reference< XNumberFormats > xFormats; + if (xFormatsSupplier.is()) + xFormats = xFormatsSupplier->getNumberFormats(); + OSL_ENSURE(xFormats.is(), "OFormLayerXMLImport_Impl::applyControlNumberStyle: could not obtain the controls number formats!"); + + // obtain a key + if (xFormats.is()) + { + sal_Int32 nFormatKey = const_cast(pDataStyle)->CreateAndInsert( xFormatsSupplier ); + OSL_ENSURE(-1 != nFormatKey, "OFormLayerXMLImport_Impl::applyControlNumberStyle: could not obtain a format key!"); + + // set the format on the control model + _rxControlModel->setPropertyValue(PROPERTY_FORMATKEY, Any(nFormatKey)); + } + } + catch(const Exception&) + { + OSL_FAIL("OFormLayerXMLImport_Impl::applyControlNumberStyle: couldn't set the format!"); + } + } + else + OSL_FAIL("OFormLayerXMLImport_Impl::applyControlNumberStyle: did not find the style with the given name!"); +} + +void OFormLayerXMLImport_Impl::registerCellValueBinding( const Reference< XPropertySet >& _rxControlModel, const OUString& _rCellAddress ) +{ + OSL_ENSURE( _rxControlModel.is() && !_rCellAddress.isEmpty(), + "OFormLayerXMLImport_Impl::registerCellValueBinding: invalid arguments!" ); + m_aCellValueBindings.emplace_back( _rxControlModel, _rCellAddress ); +} + +void OFormLayerXMLImport_Impl::registerXFormsValueBinding( + const Reference< XPropertySet >& _rxControlModel, + const OUString& _rBindingID ) +{ + // TODO: is an empty binding name allowed? + OSL_ENSURE( _rxControlModel.is(), "need model" ); + + m_aXFormsValueBindings.emplace_back( _rxControlModel, _rBindingID ); +} + +void OFormLayerXMLImport_Impl::registerXFormsListBinding( + const Reference< XPropertySet >& _rxControlModel, + const OUString& _rBindingID ) +{ + // TODO: is an empty binding name allowed? + OSL_ENSURE( _rxControlModel.is(), "need model" ); + + m_aXFormsListBindings.emplace_back( _rxControlModel, _rBindingID ); +} + +void OFormLayerXMLImport_Impl::registerXFormsSubmission( + const Reference< XPropertySet >& _rxControlModel, + const OUString& _rSubmissionID ) +{ + // TODO: is an empty binding name allowed? + OSL_ENSURE( _rxControlModel.is(), "need model" ); + + m_aXFormsSubmissions.emplace_back( _rxControlModel, _rSubmissionID ); +} + +void OFormLayerXMLImport_Impl::registerCellRangeListSource( const Reference< XPropertySet >& _rxControlModel, const OUString& _rCellRangeAddress ) +{ + OSL_ENSURE( _rxControlModel.is() && !_rCellRangeAddress.isEmpty(), + "OFormLayerXMLImport_Impl::registerCellRangeListSource: invalid arguments!" ); + m_aCellRangeListSources.emplace_back( _rxControlModel, _rCellRangeAddress ); +} +const SvXMLStyleContext* OFormLayerXMLImport_Impl::getStyleElement(const OUString& _rStyleName) const +{ + OSL_ENSURE( m_xAutoStyles.is(), "OFormLayerXMLImport_Impl::getStyleElement: have no auto style context!" ); + // did you use setAutoStyleContext? + + const SvXMLStyleContext* pControlStyle = + m_xAutoStyles.is() ? m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::TEXT_PARAGRAPH, _rStyleName ) : nullptr; + OSL_ENSURE( pControlStyle || !m_xAutoStyles.is(), + OStringBuffer("OFormLayerXMLImport_Impl::getStyleElement: did not find the style named \"" + + OUStringToOString(_rStyleName, RTL_TEXTENCODING_ASCII_US) + + "\"!").getStr() ); + return pControlStyle; +} + +void OFormLayerXMLImport_Impl::enterEventContext() +{ + // install our own translation table. We need to disable the other tables because of name conflicts. + m_rImporter.GetEventImport().PushTranslationTable(); + m_rImporter.GetEventImport().AddTranslationTable(g_pFormsEventTranslation); +} + +void OFormLayerXMLImport_Impl::leaveEventContext() +{ + // install the original event tables. + m_rImporter.GetEventImport().PopTranslationTable(); +} + +void OFormLayerXMLImport_Impl::registerControlId(const Reference< XPropertySet >& _rxControl, const OUString& _rId) +{ + OSL_ENSURE(m_aCurrentPageIds != m_aControlIds.end(), "OFormLayerXMLImport_Impl::registerControlId: no current page!"); + OSL_ENSURE(!_rId.isEmpty(), "OFormLayerXMLImport_Impl::registerControlId: invalid (empty) control id!"); + + OSL_ENSURE(m_aCurrentPageIds->second.end() == m_aCurrentPageIds->second.find(_rId), "OFormLayerXMLImport_Impl::registerControlId: control id already used!"); + m_aCurrentPageIds->second[_rId] = _rxControl; +} + +void OFormLayerXMLImport_Impl::registerControlReferences(const Reference< XPropertySet >& _rxControl, const OUString& _rReferringControls) +{ + OSL_ENSURE(!_rReferringControls.isEmpty(), "OFormLayerXMLImport_Impl::registerControlReferences: invalid (empty) control id list!"); + OSL_ENSURE(_rxControl.is(), "OFormLayerXMLImport_Impl::registerControlReferences: invalid (NULL) control!"); + m_aControlReferences.emplace_back( _rxControl, _rReferringControls ); +} + +void OFormLayerXMLImport_Impl::startPage(const Reference< XDrawPage >& _rxDrawPage) +{ + m_xCurrentPageFormsSupp.clear(); + + OSL_ENSURE(_rxDrawPage.is(), "OFormLayerXMLImport_Impl::startPage: NULL page!"); + m_xCurrentPageFormsSupp.set(_rxDrawPage, css::uno::UNO_QUERY); + OSL_ENSURE( m_xCurrentPageFormsSupp.is(), "OFormLayerXMLImport_Impl::startPage: invalid draw page (no XFormsSupplier)!" ); + if ( !m_xCurrentPageFormsSupp.is() ) + return; + + // add a new entry to our page map + ::std::pair< MapDrawPage2Map::iterator, bool > aPagePosition = m_aControlIds.emplace(_rxDrawPage, MapString2PropertySet()); + OSL_ENSURE(aPagePosition.second, "OFormLayerXMLImport_Impl::startPage: already imported this page!"); + m_aCurrentPageIds = aPagePosition.first; +} + +void OFormLayerXMLImport_Impl::endPage() +{ + OSL_ENSURE( m_xCurrentPageFormsSupp.is(), "OFormLayerXMLImport_Impl::endPage: sure you called startPage before?" ); + + // do some knittings for the controls which are referring to each other + try + { + static const sal_Unicode s_nSeparator = ','; + OUString sCurrentReferring; + OUString sSeparator(&s_nSeparator, 1); + Reference< XPropertySet > xCurrentReferring; + sal_Int32 nSeparator, nPrevSep; + for ( const auto& rReferences : m_aControlReferences ) + { + // the list of control ids is comma separated + + // in a list of n ids there are only n-1 separators ... have to catch this last id + // -> normalize the list + OUString sReferring = rReferences.second + sSeparator; + + nPrevSep = -1; + while (-1 != (nSeparator = sReferring.indexOf(s_nSeparator, nPrevSep + 1))) + { + sCurrentReferring = sReferring.copy(nPrevSep + 1, nSeparator - nPrevSep - 1); + xCurrentReferring = lookupControlId(sCurrentReferring); + if (xCurrentReferring.is()) + // if this condition fails, this is an error, but lookupControlId should have asserted this ... + xCurrentReferring->setPropertyValue( PROPERTY_CONTROLLABEL, Any( rReferences.first ) ); + + nPrevSep = nSeparator; + } + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.forms", + "unable to knit the control references (caught an exception)!"); + } + + // now that we have all children of the forms collection, attach the events + Reference< XIndexAccess > xIndexContainer; + if ( m_xCurrentPageFormsSupp.is() && m_xCurrentPageFormsSupp->hasForms() ) + xIndexContainer.set(m_xCurrentPageFormsSupp->getForms(), css::uno::UNO_QUERY); + if ( xIndexContainer.is() ) + ODefaultEventAttacherManager::setEvents( xIndexContainer ); + + // clear the structures for the control references. + m_aControlReferences.clear(); + + // and no we have no current page anymore + m_aCurrentPageIds = m_aControlIds.end(); +} + +Reference< XPropertySet > OFormLayerXMLImport_Impl::lookupControlId(const OUString& _rControlId) +{ + OSL_ENSURE(m_aCurrentPageIds != m_aControlIds.end(), "OFormLayerXMLImport_Impl::lookupControlId: no current page!"); + Reference< XPropertySet > xReturn; + if (m_aCurrentPageIds != m_aControlIds.end()) + { + MapString2PropertySet::const_iterator aPos = m_aCurrentPageIds->second.find(_rControlId); + if (m_aCurrentPageIds->second.end() != aPos) + xReturn = aPos->second; + else + SAL_WARN("xmloff", "unknown control id " << _rControlId); + } + return xReturn; +} + +SvXMLImportContext* OFormLayerXMLImport_Impl::createOfficeFormsContext( + SvXMLImport& _rImport) +{ + return new OFormsRootImport( _rImport ); +} + +SvXMLImportContext* OFormLayerXMLImport_Impl::createContext( + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList >&) +{ + SvXMLImportContext* pContext = nullptr; + if ( (nElement & TOKEN_MASK) == XML_FORM ) + { + if ( m_xCurrentPageFormsSupp.is() ) + pContext = new OFormImport(*this, *this, m_xCurrentPageFormsSupp->getForms() ); + } + else if ( nElement == XML_ELEMENT(XFORMS, XML_MODEL) ) + { + pContext = createXFormsModelContext( m_rImporter ); + } + else + SAL_WARN("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement)); + + return pContext; +} + +void OFormLayerXMLImport_Impl::documentDone( ) +{ + SvXMLImport& rImport = getGlobalContext(); + if ( !( rImport.getImportFlags() & SvXMLImportFlags::CONTENT ) ) + return; + + // create (and bind) the spreadsheet cell bindings + if ( !m_aCellValueBindings.empty() + && FormCellBindingHelper::isCellBindingAllowed( rImport.GetModel() ) + ) + { + for ( const auto& rCellBindings : m_aCellValueBindings ) + { + try + { + FormCellBindingHelper aHelper( rCellBindings.first, rImport.GetModel() ); + OSL_ENSURE( aHelper.isCellBindingAllowed(), "OFormLayerXMLImport_Impl::documentDone: can't bind this control model!" ); + if ( aHelper.isCellBindingAllowed() ) + { + // There are special bindings for listboxes. See + // OListAndComboImport::doRegisterCellValueBinding for a comment on this HACK. + OUString sBoundCellAddress( rCellBindings.second ); + sal_Int32 nIndicator = sBoundCellAddress.lastIndexOf( ":index" ); + + bool bUseIndexBinding = false; + if ( nIndicator != -1 ) + { + sBoundCellAddress = sBoundCellAddress.copy( 0, nIndicator ); + bUseIndexBinding = true; + } + + aHelper.setBinding( aHelper.createCellBindingFromStringAddress( sBoundCellAddress, bUseIndexBinding ) ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.forms", + "caught an exception while binding to a cell!"); + } + } + m_aCellValueBindings.clear(); + } + + // the same for the spreadsheet cell range list sources + if ( !m_aCellRangeListSources.empty() + && FormCellBindingHelper::isListCellRangeAllowed( rImport.GetModel() ) + ) + { + for ( const auto& rRangeBindings : m_aCellRangeListSources ) + { + try + { + FormCellBindingHelper aHelper( rRangeBindings.first, rImport.GetModel() ); + OSL_ENSURE( aHelper.isListCellRangeAllowed(), "OFormLayerXMLImport_Impl::documentDone: can't bind this control model!" ); + if ( aHelper.isListCellRangeAllowed() ) + { + aHelper.setListSource( aHelper.createCellListSourceFromStringAddress( rRangeBindings.second ) ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.forms", + "caught an exception while binding to a cell range!"); + } + } + m_aCellRangeListSources.clear(); + } + + // process XForms-bindings; call registerXFormsValueBinding for each + for (const auto& aXFormsValueBinding : m_aXFormsValueBindings) + bindXFormsValueBinding(rImport.GetModel(), aXFormsValueBinding); + // same for list bindings + for (const auto& aXFormsListBindings : m_aXFormsListBindings) + bindXFormsListBinding(rImport.GetModel(), aXFormsListBindings); + // same for submissions + for (const auto& aXFormsSubmission : m_aXFormsSubmissions) + bindXFormsSubmission(rImport.GetModel(), aXFormsSubmission); +} + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/layerimport.hxx b/xmloff/source/forms/layerimport.hxx new file mode 100644 index 000000000..21e3a79c7 --- /dev/null +++ b/xmloff/source/forms/layerimport.hxx @@ -0,0 +1,175 @@ +/* -*- 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 + +#include +#include + +#include +#include +#include +#include +#include "formattributes.hxx" +#include "eventimport.hxx" + +class SvXMLImport; +class SvXMLImportContext; +class SvXMLStyleContext; +class SvXMLStylesContext; + + // unfortunately, we can't put this into our namespace, as the macro expands to (amongst others) a forward + // declaration of the class name, which then would be in the namespace, too + +namespace xmloff +{ + + class OAttribute2Property; + + //= OFormLayerXMLImport_Impl + class OFormLayerXMLImport_Impl + : public ODefaultEventAttacherManager + { + friend class OFormLayerXMLImport; + + SvXMLImport& m_rImporter; + OAttribute2Property m_aAttributeMetaData; + + /// the supplier for the forms of the currently imported page + css::uno::Reference< css::form::XFormsSupplier2 > + m_xCurrentPageFormsSupp; + rtl::Reference m_xAutoStyles; + + typedef std::map< OUString, css::uno::Reference< css::beans::XPropertySet > > MapString2PropertySet; + typedef std::unordered_map, MapString2PropertySet> MapDrawPage2Map; + + MapDrawPage2Map m_aControlIds; // ids of the controls on all known page + MapDrawPage2Map::iterator m_aCurrentPageIds; // ifs of the controls on the current page + + typedef ::std::pair< css::uno::Reference< css::beans::XPropertySet >, OUString > + ModelStringPair; + ::std::vector< ModelStringPair > + m_aControlReferences; // control reference descriptions for current page + ::std::vector< ModelStringPair > + m_aCellValueBindings; // information about controls bound to spreadsheet cells + ::std::vector< ModelStringPair > + m_aCellRangeListSources;// information about controls bound to spreadsheet cell range list sources + + ::std::vector< ModelStringPair > + m_aXFormsValueBindings; // collect xforms:bind attributes to be resolved + + ::std::vector< ModelStringPair > + m_aXFormsListBindings; // collect forms:xforms-list-source attributes to be resolved + + ::std::vector< ModelStringPair > + m_aXFormsSubmissions; // collect xforms:submission attributes to be resolved + + public: + // IControlIdMap + void registerControlId( + const css::uno::Reference< css::beans::XPropertySet >& _rxControl, + const OUString& _rId); + void registerControlReferences( + const css::uno::Reference< css::beans::XPropertySet >& _rxControl, + const OUString& _rReferringControls); + + // OFormLayerXMLImport_Impl + OAttribute2Property& getAttributeMap() { return m_aAttributeMetaData; } + SvXMLImport& getGlobalContext() { return m_rImporter; } + const SvXMLStyleContext* getStyleElement(const OUString& _rStyleName) const; + void enterEventContext(); + void leaveEventContext(); + void applyControlNumberStyle( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const OUString& _rControlNumberStyleName + ); + void registerCellValueBinding( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const OUString& _rCellAddress + ); + + void registerCellRangeListSource( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const OUString& _rCellRangeAddress + ); + + void registerXFormsValueBinding( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const OUString& _rBindingID + ); + + void registerXFormsListBinding( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const OUString& _rBindingID + ); + + void registerXFormsSubmission( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const OUString& _rSubmissionID + ); + + ~OFormLayerXMLImport_Impl() override; + + private: + explicit OFormLayerXMLImport_Impl(SvXMLImport& _rImporter); + + /** start importing the forms of the given page + */ + void startPage( + const css::uno::Reference< css::drawing::XDrawPage >& _rxDrawPage); + + /** end importing the forms of the current page + */ + void endPage(); + + /** creates an import context for the office:forms element + */ + static SvXMLImportContext* createOfficeFormsContext( + SvXMLImport& _rImport); + + /** create an SvXMLImportContext instance which is able to import the <form:form> + element. + */ + SvXMLImportContext* createContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttribs); + + /** get the control with the given id + */ + css::uno::Reference< css::beans::XPropertySet > + lookupControlId(const OUString& _rControlId); + + /** announces the auto-style context to the form importer + */ + void setAutoStyleContext(SvXMLStylesContext* _pNewContext); + + /** to be called when the document has been completely imported + +

For some documents (currently: only some spreadsheet documents) it's necessary + do to a post processing, since not all information from the file can be processed + if the document is not completed, yet.

+ */ + void documentDone( ); + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/logging.cxx b/xmloff/source/forms/logging.cxx new file mode 100644 index 000000000..6c2bb5922 --- /dev/null +++ b/xmloff/source/forms/logging.cxx @@ -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/. + * + * 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 "logging.hxx" + +namespace xmloff +{ + +#ifdef TIMELOG + //= OStackedLogging + void OStackedLogging::enterContext( const char* _pContextName ) + { + m_aLogger.push( new ::rtl::Logfile( _pContextName ) ); + } + + void OStackedLogging::leaveTopContext( ) + { + delete m_aLogger.top(); + m_aLogger.pop(); + } +#endif + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/logging.hxx b/xmloff/source/forms/logging.hxx new file mode 100644 index 000000000..501b6c14e --- /dev/null +++ b/xmloff/source/forms/logging.hxx @@ -0,0 +1,59 @@ +/* -*- 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 +#include + +namespace rtl { class Logfile; } + +namespace xmloff +{ + +#ifdef TIMELOG + + //= OStackedLogging + class OStackedLogging + { + private: + ::std::stack< ::rtl::Logfile* > m_aLogger; + + protected: + OStackedLogging() { } + + protected: + void enterContext( const char* _pContextName ); + void leaveTopContext( ); + }; + +#define ENTER_LOG_CONTEXT( name ) enterContext( name ) +#define LEAVE_LOG_CONTEXT( ) leaveTopContext( ) + +#else + struct OStackedLogging { }; + +#define ENTER_LOG_CONTEXT( name ) +#define LEAVE_LOG_CONTEXT( ) + +#endif + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/officeforms.cxx b/xmloff/source/forms/officeforms.cxx new file mode 100644 index 000000000..07f2682d2 --- /dev/null +++ b/xmloff/source/forms/officeforms.cxx @@ -0,0 +1,177 @@ +/* -*- 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 "officeforms.hxx" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include "strings.hxx" + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::xml; + using ::xmloff::token::XML_FORMS; + using ::com::sun::star::xml::sax::XAttributeList; + using ::com::sun::star::xml::sax::XFastAttributeList; + + //= OFormsRootImport + OFormsRootImport::OFormsRootImport( SvXMLImport& rImport ) + :SvXMLImportContext(rImport) + { + } + + OFormsRootImport::~OFormsRootImport() + { + } + + css::uno::Reference< css::xml::sax::XFastContextHandler > OFormsRootImport::createFastChildContext( + sal_Int32 _nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ) + { + SvXMLImportContext* pRet = nullptr; + try + { + pRet = GetImport().GetFormImport()->createContext( _nElement, xAttrList ); + } catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.forms"); + } + return pRet; + } + + void OFormsRootImport::implImportBool(const Reference< XFastAttributeList >& _rxAttributes, OfficeFormsAttributes _eAttribute, + const Reference< XPropertySet >& _rxProps, const Reference< XPropertySetInfo >& _rxPropInfo, + const OUString& _rPropName, bool _bDefault) + { + // the complete attribute name to look for + sal_Int32 nCompleteAttributeName = XML_ELEMENT( + FORM, + OAttributeMetaData::getOfficeFormsAttributeToken(_eAttribute)); + + // get and convert the value + OUString sAttributeValue = _rxAttributes->getOptionalValue(nCompleteAttributeName); + bool bValue = _bDefault; + (void)::sax::Converter::convertBool(bValue, sAttributeValue); + + // set the property + if (_rxPropInfo->hasPropertyByName(_rPropName)) + { + _rxProps->setPropertyValue(_rPropName, Any(bValue)); + } + } + + void OFormsRootImport::startFastElement( sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& _rxAttrList ) + { + ENTER_LOG_CONTEXT( "xmloff::OFormsRootImport - importing the complete tree" ); + + try + { + Reference< XPropertySet > xDocProperties(GetImport().GetModel(), UNO_QUERY); + if ( xDocProperties.is() ) + { // an empty model is allowed: when doing a copy'n'paste from e.g. Writer to Calc, + // this is done via streaming the controls as XML. + Reference< XPropertySetInfo > xDocPropInfo; + if (xDocProperties.is()) + xDocPropInfo = xDocProperties->getPropertySetInfo(); + + implImportBool(_rxAttrList, ofaAutomaticFocus, xDocProperties, xDocPropInfo, PROPERTY_AUTOCONTROLFOCUS, false); + implImportBool(_rxAttrList, ofaApplyDesignMode, xDocProperties, xDocPropInfo, PROPERTY_APPLYDESIGNMODE, true); + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.forms", + "caught an exception while setting the document properties!"); + } + } + + void OFormsRootImport::endFastElement(sal_Int32 ) + { + LEAVE_LOG_CONTEXT( ); + } + + //= OFormsRootExport + OFormsRootExport::OFormsRootExport( SvXMLExport& _rExp ) + { + addModelAttributes(_rExp); + + m_pImplElement.reset( new SvXMLElementExport(_rExp, XML_NAMESPACE_OFFICE, XML_FORMS, true, true) ); + } + + OFormsRootExport::~OFormsRootExport( ) + { + } + + void OFormsRootExport::implExportBool(SvXMLExport& _rExp, OfficeFormsAttributes _eAttribute, + const Reference< XPropertySet >& _rxProps, const Reference< XPropertySetInfo >& _rxPropInfo, + const OUString& _rPropName, bool _bDefault) + { + // retrieve the property value + bool bValue = _bDefault; + if (_rxPropInfo->hasPropertyByName(_rPropName)) + bValue = ::cppu::any2bool(_rxProps->getPropertyValue(_rPropName)); + + // convert into a string + OUStringBuffer aValue; + ::sax::Converter::convertBool(aValue, bValue); + + // add the attribute + _rExp.AddAttribute( + OAttributeMetaData::getOfficeFormsAttributeNamespace(), + OAttributeMetaData::getOfficeFormsAttributeName(_eAttribute), + aValue.makeStringAndClear()); + } + + void OFormsRootExport::addModelAttributes(SvXMLExport& _rExp) + { + try + { + Reference< XPropertySet > xDocProperties(_rExp.GetModel(), UNO_QUERY); + if ( xDocProperties.is() ) + { // an empty model is allowed: when doing a copy'n'paste from e.g. Writer to Calc, + // this is done via streaming the controls as XML. + Reference< XPropertySetInfo > xDocPropInfo; + if (xDocProperties.is()) + xDocPropInfo = xDocProperties->getPropertySetInfo(); + + implExportBool(_rExp, ofaAutomaticFocus, xDocProperties, xDocPropInfo, PROPERTY_AUTOCONTROLFOCUS, false); + implExportBool(_rExp, ofaApplyDesignMode, xDocProperties, xDocPropInfo, PROPERTY_APPLYDESIGNMODE, true); + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.forms", + "caught an exception while retrieving the document properties!"); + } + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/officeforms.hxx b/xmloff/source/forms/officeforms.hxx new file mode 100644 index 000000000..56694835c --- /dev/null +++ b/xmloff/source/forms/officeforms.hxx @@ -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 . + */ + +#pragma once + +#include + +#include "formattributes.hxx" +#include +#include +#include "logging.hxx" + +class SvXMLElementExport; +class SvXMLExport; + +namespace xmloff +{ + + //= OFormsRootImport + class OFormsRootImport + :public SvXMLImportContext + ,public OStackedLogging + { + public: + + OFormsRootImport( SvXMLImport& _rImport); + virtual ~OFormsRootImport() override; + + // SvXMLImportContext overridable + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + private: + static void implImportBool( + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttributes, + OfficeFormsAttributes _eAttribute, + const css::uno::Reference< css::beans::XPropertySet >& _rxProps, + const css::uno::Reference< css::beans::XPropertySetInfo >& _rxPropInfo, + const OUString& _rPropName, + bool _bDefault + ); + }; + + //= OFormsRootExport + class OFormsRootExport + { + private: + std::unique_ptr m_pImplElement; + + public: + explicit OFormsRootExport( SvXMLExport& _rExp ); + ~OFormsRootExport(); + + private: + static void addModelAttributes(SvXMLExport& _rExp); + + static void implExportBool( + SvXMLExport& _rExp, + OfficeFormsAttributes _eAttribute, + const css::uno::Reference< css::beans::XPropertySet >& _rxProps, + const css::uno::Reference< css::beans::XPropertySetInfo >& _rxPropInfo, + const OUString& _rPropName, + bool _bDefault + ); + + OFormsRootExport(const OFormsRootExport&) = delete; + OFormsRootExport& operator=(const OFormsRootExport&) = delete; + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/property_description.hxx b/xmloff/source/forms/property_description.hxx new file mode 100644 index 000000000..d30afcd29 --- /dev/null +++ b/xmloff/source/forms/property_description.hxx @@ -0,0 +1,103 @@ +/* -*- 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 +#include + +#include + +namespace xmloff +{ + + //= PropertyDescription + struct AttributeDescription + { + sal_uInt16 namespacePrefix; // usually XML_NAMESPACE_FORM + ::xmloff::token::XMLTokenEnum attributeToken; + + AttributeDescription() + :namespacePrefix( 0 ) + ,attributeToken( ::xmloff::token::XML_TOKEN_INVALID ) + { + } + + AttributeDescription( + const sal_uInt16 i_namespacePrefix, + const ::xmloff::token::XMLTokenEnum i_attributeToken + ) + :namespacePrefix( i_namespacePrefix ) + ,attributeToken( i_attributeToken ) + { + } + }; + + inline bool operator==( const AttributeDescription& i_lhs, const AttributeDescription& i_rhs ) + { + return ( i_lhs.namespacePrefix == i_rhs.namespacePrefix ) + && ( i_lhs.attributeToken == i_rhs.attributeToken ); + } + + //= PropertyDescription + struct PropertyDescription + { + /// is the name of the property + const OUString propertyName; + /** denotes the attribute which represents the property. Note that multiple properties might comprise a single + attribute value. + */ + /// is the factory for creating a handler for reading and writing the property + const PropertyHandlerFactory factory; + /// the unique ID of the property. The property meta data table must not contain two entries with the same property ID + const PropertyId propertyId; + const AttributeDescription attribute; + + PropertyDescription() + :propertyName() + ,factory( nullptr ) + ,propertyId( PID_INVALID ) + ,attribute() + { + } + + PropertyDescription( + const OUString& i_propertyName, + const sal_uInt16 i_namespacePrefix, + const ::xmloff::token::XMLTokenEnum i_attributeToken, + const PropertyHandlerFactory i_factory, + const PropertyId i_propertyId + ) + :propertyName( i_propertyName ) + ,factory( i_factory ) + ,propertyId( i_propertyId ) + ,attribute( i_namespacePrefix, i_attributeToken ) + { + } + }; + + //= PropertyDescriptionList + typedef ::std::vector< const PropertyDescription* > PropertyDescriptionList; + + //= PropertyGroups + typedef ::std::vector< PropertyDescriptionList > PropertyGroups; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/property_meta_data.cxx b/xmloff/source/forms/property_meta_data.cxx new file mode 100644 index 000000000..ce5760856 --- /dev/null +++ b/xmloff/source/forms/property_meta_data.cxx @@ -0,0 +1,156 @@ +/* -*- 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 "property_description.hxx" +#include "property_meta_data.hxx" +#include +#include "strings.hxx" +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace xmloff::metadata +{ + + using namespace ::xmloff::token; + +#define FORM_SINGLE_PROPERTY( id, att ) \ + PropertyDescription( PROPERTY_##id, XML_NAMESPACE_FORM, att, &FormHandlerFactory::getFormPropertyHandler, PID_##id ) + + //= property meta data + namespace + { + const PropertyDescription* lcl_getPropertyMetaData() + { + static const PropertyDescription s_propertyMetaData[] = + { + FORM_SINGLE_PROPERTY( DATE_MIN, XML_MIN_VALUE ), + FORM_SINGLE_PROPERTY( DATE_MAX, XML_MAX_VALUE ), + FORM_SINGLE_PROPERTY( DEFAULT_DATE, XML_VALUE ), + FORM_SINGLE_PROPERTY( DATE, XML_CURRENT_VALUE ), + FORM_SINGLE_PROPERTY( TIME_MIN, XML_MIN_VALUE ), + FORM_SINGLE_PROPERTY( TIME_MAX, XML_MAX_VALUE ), + FORM_SINGLE_PROPERTY( DEFAULT_TIME, XML_VALUE ), + FORM_SINGLE_PROPERTY( TIME, XML_CURRENT_VALUE ), + + PropertyDescription() + }; + return s_propertyMetaData; + } + } + + namespace + { + // TODO: instead of having all of the below static, it should be some per-instance data. This way, the + // approach used here would scale much better. + // That is, if you have multiple "meta data instances", which manage a small, but closed set of properties, + // then looking through those multiple instances would probably be faster than searching within + // one big instance, since in this case, every instance can quickly decide whether it is responsible + // for some attribute or property, and otherwise delegate to the next instance. + + typedef std::unordered_map< OUString, const PropertyDescription* > DescriptionsByName; + + const DescriptionsByName& lcl_getPropertyDescriptions() + { + DBG_TESTSOLARMUTEX(); + static DescriptionsByName s_propertyDescriptionsByName; + if ( s_propertyDescriptionsByName.empty() ) + { + const PropertyDescription* desc = lcl_getPropertyMetaData(); + while ( !desc->propertyName.isEmpty() ) + { + s_propertyDescriptionsByName[ desc->propertyName ] = desc; + ++desc; + } + } + return s_propertyDescriptionsByName; + } + + typedef std::unordered_map< OUString, XMLTokenEnum > ReverseTokenLookup; + + struct AttributeHash + { + size_t operator()( const AttributeDescription& i_attribute ) const + { + std::size_t seed = 0; + o3tl::hash_combine(seed, i_attribute.attributeToken); + o3tl::hash_combine(seed, i_attribute.namespacePrefix); + return seed; + } + }; + + typedef std::unordered_map< AttributeDescription, PropertyGroups, AttributeHash > AttributesWithoutGroup; + + const AttributesWithoutGroup& lcl_getAttributesWithoutGroups() + { + DBG_TESTSOLARMUTEX(); + static AttributesWithoutGroup s_attributesWithoutGroup; + if ( s_attributesWithoutGroup.empty() ) + { + const PropertyDescription* desc = lcl_getPropertyMetaData(); + while ( !desc->propertyName.isEmpty() ) + { + PropertyDescriptionList singleElementList; + singleElementList.push_back( desc ); + + s_attributesWithoutGroup[ desc->attribute ].push_back( singleElementList ); + ++desc; + } + } + return s_attributesWithoutGroup; + } + } + + const PropertyDescription* getPropertyDescription( const OUString& i_propertyName ) + { + const DescriptionsByName& rAllDescriptions( lcl_getPropertyDescriptions() ); + DescriptionsByName::const_iterator pos = rAllDescriptions.find( i_propertyName ); + if ( pos != rAllDescriptions.end() ) + return pos->second; + return nullptr; + } + + void getPropertyGroupList( const AttributeDescription& i_attribute, PropertyGroups& o_propertyGroups ) + { + // the attribute is not used for any non-trivial group, which means it is mapped directly to + // a single property + const AttributesWithoutGroup& attributesWithoutGroups( lcl_getAttributesWithoutGroups() ); + const AttributesWithoutGroup::const_iterator pos = attributesWithoutGroups.find( i_attribute ); + if ( pos != attributesWithoutGroups.end() ) + o_propertyGroups = pos->second; + } + + AttributeDescription getAttributeDescription( sal_Int32 nAttributeToken ) + { + AttributeDescription attribute; + attribute.namespacePrefix = (nAttributeToken >> NMSP_SHIFT) - 1; + attribute.attributeToken = static_cast(nAttributeToken & TOKEN_MASK); + return attribute; + } + +} // namespace xmloff::metadata + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/property_meta_data.hxx b/xmloff/source/forms/property_meta_data.hxx new file mode 100644 index 000000000..0d012fbc2 --- /dev/null +++ b/xmloff/source/forms/property_meta_data.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 "property_description.hxx" + +namespace xmloff::metadata +{ + + const PropertyDescription* getPropertyDescription( const OUString& i_propertyName ); + + /** retrieves all known property groups which are mapped to the given attribute + */ + void getPropertyGroupList( + const AttributeDescription& i_attribute, + PropertyGroups& o_propertyGroups + ); + + /** retrieves the attribute descriptor for the attribute given by namespace prefix and attribute name + */ + AttributeDescription getAttributeDescription( sal_Int32 nElement ); + +} // namespace xmloff::metadata + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/propertyexport.cxx b/xmloff/source/forms/propertyexport.cxx new file mode 100644 index 000000000..79637d743 --- /dev/null +++ b/xmloff/source/forms/propertyexport.cxx @@ -0,0 +1,683 @@ +/* -*- 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 "propertyexport.hxx" + +#include + +#include +#include "strings.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.hxx" +#include +#include +#include + +namespace xmloff +{ + + using namespace css; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + + // NO using namespace ...util !!! + // need a tools Date/Time/DateTime below, which would conflict with the uno types then + + using namespace ::comphelper; + + //= OPropertyExport + OPropertyExport::OPropertyExport(IFormsExportContext& _rContext, const Reference< XPropertySet >& _rxProps) + :m_rContext(_rContext) + ,m_xProps(_rxProps) + ,m_xPropertyInfo( m_xProps->getPropertySetInfo() ) + ,m_xPropertyState( _rxProps, UNO_QUERY ) + { + // caching + OUStringBuffer aBuffer; + ::sax::Converter::convertBool(aBuffer, true); + m_sValueTrue = aBuffer.makeStringAndClear(); + ::sax::Converter::convertBool(aBuffer, false); + m_sValueFalse = aBuffer.makeStringAndClear(); + + OSL_ENSURE(m_xPropertyInfo.is(), "OPropertyExport::OPropertyExport: need an XPropertySetInfo!"); + + // collect the properties which need to be exported + examinePersistence(); + } + + bool OPropertyExport::shouldExportProperty( const OUString& i_propertyName ) const + { + // if the property state is DEFAULT, it does not need to be written - at least + // if it's a built-in property, and not a dynamically-added one. + bool bIsDefaultValue = m_xPropertyState.is() + && ( PropertyState_DEFAULT_VALUE == m_xPropertyState->getPropertyState( i_propertyName ) ); + bool bIsDynamicProperty = m_xPropertyInfo.is() + && ( ( m_xPropertyInfo->getPropertyByName( i_propertyName ).Attributes & PropertyAttribute::REMOVABLE ) != 0 ); + return ( !bIsDefaultValue || bIsDynamicProperty ); + } + + template< typename T > void + OPropertyExport::exportRemainingPropertiesSequence( + Any const & value, token::XMLTokenEnum eValueAttName) + { + css::uno::Sequence anySeq; + bool bSuccess = value >>= anySeq; + assert(bSuccess); (void)bSuccess; + for (T const & i : std::as_const(anySeq)) + { + OUString sValue(implConvertAny(Any(i))); + AddAttribute(XML_NAMESPACE_OFFICE, eValueAttName, sValue ); + SvXMLElementExport aValueTag( + m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, + token::XML_LIST_VALUE, true, false); + } + } + + void OPropertyExport::exportRemainingProperties() + { + // the properties tag (will be created if we have at least one no-default property) + std::unique_ptr pPropertiesTag; + + Any aValue; + OUString sValue; + + // loop through all the properties which are yet to be exported + for ( const auto& rProperty : m_aRemainingProps ) + { + DBG_CHECK_PROPERTY_NO_TYPE(rProperty); + + if ( !shouldExportProperty( rProperty ) ) + continue; + + // now that we have the first sub-tag we need the form:properties element + if (!pPropertiesTag) + pPropertiesTag = std::make_unique(m_rContext.getGlobalContext(), XML_NAMESPACE_FORM, token::XML_PROPERTIES, true, true); + + // add the name attribute + AddAttribute(XML_NAMESPACE_FORM, token::XML_PROPERTY_NAME, rProperty); + + // get the value + aValue = m_xProps->getPropertyValue(rProperty); + + // the type to export + Type aExportType; + + // is it a sequence + bool bIsSequence = TypeClass_SEQUENCE == aValue.getValueTypeClass(); + // the type of the property, maybe reduced to the element type of a sequence + if (bIsSequence) + aExportType = getSequenceElementType( aValue.getValueType() ); + else + aExportType = aValue.getValueType(); + + // the type attribute + + bool bIsEmptyValue = TypeClass_VOID == aValue.getValueType().getTypeClass(); + if ( bIsEmptyValue ) + { + css::beans::Property aPropDesc = m_xPropertyInfo->getPropertyByName( rProperty ); + aExportType = aPropDesc.Type; + } + token::XMLTokenEnum eValueType = implGetPropertyXMLType( aExportType ); + + if ( bIsEmptyValue ) + AddAttribute( XML_NAMESPACE_OFFICE, token::XML_VALUE_TYPE, token::XML_VOID ); + else + AddAttribute( XML_NAMESPACE_OFFICE, token::XML_VALUE_TYPE, eValueType ); + + token::XMLTokenEnum eValueAttName( token::XML_VALUE ); + switch ( eValueType ) + { + case token::XML_BOOLEAN: eValueAttName = token::XML_BOOLEAN_VALUE; break; + case token::XML_STRING: eValueAttName = token::XML_STRING_VALUE; break; + default: break; + } + + if( !bIsSequence && !bIsEmptyValue ) + { // the simple case + + sValue = implConvertAny(aValue); + AddAttribute(XML_NAMESPACE_OFFICE, eValueAttName, sValue ); + } + + // start the property tag + SvXMLElementExport aValueTag1(m_rContext.getGlobalContext(), + XML_NAMESPACE_FORM, + bIsSequence ? token::XML_LIST_PROPERTY + : token::XML_PROPERTY, true, true); + + if (!bIsSequence) + continue; + + // the not-that-simple case, we need to iterate through the sequence elements + switch ( aExportType.getTypeClass() ) + { + case TypeClass_STRING: + exportRemainingPropertiesSequence< OUString >( + aValue, eValueAttName); + break; + case TypeClass_DOUBLE: + exportRemainingPropertiesSequence< double >( + aValue, eValueAttName); + break; + case TypeClass_BOOLEAN: + exportRemainingPropertiesSequence< sal_Bool >( + aValue, eValueAttName); + break; + case TypeClass_BYTE: + exportRemainingPropertiesSequence< sal_Int8 >( + aValue, eValueAttName); + break; + case TypeClass_SHORT: + exportRemainingPropertiesSequence< sal_Int16 >( + aValue, eValueAttName); + break; + case TypeClass_LONG: + exportRemainingPropertiesSequence< sal_Int32 >( + aValue, eValueAttName); + break; + case TypeClass_HYPER: + exportRemainingPropertiesSequence< sal_Int64 >( + aValue, eValueAttName); + break; + default: + OSL_FAIL("OPropertyExport::exportRemainingProperties: unsupported sequence type !"); + break; + } + } + } + + void OPropertyExport::examinePersistence() + { + m_aRemainingProps.clear(); + const Sequence< Property > aProperties = m_xPropertyInfo->getProperties(); + for (const auto& rProp : aProperties) + { + // no transient props + if ( rProp.Attributes & PropertyAttribute::TRANSIENT ) + continue; + // no read-only props + if ( ( rProp.Attributes & PropertyAttribute::READONLY ) != 0 ) + // except they're dynamically added + if ( ( rProp.Attributes & PropertyAttribute::REMOVABLE ) == 0 ) + continue; + m_aRemainingProps.insert(rProp.Name); + } + } + + void OPropertyExport::exportStringPropertyAttribute( const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, + const OUString& _rPropertyName ) + { + DBG_CHECK_PROPERTY( _rPropertyName, OUString ); + + // no try-catch here, this would be too expensive. The outer scope has to handle exceptions (which should not + // happen if we're used correctly :) + + // this is way simple, as we don't need to convert anything (the property already is a string) + + // get the string + OUString sPropValue; + m_xProps->getPropertyValue( _rPropertyName ) >>= sPropValue; + + // add the attribute + if ( !sPropValue.isEmpty() ) + AddAttribute( _nNamespaceKey, _pAttributeName, sPropValue ); + + // the property does not need to be handled anymore + exportedProperty( _rPropertyName ); + } + + void OPropertyExport::exportBooleanPropertyAttribute(const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, + const OUString& _rPropertyName, const BoolAttrFlags _nBooleanAttributeFlags) + { + DBG_CHECK_PROPERTY_NO_TYPE( _rPropertyName ); + // no check of the property value type: this method is allowed to be called with any integer properties + // (e.g. sal_Int32, sal_uInt16 etc) + + bool bDefault(BoolAttrFlags::DefaultTrue & _nBooleanAttributeFlags); + bool bDefaultVoid(BoolAttrFlags::DefaultVoid & _nBooleanAttributeFlags); + + // get the value + bool bCurrentValue = bDefault; + Any aCurrentValue = m_xProps->getPropertyValue( _rPropertyName ); + if (aCurrentValue.hasValue()) + { + bCurrentValue = ::cppu::any2bool(aCurrentValue); + // this will extract a boolean value even if the Any contains a int or short or something like that ... + + if (_nBooleanAttributeFlags & BoolAttrFlags::InverseSemantics) + bCurrentValue = !bCurrentValue; + + // we have a non-void current value + if (bDefaultVoid || (bDefault != bCurrentValue)) + // and (the default is void, or the non-void default does not equal the current value) + // -> write the attribute + AddAttribute(_nNamespaceKey, _pAttributeName, bCurrentValue ? m_sValueTrue : m_sValueFalse); + } + else + // we have a void current value + if (!bDefaultVoid) + // and we have a non-void default + // -> write the attribute + AddAttribute(_nNamespaceKey, _pAttributeName, bCurrentValue ? m_sValueTrue : m_sValueFalse); + + // the property does not need to be handled anymore + exportedProperty( _rPropertyName ); + } + + void OPropertyExport::exportInt16PropertyAttribute(const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, + const OUString& _rPropertyName, const sal_Int16 _nDefault, bool force) + { + DBG_CHECK_PROPERTY( _rPropertyName, sal_Int16 ); + + // get the value + sal_Int16 nCurrentValue(_nDefault); + m_xProps->getPropertyValue( _rPropertyName ) >>= nCurrentValue; + + // add the attribute + if (force || _nDefault != nCurrentValue) + { + // let the formatter of the export context build a string + AddAttribute(_nNamespaceKey, _pAttributeName, OUString::number(nCurrentValue)); + } + + // the property does not need to be handled anymore + exportedProperty( _rPropertyName ); + } + + void OPropertyExport::exportInt32PropertyAttribute( const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, + const OUString& _rPropertyName, const sal_Int32 _nDefault ) + { + DBG_CHECK_PROPERTY( _rPropertyName, sal_Int32 ); + + // get the value + sal_Int32 nCurrentValue( _nDefault ); + m_xProps->getPropertyValue( _rPropertyName ) >>= nCurrentValue; + + // add the attribute + if ( _nDefault != nCurrentValue ) + { + // let the formatter of the export context build a string + AddAttribute( _nNamespaceKey, _pAttributeName, OUString::number(nCurrentValue) ); + } + + // the property does not need to be handled anymore + exportedProperty( _rPropertyName ); + } + + void OPropertyExport::exportEnumPropertyAttributeImpl( + const sal_uInt16 _nNamespaceKey, const OUString& _pAttributeName, + const OUString &rPropertyName, const SvXMLEnumMapEntry* _pValueMap, + const sal_uInt16 _nDefault, const bool _bVoidDefault) + { + // get the value + Any aValue = m_xProps->getPropertyValue(rPropertyName); + + if (aValue.hasValue()) + { // we have a non-void current value + sal_Int32 nCurrentValue(_nDefault); + ::cppu::enum2int(nCurrentValue, aValue); + + // add the attribute + if ((_nDefault != nCurrentValue) || _bVoidDefault) + { // the default does not equal the value, or the default is void and the value isn't + + // let the formatter of the export context build a string + OUStringBuffer sBuffer; + SvXMLUnitConverter::convertEnum(sBuffer, static_cast(nCurrentValue), _pValueMap); + + AddAttribute(_nNamespaceKey, _pAttributeName, sBuffer.makeStringAndClear()); + } + } + else + { + if (!_bVoidDefault) + AddAttribute(_nNamespaceKey, _pAttributeName, OUString()); + } + + // the property does not need to be handled anymore + exportedProperty(rPropertyName); + } + + void OPropertyExport::exportTargetFrameAttribute() + { + DBG_CHECK_PROPERTY( PROPERTY_TARGETFRAME, OUString ); + + OUString sTargetFrame = comphelper::getString(m_xProps->getPropertyValue(PROPERTY_TARGETFRAME)); + if( sTargetFrame != "_blank" ) + { // an empty string and "_blank" have the same meaning and don't have to be written + AddAttribute(OAttributeMetaData::getCommonControlAttributeNamespace(CCAFlags::TargetFrame) + ,OAttributeMetaData::getCommonControlAttributeName(CCAFlags::TargetFrame) + ,sTargetFrame); + } + + exportedProperty(PROPERTY_TARGETFRAME); + } + + void OPropertyExport::exportRelativeTargetLocation(const OUString& _sPropertyName,CCAFlags _nProperty,bool _bAddType) + { + Any aAny = m_xProps->getPropertyValue(_sPropertyName); + + OUString sTargetLocation; + if (aAny.has>()) + { + auto xGraphic = aAny.get>(); + OUString sOutMimeType; + sTargetLocation = m_rContext.getGlobalContext().AddEmbeddedXGraphic(xGraphic, sOutMimeType); + } + else if (aAny.has()) + { + auto sURL = aAny.get(); + sTargetLocation = m_rContext.getGlobalContext().AddEmbeddedObject(sURL); + } + else + { + SAL_WARN("xmloff.forms", "OPropertyExport::exportRelativeTargetLocation: " + "Value of " << _sPropertyName << " not found!"); + } + + if (!sTargetLocation.isEmpty()) + { + AddAttribute(OAttributeMetaData::getCommonControlAttributeNamespace(_nProperty) + ,OAttributeMetaData::getCommonControlAttributeName(_nProperty) + , sTargetLocation); + + // #i110911# add xlink:type="simple" if required + if (_bAddType) + AddAttribute(XML_NAMESPACE_XLINK, token::XML_TYPE, token::XML_SIMPLE); + + exportedProperty(_sPropertyName); + } + } + void OPropertyExport::flagStyleProperties() + { + // flag all the properties which are part of the style as "handled" + rtl::Reference< XMLPropertySetMapper > xStylePropertiesSupplier = m_rContext.getStylePropertyMapper()->getPropertySetMapper(); + for (sal_Int32 i=0; iGetEntryCount(); ++i) + exportedProperty(xStylePropertiesSupplier->GetEntryAPIName(i)); + + // the font properties are exported as single properties, but there is a FontDescriptor property which + // collects them all-in-one, this has been exported implicitly + exportedProperty(PROPERTY_FONT); + + // for the DateFormat and TimeFormat, there exist wrapper properties which has been exported as + // style, too + exportedProperty(PROPERTY_DATEFORMAT); + exportedProperty(PROPERTY_TIMEFORMAT); + + // the following properties should have been exported at the shape already: + exportedProperty( "VerticalAlign" ); + exportedProperty( "WritingMode" ); + exportedProperty( "ScaleMode" ); + // ditto the TextWritingMode + exportedProperty( "WritingMode" ); + } + + void OPropertyExport::exportGenericPropertyAttribute( + const sal_uInt16 _nAttributeNamespaceKey, const OUString& _pAttributeName, const char* _pPropertyName) + { + DBG_CHECK_PROPERTY_ASCII_NO_TYPE( _pPropertyName ); + + OUString sPropertyName = OUString::createFromAscii(_pPropertyName); + exportedProperty(sPropertyName); + + Any aCurrentValue = m_xProps->getPropertyValue(sPropertyName); + if (!aCurrentValue.hasValue()) + // nothing to do without a concrete value + return; + + OUString sValue = implConvertAny(aCurrentValue); + if (sValue.isEmpty() && (TypeClass_STRING == aCurrentValue.getValueTypeClass())) + { + // check whether or not the property is allowed to be VOID + Property aProperty = m_xPropertyInfo->getPropertyByName(sPropertyName); + if ((aProperty.Attributes & PropertyAttribute::MAYBEVOID) == 0) + // the string is empty, and the property is not allowed to be void + // -> don't need to write the attribute, 'cause missing it is unambiguous + return; + } + + // finally add the attribute to the context + AddAttribute(_nAttributeNamespaceKey, _pAttributeName, sValue); + } + + void OPropertyExport::exportStringSequenceAttribute(const sal_uInt16 _nAttributeNamespaceKey, const OUString& _pAttributeName, + const OUString& _rPropertyName) + { + const sal_Unicode _aListSeparator = ','; + const sal_Unicode _aQuoteCharacter = '"'; + DBG_CHECK_PROPERTY( _rPropertyName, Sequence< OUString > ); + + Sequence< OUString > aItems; + m_xProps->getPropertyValue( _rPropertyName ) >>= aItems; + + OUStringBuffer sFinalList; + + // unfortunately the OUString can't append single sal_Unicode characters ... + const OUString sQuote(&_aQuoteCharacter, 1); + const OUString sSeparator(&_aListSeparator, 1); + const bool bQuote = !sQuote.isEmpty(); + + // concatenate the string items + const OUString* pItems = aItems.getConstArray(); + const OUString* pEnd = pItems + aItems.getLength(); + const OUString* pLastElement = pEnd - 1; + for ( ; + pItems != pEnd; + ++pItems + ) + { + OSL_ENSURE(-1 == pItems->indexOf(_aQuoteCharacter), + "OPropertyExport::exportStringSequenceAttribute: there is an item which contains the quote character!"); + + if (bQuote) + sFinalList.append(sQuote); + sFinalList.append(*pItems); + if (bQuote) + sFinalList.append(sQuote); + + if (pItems != pLastElement) + sFinalList.append(sSeparator); + } + + if (!sFinalList.isEmpty()) + AddAttribute(_nAttributeNamespaceKey, _pAttributeName, sFinalList.makeStringAndClear()); + + exportedProperty( _rPropertyName ); + } + + OUString OPropertyExport::implConvertAny(const Any& _rValue) + { + OUStringBuffer aBuffer; + switch (_rValue.getValueTypeClass()) + { + case TypeClass_STRING: + { // extract the string + OUString sCurrentValue; + _rValue >>= sCurrentValue; + aBuffer.append(sCurrentValue); + } + break; + case TypeClass_DOUBLE: + // let the unit converter format is as string + ::sax::Converter::convertDouble(aBuffer, getDouble(_rValue)); + break; + case TypeClass_BOOLEAN: + aBuffer = getBOOL(_rValue) ? m_sValueTrue : m_sValueFalse; + break; + case TypeClass_BYTE: + case TypeClass_UNSIGNED_SHORT: + case TypeClass_SHORT: + case TypeClass_LONG: + // let the unit converter format is as string + aBuffer.append(getINT32(_rValue)); + break; + case TypeClass_UNSIGNED_LONG: + case TypeClass_HYPER: + aBuffer.append(getINT64(_rValue)); + break; + case TypeClass_UNSIGNED_HYPER: + aBuffer.append(static_cast(_rValue.get())); + break; + case TypeClass_ENUM: + { + // convert it into an int32 + sal_Int32 nValue = 0; + ::cppu::enum2int(nValue, _rValue); + aBuffer.append(nValue); + } + break; + default: + { // hmmm... what else do we know? + double fValue = 0; + css::util::Date aDate; + css::util::Time aTime; + css::util::DateTime aDateTime; + if (_rValue >>= aDate) + { + Date aToolsDate( Date::EMPTY ); + ::utl::typeConvert(aDate, aToolsDate); + fValue = aToolsDate.GetDate(); + } + else if (_rValue >>= aTime) + { + fValue = aTime.Hours / static_cast(::tools::Time::hourPerDay) + + aTime.Minutes / static_cast(::tools::Time::minutePerDay) + + aTime.Seconds / static_cast(::tools::Time::secondPerDay) + + aTime.NanoSeconds / static_cast(::tools::Time::nanoSecPerDay); + } + else if (_rValue >>= aDateTime) + { + DateTime aToolsDateTime( DateTime::EMPTY ); + ::utl::typeConvert(aDateTime, aToolsDateTime); + // the time part (the digits behind the comma) + fValue = aTime.Hours / static_cast(::tools::Time::hourPerDay) + + aTime.Minutes / static_cast(::tools::Time::minutePerDay) + + aTime.Seconds / static_cast(::tools::Time::secondPerDay) + + aTime.NanoSeconds / static_cast(::tools::Time::nanoSecPerDay); + // plus the data part (the digits in front of the comma) + fValue += aToolsDateTime.GetDate(); + } + else + { + // if any other types are added here, please remember to adjust implGetPropertyXMLType accordingly + + // no more options ... + OSL_FAIL("OPropertyExport::implConvertAny: unsupported value type!"); + break; + } + // let the unit converter format is as string + ::sax::Converter::convertDouble(aBuffer, fValue); + } + break; + } + + return aBuffer.makeStringAndClear(); + } + + token::XMLTokenEnum OPropertyExport::implGetPropertyXMLType(const css::uno::Type& _rType) + { + // handle the type description + switch (_rType.getTypeClass()) + { + case TypeClass_STRING: + return token::XML_STRING; + case TypeClass_DOUBLE: + case TypeClass_BYTE: + case TypeClass_SHORT: + case TypeClass_LONG: + case TypeClass_HYPER: + case TypeClass_ENUM: + return token::XML_FLOAT; + case TypeClass_BOOLEAN: + return token::XML_BOOLEAN; + + default: + return token::XML_FLOAT; + } + } + +#ifdef DBG_UTIL + void OPropertyExport::AddAttribute( sal_uInt16 _nPrefix, const OUString& _rName, const OUString& _rValue ) + { + OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName( _rName ).isEmpty(), + "OPropertyExport::AddAttribute: already have such an attribute"); + + m_rContext.getGlobalContext().AddAttribute( _nPrefix, _rName, _rValue ); + } + + void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue) + { + OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::xmloff::token::GetXMLToken(_eName)).isEmpty(), + "OPropertyExport::AddAttribute: already have such an attribute"); + + m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _rValue); + } + + void OPropertyExport::AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue ) + { + OSL_ENSURE(m_rContext.getGlobalContext().GetXAttrList()->getValueByName(::xmloff::token::GetXMLToken(_eName)).isEmpty(), + "OPropertyExport::AddAttribute: already have such an attribute"); + + m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _eValue); + } + + void OPropertyExport::dbg_implCheckProperty(const OUString& _rPropertyName, const Type* _pType) + { + try + { + // the property must exist + if (!m_xPropertyInfo->hasPropertyByName(_rPropertyName)) + { + SAL_WARN("xmloff.forms", "OPropertyExport: " + "no property with the name " + _rPropertyName + "!"); + return; + } + + if (_pType) + { + // and it must have the correct type + Property aPropertyDescription = m_xPropertyInfo->getPropertyByName(_rPropertyName); + OSL_ENSURE(aPropertyDescription.Type.equals(*_pType), "OPropertyExport::dbg_implCheckProperty: invalid property type!"); + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.forms", "could not check the property!"); + } + } +#endif // DBG_UTIL - dbg_implCheckProperty + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/propertyexport.hxx b/xmloff/source/forms/propertyexport.hxx new file mode 100644 index 000000000..b848ab6e4 --- /dev/null +++ b/xmloff/source/forms/propertyexport.hxx @@ -0,0 +1,413 @@ +/* -*- 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 + +#include + +#include "formattributes.hxx" +#include +#include +#include +#include +#include "callbacks.hxx" +#include "strings.hxx" + +enum class BoolAttrFlags { + DefaultFalse = 0x00, + DefaultTrue = 0x01, + DefaultVoid = 0x02, + InverseSemantics = 0x04, +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + +namespace xmloff +{ + + // if sal_True, indicates that the semantic of the property referred by _pPropertyName + // is inverse to the semantic of the XML attribute.
+ // I.e. if the property value is , has to be written and vice versa. + //

Be careful with _bDefault and _bInverseSemantics: if _bInverseSemantics + // is , the current property value is inverted before comparing it to the default.

+ + class IFormsExportContext; + //= OPropertyExport + /** provides export related tools for attribute handling + +

(The name is somewhat misleading. It's not only a PropertyExport, but in real an ElementExport. + Anyway.)

+ */ + class OPropertyExport + { + private: + std::set m_aRemainingProps; + // see examinePersistence + + void exportRelativeTargetLocation(const OUString& _sPropertyName, CCAFlags _nProperty,bool _bAddType); + + protected: + IFormsExportContext& m_rContext; + + const css::uno::Reference< css::beans::XPropertySet > + m_xProps; + const css::uno::Reference< css::beans::XPropertySetInfo > + m_xPropertyInfo; + const css::uno::Reference< css::beans::XPropertyState > + m_xPropertyState; + + // caching + OUString m_sValueTrue; + OUString m_sValueFalse; + + public: + /** constructs an object capable of handling attributes for export + @param _rContext + the export context to which's attribute list the property translation should be added + @param m_xControl + the property set to be exported + */ + OPropertyExport(IFormsExportContext& _rContext, + const css::uno::Reference< css::beans::XPropertySet >& _rxProps); + + protected: + /** examines a property set given for all properties which's value are to made persistent + +

upon return the m_aRemainingProps will be filled with the names of all properties + which need to be stored

+ */ + void examinePersistence(); + + template< typename T > void exportRemainingPropertiesSequence( + css::uno::Any const & value, + token::XMLTokenEnum eValueAttName); + + void exportRemainingProperties(); + + /** indicates that a property has been handled by a derived class, without using the helper methods of this + class. + +

Calling this method is necessary in case you use the suggested mechanism for the generic export of + properties. This means that you want to use exportRemainingProperties, which exports + all properties which need to ('cause they haven't been exported with one of the other type-specific + methods).

+ +

In this case you should call exportedProperty for every property you export yourself, so the property + will be flagged as already handled

+ */ + void exportedProperty(const OUString& _rPropertyName) + { m_aRemainingProps.erase(_rPropertyName); } + + /** add an attribute which is represented by a string property to the export context + + @param _nNamespaceKey + the key of the namespace to use for the attribute name. Is used with the namespace map + provided by the export context. + @param _pAttributeName + the name of the attribute to add. Must not contain any namespace + @param _pPropertyName + the name of the property to ask the control for + */ + void exportStringPropertyAttribute( + const sal_uInt16 _nNamespaceKey, + const OUString& _pAttributeName, + const OUString& _rPropertyName + ); + + /** add an attribute which is represented by a boolean property to the export context + + @param _nNamespaceKey + the key of the namespace to use for the attribute name. Is used with the namespace map + provided by the export context. + @param _pAttributeName + the name of the attribute to add. Must not contain any namespace (it's added automatically) + @param _pPropertyName + the name of the property to ask the control for + @param _nBooleanAttributeFlags + specifies the default and the "alignment" (inverse semantics) of the boolean property + */ + void exportBooleanPropertyAttribute( + const sal_uInt16 _nNamespaceKey, + const OUString& _pAttributeName, + const OUString& _rPropertyName, + const BoolAttrFlags _nBooleanAttributeFlags); + + /** add an attribute which is represented by a sal_Int16 property to the export context + + @param _nNamespaceKey + the key of the namespace to use for the attribute name. Is used with the namespace map + provided by the export context. + @param _pAttributeName + the name of the attribute to add. Must not contain any namespace (it's added automatically) + @param _pPropertyName + the name of the property to ask the control for + @param _nDefault + the default of the attribute. See force parameter. + @param force + if true and the property is not set or does not contain a sal_Int16, + then _nDefault is written out. + if false and the current property value equals _nDefault, + then no attribute is added. + */ + void exportInt16PropertyAttribute( + const sal_uInt16 _nNamespaceKey, + const OUString& _pAttributeName, + const OUString& _rPropertyName, + const sal_Int16 _nDefault, + const bool force = false); + + /** add an attribute which is represented by a sal_Int32 property to the export context + + @param _nNamespaceKey + the key of the namespace to use for the attribute name. Is used with the namespace map + provided by the export context. + @param _pAttributeName + the name of the attribute to add. Must not contain any namespace (it's added automatically) + @param _pPropertyName + the name of the property to ask the control for + @param _nDefault + the default of the attribute. If the current property value equals this default, no + attribute is added. + */ + void exportInt32PropertyAttribute( + const sal_uInt16 _nNamespaceKey, + const OUString& _pAttributeName, + const OUString& _rPropertyName, + const sal_Int32 _nDefault); + + /** add an attribute which is represented by an enum property to the export context + + @param _nNamespaceKey + the key of the namespace to use for the attribute name. Is used with the namespace map + provided by the export context. + @param _pAttributeName + the name of the attribute to add. Must not contain any namespace (it's added automatically) + @param _pPropertyName + the name of the property to ask the control for + @param _pValueMap + the map to use when converting the property value to an attribute value + @param _nDefault + the default of the attribute. If the current property value equals this default, no + attribute is added. + */ + template + void exportEnumPropertyAttribute( + const sal_uInt16 _nNamespaceKey, + const OUString& _pAttributeName, + const OUString& _rPropertyName, + const SvXMLEnumMapEntry* _pValueMap, + const EnumT _nDefault, + const bool _bVoidDefault = false) + { + exportEnumPropertyAttributeImpl(_nNamespaceKey, _pAttributeName, _rPropertyName, + reinterpret_cast*>(_pValueMap), + static_cast(_nDefault), _bVoidDefault); + } + void exportEnumPropertyAttributeImpl( + const sal_uInt16 _nNamespaceKey, + const OUString& _pAttributeName, + const OUString& _rPropertyName, + const SvXMLEnumMapEntry* _pValueMap, + const sal_uInt16 _nDefault, + const bool _bVoidDefault); + + // some very special methods for some very special attribute/property pairs + + /** add the hlink:target-frame attribute to the export context. + +

The value of this attribute is extracted from the TargetFrame property of the object given.

+ +

The property needs a special handling because conflicts between the default values for the attribute + and the property.

+ */ + void exportTargetFrameAttribute(); + + /** add the form:href attribute to the export context. + +

The value of this attribute is extracted from the TargetURL property of the object given.

+ +

The property needs a special handling because the URL's need to be made relative

+ +

If _bAddType is set, an additional xlink:type="simple" attribute is also added.

+ */ + void exportTargetLocationAttribute(bool _bAddType) { exportRelativeTargetLocation(PROPERTY_TARGETURL,CCAFlags::TargetLocation,_bAddType); } + + /** add the form:image attribute to the export context. + +

The value of this attribute is extracted from the ImageURL property of the object given.

+ +

The property needs a special handling because the URL's need to be made relative

+ */ + void exportImageDataAttribute() { exportRelativeTargetLocation(PROPERTY_GRAPHIC, CCAFlags::ImageData, false); } + + /** flag the style properties as 'already exported' + +

We don't have style support right now, so the only thing the method does is removing the style-relevant + properties from the list of yet-to-be-exported properties (m_aRemainingProps)

+ */ + void flagStyleProperties(); + + /** add an arbitrary attribute extracted from an arbitrary property to the export context + +

The current value of the property specified with _pPropertyName is taken and converted + into a string, no matter what type it has. (Okay, there are the usual limitations: We know Date, Datetime, + double, integer ... to name just a few).

+ +

In case the property value is (void), no attribute is added

+ +

In case the property value is an empty string, and the property is a not allowed to be (void), + no attribute is added

+ +

In case the property value is a sequence of any type, no attribute is added, 'cause sequences can't be + transported as attribute. In the debug version, an additional assertion will occur if you nonetheless try + to do this.

+ + @param _nNamespaceKey + the key of the namespace to use for the attribute name. Is used with the namespace map + provided by the export context. + @param _pAttributeName + the name of the attribute to add. Must not contain any namespace (it's added automatically) + @param _pPropertyName + the name of the property to ask the object for + */ + void exportGenericPropertyAttribute( + const sal_uInt16 _nAttributeNamespaceKey, + const OUString& _pAttributeName, + const char* _pPropertyName); + + /** exports a property value, which is a string sequence, as attribute + +

The elements of the string sequence given are quoted and concatenated, with the characters used for + this to be chosen by the caller

+ +

If you use the quote character, no check (except assertions) is made if one of the list items + contains the quote character

+ +

If you don't use the quote character, no check (except assertions) is made if one of the list items + contains the separator character (which would be deadly when reimporting the string)

+ + @param _nNamespaceKey + the key of the namespace to use for the attribute name. Is used with the namespace map + provided by the export context. + @param _pAttributeName + the name of the attribute to add. Must not contain any namespace (it's added automatically) + @param _pPropertyName + the name of the property to ask the object for + */ + void exportStringSequenceAttribute( + const sal_uInt16 _nAttributeNamespaceKey, + const OUString& _pAttributeName, + const OUString& _rPropertyName); + + /** determines whether the given property is to be exported + +

Currently, the method simply checks whether the property's state is not PropertyState.DEFAULT, + or whether the property is a dynamic property (i.e. added via an XPropertyContainer). + So, take care when using the method - the heuristics is not applicable for all properties.

+ */ + bool shouldExportProperty( const OUString& i_propertyName ) const; + + /** tries to convert an arbitrary Any into an string + +

If the type contained in the Any is not supported, the returned string will be empty. In the + debug version, an additional assertion occurs.

+ + @param _rValue + the value to convert + */ + OUString implConvertAny( + const css::uno::Any& _rValue); + + /** + @return + token which can be used in the form:property element's type attribute + to describe the type of a value.
+ Possible types returned are +
    +
  • boolean: _rValue was interpreted as boolean value before converting + it into a string
  • +
  • float: _rValue was interpreted as 64 bit floating point 16bit integer, 32bit integer or 64 bit integer value before + converting it into a string
  • +
  • string: _rValue did not need any conversion as it already was a string
  • +
+ If the type is not convertible, float is returned + */ + static ::xmloff::token::XMLTokenEnum implGetPropertyXMLType(const css::uno::Type& _rType); + +#ifdef DBG_UTIL + void AddAttribute( sal_uInt16 _nPrefix, const OUString& _rName, const OUString& _rValue ); + void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue); + void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue ); +#else + // in the product version, inline this, so it does not cost us extra time calling into our method + void AddAttribute( sal_uInt16 _nPrefix, const OUString& _rName, const OUString& _rValue ) + { m_rContext.getGlobalContext().AddAttribute( _nPrefix, _rName, _rValue ); } + void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, const OUString& _rValue) + { m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _rValue); } + void AddAttribute(sal_uInt16 _nPrefix, ::xmloff::token::XMLTokenEnum _eName, ::xmloff::token::XMLTokenEnum _eValue ) + { m_rContext.getGlobalContext().AddAttribute(_nPrefix, _eName, _eValue); } +#endif + +#ifdef DBG_UTIL + protected: + /** check a given property set for the existence and type correctness of a given property + +

This method is available in the non-product version only.

+ + @param _rPropertyName + the name of the property to ask the control model for + @param _pType + the expected type of the property. May be NULL, in this case no type check is made. + @return sal_True, if the property exists and is of the correct type + */ + void dbg_implCheckProperty( + const OUString& _rPropertyName, + const css::uno::Type* _pType); + +// void dbg_implCheckProperty( +// const char* _rPropertyName, +// const css::uno::Type* _pType) +// { +// dbg_implCheckProperty(OUString::createFromAscii(_rPropertyName), _pType); +// } +#endif + }; + + //= helper +#ifdef DBG_UTIL + #define DBG_CHECK_PROPERTY(name, type) \ + dbg_implCheckProperty(name, &cppu::UnoType::get()) + + #define DBG_CHECK_PROPERTY_NO_TYPE(name) \ + dbg_implCheckProperty(name, nullptr) + + #define DBG_CHECK_PROPERTY_ASCII_NO_TYPE( name ) \ + dbg_implCheckProperty( OUString::createFromAscii( name ), nullptr ) +#else + #define DBG_CHECK_PROPERTY(name, type) + #define DBG_CHECK_PROPERTY_NO_TYPE(name) + #define DBG_CHECK_PROPERTY_ASCII_NO_TYPE( name ) +#endif + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/propertyimport.cxx b/xmloff/source/forms/propertyimport.cxx new file mode 100644 index 000000000..ded9fa856 --- /dev/null +++ b/xmloff/source/forms/propertyimport.cxx @@ -0,0 +1,524 @@ +/* -*- 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 + +#include + +#include "propertyimport.hxx" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::xmloff::token; + +namespace xmloff +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::xml; + using ::com::sun::star::xml::sax::XAttributeList; + using ::com::sun::star::xml::sax::XFastAttributeList; + + // NO using namespace ...util !!! + // need a tools Date/Time/DateTime below, which would conflict with the uno types then + +#define TYPE_DATE 1 +#define TYPE_TIME 2 +#define TYPE_DATETIME 3 + +//= PropertyConversion +namespace +{ + css::util::Time lcl_getTime(double _nValue) + { + css::util::Time aTime; + sal_uInt64 nIntValue = static_cast(_nValue * ::tools::Time::nanoSecPerDay); + aTime.NanoSeconds = nIntValue % ::tools::Time::nanoSecPerSec; + nIntValue /= ::tools::Time::nanoSecPerSec; + aTime.Seconds = nIntValue % ::tools::Time::secondPerMinute; + nIntValue /= ::tools::Time::secondPerMinute; + aTime.Minutes = nIntValue % ::tools::Time::minutePerHour; + nIntValue /= ::tools::Time::minutePerHour; + OSL_ENSURE(nIntValue < 24, "lcl_getTime: more than a day?"); + aTime.Hours = nIntValue; + + return aTime; + } + + css::util::Date lcl_getDate( double _nValue ) + { + Date aToolsDate(static_cast(_nValue)); + css::util::Date aDate; + ::utl::typeConvert(aToolsDate, aDate); + return aDate; + } +} + +Any PropertyConversion::convertString( const css::uno::Type& _rExpectedType, + const OUString& _rReadCharacters, const SvXMLEnumMapEntry* _pEnumMap, const bool _bInvertBoolean ) +{ + Any aReturn; + bool bEnumAsInt = false; + switch (_rExpectedType.getTypeClass()) + { + case TypeClass_BOOLEAN: // sal_Bool + { + bool bValue; + bool bSuccess = + ::sax::Converter::convertBool(bValue, _rReadCharacters); + OSL_ENSURE(bSuccess, + OStringBuffer("PropertyConversion::convertString: could not convert \"" + + OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) + + "\" into a boolean!").getStr()); + aReturn <<= (_bInvertBoolean ? !bValue : bValue); + } + break; + case TypeClass_SHORT: // sal_Int16 + case TypeClass_LONG: // sal_Int32 + if (!_pEnumMap) + { // it's a real int32/16 property + sal_Int32 nValue(0); + bool bSuccess = + ::sax::Converter::convertNumber(nValue, _rReadCharacters); + OSL_ENSURE(bSuccess, + OStringBuffer("PropertyConversion::convertString: could not convert \"" + + OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) + + "\" into an integer!").getStr()); + if (TypeClass_SHORT == _rExpectedType.getTypeClass()) + aReturn <<= static_cast(nValue); + else + aReturn <<= nValue; + break; + } + bEnumAsInt = true; + [[fallthrough]]; + case TypeClass_ENUM: + { + sal_uInt16 nEnumValue(0); + bool bSuccess = SvXMLUnitConverter::convertEnum(nEnumValue, _rReadCharacters, _pEnumMap); + OSL_ENSURE(bSuccess, "PropertyConversion::convertString: could not convert to an enum value!"); + + if (bEnumAsInt) + if (TypeClass_SHORT == _rExpectedType.getTypeClass()) + aReturn <<= static_cast(nEnumValue); + else + aReturn <<= static_cast(nEnumValue); + else + aReturn = ::cppu::int2enum(static_cast(nEnumValue), _rExpectedType); + } + break; + case TypeClass_HYPER: + { + OSL_FAIL("PropertyConversion::convertString: 64-bit integers not implemented yet!"); + } + break; + case TypeClass_DOUBLE: + { + double nValue; + bool bSuccess = + ::sax::Converter::convertDouble(nValue, _rReadCharacters); + OSL_ENSURE(bSuccess, + OStringBuffer(OString::Concat("PropertyConversion::convertString: could not convert \"") + + OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) + + "\" into a double!").getStr()); + aReturn <<= nValue; + } + break; + case TypeClass_STRING: + aReturn <<= _rReadCharacters; + break; + case TypeClass_STRUCT: + { + sal_Int32 nType = 0; + if ( _rExpectedType.equals( ::cppu::UnoType< css::util::Date >::get() ) ) + nType = TYPE_DATE; + else if ( _rExpectedType.equals( ::cppu::UnoType< css::util::Time >::get() ) ) + nType = TYPE_TIME; + else if ( _rExpectedType.equals( ::cppu::UnoType< css::util::DateTime >::get() ) ) + nType = TYPE_DATETIME; + + if ( nType ) + { + // first extract the double + double nValue = 0; + bool bSuccess = + ::sax::Converter::convertDouble(nValue, _rReadCharacters); + OSL_ENSURE(bSuccess, + OStringBuffer("PropertyConversion::convertString: could not convert \"" + + OUStringToOString(_rReadCharacters, RTL_TEXTENCODING_ASCII_US) + + "\" into a double!").getStr()); + + // then convert it into the target type + switch (nType) + { + case TYPE_DATE: + { + OSL_ENSURE(std::modf(nValue, &o3tl::temporary(double())) == 0, + "PropertyConversion::convertString: a Date value with a fractional part?"); + aReturn <<= lcl_getDate(nValue); + } + break; + case TYPE_TIME: + { + OSL_ENSURE((static_cast(nValue)) == 0, + "PropertyConversion::convertString: a tools::Time value with more than a fractional part?"); + aReturn <<= lcl_getTime(nValue); + } + break; + case TYPE_DATETIME: + { + css::util::Time aTime = lcl_getTime(nValue); + css::util::Date aDate = lcl_getDate(nValue); + + css::util::DateTime aDateTime; + aDateTime.NanoSeconds = aTime.NanoSeconds; + aDateTime.Seconds = aTime.Seconds; + aDateTime.Minutes = aTime.Minutes; + aDateTime.Hours = aTime.Hours; + aDateTime.Day = aDate.Day; + aDateTime.Month = aDate.Month; + aDateTime.Year = aDate.Year; + aReturn <<= aDateTime; + } + break; + } + } + else + OSL_FAIL("PropertyConversion::convertString: unsupported property type!"); + } + break; + default: + OSL_FAIL("PropertyConversion::convertString: invalid type class!"); + } + + return aReturn; +} + +Type PropertyConversion::xmlTypeToUnoType( const OUString& _rType ) +{ + Type aUnoType( cppu::UnoType::get() ); + + static std::map< OUString, css::uno::Type > s_aTypeNameMap + { + { token::GetXMLToken( token::XML_BOOLEAN ) , cppu::UnoType::get()}, + // Not a copy paste error, quotation from: + // http://nabble.documentfoundation.org/Question-unoType-for-getXmlToken-dbaccess-reportdesign-module-tp4109071p4109116.html + // all numeric types (including the UNO double) + // consistently map to XML_FLOAT, so taking the extra precision from the + // C++ type "float" to "double" makes absolute sense + { token::GetXMLToken( token::XML_FLOAT ) , ::cppu::UnoType::get()}, + { token::GetXMLToken( token::XML_STRING ) , ::cppu::UnoType::get()}, + { token::GetXMLToken( token::XML_VOID ) , cppu::UnoType::get() }, + }; + + const std::map< OUString, css::uno::Type >::iterator aTypePos = s_aTypeNameMap.find( _rType ); + OSL_ENSURE( s_aTypeNameMap.end() != aTypePos, "PropertyConversion::xmlTypeToUnoType: invalid property name!" ); + if ( s_aTypeNameMap.end() != aTypePos ) + aUnoType = aTypePos->second; + + return aUnoType; +} + +//= OPropertyImport +OPropertyImport::OPropertyImport(OFormLayerXMLImport_Impl& _rImport) + :SvXMLImportContext(_rImport.getGlobalContext()) + ,m_rContext(_rImport) + ,m_bTrackAttributes(false) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > OPropertyImport::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + if( (nElement & TOKEN_MASK) == token::XML_PROPERTIES ) + { + return new OPropertyElementsContext( m_rContext.getGlobalContext(), this); + } + else + SAL_WARN("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement)); + return nullptr; +} + +void OPropertyImport::startFastElement(sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& xAttrList) +{ + + // assume the 'worst' case: all attributes describe properties. This should save our property array + // some reallocs + m_aValues.reserve(sax_fastparser::castToFastAttributeList(xAttrList).size()); + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + handleAttribute(aIter.getToken(), aIter.toString()); + + if (m_bTrackAttributes) + m_aEncounteredAttributes.insert(aIter.getToken() & TOKEN_MASK); + } + + // TODO: create PropertyValues for all the attributes which were not present, because they were implied + // this is necessary as soon as we have properties where the XML default is different from the property + // default +} + +bool OPropertyImport::encounteredAttribute(sal_Int32 nAttributeToken) const +{ + OSL_ENSURE(m_bTrackAttributes, "OPropertyImport::encounteredAttribute: attribute tracking not enabled!"); + return m_aEncounteredAttributes.end() != m_aEncounteredAttributes.find(nAttributeToken & TOKEN_MASK); +} + +void OPropertyImport::characters(const OUString& _rChars ) +{ + // ignore them (should be whitespace only) + OSL_ENSURE(_rChars.trim().isEmpty(), "OPropertyImport::Characters: non-whitespace characters!"); +} + +bool OPropertyImport::handleAttribute(sal_Int32 nAttributeToken, const OUString& _rValue) +{ + const OAttribute2Property::AttributeAssignment* pProperty = m_rContext.getAttributeMap().getAttributeTranslation(nAttributeToken & TOKEN_MASK); + if (pProperty) + { + // create and store a new PropertyValue + PropertyValue aNewValue; + aNewValue.Name = pProperty->sPropertyName; + + // convert the value string into the target type + if ((nAttributeToken & TOKEN_MASK) == token::XML_HREF) + { + aNewValue.Value <<= m_rContext.getGlobalContext().GetAbsoluteReference(_rValue); + } + else + { + aNewValue.Value = PropertyConversion::convertString( + pProperty->aPropertyType, _rValue, pProperty->pEnumMap, + pProperty->bInverseSemantics); + } + implPushBackPropertyValue( aNewValue ); + return true; + } + if ((nAttributeToken & TOKEN_MASK) != token::XML_TYPE) // xlink:type is valid but ignored for + { + SAL_WARN( "xmloff", "OPropertyImport::handleAttribute: Can't handle " + << SvXMLImport::getPrefixAndNameFromToken(nAttributeToken) << "=" << _rValue ); + return false; + } + return true; +} + +//= OPropertyElementsContext +OPropertyElementsContext::OPropertyElementsContext(SvXMLImport& _rImport, + const OPropertyImportRef& _rPropertyImporter) + :SvXMLImportContext(_rImport) + ,m_xPropertyImporter(_rPropertyImporter) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > OPropertyElementsContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( (nElement & TOKEN_MASK) == XML_PROPERTY ) + { + return new OSinglePropertyContext(GetImport(), m_xPropertyImporter); + } + else if( (nElement & TOKEN_MASK) == XML_LIST_PROPERTY ) + { + return new OListPropertyContext( GetImport(), m_xPropertyImporter ); + } + return nullptr; +} + +#if OSL_DEBUG_LEVEL > 0 + void OPropertyElementsContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) + { + OSL_ENSURE(0 == xAttrList->getFastAttributes().getLength(), "OPropertyElementsContext::StartElement: the form:properties element should not have attributes!"); + } + + void OPropertyElementsContext::characters(const OUString& _rChars) + { + OSL_ENSURE(_rChars.trim().isEmpty(), "OPropertyElementsContext::Characters: non-whitespace characters detected!"); + } +#endif + +//= OSinglePropertyContext +OSinglePropertyContext::OSinglePropertyContext(SvXMLImport& _rImport, + const OPropertyImportRef& _rPropertyImporter) + :SvXMLImportContext(_rImport) + ,m_xPropertyImporter(_rPropertyImporter) +{ +} + +void OSinglePropertyContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + css::beans::PropertyValue aPropValue; // the property the instance imports currently + css::uno::Type aPropType; // the type of the property the instance imports currently + + OUString sType, sValue; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(FORM, XML_PROPERTY_NAME): + aPropValue.Name = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_VALUE_TYPE): + sType = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_VALUE): + case XML_ELEMENT(OFFICE, XML_BOOLEAN_VALUE): + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + sValue = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // the name of the property + OSL_ENSURE(!aPropValue.Name.isEmpty(), "OSinglePropertyContext::StartElement: invalid property name!"); + + // needs to be translated into a css::uno::Type + aPropType = PropertyConversion::xmlTypeToUnoType( sType ); + if( TypeClass_VOID == aPropType.getTypeClass() ) + { + aPropValue.Value = Any(); + } + else + { + aPropValue.Value = + PropertyConversion::convertString(aPropType, + sValue); + } + + // now that we finally have our property value, add it to our parent object + if( !aPropValue.Name.isEmpty() ) + m_xPropertyImporter->implPushBackGenericPropertyValue(aPropValue); +} + +//= OListPropertyContext +OListPropertyContext::OListPropertyContext( SvXMLImport& _rImport, + const OPropertyImportRef& _rPropertyImporter ) + :SvXMLImportContext( _rImport ) + ,m_xPropertyImporter( _rPropertyImporter ) +{ +} + +void OListPropertyContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(FORM, XML_PROPERTY_NAME): + m_sPropertyName = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_VALUE_TYPE): + m_sPropertyType = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +void OListPropertyContext::endFastElement(sal_Int32 ) +{ + OSL_ENSURE( !m_sPropertyName.isEmpty() && !m_sPropertyType.isEmpty(), + "OListPropertyContext::EndElement: no property name or type!" ); + + if ( m_sPropertyName.isEmpty() || m_sPropertyType.isEmpty() ) + return; + + Sequence< Any > aListElements( m_aListValues.size() ); + Any* pListElement = aListElements.getArray(); + css::uno::Type aType = PropertyConversion::xmlTypeToUnoType( m_sPropertyType ); + for ( const auto& rListValue : m_aListValues ) + { + *pListElement = PropertyConversion::convertString( aType, rListValue ); + ++pListElement; + } + + PropertyValue aSequenceValue; + aSequenceValue.Name = m_sPropertyName; + aSequenceValue.Value <<= aListElements; + + m_xPropertyImporter->implPushBackGenericPropertyValue( aSequenceValue ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > OListPropertyContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( (nElement & TOKEN_MASK) == XML_LIST_VALUE ) + { + m_aListValues.emplace_back(); + return new OListValueContext( GetImport(), *m_aListValues.rbegin() ); + } + return nullptr; +} + +//= OListValueContext +OListValueContext::OListValueContext( SvXMLImport& _rImport, OUString& _rListValueHolder ) + :SvXMLImportContext( _rImport ) + ,m_rListValueHolder( _rListValueHolder ) +{ +} + +void OListValueContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(OFFICE, XML_VALUE): + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + case XML_ELEMENT(OFFICE, XML_BOOLEAN_VALUE): + m_rListValueHolder = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/propertyimport.hxx b/xmloff/source/forms/propertyimport.hxx new file mode 100644 index 000000000..b4b660d5b --- /dev/null +++ b/xmloff/source/forms/propertyimport.hxx @@ -0,0 +1,226 @@ +/* -*- 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 + +#include + +#include +#include "formattributes.hxx" +#include +#include +#include "layerimport.hxx" + +namespace com::sun::star::util { + struct Time; + struct Date; +} + +namespace xmloff +{ + + //= PropertyConversion + class PropertyConversion + { + public: + template + static css::uno::Any convertString( + const css::uno::Type& _rExpectedType, + const OUString& _rReadCharacters, + const SvXMLEnumMapEntry* _pEnumMap = nullptr + ) + { + return convertString(_rExpectedType, _rReadCharacters, + reinterpret_cast*>(_pEnumMap), /*_bInvertBoolean*/false); + } + static css::uno::Any convertString( + const css::uno::Type& _rExpectedType, + const OUString& _rReadCharacters, + const SvXMLEnumMapEntry* _pEnumMap = nullptr, + const bool _bInvertBoolean = false + ); + + static css::uno::Type xmlTypeToUnoType( const OUString& _rType ); + }; + + class OFormLayerXMLImport_Impl; + //= OPropertyImport + /** Helper class for importing property values + +

This class imports properties which are stored as attributes as well as properties which + are stored in <form:properties> elements.

+ */ + class OPropertyImport : public SvXMLImportContext + { + friend class OSinglePropertyContext; + friend class OListPropertyContext; + + protected: + typedef ::std::vector< css::beans::PropertyValue > PropertyValueArray; + PropertyValueArray m_aValues; + PropertyValueArray m_aGenericValues; + // the values which the instance collects between StartElement and EndElement + + o3tl::sorted_vector m_aEncounteredAttributes; + + OFormLayerXMLImport_Impl& m_rContext; + + bool m_bTrackAttributes; + + // TODO: think about the restriction that the class does not know anything about the object it is importing. + // Perhaps this object should be known to the class, so setting the properties ('normal' ones as well as + // style properties) can be done in our own EndElement instead of letting derived classes do this. + + public: + OPropertyImport(OFormLayerXMLImport_Impl& _rImport); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& _rxAttrList) override; + virtual void SAL_CALL characters(const OUString& _rChars) override; + + protected: + /** handle one single attribute. + +

This is called for every attribute of the element. This class' implementation checks if the attribute + describes a property, if so, it is added to m_aValues.

+ +

All non-property attributes should be handled in derived classes.

+ + @param _nNamespaceKey + key of the namespace used in the attribute + @param _rLocalName + local (relative to the namespace) attribute name + @param _rValue + attribute value + */ + virtual bool handleAttribute(sal_Int32 nElement, const OUString& _rValue); + + /** determine if the element imported by the object had a given attribute. +

Please be aware of the fact that the name given must be a local name, i.e. not contain a namespace. + All form relevant attributes are in the same namespace, so this would be a redundant information.

+ */ + bool encounteredAttribute(sal_Int32 nElement) const; + + /** enables the tracking of the encountered attributes +

The tracking will raise the import costs a little bit, but it's cheaper than + derived classes tracking this themself.

+ */ + void enableTrackAttributes() { m_bTrackAttributes = true; } + + void implPushBackPropertyValue(const css::beans::PropertyValue& _rProp) + { + m_aValues.push_back(_rProp); + } + + void implPushBackPropertyValue( const OUString& _rName, const css::uno::Any& _rValue ) + { + m_aValues.push_back( css::beans::PropertyValue( + _rName, -1, _rValue, css::beans::PropertyState_DIRECT_VALUE ) ); + } + + void implPushBackGenericPropertyValue(const css::beans::PropertyValue& _rProp) + { + m_aGenericValues.push_back(_rProp); + } + }; + typedef rtl::Reference OPropertyImportRef; + + //= OPropertyElementsContext + /** helper class for importing the <form:properties> element + */ + class OPropertyElementsContext : public SvXMLImportContext + { + OPropertyImportRef m_xPropertyImporter; // to add the properties + + public: + OPropertyElementsContext(SvXMLImport& _rImport, + const OPropertyImportRef& _rPropertyImporter); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +#if OSL_DEBUG_LEVEL > 0 + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL characters(const OUString& _rChars) override; +#endif + }; + + //= OSinglePropertyContext + /** helper class for importing a single <form:property> element + */ + class OSinglePropertyContext : public SvXMLImportContext + { + OPropertyImportRef m_xPropertyImporter; // to add the properties + + public: + OSinglePropertyContext(SvXMLImport& _rImport, + const OPropertyImportRef& _rPropertyImporter); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + }; + + //= OListPropertyContext + class OListPropertyContext : public SvXMLImportContext + { + OPropertyImportRef m_xPropertyImporter; + OUString m_sPropertyName; + OUString m_sPropertyType; + ::std::vector< OUString > m_aListValues; + + public: + OListPropertyContext( SvXMLImport& _rImport, + const OPropertyImportRef& _rPropertyImporter ); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + }; + + //= OListValueContext + class OListValueContext : public SvXMLImportContext + { + OUString& m_rListValueHolder; + + public: + OListValueContext( SvXMLImport& _rImport, OUString& _rListValueHolder ); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/strings.hxx b/xmloff/source/forms/strings.hxx new file mode 100644 index 000000000..f12067504 --- /dev/null +++ b/xmloff/source/forms/strings.hxx @@ -0,0 +1,209 @@ +/* -*- 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 + +namespace xmloff +{ + + // properties + #define PROPERTY_CLASSID "ClassId" + #define PROPERTY_ECHOCHAR "EchoChar" + #define PROPERTY_MULTILINE "MultiLine" + #define PROPERTY_NAME "Name" + #define PROPERTY_GRAPHIC "Graphic" + #define PROPERTY_LABEL "Label" + #define PROPERTY_TARGETFRAME "TargetFrame" + #define PROPERTY_TARGETURL "TargetURL" + #define PROPERTY_TITLE "Tag" + #define PROPERTY_DROPDOWN "Dropdown" + #define PROPERTY_PRINTABLE "Printable" + #define PROPERTY_READONLY "ReadOnly" + #define PROPERTY_DEFAULT_STATE "DefaultState" + #define PROPERTY_TABSTOP "Tabstop" + #define PROPERTY_STATE "State" + #define PROPERTY_ENABLED "Enabled" + #define PROPERTY_ENABLEVISIBLE "EnableVisible" + #define PROPERTY_MAXTEXTLENGTH "MaxTextLen" + #define PROPERTY_LINECOUNT "LineCount" + #define PROPERTY_TABINDEX "TabIndex" + #define PROPERTY_COMMAND "Command" + #define PROPERTY_DATASOURCENAME "DataSourceName" + #define PROPERTY_FILTER "Filter" + #define PROPERTY_ORDER "Order" + #define PROPERTY_ALLOWDELETES "AllowDeletes" + #define PROPERTY_ALLOWINSERTS "AllowInserts" + #define PROPERTY_ALLOWUPDATES "AllowUpdates" + #define PROPERTY_APPLYFILTER "ApplyFilter" + #define PROPERTY_ESCAPEPROCESSING "EscapeProcessing" + #define PROPERTY_IGNORERESULT "IgnoreResult" + #define PROPERTY_SUBMIT_ENCODING "SubmitEncoding" + #define PROPERTY_SUBMIT_METHOD "SubmitMethod" + #define PROPERTY_COMMAND_TYPE "CommandType" + #define PROPERTY_NAVIGATION "NavigationBarMode" + #define PROPERTY_CYCLE "Cycle" + #define PROPERTY_BUTTONTYPE "ButtonType" + #define PROPERTY_DATAFIELD "DataField" + #define PROPERTY_BOUNDCOLUMN "BoundColumn" + #define PROPERTY_EMPTY_IS_NULL "ConvertEmptyToNull" + #define PROPERTY_INPUT_REQUIRED "InputRequired" + #define PROPERTY_LISTSOURCE "ListSource" + #define PROPERTY_LISTSOURCETYPE "ListSourceType" + #define PROPERTY_ECHO_CHAR "EchoChar" + #define PROPERTY_STRICTFORMAT "StrictFormat" + #define PROPERTY_AUTOCOMPLETE "Autocomplete" + #define PROPERTY_MULTISELECTION "MultiSelection" + #define PROPERTY_DEFAULTBUTTON "DefaultButton" + #define PROPERTY_TRISTATE "TriState" + #define PROPERTY_CONTROLLABEL "LabelControl" + #define PROPERTY_STRING_ITEM_LIST "StringItemList" + #define PROPERTY_VALUE_SEQ "ValueItemList" + #define PROPERTY_DEFAULT_SELECT_SEQ "DefaultSelection" + #define PROPERTY_SELECT_SEQ "SelectedItems" + #define PROPERTY_DATE_MIN "DateMin" + #define PROPERTY_DATE_MAX "DateMax" + #define PROPERTY_TIME_MIN "TimeMin" + #define PROPERTY_TIME_MAX "TimeMax" + #define PROPERTY_VALUE_MIN "ValueMin" + #define PROPERTY_VALUE_MAX "ValueMax" + #define PROPERTY_EFFECTIVE_MIN "EffectiveMin" + #define PROPERTY_EFFECTIVE_MAX "EffectiveMax" + #define PROPERTY_DEFAULT_DATE "DefaultDate" + #define PROPERTY_DATE "Date" + #define PROPERTY_DEFAULT_TIME "DefaultTime" + #define PROPERTY_TIME "Time" + #define PROPERTY_DEFAULT_VALUE "DefaultValue" + #define PROPERTY_VALUE "Value" + #define PROPERTY_HIDDEN_VALUE "HiddenValue" + #define PROPERTY_DEFAULT_TEXT "DefaultText" + #define PROPERTY_TEXT "Text" + #define PROPERTY_EFFECTIVE_VALUE "EffectiveValue" + #define PROPERTY_EFFECTIVE_DEFAULT "EffectiveDefault" + #define PROPERTY_REFVALUE "RefValue" + #define PROPERTY_URL "URL" + #define PROPERTY_FONT "FontDescriptor" + #define PROPERTY_BACKGROUNDCOLOR "BackgroundColor" + #define PROPERTY_MASTERFIELDS "MasterFields" + #define PROPERTY_DETAILFIELDS "DetailFields" + #define PROPERTY_COLUMNSERVICENAME "ColumnServiceName" + #define PROPERTY_FORMATKEY "FormatKey" + #define PROPERTY_ALIGN "Align" + #define PROPERTY_BORDER "Border" + #define PROPERTY_AUTOCONTROLFOCUS "AutomaticControlFocus" + #define PROPERTY_APPLYDESIGNMODE "ApplyFormDesignMode" + #define PROPERTY_FORMATSSUPPLIER "FormatsSupplier" + #define PROPERTY_LOCALE "Locale" + #define PROPERTY_FORMATSTRING "FormatString" + #define PROPERTY_DATEFORMAT "DateFormat" + #define PROPERTY_TIMEFORMAT "TimeFormat" + #define PROPERTY_PERSISTENCE_MAXTEXTLENGTH "PersistenceMaxTextLength" + #define PROPERTY_SCROLLVALUE_MIN "ScrollValueMin" + #define PROPERTY_SCROLLVALUE_MAX "ScrollValueMax" + #define PROPERTY_SCROLLVALUE "ScrollValue" + #define PROPERTY_SCROLLVALUE_DEFAULT "DefaultScrollValue" + #define PROPERTY_LINE_INCREMENT "LineIncrement" + #define PROPERTY_BLOCK_INCREMENT "BlockIncrement" + #define PROPERTY_REPEAT_DELAY "RepeatDelay" + #define PROPERTY_SPINVALUE "SpinValue" + #define PROPERTY_SPINVALUE_MIN "SpinValueMin" + #define PROPERTY_SPINVALUE_MAX "SpinValueMax" + #define PROPERTY_DEFAULT_SPINVALUE "DefaultSpinValue" + #define PROPERTY_SPIN_INCREMENT "SpinIncrement" + #define PROPERTY_ORIENTATION "Orientation" + #define PROPERTY_TOGGLE "Toggle" + #define PROPERTY_FOCUS_ON_CLICK "FocusOnClick" + #define PROPERTY_VISUAL_EFFECT "VisualEffect" + #define PROPERTY_IMAGE_POSITION "ImagePosition" + #define PROPERTY_IMAGE_ALIGN "ImageAlign" + #define PROPERTY_SCALE_IMAGE "ScaleImage" + #define PROPERTY_GROUP_NAME "GroupName" + + #define PROPERTY_BOUND_CELL "BoundCell" + #define PROPERTY_LIST_CELL_RANGE "CellRange" + #define PROPERTY_ADDRESS "Address" + #define PROPERTY_FILE_REPRESENTATION "PersistentRepresentation" + #define PROPERTY_RICH_TEXT "RichText" + + // services + inline constexpr OUStringLiteral SERVICE_SPREADSHEET_DOCUMENT = u"com.sun.star.sheet.SpreadsheetDocument"; + inline constexpr OUStringLiteral SERVICE_CELLVALUEBINDING = u"com.sun.star.table.CellValueBinding"; + inline constexpr OUStringLiteral SERVICE_LISTINDEXCELLBINDING = u"com.sun.star.table.ListPositionCellBinding"; + inline constexpr OUStringLiteral SERVICE_CELLRANGELISTSOURCE = u"com.sun.star.table.CellRangeListSource"; + inline constexpr OUStringLiteral SERVICE_ADDRESS_CONVERSION = u"com.sun.star.table.CellAddressConversion"; + inline constexpr OUStringLiteral SERVICE_RANGEADDRESS_CONVERSION = u"com.sun.star.table.CellRangeAddressConversion"; + + // old service names (compatibility) + #define SERVICE_PERSISTENT_COMPONENT_FORM "stardiv.one.form.component.Form" + #define SERVICE_PERSISTENT_COMPONENT_EDIT "stardiv.one.form.component.Edit" + #define SERVICE_PERSISTENT_COMPONENT_LISTBOX "stardiv.one.form.component.ListBox" + #define SERVICE_PERSISTENT_COMPONENT_COMBOBOX "stardiv.one.form.component.ComboBox" + #define SERVICE_PERSISTENT_COMPONENT_RADIOBUTTON "stardiv.one.form.component.RadioButton" + #define SERVICE_PERSISTENT_COMPONENT_GROUPBOX "stardiv.one.form.component.GroupBox" + #define SERVICE_PERSISTENT_COMPONENT_FIXEDTEXT "stardiv.one.form.component.FixedText" + #define SERVICE_PERSISTENT_COMPONENT_COMMANDBUTTON "stardiv.one.form.component.CommandButton" + #define SERVICE_PERSISTENT_COMPONENT_CHECKBOX "stardiv.one.form.component.CheckBox" + #define SERVICE_PERSISTENT_COMPONENT_GRID "stardiv.one.form.component.Grid" + #define SERVICE_PERSISTENT_COMPONENT_IMAGEBUTTON "stardiv.one.form.component.ImageButton" + #define SERVICE_PERSISTENT_COMPONENT_FILECONTROL "stardiv.one.form.component.FileControl" + #define SERVICE_PERSISTENT_COMPONENT_TIMEFIELD "stardiv.one.form.component.TimeField" + #define SERVICE_PERSISTENT_COMPONENT_DATEFIELD "stardiv.one.form.component.DateField" + #define SERVICE_PERSISTENT_COMPONENT_NUMERICFIELD "stardiv.one.form.component.NumericField" + #define SERVICE_PERSISTENT_COMPONENT_CURRENCYFIELD "stardiv.one.form.component.CurrencyField" + #define SERVICE_PERSISTENT_COMPONENT_PATTERNFIELD "stardiv.one.form.component.PatternField" + #define SERVICE_PERSISTENT_COMPONENT_HIDDENCONTROL "stardiv.one.form.component.Hidden" + #define SERVICE_PERSISTENT_COMPONENT_IMAGECONTROL "stardiv.one.form.component.ImageControl" + #define SERVICE_PERSISTENT_COMPONENT_FORMATTEDFIELD "stardiv.one.form.component.FormattedField" + + // new service names, the old ones are translated into this new ones + inline constexpr OUStringLiteral SERVICE_FORM = u"com.sun.star.form.component.Form"; + inline constexpr OUStringLiteral SERVICE_EDIT = u"com.sun.star.form.component.TextField"; + inline constexpr OUStringLiteral SERVICE_LISTBOX = u"com.sun.star.form.component.ListBox"; + inline constexpr OUStringLiteral SERVICE_COMBOBOX = u"com.sun.star.form.component.ComboBox"; + inline constexpr OUStringLiteral SERVICE_RADIOBUTTON = u"com.sun.star.form.component.RadioButton"; + inline constexpr OUStringLiteral SERVICE_GROUPBOX = u"com.sun.star.form.component.GroupBox"; + inline constexpr OUStringLiteral SERVICE_FIXEDTEXT = u"com.sun.star.form.component.FixedText"; + inline constexpr OUStringLiteral SERVICE_COMMANDBUTTON = u"com.sun.star.form.component.CommandButton"; + inline constexpr OUStringLiteral SERVICE_CHECKBOX = u"com.sun.star.form.component.CheckBox"; + inline constexpr OUStringLiteral SERVICE_GRID = u"com.sun.star.form.component.GridControl"; + inline constexpr OUStringLiteral SERVICE_IMAGEBUTTON = u"com.sun.star.form.component.ImageButton"; + inline constexpr OUStringLiteral SERVICE_FILECONTROL = u"com.sun.star.form.component.FileControl"; + inline constexpr OUStringLiteral SERVICE_TIMEFIELD = u"com.sun.star.form.component.TimeField"; + inline constexpr OUStringLiteral SERVICE_DATEFIELD = u"com.sun.star.form.component.DateField"; + inline constexpr OUStringLiteral SERVICE_NUMERICFIELD = u"com.sun.star.form.component.NumericField"; + inline constexpr OUStringLiteral SERVICE_CURRENCYFIELD = u"com.sun.star.form.component.CurrencyField"; + inline constexpr OUStringLiteral SERVICE_PATTERNFIELD = u"com.sun.star.form.component.PatternField"; + inline constexpr OUStringLiteral SERVICE_HIDDENCONTROL = u"com.sun.star.form.component.HiddenControl"; + inline constexpr OUStringLiteral SERVICE_IMAGECONTROL = u"com.sun.star.form.component.DatabaseImageControl"; + inline constexpr OUStringLiteral SERVICE_FORMATTEDFIELD = u"com.sun.star.form.component.FormattedField"; + + // various strings + #define EVENT_NAME_SEPARATOR "::" + inline constexpr OUStringLiteral EVENT_TYPE = u"EventType"; + inline constexpr OUStringLiteral EVENT_LIBRARY = u"Library"; + inline constexpr OUStringLiteral EVENT_LOCALMACRONAME = u"MacroName"; + inline constexpr OUStringLiteral EVENT_SCRIPTURL = u"Script"; + inline constexpr OUStringLiteral EVENT_STAROFFICE = u"StarOffice"; + #define EVENT_STARBASIC "StarBasic" + inline constexpr OUStringLiteral EVENT_APPLICATION = u"application"; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/valueproperties.cxx b/xmloff/source/forms/valueproperties.cxx new file mode 100644 index 000000000..c2f60e5a2 --- /dev/null +++ b/xmloff/source/forms/valueproperties.cxx @@ -0,0 +1,180 @@ +/* -*- 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 "valueproperties.hxx" +#include "strings.hxx" +#include +#include + +namespace xmloff +{ + + using namespace ::com::sun::star::form; + + //= OValuePropertiesMetaData + void OValuePropertiesMetaData::getValuePropertyNames( + OControlElement::ElementType _eType, sal_Int16 _nFormComponentType, + char const * & _rpCurrentValuePropertyName, char const * & _rpValuePropertyName) + { + // reset the pointers in case we can't determine the property names + _rpCurrentValuePropertyName = _rpValuePropertyName = nullptr; + switch (_nFormComponentType) + { + case FormComponentType::TEXTFIELD: + if (OControlElement::FORMATTED_TEXT == _eType) + { + _rpCurrentValuePropertyName = PROPERTY_EFFECTIVE_VALUE; + _rpValuePropertyName = PROPERTY_EFFECTIVE_DEFAULT; + } + else + { + if (OControlElement::PASSWORD != _eType) + // no CurrentValue" for passwords + _rpCurrentValuePropertyName = PROPERTY_TEXT; + _rpValuePropertyName = PROPERTY_DEFAULT_TEXT; + } + break; + + case FormComponentType::NUMERICFIELD: + case FormComponentType::CURRENCYFIELD: + _rpCurrentValuePropertyName = PROPERTY_VALUE; + _rpValuePropertyName = PROPERTY_DEFAULT_VALUE; + break; + + case FormComponentType::PATTERNFIELD: + case FormComponentType::FILECONTROL: + case FormComponentType::COMBOBOX: + _rpValuePropertyName = PROPERTY_DEFAULT_TEXT; + [[fallthrough]]; + case FormComponentType::COMMANDBUTTON: + _rpCurrentValuePropertyName = PROPERTY_TEXT; + break; + + case FormComponentType::CHECKBOX: + case FormComponentType::RADIOBUTTON: + _rpValuePropertyName = PROPERTY_REFVALUE; + break; + + case FormComponentType::HIDDENCONTROL: + _rpValuePropertyName = PROPERTY_HIDDEN_VALUE; + break; + + case FormComponentType::SCROLLBAR: + _rpCurrentValuePropertyName = PROPERTY_SCROLLVALUE; + _rpValuePropertyName = PROPERTY_SCROLLVALUE_DEFAULT; + break; + + case FormComponentType::SPINBUTTON: + _rpCurrentValuePropertyName = PROPERTY_SPINVALUE; + _rpValuePropertyName = PROPERTY_DEFAULT_SPINVALUE; + break; + + default: + SAL_WARN( "xmloff", "OValuePropertiesMetaData::getValuePropertyNames: unsupported component type!" ); + break; + } + } + + void OValuePropertiesMetaData::getValueLimitPropertyNames(sal_Int16 _nFormComponentType, + char const * & _rpMinValuePropertyName, char const * & _rpMaxValuePropertyName) + { + _rpMinValuePropertyName = _rpMaxValuePropertyName = nullptr; + switch (_nFormComponentType) + { + case FormComponentType::NUMERICFIELD: + case FormComponentType::CURRENCYFIELD: + _rpMinValuePropertyName = PROPERTY_VALUE_MIN; + _rpMaxValuePropertyName = PROPERTY_VALUE_MAX; + break; + + case FormComponentType::TEXTFIELD: + _rpMinValuePropertyName = PROPERTY_EFFECTIVE_MIN; + _rpMaxValuePropertyName = PROPERTY_EFFECTIVE_MAX; + break; + + case FormComponentType::SCROLLBAR: + _rpMinValuePropertyName = PROPERTY_SCROLLVALUE_MIN; + _rpMaxValuePropertyName = PROPERTY_SCROLLVALUE_MAX; + break; + + case FormComponentType::SPINBUTTON: + _rpMinValuePropertyName = PROPERTY_SPINVALUE_MIN; + _rpMaxValuePropertyName = PROPERTY_SPINVALUE_MAX; + break; + + default: + SAL_WARN("xmloff", "OValuePropertiesMetaData::getValueLimitPropertyNames: unsupported component type!" ); + break; + } + } + + void OValuePropertiesMetaData::getRuntimeValuePropertyNames( + OControlElement::ElementType _eType, sal_Int16 _nFormComponentType, + char const * & _rpValuePropertyName, char const * & _rpDefaultValuePropertyName ) + { + // reset the pointers in case we can't determine the property names + _rpValuePropertyName = _rpDefaultValuePropertyName = nullptr; + switch (_nFormComponentType) + { + case FormComponentType::TEXTFIELD: + if (OControlElement::FORMATTED_TEXT == _eType) + { + _rpValuePropertyName = PROPERTY_EFFECTIVE_VALUE; + _rpDefaultValuePropertyName = PROPERTY_EFFECTIVE_DEFAULT; + } + else + { + _rpValuePropertyName = PROPERTY_TEXT; + _rpDefaultValuePropertyName = PROPERTY_DEFAULT_TEXT; + } + break; + + case FormComponentType::DATEFIELD: + _rpValuePropertyName = PROPERTY_DATE; + _rpDefaultValuePropertyName = PROPERTY_DEFAULT_DATE; + break; + + case FormComponentType::TIMEFIELD: + _rpValuePropertyName = PROPERTY_TIME; + _rpDefaultValuePropertyName = PROPERTY_DEFAULT_TIME; + break; + + case FormComponentType::NUMERICFIELD: + case FormComponentType::CURRENCYFIELD: + case FormComponentType::PATTERNFIELD: + case FormComponentType::FILECONTROL: + case FormComponentType::COMBOBOX: + case FormComponentType::SCROLLBAR: + case FormComponentType::SPINBUTTON: + // For these types, the runtime properties are the same as the ones which in the XML + // stream are named "value properties" + getValuePropertyNames( _eType, _nFormComponentType, _rpValuePropertyName, _rpDefaultValuePropertyName ); + break; + + case FormComponentType::CHECKBOX: + case FormComponentType::RADIOBUTTON: + _rpValuePropertyName = PROPERTY_STATE; + _rpDefaultValuePropertyName = PROPERTY_DEFAULT_STATE; + break; + } + } + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/forms/valueproperties.hxx b/xmloff/source/forms/valueproperties.hxx new file mode 100644 index 000000000..b22b57bb0 --- /dev/null +++ b/xmloff/source/forms/valueproperties.hxx @@ -0,0 +1,67 @@ +/* -*- 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 "controlelement.hxx" + +namespace xmloff +{ + + //= OValuePropertiesMetaData + class OValuePropertiesMetaData + { + protected: + OValuePropertiesMetaData() { } + + public: + /** calculate the property names for the current-value and the value attribute. + +

If controls of the given FormComponentType do not have any of the properties requested, + the respective out parameter will be set to NULL.

+ */ + static void getValuePropertyNames( + OControlElement::ElementType _eType, + sal_Int16 _nFormComponentType, + char const * & _rpCurrentValuePropertyName, + char const * & _rpValuePropertyName); + + /** calculate the property names for the min-value and the max-value attribute. + +

If controls of the given FormComponentType do not have any of the properties requested, + the respective out parameter will be set to NULL.

+ */ + static void getValueLimitPropertyNames( + sal_Int16 _nFormComponentType, + char const * & _rpMinValuePropertyName, + char const * & _rpMaxValuePropertyName); + + /** calculate the names of the properties which, at runtime, are used for value and + default value. + */ + static void getRuntimeValuePropertyNames( + OControlElement::ElementType _eType, + sal_Int16 _nFormComponentType, + char const * & _rpValuePropertyName, + char const * & _rpDefaultValuePropertyName); + }; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/meta/MetaExportComponent.cxx b/xmloff/source/meta/MetaExportComponent.cxx new file mode 100644 index 000000000..b5ad3177e --- /dev/null +++ b/xmloff/source/meta/MetaExportComponent.cxx @@ -0,0 +1,181 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +XMLMetaExportComponent::XMLMetaExportComponent( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, SvXMLExportFlags nFlags ) +: SvXMLExport( xContext, implementationName, util::MeasureUnit::CM, XML_TEXT, nFlags ) +{ +} + +XMLMetaExportComponent::~XMLMetaExportComponent() +{ +} + +void SAL_CALL XMLMetaExportComponent::setSourceDocument( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XComponent >& xDoc ) +{ + try + { + SvXMLExport::setSourceDocument( xDoc ); + } + catch( lang::IllegalArgumentException& ) + { + // allow to use document properties service without model access + // this is required for document properties exporter + mxDocProps = + uno::Reference< document::XDocumentProperties >::query( xDoc ); + if( !mxDocProps.is() ) + throw lang::IllegalArgumentException(); + } +} + +ErrCode XMLMetaExportComponent::exportDoc( enum XMLTokenEnum ) +{ + uno::Reference< xml::sax::XDocumentHandler > xDocHandler = GetDocHandler(); + + if( !(getExportFlags() & SvXMLExportFlags::OASIS) ) + { + uno::Reference< uno::XComponentContext > xContext = getComponentContext(); + try + { + static const ::comphelper::PropertyMapEntry aInfoMap[] = + { + { OUString("Class"), 0, + ::cppu::UnoType::get(), + beans::PropertyAttribute::MAYBEVOID, 0}, + }; + uno::Reference< beans::XPropertySet > xConvPropSet( + ::comphelper::GenericPropertySet_CreateInstance( + new ::comphelper::PropertySetInfo( aInfoMap ) ) ); + + xConvPropSet->setPropertyValue("Class", uno::Any(GetXMLToken( XML_TEXT )) ); + + uno::Reference< beans::XPropertySet > xPropSet = + getExportInfo().is() + ? PropertySetMerger_CreateInstance( getExportInfo(), + xConvPropSet ) + : getExportInfo(); + + uno::Sequence< uno::Any > aArgs{ uno::Any(xDocHandler), uno::Any(xPropSet), + uno::Any(GetModel()) }; + + // get filter component + xDocHandler.set( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.Oasis2OOoTransformer", aArgs, xContext), + uno::UNO_QUERY_THROW ); + + SetDocHandler( xDocHandler ); + } + catch( css::uno::Exception& ) + { + OSL_FAIL( "Cannot instantiate com.sun.star.comp.Oasis2OOoTransformer!"); + } + } + + + xDocHandler->startDocument(); + + addChaffWhenEncryptedStorage(); + + { + + const SvXMLNamespaceMap& rMap = GetNamespaceMap(); + sal_uInt16 nPos = rMap.GetFirstKey(); + while( USHRT_MAX != nPos ) + { + GetAttrList().AddAttribute( rMap.GetAttrNameByKey( nPos ), rMap.GetNameByKey( nPos ) ); + nPos = GetNamespaceMap().GetNextKey( nPos ); + } + + const char*const pVersion = GetODFVersionAttributeValue(); + + if( pVersion ) + AddAttribute( XML_NAMESPACE_OFFICE, XML_VERSION, + OUString::createFromAscii(pVersion) ); + + SvXMLElementExport aDocElem( *this, XML_NAMESPACE_OFFICE, XML_DOCUMENT_META, + true, true ); + + // NB: office:meta is now written by _ExportMeta + ExportMeta_(); + } + xDocHandler->endDocument(); + return ERRCODE_NONE; +} + +void XMLMetaExportComponent::ExportMeta_() +{ + if (mxDocProps.is()) { + OUString generator( ::utl::DocInfoHelper::GetGeneratorString() ); + // update generator here + mxDocProps->setGenerator(generator); + rtl::Reference pMeta = new SvXMLMetaExport(*this, mxDocProps); + pMeta->Export(); + } else { + SvXMLExport::ExportMeta_(); + } +} + +// methods without content: +void XMLMetaExportComponent::ExportAutoStyles_() {} +void XMLMetaExportComponent::ExportMasterStyles_() {} +void XMLMetaExportComponent::ExportContent_() {} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +XMLMetaExportComponent_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new XMLMetaExportComponent(context, "XMLMetaExportComponent", SvXMLExportFlags::META|SvXMLExportFlags::OASIS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +XMLMetaExportOOo_get_implementation(css::uno::XComponentContext* context, + css::uno::Sequence const&) +{ + return cppu::acquire( + new XMLMetaExportComponent(context, "XMLMetaExportOOo", SvXMLExportFlags::META)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/meta/MetaImportComponent.cxx b/xmloff/source/meta/MetaImportComponent.cxx new file mode 100644 index 000000000..7dcc88611 --- /dev/null +++ b/xmloff/source/meta/MetaImportComponent.cxx @@ -0,0 +1,97 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +namespace { + +class XMLMetaImportComponent : public SvXMLImport +{ +private: + css::uno::Reference< css::document::XDocumentProperties> mxDocProps; + +public: + // XMLMetaImportComponent() throw(); + explicit XMLMetaImportComponent( + const css::uno::Reference< css::uno::XComponentContext >& xContext + ); + +protected: + + virtual SvXMLImportContext *CreateFastContext( sal_Int32 nElement, + const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& xAttrList ) override; + + // XImporter + virtual void SAL_CALL setTargetDocument( const css::uno::Reference< css::lang::XComponent >& xDoc ) override; +}; + +} + +// global functions to support the component + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +XMLMetaImportComponent_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new XMLMetaImportComponent(context)); +} + +XMLMetaImportComponent::XMLMetaImportComponent( + const uno::Reference< uno::XComponentContext >& xContext) + : SvXMLImport(xContext, "") +{ +} + +SvXMLImportContext *XMLMetaImportComponent::CreateFastContext( sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + if (nElement == XML_ELEMENT( OFFICE, XML_DOCUMENT_META )) + { + if (!mxDocProps.is()) { + throw uno::RuntimeException( + "XMLMetaImportComponent::CreateFastContext: setTargetDocument " + "has not been called", *this); + } + return new SvXMLMetaDocumentContext( + *this, mxDocProps); + } + return nullptr; +} + +void SAL_CALL XMLMetaImportComponent::setTargetDocument( + const uno::Reference< lang::XComponent >& xDoc ) +{ + mxDocProps.set( xDoc, uno::UNO_QUERY ); + if( !mxDocProps.is() ) + throw lang::IllegalArgumentException( + "XMLMetaImportComponent::setTargetDocument: argument is no " + "XDocumentProperties", uno::Reference(*this), 0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/meta/xmlmetae.cxx b/xmloff/source/meta/xmlmetae.cxx new file mode 100644 index 000000000..994610a7f --- /dev/null +++ b/xmloff/source/meta/xmlmetae.cxx @@ -0,0 +1,479 @@ +/* -*- 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 +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +static void lcl_AddTwoDigits( OUStringBuffer& rStr, sal_Int32 nVal ) +{ + if ( nVal < 10 ) + rStr.append( '0' ); + rStr.append( nVal ); +} + +OUString +SvXMLMetaExport::GetISODateTimeString( const util::DateTime& rDateTime ) +{ + // return ISO date string "YYYY-MM-DDThh:mm:ss" + + OUStringBuffer sTmp; + sTmp.append( static_cast(rDateTime.Year) ); + sTmp.append( '-' ); + lcl_AddTwoDigits( sTmp, rDateTime.Month ); + sTmp.append( '-' ); + lcl_AddTwoDigits( sTmp, rDateTime.Day ); + sTmp.append( 'T' ); + lcl_AddTwoDigits( sTmp, rDateTime.Hours ); + sTmp.append( ':' ); + lcl_AddTwoDigits( sTmp, rDateTime.Minutes ); + sTmp.append( ':' ); + lcl_AddTwoDigits( sTmp, rDateTime.Seconds ); + + return sTmp.makeStringAndClear(); +} + +void SvXMLMetaExport::SimpleStringElement( const OUString& rText, + sal_uInt16 nNamespace, enum XMLTokenEnum eElementName ) +{ + if ( !rText.isEmpty() ) { + SvXMLElementExport aElem( mrExport, nNamespace, eElementName, + true, false ); + mrExport.Characters( rText ); + } +} + +void SvXMLMetaExport::SimpleDateTimeElement( const util::DateTime & rDate, + sal_uInt16 nNamespace, enum XMLTokenEnum eElementName ) +{ + if (rDate.Month != 0) { // invalid dates are 0-0-0 + OUString sValue = GetISODateTimeString( rDate ); + if ( !sValue.isEmpty() ) { + SvXMLElementExport aElem( mrExport, nNamespace, eElementName, + true, false ); + mrExport.Characters( sValue ); + } + } +} + +void SvXMLMetaExport::MExport_() +{ + // generator + { + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_META, XML_GENERATOR, + true, true ); + mrExport.Characters( ::utl::DocInfoHelper::GetGeneratorString() ); + } + + // document title + SimpleStringElement ( mxDocProps->getTitle(), + XML_NAMESPACE_DC, XML_TITLE ); + + // description + SimpleStringElement ( mxDocProps->getDescription(), + XML_NAMESPACE_DC, XML_DESCRIPTION ); + + // subject + SimpleStringElement ( mxDocProps->getSubject(), + XML_NAMESPACE_DC, XML_SUBJECT ); + + // created... + SimpleStringElement ( mxDocProps->getAuthor(), + XML_NAMESPACE_META, XML_INITIAL_CREATOR ); + SimpleDateTimeElement( mxDocProps->getCreationDate(), + XML_NAMESPACE_META, XML_CREATION_DATE ); + + // modified... + SimpleStringElement ( mxDocProps->getModifiedBy(), + XML_NAMESPACE_DC, XML_CREATOR ); + SimpleDateTimeElement( mxDocProps->getModificationDate(), + XML_NAMESPACE_DC, XML_DATE ); + + // printed... + SimpleStringElement ( mxDocProps->getPrintedBy(), + XML_NAMESPACE_META, XML_PRINTED_BY ); + SimpleDateTimeElement( mxDocProps->getPrintDate(), + XML_NAMESPACE_META, XML_PRINT_DATE ); + + // keywords + const uno::Sequence< OUString > keywords = mxDocProps->getKeywords(); + for (const auto& rKeyword : keywords) { + SvXMLElementExport aKwElem( mrExport, XML_NAMESPACE_META, XML_KEYWORD, + true, false ); + mrExport.Characters( rKeyword ); + } + + // document language + { + OUString sValue = LanguageTag( mxDocProps->getLanguage()).getBcp47( false); + if (!sValue.isEmpty()) { + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DC, XML_LANGUAGE, + true, false ); + mrExport.Characters( sValue ); + } + } + + // editing cycles + { + SvXMLElementExport aElem( mrExport, + XML_NAMESPACE_META, XML_EDITING_CYCLES, + true, false ); + mrExport.Characters( OUString::number( + mxDocProps->getEditingCycles() ) ); + } + + // editing duration + // property is a int32 (seconds) + { + sal_Int32 secs = mxDocProps->getEditingDuration(); + SvXMLElementExport aElem( mrExport, + XML_NAMESPACE_META, XML_EDITING_DURATION, + true, false ); + OUStringBuffer buf; + ::sax::Converter::convertDuration(buf, util::Duration( + false, 0, 0, 0, secs/3600, (secs%3600)/60, secs%60, 0)); + mrExport.Characters(buf.makeStringAndClear()); + } + + // default target + const OUString sDefTarget = mxDocProps->getDefaultTarget(); + if ( !sDefTarget.isEmpty() ) + { + mrExport.AddAttribute( XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, + sDefTarget ); + + //! define strings for xlink:show values + const XMLTokenEnum eShow = sDefTarget == "_blank" ? XML_NEW : XML_REPLACE; + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, eShow ); + + SvXMLElementExport aElem( mrExport, + XML_NAMESPACE_META,XML_HYPERLINK_BEHAVIOUR, + true, false ); + } + + // auto-reload + const OUString sReloadURL = mxDocProps->getAutoloadURL(); + const sal_Int32 sReloadDelay = mxDocProps->getAutoloadSecs(); + if (sReloadDelay != 0 || !sReloadURL.isEmpty()) + { + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, + mrExport.GetRelativeReference( sReloadURL ) ); + + OUStringBuffer buf; + ::sax::Converter::convertDuration(buf, util::Duration(false, 0, 0, 0, + sReloadDelay/3600, (sReloadDelay%3600)/60, sReloadDelay%60, 0)); + mrExport.AddAttribute( XML_NAMESPACE_META, XML_DELAY, + buf.makeStringAndClear()); + + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_META, XML_AUTO_RELOAD, + true, false ); + } + + // template + const OUString sTplPath = mxDocProps->getTemplateURL(); + if ( !sTplPath.isEmpty() ) + { + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST ); + + // template URL + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, + mrExport.GetRelativeReference(sTplPath) ); + + // template name + mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TITLE, + mxDocProps->getTemplateName() ); + + // template date + mrExport.AddAttribute( XML_NAMESPACE_META, XML_DATE, + GetISODateTimeString( mxDocProps->getTemplateDate() ) ); + + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_META, XML_TEMPLATE, + true, false ); + } + + // user defined fields + uno::Reference< beans::XPropertyAccess > xUserDefined( + mxDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); + const uno::Sequence< beans::PropertyValue > props = + xUserDefined->getPropertyValues(); + for (const auto& rProp : props) { + OUStringBuffer sValueBuffer; + OUStringBuffer sType; + if (!::sax::Converter::convertAny(sValueBuffer, sType, rProp.Value)) + { + continue; + } + mrExport.AddAttribute( XML_NAMESPACE_META, XML_NAME, rProp.Name ); + mrExport.AddAttribute( XML_NAMESPACE_META, XML_VALUE_TYPE, + sType.makeStringAndClear() ); + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_META, + XML_USER_DEFINED, true, false ); + mrExport.Characters( sValueBuffer.makeStringAndClear() ); + } + + const uno::Sequence< beans::NamedValue > aDocStatistic = + mxDocProps->getDocumentStatistics(); + // write document statistic if there is any provided + if ( !aDocStatistic.hasElements() ) + return; + + for ( const auto& rDocStat : aDocStatistic ) + { + sal_Int32 nValue = 0; + if ( rDocStat.Value >>= nValue ) + { + OUString aValue = OUString::number( nValue ); + if ( rDocStat.Name == "TableCount" ) + mrExport.AddAttribute( + XML_NAMESPACE_META, XML_TABLE_COUNT, aValue ); + else if ( rDocStat.Name == "ObjectCount" ) + mrExport.AddAttribute( + XML_NAMESPACE_META, XML_OBJECT_COUNT, aValue ); + else if ( rDocStat.Name == "ImageCount" ) + mrExport.AddAttribute( + XML_NAMESPACE_META, XML_IMAGE_COUNT, aValue ); + else if ( rDocStat.Name == "PageCount" ) + mrExport.AddAttribute( + XML_NAMESPACE_META, XML_PAGE_COUNT, aValue ); + else if ( rDocStat.Name == "ParagraphCount" ) + mrExport.AddAttribute( + XML_NAMESPACE_META, XML_PARAGRAPH_COUNT, aValue ); + else if ( rDocStat.Name == "WordCount" ) + mrExport.AddAttribute( + XML_NAMESPACE_META, XML_WORD_COUNT, aValue ); + else if ( rDocStat.Name == "CharacterCount" ) + mrExport.AddAttribute( + XML_NAMESPACE_META, XML_CHARACTER_COUNT, aValue ); + else if ( rDocStat.Name == "CellCount" ) + mrExport.AddAttribute( + XML_NAMESPACE_META, XML_CELL_COUNT, aValue ); + else + { + SAL_WARN("xmloff", "Unknown statistic value!"); + } + } + } + SvXMLElementExport aElem( mrExport, + XML_NAMESPACE_META, XML_DOCUMENT_STATISTIC, true, true ); +} + +const char s_xmlns[] = "xmlns"; +const char s_xmlns2[] = "xmlns:"; +const char s_meta[] = "meta:"; +const char s_href[] = "xlink:href"; + +SvXMLMetaExport::SvXMLMetaExport( + SvXMLExport& i_rExp, + const uno::Reference& i_rDocProps ) : + mrExport( i_rExp ), + mxDocProps( i_rDocProps ), + m_level( 0 ) +{ + assert(mxDocProps.is()); +} + +SvXMLMetaExport::~SvXMLMetaExport() +{ +} + +void SvXMLMetaExport::Export() +{ + uno::Reference< xml::sax::XSAXSerializable> xSAXable(mxDocProps, + uno::UNO_QUERY); + if (xSAXable.is()) { + ::std::vector< beans::StringPair > namespaces; + const SvXMLNamespaceMap & rNsMap(mrExport.GetNamespaceMap()); + for (sal_uInt16 key = rNsMap.GetFirstKey(); + key != USHRT_MAX; key = rNsMap.GetNextKey(key)) { + beans::StringPair ns; + const OUString attrname = rNsMap.GetAttrNameByKey(key); + if (!attrname.startsWith(s_xmlns2, &ns.First) + || attrname == s_xmlns) // default initialized empty string + { + assert(!"namespace attribute not starting with xmlns unexpected"); + } + ns.Second = rNsMap.GetNameByKey(key); + namespaces.push_back(ns); + } + xSAXable->serialize(this, comphelper::containerToSequence(namespaces)); + } else { + // office:meta + SvXMLElementExport aElem( mrExport, XML_NAMESPACE_OFFICE, XML_META, + true, true ); + // fall back to using public interface of XDocumentProperties + MExport_(); + } +} + +// css::xml::sax::XDocumentHandler: +void SAL_CALL +SvXMLMetaExport::startDocument() +{ + // ignore: has already been done by SvXMLExport::exportDoc + assert(m_level == 0 && "SvXMLMetaExport: level error"); +} + +void SAL_CALL +SvXMLMetaExport::endDocument() +{ + // ignore: will be done by SvXMLExport::exportDoc + assert(m_level == 0 && "SvXMLMetaExport: level error"); +} + +// unfortunately, this method contains far too much ugly namespace mangling. +void SAL_CALL +SvXMLMetaExport::startElement(const OUString & i_rName, + const uno::Reference< xml::sax::XAttributeList > & i_xAttribs) +{ + + if (m_level == 0) { + // namespace decls: default ones have been written at the root element + // non-default ones must be preserved here + const sal_Int16 nCount = i_xAttribs->getLength(); + for (sal_Int16 i = 0; i < nCount; ++i) { + const OUString name(i_xAttribs->getNameByIndex(i)); + if (name.startsWith(s_xmlns)) { + bool found(false); + const SvXMLNamespaceMap & rNsMap(mrExport.GetNamespaceMap()); + for (sal_uInt16 key = rNsMap.GetFirstKey(); + key != USHRT_MAX; key = rNsMap.GetNextKey(key)) { + if (name == rNsMap.GetAttrNameByKey(key)) { + found = true; + break; + } + } + if (!found) { + m_preservedNSs.emplace_back(name, + i_xAttribs->getValueByIndex(i)); + } + } + } + // ignore the root: it has been written already + ++m_level; + return; + } + + if (m_level == 1) { + // attach preserved namespace decls from root node here + for (const auto& rPreservedNS : m_preservedNSs) { + const OUString ns(rPreservedNS.First); + bool found(false); + // but only if it is not already there + const sal_Int16 nCount = i_xAttribs->getLength(); + for (sal_Int16 i = 0; i < nCount; ++i) { + const OUString name(i_xAttribs->getNameByIndex(i)); + if (ns == name) { + found = true; + break; + } + } + if (!found) { + mrExport.AddAttribute(ns, rPreservedNS.Second); + } + } + } + + // attach the attributes + if (i_rName.startsWith(s_meta)) { + // special handling for all elements that may have + // xlink:href attributes; these must be made relative + const sal_Int16 nLength = i_xAttribs->getLength(); + for (sal_Int16 i = 0; i < nLength; ++i) { + const OUString name (i_xAttribs->getNameByIndex (i)); + OUString value(i_xAttribs->getValueByIndex(i)); + if (name.startsWith(s_href)) { + value = mrExport.GetRelativeReference(value); + } + mrExport.AddAttribute(name, value); + } + } else { + const sal_Int16 nLength = i_xAttribs->getLength(); + for (sal_Int16 i = 0; i < nLength; ++i) { + const OUString name (i_xAttribs->getNameByIndex(i)); + const OUString value (i_xAttribs->getValueByIndex(i)); + mrExport.AddAttribute(name, value); + } + } + + // finally, start the element + // #i107240# no whitespace here, because the DOM may already contain + // whitespace, which is not cleared when loading and thus accumulates. + mrExport.StartElement(i_rName, m_level <= 1); + ++m_level; +} + +void SAL_CALL +SvXMLMetaExport::endElement(const OUString & i_rName) +{ + --m_level; + if (m_level == 0) { + // ignore the root; see startElement + return; + } + assert(m_level >= 0 && "SvXMLMetaExport: level error"); + mrExport.EndElement(i_rName, false); +} + +void SAL_CALL +SvXMLMetaExport::characters(const OUString & i_rChars) +{ + mrExport.Characters(i_rChars); +} + +void SAL_CALL +SvXMLMetaExport::ignorableWhitespace(const OUString & /*i_rWhitespaces*/) +{ + mrExport.IgnorableWhitespace(/*i_rWhitespaces*/); +} + +void SAL_CALL +SvXMLMetaExport::processingInstruction(const OUString &, + const OUString &) +{ + // ignore; the exporter cannot handle these +} + +void SAL_CALL +SvXMLMetaExport::setDocumentLocator(const uno::Reference&) +{ + // nothing to do here, move along... +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/meta/xmlmetai.cxx b/xmloff/source/meta/xmlmetai.cxx new file mode 100644 index 000000000..3dc240cd1 --- /dev/null +++ b/xmloff/source/meta/xmlmetai.cxx @@ -0,0 +1,318 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace ::xmloff::token; + +namespace { + +/// builds a DOM tree from SAX events, by forwarding to SAXDocumentBuilder +class XMLDocumentBuilderContext : public SvXMLImportContext +{ +private: + css::uno::Reference< css::xml::dom::XSAXDocumentBuilder2> mxDocBuilder; + SvXMLMetaDocumentContext *const m_pTopLevel; + +public: + XMLDocumentBuilderContext(SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + const css::uno::Reference& rDocBuilder, + SvXMLMetaDocumentContext * pTopLevel); + + virtual void SAL_CALL characters( const OUString& aChars ) override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; + + virtual void SAL_CALL startUnknownElement( const OUString& Namespace, const OUString& Name, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override; + + virtual void SAL_CALL endUnknownElement( const OUString& Namespace, const OUString& Name ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +}; + +} + +XMLDocumentBuilderContext::XMLDocumentBuilderContext(SvXMLImport& rImport, + sal_Int32 /*nElement*/, const uno::Reference&, + const uno::Reference& rDocBuilder, + SvXMLMetaDocumentContext *const pTopLevel) + : SvXMLImportContext(rImport) + , mxDocBuilder(rDocBuilder) + , m_pTopLevel(pTopLevel) +{ +} + +void SAL_CALL XMLDocumentBuilderContext::startFastElement( sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList >& xAttribs ) +{ + mxDocBuilder->startFastElement(nElement, xAttribs); +} + +void SAL_CALL XMLDocumentBuilderContext::endFastElement( sal_Int32 nElement ) +{ + mxDocBuilder->endFastElement(nElement); + if (m_pTopLevel) + { + // call this here because in the flat ODF case the top-level + // endFastElement is called only at the very end of the document, + // which is too late to init BuildId + m_pTopLevel->FinishMetaElement(); + } +} + +void SAL_CALL XMLDocumentBuilderContext::startUnknownElement( const OUString& rNamespace, + const OUString& rName, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + mxDocBuilder->startUnknownElement(rNamespace, rName, xAttrList); +} + +void SAL_CALL XMLDocumentBuilderContext::endUnknownElement( const OUString& rNamespace, const OUString& rName ) +{ + mxDocBuilder->endUnknownElement(rNamespace, rName); +} + +void SAL_CALL XMLDocumentBuilderContext::characters( const OUString& rChars ) +{ + mxDocBuilder->characters(rChars); +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL XMLDocumentBuilderContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + return new XMLDocumentBuilderContext(GetImport(), nElement, xAttrList, mxDocBuilder, nullptr); +} + +static void +lcl_initDocumentProperties(SvXMLImport & rImport, + uno::Reference const& xDocBuilder, + uno::Reference const& xDocProps) +{ + uno::Reference< lang::XInitialization > const xInit(xDocProps, + uno::UNO_QUERY_THROW); + try { + xInit->initialize({ uno::Any(xDocBuilder->getDocument()) }); + rImport.SetStatistics(xDocProps->getDocumentStatistics()); + // convert all URLs from relative to absolute + xDocProps->setTemplateURL(rImport.GetAbsoluteReference( + xDocProps->getTemplateURL())); + xDocProps->setAutoloadURL(rImport.GetAbsoluteReference( + xDocProps->getAutoloadURL())); + SvXMLMetaDocumentContext::setBuildId( + xDocProps->getGenerator(), rImport.getImportInfo()); + } catch (const uno::RuntimeException&) { + throw; + } catch (const uno::Exception&) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException( + "SvXMLMetaDocumentContext::initDocumentProperties: " + "properties init exception", + rImport, anyEx); + } +} + +static void +lcl_initGenerator(SvXMLImport & rImport, + uno::Reference const& xDocBuilder) +{ + uno::Reference< xml::dom::XDocument > const xDoc(xDocBuilder->getDocument(), + uno::UNO_SET_THROW); + try { + uno::Reference< xml::xpath::XXPathAPI > const xPath = xml::xpath::XPathAPI::create( + rImport.GetComponentContext() ); + xPath->registerNS(GetXMLToken(XML_NP_OFFICE),GetXMLToken(XML_N_OFFICE)); + xPath->registerNS(GetXMLToken(XML_NP_META), GetXMLToken(XML_N_META)); + + uno::Reference< xml::xpath::XXPathObject > const xObj( + xPath->eval(xDoc, "string(/office:document-meta/office:meta/meta:generator)"), + uno::UNO_SET_THROW); + OUString const value(xObj->getString()); + SvXMLMetaDocumentContext::setBuildId(value, rImport.getImportInfo()); + } catch (const uno::RuntimeException&) { + throw; + } catch (const uno::Exception&) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException( + "SvXMLMetaDocumentContext::initGenerator: exception", + rImport, anyEx); + } +} + +SvXMLMetaDocumentContext::SvXMLMetaDocumentContext(SvXMLImport& rImport, + const uno::Reference& xDocProps) : + SvXMLImportContext( rImport ), + mxDocProps(xDocProps), + mxDocBuilder( + xml::dom::SAXDocumentBuilder::create( + comphelper::getProcessComponentContext())) +{ +// #i103539#: must always read meta.xml for generator, xDocProps unwanted then +// OSL_ENSURE(xDocProps.is(), "SvXMLMetaDocumentContext: no document props"); +} + +SvXMLMetaDocumentContext::~SvXMLMetaDocumentContext() +{ +} + +void SAL_CALL SvXMLMetaDocumentContext::startFastElement(sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + mxDocBuilder->startDocument(); + // hardcode office:document-meta (necessary in case of flat file ODF) + mxDocBuilder->startFastElement(XML_ELEMENT(OFFICE, XML_DOCUMENT_META), xAttrList); +} + +void SvXMLMetaDocumentContext::FinishMetaElement() +{ + // hardcode office:document-meta (necessary in case of flat file ODF) + mxDocBuilder->endFastElement(XML_ELEMENT(OFFICE, XML_DOCUMENT_META)); + mxDocBuilder->endDocument(); + if (mxDocProps.is()) + { + lcl_initDocumentProperties(GetImport(), mxDocBuilder, mxDocProps); + } + else + { + lcl_initGenerator(GetImport(), mxDocBuilder); + } +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL SvXMLMetaDocumentContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(OFFICE, XML_META) ) + return new XMLDocumentBuilderContext( + GetImport(), nElement, xAttrList, mxDocBuilder, this); + return nullptr; +} + +void SvXMLMetaDocumentContext::setBuildId(OUString const& i_rBuildId, const uno::Reference& xImportInfo ) +{ + OUString sBuildId; + // skip to second product + sal_Int32 nBegin = i_rBuildId.indexOf( ' ' ); + if ( nBegin != -1 ) + { + // skip to build information + nBegin = i_rBuildId.indexOf( '/', nBegin ); + if ( nBegin != -1 ) + { + sal_Int32 nEnd = i_rBuildId.indexOf( 'm', nBegin ); + if ( nEnd != -1 ) + { + OUStringBuffer sBuffer( + i_rBuildId.subView( nBegin+1, nEnd-nBegin-1 ) ); + static const OUStringLiteral sBuildCompare( + u"$Build-" ); + nBegin = i_rBuildId.indexOf( sBuildCompare, nEnd ); + if ( nBegin != -1 ) + { + sBuffer.append( '$' ); + sBuffer.append( i_rBuildId.subView(nBegin + sBuildCompare.getLength()) ); + sBuildId = sBuffer.makeStringAndClear(); + } + } + } + } + + if ( sBuildId.isEmpty() ) + { + if ( i_rBuildId.startsWith("StarOffice 7") + || i_rBuildId.startsWith("StarSuite 7") + || i_rBuildId.startsWith("StarOffice 6") + || i_rBuildId.startsWith("StarSuite 6") + || i_rBuildId.startsWith("OpenOffice.org 1")) + { + sBuildId = "645$8687"; + } + else if (i_rBuildId.startsWith("NeoOffice/2")) + { + sBuildId = "680$9134"; // fake NeoOffice as OpenOffice.org 2.2 release + } + } + + // "LibreOffice_project" was hard-coded since LO 3.3.0 + // see utl::DocInfoHelper::GetGeneratorString() + if (i_rBuildId.indexOf("LibreOffice_project/") != -1) + { + OUStringBuffer sNumber; + auto const firstSlash = i_rBuildId.indexOf("/"); + assert(firstSlash != -1); + for (sal_Int32 i = firstSlash + 1; i < i_rBuildId.getLength(); ++i) + { + if (rtl::isAsciiDigit(i_rBuildId[i])) + { + sNumber.append(i_rBuildId[i]); + } + else if ('.' != i_rBuildId[i]) + { + break; + } + } + if (!sNumber.isEmpty()) + { + sBuildId += ";" + sNumber; + } + } + + if ( sBuildId.isEmpty() ) + return; + + try + { + if( xImportInfo.is() ) + { + static const OUStringLiteral aPropName(u"BuildId"); + uno::Reference< beans::XPropertySetInfo > xSetInfo( + xImportInfo->getPropertySetInfo()); + if( xSetInfo.is() && xSetInfo->hasPropertyByName( aPropName ) ) + xImportInfo->setPropertyValue( aPropName, uno::Any( sBuildId ) ); + } + } + catch(const uno::Exception&) + { + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/meta/xmlversion.cxx b/xmloff/source/meta/xmlversion.cxx new file mode 100644 index 000000000..20bf6d5a2 --- /dev/null +++ b/xmloff/source/meta/xmlversion.cxx @@ -0,0 +1,429 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +constexpr OUStringLiteral XMLN_VERSIONSLIST = u"VersionList.xml"; + +XMLVersionListExport::XMLVersionListExport( + const css::uno::Reference< css::uno::XComponentContext >& rContext, + const css::uno::Sequence < css::util::RevisionTag >& rVersions, + const OUString &rFileName, + Reference< XDocumentHandler > const &rHandler ) +: SvXMLExport( rContext, "", rFileName, util::MeasureUnit::CM, rHandler ), + maVersions( rVersions ) +{ + GetNamespaceMap_().AddAtIndex( xmloff::token::GetXMLToken(xmloff::token::XML_NP_DC), + xmloff::token::GetXMLToken(xmloff::token::XML_N_DC), XML_NAMESPACE_DC ); + GetNamespaceMap_().AddAtIndex( xmloff::token::GetXMLToken(xmloff::token::XML_NP_VERSIONS_LIST), + xmloff::token::GetXMLToken(xmloff::token::XML_N_VERSIONS_LIST), XML_NAMESPACE_FRAMEWORK ); +} + +ErrCode XMLVersionListExport::exportDoc( enum ::xmloff::token::XMLTokenEnum ) +{ + GetDocHandler()->startDocument(); + + addChaffWhenEncryptedStorage(); + + sal_uInt16 nPos = SvXMLNamespaceMap::GetIndexByKey( XML_NAMESPACE_DC ); + + AddAttribute( XML_NAMESPACE_NONE, GetNamespaceMap_().GetAttrNameByIndex( nPos ), + GetNamespaceMap_().GetNameByIndex ( nPos ) ); + + nPos = SvXMLNamespaceMap::GetIndexByKey( XML_NAMESPACE_FRAMEWORK ); + AddAttribute( XML_NAMESPACE_NONE, GetNamespaceMap_().GetAttrNameByIndex( nPos ), + GetNamespaceMap_().GetNameByIndex ( nPos ) ); + + { + // the following object will write all collected attributes in its dtor + SvXMLElementExport aRoot( *this, XML_NAMESPACE_FRAMEWORK, xmloff::token::XML_VERSION_LIST, true, true ); + + for ( const util::RevisionTag& rInfo : maVersions ) + { + AddAttribute( XML_NAMESPACE_FRAMEWORK, + xmloff::token::XML_TITLE, + rInfo.Identifier ); + AddAttribute( XML_NAMESPACE_FRAMEWORK, + xmloff::token::XML_COMMENT, + rInfo.Comment ); + AddAttribute( XML_NAMESPACE_FRAMEWORK, + xmloff::token::XML_CREATOR, + rInfo.Author ); + + OUString aDateStr = + SvXMLMetaExport::GetISODateTimeString( rInfo.TimeStamp ); + + AddAttribute( XML_NAMESPACE_DC, xmloff::token::XML_DATE_TIME, aDateStr ); + + // the following object will write all collected attributes in its dtor + SvXMLElementExport aEntry( *this, XML_NAMESPACE_FRAMEWORK, xmloff::token::XML_VERSION_ENTRY, true, true ); + } + } + GetDocHandler()->endDocument(); + return ERRCODE_NONE; +} + +XMLVersionListImport::XMLVersionListImport( + const css::uno::Reference< css::uno::XComponentContext >& rContext, + css::uno::Sequence < css::util::RevisionTag >& rVersions ) +: SvXMLImport(rContext, ""), + maVersions( rVersions ) +{ +} + +XMLVersionListImport::~XMLVersionListImport() noexcept +{} + +SvXMLImportContext *XMLVersionListImport::CreateFastContext( sal_Int32 nElement, + const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + SvXMLImportContext *pContext = nullptr; + + if ( nElement == XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_VERSION_LIST) ) + { + pContext = new XMLVersionListContext( *this ); + } + + return pContext; +} + +XMLVersionListContext::XMLVersionListContext( XMLVersionListImport& rImport) + : SvXMLImportContext( rImport ) +{ +} + +XMLVersionListContext::~XMLVersionListContext() +{} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL +XMLVersionListContext::createFastChildContext(sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList) +{ + SvXMLImportContext *pContext = nullptr; + + if ( nElement == XML_ELEMENT(FRAMEWORK, xmloff::token::XML_VERSION_ENTRY) + || nElement == XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_VERSION_ENTRY) ) + { + pContext = new XMLVersionContext( GetImport(), xAttrList ); + } + + return pContext; +} + +XMLVersionContext::XMLVersionContext( XMLVersionListImport& rImport, + const Reference< XFastAttributeList > & xAttrList ) + : SvXMLImportContext( rImport ) +{ + sax_fastparser::FastAttributeList& rAttribList = + sax_fastparser::castToFastAttributeList( xAttrList ); + if ( rAttribList.getFastAttributeTokens().empty() ) + return; + util::RevisionTag aInfo; + for (auto &aIter : rAttribList) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(FRAMEWORK, xmloff::token::XML_TITLE): + case XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_TITLE): + { + aInfo.Identifier = aIter.toString(); + break; + } + case XML_ELEMENT(FRAMEWORK, xmloff::token::XML_COMMENT): + case XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_COMMENT): + { + aInfo.Comment = aIter.toString(); + break; + } + case XML_ELEMENT(FRAMEWORK, xmloff::token::XML_CREATOR): + case XML_ELEMENT(VERSIONS_LIST, xmloff::token::XML_CREATOR): + { + aInfo.Author = aIter.toString(); + break; + } + case XML_ELEMENT(DC, xmloff::token::XML_DATE_TIME): + { + util::DateTime aTime; + if ( ParseISODateTimeString( aIter.toString(), aTime ) ) + aInfo.TimeStamp = aTime; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } + + uno::Sequence < util::RevisionTag >& aList = rImport.GetList(); + sal_Int32 nLength = aList.getLength(); + aList.realloc( nLength+1 ); + aList.getArray()[nLength] = aInfo; +} + +XMLVersionContext::~XMLVersionContext() +{} + +bool XMLVersionContext::ParseISODateTimeString( + std::u16string_view rString, + util::DateTime& rDateTime ) +{ + bool bSuccess = true; + + std::u16string_view aDateStr, aTimeStr; + size_t nPos = rString.find( 'T' ); + if ( nPos != std::u16string_view::npos ) + { + aDateStr = rString.substr( 0, nPos ); + aTimeStr = rString.substr( nPos + 1 ); + } + else + aDateStr = rString; // no separator: only date part + + sal_Int32 nYear = 0; + sal_Int32 nMonth = 1; + sal_Int32 nDay = 1; + sal_Int32 nHour = 0; + sal_Int32 nMin = 0; + sal_Int32 nSec = 0; + + auto pStr = aDateStr.begin(); + sal_Int32 nDateTokens = 1; + while ( pStr != aDateStr.end() ) + { + if ( *pStr == '-' ) + nDateTokens++; + pStr++; + } + if ( nDateTokens > 3 || aDateStr.empty() ) + bSuccess = false; + else + { + sal_Int32 n = 0; + nYear = o3tl::toInt32(o3tl::getToken(aDateStr, 0, '-', n )); + if ( nYear > 9999 ) + bSuccess = false; + else if ( nDateTokens >= 2 ) + { + nMonth = o3tl::toInt32(o3tl::getToken(aDateStr, 0, '-', n )); + if ( nMonth > 12 ) + bSuccess = false; + else if ( nDateTokens >= 3 ) + { + nDay = o3tl::toInt32(o3tl::getToken(aDateStr, 0, '-', n )); + if ( nDay > 31 ) + bSuccess = false; + } + } + } + + if ( bSuccess && !aTimeStr.empty() ) // time is optional + { + pStr = aTimeStr.begin(); + sal_Int32 nTimeTokens = 1; + while ( pStr != aTimeStr.end() ) + { + if ( *pStr == ':' ) + nTimeTokens++; + pStr++; + } + if ( nTimeTokens > 3 ) + bSuccess = false; + else + { + sal_Int32 n = 0; + nHour = o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', n )); + if ( nHour > 23 ) + bSuccess = false; + else if ( nTimeTokens >= 2 ) + { + nMin = o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', n )); + if ( nMin > 59 ) + bSuccess = false; + else if ( nTimeTokens >= 3 ) + { + nSec = o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', n )); + if ( nSec > 59 ) + bSuccess = false; + } + } + } + } + + if ( bSuccess ) + { + rDateTime.Day = sal::static_int_cast< sal_uInt16 >(nDay); + rDateTime.Month = sal::static_int_cast< sal_uInt16 >(nMonth); + rDateTime.Year = sal::static_int_cast< sal_uInt16 >(nYear); + rDateTime.Hours = sal::static_int_cast< sal_uInt16 >(nHour); + rDateTime.Minutes = sal::static_int_cast< sal_uInt16 >(nMin); + rDateTime.Seconds = sal::static_int_cast< sal_uInt16 >(nSec); + } + + return bSuccess; +} + +void SAL_CALL XMLVersionListPersistence::store( const uno::Reference< embed::XStorage >& xRoot, const uno::Sequence< util::RevisionTag >& rVersions ) +{ + // no storage, no version list! + if ( !xRoot.is() ) + return; + + // get the services needed for writing the xml data + Reference< uno::XComponentContext > xContext = + comphelper::getProcessComponentContext(); + + Reference< XWriter > xWriter = Writer::create(xContext); + + // check whether there's already a sub storage with the version info + // and delete it + OUString sVerName( XMLN_VERSIONSLIST ); + + try { + // open (create) the sub storage with the version info + uno::Reference< io::XStream > xVerStream = xRoot->openStreamElement( + sVerName, + embed::ElementModes::READWRITE | embed::ElementModes::TRUNCATE ); + if ( !xVerStream.is() ) + throw uno::RuntimeException(); + + Reference< io::XOutputStream > xOut = xVerStream->getOutputStream(); + if ( !xOut.is() ) + throw uno::RuntimeException("The stream was successfully opened for writing already!"); + + xWriter->setOutputStream(xOut); + + rtl::Reference< XMLVersionListExport > xExp( new XMLVersionListExport( xContext, rVersions, sVerName, xWriter ) ); + + xExp->exportDoc( ::xmloff::token::XML_VERSION ); + + xVerStream.clear(); // use refcounting for now to dispose + } + catch( uno::Exception& ) + { + // TODO: error handling + } +} + +uno::Sequence< util::RevisionTag > SAL_CALL XMLVersionListPersistence::load( const uno::Reference< embed::XStorage >& xRoot ) +{ + css::uno::Sequence < css::util::RevisionTag > aVersions; + + const OUString sDocName( XMLN_VERSIONSLIST ); + + try { + if ( xRoot.is() && xRoot->hasByName( sDocName ) && xRoot->isStreamElement( sDocName ) ) + { + Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + + InputSource aParserInput; + + uno::Reference< beans::XPropertySet > xProps( xRoot, uno::UNO_QUERY ); + OSL_ENSURE( xProps.is(), "Storage must implement XPropertySet!" ); + if ( xProps.is() ) + { + try { + xProps->getPropertyValue("URL") >>= aParserInput.sSystemId; + } + catch( uno::Exception& ) + {} + } + + uno::Reference< io::XStream > xDocStream = xRoot->openStreamElement( + sDocName, + embed::ElementModes::READ ); + if ( !xDocStream.is() ) + throw uno::RuntimeException(); + + aParserInput.aInputStream = xDocStream->getInputStream(); + OSL_ENSURE( aParserInput.aInputStream.is(), + "The stream was successfully opened for reading, the input part must be accessible!" ); + if ( !aParserInput.aInputStream.is() ) + throw uno::RuntimeException(); + + // get filter + rtl::Reference< XMLVersionListImport > xImport = new XMLVersionListImport( xContext, aVersions ); + + // parse + try + { + xImport->parseStream( aParserInput ); + } + catch( SAXParseException& ) {} + catch( SAXException& ) {} + catch( io::IOException& ) {} + } + } + catch( uno::Exception& ) + { + // TODO: error handling + } + + return aVersions; +} + +OUString XMLVersionListPersistence::getImplementationName() +{ + return "XMLVersionListPersistence"; +} + +sal_Bool XMLVersionListPersistence::supportsService( + OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence +XMLVersionListPersistence::getSupportedServiceNames() +{ + return css::uno::Sequence{ + "com.sun.star.document.DocumentRevisionListPersistence"}; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +XMLVersionListPersistence_get_implementation( + css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new XMLVersionListPersistence); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/script/XMLEventExport.cxx b/xmloff/source/script/XMLEventExport.cxx new file mode 100644 index 000000000..5aed1c76c --- /dev/null +++ b/xmloff/source/script/XMLEventExport.cxx @@ -0,0 +1,320 @@ +/* -*- 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 + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; + +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::document::XEventsSupplier; +using ::com::sun::star::container::XNameReplace; +using ::com::sun::star::container::XNameAccess; +using ::xmloff::token::XML_EVENT_LISTENERS; + +constexpr OUStringLiteral gsEventType(u"EventType"); + +XMLEventExport::XMLEventExport(SvXMLExport& rExp) : + rExport(rExp), + bExtNamespace(false) +{ +} + +XMLEventExport::~XMLEventExport() +{ + // delete all handlers + aHandlerMap.clear(); +} + +void XMLEventExport::AddHandler( const OUString& rName, + std::unique_ptr pHandler ) +{ + assert(pHandler); + aHandlerMap[rName] = std::move(pHandler); +} + +void XMLEventExport::AddTranslationTable( + const XMLEventNameTranslation* pTransTable ) +{ + if (nullptr != pTransTable) + { + // put translation table into map + for(const XMLEventNameTranslation* pTrans = pTransTable; + pTrans->sAPIName != nullptr; + pTrans++) + { + aNameTranslationMap[OUString::createFromAscii(pTrans->sAPIName)] = + XMLEventName(pTrans->nPrefix, pTrans->sXMLName); + } + } + // else? ignore! +} + +void XMLEventExport::Export( Reference const & rSupplier, + bool bWhitespace) +{ + if (rSupplier.is()) + { + Export(rSupplier->getEvents(), bWhitespace); + } + // else: no supplier, no export -> ignore! +} + +void XMLEventExport::Export( Reference const & rReplace, + bool bWhitespace) +{ + Reference xAccess(rReplace); + Export(xAccess, bWhitespace); +} + +void XMLEventExport::Export( Reference const & rAccess, + bool bWhitespace) +{ + // early out if we don't actually get any events + if (!rAccess.is()) + { + return; + } + + // have we already processed an element? + bool bStarted = false; + + // iterate over all event types + const Sequence aNames = rAccess->getElementNames(); + for(const auto& rName : aNames) + { + // translate name + NameMap::iterator aIter = aNameTranslationMap.find(rName); + if (aIter != aNameTranslationMap.end()) + { + const XMLEventName& rXmlName = aIter->second; + + // get PropertyValues for this event + Any aAny = rAccess->getByName( rName ); + Sequence aValues; + aAny >>= aValues; + + // now export the current event + ExportEvent( aValues, rXmlName, bWhitespace, bStarted ); + } + else + { + // don't proceed further + SAL_WARN("xmloff", "Unknown event name:" << rName ); + } + } + + // close element (if it was opened before) + if (bStarted) + { + EndElement(bWhitespace); + } +} + +void XMLEventExport::ExportExt( Reference const & rAccess ) +{ + // set bExtNamespace flag to use XML_NAMESPACE_OFFICE_EXT namespace + // for events element (not for child elements) + bExtNamespace = true; + Export(rAccess); + bExtNamespace = false; // reset for future Export calls +} + +/// export a singular event and write container +void XMLEventExport::ExportSingleEvent( + const Sequence& rEventValues, + const OUString& rApiEventName, + bool bUseWhitespace ) +{ + // translate the name + NameMap::iterator aIter = aNameTranslationMap.find(rApiEventName); + if (aIter != aNameTranslationMap.end()) + { + const XMLEventName& rXmlName = aIter->second; + + // export the event ... + bool bStarted = false; + ExportEvent( rEventValues, rXmlName, bUseWhitespace, bStarted ); + + // ... and close the container element (if necessary) + if (bStarted) + { + EndElement(bUseWhitespace); + } + } + else + { + // don't proceed further + SAL_WARN("xmloff", "Unknown event name:" << rApiEventName ); + } +} + + +/// export a single event +void XMLEventExport::ExportEvent( + const Sequence& rEventValues, + const XMLEventName& rXmlEventName, + bool bUseWhitespace, + bool& rExported ) +{ + // search for EventType value and then delegate to EventHandler + const PropertyValue* pValue = std::find_if(rEventValues.begin(), rEventValues.end(), + [](const PropertyValue& rValue) { return gsEventType == rValue.Name; }); + + if (pValue == rEventValues.end()) + return; + + // found! Now find handler and delegate + OUString sType; + pValue->Value >>= sType; + + if (aHandlerMap.count(sType)) + { + if (! rExported) + { + // OK, we have't yet exported the enclosing + // element. So we do that now. + rExported = true; + StartElement(bUseWhitespace); + } + + OUString aEventQName( + rExport.GetNamespaceMap().GetQNameByKey( + rXmlEventName.m_nPrefix, rXmlEventName.m_aName ) ); + + // delegate to proper ExportEventHandler + aHandlerMap[sType]->Export(rExport, aEventQName, + rEventValues, bUseWhitespace); + } + else + { + if ( sType != "None" ) + { + OSL_FAIL("unknown event type returned by API"); + // unknown type -> error (ignore) + } + // else: we ignore None fields + } +} + + +void XMLEventExport::StartElement(bool bWhitespace) +{ + if (bWhitespace) + { + rExport.IgnorableWhitespace(); + } + sal_uInt16 nNamespace = bExtNamespace ? XML_NAMESPACE_OFFICE_EXT + : XML_NAMESPACE_OFFICE; + rExport.StartElement( nNamespace, XML_EVENT_LISTENERS, + bWhitespace); +} + +void XMLEventExport::EndElement(bool bWhitespace) +{ + sal_uInt16 nNamespace = bExtNamespace ? XML_NAMESPACE_OFFICE_EXT + : XML_NAMESPACE_OFFICE; + rExport.EndElement(nNamespace, XML_EVENT_LISTENERS, bWhitespace); + if (bWhitespace) + { + rExport.IgnorableWhitespace(); + } +} + + +// implement aStandardEventTable (defined in xmlevent.hxx) +const XMLEventNameTranslation aStandardEventTable[] = +{ + { "OnSelect", XML_NAMESPACE_DOM, "select" }, // "on-select" + { "OnInsertStart", XML_NAMESPACE_OFFICE, "insert-start" }, // "on-insert-start" + { "OnInsertDone", XML_NAMESPACE_OFFICE, "insert-done" }, // "on-insert-done" + { "OnMailMerge", XML_NAMESPACE_OFFICE, "mail-merge" }, // "on-mail-merge" + { "OnAlphaCharInput", XML_NAMESPACE_OFFICE, "alpha-char-input" }, // "on-alpha-char-input" + { "OnNonAlphaCharInput", XML_NAMESPACE_OFFICE, "non-alpha-char-input" }, // "on-non-alpha-char-input" + { "OnResize", XML_NAMESPACE_DOM, "resize" }, // "on-resize" + { "OnMove", XML_NAMESPACE_OFFICE, "move" }, // "on-move" + { "OnPageCountChange", XML_NAMESPACE_OFFICE, "page-count-change" }, // "on-page-count-change" + { "OnMouseOver", XML_NAMESPACE_DOM, "mouseover" }, // "on-mouse-over" + { "OnClick", XML_NAMESPACE_DOM, "click" }, // "on-click" + { "OnMouseOut", XML_NAMESPACE_DOM, "mouseout" }, // "on-mouse-out" + { "OnLoadError", XML_NAMESPACE_OFFICE, "load-error" }, // "on-load-error" + { "OnLoadCancel", XML_NAMESPACE_OFFICE, "load-cancel" }, // "on-load-cancel" + { "OnLoadDone", XML_NAMESPACE_OFFICE, "load-done" }, // "on-load-done" + { "OnLoad", XML_NAMESPACE_DOM, "load" }, // "on-load" + { "OnUnload", XML_NAMESPACE_DOM, "unload" }, // "on-unload" + { "OnStartApp", XML_NAMESPACE_OFFICE, "start-app" }, // "on-start-app" + { "OnCloseApp", XML_NAMESPACE_OFFICE, "close-app" }, // "on-close-app" + { "OnNew", XML_NAMESPACE_OFFICE, "new" }, // "on-new" + { "OnSave", XML_NAMESPACE_OFFICE, "save" }, // "on-save" + { "OnSaveAs", XML_NAMESPACE_OFFICE, "save-as" }, // "on-save-as" + { "OnFocus", XML_NAMESPACE_DOM, "DOMFocusIn" }, // "on-focus" + { "OnUnfocus", XML_NAMESPACE_DOM, "DOMFocusOut" }, // "on-unfocus" + { "OnPrint", XML_NAMESPACE_OFFICE, "print" }, // "on-print" + { "OnError", XML_NAMESPACE_DOM, "error" }, // "on-error" + { "OnLoadFinished", XML_NAMESPACE_OFFICE, "load-finished" }, // "on-load-finished" + { "OnSaveFinished", XML_NAMESPACE_OFFICE, "save-finished" }, // "on-save-finished" + { "OnModifyChanged", XML_NAMESPACE_OFFICE, "modify-changed" }, // "on-modify-changed" + { "OnPrepareUnload", XML_NAMESPACE_OFFICE, "prepare-unload" }, // "on-prepare-unload" + { "OnNewMail", XML_NAMESPACE_OFFICE, "new-mail" }, // "on-new-mail" + { "OnToggleFullscreen", XML_NAMESPACE_OFFICE, "toggle-fullscreen" }, // "on-toggle-fullscreen" + { "OnSaveDone", XML_NAMESPACE_OFFICE, "save-done" }, // "on-save-done" + { "OnSaveAsDone", XML_NAMESPACE_OFFICE, "save-as-done" }, // "on-save-as-done" + { "OnCopyTo", XML_NAMESPACE_OFFICE, "copy-to" }, + { "OnCopyToDone", XML_NAMESPACE_OFFICE, "copy-to-done" }, + { "OnViewCreated", XML_NAMESPACE_OFFICE, "view-created" }, + { "OnPrepareViewClosing", XML_NAMESPACE_OFFICE, "prepare-view-closing" }, + { "OnViewClosed", XML_NAMESPACE_OFFICE, "view-close" }, + { "OnVisAreaChanged", XML_NAMESPACE_OFFICE, "visarea-changed" }, // "on-visarea-changed" + { "OnCreate", XML_NAMESPACE_OFFICE, "create" }, + { "OnSaveAsFailed", XML_NAMESPACE_OFFICE, "save-as-failed" }, + { "OnSaveFailed", XML_NAMESPACE_OFFICE, "save-failed" }, + { "OnCopyToFailed", XML_NAMESPACE_OFFICE, "copy-to-failed" }, + { "OnTitleChanged", XML_NAMESPACE_OFFICE, "title-changed" }, + { "OnModeChanged", XML_NAMESPACE_OFFICE, "mode-changed" }, + { "OnSaveTo", XML_NAMESPACE_OFFICE, "save-to" }, + { "OnSaveToDone", XML_NAMESPACE_OFFICE, "save-to-done" }, + { "OnSaveToFailed", XML_NAMESPACE_OFFICE, "save-to-failed" }, + { "OnSubComponentOpened", XML_NAMESPACE_OFFICE, "subcomponent-opened" }, + { "OnSubComponentClosed", XML_NAMESPACE_OFFICE, "subcomponent-closed" }, + { "OnStorageChanged", XML_NAMESPACE_OFFICE, "storage-changed" }, + { "OnMailMergeFinished", XML_NAMESPACE_OFFICE, "mail-merge-finished" }, + { "OnFieldMerge", XML_NAMESPACE_OFFICE, "field-merge" }, + { "OnFieldMergeFinished", XML_NAMESPACE_OFFICE, "field-merge-finished" }, + { "OnLayoutFinished", XML_NAMESPACE_OFFICE, "layout-finished" }, + { "OnDoubleClick", XML_NAMESPACE_OFFICE, "dblclick" }, + { "OnRightClick", XML_NAMESPACE_OFFICE, "contextmenu" }, + { "OnChange", XML_NAMESPACE_OFFICE, "content-changed" }, + { "OnCalculate", XML_NAMESPACE_OFFICE, "calculated" }, + + { nullptr, 0, nullptr } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/script/XMLEventImportHelper.cxx b/xmloff/source/script/XMLEventImportHelper.cxx new file mode 100644 index 000000000..aebfd13dc --- /dev/null +++ b/xmloff/source/script/XMLEventImportHelper.cxx @@ -0,0 +1,147 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +XMLEventImportHelper::XMLEventImportHelper() : + pEventNameMap(new NameMap) +{ +} + +XMLEventImportHelper::~XMLEventImportHelper() +{ + // delete factories + aFactoryMap.clear(); + + // delete name map + pEventNameMap.reset(); +} + +void XMLEventImportHelper::RegisterFactory( + const OUString& rLanguage, + std::unique_ptr pFactory ) +{ + assert(pFactory); + aFactoryMap[rLanguage] = std::move(pFactory); +} + +void XMLEventImportHelper::AddTranslationTable( + const XMLEventNameTranslation* pTransTable ) +{ + if (nullptr == pTransTable) + return; + + // put translation table into map + for(const XMLEventNameTranslation* pTrans = pTransTable; + pTrans->sAPIName != nullptr; + pTrans++) + { + XMLEventName aName( pTrans->nPrefix, pTrans->sXMLName ); + + // check for conflicting entries + DBG_ASSERT(pEventNameMap->find(aName) == pEventNameMap->end(), + "conflicting event translations"); + + // assign new translation + (*pEventNameMap)[aName] = + OUString::createFromAscii(pTrans->sAPIName); + } + // else? ignore! +} + +void XMLEventImportHelper::PushTranslationTable() +{ + // save old map and install new one + aEventNameMapVector.push_back(std::move(pEventNameMap)); + pEventNameMap.reset( new NameMap ); +} + +void XMLEventImportHelper::PopTranslationTable() +{ + DBG_ASSERT(!aEventNameMapVector.empty(), + "no translation tables left to pop"); + if ( !aEventNameMapVector.empty() ) + { + // delete current and install old map + pEventNameMap = std::move(aEventNameMapVector.back()); + aEventNameMapVector.pop_back(); + } +} + + +SvXMLImportContext* XMLEventImportHelper::CreateContext( + SvXMLImport& rImport, + const Reference & xAttrList, + XMLEventsImportContext* rEvents, + const OUString& rXmlEventName, + const OUString& rLanguage) +{ + SvXMLImportContext* pContext = nullptr; + + // translate event name from xml to api + OUString sMacroName; + sal_uInt16 nMacroPrefix = + rImport.GetNamespaceMap().GetKeyByAttrValueQName(rXmlEventName, + &sMacroName ); + XMLEventName aEventName( nMacroPrefix, sMacroName ); + NameMap::iterator aNameIter = pEventNameMap->find(aEventName); + if (aNameIter != pEventNameMap->end()) + { + OUString aScriptLanguage; + sal_uInt16 nScriptPrefix = rImport.GetNamespaceMap(). + GetKeyByAttrValueQName(rLanguage, &aScriptLanguage); + if( XML_NAMESPACE_OOO != nScriptPrefix ) + aScriptLanguage = rLanguage ; + + // check for factory + FactoryMap::iterator aFactoryIterator = + aFactoryMap.find(aScriptLanguage); + if (aFactoryIterator != aFactoryMap.end()) + { + // delegate to factory + pContext = aFactoryIterator->second->CreateContext( + rImport, xAttrList, + rEvents, aNameIter->second); + } + } + + // default context (if no context was created above) + if( nullptr == pContext ) + { + pContext = new SvXMLImportContext(rImport); + + rImport.SetError(XMLERROR_FLAG_ERROR | XMLERROR_ILLEGAL_EVENT, + { rXmlEventName, rLanguage }); + + } + + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/script/XMLEventsImportContext.cxx b/xmloff/source/script/XMLEventsImportContext.cxx new file mode 100644 index 000000000..f128cfa62 --- /dev/null +++ b/xmloff/source/script/XMLEventsImportContext.cxx @@ -0,0 +1,179 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::container::XNameReplace; +using ::com::sun::star::document::XEventsSupplier; +using ::com::sun::star::lang::IllegalArgumentException; + + +XMLEventsImportContext::XMLEventsImportContext(SvXMLImport& rImport) : + SvXMLImportContext(rImport) +{ +} + + +XMLEventsImportContext::XMLEventsImportContext( + SvXMLImport& rImport, + const Reference & xEventsSupplier) : + SvXMLImportContext(rImport), + xEvents(xEventsSupplier->getEvents()) +{ +} + + +XMLEventsImportContext::XMLEventsImportContext( + SvXMLImport& rImport, + const Reference & xNameReplace) : + SvXMLImportContext(rImport), + xEvents(xNameReplace) +{ +} + +XMLEventsImportContext::~XMLEventsImportContext() +{ +// // if, for whatever reason, the object gets destroyed prematurely, +// // we need to delete the collected events +} + + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLEventsImportContext::createFastChildContext( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // a) search for script:language and script:event-name attribute + // b) delegate to factory. The factory will: + // 1) translate XML event name into API event name + // 2) get proper event context factory from import + // 3) instantiate context + + // a) search for script:language and script:event-name attribute + OUString sLanguage; + OUString sEventName; + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + OUString sValue = aIter.toString(); + + if (aIter.getToken() == XML_ELEMENT(SCRIPT, XML_EVENT_NAME)) + { + sEventName = sValue; + } + else if (aIter.getToken() == XML_ELEMENT(SCRIPT, XML_LANGUAGE)) + { + sLanguage = sValue; + // else: ignore -> let child context handle this + } + // else: ignore -> let child context handle this + } + + // b) delegate to factory + return GetImport().GetEventImport().CreateContext( + GetImport(), xAttrList, this, sEventName, sLanguage); +} + +void XMLEventsImportContext::SetEvents( + const Reference & xEventsSupplier) +{ + if (xEventsSupplier.is()) + { + SetEvents(xEventsSupplier->getEvents()); + } +} + +void XMLEventsImportContext::SetEvents( + const Reference & xNameRepl) +{ + if (xNameRepl.is()) + { + xEvents = xNameRepl; + + // now iterate over vector and a) insert b) delete all elements + for(const auto& rEvent : aCollectEvents) + { + AddEventValues(rEvent.first, rEvent.second); + } + aCollectEvents.clear(); + } +} + +void XMLEventsImportContext::GetEventSequence( + const OUString& rName, + Sequence & rSequence ) +{ + // search through the vector + // (This shouldn't take a lot of time, since this method should only get + // called if only one (or few) events are being expected) + + auto aIter = std::find_if(aCollectEvents.begin(), aCollectEvents.end(), + [&rName](EventNameValuesPair& rEvent) { return rEvent.first == rName; }); + + // if we're not at the end, set the sequence + if (aIter != aCollectEvents.end()) + { + rSequence = aIter->second; + } +} + +void XMLEventsImportContext::AddEventValues( + const OUString& rEventName, + const Sequence & rValues ) +{ + // if we already have the events, set them; else just collect + if (xEvents.is()) + { + // set event (if name is known) + if (xEvents->hasByName(rEventName)) + { + try + { + xEvents->replaceByName(rEventName, Any(rValues)); + } catch ( const IllegalArgumentException & rException ) + { + Sequence aMsgParams { rEventName }; + + GetImport().SetError(XMLERROR_FLAG_ERROR | + XMLERROR_ILLEGAL_EVENT, + aMsgParams, rException.Message, nullptr); + } + } + } + else + { + EventNameValuesPair aPair(rEventName, rValues); + aCollectEvents.push_back(aPair); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/script/XMLScriptContextFactory.cxx b/xmloff/source/script/XMLScriptContextFactory.cxx new file mode 100644 index 000000000..3ebc45c1c --- /dev/null +++ b/xmloff/source/script/XMLScriptContextFactory.cxx @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::xmloff::token; + +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +constexpr OUStringLiteral gsEventType(u"EventType"); +constexpr OUStringLiteral gsScript(u"Script"); +constexpr OUStringLiteral gsURL(u"Script"); + +XMLScriptContextFactory::XMLScriptContextFactory() {} + +XMLScriptContextFactory::~XMLScriptContextFactory() {} + +SvXMLImportContext* XMLScriptContextFactory::CreateContext( + SvXMLImport& rImport, const Reference& xAttrList, + XMLEventsImportContext* rEvents, const OUString& rApiEventName) +{ + OUString sURLVal; + + for (auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + if (aIter.getToken() == XML_ELEMENT(XLINK, XML_HREF)) + sURLVal = aIter.toString(); + // else: ignore + } + + if (!sURLVal.isEmpty()) + rImport.NotifyMacroEventRead(); + + Sequence aValues{ comphelper::makePropertyValue(gsEventType, OUString(gsScript)), + comphelper::makePropertyValue(gsURL, sURLVal) }; + + // add values for event now + rEvents->AddEventValues(rApiEventName, aValues); + + // return dummy context + return new SvXMLImportContext(rImport); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/script/XMLScriptExportHandler.cxx b/xmloff/source/script/XMLScriptExportHandler.cxx new file mode 100644 index 000000000..6b35a4456 --- /dev/null +++ b/xmloff/source/script/XMLScriptExportHandler.cxx @@ -0,0 +1,75 @@ +/* -*- 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 + +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::PropertyValue; + +constexpr OUStringLiteral gsURL(u"Script"); + +XMLScriptExportHandler::XMLScriptExportHandler() +{ +} + +XMLScriptExportHandler::~XMLScriptExportHandler() +{ +} + +void XMLScriptExportHandler::Export( + SvXMLExport& rExport, + const OUString& rEventQName, + const Sequence & rValues, + bool bUseWhitespace) +{ + + rExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_LANGUAGE, + rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) ); + rExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, rEventQName); + + for(const auto& rValue : rValues) + { + if (gsURL == rValue.Name) + { + OUString sTmp; + rValue.Value >>= sTmp; + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sTmp); + + // #i110911# xlink:type="simple" is required + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + } + // else: disregard + } + + SvXMLElementExport aEventElemt(rExport, XML_NAMESPACE_SCRIPT, + XML_EVENT_LISTENER, + bUseWhitespace, false); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/script/XMLStarBasicContextFactory.cxx b/xmloff/source/script/XMLStarBasicContextFactory.cxx new file mode 100644 index 000000000..bab59a0d7 --- /dev/null +++ b/xmloff/source/script/XMLStarBasicContextFactory.cxx @@ -0,0 +1,101 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::xmloff::token; + +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + + +constexpr OUStringLiteral gsEventType(u"EventType"); +constexpr OUStringLiteral gsLibrary(u"Library"); +constexpr OUStringLiteral gsMacroName(u"MacroName"); +constexpr OUStringLiteral gsStarBasic(u"StarBasic"); + +XMLStarBasicContextFactory::XMLStarBasicContextFactory() +{ +} + +XMLStarBasicContextFactory::~XMLStarBasicContextFactory() +{ +} + +SvXMLImportContext* XMLStarBasicContextFactory::CreateContext( + SvXMLImport& rImport, + const Reference & xAttrList, + XMLEventsImportContext* rEvents, + const OUString& rApiEventName) +{ + OUString sLibraryVal; + OUString sMacroNameVal; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(SCRIPT, XML_MACRO_NAME)) + sMacroNameVal = aIter.toString(); + // else: ignore + } + + const OUString& rApp = GetXMLToken( XML_APPLICATION ); + const OUString& rDoc = GetXMLToken( XML_DOCUMENT ); + if( sMacroNameVal.getLength() > rApp.getLength()+1 && + o3tl::equalsIgnoreAsciiCase(sMacroNameVal.subView(0,rApp.getLength()), rApp ) && + ':' == sMacroNameVal[rApp.getLength()] ) + { + sLibraryVal = "StarOffice"; + sMacroNameVal = sMacroNameVal.copy( rApp.getLength()+1 ); + } + else if( sMacroNameVal.getLength() > rDoc.getLength()+1 && + o3tl::equalsIgnoreAsciiCase(sMacroNameVal.subView(0,rDoc.getLength()), rDoc ) && + ':' == sMacroNameVal[rDoc.getLength()] ) + { + sLibraryVal = rDoc; + sMacroNameVal = sMacroNameVal.copy( rDoc.getLength()+1 ); + } + + if (!sMacroNameVal.isEmpty()) + rImport.NotifyMacroEventRead(); + + Sequence aValues + { + comphelper::makePropertyValue(gsEventType, OUString(gsStarBasic)), + comphelper::makePropertyValue(gsLibrary, sLibraryVal), + comphelper::makePropertyValue(gsMacroName, sMacroNameVal) + }; + + // add values for event now + rEvents->AddEventValues(rApiEventName, aValues); + + // return dummy context + return new SvXMLImportContext(rImport); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/script/XMLStarBasicExportHandler.cxx b/xmloff/source/script/XMLStarBasicExportHandler.cxx new file mode 100644 index 000000000..2170d32fd --- /dev/null +++ b/xmloff/source/script/XMLStarBasicExportHandler.cxx @@ -0,0 +1,95 @@ +/* -*- 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 + +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::PropertyValue; + + +constexpr OUStringLiteral gsStarBasic(u"StarBasic"); +constexpr OUStringLiteral gsLibrary(u"Library"); +constexpr OUStringLiteral gsMacroName(u"MacroName"); +constexpr OUStringLiteral gsStarOffice(u"StarOffice"); +constexpr OUStringLiteral gsApplication(u"application"); + +XMLStarBasicExportHandler::XMLStarBasicExportHandler() +{ +} + +XMLStarBasicExportHandler::~XMLStarBasicExportHandler() +{ +} + +void XMLStarBasicExportHandler::Export( + SvXMLExport& rExport, + const OUString& rEventQName, + const Sequence & rValues, + bool bUseWhitespace) +{ + rExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_LANGUAGE, + rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OOO, gsStarBasic ) ); + rExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, rEventQName); + + OUString sLocation, sName; + for(const auto& rValue : rValues) + { + if (gsLibrary == rValue.Name) + { + OUString sTmp; + rValue.Value >>= sTmp; + sLocation = GetXMLToken( + (sTmp.equalsIgnoreAsciiCase(gsApplication) || + sTmp.equalsIgnoreAsciiCase(gsStarOffice) ) ? XML_APPLICATION + : XML_DOCUMENT ); + } + else if (gsMacroName == rValue.Name) + { + rValue.Value >>= sName; + } + // else: disregard + } + + if( !sLocation.isEmpty() ) + { + OUString sTmp = sLocation + ":" + sName; + rExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, + sTmp); + } + else + { + rExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, sName ); + } + + SvXMLElementExport aEventElemt(rExport, XML_NAMESPACE_SCRIPT, + XML_EVENT_LISTENER, + bUseWhitespace, false); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/script/xmlbasicscript.cxx b/xmloff/source/script/xmlbasicscript.cxx new file mode 100644 index 000000000..f619f71c2 --- /dev/null +++ b/xmloff/source/script/xmlbasicscript.cxx @@ -0,0 +1,316 @@ +/* -*- 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 + +#include "xmlbasicscript.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +namespace xmloff +{ +// BasicElementBase + +BasicElementBase::BasicElementBase(SvXMLImport& rImport) + : SvXMLImportContext(rImport) +{ +} + +bool BasicElementBase::getBoolAttr(bool* pRet, sal_Int32 nToken, + const Reference& xAttributes) +{ + OUString aValue = xAttributes->getOptionalValue(nToken); + if (!aValue.isEmpty()) + { + if (aValue == "true") + { + *pRet = true; + return true; + } + else if (aValue == "false") + { + *pRet = false; + return true; + } + else + { + throw xml::sax::SAXException(SvXMLImport::getNameFromToken(nToken) + + ": no boolean value (true|false)!", + Reference(), Any()); + } + } + return false; +} + +// BasicLibrariesElement + +BasicLibrariesElement::BasicLibrariesElement(SvXMLImport& rImport, + const css::uno::Reference& rxModel) + : BasicElementBase(rImport) +{ + // try the XEmbeddedScripts interface + Reference xDocumentScripts(rxModel, UNO_QUERY_THROW); + m_xLibContainer = xDocumentScripts->getBasicLibraries(); + + if (!m_xLibContainer.is()) + { + // try the "BasicLibraries" property (old-style, for compatibility) + Reference xPSet(rxModel, UNO_QUERY); + if (xPSet.is()) + xPSet->getPropertyValue("BasicLibraries") >>= m_xLibContainer; + } + + SAL_WARN_IF(!m_xLibContainer.is(), "xmlscript.xmlflat", + "BasicImport::startRootElement: nowhere to import to!"); + + if (!m_xLibContainer.is()) + { + throw xml::sax::SAXException("nowhere to import to", Reference(), Any()); + } +} + +// XElement + +Reference +BasicLibrariesElement::createFastChildContext(sal_Int32 nElement, + const Reference& xAttributes) +{ + if (!IsTokenInNamespace(nElement, XML_NAMESPACE_OOO)) + { + throw xml::sax::SAXException("illegal namespace!", Reference(), Any()); + } + else if ((nElement & TOKEN_MASK) == XML_LIBRARY_LINKED) + { + OUString aName = xAttributes->getValue(NAMESPACE_TOKEN(XML_NAMESPACE_OOO) | XML_NAME); + + OUString aStorageURL = xAttributes->getValue(XML_ELEMENT(XLINK, XML_HREF)); + + bool bReadOnly = false; + getBoolAttr(&bReadOnly, NAMESPACE_TOKEN(XML_NAMESPACE_OOO) | XML_READONLY, xAttributes); + + if (m_xLibContainer.is()) + { + try + { + Reference xLib( + m_xLibContainer->createLibraryLink(aName, aStorageURL, bReadOnly)); + if (xLib.is()) + return new BasicElementBase(GetImport()); + } + catch (const container::ElementExistException&) + { + TOOLS_INFO_EXCEPTION("xmlscript.xmlflat", + "BasicLibrariesElement::startChildElement"); + } + catch (const lang::IllegalArgumentException&) + { + TOOLS_INFO_EXCEPTION("xmlscript.xmlflat", + "BasicLibrariesElement::startChildElement"); + } + } + } + else if ((nElement & TOKEN_MASK) == XML_LIBRARY_EMBEDDED) + { + // TODO: create password protected libraries + + OUString aName = xAttributes->getValue(NAMESPACE_TOKEN(XML_NAMESPACE_OOO) | XML_NAME); + + bool bReadOnly = false; + getBoolAttr(&bReadOnly, NAMESPACE_TOKEN(XML_NAMESPACE_OOO) | XML_READONLY, xAttributes); + + if (m_xLibContainer.is()) + { + try + { + Reference xLib; + if (m_xLibContainer->hasByName(aName)) + { + // Standard library + m_xLibContainer->getByName(aName) >>= xLib; + } + else + { + xLib.set(m_xLibContainer->createLibrary(aName)); + } + + if (xLib.is()) + return new BasicEmbeddedLibraryElement(GetImport(), m_xLibContainer, aName, + bReadOnly); + } + catch (const lang::IllegalArgumentException&) + { + TOOLS_INFO_EXCEPTION("xmlscript.xmlflat", + "BasicLibrariesElement::startChildElement"); + } + } + } + else + { + throw xml::sax::SAXException("expected library-linked or library-embedded element!", + Reference(), Any()); + } + + return nullptr; +} + +// BasicEmbeddedLibraryElement + +BasicEmbeddedLibraryElement::BasicEmbeddedLibraryElement( + SvXMLImport& rImport, const Reference& rxLibContainer, + const OUString& rLibName, bool bReadOnly) + : BasicElementBase(rImport) + , m_xLibContainer(rxLibContainer) + , m_aLibName(rLibName) + , m_bReadOnly(bReadOnly) +{ + try + { + if (m_xLibContainer.is() && m_xLibContainer->hasByName(m_aLibName)) + m_xLibContainer->getByName(m_aLibName) >>= m_xLib; + } + catch (const lang::WrappedTargetException&) + { + TOOLS_INFO_EXCEPTION("xmlscript.xmlflat", "BasicEmbeddedLibraryElement::CTOR:"); + } +} + +Reference BasicEmbeddedLibraryElement::createFastChildContext( + sal_Int32 nElement, const Reference& xAttributes) +{ + if (!IsTokenInNamespace(nElement, XML_NAMESPACE_OOO)) + { + throw xml::sax::SAXException("illegal namespace!", Reference(), Any()); + } + else if ((nElement & TOKEN_MASK) == XML_MODULE) + { + OUString aName = xAttributes->getValue(NAMESPACE_TOKEN(XML_NAMESPACE_OOO) | XML_NAME); + + if (m_xLib.is() && !aName.isEmpty()) + return new BasicModuleElement(GetImport(), m_xLib, aName); + } + else + { + throw xml::sax::SAXException("expected module element!", Reference(), Any()); + } + + return nullptr; +} + +void BasicEmbeddedLibraryElement::endFastElement(sal_Int32) +{ + if (m_xLibContainer.is() && m_xLibContainer->hasByName(m_aLibName) && m_bReadOnly) + m_xLibContainer->setLibraryReadOnly(m_aLibName, m_bReadOnly); +} + +// BasicModuleElement + +BasicModuleElement::BasicModuleElement(SvXMLImport& rImport, + const Reference& rxLib, + const OUString& rName) + : BasicElementBase(rImport) + , m_xLib(rxLib) + , m_aName(rName) +{ +} + +Reference +BasicModuleElement::createFastChildContext(sal_Int32 nElement, + const Reference& xAttributes) +{ + // TODO: + + if (!IsTokenInNamespace(nElement, XML_NAMESPACE_OOO)) + { + throw xml::sax::SAXException("illegal namespace!", Reference(), Any()); + } + else if ((nElement & TOKEN_MASK) == XML_SOURCE_CODE) + { + // TODO: password protected libraries + + if (xAttributes.is()) + { + if (m_xLib.is() && !m_aName.isEmpty()) + return new BasicSourceCodeElement(GetImport(), m_xLib, m_aName); + } + } + else + { + throw xml::sax::SAXException("expected source-code element!", Reference(), + Any()); + } + + return nullptr; +} + +// BasicSourceCodeElement + +BasicSourceCodeElement::BasicSourceCodeElement(SvXMLImport& rImport, + const Reference& rxLib, + const OUString& rName) + : BasicElementBase(rImport) + , m_xLib(rxLib) + , m_aName(rName) +{ +} + +// XElement + +void BasicSourceCodeElement::characters(const OUString& rChars) { m_aBuffer.append(rChars); } + +void BasicSourceCodeElement::endFastElement(sal_Int32) +{ + try + { + if (m_xLib.is() && !m_aName.isEmpty()) + { + Any aElement; + aElement <<= m_aBuffer.makeStringAndClear(); + m_xLib->insertByName(m_aName, aElement); + } + } + catch (const container::ElementExistException&) + { + TOOLS_INFO_EXCEPTION("xmlscript.xmlflat", "BasicSourceCodeElement::endElement"); + } + catch (const lang::IllegalArgumentException&) + { + TOOLS_INFO_EXCEPTION("xmlscript.xmlflat", "BasicSourceCodeElement::endElement"); + } + catch (const lang::WrappedTargetException&) + { + TOOLS_INFO_EXCEPTION("xmlscript.xmlflat", "BasicSourceCodeElement::endElement"); + } +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/script/xmlbasicscript.hxx b/xmloff/source/script/xmlbasicscript.hxx new file mode 100644 index 000000000..1d94f344b --- /dev/null +++ b/xmloff/source/script/xmlbasicscript.hxx @@ -0,0 +1,111 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +namespace xmloff +{ +class BasicElementBase : public SvXMLImportContext +{ +protected: + static bool + getBoolAttr(bool* pRet, sal_Int32 nToken, + const css::uno::Reference& xAttributes); + +public: + BasicElementBase(SvXMLImport& rImport); +}; + +class BasicLibrariesElement : public BasicElementBase +{ +private: + css::uno::Reference m_xLibContainer; + +public: + BasicLibrariesElement(SvXMLImport& rImport, + const css::uno::Reference& rxModel); + + virtual css::uno::Reference SAL_CALL createFastChildContext( + sal_Int32 Element, + const css::uno::Reference& Attribs) override; +}; + +class BasicEmbeddedLibraryElement : public BasicElementBase +{ +private: + css::uno::Reference m_xLibContainer; + css::uno::Reference m_xLib; + OUString const m_aLibName; + bool const m_bReadOnly; + +public: + BasicEmbeddedLibraryElement( + SvXMLImport& rImport, + const css::uno::Reference& rxLibContainer, + const OUString& rLibName, bool bReadOnly); + + virtual css::uno::Reference SAL_CALL createFastChildContext( + sal_Int32 Element, + const css::uno::Reference& Attribs) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class BasicModuleElement : public BasicElementBase +{ +private: + css::uno::Reference m_xLib; + OUString const m_aName; + +public: + BasicModuleElement(SvXMLImport& rImport, + const css::uno::Reference& rxLib, + const OUString& rName); + + virtual css::uno::Reference SAL_CALL createFastChildContext( + sal_Int32 Element, + const css::uno::Reference& Attribs) override; +}; + +class BasicSourceCodeElement : public BasicElementBase +{ +private: + css::uno::Reference m_xLib; + OUString const m_aName; + OUStringBuffer m_aBuffer; + +public: + BasicSourceCodeElement(SvXMLImport& rImport, + const css::uno::Reference& rxLib, + const OUString& rName); + + virtual void SAL_CALL characters(const OUString& rChars) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +} // namespace xmloff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ \ No newline at end of file diff --git a/xmloff/source/script/xmlscripti.cxx b/xmloff/source/script/xmlscripti.cxx new file mode 100644 index 000000000..73051469b --- /dev/null +++ b/xmloff/source/script/xmlscripti.cxx @@ -0,0 +1,129 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include "xmlbasicscript.hxx" + +#include +#include + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::frame; +using namespace com::sun::star::document; +using namespace com::sun::star::xml::sax; +using namespace ::xmloff::token; + +// XMLScriptChildContext: context for element + +namespace { + +class XMLScriptChildContext : public SvXMLImportContext +{ +private: + css::uno::Reference< css::frame::XModel > m_xModel; + css::uno::Reference< css::document::XEmbeddedScripts > m_xDocumentScripts; + OUString m_aLanguage; + +public: + XMLScriptChildContext( SvXMLImport& rImport, + const css::uno::Reference< css::frame::XModel>& rxModel, + const OUString& rLanguage ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +} + +XMLScriptChildContext::XMLScriptChildContext( SvXMLImport& rImport, + const Reference< frame::XModel >& rxModel, const OUString& rLanguage ) + :SvXMLImportContext( rImport ) + ,m_xModel( rxModel ) + ,m_xDocumentScripts( rxModel, UNO_QUERY ) + ,m_aLanguage( rLanguage ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLScriptChildContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + if ( m_xDocumentScripts.is() ) + { // document supports embedding scripts/macros + OUString aBasic( GetImport().GetNamespaceMap().GetPrefixByKey( XML_NAMESPACE_OOO ) + ":Basic" ); + + if ( m_aLanguage == aBasic && nElement == XML_ELEMENT(OOO, XML_LIBRARIES) ) + { + return new xmloff::BasicLibrariesElement( GetImport(), m_xModel ); + } + } + + return nullptr; +} + +// XMLScriptContext: context for element + +XMLScriptContext::XMLScriptContext( SvXMLImport& rImport, + const Reference& rDocModel ) + :SvXMLImportContext( rImport ) + ,m_xModel( rDocModel ) +{ +} + +XMLScriptContext::~XMLScriptContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLScriptContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(OFFICE, XML_SCRIPT) ) + { + if ( m_xModel.is() ) + { + OUString aLanguage = xAttrList->getValue( XML_ELEMENT(SCRIPT, XML_LANGUAGE) ); + + uno::Sequence< beans::PropertyValue > aMedDescr = m_xModel->getArgs(); + sal_Int32 nNewLen = aMedDescr.getLength() + 1; + aMedDescr.realloc( nNewLen ); + auto pMedDescr = aMedDescr.getArray(); + pMedDescr[nNewLen-1].Name = "BreakMacroSignature"; + pMedDescr[nNewLen-1].Value <<= true; + m_xModel->attachResource( m_xModel->getURL(), aMedDescr ); + + return new XMLScriptChildContext( GetImport(), m_xModel, aLanguage ); + } + } + else if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + Reference< XEventsSupplier> xSupplier( GetImport().GetModel(), UNO_QUERY ); + return new XMLEventsImportContext( GetImport(), xSupplier ); + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/AttributeContainerHandler.cxx b/xmloff/source/style/AttributeContainerHandler.cxx new file mode 100644 index 000000000..17dc4391e --- /dev/null +++ b/xmloff/source/style/AttributeContainerHandler.cxx @@ -0,0 +1,86 @@ +/* -*- 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 +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; + + + + +XMLAttributeContainerHandler::~XMLAttributeContainerHandler() +{ + // nothing to do +} + +bool XMLAttributeContainerHandler::equals( + const Any& r1, + const Any& r2 ) const +{ + Reference< XNameContainer > xContainer1; + Reference< XNameContainer > xContainer2; + + if( ( r1 >>= xContainer1 ) && ( r2 >>= xContainer2 ) ) + { + const uno::Sequence< OUString > aAttribNames1( xContainer1->getElementNames() ); + uno::Sequence< OUString > aAttribNames2( xContainer2->getElementNames() ); + + if( aAttribNames1.getLength() == aAttribNames2.getLength() ) + { + xml::AttributeData aData1; + xml::AttributeData aData2; + + for( const OUString& rAttribName : aAttribNames1 ) + { + if( !xContainer2->hasByName( rAttribName ) ) + return false; + + xContainer1->getByName( rAttribName ) >>= aData1; + xContainer2->getByName( rAttribName ) >>= aData2; + + if( ( aData1.Namespace != aData2.Namespace ) || + ( aData1.Type != aData2.Type ) || + ( aData1.Value != aData2.Value ) ) + return false; + } + + return true; + } + } + + return false; +} + +bool XMLAttributeContainerHandler::importXML( const OUString& /*rStrImpValue*/, Any& /*rValue*/, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + return true; +} + +bool XMLAttributeContainerHandler::exportXML( OUString& /*rStrExpValue*/, const Any& /*rValue*/, const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/DashStyle.cxx b/xmloff/source/style/DashStyle.cxx new file mode 100644 index 000000000..acb866df8 --- /dev/null +++ b/xmloff/source/style/DashStyle.cxx @@ -0,0 +1,275 @@ +/* -*- 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 +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_DashStyle_Enum[] = +{ + { XML_RECT, drawing::DashStyle_RECT }, + { XML_ROUND, drawing::DashStyle_ROUND }, + { XML_RECT, drawing::DashStyle_RECTRELATIVE }, + { XML_ROUND, drawing::DashStyle_ROUNDRELATIVE }, + { XML_TOKEN_INVALID, drawing::DashStyle(0) } +}; + +// Import + +XMLDashStyleImport::XMLDashStyleImport( SvXMLImport& rImp ) + : rImport(rImp) +{ +} + +void XMLDashStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + drawing::LineDash aLineDash; + aLineDash.Style = drawing::DashStyle_RECT; + aLineDash.Dots = 0; + aLineDash.DotLen = 0; + aLineDash.Dashes = 0; + aLineDash.DashLen = 0; + aLineDash.Distance = 20; + OUString aDisplayName; + + bool bIsRel = false; + + SvXMLUnitConverter& rUnitConverter = rImport.GetMM100UnitConverter(); + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + case XML_ELEMENT(DRAW_OOO, XML_NAME): + { + rStrName = aIter.toString(); + } + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + case XML_ELEMENT(DRAW_OOO, XML_DISPLAY_NAME): + { + aDisplayName = aIter.toString(); + } + break; + case XML_ELEMENT(DRAW, XML_STYLE): + case XML_ELEMENT(DRAW_OOO, XML_STYLE): + { + SvXMLUnitConverter::convertEnum( aLineDash.Style, aIter.toView(), pXML_DashStyle_Enum ); + } + break; + case XML_ELEMENT(DRAW, XML_DOTS1): + case XML_ELEMENT(DRAW_OOO, XML_DOTS1): + aLineDash.Dots = static_cast(aIter.toInt32()); + break; + + case XML_ELEMENT(DRAW, XML_DOTS1_LENGTH): + case XML_ELEMENT(DRAW_OOO, XML_DOTS1_LENGTH): + { + if( aIter.toView().find( '%' ) != std::string_view::npos ) // it's a percentage + { + bIsRel = true; + ::sax::Converter::convertPercent(aLineDash.DotLen, aIter.toView()); + } + else + { + rUnitConverter.convertMeasureToCore( aLineDash.DotLen, + aIter.toView() ); + } + } + break; + + case XML_ELEMENT(DRAW, XML_DOTS2): + case XML_ELEMENT(DRAW_OOO, XML_DOTS2): + aLineDash.Dashes = static_cast(aIter.toInt32()); + break; + + case XML_ELEMENT(DRAW, XML_DOTS2_LENGTH): + case XML_ELEMENT(DRAW_OOO, XML_DOTS2_LENGTH): + { + if( aIter.toView().find( '%' ) != std::string_view::npos ) // it's a percentage + { + bIsRel = true; + ::sax::Converter::convertPercent(aLineDash.DashLen, aIter.toView()); + } + else + { + rUnitConverter.convertMeasureToCore( aLineDash.DashLen, + aIter.toView() ); + } + } + break; + + case XML_ELEMENT(DRAW, XML_DISTANCE): + case XML_ELEMENT(DRAW_OOO, XML_DISTANCE): + { + if( aIter.toView().find( '%' ) != std::string_view::npos ) // it's a percentage + { + bIsRel = true; + ::sax::Converter::convertPercent(aLineDash.Distance, aIter.toView()); + } + else + { + rUnitConverter.convertMeasureToCore( aLineDash.Distance, + aIter.toView() ); + } + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + if( bIsRel ) + aLineDash.Style = aLineDash.Style == drawing::DashStyle_RECT ? drawing::DashStyle_RECTRELATIVE : drawing::DashStyle_ROUNDRELATIVE; + + rValue <<= aLineDash; + + if( !aDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::SD_STROKE_DASH_ID, + rStrName, aDisplayName ); + rStrName = aDisplayName; + } +} + +// Export + +XMLDashStyleExport::XMLDashStyleExport( SvXMLExport& rExp ) + : rExport(rExp) +{ +} + +void XMLDashStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + SvXMLUnitConverter & rUnitConverter = rExport.GetMM100UnitConverter(); + + drawing::LineDash aLineDash; + + if( rStrName.isEmpty() ) + return; + + if( !(rValue >>= aLineDash) ) + return; + + bool bIsRel = aLineDash.Style == drawing::DashStyle_RECTRELATIVE || aLineDash.Style == drawing::DashStyle_ROUNDRELATIVE; + + OUString aStrValue; + OUStringBuffer aOut; + + // Name + bool bEncoded = false; + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + rExport.EncodeStyleName( rStrName, + &bEncoded ) ); + if( bEncoded ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + rStrName ); + + // Style + SvXMLUnitConverter::convertEnum( aOut, aLineDash.Style, pXML_DashStyle_Enum ); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + + // dots + if( aLineDash.Dots ) + { + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DOTS1, OUString::number( aLineDash.Dots ) ); + + if( aLineDash.DotLen ) + { + // dashes length + if( bIsRel ) + { + ::sax::Converter::convertPercent(aOut, aLineDash.DotLen); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, + aLineDash.DotLen ); + } + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DOTS1_LENGTH, aStrValue ); + } + } + + // dashes + if( aLineDash.Dashes ) + { + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DOTS2, OUString::number( aLineDash.Dashes ) ); + + if( aLineDash.DashLen ) + { + // dashes length + if( bIsRel ) + { + ::sax::Converter::convertPercent(aOut, aLineDash.DashLen); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, + aLineDash.DashLen ); + } + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DOTS2_LENGTH, aStrValue ); + } + } + + // distance + if( bIsRel ) + { + ::sax::Converter::convertPercent( aOut, aLineDash.Distance ); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, + aLineDash.Distance ); + } + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISTANCE, aStrValue ); + + // do Write + SvXMLElementExport rElem( rExport, + XML_NAMESPACE_DRAW, XML_STROKE_DASH, + true, false ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/DrawAspectHdl.cxx b/xmloff/source/style/DrawAspectHdl.cxx new file mode 100644 index 000000000..7eeb374ca --- /dev/null +++ b/xmloff/source/style/DrawAspectHdl.cxx @@ -0,0 +1,61 @@ +/* -*- 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 "DrawAspectHdl.hxx" + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +DrawAspectHdl::~DrawAspectHdl() +{ + // nothing to do +} + +bool DrawAspectHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int64 nAspect = 0; + + ::sax::Converter::convertNumber64( nAspect, rStrImpValue ); + rValue <<= nAspect; + + return nAspect > 0; +} + +bool DrawAspectHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + sal_Int64 nAspect = 0; + if( ( rValue >>= nAspect ) && nAspect > 0 ) + { + // store the aspect as an integer value + rStrExpValue = OUString::number(nAspect); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/DrawAspectHdl.hxx b/xmloff/source/style/DrawAspectHdl.hxx new file mode 100644 index 000000000..0eb1fae15 --- /dev/null +++ b/xmloff/source/style/DrawAspectHdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class DrawAspectHdl : public XMLPropertyHandler +{ +public: + virtual ~DrawAspectHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/EnumPropertyHdl.cxx b/xmloff/source/style/EnumPropertyHdl.cxx new file mode 100644 index 000000000..903ac3914 --- /dev/null +++ b/xmloff/source/style/EnumPropertyHdl.cxx @@ -0,0 +1,82 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +using namespace ::com::sun::star::uno; + + + +XMLEnumPropertyHdl::~XMLEnumPropertyHdl() +{ + // Nothing to do +} + +bool XMLEnumPropertyHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nValue = 0; + + if( SvXMLUnitConverter::convertEnum( nValue, rStrImpValue, mpEnumMap ) ) + { + switch( mrType.getTypeClass() ) + { + case TypeClass_ENUM: + rValue = ::cppu::int2enum( nValue, mrType ); + break; + case TypeClass_LONG: + rValue <<= static_cast(nValue); + break; + case TypeClass_SHORT: + rValue <<= static_cast(nValue); + break; + case TypeClass_BYTE: + rValue <<= static_cast(nValue); + break; + default: + assert(!"Wrong type for enum property handler!"); + return false; + } + return true; + } + + return false; +} + +bool XMLEnumPropertyHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + if(!(rValue >>= nValue )) + if(!::cppu::enum2int(nValue, rValue) ) + return false; + + OUStringBuffer aOut; + + if(!SvXMLUnitConverter::convertEnum( aOut, static_cast(nValue), mpEnumMap )) + return false; + + rStrExpValue = aOut.makeStringAndClear(); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/FillStyleContext.cxx b/xmloff/source/style/FillStyleContext.cxx new file mode 100644 index 000000000..8cd99a25b --- /dev/null +++ b/xmloff/source/style/FillStyleContext.cxx @@ -0,0 +1,317 @@ +/* -*- 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 +#include +#include +#include "FillStyleContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + + +XMLGradientStyleContext::XMLGradientStyleContext( SvXMLImport& rImport, sal_Int32 , + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLGradientStyleImport aGradientStyle( GetImport() ); + aGradientStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLGradientStyleContext::~XMLGradientStyleContext() +{ +} + +void XMLGradientStyleContext::endFastElement(sal_Int32 ) +{ + uno::Reference< container::XNameContainer > xGradient( GetImport().GetGradientHelper() ); + + try + { + if(xGradient.is()) + { + if( xGradient->hasByName( maStrName ) ) + { + xGradient->replaceByName( maStrName, maAny ); + } + else + { + xGradient->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLGradientStyleContext::IsTransient() const +{ + return true; +} + + +XMLHatchStyleContext::XMLHatchStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLHatchStyleImport aHatchStyle( GetImport() ); + aHatchStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLHatchStyleContext::~XMLHatchStyleContext() +{ +} + +void XMLHatchStyleContext::endFastElement(sal_Int32 ) +{ + uno::Reference< container::XNameContainer > xHatch( GetImport().GetHatchHelper() ); + + try + { + if(xHatch.is()) + { + if( xHatch->hasByName( maStrName ) ) + { + xHatch->replaceByName( maStrName, maAny ); + } + else + { + xHatch->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLHatchStyleContext::IsTransient() const +{ + return true; +} + + +XMLBitmapStyleContext::XMLBitmapStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLImageStyle::importXML( xAttrList, maAny, maStrName, rImport ); +} + +XMLBitmapStyleContext::~XMLBitmapStyleContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLBitmapStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if( nElement == XML_ELEMENT(OFFICE, xmloff::token::XML_BINARY_DATA) ) + { + OUString sURL; + maAny >>= sURL; + if( sURL.isEmpty() && !mxBase64Stream.is() ) + { + mxBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( mxBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), mxBase64Stream ); + } + } + + return nullptr; +} + +void XMLBitmapStyleContext::endFastElement(sal_Int32 ) +{ + if (!maAny.has>() && mxBase64Stream.is()) + { + // No graphic so far? Then see if it's inline. + uno::Reference xGraphic = GetImport().loadGraphicFromBase64(mxBase64Stream); + if (xGraphic.is()) + { + maAny <<= xGraphic; + } + } + + if (!maAny.has>()) + return; + + uno::Reference xBitmapContainer(GetImport().GetBitmapHelper()); + + uno::Reference xGraphic = maAny.get>(); + uno::Reference xBitmap(xGraphic, uno::UNO_QUERY); + + try + { + if (xBitmapContainer.is()) + { + if (xBitmapContainer->hasByName(maStrName)) + { + xBitmapContainer->replaceByName(maStrName, uno::Any(xBitmap)); + } + else + { + xBitmapContainer->insertByName(maStrName, uno::Any(xBitmap)); + } + } + } + catch (container::ElementExistException&) + {} +} + +bool XMLBitmapStyleContext::IsTransient() const +{ + return true; +} + + +XMLTransGradientStyleContext::XMLTransGradientStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLTransGradientStyleImport aTransGradientStyle( GetImport() ); + aTransGradientStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLTransGradientStyleContext::~XMLTransGradientStyleContext() +{ +} + +void XMLTransGradientStyleContext::endFastElement(sal_Int32 ) +{ + uno::Reference< container::XNameContainer > xTransGradient( GetImport().GetTransGradientHelper() ); + + try + { + if(xTransGradient.is()) + { + if( xTransGradient->hasByName( maStrName ) ) + { + xTransGradient->replaceByName( maStrName, maAny ); + } + else + { + xTransGradient->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLTransGradientStyleContext::IsTransient() const +{ + return true; +} + + +XMLMarkerStyleContext::XMLMarkerStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLMarkerStyleImport aMarkerStyle( GetImport() ); + aMarkerStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLMarkerStyleContext::~XMLMarkerStyleContext() +{ +} + +void XMLMarkerStyleContext::endFastElement(sal_Int32 ) +{ + uno::Reference< container::XNameContainer > xMarker( GetImport().GetMarkerHelper() ); + + try + { + if(xMarker.is()) + { + if( xMarker->hasByName( maStrName ) ) + { + xMarker->replaceByName( maStrName, maAny ); + } + else + { + xMarker->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLMarkerStyleContext::IsTransient() const +{ + return true; +} + + +XMLDashStyleContext::XMLDashStyleContext( SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList) +: SvXMLStyleContext(rImport) +{ + // start import + XMLDashStyleImport aDashStyle( GetImport() ); + aDashStyle.importXML( xAttrList, maAny, maStrName ); +} + +XMLDashStyleContext::~XMLDashStyleContext() +{ +} + +void XMLDashStyleContext::endFastElement(sal_Int32 ) +{ + uno::Reference< container::XNameContainer > xDashes( GetImport().GetDashHelper() ); + + try + { + if(xDashes.is()) + { + if( xDashes->hasByName( maStrName ) ) + { + xDashes->replaceByName( maStrName, maAny ); + } + else + { + xDashes->insertByName( maStrName, maAny ); + } + } + } + catch( container::ElementExistException& ) + {} +} + +bool XMLDashStyleContext::IsTransient() const +{ + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/FillStyleContext.hxx b/xmloff/source/style/FillStyleContext.hxx new file mode 100644 index 000000000..3b17c29c8 --- /dev/null +++ b/xmloff/source/style/FillStyleContext.hxx @@ -0,0 +1,144 @@ +/* -*- 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 +#include +#include + +// draw:gradient context + +class XMLGradientStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + +public: + + XMLGradientStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLGradientStyleContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +// draw:hatch context + +class XMLHatchStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + +public: + + XMLHatchStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLHatchStyleContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +// draw:fill-image context + +class XMLBitmapStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + css::uno::Reference < css::io::XOutputStream > mxBase64Stream; + +public: + + XMLBitmapStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLBitmapStyleContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +// draw:transparency context + +class XMLTransGradientStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + +public: + + XMLTransGradientStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLTransGradientStyleContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +// draw:marker context + +class XMLMarkerStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + +public: + + XMLMarkerStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLMarkerStyleContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +// draw:marker context + +class XMLDashStyleContext: public SvXMLStyleContext +{ +private: + css::uno::Any maAny; + OUString maStrName; + +public: + + XMLDashStyleContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual ~XMLDashStyleContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual bool IsTransient() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/GradientStyle.cxx b/xmloff/source/style/GradientStyle.cxx new file mode 100644 index 000000000..81ccd84d2 --- /dev/null +++ b/xmloff/source/style/GradientStyle.cxx @@ -0,0 +1,238 @@ +/* -*- 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 + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_GradientStyle_Enum[] = +{ + { XML_LINEAR, awt::GradientStyle_LINEAR }, + { XML_GRADIENTSTYLE_AXIAL, awt::GradientStyle_AXIAL }, + { XML_GRADIENTSTYLE_RADIAL, awt::GradientStyle_RADIAL }, + { XML_GRADIENTSTYLE_ELLIPSOID, awt::GradientStyle_ELLIPTICAL }, + { XML_GRADIENTSTYLE_SQUARE, awt::GradientStyle_SQUARE }, + { XML_GRADIENTSTYLE_RECTANGULAR, awt::GradientStyle_RECT }, + { XML_TOKEN_INVALID, awt::GradientStyle(0) } +}; + +// Import +XMLGradientStyleImport::XMLGradientStyleImport( + SvXMLImport& rImp ) + : rImport(rImp) +{ +} + +void XMLGradientStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + OUString aDisplayName; + + awt::Gradient aGradient; + aGradient.Style = css::awt::GradientStyle_LINEAR; + aGradient.StartColor = 0; + aGradient.EndColor = 0; + aGradient.Angle = 0; + aGradient.Border = 0; + aGradient.XOffset = 0; + aGradient.YOffset = 0; + aGradient.StartIntensity = 100; + aGradient.EndIntensity = 100; + aGradient.StepCount = 0; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + sal_Int32 nTmpValue(0); + + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + rStrName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + aDisplayName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_STYLE): + SvXMLUnitConverter::convertEnum( aGradient.Style, aIter.toView(), pXML_GradientStyle_Enum ); + break; + case XML_ELEMENT(DRAW, XML_CX): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.XOffset = static_cast< sal_Int16 >( nTmpValue ); + break; + case XML_ELEMENT(DRAW, XML_CY): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.YOffset = static_cast< sal_Int16 >( nTmpValue ); + break; + case XML_ELEMENT(DRAW, XML_START_COLOR): + ::sax::Converter::convertColor(aGradient.StartColor, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_END_COLOR): + ::sax::Converter::convertColor(aGradient.EndColor, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_START_INTENSITY): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.StartIntensity = static_cast< sal_Int16 >( nTmpValue ); + break; + case XML_ELEMENT(DRAW, XML_END_INTENSITY): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.EndIntensity = static_cast< sal_Int16 >( nTmpValue ); + break; + case XML_ELEMENT(DRAW, XML_GRADIENT_ANGLE): + { + auto const cmp12(rImport.GetODFVersion().compareTo(ODFVER_012_TEXT)); + bool const bSuccess = + ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(), + // tdf#89475 try to detect borked OOo angles + (cmp12 < 0) || (cmp12 == 0 + && (rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); + SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle"); + } + break; + case XML_ELEMENT(DRAW, XML_BORDER): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.Border = static_cast< sal_Int16 >( nTmpValue ); + break; + + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + rValue <<= aGradient; + + if( !aDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::SD_GRADIENT_ID, rStrName, + aDisplayName ); + rStrName = aDisplayName; + } +} + +// Export + +XMLGradientStyleExport::XMLGradientStyleExport( + SvXMLExport& rExp ) + : rExport(rExp) +{ +} + +void XMLGradientStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + awt::Gradient aGradient; + + if( rStrName.isEmpty() ) + return; + + if( !(rValue >>= aGradient) ) + return; + + OUString aStrValue; + OUStringBuffer aOut; + + // Style + if( !SvXMLUnitConverter::convertEnum( aOut, aGradient.Style, pXML_GradientStyle_Enum ) ) + return; + + // Name + bool bEncoded = false; + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + rExport.EncodeStyleName( rStrName, + &bEncoded ) ); + if( bEncoded ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + rStrName ); + + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + + // Center x/y + if( aGradient.Style != awt::GradientStyle_LINEAR && + aGradient.Style != awt::GradientStyle_AXIAL ) + { + ::sax::Converter::convertPercent(aOut, aGradient.XOffset); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue ); + ::sax::Converter::convertPercent(aOut, aGradient.YOffset); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue ); + } + + // Color start + ::sax::Converter::convertColor(aOut, aGradient.StartColor); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_COLOR, aStrValue ); + + // Color end + ::sax::Converter::convertColor(aOut, aGradient.EndColor); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_COLOR, aStrValue ); + + // Intensity start + ::sax::Converter::convertPercent(aOut, aGradient.StartIntensity); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START_INTENSITY, aStrValue ); + + // Intensity end + ::sax::Converter::convertPercent(aOut, aGradient.EndIntensity); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END_INTENSITY, aStrValue ); + + // Angle + if( aGradient.Style != awt::GradientStyle_RADIAL ) + { + ::sax::Converter::convertAngle(aOut, aGradient.Angle, rExport.getSaneDefaultVersion()); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); + } + + // Border + ::sax::Converter::convertPercent( aOut, aGradient.Border ); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); + + // Do Write + SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_GRADIENT, + true, false ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/HatchStyle.cxx b/xmloff/source/style/HatchStyle.cxx new file mode 100644 index 000000000..a70ee506e --- /dev/null +++ b/xmloff/source/style/HatchStyle.cxx @@ -0,0 +1,178 @@ +/* -*- 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 + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_HatchStyle_Enum[] = +{ + { XML_SINGLE, drawing::HatchStyle_SINGLE }, + { XML_DOUBLE, drawing::HatchStyle_DOUBLE }, + { XML_HATCHSTYLE_TRIPLE, drawing::HatchStyle_TRIPLE }, + { XML_TOKEN_INVALID, drawing::HatchStyle(0) } +}; + +// Import + +XMLHatchStyleImport::XMLHatchStyleImport( SvXMLImport& rImp ) + : rImport(rImp) +{ +} + +void XMLHatchStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + OUString aDisplayName; + + drawing::Hatch aHatch; + aHatch.Style = drawing::HatchStyle_SINGLE; + aHatch.Color = 0; + aHatch.Distance = 0; + aHatch.Angle = 0; + + SvXMLUnitConverter& rUnitConverter = rImport.GetMM100UnitConverter(); + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + case XML_ELEMENT(DRAW_OOO, XML_NAME): + rStrName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + case XML_ELEMENT(DRAW_OOO, XML_DISPLAY_NAME): + aDisplayName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_STYLE): + case XML_ELEMENT(DRAW_OOO, XML_STYLE): + SvXMLUnitConverter::convertEnum( aHatch.Style, aIter.toView(), pXML_HatchStyle_Enum ); + break; + case XML_ELEMENT(DRAW, XML_COLOR): + case XML_ELEMENT(DRAW_OOO, XML_COLOR): + ::sax::Converter::convertColor(aHatch.Color, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_DISTANCE): + case XML_ELEMENT(DRAW_OOO, XML_DISTANCE): + rUnitConverter.convertMeasureToCore(aHatch.Distance, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_ROTATION): + case XML_ELEMENT(DRAW_OOO, XML_ROTATION): + { + sal_Int32 nValue; + if (::sax::Converter::convertNumber(nValue, aIter.toView(), 0, 3600)) + aHatch.Angle = sal_Int16(nValue); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + rValue <<= aHatch; + + if( !aDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::SD_HATCH_ID, rStrName, + aDisplayName ); + rStrName = aDisplayName; + } +} + +// Export + +XMLHatchStyleExport::XMLHatchStyleExport( SvXMLExport& rExp ) + : rExport(rExp) +{ +} + +void XMLHatchStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + drawing::Hatch aHatch; + + if( rStrName.isEmpty() ) + return; + + if( !(rValue >>= aHatch) ) + return; + + OUString aStrValue; + OUStringBuffer aOut; + + SvXMLUnitConverter& rUnitConverter = + rExport.GetMM100UnitConverter(); + + // Style + if( !SvXMLUnitConverter::convertEnum( aOut, aHatch.Style, pXML_HatchStyle_Enum ) ) + return; + + // Name + bool bEncoded = false; + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + rExport.EncodeStyleName( rStrName, + &bEncoded ) ); + if( bEncoded ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + rStrName ); + + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + + // Color + ::sax::Converter::convertColor(aOut, aHatch.Color); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_COLOR, aStrValue ); + + // Distance + rUnitConverter.convertMeasureToXML( aOut, aHatch.Distance ); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISTANCE, aStrValue ); + + // Angle + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ROTATION, OUString::number(aHatch.Angle) ); + + // Do Write + SvXMLElementExport rElem( rExport, XML_NAMESPACE_DRAW, XML_HATCH, + true, false ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/ImageStyle.cxx b/xmloff/source/style/ImageStyle.cxx new file mode 100644 index 000000000..13443d4ad --- /dev/null +++ b/xmloff/source/style/ImageStyle.cxx @@ -0,0 +1,135 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace css; +using namespace xmloff::token; + +void XMLImageStyle::exportXML(OUString const & rStrName, uno::Any const & rValue, SvXMLExport& rExport) +{ + if (rStrName.isEmpty()) + return; + + if (!rValue.has>()) + return; + + // Name + bool bEncoded = false; + rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, + rExport.EncodeStyleName(rStrName, &bEncoded)); + if (bEncoded) + { + rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, rStrName); + } + + auto xBitmap = rValue.get>(); + uno::Reference xGraphic(xBitmap, uno::UNO_QUERY); + + OUString aMimeType; + const OUString aStr = rExport.AddEmbeddedXGraphic(xGraphic, aMimeType); + + // uri + if (!aStr.isEmpty()) + { + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStr ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + + // Do Write + SvXMLElementExport aElem(rExport, XML_NAMESPACE_DRAW, XML_FILL_IMAGE, true, true); + + if (xBitmap.is() && xGraphic.is()) + { + // optional office:binary-data + rExport.AddEmbeddedXGraphicAsBase64(xGraphic); + } +} + +bool XMLImageStyle::importXML(uno::Reference const & xAttrList, + uno::Any& rValue, OUString& rStrName, SvXMLImport& rImport) +{ + bool bHasHRef = false; + bool bHasName = false; + OUString aDisplayName; + uno::Reference xGraphic; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + const OUString aStrValue = aIter.toString(); + + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + { + rStrName = aStrValue; + bHasName = true; + } + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + { + aDisplayName = aStrValue; + } + break; + case XML_ELEMENT(XLINK, XML_HREF): + { + xGraphic = rImport.loadGraphicByURL(aStrValue); + bHasHRef = true; + } + break; + case XML_ELEMENT(XLINK, XML_TYPE): + // ignore + break; + case XML_ELEMENT(XLINK, XML_SHOW): + // ignore + break; + case XML_ELEMENT(XLINK, XML_ACTUATE): + // ignore + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + if (xGraphic.is()) + rValue <<= xGraphic; + + if( !aDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::SD_FILL_IMAGE_ID, + rStrName, aDisplayName ); + rStrName = aDisplayName; + } + + return bHasName && bHasHRef; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/MarkerStyle.cxx b/xmloff/source/style/MarkerStyle.cxx new file mode 100644 index 000000000..8f902feb9 --- /dev/null +++ b/xmloff/source/style/MarkerStyle.cxx @@ -0,0 +1,193 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using namespace ::xmloff::token; + +// Import + +XMLMarkerStyleImport::XMLMarkerStyleImport( SvXMLImport& rImp ) + : rImport( rImp ) +{ +} + +void XMLMarkerStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + bool bHasViewBox = false; + bool bHasPathData = false; + OUString aDisplayName; + + std::unique_ptr xViewBox; + + SvXMLUnitConverter& rUnitConverter = rImport.GetMM100UnitConverter(); + + OUString strPathData; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + OUString aStrValue = aIter.toString(); + + switch (aIter.getToken() & TOKEN_MASK) + { + case XML_NAME: + rStrName = aStrValue; + break; + case XML_DISPLAY_NAME: + aDisplayName = aStrValue; + break; + case XML_VIEWBOX: + xViewBox.reset(new SdXMLImExViewBox(aStrValue, rUnitConverter)); + bHasViewBox = true; + break; + case XML_D: + strPathData = aStrValue; + bHasPathData = true; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + if( bHasViewBox && bHasPathData ) + { + basegfx::B2DPolyPolygon aPolyPolygon; + + if(basegfx::utils::importFromSvgD(aPolyPolygon, strPathData, rImport.needFixPositionAfterZ(), nullptr)) + { + if(aPolyPolygon.count()) + { + // ViewBox probably not used, but stay with former processing inside of + // SdXMLImExSvgDElement + const basegfx::B2DRange aSourceRange( + xViewBox->GetX(), xViewBox->GetY(), + xViewBox->GetX() + xViewBox->GetWidth(), + xViewBox->GetY() + xViewBox->GetHeight()); + const basegfx::B2DRange aTargetRange( + 0.0, 0.0, + xViewBox->GetWidth(), xViewBox->GetHeight()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolyPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + // always use PolyPolygonBezierCoords here + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + rValue <<= aSourcePolyPolygon; + } + } + + if( !aDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::SD_MARKER_ID, rStrName, + aDisplayName ); + rStrName = aDisplayName; + } + } + + xViewBox.reset(); +} + +// Export + +XMLMarkerStyleExport::XMLMarkerStyleExport( SvXMLExport& rExp ) + : rExport( rExp ) +{ +} + +void XMLMarkerStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + if(rStrName.isEmpty()) + return; + + drawing::PolyPolygonBezierCoords aBezier; + + if(!(rValue >>= aBezier)) + return; + + // Name + bool bEncoded(false); + + rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, rExport.EncodeStyleName( rStrName, &bEncoded ) ); + + if( bEncoded ) + { + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, rStrName ); + } + + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + aBezier)); + const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange()); + + + // Viewbox (viewBox="0 0 1500 1000") + + SdXMLImExViewBox aViewBox( + aPolyPolygonRange.getMinX(), + aPolyPolygonRange.getMinY(), + aPolyPolygonRange.getWidth(), + aPolyPolygonRange.getHeight()); + rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() ); + + // Pathdata + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + rExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString); + + // Do Write + SvXMLElementExport rElem( rExport, XML_NAMESPACE_DRAW, XML_MARKER, true, false ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/MultiPropertySetHelper.cxx b/xmloff/source/style/MultiPropertySetHelper.cxx new file mode 100644 index 000000000..7636278eb --- /dev/null +++ b/xmloff/source/style/MultiPropertySetHelper.cxx @@ -0,0 +1,169 @@ +/* -*- 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 +#include +#include +#include + +#include + +using ::com::sun::star::beans::XMultiPropertySet; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XPropertySetInfo; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; + + +MultiPropertySetHelper::MultiPropertySetHelper( + const char** pNames ) : + nLength( 0 ), + pValues( nullptr ) +{ + // first count the elements + for( const char** pPtr = pNames; *pPtr != nullptr; pPtr++ ) + nLength++; + + // allocate array and create strings + pPropertyNames.reset( new OUString[nLength] ); + for( sal_Int16 i = 0; i < nLength; i++ ) + pPropertyNames[i] = OUString::createFromAscii( pNames[i] ); +} + + +MultiPropertySetHelper::~MultiPropertySetHelper() +{ + pValues = nullptr; // memory 'owned' by aValues +} + + +void MultiPropertySetHelper::hasProperties( + const Reference & rInfo ) +{ + SAL_WARN_IF( !rInfo.is(), "xmloff", "I'd really like an XPropertySetInfo here." ); + + // allocate sequence index + if ( !pSequenceIndex ) + pSequenceIndex.reset( new sal_Int16[nLength] ); + + // construct pSequenceIndex + sal_Int16 nNumberOfProperties = 0; + sal_Int16 i; + + for( i = 0; i < nLength; i++ ) + { + // ask for property + bool bHasProperty = + rInfo->hasPropertyByName( pPropertyNames[i] ); + + // set index and increment (if appropriate) + pSequenceIndex[i]= bHasProperty ? nNumberOfProperties : -1; + if ( bHasProperty ) + nNumberOfProperties++; + } + + // construct property sequence from index array + if ( aPropertySequence.getLength() != nNumberOfProperties ) + aPropertySequence.realloc( nNumberOfProperties ); + OUString* pPropertySequence = aPropertySequence.getArray(); + for( i = 0; i < nLength; i ++ ) + { + sal_Int16 nIndex = pSequenceIndex[i]; + if ( nIndex != -1 ) + pPropertySequence[nIndex] = pPropertyNames[i]; + } +} + +bool MultiPropertySetHelper::checkedProperties() +{ + return (nullptr != pSequenceIndex); +} + + +void MultiPropertySetHelper::getValues( + const Reference & rMultiPropertySet ) +{ + SAL_WARN_IF( !rMultiPropertySet.is(), "xmloff", "We need an XMultiPropertySet." ); + + aValues = rMultiPropertySet->getPropertyValues( aPropertySequence ); + pValues = aValues.getConstArray(); +} + +void MultiPropertySetHelper::getValues( + const Reference & rPropertySet ) +{ + SAL_WARN_IF( !rPropertySet.is(), "xmloff", "We need an XPropertySet." ); + + // re-alloc aValues (if necessary) and fill with values from XPropertySet + sal_Int16 nSupportedPropertiesCount = + static_cast(aPropertySequence.getLength()); + if ( aValues.getLength() != nSupportedPropertiesCount ) + aValues.realloc( nSupportedPropertiesCount ); + Any* pMutableArray = aValues.getArray(); + for( sal_Int16 i = 0; i < nSupportedPropertiesCount; i++ ) + { + pMutableArray[i] = rPropertySet->getPropertyValue( + pPropertyNames[ pSequenceIndex[ i ] ] ); + } + + // re-establish pValues pointer + pValues = aValues.getConstArray(); +} + + +const Any& MultiPropertySetHelper::getValue( sal_Int16 nIndex, + const Reference< XPropertySet> & rPropSet, + bool bTryMulti ) +{ + if( !pValues ) + { + if( bTryMulti ) + { + Reference < XMultiPropertySet > xMultiPropSet( rPropSet, + UNO_QUERY ); + if( xMultiPropSet.is() ) + getValues( xMultiPropSet ); + else + getValues( rPropSet ); + } + else + { + getValues( rPropSet ); + } + } + + return getValue( nIndex ); +} + +const Any& MultiPropertySetHelper::getValue( sal_Int16 nIndex, + const Reference< XMultiPropertySet> & rMultiPropSet ) +{ + if( !pValues ) + getValues( rMultiPropSet ); + + return getValue( nIndex ); +} + +// inline methods defined in header: +// inline Any& MultiPropertySetHelper::getValue( sal_Int16 nIndex ) +// inline sal_Bool MultiPropertySetHelper::hasProperty( sal_Int16 nValueNo ) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/NamedBoolPropertyHdl.cxx b/xmloff/source/style/NamedBoolPropertyHdl.cxx new file mode 100644 index 000000000..be74fa4b7 --- /dev/null +++ b/xmloff/source/style/NamedBoolPropertyHdl.cxx @@ -0,0 +1,67 @@ +/* -*- 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 +#include +#include +#include +#include + +using namespace ::com::sun::star::uno; + + + + +XMLNamedBoolPropertyHdl::~XMLNamedBoolPropertyHdl() +{ + // Nothing to do +} + +bool XMLNamedBoolPropertyHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + if( rStrImpValue == maTrueStr ) + { + rValue <<= true; + return true; + } + + if( rStrImpValue == maFalseStr ) + { + rValue <<= false; + return true; + } + + return false; +} + +bool XMLNamedBoolPropertyHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + if( ::cppu::any2bool( rValue ) ) + { + rStrExpValue = maTrueStr; + } + else + { + rStrExpValue = maFalseStr; + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageHeaderFooterContext.cxx b/xmloff/source/style/PageHeaderFooterContext.cxx new file mode 100644 index 000000000..3c9e0993b --- /dev/null +++ b/xmloff/source/style/PageHeaderFooterContext.cxx @@ -0,0 +1,71 @@ +/* -*- 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 "PageHeaderFooterContext.hxx" +#include +#include +#include +#include +#include "PagePropertySetContext.hxx" +#include + +using namespace com::sun::star; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_HEADER_FOOTER_PROPERTIES; + +PageHeaderFooterContext::PageHeaderFooterContext( SvXMLImport& rImport, + ::std::vector< XMLPropertyState > & rTempProperties, + const rtl::Reference < SvXMLImportPropertyMapper > &rTempMap, + sal_Int32 nStart, sal_Int32 nEnd, + const bool bTempHeader ) : + SvXMLImportContext( rImport ), + rProperties(rTempProperties), + nStartIndex(nStart), + nEndIndex(nEnd), + rMap(rTempMap) +{ + bHeader = bTempHeader; +} + +PageHeaderFooterContext::~PageHeaderFooterContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > PageHeaderFooterContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_HEADER_FOOTER_PROPERTIES) ) + { + PageContextType aType = Header; + if (!bHeader) + aType = Footer; + return new PagePropertySetContext( GetImport(), nElement, + xAttrList, + XML_TYPE_PROP_HEADER_FOOTER, + rProperties, + rMap, nStartIndex, nEndIndex, aType); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageHeaderFooterContext.hxx b/xmloff/source/style/PageHeaderFooterContext.hxx new file mode 100644 index 000000000..a96a8a393 --- /dev/null +++ b/xmloff/source/style/PageHeaderFooterContext.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/. + * + * 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 +#include + +class PageHeaderFooterContext : public SvXMLImportContext +{ + ::std::vector< XMLPropertyState > & rProperties; + sal_Int32 nStartIndex; + sal_Int32 nEndIndex; + bool bHeader; + const rtl::Reference < SvXMLImportPropertyMapper > rMap; + +public: + + PageHeaderFooterContext( SvXMLImport& rImport, + ::std::vector< XMLPropertyState > & rProperties, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + sal_Int32 nStartIndex, sal_Int32 nEndIndex, + const bool bHeader); + + virtual ~PageHeaderFooterContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterExportPropMapper.cxx b/xmloff/source/style/PageMasterExportPropMapper.cxx new file mode 100644 index 000000000..725ad6f9e --- /dev/null +++ b/xmloff/source/style/PageMasterExportPropMapper.cxx @@ -0,0 +1,650 @@ +/* -*- 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 "PageMasterExportPropMapper.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::comphelper; +using namespace ::xmloff::token; + +static bool lcl_HasSameLineWidth( const table::BorderLine2& rLine1, const table::BorderLine2& rLine2 ) +{ + return (rLine1.InnerLineWidth == rLine2.InnerLineWidth) && + (rLine1.OuterLineWidth == rLine2.OuterLineWidth) && + (rLine1.LineDistance == rLine2.LineDistance) && + (rLine1.LineWidth == rLine2.LineWidth); +} + +static void lcl_RemoveState( XMLPropertyState* pState ) +{ + pState->mnIndex = -1; + pState->maValue.clear(); +} + +static void lcl_RemoveStateIfZero16( XMLPropertyState* pState ) +{ + sal_Int16 nValue = sal_Int16(); + if( (pState->maValue >>= nValue) && !nValue ) + lcl_RemoveState( pState ); +} + +static void lcl_AddState(::std::vector< XMLPropertyState >& rPropState, sal_Int32 nIndex, const OUString& rProperty, const uno::Reference< beans::XPropertySet >& xProps) +{ + if(::cppu::any2bool(xProps->getPropertyValue(rProperty))) + rPropState.emplace_back(nIndex, css::uno::Any(true)); +} + +// helper struct to handle equal XMLPropertyState's for page, header and footer + +namespace { + +struct XMLPropertyStateBuffer +{ + XMLPropertyState* pPMMarginAll; + + XMLPropertyState* pPMBorderAll; + XMLPropertyState* pPMBorderTop; + XMLPropertyState* pPMBorderBottom; + XMLPropertyState* pPMBorderLeft; + XMLPropertyState* pPMBorderRight; + + XMLPropertyState* pPMBorderWidthAll; + XMLPropertyState* pPMBorderWidthTop; + XMLPropertyState* pPMBorderWidthBottom; + XMLPropertyState* pPMBorderWidthLeft; + XMLPropertyState* pPMBorderWidthRight; + + XMLPropertyState* pPMPaddingAll; + XMLPropertyState* pPMPaddingTop; + XMLPropertyState* pPMPaddingBottom; + XMLPropertyState* pPMPaddingLeft; + XMLPropertyState* pPMPaddingRight; + + XMLPropertyState* pPMMarginGutter; + XMLPropertyState* pPMMarginLeft; + XMLPropertyState* pPMRtlGutter; + XMLPropertyState* pPMMarginRight; + bool m_bGutterAtTop; + XMLPropertyState* pPMMarginTop; + + XMLPropertyStateBuffer(); + void ContextFilter( ::std::vector< XMLPropertyState >& rPropState ); +}; + +} + +XMLPropertyStateBuffer::XMLPropertyStateBuffer() + : pPMMarginAll( nullptr ) + , + pPMBorderAll( nullptr ), + pPMBorderTop( nullptr ), + pPMBorderBottom( nullptr ), + pPMBorderLeft( nullptr ), + pPMBorderRight( nullptr ), + + pPMBorderWidthAll( nullptr ), + pPMBorderWidthTop( nullptr ), + pPMBorderWidthBottom( nullptr ), + pPMBorderWidthLeft( nullptr ), + pPMBorderWidthRight( nullptr ), + + pPMPaddingAll( nullptr ), + pPMPaddingTop( nullptr ), + pPMPaddingBottom( nullptr ), + pPMPaddingLeft( nullptr ), + pPMPaddingRight( nullptr ), + + pPMMarginGutter( nullptr ), + pPMMarginLeft( nullptr ), + pPMRtlGutter( nullptr ), + pPMMarginRight( nullptr ), + m_bGutterAtTop( false ), + pPMMarginTop( nullptr ) +{ +} + +void XMLPropertyStateBuffer::ContextFilter( ::std::vector< XMLPropertyState >& ) +{ + if (pPMMarginGutter) + { + sal_Int32 nGutterMargin{}; + pPMMarginGutter->maValue >>= nGutterMargin; + if (m_bGutterAtTop) + { + if (nGutterMargin && pPMMarginTop) + { + // Increase top margin to include gutter. + sal_Int32 nTopMargin{}; + pPMMarginTop->maValue >>= nTopMargin; + nTopMargin += nGutterMargin; + pPMMarginTop->maValue <<= nTopMargin; + } + } + else + { + bool bRtlGutter{}; + if (nGutterMargin && pPMRtlGutter) + { + pPMRtlGutter->maValue >>= bRtlGutter; + } + if (bRtlGutter) + { + if (nGutterMargin && pPMMarginRight) + { + // Increase right margin to include gutter. + sal_Int32 nRightMargin{}; + pPMMarginRight->maValue >>= nRightMargin; + nRightMargin += nGutterMargin; + pPMMarginRight->maValue <<= nRightMargin; + } + } + else + { + if (nGutterMargin && pPMMarginLeft) + { + // Increase left margin to include gutter. + sal_Int32 nLeftMargin{}; + pPMMarginLeft->maValue >>= nLeftMargin; + nLeftMargin += nGutterMargin; + pPMMarginLeft->maValue <<= nLeftMargin; + } + } + } + } + + if (pPMMarginAll) + { + lcl_RemoveState(pPMMarginAll); // #i117696# do not write fo:margin + } + + if( pPMBorderAll ) + { + if( pPMBorderTop && pPMBorderBottom && pPMBorderLeft && pPMBorderRight ) + { + table::BorderLine2 aLineTop, aLineBottom, aLineLeft, aLineRight; + + pPMBorderTop->maValue >>= aLineTop; + pPMBorderBottom->maValue >>= aLineBottom; + pPMBorderLeft->maValue >>= aLineLeft; + pPMBorderRight->maValue >>= aLineRight; + + if( (aLineTop == aLineBottom) && (aLineBottom == aLineLeft) && (aLineLeft == aLineRight) ) + { + lcl_RemoveState( pPMBorderTop ); + lcl_RemoveState( pPMBorderBottom ); + lcl_RemoveState( pPMBorderLeft ); + lcl_RemoveState( pPMBorderRight ); + } + else + lcl_RemoveState( pPMBorderAll ); + } + else + lcl_RemoveState( pPMBorderAll ); + } + + if( pPMBorderWidthAll ) + { + if( pPMBorderWidthTop && pPMBorderWidthBottom && pPMBorderWidthLeft && pPMBorderWidthRight ) + { + table::BorderLine2 aLineTop, aLineBottom, aLineLeft, aLineRight; + + pPMBorderWidthTop->maValue >>= aLineTop; + pPMBorderWidthBottom->maValue >>= aLineBottom; + pPMBorderWidthLeft->maValue >>= aLineLeft; + pPMBorderWidthRight->maValue >>= aLineRight; + + if( lcl_HasSameLineWidth( aLineTop, aLineBottom ) && + lcl_HasSameLineWidth( aLineBottom, aLineLeft ) && + lcl_HasSameLineWidth( aLineLeft, aLineRight ) ) + { + lcl_RemoveState( pPMBorderWidthTop ); + lcl_RemoveState( pPMBorderWidthBottom ); + lcl_RemoveState( pPMBorderWidthLeft ); + lcl_RemoveState( pPMBorderWidthRight ); + } + else + lcl_RemoveState( pPMBorderWidthAll ); + } + else + lcl_RemoveState( pPMBorderWidthAll ); + } + + if( !pPMPaddingAll ) + return; + + if( pPMPaddingTop && pPMPaddingBottom && pPMPaddingLeft && pPMPaddingRight ) + { + sal_Int32 nTop = 0, nBottom = 0, nLeft = 0, nRight = 0; + + pPMPaddingTop->maValue >>= nTop; + pPMPaddingBottom->maValue >>= nBottom; + pPMPaddingLeft->maValue >>= nLeft; + pPMPaddingRight->maValue >>= nRight; + + if( (nTop == nBottom) && (nBottom == nLeft) && (nLeft == nRight) ) + { + lcl_RemoveState( pPMPaddingTop ); + lcl_RemoveState( pPMPaddingBottom ); + lcl_RemoveState( pPMPaddingLeft ); + lcl_RemoveState( pPMPaddingRight ); + } + else + lcl_RemoveState( pPMPaddingAll ); + } + else + lcl_RemoveState( pPMPaddingAll ); +} + +XMLPageMasterExportPropMapper::XMLPageMasterExportPropMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExport ) : + SvXMLExportPropertyMapper( rMapper ), + aBackgroundImageExport( rExport ), + aTextColumnsExport( rExport ), + aFootnoteSeparatorExport( rExport ) +{ +} + +XMLPageMasterExportPropMapper::~XMLPageMasterExportPropMapper() +{ +} + +void XMLPageMasterExportPropMapper::handleElementItem( + SvXMLExport&, + const XMLPropertyState& rProperty, + SvXmlExportFlags /*nFlags*/, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx ) const +{ + XMLPageMasterExportPropMapper* pThis = const_cast(this); + + sal_uInt32 nContextId = getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ); + switch( nContextId ) + { + case CTF_PM_GRAPHICURL: + case CTF_PM_HEADERGRAPHICURL: + case CTF_PM_FOOTERGRAPHICURL: + { + assert(pProperties); + assert(nIdx >= 2 && "horrible array ordering borked again"); + sal_Int32 nPos(-1); + sal_Int32 nFilter(-1); + switch( nContextId ) + { + case CTF_PM_GRAPHICURL: + nPos = CTF_PM_GRAPHICPOSITION; + nFilter = CTF_PM_GRAPHICFILTER; + break; + case CTF_PM_HEADERGRAPHICURL: + nPos = CTF_PM_HEADERGRAPHICPOSITION; + nFilter = CTF_PM_HEADERGRAPHICFILTER; + break; + case CTF_PM_FOOTERGRAPHICURL: + nPos = CTF_PM_FOOTERGRAPHICPOSITION; + nFilter = CTF_PM_FOOTERGRAPHICFILTER; + break; + default: + assert(false); + } + const Any* pPos = nullptr; + const Any* pFilter = nullptr; + sal_uInt32 nIndex(nIdx - 1); + const XMLPropertyState& rFilter = (*pProperties)[nIndex]; + if (getPropertySetMapper()->GetEntryContextId(rFilter.mnIndex) == nFilter) + { + pFilter = &rFilter.maValue; + --nIndex; + } + const XMLPropertyState& rPos = (*pProperties)[nIndex]; + if (getPropertySetMapper()->GetEntryContextId(rPos.mnIndex) == nPos) + { + pPos = &rPos.maValue; + --nIndex; + } + sal_uInt32 nPropIndex = rProperty.mnIndex; + pThis->aBackgroundImageExport.exportXML( rProperty.maValue, pPos, pFilter, nullptr, + getPropertySetMapper()->GetEntryNameSpace( nPropIndex ), + getPropertySetMapper()->GetEntryXMLName( nPropIndex ) ); + } + break; + case CTF_PM_TEXTCOLUMNS: + pThis->aTextColumnsExport.exportXML( rProperty.maValue ); + break; + case CTF_PM_FTN_LINE_WEIGHT: + pThis->aFootnoteSeparatorExport.exportXML( pProperties, nIdx, + getPropertySetMapper()); + break; + } +} + +void XMLPageMasterExportPropMapper::handleSpecialItem( + SvXMLAttributeList&, + const XMLPropertyState&, + const SvXMLUnitConverter&, + const SvXMLNamespaceMap&, + const ::std::vector< XMLPropertyState >*, + sal_uInt32 /*nIdx*/) const +{ +} + +void XMLPageMasterExportPropMapper::ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rPropState, + const Reference< XPropertySet >& rPropSet ) const +{ + XMLPropertyStateBuffer aPageBuffer; + if (m_bGutterAtTop) + { + aPageBuffer.m_bGutterAtTop = true; + } + + XMLPropertyStateBuffer aHeaderBuffer; + XMLPropertyStateBuffer aFooterBuffer; + + XMLPropertyState* pPMHeaderHeight = nullptr; + XMLPropertyState* pPMHeaderMinHeight = nullptr; + XMLPropertyState* pPMHeaderDynamic = nullptr; + + XMLPropertyState* pPMFooterHeight = nullptr; + XMLPropertyState* pPMFooterMinHeight = nullptr; + XMLPropertyState* pPMFooterDynamic = nullptr; + + XMLPropertyState* pPMScaleTo = nullptr; + XMLPropertyState* pPMScaleToPages = nullptr; + XMLPropertyState* pPMScaleToX = nullptr; + XMLPropertyState* pPMScaleToY = nullptr; + XMLPropertyState* pPMStandardMode = nullptr; + XMLPropertyState* pPMGridBaseWidth = nullptr; + // same as pPMGridSnapTo but for backward compatibility only + XMLPropertyState* pPMGridSnapToChars = nullptr; + XMLPropertyState* pPMGridSnapTo = nullptr; + + XMLPropertyState* pPrint = nullptr; + + XMLPropertyState* pRepeatOffsetX = nullptr; + XMLPropertyState* pRepeatOffsetY = nullptr; + XMLPropertyState* pHeaderRepeatOffsetX = nullptr; + XMLPropertyState* pHeaderRepeatOffsetY = nullptr; + XMLPropertyState* pFooterRepeatOffsetX = nullptr; + XMLPropertyState* pFooterRepeatOffsetY = nullptr; + + rtl::Reference < XMLPropertySetMapper > aPropMapper(getPropertySetMapper()); + + // distinguish 2 cases: drawing-page export has CTF_PM_FILL, page-layout-properties export does not + bool const isDrawingPageExport(aPropMapper->FindEntryIndex(CTF_PM_FILL) != -1); + + for( auto& rProp : rPropState ) + { + XMLPropertyState *pProp = &rProp; + sal_Int16 nContextId = aPropMapper->GetEntryContextId( pProp->mnIndex ); + sal_Int16 nFlag = nContextId & CTF_PM_FLAGMASK; + sal_Int16 nSimpleId = nContextId & (~CTF_PM_FLAGMASK | XML_PM_CTF_START); + sal_Int16 nPrintId = nContextId & CTF_PM_PRINTMASK; + + + // tdf#103602 don't export draw:fill attributes on page-layout-properties in strict ODF + if (!isDrawingPageExport + && [](OUString const& rName) -> bool { + return rName.startsWith("Fill") + || rName.startsWith("HeaderFill") + || rName.startsWith("FooterFill"); + } (aPropMapper->GetEntryAPIName(rProp.mnIndex)) + && ((aBackgroundImageExport.GetExport().getSaneDefaultVersion() + & SvtSaveOptions::ODFSVER_EXTENDED) == 0)) + { + lcl_RemoveState(&rProp); + continue; + } + + XMLPropertyStateBuffer* pBuffer; + switch( nFlag ) + { + case CTF_PM_HEADERFLAG: pBuffer = &aHeaderBuffer; break; + case CTF_PM_FOOTERFLAG: pBuffer = &aFooterBuffer; break; + default: pBuffer = &aPageBuffer; break; + } + + switch( nSimpleId ) + { + case CTF_PM_MARGINALL: pBuffer->pPMMarginAll = pProp; break; + case CTF_PM_BORDERALL: pBuffer->pPMBorderAll = pProp; break; + case CTF_PM_BORDERTOP: pBuffer->pPMBorderTop = pProp; break; + case CTF_PM_BORDERBOTTOM: pBuffer->pPMBorderBottom = pProp; break; + case CTF_PM_BORDERLEFT: pBuffer->pPMBorderLeft = pProp; break; + case CTF_PM_BORDERRIGHT: pBuffer->pPMBorderRight = pProp; break; + case CTF_PM_BORDERWIDTHALL: pBuffer->pPMBorderWidthAll = pProp; break; + case CTF_PM_BORDERWIDTHTOP: pBuffer->pPMBorderWidthTop = pProp; break; + case CTF_PM_BORDERWIDTHBOTTOM: pBuffer->pPMBorderWidthBottom = pProp; break; + case CTF_PM_BORDERWIDTHLEFT: pBuffer->pPMBorderWidthLeft = pProp; break; + case CTF_PM_BORDERWIDTHRIGHT: pBuffer->pPMBorderWidthRight = pProp; break; + case CTF_PM_PADDINGALL: pBuffer->pPMPaddingAll = pProp; break; + case CTF_PM_PADDINGTOP: pBuffer->pPMPaddingTop = pProp; break; + case CTF_PM_PADDINGBOTTOM: pBuffer->pPMPaddingBottom = pProp; break; + case CTF_PM_PADDINGLEFT: pBuffer->pPMPaddingLeft = pProp; break; + case CTF_PM_PADDINGRIGHT: pBuffer->pPMPaddingRight = pProp; break; + case CTF_PM_MARGINGUTTER: + pBuffer->pPMMarginGutter = pProp; + break; + case CTF_PM_MARGINLEFT: + pBuffer->pPMMarginLeft = pProp; + break; + case CTF_PM_RTLGUTTER: + pBuffer->pPMRtlGutter = pProp; + break; + case CTF_PM_MARGINRIGHT: + pBuffer->pPMMarginRight = pProp; + break; + case CTF_PM_MARGINTOP: + pBuffer->pPMMarginTop = pProp; + break; + } + + switch( nContextId ) + { + case CTF_PM_HEADERHEIGHT: pPMHeaderHeight = pProp; break; + case CTF_PM_HEADERMINHEIGHT: pPMHeaderMinHeight = pProp; break; + case CTF_PM_HEADERDYNAMIC: pPMHeaderDynamic = pProp; break; + case CTF_PM_FOOTERHEIGHT: pPMFooterHeight = pProp; break; + case CTF_PM_FOOTERMINHEIGHT: pPMFooterMinHeight = pProp; break; + case CTF_PM_FOOTERDYNAMIC: pPMFooterDynamic = pProp; break; + case CTF_PM_SCALETO: pPMScaleTo = pProp; break; + case CTF_PM_SCALETOPAGES: pPMScaleToPages = pProp; break; + case CTF_PM_SCALETOX: pPMScaleToX = pProp; break; + case CTF_PM_SCALETOY: pPMScaleToY = pProp; break; + case CTF_PM_STANDARD_MODE: pPMStandardMode = pProp; break; + case CTP_PM_GRID_BASE_WIDTH: pPMGridBaseWidth = pProp; break; + case CTP_PM_GRID_SNAP_TO_CHARS: pPMGridSnapToChars = pProp; break; + case CTP_PM_GRID_SNAP_TO: pPMGridSnapTo = pProp; break; + + case CTF_PM_REPEAT_OFFSET_X: + pRepeatOffsetX = pProp; + break; + + case CTF_PM_REPEAT_OFFSET_Y: + pRepeatOffsetY = pProp; + break; + + case CTF_PM_HEADERREPEAT_OFFSET_X: + pHeaderRepeatOffsetX = pProp; + break; + + case CTF_PM_HEADERREPEAT_OFFSET_Y: + pHeaderRepeatOffsetY = pProp; + break; + + case CTF_PM_FOOTERREPEAT_OFFSET_X: + pFooterRepeatOffsetX = pProp; + break; + + case CTF_PM_FOOTERREPEAT_OFFSET_Y: + pFooterRepeatOffsetY = pProp; + break; + + // Sort out empty entries + case CTF_PM_FILLGRADIENTNAME: + case CTF_PM_FILLHATCHNAME: + case CTF_PM_FILLBITMAPNAME: + case CTF_PM_FILLTRANSNAME: + + case CTF_PM_HEADERFILLGRADIENTNAME: + case CTF_PM_HEADERFILLHATCHNAME: + case CTF_PM_HEADERFILLBITMAPNAME: + case CTF_PM_HEADERFILLTRANSNAME: + + case CTF_PM_FOOTERFILLGRADIENTNAME: + case CTF_PM_FOOTERFILLHATCHNAME: + case CTF_PM_FOOTERFILLBITMAPNAME: + case CTF_PM_FOOTERFILLTRANSNAME: + { + OUString aStr; + + if( (pProp->maValue >>= aStr) && 0 == aStr.getLength() ) + { + pProp->mnIndex = -1; + } + + break; + } + } + + if (nPrintId == CTF_PM_PRINTMASK) + { + pPrint = pProp; + lcl_RemoveState(pPrint); + } + } + + // These entries need to be reduced to a single one for XML export. + // Both would be exported as 'draw:tile-repeat-offset' following a percent + // value and a 'vertical' or 'horizontal' tag as mark. If both would be active + // and both would be exported this would create an XML error (same property twice) + if(pRepeatOffsetX && pRepeatOffsetY) + { + sal_Int32 nOffset(0); + + if((pRepeatOffsetX->maValue >>= nOffset) && (!nOffset)) + { + pRepeatOffsetX->mnIndex = -1; + } + else + { + pRepeatOffsetY->mnIndex = -1; + } + } + + // Same as above for Header + if(pHeaderRepeatOffsetX && pHeaderRepeatOffsetY) + { + sal_Int32 nOffset(0); + + if((pHeaderRepeatOffsetX->maValue >>= nOffset) && (!nOffset)) + { + pHeaderRepeatOffsetX->mnIndex = -1; + } + else + { + pHeaderRepeatOffsetY->mnIndex = -1; + } + } + + // Same as above for Footer + if(pFooterRepeatOffsetX && pFooterRepeatOffsetY) + { + sal_Int32 nOffset(0); + + if((pFooterRepeatOffsetX->maValue >>= nOffset) && (!nOffset)) + { + pFooterRepeatOffsetX->mnIndex = -1; + } + else + { + pFooterRepeatOffsetY->mnIndex = -1; + } + } + + if( pPMStandardMode && !getBOOL(pPMStandardMode->maValue) ) + { + lcl_RemoveState(pPMStandardMode); + if( pPMGridBaseWidth ) + lcl_RemoveState(pPMGridBaseWidth); + if( pPMGridSnapToChars ) + lcl_RemoveState(pPMGridSnapToChars); + if (pPMGridSnapTo) + { + lcl_RemoveState(pPMGridSnapTo); + } + } + + if( pPMGridBaseWidth && pPMStandardMode ) + lcl_RemoveState(pPMStandardMode); + + aPageBuffer.ContextFilter( rPropState ); + aHeaderBuffer.ContextFilter( rPropState ); + aFooterBuffer.ContextFilter( rPropState ); + + if( pPMHeaderHeight && (!pPMHeaderDynamic || getBOOL( pPMHeaderDynamic->maValue )) ) + lcl_RemoveState( pPMHeaderHeight ); + if( pPMHeaderMinHeight && pPMHeaderDynamic && !getBOOL( pPMHeaderDynamic->maValue ) ) + lcl_RemoveState( pPMHeaderMinHeight ); + if( pPMHeaderDynamic ) + lcl_RemoveState( pPMHeaderDynamic ); + + if( pPMFooterHeight && (!pPMFooterDynamic || getBOOL( pPMFooterDynamic->maValue )) ) + lcl_RemoveState( pPMFooterHeight ); + if( pPMFooterMinHeight && pPMFooterDynamic && !getBOOL( pPMFooterDynamic->maValue ) ) + lcl_RemoveState( pPMFooterMinHeight ); + if( pPMFooterDynamic ) + lcl_RemoveState( pPMFooterDynamic ); + + if( pPMScaleTo ) + lcl_RemoveStateIfZero16( pPMScaleTo ); + if( pPMScaleToPages ) + lcl_RemoveStateIfZero16( pPMScaleToPages ); + if( pPMScaleToX ) + lcl_RemoveStateIfZero16( pPMScaleToX ); + if( pPMScaleToY ) + lcl_RemoveStateIfZero16( pPMScaleToY ); + + if (pPrint) + { + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_ANNOTATIONS), "PrintAnnotations", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_CHARTS), "PrintCharts", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_DRAWING), "PrintDrawing", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_FORMULAS), "PrintFormulas", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_GRID), "PrintGrid", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_HEADERS), "PrintHeaders", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_OBJECTS), "PrintObjects", rPropSet); + lcl_AddState(rPropState, aPropMapper->FindEntryIndex(CTF_PM_PRINT_ZEROVALUES), "PrintZeroValues", rPropSet); + } + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rPropState, rPropSet); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterExportPropMapper.hxx b/xmloff/source/style/PageMasterExportPropMapper.hxx new file mode 100644 index 000000000..8aa2debc8 --- /dev/null +++ b/xmloff/source/style/PageMasterExportPropMapper.hxx @@ -0,0 +1,66 @@ +/* -*- 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 +#include +#include +#include "XMLFootnoteSeparatorExport.hxx" + +class XMLPageMasterExportPropMapper : public SvXMLExportPropertyMapper +{ + XMLBackgroundImageExport aBackgroundImageExport; + XMLTextColumnsExport aTextColumnsExport; + XMLFootnoteSeparatorExport aFootnoteSeparatorExport; + bool m_bGutterAtTop = false; + + virtual void ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet + ) const override; + +public: + XMLPageMasterExportPropMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExport + ); + virtual ~XMLPageMasterExportPropMapper() override; + + virtual void handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx + ) const override; + virtual void handleSpecialItem( + SvXMLAttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState >* pProperties, + sal_uInt32 nIdx + ) const override; + + void SetGutterAtTop(bool bGutterAtTop) { m_bGutterAtTop = bGutterAtTop; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterImportContext.cxx b/xmloff/source/style/PageMasterImportContext.cxx new file mode 100644 index 000000000..874c87509 --- /dev/null +++ b/xmloff/source/style/PageMasterImportContext.cxx @@ -0,0 +1,434 @@ +/* -*- 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 +#include +#include +#include +#include +#include "PageMasterPropHdl.hxx" +#include "PagePropertySetContext.hxx" +#include "PageHeaderFooterContext.hxx" +#include +#include +#include +#include + +// +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +// +using namespace ::com::sun::star::beans; + +void PageStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_PAGE_USAGE) ) + { + sPageUsage = rValue; + } + else + { + XMLPropStyleContext::SetAttribute( nElement, rValue ); + } +} + + +PageStyleContext::PageStyleContext( SvXMLImport& rImport, + SvXMLStylesContext& rStyles, + bool bDefaultStyle) : + XMLPropStyleContext( rImport, rStyles, XmlStyleFamily::PAGE_MASTER, bDefaultStyle), + m_bIsFillStyleAlreadyConverted(false) // +{ +} + +PageStyleContext::~PageStyleContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > PageStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_HEADER_STYLE) || + nElement == XML_ELEMENT(STYLE, XML_FOOTER_STYLE) ) + { + bool bHeader = nElement == XML_ELEMENT(STYLE, XML_HEADER_STYLE); + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + { + const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper(); + sal_Int32 nFlag; + if (bHeader) + nFlag = CTF_PM_HEADERFLAG; + else + nFlag = CTF_PM_FOOTERFLAG; + sal_Int32 nStartIndex (-1); + sal_Int32 nEndIndex (-1); + bool bFirst(false); + bool bEnd(false); + sal_Int32 nIndex = 0; + while ( nIndex < rMapper->GetEntryCount() && !bEnd) + { + if ((rMapper->GetEntryContextId( nIndex ) & CTF_PM_FLAGMASK) == nFlag) + { + if (!bFirst) + { + bFirst = true; + nStartIndex = nIndex; + } + } + else if (bFirst) + { + bEnd = true; + nEndIndex = nIndex; + } + nIndex++; + } + if (!bEnd) + nEndIndex = nIndex; + return new PageHeaderFooterContext(GetImport(), + GetProperties(), xImpPrMap, nStartIndex, nEndIndex, bHeader); + } + } + + if( nElement == XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_PROPERTIES) ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + { + const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper(); + sal_Int32 nEndIndex (-1); + bool bEnd(false); + sal_Int32 nIndex = 0; + sal_Int16 nContextID; + while ( nIndex < rMapper->GetEntryCount() && !bEnd) + { + nContextID = rMapper->GetEntryContextId( nIndex ); + if (nContextID && ((nContextID & CTF_PM_FLAGMASK) != XML_PM_CTF_START)) + { + nEndIndex = nIndex; + bEnd = true; + } + nIndex++; + } + if (!bEnd) + nEndIndex = nIndex; + return new PagePropertySetContext( GetImport(), nElement, + xAttrList, + XML_TYPE_PROP_PAGE_LAYOUT, + GetProperties(), + xImpPrMap, 0, nEndIndex, Page); + } + } + + return XMLPropStyleContext::createFastChildContext(nElement, xAttrList); +} + +void PageStyleContext::FillPropertySet(const uno::Reference &) +{ + assert(false); // don't call this virtual, call function below +} + +void PageStyleContext::FillPropertySet_PageStyle( + const uno::Reference & xPropSet, + XMLPropStyleContext *const pDrawingPageStyle) +{ + // need to filter out old fill definitions when the new ones are used. The new + // ones are used when a FillStyle is defined + if(!m_bIsFillStyleAlreadyConverted && !GetProperties().empty()) + { + static constexpr OUStringLiteral s_FillStyle(u"FillStyle"); + static constexpr OUStringLiteral s_HeaderFillStyle(u"HeaderFillStyle"); + static constexpr OUStringLiteral s_FooterFillStyle(u"FooterFillStyle"); + + // note: the function must only check by property name, not any id/flag! + if (doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle) + || (pDrawingPageStyle && pDrawingPageStyle->doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle))) + { + deactivateOldFillStyleDefinitions(getStandardSet()); + } + + if(doNewDrawingLayerFillStyleDefinitionsExist(s_HeaderFillStyle)) + { + deactivateOldFillStyleDefinitions(getHeaderSet()); + } + + if(doNewDrawingLayerFillStyleDefinitionsExist(s_FooterFillStyle)) + { + deactivateOldFillStyleDefinitions(getFooterSet()); + } + + m_bIsFillStyleAlreadyConverted = true; + } + + // do not use XMLPropStyleContext::FillPropertySet, we need to handle this ourselves since + // we have properties which use the MID_FLAG_NO_PROPERTY_IMPORT flag since they need some special + // handling + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = GetStyles()->GetImportPropertyMapper(GetFamily()); + + if(xImpPrMap.is()) + { + // properties that need special handling because they need the used name to be translated first + struct ContextID_Index_Pair aContextIDs[] = + { + { CTF_PM_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_PM_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_PM_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_PM_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + // also need to special handling for header entries + { CTF_PM_HEADERFILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_PM_HEADERFILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_PM_HEADERFILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_PM_HEADERFILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + // also need to special handling for footer entries + { CTF_PM_FOOTERFILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_PM_FOOTERFILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_PM_FOOTERFILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_PM_FOOTERFILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + {-1, -1, drawing::FillStyle::FillStyle_GRADIENT} + }; + + // the style families associated with the same index modulo 4 + static const XmlStyleFamily aFamilies[] = + { + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID + }; + + // Fill PropertySet, but let it handle special properties not itself + xImpPrMap->FillPropertySet(GetProperties(), xPropSet, aContextIDs); + + // get property set mapper + const rtl::Reference< XMLPropertySetMapper >& rMapper = xImpPrMap->getPropertySetMapper(); + Reference const xInfo(xPropSet->getPropertySetInfo()); + + // don't look at the attributes, look at the property, could + // theoretically be inherited and we don't want to delete erroneously + drawing::FillStyle fillStyle{drawing::FillStyle_NONE}; + drawing::FillStyle fillStyleHeader{drawing::FillStyle_NONE}; + drawing::FillStyle fillStyleFooter{drawing::FillStyle_NONE}; + if (xInfo->hasPropertyByName("FillStyle")) // SwXTextDefaults lacks it? + { + xPropSet->getPropertyValue("FillStyle") >>= fillStyle; + xPropSet->getPropertyValue("HeaderFillStyle") >>= fillStyleHeader; + xPropSet->getPropertyValue("FooterFillStyle") >>= fillStyleFooter; + } + + // handle special attributes which have MID_FLAG_NO_PROPERTY_IMPORT set + for(sal_uInt16 i = 0; aContextIDs[i].nContextID != -1; i++) + { + sal_Int32 nIndex = aContextIDs[i].nIndex; + + if(nIndex != -1) + { + drawing::FillStyle const* pFillStyle(nullptr); + switch(aContextIDs[i].nContextID) + { + case CTF_PM_FILLGRADIENTNAME: + case CTF_PM_FILLTRANSNAME: + case CTF_PM_FILLHATCHNAME: + case CTF_PM_FILLBITMAPNAME: + pFillStyle = &fillStyle; + [[fallthrough]]; + case CTF_PM_HEADERFILLGRADIENTNAME: + case CTF_PM_HEADERFILLTRANSNAME: + case CTF_PM_HEADERFILLHATCHNAME: + case CTF_PM_HEADERFILLBITMAPNAME: + if (!pFillStyle) { pFillStyle = &fillStyleHeader; } + [[fallthrough]]; + case CTF_PM_FOOTERFILLGRADIENTNAME: + case CTF_PM_FOOTERFILLTRANSNAME: + case CTF_PM_FOOTERFILLHATCHNAME: + case CTF_PM_FOOTERFILLBITMAPNAME: + { + if (!pFillStyle) { pFillStyle = &fillStyleFooter; } + struct XMLPropertyState& rState = GetProperties()[nIndex]; + OUString sStyleName; + rState.maValue >>= sStyleName; + + if (aContextIDs[i].nExpectedFillStyle != drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE + && aContextIDs[i].nExpectedFillStyle != *pFillStyle) + { + SAL_INFO("xmloff.style", "PageStyleContext: dropping fill named item: " << sStyleName); + break; // ignore it, it's not used + } + // translate the used name from ODF intern to the name used in the Model + sStyleName = GetImport().GetStyleDisplayName(aFamilies[i%4], sStyleName); + + try + { + // set property + const OUString& rPropertyName = rMapper->GetEntryAPIName(rState.mnIndex); + + if(xInfo->hasPropertyByName(rPropertyName)) + { + xPropSet->setPropertyValue(rPropertyName,Any(sStyleName)); + } + } + catch(css::lang::IllegalArgumentException& e) + { + Sequence aSeq { sStyleName }; + GetImport().SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, + aSeq,e.Message,nullptr); + } + break; + } + } + } + } + } + else + { + OSL_ENSURE(xImpPrMap.is(), "Got no SvXMLImportPropertyMapper (!)"); + } + + // pDrawingPageStyle overrides this + if (pDrawingPageStyle) + { + pDrawingPageStyle->FillPropertySet(xPropSet); + } + // horrible heuristic to guess BackgroundFullSize for Writer < 7.0 + else if (!IsDefaultStyle() // ignore pool default, only fix existing styles + && (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x)) + { + bool isFullSize(true); // default is current LO default + drawing::FillStyle fillStyle{drawing::FillStyle_NONE}; + xPropSet->getPropertyValue("FillStyle") >>= fillStyle; + if (GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_63x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || GetImport().getGeneratorVersion() == SvXMLImport::AOO_4x) + { + // before LO 6.3, always inside the margins (but ignore it if NONE) + if (fillStyle != drawing::FillStyle_NONE) + { + isFullSize = false; + } + } + else + { + // LO 6.3/6.4: guess depending on fill style/bitmap mode + // this should work even if the document doesn't contain fill style + // but only old background attributes + // (can't use the aContextIDs stuff above because that requires + // re-routing through handleSpecialItem()) + switch (fillStyle) + { + case drawing::FillStyle_NONE: + break; + case drawing::FillStyle_SOLID: + case drawing::FillStyle_GRADIENT: + case drawing::FillStyle_HATCH: + isFullSize = true; + break; + case drawing::FillStyle_BITMAP: + { + drawing::BitmapMode bitmapMode{}; + xPropSet->getPropertyValue("FillBitmapMode") >>= bitmapMode; + switch (bitmapMode) + { + case drawing::BitmapMode_REPEAT: + isFullSize = true; + break; + case drawing::BitmapMode_STRETCH: + case drawing::BitmapMode_NO_REPEAT: + isFullSize = false; + break; + default: + assert(false); + } + } + break; + default: + assert(false); + } + } + // set it explicitly if it's not the default + if (!isFullSize) + { + SAL_INFO("xmloff.style", "FillPropertySet_PageStyle: Heuristically resetting BackgroundFullSize"); + xPropSet->setPropertyValue("BackgroundFullSize", uno::Any(isFullSize)); + } + } + + // old code, replaced by above stuff + // XMLPropStyleContext::FillPropertySet(rPropSet); + + if (!sPageUsage.isEmpty()) + { + uno::Any aPageUsage; + XMLPMPropHdl_PageStyleLayout aPageUsageHdl; + if (aPageUsageHdl.importXML(sPageUsage, aPageUsage, GetImport().GetMM100UnitConverter())) + xPropSet->setPropertyValue("PageStyleLayout", aPageUsage); + } +} + +extern ContextID_Index_Pair const g_MasterPageContextIDs[] = +{ + { CTF_PM_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_PM_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_PM_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_PM_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + {-1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE} +}; + +extern XmlStyleFamily const g_MasterPageFamilies[] = +{ + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID +}; + +// text grid enhancement for better CJK support +//set default page layout style +void PageStyleContext::SetDefaults( ) +{ + Reference < XMultiServiceFactory > xFactory ( GetImport().GetModel(), UNO_QUERY); + if (xFactory.is()) + { + Reference < XInterface > xInt = xFactory->createInstance( "com.sun.star.text.Defaults" ); + Reference < beans::XPropertySet > xProperties ( xInt, UNO_QUERY ); + if ( xProperties.is() ) + FillPropertySet_PageStyle(xProperties, nullptr); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterImportPropMapper.cxx b/xmloff/source/style/PageMasterImportPropMapper.cxx new file mode 100644 index 000000000..d4eba7601 --- /dev/null +++ b/xmloff/source/style/PageMasterImportPropMapper.cxx @@ -0,0 +1,521 @@ +/* -*- 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 "PageMasterImportPropMapper.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define XML_LINE_LEFT 0 +#define XML_LINE_RIGHT 1 +#define XML_LINE_TOP 2 +#define XML_LINE_BOTTOM 3 + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; + +PageMasterImportPropertyMapper::PageMasterImportPropertyMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLImport& rImp ) : + SvXMLImportPropertyMapper( rMapper, rImp ), + rImport( rImp ) +{ +} + +PageMasterImportPropertyMapper::~PageMasterImportPropertyMapper() +{ +} + +bool PageMasterImportPropertyMapper::handleSpecialItem( + XMLPropertyState& rProperty, + std::vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const +{ + bool bRet = false; + sal_Int16 nContextID = + getPropertySetMapper()->GetEntryContextId(rProperty.mnIndex); + + if( CTF_PM_REGISTER_STYLE==nContextID ) + { + OUString sDisplayName( rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, rValue ) ); + Reference < XNameContainer > xParaStyles = + rImport.GetTextImport()->GetParaStyles(); + if( xParaStyles.is() && xParaStyles->hasByName( sDisplayName ) ) + { + rProperty.maValue <<= sDisplayName; + bRet = true; + } + } + else + { + bRet = SvXMLImportPropertyMapper::handleSpecialItem( + rProperty, rProperties, rValue, + rUnitConverter, rNamespaceMap ); + } + + return bRet; +} + + +void PageMasterImportPropertyMapper::finished(std::vector< XMLPropertyState >& rProperties, sal_Int32 nStartIndex, sal_Int32 nEndIndex ) const +{ + SvXMLImportPropertyMapper::finished(rProperties, nStartIndex, nEndIndex); + XMLPropertyState* pAllPaddingProperty = nullptr; + XMLPropertyState* pPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pNewPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllBorderProperty = nullptr; + XMLPropertyState* pBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllBorderWidthProperty = nullptr; + XMLPropertyState* pBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllHeaderPaddingProperty = nullptr; + XMLPropertyState* pHeaderPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pHeaderNewPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllHeaderBorderProperty = nullptr; + XMLPropertyState* pHeaderBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pHeaderNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllHeaderBorderWidthProperty = nullptr; + XMLPropertyState* pHeaderBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllFooterPaddingProperty = nullptr; + XMLPropertyState* pFooterPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pFooterNewPadding[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllFooterBorderProperty = nullptr; + XMLPropertyState* pFooterBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pFooterNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllFooterBorderWidthProperty = nullptr; + XMLPropertyState* pFooterBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pHeaderHeight = nullptr; + XMLPropertyState* pHeaderMinHeight = nullptr; + std::optional xHeaderDynamic; + XMLPropertyState* pFooterHeight = nullptr; + XMLPropertyState* pFooterMinHeight = nullptr; + std::optional xFooterDynamic; + XMLPropertyState* pAllMarginProperty = nullptr; + XMLPropertyState* pMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + std::optional pNewMargins[4]; + XMLPropertyState* pAllHeaderMarginProperty = nullptr; + XMLPropertyState* pHeaderMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + std::optional pNewHeaderMargins[4]; + XMLPropertyState* pAllFooterMarginProperty = nullptr; + XMLPropertyState* pFooterMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + std::optional pNewFooterMargins[4]; + XMLPropertyState* pMarginGutter = nullptr; + XMLPropertyState* pRtlGutter = nullptr; + + for (auto& rProp : rProperties) + { + XMLPropertyState *property = &rProp; + sal_Int16 nContextID = getPropertySetMapper()->GetEntryContextId(property->mnIndex); + if (property->mnIndex >= nStartIndex && property->mnIndex < nEndIndex) + { + switch (nContextID) + { + case CTF_PM_PADDINGALL : pAllPaddingProperty = property; break; + case CTF_PM_PADDINGLEFT : pPadding[XML_LINE_LEFT] = property; break; + case CTF_PM_PADDINGRIGHT : pPadding[XML_LINE_RIGHT] = property; break; + case CTF_PM_PADDINGTOP : pPadding[XML_LINE_TOP] = property; break; + case CTF_PM_PADDINGBOTTOM : pPadding[XML_LINE_BOTTOM] = property; break; + case CTF_PM_BORDERALL : pAllBorderProperty = property; break; + case CTF_PM_BORDERLEFT : pBorders[XML_LINE_LEFT] = property; break; + case CTF_PM_BORDERRIGHT : pBorders[XML_LINE_RIGHT] = property; break; + case CTF_PM_BORDERTOP : pBorders[XML_LINE_TOP] = property; break; + case CTF_PM_BORDERBOTTOM : pBorders[XML_LINE_BOTTOM] = property; break; + case CTF_PM_BORDERWIDTHALL : pAllBorderWidthProperty = property; break; + case CTF_PM_BORDERWIDTHLEFT : pBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_PM_BORDERWIDTHRIGHT : pBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_PM_BORDERWIDTHTOP : pBorderWidths[XML_LINE_TOP] = property; break; + case CTF_PM_BORDERWIDTHBOTTOM : pBorderWidths[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERPADDINGALL : pAllHeaderPaddingProperty = property; break; + case CTF_PM_HEADERPADDINGLEFT : pHeaderPadding[XML_LINE_LEFT] = property; break; + case CTF_PM_HEADERPADDINGRIGHT : pHeaderPadding[XML_LINE_RIGHT] = property; break; + case CTF_PM_HEADERPADDINGTOP : pHeaderPadding[XML_LINE_TOP] = property; break; + case CTF_PM_HEADERPADDINGBOTTOM : pHeaderPadding[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERBORDERALL : pAllHeaderBorderProperty = property; break; + case CTF_PM_HEADERBORDERLEFT : pHeaderBorders[XML_LINE_LEFT] = property; break; + case CTF_PM_HEADERBORDERRIGHT : pHeaderBorders[XML_LINE_RIGHT] = property; break; + case CTF_PM_HEADERBORDERTOP : pHeaderBorders[XML_LINE_TOP] = property; break; + case CTF_PM_HEADERBORDERBOTTOM : pHeaderBorders[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERBORDERWIDTHALL : pAllHeaderBorderWidthProperty = property; break; + case CTF_PM_HEADERBORDERWIDTHLEFT : pHeaderBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_PM_HEADERBORDERWIDTHRIGHT : pHeaderBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_PM_HEADERBORDERWIDTHTOP : pHeaderBorderWidths[XML_LINE_TOP] = property; break; + case CTF_PM_HEADERBORDERWIDTHBOTTOM : pHeaderBorderWidths[XML_LINE_BOTTOM] = property; break; + case CTF_PM_FOOTERPADDINGALL : pAllFooterPaddingProperty = property; break; + case CTF_PM_FOOTERPADDINGLEFT : pFooterPadding[XML_LINE_LEFT] = property; break; + case CTF_PM_FOOTERPADDINGRIGHT : pFooterPadding[XML_LINE_RIGHT] = property; break; + case CTF_PM_FOOTERPADDINGTOP : pFooterPadding[XML_LINE_TOP] = property; break; + case CTF_PM_FOOTERPADDINGBOTTOM : pFooterPadding[XML_LINE_BOTTOM] = property; break; + case CTF_PM_FOOTERBORDERALL : pAllFooterBorderProperty = property; break; + case CTF_PM_FOOTERBORDERLEFT : pFooterBorders[XML_LINE_LEFT] = property; break; + case CTF_PM_FOOTERBORDERRIGHT : pFooterBorders[XML_LINE_RIGHT] = property; break; + case CTF_PM_FOOTERBORDERTOP : pFooterBorders[XML_LINE_TOP] = property; break; + case CTF_PM_FOOTERBORDERBOTTOM : pFooterBorders[XML_LINE_BOTTOM] = property; break; + case CTF_PM_FOOTERBORDERWIDTHALL : pAllFooterBorderWidthProperty = property; break; + case CTF_PM_FOOTERBORDERWIDTHLEFT : pFooterBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_PM_FOOTERBORDERWIDTHRIGHT : pFooterBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_PM_FOOTERBORDERWIDTHTOP : pFooterBorderWidths[XML_LINE_TOP] = property; break; + case CTF_PM_FOOTERBORDERWIDTHBOTTOM : pFooterBorderWidths[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERHEIGHT : pHeaderHeight = property; break; + case CTF_PM_HEADERMINHEIGHT : pHeaderMinHeight = property; break; + case CTF_PM_FOOTERHEIGHT : pFooterHeight = property; break; + case CTF_PM_FOOTERMINHEIGHT : pFooterMinHeight = property; break; + case CTF_PM_MARGINALL : + pAllMarginProperty = property; break; + case CTF_PM_MARGINTOP : + pMargins[XML_LINE_TOP] = property; break; + case CTF_PM_MARGINBOTTOM: + pMargins[XML_LINE_BOTTOM] = property; break; + case CTF_PM_MARGINLEFT : + pMargins[XML_LINE_LEFT] = property; break; + case CTF_PM_MARGINRIGHT : + pMargins[XML_LINE_RIGHT] = property; break; + case CTF_PM_MARGINGUTTER: + pMarginGutter = property; + break; + case CTF_PM_RTLGUTTER: + pRtlGutter = property; + break; + case CTF_PM_HEADERMARGINALL : + pAllHeaderMarginProperty = property; break; + case CTF_PM_HEADERMARGINTOP : + pHeaderMargins[XML_LINE_TOP] = property; break; + case CTF_PM_HEADERMARGINBOTTOM: + pHeaderMargins[XML_LINE_BOTTOM] = property; break; + case CTF_PM_HEADERMARGINLEFT : + pHeaderMargins[XML_LINE_LEFT] = property; break; + case CTF_PM_HEADERMARGINRIGHT : + pHeaderMargins[XML_LINE_RIGHT] = property; break; + case CTF_PM_FOOTERMARGINALL : + pAllFooterMarginProperty = property; break; + case CTF_PM_FOOTERMARGINTOP : + pFooterMargins[XML_LINE_TOP] = property; break; + case CTF_PM_FOOTERMARGINBOTTOM: + pFooterMargins[XML_LINE_BOTTOM] = property; break; + case CTF_PM_FOOTERMARGINLEFT : + pFooterMargins[XML_LINE_LEFT] = property; break; + case CTF_PM_FOOTERMARGINRIGHT : + pFooterMargins[XML_LINE_RIGHT] = property; break; + } + } + } + + for (sal_uInt16 i = 0; i < 4; i++) + { + if (pAllMarginProperty && !pMargins[i]) + { + pNewMargins[i].emplace( + pAllMarginProperty->mnIndex + 1 + i, + pAllMarginProperty->maValue); + } + if (pAllHeaderMarginProperty && !pHeaderMargins[i]) + { + pNewHeaderMargins[i].emplace( + pAllHeaderMarginProperty->mnIndex + 1 + i, + pAllHeaderMarginProperty->maValue); + } + if (pAllFooterMarginProperty && !pFooterMargins[i]) + { + pNewFooterMargins[i].emplace( + pAllFooterMarginProperty->mnIndex + 1 + i, + pAllFooterMarginProperty->maValue); + } + if (pAllPaddingProperty && !pPadding[i]) + pNewPadding[i] = new XMLPropertyState(pAllPaddingProperty->mnIndex + 1 + i, pAllPaddingProperty->maValue); + if (pAllBorderProperty && !pBorders[i]) + { + pNewBorders[i] = new XMLPropertyState(pAllBorderProperty->mnIndex + 1 + i, pAllBorderProperty->maValue); + pBorders[i] = pNewBorders[i]; + } + if( !pBorderWidths[i] ) + pBorderWidths[i] = pAllBorderWidthProperty; + else + pBorderWidths[i]->mnIndex = -1; + if( pBorders[i] ) + { + table::BorderLine2 aBorderLine; + pBorders[i]->maValue >>= aBorderLine; + if( pBorderWidths[i] ) + { + table::BorderLine2 aBorderLineWidth; + pBorderWidths[i]->maValue >>= aBorderLineWidth; + aBorderLine.OuterLineWidth = aBorderLineWidth.OuterLineWidth; + aBorderLine.InnerLineWidth = aBorderLineWidth.InnerLineWidth; + aBorderLine.LineDistance = aBorderLineWidth.LineDistance; + aBorderLine.LineWidth = aBorderLineWidth.LineWidth; + pBorders[i]->maValue <<= aBorderLine; + } + } + if (pAllHeaderPaddingProperty && !pHeaderPadding[i]) + pHeaderNewPadding[i] = new XMLPropertyState(pAllHeaderPaddingProperty->mnIndex + 1 + i, pAllHeaderPaddingProperty->maValue); + if (pAllHeaderBorderProperty && !pHeaderBorders[i]) + pHeaderNewBorders[i] = new XMLPropertyState(pAllHeaderBorderProperty->mnIndex + 1 + i, pAllHeaderBorderProperty->maValue); + if( !pHeaderBorderWidths[i] ) + pHeaderBorderWidths[i] = pAllHeaderBorderWidthProperty; + else + pHeaderBorderWidths[i]->mnIndex = -1; + if( pHeaderBorders[i] ) + { + table::BorderLine2 aBorderLine; + pHeaderBorders[i]->maValue >>= aBorderLine; + if( pHeaderBorderWidths[i] ) + { + table::BorderLine2 aBorderLineWidth; + pHeaderBorderWidths[i]->maValue >>= aBorderLineWidth; + aBorderLine.OuterLineWidth = aBorderLineWidth.OuterLineWidth; + aBorderLine.InnerLineWidth = aBorderLineWidth.InnerLineWidth; + aBorderLine.LineDistance = aBorderLineWidth.LineDistance; + aBorderLine.LineWidth = aBorderLineWidth.LineWidth; + pHeaderBorders[i]->maValue <<= aBorderLine; + } + } + if (pAllFooterPaddingProperty && !pFooterPadding[i]) + pFooterNewPadding[i] = new XMLPropertyState(pAllFooterPaddingProperty->mnIndex + 1 + i, pAllFooterPaddingProperty->maValue); + if (pAllFooterBorderProperty && !pFooterBorders[i]) + pFooterNewBorders[i] = new XMLPropertyState(pAllFooterBorderProperty->mnIndex + 1 + i, pAllFooterBorderProperty->maValue); + if( !pFooterBorderWidths[i] ) + pFooterBorderWidths[i] = pAllFooterBorderWidthProperty; + else + pFooterBorderWidths[i]->mnIndex = -1; + if( pFooterBorders[i] ) + { + table::BorderLine2 aBorderLine; + pFooterBorders[i]->maValue >>= aBorderLine; + if( pFooterBorderWidths[i] ) + { + table::BorderLine2 aBorderLineWidth; + pFooterBorderWidths[i]->maValue >>= aBorderLineWidth; + aBorderLine.OuterLineWidth = aBorderLineWidth.OuterLineWidth; + aBorderLine.InnerLineWidth = aBorderLineWidth.InnerLineWidth; + aBorderLine.LineDistance = aBorderLineWidth.LineDistance; + aBorderLine.LineWidth = aBorderLineWidth.LineWidth; + pFooterBorders[i]->maValue <<= aBorderLine; + } + } + } + + if (pHeaderHeight) + { + xHeaderDynamic.emplace(pHeaderHeight->mnIndex + 2, Any(false)); + } + if (pHeaderMinHeight) + { + xHeaderDynamic.emplace(pHeaderMinHeight->mnIndex + 1, Any(true)); + } + if (pFooterHeight) + { + xFooterDynamic.emplace(pFooterHeight->mnIndex + 2, Any(false)); + } + if (pFooterMinHeight) + { + xFooterDynamic.emplace(pFooterMinHeight->mnIndex + 1, Any(true)); + } + + // fdo#38056: nerf the various AllFoo properties so they do not override + // the individual Foo properties later on + if (pAllPaddingProperty) + { + pAllPaddingProperty->mnIndex = -1; + } + if (pAllBorderProperty) + { + pAllBorderProperty->mnIndex = -1; + } + if (pAllBorderWidthProperty) + { + pAllBorderWidthProperty->mnIndex = -1; + } + if (pAllHeaderPaddingProperty) + { + pAllHeaderPaddingProperty->mnIndex = -1; + } + if (pAllHeaderBorderProperty) + { + pAllHeaderBorderProperty->mnIndex = -1; + } + if (pAllHeaderBorderWidthProperty) + { + pAllHeaderBorderWidthProperty->mnIndex = -1; + } + if (pAllFooterPaddingProperty) + { + pAllFooterPaddingProperty->mnIndex = -1; + } + if (pAllFooterBorderProperty) + { + pAllFooterBorderProperty->mnIndex = -1; + } + if (pAllFooterBorderWidthProperty) + { + pAllFooterBorderWidthProperty->mnIndex = -1; + } + if (pAllMarginProperty) + { + pAllMarginProperty->mnIndex = -1; + } + if (pAllHeaderMarginProperty) + { + pAllHeaderMarginProperty->mnIndex = -1; + } + if (pAllFooterMarginProperty) + { + pAllFooterMarginProperty->mnIndex = -1; + } + + if (pMarginGutter) + { + sal_Int32 nGutterMargin{}; + pMarginGutter->maValue >>= nGutterMargin; + + bool bGutterAtTop{}; + uno::Reference xSI(GetImport().GetModel(), uno::UNO_QUERY); + if (xSI.is() && xSI->supportsService("com.sun.star.text.TextDocument")) + { + uno::Reference xFac(GetImport().GetModel(), uno::UNO_QUERY); + if (xFac.is()) + { + uno::Reference xProps( + xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY); + if (xProps.is()) + { + xProps->getPropertyValue("GutterAtTop") >>= bGutterAtTop; + } + } + } + if (bGutterAtTop) + { + if (nGutterMargin && pMargins[XML_LINE_TOP]) + { + // Decrease top margin to not include gutter. + sal_Int32 nTopMargin{}; + pMargins[XML_LINE_TOP]->maValue >>= nTopMargin; + nTopMargin -= nGutterMargin; + pMargins[XML_LINE_TOP]->maValue <<= nTopMargin; + } + } + else + { + bool bRtlGutter{}; + if (nGutterMargin && pRtlGutter) + { + pRtlGutter->maValue >>= bRtlGutter; + } + if (bRtlGutter) + { + if (nGutterMargin && pMargins[XML_LINE_RIGHT]) + { + // Decrease right margin to not include gutter. + sal_Int32 nRightMargin{}; + pMargins[XML_LINE_RIGHT]->maValue >>= nRightMargin; + nRightMargin -= nGutterMargin; + pMargins[XML_LINE_RIGHT]->maValue <<= nRightMargin; + } + } + else + { + if (nGutterMargin && pMargins[XML_LINE_LEFT]) + { + // Decrease left margin to not include gutter. + sal_Int32 nLeftMargin{}; + pMargins[XML_LINE_LEFT]->maValue >>= nLeftMargin; + nLeftMargin -= nGutterMargin; + pMargins[XML_LINE_LEFT]->maValue <<= nLeftMargin; + } + } + } + } + + // CAUTION! + // The following code adds into the rProperties vector, so all the + // XMLPropertyState* pointers that are pointing to the rProperties + // elements could potentially be deallocated, so don't use them after + // this! + for (sal_uInt16 i = 0; i < 4; i++) + { + if (pNewMargins[i]) + { + rProperties.push_back(*pNewMargins[i]); + } + if (pNewHeaderMargins[i]) + { + rProperties.push_back(*pNewHeaderMargins[i]); + } + if (pNewFooterMargins[i]) + { + rProperties.push_back(*pNewFooterMargins[i]); + } + if (pNewPadding[i]) + { + rProperties.push_back(*pNewPadding[i]); + delete pNewPadding[i]; + } + if (pNewBorders[i]) + { + rProperties.push_back(*pNewBorders[i]); + delete pNewBorders[i]; + } + if (pHeaderNewPadding[i]) + { + rProperties.push_back(*pHeaderNewPadding[i]); + delete pHeaderNewPadding[i]; + } + if (pHeaderNewBorders[i]) + { + rProperties.push_back(*pHeaderNewBorders[i]); + delete pHeaderNewBorders[i]; + } + if (pFooterNewPadding[i]) + { + rProperties.push_back(*pFooterNewPadding[i]); + delete pFooterNewPadding[i]; + } + if (pFooterNewBorders[i]) + { + rProperties.push_back(*pFooterNewBorders[i]); + delete pFooterNewBorders[i]; + } + } + // CAUTION - do not use XMLPropertyState* pointers (like pMargins, + // pMarginGutter) after this. + + if(xHeaderDynamic) + { + rProperties.push_back(*xHeaderDynamic); + xHeaderDynamic.reset(); + } + if(xFooterDynamic) + { + rProperties.push_back(*xFooterDynamic); + xFooterDynamic.reset(); + } + +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterImportPropMapper.hxx b/xmloff/source/style/PageMasterImportPropMapper.hxx new file mode 100644 index 000000000..1493ffd6b --- /dev/null +++ b/xmloff/source/style/PageMasterImportPropMapper.hxx @@ -0,0 +1,53 @@ +/* -*- 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 + +class SvXMLImport; + +class PageMasterImportPropertyMapper : public SvXMLImportPropertyMapper +{ + SvXMLImport& rImport; + +protected: + +public: + + PageMasterImportPropertyMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLImport& rImp); + virtual ~PageMasterImportPropertyMapper() override; + + /** this method is called for every item that has the MID_FLAG_SPECIAL_ITEM_IMPORT flag set */ + virtual bool handleSpecialItem( + XMLPropertyState& rProperty, + ::std::vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const override; + + /** This method is called when all attributes have been processed. It may be used to remove items that are incomplete */ + virtual void finished( + ::std::vector< XMLPropertyState >& rProperties, + sal_Int32 nStartIndex, sal_Int32 nEndIndex ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterPropHdl.cxx b/xmloff/source/style/PageMasterPropHdl.cxx new file mode 100644 index 000000000..c1fb9010b --- /dev/null +++ b/xmloff/source/style/PageMasterPropHdl.cxx @@ -0,0 +1,398 @@ +/* -*- 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 "PageMasterPropHdl.hxx" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::comphelper; +using namespace ::xmloff::token; + +#define DEFAULT_PAPERTRAY (sal_Int32(-1)) + +// property handler for style:page-usage (style::PageStyleLayout) + +XMLPMPropHdl_PageStyleLayout::~XMLPMPropHdl_PageStyleLayout() +{ +} + +bool XMLPMPropHdl_PageStyleLayout::equals( const Any& rAny1, const Any& rAny2 ) const +{ + style::PageStyleLayout eLayout1, eLayout2; + return (rAny1 >>= eLayout1) && (rAny2 >>= eLayout2) && (eLayout1 == eLayout2); +} + +bool XMLPMPropHdl_PageStyleLayout::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + + if( IsXMLToken( rStrImpValue, XML_ALL ) ) + rValue <<= PageStyleLayout_ALL; + else if( IsXMLToken( rStrImpValue, XML_LEFT ) ) + rValue <<= PageStyleLayout_LEFT; + else if( IsXMLToken( rStrImpValue, XML_RIGHT ) ) + rValue <<= PageStyleLayout_RIGHT; + else if( IsXMLToken( rStrImpValue, XML_MIRRORED ) ) + rValue <<= PageStyleLayout_MIRRORED; + else + bRet = false; + + return bRet; +} + +bool XMLPMPropHdl_PageStyleLayout::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + PageStyleLayout eLayout; + + if( rValue >>= eLayout ) + { + bRet = true; + switch( eLayout ) + { + case PageStyleLayout_ALL: + rStrExpValue = GetXMLToken( XML_ALL ); + break; + case PageStyleLayout_LEFT: + rStrExpValue = GetXMLToken( XML_LEFT ); + break; + case PageStyleLayout_RIGHT: + rStrExpValue = GetXMLToken( XML_RIGHT ); + break; + case PageStyleLayout_MIRRORED: + rStrExpValue = GetXMLToken( XML_MIRRORED ); + break; + default: + bRet = false; + } + } + + return bRet; +} + +// property handler for style:num-format (style::NumberingType) + +XMLPMPropHdl_NumFormat::~XMLPMPropHdl_NumFormat() +{ +} + +bool XMLPMPropHdl_NumFormat::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int16 nSync = sal_Int16(); + sal_Int16 nNumType = NumberingType::NUMBER_NONE; + rUnitConverter.convertNumFormat( nNumType, rStrImpValue, u"", true ); + + if( !(rValue >>= nSync) ) + nSync = NumberingType::NUMBER_NONE; + + // if num-letter-sync appears before num-format, the function + // XMLPMPropHdl_NumLetterSync::importXML() sets the value + // NumberingType::CHARS_LOWER_LETTER_N + if( nSync == NumberingType::CHARS_LOWER_LETTER_N ) + { + switch( nNumType ) + { + case NumberingType::CHARS_LOWER_LETTER: + nNumType = NumberingType::CHARS_LOWER_LETTER_N; + break; + case NumberingType::CHARS_UPPER_LETTER: + nNumType = NumberingType::CHARS_UPPER_LETTER_N; + break; + } + } + rValue <<= nNumType; + + return true; +} + +bool XMLPMPropHdl_NumFormat::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int16 nNumType = sal_Int16(); + + if( rValue >>= nNumType ) + { + OUStringBuffer aBuffer( 10 ); + rUnitConverter.convertNumFormat( aBuffer, nNumType ); + rStrExpValue = aBuffer.makeStringAndClear(); + bRet = true; + } + return bRet; +} + +// property handler for style:num-letter-sync (style::NumberingType) + +XMLPMPropHdl_NumLetterSync::~XMLPMPropHdl_NumLetterSync() +{ +} + +bool XMLPMPropHdl_NumLetterSync::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int16 nNumType; + sal_Int16 nSync = NumberingType::NUMBER_NONE; + rUnitConverter.convertNumFormat( nSync, rStrImpValue, + GetXMLToken( XML_A ), true ); + + if( !(rValue >>= nNumType) ) + nNumType = NumberingType::NUMBER_NONE; + + if( nSync == NumberingType::CHARS_LOWER_LETTER_N ) + { + switch( nNumType ) + { + case NumberingType::CHARS_LOWER_LETTER: + nNumType = NumberingType::CHARS_LOWER_LETTER_N; + break; + case NumberingType::CHARS_UPPER_LETTER: + nNumType = NumberingType::CHARS_UPPER_LETTER_N; + break; + } + } + rValue <<= nNumType; + + return true; +} + +bool XMLPMPropHdl_NumLetterSync::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& /*rUnitConverter*/ ) const +{ + bool bRet = false; + sal_Int16 nNumType = sal_Int16(); + + if( rValue >>= nNumType ) + { + OUStringBuffer aBuffer( 5 ); + SvXMLUnitConverter::convertNumLetterSync( aBuffer, nNumType ); + rStrExpValue = aBuffer.makeStringAndClear(); + bRet = !rStrExpValue.isEmpty(); + } + return bRet; +} + +// property handler for style:paper-tray-number + +XMLPMPropHdl_PaperTrayNumber::~XMLPMPropHdl_PaperTrayNumber() +{ +} + +bool XMLPMPropHdl_PaperTrayNumber::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( IsXMLToken( rStrImpValue, XML_DEFAULT ) ) + { + rValue <<= DEFAULT_PAPERTRAY; + bRet = true; + } + else + { + sal_Int32 nPaperTray; + if (::sax::Converter::convertNumber( nPaperTray, rStrImpValue, 0 )) + { + rValue <<= nPaperTray; + bRet = true; + } + } + + return bRet; +} + +bool XMLPMPropHdl_PaperTrayNumber::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nPaperTray = 0; + + if( rValue >>= nPaperTray ) + { + if( nPaperTray == DEFAULT_PAPERTRAY ) + rStrExpValue = GetXMLToken( XML_DEFAULT ); + else + { + rStrExpValue = OUString::number( nPaperTray ); + } + bRet = true; + } + return bRet; +} + +// property handler for style:print + +XMLPMPropHdl_Print::XMLPMPropHdl_Print( enum XMLTokenEnum eValue ) : + sAttrValue( GetXMLToken( eValue ) ) +{ +} + +XMLPMPropHdl_Print::~XMLPMPropHdl_Print() +{ +} + +bool XMLPMPropHdl_Print::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nTokenIndex = 0; + bool bFound = false; + + do + { + bFound = (sAttrValue == o3tl::getToken(rStrImpValue, 0, ' ', nTokenIndex )); + } + while ( (nTokenIndex >= 0) && !bFound ); + + rValue <<= bFound; + return true; +} + +bool XMLPMPropHdl_Print::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( getBOOL( rValue ) ) + { + if( !rStrExpValue.isEmpty() ) + rStrExpValue += " "; + rStrExpValue += sAttrValue; + } + + return true; +} + +// property handler for style:table-centering + +XMLPMPropHdl_CenterHorizontal::~XMLPMPropHdl_CenterHorizontal() +{ +} + +bool XMLPMPropHdl_CenterHorizontal::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if (!rStrImpValue.isEmpty()) + if (IsXMLToken( rStrImpValue, XML_BOTH) || + IsXMLToken( rStrImpValue, XML_HORIZONTAL)) + { + rValue <<= true; + bRet = true; + } + + return bRet; +} + +bool XMLPMPropHdl_CenterHorizontal::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if ( ::cppu::any2bool( rValue ) ) + { + bRet = true; + if (!rStrExpValue.isEmpty()) + rStrExpValue = GetXMLToken(XML_BOTH); + else + rStrExpValue = GetXMLToken(XML_HORIZONTAL); + } + + return bRet; +} + +XMLPMPropHdl_CenterVertical::~XMLPMPropHdl_CenterVertical() +{ +} + +bool XMLPMPropHdl_CenterVertical::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if (!rStrImpValue.isEmpty()) + if (IsXMLToken(rStrImpValue, XML_BOTH) || + IsXMLToken(rStrImpValue, XML_VERTICAL) ) + { + rValue <<= true; + bRet = true; + } + + return bRet; +} + +bool XMLPMPropHdl_CenterVertical::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if ( ::cppu::any2bool( rValue ) ) + { + bRet = true; + if (!rStrExpValue.isEmpty()) + rStrExpValue = GetXMLToken(XML_BOTH); + else + rStrExpValue = GetXMLToken(XML_VERTICAL); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterPropHdl.hxx b/xmloff/source/style/PageMasterPropHdl.hxx new file mode 100644 index 000000000..2cfd39aff --- /dev/null +++ b/xmloff/source/style/PageMasterPropHdl.hxx @@ -0,0 +1,158 @@ +/* -*- 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 +#include +#include + +// property handler for style:page-usage (style::PageStyleLayout) + +class XMLPMPropHdl_PageStyleLayout : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_PageStyleLayout() override; + virtual bool equals( + const css::uno::Any& rAny1, + const css::uno::Any& rAny2 + ) const override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:num-format (style::NumberingType) + +class XMLPMPropHdl_NumFormat : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_NumFormat() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:num-letter-sync (style::NumberingType) + +class XMLPMPropHdl_NumLetterSync : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_NumLetterSync() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:paper-tray-number + +class XMLPMPropHdl_PaperTrayNumber : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_PaperTrayNumber() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:print + +class XMLPMPropHdl_Print : public XMLPropertyHandler +{ + OUString sAttrValue; + +public: + explicit XMLPMPropHdl_Print( enum ::xmloff::token::XMLTokenEnum eValue ); + virtual ~XMLPMPropHdl_Print() override; + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +// property handler for style:table-centering + +class XMLPMPropHdl_CenterHorizontal : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_CenterHorizontal() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +class XMLPMPropHdl_CenterVertical : public XMLPropertyHandler +{ +public: + virtual ~XMLPMPropHdl_CenterVertical() override; + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter + ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterPropHdlFactory.cxx b/xmloff/source/style/PageMasterPropHdlFactory.cxx new file mode 100644 index 000000000..88a14fb80 --- /dev/null +++ b/xmloff/source/style/PageMasterPropHdlFactory.cxx @@ -0,0 +1,170 @@ +/* -*- 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 +#include +#include +#include +#include +#include "xmlbahdl.hxx" +#include +#include +#include +#include "PageMasterPropHdl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::xmloff::token; +using namespace ::com::sun::star; +using namespace ::com::sun::star::drawing; + +SvXMLEnumMapEntry const aXML_TextGridMode_ConstantMap[] = +{ + { XML_NONE, text::TextGridMode::NONE }, + { XML_LINE, text::TextGridMode::LINES }, + { XML_BOTH, text::TextGridMode::LINES_AND_CHARS }, + { XML_TOKEN_INVALID, 0 } +}; + +XMLPageMasterPropHdlFactory::XMLPageMasterPropHdlFactory() +{ +} + +XMLPageMasterPropHdlFactory::~XMLPageMasterPropHdlFactory() +{ +} + +const XMLPropertyHandler* XMLPageMasterPropHdlFactory::GetPropertyHandler( sal_Int32 nType ) const +{ + nType &= MID_FLAG_MASK; + + XMLPropertyHandler* pHdl = const_cast(XMLPropertyHandlerFactory::GetPropertyHandler( nType )); + if( !pHdl ) + { + switch( nType ) + { + case XML_PM_TYPE_PAGESTYLELAYOUT: + pHdl = new XMLPMPropHdl_PageStyleLayout; + break; + case XML_PM_TYPE_NUMFORMAT: + pHdl = new XMLPMPropHdl_NumFormat; + break; + case XML_PM_TYPE_NUMLETTERSYNC: + pHdl = new XMLPMPropHdl_NumLetterSync; + break; + case XML_PM_TYPE_PAPERTRAYNUMBER: + pHdl = new XMLPMPropHdl_PaperTrayNumber; + break; + case XML_PM_TYPE_PRINTORIENTATION: + pHdl = new XMLNamedBoolPropertyHdl( + GetXMLToken( XML_LANDSCAPE ), + GetXMLToken( XML_PORTRAIT ) ); + break; + case XML_PM_TYPE_PRINTANNOTATIONS: + pHdl = new XMLPMPropHdl_Print( XML_ANNOTATIONS ); + break; + case XML_PM_TYPE_PRINTCHARTS: + pHdl = new XMLPMPropHdl_Print( XML_CHARTS ); + break; + case XML_PM_TYPE_PRINTDRAWING: + pHdl = new XMLPMPropHdl_Print( XML_DRAWINGS ); + break; + case XML_PM_TYPE_PRINTFORMULAS: + pHdl = new XMLPMPropHdl_Print( XML_FORMULAS ); + break; + case XML_PM_TYPE_PRINTGRID: + pHdl = new XMLPMPropHdl_Print( XML_GRID ); + break; + case XML_PM_TYPE_PRINTHEADERS: + pHdl = new XMLPMPropHdl_Print( XML_HEADERS ); + break; + case XML_PM_TYPE_PRINTOBJECTS: + pHdl = new XMLPMPropHdl_Print( XML_OBJECTS ); + break; + case XML_PM_TYPE_PRINTZEROVALUES: + pHdl = new XMLPMPropHdl_Print( XML_ZERO_VALUES ); + break; + case XML_PM_TYPE_PRINTPAGEORDER: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_TTB ), + GetXMLToken( XML_LTR ) ); + break; + case XML_PM_TYPE_FIRSTPAGENUMBER: + pHdl = new XMLNumberNonePropHdl( XML_CONTINUE, 2 ); + break; + case XML_PM_TYPE_CENTER_HORIZONTAL: + pHdl = new XMLPMPropHdl_CenterHorizontal; + break; + case XML_PM_TYPE_CENTER_VERTICAL: + pHdl = new XMLPMPropHdl_CenterVertical; + break; + case XML_TYPE_TEXT_COLUMNS: + pHdl = new XMLTextColumnsPropertyHandler; + break; + case XML_TYPE_LAYOUT_GRID_MODE: + pHdl = new XMLConstantsPropertyHandler( + aXML_TextGridMode_ConstantMap, XML_NONE ); + break; + + case XML_SW_TYPE_FILLSTYLE: + pHdl = new XMLEnumPropertyHdl( aXML_FillStyle_EnumMap ); + break; + case XML_SW_TYPE_PRESPAGE_BACKSIZE: + pHdl = new XMLNamedBoolPropertyHdl(GetXMLToken(XML_FULL), GetXMLToken(XML_BORDER)); + break; + case XML_SW_TYPE_FILLBITMAPSIZE: + pHdl = new XMLFillBitmapSizePropertyHandler(); + break; + case XML_SW_TYPE_LOGICAL_SIZE: + pHdl = new XMLBitmapLogicalSizePropertyHandler(); + break; + case XML_SW_TYPE_BITMAP_REFPOINT: + pHdl = new XMLEnumPropertyHdl( aXML_RefPoint_EnumMap ); + break; + case XML_SW_TYPE_BITMAP_MODE: + pHdl = new XMLEnumPropertyHdl( aXML_BitmapMode_EnumMap ); + break; + case XML_SW_TYPE_BITMAPREPOFFSETX: + case XML_SW_TYPE_BITMAPREPOFFSETY: + pHdl = new XMLBitmapRepeatOffsetPropertyHandler(XML_SW_TYPE_BITMAPREPOFFSETX == nType); + break; + case XML_SW_TYPE_RTLGUTTER: + pHdl = new XMLRtlGutterPropertyHandler(); + break; + + default: + { + OSL_ENSURE(false, "XMLPropertyHandler missing (!)"); + break; + } + } + + if( pHdl ) + PutHdlCache( nType, pHdl ); + } + return pHdl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterPropMapper.cxx b/xmloff/source/style/PageMasterPropMapper.cxx new file mode 100644 index 000000000..c792ff0a0 --- /dev/null +++ b/xmloff/source/style/PageMasterPropMapper.cxx @@ -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/. + * + * 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 + +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + +XMLPageMasterPropSetMapper::XMLPageMasterPropSetMapper(): + XMLPropertySetMapper( aXMLPageMasterStyleMap, new XMLPageMasterPropHdlFactory(), false/*bForExport*/) +{ +} + +XMLPageMasterPropSetMapper::XMLPageMasterPropSetMapper( + const XMLPropertyMapEntry* pEntries, + const rtl::Reference< XMLPropertyHandlerFactory >& rFactory ) : + XMLPropertySetMapper( pEntries, rFactory, true/*bForExport*/ ) +{ +} + +XMLPageMasterPropSetMapper::~XMLPageMasterPropSetMapper() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PageMasterStyleMap.cxx b/xmloff/source/style/PageMasterStyleMap.cxx new file mode 100644 index 000000000..349badc23 --- /dev/null +++ b/xmloff/source/style/PageMasterStyleMap.cxx @@ -0,0 +1,305 @@ +/* -*- 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 +#include +#include + +using namespace ::xmloff::token; + +#define MAP(name,prefix,token,type,context,version) { name, prefix, token, type, context, version, false } +#define DPMAP(name,prefix,token,type,context) MAP(name, prefix, token, type|XML_TYPE_PROP_DRAWING_PAGE, context, SvtSaveOptions::ODFSVER_013) +#define PLMAP(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_PAGE_LAYOUT, context, SvtSaveOptions::ODFSVER_010) +#define PLMAP_12(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_PAGE_LAYOUT, context, SvtSaveOptions::ODFSVER_012) +#define PLMAP_ODF13(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_PAGE_LAYOUT, context, SvtSaveOptions::ODFSVER_013) +#define PLMAP_EXT(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_PAGE_LAYOUT, context, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED) +#define HFMAP(name,prefix,token,type,context) \ + MAP(name, prefix, token, type|XML_TYPE_PROP_HEADER_FOOTER, context, SvtSaveOptions::ODFSVER_010) + +const XMLPropertyMapEntry aXMLPageMasterStyleMap[] = +{ + ////////////////////////////////////////////////////////////////////////// + // Section for 'page-layout-properties' + + // page master + PLMAP( "PageStyleLayout", XML_NAMESPACE_STYLE, XML_PAGE_USAGE, XML_PM_TYPE_PAGESTYLELAYOUT | MID_FLAG_SPECIAL_ITEM, CTF_PM_PAGEUSAGE ), + PLMAP( "Width", XML_NAMESPACE_FO, XML_PAGE_WIDTH, XML_TYPE_MEASURE, 0 ), + PLMAP( "Height", XML_NAMESPACE_FO, XML_PAGE_HEIGHT, XML_TYPE_MEASURE, 0 ), + PLMAP( "NumberingType", XML_NAMESPACE_STYLE, XML_NUM_FORMAT, XML_PM_TYPE_NUMFORMAT | MID_FLAG_MERGE_PROPERTY, 0 ), + PLMAP( "NumberingType", XML_NAMESPACE_STYLE, XML_NUM_LETTER_SYNC, XML_PM_TYPE_NUMLETTERSYNC, 0 ), + PLMAP( "PrinterPaperTray", XML_NAMESPACE_STYLE, XML_PAPER_TRAY_NAME, XML_TYPE_STRING | MID_FLAG_PROPERTY_MAY_THROW, 0 ), + PLMAP( "IsLandscape", XML_NAMESPACE_STYLE, XML_PRINT_ORIENTATION, XML_PM_TYPE_PRINTORIENTATION, 0 ), + PLMAP( "TopMargin", XML_NAMESPACE_FO, XML_MARGIN, XML_TYPE_MEASURE, CTF_PM_MARGINALL ), + PLMAP( "TopMargin", XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_TYPE_MEASURE, CTF_PM_MARGINTOP ), + PLMAP( "BottomMargin", XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_TYPE_MEASURE, CTF_PM_MARGINBOTTOM ), + PLMAP( "LeftMargin", XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE, CTF_PM_MARGINLEFT ), + PLMAP( "RightMargin", XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE, CTF_PM_MARGINRIGHT ), + PLMAP( "TopBorder", XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER, CTF_PM_BORDERALL ), + PLMAP( "TopBorder", XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER, CTF_PM_BORDERTOP ), + PLMAP( "BottomBorder", XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER, CTF_PM_BORDERBOTTOM ), + PLMAP( "LeftBorder", XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER, CTF_PM_BORDERLEFT ), + PLMAP( "RightBorder", XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER, CTF_PM_BORDERRIGHT ), + PLMAP( "TopBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHALL ), + PLMAP( "TopBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHTOP ), + PLMAP( "BottomBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHBOTTOM ), + PLMAP( "LeftBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHLEFT ), + PLMAP( "RightBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_PM_BORDERWIDTHRIGHT ), + PLMAP( "TopBorderDistance", XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE, CTF_PM_PADDINGALL ), + PLMAP( "TopBorderDistance", XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE, CTF_PM_PADDINGTOP ), + PLMAP( "BottomBorderDistance", XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE, CTF_PM_PADDINGBOTTOM ), + PLMAP( "LeftBorderDistance", XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE, CTF_PM_PADDINGLEFT ), + PLMAP( "RightBorderDistance", XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE, CTF_PM_PADDINGRIGHT ), + PLMAP( "ShadowFormat", XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW, 0 ), + PLMAP( "BackColor", XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT | MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( "BackTransparent", XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT | MID_FLAG_MERGE_ATTRIBUTE, 0 ), + PLMAP( "BackGraphicLocation", XML_NAMESPACE_STYLE, XML_POSITION, XML_TYPE_BUILDIN_CMP_ONLY | MID_FLAG_SPECIAL_ITEM, CTF_PM_GRAPHICPOSITION ), + PLMAP( "BackGraphicFilter", XML_NAMESPACE_STYLE, XML_FILTER_NAME, XML_TYPE_STRING | MID_FLAG_SPECIAL_ITEM, CTF_PM_GRAPHICFILTER ), + PLMAP( "BackGraphic", XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, CTF_PM_GRAPHICURL ), + PLMAP( "PrintAnnotations", XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTANNOTATIONS | MID_FLAG_MULTI_PROPERTY, CTF_PM_PRINT_ANNOTATIONS ), + PLMAP( "PrintCharts", XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTCHARTS | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_CHARTS ), + PLMAP( "PrintDrawing", XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTDRAWING | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_DRAWING ), + PLMAP( "PrintFormulas", XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTFORMULAS | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_FORMULAS ), + PLMAP( "PrintGrid", XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTGRID | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_GRID ), + PLMAP( "PrintHeaders", XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTHEADERS | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_HEADERS ), + PLMAP( "PrintObjects", XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTOBJECTS | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_OBJECTS ), + PLMAP( "PrintZeroValues", XML_NAMESPACE_STYLE, XML_PRINT, XML_PM_TYPE_PRINTZEROVALUES | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_PRINT_ZEROVALUES ), + PLMAP( "PrintDownFirst", XML_NAMESPACE_STYLE, XML_PRINT_PAGE_ORDER, XML_PM_TYPE_PRINTPAGEORDER, 0 ), + PLMAP( "FirstPageNumber", XML_NAMESPACE_STYLE, XML_FIRST_PAGE_NUMBER, XML_PM_TYPE_FIRSTPAGENUMBER, 0 ), + PLMAP( "PageScale", XML_NAMESPACE_STYLE, XML_SCALE_TO, XML_TYPE_PERCENT16, CTF_PM_SCALETO ), + PLMAP( "ScaleToPages", XML_NAMESPACE_STYLE, XML_SCALE_TO_PAGES, XML_TYPE_NUMBER16, CTF_PM_SCALETOPAGES ), + // ODF 1.3 OFFICE-3857 + PLMAP_ODF13( "ScaleToPagesX", XML_NAMESPACE_STYLE, XML_SCALE_TO_X, XML_TYPE_NUMBER16, CTF_PM_SCALETOX ), + PLMAP_ODF13( "ScaleToPagesY", XML_NAMESPACE_STYLE, XML_SCALE_TO_Y, XML_TYPE_NUMBER16, CTF_PM_SCALETOY ), + PLMAP_ODF13( "ScaleToPagesX", XML_NAMESPACE_LO_EXT, XML_SCALE_TO_X, XML_TYPE_NUMBER16, CTF_PM_SCALETOX ), + PLMAP_ODF13( "ScaleToPagesY", XML_NAMESPACE_LO_EXT, XML_SCALE_TO_Y, XML_TYPE_NUMBER16, CTF_PM_SCALETOY ), + PLMAP( "CenterHorizontally", XML_NAMESPACE_STYLE, XML_TABLE_CENTERING, XML_PM_TYPE_CENTER_HORIZONTAL | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, 0 ), + PLMAP( "CenterVertically", XML_NAMESPACE_STYLE, XML_TABLE_CENTERING, XML_PM_TYPE_CENTER_VERTICAL | MID_FLAG_MULTI_PROPERTY | MID_FLAG_MERGE_ATTRIBUTE, 0 ), + PLMAP( "TextColumns", XML_NAMESPACE_STYLE, XML_COLUMNS, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_COLUMNS, CTF_PM_TEXTCOLUMNS ), + PLMAP( "RegisterModeActive", XML_NAMESPACE_STYLE, XML_REGISTER_TRUE, XML_TYPE_BOOL, 0 ), + PLMAP( "RegisterParagraphStyle", XML_NAMESPACE_STYLE, XML_REGISTER_TRUTH_REF_STYLE_NAME, XML_TYPE_STYLENAME| MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_PM_REGISTER_STYLE ), + PLMAP( "WritingMode", XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE | MID_FLAG_MULTI_PROPERTY, CTF_PM_WRITINGMODE ), + PLMAP( "RtlGutter", XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_SW_TYPE_RTLGUTTER | MID_FLAG_MULTI_PROPERTY, CTF_PM_RTLGUTTER ), + + // Index 53: Grid definitions + PLMAP( "GridColor", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_COLOR, XML_TYPE_COLOR, 0 ), + PLMAP( "GridLines", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_LINES, XML_TYPE_NUMBER16, 0 ), + PLMAP( "GridBaseHeight", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_BASE_HEIGHT, XML_TYPE_MEASURE, 0 ), + PLMAP( "GridRubyHeight", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_RUBY_HEIGHT, XML_TYPE_MEASURE, 0 ), + PLMAP( "GridMode", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_MODE, XML_TYPE_LAYOUT_GRID_MODE, 0 ), + PLMAP( "RubyBelow", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_RUBY_BELOW, XML_TYPE_BOOL, 0 ), + PLMAP( "GridPrint", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_PRINT, XML_TYPE_BOOL, 0 ), + PLMAP( "GridDisplay", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_DISPLAY, XML_TYPE_BOOL, 0 ), + + //text grid enhancement for better CJK support + PLMAP_12( "GridBaseWidth", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_BASE_WIDTH, XML_TYPE_MEASURE, CTP_PM_GRID_BASE_WIDTH ), + PLMAP_12( "GridSnapToChars", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_SNAP_TO, XML_TYPE_BOOL, CTP_PM_GRID_SNAP_TO ), + //export as a default attribute + PLMAP_12( "StandardPageMode", XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_STANDARD_MODE, XML_TYPE_BOOL|MID_FLAG_DEFAULT_ITEM_EXPORT, CTF_PM_STANDARD_MODE ), + + PLMAP( "UserDefinedAttributes", XML_NAMESPACE_TEXT, XML_XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + + //Index 65: fill attributes; use PLMAP macro here instead of GMAP, this list is ordered and its order is used + // to decide in which section in ODF to export the contained stuff (the PageMasterStyle creates several XML + // sections, for Page, Header and Footer). The needed order seems to rely not on filtering, but using sections + // based on the order used in this list. + // Also need own defines for the used context flags (e.g. CTF_PM_FILLGRADIENTNAME instead of + // CTF_FILLGRADIENTNAME) since these are used to *filter* up to which entry the attributes belong to the + // 'page-layout-properties' section (!), see SvXMLAutoStylePoolP_Impl::exportXML, look for XmlStyleFamily::PAGE_MASTER + // note: these are duplicated below, in g_XMLPageMasterDrawingPageStyleMap + PLMAP( "FillStyle", XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, 0 ), + PLMAP( "FillColor", XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0 ), + PLMAP( "FillColor2", XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0 ), + PLMAP( "FillGradientName", XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLGRADIENTNAME ), + PLMAP( "FillGradientStepCount", XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0 ), + PLMAP( "FillHatchName", XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLHATCHNAME ), + PLMAP( "FillBackground", XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + PLMAP( "FillBitmapName", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLBITMAPNAME ), + PLMAP( "FillTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + PLMAP( "FillTransparenceGradientName", XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLTRANSNAME ), + PLMAP( "FillBitmapSizeX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( "FillBitmapSizeY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + PLMAP( "FillBitmapMode", XML_NAMESPACE_STYLE, XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FILLBITMAPMODE ), + PLMAP( "FillBitmapPositionOffsetX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + PLMAP( "FillBitmapPositionOffsetY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + PLMAP( "FillBitmapRectanglePoint", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, 0 ), + PLMAP( "FillBitmapOffsetX", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_PM_REPEAT_OFFSET_X ), + PLMAP( "FillBitmapOffsetY", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_PM_REPEAT_OFFSET_Y ), + + // Index 85: footnote + PLMAP( "FootnoteHeight", XML_NAMESPACE_STYLE, XML_FOOTNOTE_MAX_HEIGHT, XML_TYPE_MEASURE, CTF_PM_FTN_HEIGHT ), + PLMAP( "FootnoteLineAdjust", XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_TEXT_HORIZONTAL_ADJUST|MID_FLAG_SPECIAL_ITEM, CTF_PM_FTN_LINE_ADJUST ), + PLMAP( "FootnoteLineColor", XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_COLOR|MID_FLAG_SPECIAL_ITEM, CTF_PM_FTN_LINE_COLOR ), + PLMAP( "FootnoteLineDistance", XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM,CTF_PM_FTN_DISTANCE ), + PLMAP( "FootnoteLineRelativeWidth", XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_PERCENT8|MID_FLAG_SPECIAL_ITEM, CTF_PM_FTN_LINE_WIDTH ), + PLMAP( "FootnoteLineTextDistance", XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM, CTF_PM_FTN_LINE_DISTANCE ), + PLMAP( "FootnoteLineWeight", XML_NAMESPACE_STYLE, XML_FOOTNOTE_SEP, XML_TYPE_MEASURE16|MID_FLAG_ELEMENT_ITEM, CTF_PM_FTN_LINE_WEIGHT ), + PLMAP( "FootnoteLineStyle", XML_NAMESPACE_STYLE, XML_EMPTY, XML_TYPE_STRING|MID_FLAG_ELEMENT_ITEM, CTF_PM_FTN_LINE_STYLE ), + PLMAP_EXT("GutterMargin", XML_NAMESPACE_LO_EXT, XML_MARGIN_GUTTER, XML_TYPE_MEASURE, CTF_PM_MARGINGUTTER), + + ////////////////////////////////////////////////////////////////////////// + //Index 92: Section for 'header-style' own section, all members *have* to use CTF_PM_HEADERFLAG in the context entry (the 5th one) + HFMAP( "HeaderHeight", XML_NAMESPACE_SVG, XML_HEIGHT, XML_TYPE_MEASURE, CTF_PM_HEADERHEIGHT ), + HFMAP( "HeaderHeight", XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_TYPE_MEASURE, CTF_PM_HEADERMINHEIGHT ), + HFMAP( "HeaderIsDynamicHeight", XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_BOOL, CTF_PM_HEADERDYNAMIC ), + HFMAP( "HeaderLeftMargin", XML_NAMESPACE_FO, XML_MARGIN, XML_TYPE_MEASURE, CTF_PM_HEADERMARGINALL ), + HFMAP( "HeaderLeftMargin", XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE, CTF_PM_HEADERMARGINLEFT ), + HFMAP( "HeaderRightMargin", XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE, CTF_PM_HEADERMARGINRIGHT ), + HFMAP( "HeaderBodyDistance", XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_TYPE_MEASURE, CTF_PM_HEADERMARGINBOTTOM ), + HFMAP( "HeaderTopBorder", XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER, CTF_PM_HEADERBORDERALL ), + HFMAP( "HeaderTopBorder", XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER, CTF_PM_HEADERBORDERTOP ), + HFMAP( "HeaderBottomBorder", XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER, CTF_PM_HEADERBORDERBOTTOM ), + HFMAP( "HeaderLeftBorder", XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER, CTF_PM_HEADERBORDERLEFT ), + HFMAP( "HeaderRightBorder", XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER, CTF_PM_HEADERBORDERRIGHT ), + HFMAP( "HeaderTopBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHALL ), + HFMAP( "HeaderTopBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHTOP ), + HFMAP( "HeaderBottomBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHBOTTOM ), + HFMAP( "HeaderLeftBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHLEFT ), + HFMAP( "HeaderRightBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_PM_HEADERBORDERWIDTHRIGHT ), + HFMAP( "HeaderTopBorderDistance", XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGALL ), + HFMAP( "HeaderTopBorderDistance", XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGTOP ), + HFMAP( "HeaderBottomBorderDistance", XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGBOTTOM ), + HFMAP( "HeaderLeftBorderDistance", XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGLEFT ), + HFMAP( "HeaderRightBorderDistance", XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE, CTF_PM_HEADERPADDINGRIGHT ), + HFMAP( "HeaderShadowFormat", XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderBackColor", XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT | MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderBackTransparent", XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderBackGraphicLocation", XML_NAMESPACE_STYLE, XML_POSITION, XML_TYPE_BUILDIN_CMP_ONLY | MID_FLAG_SPECIAL_ITEM, CTF_PM_HEADERGRAPHICPOSITION ), + HFMAP( "HeaderBackGraphicFilter", XML_NAMESPACE_STYLE, XML_FILTER_NAME, XML_TYPE_STRING | MID_FLAG_SPECIAL_ITEM, CTF_PM_HEADERGRAPHICFILTER ), + HFMAP( "HeaderBackGraphic", XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, CTF_PM_HEADERGRAPHICURL ), + HFMAP( "HeaderDynamicSpacing", XML_NAMESPACE_STYLE, XML_DYNAMIC_SPACING, XML_TYPE_BOOL, CTF_PM_HEADERFLAG ), + + //Index 121: Header DrawingLayer FillAttributes + // Use HFMAP to get XML_TYPE_PROP_HEADER_FOOTER ORed to the 4th entry + // Names have to begin with 'Header', all 5th entries need to be ORed with the CTF_PM_HEADERFLAG + HFMAP( "HeaderFillStyle", XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillColor", XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillColor2", XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillGradientName", XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_HEADERFILLGRADIENTNAME ), + HFMAP( "HeaderFillGradientStepCount", XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillHatchName", XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_HEADERFILLHATCHNAME ), + HFMAP( "HeaderFillBackground", XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillBitmapName", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_HEADERFILLBITMAPNAME ), + HFMAP( "HeaderFillTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), // exists in SW, too + HFMAP( "HeaderFillTransparenceGradientName", XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_HEADERFILLTRANSNAME ), + HFMAP( "HeaderFillBitmapSizeX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillBitmapSizeY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillBitmapMode", XML_NAMESPACE_STYLE, XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillBitmapPositionOffsetX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillBitmapPositionOffsetY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillBitmapRectanglePoint", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, CTF_PM_HEADERFLAG ), + HFMAP( "HeaderFillBitmapOffsetX", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERREPEAT_OFFSET_X ), + HFMAP( "HeaderFillBitmapOffsetY", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_PM_HEADERREPEAT_OFFSET_Y ), + + ////////////////////////////////////////////////////////////////////////// + //Index 141: Section for 'footer-style' own section, all members *have* to use CTF_PM_FOOTERFLAG in the context entry (the 5th one) + HFMAP( "FooterHeight", XML_NAMESPACE_SVG, XML_HEIGHT, XML_TYPE_MEASURE, CTF_PM_FOOTERHEIGHT ), + HFMAP( "FooterHeight", XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_TYPE_MEASURE, CTF_PM_FOOTERMINHEIGHT ), + HFMAP( "FooterIsDynamicHeight", XML_NAMESPACE_STYLE, XML__EMPTY, XML_TYPE_BOOL, CTF_PM_FOOTERDYNAMIC ), + HFMAP( "FooterLeftMargin", XML_NAMESPACE_FO, XML_MARGIN, XML_TYPE_MEASURE, CTF_PM_FOOTERMARGINALL ), + HFMAP( "FooterLeftMargin", XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_TYPE_MEASURE, CTF_PM_FOOTERMARGINLEFT ), + HFMAP( "FooterRightMargin", XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_TYPE_MEASURE, CTF_PM_FOOTERMARGINRIGHT ), + HFMAP( "FooterBodyDistance", XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_TYPE_MEASURE, CTF_PM_FOOTERMARGINTOP ), + HFMAP( "FooterTopBorder", XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERALL ), + HFMAP( "FooterTopBorder", XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERTOP ), + HFMAP( "FooterBottomBorder", XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERBOTTOM ), + HFMAP( "FooterLeftBorder", XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERLEFT ), + HFMAP( "FooterRightBorder", XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER, CTF_PM_FOOTERBORDERRIGHT ), + HFMAP( "FooterTopBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHALL ), + HFMAP( "FooterTopBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHTOP ), + HFMAP( "FooterBottomBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHBOTTOM ), + HFMAP( "FooterLeftBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHLEFT ), + HFMAP( "FooterRightBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_PM_FOOTERBORDERWIDTHRIGHT ), + HFMAP( "FooterTopBorderDistance", XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGALL ), + HFMAP( "FooterTopBorderDistance", XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGTOP ), + HFMAP( "FooterBottomBorderDistance", XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGBOTTOM ), + HFMAP( "FooterLeftBorderDistance", XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGLEFT ), + HFMAP( "FooterRightBorderDistance", XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE, CTF_PM_FOOTERPADDINGRIGHT ), + HFMAP( "FooterShadowFormat", XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterBackColor", XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT | MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterBackTransparent", XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT | MID_FLAG_MERGE_ATTRIBUTE, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterBackGraphicLocation", XML_NAMESPACE_STYLE, XML_POSITION, XML_TYPE_BUILDIN_CMP_ONLY | MID_FLAG_SPECIAL_ITEM, CTF_PM_FOOTERGRAPHICPOSITION ), + HFMAP( "FooterBackGraphicFilter", XML_NAMESPACE_STYLE, XML_FILTER_NAME, XML_TYPE_STRING | MID_FLAG_SPECIAL_ITEM, CTF_PM_FOOTERGRAPHICFILTER ), + HFMAP( "FooterBackGraphic", XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, XML_TYPE_STRING | MID_FLAG_ELEMENT_ITEM, CTF_PM_FOOTERGRAPHICURL ), + HFMAP( "FooterDynamicSpacing", XML_NAMESPACE_STYLE, XML_DYNAMIC_SPACING, XML_TYPE_BOOL, CTF_PM_FOOTERFLAG ), + + //Index 170: Footer DrawingLayer FillAttributes + // Use HFMAP to get XML_TYPE_PROP_HEADER_FOOTER ORed to the 4th entry + // Names have to begin with 'Footer', all 5th entries need to be ORed with the CTF_PM_FOOTERFLAG + HFMAP( "FooterFillStyle", XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillColor", XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillColor2", XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillGradientName", XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FOOTERFILLGRADIENTNAME ), + HFMAP( "FooterFillGradientStepCount", XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillHatchName", XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FOOTERFILLHATCHNAME ), + HFMAP( "FooterFillBackground", XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillBitmapName", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FOOTERFILLBITMAPNAME ), + HFMAP( "FooterFillTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), // exists in SW, too + HFMAP( "FooterFillTransparenceGradientName", XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FOOTERFILLTRANSNAME ), + HFMAP( "FooterFillBitmapSizeX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillBitmapSizeY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillBitmapMode", XML_NAMESPACE_STYLE, XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillBitmapPositionOffsetX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillBitmapPositionOffsetY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillBitmapRectanglePoint", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, CTF_PM_FOOTERFLAG ), + HFMAP( "FooterFillBitmapOffsetX", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERREPEAT_OFFSET_X ), + HFMAP( "FooterFillBitmapOffsetY", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_PM_FOOTERREPEAT_OFFSET_Y ), + + { nullptr, 0, XML_EMPTY, 0, 0, SvtSaveOptions::ODFSVER_010, false } // index 190 +}; + +XMLPropertyMapEntry const g_XMLPageMasterDrawingPageStyleMap[] = +{ + // ODF 1.3 OFFICE-3937 style of family "drawing-page" referenced from style:master-page + // duplication of relevant part of aXMLPageMasterStyleMap but as DP type + DPMAP("FillStyle", XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, CTF_PM_FILL), + DPMAP("BackgroundFullSize", XML_NAMESPACE_DRAW, XML_BACKGROUND_SIZE, XML_SW_TYPE_PRESPAGE_BACKSIZE, CTF_PM_BACKGROUNDSIZE), + DPMAP("FillColor", XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0), + DPMAP("FillColor2", XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0), + DPMAP("FillGradientName", XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLGRADIENTNAME), + DPMAP("FillGradientStepCount", XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0), + DPMAP("FillHatchName", XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLHATCHNAME), + DPMAP("FillBackground", XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0), + DPMAP("FillBitmapName", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLBITMAPNAME), + DPMAP("FillTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0), /* exists in SW, too */ + DPMAP("FillTransparenceGradientName", XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_PM_FILLTRANSNAME), + DPMAP("FillBitmapSizeX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0), + DPMAP("FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0), + DPMAP("FillBitmapSizeY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0), + DPMAP("FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0), + DPMAP("FillBitmapMode", XML_NAMESPACE_STYLE, XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, CTF_PM_FILLBITMAPMODE), + DPMAP("FillBitmapPositionOffsetX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0), + DPMAP("FillBitmapPositionOffsetY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0), + DPMAP("FillBitmapRectanglePoint", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, 0), + DPMAP("FillBitmapOffsetX", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_PM_REPEAT_OFFSET_X), + DPMAP("FillBitmapOffsetY", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_PM_REPEAT_OFFSET_Y), + + { nullptr, 0, XML_EMPTY, 0, 0, SvtSaveOptions::ODFSVER_010, false } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PagePropertySetContext.cxx b/xmloff/source/style/PagePropertySetContext.cxx new file mode 100644 index 000000000..31c541f56 --- /dev/null +++ b/xmloff/source/style/PagePropertySetContext.cxx @@ -0,0 +1,119 @@ +/* -*- 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 +#include "PagePropertySetContext.hxx" +#include +#include +#include +#include "XMLFootnoteSeparatorImport.hxx" +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +PagePropertySetContext::PagePropertySetContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + sal_uInt32 nFam, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + sal_Int32 nStartIndex, sal_Int32 nEndIndex, + const PageContextType aTempType ) : + SvXMLPropertySetContext( rImport, nElement, xAttrList, nFam, + rProps, rMap, nStartIndex, nEndIndex ) +{ + aType = aTempType; +} + +PagePropertySetContext::~PagePropertySetContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > PagePropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + sal_Int32 nPos = CTF_PM_GRAPHICPOSITION; + sal_Int32 nFil = CTF_PM_GRAPHICFILTER; + switch ( aType ) + { + case Header: + { + nPos = CTF_PM_HEADERGRAPHICPOSITION; + nFil = CTF_PM_HEADERGRAPHICFILTER; + } + break; + case Footer: + { + nPos = CTF_PM_FOOTERGRAPHICPOSITION; + nFil = CTF_PM_FOOTERGRAPHICFILTER; + } + break; + default: + break; + } + + switch( mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_PM_GRAPHICURL: + case CTF_PM_HEADERGRAPHICURL: + case CTF_PM_FOOTERGRAPHICURL: + DBG_ASSERT( rProp.mnIndex >= 2 && + nPos == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-2 ) && + nFil == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-1 ), + "invalid property map!"); + return + new XMLBackgroundImageContext( GetImport(), nElement, + xAttrList, + rProp, + rProp.mnIndex-2, + rProp.mnIndex-1, + -1, + mxMapper->getPropertySetMapper()->FindEntryIndex(CTF_PM_FILLBITMAPMODE), + rProperties ); + break; + + case CTF_PM_TEXTCOLUMNS: + return new XMLTextColumnsContext( GetImport(), nElement, + xAttrList, rProp, + rProperties ); + break; + + case CTF_PM_FTN_LINE_WEIGHT: + return new XMLFootnoteSeparatorImport( + GetImport(), nElement, rProperties, + mxMapper->getPropertySetMapper(), rProp.mnIndex); + break; + } + + return SvXMLPropertySetContext::createFastChildContext( nElement, + xAttrList, + rProperties, rProp ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/PagePropertySetContext.hxx b/xmloff/source/style/PagePropertySetContext.hxx new file mode 100644 index 000000000..2429dc194 --- /dev/null +++ b/xmloff/source/style/PagePropertySetContext.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/. + * + * 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 + +enum PageContextType +{ + Page, + Header, + Footer +}; + +class PagePropertySetContext : public SvXMLPropertySetContext +{ + PageContextType aType; + +public: + PagePropertySetContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + sal_uInt32 nFam, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + sal_Int32 nStartIndex, sal_Int32 nEndIndex, + const PageContextType aType ); + + virtual ~PagePropertySetContext() override; + + using SvXMLPropertySetContext::createFastChildContext; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/SinglePropertySetInfoCache.cxx b/xmloff/source/style/SinglePropertySetInfoCache.cxx new file mode 100644 index 000000000..1bc06ef4d --- /dev/null +++ b/xmloff/source/style/SinglePropertySetInfoCache.cxx @@ -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/. + * + * 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 +#include +#include + +using namespace ::com::sun::star::uno; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XPropertySetInfo; + +bool SinglePropertySetInfoCache::hasProperty( + const Reference< XPropertySet >& rPropSet, + Reference< XPropertySetInfo >& rPropSetInfo ) +{ + if( !rPropSetInfo.is() ) + rPropSetInfo = rPropSet->getPropertySetInfo(); + Map::iterator aIter = map_.find( rPropSetInfo ); + if( aIter != map_.end() ) + { + return (*aIter).second; + } + bool bRet = rPropSetInfo->hasPropertyByName( sName ); + // Check whether the property set info is destroyed if it is assigned to a + // weak reference only; if it is destroyed, then every instance of + // getPropertySetInfo returns a new object; Such property set infos must not + // be cached: + WeakReference < XPropertySetInfo > xWeakInfo( rPropSetInfo ); + rPropSetInfo = nullptr; + rPropSetInfo = xWeakInfo; + if( rPropSetInfo.is() ) + { + map_.emplace(rPropSetInfo, bRet); + } + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/StyleMap.cxx b/xmloff/source/style/StyleMap.cxx new file mode 100644 index 000000000..1d52ea112 --- /dev/null +++ b/xmloff/source/style/StyleMap.cxx @@ -0,0 +1,32 @@ +/* -*- 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 + +using namespace css::uno; +using namespace css::lang; + +StyleMap::StyleMap() {} + +StyleMap::~StyleMap() {} + +// XUnoTunnel & co +UNO3_GETIMPLEMENTATION_IMPL(StyleMap); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/TransGradientStyle.cxx b/xmloff/source/style/TransGradientStyle.cxx new file mode 100644 index 000000000..9b000c3eb --- /dev/null +++ b/xmloff/source/style/TransGradientStyle.cxx @@ -0,0 +1,246 @@ +/* -*- 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 + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_GradientStyle_Enum[] = +{ + { XML_LINEAR, awt::GradientStyle_LINEAR }, + { XML_GRADIENTSTYLE_AXIAL, awt::GradientStyle_AXIAL }, + { XML_GRADIENTSTYLE_RADIAL, awt::GradientStyle_RADIAL }, + { XML_GRADIENTSTYLE_ELLIPSOID, awt::GradientStyle_ELLIPTICAL }, + { XML_GRADIENTSTYLE_SQUARE, awt::GradientStyle_SQUARE }, + { XML_GRADIENTSTYLE_RECTANGULAR, awt::GradientStyle_RECT }, + { XML_TOKEN_INVALID, awt::GradientStyle(0) } +}; + +// Import + +XMLTransGradientStyleImport::XMLTransGradientStyleImport( SvXMLImport& rImp ) + : rImport(rImp) +{ +} + +void XMLTransGradientStyleImport::importXML( + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + uno::Any& rValue, + OUString& rStrName ) +{ + OUString aDisplayName; + + awt::Gradient aGradient; + aGradient.XOffset = 0; + aGradient.YOffset = 0; + aGradient.StartIntensity = 100; + aGradient.EndIntensity = 100; + aGradient.Angle = 0; + aGradient.Border = 0; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + sal_Int32 nTmpValue; + + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_NAME): + { + rStrName = aIter.toString(); + } + break; + case XML_ELEMENT(DRAW, XML_DISPLAY_NAME): + { + aDisplayName = aIter.toString(); + } + break; + case XML_ELEMENT(DRAW, XML_STYLE): + { + SvXMLUnitConverter::convertEnum( aGradient.Style, aIter.toView(), pXML_GradientStyle_Enum ); + } + break; + case XML_ELEMENT(DRAW, XML_CX): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.XOffset = sal::static_int_cast< sal_Int16 >(nTmpValue); + break; + case XML_ELEMENT(DRAW, XML_CY): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.YOffset = sal::static_int_cast< sal_Int16 >(nTmpValue); + break; + case XML_ELEMENT(DRAW, XML_START): + { + sal_Int32 aStartTransparency; + ::sax::Converter::convertPercent( aStartTransparency, aIter.toView() ); + + sal_uInt8 n = sal::static_int_cast< sal_uInt8 >( + ( (100 - aStartTransparency) * 255 ) / 100 ); + + Color aColor( n, n, n ); + aGradient.StartColor = static_cast( aColor ); + } + break; + case XML_ELEMENT(DRAW, XML_END): + { + sal_Int32 aEndTransparency; + ::sax::Converter::convertPercent( aEndTransparency, aIter.toView() ); + + sal_uInt8 n = sal::static_int_cast< sal_uInt8 >( + ( (100 - aEndTransparency) * 255 ) / 100 ); + + Color aColor( n, n, n ); + aGradient.EndColor = static_cast( aColor ); + } + break; + case XML_ELEMENT(DRAW, XML_GRADIENT_ANGLE): + { + auto const cmp12(rImport.GetODFVersion().compareTo(ODFVER_012_TEXT)); + bool const bSuccess = + ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(), + // tdf#89475 try to detect borked OOo angles + (cmp12 < 0) || (cmp12 == 0 + && (rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); + SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle"); + } + break; + case XML_ELEMENT(DRAW, XML_BORDER): + ::sax::Converter::convertPercent( nTmpValue, aIter.toView() ); + aGradient.Border = sal::static_int_cast< sal_Int16 >(nTmpValue); + break; + + default: + XMLOFF_WARN_UNKNOWN("xmloff.style", aIter); + } + } + + rValue <<= aGradient; + + if( !aDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::SD_GRADIENT_ID, rStrName, + aDisplayName ); + rStrName = aDisplayName; + } +} + +// Export + +XMLTransGradientStyleExport::XMLTransGradientStyleExport( SvXMLExport& rExp ) + : rExport(rExp) +{ +} + +void XMLTransGradientStyleExport::exportXML( + const OUString& rStrName, + const uno::Any& rValue ) +{ + awt::Gradient aGradient; + + if( rStrName.isEmpty() ) + return; + + if( !(rValue >>= aGradient) ) + return; + + OUString aStrValue; + OUStringBuffer aOut; + + // Style + if( !SvXMLUnitConverter::convertEnum( aOut, aGradient.Style, pXML_GradientStyle_Enum ) ) + return; + + // Name + bool bEncoded = false; + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + rExport.EncodeStyleName( rStrName, + &bEncoded ) ); + if( bEncoded ) + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISPLAY_NAME, + rStrName ); + + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE, aStrValue ); + + // Center x/y + if( aGradient.Style != awt::GradientStyle_LINEAR && + aGradient.Style != awt::GradientStyle_AXIAL ) + { + ::sax::Converter::convertPercent(aOut, aGradient.XOffset); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CX, aStrValue ); + + ::sax::Converter::convertPercent(aOut, aGradient.YOffset); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CY, aStrValue ); + } + + // Transparency start + Color aColor(ColorTransparency, aGradient.StartColor); + sal_Int32 aStartValue = 100 - static_cast(((aColor.GetRed() + 1) * 100) / 255); + ::sax::Converter::convertPercent( aOut, aStartValue ); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_START, aStrValue ); + + // Transparency end + aColor = Color(ColorTransparency, aGradient.EndColor); + sal_Int32 aEndValue = 100 - static_cast(((aColor.GetRed() + 1) * 100) / 255); + ::sax::Converter::convertPercent( aOut, aEndValue ); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_END, aStrValue ); + + // Angle + if( aGradient.Style != awt::GradientStyle_RADIAL ) + { + ::sax::Converter::convertAngle(aOut, aGradient.Angle, rExport.getSaneDefaultVersion()); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); + } + + // Border + ::sax::Converter::convertPercent( aOut, aGradient.Border ); + aStrValue = aOut.makeStringAndClear(); + rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_BORDER, aStrValue ); + + // Do Write + SvXMLElementExport rElem( rExport, + XML_NAMESPACE_DRAW, XML_OPACITY, + true, false ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/WordWrapPropertyHdl.cxx b/xmloff/source/style/WordWrapPropertyHdl.cxx new file mode 100644 index 000000000..0a01bd11d --- /dev/null +++ b/xmloff/source/style/WordWrapPropertyHdl.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/. + * + * 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 +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star::uno; + + + + +XMLWordWrapPropertyHdl::XMLWordWrapPropertyHdl( SvXMLImport* pImport ) +: mpImport( pImport ) +{ +} + +XMLWordWrapPropertyHdl::~XMLWordWrapPropertyHdl() +{ + // Nothing to do +} + +bool XMLWordWrapPropertyHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRetValue = false; + bool bValue = false; + if( rStrImpValue == GetXMLToken( xmloff::token::XML_WRAP ) ) + { + bValue = true; + bRetValue = true; + } + if( rStrImpValue == GetXMLToken( xmloff::token::XML_NO_WRAP ) ) + { + bValue = false; + bRetValue = true; + } + if ( bRetValue && mpImport ) + { + sal_Int32 nUPD, nBuildId; + if( mpImport->getBuildIds( nUPD, nBuildId ) ) + { + if( nUPD == 300 ) + { + if( ( nBuildId > 0 ) && (nBuildId < 9316 ) ) + bValue = !bValue; // treat OOo 3.0 beta1 as OOo 2.x + } + else if( ( nUPD == 680 ) || ( nUPD >= 640 && nUPD <= 645 ) ) + bValue = !bValue; + } + rValue <<= bValue; + } + return bRetValue; +} + +bool XMLWordWrapPropertyHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + if( ::cppu::any2bool( rValue ) ) + { + rStrExpValue = GetXMLToken( xmloff::token::XML_WRAP ); + } + else + { + rStrExpValue = GetXMLToken( xmloff::token::XML_NO_WRAP ); + } + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLBackgroundImageContext.cxx b/xmloff/source/style/XMLBackgroundImageContext.cxx new file mode 100644 index 000000000..cd500672c --- /dev/null +++ b/xmloff/source/style/XMLBackgroundImageContext.cxx @@ -0,0 +1,397 @@ +/* -*- 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 +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::io; +using namespace ::xmloff::token; + +const SvXMLEnumMapEntry psXML_BrushHoriPos[] = +{ + { XML_LEFT, GraphicLocation_LEFT_MIDDLE }, + { XML_RIGHT, GraphicLocation_RIGHT_MIDDLE }, + { XML_TOKEN_INVALID, GraphicLocation(0) } +}; + +const SvXMLEnumMapEntry psXML_BrushVertPos[] = +{ + { XML_TOP, GraphicLocation_MIDDLE_TOP }, + { XML_BOTTOM, GraphicLocation_MIDDLE_BOTTOM }, + { XML_TOKEN_INVALID, GraphicLocation(0) } +}; + +static void lcl_xmlbic_MergeHoriPos( GraphicLocation& ePos, + GraphicLocation eHori ) +{ + DBG_ASSERT( GraphicLocation_LEFT_MIDDLE==eHori || + GraphicLocation_MIDDLE_MIDDLE==eHori || + GraphicLocation_RIGHT_MIDDLE==eHori, + "lcl_xmlbic_MergeHoriPos: vertical pos must be middle" ); + + switch( ePos ) + { + case GraphicLocation_LEFT_TOP: + case GraphicLocation_MIDDLE_TOP: + case GraphicLocation_RIGHT_TOP: + ePos = GraphicLocation_LEFT_MIDDLE==eHori + ? GraphicLocation_LEFT_TOP + : (GraphicLocation_MIDDLE_MIDDLE==eHori + ? GraphicLocation_MIDDLE_TOP + : GraphicLocation_RIGHT_TOP); + break; + + case GraphicLocation_LEFT_MIDDLE: + case GraphicLocation_MIDDLE_MIDDLE: + case GraphicLocation_RIGHT_MIDDLE: + ePos = eHori; + break; + + case GraphicLocation_LEFT_BOTTOM: + case GraphicLocation_MIDDLE_BOTTOM: + case GraphicLocation_RIGHT_BOTTOM: + ePos = GraphicLocation_LEFT_MIDDLE==eHori + ? GraphicLocation_LEFT_BOTTOM + : (GraphicLocation_MIDDLE_MIDDLE==eHori + ? GraphicLocation_MIDDLE_BOTTOM + : GraphicLocation_RIGHT_BOTTOM); + break; + default: + break; + } +} + +static void lcl_xmlbic_MergeVertPos( GraphicLocation& ePos, + GraphicLocation eVert ) +{ + DBG_ASSERT( GraphicLocation_MIDDLE_TOP==eVert || + GraphicLocation_MIDDLE_MIDDLE==eVert || + GraphicLocation_MIDDLE_BOTTOM==eVert, + "lcl_xmlbic_MergeVertPos: horizontal pos must be middle" ); + + switch( ePos ) + { + case GraphicLocation_LEFT_TOP: + case GraphicLocation_LEFT_MIDDLE: + case GraphicLocation_LEFT_BOTTOM: + ePos = GraphicLocation_MIDDLE_TOP==eVert + ? GraphicLocation_LEFT_TOP + : (GraphicLocation_MIDDLE_MIDDLE==eVert + ? GraphicLocation_LEFT_MIDDLE + : GraphicLocation_LEFT_BOTTOM); + break; + + case GraphicLocation_MIDDLE_TOP: + case GraphicLocation_MIDDLE_MIDDLE: + case GraphicLocation_MIDDLE_BOTTOM: + ePos = eVert; + break; + + case GraphicLocation_RIGHT_TOP: + case GraphicLocation_RIGHT_MIDDLE: + case GraphicLocation_RIGHT_BOTTOM: + ePos = GraphicLocation_MIDDLE_TOP==eVert + ? GraphicLocation_RIGHT_TOP + : (GraphicLocation_MIDDLE_MIDDLE==eVert + ? GraphicLocation_RIGHT_MIDDLE + : GraphicLocation_RIGHT_BOTTOM); + break; + default: + break; + } +} + + +void XMLBackgroundImageContext::ProcessAttrs( + const Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + ePos = GraphicLocation_NONE; + + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + m_sURL = aIter.toString(); + if( GraphicLocation_NONE == ePos ) + ePos = GraphicLocation_TILED; + break; + case XML_ELEMENT(XLINK, XML_TYPE): + case XML_ELEMENT(XLINK, XML_ACTUATE): + case XML_ELEMENT(XLINK, XML_SHOW): + break; + case XML_ELEMENT(STYLE, XML_POSITION): + { + GraphicLocation eNewPos = GraphicLocation_NONE, eTmp; + OUString sValue = aIter.toString(); + SvXMLTokenEnumerator aTokenEnum( sValue ); + std::u16string_view aToken; + bool bHori = false, bVert = false; + bool bOK = true; + while( bOK && aTokenEnum.getNextToken( aToken ) ) + { + GraphicLocation nTmpGraphicLocation; + if( bHori && bVert ) + { + bOK = false; + } + else if( std::u16string_view::npos != aToken.find( '%' ) ) + { + sal_Int32 nPrc = 50; + if (::sax::Converter::convertPercent( nPrc, aToken )) + { + if( !bHori ) + { + eNewPos = nPrc < 25 + ? GraphicLocation_LEFT_TOP + : (nPrc < 75 ? GraphicLocation_MIDDLE_MIDDLE + : GraphicLocation_RIGHT_BOTTOM); + bHori = true; + } + else + { + eTmp = nPrc < 25 + ? GraphicLocation_LEFT_TOP + : (nPrc < 75 ? GraphicLocation_LEFT_MIDDLE + : GraphicLocation_LEFT_BOTTOM); + lcl_xmlbic_MergeVertPos( eNewPos, eTmp ); + bVert = true; + } + } + else + { + // wrong percentage + bOK = false; + } + } + else if( IsXMLToken( aToken, XML_CENTER ) ) + { + if( bHori ) + lcl_xmlbic_MergeVertPos( eNewPos, + GraphicLocation_MIDDLE_MIDDLE ); + else if ( bVert ) + lcl_xmlbic_MergeHoriPos( eNewPos, + GraphicLocation_MIDDLE_MIDDLE ); + else + eNewPos = GraphicLocation_MIDDLE_MIDDLE; + } + else if( SvXMLUnitConverter::convertEnum( nTmpGraphicLocation, aToken, + psXML_BrushHoriPos ) ) + { + if( bVert ) + lcl_xmlbic_MergeHoriPos( eNewPos, nTmpGraphicLocation ); + else if( !bHori ) + eNewPos = nTmpGraphicLocation; + else + bOK = false; + bHori = true; + } + else if( SvXMLUnitConverter::convertEnum( nTmpGraphicLocation, aToken, + psXML_BrushVertPos ) ) + { + if( bHori ) + lcl_xmlbic_MergeVertPos( eNewPos, nTmpGraphicLocation ); + else if( !bVert ) + eNewPos = nTmpGraphicLocation; + else + bOK = false; + bVert = true; + } + else + { + bOK = false; + } + } + + bOK &= GraphicLocation_NONE != eNewPos; + if( bOK ) + ePos = eNewPos; + } + break; + case XML_ELEMENT(STYLE, XML_REPEAT): + { + GraphicLocation nPos = GraphicLocation_NONE; + static const SvXMLEnumMapEntry psXML_BrushRepeat[] = + { + { XML_REPEAT, GraphicLocation_TILED }, + { XML_BACKGROUND_NO_REPEAT, GraphicLocation_MIDDLE_MIDDLE }, + { XML_STRETCH, GraphicLocation_AREA }, + { XML_TOKEN_INVALID, GraphicLocation(0) } + }; + if( SvXMLUnitConverter::convertEnum( nPos, aIter.toView(), + psXML_BrushRepeat ) ) + { + if( GraphicLocation_MIDDLE_MIDDLE != nPos || + GraphicLocation_NONE == ePos || + GraphicLocation_AREA == ePos || + GraphicLocation_TILED == ePos ) + ePos = nPos; + } + } + break; + case XML_ELEMENT(STYLE, XML_FILTER_NAME): + sFilter = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_OPACITY): + { + sal_Int32 nTmp; + // convert from percent and clip + if (::sax::Converter::convertPercent( nTmp, aIter.toView() )) + { + if( (nTmp >= 0) && (nTmp <= 100) ) + nTransparency = static_cast( 100-nTmp ); + } + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + +} + +XMLBackgroundImageContext::XMLBackgroundImageContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + const XMLPropertyState& rProp, + sal_Int32 nPosIdx, + sal_Int32 nFilterIdx, + sal_Int32 nTransparencyIdx, + sal_Int32 nBitmapModeIdx, + ::std::vector< XMLPropertyState > &rProps ) : + XMLElementPropertyContext( rImport, nElement, rProp, rProps ), + aPosProp( nPosIdx ), + m_nBitmapModeIdx(nBitmapModeIdx), + aFilterProp( nFilterIdx ), + aTransparencyProp( nTransparencyIdx ), + nTransparency( 0 ) +{ + ProcessAttrs( xAttrList ); +} + +XMLBackgroundImageContext::~XMLBackgroundImageContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLBackgroundImageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + if( nElement == XML_ELEMENT(OFFICE, xmloff::token::XML_BINARY_DATA) ) + { + if( m_sURL.isEmpty() && !m_xBase64Stream.is() ) + { + m_xBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( m_xBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), m_xBase64Stream ); + } + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLBackgroundImageContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference xGraphic; + if (!m_sURL.isEmpty()) + { + xGraphic = GetImport().loadGraphicByURL(m_sURL); + } + else if (m_xBase64Stream.is()) + { + xGraphic = GetImport().loadGraphicFromBase64(m_xBase64Stream); + m_xBase64Stream = nullptr; + } + + if (!xGraphic.is()) + ePos = GraphicLocation_NONE; + else if (GraphicLocation_NONE == ePos) + ePos = GraphicLocation_TILED; + + if (xGraphic.is()) + aProp.maValue <<= xGraphic; + aPosProp.maValue <<= ePos; + aFilterProp.maValue <<= sFilter; + aTransparencyProp.maValue <<= nTransparency; + + SetInsert( true ); + XMLElementPropertyContext::endFastElement(nElement); + + if( -1 != aPosProp.mnIndex ) + { + // See if a FillBitmapMode property is already set, in that case + // BackGraphicLocation will be ignored. + bool bFound = false; + if (m_nBitmapModeIdx != -1) + { + for (XMLPropertyState& rProperty : rProperties) + { + if (rProperty.mnIndex == m_nBitmapModeIdx) + { + bFound = true; + + // Found, so map the old property to the new one. + switch (ePos) + { + case GraphicLocation_TILED: + rProperty.maValue <<= drawing::BitmapMode_REPEAT; + break; + case GraphicLocation_AREA: + rProperty.maValue <<= drawing::BitmapMode_STRETCH; + break; + case GraphicLocation_MIDDLE_MIDDLE: + rProperty.maValue <<= drawing::BitmapMode_NO_REPEAT; + break; + default: + break; + } + break; + } + } + } + if (!bFound) + rProperties.push_back( aPosProp ); + } + if( -1 != aFilterProp.mnIndex ) + rProperties.push_back( aFilterProp ); + if( -1 != aTransparencyProp.mnIndex ) + rProperties.push_back( aTransparencyProp ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLBackgroundImageExport.cxx b/xmloff/source/style/XMLBackgroundImageExport.cxx new file mode 100644 index 000000000..c3ae8748a --- /dev/null +++ b/xmloff/source/style/XMLBackgroundImageExport.cxx @@ -0,0 +1,165 @@ +/* -*- 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 +#include + +#include + +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + +XMLBackgroundImageExport::XMLBackgroundImageExport( SvXMLExport& rExp ) : + rExport( rExp ) +{ +} + +void XMLBackgroundImageExport::exportXML( const Any& rGraphicAny, + const Any *pPos, + const Any *pFilter, + const Any *pTransparency, + sal_uInt16 nPrefix, + const OUString& rLocalName ) +{ + GraphicLocation ePos; + if( !(pPos && ((*pPos) >>= ePos)) ) + ePos = GraphicLocation_AREA; + + uno::Reference xGraphic; + if (rGraphicAny.has>()) + xGraphic = rGraphicAny.get>(); + + if (xGraphic.is() && GraphicLocation_NONE != ePos) + { + OUString sUsedMimeType; + OUString sInternalURL(GetExport().AddEmbeddedXGraphic(xGraphic, sUsedMimeType)); + + if (!sInternalURL.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + + OUStringBuffer aOut; + switch( ePos ) + { + case GraphicLocation_LEFT_TOP: + case GraphicLocation_MIDDLE_TOP: + case GraphicLocation_RIGHT_TOP: + aOut.append( GetXMLToken(XML_TOP) ); + break; + case GraphicLocation_LEFT_MIDDLE: + case GraphicLocation_MIDDLE_MIDDLE: + case GraphicLocation_RIGHT_MIDDLE: + aOut.append( GetXMLToken(XML_CENTER) ); + break; + case GraphicLocation_LEFT_BOTTOM: + case GraphicLocation_MIDDLE_BOTTOM: + case GraphicLocation_RIGHT_BOTTOM: + aOut.append( GetXMLToken(XML_BOTTOM) ); + break; + default: + break; + } + + if( !aOut.isEmpty() ) + { + aOut.append( ' ' ); + + switch( ePos ) + { + case GraphicLocation_LEFT_TOP: + case GraphicLocation_LEFT_BOTTOM: + case GraphicLocation_LEFT_MIDDLE: + aOut.append( GetXMLToken(XML_LEFT) ); + break; + case GraphicLocation_MIDDLE_TOP: + case GraphicLocation_MIDDLE_MIDDLE: + case GraphicLocation_MIDDLE_BOTTOM: + aOut.append( GetXMLToken(XML_CENTER) ); + break; + case GraphicLocation_RIGHT_MIDDLE: + case GraphicLocation_RIGHT_TOP: + case GraphicLocation_RIGHT_BOTTOM: + aOut.append( GetXMLToken(XML_RIGHT) ); + break; + default: + break; + } + } + if( !aOut.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_POSITION, aOut.makeStringAndClear() ); + + if( GraphicLocation_AREA == ePos ) + { + aOut.append( GetXMLToken(XML_STRETCH) ); + } + else if( GraphicLocation_NONE != ePos && GraphicLocation_TILED != ePos ) + { + aOut.append( GetXMLToken(XML_BACKGROUND_NO_REPEAT) ); + } + if( !aOut.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REPEAT, + aOut.makeStringAndClear() ); + + if( pFilter ) + { + OUString sFilter; + (*pFilter) >>= sFilter; + if( !sFilter.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_FILTER_NAME, + sFilter ); + } + + if( pTransparency ) + { + sal_Int8 nTransparency = sal_Int8(); + if( (*pTransparency) >>= nTransparency ) + { + OUStringBuffer aTransOut; + ::sax::Converter::convertPercent(aTransOut, 100-nTransparency); + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_OPACITY, + aTransOut.makeStringAndClear() ); + } + } + } + + { + SvXMLElementExport aElem(GetExport(), nPrefix, rLocalName, true, true); + if (xGraphic.is() && GraphicLocation_NONE != ePos) + { + // optional office:binary-data + GetExport().AddEmbeddedXGraphicAsBase64(xGraphic); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLBitmapLogicalSizePropertyHandler.cxx b/xmloff/source/style/XMLBitmapLogicalSizePropertyHandler.cxx new file mode 100644 index 000000000..92d409e8a --- /dev/null +++ b/xmloff/source/style/XMLBitmapLogicalSizePropertyHandler.cxx @@ -0,0 +1,53 @@ +/* -*- 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 +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLBitmapLogicalSizePropertyHandler::XMLBitmapLogicalSizePropertyHandler() +{ +} + +XMLBitmapLogicalSizePropertyHandler::~XMLBitmapLogicalSizePropertyHandler() +{ +} + +bool XMLBitmapLogicalSizePropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + rValue <<= ( rStrImpValue.indexOf( '%' ) == -1 ); + return true; +} + +bool XMLBitmapLogicalSizePropertyHandler::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLBitmapRepeatOffsetPropertyHandler.cxx b/xmloff/source/style/XMLBitmapRepeatOffsetPropertyHandler.cxx new file mode 100644 index 000000000..29e743dfa --- /dev/null +++ b/xmloff/source/style/XMLBitmapRepeatOffsetPropertyHandler.cxx @@ -0,0 +1,94 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +using ::xmloff::token::GetXMLToken; +using ::xmloff::token::XML_VERTICAL; +using ::xmloff::token::XML_HORIZONTAL; + + +XMLBitmapRepeatOffsetPropertyHandler::XMLBitmapRepeatOffsetPropertyHandler( bool bX ) +: mbX( bX ), + msVertical( GetXMLToken(XML_VERTICAL) ), + msHorizontal( GetXMLToken(XML_HORIZONTAL) ) +{ +} + +XMLBitmapRepeatOffsetPropertyHandler::~XMLBitmapRepeatOffsetPropertyHandler() +{ +} + +bool XMLBitmapRepeatOffsetPropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + std::u16string_view aToken; + if( aTokenEnum.getNextToken( aToken ) ) + { + sal_Int32 nValue; + if (::sax::Converter::convertPercent( nValue, aToken )) + { + if( aTokenEnum.getNextToken( aToken ) ) + { + if( ( mbX && ( aToken == msHorizontal ) ) || ( !mbX && ( aToken == msVertical ) ) ) + { + rValue <<= nValue; + return true; + } + } + } + } + + return false; + +} + +bool XMLBitmapRepeatOffsetPropertyHandler::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + aOut.append( ' ' ); + aOut.append( mbX ? msHorizontal : msVertical ); + rStrExpValue = aOut.makeStringAndClear(); + + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLClipPropertyHandler.cxx b/xmloff/source/style/XMLClipPropertyHandler.cxx new file mode 100644 index 000000000..4bfa563d2 --- /dev/null +++ b/xmloff/source/style/XMLClipPropertyHandler.cxx @@ -0,0 +1,141 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + + + + +XMLClipPropertyHandler::XMLClipPropertyHandler( bool bODF11 ) : + m_bODF11( bODF11 ) +{ +} + +XMLClipPropertyHandler::~XMLClipPropertyHandler() +{ + // nothing to do +} + +bool XMLClipPropertyHandler::equals( + const Any& r1, + const Any& r2 ) const +{ + GraphicCrop aCrop1, aCrop2; + r1 >>= aCrop1; + r2 >>= aCrop2; + + return aCrop1.Top == aCrop2.Top && + aCrop1.Bottom == aCrop2.Bottom && + aCrop1.Left == aCrop2.Left && + aCrop1.Right == aCrop2.Right; +} + +bool XMLClipPropertyHandler::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int32 nLen = rStrImpValue.getLength(); + if( nLen > 6 && + rStrImpValue.startsWith( GetXMLToken(XML_RECT)) && + rStrImpValue[4] == '(' && + rStrImpValue[nLen-1] == ')' ) + { + GraphicCrop aCrop; + OUString sTmp( rStrImpValue.copy( 5, nLen-6 ) ); + + bool bHasComma = sTmp.indexOf( ',' ) != -1; + SvXMLTokenEnumerator aTokenEnum( sTmp, bHasComma ? ',' : ' ' ); + + sal_uInt16 nPos = 0; + std::u16string_view aToken; + while( aTokenEnum.getNextToken( aToken ) ) + { + sal_Int32 nVal = 0; + if( !IsXMLToken(aToken, XML_AUTO) && + !rUnitConverter.convertMeasureToCore( nVal, aToken ) ) + break; + + // fdo#80009 such nonsense could be written via WW8 import fdo#77454 + if (abs(nVal) > 400000) + { + SAL_INFO("xmloff.style", "ignoring excessive clip " << OUString(aToken)); + nVal = 0; + } + + switch( nPos ) + { + case 0: aCrop.Top = nVal; break; + case 1: aCrop.Right = nVal; break; + case 2: aCrop.Bottom = nVal; break; + case 3: aCrop.Left = nVal; break; + } + nPos++; + } + + bRet = (4 == nPos ); + if( bRet ) + rValue <<= aCrop; + } + + return bRet; +} + +bool XMLClipPropertyHandler::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + OUStringBuffer aOut(30); + GraphicCrop aCrop; + + if( rValue >>= aCrop ) + { + aOut.append( GetXMLToken(XML_RECT) ); + aOut.append( '(' ); + rUnitConverter.convertMeasureToXML( aOut, aCrop.Top ); + if( !m_bODF11 ) + aOut.append( ',' ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aCrop.Right ); + if( !m_bODF11 ) + aOut.append( ',' ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aCrop.Bottom ); + if( !m_bODF11 ) + aOut.append( ',' ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aCrop.Left ); + aOut.append( ')' ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLConstantsPropertyHandler.cxx b/xmloff/source/style/XMLConstantsPropertyHandler.cxx new file mode 100644 index 000000000..a5467f247 --- /dev/null +++ b/xmloff/source/style/XMLConstantsPropertyHandler.cxx @@ -0,0 +1,91 @@ +/* -*- 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 +#include +#include +#include +#include + +using namespace ::com::sun::star::uno; + +XMLConstantsPropertyHandler::~XMLConstantsPropertyHandler() +{ +} + +bool XMLConstantsPropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_uInt16 nEnum; + bool bRet = SvXMLUnitConverter::convertEnum( + nEnum, rStrImpValue, pMap ); + + if( bRet ) + rValue <<= static_cast(nEnum); + + return bRet; +} + +bool XMLConstantsPropertyHandler::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + sal_Int32 nEnum = 0; + + if( rValue.hasValue() && (rValue.getValueTypeClass() == TypeClass_ENUM)) + { + nEnum = *static_cast(rValue.getValue()); + bRet = true; + } + else + { + bRet = (rValue >>= nEnum ); + } + + if( bRet ) + { + if( (nEnum >= 0) && (nEnum <= 0xffff) ) + { + sal_uInt16 nConst = static_cast( nEnum ); + OUStringBuffer aOut; + + bRet = SvXMLUnitConverter::convertEnum( + aOut, nConst, pMap, eDefault ); + + rStrExpValue = aOut.makeStringAndClear(); + } + else + { + OSL_FAIL("XMLConstantsPropertyHandler::exportXML() constant is out of range for implementation using sal_uInt16"); + } + } + else + { + OSL_FAIL("XMLConstantsPropertyHandler::exportXML() could not convert any to sal_Int32"); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLElementPropertyContext.cxx b/xmloff/source/style/XMLElementPropertyContext.cxx new file mode 100644 index 000000000..f065e081d --- /dev/null +++ b/xmloff/source/style/XMLElementPropertyContext.cxx @@ -0,0 +1,44 @@ +/* -*- 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 + + +XMLElementPropertyContext::XMLElementPropertyContext ( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ) : + SvXMLImportContext( rImport ), + bInsert( false ), + rProperties( rProps ), + aProp( rProp ) +{ +} + +XMLElementPropertyContext::~XMLElementPropertyContext() +{ +} + +void XMLElementPropertyContext::endFastElement(sal_Int32 ) +{ + if( bInsert ) + rProperties.push_back( aProp ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFillBitmapSizePropertyHandler.cxx b/xmloff/source/style/XMLFillBitmapSizePropertyHandler.cxx new file mode 100644 index 000000000..4dded1859 --- /dev/null +++ b/xmloff/source/style/XMLFillBitmapSizePropertyHandler.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/. + * + * 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 +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLFillBitmapSizePropertyHandler::XMLFillBitmapSizePropertyHandler() +{ +} + +XMLFillBitmapSizePropertyHandler::~XMLFillBitmapSizePropertyHandler() +{ +} + +bool XMLFillBitmapSizePropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int32 nValue; + bool bRet; + + if( rStrImpValue.indexOf( '%' ) != -1 ) + { + bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + nValue *= -1; + } + else + { + bRet = rUnitConverter.convertMeasureToCore( nValue, rStrImpValue ); + } + + if( bRet ) + rValue <<= nValue; + + return bRet; +} + +bool XMLFillBitmapSizePropertyHandler::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + if( nValue < 0 ) + { + ::sax::Converter::convertPercent( aOut, -nValue ); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, nValue ); + } + + rStrExpValue = aOut.makeStringAndClear(); + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFontAutoStylePool.cxx b/xmloff/source/style/XMLFontAutoStylePool.cxx new file mode 100644 index 000000000..543b3670f --- /dev/null +++ b/xmloff/source/style/XMLFontAutoStylePool.cxx @@ -0,0 +1,680 @@ +/* -*- 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 +#include +#include +#include +#include +#include "fonthdl.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +namespace { + +class XMLFontAutoStylePoolEntry_Impl +{ + OUString sName; + OUString sFamilyName; + OUString sStyleName; + FontFamily nFamily; + FontPitch nPitch; + rtl_TextEncoding eEnc; + +public: + + inline XMLFontAutoStylePoolEntry_Impl( + const OUString& rName, + const OUString& rFamilyName, + const OUString& rStyleName, + FontFamily nFamily, + FontPitch nPitch, + rtl_TextEncoding eEnc ); + + inline XMLFontAutoStylePoolEntry_Impl( + const OUString& rFamilyName, + const OUString& rStyleName, + FontFamily nFamily, + FontPitch nPitch, + rtl_TextEncoding eEnc ); + + const OUString& GetName() const { return sName; } + const OUString& GetFamilyName() const { return sFamilyName; } + const OUString& GetStyleName() const { return sStyleName; } + FontFamily GetFamily() const { return nFamily; } + FontPitch GetPitch() const { return nPitch; } + rtl_TextEncoding GetEncoding() const { return eEnc; } +}; + +} + +inline XMLFontAutoStylePoolEntry_Impl::XMLFontAutoStylePoolEntry_Impl( + const OUString& rName, + const OUString& rFamilyName, + const OUString& rStyleName, + FontFamily nFam, + FontPitch nP, + rtl_TextEncoding eE ) : + sName( rName ), + sFamilyName( rFamilyName ), + sStyleName( rStyleName ), + nFamily( nFam ), + nPitch( nP ), + eEnc( eE ) +{ +} + +inline XMLFontAutoStylePoolEntry_Impl::XMLFontAutoStylePoolEntry_Impl( + const OUString& rFamilyName, + const OUString& rStyleName, + FontFamily nFam, + FontPitch nP, + rtl_TextEncoding eE ) : + sFamilyName( rFamilyName ), + sStyleName( rStyleName ), + nFamily( nFam ), + nPitch( nP ), + eEnc( eE ) +{ +} + +namespace { + +struct XMLFontAutoStylePoolEntryCmp_Impl { + bool operator()( + std::unique_ptr const& r1, + std::unique_ptr const& r2 ) const + { + bool bEnc1(r1->GetEncoding() != RTL_TEXTENCODING_SYMBOL); + bool bEnc2(r2->GetEncoding() != RTL_TEXTENCODING_SYMBOL); + if( bEnc1 != bEnc2 ) + return bEnc1 < bEnc2; + else if( r1->GetPitch() != r2->GetPitch() ) + return r1->GetPitch() < r2->GetPitch(); + else if( r1->GetFamily() != r2->GetFamily() ) + return r1->GetFamily() < r2->GetFamily(); + else + { + sal_Int32 nCmp = r1->GetFamilyName().compareTo( r2->GetFamilyName() ); + if( 0 == nCmp ) + return r1->GetStyleName().compareTo( r2->GetStyleName() ) < 0; + else + return nCmp < 0; + } + } +}; + +} + +class XMLFontAutoStylePool_Impl : public o3tl::sorted_vector, XMLFontAutoStylePoolEntryCmp_Impl> +{ +}; + +XMLFontAutoStylePool::XMLFontAutoStylePool(SvXMLExport& rExp, bool bTryToEmbedFonts) : + rExport( rExp ), + m_pFontAutoStylePool( new XMLFontAutoStylePool_Impl ), + m_bTryToEmbedFonts( bTryToEmbedFonts ), + m_bEmbedUsedOnly(false), + m_bEmbedLatinScript(true), + m_bEmbedAsianScript(true), + m_bEmbedComplexScript(true) +{ +} + +XMLFontAutoStylePool::~XMLFontAutoStylePool() +{ +} + +OUString XMLFontAutoStylePool::Add( + const OUString& rFamilyName, + const OUString& rStyleName, + FontFamily nFamily, + FontPitch nPitch, + rtl_TextEncoding eEnc ) +{ + OUString sPoolName; + XMLFontAutoStylePoolEntry_Impl aTmp( rFamilyName, rStyleName, nFamily, + nPitch, eEnc ); + XMLFontAutoStylePool_Impl::const_iterator it = m_pFontAutoStylePool->find( &aTmp ); + if( it != m_pFontAutoStylePool->end() ) + { + sPoolName = (*it)->GetName(); + } + else + { + OUString sName; + sal_Int32 nLen = rFamilyName.indexOf( ';' ); + if( -1 == nLen ) + { + sName = rFamilyName; + } + else if( nLen > 0 ) + { + sName = rFamilyName.copy( 0, nLen ); + sName = sName.trim(); + } + + if( sName.isEmpty() ) + sName = "F"; + + if( m_aNames.find(sName) != m_aNames.end() ) + { + sal_Int32 nCount = 1; + OUString sPrefix( sName ); + sName = sPrefix + OUString::number( nCount ); + while( m_aNames.find(sName) != m_aNames.end() ) + { + sName = sPrefix + OUString::number( ++nCount ); + } + } + + std::unique_ptr pEntry( + new XMLFontAutoStylePoolEntry_Impl( sName, rFamilyName, rStyleName, + nFamily, nPitch, eEnc )); + m_pFontAutoStylePool->insert( std::move(pEntry) ); + m_aNames.insert(sName); + } + + return sPoolName; +} + +OUString XMLFontAutoStylePool::Find( + const OUString& rFamilyName, + const OUString& rStyleName, + FontFamily nFamily, + FontPitch nPitch, + rtl_TextEncoding eEnc ) const +{ + OUString sName; + XMLFontAutoStylePoolEntry_Impl aTmp( rFamilyName, rStyleName, nFamily, + nPitch, eEnc ); + XMLFontAutoStylePool_Impl::const_iterator it = m_pFontAutoStylePool->find( &aTmp ); + if( it != m_pFontAutoStylePool->end() ) + { + sName = (*it)->GetName(); + } + + return sName; +} + +namespace +{ + +OUString lcl_checkFontFile( const OUString &fileUrl ) +{ + osl::DirectoryItem aDirItem; + if( osl::DirectoryItem::get( fileUrl, aDirItem ) == osl::File::E_None ) + { + osl::FileStatus aStatus( osl_FileStatus_Mask_Type ); + if( aDirItem.getFileStatus( aStatus ) == osl::File::E_None ) + { + if( !aStatus.isDirectory() ) + return fileUrl; + } + } + return OUString(); +} + +/// Contains information about a single variant of an embedded font. +struct EmbeddedFontInfo +{ + OUString aURL; + FontWeight eWeight = WEIGHT_NORMAL; + FontItalic eItalic = ITALIC_NONE; +}; + +/// Converts FontWeight to CSS-compatible string representation. +OUString FontWeightToString(FontWeight eWeight) +{ + OUString aRet; + + switch (eWeight) + { + case WEIGHT_BOLD: + aRet = "bold"; + break; + default: + aRet = "normal"; + break; + } + + return aRet; +} + +/// Converts FontItalic to CSS-compatible string representation. +OUString FontItalicToString(FontItalic eWeight) +{ + OUString aRet; + + switch (eWeight) + { + case ITALIC_NORMAL: + aRet = "italic"; + break; + default: + aRet = "normal"; + break; + } + + return aRet; +} + +} + +std::unordered_set XMLFontAutoStylePool::getUsedFontList() +{ + std::unordered_set aReturnSet; + + uno::Reference xFamiliesSupp(GetExport().GetModel(), UNO_QUERY); + if (!xFamiliesSupp.is()) + return aReturnSet; + + // Check styles first + uno::Reference xFamilies(xFamiliesSupp->getStyleFamilies()); + if (xFamilies.is()) + { + const uno::Sequence aFamilyNames = xFamilies->getElementNames(); + for (OUString const & sFamilyName : aFamilyNames) + { + uno::Reference xStyleContainer; + xFamilies->getByName(sFamilyName) >>= xStyleContainer; + + if (xStyleContainer.is()) + { + const uno::Sequence aStyleNames = xStyleContainer->getElementNames(); + for (OUString const & rName : aStyleNames) + { + uno::Reference xStyle; + xStyleContainer->getByName(rName) >>= xStyle; + if (xStyle->isInUse()) + { + uno::Reference xPropertySet(xStyle, UNO_QUERY); + if (xPropertySet.is()) + { + uno::Reference xInfo(xPropertySet->getPropertySetInfo()); + if (m_bEmbedLatinScript && xInfo->hasPropertyByName("CharFontName")) + { + OUString sCharFontName; + Any aFontAny = xPropertySet->getPropertyValue("CharFontName"); + aFontAny >>= sCharFontName; + if (!sCharFontName.isEmpty()) + aReturnSet.insert(sCharFontName); + } + if (m_bEmbedAsianScript && xInfo->hasPropertyByName("CharFontNameAsian")) + { + OUString sCharFontNameAsian; + Any aFontAny = xPropertySet->getPropertyValue("CharFontNameAsian"); + aFontAny >>= sCharFontNameAsian; + if (!sCharFontNameAsian.isEmpty()) + aReturnSet.insert(sCharFontNameAsian); + } + if (m_bEmbedComplexScript && xInfo->hasPropertyByName("CharFontNameComplex")) + { + OUString sCharFontNameComplex; + Any aFontAny = xPropertySet->getPropertyValue("CharFontNameComplex"); + aFontAny >>= sCharFontNameComplex; + if (!sCharFontNameComplex.isEmpty()) + aReturnSet.insert(sCharFontNameComplex); + } + } + } + } + } + } + } + + // make sure auto-styles are collected + GetExport().collectAutoStyles(); + + // Check auto-styles for fonts + std::vector aAutoStyleEntries = GetExport().GetAutoStylePool()->GetAutoStyleEntries(); + for (auto const & rAutoStyleEntry : aAutoStyleEntries) + { + for (auto const & rPair : rAutoStyleEntry.m_aXmlProperties) + { + if (rPair.first == "font-name" || + rPair.first == "font-weight-asian" || + rPair.first == "font-weight-complex") + { + if (rPair.second.has()) + { + OUString sFontName = rPair.second.get(); + if (!sFontName.isEmpty()) + aReturnSet.insert(sFontName); + } + } + } + } + + return aReturnSet; +} + +void XMLFontAutoStylePool::exportXML() +{ + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_OFFICE, + XML_FONT_FACE_DECLS, + true, true); + Any aAny; + OUString sTmp; + XMLFontFamilyNamePropHdl aFamilyNameHdl; + XMLFontFamilyPropHdl aFamilyHdl; + XMLFontPitchPropHdl aPitchHdl; + XMLFontEncodingPropHdl aEncHdl; + const SvXMLUnitConverter& rUnitConv = GetExport().GetMM100UnitConverter(); + + std::map fontFilesMap; // our url to document url + + std::unordered_set aUsedFontNames; + if (m_bEmbedUsedOnly) + aUsedFontNames = getUsedFontList(); + + // Sort elements based on their style:name attribute. + std::vector aFontAutoStyles; + for (const auto& pEntry : *m_pFontAutoStylePool) + { + aFontAutoStyles.push_back(pEntry.get()); + } + std::sort( + aFontAutoStyles.begin(), aFontAutoStyles.end(), + [](const XMLFontAutoStylePoolEntry_Impl* pA, XMLFontAutoStylePoolEntry_Impl* pB) -> bool { + return pA->GetName() < pB->GetName(); + }); + + for (const auto& pEntry : aFontAutoStyles) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NAME, pEntry->GetName()); + + aAny <<= pEntry->GetFamilyName(); + if (aFamilyNameHdl.exportXML(sTmp, aAny, rUnitConv)) + GetExport().AddAttribute(XML_NAMESPACE_SVG, + XML_FONT_FAMILY, sTmp); + + const OUString& rStyleName = pEntry->GetStyleName(); + if (!rStyleName.isEmpty()) + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_FONT_ADORNMENTS, + rStyleName); + + aAny <<= static_cast(pEntry->GetFamily()); + if (aFamilyHdl.exportXML(sTmp, aAny, rUnitConv)) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_FONT_FAMILY_GENERIC, sTmp); + } + aAny <<= static_cast(pEntry->GetPitch()); + if (aPitchHdl.exportXML(sTmp, aAny, rUnitConv)) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_FONT_PITCH, sTmp); + } + + aAny <<= static_cast(pEntry->GetEncoding()); + if (aEncHdl.exportXML( sTmp, aAny, rUnitConv)) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_FONT_CHARSET, sTmp); + } + + SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_STYLE, + XML_FONT_FACE, true, true); + + if (m_bTryToEmbedFonts) + { + const bool bExportFlat(GetExport().getExportFlags() & SvXMLExportFlags::EMBEDDED); + std::vector aEmbeddedFonts; + static const std::vector> aCombinations = + { + { WEIGHT_NORMAL, ITALIC_NONE }, + { WEIGHT_BOLD, ITALIC_NONE }, + { WEIGHT_NORMAL, ITALIC_NORMAL }, + { WEIGHT_BOLD, ITALIC_NORMAL }, + }; + + for (auto const & aCombinationPair : aCombinations) + { + // 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 sFileUrl = EmbeddedFontsHelper::fontFileUrl( + pEntry->GetFamilyName(), pEntry->GetFamily(), + aCombinationPair.second, aCombinationPair.first, pEntry->GetPitch(), + EmbeddedFontsHelper::FontRights::ViewingAllowed); + if (sFileUrl.isEmpty()) + continue; + + // When embedded only is not set or font is used + if (!m_bEmbedUsedOnly || + aUsedFontNames.find(pEntry->GetFamilyName()) != aUsedFontNames.end()) + { + if (!fontFilesMap.count(sFileUrl)) + { + const OUString docUrl = bExportFlat ? + lcl_checkFontFile(sFileUrl) : embedFontFile(sFileUrl, pEntry->GetFamilyName()); + if (!docUrl.isEmpty()) + fontFilesMap[sFileUrl] = docUrl; + else + continue; // --> failed to embed + } + EmbeddedFontInfo aEmbeddedFont; + aEmbeddedFont.aURL = sFileUrl; + aEmbeddedFont.eWeight = aCombinationPair.first; + aEmbeddedFont.eItalic = aCombinationPair.second; + aEmbeddedFonts.push_back(aEmbeddedFont); + } + } + if (!aEmbeddedFonts.empty()) + { + SvXMLElementExport fontFaceSrc(GetExport(), XML_NAMESPACE_SVG, XML_FONT_FACE_SRC, true, true); + for (EmbeddedFontInfo const & rEmbeddedFont : aEmbeddedFonts) + { + if (fontFilesMap.count(rEmbeddedFont.aURL)) + { + if (!bExportFlat) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, + fontFilesMap[rEmbeddedFont.aURL]); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, "simple"); + } + + // Help consumers of our output by telling them which + // font file is which one. + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_FONT_STYLE, + FontItalicToString(rEmbeddedFont.eItalic)); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_FONT_WEIGHT, + FontWeightToString(rEmbeddedFont.eWeight)); + + SvXMLElementExport fontFaceUri(GetExport(), XML_NAMESPACE_SVG, + XML_FONT_FACE_URI, true, true); + + if (bExportFlat) + { + const uno::Reference xFileAccess( + ucb::SimpleFileAccess::create(GetExport().getComponentContext())); + try + { + const uno::Reference xInput(xFileAccess->openFileRead(fontFilesMap[rEmbeddedFont.aURL])); + XMLBase64Export aBase64Exp(GetExport()); + aBase64Exp.exportOfficeBinaryDataElement(xInput); + } + catch (const uno::Exception &) + { + // opening the file failed, ignore + } + } + + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_STRING, "truetype"); + SvXMLElementExport fontFaceFormat(GetExport(), XML_NAMESPACE_SVG, + XML_FONT_FACE_FORMAT, true, true); + } + } + } + } + } +} + +static OUString getFreeFontName(uno::Reference const & rxStorage, OUString const & rFamilyName) +{ + OUString sName; + int nIndex = 1; + do + { + sName = "Font_" + + rFamilyName.replaceAll(" ", "_") + "_" + + OUString::number(nIndex) + ".ttf"; + nIndex++; + } while (rxStorage->hasByName(sName)); + + return sName; +} + +static OString convertToHashString(std::vector const & rHash) +{ + std::stringstream aStringStream; + for (auto const & rByte : rHash) + { + aStringStream << std::setw(2) << std::setfill('0') << std::hex << int(rByte); + } + + return aStringStream.str().c_str(); +} + +static OString getFileHash(OUString const & rFileUrl) +{ + OString aHash; + osl::File aFile(rFileUrl); + if (aFile.open(osl_File_OpenFlag_Read) != osl::File::E_None) + return aHash; + + comphelper::Hash aHashEngine(comphelper::HashType::SHA512); + for (;;) + { + sal_Int8 aBuffer[4096]; + sal_uInt64 nReadSize; + sal_Bool bEof; + if (aFile.isEndOfFile(&bEof) != osl::File::E_None) + { + SAL_WARN("xmloff", "Error reading font file " << rFileUrl); + return aHash; + } + if (bEof) + break; + if (aFile.read(aBuffer, 4096, nReadSize) != osl::File::E_None) + { + SAL_WARN("xmloff", "Error reading font file " << rFileUrl); + return aHash; + } + if (nReadSize == 0) + break; + aHashEngine.update(reinterpret_cast(aBuffer), nReadSize); + } + return convertToHashString(aHashEngine.finalize()); +} + +OUString XMLFontAutoStylePool::embedFontFile(OUString const & fileUrl, OUString const & rFamilyName) +{ + try + { + OString sHashString = getFileHash(fileUrl); + if (m_aEmbeddedFontFiles.find(sHashString) != m_aEmbeddedFontFiles.end()) + return m_aEmbeddedFontFiles.at(sHashString); + + osl::File file( fileUrl ); + if( file.open( osl_File_OpenFlag_Read ) != osl::File::E_None ) + return OUString(); + + if ( !GetExport().GetTargetStorage().is() ) + return OUString(); + + uno::Reference< embed::XStorage > storage; + storage.set( GetExport().GetTargetStorage()->openStorageElement( "Fonts", + ::embed::ElementModes::WRITE ), uno::UNO_SET_THROW ); + + OUString name = getFreeFontName(storage, rFamilyName); + + uno::Reference< io::XOutputStream > outputStream; + outputStream.set( storage->openStreamElement( name, ::embed::ElementModes::WRITE ), UNO_QUERY_THROW ); + uno::Reference < beans::XPropertySet > propertySet( outputStream, uno::UNO_QUERY ); + assert( propertySet.is()); + propertySet->setPropertyValue( "MediaType", uno::Any( OUString( "application/x-font-ttf" ))); // TODO + for(;;) + { + sal_Int8 buffer[ 4096 ]; + sal_uInt64 readSize; + sal_Bool eof; + if( file.isEndOfFile( &eof ) != osl::File::E_None ) + { + SAL_WARN( "xmloff", "Error reading font file " << fileUrl ); + outputStream->closeOutput(); + return OUString(); + } + if( eof ) + break; + if( file.read( buffer, 4096, readSize ) != osl::File::E_None ) + { + SAL_WARN( "xmloff", "Error reading font file " << fileUrl ); + outputStream->closeOutput(); + return OUString(); + } + if( readSize == 0 ) + break; + // coverity[overrun-buffer-arg : FALSE] - coverity has difficulty with css::uno::Sequence + outputStream->writeBytes(uno::Sequence(buffer, readSize)); + } + outputStream->closeOutput(); + if( storage.is() ) + { + Reference< embed::XTransactedObject > transaction( storage, UNO_QUERY ); + if( transaction.is()) + { + transaction->commit(); + OUString sInternalName = "Fonts/" + name; + m_aEmbeddedFontFiles.emplace(sHashString, sInternalName); + return sInternalName; + } + } + } catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "xmloff", "Exception when embedding a font file" ); + } + return OUString(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFontStylesContext.cxx b/xmloff/source/style/XMLFontStylesContext.cxx new file mode 100644 index 000000000..56d87c02c --- /dev/null +++ b/xmloff/source/style/XMLFontStylesContext.cxx @@ -0,0 +1,352 @@ +/* -*- 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 +#include "XMLFontStylesContext_impl.hxx" + +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include "fonthdl.hxx" +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::awt; +using namespace ::xmloff::token; + + +#define XML_STYLE_FAMILY_FONT XmlStyleFamily::PAGE_MASTER + +XMLFontStyleContextFontFace::XMLFontStyleContextFontFace( SvXMLImport& rImport, + XMLFontStylesContext& rStyles ) : + SvXMLStyleContext( rImport, XML_STYLE_FAMILY_FONT ), + xStyles( &rStyles ) +{ + aFamilyName <<= OUString(); + aStyleName <<= OUString(); + aFamily <<= sal_Int16(awt::FontFamily::DONTKNOW); + aPitch <<= sal_Int16(awt::FontPitch::DONTKNOW); + aEnc <<= static_cast(rStyles.GetDfltCharset()); +} + +void XMLFontStyleContextFontFace::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + SvXMLUnitConverter& rUnitConv = GetImport().GetMM100UnitConverter(); + Any aAny; + + switch(nElement) + { + case XML_ELEMENT(SVG, XML_FONT_FAMILY): + case XML_ELEMENT(SVG_COMPAT, XML_FONT_FAMILY): + if( GetStyles()->GetFamilyNameHdl().importXML( rValue, aAny, + rUnitConv ) ) + aFamilyName = aAny; + break; + case XML_ELEMENT(STYLE, XML_FONT_ADORNMENTS): + aStyleName <<= rValue; + break; + case XML_ELEMENT(STYLE, XML_FONT_FAMILY_GENERIC): + if( GetStyles()->GetFamilyHdl().importXML( rValue, aAny, + rUnitConv ) ) + aFamily = aAny; + break; + case XML_ELEMENT(STYLE, XML_FONT_PITCH): + if( GetStyles()->GetPitchHdl().importXML( rValue, aAny, + rUnitConv ) ) + aPitch = aAny; + break; + case XML_ELEMENT(STYLE, XML_FONT_CHARSET): + if( GetStyles()->GetEncodingHdl().importXML( rValue, aAny, + rUnitConv ) ) + aEnc = aAny; + break; + default: + SvXMLStyleContext::SetAttribute( nElement, rValue ); + break; + } +} + +XMLFontStyleContextFontFace::~XMLFontStyleContextFontFace() +{ +} + +void XMLFontStyleContextFontFace::FillProperties( + ::std::vector< XMLPropertyState > &rProps, + sal_Int32 nFamilyNameIdx, + sal_Int32 nStyleNameIdx, + sal_Int32 nFamilyIdx, + sal_Int32 nPitchIdx, + sal_Int32 nCharsetIdx ) const +{ + if( nFamilyNameIdx != -1 ) + { + XMLPropertyState aPropState( nFamilyNameIdx, aFamilyName ); + rProps.push_back( aPropState ); + } + if( nStyleNameIdx != -1 ) + { + XMLPropertyState aPropState( nStyleNameIdx, aStyleName ); + rProps.push_back( aPropState ); + } + if( nFamilyIdx != -1 ) + { + XMLPropertyState aPropState( nFamilyIdx, aFamily ); + rProps.push_back( aPropState ); + } + if( nPitchIdx != -1 ) + { + XMLPropertyState aPropState( nPitchIdx, aPitch ); + rProps.push_back( aPropState ); + } + if( nCharsetIdx != -1 ) + { + XMLPropertyState aPropState( nCharsetIdx, aEnc ); + rProps.push_back( aPropState ); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFontStyleContextFontFace::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & ) +{ + if( nElement == XML_ELEMENT(SVG, XML_FONT_FACE_SRC) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_FONT_FACE_SRC) ) + return new XMLFontStyleContextFontFaceSrc( GetImport(), *this ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +OUString XMLFontStyleContextFontFace::familyName() const +{ + OUString ret; + aFamilyName >>= ret; + return ret; +} + + +XMLFontStyleContextFontFaceFormat::XMLFontStyleContextFontFaceFormat( SvXMLImport& rImport, + XMLFontStyleContextFontFaceUri& _uri ) + : SvXMLStyleContext( rImport ) + , uri(_uri) +{ +} + +void XMLFontStyleContextFontFaceFormat::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(SVG, XML_STRING) || nElement == XML_ELEMENT(SVG_COMPAT, XML_STRING)) + uri.SetFormat(rValue); + else + SvXMLStyleContext::SetAttribute( nElement, rValue ); +} + + +XMLFontStyleContextFontFaceSrc::XMLFontStyleContextFontFaceSrc( SvXMLImport& rImport, + const XMLFontStyleContextFontFace& _font ) + : SvXMLImportContext( rImport ) + , font( _font ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFontStyleContextFontFaceSrc::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) +{ + if( nElement == XML_ELEMENT(SVG, XML_FONT_FACE_URI) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_FONT_FACE_URI) ) + return new XMLFontStyleContextFontFaceUri( GetImport(), font ); + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +XMLFontStyleContextFontFaceUri::XMLFontStyleContextFontFaceUri( SvXMLImport& rImport, + const XMLFontStyleContextFontFace& _font ) + : SvXMLStyleContext( rImport ) + , font( _font ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFontStyleContextFontFaceUri::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/ ) +{ + if( nElement == XML_ELEMENT(SVG, XML_FONT_FACE_FORMAT) ) + return new XMLFontStyleContextFontFaceFormat( GetImport(), *this ); + else if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) ) + { + assert(linkPath.isEmpty()); + if( linkPath.isEmpty() ) + { + mxBase64Stream.set( new comphelper::OSequenceOutputStream( maFontData ) ); + if( mxBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), mxBase64Stream ); + } + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLFontStyleContextFontFaceUri::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(XLINK, XML_HREF) ) + linkPath = rValue; + else + SvXMLStyleContext::SetAttribute( nElement, rValue ); +} + +void XMLFontStyleContextFontFaceUri::SetFormat( const OUString& rFormat ) +{ + format = rFormat; +} + +// the CSS2 standard ( http://www.w3.org/TR/2008/REC-CSS2-20080411/fonts.html#referencing ) +// defines these format strings. +const char OPENTYPE_FORMAT[] = "opentype"; +const char TRUETYPE_FORMAT[] = "truetype"; +const char EOT_FORMAT[] = "embedded-opentype"; + +void XMLFontStyleContextFontFaceUri::endFastElement(sal_Int32 ) +{ + if( ( linkPath.getLength() == 0 ) && ( !maFontData.hasElements() ) ) + { + SAL_WARN( "xmloff", "svg:font-face-uri tag with no link or base64 data; ignoring." ); + return; + } + bool eot; + // Assume by default that the font is not compressed. + if( format.getLength() == 0 + || format == OPENTYPE_FORMAT + || format == TRUETYPE_FORMAT ) + { + eot = false; + } + else if( format == EOT_FORMAT ) + { + eot = true; + } + else + { + SAL_WARN( "xmloff", "Unknown format of embedded font; assuming TTF." ); + eot = false; + } + if ( !maFontData.hasElements() ) + handleEmbeddedFont( linkPath, eot ); + else + handleEmbeddedFont( maFontData, eot ); +} + +void XMLFontStyleContextFontFaceUri::handleEmbeddedFont( const OUString& url, bool eot ) +{ + if( GetImport().embeddedFontAlreadyProcessed( url )) + { + GetImport().NotifyContainsEmbeddedFont(); + return; + } + OUString fontName = font.familyName(); + // If there's any giveMeStreamForThisURL(), then it's well-hidden for me to find it. + if( GetImport().IsPackageURL( url )) + { + uno::Reference< embed::XStorage > storage; + storage.set( GetImport().GetSourceStorage(), UNO_SET_THROW ); + if( url.indexOf( '/' ) > -1 ) // TODO what if more levels? + storage.set( storage->openStorageElement( url.copy( 0, url.indexOf( '/' )), + ::embed::ElementModes::READ ), uno::UNO_SET_THROW ); + uno::Reference< io::XInputStream > inputStream; + inputStream.set( storage->openStreamElement( url.copy( url.indexOf( '/' ) + 1 ), ::embed::ElementModes::READ ), + UNO_QUERY_THROW ); + if (GetImport().addEmbeddedFont(inputStream, fontName, "?", std::vector< unsigned char >(), eot)) + GetImport().NotifyContainsEmbeddedFont(); + inputStream->closeInput(); + } + else + SAL_WARN( "xmloff", "External URL for font file not handled." ); +} + +void XMLFontStyleContextFontFaceUri::handleEmbeddedFont( const ::css::uno::Sequence< sal_Int8 >& rData, const bool eot ) +{ + const uno::Reference< io::XInputStream > xInput( new comphelper::SequenceInputStream( rData ) ); + const OUString fontName = font.familyName(); + if (GetImport().addEmbeddedFont(xInput, fontName, "?", std::vector< unsigned char >(), eot)) + GetImport().NotifyContainsEmbeddedFont(); + xInput->closeInput(); +} + +SvXMLStyleContext *XMLFontStylesContext::CreateStyleChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_FONT_FACE) ) + { + return new XMLFontStyleContextFontFace( GetImport(), *this ); + } + return SvXMLStylesContext::CreateStyleChildContext( nElement, xAttrList ); +} + + +XMLFontStylesContext::XMLFontStylesContext( SvXMLImport& rImport, + rtl_TextEncoding eDfltEnc ) : + SvXMLStylesContext( rImport ), + pFamilyNameHdl( new XMLFontFamilyNamePropHdl ), + pFamilyHdl( new XMLFontFamilyPropHdl ), + pPitchHdl( new XMLFontPitchPropHdl ), + pEncHdl( new XMLFontEncodingPropHdl ), + eDfltEncoding( eDfltEnc ) +{ +} + +XMLFontStylesContext::~XMLFontStylesContext() {} + +bool XMLFontStylesContext::FillProperties( const OUString& rName, + ::std::vector< XMLPropertyState > &rProps, + sal_Int32 nFamilyNameIdx, + sal_Int32 nStyleNameIdx, + sal_Int32 nFamilyIdx, + sal_Int32 nPitchIdx, + sal_Int32 nCharsetIdx ) const +{ + const SvXMLStyleContext* pStyle = FindStyleChildContext( XML_STYLE_FAMILY_FONT, rName, true ); + const XMLFontStyleContextFontFace *pFontStyle = dynamic_cast(pStyle);// use temp var, PTR_CAST is a bad macro, FindStyleChildContext will be called twice + if( pFontStyle ) + pFontStyle->FillProperties( rProps, nFamilyNameIdx, nStyleNameIdx, + nFamilyIdx, nPitchIdx, nCharsetIdx ); + return nullptr != pFontStyle; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFontStylesContext_impl.hxx b/xmloff/source/style/XMLFontStylesContext_impl.hxx new file mode 100644 index 000000000..b86bedbd1 --- /dev/null +++ b/xmloff/source/style/XMLFontStylesContext_impl.hxx @@ -0,0 +1,122 @@ +/* -*- 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 + +namespace com::sun::star::io { + class XOutputStream; +} + +/// Handles +class XMLFontStyleContextFontFace : public SvXMLStyleContext +{ + css::uno::Any aFamilyName; + css::uno::Any aStyleName; + css::uno::Any aFamily; + css::uno::Any aPitch; + css::uno::Any aEnc; + + rtl::Reference xStyles; + + XMLFontStylesContext *GetStyles() + { + return xStyles.get(); + } + +public: + + + XMLFontStyleContextFontFace( SvXMLImport& rImport, + XMLFontStylesContext& rStyles ); + virtual ~XMLFontStyleContextFontFace() override; + + void SetAttribute( sal_Int32 nElement, + const OUString& rValue ) override; + + void FillProperties( ::std::vector< XMLPropertyState > &rProps, + sal_Int32 nFamilyNameIdx, + sal_Int32 nStyleNameIdx, + sal_Int32 nFamilyIdx, + sal_Int32 nPitchIdx, + sal_Int32 nCharsetIdx ) const; + + OUString familyName() const; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override; +}; + +/// Handles +class XMLFontStyleContextFontFaceSrc : public SvXMLImportContext +{ + const XMLFontStyleContextFontFace& font; +public: + + + XMLFontStyleContextFontFaceSrc( SvXMLImport& rImport, + const XMLFontStyleContextFontFace& font ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override; +}; + +/// Handles +class XMLFontStyleContextFontFaceUri : public SvXMLStyleContext +{ + const XMLFontStyleContextFontFace& font; + OUString format; + OUString linkPath; + ::css::uno::Sequence< sal_Int8 > maFontData; + ::css::uno::Reference< ::css::io::XOutputStream > mxBase64Stream; + + void handleEmbeddedFont( const OUString& url, bool eot ); + void handleEmbeddedFont( const ::css::uno::Sequence< sal_Int8 >& rData, bool eot ); +public: + + + XMLFontStyleContextFontFaceUri( SvXMLImport& rImport, + const XMLFontStyleContextFontFace& font ); + + virtual void SetAttribute( sal_Int32 nElement, + const OUString& rValue ) override; + void SetFormat( const OUString& rFormat ); + void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override; +}; + +/// Handles +class XMLFontStyleContextFontFaceFormat : public SvXMLStyleContext +{ + XMLFontStyleContextFontFaceUri& uri; +public: + + XMLFontStyleContextFontFaceFormat( SvXMLImport& rImport, + XMLFontStyleContextFontFaceUri& uri ); + + void SetAttribute( sal_Int32 nElement, + const OUString& rValue ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFootnoteSeparatorExport.cxx b/xmloff/source/style/XMLFootnoteSeparatorExport.cxx new file mode 100644 index 000000000..c5e160dff --- /dev/null +++ b/xmloff/source/style/XMLFootnoteSeparatorExport.cxx @@ -0,0 +1,179 @@ +/* -*- 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 "XMLFootnoteSeparatorExport.hxx" + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using ::std::vector; + +XMLFootnoteSeparatorExport::XMLFootnoteSeparatorExport(SvXMLExport& rExp) : + rExport(rExp) +{ +} + +void XMLFootnoteSeparatorExport::exportXML( + const vector * pProperties, + sal_uInt32 const nIdx, + const rtl::Reference & rMapper) +{ + assert(pProperties); + + // initialize values + text::HorizontalAdjust eLineAdjust = text::HorizontalAdjust_LEFT; + sal_Int32 nLineColor = 0; + sal_Int32 nLineDistance = 0; + sal_Int8 nLineRelWidth = 0; + sal_Int32 nLineTextDistance = 0; + sal_Int16 nLineWeight = 0; + sal_Int8 nLineStyle = 0; + + // find indices into property map and get values + sal_uInt32 nCount = pProperties->size(); + for(sal_uInt32 i = 0; i < nCount; i++) + { + const XMLPropertyState& rState = (*pProperties)[i]; + + if( rState.mnIndex == -1 ) + continue; + + switch (rMapper->GetEntryContextId(rState.mnIndex)) + { + case CTF_PM_FTN_LINE_ADJUST: + { + sal_Int16 nTmp; + if (rState.maValue >>= nTmp) + eLineAdjust = static_cast(nTmp); + break; + } + case CTF_PM_FTN_LINE_COLOR: + rState.maValue >>= nLineColor; + break; + case CTF_PM_FTN_DISTANCE: + rState.maValue >>= nLineDistance; + break; + case CTF_PM_FTN_LINE_WIDTH: + rState.maValue >>= nLineRelWidth; + break; + case CTF_PM_FTN_LINE_DISTANCE: + rState.maValue >>= nLineTextDistance; + break; + case CTF_PM_FTN_LINE_WEIGHT: + (void) nIdx; + assert(i == nIdx && "received wrong property state index"); + rState.maValue >>= nLineWeight; + break; + case CTF_PM_FTN_LINE_STYLE: + rState.maValue >>= nLineStyle; + break; + } + } + + OUStringBuffer sBuf; + + // weight/width + if (nLineWeight > 0) + { + rExport.GetMM100UnitConverter().convertMeasureToXML(sBuf, nLineWeight); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_WIDTH, + sBuf.makeStringAndClear()); + } + + // line text distance + if (nLineTextDistance > 0) + { + rExport.GetMM100UnitConverter().convertMeasureToXML(sBuf, + nLineTextDistance); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DISTANCE_BEFORE_SEP, + sBuf.makeStringAndClear()); + } + + // line distance + if (nLineDistance > 0) + { + rExport.GetMM100UnitConverter().convertMeasureToXML(sBuf, + nLineDistance); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_DISTANCE_AFTER_SEP, + sBuf.makeStringAndClear()); + } + + // line style + static const SvXMLEnumMapEntry aXML_LineStyle_Enum[] = + { + { XML_NONE, 0 }, + { XML_SOLID, 1 }, + { XML_DOTTED, 2 }, + { XML_DASH, 3 }, + { XML_TOKEN_INVALID, 0 } + }; + if (SvXMLUnitConverter::convertEnum( + sBuf, nLineStyle, aXML_LineStyle_Enum ) ) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_LINE_STYLE, + sBuf.makeStringAndClear()); + } + + // adjustment + static const SvXMLEnumMapEntry aXML_HorizontalAdjust_Enum[] = + { + { XML_LEFT, text::HorizontalAdjust_LEFT }, + { XML_CENTER, text::HorizontalAdjust_CENTER }, + { XML_RIGHT, text::HorizontalAdjust_RIGHT }, + { XML_TOKEN_INVALID, text::HorizontalAdjust(0) } + }; + + if (SvXMLUnitConverter::convertEnum( + sBuf, eLineAdjust, aXML_HorizontalAdjust_Enum)) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_ADJUSTMENT, + sBuf.makeStringAndClear()); + } + + // relative line width + ::sax::Converter::convertPercent(sBuf, nLineRelWidth); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_REL_WIDTH, + sBuf.makeStringAndClear()); + + // color + ::sax::Converter::convertColor(sBuf, nLineColor); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_COLOR, + sBuf.makeStringAndClear()); + + // line-style + + SvXMLElementExport aElem(rExport, XML_NAMESPACE_STYLE, + XML_FOOTNOTE_SEP, true, true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFootnoteSeparatorExport.hxx b/xmloff/source/style/XMLFootnoteSeparatorExport.hxx new file mode 100644 index 000000000..2784e291b --- /dev/null +++ b/xmloff/source/style/XMLFootnoteSeparatorExport.hxx @@ -0,0 +1,50 @@ +/* -*- 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 +#include + +class SvXMLExport; +class XMLPropertySetMapper; +struct XMLPropertyState; +namespace rtl { + template class Reference; +} + +/** + * export footnote separator element in page styles + */ +class XMLFootnoteSeparatorExport +{ + SvXMLExport& rExport; + +public: + + explicit XMLFootnoteSeparatorExport(SvXMLExport& rExp); + + void exportXML( + const ::std::vector * pProperties, + sal_uInt32 nIdx, + /// used only for debugging + const rtl::Reference & rMapper); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFootnoteSeparatorImport.cxx b/xmloff/source/style/XMLFootnoteSeparatorImport.cxx new file mode 100644 index 000000000..399741023 --- /dev/null +++ b/xmloff/source/style/XMLFootnoteSeparatorImport.cxx @@ -0,0 +1,198 @@ +/* -*- 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 "XMLFootnoteSeparatorImport.hxx" + +#include +#include + +#include +#include +#include + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::std::vector; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLFootnoteSeparatorImport::XMLFootnoteSeparatorImport( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + vector & rProps, + const rtl::Reference & rMapperRef, + sal_Int32 nIndex) : + SvXMLImportContext(rImport), + rProperties(rProps), + rMapper(rMapperRef), + nPropIndex(nIndex) +{ +} + +XMLFootnoteSeparatorImport::~XMLFootnoteSeparatorImport() +{ +} + +void XMLFootnoteSeparatorImport::startFastElement( + sal_Int32 /*nElement*/, + const Reference & xAttrList) +{ + // get the values from the properties + sal_Int16 nLineWeight = 0; + sal_Int32 nLineColor = 0; + sal_Int8 nLineRelWidth = 0; + text::HorizontalAdjust eLineAdjust = text::HorizontalAdjust_LEFT; + sal_Int32 nLineTextDistance = 0; + sal_Int32 nLineDistance = 0; + + // Default separator line style should be SOLID (used to be default before + // the choice selector was available) + sal_Int8 nLineStyle = 1; + + // iterate over xattribute list and fill values + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + sal_Int32 nTmp; + switch (aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_WIDTH): + { + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nTmp, aIter.toView())) + { + nLineWeight = static_cast(nTmp); + } + break; + } + case XML_ELEMENT(STYLE, XML_DISTANCE_BEFORE_SEP): + { + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nTmp, aIter.toView())) + nLineTextDistance = nTmp; + break; + } + case XML_ELEMENT(STYLE, XML_DISTANCE_AFTER_SEP): + { + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nTmp, aIter.toView())) + nLineDistance = nTmp; + break; + } + case XML_ELEMENT(STYLE, XML_ADJUSTMENT ): + { + static const SvXMLEnumMapEntry aXML_HorizontalAdjust_Enum[] = + { + { XML_LEFT, text::HorizontalAdjust_LEFT }, + { XML_CENTER, text::HorizontalAdjust_CENTER }, + { XML_RIGHT, text::HorizontalAdjust_RIGHT }, + { XML_TOKEN_INVALID, text::HorizontalAdjust(0) } + }; + + SvXMLUnitConverter::convertEnum( + eLineAdjust, aIter.toView(), aXML_HorizontalAdjust_Enum); + break; + } + case XML_ELEMENT(STYLE, XML_REL_WIDTH ): + { + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nLineRelWidth = static_cast(nTmp); + break; + } + case XML_ELEMENT(STYLE, XML_COLOR): + { + if (::sax::Converter::convertColor(nTmp, aIter.toView())) + { + nLineColor = nTmp; + } + break; + } + case XML_ELEMENT(STYLE, XML_LINE_STYLE ): + { + static const SvXMLEnumMapEntry aXML_LineStyle_Enum[] = + { + { XML_NONE, 0 }, + { XML_SOLID, 1 }, + { XML_DOTTED, 2 }, + { XML_DASH, 3 }, + { XML_TOKEN_INVALID, 0 } + }; + + SvXMLUnitConverter::convertEnum(nLineStyle, aIter.toView(), aXML_LineStyle_Enum); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // OK, now we have all values and can fill the XMLPropertyState vector + sal_Int32 nIndex; + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_ADJUST); + XMLPropertyState aLineAdjust( nIndex, uno::Any(sal_Int16(eLineAdjust)) ); + rProperties.push_back(aLineAdjust); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_COLOR); + XMLPropertyState aLineColor( nIndex, uno::Any(nLineColor) ); + rProperties.push_back(aLineColor); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_STYLE); + XMLPropertyState aLineStyle( nIndex, uno::Any(nLineStyle) ); + rProperties.push_back(aLineStyle); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_DISTANCE); + XMLPropertyState aLineDistance( nIndex, uno::Any(nLineDistance) ); + rProperties.push_back(aLineDistance); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_WIDTH); + XMLPropertyState aLineRelWidth( nIndex, uno::Any(nLineRelWidth)); + rProperties.push_back(aLineRelWidth); + + nIndex = rMapper->FindEntryIndex(CTF_PM_FTN_LINE_DISTANCE); + XMLPropertyState aLineTextDistance( nIndex, uno::Any(nLineTextDistance)); + rProperties.push_back(aLineTextDistance); + + SAL_WARN_IF( rMapper->FindEntryIndex(CTF_PM_FTN_LINE_WEIGHT) != nPropIndex, "xmloff", + "Received wrong property map index!" ); + XMLPropertyState aLineWeight( nPropIndex, uno::Any(nLineWeight) ); + rProperties.push_back(aLineWeight); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLFootnoteSeparatorImport.hxx b/xmloff/source/style/XMLFootnoteSeparatorImport.hxx new file mode 100644 index 000000000..be0289f80 --- /dev/null +++ b/xmloff/source/style/XMLFootnoteSeparatorImport.hxx @@ -0,0 +1,61 @@ +/* -*- 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 +#include +#include + + +class SvXMLImport; +struct XMLPropertyState; +class XMLPropertySetMapper; +namespace com::sun::star { + namespace uno { template class Reference; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import the footnote-separator element in page styles. + */ +class XMLFootnoteSeparatorImport : public SvXMLImportContext +{ + ::std::vector & rProperties; + rtl::Reference rMapper; + sal_Int32 nPropIndex; + +public: + + + XMLFootnoteSeparatorImport( + SvXMLImport& rImport, + sal_Int32 nElement, + ::std::vector & rProperties, + const rtl::Reference & rMapperRef, + sal_Int32 nIndex); + + virtual ~XMLFootnoteSeparatorImport() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLIsPercentagePropertyHandler.cxx b/xmloff/source/style/XMLIsPercentagePropertyHandler.cxx new file mode 100644 index 000000000..3d32e8479 --- /dev/null +++ b/xmloff/source/style/XMLIsPercentagePropertyHandler.cxx @@ -0,0 +1,50 @@ +/* -*- 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 +#include +#include + +using namespace ::com::sun::star; +using namespace css::uno; + + +XMLIsPercentagePropertyHandler::~XMLIsPercentagePropertyHandler() +{ +} + +bool XMLIsPercentagePropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + rValue <<= rStrImpValue.indexOf( '%' ) != -1; + return true; +} + +bool XMLIsPercentagePropertyHandler::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + OSL_FAIL( "XMLIsPercentagePropertyHandler is not for export!" ); + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLPageExport.cxx b/xmloff/source/style/XMLPageExport.cxx new file mode 100644 index 000000000..042a70398 --- /dev/null +++ b/xmloff/source/style/XMLPageExport.cxx @@ -0,0 +1,319 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "PageMasterExportPropMapper.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +constexpr OUStringLiteral gsIsPhysical( u"IsPhysical" ); +constexpr OUStringLiteral gsFollowStyle( u"FollowStyle" ); + +namespace { + +bool findPageMasterNameEntry( + ::std::vector const& aNameVector, + const OUString& rStyleName, XMLPageExportNameEntry & o_rEntry) +{ + auto pEntry = std::find_if(aNameVector.cbegin(), aNameVector.cend(), + [&rStyleName](const XMLPageExportNameEntry& rEntry) { return rEntry.sStyleName == rStyleName; }); + + if( pEntry != aNameVector.cend() ) + { + o_rEntry = *pEntry; + return true; + } + + return false; +} + +} // namespace + +void XMLPageExport::collectPageMasterAutoStyle( + const Reference < XPropertySet > & rPropSet, + XMLPageExportNameEntry & rEntry) +{ + SAL_WARN_IF( !xPageMasterPropSetMapper.is(), "xmloff", "page master family/XMLPageMasterPropSetMapper not found" ); + if( xPageMasterPropSetMapper.is() ) + { + ::std::vector aPropStates = xPageMasterExportPropMapper->Filter(rExport, rPropSet); + if( !aPropStates.empty()) + { + OUString sParent; + rEntry.sPageMasterName = rExport.GetAutoStylePool()->Find( XmlStyleFamily::PAGE_MASTER, sParent, aPropStates ); + if (rEntry.sPageMasterName.isEmpty()) + { + rEntry.sPageMasterName = rExport.GetAutoStylePool()->Add(XmlStyleFamily::PAGE_MASTER, sParent, std::move(aPropStates)); + } + } + } + assert(m_xPageMasterDrawingPageExportPropMapper.is()); + ::std::vector aPropStates( + m_xPageMasterDrawingPageExportPropMapper->Filter(rExport, rPropSet)); + if (!aPropStates.empty()) + { + OUString sParent; + rEntry.sDrawingPageStyleName = rExport.GetAutoStylePool()->Find(XmlStyleFamily::SD_DRAWINGPAGE_ID, sParent, aPropStates); + if (rEntry.sDrawingPageStyleName.isEmpty()) + { + rEntry.sDrawingPageStyleName = rExport.GetAutoStylePool()->Add(XmlStyleFamily::SD_DRAWINGPAGE_ID, sParent, std::move(aPropStates)); + } + } +} + +void XMLPageExport::exportMasterPageContent( + const Reference < XPropertySet > &, + bool /*bAutoStyles*/ ) +{ + +} + +bool XMLPageExport::exportStyle( + const Reference< XStyle >& rStyle, + bool bAutoStyles ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + + // Don't export styles that aren't existing really. This may be the + // case for StarOffice Writer's pool styles. + if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) ) + { + Any aAny = xPropSet->getPropertyValue( gsIsPhysical ); + if( !*o3tl::doAccess(aAny) ) + return false; + } + + if( bAutoStyles ) + { + XMLPageExportNameEntry aEntry; + collectPageMasterAutoStyle(xPropSet, aEntry); + aEntry.sStyleName = rStyle->getName(); + aNameVector.push_back( aEntry ); + + exportMasterPageContent( xPropSet, true ); + } + else + { + OUString sName( rStyle->getName() ); + bool bEncoded = false; + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, + GetExport().EncodeStyleName( sName, &bEncoded ) ); + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + uno::Any aValue = xPropSet->getPropertyValue( "Hidden" ); + bool bHidden = false; + if ((aValue >>= bHidden) && bHidden + && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDDEN, "true"); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_HIDDEN, "true"); // FIXME for compatibility + } + } + + if( bEncoded ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, + sName); + + XMLPageExportNameEntry entry; + if (findPageMasterNameEntry(aNameVector, sName, entry)) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_NAME, GetExport().EncodeStyleName(entry.sPageMasterName)); + if (!entry.sDrawingPageStyleName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, GetExport().EncodeStyleName(entry.sDrawingPageStyleName)); + } + } + + Reference xInfo = xPropSet->getPropertySetInfo(); + if ( xInfo.is() && xInfo->hasPropertyByName(gsFollowStyle) ) + { + OUString sNextName; + xPropSet->getPropertyValue( gsFollowStyle ) >>= sNextName; + + if( sName != sNextName && !sNextName.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NEXT_STYLE_NAME, + GetExport().EncodeStyleName( sNextName ) ); + } + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_MASTER_PAGE, true, true ); + + exportMasterPageContent( xPropSet, false ); + } + + return true; +} + +XMLPageExport::XMLPageExport(SvXMLExport & rExp) + : rExport(rExp) + , xPageMasterPropHdlFactory(new XMLPageMasterPropHdlFactory) + , xPageMasterPropSetMapper(new XMLPageMasterPropSetMapper( + aXMLPageMasterStyleMap, + xPageMasterPropHdlFactory)) + , xPageMasterExportPropMapper(new XMLPageMasterExportPropMapper( + xPageMasterPropSetMapper, rExp)) + , m_xPageMasterDrawingPagePropSetMapper(new XMLPageMasterPropSetMapper( + g_XMLPageMasterDrawingPageStyleMap, + xPageMasterPropHdlFactory)) + // use same class but with different map, need its ContextFilter() + , m_xPageMasterDrawingPageExportPropMapper(new XMLPageMasterExportPropMapper( + m_xPageMasterDrawingPagePropSetMapper, rExp)) +{ + rExport.GetAutoStylePool()->AddFamily( XmlStyleFamily::PAGE_MASTER, XML_STYLE_FAMILY_PAGE_MASTER_NAME, + xPageMasterExportPropMapper, XML_STYLE_FAMILY_PAGE_MASTER_PREFIX, false ); + rExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::SD_DRAWINGPAGE_ID, XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME, + m_xPageMasterDrawingPageExportPropMapper, XML_STYLE_FAMILY_SD_DRAWINGPAGE_PREFIX); + + Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), + UNO_QUERY ); + SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", + "No XStyleFamiliesSupplier from XModel for export!" ); + if( !xFamiliesSupp.is() ) + return; + + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", + "getStyleFamilies() from XModel failed for export!" ); + if( xFamilies.is() ) + { + static const OUStringLiteral aPageStyleName(u"PageStyles"); + + if( xFamilies->hasByName( aPageStyleName ) ) + { + xPageStyles.set(xFamilies->getByName( aPageStyleName ),uno::UNO_QUERY); + + SAL_WARN_IF( !xPageStyles.is(), "xmloff", + "Page Styles not found for export!" ); + } + } + + if (GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITER) + return; + + uno::Reference xFac(GetExport().GetModel(), uno::UNO_QUERY); + if (!xFac.is()) + return; + + uno::Reference xProps( + xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY); + if (!xProps.is()) + return; + + bool bGutterAtTop{}; + xProps->getPropertyValue("GutterAtTop") >>= bGutterAtTop; + if (bGutterAtTop) + { + static_cast(xPageMasterExportPropMapper.get()) + ->SetGutterAtTop(true); + } +} + +XMLPageExport::~XMLPageExport() +{ +} + +void XMLPageExport::exportStyles( bool bUsed, bool bAutoStyles ) +{ + if( xPageStyles.is() ) + { + const uno::Sequence< OUString> aSeq = xPageStyles->getElementNames(); + for(const auto& rName : aSeq) + { + Reference< XStyle > xStyle(xPageStyles->getByName( rName ),uno::UNO_QUERY); + if( !bUsed || xStyle->isInUse() ) + exportStyle( xStyle, bAutoStyles ); + } + } +} + +void XMLPageExport::exportAutoStyles() +{ + rExport.GetAutoStylePool()->exportXML(XmlStyleFamily::PAGE_MASTER); + // tdf#103602 this is called by both Writer and Calc but Calc doesn't + // have fill properties yet + rExport.GetAutoStylePool()->exportXML(XmlStyleFamily::SD_DRAWINGPAGE_ID); +} + +void XMLPageExport::exportDefaultStyle() +{ + Reference < lang::XMultiServiceFactory > xFactory (GetExport().GetModel(), UNO_QUERY); + if (!xFactory.is()) + return; + + Reference < XPropertySet > xPropSet (xFactory->createInstance ( "com.sun.star.text.Defaults" ), UNO_QUERY); + if (!xPropSet.is()) + return; + + // + GetExport().CheckAttrList(); + + ::std::vector< XMLPropertyState > aPropStates = + xPageMasterExportPropMapper->FilterDefaults(rExport, xPropSet); + + bool bExport = false; + rtl::Reference < XMLPropertySetMapper > aPropMapper(xPageMasterExportPropMapper->getPropertySetMapper()); + for( const auto& rProp : aPropStates ) + { + sal_Int16 nContextId = aPropMapper->GetEntryContextId( rProp.mnIndex ); + if( nContextId == CTF_PM_STANDARD_MODE ) + { + bExport = true; + break; + } + } + + if( !bExport ) + return; + + assert(GetExport().getSaneDefaultVersion() + >= SvtSaveOptions::ODFSVER_012); + + // + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_DEFAULT_PAGE_LAYOUT, + true, true ); + + xPageMasterExportPropMapper->exportXML( GetExport(), aPropStates, + SvXmlExportFlags::IGN_WS ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLPercentOrMeasurePropertyHandler.cxx b/xmloff/source/style/XMLPercentOrMeasurePropertyHandler.cxx new file mode 100644 index 000000000..d49174c35 --- /dev/null +++ b/xmloff/source/style/XMLPercentOrMeasurePropertyHandler.cxx @@ -0,0 +1,75 @@ +/* -*- 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 + +#include + +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLPercentOrMeasurePropertyHandler::XMLPercentOrMeasurePropertyHandler() +{ +} + +XMLPercentOrMeasurePropertyHandler::~XMLPercentOrMeasurePropertyHandler() +{ +} + +bool XMLPercentOrMeasurePropertyHandler::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + if( rStrImpValue.indexOf( '%' ) != -1 ) + return false; + + sal_Int32 nValue; + + if (!rUnitConverter.convertMeasureToCore( nValue, rStrImpValue )) + return false; + + rValue <<= nValue; + return true; +} + +bool XMLPercentOrMeasurePropertyHandler::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + sal_Int32 nValue = 0; + if( !(rValue >>= nValue ) ) + return false; + + rUnitConverter.convertMeasureToXML( aOut, nValue ); + + rStrExpValue = aOut.makeStringAndClear(); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLRectangleMembersHandler.cxx b/xmloff/source/style/XMLRectangleMembersHandler.cxx new file mode 100644 index 000000000..5a80cd0c1 --- /dev/null +++ b/xmloff/source/style/XMLRectangleMembersHandler.cxx @@ -0,0 +1,112 @@ +/* -*- 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 +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +XMLRectangleMembersHdl::XMLRectangleMembersHdl( sal_Int32 nType ) +: mnType( nType ) +{ +} + +XMLRectangleMembersHdl::~XMLRectangleMembersHdl() +{ +} + +bool XMLRectangleMembersHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + awt::Rectangle aRect( 0, 0, 0, 0 ); + if( rValue.hasValue() ) + rValue >>= aRect; + + sal_Int32 nValue; + + if (rUnitConverter.convertMeasureToCore( nValue, rStrImpValue )) + { + switch( mnType ) + { + case XML_TYPE_RECTANGLE_LEFT : + aRect.X = nValue; + break; + case XML_TYPE_RECTANGLE_TOP : + aRect.Y = nValue; + break; + case XML_TYPE_RECTANGLE_WIDTH : + aRect.Width = nValue; + break; + case XML_TYPE_RECTANGLE_HEIGHT : + aRect.Height = nValue; + break; + } + + rValue <<= aRect; + return true; + } + + return false; +} + +bool XMLRectangleMembersHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const +{ + awt::Rectangle aRect( 0, 0, 0, 0 ); + rValue >>= aRect; + + sal_Int32 nValue; + + switch( mnType ) + { + case XML_TYPE_RECTANGLE_LEFT : + nValue = aRect.X; + break; + case XML_TYPE_RECTANGLE_TOP : + nValue = aRect.Y; + break; + case XML_TYPE_RECTANGLE_WIDTH : + nValue = aRect.Width; + break; + case XML_TYPE_RECTANGLE_HEIGHT : + nValue = aRect.Height; + break; + default: + nValue = 0; // TODO What value should this be? + break; + } + + OUStringBuffer sBuffer; + rUnitConverter.convertMeasureToXML( sBuffer, nValue ); + rStrExpValue = sBuffer.makeStringAndClear(); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/XMLRtlGutterPropertyHandler.cxx b/xmloff/source/style/XMLRtlGutterPropertyHandler.cxx new file mode 100644 index 000000000..651406f0f --- /dev/null +++ b/xmloff/source/style/XMLRtlGutterPropertyHandler.cxx @@ -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 . + */ + +#include + +#include + +#include + +#include + +using namespace com::sun::star; + +XMLRtlGutterPropertyHandler::XMLRtlGutterPropertyHandler() = default; + +XMLRtlGutterPropertyHandler::~XMLRtlGutterPropertyHandler() = default; + +bool XMLRtlGutterPropertyHandler::importXML(const OUString& rStrImpValue, uno::Any& rValue, + const SvXMLUnitConverter&) const +{ + // Infer RtlGutter from WritingMode. + std::set aRtlModes = { "rl-tb", "tb-rl", "rl", "tb" }; + auto it = aRtlModes.find(rStrImpValue); + rValue <<= (it != aRtlModes.end()); + return true; +} + +bool XMLRtlGutterPropertyHandler::exportXML(OUString&, const uno::Any&, + const SvXMLUnitConverter&) const +{ + // No need to export RtlGutter. + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/adjushdl.cxx b/xmloff/source/style/adjushdl.cxx new file mode 100644 index 000000000..41a93d57f --- /dev/null +++ b/xmloff/source/style/adjushdl.cxx @@ -0,0 +1,121 @@ +/* -*- 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 "adjushdl.hxx" +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_Para_Adjust_Enum[] = +{ + { XML_START, style::ParagraphAdjust_LEFT }, + { XML_END, style::ParagraphAdjust_RIGHT }, + { XML_CENTER, style::ParagraphAdjust_CENTER }, + { XML_JUSTIFY, style::ParagraphAdjust_BLOCK }, + { XML_JUSTIFIED, style::ParagraphAdjust_BLOCK }, // obsolete + { XML_LEFT, style::ParagraphAdjust_LEFT }, + { XML_RIGHT, style::ParagraphAdjust_RIGHT }, + { XML_TOKEN_INVALID, style::ParagraphAdjust(0) } +}; + +SvXMLEnumMapEntry const pXML_Para_Align_Last_Enum[] = +{ + { XML_START, style::ParagraphAdjust_LEFT }, + { XML_CENTER, style::ParagraphAdjust_CENTER }, + { XML_JUSTIFY, style::ParagraphAdjust_BLOCK }, + { XML_JUSTIFIED, style::ParagraphAdjust_BLOCK }, // obsolete + { XML_TOKEN_INVALID, style::ParagraphAdjust(0) } +}; + + + + +XMLParaAdjustPropHdl::~XMLParaAdjustPropHdl() +{ + // nothing to do +} + +bool XMLParaAdjustPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + style::ParagraphAdjust eAdjust; + bool bRet = SvXMLUnitConverter::convertEnum( eAdjust, rStrImpValue, pXML_Para_Adjust_Enum ); + if( bRet ) + rValue <<= static_cast(eAdjust); + + return bRet; +} + +bool XMLParaAdjustPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if(!rValue.hasValue()) + return false; + OUStringBuffer aOut; + sal_Int16 nVal = 0; + + rValue >>= nVal; + + bool bRet = SvXMLUnitConverter::convertEnum( aOut, static_cast(nVal), pXML_Para_Adjust_Enum, XML_START ); + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + + + + +XMLLastLineAdjustPropHdl::~XMLLastLineAdjustPropHdl() +{ + // nothing to do +} + +bool XMLLastLineAdjustPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + style::ParagraphAdjust eAdjust; + bool bRet = SvXMLUnitConverter::convertEnum( eAdjust, rStrImpValue, pXML_Para_Align_Last_Enum ); + if( bRet ) + rValue <<= static_cast(eAdjust); + + return bRet; +} + +bool XMLLastLineAdjustPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut; + sal_Int16 nVal = 0; + bool bRet = false; + + rValue >>= nVal; + + if( static_cast(nVal) != style::ParagraphAdjust_LEFT ) + bRet = SvXMLUnitConverter::convertEnum( aOut, static_cast(nVal), pXML_Para_Align_Last_Enum, XML_START ); + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/adjushdl.hxx b/xmloff/source/style/adjushdl.hxx new file mode 100644 index 000000000..5de055163 --- /dev/null +++ b/xmloff/source/style/adjushdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLParaAdjustPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLParaAdjustPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLLastLineAdjustPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLLastLineAdjustPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/backhdl.cxx b/xmloff/source/style/backhdl.cxx new file mode 100644 index 000000000..4df7a2f6e --- /dev/null +++ b/xmloff/source/style/backhdl.cxx @@ -0,0 +1,285 @@ +/* -*- 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 "backhdl.hxx" +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_BrushHorizontalPos[] = +{ + { XML_LEFT, style::GraphicLocation_LEFT_MIDDLE }, + { XML_RIGHT, style::GraphicLocation_RIGHT_MIDDLE }, + { XML_TOKEN_INVALID, style::GraphicLocation(0) } +}; + +SvXMLEnumMapEntry const pXML_BrushVerticalPos[] = +{ + { XML_TOP, style::GraphicLocation_MIDDLE_TOP }, + { XML_BOTTOM, style::GraphicLocation_MIDDLE_BOTTOM }, + { XML_TOKEN_INVALID, style::GraphicLocation(0) } +}; + + + + +XMLBackGraphicPositionPropHdl::~XMLBackGraphicPositionPropHdl() +{ + // Nothing to do +} + +bool XMLBackGraphicPositionPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = true; + style::GraphicLocation ePos = style::GraphicLocation_NONE, eTmp; + style::GraphicLocation nTmpGraphicLocation; + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + std::u16string_view aToken; + bool bHori = false, bVert = false; + + while( bRet && aTokenEnum.getNextToken( aToken ) ) + { + if( bHori && bVert ) + { + bRet = false; + } + else if( std::u16string_view::npos != aToken.find( '%' ) ) + { + sal_Int32 nPrc = 50; + if (::sax::Converter::convertPercent( nPrc, aToken )) + { + if( !bHori ) + { + ePos = nPrc < 25 ? style::GraphicLocation_LEFT_TOP : + (nPrc < 75 ? style::GraphicLocation_MIDDLE_MIDDLE : + style::GraphicLocation_RIGHT_BOTTOM); + bHori = true; + } + else + { + eTmp = nPrc < 25 ? style::GraphicLocation_LEFT_TOP: + (nPrc < 75 ? style::GraphicLocation_LEFT_MIDDLE : + style::GraphicLocation_LEFT_BOTTOM); + MergeXMLVertPos( ePos, eTmp ); + bVert = true; + } + } + else + { + // wrong percentage + bRet = false; + } + } + else if( IsXMLToken( aToken, XML_CENTER ) ) + { + if( bHori ) + MergeXMLVertPos( ePos, style::GraphicLocation_MIDDLE_MIDDLE ); + else if ( bVert ) + MergeXMLHoriPos( ePos, style::GraphicLocation_MIDDLE_MIDDLE ); + else + ePos = style::GraphicLocation_MIDDLE_MIDDLE; + } + else if( SvXMLUnitConverter::convertEnum( nTmpGraphicLocation, aToken, pXML_BrushHorizontalPos ) ) + { + if( bVert ) + MergeXMLHoriPos( ePos, nTmpGraphicLocation ); + else if( !bHori ) + ePos = nTmpGraphicLocation; + else + bRet = false; + + bHori = true; + } + else if( SvXMLUnitConverter::convertEnum( nTmpGraphicLocation, aToken, pXML_BrushVerticalPos ) ) + { + if( bHori ) + MergeXMLVertPos( ePos, nTmpGraphicLocation ); + else if( !bVert ) + ePos = nTmpGraphicLocation; + else + bRet = false; + bVert = true; + } + else + { + bRet = false; + } + } + + bRet &= style::GraphicLocation_NONE != ePos; + if( bRet ) + rValue <<= static_cast(static_cast(ePos)); + + return bRet; +} + +bool XMLBackGraphicPositionPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = true; + OUStringBuffer aOut; + + style::GraphicLocation eLocation; + if( !( rValue >>= eLocation ) ) + { + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + eLocation = static_cast(nValue); + else + bRet = false; + } + + if( bRet ) + { + bRet = false; + + switch( eLocation ) + { + case style::GraphicLocation_LEFT_TOP: + case style::GraphicLocation_MIDDLE_TOP: + case style::GraphicLocation_RIGHT_TOP: + aOut.append( GetXMLToken(XML_TOP) ); + bRet = true; + break; + case style::GraphicLocation_LEFT_MIDDLE: + case style::GraphicLocation_MIDDLE_MIDDLE: + case style::GraphicLocation_RIGHT_MIDDLE: + aOut.append( GetXMLToken(XML_CENTER) ); + bRet = true; + break; + case style::GraphicLocation_LEFT_BOTTOM: + case style::GraphicLocation_MIDDLE_BOTTOM: + case style::GraphicLocation_RIGHT_BOTTOM: + aOut.append( GetXMLToken(XML_BOTTOM) ); + bRet = true; + break; + default: + break; + } + + if( bRet ) + { + aOut.append( ' ' ); + + switch( eLocation ) + { + case style::GraphicLocation_LEFT_TOP: + case style::GraphicLocation_LEFT_BOTTOM: + case style::GraphicLocation_LEFT_MIDDLE: + aOut.append( GetXMLToken(XML_LEFT) ); + break; + case style::GraphicLocation_MIDDLE_TOP: + case style::GraphicLocation_MIDDLE_MIDDLE: + case style::GraphicLocation_MIDDLE_BOTTOM: + aOut.append( GetXMLToken(XML_CENTER) ); + break; + case style::GraphicLocation_RIGHT_MIDDLE: + case style::GraphicLocation_RIGHT_TOP: + case style::GraphicLocation_RIGHT_BOTTOM: + aOut.append( GetXMLToken(XML_RIGHT) ); + break; + default: + break; + } + } + } + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +void XMLBackGraphicPositionPropHdl::MergeXMLVertPos( style::GraphicLocation& ePos, style::GraphicLocation eVert ) +{ + switch( ePos ) + { + case style::GraphicLocation_LEFT_TOP: + case style::GraphicLocation_LEFT_MIDDLE: + case style::GraphicLocation_LEFT_BOTTOM: + ePos = style::GraphicLocation_MIDDLE_TOP==eVert ? + style::GraphicLocation_LEFT_TOP : + (style::GraphicLocation_MIDDLE_MIDDLE==eVert ? + style::GraphicLocation_LEFT_MIDDLE : + style::GraphicLocation_LEFT_BOTTOM); + break; + + case style::GraphicLocation_MIDDLE_TOP: + case style::GraphicLocation_MIDDLE_MIDDLE: + case style::GraphicLocation_MIDDLE_BOTTOM: + ePos = eVert; + break; + + case style::GraphicLocation_RIGHT_TOP: + case style::GraphicLocation_RIGHT_MIDDLE: + case style::GraphicLocation_RIGHT_BOTTOM: + ePos = style::GraphicLocation_MIDDLE_TOP==eVert ? + style::GraphicLocation_RIGHT_TOP : + (style::GraphicLocation_MIDDLE_MIDDLE==eVert ? + style::GraphicLocation_RIGHT_MIDDLE : + style::GraphicLocation_RIGHT_BOTTOM); + break; + default: + break; + } +} + +void XMLBackGraphicPositionPropHdl::MergeXMLHoriPos( style::GraphicLocation& ePos, style::GraphicLocation eHori ) +{ + SAL_WARN_IF( !(style::GraphicLocation_LEFT_MIDDLE==eHori || style::GraphicLocation_MIDDLE_MIDDLE==eHori || style::GraphicLocation_RIGHT_MIDDLE==eHori), "xmloff", + "lcl_frmitems_MergeXMLHoriPos: vertical pos must be middle" ); + + switch( ePos ) + { + case style::GraphicLocation_LEFT_TOP: + case style::GraphicLocation_MIDDLE_TOP: + case style::GraphicLocation_RIGHT_TOP: + ePos = style::GraphicLocation_LEFT_MIDDLE==eHori ? + style::GraphicLocation_LEFT_TOP : + (style::GraphicLocation_MIDDLE_MIDDLE==eHori ? + style::GraphicLocation_MIDDLE_TOP : + style::GraphicLocation_RIGHT_TOP); + break; + + case style::GraphicLocation_LEFT_MIDDLE: + case style::GraphicLocation_MIDDLE_MIDDLE: + case style::GraphicLocation_RIGHT_MIDDLE: + ePos = eHori; + break; + + case style::GraphicLocation_LEFT_BOTTOM: + case style::GraphicLocation_MIDDLE_BOTTOM: + case style::GraphicLocation_RIGHT_BOTTOM: + ePos = style::GraphicLocation_LEFT_MIDDLE==eHori ? + style::GraphicLocation_LEFT_BOTTOM : + (style::GraphicLocation_MIDDLE_MIDDLE==eHori ? + style::GraphicLocation_MIDDLE_BOTTOM : + style::GraphicLocation_RIGHT_BOTTOM); + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/backhdl.hxx b/xmloff/source/style/backhdl.hxx new file mode 100644 index 000000000..0392909df --- /dev/null +++ b/xmloff/source/style/backhdl.hxx @@ -0,0 +1,43 @@ +/* -*- 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 +#include + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLBackGraphicPositionPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLBackGraphicPositionPropHdl() override; + + /// TabStops will be imported/exported as XML-Elements. So the Import/Export-work must be done at another place. + using XMLPropertyHandler::importXML; + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + +private: + static void MergeXMLHoriPos( css::style::GraphicLocation& ePos, css::style::GraphicLocation eHori ); + static void MergeXMLVertPos( css::style::GraphicLocation& ePos, css::style::GraphicLocation eVert ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/bordrhdl.cxx b/xmloff/source/style/bordrhdl.cxx new file mode 100644 index 000000000..4b3a7b666 --- /dev/null +++ b/xmloff/source/style/bordrhdl.cxx @@ -0,0 +1,351 @@ +/* -*- 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 "bordrhdl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +#define DEF_LINE_WIDTH_0 1 +#define DEF_LINE_WIDTH_1 35 +#define DEF_LINE_WIDTH_2 88 + +#define SVX_XML_BORDER_WIDTH_THIN 0 +#define SVX_XML_BORDER_WIDTH_MIDDLE 1 +#define SVX_XML_BORDER_WIDTH_THICK 2 + +SvXMLEnumMapEntry const pXML_BorderStyles[] = +{ + { XML_NONE, table::BorderLineStyle::NONE }, + { XML_HIDDEN, table::BorderLineStyle::NONE }, + { XML_SOLID, table::BorderLineStyle::SOLID }, + { XML_DOUBLE, table::BorderLineStyle::DOUBLE }, + { XML_DOUBLE_THIN, table::BorderLineStyle::DOUBLE_THIN }, + { XML_DOTTED, table::BorderLineStyle::DOTTED }, + { XML_DASHED, table::BorderLineStyle::DASHED }, + { XML_GROOVE, table::BorderLineStyle::ENGRAVED }, + { XML_RIDGE, table::BorderLineStyle::EMBOSSED }, + { XML_INSET, table::BorderLineStyle::INSET }, + { XML_OUTSET, table::BorderLineStyle::OUTSET }, + { XML_FINE_DASHED, table::BorderLineStyle::FINE_DASHED }, + { XML_DASH_DOT, table::BorderLineStyle::DASH_DOT }, + { XML_DASH_DOT_DOT, table::BorderLineStyle::DASH_DOT_DOT }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_NamedBorderWidths[] = +{ + { XML_THIN, SVX_XML_BORDER_WIDTH_THIN }, + { XML_MIDDLE, SVX_XML_BORDER_WIDTH_MIDDLE }, + { XML_THICK, SVX_XML_BORDER_WIDTH_THICK }, + { XML_TOKEN_INVALID, 0 } +}; +// mapping tables to map external xml input to internal box line widths + +sal_uInt16 const aBorderWidths[] = +{ + DEF_LINE_WIDTH_0, + DEF_LINE_WIDTH_1, + DEF_LINE_WIDTH_2 +}; + +static void lcl_frmitems_setXMLBorderStyle( table::BorderLine2 & rBorderLine, sal_uInt16 nStyle ) +{ + sal_Int16 eStyle = -1; // None + if (nStyle != table::BorderLineStyle::NONE) + eStyle = sal_Int16( nStyle ); + + rBorderLine.LineStyle = eStyle; +} + + + + +XMLBorderWidthHdl::~XMLBorderWidthHdl() +{ + // nothing to do +} + +bool XMLBorderWidthHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + + sal_Int32 nInWidth, nDistance, nOutWidth; + + std::u16string_view aToken; + if( !aTokenEnum.getNextToken( aToken ) ) + return false; + + if (!rUnitConverter.convertMeasureToCore( nInWidth, aToken, 0, 500 )) + return false; + + if( !aTokenEnum.getNextToken( aToken ) ) + return false; + + if (!rUnitConverter.convertMeasureToCore( nDistance, aToken, 0, 500 )) + return false; + + if( !aTokenEnum.getNextToken( aToken ) ) + return false; + + if (!rUnitConverter.convertMeasureToCore( nOutWidth, aToken, 0, 500 )) + return false; + + table::BorderLine2 aBorderLine; + if(!(rValue >>= aBorderLine)) + aBorderLine.Color = 0; + + aBorderLine.InnerLineWidth = sal::static_int_cast< sal_Int16 >(nInWidth); + aBorderLine.OuterLineWidth = sal::static_int_cast< sal_Int16 >(nOutWidth); + aBorderLine.LineDistance = sal::static_int_cast< sal_Int16 >(nDistance); + + rValue <<= aBorderLine; + return true; +} + +bool XMLBorderWidthHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + table::BorderLine2 aBorderLine; + if(!(rValue >>= aBorderLine)) + return false; + + bool bDouble = false; + switch ( aBorderLine.LineStyle ) + { + case table::BorderLineStyle::DOUBLE: + case table::BorderLineStyle::DOUBLE_THIN: + case table::BorderLineStyle::THINTHICK_SMALLGAP: + case table::BorderLineStyle::THINTHICK_MEDIUMGAP: + case table::BorderLineStyle::THINTHICK_LARGEGAP: + case table::BorderLineStyle::THICKTHIN_SMALLGAP: + case table::BorderLineStyle::THICKTHIN_MEDIUMGAP: + case table::BorderLineStyle::THICKTHIN_LARGEGAP: + bDouble = true; + break; + default: + break; + } + + if( ( aBorderLine.LineDistance == 0 && aBorderLine.InnerLineWidth == 0 ) || !bDouble ) + return false; + + rUnitConverter.convertMeasureToXML( aOut, aBorderLine.InnerLineWidth ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aBorderLine.LineDistance ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, aBorderLine.OuterLineWidth ); + + rStrExpValue = aOut.makeStringAndClear(); + return true; +} + + + + +XMLBorderHdl::~XMLBorderHdl() +{ + // nothing to do +} + +bool XMLBorderHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + std::u16string_view aToken; + SvXMLTokenEnumerator aTokens( rStrImpValue ); + + bool bHasStyle = false; + bool bHasWidth = false; + bool bHasColor = false; + + sal_uInt16 nStyle = USHRT_MAX; + sal_uInt16 nWidth = 0; + sal_uInt16 nNamedWidth = USHRT_MAX; + sal_Int32 nColor = 0; + + sal_Int32 nTemp; + while( aTokens.getNextToken( aToken ) && !aToken.empty() ) + { + if( !bHasWidth && + SvXMLUnitConverter::convertEnum( nNamedWidth, aToken, + pXML_NamedBorderWidths ) ) + { + bHasWidth = true; + } + else if( !bHasStyle && + SvXMLUnitConverter::convertEnum( nStyle, aToken, + pXML_BorderStyles ) ) + { + bHasStyle = true; + } + else if (!bHasColor && ::sax::Converter::convertColor(nColor, aToken)) + { + bHasColor = true; + } + else if( !bHasWidth && + rUnitConverter.convertMeasureToCore( nTemp, aToken, 0, + USHRT_MAX ) ) + { + nWidth = static_cast(nTemp); + bHasWidth = true; + } + else + { + // misformed + return false; + } + } + + // if there is no style or a different style than none but no width, + // then the declaration is not valid. + if (!bHasStyle || (table::BorderLineStyle::NONE != nStyle && !bHasWidth)) + return false; + + table::BorderLine2 aBorderLine; + if(!(rValue >>= aBorderLine)) + { + aBorderLine.Color = 0; + aBorderLine.InnerLineWidth = 0; + aBorderLine.OuterLineWidth = 0; + aBorderLine.LineDistance = 0; + aBorderLine.LineWidth = 0; + } + + // first of all, delete an empty line + if (table::BorderLineStyle::NONE == nStyle || + (bHasWidth && USHRT_MAX == nNamedWidth && 0 == nWidth) ) + { + aBorderLine.InnerLineWidth = 0; + aBorderLine.OuterLineWidth = 0; + aBorderLine.LineDistance = 0; + aBorderLine.LineWidth = 0; + } + else + { + if( USHRT_MAX != nNamedWidth ) + { + aBorderLine.LineWidth = aBorderWidths[nNamedWidth]; + } + else + { + aBorderLine.LineWidth = nWidth; + lcl_frmitems_setXMLBorderStyle( aBorderLine, nStyle ); + } + } + + // set color + if( bHasColor ) + { + aBorderLine.Color = nColor; + } + + rValue <<= aBorderLine; + return true; +} + +bool XMLBorderHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& /* rUnitConverter */ ) const +{ + OUStringBuffer aOut; + + table::BorderLine2 aBorderLine; + if(!(rValue >>= aBorderLine)) + return false; + + sal_Int32 nWidth = aBorderLine.LineWidth; + + if( nWidth == 0 ) + { + aOut.append( GetXMLToken( XML_NONE ) ); + } + else + { + ::sax::Converter::convertMeasure( aOut, nWidth, + util::MeasureUnit::MM_100TH, util::MeasureUnit::POINT); + + aOut.append( ' ' ); + + XMLTokenEnum eStyleToken = XML_SOLID; + switch ( aBorderLine.LineStyle ) + { + case table::BorderLineStyle::DASHED: + eStyleToken = XML_DASHED; + break; + case table::BorderLineStyle::DOTTED: + eStyleToken = XML_DOTTED; + break; + case table::BorderLineStyle::DOUBLE: + case table::BorderLineStyle::THINTHICK_SMALLGAP: + case table::BorderLineStyle::THINTHICK_MEDIUMGAP: + case table::BorderLineStyle::THINTHICK_LARGEGAP: + case table::BorderLineStyle::THICKTHIN_SMALLGAP: + case table::BorderLineStyle::THICKTHIN_MEDIUMGAP: + case table::BorderLineStyle::THICKTHIN_LARGEGAP: + eStyleToken = XML_DOUBLE; + break; + case table::BorderLineStyle::EMBOSSED: + eStyleToken = XML_RIDGE; + break; + case table::BorderLineStyle::ENGRAVED: + eStyleToken = XML_GROOVE; + break; + case table::BorderLineStyle::OUTSET: + eStyleToken = XML_OUTSET; + break; + case table::BorderLineStyle::INSET: + eStyleToken = XML_INSET; + break; + case table::BorderLineStyle::FINE_DASHED: + eStyleToken = XML_FINE_DASHED; + break; + case table::BorderLineStyle::DASH_DOT: + eStyleToken = XML_DASH_DOT; + break; + case table::BorderLineStyle::DASH_DOT_DOT: + eStyleToken = XML_DASH_DOT_DOT; + break; + case table::BorderLineStyle::DOUBLE_THIN: + eStyleToken = XML_DOUBLE_THIN; + break; + case table::BorderLineStyle::SOLID: + default: + break; + } + aOut.append( GetXMLToken( eStyleToken ) ); + + aOut.append( ' ' ); + + ::sax::Converter::convertColor( aOut, aBorderLine.Color ); + } + + rStrExpValue = aOut.makeStringAndClear(); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/bordrhdl.hxx b/xmloff/source/style/bordrhdl.hxx new file mode 100644 index 000000000..3741fc3a7 --- /dev/null +++ b/xmloff/source/style/bordrhdl.hxx @@ -0,0 +1,45 @@ +/* -*- 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLBorderWidthHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLBorderWidthHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLBorderHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLBorderHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/breakhdl.cxx b/xmloff/source/style/breakhdl.cxx new file mode 100644 index 000000000..d1490881f --- /dev/null +++ b/xmloff/source/style/breakhdl.cxx @@ -0,0 +1,179 @@ +/* -*- 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 "breakhdl.hxx" +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_BreakTypes[] = +{ + { XML_AUTO, 0 }, + { XML_COLUMN, 1 }, + { XML_PAGE, 2 }, + { XML_EVEN_PAGE, 2 }, + { XML_ODD_PAGE, 2 }, + { XML_TOKEN_INVALID, 0} +}; + + + + +XMLFmtBreakBeforePropHdl::~XMLFmtBreakBeforePropHdl() +{ + // Nothing to do +} + +bool XMLFmtBreakBeforePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nEnum; + bool bRet = SvXMLUnitConverter::convertEnum( nEnum, rStrImpValue, pXML_BreakTypes ); + if( bRet ) + { + style::BreakType eBreak; + switch ( nEnum ) + { + case 0: + eBreak = style::BreakType_NONE; + break; + case 1: + eBreak = style::BreakType_COLUMN_BEFORE; + break; + default: + eBreak = style::BreakType_PAGE_BEFORE; + break; + } + rValue <<= eBreak; + } + + return bRet; +} + +bool XMLFmtBreakBeforePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + style::BreakType eBreak; + + if( !( rValue >>= eBreak ) ) + { + sal_Int32 nValue = 0; + if( !( rValue >>= nValue ) ) + return false; + + eBreak = static_cast(nValue); + } + + sal_uInt16 nEnum = 0; + switch( eBreak ) + { + case style::BreakType_COLUMN_BEFORE: + nEnum = 1; + break; + case style::BreakType_PAGE_BEFORE: + nEnum = 2; + break; + case style::BreakType_NONE: + nEnum = 0; + break; + default: + return false; + } + + OUStringBuffer aOut; + /* bool bOk = */ SvXMLUnitConverter::convertEnum( aOut, nEnum, pXML_BreakTypes ); + rStrExpValue = aOut.makeStringAndClear(); + + return true; +} + + + + +XMLFmtBreakAfterPropHdl::~XMLFmtBreakAfterPropHdl() +{ + // Nothing to do +} + +bool XMLFmtBreakAfterPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nEnum; + bool bRet = SvXMLUnitConverter::convertEnum( nEnum, rStrImpValue, pXML_BreakTypes ); + if( bRet ) + { + style::BreakType eBreak; + switch ( nEnum ) + { + case 0: + eBreak = style::BreakType_NONE; + break; + case 1: + eBreak = style::BreakType_COLUMN_AFTER; + break; + default: + eBreak = style::BreakType_PAGE_AFTER; + break; + } + rValue <<= eBreak; + } + + return bRet; +} + +bool XMLFmtBreakAfterPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + style::BreakType eBreak; + + if( !( rValue >>= eBreak ) ) + { + sal_Int32 nValue = 0; + if( !( rValue >>= nValue ) ) + return false; + + eBreak = static_cast(nValue); + } + + sal_uInt16 nEnum = 0; + switch( eBreak ) + { + case style::BreakType_COLUMN_AFTER: + nEnum = 1; + break; + case style::BreakType_PAGE_AFTER: + nEnum = 2; + break; + case style::BreakType_NONE: + nEnum = 0; + break; + default: + return false; + } + + OUStringBuffer aOut; + /* bool bOk = */ SvXMLUnitConverter::convertEnum( aOut, nEnum, pXML_BreakTypes ); + rStrExpValue = aOut.makeStringAndClear(); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/breakhdl.hxx b/xmloff/source/style/breakhdl.hxx new file mode 100644 index 000000000..c38e33ba6 --- /dev/null +++ b/xmloff/source/style/breakhdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFmtBreakBeforePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFmtBreakBeforePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFmtBreakAfterPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFmtBreakAfterPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/cdouthdl.cxx b/xmloff/source/style/cdouthdl.cxx new file mode 100644 index 000000000..0b484dcf0 --- /dev/null +++ b/xmloff/source/style/cdouthdl.cxx @@ -0,0 +1,305 @@ +/* -*- 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 "cdouthdl.hxx" +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::awt; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_CrossedoutType_Enum[] = +{ + { XML_NONE, awt::FontStrikeout::NONE }, + { XML_SINGLE, awt::FontStrikeout::SINGLE }, + { XML_DOUBLE, awt::FontStrikeout::DOUBLE }, + { XML_SINGLE, awt::FontStrikeout::BOLD }, + { XML_SINGLE, awt::FontStrikeout::SLASH }, + { XML_SINGLE, awt::FontStrikeout::X }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_CrossedoutStyle_Enum[] = +{ + { XML_NONE, awt::FontStrikeout::NONE }, + { XML_SOLID, awt::FontStrikeout::SINGLE }, + { XML_SOLID, awt::FontStrikeout::DOUBLE }, + { XML_SOLID, awt::FontStrikeout::BOLD }, + { XML_SOLID, awt::FontStrikeout::SLASH }, + { XML_SOLID, awt::FontStrikeout::X }, + { XML_DOTTED, awt::FontStrikeout::SINGLE }, + { XML_DASH, awt::FontStrikeout::SINGLE }, + { XML_LONG_DASH, awt::FontStrikeout::SINGLE }, + { XML_DOT_DASH, awt::FontStrikeout::SINGLE }, + { XML_DOT_DOT_DASH, awt::FontStrikeout::SINGLE }, + { XML_WAVE, awt::FontStrikeout::SINGLE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_CrossedoutWidth_Enum[] = +{ + { XML_AUTO, awt::FontStrikeout::NONE }, + { XML_AUTO, awt::FontStrikeout::SINGLE }, + { XML_AUTO, awt::FontStrikeout::DOUBLE }, + { XML_BOLD, awt::FontStrikeout::BOLD }, + { XML_AUTO, awt::FontStrikeout::SLASH }, + { XML_AUTO, awt::FontStrikeout::X }, + { XML_THIN, awt::FontStrikeout::NONE }, + { XML_MEDIUM, awt::FontStrikeout::NONE }, + { XML_THICK, awt::FontStrikeout::NONE }, + { XML_TOKEN_INVALID, 0 } +}; + + +XMLCrossedOutTypePropHdl::~XMLCrossedOutTypePropHdl() +{ + // nothing to do +} + +bool XMLCrossedOutTypePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewStrikeout = 0; + bool bRet = SvXMLUnitConverter::convertEnum( + eNewStrikeout, rStrImpValue, pXML_CrossedoutType_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eStrikeout = sal_Int16(); + if( (rValue >>= eStrikeout) && awt::FontStrikeout::NONE!=eStrikeout ) + { + switch( eNewStrikeout ) + { + case awt::FontStrikeout::NONE: + case awt::FontStrikeout::SINGLE: + // keep existing line style + eNewStrikeout = eStrikeout; + break; + case awt::FontStrikeout::DOUBLE: + // A double line style has priority over a solid or a bold + // line style, + // but not about any other line style + switch( eStrikeout ) + { + case awt::FontStrikeout::SINGLE: + case awt::FontStrikeout::BOLD: + break; + default: + // If a double line style is not supported for the existing + // value, keep the new one + eNewStrikeout = eStrikeout; + break; + } + break; + default: + OSL_ENSURE( bRet, "unexpected line type value" ); + break; + } + if( eNewStrikeout != eStrikeout ) + rValue <<= static_cast(eNewStrikeout); + } + else + { + rValue <<= static_cast(eNewStrikeout); + } + } + + return bRet; +} + +bool XMLCrossedOutTypePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if (rValue >>= nValue) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_CrossedoutType_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + +XMLCrossedOutStylePropHdl::~XMLCrossedOutStylePropHdl() +{ + // nothing to do +} + +bool XMLCrossedOutStylePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewStrikeout(0); + bool bRet = SvXMLUnitConverter::convertEnum( + eNewStrikeout, rStrImpValue, pXML_CrossedoutStyle_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eStrikeout = sal_Int16(); + if( (rValue >>= eStrikeout) && awt::FontStrikeout::NONE!=eStrikeout ) + { + // one NONE a SINGLE are possible new values. For both, the + // existing value is kept. + } + else + { + rValue <<= static_cast(eNewStrikeout); + } + } + + return bRet; +} + +bool XMLCrossedOutStylePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_CrossedoutStyle_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + +XMLCrossedOutWidthPropHdl::~XMLCrossedOutWidthPropHdl() +{ + // nothing to do +} + +bool XMLCrossedOutWidthPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewStrikeout = 0; + bool bRet = SvXMLUnitConverter::convertEnum( + eNewStrikeout, rStrImpValue, pXML_CrossedoutWidth_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eStrikeout = sal_Int16(); + if( (rValue >>= eStrikeout) && awt::FontStrikeout::NONE!=eStrikeout ) + { + switch( eNewStrikeout ) + { + case awt::FontStrikeout::NONE: + // keep existing line style + eNewStrikeout = eStrikeout; + break; + case awt::FontStrikeout::BOLD: + switch( eStrikeout ) + { + case awt::FontStrikeout::SINGLE: + break; + default: + // If a double line style is not supported for the existing + // value, keep the new one + eNewStrikeout = eStrikeout; + break; + } + break; + default: + OSL_ENSURE( bRet, "unexpected line type value" ); + break; + } + if( eNewStrikeout != eStrikeout ) + rValue <<= static_cast(eNewStrikeout); + } + else + { + rValue <<= static_cast(eNewStrikeout); + } + } + + return bRet; +} + +bool XMLCrossedOutWidthPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( (rValue >>= nValue) && (awt::FontStrikeout::BOLD == nValue) ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_CrossedoutWidth_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + +XMLCrossedOutTextPropHdl::~XMLCrossedOutTextPropHdl() +{ + // nothing to do +} + +bool XMLCrossedOutTextPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( !rStrImpValue.isEmpty() ) + { + sal_Int16 eStrikeout = ('/' == rStrImpValue[0] + ? awt::FontStrikeout::SLASH + : awt::FontStrikeout::X); + rValue <<= eStrikeout; + bRet = true; + } + + return bRet; +} + +bool XMLCrossedOutTextPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int16 nValue = sal_Int16(); + + if( (rValue >>= nValue) && + (awt::FontStrikeout::SLASH == nValue || awt::FontStrikeout::X == nValue) ) + { + rStrExpValue = OUString( + static_cast< sal_Unicode>( awt::FontStrikeout::SLASH == nValue ? '/' + : 'X' ) ); + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/cdouthdl.hxx b/xmloff/source/style/cdouthdl.hxx new file mode 100644 index 000000000..70f9ddbba --- /dev/null +++ b/xmloff/source/style/cdouthdl.hxx @@ -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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLCrossedOutTypePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCrossedOutTypePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCrossedOutStylePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCrossedOutStylePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCrossedOutWidthPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCrossedOutWidthPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCrossedOutTextPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCrossedOutTextPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/chrhghdl.cxx b/xmloff/source/style/chrhghdl.cxx new file mode 100644 index 000000000..5417800c6 --- /dev/null +++ b/xmloff/source/style/chrhghdl.cxx @@ -0,0 +1,150 @@ +/* -*- 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 "chrhghdl.hxx" + +#include + +#include + +#include + +#include + +using namespace ::com::sun::star; + + + + +XMLCharHeightHdl::~XMLCharHeightHdl() +{ + // nothing to do +} + +bool XMLCharHeightHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if( rStrImpValue.indexOf( '%' ) == -1 ) + { + double fSize; + sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString( + rStrImpValue, util::MeasureUnit::POINT ); + if (::sax::Converter::convertDouble(fSize, rStrImpValue, + eSrcUnit, util::MeasureUnit::POINT)) + { + fSize = ::std::max(fSize, 1.0); // fdo#49876: 0pt is invalid + rValue <<= static_cast(fSize); + return true; + } + } + + return false; +} + +bool XMLCharHeightHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut; + + float fSize = 0; + if( rValue >>= fSize ) + { + fSize = ::std::max(fSize, 1.0f); // fdo#49876: 0pt is invalid + ::sax::Converter::convertDouble(aOut, static_cast(fSize), true, + util::MeasureUnit::POINT, util::MeasureUnit::POINT); + aOut.append( 'p'); + aOut.append( 't'); + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLCharHeightPropHdl::~XMLCharHeightPropHdl() +{ + // nothing to do +} + +bool XMLCharHeightPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if( rStrImpValue.indexOf( '%' ) != -1 ) + { + sal_Int32 nPrc = 100; + if (::sax::Converter::convertPercent( nPrc, rStrImpValue )) + { + rValue <<= static_cast(nPrc); + return true; + } + } + + return false; +} + +bool XMLCharHeightPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut( rStrExpValue ); + + sal_Int16 nValue = sal_Int16(); + if( rValue >>= nValue ) + { + ::sax::Converter::convertPercent( aOut, nValue ); + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLCharHeightDiffHdl::~XMLCharHeightDiffHdl() +{ + // nothing to do +} + +bool XMLCharHeightDiffHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nRel = 0; + + if (::sax::Converter::convertMeasure( nRel, rStrImpValue, + util::MeasureUnit::POINT )) + { + rValue <<= static_cast(nRel); + return true; + } + + return false; +} + +bool XMLCharHeightDiffHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + float nRel = 0; + if( (rValue >>= nRel) && (nRel != 0) ) + { + OUStringBuffer aOut; + ::sax::Converter::convertMeasure( aOut, static_cast(nRel), + util::MeasureUnit::POINT, util::MeasureUnit::POINT ); + rStrExpValue = aOut.makeStringAndClear(); + } + + return !rStrExpValue.isEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/chrhghdl.hxx b/xmloff/source/style/chrhghdl.hxx new file mode 100644 index 000000000..392ffab6f --- /dev/null +++ b/xmloff/source/style/chrhghdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLCharHeightHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharHeightHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharHeightPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharHeightPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharHeightDiffHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharHeightDiffHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/chrlohdl.cxx b/xmloff/source/style/chrlohdl.cxx new file mode 100644 index 000000000..05dd6d770 --- /dev/null +++ b/xmloff/source/style/chrlohdl.cxx @@ -0,0 +1,423 @@ +/* -*- 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 "chrlohdl.hxx" +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +/* TODO-BCP47: this fiddling with Locale is quite ugly and fragile, especially + * for the fo:script temporarily stored in Variant, it would be better to use + * LanguageTagODF but we have that nasty UNO API requirement here. + * => make LanguageTagODF (unpublished) API? */ + +// For runtime performance, instead of converting back and forth between +// css::Locale and LanguageTag to decide if script or tag are +// needed, this code takes advantage of knowledge about the internal +// representation of BCP 47 language tags in a Locale if present as done in a +// LanguageTag. + +XMLCharLanguageHdl::~XMLCharLanguageHdl() +{ + // nothing to do +} + +bool XMLCharLanguageHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const +{ + bool bRet = false; + lang::Locale aLocale1, aLocale2; + + if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) ) + { + bool bEmptyOrScriptVariant1 = (aLocale1.Variant.isEmpty() || aLocale1.Variant[0] == '-'); + bool bEmptyOrScriptVariant2 = (aLocale2.Variant.isEmpty() || aLocale2.Variant[0] == '-'); + if (bEmptyOrScriptVariant1 && bEmptyOrScriptVariant2) + bRet = ( aLocale1.Language == aLocale2.Language ); + else + { + OUString aLanguage1, aLanguage2; + if (bEmptyOrScriptVariant1) + aLanguage1 = aLocale1.Language; + else + aLanguage1 = LanguageTag( aLocale1).getLanguage(); + if (bEmptyOrScriptVariant2) + aLanguage2 = aLocale2.Language; + else + aLanguage2 = LanguageTag( aLocale2).getLanguage(); + bRet = ( aLanguage1 == aLanguage2 ); + } + } + + return bRet; +} + +bool XMLCharLanguageHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + rValue >>= aLocale; + + if( !IsXMLToken(rStrImpValue, XML_NONE) ) + { + if (aLocale.Variant.isEmpty()) + aLocale.Language = rStrImpValue; + else + { + if (!aLocale.Language.isEmpty() || aLocale.Variant[0] != '-') + { + SAL_WARN_IF( aLocale.Language != I18NLANGTAG_QLT, "xmloff.style", + "XMLCharLanguageHdl::importXML - attempt to import language twice"); + } + else + { + aLocale.Variant = rStrImpValue + aLocale.Variant; + if (!aLocale.Country.isEmpty()) + aLocale.Variant += "-" + aLocale.Country; + aLocale.Language = I18NLANGTAG_QLT; + } + } + } + + rValue <<= aLocale; + return true; +} + +bool XMLCharLanguageHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + if(!(rValue >>= aLocale)) + return false; + + if (aLocale.Variant.isEmpty()) + rStrExpValue = aLocale.Language; + else + { + LanguageTag aLanguageTag( aLocale); + OUString aScript, aCountry; + aLanguageTag.getIsoLanguageScriptCountry( rStrExpValue, aScript, aCountry); + // Do not write *:language='none' for a non-ISO language with + // *:rfc-language-tag that is written if Variant is not empty. If there + // is no match do not write this attribute at all. + if (rStrExpValue.isEmpty()) + return false; + } + + if( rStrExpValue.isEmpty() ) + rStrExpValue = GetXMLToken( XML_NONE ); + + return true; +} + +XMLCharScriptHdl::~XMLCharScriptHdl() +{ + // nothing to do +} + +bool XMLCharScriptHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const +{ + bool bRet = false; + lang::Locale aLocale1, aLocale2; + + if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) ) + { + bool bEmptyVariant1 = aLocale1.Variant.isEmpty(); + bool bEmptyVariant2 = aLocale2.Variant.isEmpty(); + if (bEmptyVariant1 && bEmptyVariant2) + bRet = true; + else if (bEmptyVariant1 != bEmptyVariant2) + ; // stays false + else + { + OUString aScript1, aScript2; + if (aLocale1.Variant[0] == '-') + aScript1 = aLocale1.Variant.copy(1); + else + aScript1 = LanguageTag( aLocale1).getScript(); + if (aLocale2.Variant[0] == '-') + aScript2 = aLocale2.Variant.copy(1); + else + aScript2 = LanguageTag( aLocale2).getScript(); + bRet = ( aScript1 == aScript2 ); + } + } + + return bRet; +} + +bool XMLCharScriptHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + rValue >>= aLocale; + + if( !IsXMLToken( rStrImpValue, XML_NONE ) ) + { + // Import the script only if we don't have a full BCP 47 language tag + // in Variant yet. + if (aLocale.Variant.isEmpty()) + { + if (aLocale.Language.isEmpty()) + { + SAL_INFO( "xmloff.style", "XMLCharScriptHdl::importXML - script but no language yet"); + // Temporarily store in Variant and hope the best (we will get + // a language later, yes?) + aLocale.Variant = "-" + rStrImpValue; + } + else + { + aLocale.Variant = aLocale.Language + "-" + rStrImpValue; + if (!aLocale.Country.isEmpty()) + aLocale.Variant += "-" + aLocale.Country; + aLocale.Language = I18NLANGTAG_QLT; + } + } + else if (aLocale.Variant[0] == '-') + { + SAL_WARN( "xmloff.style", "XMLCharScriptHdl::importXML - attempt to insert script twice: " + << rStrImpValue << " -> " << aLocale.Variant); + } + else + { + // Assume that if there already is a script or anything else BCP 47 + // it was read by XMLCharRfcLanguageTagHdl() and takes precedence. + // On the other hand, an *:rfc-language-tag without script and a + // *:script ?!? +#if OSL_DEBUG_LEVEL > 0 || defined(DBG_UTIL) + LanguageTag aLanguageTag( aLocale); + if (!aLanguageTag.hasScript()) + { + SAL_WARN( "xmloff.style", "XMLCharScriptHdl::importXML - attempt to insert script over bcp47: " + << rStrImpValue << " -> " << aLanguageTag.getBcp47()); + } +#endif + } + } + + rValue <<= aLocale; + return true; +} + +bool XMLCharScriptHdl::exportXML(OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& rUnitConv) const +{ + lang::Locale aLocale; + if(!(rValue >>= aLocale)) + return false; + + // Do not write script='none' for default script. + + if (aLocale.Variant.isEmpty()) + return false; + + LanguageTag aLanguageTag( aLocale); + if (!aLanguageTag.hasScript()) + return false; + + if (rUnitConv.getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012) + return false; + + OUString aLanguage, aCountry; + aLanguageTag.getIsoLanguageScriptCountry( aLanguage, rStrExpValue, aCountry); + // For non-ISO language it does not make sense to write *:script if + // *:language is not written either, does it? It's all in + // *:rfc-language-tag + return !aLanguage.isEmpty() && !rStrExpValue.isEmpty(); +} + +XMLCharCountryHdl::~XMLCharCountryHdl() +{ + // nothing to do +} + +bool XMLCharCountryHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const +{ + bool bRet = false; + lang::Locale aLocale1, aLocale2; + + if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) ) + bRet = ( aLocale1.Country == aLocale2.Country ); + + return bRet; +} + +bool XMLCharCountryHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + rValue >>= aLocale; + + if( !IsXMLToken( rStrImpValue, XML_NONE ) ) + { + if (aLocale.Country.isEmpty()) + { + aLocale.Country = rStrImpValue; + if (aLocale.Variant.getLength() >= 7 && aLocale.Language == I18NLANGTAG_QLT) + { + // already assembled language tag, at least ll-Ssss and not + // ll-CC or lll-CC + sal_Int32 i = aLocale.Variant.indexOf('-'); // separator to script + if (2 <= i && i < aLocale.Variant.getLength()) + { + i = aLocale.Variant.indexOf( '-', i+1); + if (i < 0) // no other separator + aLocale.Variant += "-" + rStrImpValue; // append country + } + } + } + } + + rValue <<= aLocale; + return true; +} + +bool XMLCharCountryHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + if(!(rValue >>= aLocale)) + return false; + + if (aLocale.Variant.isEmpty()) + rStrExpValue = aLocale.Country; + else + { + LanguageTag aLanguageTag( aLocale); + OUString aLanguage, aScript; + aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, rStrExpValue); + // Do not write *:country='none' for a non-ISO country with + // *:rfc-language-tag that is written if Variant is not empty. If there + // is no match do not write this attribute at all. + if (rStrExpValue.isEmpty()) + return false; + } + + if( rStrExpValue.isEmpty() ) + rStrExpValue = GetXMLToken( XML_NONE ); + + return true; +} + +XMLCharRfcLanguageTagHdl::~XMLCharRfcLanguageTagHdl() +{ + // nothing to do +} + +bool XMLCharRfcLanguageTagHdl::equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const +{ + bool bRet = false; + lang::Locale aLocale1, aLocale2; + + if( ( r1 >>= aLocale1 ) && ( r2 >>= aLocale2 ) ) + bRet = ( aLocale1.Variant == aLocale2.Variant ); + + return bRet; +} + +bool XMLCharRfcLanguageTagHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + lang::Locale aLocale; + rValue >>= aLocale; + + if( !IsXMLToken( rStrImpValue, XML_NONE ) ) + { + // Stored may be a *:rfc-language-tag in violation of ODF v1.3 + // 19.516 style:rfc-language-tag "It shall only be used if its value + // cannot be expressed as a valid combination of the fo:language + // 19.871, fo:script 19.242 and fo:country 19.234 attributes". + // That could override a more detailed fo:* and we also don't want an + // unjustified I18NLANGTAG_QLT extended locale tag, but fetch the + // values in case fo:* doesn't follow. + // Rule out the obvious. + if (rStrImpValue.getLength() < 7) + { + SAL_WARN("xmloff.style","rfc-language-tag too short: {" << rStrImpValue << "} Set: " + << aLocale.Language <<","<< aLocale.Country <<","<< aLocale.Variant); + // Ignore empty and keep Ssss or any earlier qlt already set. + if (!rStrImpValue.isEmpty() && aLocale.Language != I18NLANGTAG_QLT) + { + // Shorter than ll-Ssss, so try ll-CC or lll-CC or ll or lll + sal_Int32 h = rStrImpValue.indexOf('-'); + OUString aLang; + if (2 <= h && h <= 3) + aLang = rStrImpValue.copy(0, h); + else if (h < 0 && 2 <= rStrImpValue.getLength() && rStrImpValue.getLength() <= 3) + aLang = rStrImpValue; + OUString aCoun; + if (!aLang.isEmpty() && aLang.getLength() + 3 == rStrImpValue.getLength()) + aCoun = rStrImpValue.copy( aLang.getLength() + 1); + // Ignore identical value or less information. + if ((!aLang.isEmpty() && aLang != aLocale.Language) || + (!aCoun.isEmpty() && aCoun != aLocale.Country)) + { + // Do not override existing values. + if (aLocale.Language.isEmpty()) + aLocale.Language = aLang; + if (aLocale.Country.isEmpty()) + aLocale.Country = aCoun; + if (aLang != aLocale.Language || aCoun != aLocale.Country) + { + // No match, so we still need the qlt anyway. Whatever.. + aLocale.Variant = rStrImpValue; + aLocale.Language = I18NLANGTAG_QLT; + } + } + else if (aLang.isEmpty() && aCoun.isEmpty()) + { + // Both empty, some other tag. + aLocale.Variant = rStrImpValue; + aLocale.Language = I18NLANGTAG_QLT; + } + } + SAL_WARN("xmloff.style","rfc-language-tag too short: now set: " + << aLocale.Language <<","<< aLocale.Country <<","<< aLocale.Variant); + } + else + { + aLocale.Variant = rStrImpValue; + aLocale.Language = I18NLANGTAG_QLT; + } + } + + rValue <<= aLocale; + return true; +} + +bool XMLCharRfcLanguageTagHdl::exportXML(OUString& rStrExpValue, + const uno::Any& rValue, const SvXMLUnitConverter& rUnitConv) const +{ + lang::Locale aLocale; + if(!(rValue >>= aLocale)) + return false; + + // Do not write rfc-language-tag='none' if BCP 47 is not needed. + if (aLocale.Variant.isEmpty()) + return false; + + if (rUnitConv.getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012) + return false; + + rStrExpValue = aLocale.Variant; + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/chrlohdl.hxx b/xmloff/source/style/chrlohdl.hxx new file mode 100644 index 000000000..a6e710b26 --- /dev/null +++ b/xmloff/source/style/chrlohdl.hxx @@ -0,0 +1,71 @@ +/* -*- 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLCharLanguageHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharLanguageHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharScriptHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharScriptHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharCountryHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharCountryHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCharRfcLanguageTagHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCharRfcLanguageTagHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/csmaphdl.cxx b/xmloff/source/style/csmaphdl.cxx new file mode 100644 index 000000000..4e760a6c9 --- /dev/null +++ b/xmloff/source/style/csmaphdl.cxx @@ -0,0 +1,120 @@ +/* -*- 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 "csmaphdl.hxx" +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +const SvXMLEnumMapEntry pXML_Casemap_Enum[] = +{ + { XML_NONE, style::CaseMap::NONE }, + { XML_CASEMAP_LOWERCASE, style::CaseMap::LOWERCASE }, + { XML_CASEMAP_UPPERCASE, style::CaseMap::UPPERCASE }, + { XML_CASEMAP_CAPITALIZE, style::CaseMap::TITLE }, + { XML_TOKEN_INVALID, 0 } +}; + + +XMLCaseMapPropHdl::~XMLCaseMapPropHdl() +{ + // nothing to do +} + +bool XMLCaseMapPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nVal; + bool bRet = SvXMLUnitConverter::convertEnum( + nVal, rStrImpValue, pXML_Casemap_Enum ); + if( bRet ) + rValue <<= nVal; + + return bRet; +} + +bool XMLCaseMapPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_Casemap_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + +XMLCaseMapVariantHdl::~XMLCaseMapVariantHdl() +{ + // nothing to do +} + +bool XMLCaseMapVariantHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( IsXMLToken( rStrImpValue, XML_CASEMAP_SMALL_CAPS ) ) + { + rValue <<= sal_Int16(style::CaseMap::SMALLCAPS); + bRet = true; + } + else if( IsXMLToken( rStrImpValue, XML_NORMAL ) ) + { + rValue <<= sal_Int16(style::CaseMap::NONE); + bRet = true; + } + + return bRet; +} + +bool XMLCaseMapVariantHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 nValue = sal_uInt16(); + OUStringBuffer aOut; + + if( rValue >>= nValue ) + { + switch( nValue ) + { + case style::CaseMap::NONE: + aOut.append( GetXMLToken(XML_NORMAL) ); + break; + case style::CaseMap::SMALLCAPS: + aOut.append( GetXMLToken(XML_CASEMAP_SMALL_CAPS) ); + break; + } + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/csmaphdl.hxx b/xmloff/source/style/csmaphdl.hxx new file mode 100644 index 000000000..1d80d676a --- /dev/null +++ b/xmloff/source/style/csmaphdl.hxx @@ -0,0 +1,45 @@ +/* -*- 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLCaseMapPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCaseMapPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLCaseMapVariantHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCaseMapVariantHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/durationhdl.cxx b/xmloff/source/style/durationhdl.cxx new file mode 100644 index 000000000..a58181027 --- /dev/null +++ b/xmloff/source/style/durationhdl.cxx @@ -0,0 +1,71 @@ +/* -*- 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 "durationhdl.hxx" +#include +#include +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; + +bool XMLDurationMS16PropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + Duration aDuration; + if (!::sax::Converter::convertDuration( aDuration, rStrImpValue )) + return false; + + // TODO FIXME why is this in centiseconds? Should it be nanoseconds? + // This overflows... 24h == 8640000cs >> 0x7FFF cs == 32767 + // 32767cs = approx 5 minutes and 27.67s + const sal_Int16 nMS = ((aDuration.Hours * 60 + aDuration.Minutes) * 60 + + aDuration.Seconds) * 100 + (aDuration.NanoSeconds / (10*1000*1000)); + rValue <<= nMS; + + return true; +} + +bool XMLDurationMS16PropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int16 nMS = sal_Int16(); + + if(rValue >>= nMS) + { + OUStringBuffer aOut; + Duration aDuration(false, 0, 0, 0, 0, 0, 0, nMS * 10); + ::sax::Converter::convertDuration(aOut, aDuration); + rStrExpValue = aOut.makeStringAndClear(); + return true; + } + + return false; +} + +XMLDurationMS16PropHdl_Impl::~XMLDurationMS16PropHdl_Impl() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/durationhdl.hxx b/xmloff/source/style/durationhdl.hxx new file mode 100644 index 000000000..de5193f60 --- /dev/null +++ b/xmloff/source/style/durationhdl.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/. + * + * 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 + +/** + PropertyHandler for a sal_int16 duration in ms: +*/ +class XMLDurationMS16PropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual ~XMLDurationMS16PropHdl_Impl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/escphdl.cxx b/xmloff/source/style/escphdl.cxx new file mode 100644 index 000000000..8148fb69a --- /dev/null +++ b/xmloff/source/style/escphdl.cxx @@ -0,0 +1,156 @@ +/* -*- 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 "escphdl.hxx" + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + + + +XMLEscapementPropHdl::~XMLEscapementPropHdl() +{ + // nothing to do +} + +bool XMLEscapementPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int16 nVal; + + SvXMLTokenEnumerator aTokens( rStrImpValue ); + + std::u16string_view aToken; + if( ! aTokens.getNextToken( aToken ) ) + return false; + + if( IsXMLToken( aToken, XML_ESCAPEMENT_SUB ) ) + { + nVal = DFLT_ESC_AUTO_SUB; + } + else if( IsXMLToken( aToken, XML_ESCAPEMENT_SUPER ) ) + { + nVal = DFLT_ESC_AUTO_SUPER; + } + else + { + sal_Int32 nNewEsc; + if (!::sax::Converter::convertPercent( nNewEsc, aToken )) + return false; + + nVal = static_cast(nNewEsc); + } + + rValue <<= nVal; + return true; +} + +bool XMLEscapementPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + OUStringBuffer aOut; + + if( rValue >>= nValue ) + { + if( nValue == DFLT_ESC_AUTO_SUPER ) + { + aOut.append( GetXMLToken(XML_ESCAPEMENT_SUPER) ); + } + else if( nValue == DFLT_ESC_AUTO_SUB ) + { + aOut.append( GetXMLToken(XML_ESCAPEMENT_SUB) ); + } + else + { + ::sax::Converter::convertPercent( aOut, nValue ); + } + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLEscapementHeightPropHdl::~XMLEscapementHeightPropHdl() +{ + // nothing to do +} + +bool XMLEscapementHeightPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if( IsXMLToken( rStrImpValue, XML_CASEMAP_SMALL_CAPS ) ) + return false; + + SvXMLTokenEnumerator aTokens( rStrImpValue ); + + std::u16string_view aToken; + if( ! aTokens.getNextToken( aToken ) ) + return false; + + sal_Int8 nProp; + if( aTokens.getNextToken( aToken ) ) + { + sal_Int32 nNewProp; + if (!::sax::Converter::convertPercent( nNewProp, aToken )) + return false; + nProp = static_cast(nNewProp); + } + else + { + sal_Int32 nEscapementPosition=0; + if (::sax::Converter::convertPercent( nEscapementPosition, aToken ) + && (nEscapementPosition == 0)) + { + nProp = 100; //if escapement position is zero and no escapement height is given the default height should be 100percent and not something smaller (#i91800#) + } + else + nProp = sal_Int8(DFLT_ESC_PROP); + } + + rValue <<= nProp; + return true; +} + +bool XMLEscapementHeightPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut( rStrExpValue ); + + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + { + if( !rStrExpValue.isEmpty() ) + aOut.append( ' '); + + ::sax::Converter::convertPercent( aOut, nValue ); + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/escphdl.hxx b/xmloff/source/style/escphdl.hxx new file mode 100644 index 000000000..d52e20f71 --- /dev/null +++ b/xmloff/source/style/escphdl.hxx @@ -0,0 +1,45 @@ +/* -*- 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLEscapementPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLEscapementPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLEscapementHeightPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLEscapementHeightPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/fonthdl.cxx b/xmloff/source/style/fonthdl.cxx new file mode 100644 index 000000000..144de999c --- /dev/null +++ b/xmloff/source/style/fonthdl.cxx @@ -0,0 +1,291 @@ +/* -*- 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 + +#include + +#include "fonthdl.hxx" + +#include + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +static const SvXMLEnumMapEntry* lcl_getFontFamilyGenericMapping() +{ + static SvXMLEnumMapEntry const aFontFamilyGenericMapping[] = + { + { XML_DECORATIVE, FAMILY_DECORATIVE }, + + { XML_MODERN, FAMILY_MODERN }, + { XML_ROMAN, FAMILY_ROMAN }, + { XML_SCRIPT, FAMILY_SCRIPT }, + { XML_SWISS, FAMILY_SWISS }, + { XML_SYSTEM, FAMILY_SYSTEM }, + { XML_TOKEN_INVALID, FontFamily(0) } + }; + return aFontFamilyGenericMapping; +} + +SvXMLEnumMapEntry const aFontPitchMapping[] = +{ + { XML_FIXED, PITCH_FIXED }, + { XML_VARIABLE, PITCH_VARIABLE }, + { XML_TOKEN_INVALID, FontPitch(0) } +}; + + +XMLFontFamilyNamePropHdl::~XMLFontFamilyNamePropHdl() +{ + // Nothing to do +} + +bool XMLFontFamilyNamePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + OUStringBuffer sValue; + sal_Int32 nPos = 0; + + do + { + sal_Int32 nFirst = nPos; + nPos = ::sax::Converter::indexOfComma( rStrImpValue, nPos ); + sal_Int32 nLast = (-1 == nPos ? rStrImpValue.getLength() - 1 : nPos - 1); + + // skip trailing blanks + while( nLast > nFirst && ' ' == rStrImpValue[nLast] ) + nLast--; + + // skip leading blanks + while(nFirst <= nLast && ' ' == rStrImpValue[nFirst]) + nFirst++; + + // remove quotes + sal_Unicode c = nFirst > nLast ? 0 : rStrImpValue[nFirst]; + if( nFirst < nLast && ('\'' == c || '\"' == c) && rStrImpValue[nLast] == c ) + { + nFirst++; + nLast--; + } + + if( nFirst <= nLast ) + { + if( !sValue.isEmpty() ) + sValue.append(';'); + + sValue.append(rStrImpValue.subView(nFirst, nLast-nFirst+1)); + } + + if( -1 != nPos ) + nPos++; + } + while( -1 != nPos ); + + if (!sValue.isEmpty()) + { + rValue <<= sValue.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + +bool XMLFontFamilyNamePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + OUString aStrFamilyName; + + if( rValue >>= aStrFamilyName ) + { + OUStringBuffer sValue( aStrFamilyName.getLength() + 2 ); + sal_Int32 nPos = 0; + do + { + sal_Int32 nFirst = nPos; + nPos = aStrFamilyName.indexOf( ';', nPos ); + sal_Int32 nLast = (-1 == nPos ? aStrFamilyName.getLength() : nPos); + + // Set position to the character behind the ';', so we won't + // forget this. + if( -1 != nPos ) + nPos++; + + // If the property value was empty, we stop now. + // If there is a ';' at the first position, the empty name + // at the start will be removed. + if( 0 == nLast ) + continue; + + // nFirst and nLast now denote the first and last character of + // one font name. + nLast--; + + // skip trailing blanks + while( nLast > nFirst && ' ' == aStrFamilyName[nLast] ) + nLast--; + + // skip leading blanks + while( nFirst <= nLast && ' ' == aStrFamilyName[nFirst] ) + nFirst++; + + if( nFirst <= nLast ) + { + if( !sValue.isEmpty() ) + { + sValue.append( ',' ); + sValue.append( ' ' ); + } + sal_Int32 nLen = nLast-nFirst+1; + OUString sFamily( aStrFamilyName.copy( nFirst, nLen ) ); + bool bQuote = false; + for( sal_Int32 i=0; i < nLen; i++ ) + { + sal_Unicode c = sFamily[i]; + if( ' ' == c || ',' == c ) + { + bQuote = true; + break; + } + } + if( bQuote ) + sValue.append( '\'' ); + sValue.append( sFamily ); + if( bQuote ) + sValue.append( '\'' ); + } + } + while( -1 != nPos ); + + rStrExpValue = sValue.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLFontFamilyPropHdl::~XMLFontFamilyPropHdl() +{ + // Nothing to do +} + +bool XMLFontFamilyPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + FontFamily eNewFamily; + bool bRet = SvXMLUnitConverter::convertEnum( eNewFamily, rStrImpValue, lcl_getFontFamilyGenericMapping() ); + if( bRet ) + rValue <<= static_cast(eNewFamily); + + return bRet; +} + +bool XMLFontFamilyPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + OUStringBuffer aOut; + + sal_Int16 nFamily = sal_Int16(); + if( rValue >>= nFamily ) + { + FontFamily eFamily = static_cast(nFamily); + if( eFamily != FAMILY_DONTKNOW ) + bRet = SvXMLUnitConverter::convertEnum( aOut, eFamily, lcl_getFontFamilyGenericMapping() ); + } + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + + +XMLFontEncodingPropHdl::~XMLFontEncodingPropHdl() +{ + // Nothing to do +} + +bool XMLFontEncodingPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + if( IsXMLToken( rStrImpValue, XML_X_SYMBOL ) ) + rValue <<= sal_Int16(RTL_TEXTENCODING_SYMBOL); + + return true; +} + +bool XMLFontEncodingPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int16 nSet = sal_Int16(); + + if( rValue >>= nSet ) + { + if( static_cast(nSet) == RTL_TEXTENCODING_SYMBOL ) + { + rStrExpValue = GetXMLToken(XML_X_SYMBOL); + bRet = true; + } + } + + return bRet; +} + + +XMLFontPitchPropHdl::~XMLFontPitchPropHdl() +{ + // Nothing to do +} + +bool XMLFontPitchPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + FontPitch eNewPitch; + bool bRet = SvXMLUnitConverter::convertEnum( eNewPitch, rStrImpValue, aFontPitchMapping ); + if( bRet ) + rValue <<= static_cast(eNewPitch); + + return bRet; +} + +bool XMLFontPitchPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int16 nPitch = sal_Int16(); + + FontPitch ePitch = PITCH_DONTKNOW; + if( rValue >>= nPitch ) + ePitch = static_cast(nPitch); + + if( PITCH_DONTKNOW != ePitch ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( aOut, ePitch, aFontPitchMapping, XML_FIXED ); + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/fonthdl.hxx b/xmloff/source/style/fonthdl.hxx new file mode 100644 index 000000000..970cbc273 --- /dev/null +++ b/xmloff/source/style/fonthdl.hxx @@ -0,0 +1,73 @@ +/* -*- 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontFamilyNamePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontFamilyNamePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontFamilyPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontFamilyPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontEncodingPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontEncodingPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontPitchPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontPitchPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/impastpl.cxx b/xmloff/source/style/impastpl.cxx new file mode 100644 index 000000000..42565e08c --- /dev/null +++ b/xmloff/source/style/impastpl.cxx @@ -0,0 +1,716 @@ +/* -*- 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "impastpl.hxx" + +using namespace ::std; + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +// Class XMLAutoStyleFamily +// ctor/dtor class XMLAutoStyleFamily + +XMLAutoStyleFamily::XMLAutoStyleFamily( + XmlStyleFamily nFamily, + const OUString& rStrName, + const rtl::Reference < SvXMLExportPropertyMapper > &rMapper, + const OUString& rStrPrefix, + bool bAsFamily ) : + mnFamily( nFamily ), maStrFamilyName( rStrName), mxMapper( rMapper ), + mnCount( 0 ), mnName( 0 ), maStrPrefix( rStrPrefix ), mbAsFamily( bAsFamily ) +{} + +XMLAutoStyleFamily::XMLAutoStyleFamily( XmlStyleFamily nFamily ) : + mnFamily(nFamily), mnCount(0), mnName(0), mbAsFamily(false) {} + +void XMLAutoStyleFamily::ClearEntries() +{ + m_ParentSet.clear(); +} + +static OUString +data2string(void *data, + const typelib_TypeDescriptionReference *type); + +static OUString +struct2string(void *data, + const typelib_TypeDescription *type) +{ + assert(type->eTypeClass == typelib_TypeClass_STRUCT); + + OUStringBuffer result; + + result.append("{"); + + const typelib_CompoundTypeDescription *compoundType = + &reinterpret_cast(type)->aBase; + + for (int i = 0; i < compoundType->nMembers; i++) + { + if (i > 0) + result.append(":"); + result.append(compoundType->ppMemberNames[i]); + result.append("="); + result.append(data2string(static_cast(data)+compoundType->pMemberOffsets[i], + compoundType->ppTypeRefs[i])); + } + + result.append("}"); + + return result.makeStringAndClear(); +} + +static OUString +data2string(void *data, + const typelib_TypeDescriptionReference *type) +{ + switch (type->eTypeClass) + { + case typelib_TypeClass_VOID: + return ""; + case typelib_TypeClass_BOOLEAN: + return *static_cast(data) ? OUString("true") : OUString("false"); + case typelib_TypeClass_BYTE: + return OUString::number(*static_cast(data)); + case typelib_TypeClass_SHORT: + return OUString::number(*static_cast(data)); + case typelib_TypeClass_LONG: + return OUString::number(*static_cast(data)); + case typelib_TypeClass_HYPER: + return OUString::number(*static_cast(data)); + case typelib_TypeClass_UNSIGNED_SHORT: + return OUString::number(*static_cast(data)); + case typelib_TypeClass_UNSIGNED_LONG: + return OUString::number((*static_cast(data)), 16); + case typelib_TypeClass_UNSIGNED_HYPER: + return OUString::number((*static_cast(data)), 16); + case typelib_TypeClass_FLOAT: + return OUString::number(*static_cast(data)); + case typelib_TypeClass_DOUBLE: + return OUString::number(*static_cast(data)); + case typelib_TypeClass_CHAR: + return ("U+" + OUString::number(*static_cast(data))); + case typelib_TypeClass_STRING: + return *static_cast(data); + case typelib_TypeClass_TYPE: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_INTERFACE: + return "wtf"; + case typelib_TypeClass_STRUCT: + return struct2string(data, type->pType); + case typelib_TypeClass_ENUM: + return OUString::number(*static_cast(data)); + default: + assert(false); // this cannot happen I hope + break; + } + return ""; +} + +static OUString any2string(const uno::Any& any) +{ + return data2string(const_cast(any.getValue()), any.pType); +} + +// Class SvXMLAutoStylePoolProperties_Impl +// ctor class SvXMLAutoStylePoolProperties_Impl + +XMLAutoStylePoolProperties::XMLAutoStylePoolProperties( XMLAutoStyleFamily& rFamilyData, vector< XMLPropertyState >&& rProperties, OUString const & rParentName ) +: maProperties( std::move(rProperties) ), + mnPos ( rFamilyData.mnCount ) +{ + static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr); + + if (bHack) + { + OUStringBuffer aStemBuffer(32); + aStemBuffer.append( rFamilyData.maStrPrefix ); + + if (!rParentName.isEmpty()) + { + aStemBuffer.append("-"); + aStemBuffer.append(rParentName); + } + + // Create a name based on the properties used + for(XMLPropertyState const & rState : maProperties) + { + if (rState.mnIndex == -1) + continue; + OUString sXMLName(rFamilyData.mxMapper->getPropertySetMapper()->GetEntryXMLName(rState.mnIndex)); + if (sXMLName.isEmpty()) + continue; + aStemBuffer.append("-"); + aStemBuffer.append(static_cast(rFamilyData.mxMapper->getPropertySetMapper()->GetEntryNameSpace(rState.mnIndex))); + aStemBuffer.append(":"); + aStemBuffer.append(sXMLName); + aStemBuffer.append("="); + aStemBuffer.append(any2string(rState.maValue)); + } + +#if 0 + // Finally append an incremental counter in an attempt to make identical + // styles always come out in the same order. Will see if this works. + aStemBuffer.append("-z"); + static sal_Int32 nCounter = 0; + aStemBuffer.append(nCounter++)); +#endif + + // create a name that hasn't been used before. The created name has not + // to be added to the array, because it will never tried again + OUStringBuffer aTry( aStemBuffer ); + + msName = aTry.makeStringAndClear(); + bool bWarned = false; + while (rFamilyData.maNameSet.find(msName) != + rFamilyData.maNameSet.end()) + { + if (!bWarned) + SAL_WARN("xmloff", "Overlapping style name for " << msName); + bWarned = true; + rFamilyData.mnName++; + aTry.append( aStemBuffer ); + aTry.append( "-" ); + aTry.append( static_cast(rFamilyData.mnName) ); + msName = aTry.makeStringAndClear(); + } + rFamilyData.maNameSet.insert(msName); + } + else + { + // create a name that hasn't been used before. The created name has not + // to be added to the array, because it will never tried again + OUStringBuffer sBuffer( 7 ); + do + { + rFamilyData.mnName++; + sBuffer.append( rFamilyData.maStrPrefix ); + sBuffer.append( static_cast(rFamilyData.mnName) ); + msName = sBuffer.makeStringAndClear(); + } + while (rFamilyData.maNameSet.find(msName) != rFamilyData.maNameSet.end() || rFamilyData.maReservedNameSet.find(msName) != rFamilyData.maReservedNameSet.end()); + } + +#if OSL_DEBUG_LEVEL > 0 + std::set DebugProperties; + for (XMLPropertyState const & rPropState : maProperties) + { + sal_Int32 const property(rPropState.mnIndex); + // serious bug: will cause duplicate attributes to be exported + assert(DebugProperties.find(property) == DebugProperties.end()); + if (-1 != property) + { + DebugProperties.insert(property); + } + } +#endif +} + +bool operator<( const XMLAutoStyleFamily& r1, const XMLAutoStyleFamily& r2) +{ + return r1.mnFamily < r2.mnFamily; +} + + +XMLAutoStylePoolParent::~XMLAutoStylePoolParent() +{ +} + +namespace { + +struct ComparePartial +{ + const XMLAutoStyleFamily& rFamilyData; + + bool operator()(const vector< XMLPropertyState >& lhs, + const std::unique_ptr& rhs) const + { + return rFamilyData.mxMapper->LessPartial(lhs, rhs->GetProperties()); + } + bool operator()(const std::unique_ptr& lhs, + const vector< XMLPropertyState >& rhs ) const + { + return rFamilyData.mxMapper->LessPartial(lhs->GetProperties(), rhs); + } +}; + +} + +// Adds an array of XMLPropertyState ( vector< XMLPropertyState > ) to list +// if not added, yet. + +bool XMLAutoStylePoolParent::Add( XMLAutoStyleFamily& rFamilyData, vector< XMLPropertyState >&& rProperties, OUString& rName, bool bDontSeek ) +{ + XMLAutoStylePoolProperties *pProperties = nullptr; + auto [itBegin, itEnd] = std::equal_range(m_PropertiesList.begin(), m_PropertiesList.end(), rProperties, ComparePartial{rFamilyData}); + if (!bDontSeek) + for (auto it = itBegin; it != itEnd; ++it) + if (rFamilyData.mxMapper->Equals((*it)->GetProperties(), rProperties)) + pProperties = it->get(); + + bool bAdded = false; + if( bDontSeek || !pProperties ) + { + pProperties = new XMLAutoStylePoolProperties( rFamilyData, std::move(rProperties), msParent ); + m_PropertiesList.insert(itBegin, std::unique_ptr(pProperties)); + bAdded = true; + } + + rName = pProperties->GetName(); + + return bAdded; +} + + +// Adds an array of XMLPropertyState ( vector< XMLPropertyState > ) with a given name. +// If the name exists already, nothing is done. If a style with a different name and +// the same properties exists, a new one is added (like with bDontSeek). + + +bool XMLAutoStylePoolParent::AddNamed( XMLAutoStyleFamily& rFamilyData, vector< XMLPropertyState >&& rProperties, const OUString& rName ) +{ + if (rFamilyData.maNameSet.find(rName) != rFamilyData.maNameSet.end()) + return false; + + auto it = std::lower_bound(m_PropertiesList.begin(), m_PropertiesList.end(), rProperties, ComparePartial{rFamilyData}); + + std::unique_ptr pProperties( + new XMLAutoStylePoolProperties(rFamilyData, std::move(rProperties), msParent)); + // ignore the generated name + pProperties->SetName( rName ); + m_PropertiesList.insert(it, std::move(pProperties)); + return true; +} + + +// Search for an array of XMLPropertyState ( vector< XMLPropertyState > ) in list + + +OUString XMLAutoStylePoolParent::Find( const XMLAutoStyleFamily& rFamilyData, const vector< XMLPropertyState >& rProperties ) const +{ + OUString sName; + auto [itBegin,itEnd] = std::equal_range(m_PropertiesList.begin(), m_PropertiesList.end(), rProperties, ComparePartial{rFamilyData}); + for (auto it = itBegin; it != itEnd; ++it) + if (rFamilyData.mxMapper->Equals((*it)->GetProperties(), rProperties)) + sName = (*it)->GetName(); + + return sName; +} + +bool XMLAutoStylePoolParent::operator< (const XMLAutoStylePoolParent& rOther) const +{ + return msParent < rOther.msParent; +} + +// Class SvXMLAutoStylePool_Impl +// ctor/dtor class SvXMLAutoStylePool_Impl + +SvXMLAutoStylePoolP_Impl::SvXMLAutoStylePoolP_Impl( SvXMLExport& rExp) + : rExport( rExp ) +{ +} + +SvXMLAutoStylePoolP_Impl::~SvXMLAutoStylePoolP_Impl() +{ +} + +// Adds stylefamily-information to sorted list + +void SvXMLAutoStylePoolP_Impl::AddFamily( + XmlStyleFamily nFamily, + const OUString& rStrName, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper, + const OUString& rStrPrefix, + bool bAsFamily ) +{ + // store family in a list if not already stored + SvXMLExportFlags nExportFlags = GetExport().getExportFlags(); + bool bStylesOnly = (nExportFlags & SvXMLExportFlags::STYLES) && !(nExportFlags & SvXMLExportFlags::CONTENT); + + OUString aPrefix( rStrPrefix ); + if( bStylesOnly ) + { + aPrefix = "M" + rStrPrefix; + } + +#if OSL_DEBUG_LEVEL > 0 + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + if (iter != m_FamilySet.end()) + { + // FIXME: do we really intend to replace the previous nFamily + // entry in this case ? + SAL_WARN_IF( (*iter)->mxMapper != rMapper, "xmloff", + "Adding duplicate family " << rStrName << + " with mismatching mapper ! " << + typeid((*iter)->mxMapper.get()).name() << " " << + typeid(*rMapper).name() ); + } +#endif + + m_FamilySet.insert(std::make_unique(nFamily, rStrName, rMapper, aPrefix, bAsFamily)); +} + +void SvXMLAutoStylePoolP_Impl::SetFamilyPropSetMapper( + XmlStyleFamily nFamily, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper ) +{ + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + if (iter != m_FamilySet.end()) + (*iter)->mxMapper = rMapper; +} + +// Adds a name to list +void SvXMLAutoStylePoolP_Impl::RegisterName( XmlStyleFamily nFamily, const OUString& rName ) +{ + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + (*iter)->maNameSet.insert(rName); +} + +// Adds a name to list +void SvXMLAutoStylePoolP_Impl::RegisterDefinedName( XmlStyleFamily nFamily, const OUString& rName ) +{ + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + (*iter)->maReservedNameSet.insert(rName); +} + + +// Retrieve the list of registered names + + +void SvXMLAutoStylePoolP_Impl::GetRegisteredNames( + uno::Sequence& rFamilies, + uno::Sequence& rNames ) +{ + // collect registered names + families + vector aFamilies; + vector aNames; + + // iterate over families + for (auto const& aJ : m_FamilySet) + { + XMLAutoStyleFamily &rFamily = *aJ; + + // iterate over names + for (const auto& rName : rFamily.maNameSet) + { + aFamilies.push_back( static_cast(rFamily.mnFamily) ); + aNames.push_back( rName ); + } + } + + // copy the families + names into the sequence types + assert(aFamilies.size() == aNames.size()); + + rFamilies.realloc( aFamilies.size() ); + std::copy( aFamilies.begin(), aFamilies.end(), rFamilies.getArray() ); + + rNames.realloc( aNames.size() ); + std::copy( aNames.begin(), aNames.end(), rNames.getArray() ); +} + +// Adds an array of XMLPropertyState ( vector< XMLPropertyState > ) to list +// if not added, yet. + +bool SvXMLAutoStylePoolP_Impl::Add( + OUString& rName, XmlStyleFamily nFamily, const OUString& rParentName, + ::std::vector< XMLPropertyState >&& rProperties, bool bDontSeek ) +{ + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + + XMLAutoStyleFamily &rFamily = **iter; + + auto itPair = rFamily.m_ParentSet.insert(std::make_unique( + rParentName)); + XMLAutoStylePoolParent& rParent = **itPair.first; + + bool bRet = false; + if (rParent.Add(rFamily, std::move(rProperties), rName, bDontSeek)) + { + rFamily.mnCount++; + bRet = true; + } + + return bRet; +} + +bool SvXMLAutoStylePoolP_Impl::AddNamed( + const OUString& rName, XmlStyleFamily nFamily, const OUString& rParentName, + std::vector< XMLPropertyState >&& rProperties ) +{ + // get family and parent the same way as in Add() + + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + + XMLAutoStyleFamily &rFamily = **iter; + + auto itPair = rFamily.m_ParentSet.insert(std::make_unique( + rParentName)); + XMLAutoStylePoolParent& rParent = **itPair.first; + + bool bRet = false; + if (rParent.AddNamed(rFamily, std::move(rProperties), rName)) + { + rFamily.mnCount++; + bRet = true; + } + + return bRet; +} + + +// Search for an array of XMLPropertyState ( vector< XMLPropertyState > ) in list + + +OUString SvXMLAutoStylePoolP_Impl::Find( XmlStyleFamily nFamily, + const OUString& rParent, + const vector< XMLPropertyState >& rProperties ) const +{ + OUString sName; + + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + + XMLAutoStyleFamily const& rFamily = **iter; + XMLAutoStylePoolParent aTmp(rParent); + auto const it2 = rFamily.m_ParentSet.find(aTmp); + if (it2 != rFamily.m_ParentSet.end()) + { + sName = (*it2)->Find(rFamily, rProperties); + } + + return sName; +} + +std::vector SvXMLAutoStylePoolP_Impl::GetAutoStyleEntries() const +{ + std::vector rReturnVector; + + for (std::unique_ptr const & rFamily : m_FamilySet) + { + rtl::Reference aPropertyMapper = rFamily->mxMapper->getPropertySetMapper(); + for (auto const & rParent : rFamily->m_ParentSet) + { + for (auto const & rProperty : rParent->GetPropertiesList()) + { + rReturnVector.emplace_back(); + xmloff::AutoStyleEntry & rEntry = rReturnVector.back(); + for (XMLPropertyState const & rPropertyState : rProperty->GetProperties()) + { + if (rPropertyState.mnIndex >= 0) + { + OUString sXmlName = aPropertyMapper->GetEntryXMLName(rPropertyState.mnIndex); + rEntry.m_aXmlProperties.emplace_back(sXmlName, rPropertyState.maValue); + } + } + } + } + } + return rReturnVector; +} + +namespace { + +struct AutoStylePoolExport +{ + const OUString* mpParent; + XMLAutoStylePoolProperties* mpProperties; + + AutoStylePoolExport() : mpParent(nullptr), mpProperties(nullptr) {} +}; + +struct StyleComparator +{ + bool operator() (const AutoStylePoolExport& a, const AutoStylePoolExport& b) + { + return (a.mpProperties->GetName() < b.mpProperties->GetName() || + (a.mpProperties->GetName() == b.mpProperties->GetName() && *a.mpParent < *b.mpParent)); + } +}; + +} + +void SvXMLAutoStylePoolP_Impl::exportXML( + XmlStyleFamily nFamily, + const SvXMLAutoStylePoolP *pAntiImpl) const +{ + // Get list of parents for current family (nFamily) + XMLAutoStyleFamily aTemp(nFamily); + auto const iter = m_FamilySet.find(aTemp); + assert(iter != m_FamilySet.end()); // family must be known + + const XMLAutoStyleFamily &rFamily = **iter; + sal_uInt32 nCount = rFamily.mnCount; + + if (!nCount) + return; + + // create, initialize and fill helper-structure (SvXMLAutoStylePoolProperties_Impl) + // which contains a parent-name and a SvXMLAutoStylePoolProperties_Impl + std::vector aExpStyles(nCount); + + for (auto const& it : rFamily.m_ParentSet) + { + XMLAutoStylePoolParent& rParent = *it; + size_t nProperties = rParent.GetPropertiesList().size(); + for( size_t j = 0; j < nProperties; j++ ) + { + XMLAutoStylePoolProperties *const pProperties = + rParent.GetPropertiesList()[j].get(); + sal_uInt32 nPos = pProperties->GetPos(); + assert(nPos < nCount); + assert(!aExpStyles[nPos].mpProperties); + aExpStyles[nPos].mpProperties = pProperties; + aExpStyles[nPos].mpParent = &rParent.GetParent(); + } + } + + static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr); + + if (bHack) + { + + std::sort(aExpStyles.begin(), aExpStyles.end(), StyleComparator()); + + for (size_t i = 0; i < nCount; i++) + { + OUString oldName = aExpStyles[i].mpProperties->GetName(); + sal_Int32 dashIx = oldName.indexOf('-'); + OUString newName = (dashIx > 0 ? oldName.copy(0, dashIx) : oldName) + OUString::number(i); + aExpStyles[i].mpProperties->SetName(newName); + } + } + + + // create string to export for each XML-style. That means for each property-list + + OUString aStrFamilyName = rFamily.maStrFamilyName; + + for( size_t i = 0; i < nCount; i++ ) + { + assert(aExpStyles[i].mpProperties); + + if( aExpStyles[i].mpProperties ) + { + GetExport().AddAttribute( + XML_NAMESPACE_STYLE, XML_NAME, + aExpStyles[i].mpProperties->GetName() ); + + bool bExtensionNamespace = false; + if( rFamily.mbAsFamily ) + { + GetExport().AddAttribute( + XML_NAMESPACE_STYLE, XML_FAMILY, aStrFamilyName ); + if(aStrFamilyName != "graphic" && + aStrFamilyName != "drawing-page" && + aStrFamilyName != "presentation" && + aStrFamilyName != "chart" ) + bExtensionNamespace = true; + } + + if( !aExpStyles[i].mpParent->isEmpty() ) + { + GetExport().AddAttribute( + XML_NAMESPACE_STYLE, XML_PARENT_STYLE_NAME, + GetExport().EncodeStyleName( + *aExpStyles[i].mpParent ) ); + } + + OUString sName; + if( rFamily.mbAsFamily ) + sName = GetXMLToken(XML_STYLE); + else + sName = rFamily.maStrFamilyName; + + pAntiImpl->exportStyleAttributes(GetExport().GetAttrList(), nFamily, + aExpStyles[i].mpProperties->GetProperties(), + *rFamily.mxMapper, GetExport().GetMM100UnitConverter(), + GetExport().GetNamespaceMap()); + + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_STYLE, sName, + true, true ); + + sal_Int32 nStart(-1); + sal_Int32 nEnd(-1); + if (nFamily == XmlStyleFamily::PAGE_MASTER) + { + nStart = 0; + sal_Int32 nIndex = 0; + rtl::Reference< XMLPropertySetMapper > aPropMapper = + rFamily.mxMapper->getPropertySetMapper(); + sal_Int16 nContextID; + while(nIndex < aPropMapper->GetEntryCount() && nEnd == -1) + { + nContextID = aPropMapper->GetEntryContextId( nIndex ); + if (nContextID && ((nContextID & CTF_PM_FLAGMASK) != XML_PM_CTF_START)) + nEnd = nIndex; + nIndex++; + } + if (nEnd == -1) + nEnd = nIndex; + } + + rFamily.mxMapper->exportXML( + GetExport(), + aExpStyles[i].mpProperties->GetProperties(), + nStart, nEnd, SvXmlExportFlags::IGN_WS, bExtensionNamespace ); + + pAntiImpl->exportStyleContent(GetExport().GetDocHandler(), nFamily, + aExpStyles[i].mpProperties->GetProperties(), + *rFamily.mxMapper, GetExport().GetMM100UnitConverter(), + GetExport().GetNamespaceMap()); + } + } +} + +void SvXMLAutoStylePoolP_Impl::ClearEntries() +{ + for (auto & aI : m_FamilySet) + aI->ClearEntries(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/impastpl.hxx b/xmloff/source/style/impastpl.hxx new file mode 100644 index 000000000..4645305e1 --- /dev/null +++ b/xmloff/source/style/impastpl.hxx @@ -0,0 +1,180 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +class SvXMLAutoStylePoolP; +class XMLAutoStylePoolParent; +struct XMLAutoStyleFamily; +class SvXMLExportPropertyMapper; +class SvXMLExport; +enum class XmlStyleFamily; + +// Properties of a pool + +class XMLAutoStylePoolProperties +{ + OUString msName; + ::std::vector< XMLPropertyState > maProperties; + sal_uInt32 mnPos; + +public: + + XMLAutoStylePoolProperties( XMLAutoStyleFamily& rFamilyData, std::vector< XMLPropertyState >&& rProperties, OUString const & rParentname ); + + const OUString& GetName() const { return msName; } + const ::std::vector< XMLPropertyState >& GetProperties() const { return maProperties; } + sal_uInt32 GetPos() const { return mnPos; } + + void SetName( const OUString& rNew ) { msName = rNew; } +}; + +// Parents of AutoStylePool's +class XMLAutoStylePoolParent +{ +public: + typedef std::vector> PropertiesListType; + +private: + OUString msParent; + PropertiesListType m_PropertiesList; + +public: + + explicit XMLAutoStylePoolParent( const OUString & rParent ) : + msParent( rParent ) + { + } + + ~XMLAutoStylePoolParent(); + + bool Add( XMLAutoStyleFamily& rFamilyData, std::vector< XMLPropertyState >&& rProperties, OUString& rName, bool bDontSeek ); + + bool AddNamed( XMLAutoStyleFamily& rFamilyData, std::vector< XMLPropertyState >&& rProperties, const OUString& rName ); + + OUString Find( const XMLAutoStyleFamily& rFamilyData, const ::std::vector< XMLPropertyState >& rProperties ) const; + + const OUString& GetParent() const { return msParent; } + + PropertiesListType& GetPropertiesList() + { + return m_PropertiesList; + } + + bool operator< (const XMLAutoStylePoolParent& rOther) const; +}; + +// Implementationclass for stylefamily-information + +struct XMLAutoStyleFamily +{ + typedef std::set, + comphelper::UniquePtrValueLess> ParentSetType; + + XmlStyleFamily mnFamily; + OUString maStrFamilyName; + rtl::Reference mxMapper; + + ParentSetType m_ParentSet; + std::set maNameSet; + std::set maReservedNameSet; + sal_uInt32 mnCount; + sal_uInt32 mnName; + OUString maStrPrefix; + bool mbAsFamily; + + XMLAutoStyleFamily( XmlStyleFamily nFamily, const OUString& rStrName, + const rtl::Reference& rMapper, + const OUString& rStrPrefix, bool bAsFamily ); + + explicit XMLAutoStyleFamily( XmlStyleFamily nFamily ); + + XMLAutoStyleFamily(const XMLAutoStyleFamily&) = delete; + XMLAutoStyleFamily& operator=(const XMLAutoStyleFamily&) = delete; + + friend bool operator<(const XMLAutoStyleFamily& r1, const XMLAutoStyleFamily& r2); + + void ClearEntries(); +}; + +// Implementationclass of SvXMLAutoStylePool + +class SvXMLAutoStylePoolP_Impl +{ + // A set that finds and sorts based only on mnFamily + typedef std::set, + comphelper::UniquePtrValueLess> FamilySetType; + + SvXMLExport& rExport; + FamilySetType m_FamilySet; + +public: + + explicit SvXMLAutoStylePoolP_Impl( SvXMLExport& rExport ); + ~SvXMLAutoStylePoolP_Impl(); + + SvXMLExport& GetExport() const { return rExport; } + + void AddFamily( XmlStyleFamily nFamily, const OUString& rStrName, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper, + const OUString& rStrPrefix, bool bAsFamily ); + void SetFamilyPropSetMapper( XmlStyleFamily nFamily, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper ); + void RegisterName( XmlStyleFamily nFamily, const OUString& rName ); + void RegisterDefinedName( XmlStyleFamily nFamily, const OUString& rName ); + void GetRegisteredNames( + css::uno::Sequence& aFamilies, + css::uno::Sequence& aNames ); + + bool Add( + OUString& rName, XmlStyleFamily nFamily, + const OUString& rParentName, + std::vector< XMLPropertyState >&& rProperties, + bool bDontSeek = false ); + + bool AddNamed( + const OUString& rName, XmlStyleFamily nFamily, + const OUString& rParentName, + std::vector< XMLPropertyState >&& rProperties ); + + OUString Find( XmlStyleFamily nFamily, const OUString& rParent, + const ::std::vector< XMLPropertyState >& rProperties ) const; + + void exportXML( XmlStyleFamily nFamily, + const SvXMLAutoStylePoolP *pAntiImpl) const; + + void ClearEntries(); + + std::vector GetAutoStyleEntries() const; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/kernihdl.cxx b/xmloff/source/style/kernihdl.cxx new file mode 100644 index 000000000..cee24fe20 --- /dev/null +++ b/xmloff/source/style/kernihdl.cxx @@ -0,0 +1,78 @@ +/* -*- 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 "kernihdl.hxx" +#include +#include + + +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + + + + +XMLKerningPropHdl::~XMLKerningPropHdl() +{ + // nothing to do +} + +bool XMLKerningPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = true; + sal_Int32 nKerning = 0; + + if( ! IsXMLToken( rStrImpValue, XML_NORMAL ) ) + { + bRet = rUnitConverter.convertMeasureToCore( nKerning, rStrImpValue ); + } + + rValue <<= static_cast(nKerning); + + return bRet; +} + +bool XMLKerningPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int16 nValue = sal_Int16(); + + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + + if( nValue == 0 ) + aOut.append( GetXMLToken(XML_NORMAL) ); + else + { + rUnitConverter.convertMeasureToXML( aOut, nValue ); + } + + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/kernihdl.hxx b/xmloff/source/style/kernihdl.hxx new file mode 100644 index 000000000..3f4a7b4f8 --- /dev/null +++ b/xmloff/source/style/kernihdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLKerningPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLKerningPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/lspachdl.cxx b/xmloff/source/style/lspachdl.cxx new file mode 100644 index 000000000..21a3e7dac --- /dev/null +++ b/xmloff/source/style/lspachdl.cxx @@ -0,0 +1,173 @@ +/* -*- 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 "lspachdl.hxx" +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_NORMAL; + + + + +XMLLineHeightHdl::~XMLLineHeightHdl() +{ + // nothing to do +} + +bool XMLLineHeightHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + style::LineSpacing aLSp; + sal_Int32 nTemp = 0; + + if( -1 != rStrImpValue.indexOf( '%' ) ) + { + aLSp.Mode = style::LineSpacingMode::PROP; + if (!::sax::Converter::convertPercent( nTemp, rStrImpValue )) + return false; + aLSp.Height = sal::static_int_cast< sal_Int16 >(nTemp); + } + else if( IsXMLToken( rStrImpValue, XML_NORMAL) ) + { + aLSp.Mode = style::LineSpacingMode::PROP; + aLSp.Height = 100; + } + else + { + aLSp.Mode = style::LineSpacingMode::FIX; + if (!rUnitConverter.convertMeasureToCore( + nTemp, rStrImpValue, 0x0000, 0xffff)) + return false; + aLSp.Height = sal::static_int_cast< sal_Int16 >(nTemp); + } + + rValue <<= aLSp; + return true; +} + +bool XMLLineHeightHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + style::LineSpacing aLSp; + if(!(rValue >>= aLSp)) + return false; + + if( style::LineSpacingMode::PROP != aLSp.Mode && style::LineSpacingMode::FIX != aLSp.Mode ) + return false; + + if( style::LineSpacingMode::PROP == aLSp.Mode ) + { + ::sax::Converter::convertPercent( aOut, aLSp.Height ); + } + else + { + rUnitConverter.convertMeasureToXML( aOut, aLSp.Height ); + } + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLLineHeightAtLeastHdl::~XMLLineHeightAtLeastHdl() +{ + // nothing to do +} + +bool XMLLineHeightAtLeastHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + style::LineSpacing aLSp; + + sal_Int32 nTemp; + aLSp.Mode = style::LineSpacingMode::MINIMUM; + if (!rUnitConverter.convertMeasureToCore( nTemp, rStrImpValue, 0, 0xffff)) + return false; + aLSp.Height = sal::static_int_cast< sal_Int16 >(nTemp); + + rValue <<= aLSp; + return true; +} + +bool XMLLineHeightAtLeastHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + style::LineSpacing aLSp; + if(!(rValue >>= aLSp)) + return false; + + if( style::LineSpacingMode::MINIMUM != aLSp.Mode ) + return false; + + rUnitConverter.convertMeasureToXML( aOut, aLSp.Height ); + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + + + + +XMLLineSpacingHdl::~XMLLineSpacingHdl() +{ + // nothing to do +} + +bool XMLLineSpacingHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + style::LineSpacing aLSp; + sal_Int32 nTemp; + + aLSp.Mode = style::LineSpacingMode::LEADING; + if (!rUnitConverter.convertMeasureToCore( nTemp, rStrImpValue, 0, 0xffff)) + return false; + aLSp.Height = sal::static_int_cast< sal_Int16 >(nTemp); + + rValue <<= aLSp; + return true; +} + +bool XMLLineSpacingHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + OUStringBuffer aOut; + + style::LineSpacing aLSp; + if(!(rValue >>= aLSp)) + return false; + + if( style::LineSpacingMode::LEADING != aLSp.Mode ) + return false; + + rUnitConverter.convertMeasureToXML( aOut, aLSp.Height ); + + rStrExpValue = aOut.makeStringAndClear(); + return !rStrExpValue.isEmpty(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/lspachdl.hxx b/xmloff/source/style/lspachdl.hxx new file mode 100644 index 000000000..b0b4d41d7 --- /dev/null +++ b/xmloff/source/style/lspachdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLLineHeightHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLLineHeightHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLLineHeightAtLeastHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLLineHeightAtLeastHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLLineSpacingHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLLineSpacingHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/numehelp.cxx b/xmloff/source/style/numehelp.cxx new file mode 100644 index 000000000..c375fe3e6 --- /dev/null +++ b/xmloff/source/style/numehelp.cxx @@ -0,0 +1,510 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace xmloff::token; + +constexpr OUStringLiteral gsStandardFormat(u"StandardFormat"); +constexpr OUStringLiteral gsType(u"Type"); +constexpr OUStringLiteral gsCurrencySymbol(u"CurrencySymbol"); +constexpr OUStringLiteral gsCurrencyAbbreviation(u"CurrencyAbbreviation"); + +XMLNumberFormatAttributesExportHelper::XMLNumberFormatAttributesExportHelper( + css::uno::Reference< css::util::XNumberFormatsSupplier > const & xTempNumberFormatsSupplier) + : xNumberFormats(xTempNumberFormatsSupplier.is() ? xTempNumberFormatsSupplier->getNumberFormats() : css::uno::Reference< css::util::XNumberFormats > ()), + pExport(nullptr) +{ +} + +XMLNumberFormatAttributesExportHelper::XMLNumberFormatAttributesExportHelper( + css::uno::Reference< css::util::XNumberFormatsSupplier > const & xTempNumberFormatsSupplier, + SvXMLExport& rTempExport ) +: xNumberFormats(xTempNumberFormatsSupplier.is() ? xTempNumberFormatsSupplier->getNumberFormats() : css::uno::Reference< css::util::XNumberFormats > ()), + pExport(&rTempExport), + sAttrValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_VALUE))), + sAttrDateValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_DATE_VALUE))), + sAttrTimeValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_TIME_VALUE))), + sAttrBooleanValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_BOOLEAN_VALUE))), + sAttrStringValue(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_STRING_VALUE))), + sAttrCurrency(rTempExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, GetXMLToken(XML_CURRENCY))) +{ +} + +XMLNumberFormatAttributesExportHelper::~XMLNumberFormatAttributesExportHelper() +{ +} + +sal_Int16 XMLNumberFormatAttributesExportHelper::GetCellType(const sal_Int32 nNumberFormat, OUString& sCurrency, bool& bIsStandard) +{ + XMLNumberFormat aFormat(nNumberFormat); + XMLNumberFormatSet::iterator aItr(aNumberFormats.find(aFormat)); + XMLNumberFormatSet::iterator aEndItr(aNumberFormats.end()); + if (aItr != aEndItr) + { + bIsStandard = aItr->bIsStandard; + sCurrency = aItr->sCurrency; + return aItr->nType; + } + else + { + aFormat.nType = GetCellType(nNumberFormat, bIsStandard); + aFormat.bIsStandard = bIsStandard; + if ((aFormat.nType & ~util::NumberFormat::DEFINED) == util::NumberFormat::CURRENCY) + if (GetCurrencySymbol(nNumberFormat, aFormat.sCurrency)) + sCurrency = aFormat.sCurrency; + aNumberFormats.insert(aFormat); + return aFormat.nType; + } +} + +void XMLNumberFormatAttributesExportHelper::WriteAttributes(SvXMLExport& rXMLExport, + const sal_Int16 nTypeKey, + const double& rValue, + const OUString& rCurrency, + bool bExportValue) +{ + bool bWasSetTypeAttribute = false; + switch(nTypeKey & ~util::NumberFormat::DEFINED) + { + case 0: + case util::NumberFormat::NUMBER: + case util::NumberFormat::SCIENTIFIC: + case util::NumberFormat::FRACTION: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT); + bWasSetTypeAttribute = true; + [[fallthrough]]; + } + case util::NumberFormat::PERCENT: + { + if (!bWasSetTypeAttribute) + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_PERCENTAGE); + bWasSetTypeAttribute = true; + } + [[fallthrough]]; + } + case util::NumberFormat::CURRENCY: + { + if (!bWasSetTypeAttribute) + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_CURRENCY); + if (!rCurrency.isEmpty()) + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_CURRENCY, rCurrency); + } + + if (bExportValue) + { + OUString sValue( ::rtl::math::doubleToUString( rValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', true)); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE, sValue); + } + } + break; + case util::NumberFormat::DATE: + case util::NumberFormat::DATETIME: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_DATE); + if (bExportValue) + { + if ( rXMLExport.SetNullDateOnUnitConverter() ) + { + OUStringBuffer sBuffer; + rXMLExport.GetMM100UnitConverter().convertDateTime(sBuffer, rValue); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_DATE_VALUE, sBuffer.makeStringAndClear()); + } + } + } + break; + case util::NumberFormat::TIME: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_TIME); + if (bExportValue) + { + OUStringBuffer sBuffer; + ::sax::Converter::convertDuration(sBuffer, rValue); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TIME_VALUE, sBuffer.makeStringAndClear()); + } + } + break; + case util::NumberFormat::LOGICAL: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_BOOLEAN); + if (bExportValue) + { + double fTempValue = rValue; + if (::rtl::math::approxEqual( fTempValue, 1.0 )) + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, XML_TRUE); + } + else + { + if (rValue == 0.0) + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, XML_FALSE); + } + else + { + OUString sValue( ::rtl::math::doubleToUString( + fTempValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', + true)); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, sValue); + } + } + } + } + break; + case util::NumberFormat::TEXT: + { + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_FLOAT); + if (bExportValue) + { + OUString sValue( ::rtl::math::doubleToUString( rValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', true)); + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE, sValue); + } + } + break; + } +} + +bool XMLNumberFormatAttributesExportHelper::GetCurrencySymbol(const sal_Int32 nNumberFormat, OUString& sCurrencySymbol, + uno::Reference const & xNumberFormatsSupplier) +{ + if (xNumberFormatsSupplier.is()) + { + uno::Reference xNumberFormats(xNumberFormatsSupplier->getNumberFormats()); + if (xNumberFormats.is()) + { + try + { + uno::Reference xNumberPropertySet(xNumberFormats->getByKey(nNumberFormat)); + if ( xNumberPropertySet->getPropertyValue(gsCurrencySymbol) >>= sCurrencySymbol) + { + OUString sCurrencyAbbreviation; + if ( xNumberPropertySet->getPropertyValue(gsCurrencyAbbreviation) >>= sCurrencyAbbreviation) + { + if ( !sCurrencyAbbreviation.isEmpty()) + sCurrencySymbol = sCurrencyAbbreviation; + else + { + if ( sCurrencySymbol.getLength() == 1 && sCurrencySymbol.toChar() == NfCurrencyEntry::GetEuroSymbol() ) + sCurrencySymbol = "EUR"; + } + } + return true; + } + } + catch ( uno::Exception& ) + { + OSL_FAIL("Numberformat not found"); + } + } + } + return false; +} + + +sal_Int16 XMLNumberFormatAttributesExportHelper::GetCellType(const sal_Int32 nNumberFormat, bool& bIsStandard, + uno::Reference const & xNumberFormatsSupplier) +{ + if (xNumberFormatsSupplier.is()) + { + uno::Reference xNumberFormats(xNumberFormatsSupplier->getNumberFormats()); + if (xNumberFormats.is()) + { + try + { + uno::Reference xNumberPropertySet(xNumberFormats->getByKey(nNumberFormat)); + xNumberPropertySet->getPropertyValue(gsStandardFormat) >>= bIsStandard; + sal_Int16 nNumberType = sal_Int16(); + if ( xNumberPropertySet->getPropertyValue(gsType) >>= nNumberType ) + { + return nNumberType; + } + } + catch ( uno::Exception& ) + { + OSL_FAIL("Numberformat not found"); + } + } + } + return 0; +} + +void XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes(SvXMLExport& rXMLExport, + const sal_Int32 nNumberFormat, const double& rValue, bool bExportValue) +{ + bool bIsStandard; + sal_Int16 nTypeKey = GetCellType(nNumberFormat, bIsStandard, rXMLExport.GetNumberFormatsSupplier()); + OUString sCurrency; + if ((nTypeKey & ~util::NumberFormat::DEFINED) == util::NumberFormat::CURRENCY) + GetCurrencySymbol(nNumberFormat, sCurrency, rXMLExport.GetNumberFormatsSupplier()); + WriteAttributes(rXMLExport, nTypeKey, rValue, sCurrency, bExportValue); +} + +void XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes(SvXMLExport& rXMLExport, + const OUString& rValue, std::u16string_view rCharacters, + bool bExportValue, bool bExportTypeAttribute) +{ + if (bExportTypeAttribute) + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_STRING); + if (bExportValue && !rValue.isEmpty() && (rValue != rCharacters)) + rXMLExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, rValue); +} + +bool XMLNumberFormatAttributesExportHelper::GetCurrencySymbol(const sal_Int32 nNumberFormat, OUString& rCurrencySymbol) +{ + if (!xNumberFormats.is() && pExport && pExport->GetNumberFormatsSupplier().is()) + xNumberFormats.set(pExport->GetNumberFormatsSupplier()->getNumberFormats()); + + if (xNumberFormats.is()) + { + try + { + uno::Reference xNumberPropertySet(xNumberFormats->getByKey(nNumberFormat)); + if ( xNumberPropertySet->getPropertyValue(gsCurrencySymbol) >>= rCurrencySymbol) + { + OUString sCurrencyAbbreviation; + if ( xNumberPropertySet->getPropertyValue(gsCurrencyAbbreviation) >>= sCurrencyAbbreviation) + { + if ( !sCurrencyAbbreviation.isEmpty()) + rCurrencySymbol = sCurrencyAbbreviation; + else + { + if ( rCurrencySymbol.getLength() == 1 && rCurrencySymbol.toChar() == NfCurrencyEntry::GetEuroSymbol() ) + rCurrencySymbol = "EUR"; + } + } + return true; + } + } + catch ( uno::Exception& ) + { + OSL_FAIL("Numberformat not found"); + } + } + return false; +} + +sal_Int16 XMLNumberFormatAttributesExportHelper::GetCellType(const sal_Int32 nNumberFormat, bool& bIsStandard) +{ + if (!xNumberFormats.is() && pExport && pExport->GetNumberFormatsSupplier().is()) + xNumberFormats.set(pExport->GetNumberFormatsSupplier()->getNumberFormats()); + + if (xNumberFormats.is()) + { + try + { + uno::Reference xNumberPropertySet(xNumberFormats->getByKey(nNumberFormat)); + if (xNumberPropertySet.is()) + { + xNumberPropertySet->getPropertyValue(gsStandardFormat) >>= bIsStandard; + sal_Int16 nNumberType = sal_Int16(); + if ( xNumberPropertySet->getPropertyValue(gsType) >>= nNumberType ) + { + return nNumberType; + } + } + } + catch ( uno::Exception& ) + { + OSL_FAIL("Numberformat not found"); + } + } + return 0; +} + +void XMLNumberFormatAttributesExportHelper::WriteAttributes( + const sal_Int16 nTypeKey, + const double& rValue, + const OUString& rCurrency, + bool bExportValue, sal_uInt16 nNamespace) +{ + if (!pExport) + return; + + bool bWasSetTypeAttribute = false; + OUString sAttrValType = pExport->GetNamespaceMap().GetQNameByKey( nNamespace, GetXMLToken(XML_VALUE_TYPE)); + switch(nTypeKey & ~util::NumberFormat::DEFINED) + { + case 0: + case util::NumberFormat::NUMBER: + case util::NumberFormat::SCIENTIFIC: + case util::NumberFormat::FRACTION: + { + pExport->AddAttribute(sAttrValType, XML_FLOAT); + bWasSetTypeAttribute = true; + [[fallthrough]]; + } + case util::NumberFormat::PERCENT: + { + if (!bWasSetTypeAttribute) + { + pExport->AddAttribute(sAttrValType, XML_PERCENTAGE); + bWasSetTypeAttribute = true; + } + [[fallthrough]]; + } + case util::NumberFormat::CURRENCY: + { + if (!bWasSetTypeAttribute) + { + pExport->AddAttribute(sAttrValType, XML_CURRENCY); + if (!rCurrency.isEmpty()) + pExport->AddAttribute(sAttrCurrency, rCurrency); + } + + if (bExportValue) + { + OUString sValue( ::rtl::math::doubleToUString( rValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', true)); + pExport->AddAttribute(sAttrValue, sValue); + } + } + break; + case util::NumberFormat::DATE: + case util::NumberFormat::DATETIME: + { + pExport->AddAttribute(sAttrValType, XML_DATE); + if (bExportValue) + { + if ( pExport->SetNullDateOnUnitConverter() ) + { + OUStringBuffer sBuffer; + pExport->GetMM100UnitConverter().convertDateTime(sBuffer, rValue); + pExport->AddAttribute(sAttrDateValue, sBuffer.makeStringAndClear()); + } + } + } + break; + case util::NumberFormat::TIME: + { + pExport->AddAttribute(sAttrValType, XML_TIME); + if (bExportValue) + { + OUStringBuffer sBuffer; + ::sax::Converter::convertDuration(sBuffer, rValue); + pExport->AddAttribute(sAttrTimeValue, sBuffer.makeStringAndClear()); + } + } + break; + case util::NumberFormat::LOGICAL: + { + pExport->AddAttribute(sAttrValType, XML_BOOLEAN); + if (bExportValue) + { + double fTempValue = rValue; + if (::rtl::math::approxEqual( fTempValue, 1.0 )) + { + pExport->AddAttribute(sAttrBooleanValue, XML_TRUE); + } + else + { + if (rValue == 0.0) + { + pExport->AddAttribute(sAttrBooleanValue, XML_FALSE); + } + else + { + OUString sValue( ::rtl::math::doubleToUString( + fTempValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', + true)); + pExport->AddAttribute(sAttrBooleanValue, sValue); + } + } + } + } + break; + case util::NumberFormat::TEXT: + { + pExport->AddAttribute(sAttrValType, XML_FLOAT); + if (bExportValue) + { + OUString sValue( ::rtl::math::doubleToUString( rValue, + rtl_math_StringFormat_Automatic, + rtl_math_DecimalPlaces_Max, '.', true)); + pExport->AddAttribute(sAttrValue, sValue); + } + } + break; + } +} + +void XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes( + const sal_Int32 nNumberFormat, const double& rValue, bool bExportValue, + sal_uInt16 nNamespace, bool bExportCurrencySymbol) +{ + if (pExport) + { + bool bIsStandard; + OUString sCurrency; + sal_Int16 nTypeKey = GetCellType(nNumberFormat, sCurrency, bIsStandard); + if(!bExportCurrencySymbol) + sCurrency.clear(); + + WriteAttributes(nTypeKey, rValue, sCurrency, bExportValue, nNamespace); + } + else { + OSL_FAIL("no SvXMLExport given"); + } +} + +void XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes( + const OUString& rValue, std::u16string_view rCharacters, + bool bExportValue, + sal_uInt16 nNamespace) +{ + if (pExport) + { + pExport->AddAttribute(nNamespace, XML_VALUE_TYPE, XML_STRING); + if (bExportValue && !rValue.isEmpty() && (rValue != rCharacters)) + pExport->AddAttribute(sAttrStringValue, rValue); + } + else { + OSL_FAIL("no SvXMLExport given"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/opaquhdl.cxx b/xmloff/source/style/opaquhdl.cxx new file mode 100644 index 000000000..c710d67c6 --- /dev/null +++ b/xmloff/source/style/opaquhdl.cxx @@ -0,0 +1,61 @@ +/* -*- 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 "opaquhdl.hxx" +#include + +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + + +XMLOpaquePropHdl::~XMLOpaquePropHdl() +{ + // nothing to do +} + +bool XMLOpaquePropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue = IsXMLToken( rStrImpValue, XML_FOREGROUND ); + rValue <<= bValue; + + return true; +} + +bool XMLOpaquePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + if( bValue ) + rStrExpValue = GetXMLToken( XML_FOREGROUND ); + else + rStrExpValue = GetXMLToken( XML_BACKGROUND ); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/opaquhdl.hxx b/xmloff/source/style/opaquhdl.hxx new file mode 100644 index 000000000..1d4c193a9 --- /dev/null +++ b/xmloff/source/style/opaquhdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLOpaquePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLOpaquePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/postuhdl.cxx b/xmloff/source/style/postuhdl.cxx new file mode 100644 index 000000000..5e0d5bfbc --- /dev/null +++ b/xmloff/source/style/postuhdl.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/. + * + * 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 "postuhdl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const aPostureGenericMapping[] = +{ + { XML_NORMAL, ITALIC_NONE }, + { XML_ITALIC, ITALIC_NORMAL }, + { XML_POSTURE_OBLIQUE, ITALIC_OBLIQUE }, + { XML_TOKEN_INVALID, FontItalic(0) } +}; + + + + +XMLPosturePropHdl::~XMLPosturePropHdl() +{ + // nothing to do +} + +bool XMLPosturePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + FontItalic ePosture; + bool bRet = SvXMLUnitConverter::convertEnum( ePosture, rStrImpValue, aPostureGenericMapping ); + if( bRet ) + rValue <<= vcl::unohelper::ConvertFontSlant(ePosture); + + return bRet; +} + +bool XMLPosturePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + awt::FontSlant eSlant; + + if( !( rValue >>= eSlant ) ) + { + sal_Int32 nValue = 0; + + if( !( rValue >>= nValue ) ) + return false; + + eSlant = static_cast(nValue); + } + + OUStringBuffer aOut; + bool bRet = SvXMLUnitConverter::convertEnum(aOut, vcl::unohelper::ConvertFontSlant(eSlant), aPostureGenericMapping); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/postuhdl.hxx b/xmloff/source/style/postuhdl.hxx new file mode 100644 index 000000000..b63abd607 --- /dev/null +++ b/xmloff/source/style/postuhdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLPosturePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLPosturePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/prhdlfac.cxx b/xmloff/source/style/prhdlfac.cxx new file mode 100644 index 000000000..ca96e0421 --- /dev/null +++ b/xmloff/source/style/prhdlfac.cxx @@ -0,0 +1,475 @@ +/* -*- 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 + +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include "xmlbahdl.hxx" +#include +#include +#include "cdouthdl.hxx" +#include "csmaphdl.hxx" +#include "fonthdl.hxx" +#include "kernihdl.hxx" +#include "postuhdl.hxx" +#include "shadwhdl.hxx" +#include "shdwdhdl.hxx" +#include "undlihdl.hxx" +#include "weighhdl.hxx" +#include "breakhdl.hxx" +#include "adjushdl.hxx" +#include "escphdl.hxx" +#include "chrhghdl.hxx" +#include "chrlohdl.hxx" +#include "lspachdl.hxx" +#include "bordrhdl.hxx" +#include "tabsthdl.hxx" +#include +#include +#include "durationhdl.hxx" +#include +#include +#include "DrawAspectHdl.hxx" + +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const aXML_ColorMode_EnumMap[] = +{ + { XML_GREYSCALE, drawing::ColorMode_GREYS }, + { XML_MONO, drawing::ColorMode_MONO }, + { XML_WATERMARK, drawing::ColorMode_WATERMARK }, + { XML_STANDARD, drawing::ColorMode_STANDARD }, + { XML_TOKEN_INVALID, drawing::ColorMode(0) } +}; + +SvXMLEnumMapEntry const aXML_HorizontalAdjust_Enum[] = +{ + { XML_LEFT, text::HorizontalAdjust_LEFT }, + { XML_CENTER, text::HorizontalAdjust_CENTER }, + { XML_RIGHT, text::HorizontalAdjust_RIGHT }, + { XML_TOKEN_INVALID, text::HorizontalAdjust(0) } +}; + +// aXML_WritingDirection_Enum is used with and without 'page' +// attribute, so you'll find uses of aXML_WritingDirection_Enum +// directly, as well as &(aXML_WritingDirection_Enum[1]) +SvXMLEnumMapEntry const aXML_WritingDirection_Enum[] = +{ + // aXML_WritingDirection_Enum + { XML_PAGE, text::WritingMode2::PAGE }, + + // &(aXML_WritingDirection_Enum[1]) + { XML_LR_TB, text::WritingMode2::LR_TB }, + { XML_RL_TB, text::WritingMode2::RL_TB }, + { XML_TB_RL, text::WritingMode2::TB_RL }, + { XML_TB_LR, text::WritingMode2::TB_LR }, + { XML_BT_LR, text::WritingMode2::BT_LR }, + + // alternative names of the above, as accepted by XSL + { XML_LR, text::WritingMode2::LR_TB }, + { XML_RL, text::WritingMode2::RL_TB }, + { XML_TB, text::WritingMode2::TB_RL }, + + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_VertPos_Enum[] = +{ + { XML_FROM_TOP, text::VertOrientation::NONE }, + { XML_TOP, text::VertOrientation::TOP }, + { XML_TOP, text::VertOrientation::CHAR_TOP }, // export only + { XML_TOP, text::VertOrientation::LINE_TOP }, // export only + { XML_MIDDLE, text::VertOrientation::CENTER }, + { XML_MIDDLE, text::VertOrientation::CHAR_CENTER }, // export only + { XML_MIDDLE, text::VertOrientation::LINE_CENTER }, // export only + { XML_BOTTOM, text::VertOrientation::BOTTOM }, + { XML_BOTTOM, text::VertOrientation::CHAR_BOTTOM }, // export only + { XML_BOTTOM, text::VertOrientation::LINE_BOTTOM }, // export only + { XML_BELOW, text::VertOrientation::CHAR_BOTTOM }, // import only + { XML_TOKEN_INVALID, 0 } +}; + +typedef std::map CacheMap; + +struct XMLPropertyHandlerFactory::Impl +{ + mutable CacheMap maHandlerCache; +}; + +XMLPropertyHandlerFactory::XMLPropertyHandlerFactory() : + mpImpl(new Impl) {} + +XMLPropertyHandlerFactory::~XMLPropertyHandlerFactory() +{ + for( const auto& rCacheEntry : mpImpl->maHandlerCache ) + delete rCacheEntry.second; +} + +// Interface +const XMLPropertyHandler* XMLPropertyHandlerFactory::GetPropertyHandler( sal_Int32 nType ) const +{ + SAL_WARN_IF( (nType & ~(sal_uInt32(MID_FLAG_MASK))) != 0, "xmloff", + "GetPropertyHandler called with flags in type" ); + return GetBasicHandler( nType ); +} + +// Helper-methods to create and cache PropertyHandler +const XMLPropertyHandler* XMLPropertyHandlerFactory::GetHdlCache( sal_Int32 nType ) const +{ + const XMLPropertyHandler* pRet = nullptr; + + if( mpImpl->maHandlerCache.find( nType ) != mpImpl->maHandlerCache.end() ) + pRet = mpImpl->maHandlerCache.find( nType )->second; + + return pRet; +} + +void XMLPropertyHandlerFactory::PutHdlCache( sal_Int32 nType, const XMLPropertyHandler* pHdl ) const +{ + mpImpl->maHandlerCache[nType] = pHdl; +} + +const XMLPropertyHandler* XMLPropertyHandlerFactory::GetBasicHandler( sal_Int32 nType ) const +{ + const XMLPropertyHandler* pPropHdl = GetHdlCache( nType ); + if( pPropHdl ) + return pPropHdl; + + std::unique_ptr pNewPropHdl = CreatePropertyHandler( nType ); + if( pNewPropHdl ) + PutHdlCache( nType, pNewPropHdl.get() ); + return pNewPropHdl.release(); +} + +std::unique_ptr XMLPropertyHandlerFactory::CreatePropertyHandler( sal_Int32 nType ) +{ + std::unique_ptr pPropHdl; + + switch( nType ) + { + case XML_TYPE_BOOL : + pPropHdl.reset(new XMLBoolPropHdl); + break; + case XML_TYPE_BOOL_FALSE : + pPropHdl.reset(new XMLBoolFalsePropHdl); + break; + case XML_TYPE_MEASURE : + pPropHdl.reset(new XMLMeasurePropHdl( 4 )); + break; + case XML_TYPE_MEASURE8 : + pPropHdl.reset(new XMLMeasurePropHdl( 1 )); + break; + case XML_TYPE_MEASURE16: + pPropHdl.reset(new XMLMeasurePropHdl( 2 )); + break; + case XML_TYPE_PERCENT : + pPropHdl.reset(new XMLPercentPropHdl( 4 )); + break; + case XML_TYPE_PERCENT8 : + pPropHdl.reset(new XMLPercentPropHdl( 1 )); + break; + case XML_TYPE_PERCENT16 : + pPropHdl.reset(new XMLPercentPropHdl( 2 )); + break; + case XML_TYPE_PERCENT100: + pPropHdl.reset(new XML100thPercentPropHdl); + break; + case XML_TYPE_DOUBLE_PERCENT : + pPropHdl.reset(new XMLDoublePercentPropHdl); + break; + case XML_TYPE_NEG_PERCENT : + pPropHdl.reset(new XMLNegPercentPropHdl( 4 )); + break; + case XML_TYPE_NEG_PERCENT8 : + pPropHdl.reset(new XMLNegPercentPropHdl( 1 )); + break; + case XML_TYPE_NEG_PERCENT16 : + pPropHdl.reset(new XMLNegPercentPropHdl( 2 )); + break; + case XML_TYPE_MEASURE_PX : + pPropHdl.reset(new XMLMeasurePxPropHdl( 4 )); + break; + case XML_TYPE_STRING : + pPropHdl.reset(new XMLStringPropHdl); + break; + case XML_TYPE_COLOR : + pPropHdl.reset(new XMLColorPropHdl); + break; + case XML_TYPE_HEX : + pPropHdl.reset(new XMLHexPropHdl); + break; + case XML_TYPE_NUMBER : + pPropHdl.reset(new XMLNumberPropHdl( 4 )); + break; + case XML_TYPE_NUMBER8 : + pPropHdl.reset(new XMLNumberPropHdl( 1 )); + break; + case XML_TYPE_NUMBER16: + pPropHdl.reset(new XMLNumberPropHdl( 2 )); + break; + case XML_TYPE_NUMBER_NONE : + pPropHdl.reset(new XMLNumberNonePropHdl); + break; + case XML_TYPE_NUMBER8_NONE : + pPropHdl.reset(new XMLNumberNonePropHdl( 1 )); + break; + case XML_TYPE_NUMBER16_NONE : + pPropHdl.reset(new XMLNumberNonePropHdl( 2 )); + break; + case XML_TYPE_DOUBLE : + pPropHdl.reset(new XMLDoublePropHdl); + break; + case XML_TYPE_NBOOL : + pPropHdl.reset(new XMLNBoolPropHdl); + break; + case XML_TYPE_COLORTRANSPARENT : + pPropHdl.reset(new XMLColorTransparentPropHdl); + break; + case XML_TYPE_ISTRANSPARENT : + pPropHdl.reset(new XMLIsTransparentPropHdl); + break; + case XML_TYPE_COLORAUTO : + pPropHdl.reset(new XMLColorAutoPropHdl); + break; + case XML_TYPE_ISAUTOCOLOR : + pPropHdl.reset(new XMLIsAutoColorPropHdl); + break; + case XML_TYPE_BUILDIN_CMP_ONLY : + pPropHdl.reset(new XMLCompareOnlyPropHdl); + break; + + case XML_TYPE_RECTANGLE_LEFT : + case XML_TYPE_RECTANGLE_TOP : + case XML_TYPE_RECTANGLE_WIDTH : + case XML_TYPE_RECTANGLE_HEIGHT : + pPropHdl.reset(new XMLRectangleMembersHdl( nType )); + break; + + case XML_TYPE_TEXT_CROSSEDOUT_TYPE: + pPropHdl.reset(new XMLCrossedOutTypePropHdl) ; + break; + case XML_TYPE_TEXT_CROSSEDOUT_STYLE: + pPropHdl.reset(new XMLCrossedOutStylePropHdl) ; + break; + case XML_TYPE_TEXT_CROSSEDOUT_WIDTH: + pPropHdl.reset(new XMLCrossedOutWidthPropHdl) ; + break; + case XML_TYPE_TEXT_CROSSEDOUT_TEXT: + pPropHdl.reset(new XMLCrossedOutTextPropHdl) ; + break; + case XML_TYPE_TEXT_BOOLCROSSEDOUT: + pPropHdl.reset(new XMLNamedBoolPropertyHdl( + GetXMLToken(XML_SOLID), + GetXMLToken(XML_NONE) )); + break; + case XML_TYPE_TEXT_ESCAPEMENT: + pPropHdl.reset(new XMLEscapementPropHdl); + break; + case XML_TYPE_TEXT_ESCAPEMENT_HEIGHT: + pPropHdl.reset(new XMLEscapementHeightPropHdl); + break; + case XML_TYPE_TEXT_CASEMAP: + pPropHdl.reset(new XMLCaseMapPropHdl); + break; + case XML_TYPE_TEXT_CASEMAP_VAR: + pPropHdl.reset(new XMLCaseMapVariantHdl); + break; + case XML_TYPE_TEXT_FONTFAMILYNAME: + pPropHdl.reset(new XMLFontFamilyNamePropHdl); + break; + case XML_TYPE_TEXT_FONTFAMILY: + pPropHdl.reset(new XMLFontFamilyPropHdl); + break; + case XML_TYPE_TEXT_FONTENCODING: + pPropHdl.reset(new XMLFontEncodingPropHdl); + break; + case XML_TYPE_TEXT_FONTPITCH: + pPropHdl.reset(new XMLFontPitchPropHdl); + break; + case XML_TYPE_TEXT_KERNING: + pPropHdl.reset(new XMLKerningPropHdl); + break; + case XML_TYPE_TEXT_POSTURE: + pPropHdl.reset(new XMLPosturePropHdl); + break; + case XML_TYPE_TEXT_SHADOWED: + pPropHdl.reset(new XMLShadowedPropHdl); + break; + case XML_TYPE_TEXT_UNDERLINE_TYPE: + pPropHdl.reset(new XMLUnderlineTypePropHdl); + break; + case XML_TYPE_TEXT_UNDERLINE_STYLE: + pPropHdl.reset(new XMLUnderlineStylePropHdl); + break; + case XML_TYPE_TEXT_UNDERLINE_WIDTH: + pPropHdl.reset(new XMLUnderlineWidthPropHdl); + break; + case XML_TYPE_TEXT_UNDERLINE_COLOR: + pPropHdl.reset(new XMLColorTransparentPropHdl( XML_FONT_COLOR )); + break; + case XML_TYPE_TEXT_UNDERLINE_HASCOLOR: + pPropHdl.reset(new XMLIsTransparentPropHdl( XML_FONT_COLOR, + false )); + break; + case XML_TYPE_TEXT_OVERLINE_TYPE: + pPropHdl.reset(new XMLUnderlineTypePropHdl); + break; + case XML_TYPE_TEXT_OVERLINE_STYLE: + pPropHdl.reset(new XMLUnderlineStylePropHdl); + break; + case XML_TYPE_TEXT_OVERLINE_WIDTH: + pPropHdl.reset(new XMLUnderlineWidthPropHdl); + break; + case XML_TYPE_TEXT_OVERLINE_COLOR: + pPropHdl.reset(new XMLColorTransparentPropHdl( XML_FONT_COLOR )); + break; + case XML_TYPE_TEXT_OVERLINE_HASCOLOR: + pPropHdl.reset(new XMLIsTransparentPropHdl( XML_FONT_COLOR, + false )); + break; + case XML_TYPE_TEXT_WEIGHT: + pPropHdl.reset(new XMLFontWeightPropHdl); + break; + case XML_TYPE_TEXT_SPLIT: + pPropHdl.reset(new XMLNamedBoolPropertyHdl( + GetXMLToken(XML_AUTO), + GetXMLToken(XML_ALWAYS) )); + break; + case XML_TYPE_TEXT_BREAKBEFORE: + pPropHdl.reset(new XMLFmtBreakBeforePropHdl); + break; + case XML_TYPE_TEXT_BREAKAFTER: + pPropHdl.reset(new XMLFmtBreakAfterPropHdl); + break; + case XML_TYPE_TEXT_SHADOW: + pPropHdl.reset(new XMLShadowPropHdl); + break; + case XML_TYPE_TEXT_ADJUST: + pPropHdl.reset(new XMLParaAdjustPropHdl); + break; + case XML_TYPE_TEXT_ADJUSTLAST: + pPropHdl.reset(new XMLLastLineAdjustPropHdl); + break; + case XML_TYPE_CHAR_HEIGHT: + pPropHdl.reset(new XMLCharHeightHdl); + break; + case XML_TYPE_CHAR_HEIGHT_PROP: + pPropHdl.reset(new XMLCharHeightPropHdl); + break; + case XML_TYPE_CHAR_HEIGHT_DIFF: + pPropHdl.reset(new XMLCharHeightDiffHdl); + break; + case XML_TYPE_CHAR_RFC_LANGUAGE_TAG: + pPropHdl.reset(new XMLCharRfcLanguageTagHdl); + break; + case XML_TYPE_CHAR_LANGUAGE: + pPropHdl.reset(new XMLCharLanguageHdl); + break; + case XML_TYPE_CHAR_SCRIPT: + pPropHdl.reset(new XMLCharScriptHdl); + break; + case XML_TYPE_CHAR_COUNTRY: + pPropHdl.reset(new XMLCharCountryHdl); + break; + case XML_TYPE_LINE_SPACE_FIXED: + pPropHdl.reset(new XMLLineHeightHdl); + break; + case XML_TYPE_LINE_SPACE_MINIMUM: + pPropHdl.reset(new XMLLineHeightAtLeastHdl); + break; + case XML_TYPE_LINE_SPACE_DISTANCE: + pPropHdl.reset(new XMLLineSpacingHdl); + break; + case XML_TYPE_BORDER_WIDTH: + pPropHdl.reset(new XMLBorderWidthHdl); + break; + case XML_TYPE_BORDER: + pPropHdl.reset(new XMLBorderHdl); + break; + case XML_TYPE_TEXT_TABSTOP: + pPropHdl.reset(new XMLTabStopPropHdl); + break; + case XML_TYPE_ATTRIBUTE_CONTAINER: + pPropHdl.reset(new XMLAttributeContainerHandler); + break; + case XML_TYPE_COLOR_MODE: + pPropHdl.reset(new XMLEnumPropertyHdl(aXML_ColorMode_EnumMap)); + break; + case XML_TYPE_DURATION16_MS: + pPropHdl.reset(new XMLDurationMS16PropHdl_Impl); + break; + case XML_TYPE_TEXT_HORIZONTAL_ADJUST: + pPropHdl.reset(new XMLEnumPropertyHdl(aXML_HorizontalAdjust_Enum)); + break; + case XML_TYPE_TEXT_DRAW_ASPECT: + pPropHdl.reset(new DrawAspectHdl); + break; + case XML_TYPE_TEXT_WRITING_MODE: + pPropHdl.reset(new XMLConstantsPropertyHandler( + &(aXML_WritingDirection_Enum[1]), + XML_LR_TB)); + break; + case XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT: + pPropHdl.reset(new XMLConstantsPropertyHandler( + aXML_WritingDirection_Enum, + XML_PAGE)); + break; + case XML_TYPE_TEXT_HIDDEN_AS_DISPLAY: + pPropHdl.reset(new XMLNamedBoolPropertyHdl( + GetXMLToken(XML_NONE), + GetXMLToken(XML_TRUE) )); + break; + case XML_TYPE_STYLENAME : + pPropHdl.reset(new XMLStyleNamePropHdl); + break; + case XML_TYPE_NUMBER_NO_ZERO: + pPropHdl.reset(new XMLNumberWithoutZeroPropHdl( 4 )); + break; + case XML_TYPE_NUMBER8_NO_ZERO: + pPropHdl.reset(new XMLNumberWithoutZeroPropHdl( 1 )); + break; + case XML_TYPE_NUMBER16_NO_ZERO: + pPropHdl.reset(new XMLNumberWithoutZeroPropHdl( 2 )); + break; + case XML_TYPE_NUMBER16_AUTO: + pPropHdl.reset(new XMLNumberWithAutoForVoidPropHdl); + break; + case XML_TYPE_TEXT_VERTICAL_POS: + pPropHdl.reset(new XMLConstantsPropertyHandler( pXML_VertPos_Enum, XML_TOKEN_INVALID )); + break; + + } + + return pPropHdl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/prstylecond.cxx b/xmloff/source/style/prstylecond.cxx new file mode 100644 index 000000000..4da002488 --- /dev/null +++ b/xmloff/source/style/prstylecond.cxx @@ -0,0 +1,91 @@ +/* -*- 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 +#include +#include + +using namespace ::xmloff::token; + +// note: keep this in sync with the list of conditions in sw/source/uibase/chrdlg/ccoll.cxx + +namespace { + +struct ConditionMap +{ + char const* aInternal; + XMLTokenEnum nExternal; + int aValue; +}; + +} + +const ConditionMap g_ConditionMap[] = +{ + { "TableHeader", XML_TABLE_HEADER, -1 }, + { "Table", XML_TABLE, -1 }, + { "Frame", XML_TEXT_BOX, -1 }, // FIXME - Not in ODF spec + { "Section", XML_SECTION, -1 }, + { "Footnote", XML_FOOTNOTE, -1 }, + { "Endnote", XML_ENDNOTE, -1 }, + { "Header", XML_HEADER, -1 }, + { "Footer", XML_FOOTER, -1 }, + { "OutlineLevel1", XML_OUTLINE_LEVEL, 1 }, + { "OutlineLevel2", XML_OUTLINE_LEVEL, 2 }, + { "OutlineLevel3", XML_OUTLINE_LEVEL, 3 }, + { "OutlineLevel4", XML_OUTLINE_LEVEL, 4 }, + { "OutlineLevel5", XML_OUTLINE_LEVEL, 5 }, + { "OutlineLevel6", XML_OUTLINE_LEVEL, 6 }, + { "OutlineLevel7", XML_OUTLINE_LEVEL, 7 }, + { "OutlineLevel8", XML_OUTLINE_LEVEL, 8 }, + { "OutlineLevel9", XML_OUTLINE_LEVEL, 9 }, + { "OutlineLevel10", XML_OUTLINE_LEVEL, 10 }, + { "NumberingLevel1", XML_LIST_LEVEL, 1 }, + { "NumberingLevel2", XML_LIST_LEVEL, 2 }, + { "NumberingLevel3", XML_LIST_LEVEL, 3 }, + { "NumberingLevel4", XML_LIST_LEVEL, 4 }, + { "NumberingLevel5", XML_LIST_LEVEL, 5 }, + { "NumberingLevel6", XML_LIST_LEVEL, 6 }, + { "NumberingLevel7", XML_LIST_LEVEL, 7 }, + { "NumberingLevel8", XML_LIST_LEVEL, 8 }, + { "NumberingLevel9", XML_LIST_LEVEL, 9 }, + { "NumberingLevel10", XML_LIST_LEVEL, 10 } +}; + +OUString GetParaStyleCondExternal( OUString const &internal) +{ + for (size_t i = 0; i < SAL_N_ELEMENTS(g_ConditionMap); ++i) + { + if (internal.compareToAscii( g_ConditionMap[i].aInternal ) == 0) + { + OUString aResult = GetXMLToken( g_ConditionMap[i].nExternal ) + + "()"; + if (g_ConditionMap[i].aValue != -1) + { + aResult += "=" + + OUString::number( g_ConditionMap[i].aValue ); + } + return aResult; + } + } + assert(!"GetParaStyleCondExternal: model has unknown style condition"); + return OUString(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/prstylei.cxx b/xmloff/source/style/prstylei.cxx new file mode 100644 index 000000000..aae787d49 --- /dev/null +++ b/xmloff/source/style/prstylei.cxx @@ -0,0 +1,664 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::xmloff::token; +using namespace com::sun::star::drawing; + +void XMLPropStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_FAMILY) ) + { + SAL_WARN_IF( GetFamily() != SvXMLStylesContext::GetFamily( rValue ), "xmloff", "unexpected style family" ); + } + else + { + SvXMLStyleContext::SetAttribute( nElement, rValue ); + } +} + + +namespace +{ + struct theStandardSet : + public rtl::StaticWithInit + { + OldFillStyleDefinitionSet operator () () + { + OldFillStyleDefinitionSet aSet; + aSet.insert("BackColorRGB"); + aSet.insert("BackTransparent"); + aSet.insert("BackColorTransparency"); + aSet.insert("BackGraphic"); + aSet.insert("BackGraphicFilter"); + aSet.insert("BackGraphicLocation"); + aSet.insert("BackGraphicTransparency"); + return aSet; + } + }; + struct theHeaderSet : + public rtl::StaticWithInit + { + OldFillStyleDefinitionSet operator () () + { + OldFillStyleDefinitionSet aSet; + aSet.insert("HeaderBackColorRGB"); + aSet.insert("HeaderBackTransparent"); + aSet.insert("HeaderBackColorTransparency"); + aSet.insert("HeaderBackGraphic"); + aSet.insert("HeaderBackGraphicFilter"); + aSet.insert("HeaderBackGraphicLocation"); + aSet.insert("HeaderBackGraphicTransparency"); + return aSet; + } + }; + struct theFooterSet : + public rtl::StaticWithInit + { + OldFillStyleDefinitionSet operator () () + { + OldFillStyleDefinitionSet aSet; + aSet.insert("FooterBackColorRGB"); + aSet.insert("FooterBackTransparent"); + aSet.insert("FooterBackColorTransparency"); + aSet.insert("FooterBackGraphic"); + aSet.insert("FooterBackGraphicFilter"); + aSet.insert("FooterBackGraphicLocation"); + aSet.insert("FooterBackGraphicTransparency"); + return aSet; + } + }; + struct theParaSet : + public rtl::StaticWithInit + { + OldFillStyleDefinitionSet operator () () + { + OldFillStyleDefinitionSet aSet; + // Caution: here it is *not* 'ParaBackColorRGB' as it should be, but indeed + // 'ParaBackColor' is used, see aXMLParaPropMap definition (line 313) + aSet.insert("ParaBackColor"); + aSet.insert("ParaBackTransparent"); + aSet.insert("ParaBackGraphicLocation"); + aSet.insert("ParaBackGraphicFilter"); + aSet.insert("ParaBackGraphic"); + + // These are not used in aXMLParaPropMap definition, thus not needed here + // aSet.insert("ParaBackColorTransparency"); + // aSet.insert("ParaBackGraphicTransparency"); + return aSet; + } + }; +} + + + +constexpr OUStringLiteral gsIsPhysical( u"IsPhysical" ); +constexpr OUStringLiteral gsFollowStyle( u"FollowStyle" ); + +XMLPropStyleContext::XMLPropStyleContext( SvXMLImport& rImport, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily, + bool bDefault ) +: SvXMLStyleContext( rImport, nFamily, bDefault ) +, mxStyles( &rStyles ) +{ +} + +XMLPropStyleContext::~XMLPropStyleContext() +{ +} + +const OldFillStyleDefinitionSet& XMLPropStyleContext::getStandardSet() +{ + return theStandardSet::get(); +} + +const OldFillStyleDefinitionSet& XMLPropStyleContext::getHeaderSet() +{ + return theHeaderSet::get(); +} + +const OldFillStyleDefinitionSet& XMLPropStyleContext::getFooterSet() +{ + return theFooterSet::get(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLPropStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + sal_uInt32 nFamily = 0; + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) || + IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + if( nLocalName == XML_GRAPHIC_PROPERTIES ) + nFamily = XML_TYPE_PROP_GRAPHIC; + else if( nLocalName == XML_DRAWING_PAGE_PROPERTIES ) + nFamily = XML_TYPE_PROP_DRAWING_PAGE; + else if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_RUBY_PROPERTIES ) + nFamily = XML_TYPE_PROP_RUBY; + else if( nLocalName == XML_SECTION_PROPERTIES ) + nFamily = XML_TYPE_PROP_SECTION; + else if( nLocalName == XML_TABLE_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE; + else if( nLocalName == XML_TABLE_COLUMN_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE_COLUMN; + else if( nLocalName ==XML_TABLE_ROW_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE_ROW; + else if( nLocalName == XML_TABLE_CELL_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE_CELL; + else if( nLocalName == XML_CHART_PROPERTIES ) + nFamily = XML_TYPE_PROP_CHART; + } + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + mxStyles->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new SvXMLPropertySetContext( GetImport(), nElement, + xAttrList, + nFamily, + maProperties, + xImpPrMap ); + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLPropStyleContext::FillPropertySet( + const Reference< XPropertySet > & rPropSet ) +{ + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + mxStyles->GetImportPropertyMapper( GetFamily() ); + SAL_WARN_IF( !xImpPrMap.is(), "xmloff", "There is the import prop mapper" ); + if( xImpPrMap.is() ) + xImpPrMap->FillPropertySet( maProperties, rPropSet ); +} + +void XMLPropStyleContext::SetDefaults() +{ +} + +Reference < XStyle > XMLPropStyleContext::Create() +{ + Reference < XStyle > xNewStyle; + + OUString sServiceName = mxStyles->GetServiceName( GetFamily() ); + if( !sServiceName.isEmpty() ) + { + Reference< XMultiServiceFactory > xFactory( GetImport().GetModel(), + UNO_QUERY ); + if( xFactory.is() ) + { + Reference < XInterface > xIfc = + xFactory->createInstance( sServiceName ); + if( xIfc.is() ) + xNewStyle.set( xIfc, UNO_QUERY ); + } + } + + return xNewStyle; +} + +void XMLPropStyleContext::CreateAndInsert( bool bOverwrite ) +{ + SvXMLStylesContext* pSvXMLStylesContext = mxStyles.get(); + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = pSvXMLStylesContext->GetImportPropertyMapper(GetFamily()); + OSL_ENSURE(xImpPrMap.is(), "There is no import prop mapper"); + + // need to filter out old fill definitions when the new ones are used. The new + // ones are used when a FillStyle is defined + const bool bTakeCareOfDrawingLayerFillStyle(xImpPrMap.is() && GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH); + bool bDrawingLayerFillStylesUsed(false); + + if(bTakeCareOfDrawingLayerFillStyle) + { + // check if new FillStyles are used and if so mark old ones with -1 + static OUString s_FillStyle("FillStyle"); + + if(doNewDrawingLayerFillStyleDefinitionsExist(s_FillStyle)) + { + deactivateOldFillStyleDefinitions(theParaSet::get()); + bDrawingLayerFillStylesUsed = true; + } + } + + if( pSvXMLStylesContext->IsAutomaticStyle() + && ( GetFamily() == XmlStyleFamily::TEXT_TEXT || GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH ) ) + { + // Need to translate StyleName from temp MapNames to names + // used in already imported items (already exist in the pool). This + // is required for AutomaticStyles since these do *not* use FillPropertySet + // and thus just trigger CheckSpecialContext in XMLTextStyleContext::FillPropertySet + // (which may be double action anyways). The mechanism there to use _ContextID_Index_Pair + // is not working for AutomaticStyles and is already too late, too (this + // method is already called before XMLTextStyleContext::FillPropertySet gets called) + if(bDrawingLayerFillStylesUsed) + { + translateNameBasedDrawingLayerFillStyleDefinitionsToStyleDisplayNames(); + } + + Reference < XAutoStyleFamily > xAutoFamily = pSvXMLStylesContext->GetAutoStyles( GetFamily() ); + if( !xAutoFamily.is() ) + return; + if( xImpPrMap.is() ) + { + Sequence< PropertyValue > aValues; + xImpPrMap->FillPropertySequence( maProperties, aValues ); + + sal_Int32 nLen = aValues.getLength(); + if( nLen ) + { + if( GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH ) + { + aValues.realloc( nLen + 2 ); + PropertyValue *pProps = aValues.getArray() + nLen; + pProps->Name = "ParaStyleName"; + OUString sParent( GetParentName() ); + if( !sParent.isEmpty() ) + { + sParent = GetImport().GetStyleDisplayName( GetFamily(), sParent ); + Reference < XNameContainer > xFamilies = pSvXMLStylesContext->GetStylesContainer( GetFamily() ); + if(xFamilies.is() && xFamilies->hasByName( sParent ) ) + { + css::uno::Reference< css::style::XStyle > xStyle; + Any aAny = xFamilies->getByName( sParent ); + aAny >>= xStyle; + sParent = xStyle->getName() ; + } + } + else + sParent = "Standard"; + pProps->Value <<= sParent; + ++pProps; + pProps->Name = "ParaConditionalStyleName"; + pProps->Value <<= sParent; + } + + Reference < XAutoStyle > xAutoStyle = xAutoFamily->insertStyle( aValues ); + if( xAutoStyle.is() ) + { + Sequence< OUString > aPropNames + { + (GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH)? + OUString("ParaAutoStyleName"): + OUString("CharAutoStyleName") + }; + Sequence< Any > aAny = xAutoStyle->getPropertyValues( aPropNames ); + if( aAny.hasElements() ) + { + OUString aName; + aAny[0] >>= aName; + SetAutoName( aName ); + } + } + } + } + } + else + { + const OUString& rName = GetDisplayName(); + if( rName.isEmpty() || IsDefaultStyle() ) + return; + + Reference < XNameContainer > xFamilies = pSvXMLStylesContext->GetStylesContainer( GetFamily() ); + if( !xFamilies.is() ) + { + SAL_WARN("xmloff", "no styles container for family " << static_cast(GetFamily())); + return; + } + + bool bNew = false; + if( xFamilies->hasByName( rName ) ) + { + Any aAny = xFamilies->getByName( rName ); + aAny >>= mxStyle; + } + else + { + mxStyle = Create(); + if( !mxStyle.is() ) + return; + + xFamilies->insertByName( rName, Any(mxStyle) ); + bNew = true; + } + + Reference < XPropertySet > xPropSet( mxStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( !bNew && xPropSetInfo->hasPropertyByName( gsIsPhysical ) ) + { + Any aAny = xPropSet->getPropertyValue( gsIsPhysical ); + bNew = !*o3tl::doAccess(aAny); + } + SetNew( bNew ); + if( rName != GetName() ) + GetImport().AddStyleDisplayName( GetFamily(), GetName(), rName ); + + + if( bOverwrite || bNew ) + { + rtl::Reference < XMLPropertySetMapper > xPrMap; + if( xImpPrMap.is() ) + xPrMap = xImpPrMap->getPropertySetMapper(); + if( xPrMap.is() ) + { + Reference < XMultiPropertyStates > xMultiStates( xPropSet, + UNO_QUERY ); + if( xMultiStates.is() ) + { + xMultiStates->setAllPropertiesToDefault(); + } + else + { + std::set < OUString > aNameSet; + sal_Int32 nCount = xPrMap->GetEntryCount(); + sal_Int32 i; + for( i = 0; i < nCount; i++ ) + { + const OUString& rPrName = xPrMap->GetEntryAPIName( i ); + if( xPropSetInfo->hasPropertyByName( rPrName ) ) + aNameSet.insert( rPrName ); + } + Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if (xPropState.is()) + { + nCount = aNameSet.size(); + Sequence aNames( comphelper::containerToSequence(aNameSet) ); + Sequence < PropertyState > aStates( xPropState->getPropertyStates(aNames) ); + const PropertyState *pStates = aStates.getConstArray(); + OUString* pNames = aNames.getArray(); + + for( i = 0; i < nCount; i++ ) + { + if( PropertyState_DIRECT_VALUE == *pStates++ ) + xPropState->setPropertyToDefault( pNames[i] ); + } + } + } + } + + if (mxStyle.is()) + mxStyle->setParentStyle(OUString()); + + FillPropertySet( xPropSet ); + } + else + { + SetValid( false ); + } + } +} + +void XMLPropStyleContext::Finish( bool bOverwrite ) +{ + if( !mxStyle.is() || !(IsNew() || bOverwrite) ) + return; + + // The families container must exist + Reference < XNameContainer > xFamilies = mxStyles->GetStylesContainer( GetFamily() ); + SAL_WARN_IF( !xFamilies.is(), "xmloff", "Families lost" ); + if( !xFamilies.is() ) + return; + + // connect parent + OUString sParent( GetParentName() ); + if( !sParent.isEmpty() ) + sParent = GetImport().GetStyleDisplayName( GetFamily(), sParent ); + if( !sParent.isEmpty() && !xFamilies->hasByName( sParent ) ) + sParent.clear(); + + if( sParent != mxStyle->getParentStyle() ) + { + // this may except if setting the parent style forms a + // circle in the style dependencies; especially if the parent + // style is the same as the current style + try + { + mxStyle->setParentStyle( sParent ); + } + catch(const uno::Exception& e) + { + // according to the API definition, I would expect a + // container::NoSuchElementException. But it throws an + // uno::RuntimeException instead. I catch + // uno::Exception in order to process both of them. + + // We can't set the parent style. For a proper + // Error-Message, we should pass in the name of the + // style, as well as the desired parent style. + + // getName() throws no non-Runtime exception: + GetImport().SetError( + XMLERROR_FLAG_ERROR | XMLERROR_PARENT_STYLE_NOT_ALLOWED, + { mxStyle->getName(), sParent }, e.Message, nullptr ); + } + } + + // connect follow + OUString sFollow( GetFollow() ); + if( !sFollow.isEmpty() ) + sFollow = GetImport().GetStyleDisplayName( GetFamily(), sFollow ); + if( sFollow.isEmpty() || !xFamilies->hasByName( sFollow ) ) + sFollow = mxStyle->getName(); + + Reference < XPropertySet > xPropSet( mxStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) ) + { + Any aAny = xPropSet->getPropertyValue( gsFollowStyle ); + OUString sCurrFollow; + aAny >>= sCurrFollow; + if( sCurrFollow != sFollow ) + { + xPropSet->setPropertyValue( gsFollowStyle, Any(sFollow) ); + } + } + + // Connect linked style. + OUString aLinked(GetLinked()); + if (!aLinked.isEmpty()) + { + if (GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH) + { + aLinked = GetImport().GetStyleDisplayName(XmlStyleFamily::TEXT_TEXT, aLinked); + } + else if (GetFamily() == XmlStyleFamily::TEXT_TEXT) + { + aLinked = GetImport().GetStyleDisplayName(XmlStyleFamily::TEXT_PARAGRAPH, aLinked); + } + } + if (!aLinked.isEmpty() && xPropSetInfo->hasPropertyByName("LinkStyle")) + { + uno::Any aAny = xPropSet->getPropertyValue("LinkStyle"); + OUString aCurrentLinked; + aAny >>= aCurrentLinked; + if (aCurrentLinked != aLinked) + { + xPropSet->setPropertyValue("LinkStyle", uno::Any(aLinked)); + } + } + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + xPropSet->setPropertyValue( "Hidden", uno::Any( IsHidden( ) ) ); + } + +} + +bool XMLPropStyleContext::doNewDrawingLayerFillStyleDefinitionsExist( + const OUString& rFillStyleTag) const +{ + if(!maProperties.empty() && rFillStyleTag.getLength()) + { + // no & to avoid non-obvious UAF due to the 2nd temp Reference + const rtl::Reference rMapper = GetStyles()->GetImportPropertyMapper(GetFamily())->getPropertySetMapper(); + + if(rMapper.is()) + { + for(const auto& a : maProperties) + { + if(a.mnIndex != -1) + { + const OUString& rPropName = rMapper->GetEntryAPIName(a.mnIndex); + + if(rPropName == rFillStyleTag) + { + FillStyle eFillStyle(FillStyle_NONE); + + if(a.maValue >>= eFillStyle) + { + // okay, type was good, FillStyle is set + } + else + { + // also try an int (see XFillStyleItem::PutValue) + sal_Int32 nFillStyle(0); + + if(a.maValue >>= nFillStyle) + { + eFillStyle = static_cast< FillStyle >(nFillStyle); + } + } + + // we found the entry, check it + return FillStyle_NONE != eFillStyle; + } + } + } + } + } + + return false; +} + +void XMLPropStyleContext::deactivateOldFillStyleDefinitions( + const OldFillStyleDefinitionSet& rHashSetOfTags) +{ + if(rHashSetOfTags.empty() || maProperties.empty()) + return; + + const rtl::Reference< XMLPropertySetMapper >& rMapper = GetStyles()->GetImportPropertyMapper(GetFamily())->getPropertySetMapper(); + + if(!rMapper.is()) + return; + + for(auto& a : maProperties) + { + if(a.mnIndex != -1) + { + const OUString& rPropName = rMapper->GetEntryAPIName(a.mnIndex); + + if(rHashSetOfTags.find(rPropName) != rHashSetOfTags.end()) + { + // mark entry as inactive + a.mnIndex = -1; + } + } + } +} + +void XMLPropStyleContext::translateNameBasedDrawingLayerFillStyleDefinitionsToStyleDisplayNames() +{ + if(maProperties.empty()) + return; + + const rtl::Reference< XMLPropertySetMapper >& rMapper = GetStyles()->GetImportPropertyMapper(GetFamily())->getPropertySetMapper(); + + if(!rMapper.is()) + return; + + static constexpr OUStringLiteral s_FillGradientName(u"FillGradientName"); + static constexpr OUStringLiteral s_FillHatchName(u"FillHatchName"); + static constexpr OUStringLiteral s_FillBitmapName(u"FillBitmapName"); + static constexpr OUStringLiteral s_FillTransparenceGradientName(u"FillTransparenceGradientName"); + + for(auto& a : maProperties) + { + if(a.mnIndex != -1) + { + const OUString& rPropName = rMapper->GetEntryAPIName(a.mnIndex); + XmlStyleFamily aStyleFamily(XmlStyleFamily::DATA_STYLE); + + if(rPropName == s_FillGradientName || rPropName == s_FillTransparenceGradientName) + { + aStyleFamily = XmlStyleFamily::SD_GRADIENT_ID; + } + else if(rPropName == s_FillHatchName) + { + aStyleFamily = XmlStyleFamily::SD_HATCH_ID; + } + else if(rPropName == s_FillBitmapName) + { + aStyleFamily = XmlStyleFamily::SD_FILL_IMAGE_ID; + } + + if(aStyleFamily != XmlStyleFamily::DATA_STYLE) + { + OUString sStyleName; + + a.maValue >>= sStyleName; + sStyleName = GetImport().GetStyleDisplayName( aStyleFamily, sStyleName ); + a.maValue <<= sStyleName; + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/shadwhdl.cxx b/xmloff/source/style/shadwhdl.cxx new file mode 100644 index 000000000..b80db3a8d --- /dev/null +++ b/xmloff/source/style/shadwhdl.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/. + * + * 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 "shadwhdl.hxx" +#include +#include + + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + + + +XMLShadowPropHdl::~XMLShadowPropHdl() +{ + // nothing to do +} + +bool XMLShadowPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + table::ShadowFormat aShadow; + aShadow.Location = table::ShadowLocation_BOTTOM_RIGHT; + + bool bColorFound = false; + bool bOffsetFound = false; + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + Color aColor( 128,128, 128 ); + std::u16string_view aToken; + + while( aTokenEnum.getNextToken( aToken ) ) + { + if( IsXMLToken( aToken, XML_NONE ) ) + { + aShadow.Location = table::ShadowLocation_NONE; + bRet = true; + break; + } + else if( !bColorFound && aToken.substr(0,1) == u"#" ) + { + bRet = ::sax::Converter::convertColor( aColor, aToken ); + if( !bRet ) + return false; + bColorFound = true; + } + else if( !bOffsetFound ) + { + sal_Int32 nX = 0, nY = 0; + + bRet = rUnitConverter.convertMeasureToCore( nX, aToken ); + if( bRet && aTokenEnum.getNextToken( aToken ) ) + bRet = rUnitConverter.convertMeasureToCore( nY, aToken ); + + if( bRet ) + { + if( nX < 0 ) + { + if( nY < 0 ) + aShadow.Location = table::ShadowLocation_TOP_LEFT; + else + aShadow.Location = table::ShadowLocation_BOTTOM_LEFT; + } + else + { + if( nY < 0 ) + aShadow.Location = table::ShadowLocation_TOP_RIGHT; + else + aShadow.Location = table::ShadowLocation_BOTTOM_RIGHT; + } + + if (nX < 0) + nX = o3tl::saturating_toggle_sign(nX); + if (nY < 0) + nY = o3tl::saturating_toggle_sign(nY); + + sal_Int32 nWidth; + bRet = !o3tl::checked_add(nX, nY, nWidth); + if (bRet) + aShadow.ShadowWidth = sal::static_int_cast(nWidth >> 1); + } + } + } + + if( bRet && ( bColorFound || bOffsetFound ) ) + { + aShadow.IsTransparent = aColor.IsTransparent(); + aShadow.Color = sal_Int32(aColor); + bRet = true; + } + + rValue <<= aShadow; + + return bRet; +} + +bool XMLShadowPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + table::ShadowFormat aShadow; + + if( rValue >>= aShadow ) + { + sal_Int32 nX = 1, nY = 1; + + switch( aShadow.Location ) + { + case table::ShadowLocation_TOP_LEFT: + nX = -1; + nY = -1; + break; + case table::ShadowLocation_TOP_RIGHT: + nY = -1; + break; + case table::ShadowLocation_BOTTOM_LEFT: + nX = -1; + break; + case table::ShadowLocation_BOTTOM_RIGHT: + break; + case table::ShadowLocation_NONE: + default: + rStrExpValue = GetXMLToken(XML_NONE); + return true; + } + + nX *= aShadow.ShadowWidth; + nY *= aShadow.ShadowWidth; + + OUStringBuffer aOut; + ::sax::Converter::convertColor( aOut, aShadow.Color ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, nX ); + aOut.append( ' ' ); + rUnitConverter.convertMeasureToXML( aOut, nY ); + + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/shadwhdl.hxx b/xmloff/source/style/shadwhdl.hxx new file mode 100644 index 000000000..8b0a7762f --- /dev/null +++ b/xmloff/source/style/shadwhdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLShadowPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLShadowPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/shdwdhdl.cxx b/xmloff/source/style/shdwdhdl.cxx new file mode 100644 index 000000000..41b1b4574 --- /dev/null +++ b/xmloff/source/style/shdwdhdl.cxx @@ -0,0 +1,67 @@ +/* -*- 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 "shdwdhdl.hxx" +#include + + +#include + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + + + + +XMLShadowedPropHdl::~XMLShadowedPropHdl() +{ + // nothing to do +} + +bool XMLShadowedPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue = ! IsXMLToken( rStrImpValue, XML_NONE ); + rValue <<= bValue; + + return true; +} + +bool XMLShadowedPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + if( bValue ) + { + rStrExpValue = "1pt 1pt"; + } + else + { + rStrExpValue = GetXMLToken( XML_NONE ); + } + + bRet = true; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/shdwdhdl.hxx b/xmloff/source/style/shdwdhdl.hxx new file mode 100644 index 000000000..e7397f80c --- /dev/null +++ b/xmloff/source/style/shdwdhdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLShadowedPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLShadowedPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/styleexp.cxx b/xmloff/source/style/styleexp.cxx new file mode 100644 index 000000000..b311dbdf6 --- /dev/null +++ b/xmloff/source/style/styleexp.cxx @@ -0,0 +1,592 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::document::XEventsSupplier; + +constexpr OUStringLiteral gsIsPhysical( u"IsPhysical" ); +constexpr OUStringLiteral gsIsAutoUpdate( u"IsAutoUpdate" ); +constexpr OUStringLiteral gsFollowStyle( u"FollowStyle" ); +constexpr OUStringLiteral gsNumberingStyleName( u"NumberingStyleName" ); +constexpr OUStringLiteral gsOutlineLevel( u"OutlineLevel" ); + +XMLStyleExport::XMLStyleExport( + SvXMLExport& rExp, + SvXMLAutoStylePoolP *pAutoStyleP ) : + rExport( rExp ), + pAutoStylePool( pAutoStyleP ) +{ +} + +XMLStyleExport::~XMLStyleExport() +{ +} + +void XMLStyleExport::exportStyleAttributes( const Reference< XStyle >& ) +{ +} + +void XMLStyleExport::exportStyleContent( const Reference< XStyle >& rStyle ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + assert(xPropSet.is()); + + try + { + uno::Any aProperty = xPropSet->getPropertyValue( "ParaStyleConditions" ); + uno::Sequence< beans::NamedValue > aSeq; + + aProperty >>= aSeq; + + for (beans::NamedValue const& rNamedCond : std::as_const(aSeq)) + { + OUString aStyleName; + + if (rNamedCond.Value >>= aStyleName) + { + if (!aStyleName.isEmpty()) + { + OUString aExternal = GetParaStyleCondExternal(rNamedCond.Name); + + if (!aExternal.isEmpty()) + { + bool bEncoded; + + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_CONDITION, + aExternal); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_APPLY_STYLE_NAME, + GetExport().EncodeStyleName( aStyleName, + &bEncoded ) ); + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_STYLE, + XML_MAP, + true, + true ); + } + } + } + } + } + catch( const beans::UnknownPropertyException& ) + { + } +} + +namespace +{ +/// Writes for Writer paragraph styles. +void ExportStyleListlevel(const uno::Reference& xPropSetInfo, + const uno::Reference& xPropState, + const uno::Reference& xPropSet, SvXMLExport& rExport) +{ + if (!xPropSetInfo->hasPropertyByName("NumberingLevel")) + { + SAL_WARN("xmloff", "ExportStyleListlevel: no NumberingLevel for a Writer paragraph style"); + return; + } + + if (xPropState->getPropertyState("NumberingLevel") != beans::PropertyState_DIRECT_VALUE) + { + return; + } + + sal_Int16 nNumberingLevel{}; + if (!(xPropSet->getPropertyValue("NumberingLevel") >>= nNumberingLevel)) + { + return; + } + + // The spec is positiveInteger (1-based), but the implementation is 0-based. + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_LIST_LEVEL, OUString::number(++nNumberingLevel)); +} +} + +bool XMLStyleExport::exportStyle( + const Reference< XStyle >& rStyle, + const OUString& rXMLFamily, + const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper, + const Reference< XNameAccess >& xStyles, + const OUString* pPrefix ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + if (!xPropSet) + return false; + + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + Any aAny; + + // Don't export styles that aren't existing really. This may be the + // case for StarOffice Writer's pool styles. + if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) ) + { + aAny = xPropSet->getPropertyValue( gsIsPhysical ); + if( !*o3tl::doAccess(aAny) ) + return false; + } + + // + GetExport().CheckAttrList(); + + // style:name="..." + OUString sName; + + if(pPrefix) + sName = *pPrefix; + sName += rStyle->getName(); + + bool bEncoded = false; + const OUString sEncodedStyleName(GetExport().EncodeStyleName( sName, &bEncoded )); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, sEncodedStyleName ); + + if( bEncoded ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, + sName); + + // style:family="..." + if( !rXMLFamily.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, rXMLFamily); + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + aAny = xPropSet->getPropertyValue( "Hidden" ); + bool bHidden = false; + if ((aAny >>= bHidden) && bHidden + && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDDEN, "true"); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_HIDDEN, "true"); // FIXME for compatibility + } + } + + // style:parent-style-name="..." + OUString sParentString(rStyle->getParentStyle()); + OUString sParent; + + if(!sParentString.isEmpty()) + { + if(pPrefix) + sParent = *pPrefix; + sParent += sParentString; + } + + if( !sParent.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_PARENT_STYLE_NAME, + GetExport().EncodeStyleName( sParent ) ); + + // style:next-style-name="..." (paragraph styles only) + if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) ) + { + aAny = xPropSet->getPropertyValue( gsFollowStyle ); + OUString sNextName; + aAny >>= sNextName; + if( sName != sNextName ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NEXT_STYLE_NAME, + GetExport().EncodeStyleName( sNextName ) ); + } + } + + // style:linked-style-name="..." (SW paragraph and character styles only) + if (xPropSetInfo->hasPropertyByName("LinkStyle")) + { + aAny = xPropSet->getPropertyValue("LinkStyle"); + OUString sLinkName; + aAny >>= sLinkName; + if (!sLinkName.isEmpty() + && (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_LINKED_STYLE_NAME, + GetExport().EncodeStyleName(sLinkName)); + } + } + + // style:auto-update="..." (SW only) + if( xPropSetInfo->hasPropertyByName( gsIsAutoUpdate ) ) + { + aAny = xPropSet->getPropertyValue( gsIsAutoUpdate ); + if( *o3tl::doAccess(aAny) ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_AUTO_UPDATE, + XML_TRUE ); + } + + // style:default-outline-level"..." + sal_Int32 nOutlineLevel = 0; + if( xPropSetInfo->hasPropertyByName( gsOutlineLevel ) ) + { + Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if( PropertyState_DIRECT_VALUE == xPropState->getPropertyState( gsOutlineLevel ) ) + { + aAny = xPropSet->getPropertyValue( gsOutlineLevel ); + aAny >>= nOutlineLevel; + if( nOutlineLevel > 0 ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DEFAULT_OUTLINE_LEVEL, + OUString::number(nOutlineLevel) ); + } + else + { + /* Empty value for style:default-outline-level does exist + since ODF 1.2. Thus, suppress its export for former versions. (#i104889#) + */ + if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DEFAULT_OUTLINE_LEVEL, + OUString( "" )); + } + } + } + } + + // style:list-style-name="..." (SW paragraph styles only) + if( xPropSetInfo->hasPropertyByName( gsNumberingStyleName ) ) + { + Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if( PropertyState_DIRECT_VALUE == + xPropState->getPropertyState( gsNumberingStyleName ) ) + { + aAny = xPropSet->getPropertyValue( gsNumberingStyleName ); + if( aAny.hasValue() ) + { + OUString sListName; + aAny >>= sListName; + + /* A direct set empty list style has to be written. Otherwise, + this information is lost and causes an error, if the parent + style has a list style set. (#i69523#) + */ + if ( sListName.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_LIST_STYLE_NAME, + sListName /* empty string */); + } + else + { + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + bool bSuppressListStyle( false ); + { + if ( !GetExport().writeOutlineStyleAsNormalListStyle() ) + { + Reference< XChapterNumberingSupplier > xCNSupplier + (GetExport().GetModel(), UNO_QUERY); + + if (xCNSupplier.is()) + { + Reference< XIndexReplace > xNumRule + ( xCNSupplier->getChapterNumberingRules() ); + assert(xNumRule.is()); + + Reference< XPropertySet > xNumRulePropSet + (xNumRule, UNO_QUERY); + OUString sOutlineName; + xNumRulePropSet->getPropertyValue("Name") + >>= sOutlineName; + bSuppressListStyle = sListName == sOutlineName; + } + } + } + + if ( !sListName.isEmpty() && !bSuppressListStyle ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_LIST_STYLE_NAME, + GetExport().EncodeStyleName( sListName ) ); + + ExportStyleListlevel(xPropSetInfo, xPropState, xPropSet, GetExport()); + } + } + } + } + else if( nOutlineLevel > 0 ) + { + + bool bNoInheritedListStyle( true ); + + Reference xStyle( xPropState, UNO_QUERY ); + while ( xStyle.is() ) + { + OUString aParentStyle( xStyle->getParentStyle() ); + if ( aParentStyle.isEmpty() || !xStyles->hasByName( aParentStyle ) ) + { + break; + } + else + { + xPropState.set( xStyles->getByName( aParentStyle ), UNO_QUERY ); + if ( !xPropState.is() ) + { + break; + } + if ( xPropState->getPropertyState( gsNumberingStyleName ) == PropertyState_DIRECT_VALUE ) + { + bNoInheritedListStyle = false; + break; + } + else + { + xStyle.set( xPropState, UNO_QUERY ); + } + } + } + if ( bNoInheritedListStyle ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_LIST_STYLE_NAME, + OUString( "" )); + } + } + + // style:pool-id="..." is not required any longer since we use + // english style names only + exportStyleAttributes( rStyle ); + + // TODO: style:help-file-name="..." and style:help-id="..." can neither + // be modified by UI nor by API and that for, have not to be exported + // currently. + + { + // + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, XML_STYLE, + true, true ); + + rPropMapper->SetStyleName( sName ); + + // + ::std::vector< XMLPropertyState > aPropStates = + rPropMapper->Filter(GetExport(), xPropSet, true); + bool const bUseExtensionNamespaceForGraphicProperties( + rXMLFamily != "drawing-page" && + rXMLFamily != "graphic" && + rXMLFamily != "presentation" && + rXMLFamily != "chart"); + rPropMapper->exportXML( GetExport(), aPropStates, + SvXmlExportFlags::IGN_WS, + bUseExtensionNamespaceForGraphicProperties ); + + rPropMapper->SetStyleName( OUString() ); + + exportStyleContent( rStyle ); + + // , if they are supported by this style + Reference xEventsSupp(rStyle, UNO_QUERY); + GetExport().GetEventExport().Export(xEventsSupp); + } + return true; +} + +void XMLStyleExport::exportDefaultStyle( + const Reference< XPropertySet >& xPropSet, + const OUString& rXMLFamily, + const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper ) +{ + // + GetExport().CheckAttrList(); + + { + // style:family="..." + if( !rXMLFamily.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_FAMILY, + rXMLFamily ); + // + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_DEFAULT_STYLE, + true, true ); + // + ::std::vector< XMLPropertyState > aPropStates = + rPropMapper->FilterDefaults(GetExport(), xPropSet); + rPropMapper->exportXML( GetExport(), aPropStates, + SvXmlExportFlags::IGN_WS ); + } +} + +void XMLStyleExport::exportStyleFamily( + const char *pFamily, + const OUString& rXMLFamily, + const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper, + bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix) +{ + const OUString sFamily(OUString::createFromAscii(pFamily )); + exportStyleFamily( sFamily, rXMLFamily, rPropMapper, bUsed, nFamily, + pPrefix); +} + +void XMLStyleExport::exportStyleFamily( + const OUString& rFamily, const OUString& rXMLFamily, + const rtl::Reference < SvXMLExportPropertyMapper >& rPropMapper, + bool bUsed, XmlStyleFamily nFamily, const OUString* pPrefix) +{ + assert(GetExport().GetModel().is()); + Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), UNO_QUERY ); + if( !xFamiliesSupp.is() ) + return; // family not available in current model + + Reference< XNameAccess > xStyleCont; + + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + if( xFamilies->hasByName( rFamily ) ) + xFamilies->getByName( rFamily ) >>= xStyleCont; + + if( !xStyleCont.is() ) + return; + + // If next styles are supported and used styles should be exported only, + // the next style may be unused but has to be exported, too. In this case + // the names of all exported styles are remembered. + std::optional > xExportedStyles; + bool bFirstStyle = true; + + const uno::Sequence< OUString> aSeq = xStyleCont->getElementNames(); + for(const auto& rName : aSeq) + { + Reference< XStyle > xStyle; + try + { + xStyleCont->getByName( rName ) >>= xStyle; + } + catch(const lang::IndexOutOfBoundsException&) + { + // due to bugs in prior versions it is possible that + // a binary file is missing some critical styles. + // The only possible way to deal with this is to + // not export them here and remain silent. + continue; + } + catch(css::container::NoSuchElementException&) + { + continue; + } + + assert(xStyle.is()); + if (!bUsed || xStyle->isInUse()) + { + bool bExported = exportStyle( xStyle, rXMLFamily, rPropMapper, + xStyleCont,pPrefix ); + if (bUsed && bFirstStyle && bExported) + { + // If this is the first style, find out whether next styles + // are supported. + Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + + if (xPropSetInfo->hasPropertyByName( gsFollowStyle )) + xExportedStyles.emplace(); + bFirstStyle = false; + } + + if (xExportedStyles && bExported) + { + // If next styles are supported, remember this style's name. + xExportedStyles->insert( xStyle->getName() ); + } + } + + // if an auto style pool is given, remember this style's name as a + // style name that must not be used by automatic styles. + if (pAutoStylePool) + pAutoStylePool->RegisterName( nFamily, xStyle->getName() ); + } + + if( !xExportedStyles ) + return; + + // if next styles are supported, export all next styles that are + // unused and that for, haven't been exported in the first loop. + for(const auto& rName : aSeq) + { + Reference< XStyle > xStyle; + xStyleCont->getByName( rName ) >>= xStyle; + + assert(xStyle.is()); + + Reference< XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + + // styles that aren't existing really are ignored. + if (xPropSetInfo->hasPropertyByName( gsIsPhysical )) + { + Any aAny( xPropSet->getPropertyValue( gsIsPhysical ) ); + if (!*o3tl::doAccess(aAny)) + continue; + } + + if (!xStyle->isInUse()) + continue; + + if (!xPropSetInfo->hasPropertyByName( gsFollowStyle )) + { + continue; + } + + OUString sNextName; + xPropSet->getPropertyValue( gsFollowStyle ) >>= sNextName; + OUString sTmp( sNextName ); + // if the next style hasn't been exported by now, export it now + // and remember its name. + if (xStyle->getName() != sNextName && + 0 == xExportedStyles->count( sTmp )) + { + xStyleCont->getByName( sNextName ) >>= xStyle; + assert(xStyle.is()); + + if (exportStyle(xStyle, rXMLFamily, rPropMapper, xStyleCont, pPrefix)) + xExportedStyles->insert( sTmp ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/tabsthdl.cxx b/xmloff/source/style/tabsthdl.cxx new file mode 100644 index 000000000..2e497f3ea --- /dev/null +++ b/xmloff/source/style/tabsthdl.cxx @@ -0,0 +1,65 @@ +/* -*- 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 "tabsthdl.hxx" +#include +#include + +using namespace ::com::sun::star; + + + + +XMLTabStopPropHdl::~XMLTabStopPropHdl() +{ + // Nothing to do +} + +bool XMLTabStopPropHdl::equals( const uno::Any& r1, const uno::Any& r2 ) const +{ + uno::Sequence< style::TabStop> aSeq1; + if( r1 >>= aSeq1 ) + { + uno::Sequence< style::TabStop> aSeq2; + if( r2 >>= aSeq2 ) + { + return std::equal(std::cbegin(aSeq1), std::cend(aSeq1), std::cbegin(aSeq2), std::cend(aSeq2), + [](const style::TabStop& a, const style::TabStop& b) { + return a.Position == b.Position + && a.Alignment == b.Alignment + && a.DecimalChar == b.DecimalChar + && a.FillChar == b.FillChar; + }); + } + } + + return false; +} + +bool XMLTabStopPropHdl::importXML( const OUString&, css::uno::Any&, const SvXMLUnitConverter& ) const +{ + return false; +} + +bool XMLTabStopPropHdl::exportXML( OUString&, const css::uno::Any&, const SvXMLUnitConverter& ) const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/tabsthdl.hxx b/xmloff/source/style/tabsthdl.hxx new file mode 100644 index 000000000..755790e8f --- /dev/null +++ b/xmloff/source/style/tabsthdl.hxx @@ -0,0 +1,39 @@ +/* -*- 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLTabStopPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLTabStopPropHdl() override; + + virtual bool equals( const css::uno::Any& r1, const css::uno::Any& r2 ) const override; + + /// TabStops will be imported/exported as XML-Elements. So the Import/Export-work must be done at another place. + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/undlihdl.cxx b/xmloff/source/style/undlihdl.cxx new file mode 100644 index 000000000..4d6482c4f --- /dev/null +++ b/xmloff/source/style/undlihdl.cxx @@ -0,0 +1,365 @@ +/* -*- 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 "undlihdl.hxx" +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::awt; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_UnderlineType_Enum[] = +{ + { XML_NONE, awt::FontUnderline::NONE }, + { XML_SINGLE, awt::FontUnderline::SINGLE }, + { XML_DOUBLE, awt::FontUnderline::DOUBLE }, + { XML_SINGLE, awt::FontUnderline::DOTTED }, + { XML_SINGLE, awt::FontUnderline::DASH }, + { XML_SINGLE, awt::FontUnderline::LONGDASH }, + { XML_SINGLE, awt::FontUnderline::DASHDOT }, + { XML_SINGLE, awt::FontUnderline::DASHDOTDOT }, + { XML_SINGLE, awt::FontUnderline::WAVE }, + { XML_SINGLE, awt::FontUnderline::BOLD }, + { XML_SINGLE, awt::FontUnderline::BOLDDOTTED }, + { XML_SINGLE, awt::FontUnderline::BOLDDASH }, + { XML_SINGLE, awt::FontUnderline::BOLDLONGDASH }, + { XML_SINGLE, awt::FontUnderline::BOLDDASHDOT }, + { XML_SINGLE, awt::FontUnderline::BOLDDASHDOTDOT }, + { XML_SINGLE, awt::FontUnderline::BOLDWAVE }, + { XML_DOUBLE, awt::FontUnderline::DOUBLEWAVE }, + { XML_SINGLE, awt::FontUnderline::SMALLWAVE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_UnderlineStyle_Enum[] = +{ + { XML_NONE, awt::FontUnderline::NONE }, + { XML_SOLID, awt::FontUnderline::SINGLE }, + { XML_SOLID, awt::FontUnderline::DOUBLE }, + { XML_DOTTED, awt::FontUnderline::DOTTED }, + { XML_DASH, awt::FontUnderline::DASH }, + { XML_LONG_DASH, awt::FontUnderline::LONGDASH }, + { XML_DOT_DASH, awt::FontUnderline::DASHDOT }, + { XML_DOT_DOT_DASH, awt::FontUnderline::DASHDOTDOT }, + { XML_WAVE, awt::FontUnderline::WAVE }, + { XML_SOLID, awt::FontUnderline::BOLD }, + { XML_DOTTED, awt::FontUnderline::BOLDDOTTED }, + { XML_DASH, awt::FontUnderline::BOLDDASH }, + { XML_LONG_DASH, awt::FontUnderline::BOLDLONGDASH }, + { XML_DOT_DASH, awt::FontUnderline::BOLDDASHDOT }, + { XML_DOT_DOT_DASH, awt::FontUnderline::BOLDDASHDOTDOT }, + { XML_WAVE, awt::FontUnderline::BOLDWAVE }, + { XML_WAVE, awt::FontUnderline::DOUBLEWAVE }, + { XML_SMALL_WAVE, awt::FontUnderline::SMALLWAVE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_UnderlineWidth_Enum[] = +{ + { XML_AUTO, awt::FontUnderline::NONE }, + { XML_AUTO, awt::FontUnderline::SINGLE }, + { XML_AUTO, awt::FontUnderline::DOUBLE }, + { XML_AUTO, awt::FontUnderline::DOTTED }, + { XML_AUTO, awt::FontUnderline::DASH }, + { XML_AUTO, awt::FontUnderline::LONGDASH }, + { XML_AUTO, awt::FontUnderline::DASHDOT }, + { XML_AUTO, awt::FontUnderline::DASHDOTDOT }, + { XML_AUTO, awt::FontUnderline::WAVE }, + { XML_BOLD, awt::FontUnderline::BOLD }, + { XML_BOLD, awt::FontUnderline::BOLDDOTTED }, + { XML_BOLD, awt::FontUnderline::BOLDDASH }, + { XML_BOLD, awt::FontUnderline::BOLDLONGDASH }, + { XML_BOLD, awt::FontUnderline::BOLDDASHDOT }, + { XML_BOLD, awt::FontUnderline::BOLDDASHDOTDOT }, + { XML_BOLD, awt::FontUnderline::BOLDWAVE }, + { XML_AUTO, awt::FontUnderline::DOUBLEWAVE }, + { XML_THIN, awt::FontUnderline::NONE }, + { XML_MEDIUM, awt::FontUnderline::NONE }, + { XML_THICK, awt::FontUnderline::BOLD}, + { XML_TOKEN_INVALID, 0 } +}; + + + + +XMLUnderlineTypePropHdl::~XMLUnderlineTypePropHdl() +{ + // nothing to do +} + +bool XMLUnderlineTypePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewUnderline(0); + bool bRet = SvXMLUnitConverter::convertEnum( + eNewUnderline, rStrImpValue, pXML_UnderlineType_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eUnderline = sal_Int16(); + if( (rValue >>= eUnderline) && awt::FontUnderline::NONE!=eUnderline ) + { + switch( eNewUnderline ) + { + case awt::FontUnderline::NONE: + case awt::FontUnderline::SINGLE: + // keep existing line style + eNewUnderline = eUnderline; + break; + case awt::FontUnderline::DOUBLE: + // A double line style has priority over a bold line style, + // but not over the line style itself. + switch( eUnderline ) + { + case awt::FontUnderline::SINGLE: + case awt::FontUnderline::BOLD: + break; + case awt::FontUnderline::WAVE: + case awt::FontUnderline::BOLDWAVE: + eNewUnderline = awt::FontUnderline::DOUBLEWAVE; + break; + default: + // If a double line style is not supported for the existing + // value, keep the new one + eNewUnderline = eUnderline; + break; + } + break; + default: + OSL_ENSURE( bRet, "unexpected line type value" ); + break; + } + if( eNewUnderline != eUnderline ) + rValue <<= static_cast(eNewUnderline); + } + else + { + rValue <<= static_cast(eNewUnderline); + } + } + + return bRet; +} + +bool XMLUnderlineTypePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( (rValue >>= nValue) && + (awt::FontUnderline::DOUBLE == nValue || + awt::FontUnderline::DOUBLEWAVE == nValue) ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_UnderlineType_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + + + +XMLUnderlineStylePropHdl::~XMLUnderlineStylePropHdl() +{ + // nothing to do +} + +bool XMLUnderlineStylePropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewUnderline(0); + bool bRet = SvXMLUnitConverter::convertEnum( + eNewUnderline, rStrImpValue, pXML_UnderlineStyle_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eUnderline = sal_Int16(); + if( (rValue >>= eUnderline) && awt::FontUnderline::NONE!=eUnderline ) + { + switch( eNewUnderline ) + { + case awt::FontUnderline::NONE: + case awt::FontUnderline::SINGLE: + // keep double or bold line style + eNewUnderline = eUnderline; + break; + case awt::FontUnderline::DOTTED: + // The line style has priority over a double type. + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDDOTTED; + break; + case awt::FontUnderline::DASH: + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDDASH; + break; + case awt::FontUnderline::LONGDASH: + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDLONGDASH; + break; + case awt::FontUnderline::DASHDOT: + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDDASHDOT; + break; + case awt::FontUnderline::DASHDOTDOT: + if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDDASHDOTDOT; + break; + case awt::FontUnderline::WAVE: + if( awt::FontUnderline::DOUBLE == eUnderline ) + eNewUnderline = awt::FontUnderline::DOUBLEWAVE; + else if( awt::FontUnderline::BOLD == eUnderline ) + eNewUnderline = awt::FontUnderline::BOLDWAVE; + break; + case awt::FontUnderline::SMALLWAVE: + // SMALLWAVE is not used + default: + OSL_ENSURE( bRet, "unexpected line style value" ); + break; + } + if( eNewUnderline != eUnderline ) + rValue <<= static_cast(eNewUnderline); + } + else + { + rValue <<= static_cast(eNewUnderline); + } + } + + return bRet; +} + +bool XMLUnderlineStylePropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( rValue >>= nValue ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_UnderlineStyle_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + + + + +XMLUnderlineWidthPropHdl::~XMLUnderlineWidthPropHdl() +{ + // nothing to do +} + +bool XMLUnderlineWidthPropHdl::importXML( const OUString& rStrImpValue, uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt16 eNewUnderline(0); + bool bRet = SvXMLUnitConverter::convertEnum( + eNewUnderline, rStrImpValue, pXML_UnderlineWidth_Enum ); + if( bRet ) + { + // multi property: style and width might be set already. + // If the old value is NONE, the new is used unchanged. + sal_Int16 eUnderline = sal_Int16(); + if( (rValue >>= eUnderline) && awt::FontUnderline::NONE!=eUnderline ) + { + switch( eNewUnderline ) + { + case awt::FontUnderline::NONE: + // keep existing line style + eNewUnderline = eUnderline; + break; + case awt::FontUnderline::BOLD: + // A double line style has priority over a bold line style, + // but not over the line style itself. + switch( eUnderline ) + { + case awt::FontUnderline::SINGLE: + break; + case awt::FontUnderline::DOTTED: + eNewUnderline = awt::FontUnderline::BOLDDOTTED; + break; + case awt::FontUnderline::DASH: + eNewUnderline = awt::FontUnderline::BOLDDASH; + break; + case awt::FontUnderline::LONGDASH: + eNewUnderline = awt::FontUnderline::BOLDLONGDASH; + break; + case awt::FontUnderline::DASHDOT: + eNewUnderline = awt::FontUnderline::BOLDDASHDOT; + break; + case awt::FontUnderline::DASHDOTDOT: + eNewUnderline = awt::FontUnderline::BOLDDASHDOTDOT; + break; + case awt::FontUnderline::WAVE: + eNewUnderline = awt::FontUnderline::BOLDWAVE; + break; + default: + // a double line style overwrites a bold one + eNewUnderline = eUnderline; + break; + } + break; + default: + OSL_ENSURE( bRet, "unexpected line width value" ); + break; + } + if( eNewUnderline != eUnderline ) + rValue <<= static_cast(eNewUnderline); + } + else + { + rValue <<= static_cast(eNewUnderline); + } + } + + return bRet; +} + +bool XMLUnderlineWidthPropHdl::exportXML( OUString& rStrExpValue, const uno::Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nValue = sal_uInt16(); + + if( (rValue >>= nValue) && (awt::FontUnderline::NONE != nValue) ) + { + OUStringBuffer aOut; + bRet = SvXMLUnitConverter::convertEnum( + aOut, nValue, pXML_UnderlineWidth_Enum ); + if( bRet ) + rStrExpValue = aOut.makeStringAndClear(); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/undlihdl.hxx b/xmloff/source/style/undlihdl.hxx new file mode 100644 index 000000000..4b9ad1b50 --- /dev/null +++ b/xmloff/source/style/undlihdl.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/. + * + * 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLUnderlineTypePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLUnderlineTypePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLUnderlineStylePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLUnderlineStylePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLUnderlineWidthPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLUnderlineWidthPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/weighhdl.cxx b/xmloff/source/style/weighhdl.cxx new file mode 100644 index 000000000..a069dbd30 --- /dev/null +++ b/xmloff/source/style/weighhdl.cxx @@ -0,0 +1,154 @@ +/* -*- 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 "weighhdl.hxx" + +#include + +#include + +#include + +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +namespace { + +struct FontWeightMapper +{ + float fWeight; + sal_uInt16 nValue; +}; + +} + +FontWeightMapper const aFontWeightMap[] = +{ + { css::awt::FontWeight::DONTKNOW, 0 }, + { css::awt::FontWeight::THIN, 100 }, + { css::awt::FontWeight::ULTRALIGHT, 150 }, + { css::awt::FontWeight::LIGHT, 250 }, + { css::awt::FontWeight::SEMILIGHT, 350 }, + { css::awt::FontWeight::NORMAL, 400 }, + { css::awt::FontWeight::NORMAL, 450 }, + { css::awt::FontWeight::SEMIBOLD, 600 }, + { css::awt::FontWeight::BOLD, 700 }, + { css::awt::FontWeight::ULTRABOLD, 800 }, + { css::awt::FontWeight::BLACK, 900 }, + { css::awt::FontWeight::DONTKNOW, 1000 } +}; + + +XMLFontWeightPropHdl::~XMLFontWeightPropHdl() +{ + // Nothing to do +} + +bool XMLFontWeightPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt16 nWeight = 0; + + if( IsXMLToken( rStrImpValue, XML_NORMAL ) ) + { + nWeight = 400; + bRet = true; + } + else if( IsXMLToken( rStrImpValue, XML_BOLD ) ) + { + nWeight = 700; + bRet = true; + } + else + { + sal_Int32 nTemp; + bRet = ::sax::Converter::convertNumber(nTemp, rStrImpValue, 100, 900); + if( bRet ) + nWeight = sal::static_int_cast< sal_uInt16 >(nTemp); + } + + if( bRet ) + { + bRet = false; + int const nCount = SAL_N_ELEMENTS(aFontWeightMap); + for (int i = 0; i < (nCount-1); ++i) + { + if( (nWeight >= aFontWeightMap[i].nValue) && (nWeight <= aFontWeightMap[i+1].nValue) ) + { + sal_uInt16 nDiff1 = nWeight - aFontWeightMap[i].nValue; + sal_uInt16 nDiff2 = aFontWeightMap[i+1].nValue - nWeight; + + if( nDiff1 < nDiff2 ) + rValue <<= aFontWeightMap[i].fWeight; + else + rValue <<= aFontWeightMap[i+1].fWeight; + + bRet = true; + break; + } + } + } + + return bRet; +} + +bool XMLFontWeightPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + float fValue = float(); + if( !( rValue >>= fValue ) ) + { + sal_Int32 nValue = 0; + if( rValue >>= nValue ) + { + fValue = static_cast(nValue); + bRet = true; + } + } + else + bRet = true; + + if( bRet ) + { + sal_uInt16 nWeight = 0; + for( auto const & pair : aFontWeightMap ) + { + if( fValue <= pair.fWeight ) + { + nWeight = pair.nValue; + break; + } + } + + if( 400 == nWeight ) + rStrExpValue = GetXMLToken(XML_NORMAL); + else if( 700 == nWeight ) + rStrExpValue = GetXMLToken(XML_BOLD); + else + rStrExpValue = OUString::number( nWeight ); + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/weighhdl.hxx b/xmloff/source/style/weighhdl.hxx new file mode 100644 index 000000000..e9df03001 --- /dev/null +++ b/xmloff/source/style/weighhdl.hxx @@ -0,0 +1,37 @@ +/* -*- 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 + +/** + PropertyHandler for the XML-data-type: +*/ +class XMLFontWeightPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLFontWeightPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlaustp.cxx b/xmloff/source/style/xmlaustp.cxx new file mode 100644 index 000000000..859477250 --- /dev/null +++ b/xmloff/source/style/xmlaustp.cxx @@ -0,0 +1,384 @@ +/* -*- 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 +#include "impastpl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +using namespace ::std; + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + + +namespace +{ + void lcl_exportDataStyle( SvXMLExport& _rExport, const rtl::Reference< XMLPropertySetMapper >& _rxMapper, + const XMLPropertyState& _rProperty ) + { + assert(_rxMapper.is()); + // obtain the data style name + OUString sDataStyleName; + _rProperty.maValue >>= sDataStyleName; + assert(!sDataStyleName.isEmpty() && "xmloff::lcl_exportDataStyle: invalid property value for the data style name!"); + + // add the attribute + _rExport.AddAttribute( + _rxMapper->GetEntryNameSpace( _rProperty.mnIndex ), + _rxMapper->GetEntryXMLName( _rProperty.mnIndex ), + sDataStyleName ); + } +} + +void SvXMLAutoStylePoolP::exportStyleAttributes( + SvXMLAttributeList&, + XmlStyleFamily nFamily, + const vector< XMLPropertyState >& rProperties, + const SvXMLExportPropertyMapper& rPropExp, + const SvXMLUnitConverter&, + const SvXMLNamespaceMap& + ) const +{ + if ( XmlStyleFamily::CONTROL_ID == nFamily ) + { // it's a control-related style + const rtl::Reference< XMLPropertySetMapper >& aPropertyMapper = rPropExp.getPropertySetMapper(); + + for (const auto& rProp : rProperties) + { + if ( ( rProp.mnIndex > -1 ) + && ( CTF_FORMS_DATA_STYLE == aPropertyMapper->GetEntryContextId( rProp.mnIndex ) ) + ) + { // it's the data-style for a grid column + lcl_exportDataStyle( GetExport(), aPropertyMapper, rProp ); + } + } + } + + if( (XmlStyleFamily::SD_GRAPHICS_ID == nFamily) || (XmlStyleFamily::SD_PRESENTATION_ID == nFamily) ) + { // it's a graphics style + const rtl::Reference< XMLPropertySetMapper >& aPropertyMapper = rPropExp.getPropertySetMapper(); + assert(aPropertyMapper.is()); + + bool bFoundControlShapeDataStyle = false; + bool bFoundNumberingRulesName = false; + + for (const auto& rProp : rProperties) + { + if (rProp.mnIndex > -1) + { // it's a valid property + switch( aPropertyMapper->GetEntryContextId(rProp.mnIndex) ) + { + case CTF_SD_CONTROL_SHAPE_DATA_STYLE: + { // it's the control shape data style property + + if (bFoundControlShapeDataStyle) + { + OSL_FAIL("SvXMLAutoStylePoolP::exportStyleAttributes: found two properties with the ControlShapeDataStyle context id!"); + // already added the attribute for the first occurrence + break; + } + + lcl_exportDataStyle( GetExport(), aPropertyMapper, rProp ); + + // check if there is another property with the special context id we're handling here + bFoundControlShapeDataStyle = true; + break; + } + case CTF_SD_NUMBERINGRULES_NAME: + { + if (bFoundNumberingRulesName) + { + OSL_FAIL("SvXMLAutoStylePoolP::exportStyleAttributes: found two properties with the numbering rules name context id!"); + // already added the attribute for the first occurrence + break; + } + + uno::Reference< container::XIndexReplace > xNumRule; + rProp.maValue >>= xNumRule; + if( xNumRule.is() && (xNumRule->getCount() > 0 ) ) + { + const OUString sName(const_cast(&GetExport().GetTextParagraphExport()->GetListAutoStylePool())->Add( xNumRule )); + + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_LIST_STYLE_NAME, GetExport().EncodeStyleName( sName ) ); + } + + bFoundNumberingRulesName = true; + break; + } + } + } + } + } + + if( nFamily != XmlStyleFamily::PAGE_MASTER ) + return; + + for( const auto& rProp : rProperties ) + { + if (rProp.mnIndex > -1) + { + const rtl::Reference< XMLPropertySetMapper >& aPropMapper = rPropExp.getPropertySetMapper(); + sal_Int32 nIndex = rProp.mnIndex; + sal_Int16 nContextID = aPropMapper->GetEntryContextId( nIndex ); + switch( nContextID ) + { + case CTF_PM_PAGEUSAGE: + { + OUString sValue; + const XMLPropertyHandler* pPropHdl = aPropMapper->GetPropertyHandler( nIndex ); + if( pPropHdl && + pPropHdl->exportXML( sValue, rProp.maValue, + GetExport().GetMM100UnitConverter() ) && + ( ! IsXMLToken( sValue, XML_ALL ) ) ) + { + GetExport().AddAttribute( aPropMapper->GetEntryNameSpace( nIndex ), aPropMapper->GetEntryXMLName( nIndex ), sValue ); + } + } + break; + } + } + } +} + +void SvXMLAutoStylePoolP::exportStyleContent( + const css::uno::Reference< css::xml::sax::XDocumentHandler > &, + XmlStyleFamily nFamily, + const vector< XMLPropertyState >& rProperties, + const SvXMLExportPropertyMapper& rPropExp, + const SvXMLUnitConverter&, + const SvXMLNamespaceMap& + ) const +{ + if( nFamily != XmlStyleFamily::PAGE_MASTER ) + return; + + sal_Int32 nHeaderStartIndex(-1); + sal_Int32 nHeaderEndIndex(-1); + sal_Int32 nFooterStartIndex(-1); + sal_Int32 nFooterEndIndex(-1); + bool bHeaderStartIndex(false); + bool bHeaderEndIndex(false); + bool bFooterStartIndex(false); + bool bFooterEndIndex(false); + + const rtl::Reference< XMLPropertySetMapper >& aPropMapper = rPropExp.getPropertySetMapper(); + + sal_Int32 nIndex(0); + while(nIndex < aPropMapper->GetEntryCount()) + { + switch( aPropMapper->GetEntryContextId( nIndex ) & CTF_PM_FLAGMASK ) + { + case CTF_PM_HEADERFLAG: + { + if (!bHeaderStartIndex) + { + nHeaderStartIndex = nIndex; + bHeaderStartIndex = true; + } + if (bFooterStartIndex && !bFooterEndIndex) + { + nFooterEndIndex = nIndex; + bFooterEndIndex = true; + } + } + break; + case CTF_PM_FOOTERFLAG: + { + if (!bFooterStartIndex) + { + nFooterStartIndex = nIndex; + bFooterStartIndex = true; + } + if (bHeaderStartIndex && !bHeaderEndIndex) + { + nHeaderEndIndex = nIndex; + bHeaderEndIndex = true; + } + } + break; + } + nIndex++; + } + if (!bHeaderEndIndex) + nHeaderEndIndex = nIndex; + if (!bFooterEndIndex) + nFooterEndIndex = nIndex; + + // export header style element + { + SvXMLElementExport aElem( + GetExport(), XML_NAMESPACE_STYLE, XML_HEADER_STYLE, + true, true ); + + rPropExp.exportXML( + GetExport(), rProperties, + nHeaderStartIndex, nHeaderEndIndex, SvXmlExportFlags::IGN_WS); + } + + // export footer style + { + SvXMLElementExport aElem( + GetExport(), XML_NAMESPACE_STYLE, XML_FOOTER_STYLE, + true, true ); + + rPropExp.exportXML( + GetExport(), rProperties, + nFooterStartIndex, nFooterEndIndex, SvXmlExportFlags::IGN_WS); + } + +} + +SvXMLAutoStylePoolP::SvXMLAutoStylePoolP( SvXMLExport& rExport ) + : pImpl( new SvXMLAutoStylePoolP_Impl( rExport ) ) +{ +} + +SvXMLAutoStylePoolP::~SvXMLAutoStylePoolP() +{ +} + +SvXMLExport& SvXMLAutoStylePoolP::GetExport() const +{ + return pImpl->GetExport(); +} + +// TODO: remove this +void SvXMLAutoStylePoolP::AddFamily( + XmlStyleFamily nFamily, + const OUString& rStrName, + SvXMLExportPropertyMapper* pMapper, + const OUString& aStrPrefix ) +{ + rtl::Reference xTmp = pMapper; + AddFamily( nFamily, rStrName, xTmp, aStrPrefix ); +} + +void SvXMLAutoStylePoolP::AddFamily( + XmlStyleFamily nFamily, + const OUString& rStrName, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper, + const OUString& rStrPrefix, + bool bAsFamily ) +{ + pImpl->AddFamily( nFamily, rStrName, rMapper, rStrPrefix, bAsFamily ); +} + +void SvXMLAutoStylePoolP::SetFamilyPropSetMapper( + XmlStyleFamily nFamily, + const rtl::Reference < SvXMLExportPropertyMapper > & rMapper ) +{ + pImpl->SetFamilyPropSetMapper( nFamily, rMapper ); +} + +void SvXMLAutoStylePoolP::RegisterName( XmlStyleFamily nFamily, + const OUString& rName ) +{ + pImpl->RegisterName( nFamily, rName ); +} + +void SvXMLAutoStylePoolP::RegisterDefinedName( XmlStyleFamily nFamily, + const OUString& rName ) +{ + pImpl->RegisterDefinedName( nFamily, rName ); +} + +void SvXMLAutoStylePoolP::GetRegisteredNames( + uno::Sequence& rFamilies, + uno::Sequence& rNames ) +{ + pImpl->GetRegisteredNames( rFamilies, rNames ); +} + +void SvXMLAutoStylePoolP::RegisterNames( + uno::Sequence const & aFamilies, + uno::Sequence const & aNames ) +{ + assert(aFamilies.getLength() == aNames.getLength()); + + // iterate over sequence(s) and call RegisterName(..) for each pair + const sal_Int32* pFamilies = aFamilies.getConstArray(); + const OUString* pNames = aNames.getConstArray(); + sal_Int32 nCount = min( aFamilies.getLength(), aNames.getLength() ); + for( sal_Int32 n = 0; n < nCount; n++ ) + RegisterName( static_cast(pFamilies[n]), pNames[n] ); +} + +OUString SvXMLAutoStylePoolP::Add( XmlStyleFamily nFamily, + vector< XMLPropertyState >&& rProperties ) +{ + OUString sName; + pImpl->Add(sName, nFamily, "", std::move(rProperties) ); + return sName; +} + +OUString SvXMLAutoStylePoolP::Add( XmlStyleFamily nFamily, + const OUString& rParent, + vector< XMLPropertyState >&& rProperties, bool bDontSeek ) +{ + OUString sName; + pImpl->Add(sName, nFamily, rParent, std::move(rProperties), bDontSeek); + return sName; +} + +bool SvXMLAutoStylePoolP::Add(OUString& rName, XmlStyleFamily nFamily, const OUString& rParent, ::std::vector< XMLPropertyState >&& rProperties ) +{ + return pImpl->Add(rName, nFamily, rParent, std::move(rProperties)); +} + +bool SvXMLAutoStylePoolP::AddNamed( const OUString& rName, XmlStyleFamily nFamily, const OUString& rParent, + std::vector< XMLPropertyState >&& rProperties ) + +{ + return pImpl->AddNamed(rName, nFamily, rParent, std::move(rProperties)); +} + +OUString SvXMLAutoStylePoolP::Find( XmlStyleFamily nFamily, + const OUString& rParent, + const vector< XMLPropertyState >& rProperties ) const +{ + return pImpl->Find( nFamily, rParent, rProperties ); +} + +void SvXMLAutoStylePoolP::exportXML( XmlStyleFamily nFamily ) const +{ + pImpl->exportXML( nFamily, this ); +} + +void SvXMLAutoStylePoolP::ClearEntries() +{ + pImpl->ClearEntries(); +} + +std::vector SvXMLAutoStylePoolP::GetAutoStyleEntries() const +{ + return pImpl->GetAutoStyleEntries(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlbahdl.cxx b/xmloff/source/style/xmlbahdl.cxx new file mode 100644 index 000000000..36bc1037c --- /dev/null +++ b/xmloff/source/style/xmlbahdl.cxx @@ -0,0 +1,904 @@ +/* -*- 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 "xmlbahdl.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +static void lcl_xmloff_setAny( Any& rValue, sal_Int32 nValue, sal_Int8 nBytes ) +{ + switch( nBytes ) + { + case 1: + if( nValue < SCHAR_MIN ) + nValue = SCHAR_MIN; + else if( nValue > SCHAR_MAX ) + nValue = SCHAR_MAX; + rValue <<= static_cast(nValue); + break; + case 2: + if( nValue < SHRT_MIN ) + nValue = SHRT_MIN; + else if( nValue > SHRT_MAX ) + nValue = SHRT_MAX; + rValue <<= static_cast(nValue); + break; + case 4: + rValue <<= nValue; + break; + } +} + +static bool lcl_xmloff_getAny( const Any& rValue, sal_Int32& nValue, + sal_Int8 nBytes ) +{ + bool bRet = false; + + switch( nBytes ) + { + case 1: + { + sal_Int8 nValue8 = 0; + bRet = rValue >>= nValue8; + nValue = nValue8; + } + break; + case 2: + { + sal_Int16 nValue16 = 0; + bRet = rValue >>= nValue16; + nValue = nValue16; + } + break; + case 4: + bRet = rValue >>= nValue; + break; + } + + return bRet; +} + + +XMLNumberPropHdl::~XMLNumberPropHdl() +{ + // nothing to do +} + +bool XMLNumberPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + lcl_xmloff_setAny( rValue, nValue, nBytes ); + + return bRet; +} + +bool XMLNumberPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + rStrExpValue = OUString::number( nValue ); + + bRet = true; + } + + return bRet; +} + + +XMLNumberNonePropHdl::XMLNumberNonePropHdl( sal_Int8 nB ) : + sZeroStr( GetXMLToken(XML_NO_LIMIT) ), + nBytes( nB ) +{ +} + +XMLNumberNonePropHdl::XMLNumberNonePropHdl( enum XMLTokenEnum eZeroString, sal_Int8 nB ) : + sZeroStr( GetXMLToken( eZeroString ) ), + nBytes( nB ) +{ +} + +XMLNumberNonePropHdl::~XMLNumberNonePropHdl() +{ + // nothing to do +} + +bool XMLNumberNonePropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + sal_Int32 nValue = 0; + if( rStrImpValue == sZeroStr ) + { + bRet = true; + } + else + { + bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + } + lcl_xmloff_setAny( rValue, nValue, nBytes ); + + return bRet; +} + +bool XMLNumberNonePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + if( nValue == 0 ) + { + rStrExpValue = sZeroStr; + } + else + { + rStrExpValue = OUString::number( nValue ); + } + + bRet = true; + } + + return bRet; +} + + +XMLMeasurePropHdl::~XMLMeasurePropHdl() +{ + // nothing to do +} + +bool XMLMeasurePropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + sal_Int32 nValue = 0; + bool bRet = rUnitConverter.convertMeasureToCore( nValue, rStrImpValue ); + lcl_xmloff_setAny( rValue, nValue, nBytes ); + return bRet; +} + +bool XMLMeasurePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + OUStringBuffer aOut; + rUnitConverter.convertMeasureToXML( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLBoolFalsePropHdl::~XMLBoolFalsePropHdl() +{ + // nothing to do +} + +bool XMLBoolFalsePropHdl::importXML( const OUString&, Any&, const SvXMLUnitConverter& ) const +{ + return false; +} + +bool XMLBoolFalsePropHdl::exportXML( OUString& rStrExpValue, const Any& /*rValue*/, const SvXMLUnitConverter& rCnv) const +{ + return XMLBoolPropHdl::exportXML( rStrExpValue, Any( false ), rCnv ); +} + + +XMLBoolPropHdl::~XMLBoolPropHdl() +{ + // nothing to do +} + +bool XMLBoolPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue(false); + bool const bRet = ::sax::Converter::convertBool( bValue, rStrImpValue ); + rValue <<= bValue; + + return bRet; +} + +bool XMLBoolPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + OUStringBuffer aOut; + ::sax::Converter::convertBool( aOut, bValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLNBoolPropHdl::~XMLNBoolPropHdl() +{ + // nothing to do +} + +bool XMLNBoolPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue(false); + bool const bRet = ::sax::Converter::convertBool( bValue, rStrImpValue ); + rValue <<= !bValue; + + return bRet; +} + +bool XMLNBoolPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + bool bValue; + + if (rValue >>= bValue) + { + OUStringBuffer aOut; + ::sax::Converter::convertBool( aOut, !bValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLPercentPropHdl::~XMLPercentPropHdl() +{ + // nothing to do +} + +bool XMLPercentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool const bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + lcl_xmloff_setAny( rValue, nValue, nBytes ); + + return bRet; +} + +bool XMLPercentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +bool XMLDoublePercentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + double fValue = 1.0; + + if( rStrImpValue.indexOf( '%' ) == -1 ) + { + fValue = rStrImpValue.toDouble(); + } + else + { + sal_Int32 nValue = 0; + bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + fValue = static_cast(nValue) / 100.0; + } + rValue <<= fValue; + + return bRet; +} + +bool XMLDoublePercentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + double fValue = 0; + + if( rValue >>= fValue ) + { + fValue *= 100.0; + if( fValue > 0 ) fValue += 0.5; else fValue -= 0.5; + + sal_Int32 nValue = static_cast(fValue); + + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +bool XML100thPercentPropHdl::importXML(const OUString& rStrImpValue, Any& rValue, + const SvXMLUnitConverter&) const +{ + bool bRet = false; + + sal_Int32 nValue = 0; + bRet = sax::Converter::convertPercent(nValue, rStrImpValue); + rValue <<= static_cast(nValue * 100); + + return bRet; +} + +bool XML100thPercentPropHdl::exportXML(OUString& rStrExpValue, const Any& rValue, + const SvXMLUnitConverter&) const +{ + bool bRet = false; + sal_Int16 nValue = 0; + + if (rValue >>= nValue) + { + nValue = std::round(static_cast(nValue) / 100); + OUStringBuffer aOut; + sax::Converter::convertPercent(aOut, nValue); + rStrExpValue = aOut.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + + +XMLNegPercentPropHdl::~XMLNegPercentPropHdl() +{ + // nothing to do +} + +bool XMLNegPercentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + if (bRet) + bRet = !o3tl::checked_sub(100, nValue, nValue); + if (bRet) + lcl_xmloff_setAny( rValue, nValue, nBytes ); + return bRet; +} + +bool XMLNegPercentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, 100-nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +XMLMeasurePxPropHdl::~XMLMeasurePxPropHdl() +{ + // nothing to do +} + +bool XMLMeasurePxPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool bRet = ::sax::Converter::convertMeasurePx( nValue, rStrImpValue ); + lcl_xmloff_setAny( rValue, nValue, nBytes ); + return bRet; +} + +bool XMLMeasurePxPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nValue; + + if( lcl_xmloff_getAny( rValue, nValue, nBytes ) ) + { + OUStringBuffer aOut; + ::sax::Converter::convertMeasurePx( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLColorPropHdl::~XMLColorPropHdl() +{ + // Nothing to do +} + +bool XMLColorPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( rStrImpValue.matchIgnoreAsciiCase( "hsl" ) ) + { + sal_Int32 nOpen = rStrImpValue.indexOf( '(' ); + sal_Int32 nClose = rStrImpValue.lastIndexOf( ')' ); + + if( (nOpen != -1) && (nClose > nOpen) ) + { + const std::u16string_view aTmp( rStrImpValue.subView( nOpen+1, nClose - nOpen-1) ); + + sal_Int32 nIndex = 0; + + Sequence< double > aHSL + { + o3tl::toDouble(o3tl::getToken(aTmp, 0, ',', nIndex )), + o3tl::toDouble(o3tl::getToken(aTmp, 0, ',', nIndex )) / 100.0, + o3tl::toDouble(o3tl::getToken(aTmp, 0, ',', nIndex )) / 100.0 + }; + rValue <<= aHSL; + bRet = true; + } + } + else + { + sal_Int32 nColor(0); + bRet = ::sax::Converter::convertColor( nColor, rStrImpValue ); + rValue <<= nColor; + } + + return bRet; +} + +bool XMLColorPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nColor = 0; + + OUStringBuffer aOut; + if( rValue >>= nColor ) + { + ::sax::Converter::convertColor( aOut, nColor ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + else + { + Sequence< double > aHSL; + if( (rValue >>= aHSL) && (aHSL.getLength() == 3) ) + { + rStrExpValue = "hsl(" + OUString::number(aHSL[0]) + "," + + OUString::number(aHSL[1] * 100.0) + "%," + + OUString::number(aHSL[2] * 100.0) + "%)"; + + bRet = true; + } + } + + return bRet; +} + + +XMLHexPropHdl::~XMLHexPropHdl() +{ + // Nothing to do +} + +bool XMLHexPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + sal_uInt32 nRsid; + bool bRet = SvXMLUnitConverter::convertHex( nRsid, rStrImpValue ); + rValue <<= nRsid; + + return bRet; +} + +bool XMLHexPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_uInt32 nRsid = 0; + + if( rValue >>= nRsid ) + { + OUStringBuffer aOut; + SvXMLUnitConverter::convertHex( aOut, nRsid ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + else + { + bRet = false; + } + + return bRet; +} + + +XMLStringPropHdl::~XMLStringPropHdl() +{ + // Nothing to do +} + +bool XMLStringPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + rValue <<= rStrImpValue; + return true; +} + +bool XMLStringPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( rValue >>= rStrExpValue ) + bRet = true; + + return bRet; +} + + +XMLStyleNamePropHdl::~XMLStyleNamePropHdl() +{ + // Nothing to do +} + +bool XMLStyleNamePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + + if( rValue >>= rStrExpValue ) + { + rStrExpValue = rUnitConverter.encodeStyleName( rStrExpValue ); + bRet = true; + } + + return bRet; +} + + +XMLDoublePropHdl::~XMLDoublePropHdl() +{ + // Nothing to do +} + +bool XMLDoublePropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + double fDblValue(0.0); + bool const bRet = ::sax::Converter::convertDouble(fDblValue, rStrImpValue); + rValue <<= fDblValue; + return bRet; +} + +bool XMLDoublePropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + double fValue = 0; + + if( rValue >>= fValue ) + { + OUStringBuffer aOut; + ::sax::Converter::convertDouble( aOut, fValue ); + rStrExpValue = aOut.makeStringAndClear(); + bRet = true; + } + + return bRet; +} + + +XMLColorTransparentPropHdl::XMLColorTransparentPropHdl( + enum XMLTokenEnum eTransparent ) : + sTransparent( GetXMLToken( + eTransparent != XML_TOKEN_INVALID ? eTransparent : XML_TRANSPARENT ) ) +{ + // Nothing to do +} + +XMLColorTransparentPropHdl::~XMLColorTransparentPropHdl() +{ + // Nothing to do +} + +bool XMLColorTransparentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + if( rStrImpValue != sTransparent ) + { + sal_Int32 nColor(0); + bRet = ::sax::Converter::convertColor( nColor, rStrImpValue ); + rValue <<= nColor; + } + + return bRet; +} + +bool XMLColorTransparentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nColor = 0; + + if( rStrExpValue == sTransparent ) + bRet = false; + else if( rValue >>= nColor ) + { + OUStringBuffer aOut; + ::sax::Converter::convertColor( aOut, nColor ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLIsTransparentPropHdl::XMLIsTransparentPropHdl( + enum XMLTokenEnum eTransparent, bool bTransPropVal ) : + sTransparent( GetXMLToken( + eTransparent != XML_TOKEN_INVALID ? eTransparent : XML_TRANSPARENT ) ), + bTransPropValue( bTransPropVal ) +{ +} + +XMLIsTransparentPropHdl::~XMLIsTransparentPropHdl() +{ + // Nothing to do +} + +bool XMLIsTransparentPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bValue = ( (rStrImpValue == sTransparent) == bTransPropValue); + rValue <<= bValue; + + return true; +} + +bool XMLIsTransparentPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + // MIB: This looks a bit strange, because bTransPropValue == bValue should + // do the same, but this only applies if 'true' is represented by the same + // 8 bit value in bValue and bTransPropValue. Who will ensure this? + bool bValue = *o3tl::doAccess(rValue); + bool bIsTrans = bTransPropValue ? bValue : !bValue; + + if( bIsTrans ) + { + rStrExpValue = sTransparent; + bRet = true; + } + + return bRet; +} + + +XMLColorAutoPropHdl::XMLColorAutoPropHdl() +{ + // Nothing to do +} + +XMLColorAutoPropHdl::~XMLColorAutoPropHdl() +{ + // Nothing to do +} + +bool XMLColorAutoPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + // This is a multi property: the value might be set to AUTO_COLOR + // already by the XMLIsAutoColorPropHdl! + sal_Int32 nColor = 0; + if( !(rValue >>= nColor) || -1 != nColor ) + { + bRet = ::sax::Converter::convertColor( nColor, rStrImpValue ); + if( bRet ) + rValue <<= nColor; + } + + return bRet; +} + +bool XMLColorAutoPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + + sal_Int32 nColor = 0; + if( (rValue >>= nColor) && -1 != nColor ) + { + OUStringBuffer aOut; + ::sax::Converter::convertColor( aOut, nColor ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLIsAutoColorPropHdl::XMLIsAutoColorPropHdl() +{ +} + +XMLIsAutoColorPropHdl::~XMLIsAutoColorPropHdl() +{ + // Nothing to do +} + +bool XMLIsAutoColorPropHdl::importXML( const OUString& rStrImpValue, Any& rValue, const SvXMLUnitConverter& ) const +{ + // An auto color overrides any other color set! + bool bValue; + bool const bRet = ::sax::Converter::convertBool( bValue, rStrImpValue ); + if( bRet && bValue ) + rValue <<= sal_Int32(-1); + + return true; +} + +bool XMLIsAutoColorPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int32 nColor = 0; + + if( (rValue >>= nColor) && -1 == nColor ) + { + OUStringBuffer aOut; + ::sax::Converter::convertBool( aOut, true ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + + +XMLCompareOnlyPropHdl::~XMLCompareOnlyPropHdl() +{ + // Nothing to do +} + +bool XMLCompareOnlyPropHdl::importXML( const OUString&, Any&, const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "importXML called for compare-only-property" ); + return false; +} + +bool XMLCompareOnlyPropHdl::exportXML( OUString&, const Any&, const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "exportXML called for compare-only-property" ); + return false; +} + + +XMLNumberWithoutZeroPropHdl::XMLNumberWithoutZeroPropHdl( sal_Int8 nB ) : + nBytes( nB ) +{ +} + +XMLNumberWithoutZeroPropHdl::~XMLNumberWithoutZeroPropHdl() +{ +} + +bool XMLNumberWithoutZeroPropHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool const bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + if( bRet ) + lcl_xmloff_setAny( rValue, nValue, nBytes ); + return bRet; +} + +bool XMLNumberWithoutZeroPropHdl::exportXML( OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter& ) const +{ + + sal_Int32 nValue = 0; + bool bRet = lcl_xmloff_getAny( rValue, nValue, nBytes ); + bRet &= nValue != 0; + + if( bRet ) + { + rStrExpValue = OUString::number(nValue); + } + + return bRet; +} + + +XMLNumberWithAutoForVoidPropHdl::~XMLNumberWithAutoForVoidPropHdl() +{ +} + +bool XMLNumberWithAutoForVoidPropHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + if( bRet ) + lcl_xmloff_setAny( rValue, nValue, 2 ); + else if( rStrImpValue == GetXMLToken( XML_AUTO ) ) + { + rValue.clear(); // void + bRet = true; + } + return bRet; +} + +bool XMLNumberWithAutoForVoidPropHdl::exportXML( + OUString& rStrExpValue, const Any& rValue, const SvXMLUnitConverter&) const +{ + + sal_Int32 nValue = 0; + bool bRet = lcl_xmloff_getAny( rValue, nValue, 2 ); + + // note: 0 is a valid value here, see CTF_PAGENUMBEROFFSET for when it isn't + + if (!bRet) + rStrExpValue = GetXMLToken( XML_AUTO ); + else + { + rStrExpValue = OUString::number(nValue); + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlbahdl.hxx b/xmloff/source/style/xmlbahdl.hxx new file mode 100644 index 000000000..09e392d6c --- /dev/null +++ b/xmloff/source/style/xmlbahdl.hxx @@ -0,0 +1,314 @@ +/* -*- 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 +#include + + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NUMBER +*/ +class XMLNumberPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; + +public: + explicit XMLNumberPropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLNumberPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NUMBER_NONE +*/ +class XMLNumberNonePropHdl : public XMLPropertyHandler +{ + OUString sZeroStr; + sal_Int8 nBytes; +public: + explicit XMLNumberNonePropHdl( sal_Int8 nB = 4 ); + XMLNumberNonePropHdl( enum ::xmloff::token::XMLTokenEnum eZeroString, sal_Int8 nB ); + virtual ~XMLNumberNonePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_MEASURE +*/ +class XMLMeasurePropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLMeasurePropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLMeasurePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_PERCENT +*/ +class XMLPercentPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLPercentPropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLPercentPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_PERCENT + that is mapped on a double from 0.0 to 1.0 +*/ +class XMLDoublePercentPropHdl : public XMLPropertyHandler +{ + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/// Maps between XML percentage and our 100th percent ints. +class XML100thPercentPropHdl : public XMLPropertyHandler +{ + virtual bool importXML(const OUString& rStrImpValue, css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter) const override; + virtual bool exportXML(OUString& rStrExpValue, const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NEG_PERCENT +*/ +class XMLNegPercentPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLNegPercentPropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLNegPercentPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_PERCENT +*/ +class XMLMeasurePxPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLMeasurePxPropHdl( sal_Int8 nB ) : nBytes( nB ) {} + virtual ~XMLMeasurePxPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_BOOL +*/ +class XMLBoolPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLBoolPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +class XMLBoolFalsePropHdl : public XMLBoolPropHdl +{ +public: + virtual ~XMLBoolFalsePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_COLOR +*/ +class XMLColorPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLColorPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_HEX +*/ +class XMLHexPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLHexPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_STRING +*/ +class XMLStringPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLStringPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_STYLENAME +*/ +class XMLStyleNamePropHdl : public XMLStringPropHdl +{ +public: + virtual ~XMLStyleNamePropHdl() override; + + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + + +/** + PropertyHandler for the XML-data-type: XML_TYPE_DOUBLE +*/ +class XMLDoublePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLDoublePropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NBOOL +*/ +class XMLNBoolPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLNBoolPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_COLORTRANSPARENT +*/ +class XMLColorTransparentPropHdl : public XMLPropertyHandler +{ + const OUString sTransparent; + +public: + explicit XMLColorTransparentPropHdl( enum ::xmloff::token::XMLTokenEnum eTransparent = xmloff::token::XML_TOKEN_INVALID ); + virtual ~XMLColorTransparentPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_ISTRANSPARENT +*/ +class XMLIsTransparentPropHdl : public XMLPropertyHandler +{ + const OUString sTransparent; + bool bTransPropValue; + +public: + XMLIsTransparentPropHdl( enum ::xmloff::token::XMLTokenEnum eTransparent = xmloff::token::XML_TOKEN_INVALID, + bool bTransPropValue = true ); + virtual ~XMLIsTransparentPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_COLORAUTO +*/ +class XMLColorAutoPropHdl : public XMLPropertyHandler +{ +public: + XMLColorAutoPropHdl(); + virtual ~XMLColorAutoPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_COLORISAUTO +*/ +class XMLIsAutoColorPropHdl : public XMLPropertyHandler +{ +public: + XMLIsAutoColorPropHdl(); + virtual ~XMLIsAutoColorPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + + +/** + PropertyHandler for properties that cannot make use of importXML + and exportXML methods, but can make use of the default comparison +*/ +class XMLCompareOnlyPropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLCompareOnlyPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/** + PropertyHandler for the XML-data-type: XML_TYPE_NUMBER_NO_ZERO + Reads/writes numeric properties, but fails for the value zero + (i.e., a value 0 property will not be written) +*/ +class XMLNumberWithoutZeroPropHdl : public XMLPropertyHandler +{ + sal_Int8 nBytes; +public: + explicit XMLNumberWithoutZeroPropHdl( sal_Int8 nB ); + virtual ~XMLNumberWithoutZeroPropHdl() override; + + virtual bool importXML( const OUString& rStrImpValue, css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( OUString& rStrExpValue, const css::uno::Any& rValue, const SvXMLUnitConverter& rUnitConverter ) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlexppr.cxx b/xmloff/source/style/xmlexppr.cxx new file mode 100644 index 000000000..d81253238 --- /dev/null +++ b/xmloff/source/style/xmlexppr.cxx @@ -0,0 +1,1129 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::std; +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::xmloff::token; + +#define GET_PROP_TYPE( f ) static_cast((f & XML_TYPE_PROP_MASK) >> XML_TYPE_PROP_SHIFT) +#define ENTRY(t) { GET_PROP_TYPE(XML_TYPE_PROP_##t), XML_##t##_PROPERTIES } + +namespace { + +struct XMLPropTokens_Impl +{ + sal_uInt16 nType; + XMLTokenEnum eToken; +}; + +const sal_uInt16 MAX_PROP_TYPES = + (XML_TYPE_PROP_END >> XML_TYPE_PROP_SHIFT) - + (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT); + +XMLPropTokens_Impl const aPropTokens[MAX_PROP_TYPES] = +{ + ENTRY(CHART), + ENTRY(GRAPHIC), + ENTRY(TABLE), + ENTRY(TABLE_COLUMN), + ENTRY(TABLE_ROW), + ENTRY(TABLE_CELL), + ENTRY(LIST_LEVEL), + ENTRY(PARAGRAPH), + ENTRY(TEXT), + ENTRY(DRAWING_PAGE), + ENTRY(PAGE_LAYOUT), + ENTRY(HEADER_FOOTER), + ENTRY(RUBY), + ENTRY(SECTION) +}; + +// public methods + +// Take all properties of the XPropertySet which are also found in the +// XMLPropertyMapEntry-array and which are not set to their default-value, +// if a state is available. +// After that I call the method 'ContextFilter'. + +struct ComparePropertyState +{ + bool operator()(XMLPropertyState const& lhs, XMLPropertyState const& rhs) + { + return lhs.mnIndex < rhs.mnIndex; + } +}; +class XMLPropertyStates_Impl +{ + o3tl::sorted_vector aPropStates; +public: + XMLPropertyStates_Impl(); + void AddPropertyState(const XMLPropertyState& rPropState); + void FillPropertyStateVector(std::vector& rVector); +}; + +XMLPropertyStates_Impl::XMLPropertyStates_Impl() +{ +} + +void XMLPropertyStates_Impl::AddPropertyState( + const XMLPropertyState& rPropState) +{ + aPropStates.insert(rPropState); +} + +void XMLPropertyStates_Impl::FillPropertyStateVector( + std::vector& rVector) +{ + rVector.insert( rVector.begin(), aPropStates.begin(), aPropStates.end() ); +} + +class FilterPropertyInfo_Impl +{ + OUString msApiName; + std::vector maIndexes; + +public: + + FilterPropertyInfo_Impl( const OUString& rApiName, + const sal_uInt32 nIndex); + + const OUString& GetApiName() const { return msApiName; } + std::vector& GetIndexes() { return maIndexes; } + + // for sort + bool operator< ( const FilterPropertyInfo_Impl& rArg ) const + { + return (GetApiName() < rArg.GetApiName()); + } +}; + +FilterPropertyInfo_Impl::FilterPropertyInfo_Impl( + const OUString& rApiName, + const sal_uInt32 nIndex ) : + msApiName( rApiName ) +{ + maIndexes.push_back(nIndex); +} + +typedef std::list FilterPropertyInfoList_Impl; + +class FilterPropertiesInfo_Impl +{ + FilterPropertyInfoList_Impl aPropInfos; + + std::optional> mxApiNames; + +public: + FilterPropertiesInfo_Impl(); + + void AddProperty(const OUString& rApiName, const sal_uInt32 nIndex); + const uno::Sequence& GetApiNames(); + void FillPropertyStateArray( + vector< XMLPropertyState >& rPropStates, + const Reference< XPropertySet >& xPropSet, + const rtl::Reference< XMLPropertySetMapper >& maPropMapper, + const bool bDefault); + sal_uInt32 GetPropertyCount() const { return aPropInfos.size(); } +}; + +FilterPropertiesInfo_Impl::FilterPropertiesInfo_Impl() +{ +} + +void FilterPropertiesInfo_Impl::AddProperty( + const OUString& rApiName, const sal_uInt32 nIndex) +{ + aPropInfos.emplace_back(rApiName, nIndex); + + OSL_ENSURE( !mxApiNames, "performance warning: API names already retrieved" ); + mxApiNames.reset(); +} + +const uno::Sequence& FilterPropertiesInfo_Impl::GetApiNames() +{ + if( !mxApiNames ) + { + // we have to do three things: + // 1) sort API names, + // 2) merge duplicates, + // 3) construct sequence + + // sort names + aPropInfos.sort(); + + // merge duplicates + if ( aPropInfos.size() > 1 ) + { + FilterPropertyInfoList_Impl::iterator aOld = aPropInfos.begin(); + FilterPropertyInfoList_Impl::iterator aEnd = aPropInfos.end(); + FilterPropertyInfoList_Impl::iterator aCurrent = aOld; + ++aCurrent; + + while ( aCurrent != aEnd ) + { + // equal to next element? + if ( aOld->GetApiName() == aCurrent->GetApiName() ) + { + // if equal: merge index lists + std::vector aMerged; + std::merge(aOld->GetIndexes().begin(), aOld->GetIndexes().end(), + aCurrent->GetIndexes().begin(), aCurrent->GetIndexes().end(), + std::back_inserter(aMerged)); + aOld->GetIndexes() = std::move(aMerged); + aCurrent->GetIndexes().clear(); + // erase element, and continue with next + aCurrent = aPropInfos.erase( aCurrent ); + } + else + { + // remember old element and continue with next + aOld = aCurrent; + ++aCurrent; + } + } + } + + // construct sequence + mxApiNames.emplace( aPropInfos.size() ); + OUString *pNames = mxApiNames->getArray(); + + for (auto const& propInfo : aPropInfos) + { + *pNames = propInfo.GetApiName(); + ++pNames; + } + } + + return *mxApiNames; +} + +void FilterPropertiesInfo_Impl::FillPropertyStateArray( + vector< XMLPropertyState >& rPropStates, + const Reference< XPropertySet >& rPropSet, + const rtl::Reference< XMLPropertySetMapper >& rPropMapper, + const bool bDefault ) +{ + XMLPropertyStates_Impl aPropStates; + + const uno::Sequence& rApiNames = GetApiNames(); + + Reference < XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY ); + if (xTolPropSet.is()) + { + if (!bDefault) + { + Sequence < beans::GetDirectPropertyTolerantResult > aResults(xTolPropSet->getDirectPropertyValuesTolerant(rApiNames)); + sal_Int32 nResultCount(aResults.getLength()); + if (nResultCount > 0) + { + const beans::GetDirectPropertyTolerantResult *pResults = aResults.getConstArray(); + FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin()); + XMLPropertyState aNewProperty( -1 ); + while (nResultCount > 0 && aPropIter != aPropInfos.end()) + { + if (pResults->Name == aPropIter->GetApiName()) + { + aNewProperty.mnIndex = -1; + aNewProperty.maValue = pResults->Value; + + for (auto const& index : aPropIter->GetIndexes()) + { + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + ++pResults; + --nResultCount; + } + ++aPropIter; + } + } + } + else + { + const Sequence < beans::GetPropertyTolerantResult > aResults(xTolPropSet->getPropertyValuesTolerant(rApiNames)); + OSL_ENSURE( rApiNames.getLength() == aResults.getLength(), "wrong implemented XTolerantMultiPropertySet" ); + FilterPropertyInfoList_Impl::iterator aPropIter(aPropInfos.begin()); + XMLPropertyState aNewProperty( -1 ); + OSL_ENSURE( aPropInfos.size() == static_cast(aResults.getLength()), "wrong implemented XTolerantMultiPropertySet??" ); + for( const auto& rResult : aResults ) + { + if ((rResult.Result == beans::TolerantPropertySetResultType::SUCCESS) && + ((rResult.State == PropertyState_DIRECT_VALUE) || (rResult.State == PropertyState_DEFAULT_VALUE))) + { + aNewProperty.mnIndex = -1; + aNewProperty.maValue = rResult.Value; + + for (auto const& index : aPropIter->GetIndexes()) + { + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + } + ++aPropIter; + } + } + } + else + { + Sequence < PropertyState > aStates; + const PropertyState *pStates = nullptr; + Reference< XPropertyState > xPropState( rPropSet, UNO_QUERY ); + if( xPropState.is() ) + { + aStates = xPropState->getPropertyStates( rApiNames ); + pStates = aStates.getConstArray(); + } + + Reference < XMultiPropertySet > xMultiPropSet( rPropSet, UNO_QUERY ); + if( xMultiPropSet.is() && !bDefault ) + { + Sequence < Any > aValues; + if( pStates ) + { + // step 1: get value count + sal_uInt32 nValueCount = 0; + + for (size_t i = 0; i < aPropInfos.size(); ++i, ++pStates) + { + if( *pStates == PropertyState_DIRECT_VALUE ) + nValueCount++; + } + + if( nValueCount ) + { + // step 2: collect property names + Sequence < OUString > aAPINames( nValueCount ); + OUString *pAPINames = aAPINames.getArray(); + + ::std::vector< FilterPropertyInfoList_Impl::iterator > aPropIters; + aPropIters.reserve( nValueCount ); + + FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin(); + OSL_ENSURE(aItr != aPropInfos.end(),"Invalid iterator!"); + + pStates = aStates.getConstArray(); + sal_uInt32 i = 0; + while( i < nValueCount ) + { + if( *pStates == PropertyState_DIRECT_VALUE ) + { + *pAPINames++ = aItr->GetApiName(); + aPropIters.push_back( aItr ); + ++i; + } + ++aItr; + ++pStates; + } + + aValues = xMultiPropSet->getPropertyValues( aAPINames ); + const Any *pValues = aValues.getConstArray(); + + ::std::vector< FilterPropertyInfoList_Impl::iterator >::const_iterator + pPropIter = aPropIters.begin(); + + XMLPropertyState aNewProperty( -1 ); + for( i = 0; i < nValueCount; ++i ) + { + aNewProperty.mnIndex = -1; + aNewProperty.maValue = *pValues; + + for (auto const& index : (*pPropIter)->GetIndexes()) + { + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + + ++pPropIter; + ++pValues; + } + } + } + else + { + aValues = xMultiPropSet->getPropertyValues( rApiNames ); + const Any *pValues = aValues.getConstArray(); + + FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin(); + for (size_t i = 0; i < aPropInfos.size(); ++i) + { + // The value is stored in the PropertySet itself, add to list. + XMLPropertyState aNewProperty( -1 ); + aNewProperty.maValue = *pValues; + ++pValues; + for (auto const& index : aItr->GetIndexes()) + { + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + ++aItr; + } + } + } + else + { + FilterPropertyInfoList_Impl::iterator aItr = aPropInfos.begin(); + for (size_t i = 0; i < aPropInfos.size(); ++i) + { + bool bDirectValue = + !pStates || *pStates == PropertyState_DIRECT_VALUE; + if( bDirectValue || bDefault ) + { + // The value is stored in the PropertySet itself, add to list. + bool bGotValue = false; + XMLPropertyState aNewProperty( -1 ); + for (auto const& index : aItr->GetIndexes()) + { + if( bDirectValue || + (rPropMapper->GetEntryFlags(index) & + MID_FLAG_DEFAULT_ITEM_EXPORT) != 0 ) + { + try + { + if( !bGotValue ) + { + aNewProperty.maValue = + rPropSet->getPropertyValue( aItr->GetApiName() ); + bGotValue = true; + } + aNewProperty.mnIndex = index; + aPropStates.AddPropertyState( aNewProperty ); + } + catch( UnknownPropertyException& ) + { + // might be a problem of getImplementationId + OSL_ENSURE( false, "unknown property in getPropertyValue" ); + } + + } + } + } + + ++aItr; + if( pStates ) + ++pStates; + } + } + } + aPropStates.FillPropertyStateVector(rPropStates); +} + +} + +struct SvXMLExportPropertyMapper::Impl +{ + typedef std::map, std::unique_ptr> CacheType; + CacheType maCache; + + rtl::Reference mxNextMapper; + rtl::Reference mxPropMapper; + + OUString maStyleName; +}; + +// ctor/dtor , class SvXMLExportPropertyMapper + +SvXMLExportPropertyMapper::SvXMLExportPropertyMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper ) : + mpImpl(new Impl) +{ + mpImpl->mxPropMapper = rMapper; +} + +SvXMLExportPropertyMapper::~SvXMLExportPropertyMapper() +{ +} + +void SvXMLExportPropertyMapper::ChainExportMapper( + const rtl::Reference< SvXMLExportPropertyMapper>& rMapper ) +{ + // add map entries from rMapper to current map + mpImpl->mxPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() ); + // rMapper uses the same map as 'this' + rMapper->mpImpl->mxPropMapper = mpImpl->mxPropMapper; + + // set rMapper as last mapper in current chain + rtl::Reference< SvXMLExportPropertyMapper > xNext = mpImpl->mxNextMapper; + if( xNext.is()) + { + while (xNext->mpImpl->mxNextMapper.is()) + xNext = xNext->mpImpl->mxNextMapper; + xNext->mpImpl->mxNextMapper = rMapper; + } + else + mpImpl->mxNextMapper = rMapper; + + // if rMapper was already chained, correct + // map pointer of successors + xNext = rMapper; + + while (xNext->mpImpl->mxNextMapper.is()) + { + xNext = xNext->mpImpl->mxNextMapper; + xNext->mpImpl->mxPropMapper = mpImpl->mxPropMapper; + } +} + +std::vector SvXMLExportPropertyMapper::Filter( + SvXMLExport const& rExport, + const uno::Reference& rPropSet, bool bEnableFoFontFamily ) const +{ + return Filter_(rExport, rPropSet, false, bEnableFoFontFamily); +} + +std::vector SvXMLExportPropertyMapper::FilterDefaults( + SvXMLExport const& rExport, + const uno::Reference& rPropSet ) const +{ + return Filter_(rExport, rPropSet, true, false/*bEnableFoFontFamily*/); +} + +vector SvXMLExportPropertyMapper::Filter_( + SvXMLExport const& rExport, + const Reference& xPropSet, bool bDefault, bool bEnableFoFontFamily ) const +{ + vector< XMLPropertyState > aPropStateArray; + + // Retrieve XPropertySetInfo and XPropertyState + Reference< XPropertySetInfo > xInfo( xPropSet->getPropertySetInfo() ); + if( !xInfo.is() ) + return aPropStateArray; + + sal_Int32 nProps = mpImpl->mxPropMapper->GetEntryCount(); + + FilterPropertiesInfo_Impl *pFilterInfo = nullptr; + + Impl::CacheType::iterator aIter = mpImpl->maCache.find(xInfo); + if (aIter != mpImpl->maCache.end()) + pFilterInfo = (*aIter).second.get(); + + bool bDelInfo = false; + if( !pFilterInfo ) + { + assert(GetODFDefaultVersion() != SvtSaveOptions::ODFVER_UNKNOWN); + const SvtSaveOptions::ODFSaneDefaultVersion nCurrentVersion(rExport.getSaneDefaultVersion()); + pFilterInfo = new FilterPropertiesInfo_Impl; + for( sal_Int32 i=0; i < nProps; i++ ) + { + // Are we allowed to ask for the property? (MID_FLAG_NO_PROP..) + // Does the PropertySet contain name of mpEntries-array ? + const OUString& rAPIName = mpImpl->mxPropMapper->GetEntryAPIName( i ); + const sal_Int32 nFlags = mpImpl->mxPropMapper->GetEntryFlags( i ); + if( (0 == (nFlags & MID_FLAG_NO_PROPERTY_EXPORT)) && + ( (0 != (nFlags & MID_FLAG_MUST_EXIST)) || + xInfo->hasPropertyByName( rAPIName ) ) ) + { + const SvtSaveOptions::ODFSaneDefaultVersion nEarliestODFVersionForExport( + mpImpl->mxPropMapper->GetEarliestODFVersionForExport(i)); + // note: only standard ODF versions are allowed here, + // only exception is the unknown future + assert((nEarliestODFVersionForExport & SvtSaveOptions::ODFSVER_EXTENDED) == 0 + || nEarliestODFVersionForExport == SvtSaveOptions::ODFSVER_FUTURE_EXTENDED); + static_assert(SvtSaveOptions::ODFSVER_LATEST_EXTENDED < SvtSaveOptions::ODFSVER_FUTURE_EXTENDED); + /// standard ODF namespaces for elements and attributes + static sal_uInt16 s_OdfNs[] = { + XML_NAMESPACE_OFFICE, + XML_NAMESPACE_STYLE, + XML_NAMESPACE_TEXT, + XML_NAMESPACE_TABLE, + XML_NAMESPACE_DRAW, + XML_NAMESPACE_FO, + XML_NAMESPACE_XLINK, + XML_NAMESPACE_DC, + XML_NAMESPACE_META, + XML_NAMESPACE_NUMBER, + XML_NAMESPACE_PRESENTATION, + XML_NAMESPACE_SVG, + XML_NAMESPACE_CHART, + XML_NAMESPACE_DR3D, + XML_NAMESPACE_MATH, + XML_NAMESPACE_FORM, + XML_NAMESPACE_SCRIPT, + XML_NAMESPACE_CONFIG, + XML_NAMESPACE_DB, + XML_NAMESPACE_XFORMS, + XML_NAMESPACE_SMIL, + XML_NAMESPACE_ANIMATION, + XML_NAMESPACE_XML, + XML_NAMESPACE_XHTML, + XML_NAMESPACE_GRDDL, + }; + static bool s_Assert(false); + if (!s_Assert) + { + assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs))); + s_Assert = true; + } + //static_assert(std::is_sorted(std::begin(s_OdfNs), std::end(s_OdfNs))); + auto const ns(mpImpl->mxPropMapper->GetEntryNameSpace(i)); + auto const iter(std::lower_bound(std::begin(s_OdfNs), std::end(s_OdfNs), + ns)); + bool const isExtension(iter == std::end(s_OdfNs) || *iter != ns + // FIXME: very special hack to suppress style:hyperlink + || (ns == XML_NAMESPACE_STYLE + && mpImpl->mxPropMapper->GetEntryXMLName(i) == GetXMLToken(XML_HYPERLINK))); + if (isExtension + ? ((nCurrentVersion & SvtSaveOptions::ODFSVER_EXTENDED) + // if it's in standard ODF, don't export extension + && (nCurrentVersion < nEarliestODFVersionForExport)) + : (nEarliestODFVersionForExport <= nCurrentVersion)) + { + pFilterInfo->AddProperty(rAPIName, i); + } + } + } + + // Check whether the property set info is destroyed if it is assigned to + // a weak reference only; If it is destroyed, then every instance of + // getPropertySetInfo returns a new object; such property set infos must + // not be cached: + WeakReference < XPropertySetInfo > xWeakInfo( xInfo ); + xInfo.clear(); + xInfo = xWeakInfo; + if( xInfo.is() ) + { + mpImpl->maCache.emplace(xInfo, std::unique_ptr(pFilterInfo)); + } + else + bDelInfo = true; + } + + if( pFilterInfo->GetPropertyCount() ) + { + try + { + pFilterInfo->FillPropertyStateArray( + aPropStateArray, xPropSet, mpImpl->mxPropMapper, bDefault); + } + catch( UnknownPropertyException& ) + { + // might be a problem of getImplementationId + OSL_ENSURE( false, "unknown property in getPropertyStates" ); + } + } + + // Call context-filter + if( !aPropStateArray.empty() ) + ContextFilter(bEnableFoFontFamily, aPropStateArray, xPropSet); + + // Have to do if we change from a vector to a list or something like that + + if( bDelInfo ) + delete pFilterInfo; + + return aPropStateArray; +} + +void SvXMLExportPropertyMapper::ContextFilter( + bool bEnableFoFontFamily, + vector< XMLPropertyState >& rProperties, + const Reference< XPropertySet >& rPropSet ) const +{ + // Derived class could implement this. + if (mpImpl->mxNextMapper.is()) + mpImpl->mxNextMapper->ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +// Compares two Sequences of XMLPropertyState: +// 1.Number of elements equal ? +// 2.Index of each element equal ? (So I know whether the propertynames are the same) +// 3.Value of each element equal ? +bool SvXMLExportPropertyMapper::Equals( + const vector< XMLPropertyState >& aProperties1, + const vector< XMLPropertyState >& aProperties2 ) const +{ + if (aProperties1.size() < aProperties2.size()) + return true; + if (aProperties1.size() > aProperties2.size()) + return false; + + sal_uInt32 nCount = aProperties1.size(); + + for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex) + { + const XMLPropertyState& rProp1 = aProperties1[ nIndex ]; + const XMLPropertyState& rProp2 = aProperties2[ nIndex ]; + + // Compare index. If equal, compare value + if( rProp1.mnIndex < rProp2.mnIndex ) + return true; + if( rProp1.mnIndex > rProp2.mnIndex ) + return false; + + if( rProp1.mnIndex != -1 ) + { + // Now compare values + if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) & + XML_TYPE_BUILDIN_CMP ) != 0 ) + { + // simple type ( binary compare ) + if ( rProp1.maValue != rProp2.maValue) + return false; + } + else + { + // complex type ( ask for compare-function ) + if (!mpImpl->mxPropMapper->GetPropertyHandler( + rProp1.mnIndex )->equals( rProp1.maValue, + rProp2.maValue )) + return false; + } + } + } + + return true; +} + +// Compares two Sequences of XMLPropertyState: +// 1.Number of elements equal ? +// 2.Index of each element equal ? (So I know whether the propertynames are the same) +// 3.Value of each element equal ? +bool SvXMLExportPropertyMapper::LessPartial( + const vector< XMLPropertyState >& aProperties1, + const vector< XMLPropertyState >& aProperties2 ) const +{ + if (aProperties1.size() < aProperties2.size()) + return true; + if (aProperties1.size() > aProperties2.size()) + return false; + + sal_uInt32 nCount = aProperties1.size(); + + for (sal_uInt32 nIndex = 0; nIndex < nCount; ++nIndex) + { + const XMLPropertyState& rProp1 = aProperties1[ nIndex ]; + const XMLPropertyState& rProp2 = aProperties2[ nIndex ]; + + // Compare index. If equal, compare value + if( rProp1.mnIndex < rProp2.mnIndex ) + return true; + if( rProp1.mnIndex > rProp2.mnIndex ) + return false; + + if( rProp1.mnIndex != -1 ) + { + // Now compare values + if ( (mpImpl->mxPropMapper->GetEntryType( rProp1.mnIndex ) & + XML_TYPE_BUILDIN_CMP ) != 0 ) + { + // simple type ( binary compare ) + if ( comphelper::anyLess(rProp1.maValue, rProp2.maValue) ) + return true; + if ( comphelper::anyLess(rProp2.maValue, rProp1.maValue ) ) + return false; + } + } + } + + return false; +} + +/** fills the given attribute list with the items in the given set +void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList, + const ::std::vector< XMLPropertyState >& rProperties, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + sal_uInt16 nFlags ) const +{ + _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap, + nFlags, 0, -1, -1 ); +} + +void SvXMLExportPropertyMapper::exportXML( SvXMLAttributeList& rAttrList, + const ::std::vector< XMLPropertyState >& rProperties, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx, + sal_uInt16 nFlags ) const +{ + _exportXML( rAttrList, rProperties, rUnitConverter, rNamespaceMap, + nFlags, 0, nPropMapStartIdx, nPropMapEndIdx ); +} +*/ + +void SvXMLExportPropertyMapper::exportXML( + SvXMLExport& rExport, + const ::std::vector< XMLPropertyState >& rProperties, + SvXmlExportFlags nFlags, + bool bUseExtensionNamespaceForGraphicProperties) const +{ + exportXML(rExport, rProperties, -1, -1, nFlags, bUseExtensionNamespaceForGraphicProperties); +} + + +void SvXMLExportPropertyMapper::exportXML( + SvXMLExport& rExport, + const ::std::vector< XMLPropertyState >& rProperties, + sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx, + SvXmlExportFlags nFlags, bool bUseExtensionNamespaceForGraphicProperties) const +{ + sal_uInt16 nPropTypeFlags = 0; + for( sal_uInt16 i=0; i aIndexArray; + + _exportXML( nPropType, nPropTypeFlags, + rExport.GetAttrList(), rProperties, + rExport.GetMM100UnitConverter(), + rExport.GetNamespaceMap(), + &aIndexArray, + nPropMapStartIdx, nPropMapEndIdx ); + + if( rExport.GetAttrList().getLength() > 0 || + !aIndexArray.empty() ) + { + SvXMLElementExport aElem( rExport, nNamespace, + aPropTokens[i].eToken, + bool(nFlags & SvXmlExportFlags::IGN_WS), + false ); + + exportElementItems( rExport, rProperties, nFlags, aIndexArray ); + } + } + } +} + +/** this method is called for every item that has the + MID_FLAG_SPECIAL_ITEM_EXPORT flag set */ +void SvXMLExportPropertyMapper::handleSpecialItem( + SvXMLAttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + OSL_ENSURE(mpImpl->mxNextMapper.is(), "special item not handled in xml export"); + if (mpImpl->mxNextMapper.is()) + mpImpl->mxNextMapper->handleSpecialItem( + rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx); +} + +/** this method is called for every item that has the + MID_FLAG_ELEMENT_EXPORT flag set */ +void SvXMLExportPropertyMapper::handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + OSL_ENSURE(mpImpl->mxNextMapper.is(), "element item not handled in xml export"); + if (mpImpl->mxNextMapper.is()) + mpImpl->mxNextMapper->handleElementItem(rExport, rProperty, nFlags, pProperties, nIdx); +} + +// protected methods + +/** fills the given attribute list with the items in the given set */ +void SvXMLExportPropertyMapper::_exportXML( + sal_uInt16 nPropType, sal_uInt16& rPropTypeFlags, + SvXMLAttributeList& rAttrList, + const ::std::vector< XMLPropertyState >& rProperties, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + std::vector* pIndexArray, + sal_Int32 nPropMapStartIdx, sal_Int32 nPropMapEndIdx ) const +{ + const sal_uInt32 nCount = rProperties.size(); + sal_uInt32 nIndex = 0; + + if( -1 == nPropMapStartIdx ) + nPropMapStartIdx = 0; + if( -1 == nPropMapEndIdx ) + nPropMapEndIdx = mpImpl->mxPropMapper->GetEntryCount(); + + while( nIndex < nCount ) + { + sal_Int32 nPropMapIdx = rProperties[nIndex].mnIndex; + if( nPropMapIdx >= nPropMapStartIdx && + nPropMapIdx < nPropMapEndIdx )// valid entry? + { + sal_uInt32 nEFlags = mpImpl->mxPropMapper->GetEntryFlags(nPropMapIdx); + sal_uInt16 nEPType = GET_PROP_TYPE(nEFlags); + OSL_ENSURE(nEPType >= (XML_TYPE_PROP_START >> XML_TYPE_PROP_SHIFT), + "no prop type specified"); + rPropTypeFlags |= (1 << nEPType); + if( nEPType == nPropType ) + { + // we have a valid map entry here, so lets use it... + if( ( nEFlags & MID_FLAG_ELEMENT_ITEM_EXPORT ) != 0 ) + { + // element items do not add any properties, + // we export it later + if( pIndexArray ) + { + pIndexArray->push_back( static_cast(nIndex) ); + } + } + else + { + _exportXML( rAttrList, rProperties[nIndex], rUnitConverter, + rNamespaceMap, &rProperties, nIndex ); + } + } + } + + nIndex++; + } +} + +namespace +{ +// -1 = Attribute needs extended namespace, but current ODF version is strict. +// 1 = Attribute needs extended namespace and current ODF version allows it. +// 0 = Attribute does not need extended namespace +sal_Int8 CheckExtendedNamespace(std::u16string_view sXMLAttributeName, std::u16string_view sValue, + const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion) +{ + if (IsXMLToken(sXMLAttributeName, XML_WRITING_MODE) && IsXMLToken(sValue, XML_BT_LR)) + return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1; + else if (IsXMLToken(sXMLAttributeName, XML_VERTICAL_REL) + && (IsXMLToken(sValue, XML_PAGE_CONTENT_BOTTOM) + || IsXMLToken(sValue, XML_PAGE_CONTENT_TOP))) + return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1; + return 0; +} +} + +void SvXMLExportPropertyMapper::_exportXML( + SvXMLAttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_SPECIAL_ITEM_EXPORT) != 0) + { + uno::Reference< container::XNameContainer > xAttrContainer; + if( (rProperty.maValue >>= xAttrContainer) && xAttrContainer.is() ) + { + std::unique_ptr pNewNamespaceMap; + const SvXMLNamespaceMap *pNamespaceMap = &rNamespaceMap; + + const uno::Sequence< OUString > aAttribNames( xAttrContainer->getElementNames() ); + + OUStringBuffer sNameBuffer; + xml::AttributeData aData; + for( const auto& rAttribName : aAttribNames ) + { + xAttrContainer->getByName( rAttribName ) >>= aData; + OUString sAttribName( rAttribName ); + + // extract namespace prefix from attribute name if it exists + OUString sPrefix; + const sal_Int32 nColonPos = + rAttribName.indexOf( ':' ); + if( nColonPos != -1 ) + sPrefix = rAttribName.copy( 0, nColonPos ); + + if( !sPrefix.isEmpty() ) + { + OUString sNamespace( aData.Namespace ); + + // if the prefix isn't defined yet or has another meaning, + // we have to redefine it now. + sal_uInt16 nKey = pNamespaceMap->GetKeyByPrefix( sPrefix ); + if( USHRT_MAX == nKey || pNamespaceMap->GetNameByKey( nKey ) != sNamespace ) + { + bool bAddNamespace = false; + if( USHRT_MAX == nKey ) + { + // The prefix is unused, so it is sufficient + // to add it to the namespace map. + bAddNamespace = true; + } + else + { + // check if there is a prefix registered for the + // namespace URI + nKey = pNamespaceMap->GetKeyByName( sNamespace ); + if( XML_NAMESPACE_UNKNOWN == nKey ) + { + // There is no prefix for the namespace, so + // we have to generate one and have to add it. + sal_Int32 n=0; + OUString sOrigPrefix( sPrefix ); + do + { + sNameBuffer.append( sOrigPrefix ); + sNameBuffer.append( ++n ); + sPrefix = sNameBuffer.makeStringAndClear(); + nKey = pNamespaceMap->GetKeyByPrefix( sPrefix ); + } + while( nKey != USHRT_MAX ); + + bAddNamespace = true; + } + else + { + // If there is a prefix for the namespace, + // we reuse that. + sPrefix = pNamespaceMap->GetPrefixByKey( nKey ); + } + // In any case, the attribute name has to be adapted. + sNameBuffer.append(sPrefix + ":" + rAttribName.subView(nColonPos+1)); + sAttribName = sNameBuffer.makeStringAndClear(); + } + + if( bAddNamespace ) + { + if( !pNewNamespaceMap ) + { + pNewNamespaceMap.reset(new SvXMLNamespaceMap( rNamespaceMap )); + pNamespaceMap = pNewNamespaceMap.get(); + } + pNewNamespaceMap->Add( sPrefix, sNamespace ); + OUString sAttr = GetXMLToken(XML_XMLNS) + ":" + sPrefix; + rAttrList.AddAttribute( sAttr, sNamespace ); + } + } + } + OUString sOldValue( rAttrList.getValueByName( sAttribName ) ); + OSL_ENSURE( sOldValue.isEmpty(), "alien attribute exists already" ); + OSL_ENSURE(aData.Type == GetXMLToken(XML_CDATA), "different type to our default type which should be written out"); + if( sOldValue.isEmpty() ) + rAttrList.AddAttribute( sAttribName, aData.Value ); + } + } + else + { + handleSpecialItem( rAttrList, rProperty, rUnitConverter, + rNamespaceMap, pProperties, nIdx ); + } + } + else if ((mpImpl->mxPropMapper->GetEntryFlags(rProperty.mnIndex) & MID_FLAG_ELEMENT_ITEM_EXPORT ) == 0) + { + OUString aValue; + OUString sName = rNamespaceMap.GetQNameByKey( + mpImpl->mxPropMapper->GetEntryNameSpace(rProperty.mnIndex), + mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); + + bool bRemove = false; + if ((mpImpl->mxPropMapper->GetEntryFlags( rProperty.mnIndex ) & MID_FLAG_MERGE_ATTRIBUTE) != 0) + { + aValue = rAttrList.getValueByName( sName ); + bRemove = true; + } + + if (mpImpl->mxPropMapper->exportXML(aValue, rProperty, rUnitConverter)) + { + if( bRemove ) + rAttrList.RemoveAttribute( sName ); + + // We don't seem to have a generic mechanism to write an attribute in the extension + // namespace in case of certain attribute values only, so do this manually. + sal_Int8 nExtendedStatus + = CheckExtendedNamespace(mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex), + aValue, rUnitConverter.getSaneDefaultVersion()); + if (nExtendedStatus == -1) + return; + if (nExtendedStatus == 1) + sName = rNamespaceMap.GetQNameByKey( + XML_NAMESPACE_LO_EXT, mpImpl->mxPropMapper->GetEntryXMLName(rProperty.mnIndex)); + rAttrList.AddAttribute( sName, aValue ); + } + } +} + +void SvXMLExportPropertyMapper::exportElementItems( + SvXMLExport& rExport, + const ::std::vector< XMLPropertyState >& rProperties, + SvXmlExportFlags nFlags, + const std::vector& rIndexArray ) const +{ + bool bItemsExported = false; + for (const sal_uInt16 nElement : rIndexArray) + { + OSL_ENSURE( 0 != (mpImpl->mxPropMapper->GetEntryFlags( + rProperties[nElement].mnIndex ) & MID_FLAG_ELEMENT_ITEM_EXPORT), + "wrong mid flag!" ); + + rExport.IgnorableWhitespace(); + handleElementItem( rExport, rProperties[nElement], + nFlags, &rProperties, nElement ); + bItemsExported = true; + } + + if( bItemsExported ) + rExport.IgnorableWhitespace(); +} + +const rtl::Reference& SvXMLExportPropertyMapper::getPropertySetMapper() const +{ + return mpImpl->mxPropMapper; +} + +void SvXMLExportPropertyMapper::SetStyleName( const OUString& rStyleName ) +{ + mpImpl->maStyleName = rStyleName; +} + +const OUString& SvXMLExportPropertyMapper::GetStyleName() const +{ + return mpImpl->maStyleName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlimppr.cxx b/xmloff/source/style/xmlimppr.cxx new file mode 100644 index 000000000..e8ecf4109 --- /dev/null +++ b/xmloff/source/style/xmlimppr.cxx @@ -0,0 +1,762 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::xml; +using namespace ::com::sun::star::xml::sax; + +using namespace ::std; +using namespace ::xmloff::token; +using ::com::sun::star::lang::IllegalArgumentException; +using ::com::sun::star::lang::WrappedTargetException; +using ::com::sun::star::beans::UnknownPropertyException; +using ::com::sun::star::beans::PropertyVetoException; + + +SvXMLImportPropertyMapper::SvXMLImportPropertyMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLImport& rImp ): + rImport(rImp), + maPropMapper ( rMapper ) +{ +} + +SvXMLImportPropertyMapper::~SvXMLImportPropertyMapper() +{ + mxNextMapper = nullptr; +} + +void SvXMLImportPropertyMapper::ChainImportMapper( + const rtl::Reference< SvXMLImportPropertyMapper>& rMapper ) +{ + // add map entries from rMapper to current map + maPropMapper->AddMapperEntry( rMapper->getPropertySetMapper() ); + // rMapper uses the same map as 'this' + rMapper->maPropMapper = maPropMapper; + + // set rMapper as last mapper in current chain + rtl::Reference< SvXMLImportPropertyMapper > xNext = mxNextMapper; + if( xNext.is()) + { + while( xNext->mxNextMapper.is()) + xNext = xNext->mxNextMapper; + xNext->mxNextMapper = rMapper; + } + else + mxNextMapper = rMapper; + + // if rMapper was already chained, correct + // map pointer of successors + xNext = rMapper; + + while( xNext->mxNextMapper.is()) + { + xNext = xNext->mxNextMapper; + xNext->maPropMapper = maPropMapper; + } +} + +/** fills the given itemset with the attributes in the given list */ +void SvXMLImportPropertyMapper::importXML( + vector< XMLPropertyState >& rProperties, + const Reference< XFastAttributeList >& xAttrList, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + sal_uInt32 nPropType, + sal_Int32 nStartIdx, + sal_Int32 nEndIdx ) const +{ + Reference< XNameContainer > xAttrContainer; + + if( -1 == nStartIdx ) + nStartIdx = 0; + if( -1 == nEndIdx ) + nEndIdx = maPropMapper->GetEntryCount(); + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + sal_Int32 nToken = aIter.getToken(); + if( IsTokenInNamespace(nToken, XML_NAMESPACE_XMLNS) ) + continue; + + const OUString aPrefix = SvXMLImport::getNamespacePrefixFromToken(nToken, &rNamespaceMap); + const OUString aNamespaceURI = SvXMLImport::getNamespaceURIFromToken(nToken); + OUString sAttrName = SvXMLImport::getNameFromToken( nToken ); + if ( !aPrefix.isEmpty() ) + sAttrName = aPrefix + SvXMLImport::aNamespaceSeparator + sAttrName; + + const OUString sValue = aIter.toString(); + + importXMLAttribute(rProperties, rUnitConverter, rNamespaceMap, + nPropType, nStartIdx, nEndIdx, xAttrContainer, + sAttrName, aNamespaceURI, sValue); + } + + const css::uno::Sequence< css::xml::Attribute > unknownAttribs = xAttrList->getUnknownAttributes(); + for (const css::xml::Attribute& rAttribute : unknownAttribs) + { + int nSepIndex = rAttribute.Name.indexOf(SvXMLImport::aNamespaceSeparator); + if (nSepIndex != -1) + { + // If it's an unknown attribute in a known namespace, ignore it. + OUString aPrefix = rAttribute.Name.copy(0, nSepIndex); + auto nKey = rNamespaceMap.GetKeyByPrefix(aPrefix); + if (nKey != USHRT_MAX && !(nKey & XML_NAMESPACE_UNKNOWN_FLAG)) + continue; + } + + importXMLAttribute(rProperties, rUnitConverter, rNamespaceMap, + nPropType, nStartIdx, nEndIdx, xAttrContainer, + rAttribute.Name, rAttribute.NamespaceURL, rAttribute.Value); + } + + finished( rProperties, nStartIdx, nEndIdx ); +} + +void SvXMLImportPropertyMapper::importXMLAttribute( + vector< XMLPropertyState >& rProperties, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const sal_uInt32 nPropType, + const sal_Int32 nStartIdx, + const sal_Int32 nEndIdx, + Reference< XNameContainer >& xAttrContainer, + const OUString& rAttrName, + const OUString& aNamespaceURI, + const OUString& sValue) const +{ + OUString aLocalName, aPrefix, aNamespace; + sal_uInt16 nPrefix = rNamespaceMap.GetKeyByAttrName( rAttrName, &aPrefix, + &aLocalName, &aNamespace ); + + // index of actual property map entry + // This looks very strange, but it works well: + // If the start index is 0, the new value will become -1, and + // GetEntryIndex will start searching with position 0. + // Otherwise GetEntryIndex will start with the next position specified. + sal_Int32 nIndex = nStartIdx - 1; + sal_uInt32 nFlags = 0; // flags of actual property map entry + bool bFound = false; + + // for better error reporting: this should be set true if no + // warning is needed + bool bNoWarning = false; + + do + { + // find an entry for this attribute + nIndex = maPropMapper->GetEntryIndex( nPrefix, aLocalName, + nPropType, nIndex ); + + if( nIndex > -1 && nIndex < nEndIdx ) + { + // create a XMLPropertyState with an empty value + + nFlags = maPropMapper->GetEntryFlags( nIndex ); + if( ( nFlags & MID_FLAG_ELEMENT_ITEM_IMPORT ) == 0 ) + { + XMLPropertyState aNewProperty( nIndex ); + sal_Int32 nReference = -1; + + // if this is a multi attribute check if another attribute already set + // this any. If so use this as an initial value + if( ( nFlags & MID_FLAG_MERGE_PROPERTY ) != 0 ) + { + const OUString aAPIName( maPropMapper->GetEntryAPIName( nIndex ) ); + const sal_Int32 nSize = rProperties.size(); + for( nReference = 0; nReference < nSize; nReference++ ) + { + sal_Int32 nRefIdx = rProperties[nReference].mnIndex; + if( (nRefIdx != -1) && (nIndex != nRefIdx) && + (maPropMapper->GetEntryAPIName( nRefIdx ) == aAPIName )) + { + aNewProperty = rProperties[nReference]; + aNewProperty.mnIndex = nIndex; + break; + } + } + + if( nReference == nSize ) + nReference = -1; + } + + bool bSet = false; + if( ( nFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) == 0 ) + { + // let the XMLPropertySetMapper decide how to import the value + bSet = maPropMapper->importXML( sValue, aNewProperty, + rUnitConverter ); + } + else + { + sal_uInt32 nOldSize = rProperties.size(); + + bSet = handleSpecialItem( aNewProperty, rProperties, + sValue, rUnitConverter, + rNamespaceMap ); + + // no warning if handleSpecialItem added properties + bNoWarning |= ( nOldSize != rProperties.size() ); + } + + // no warning if we found could set the item. This + // 'remembers' bSet across multi properties. + bNoWarning |= bSet; + + // store the property in the given vector + if( bSet ) + { + if( nReference == -1 ) + rProperties.push_back( aNewProperty ); + else + rProperties[nReference] = aNewProperty; + } + else + { + // warn about unknown value. Unless it's a + // multi property: Then we get another chance + // to set the value. + if( !bNoWarning && + ((nFlags & MID_FLAG_MULTI_PROPERTY) == 0) ) + { + rImport.SetError( XMLERROR_FLAG_WARNING | + XMLERROR_STYLE_ATTR_VALUE, + { rAttrName, sValue } ); + } + } + } + bFound = true; + continue; + } + + if( !bFound ) + { + SAL_INFO_IF((XML_NAMESPACE_NONE != nPrefix) && + !(XML_NAMESPACE_UNKNOWN_FLAG & nPrefix), + "xmloff.style", + "unknown attribute: \"" << rAttrName << "\""); + if( (XML_NAMESPACE_UNKNOWN_FLAG & nPrefix) || (XML_NAMESPACE_NONE == nPrefix) ) + { + if( !xAttrContainer.is() ) + { + // add an unknown attribute container to the properties + Reference< XNameContainer > xNew( SvUnoAttributeContainer_CreateInstance(), UNO_QUERY ); + xAttrContainer = xNew; + + // find map entry and create new property state + if( -1 == nIndex ) + { + switch( nPropType ) + { + case XML_TYPE_PROP_CHART: + nIndex = maPropMapper->FindEntryIndex( "ChartUserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) ); + break; + case XML_TYPE_PROP_PARAGRAPH: + nIndex = maPropMapper->FindEntryIndex( "ParaUserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) ); + break; + case XML_TYPE_PROP_TEXT: + nIndex = maPropMapper->FindEntryIndex( "TextUserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) ); + break; + default: + break; + } + // other property type or property not found + if( -1 == nIndex ) + nIndex = maPropMapper->FindEntryIndex( "UserDefinedAttributes", XML_NAMESPACE_TEXT, GetXMLToken(XML_XMLNS) ); + } + + // #106963#; use userdefined attribute only if it is in the specified property range + if( nIndex != -1 && nIndex >= nStartIdx && nIndex < nEndIdx) + { + XMLPropertyState aNewProperty( nIndex, Any(xAttrContainer) ); + + // push it on our stack so we export it later + rProperties.push_back( aNewProperty ); + } + } + + if( xAttrContainer.is() ) + { + AttributeData aData; + aData.Type = GetXMLToken( XML_CDATA ); + aData.Value = sValue; + OUString sName; + if( XML_NAMESPACE_NONE != nPrefix ) + { + sName = rAttrName; + aData.Namespace = aNamespaceURI; + } + else + sName = aLocalName; + xAttrContainer->insertByName( sName, Any(aData) ); + } + } + } + } + while( ( nIndex >= 0 && nIndex + 1 < nEndIdx ) && (( nFlags & MID_FLAG_MULTI_PROPERTY ) != 0 ) ); +} + +/** this method is called for every item that has the MID_FLAG_SPECIAL_ITEM_IMPORT flag set */ +bool SvXMLImportPropertyMapper::handleSpecialItem( + XMLPropertyState& rProperty, + vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const +{ + OSL_ENSURE( mxNextMapper.is(), "unsupported special item in xml import" ); + if( mxNextMapper.is() ) + return mxNextMapper->handleSpecialItem( rProperty, rProperties, rValue, + rUnitConverter, rNamespaceMap ); + else + return false; +} + +void SvXMLImportPropertyMapper::FillPropertySequence( + const ::std::vector< XMLPropertyState >& rProperties, + css::uno::Sequence< css::beans::PropertyValue >& rValues ) + const +{ + sal_Int32 nCount = rProperties.size(); + sal_Int32 nValueCount = 0; + rValues.realloc( nCount ); + PropertyValue *pProps = rValues.getArray(); + for( sal_Int32 i=0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = rProperties[i]; + sal_Int32 nIdx = rProp.mnIndex; + if( nIdx == -1 ) + continue; + pProps->Name = maPropMapper->GetEntryAPIName( nIdx ); + if( !pProps->Name.isEmpty() ) + { + pProps->Value = rProp.maValue; + ++pProps; + ++nValueCount; + } + } + if( nValueCount < nCount ) + rValues.realloc( nValueCount ); +} + +void SvXMLImportPropertyMapper::CheckSpecialContext( + const ::std::vector< XMLPropertyState >& aProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet, + ContextID_Index_Pair* pSpecialContextIds ) const +{ + OSL_ENSURE( rPropSet.is(), "need an XPropertySet" ); + sal_Int32 nCount = aProperties.size(); + + for( sal_Int32 i=0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = aProperties[i]; + sal_Int32 nIdx = rProp.mnIndex; + + // disregard property state if it has an invalid index + if( -1 == nIdx ) + continue; + + const sal_Int32 nPropFlags = maPropMapper->GetEntryFlags( nIdx ); + + // handle no-property and special items + if( ( pSpecialContextIds != nullptr ) && + ( ( 0 != ( nPropFlags & MID_FLAG_NO_PROPERTY_IMPORT ) ) || + ( 0 != ( nPropFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) ) ) ) + { + // maybe it's one of our special context ids? + sal_Int16 nContextId = maPropMapper->GetEntryContextId(nIdx); + + for ( sal_Int32 n = 0; + pSpecialContextIds[n].nContextID != -1; + n++ ) + { + // found: set index in pSpecialContextIds array + if ( pSpecialContextIds[n].nContextID == nContextId ) + { + pSpecialContextIds[n].nIndex = i; + break; // early out + } + } + } + } + +} + +bool SvXMLImportPropertyMapper::FillPropertySet( + const vector< XMLPropertyState >& aProperties, + const Reference< XPropertySet >& rPropSet, + ContextID_Index_Pair* pSpecialContextIds ) const +{ + bool bSet = false; + + Reference< XTolerantMultiPropertySet > xTolPropSet( rPropSet, UNO_QUERY ); + if (xTolPropSet.is()) + bSet = FillTolerantMultiPropertySet_( aProperties, xTolPropSet, maPropMapper, rImport, + pSpecialContextIds ); + + if (!bSet) + { + // get property set info + Reference< XPropertySetInfo > xInfo(rPropSet->getPropertySetInfo()); + + // check for multi-property set + Reference xMultiPropSet( rPropSet, UNO_QUERY ); + if ( xMultiPropSet.is() ) + { + // Try XMultiPropertySet. If that fails, try the regular route. + bSet = FillMultiPropertySet_( aProperties, xMultiPropSet, + xInfo, maPropMapper, + pSpecialContextIds ); + if ( !bSet ) + bSet = FillPropertySet_( aProperties, rPropSet, + xInfo, maPropMapper, rImport, + pSpecialContextIds); + } + else + bSet = FillPropertySet_( aProperties, rPropSet, xInfo, + maPropMapper, rImport, + pSpecialContextIds ); + } + + return bSet; +} + +bool SvXMLImportPropertyMapper::FillPropertySet_( + const vector & rProperties, + const Reference & rPropSet, + const Reference & rPropSetInfo, + const rtl::Reference & rPropMapper, + SvXMLImport& rImport, + ContextID_Index_Pair* pSpecialContextIds ) +{ + OSL_ENSURE( rPropSet.is(), "need an XPropertySet" ); + OSL_ENSURE( rPropSetInfo.is(), "need an XPropertySetInfo" ); + + // preliminaries + bool bSet = false; + sal_Int32 nCount = rProperties.size(); + + // iterate over property states that we want to set + for( sal_Int32 i=0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = rProperties[i]; + sal_Int32 nIdx = rProp.mnIndex; + + // disregard property state if it has an invalid index + if( -1 == nIdx ) + continue; + + const OUString& rPropName = rPropMapper->GetEntryAPIName( nIdx ); + const sal_Int32 nPropFlags = rPropMapper->GetEntryFlags( nIdx ); + + if ( ( 0 == ( nPropFlags & MID_FLAG_NO_PROPERTY ) ) && + ( ( 0 != ( nPropFlags & MID_FLAG_MUST_EXIST ) ) || + rPropSetInfo->hasPropertyByName( rPropName ) ) ) + { + // try setting the property + try + { + rPropSet->setPropertyValue( rPropName, rProp.maValue ); + bSet = true; + } + catch ( const IllegalArgumentException& e ) + { + // illegal value: check whether this property is + // allowed to throw this exception + if ( 0 == ( nPropFlags & MID_FLAG_PROPERTY_MAY_THROW ) ) + { + Sequence aSeq { rPropName }; + rImport.SetError( + XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_ERROR, + aSeq, e.Message, nullptr ); + } + } + catch ( const UnknownPropertyException& e ) + { + // unknown property: This is always an error! + Sequence aSeq { rPropName }; + rImport.SetError( + XMLERROR_STYLE_PROP_UNKNOWN | XMLERROR_FLAG_ERROR, + aSeq, e.Message, nullptr ); + } + catch ( const PropertyVetoException& e ) + { + // property veto: this shouldn't happen + Sequence aSeq { rPropName }; + rImport.SetError( + XMLERROR_STYLE_PROP_OTHER | XMLERROR_FLAG_ERROR, + aSeq, e.Message, nullptr ); + } + catch ( const WrappedTargetException& e ) + { + // wrapped target: this shouldn't happen either + Sequence aSeq { rPropName }; + rImport.SetError( + XMLERROR_STYLE_PROP_OTHER | XMLERROR_FLAG_ERROR, + aSeq, e.Message, nullptr ); + } + } + + // handle no-property and special items + if( ( pSpecialContextIds != nullptr ) && + ( ( 0 != ( nPropFlags & MID_FLAG_NO_PROPERTY_IMPORT ) ) || + ( 0 != ( nPropFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) ) ) ) + { + // maybe it's one of our special context ids? + sal_Int16 nContextId = rPropMapper->GetEntryContextId(nIdx); + + for ( sal_Int32 n = 0; + pSpecialContextIds[n].nContextID != -1; + n++ ) + { + // found: set index in pSpecialContextIds array + if ( pSpecialContextIds[n].nContextID == nContextId ) + { + pSpecialContextIds[n].nIndex = i; + break; // early out + } + } + } + } + + return bSet; +} + + +typedef pair PropertyPair; + +namespace { + +struct PropertyPairLessFunctor +{ + bool operator()( const PropertyPair& a, const PropertyPair& b ) const + { + return (*a.first < *b.first); + } +}; + +} + +void SvXMLImportPropertyMapper::PrepareForMultiPropertySet_( + const vector & rProperties, + const Reference & rPropSetInfo, + const rtl::Reference & rPropMapper, + ContextID_Index_Pair* pSpecialContextIds, + Sequence& rNames, + Sequence& rValues) +{ + sal_Int32 nCount = rProperties.size(); + + // property pairs structure stores names + values of properties to be set. + vector aPropertyPairs; + aPropertyPairs.reserve( nCount ); + + // iterate over property states that we want to set + sal_Int32 i; + for( i = 0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = rProperties[i]; + sal_Int32 nIdx = rProp.mnIndex; + + // disregard property state if it has an invalid index + if( -1 == nIdx ) + continue; + + const OUString& rPropName = rPropMapper->GetEntryAPIName( nIdx ); + const sal_Int32 nPropFlags = rPropMapper->GetEntryFlags( nIdx ); + + if ( ( 0 == ( nPropFlags & MID_FLAG_NO_PROPERTY ) ) && + ( ( 0 != ( nPropFlags & MID_FLAG_MUST_EXIST ) ) || + !rPropSetInfo.is() || + rPropSetInfo->hasPropertyByName(rPropName) ) ) + { + // save property into property pair structure + aPropertyPairs.emplace_back( &rPropName, &rProp.maValue ); + } + + // handle no-property and special items + if( ( pSpecialContextIds != nullptr ) && + ( ( 0 != ( nPropFlags & MID_FLAG_NO_PROPERTY_IMPORT ) ) || + ( 0 != ( nPropFlags & MID_FLAG_SPECIAL_ITEM_IMPORT ) ) ) ) + { + // maybe it's one of our special context ids? + sal_Int16 nContextId = rPropMapper->GetEntryContextId(nIdx); + for ( sal_Int32 n = 0; + pSpecialContextIds[n].nContextID != -1; + n++ ) + { + // found: set index in pSpecialContextIds array + if ( pSpecialContextIds[n].nContextID == nContextId ) + { + pSpecialContextIds[n].nIndex = i; + break; // early out + } + } + } + } + + // We now need to construct the sequences and actually the set + // values. + + // sort the property pairs + sort( aPropertyPairs.begin(), aPropertyPairs.end(), + PropertyPairLessFunctor()); + + // create sequences + rNames.realloc( aPropertyPairs.size() ); + OUString* pNamesArray = rNames.getArray(); + rValues.realloc( aPropertyPairs.size() ); + Any* pValuesArray = rValues.getArray(); + + // copy values into sequences + i = 0; + for( const auto& rPropertyPair : aPropertyPairs ) + { + pNamesArray[i] = *(rPropertyPair.first); + pValuesArray[i++] = *(rPropertyPair.second); + } +} + +bool SvXMLImportPropertyMapper::FillMultiPropertySet_( + const vector & rProperties, + const Reference & rMultiPropSet, + const Reference & rPropSetInfo, + const rtl::Reference & rPropMapper, + ContextID_Index_Pair* pSpecialContextIds ) +{ + OSL_ENSURE( rMultiPropSet.is(), "Need multi property set. "); + OSL_ENSURE( rPropSetInfo.is(), "Need property set info." ); + + bool bSuccessful = false; + + Sequence aNames; + Sequence aValues; + + PrepareForMultiPropertySet_(rProperties, rPropSetInfo, rPropMapper, pSpecialContextIds, + aNames, aValues); + + // and, finally, try to set the values + try + { + rMultiPropSet->setPropertyValues( aNames, aValues ); + bSuccessful = true; + } + catch ( ... ) + { + OSL_ENSURE(bSuccessful, "Exception caught; style may not be imported correctly."); + } + + return bSuccessful; +} + +bool SvXMLImportPropertyMapper::FillTolerantMultiPropertySet_( + const vector & rProperties, + const Reference & rTolMultiPropSet, + const rtl::Reference & rPropMapper, + SvXMLImport& rImport, + ContextID_Index_Pair* pSpecialContextIds ) +{ + OSL_ENSURE( rTolMultiPropSet.is(), "Need tolerant multi property set. "); + + bool bSuccessful = false; + + Sequence aNames; + Sequence aValues; + + PrepareForMultiPropertySet_(rProperties, Reference(nullptr), rPropMapper, pSpecialContextIds, + aNames, aValues); + + // and, finally, try to set the values + try + { + const Sequence< SetPropertyTolerantFailed > aResults(rTolMultiPropSet->setPropertyValuesTolerant( aNames, aValues )); + bSuccessful = !aResults.hasElements(); + for( const auto& rResult : aResults) + { + Sequence aSeq { rResult.Name }; + OUString sMessage; + switch (rResult.Result) + { + case TolerantPropertySetResultType::UNKNOWN_PROPERTY : + sMessage = "UNKNOWN_PROPERTY"; + break; + case TolerantPropertySetResultType::ILLEGAL_ARGUMENT : + sMessage = "ILLEGAL_ARGUMENT"; + break; + case TolerantPropertySetResultType::PROPERTY_VETO : + sMessage = "PROPERTY_VETO"; + break; + case TolerantPropertySetResultType::WRAPPED_TARGET : + sMessage = "WRAPPED_TARGET"; + break; + } + rImport.SetError( + XMLERROR_STYLE_PROP_OTHER | XMLERROR_FLAG_ERROR, + aSeq, sMessage, nullptr ); + } + } + catch ( ... ) + { + OSL_ENSURE(bSuccessful, "Exception caught; style may not be imported correctly."); + } + + return bSuccessful; +} + +void SvXMLImportPropertyMapper::finished( + vector< XMLPropertyState >& rProperties, + sal_Int32 nStartIndex, sal_Int32 nEndIndex ) const +{ + // nothing to do here + if( mxNextMapper.is() ) + mxNextMapper->finished( rProperties, nStartIndex, nEndIndex ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlnume.cxx b/xmloff/source/style/xmlnume.cxx new file mode 100644 index 000000000..682fc648a --- /dev/null +++ b/xmloff/source/style/xmlnume.cxx @@ -0,0 +1,832 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "fonthdl.hxx" +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +void SvxXMLNumRuleExport::exportLevelStyles( const uno::Reference< css::container::XIndexReplace > & xNumRule, + bool bOutline ) +{ + sal_Int32 nCount = xNumRule ->getCount(); + for( sal_Int32 i=0; igetByIndex( i ) ); + uno::Sequence aSeq; + if( aEntry >>= aSeq ) + { + exportLevelStyle( i, aSeq, bOutline ); + } + } +} + +void SvxXMLNumRuleExport::exportLevelStyle( sal_Int32 nLevel, + const uno::Sequence& rProps, + bool bOutline ) +{ + sal_Int16 eType = NumberingType::CHAR_SPECIAL; + + sal_Int16 eAdjust = HoriOrientation::LEFT; + OUString sPrefix, sSuffix, sListFormat; + OUString sTextStyleName; + bool bHasColor = false; + sal_Int32 nColor = 0; + sal_Int32 nSpaceBefore = 0, nMinLabelWidth = 0, nMinLabelDist = 0; + + sal_Int16 nStartValue = 1, nDisplayLevels = 1, nBullRelSize = 0; + + sal_UCS4 cBullet = 0xf095; + OUString sBulletFontName, sBulletFontStyleName ; + FontFamily eBulletFontFamily = FAMILY_DONTKNOW; + FontPitch eBulletFontPitch = PITCH_DONTKNOW; + rtl_TextEncoding eBulletFontEncoding = RTL_TEXTENCODING_DONTKNOW; + + uno::Reference xGraphic; + + sal_Int32 nImageWidth = 0, nImageHeight = 0; + sal_Int16 eImageVertOrient = VertOrientation::LINE_CENTER; + + sal_Int16 ePosAndSpaceMode = PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION; + sal_Int16 eLabelFollowedBy = LabelFollow::LISTTAB; + sal_Int32 nListtabStopPosition( 0 ); + sal_Int32 nFirstLineIndent( 0 ); + sal_Int32 nIndentAt( 0 ); + + for( const beans::PropertyValue& rProp : rProps ) + { + if( rProp.Name == "NumberingType" ) + { + rProp.Value >>= eType; + } + else if( rProp.Name == "Prefix" ) + { + rProp.Value >>= sPrefix; + } + else if( rProp.Name == "Suffix" ) + { + rProp.Value >>= sSuffix; + } + else if (rProp.Name == "ListFormat") + { + rProp.Value >>= sListFormat; + } + else if (rProp.Name == "BulletChar") + { + OUString sValue; + rProp.Value >>= sValue; + if( !sValue.isEmpty() ) + { + cBullet = sValue.iterateCodePoints(&o3tl::temporary(sal_Int32(0))); + } + } + else if( rProp.Name == "BulletRelSize" ) + { + rProp.Value >>= nBullRelSize; + } + else if( rProp.Name == "Adjust" ) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + eAdjust = nValue; + } + else if( rProp.Name == "BulletFont" ) + { + awt::FontDescriptor rFDesc; + if( rProp.Value >>= rFDesc ) + { + sBulletFontName = rFDesc.Name; + sBulletFontStyleName = rFDesc.StyleName; + eBulletFontFamily = static_cast< FontFamily >( rFDesc.Family ); + eBulletFontPitch = static_cast< FontPitch >( rFDesc.Pitch ); + eBulletFontEncoding = static_cast(rFDesc.CharSet); + } + } + else if( rProp.Name == "GraphicBitmap" ) + { + uno::Reference xBitmap; + rProp.Value >>= xBitmap; + xGraphic.set(xBitmap, uno::UNO_QUERY); + } + else if( rProp.Name == "BulletColor" ) + { + rProp.Value >>= nColor; + bHasColor = true; + } + else if( rProp.Name == "StartWith" ) + { + rProp.Value >>= nStartValue; + } + else if( rProp.Name == "LeftMargin" ) + { + rProp.Value >>= nSpaceBefore; + } + else if( rProp.Name == "FirstLineOffset" ) + { + rProp.Value >>= nMinLabelWidth; + } + else if( rProp.Name == "SymbolTextDistance" ) + { + rProp.Value >>= nMinLabelDist; + } + else if( rProp.Name == "ParentNumbering" ) + { + rProp.Value >>= nDisplayLevels; + if( nDisplayLevels > nLevel+1 ) + nDisplayLevels = static_cast( nLevel )+1; + } + else if( rProp.Name == "CharStyleName" ) + { + rProp.Value >>= sTextStyleName; + } + else if( rProp.Name == "GraphicSize" ) + { + awt::Size aSize; + if( rProp.Value >>= aSize ) + { + nImageWidth = aSize.Width; + nImageHeight = aSize.Height; + } + } + else if( rProp.Name == "VertOrient" ) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + eImageVertOrient = nValue; + } + else if( rProp.Name == "PositionAndSpaceMode" ) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + ePosAndSpaceMode = nValue; + } + else if( rProp.Name == "LabelFollowedBy" ) + { + sal_Int16 nValue = 0; + rProp.Value >>= nValue; + eLabelFollowedBy = nValue; + } + else if( rProp.Name == "ListtabStopPosition" ) + { + rProp.Value >>= nListtabStopPosition; + } + else if( rProp.Name == "FirstLineIndent" ) + { + rProp.Value >>= nFirstLineIndent; + } + else if( rProp.Name == "IndentAt" ) + { + rProp.Value >>= nIndentAt; + } + } + + if( bOutline && (NumberingType::CHAR_SPECIAL == eType || + NumberingType::BITMAP == eType) ) + { + SAL_WARN_IF( bOutline, "xmloff", + "SvxXMLNumRuleExport::exportLevelStyle: invalid style for outline" ); + return; + } + + GetExport().CheckAttrList(); + + // text:level + OUStringBuffer sTmp; + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_LEVEL, OUString::number( nLevel + 1 ) ); + // #i110694#: no style-name on list-level-style-image + // #i116149#: neither prefix/suffix + if (NumberingType::BITMAP != eType) + { + if (!sTextStyleName.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sTextStyleName ) ); + } + if (!sListFormat.isEmpty()) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + // Write only in extended mode: in ODF 1.3 we write only prefix/suffix, + // no list format yet available. Praying we did not lost some formatting. + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_NUM_LIST_FORMAT, sListFormat); + } + } + if (!sPrefix.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NUM_PREFIX, + sPrefix ); + } + if (!sSuffix.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NUM_SUFFIX, + sSuffix ); + } + } + + enum XMLTokenEnum eElem = XML_LIST_LEVEL_STYLE_NUMBER; + if( NumberingType::CHAR_SPECIAL == eType ) + { + // + eElem = XML_LIST_LEVEL_STYLE_BULLET; + + if( cBullet ) + { + if( cBullet < ' ' ) + { + cBullet = 0xF000 + 149; + } + // text:bullet-char="..." + sTmp.append(OUString(&cBullet, 1)); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_BULLET_CHAR, + sTmp.makeStringAndClear() ); + } + else + { + // If 'cBullet' is zero, XML_BULLET_CHAR must exist with blank. + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_BULLET_CHAR, ""); + } + } + else if( NumberingType::BITMAP == eType ) + { + // + + eElem = XML_LIST_LEVEL_STYLE_IMAGE; + + if (xGraphic.is()) + { + OUString sUsedMimeType; + OUString sInternalURL = GetExport().AddEmbeddedXGraphic(xGraphic, sUsedMimeType); + if (!sInternalURL.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED ); + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD ); + } + } + else + { + SAL_WARN_IF(xGraphic.is(), "xmloff", "embedded images are not supported by now"); + } + } + else + { + // or + if( bOutline ) + eElem = XML_OUTLINE_LEVEL_STYLE; + else + eElem = XML_LIST_LEVEL_STYLE_NUMBER; + + GetExport().GetMM100UnitConverter().convertNumFormat( sTmp, eType ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sTmp.makeStringAndClear() ); + SvXMLUnitConverter::convertNumLetterSync( sTmp, eType ); + if( !sTmp.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_NUM_LETTER_SYNC, + sTmp.makeStringAndClear() ); + + if( nStartValue != 1 ) + { + sTmp.append( static_cast(nStartValue) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, + sTmp.makeStringAndClear() ); + } + if( nDisplayLevels > 1 && NumberingType::NUMBER_NONE != eType ) + { + sTmp.append( static_cast(nDisplayLevels) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_DISPLAY_LEVELS, + sTmp.makeStringAndClear() ); + } + } + + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, eElem, + true, true ); + + if ( ePosAndSpaceMode == PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION ) + { + nSpaceBefore += nMinLabelWidth; + nMinLabelWidth = -nMinLabelWidth; + if( nSpaceBefore != 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nSpaceBefore ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_SPACE_BEFORE, sAttr ); + } + if( nMinLabelWidth != 0 ) + { + OUString s = GetExport().GetMM100UnitConverter().convertMeasureToXML( nMinLabelWidth ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_MIN_LABEL_WIDTH, s); + } + if( nMinLabelDist > 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nMinLabelDist ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_MIN_LABEL_DISTANCE, sAttr); + } + } + /* Check, if properties for position-and-space-mode LABEL_ALIGNMENT + are allowed to be exported. (#i89178#) + */ + else if ( ePosAndSpaceMode == PositionAndSpaceMode::LABEL_ALIGNMENT && + mbExportPositionAndSpaceModeLabelAlignment ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_LIST_LEVEL_POSITION_AND_SPACE_MODE, + XML_LABEL_ALIGNMENT ); + } + if( HoriOrientation::LEFT != eAdjust ) + { + enum XMLTokenEnum eValue = XML_TOKEN_INVALID; + switch( eAdjust ) + { + case HoriOrientation::RIGHT: eValue = XML_END; break; + case HoriOrientation::CENTER: eValue = XML_CENTER; break; + } + if( eValue != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_TEXT_ALIGN, eValue ); + } + + if( NumberingType::BITMAP == eType ) + { + enum XMLTokenEnum eValue = XML_TOKEN_INVALID; + switch( eImageVertOrient ) + { + case VertOrientation::BOTTOM: // yes, it's OK: BOTTOM means that the baseline + // hits the frame at its topmost position + case VertOrientation::LINE_TOP: + case VertOrientation::CHAR_TOP: + eValue = XML_TOP; + break; + case VertOrientation::CENTER: + case VertOrientation::LINE_CENTER: + case VertOrientation::CHAR_CENTER: + eValue = XML_MIDDLE; + break; + case VertOrientation::TOP: // yes, it's OK: TOP means that the baseline + // hits the frame at its bottommost position + case VertOrientation::LINE_BOTTOM: + case VertOrientation::CHAR_BOTTOM: + eValue = XML_BOTTOM; + break; + } + if( eValue != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_VERTICAL_POS, eValue ); + + eValue = XML_TOKEN_INVALID; + switch( eImageVertOrient ) + { + case VertOrientation::TOP: + case VertOrientation::CENTER: + case VertOrientation::BOTTOM: + eValue = XML_BASELINE; + break; + case VertOrientation::LINE_TOP: + case VertOrientation::LINE_CENTER: + case VertOrientation::LINE_BOTTOM: + eValue = XML_LINE; + break; + case VertOrientation::CHAR_TOP: + case VertOrientation::CHAR_CENTER: + case VertOrientation::CHAR_BOTTOM: + eValue = XML_CHAR; + break; + } + if( eValue != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_VERTICAL_REL, eValue ); + + if( nImageWidth > 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nImageWidth ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_WIDTH, sAttr ); + } + + if( nImageHeight > 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nImageHeight ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_HEIGHT, sAttr ); + } + } + + { + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, + XML_LIST_LEVEL_PROPERTIES, true, true ); + + /* Check, if properties for position-and-space-mode LABEL_ALIGNMENT + are allowed to be exported. (#i89178#) + */ + if ( ePosAndSpaceMode == PositionAndSpaceMode::LABEL_ALIGNMENT && + mbExportPositionAndSpaceModeLabelAlignment ) + { + enum XMLTokenEnum eValue = XML_LISTTAB; + if ( eLabelFollowedBy == LabelFollow::SPACE ) + { + eValue = XML_SPACE; + } + else if ( eLabelFollowedBy == LabelFollow::NOTHING ) + { + eValue = XML_NOTHING; + } + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_LABEL_FOLLOWED_BY, eValue ); + + if (eLabelFollowedBy == LabelFollow::NEWLINE) + { + eValue = XML_NEWLINE; + GetExport().AddAttribute( XML_NAMESPACE_LO_EXT, + XML_LABEL_FOLLOWED_BY, eValue ); + } + + if ( eLabelFollowedBy == LabelFollow::LISTTAB && + nListtabStopPosition > 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nListtabStopPosition ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_LIST_TAB_STOP_POSITION, + sAttr ); + } + + if ( nFirstLineIndent != 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nFirstLineIndent ); + GetExport().AddAttribute( XML_NAMESPACE_FO, + XML_TEXT_INDENT, + sAttr ); + } + + if ( nIndentAt != 0 ) + { + OUString sAttr = GetExport().GetMM100UnitConverter().convertMeasureToXML( + nIndentAt ); + GetExport().AddAttribute( XML_NAMESPACE_FO, + XML_MARGIN_LEFT, + sAttr ); + } + + SvXMLElementExport aLabelAlignmentElement( GetExport(), XML_NAMESPACE_STYLE, + XML_LIST_LEVEL_LABEL_ALIGNMENT, + true, true ); + } + } + + if( NumberingType::CHAR_SPECIAL == eType ) + { + if( !sBulletFontName.isEmpty() ) + { + OUString sStyleName = + GetExport().GetFontAutoStylePool()->Find( + sBulletFontName, sBulletFontStyleName, + eBulletFontFamily, eBulletFontPitch, + eBulletFontEncoding ); + + if( !sStyleName.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_NAME, + sStyleName ); + } + else + { + OUString sTemp; + + const SvXMLUnitConverter& rUnitConv = + GetExport().GetMM100UnitConverter(); + XMLFontFamilyNamePropHdl aFamilyNameHdl; + if( aFamilyNameHdl.exportXML( sTemp, Any(sBulletFontName), rUnitConv ) ) + GetExport().AddAttribute( XML_NAMESPACE_FO, + XML_FONT_FAMILY, sTemp ); + + if( !sBulletFontStyleName.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_STYLE_NAME, + sBulletFontStyleName ); + + XMLFontFamilyPropHdl aFamilyHdl; + if( aFamilyHdl.exportXML( sTemp, Any(static_cast(eBulletFontFamily)), rUnitConv ) ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_FAMILY_GENERIC, + sTemp ); + + XMLFontPitchPropHdl aPitchHdl; + if( aPitchHdl.exportXML( sTemp, Any(static_cast(eBulletFontPitch)), rUnitConv ) ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_PITCH, sTemp ); + + XMLFontEncodingPropHdl aEncHdl; + if( aEncHdl.exportXML( sTemp, Any(static_cast(eBulletFontEncoding)), rUnitConv ) ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_FONT_CHARSET, sTemp ); + } + } + } + if( NumberingType::BITMAP != eType ) + { + // fo:color = "#..." + if( bHasColor ) + { + if (0xffffffff == static_cast(nColor)) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_USE_WINDOW_FONT_COLOR, XML_TRUE ); + } + else + { + OUStringBuffer sBuffer; + ::sax::Converter::convertColor( sBuffer, nColor ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_COLOR, + sBuffer.makeStringAndClear() ); + } + } + // fo:height="...%" + if( nBullRelSize ) + { + ::sax::Converter::convertPercent( sTmp, nBullRelSize ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_FONT_SIZE, + sTmp.makeStringAndClear() ); + } + } + if( GetExport().GetAttrList().getLength() > 0 ) + { + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, + XML_TEXT_PROPERTIES, true, true ); + } + if (xGraphic.is() && NumberingType::BITMAP == eType) + { + // optional office:binary-data + GetExport().AddEmbeddedXGraphicAsBase64(xGraphic); + } + } +} + + +constexpr OUStringLiteral gsNumberingRules( u"NumberingRules" ); +constexpr OUStringLiteral gsIsPhysical( u"IsPhysical" ); +constexpr OUStringLiteral gsIsContinuousNumbering( u"IsContinuousNumbering" ); + +SvxXMLNumRuleExport::SvxXMLNumRuleExport( SvXMLExport& rExp ) : + rExport( rExp ), + // Let list style creation depend on Load/Save option "ODF format version" (#i89178#) + mbExportPositionAndSpaceModeLabelAlignment( true ) +{ + switch (GetExport().getSaneDefaultVersion()) + { + case SvtSaveOptions::ODFSVER_010: + case SvtSaveOptions::ODFSVER_011: + { + mbExportPositionAndSpaceModeLabelAlignment = false; + } + break; + default: // >= ODFSVER_012 + { + mbExportPositionAndSpaceModeLabelAlignment = true; + } + } +} + +void SvxXMLNumRuleExport::exportNumberingRule( + const OUString& rName, bool bIsHidden, + const Reference< XIndexReplace >& rNumRule ) +{ + Reference< XPropertySet > xPropSet( rNumRule, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo; + if( xPropSet.is() ) + xPropSetInfo = xPropSet->getPropertySetInfo(); + + GetExport().CheckAttrList(); + + // style:name="..." + if( !rName.isEmpty() ) + { + bool bEncoded = false; + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, + GetExport().EncodeStyleName( rName, &bEncoded ) ); + if( bEncoded ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_DISPLAY_NAME, + rName); + } + + // style:hidden="..." + if (bIsHidden + && GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_HIDDEN, "true"); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_HIDDEN, "true"); // FIXME for compatibility + } + + // text:consecutive-numbering="..." + bool bContNumbering = false; + if( xPropSetInfo.is() && + xPropSetInfo->hasPropertyByName( gsIsContinuousNumbering ) ) + { + Any aAny( xPropSet->getPropertyValue( gsIsContinuousNumbering ) ); + bContNumbering = *o3tl::doAccess(aAny); + } + if( bContNumbering ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_CONSECUTIVE_NUMBERING, XML_TRUE ); + + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, XML_LIST_STYLE , + true, true ); + exportLevelStyles( rNumRule ); + } +} + +void SvxXMLNumRuleExport::exportStyle( const Reference< XStyle >& rStyle ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + + Any aAny; + + // Don't export styles that aren't existing really. This may be the + // case for StarOffice Writer's pool styles. + if( xPropSetInfo->hasPropertyByName( gsIsPhysical ) ) + { + aAny = xPropSet->getPropertyValue( gsIsPhysical ); + if( !*o3tl::doAccess(aAny) ) + return; + } + + aAny = xPropSet->getPropertyValue( gsNumberingRules ); + Reference xNumRule; + aAny >>= xNumRule; + + OUString sName = rStyle->getName(); + + bool bHidden = false; + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + aAny = xPropSet->getPropertyValue( "Hidden" ); + aAny >>= bHidden; + } + + exportNumberingRule( sName, bHidden, xNumRule ); +} + +void SvxXMLNumRuleExport::exportOutline() +{ + Reference< XChapterNumberingSupplier > xCNSupplier( GetExport().GetModel(), + UNO_QUERY ); + SAL_WARN_IF( !xCNSupplier.is(), "xmloff", "no chapter numbering supplier" ); + + if( !xCNSupplier.is() ) + return; + + Reference< XIndexReplace > xNumRule( xCNSupplier->getChapterNumberingRules() ); + SAL_WARN_IF( !xNumRule.is(), "xmloff", "no chapter numbering rules" ); + + if( !xNumRule.is() ) + return; + + /* Outline style has property style:name since ODF 1.2 + Thus, export this property and adjust fix for issue #i69627# (#i90780#) + */ + OUString sOutlineStyleName; + { + Reference xNumRulePropSet( + xCNSupplier->getChapterNumberingRules(), UNO_QUERY ); + if (xNumRulePropSet.is()) + { + xNumRulePropSet->getPropertyValue( "Name" ) >>= sOutlineStyleName; + } + } + const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion = + GetExport().getSaneDefaultVersion(); + if ((nODFVersion == SvtSaveOptions::ODFSVER_010 || + nODFVersion == SvtSaveOptions::ODFSVER_011) + && GetExport().writeOutlineStyleAsNormalListStyle()) + { + exportNumberingRule( sOutlineStyleName, false, xNumRule ); + } + else + { + if (nODFVersion != SvtSaveOptions::ODFSVER_010 && + nODFVersion != SvtSaveOptions::ODFSVER_011) + { + // style:name="..." + GetExport().CheckAttrList(); + if ( !sOutlineStyleName.isEmpty() ) + { + bool bEncoded = false; + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, + GetExport().EncodeStyleName( sOutlineStyleName, + &bEncoded ) ); + if( bEncoded ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY_NAME, + sOutlineStyleName ); + } + } + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_OUTLINE_STYLE, true, true ); + exportLevelStyles( xNumRule, true ); + } +} + +void SvxXMLNumRuleExport::exportStyles( bool bUsed, + XMLTextListAutoStylePool *pPool, + bool bExportChapterNumbering ) +{ + if( bExportChapterNumbering ) + exportOutline(); + + Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetExport().GetModel(), UNO_QUERY ); + SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", "No XStyleFamiliesSupplier from XModel for export!" ); + if( !xFamiliesSupp.is() ) + return; + + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", "getStyleFamilies() from XModel failed for export!" ); + + if( !xFamilies.is() ) + return; + + static const OUStringLiteral aNumberStyleName( u"NumberingStyles" ); + + Reference< XIndexAccess > xStyles; + if( !xFamilies->hasByName( aNumberStyleName ) ) + return; + + xFamilies->getByName( aNumberStyleName ) >>= xStyles; + + SAL_WARN_IF( !xStyles.is(), "xmloff", "Style not found for export!" ); + + if( !xStyles.is() ) + return; + + const sal_Int32 nStyles = xStyles->getCount(); + + for( sal_Int32 i=0; i < nStyles; i++ ) + { + Reference< XStyle > xStyle; + xStyles->getByIndex( i ) >>= xStyle; + + if( !bUsed || xStyle->isInUse() ) + { + exportStyle( xStyle ); + if( pPool ) + pPool->RegisterName( xStyle->getName() ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx new file mode 100644 index 000000000..6deeca688 --- /dev/null +++ b/xmloff/source/style/xmlnumfe.cxx @@ -0,0 +1,2026 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; +using namespace ::svt; + +typedef std::set< sal_uInt32 > SvXMLuInt32Set; + +namespace { + +struct SvXMLEmbeddedTextEntry +{ + sal_uInt16 nSourcePos; // position in NumberFormat (to skip later) + sal_Int32 nFormatPos; // resulting position in embedded-text element + OUString aText; + + SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, const OUString& rT ) : + nSourcePos(nSP), nFormatPos(nFP), aText(rT) {} +}; + +} + +class SvXMLEmbeddedTextEntryArr +{ + typedef std::vector DataType; + DataType maData; + +public: + + void push_back( SvXMLEmbeddedTextEntry const& r ) + { + maData.push_back(r); + } + + const SvXMLEmbeddedTextEntry& operator[] ( size_t i ) const + { + return maData[i]; + } + + size_t size() const + { + return maData.size(); + } +}; + +class SvXMLNumUsedList_Impl +{ + SvXMLuInt32Set aUsed; + SvXMLuInt32Set aWasUsed; + SvXMLuInt32Set::iterator aCurrentUsedPos; + sal_uInt32 nUsedCount; + sal_uInt32 nWasUsedCount; + +public: + SvXMLNumUsedList_Impl(); + + void SetUsed( sal_uInt32 nKey ); + bool IsUsed( sal_uInt32 nKey ) const; + bool IsWasUsed( sal_uInt32 nKey ) const; + void Export(); + + bool GetFirstUsed(sal_uInt32& nKey); + bool GetNextUsed(sal_uInt32& nKey); + + uno::Sequence GetWasUsed() const; + void SetWasUsed(const uno::Sequence& rWasUsed); +}; + +//! SvXMLNumUsedList_Impl should be optimized! + +SvXMLNumUsedList_Impl::SvXMLNumUsedList_Impl() : + nUsedCount(0), + nWasUsedCount(0) +{ +} + +void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey ) +{ + if ( !IsWasUsed(nKey) ) + { + std::pair aPair = aUsed.insert( nKey ); + if (aPair.second) + nUsedCount++; + } +} + +bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const +{ + SvXMLuInt32Set::const_iterator aItr = aUsed.find(nKey); + return (aItr != aUsed.end()); +} + +bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const +{ + SvXMLuInt32Set::const_iterator aItr = aWasUsed.find(nKey); + return (aItr != aWasUsed.end()); +} + +void SvXMLNumUsedList_Impl::Export() +{ + SvXMLuInt32Set::const_iterator aItr = aUsed.begin(); + while (aItr != aUsed.end()) + { + std::pair aPair = aWasUsed.insert( *aItr ); + if (aPair.second) + nWasUsedCount++; + ++aItr; + } + aUsed.clear(); + nUsedCount = 0; +} + +bool SvXMLNumUsedList_Impl::GetFirstUsed(sal_uInt32& nKey) +{ + bool bRet(false); + aCurrentUsedPos = aUsed.begin(); + if(nUsedCount) + { + DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong"); + nKey = *aCurrentUsedPos; + bRet = true; + } + return bRet; +} + +bool SvXMLNumUsedList_Impl::GetNextUsed(sal_uInt32& nKey) +{ + bool bRet(false); + if (aCurrentUsedPos != aUsed.end()) + { + ++aCurrentUsedPos; + if (aCurrentUsedPos != aUsed.end()) + { + nKey = *aCurrentUsedPos; + bRet = true; + } + } + return bRet; +} + +uno::Sequence SvXMLNumUsedList_Impl::GetWasUsed() const +{ + return comphelper::containerToSequence(aWasUsed); +} + +void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence& rWasUsed) +{ + DBG_ASSERT(nWasUsedCount == 0, "WasUsed should be empty"); + for (const auto nWasUsed : rWasUsed) + { + std::pair aPair = aWasUsed.insert( nWasUsed ); + if (aPair.second) + nWasUsedCount++; + } +} + +SvXMLNumFmtExport::SvXMLNumFmtExport( + SvXMLExport& rExp, + const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) : + rExport( rExp ), + sPrefix( OUString("N") ), + pFormatter( nullptr ), + bHasText( false ) +{ + // supplier must be SvNumberFormatsSupplierObj + SvNumberFormatsSupplierObj* pObj = + comphelper::getFromUnoTunnel( rSupp ); + if (pObj) + pFormatter = pObj->GetNumberFormatter(); + + if ( pFormatter ) + { + pLocaleData.reset( new LocaleDataWrapper( pFormatter->GetComponentContext(), + pFormatter->GetLanguageTag() ) ); + } + else + { + LanguageTag aLanguageTag( MsLangId::getConfiguredSystemLanguage() ); + + pLocaleData.reset( new LocaleDataWrapper( rExport.getComponentContext(), std::move(aLanguageTag) ) ); + } + + pUsedList.reset(new SvXMLNumUsedList_Impl); +} + +SvXMLNumFmtExport::SvXMLNumFmtExport( + SvXMLExport& rExp, + const css::uno::Reference< css::util::XNumberFormatsSupplier >& rSupp, + const OUString& rPrefix ) : + rExport( rExp ), + sPrefix( rPrefix ), + pFormatter( nullptr ), + bHasText( false ) +{ + // supplier must be SvNumberFormatsSupplierObj + SvNumberFormatsSupplierObj* pObj = + comphelper::getFromUnoTunnel( rSupp ); + if (pObj) + pFormatter = pObj->GetNumberFormatter(); + + if ( pFormatter ) + { + pLocaleData.reset( new LocaleDataWrapper( pFormatter->GetComponentContext(), + pFormatter->GetLanguageTag() ) ); + } + else + { + LanguageTag aLanguageTag( MsLangId::getConfiguredSystemLanguage() ); + + pLocaleData.reset( new LocaleDataWrapper( rExport.getComponentContext(), std::move(aLanguageTag) ) ); + } + + pUsedList.reset(new SvXMLNumUsedList_Impl); +} + +SvXMLNumFmtExport::~SvXMLNumFmtExport() +{ +} + +// helper methods + +static OUString lcl_CreateStyleName( sal_Int32 nKey, sal_Int32 nPart, bool bDefPart, std::u16string_view rPrefix ) +{ + OUStringBuffer aFmtName(10); + aFmtName.append( rPrefix ); + aFmtName.append( nKey ); + if (!bDefPart) + { + aFmtName.append( 'P' ); + aFmtName.append( nPart ); + } + return aFmtName.makeStringAndClear(); +} + +void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar ) +{ + if ( !rCalendar.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_CALENDAR, rCalendar ); + } +} + +void SvXMLNumFmtExport::AddStyleAttr_Impl( bool bLong ) +{ + if ( bLong ) // short is default + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_STYLE, XML_LONG ); + } +} + +void SvXMLNumFmtExport::AddLanguageAttr_Impl( LanguageType nLang ) +{ + if ( nLang != LANGUAGE_SYSTEM ) + { + rExport.AddLanguageTagAttributes( XML_NAMESPACE_NUMBER, XML_NAMESPACE_NUMBER, + LanguageTag( nLang), false); + } +} + +// methods to write individual elements within a format + +void SvXMLNumFmtExport::AddToTextElement_Impl( std::u16string_view rString ) +{ + // append to sTextContent, write element in FinishTextElement_Impl + // to avoid several text elements following each other + + sTextContent.append( rString ); + // Also empty string leads to a number:text element as it may separate + // keywords of the same letter (e.g. MM""MMM) that otherwise would be + // concatenated when reading back in. + bHasText = true; +} + +void SvXMLNumFmtExport::FinishTextElement_Impl(bool bUseExtensionNS) +{ + if ( bHasText ) + { + sal_uInt16 nNS = bUseExtensionNS ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER; + SvXMLElementExport aElem( rExport, nNS, XML_TEXT, + true, false ); + rExport.Characters( sTextContent.makeStringAndClear() ); + bHasText = false; + } +} + +void SvXMLNumFmtExport::WriteColorElement_Impl( const Color& rColor ) +{ + FinishTextElement_Impl(); + + OUStringBuffer aColStr( 7 ); + ::sax::Converter::convertColor( aColStr, rColor ); + rExport.AddAttribute( XML_NAMESPACE_FO, XML_COLOR, + aColStr.makeStringAndClear() ); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_TEXT_PROPERTIES, + true, false ); +} + +void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString& rString, + std::u16string_view rExt ) +{ + FinishTextElement_Impl(); + + if ( !rExt.empty() ) + { + // rExt should be a 16-bit hex value max FFFF which may contain a + // leading "-" separator (that is not a minus sign, but toInt32 can be + // used to parse it, with post-processing as necessary): + sal_Int32 nLang = o3tl::toInt32(rExt, 16); + if ( nLang < 0 ) + nLang = -nLang; + AddLanguageAttr_Impl( LanguageType(nLang) ); // adds to pAttrList + } + + SvXMLElementExport aElem( rExport, + XML_NAMESPACE_NUMBER, XML_CURRENCY_SYMBOL, + true, false ); + rExport.Characters( rString ); +} + +void SvXMLNumFmtExport::WriteBooleanElement_Impl() +{ + FinishTextElement_Impl(); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_BOOLEAN, + true, false ); +} + +void SvXMLNumFmtExport::WriteTextContentElement_Impl() +{ + FinishTextElement_Impl(); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT_CONTENT, + true, false ); +} + +// date elements + +void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY, + true, false ); +} + +void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, bool bLong, bool bText ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + if ( bText ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TEXTUAL, XML_TRUE ); + } + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MONTH, + true, false ); +} + +void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_YEAR, + true, false ); +} + +void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_ERA, + true, false ); +} + +void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_DAY_OF_WEEK, + true, false ); +} + +void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_WEEK_OF_YEAR, + true, false ); +} + +void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, bool bLong ) +{ + FinishTextElement_Impl(); + + AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_QUARTER, + true, false ); +} + +// time elements + +void SvXMLNumFmtExport::WriteHoursElement_Impl( bool bLong ) +{ + FinishTextElement_Impl(); + + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_HOURS, + true, false ); +} + +void SvXMLNumFmtExport::WriteMinutesElement_Impl( bool bLong ) +{ + FinishTextElement_Impl(); + + AddStyleAttr_Impl( bLong ); // adds to pAttrList + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_MINUTES, + true, false ); +} + +void SvXMLNumFmtExport::WriteRepeatedElement_Impl( sal_Unicode nChar ) +{ + // Export only for 1.2 with extensions or 1.3 and later. + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + FinishTextElement_Impl(eVersion < SvtSaveOptions::ODFSVER_013); + // OFFICE-3765 For 1.2+ use loext namespace, for 1.3 use number namespace. + SvXMLElementExport aElem( rExport, + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_FILL_CHARACTER, true, false ); + rExport.Characters( OUString( nChar ) ); + } +} + +void SvXMLNumFmtExport::WriteSecondsElement_Impl( bool bLong, sal_uInt16 nDecimals ) +{ + FinishTextElement_Impl(); + + AddStyleAttr_Impl( bLong ); // adds to pAttrList + if ( nDecimals > 0 ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, + OUString::number( nDecimals ) ); + } + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_SECONDS, + true, false ); +} + +void SvXMLNumFmtExport::WriteAMPMElement_Impl() +{ + FinishTextElement_Impl(); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_AM_PM, + true, false ); +} + +// numbers + +void SvXMLNumFmtExport::WriteNumberElement_Impl( + sal_Int32 nDecimals, sal_Int32 nMinDecimals, + sal_Int32 nInteger, const OUString& rDashStr, + bool bGrouping, sal_Int32 nTrailingThousands, + const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ) +{ + FinishTextElement_Impl(); + + // decimals + if ( nDecimals >= 0 ) // negative = automatic + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, + OUString::number( nDecimals ) ); + } + + if ( nMinDecimals >= 0 ) // negative = automatic + { + // Export only for 1.2 with extensions or 1.3 and later. + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace. + rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_MIN_DECIMAL_PLACES, + OUString::number( nMinDecimals ) ); + } + } + + // integer digits + if ( nInteger >= 0 ) // negative = automatic + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, + OUString::number( nInteger ) ); + } + + // decimal replacement (dashes) or variable decimals (#) + if ( !rDashStr.isEmpty() || nMinDecimals < nDecimals ) + { + // full variable decimals means an empty replacement string + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_REPLACEMENT, + rDashStr ); + } + + // (automatic) grouping separator + if ( bGrouping ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); + } + + // display-factor if there are trailing thousands separators + if ( nTrailingThousands ) + { + // each separator character removes three digits + double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands ); + + OUStringBuffer aFactStr; + ::sax::Converter::convertDouble( aFactStr, fFactor ); + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() ); + } + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_NUMBER, + true, true ); + + // number:embedded-text as child elements + + auto nEntryCount = rEmbeddedEntries.size(); + for (decltype(nEntryCount) nEntry=0; nEntry < nEntryCount; ++nEntry) + { + const SvXMLEmbeddedTextEntry *const pObj = &rEmbeddedEntries[nEntry]; + + // position attribute + // position == 0 is between first integer digit and decimal separator + // position < 0 is inside decimal part + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_POSITION, + OUString::number( pObj->nFormatPos ) ); + SvXMLElementExport aChildElem( rExport, XML_NAMESPACE_NUMBER, XML_EMBEDDED_TEXT, + true, false ); + + // text as element content + OUStringBuffer aContent( pObj->aText ); + while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1].nFormatPos == pObj->nFormatPos ) + { + // The array can contain several elements for the same position in the number + // (for example, literal text and space from underscores). They must be merged + // into a single embedded-text element. + aContent.append(rEmbeddedEntries[nEntry+1].aText); + ++nEntry; + } + rExport.Characters( aContent.makeStringAndClear() ); + } +} + +void SvXMLNumFmtExport::WriteScientificElement_Impl( + sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, + bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign ) +{ + FinishTextElement_Impl(); + + // decimals + if ( nDecimals >= 0 ) // negative = automatic + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DECIMAL_PLACES, + OUString::number( nDecimals ) ); + } + + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if ( nMinDecimals >= 0 ) // negative = automatic + { + // Export only for 1.2 with extensions or 1.3 and later. + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace. + rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_MIN_DECIMAL_PLACES, + OUString::number( nMinDecimals ) ); + } + } + + // integer digits + if ( nInteger >= 0 ) // negative = automatic + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, + OUString::number( nInteger ) ); + } + + // (automatic) grouping separator + if ( bGrouping ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); + } + + // exponent digits + if ( nExp >= 0 ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_EXPONENT_DIGITS, + OUString::number( nExp ) ); + } + + // exponent interval for engineering notation + if ( nExpInterval >= 0 ) + { + // Export only for 1.2 with extensions or 1.3 and later. + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-1828 For 1.2+ use loext namespace, for 1.3 use number namespace. + rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_EXPONENT_INTERVAL, OUString::number( nExpInterval ) ); + } + } + + // exponent sign + // Export only for 1.2 with extensions or 1.3 and later. + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace. + rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_FORCED_EXPONENT_SIGN, + bExpSign? XML_TRUE : XML_FALSE ); + } + + SvXMLElementExport aElem( rExport, + XML_NAMESPACE_NUMBER, XML_SCIENTIFIC_NUMBER, + true, false ); +} + +void SvXMLNumFmtExport::WriteFractionElement_Impl( + sal_Int32 nInteger, bool bGrouping, + const SvNumberformat& rFormat, sal_uInt16 nPart ) +{ + FinishTextElement_Impl(); + const OUString aNumeratorString = rFormat.GetNumeratorString( nPart ); + const OUString aDenominatorString = rFormat.GetDenominatorString( nPart ); + const OUString aIntegerFractionDelimiterString = rFormat.GetIntegerFractionDelimiterString( nPart ); + sal_Int32 nMaxNumeratorDigits = aNumeratorString.getLength(); + // Count '0' as '?' + sal_Int32 nMinNumeratorDigits = aNumeratorString.replaceAll("0","?").indexOf('?'); + sal_Int32 nZerosNumeratorDigits = aNumeratorString.indexOf('0'); + if ( nMinNumeratorDigits >= 0 ) + nMinNumeratorDigits = nMaxNumeratorDigits - nMinNumeratorDigits; + else + nMinNumeratorDigits = 0; + if ( nZerosNumeratorDigits >= 0 ) + nZerosNumeratorDigits = nMaxNumeratorDigits - nZerosNumeratorDigits; + else + nZerosNumeratorDigits = 0; + sal_Int32 nMaxDenominatorDigits = aDenominatorString.getLength(); + sal_Int32 nMinDenominatorDigits = aDenominatorString.replaceAll("0","?").indexOf('?'); + sal_Int32 nZerosDenominatorDigits = aDenominatorString.indexOf('0'); + if ( nMinDenominatorDigits >= 0 ) + nMinDenominatorDigits = nMaxDenominatorDigits - nMinDenominatorDigits; + else + nMinDenominatorDigits = 0; + if ( nZerosDenominatorDigits >= 0 ) + nZerosDenominatorDigits = nMaxDenominatorDigits - nZerosDenominatorDigits; + else + nZerosDenominatorDigits = 0; + sal_Int32 nDenominator = aDenominatorString.toInt32(); + + // integer digits + if ( nInteger >= 0 ) // negative = default (no integer part) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, + OUString::number( nInteger ) ); + } + + // (automatic) grouping separator + if ( bGrouping ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); + } + + // integer/fraction delimiter + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if ( !aIntegerFractionDelimiterString.isEmpty() && aIntegerFractionDelimiterString != " " + && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) ) + { // Export only for 1.2/1.3 with extensions. + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_INTEGER_FRACTION_DELIMITER, + aIntegerFractionDelimiterString ); + } + + // numerator digits + if ( nMinNumeratorDigits == 0 ) // at least one digit to keep compatibility with previous versions + nMinNumeratorDigits++; + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, + OUString::number( nMinNumeratorDigits ) ); + // Export only for 1.2/1.3 with extensions. + if ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) + { + // For extended ODF use loext namespace + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_MAX_NUMERATOR_DIGITS, + OUString::number( nMaxNumeratorDigits ) ); + } + if ( nZerosNumeratorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) ) + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_ZEROS_NUMERATOR_DIGITS, + OUString::number( nZerosNumeratorDigits ) ); + + if ( nDenominator ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DENOMINATOR_VALUE, + OUString::number( nDenominator) ); + } + // it's not necessary to export nDenominatorDigits + // if we have a forced denominator + else + { + if ( nMinDenominatorDigits == 0 ) // at least one digit to keep compatibility with previous versions + nMinDenominatorDigits++; + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS, + OUString::number( nMinDenominatorDigits ) ); + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // OFFICE-3695 For 1.2+ use loext namespace, for 1.3 use number namespace. + rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_MAX_DENOMINATOR_VALUE, + OUString::number( pow ( 10.0, nMaxDenominatorDigits ) - 1 ) ); // 9, 99 or 999 + } + if ( nZerosDenominatorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) ) + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_ZEROS_DENOMINATOR_DIGITS, + OUString::number( nZerosDenominatorDigits ) ); + } + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_FRACTION, + true, false ); +} + +// mapping (condition) + +void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit, + sal_Int32 nKey, sal_Int32 nPart ) +{ + FinishTextElement_Impl(); + + if ( nOp == NUMBERFORMAT_OP_NO ) + return; + + // style namespace + + OUStringBuffer aCondStr(20); + aCondStr.append( "value()" ); //! define constant + switch ( nOp ) + { + case NUMBERFORMAT_OP_EQ: aCondStr.append( '=' ); break; + case NUMBERFORMAT_OP_NE: aCondStr.append( "!=" ); break; + case NUMBERFORMAT_OP_LT: aCondStr.append( '<' ); break; + case NUMBERFORMAT_OP_LE: aCondStr.append( "<=" ); break; + case NUMBERFORMAT_OP_GT: aCondStr.append( '>' ); break; + case NUMBERFORMAT_OP_GE: aCondStr.append( ">=" ); break; + default: + OSL_FAIL("unknown operator"); + } + ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit, + rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, + '.', true ); + + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CONDITION, + aCondStr.makeStringAndClear() ); + + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_APPLY_STYLE_NAME, + rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, false, + sPrefix ) ) ); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_MAP, + true, false ); +} + +// for old (automatic) currency formats: parse currency symbol from text + +static sal_Int32 lcl_FindSymbol( const OUString& sUpperStr, std::u16string_view sCurString ) +{ + // search for currency symbol + // Quoting as in ImpSvNumberformatScan::Symbol_Division + + sal_Int32 nCPos = 0; + while (nCPos >= 0) + { + nCPos = sUpperStr.indexOf( sCurString, nCPos ); + if (nCPos >= 0) + { + // in Quotes? + sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos ); + if ( nQ < 0 ) + { + // dm can be escaped as "dm or \d + sal_Unicode c; + if ( nCPos == 0 ) + return nCPos; // found + c = sUpperStr[nCPos-1]; + if ( c != '"' && c != '\\') + { + return nCPos; // found + } + else + { + nCPos++; // continue + } + } + else + { + nCPos = nQ + 1; // continue after quote end + } + } + } + return -1; +} + +bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString& rString, + const css::lang::Locale& rLocale ) +{ + // returns true if currency element was written + + bool bRet = false; + + LanguageTag aLanguageTag( rLocale ); + pFormatter->ChangeIntl( aLanguageTag.getLanguageType( false) ); + OUString sCurString, sDummy; + pFormatter->GetCompatibilityCurrency( sCurString, sDummy ); + + OUString sUpperStr = pFormatter->GetCharClass()->uppercase(rString); + sal_Int32 nPos = lcl_FindSymbol( sUpperStr, sCurString ); + if ( nPos >= 0 ) + { + sal_Int32 nLength = rString.getLength(); + sal_Int32 nCurLen = sCurString.getLength(); + sal_Int32 nCont = nPos + nCurLen; + + // text before currency symbol + if ( nPos > 0 ) + { + AddToTextElement_Impl( rString.subView( 0, nPos ) ); + } + // currency symbol (empty string -> default) + WriteCurrencyElement_Impl( "", u"" ); + bRet = true; + + // text after currency symbol + if ( nCont < nLength ) + { + AddToTextElement_Impl( rString.subView( nCont, nLength-nCont ) ); + } + } + else + { + AddToTextElement_Impl( rString ); // simple text + } + + return bRet; // true: currency element written +} + +static OUString lcl_GetDefaultCalendar( SvNumberFormatter const * pFormatter, LanguageType nLang ) +{ + // get name of first non-gregorian calendar for the language + + OUString aCalendar; + CalendarWrapper* pCalendar = pFormatter->GetCalendar(); + if (pCalendar) + { + lang::Locale aLocale( LanguageTag::convertToLocale( nLang ) ); + + const uno::Sequence aCals = pCalendar->getAllCalendars( aLocale ); + auto pCal = std::find_if(aCals.begin(), aCals.end(), + [](const OUString& rCal) { return rCal != "gregorian"; }); + if (pCal != aCals.end()) + aCalendar = *pCal; + } + return aCalendar; +} + +static bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos ) +{ + auto nCount = rEmbeddedEntries.size(); + for (decltype(nCount) i=0; i no default date format + bEnd = true; // end of format reached + break; + case NF_SYMBOLTYPE_STRING: + case NF_SYMBOLTYPE_DATESEP: + case NF_SYMBOLTYPE_TIMESEP: + case NF_SYMBOLTYPE_TIME100SECSEP: + // text is ignored, except at the end + break; + // same mapping as in SvXMLNumFormatContext::AddNfKeyword: + case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break; + case NF_KEY_NNN: + case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break; + case NF_KEY_D: eDateDay = XML_DEA_SHORT; break; + case NF_KEY_DD: eDateDay = XML_DEA_LONG; break; + case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break; + case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break; + case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break; + case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break; + case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break; + case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break; + case NF_KEY_H: eDateHours = XML_DEA_SHORT; break; + case NF_KEY_HH: eDateHours = XML_DEA_LONG; break; + case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break; + case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break; + case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break; + case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break; + case NF_KEY_AP: + case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself + default: + bDateNoDefault = true; // any other element -> no default format + } + nLastType = nElemType; + ++nPos; + } + + if ( bDateNoDefault ) + return false; // additional elements + else + { + NfIndexTableOffset eFound = static_cast(SvXMLNumFmtDefaults::GetDefaultDateFormat( + eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate )); + + return ( eFound == eBuiltIn ); + } +} + +// export one part (condition) + +void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey, + sal_uInt16 nPart, bool bDefPart ) +{ + //! for the default part, pass the conditions from the other parts! + + // element name + + NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nRealKey ); + + SvNumFormatType nFmtType = SvNumFormatType::ALL; + bool bThousand = false; + sal_uInt16 nPrecision = 0; + sal_uInt16 nLeading = 0; + rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading); + nFmtType &= ~SvNumFormatType::DEFINED; + + // special treatment of builtin formats that aren't detected by normal parsing + // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats) + if ( eBuiltIn == NF_NUMBER_STANDARD ) + nFmtType = SvNumFormatType::NUMBER; + else if ( eBuiltIn == NF_BOOLEAN ) + nFmtType = SvNumFormatType::LOGICAL; + else if ( eBuiltIn == NF_TEXT ) + nFmtType = SvNumFormatType::TEXT; + + // #101606# An empty subformat is a valid number-style resulting in an + // empty display string for the condition of the subformat. + + XMLTokenEnum eType = XML_TOKEN_INVALID; + switch ( nFmtType ) + { + // Type UNDEFINED likely is a crappy format string for that we could + // not decide on any format type (and maybe could try harder?), but the + // resulting XMLTokenEnum should be something valid, so make that + // number-style. + case SvNumFormatType::UNDEFINED: + SAL_WARN("xmloff.style","UNDEFINED number format: '" << rFormat.GetFormatstring() << "'"); + [[fallthrough]]; + // Type is 0 if a format contains no recognized elements + // (like text only) - this is handled as a number-style. + case SvNumFormatType::ALL: + case SvNumFormatType::EMPTY: + case SvNumFormatType::NUMBER: + case SvNumFormatType::SCIENTIFIC: + case SvNumFormatType::FRACTION: + eType = XML_NUMBER_STYLE; + break; + case SvNumFormatType::PERCENT: + eType = XML_PERCENTAGE_STYLE; + break; + case SvNumFormatType::CURRENCY: + eType = XML_CURRENCY_STYLE; + break; + case SvNumFormatType::DATE: + case SvNumFormatType::DATETIME: + eType = XML_DATE_STYLE; + break; + case SvNumFormatType::TIME: + eType = XML_TIME_STYLE; + break; + case SvNumFormatType::TEXT: + eType = XML_TEXT_STYLE; + break; + case SvNumFormatType::LOGICAL: + eType = XML_BOOLEAN_STYLE; + break; + default: break; + } + SAL_WARN_IF( eType == XML_TOKEN_INVALID, "xmloff.style", "unknown format type" ); + + OUString sAttrValue; + bool bUserDef( rFormat.GetType() & SvNumFormatType::DEFINED ); + + // common attributes for format + + // format name (generated from key) - style namespace + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_NAME, + lcl_CreateStyleName( nKey, nPart, bDefPart, sPrefix ) ); + + // "volatile" attribute for styles used only in maps + if ( !bDefPart ) + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_VOLATILE, XML_TRUE ); + + // language / country + LanguageType nLang = rFormat.GetLanguage(); + AddLanguageAttr_Impl( nLang ); // adds to pAttrList + + // title (comment) + // titles for builtin formats are not written + sAttrValue = rFormat.GetComment(); + if ( !sAttrValue.isEmpty() && bUserDef && bDefPart ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TITLE, sAttrValue ); + } + + // automatic ordering for currency and date formats + // only used for some built-in formats + bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT || eBuiltIn == NF_CURRENCY_1000DEC2 || + eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED || + eBuiltIn == NF_CURRENCY_1000DEC2_DASHED || + eBuiltIn == NF_DATE_SYSTEM_SHORT || eBuiltIn == NF_DATE_SYSTEM_LONG || + eBuiltIn == NF_DATE_SYS_MMYY || eBuiltIn == NF_DATE_SYS_DDMMM || + eBuiltIn == NF_DATE_SYS_DDMMYYYY || eBuiltIn == NF_DATE_SYS_DDMMYY || + eBuiltIn == NF_DATE_SYS_DMMMYY || eBuiltIn == NF_DATE_SYS_DMMMYYYY || + eBuiltIn == NF_DATE_SYS_DMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNDMMMYY || + eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY || + eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM || eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMM || + eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS ); + + // format source (for date and time formats) + // only used for some built-in formats + bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT || + eBuiltIn == NF_DATE_SYSTEM_LONG || + eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM ); + bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG ); + + // check if the format definition matches the key + if ( bAutoOrder && ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) && + !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) ) + { + bAutoOrder = bSystemDate = bLongSysDate = false; // don't write automatic-order attribute then + } + + if ( bAutoOrder && + ( nFmtType == SvNumFormatType::CURRENCY || nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) ) + { + // #85109# format type must be checked to avoid dtd errors if + // locale data contains other format types at the built-in positions + + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_AUTOMATIC_ORDER, + XML_TRUE ); + } + + if ( bSystemDate && bAutoOrder && + ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) ) + { + // #85109# format type must be checked to avoid dtd errors if + // locale data contains other format types at the built-in positions + + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_FORMAT_SOURCE, + XML_LANGUAGE ); + } + + // overflow for time formats as in [hh]:mm + // controlled by bThousand from number format info + // default for truncate-on-overflow is true + if ( nFmtType == SvNumFormatType::TIME && bThousand ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRUNCATE_ON_OVERFLOW, + XML_FALSE ); + } + + // Native number transliteration + css::i18n::NativeNumberXmlAttributes2 aAttr; + rFormat.GetNatNumXml( aAttr, nPart ); + if ( !aAttr.Format.isEmpty() ) + { + assert(aAttr.Spellout.isEmpty()); // mutually exclusive + + /* FIXME-BCP47: ODF defines no transliteration-script or + * transliteration-rfc-language-tag */ + LanguageTag aLanguageTag( aAttr.Locale); + OUString aLanguage, aScript, aCountry; + aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry); + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_FORMAT, + aAttr.Format ); + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE, + aLanguage ); + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY, + aCountry ); + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_STYLE, + aAttr.Style ); + } + + if ( !aAttr.Spellout.isEmpty() ) + { + const bool bWriteSpellout = aAttr.Format.isEmpty(); + assert(bWriteSpellout); // mutually exclusive + + // Export only for 1.2 and later with extensions + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + // Also ensure that duplicated transliteration-language and + // transliteration-country attributes never escape into the wild with + // releases. + if ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) && bWriteSpellout ) + { + /* FIXME-BCP47: ODF defines no transliteration-script or + * transliteration-rfc-language-tag */ + LanguageTag aLanguageTag( aAttr.Locale); + OUString aLanguage, aScript, aCountry; + aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry); + // For 1.2/1.3+ use loext namespace. + rExport.AddAttribute( /*((eVersion < SvtSaveOptions::ODFSVER_) + ? */ XML_NAMESPACE_LO_EXT /*: XML_NAMESPACE_NUMBER)*/, + XML_TRANSLITERATION_SPELLOUT, aAttr.Spellout ); + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_LANGUAGE, + aLanguage ); + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_TRANSLITERATION_COUNTRY, + aCountry ); + } + } + + // The element + SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, eType, + true, true ); + + // color (properties element) + + const Color* pCol = rFormat.GetColor( nPart ); + if (pCol) + WriteColorElement_Impl(*pCol); + + // detect if there is "real" content, excluding color and maps + //! move to implementation of Write... methods? + bool bAnyContent = false; + + // format elements + + SvXMLEmbeddedTextEntryArr aEmbeddedEntries; + if ( eBuiltIn == NF_NUMBER_STANDARD ) + { + // default number format contains just one number element + WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries ); + bAnyContent = true; + } + else if ( eBuiltIn == NF_BOOLEAN ) + { + // boolean format contains just one boolean element + WriteBooleanElement_Impl(); + bAnyContent = true; + } + else if (eType == XML_BOOLEAN_STYLE) + { + // may contain only and + // elements. + sal_uInt16 nPos = 0; + bool bEnd = false; + while (!bEnd) + { + const short nElemType = rFormat.GetNumForType( nPart, nPos ); + switch (nElemType) + { + case 0: + bEnd = true; // end of format reached + if (bHasText && sTextContent.isEmpty()) + bHasText = false; // don't write trailing empty text + break; + case NF_SYMBOLTYPE_STRING: + { + const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos ); + if (pElemStr) + AddToTextElement_Impl( *pElemStr ); + } + break; + case NF_KEY_BOOLEAN: + WriteBooleanElement_Impl(); + bAnyContent = true; + break; + } + ++nPos; + } + } + else + { + // first loop to collect attributes + + bool bDecDashes = false; + bool bExpFound = false; + bool bCurrFound = false; + bool bInInteger = true; + bool bExpSign = true; + bool bDecAlign = false; // decimal alignment with "?" + sal_Int32 nExpDigits = 0; + sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#" + sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits + sal_Int32 nMinDecimals = nPrecision; + OUString sCurrExt; + OUString aCalendar; + bool bImplicitOtherCalendar = false; + bool bExplicitCalendar = false; + sal_uInt16 nPos = 0; + bool bEnd = false; + while (!bEnd) + { + short nElemType = rFormat.GetNumForType( nPart, nPos ); + const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos ); + + switch ( nElemType ) + { + case 0: + bEnd = true; // end of format reached + break; + case NF_SYMBOLTYPE_DIGIT: + if ( bExpFound && pElemStr ) + nExpDigits += pElemStr->getLength(); + else if ( !bDecDashes && pElemStr && (*pElemStr)[0] == '-' ) + { + bDecDashes = true; + nMinDecimals = 0; + } + else if ( !bInInteger && pElemStr ) + { + for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- ) + { + sal_Unicode aChar = (*pElemStr)[i]; + if ( aChar == '#' || aChar == '?' ) + { + nMinDecimals --; + if ( aChar == '?' ) + bDecAlign = true; + } + else + break; + } + } + if ( bInInteger && pElemStr ) + nIntegerSymbols += pElemStr->getLength(); + nTrailingThousands = 0; + break; + case NF_SYMBOLTYPE_DECSEP: + bInInteger = false; + break; + case NF_SYMBOLTYPE_THSEP: + if (pElemStr) + nTrailingThousands += pElemStr->getLength(); // is reset to 0 if digits follow + break; + case NF_SYMBOLTYPE_EXP: + bExpFound = true; // following digits are exponent digits + bInInteger = false; + if ( pElemStr && ( pElemStr->getLength() == 1 + || ( pElemStr->getLength() == 2 && (*pElemStr)[1] == '-' ) ) ) + bExpSign = false; // for 0.00E0 or 0.00E-00 + break; + case NF_SYMBOLTYPE_CURRENCY: + bCurrFound = true; + break; + case NF_SYMBOLTYPE_CURREXT: + if (pElemStr) + sCurrExt = *pElemStr; + break; + + // E, EE, R, RR: select non-gregorian calendar + // AAA, AAAA: calendar is switched at the position of the element + case NF_KEY_EC: + case NF_KEY_EEC: + case NF_KEY_R: + case NF_KEY_RR: + if (aCalendar.isEmpty()) + { + aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang ); + bImplicitOtherCalendar = true; + } + break; + } + ++nPos; + } + + // collect strings for embedded-text (must be known before number element is written) + + bool bAllowEmbedded = ( nFmtType == SvNumFormatType::ALL || nFmtType == SvNumFormatType::NUMBER || + nFmtType == SvNumFormatType::CURRENCY || + nFmtType == SvNumFormatType::PERCENT ); + if ( bAllowEmbedded ) + { + sal_Int32 nDigitsPassed = 0; + sal_Int32 nEmbeddedPositionsMax = nIntegerSymbols; + // Enable embedded text in decimal part only if there's a decimal part + if ( nPrecision ) + nEmbeddedPositionsMax += nPrecision + 1; + nPos = 0; + bEnd = false; + while (!bEnd) + { + short nElemType = rFormat.GetNumForType( nPart, nPos ); + const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos ); + + switch ( nElemType ) + { + case 0: + bEnd = true; // end of format reached + break; + case NF_SYMBOLTYPE_DIGIT: + if ( pElemStr ) + nDigitsPassed += pElemStr->getLength(); + break; + case NF_SYMBOLTYPE_DECSEP: + nDigitsPassed++; + break; + case NF_SYMBOLTYPE_STRING: + case NF_SYMBOLTYPE_BLANK: + case NF_SYMBOLTYPE_PERCENT: + if ( 0 < nDigitsPassed && nDigitsPassed < nEmbeddedPositionsMax && pElemStr ) + { + // text (literal or underscore) within the integer (>=0) or decimal (<0) part of a number:number element + + OUString aEmbeddedStr; + if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT ) + { + aEmbeddedStr = *pElemStr; + } + else if (pElemStr->getLength() >= 2) + { + SvNumberformat::InsertBlanks( aEmbeddedStr, 0, (*pElemStr)[1] ); + } + sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed; + + aEmbeddedEntries.push_back( + SvXMLEmbeddedTextEntry(nPos, nEmbedPos, aEmbeddedStr)); + } + break; + } + ++nPos; + } + } + + // final loop to write elements + + bool bNumWritten = false; + bool bCurrencyWritten = false; + short nPrevType = 0; + nPos = 0; + bEnd = false; + while (!bEnd) + { + short nElemType = rFormat.GetNumForType( nPart, nPos ); + const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos ); + + switch ( nElemType ) + { + case 0: + bEnd = true; // end of format reached + if (bHasText && sTextContent.isEmpty()) + bHasText = false; // don't write trailing empty text + break; + case NF_SYMBOLTYPE_STRING: + case NF_SYMBOLTYPE_DATESEP: + case NF_SYMBOLTYPE_TIMESEP: + case NF_SYMBOLTYPE_TIME100SECSEP: + case NF_SYMBOLTYPE_PERCENT: + if (pElemStr) + { + if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) && + ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) && + nPrecision > 0 ) + { + // decimal separator after seconds is implied by + // "decimal-places" attribute and must not be written + // as text element + //! difference between '.' and ',' is lost here + } + else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) ) + { + // text is written as embedded-text child of the number, + // don't create a text element + } + else if ( nFmtType == SvNumFormatType::CURRENCY && !bCurrFound && !bCurrencyWritten ) + { + // automatic currency symbol is implemented as part of + // normal text -> search for the symbol + bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr, + LanguageTag::convertToLocale( nLang ) ); + bAnyContent = true; + } + else + AddToTextElement_Impl( *pElemStr ); + } + break; + case NF_SYMBOLTYPE_BLANK: + if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) ) + { + // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat + // (#i20396# the spaces may also be in embedded-text elements) + + OUString aBlanks; + if (pElemStr->getLength() >= 2) + SvNumberformat::InsertBlanks( aBlanks, 0, (*pElemStr)[1] ); + AddToTextElement_Impl( aBlanks ); + } + break; + case NF_KEY_GENERAL : + WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries ); + bAnyContent = true; + break; + case NF_KEY_CCC: + if (pElemStr) + { + if ( bCurrencyWritten ) + AddToTextElement_Impl( *pElemStr ); // never more than one currency element + else + { + //! must be different from short automatic format + //! but should still be empty (meaning automatic) + // pElemStr is "CCC" + + WriteCurrencyElement_Impl( *pElemStr, u"" ); + bAnyContent = true; + bCurrencyWritten = true; + } + } + break; + case NF_SYMBOLTYPE_CURRENCY: + if (pElemStr) + { + if ( bCurrencyWritten ) + AddToTextElement_Impl( *pElemStr ); // never more than one currency element + else + { + WriteCurrencyElement_Impl( *pElemStr, sCurrExt ); + bAnyContent = true; + bCurrencyWritten = true; + } + } + break; + case NF_SYMBOLTYPE_DIGIT: + if (!bNumWritten) // write number part + { + switch ( nFmtType ) + { + // for type 0 (not recognized as a special type), + // write a "normal" number + case SvNumFormatType::ALL: + case SvNumFormatType::NUMBER: + case SvNumFormatType::CURRENCY: + case SvNumFormatType::PERCENT: + { + // decimals + // only some built-in formats have automatic decimals + sal_Int32 nDecimals = nPrecision; // from GetFormatSpecialInfo + if ( eBuiltIn == NF_NUMBER_STANDARD || + eBuiltIn == NF_CURRENCY_1000DEC2 || + eBuiltIn == NF_CURRENCY_1000DEC2_RED || + eBuiltIn == NF_CURRENCY_1000DEC2_CCC || + eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ) + nDecimals = -1; + + // integer digits + // only one built-in format has automatic integer digits + sal_Int32 nInteger = nLeading; + if ( eBuiltIn == NF_NUMBER_SYSTEM ) + nInteger = -1; + + // string for decimal replacement + // has to be taken from nPrecision + // (positive number even for automatic decimals) + OUStringBuffer sDashStr; + if (bDecDashes && nPrecision > 0) + comphelper::string::padToLength(sDashStr, nPrecision, '-'); + // "?" in decimal part are replaced by space character + if (bDecAlign && nPrecision > 0) + sDashStr = " "; + + WriteNumberElement_Impl(nDecimals, nMinDecimals, nInteger, sDashStr.makeStringAndClear(), + bThousand, nTrailingThousands, aEmbeddedEntries); + bAnyContent = true; + } + break; + case SvNumFormatType::SCIENTIFIC: + // #i43959# for scientific numbers, count all integer symbols ("0" and "#") + // as integer digits: use nIntegerSymbols instead of nLeading + // nIntegerSymbols represents exponent interval (for engineering notation) + WriteScientificElement_Impl( nPrecision, nMinDecimals, nLeading, bThousand, nExpDigits, nIntegerSymbols, bExpSign ); + bAnyContent = true; + break; + case SvNumFormatType::FRACTION: + { + sal_Int32 nInteger = nLeading; + if ( rFormat.GetNumForNumberElementCount( nPart ) == 3 ) + { + // If there is only two numbers + fraction in format string + // the fraction doesn't have an integer part, and no + // min-integer-digits attribute must be written. + nInteger = -1; + } + WriteFractionElement_Impl( nInteger, bThousand, rFormat, nPart ); + bAnyContent = true; + } + break; + default: break; + } + + bNumWritten = true; + } + break; + case NF_SYMBOLTYPE_DECSEP: + if ( pElemStr && nPrecision == 0 ) + { + // A decimal separator after the number, without following decimal digits, + // isn't modelled as part of the number element, so it's written as text + // (the distinction between a quoted and non-quoted, locale-dependent + // character is lost here). + + AddToTextElement_Impl( *pElemStr ); + } + break; + case NF_SYMBOLTYPE_DEL: + if ( pElemStr && *pElemStr == "@" ) + { + WriteTextContentElement_Impl(); + bAnyContent = true; + } + break; + + case NF_SYMBOLTYPE_CALENDAR: + if ( pElemStr ) + { + aCalendar = *pElemStr; + bExplicitCalendar = true; + } + break; + + // date elements: + + case NF_KEY_D: + case NF_KEY_DD: + { + bool bLong = ( nElemType == NF_KEY_DD ); + WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); + bAnyContent = true; + } + break; + case NF_KEY_DDD: + case NF_KEY_DDDD: + case NF_KEY_NN: + case NF_KEY_NNN: + case NF_KEY_NNNN: + case NF_KEY_AAA: + case NF_KEY_AAAA: + { + OUString aCalAttr = aCalendar; + if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA ) + { + // calendar attribute for AAA and AAAA is switched only for this element + if (aCalAttr.isEmpty()) + aCalAttr = lcl_GetDefaultCalendar( pFormatter, nLang ); + } + + bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN || + nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA ); + WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) ); + bAnyContent = true; + if ( nElemType == NF_KEY_NNNN ) + { + // write additional text element for separator + pLocaleData.reset( new LocaleDataWrapper( pFormatter->GetComponentContext(), + LanguageTag( nLang ) ) ); + AddToTextElement_Impl( pLocaleData->getLongDateDayOfWeekSep() ); + } + } + break; + case NF_KEY_M: + case NF_KEY_MM: + case NF_KEY_MMM: + case NF_KEY_MMMM: + case NF_KEY_MMMMM: //! first letter of month name, no attribute available + { + bool bLong = ( nElemType == NF_KEY_MM || nElemType == NF_KEY_MMMM ); + bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM || + nElemType == NF_KEY_MMMMM ); + WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText ); + bAnyContent = true; + } + break; + case NF_KEY_YY: + case NF_KEY_YYYY: + case NF_KEY_EC: + case NF_KEY_EEC: + case NF_KEY_R: //! R acts as EE, no attribute available + { + //! distinguish EE and R + // Calendar attribute for E and EE and R is set in + // first loop. If set and not an explicit calendar and + // YY or YYYY is encountered, switch temporarily to + // Gregorian. + bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC || + nElemType == NF_KEY_R ); + WriteYearElement_Impl( + ((bImplicitOtherCalendar && !bExplicitCalendar + && (nElemType == NF_KEY_YY || nElemType == NF_KEY_YYYY)) ? "gregorian" : aCalendar), + (bSystemDate ? bLongSysDate : bLong)); + bAnyContent = true; + } + break; + case NF_KEY_G: + case NF_KEY_GG: + case NF_KEY_GGG: + case NF_KEY_RR: //! RR acts as GGGEE, no attribute available + { + //! distinguish GG and GGG and RR + bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR ); + WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); + bAnyContent = true; + if ( nElemType == NF_KEY_RR ) + { + // calendar attribute for RR is set in first loop + WriteYearElement_Impl( aCalendar, ( bSystemDate || bLongSysDate ) ); + } + } + break; + case NF_KEY_Q: + case NF_KEY_QQ: + { + bool bLong = ( nElemType == NF_KEY_QQ ); + WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) ); + bAnyContent = true; + } + break; + case NF_KEY_WW: + WriteWeekElement_Impl( aCalendar ); + bAnyContent = true; + break; + + // time elements (bSystemDate is not used): + + case NF_KEY_H: + case NF_KEY_HH: + WriteHoursElement_Impl( nElemType == NF_KEY_HH ); + bAnyContent = true; + break; + case NF_KEY_MI: + case NF_KEY_MMI: + WriteMinutesElement_Impl( nElemType == NF_KEY_MMI ); + bAnyContent = true; + break; + case NF_KEY_S: + case NF_KEY_SS: + WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision ); + bAnyContent = true; + break; + case NF_KEY_AMPM: + case NF_KEY_AP: + WriteAMPMElement_Impl(); // short/long? + bAnyContent = true; + break; + case NF_SYMBOLTYPE_STAR : + // export only if ODF 1.2 extensions are enabled + if (rExport.getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + if ( pElemStr && pElemStr->getLength() > 1 ) + WriteRepeatedElement_Impl( (*pElemStr)[1] ); + } + break; + } + nPrevType = nElemType; + ++nPos; + } + } + + if ( !sTextContent.isEmpty() ) + bAnyContent = true; // element written in FinishTextElement_Impl + + FinishTextElement_Impl(); // final text element - before maps + + if ( !bAnyContent ) + { + // for an empty format, write an empty text element + SvXMLElementExport aTElem( rExport, XML_NAMESPACE_NUMBER, XML_TEXT, + true, false ); + } + + // mapping (conditions) must be last elements + + if (!bDefPart) + return; + + SvNumberformatLimitOps eOp1, eOp2; + double fLimit1, fLimit2; + rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 ); + + WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 ); + WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 ); + + if ( !rFormat.HasTextFormat() ) + return; + + // 4th part is for text -> make an "all other numbers" condition for the 3rd part + // by reversing the 2nd condition. + // For a trailing text format like 0;@ that has no conditions + // use a "less or equal than biggest" condition for the number + // part, ODF can't store subformats (style maps) without + // conditions. + + SvNumberformatLimitOps eOp3 = NUMBERFORMAT_OP_NO; + double fLimit3 = fLimit2; + sal_uInt16 nLastPart = 2; + SvNumberformatLimitOps eOpLast = eOp2; + if (eOp2 == NUMBERFORMAT_OP_NO) + { + eOpLast = eOp1; + fLimit3 = fLimit1; + nLastPart = (eOp1 == NUMBERFORMAT_OP_NO) ? 0 : 1; + } + switch ( eOpLast ) + { + case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break; + case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break; + case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break; + case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break; + case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break; + case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break; + case NUMBERFORMAT_OP_NO: eOp3 = NUMBERFORMAT_OP_LE; fLimit3 = DBL_MAX; break; + } + + if ( fLimit1 == fLimit2 && + ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) || + ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) ) + { + // For x, add =x as last condition + // (just for readability, <=x would be valid, too) + + eOp3 = NUMBERFORMAT_OP_EQ; + } + + WriteMapElement_Impl( eOp3, fLimit3, nKey, nLastPart ); +} + +// export one format + +void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey ) +{ + const sal_uInt16 XMLNUM_MAX_PARTS = 4; + bool bParts[XMLNUM_MAX_PARTS] = { false, false, false, false }; + sal_uInt16 nUsedParts = 0; + for (sal_uInt16 nPart=0; nPart no entries + + sal_uInt32 nKey; + const SvNumberformat* pFormat = nullptr; + bool bNext(pUsedList->GetFirstUsed(nKey)); + while(bNext) + { + // ODF has its notation of system formats, so obtain the "real" already + // substituted format but use the original key for style name. + sal_uInt32 nRealKey = nKey; + pFormat = pFormatter->GetSubstitutedEntry( nKey, nRealKey); + if(pFormat) + ExportFormat_Impl( *pFormat, nKey, nRealKey ); + bNext = pUsedList->GetNextUsed(nKey); + } + if (!bIsAutoStyle) + { + std::vector aLanguages; + pFormatter->GetUsedLanguages( aLanguages ); + for (const auto& nLang : aLanguages) + { + sal_uInt32 nDefaultIndex = 0; + SvNumberFormatTable& rTable = pFormatter->GetEntryTable( + SvNumFormatType::DEFINED, nDefaultIndex, nLang ); + for (const auto& rTableEntry : rTable) + { + nKey = rTableEntry.first; + pFormat = rTableEntry.second; + if (!pUsedList->IsUsed(nKey)) + { + DBG_ASSERT((pFormat->GetType() & SvNumFormatType::DEFINED), "a not user defined numberformat found"); + sal_uInt32 nRealKey = nKey; + if (pFormat->IsSubstituted()) + { + pFormat = pFormatter->GetSubstitutedEntry( nKey, nRealKey); // export the "real" format + assert(pFormat); + } + // user-defined and used formats are exported + ExportFormat_Impl( *pFormat, nKey, nRealKey ); + // if it is a user-defined Format it will be added else nothing will happen + pUsedList->SetUsed(nKey); + } + } + } + } + pUsedList->Export(); +} + +OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey ) +{ + if(pUsedList->IsUsed(nKey) || pUsedList->IsWasUsed(nKey)) + return lcl_CreateStyleName( nKey, 0, true, sPrefix ); + else + { + OSL_FAIL("There is no written Data-Style"); + return OUString(); + } +} + +void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey ) +{ + SAL_WARN_IF( pFormatter == nullptr, "xmloff.style", "missing formatter" ); + if( !pFormatter ) + return; + + if (pFormatter->GetEntry(nKey)) + pUsedList->SetUsed( nKey ); + else { + OSL_FAIL("no existing Numberformat found with this key"); + } +} + +uno::Sequence SvXMLNumFmtExport::GetWasUsed() const +{ + if (pUsedList) + return pUsedList->GetWasUsed(); + return uno::Sequence(); +} + +void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence& rWasUsed) +{ + if (pUsedList) + pUsedList->SetWasUsed(rWasUsed); +} + +static const SvNumberformat* lcl_GetFormat( SvNumberFormatter const * pFormatter, + sal_uInt32 nKey ) +{ + return ( pFormatter != nullptr ) ? pFormatter->GetEntry( nKey ) : nullptr; +} + +sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey ) +{ + sal_uInt32 nRet = nKey; + + const SvNumberformat* pFormat = lcl_GetFormat( pFormatter, nKey ); + if( pFormat != nullptr ) + { + SAL_WARN_IF( pFormatter == nullptr, "xmloff.style", "format without formatter?" ); + + SvNumFormatType nType = pFormat->GetType(); + + sal_uInt32 nNewKey = pFormatter->GetFormatForLanguageIfBuiltIn( + nKey, LANGUAGE_SYSTEM ); + + if( nNewKey != nKey ) + { + nRet = nNewKey; + } + else + { + OUString aFormatString( pFormat->GetFormatstring() ); + sal_Int32 nErrorPos; + pFormatter->PutandConvertEntry( + aFormatString, + nErrorPos, nType, nNewKey, + pFormat->GetLanguage(), LANGUAGE_SYSTEM, true); + + // success? Then use new key. + if( nErrorPos == 0 ) + nRet = nNewKey; + } + } + + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlnumfi.cxx b/xmloff/source/style/xmlnumfi.cxx new file mode 100644 index 000000000..b046e5f59 --- /dev/null +++ b/xmloff/source/style/xmlnumfi.cxx @@ -0,0 +1,2231 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +namespace { + +struct SvXMLNumFmtEntry +{ + OUString aName; + sal_uInt32 nKey; + bool bRemoveAfterUse; + + SvXMLNumFmtEntry( const OUString& rN, sal_uInt32 nK, bool bR ) : + aName(rN), nKey(nK), bRemoveAfterUse(bR) {} +}; + +} + +class SvXMLNumImpData +{ + SvNumberFormatter* pFormatter; + std::unique_ptr pLocaleData; + std::vector m_NameEntries; + + uno::Reference< uno::XComponentContext > m_xContext; + +public: + SvXMLNumImpData( + SvNumberFormatter* pFmt, + const uno::Reference& rxContext ); + + SvNumberFormatter* GetNumberFormatter() const { return pFormatter; } + const LocaleDataWrapper& GetLocaleData( LanguageType nLang ); + sal_uInt32 GetKeyForName( std::u16string_view rName ); + void AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse ); + void SetUsed( sal_uInt32 nKey ); + void RemoveVolatileFormats(); +}; + +struct SvXMLNumberInfo +{ + sal_Int32 nDecimals = -1; + sal_Int32 nInteger = -1; + sal_Int32 nExpDigits = -1; + sal_Int32 nExpInterval = -1; + sal_Int32 nMinNumerDigits = -1; + sal_Int32 nMinDenomDigits = -1; + sal_Int32 nMaxNumerDigits = -1; + sal_Int32 nMaxDenomDigits = -1; + sal_Int32 nFracDenominator = -1; + sal_Int32 nMinDecimalDigits = -1; + sal_Int32 nZerosNumerDigits = -1; + sal_Int32 nZerosDenomDigits = -1; + bool bGrouping = false; + bool bDecReplace = false; + bool bExpSign = true; + bool bDecAlign = false; + double fDisplayFactor = 1.0; + OUString aIntegerFractionDelimiter; + std::map m_EmbeddedElements; +}; + +namespace { + +enum class SvXMLStyleTokens; + +class SvXMLNumFmtElementContext : public SvXMLImportContext +{ + SvXMLNumFormatContext& rParent; + SvXMLStyleTokens nType; + OUStringBuffer aContent; + SvXMLNumberInfo aNumInfo; + LanguageType nElementLang; + bool bLong; + bool bTextual; + OUString sCalendar; + +public: + SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_Int32 nElement, + SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + void AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent ); +}; + +class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext +{ + SvXMLNumFmtElementContext& rParent; + OUStringBuffer aContent; + sal_Int32 nTextPosition; + +public: + SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_Int32 nElement, + SvXMLNumFmtElementContext& rParentContext, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + virtual void SAL_CALL characters( const OUString& rChars ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class SvXMLNumFmtMapContext : public SvXMLImportContext +{ + SvXMLNumFormatContext& rParent; + OUString sCondition; + OUString sName; + +public: + SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_Int32 nElement, + SvXMLNumFormatContext& rParentContext, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +class SvXMLNumFmtPropContext : public SvXMLImportContext +{ + SvXMLNumFormatContext& rParent; + Color m_nColor; + bool bColSet; + +public: + SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_Int32 nElement, + SvXMLNumFormatContext& rParentContext, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +enum class SvXMLStyleTokens +{ + Text, + FillCharacter, + Number, + ScientificNumber, + Fraction, + CurrencySymbol, + Day, + Month, + Year, + Era, + DayOfWeek, + WeekOfYear, + Quarter, + Hours, + AmPm, + Minutes, + Seconds, + Boolean, + TextContent +}; + +} + +// standard colors + + +#define XML_NUMF_COLORCOUNT 10 + +const Color aNumFmtStdColors[XML_NUMF_COLORCOUNT] = +{ + COL_BLACK, + COL_LIGHTBLUE, + COL_LIGHTGREEN, + COL_LIGHTCYAN, + COL_LIGHTRED, + COL_LIGHTMAGENTA, + COL_BROWN, + COL_GRAY, + COL_YELLOW, + COL_WHITE +}; + + +// token maps + + +// maps for SvXMLUnitConverter::convertEnum + +const SvXMLEnumMapEntry aStyleValueMap[] = +{ + { XML_SHORT, false }, + { XML_LONG, true }, + { XML_TOKEN_INVALID, false } +}; + +const SvXMLEnumMapEntry aFormatSourceMap[] = +{ + { XML_FIXED, false }, + { XML_LANGUAGE, true }, + { XML_TOKEN_INVALID, false } +}; + +namespace { + +struct SvXMLDefaultDateFormat +{ + NfIndexTableOffset eFormat; + SvXMLDateElementAttributes eDOW; + SvXMLDateElementAttributes eDay; + SvXMLDateElementAttributes eMonth; + SvXMLDateElementAttributes eYear; + SvXMLDateElementAttributes eHours; + SvXMLDateElementAttributes eMins; + SvXMLDateElementAttributes eSecs; + bool bSystem; +}; + +} + +const SvXMLDefaultDateFormat aDefaultDateFormats[] = +{ + // format day-of-week day month year hours minutes seconds format-source + + { NF_DATE_SYSTEM_SHORT, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, true }, + { NF_DATE_SYSTEM_LONG, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, true }, + { NF_DATE_SYS_MMYY, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DDMMM, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_TEXTSHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DDMMYYYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DDMMYY, XML_DEA_NONE, XML_DEA_LONG, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DMMMYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_DMMMMYYYY, XML_DEA_NONE, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_NNDMMMYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTSHORT, XML_DEA_SHORT, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_NNDMMMMYYYY, XML_DEA_SHORT, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATE_SYS_NNNNDMMMMYYYY, XML_DEA_LONG, XML_DEA_SHORT, XML_DEA_TEXTLONG, XML_DEA_LONG, XML_DEA_NONE, XML_DEA_NONE, XML_DEA_NONE, false }, + { NF_DATETIME_SYS_DDMMYYYY_HHMM, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_LONG, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, false }, + { NF_DATETIME_SYSTEM_SHORT_HHMM, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_NONE, true }, + { NF_DATETIME_SYS_DDMMYYYY_HHMMSS, XML_DEA_NONE, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, XML_DEA_ANY, false } +}; + + +// SvXMLNumImpData + + +SvXMLNumImpData::SvXMLNumImpData( + SvNumberFormatter* pFmt, + const uno::Reference& rxContext ) +: pFormatter(pFmt), + m_xContext(rxContext) +{ + SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" ); +} + +sal_uInt32 SvXMLNumImpData::GetKeyForName( std::u16string_view rName ) +{ + for (const auto& rObj : m_NameEntries) + { + if (rObj.aName == rName) + return rObj.nKey; // found + } + return NUMBERFORMAT_ENTRY_NOT_FOUND; +} + +void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse ) +{ + if ( bRemoveAfterUse ) + { + // if there is already an entry for this key without the bRemoveAfterUse flag, + // clear the flag for this entry, too + + for (const auto& rObj : m_NameEntries) + { + if (rObj.nKey == nKey && !rObj.bRemoveAfterUse) + { + bRemoveAfterUse = false; // clear flag for new entry + break; + } + } + } + else + { + // call SetUsed to clear the bRemoveAfterUse flag for other entries for this key + SetUsed( nKey ); + } + + m_NameEntries.emplace_back(rName, nKey, bRemoveAfterUse); +} + +void SvXMLNumImpData::SetUsed( sal_uInt32 nKey ) +{ + for (auto& rObj : m_NameEntries) + { + if (rObj.nKey == nKey) + { + rObj.bRemoveAfterUse = false; // used -> don't remove + + // continue searching - there may be several entries for the same key + // (with different names), the format must not be deleted if any one of + // them is used + } + } +} + +void SvXMLNumImpData::RemoveVolatileFormats() +{ + // remove temporary (volatile) formats from NumberFormatter + // called at the end of each import (styles and content), so volatile formats + // from styles can't be used in content + + if ( !pFormatter ) + return; + + for (const auto& rObj : m_NameEntries) + { + if (rObj.bRemoveAfterUse ) + { + const SvNumberformat* pFormat = pFormatter->GetEntry(rObj.nKey); + if (pFormat && (pFormat->GetType() & SvNumFormatType::DEFINED)) + pFormatter->DeleteEntry(rObj.nKey); + } + } +} + +const LocaleDataWrapper& SvXMLNumImpData::GetLocaleData( LanguageType nLang ) +{ + if ( !pLocaleData || pLocaleData->getLanguageTag() != LanguageTag(nLang) ) + pLocaleData = std::make_unique( + pFormatter ? pFormatter->GetComponentContext() : m_xContext, + LanguageTag( nLang ) ); + return *pLocaleData; +} + + +// SvXMLNumFmtMapContext + + +SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumFormatContext& rParentContext, + const uno::Reference& xAttrList ) : + SvXMLImportContext( rImport ), + rParent( rParentContext ) +{ + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_CONDITION): + sCondition = sValue; + break; + case XML_ELEMENT(STYLE, XML_APPLY_STYLE_NAME): + sName = sValue; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +void SvXMLNumFmtMapContext::endFastElement(sal_Int32 ) +{ + rParent.AddCondition( sCondition, sName ); +} + + +// SvXMLNumFmtPropContext + + +SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumFormatContext& rParentContext, + const uno::Reference& xAttrList ) : + SvXMLImportContext( rImport ), + rParent( rParentContext ), + m_nColor( 0 ), + bColSet( false ) +{ + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + switch ( aIter.getToken()) + { + case XML_ELEMENT(FO, XML_COLOR): + case XML_ELEMENT(FO_COMPAT, XML_COLOR): + bColSet = ::sax::Converter::convertColor( m_nColor, aIter.toView() ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +void SvXMLNumFmtPropContext::endFastElement(sal_Int32 ) +{ + if (bColSet) + rParent.AddColor( m_nColor ); +} + + +// SvXMLNumFmtEmbeddedTextContext + + +SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumFmtElementContext& rParentContext, + const uno::Reference& xAttrList ) : + SvXMLImportContext( rImport ), + rParent( rParentContext ), + nTextPosition( 0 ) +{ + sal_Int32 nAttrVal; + + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + if ( aIter.getToken() == XML_ELEMENT(NUMBER, XML_POSITION) ) + { + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView() )) + nTextPosition = nAttrVal; + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +void SvXMLNumFmtEmbeddedTextContext::characters( const OUString& rChars ) +{ + aContent.append( rChars ); +} + +void SvXMLNumFmtEmbeddedTextContext::endFastElement(sal_Int32 ) +{ + rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() ); +} + +static bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent ) +{ + SvXMLStylesTokens nFormatType = rParent.GetType(); + + // Treat space equal to non-breaking space separator. + const sal_Unicode cNBSP = 0x00A0; + sal_Unicode cTS; + if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE || + nFormatType == SvXMLStylesTokens::CURRENCY_STYLE || + nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) && + (cChar == (cTS = rParent.GetLocaleData().getNumThousandSep()[0]) || + (cChar == ' ' && cTS == cNBSP)) ) + { + // #i22394# Extra occurrences of thousands separator must be quoted, so they + // aren't mis-interpreted as display-factor. + // This must be limited to the format types that can contain a number element, + // because the same character can be a date separator that should not be quoted + // in date formats. + + return false; // force quotes + } + + // see ImpSvNumberformatScan::Next_Symbol + + // All format types except BOOLEAN may contain minus sign or delimiter. + if ( cChar == '-' ) + return nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE; + + if ( ( cChar == ' ' || + cChar == '/' || + cChar == '.' || + cChar == ',' || + cChar == ':' || + cChar == '\'' ) && + ( nFormatType == SvXMLStylesTokens::CURRENCY_STYLE || + nFormatType == SvXMLStylesTokens::DATE_STYLE || + nFormatType == SvXMLStylesTokens::TIME_STYLE ) ) // other formats do not require delimiter tdf#97837 + return true; + + // percent sign must be used without quotes for percentage styles only + if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && cChar == '%' ) + return true; + + // don't put quotes around single parentheses (often used for negative numbers) + if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE || + nFormatType == SvXMLStylesTokens::CURRENCY_STYLE || + nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) && + ( cChar == '(' || cChar == ')' ) ) + return true; + + return false; +} + +static void lcl_EnquoteIfNecessary( OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent ) +{ + bool bQuote = true; + sal_Int32 nLength = rContent.getLength(); + const SvXMLStylesTokens nFormatType = rParent.GetType(); + + if (nFormatType != SvXMLStylesTokens::BOOLEAN_STYLE && + ((nLength == 1 && lcl_ValidChar( rContent[0], rParent)) || + (nLength == 2 && + ((rContent[0] == ' ' && rContent[1] == '-') || + (rContent[1] == ' ' && lcl_ValidChar( rContent[0], rParent)))))) + { + // Don't quote single separator characters like space or percent, + // or separator characters followed by space (used in date formats). + // Or space followed by minus (used in currency formats) that would + // lead to almost duplicated formats with built-in formats just with + // the difference of quotes. + bQuote = false; + } + else if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && nLength > 1 ) + { + // the percent character in percentage styles must be left out of quoting + // (one occurrence is enough even if there are several percent characters in the string) + + sal_Int32 nPos = rContent.indexOf( '%' ); + if ( nPos >= 0 ) + { + if ( nPos + 1 < nLength ) + { + if ( nPos + 2 == nLength && lcl_ValidChar( rContent[nPos + 1], rParent ) ) + { + // single character that doesn't need quoting + } + else + { + // quote text behind percent character + rContent.insert( nPos + 1, '"' ); + rContent.append( '"' ); + } + } + if ( nPos > 0 ) + { + if ( nPos == 1 && lcl_ValidChar( rContent[0], rParent ) ) + { + // single character that doesn't need quoting + } + else + { + // quote text before percent character + rContent.insert( nPos, '"' ); + rContent.insert( 0, '"' ); + } + } + bQuote = false; + } + // else: normal quoting (below) + } + + if ( !bQuote ) + return; + + // #i55469# quotes in the string itself have to be escaped + bool bEscape = ( rContent.indexOf( '"' ) >= 0 ); + if ( bEscape ) + { + // A quote is turned into "\"" - a quote to end quoted text, an escaped quote, + // and a quote to resume quoting. + OUString aInsert( "\"\\\"" ); + + sal_Int32 nPos = 0; + while ( nPos < rContent.getLength() ) + { + if ( rContent[nPos] == '"' ) + { + rContent.insert( nPos, aInsert ); + nPos += aInsert.getLength(); + } + ++nPos; + } + } + + // quote string literals + rContent.insert( 0, '"' ); + rContent.append( '"' ); + + // remove redundant double quotes at start or end + if ( !bEscape ) + return; + + if ( rContent.getLength() > 2 && + rContent[0] == '"' && + rContent[1] == '"' ) + { + rContent.remove(0, 2); + } + + sal_Int32 nLen = rContent.getLength(); + if ( nLen > 2 && + rContent[nLen - 1] == '"' && + rContent[nLen - 2] == '"' ) + { + rContent.truncate(nLen - 2); + } +} + + +// SvXMLNumFmtElementContext + + +SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType, + const uno::Reference& xAttrList ) : + SvXMLImportContext( rImport ), + rParent( rParentContext ), + nType( nNewType ), + nElementLang( LANGUAGE_SYSTEM ), + bLong( false ), + bTextual( false ) +{ + LanguageTagODF aLanguageTagODF; + sal_Int32 nAttrVal; + bool bAttrBool(false); + bool bVarDecimals = false; + bool bIsMaxDenominator = false; + double fAttrDouble; + + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(NUMBER, XML_DECIMAL_PLACES): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + { + // fdo#58539 & gnome#627420: limit number of digits during import + aNumInfo.nDecimals = std::min(nAttrVal, NF_MAX_FORMAT_SYMBOLS); + } + break; + case XML_ELEMENT(LO_EXT, XML_MIN_DECIMAL_PLACES): + case XML_ELEMENT(NUMBER, XML_MIN_DECIMAL_PLACES): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nMinDecimalDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_MIN_INTEGER_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nInteger = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_GROUPING): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + aNumInfo.bGrouping = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_DISPLAY_FACTOR): + if (::sax::Converter::convertDouble( fAttrDouble, aIter.toView() )) + aNumInfo.fDisplayFactor = fAttrDouble; + break; + case XML_ELEMENT(NUMBER, XML_DECIMAL_REPLACEMENT): + if ( aIter.toView() == " " ) + { + aNumInfo.bDecAlign = true; // space replacement for "?" + bVarDecimals = true; + } + else + if ( aIter.isEmpty() ) + bVarDecimals = true; // empty replacement string: variable decimals + else // all other strings + aNumInfo.bDecReplace = true; // decimal replacement with dashes + break; + case XML_ELEMENT(NUMBER, XML_MIN_EXPONENT_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nExpDigits = std::min(nAttrVal, NF_MAX_FORMAT_SYMBOLS); + break; + case XML_ELEMENT(NUMBER, XML_EXPONENT_INTERVAL): + case XML_ELEMENT(LO_EXT, XML_EXPONENT_INTERVAL): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nExpInterval = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_FORCED_EXPONENT_SIGN): + case XML_ELEMENT(LO_EXT, XML_FORCED_EXPONENT_SIGN): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + aNumInfo.bExpSign = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_MIN_NUMERATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nMinNumerDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_MIN_DENOMINATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nMinDenomDigits = nAttrVal; + break; + case XML_ELEMENT(LO_EXT, XML_MAX_NUMERATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 )) // at least one '#' + aNumInfo.nMaxNumerDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_DENOMINATOR_VALUE): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 )) // 0 is not valid + { + aNumInfo.nFracDenominator = nAttrVal; + bIsMaxDenominator = false; + } + break; + case XML_ELEMENT(NUMBER, XML_MAX_DENOMINATOR_VALUE): // part of ODF 1.3 + case XML_ELEMENT(LO_EXT, XML_MAX_DENOMINATOR_VALUE): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 1 ) && aNumInfo.nFracDenominator <= 0) + { // if denominator value not yet defined + aNumInfo.nFracDenominator = nAttrVal; + bIsMaxDenominator = true; + } + break; + case XML_ELEMENT(LO_EXT, XML_ZEROS_NUMERATOR_DIGITS): + case XML_ELEMENT(NUMBER, XML_ZEROS_NUMERATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nZerosNumerDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_ZEROS_DENOMINATOR_DIGITS): + case XML_ELEMENT(LO_EXT, XML_ZEROS_DENOMINATOR_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nZerosDenomDigits = nAttrVal; + break; + case XML_ELEMENT(NUMBER, XML_INTEGER_FRACTION_DELIMITER): + case XML_ELEMENT(LO_EXT, XML_INTEGER_FRACTION_DELIMITER): + aNumInfo.aIntegerFractionDelimiter = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG): + aLanguageTagODF.maRfcLanguageTag = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_LANGUAGE): + aLanguageTagODF.maLanguage = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_SCRIPT): + aLanguageTagODF.maScript = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_COUNTRY): + aLanguageTagODF.maCountry = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_STYLE): + SvXMLUnitConverter::convertEnum( bLong, aIter.toView(), aStyleValueMap ); + break; + case XML_ELEMENT(NUMBER, XML_TEXTUAL): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + bTextual = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_CALENDAR): + sCalendar = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + if ( aNumInfo.nMinDecimalDigits == -1) + { + if ( bVarDecimals || aNumInfo.bDecReplace ) + aNumInfo.nMinDecimalDigits = 0; + else + aNumInfo.nMinDecimalDigits = aNumInfo.nDecimals; + } + if ( aNumInfo.nZerosDenomDigits > 0 ) + { // nMin = count of '0' and '?' + if ( aNumInfo.nMinDenomDigits < aNumInfo.nZerosDenomDigits ) + aNumInfo.nMinDenomDigits = aNumInfo.nZerosDenomDigits; + } + else + aNumInfo.nZerosDenomDigits = 0; + if ( aNumInfo.nMinDenomDigits >= 0 ) + if ( aNumInfo.nMaxDenomDigits < aNumInfo.nMinDenomDigits ) + aNumInfo.nMaxDenomDigits = ( aNumInfo.nMinDenomDigits ? aNumInfo.nMinDenomDigits : 1 ); + if ( aNumInfo.nZerosNumerDigits > 0 ) + { + if ( aNumInfo.nMinNumerDigits < aNumInfo.nZerosNumerDigits ) + aNumInfo.nMinNumerDigits = aNumInfo.nZerosNumerDigits; + } + else + aNumInfo.nZerosNumerDigits = 0; + if ( aNumInfo.nMinNumerDigits >= 0 ) + if ( aNumInfo.nMaxNumerDigits < aNumInfo.nMinNumerDigits ) + aNumInfo.nMaxNumerDigits = ( aNumInfo.nMinNumerDigits ? aNumInfo.nMinNumerDigits : 1 ); + if ( bIsMaxDenominator && aNumInfo.nFracDenominator > 0 ) + { + aNumInfo.nMaxDenomDigits = floor( log10( aNumInfo.nFracDenominator ) ) + 1; + aNumInfo.nFracDenominator = -1; // Max denominator value only gives number of digits at denominator + } + if ( aNumInfo.nMaxDenomDigits > 0 ) + { + if ( aNumInfo.nMinDenomDigits < 0 ) + aNumInfo.nMinDenomDigits = 0; + else if ( aNumInfo.nMinDenomDigits > aNumInfo.nMaxDenomDigits ) + aNumInfo.nMinDenomDigits = aNumInfo.nMaxDenomDigits; + } + + if ( !aLanguageTagODF.isEmpty() ) + { + nElementLang = aLanguageTagODF.getLanguageTag().getLanguageType( false); + if ( nElementLang == LANGUAGE_DONTKNOW ) + nElementLang = LANGUAGE_SYSTEM; //! error handling for unknown locales? + } + + if ( aNumInfo.aIntegerFractionDelimiter.isEmpty() ) + aNumInfo.aIntegerFractionDelimiter = " "; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFmtElementContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // only number:number supports number:embedded-text child element + + if ( nType == SvXMLStyleTokens::Number && + nElement == XML_ELEMENT(NUMBER, XML_EMBEDDED_TEXT) ) + { + return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nElement, *this, xAttrList ); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SvXMLNumFmtElementContext::characters( const OUString& rChars ) +{ + aContent.append( rChars ); +} + +void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent ) +{ + if (rContent.isEmpty()) + return; + + auto iterPair = aNumInfo.m_EmbeddedElements.emplace(nFormatPos, rContent); + if (!iterPair.second) + // there's already an element at this position - append text to existing element + iterPair.first->second += rContent; +} + +void SvXMLNumFmtElementContext::endFastElement(sal_Int32 ) +{ + bool bEffLong = bLong; + switch (nType) + { + case SvXMLStyleTokens::Text: + if ( rParent.HasLongDoW() && + std::u16string_view(aContent) == rParent.GetLocaleData().getLongDateDayOfWeekSep() ) + { + // skip separator constant after long day of week + // (NF_KEY_NNNN contains the separator) + + if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) ) + { + aContent.truncate(); + } + + rParent.SetHasLongDoW( false ); // only once + } + if ( !aContent.isEmpty() ) + { + lcl_EnquoteIfNecessary( aContent, rParent ); + rParent.AddToCode( aContent ); + aContent.setLength(0); + } + else + { + // Quoted empty text may be significant to separate. + aContent.append("\"\""); + rParent.AddToCode( aContent ); + aContent.setLength(0); + rParent.SetHasTrailingEmptyText(true); // *after* AddToCode() + } + break; + + case SvXMLStyleTokens::Number: + rParent.AddNumber( aNumInfo ); + break; + + case SvXMLStyleTokens::CurrencySymbol: + rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang ); + break; + + case SvXMLStyleTokens::TextContent: + rParent.AddToCode( '@'); + break; + case SvXMLStyleTokens::FillCharacter: + if ( !aContent.isEmpty() ) + { + rParent.AddToCode( '*' ); + rParent.AddToCode( aContent[0] ); + } + break; + case SvXMLStyleTokens::Boolean: + rParent.AddNfKeyword( NF_KEY_BOOLEAN ); + break; + + case SvXMLStyleTokens::Day: + rParent.UpdateCalendar( sCalendar ); +//! I18N doesn't provide SYSTEM or extended date information yet + + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_DD : NF_KEY_D ) ); + break; + case SvXMLStyleTokens::Month: + rParent.UpdateCalendar( sCalendar ); +//! I18N doesn't provide SYSTEM or extended date information yet + + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bTextual + ? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM ) + : ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) ); + break; + case SvXMLStyleTokens::Year: +//! I18N doesn't provide SYSTEM or extended date information yet + { + // Y after G (era) is replaced by E for a secondary calendar. + // Do not replace for default calendar. + // Also replace Y by E if we're switching to the secondary + // calendar of a locale if it is known to implicitly use E. + rParent.UpdateCalendar( sCalendar); + const SvXMLNumFormatContext::ImplicitCalendar eCal = rParent.GetImplicitCalendarState(); + if (eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY + || eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER) + { + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_EEC : NF_KEY_EC ) ); + } + else + { + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) ); + } + } + break; + case SvXMLStyleTokens::Era: + rParent.UpdateCalendar( sCalendar ); +//! I18N doesn't provide SYSTEM or extended date information yet + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_GGG : NF_KEY_G ) ); + // HasEra flag is set + break; + case SvXMLStyleTokens::DayOfWeek: +//! I18N doesn't provide SYSTEM or extended date information yet + { + // Implicit secondary calendar uses A keyword, default and + // explicit calendar N keyword. + rParent.UpdateCalendar( sCalendar); + const SvXMLNumFormatContext::ImplicitCalendar eCal = rParent.GetImplicitCalendarState(); + if (eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY + || eCal == SvXMLNumFormatContext::ImplicitCalendar::SECONDARY_FROM_OTHER) + { + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_AAAA : NF_KEY_AAA ) ); + } + else + { + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) ); + } + } + break; + case SvXMLStyleTokens::WeekOfYear: + rParent.UpdateCalendar( sCalendar ); + rParent.AddNfKeyword( NF_KEY_WW ); + break; + case SvXMLStyleTokens::Quarter: + rParent.UpdateCalendar( sCalendar ); + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_QQ : NF_KEY_Q ) ); + break; + case SvXMLStyleTokens::Hours: + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_HH : NF_KEY_H ) ); + break; + case SvXMLStyleTokens::AmPm: + //! short/long? + rParent.AddNfKeyword( NF_KEY_AMPM ); + break; + case SvXMLStyleTokens::Minutes: + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_MMI : NF_KEY_MI ) ); + break; + case SvXMLStyleTokens::Seconds: + rParent.AddNfKeyword( + sal::static_int_cast< sal_uInt16 >( + bEffLong ? NF_KEY_SS : NF_KEY_S ) ); + if ( aNumInfo.nDecimals > 0 ) + { + // manually add the decimal places + rParent.AddToCode(rParent.GetLocaleData().getNumDecimalSep()); + for (sal_Int32 i=0; i= 0 ) + { + // add integer part only if min-integer-digits attribute is there + aNumInfo.nDecimals = 0; + rParent.AddNumber( aNumInfo ); // number without decimals + OUStringBuffer sIntegerFractionDelimiter(aNumInfo.aIntegerFractionDelimiter); + lcl_EnquoteIfNecessary( sIntegerFractionDelimiter, rParent ); + rParent.AddToCode( sIntegerFractionDelimiter ); // default is ' ' + } + + //! build string and add at once + + sal_Int32 i; + for (i=aNumInfo.nMaxNumerDigits; i > 0; i--) + { + if ( i > aNumInfo.nMinNumerDigits ) + rParent.AddToCode( '#' ); + else if ( i > aNumInfo.nZerosNumerDigits ) + rParent.AddToCode( '?' ); + else + rParent.AddToCode( '0' ); + } + rParent.AddToCode( '/' ); + if ( aNumInfo.nFracDenominator > 0 ) + { + rParent.AddToCode( OUString::number( aNumInfo.nFracDenominator ) ); + } + else + { + for (i=aNumInfo.nMaxDenomDigits; i > 0 ; i--) + { + if ( i > aNumInfo.nMinDenomDigits ) + rParent.AddToCode( '#' ); + else if ( i > aNumInfo.nZerosDenomDigits ) + rParent.AddToCode( '?' ); + else + rParent.AddToCode( '0' ); + } + } + } + break; + + case SvXMLStyleTokens::ScientificNumber: + { + // exponential interval for engineering notation + if( !aNumInfo.bGrouping && aNumInfo.nExpInterval > aNumInfo.nInteger ) + { + for (sal_Int32 i=aNumInfo.nInteger; i(rEntry.eFormat); + } + } + + return NF_INDEX_TABLE_ENTRIES; // invalid +} + + +// SvXMLNumFormatContext + +SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + SvXMLNumImpData* pNewData, SvXMLStylesTokens nNewType, + const uno::Reference& xAttrList, + SvXMLStylesContext& rStyles ) : + SvXMLStyleContext( rImport ), + pData( pNewData ), + pStyles( &rStyles ), + nType( nNewType ), + nKey(-1), + eImplicitCalendar(ImplicitCalendar::DEFAULT), + nFormatLang( LANGUAGE_SYSTEM ), + bAutoOrder( false ), + bFromSystem( false ), + bTruncate( true ), + bAutoDec( false ), + bAutoInt( false ), + bHasExtraText( false ), + bHasTrailingEmptyText( false ), + bHasLongDoW( false ), + bHasDateTime( false ), + bRemoveAfterUse( false ), + eDateDOW( XML_DEA_NONE ), + eDateDay( XML_DEA_NONE ), + eDateMonth( XML_DEA_NONE ), + eDateYear( XML_DEA_NONE ), + eDateHours( XML_DEA_NONE ), + eDateMins( XML_DEA_NONE ), + eDateSecs( XML_DEA_NONE ), + bDateNoDefault( false ) +{ + LanguageTagODF aLanguageTagODF; + css::i18n::NativeNumberXmlAttributes aNatNumAttr; + OUString aSpellout; + bool bAttrBool(false); + + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + switch (aIter.getToken()) + { + // attributes for a style + case XML_ELEMENT(STYLE, XML_NAME): + break; + case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG): + aLanguageTagODF.maRfcLanguageTag = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_LANGUAGE): + aLanguageTagODF.maLanguage = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_SCRIPT): + aLanguageTagODF.maScript = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_COUNTRY): + aLanguageTagODF.maCountry = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_TITLE): + sFormatTitle = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_AUTOMATIC_ORDER): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + bAutoOrder = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_FORMAT_SOURCE): + SvXMLUnitConverter::convertEnum( bFromSystem, aIter.toView(), aFormatSourceMap ); + break; + case XML_ELEMENT(NUMBER, XML_TRUNCATE_ON_OVERFLOW): + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + bTruncate = bAttrBool; + break; + case XML_ELEMENT(STYLE, XML_VOLATILE): + // volatile formats can be removed after importing + // if not used in other styles + if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) + bRemoveAfterUse = bAttrBool; + break; + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_FORMAT): + aNatNumAttr.Format = aIter.toString(); + break; + case XML_ELEMENT(LO_EXT, XML_TRANSLITERATION_SPELLOUT): + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_SPELLOUT): + aSpellout = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_LANGUAGE): + aNatNumAttr.Locale.Language = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_COUNTRY): + aNatNumAttr.Locale.Country = aIter.toString(); + break; + case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_STYLE): + aNatNumAttr.Style = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if (!aLanguageTagODF.isEmpty()) + { + nFormatLang = aLanguageTagODF.getLanguageTag().getLanguageType( false); + if ( nFormatLang == LANGUAGE_DONTKNOW ) + nFormatLang = LANGUAGE_SYSTEM; //! error handling for unknown locales? + } + + if (aNatNumAttr.Format.isEmpty() && aSpellout.isEmpty()) + return; + + LanguageTag aLanguageTag( OUString(), aNatNumAttr.Locale.Language, + std::u16string_view(), aNatNumAttr.Locale.Country); + aNatNumAttr.Locale = aLanguageTag.getLocale( false); + + // NatNum12 spell out formula (cardinal, ordinal, ordinal-feminine etc.) + if ( !aSpellout.isEmpty() ) + { + aFormatCode.append( "[NatNum12 " ); + aFormatCode.append( aSpellout ); + } else { + SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); + if ( !pFormatter ) return; + + sal_Int32 nNatNum = pFormatter->GetNatNum()->convertFromXmlAttributes( aNatNumAttr ); + aFormatCode.append( "[NatNum" ); + aFormatCode.append( nNatNum ); + } + + LanguageType eLang = aLanguageTag.getLanguageType( false ); + if ( eLang == LANGUAGE_DONTKNOW ) + eLang = LANGUAGE_SYSTEM; //! error handling for unknown locales? + if ( eLang != nFormatLang && eLang != LANGUAGE_SYSTEM ) + { + aFormatCode.append( "][$-" ); + // language code in upper hex: + aFormatCode.append(OUString::number(static_cast(eLang), 16).toAsciiUpperCase()); + } + aFormatCode.append( ']' ); +} + +SvXMLNumFormatContext::SvXMLNumFormatContext( SvXMLImport& rImport, + const OUString& rName, + const uno::Reference& /*xAttrList*/, + const sal_Int32 nTempKey, LanguageType nLang, + SvXMLStylesContext& rStyles ) : + SvXMLStyleContext( rImport, XmlStyleFamily::DATA_STYLE ), + pData( nullptr ), + pStyles( &rStyles ), + nType( SvXMLStylesTokens::NUMBER_STYLE ), + nKey(nTempKey), + eImplicitCalendar(ImplicitCalendar::DEFAULT), + nFormatLang( nLang ), + bAutoOrder( false ), + bFromSystem( false ), + bTruncate( true ), + bAutoDec( false ), + bAutoInt( false ), + bHasExtraText( false ), + bHasTrailingEmptyText( false ), + bHasLongDoW( false ), + bHasDateTime( false ), + bRemoveAfterUse( false ), + eDateDOW( XML_DEA_NONE ), + eDateDay( XML_DEA_NONE ), + eDateMonth( XML_DEA_NONE ), + eDateYear( XML_DEA_NONE ), + eDateHours( XML_DEA_NONE ), + eDateMins( XML_DEA_NONE ), + eDateSecs( XML_DEA_NONE ), + bDateNoDefault( false ) +{ + SetAttribute(XML_ELEMENT(STYLE, XML_NAME), rName); +} + +SvXMLNumFormatContext::~SvXMLNumFormatContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFormatContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext* pContext = nullptr; + + switch (nElement) + { + case XML_ELEMENT(LO_EXT, XML_TEXT): + case XML_ELEMENT(NUMBER, XML_TEXT): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Text, xAttrList ); + break; + case XML_ELEMENT(LO_EXT, XML_FILL_CHARACTER): + case XML_ELEMENT(NUMBER, XML_FILL_CHARACTER): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::FillCharacter, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_NUMBER): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Number, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_SCIENTIFIC_NUMBER): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::ScientificNumber, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_FRACTION): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Fraction, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_CURRENCY_SYMBOL): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::CurrencySymbol, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_DAY): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Day, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_MONTH): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Month, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_YEAR): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Year, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_ERA): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Era, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_DAY_OF_WEEK): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::DayOfWeek, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_WEEK_OF_YEAR): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::WeekOfYear, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_QUARTER): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Quarter, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_HOURS): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Hours, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_AM_PM): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::AmPm, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_MINUTES): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Minutes, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_SECONDS): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Seconds, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_BOOLEAN): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::Boolean, xAttrList ); + break; + case XML_ELEMENT(NUMBER, XML_TEXT_CONTENT): + pContext = new SvXMLNumFmtElementContext( GetImport(), nElement, + *this, SvXMLStyleTokens::TextContent, xAttrList ); + break; + + case XML_ELEMENT(STYLE, XML_TEXT_PROPERTIES): + pContext = new SvXMLNumFmtPropContext( GetImport(), nElement, + *this, xAttrList ); + break; + case XML_ELEMENT(STYLE, XML_MAP): + { + // SvXMLNumFmtMapContext::EndElement adds to aMyConditions, + // so there's no need for an extra flag + pContext = new SvXMLNumFmtMapContext( GetImport(), nElement, + *this, xAttrList ); + } + break; + } + + if( !pContext ) + { + SAL_WARN("xmloff.core", "No context for unknown-element " << SvXMLImport::getPrefixAndNameFromToken(nElement)); + pContext = new SvXMLImportContext(GetImport()); + } + + return pContext; +} + +sal_Int32 SvXMLNumFormatContext::GetKey() +{ + if (nKey > -1) + { + if (bRemoveAfterUse) + { + // format is used -> don't remove + bRemoveAfterUse = false; + if (pData) + pData->SetUsed(nKey); + + // Add to import's list of keys now - CreateAndInsert didn't add + // the style if bRemoveAfterUse was set. + GetImport().AddNumberStyle( nKey, GetName() ); + } + return nKey; + } + else + { + // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set + bRemoveAfterUse = false; + CreateAndInsert(true); + return nKey; + } +} + +sal_Int32 SvXMLNumFormatContext::PrivateGetKey() +{ + // used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag + + if (nKey > -1) + return nKey; + else + { + CreateAndInsert(true); + return nKey; + } +} + +sal_Int32 SvXMLNumFormatContext::CreateAndInsert( css::uno::Reference< css::util::XNumberFormatsSupplier > const & xFormatsSupplier ) +{ + if (nKey <= -1) + { + SvNumberFormatter* pFormatter = nullptr; + SvNumberFormatsSupplierObj* pObj = + comphelper::getFromUnoTunnel( xFormatsSupplier ); + if (pObj) + pFormatter = pObj->GetNumberFormatter(); + + if ( pFormatter ) + return CreateAndInsert( pFormatter ); + else + return -1; + } + else + return nKey; +} + +void SvXMLNumFormatContext::CreateAndInsert(bool /*bOverwrite*/) +{ + if (nKey <= -1) + CreateAndInsert(pData->GetNumberFormatter()); +} + +sal_Int32 SvXMLNumFormatContext::CreateAndInsert(SvNumberFormatter* pFormatter) +{ + if (!pFormatter) + { + OSL_FAIL("no number formatter"); + return -1; + } + + sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND; + + for (size_t i = 0; i < aMyConditions.size(); i++) + { + SvXMLNumFormatContext* pStyle = const_cast( static_cast(pStyles->FindStyleChildContext( + XmlStyleFamily::DATA_STYLE, aMyConditions[i].sMapName))); + if (this == pStyle) + { + SAL_INFO("xmloff.style", "invalid style:map references containing style"); + pStyle = nullptr; + } + if (pStyle) + { + if (pStyle->PrivateGetKey() > -1) // don't reset pStyle's bRemoveAfterUse flag + AddCondition(i); + } + } + + sal_Int32 nBufLen; + if ( aFormatCode.isEmpty() ) + { + // insert empty format as empty string (with quotes) + // #93901# this check has to be done before inserting the conditions + aFormatCode.append("\"\""); // "" + } + else if (bHasTrailingEmptyText && (nBufLen = aFormatCode.getLength()) >= 3) + { + // Remove a trailing empty text. Earlier this may had been written to + // file, like in "General;General" written with elements for + // 'General"";General""' (whyever); when reading, empty text was + // ignored, which it isn't anymore, so get rid of those. + if (aFormatCode[nBufLen-1] == '"' && aFormatCode[nBufLen-2] == '"') + aFormatCode.truncate( nBufLen - 2); + } + + aFormatCode.insert( 0, aConditions ); + aConditions.setLength(0); + OUString sFormat = aFormatCode.makeStringAndClear(); + + // test special cases + + if ( bAutoDec ) // automatic decimal places + { + // #99391# adjust only if the format contains no text elements, no conditions + // and no color definition (detected by the '[' at the start) + + if ( nType == SvXMLStylesTokens::NUMBER_STYLE && !bHasExtraText && + aMyConditions.empty() && sFormat.toChar() != '[' ) + nIndex = pFormatter->GetStandardIndex( nFormatLang ); + } + if ( bAutoInt ) // automatic integer digits + { + //! only if two decimal places was set? + + if ( nType == SvXMLStylesTokens::NUMBER_STYLE && !bHasExtraText && + aMyConditions.empty() && sFormat.toChar() != '[' ) + nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, nFormatLang ); + } + + if ( nType == SvXMLStylesTokens::BOOLEAN_STYLE && !bHasExtraText && + aMyConditions.empty() && sFormat.toChar() != '[' ) + nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang ); + + // check for default date formats + if ( nType == SvXMLStylesTokens::DATE_STYLE && bAutoOrder && !bDateNoDefault ) + { + NfIndexTableOffset eFormat = static_cast(SvXMLNumFmtDefaults::GetDefaultDateFormat( + eDateDOW, eDateDay, eDateMonth, eDateYear, + eDateHours, eDateMins, eDateSecs, bFromSystem )); + if ( eFormat < NF_INDEX_TABLE_RESERVED_START ) + { + // #109651# if a date format has the automatic-order attribute and + // contains exactly the elements of one of the default date formats, + // use that default format, with the element order and separators + // from the current locale settings + + nIndex = pFormatter->GetFormatIndex( eFormat, nFormatLang ); + } + } + + if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && !sFormat.isEmpty() ) + { + // insert by format string + + OUString aFormatStr( sFormat ); + nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang ); + if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { + sal_Int32 nErrPos = 0; + SvNumFormatType l_nType = SvNumFormatType::ALL; + bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, nFormatLang ); + if ( !bOk && nErrPos == 0 && aFormatStr != sFormat ) + { + // if the string was modified by PutEntry, look for an existing format + // with the modified string + nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang ); + if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND ) + bOk = true; + } + if (!bOk) + nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND; + } + } + +//! I18N doesn't provide SYSTEM or extended date information yet + if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !bAutoOrder ) + { + // use fixed-order formats instead of SYS... if bAutoOrder is false + // (only if the format strings are equal for the locale) + + NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex ); + if ( eOffset == NF_DATE_SYS_DMMMYYYY ) + { + sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, nFormatLang ); + const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex ); + const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex ); + if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() ) + nIndex = nNewIndex; + } + else if ( eOffset == NF_DATE_SYS_DMMMMYYYY ) + { + sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, nFormatLang ); + const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex ); + const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex ); + if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() ) + nIndex = nNewIndex; + } + } + + if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && !sFormatTitle.isEmpty()) + { + SvNumberformat* pFormat = const_cast(pFormatter->GetEntry( nIndex )); + if (pFormat) + { + pFormat->SetComment(sFormatTitle); + } + } + + if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND ) + { + OSL_FAIL("invalid number format"); + nIndex = pFormatter->GetStandardIndex( nFormatLang ); + } + + pData->AddKey( nIndex, GetName(), bRemoveAfterUse ); + nKey = nIndex; + + // Add to import's list of keys (shared between styles and content import) + // only if not volatile - formats are removed from NumberFormatter at the + // end of each import (in SvXMLNumFmtHelper dtor). + // If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there. + + if (!bRemoveAfterUse) + GetImport().AddNumberStyle( nKey, GetName() ); + + return nKey; +} + +const LocaleDataWrapper& SvXMLNumFormatContext::GetLocaleData() const +{ + return pData->GetLocaleData( nFormatLang ); +} + +void SvXMLNumFormatContext::AddToCode( sal_Unicode c ) +{ + aFormatCode.append( c ); + bHasExtraText = true; +} + +void SvXMLNumFormatContext::AddToCode( std::u16string_view rString ) +{ + aFormatCode.append( rString ); + bHasExtraText = true; + bHasTrailingEmptyText = false; // is set by caller again if so +} + +void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) +{ + SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); + if (!pFormatter) + return; + + // store special conditions + bAutoDec = ( rInfo.nDecimals < 0 ); + bAutoInt = ( rInfo.nInteger < 0 ); + + sal_uInt16 nPrec = 0; + sal_uInt16 nLeading = 0; + if ( rInfo.nDecimals >= 0 ) // < 0 : Default + nPrec = static_cast(rInfo.nDecimals); + if ( rInfo.nInteger >= 0 ) // < 0 : Default + nLeading = static_cast(rInfo.nInteger); + + if ( bAutoDec ) + { + if ( nType == SvXMLStylesTokens::CURRENCY_STYLE ) + { + // for currency formats, "automatic decimals" is used for the automatic + // currency format with (fixed) decimals from the locale settings + + const LocaleDataWrapper& rLoc = pData->GetLocaleData( nFormatLang ); + nPrec = rLoc.getCurrDigits(); + } + else + { + // for other types, "automatic decimals" means dynamic determination of + // decimals, as achieved with the "general" keyword + + aFormatCode.append( pFormatter->GetStandardName( nFormatLang ) ); + return; + } + } + if ( bAutoInt ) + { + //!... + } + + sal_uInt16 nGenPrec = nPrec; + if ( rInfo.nMinDecimalDigits >= 0 ) + nGenPrec = rInfo.nMinDecimalDigits; + if ( rInfo.bDecReplace ) + nGenPrec = 0; // generate format without decimals... + + bool bGrouping = rInfo.bGrouping; + size_t const nEmbeddedCount = rInfo.m_EmbeddedElements.size(); + if ( nEmbeddedCount && rInfo.m_EmbeddedElements.rbegin()->first > 0 ) + bGrouping = false; // grouping and embedded characters in integer part can't be used together + + sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang ); + OUStringBuffer aNumStr(pFormatter->GenerateFormat( nStdIndex, nFormatLang, + bGrouping, false, nGenPrec, nLeading )); + + if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 ) + { + // #i43959# For scientific numbers, "#" in the integer part forces a digit, + // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0"). + + aNumStr.stripStart('#'); + } + + if ( bGrouping && rInfo.nExpInterval > rInfo.nInteger ) + { + sal_Int32 nIndex = 0; + sal_Int32 nDigits = rInfo.nInteger; + sal_Int32 nIntegerEnd = aNumStr.indexOf( pFormatter->GetNumDecimalSep() ); + if ( nIntegerEnd < 0 ) + nIntegerEnd = aNumStr.getLength(); + while ( nIndex >= 0 && nIndex < nIntegerEnd ) + { + if ( ( nIndex = aNumStr.indexOf( '#', nIndex ) ) >= 0 ) + { + nDigits ++; + nIndex ++; + } + else + nIndex = -1; + } + while ( rInfo.nExpInterval > nDigits ) + { + nDigits++; + aNumStr.insert( 0, '#' ); + } + } + + if ( ( rInfo.bDecReplace || rInfo.nMinDecimalDigits < rInfo.nDecimals ) && nPrec ) // add decimal replacement (dashes) + { + // add dashes for explicit decimal replacement, # or ? for variable decimals + sal_Unicode cAdd = rInfo.bDecReplace ? '-' : ( rInfo.bDecAlign ? '?': '#' ); + + if ( rInfo.nMinDecimalDigits == 0 ) + aNumStr.append( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); + for ( sal_uInt16 i=rInfo.nMinDecimalDigits; i=0) and decimal (position <0) part + // nZeroPos is the string position where format position 0 is inserted + + sal_Int32 nZeroPos = aNumStr.indexOf( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() ); + if ( nZeroPos < 0 ) + { + nZeroPos = aNumStr.getLength(); + } + + // m_EmbeddedElements is sorted - last entry has the largest position (leftmost) + sal_Int32 const nLastFormatPos = rInfo.m_EmbeddedElements.rbegin()->first; + if ( nLastFormatPos >= nZeroPos ) + { + // add '#' characters so all embedded texts are really embedded in digits + // (there always has to be a digit before the leftmost embedded text) + + sal_Int32 nAddCount = nLastFormatPos + 1 - nZeroPos; + for(sal_Int32 index = 0; index < nAddCount; ++index) + { + aNumStr.insert(0, '#'); + } + nZeroPos = nZeroPos + nAddCount; + } + + // m_EmbeddedElements is sorted with ascending positions - loop is from right to left + for (auto const& it : rInfo.m_EmbeddedElements) + { + sal_Int32 const nFormatPos = it.first; + sal_Int32 nInsertPos = nZeroPos - nFormatPos; + if ( nInsertPos >= 0 ) + { + // #107805# always quote embedded strings - even space would otherwise + // be recognized as thousands separator in French. + + aNumStr.insert(nInsertPos, '"'); + aNumStr.insert(nInsertPos, it.second); + aNumStr.insert(nInsertPos, '"'); + } + } + } + + aFormatCode.append( aNumStr ); + + // add extra thousands separators for display factor + + if (rInfo.fDisplayFactor == 1.0 || rInfo.fDisplayFactor <= 0.0) + return; + + // test for 1.0 is just for optimization - nSepCount would be 0 + + // one separator for each factor of 1000 + sal_Int32 nSepCount = static_cast(::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 )); + if ( nSepCount > 0 ) + { + OUString aSep = pData->GetLocaleData( nFormatLang ).getNumThousandSep(); + for ( sal_Int32 i=0; iGetNumberFormatter(); + if ( pFormatter ) + { + pFormatter->ChangeIntl( nFormatLang ); + OUString sCurString, sDummy; + pFormatter->GetCompatibilityCurrency( sCurString, sDummy ); + aSymbol = sCurString; + + bAutomatic = true; + } + } + else if ( nLang == LANGUAGE_SYSTEM && aSymbol == "CCC" ) + { + // "CCC" is used for automatic long symbol + bAutomatic = true; + } + + if ( bAutomatic ) + { + // remove unnecessary quotes before automatic symbol (formats like "-(0DM)") + // otherwise the currency symbol isn't recognized (#94048#) + + sal_Int32 nLength = aFormatCode.getLength(); + if ( nLength > 1 && aFormatCode[nLength - 1] == '"' ) + { + // find start of quoted string + // When SvXMLNumFmtElementContext::EndElement creates escaped quotes, + // they must be handled here, too. + + sal_Int32 nFirst = nLength - 2; + while ( nFirst >= 0 && aFormatCode[nFirst] != '"' ) + --nFirst; + if ( nFirst >= 0 ) + { + // remove both quotes from aFormatCode + OUString aOld = aFormatCode.makeStringAndClear(); + if ( nFirst > 0 ) + aFormatCode.append( aOld.subView( 0, nFirst ) ); + if ( nLength > nFirst + 2 ) + aFormatCode.append( aOld.subView( nFirst + 1, nLength - nFirst - 2 ) ); + } + } + } + + if (!bAutomatic) + aFormatCode.append( "[$" ); // intro for "new" currency symbols + + aFormatCode.append( aSymbol ); + + if (!bAutomatic) + { + if ( nLang != LANGUAGE_SYSTEM ) + { + // '-' sign and language code in hex: + aFormatCode.append("-" + OUString(OUString::number(sal_uInt16(nLang), 16)).toAsciiUpperCase()); + } + + aFormatCode.append( ']' ); // end of "new" currency symbol + } +} + +void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex ) +{ + SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); + if (!pFormatter) + return; + + if ( nIndex == NF_KEY_NNNN ) + { + nIndex = NF_KEY_NNN; + bHasLongDoW = true; // to remove string constant with separator + } + + OUString sKeyword = pFormatter->GetKeyword( nFormatLang, nIndex ); + + if ( nIndex == NF_KEY_H || nIndex == NF_KEY_HH || + nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI || + nIndex == NF_KEY_S || nIndex == NF_KEY_SS ) + { + if ( !bTruncate && !bHasDateTime ) + { + // with truncate-on-overflow = false, add "[]" to first time part + aFormatCode.append("[" + sKeyword + "]"); + } + else + { + aFormatCode.append( sKeyword ); + } + bHasDateTime = true; + } + else + { + aFormatCode.append( sKeyword ); + } + // collect the date elements that the format contains, to recognize default date formats + switch ( nIndex ) + { + case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break; + case NF_KEY_NNN: + case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break; + case NF_KEY_D: eDateDay = XML_DEA_SHORT; break; + case NF_KEY_DD: eDateDay = XML_DEA_LONG; break; + case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break; + case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break; + case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break; + case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break; + case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break; + case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break; + case NF_KEY_H: eDateHours = XML_DEA_SHORT; break; + case NF_KEY_HH: eDateHours = XML_DEA_LONG; break; + case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break; + case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break; + case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break; + case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break; + case NF_KEY_AP: + case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself + default: + bDateNoDefault = true; // any other element -> no default format + } +} + +static bool lcl_IsAtEnd( OUStringBuffer& rBuffer, const OUString& rToken ) +{ + sal_Int32 nBufLen = rBuffer.getLength(); + sal_Int32 nTokLen = rToken.getLength(); + + if ( nTokLen > nBufLen ) + return false; + + sal_Int32 nStartPos = nBufLen - nTokLen; + for ( sal_Int32 nTokPos = 0; nTokPos < nTokLen; nTokPos++ ) + if ( rToken[ nTokPos ] != rBuffer[nStartPos + nTokPos] ) + return false; + + return true; +} + +bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew ) +{ + // replaces one keyword with another if it is found at the end of the code + + SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); + if (!pFormatter) + return false; + + OUString sOldStr = pFormatter->GetKeyword( nFormatLang, nOld ); + if ( lcl_IsAtEnd( aFormatCode, sOldStr ) ) + { + // remove old keyword + aFormatCode.setLength( aFormatCode.getLength() - sOldStr.getLength() ); + + // add new keyword + OUString sNewStr = pFormatter->GetKeyword( nFormatLang, nNew ); + aFormatCode.append( sNewStr ); + + return true; // changed + } + return false; // not found +} + +void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex ) +{ + OUString rApplyName = aMyConditions[nIndex].sMapName; + OUString rCondition = aMyConditions[nIndex].sCondition; + SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); + sal_uInt32 l_nKey = pData->GetKeyForName( rApplyName ); + + OUString sRealCond; + if ( !(pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND && + rCondition.startsWith("value()", &sRealCond)) ) + return; + + //! test for valid conditions + //! test for default conditions + + bool bDefaultCond = false; + + //! collect all conditions first and adjust default to >=0, >0 or <0 depending on count + //! allow blanks in conditions + if ( aConditions.isEmpty() && aMyConditions.size() == 1 && sRealCond == ">=0" ) + bDefaultCond = true; + + if ( nType == SvXMLStylesTokens::TEXT_STYLE && static_cast(nIndex) == aMyConditions.size() - 1 ) + { + // The last condition in a number format with a text part can only + // be "all other numbers", the condition string must be empty. + bDefaultCond = true; + } + + if (!bDefaultCond) + { + // Convert != to <> + sal_Int32 nPos = sRealCond.indexOf( "!=" ); + if ( nPos >= 0 ) + { + sRealCond = sRealCond.replaceAt( nPos, 2, u"<>" ); + } + + nPos = sRealCond.indexOf( '.' ); + if ( nPos >= 0 ) + { + // #i8026# #103991# localize decimal separator + const OUString& rDecSep = GetLocaleData().getNumDecimalSep(); + if ( rDecSep.getLength() > 1 || rDecSep[0] != '.' ) + { + sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep ); + } + } + aConditions.append("[" + sRealCond + "]"); + } + + const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey); + if ( pFormat ) + aConditions.append( pFormat->GetFormatstring() ); + + aConditions.append( ';' ); +} + +void SvXMLNumFormatContext::AddCondition( const OUString& rCondition, const OUString& rApplyName ) +{ + MyCondition aCondition; + aCondition.sCondition = rCondition; + aCondition.sMapName = rApplyName; + aMyConditions.push_back(aCondition); +} + +void SvXMLNumFormatContext::AddColor( Color const nColor ) +{ + SvNumberFormatter* pFormatter = pData->GetNumberFormatter(); + if (!pFormatter) + return; + + OUStringBuffer aColName; + for ( sal_uInt16 i=0; iGetKeyword( nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) ); + break; + } + + if ( !aColName.isEmpty() ) + { + aColName.insert( 0, '[' ); + aColName.append( ']' ); + aFormatCode.insert( 0, aColName ); + } +} + +void SvXMLNumFormatContext::UpdateCalendar( const OUString& rNewCalendar ) +{ + if ( rNewCalendar == sCalendar ) + return; + + if (rNewCalendar.isEmpty() || rNewCalendar == aImplicitCalendar[0]) + { + eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ? + ImplicitCalendar::DEFAULT_FROM_OTHER : ImplicitCalendar::DEFAULT); + } + else if (aImplicitCalendar[0].isEmpty() && rNewCalendar == GetLocaleData().getDefaultCalendar()->Name) + { + eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ? + ImplicitCalendar::DEFAULT_FROM_OTHER : ImplicitCalendar::DEFAULT); + aImplicitCalendar[0] = rNewCalendar; + } + else if (rNewCalendar == aImplicitCalendar[1]) + { + eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ? + ImplicitCalendar::SECONDARY_FROM_OTHER : ImplicitCalendar::SECONDARY); + } + else if (aImplicitCalendar[1].isEmpty() && GetLocaleData().doesSecondaryCalendarUseEC( rNewCalendar)) + { + eImplicitCalendar = (eImplicitCalendar == ImplicitCalendar::OTHER ? + ImplicitCalendar::SECONDARY_FROM_OTHER : ImplicitCalendar::SECONDARY); + aImplicitCalendar[1] = rNewCalendar; + } + else + { + eImplicitCalendar = ImplicitCalendar::OTHER; + } + + if (eImplicitCalendar != ImplicitCalendar::DEFAULT && eImplicitCalendar != ImplicitCalendar::SECONDARY) + { + // A switch from empty default calendar to named default calendar or + // vice versa is not a switch. + bool bSameDefault = false; + if (sCalendar.isEmpty() || rNewCalendar.isEmpty()) + { + // As both are not equal, only one can be empty here, the other + // can not. + const OUString& rDefaultCalendar = GetLocaleData().getDefaultCalendar()->Name; + // So if one is the named default calendar the other is the + // empty default calendar. + bSameDefault = (rNewCalendar == rDefaultCalendar || sCalendar == rDefaultCalendar); + } + if (!bSameDefault) + { + aFormatCode.append( "[~" ); // intro for calendar code + if (rNewCalendar.isEmpty()) + { + // Empty calendar name here means switching to default calendar + // from a different calendar. Needs to be explicitly stated in + // format code. + aFormatCode.append( GetLocaleData().getDefaultCalendar()->Name ); + } + else + { + aFormatCode.append( rNewCalendar ); + } + aFormatCode.append( ']' ); // end of calendar code + } + } + sCalendar = rNewCalendar; +} + +bool SvXMLNumFormatContext::IsSystemLanguage() const +{ + return nFormatLang == LANGUAGE_SYSTEM; +} + + +// SvXMLNumFmtHelper + + +SvXMLNumFmtHelper::SvXMLNumFmtHelper( + const uno::Reference& rSupp, + const uno::Reference& rxContext ) +{ + SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" ); + + SvNumberFormatter* pFormatter = nullptr; + SvNumberFormatsSupplierObj* pObj = + comphelper::getFromUnoTunnel( rSupp ); + if (pObj) + pFormatter = pObj->GetNumberFormatter(); + + pData = std::make_unique( pFormatter, rxContext ); +} + +SvXMLNumFmtHelper::SvXMLNumFmtHelper( + SvNumberFormatter* pNumberFormatter, + const uno::Reference& rxContext ) +{ + SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" ); + + pData = std::make_unique( pNumberFormatter, rxContext ); +} + +SvXMLNumFmtHelper::~SvXMLNumFmtHelper() +{ + // remove temporary (volatile) formats from NumberFormatter + pData->RemoveVolatileFormats(); +} + + +SvXMLStyleContext* SvXMLNumFmtHelper::CreateChildContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + SvXMLStylesContext& rStyles ) +{ + SvXMLStylesTokens nStyleToken; + switch (nElement) + { + case XML_ELEMENT(NUMBER, XML_NUMBER_STYLE): + nStyleToken = SvXMLStylesTokens::NUMBER_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_CURRENCY_STYLE): + nStyleToken = SvXMLStylesTokens::CURRENCY_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_PERCENTAGE_STYLE): + nStyleToken = SvXMLStylesTokens::PERCENTAGE_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_DATE_STYLE): + nStyleToken = SvXMLStylesTokens::DATE_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_TIME_STYLE): + nStyleToken = SvXMLStylesTokens::TIME_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_BOOLEAN_STYLE): + nStyleToken = SvXMLStylesTokens::BOOLEAN_STYLE; + break; + case XML_ELEMENT(NUMBER, XML_TEXT_STYLE): + nStyleToken = SvXMLStylesTokens::TEXT_STYLE; + break; + default: + // return NULL if not a data style, caller must handle other elements + return nullptr; + } + return new SvXMLNumFormatContext( rImport, nElement, + pData.get(), nStyleToken, xAttrList, rStyles ); +} + +LanguageType SvXMLNumFmtHelper::GetLanguageForKey(sal_Int32 nKey) const +{ + if (pData->GetNumberFormatter()) + { + const SvNumberformat* pEntry = pData->GetNumberFormatter()->GetEntry(nKey); + if (pEntry) + return pEntry->GetLanguage(); + } + + return LANGUAGE_SYSTEM; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlnumi.cxx b/xmloff/source/style/xmlnumi.cxx new file mode 100644 index 000000000..78fba23d0 --- /dev/null +++ b/xmloff/source/style/xmlnumi.cxx @@ -0,0 +1,1081 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include "fonthdl.hxx" +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::frame; +using namespace ::xmloff::token; +using namespace ::com::sun::star::io; + +class SvxXMLListLevelStyleContext_Impl; + +namespace { + +class SvxXMLListLevelStyleAttrContext_Impl : public SvXMLImportContext +{ + SvxXMLListLevelStyleContext_Impl& rListLevel; + +public: + + SvxXMLListLevelStyleAttrContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList >& xAttrList, + SvxXMLListLevelStyleContext_Impl& rLLevel ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +class SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl : public SvXMLImportContext +{ +public: + + SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList >& xAttrList, + SvxXMLListLevelStyleContext_Impl& rLLevel ); +}; + +} + +class SvxXMLListLevelStyleContext_Impl : public SvXMLImportContext +{ + friend SvxXMLListLevelStyleAttrContext_Impl; + + OUString sPrefix; + OUString sSuffix; + std::optional sListFormat; // It is optional to distinguish empty format string + // from not existing format string in old docs + OUString sTextStyleName; + OUString sNumFormat; + OUString sNumLetterSync; + OUString sBulletFontName; + OUString sBulletFontStyleName; + OUString sImageURL; + + Reference < XOutputStream > xBase64Stream; + + sal_Int32 nLevel; + sal_Int32 nSpaceBefore; + sal_Int32 nMinLabelWidth; + sal_Int32 nMinLabelDist; + sal_Int32 nImageWidth; + sal_Int32 nImageHeight; + sal_Int16 nNumStartValue; + sal_Int16 nNumDisplayLevels; + + sal_Int16 eAdjust; + sal_Int16 eBulletFontFamily; + sal_Int16 eBulletFontPitch; + rtl_TextEncoding eBulletFontEncoding; + sal_Int16 eImageVertOrient; + + sal_UCS4 cBullet; + + sal_Int16 nRelSize; + Color m_nColor; + + sal_Int16 ePosAndSpaceMode; + sal_Int16 eLabelFollowedBy; + sal_Int32 nListtabStopPosition; + sal_Int32 nFirstLineIndent; + sal_Int32 nIndentAt; + + bool bBullet : 1; + bool bImage : 1; + bool bNum : 1; + bool bHasColor : 1; + + void SetRelSize( sal_Int16 nRel ) { nRelSize = nRel; } + void SetColor( Color nColor ) + { m_nColor = nColor; bHasColor = true; } + void SetSpaceBefore( sal_Int32 nSet ) { nSpaceBefore = nSet; } + void SetMinLabelWidth( sal_Int32 nSet ) { nMinLabelWidth = nSet; } + void SetMinLabelDist( sal_Int32 nSet ) { nMinLabelDist = nSet; } + void SetAdjust( sal_Int16 eSet ) { eAdjust = eSet; } + + void SetBulletFontName( const OUString& rSet ) { sBulletFontName = rSet; } + void SetBulletFontStyleName( const OUString& rSet ) + { sBulletFontStyleName = rSet; } + void SetBulletFontFamily( sal_Int16 eSet ) { eBulletFontFamily = eSet; } + void SetBulletFontPitch( sal_Int16 eSet ) { eBulletFontPitch = eSet; } + void SetBulletFontEncoding( rtl_TextEncoding eSet ) + { eBulletFontEncoding = eSet; } + + void SetImageWidth( sal_Int32 nSet ) { nImageWidth = nSet; } + void SetImageHeight( sal_Int32 nSet ) { nImageHeight = nSet; } + void SetImageVertOrient( sal_Int16 eSet ) + { eImageVertOrient = eSet; } + +public: + + SvxXMLListLevelStyleContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + sal_Int32 GetLevel() const { return nLevel; } + Sequence GetProperties(); + + void SetPosAndSpaceMode( sal_Int16 eValue ) + { + ePosAndSpaceMode = eValue; + } + void SetLabelFollowedBy( sal_Int16 eValue ) + { + eLabelFollowedBy = eValue; + } + void SetListtabStopPosition( sal_Int32 nValue ) + { + nListtabStopPosition = nValue; + } + void SetFirstLineIndent( sal_Int32 nValue ) + { + nFirstLineIndent = nValue; + } + void SetIndentAt( sal_Int32 nValue ) + { + nIndentAt = nValue; + } +}; + +constexpr OUStringLiteral gsStarBats( u"StarBats" ); +constexpr OUStringLiteral gsStarMath( u"StarMath" ); + +SvxXMLListLevelStyleContext_Impl::SvxXMLListLevelStyleContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList ) + +: SvXMLImportContext( rImport ) +, sNumFormat( "1" ) +, nLevel( -1 ) +, nSpaceBefore( 0 ) +, nMinLabelWidth( 0 ) +, nMinLabelDist( 0 ) +, nImageWidth( 0 ) +, nImageHeight( 0 ) +, nNumStartValue( 1 ) +, nNumDisplayLevels( 1 ) +, eAdjust( HoriOrientation::LEFT ) +, eBulletFontFamily( FAMILY_DONTKNOW ) +, eBulletFontPitch( PITCH_DONTKNOW ) +, eBulletFontEncoding( RTL_TEXTENCODING_DONTKNOW ) +, eImageVertOrient(0) +, cBullet( 0 ) +, nRelSize(0) +, m_nColor(0) +, ePosAndSpaceMode( PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION ) +, eLabelFollowedBy( LabelFollow::LISTTAB ) +, nListtabStopPosition( 0 ) +, nFirstLineIndent( 0 ) +, nIndentAt( 0 ) +, bBullet( false ) +, bImage( false ) +, bNum( false ) +, bHasColor( false ) +{ + switch (nElement & TOKEN_MASK) + { + case XML_LIST_LEVEL_STYLE_NUMBER: + case XML_OUTLINE_LEVEL_STYLE: + bNum = true; + break; + case XML_LIST_LEVEL_STYLE_BULLET: + bBullet = true; + break; + case XML_LIST_LEVEL_STYLE_IMAGE: + bImage = true; + break; + } + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(TEXT, XML_LEVEL): + nLevel = aIter.toInt32(); + if( nLevel >= 1 ) + nLevel--; + else + nLevel = 0; + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + sTextStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_BULLET_CHAR): + if (!aIter.isEmpty()) + { + cBullet = aIter.toString().iterateCodePoints(&o3tl::temporary(sal_Int32(0))); + } + break; + case XML_ELEMENT(XLINK, XML_HREF): + if( bImage ) + sImageURL = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_TYPE): + case XML_ELEMENT(XLINK, XML_SHOW): + case XML_ELEMENT(XLINK, XML_ACTUATE): + // This properties will be ignored + break; + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + if( bNum ) + sNumFormat = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_NUM_PREFIX): + sPrefix = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_NUM_SUFFIX): + sSuffix = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_NUM_LIST_FORMAT): + case XML_ELEMENT(LO_EXT, XML_NUM_LIST_FORMAT): + sListFormat = std::make_optional(aIter.toString()); + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + if( bNum ) + sNumLetterSync = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_START_VALUE): + if( bNum ) + { + sal_Int32 nTmp = aIter.toInt32(); + nNumStartValue = + (nTmp < 0) ? 1 : ( (nTmp>SHRT_MAX) ? SHRT_MAX + : static_cast(nTmp) ); + } + break; + case XML_ELEMENT(TEXT, XML_DISPLAY_LEVELS): + if( bNum ) + { + sal_Int32 nTmp = aIter.toInt32(); + nNumDisplayLevels = + (nTmp < 1) ? 1 : ( (nTmp>SHRT_MAX) ? SHRT_MAX + : static_cast(nTmp) ); + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLListLevelStyleContext_Impl::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_LIST_LEVEL_PROPERTIES) || + nElement == XML_ELEMENT(STYLE, XML_TEXT_PROPERTIES) ) + { + return new SvxXMLListLevelStyleAttrContext_Impl( GetImport(), + nElement, + xAttrList, + *this ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) ) + { + if( bImage && sImageURL.isEmpty() && !xBase64Stream.is() ) + { + xBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( xBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), xBase64Stream ); + } + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +Sequence SvxXMLListLevelStyleContext_Impl::GetProperties() +{ + if (!bBullet && !bImage && !bNum) + { + return Sequence(); + } + + sal_Int16 eType = NumberingType::NUMBER_NONE; + std::vector aProperties; + + if( bBullet ) + { + eType = NumberingType::CHAR_SPECIAL; + } + if( bImage ) + { + eType = NumberingType::BITMAP; + } + if( bNum ) + { + eType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( + eType, sNumFormat, sNumLetterSync, true ); + } + + if (bBullet && !sSuffix.isEmpty()) + { + sal_uInt16 const nVersion(GetImport().getGeneratorVersion()); + sal_Int32 nUPD; + sal_Int32 nBuildId; + if (GetImport().getBuildIds(nUPD, nBuildId) + && ( (SvXMLImport::OOo_1x == nVersion) + || (SvXMLImport::OOo_2x == nVersion) + || (310 == nUPD) || (320 == nUPD) || (330 == nUPD) + || ((300 == nUPD) && (nBuildId <= 9573)))) + { + // #i93908# OOo < 3.4 wrote a bogus suffix for bullet chars + sSuffix.clear(); // clear it + } + } + + if (!sListFormat.has_value()) + { + // This is older document: it has no list format, but can probably contain prefix and/or suffix + // Generate list format string, based on this + sListFormat = std::make_optional(sPrefix); + + for (int i = 1; i <= nNumDisplayLevels; i++) + { + *sListFormat += "%"; + *sListFormat += OUString::number(nLevel - nNumDisplayLevels + i + 1); + *sListFormat += "%"; + if (i != nNumDisplayLevels) + *sListFormat += "."; // Default separator for older ODT + } + + *sListFormat += sSuffix; + } + + aProperties.push_back(comphelper::makePropertyValue("NumberingType", eType)); + + aProperties.push_back(comphelper::makePropertyValue("Prefix", sPrefix)); + + aProperties.push_back(comphelper::makePropertyValue("Suffix", sSuffix)); + + aProperties.push_back(comphelper::makePropertyValue("Adjust", eAdjust)); + + sal_Int32 nLeftMargin = nSpaceBefore + nMinLabelWidth; + aProperties.push_back(comphelper::makePropertyValue("LeftMargin", nLeftMargin)); + + sal_Int32 nFirstLineOffset = -nMinLabelWidth; + aProperties.push_back(comphelper::makePropertyValue("FirstLineOffset", nFirstLineOffset)); + + aProperties.push_back(comphelper::makePropertyValue("SymbolTextDistance", static_cast(nMinLabelDist))); + + aProperties.push_back(comphelper::makePropertyValue("PositionAndSpaceMode", ePosAndSpaceMode)); + + aProperties.push_back(comphelper::makePropertyValue("LabelFollowedBy", eLabelFollowedBy)); + + aProperties.push_back(comphelper::makePropertyValue("ListtabStopPosition", nListtabStopPosition)); + + aProperties.push_back(comphelper::makePropertyValue("FirstLineIndent", nFirstLineIndent)); + + aProperties.push_back(comphelper::makePropertyValue("IndentAt", nIndentAt)); + + OUString sDisplayTextStyleName = GetImport().GetStyleDisplayName(XmlStyleFamily::TEXT_TEXT, sTextStyleName); + aProperties.push_back(comphelper::makePropertyValue("CharStyleName", sDisplayTextStyleName)); + + if( bBullet ) + { + awt::FontDescriptor aFDesc; + aFDesc.Name = sBulletFontName; + if( !sBulletFontName.isEmpty() ) + { + aFDesc.StyleName = sBulletFontStyleName; + aFDesc.Family = eBulletFontFamily; + aFDesc.Pitch = eBulletFontPitch; + aFDesc.CharSet = eBulletFontEncoding; + aFDesc.Weight = WEIGHT_DONTKNOW; + bool bStarSymbol = false; + if( aFDesc.Name.equalsIgnoreAsciiCase( gsStarBats ) ) + { + cBullet = GetImport().ConvStarBatsCharToStarSymbol( cBullet ); + bStarSymbol = true; + } + else if( aFDesc.Name.equalsIgnoreAsciiCase( gsStarMath ) ) + { + cBullet = GetImport().ConvStarMathCharToStarSymbol( cBullet ); + bStarSymbol = true; + } + if( bStarSymbol ) + aFDesc.Name = "StarSymbol" ; + } + + // Must append 'cBullet' even if it is zero + // if 'bBullet' is true and 'cBullet' is zero - BulletChar property must be 0. + aProperties.push_back(comphelper::makePropertyValue("BulletChar", OUString(&cBullet, 1))); + aProperties.push_back(comphelper::makePropertyValue("BulletFont", aFDesc)); + } + + if( bImage ) + { + uno::Reference xGraphic; + if (!sImageURL.isEmpty()) + { + xGraphic = GetImport().loadGraphicByURL(sImageURL); + } + else if( xBase64Stream.is() ) + { + xGraphic = GetImport().loadGraphicFromBase64(xBase64Stream); + } + + uno::Reference xBitmap; + if (xGraphic.is()) + xBitmap.set(xGraphic, uno::UNO_QUERY); + + if (xBitmap.is()) + { + aProperties.push_back(comphelper::makePropertyValue("GraphicBitmap", xBitmap)); + } + + awt::Size aSize(nImageWidth, nImageHeight); + aProperties.push_back(comphelper::makePropertyValue("GraphicSize", aSize)); + aProperties.push_back(comphelper::makePropertyValue("VertOrient", eImageVertOrient)); + } + + if( bNum ) + { + aProperties.push_back(comphelper::makePropertyValue("StartWith", nNumStartValue)); + aProperties.push_back(comphelper::makePropertyValue("ParentNumbering", nNumDisplayLevels)); + } + + if( ( bNum || bBullet ) && nRelSize ) + { + aProperties.push_back(comphelper::makePropertyValue("BulletRelSize", nRelSize)); + } + + if( !bImage && bHasColor ) + { + aProperties.push_back(comphelper::makePropertyValue("BulletColor", m_nColor)); + } + + aProperties.push_back(comphelper::makePropertyValue("ListFormat", *sListFormat)); + + return comphelper::containerToSequence(aProperties); +} + +SvxXMLListLevelStyleAttrContext_Impl::SvxXMLListLevelStyleAttrContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + SvxXMLListLevelStyleContext_Impl& rLLevel ) : + SvXMLImportContext( rImport ), + rListLevel( rLLevel ) +{ + SvXMLUnitConverter& rUnitConv = GetImport().GetMM100UnitConverter(); + + OUString sFontName, sFontFamily, sFontStyleName, sFontFamilyGeneric, + sFontPitch, sFontCharset; + OUString sVerticalPos, sVerticalRel; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(TEXT, XML_SPACE_BEFORE): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), SHRT_MIN, SHRT_MAX)) + rListLevel.SetSpaceBefore( nVal ); + break; + case XML_ELEMENT(TEXT, XML_MIN_LABEL_WIDTH): + if (rUnitConv.convertMeasureToCore( nVal, aIter.toView(), 0, SHRT_MAX )) + rListLevel.SetMinLabelWidth( nVal ); + break; + case XML_ELEMENT(TEXT, XML_MIN_LABEL_DISTANCE): + if (rUnitConv.convertMeasureToCore( nVal, aIter.toView(), 0, USHRT_MAX )) + rListLevel.SetMinLabelDist( nVal ); + break; + case XML_ELEMENT(FO, XML_TEXT_ALIGN): + case XML_ELEMENT(FO_COMPAT, XML_TEXT_ALIGN): + if( !aIter.isEmpty() ) + { + sal_Int16 eAdjust = HoriOrientation::LEFT; + if( IsXMLToken( aIter, XML_CENTER ) ) + eAdjust = HoriOrientation::CENTER; + else if( IsXMLToken( aIter, XML_END ) ) + eAdjust = HoriOrientation::RIGHT; + rListLevel.SetAdjust( eAdjust ); + } + break; + case XML_ELEMENT(STYLE, XML_FONT_NAME): + sFontName = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_FONT_FAMILY): + case XML_ELEMENT(FO_COMPAT, XML_FONT_FAMILY): + sFontFamily = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_FONT_FAMILY_GENERIC): + sFontFamilyGeneric = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_FONT_STYLE_NAME): + sFontStyleName = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_FONT_PITCH): + sFontPitch = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_FONT_CHARSET): + sFontCharset = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_VERTICAL_POS): + sVerticalPos = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_VERTICAL_REL): + sVerticalRel = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_WIDTH): + case XML_ELEMENT(FO_COMPAT, XML_WIDTH): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView())) + rListLevel.SetImageWidth( nVal ); + break; + case XML_ELEMENT(FO, XML_HEIGHT): + case XML_ELEMENT(FO_COMPAT, XML_HEIGHT): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView())) + rListLevel.SetImageHeight( nVal ); + break; + case XML_ELEMENT(FO, XML_COLOR): + case XML_ELEMENT(FO_COMPAT, XML_COLOR): + { + Color nColor; + if (::sax::Converter::convertColor( nColor, aIter.toView() )) + rListLevel.SetColor( nColor ); + } + break; + case XML_ELEMENT(STYLE, XML_USE_WINDOW_FONT_COLOR): + { + if( IsXMLToken( aIter, XML_TRUE ) ) + rListLevel.SetColor(COL_AUTO); + } + break; + case XML_ELEMENT(FO, XML_FONT_SIZE): + case XML_ELEMENT(FO_COMPAT, XML_FONT_SIZE): + if (::sax::Converter::convertPercent( nVal, aIter.toView() )) + rListLevel.SetRelSize( static_cast(nVal) ); + break; + case XML_ELEMENT(TEXT, XML_LIST_LEVEL_POSITION_AND_SPACE_MODE): + { + sal_Int16 ePosAndSpaceMode = PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION; + if( IsXMLToken( aIter, XML_LABEL_ALIGNMENT ) ) + ePosAndSpaceMode = PositionAndSpaceMode::LABEL_ALIGNMENT; + rListLevel.SetPosAndSpaceMode( ePosAndSpaceMode ); + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !sFontName.isEmpty() ) + { + const XMLFontStylesContext *pFontDecls = + GetImport().GetFontDecls(); + if( pFontDecls ) + { + ::std::vector < XMLPropertyState > aProps; + if( pFontDecls->FillProperties( sFontName, aProps, 0, 1, 2, 3, 4 ) ) + { + OUString sTmp; + sal_Int16 nTmp = 0; + for( const auto& rProp : aProps ) + { + switch( rProp.mnIndex ) + { + case 0: + rProp.maValue >>= sTmp; + rListLevel.SetBulletFontName( sTmp); + break; + case 1: + rProp.maValue >>= sTmp; + rListLevel.SetBulletFontStyleName( sTmp ); + break; + case 2: + rProp.maValue >>= nTmp; + rListLevel.SetBulletFontFamily( nTmp ); + break; + case 3: + rProp.maValue >>= nTmp; + rListLevel.SetBulletFontPitch( nTmp ); + break; + case 4: + rProp.maValue >>= nTmp; + rListLevel.SetBulletFontEncoding( nTmp ); + break; + } + } + } + } + } + if( !sFontFamily.isEmpty() ) + { + Any aAny; + + XMLFontFamilyNamePropHdl aFamilyNameHdl; + if( aFamilyNameHdl.importXML( sFontFamily, aAny, rUnitConv ) ) + { + OUString sTmp; + aAny >>= sTmp; + rListLevel.SetBulletFontName( sTmp); + } + + XMLFontFamilyPropHdl aFamilyHdl; + if( !sFontFamilyGeneric.isEmpty() && + aFamilyHdl.importXML( sFontFamilyGeneric, aAny, rUnitConv ) ) + { + sal_Int16 nTmp = 0; + aAny >>= nTmp; + rListLevel.SetBulletFontFamily( nTmp ); + } + + if( !sFontStyleName.isEmpty() ) + rListLevel.SetBulletFontStyleName( sFontStyleName ); + + XMLFontPitchPropHdl aPitchHdl; + if( !sFontPitch.isEmpty() && + aPitchHdl.importXML( sFontPitch, aAny, rUnitConv ) ) + { + sal_Int16 nTmp = 0; + aAny >>= nTmp; + rListLevel.SetBulletFontPitch( nTmp ); + } + + XMLFontEncodingPropHdl aEncHdl; + if( !sFontCharset.isEmpty() && + aEncHdl.importXML( sFontCharset, aAny, rUnitConv ) ) + { + sal_Int16 nTmp = 0; + aAny >>= nTmp; + rListLevel.SetBulletFontEncoding( nTmp ); + } + } + + sal_Int16 eVertOrient = VertOrientation::LINE_CENTER; + if( !sVerticalPos.isEmpty() ) + { + if( IsXMLToken( sVerticalPos, XML_TOP ) ) + eVertOrient = VertOrientation::LINE_TOP; + else if( IsXMLToken( sVerticalPos, XML_BOTTOM ) ) + eVertOrient = VertOrientation::LINE_BOTTOM; + } + if( !sVerticalRel.isEmpty() ) + { + if( IsXMLToken( sVerticalRel, XML_BASELINE ) ) + { + // TOP and BOTTOM are exchanged for a baseline relation + switch( eVertOrient ) + { + case VertOrientation::LINE_TOP: + eVertOrient = VertOrientation::BOTTOM; + break; + case VertOrientation::LINE_CENTER: + eVertOrient = VertOrientation::CENTER; + break; + case VertOrientation::LINE_BOTTOM: + eVertOrient = VertOrientation::TOP; + break; + } + } + else if( IsXMLToken( sVerticalRel, XML_CHAR ) ) + { + switch( eVertOrient ) + { + case VertOrientation::LINE_TOP: + eVertOrient = VertOrientation::CHAR_TOP; + break; + case VertOrientation::LINE_CENTER: + eVertOrient = VertOrientation::CHAR_CENTER; + break; + case VertOrientation::LINE_BOTTOM: + eVertOrient = VertOrientation::CHAR_BOTTOM; + break; + } + } + } + rListLevel.SetImageVertOrient( eVertOrient ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLListLevelStyleAttrContext_Impl::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(STYLE, XML_LIST_LEVEL_LABEL_ALIGNMENT) ) + { + return new SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl( GetImport(), + nElement, + xAttrList, + rListLevel ); + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl::SvxXMLListLevelStyleLabelAlignmentAttrContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + SvxXMLListLevelStyleContext_Impl& rLLevel ) : + SvXMLImportContext( rImport ) +{ + SvXMLUnitConverter& rUnitConv = GetImport().GetMM100UnitConverter(); + + sal_Int16 eLabelFollowedBy = LabelFollow::LISTTAB; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(TEXT, XML_LABEL_FOLLOWED_BY): + case XML_ELEMENT(LO_EXT, XML_LABEL_FOLLOWED_BY): + { + if( eLabelFollowedBy == LabelFollow::NEWLINE) + //NewLine from LO_EXT has precedence over other values of the Non LO_EXT namespace + break; + if( IsXMLToken( aIter, XML_SPACE ) ) + eLabelFollowedBy = LabelFollow::SPACE; + else if( IsXMLToken( aIter, XML_NOTHING ) ) + eLabelFollowedBy = LabelFollow::NOTHING; + else if( IsXMLToken( aIter, XML_NEWLINE ) ) + eLabelFollowedBy = LabelFollow::NEWLINE; + } + break; + case XML_ELEMENT(TEXT, XML_LIST_TAB_STOP_POSITION): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), 0, SHRT_MAX)) + rLLevel.SetListtabStopPosition( nVal ); + break; + case XML_ELEMENT(FO, XML_TEXT_INDENT): + case XML_ELEMENT(FO_COMPAT, XML_TEXT_INDENT): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), SHRT_MIN, SHRT_MAX)) + rLLevel.SetFirstLineIndent( nVal ); + break; + case XML_ELEMENT(FO, XML_MARGIN_LEFT): + case XML_ELEMENT(FO_COMPAT, XML_MARGIN_LEFT): + if (rUnitConv.convertMeasureToCore(nVal, aIter.toView(), SHRT_MIN, SHRT_MAX)) + rLLevel.SetIndentAt( nVal ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + rLLevel.SetLabelFollowedBy( eLabelFollowedBy ); +} + +void SvxXMLListStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(TEXT, XML_CONSECUTIVE_NUMBERING) ) + { + bConsecutive = IsXMLToken( rValue, XML_TRUE ); + } + else + { + SvXMLStyleContext::SetAttribute( nElement, rValue ); + } +} + +constexpr OUStringLiteral sIsPhysical( u"IsPhysical" ); +constexpr OUStringLiteral sNumberingRules( u"NumberingRules" ); +constexpr OUStringLiteral sIsContinuousNumbering( u"IsContinuousNumbering" ); + +SvxXMLListStyleContext::SvxXMLListStyleContext( SvXMLImport& rImport, + bool bOutl ) +: SvXMLStyleContext( rImport, bOutl ? XmlStyleFamily::TEXT_OUTLINE : XmlStyleFamily::TEXT_LIST ) +, bConsecutive( false ) +, bOutline( bOutl ) +{ +} + +SvxXMLListStyleContext::~SvxXMLListStyleContext() {} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLListStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( bOutline + ? nElement == XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL_STYLE) + : ( nElement == XML_ELEMENT(TEXT, XML_LIST_LEVEL_STYLE_NUMBER) || + nElement == XML_ELEMENT(TEXT, XML_LIST_LEVEL_STYLE_BULLET) || + nElement == XML_ELEMENT(TEXT, XML_LIST_LEVEL_STYLE_IMAGE ) ) ) + { + rtl::Reference xLevelStyle{ + new SvxXMLListLevelStyleContext_Impl( GetImport(), nElement, xAttrList )}; + if( !pLevelStyles ) + pLevelStyles = std::make_unique(); + pLevelStyles->push_back( xLevelStyle ); + + return xLevelStyle; + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void SvxXMLListStyleContext::FillUnoNumRule( + const Reference & rNumRule) const +{ + try + { + if( pLevelStyles && rNumRule.is() ) + { + sal_Int32 l_nLevels = rNumRule->getCount(); + for (const auto& pLevelStyle : *pLevelStyles) + { + sal_Int32 nLevel = pLevelStyle->GetLevel(); + if( nLevel >= 0 && nLevel < l_nLevels ) + { + Sequence aProps = + pLevelStyle->GetProperties(); + rNumRule->replaceByIndex( nLevel, Any(aProps) ); + } + } + } + + Reference < XPropertySet > xPropSet( rNumRule, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo; + if (xPropSet.is()) + xPropSetInfo = xPropSet->getPropertySetInfo(); + if( xPropSetInfo.is() && + xPropSetInfo->hasPropertyByName( sIsContinuousNumbering ) ) + { + xPropSet->setPropertyValue( sIsContinuousNumbering, Any(bConsecutive) ); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.style", "" ); + } +} + +void SvxXMLListStyleContext::CreateAndInsertLate( bool bOverwrite ) +{ + if( bOutline ) + { + if( bOverwrite ) + { + const Reference< XIndexReplace >& rNumRule = + GetImport().GetTextImport()->GetChapterNumbering(); + // We don't set xNumberingRules here, to avoid using them + // as numbering rules. + if( rNumRule.is() ) + FillUnoNumRule(rNumRule); + } + } + else + { + Reference < XStyle > xStyle; + const OUString& rName = GetDisplayName(); + if( rName.isEmpty() ) + { + SetValid( false ); + return; + } + + const Reference < XNameContainer >& rNumStyles = + GetImport().GetTextImport()->GetNumberingStyles(); + if( !rNumStyles.is() ) + { + SetValid( false ); + return; + } + + bool bNew = false; + if( rNumStyles->hasByName( rName ) ) + { + Any aAny = rNumStyles->getByName( rName ); + aAny >>= xStyle; + } + else + { + Reference< XMultiServiceFactory > xFactory( GetImport().GetModel(), + UNO_QUERY ); + SAL_WARN_IF( !xFactory.is(), "xmloff", "no factory" ); + if( !xFactory.is() ) + return; + + Reference < XInterface > xIfc = xFactory->createInstance("com.sun.star.style.NumberingStyle"); + if( !xIfc.is() ) + return; + Reference < XStyle > xTmp( xIfc, UNO_QUERY ); + xStyle = xTmp; + if( !xStyle.is() ) + return; + + rNumStyles->insertByName( rName, Any(xStyle) ); + bNew = true; + } + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( !bNew && xPropSetInfo->hasPropertyByName( sIsPhysical ) ) + { + Any aAny = xPropSet->getPropertyValue( sIsPhysical ); + bNew = !*o3tl::doAccess(aAny); + } + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + xPropSet->setPropertyValue( "Hidden", uno::Any( IsHidden( ) ) ); + + if( rName != GetName() ) + GetImport().AddStyleDisplayName( XmlStyleFamily::TEXT_LIST, + GetName(), rName ); + + Any aAny = xPropSet->getPropertyValue( sNumberingRules ); + aAny >>= xNumRules; + if( bOverwrite || bNew ) + { + FillUnoNumRule(xNumRules); + xPropSet->setPropertyValue( sNumberingRules, Any(xNumRules) ); + } + else + { + SetValid( false ); + } + + SetNew( bNew ); + } +} + +void SvxXMLListStyleContext::CreateAndInsertAuto() const +{ + SAL_WARN_IF( bOutline, "xmloff", "Outlines cannot be inserted here" ); + SAL_WARN_IF( xNumRules.is(), "xmloff", "Numbering Rule is existing already" ); + + const OUString& rName = GetName(); + if( bOutline || xNumRules.is() || rName.isEmpty() ) + { + const_cast(this)->SetValid( false ); + return; + } + + const_cast(this)->xNumRules = CreateNumRule( + GetImport().GetModel() ); + + FillUnoNumRule(xNumRules); +} + +Reference < XIndexReplace > SvxXMLListStyleContext::CreateNumRule( + const Reference < XModel > & rModel ) +{ + Reference xNumRule; + + Reference< XMultiServiceFactory > xFactory( rModel, UNO_QUERY ); + SAL_WARN_IF( !xFactory.is(), "xmloff", "no factory" ); + if( !xFactory.is() ) + return xNumRule; + + Reference < XInterface > xIfc = xFactory->createInstance("com.sun.star.text.NumberingRules"); + if( !xIfc.is() ) + return xNumRule; + + xNumRule.set( xIfc, UNO_QUERY ); + SAL_WARN_IF( !xNumRule.is(), "xmloff", "go no numbering rule" ); + + return xNumRule; +} + +void SvxXMLListStyleContext::SetDefaultStyle( + const Reference < XIndexReplace > & rNumRule, + sal_Int16 nLevel, + bool bOrdered ) +{ + Sequence aPropSeq( bOrdered ? 1 : 4 ); + beans::PropertyValue *pProps = aPropSeq.getArray(); + + pProps->Name = "NumberingType"; + (pProps++)->Value <<= static_cast(bOrdered ? NumberingType::ARABIC + : NumberingType::CHAR_SPECIAL ); + if( !bOrdered ) + { + // TODO: Bullet-Font + awt::FontDescriptor aFDesc; + aFDesc.Name = +#ifdef _WIN32 + "StarBats" +#else + "starbats" +#endif + ; + aFDesc.Family = FAMILY_DONTKNOW ; + aFDesc.Pitch = PITCH_DONTKNOW ; + aFDesc.CharSet = RTL_TEXTENCODING_SYMBOL ; + aFDesc.Weight = WEIGHT_DONTKNOW; + pProps->Name = "BulletFont"; + (pProps++)->Value <<= aFDesc; + + pProps->Name = "BulletChar"; + (pProps++)->Value <<= OUString(sal_Unicode(0xF000 + 149)); + pProps->Name = "CharStyleName"; + (pProps++)->Value <<= OUString( "Numbering Symbols" ); + } + + rNumRule->replaceByIndex( nLevel, Any(aPropSeq) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlprcon.cxx b/xmloff/source/style/xmlprcon.cxx new file mode 100644 index 000000000..cb0a6eca9 --- /dev/null +++ b/xmloff/source/style/xmlprcon.cxx @@ -0,0 +1,89 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::std; + +SvXMLPropertySetContext::SvXMLPropertySetContext( + SvXMLImport& rImp, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList >& xAttrList, + sal_uInt32 nFam, + vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + sal_Int32 nSIdx, sal_Int32 nEIdx ) +: SvXMLImportContext( rImp ) +, mnStartIdx( nSIdx ) +, mnEndIdx( nEIdx ) +, mnFamily( nFam ) +, mrProperties( rProps ) +, mxMapper( rMap ) +{ + mxMapper->importXML( mrProperties, xAttrList, + GetImport().GetMM100UnitConverter(), + GetImport().GetNamespaceMap(), mnFamily, + mnStartIdx, mnEndIdx ); +} + +SvXMLPropertySetContext::~SvXMLPropertySetContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLPropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + rtl::Reference< XMLPropertySetMapper > aSetMapper( + mxMapper->getPropertySetMapper() ); + sal_Int32 nEntryIndex = aSetMapper->GetEntryIndex( nElement, mnFamily, mnStartIdx ); + + if( ( nEntryIndex != -1 ) && (-1 == mnEndIdx || nEntryIndex < mnEndIdx ) && + ( 0 != ( aSetMapper->GetEntryFlags( nEntryIndex ) + & MID_FLAG_ELEMENT_ITEM_IMPORT ) ) ) + { + XMLPropertyState aProp( nEntryIndex ); + return createFastChildContext( nElement, xAttrList, mrProperties, aProp ); + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +/** This method is called from this instance implementation of + CreateChildContext if the element matches an entry in the + SvXMLImportItemMapper with the mid flag MID_FLAG_ELEMENT +*/ +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLPropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/, + ::std::vector< XMLPropertyState > &/*rProperties*/, + const XMLPropertyState& /*rProp*/ ) +{ + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlprhdl.cxx b/xmloff/source/style/xmlprhdl.cxx new file mode 100644 index 000000000..530bcd479 --- /dev/null +++ b/xmloff/source/style/xmlprhdl.cxx @@ -0,0 +1,33 @@ +/* -*- 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 +#include + +XMLPropertyHandler::~XMLPropertyHandler() +{ + // does nothing +} + +bool XMLPropertyHandler::equals(const css::uno::Any& r1, const css::uno::Any& r2) const +{ + return (r1 == r2); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlprmap.cxx b/xmloff/source/style/xmlprmap.cxx new file mode 100644 index 000000000..a2e35b774 --- /dev/null +++ b/xmloff/source/style/xmlprmap.cxx @@ -0,0 +1,361 @@ +/* -*- 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 +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +using namespace ::std; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using ::xmloff::token::GetXMLToken; + +namespace { + +/** Helper-class for XML-im/export: + - Holds a pointer to a given array of XMLPropertyMapEntry + - Provides several methods to access data from this array + - Holds a Sequence of XML-names (for properties) + - The filter takes all properties of the XPropertySet which are also + in the XMLPropertyMapEntry and which are have not a default value + and put them into a vector of XMLPropertyStae + - this class knows how to compare, im/export properties + + Attention: At all methods, which get an index as parameter, there is no + range validation to save runtime !! +*/ +struct XMLPropertySetMapperEntry_Impl +{ + OUString sXMLAttributeName; + OUString sAPIPropertyName; + sal_Int32 nType; + sal_uInt16 nXMLNameSpace; + sal_Int16 nContextId; + SvtSaveOptions::ODFSaneDefaultVersion nEarliestODFVersionForExport; + bool bImportOnly; + const XMLPropertyHandler *pHdl; + + XMLPropertySetMapperEntry_Impl( + const XMLPropertyMapEntry& rMapEntry, + const rtl::Reference< XMLPropertyHandlerFactory >& rFactory ); + + sal_uInt32 GetPropType() const { return nType & XML_TYPE_PROP_MASK; } +}; + +} + +XMLPropertySetMapperEntry_Impl::XMLPropertySetMapperEntry_Impl( + const XMLPropertyMapEntry& rMapEntry, + const rtl::Reference< XMLPropertyHandlerFactory >& rFactory ) : + sXMLAttributeName( GetXMLToken(rMapEntry.meXMLName) ), + sAPIPropertyName( OUString(rMapEntry.msApiName, rMapEntry.nApiNameLength, + RTL_TEXTENCODING_ASCII_US ) ), + nType( rMapEntry.mnType ), + nXMLNameSpace( rMapEntry.mnNameSpace ), + nContextId( rMapEntry.mnContextId ), + nEarliestODFVersionForExport( rMapEntry.mnEarliestODFVersionForExport ), + bImportOnly( rMapEntry.mbImportOnly), + pHdl( rFactory->GetPropertyHandler( rMapEntry.mnType & MID_FLAG_MASK ) ) +{ + assert(pHdl); +} + +struct XMLPropertySetMapper::Impl +{ + std::vector maMapEntries; + std::vector > maHdlFactories; + + bool mbOnlyExportMappings; + + explicit Impl( bool bForExport ) : mbOnlyExportMappings(bForExport) {} +}; + +// Ctor +XMLPropertySetMapper::XMLPropertySetMapper( + const XMLPropertyMapEntry* pEntries, const rtl::Reference& rFactory, + bool bForExport ) : + mpImpl(new Impl(bForExport)) +{ + mpImpl->maHdlFactories.push_back(rFactory); + if( !pEntries ) + return; + + const XMLPropertyMapEntry* pIter = pEntries; + + if (mpImpl->mbOnlyExportMappings) + { + while( pIter->msApiName ) + { + if (!pIter->mbImportOnly) + { + XMLPropertySetMapperEntry_Impl aEntry( *pIter, rFactory ); + mpImpl->maMapEntries.push_back( aEntry ); + } + ++pIter; + } + } + else + { + while( pIter->msApiName ) + { + XMLPropertySetMapperEntry_Impl aEntry( *pIter, rFactory ); + mpImpl->maMapEntries.push_back( aEntry ); + ++pIter; + } + } +} + +XMLPropertySetMapper::~XMLPropertySetMapper() +{ +} + +void XMLPropertySetMapper::AddMapperEntry( + const rtl::Reference < XMLPropertySetMapper >& rMapper ) +{ + for( const auto& rHdlFactory : rMapper->mpImpl->maHdlFactories ) + { + mpImpl->maHdlFactories.push_back(rHdlFactory); + } + + for( const auto& rMapEntry : rMapper->mpImpl->maMapEntries ) + { + if (!mpImpl->mbOnlyExportMappings || !rMapEntry.bImportOnly) + mpImpl->maMapEntries.push_back( rMapEntry ); + } +} + +sal_Int32 XMLPropertySetMapper::GetEntryCount() const +{ + return mpImpl->maMapEntries.size(); +} + +sal_uInt32 XMLPropertySetMapper::GetEntryFlags( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].nType & ~MID_FLAG_MASK; +} + +sal_uInt32 XMLPropertySetMapper::GetEntryType( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + sal_uInt32 nType = mpImpl->maMapEntries[nIndex].nType; + return nType; +} + +sal_uInt16 XMLPropertySetMapper::GetEntryNameSpace( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].nXMLNameSpace; +} + +const OUString& XMLPropertySetMapper::GetEntryXMLName( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].sXMLAttributeName; +} + +const OUString& XMLPropertySetMapper::GetEntryAPIName( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].sAPIPropertyName; +} + +sal_Int16 XMLPropertySetMapper::GetEntryContextId( sal_Int32 nIndex ) const +{ + assert((-1 <= nIndex) && (nIndex < static_cast(mpImpl->maMapEntries.size()))); + return nIndex == -1 ? 0 : mpImpl->maMapEntries[nIndex].nContextId; +} + +SvtSaveOptions::ODFSaneDefaultVersion +XMLPropertySetMapper::GetEarliestODFVersionForExport(sal_Int32 const nIndex) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].nEarliestODFVersionForExport; +} + +const XMLPropertyHandler* XMLPropertySetMapper::GetPropertyHandler( sal_Int32 nIndex ) const +{ + assert((0 <= nIndex) && (o3tl::make_unsigned(nIndex) < mpImpl->maMapEntries.size())); + return mpImpl->maMapEntries[nIndex].pHdl; +} + +// Export a Property +bool XMLPropertySetMapper::exportXML( + OUString& rStrExpValue, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + + const XMLPropertyHandler* pHdl = GetPropertyHandler( rProperty.mnIndex ); + + assert(pHdl); + if( pHdl ) + bRet = pHdl->exportXML( rStrExpValue, rProperty.maValue, + rUnitConverter ); + + return bRet; +} + +// Import a Property +bool XMLPropertySetMapper::importXML( + const OUString& rStrImpValue, + XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter ) const +{ + bool bRet = false; + + const XMLPropertyHandler* pHdl = GetPropertyHandler( rProperty.mnIndex ); + + if( pHdl ) + bRet = pHdl->importXML( rStrImpValue, rProperty.maValue, + rUnitConverter ); + + return bRet; +} + +// Search for the given name and the namespace in the list and return +// the index of the entry +// If there is no matching entry the method returns -1 +sal_Int32 XMLPropertySetMapper::GetEntryIndex( + sal_uInt16 nNamespace, + std::u16string_view rStrName, + sal_uInt32 nPropType, + sal_Int32 nStartAt /* = -1 */ ) const +{ + sal_Int32 nEntries = GetEntryCount(); + sal_Int32 nIndex= nStartAt == - 1? 0 : nStartAt+1; + + if ( nEntries && nIndex < nEntries ) + { + do + { + const XMLPropertySetMapperEntry_Impl& rEntry = mpImpl->maMapEntries[nIndex]; + if( (!nPropType || nPropType == rEntry.GetPropType()) && + rEntry.nXMLNameSpace == nNamespace && + rStrName == rEntry.sXMLAttributeName ) + return nIndex; + else + nIndex++; + + } while( nIndex> NMSP_SHIFT) - 1; + const OUString& rStrName = SvXMLImport::getNameFromToken(nElement); + do + { + const XMLPropertySetMapperEntry_Impl& rEntry = mpImpl->maMapEntries[nIndex]; + if( (!nPropType || nPropType == rEntry.GetPropType()) && + rEntry.nXMLNameSpace == nNamespace && + rStrName == rEntry.sXMLAttributeName ) + return nIndex; + else + nIndex++; + + } while( nIndexmaMapEntries[nIndex]; + if( rEntry.nXMLNameSpace == nNameSpace && + rEntry.sXMLAttributeName == sXMLName && + rEntry.sAPIPropertyName.equalsAscii( sApiName ) ) + return nIndex; + else + nIndex++; + + } while( nIndex < nEntries ); + + return -1; +} + +sal_Int32 XMLPropertySetMapper::FindEntryIndex( const sal_Int16 nContextId ) const +{ + const sal_Int32 nEntries = GetEntryCount(); + + if ( nEntries ) + { + sal_Int32 nIndex = 0; + do + { + const XMLPropertySetMapperEntry_Impl& rEntry = mpImpl->maMapEntries[nIndex]; + if( rEntry.nContextId == nContextId ) + return nIndex; + else + nIndex++; + + } while( nIndex < nEntries ); + } + + return -1; +} + +void XMLPropertySetMapper::RemoveEntry( sal_Int32 nIndex ) +{ + const sal_Int32 nEntries = GetEntryCount(); + if( nIndex>=nEntries || nIndex<0 ) + return; + vector < XMLPropertySetMapperEntry_Impl >::iterator aEIter = mpImpl->maMapEntries.begin(); + std::advance(aEIter, nIndex); + mpImpl->maMapEntries.erase( aEIter ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmlstyle.cxx b/xmloff/source/style/xmlstyle.cxx new file mode 100644 index 000000000..d46365008 --- /dev/null +++ b/xmloff/source/style/xmlstyle.cxx @@ -0,0 +1,806 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "FillStyleContext.hxx" +#include +#include +#include +#include +#include "PageMasterImportPropMapper.hxx" + +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + +constexpr OUStringLiteral gsParaStyleServiceName( u"com.sun.star.style.ParagraphStyle" ); +constexpr OUStringLiteral gsTextStyleServiceName( u"com.sun.star.style.CharacterStyle" ); + +void SvXMLStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + switch (nElement) + { + case XML_ELEMENT(STYLE, XML_FAMILY): + { + if( IsXMLToken( rValue, XML_PARAGRAPH ) ) + mnFamily = XmlStyleFamily(SfxStyleFamily::Para); + else if( IsXMLToken( rValue, XML_TEXT ) ) + mnFamily = XmlStyleFamily(SfxStyleFamily::Char); + break; + } + case XML_ELEMENT(STYLE, XML_NAME): + maName = rValue; + break; + case XML_ELEMENT(STYLE, XML_DISPLAY_NAME): + maDisplayName = rValue; + break; + case XML_ELEMENT(STYLE, XML_PARENT_STYLE_NAME): + maParentName = rValue; + break; + case XML_ELEMENT(STYLE, XML_NEXT_STYLE_NAME): + maFollow = rValue; + break; + case XML_ELEMENT(LO_EXT, XML_LINKED_STYLE_NAME): + maLinked = rValue; + break; + case XML_ELEMENT(STYLE, XML_HIDDEN): + mbHidden = rValue.toBoolean(); + break; + case XML_ELEMENT(LO_EXT, XML_HIDDEN): + mbHidden = rValue.toBoolean(); + break; + } +} + + +SvXMLStyleContext::SvXMLStyleContext( + SvXMLImport& rImp, + XmlStyleFamily nFam, bool bDefault ) : + SvXMLImportContext( rImp ), + mbHidden( false ), + mnFamily( nFam ), + mbValid( true ), + mbNew( true ), + mbDefaultStyle( bDefault ) +{ +} + +SvXMLStyleContext::~SvXMLStyleContext() +{ +} + +void SvXMLStyleContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto &it : sax_fastparser::castToFastAttributeList( xAttrList ) ) + SetAttribute( it.getToken(), it.toString() ); +} + +void SvXMLStyleContext::SetDefaults() +{ +} + +void SvXMLStyleContext::CreateAndInsert( bool /*bOverwrite*/ ) +{ +} + +void SvXMLStyleContext::CreateAndInsertLate( bool /*bOverwrite*/ ) +{ +} + +void SvXMLStyleContext::Finish( bool /*bOverwrite*/ ) +{ +} + +bool SvXMLStyleContext::IsTransient() const +{ + return false; +} + +namespace { + +class SvXMLStyleIndex_Impl +{ + OUString sName; + XmlStyleFamily nFamily; + // we deliberately don't use a reference here, to avoid creating a ref-count-cycle + SvXMLStyleContext* mpStyle; + +public: + + SvXMLStyleIndex_Impl( XmlStyleFamily nFam, const OUString& rName ) : + sName( rName ), + nFamily( nFam ), + mpStyle(nullptr) + { + } + + SvXMLStyleIndex_Impl( const rtl::Reference &rStl ) : + sName( rStl->GetName() ), + nFamily( rStl->GetFamily() ), + mpStyle ( rStl.get() ) + { + } + + const OUString& GetName() const { return sName; } + XmlStyleFamily GetFamily() const { return nFamily; } + const SvXMLStyleContext *GetStyle() const { return mpStyle; } +}; + +struct SvXMLStyleIndexCmp_Impl +{ + bool operator()(const SvXMLStyleIndex_Impl& r1, const SvXMLStyleIndex_Impl& r2) const + { + sal_Int32 nRet; + + if( r1.GetFamily() < r2.GetFamily() ) + nRet = -1; + else if( r1.GetFamily() > r2.GetFamily() ) + nRet = 1; + else + nRet = r1.GetName().compareTo( r2.GetName() ); + + return nRet < 0; + } +}; + +} + +class SvXMLStylesContext_Impl +{ + typedef std::set IndicesType; + + std::vector> aStyles; + mutable std::unique_ptr pIndices; + bool bAutomaticStyle; + +#if OSL_DEBUG_LEVEL > 0 + mutable sal_uInt32 m_nIndexCreated; +#endif + + void FlushIndex() { pIndices.reset(); } + +public: + explicit SvXMLStylesContext_Impl( bool bAuto ); + + size_t GetStyleCount() const { return aStyles.size(); } + + SvXMLStyleContext *GetStyle( size_t i ) + { + return i < aStyles.size() ? aStyles[ i ].get() : nullptr; + } + + inline void AddStyle( SvXMLStyleContext *pStyle ); + void dispose(); + + const SvXMLStyleContext *FindStyleChildContext( XmlStyleFamily nFamily, + const OUString& rName, + bool bCreateIndex ) const; + bool IsAutomaticStyle() const { return bAutomaticStyle; } +}; + +SvXMLStylesContext_Impl::SvXMLStylesContext_Impl( bool bAuto ) : + bAutomaticStyle( bAuto ) +#if OSL_DEBUG_LEVEL > 0 + , m_nIndexCreated( 0 ) +#endif +{} + +inline void SvXMLStylesContext_Impl::AddStyle( SvXMLStyleContext *pStyle ) +{ +#if OSL_DEBUG_LEVEL > 0 +// for (auto const & xStyle : aStyles) +// if (xStyle->GetFamily() == pStyle->GetFamily() && xStyle->GetName() == pStyle->GetName()) +// assert(false && "duplicate style"); +#endif + aStyles.emplace_back(pStyle ); + + FlushIndex(); +} + +void SvXMLStylesContext_Impl::dispose() +{ + FlushIndex(); + aStyles.clear(); +} + +const SvXMLStyleContext *SvXMLStylesContext_Impl::FindStyleChildContext( XmlStyleFamily nFamily, + const OUString& rName, + bool bCreateIndex ) const +{ + const SvXMLStyleContext *pStyle = nullptr; + + if( !pIndices && bCreateIndex && !aStyles.empty() ) + { + pIndices = std::make_unique(aStyles.begin(), aStyles.end()); + SAL_WARN_IF(pIndices->size() != aStyles.size(), "xmloff.style", "Here is a duplicate Style"); +#if OSL_DEBUG_LEVEL > 0 + SAL_WARN_IF(0 != m_nIndexCreated, "xmloff.style", + "Performance warning: sdbcx::Index created multiple times"); + ++m_nIndexCreated; +#endif + } + + if( pIndices ) + { + SvXMLStyleIndex_Impl aIndex( nFamily, rName ); + IndicesType::iterator aFind = pIndices->find(aIndex); + if( aFind != pIndices->end() ) + pStyle = aFind->GetStyle(); + } + else + { + for( size_t i = 0; !pStyle && i < aStyles.size(); i++ ) + { + const SvXMLStyleContext *pS = aStyles[ i ].get(); + if( pS->GetFamily() == nFamily && + pS->GetName() == rName ) + pStyle = pS; + } + } + return pStyle; +} + + +sal_uInt32 SvXMLStylesContext::GetStyleCount() const +{ + return mpImpl->GetStyleCount(); +} + +SvXMLStyleContext *SvXMLStylesContext::GetStyle( sal_uInt32 i ) +{ + return mpImpl->GetStyle( i ); +} + +const SvXMLStyleContext *SvXMLStylesContext::GetStyle( sal_uInt32 i ) const +{ + return mpImpl->GetStyle( i ); +} + +bool SvXMLStylesContext::IsAutomaticStyle() const +{ + return mpImpl->IsAutomaticStyle(); +} + +SvXMLStyleContext *SvXMLStylesContext::CreateStyleChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + SvXMLStyleContext *pStyle = nullptr; + + if(GetImport().GetDataStylesImport()) + { + pStyle = GetImport().GetDataStylesImport()->CreateChildContext(GetImport(), nElement, + xAttrList, *this); + if (pStyle) + return pStyle; + } + + switch (nElement) + { + case XML_ELEMENT(STYLE, XML_STYLE): + case XML_ELEMENT(STYLE, XML_DEFAULT_STYLE): + { + XmlStyleFamily nFamily = XmlStyleFamily::DATA_STYLE; + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + if( aIter.getToken() == XML_ELEMENT(STYLE, XML_FAMILY) ) + { + nFamily = GetFamily( aIter.toString() ); + break; + } + } + pStyle = XML_ELEMENT(STYLE, XML_STYLE)==nElement + ? CreateStyleStyleChildContext( nFamily, nElement, xAttrList ) + : CreateDefaultStyleStyleChildContext( nFamily, nElement, xAttrList ); + break; + } + case XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY_CONFIGURATION): + pStyle = new XMLIndexBibliographyConfigurationContext(GetImport()); + break; + case XML_ELEMENT(TEXT, XML_NOTES_CONFIGURATION): + pStyle = new XMLFootnoteConfigurationImportContext( + GetImport(), nElement, xAttrList); + break; + case XML_ELEMENT(TEXT, XML_LINENUMBERING_CONFIGURATION): + pStyle = new XMLLineNumberingImportContext(GetImport()); + break; + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT): + case XML_ELEMENT(STYLE, XML_DEFAULT_PAGE_LAYOUT): + { + //there is not page family in ODF now, so I specify one for it + bool bDefaultStyle = XML_ELEMENT(STYLE, XML_DEFAULT_PAGE_LAYOUT) == nElement; + pStyle = new PageStyleContext( GetImport(), *this, bDefaultStyle ); + } + break; + case XML_ELEMENT(TEXT, XML_LIST_STYLE): + pStyle = new SvxXMLListStyleContext( GetImport() ); + break; + case XML_ELEMENT(TEXT, XML_OUTLINE_STYLE): + pStyle = new SvxXMLListStyleContext( GetImport(), true ); + break; + + // FillStyles + + case XML_ELEMENT(DRAW, XML_GRADIENT): + { + pStyle = new XMLGradientStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_HATCH): + { + pStyle = new XMLHatchStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_FILL_IMAGE): + { + pStyle = new XMLBitmapStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_OPACITY): + { + pStyle = new XMLTransGradientStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_MARKER): + { + pStyle = new XMLMarkerStyleContext( GetImport(), nElement, xAttrList ); + break; + } + case XML_ELEMENT(DRAW, XML_STROKE_DASH): + { + pStyle = new XMLDashStyleContext( GetImport(), nElement, xAttrList ); + break; + } + } + + if (!pStyle) + SAL_WARN("xmloff", "Unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement)); + + return pStyle; +} + +SvXMLStyleContext *SvXMLStylesContext::CreateStyleStyleChildContext( + XmlStyleFamily nFamily, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList > & /*xAttrList*/ ) +{ + SvXMLStyleContext *pStyle = nullptr; + + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + case XmlStyleFamily::TEXT_TEXT: + case XmlStyleFamily::TEXT_SECTION: + pStyle = new XMLTextStyleContext( GetImport(), *this, nFamily ); + break; + + case XmlStyleFamily::TEXT_RUBY: + pStyle = new XMLPropStyleContext( GetImport(), *this, nFamily ); + break; +#if !ENABLE_WASM_STRIP_CHART + // WASM_CHART change + case XmlStyleFamily::SCH_CHART_ID: + pStyle = new XMLChartStyleContext( GetImport(), *this, nFamily ); + break; +#endif + case XmlStyleFamily::SD_GRAPHICS_ID: + case XmlStyleFamily::SD_PRESENTATION_ID: + case XmlStyleFamily::SD_POOL_ID: + pStyle = new XMLShapeStyleContext( GetImport(), *this, nFamily ); + break; + default: break; + } + + return pStyle; +} + +SvXMLStyleContext *SvXMLStylesContext::CreateDefaultStyleStyleChildContext( + XmlStyleFamily /*nFamily*/, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList > & ) +{ + return nullptr; +} + +bool SvXMLStylesContext::InsertStyleFamily( XmlStyleFamily ) const +{ + return true; +} + +XmlStyleFamily SvXMLStylesContext::GetFamily( std::u16string_view rValue ) +{ + XmlStyleFamily nFamily = XmlStyleFamily::DATA_STYLE; + if( IsXMLToken( rValue, XML_PARAGRAPH ) ) + { + nFamily = XmlStyleFamily::TEXT_PARAGRAPH; + } + else if( IsXMLToken( rValue, XML_TEXT ) ) + { + nFamily = XmlStyleFamily::TEXT_TEXT; + } + else if( IsXMLToken( rValue, XML_DATA_STYLE ) ) + { + nFamily = XmlStyleFamily::DATA_STYLE; + } + else if ( IsXMLToken( rValue, XML_SECTION ) ) + { + nFamily = XmlStyleFamily::TEXT_SECTION; + } + else if( IsXMLToken( rValue, XML_TABLE ) ) + { + nFamily = XmlStyleFamily::TABLE_TABLE; + } + else if( IsXMLToken( rValue, XML_TABLE_COLUMN ) ) + nFamily = XmlStyleFamily::TABLE_COLUMN; + else if( IsXMLToken( rValue, XML_TABLE_ROW ) ) + nFamily = XmlStyleFamily::TABLE_ROW; + else if( IsXMLToken( rValue, XML_TABLE_CELL ) ) + nFamily = XmlStyleFamily::TABLE_CELL; + else if ( rValue == XML_STYLE_FAMILY_SD_GRAPHICS_NAME ) + { + nFamily = XmlStyleFamily::SD_GRAPHICS_ID; + } + else if ( rValue == XML_STYLE_FAMILY_SD_PRESENTATION_NAME ) + { + nFamily = XmlStyleFamily::SD_PRESENTATION_ID; + } + else if ( rValue == XML_STYLE_FAMILY_SD_POOL_NAME ) + { + nFamily = XmlStyleFamily::SD_POOL_ID; + } + else if ( rValue == XML_STYLE_FAMILY_SD_DRAWINGPAGE_NAME ) + { + nFamily = XmlStyleFamily::SD_DRAWINGPAGE_ID; + } + else if ( rValue == XML_STYLE_FAMILY_SCH_CHART_NAME ) + { + nFamily = XmlStyleFamily::SCH_CHART_ID; + } + else if ( IsXMLToken( rValue, XML_RUBY ) ) + { + nFamily = XmlStyleFamily::TEXT_RUBY; + } + + return nFamily; +} + +rtl::Reference < SvXMLImportPropertyMapper > SvXMLStylesContext::GetImportPropertyMapper( + XmlStyleFamily nFamily ) const +{ + rtl::Reference < SvXMLImportPropertyMapper > xMapper; + + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + if( !mxParaImpPropMapper.is() ) + { + SvXMLStylesContext * pThis = const_cast(this); + pThis->mxParaImpPropMapper = + pThis->GetImport().GetTextImport() + ->GetParaImportPropertySetMapper(); + } + xMapper = mxParaImpPropMapper; + break; + case XmlStyleFamily::TEXT_TEXT: + if( !mxTextImpPropMapper.is() ) + { + SvXMLStylesContext * pThis = const_cast(this); + pThis->mxTextImpPropMapper = + pThis->GetImport().GetTextImport() + ->GetTextImportPropertySetMapper(); + } + xMapper = mxTextImpPropMapper; + break; + + case XmlStyleFamily::TEXT_SECTION: + // don't cache section mapper, as it's rarely used + // *sigh*, cast to non-const, because this is a const method, + // but SvXMLImport::GetTextImport() isn't. + xMapper = const_cast(this)->GetImport().GetTextImport()-> + GetSectionImportPropertySetMapper(); + break; + + case XmlStyleFamily::TEXT_RUBY: + // don't cache section mapper, as it's rarely used + // *sigh*, cast to non-const, because this is a const method, + // but SvXMLImport::GetTextImport() isn't. + xMapper = const_cast(this)->GetImport().GetTextImport()-> + GetRubyImportPropertySetMapper(); + break; + + case XmlStyleFamily::SD_GRAPHICS_ID: + case XmlStyleFamily::SD_PRESENTATION_ID: + case XmlStyleFamily::SD_POOL_ID: + if(!mxShapeImpPropMapper.is()) + { + rtl::Reference< XMLShapeImportHelper > aImpHelper = const_cast(GetImport()).GetShapeImport(); + const_cast(this)->mxShapeImpPropMapper = + aImpHelper->GetPropertySetMapper(); + } + xMapper = mxShapeImpPropMapper; + break; +#if !ENABLE_WASM_STRIP_CHART + // WASM_CHART change + case XmlStyleFamily::SCH_CHART_ID: + if( ! mxChartImpPropMapper.is() ) + { + XMLPropertySetMapper *const pPropMapper = new XMLChartPropertySetMapper(nullptr); + mxChartImpPropMapper = new XMLChartImportPropertyMapper( pPropMapper, GetImport() ); + } + xMapper = mxChartImpPropMapper; + break; +#endif + case XmlStyleFamily::PAGE_MASTER: + if( ! mxPageImpPropMapper.is() ) + { + XMLPropertySetMapper *pPropMapper = + new XMLPageMasterPropSetMapper(); + mxPageImpPropMapper = + new PageMasterImportPropertyMapper( pPropMapper, + const_cast(this)->GetImport() ); + } + xMapper = mxPageImpPropMapper; + break; + default: break; + } + + return xMapper; +} + +Reference < XAutoStyleFamily > SvXMLStylesContext::GetAutoStyles( XmlStyleFamily nFamily ) const +{ + Reference < XAutoStyleFamily > xAutoStyles; + if( XmlStyleFamily::TEXT_TEXT == nFamily || XmlStyleFamily::TEXT_PARAGRAPH == nFamily) + { + bool bPara = XmlStyleFamily::TEXT_PARAGRAPH == nFamily; + if( !bPara && mxTextAutoStyles.is() ) + xAutoStyles = mxTextAutoStyles; + else if( bPara && mxParaAutoStyles.is() ) + xAutoStyles = mxParaAutoStyles; + else + { + OUString sName(bPara ? std::u16string_view( u"ParagraphStyles" ): std::u16string_view( u"CharacterStyles" )); + Reference< XAutoStylesSupplier > xAutoStylesSupp( GetImport().GetModel(), UNO_QUERY ); + Reference< XAutoStyles > xAutoStyleFamilies = xAutoStylesSupp->getAutoStyles(); + if (xAutoStyleFamilies->hasByName(sName)) + { + Any aAny = xAutoStyleFamilies->getByName( sName ); + aAny >>= xAutoStyles; + if( bPara ) + const_cast(this)->mxParaAutoStyles = xAutoStyles; + else + const_cast(this)->mxTextAutoStyles = xAutoStyles; + } + } + } + return xAutoStyles; +} + +Reference < XNameContainer > SvXMLStylesContext::GetStylesContainer( + XmlStyleFamily nFamily ) const +{ + Reference < XNameContainer > xStyles; + OUString sName; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + if( mxParaStyles.is() ) + xStyles = mxParaStyles; + else + sName = "ParagraphStyles"; + break; + + case XmlStyleFamily::TEXT_TEXT: + if( mxTextStyles.is() ) + xStyles = mxTextStyles; + else + sName = "CharacterStyles"; + break; + default: break; + } + if( !xStyles.is() && !sName.isEmpty() ) + { + Reference< XStyleFamiliesSupplier > xFamiliesSupp( + GetImport().GetModel(), UNO_QUERY ); + if ( xFamiliesSupp.is() ) + { + Reference< XNameAccess > xFamilies = xFamiliesSupp->getStyleFamilies(); + if (xFamilies->hasByName(sName)) + { + xStyles.set(xFamilies->getByName( sName ),uno::UNO_QUERY); + + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + const_cast(this)->mxParaStyles = xStyles; + break; + + case XmlStyleFamily::TEXT_TEXT: + const_cast(this)->mxTextStyles = xStyles; + break; + default: break; + } + } + } + } + + return xStyles; +} + +OUString SvXMLStylesContext::GetServiceName( XmlStyleFamily nFamily ) const +{ + OUString sServiceName; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + sServiceName = gsParaStyleServiceName; + break; + case XmlStyleFamily::TEXT_TEXT: + sServiceName = gsTextStyleServiceName; + break; + default: break; + } + + return sServiceName; +} + +SvXMLStylesContext::SvXMLStylesContext( SvXMLImport& rImport, bool bAuto ) : + SvXMLImportContext( rImport ), + mpImpl( new SvXMLStylesContext_Impl( bAuto ) ) +{ +} + +SvXMLStylesContext::~SvXMLStylesContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLStylesContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLStyleContext *pStyle = + CreateStyleChildContext( nElement, xAttrList ); + if( pStyle ) + { + if( !pStyle->IsTransient() ) + mpImpl->AddStyle( pStyle ); + return pStyle; + } + + return nullptr; +} + +void SvXMLStylesContext::AddStyle(SvXMLStyleContext& rNew) +{ + mpImpl->AddStyle( &rNew ); +} + +void SvXMLStylesContext::dispose() +{ + mpImpl->dispose(); +} + +void SvXMLStylesContext::CopyAutoStylesToDoc() +{ + sal_uInt32 nCount = GetStyleCount(); + sal_uInt32 i; + for( i = 0; i < nCount; i++ ) + { + SvXMLStyleContext *pStyle = GetStyle( i ); + if( !pStyle || ( pStyle->GetFamily() != XmlStyleFamily::TEXT_TEXT && + pStyle->GetFamily() != XmlStyleFamily::TEXT_PARAGRAPH && + pStyle->GetFamily() != XmlStyleFamily::TABLE_CELL ) ) + continue; + pStyle->CreateAndInsert( false ); + } +} + +void SvXMLStylesContext::CopyStylesToDoc( bool bOverwrite, + bool bFinish ) +{ + // pass 1: create text, paragraph and frame styles + sal_uInt32 nCount = GetStyleCount(); + sal_uInt32 i; + + for( i = 0; i < nCount; i++ ) + { + SvXMLStyleContext *pStyle = GetStyle( i ); + if( !pStyle ) + continue; + + if (pStyle->IsDefaultStyle()) + { + if (bOverwrite) pStyle->SetDefaults(); + } + else if( InsertStyleFamily( pStyle->GetFamily() ) ) + pStyle->CreateAndInsert( bOverwrite ); + } + + // pass 2: create list styles (they require char styles) + for( i=0; iIsDefaultStyle()) + continue; + + if( InsertStyleFamily( pStyle->GetFamily() ) ) + pStyle->CreateAndInsertLate( bOverwrite ); + } + + // pass3: finish creation of styles + if( bFinish ) + FinishStyles( bOverwrite ); +} + +void SvXMLStylesContext::FinishStyles( bool bOverwrite ) +{ + sal_uInt32 nCount = GetStyleCount(); + for( sal_uInt32 i=0; iIsValid() || pStyle->IsDefaultStyle() ) + continue; + + if( InsertStyleFamily( pStyle->GetFamily() ) ) + pStyle->Finish( bOverwrite ); + } +} + +const SvXMLStyleContext *SvXMLStylesContext::FindStyleChildContext( + XmlStyleFamily nFamily, + const OUString& rName, + bool bCreateIndex ) const +{ + return mpImpl->FindStyleChildContext( nFamily, rName, bCreateIndex ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmltabe.cxx b/xmloff/source/style/xmltabe.cxx new file mode 100644 index 000000000..661caedf6 --- /dev/null +++ b/xmloff/source/style/xmltabe.cxx @@ -0,0 +1,120 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_tabstop_style[] = +{ + { XML_LEFT, style::TabAlign_LEFT }, + { XML_CENTER, style::TabAlign_CENTER }, + { XML_RIGHT, style::TabAlign_RIGHT }, + { XML_CHAR, style::TabAlign_DECIMAL }, + { XML_DEFAULT, style::TabAlign_DEFAULT }, // ????????????????????????????????????? + { XML_TOKEN_INVALID, style::TabAlign(0) } +}; + +void SvxXMLTabStopExport::exportTabStop( const css::style::TabStop* pTabStop ) +{ + SvXMLUnitConverter& rUnitConv = rExport.GetMM100UnitConverter(); + + // text:level + OUStringBuffer sBuffer; + + // position attribute + rUnitConv.convertMeasureToXML( sBuffer, pTabStop->Position ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_POSITION, + sBuffer.makeStringAndClear() ); + + // type attribute + if( style::TabAlign_LEFT != pTabStop->Alignment ) + { + SvXMLUnitConverter::convertEnum( sBuffer, pTabStop->Alignment, + pXML_tabstop_style ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_TYPE, + sBuffer.makeStringAndClear() ); + } + + // char + if( style::TabAlign_DECIMAL == pTabStop->Alignment && + pTabStop->DecimalChar != 0 ) + { + sBuffer.append( pTabStop->DecimalChar ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_CHAR, + sBuffer.makeStringAndClear() ); + } + + // leader-char + if( ' ' != pTabStop->FillChar && 0 != pTabStop->FillChar ) + { + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEADER_STYLE, + GetXMLToken('.' == pTabStop->FillChar ? XML_DOTTED + : XML_SOLID) ); + + sBuffer.append( pTabStop->FillChar ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LEADER_TEXT, + sBuffer.makeStringAndClear() ); + } + + SvXMLElementExport rElem( rExport, XML_NAMESPACE_STYLE, XML_TAB_STOP, + true, true ); +} + + +SvxXMLTabStopExport::SvxXMLTabStopExport( + SvXMLExport& rExp) + : rExport( rExp ) +{ +} + +void SvxXMLTabStopExport::Export( const uno::Any& rAny ) +{ + uno::Sequence< css::style::TabStop> aSeq; + if(!(rAny >>= aSeq)) + { + OSL_FAIL( "SvxXMLTabStopExport needs a Sequence css::style::TabStop>" ); + } + else + { + SvXMLElementExport rElem( rExport, XML_NAMESPACE_STYLE, XML_TAB_STOPS, + true, true ); + + for( const auto& rTab : std::as_const(aSeq) ) + { + if( style::TabAlign_DEFAULT != rTab.Alignment ) + exportTabStop( &rTab ); + } + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/style/xmltabi.cxx b/xmloff/source/style/xmltabi.cxx new file mode 100644 index 000000000..601c3f5fd --- /dev/null +++ b/xmloff/source/style/xmltabi.cxx @@ -0,0 +1,186 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +class SvxXMLTabStopContext_Impl : public SvXMLImportContext +{ +private: + style::TabStop aTabStop; + +public: + + SvxXMLTabStopContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList > & xAttrList ); + + const style::TabStop& getTabStop() const { return aTabStop; } +}; + + +SvxXMLTabStopContext_Impl::SvxXMLTabStopContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< xml::sax::XFastAttributeList > & xAttrList ) +: SvXMLImportContext( rImport ) +{ + aTabStop.Position = 0; + aTabStop.Alignment = style::TabAlign_LEFT; + aTabStop.DecimalChar = ','; + aTabStop.FillChar = ' '; + sal_Unicode cTextFillChar = 0; + + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(STYLE, XML_POSITION): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nVal, aIter.toView())) + { + aTabStop.Position = nVal; + } + break; + case XML_ELEMENT(STYLE, XML_TYPE): + if( IsXMLToken( aIter, XML_LEFT ) ) + { + aTabStop.Alignment = style::TabAlign_LEFT; + } + else if( IsXMLToken( aIter, XML_RIGHT ) ) + { + aTabStop.Alignment = style::TabAlign_RIGHT; + } + else if( IsXMLToken( aIter, XML_CENTER ) ) + { + aTabStop.Alignment = style::TabAlign_CENTER; + } + else if( IsXMLToken( aIter, XML_CHAR ) ) + { + aTabStop.Alignment = style::TabAlign_DECIMAL; + } + else if( IsXMLToken( aIter, XML_DEFAULT ) ) + { + aTabStop.Alignment = style::TabAlign_DEFAULT; + } + break; + case XML_ELEMENT(STYLE, XML_CHAR): + if( !aIter.isEmpty() ) + aTabStop.DecimalChar = aIter.toString()[0]; + break; + case XML_ELEMENT(STYLE, XML_LEADER_STYLE): + if( IsXMLToken( aIter, XML_NONE ) ) + aTabStop.FillChar = ' '; + else if( IsXMLToken( aIter, XML_DOTTED ) ) + aTabStop.FillChar = '.'; + else + aTabStop.FillChar = '_'; + break; + case XML_ELEMENT(STYLE, XML_LEADER_TEXT): + if( !aIter.isEmpty() ) + cTextFillChar = aIter.toString()[0]; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( cTextFillChar != 0 && aTabStop.FillChar != ' ' ) + aTabStop.FillChar = cTextFillChar; +} + + +SvxXMLTabStopImportContext::SvxXMLTabStopImportContext( + SvXMLImport& rImport, sal_Int32 nElement, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ) +: XMLElementPropertyContext( rImport, nElement, rProp, rProps ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SvxXMLTabStopImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + if( nElement == XML_ELEMENT(STYLE, XML_TAB_STOP) ) + { + // create new tabstop import context + const rtl::Reference xTabStopContext{ + new SvxXMLTabStopContext_Impl( GetImport(), nElement, xAttrList )}; + + // add new tabstop to array of tabstops + if( !mpTabStops ) + mpTabStops = std::make_unique(); + + mpTabStops->push_back( xTabStopContext ); + + return xTabStopContext; + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +void SvxXMLTabStopImportContext::endFastElement(sal_Int32 nElement) +{ + sal_uInt16 nCount = mpTabStops ? mpTabStops->size() : 0; + uno::Sequence< style::TabStop> aSeq( nCount ); + + if( mpTabStops ) + { + sal_uInt16 nNewCount = 0; + + style::TabStop* pTabStops = aSeq.getArray(); + for( sal_uInt16 i=0; i < nCount; i++ ) + { + SvxXMLTabStopContext_Impl *pTabStopContext = (*mpTabStops)[i].get(); + const style::TabStop& rTabStop = pTabStopContext->getTabStop(); + bool bDflt = style::TabAlign_DEFAULT == rTabStop.Alignment; + if( !bDflt || 0==i ) + { + *pTabStops++ = pTabStopContext->getTabStop(); + nNewCount++; + } + if( bDflt && 0==i ) + break; + } + + if( nCount != nNewCount ) + aSeq.realloc( nNewCount ); + } + aProp.maValue <<= aSeq; + + SetInsert( true ); + XMLElementPropertyContext::endFastElement(nElement); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/table/XMLTableExport.cxx b/xmloff/source/table/XMLTableExport.cxx new file mode 100644 index 000000000..c9e306f5e --- /dev/null +++ b/xmloff/source/table/XMLTableExport.cxx @@ -0,0 +1,707 @@ +/* -*- 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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "table.hxx" + +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; + +#define MAP_(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_010, false } +#define CMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TABLE_COLUMN,context) +#define RMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TABLE_ROW,context) +#define CELLMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TABLE_CELL,context) +#define MAP_END { nullptr, 0, XML_EMPTY, 0, 0, SvtSaveOptions::ODFSVER_010, false } + +const XMLPropertyMapEntry* getColumnPropertiesMap() +{ + static const XMLPropertyMapEntry aXMLColumnProperties[] = + { + CMAP( "Width", XML_NAMESPACE_STYLE, XML_COLUMN_WIDTH, XML_TYPE_MEASURE, 0 ), + CMAP( "OptimalWidth", XML_NAMESPACE_STYLE, XML_USE_OPTIMAL_COLUMN_WIDTH, XML_TYPE_BOOL, 0 ), + MAP_END + }; + + return &aXMLColumnProperties[0]; +} + +const XMLPropertyMapEntry* getRowPropertiesMap() +{ + static const XMLPropertyMapEntry aXMLRowProperties[] = + { + RMAP( "Height", XML_NAMESPACE_STYLE, XML_ROW_HEIGHT, XML_TYPE_MEASURE, 0 ), + RMAP( "MinHeight", XML_NAMESPACE_STYLE, XML_MIN_ROW_HEIGHT, XML_TYPE_MEASURE, 0 ), + RMAP( "OptimalHeight", XML_NAMESPACE_STYLE, XML_USE_OPTIMAL_ROW_HEIGHT, XML_TYPE_BOOL, 0 ), + MAP_END + }; + + return &aXMLRowProperties[0]; +} + +const XMLPropertyMapEntry* getCellPropertiesMap() +{ + static const XMLPropertyMapEntry aXMLCellProperties[] = + { + CELLMAP( "RotateAngle", XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_SD_TYPE_CELL_ROTATION_ANGLE, 0), + MAP_END + }; + + return &aXMLCellProperties[0]; +} + +namespace { + +class StringStatisticHelper +{ +private: + std::map< OUString, sal_Int32 > mStats; + +public: + void add( const OUString& rStyleName ); + void clear() { mStats.clear(); } + + sal_Int32 getModeString( /* out */ OUString& rModeString ); +}; + +} + +void StringStatisticHelper::add( const OUString& rStyleName ) +{ + std::map< OUString, sal_Int32 >::iterator iter( mStats.find( rStyleName ) ); + if( iter == mStats.end() ) + { + mStats[rStyleName] = 1; + } + else + { + (*iter).second += 1; + } +} + +sal_Int32 StringStatisticHelper::getModeString( OUString& rStyleName ) +{ + sal_Int32 nMax = 0; + for( const auto& rStatsEntry : mStats ) + { + if( rStatsEntry.second > nMax ) + { + rStyleName = rStatsEntry.first; + nMax = rStatsEntry.second; + } + } + + return nMax; +} + +namespace { + +class XMLCellExportPropertyMapper : public SvXMLExportPropertyMapper +{ +public: + using SvXMLExportPropertyMapper::SvXMLExportPropertyMapper; + /** this method is called for every item that has the + MID_FLAG_SPECIAL_ITEM_EXPORT flag set */ + virtual void handleSpecialItem(SvXMLAttributeList&, const XMLPropertyState&, const SvXMLUnitConverter&, + const SvXMLNamespaceMap&, const std::vector*, sal_uInt32) const override + { + // the SpecialItem NumberFormat must not be handled by this method + } +}; + +} + +XMLTableExport::XMLTableExport(SvXMLExport& rExp, const rtl::Reference< SvXMLExportPropertyMapper >& xExportPropertyMapper, const rtl::Reference< XMLPropertyHandlerFactory >& xFactoryRef ) +: mrExport( rExp ) +, mbExportTables( false ) +, mbWriter( false ) +{ + Reference< XMultiServiceFactory > xFac( rExp.GetModel(), UNO_QUERY ); + if( xFac.is() ) try + { + const Sequence< OUString > sSNS( xFac->getAvailableServiceNames() ); + const OUString* pSNS = std::find_if(sSNS.begin(), sSNS.end(), + [](const OUString& rSNS) { + return rSNS == "com.sun.star.drawing.TableShape" + || rSNS == "com.sun.star.style.TableStyle"; }); + if (pSNS != sSNS.end()) + { + mbExportTables = true; + mbWriter = (*pSNS == "com.sun.star.style.TableStyle"); + } + } + catch(const Exception&) + { + } + + if (mbWriter) + { + mxCellExportPropertySetMapper = new XMLCellExportPropertyMapper(new XMLTextPropertySetMapper(TextPropMap::CELL, true)); + } + else + { + mxCellExportPropertySetMapper = xExportPropertyMapper; + mxCellExportPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp)); + mxCellExportPropertySetMapper->ChainExportMapper(new SvXMLExportPropertyMapper(new XMLPropertySetMapper(getCellPropertiesMap(), xFactoryRef, true))); + } + + mxRowExportPropertySetMapper = new SvXMLExportPropertyMapper( new XMLPropertySetMapper( getRowPropertiesMap(), xFactoryRef, true ) ); + mxColumnExportPropertySetMapper = new SvXMLExportPropertyMapper( new XMLPropertySetMapper( getColumnPropertiesMap(), xFactoryRef, true ) ); + + mrExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_COLUMN, + OUString(XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME), + mxColumnExportPropertySetMapper.get(), + OUString(XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX)); + mrExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_ROW, + OUString(XML_STYLE_FAMILY_TABLE_ROW_STYLES_NAME), + mxRowExportPropertySetMapper.get(), + OUString(XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX)); + mrExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_CELL, + OUString(XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME), + mxCellExportPropertySetMapper.get(), + OUString(XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX)); +} + +XMLTableExport::~XMLTableExport () +{ +} + +static bool has_states( const std::vector< XMLPropertyState >& xPropStates ) +{ + return std::any_of(xPropStates.cbegin(), xPropStates.cend(), + [](const XMLPropertyState& rPropertyState) { return rPropertyState.mnIndex != -1; }); +} + + void XMLTableExport::collectTableAutoStyles(const Reference < XColumnRowRange >& xColumnRowRange) + { + if( !mbExportTables ) + return; + + auto xTableInfo = std::make_shared(); + maTableInfoMap[xColumnRowRange] = xTableInfo; + + try + { + Reference< XIndexAccess > xIndexAccessCols( xColumnRowRange->getColumns(), UNO_QUERY_THROW ); + const sal_Int32 nColumnCount = xIndexAccessCols->getCount(); + for( sal_Int32 nColumn = 0; nColumn < nColumnCount; ++nColumn ) try + { + Reference< XPropertySet > xPropSet( xIndexAccessCols->getByIndex(nColumn) , UNO_QUERY_THROW ); + std::vector aPropStates(mxColumnExportPropertySetMapper->Filter(mrExport, xPropSet)); + + if( has_states( aPropStates ) ) + { + const OUString sStyleName( mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TABLE_COLUMN, std::move(aPropStates)) ); + Reference< XInterface > xKey( xPropSet, UNO_QUERY ); + xTableInfo->maColumnStyleMap[xKey] = sStyleName; + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.table", "exception during column style collection!"); + } + + Reference< XIndexAccess > xIndexAccessRows( xColumnRowRange->getRows(), UNO_QUERY_THROW ); + const sal_Int32 nRowCount = xIndexAccessRows->getCount(); + xTableInfo->maDefaultRowCellStyles.resize(nRowCount); + + StringStatisticHelper aStringStatistic; + + for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow ) + try + { + Reference< XPropertySet > xPropSet( xIndexAccessRows->getByIndex(nRow) , UNO_QUERY_THROW ); + std::vector aRowPropStates(mxRowExportPropertySetMapper->Filter(mrExport, xPropSet)); + + if( has_states( aRowPropStates ) ) + { + const OUString sStyleName( mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TABLE_ROW, std::move(aRowPropStates)) ); + Reference< XInterface > xKey( xPropSet, UNO_QUERY ); + xTableInfo->maRowStyleMap[xKey] = sStyleName; + } + + // get the current row + Reference< XCellRange > xCellRange( xPropSet, UNO_QUERY_THROW ); + for ( sal_Int32 nColumn = 0; nColumn < nColumnCount; ++nColumn ) + { + // get current cell, remarks row index is 0, because we get the range for each row separate + Reference< XPropertySet > xCellSet( xCellRange->getCellByPosition(nColumn, 0), UNO_QUERY_THROW ); + + // get style + OUString sParentStyleName; + Reference< XPropertySetInfo > xPropertySetInfo( xCellSet->getPropertySetInfo() ); + if( xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName("Style") ) + { + Reference< XStyle > xStyle( xCellSet->getPropertyValue("Style"), UNO_QUERY ); + if( xStyle.is() ) + sParentStyleName = xStyle->getName(); + } + + // create auto style, if needed + OUString sStyleName; + std::vector aCellPropStates(mxCellExportPropertySetMapper->Filter(mrExport, xCellSet)); + if( has_states( aCellPropStates ) ) + sStyleName = mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TABLE_CELL, std::move(aCellPropStates)); + else + sStyleName = sParentStyleName; + + if( !sStyleName.isEmpty() ) + { + Reference< XInterface > xKey( xCellSet, UNO_QUERY ); + xTableInfo->maCellStyleMap[xKey] = sStyleName; + } + + // create auto style for text + Reference< XText > xText(xCellSet, UNO_QUERY); + if(xText.is() && !xText->getString().isEmpty()) + GetExport().GetTextParagraphExport()->collectTextAutoStyles( xText ); + + aStringStatistic.add( sStyleName ); + } + + OUString sDefaultCellStyle; + if( aStringStatistic.getModeString( sDefaultCellStyle ) > 1 ) + xTableInfo->maDefaultRowCellStyles[nRow] = sDefaultCellStyle; + + aStringStatistic.clear(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.table", "exception during column style collection!"); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.table", "exception caught!"); + } + } + + void XMLTableExport::exportTable( const Reference < XColumnRowRange >& xColumnRowRange ) + { + if( !mbExportTables ) + return; + + try + { + std::shared_ptr< XMLTableInfo > xTableInfo( maTableInfoMap[xColumnRowRange] ); + + // get row and column count + Reference< XIndexAccess > xIndexAccess( xColumnRowRange->getRows(), UNO_QUERY_THROW ); + Reference< XIndexAccess > xIndexAccessCols( xColumnRowRange->getColumns(), UNO_QUERY_THROW ); + + const sal_Int32 rowCount = xIndexAccess->getCount(); + const sal_Int32 columnCount = xIndexAccessCols->getCount(); + + SvXMLElementExport tableElement( mrExport, XML_NAMESPACE_TABLE, XML_TABLE, true, true ); + + // export table columns + ExportTableColumns( xIndexAccessCols, xTableInfo ); + + // start iterating rows and columns + for ( sal_Int32 rowIndex = 0; rowIndex < rowCount; rowIndex++ ) + { + // get the current row + Reference< XCellRange > xCellRange( xIndexAccess->getByIndex(rowIndex), UNO_QUERY_THROW ); + + OUString sDefaultCellStyle; + + // table:style-name + if( xTableInfo ) + { + Reference< XInterface > xKey( xCellRange, UNO_QUERY ); + const OUString sStyleName( xTableInfo->maRowStyleMap[xKey] ); + if( !sStyleName.isEmpty() ) + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sStyleName ); + + sDefaultCellStyle = xTableInfo->maDefaultRowCellStyles[rowIndex]; + if( !sDefaultCellStyle.isEmpty() ) + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DEFAULT_CELL_STYLE_NAME, sDefaultCellStyle ); + } + + // write row element + SvXMLElementExport tableRowElement( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true ); + + for ( sal_Int32 columnIndex = 0; columnIndex < columnCount; columnIndex++ ) + { + // get current cell, remarks row index is 0, because we get the range for each row separate + Reference< XCell > xCell( xCellRange->getCellByPosition(columnIndex, 0), UNO_SET_THROW ); + + // use XMergeableCell interface from offapi + Reference< XMergeableCell > xMergeableCell( xCell, UNO_QUERY_THROW ); + + // export cell + ExportCell( xCell, xTableInfo, sDefaultCellStyle ); + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.table", "" ); + } + } + +// Export the table columns + + void XMLTableExport::ExportTableColumns( const Reference < XIndexAccess >& xtableColumnsIndexAccess, const std::shared_ptr< XMLTableInfo >& rTableInfo ) + { + const sal_Int32 nColumnCount = xtableColumnsIndexAccess->getCount(); + for( sal_Int32 nColumn = 0; nColumn < nColumnCount; ++nColumn ) + { + Reference< XPropertySet > xColumnProperties( xtableColumnsIndexAccess->getByIndex(nColumn) , UNO_QUERY ); + if ( xColumnProperties.is() ) + { + // table:style-name + if( rTableInfo ) + { + Reference< XInterface > xKey( xColumnProperties, UNO_QUERY ); + const OUString sStyleName( rTableInfo->maColumnStyleMap[xKey] ); + if( !sStyleName.isEmpty() ) + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sStyleName ); + } + + // TODO: all columns first have to be checked if someone + // have identical properties. If yes, attr table:number-columns-repeated + // has to be written. + SvXMLElementExport tableColumnElement( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); + } + } + } + +// ODF export for a table cell. + + void XMLTableExport::ExportCell( const Reference < XCell >& xCell, const std::shared_ptr< XMLTableInfo >& rTableInfo, std::u16string_view rDefaultCellStyle ) + { + bool bIsMerged = false; + sal_Int32 nRowSpan = 0; + sal_Int32 nColSpan = 0; + + try + { + if( rTableInfo ) + { + // table:style-name + Reference< XInterface > xKey( xCell, UNO_QUERY ); + const OUString sStyleName( rTableInfo->maCellStyleMap[xKey] ); + if( !sStyleName.isEmpty() && (sStyleName != rDefaultCellStyle) ) + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sStyleName ); + } + + Reference< XMergeableCell > xMerge( xCell, UNO_QUERY ); + if( xMerge.is() ) + { + bIsMerged = xMerge->isMerged(); + nRowSpan = xMerge->getRowSpan(); + nColSpan = xMerge->getColumnSpan(); + } + SAL_WARN_IF( (nRowSpan < 1) || (nColSpan < 1), "xmloff", "xmloff::XMLTableExport::ExportCell(), illegal row or col span < 1?" ); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.table", "exception while exporting a table cell"); + } + + // table:number-columns-repeated + // todo + + // table:number-columns-spanned + if( nColSpan > 1 ) + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, OUString::number( nColSpan ) ); + + // table:number-rows-spanned + if( nRowSpan > 1 ) + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, OUString::number( nRowSpan ) ); + + // or + SvXMLElementExport tableCellElement( mrExport, XML_NAMESPACE_TABLE, bIsMerged ? XML_COVERED_TABLE_CELL : XML_TABLE_CELL, true, true ); + + // export cells text content + ImpExportText( xCell ); + } + +// ODF export of the text contents of a table cell. +// Remarks: Up to now we only export text contents! +// TODO: Check against nested tables... + + void XMLTableExport::ImpExportText( const Reference< XCell >& xCell ) + { + Reference< XText > xText( xCell, UNO_QUERY ); + if( xText.is() && !xText->getString().isEmpty()) + mrExport.GetTextParagraphExport()->exportText( xText ); + } + +void XMLTableExport::exportTableStyles() +{ + if( !mbExportTables ) + return; + + rtl::Reference aStEx; + OUString sCellStyleName; + if (mbWriter) + { + sCellStyleName = "CellStyles"; + aStEx.set(new XMLCellStyleExport(mrExport)); + } + else + { + // write graphic family styles + sCellStyleName = "cell"; + aStEx.set(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get())); + } + + aStEx->exportStyleFamily(sCellStyleName, OUString(XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME), mxCellExportPropertySetMapper, true, XmlStyleFamily::TABLE_CELL); + + exportTableTemplates(); +} + +// Export the collected automatic styles + +void XMLTableExport::exportAutoStyles() +{ + if( !mbExportTables ) + return; + + mrExport.GetAutoStylePool()->exportXML( XmlStyleFamily::TABLE_COLUMN ); + mrExport.GetAutoStylePool()->exportXML( XmlStyleFamily::TABLE_ROW ); + mrExport.GetAutoStylePool()->exportXML( XmlStyleFamily::TABLE_CELL ); +} + +const TableStyleElement* getTableStyleMap() +{ + static const struct TableStyleElement gTableStyleElements[] = + { + { XML_FIRST_ROW, OUString("first-row") }, + { XML_LAST_ROW, OUString("last-row") }, + { XML_FIRST_COLUMN, OUString("first-column") }, + { XML_LAST_COLUMN, OUString("last-column") }, + { XML_BODY, OUString("body") }, + { XML_EVEN_ROWS, OUString("even-rows") }, + { XML_ODD_ROWS, OUString("odd-rows") }, + { XML_EVEN_COLUMNS, OUString("even-columns") }, + { XML_ODD_COLUMNS, OUString("odd-columns") }, + { XML_BACKGROUND, OUString("background") }, + { XML_TOKEN_END, OUString() } + }; + + return &gTableStyleElements[0]; +} + +const TableStyleElement* getWriterSpecificTableStyleMap() +{ + static const struct TableStyleElement gWriterSpecificTableStyleElements[] = + { + { XML_FIRST_ROW_EVEN_COLUMN, OUString("first-row-even-column") }, + { XML_LAST_ROW_EVEN_COLUMN, OUString("last-row-even-column") }, + { XML_FIRST_ROW_END_COLUMN, OUString("first-row-end-column") }, + { XML_FIRST_ROW_START_COLUMN, OUString("first-row-start-column") }, + { XML_LAST_ROW_END_COLUMN, OUString("last-row-end-column") }, + { XML_LAST_ROW_START_COLUMN, OUString("last-row-start-column") }, + { XML_TOKEN_END, OUString() } + }; + + return &gWriterSpecificTableStyleElements[0]; +} + +static const TableStyleElement* getWriterSpecificTableStyleAttributes() +{ + static const struct TableStyleElement gWriterSpecifitTableStyleAttributes[] = + { + { XML_FIRST_ROW_END_COLUMN, OUString("FirstRowEndColumn") }, + { XML_FIRST_ROW_START_COLUMN, OUString("FirstRowStartColumn") }, + { XML_LAST_ROW_END_COLUMN, OUString("LastRowEndColumn") }, + { XML_LAST_ROW_START_COLUMN, OUString("LastRowStartColumn") }, + { XML_TOKEN_END, OUString() } + }; + + return &gWriterSpecifitTableStyleAttributes[0]; +} + +void XMLTableExport::exportTableTemplates() +{ + if( !mbExportTables ) + return; + + try + { + Reference< XStyleFamiliesSupplier > xFamiliesSupp( mrExport.GetModel(), UNO_QUERY_THROW ); + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + OUString sFamilyName; + if (mbWriter) + sFamilyName = "TableStyles"; + else + sFamilyName = "table"; + + Reference< XIndexAccess > xTableFamily( xFamilies->getByName( sFamilyName ), UNO_QUERY_THROW ); + + for( sal_Int32 nIndex = 0; nIndex < xTableFamily->getCount(); nIndex++ ) try + { + SvtSaveOptions::ODFSaneDefaultVersion eVersion = mrExport.getSaneDefaultVersion(); + + Reference< XStyle > xTableStyle( xTableFamily->getByIndex( nIndex ), UNO_QUERY_THROW ); + if( !xTableStyle->isInUse() ) + continue; + + const TableStyleElement* pElements; + if (mbWriter) + { + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, xTableStyle->getName()); + Reference xTableStylePropSet(xTableStyle, UNO_QUERY_THROW); + pElements = getWriterSpecificTableStyleAttributes(); + while(pElements->meElement != XML_TOKEN_END) + { + try + { + OUString sVal; + xTableStylePropSet->getPropertyValue(pElements->msStyleName) >>= sVal; + mrExport.AddAttribute(XML_NAMESPACE_TABLE, pElements->meElement, sVal); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff", "XMLTableExport::exportTableTemplates(), export Writer specific attributes, exception caught!"); + } + pElements++; + } + } + else + { + // checks if any of the extended version of ODF are set + if (eVersion == SvtSaveOptions::ODFSVER_012_EXT_COMPAT) + { + // tdf#106780 historically this wrong attribute was used + // for the name; write it if extended because LO < 5.3 can + // read only text:style-name, not the correct table:name + mrExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, GetExport().EncodeStyleName( xTableStyle->getName() ) ); + } + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, GetExport().EncodeStyleName(xTableStyle->getName())); + } + + SvXMLElementExport tableTemplate( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_TEMPLATE, true, true ); + + Reference< XNameAccess > xStyleNames( xTableStyle, UNO_QUERY_THROW ); + pElements = getTableStyleMap(); + while( pElements->meElement != XML_TOKEN_END ) + { + try + { + Reference< XStyle > xStyle( xStyleNames->getByName( pElements->msStyleName ), UNO_QUERY ); + if( xStyle.is() ) + { + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, GetExport().EncodeStyleName( xStyle->getName() ) ); + SvXMLElementExport element( mrExport, XML_NAMESPACE_TABLE, pElements->meElement, true, true ); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.table", ""); + } + + pElements++; + } + + if (mbWriter && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0)) + { + pElements = getWriterSpecificTableStyleMap(); + while(pElements->meElement != XML_TOKEN_END) + { + try + { + Reference xStyle(xStyleNames->getByName(pElements->msStyleName), UNO_QUERY); + if(xStyle.is()) + { + mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, GetExport().EncodeStyleName(xStyle->getName())); + SvXMLElementExport element(mrExport, XML_NAMESPACE_LO_EXT, pElements->meElement, true, true); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff", "XMLTableExport::exportTableTemplates(), export Writer specific styles, exception caught!"); + } + pElements++; + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff", "XMLTableExport::exportTableDesigns(), exception caught while exporting a table design!"); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff", "XMLTableExport::exportTableDesigns()"); + } +} + +void XMLCellStyleExport::exportStyleContent(const Reference& /*rStyle*/) +{ +} + +void XMLCellStyleExport::exportStyleAttributes(const Reference& rStyle) +{ + Reference xPropSet(rStyle, UNO_QUERY); + if (!xPropSet.is()) + return; + + Reference xPropSetInfo(xPropSet->getPropertySetInfo()); + static const OUStringLiteral sNumberFormat(u"NumberFormat"); + if (xPropSetInfo->hasPropertyByName(sNumberFormat)) + { + Reference xPropState(xPropSet, UNO_QUERY); + if (xPropState.is() && (PropertyState_DIRECT_VALUE == + xPropState->getPropertyState(sNumberFormat))) + { + sal_Int32 nNumberFormat = 0; + if (xPropSet->getPropertyValue(sNumberFormat) >>= nNumberFormat) + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, + GetExport().getDataStyleName(nNumberFormat)); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/table/XMLTableImport.cxx b/xmloff/source/table/XMLTableImport.cxx new file mode 100644 index 000000000..47923d66c --- /dev/null +++ b/xmloff/source/table/XMLTableImport.cxx @@ -0,0 +1,808 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "table.hxx" + +#include + +#include + +using namespace ::xmloff::token; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; + +namespace { + +struct ColumnInfo +{ + OUString msStyleName; + OUString msDefaultCellStyleName; +}; + +class XMLProxyContext : public SvXMLImportContext +{ +public: + XMLProxyContext( SvXMLImport& rImport, const SvXMLImportContextRef& xParent ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +private: + SvXMLImportContextRef mxParent; +}; + +struct MergeInfo +{ + sal_Int32 mnStartColumn; + sal_Int32 mnStartRow; + sal_Int32 mnEndColumn; + sal_Int32 mnEndRow; + + MergeInfo( sal_Int32 nStartColumn, sal_Int32 nStartRow, sal_Int32 nColumnSpan, sal_Int32 nRowSpan ) + : mnStartColumn( nStartColumn ), mnStartRow( nStartRow ), mnEndColumn( nStartColumn + nColumnSpan - 1 ), mnEndRow( nStartRow + nRowSpan - 1 ) {}; +}; + +} + +class XMLTableImportContext : public SvXMLImportContext +{ +public: + XMLTableImportContext( const rtl::Reference< XMLTableImport >& xThis, Reference< XColumnRowRange > const & xColumnRowRange ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + void InitColumns(); + + SvXMLImportContextRef ImportColumn( const Reference< XFastAttributeList >& xAttrList ); + SvXMLImportContext * ImportRow( const Reference< XFastAttributeList >& xAttrList ); + SvXMLImportContextRef ImportCell( sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList ); + + OUString GetDefaultCellStyleName() const; + + css::uno::Reference< css::table::XTable > mxTable; + Reference< XTableColumns > mxColumns; + Reference< XTableRows > mxRows; + + std::vector< std::shared_ptr< ColumnInfo > > maColumnInfos; + sal_Int32 mnCurrentRow; + sal_Int32 mnCurrentColumn; + + // default cell style name for the current row + OUString msDefaultCellStyleName; + + std::vector< std::shared_ptr< MergeInfo > > maMergeInfos; +}; + +namespace { + +class XMLCellImportContext : public SvXMLImportContext +{ +public: + XMLCellImportContext( SvXMLImport& rImport, + const Reference< XMergeableCell >& xCell, + const OUString& sDefaultCellStyleName, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + sal_Int32 getColumnSpan() const { return mnColSpan; } + sal_Int32 getRowSpan() const { return mnRowSpan; } + sal_Int32 getRepeated() const { return mnRepeated; } + + Reference< XMergeableCell > mxCell; + Reference< XTextCursor > mxCursor; + Reference< XTextCursor > mxOldCursor; + bool mbListContextPushed; + + sal_Int32 mnColSpan, mnRowSpan, mnRepeated; +}; + +class XMLTableTemplateContext : public SvXMLStyleContext +{ +public: + XMLTableTemplateContext( SvXMLImport& rImport ); + + // Create child element. + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual void CreateAndInsert( bool bOverwrite ) override; +protected: + virtual void SetAttribute( sal_Int32 nElement, + const OUString& rValue ) override; +private: + XMLTableTemplate maTableTemplate; + OUString msTemplateStyleName; +}; + +} + + +XMLProxyContext::XMLProxyContext( SvXMLImport& rImport, const SvXMLImportContextRef& xParent ) +: SvXMLImportContext( rImport ) +, mxParent( xParent ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLProxyContext::createFastChildContext( sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList ) +{ + if( mxParent.is() ) + return mxParent->createFastChildContext( nElement, xAttrList ); + return nullptr; +} + + +XMLTableImport::XMLTableImport( SvXMLImport& rImport, const rtl::Reference< XMLPropertySetMapper >& xCellPropertySetMapper, const rtl::Reference< XMLPropertyHandlerFactory >& xFactoryRef ) +: mrImport( rImport ) +{ + bool bWriter = false; + // check if called by Writer + Reference xFac(rImport.GetModel(), UNO_QUERY); + if (xFac.is()) try + { + Sequence sSNS = xFac->getAvailableServiceNames(); + bWriter = comphelper::findValue(sSNS, "com.sun.star.style.TableStyle") != -1; + } + catch(const Exception&) + { + SAL_WARN("xmloff.table", "Error while checking available service names"); + } + + if (bWriter) + { + mxCellImportPropertySetMapper = XMLTextImportHelper::CreateTableCellExtPropMapper(rImport); + } + else + { + mxCellImportPropertySetMapper = new SvXMLImportPropertyMapper( xCellPropertySetMapper, rImport ); + mxCellImportPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImport)); + mxCellImportPropertySetMapper->ChainImportMapper(new SvXMLImportPropertyMapper(new XMLPropertySetMapper(getCellPropertiesMap(), xFactoryRef, true), rImport)); + } + + rtl::Reference < XMLPropertySetMapper > xRowMapper( new XMLPropertySetMapper( getRowPropertiesMap(), xFactoryRef, false ) ); + mxRowImportPropertySetMapper = new SvXMLImportPropertyMapper( xRowMapper, rImport ); + + rtl::Reference < XMLPropertySetMapper > xColMapper( new XMLPropertySetMapper( getColumnPropertiesMap(), xFactoryRef, false ) ); + mxColumnImportPropertySetMapper = new SvXMLImportPropertyMapper( xColMapper, rImport ); +} + +XMLTableImport::~XMLTableImport() +{ +} + +SvXMLImportContext* XMLTableImport::CreateTableContext( Reference< XColumnRowRange > const & xColumnRowRange ) +{ + rtl::Reference< XMLTableImport > xThis( this ); + return new XMLTableImportContext( xThis, xColumnRowRange ); +} + +SvXMLStyleContext* XMLTableImport::CreateTableTemplateContext( sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& /*xAttrList*/ ) +{ + return new XMLTableTemplateContext( mrImport ); +} + +void XMLTableImport::addTableTemplate( const OUString& rsStyleName, XMLTableTemplate& xTableTemplate ) +{ + auto xPtr = std::make_shared(); + xPtr->swap( xTableTemplate ); + maTableTemplates[rsStyleName] = xPtr; +} + +void XMLTableImport::insertTabletemplate(const OUString& rsStyleName, bool bOverwrite) +{ + XMLTableTemplateMap::iterator it = maTableTemplates.find(rsStyleName); + if (it == maTableTemplates.end()) + return; + + try + { + Reference xFamiliesSupp(mrImport.GetModel(), UNO_QUERY_THROW); + Reference xFamilies(xFamiliesSupp->getStyleFamilies()); + + Reference xTableFamily(xFamilies->getByName("TableStyles"), UNO_QUERY_THROW); + Reference xCellFamily(xFamilies->getByName("CellStyles"), UNO_QUERY_THROW); + + const OUString sTemplateName(it->first); + Reference xFactory(mrImport.GetModel(), UNO_QUERY_THROW); + Reference xTemplate(xFactory->createInstance("com.sun.star.style.TableStyle"), UNO_QUERY_THROW); + + std::shared_ptr xT(it->second); + + for (const auto& rStyle : *xT) try + { + const OUString sPropName(rStyle.first); + const OUString sStyleName(rStyle.second); + // Internally unassigned cell styles are stored by display name. + // However table-template elements reference cell styles by its encoded name. + // This loop is looking for cell style by their encoded names. + sal_Int32 nCount = xCellFamily->getCount(); + for (sal_Int32 i=0; i < nCount; ++i) + { + Any xCellStyle = xCellFamily->getByIndex(i); + OUString sEncodedStyleName = mrImport.GetMM100UnitConverter().encodeStyleName( + xCellStyle.get>()->getName()); + if (sEncodedStyleName == sStyleName) + { + xTemplate->replaceByName(sPropName, xCellStyle); + break; + } + } + } + catch (Exception const &) + { + TOOLS_WARN_EXCEPTION("xmloff.table", "XMLTableImport::insertTabletemplate()"); + } + + if (xTemplate.is()) + { + if (xTableFamily->hasByName(sTemplateName) && bOverwrite) + xTableFamily->replaceByName(sTemplateName, Any(xTemplate)); + else + xTableFamily->insertByName(sTemplateName, Any(xTemplate)); + } + } + catch (Exception&) + { + TOOLS_WARN_EXCEPTION("xmloff.table", "XMLTableImport::insertTabletemplate()"); + } +} + +void XMLTableImport::finishStyles() +{ + if( maTableTemplates.empty() ) + return; + + try + { + Reference< XStyleFamiliesSupplier > xFamiliesSupp( mrImport.GetModel(), UNO_QUERY_THROW ); + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + + Reference< XNameContainer > xTableFamily( xFamilies->getByName( "table" ), UNO_QUERY_THROW ); + Reference< XNameAccess > xCellFamily( xFamilies->getByName( "cell" ), UNO_QUERY_THROW ); + + Reference< XSingleServiceFactory > xFactory( xTableFamily, UNO_QUERY_THROW ); + + for( const auto& rTemplate : maTableTemplates ) try + { + const OUString sTemplateName( rTemplate.first ); + Reference< XNameReplace > xTemplate( xFactory->createInstance(), UNO_QUERY_THROW ); + + std::shared_ptr< XMLTableTemplate > xT( rTemplate.second ); + + for( const auto& rStyle : *xT ) try + { + const OUString sPropName( rStyle.first ); + const OUString sStyleName( rStyle.second ); + xTemplate->replaceByName( sPropName, xCellFamily->getByName( sStyleName ) ); + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.table", ""); + } + + if( xTemplate.is() ) + { + if( xTableFamily->hasByName( sTemplateName ) ) + xTableFamily->replaceByName( sTemplateName, Any( xTemplate ) ); + else + xTableFamily->insertByName( sTemplateName, Any( xTemplate ) ); + } + + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.table", ""); + } + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.table", ""); + } +} + + +XMLTableImportContext::XMLTableImportContext( const rtl::Reference< XMLTableImport >& xImporter, Reference< XColumnRowRange > const & xColumnRowRange ) +: SvXMLImportContext( xImporter->mrImport ) +, mxTable( xColumnRowRange, UNO_QUERY ) +, mxColumns( xColumnRowRange->getColumns() ) +, mxRows( xColumnRowRange->getRows() ) +, mnCurrentRow( -1 ) +, mnCurrentColumn( -1 ) +{ +} + +SvXMLImportContextRef XMLTableImportContext::ImportColumn( const Reference< XFastAttributeList >& xAttrList ) +{ + if( mxColumns.is() && (mnCurrentRow == -1) ) try + { + auto xInfo = std::make_shared(); + + sal_Int32 nRepeated = 1; + + // read attributes for the table-column + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED): + nRepeated = aIter.toInt32(); + break; + case XML_ELEMENT(TABLE, XML_STYLE_NAME): + xInfo->msStyleName = aIter.toString(); + break; + case XML_ELEMENT(TABLE, XML_DEFAULT_CELL_STYLE_NAME): + xInfo->msDefaultCellStyleName = aIter.toString(); + break; + case XML_ELEMENT(XML, XML_ID): + //FIXME: TODO + break; + } + } + + if( nRepeated <= 1 ) + { + maColumnInfos.push_back( xInfo ); + } + else + { + maColumnInfos.insert( maColumnInfos.end(), nRepeated, xInfo ); + } + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.table", ""); + } + + return nullptr; +} + +void XMLTableImportContext::InitColumns() +{ + if( !mxColumns.is() ) + return; + + try + { + const sal_Int32 nCount1 = mxColumns->getCount(); + const sal_Int32 nCount2 = sal::static_int_cast< sal_Int32 >( maColumnInfos.size() ); + if( nCount1 < nCount2 ) + mxColumns->insertByIndex( nCount1, nCount2 - nCount1 ); + + SvXMLStylesContext * pAutoStyles = GetImport().GetShapeImport()->GetAutoStylesContext(); + + for( sal_Int32 nCol = 0; nCol < nCount2; nCol++ ) + { + std::shared_ptr< ColumnInfo > xInfo( maColumnInfos[nCol] ); + + if( pAutoStyles && !xInfo->msStyleName.isEmpty() ) + { + const XMLPropStyleContext* pStyle = + dynamic_cast< const XMLPropStyleContext* >( + pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_COLUMN, xInfo->msStyleName) ); + + if( pStyle ) + { + Reference< XPropertySet > xColProps( mxColumns->getByIndex(nCol), UNO_QUERY_THROW ); + const_cast< XMLPropStyleContext* >( pStyle )->FillPropertySet( xColProps ); + } + } + + } + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.table", ""); + } +} + +SvXMLImportContext * XMLTableImportContext::ImportRow( const Reference< XFastAttributeList >& xAttrList ) +{ + if( mxRows.is() ) + { + mnCurrentRow++; + if( mnCurrentRow == 0 ) + InitColumns(); // first init columns + + mnCurrentColumn = -1; + + const sal_Int32 nRowCount = mxRows->getCount(); + if( ( nRowCount - 1) < mnCurrentRow ) + { + const sal_Int32 nCount = mnCurrentRow - nRowCount + 1; + mxRows->insertByIndex( nRowCount, nCount ); + } + + Reference< XPropertySet > xRowSet( mxRows->getByIndex(mnCurrentRow), UNO_QUERY ); + + OUString sStyleName; + + // read attributes for the table-row + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TABLE, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + case XML_ELEMENT(TABLE, XML_DEFAULT_CELL_STYLE_NAME): + msDefaultCellStyleName = aIter.toString(); + break; + case XML_ELEMENT(XML, XML_ID): + //FIXME: TODO + break; + } + } + + if( !sStyleName.isEmpty() ) + { + SvXMLStylesContext * pAutoStyles = GetImport().GetShapeImport()->GetAutoStylesContext(); + if( pAutoStyles ) + { + const XMLPropStyleContext* pStyle = + dynamic_cast< const XMLPropStyleContext* >( + pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_ROW, sStyleName) ); + + if( pStyle ) + { + const_cast< XMLPropStyleContext* >( pStyle )->FillPropertySet( xRowSet ); + } + } + } + } + + SvXMLImportContextRef xThis( this ); + return new XMLProxyContext( GetImport(), xThis ); +} + +SvXMLImportContextRef XMLTableImportContext::ImportCell( sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList ) +{ + mnCurrentColumn++; + if( mxColumns.is() ) try + { + if( mxColumns->getCount() <= mnCurrentColumn ) + mxColumns->insertByIndex( mxColumns->getCount(), mnCurrentColumn - mxColumns->getCount() + 1 ); + + Reference< XMergeableCell > xCell( mxTable->getCellByPosition( mnCurrentColumn, mnCurrentRow ), UNO_QUERY_THROW ); + XMLCellImportContext* pCellContext = new XMLCellImportContext( GetImport(), xCell, GetDefaultCellStyleName(), nElement, xAttrList ); + + const sal_Int32 nColumnSpan = pCellContext->getColumnSpan(); + const sal_Int32 nRowSpan = pCellContext->getRowSpan(); + if( (nColumnSpan > 1) || (nRowSpan > 1) ) + maMergeInfos.push_back( std::make_shared< MergeInfo >( mnCurrentColumn, mnCurrentRow, nColumnSpan, nRowSpan ) ); + + const sal_Int32 nRepeated = pCellContext->getRepeated(); + if( nRepeated > 1 ) + { + OSL_FAIL("xmloff::XMLTableImportContext::ImportCell(), import of repeated Cells not implemented (TODO)"); + mnCurrentColumn += nRepeated - 1; + } + + return pCellContext; + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.table", ""); + } + + return nullptr; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTableImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + switch (nElement) + { + case XML_ELEMENT(TABLE, XML_TABLE_CELL): + case XML_ELEMENT(TABLE, XML_COVERED_TABLE_CELL): + return ImportCell( nElement, xAttrList ); + case XML_ELEMENT(TABLE, XML_TABLE_COLUMN): + return ImportColumn( xAttrList ); + case XML_ELEMENT(TABLE, XML_TABLE_ROW): + return ImportRow( xAttrList ); + case XML_ELEMENT(TABLE, XML_TABLE_COLUMNS): + case XML_ELEMENT(TABLE, XML_TABLE_ROWS): + { + SvXMLImportContextRef xThis( this ); + return new XMLProxyContext( GetImport(), xThis ); + } + } + SAL_WARN("xmloff", "unknown element"); + return nullptr; +} + +void XMLTableImportContext::endFastElement(sal_Int32 ) +{ + for( const std::shared_ptr< MergeInfo >& xInfo : maMergeInfos ) + { + if( xInfo ) try + { + Reference< XCellRange > xRange( mxTable->getCellRangeByPosition( xInfo->mnStartColumn, xInfo->mnStartRow, xInfo->mnEndColumn, xInfo->mnEndRow ) ); + Reference< XMergeableCellRange > xCursor( mxTable->createCursorByRange( xRange ), UNO_QUERY_THROW ); + xCursor->merge(); + } + catch( Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff.table", ""); + } + } +} + +OUString XMLTableImportContext::GetDefaultCellStyleName() const +{ + OUString sStyleName( msDefaultCellStyleName ); + + // if there is still no style name, try default style name from column + if( (sStyleName.isEmpty()) && (mnCurrentColumn < sal::static_int_cast(maColumnInfos.size())) ) + sStyleName = maColumnInfos[mnCurrentColumn]->msDefaultCellStyleName; + + return sStyleName; +} + +// XMLCellImportContext + +XMLCellImportContext::XMLCellImportContext( SvXMLImport& rImport, + const Reference< XMergeableCell >& xCell, + const OUString& sDefaultCellStyleName, + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +: SvXMLImportContext( rImport ) +, mxCell( xCell ) +, mbListContextPushed( false ) +, mnColSpan( 1 ) +, mnRowSpan( 1 ) +, mnRepeated( 1 ) +{ + OUString sStyleName; + + // read attributes for the table-cell + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED): + mnRepeated = aIter.toInt32(); + break; + case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_SPANNED): + mnColSpan = aIter.toInt32(); + break; + case XML_ELEMENT(TABLE, XML_NUMBER_ROWS_SPANNED): + mnRowSpan = aIter.toInt32(); + break; + case XML_ELEMENT(TABLE, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + case XML_ELEMENT(XML, XML_ID): +//FIXME: TODO + break; +//FIXME: RDFa (table:table-cell) + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // if there is no style name at the cell, try default style name from row + if( sStyleName.isEmpty() ) + sStyleName = sDefaultCellStyleName; + + if( sStyleName.isEmpty() ) + return; + + SvXMLStylesContext * pAutoStyles = GetImport().GetShapeImport()->GetAutoStylesContext(); + if( !pAutoStyles ) + return; + + const XMLPropStyleContext* pStyle = + dynamic_cast< const XMLPropStyleContext* >( + pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_CELL, sStyleName) ); + + if( pStyle ) + { + Reference< XPropertySet > xCellSet( mxCell, UNO_QUERY ); + if( xCellSet.is() ) + const_cast< XMLPropStyleContext* >( pStyle )->FillPropertySet( xCellSet ); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLCellImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create text cursor on demand + if( !mxCursor.is() ) + { + Reference< XText > xText( mxCell, UNO_QUERY ); + if( xText.is() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport( GetImport().GetTextImport() ); + mxOldCursor = xTxtImport->GetCursor(); + mxCursor = xText->createTextCursor(); + if( mxCursor.is() ) + xTxtImport->SetCursor( mxCursor ); + + // remember old list item and block (#91964#) and reset them + // for the text frame + xTxtImport->PushListContext(); + mbListContextPushed = true; + } + } + + SvXMLImportContext * pContext = nullptr; + + // if we have a text cursor, lets try to import some text + if( mxCursor.is() ) + { + pContext = GetImport().GetTextImport()->CreateTextChildContext( GetImport(), nElement, xAttrList ); + } + + if (!pContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return pContext; +} + +void XMLCellImportContext::endFastElement(sal_Int32 ) +{ + if(mxCursor.is()) + { + // delete addition newline + mxCursor->gotoEnd( false ); + mxCursor->goLeft( 1, true ); + mxCursor->setString( "" ); + + // reset cursor + GetImport().GetTextImport()->ResetCursor(); + } + + if(mxOldCursor.is()) + GetImport().GetTextImport()->SetCursor( mxOldCursor ); + + // reinstall old list item (if necessary) #91964# + if (mbListContextPushed) { + GetImport().GetTextImport()->PopListContext(); + } +} + + +XMLTableTemplateContext::XMLTableTemplateContext( SvXMLImport& rImport ) +: SvXMLStyleContext( rImport, XmlStyleFamily::TABLE_TEMPLATE_ID, false ) +{ +} + +void XMLTableTemplateContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(TEXT, XML_STYLE_NAME) + // Writer specific: according to oasis odf 1.2 prefix should be "table" and element name should be "name" + || nElement == XML_ELEMENT(TABLE, XML_NAME) ) + { + msTemplateStyleName = rValue; + } +} + +void XMLTableTemplateContext::endFastElement(sal_Int32 ) +{ + rtl::Reference< XMLTableImport > xTableImport( GetImport().GetShapeImport()->GetShapeTableImport() ); + if( xTableImport.is() ) + xTableImport->addTableTemplate( msTemplateStyleName, maTableTemplate ); +} + +void XMLTableTemplateContext::CreateAndInsert(bool bOverwrite) +{ + rtl::Reference xTableImport(GetImport().GetShapeImport()->GetShapeTableImport()); + if(xTableImport.is()) + xTableImport->insertTabletemplate(msTemplateStyleName, bOverwrite); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTableTemplateContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_TABLE) ) + { + const TableStyleElement* pElements = getTableStyleMap(); + sal_Int32 nLocalName = nElement & TOKEN_MASK; + while( (pElements->meElement != XML_TOKEN_END) && pElements->meElement != nLocalName) + pElements++; + + if( pElements->meElement != XML_TOKEN_END ) + { + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + case XML_ELEMENT(TABLE, XML_STYLE_NAME): + maTableTemplate[pElements->msStyleName] = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + } + } else if (IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT)) // Writer specific cell styles + { + const TableStyleElement* pElements = getWriterSpecificTableStyleMap(); + sal_Int32 nLocalName = nElement & TOKEN_MASK; + while( (pElements->meElement != XML_TOKEN_END) && pElements->meElement != nLocalName) + pElements++; + + if (pElements->meElement != XML_TOKEN_END) + { + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + case XML_ELEMENT(TABLE, XML_STYLE_NAME): + maTableTemplate[pElements->msStyleName] = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + } + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/table/table.hxx b/xmloff/source/table/table.hxx new file mode 100644 index 000000000..686972065 --- /dev/null +++ b/xmloff/source/table/table.hxx @@ -0,0 +1,38 @@ +/* -*- 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 + +struct XMLPropertyMapEntry; + +struct TableStyleElement +{ + ::xmloff::token::XMLTokenEnum meElement; + OUString msStyleName; +}; + +extern const TableStyleElement* getTableStyleMap(); +extern const TableStyleElement* getWriterSpecificTableStyleMap(); +extern const XMLPropertyMapEntry* getColumnPropertiesMap(); +extern const XMLPropertyMapEntry* getRowPropertiesMap(); +extern const XMLPropertyMapEntry* getCellPropertiesMap(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAnchorTypePropHdl.hxx b/xmloff/source/text/XMLAnchorTypePropHdl.hxx new file mode 100644 index 000000000..64bddb078 --- /dev/null +++ b/xmloff/source/text/XMLAnchorTypePropHdl.hxx @@ -0,0 +1,43 @@ +/* -*- 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 +#include + + +class XMLAnchorTypePropHdl : public XMLPropertyHandler +{ +public: + virtual ~XMLAnchorTypePropHdl () override; + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter ) const override; + static bool convert( std::string_view rStrImpValue, + css::text::TextContentAnchorType& rType ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoMarkFileContext.cxx b/xmloff/source/text/XMLAutoMarkFileContext.cxx new file mode 100644 index 000000000..1582465af --- /dev/null +++ b/xmloff/source/text/XMLAutoMarkFileContext.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/. + * + * 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 "XMLAutoMarkFileContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::beans::XPropertySet; + +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_HREF; + + +XMLAutoMarkFileContext::XMLAutoMarkFileContext( + SvXMLImport& rImport) : + SvXMLImportContext(rImport) +{ +} + +XMLAutoMarkFileContext::~XMLAutoMarkFileContext() +{ +} + + +void XMLAutoMarkFileContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // scan for text:alphabetical-index-auto-mark-file attribute, and if + // found set value with the document + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + { + Any aAny; + aAny <<= GetImport().GetAbsoluteReference( aIter.toString() ); + Reference xPropertySet( + GetImport().GetModel(), UNO_QUERY ); + if (xPropertySet.is()) + { + xPropertySet->setPropertyValue( "IndexAutoMarkFileURL", aAny ); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoMarkFileContext.hxx b/xmloff/source/text/XMLAutoMarkFileContext.hxx new file mode 100644 index 000000000..cf74dd596 --- /dev/null +++ b/xmloff/source/text/XMLAutoMarkFileContext.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/. + * + * 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 + + +namespace com::sun::star { + namespace uno { template class Reference; } + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + + +class XMLAutoMarkFileContext : public SvXMLImportContext +{ +public: + + XMLAutoMarkFileContext( + SvXMLImport& rImport); + + virtual ~XMLAutoMarkFileContext() override; + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextContainerEventImport.cxx b/xmloff/source/text/XMLAutoTextContainerEventImport.cxx new file mode 100644 index 000000000..bb5101b52 --- /dev/null +++ b/xmloff/source/text/XMLAutoTextContainerEventImport.cxx @@ -0,0 +1,65 @@ +/* -*- 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 "XMLAutoTextContainerEventImport.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::container::XNameReplace; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_EVENT_LISTENERS; + + +XMLAutoTextContainerEventImport::XMLAutoTextContainerEventImport( + SvXMLImport& rImport, + const Reference & rEvnts ) : + SvXMLImportContext(rImport), + rEvents(rEvnts) +{ +} + +XMLAutoTextContainerEventImport::~XMLAutoTextContainerEventImport() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLAutoTextContainerEventImport::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + return new XMLEventsImportContext(GetImport(), rEvents); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextContainerEventImport.hxx b/xmloff/source/text/XMLAutoTextContainerEventImport.hxx new file mode 100644 index 000000000..2640f27ed --- /dev/null +++ b/xmloff/source/text/XMLAutoTextContainerEventImport.hxx @@ -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/. + * + * 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 +#include + + +namespace com::sun::star { + namespace container { class XNameReplace; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import the text:auto-text-container element. + * This only instantiates text:auto-text-group context. + */ +class XMLAutoTextContainerEventImport : public SvXMLImportContext +{ + /// the parent auto text container + const css::uno::Reference & rEvents; + +public: + + + XMLAutoTextContainerEventImport( + SvXMLImport& rImport, + const css::uno::Reference & rEvents ); + + virtual ~XMLAutoTextContainerEventImport() override; + + +protected: + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextEventExport.cxx b/xmloff/source/text/XMLAutoTextEventExport.cxx new file mode 100644 index 000000000..21abaf0a7 --- /dev/null +++ b/xmloff/source/text/XMLAutoTextEventExport.cxx @@ -0,0 +1,217 @@ +/* -*- 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 "XMLAutoTextEventExport.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::container::XNameReplace; +using ::com::sun::star::document::XEventsSupplier; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::xml::sax::XDocumentHandler; + + +XMLAutoTextEventExport::XMLAutoTextEventExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + OUString const & implementationName, SvXMLExportFlags nFlags + ) +: SvXMLExport(xContext, implementationName, util::MeasureUnit::INCH, XML_AUTO_TEXT, nFlags) +{ +} + +XMLAutoTextEventExport::~XMLAutoTextEventExport() +{ +} + +void XMLAutoTextEventExport::initialize( + const Sequence & rArguments ) +{ + if (rArguments.getLength() > 1) + { + Reference xSupplier; + rArguments[1] >>= xSupplier; + if (xSupplier.is()) + { + xEvents = xSupplier->getEvents(); + } + else + { + Reference xReplace; + rArguments[1] >>= xReplace; + if (xReplace.is()) + { + xEvents = xReplace; + } + else + { + rArguments[1] >>= xEvents; + } + } + } + + // call super class (for XHandler) + SvXMLExport::initialize(rArguments); +} + + +ErrCode XMLAutoTextEventExport::exportDoc( enum XMLTokenEnum ) +{ + if( !(getExportFlags() & SvXMLExportFlags::OASIS) ) + { + Reference< uno::XComponentContext> xContext = getComponentContext(); + try + { + + Sequence aArgs{ Any(GetDocHandler()) }; + + // get filter component + Reference< xml::sax::XDocumentHandler > xTmpDocHandler( + xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.Oasis2OOoTransformer", + aArgs, + xContext), + UNO_QUERY); + OSL_ENSURE( xTmpDocHandler.is(), + "can't instantiate OASIS transformer component" ); + if( xTmpDocHandler.is() ) + { + SetDocHandler( xTmpDocHandler ); + } + } + catch( css::uno::Exception& ) + { + } + } + if (hasEvents()) + { + GetDocHandler()->startDocument(); + + addChaffWhenEncryptedStorage(); + + addNamespaces(); + + { + // container element + SvXMLElementExport aContainerElement( + *this, XML_NAMESPACE_OOO, XML_AUTO_TEXT_EVENTS, + true, true); + + exportEvents(); + } + + // and close document again + GetDocHandler()->endDocument(); + } + + return ERRCODE_NONE; +} + +bool XMLAutoTextEventExport::hasEvents() const +{ + // TODO: provide full implementation that check for presence of events + return xEvents.is(); +} + +void XMLAutoTextEventExport::addNamespaces() +{ + // namespaces for office:, text: and script: + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_OFFICE ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_OFFICE ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_TEXT ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_TEXT ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_SCRIPT ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_SCRIPT ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_DOM ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_DOM ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_OOO ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_OOO ) ); + GetAttrList().AddAttribute( + GetNamespaceMap().GetAttrNameByIndex( XML_NAMESPACE_XLINK ), + GetNamespaceMap().GetNameByIndex( XML_NAMESPACE_XLINK ) ); +} + +void XMLAutoTextEventExport::exportEvents() +{ + DBG_ASSERT(hasEvents(), "no events to export!"); + + GetEventExport().Export(xEvents); +} + + +// methods without content: + +void XMLAutoTextEventExport::ExportMeta_() {} +void XMLAutoTextEventExport::ExportScripts_() {} +void XMLAutoTextEventExport::ExportFontDecls_() {} +void XMLAutoTextEventExport::ExportStyles_( bool ) {} +void XMLAutoTextEventExport::ExportAutoStyles_() {} +void XMLAutoTextEventExport::ExportMasterStyles_() {} +void XMLAutoTextEventExport::ExportContent_() {} + + +// methods to support the component registration + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_XMLOasisAutotextEventsExporter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new XMLAutoTextEventExport( + context, "com.sun.star.comp.Writer.XMLOasisAutotextEventsExporter", + SvXMLExportFlags::ALL | SvXMLExportFlags::OASIS)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_XMLAutotextEventsExporter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new XMLAutoTextEventExport( + context, "com.sun.star.comp.Writer.XMLAutotextEventsExporter", + SvXMLExportFlags::ALL)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextEventExport.hxx b/xmloff/source/text/XMLAutoTextEventExport.hxx new file mode 100644 index 000000000..27e6de771 --- /dev/null +++ b/xmloff/source/text/XMLAutoTextEventExport.hxx @@ -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/. + * + * 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 + + +namespace com::sun::star { + namespace container { class XNameAccess; } + namespace frame { class XModel; } + namespace lang { class XMultiServiceFactory; } + namespace uno { template class Reference; } + namespace uno { template class Sequence; } + namespace uno { class XInterface; } + namespace uno { class Exception; } + namespace xml::sax { class XDocumentHandler; } +} + + +/** + * Component for the export of events attached to autotext blocks. + * Via the XInitialization interface it expects up to two strings, the + * first giving the file name (URL) of the autotext group, and the second + * identifying the autotext. If one of the strings is not given, it + * will export the whole group / all groups. + */ +class XMLAutoTextEventExport : public SvXMLExport +{ + css::uno::Reference xEvents; + +public: + + XMLAutoTextEventExport( + const css::uno::Reference< css::uno::XComponentContext >& xContext, OUString const & implementationName, SvXMLExportFlags nFlags + ); + + virtual ~XMLAutoTextEventExport() override; + + // XInitialization + virtual void SAL_CALL initialize( + const css::uno::Sequence & rArguments ) override; + +private: + + /// export the events off all autotexts + virtual ErrCode exportDoc( + enum ::xmloff::token::XMLTokenEnum eClass = xmloff::token::XML_TOKEN_INVALID ) override; + + /// does the document have any events ? + bool hasEvents() const; + + /// export the events element + void exportEvents(); + + + /// add the namespaces used by events + /// (to be called for the document element) + void addNamespaces(); + + + // methods without content: + virtual void ExportMeta_() override; + virtual void ExportScripts_() override; + virtual void ExportFontDecls_() override; + virtual void ExportStyles_( bool bUsed ) override ; + virtual void ExportAutoStyles_() override; + virtual void ExportMasterStyles_() override; + virtual void ExportContent_() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextEventImport.cxx b/xmloff/source/text/XMLAutoTextEventImport.cxx new file mode 100644 index 000000000..b1873e4c4 --- /dev/null +++ b/xmloff/source/text/XMLAutoTextEventImport.cxx @@ -0,0 +1,94 @@ +/* -*- 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 "XMLAutoTextEventImport.hxx" +#include +#include +#include +#include +#include "XMLAutoTextContainerEventImport.hxx" +#include +#include +#include +#include + +using namespace ::com::sun::star; + +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Type; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::document::XEventsSupplier; +using ::com::sun::star::container::XNameReplace; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::xmloff::token::XML_AUTO_TEXT_EVENTS; + +XMLAutoTextEventImport::XMLAutoTextEventImport( + const css::uno::Reference& xContext) + : SvXMLImport(xContext, "") +{ +} + +XMLAutoTextEventImport::~XMLAutoTextEventImport() noexcept {} + +void XMLAutoTextEventImport::initialize(const Sequence& rArguments) +{ + // The events may come as either an XNameReplace or XEventsSupplier. + + for (const auto& rArgument : rArguments) + { + const Type& rType = rArgument.getValueType(); + if (rType == cppu::UnoType::get()) + { + Reference xSupplier; + rArgument >>= xSupplier; + DBG_ASSERT(xSupplier.is(), "need XEventsSupplier or XNameReplace"); + + xEvents = xSupplier->getEvents(); + } + else if (rType == cppu::UnoType::get()) + { + rArgument >>= xEvents; + DBG_ASSERT(xEvents.is(), "need XEventsSupplier or XNameReplace"); + } + } + + // call parent + SvXMLImport::initialize(rArguments); +} + +SvXMLImportContext* XMLAutoTextEventImport::CreateFastContext( + sal_Int32 nElement, const Reference& /*xAttrList*/) +{ + if (xEvents.is() && nElement == XML_ELEMENT(OOO, XML_AUTO_TEXT_EVENTS)) + { + return new XMLAutoTextContainerEventImport(*this, xEvents); + } + return nullptr; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_Writer_XMLOasisAutotextEventsImporter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + return cppu::acquire(new XMLAutoTextEventImport(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLAutoTextEventImport.hxx b/xmloff/source/text/XMLAutoTextEventImport.hxx new file mode 100644 index 000000000..b79b231c5 --- /dev/null +++ b/xmloff/source/text/XMLAutoTextEventImport.hxx @@ -0,0 +1,59 @@ +/* -*- 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 +#include +#include + + +namespace com::sun::star { + namespace frame { class XModel; } + namespace text { class XAutoTextContainer; } + namespace text { class XAutoTextGroup; } + namespace text { class XAutoTextEntry; } + namespace uno { template class Reference; } + namespace uno { template class Sequence; } + namespace xml::sax { class XDocumentHandler; } +} + + +class XMLAutoTextEventImport : public SvXMLImport +{ + css::uno::Reference xEvents; + +public: + explicit XMLAutoTextEventImport( + const css::uno::Reference< css::uno::XComponentContext >& xContext); + + virtual ~XMLAutoTextEventImport() noexcept override; + + // XInitialization + virtual void SAL_CALL initialize( + const css::uno::Sequence & rArguments ) override; + +protected: + + virtual SvXMLImportContext *CreateFastContext( sal_Int32 Element, + const ::css::uno::Reference< ::css::xml::sax::XFastAttributeList >& xAttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLCalculationSettingsContext.cxx b/xmloff/source/text/XMLCalculationSettingsContext.cxx new file mode 100644 index 000000000..fa7ff4236 --- /dev/null +++ b/xmloff/source/text/XMLCalculationSettingsContext.cxx @@ -0,0 +1,73 @@ +/* -*- 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 "XMLCalculationSettingsContext.hxx" + +#include +#include + +#include +#include + +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +XMLCalculationSettingsContext::XMLCalculationSettingsContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +: SvXMLImportContext ( rImport ) +, nYear( 1930 ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(TABLE, XML_NULL_YEAR) ) + { + nYear = static_cast (aIter.toInt32()); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +XMLCalculationSettingsContext::~XMLCalculationSettingsContext() +{ +} +void XMLCalculationSettingsContext::endFastElement(sal_Int32 ) +{ + if (nYear != 1930 ) + { + Reference < XTextDocument > xTextDoc ( GetImport().GetModel(), UNO_QUERY); + if (xTextDoc.is()) + { + Reference < XPropertySet > xPropSet ( xTextDoc, UNO_QUERY ); + xPropSet->setPropertyValue ( "TwoDigitYear", Any(nYear) ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLCalculationSettingsContext.hxx b/xmloff/source/text/XMLCalculationSettingsContext.hxx new file mode 100644 index 000000000..d0668b2e5 --- /dev/null +++ b/xmloff/source/text/XMLCalculationSettingsContext.hxx @@ -0,0 +1,38 @@ +/* -*- 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 + +class XMLCalculationSettingsContext : public SvXMLImportContext +{ + sal_Int16 nYear; +public: + XMLCalculationSettingsContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + + virtual ~XMLCalculationSettingsContext() override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeElementImportContext.cxx b/xmloff/source/text/XMLChangeElementImportContext.cxx new file mode 100644 index 000000000..b00cdedb0 --- /dev/null +++ b/xmloff/source/text/XMLChangeElementImportContext.cxx @@ -0,0 +1,94 @@ +/* -*- 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 "XMLChangeElementImportContext.hxx" +#include "XMLChangedRegionImportContext.hxx" +#include "XMLChangeInfoContext.hxx" +#include +#include +#include +#include + + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_CHANGE_INFO; + + +XMLChangeElementImportContext::XMLChangeElementImportContext( + SvXMLImport& rImport, + bool bAccContent, + XMLChangedRegionImportContext& rParent, + OUString const & rType) : + SvXMLImportContext(rImport), + bAcceptContent(bAccContent), + maType(rType), + rChangedRegion(rParent) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChangeElementImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + + if ( nElement == XML_ELEMENT(OFFICE, XML_CHANGE_INFO) ) + { + xContext = new XMLChangeInfoContext(GetImport(), + rChangedRegion, maType); + } + else + { + // import into redline -> create XText + rChangedRegion.UseRedlineText(); + + xContext = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, + XMLTextType::ChangedRegion); + + if (!xContext) + { + // no text element + // illegal element content! TODO: discard this redline! + // for the moment -> use default + } + } + + return xContext; +} + +void XMLChangeElementImportContext::startFastElement( sal_Int32, const Reference< css::xml::sax::XFastAttributeList >& ) +{ + if(bAcceptContent) + { + GetImport().GetTextImport()->SetInsideDeleteContext(true); + } +} + +void XMLChangeElementImportContext::endFastElement(sal_Int32 ) +{ + if(bAcceptContent) + { + GetImport().GetTextImport()->SetInsideDeleteContext(false); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeElementImportContext.hxx b/xmloff/source/text/XMLChangeElementImportContext.hxx new file mode 100644 index 000000000..dff7222d7 --- /dev/null +++ b/xmloff/source/text/XMLChangeElementImportContext.hxx @@ -0,0 +1,80 @@ +/* -*- 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 +#include + + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } +} +class XMLChangedRegionImportContext; + + +/** + * Import and elements contained in a + * element. + */ + class XMLChangeElementImportContext : public SvXMLImportContext +{ + /** + * accept text content (paragraphs) in element as redline content? + * + * From the "5.5.4 " section of the ODF 1.2 standard : + * The element may also contain content that was + * deleted while change tracking was enabled. + * + * No other section in the "5.5 Change Tracking" chapter contain + * this sentence. + * + * So if bAcceptContent is true, we are importing a element + */ + bool bAcceptContent; + + OUString maType; + + /// context of enclosing element + XMLChangedRegionImportContext& rChangedRegion; + +public: + + XMLChangeElementImportContext( + SvXMLImport& rImport, + /// accept text content (paragraphs) in element as redline content? + bool bAcceptContent, + /// context of enclosing element + XMLChangedRegionImportContext& rParent, + OUString const & rType); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + // Start- and EndElement are needed here to set the inside_deleted_section + // flag at the corresponding TextImportHelper + virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeImportContext.cxx b/xmloff/source/text/XMLChangeImportContext.cxx new file mode 100644 index 000000000..0ef536df9 --- /dev/null +++ b/xmloff/source/text/XMLChangeImportContext.cxx @@ -0,0 +1,84 @@ +/* -*- 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 "XMLChangeImportContext.hxx" +#include +#include +#include +#include +#include + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_CHANGE_ID; + + +XMLChangeImportContext::XMLChangeImportContext( + SvXMLImport& rImport, + Element const eElement, + bool bOutsideOfParagraph) + : SvXMLImportContext(rImport) + , m_Element(eElement) + , m_bIsOutsideOfParagraph(bOutsideOfParagraph) +{ +} + +XMLChangeImportContext::~XMLChangeImportContext() +{ +} + +void XMLChangeImportContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_CHANGE_ID): + { + // Id found! Now call RedlineImportHelper + + // prepare parameters + rtl::Reference rHelper = + GetImport().GetTextImport(); + OUString sID = aIter.toString(); + + // is both start and end + if (Element::START == m_Element || Element::POINT == m_Element) + rHelper->RedlineSetCursor(sID, true, m_bIsOutsideOfParagraph); + if (Element::END == m_Element || Element::POINT == m_Element) + rHelper->RedlineSetCursor(sID, false, m_bIsOutsideOfParagraph); + + // outside of paragraph and still open? set open redline ID + if (m_bIsOutsideOfParagraph) + { + rHelper->SetOpenRedlineId(sID); + } + break; + } + // else: ignore + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeImportContext.hxx b/xmloff/source/text/XMLChangeImportContext.hxx new file mode 100644 index 000000000..c2e128c55 --- /dev/null +++ b/xmloff/source/text/XMLChangeImportContext.hxx @@ -0,0 +1,67 @@ +/* -*- 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 +#include + + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } +} + + +/** + * import change tracking/redlining markers + * , , + */ +class XMLChangeImportContext : public SvXMLImportContext +{ +public: + enum class Element { START, END, POINT }; + + /** + * import a change mark + * (, , ) + * Note: a mark denotes start and end of a change + * simultaneously, as in Element::POINT. + */ + XMLChangeImportContext( + SvXMLImport& rImport, + Element eElement, + /// true if change mark is encountered outside of a paragraph + /// (usually before a section or table) + bool bIsOutsideOfParagraph); + + virtual ~XMLChangeImportContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +private: + Element m_Element; + bool m_bIsOutsideOfParagraph; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeInfoContext.cxx b/xmloff/source/text/XMLChangeInfoContext.cxx new file mode 100644 index 000000000..9dddbad72 --- /dev/null +++ b/xmloff/source/text/XMLChangeInfoContext.cxx @@ -0,0 +1,84 @@ +/* -*- 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 "XMLChangeInfoContext.hxx" +#include "XMLChangedRegionImportContext.hxx" +#include +#include +#include +#include +#include +#include + + +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLChangeInfoContext::XMLChangeInfoContext( + SvXMLImport& rImport, + XMLChangedRegionImportContext& rPParent, + const OUString& rChangeType) +: SvXMLImportContext(rImport) +, rType(rChangeType) +, rChangedRegion(rPParent) +{ +} + +XMLChangeInfoContext::~XMLChangeInfoContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChangeInfoContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContextRef xContext; + + switch (nElement) + { + case XML_ELEMENT(DC, XML_CREATOR): + xContext = new XMLStringBufferImportContext(GetImport(), sAuthorBuffer); + break; + case XML_ELEMENT(DC, XML_DATE): + xContext = new XMLStringBufferImportContext(GetImport(), sDateTimeBuffer); + break; + case XML_ELEMENT(TEXT, XML_P): + case XML_ELEMENT(LO_EXT, XML_P): + xContext = new XMLStringBufferImportContext(GetImport(), sCommentBuffer); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return xContext; +} + +void XMLChangeInfoContext::endFastElement(sal_Int32 ) +{ + // set values at changed region context + rChangedRegion.SetChangeInfo(rType, sAuthorBuffer.makeStringAndClear(), + sCommentBuffer.makeStringAndClear(), + sDateTimeBuffer); + sDateTimeBuffer.setLength(0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangeInfoContext.hxx b/xmloff/source/text/XMLChangeInfoContext.hxx new file mode 100644 index 000000000..04f055d53 --- /dev/null +++ b/xmloff/source/text/XMLChangeInfoContext.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/. + * + * 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 +#include +#include +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLChangedRegionImportContext; + + +/** + * Import elements as children of + * elements. The attribute values will be passed to the enclosing + * XMLChangedRegionImportContext (which has to be passed down in the + * constructor). + */ +class XMLChangeInfoContext : public SvXMLImportContext +{ + const OUString& rType; + + OUStringBuffer sAuthorBuffer; + OUStringBuffer sDateTimeBuffer; + OUStringBuffer sCommentBuffer; + + XMLChangedRegionImportContext& rChangedRegion; + +public: + + + XMLChangeInfoContext( + SvXMLImport& rImport, + XMLChangedRegionImportContext& rChangedRegion, + const OUString& rChangeType); + + virtual ~XMLChangeInfoContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangedRegionImportContext.cxx b/xmloff/source/text/XMLChangedRegionImportContext.cxx new file mode 100644 index 000000000..fe00c4a05 --- /dev/null +++ b/xmloff/source/text/XMLChangedRegionImportContext.cxx @@ -0,0 +1,176 @@ +/* -*- 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 "XMLChangedRegionImportContext.hxx" +#include "XMLChangeElementImportContext.hxx" +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + + +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::text::XTextCursor; +using namespace ::com::sun::star; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLChangedRegionImportContext::XMLChangedRegionImportContext(SvXMLImport& rImport) : + SvXMLImportContext(rImport), + bMergeLastPara(true) +{ +} + +XMLChangedRegionImportContext::~XMLChangedRegionImportContext() +{ +} + +void XMLChangedRegionImportContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process attributes: id + bool bHaveXmlId( false ); + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(XML, XML_ID): + { + sID = aIter.toString(); + bHaveXmlId = true; + break; + } + case XML_ELEMENT(TEXT, XML_ID): + { + if (!bHaveXmlId) { sID = aIter.toString(); } + break; + } + case XML_ELEMENT(TEXT, XML_MERGE_LAST_PARAGRAPH): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bMergeLastPara = bTmp; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLChangedRegionImportContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContextRef xContext; + + // from the ODF 1.2 standard : + // The element has the following child elements: + // , and . + if (nElement == XML_ELEMENT(TEXT, XML_INSERTION) || + nElement == XML_ELEMENT(TEXT, XML_DELETION) || + nElement == XML_ELEMENT(TEXT, XML_FORMAT_CHANGE) ) + { + // create XMLChangeElementImportContext for all kinds of changes + xContext = new XMLChangeElementImportContext( + GetImport(), + nElement == XML_ELEMENT(TEXT, XML_DELETION), + *this, + SvXMLImport::getNameFromToken(nElement)); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + // illegal element content! TODO: discard the redlines + // for the moment -> use text + // or default if text fail + + return xContext; +} + +void XMLChangedRegionImportContext::endFastElement(sal_Int32 ) +{ + // restore old XCursor (if necessary) + if (xOldCursor.is()) + { + // delete last paragraph + // (one extra paragraph was inserted in the beginning) + try + { + GetImport().GetTextImport()->DeleteParagraph(); + } + catch (uno::Exception const&) + { // cursor may be disposed - must reset to old cursor! + SAL_INFO("xmloff.text", "XMLChangedRegionImportContext: delete paragraph failed"); + } + + GetImport().GetTextImport()->SetCursor(xOldCursor); + xOldCursor = nullptr; + } +} + +void XMLChangedRegionImportContext::SetChangeInfo( + const OUString& rType, + const OUString& rAuthor, + const OUString& rComment, + std::u16string_view rDate) +{ + util::DateTime aDateTime; + if (::sax::Converter::parseDateTime(aDateTime, rDate)) + { + GetImport().GetTextImport()->RedlineAdd( + rType, sID, rAuthor, rComment, aDateTime, bMergeLastPara); + } +} + +void XMLChangedRegionImportContext::UseRedlineText() +{ + // if we haven't already installed the redline cursor, do it now + if ( xOldCursor.is()) + return; + + // get TextImportHelper and old Cursor + rtl::Reference rHelper(GetImport().GetTextImport()); + Reference xCursor( rHelper->GetCursor() ); + + // create Redline and new Cursor + Reference xNewCursor = + rHelper->RedlineCreateText(xCursor, sID); + + if (xNewCursor.is()) + { + // save old cursor and install new one + xOldCursor = xCursor; + rHelper->SetCursor( xNewCursor ); + } + // else: leave as is +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLChangedRegionImportContext.hxx b/xmloff/source/text/XMLChangedRegionImportContext.hxx new file mode 100644 index 000000000..db0e48a43 --- /dev/null +++ b/xmloff/source/text/XMLChangedRegionImportContext.hxx @@ -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/. + * + * 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 +#include + + +namespace com::sun::star { + namespace text { + class XTextCursor; + } + namespace xml::sax { + class XAttributeList; + } +} + +/** + * Import elements contained in a + * element. + */ +class XMLChangedRegionImportContext : public SvXMLImportContext +{ + /// if we replace the current XTextCursor/XText by the ones for + /// the redline, we remember the old cursor here. + css::uno::Reference xOldCursor; + + /// redline-ID + OUString sID; + + /// merge-last-paragraph flag + bool bMergeLastPara; + +public: + + + XMLChangedRegionImportContext(SvXMLImport& rImport); + + virtual ~XMLChangedRegionImportContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + + /// change info: To be called from change-info context + void SetChangeInfo(const OUString& rType, + const OUString& rAuthor, + const OUString& rComment, + std::u16string_view rDate); + + /// create redline XText/XTextCursor on demand and register with + /// XMLTextImportHelper + void UseRedlineText(); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteBodyImportContext.cxx b/xmloff/source/text/XMLFootnoteBodyImportContext.cxx new file mode 100644 index 000000000..406d30d75 --- /dev/null +++ b/xmloff/source/text/XMLFootnoteBodyImportContext.cxx @@ -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/. + * + * 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 "XMLFootnoteBodyImportContext.hxx" + +#include +#include +#include +#include + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLFootnoteBodyImportContext::XMLFootnoteBodyImportContext( SvXMLImport& rImport ) : + SvXMLImportContext(rImport) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFootnoteBodyImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // return text context + return + GetImport().GetTextImport()->CreateTextChildContext(GetImport(), + nElement, + xAttrList, + XMLTextType::Footnote); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteBodyImportContext.hxx b/xmloff/source/text/XMLFootnoteBodyImportContext.hxx new file mode 100644 index 000000000..d52557797 --- /dev/null +++ b/xmloff/source/text/XMLFootnoteBodyImportContext.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/. + * + * 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 +#include + + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } +} + + +/// import foot- and endnote body elements () +class XMLFootnoteBodyImportContext : public SvXMLImportContext +{ + +public: + + XMLFootnoteBodyImportContext( SvXMLImport& rImport ); + +protected: + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteConfigurationImportContext.cxx b/xmloff/source/text/XMLFootnoteConfigurationImportContext.cxx new file mode 100644 index 000000000..8e67b2d90 --- /dev/null +++ b/xmloff/source/text/XMLFootnoteConfigurationImportContext.cxx @@ -0,0 +1,335 @@ +/* -*- 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 + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + + +// XMLFootnoteConfigHelper + +namespace { + +/// local helper class for import of quo-vadis and ergo-sum elements +class XMLFootnoteConfigHelper : public SvXMLImportContext +{ + OUStringBuffer sBuffer; + XMLFootnoteConfigurationImportContext& rConfig; + bool bIsBegin; + +public: + + XMLFootnoteConfigHelper( + SvXMLImport& rImport, + XMLFootnoteConfigurationImportContext& rConfigImport, + bool bBegin); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +} + +XMLFootnoteConfigHelper::XMLFootnoteConfigHelper( + SvXMLImport& rImport, + XMLFootnoteConfigurationImportContext& rConfigImport, + bool bBegin) +: SvXMLImportContext(rImport) +, rConfig(rConfigImport) +, bIsBegin(bBegin) +{ +} + +void XMLFootnoteConfigHelper::endFastElement(sal_Int32 ) +{ + if (bIsBegin) + { + rConfig.SetBeginNotice(sBuffer.makeStringAndClear()); + } + else + { + rConfig.SetEndNotice(sBuffer.makeStringAndClear()); + } +// rConfig = NULL; // import contexts are ref-counted +} + +void XMLFootnoteConfigHelper::characters( const OUString& rChars ) +{ + sBuffer.append(rChars); +} + + +// XMLFootnoteConfigurationImportContext + +constexpr OUStringLiteral gsPropertyAnchorCharStyleName(u"AnchorCharStyleName"); +constexpr OUStringLiteral gsPropertyCharStyleName(u"CharStyleName"); +constexpr OUStringLiteral gsPropertyNumberingType(u"NumberingType"); +constexpr OUStringLiteral gsPropertyPageStyleName(u"PageStyleName"); +constexpr OUStringLiteral gsPropertyParagraphStyleName(u"ParaStyleName"); +constexpr OUStringLiteral gsPropertyPrefix(u"Prefix"); +constexpr OUStringLiteral gsPropertyStartAt(u"StartAt"); +constexpr OUStringLiteral gsPropertySuffix(u"Suffix"); +constexpr OUStringLiteral gsPropertyPositionEndOfDoc(u"PositionEndOfDoc"); +constexpr OUStringLiteral gsPropertyFootnoteCounting(u"FootnoteCounting"); +constexpr OUStringLiteral gsPropertyEndNotice(u"EndNotice"); +constexpr OUStringLiteral gsPropertyBeginNotice(u"BeginNotice"); + +XMLFootnoteConfigurationImportContext::XMLFootnoteConfigurationImportContext( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference & xAttrList) +: SvXMLStyleContext(rImport, XmlStyleFamily::TEXT_FOOTNOTECONFIG) +, sNumFormat("1") +, sNumSync("false") +, nOffset(0) +, nNumbering(FootnoteNumbering::PER_PAGE) +, bPosition(false) +, bIsEndnote(false) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_NOTE_CLASS) ) + { + if( IsXMLToken(aIter, XML_ENDNOTE ) ) + { + bIsEndnote = true; + SetFamily( XmlStyleFamily::TEXT_FOOTNOTECONFIG ); + } + break; + } + } + +} +XMLFootnoteConfigurationImportContext::~XMLFootnoteConfigurationImportContext() +{ +} + +SvXMLEnumMapEntry const aFootnoteNumberingMap[] = +{ + { XML_PAGE, FootnoteNumbering::PER_PAGE }, + { XML_CHAPTER, FootnoteNumbering::PER_CHAPTER }, + { XML_DOCUMENT, FootnoteNumbering::PER_DOCUMENT }, + { XML_TOKEN_INVALID, 0 }, +}; + +void XMLFootnoteConfigurationImportContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_CITATION_STYLE_NAME): + sCitationStyle = rValue; + break; + case XML_ELEMENT(TEXT, XML_CITATION_BODY_STYLE_NAME): + sAnchorStyle = rValue; + break; + case XML_ELEMENT(TEXT, XML_DEFAULT_STYLE_NAME): + sDefaultStyle = rValue; + break; + case XML_ELEMENT(TEXT, XML_MASTER_PAGE_NAME): + sPageStyle = rValue; + break; + case XML_ELEMENT(TEXT, XML_START_VALUE): + case XML_ELEMENT(TEXT, XML_OFFSET): // for backwards compatibility with SRC630 & earlier + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, rValue)) + { + nOffset = static_cast(nTmp); + } + break; + } + case XML_ELEMENT(STYLE, XML_NUM_PREFIX): + case XML_ELEMENT(TEXT, XML_NUM_PREFIX): // for backwards compatibility with SRC630 & earlier + sPrefix = rValue; + break; + case XML_ELEMENT(STYLE, XML_NUM_SUFFIX): + case XML_ELEMENT(TEXT, XML_NUM_SUFFIX): // for backwards compatibility with SRC630 & earlier + sSuffix = rValue; + break; + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumFormat = rValue; + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumSync = rValue; + break; + case XML_ELEMENT(TEXT, XML_START_NUMBERING_AT): + { + (void)SvXMLUnitConverter::convertEnum(nNumbering, rValue, + aFootnoteNumberingMap); + break; + } + case XML_ELEMENT(TEXT, XML_FOOTNOTES_POSITION): + bPosition = IsXMLToken( rValue, XML_DOCUMENT ); + break; + default: + ; // ignore + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFootnoteConfigurationImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + + if (bIsEndnote) + return nullptr; + + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_FOOTNOTE_CONTINUATION_NOTICE_FORWARD): + xContext = new XMLFootnoteConfigHelper(GetImport(), *this, false); + break; + case XML_ELEMENT(TEXT, XML_FOOTNOTE_CONTINUATION_NOTICE_BACKWARD): + xContext = new XMLFootnoteConfigHelper(GetImport(), *this, true); + break; + } + + return xContext; +} + +// Rename method to (#i40597#) +void XMLFootnoteConfigurationImportContext::Finish( bool bOverwrite ) +{ + + if (!bOverwrite) + return; + + if (bIsEndnote) + { + Reference xSupplier( + GetImport().GetModel(), UNO_QUERY); + if (xSupplier.is()) + { + ProcessSettings(xSupplier->getEndnoteSettings()); + } + } + else + { + Reference xSupplier( + GetImport().GetModel(), UNO_QUERY); + if (xSupplier.is()) + { + ProcessSettings(xSupplier->getFootnoteSettings()); + } + } + // else: ignore (there's only one configuration, so we can only overwrite) +} + +void XMLFootnoteConfigurationImportContext::ProcessSettings( + const Reference & rConfig) +{ + Any aAny; + + if (!sCitationStyle.isEmpty()) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sCitationStyle ); + rConfig->setPropertyValue(gsPropertyCharStyleName, aAny); + } + + if (!sAnchorStyle.isEmpty()) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sAnchorStyle ); + rConfig->setPropertyValue(gsPropertyAnchorCharStyleName, aAny); + } + + if (!sPageStyle.isEmpty()) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, sPageStyle ); + rConfig->setPropertyValue(gsPropertyPageStyleName, aAny); + } + + if (!sDefaultStyle.isEmpty()) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, sDefaultStyle ); + rConfig->setPropertyValue(gsPropertyParagraphStyleName, aAny); + } + + rConfig->setPropertyValue(gsPropertyPrefix, Any(sPrefix)); + + rConfig->setPropertyValue(gsPropertySuffix, Any(sSuffix)); + + sal_Int16 nNumType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, sNumFormat, + sNumSync ); + // #i61399: Corrupt file? It contains "Bullet" as numbering style for footnotes. + // Okay, even it seems to be corrupt, we will oversee this and set the style to ARABIC + if( NumberingType::CHAR_SPECIAL == nNumType ) + nNumType = NumberingType::ARABIC; + + rConfig->setPropertyValue(gsPropertyNumberingType, Any(nNumType)); + + rConfig->setPropertyValue(gsPropertyStartAt, Any(nOffset)); + + if (!bIsEndnote) + { + rConfig->setPropertyValue(gsPropertyPositionEndOfDoc, Any(bPosition)); + rConfig->setPropertyValue(gsPropertyFootnoteCounting, Any(nNumbering)); + rConfig->setPropertyValue(gsPropertyEndNotice, Any(sEndNotice)); + rConfig->setPropertyValue(gsPropertyBeginNotice, Any(sBeginNotice)); + } +} + +void XMLFootnoteConfigurationImportContext::SetBeginNotice( + const OUString& sText) +{ + sBeginNotice = sText; +} + +void XMLFootnoteConfigurationImportContext::SetEndNotice( + const OUString& sText) +{ + sEndNotice = sText; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteImportContext.cxx b/xmloff/source/text/XMLFootnoteImportContext.cxx new file mode 100644 index 000000000..f2a074033 --- /dev/null +++ b/xmloff/source/text/XMLFootnoteImportContext.cxx @@ -0,0 +1,169 @@ +/* -*- 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 "XMLFootnoteImportContext.hxx" + +#include +#include +#include +#include +#include +#include +#include + +#include "XMLFootnoteBodyImportContext.hxx" + +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLFootnoteImportContext::XMLFootnoteImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp ) +: SvXMLImportContext(rImport) +, mbListContextPushed(false) +, rHelper(rHlp) +{ +} + +void XMLFootnoteImportContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // create footnote + Reference xFactory(GetImport().GetModel(), + UNO_QUERY); + if( !xFactory.is() ) + return; + + // create endnote or footnote + bool bIsEndnote = false; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_NOTE_CLASS) ) + { + if( IsXMLToken( aIter, XML_ENDNOTE ) ) + bIsEndnote = true; + break; + } + } + + Reference xIfc = xFactory->createInstance( + bIsEndnote ? + OUString("com.sun.star.text.Endnote") : + OUString("com.sun.star.text.Footnote") ); + + // attach footnote to document + Reference xTextContent(xIfc, UNO_QUERY); + rHelper.InsertTextContent(xTextContent); + + // process id attribute + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_ID) ) + { + // get ID ... + Reference xPropertySet(xTextContent, UNO_QUERY); + Any aAny =xPropertySet->getPropertyValue("ReferenceId"); + sal_Int16 nID = 0; + aAny >>= nID; + + // ... and insert into map + rHelper.InsertFootnoteID( aIter.toString(), nID); + break; + } + } + + // save old cursor and install new one + xOldCursor = rHelper.GetCursor(); + Reference xText(xTextContent, UNO_QUERY); + rHelper.SetCursor(xText->createTextCursor()); + + // remember old list item and block (#89891#) and reset them + // for the footnote + rHelper.PushListContext(); + mbListContextPushed = true; + + // remember footnote (for CreateChildContext) + Reference xNote(xTextContent, UNO_QUERY); + xFootnote = xNote; + + // else: ignore footnote! Content will be merged into document. +} + +void XMLFootnoteImportContext::endFastElement(sal_Int32 ) +{ + // get rid of last dummy paragraph + rHelper.DeleteParagraph(); + + // reinstall old cursor + rHelper.SetCursor(xOldCursor); + + // reinstall old list item + if (mbListContextPushed) { + rHelper.PopListContext(); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLFootnoteImportContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + + switch(nElement) + { + case XML_ELEMENT(TEXT, XML_NOTE_CITATION): + { + // little hack: we only care for one attribute of the citation + // element. We handle that here, and then return a + // default context. + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_LABEL) ) + xFootnote->setLabel(aIter.toString()); + } + + // ignore content: return default context + break; + } + + case XML_ELEMENT(TEXT, XML_NOTE_BODY): + // return footnote body + xContext = new XMLFootnoteBodyImportContext(GetImport()); + break; + + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLFootnoteImportContext.hxx b/xmloff/source/text/XMLFootnoteImportContext.hxx new file mode 100644 index 000000000..d05b7b631 --- /dev/null +++ b/xmloff/source/text/XMLFootnoteImportContext.hxx @@ -0,0 +1,72 @@ +/* -*- 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 +#include + + +namespace com::sun::star { + namespace text { + class XTextCursor; + class XFootnote; + } + namespace xml::sax { + class XAttributeList; + } +} +class XMLTextImportHelper; + +/// import footnote elements () +class XMLFootnoteImportContext : public SvXMLImportContext +{ + /// old document cursor + css::uno::Reference xOldCursor; + + /// old list item and block (#89891#) + bool mbListContextPushed; + + /// text import helper; holds current XTextCursor (and XText) + XMLTextImportHelper& rHelper; + + /// the footnote + css::uno::Reference xFootnote; + +public: + + + XMLFootnoteImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp ); + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexAlphabeticalSourceContext.cxx b/xmloff/source/text/XMLIndexAlphabeticalSourceContext.cxx new file mode 100644 index 000000000..df1385d95 --- /dev/null +++ b/xmloff/source/text/XMLIndexAlphabeticalSourceContext.cxx @@ -0,0 +1,214 @@ +/* -*- 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 "XMLIndexAlphabeticalSourceContext.hxx" + +#include +#include + +#include + +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include +#include +#include + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using namespace ::xmloff::token; + +XMLIndexAlphabeticalSourceContext::XMLIndexAlphabeticalSourceContext( + SvXMLImport& rImport, + Reference & rPropSet) +: XMLIndexSourceBaseContext(rImport, rPropSet, false) +, bMainEntryStyleNameOK(false) +, bSeparators(false) +, bCombineEntries(true) +, bCaseSensitive(true) +, bEntry(false) +, bUpperCase(false) +, bCombineDash(false) +, bCombinePP(true) +, bCommaSeparated(false) +{ +} + +XMLIndexAlphabeticalSourceContext::~XMLIndexAlphabeticalSourceContext() +{ +} + +void XMLIndexAlphabeticalSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + bool bTmp(false); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_MAIN_ENTRY_STYLE_NAME): + { + sMainEntryStyleName = aIter.toString(); + OUString sDisplayStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sMainEntryStyleName ); + const Reference < css::container::XNameContainer >& + rStyles = GetImport().GetTextImport()->GetTextStyles(); + bMainEntryStyleNameOK = rStyles.is() && rStyles->hasByName( sDisplayStyleName ); + } + break; + + case XML_ELEMENT(TEXT, XML_IGNORE_CASE): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCaseSensitive = !bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_SEPARATORS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bSeparators = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COMBINE_ENTRIES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCombineEntries = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COMBINE_ENTRIES_WITH_DASH): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCombineDash = bTmp; + } + break; + case XML_ELEMENT(TEXT, XML_USE_KEYS_AS_ENTRIES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bEntry = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COMBINE_ENTRIES_WITH_PP): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCombinePP = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_CAPITALIZE_ENTRIES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUpperCase = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COMMA_SEPARATED): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bCommaSeparated = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_SORT_ALGORITHM): + sAlgorithm = aIter.toString(); + break; + case XML_ELEMENT(STYLE, XML_RFC_LANGUAGE_TAG): + maLanguageTagODF.maRfcLanguageTag = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_LANGUAGE): + maLanguageTagODF.maLanguage = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_SCRIPT): + maLanguageTagODF.maScript = aIter.toString(); + break; + case XML_ELEMENT(FO, XML_COUNTRY): + maLanguageTagODF.maCountry = aIter.toString(); + break; + + default: + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexAlphabeticalSourceContext::endFastElement(sal_Int32 nElement) +{ + + Any aAny; + + if (bMainEntryStyleNameOK) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sMainEntryStyleName ); + rIndexPropertySet->setPropertyValue("MainEntryCharacterStyleName",aAny); + } + + rIndexPropertySet->setPropertyValue("UseAlphabeticalSeparators", css::uno::Any(bSeparators)); + rIndexPropertySet->setPropertyValue("UseCombinedEntries", css::uno::Any(bCombineEntries)); + rIndexPropertySet->setPropertyValue("IsCaseSensitive", css::uno::Any(bCaseSensitive)); + rIndexPropertySet->setPropertyValue("UseKeyAsEntry", css::uno::Any(bEntry)); + rIndexPropertySet->setPropertyValue("UseUpperCase", css::uno::Any(bUpperCase)); + rIndexPropertySet->setPropertyValue("UseDash", css::uno::Any(bCombineDash)); + rIndexPropertySet->setPropertyValue("UsePP", css::uno::Any(bCombinePP)); + rIndexPropertySet->setPropertyValue("IsCommaSeparated", css::uno::Any(bCommaSeparated)); + + + if (!sAlgorithm.isEmpty()) + { + rIndexPropertySet->setPropertyValue("SortAlgorithm", css::uno::Any(sAlgorithm)); + } + + if ( !maLanguageTagODF.isEmpty() ) + { + aAny <<= maLanguageTagODF.getLanguageTag().getLocale( false); + rIndexPropertySet->setPropertyValue("Locale", aAny); + } + + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexAlphabeticalSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameAlphaMap, + XML_OUTLINE_LEVEL, + aLevelStylePropNameAlphaMap, + aAllowedTokenTypesAlpha); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexAlphabeticalSourceContext.hxx b/xmloff/source/text/XMLIndexAlphabeticalSourceContext.hxx new file mode 100644 index 000000000..45fcea4ba --- /dev/null +++ b/xmloff/source/text/XMLIndexAlphabeticalSourceContext.hxx @@ -0,0 +1,73 @@ +/* -*- 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 "XMLIndexSourceBaseContext.hxx" +#include +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import alphabetical (keyword) index source element + */ +class XMLIndexAlphabeticalSourceContext : public XMLIndexSourceBaseContext +{ + LanguageTagODF maLanguageTagODF; + OUString sAlgorithm; + + OUString sMainEntryStyleName; + bool bMainEntryStyleNameOK; + + bool bSeparators; + bool bCombineEntries; + bool bCaseSensitive; + bool bEntry; + bool bUpperCase; + bool bCombineDash; + bool bCombinePP; + bool bCommaSeparated; + +public: + + + XMLIndexAlphabeticalSourceContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet); + + virtual ~XMLIndexAlphabeticalSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographyConfigurationContext.cxx b/xmloff/source/text/XMLIndexBibliographyConfigurationContext.cxx new file mode 100644 index 000000000..246a804a7 --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographyConfigurationContext.cxx @@ -0,0 +1,216 @@ +/* -*- 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 +#include +#include "XMLIndexBibliographyEntryContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::lang::XMultiServiceFactory; + + +constexpr OUStringLiteral gsFieldMaster_Bibliography(u"com.sun.star.text.FieldMaster.Bibliography"); +constexpr OUStringLiteral gsBracketBefore(u"BracketBefore"); +constexpr OUStringLiteral gsBracketAfter(u"BracketAfter"); +constexpr OUStringLiteral gsIsNumberEntries(u"IsNumberEntries"); +constexpr OUStringLiteral gsIsSortByPosition(u"IsSortByPosition"); +constexpr OUStringLiteral gsSortKeys(u"SortKeys"); +constexpr OUStringLiteral gsSortKey(u"SortKey"); +constexpr OUStringLiteral gsIsSortAscending(u"IsSortAscending"); +constexpr OUStringLiteral gsSortAlgorithm(u"SortAlgorithm"); +constexpr OUStringLiteral gsLocale(u"Locale"); + +XMLIndexBibliographyConfigurationContext::XMLIndexBibliographyConfigurationContext( + SvXMLImport& rImport) : + SvXMLStyleContext(rImport, XmlStyleFamily::TEXT_BIBLIOGRAPHYCONFIG), + maLanguageTagODF(), + bNumberedEntries(false), + bSortByPosition(true) +{ +} + +XMLIndexBibliographyConfigurationContext::~XMLIndexBibliographyConfigurationContext() +{ +} + +void XMLIndexBibliographyConfigurationContext::SetAttribute( + sal_Int32 nElement, + const OUString& sValue) +{ + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_PREFIX): + sPrefix = sValue; + break; + case XML_ELEMENT(TEXT, XML_SUFFIX): + sSuffix = sValue; + break; + case XML_ELEMENT(TEXT, XML_NUMBERED_ENTRIES): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sValue)) + { + bNumberedEntries = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_SORT_BY_POSITION): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sValue)) + { + bSortByPosition = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_SORT_ALGORITHM): + sAlgorithm = sValue; + break; + case XML_ELEMENT(FO, XML_LANGUAGE): + maLanguageTagODF.maLanguage = sValue; + break; + case XML_ELEMENT(FO, XML_SCRIPT): + maLanguageTagODF.maScript = sValue; + break; + case XML_ELEMENT(FO, XML_COUNTRY): + maLanguageTagODF.maCountry = sValue; + break; + case XML_ELEMENT(STYLE, XML_RFC_LANGUAGE_TAG): + maLanguageTagODF.maRfcLanguageTag = sValue; + break; + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexBibliographyConfigurationContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process children here and use default context! + if ( nElement == XML_ELEMENT(TEXT, XML_SORT_KEY) ) + { + std::string_view sKey; + bool bSort(true); + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_KEY): + sKey = aIter.toView(); + break; + case XML_ELEMENT(TEXT, XML_SORT_ASCENDING): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + bSort = bTmp; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } + + // valid data? + sal_uInt16 nKey; + if (SvXMLUnitConverter::convertEnum(nKey, sKey, + aBibliographyDataFieldMap)) + { + Sequence aKey + { + comphelper::makePropertyValue(gsSortKey, static_cast(nKey)), + comphelper::makePropertyValue(gsIsSortAscending, bSort) + }; + + aSortKeys.push_back(aKey); + } + } + + return nullptr; +} + +void XMLIndexBibliographyConfigurationContext::CreateAndInsert(bool) +{ + // (code almost the same as export...) + + // insert and block mode is handled in insertStyleFamily + + // first: get field master + // (we'll create one, and get the only master for this type) + Reference xFactory(GetImport().GetModel(),UNO_QUERY); + if( !xFactory.is() ) + return; + + Sequence aServices = xFactory->getAvailableServiceNames(); + // here we should use a method which compares in reverse order if available + if (comphelper::findValue(aServices, gsFieldMaster_Bibliography) == -1) + return; + + Reference xIfc = + xFactory->createInstance(gsFieldMaster_Bibliography); + if( !xIfc.is() ) + return; + + Reference xPropSet( xIfc, UNO_QUERY ); + Any aAny; + + xPropSet->setPropertyValue(gsBracketAfter, Any(sSuffix)); + xPropSet->setPropertyValue(gsBracketBefore, Any(sPrefix)); + xPropSet->setPropertyValue(gsIsNumberEntries, Any(bNumberedEntries)); + xPropSet->setPropertyValue(gsIsSortByPosition, Any(bSortByPosition)); + + if( !maLanguageTagODF.isEmpty() ) + { + aAny <<= maLanguageTagODF.getLanguageTag().getLocale( false); + xPropSet->setPropertyValue(gsLocale, aAny); + } + + if( !sAlgorithm.isEmpty() ) + { + xPropSet->setPropertyValue(gsSortAlgorithm, Any(sAlgorithm)); + } + + Sequence > aKeysSeq = comphelper::containerToSequence(aSortKeys); + xPropSet->setPropertyValue(gsSortKeys, Any(aKeysSeq)); + // else: can't get FieldMaster -> ignore + // else: can't even get Factory -> ignore +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographyEntryContext.cxx b/xmloff/source/text/XMLIndexBibliographyEntryContext.cxx new file mode 100644 index 000000000..fdb2657fd --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographyEntryContext.cxx @@ -0,0 +1,157 @@ +/* -*- 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 "XMLIndexBibliographyEntryContext.hxx" +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLIndexBibliographyEntryContext::XMLIndexBibliographyEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ) : + XMLIndexSimpleEntryContext(rImport, + "TokenBibliographyDataField", + rTemplate), + nBibliographyInfo(BibliographyDataField::IDENTIFIER), + bBibliographyInfoOK(false) +{ +} + +XMLIndexBibliographyEntryContext::~XMLIndexBibliographyEntryContext() +{ +} + +const SvXMLEnumMapEntry aBibliographyDataFieldMap[] = +{ + { XML_ADDRESS, BibliographyDataField::ADDRESS }, + { XML_ANNOTE, BibliographyDataField::ANNOTE }, + { XML_AUTHOR, BibliographyDataField::AUTHOR }, + { XML_BIBLIOGRAPHY_TYPE, BibliographyDataField::BIBILIOGRAPHIC_TYPE }, + // #96658#: also read old documents (bib*i*liographic...) + { XML_BIBILIOGRAPHIC_TYPE, BibliographyDataField::BIBILIOGRAPHIC_TYPE }, + { XML_BOOKTITLE, BibliographyDataField::BOOKTITLE }, + { XML_CHAPTER, BibliographyDataField::CHAPTER }, + { XML_CUSTOM1, BibliographyDataField::CUSTOM1 }, + { XML_CUSTOM2, BibliographyDataField::CUSTOM2 }, + { XML_CUSTOM3, BibliographyDataField::CUSTOM3 }, + { XML_CUSTOM4, BibliographyDataField::CUSTOM4 }, + { XML_CUSTOM5, BibliographyDataField::CUSTOM5 }, + { XML_EDITION, BibliographyDataField::EDITION }, + { XML_EDITOR, BibliographyDataField::EDITOR }, + { XML_HOWPUBLISHED, BibliographyDataField::HOWPUBLISHED }, + { XML_IDENTIFIER, BibliographyDataField::IDENTIFIER }, + { XML_INSTITUTION, BibliographyDataField::INSTITUTION }, + { XML_ISBN, BibliographyDataField::ISBN }, + { XML_JOURNAL, BibliographyDataField::JOURNAL }, + { XML_MONTH, BibliographyDataField::MONTH }, + { XML_NOTE, BibliographyDataField::NOTE }, + { XML_NUMBER, BibliographyDataField::NUMBER }, + { XML_ORGANIZATIONS, BibliographyDataField::ORGANIZATIONS }, + { XML_PAGES, BibliographyDataField::PAGES }, + { XML_PUBLISHER, BibliographyDataField::PUBLISHER }, + { XML_REPORT_TYPE, BibliographyDataField::REPORT_TYPE }, + { XML_SCHOOL, BibliographyDataField::SCHOOL }, + { XML_SERIES, BibliographyDataField::SERIES }, + { XML_TITLE, BibliographyDataField::TITLE }, + { XML_URL, BibliographyDataField::URL }, + { XML_VOLUME, BibliographyDataField::VOLUME }, + { XML_YEAR, BibliographyDataField::YEAR }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLIndexBibliographyEntryContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // handle both, style name and bibliography info + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + { + m_sCharStyleName = aIter.toString(); + m_bCharStyleNameOK = true; + break; + } + case XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY_DATA_FIELD): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, aIter.toView(), aBibliographyDataFieldMap)) + { + nBibliographyInfo = nTmp; + bBibliographyInfoOK = true; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // if we have a style name, set it! + if (m_bCharStyleNameOK) + { + m_nValues++; + } + + // always bibliography; else element is not valid + m_nValues++; +} + +void XMLIndexBibliographyEntryContext::endFastElement(sal_Int32 nElement) +{ + // only valid, if we have bibliography info + if (bBibliographyInfoOK) + { + XMLIndexSimpleEntryContext::endFastElement(nElement); + } +} + +void XMLIndexBibliographyEntryContext::FillPropertyValues( + css::uno::Sequence & rValues) +{ + // entry name and (optionally) style name in parent class + XMLIndexSimpleEntryContext::FillPropertyValues(rValues); + + // bibliography data field + sal_Int32 nIndex = m_bCharStyleNameOK ? 2 : 1; + auto pValues = rValues.getArray(); + pValues[nIndex].Name = "BibliographyDataField"; + pValues[nIndex].Value <<= nBibliographyInfo; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographyEntryContext.hxx b/xmloff/source/text/XMLIndexBibliographyEntryContext.hxx new file mode 100644 index 000000000..4c586a5a8 --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographyEntryContext.hxx @@ -0,0 +1,70 @@ +/* -*- 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 "XMLIndexSimpleEntryContext.hxx" +#include +#include +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLIndexTemplateContext; +template struct SvXMLEnumMapEntry; + +extern const SvXMLEnumMapEntry aBibliographyDataFieldMap[]; + +/** + * Import bibliography index entry templates + */ +class XMLIndexBibliographyEntryContext : public XMLIndexSimpleEntryContext +{ + // bibliography info + sal_Int16 nBibliographyInfo; + bool bBibliographyInfoOK; + +public: + + + XMLIndexBibliographyEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ); + + virtual ~XMLIndexBibliographyEntryContext() override; + +protected: + + /** process parameters */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** call FillPropertyValues and insert into template */ + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + /** fill property values for this template entry */ + virtual void FillPropertyValues( + css::uno::Sequence & rValues) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographySourceContext.cxx b/xmloff/source/text/XMLIndexBibliographySourceContext.cxx new file mode 100644 index 000000000..0ec556389 --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographySourceContext.cxx @@ -0,0 +1,82 @@ +/* -*- 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 "XMLIndexBibliographySourceContext.hxx" +#include +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLIndexBibliographySourceContext::XMLIndexBibliographySourceContext( + SvXMLImport& rImport, + Reference & rPropSet) : + XMLIndexSourceBaseContext(rImport, + rPropSet, false) +{ +} + +XMLIndexBibliographySourceContext::~XMLIndexBibliographySourceContext() +{ +} + +void XMLIndexBibliographySourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + // We have no attributes. Who wants attributes, anyway? + XMLOFF_WARN_UNKNOWN("xmloff", aIter); +} + +void XMLIndexBibliographySourceContext::endFastElement(sal_Int32 ) +{ + // No attributes, no properties. +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexBibliographySourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameBibliographyMap, + XML_BIBLIOGRAPHY_TYPE, + aLevelStylePropNameBibliographyMap, + aAllowedTokenTypesBibliography); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBibliographySourceContext.hxx b/xmloff/source/text/XMLIndexBibliographySourceContext.hxx new file mode 100644 index 000000000..497c33d1c --- /dev/null +++ b/xmloff/source/text/XMLIndexBibliographySourceContext.hxx @@ -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/. + * + * 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 "XMLIndexSourceBaseContext.hxx" +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import bibliography source element + */ +class XMLIndexBibliographySourceContext : public XMLIndexSourceBaseContext +{ + +public: + + XMLIndexBibliographySourceContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet); + + virtual ~XMLIndexBibliographySourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBodyContext.cxx b/xmloff/source/text/XMLIndexBodyContext.cxx new file mode 100644 index 000000000..05392d57a --- /dev/null +++ b/xmloff/source/text/XMLIndexBodyContext.cxx @@ -0,0 +1,53 @@ +/* -*- 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 "XMLIndexBodyContext.hxx" +#include +#include +#include +#include + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLIndexBodyContext::XMLIndexBodyContext( SvXMLImport& rImport ) : + SvXMLImportContext(rImport), + bHasContent(false) +{ +} + +XMLIndexBodyContext::~XMLIndexBodyContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexBodyContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // return text content (if possible) + SvXMLImportContext* pContext = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, XMLTextType::Section ); + if (pContext) + bHasContent = true; + + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexBodyContext.hxx b/xmloff/source/text/XMLIndexBodyContext.hxx new file mode 100644 index 000000000..5962bacf3 --- /dev/null +++ b/xmloff/source/text/XMLIndexBodyContext.hxx @@ -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/. + * + * 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 +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + +/** + * Import index body. + * + * This class basically delegates all CreateChildContext() calls to + * the text import and doesn't do much else. + */ +class XMLIndexBodyContext : public SvXMLImportContext +{ + bool bHasContent; + +public: + + + XMLIndexBodyContext( SvXMLImport& rImport ); + + virtual ~XMLIndexBodyContext() override; + + /// return whether any content elements were encountered + inline bool HasContent() const; + +protected: + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +inline bool XMLIndexBodyContext::HasContent() const +{ + return bHasContent; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexChapterInfoEntryContext.cxx b/xmloff/source/text/XMLIndexChapterInfoEntryContext.cxx new file mode 100644 index 000000000..18355fe2e --- /dev/null +++ b/xmloff/source/text/XMLIndexChapterInfoEntryContext.cxx @@ -0,0 +1,186 @@ +/* -*- 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 "XMLIndexChapterInfoEntryContext.hxx" + +#include + +#include +#include + +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLIndexChapterInfoEntryContext::XMLIndexChapterInfoEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate, + bool bT ) : + XMLIndexSimpleEntryContext(rImport, + (bT ? OUString("TokenEntryNumber") + : OUString("TokenChapterInfo")), + rTemplate), + nChapterInfo(ChapterFormat::NAME_NUMBER), + bChapterInfoOK(false), + bTOC( bT ), + nOutlineLevel( 0 ), + bOutlineLevelOK(false) +{ +} + +XMLIndexChapterInfoEntryContext::~XMLIndexChapterInfoEntryContext() +{ +} + +const SvXMLEnumMapEntry aChapterDisplayMap[] = +{ + { XML_NAME, ChapterFormat::NAME }, + { XML_NUMBER, ChapterFormat::NUMBER }, + { XML_NUMBER_AND_NAME, ChapterFormat::NAME_NUMBER }, + //---> i89791 + // enabled for ODF 1.2, full index support in 3.0 + { XML_PLAIN_NUMBER_AND_NAME, ChapterFormat::NO_PREFIX_SUFFIX }, + { XML_PLAIN_NUMBER, ChapterFormat::DIGIT }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLIndexChapterInfoEntryContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // handle both, style name and bibliography info + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + { + m_sCharStyleName = aIter.toString(); + m_bCharStyleNameOK = true; + break; + } + case XML_ELEMENT(TEXT, XML_DISPLAY): //i53420, always true, in TOC as well + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, aIter.toView(), aChapterDisplayMap)) + { + nChapterInfo = nTmp; + bChapterInfoOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView())) + { +//control on range is carried out in the UNO level + nOutlineLevel = static_cast(nTmp); + bOutlineLevelOK = true; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // if we have a style name, set it! + if (m_bCharStyleNameOK) + { + m_nValues++; + } + + // if we have chapter info, set it! + if (bChapterInfoOK) + { + m_nValues++; + /* Some of the index chapter information attributes written to ODF 1.1 + and 1.2 don't reflect the displaying (#i89791#) + */ + if ( !bTOC ) + { + bool bConvert( false ); + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); + if ( GetImport().IsTextDocInOOoFileFormat() || + ( bBuildIdFound && + ( nUPD== 680 || nUPD == 645 || nUPD == 641 ) ) ) + { + bConvert = true; + } + } + if ( bConvert ) + { + if ( nChapterInfo == ChapterFormat::NUMBER ) + { + nChapterInfo = ChapterFormat::DIGIT; + } + else if ( nChapterInfo == ChapterFormat::NAME_NUMBER ) + { + nChapterInfo = ChapterFormat::NO_PREFIX_SUFFIX; + } + } + } + } + if (bOutlineLevelOK) + m_nValues++; +} + +void XMLIndexChapterInfoEntryContext::FillPropertyValues( + css::uno::Sequence & rValues) +{ + // entry name and (optionally) style name in parent class + XMLIndexSimpleEntryContext::FillPropertyValues(rValues); + + sal_Int32 nIndex = m_bCharStyleNameOK ? 2 : 1; + auto pValues = rValues.getArray(); + + if( bChapterInfoOK ) + { + // chapter info field + pValues[nIndex].Name = "ChapterFormat"; + pValues[nIndex].Value <<= nChapterInfo; + nIndex++; + } + if( bOutlineLevelOK ) + { + pValues[nIndex].Name = "ChapterLevel"; + pValues[nIndex].Value <<= nOutlineLevel; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexChapterInfoEntryContext.hxx b/xmloff/source/text/XMLIndexChapterInfoEntryContext.hxx new file mode 100644 index 000000000..f1cc400e5 --- /dev/null +++ b/xmloff/source/text/XMLIndexChapterInfoEntryContext.hxx @@ -0,0 +1,67 @@ +/* -*- 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 "XMLIndexSimpleEntryContext.hxx" +#include +#include +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLIndexTemplateContext; + +/** + * Import chapter info index entry templates + */ +class XMLIndexChapterInfoEntryContext : public XMLIndexSimpleEntryContext +{ + // chapter format + sal_Int16 nChapterInfo; + bool bChapterInfoOK; + bool bTOC; + sal_Int16 nOutlineLevel; + bool bOutlineLevelOK; + +public: + + + XMLIndexChapterInfoEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate, + bool bTOC ); + + virtual ~XMLIndexChapterInfoEntryContext() override; + +protected: + + /** process parameters */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** fill property values for this template entry */ + virtual void FillPropertyValues( + css::uno::Sequence & rValues) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexIllustrationSourceContext.cxx b/xmloff/source/text/XMLIndexIllustrationSourceContext.cxx new file mode 100644 index 000000000..780d821bc --- /dev/null +++ b/xmloff/source/text/XMLIndexIllustrationSourceContext.cxx @@ -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 . + */ + +#include "XMLIndexIllustrationSourceContext.hxx" +#include +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include +#include + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_ILLUSTRATION_INDEX_ENTRY_TEMPLATE; +using ::xmloff::token::XML_TOKEN_INVALID; + + +XMLIndexIllustrationSourceContext::XMLIndexIllustrationSourceContext( + SvXMLImport& rImport, + Reference & rPropSet) : + XMLIndexTableSourceContext(rImport, rPropSet) +{ +} + +XMLIndexIllustrationSourceContext::~XMLIndexIllustrationSourceContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexIllustrationSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_ILLUSTRATION_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameTableMap, + XML_TOKEN_INVALID, // no outline-level attr + aLevelStylePropNameTableMap, + aAllowedTokenTypesTable); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexIllustrationSourceContext.hxx b/xmloff/source/text/XMLIndexIllustrationSourceContext.hxx new file mode 100644 index 000000000..b482c63ff --- /dev/null +++ b/xmloff/source/text/XMLIndexIllustrationSourceContext.hxx @@ -0,0 +1,55 @@ +/* -*- 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 "XMLIndexTableSourceContext.hxx" +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import illustration index source element; + * + * All logic is inherited from table source context. The only difference is + * the different child context (illustration entry template). + */ +class XMLIndexIllustrationSourceContext : public XMLIndexTableSourceContext +{ +public: + + XMLIndexIllustrationSourceContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet); + + virtual ~XMLIndexIllustrationSourceContext() override; + +protected: + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexMarkExport.cxx b/xmloff/source/text/XMLIndexMarkExport.cxx new file mode 100644 index 000000000..f27c87d9e --- /dev/null +++ b/xmloff/source/text/XMLIndexMarkExport.cxx @@ -0,0 +1,228 @@ +/* -*- 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 "XMLIndexMarkExport.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XPropertySetInfo; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; + +XMLIndexMarkExport::XMLIndexMarkExport( + SvXMLExport& rExp) +: rExport(rExp) +{ +} + +const enum XMLTokenEnum lcl_pTocMarkNames[] = + { XML_TOC_MARK, XML_TOC_MARK_START, XML_TOC_MARK_END }; +const enum XMLTokenEnum lcl_pUserIndexMarkName[] = + { XML_USER_INDEX_MARK, + XML_USER_INDEX_MARK_START, XML_USER_INDEX_MARK_END }; +const enum XMLTokenEnum lcl_pAlphaIndexMarkName[] = + { XML_ALPHABETICAL_INDEX_MARK, + XML_ALPHABETICAL_INDEX_MARK_START, + XML_ALPHABETICAL_INDEX_MARK_END }; + + +void XMLIndexMarkExport::ExportIndexMark( + const Reference & rPropSet, + bool bAutoStyles) +{ + /// index marks have no styles! + if (bAutoStyles) + return; + + const enum XMLTokenEnum * pElements = nullptr; + sal_Int8 nElementNo = -1; + + // get index mark + Any aAny = rPropSet->getPropertyValue(gsDocumentIndexMark); + Reference xIndexMarkPropSet; + aAny >>= xIndexMarkPropSet; + + // common: handling of start, end, collapsed entries and + // alternative text + + // collapsed/alternative text entry? + aAny = rPropSet->getPropertyValue(gsIsCollapsed); + if (*o3tl::doAccess(aAny)) + { + // collapsed entry: needs alternative text + nElementNo = 0; + + aAny = xIndexMarkPropSet->getPropertyValue(gsAlternativeText); + OUString sTmp; + aAny >>= sTmp; + DBG_ASSERT(!sTmp.isEmpty(), + "collapsed index mark without alternative text"); + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STRING_VALUE, sTmp); + } + else + { + // start and end entries: has ID + aAny = rPropSet->getPropertyValue(gsIsStart); + nElementNo = *o3tl::doAccess(aAny) ? 1 : 2; + + // generate ID + OUStringBuffer sBuf; + GetID(sBuf, xIndexMarkPropSet); + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_ID, + sBuf.makeStringAndClear()); + } + + // distinguish between TOC, user, alphab. index marks by + // asking for specific properties + // Export attributes for -mark-start and -mark elements, + // but not for -mark-end + Reference xPropertySetInfo = + xIndexMarkPropSet->getPropertySetInfo(); + if (xPropertySetInfo->hasPropertyByName(gsUserIndexName)) + { + // user index mark + pElements = lcl_pUserIndexMarkName; + if (nElementNo != 2) + { + ExportUserIndexMarkAttributes(xIndexMarkPropSet); + } + } + else if (xPropertySetInfo->hasPropertyByName(gsPrimaryKey)) + { + // alphabetical index mark + pElements = lcl_pAlphaIndexMarkName; + if (nElementNo != 2) + { + ExportAlphabeticalIndexMarkAttributes(xIndexMarkPropSet); + } + } + else + { + // table of content: + pElements = lcl_pTocMarkNames; + if (nElementNo != 2) + { + ExportTOCMarkAttributes(xIndexMarkPropSet); + } + } + + // export element + DBG_ASSERT(pElements != nullptr, "illegal element array"); + DBG_ASSERT(nElementNo >= 0, "illegal name array index"); + DBG_ASSERT(nElementNo <= 2, "illegal name array index"); + + if ((pElements != nullptr) && (nElementNo != -1)) + { + SvXMLElementExport aElem(rExport, + XML_NAMESPACE_TEXT, + pElements[nElementNo], + false, false); + } + +} + +void XMLIndexMarkExport::ExportTOCMarkAttributes( + const Reference & rPropSet) +{ + // outline level + sal_Int16 nLevel = 0; + Any aAny = rPropSet->getPropertyValue(gsLevel); + aAny >>= nLevel; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_OUTLINE_LEVEL, + OUString::number(nLevel + 1)); +} + +static void lcl_ExportPropertyString( SvXMLExport& rExport, + const Reference & rPropSet, + const OUString & sProperty, + XMLTokenEnum eToken, + Any& rAny ) +{ + rAny = rPropSet->getPropertyValue( sProperty ); + + OUString sValue; + if( (rAny >>= sValue) && !sValue.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_TEXT, eToken, sValue ); + } +} + +static void lcl_ExportPropertyBool( SvXMLExport& rExport, + const Reference & rPropSet, + const OUString & sProperty, + XMLTokenEnum eToken, + Any& rAny ) +{ + rAny = rPropSet->getPropertyValue( sProperty ); + + bool bValue; + if( (rAny >>= bValue) && bValue ) + { + rExport.AddAttribute( XML_NAMESPACE_TEXT, eToken, XML_TRUE ); + } +} + +void XMLIndexMarkExport::ExportUserIndexMarkAttributes( + const Reference & rPropSet) +{ + // name of user index + // (unless it's the default index; then it has no name) + Any aAny; + lcl_ExportPropertyString( rExport, rPropSet, gsUserIndexName, XML_INDEX_NAME, aAny ); + + // additionally export outline level; just reuse ExportTOCMarkAttributes + ExportTOCMarkAttributes( rPropSet ); +} + +void XMLIndexMarkExport::ExportAlphabeticalIndexMarkAttributes( + const Reference & rPropSet) +{ + // primary and secondary keys (if available) + Any aAny; + lcl_ExportPropertyString( rExport, rPropSet, gsTextReading, XML_STRING_VALUE_PHONETIC, aAny ); + lcl_ExportPropertyString( rExport, rPropSet, gsPrimaryKey, XML_KEY1, aAny ); + lcl_ExportPropertyString( rExport, rPropSet, gsPrimaryKeyReading, XML_KEY1_PHONETIC, aAny ); + lcl_ExportPropertyString( rExport, rPropSet, gsSecondaryKey, XML_KEY2, aAny ); + lcl_ExportPropertyString( rExport, rPropSet, gsSecondaryKeyReading, XML_KEY2_PHONETIC, aAny ); + lcl_ExportPropertyBool( rExport, rPropSet, gsMainEntry, XML_MAIN_ENTRY, aAny ); +} + +void XMLIndexMarkExport::GetID( + OUStringBuffer& sBuf, + const Reference & rPropSet) +{ + // HACK: use address of object to form identifier + sal_Int64 nId = sal::static_int_cast(reinterpret_cast(rPropSet.get())); + sBuf.append("IMark"); + sBuf.append(nId); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexMarkExport.hxx b/xmloff/source/text/XMLIndexMarkExport.hxx new file mode 100644 index 000000000..e406401a6 --- /dev/null +++ b/xmloff/source/text/XMLIndexMarkExport.hxx @@ -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 . + */ + +#pragma once + +#include +#include + +class SvXMLExport; +namespace com::sun::star { + namespace beans { class XPropertySet; } +} + + +/** + * This class handles the export of index marks for table of content, + * alphabetical and user index. + * + * Marks for bibliography indices are internally modelled as text + * fields and thus handled in txtparae.cxx + */ +class XMLIndexMarkExport +{ + static constexpr OUStringLiteral gsLevel = u"Level"; + static constexpr OUStringLiteral gsUserIndexName = u"UserIndexName"; + static constexpr OUStringLiteral gsPrimaryKey = u"PrimaryKey"; + static constexpr OUStringLiteral gsSecondaryKey = u"SecondaryKey"; + static constexpr OUStringLiteral gsDocumentIndexMark = u"DocumentIndexMark"; + static constexpr OUStringLiteral gsIsStart = u"IsStart"; + static constexpr OUStringLiteral gsIsCollapsed = u"IsCollapsed"; + static constexpr OUStringLiteral gsAlternativeText = u"AlternativeText"; + static constexpr OUStringLiteral gsTextReading = u"TextReading"; + static constexpr OUStringLiteral gsPrimaryKeyReading = u"PrimaryKeyReading"; + static constexpr OUStringLiteral gsSecondaryKeyReading = u"SecondaryKeyReading"; + static constexpr OUStringLiteral gsMainEntry = u"IsMainEntry"; + + SvXMLExport& rExport; + +public: + explicit XMLIndexMarkExport(SvXMLExport& rExp); + + /** + * export by the property set of its *text* *portion*. + * + * The text portion supplies us with the properties of the index + * mark itself, as well as the information whether we are at the + * start or end of an index mark, or whether the index mark is + * collapsed. + */ + void ExportIndexMark( + const css::uno::Reference & rPropSet, + bool bAutoStyles); + +private: + + /// export attributes of table-of-content index marks + void ExportTOCMarkAttributes( + const css::uno::Reference & rPropSet); + + /// export attributes of user index marks + void ExportUserIndexMarkAttributes( + const css::uno::Reference & rPropSet); + + /// export attributes of alphabetical index marks + void ExportAlphabeticalIndexMarkAttributes( + const css::uno::Reference & rPropSet); + + /// create a numerical ID for this index mark + /// (represented by its properties) + static void GetID( + OUStringBuffer& sBuffer, + const css::uno::Reference & rPropSet); + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexObjectSourceContext.cxx b/xmloff/source/text/XMLIndexObjectSourceContext.cxx new file mode 100644 index 000000000..d35f3f025 --- /dev/null +++ b/xmloff/source/text/XMLIndexObjectSourceContext.cxx @@ -0,0 +1,139 @@ +/* -*- 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 "XMLIndexObjectSourceContext.hxx" + +#include + +#include + +#include + +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using namespace ::xmloff::token; + + +XMLIndexObjectSourceContext::XMLIndexObjectSourceContext( + SvXMLImport& rImport, + Reference & rPropSet) : + XMLIndexSourceBaseContext(rImport, + rPropSet, false), + bUseCalc(false), + bUseChart(false), + bUseDraw(false), + bUseMath(false), + bUseOtherObjects(false) +{ +} + +XMLIndexObjectSourceContext::~XMLIndexObjectSourceContext() +{ +} + +void XMLIndexObjectSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + bool bTmp(false); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_USE_OTHER_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseOtherObjects = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_SPREADSHEET_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseCalc = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_CHART_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseChart = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_DRAW_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseDraw = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_MATH_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseMath = bTmp; + } + break; + + default: + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexObjectSourceContext::endFastElement(sal_Int32 nElement) +{ + rIndexPropertySet->setPropertyValue("CreateFromStarCalc", css::uno::Any(bUseCalc)); + rIndexPropertySet->setPropertyValue("CreateFromStarChart", css::uno::Any(bUseChart)); + rIndexPropertySet->setPropertyValue("CreateFromStarDraw", css::uno::Any(bUseDraw)); + rIndexPropertySet->setPropertyValue("CreateFromStarMath", css::uno::Any(bUseMath)); + rIndexPropertySet->setPropertyValue("CreateFromOtherEmbeddedObjects", css::uno::Any(bUseOtherObjects)); + + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexObjectSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_OBJECT_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameTableMap, + XML_TOKEN_INVALID, // no outline-level attr + aLevelStylePropNameTableMap, + aAllowedTokenTypesTable); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexObjectSourceContext.hxx b/xmloff/source/text/XMLIndexObjectSourceContext.hxx new file mode 100644 index 000000000..6240a5c28 --- /dev/null +++ b/xmloff/source/text/XMLIndexObjectSourceContext.hxx @@ -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/. + * + * 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 "XMLIndexSourceBaseContext.hxx" +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import object index source element + */ +class XMLIndexObjectSourceContext : public XMLIndexSourceBaseContext +{ + bool bUseCalc; + bool bUseChart; + bool bUseDraw; + bool bUseMath; + bool bUseOtherObjects; + +public: + + + XMLIndexObjectSourceContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet); + + virtual ~XMLIndexObjectSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSimpleEntryContext.cxx b/xmloff/source/text/XMLIndexSimpleEntryContext.cxx new file mode 100644 index 000000000..aa29f4c69 --- /dev/null +++ b/xmloff/source/text/XMLIndexSimpleEntryContext.cxx @@ -0,0 +1,124 @@ +/* -*- 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 "XMLIndexSimpleEntryContext.hxx" +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_STYLE_NAME; + + +XMLIndexSimpleEntryContext::XMLIndexSimpleEntryContext( + SvXMLImport& rImport, + const OUString& rEntry, + XMLIndexTemplateContext& rTemplate ) +: SvXMLImportContext(rImport) +, m_rEntryType(rEntry) +, m_bCharStyleNameOK(false) +, m_rTemplateContext(rTemplate) +, m_nValues(1) +{ +} + +XMLIndexSimpleEntryContext::~XMLIndexSimpleEntryContext() +{ +} + +void XMLIndexSimpleEntryContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // we know only one attribute: style-name + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if(aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME)) + { + m_sCharStyleName = aIter.toString(); + OUString sDisplayStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, m_sCharStyleName ); + // #142494#: Check if style exists + const Reference < css::container::XNameContainer > & rStyles = + GetImport().GetTextImport()->GetTextStyles(); + if( rStyles.is() && rStyles->hasByName( sDisplayStyleName ) ) + m_bCharStyleNameOK = true; + else + m_bCharStyleNameOK = false; + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + + // if we have a style name, set it! + if (m_bCharStyleNameOK) + { + m_nValues++; + } + +} + +void XMLIndexSimpleEntryContext::endFastElement(sal_Int32 ) +{ + Sequence aValues(m_nValues); + + FillPropertyValues(aValues); + m_rTemplateContext.addTemplateEntry(aValues); +} + +void XMLIndexSimpleEntryContext::FillPropertyValues( + css::uno::Sequence & rValues) +{ + // due to the limited number of subclasses, we fill the values + // directly into the slots. Subclasses will have to know they can + // only use slot so-and-so. + + Any aAny; + auto pValues = rValues.getArray(); + + // token type + pValues[0].Name = "TokenType"; + pValues[0].Value <<= m_rEntryType; + + // char style + if (m_bCharStyleNameOK) + { + pValues[1].Name = "CharacterStyleName"; + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, + m_sCharStyleName ); + pValues[1].Value = aAny; + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSimpleEntryContext.hxx b/xmloff/source/text/XMLIndexSimpleEntryContext.hxx new file mode 100644 index 000000000..1fafb4190 --- /dev/null +++ b/xmloff/source/text/XMLIndexSimpleEntryContext.hxx @@ -0,0 +1,79 @@ +/* -*- 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 +#include +#include +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLIndexTemplateContext; + +/** + * Import index entry templates + */ +class XMLIndexSimpleEntryContext : public SvXMLImportContext +{ + + // entry type + const OUString m_rEntryType; + +protected: + // character style + OUString m_sCharStyleName; + bool m_bCharStyleNameOK; + + // surrounding template + XMLIndexTemplateContext& m_rTemplateContext; + + // number of values for PropertyValues + sal_Int32 m_nValues; + +public: + + + XMLIndexSimpleEntryContext( + SvXMLImport& rImport, + const OUString& rEntry, + XMLIndexTemplateContext& rTemplate ); + + virtual ~XMLIndexSimpleEntryContext() override; + +protected: + + /** process parameters */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** call FillPropertyValues and insert into template */ + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + /** fill property values for this template entry */ + virtual void FillPropertyValues( + css::uno::Sequence & rValues); + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSourceBaseContext.cxx b/xmloff/source/text/XMLIndexSourceBaseContext.cxx new file mode 100644 index 000000000..77de7bf4c --- /dev/null +++ b/xmloff/source/text/XMLIndexSourceBaseContext.cxx @@ -0,0 +1,123 @@ +/* -*- 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 "XMLIndexSourceBaseContext.hxx" +#include +#include "XMLIndexTitleTemplateContext.hxx" +#include "XMLIndexTOCStylesContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLIndexSourceBaseContext::XMLIndexSourceBaseContext( + SvXMLImport& rImport, + Reference & rPropSet, + bool bLevelFormats) +: SvXMLImportContext(rImport) +, bUseLevelFormats(bLevelFormats) +, bChapterIndex(false) +, bRelativeTabs(true) +, rIndexPropertySet(rPropSet) +{ +} + +XMLIndexSourceBaseContext::~XMLIndexSourceBaseContext() +{ +} + +void XMLIndexSourceBaseContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process attributes + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + ProcessAttribute(aIter); +} + +void XMLIndexSourceBaseContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_INDEX_SCOPE): + if ( IsXMLToken( aIter, XML_CHAPTER ) ) + { + bChapterIndex = true; + } + break; + + case XML_ELEMENT(TEXT, XML_RELATIVE_TAB_STOP_POSITION): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bRelativeTabs = bTmp; + } + break; + } + + default: + // unknown attribute -> ignore + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } +} + +void XMLIndexSourceBaseContext::endFastElement(sal_Int32 ) +{ + rIndexPropertySet->setPropertyValue("IsRelativeTabstops", css::uno::Any(bRelativeTabs)); + rIndexPropertySet->setPropertyValue("CreateFromChapter", css::uno::Any(bChapterIndex)); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexSourceBaseContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContextRef xContext; + + if (nElement == XML_ELEMENT(TEXT, XML_INDEX_TITLE_TEMPLATE) ) + { + xContext = new XMLIndexTitleTemplateContext(GetImport(), + rIndexPropertySet); + } + else if ( bUseLevelFormats && + nElement == XML_ELEMENT(TEXT, XML_INDEX_SOURCE_STYLES) ) + { + xContext = new XMLIndexTOCStylesContext(GetImport(), + rIndexPropertySet); + } + // else: unknown namespace -> ignore + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSourceBaseContext.hxx b/xmloff/source/text/XMLIndexSourceBaseContext.hxx new file mode 100644 index 000000000..17d287e9a --- /dev/null +++ b/xmloff/source/text/XMLIndexSourceBaseContext.hxx @@ -0,0 +1,72 @@ +/* -*- 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 +#include +#include +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + +/** + * Superclass for index source elements + */ +class XMLIndexSourceBaseContext : public SvXMLImportContext +{ + bool bUseLevelFormats; + bool bChapterIndex; /// chapter-wise or document index? + bool bRelativeTabs; /// tab stops relative to margin or indent? + +protected: + + /// property set of index; must be accessible to subclasses + css::uno::Reference & rIndexPropertySet; + +public: + + + XMLIndexSourceBaseContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet, + bool bLevelFormats); + + virtual ~XMLIndexSourceBaseContext() override; + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSpanEntryContext.cxx b/xmloff/source/text/XMLIndexSpanEntryContext.cxx new file mode 100644 index 000000000..ba0c976cf --- /dev/null +++ b/xmloff/source/text/XMLIndexSpanEntryContext.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/. + * + * 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 "XMLIndexSpanEntryContext.hxx" +#include +#include "XMLIndexTemplateContext.hxx" +#include + + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::com::sun::star::beans::PropertyValue; + + +XMLIndexSpanEntryContext::XMLIndexSpanEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ) : + XMLIndexSimpleEntryContext(rImport, "TokenText", + rTemplate) +{ + m_nValues++; // one more for the text string +} + +XMLIndexSpanEntryContext::~XMLIndexSpanEntryContext() +{ +} + +void XMLIndexSpanEntryContext::characters(const OUString& sString) +{ + sContent.append(sString); +} + +void XMLIndexSpanEntryContext::FillPropertyValues( + Sequence & rValues) +{ + // call superclass for token type, stylename, + XMLIndexSimpleEntryContext::FillPropertyValues(rValues); + + // content + auto pValues = rValues.getArray(); + Any aAny; + aAny <<= sContent.makeStringAndClear(); + pValues[m_nValues-1].Name = "Text"; + pValues[m_nValues-1].Value = aAny; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexSpanEntryContext.hxx b/xmloff/source/text/XMLIndexSpanEntryContext.hxx new file mode 100644 index 000000000..8b4711c1f --- /dev/null +++ b/xmloff/source/text/XMLIndexSpanEntryContext.hxx @@ -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/. + * + * 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 "XMLIndexSimpleEntryContext.hxx" +#include +#include +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} + +/** + * Import index entry templates + */ +class XMLIndexSpanEntryContext : public XMLIndexSimpleEntryContext +{ + OUStringBuffer sContent; + +public: + + + XMLIndexSpanEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ); + + virtual ~XMLIndexSpanEntryContext() override; + +protected: + + /// Collect element contents + virtual void SAL_CALL characters(const OUString& sString) override; + + /// add Text PropertyValue + virtual void FillPropertyValues( + css::uno::Sequence & rValues) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCContext.cxx b/xmloff/source/text/XMLIndexTOCContext.cxx new file mode 100644 index 000000000..e7235f093 --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCContext.cxx @@ -0,0 +1,344 @@ +/* -*- 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 "XMLIndexTOCContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "XMLIndexTOCSourceContext.hxx" +#include "XMLIndexObjectSourceContext.hxx" +#include "XMLIndexAlphabeticalSourceContext.hxx" +#include "XMLIndexUserSourceContext.hxx" +#include "XMLIndexBibliographySourceContext.hxx" +#include "XMLIndexTableSourceContext.hxx" +#include "XMLIndexIllustrationSourceContext.hxx" +#include "XMLIndexBodyContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::lang::IllegalArgumentException; + + +static const char* aIndexServiceMap[] = +{ + "com.sun.star.text.ContentIndex", + "com.sun.star.text.DocumentIndex", + "com.sun.star.text.TableIndex", + "com.sun.star.text.ObjectIndex", + "com.sun.star.text.Bibliography", + "com.sun.star.text.UserIndex", + "com.sun.star.text.IllustrationsIndex" +}; + +const XMLTokenEnum aIndexSourceElementMap[] = +{ + XML_TABLE_OF_CONTENT_SOURCE, + XML_ALPHABETICAL_INDEX_SOURCE, + XML_TABLE_INDEX_SOURCE, + XML_OBJECT_INDEX_SOURCE, + XML_BIBLIOGRAPHY_SOURCE, + XML_USER_INDEX_SOURCE, + XML_ILLUSTRATION_INDEX_SOURCE +}; + +SvXMLEnumMapEntry const aIndexTypeMap[] = +{ + { XML_TABLE_OF_CONTENT, TEXT_INDEX_TOC }, + { XML_ALPHABETICAL_INDEX, TEXT_INDEX_ALPHABETICAL }, + { XML_TABLE_INDEX, TEXT_INDEX_TABLE }, + { XML_OBJECT_INDEX, TEXT_INDEX_OBJECT }, + { XML_BIBLIOGRAPHY, TEXT_INDEX_BIBLIOGRAPHY }, + { XML_USER_INDEX, TEXT_INDEX_USER }, + { XML_ILLUSTRATION_INDEX, TEXT_INDEX_ILLUSTRATION }, + { XML_TOKEN_INVALID, IndexTypeEnum(0) } +}; + + +XMLIndexTOCContext::XMLIndexTOCContext(SvXMLImport& rImport, + sal_Int32 nElement) + : SvXMLImportContext(rImport) + , eIndexType(TEXT_INDEX_UNKNOWN) + , bValid(false) +{ + if (IsTokenInNamespace(nElement, XML_NAMESPACE_TEXT)) + { + if (SvXMLUnitConverter::convertEnum(eIndexType, SvXMLImport::getNameFromToken(nElement), aIndexTypeMap)) + { + // check for array index: + OSL_ENSURE(unsigned(eIndexType) < (SAL_N_ELEMENTS(aIndexServiceMap)), "index out of range"); + OSL_ENSURE(SAL_N_ELEMENTS(aIndexServiceMap) == + SAL_N_ELEMENTS(aIndexSourceElementMap), + "service and source element maps must be same size"); + bValid = true; + } + } +} + +XMLIndexTOCContext::~XMLIndexTOCContext() +{ +} + +void XMLIndexTOCContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if (!bValid) + return; + + // find text:style-name attribute and set section style + // find text:protected and set value + // find text:name and set value (if not empty) + bool bProtected = false; + OUString sIndexName; + OUString sXmlId; + XMLPropStyleContext* pStyle(nullptr); + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + { + pStyle = GetImport().GetTextImport()->FindSectionStyle( + aIter.toString()); + break; + } + case XML_ELEMENT(TEXT, XML_PROTECTED): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bProtected = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_NAME): + { + sIndexName = aIter.toString(); + break; + } + case XML_ELEMENT(XML, XML_ID): + { + sXmlId = aIter.toString(); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // create table of content (via MultiServiceFactory) + Reference xFactory(GetImport().GetModel(), + UNO_QUERY); + if( xFactory.is() ) + { + Reference xIfc = + xFactory->createInstance( + OUString::createFromAscii(aIndexServiceMap[eIndexType])); + if( xIfc.is() ) + { + // get Property set + Reference xPropSet(xIfc, UNO_QUERY); + xTOCPropertySet = xPropSet; + + // insert section + // a) insert section + // The inserted index consists of an empty paragraph + // only, as well as an empty paragraph *after* the index + // b) insert marker after index, and put Cursor inside of the + // index + + // preliminaries +#ifndef DBG_UTIL + OUString const sMarker(" "); +#else + OUString const sMarker("Y"); +#endif + rtl::Reference rImport = + GetImport().GetTextImport(); + + // a) insert index + Reference xTextContent(xIfc, UNO_QUERY); + try + { + GetImport().GetTextImport()->InsertTextContent( + xTextContent); + } + catch(const IllegalArgumentException& e) + { + // illegal argument? Then we can't accept indices here! + Sequence aSeq { SvXMLImport::getNameFromToken(nElement) }; + GetImport().SetError( + XMLERROR_FLAG_ERROR | XMLERROR_NO_INDEX_ALLOWED_HERE, + aSeq, e.Message, nullptr ); + + // set bValid to false, and return prematurely + bValid = false; + return; + } + + // xml:id for RDF metadata + GetImport().SetXmlId(xIfc, sXmlId); + + // b) insert marker and move cursor + rImport->InsertString(sMarker); + rImport->GetCursor()->goLeft(2, false); + } + } + + // finally, check for redlines that should start at + // the section start node + if( bValid ) + GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(); + + if (pStyle != nullptr) + { + pStyle->FillPropertySet( xTOCPropertySet ); + } + + xTOCPropertySet->setPropertyValue( "IsProtected", Any(bProtected) ); + + if (!sIndexName.isEmpty()) + { + xTOCPropertySet->setPropertyValue( "Name", Any(sIndexName) ); + } + +} + +void XMLIndexTOCContext::endFastElement(sal_Int32 ) +{ + // complete import of index by removing the markers (if the index + // was actually inserted, that is) + if( !bValid ) + return; + + // preliminaries + rtl::Reference rHelper= GetImport().GetTextImport(); + + // get rid of last paragraph (unless it's the only paragraph) + rHelper->GetCursor()->goRight(1, false); + if( xBodyContextRef.is() && xBodyContextRef->HasContent() ) + { + rHelper->GetCursor()->goLeft(1, true); + rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), + "", true); + } + + // and delete second marker + rHelper->GetCursor()->goRight(1, true); + rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), + "", true); + + // check for Redlines on our end node + GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTOCContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContextRef xContext; + + // not valid -> ignore + if (!bValid) + return nullptr; + + if (nElement == XML_ELEMENT(TEXT, XML_INDEX_BODY) ) + { + rtl::Reference xNewBodyContext = new XMLIndexBodyContext(GetImport()); + xContext = xNewBodyContext; + if ( !xBodyContextRef.is() || !xBodyContextRef->HasContent() ) + { + xBodyContextRef = xNewBodyContext; + } + } + else if (nElement == XML_ELEMENT(TEXT, aIndexSourceElementMap[eIndexType])) + { + // instantiate source context for the appropriate index type + switch (eIndexType) + { + case TEXT_INDEX_TOC: + xContext = new XMLIndexTOCSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_OBJECT: + xContext = new XMLIndexObjectSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_ALPHABETICAL: + xContext = new XMLIndexAlphabeticalSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_USER: + xContext = new XMLIndexUserSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_BIBLIOGRAPHY: + xContext = new XMLIndexBibliographySourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_TABLE: + xContext = new XMLIndexTableSourceContext( + GetImport(), xTOCPropertySet); + break; + + case TEXT_INDEX_ILLUSTRATION: + xContext = new XMLIndexIllustrationSourceContext( + GetImport(), xTOCPropertySet); + break; + + default: + OSL_FAIL("index type not implemented"); + break; + } + } + // else: ignore + + return xContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCContext.hxx b/xmloff/source/text/XMLIndexTOCContext.hxx new file mode 100644 index 000000000..47cd8ad2c --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCContext.hxx @@ -0,0 +1,82 @@ +/* -*- 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 +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +enum IndexTypeEnum +{ + TEXT_INDEX_TOC, + TEXT_INDEX_ALPHABETICAL, + TEXT_INDEX_TABLE, + TEXT_INDEX_OBJECT, + TEXT_INDEX_BIBLIOGRAPHY, + TEXT_INDEX_USER, + TEXT_INDEX_ILLUSTRATION, + + TEXT_INDEX_UNKNOWN +}; + +class XMLIndexBodyContext; +/** + * Import all indices. + * + * Originally, this class would import only the TOC (table of + * content), but now it's role has been expanded to handle all + * indices, and hence is named inappropriately. Depending on the + * element name it decides which index source element context to create. + */ +class XMLIndexTOCContext final : public SvXMLImportContext +{ + /** XPropertySet of the index */ + css::uno::Reference xTOCPropertySet; + + enum IndexTypeEnum eIndexType; + + bool bValid; + + rtl::Reference xBodyContextRef; + +public: + + XMLIndexTOCContext( SvXMLImport& rImport, sal_Int32 nElement ); + + virtual ~XMLIndexTOCContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCSourceContext.cxx b/xmloff/source/text/XMLIndexTOCSourceContext.cxx new file mode 100644 index 000000000..45899e454 --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCSourceContext.cxx @@ -0,0 +1,150 @@ +/* -*- 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 "XMLIndexTOCSourceContext.hxx" +#include +#include +#include +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include +#include + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::xml::sax::XAttributeList; + +XMLIndexTOCSourceContext::XMLIndexTOCSourceContext( + SvXMLImport& rImport, + Reference & rPropSet) +: XMLIndexSourceBaseContext(rImport, rPropSet, true) + // use all chapters by default +, nOutlineLevel(rImport.GetTextImport()->GetChapterNumbering()->getCount()) +, bUseOutline(true) +, bUseMarks(true) +, bUseParagraphStyles(false) +{ +} + +XMLIndexTOCSourceContext::~XMLIndexTOCSourceContext() +{ +} + +void XMLIndexTOCSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + if ( IsXMLToken( aIter, XML_NONE ) ) + { + // #104651# use OUTLINE_LEVEL and USE_OUTLINE_LEVEL instead of + // OUTLINE_LEVEL with values none|1..10. For backwards + // compatibility, 'none' must still be read. + bUseOutline = false; + } + else + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( + nTmp, aIter.toView(), 1, GetImport().GetTextImport()-> + GetChapterNumbering()->getCount())) + { + bUseOutline = true; + nOutlineLevel = nTmp; + } + } + break; + + case XML_ELEMENT(TEXT, XML_USE_OUTLINE_LEVEL): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseOutline = bTmp; + } + break; + } + + + case XML_ELEMENT(TEXT, XML_USE_INDEX_MARKS): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseMarks = bTmp; + } + break; + } + + case XML_ELEMENT(TEXT, XML_USE_INDEX_SOURCE_STYLES): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseParagraphStyles = bTmp; + } + break; + } + + default: + // default: ask superclass + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexTOCSourceContext::endFastElement(sal_Int32 nElement) +{ + rIndexPropertySet->setPropertyValue("CreateFromMarks", css::uno::Any(bUseMarks)); + rIndexPropertySet->setPropertyValue("CreateFromOutline", css::uno::Any(bUseOutline)); + rIndexPropertySet->setPropertyValue("CreateFromLevelParagraphStyles", css::uno::Any(bUseParagraphStyles)); + + rIndexPropertySet->setPropertyValue("Level", css::uno::Any(static_cast(nOutlineLevel))); + + // process common attributes + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTOCSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_TABLE_OF_CONTENT_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aSvLevelNameTOCMap, + XML_OUTLINE_LEVEL, + aLevelStylePropNameTOCMap, + aAllowedTokenTypesTOC, true ); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCSourceContext.hxx b/xmloff/source/text/XMLIndexTOCSourceContext.hxx new file mode 100644 index 000000000..f8129fc14 --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCSourceContext.hxx @@ -0,0 +1,62 @@ +/* -*- 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 "XMLIndexSourceBaseContext.hxx" +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import table of context source element + */ +class XMLIndexTOCSourceContext : public XMLIndexSourceBaseContext +{ + sal_Int32 nOutlineLevel; + bool bUseOutline; + bool bUseMarks; + bool bUseParagraphStyles; + +public: + + + XMLIndexTOCSourceContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet); + + virtual ~XMLIndexTOCSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCStylesContext.cxx b/xmloff/source/text/XMLIndexTOCStylesContext.cxx new file mode 100644 index 000000000..5331b687a --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCStylesContext.cxx @@ -0,0 +1,128 @@ +/* -*- 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 "XMLIndexTOCStylesContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::com::sun::star::container::XIndexReplace; +using ::com::sun::star::xml::sax::XAttributeList; + + + +XMLIndexTOCStylesContext::XMLIndexTOCStylesContext( + SvXMLImport& rImport, Reference & rPropSet) + : SvXMLImportContext(rImport) + , rTOCPropertySet(rPropSet) + , nOutlineLevel(0) +{ +} + +XMLIndexTOCStylesContext::~XMLIndexTOCStylesContext() +{ +} + +void XMLIndexTOCStylesContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // find text:outline-level attribute + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL) ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( + nTmp, aIter.toView(), 1, + GetImport().GetTextImport()->GetChapterNumbering()-> + getCount())) + { + // API numbers 0..9, we number 1..10 + nOutlineLevel = nTmp-1; + } + break; + } + } +} + +void XMLIndexTOCStylesContext::endFastElement(sal_Int32 ) +{ + // if valid... + if (nOutlineLevel < 0) + return; + + // copy vector into sequence + const sal_Int32 nCount = aStyleNames.size(); + Sequence aStyleNamesSequence(nCount); + auto aStyleNamesSequenceRange = asNonConstRange(aStyleNamesSequence); + for(sal_Int32 i = 0; i < nCount; i++) + { + aStyleNamesSequenceRange[i] = GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, + aStyleNames[i] ); + } + + // get index replace + Any aAny = rTOCPropertySet->getPropertyValue("LevelParagraphStyles"); + Reference xIndexReplace; + aAny >>= xIndexReplace; + + // set style names + xIndexReplace->replaceByIndex(nOutlineLevel, Any(aStyleNamesSequence)); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTOCStylesContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // check for index-source-style + if ( nElement == XML_ELEMENT(TEXT, XML_INDEX_SOURCE_STYLE) ) + { + // find text:style-name attribute and record in aStyleNames + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + aStyleNames.push_back(aIter.toString()); + break; + } + } + } + + // always return default context; we already got the interesting info + return new SvXMLImportContext(GetImport()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTOCStylesContext.hxx b/xmloff/source/text/XMLIndexTOCStylesContext.hxx new file mode 100644 index 000000000..a34cf604f --- /dev/null +++ b/xmloff/source/text/XMLIndexTOCStylesContext.hxx @@ -0,0 +1,73 @@ +/* -*- 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 +#include + +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import elements and their children + * + * (Small hackery here: Because there's only one type of child + * elements with only one interesting attribute, we completely handle + * them inside the CreateChildContext method, rather than creating a + * new import class for them. This must be changed if children become + * more complex in future versions.) + */ +class XMLIndexTOCStylesContext : public SvXMLImportContext +{ + /// XPropertySet of the index + css::uno::Reference & rTOCPropertySet; + + /// style names for this level + ::std::vector< OUString > aStyleNames; + + /// outline level + sal_Int32 nOutlineLevel; + +public: + XMLIndexTOCStylesContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet ); + + virtual ~XMLIndexTOCStylesContext() override; + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTabStopEntryContext.cxx b/xmloff/source/text/XMLIndexTabStopEntryContext.cxx new file mode 100644 index 000000000..528b72a7a --- /dev/null +++ b/xmloff/source/text/XMLIndexTabStopEntryContext.cxx @@ -0,0 +1,156 @@ +/* -*- 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 "XMLIndexTabStopEntryContext.hxx" + +#include + +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include +#include +#include + +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLIndexTabStopEntryContext::XMLIndexTabStopEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ) : + XMLIndexSimpleEntryContext(rImport, "TokenTabStop", + rTemplate), + nTabPosition(0), + bTabPositionOK(false), + bTabRightAligned(false), + bLeaderCharOK(false), + bWithTab(true) // #i21237# +{ +} + +XMLIndexTabStopEntryContext::~XMLIndexTabStopEntryContext() +{ +} + +void XMLIndexTabStopEntryContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process three attributes: type, position, leader char + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_TYPE): + { + // if it's neither left nor right, value is + // ignored. Since left is default, we only need to + // check for right + bTabRightAligned = IsXMLToken( aIter, XML_RIGHT ); + break; + } + case XML_ELEMENT(STYLE, XML_POSITION): + { + sal_Int32 nTmp; + if (GetImport().GetMM100UnitConverter(). + convertMeasureToCore(nTmp, aIter.toView())) + { + nTabPosition = nTmp; + bTabPositionOK = true; + } + break; + } + case XML_ELEMENT(STYLE, XML_LEADER_CHAR): + { + sLeaderChar = aIter.toString(); + // valid only, if we have a char! + bLeaderCharOK = !sLeaderChar.isEmpty(); + break; + } + case XML_ELEMENT(STYLE, XML_WITH_TAB): + { + // #i21237# + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + bWithTab = bTmp; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + // else: unknown style: attribute -> ignore + } + } + + // how many entries? #i21237# + m_nValues += 2 + (bTabPositionOK ? 1 : 0) + (bLeaderCharOK ? 1 : 0); + + // now try parent class (for character style) + XMLIndexSimpleEntryContext::startFastElement( nElement, xAttrList ); +} + +void XMLIndexTabStopEntryContext::FillPropertyValues( + Sequence & rValues) +{ + // fill values from parent class (type + style name) + XMLIndexSimpleEntryContext::FillPropertyValues(rValues); + + // get values array and next entry to be written; + sal_Int32 nNextEntry = m_bCharStyleNameOK ? 2 : 1; + PropertyValue* pValues = rValues.getArray(); + + // right aligned? + pValues[nNextEntry].Name = "TabStopRightAligned"; + pValues[nNextEntry].Value <<= bTabRightAligned; + nNextEntry++; + + // position + if (bTabPositionOK) + { + pValues[nNextEntry].Name = "TabStopPosition"; + pValues[nNextEntry].Value <<= nTabPosition; + nNextEntry++; + } + + // leader char + if (bLeaderCharOK) + { + pValues[nNextEntry].Name = "TabStopFillCharacter"; + pValues[nNextEntry].Value <<= sLeaderChar; + nNextEntry++; + } + + // tab character #i21237# + pValues[nNextEntry].Name = "WithTab"; + pValues[nNextEntry].Value <<= bWithTab; + nNextEntry++; + + // check whether we really filled all elements of the sequence + SAL_WARN_IF( nNextEntry != rValues.getLength(), "xmloff", + "length incorrectly precomputed!" ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTabStopEntryContext.hxx b/xmloff/source/text/XMLIndexTabStopEntryContext.hxx new file mode 100644 index 000000000..5c208f638 --- /dev/null +++ b/xmloff/source/text/XMLIndexTabStopEntryContext.hxx @@ -0,0 +1,66 @@ +/* -*- 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 "XMLIndexSimpleEntryContext.hxx" +#include +#include +#include +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLIndexTemplateContext; + +/** + * Import index entry templates + */ +class XMLIndexTabStopEntryContext : public XMLIndexSimpleEntryContext +{ + OUString sLeaderChar; /// fill ("leader") character + sal_Int32 nTabPosition; /// tab position + bool bTabPositionOK; /// is tab right aligned? + bool bTabRightAligned; /// is nTabPosition valid? + bool bLeaderCharOK; /// is sLeaderChar valid? + bool bWithTab; /// is tab char present? #i21237# + +public: + + + XMLIndexTabStopEntryContext( + SvXMLImport& rImport, + XMLIndexTemplateContext& rTemplate ); + + virtual ~XMLIndexTabStopEntryContext() override; + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** fill property values for this template entry */ + virtual void FillPropertyValues( + css::uno::Sequence & rValues) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTableSourceContext.cxx b/xmloff/source/text/XMLIndexTableSourceContext.cxx new file mode 100644 index 000000000..480baf0ce --- /dev/null +++ b/xmloff/source/text/XMLIndexTableSourceContext.cxx @@ -0,0 +1,148 @@ +/* -*- 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 "XMLIndexTableSourceContext.hxx" + +#include +#include + +#include + +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::xml::sax::XAttributeList; + +XMLIndexTableSourceContext::XMLIndexTableSourceContext( + SvXMLImport& rImport, Reference & rPropSet) + : XMLIndexSourceBaseContext(rImport, + rPropSet, false) + , nDisplayFormat(0) + , bSequenceOK(false) + , bDisplayFormatOK(false) + , bUseCaption(true) +{ +} + +XMLIndexTableSourceContext::~XMLIndexTableSourceContext() +{ +} + +SvXMLEnumMapEntry const lcl_aReferenceTypeTokenMap[] = +{ + + { XML_TEXT, ReferenceFieldPart::TEXT }, + { XML_CATEGORY_AND_VALUE, ReferenceFieldPart::CATEGORY_AND_NUMBER }, + { XML_CAPTION, ReferenceFieldPart::ONLY_CAPTION }, + + // wrong values that previous versions wrote: + { XML_CHAPTER, ReferenceFieldPart::CATEGORY_AND_NUMBER }, + { XML_PAGE, ReferenceFieldPart::ONLY_CAPTION }, + + { XML_TOKEN_INVALID, 0 } +}; + +void XMLIndexTableSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + bool bTmp(false); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_USE_CAPTION): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseCaption = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_CAPTION_SEQUENCE_NAME): + sSequence = aIter.toString(); + bSequenceOK = true; + break; + + case XML_ELEMENT(TEXT, XML_CAPTION_SEQUENCE_FORMAT): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, aIter.toView(), + lcl_aReferenceTypeTokenMap)) + { + nDisplayFormat = nTmp; + bDisplayFormatOK = true; + } + break; + } + + default: + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexTableSourceContext::endFastElement(sal_Int32 nElement) +{ + rIndexPropertySet->setPropertyValue("CreateFromLabels", css::uno::Any(bUseCaption)); + + if (bSequenceOK) + { + rIndexPropertySet->setPropertyValue("LabelCategory", css::uno::Any(sSequence)); + } + + if (bDisplayFormatOK) + { + rIndexPropertySet->setPropertyValue("LabelDisplayType", css::uno::Any(nDisplayFormat)); + } + + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTableSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_TABLE_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aLevelNameTableMap, + XML_TOKEN_INVALID, // no outline-level attr + aLevelStylePropNameTableMap, + aAllowedTokenTypesTable); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTableSourceContext.hxx b/xmloff/source/text/XMLIndexTableSourceContext.hxx new file mode 100644 index 000000000..1a0a7b0bf --- /dev/null +++ b/xmloff/source/text/XMLIndexTableSourceContext.hxx @@ -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/. + * + * 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 "XMLIndexSourceBaseContext.hxx" +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import table index source element + */ +class XMLIndexTableSourceContext : public XMLIndexSourceBaseContext +{ + OUString sSequence; + sal_Int16 nDisplayFormat; + + bool bSequenceOK; + bool bDisplayFormatOK; + bool bUseCaption; + +public: + + XMLIndexTableSourceContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet); + + virtual ~XMLIndexTableSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTemplateContext.cxx b/xmloff/source/text/XMLIndexTemplateContext.cxx new file mode 100644 index 000000000..8dfa4b1fd --- /dev/null +++ b/xmloff/source/text/XMLIndexTemplateContext.cxx @@ -0,0 +1,422 @@ +/* -*- 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 "XMLIndexTemplateContext.hxx" +#include "XMLIndexSimpleEntryContext.hxx" +#include "XMLIndexSpanEntryContext.hxx" +#include "XMLIndexTabStopEntryContext.hxx" +#include "XMLIndexBibliographyEntryContext.hxx" +#include "XMLIndexChapterInfoEntryContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::std; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::PropertyValues; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::Any; +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::container::XIndexReplace; + +XMLIndexTemplateContext::XMLIndexTemplateContext( + SvXMLImport& rImport, + Reference & rPropSet, + const SvXMLEnumMapEntry* pLevelNameMap, + enum XMLTokenEnum eLevelAttrName, + const char** pLevelStylePropMap, + const bool* pAllowedTokenTypes, + bool bT ) +: SvXMLImportContext(rImport) +, pOutlineLevelNameMap(pLevelNameMap) +, eOutlineLevelAttrName(eLevelAttrName) +, pOutlineLevelStylePropMap(pLevelStylePropMap) +, pAllowedTokenTypesMap(pAllowedTokenTypes) +, nOutlineLevel(1) // all indices have level 1 (0 is for header) +, bStyleNameOK(false) +, bOutlineLevelOK(false) +, bTOC( bT ) +, rPropertySet(rPropSet) +{ + DBG_ASSERT( ((XML_TOKEN_INVALID != eLevelAttrName) && (nullptr != pLevelNameMap)) + || ((XML_TOKEN_INVALID == eLevelAttrName) && (nullptr == pLevelNameMap)), + "need both, attribute name and value map, or neither" ); + SAL_WARN_IF( nullptr == pOutlineLevelStylePropMap, "xmloff", "need property name map" ); + SAL_WARN_IF( nullptr == pAllowedTokenTypes, "xmloff", "need allowed tokens map" ); + + // no map for outline-level? then use 1 + if (nullptr == pLevelNameMap) + { + nOutlineLevel = 1; + bOutlineLevelOK = true; + } +} + +XMLIndexTemplateContext::~XMLIndexTemplateContext() +{ +} + + +void XMLIndexTemplateContext::addTemplateEntry( + const PropertyValues& aValues) +{ + aValueVector.push_back(aValues); +} + + +void XMLIndexTemplateContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process two attributes: style-name, outline-level + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if(aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME)) + { + // style name + sStyleName = aIter.toString(); + bStyleNameOK = true; + } + else if (aIter.getToken() == XML_ELEMENT(TEXT, eOutlineLevelAttrName)) + { + // we have an attr name! Then see if we have the attr, too. + // outline level + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, aIter.toView(), pOutlineLevelNameMap)) + { + nOutlineLevel = nTmp; + bOutlineLevelOK = true; + } + // else: illegal value -> ignore + } + // else: attribute not in text namespace -> ignore + } +} + +void XMLIndexTemplateContext::endFastElement(sal_Int32 ) +{ + if (!bOutlineLevelOK) + return; + + const sal_Int32 nCount = aValueVector.size(); + Sequence aValueSequence(nCount); + std::copy(aValueVector.begin(), aValueVector.end(), aValueSequence.getArray()); + + // get LevelFormat IndexReplace ... + Any aAny = rPropertySet->getPropertyValue("LevelFormat"); + Reference xIndexReplace; + aAny >>= xIndexReplace; + + // ... and insert + xIndexReplace->replaceByIndex(nOutlineLevel, Any(aValueSequence)); + + if (!bStyleNameOK) + return; + + const char* pStyleProperty = + pOutlineLevelStylePropMap[nOutlineLevel]; + + DBG_ASSERT(nullptr != pStyleProperty, "need property name"); + if (nullptr == pStyleProperty) + return; + + OUString sDisplayStyleName = + GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, + sStyleName ); + // #i50288#: Check if style exists + const Reference < css::container::XNameContainer > & rStyles = + GetImport().GetTextImport()->GetParaStyles(); + if( rStyles.is() && + rStyles->hasByName( sDisplayStyleName ) ) + { + rPropertySet->setPropertyValue( + OUString::createFromAscii(pStyleProperty), css::uno::Any(sDisplayStyleName)); + } +} + +namespace { +/// template token types; used for aTokenTypeMap parameter +enum TemplateTokenType +{ + XML_TOK_INDEX_TYPE_ENTRY_TEXT = 0, + XML_TOK_INDEX_TYPE_TAB_STOP, + XML_TOK_INDEX_TYPE_TEXT, + XML_TOK_INDEX_TYPE_PAGE_NUMBER, + XML_TOK_INDEX_TYPE_CHAPTER, + XML_TOK_INDEX_TYPE_LINK_START, + XML_TOK_INDEX_TYPE_LINK_END, + XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + +} + +SvXMLEnumMapEntry const aTemplateTokenTypeMap[] = +{ + { XML_INDEX_ENTRY_TEXT, XML_TOK_INDEX_TYPE_ENTRY_TEXT }, + { XML_INDEX_ENTRY_TAB_STOP, XML_TOK_INDEX_TYPE_TAB_STOP }, + { XML_INDEX_ENTRY_SPAN, XML_TOK_INDEX_TYPE_TEXT }, + { XML_INDEX_ENTRY_PAGE_NUMBER, XML_TOK_INDEX_TYPE_PAGE_NUMBER }, + { XML_INDEX_ENTRY_CHAPTER, XML_TOK_INDEX_TYPE_CHAPTER }, + { XML_INDEX_ENTRY_LINK_START, XML_TOK_INDEX_TYPE_LINK_START }, + { XML_INDEX_ENTRY_LINK_END, XML_TOK_INDEX_TYPE_LINK_END }, + { XML_INDEX_ENTRY_BIBLIOGRAPHY, XML_TOK_INDEX_TYPE_BIBLIOGRAPHY }, + { XML_TOKEN_INVALID, TemplateTokenType(0) } +}; + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexTemplateContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + if (IsTokenInNamespace(nElement, XML_NAMESPACE_TEXT) || IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT)) + { + TemplateTokenType nToken; + if (SvXMLUnitConverter::convertEnum(nToken, SvXMLImport::getNameFromToken(nElement), + aTemplateTokenTypeMap)) + { + // can this index accept this kind of token? + if (pAllowedTokenTypesMap[nToken]) + { + switch (nToken) + { + case XML_TOK_INDEX_TYPE_ENTRY_TEXT: + pContext = new XMLIndexSimpleEntryContext( + GetImport(), "TokenEntryText", *this); + break; + + case XML_TOK_INDEX_TYPE_PAGE_NUMBER: + pContext = new XMLIndexSimpleEntryContext( + GetImport(), "TokenPageNumber", *this); + break; + + case XML_TOK_INDEX_TYPE_LINK_START: + pContext = new XMLIndexSimpleEntryContext( + GetImport(), "TokenHyperlinkStart", *this); + break; + + case XML_TOK_INDEX_TYPE_LINK_END: + pContext = new XMLIndexSimpleEntryContext( + GetImport(), "TokenHyperlinkEnd", *this); + break; + + case XML_TOK_INDEX_TYPE_TEXT: + pContext = new XMLIndexSpanEntryContext( + GetImport(), *this); + break; + + case XML_TOK_INDEX_TYPE_TAB_STOP: + pContext = new XMLIndexTabStopEntryContext( + GetImport(), *this); + break; + + case XML_TOK_INDEX_TYPE_BIBLIOGRAPHY: + pContext = new XMLIndexBibliographyEntryContext( + GetImport(), *this); + break; + + case XML_TOK_INDEX_TYPE_CHAPTER: + pContext = new XMLIndexChapterInfoEntryContext( + GetImport(), *this, bTOC ); + break; + + default: + // ignore! + break; + } + } + } + } + + // ignore unknown + return pContext; +} + + +// maps for the XMLIndexTemplateContext constructor + + +// table of content and user defined index: + +const SvXMLEnumMapEntry aSvLevelNameTOCMap[] = +{ + { XML_1, 1 }, + { XML_2, 2 }, + { XML_3, 3 }, + { XML_4, 4 }, + { XML_5, 5 }, + { XML_6, 6 }, + { XML_7, 7 }, + { XML_8, 8 }, + { XML_9, 9 }, + { XML_10, 10 }, + { XML_TOKEN_INVALID, 0 } +}; + +const char* aLevelStylePropNameTOCMap[] = + { nullptr, "ParaStyleLevel1", "ParaStyleLevel2", "ParaStyleLevel3", + "ParaStyleLevel4", "ParaStyleLevel5", "ParaStyleLevel6", + "ParaStyleLevel7", "ParaStyleLevel8", "ParaStyleLevel9", + "ParaStyleLevel10", nullptr }; + +const bool aAllowedTokenTypesTOC[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + true, // XML_TOK_INDEX_TYPE_CHAPTER, + true, // XML_TOK_INDEX_TYPE_LINK_START, + true, // XML_TOK_INDEX_TYPE_LINK_END, + false // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + +const bool aAllowedTokenTypesUser[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + true, // XML_TOK_INDEX_TYPE_CHAPTER, + true, // XML_TOK_INDEX_TYPE_LINK_START, + true, // XML_TOK_INDEX_TYPE_LINK_END, + false // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + + +// alphabetical index + +const SvXMLEnumMapEntry aLevelNameAlphaMap[] = +{ + { XML_SEPARATOR, 1 }, + { XML_1, 2 }, + { XML_2, 3 }, + { XML_3, 4 }, + { XML_TOKEN_INVALID, 0 } +}; + +const char* aLevelStylePropNameAlphaMap[] = + { nullptr, "ParaStyleSeparator", "ParaStyleLevel1", "ParaStyleLevel2", + "ParaStyleLevel3", nullptr }; + +const bool aAllowedTokenTypesAlpha[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + true, // XML_TOK_INDEX_TYPE_CHAPTER, + false, // XML_TOK_INDEX_TYPE_LINK_START, + false, // XML_TOK_INDEX_TYPE_LINK_END, + false // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + + +// bibliography index: + +const SvXMLEnumMapEntry aLevelNameBibliographyMap[] = +{ + { XML_ARTICLE, 1 }, + { XML_BOOK, 2 }, + { XML_BOOKLET, 3 }, + { XML_CONFERENCE, 4 }, + { XML_CUSTOM1, 5 }, + { XML_CUSTOM2, 6 }, + { XML_CUSTOM3, 7 }, + { XML_CUSTOM4, 8 }, + { XML_CUSTOM5, 9 }, + { XML_EMAIL, 10 }, + { XML_INBOOK, 11 }, + { XML_INCOLLECTION, 12 }, + { XML_INPROCEEDINGS, 13 }, + { XML_JOURNAL, 14 }, + { XML_MANUAL, 15 }, + { XML_MASTERSTHESIS, 16 }, + { XML_MISC, 17 }, + { XML_PHDTHESIS, 18 }, + { XML_PROCEEDINGS, 19 }, + { XML_TECHREPORT, 20 }, + { XML_UNPUBLISHED, 21 }, + { XML_WWW, 22 }, + { XML_TOKEN_INVALID, 0 } +}; + +// TODO: replace with real property names, when available +const char* aLevelStylePropNameBibliographyMap[] = +{ + nullptr, "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", nullptr }; + +const bool aAllowedTokenTypesBibliography[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + false, // XML_TOK_INDEX_TYPE_CHAPTER, + false, // XML_TOK_INDEX_TYPE_LINK_START, + false, // XML_TOK_INDEX_TYPE_LINK_END, + true // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + + +// table, illustration and object index + +// no name map +const SvXMLEnumMapEntry* aLevelNameTableMap = nullptr; + +const char* aLevelStylePropNameTableMap[] = + { nullptr, "ParaStyleLevel1", nullptr }; + +const bool aAllowedTokenTypesTable[] = +{ + true, // XML_TOK_INDEX_TYPE_ENTRY_TEXT = + true, // XML_TOK_INDEX_TYPE_TAB_STOP, + true, // XML_TOK_INDEX_TYPE_TEXT, + true, // XML_TOK_INDEX_TYPE_PAGE_NUMBER, + true, // XML_TOK_INDEX_TYPE_CHAPTER, + true, // XML_TOK_INDEX_TYPE_LINK_START, + true, // XML_TOK_INDEX_TYPE_LINK_END, + false // XML_TOK_INDEX_TYPE_BIBLIOGRAPHY +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTemplateContext.hxx b/xmloff/source/text/XMLIndexTemplateContext.hxx new file mode 100644 index 000000000..424693d7e --- /dev/null +++ b/xmloff/source/text/XMLIndexTemplateContext.hxx @@ -0,0 +1,125 @@ +/* -*- 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 +#include + +#include +#include +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} +template struct SvXMLEnumMapEntry; + + +// constants for the XMLIndexTemplateContext constructor + +// TOC and user defined index: +extern const SvXMLEnumMapEntry aSvLevelNameTOCMap[]; +extern const char* aLevelStylePropNameTOCMap[]; +extern const bool aAllowedTokenTypesTOC[]; +extern const bool aAllowedTokenTypesUser[]; + +// alphabetical index: +extern const SvXMLEnumMapEntry aLevelNameAlphaMap[]; +extern const char* aLevelStylePropNameAlphaMap[]; +extern const bool aAllowedTokenTypesAlpha[]; + +// bibliography: +extern const SvXMLEnumMapEntry aLevelNameBibliographyMap[]; +extern const char* aLevelStylePropNameBibliographyMap[]; +extern const bool aAllowedTokenTypesBibliography[]; + +// table, illustration and object tables: +extern const SvXMLEnumMapEntry* aLevelNameTableMap; // NULL: no outline-level +extern const char* aLevelStylePropNameTableMap[]; +extern const bool aAllowedTokenTypesTable[]; + + +/** + * Import index entry templates + */ +class XMLIndexTemplateContext : public SvXMLImportContext +{ + // pick up PropertyValues to be turned into a sequence. + ::std::vector< css::beans::PropertyValues > aValueVector; + + OUString sStyleName; + + const SvXMLEnumMapEntry* pOutlineLevelNameMap; + enum ::xmloff::token::XMLTokenEnum eOutlineLevelAttrName; + const char** pOutlineLevelStylePropMap; + const bool* pAllowedTokenTypesMap; + + sal_Int32 nOutlineLevel; + bool bStyleNameOK; + bool bOutlineLevelOK; + bool bTOC; + + // PropertySet of current index + css::uno::Reference & rPropertySet; + +public: + template + XMLIndexTemplateContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet, + const SvXMLEnumMapEntry* aLevelNameMap, + enum ::xmloff::token::XMLTokenEnum eLevelAttrName, + const char** aLevelStylePropNameMap, + const bool* aAllowedTokenTypes, + bool bTOC_=false) + : XMLIndexTemplateContext(rImport,rPropSet, + reinterpret_cast*>(aLevelNameMap), + eLevelAttrName, aLevelStylePropNameMap, aAllowedTokenTypes, bTOC_) {} + XMLIndexTemplateContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet, + const SvXMLEnumMapEntry* aLevelNameMap, + enum ::xmloff::token::XMLTokenEnum eLevelAttrName, + const char** aLevelStylePropNameMap, + const bool* aAllowedTokenTypes, + bool bTOC); + + virtual ~XMLIndexTemplateContext() override; + + /** add template; to be called by child template entry contexts */ + void addTemplateEntry( + const css::beans::PropertyValues& aValues); + +protected: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTitleTemplateContext.cxx b/xmloff/source/text/XMLIndexTitleTemplateContext.cxx new file mode 100644 index 000000000..e5c690f09 --- /dev/null +++ b/xmloff/source/text/XMLIndexTitleTemplateContext.cxx @@ -0,0 +1,97 @@ +/* -*- 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 "XMLIndexTitleTemplateContext.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_STYLE_NAME; + + +XMLIndexTitleTemplateContext::XMLIndexTitleTemplateContext( + SvXMLImport& rImport, + Reference & rPropSet) +: SvXMLImportContext(rImport) +, bStyleNameOK(false) +, rTOCPropertySet(rPropSet) +{ +} + + +XMLIndexTitleTemplateContext::~XMLIndexTitleTemplateContext() +{ +} + +void XMLIndexTitleTemplateContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // there's only one attribute: style-name + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + sStyleName = aIter.toString(); + OUString sDisplayStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, sStyleName ); + const Reference < css::container::XNameContainer >& + rStyles = GetImport().GetTextImport()->GetParaStyles(); + bStyleNameOK = rStyles.is() && rStyles->hasByName( sDisplayStyleName ); + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +void XMLIndexTitleTemplateContext::endFastElement(sal_Int32 ) +{ + Any aAny; + + aAny <<= sContent.makeStringAndClear(); + rTOCPropertySet->setPropertyValue("Title", aAny); + + if (bStyleNameOK) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_PARAGRAPH, + sStyleName ); + rTOCPropertySet->setPropertyValue("ParaStyleHeading", aAny); + } +} + +void XMLIndexTitleTemplateContext::characters( + const OUString& sString) +{ + sContent.append(sString); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexTitleTemplateContext.hxx b/xmloff/source/text/XMLIndexTitleTemplateContext.hxx new file mode 100644 index 000000000..2de195499 --- /dev/null +++ b/xmloff/source/text/XMLIndexTitleTemplateContext.hxx @@ -0,0 +1,71 @@ +/* -*- 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 +#include +#include +#include + + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import index title templates + */ +class XMLIndexTitleTemplateContext : public SvXMLImportContext +{ + // paragraph style + OUString sStyleName; + bool bStyleNameOK; + + // content + OUStringBuffer sContent; + + // TOC property set + css::uno::Reference & rTOCPropertySet; + +public: + + XMLIndexTitleTemplateContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet); + + virtual ~XMLIndexTitleTemplateContext() override; + +protected: + + /** process parameters */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** set values */ + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + /** pick up title characters */ + virtual void SAL_CALL characters(const OUString& sString) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexUserSourceContext.cxx b/xmloff/source/text/XMLIndexUserSourceContext.cxx new file mode 100644 index 000000000..392e8b72b --- /dev/null +++ b/xmloff/source/text/XMLIndexUserSourceContext.cxx @@ -0,0 +1,160 @@ +/* -*- 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 "XMLIndexUserSourceContext.hxx" +#include +#include +#include "XMLIndexTemplateContext.hxx" +#include +#include +#include +#include +#include + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using namespace ::xmloff::token; + +XMLIndexUserSourceContext::XMLIndexUserSourceContext( + SvXMLImport& rImport, + Reference & rPropSet) : + XMLIndexSourceBaseContext(rImport, + rPropSet, true), + bUseObjects(false), + bUseGraphic(false), + bUseMarks(false), + bUseTables(false), + bUseFrames(false), + bUseLevelFromSource(false), + bUseLevelParagraphStyles(false) +{ +} + +XMLIndexUserSourceContext::~XMLIndexUserSourceContext() +{ +} + +void XMLIndexUserSourceContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + bool bTmp(false); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_USE_INDEX_MARKS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseMarks = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_OBJECTS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseObjects = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_GRAPHICS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseGraphic = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_TABLES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseTables = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_FLOATING_FRAMES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseFrames = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COPY_OUTLINE_LEVELS): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseLevelFromSource = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_USE_INDEX_SOURCE_STYLES): + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bUseLevelParagraphStyles = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_INDEX_NAME): + sIndexName = aIter.toString(); + break; + + default: + XMLIndexSourceBaseContext::ProcessAttribute(aIter); + break; + } +} + +void XMLIndexUserSourceContext::endFastElement(sal_Int32 nElement) +{ + rIndexPropertySet->setPropertyValue("CreateFromEmbeddedObjects", css::uno::Any(bUseObjects)); + rIndexPropertySet->setPropertyValue("CreateFromGraphicObjects", css::uno::Any(bUseGraphic)); + rIndexPropertySet->setPropertyValue("UseLevelFromSource", css::uno::Any(bUseLevelFromSource)); + rIndexPropertySet->setPropertyValue("CreateFromMarks", css::uno::Any(bUseMarks)); + rIndexPropertySet->setPropertyValue("CreateFromTables", css::uno::Any(bUseTables)); + rIndexPropertySet->setPropertyValue("CreateFromTextFrames", css::uno::Any(bUseFrames)); + rIndexPropertySet->setPropertyValue("CreateFromLevelParagraphStyles", css::uno::Any(bUseLevelParagraphStyles)); + + if( !sIndexName.isEmpty() ) + { + rIndexPropertySet->setPropertyValue("UserIndexName", css::uno::Any(sIndexName)); + } + + XMLIndexSourceBaseContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLIndexUserSourceContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_USER_INDEX_ENTRY_TEMPLATE) ) + { + return new XMLIndexTemplateContext(GetImport(), rIndexPropertySet, + aSvLevelNameTOCMap, + XML_OUTLINE_LEVEL, + aLevelStylePropNameTOCMap, + aAllowedTokenTypesUser); + } + else + { + return XMLIndexSourceBaseContext::createFastChildContext(nElement, + xAttrList); + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLIndexUserSourceContext.hxx b/xmloff/source/text/XMLIndexUserSourceContext.hxx new file mode 100644 index 000000000..c275f8a05 --- /dev/null +++ b/xmloff/source/text/XMLIndexUserSourceContext.hxx @@ -0,0 +1,65 @@ +/* -*- 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 "XMLIndexSourceBaseContext.hxx" +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + + +/** + * Import user defined index source element + */ +class XMLIndexUserSourceContext : public XMLIndexSourceBaseContext +{ + bool bUseObjects; + bool bUseGraphic; + bool bUseMarks; + bool bUseTables; + bool bUseFrames; + bool bUseLevelFromSource; + bool bUseLevelParagraphStyles; + OUString sIndexName; + +public: + + XMLIndexUserSourceContext( + SvXMLImport& rImport, + css::uno::Reference & rPropSet); + + virtual ~XMLIndexUserSourceContext() override; + +protected: + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingExport.cxx b/xmloff/source/text/XMLLineNumberingExport.cxx new file mode 100644 index 000000000..613f2d033 --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingExport.cxx @@ -0,0 +1,185 @@ +/* -*- 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 "XMLLineNumberingExport.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::text::XLineNumberingProperties; + + +XMLLineNumberingExport::XMLLineNumberingExport(SvXMLExport& rExp) +: rExport(rExp) +{ +} + +SvXMLEnumMapEntry const aLineNumberPositionMap[] = +{ + { XML_LEFT, style::LineNumberPosition::LEFT }, + { XML_RIGHT, style::LineNumberPosition::RIGHT }, + { XML_INSIDE, style::LineNumberPosition::INSIDE }, + { XML_OUTSIDE, style::LineNumberPosition::OUTSIDE }, + { XML_TOKEN_INVALID, 0 } +}; + + +void XMLLineNumberingExport::Export() +{ + // export element if we have line numbering info + Reference xSupplier(rExport.GetModel(), + UNO_QUERY); + if (!xSupplier.is()) + return; + + Reference xLineNumbering = + xSupplier->getLineNumberingProperties(); + + if (!xLineNumbering.is()) + return; + + // char style + Any aAny = xLineNumbering->getPropertyValue("CharStyleName"); + OUString sTmp; + aAny >>= sTmp; + if (!sTmp.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, + rExport.EncodeStyleName( sTmp )); + } + + // enable + aAny = xLineNumbering->getPropertyValue("IsOn"); + if (! *o3tl::doAccess(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_NUMBER_LINES, XML_FALSE); + } + + // count empty lines + aAny = xLineNumbering->getPropertyValue("CountEmptyLines"); + if (! *o3tl::doAccess(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_COUNT_EMPTY_LINES, XML_FALSE); + } + + // count in frames + aAny = xLineNumbering->getPropertyValue("CountLinesInFrames"); + if (*o3tl::doAccess(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_COUNT_IN_TEXT_BOXES, XML_TRUE); + } + + // restart numbering + aAny = xLineNumbering->getPropertyValue("RestartAtEachPage"); + if (*o3tl::doAccess(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_RESTART_ON_PAGE, XML_TRUE); + } + + // Distance + aAny = xLineNumbering->getPropertyValue("Distance"); + sal_Int32 nLength = 0; + aAny >>= nLength; + if (nLength != 0) + { + OUStringBuffer sBuf; + rExport.GetMM100UnitConverter().convertMeasureToXML( + sBuf, nLength); + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_OFFSET, + sBuf.makeStringAndClear()); + } + + // NumberingType + OUStringBuffer sNumPosBuf; + aAny = xLineNumbering->getPropertyValue("NumberingType"); + sal_Int16 nFormat = 0; + aAny >>= nFormat; + rExport.GetMM100UnitConverter().convertNumFormat( sNumPosBuf, nFormat ); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sNumPosBuf.makeStringAndClear()); + SvXMLUnitConverter::convertNumLetterSync( sNumPosBuf, nFormat ); + if( !sNumPosBuf.isEmpty() ) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, + XML_NUM_LETTER_SYNC, + sNumPosBuf.makeStringAndClear() ); + } + + // number position + aAny = xLineNumbering->getPropertyValue("NumberPosition"); + sal_uInt16 nPosition = 0; + aAny >>= nPosition; + if (SvXMLUnitConverter::convertEnum(sNumPosBuf, nPosition, + aLineNumberPositionMap)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_NUMBER_POSITION, + sNumPosBuf.makeStringAndClear()); + } + + // sInterval + aAny = xLineNumbering->getPropertyValue("Interval"); + sal_Int16 nLineInterval = 0; + aAny >>= nLineInterval; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_INCREMENT, + OUString::number(nLineInterval)); + + SvXMLElementExport aConfigElem(rExport, XML_NAMESPACE_TEXT, + XML_LINENUMBERING_CONFIGURATION, + true, true); + + // line separator + aAny = xLineNumbering->getPropertyValue("SeparatorText"); + OUString sSeparator; + aAny >>= sSeparator; + if (sSeparator.isEmpty()) + return; + + // SeparatorInterval + aAny = xLineNumbering->getPropertyValue("SeparatorInterval"); + sal_Int16 nLineDistance = 0; + aAny >>= nLineDistance; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_INCREMENT, + OUString::number(nLineDistance)); + + SvXMLElementExport aSeparatorElem(rExport, XML_NAMESPACE_TEXT, + XML_LINENUMBERING_SEPARATOR, + true, false); + rExport.Characters(sSeparator); + // else: no configuration: don't save -> default + // can't even get supplier: don't save -> default +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingExport.hxx b/xmloff/source/text/XMLLineNumberingExport.hxx new file mode 100644 index 000000000..4beb2a2b4 --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingExport.hxx @@ -0,0 +1,35 @@ +/* -*- 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 + +class SvXMLExport; + +/** export and its child elements */ +class XMLLineNumberingExport +{ + SvXMLExport& rExport; + +public: + explicit XMLLineNumberingExport(SvXMLExport& rExp); + + void Export(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingImportContext.cxx b/xmloff/source/text/XMLLineNumberingImportContext.cxx new file mode 100644 index 000000000..ad0f16201 --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingImportContext.cxx @@ -0,0 +1,234 @@ +/* -*- 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 +#include "XMLLineNumberingSeparatorImportContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::text::XLineNumberingProperties; + + +constexpr OUStringLiteral gsCharStyleName(u"CharStyleName"); +constexpr OUStringLiteral gsCountEmptyLines(u"CountEmptyLines"); +constexpr OUStringLiteral gsCountLinesInFrames(u"CountLinesInFrames"); +constexpr OUStringLiteral gsDistance(u"Distance"); +constexpr OUStringLiteral gsInterval(u"Interval"); +constexpr OUStringLiteral gsSeparatorText(u"SeparatorText"); +constexpr OUStringLiteral gsNumberPosition(u"NumberPosition"); +constexpr OUStringLiteral gsNumberingType(u"NumberingType"); +constexpr OUStringLiteral gsIsOn(u"IsOn"); +constexpr OUStringLiteral gsRestartAtEachPage(u"RestartAtEachPage"); +constexpr OUStringLiteral gsSeparatorInterval(u"SeparatorInterval"); + +XMLLineNumberingImportContext::XMLLineNumberingImportContext( + SvXMLImport& rImport) +: SvXMLStyleContext(rImport, XmlStyleFamily::TEXT_LINENUMBERINGCONFIG) +, sNumFormat(GetXMLToken(XML_1)) +, sNumLetterSync(GetXMLToken(XML_FALSE)) +, nOffset(-1) +, nNumberPosition(style::LineNumberPosition::LEFT) +, nIncrement(-1) +, nSeparatorIncrement(-1) +, bNumberLines(true) +, bCountEmptyLines(true) +, bCountInFloatingFrames(false) +, bRestartNumbering(false) +{ +} + +XMLLineNumberingImportContext::~XMLLineNumberingImportContext() +{ +} + +void XMLLineNumberingImportContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + bool bTmp(false); + sal_Int32 nTmp; + + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + sStyleName = rValue; + break; + + case XML_ELEMENT(TEXT, XML_NUMBER_LINES): + if (::sax::Converter::convertBool(bTmp, rValue)) + { + bNumberLines = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COUNT_EMPTY_LINES): + if (::sax::Converter::convertBool(bTmp, rValue)) + { + bCountEmptyLines = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_COUNT_IN_TEXT_BOXES): + if (::sax::Converter::convertBool(bTmp, rValue)) + { + bCountInFloatingFrames = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_RESTART_ON_PAGE): + if (::sax::Converter::convertBool(bTmp, rValue)) + { + bRestartNumbering = bTmp; + } + break; + + case XML_ELEMENT(TEXT, XML_OFFSET): + if (GetImport().GetMM100UnitConverter(). + convertMeasureToCore(nTmp, rValue)) + { + nOffset = nTmp; + } + break; + + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumFormat = rValue; + break; + + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumLetterSync = rValue; + break; + + case XML_ELEMENT(TEXT, XML_NUMBER_POSITION): + { + static const SvXMLEnumMapEntry aLineNumberPositionMap[] = + { + { XML_LEFT, style::LineNumberPosition::LEFT }, + { XML_RIGHT, style::LineNumberPosition::RIGHT }, + { XML_INSIDE, style::LineNumberPosition::INSIDE }, + { XML_OUTSIDE, style::LineNumberPosition::OUTSIDE }, + { XML_TOKEN_INVALID, 0 } + }; + + (void)SvXMLUnitConverter::convertEnum(nNumberPosition, rValue, + aLineNumberPositionMap); + break; + } + + case XML_ELEMENT(TEXT, XML_INCREMENT): + if (::sax::Converter::convertNumber(nTmp, rValue, 0)) + { + nIncrement = static_cast(nTmp); + } + break; + } +} + +void XMLLineNumberingImportContext::CreateAndInsert(bool) +{ + // insert and block mode is handled in insertStyleFamily + + // we'll try to get the LineNumberingProperties + Reference xSupplier(GetImport().GetModel(), + UNO_QUERY); + if (!xSupplier.is()) + return; + + Reference xLineNumbering = + xSupplier->getLineNumberingProperties(); + + if (!xLineNumbering.is()) + return; + + Any aAny; + + // set style name (if it exists) + if ( GetImport().GetStyles()->FindStyleChildContext( + XmlStyleFamily::TEXT_TEXT, sStyleName ) != nullptr ) + { + aAny <<= GetImport().GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, sStyleName ); + xLineNumbering->setPropertyValue(gsCharStyleName, aAny); + } + + xLineNumbering->setPropertyValue(gsSeparatorText, Any(sSeparator)); + xLineNumbering->setPropertyValue(gsDistance, Any(nOffset)); + xLineNumbering->setPropertyValue(gsNumberPosition, Any(nNumberPosition)); + + if (nIncrement >= 0) + { + xLineNumbering->setPropertyValue(gsInterval, Any(nIncrement)); + } + + if (nSeparatorIncrement >= 0) + { + xLineNumbering->setPropertyValue(gsSeparatorInterval, Any(nSeparatorIncrement)); + } + + xLineNumbering->setPropertyValue(gsIsOn, Any(bNumberLines)); + xLineNumbering->setPropertyValue(gsCountEmptyLines, Any(bCountEmptyLines)); + xLineNumbering->setPropertyValue(gsCountLinesInFrames, Any(bCountInFloatingFrames)); + xLineNumbering->setPropertyValue(gsRestartAtEachPage, Any(bRestartNumbering)); + + sal_Int16 nNumType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumFormat, + sNumLetterSync ); + xLineNumbering->setPropertyValue(gsNumberingType, Any(nNumType)); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLLineNumberingImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_LINENUMBERING_SEPARATOR) ) + return new XMLLineNumberingSeparatorImportContext(GetImport(), *this); + return nullptr; +} + +void XMLLineNumberingImportContext::SetSeparatorText( + const OUString& sText) +{ + sSeparator = sText; +} + +void XMLLineNumberingImportContext::SetSeparatorIncrement( + sal_Int16 nIncr) +{ + nSeparatorIncrement = nIncr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingSeparatorImportContext.cxx b/xmloff/source/text/XMLLineNumberingSeparatorImportContext.cxx new file mode 100644 index 000000000..a27530727 --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingSeparatorImportContext.cxx @@ -0,0 +1,80 @@ +/* -*- 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 "XMLLineNumberingSeparatorImportContext.hxx" + +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; + +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_INCREMENT; + + +XMLLineNumberingSeparatorImportContext::XMLLineNumberingSeparatorImportContext( + SvXMLImport& rImport, + XMLLineNumberingImportContext& rLineNumbering) : + SvXMLImportContext(rImport), + rLineNumberingContext(rLineNumbering) +{ +} + +XMLLineNumberingSeparatorImportContext::~XMLLineNumberingSeparatorImportContext() +{ +} + +void XMLLineNumberingSeparatorImportContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_INCREMENT) ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView(), 0)) + { + rLineNumberingContext.SetSeparatorIncrement(static_cast(nTmp)); + } + // else: invalid number -> ignore + } + // else: unknown attribute -> ignore + } +} + +void XMLLineNumberingSeparatorImportContext::characters( + const OUString& rChars ) +{ + sSeparatorBuf.append(rChars); +} + +void XMLLineNumberingSeparatorImportContext::endFastElement(sal_Int32 ) +{ + rLineNumberingContext.SetSeparatorText(sSeparatorBuf.makeStringAndClear()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLLineNumberingSeparatorImportContext.hxx b/xmloff/source/text/XMLLineNumberingSeparatorImportContext.hxx new file mode 100644 index 000000000..110aae6dc --- /dev/null +++ b/xmloff/source/text/XMLLineNumberingSeparatorImportContext.hxx @@ -0,0 +1,59 @@ +/* -*- 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 +#include +#include +#include + + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } +} +class XMLLineNumberingImportContext; + + +/** import elements */ +class XMLLineNumberingSeparatorImportContext : public SvXMLImportContext +{ + OUStringBuffer sSeparatorBuf; + XMLLineNumberingImportContext& rLineNumberingContext; + +public: + + + XMLLineNumberingSeparatorImportContext( + SvXMLImport& rImport, + XMLLineNumberingImportContext& rLineNumbering); + + virtual ~XMLLineNumberingSeparatorImportContext() override; + +protected: + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLPropertyBackpatcher.cxx b/xmloff/source/text/XMLPropertyBackpatcher.cxx new file mode 100644 index 000000000..a2e4ac3a6 --- /dev/null +++ b/xmloff/source/text/XMLPropertyBackpatcher.cxx @@ -0,0 +1,207 @@ +/* -*- 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 +#include +#include + +#include +#include "XMLPropertyBackpatcher.hxx" +#include + +using ::std::map; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Any; +using ::com::sun::star::beans::XPropertySet; + + +template +XMLPropertyBackpatcher::XMLPropertyBackpatcher( + const OUString& sPropName) +: sPropertyName(sPropName) +{ +} + + +template +XMLPropertyBackpatcher::~XMLPropertyBackpatcher() +{ +} + + +template +void XMLPropertyBackpatcher::ResolveId( + const OUString& sName, + A aValue) +{ + // insert ID into ID map + aIDMap[sName] = aValue; + + // backpatch old references, if backpatch list exists + auto it = aBackpatchListMap.find(sName); + if (it == aBackpatchListMap.end()) + return; + + // aah, we have a backpatch list! + std::unique_ptr pList = std::move(it->second); + + // a) remove list from list map + aBackpatchListMap.erase(it); + + // b) for every item, set SequenceNumber + // (and preserve Property, if appropriate) + Any aAny; + aAny <<= aValue; + for(const auto& rBackpatch : *pList) + { + rBackpatch->setPropertyValue(sPropertyName, aAny); + } + // else: no backpatch list -> then we're finished +} + +template +void XMLPropertyBackpatcher::SetProperty( + const Reference & xPropSet, + const OUString& sName) +{ + if (aIDMap.count(sName)) + { + // we know this ID -> set property + xPropSet->setPropertyValue(sPropertyName, css::uno::Any(aIDMap[sName])); + } + else + { + // ID unknown -> into backpatch list for later fixup + if (! aBackpatchListMap.count(sName)) + { + // create backpatch list for this name + aBackpatchListMap.emplace(sName, new BackpatchListType); + } + + // insert footnote + aBackpatchListMap[sName]->push_back(xPropSet); + } +} + +// force instantiation of templates +template class XMLPropertyBackpatcher; +template class XMLPropertyBackpatcher; + +struct XMLTextImportHelper::BackpatcherImpl +{ + /// backpatcher for references to footnotes and endnotes + ::std::unique_ptr< XMLPropertyBackpatcher > + m_pFootnoteBackpatcher; + + /// backpatchers for references to sequences + ::std::unique_ptr< XMLPropertyBackpatcher > + m_pSequenceIdBackpatcher; + + ::std::unique_ptr< XMLPropertyBackpatcher< OUString> > + m_pSequenceNameBackpatcher; +}; + +std::shared_ptr +XMLTextImportHelper::MakeBackpatcherImpl() +{ + // n.b.: the shared_ptr stores the dtor! + return std::make_shared(); +} + +static OUString GetSequenceNumber() +{ + return "SequenceNumber"; +} + + +// XMLTextImportHelper + +// Code from XMLTextImportHelper using the XMLPropertyBackpatcher is +// implemented here. The reason is that in the unxsols2 environment, +// all templates are instantiated as file local (switch +// -instances=static), and thus are not accessible from the outside. + +// The previous solution was to force additional instantiation of +// XMLPropertyBackpatcher in txtimp.cxx. This solution combines all +// usage of the XMLPropertyBackpatcher in XMLPropertyBackpatcher.cxx +// instead. + + +XMLPropertyBackpatcher& XMLTextImportHelper::GetFootnoteBP() +{ + if (!m_xBackpatcherImpl->m_pFootnoteBackpatcher) + { + m_xBackpatcherImpl->m_pFootnoteBackpatcher.reset( + new XMLPropertyBackpatcher(GetSequenceNumber())); + } + return *m_xBackpatcherImpl->m_pFootnoteBackpatcher; +} + +XMLPropertyBackpatcher& XMLTextImportHelper::GetSequenceIdBP() +{ + if (!m_xBackpatcherImpl->m_pSequenceIdBackpatcher) + { + m_xBackpatcherImpl->m_pSequenceIdBackpatcher.reset( + new XMLPropertyBackpatcher(GetSequenceNumber())); + } + return *m_xBackpatcherImpl->m_pSequenceIdBackpatcher; +} + +XMLPropertyBackpatcher& XMLTextImportHelper::GetSequenceNameBP() +{ + if (!m_xBackpatcherImpl->m_pSequenceNameBackpatcher) + { + m_xBackpatcherImpl->m_pSequenceNameBackpatcher.reset( + new XMLPropertyBackpatcher("SourceName")); + } + return *m_xBackpatcherImpl->m_pSequenceNameBackpatcher; +} + +void XMLTextImportHelper::InsertFootnoteID( + const OUString& sXMLId, + sal_Int16 nAPIId) +{ + GetFootnoteBP().ResolveId(sXMLId, nAPIId); +} + +void XMLTextImportHelper::ProcessFootnoteReference( + const OUString& sXMLId, + const Reference & xPropSet) +{ + GetFootnoteBP().SetProperty(xPropSet, sXMLId); +} + +void XMLTextImportHelper::InsertSequenceID( + const OUString& sXMLId, + const OUString& sName, + sal_Int16 nAPIId) +{ + GetSequenceIdBP().ResolveId(sXMLId, nAPIId); + GetSequenceNameBP().ResolveId(sXMLId, sName); +} + +void XMLTextImportHelper::ProcessSequenceReference( + const OUString& sXMLId, + const Reference & xPropSet) +{ + GetSequenceIdBP().SetProperty(xPropSet, sXMLId); + GetSequenceNameBP().SetProperty(xPropSet, sXMLId); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLPropertyBackpatcher.hxx b/xmloff/source/text/XMLPropertyBackpatcher.hxx new file mode 100644 index 000000000..3a243f3bf --- /dev/null +++ b/xmloff/source/text/XMLPropertyBackpatcher.hxx @@ -0,0 +1,97 @@ +/* -*- 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 + +#include +#include +#include + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace uno { template class Reference; } +} + + +/** This class maintains an OUString->sal_Int16 mapping for cases in + * which an XPropertySet needs to be filled with values that are not + * yet known. + * + * A good example for appropriate use are footnotes and references to + * footnotes. Internally, the LibreOffice API numbers footnotes, and + * references to footnotes refer to that internal numbering. In the + * XML file format, these numbers are replaced with name strings. Now + * if during import of a document a reference to a footnote is + * encountered, two things can happen: 1) The footnote already + * appeared in the document. In this case the name is already known + * and the proper ID can be requested from the footnote. 2) The + * footnote will appear later in the document. In this case the ID is + * not yet known, and the reference-ID property of the reference + * cannot be determined. Hence, the reference has to be stored and the + * ID needs to bet set later, when the footnote is eventually found in + * the document. + * + * This class simplifies this process: If the footnote is found, + * ResolveId with the XML name and the ID is called. When a reference + * is encountered, SetProperty gets called with the reference's + * XPropertySet and the XML name. All remaining tasks are handled by + * the class. + */ +template +class XMLPropertyBackpatcher +{ + + /// name of property that gets set or backpatched + OUString sPropertyName; + + /// backpatch list type + typedef ::std::vector< + css::uno::Reference > BackpatchListType; + + /// backpatch list for unresolved IDs + ::std::map> aBackpatchListMap; + + /// mapping of names -> IDs + ::std::map aIDMap; + +public: + + explicit XMLPropertyBackpatcher( + const OUString& sPropertyName); + + ~XMLPropertyBackpatcher(); + + /// resolve a known ID. + /// Call this as soon as the value for a particular name is known. + void ResolveId( + const OUString& sName, + A aValue); + + /// Set property with the proper value for this name. If the value + /// is not yet known, store the XPropertySet in the backpatch list. + /// Use this whenever the value should be set, even if it is not yet known. + void SetProperty( + const css::uno::Reference & xPropSet, + const OUString& sName); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLRedlineExport.cxx b/xmloff/source/text/XMLRedlineExport.cxx new file mode 100644 index 000000000..eb8f8d68a --- /dev/null +++ b/xmloff/source/text/XMLRedlineExport.cxx @@ -0,0 +1,646 @@ +/* -*- 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 "XMLRedlineExport.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::UnknownPropertyException; +using ::com::sun::star::document::XRedlinesSupplier; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; +using ::com::sun::star::text::XText; +using ::com::sun::star::text::XTextContent; +using ::com::sun::star::text::XTextSection; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + + +XMLRedlineExport::XMLRedlineExport(SvXMLExport& rExp) +: sDeletion(GetXMLToken(XML_DELETION)) +, sFormatChange(GetXMLToken(XML_FORMAT_CHANGE)) +, sInsertion(GetXMLToken(XML_INSERTION)) +, rExport(rExp) +, pCurrentChangesList(nullptr) +{ +} + + +XMLRedlineExport::~XMLRedlineExport() +{ +} + + +void XMLRedlineExport::ExportChange( + const Reference & rPropSet, + bool bAutoStyle) +{ + if (bAutoStyle) + { + // For the headers/footers, we have to collect the autostyles + // here. For the general case, however, it's better to collect + // the autostyles by iterating over the global redline + // list. So that's what we do: Here, we collect autostyles + // only if we have no current list of changes. For the + // main-document case, the autostyles are collected in + // ExportChangesListAutoStyles(). + if (pCurrentChangesList != nullptr) + ExportChangeAutoStyle(rPropSet); + } + else + { + ExportChangeInline(rPropSet); + } +} + + +void XMLRedlineExport::ExportChangesList(bool bAutoStyles) +{ + if (bAutoStyles) + { + ExportChangesListAutoStyles(); + } + else + { + ExportChangesListElements(); + } +} + + +void XMLRedlineExport::ExportChangesList( + const Reference & rText, + bool bAutoStyles) +{ + // in the header/footer case, auto styles are collected from the + // inline change elements. + if (bAutoStyles) + return; + + // look for changes list for this XText + ChangesMapType::iterator aFind = aChangeMap.find(rText); + if (aFind == aChangeMap.end()) + return; + + ChangesVectorType* pChangesList = aFind->second.get(); + + // export only if changes are found + if (pChangesList->empty()) + return; + + // changes container element + SvXMLElementExport aChanges(rExport, XML_NAMESPACE_TEXT, + XML_TRACKED_CHANGES, + true, true); + + // iterate over changes list + for (auto const& change : *pChangesList) + { + ExportChangedRegion(change); + } + // else: changes list empty -> ignore + // else: no changes list found -> empty +} + +void XMLRedlineExport::SetCurrentXText( + const Reference & rText) +{ + if (rText.is()) + { + // look for appropriate list in map; use the found one, or create new + ChangesMapType::iterator aIter = aChangeMap.find(rText); + if (aIter == aChangeMap.end()) + { + ChangesVectorType* pList = new ChangesVectorType; + aChangeMap[rText].reset( pList ); + pCurrentChangesList = pList; + } + else + pCurrentChangesList = aIter->second.get(); + } + else + { + // don't record changes + SetCurrentXText(); + } +} + +void XMLRedlineExport::SetCurrentXText() +{ + pCurrentChangesList = nullptr; +} + + +void XMLRedlineExport::ExportChangesListElements() +{ + // get redlines (aka tracked changes) from the model + Reference xSupplier(rExport.GetModel(), uno::UNO_QUERY); + if (!xSupplier.is()) + return; + + Reference aEnumAccess = xSupplier->getRedlines(); + + // redline protection key + Reference aDocPropertySet( rExport.GetModel(), + uno::UNO_QUERY ); + // redlining enabled? + bool bEnabled = *o3tl::doAccess(aDocPropertySet->getPropertyValue( + "RecordChanges" )); + + // only export if we have redlines or attributes + if ( !(aEnumAccess->hasElements() || bEnabled) ) + return; + + + // export only if we have changes, but tracking is not enabled + if ( !bEnabled != !aEnumAccess->hasElements() ) + { + rExport.AddAttribute( + XML_NAMESPACE_TEXT, XML_TRACK_CHANGES, + bEnabled ? XML_TRUE : XML_FALSE ); + } + + // changes container element + SvXMLElementExport aChanges(rExport, XML_NAMESPACE_TEXT, + XML_TRACKED_CHANGES, + true, true); + + // get enumeration and iterate over elements + Reference aEnum = aEnumAccess->createEnumeration(); + while (aEnum->hasMoreElements()) + { + Any aAny = aEnum->nextElement(); + Reference xPropSet; + aAny >>= xPropSet; + + DBG_ASSERT(xPropSet.is(), + "can't get XPropertySet; skipping Redline"); + if (xPropSet.is()) + { + // export only if not in header or footer + // (those must be exported with their XText) + aAny = xPropSet->getPropertyValue("IsInHeaderFooter"); + if (! *o3tl::doAccess(aAny)) + { + // and finally, export change + ExportChangedRegion(xPropSet); + } + } + // else: no XPropertySet -> no export + } + // else: no redlines -> no export + // else: no XRedlineSupplier -> no export +} + +void XMLRedlineExport::ExportChangeAutoStyle( + const Reference & rPropSet) +{ + // record change (if changes should be recorded) + if (nullptr != pCurrentChangesList) + { + // put redline in list if it's collapsed or the redline start + Any aIsStart = rPropSet->getPropertyValue("IsStart"); + Any aIsCollapsed = rPropSet->getPropertyValue("IsCollapsed"); + + if ( *o3tl::doAccess(aIsStart) || + *o3tl::doAccess(aIsCollapsed) ) + pCurrentChangesList->push_back(rPropSet); + } + + // get XText for export of redline auto styles + Any aAny = rPropSet->getPropertyValue("RedlineText"); + Reference xText; + aAny >>= xText; + if (xText.is()) + { + // export the auto styles + rExport.GetTextParagraphExport()->collectTextAutoStyles(xText); + } +} + +void XMLRedlineExport::ExportChangesListAutoStyles() +{ + // get redlines (aka tracked changes) from the model + Reference xSupplier(rExport.GetModel(), uno::UNO_QUERY); + if (!xSupplier.is()) + return; + + Reference aEnumAccess = xSupplier->getRedlines(); + + // only export if we actually have redlines + if (!aEnumAccess->hasElements()) + return; + + // get enumeration and iterate over elements + Reference aEnum = aEnumAccess->createEnumeration(); + while (aEnum->hasMoreElements()) + { + Any aAny = aEnum->nextElement(); + Reference xPropSet; + aAny >>= xPropSet; + + DBG_ASSERT(xPropSet.is(), + "can't get XPropertySet; skipping Redline"); + if (xPropSet.is()) + { + + // export only if not in header or footer + // (those must be exported with their XText) + aAny = xPropSet->getPropertyValue("IsInHeaderFooter"); + if (! *o3tl::doAccess(aAny)) + { + ExportChangeAutoStyle(xPropSet); + } + } + } +} + +void XMLRedlineExport::ExportChangeInline( + const Reference & rPropSet) +{ + // determine element name (depending on collapsed, start/end) + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + Any aAny = rPropSet->getPropertyValue("IsCollapsed"); + bool bCollapsed = *o3tl::doAccess(aAny); + if (bCollapsed) + { + eElement = XML_CHANGE; + } + else + { + aAny = rPropSet->getPropertyValue("IsStart"); + const bool bStart = *o3tl::doAccess(aAny); + eElement = bStart ? XML_CHANGE_START : XML_CHANGE_END; + } + + if (XML_TOKEN_INVALID != eElement) + { + // we always need the ID + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID, + GetRedlineID(rPropSet)); + + // export the element (no whitespace because we're in the text body) + SvXMLElementExport aChangeElem(rExport, XML_NAMESPACE_TEXT, + eElement, false, false); + } +} + + +void XMLRedlineExport::ExportChangedRegion( + const Reference & rPropSet) +{ + // Redline-ID + rExport.AddAttributeIdLegacy(XML_NAMESPACE_TEXT, GetRedlineID(rPropSet)); + + // merge-last-paragraph + Any aAny = rPropSet->getPropertyValue("MergeLastPara"); + if( ! *o3tl::doAccess(aAny) ) + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_MERGE_LAST_PARAGRAPH, + XML_FALSE); + + // export change region element + SvXMLElementExport aChangedRegion(rExport, XML_NAMESPACE_TEXT, + XML_CHANGED_REGION, true, true); + + + // scope for (first) change element + { + aAny = rPropSet->getPropertyValue("RedlineType"); + OUString sType; + aAny >>= sType; + SvXMLElementExport aChange(rExport, XML_NAMESPACE_TEXT, + ConvertTypeName(sType), true, true); + + ExportChangeInfo(rPropSet); + + // get XText from the redline and export (if the XText exists) + aAny = rPropSet->getPropertyValue("RedlineText"); + Reference xText; + aAny >>= xText; + if (xText.is()) + { + rExport.GetTextParagraphExport()->exportText(xText); + // default parameters: bProgress, bExportParagraph ??? + } + // else: no text interface -> content is inline and will + // be exported there + } + + // changed change? Hierarchical changes can only be two levels + // deep. Here we check for the second level. + aAny = rPropSet->getPropertyValue("RedlineSuccessorData"); + Sequence aSuccessorData; + aAny >>= aSuccessorData; + + // if we actually got a hierarchical change, make element and + // process change info + if (aSuccessorData.hasElements()) + { + // The only change that can be "undone" is an insertion - + // after all, you can't re-insert a deletion, but you can + // delete an insertion. This assumption is asserted in + // ExportChangeInfo(Sequence&). + SvXMLElementExport aSecondChangeElem( + rExport, XML_NAMESPACE_TEXT, XML_INSERTION, + true, true); + + ExportChangeInfo(aSuccessorData); + } + // else: no hierarchical change +} + + +OUString const & XMLRedlineExport::ConvertTypeName( + std::u16string_view sApiName) +{ + if (sApiName == u"Delete") + { + return sDeletion; + } + else if (sApiName == u"Insert") + { + return sInsertion; + } + else if (sApiName == u"Format") + { + return sFormatChange; + } + else + { + OSL_FAIL("unknown redline type"); + static const OUString sUnknownChange("UnknownChange"); + return sUnknownChange; + } +} + + +/** Create a Redline-ID */ +OUString XMLRedlineExport::GetRedlineID( + const Reference & rPropSet) +{ + Any aAny = rPropSet->getPropertyValue("RedlineIdentifier"); + OUString sTmp; + aAny >>= sTmp; + + return "ct" + sTmp; +} + + +void XMLRedlineExport::ExportChangeInfo( + const Reference & rPropSet) +{ + bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ); + + SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE, + XML_CHANGE_INFO, true, true); + + Any aAny = rPropSet->getPropertyValue("RedlineAuthor"); + OUString sTmp; + aAny >>= sTmp; + if (!sTmp.isEmpty()) + { + SvXMLElementExport aCreatorElem( rExport, XML_NAMESPACE_DC, + XML_CREATOR, true, + false ); + rExport.Characters(bRemovePersonalInfo + ? "Author" + OUString::number(rExport.GetInfoID(sTmp)) + : sTmp ); + } + + aAny = rPropSet->getPropertyValue("RedlineDateTime"); + util::DateTime aDateTime; + aAny >>= aDateTime; + { + OUStringBuffer sBuf; + ::sax::Converter::convertDateTime(sBuf, bRemovePersonalInfo + ? util::DateTime(0, 0, 0, 0, 1, 1, 1970, true) // Epoch time + : aDateTime, nullptr); + SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC, + XML_DATE, true, + false ); + rExport.Characters(sBuf.makeStringAndClear()); + } + + // comment as sequence + aAny = rPropSet->getPropertyValue("RedlineComment"); + aAny >>= sTmp; + WriteComment( sTmp ); +} + +// write RedlineSuccessorData +void XMLRedlineExport::ExportChangeInfo( + const Sequence & rPropertyValues) +{ + OUString sComment; + bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ); + + SvXMLElementExport aChangeInfo(rExport, XML_NAMESPACE_OFFICE, + XML_CHANGE_INFO, true, true); + + for(const PropertyValue& rVal : rPropertyValues) + { + if( rVal.Name == "RedlineAuthor" ) + { + OUString sTmp; + rVal.Value >>= sTmp; + if (!sTmp.isEmpty()) + { + SvXMLElementExport aCreatorElem( rExport, XML_NAMESPACE_DC, + XML_CREATOR, true, + false ); + rExport.Characters(bRemovePersonalInfo + ? "Author" + OUString::number(rExport.GetInfoID(sTmp)) + : sTmp ); + } + } + else if( rVal.Name == "RedlineComment" ) + { + rVal.Value >>= sComment; + } + else if( rVal.Name == "RedlineDateTime" ) + { + util::DateTime aDateTime; + rVal.Value >>= aDateTime; + OUStringBuffer sBuf; + ::sax::Converter::convertDateTime(sBuf, bRemovePersonalInfo + ? util::DateTime(0, 0, 0, 0, 1, 1, 1970, true) // Epoch time + : aDateTime, nullptr); + SvXMLElementExport aDateElem( rExport, XML_NAMESPACE_DC, + XML_DATE, true, + false ); + rExport.Characters(sBuf.makeStringAndClear()); + } + else if( rVal.Name == "RedlineType" ) + { + // check if this is an insertion; cf. comment at calling location + OUString sTmp; + rVal.Value >>= sTmp; + DBG_ASSERT(sTmp == "Insert", + "hierarchical change must be insertion"); + } + // else: unknown value -> ignore + } + + // finally write comment paragraphs + WriteComment( sComment ); +} + +void XMLRedlineExport::ExportStartOrEndRedline( + const Reference & rPropSet, + bool bStart) +{ + if( ! rPropSet.is() ) + return; + + // get appropriate (start or end) property + Any aAny; + try + { + aAny = rPropSet->getPropertyValue(bStart ? OUString("StartRedline") : OUString("EndRedline")); + } + catch(const UnknownPropertyException&) + { + // If we don't have the property, there's nothing to do. + return; + } + + Sequence aValues; + aAny >>= aValues; + + // seek for redline properties + bool bIsCollapsed = false; + bool bIsStart = true; + OUString sId; + bool bIdOK = false; // have we seen an ID? + for(const auto& rValue : std::as_const(aValues)) + { + if (rValue.Name == "RedlineIdentifier") + { + rValue.Value >>= sId; + bIdOK = true; + } + else if (rValue.Name == "IsCollapsed") + { + bIsCollapsed = *o3tl::doAccess(rValue.Value); + } + else if (rValue.Name == "IsStart") + { + bIsStart = *o3tl::doAccess(rValue.Value); + } + } + + if( !bIdOK ) + return; + + SAL_WARN_IF( sId.isEmpty(), "xmloff", "Redlines must have IDs" ); + + // TODO: use GetRedlineID or eliminate that function + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_CHANGE_ID, + "ct" + sId); + + // export the element + // (whitespace because we're not inside paragraphs) + SvXMLElementExport aChangeElem( + rExport, XML_NAMESPACE_TEXT, + bIsCollapsed ? XML_CHANGE : + ( bIsStart ? XML_CHANGE_START : XML_CHANGE_END ), + true, true); +} + +void XMLRedlineExport::ExportStartOrEndRedline( + const Reference & rContent, + bool bStart) +{ + Reference xPropSet(rContent, uno::UNO_QUERY); + if (xPropSet.is()) + { + ExportStartOrEndRedline(xPropSet, bStart); + } + else + { + OSL_FAIL("XPropertySet expected"); + } +} + +void XMLRedlineExport::ExportStartOrEndRedline( + const Reference & rSection, + bool bStart) +{ + Reference xPropSet(rSection, uno::UNO_QUERY); + if (xPropSet.is()) + { + ExportStartOrEndRedline(xPropSet, bStart); + } + else + { + OSL_FAIL("XPropertySet expected"); + } +} + +void XMLRedlineExport::WriteComment(std::u16string_view rComment) +{ + if (rComment.empty()) + return; + + // iterate over all string-pieces separated by return (0x0a) and + // put each inside a paragraph element. + SvXMLTokenEnumerator aEnumerator(rComment, char(0x0a)); + std::u16string_view aSubString; + while (aEnumerator.getNextToken(aSubString)) + { + SvXMLElementExport aParagraph( + rExport, XML_NAMESPACE_TEXT, XML_P, true, false); + rExport.Characters(OUString(aSubString)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLRedlineExport.hxx b/xmloff/source/text/XMLRedlineExport.hxx new file mode 100644 index 000000000..5eee02a5d --- /dev/null +++ b/xmloff/source/text/XMLRedlineExport.hxx @@ -0,0 +1,163 @@ +/* -*- 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 +#include + +#include +#include +#include + +class SvXMLExport; +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace beans { struct PropertyValue; } + namespace text { class XText; } + namespace text { class XTextContent; } + namespace text { class XTextSection; } +} + +// store a list of redline properties +typedef ::std::vector< + css::uno::Reference > ChangesVectorType; + +// store a list of redline properties for each XText +typedef ::std::map< + css::uno::Reference< css::text::XText>, + std::unique_ptr > ChangesMapType; + + +/** + * This class handles the export of redline portions. + * It is to be called from XMLTextParagraphExport. + */ +class XMLRedlineExport +{ + const OUString sDeletion; + const OUString sFormatChange; + const OUString sInsertion; + + SvXMLExport& rExport; + + + // handling of change recording: + + // To support change tracking in headers and footers we need to + // write these changes separately. To do this, we record the + // changes for headers and footers. For the main document body, we + // get the complete list of changes from the document, which + // should be much more efficient than recording all of those. + + ChangesMapType aChangeMap; /// map of recorded changes + + /// list of current changes; is NULL or points to member of aChangeMap + ChangesVectorType* pCurrentChangesList; + + +public: + explicit XMLRedlineExport(SvXMLExport& rExp); + + ~XMLRedlineExport(); + + /// export a change + void ExportChange( + /// PropertySet of RedlinePortion + const css::uno::Reference & rPropSet, + bool bAutoStyle); + + /// export the list of changes (complete list minus recorded changed) + void ExportChangesList(bool bAutoStyles); + + /// export the list of changes (recorded changes for this XText only) + void ExportChangesList( + const css::uno::Reference & rText, + bool bAutoStyles); + + /// set the current XText for which changes should be recorded. + /// An empty XText means: don't record changes + void SetCurrentXText( + const css::uno::Reference & rText); + + /// Do not record changes. + /// Same as SetCurrentXText(Reference) with empty argument. + void SetCurrentXText(); + + /// export redline marks which start or end at start nodes, + /// i.e. that include the complete paragraph/table/section + void ExportStartOrEndRedline( + const css::uno::Reference< + css::beans::XPropertySet> & rPropSet, + bool bStart); /// start or end of text entity (e.g. paragraph)? + + /// convenience method, calls XPropertySet-version of this method + void ExportStartOrEndRedline( + /// XTextContent; must also be an XPropertySet + const css::uno::Reference & rContent, + bool bStart); + + /// convenience method, calls XPropertySet-version of this method + void ExportStartOrEndRedline( + /// XTextSection; must also be an XPropertySet + const css::uno::Reference & rSection, + bool bStart); + +private: + + /// export the change mark contained in the text body + void ExportChangeInline( + /// PropertySet of RedlinePortion + const css::uno::Reference & rPropSet); + + /// export the auto styles used in this change + void ExportChangeAutoStyle( + /// PropertySet of RedlinePortion + const css::uno::Reference & rPropSet); + + /// export the changes list () + void ExportChangesListElements(); + + /// export the auto styles needed by the changes list + void ExportChangesListAutoStyles(); + + /// export the changed-region element + void ExportChangedRegion( + const css::uno::Reference & rPropSet); + + /// export a change-info element (from a PropertySet) + void ExportChangeInfo( + const css::uno::Reference & rPropSet); + + /// export a change-info element (from PropertyValues) + void ExportChangeInfo( + const css::uno::Sequence & rValues); + + /// convert the change type from API to XML names + OUString const & ConvertTypeName(std::u16string_view sApiName); + + /// Get ID string! + static OUString GetRedlineID( + const css::uno::Reference & rPropSet); + + /// write a comment string as sequence of elements + void WriteComment(std::u16string_view rComment); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionExport.cxx b/xmloff/source/text/XMLSectionExport.cxx new file mode 100644 index 000000000..d97e30c0c --- /dev/null +++ b/xmloff/source/text/XMLSectionExport.cxx @@ -0,0 +1,1821 @@ +/* -*- 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 "XMLSectionExport.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::std; +using namespace ::xmloff::token; + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::PropertyValue; +using ::com::sun::star::beans::PropertyValues; +using ::com::sun::star::container::XIndexReplace; +using ::com::sun::star::container::XNameAccess; +using ::com::sun::star::container::XNamed; +using ::com::sun::star::lang::Locale; + + +XMLSectionExport::XMLSectionExport( + SvXMLExport& rExp, + XMLTextParagraphExport& rParaExp) +: rExport(rExp) +, rParaExport(rParaExp) +, bHeadingDummiesExported( false ) +{ +} + + +void XMLSectionExport::ExportSectionStart( + const Reference & rSection, + bool bAutoStyles) +{ + Reference xPropertySet(rSection, UNO_QUERY); + + // always export section (auto) style + if (bAutoStyles) + { + // get PropertySet and add section style + GetParaExport().Add( XmlStyleFamily::TEXT_SECTION, xPropertySet ); + } + else + { + // always export section style + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetParaExport().Find( + XmlStyleFamily::TEXT_SECTION, + xPropertySet, "" ) ); + + // xml:id for RDF metadata + GetExport().AddAttributeXmlId(rSection); + + // export index or regular section + Reference xIndex; + if (GetIndex(rSection, xIndex)) + { + if (xIndex.is()) + { + // we are an index + ExportIndexStart(xIndex); + } + else + { + // we are an index header + ExportIndexHeaderStart(rSection); + } + } + else + { + // we are not an index + ExportRegularSectionStart(rSection); + } + } +} + +bool XMLSectionExport::GetIndex( + const Reference & rSection, + Reference & rIndex) +{ + // first, reset result + bool bRet = false; + rIndex = nullptr; + + // get section Properties + Reference xSectionPropSet(rSection, UNO_QUERY); + + // then check if this section happens to be inside an index + if (xSectionPropSet->getPropertySetInfo()-> + hasPropertyByName("DocumentIndex")) + { + Any aAny = xSectionPropSet->getPropertyValue("DocumentIndex"); + Reference xDocumentIndex; + aAny >>= xDocumentIndex; + + // OK, are we inside of an index + if (xDocumentIndex.is()) + { + // is the enclosing index identical with "our" section? + Reference xIndexPropSet(xDocumentIndex, UNO_QUERY); + aAny = xIndexPropSet->getPropertyValue("ContentSection"); + Reference xEnclosingSection; + aAny >>= xEnclosingSection; + + // if the enclosing section is "our" section, then we are an index! + if (rSection == xEnclosingSection) + { + rIndex = xDocumentIndex; + bRet = true; + } + // else: index header or regular section + + // is the enclosing index identical with the header section? + aAny = xIndexPropSet->getPropertyValue("HeaderSection"); + // now mis-named: contains header section + aAny >>= xEnclosingSection; + + // if the enclosing section is "our" section, then we are an index! + if (rSection == xEnclosingSection) + { + bRet = true; + } + // else: regular section + } + // else: we aren't even inside of an index + } + // else: we don't even know what an index is. + + return bRet; +} + + +void XMLSectionExport::ExportSectionEnd( + const Reference & rSection, + bool bAutoStyles) +{ + // no end section for styles + if (bAutoStyles) + return; + + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + // export index or regular section end + Reference xIndex; + if (GetIndex(rSection, xIndex)) + { + if (xIndex.is()) + { + // index end: close index body element + GetExport().EndElement( XML_NAMESPACE_TEXT, XML_INDEX_BODY, + true ); + GetExport().IgnorableWhitespace(); + + switch (MapSectionType(xIndex->getServiceName())) + { + case TEXT_SECTION_TYPE_TOC: + eElement = XML_TABLE_OF_CONTENT; + break; + + case TEXT_SECTION_TYPE_ILLUSTRATION: + eElement = XML_ILLUSTRATION_INDEX; + break; + + case TEXT_SECTION_TYPE_ALPHABETICAL: + eElement = XML_ALPHABETICAL_INDEX; + break; + + case TEXT_SECTION_TYPE_TABLE: + eElement = XML_TABLE_INDEX; + break; + + case TEXT_SECTION_TYPE_OBJECT: + eElement = XML_OBJECT_INDEX; + break; + + case TEXT_SECTION_TYPE_USER: + eElement = XML_USER_INDEX; + break; + + case TEXT_SECTION_TYPE_BIBLIOGRAPHY: + eElement = XML_BIBLIOGRAPHY; + break; + + default: + OSL_FAIL("unknown index type"); + // default: skip index! + break; + } + } + else + { + eElement = XML_INDEX_TITLE; + } + } + else + { + eElement = XML_SECTION; + } + + if (XML_TOKEN_INVALID != eElement) + { + // any old attributes? + GetExport().CheckAttrList(); + + // element surrounded by whitespace + GetExport().EndElement( XML_NAMESPACE_TEXT, eElement, true); + GetExport().IgnorableWhitespace(); + } + else + { + OSL_FAIL("Need element name!"); + } + // else: autostyles -> ignore +} + +void XMLSectionExport::ExportIndexStart( + const Reference & rIndex) +{ + // get PropertySet + Reference xPropertySet(rIndex, UNO_QUERY); + + switch (MapSectionType(rIndex->getServiceName())) + { + case TEXT_SECTION_TYPE_TOC: + ExportTableOfContentStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_ILLUSTRATION: + ExportIllustrationIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_ALPHABETICAL: + ExportAlphabeticalIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_TABLE: + ExportTableIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_OBJECT: + ExportObjectIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_USER: + ExportUserIndexStart(xPropertySet); + break; + + case TEXT_SECTION_TYPE_BIBLIOGRAPHY: + ExportBibliographyStart(xPropertySet); + break; + + default: + // skip index + OSL_FAIL("unknown index type"); + break; + } +} + +void XMLSectionExport::ExportIndexHeaderStart( + const Reference & rSection) +{ + // export name, dammit! + Reference xName(rSection, UNO_QUERY); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xName->getName()); + + // format already handled -> export only start element + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_INDEX_TITLE, true ); + GetExport().IgnorableWhitespace(); +} + + +SvXMLEnumStringMapEntry const aIndexTypeMap[] = +{ + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.ContentIndex", TEXT_SECTION_TYPE_TOC ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.DocumentIndex", TEXT_SECTION_TYPE_ALPHABETICAL ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.TableIndex", TEXT_SECTION_TYPE_TABLE ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.ObjectIndex", TEXT_SECTION_TYPE_OBJECT ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.Bibliography", TEXT_SECTION_TYPE_BIBLIOGRAPHY ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.UserIndex", TEXT_SECTION_TYPE_USER ), + ENUM_STRING_MAP_ENTRY( "com.sun.star.text.IllustrationsIndex", TEXT_SECTION_TYPE_ILLUSTRATION ), + { nullptr, 0, SectionTypeEnum(0) } +}; + +enum SectionTypeEnum XMLSectionExport::MapSectionType( + std::u16string_view rServiceName) +{ + enum SectionTypeEnum eType = TEXT_SECTION_TYPE_UNKNOWN; + + SvXMLUnitConverter::convertEnum(eType, rServiceName, aIndexTypeMap); + + // TODO: index header section types, etc. + + return eType; +} + +void XMLSectionExport::ExportRegularSectionStart( + const Reference & rSection) +{ + // style name already handled in ExportSectionStart(...) + + Reference xName(rSection, UNO_QUERY); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xName->getName()); + + // get XPropertySet for other values + Reference xPropSet(rSection, UNO_QUERY); + + // condition and display + Any aAny = xPropSet->getPropertyValue("Condition"); + OUString sCond; + aAny >>= sCond; + enum XMLTokenEnum eDisplay = XML_TOKEN_INVALID; + if (!sCond.isEmpty()) + { + OUString sQValue = + GetExport().GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OOOW, + sCond, false ); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_CONDITION, sQValue); + eDisplay = XML_CONDITION; + + // #97450# store hidden-status (of conditional sections only) + aAny = xPropSet->getPropertyValue("IsCurrentlyVisible"); + if (! *o3tl::doAccess(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_IS_HIDDEN, + XML_TRUE); + } + } + else + { + eDisplay = XML_NONE; + } + aAny = xPropSet->getPropertyValue("IsVisible"); + if (! *o3tl::doAccess(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_DISPLAY, eDisplay); + } + + // protect + protection key + aAny = xPropSet->getPropertyValue("IsProtected"); + if (*o3tl::doAccess(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_PROTECTED, XML_TRUE); + } + Sequence aPassword; + xPropSet->getPropertyValue("ProtectionKey") >>= aPassword; + if (aPassword.hasElements()) + { + OUStringBuffer aBuffer; + ::comphelper::Base64::encode(aBuffer, aPassword); + // in ODF 1.0/1.1 the algorithm was left unspecified so we can write anything + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_PROTECTION_KEY, + aBuffer.makeStringAndClear()); + if (aPassword.getLength() == 32 && GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + // attribute exists in ODF 1.2 or later; default is SHA1 so no need to write that + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM, + // write the URL from ODF 1.2, not the W3C one + "http://www.w3.org/2000/09/xmldsig#sha256"); + } + } + + // export element + GetExport().IgnorableWhitespace(); + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_SECTION, true ); + + // data source + // unfortunately, we have to test all relevant strings for non-zero length + aAny = xPropSet->getPropertyValue("FileLink"); + SectionFileLink aFileLink; + aAny >>= aFileLink; + + aAny = xPropSet->getPropertyValue("LinkRegion"); + OUString sRegionName; + aAny >>= sRegionName; + + if ( !aFileLink.FileURL.isEmpty() || + !aFileLink.FilterName.isEmpty() || + !sRegionName.isEmpty()) + { + if (!aFileLink.FileURL.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, + GetExport().GetRelativeReference( aFileLink.FileURL) ); + } + + if (!aFileLink.FilterName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_FILTER_NAME, + aFileLink.FilterName); + } + + if (!sRegionName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_SECTION_NAME, + sRegionName); + } + + SvXMLElementExport aElem(GetExport(), + XML_NAMESPACE_TEXT, XML_SECTION_SOURCE, + true, true); + } + else + { + // check for DDE first + if (xPropSet->getPropertySetInfo()->hasPropertyByName("DDECommandFile")) + { + // data source DDE + // unfortunately, we have to test all relevant strings for + // non-zero length + aAny = xPropSet->getPropertyValue("DDECommandFile"); + OUString sApplication; + aAny >>= sApplication; + aAny = xPropSet->getPropertyValue("DDECommandType"); + OUString sTopic; + aAny >>= sTopic; + aAny = xPropSet->getPropertyValue("DDECommandElement"); + OUString sItem; + aAny >>= sItem; + + if ( !sApplication.isEmpty() || + !sTopic.isEmpty() || + !sItem.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, + XML_DDE_APPLICATION, sApplication); + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_DDE_TOPIC, + sTopic); + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_DDE_ITEM, + sItem); + + aAny = xPropSet->getPropertyValue("IsAutomaticUpdate"); + if (*o3tl::doAccess(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, + XML_AUTOMATIC_UPDATE, XML_TRUE); + } + + SvXMLElementExport aElem(GetExport(), + XML_NAMESPACE_OFFICE, + XML_DDE_SOURCE, true, true); + } + // else: no DDE data source + } + // else: no DDE on this system + } +} + +void XMLSectionExport::ExportTableOfContentStart( + const Reference & rPropertySet) +{ + // export TOC element start + ExportBaseIndexStart(XML_TABLE_OF_CONTENT, rPropertySet); + + // scope for table-of-content-source element + { + // TOC specific index source attributes: + + // outline-level: 1..10 + sal_Int16 nLevel = sal_Int16(); + if( rPropertySet->getPropertyValue("Level") >>= nLevel ) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_OUTLINE_LEVEL, + OUString::number(nLevel)); + } + + // use outline level + ExportBoolean(rPropertySet, "CreateFromOutline", + XML_USE_OUTLINE_LEVEL, true); + + // use index marks + ExportBoolean(rPropertySet, "CreateFromMarks", + XML_USE_INDEX_MARKS, true); + + // use level styles + ExportBoolean(rPropertySet, "CreateFromLevelParagraphStyles", + XML_USE_INDEX_SOURCE_STYLES, false); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_TOC, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_TOC, rPropertySet); +} + +void XMLSectionExport::ExportObjectIndexStart( + const Reference & rPropertySet) +{ + // export index start + ExportBaseIndexStart(XML_OBJECT_INDEX, rPropertySet); + + // scope for index source element + { + ExportBoolean(rPropertySet, "CreateFromOtherEmbeddedObjects", + XML_USE_OTHER_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromStarCalc", + XML_USE_SPREADSHEET_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromStarChart", + XML_USE_CHART_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromStarDraw", + XML_USE_DRAW_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromStarMath", + XML_USE_MATH_OBJECTS, false); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_OBJECT, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_OBJECT, rPropertySet); +} + +void XMLSectionExport::ExportIllustrationIndexStart( + const Reference & rPropertySet) +{ + // export index start + ExportBaseIndexStart(XML_ILLUSTRATION_INDEX, rPropertySet); + + // scope for index source element + { + // export common attributes for illustration and table indices + ExportTableAndIllustrationIndexSourceAttributes(rPropertySet); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_ILLUSTRATION, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_ILLUSTRATION, rPropertySet); +} + +void XMLSectionExport::ExportTableIndexStart( + const Reference & rPropertySet) +{ + // export index start + ExportBaseIndexStart(XML_TABLE_INDEX, rPropertySet); + + // scope for index source element + { + // export common attributes for illustration and table indices + ExportTableAndIllustrationIndexSourceAttributes(rPropertySet); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_TABLE, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_TABLE, rPropertySet); +} + +void XMLSectionExport::ExportAlphabeticalIndexStart( + const Reference & rPropertySet) +{ + // export TOC element start + ExportBaseIndexStart(XML_ALPHABETICAL_INDEX, rPropertySet); + + // scope for table-of-content-source element + { + + // style name (if present) + Any aAny = rPropertySet->getPropertyValue("MainEntryCharacterStyleName"); + OUString sStyleName; + aAny >>= sStyleName; + if (!sStyleName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_MAIN_ENTRY_STYLE_NAME, + GetExport().EncodeStyleName( sStyleName )); + } + + // other (boolean) attributes + ExportBoolean(rPropertySet, "IsCaseSensitive", XML_IGNORE_CASE, + false, true); + ExportBoolean(rPropertySet, "UseAlphabeticalSeparators", + XML_ALPHABETICAL_SEPARATORS, false); + ExportBoolean(rPropertySet, "UseCombinedEntries", XML_COMBINE_ENTRIES, + true); + ExportBoolean(rPropertySet, "UseDash", XML_COMBINE_ENTRIES_WITH_DASH, + false); + ExportBoolean(rPropertySet, "UseKeyAsEntry", XML_USE_KEYS_AS_ENTRIES, + false); + ExportBoolean(rPropertySet, "UsePP", XML_COMBINE_ENTRIES_WITH_PP, + true); + ExportBoolean(rPropertySet, "UseUpperCase", XML_CAPITALIZE_ENTRIES, + false); + ExportBoolean(rPropertySet, "IsCommaSeparated", XML_COMMA_SEPARATED, + false); + + // sort algorithm + aAny = rPropertySet->getPropertyValue("SortAlgorithm"); + OUString sAlgorithm; + aAny >>= sAlgorithm; + if (!sAlgorithm.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_SORT_ALGORITHM, + sAlgorithm ); + } + + // locale + aAny = rPropertySet->getPropertyValue("Locale"); + Locale aLocale; + aAny >>= aLocale; + GetExport().AddLanguageTagAttributes( XML_NAMESPACE_FO, XML_NAMESPACE_STYLE, aLocale, true); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_ALPHABETICAL, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_ALPHABETICAL, rPropertySet); +} + +void XMLSectionExport::ExportUserIndexStart( + const Reference & rPropertySet) +{ + // export TOC element start + ExportBaseIndexStart(XML_USER_INDEX, rPropertySet); + + // scope for table-of-content-source element + { + // bool attributes + ExportBoolean(rPropertySet, "CreateFromEmbeddedObjects", + XML_USE_OBJECTS, false); + ExportBoolean(rPropertySet, "CreateFromGraphicObjects", + XML_USE_GRAPHICS, false); + ExportBoolean(rPropertySet, "CreateFromMarks", + XML_USE_INDEX_MARKS, false); + ExportBoolean(rPropertySet, "CreateFromTables", + XML_USE_TABLES, false); + ExportBoolean(rPropertySet, "CreateFromTextFrames", + XML_USE_FLOATING_FRAMES, false); + ExportBoolean(rPropertySet, "UseLevelFromSource", + XML_COPY_OUTLINE_LEVELS, false); + ExportBoolean(rPropertySet, "CreateFromLevelParagraphStyles", + XML_USE_INDEX_SOURCE_STYLES, false); + + Any aAny = rPropertySet->getPropertyValue( "UserIndexName" ); + OUString sIndexName; + aAny >>= sIndexName; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_INDEX_NAME, + sIndexName); + + ExportBaseIndexSource(TEXT_SECTION_TYPE_USER, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_USER, rPropertySet); +} + +void XMLSectionExport::ExportBibliographyStart( + const Reference & rPropertySet) +{ + // export TOC element start + ExportBaseIndexStart(XML_BIBLIOGRAPHY, rPropertySet); + + // scope for table-of-content-source element + { + // No attributes. Fine. + + ExportBaseIndexSource(TEXT_SECTION_TYPE_BIBLIOGRAPHY, rPropertySet); + } + + ExportBaseIndexBody(TEXT_SECTION_TYPE_BIBLIOGRAPHY, rPropertySet); +} + + +void XMLSectionExport::ExportBaseIndexStart( + XMLTokenEnum eElement, + const Reference & rPropertySet) +{ + // protect + protection key + Any aAny = rPropertySet->getPropertyValue("IsProtected"); + if (*o3tl::doAccess(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_PROTECTED, XML_TRUE); + } + + // index name + OUString sIndexName; + rPropertySet->getPropertyValue("Name") >>= sIndexName; + if ( !sIndexName.isEmpty() ) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, sIndexName); + } + + // index Element start + GetExport().IgnorableWhitespace(); + GetExport().StartElement( XML_NAMESPACE_TEXT, eElement, false ); +} + +const XMLTokenEnum aTypeSourceElementNameMap[] = +{ + XML_TABLE_OF_CONTENT_SOURCE, // TOC + XML_TABLE_INDEX_SOURCE, // table index + XML_ILLUSTRATION_INDEX_SOURCE, // illustration index + XML_OBJECT_INDEX_SOURCE, // object index + XML_USER_INDEX_SOURCE, // user index + XML_ALPHABETICAL_INDEX_SOURCE, // alphabetical index + XML_BIBLIOGRAPHY_SOURCE // bibliography +}; + +void XMLSectionExport::ExportBaseIndexSource( + SectionTypeEnum eType, + const Reference & rPropertySet) +{ + // check type + OSL_ENSURE(eType >= TEXT_SECTION_TYPE_TOC, "illegal index type"); + OSL_ENSURE(eType <= TEXT_SECTION_TYPE_BIBLIOGRAPHY, "illegal index type"); + + Any aAny; + + // common attributes; not supported by bibliography + if (eType != TEXT_SECTION_TYPE_BIBLIOGRAPHY) + { + // document or chapter index? + aAny = rPropertySet->getPropertyValue("CreateFromChapter"); + if (*o3tl::doAccess(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_INDEX_SCOPE, XML_CHAPTER); + } + + // tab-stops relative to margin? + aAny = rPropertySet->getPropertyValue("IsRelativeTabstops"); + if (! *o3tl::doAccess(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_RELATIVE_TAB_STOP_POSITION, + XML_FALSE); + } + } + + // the index source element (all indices) + SvXMLElementExport aElem(GetExport(), + XML_NAMESPACE_TEXT, + GetXMLToken( + aTypeSourceElementNameMap[ + eType - TEXT_SECTION_TYPE_TOC]), + true, true); + + // scope for title template (all indices) + { + // header style name + aAny = rPropertySet->getPropertyValue("ParaStyleHeading"); + OUString sStyleName; + aAny >>= sStyleName; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyleName )); + + // title template + SvXMLElementExport aHeaderTemplate(GetExport(), + XML_NAMESPACE_TEXT, + XML_INDEX_TITLE_TEMPLATE, + true, false); + + // title as element content + aAny = rPropertySet->getPropertyValue("Title"); + OUString sTitleString; + aAny >>= sTitleString; + GetExport().Characters(sTitleString); + } + + // export level templates (all indices) + aAny = rPropertySet->getPropertyValue("LevelFormat"); + Reference xLevelTemplates; + aAny >>= xLevelTemplates; + + // iterate over level formats; + // skip element 0 (empty template for title) + sal_Int32 nLevelCount = xLevelTemplates->getCount(); + for(sal_Int32 i = 1; i aTemplateSequence; + aAny = xLevelTemplates->getByIndex(i); + aAny >>= aTemplateSequence; + + // export the sequence (abort export if an error occurred; #91214#) + bool bResult = + ExportIndexTemplate(eType, i, rPropertySet, aTemplateSequence); + if ( !bResult ) + break; + } + + // only TOC and user index: + // styles from which to build the index (LevelParagraphStyles) + if ( (TEXT_SECTION_TYPE_TOC == eType) || + (TEXT_SECTION_TYPE_USER == eType) ) + { + aAny = rPropertySet->getPropertyValue("LevelParagraphStyles"); + Reference xLevelParagraphStyles; + aAny >>= xLevelParagraphStyles; + ExportLevelParagraphStyles(xLevelParagraphStyles); + } +} + + +void XMLSectionExport::ExportBaseIndexBody( + SectionTypeEnum eType, + const Reference &) +{ + // type not used; checked anyway. + OSL_ENSURE(eType >= TEXT_SECTION_TYPE_TOC, "illegal index type"); + OSL_ENSURE(eType <= TEXT_SECTION_TYPE_BIBLIOGRAPHY, "illegal index type"); + + // export start only + + // any old attributes? + GetExport().CheckAttrList(); + + // start surrounded by whitespace + GetExport().IgnorableWhitespace(); + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_INDEX_BODY, true ); +} + +void XMLSectionExport::ExportTableAndIllustrationIndexSourceAttributes( + const Reference & rPropertySet) +{ + // use caption + Any aAny = rPropertySet->getPropertyValue("CreateFromLabels"); + if (! *o3tl::doAccess(aAny)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_USE_CAPTION, XML_FALSE); + } + + // sequence name + aAny = rPropertySet->getPropertyValue("LabelCategory"); + OUString sSequenceName; + aAny >>= sSequenceName; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_CAPTION_SEQUENCE_NAME, + sSequenceName); + + // caption format + aAny = rPropertySet->getPropertyValue("LabelDisplayType"); + sal_Int16 nType = 0; + aAny >>= nType; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_CAPTION_SEQUENCE_FORMAT, + XMLTextFieldExport::MapReferenceType(nType)); +} + + +// map index of LevelFormats to attribute value; +// level 0 is always the header +const XMLTokenEnum aLevelNameTOCMap[] = + { XML_TOKEN_INVALID, XML_1, XML_2, XML_3, XML_4, XML_5, XML_6, XML_7, + XML_8, XML_9, XML_10, XML_TOKEN_INVALID }; +const XMLTokenEnum aLevelNameTableMap[] = + { XML_TOKEN_INVALID, XML__EMPTY, XML_TOKEN_INVALID }; +const XMLTokenEnum aLevelNameAlphaMap[] = + { XML_TOKEN_INVALID, XML_SEPARATOR, XML_1, XML_2, XML_3, XML_TOKEN_INVALID }; +const XMLTokenEnum aLevelNameBibliographyMap[] = + { XML_TOKEN_INVALID, XML_ARTICLE, XML_BOOK, XML_BOOKLET, XML_CONFERENCE, + XML_CUSTOM1, XML_CUSTOM2, XML_CUSTOM3, XML_CUSTOM4, + XML_CUSTOM5, XML_EMAIL, XML_INBOOK, XML_INCOLLECTION, + XML_INPROCEEDINGS, XML_JOURNAL, + XML_MANUAL, XML_MASTERSTHESIS, XML_MISC, XML_PHDTHESIS, + XML_PROCEEDINGS, XML_TECHREPORT, XML_UNPUBLISHED, XML_WWW, + XML_TOKEN_INVALID }; + +static const XMLTokenEnum* aTypeLevelNameMap[] = +{ + aLevelNameTOCMap, // TOC + aLevelNameTableMap, // table index + aLevelNameTableMap, // illustration index + aLevelNameTableMap, // object index + aLevelNameTOCMap, // user index + aLevelNameAlphaMap, // alphabetical index + aLevelNameBibliographyMap // bibliography +}; + +static const char* aLevelStylePropNameTOCMap[] = + { nullptr, "ParaStyleLevel1", "ParaStyleLevel2", "ParaStyleLevel3", + "ParaStyleLevel4", "ParaStyleLevel5", "ParaStyleLevel6", + "ParaStyleLevel7", "ParaStyleLevel8", "ParaStyleLevel9", + "ParaStyleLevel10", nullptr }; +static const char* aLevelStylePropNameTableMap[] = + { nullptr, "ParaStyleLevel1", nullptr }; +static const char* aLevelStylePropNameAlphaMap[] = + { nullptr, "ParaStyleSeparator", "ParaStyleLevel1", "ParaStyleLevel2", + "ParaStyleLevel3", nullptr }; +static const char* aLevelStylePropNameBibliographyMap[] = + // TODO: replace with real property names, when available + { nullptr, "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", "ParaStyleLevel1", "ParaStyleLevel1", + "ParaStyleLevel1", + nullptr }; + +static const char** aTypeLevelStylePropNameMap[] = +{ + aLevelStylePropNameTOCMap, // TOC + aLevelStylePropNameTableMap, // table index + aLevelStylePropNameTableMap, // illustration index + aLevelStylePropNameTableMap, // object index + aLevelStylePropNameTOCMap, // user index + aLevelStylePropNameAlphaMap, // alphabetical index + aLevelStylePropNameBibliographyMap // bibliography +}; + +const XMLTokenEnum aTypeLevelAttrMap[] = +{ + XML_OUTLINE_LEVEL, // TOC + XML_TOKEN_INVALID, // table index + XML_TOKEN_INVALID, // illustration index + XML_TOKEN_INVALID, // object index + XML_OUTLINE_LEVEL, // user index + XML_OUTLINE_LEVEL, // alphabetical index + XML_BIBLIOGRAPHY_TYPE // bibliography +}; + +const XMLTokenEnum aTypeElementNameMap[] = +{ + XML_TABLE_OF_CONTENT_ENTRY_TEMPLATE, // TOC + XML_TABLE_INDEX_ENTRY_TEMPLATE, // table index + XML_ILLUSTRATION_INDEX_ENTRY_TEMPLATE, // illustration index + XML_OBJECT_INDEX_ENTRY_TEMPLATE, // object index + XML_USER_INDEX_ENTRY_TEMPLATE, // user index + XML_ALPHABETICAL_INDEX_ENTRY_TEMPLATE, // alphabetical index + XML_BIBLIOGRAPHY_ENTRY_TEMPLATE // bibliography +}; + + +bool XMLSectionExport::ExportIndexTemplate( + SectionTypeEnum eType, + sal_Int32 nOutlineLevel, + const Reference & rPropertySet, + const Sequence > & rValues) +{ + OSL_ENSURE(eType >= TEXT_SECTION_TYPE_TOC, "illegal index type"); + OSL_ENSURE(eType <= TEXT_SECTION_TYPE_BIBLIOGRAPHY, "illegal index type"); + OSL_ENSURE(nOutlineLevel >= 0, "illegal outline level"); + + if ( (eType >= TEXT_SECTION_TYPE_TOC) && + (eType <= TEXT_SECTION_TYPE_BIBLIOGRAPHY) && + (nOutlineLevel >= 0) ) + { + // get level name and level attribute name from aLevelNameMap; + const XMLTokenEnum eLevelAttrName( + aTypeLevelAttrMap[eType-TEXT_SECTION_TYPE_TOC]); + const XMLTokenEnum eLevelName( + aTypeLevelNameMap[eType-TEXT_SECTION_TYPE_TOC][nOutlineLevel]); + + // #92124#: some old documents may be broken, then they have + // too many template levels; we need to recognize this and + // export only as many as is legal for the respective index + // type. To do this, we simply return an error flag, which + // will then abort further template level exports. + OSL_ENSURE(XML_TOKEN_INVALID != eLevelName, "can't find level name"); + if ( XML_TOKEN_INVALID == eLevelName ) + { + // output level not found? Then end of templates! #91214# + return false; + } + + // output level name + if ((XML_TOKEN_INVALID != eLevelName) && (XML_TOKEN_INVALID != eLevelAttrName)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + GetXMLToken(eLevelAttrName), + GetXMLToken(eLevelName)); + } + + // paragraph level style name + const char* pPropName( + aTypeLevelStylePropNameMap[eType-TEXT_SECTION_TYPE_TOC][nOutlineLevel]); + OSL_ENSURE(nullptr != pPropName, "can't find property name"); + if (nullptr != pPropName) + { + Any aAny = rPropertySet->getPropertyValue( + OUString::createFromAscii(pPropName)); + OUString sParaStyleName; + aAny >>= sParaStyleName; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, + GetExport().EncodeStyleName( sParaStyleName )); + } + + // template element + const XMLTokenEnum eElementName( + aTypeElementNameMap[eType - TEXT_SECTION_TYPE_TOC]); + SvXMLElementExport aLevelTemplate(GetExport(), + XML_NAMESPACE_TEXT, + GetXMLToken(eElementName), + true, true); + + // export sequence + for(auto& rValue : rValues) + { + ExportIndexTemplateElement( + eType, //i90246 + rValue); + } + } + + return true; +} + +namespace { + +enum TemplateTypeEnum +{ + TOK_TTYPE_ENTRY_NUMBER, + TOK_TTYPE_ENTRY_TEXT, + TOK_TTYPE_TAB_STOP, + TOK_TTYPE_TEXT, + TOK_TTYPE_PAGE_NUMBER, + TOK_TTYPE_CHAPTER_INFO, + TOK_TTYPE_HYPERLINK_START, + TOK_TTYPE_HYPERLINK_END, + TOK_TTYPE_BIBLIOGRAPHY, + TOK_TTYPE_INVALID +}; + +enum TemplateParamEnum +{ + TOK_TPARAM_TOKEN_TYPE, + TOK_TPARAM_CHAR_STYLE, + TOK_TPARAM_TAB_RIGHT_ALIGNED, + TOK_TPARAM_TAB_POSITION, + TOK_TPARAM_TAB_WITH_TAB, // #i21237# + TOK_TPARAM_TAB_FILL_CHAR, + TOK_TPARAM_TEXT, + TOK_TPARAM_CHAPTER_FORMAT, + TOK_TPARAM_CHAPTER_LEVEL,//i53420 + TOK_TPARAM_BIBLIOGRAPHY_DATA +}; + +} + +SvXMLEnumStringMapEntry const aTemplateTypeMap[] = +{ + ENUM_STRING_MAP_ENTRY( "TokenEntryNumber", TOK_TTYPE_ENTRY_NUMBER ), + ENUM_STRING_MAP_ENTRY( "TokenEntryText", TOK_TTYPE_ENTRY_TEXT ), + ENUM_STRING_MAP_ENTRY( "TokenTabStop", TOK_TTYPE_TAB_STOP ), + ENUM_STRING_MAP_ENTRY( "TokenText", TOK_TTYPE_TEXT ), + ENUM_STRING_MAP_ENTRY( "TokenPageNumber", TOK_TTYPE_PAGE_NUMBER ), + ENUM_STRING_MAP_ENTRY( "TokenChapterInfo", TOK_TTYPE_CHAPTER_INFO ), + ENUM_STRING_MAP_ENTRY( "TokenHyperlinkStart", TOK_TTYPE_HYPERLINK_START ), + ENUM_STRING_MAP_ENTRY( "TokenHyperlinkEnd", TOK_TTYPE_HYPERLINK_END ), + ENUM_STRING_MAP_ENTRY( "TokenBibliographyDataField", TOK_TTYPE_BIBLIOGRAPHY ), + { nullptr, 0, TemplateTypeEnum(0)} +}; + +SvXMLEnumStringMapEntry const aTemplateParamMap[] = +{ + ENUM_STRING_MAP_ENTRY( "TokenType", TOK_TPARAM_TOKEN_TYPE ), + ENUM_STRING_MAP_ENTRY( "CharacterStyleName", TOK_TPARAM_CHAR_STYLE ), + ENUM_STRING_MAP_ENTRY( "TabStopRightAligned", TOK_TPARAM_TAB_RIGHT_ALIGNED ), + ENUM_STRING_MAP_ENTRY( "TabStopPosition", TOK_TPARAM_TAB_POSITION ), + ENUM_STRING_MAP_ENTRY( "TabStopFillCharacter", TOK_TPARAM_TAB_FILL_CHAR ), + // #i21237# + ENUM_STRING_MAP_ENTRY( "WithTab", TOK_TPARAM_TAB_WITH_TAB ), + ENUM_STRING_MAP_ENTRY( "Text", TOK_TPARAM_TEXT ), + ENUM_STRING_MAP_ENTRY( "ChapterFormat", TOK_TPARAM_CHAPTER_FORMAT ), + ENUM_STRING_MAP_ENTRY( "ChapterLevel", TOK_TPARAM_CHAPTER_LEVEL ),//i53420 + ENUM_STRING_MAP_ENTRY( "BibliographyDataField", TOK_TPARAM_BIBLIOGRAPHY_DATA ), + { nullptr, 0, TemplateParamEnum(0)} +}; + +SvXMLEnumMapEntry const aBibliographyDataFieldMap[] = +{ + { XML_ADDRESS, BibliographyDataField::ADDRESS }, + { XML_ANNOTE, BibliographyDataField::ANNOTE }, + { XML_AUTHOR, BibliographyDataField::AUTHOR }, + { XML_BIBLIOGRAPHY_TYPE, BibliographyDataField::BIBILIOGRAPHIC_TYPE }, + { XML_BOOKTITLE, BibliographyDataField::BOOKTITLE }, + { XML_CHAPTER, BibliographyDataField::CHAPTER }, + { XML_CUSTOM1, BibliographyDataField::CUSTOM1 }, + { XML_CUSTOM2, BibliographyDataField::CUSTOM2 }, + { XML_CUSTOM3, BibliographyDataField::CUSTOM3 }, + { XML_CUSTOM4, BibliographyDataField::CUSTOM4 }, + { XML_CUSTOM5, BibliographyDataField::CUSTOM5 }, + { XML_EDITION, BibliographyDataField::EDITION }, + { XML_EDITOR, BibliographyDataField::EDITOR }, + { XML_HOWPUBLISHED, BibliographyDataField::HOWPUBLISHED }, + { XML_IDENTIFIER, BibliographyDataField::IDENTIFIER }, + { XML_INSTITUTION, BibliographyDataField::INSTITUTION }, + { XML_ISBN, BibliographyDataField::ISBN }, + { XML_JOURNAL, BibliographyDataField::JOURNAL }, + { XML_MONTH, BibliographyDataField::MONTH }, + { XML_NOTE, BibliographyDataField::NOTE }, + { XML_NUMBER, BibliographyDataField::NUMBER }, + { XML_ORGANIZATIONS, BibliographyDataField::ORGANIZATIONS }, + { XML_PAGES, BibliographyDataField::PAGES }, + { XML_PUBLISHER, BibliographyDataField::PUBLISHER }, + { XML_REPORT_TYPE, BibliographyDataField::REPORT_TYPE }, + { XML_SCHOOL, BibliographyDataField::SCHOOL }, + { XML_SERIES, BibliographyDataField::SERIES }, + { XML_TITLE, BibliographyDataField::TITLE }, + { XML_URL, BibliographyDataField::URL }, + { XML_VOLUME, BibliographyDataField::VOLUME }, + { XML_YEAR, BibliographyDataField::YEAR }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLSectionExport::ExportIndexTemplateElement( + SectionTypeEnum eType, //i90246 + const Sequence & rValues) +{ + // variables for template values + + // char style + OUString sCharStyle; + bool bCharStyleOK = false; + + // text + OUString sText; + bool bTextOK = false; + + // tab position + bool bRightAligned = false; + + // tab position + sal_Int32 nTabPosition = 0; + bool bTabPositionOK = false; + + // fill character + OUString sFillChar; + bool bFillCharOK = false; + + // chapter format + sal_Int16 nChapterFormat = 0; + bool bChapterFormatOK = false; + + // outline max level + sal_Int16 nLevel = 0; + bool bLevelOK = false; + + // Bibliography Data + sal_Int16 nBibliographyData = 0; + bool bBibliographyDataOK = false; + + // With Tab Stop #i21237# + bool bWithTabStop = false; + bool bWithTabStopOK = false; + + //i90246, the ODF version being written to is: + const SvtSaveOptions::ODFSaneDefaultVersion aODFVersion = rExport.getSaneDefaultVersion(); + //the above version cannot be used for old OOo (OOo 1.0) formats! + + // token type + enum TemplateTypeEnum nTokenType = TOK_TTYPE_INVALID; + + for(const auto& rValue : rValues) + { + TemplateParamEnum nToken; + if ( SvXMLUnitConverter::convertEnum( nToken, rValue.Name, + aTemplateParamMap ) ) + { + // Only use direct and default values. + // Wrong. no property states, so ignore. + // if ( (beans::PropertyState_DIRECT_VALUE == rValues[i].State) || + // (beans::PropertyState_DEFAULT_VALUE == rValues[i].State) ) + + switch (nToken) + { + case TOK_TPARAM_TOKEN_TYPE: + { + OUString sVal; + rValue.Value >>= sVal; + SvXMLUnitConverter::convertEnum( nTokenType, sVal, aTemplateTypeMap); + break; + } + + case TOK_TPARAM_CHAR_STYLE: + // only valid, if not empty + rValue.Value >>= sCharStyle; + bCharStyleOK = !sCharStyle.isEmpty(); + break; + + case TOK_TPARAM_TEXT: + rValue.Value >>= sText; + bTextOK = true; + break; + + case TOK_TPARAM_TAB_RIGHT_ALIGNED: + bRightAligned = + *o3tl::doAccess(rValue.Value); + break; + + case TOK_TPARAM_TAB_POSITION: + rValue.Value >>= nTabPosition; + bTabPositionOK = true; + break; + + // #i21237# + case TOK_TPARAM_TAB_WITH_TAB: + bWithTabStop = *o3tl::doAccess(rValue.Value); + bWithTabStopOK = true; + break; + + case TOK_TPARAM_TAB_FILL_CHAR: + rValue.Value >>= sFillChar; + bFillCharOK = true; + break; + + case TOK_TPARAM_CHAPTER_FORMAT: + rValue.Value >>= nChapterFormat; + bChapterFormatOK = true; + break; +//---> i53420 + case TOK_TPARAM_CHAPTER_LEVEL: + rValue.Value >>= nLevel; + bLevelOK = true; + break; + case TOK_TPARAM_BIBLIOGRAPHY_DATA: + rValue.Value >>= nBibliographyData; + bBibliographyDataOK = true; + break; + } + } + } + + // convert type to token (and check validity) ... + XMLTokenEnum eElement(XML_TOKEN_INVALID); + sal_uInt16 nNamespace(XML_NAMESPACE_TEXT); + switch(nTokenType) + { + case TOK_TTYPE_ENTRY_TEXT: + eElement = XML_INDEX_ENTRY_TEXT; + break; + case TOK_TTYPE_TAB_STOP: + // test validity + if ( bRightAligned || bTabPositionOK || bFillCharOK ) + { + eElement = XML_INDEX_ENTRY_TAB_STOP; + } + break; + case TOK_TTYPE_TEXT: + // test validity + if (bTextOK) + { + eElement = XML_INDEX_ENTRY_SPAN; + } + break; + case TOK_TTYPE_PAGE_NUMBER: + eElement = XML_INDEX_ENTRY_PAGE_NUMBER; + break; + case TOK_TTYPE_CHAPTER_INFO: // keyword index + eElement = XML_INDEX_ENTRY_CHAPTER; + break; + case TOK_TTYPE_ENTRY_NUMBER: // table of content + eElement = XML_INDEX_ENTRY_CHAPTER; + break; + case TOK_TTYPE_HYPERLINK_START: + eElement = XML_INDEX_ENTRY_LINK_START; + break; + case TOK_TTYPE_HYPERLINK_END: + eElement = XML_INDEX_ENTRY_LINK_END; + break; + case TOK_TTYPE_BIBLIOGRAPHY: + if (bBibliographyDataOK) + { + eElement = XML_INDEX_ENTRY_BIBLIOGRAPHY; + } + break; + default: + ; // unknown/unimplemented template + break; + } + + if (eType != TEXT_SECTION_TYPE_TOC) + { + switch (nTokenType) + { + case TOK_TTYPE_HYPERLINK_START: + case TOK_TTYPE_HYPERLINK_END: + if (SvtSaveOptions::ODFSVER_012 < aODFVersion) + { + assert(eType == TEXT_SECTION_TYPE_ILLUSTRATION + || eType == TEXT_SECTION_TYPE_OBJECT + || eType == TEXT_SECTION_TYPE_TABLE + || eType == TEXT_SECTION_TYPE_USER); + // ODF 1.3 OFFICE-3941 + nNamespace = (SvtSaveOptions::ODFSVER_013 <= aODFVersion) + ? XML_NAMESPACE_TEXT + : XML_NAMESPACE_LO_EXT; + } + else + { + eElement = XML_TOKEN_INVALID; // not allowed in ODF <= 1.2 + } + break; + default: + break; + } + } + + //--->i90246 + //check the ODF version being exported + if (aODFVersion == SvtSaveOptions::ODFSVER_011 + || aODFVersion == SvtSaveOptions::ODFSVER_010) + { + bLevelOK = false; + if (TOK_TTYPE_CHAPTER_INFO == nTokenType) + { + //if we are emitting for ODF 1.1 or 1.0, this information can be used for alphabetical index only + //it's not permitted in other indexes + if (eType != TEXT_SECTION_TYPE_ALPHABETICAL) + { + eElement = XML_TOKEN_INVALID; //not permitted, invalidate the element + } + else //maps format for 1.1 & 1.0 + { + // a few word here: OOo up to 2.4 uses the field chapter info in Alphabetical index + // in a way different from the ODF 1.1/1.0 specification: + + // ODF1.1/1.0 OOo display in chapter info ODF1.2 + // (used in alphabetical index only + + // number chapter number without pre/postfix plain-number + // number-and-name chapter number without pre/postfix plus title plain-number-and-name + + // with issue i89791 the reading of ODF 1.1 and 1.0 was corrected + // this one corrects the writing back from ODF 1.2 to ODF 1.1/1.0 + // unfortunately if there is another application which interprets correctly ODF1.1/1.0, + // the resulting alphabetical index will be rendered wrong by OOo 2.4 version + + switch( nChapterFormat ) + { + case ChapterFormat::DIGIT: + nChapterFormat = ChapterFormat::NUMBER; + break; + case ChapterFormat::NO_PREFIX_SUFFIX: + nChapterFormat = ChapterFormat::NAME_NUMBER; + break; + } + } + } + else if (TOK_TTYPE_ENTRY_NUMBER == nTokenType) + { + //in case of ODF 1.1 or 1.0 the only allowed number format is "number" + //so, force it... + // The only expected 'foreign' nChapterFormat is + // ' ChapterFormat::DIGIT', forced to 'none, since the + // 'value allowed in ODF 1.1 and 1.0 is 'number' the default + // this can be obtained by simply disabling the chapter format + bChapterFormatOK = false; + } + } + + // ... and write Element + if (eElement == XML_TOKEN_INVALID) + return; + + // character style (for most templates) + if (bCharStyleOK) + { + switch (nTokenType) + { + case TOK_TTYPE_ENTRY_TEXT: + case TOK_TTYPE_TEXT: + case TOK_TTYPE_PAGE_NUMBER: + case TOK_TTYPE_ENTRY_NUMBER: + case TOK_TTYPE_HYPERLINK_START: + case TOK_TTYPE_HYPERLINK_END: + case TOK_TTYPE_BIBLIOGRAPHY: + case TOK_TTYPE_CHAPTER_INFO: + case TOK_TTYPE_TAB_STOP: + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, + GetExport().EncodeStyleName( sCharStyle) ); + break; + default: + ; // nothing: no character style + break; + } + } + + // tab properties + if (TOK_TTYPE_TAB_STOP == nTokenType) + { + // tab type + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_TYPE, + bRightAligned ? XML_RIGHT : XML_LEFT); + + if (bTabPositionOK && (! bRightAligned)) + { + // position for left tabs (convert to measure) + OUStringBuffer sBuf; + GetExport().GetMM100UnitConverter().convertMeasureToXML(sBuf, + nTabPosition); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_POSITION, + sBuf.makeStringAndClear()); + } + + // fill char ("leader char") + if (bFillCharOK && !sFillChar.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_LEADER_CHAR, sFillChar); + } + + // #i21237# + if (bWithTabStopOK && ! bWithTabStop) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, + XML_WITH_TAB, + XML_FALSE); + } + } + + // bibliography data + if (TOK_TTYPE_BIBLIOGRAPHY == nTokenType) + { + OSL_ENSURE(bBibliographyDataOK, "need bibl data"); + OUStringBuffer sBuf; + if (SvXMLUnitConverter::convertEnum( sBuf, nBibliographyData, + aBibliographyDataFieldMap ) ) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_BIBLIOGRAPHY_DATA_FIELD, + sBuf.makeStringAndClear()); + } + } + + // chapter info + if (TOK_TTYPE_CHAPTER_INFO == nTokenType) + { + OSL_ENSURE(bChapterFormatOK, "need chapter info"); + GetExport().AddAttribute( + XML_NAMESPACE_TEXT, XML_DISPLAY, + XMLTextFieldExport::MapChapterDisplayFormat(nChapterFormat)); +//---> i53420 + if (bLevelOK) + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_OUTLINE_LEVEL, + OUString::number(nLevel)); + } + +//--->i53420 + if (TOK_TTYPE_ENTRY_NUMBER == nTokenType) + { + if (bChapterFormatOK) + GetExport().AddAttribute( + XML_NAMESPACE_TEXT, XML_DISPLAY, + XMLTextFieldExport::MapChapterDisplayFormat(nChapterFormat)); + + if (bLevelOK) + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_OUTLINE_LEVEL, + OUString::number(nLevel)); + } + // export template + SvXMLElementExport aTemplateElement(GetExport(), nNamespace, + GetXMLToken(eElement), + true, false) + ; + + // entry text or span element: write text + if (TOK_TTYPE_TEXT == nTokenType) + { + GetExport().Characters(sText); + } +} + +void XMLSectionExport::ExportLevelParagraphStyles( + Reference const & xLevelParagraphStyles) +{ + // iterate over levels + sal_Int32 nPLevelCount = xLevelParagraphStyles->getCount(); + for(sal_Int32 nLevel = 0; nLevel < nPLevelCount; nLevel++) + { + Any aAny = xLevelParagraphStyles->getByIndex(nLevel); + Sequence aStyleNames; + aAny >>= aStyleNames; + + // export only if at least one style is contained + if (aStyleNames.hasElements()) + { + // level attribute; we count 1..10; API 0..9 + sal_Int32 nLevelPlusOne = nLevel + 1; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_OUTLINE_LEVEL, + OUString::number(nLevelPlusOne)); + + // source styles element + SvXMLElementExport aParaStyles(GetExport(), + XML_NAMESPACE_TEXT, + XML_INDEX_SOURCE_STYLES, + true, true); + + // iterate over styles in this level + for(const auto& rStyleName : std::as_const(aStyleNames)) + { + // stylename attribute + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, + GetExport().EncodeStyleName(rStyleName) ); + + // element + SvXMLElementExport aParaStyle(GetExport(), + XML_NAMESPACE_TEXT, + XML_INDEX_SOURCE_STYLE, + true, false); + } + } + } +} + +void XMLSectionExport::ExportBoolean( + const Reference & rPropSet, + const OUString& sPropertyName, + enum XMLTokenEnum eAttributeName, + bool bDefault, + bool bInvert) +{ + OSL_ENSURE(eAttributeName != XML_TOKEN_INVALID, "Need attribute name"); + + Any aAny = rPropSet->getPropertyValue(sPropertyName); + bool bTmp = *o3tl::doAccess(aAny); + + // value = value ^ bInvert + // omit if value == default + if ( (bTmp != bInvert) != bDefault ) + { + // export non-default value (since default is omitted) + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + eAttributeName, + bDefault ? XML_FALSE : XML_TRUE); + } +} + +void XMLSectionExport::ExportBibliographyConfiguration(SvXMLExport& rExport) +{ + // first: get field master (via text field supplier) + Reference xTextFieldsSupp( rExport.GetModel(), + UNO_QUERY ); + if ( !xTextFieldsSupp.is() ) + return; + + static const OUStringLiteral sFieldMaster_Bibliography(u"com.sun.star.text.FieldMaster.Bibliography"); + + // get bibliography field master + Reference xMasters = + xTextFieldsSupp->getTextFieldMasters(); + if ( !xMasters->hasByName(sFieldMaster_Bibliography) ) + return; + + Any aAny = + xMasters->getByName(sFieldMaster_Bibliography); + Reference xPropSet; + aAny >>= xPropSet; + + OSL_ENSURE( xPropSet.is(), "field master must have XPropSet" ); + + OUString sTmp; + + aAny = xPropSet->getPropertyValue("BracketBefore"); + aAny >>= sTmp; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_PREFIX, sTmp); + + aAny = xPropSet->getPropertyValue("BracketAfter"); + aAny >>= sTmp; + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_SUFFIX, sTmp); + + aAny = xPropSet->getPropertyValue("IsNumberEntries"); + if (*o3tl::doAccess(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_NUMBERED_ENTRIES, XML_TRUE); + } + + aAny = xPropSet->getPropertyValue("IsSortByPosition"); + if (! *o3tl::doAccess(aAny)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_SORT_BY_POSITION, XML_FALSE); + } + + // sort algorithm + aAny = xPropSet->getPropertyValue("SortAlgorithm"); + OUString sAlgorithm; + aAny >>= sAlgorithm; + if( !sAlgorithm.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_TEXT, + XML_SORT_ALGORITHM, sAlgorithm ); + } + + // locale + aAny = xPropSet->getPropertyValue("Locale"); + Locale aLocale; + aAny >>= aLocale; + rExport.AddLanguageTagAttributes( XML_NAMESPACE_FO, XML_NAMESPACE_STYLE, aLocale, true); + + // configuration element + SvXMLElementExport aElement(rExport, XML_NAMESPACE_TEXT, + XML_BIBLIOGRAPHY_CONFIGURATION, + true, true); + + // sort keys + aAny = xPropSet->getPropertyValue("SortKeys"); + Sequence > aKeys; + aAny >>= aKeys; + for(const Sequence & rKey : std::as_const(aKeys)) + { + for(const PropertyValue& rValue : rKey) + { + if (rValue.Name == "SortKey") + { + sal_Int16 nKey = 0; + rValue.Value >>= nKey; + OUStringBuffer sBuf; + if (SvXMLUnitConverter::convertEnum( sBuf, nKey, + aBibliographyDataFieldMap ) ) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_KEY, + sBuf.makeStringAndClear()); + } + } + else if (rValue.Name == "IsSortAscending") + { + bool bTmp = *o3tl::doAccess(rValue.Value); + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_SORT_ASCENDING, + bTmp ? XML_TRUE : XML_FALSE); + } + } + + SvXMLElementExport aKeyElem(rExport, + XML_NAMESPACE_TEXT, XML_SORT_KEY, + true, true); + } +} + + +bool XMLSectionExport::IsMuteSection( + const Reference & rSection) const +{ + bool bRet = false; + + // a section is mute if + // 1) it exists + // 2) the SaveLinkedSections flag (at the export) is false + // 3) the IsGlobalDocumentSection property is true + // 4) it is not an Index + + if ( (!rExport.IsSaveLinkedSections()) && rSection.is() ) + { + // walk the section chain and set bRet if any is linked + for(Reference aSection(rSection); + aSection.is(); + aSection = aSection->getParentSection()) + { + // check if it is a global document section (linked or index) + Reference xPropSet(aSection, UNO_QUERY); + if (xPropSet.is()) + { + Any aAny = xPropSet->getPropertyValue("IsGlobalDocumentSection"); + + if ( *o3tl::doAccess(aAny) ) + { + Reference xIndex; + if (! GetIndex(rSection, xIndex)) + { + bRet = true; + + // early out if result is known + break; + } + } + } + // section has no properties: ignore + } + } + // else: no section, or always save sections: default (false) + + return bRet; +} + +bool XMLSectionExport::IsMuteSection( + const Reference & rSection, + bool bDefault) const +{ + // default: like default argument + bool bRet = bDefault; + + Reference xPropSet(rSection->getAnchor(), UNO_QUERY); + if (xPropSet.is()) + { + if (xPropSet->getPropertySetInfo()->hasPropertyByName("TextSection")) + { + Any aAny = xPropSet->getPropertyValue("TextSection"); + Reference xSection; + aAny >>= xSection; + + bRet = IsMuteSection(xSection); + } + // else: return default + } + // else: return default + + return bRet; +} + +bool XMLSectionExport::IsInSection( + const Reference & rEnclosingSection, + const Reference & rContent, + bool bDefault) +{ + // default: like default argument + bool bRet = bDefault; + OSL_ENSURE(rEnclosingSection.is(), "enclosing section expected"); + + Reference xPropSet(rContent, UNO_QUERY); + if (xPropSet.is()) + { + if (xPropSet->getPropertySetInfo()->hasPropertyByName("TextSection")) + { + Any aAny = xPropSet->getPropertyValue("TextSection"); + Reference xSection; + aAny >>= xSection; + + // now walk chain of text sections (if we have one) + if (xSection.is()) + { + do + { + bRet = (rEnclosingSection == xSection); + xSection = xSection->getParentSection(); + } + while (!bRet && xSection.is()); + } + else + bRet = false; // no section -> can't be inside + } + // else: no TextSection property -> return default + } + // else: no XPropertySet -> return default + + return bRet; +} + + +void XMLSectionExport::ExportMasterDocHeadingDummies() +{ + if( bHeadingDummiesExported ) + return; + + Reference< XChapterNumberingSupplier > xCNSupplier( rExport.GetModel(), + UNO_QUERY ); + + Reference< XIndexReplace > xChapterNumbering; + if( xCNSupplier.is() ) + xChapterNumbering = xCNSupplier->getChapterNumberingRules(); + + if( !xChapterNumbering.is() ) + return; + + sal_Int32 nCount = xChapterNumbering->getCount(); + for( sal_Int32 nLevel = 0; nLevel < nCount; nLevel++ ) + { + OUString sStyle; + Sequence aProperties; + xChapterNumbering->getByIndex( nLevel ) >>= aProperties; + auto pProp = std::find_if(std::cbegin(aProperties), std::cend(aProperties), + [](const PropertyValue& rProp) { return rProp.Name == "HeadingStyleName"; }); + if (pProp != std::cend(aProperties)) + pProp->Value >>= sStyle; + + if( !sStyle.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyle ) ); + + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_LEVEL, + OUString::number( nLevel + 1 ) ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, XML_H, + true, false ); + } + } + + bHeadingDummiesExported = true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionExport.hxx b/xmloff/source/text/XMLSectionExport.hxx new file mode 100644 index 000000000..05180e2f2 --- /dev/null +++ b/xmloff/source/text/XMLSectionExport.hxx @@ -0,0 +1,262 @@ +/* -*- 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 +#include +#include +#include +#include + +class SvXMLExport; +class XMLTextParagraphExport; +namespace com::sun::star { + namespace text + { + class XTextSection; + class XDocumentIndex; + class XTextContent; + } + namespace beans + { + class XPropertySet; + } + namespace container + { + class XIndexReplace; + } +} + + +enum SectionTypeEnum +{ + TEXT_SECTION_TYPE_TOC, + TEXT_SECTION_TYPE_TABLE, + TEXT_SECTION_TYPE_ILLUSTRATION, + TEXT_SECTION_TYPE_OBJECT, + TEXT_SECTION_TYPE_USER, + TEXT_SECTION_TYPE_ALPHABETICAL, + TEXT_SECTION_TYPE_BIBLIOGRAPHY, + TEXT_SECTION_TYPE_UNKNOWN +}; + + +/** + * This class handles the export of sections and indices (which are, + * internally, just sections). It is intended to be used only from + * within the XMLTextParagraphExport class. + */ +class XMLSectionExport +{ + SvXMLExport& rExport; + XMLTextParagraphExport& rParaExport; + + bool bHeadingDummiesExported; + +public: + XMLSectionExport(SvXMLExport& rExp, + XMLTextParagraphExport& rParaExp); + + /** + * export section or index start and source elements. This + * method handles the section styles, and delegates to the + * appropriate section or index method. + */ + void ExportSectionStart( + const css::uno::Reference < css::text::XTextSection > & rSection, + bool bAutoStyles); + + /** + * export section or index end elements + */ + void ExportSectionEnd( + const css::uno::Reference < css::text::XTextSection > & rSection, + bool bAutoStyles); + + /** + * Should the content of this section be exported? + * (E.g. linked sections in global documents are not always exported) + */ + bool IsMuteSection( + const css::uno::Reference < css::text::XTextSection > & rSection) const; + + /** + * XTextContent-version of IsMuteSection(Reference&) + * returns *true* for all non-section elements + */ + bool IsMuteSection( + const css::uno::Reference < css::text::XTextContent > & rSection, + /// return value if this content doesn't support the section property + bool bDefault) const; + + /** + * Determine whether rContent is contained in rEnclosingSection. If the + * current section of rContent can not be determined, return bDefault. + */ + static bool IsInSection( + const css::uno::Reference < css::text::XTextSection > & rEnclosingSection, + const css::uno::Reference < css::text::XTextContent > & rContent, + /// return value if this content doesn't support the section property + bool bDefault); + + /** + * Export the configuration element for bibliography indices. + * + * (This is part of XMLSectionExport because all section- and + * index-related items are handled here.) + */ + static void ExportBibliographyConfiguration(SvXMLExport& rExport); + + /** export a heading for every level. This is used by master documents + * to not lose the heading information if master documents are exported + * without section contents + */ + void ExportMasterDocHeadingDummies(); + + +private: + + SvXMLExport& GetExport() { return rExport; } + XMLTextParagraphExport& GetParaExport() { return rParaExport; } + + // export methods for section and index start: + + /// export an index start element. + void ExportIndexStart( + const css::uno::Reference < css::text::XDocumentIndex > & rSection); + + /// export an index header start element. + void ExportIndexHeaderStart( + const css::uno::Reference < css::text::XTextSection > & rSection); + + /// export a proper section (and source elements) + void ExportRegularSectionStart( + const css::uno::Reference < css::text::XTextSection > & rSection); + + /// export a table of content (and source element) + void ExportTableOfContentStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export a table index (and source element) + void ExportTableIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export an object index (and source element) + void ExportObjectIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export an illustration index (and source element) + void ExportIllustrationIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export an alphabetical/keyword index (and source element) + void ExportAlphabeticalIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export a user index (and source element) + void ExportUserIndexStart( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export the bibliography (and source element) + void ExportBibliographyStart( + const css::uno::Reference < css::beans::XPropertySet > & rIndex); + + // helper methods: + + /** + * If this section is an index, the index is written in the + * rIndex parameter. The return value is sal_True for all "special" + * sections. + * + * Thus we have: + * return sal_False: regular section + * return sal_True, xIndex is empty: index header section + * return sal_True, xIndex is set: index section */ + static bool GetIndex( + const css::uno::Reference < css::text::XTextSection > & rSection, + css::uno::Reference < css::text::XDocumentIndex > & rIndex); + + /// map service name to section type + static enum SectionTypeEnum MapSectionType(std::u16string_view rSectionName); + + /** + * Export the index element start (for all index types). + * + * All additional attributes (usually none) for the index element + * should have been set at GetExport() before calling this method. + */ + void ExportBaseIndexStart( + ::xmloff::token::XMLTokenEnum eElement, + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /** + * Export the index source element (common for all index types). + * + * All additional attributes for the source element should have + * been set at the GetExport() before calling this method. + */ + void ExportBaseIndexSource( + SectionTypeEnum eType, /// index type + const css::uno::Reference < + css::beans::XPropertySet > & rSection); + + /** + * Export the index body (common for all index types). + */ + void ExportBaseIndexBody( + SectionTypeEnum eType, /// index type + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + + /** + * Helper method to export common attributes for table and + * illustration indices + */ + void ExportTableAndIllustrationIndexSourceAttributes( + const css::uno::Reference < css::beans::XPropertySet > & rSection); + + /// export one template for the specific index type + bool ExportIndexTemplate( + SectionTypeEnum eType, /// index type + sal_Int32 nLevel, /// outline level (if applicable) + const css::uno::Reference< css::beans::XPropertySet> & rPropSet, + const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue> > & rValues); + + /// export a single template element (e.g. span or tab-stop) + void ExportIndexTemplateElement( + SectionTypeEnum eType, //i90246, needed for ODF 1.0, 1.0 and 1.2 management + const css::uno::Sequence< + css::beans::PropertyValue> & rValues); + + /// export level paragraph styles + void ExportLevelParagraphStyles( + css::uno::Reference< css::container::XIndexReplace> const & xStyles); + + + /// helper to export boolean properties + void ExportBoolean( + const css::uno::Reference & rPropSet, + const OUString& sPropertyName, + enum ::xmloff::token::XMLTokenEnum eAttributeName, + bool bDefault, + bool bInvert = false); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionFootnoteConfigExport.cxx b/xmloff/source/text/XMLSectionFootnoteConfigExport.cxx new file mode 100644 index 000000000..6e1c06319 --- /dev/null +++ b/xmloff/source/text/XMLSectionFootnoteConfigExport.cxx @@ -0,0 +1,179 @@ +/* -*- 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 "XMLSectionFootnoteConfigExport.hxx" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + + +using namespace ::xmloff::token; + +using ::std::vector; +using css::style::NumberingType::ARABIC; + + +void XMLSectionFootnoteConfigExport::exportXML( + SvXMLExport& rExport, + bool bEndnote, + const vector *pProperties, + sal_uInt32 nIdx, + const rtl::Reference & rMapper) +{ + // store and initialize the values + bool bNumOwn = false; + bool bNumRestart = false; + sal_Int16 nNumRestartAt = 0; + sal_Int16 nNumberingType = ARABIC; + OUString sNumPrefix; + OUString sNumSuffix; + bool bEnd = false; + + // find entries in property states vector + sal_uInt32 nCount = pProperties->size(); + for(sal_uInt32 i = 0; i < nCount; i++) + { + const XMLPropertyState& rState = (*pProperties)[i]; + + sal_Int16 nContextId = rMapper->GetEntryContextId(rState.mnIndex); + if (!bEndnote) + { + switch (nContextId) + { + case CTF_SECTION_FOOTNOTE_NUM_OWN: + rState.maValue >>= bNumOwn; + break; + case CTF_SECTION_FOOTNOTE_NUM_RESTART: + rState.maValue >>= bNumRestart; + break; + case CTF_SECTION_FOOTNOTE_NUM_RESTART_AT: + rState.maValue >>= nNumRestartAt; + break; + case CTF_SECTION_FOOTNOTE_NUM_TYPE: + rState.maValue >>= nNumberingType; + break; + case CTF_SECTION_FOOTNOTE_NUM_PREFIX: + rState.maValue >>= sNumPrefix; + break; + case CTF_SECTION_FOOTNOTE_NUM_SUFFIX: + rState.maValue >>= sNumSuffix; + break; + case CTF_SECTION_FOOTNOTE_END: + SAL_WARN_IF( i != nIdx, "xmloff", + "received wrong property state index" ); + rState.maValue >>= bEnd; + break; + } + } + else + { + switch (nContextId) + { + case CTF_SECTION_ENDNOTE_NUM_OWN: + rState.maValue >>= bNumOwn; + break; + case CTF_SECTION_ENDNOTE_NUM_RESTART: + rState.maValue >>= bNumRestart; + break; + case CTF_SECTION_ENDNOTE_NUM_RESTART_AT: + rState.maValue >>= nNumRestartAt; + break; + case CTF_SECTION_ENDNOTE_NUM_TYPE: + rState.maValue >>= nNumberingType; + break; + case CTF_SECTION_ENDNOTE_NUM_PREFIX: + rState.maValue >>= sNumPrefix; + break; + case CTF_SECTION_ENDNOTE_NUM_SUFFIX: + rState.maValue >>= sNumSuffix; + break; + case CTF_SECTION_ENDNOTE_END: + SAL_WARN_IF( i != nIdx, "xmloff", + "received wrong property state index" ); + rState.maValue >>= bEnd; + break; + } + } + } + + // we only make an element if we have an own footnote/endnote numbering + if (!bEnd) + return; + + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + GetXMLToken( bEndnote ? XML_ENDNOTE + : XML_FOOTNOTE ) ); + // start numbering + if (bNumRestart) + { + // restart number is stored as 0.., but interpreted as 1.. + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_START_VALUE, + OUString::number(nNumRestartAt+1)); + } + + if (bNumOwn) + { + // prefix and suffix + if (!sNumPrefix.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_PREFIX, + sNumPrefix); + } + if (!sNumSuffix.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_SUFFIX, + sNumSuffix); + } + + // number type: num format + OUStringBuffer sBuf; + rExport.GetMM100UnitConverter().convertNumFormat( sBuf, + nNumberingType ); + rExport.AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sBuf.makeStringAndClear()); + + // and letter sync, if applicable + SvXMLUnitConverter::convertNumLetterSync( + sBuf, nNumberingType ); + if (!sBuf.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_STYLE, + XML_NUM_LETTER_SYNC, + sBuf.makeStringAndClear()); + } + } + + // and finally, the element + SvXMLElementExport rElem(rExport, XML_NAMESPACE_TEXT, + XML_NOTES_CONFIGURATION, + true, true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionFootnoteConfigExport.hxx b/xmloff/source/text/XMLSectionFootnoteConfigExport.hxx new file mode 100644 index 000000000..dcbf66c2e --- /dev/null +++ b/xmloff/source/text/XMLSectionFootnoteConfigExport.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/. + * + * 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 + +#include + +class SvXMLExport; +class XMLPropertySetMapper; +struct XMLPropertyState; +namespace rtl { + template class Reference; +} + +/** + * Export the footnote-/endnote-configuration element in section styles. + * + * Because this class contains only one method, and all information is + * available during that method call, we simply make it static. + */ +class XMLSectionFootnoteConfigExport +{ + +public: + static void exportXML( + SvXMLExport& rExport, + bool bEndnote, + const ::std::vector * pProperties, + sal_uInt32 nIdx, + const rtl::Reference & rMapper); /// used only for debugging +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionFootnoteConfigImport.cxx b/xmloff/source/text/XMLSectionFootnoteConfigImport.cxx new file mode 100644 index 000000000..0f4f51e1b --- /dev/null +++ b/xmloff/source/text/XMLSectionFootnoteConfigImport.cxx @@ -0,0 +1,170 @@ +/* -*- 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 "XMLSectionFootnoteConfigImport.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +using namespace ::xmloff::token; +using namespace ::com::sun::star::style; + +using ::std::vector; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; + + +XMLSectionFootnoteConfigImport::XMLSectionFootnoteConfigImport( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + vector & rProps, + const rtl::Reference & rMapperRef) : + SvXMLImportContext(rImport), + rProperties(rProps), + rMapper(rMapperRef) +{ +} + +XMLSectionFootnoteConfigImport::~XMLSectionFootnoteConfigImport() +{ +} + +void XMLSectionFootnoteConfigImport::startFastElement( + sal_Int32 /*nElement*/, + const Reference & xAttrList) +{ + bool bNumOwn = false; + bool bNumRestart = false; + bool bEndnote = false; + sal_Int16 nNumRestartAt = 0; + OUString sNumPrefix; + OUString sNumSuffix; + OUString sNumFormat; + OUString sNumLetterSync; + + // iterate over xattribute list and fill values + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_START_VALUE): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView())) + { + nNumRestartAt = static_cast< sal_Int16 >( nTmp ) - 1; + bNumRestart = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_NOTE_CLASS): + { + if( IsXMLToken( aIter, XML_ENDNOTE ) ) + bEndnote = true; + break; + } + case XML_ELEMENT(STYLE, XML_NUM_PREFIX): + { + sNumPrefix = aIter.toString(); + bNumOwn = true; + break; + } + case XML_ELEMENT(STYLE, XML_NUM_SUFFIX): + { + sNumSuffix = aIter.toString(); + bNumOwn = true; + break; + } + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + { + sNumFormat = aIter.toString(); + bNumOwn = true; + break; + } + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + { + sNumLetterSync = aIter.toString(); + bNumOwn = true; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // OK, now we have all values and can fill the XMLPropertyState vector + + sal_Int32 nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_OWN : CTF_SECTION_FOOTNOTE_NUM_OWN ); + XMLPropertyState aNumOwn( nIndex, css::uno::Any(bNumOwn) ); + rProperties.push_back( aNumOwn ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_RESTART : CTF_SECTION_FOOTNOTE_NUM_RESTART ); + XMLPropertyState aNumRestart( nIndex, css::uno::Any(bNumRestart) ); + rProperties.push_back( aNumRestart ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_RESTART_AT : + CTF_SECTION_FOOTNOTE_NUM_RESTART_AT ); + XMLPropertyState aNumRestartAtState( nIndex, css::uno::Any(nNumRestartAt) ); + rProperties.push_back( aNumRestartAtState ); + + sal_Int16 nNumType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumFormat, + sNumLetterSync ); + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_TYPE : CTF_SECTION_FOOTNOTE_NUM_TYPE ); + XMLPropertyState aNumFormatState( nIndex, css::uno::Any(nNumType) ); + rProperties.push_back( aNumFormatState ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_PREFIX : CTF_SECTION_FOOTNOTE_NUM_PREFIX ); + XMLPropertyState aPrefixState( nIndex, css::uno::Any(sNumPrefix) ); + rProperties.push_back( aPrefixState ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_NUM_SUFFIX : CTF_SECTION_FOOTNOTE_NUM_SUFFIX ); + XMLPropertyState aSuffixState( nIndex, css::uno::Any(sNumSuffix) ); + rProperties.push_back( aSuffixState ); + + nIndex = rMapper->FindEntryIndex( bEndnote ? + CTF_SECTION_ENDNOTE_END : CTF_SECTION_FOOTNOTE_END ); + XMLPropertyState aEndState( nIndex, css::uno::Any(true) ); // we're inside the element, so this is true + rProperties.push_back( aEndState ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionFootnoteConfigImport.hxx b/xmloff/source/text/XMLSectionFootnoteConfigImport.hxx new file mode 100644 index 000000000..dc7bc7c94 --- /dev/null +++ b/xmloff/source/text/XMLSectionFootnoteConfigImport.hxx @@ -0,0 +1,61 @@ +/* -*- 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 +#include +#include + + +class SvXMLImport; +struct XMLPropertyState; +class XMLPropertySetMapper; +namespace com::sun::star { + namespace uno { template class Reference; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import the footnote-/endnote-configuration element in section styles. + */ +class XMLSectionFootnoteConfigImport : public SvXMLImportContext +{ + ::std::vector & rProperties; + rtl::Reference rMapper; + +public: + + + XMLSectionFootnoteConfigImport( + SvXMLImport& rImport, + sal_Int32 nElement, + ::std::vector & rProperties, + const rtl::Reference & rMapperRef); + + virtual ~XMLSectionFootnoteConfigImport() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionImportContext.cxx b/xmloff/source/text/XMLSectionImportContext.cxx new file mode 100644 index 000000000..54620ddfe --- /dev/null +++ b/xmloff/source/text/XMLSectionImportContext.cxx @@ -0,0 +1,325 @@ +/* -*- 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 "XMLSectionImportContext.hxx" +#include "XMLSectionSourceImportContext.hxx" +#include "XMLSectionSourceDDEImportContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::container::XNamed; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + + +// section import: This one is fairly tricky due to a variety of +// limits of the core or the API. The main problem is that if you +// insert a section within another section, you can't move the cursor +// between the ends of the inner and the enclosing section. To avoid +// these problems, additional markers are first inserted and later deleted. +XMLSectionImportContext::XMLSectionImportContext( SvXMLImport& rImport ) +: SvXMLImportContext(rImport) +, bProtect(false) +, bCondOK(false) +, bIsVisible(true) +, bValid(false) +, bSequenceOK(false) +, bIsCurrentlyVisible(true) +, bIsCurrentlyVisibleOK(false) +, bHasContent(false) +{ +} + +XMLSectionImportContext::~XMLSectionImportContext() +{ +} + +void XMLSectionImportContext::startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // process attributes + ProcessAttributes(xAttrList); + + // process index headers: + bool bIsIndexHeader = (nElement & TOKEN_MASK) == XML_INDEX_TITLE; + if (bIsIndexHeader) + { + bValid = true; + } + + rtl::Reference rHelper = GetImport().GetTextImport(); + + // valid? + if (!bValid) + return; + + // create text section (as XPropertySet) + Reference xFactory( + GetImport().GetModel(),UNO_QUERY); + if (!xFactory.is()) + return; + + Reference xIfc = + xFactory->createInstance( bIsIndexHeader ? OUString("com.sun.star.text.IndexHeaderSection") + : OUString("com.sun.star.text.TextSection") ); + if (!xIfc.is()) + return; + + Reference xPropSet(xIfc, UNO_QUERY); + + // save PropertySet (for CreateChildContext) + xSectionPropertySet = xPropSet; + + // name + Reference xNamed(xPropSet, UNO_QUERY); + xNamed->setName(sName); + + // stylename? + if (!sStyleName.isEmpty()) + { + XMLPropStyleContext* pStyle = rHelper-> + FindSectionStyle(sStyleName); + + if (pStyle != nullptr) + { + pStyle->FillPropertySet( xPropSet ); + } + } + + // IsVisible and condition (not for index headers) + if (! bIsIndexHeader) + { + xPropSet->setPropertyValue( "IsVisible", Any(bIsVisible) ); + + // #97450# hidden sections must be hidden on reload + // For backwards compatibility, set flag only if it is + // present + if( bIsCurrentlyVisibleOK ) + { + xPropSet->setPropertyValue( "IsCurrentlyVisible", Any(bIsCurrentlyVisible)); + } + + if (bCondOK) + { + xPropSet->setPropertyValue( "Condition", Any(sCond) ); + } + } + + // password (only for regular sections) + if ( bSequenceOK && + (nElement & TOKEN_MASK) == XML_SECTION ) + { + xPropSet->setPropertyValue("ProtectionKey", Any(aSequence)); + } + + // protection + xPropSet->setPropertyValue( "IsProtected", Any(bProtect) ); + + // insert marker, , marker; then insert + // section over the first marker character, and delete the + // last paragraph (and marker) when closing a section. + Reference xStart = + rHelper->GetCursor()->getStart(); +#ifndef DBG_UTIL + OUString sMarkerString(" "); +#else + OUString sMarkerString("X"); +#endif + rHelper->InsertString(sMarkerString); + rHelper->InsertControlCharacter( + ControlCharacter::APPEND_PARAGRAPH ); + rHelper->InsertString(sMarkerString); + + // select first marker + rHelper->GetCursor()->gotoRange(xStart, false); + rHelper->GetCursor()->goRight(1, true); + + // convert section to XTextContent + Reference xTextContent(xSectionPropertySet, + UNO_QUERY); + + // and insert (over marker) + rHelper->GetText()->insertTextContent( + rHelper->GetCursorAsRange(), xTextContent, true ); + + // and delete first marker (in section) + rHelper->GetText()->insertString( + rHelper->GetCursorAsRange(), "", true); + + // finally, check for redlines that should start at + // the section start node + rHelper->RedlineAdjustStartNodeCursor(); // start ??? + + // xml:id for RDF metadata + GetImport().SetXmlId(xIfc, sXmlId); +} + +void XMLSectionImportContext::ProcessAttributes( + const Reference & xAttrList ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(XML, XML_ID): + sXmlId = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_NAME): + sName = aIter.toString(); + bValid = true; + break; + case XML_ELEMENT(TEXT, XML_CONDITION): + { + OUString sValue = aIter.toString(); + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). + GetKeyByAttrValueQName(sValue, &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCond = sTmp; + bCondOK = true; + } + else + sCond = sValue; + } + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + if (IsXMLToken(aIter, XML_TRUE)) + { + bIsVisible = true; + } + else if ( IsXMLToken(aIter, XML_NONE) || + IsXMLToken(aIter, XML_CONDITION) ) + { + bIsVisible = false; + } + // else: ignore + break; + case XML_ELEMENT(TEXT, XML_IS_HIDDEN): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bIsCurrentlyVisible = !bTmp; + bIsCurrentlyVisibleOK = true; + } + } + break; + case XML_ELEMENT(TEXT, XML_PROTECTION_KEY): + ::comphelper::Base64::decode(aSequence, aIter.toString()); + bSequenceOK = true; + break; + case XML_ELEMENT(TEXT, XML_PROTECTED): + // compatibility with SRC629 (or earlier) versions + case XML_ELEMENT(TEXT, XML_PROTECT): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bProtect = bTmp; + } + break; + } + default: + // ignore + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } +} + +void XMLSectionImportContext::endFastElement(sal_Int32 ) +{ + // get rid of last paragraph + // (unless it's the only paragraph in the section) + rtl::Reference rHelper = GetImport().GetTextImport(); + rHelper->GetCursor()->goRight(1, false); + if (bHasContent) + { + rHelper->GetCursor()->goLeft(1, true); + rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), + "", true); + } + + // and delete second marker + rHelper->GetCursor()->goRight(1, true); + rHelper->GetText()->insertString(rHelper->GetCursorAsRange(), + "", true); + + // check for redlines to our endnode + rHelper->RedlineAdjustStartNodeCursor(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLSectionImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // section-source (-dde) elements + if ( nElement == XML_ELEMENT(TEXT, XML_SECTION_SOURCE) ) + { + return new XMLSectionSourceImportContext(GetImport(), + xSectionPropertySet); + } + else if ( nElement == XML_ELEMENT(OFFICE, XML_DDE_SOURCE) ) + { + return new XMLSectionSourceDDEImportContext(GetImport(), + xSectionPropertySet); + } + else + { + // otherwise: text context + auto pContext = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, XMLTextType::Section ); + + // if that fails, default context + if (pContext) + bHasContent = true; + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return pContext; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionImportContext.hxx b/xmloff/source/text/XMLSectionImportContext.hxx new file mode 100644 index 000000000..83f40d05e --- /dev/null +++ b/xmloff/source/text/XMLSectionImportContext.hxx @@ -0,0 +1,80 @@ +/* -*- 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 +#include +#include + +namespace com::sun::star { + namespace text { class XTextRange; } + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + + +/** + * Import text sections. + * + * This context may *also* be used for index header sections. The + * differentiates its behaviour based on GetLocalName(). + */ +class XMLSectionImportContext final : public SvXMLImportContext +{ + /// TextSection (as XPropertySet) for passing down to data source elements + css::uno::Reference xSectionPropertySet; + + OUString sXmlId; + OUString sStyleName; + OUString sName; + OUString sCond; + css::uno::Sequence aSequence; + bool bProtect; + bool bCondOK; + bool bIsVisible; + bool bValid; + bool bSequenceOK; + bool bIsCurrentlyVisible; + bool bIsCurrentlyVisibleOK; + + bool bHasContent; + +public: + + XMLSectionImportContext( SvXMLImport& rImport ); + + virtual ~XMLSectionImportContext() override; + +private: + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + void ProcessAttributes( + const css::uno::Reference & xAttrList ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionSourceDDEImportContext.cxx b/xmloff/source/text/XMLSectionSourceDDEImportContext.cxx new file mode 100644 index 000000000..e2d8f1ce8 --- /dev/null +++ b/xmloff/source/text/XMLSectionSourceDDEImportContext.cxx @@ -0,0 +1,108 @@ +/* -*- 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 "XMLSectionSourceDDEImportContext.hxx" +#include "XMLSectionImportContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::beans::XMultiPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XFastAttributeList; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + +XMLSectionSourceDDEImportContext::XMLSectionSourceDDEImportContext( + SvXMLImport& rImport, + Reference & rSectPropSet) : + SvXMLImportContext(rImport), + rSectionPropertySet(rSectPropSet) +{ +} + +XMLSectionSourceDDEImportContext::~XMLSectionSourceDDEImportContext() +{ +} + +void XMLSectionSourceDDEImportContext::startFastElement(sal_Int32 /*nElement*/, + const Reference & xAttrList) +{ + OUString sApplication; + OUString sTopic; + OUString sItem; + bool bAutomaticUpdate = false; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(OFFICE, XML_DDE_APPLICATION): + sApplication = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_DDE_TOPIC): + sTopic = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_DDE_ITEM): + sItem = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_UPDATE): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bAutomaticUpdate = bTmp; + } + break; + } + default: + ; // ignore + break; + } + } + + // DDE not supported on all platforms; query property first + if (!rSectionPropertySet->getPropertySetInfo()-> + hasPropertyByName("DDECommandFile")) + return; + + // use multi property set to force single update of connection #83654# + Sequence aNames { "DDECommandFile", "DDECommandType", "DDECommandElement", "IsAutomaticUpdate" }; + Sequence aValues { Any(sApplication), Any(sTopic), Any(sItem), Any(bAutomaticUpdate) }; + + Reference rMultiPropSet(rSectionPropertySet, + UNO_QUERY); + DBG_ASSERT(rMultiPropSet.is(), "we'd really like a XMultiPropertySet"); + if (rMultiPropSet.is()) + rMultiPropSet->setPropertyValues(aNames, aValues); + // else: ignore + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionSourceDDEImportContext.hxx b/xmloff/source/text/XMLSectionSourceDDEImportContext.hxx new file mode 100644 index 000000000..31726f098 --- /dev/null +++ b/xmloff/source/text/XMLSectionSourceDDEImportContext.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/. + * + * 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 +#include + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + +class XMLSectionSourceDDEImportContext : public SvXMLImportContext +{ + css::uno::Reference & rSectionPropertySet; + +public: + + XMLSectionSourceDDEImportContext( + SvXMLImport& rImport, + css::uno::Reference & rSectPropSet); + + virtual ~XMLSectionSourceDDEImportContext() override; + +protected: + + virtual void SAL_CALL startFastElement(sal_Int32 nElement, + const css::uno::Reference & xAttrList) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionSourceImportContext.cxx b/xmloff/source/text/XMLSectionSourceImportContext.cxx new file mode 100644 index 000000000..c24ffd9e9 --- /dev/null +++ b/xmloff/source/text/XMLSectionSourceImportContext.cxx @@ -0,0 +1,98 @@ +/* -*- 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 "XMLSectionSourceImportContext.hxx" +#include "XMLSectionImportContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + + +using ::com::sun::star::beans::XPropertySet; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; + + +XMLSectionSourceImportContext::XMLSectionSourceImportContext( + SvXMLImport& rImport, + Reference & rSectPropSet) : + SvXMLImportContext(rImport), + rSectionPropertySet(rSectPropSet) +{ +} + +XMLSectionSourceImportContext::~XMLSectionSourceImportContext() +{ +} + +void XMLSectionSourceImportContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + OUString sURL; + OUString sFilterName; + OUString sSectionName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + sURL = sValue; + break; + + case XML_ELEMENT(TEXT, XML_FILTER_NAME): + sFilterName = sValue; + break; + + case XML_ELEMENT(TEXT, XML_SECTION_NAME): + sSectionName = sValue; + break; + + default: + ; // ignore + break; + } + } + + if (!sURL.isEmpty() || !sFilterName.isEmpty()) + { + SectionFileLink aFileLink; + aFileLink.FileURL = GetImport().GetAbsoluteReference( sURL ); + aFileLink.FilterName = sFilterName; + + rSectionPropertySet->setPropertyValue("FileLink", Any(aFileLink)); + } + + if (!sSectionName.isEmpty()) + { + rSectionPropertySet->setPropertyValue("LinkRegion", Any(sSectionName)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLSectionSourceImportContext.hxx b/xmloff/source/text/XMLSectionSourceImportContext.hxx new file mode 100644 index 000000000..f47dddcbb --- /dev/null +++ b/xmloff/source/text/XMLSectionSourceImportContext.hxx @@ -0,0 +1,46 @@ +/* -*- 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 +#include + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace xml::sax { class XAttributeList; } +} + +class XMLSectionSourceImportContext final : public SvXMLImportContext +{ + css::uno::Reference & rSectionPropertySet; + +public: + + XMLSectionSourceImportContext( + SvXMLImport& rImport, + css::uno::Reference & rSectPropSet); + + virtual ~XMLSectionSourceImportContext() override; + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLStringBufferImportContext.cxx b/xmloff/source/text/XMLStringBufferImportContext.cxx new file mode 100644 index 000000000..9e25d6234 --- /dev/null +++ b/xmloff/source/text/XMLStringBufferImportContext.cxx @@ -0,0 +1,62 @@ +/* -*- 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 +#include +#include + + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_P; + +XMLStringBufferImportContext::XMLStringBufferImportContext( + SvXMLImport& rImport, + OUStringBuffer& rBuffer) : + SvXMLImportContext(rImport), + rTextBuffer(rBuffer) +{ +} + +XMLStringBufferImportContext::~XMLStringBufferImportContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLStringBufferImportContext::createFastChildContext( + sal_Int32 /*nElement*/, const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) +{ + return new XMLStringBufferImportContext(GetImport(), rTextBuffer); +} + +void XMLStringBufferImportContext::characters(const OUString& rChars ) +{ + rTextBuffer.append(rChars); +} + +void XMLStringBufferImportContext::endFastElement(sal_Int32 nElement) +{ + // add return for paragraph elements + if ( nElement == XML_ELEMENT(TEXT, XML_P) || nElement == XML_ELEMENT(LO_EXT, XML_P)) + { + rTextBuffer.append(u'\x000a'); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextCharStyleNamesElementExport.cxx b/xmloff/source/text/XMLTextCharStyleNamesElementExport.cxx new file mode 100644 index 000000000..4cdbbc2b0 --- /dev/null +++ b/xmloff/source/text/XMLTextCharStyleNamesElementExport.cxx @@ -0,0 +1,75 @@ +/* -*- 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 "XMLTextCharStyleNamesElementExport.hxx" +#include +#include +#include +#include +#include + +namespace com::sun::star::beans { class XPropertySet; } + +using namespace ::com::sun::star::uno; +using ::com::sun::star::beans::XPropertySet; +using namespace ::xmloff::token; + +XMLTextCharStyleNamesElementExport::XMLTextCharStyleNamesElementExport( + SvXMLExport& rExp, + bool bDoSth, + bool bAllStyles, + const Reference < XPropertySet > & rPropSet, + const OUString& rPropName ) : + rExport( rExp ), + nCount( 0 ) +{ + if( !bDoSth ) + return; + + Any aAny = rPropSet->getPropertyValue( rPropName ); + Sequence < OUString > aNames; + if( !(aAny >>= aNames) ) + return; + + nCount = aNames.getLength(); + OSL_ENSURE( nCount > 0, "no char style found" ); + if ( bAllStyles ) ++nCount; + if( nCount > 1 ) + { + aName = rExport.GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, GetXMLToken(XML_SPAN) ); + for( sal_Int32 i = 1; i < nCount; ++i ) + { + rExport.AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + rExport.EncodeStyleName( aNames[i - 1] ) ); + rExport.StartElement( aName, false ); + } + } +} + +XMLTextCharStyleNamesElementExport::~XMLTextCharStyleNamesElementExport() +{ + if( nCount > 1 ) + { + for( sal_Int32 i = 1; i < nCount; ++i ) + rExport.EndElement( aName, false ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextCharStyleNamesElementExport.hxx b/xmloff/source/text/XMLTextCharStyleNamesElementExport.hxx new file mode 100644 index 000000000..0eaad5d33 --- /dev/null +++ b/xmloff/source/text/XMLTextCharStyleNamesElementExport.hxx @@ -0,0 +1,46 @@ +/* -*- 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 +#include + + +namespace com::sun::star { + namespace beans { class XPropertySet; } +} + +class SvXMLExport; + +class XMLTextCharStyleNamesElementExport +{ + SvXMLExport& rExport; + OUString aName; + sal_Int32 nCount; + +public: + + XMLTextCharStyleNamesElementExport( + SvXMLExport& rExp, bool bDoSomething, bool bAllStyles, + const css::uno::Reference < css::beans::XPropertySet > & rPropSet, + const OUString& rPropName ); + ~XMLTextCharStyleNamesElementExport(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextColumnsContext.cxx b/xmloff/source/text/XMLTextColumnsContext.cxx new file mode 100644 index 000000000..244a0ecce --- /dev/null +++ b/xmloff/source/text/XMLTextColumnsContext.cxx @@ -0,0 +1,372 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +SvXMLEnumMapEntry const pXML_Sep_Style_Enum[] = +{ + { XML_NONE, 0 }, + { XML_SOLID, 1 }, + { XML_DOTTED, 2 }, + { XML_DASHED, 3 }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_Sep_Align_Enum[] = +{ + { XML_TOP, VerticalAlignment_TOP }, + { XML_MIDDLE, VerticalAlignment_MIDDLE }, + { XML_BOTTOM, VerticalAlignment_BOTTOM }, + { XML_TOKEN_INVALID, VerticalAlignment(0) } +}; + +class XMLTextColumnContext_Impl: public SvXMLImportContext +{ + text::TextColumn aColumn; + +public: + + XMLTextColumnContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< + xml::sax::XFastAttributeList > & xAttrList ); + + text::TextColumn& getTextColumn() { return aColumn; } +}; + + +XMLTextColumnContext_Impl::XMLTextColumnContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< + xml::sax::XFastAttributeList > & xAttrList ) : + SvXMLImportContext( rImport ) +{ + aColumn.Width = 0; + aColumn.LeftMargin = 0; + aColumn.RightMargin = 0; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(STYLE, XML_REL_WIDTH): + { + size_t nPos = aIter.toView().find( '*' ); + if( nPos != std::string_view::npos && static_cast(nPos+1) == aIter.getLength() ) + { + if (::sax::Converter::convertNumber( + nVal, + aIter.toView().substr(0, nPos), + 0, USHRT_MAX)) + aColumn.Width = nVal; + } + } + break; + case XML_ELEMENT(FO, XML_START_INDENT): + case XML_ELEMENT(FO_COMPAT, XML_START_INDENT): + if( GetImport().GetMM100UnitConverter(). + convertMeasureToCore( nVal, aIter.toView() ) ) + aColumn.LeftMargin = nVal; + break; + case XML_ELEMENT(FO, XML_END_INDENT): + case XML_ELEMENT(FO_COMPAT, XML_END_INDENT): + if( GetImport().GetMM100UnitConverter(). + convertMeasureToCore( nVal, aIter.toView() ) ) + aColumn.RightMargin = nVal; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } + } +} + +class XMLTextColumnSepContext_Impl: public SvXMLImportContext +{ + sal_Int32 nWidth; + sal_Int32 nColor; + sal_Int8 nHeight; + sal_Int8 nStyle; + VerticalAlignment eVertAlign; + +public: + + XMLTextColumnSepContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const uno::Reference< + xml::sax::XFastAttributeList > & xAttrList ); + + sal_Int32 GetWidth() const { return nWidth; } + sal_Int32 GetColor() const { return nColor; } + sal_Int8 GetHeight() const { return nHeight; } + sal_Int8 GetStyle() const { return nStyle; } + VerticalAlignment GetVertAlign() const { return eVertAlign; } +}; + + +XMLTextColumnSepContext_Impl::XMLTextColumnSepContext_Impl( + SvXMLImport& rImport, sal_Int32 /*nElement*/, + const uno::Reference< + xml::sax::XFastAttributeList > & xAttrList) : + SvXMLImportContext( rImport ), + nWidth( 2 ), + nColor( 0 ), + nHeight( 100 ), + nStyle( 1 ), + eVertAlign( VerticalAlignment_TOP ) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + sal_Int32 nVal; + switch( aIter.getToken() ) + { + case XML_ELEMENT(STYLE, XML_WIDTH): + if( GetImport().GetMM100UnitConverter(). + convertMeasureToCore( nVal, aIter.toView() ) ) + nWidth = nVal; + break; + case XML_ELEMENT(STYLE, XML_HEIGHT): + if (::sax::Converter::convertPercent( nVal, aIter.toView() ) && + nVal >=1 && nVal <= 100 ) + nHeight = static_cast(nVal); + break; + case XML_ELEMENT(STYLE, XML_COLOR): + ::sax::Converter::convertColor( nColor, aIter.toView() ); + break; + case XML_ELEMENT(STYLE, XML_VERTICAL_ALIGN): + SvXMLUnitConverter::convertEnum( eVertAlign, aIter.toView(), + pXML_Sep_Align_Enum ); + break; + case XML_ELEMENT(STYLE, XML_STYLE): + SvXMLUnitConverter::convertEnum( nStyle, aIter.toView(), + pXML_Sep_Style_Enum ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +constexpr OUStringLiteral gsSeparatorLineIsOn(u"SeparatorLineIsOn"); +constexpr OUStringLiteral gsSeparatorLineWidth(u"SeparatorLineWidth"); +constexpr OUStringLiteral gsSeparatorLineColor(u"SeparatorLineColor"); +constexpr OUStringLiteral gsSeparatorLineRelativeHeight(u"SeparatorLineRelativeHeight"); +constexpr OUStringLiteral gsSeparatorLineVerticalAlignment(u"SeparatorLineVerticalAlignment"); +constexpr OUStringLiteral gsAutomaticDistance(u"AutomaticDistance"); +constexpr OUStringLiteral gsSeparatorLineStyle(u"SeparatorLineStyle"); + +XMLTextColumnsContext::XMLTextColumnsContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList >& xAttrList, + const XMLPropertyState& rProp, + ::std::vector< XMLPropertyState > &rProps ) +: XMLElementPropertyContext( rImport, nElement, rProp, rProps ) +, nCount( 0 ) +, bAutomatic( false ) +, nAutomaticDistance( 0 ) +{ + sal_Int32 nVal; + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(FO, XML_COLUMN_COUNT): + case XML_ELEMENT(FO_COMPAT, XML_COLUMN_COUNT): + if(::sax::Converter::convertNumber( nVal, aIter.toView(), 0, SHRT_MAX )) + nCount = static_cast(nVal); + break; + case XML_ELEMENT(FO, XML_COLUMN_GAP): + case XML_ELEMENT(FO_COMPAT, XML_COLUMN_GAP): + { + bAutomatic = GetImport().GetMM100UnitConverter(). + convertMeasureToCore( nAutomaticDistance, aIter.toView() ); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextColumnsContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_COLUMN) ) + { + const rtl::Reference xColumn{ + new XMLTextColumnContext_Impl( GetImport(), nElement, xAttrList )}; + + // add new tabstop to array of tabstops + if( !pColumns ) + pColumns = std::make_unique(); + + pColumns->push_back( xColumn ); + + return xColumn; + } + else if( nElement == XML_ELEMENT(STYLE, XML_COLUMN_SEP) ) + { + mxColumnSep.set( + new XMLTextColumnSepContext_Impl( GetImport(), nElement, xAttrList )); + + return mxColumnSep; + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +void XMLTextColumnsContext::endFastElement(sal_Int32 nElement ) +{ + Reference xFactory(GetImport().GetModel(),UNO_QUERY); + if( !xFactory.is() ) + return; + + Reference xIfc = xFactory->createInstance("com.sun.star.text.TextColumns"); + if( !xIfc.is() ) + return; + + Reference< XTextColumns > xColumns( xIfc, UNO_QUERY ); + if ( 0 == nCount ) + { + // zero columns = no columns -> 1 column + xColumns->setColumnCount( 1 ); + } + else if( !bAutomatic && pColumns && + pColumns->size() == static_cast(nCount) ) + { + // if we have column descriptions, one per column, and we don't use + // automatic width, then set the column widths + + sal_Int32 nRelWidth = 0; + sal_uInt16 nColumnsWithWidth = 0; + sal_Int16 i; + + for( i = 0; i < nCount; i++ ) + { + const TextColumn& rColumn = + (*pColumns)[static_cast(i)]->getTextColumn(); + if( rColumn.Width > 0 ) + { + nRelWidth += rColumn.Width; + nColumnsWithWidth++; + } + } + if( nColumnsWithWidth < nCount ) + { + sal_Int32 nColWidth = 0==nRelWidth + ? USHRT_MAX / nCount + : nRelWidth / nColumnsWithWidth; + + for( i=0; i < nCount; i++ ) + { + TextColumn& rColumn = + (*pColumns)[static_cast(i)]->getTextColumn(); + if( rColumn.Width == 0 ) + { + rColumn.Width = nColWidth; + nRelWidth += rColumn.Width; + if( 0 == --nColumnsWithWidth ) + break; + } + } + } + + Sequence< TextColumn > aColumns( static_cast(nCount) ); + TextColumn *pTextColumns = aColumns.getArray(); + for( i=0; i < nCount; i++ ) + *pTextColumns++ = (*pColumns)[static_cast(i)]->getTextColumn(); + + xColumns->setColumns( aColumns ); + } + else + { + // only set column count (and let the columns be distributed + // automatically) + + xColumns->setColumnCount( nCount ); + } + + Reference < XPropertySet > xPropSet( xColumns, UNO_QUERY ); + if( xPropSet.is() ) + { + bool bOn = mxColumnSep != nullptr; + + xPropSet->setPropertyValue( gsSeparatorLineIsOn, Any(bOn) ); + + if( mxColumnSep.is() ) + { + if( mxColumnSep->GetWidth() ) + { + xPropSet->setPropertyValue( gsSeparatorLineWidth, Any(mxColumnSep->GetWidth()) ); + } + if( mxColumnSep->GetHeight() ) + { + xPropSet->setPropertyValue( gsSeparatorLineRelativeHeight, + Any(mxColumnSep->GetHeight()) ); + } + if ( mxColumnSep->GetStyle() ) + { + xPropSet->setPropertyValue( gsSeparatorLineStyle, Any(mxColumnSep->GetStyle()) ); + } + + xPropSet->setPropertyValue( gsSeparatorLineColor, Any(mxColumnSep->GetColor()) ); + + xPropSet->setPropertyValue( gsSeparatorLineVerticalAlignment, Any(mxColumnSep->GetVertAlign()) ); + } + + // handle 'automatic columns': column distance + if( bAutomatic ) + { + xPropSet->setPropertyValue( gsAutomaticDistance, Any(nAutomaticDistance) ); + } + } + + aProp.maValue <<= xColumns; + + SetInsert( true ); + XMLElementPropertyContext::endFastElement(nElement); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextColumnsExport.cxx b/xmloff/source/text/XMLTextColumnsExport.cxx new file mode 100644 index 000000000..ec80f2ed9 --- /dev/null +++ b/xmloff/source/text/XMLTextColumnsExport.cxx @@ -0,0 +1,196 @@ +/* -*- 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 + +#include +#include + + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + + +constexpr OUStringLiteral gsSeparatorLineIsOn(u"SeparatorLineIsOn"); +constexpr OUStringLiteral gsSeparatorLineWidth(u"SeparatorLineWidth"); +constexpr OUStringLiteral gsSeparatorLineColor(u"SeparatorLineColor"); +constexpr OUStringLiteral gsSeparatorLineRelativeHeight(u"SeparatorLineRelativeHeight"); +constexpr OUStringLiteral gsSeparatorLineVerticalAlignment(u"SeparatorLineVerticalAlignment"); +constexpr OUStringLiteral gsIsAutomatic(u"IsAutomatic"); +constexpr OUStringLiteral gsAutomaticDistance(u"AutomaticDistance"); +constexpr OUStringLiteral gsSeparatorLineStyle(u"SeparatorLineStyle"); + +XMLTextColumnsExport::XMLTextColumnsExport( SvXMLExport& rExp ) : + rExport( rExp ) +{ +} + +void XMLTextColumnsExport::exportXML( const Any& rAny ) +{ + Reference < XTextColumns > xColumns; + rAny >>= xColumns; + if (!xColumns) + return; + + const Sequence < TextColumn > aColumns = xColumns->getColumns(); + sal_Int32 nCount = aColumns.getLength(); + + OUStringBuffer sValue; + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_COLUMN_COUNT, + OUString::number(nCount ? nCount : 1) ); + + // handle 'automatic' columns + Reference < XPropertySet > xPropSet( xColumns, UNO_QUERY ); + if( xPropSet.is() ) + { + Any aAny = xPropSet->getPropertyValue( gsIsAutomatic ); + if ( *o3tl::doAccess(aAny) ) + { + aAny = xPropSet->getPropertyValue( gsAutomaticDistance ); + sal_Int32 nDistance = 0; + aAny >>= nDistance; + OUStringBuffer aBuffer; + GetExport().GetMM100UnitConverter().convertMeasureToXML( + aBuffer, nDistance ); + GetExport().AddAttribute( XML_NAMESPACE_FO, + XML_COLUMN_GAP, + aBuffer.makeStringAndClear() ); + } + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, XML_COLUMNS, + true, true ); + + if( xPropSet.is() ) + { + Any aAny = xPropSet->getPropertyValue( gsSeparatorLineIsOn ); + if( *o3tl::doAccess(aAny) ) + { + // style:width + aAny = xPropSet->getPropertyValue( gsSeparatorLineWidth ); + sal_Int32 nWidth = 0; + aAny >>= nWidth; + GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue, + nWidth ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_WIDTH, + sValue.makeStringAndClear() ); + + // style:color + aAny = xPropSet->getPropertyValue( gsSeparatorLineColor ); + sal_Int32 nColor = 0; + aAny >>= nColor; + ::sax::Converter::convertColor( sValue, nColor ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_COLOR, + sValue.makeStringAndClear() ); + + // style:height + aAny = xPropSet->getPropertyValue( gsSeparatorLineRelativeHeight ); + sal_Int32 nHeight = 0; + aAny >>= nHeight; + ::sax::Converter::convertPercent( sValue, nHeight ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_HEIGHT, + sValue.makeStringAndClear() ); + + // style::style + aAny = xPropSet->getPropertyValue( gsSeparatorLineStyle ); + sal_Int16 nStyle = css::text::ColumnSeparatorStyle::NONE; + aAny >>= nStyle; + + enum XMLTokenEnum eStr = XML_TOKEN_INVALID; + switch ( nStyle ) + { + case css::text::ColumnSeparatorStyle::NONE: eStr = XML_NONE; break; + case css::text::ColumnSeparatorStyle::SOLID: eStr = XML_SOLID; break; + case css::text::ColumnSeparatorStyle::DOTTED: eStr = XML_DOTTED; break; + case css::text::ColumnSeparatorStyle::DASHED: eStr = XML_DASHED; break; + default: + break; + } + if ( eStr != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_STYLE, eStr ); + + // style:vertical-align + aAny = xPropSet->getPropertyValue( gsSeparatorLineVerticalAlignment ); + VerticalAlignment eVertAlign; + aAny >>= eVertAlign; + + eStr = XML_TOKEN_INVALID; + switch( eVertAlign ) + { +// case VerticalAlignment_TOP: eStr = XML_TOP; + case VerticalAlignment_MIDDLE: eStr = XML_MIDDLE; break; + case VerticalAlignment_BOTTOM: eStr = XML_BOTTOM; break; + default: + break; + } + + if( eStr != XML_TOKEN_INVALID) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_VERTICAL_ALIGN, eStr ); + + // style:column-sep + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, + XML_COLUMN_SEP, + true, true ); + } + } + + for (const auto& rColumn : aColumns) + { + // style:rel-width + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH, + OUString::number(rColumn.Width) + "*" ); + + // fo:margin-left + GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue, + rColumn.LeftMargin ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_START_INDENT, + sValue.makeStringAndClear() ); + + // fo:margin-right + GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue, + rColumn.RightMargin ); + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_END_INDENT, + sValue.makeStringAndClear() ); + + // style:column + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_STYLE, XML_COLUMN, + true, true ); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextFrameContext.cxx b/xmloff/source/text/XMLTextFrameContext.cxx new file mode 100644 index 000000000..b24859860 --- /dev/null +++ b/xmloff/source/text/XMLTextFrameContext.cxx @@ -0,0 +1,1719 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "XMLAnchorTypePropHdl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "XMLTextFrameContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::document; +using namespace ::xmloff::token; +using ::com::sun::star::document::XEventsSupplier; + +#define XML_TEXT_FRAME_TEXTBOX 1 +#define XML_TEXT_FRAME_GRAPHIC 2 +#define XML_TEXT_FRAME_OBJECT 3 +#define XML_TEXT_FRAME_OBJECT_OLE 4 +#define XML_TEXT_FRAME_APPLET 5 +#define XML_TEXT_FRAME_PLUGIN 6 +#define XML_TEXT_FRAME_FLOATING_FRAME 7 + +typedef ::std::map < const OUString, OUString > ParamMap; + +class XMLTextFrameContextHyperlink_Impl +{ + OUString sHRef; + OUString sName; + OUString sTargetFrameName; + bool bMap; + +public: + + inline XMLTextFrameContextHyperlink_Impl( const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + bool bMap ); + + const OUString& GetHRef() const { return sHRef; } + const OUString& GetName() const { return sName; } + const OUString& GetTargetFrameName() const { return sTargetFrameName; } + bool GetMap() const { return bMap; } +}; + +inline XMLTextFrameContextHyperlink_Impl::XMLTextFrameContextHyperlink_Impl( + const OUString& rHRef, const OUString& rName, + const OUString& rTargetFrameName, bool bM ) : + sHRef( rHRef ), + sName( rName ), + sTargetFrameName( rTargetFrameName ), + bMap( bM ) +{ +} + +namespace { + +// Implement Title/Description Elements UI (#i73249#) +class XMLTextFrameTitleOrDescContext_Impl : public SvXMLImportContext +{ + OUString& mrTitleOrDesc; + +public: + + + XMLTextFrameTitleOrDescContext_Impl( SvXMLImport& rImport, + OUString& rTitleOrDesc ); + + virtual void SAL_CALL characters( const OUString& rText ) override; +}; + +} + +XMLTextFrameTitleOrDescContext_Impl::XMLTextFrameTitleOrDescContext_Impl( + SvXMLImport& rImport, + OUString& rTitleOrDesc ) + : SvXMLImportContext( rImport ) + , mrTitleOrDesc( rTitleOrDesc ) +{ +} + +void XMLTextFrameTitleOrDescContext_Impl::characters( const OUString& rText ) +{ + mrTitleOrDesc += rText; +} + +namespace { + +class XMLTextFrameParam_Impl : public SvXMLImportContext +{ +public: + XMLTextFrameParam_Impl( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + ParamMap &rParamMap); +}; + +} + +XMLTextFrameParam_Impl::XMLTextFrameParam_Impl( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + ParamMap &rParamMap): + SvXMLImportContext( rImport ) +{ + OUString sName, sValue; + bool bFoundValue = false; // to allow empty values + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_VALUE): + { + sValue = aIter.toString(); + bFoundValue = true; + break; + } + case XML_ELEMENT(DRAW, XML_NAME): + sName = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + if (!sName.isEmpty() && bFoundValue ) + rParamMap[sName] = sValue; +} + +namespace { + +class XMLTextFrameContourContext_Impl : public SvXMLImportContext +{ + Reference < XPropertySet > xPropSet; + +public: + + + XMLTextFrameContourContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + const Reference < XPropertySet >& rPropSet, + bool bPath ); +}; + +} + +XMLTextFrameContourContext_Impl::XMLTextFrameContourContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & xAttrList, + const Reference < XPropertySet >& rPropSet, + bool bPath ) : + SvXMLImportContext( rImport ), + xPropSet( rPropSet ) +{ + OUString sD, sPoints, sViewBox; + bool bPixelWidth = false, bPixelHeight = false; + bool bAuto = false; + sal_Int32 nWidth = 0; + sal_Int32 nHeight = 0; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + sViewBox = aIter.toString(); + break; + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + if( bPath ) + sD = aIter.toString(); + break; + case XML_ELEMENT(DRAW,XML_POINTS): + if( !bPath ) + sPoints = aIter.toString(); + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + if (::sax::Converter::convertMeasurePx(nWidth, aIter.toView())) + bPixelWidth = true; + else + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nWidth, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + if (::sax::Converter::convertMeasurePx(nHeight, aIter.toView())) + bPixelHeight = true; + else + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nHeight, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_RECREATE_ON_EDIT): + bAuto = IsXMLToken(aIter, XML_TRUE); + break; + } + } + + OUString sContourPolyPolygon("ContourPolyPolygon"); + Reference < XPropertySetInfo > xPropSetInfo = rPropSet->getPropertySetInfo(); + + if(!xPropSetInfo->hasPropertyByName(sContourPolyPolygon) || + nWidth <= 0 || nHeight <= 0 || bPixelWidth != bPixelHeight || + !(bPath ? sD : sPoints).getLength()) + return; + + const SdXMLImExViewBox aViewBox( sViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DPolyPolygon aPolyPolygon; + + if( bPath ) + { + basegfx::utils::importFromSvgD(aPolyPolygon, sD, GetImport().needFixPositionAfterZ(), nullptr); + } + else + { + basegfx::B2DPolygon aPolygon; + + if(basegfx::utils::importFromSvgPoints(aPolygon, sPoints)) + { + aPolyPolygon = basegfx::B2DPolyPolygon(aPolygon); + } + } + + if(aPolyPolygon.count()) + { + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + 0.0, 0.0, + nWidth, nHeight); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolyPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + css::drawing::PointSequenceSequence aPointSequenceSequence; + basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence(aPolyPolygon, aPointSequenceSequence); + xPropSet->setPropertyValue( sContourPolyPolygon, Any(aPointSequenceSequence) ); + } + + static const OUStringLiteral sIsPixelContour(u"IsPixelContour"); + + if( xPropSetInfo->hasPropertyByName( sIsPixelContour ) ) + { + xPropSet->setPropertyValue( sIsPixelContour, Any(bPixelWidth) ); + } + + static const OUStringLiteral sIsAutomaticContour(u"IsAutomaticContour"); + + if( xPropSetInfo->hasPropertyByName( sIsAutomaticContour ) ) + { + xPropSet->setPropertyValue( sIsAutomaticContour, Any(bAuto) ); + } +} + +namespace { + +class XMLTextFrameContext_Impl : public SvXMLImportContext +{ + css::uno::Reference < css::text::XTextCursor > xOldTextCursor; + css::uno::Reference < css::beans::XPropertySet > xPropSet; + css::uno::Reference < css::io::XOutputStream > xBase64Stream; + + /// old list item and block (#89891#) + bool mbListContextPushed; + + OUString m_sOrigName; + OUString sName; + OUString sStyleName; + OUString sNextName; + OUString sHRef; + OUString sCode; + OUString sMimeType; + OUString sFrameName; + OUString sAppletName; + OUString sFilterService; + OUString sBase64CharsLeft; + OUString sTblName; + OUStringBuffer maUrlBuffer; + + ParamMap aParamMap; + + sal_Int32 nX; + sal_Int32 nY; + sal_Int32 nWidth; + sal_Int32 nHeight; + sal_Int32 nZIndex; + sal_Int16 nPage; + sal_Int16 nRotation; + sal_Int16 nRelWidth; + sal_Int16 nRelHeight; + + sal_uInt16 nType; + css::text::TextContentAnchorType eAnchorType; + + bool bMayScript : 1; + bool bMinWidth : 1; + bool bMinHeight : 1; + bool bSyncWidth : 1; + bool bSyncHeight : 1; + bool bCreateFailed : 1; + bool bOwnBase64Stream : 1; + bool mbMultipleContent : 1; // This context is created based on a multiple content (image) + + void Create(); + +public: + + + bool CreateIfNotThere(); + const OUString& GetHRef() const { return sHRef; } + + XMLTextFrameContext_Impl( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference & rAttrList, + css::text::TextContentAnchorType eAnchorType, + sal_uInt16 nType, + const css::uno::Reference & rFrameAttrList, + bool bMultipleContent = false ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + void SetHyperlink( const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + bool bMap ); + + // Implement Title/Description Elements UI (#i73249#) + void SetTitle( const OUString& rTitle ); + + void SetDesc( const OUString& rDesc ); + + void SetName(); + + const OUString& GetOrigName() const { return m_sOrigName; } + + css::text::TextContentAnchorType GetAnchorType() const { return eAnchorType; } + + const css::uno::Reference < css::beans::XPropertySet >& GetPropSet() const { return xPropSet; } +}; + +} + +void XMLTextFrameContext_Impl::Create() +{ + rtl::Reference < XMLTextImportHelper > xTextImportHelper = + GetImport().GetTextImport(); + + switch ( nType) + { + case XML_TEXT_FRAME_OBJECT: + case XML_TEXT_FRAME_OBJECT_OLE: + if( xBase64Stream.is() ) + { + OUString sURL( GetImport().ResolveEmbeddedObjectURLFromBase64() ); + if( !sURL.isEmpty() ) + xPropSet = GetImport().GetTextImport() + ->createAndInsertOLEObject( GetImport(), sURL, + sStyleName, + sTblName, + nWidth, nHeight ); + } + else if( !sHRef.isEmpty() ) + { + OUString sURL( GetImport().ResolveEmbeddedObjectURL( sHRef, + std::u16string_view() ) ); + + if( GetImport().IsPackageURL( sHRef ) ) + { + xPropSet = GetImport().GetTextImport() + ->createAndInsertOLEObject( GetImport(), sURL, + sStyleName, + sTblName, + nWidth, nHeight ); + } + else + { + // it should be an own OOo link that has no storage persistence + xPropSet = GetImport().GetTextImport() + ->createAndInsertOOoLink( GetImport(), + sURL, + sStyleName, + sTblName, + nWidth, nHeight ); + } + } + else + { + OUString sURL = "vnd.sun.star.ServiceName:" + sFilterService; + xPropSet = GetImport().GetTextImport() + ->createAndInsertOLEObject( GetImport(), sURL, + sStyleName, + sTblName, + nWidth, nHeight ); + + } + break; + case XML_TEXT_FRAME_APPLET: + { + xPropSet = GetImport().GetTextImport() + ->createAndInsertApplet( sAppletName, sCode, + bMayScript, sHRef, + nWidth, nHeight); + break; + } + case XML_TEXT_FRAME_PLUGIN: + { + if(!sHRef.isEmpty()) + GetImport().GetAbsoluteReference(sHRef); + xPropSet = GetImport().GetTextImport() + ->createAndInsertPlugin( sMimeType, sHRef, + nWidth, nHeight); + + break; + } + case XML_TEXT_FRAME_FLOATING_FRAME: + { + xPropSet = GetImport().GetTextImport() + ->createAndInsertFloatingFrame( sFrameName, sHRef, + sStyleName, + nWidth, nHeight); + break; + } + default: + { + Reference xFactory( GetImport().GetModel(), + UNO_QUERY ); + if( xFactory.is() ) + { + OUString sServiceName; + switch( nType ) + { + case XML_TEXT_FRAME_TEXTBOX: sServiceName = "com.sun.star.text.TextFrame"; break; + case XML_TEXT_FRAME_GRAPHIC: sServiceName = "com.sun.star.text.GraphicObject"; break; + } + Reference xIfc = xFactory->createInstance( sServiceName ); + SAL_WARN_IF( !xIfc.is(), "xmloff.text", "couldn't create frame" ); + if( xIfc.is() ) + xPropSet.set( xIfc, UNO_QUERY ); + } + } + } + + if( !xPropSet.is() ) + { + bCreateFailed = true; + return; + } + + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + + // Skip duplicated frames + if(!mbMultipleContent && // It's allowed to have multiple image for the same frame + !sName.isEmpty() && + xTextImportHelper->IsDuplicateFrame(sName, nX, nY, nWidth, nHeight)) + { + bCreateFailed = true; + return; + } + + // set name + Reference < XNamed > xNamed( xPropSet, UNO_QUERY ); + if( xNamed.is() ) + { + OUString sOrigName( xNamed->getName() ); + if( sOrigName.isEmpty() || + (!sName.isEmpty() && sOrigName != sName) ) + { + OUString sOldName( sName ); + + sal_Int32 i = 0; + while( xTextImportHelper->HasFrameByName( sName ) ) + { + sName = sOldName + OUString::number( ++i ); + } + xNamed->setName( sName ); + if( sName != sOldName ) + { + xTextImportHelper->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_FRAME, + sOldName, sName ); + + } + } + } + + // frame style + XMLPropStyleContext *pStyle = nullptr; + if( !sStyleName.isEmpty() ) + { + pStyle = xTextImportHelper->FindAutoFrameStyle( sStyleName ); + if( pStyle ) + sStyleName = pStyle->GetParentName(); + } + + Any aAny; + if( !sStyleName.isEmpty() ) + { + OUString sDisplayStyleName( GetImport().GetStyleDisplayName( + XmlStyleFamily::SD_GRAPHICS_ID, sStyleName ) ); + const Reference < XNameContainer > & rStyles = + xTextImportHelper->GetFrameStyles(); + if( rStyles.is() && + rStyles->hasByName( sDisplayStyleName ) ) + { + xPropSet->setPropertyValue( "FrameStyleName", Any(sDisplayStyleName) ); + } + } + + // anchor type (must be set before any other properties, because + // otherwise some orientations cannot be set or will be changed + // afterwards) + xPropSet->setPropertyValue( "AnchorType", Any(eAnchorType) ); + + // hard properties + if( pStyle ) + pStyle->FillPropertySet( xPropSet ); + + // x and y + sal_Int16 nHoriOrient = HoriOrientation::NONE; + aAny = xPropSet->getPropertyValue( "HoriOrient" ); + aAny >>= nHoriOrient; + if( HoriOrientation::NONE == nHoriOrient ) + { + xPropSet->setPropertyValue( "HoriOrientPosition", Any(nX) ); + } + + sal_Int16 nVertOrient = VertOrientation::NONE; + aAny = xPropSet->getPropertyValue( "VertOrient" ); + aAny >>= nVertOrient; + if( VertOrientation::NONE == nVertOrient ) + { + xPropSet->setPropertyValue( "VertOrientPosition", Any(nY) ); + } + + // width + if( nWidth > 0 ) + { + xPropSet->setPropertyValue( "Width", Any(nWidth) ); + } + if( nRelWidth > 0 || nWidth > 0 ) + { + xPropSet->setPropertyValue( "RelativeWidth", Any(nRelWidth) ); + } + if( bSyncWidth || nWidth > 0 ) + { + xPropSet->setPropertyValue( "IsSyncWidthToHeight", Any(bSyncWidth) ); + } + if( xPropSetInfo->hasPropertyByName( "WidthType" ) && + (bMinWidth || nWidth > 0 || nRelWidth > 0 ) ) + { + sal_Int16 nSizeType = + (bMinWidth && XML_TEXT_FRAME_TEXTBOX == nType) ? SizeType::MIN + : SizeType::FIX; + xPropSet->setPropertyValue( "WidthType", Any(nSizeType) ); + } + + if( nHeight > 0 ) + { + xPropSet->setPropertyValue( "Height", Any(nHeight) ); + } + if( nRelHeight > 0 || nHeight > 0 ) + { + xPropSet->setPropertyValue( "RelativeHeight", Any(nRelHeight) ); + } + if( bSyncHeight || nHeight > 0 ) + { + xPropSet->setPropertyValue( "IsSyncHeightToWidth", Any(bSyncHeight) ); + } + if( xPropSetInfo->hasPropertyByName( "SizeType" ) && + (bMinHeight || nHeight > 0 || nRelHeight > 0 ) ) + { + sal_Int16 nSizeType = + (bMinHeight && XML_TEXT_FRAME_TEXTBOX == nType) ? SizeType::MIN + : SizeType::FIX; + xPropSet->setPropertyValue( "SizeType", Any(nSizeType) ); + } + + if( XML_TEXT_FRAME_GRAPHIC == nType ) + { + // URL + OSL_ENSURE( !sHRef.isEmpty() || xBase64Stream.is(), + "neither URL nor base64 image data given" ); + uno::Reference xGraphic; + if (!sHRef.isEmpty()) + { + xGraphic = GetImport().loadGraphicByURL(sHRef); + } + else if (xBase64Stream.is()) + { + xGraphic = GetImport().loadGraphicFromBase64(xBase64Stream); + xBase64Stream = nullptr; + } + + if (xGraphic.is()) + xPropSet->setPropertyValue("Graphic", Any(xGraphic)); + + // filter name + xPropSet->setPropertyValue( "GraphicFilter", Any(OUString()) ); + + // rotation + xPropSet->setPropertyValue( "GraphicRotation", Any(nRotation) ); + } + + // page number (must be set after the frame is inserted, because it + // will be overwritten then inserting the frame. + if( TextContentAnchorType_AT_PAGE == eAnchorType && nPage > 0 ) + { + xPropSet->setPropertyValue( "AnchorPageNo", Any(nPage) ); + } + + if( XML_TEXT_FRAME_OBJECT != nType && + XML_TEXT_FRAME_OBJECT_OLE != nType && + XML_TEXT_FRAME_APPLET != nType && + XML_TEXT_FRAME_PLUGIN!= nType && + XML_TEXT_FRAME_FLOATING_FRAME != nType) + { + Reference < XTextContent > xTxtCntnt( xPropSet, UNO_QUERY ); + try + { + xTextImportHelper->InsertTextContent(xTxtCntnt); + } + catch (lang::IllegalArgumentException const&) + { + TOOLS_WARN_EXCEPTION("xmloff.text", "Cannot import part of the text - probably an image in the text frame?"); + return; + } + } + + // Make adding the shape to Z-Ordering dependent from if we are + // inside an inside_deleted_section (redlining). That is necessary + // since the shape will be removed again later. It would lead to + // errors if it would stay inside the Z-Ordering. Thus, the + // easiest way to solve that conflict is to not add it here. + if(!GetImport().HasTextImport() + || !GetImport().GetTextImport()->IsInsideDeleteContext()) + { + Reference < XShape > xShape( xPropSet, UNO_QUERY ); + + GetImport().GetShapeImport()->shapeWithZIndexAdded( xShape, nZIndex ); + } + + if( XML_TEXT_FRAME_TEXTBOX != nType ) + return; + + xTextImportHelper->ConnectFrameChains( sName, sNextName, xPropSet ); + Reference < XTextFrame > xTxtFrame( xPropSet, UNO_QUERY ); + Reference < XText > xTxt = xTxtFrame->getText(); + xOldTextCursor = xTextImportHelper->GetCursor(); + xTextImportHelper->SetCursor( xTxt->createTextCursor() ); + + // remember old list item and block (#89892#) and reset them + // for the text frame + xTextImportHelper->PushListContext(); + mbListContextPushed = true; +} + +void XMLTextFrameContext::removeGraphicFromImportContext(const SvXMLImportContext& rContext) +{ + const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast< const XMLTextFrameContext_Impl* >(&rContext); + + if(!pXMLTextFrameContext_Impl) + return; + + try + { + // just dispose to delete + uno::Reference< lang::XComponent > xComp(pXMLTextFrameContext_Impl->GetPropSet(), UNO_QUERY); + + // Inform shape importer about the removal so it can adjust + // z-indexes. + uno::Reference xShape(xComp, uno::UNO_QUERY); + GetImport().GetShapeImport()->shapeRemoved(xShape); + + if(xComp.is()) + { + xComp->dispose(); + } + } + catch( uno::Exception& ) + { + OSL_FAIL( "Error in cleanup of multiple graphic object import (!)" ); + } +} + +OUString XMLTextFrameContext::getGraphicPackageURLFromImportContext(const SvXMLImportContext& rContext) const +{ + const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast< const XMLTextFrameContext_Impl* >(&rContext); + + if(pXMLTextFrameContext_Impl) + { + return "vnd.sun.star.Package:" + pXMLTextFrameContext_Impl->GetHRef(); + } + + return OUString(); +} + +css::uno::Reference XMLTextFrameContext::getGraphicFromImportContext(const SvXMLImportContext& rContext) const +{ + uno::Reference xGraphic; + + const XMLTextFrameContext_Impl* pXMLTextFrameContext_Impl = dynamic_cast(&rContext); + + if (pXMLTextFrameContext_Impl) + { + try + { + const uno::Reference& xPropertySet = pXMLTextFrameContext_Impl->GetPropSet(); + + if (xPropertySet.is()) + { + xPropertySet->getPropertyValue("Graphic") >>= xGraphic; + } + } + catch (uno::Exception&) + {} + } + return xGraphic; +} + +bool XMLTextFrameContext_Impl::CreateIfNotThere() +{ + if( !xPropSet.is() && + ( XML_TEXT_FRAME_OBJECT_OLE == nType || + XML_TEXT_FRAME_GRAPHIC == nType ) && + xBase64Stream.is() && !bCreateFailed ) + { + if( bOwnBase64Stream ) + xBase64Stream->closeOutput(); + Create(); + } + + return xPropSet.is(); +} + +XMLTextFrameContext_Impl::XMLTextFrameContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & rAttrList, + TextContentAnchorType eATyp, + sal_uInt16 nNewType, + const Reference< XFastAttributeList > & rFrameAttrList, + bool bMultipleContent ) +: SvXMLImportContext( rImport ) +, mbListContextPushed( false ) +, nType( nNewType ) +, eAnchorType( eATyp ) +{ + nX = 0; + nY = 0; + nWidth = 0; + nHeight = 0; + nZIndex = -1; + nPage = 0; + nRotation = 0; + nRelWidth = 0; + nRelHeight = 0; + bMayScript = false; + + bMinHeight = false; + bMinWidth = false; + bSyncWidth = false; + bSyncHeight = false; + bCreateFailed = false; + bOwnBase64Stream = false; + mbMultipleContent = bMultipleContent; + + auto processAttr = [&](sal_Int32 nElement, const sax_fastparser::FastAttributeList::FastAttributeIter& aIter) -> void + { + switch( nElement ) + { + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_NAME): + m_sOrigName = aIter.toString(); + sName = m_sOrigName; + break; + case XML_ELEMENT(DRAW, XML_FRAME_NAME): + sFrameName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_APPLET_NAME): + sAppletName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_ANCHOR_TYPE): + if( TextContentAnchorType_AT_PARAGRAPH == eAnchorType || + TextContentAnchorType_AT_CHARACTER == eAnchorType || + TextContentAnchorType_AS_CHARACTER == eAnchorType ) + { + + TextContentAnchorType eNew; + if( XMLAnchorTypePropHdl::convert( aIter.toView(), eNew ) && + ( TextContentAnchorType_AT_PARAGRAPH == eNew || + TextContentAnchorType_AT_CHARACTER == eNew || + TextContentAnchorType_AS_CHARACTER == eNew || + TextContentAnchorType_AT_PAGE == eNew) ) + eAnchorType = eNew; + } + break; + case XML_ELEMENT(TEXT, XML_ANCHOR_PAGE_NUMBER): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView(), 1, SHRT_MAX)) + nPage = static_cast(nTmp); + } + break; + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nX, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nY, aIter.toView() ); + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + // relative widths are obsolete since SRC617. Remove them some day! + if( aIter.toView().find( '%' ) != std::string_view::npos ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nRelWidth = static_cast(nTmp); + } + else + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nWidth, aIter.toView(), 0 ); + } + break; + case XML_ELEMENT(STYLE, XML_REL_WIDTH): + if( IsXMLToken(aIter, XML_SCALE) ) + { + bSyncWidth = true; + } + else + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent( nTmp, aIter.toView() )) + nRelWidth = static_cast(nTmp); + } + break; + case XML_ELEMENT(FO, XML_MIN_WIDTH): + case XML_ELEMENT(FO_COMPAT, XML_MIN_WIDTH): + if( aIter.toView().find( '%' ) != std::string_view::npos ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nRelWidth = static_cast(nTmp); + } + else + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nWidth, aIter.toView(), 0 ); + } + bMinWidth = true; + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + // relative heights are obsolete since SRC617. Remove them some day! + if( aIter.toView().find( '%' ) != std::string_view::npos ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nRelHeight = static_cast(nTmp); + } + else + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nHeight, aIter.toView(), 0 ); + } + break; + case XML_ELEMENT(STYLE, XML_REL_HEIGHT): + if( IsXMLToken( aIter, XML_SCALE ) ) + { + bSyncHeight = true; + } + else if( IsXMLToken( aIter, XML_SCALE_MIN ) ) + { + bSyncHeight = true; + bMinHeight = true; + } + else + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent( nTmp, aIter.toView() )) + nRelHeight = static_cast(nTmp); + } + break; + case XML_ELEMENT(FO, XML_MIN_HEIGHT): + case XML_ELEMENT(FO_COMPAT, XML_MIN_HEIGHT): + if( aIter.toView().find( '%' ) != std::string_view::npos ) + { + sal_Int32 nTmp; + if (::sax::Converter::convertPercent(nTmp, aIter.toView())) + nRelHeight = static_cast(nTmp); + } + else + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + nHeight, aIter.toView(), 0 ); + } + bMinHeight = true; + break; + case XML_ELEMENT(DRAW, XML_ZINDEX): + ::sax::Converter::convertNumber( nZIndex, aIter.toView(), -1 ); + break; + case XML_ELEMENT(DRAW, XML_CHAIN_NEXT_NAME): + sNextName = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + sHRef = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_TRANSFORM): + { + // RotateFlyFrameFix: im/export full 'draw:transform' using existing tooling + // Currently only rotation is used, but combinations with 'draw:transform' + // may be necessary in the future, so that svg:x/svg:y/svg:width/svg:height + // may be extended/replaced with 'draw:transform' (see draw objects) + SdXMLImExTransform2D aSdXMLImExTransform2D; + basegfx::B2DHomMatrix aFullTransform; + + // Use SdXMLImExTransform2D to convert to transformation + // Note: using GetTwipUnitConverter instead of GetMM100UnitConverter may be needed, + // but is not generally available (as it should be, a 'current' UnitConverter should + // be available at GetExport() - and maybe was once). May have to be addressed as soon + // as translate transformations are used here. + aSdXMLImExTransform2D.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + aSdXMLImExTransform2D.GetFullTransform(aFullTransform); + + if(!aFullTransform.isIdentity()) + { + const basegfx::utils::B2DHomMatrixBufferedDecompose aDecomposedTransform(aFullTransform); + + // currently we *only* use rotation (and translation indirectly), so warn if *any* + // of the other transform parts is used + SAL_WARN_IF(!basegfx::fTools::equal(1.0, aDecomposedTransform.getScale().getX()), "xmloff.text", "draw:transform uses scaleX" ); + SAL_WARN_IF(!basegfx::fTools::equal(1.0, aDecomposedTransform.getScale().getY()), "xmloff.text", "draw:transform uses scaleY" ); + SAL_WARN_IF(!basegfx::fTools::equalZero(aDecomposedTransform.getShearX()), "xmloff.text", "draw:transform uses shearX" ); + + // Translation comes from the translate to RotCenter, rot and BackTranslate. + // This means that it represents the translation between unrotated TopLeft + // and rotated TopLeft. This may be checked here now, but currently we only + // use rotation around center and assume that this *was* a rotation around + // center. The check would compare the object's center with the RotCenter + // that can be extracted from the transformation in aFullTransform. + // The definition contains implicitly the RotationCenter absolute + // to the scaled and translated object, so this may be used if needed (see + // _exportTextGraphic how the -trans/rot/trans is composed) + + if(!basegfx::fTools::equalZero(aDecomposedTransform.getRotate())) + { + // rotation is used, set it. Convert from deg to 10th degree integer + // CAUTION: due to #i78696# (rotation mirrored using API) the rotate + // value is already mirrored, so do not do it again here (to be in sync + // with XMLTextParagraphExport::_exportTextGraphic normally it would need + // to me mirrored using * -1.0, see conversion there) + // CAUTION-II: due to tdf#115782 it is better for current ODF to indeed use it + // with the wrong orientation as in all other cases - ARGH! We will need to + // correct this in future ODF ASAP! For now, mirror the rotation here AGAIN + const double fRotate(-basegfx::rad2deg<10>(aDecomposedTransform.getRotate())); + nRotation = static_cast< sal_Int16 >(basegfx::fround(fRotate) % 3600); + + // tdf#115529 may be negative, with the above modulo maximal -3599, so + // no loop needed here. nRotation is used in setPropertyValue("GraphicRotation") + // and *has* to be in the range [0 .. 3600[ + if(nRotation < 0) + { + nRotation += 3600; + } + } + } + } + break; + case XML_ELEMENT(DRAW, XML_CODE): + sCode = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_OBJECT): + break; + case XML_ELEMENT(DRAW, XML_ARCHIVE): + break; + case XML_ELEMENT(DRAW, XML_MAY_SCRIPT): + bMayScript = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(DRAW, XML_MIME_TYPE): + case XML_ELEMENT(LO_EXT, XML_MIME_TYPE): + sMimeType = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_NOTIFY_ON_UPDATE_OF_RANGES): + case XML_ELEMENT(DRAW, XML_NOTIFY_ON_UPDATE_OF_TABLE): + sTblName = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + }; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(rAttrList) ) + processAttr(aIter.getToken(), aIter); + for( auto& aIter : sax_fastparser::castToFastAttributeList(rFrameAttrList) ) + processAttr(aIter.getToken(), aIter); + + if( ( (XML_TEXT_FRAME_GRAPHIC == nType || + XML_TEXT_FRAME_OBJECT == nType || + XML_TEXT_FRAME_OBJECT_OLE == nType) && + sHRef.isEmpty() ) || + ( XML_TEXT_FRAME_APPLET == nType && sCode.isEmpty() ) || + ( XML_TEXT_FRAME_PLUGIN == nType && + sHRef.isEmpty() && sMimeType.isEmpty() ) ) + return; // no URL: no image or OLE object + + Create(); +} + +void XMLTextFrameContext_Impl::endFastElement(sal_Int32 ) +{ + if( ( XML_TEXT_FRAME_OBJECT_OLE == nType || + XML_TEXT_FRAME_GRAPHIC == nType) && + !xPropSet.is() && !bCreateFailed ) + { + std::u16string_view sTrimmedChars = o3tl::trim(maUrlBuffer); + if( !sTrimmedChars.empty() ) + { + if( !xBase64Stream.is() ) + { + if( XML_TEXT_FRAME_GRAPHIC == nType ) + { + xBase64Stream = + GetImport().GetStreamForGraphicObjectURLFromBase64(); + } + else + { + xBase64Stream = + GetImport().GetStreamForEmbeddedObjectURLFromBase64(); + } + if( xBase64Stream.is() ) + bOwnBase64Stream = true; + } + if( bOwnBase64Stream && xBase64Stream.is() ) + { + OUString sChars; + if( !sBase64CharsLeft.isEmpty() ) + { + sChars = sBase64CharsLeft + sTrimmedChars; + sBase64CharsLeft.clear(); + } + else + { + sChars = sTrimmedChars; + } + Sequence< sal_Int8 > aBuffer( (sChars.getLength() / 4) * 3 ); + sal_Int32 nCharsDecoded = + ::comphelper::Base64::decodeSomeChars( aBuffer, sChars ); + xBase64Stream->writeBytes( aBuffer ); + if( nCharsDecoded != sChars.getLength() ) + sBase64CharsLeft = sChars.copy( nCharsDecoded ); + } + } + maUrlBuffer.setLength(0); + } + + CreateIfNotThere(); + + if( xOldTextCursor.is() ) + { + GetImport().GetTextImport()->DeleteParagraph(); + GetImport().GetTextImport()->SetCursor( xOldTextCursor ); + } + + // reinstall old list item (if necessary) #89892# + if (mbListContextPushed) { + GetImport().GetTextImport()->PopListContext(); + } + + if (( nType == XML_TEXT_FRAME_APPLET || nType == XML_TEXT_FRAME_PLUGIN ) && xPropSet.is()) + GetImport().GetTextImport()->endAppletOrPlugin( xPropSet, aParamMap); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextFrameContext_Impl::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_PARAM) ) + { + if ( nType == XML_TEXT_FRAME_APPLET || nType == XML_TEXT_FRAME_PLUGIN ) + return new XMLTextFrameParam_Impl( GetImport(), + xAttrList, aParamMap ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) ) + { + if( !xPropSet.is() && !xBase64Stream.is() && !bCreateFailed ) + { + switch( nType ) + { + case XML_TEXT_FRAME_GRAPHIC: + xBase64Stream = + GetImport().GetStreamForGraphicObjectURLFromBase64(); + break; + case XML_TEXT_FRAME_OBJECT_OLE: + xBase64Stream = + GetImport().GetStreamForEmbeddedObjectURLFromBase64(); + break; + } + if( xBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), xBase64Stream ); + } + } + // Correction of condition which also avoids warnings. (#i100480#) + if( XML_TEXT_FRAME_OBJECT == nType && + ( nElement == XML_ELEMENT(OFFICE, XML_DOCUMENT) || + nElement == XML_ELEMENT(MATH, XML_MATH) ) ) + { + if( !xPropSet.is() && !bCreateFailed ) + { + XMLEmbeddedObjectImportContext *pEContext = + new XMLEmbeddedObjectImportContext( GetImport(), nElement, xAttrList ); + sFilterService = pEContext->GetFilterServiceName(); + if( !sFilterService.isEmpty() ) + { + Create(); + if( xPropSet.is() ) + { + Reference < XEmbeddedObjectSupplier > xEOS( xPropSet, + UNO_QUERY ); + OSL_ENSURE( xEOS.is(), + "no embedded object supplier for own object" ); + Reference aXComponent(xEOS->getEmbeddedObject()); + pEContext->SetComponent( aXComponent ); + } + } + return pEContext; + } + } + + if( xOldTextCursor.is() ) // text-box + { + auto p = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, + XMLTextType::TextBox ); + if (p) + return p; + } + + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +void XMLTextFrameContext_Impl::characters( const OUString& rChars ) +{ + maUrlBuffer.append(rChars); +} + +void XMLTextFrameContext_Impl::SetHyperlink( const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + bool bMap ) +{ + static constexpr OUStringLiteral s_HyperLinkURL = u"HyperLinkURL"; + static constexpr OUStringLiteral s_HyperLinkName = u"HyperLinkName"; + static constexpr OUStringLiteral s_HyperLinkTarget = u"HyperLinkTarget"; + static constexpr OUStringLiteral s_ServerMap = u"ServerMap"; + if( !xPropSet.is() ) + return; + + Reference < XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( !xPropSetInfo.is() || + !xPropSetInfo->hasPropertyByName(s_HyperLinkURL)) + return; + + xPropSet->setPropertyValue( s_HyperLinkURL, Any(rHRef) ); + + if (xPropSetInfo->hasPropertyByName(s_HyperLinkName)) + { + xPropSet->setPropertyValue(s_HyperLinkName, Any(rName)); + } + + if (xPropSetInfo->hasPropertyByName(s_HyperLinkTarget)) + { + xPropSet->setPropertyValue( s_HyperLinkTarget, Any(rTargetFrameName) ); + } + + if (xPropSetInfo->hasPropertyByName(s_ServerMap)) + { + xPropSet->setPropertyValue(s_ServerMap, Any(bMap)); + } +} + +void XMLTextFrameContext_Impl::SetName() +{ + Reference xNamed(xPropSet, UNO_QUERY); + if (m_sOrigName.isEmpty() || !xNamed.is()) + return; + + OUString const name(xNamed->getName()); + if (name != m_sOrigName) + { + try + { + xNamed->setName(m_sOrigName); + } + catch (uno::Exception const&) + { // fdo#71698 document contains 2 frames with same draw:name + TOOLS_INFO_EXCEPTION("xmloff.text", "SetName(): exception setting \"" + << m_sOrigName << "\""); + } + } +} + +// Implement Title/Description Elements UI (#i73249#) +void XMLTextFrameContext_Impl::SetTitle( const OUString& rTitle ) +{ + if ( xPropSet.is() ) + { + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( "Title" ) ) + { + xPropSet->setPropertyValue( "Title", Any( rTitle ) ); + } + } +} + +void XMLTextFrameContext_Impl::SetDesc( const OUString& rDesc ) +{ + if ( xPropSet.is() ) + { + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( "Description" ) ) + { + xPropSet->setPropertyValue( "Description", Any( rDesc ) ); + } + } +} + + +bool XMLTextFrameContext::CreateIfNotThere( css::uno::Reference < css::beans::XPropertySet >& rPropSet ) +{ + SvXMLImportContext *pContext = m_xImplContext.get(); + XMLTextFrameContext_Impl *pImpl = dynamic_cast< XMLTextFrameContext_Impl*>( pContext ); + if( pImpl && pImpl->CreateIfNotThere() ) + rPropSet = pImpl->GetPropSet(); + + return rPropSet.is(); +} + +XMLTextFrameContext::XMLTextFrameContext( + SvXMLImport& rImport, + const Reference< XFastAttributeList > & xAttrList, + TextContentAnchorType eATyp ) +: SvXMLImportContext( rImport ) +, m_xAttrList( new sax_fastparser::FastAttributeList( xAttrList ) ) + // Implement Title/Description Elements UI (#i73249#) +, m_eDefaultAnchorType( eATyp ) + // Shapes in Writer cannot be named via context menu (#i51726#) +, m_HasAutomaticStyleWithoutParentStyle( false ) +, m_bSupportsReplacement( false ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + // New distinguish attribute between Writer objects and Draw objects is: + // Draw objects have an automatic style without a parent style (#i51726#) + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + { + OUString aStyleName = aIter.toString(); + if( !aStyleName.isEmpty() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport = + GetImport().GetTextImport(); + XMLPropStyleContext* pStyle = xTxtImport->FindAutoFrameStyle( aStyleName ); + if ( pStyle && pStyle->GetParentName().isEmpty() ) + { + m_HasAutomaticStyleWithoutParentStyle = true; + } + } + break; + } + case XML_ELEMENT(TEXT, XML_ANCHOR_TYPE): + { + TextContentAnchorType eNew; + if( XMLAnchorTypePropHdl::convert( aIter.toView(), eNew ) && + ( TextContentAnchorType_AT_PARAGRAPH == eNew || + TextContentAnchorType_AT_CHARACTER == eNew || + TextContentAnchorType_AS_CHARACTER == eNew || + TextContentAnchorType_AT_PAGE == eNew) ) + m_eDefaultAnchorType = eNew; + break; + } + } + } +} + +void XMLTextFrameContext::endFastElement(sal_Int32 ) +{ + /// solve if multiple image child contexts were imported + SvXMLImportContextRef const pMultiContext(solveMultipleImages()); + + SvXMLImportContext const*const pContext = + (pMultiContext.is()) ? pMultiContext.get() : m_xImplContext.get(); + XMLTextFrameContext_Impl *pImpl = const_cast(dynamic_cast< const XMLTextFrameContext_Impl*>( pContext )); + assert(!pMultiContext.is() || pImpl); + + // When we are dealing with a textbox, pImpl will be null; + // we need to set the hyperlink to the shape instead + Reference xShape = GetShape(); + if (xShape.is() && m_pHyperlink) + { + Reference xProps(xShape, UNO_QUERY); + if (xProps.is()) + xProps->setPropertyValue("Hyperlink", Any(m_pHyperlink->GetHRef())); + } + + if( !pImpl ) + return; + + pImpl->CreateIfNotThere(); + + // fdo#68839: in case the surviving image was not the first one, + // it will have a counter added to its name - set the original name + if (pMultiContext.is()) // do this only when necessary; esp. not for text + { // frames that may have entries in GetRenameMap()! + pImpl->SetName(); + } + + if( !m_sTitle.isEmpty() ) + { + pImpl->SetTitle( m_sTitle ); + } + if( !m_sDesc.isEmpty() ) + { + pImpl->SetDesc( m_sDesc ); + } + + if( m_pHyperlink ) + { + pImpl->SetHyperlink( m_pHyperlink->GetHRef(), m_pHyperlink->GetName(), + m_pHyperlink->GetTargetFrameName(), m_pHyperlink->GetMap() ); + m_pHyperlink.reset(); + } + + GetImport().GetTextImport()->StoreLastImportedFrameName(pImpl->GetOrigName()); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextFrameContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + SvXMLImportContextRef xContext; + + if( !m_xImplContext.is() ) + { + // no child exists + if( IsTokenInNamespace(nElement, XML_NAMESPACE_DRAW) ) + { + sal_uInt16 nFrameType = USHRT_MAX; + switch (nElement & TOKEN_MASK) + { + case XML_TEXT_BOX: + nFrameType = XML_TEXT_FRAME_TEXTBOX; + break; + case XML_IMAGE: + nFrameType = XML_TEXT_FRAME_GRAPHIC; + break; + case XML_OBJECT: + nFrameType = XML_TEXT_FRAME_OBJECT; + break; + case XML_OBJECT_OLE: + nFrameType = XML_TEXT_FRAME_OBJECT_OLE; + break; + case XML_APPLET: + nFrameType = XML_TEXT_FRAME_APPLET; + break; + case XML_PLUGIN: + nFrameType = XML_TEXT_FRAME_PLUGIN; + break; + case XML_FLOATING_FRAME: + nFrameType = XML_TEXT_FRAME_FLOATING_FRAME; + break; + } + + if( USHRT_MAX != nFrameType ) + { + // Shapes in Writer cannot be named via context menu (#i51726#) + if ( ( XML_TEXT_FRAME_TEXTBOX == nFrameType || + XML_TEXT_FRAME_GRAPHIC == nFrameType ) && + m_HasAutomaticStyleWithoutParentStyle ) + { + Reference < XShapes > xShapes; + xContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, xShapes, m_xAttrList ); + } + else if( XML_TEXT_FRAME_PLUGIN == nFrameType ) + { + bool bMedia = false; + + // check, if we have a media object + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_MIME_TYPE) ) + { + if( aIter.toView() == "application/vnd.sun.star.media" ) + bMedia = true; + + // leave this loop + break; + } + } + + if( bMedia ) + { + Reference < XShapes > xShapes; + xContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, xShapes, m_xAttrList ); + } + } + else if( XML_TEXT_FRAME_OBJECT == nFrameType || + XML_TEXT_FRAME_OBJECT_OLE == nFrameType ) + { + m_bSupportsReplacement = true; + } + else if(XML_TEXT_FRAME_GRAPHIC == nFrameType) + { + setSupportsMultipleContents( (nElement & TOKEN_MASK) == XML_IMAGE ); + } + + if (!xContext) + { + xContext = new XMLTextFrameContext_Impl( GetImport(), nElement, + xAttrList, + m_eDefaultAnchorType, + nFrameType, + m_xAttrList ); + } + + m_xImplContext = xContext; + + if(getSupportsMultipleContents() && XML_TEXT_FRAME_GRAPHIC == nFrameType) + { + addContent(*m_xImplContext); + } + } + } + } + else if(getSupportsMultipleContents() && nElement == XML_ELEMENT(DRAW, XML_IMAGE)) + { + // read another image + xContext = new XMLTextFrameContext_Impl( + GetImport(), nElement, xAttrList, + m_eDefaultAnchorType, XML_TEXT_FRAME_GRAPHIC, m_xAttrList, true); + + m_xImplContext = xContext; + addContent(*m_xImplContext); + } + else if( m_bSupportsReplacement && !m_xReplImplContext.is() && + nElement == XML_ELEMENT(DRAW, XML_IMAGE) ) + { + // read replacement image + Reference < XPropertySet > xPropSet; + if( CreateIfNotThere( xPropSet ) ) + { + xContext = new XMLReplacementImageContext( GetImport(), + nElement, xAttrList, xPropSet ); + m_xReplImplContext = xContext; + } + } + else if( nullptr != dynamic_cast< const XMLTextFrameContext_Impl*>( m_xImplContext.get() )) + { + // the child is a writer frame + if( IsTokenInNamespace(nElement, XML_NAMESPACE_SVG) || + IsTokenInNamespace(nElement, XML_NAMESPACE_SVG_COMPAT) ) + { + // Implement Title/Description Elements UI (#i73249#) + const bool bOld = SvXMLImport::OOo_2x >= GetImport().getGeneratorVersion(); + if ( bOld ) + { + if ( (nElement & TOKEN_MASK) == XML_DESC ) + { + xContext = new XMLTextFrameTitleOrDescContext_Impl( GetImport(), + m_sTitle ); + } + } + else + { + if( (nElement & TOKEN_MASK) == XML_TITLE ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + xContext = new XMLTextFrameTitleOrDescContext_Impl( GetImport(), + m_sTitle ); + } + else if ( (nElement & TOKEN_MASK) == XML_DESC ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + xContext = new XMLTextFrameTitleOrDescContext_Impl( GetImport(), + m_sDesc ); + } + } + } + else if( IsTokenInNamespace(nElement, XML_NAMESPACE_DRAW) ) + { + Reference < XPropertySet > xPropSet; + if( (nElement & TOKEN_MASK) == XML_CONTOUR_POLYGON ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + if( CreateIfNotThere( xPropSet ) ) + xContext = new XMLTextFrameContourContext_Impl( GetImport(), nElement, + xAttrList, xPropSet, false ); + } + else if( (nElement & TOKEN_MASK) == XML_CONTOUR_PATH ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + if( CreateIfNotThere( xPropSet ) ) + xContext = new XMLTextFrameContourContext_Impl( GetImport(), nElement, + xAttrList, xPropSet, true ); + } + else if( (nElement & TOKEN_MASK) == XML_IMAGE_MAP ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + if( CreateIfNotThere( xPropSet ) ) + xContext = new XMLImageMapContext( GetImport(), xPropSet ); + } + } + else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + m_xImplContext = solveMultipleImages(); + } + // do we still have the frame object? + Reference < XPropertySet > xPropSet; + if( CreateIfNotThere( xPropSet ) ) + { + // is it an event supplier? + Reference xEventsSupplier(xPropSet, UNO_QUERY); + if (xEventsSupplier.is()) + { + // OK, we have the events, so create the context + xContext = new XMLEventsImportContext(GetImport(), xEventsSupplier); + } + } + } + } + // #i68101# + else if( nElement == XML_ELEMENT(SVG, XML_TITLE) || nElement == XML_ELEMENT(SVG, XML_DESC ) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC ) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + m_xImplContext = solveMultipleImages(); + } + xContext = static_cast(m_xImplContext->createFastChildContext( nElement, xAttrList ).get()); + } + else if (nElement == XML_ELEMENT(LO_EXT, XML_SIGNATURELINE)) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + m_xImplContext = solveMultipleImages(); + } + xContext = static_cast(m_xImplContext->createFastChildContext(nElement, xAttrList).get()); + } + else if (nElement == XML_ELEMENT(LO_EXT, XML_QRCODE)) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + m_xImplContext = solveMultipleImages(); + } + xContext = static_cast(m_xImplContext->createFastChildContext(nElement, xAttrList).get()); + } + else if (nElement == XML_ELEMENT(DRAW, XML_A)) + { + xContext = static_cast(m_xImplContext->createFastChildContext(nElement, xAttrList).get()); + } + else + { + // the child is a drawing shape + return XMLShapeImportHelper::CreateFrameChildContext( + m_xImplContext.get(), nElement, xAttrList ); + } + + return xContext; +} + +void XMLTextFrameContext::SetHyperlink( const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + bool bMap ) +{ + OSL_ENSURE( !m_pHyperlink, "recursive SetHyperlink call" ); + m_pHyperlink = std::make_unique( + rHRef, rName, rTargetFrameName, bMap ); +} + +TextContentAnchorType XMLTextFrameContext::GetAnchorType() const +{ + SvXMLImportContext *pContext = m_xImplContext.get(); + XMLTextFrameContext_Impl *pImpl = dynamic_cast< XMLTextFrameContext_Impl*>( pContext ); + if( pImpl ) + return pImpl->GetAnchorType(); + else + return m_eDefaultAnchorType; +} + +Reference < XTextContent > XMLTextFrameContext::GetTextContent() const +{ + Reference < XTextContent > xTxtCntnt; + SvXMLImportContext *pContext = m_xImplContext.get(); + XMLTextFrameContext_Impl *pImpl = dynamic_cast< XMLTextFrameContext_Impl* >( pContext ); + if( pImpl ) + xTxtCntnt.set( pImpl->GetPropSet(), UNO_QUERY ); + + return xTxtCntnt; +} + +Reference < XShape > XMLTextFrameContext::GetShape() const +{ + Reference < XShape > xShape; + SvXMLImportContext* pContext = m_xImplContext.get(); + SvXMLShapeContext* pImpl = dynamic_cast( pContext ); + if ( pImpl ) + { + xShape = pImpl->getShape(); + } + + return xShape; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextFrameContext.hxx b/xmloff/source/text/XMLTextFrameContext.hxx new file mode 100644 index 000000000..27c9b4c2b --- /dev/null +++ b/xmloff/source/text/XMLTextFrameContext.hxx @@ -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 . + */ + +#pragma once + +#include + +#include +#include +#include + +namespace com::sun::star { + namespace text { class XTextCursor; class XTextContent; } +} + +class XMLTextFrameContextHyperlink_Impl; + +class XMLTextFrameContext : public SvXMLImportContext, public MultiImageImportHelper +{ + rtl::Reference< sax_fastparser::FastAttributeList > m_xAttrList; + + SvXMLImportContextRef m_xImplContext; + SvXMLImportContextRef m_xReplImplContext; + + std::unique_ptr m_pHyperlink; + // Implement Title/Description Elements UI (#i73249#) + OUString m_sTitle; + OUString m_sDesc; + + css::text::TextContentAnchorType m_eDefaultAnchorType; + + /* The can longer be used to distinguish Writer graphic/text box + objects and Draw graphic/text box objects. + The new distinguish attribute is the parent style of the automatic style + of the object. All Draw objects have an automatic style without a parent style. + (#i51726#) + */ + bool m_HasAutomaticStyleWithoutParentStyle; + bool m_bSupportsReplacement; + + bool CreateIfNotThere( css::uno::Reference < css::beans::XPropertySet >& rPropSet ); + +protected: + /// helper to get the created xShape instance, needs to be overridden + void removeGraphicFromImportContext(const SvXMLImportContext& rContext) override; + OUString getGraphicPackageURLFromImportContext(const SvXMLImportContext& rContext) const override; + css::uno::Reference getGraphicFromImportContext(const SvXMLImportContext& rContext) const override; + +public: + + + XMLTextFrameContext( SvXMLImport& rImport, + const css::uno::Reference< + css::xml::sax::XFastAttributeList > & xAttrList, + css::text::TextContentAnchorType eDfltAnchorType ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + void SetHyperlink( const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + bool bMap ); + + css::text::TextContentAnchorType GetAnchorType() const; + + css::uno::Reference < css::text::XTextContent > GetTextContent() const; + + // Frame "to character": anchor moves from first to last char after saving (#i33242#) + css::uno::Reference < css::drawing::XShape > GetShape() const; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextFrameHyperlinkContext.cxx b/xmloff/source/text/XMLTextFrameHyperlinkContext.cxx new file mode 100644 index 000000000..64e16f147 --- /dev/null +++ b/xmloff/source/text/XMLTextFrameHyperlinkContext.cxx @@ -0,0 +1,183 @@ +/* -*- 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 +#include + +#include +#include +#include +#include +#include +#include "XMLTextFrameContext.hxx" +#include "XMLTextFrameHyperlinkContext.hxx" + +#include + +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +namespace drawing = com::sun::star::drawing; + + +XMLTextFrameHyperlinkContext::XMLTextFrameHyperlinkContext( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & xAttrList, + TextContentAnchorType eATyp ) : + SvXMLImportContext( rImport ), + eDefaultAnchorType( eATyp ), + bMap( false ) +{ + OUString sShow; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + sHRef = GetImport().GetAbsoluteReference( aIter.toString() ); + break; + case XML_ELEMENT(OFFICE, XML_NAME): + sName = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME): + sTargetFrameName = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_SHOW): + sShow = aIter.toString(); + break; + case XML_ELEMENT(OFFICE, XML_SERVER_MAP): + { + bool bTmp(false); + if (::sax::Converter::convertBool( bTmp, aIter.toView() )) + { + bMap = bTmp; + } + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !sShow.isEmpty() && sTargetFrameName.isEmpty() ) + { + if( IsXMLToken( sShow, XML_NEW ) ) + sTargetFrameName = "_blank"; + else if( IsXMLToken( sShow, XML_REPLACE ) ) + sTargetFrameName = "_self"; + } +} + +XMLTextFrameHyperlinkContext::~XMLTextFrameHyperlinkContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextFrameHyperlinkContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + XMLTextFrameContext *pTextFrameContext = nullptr; + + switch (nElement) + { + case XML_ELEMENT(DRAW, XML_FRAME): + { + pTextFrameContext = new XMLTextFrameContext(GetImport(), xAttrList, eDefaultAnchorType); + pTextFrameContext->SetHyperlink(sHRef, sName, sTargetFrameName, bMap); + pContext = pTextFrameContext; + xFrameContext = pContext; + } + break; + case XML_ELEMENT(DRAW, XML_CUSTOM_SHAPE): + case XML_ELEMENT(DRAW, XML_PATH): + case XML_ELEMENT(DRAW, XML_ELLIPSE): + case XML_ELEMENT(DRAW, XML_LINE): + case XML_ELEMENT(DRAW, XML_RECT): + case XML_ELEMENT(DRAW, XML_CAPTION): + case XML_ELEMENT(DRAW, XML_POLYGON): + case XML_ELEMENT(DRAW, XML_POLYLINE): + case XML_ELEMENT(DRAW, XML_MEASURE): + case XML_ELEMENT(DRAW, XML_CIRCLE): + case XML_ELEMENT(DRAW, XML_CONNECTOR): + case XML_ELEMENT(DRAW, XML_CONTROL): + case XML_ELEMENT(DRAW, XML_PAGE_THUMBNAIL): + case XML_ELEMENT(DRAW, XML_G): + case XML_ELEMENT(DR3D, XML_SCENE): + { + Reference xShapes; + SvXMLShapeContext* pShapeContext = XMLShapeImportHelper::CreateGroupChildContext( + GetImport(), nElement, xAttrList, xShapes); + pShapeContext->setHyperlink(sHRef); + pContext = pShapeContext; + } + break; + } + + if (!pContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return pContext; +} + + +TextContentAnchorType XMLTextFrameHyperlinkContext::GetAnchorType() const +{ + if( xFrameContext.is() ) + { + SvXMLImportContext *pContext = xFrameContext.get(); + return dynamic_cast(*pContext).GetAnchorType(); + } + else + return eDefaultAnchorType; + +} + +Reference < XTextContent > XMLTextFrameHyperlinkContext::GetTextContent() const +{ + Reference xTxt; + if( xFrameContext.is() ) + { + SvXMLImportContext *pContext = xFrameContext.get(); + xTxt = dynamic_cast(*pContext).GetTextContent(); + } + + return xTxt; +} + +// Frame "to character": anchor moves from first to last char after saving (#i33242#) +Reference < drawing::XShape > XMLTextFrameHyperlinkContext::GetShape() const +{ + Reference < drawing::XShape > xShape; + if( xFrameContext.is() ) + { + SvXMLImportContext *pContext = xFrameContext.get(); + xShape = dynamic_cast(*pContext).GetShape(); + } + + return xShape; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextFrameHyperlinkContext.hxx b/xmloff/source/text/XMLTextFrameHyperlinkContext.hxx new file mode 100644 index 000000000..a76081632 --- /dev/null +++ b/xmloff/source/text/XMLTextFrameHyperlinkContext.hxx @@ -0,0 +1,62 @@ +/* -*- 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 +#include +#include +#include + +namespace com::sun::star { + namespace text { class XTextCursor; class XTextFrame; } + namespace beans { class XPropertySet; } +} + +/// Used for hyperlinks attached to objects (drawing objects, text boxes, Writer frames) +class XMLTextFrameHyperlinkContext : public SvXMLImportContext +{ + OUString sHRef; + OUString sName; + OUString sTargetFrameName; + css::text::TextContentAnchorType eDefaultAnchorType; + SvXMLImportContextRef xFrameContext; + bool bMap; + +public: + + XMLTextFrameHyperlinkContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + css::text::TextContentAnchorType eDefaultAnchorType ); + virtual ~XMLTextFrameHyperlinkContext() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + css::text::TextContentAnchorType GetAnchorType() const; + + css::uno::Reference < css::text::XTextContent > GetTextContent() const; + + // Frame "to character": anchor moves from first to last char after saving (#i33242#) + css::uno::Reference < css::drawing::XShape > GetShape() const; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextHeaderFooterContext.cxx b/xmloff/source/text/XMLTextHeaderFooterContext.cxx new file mode 100644 index 000000000..9c176c7f4 --- /dev/null +++ b/xmloff/source/text/XMLTextHeaderFooterContext.cxx @@ -0,0 +1,190 @@ +/* -*- 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 +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; + + +XMLTextHeaderFooterContext::XMLTextHeaderFooterContext( SvXMLImport& rImport, + const Reference < XPropertySet > & rPageStylePropSet, + bool bFooter, bool bLft, bool bFrst ) : + SvXMLImportContext( rImport ), + xPropSet( rPageStylePropSet ), + sOn( bFooter ? OUString("FooterIsOn") : OUString("HeaderIsOn") ), + sShareContent( bFooter ? OUString("FooterIsShared") : OUString("HeaderIsShared") ), + sText( bFooter ? OUString("FooterText") : OUString("HeaderText") ), + sTextFirst(bFooter ? OUString("FooterTextFirst") : OUString("HeaderTextFirst")), + sTextLeft( bFooter ? OUString("FooterTextLeft") : OUString("HeaderTextLeft") ), + bInsertContent( true ), + bLeft( bLft ), + bFirst( bFrst ) +{ + // NOTE: if this ever handles XML_DISPLAY attr then beware of fdo#72850 ! + if( !(bLeft || bFirst) ) + return; + + Any aAny = xPropSet->getPropertyValue( sOn ); + bool bOn = *o3tl::doAccess(aAny); + + if( bOn ) + { + if (bLeft) + { + aAny = xPropSet->getPropertyValue( sShareContent ); + bool bShared = bool(); + if (!(aAny >>= bShared)) + assert(false); // should return a value! + if( bShared ) + { + // Don't share headers any longer + xPropSet->setPropertyValue( sShareContent, Any(false) ); + } + } + if (bFirst) + { + static const OUStringLiteral sShareContentFirst( u"FirstIsShared" ); + aAny = xPropSet->getPropertyValue( sShareContentFirst ); + bool bSharedFirst = bool(); + if (!(aAny >>= bSharedFirst)) + assert(false); // should return a value! + if( bSharedFirst ) + { + // Don't share first/right headers any longer + xPropSet->setPropertyValue( sShareContentFirst, Any(false) ); + } + } + } + else + { + // If headers or footers are switched off, no content must be + // inserted. + bInsertContent = false; + } +} + +XMLTextHeaderFooterContext::~XMLTextHeaderFooterContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextHeaderFooterContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + if( bInsertContent ) + { + if( !xOldTextCursor.is() ) + { + bool bRemoveContent = true; + Any aAny; + if( bLeft || bFirst ) + { + // Headers and footers are switched on already, + // and they aren't shared. + if (bLeft) + aAny = xPropSet->getPropertyValue( sTextLeft ); + else + aAny = xPropSet->getPropertyValue( sTextFirst ); + } + else + { + aAny = xPropSet->getPropertyValue( sOn ); + bool bOn = *o3tl::doAccess(aAny); + + if( !bOn ) + { + // Switch header on + xPropSet->setPropertyValue( sOn, Any(true) ); + + // The content has not to be removed, because the header + // or footer is empty already. + bRemoveContent = false; + } + + // If a header or footer is not shared, share it now. + aAny = xPropSet->getPropertyValue( sShareContent ); + bool bShared = *o3tl::doAccess(aAny); + if( !bShared ) + { + xPropSet->setPropertyValue( sShareContent, Any(true) ); + } + + aAny = xPropSet->getPropertyValue( sText ); + } + + Reference < XText > xText; + aAny >>= xText; + + if( bRemoveContent ) + { + xText->setString(OUString()); + // fdo#82165 shapes anchored at the beginning or end survive + // setString("") - kill them the hard way: SwDoc::DelFullPara() + uno::Reference const xAppend( + xText, uno::UNO_QUERY_THROW); + uno::Reference const xPara( + xAppend->finishParagraph( + uno::Sequence()), + uno::UNO_QUERY_THROW); + xPara->dispose(); + } + + rtl::Reference < XMLTextImportHelper > xTxtImport = + GetImport().GetTextImport(); + + xOldTextCursor = xTxtImport->GetCursor(); + xTxtImport->SetCursor( xText->createTextCursor() ); + } + + pContext = + GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, + XMLTextType::HeaderFooter ); + } + + return pContext; +} + +void XMLTextHeaderFooterContext::endFastElement(sal_Int32 ) +{ + if( xOldTextCursor.is() ) + { + GetImport().GetTextImport()->DeleteParagraph(); + GetImport().GetTextImport()->SetCursor( xOldTextCursor ); + } + else if( !bLeft ) + { + // If no content has been inserted into the header or footer, + // switch it off. + xPropSet->setPropertyValue( sOn, Any(false) ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListAutoStylePool.cxx b/xmloff/source/text/XMLTextListAutoStylePool.cxx new file mode 100644 index 000000000..d2744cb18 --- /dev/null +++ b/xmloff/source/text/XMLTextListAutoStylePool.cxx @@ -0,0 +1,276 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; + + +class XMLTextListAutoStylePoolEntry_Impl +{ + OUString sName; + OUString sInternalName; + Reference < XIndexReplace > xNumRules; + sal_uInt32 nPos; + bool bIsNamed; + + +public: + + XMLTextListAutoStylePoolEntry_Impl( + sal_uInt32 nPos, + const Reference < XIndexReplace > & rNumRules, + XMLTextListAutoStylePoolNames_Impl& rNames, + std::u16string_view rPrefix, + sal_uInt32& rName ); + + explicit XMLTextListAutoStylePoolEntry_Impl( + const Reference < XIndexReplace > & rNumRules ) : + xNumRules( rNumRules ), + nPos( 0 ), + bIsNamed( false ) + { + Reference < XNamed > xNamed( xNumRules, UNO_QUERY ); + if( xNamed.is() ) + { + sInternalName = xNamed->getName(); + bIsNamed = true; + } + } + + explicit XMLTextListAutoStylePoolEntry_Impl( + const OUString& rInternalName ) : + sInternalName( rInternalName ), + nPos( 0 ), + bIsNamed( true ) + { + } + + const OUString& GetName() const { return sName; } + const OUString& GetInternalName() const { return sInternalName; } + const Reference < XIndexReplace > & GetNumRules() const { return xNumRules; } + sal_uInt32 GetPos() const { return nPos; } + bool IsNamed() const { return bIsNamed; } +}; + +XMLTextListAutoStylePoolEntry_Impl::XMLTextListAutoStylePoolEntry_Impl( + sal_uInt32 nP, + const Reference < XIndexReplace > & rNumRules, + XMLTextListAutoStylePoolNames_Impl& rNames, + std::u16string_view rPrefix, + sal_uInt32& rName ) : + xNumRules( rNumRules ), + nPos( nP ), + bIsNamed( false ) +{ + Reference < XNamed > xNamed( xNumRules, UNO_QUERY ); + if( xNamed.is() ) + { + sInternalName = xNamed->getName(); + bIsNamed = true; + } + + // create a name that hasn't been used before. The created name has not + // to be added to the array, because it will never tried again + OUStringBuffer sBuffer( 7 ); + do + { + rName++; + sBuffer.append( rPrefix ); + sBuffer.append( static_cast(rName) ); + sName = sBuffer.makeStringAndClear(); + } + while (rNames.find(sName) != rNames.end()); +} + +namespace { + +struct XMLTextListAutoStylePoolEntryCmp_Impl +{ + bool operator()( + std::unique_ptr const& r1, + std::unique_ptr const& r2 ) const + { + if( r1->IsNamed() ) + { + if( r2->IsNamed() ) + return r1->GetInternalName().compareTo( r2->GetInternalName() ) < 0; + else + return true; + } + else + { + if( r2->IsNamed() ) + return false; + else + return r1->GetNumRules().get() < r2->GetNumRules().get(); + } + } +}; + +} + +class XMLTextListAutoStylePool_Impl : public o3tl::sorted_vector, XMLTextListAutoStylePoolEntryCmp_Impl> {}; + +XMLTextListAutoStylePool::XMLTextListAutoStylePool( SvXMLExport& rExp ) : + rExport( rExp ), + sPrefix( "L" ), + pPool( new XMLTextListAutoStylePool_Impl ), + nName( 0 ) +{ + Reference xCompareFac( rExp.GetModel(), uno::UNO_QUERY ); + if( xCompareFac.is() ) + mxNumRuleCompare = xCompareFac->createAnyCompareByName( "NumberingRules" ); + SvXMLExportFlags nExportFlags = rExport.getExportFlags(); + bool bStylesOnly = (nExportFlags & SvXMLExportFlags::STYLES) && !(nExportFlags & SvXMLExportFlags::CONTENT); + if( bStylesOnly ) + sPrefix = "ML"; + +} + +XMLTextListAutoStylePool::~XMLTextListAutoStylePool() +{ +} + +void XMLTextListAutoStylePool::RegisterName( const OUString& rName ) +{ + m_aNames.insert(rName); +} + +sal_uInt32 XMLTextListAutoStylePool::Find( const XMLTextListAutoStylePoolEntry_Impl* pEntry ) const +{ + if( !pEntry->IsNamed() && mxNumRuleCompare.is() ) + { + const sal_uInt32 nCount = pPool->size(); + + uno::Any aAny1, aAny2; + aAny1 <<= pEntry->GetNumRules(); + + for( sal_uInt32 nPos = 0; nPos < nCount; nPos++ ) + { + aAny2 <<= (*pPool)[nPos]->GetNumRules(); + + if( mxNumRuleCompare->compare( aAny1, aAny2 ) == 0 ) + return nPos; + } + } + else + { + XMLTextListAutoStylePool_Impl::const_iterator it = pPool->find( pEntry ); + if( it != pPool->end() ) + return it - pPool->begin(); + } + + return sal_uInt32(-1); +} + +OUString XMLTextListAutoStylePool::Add( + const Reference < XIndexReplace > & rNumRules ) +{ + OUString sName; + XMLTextListAutoStylePoolEntry_Impl aTmp( rNumRules ); + + sal_uInt32 nPos = Find( &aTmp ); + if( nPos != sal_uInt32(-1) ) + { + sName = (*pPool)[ nPos ]->GetName(); + } + else + { + std::unique_ptr pEntry( + new XMLTextListAutoStylePoolEntry_Impl( pPool->size(), + rNumRules, m_aNames, sPrefix, + nName )); + sName = pEntry->GetName(); + pPool->insert( std::move(pEntry) ); + } + + return sName; +} + +OUString XMLTextListAutoStylePool::Find( + const Reference < XIndexReplace > & rNumRules ) const +{ + OUString sName; + XMLTextListAutoStylePoolEntry_Impl aTmp( rNumRules ); + + sal_uInt32 nPos = Find( &aTmp ); + if( nPos != sal_uInt32(-1) ) + sName = (*pPool)[ nPos ]->GetName(); + + return sName; +} + +OUString XMLTextListAutoStylePool::Find( + const OUString& rInternalName ) const +{ + OUString sName; + XMLTextListAutoStylePoolEntry_Impl aTmp( rInternalName ); + sal_uInt32 nPos = Find( &aTmp ); + if( nPos != sal_uInt32(-1) ) + sName = (*pPool)[ nPos ]->GetName(); + + return sName; +} + +void XMLTextListAutoStylePool::exportXML() const +{ + sal_uInt32 nCount = pPool->size(); + if( !nCount ) + return; + + std::vector aExpEntries(nCount); + + sal_uInt32 i; + for( i=0; i < nCount; i++ ) + { + XMLTextListAutoStylePoolEntry_Impl *pEntry = (*pPool)[i].get(); + SAL_WARN_IF( pEntry->GetPos() >= nCount, "xmloff", "Illegal pos" ); + aExpEntries[pEntry->GetPos()] = pEntry; + } + + SvxXMLNumRuleExport aNumRuleExp( rExport ); + + for( i=0; i < nCount; i++ ) + { + XMLTextListAutoStylePoolEntry_Impl *pEntry = aExpEntries[i]; + aNumRuleExp.exportNumberingRule( pEntry->GetName(), false, + pEntry->GetNumRules() ); + } +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListBlockContext.cxx b/xmloff/source/text/XMLTextListBlockContext.cxx new file mode 100644 index 000000000..7c688f4c5 --- /dev/null +++ b/xmloff/source/text/XMLTextListBlockContext.cxx @@ -0,0 +1,269 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include "XMLTextListItemContext.hxx" +#include "XMLTextListBlockContext.hxx" +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + + +// OD 2008-05-07 #refactorlists# +// add optional parameter and its handling +XMLTextListBlockContext::XMLTextListBlockContext( + SvXMLImport& rImport, + XMLTextImportHelper& rTxtImp, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + const bool bRestartNumberingAtSubList ) +: SvXMLImportContext( rImport ) +, mrTxtImport( rTxtImp ) +, mnLevel( 0 ) +, mbRestartNumbering( false ) +, mbSetDefaults( false ) +{ + static constexpr OUStringLiteral s_PropNameDefaultListId = u"DefaultListId"; + { + // get the parent list block context (if any); this is a bit ugly... + XMLTextListBlockContext * pLB(nullptr); + XMLTextListItemContext * pLI(nullptr); + XMLNumberedParaContext * pNP(nullptr); + rTxtImp.GetTextListHelper().ListContextTop(pLB, pLI, pNP); + mxParentListBlock = pLB; + } + // Inherit style name from parent list, as well as the flags whether + // numbering must be restarted and formats have to be created. + OUString sParentListStyleName; + if( mxParentListBlock.is() ) + { + XMLTextListBlockContext *pParent = mxParentListBlock.get(); + msListStyleName = pParent->msListStyleName; + sParentListStyleName = msListStyleName; + mxNumRules = pParent->GetNumRules(); + mnLevel = pParent->GetLevel() + 1; + mbRestartNumbering = pParent->IsRestartNumbering() || + bRestartNumberingAtSubList; + mbSetDefaults = pParent->mbSetDefaults; + msListId = pParent->GetListId(); + msContinueListId = pParent->GetContinueListId(); + } + + bool bIsContinueNumberingAttributePresent( false ); + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XML, XML_ID): +//FIXME: there is no UNO API for lists + // xml:id is also the list ID (#i92221#) + if ( mnLevel == 0 ) // root element + { + msListId = aIter.toString(); + } + break; + case XML_ELEMENT(TEXT, XML_CONTINUE_NUMBERING): + mbRestartNumbering = !IsXMLToken(aIter, XML_TRUE); + bIsContinueNumberingAttributePresent = true; + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + msListStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_CONTINUE_LIST): + if ( mnLevel == 0 ) // root element + { + msContinueListId = aIter.toString(); + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // Remember this list block. + mrTxtImport.GetTextListHelper().PushListContext( this ); + + mxNumRules = XMLTextListsHelper::MakeNumRule(GetImport(), mxNumRules, + sParentListStyleName, msListStyleName, + mnLevel, &mbRestartNumbering, &mbSetDefaults ); + if( !mxNumRules.is() ) + return; + + if ( mnLevel != 0 ) // root element + return; + + XMLTextListsHelper& rTextListsHelper( mrTxtImport.GetTextListHelper() ); + // Inconsistent behavior regarding lists (#i92811#) + OUString sListStyleDefaultListId; + { + uno::Reference< beans::XPropertySet > xNumRuleProps( mxNumRules, UNO_QUERY ); + if ( xNumRuleProps.is() ) + { + uno::Reference< beans::XPropertySetInfo > xNumRulePropSetInfo( + xNumRuleProps->getPropertySetInfo()); + if (xNumRulePropSetInfo.is() && + xNumRulePropSetInfo->hasPropertyByName( + s_PropNameDefaultListId)) + { + xNumRuleProps->getPropertyValue(s_PropNameDefaultListId) + >>= sListStyleDefaultListId; + SAL_WARN_IF( sListStyleDefaultListId.isEmpty(), "xmloff", + "no default list id found at numbering rules instance. Serious defect." ); + } + } + } + if ( msListId.isEmpty() ) // no text:id property found + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); + if ( rImport.IsTextDocInOOoFileFormat() || + ( bBuildIdFound && nUPD == 680 ) ) + { + /* handling former documents written by OpenOffice.org: + use default list id of numbering rules instance, if existing + (#i92811#) + */ + if ( !sListStyleDefaultListId.isEmpty() ) + { + msListId = sListStyleDefaultListId; + if ( !bIsContinueNumberingAttributePresent && + !mbRestartNumbering && + rTextListsHelper.IsListProcessed( msListId ) ) + { + mbRestartNumbering = true; + } + } + } + if ( msListId.isEmpty() ) + { + // generate a new list id for the list + msListId = rTextListsHelper.GenerateNewListId(); + } + } + + if ( bIsContinueNumberingAttributePresent && !mbRestartNumbering && + msContinueListId.isEmpty() ) + { + const OUString& Last( rTextListsHelper.GetLastProcessedListId() ); + if ( rTextListsHelper.GetListStyleOfLastProcessedList() == msListStyleName + && Last != msListId ) + { + msContinueListId = Last; + } + } + + bool bContinueNumbering = bIsContinueNumberingAttributePresent && !mbRestartNumbering; + if (msContinueListId.isEmpty() && bContinueNumbering && GetImport().IsMSO()) + { + // No "continue list" id, but continue numbering was requested. Connect to the last list of + // the same list style in the Word case, even if there was a different list in the meantime. + msContinueListId = rTextListsHelper.GetLastIdOfStyleName(msListStyleName); + } + + if ( !msContinueListId.isEmpty() ) + { + if ( !rTextListsHelper.IsListProcessed( msContinueListId ) ) + { + msContinueListId.clear(); + } + else + { + // search continue list chain for master list and + // continue the master list. + OUString sTmpStr = + rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId ); + while ( !sTmpStr.isEmpty() ) + { + msContinueListId = sTmpStr; + + sTmpStr = + rTextListsHelper.GetContinueListIdOfProcessedList( msContinueListId ); + } + } + } + + if ( !rTextListsHelper.IsListProcessed( msListId ) ) + { + // Inconsistent behavior regarding lists (#i92811#) + rTextListsHelper.KeepListAsProcessed( + msListId, msListStyleName, msContinueListId, + sListStyleDefaultListId ); + } +} + +XMLTextListBlockContext::~XMLTextListBlockContext() +{ +} + +void XMLTextListBlockContext::endFastElement(sal_Int32 ) +{ + // Numbering has not to be restarted if it has been restarted within + // a child list. + XMLTextListBlockContext *pParent = mxParentListBlock.get(); + if( pParent ) + { + pParent->mbRestartNumbering = mbRestartNumbering; + } + + // Restore current list block. + mrTxtImport.GetTextListHelper().PopListContext(); + + // Any paragraph following the list within the same list item must not + // be numbered. + mrTxtImport.GetTextListHelper().SetListItem( nullptr ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextListBlockContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + + bool bHeader = false; + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_LIST_HEADER): + bHeader = true; + [[fallthrough]]; + case XML_ELEMENT(TEXT, XML_LIST_ITEM): + pContext = new XMLTextListItemContext( GetImport(), mrTxtImport, + xAttrList, bHeader ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return pContext; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListBlockContext.hxx b/xmloff/source/text/XMLTextListBlockContext.hxx new file mode 100644 index 000000000..9446ee5e9 --- /dev/null +++ b/xmloff/source/text/XMLTextListBlockContext.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/. + * + * 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 +#include + +class XMLTextImportHelper; + +class XMLTextListBlockContext : public SvXMLImportContext +{ + XMLTextImportHelper& mrTxtImport; + + css::uno::Reference< css::container::XIndexReplace > mxNumRules; + + // text:style-name property of element + OUString msListStyleName; + + rtl::Reference mxParentListBlock; + + sal_Int16 mnLevel; + bool mbRestartNumbering; + bool mbSetDefaults; + + // text:id property of element, only valid for root element + OUString msListId; + // text:continue-list property of element, only valid for root element + OUString msContinueListId; + +public: + + + // add optional parameter + XMLTextListBlockContext( + SvXMLImport& rImport, + XMLTextImportHelper& rTxtImp, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + const bool bRestartNumberingAtSubList = false ); + virtual ~XMLTextListBlockContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + sal_Int16 GetLevel() const { return mnLevel; } + bool IsRestartNumbering() const { return mbRestartNumbering; } + void ResetRestartNumbering() { mbRestartNumbering = false; } + + const css::uno::Reference < css::container::XIndexReplace >& GetNumRules() const + { return mxNumRules; } + + const OUString& GetListId() const { return msListId;} + const OUString& GetContinueListId() const { return msContinueListId;} +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListItemContext.cxx b/xmloff/source/text/XMLTextListItemContext.cxx new file mode 100644 index 000000000..1ef6736fa --- /dev/null +++ b/xmloff/source/text/XMLTextListItemContext.cxx @@ -0,0 +1,152 @@ +/* -*- 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 +#include +#include +#include +#include "txtparai.hxx" +#include +#include "XMLTextListBlockContext.hxx" +#include +#include +#include +#include +#include +#include +#include "XMLTextListItemContext.hxx" +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + + +XMLTextListItemContext::XMLTextListItemContext( + SvXMLImport& rImport, + XMLTextImportHelper& rTxtImp, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + const bool bIsHeader ) + : SvXMLImportContext( rImport ), + rTxtImport( rTxtImp ), + nStartValue( -1 ), + mnSubListCount( 0 ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( !bIsHeader && aIter.getToken() == XML_ELEMENT(TEXT, XML_START_VALUE) ) + { + sal_Int32 nTmp = aIter.toInt32(); + if( nTmp >= 0 && nTmp <= SHRT_MAX ) + nStartValue = static_cast(nTmp); + } + else if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_OVERRIDE) ) + { + OUString sListStyleOverrideName = aIter.toString(); + if ( !sListStyleOverrideName.isEmpty() ) + { + OUString sDisplayStyleName( + GetImport().GetStyleDisplayName( XmlStyleFamily::TEXT_LIST, + sListStyleOverrideName ) ); + const Reference < container::XNameContainer >& rNumStyles = + rTxtImp.GetNumberingStyles(); + if( rNumStyles.is() && rNumStyles->hasByName( sDisplayStyleName ) ) + { + Reference < style::XStyle > xStyle; + Any aAny = rNumStyles->getByName( sDisplayStyleName ); + aAny >>= xStyle; + + uno::Reference< beans::XPropertySet > xPropSet( xStyle, UNO_QUERY ); + aAny = xPropSet->getPropertyValue("NumberingRules"); + aAny >>= mxNumRulesOverride; + } + else + { + const SvxXMLListStyleContext* pListStyle = + rTxtImp.FindAutoListStyle( sListStyleOverrideName ); + if( pListStyle ) + { + mxNumRulesOverride = pListStyle->GetNumRules(); + if( !mxNumRulesOverride.is() ) + { + pListStyle->CreateAndInsertAuto(); + mxNumRulesOverride = pListStyle->GetNumRules(); + } + } + } + } + } + else if ( aIter.getToken() == XML_ELEMENT(XML, XML_ID) ) + { +//FIXME: there is no UNO API for list items + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + + // If this is a element, then remember it as a sign + // that a bullet has to be generated. + if( !bIsHeader ) { + rTxtImport.GetTextListHelper().SetListItem( this ); + } + +} + +XMLTextListItemContext::~XMLTextListItemContext() +{ +} + +void XMLTextListItemContext::endFastElement(sal_Int32 ) +{ + // finish current list item + rTxtImport.GetTextListHelper().SetListItem( nullptr ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextListItemContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_H): + case XML_ELEMENT(TEXT, XML_P): + case XML_ELEMENT(LO_EXT, XML_P): + pContext = new XMLParaContext( GetImport(), nElement, + xAttrList ); + if (rTxtImport.IsProgress()) + GetImport().GetProgressBarHelper()->Increment(); + + break; + case XML_ELEMENT(TEXT, XML_LIST): + ++mnSubListCount; + pContext = new XMLTextListBlockContext( GetImport(), rTxtImport, + xAttrList, + (mnSubListCount > 1) ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextListItemContext.hxx b/xmloff/source/text/XMLTextListItemContext.hxx new file mode 100644 index 000000000..de43d90f9 --- /dev/null +++ b/xmloff/source/text/XMLTextListItemContext.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 + +#include + +class XMLTextImportHelper; + +class XMLTextListItemContext : public SvXMLImportContext +{ + XMLTextImportHelper& rTxtImport; + + sal_Int16 nStartValue; + + // quantity of child elements + sal_Int16 mnSubListCount; + // list style instance for text::style-override property + css::uno::Reference< css::container::XIndexReplace > mxNumRulesOverride; + +public: + + + XMLTextListItemContext( + SvXMLImport& rImport, + XMLTextImportHelper& rTxtImp, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + const bool bIsHeader ); + virtual ~XMLTextListItemContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + bool HasStartValue() const { return -1 != nStartValue; } + sal_Int16 GetStartValue() const { return nStartValue; } + + bool HasNumRulesOverride() const + { + return mxNumRulesOverride.is(); + } + const css::uno::Reference < css::container::XIndexReplace >& GetNumRulesOverride() const + { + return mxNumRulesOverride; + } +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMarkImportContext.cxx b/xmloff/source/text/XMLTextMarkImportContext.cxx new file mode 100644 index 000000000..4a71194df --- /dev/null +++ b/xmloff/source/text/XMLTextMarkImportContext.cxx @@ -0,0 +1,584 @@ +/* -*- 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 "XMLTextMarkImportContext.hxx" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + + +XMLFieldParamImportContext::XMLFieldParamImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp ) : + SvXMLImportContext(rImport), + rHelper(rHlp) +{ +} + + +void XMLFieldParamImportContext::startFastElement(sal_Int32 /*nElement*/, const css::uno::Reference< css::xml::sax::XFastAttributeList> & xAttrList) +{ + OUString sName; + OUString sValue; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(FIELD, XML_NAME): + sName = aIter.toString(); + break; + case XML_ELEMENT(FIELD, XML_VALUE): + sValue = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + if (rHelper.hasCurrentFieldCtx() && !sName.isEmpty()) { + rHelper.addFieldParam(sName, sValue); + } +} + + +XMLTextMarkImportContext::XMLTextMarkImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp, + uno::Reference & io_rxCrossRefHeadingBookmark ) + : SvXMLImportContext(rImport) + , m_rHelper(rHlp) + , m_rxCrossRefHeadingBookmark(io_rxCrossRefHeadingBookmark) + , m_isHidden(false) + , m_bHaveAbout(false) +{ +} + +namespace { + +enum lcl_MarkType { TypeReference, TypeReferenceStart, TypeReferenceEnd, + TypeBookmark, TypeBookmarkStart, TypeBookmarkEnd, + TypeFieldmark, TypeFieldmarkStart, TypeFieldmarkSeparator, TypeFieldmarkEnd + }; + +} + +SvXMLEnumMapEntry const lcl_aMarkTypeMap[] = +{ + { XML_REFERENCE_MARK, TypeReference }, + { XML_REFERENCE_MARK_START, TypeReferenceStart }, + { XML_REFERENCE_MARK_END, TypeReferenceEnd }, + { XML_BOOKMARK, TypeBookmark }, + { XML_BOOKMARK_START, TypeBookmarkStart }, + { XML_BOOKMARK_END, TypeBookmarkEnd }, + { XML_FIELDMARK, TypeFieldmark }, + { XML_FIELDMARK_START, TypeFieldmarkStart }, + { XML_FIELDMARK_SEPARATOR, TypeFieldmarkSeparator }, + { XML_FIELDMARK_END, TypeFieldmarkEnd }, + { XML_TOKEN_INVALID, lcl_MarkType(0) }, +}; + + +static OUString lcl_getFormFieldmarkName(std::u16string_view name) +{ + if (name == ODF_FORMCHECKBOX || + name == u"msoffice.field.FORMCHECKBOX" || + name == u"ecma.office-open-xml.field.FORMCHECKBOX") + return ODF_FORMCHECKBOX; + else if (name == ODF_FORMDROPDOWN || + name == u"ecma.office-open-xml.field.FORMDROPDOWN") + return ODF_FORMDROPDOWN; + else + return OUString(); +} + +static OUString lcl_getFieldmarkName(OUString const& name) +{ + if (name == "msoffice.field.FORMTEXT" || + name == "ecma.office-open-xml.field.FORMTEXT") + return ODF_FORMTEXT; + else + return name; +} + + +void XMLTextMarkImportContext::startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if (!FindName(xAttrList)) + { + m_sBookmarkName.clear(); + } + + if ((nElement & TOKEN_MASK) == XML_FIELDMARK_START || + (nElement & TOKEN_MASK) == XML_FIELDMARK) + { + if (m_sBookmarkName.isEmpty()) + { + m_sBookmarkName = "Unknown"; + } + m_rHelper.pushFieldCtx( m_sBookmarkName, m_sFieldName ); + } + + if ((nElement & TOKEN_MASK) == XML_BOOKMARK_START) + { + m_rHelper.setBookmarkAttributes(m_sBookmarkName, m_isHidden, m_sCondition); + } +} + +static auto InsertFieldmark(SvXMLImport & rImport, + XMLTextImportHelper & rHelper, bool const isFieldmarkSeparatorMissing) -> void +{ + assert(rHelper.hasCurrentFieldCtx()); // was set up in StartElement() + + // fdo#86795 check if it's actually a checkbox first + auto const [ name, type ] = rHelper.getCurrentFieldType(); + OUString const fieldmarkTypeName = lcl_getFieldmarkName(type); + if (fieldmarkTypeName == ODF_FORMCHECKBOX || + fieldmarkTypeName == ODF_FORMDROPDOWN) + { // sw can't handle checkbox with start+end + SAL_INFO("xmloff.text", "invalid fieldmark-start/fieldmark-end ignored"); + return; + } + + uno::Reference const xStartRange(rHelper.getCurrentFieldStart()); + uno::Reference const xCursor( + rHelper.GetText()->createTextCursorByRange(xStartRange)); + uno::Reference const xCompare(rHelper.GetText(), uno::UNO_QUERY); + if (xCompare->compareRegionStarts(xStartRange, rHelper.GetCursorAsRange()) < 0) + { + SAL_WARN("xmloff.text", "invalid field mark positions"); + assert(false); + } + xCursor->gotoRange(rHelper.GetCursorAsRange(), true); + + Reference const xContent = XMLTextMarkImportContext::CreateAndInsertMark( + rImport, "com.sun.star.text.Fieldmark", name, xCursor, + OUString(), isFieldmarkSeparatorMissing); + + if (!xContent.is()) + return; + + // setup fieldmark... + Reference const xFormField(xContent, UNO_QUERY); + assert(xFormField.is()); + try { + xFormField->setFieldType(fieldmarkTypeName); + } catch (uno::RuntimeException const&) { + // tdf#140437 somehow old documents had the field code in the type + // attribute instead of field:param + SAL_INFO("xmloff.text", "invalid fieldmark type, converting to param"); + // add without checking: FieldParamImporter::Import() catches ElementExistException + rHelper.addFieldParam(ODF_CODE_PARAM, fieldmarkTypeName); + xFormField->setFieldType(ODF_UNHANDLED); + } + rHelper.setCurrentFieldParamsTo(xFormField); + // move cursor after setFieldType as that may delete/re-insert + rHelper.GetCursor()->gotoRange(xContent->getAnchor()->getEnd(), false); + rHelper.GetCursor()->goLeft(1, false); // move before CH_TXT_ATR_FIELDEND + // tdf#129520: AppendTextNode() ignores the content index! + // plan B: insert a spurious paragraph break now and join + // it in PopFieldmark()! + rHelper.GetText()->insertControlCharacter(rHelper.GetCursor(), + text::ControlCharacter::PARAGRAPH_BREAK, false); + rHelper.GetCursor()->goLeft(1, false); // back to previous paragraph +} + +static auto PopFieldmark(XMLTextImportHelper & rHelper) -> void +{ + // can't verify name because it's not written as an attribute... + uno::Reference const xField(rHelper.popFieldCtx(), + uno::UNO_QUERY); + if (!xField.is()) + return; + + if (rHelper.GetText() == xField->getAnchor()->getText()) + { + try + { // skip CH_TXT_ATR_FIELDEND + rHelper.GetCursor()->goRight(1, true); + rHelper.GetCursor()->setString(OUString()); // undo AppendTextNode from InsertFieldmark + rHelper.GetCursor()->gotoRange(xField->getAnchor()->getEnd(), false); + } + catch (uno::Exception const&) + { + assert(false); // must succeed + } + } + else + { + SAL_INFO("xmloff.text", "fieldmark has invalid positions"); + // could either dispose it or leave it to end at the end of the document? + xField->dispose(); + } +} + +void XMLTextMarkImportContext::endFastElement(sal_Int32 nElement) +{ + static constexpr OUStringLiteral sAPI_bookmark = u"com.sun.star.text.Bookmark"; + + lcl_MarkType nTmp{}; + if (!SvXMLUnitConverter::convertEnum(nTmp, SvXMLImport::getNameFromToken(nElement), lcl_aMarkTypeMap)) + return; + + if (m_sBookmarkName.isEmpty() && TypeFieldmarkEnd != nTmp && TypeFieldmarkSeparator != nTmp) + return; + + switch (nTmp) + { + case TypeReference: + // export point reference mark + CreateAndInsertMark(GetImport(), + "com.sun.star.text.ReferenceMark", + m_sBookmarkName, + m_rHelper.GetCursorAsRange()->getStart()); + break; + + case TypeBookmark: + { + // tdf#94804: detect duplicate heading cross reference bookmarks + if (m_sBookmarkName.startsWith("__RefHeading__")) + { + if (m_rxCrossRefHeadingBookmark.is()) + { + uno::Reference const xNamed( + m_rxCrossRefHeadingBookmark, uno::UNO_QUERY); + m_rHelper.AddCrossRefHeadingMapping( + m_sBookmarkName, xNamed->getName()); + break; // don't insert + } + } + } + [[fallthrough]]; + case TypeFieldmark: + { + const OUString formFieldmarkName=lcl_getFormFieldmarkName(m_sFieldName); + bool bImportAsField = (nTmp==TypeFieldmark && !formFieldmarkName.isEmpty()); //@TODO handle abbreviation cases... + // export point bookmark + const Reference xContent( + CreateAndInsertMark(GetImport(), + (bImportAsField ? OUString("com.sun.star.text.FormFieldmark") : OUString(sAPI_bookmark)), + m_sBookmarkName, + m_rHelper.GetCursorAsRange()->getStart(), + m_sXmlId) ); + if (nTmp==TypeFieldmark) { + if (xContent.is() && bImportAsField) { + // setup fieldmark... + Reference< css::text::XFormField> xFormField(xContent, UNO_QUERY); + xFormField->setFieldType(formFieldmarkName); + if (xFormField.is() && m_rHelper.hasCurrentFieldCtx()) { + m_rHelper.setCurrentFieldParamsTo(xFormField); + } + } + m_rHelper.popFieldCtx(); + } + if (TypeBookmark == nTmp + && m_sBookmarkName.startsWith("__RefHeading__")) + { + assert(xContent.is()); + m_rxCrossRefHeadingBookmark = xContent; + } + } + break; + + case TypeBookmarkStart: + // save XTextRange for later construction of bookmark + { + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > + xRDFaAttributes; + if (m_bHaveAbout && TypeBookmarkStart == nTmp) + { + xRDFaAttributes = + GetImport().GetRDFaImportHelper().ParseRDFa( + m_sAbout, m_sProperty, + m_sContent, m_sDatatype); + } + m_rHelper.InsertBookmarkStartRange( + m_sBookmarkName, + m_rHelper.GetCursorAsRange()->getStart(), + m_sXmlId, xRDFaAttributes); + } + break; + + case TypeBookmarkEnd: + { + // tdf#94804: detect duplicate heading cross reference bookmarks + if (m_sBookmarkName.startsWith("__RefHeading__")) + { + if (m_rxCrossRefHeadingBookmark.is()) + { + uno::Reference const xNamed( + m_rxCrossRefHeadingBookmark, uno::UNO_QUERY); + m_rHelper.AddCrossRefHeadingMapping( + m_sBookmarkName, xNamed->getName()); + break; // don't insert + } + } + + // get old range, and construct + Reference xStartRange; + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > + xRDFaAttributes; + if (m_rHelper.FindAndRemoveBookmarkStartRange( + m_sBookmarkName, xStartRange, + m_sXmlId, xRDFaAttributes)) + { + Reference xEndRange( + m_rHelper.GetCursorAsRange()->getStart()); + + // check if beginning and end are in same XText + if (xStartRange.is() && xEndRange.is() && xStartRange->getText() == xEndRange->getText()) + { + // create range for insertion + Reference xInsertionCursor = + m_rHelper.GetText()->createTextCursorByRange( + xEndRange); + try { + xInsertionCursor->gotoRange(xStartRange, true); + } catch (uno::Exception&) { + OSL_ENSURE(false, + "cannot go to end position of bookmark"); + } + + //DBG_ASSERT(! xInsertionCursor->isCollapsed(), + // "we want no point mark"); + // can't assert, because someone could + // create a file with subsequence + // start/end elements + + Reference xContent; + // insert reference + xContent = CreateAndInsertMark(GetImport(), + sAPI_bookmark, + m_sBookmarkName, + xInsertionCursor, + m_sXmlId); + if (xRDFaAttributes) + { + const Reference + xMeta(xContent, UNO_QUERY); + GetImport().GetRDFaImportHelper().AddRDFa( + xMeta, xRDFaAttributes); + } + const Reference xPropertySet(xContent, UNO_QUERY); + if (xPropertySet.is()) + { + xPropertySet->setPropertyValue("BookmarkHidden", uno::Any(m_rHelper.getBookmarkHidden(m_sBookmarkName))); + xPropertySet->setPropertyValue("BookmarkCondition", uno::Any(m_rHelper.getBookmarkCondition(m_sBookmarkName))); + } + if (m_sBookmarkName.startsWith("__RefHeading__")) + { + assert(xContent.is()); + m_rxCrossRefHeadingBookmark = xContent; + } + } + // else: beginning/end in different XText -> ignore! + } + // else: no start found -> ignore! + break; + } + case TypeFieldmarkStart: + { + break; + } + case TypeFieldmarkSeparator: + { + InsertFieldmark(GetImport(), m_rHelper, false); + break; + } + case TypeFieldmarkEnd: + { + if (m_rHelper.hasCurrentFieldCtx() && !m_rHelper.hasCurrentFieldSeparator()) + { // backward compat for old files without separator + InsertFieldmark(GetImport(), m_rHelper, true); + } + PopFieldmark(m_rHelper); + break; + } + case TypeReferenceStart: + case TypeReferenceEnd: + OSL_FAIL("reference start/end are handled in txtparai !"); + break; + + default: + OSL_FAIL("unknown mark type"); + break; + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextMarkImportContext::createFastChildContext( + sal_Int32 , + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + return new XMLFieldParamImportContext(GetImport(), m_rHelper); +} + + +Reference XMLTextMarkImportContext::CreateAndInsertMark( + SvXMLImport& rImport, + const OUString& sServiceName, + const OUString& sMarkName, + const Reference & rRange, + const OUString& i_rXmlId, + bool const isFieldmarkSeparatorMissing) +{ + // create mark + const Reference xFactory(rImport.GetModel(), + UNO_QUERY); + Reference xIfc; + + if (xFactory.is()) + { + xIfc = xFactory->createInstance(sServiceName); + + if (!xIfc.is()) + { + OSL_FAIL("CreateAndInsertMark: cannot create service?"); + return nullptr; + } + + // set name (unless there is no name (text:meta)) + const Reference xNamed(xIfc, UNO_QUERY); + if (xNamed.is()) + { + xNamed->setName(sMarkName); + } + else + { + if (!sMarkName.isEmpty()) + { + OSL_FAIL("name given, but XNamed not supported?"); + return nullptr; + } + } + + if (isFieldmarkSeparatorMissing) + { + uno::Reference const xProps(xIfc, uno::UNO_QUERY_THROW); + xProps->setPropertyValue("PrivateSeparatorAtStart", uno::Any(true)); + } + + // cast to XTextContent and attach to document + const Reference xTextContent(xIfc, UNO_QUERY); + if (xTextContent.is()) + { + try + { + // if inserting marks, bAbsorb==sal_False will cause + // collapsing of the given XTextRange. + rImport.GetTextImport()->GetText()->insertTextContent(rRange, + xTextContent, true); + + // xml:id for RDF metadata -- after insertion! + rImport.SetXmlId(xIfc, i_rXmlId); + + return xTextContent; + } + catch (css::lang::IllegalArgumentException &) + { + OSL_FAIL("CreateAndInsertMark: cannot insert?"); + return nullptr; + } + } + } + return nullptr; +} + +bool XMLTextMarkImportContext::FindName( + const Reference & xAttrList) +{ + bool bNameOK = false; + + // find name attribute first + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch(aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_NAME): + m_sBookmarkName = sValue; + bNameOK = true; + break; + case XML_ELEMENT(XML, XML_ID): + m_sXmlId = sValue; + break; + // RDFa + case XML_ELEMENT(XHTML, XML_ABOUT): + m_sAbout = sValue; + m_bHaveAbout = true; + break; + case XML_ELEMENT(XHTML, XML_PROPERTY): + m_sProperty = sValue; + break; + case XML_ELEMENT(XHTML, XML_CONTENT): + m_sContent = sValue; + break; + case XML_ELEMENT(XHTML, XML_DATATYPE): + m_sDatatype = sValue; + break; + case XML_ELEMENT(FIELD, XML_TYPE): + m_sFieldName = sValue; + break; + case XML_ELEMENT(LO_EXT, XML_HIDDEN): + ::sax::Converter::convertBool(m_isHidden, sValue); + break; + case XML_ELEMENT(LO_EXT, XML_CONDITION): + m_sCondition = sValue; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + return bNameOK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMarkImportContext.hxx b/xmloff/source/text/XMLTextMarkImportContext.hxx new file mode 100644 index 000000000..da05f5240 --- /dev/null +++ b/xmloff/source/text/XMLTextMarkImportContext.hxx @@ -0,0 +1,106 @@ +/* -*- 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 +#include + + +namespace com::sun::star { + namespace text { + class XTextRange; + class XTextContent; + } + namespace xml::sax { + class XAttributeList; + } +} +class XMLTextImportHelper; + +class XMLFieldParamImportContext : public SvXMLImportContext +{ + XMLTextImportHelper& rHelper; +public: + XMLFieldParamImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp ); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference & xAttrList) override; +}; + + +/** + * import bookmarks and reference marks + * ( , , , + * , , ) + * + * All elements are handled by the same class due to their similarities. + */ +class XMLTextMarkImportContext final : public SvXMLImportContext +{ +private: + XMLTextImportHelper & m_rHelper; + + css::uno::Reference & m_rxCrossRefHeadingBookmark; + + OUString m_sBookmarkName; + OUString m_sFieldName; + bool m_isHidden; + OUString m_sCondition; + OUString m_sXmlId; + // RDFa + bool m_bHaveAbout; + OUString m_sAbout; + OUString m_sProperty; + OUString m_sContent; + OUString m_sDatatype; + +public: + + XMLTextMarkImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp, + css::uno::Reference & io_rxCrossRefHeadingBookmark ); + + virtual void SAL_CALL startFastElement( sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +public: + static css::uno::Reference< css::text::XTextContent > CreateAndInsertMark( + SvXMLImport& rImport, + const OUString& sServiceName, + const OUString& sMarkName, + const css::uno::Reference & rRange, + const OUString& i_rXmlId = OUString(), + bool const isFieldmarkSeparatorMissing = false); + + bool FindName( + const css::uno::Reference & xAttrList); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMasterPageContext.cxx b/xmloff/source/text/XMLTextMasterPageContext.cxx new file mode 100644 index 000000000..f9584cc81 --- /dev/null +++ b/xmloff/source/text/XMLTextMasterPageContext.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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::xmloff::token; + +Reference < XStyle > XMLTextMasterPageContext::Create() +{ + Reference < XStyle > xNewStyle; + + Reference< XMultiServiceFactory > xFactory( GetImport().GetModel(), + UNO_QUERY ); + if( xFactory.is() ) + { + Reference < XInterface > xIfc = + xFactory->createInstance("com.sun.star.style.PageStyle"); + if( xIfc.is() ) + xNewStyle.set( xIfc, UNO_QUERY ); + } + + return xNewStyle; +} + +constexpr OUStringLiteral gsFollowStyle( u"FollowStyle" ); + +XMLTextMasterPageContext::XMLTextMasterPageContext( SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & xAttrList, + bool bOverwrite ) +: SvXMLStyleContext( rImport, XmlStyleFamily::MASTER_PAGE ) +, bInsertHeader( false ) +, bInsertFooter( false ) +, bInsertHeaderLeft( false ) +, bInsertFooterLeft( false ) +, bInsertHeaderFirst( false ) +, bInsertFooterFirst( false ) +, bHeaderInserted( false ) +, bFooterInserted( false ) +{ + OUString sName, sDisplayName; + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + const OUString aValue = aIter.toString(); + switch (aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_NAME): + sName = aValue; + break; + case XML_ELEMENT(STYLE, XML_DISPLAY_NAME): + sDisplayName = aValue; + break; + case XML_ELEMENT(STYLE, XML_NEXT_STYLE_NAME): + sFollow = aValue; + break; + case XML_ELEMENT(STYLE, XML_PAGE_LAYOUT_NAME): + sPageMasterName = aValue; + break; + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + m_sDrawingPageStyle = aValue; + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !sDisplayName.isEmpty() ) + { + rImport.AddStyleDisplayName( XmlStyleFamily::MASTER_PAGE, sName, + sDisplayName ); + } + else + { + sDisplayName = sName; + } + + if( sDisplayName.isEmpty() ) + return; + + Reference < XNameContainer > xPageStyles = + GetImport().GetTextImport()->GetPageStyles(); + if( !xPageStyles.is() ) + return; + + Any aAny; + bool bNew = false; + if( xPageStyles->hasByName( sDisplayName ) ) + { + aAny = xPageStyles->getByName( sDisplayName ); + aAny >>= xStyle; + } + else + { + xStyle = Create(); + if( !xStyle.is() ) + return; + + xPageStyles->insertByName( sDisplayName, Any(xStyle) ); + bNew = true; + } + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + OUString sIsPhysical( "IsPhysical" ); + if( !bNew && xPropSetInfo->hasPropertyByName( sIsPhysical ) ) + { + aAny = xPropSet->getPropertyValue( sIsPhysical ); + bNew = !*o3tl::doAccess(aAny); + } + SetNew( bNew ); + + if( !(bOverwrite || bNew) ) + return; + + Reference < XMultiPropertyStates > xMultiStates( xPropSet, + UNO_QUERY ); + OSL_ENSURE( xMultiStates.is(), + "text page style does not support multi property set" ); + if( xMultiStates.is() ) + xMultiStates->setAllPropertiesToDefault(); + + if ( xPropSetInfo->hasPropertyByName( "GridDisplay" ) ) + xPropSet->setPropertyValue( "GridDisplay", Any(false) ); + + if ( xPropSetInfo->hasPropertyByName( "GridPrint" ) ) + xPropSet->setPropertyValue( "GridPrint", Any(false) ); + + bInsertHeader = bInsertFooter = true; + bInsertHeaderLeft = bInsertFooterLeft = true; + bInsertHeaderFirst = bInsertFooterFirst = true; +} + +XMLTextMasterPageContext::~XMLTextMasterPageContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextMasterPageContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + + bool bInsert = false, bFooter = false, bLeft = false, bFirst = false; + switch( nElement ) + { + case XML_ELEMENT(STYLE, XML_HEADER): + if( bInsertHeader && !bHeaderInserted ) + { + bInsert = true; + bHeaderInserted = true; + } + break; + case XML_ELEMENT(STYLE, XML_FOOTER): + if( bInsertFooter && !bFooterInserted ) + { + bInsert = bFooter = true; + bFooterInserted = true; + } + break; + case XML_ELEMENT(STYLE, XML_HEADER_LEFT): + if( bInsertHeaderLeft && bHeaderInserted ) + bInsert = bLeft = true; + break; + case XML_ELEMENT(STYLE, XML_FOOTER_LEFT): + if( bInsertFooterLeft && bFooterInserted ) + bInsert = bFooter = bLeft = true; + break; + case XML_ELEMENT(LO_EXT, XML_HEADER_FIRST): + case XML_ELEMENT(STYLE, XML_HEADER_FIRST): + if( bInsertHeaderFirst && bHeaderInserted ) + bInsert = bFirst = true; + break; + case XML_ELEMENT(LO_EXT, XML_FOOTER_FIRST): + case XML_ELEMENT(STYLE, XML_FOOTER_FIRST): + if( bInsertFooterFirst && bFooterInserted ) + bInsert = bFooter = bFirst = true; + break; + } + + if( bInsert && xStyle.is() ) + { + xContext = CreateHeaderFooterContext( nElement, xAttrList, + bFooter, bLeft, bFirst ); + } + + return xContext; +} + +SvXMLImportContext *XMLTextMasterPageContext::CreateHeaderFooterContext( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*xAttrList*/, + const bool bFooter, + const bool bLeft, + const bool bFirst ) +{ + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + return new XMLTextHeaderFooterContext( GetImport(), xPropSet, bFooter, bLeft, bFirst ); +} + +void XMLTextMasterPageContext::Finish( bool bOverwrite ) +{ + if( !(xStyle.is() && (IsNew() || bOverwrite)) ) + return; + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + XMLPropStyleContext * pDrawingPageStyle(nullptr); + if (!m_sDrawingPageStyle.isEmpty()) + { + pDrawingPageStyle = GetImport().GetTextImport()->FindDrawingPage(m_sDrawingPageStyle); + } + PageStyleContext * pPageLayout(nullptr); + if( !sPageMasterName.isEmpty() ) + { + pPageLayout = static_cast(GetImport().GetTextImport()->FindPageMaster(sPageMasterName)); + } + if (pPageLayout) + { + pPageLayout->FillPropertySet_PageStyle(xPropSet, pDrawingPageStyle); + } + else if (pDrawingPageStyle) + { + // don't need to care about old background attributes in this case + pDrawingPageStyle->FillPropertySet(xPropSet); + } + + Reference < XNameContainer > xPageStyles = + GetImport().GetTextImport()->GetPageStyles(); + if( !xPageStyles.is() ) + return; + + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( gsFollowStyle ) ) + { + OUString sDisplayFollow( + GetImport().GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, sFollow ) ); + if( sDisplayFollow.isEmpty() || + !xPageStyles->hasByName( sDisplayFollow ) ) + sDisplayFollow = xStyle->getName(); + + Any aAny = xPropSet->getPropertyValue( gsFollowStyle ); + OUString sCurrFollow; + aAny >>= sCurrFollow; + if( sCurrFollow != sDisplayFollow ) + { + xPropSet->setPropertyValue( gsFollowStyle, Any(sDisplayFollow) ); + } + } + + if ( xPropSetInfo->hasPropertyByName( "Hidden" ) ) + { + xPropSet->setPropertyValue( "Hidden", uno::Any( IsHidden( ) ) ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMasterPageExport.cxx b/xmloff/source/text/XMLTextMasterPageExport.cxx new file mode 100644 index 000000000..87490a0df --- /dev/null +++ b/xmloff/source/text/XMLTextMasterPageExport.cxx @@ -0,0 +1,237 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +constexpr OUStringLiteral gsHeaderText( u"HeaderText" ); +constexpr OUStringLiteral gsHeaderOn( u"HeaderIsOn" ); +constexpr OUStringLiteral gsHeaderShareContent( u"HeaderIsShared" ); +constexpr OUStringLiteral gsHeaderTextFirst( u"HeaderTextFirst" ); +constexpr OUStringLiteral gsHeaderTextLeft( u"HeaderTextLeft" ); +constexpr OUStringLiteral gsFirstShareContent( u"FirstIsShared" ); +constexpr OUStringLiteral gsFooterText( u"FooterText" ); +constexpr OUStringLiteral gsFooterOn( u"FooterIsOn" ); +constexpr OUStringLiteral gsFooterShareContent( u"FooterIsShared" ); +constexpr OUStringLiteral gsFooterTextFirst( u"FooterTextFirst" ); +constexpr OUStringLiteral gsFooterTextLeft( u"FooterTextLeft" ); + +XMLTextMasterPageExport::XMLTextMasterPageExport( SvXMLExport& rExp ) : + XMLPageExport( rExp ) +{ +} + +XMLTextMasterPageExport::~XMLTextMasterPageExport() +{ +} + + +void XMLTextMasterPageExport::exportHeaderFooterContent( + const Reference< XText >& rText, + bool bAutoStyles, bool bExportParagraph ) +{ + SAL_WARN_IF( !rText.is(), "xmloff", "There is the text" ); + + // tracked changes (autostyles + changes list) + GetExport().GetTextParagraphExport()->recordTrackedChangesForXText(rText); + GetExport().GetTextParagraphExport()->exportTrackedChanges(rText, + bAutoStyles); + if( bAutoStyles ) + GetExport().GetTextParagraphExport() + ->collectTextAutoStyles( rText, true, bExportParagraph ); + else + { + GetExport().GetTextParagraphExport()->exportTextDeclarations( rText ); + GetExport().GetTextParagraphExport()->exportText( rText, true, bExportParagraph ); + } + + // tracked changes (end of XText) + GetExport().GetTextParagraphExport()->recordTrackedChangesNoXText(); +} + +void XMLTextMasterPageExport::exportMasterPageContent( + const Reference < XPropertySet > & rPropSet, + bool bAutoStyles ) +{ + Any aAny; + + Reference < XText > xHeaderText; + aAny = rPropSet->getPropertyValue( gsHeaderText ); + aAny >>= xHeaderText; + + Reference < XText > xHeaderTextFirst; + aAny = rPropSet->getPropertyValue( gsHeaderTextFirst ); + aAny >>= xHeaderTextFirst; + + Reference < XText > xHeaderTextLeft; + aAny = rPropSet->getPropertyValue( gsHeaderTextLeft ); + aAny >>= xHeaderTextLeft; + + Reference < XText > xFooterText; + aAny = rPropSet->getPropertyValue( gsFooterText ); + aAny >>= xFooterText; + + Reference < XText > xFooterTextFirst; + aAny = rPropSet->getPropertyValue( gsFooterTextFirst ); + aAny >>= xFooterTextFirst; + + Reference < XText > xFooterTextLeft; + aAny = rPropSet->getPropertyValue( gsFooterTextLeft ); + aAny >>= xFooterTextLeft; + + if( bAutoStyles ) + { + if( xHeaderText.is() ) + exportHeaderFooterContent( xHeaderText, true ); + if( xHeaderTextFirst.is() && xHeaderTextFirst != xHeaderText ) + exportHeaderFooterContent( xHeaderTextFirst, true ); + if( xHeaderTextLeft.is() && xHeaderTextLeft != xHeaderText ) + exportHeaderFooterContent( xHeaderTextLeft, true ); + if( xFooterText.is() ) + exportHeaderFooterContent( xFooterText, true ); + if( xFooterTextFirst.is() && xFooterTextFirst != xFooterText ) + exportHeaderFooterContent( xFooterTextFirst, true ); + if( xFooterTextLeft.is() && xFooterTextLeft != xFooterText ) + exportHeaderFooterContent( xFooterTextLeft, true ); + } + else + { + auto const nVersion(GetExport().getSaneDefaultVersion()); + + aAny = rPropSet->getPropertyValue( gsHeaderOn ); + bool bHeader = false; + aAny >>= bHeader; + + bool bHeaderFirstShared = false; + if( bHeader ) + { + aAny = rPropSet->getPropertyValue( gsFirstShareContent ); + aAny >>= bHeaderFirstShared; + } + + bool bHeaderLeftShared = false; + if( bHeader ) + { + aAny = rPropSet->getPropertyValue( gsHeaderShareContent ); + aAny >>= bHeaderLeftShared; + } + + if( xHeaderText.is() ) + { + if( !bHeader ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_HEADER, true, true ); + exportHeaderFooterContent( xHeaderText, false ); + } + + if( xHeaderTextLeft.is() && xHeaderTextLeft != xHeaderText ) + { + if (bHeaderLeftShared) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_HEADER_LEFT, true, true ); + exportHeaderFooterContent( xHeaderTextLeft, false ); + } + + if (xHeaderTextFirst.is() && xHeaderTextFirst != xHeaderText + && SvtSaveOptions::ODFSVER_012 < nVersion) + { + if (bHeaderFirstShared) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + // ODF 1.3 OFFICE-3789 + SvXMLElementExport aElem( GetExport(), + SvtSaveOptions::ODFSVER_013 <= nVersion + ? XML_NAMESPACE_STYLE + : XML_NAMESPACE_LO_EXT, + XML_HEADER_FIRST, true, true ); + exportHeaderFooterContent( xHeaderTextFirst, false ); + } + + aAny = rPropSet->getPropertyValue( gsFooterOn ); + bool bFooter = false; + aAny >>= bFooter; + + bool bFooterFirstShared = false; + if( bFooter ) + { + aAny = rPropSet->getPropertyValue( gsFirstShareContent ); + aAny >>= bFooterFirstShared; + } + + bool bFooterLeftShared = false; + if( bFooter ) + { + aAny = rPropSet->getPropertyValue( gsFooterShareContent ); + aAny >>= bFooterLeftShared; + } + + if( xFooterText.is() ) + { + if( !bFooter ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_FOOTER, true, true ); + exportHeaderFooterContent( xFooterText, false ); + } + + if( xFooterTextLeft.is() && xFooterTextLeft != xFooterText ) + { + if (bFooterLeftShared) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_STYLE, + XML_FOOTER_LEFT, true, true ); + exportHeaderFooterContent( xFooterTextLeft, false ); + } + + if (xFooterTextFirst.is() && xFooterTextFirst != xFooterText + && SvtSaveOptions::ODFSVER_012 < nVersion) + { + if (bFooterFirstShared) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DISPLAY, XML_FALSE ); + // ODF 1.3 OFFICE-3789 + SvXMLElementExport aElem( GetExport(), + SvtSaveOptions::ODFSVER_013 <= nVersion + ? XML_NAMESPACE_STYLE + : XML_NAMESPACE_LO_EXT, + XML_FOOTER_FIRST, true, true ); + exportHeaderFooterContent( xFooterTextFirst, false ); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextMasterStylesContext.cxx b/xmloff/source/text/XMLTextMasterStylesContext.cxx new file mode 100644 index 000000000..91e637b91 --- /dev/null +++ b/xmloff/source/text/XMLTextMasterStylesContext.cxx @@ -0,0 +1,67 @@ +/* -*- 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 +#include +#include + +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +using ::xmloff::token::IsXMLToken; +using ::xmloff::token::XML_MASTER_PAGE; + + +bool XMLTextMasterStylesContext::InsertStyleFamily( XmlStyleFamily ) const +{ + return true; +} + +XMLTextMasterStylesContext::XMLTextMasterStylesContext( + SvXMLImport& rImport ) : + SvXMLStylesContext( rImport ) +{ +} + +XMLTextMasterStylesContext::~XMLTextMasterStylesContext() +{ +} + +SvXMLStyleContext *XMLTextMasterStylesContext::CreateStyleChildContext( + sal_Int32 nElement, + const Reference< XFastAttributeList > & xAttrList ) +{ + SvXMLStyleContext *pContext = nullptr; + + if( nElement == XML_ELEMENT(STYLE, XML_MASTER_PAGE) && + InsertStyleFamily( XmlStyleFamily::MASTER_PAGE ) ) + pContext = new XMLTextMasterPageContext( + GetImport(), nElement, + xAttrList, + !GetImport().GetTextImport()->IsInsertMode() ); + + // any other style will be ignored here! + + return pContext; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextNumRuleInfo.cxx b/xmloff/source/text/XMLTextNumRuleInfo.cxx new file mode 100644 index 000000000..062b92879 --- /dev/null +++ b/xmloff/source/text/XMLTextNumRuleInfo.cxx @@ -0,0 +1,226 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "XMLTextNumRuleInfo.hxx" +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::style; + +// Complete refactoring of the class and enhancement of the class for lists. +XMLTextNumRuleInfo::XMLTextNumRuleInfo() + : mbListIdIsDefault(false) + , mnListStartValue( -1 ) + , mnListLevel( 0 ) + , mbIsNumbered( false ) + , mbIsRestart( false ) + , mnListLevelStartValue( -1 ) + , mbOutlineStyleAsNormalListStyle( false ) +{ + Reset(); +} + +// Written OpenDocument file format doesn't fit to the created text document (#i69627#) +void XMLTextNumRuleInfo::Set( + const css::uno::Reference < css::text::XTextContent > & xTextContent, + const bool bOutlineStyleAsNormalListStyle, + const XMLTextListAutoStylePool& rListAutoPool, + const bool bExportTextNumberElement ) +{ + Reset(); + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + mbOutlineStyleAsNormalListStyle = bOutlineStyleAsNormalListStyle; + + Reference< XPropertySet > xPropSet( xTextContent, UNO_QUERY ); + Reference xPropState(xTextContent, UNO_QUERY); + Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo(); + + // check if this paragraph supports a numbering + if( !xPropSetInfo->hasPropertyByName( "NumberingLevel" ) ) + return; + + if( xPropSet->getPropertyValue( "NumberingLevel" ) >>= mnListLevel ) + { + if( xPropSetInfo->hasPropertyByName( "NumberingRules" ) ) + { + xPropSet->getPropertyValue( "NumberingRules" ) >>= mxNumRules; + } + } + else + { + // in applications using the outliner we always have a numbering rule, + // so a void property no numbering + mnListLevel = 0; + } + + // Assertion saving writer document (#i97312#) + if ( mxNumRules.is() && mxNumRules->getCount() < 1 ) + { + SAL_WARN("xmloff", + " - numbering rules instance does not contain any numbering rule" ); + Reset(); + return; + } + + if ( mnListLevel < 0 ) + { + SAL_WARN("xmloff", + " - unexpected numbering level" ); + Reset(); + return; + } + + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + bool bSuppressListStyle( false ); + if ( mxNumRules.is() ) + { + if ( !mbOutlineStyleAsNormalListStyle ) + { + Reference xNumRulesProps(mxNumRules, UNO_QUERY); + if ( xNumRulesProps.is() && + xNumRulesProps->getPropertySetInfo()-> + hasPropertyByName( "NumberingIsOutline" ) ) + { + bool bIsOutline = false; + xNumRulesProps->getPropertyValue( "NumberingIsOutline" ) >>= bIsOutline; + bSuppressListStyle = bIsOutline; + } + } + } + + if( mxNumRules.is() && !bSuppressListStyle ) + { + // First try to find the numbering rules in the list auto style pool. + // If not found, the numbering rules instance has to be named. + msNumRulesName = rListAutoPool.Find( mxNumRules ); + if ( msNumRulesName.isEmpty() ) + { + Reference < XNamed > xNamed( mxNumRules, UNO_QUERY ); + SAL_WARN_IF( !xNamed.is(), "xmloff", + " - numbering rules instance have to be named. Serious defect." ); + if( xNamed.is() ) + { + msNumRulesName = xNamed->getName(); + } + } + SAL_WARN_IF( msNumRulesName.isEmpty(), "xmloff", + " - no name found for numbering rules instance. Serious defect." ); + + if( xPropSetInfo->hasPropertyByName( "ListId" ) ) + { + xPropSet->getPropertyValue( "ListId" ) >>= msListId; + + if (xPropState.is()) + { + mbListIdIsDefault + = xPropState->getPropertyState("ListId") == PropertyState_DEFAULT_VALUE; + } + } + + mbContinueingPreviousSubTree = false; + if( xPropSetInfo->hasPropertyByName( "ContinueingPreviousSubTree" ) ) + { + xPropSet->getPropertyValue( "ContinueingPreviousSubTree" ) >>= mbContinueingPreviousSubTree; + } + + mbIsNumbered = true; + if( xPropSetInfo->hasPropertyByName( "NumberingIsNumber" ) ) + { + if( !(xPropSet->getPropertyValue( "NumberingIsNumber" ) >>= mbIsNumbered ) ) + { + OSL_FAIL( "numbered paragraph without number info" ); + mbIsNumbered = false; + } + } + + if( mbIsNumbered ) + { + if( xPropSetInfo->hasPropertyByName( "ParaIsNumberingRestart" ) ) + { + xPropSet->getPropertyValue( "ParaIsNumberingRestart" ) >>= mbIsRestart; + } + if( xPropSetInfo->hasPropertyByName( "NumberingStartValue" ) ) + { + xPropSet->getPropertyValue( "NumberingStartValue" ) >>= mnListStartValue; + } + } + + OSL_ENSURE( mnListLevel < mxNumRules->getCount(), "wrong num rule level" ); + if( mnListLevel >= mxNumRules->getCount() ) + { + Reset(); + return; + } + + Sequence aProps; + mxNumRules->getByIndex( mnListLevel ) >>= aProps; + + auto pProp = std::find_if(std::cbegin(aProps), std::cend(aProps), + [](const PropertyValue& rProp) { return rProp.Name == "StartWith"; }); + if (pProp != std::cend(aProps)) + { + pProp->Value >>= mnListLevelStartValue; + } + + msListLabelString.clear(); + if ( bExportTextNumberElement && + xPropSetInfo->hasPropertyByName( "ListLabelString" ) ) + { + xPropSet->getPropertyValue( "ListLabelString" ) >>= msListLabelString; + } + + // paragraph's list level range is [0..9] representing list levels [1..10] + ++mnListLevel; + } + else + { + mnListLevel = 0; + } +} + +bool XMLTextNumRuleInfo::BelongsToSameList( const XMLTextNumRuleInfo& rCmp ) const +{ + bool bRet( true ); + // Currently only the text documents support . + if ( !rCmp.msListId.isEmpty() || !msListId.isEmpty() ) + { + bRet = rCmp.msListId == msListId; + } + else + { + bRet = rCmp.msNumRulesName == msNumRulesName; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextNumRuleInfo.hxx b/xmloff/source/text/XMLTextNumRuleInfo.hxx new file mode 100644 index 000000000..adb405411 --- /dev/null +++ b/xmloff/source/text/XMLTextNumRuleInfo.hxx @@ -0,0 +1,157 @@ +/* -*- 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 +#include +#include + +namespace com::sun::star { + namespace text { class XTextContent; } +} + +class XMLTextListAutoStylePool; + +/** information about list and list style for a certain paragraph + + OD 2008-04-24 #refactorlists# + Complete refactoring of the class and enhancement of the class for lists. + These changes are considered by method +*/ +class XMLTextNumRuleInfo +{ + // numbering rules instance and its name + css::uno::Reference < css::container::XIndexReplace > mxNumRules; + OUString msNumRulesName; + + // paragraph's list attributes + OUString msListId; + /// msListId won't be referenced by later lists. + bool mbListIdIsDefault; + sal_Int16 mnListStartValue; + sal_Int16 mnListLevel; + bool mbIsNumbered; + bool mbIsRestart; + + // numbering rules' attributes + sal_Int16 mnListLevelStartValue; + + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + bool mbOutlineStyleAsNormalListStyle; + + bool mbContinueingPreviousSubTree; + OUString msListLabelString; + +public: + + XMLTextNumRuleInfo(); + + inline XMLTextNumRuleInfo& operator=( const XMLTextNumRuleInfo& rInfo ); + + void Set( const css::uno::Reference < css::text::XTextContent > & rTextContent, + const bool bOutlineStyleAsNormalListStyle, + const XMLTextListAutoStylePool& rListAutoPool, + const bool bExportTextNumberElement ); + inline void Reset(); + + const OUString& GetNumRulesName() const + { + return msNumRulesName; + } + sal_Int16 GetListLevelStartValue() const + { + return mnListLevelStartValue; + } + + const OUString& GetListId() const + { + return msListId; + } + + bool IsListIdDefault() const { return mbListIdIsDefault; } + + sal_Int16 GetLevel() const + { + return mnListLevel; + } + + bool HasStartValue() const + { + return mnListStartValue != -1; + } + sal_uInt32 GetStartValue() const + { + return mnListStartValue; + } + + bool IsNumbered() const + { + return mbIsNumbered; + } + bool IsRestart() const + { + return mbIsRestart; + } + + bool BelongsToSameList( const XMLTextNumRuleInfo& rCmp ) const; + + bool IsContinueingPreviousSubTree() const + { + return mbContinueingPreviousSubTree; + } + const OUString& ListLabelString() const + { + return msListLabelString; + } +}; + +inline XMLTextNumRuleInfo& XMLTextNumRuleInfo::operator=( + const XMLTextNumRuleInfo& rInfo ) +{ + msNumRulesName = rInfo.msNumRulesName; + mxNumRules = rInfo.mxNumRules; + msListId = rInfo.msListId; + mnListStartValue = rInfo.mnListStartValue; + mnListLevel = rInfo.mnListLevel; + mbIsNumbered = rInfo.mbIsNumbered; + mbIsRestart = rInfo.mbIsRestart; + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + mbOutlineStyleAsNormalListStyle = rInfo.mbOutlineStyleAsNormalListStyle; + mbContinueingPreviousSubTree = rInfo.mbContinueingPreviousSubTree; + msListLabelString = rInfo.msListLabelString; + + return *this; +} + +inline void XMLTextNumRuleInfo::Reset() +{ + mxNumRules = nullptr; + msNumRulesName.clear(); + msListId.clear(); + mnListStartValue = -1; + mnListLevel = 0; + // Written OpenDocument file format doesn't fit to the created text document (#i69627#) + mbIsNumbered = mbIsRestart = + mbOutlineStyleAsNormalListStyle = false; + mbContinueingPreviousSubTree = false; + msListLabelString.clear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextPropertySetContext.cxx b/xmloff/source/text/XMLTextPropertySetContext.cxx new file mode 100644 index 000000000..b2db201ca --- /dev/null +++ b/xmloff/source/text/XMLTextPropertySetContext.cxx @@ -0,0 +1,131 @@ +/* -*- 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 +#include "XMLTextPropertySetContext.hxx" +#include +#include +#include "XMLSectionFootnoteConfigImport.hxx" + +#include +#include +#include +#include "txtdropi.hxx" + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +XMLTextPropertySetContext::XMLTextPropertySetContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + OUString& rDCTextStyleName ) : + SvXMLPropertySetContext( rImport, nElement, xAttrList, nFamily, + rProps, rMap ), + rDropCapTextStyleName( rDCTextStyleName ) +{ +} + +XMLTextPropertySetContext::~XMLTextPropertySetContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextPropertySetContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + switch( mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_TABSTOP: + return new SvxXMLTabStopImportContext( GetImport(), nElement, + rProp, + rProperties ); + break; + case CTF_TEXTCOLUMNS: + return new XMLTextColumnsContext( GetImport(), nElement, + xAttrList, rProp, + rProperties ); + break; + + case CTF_DROPCAPFORMAT: + { + DBG_ASSERT( rProp.mnIndex >= 2 && + CTF_DROPCAPWHOLEWORD == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-2 ), + "invalid property map!"); + XMLTextDropCapImportContext *pDCContext = + new XMLTextDropCapImportContext( GetImport(), nElement, + xAttrList, + rProp, + rProp.mnIndex-2, + rProperties ); + rDropCapTextStyleName = pDCContext->GetStyleName(); + return pDCContext; + } + break; + + case CTF_BACKGROUND_URL: + { + DBG_ASSERT( rProp.mnIndex >= 2 && + CTF_BACKGROUND_POS == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-2 ) && + CTF_BACKGROUND_FILTER == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-1 ), + "invalid property map!"); + + // #99657# Transparency might be there as well... but doesn't have + // to. Thus, this is checked with an if, rather than with an assertion. + sal_Int32 nTranspIndex = -1; + if( (rProp.mnIndex >= 3) && + ( CTF_BACKGROUND_TRANSPARENCY == + mxMapper->getPropertySetMapper()->GetEntryContextId( + rProp.mnIndex-3 ) ) ) + nTranspIndex = rProp.mnIndex-3; + + return + new XMLBackgroundImageContext( GetImport(), nElement, + xAttrList, + rProp, + rProp.mnIndex-2, + rProp.mnIndex-1, + nTranspIndex, + -1, + rProperties ); + } + break; + case CTF_SECTION_FOOTNOTE_END: + case CTF_SECTION_ENDNOTE_END: + return new XMLSectionFootnoteConfigImport( + GetImport(), nElement, rProperties, + mxMapper->getPropertySetMapper()); + break; + } + + return SvXMLPropertySetContext::createFastChildContext( nElement, + xAttrList, + rProperties, rProp ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextPropertySetContext.hxx b/xmloff/source/text/XMLTextPropertySetContext.hxx new file mode 100644 index 000000000..2286e773f --- /dev/null +++ b/xmloff/source/text/XMLTextPropertySetContext.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 + + +class XMLTextPropertySetContext : public SvXMLPropertySetContext +{ +// SvXMLImportContextRef xTabStop; +// SvXMLImportContextRef xBackground; +// SvXMLImportContextRef xDropCap; + OUString& rDropCapTextStyleName; + +public: + XMLTextPropertySetContext( SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference& xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap, + OUString& rDopCapTextStyleName ); + + virtual ~XMLTextPropertySetContext() override; + + using SvXMLPropertySetContext::createFastChildContext; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextShapeImportHelper.cxx b/xmloff/source/text/XMLTextShapeImportHelper.cxx new file mode 100644 index 000000000..21c6c3134 --- /dev/null +++ b/xmloff/source/text/XMLTextShapeImportHelper.cxx @@ -0,0 +1,149 @@ +/* -*- 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 +#include + +#include + +#include +#include +#include +#include +#include +#include "XMLAnchorTypePropHdl.hxx" +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +constexpr OUStringLiteral gsAnchorType(u"AnchorType"); +constexpr OUStringLiteral gsAnchorPageNo(u"AnchorPageNo"); +constexpr OUStringLiteral gsVertOrientPosition(u"VertOrientPosition"); + +XMLTextShapeImportHelper::XMLTextShapeImportHelper( + SvXMLImport& rImp ) : + XMLShapeImportHelper( rImp, rImp.GetModel(), + XMLTextImportHelper::CreateShapeExtPropMapper(rImp) ), + rImport( rImp ) +{ + Reference < XDrawPageSupplier > xDPS( rImp.GetModel(), UNO_QUERY ); + if( xDPS.is() ) + { + Reference < XShapes > xShapes = xDPS->getDrawPage(); + pushGroupForPostProcessing( xShapes ); + } + +} + +XMLTextShapeImportHelper::~XMLTextShapeImportHelper() +{ + popGroupAndPostProcess(); +} + +void XMLTextShapeImportHelper::addShape( + Reference< XShape >& rShape, + const Reference< XFastAttributeList >& xAttrList, + Reference< XShapes >& rShapes ) +{ + if( rShapes.is() ) + { + // It's a group shape or 3DScene , so we have to call the base class method. + XMLShapeImportHelper::addShape( rShape, xAttrList, rShapes ); + return; + } + + TextContentAnchorType eAnchorType = TextContentAnchorType_AT_PARAGRAPH; + sal_Int16 nPage = 0; + sal_Int32 nY = 0; + + rtl::Reference < XMLTextImportHelper > xTxtImport = + rImport.GetTextImport(); + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(TEXT, XML_ANCHOR_TYPE): + { + TextContentAnchorType eNew; + // OD 2004-06-01 #i26791# - allow all anchor types + if ( XMLAnchorTypePropHdl::convert( aIter.toView(), eNew ) ) + { + eAnchorType = eNew; + } + } + break; + case XML_ELEMENT(TEXT, XML_ANCHOR_PAGE_NUMBER): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, aIter.toView(), 1, SHRT_MAX)) + nPage = static_cast(nTmp); + } + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + rImport.GetMM100UnitConverter().convertMeasureToCore( nY, aIter.toView() ); + break; + } + } + + Reference < XPropertySet > xPropSet( rShape, UNO_QUERY ); + + // anchor type + xPropSet->setPropertyValue( gsAnchorType, Any(eAnchorType) ); + + // page number must be set before the frame is inserted + switch( eAnchorType ) + { + case TextContentAnchorType_AT_PAGE: + // only set positive page numbers + if ( nPage > 0 ) + { + xPropSet->setPropertyValue( gsAnchorPageNo, Any(nPage) ); + } + break; + default: + break; + } + + Reference < XTextContent > xTxtCntnt( rShape, UNO_QUERY ); + xTxtImport->InsertTextContent( xTxtCntnt ); + + switch( eAnchorType ) + { + case TextContentAnchorType_AS_CHARACTER: + xPropSet->setPropertyValue( gsVertOrientPosition, Any(nY) ); + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextShapeStyleContext.cxx b/xmloff/source/text/XMLTextShapeStyleContext.cxx new file mode 100644 index 000000000..81df6cf85 --- /dev/null +++ b/xmloff/source/text/XMLTextShapeStyleContext.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +namespace { + +class XMLTextShapePropertySetContext_Impl : public XMLShapePropertySetContext +{ +public: + XMLTextShapePropertySetContext_Impl( SvXMLImport& rImport, sal_Int32 nElement, + const Reference< XFastAttributeList >& xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ); + + using SvXMLPropertySetContext::createFastChildContext; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) override; +}; + +} + +XMLTextShapePropertySetContext_Impl::XMLTextShapePropertySetContext_Impl( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< XFastAttributeList > & xAttrList, + sal_uInt32 nFamily, + ::std::vector< XMLPropertyState > &rProps, + const rtl::Reference < SvXMLImportPropertyMapper > &rMap ) : + XMLShapePropertySetContext( rImport, nElement, xAttrList, nFamily, + rProps, rMap ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextShapePropertySetContext_Impl::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList, + ::std::vector< XMLPropertyState > &rProperties, + const XMLPropertyState& rProp ) +{ + switch( mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex ) ) + { + case CTF_TEXTCOLUMNS: + return new XMLTextColumnsContext( GetImport(), nElement, + xAttrList, rProp, + rProperties ); + break; + + case CTF_BACKGROUND_URL: + DBG_ASSERT( rProp.mnIndex >= 3 && + CTF_BACKGROUND_TRANSPARENCY == + mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-3 ) && + CTF_BACKGROUND_POS == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-2 ) && + CTF_BACKGROUND_FILTER == mxMapper->getPropertySetMapper() + ->GetEntryContextId( rProp.mnIndex-1 ), + "invalid property map!"); + return + new XMLBackgroundImageContext( GetImport(), nElement, + xAttrList, + rProp, + rProp.mnIndex-2, + rProp.mnIndex-1, + rProp.mnIndex-3, + -1, + rProperties ); + break; + } + + return XMLShapePropertySetContext::createFastChildContext( + nElement, xAttrList, rProperties, rProp ); +} + +void XMLTextShapeStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + if( nElement == XML_ELEMENT(STYLE, XML_AUTO_UPDATE) ) + { + if( IsXMLToken( rValue, XML_TRUE ) ) + bAutoUpdate = true; + } + else + { + XMLShapeStyleContext::SetAttribute( nElement, rValue ); + } +} + + +constexpr OUStringLiteral gsIsAutoUpdate( u"IsAutoUpdate" ); + +XMLTextShapeStyleContext::XMLTextShapeStyleContext( SvXMLImport& rImport, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily ) : + XMLShapeStyleContext( rImport, rStyles, nFamily ), + bAutoUpdate( false ) +{ +} + +XMLTextShapeStyleContext::~XMLTextShapeStyleContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextShapeStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) || + IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + sal_uInt32 nFamily = 0; + if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_GRAPHIC_PROPERTIES ) + nFamily = XML_TYPE_PROP_GRAPHIC; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + { + return new XMLTextShapePropertySetContext_Impl( + GetImport(), nElement, xAttrList, nFamily, + GetProperties(), xImpPrMap ); + } + } + } + else if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + // create and remember events import context + // (for delayed processing of events) + xEventContext = new XMLEventsImportContext( GetImport() ); + return xEventContext; + } + + return XMLShapeStyleContext::createFastChildContext( nElement, xAttrList ); +} + +void XMLTextShapeStyleContext::CreateAndInsert( bool bOverwrite ) +{ + XMLShapeStyleContext::CreateAndInsert( bOverwrite ); + Reference < XStyle > xStyle = GetStyle(); + if( !xStyle.is() || !(bOverwrite || IsNew()) ) + return; + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + if( xPropSetInfo->hasPropertyByName( gsIsAutoUpdate ) ) + { + bool bTmp = bAutoUpdate; + xPropSet->setPropertyValue( gsIsAutoUpdate, Any(bTmp) ); + } + + // tell the style about it's events (if applicable) + if( xEventContext.is() ) + { + // set event supplier and release reference to context + Reference xEventsSupplier(xStyle, UNO_QUERY); + xEventContext->SetEvents(xEventsSupplier); + xEventContext = nullptr; + } +} + +void XMLTextShapeStyleContext::Finish( bool bOverwrite ) +{ + XMLPropStyleContext::Finish( bOverwrite ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTextTableContext.cxx b/xmloff/source/text/XMLTextTableContext.cxx new file mode 100644 index 000000000..2a56c0e60 --- /dev/null +++ b/xmloff/source/text/XMLTextTableContext.cxx @@ -0,0 +1,35 @@ +/* -*- 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 + + +using namespace ::com::sun::star::uno; + + +XMLTextTableContext::XMLTextTableContext( SvXMLImport& rImport ) : + SvXMLImportContext( rImport ) +{ +} + +XMLTextTableContext::~XMLTextTableContext() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTrackedChangesImportContext.cxx b/xmloff/source/text/XMLTrackedChangesImportContext.cxx new file mode 100644 index 000000000..63e0d1497 --- /dev/null +++ b/xmloff/source/text/XMLTrackedChangesImportContext.cxx @@ -0,0 +1,84 @@ +/* -*- 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 "XMLTrackedChangesImportContext.hxx" +#include "XMLChangedRegionImportContext.hxx" +#include +#include +#include +#include +#include +#include +#include + + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::xml::sax::XAttributeList; +using namespace ::xmloff::token; + + +XMLTrackedChangesImportContext::XMLTrackedChangesImportContext( + SvXMLImport& rImport) : + SvXMLImportContext(rImport) +{ +} + +XMLTrackedChangesImportContext::~XMLTrackedChangesImportContext() +{ +} + +void XMLTrackedChangesImportContext::startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + bool bTrackChanges = true; + + // scan for text:track-changes and text:protection-key attributes + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(TEXT, XML_TRACK_CHANGES) ) + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + { + bTrackChanges = bTmp; + } + break; + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + + // set tracked changes + GetImport().GetTextImport()->SetRecordChanges( bTrackChanges ); +} + + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTrackedChangesImportContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_CHANGED_REGION) ) + { + return new XMLChangedRegionImportContext(GetImport()); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/XMLTrackedChangesImportContext.hxx b/xmloff/source/text/XMLTrackedChangesImportContext.hxx new file mode 100644 index 000000000..6ae3c4a55 --- /dev/null +++ b/xmloff/source/text/XMLTrackedChangesImportContext.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/. + * + * 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 +#include + +namespace com::sun::star { + namespace xml::sax { + class XAttributeList; + } +} + +class XMLTrackedChangesImportContext : public SvXMLImportContext +{ +public: + + XMLTrackedChangesImportContext(SvXMLImport& rImport); + + virtual ~XMLTrackedChangesImportContext() override; + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtdrope.cxx b/xmloff/source/text/txtdrope.cxx new file mode 100644 index 000000000..5013d422c --- /dev/null +++ b/xmloff/source/text/txtdrope.cxx @@ -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/. + * + * 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 +#include +#include +#include +#include +#include +#include "txtdrope.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::uno; + +using namespace ::xmloff::token; + + +XMLTextDropCapExport::XMLTextDropCapExport( SvXMLExport& rExp ) : + rExport(rExp) +{ +} + +void XMLTextDropCapExport::exportXML( const Any& rAny, + bool bWholeWord, + const OUString& rStyleName ) +{ + DropCapFormat aFormat; + rAny >>= aFormat; + if( aFormat.Lines > 1 ) + { + SvXMLUnitConverter& rUnitConv = rExport.GetMM100UnitConverter(); + + // style:lines + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LINES, + OUString::number( aFormat.Lines ) ); + + // style:length + OUString sValue; + if( bWholeWord ) + { + sValue = GetXMLToken(XML_WORD); + } + else if( aFormat.Count > 1 ) + { + sValue = OUString::number(aFormat.Count); + } + if( !sValue.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_LENGTH, sValue ); + + // style:distance + if( aFormat.Distance > 0 ) + { + OUStringBuffer sBuffer; + rUnitConv.convertMeasureToXML( sBuffer, aFormat.Distance ); + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_DISTANCE, + sBuffer.makeStringAndClear() ); + } + + // style:style-name + if( !rStyleName.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_STYLE, XML_STYLE_NAME, + rExport.EncodeStyleName( rStyleName ) ); + } + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_STYLE, XML_DROP_CAP, + false, false ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtdrope.hxx b/xmloff/source/text/txtdrope.hxx new file mode 100644 index 000000000..6e6b05a0b --- /dev/null +++ b/xmloff/source/text/txtdrope.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/. + * + * 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 + +class SvXMLExport; +namespace com::sun::star::uno { class Any; } + +class XMLTextDropCapExport +{ + SvXMLExport& rExport; + +public: + + explicit XMLTextDropCapExport( SvXMLExport& rExport ); + + void exportXML( const css::uno::Any& rAny, + bool bWholeWord, + const OUString& rStyleName ); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtdropi.cxx b/xmloff/source/text/txtdropi.cxx new file mode 100644 index 000000000..66b219884 --- /dev/null +++ b/xmloff/source/text/txtdropi.cxx @@ -0,0 +1,122 @@ +/* -*- 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 "txtdropi.hxx" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + +void XMLTextDropCapImportContext::ProcessAttrs( + const Reference< xml::sax::XFastAttributeList >& xAttrList ) +{ + DropCapFormat aFormat; + bool bWholeWord = false; + + sal_Int32 nTmp; + for (auto &aIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(STYLE, XML_LINES): + if (::sax::Converter::convertNumber( nTmp, aIter.toView(), 0, 255 )) + { + aFormat.Lines = nTmp < 2 ? 0 : static_cast(nTmp); + } + break; + + case XML_ELEMENT(STYLE, XML_LENGTH): + if( IsXMLToken( aIter, XML_WORD ) ) + { + bWholeWord = true; + } + else if (::sax::Converter::convertNumber( nTmp, aIter.toView(), 1, 255 )) + { + bWholeWord = false; + aFormat.Count = static_cast(nTmp); + } + break; + + case XML_ELEMENT(STYLE, XML_DISTANCE): + if (GetImport().GetMM100UnitConverter().convertMeasureToCore( + nTmp, aIter.toView(), 0 )) + { + aFormat.Distance = static_cast(nTmp); + } + break; + + case XML_ELEMENT(STYLE, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( aFormat.Lines > 1 && aFormat.Count < 1 ) + aFormat.Count = 1; + + aProp.maValue <<= aFormat; + + aWholeWordProp.maValue <<= bWholeWord; +} + +XMLTextDropCapImportContext::XMLTextDropCapImportContext( + SvXMLImport& rImport, sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + const XMLPropertyState& rProp, + sal_Int32 nWholeWordIdx, + ::std::vector< XMLPropertyState > &rProps ) : + XMLElementPropertyContext( rImport, nElement, rProp, rProps ), + aWholeWordProp( nWholeWordIdx ) +{ + ProcessAttrs( xAttrList ); +} + +XMLTextDropCapImportContext::~XMLTextDropCapImportContext() +{ +} + +void XMLTextDropCapImportContext::endFastElement(sal_Int32 nElement) +{ + SetInsert( true ); + XMLElementPropertyContext::endFastElement(nElement); + + if( -1 != aWholeWordProp.mnIndex ) + rProperties.push_back( aWholeWordProp ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtdropi.hxx b/xmloff/source/text/txtdropi.hxx new file mode 100644 index 000000000..4a9d24b10 --- /dev/null +++ b/xmloff/source/text/txtdropi.hxx @@ -0,0 +1,46 @@ +/* -*- 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 + +class XMLTextDropCapImportContext : public XMLElementPropertyContext +{ + XMLPropertyState aWholeWordProp; + OUString sStyleName; + +private: + void ProcessAttrs(const css::uno::Reference& xAttrList); + +public: + XMLTextDropCapImportContext( + SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference& xAttrList, + const XMLPropertyState& rProp, sal_Int32 nWholeWOrdIdx, + ::std::vector& rProps); + + virtual ~XMLTextDropCapImportContext() override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + const OUString& GetStyleName() const { return sStyleName; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtexppr.cxx b/xmloff/source/text/txtexppr.cxx new file mode 100644 index 000000000..65cdf59b7 --- /dev/null +++ b/xmloff/source/text/txtexppr.cxx @@ -0,0 +1,1199 @@ +/* -*- 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 + +#include "txtexppr.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "XMLSectionFootnoteConfigExport.hxx" +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; + +void XMLTextExportPropertySetMapper::handleElementItem( + SvXMLExport& rExp, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + XMLTextExportPropertySetMapper *pThis = + const_cast(this); + + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_DROPCAPFORMAT: + pThis->maDropCapExport.exportXML( rProperty.maValue, bDropWholeWord, + sDropCharStyle ); + pThis->bDropWholeWord = false; + pThis->sDropCharStyle.clear(); + break; + + case CTF_TABSTOP: + pThis->maTabStopExport.Export( rProperty.maValue ); + break; + + case CTF_TEXTCOLUMNS: + pThis->maTextColumnsExport.exportXML( rProperty.maValue ); + break; + + case CTF_BACKGROUND_URL: + { + const Any *pPos = nullptr, *pFilter = nullptr, *pTrans = nullptr; + sal_uInt32 nPropIndex = rProperty.mnIndex; + + // these are all optional, so have to check them in order + // note: this index order dependency is a steaming pile of manure + if (nIdx) + { + const XMLPropertyState& rFilter = (*pProperties)[nIdx - 1]; + if (CTF_BACKGROUND_FILTER == getPropertySetMapper() + ->GetEntryContextId(rFilter.mnIndex)) + { + pFilter = &rFilter.maValue; + --nIdx; + } + } + + if (nIdx) + { + const XMLPropertyState& rPos = (*pProperties)[nIdx - 1]; + if (CTF_BACKGROUND_POS == getPropertySetMapper() + ->GetEntryContextId(rPos.mnIndex)) + { + pPos = &rPos.maValue; + --nIdx; + } + } + + if (nIdx) + { + const XMLPropertyState& rTrans = (*pProperties)[nIdx - 1]; + // #99657# transparency may be there, but doesn't have to be. + // If it's there, it must be in the right position. + if( CTF_BACKGROUND_TRANSPARENCY == getPropertySetMapper() + ->GetEntryContextId( rTrans.mnIndex ) ) + pTrans = &rTrans.maValue; + } + + pThis->maBackgroundImageExport.exportXML( + rProperty.maValue, pPos, pFilter, pTrans, + getPropertySetMapper()->GetEntryNameSpace( nPropIndex ), + getPropertySetMapper()->GetEntryXMLName( nPropIndex ) ); + } + break; + + case CTF_SECTION_FOOTNOTE_END: + XMLSectionFootnoteConfigExport::exportXML(rExp, false, + pProperties, nIdx, + getPropertySetMapper()); + break; + + case CTF_SECTION_ENDNOTE_END: + XMLSectionFootnoteConfigExport::exportXML(rExp, true, + pProperties, nIdx, + getPropertySetMapper()); + break; + + default: + SvXMLExportPropertyMapper::handleElementItem( rExp, rProperty, nFlags, pProperties, nIdx ); + break; + } +} + +void XMLTextExportPropertySetMapper::handleSpecialItem( + SvXMLAttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const +{ + XMLTextExportPropertySetMapper *pThis = + const_cast(this); + + switch( getPropertySetMapper()->GetEntryContextId( rProperty.mnIndex ) ) + { + case CTF_PAGENUMBEROFFSET: + { + OUString value; + XMLNumberWithAutoForVoidPropHdl const handler; + handler.exportXML(value, rProperty.maValue, rUnitConverter); + if (GetExport().getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_013 + && value == "0") // tdf#91306 ODF 1.3 OFFICE-3923 + { + value = "auto"; + } + OUString const name = rNamespaceMap.GetQNameByKey( + getPropertySetMapper()->GetEntryNameSpace(rProperty.mnIndex), + getPropertySetMapper()->GetEntryXMLName(rProperty.mnIndex)); + rAttrList.AddAttribute(name, value); + } + break; + case CTF_DROPCAPWHOLEWORD: + SAL_WARN_IF( !!bDropWholeWord, "xmloff", "drop whole word is set already!" ); + pThis->bDropWholeWord = *o3tl::doAccess(rProperty.maValue); + break; + case CTF_DROPCAPCHARSTYLE: + SAL_WARN_IF( !sDropCharStyle.isEmpty(), "xmloff", "drop char style is set already!" ); + rProperty.maValue >>= pThis->sDropCharStyle; + break; + case CTF_NUMBERINGSTYLENAME: + case CTF_PAGEDESCNAME: + case CTF_OLDTEXTBACKGROUND: + case CTF_BACKGROUND_POS: + case CTF_BACKGROUND_FILTER: + case CTF_BACKGROUND_TRANSPARENCY: + case CTF_SECTION_FOOTNOTE_NUM_OWN: + case CTF_SECTION_FOOTNOTE_NUM_RESTART: + case CTF_SECTION_FOOTNOTE_NUM_RESTART_AT: + case CTF_SECTION_FOOTNOTE_NUM_TYPE: + case CTF_SECTION_FOOTNOTE_NUM_PREFIX: + case CTF_SECTION_FOOTNOTE_NUM_SUFFIX: + case CTF_SECTION_ENDNOTE_NUM_OWN: + case CTF_SECTION_ENDNOTE_NUM_RESTART: + case CTF_SECTION_ENDNOTE_NUM_RESTART_AT: + case CTF_SECTION_ENDNOTE_NUM_TYPE: + case CTF_SECTION_ENDNOTE_NUM_PREFIX: + case CTF_SECTION_ENDNOTE_NUM_SUFFIX: + case CTF_DEFAULT_OUTLINE_LEVEL: + case CTF_OLD_FLOW_WITH_TEXT: + // There's nothing to do here! + break; + default: + SvXMLExportPropertyMapper::handleSpecialItem(rAttrList, rProperty, rUnitConverter, rNamespaceMap, pProperties, nIdx ); + break; + } +} + +XMLTextExportPropertySetMapper::XMLTextExportPropertySetMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExp ) : + SvXMLExportPropertyMapper( rMapper ), + rExport( rExp ), + bDropWholeWord( false ), + maDropCapExport( rExp ), + maTabStopExport( rExp ), + maTextColumnsExport( rExp ), + maBackgroundImageExport( rExp ) +{ +} + +XMLTextExportPropertySetMapper::~XMLTextExportPropertySetMapper() +{ +} + +void XMLTextExportPropertySetMapper::ContextFontFilter( + bool bEnableFoFontFamily, + XMLPropertyState *pFontNameState, + XMLPropertyState *pFontFamilyNameState, + XMLPropertyState *pFontStyleNameState, + XMLPropertyState *pFontFamilyState, + XMLPropertyState *pFontPitchState, + XMLPropertyState *pFontCharsetState ) const +{ + OUString sFamilyName; + OUString sStyleName; + FontFamily nFamily = FAMILY_DONTKNOW; + FontPitch nPitch = PITCH_DONTKNOW; + rtl_TextEncoding eEnc = RTL_TEXTENCODING_DONTKNOW; + + OUString sTmp; + if( pFontFamilyNameState && (pFontFamilyNameState->maValue >>= sTmp ) ) + sFamilyName = sTmp; + if( pFontStyleNameState && (pFontStyleNameState->maValue >>= sTmp ) ) + sStyleName = sTmp; + + sal_Int16 nTmp = sal_Int16(); + if( pFontFamilyState && (pFontFamilyState->maValue >>= nTmp ) ) + nFamily = static_cast< FontFamily >( nTmp ); + if( pFontPitchState && (pFontPitchState->maValue >>= nTmp ) ) + nPitch = static_cast< FontPitch >( nTmp ); + if( pFontCharsetState && (pFontCharsetState->maValue >>= nTmp ) ) + eEnc = static_cast(nTmp); + + //Resolves: fdo#67665 The purpose here appears to be to replace + //FontFamilyName and FontStyleName etc with a single FontName property. The + //problem is that repeated calls to here will first set + //pFontFamilyNameState->mnIndex to -1 to indicate it is disabled, so the + //next time pFontFamilyNameState is not passed here at all, which gives an + //empty sFamilyName resulting in disabling pFontNameState->mnIndex to -1. + //That doesn't seem right to me. + + //So assuming that the main purpose is just to convert the properties in + //the main when we can, and to leave them alone when we can't. And with a + //secondary purpose to filter out empty font properties, then is would + //appear to make sense to base attempting the conversion if we have + //both of the major facts of the font description + + //An alternative solution is to *not* fill the FontAutoStylePool with + //every font in the document, but to partition the fonts into the + //hard-attribute fonts which go into that pool and the style-attribute + //fonts which go into some additional pool which get merged just for + //the purposes of writing the embedded fonts but are not queried by + //"Find" which restores the original logic. + if (pFontFamilyNameState || pFontStyleNameState) + { + OUString sName( const_cast(GetExport()).GetFontAutoStylePool()->Find( + sFamilyName, sStyleName, nFamily, nPitch, eEnc ) ); + if (!sName.isEmpty()) + { + pFontNameState->maValue <<= sName; + //Resolves: fdo#68431 style:font-name unrecognized by LibreOffice + //<= 4.1 in styles (but recognized in autostyles) so add + //fo:font-family, etc + if (!bEnableFoFontFamily) + { + if( pFontFamilyNameState ) + pFontFamilyNameState->mnIndex = -1; + if( pFontStyleNameState ) + pFontStyleNameState->mnIndex = -1; + if( pFontFamilyState ) + pFontFamilyState->mnIndex = -1; + if( pFontPitchState ) + pFontPitchState->mnIndex = -1; + if( pFontCharsetState ) + pFontCharsetState->mnIndex = -1; + } + } + else + { + pFontNameState->mnIndex = -1; + } + } + + if( pFontFamilyNameState && sFamilyName.isEmpty() ) + { + pFontFamilyNameState->mnIndex = -1; + } + + if( pFontStyleNameState && sStyleName.isEmpty() ) + { + pFontStyleNameState->mnIndex = -1; + } +} + +void XMLTextExportPropertySetMapper::ContextFontHeightFilter( + XMLPropertyState* pCharHeightState, + XMLPropertyState* pCharPropHeightState, + XMLPropertyState* pCharDiffHeightState ) +{ + if( pCharPropHeightState ) + { + sal_Int32 nTemp = 0; + pCharPropHeightState->maValue >>= nTemp; + if( nTemp == 100 ) + { + pCharPropHeightState->mnIndex = -1; + pCharPropHeightState->maValue.clear(); + } + else + { + pCharHeightState->mnIndex = -1; + pCharHeightState->maValue.clear(); + } + } + if( !pCharDiffHeightState ) + return; + + float nTemp = 0; + pCharDiffHeightState->maValue >>= nTemp; + if( nTemp == 0. ) + { + pCharDiffHeightState->mnIndex = -1; + pCharDiffHeightState->maValue.clear(); + } + else + { + pCharHeightState->mnIndex = -1; + pCharHeightState->maValue.clear(); + } + +} + +namespace { + +// helper method; implementation below +bool lcl_IsOutlineStyle(const SvXMLExport&, std::u16string_view); + +void +lcl_checkMultiProperty(XMLPropertyState *const pState, + XMLPropertyState *const pRelState) +{ + if (!(pState && pRelState)) + return; + + sal_Int32 nTemp = 0; + pRelState->maValue >>= nTemp; + if (100 == nTemp) + { + pRelState->mnIndex = -1; + pRelState->maValue.clear(); + } + else + { + pState->mnIndex = -1; + pState->maValue.clear(); + } +} + +/** + * Filter context of paragraph and character borders. + * Compress border attributes. If one of groupable attributes (border type, border width, padding) + * is equal for all four side then just one general attribute will be exported. +**/ +void lcl_FilterBorders( + XMLPropertyState* pAllBorderWidthState, XMLPropertyState* pLeftBorderWidthState, + XMLPropertyState* pRightBorderWidthState, XMLPropertyState* pTopBorderWidthState, + XMLPropertyState* pBottomBorderWidthState, XMLPropertyState* pAllBorderDistanceState, + XMLPropertyState* pLeftBorderDistanceState, XMLPropertyState* pRightBorderDistanceState, + XMLPropertyState* pTopBorderDistanceState, XMLPropertyState* pBottomBorderDistanceState, + XMLPropertyState* pAllBorderState, XMLPropertyState* pLeftBorderState, + XMLPropertyState* pRightBorderState,XMLPropertyState* pTopBorderState, + XMLPropertyState* pBottomBorderState ) +{ + if( pAllBorderWidthState ) + { + if( pLeftBorderWidthState && pRightBorderWidthState && pTopBorderWidthState && pBottomBorderWidthState ) + { + table::BorderLine2 aLeft, aRight, aTop, aBottom; + + pLeftBorderWidthState->maValue >>= aLeft; + pRightBorderWidthState->maValue >>= aRight; + pTopBorderWidthState->maValue >>= aTop; + pBottomBorderWidthState->maValue >>= aBottom; + if( aLeft.Color == aRight.Color && aLeft.InnerLineWidth == aRight.InnerLineWidth && + aLeft.OuterLineWidth == aRight.OuterLineWidth && aLeft.LineDistance == aRight.LineDistance && + aLeft.LineStyle == aRight.LineStyle && + aLeft.LineWidth == aRight.LineWidth && + aLeft.Color == aTop.Color && aLeft.InnerLineWidth == aTop.InnerLineWidth && + aLeft.OuterLineWidth == aTop.OuterLineWidth && aLeft.LineDistance == aTop.LineDistance && + aLeft.LineStyle == aTop.LineStyle && + aLeft.LineWidth == aTop.LineWidth && + aLeft.Color == aBottom.Color && aLeft.InnerLineWidth == aBottom.InnerLineWidth && + aLeft.OuterLineWidth == aBottom.OuterLineWidth && aLeft.LineDistance == aBottom.LineDistance && + aLeft.LineStyle == aBottom.LineStyle && + aLeft.LineWidth == aBottom.LineWidth ) + { + pLeftBorderWidthState->mnIndex = -1; + pLeftBorderWidthState->maValue.clear(); + pRightBorderWidthState->mnIndex = -1; + pRightBorderWidthState->maValue.clear(); + pTopBorderWidthState->mnIndex = -1; + pTopBorderWidthState->maValue.clear(); + pBottomBorderWidthState->mnIndex = -1; + pBottomBorderWidthState->maValue.clear(); + } + else + { + pAllBorderWidthState->mnIndex = -1; + pAllBorderWidthState->maValue.clear(); + } + } + else + { + pAllBorderWidthState->mnIndex = -1; + pAllBorderWidthState->maValue.clear(); + } + } + + if( pAllBorderDistanceState ) + { + if( pLeftBorderDistanceState && pRightBorderDistanceState && pTopBorderDistanceState && pBottomBorderDistanceState ) + { + sal_Int32 aLeft = 0, aRight = 0, aTop = 0, aBottom = 0; + + pLeftBorderDistanceState->maValue >>= aLeft; + pRightBorderDistanceState->maValue >>= aRight; + pTopBorderDistanceState->maValue >>= aTop; + pBottomBorderDistanceState->maValue >>= aBottom; + if( aLeft == aRight && aLeft == aTop && aLeft == aBottom ) + { + pLeftBorderDistanceState->mnIndex = -1; + pLeftBorderDistanceState->maValue.clear(); + pRightBorderDistanceState->mnIndex = -1; + pRightBorderDistanceState->maValue.clear(); + pTopBorderDistanceState->mnIndex = -1; + pTopBorderDistanceState->maValue.clear(); + pBottomBorderDistanceState->mnIndex = -1; + pBottomBorderDistanceState->maValue.clear(); + } + else + { + pAllBorderDistanceState->mnIndex = -1; + pAllBorderDistanceState->maValue.clear(); + } + } + else + { + pAllBorderDistanceState->mnIndex = -1; + pAllBorderDistanceState->maValue.clear(); + } + } + + if( !pAllBorderState ) + return; + + if( pLeftBorderState && pRightBorderState && pTopBorderState && pBottomBorderState ) + { + table::BorderLine2 aLeft, aRight, aTop, aBottom; + + pLeftBorderState->maValue >>= aLeft; + pRightBorderState->maValue >>= aRight; + pTopBorderState->maValue >>= aTop; + pBottomBorderState->maValue >>= aBottom; + if( aLeft.Color == aRight.Color && aLeft.InnerLineWidth == aRight.InnerLineWidth && + aLeft.OuterLineWidth == aRight.OuterLineWidth && aLeft.LineDistance == aRight.LineDistance && + aLeft.LineStyle == aRight.LineStyle && + aLeft.LineWidth == aRight.LineWidth && + aLeft.Color == aTop.Color && aLeft.InnerLineWidth == aTop.InnerLineWidth && + aLeft.OuterLineWidth == aTop.OuterLineWidth && aLeft.LineDistance == aTop.LineDistance && + aLeft.LineStyle == aTop.LineStyle && + aLeft.LineWidth == aTop.LineWidth && + aLeft.Color == aBottom.Color && aLeft.InnerLineWidth == aBottom.InnerLineWidth && + aLeft.OuterLineWidth == aBottom.OuterLineWidth && aLeft.LineDistance == aBottom.LineDistance && + aLeft.LineWidth == aBottom.LineWidth && + aLeft.LineStyle == aBottom.LineStyle ) + { + pLeftBorderState->mnIndex = -1; + pLeftBorderState->maValue.clear(); + pRightBorderState->mnIndex = -1; + pRightBorderState->maValue.clear(); + pTopBorderState->mnIndex = -1; + pTopBorderState->maValue.clear(); + pBottomBorderState->mnIndex = -1; + pBottomBorderState->maValue.clear(); + } + else + { + pAllBorderState->mnIndex = -1; + pAllBorderState->maValue.clear(); + } + } + else + { + pAllBorderState->mnIndex = -1; + pAllBorderState->maValue.clear(); + } +} + +} + +void XMLTextExportPropertySetMapper::ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const Reference< XPropertySet >& rPropSet ) const +{ + // filter font + XMLPropertyState *pFontNameState = nullptr; + XMLPropertyState *pFontFamilyNameState = nullptr; + XMLPropertyState *pFontStyleNameState = nullptr; + XMLPropertyState *pFontFamilyState = nullptr; + XMLPropertyState *pFontPitchState = nullptr; + XMLPropertyState *pFontCharsetState = nullptr; + XMLPropertyState *pFontNameCJKState = nullptr; + XMLPropertyState *pFontFamilyNameCJKState = nullptr; + XMLPropertyState *pFontStyleNameCJKState = nullptr; + XMLPropertyState *pFontFamilyCJKState = nullptr; + XMLPropertyState *pFontPitchCJKState = nullptr; + XMLPropertyState *pFontCharsetCJKState = nullptr; + XMLPropertyState *pFontNameCTLState = nullptr; + XMLPropertyState *pFontFamilyNameCTLState = nullptr; + XMLPropertyState *pFontStyleNameCTLState = nullptr; + XMLPropertyState *pFontFamilyCTLState = nullptr; + XMLPropertyState *pFontPitchCTLState = nullptr; + XMLPropertyState *pFontCharsetCTLState = nullptr; + + // filter char height point/percent + XMLPropertyState* pCharHeightState = nullptr; + XMLPropertyState* pCharPropHeightState = nullptr; + XMLPropertyState* pCharDiffHeightState = nullptr; + XMLPropertyState* pCharHeightCJKState = nullptr; + XMLPropertyState* pCharPropHeightCJKState = nullptr; + XMLPropertyState* pCharDiffHeightCJKState = nullptr; + XMLPropertyState* pCharHeightCTLState = nullptr; + XMLPropertyState* pCharPropHeightCTLState = nullptr; + XMLPropertyState* pCharDiffHeightCTLState = nullptr; + + // filter left margin measure/percent + XMLPropertyState* pParaLeftMarginState = nullptr; + XMLPropertyState* pParaLeftMarginRelState = nullptr; + + // filter right margin measure/percent + XMLPropertyState* pParaRightMarginState = nullptr; + XMLPropertyState* pParaRightMarginRelState = nullptr; + + // filter first line indent measure/percent + XMLPropertyState* pParaFirstLineState = nullptr; + XMLPropertyState* pParaFirstLineRelState = nullptr; + + // filter ParaTopMargin/Relative + XMLPropertyState* pParaTopMarginState = nullptr; + XMLPropertyState* pParaTopMarginRelState = nullptr; + + // filter ParaTopMargin/Relative + XMLPropertyState* pParaBottomMarginState = nullptr; + XMLPropertyState* pParaBottomMarginRelState = nullptr; + + // filter (Left|Right|Top|Bottom|)BorderWidth + XMLPropertyState* pAllBorderWidthState = nullptr; + XMLPropertyState* pLeftBorderWidthState = nullptr; + XMLPropertyState* pRightBorderWidthState = nullptr; + XMLPropertyState* pTopBorderWidthState = nullptr; + XMLPropertyState* pBottomBorderWidthState = nullptr; + + // filter (Left|Right|Top|)BorderDistance + XMLPropertyState* pAllBorderDistanceState = nullptr; + XMLPropertyState* pLeftBorderDistanceState = nullptr; + XMLPropertyState* pRightBorderDistanceState = nullptr; + XMLPropertyState* pTopBorderDistanceState = nullptr; + XMLPropertyState* pBottomBorderDistanceState = nullptr; + + // filter (Left|Right|Top|Bottom|)Border + XMLPropertyState* pAllBorderState = nullptr; + XMLPropertyState* pLeftBorderState = nullptr; + XMLPropertyState* pRightBorderState = nullptr; + XMLPropertyState* pTopBorderState = nullptr; + XMLPropertyState* pBottomBorderState = nullptr; + + // filter Char(Left|Right|Top|Bottom|)BorderWidth + XMLPropertyState* pCharAllBorderWidthState = nullptr; + XMLPropertyState* pCharLeftBorderWidthState = nullptr; + XMLPropertyState* pCharRightBorderWidthState = nullptr; + XMLPropertyState* pCharTopBorderWidthState = nullptr; + XMLPropertyState* pCharBottomBorderWidthState = nullptr; + + // filter Char(Left|Right|Top|)BorderDistance + XMLPropertyState* pCharAllBorderDistanceState = nullptr; + XMLPropertyState* pCharLeftBorderDistanceState = nullptr; + XMLPropertyState* pCharRightBorderDistanceState = nullptr; + XMLPropertyState* pCharTopBorderDistanceState = nullptr; + XMLPropertyState* pCharBottomBorderDistanceState = nullptr; + + // filter Char(Left|Right|Top|Bottom|)Border + XMLPropertyState* pCharAllBorderState = nullptr; + XMLPropertyState* pCharLeftBorderState = nullptr; + XMLPropertyState* pCharRightBorderState = nullptr; + XMLPropertyState* pCharTopBorderState = nullptr; + XMLPropertyState* pCharBottomBorderState = nullptr; + + // filter height properties + XMLPropertyState* pHeightMinAbsState = nullptr; + XMLPropertyState* pHeightMinRelState = nullptr; + XMLPropertyState* pHeightAbsState = nullptr; + XMLPropertyState* pHeightRelState = nullptr; + XMLPropertyState* pSizeTypeState = nullptr; + + // filter width properties + XMLPropertyState* pWidthMinAbsState = nullptr; + XMLPropertyState* pWidthMinRelState = nullptr; + XMLPropertyState* pWidthAbsState = nullptr; + XMLPropertyState* pWidthRelState = nullptr; + XMLPropertyState* pWidthTypeState = nullptr; + + // wrap + XMLPropertyState* pWrapState = nullptr; + XMLPropertyState* pWrapContourState = nullptr; + XMLPropertyState* pWrapContourModeState = nullptr; + XMLPropertyState* pWrapParagraphOnlyState = nullptr; + + // anchor + XMLPropertyState* pAnchorTypeState = nullptr; + + // horizontal position and relation + XMLPropertyState* pHoriOrientState = nullptr; + XMLPropertyState* pHoriOrientMirroredState = nullptr; + XMLPropertyState* pHoriOrientRelState = nullptr; + XMLPropertyState* pHoriOrientRelFrameState = nullptr; + XMLPropertyState* pHoriOrientMirrorState = nullptr; + // Horizontal position and relation for shapes (#i28749#) + XMLPropertyState* pShapeHoriOrientState = nullptr; + XMLPropertyState* pShapeHoriOrientMirroredState = nullptr; + XMLPropertyState* pShapeHoriOrientRelState = nullptr; + XMLPropertyState* pShapeHoriOrientRelFrameState = nullptr; + XMLPropertyState* pShapeHoriOrientMirrorState = nullptr; + + // vertical position and relation + XMLPropertyState* pVertOrientState = nullptr; + XMLPropertyState* pVertOrientAtCharState = nullptr; + XMLPropertyState* pVertOrientRelState = nullptr; + XMLPropertyState* pVertOrientRelPageState = nullptr; + XMLPropertyState* pVertOrientRelFrameState = nullptr; + XMLPropertyState* pVertOrientRelAsCharState = nullptr; + XMLPropertyState* pRelWidthRel = nullptr; + XMLPropertyState* pRelHeightRel = nullptr; + + // Vertical position and relation for shapes (#i28749#) + XMLPropertyState* pShapeVertOrientState = nullptr; + XMLPropertyState* pShapeVertOrientAtCharState = nullptr; + XMLPropertyState* pShapeVertOrientRelState = nullptr; + XMLPropertyState* pShapeVertOrientRelPageState = nullptr; + XMLPropertyState* pShapeVertOrientRelFrameState = nullptr; + + // filter underline color + XMLPropertyState* pUnderlineState = nullptr; + XMLPropertyState* pUnderlineColorState = nullptr; + XMLPropertyState* pUnderlineHasColorState = nullptr; + + // filter list style name + XMLPropertyState* pListStyleName = nullptr; + + // filter fo:clip + XMLPropertyState* pClip11State = nullptr; + XMLPropertyState* pClipState = nullptr; + + // filter fo:margin + XMLPropertyState* pAllParaMarginRel = nullptr; + XMLPropertyState* pAllParaMargin = nullptr; + XMLPropertyState* pAllMargin = nullptr; + + XMLPropertyState* pRepeatOffsetX = nullptr; + XMLPropertyState* pRepeatOffsetY = nullptr; + + // character background and highlight + XMLPropertyState* pCharBackground = nullptr; + XMLPropertyState* pCharBackgroundTransparency = nullptr; + XMLPropertyState* pCharHighlight = nullptr; + + bool bNeedsAnchor = false; + + for( auto& rPropertyState : rProperties ) + { + XMLPropertyState *propertyState = &rPropertyState; + if( propertyState->mnIndex == -1 ) + continue; + + switch( getPropertySetMapper()->GetEntryContextId( propertyState->mnIndex ) ) + { + case CTF_CHARHEIGHT: pCharHeightState = propertyState; break; + case CTF_CHARHEIGHT_REL: pCharPropHeightState = propertyState; break; + case CTF_CHARHEIGHT_DIFF: pCharDiffHeightState = propertyState; break; + case CTF_CHARHEIGHT_CJK: pCharHeightCJKState = propertyState; break; + case CTF_CHARHEIGHT_REL_CJK: pCharPropHeightCJKState = propertyState; break; + case CTF_CHARHEIGHT_DIFF_CJK: pCharDiffHeightCJKState = propertyState; break; + case CTF_CHARHEIGHT_CTL: pCharHeightCTLState = propertyState; break; + case CTF_CHARHEIGHT_REL_CTL: pCharPropHeightCTLState = propertyState; break; + case CTF_CHARHEIGHT_DIFF_CTL: pCharDiffHeightCTLState = propertyState; break; + case CTF_PARALEFTMARGIN: pParaLeftMarginState = propertyState; break; + case CTF_PARALEFTMARGIN_REL: pParaLeftMarginRelState = propertyState; break; + case CTF_PARARIGHTMARGIN: pParaRightMarginState = propertyState; break; + case CTF_PARARIGHTMARGIN_REL: pParaRightMarginRelState = propertyState; break; + case CTF_PARAFIRSTLINE: pParaFirstLineState = propertyState; break; + case CTF_PARAFIRSTLINE_REL: pParaFirstLineRelState = propertyState; break; + case CTF_PARATOPMARGIN: pParaTopMarginState = propertyState; break; + case CTF_PARATOPMARGIN_REL: pParaTopMarginRelState = propertyState; break; + case CTF_PARABOTTOMMARGIN: pParaBottomMarginState = propertyState; break; + case CTF_PARABOTTOMMARGIN_REL: pParaBottomMarginRelState = propertyState; break; + + case CTF_ALLBORDERWIDTH: pAllBorderWidthState = propertyState; break; + case CTF_LEFTBORDERWIDTH: pLeftBorderWidthState = propertyState; break; + case CTF_RIGHTBORDERWIDTH: pRightBorderWidthState = propertyState; break; + case CTF_TOPBORDERWIDTH: pTopBorderWidthState = propertyState; break; + case CTF_BOTTOMBORDERWIDTH: pBottomBorderWidthState = propertyState; break; + case CTF_ALLBORDERDISTANCE: pAllBorderDistanceState = propertyState; break; + case CTF_LEFTBORDERDISTANCE: pLeftBorderDistanceState = propertyState; break; + case CTF_RIGHTBORDERDISTANCE: pRightBorderDistanceState = propertyState; break; + case CTF_TOPBORDERDISTANCE: pTopBorderDistanceState = propertyState; break; + case CTF_BOTTOMBORDERDISTANCE: pBottomBorderDistanceState = propertyState; break; + case CTF_ALLBORDER: pAllBorderState = propertyState; break; + case CTF_LEFTBORDER: pLeftBorderState = propertyState; break; + case CTF_RIGHTBORDER: pRightBorderState = propertyState; break; + case CTF_TOPBORDER: pTopBorderState = propertyState; break; + case CTF_BOTTOMBORDER: pBottomBorderState = propertyState; break; + + case CTF_CHARALLBORDERWIDTH: pCharAllBorderWidthState = propertyState; break; + case CTF_CHARLEFTBORDERWIDTH: pCharLeftBorderWidthState = propertyState; break; + case CTF_CHARRIGHTBORDERWIDTH: pCharRightBorderWidthState = propertyState; break; + case CTF_CHARTOPBORDERWIDTH: pCharTopBorderWidthState = propertyState; break; + case CTF_CHARBOTTOMBORDERWIDTH: pCharBottomBorderWidthState = propertyState; break; + case CTF_CHARALLBORDERDISTANCE: pCharAllBorderDistanceState = propertyState; break; + case CTF_CHARLEFTBORDERDISTANCE: pCharLeftBorderDistanceState = propertyState; break; + case CTF_CHARRIGHTBORDERDISTANCE: pCharRightBorderDistanceState = propertyState; break; + case CTF_CHARTOPBORDERDISTANCE: pCharTopBorderDistanceState = propertyState; break; + case CTF_CHARBOTTOMBORDERDISTANCE: pCharBottomBorderDistanceState = propertyState; break; + case CTF_CHARALLBORDER: pCharAllBorderState = propertyState; break; + case CTF_CHARLEFTBORDER: pCharLeftBorderState = propertyState; break; + case CTF_CHARRIGHTBORDER: pCharRightBorderState = propertyState; break; + case CTF_CHARTOPBORDER: pCharTopBorderState = propertyState; break; + case CTF_CHARBOTTOMBORDER: pCharBottomBorderState = propertyState; break; + + case CTF_FRAMEHEIGHT_MIN_ABS: pHeightMinAbsState = propertyState; break; + case CTF_FRAMEHEIGHT_MIN_REL: pHeightMinRelState = propertyState; break; + case CTF_FRAMEHEIGHT_ABS: pHeightAbsState = propertyState; break; + case CTF_FRAMEHEIGHT_REL: pHeightRelState = propertyState; break; + case CTF_SIZETYPE: pSizeTypeState = propertyState; break; + + case CTF_FRAMEWIDTH_MIN_ABS: pWidthMinAbsState = propertyState; break; + case CTF_FRAMEWIDTH_MIN_REL: pWidthMinRelState = propertyState; break; + case CTF_FRAMEWIDTH_ABS: pWidthAbsState = propertyState; break; + case CTF_FRAMEWIDTH_REL: pWidthRelState = propertyState; break; + case CTF_FRAMEWIDTH_TYPE: pWidthTypeState = propertyState; break; + + case CTF_WRAP: pWrapState = propertyState; break; + case CTF_WRAP_CONTOUR: pWrapContourState = propertyState; break; + case CTF_WRAP_CONTOUR_MODE: pWrapContourModeState = propertyState; break; + case CTF_WRAP_PARAGRAPH_ONLY: pWrapParagraphOnlyState = propertyState; break; + case CTF_ANCHORTYPE: pAnchorTypeState = propertyState; break; + + case CTF_HORIZONTALPOS: pHoriOrientState = propertyState; bNeedsAnchor = true; break; + case CTF_HORIZONTALPOS_MIRRORED: pHoriOrientMirroredState = propertyState; bNeedsAnchor = true; break; + case CTF_HORIZONTALREL: pHoriOrientRelState = propertyState; bNeedsAnchor = true; break; + case CTF_HORIZONTALREL_FRAME: pHoriOrientRelFrameState = propertyState; bNeedsAnchor = true; break; + case CTF_HORIZONTALMIRROR: pHoriOrientMirrorState = propertyState; bNeedsAnchor = true; break; + case CTF_RELWIDTHREL: pRelWidthRel = propertyState; break; + case CTF_VERTICALPOS: pVertOrientState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALPOS_ATCHAR: pVertOrientAtCharState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALREL: pVertOrientRelState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALREL_PAGE: pVertOrientRelPageState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALREL_FRAME: pVertOrientRelFrameState = propertyState; bNeedsAnchor = true; break; + case CTF_VERTICALREL_ASCHAR: pVertOrientRelAsCharState = propertyState; bNeedsAnchor = true; break; + case CTF_RELHEIGHTREL: pRelHeightRel = propertyState; break; + + // Handle new CTFs for shape positioning properties (#i28749#) + case CTF_SHAPE_HORIZONTALPOS: pShapeHoriOrientState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_HORIZONTALPOS_MIRRORED: pShapeHoriOrientMirroredState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_HORIZONTALREL: pShapeHoriOrientRelState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_HORIZONTALREL_FRAME: pShapeHoriOrientRelFrameState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_HORIZONTALMIRROR: pShapeHoriOrientMirrorState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALPOS: pShapeVertOrientState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALPOS_ATCHAR: pShapeVertOrientAtCharState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALREL: pShapeVertOrientRelState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALREL_PAGE: pShapeVertOrientRelPageState = propertyState; bNeedsAnchor = true; break; + case CTF_SHAPE_VERTICALREL_FRAME: pShapeVertOrientRelFrameState = propertyState; bNeedsAnchor = true; break; + case CTF_FONTNAME: pFontNameState = propertyState; break; + case CTF_FONTFAMILYNAME: pFontFamilyNameState = propertyState; break; + case CTF_FONTSTYLENAME: pFontStyleNameState = propertyState; break; + case CTF_FONTFAMILY: pFontFamilyState = propertyState; break; + case CTF_FONTPITCH: pFontPitchState = propertyState; break; + case CTF_FONTCHARSET: pFontCharsetState = propertyState; break; + + case CTF_FONTNAME_CJK: pFontNameCJKState = propertyState; break; + case CTF_FONTFAMILYNAME_CJK: pFontFamilyNameCJKState = propertyState; break; + case CTF_FONTSTYLENAME_CJK: pFontStyleNameCJKState = propertyState; break; + case CTF_FONTFAMILY_CJK: pFontFamilyCJKState = propertyState; break; + case CTF_FONTPITCH_CJK: pFontPitchCJKState = propertyState; break; + case CTF_FONTCHARSET_CJK: pFontCharsetCJKState = propertyState; break; + + case CTF_FONTNAME_CTL: pFontNameCTLState = propertyState; break; + case CTF_FONTFAMILYNAME_CTL: pFontFamilyNameCTLState = propertyState; break; + case CTF_FONTSTYLENAME_CTL: pFontStyleNameCTLState = propertyState; break; + case CTF_FONTFAMILY_CTL: pFontFamilyCTLState = propertyState; break; + case CTF_FONTPITCH_CTL: pFontPitchCTLState = propertyState; break; + case CTF_FONTCHARSET_CTL: pFontCharsetCTLState = propertyState; break; + case CTF_UNDERLINE: pUnderlineState = propertyState; break; + case CTF_UNDERLINE_COLOR: pUnderlineColorState = propertyState; break; + case CTF_UNDERLINE_HASCOLOR: pUnderlineHasColorState = propertyState; break; + case CTF_NUMBERINGSTYLENAME: pListStyleName = propertyState; break; + case CTF_TEXT_CLIP11: pClip11State = propertyState; break; + case CTF_TEXT_CLIP: pClipState = propertyState; break; + case CTF_PARAMARGINALL_REL: pAllParaMarginRel = propertyState; break; + case CTF_PARAMARGINALL: pAllParaMargin = propertyState; break; + case CTF_MARGINALL: pAllMargin = propertyState; break; + + case CTF_REPEAT_OFFSET_X: + pRepeatOffsetX = propertyState; + break; + + case CTF_REPEAT_OFFSET_Y: + pRepeatOffsetY = propertyState; + break; + + case CTF_FILLGRADIENTNAME: + case CTF_FILLHATCHNAME: + case CTF_FILLBITMAPNAME: + case CTF_FILLTRANSNAME: + { + OUString aStr; + if( (propertyState->maValue >>= aStr) && 0 == aStr.getLength() ) + propertyState->mnIndex = -1; + } + break; + + case CTF_CHAR_BACKGROUND: pCharBackground = propertyState; break; + case CTF_CHAR_BACKGROUND_TRANSPARENCY: pCharBackgroundTransparency = propertyState; break; + case CTF_CHAR_HIGHLIGHT: pCharHighlight = propertyState; break; + } + } + + if( pRepeatOffsetX && pRepeatOffsetY ) + { + sal_Int32 nOffset = 0; + if( ( pRepeatOffsetX->maValue >>= nOffset ) && ( nOffset == 0 ) ) + pRepeatOffsetX->mnIndex = -1; + else + pRepeatOffsetY->mnIndex = -1; + } + + if( pFontNameState ) + ContextFontFilter( bEnableFoFontFamily, pFontNameState, pFontFamilyNameState, + pFontStyleNameState, pFontFamilyState, + pFontPitchState, pFontCharsetState ); + if( pFontNameCJKState ) + ContextFontFilter( bEnableFoFontFamily, pFontNameCJKState, pFontFamilyNameCJKState, + pFontStyleNameCJKState, pFontFamilyCJKState, + pFontPitchCJKState, pFontCharsetCJKState ); + if( pFontNameCTLState ) + ContextFontFilter( bEnableFoFontFamily, pFontNameCTLState, pFontFamilyNameCTLState, + pFontStyleNameCTLState, pFontFamilyCTLState, + pFontPitchCTLState, pFontCharsetCTLState ); + + if( pCharHeightState && (pCharPropHeightState || pCharDiffHeightState ) ) + ContextFontHeightFilter( pCharHeightState, pCharPropHeightState, + pCharDiffHeightState ); + if( pCharHeightCJKState && + (pCharPropHeightCJKState || pCharDiffHeightCJKState ) ) + ContextFontHeightFilter( pCharHeightCJKState, pCharPropHeightCJKState, + pCharDiffHeightCJKState ); + if( pCharHeightCTLState && + (pCharPropHeightCTLState || pCharDiffHeightCTLState ) ) + ContextFontHeightFilter( pCharHeightCTLState, pCharPropHeightCTLState, + pCharDiffHeightCTLState ); + if( pUnderlineColorState || pUnderlineHasColorState ) + { + bool bClear = !pUnderlineState; + if( !bClear ) + { + sal_Int16 nUnderline = 0; + pUnderlineState->maValue >>= nUnderline; + bClear = awt::FontUnderline::NONE == nUnderline; + } + if( bClear ) + { + if( pUnderlineColorState ) + pUnderlineColorState->mnIndex = -1; + if( pUnderlineHasColorState ) + pUnderlineHasColorState->mnIndex = -1; + } + } + + lcl_checkMultiProperty(pParaLeftMarginState, pParaLeftMarginRelState); + lcl_checkMultiProperty(pParaRightMarginState, pParaRightMarginRelState); + lcl_checkMultiProperty(pParaTopMarginState, pParaTopMarginRelState); + lcl_checkMultiProperty(pParaBottomMarginState, pParaBottomMarginRelState); + lcl_checkMultiProperty(pParaFirstLineState, pParaFirstLineRelState); + + if (pAllParaMarginRel) + { // because older OOo/LO versions can't read fo:margin: + pAllParaMarginRel->mnIndex = -1; // just export individual attributes... + pAllParaMarginRel->maValue.clear(); + } + if (pAllParaMargin) + { + pAllParaMargin->mnIndex = -1; // just export individual attributes... + pAllParaMargin->maValue.clear(); + } + if (pAllMargin) + { + pAllMargin->mnIndex = -1; // just export individual attributes... + pAllMargin->maValue.clear(); + } + + lcl_FilterBorders( + pAllBorderWidthState, pLeftBorderWidthState, pRightBorderWidthState, + pTopBorderWidthState, pBottomBorderWidthState, pAllBorderDistanceState, + pLeftBorderDistanceState, pRightBorderDistanceState, pTopBorderDistanceState, + pBottomBorderDistanceState, pAllBorderState, pLeftBorderState, + pRightBorderState, pTopBorderState, pBottomBorderState); + + lcl_FilterBorders( + pCharAllBorderWidthState, pCharLeftBorderWidthState, pCharRightBorderWidthState, + pCharTopBorderWidthState, pCharBottomBorderWidthState, pCharAllBorderDistanceState, + pCharLeftBorderDistanceState, pCharRightBorderDistanceState, pCharTopBorderDistanceState, + pCharBottomBorderDistanceState, pCharAllBorderState, pCharLeftBorderState, + pCharRightBorderState, pCharTopBorderState, pCharBottomBorderState); + + sal_Int16 nSizeType = SizeType::FIX; + if( pSizeTypeState ) + { + pSizeTypeState->maValue >>= nSizeType; + pSizeTypeState->mnIndex = -1; + } + + if( pHeightMinAbsState ) + { + sal_Int16 nRel = sal_Int16(); + if( (SizeType::FIX == nSizeType) || + ( pHeightMinRelState && + ( !(pHeightMinRelState->maValue >>= nRel) || nRel > 0 ) ) ) + { + pHeightMinAbsState->mnIndex = -1; + } + + // export SizeType::VARIABLE as min-width="0" + if( SizeType::VARIABLE == nSizeType ) + pHeightMinAbsState->maValue <<= static_cast( 0 ); + } + if( pHeightMinRelState && SizeType::MIN != nSizeType) + pHeightMinRelState->mnIndex = -1; + if( pHeightAbsState && pHeightMinAbsState && + -1 != pHeightMinAbsState->mnIndex ) + pHeightAbsState->mnIndex = -1; + if( pHeightRelState && SizeType::FIX != nSizeType) + pHeightRelState->mnIndex = -1; + + // frame width + nSizeType = SizeType::FIX; + if( pWidthTypeState ) + { + pWidthTypeState->maValue >>= nSizeType; + pWidthTypeState->mnIndex = -1; + } + if( pWidthMinAbsState ) + { + sal_Int16 nRel = sal_Int16(); + if( (SizeType::FIX == nSizeType) || + ( pWidthMinRelState && + ( !(pWidthMinRelState->maValue >>= nRel) || nRel > 0 ) ) ) + { + pWidthMinAbsState->mnIndex = -1; + } + + // export SizeType::VARIABLE as min-width="0" + if( SizeType::VARIABLE == nSizeType ) + pWidthMinAbsState->maValue <<= static_cast( 0 ); + } + if( pWidthMinRelState && SizeType::MIN != nSizeType) + pWidthMinRelState->mnIndex = -1; + if( pWidthAbsState && pWidthMinAbsState && + -1 != pWidthMinAbsState->mnIndex ) + pWidthAbsState->mnIndex = -1; + if( pWidthRelState && SizeType::FIX != nSizeType) + pWidthRelState->mnIndex = -1; + + if( pWrapState ) + { + WrapTextMode eVal; + pWrapState->maValue >>= eVal; + switch( eVal ) + { + case WrapTextMode_NONE: + // no wrapping: disable para-only and contour + if( pWrapParagraphOnlyState ) + pWrapParagraphOnlyState->mnIndex = -1; + [[fallthrough]]; + case WrapTextMode_THROUGH: + // wrap through: disable only contour + if( pWrapContourState ) + pWrapContourState->mnIndex = -1; + break; + default: + break; + } + if( pWrapContourModeState && + (!pWrapContourState || + !*o3tl::doAccess(pWrapContourState ->maValue) ) ) + pWrapContourModeState->mnIndex = -1; + } + + TextContentAnchorType eAnchor = TextContentAnchorType_AT_PARAGRAPH; + if( pAnchorTypeState ) + pAnchorTypeState->maValue >>= eAnchor; + else if( bNeedsAnchor ) + { + Any aAny = rPropSet->getPropertyValue("AnchorType"); + aAny >>= eAnchor; + } + + // states for frame positioning attributes + { + if( pHoriOrientState && pHoriOrientMirroredState ) + { + if( pHoriOrientMirrorState && + *o3tl::doAccess(pHoriOrientMirrorState->maValue) ) + pHoriOrientState->mnIndex = -1; + else + pHoriOrientMirroredState->mnIndex = -1; + } + if( pHoriOrientMirrorState ) + pHoriOrientMirrorState->mnIndex = -1; + + if( pHoriOrientRelState && TextContentAnchorType_AT_FRAME == eAnchor ) + pHoriOrientRelState->mnIndex = -1; + if( pHoriOrientRelFrameState && TextContentAnchorType_AT_FRAME != eAnchor ) + pHoriOrientRelFrameState->mnIndex = -1; + if (pRelWidthRel) + { + sal_Int16 nRelWidth = 0; + rPropSet->getPropertyValue("RelativeWidth") >>= nRelWidth; + if (!nRelWidth) + pRelWidthRel->mnIndex = -1; + } + + if( pVertOrientState && TextContentAnchorType_AT_CHARACTER == eAnchor ) + pVertOrientState->mnIndex = -1; + if( pVertOrientAtCharState && TextContentAnchorType_AT_CHARACTER != eAnchor ) + pVertOrientAtCharState->mnIndex = -1; + if( pVertOrientRelState && TextContentAnchorType_AT_PARAGRAPH != eAnchor && + TextContentAnchorType_AT_CHARACTER != eAnchor ) + pVertOrientRelState->mnIndex = -1; + if( pVertOrientRelPageState && TextContentAnchorType_AT_PAGE != eAnchor ) + pVertOrientRelPageState->mnIndex = -1; + if( pVertOrientRelFrameState && TextContentAnchorType_AT_FRAME != eAnchor ) + pVertOrientRelFrameState->mnIndex = -1; + if( pVertOrientRelAsCharState && TextContentAnchorType_AS_CHARACTER != eAnchor ) + pVertOrientRelAsCharState->mnIndex = -1; + if (pRelHeightRel) + { + sal_Int16 nRelHeight = 0; + rPropSet->getPropertyValue("RelativeHeight") >>= nRelHeight; + if (!nRelHeight) + pRelHeightRel->mnIndex = -1; + } + } + + // States for shape positioning properties (#i28749#) + if ( eAnchor != TextContentAnchorType_AS_CHARACTER && + !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) ) + { + // no export of shape positioning properties, + // if shape isn't anchored as-character and + // destination file format is OpenOffice.org file format + if ( pShapeHoriOrientState ) + pShapeHoriOrientState->mnIndex = -1; + if ( pShapeHoriOrientMirroredState ) + pShapeHoriOrientMirroredState->mnIndex = -1; + if ( pShapeHoriOrientRelState ) + pShapeHoriOrientRelState->mnIndex = -1; + if ( pShapeHoriOrientRelFrameState ) + pShapeHoriOrientRelFrameState->mnIndex = -1; + if ( pShapeHoriOrientMirrorState ) + pShapeHoriOrientMirrorState->mnIndex = -1; + if ( pShapeVertOrientState ) + pShapeVertOrientState->mnIndex = -1; + if ( pShapeVertOrientAtCharState ) + pShapeVertOrientAtCharState->mnIndex = -1; + if ( pShapeVertOrientRelState ) + pShapeVertOrientRelState->mnIndex = -1; + if ( pShapeVertOrientRelPageState ) + pShapeVertOrientRelPageState->mnIndex = -1; + if ( pShapeVertOrientRelFrameState ) + pShapeVertOrientRelFrameState->mnIndex = -1; + } + else + { + // handling of shape positioning property states as for frames - see above + if( pShapeHoriOrientState && pShapeHoriOrientMirroredState ) + { + if( pShapeHoriOrientMirrorState && + *o3tl::doAccess(pShapeHoriOrientMirrorState->maValue) ) + pShapeHoriOrientState->mnIndex = -1; + else + pShapeHoriOrientMirroredState->mnIndex = -1; + } + if( pShapeHoriOrientMirrorState ) + pShapeHoriOrientMirrorState->mnIndex = -1; + + if( pShapeHoriOrientRelState && TextContentAnchorType_AT_FRAME == eAnchor ) + pShapeHoriOrientRelState->mnIndex = -1; + if( pShapeHoriOrientRelFrameState && TextContentAnchorType_AT_FRAME != eAnchor ) + pShapeHoriOrientRelFrameState->mnIndex = -1; + + if( pShapeVertOrientState && TextContentAnchorType_AT_CHARACTER == eAnchor ) + pShapeVertOrientState->mnIndex = -1; + if( pShapeVertOrientAtCharState && TextContentAnchorType_AT_CHARACTER != eAnchor ) + pShapeVertOrientAtCharState->mnIndex = -1; + if( pShapeVertOrientRelState && TextContentAnchorType_AT_PARAGRAPH != eAnchor && + TextContentAnchorType_AT_CHARACTER != eAnchor ) + pShapeVertOrientRelState->mnIndex = -1; + if( pShapeVertOrientRelPageState && TextContentAnchorType_AT_PAGE != eAnchor ) + pShapeVertOrientRelPageState->mnIndex = -1; + if( pShapeVertOrientRelFrameState && TextContentAnchorType_AT_FRAME != eAnchor ) + pShapeVertOrientRelFrameState->mnIndex = -1; + } + + // list style name: remove list style if it is the default outline style + if( pListStyleName != nullptr ) + { + OUString sListStyleName; + pListStyleName->maValue >>= sListStyleName; + if( lcl_IsOutlineStyle( GetExport(), sListStyleName ) ) + pListStyleName->mnIndex = -1; + } + + if( pClipState != nullptr && pClip11State != nullptr ) + pClip11State->mnIndex = -1; + + // When both background attributes are available export the visible one + if (pCharHighlight) + { + Color nColor = COL_TRANSPARENT; + pCharHighlight->maValue >>= nColor; + if( nColor == COL_TRANSPARENT ) + { + // actually this would not be exported as transparent anyway + // and we'd need another property CharHighlightTransparent for that + pCharHighlight->mnIndex = -1; + } + // When both background attributes are available export the visible one + else if(pCharBackground) + { + assert(pCharBackgroundTransparency); // always together + pCharBackground->mnIndex = -1; + pCharBackgroundTransparency->mnIndex = -1; + } + } + + SvXMLExportPropertyMapper::ContextFilter(bEnableFoFontFamily, rProperties, rPropSet); +} + +namespace { + +bool lcl_IsOutlineStyle(const SvXMLExport &rExport, std::u16string_view rName) +{ + Reference< XChapterNumberingSupplier > + xCNSupplier(rExport.GetModel(), UNO_QUERY); + + OUString sOutlineName; + + if (xCNSupplier.is()) + { + Reference xNumRule( + xCNSupplier->getChapterNumberingRules(), UNO_QUERY ); + SAL_WARN_IF( !xNumRule.is(), "xmloff", "no chapter numbering rules" ); + if (xNumRule.is()) + { + xNumRule->getPropertyValue("Name") >>= sOutlineName; + } + } + + return rName == sOutlineName; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtexppr.hxx b/xmloff/source/text/txtexppr.hxx new file mode 100644 index 000000000..626261364 --- /dev/null +++ b/xmloff/source/text/txtexppr.hxx @@ -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/. + * + * 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 +#include "txtdrope.hxx" +#include +#include +#include + +class SvXMLExport; +class XMLTextExportPropertySetMapper: public SvXMLExportPropertyMapper +{ + SvXMLExport& rExport; + + OUString sDropCharStyle; + bool bDropWholeWord; + + void ContextFontFilter( + bool bEnableFoFontFamily, + XMLPropertyState *pFontNameState, + XMLPropertyState *pFontFamilyNameState, + XMLPropertyState *pFontStyleNameState, + XMLPropertyState *pFontFamilyState, + XMLPropertyState *pFontPitchState, + XMLPropertyState *pFontCharsetState ) const; + static void ContextFontHeightFilter( + XMLPropertyState* pCharHeightState, + XMLPropertyState* pCharPropHeightState, + XMLPropertyState* pCharDiffHeightState ); + +private: +// SvXMLUnitConverter& mrUnitConverter; +// const Reference< xml::sax::XDocumentHandler > & mrHandler; + XMLTextDropCapExport maDropCapExport; + SvxXMLTabStopExport maTabStopExport; + XMLTextColumnsExport maTextColumnsExport; + XMLBackgroundImageExport maBackgroundImageExport; + + /** Application-specific filter. By default do nothing. */ + virtual void ContextFilter( + bool bEnableFoFontFamily, + ::std::vector< XMLPropertyState >& rProperties, + const css::uno::Reference< css::beans::XPropertySet >& rPropSet ) const override; + const SvXMLExport& GetExport() const { return rExport; } + +public: + + XMLTextExportPropertySetMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLExport& rExt ); + virtual ~XMLTextExportPropertySetMapper() override; + + virtual void handleElementItem( + SvXMLExport& rExport, + const XMLPropertyState& rProperty, + SvXmlExportFlags nFlags, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const override; + + virtual void handleSpecialItem( + SvXMLAttributeList& rAttrList, + const XMLPropertyState& rProperty, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap, + const ::std::vector< XMLPropertyState > *pProperties, + sal_uInt32 nIdx ) const override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtflde.cxx b/xmloff/source/text/txtflde.cxx new file mode 100644 index 000000000..54341aab0 --- /dev/null +++ b/xmloff/source/text/txtflde.cxx @@ -0,0 +1,3550 @@ +/* -*- 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 . + */ + + +/** @#file + * + * export of all text fields + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "XMLTextCharStyleNamesElementExport.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +using namespace ::std; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::container; +using namespace ::xmloff::token; + + +char const FIELD_SERVICE_SENDER[] = "ExtendedUser"; +char const FIELD_SERVICE_AUTHOR[] = "Author"; +char const FIELD_SERVICE_JUMPEDIT[] = "JumpEdit"; +char const FIELD_SERVICE_GETEXP[] = "GetExpression"; +char const FIELD_SERVICE_SETEXP[] = "SetExpression"; +char const FIELD_SERVICE_USER[] = "User"; +char const FIELD_SERVICE_INPUT[] = "Input"; +char const FIELD_SERVICE_USERINPUT[] = "InputUser"; +char const FIELD_SERVICE_DATETIME[] = "DateTime"; +char const FIELD_SERVICE_PAGENUMBER[] = "PageNumber"; +char const FIELD_SERVICE_DB_NEXT[] = "DatabaseNextSet"; +char const FIELD_SERVICE_DB_SELECT[] = "DatabaseNumberOfSet"; +char const FIELD_SERVICE_DB_NUMBER[] = "DatabaseSetNumber"; +char const FIELD_SERVICE_DB_DISPLAY[] = "Database"; +char const FIELD_SERVICE_DB_NAME[] = "DatabaseName"; +char const FIELD_SERVICE_CONDITIONAL_TEXT[] = "ConditionalText"; +char const FIELD_SERVICE_HIDDEN_TEXT[] = "HiddenText"; +char const FIELD_SERVICE_HIDDEN_PARAGRAPH[] = "HiddenParagraph"; +char const FIELD_SERVICE_DOC_INFO_CHANGE_AUTHOR[] = "DocInfo.ChangeAuthor"; +char const FIELD_SERVICE_DOC_INFO_CHANGE_AUTHOR2[] = "docinfo.ChangeAuthor"; +char const FIELD_SERVICE_DOC_INFO_CHANGE_DATE_TIME[] = "DocInfo.ChangeDateTime"; +char const FIELD_SERVICE_DOC_INFO_CHANGE_DATE_TIME2[] = "docinfo.ChangeDateTime"; +char const FIELD_SERVICE_DOC_INFO_EDIT_TIME[] = "DocInfo.EditTime"; +char const FIELD_SERVICE_DOC_INFO_EDIT_TIME2[] = "docinfo.EditTime"; +char const FIELD_SERVICE_DOC_INFO_DESCRIPTION[] = "DocInfo.Description"; +char const FIELD_SERVICE_DOC_INFO_DESCRIPTION2[] = "docinfo.Description"; +char const FIELD_SERVICE_DOC_INFO_CREATE_AUTHOR[] = "DocInfo.CreateAuthor"; +char const FIELD_SERVICE_DOC_INFO_CREATE_AUTHOR2[] = "docinfo.CreateAuthor"; +char const FIELD_SERVICE_DOC_INFO_CREATE_DATE_TIME[] = "DocInfo.CreateDateTime"; +char const FIELD_SERVICE_DOC_INFO_CREATE_DATE_TIME2[] = "docinfo.CreateDateTime"; +char const FIELD_SERVICE_DOC_INFO_CUSTOM[] = "DocInfo.Custom"; +char const FIELD_SERVICE_DOC_INFO_CUSTOM2[] = "docinfo.Custom"; +char const FIELD_SERVICE_DOC_INFO_PRINT_AUTHOR[] = "DocInfo.PrintAuthor"; +char const FIELD_SERVICE_DOC_INFO_PRINT_AUTHOR2[] = "docinfo.PrintAuthor"; +char const FIELD_SERVICE_DOC_INFO_PRINT_DATE_TIME[] = "DocInfo.PrintDateTime"; +char const FIELD_SERVICE_DOC_INFO_PRINT_DATE_TIME2[] = "docinfo.PrintDateTime"; +char const FIELD_SERVICE_DOC_INFO_KEY_WORDS[] = "DocInfo.KeyWords"; +char const FIELD_SERVICE_DOC_INFO_KEY_WORDS2[] = "docinfo.KeyWords"; +char const FIELD_SERVICE_DOC_INFO_SUBJECT[] = "DocInfo.Subject"; +char const FIELD_SERVICE_DOC_INFO_SUBJECT2[] = "docinfo.Subject"; +char const FIELD_SERVICE_DOC_INFO_TITLE[] = "DocInfo.Title"; +char const FIELD_SERVICE_DOC_INFO_TITLE2[] = "docinfo.Title"; +char const FIELD_SERVICE_DOC_INFO_REVISION[] = "DocInfo.Revision"; +char const FIELD_SERVICE_DOC_INFO_REVISION2[] = "docinfo.Revision"; +char const FIELD_SERVICE_FILE_NAME[] = "FileName"; +char const FIELD_SERVICE_CHAPTER[] = "Chapter"; +char const FIELD_SERVICE_TEMPLATE_NAME[] = "TemplateName"; +char const FIELD_SERVICE_PAGE_COUNT[] = "PageCount"; +char const FIELD_SERVICE_PARAGRAPH_COUNT[] = "ParagraphCount"; +char const FIELD_SERVICE_WORD_COUNT[] = "WordCount"; +char const FIELD_SERVICE_CHARACTER_COUNT[] = "CharacterCount"; +char const FIELD_SERVICE_TABLE_COUNT[] = "TableCount"; +char const FIELD_SERVICE_GRAPHIC_COUNT[] = "GraphicObjectCount"; +char const FIELD_SERVICE_OBJECT_COUNT[] = "EmbeddedObjectCount"; +char const FIELD_SERVICE_REFERENCE_PAGE_SET[] = "ReferencePageSet"; +char const FIELD_SERVICE_REFERENCE_PAGE_GET[] = "ReferencePageGet"; +char const FIELD_SERVICE_SHEET_NAME[] = "SheetName"; +char const FIELD_SERVICE_PAGE_NAME[] = "PageName"; +char const FIELD_SERVICE_MACRO[] = "Macro"; +char const FIELD_SERVICE_GET_REFERENCE[] = "GetReference"; +char const FIELD_SERVICE_DDE[] = "DDE"; +char const FIELD_SERVICE_URL[] = "URL"; +char const FIELD_SERVICE_BIBLIOGRAPHY[] = "Bibliography"; +char const FIELD_SERVICE_SCRIPT[] = "Script"; +char const FIELD_SERVICE_ANNOTATION[] = "Annotation"; +char const FIELD_SERVICE_COMBINED_CHARACTERS[] = "CombinedCharacters"; +char const FIELD_SERVICE_META[] = "MetadataField"; +char const FIELD_SERVICE_MEASURE[] = "Measure"; +char const FIELD_SERVICE_TABLE_FORMULA[] = "TableFormula"; +char const FIELD_SERVICE_DROP_DOWN[] = "DropDown"; + +namespace +{ +/// Walks up the parent chain of xText and returns the topmost text. +uno::Reference GetToplevelText(const uno::Reference& xText) +{ + uno::Reference xRet = xText; + while (true) + { + uno::Reference xPropertySet(xRet, uno::UNO_QUERY); + if (!xPropertySet.is()) + return xRet; + + if (!xPropertySet->getPropertySetInfo()->hasPropertyByName("ParentText")) + return xRet; + + uno::Reference xParent; + if (xPropertySet->getPropertyValue("ParentText") >>= xParent) + xRet = xParent; + else + return xRet; + } + return xRet; +} +} + +SvXMLEnumStringMapEntry const aFieldServiceNameMapping[] = +{ + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_SENDER, FIELD_ID_SENDER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_AUTHOR, FIELD_ID_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_JUMPEDIT, FIELD_ID_PLACEHOLDER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_GETEXP, FIELD_ID_VARIABLE_GET ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_SETEXP, FIELD_ID_VARIABLE_SET ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_USER, FIELD_ID_USER_GET ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_INPUT, FIELD_ID_TEXT_INPUT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_USERINPUT, FIELD_ID_USER_INPUT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DATETIME, FIELD_ID_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PAGENUMBER, FIELD_ID_PAGENUMBER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_REFERENCE_PAGE_SET, FIELD_ID_REFPAGE_SET ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_REFERENCE_PAGE_GET, FIELD_ID_REFPAGE_GET ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_NEXT, FIELD_ID_DATABASE_NEXT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_SELECT, FIELD_ID_DATABASE_SELECT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_NUMBER, FIELD_ID_DATABASE_NUMBER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_DISPLAY, FIELD_ID_DATABASE_DISPLAY ), + // workaround for #no-bug#: Database/DataBase + ENUM_STRING_MAP_ENTRY( "DataBase", FIELD_ID_DATABASE_DISPLAY ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DB_NAME, FIELD_ID_DATABASE_NAME ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CREATE_AUTHOR, FIELD_ID_DOCINFO_CREATION_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CREATE_AUTHOR2, FIELD_ID_DOCINFO_CREATION_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CREATE_DATE_TIME, FIELD_ID_DOCINFO_CREATION_TIME), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CREATE_DATE_TIME2, FIELD_ID_DOCINFO_CREATION_TIME), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CHANGE_AUTHOR, FIELD_ID_DOCINFO_SAVE_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CHANGE_AUTHOR2, FIELD_ID_DOCINFO_SAVE_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CHANGE_DATE_TIME, FIELD_ID_DOCINFO_SAVE_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CHANGE_DATE_TIME2, FIELD_ID_DOCINFO_SAVE_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_EDIT_TIME, FIELD_ID_DOCINFO_EDIT_DURATION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_EDIT_TIME2, FIELD_ID_DOCINFO_EDIT_DURATION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_DESCRIPTION, FIELD_ID_DOCINFO_DESCRIPTION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_DESCRIPTION2, FIELD_ID_DOCINFO_DESCRIPTION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CUSTOM, FIELD_ID_DOCINFO_CUSTOM ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_CUSTOM2, FIELD_ID_DOCINFO_CUSTOM ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_PRINT_AUTHOR, FIELD_ID_DOCINFO_PRINT_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_PRINT_AUTHOR2, FIELD_ID_DOCINFO_PRINT_AUTHOR ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_PRINT_DATE_TIME, FIELD_ID_DOCINFO_PRINT_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_PRINT_DATE_TIME2, FIELD_ID_DOCINFO_PRINT_TIME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_KEY_WORDS, FIELD_ID_DOCINFO_KEYWORDS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_KEY_WORDS2, FIELD_ID_DOCINFO_KEYWORDS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_SUBJECT, FIELD_ID_DOCINFO_SUBJECT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_SUBJECT2, FIELD_ID_DOCINFO_SUBJECT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_TITLE, FIELD_ID_DOCINFO_TITLE ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_TITLE2, FIELD_ID_DOCINFO_TITLE ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_REVISION, FIELD_ID_DOCINFO_REVISION ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DOC_INFO_REVISION2, FIELD_ID_DOCINFO_REVISION ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_CONDITIONAL_TEXT, FIELD_ID_CONDITIONAL_TEXT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_HIDDEN_TEXT, FIELD_ID_HIDDEN_TEXT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_HIDDEN_PARAGRAPH, FIELD_ID_HIDDEN_PARAGRAPH ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_FILE_NAME, FIELD_ID_FILE_NAME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_CHAPTER, FIELD_ID_CHAPTER ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_TEMPLATE_NAME, FIELD_ID_TEMPLATE_NAME ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PAGE_COUNT, FIELD_ID_COUNT_PAGES ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PARAGRAPH_COUNT, FIELD_ID_COUNT_PARAGRAPHS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_WORD_COUNT, FIELD_ID_COUNT_WORDS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_CHARACTER_COUNT, FIELD_ID_COUNT_CHARACTERS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_TABLE_COUNT, FIELD_ID_COUNT_TABLES ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_GRAPHIC_COUNT, FIELD_ID_COUNT_GRAPHICS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_OBJECT_COUNT, FIELD_ID_COUNT_OBJECTS ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_MACRO, FIELD_ID_MACRO ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_GET_REFERENCE, FIELD_ID_REF_REFERENCE ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DDE, FIELD_ID_DDE ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_BIBLIOGRAPHY, FIELD_ID_BIBLIOGRAPHY ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_SCRIPT, FIELD_ID_SCRIPT ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_ANNOTATION, FIELD_ID_ANNOTATION ), + + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_COMBINED_CHARACTERS, FIELD_ID_COMBINED_CHARACTERS ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_META, FIELD_ID_META ), + + // non-writer fields + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_SHEET_NAME, FIELD_ID_SHEET_NAME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_PAGE_NAME, FIELD_ID_PAGENAME ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_URL, FIELD_ID_URL ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_MEASURE, FIELD_ID_MEASURE ), + + // deprecated fields + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_TABLE_FORMULA, FIELD_ID_TABLE_FORMULA ), + ENUM_STRING_MAP_ENTRY( FIELD_SERVICE_DROP_DOWN, FIELD_ID_DROP_DOWN ), + + { nullptr, 0, FieldIdEnum(0) } +}; + + +// property accessor helper functions +static bool GetBoolProperty(const OUString&, + const Reference &); +static bool GetOptionalBoolProperty(const OUString&, + const Reference &, + const Reference &, + bool bDefault); +static double GetDoubleProperty(const OUString&, + const Reference &); +static OUString GetStringProperty(const OUString&, + const Reference &); +static sal_Int32 GetIntProperty(const OUString&, + const Reference &); +static sal_Int16 GetInt16Property(const OUString&, + const Reference &); +static sal_Int8 GetInt8Property(const OUString&, + const Reference &); +static util::DateTime GetDateTimeProperty( const OUString& sPropName, + const Reference & xPropSet); +static Sequence GetStringSequenceProperty( + const OUString& sPropName, + const Reference & xPropSet); + + + // service names +constexpr OUStringLiteral gsServicePrefix(u"com.sun.star.text.textfield."); +constexpr OUStringLiteral gsFieldMasterPrefix(u"com.sun.star.text.FieldMaster."); +constexpr OUStringLiteral gsPresentationServicePrefix(u"com.sun.star.presentation.TextField."); + + // property names +constexpr OUStringLiteral gsPropertyAdjust(u"Adjust"); +constexpr OUStringLiteral gsPropertyAuthor(u"Author"); +constexpr OUStringLiteral gsPropertyChapterFormat(u"ChapterFormat"); +constexpr OUStringLiteral gsPropertyChapterNumberingLevel(u"ChapterNumberingLevel"); +constexpr OUStringLiteral gsPropertyCharStyleNames(u"CharStyleNames"); +constexpr OUStringLiteral gsPropertyCondition(u"Condition"); +constexpr OUStringLiteral gsPropertyContent(u"Content"); +constexpr OUStringLiteral gsPropertyDataBaseName(u"DataBaseName"); +constexpr OUStringLiteral gsPropertyDataBaseURL(u"DataBaseURL"); +constexpr OUStringLiteral gsPropertyDataColumnName(u"DataColumnName"); +constexpr OUStringLiteral gsPropertyDataCommandType(u"DataCommandType"); +constexpr OUStringLiteral gsPropertyDataTableName(u"DataTableName"); +constexpr OUStringLiteral gsPropertyDateTime(u"DateTime"); +constexpr OUStringLiteral gsPropertyDateTimeValue(u"DateTimeValue"); +constexpr OUStringLiteral gsPropertyDDECommandElement(u"DDECommandElement"); +constexpr OUStringLiteral gsPropertyDDECommandFile(u"DDECommandFile"); +constexpr OUStringLiteral gsPropertyDDECommandType(u"DDECommandType"); +constexpr OUStringLiteral gsPropertyDependentTextFields(u"DependentTextFields"); +constexpr OUStringLiteral gsPropertyFalseContent(u"FalseContent"); +constexpr OUStringLiteral gsPropertyFields(u"Fields"); +constexpr OUStringLiteral gsPropertyFieldSubType(u"UserDataType"); +constexpr OUStringLiteral gsPropertyFileFormat(u"FileFormat"); +constexpr OUStringLiteral gsPropertyFullName(u"FullName"); +constexpr OUStringLiteral gsPropertyHint(u"Hint"); +constexpr OUStringLiteral gsPropertyInitials(u"Initials"); +constexpr OUStringLiteral gsPropertyInstanceName(u"InstanceName"); +constexpr OUStringLiteral gsPropertyIsAutomaticUpdate(u"IsAutomaticUpdate"); +constexpr OUStringLiteral gsPropertyIsConditionTrue(u"IsConditionTrue"); +constexpr OUStringLiteral gsPropertyIsDataBaseFormat(u"DataBaseFormat"); +constexpr OUStringLiteral gsPropertyIsDate(u"IsDate"); +constexpr OUStringLiteral gsPropertyIsExpression(u"IsExpression"); +constexpr OUStringLiteral gsPropertyIsFixed(u"IsFixed"); +constexpr OUStringLiteral gsPropertyIsFixedLanguage(u"IsFixedLanguage"); +constexpr OUStringLiteral gsPropertyIsHidden(u"IsHidden"); +constexpr OUStringLiteral gsPropertyIsInput(u"Input"); +constexpr OUStringLiteral gsPropertyIsShowFormula(u"IsShowFormula"); +constexpr OUStringLiteral gsPropertyIsVisible(u"IsVisible"); +constexpr OUStringLiteral gsPropertyItems(u"Items"); +constexpr OUStringLiteral gsPropertyLevel(u"Level"); +constexpr OUStringLiteral gsPropertyMeasureKind(u"Kind"); +constexpr OUStringLiteral gsPropertyName(u"Name"); +constexpr OUStringLiteral gsPropertyNumberFormat(u"NumberFormat"); +constexpr OUStringLiteral gsPropertyNumberingSeparator(u"NumberingSeparator"); +constexpr OUStringLiteral gsPropertyNumberingType(u"NumberingType"); +constexpr OUStringLiteral gsPropertyOffset(u"Offset"); +constexpr OUStringLiteral gsPropertyOn(u"On"); +constexpr OUStringLiteral gsPropertyPlaceholderType(u"PlaceHolderType"); +constexpr OUStringLiteral gsPropertyReferenceFieldPart(u"ReferenceFieldPart"); +constexpr OUStringLiteral gsPropertyReferenceFieldSource(u"ReferenceFieldSource"); +constexpr OUStringLiteral gsPropertyReferenceFieldLanguage(u"ReferenceFieldLanguage"); +constexpr OUStringLiteral gsPropertyScriptType(u"ScriptType"); +constexpr OUStringLiteral gsPropertySelectedItem(u"SelectedItem"); +constexpr OUStringLiteral gsPropertySequenceNumber(u"SequenceNumber"); +constexpr OUStringLiteral gsPropertySequenceValue(u"SequenceValue"); +constexpr OUStringLiteral gsPropertySetNumber(u"SetNumber"); +constexpr OUStringLiteral gsPropertySourceName(u"SourceName"); +constexpr OUStringLiteral gsPropertySubType(u"SubType"); +constexpr OUStringLiteral gsPropertyTargetFrame(u"TargetFrame"); +constexpr OUStringLiteral gsPropertyTrueContent(u"TrueContent"); +constexpr OUStringLiteral gsPropertyURL(u"URL"); +constexpr OUStringLiteral gsPropertyURLContent(u"URLContent"); +constexpr OUStringLiteral gsPropertyUserText(u"UserText"); +constexpr OUStringLiteral gsPropertyValue(u"Value"); +constexpr OUStringLiteral gsPropertyVariableName(u"VariableName"); +constexpr OUStringLiteral gsPropertyHelp(u"Help"); +constexpr OUStringLiteral gsPropertyTooltip(u"Tooltip"); +constexpr OUStringLiteral gsPropertyTextRange(u"TextRange"); + +XMLTextFieldExport::XMLTextFieldExport( SvXMLExport& rExp, + std::unique_ptr pCombinedCharState) + : rExport(rExp), + pCombinedCharactersPropertyState(std::move(pCombinedCharState)) +{ + SetExportOnlyUsedFieldDeclarations(); +} + +XMLTextFieldExport::~XMLTextFieldExport() +{ +} + +/// get the field ID (as in FieldIDEnum) from XTextField +enum FieldIdEnum XMLTextFieldExport::GetFieldID( + const Reference & rTextField, + const Reference & xPropSet) +{ + // get service names for rTextField (via XServiceInfo service) + Reference xService(rTextField, UNO_QUERY); + const Sequence aServices = xService->getSupportedServiceNames(); + + OUString sFieldName; // service name postfix of current field + + // search for TextField service name + const OUString* pNames = std::find_if(aServices.begin(), aServices.end(), + [](const OUString& rName) { return rName.matchIgnoreAsciiCase(gsServicePrefix); }); + if (pNames != aServices.end()) + { + // TextField found => postfix is field type! + sFieldName = pNames->copy(gsServicePrefix.getLength()); + } + + // if this is not a normal text field, check if it's a presentation text field + if( sFieldName.isEmpty() ) + { + // search for TextField service name + pNames = std::find_if(aServices.begin(), aServices.end(), + [](const OUString& rName) { return rName.startsWith(gsPresentationServicePrefix); }); + if (pNames != aServices.end()) + { + // TextField found => postfix is field type! + sFieldName = pNames->copy(gsPresentationServicePrefix.getLength()); + } + + if( !sFieldName.isEmpty() ) + { + if( sFieldName == "Header" ) + { + return FIELD_ID_DRAW_HEADER; + } + else if( sFieldName == "Footer" ) + { + return FIELD_ID_DRAW_FOOTER; + } + else if( sFieldName == "DateTime" ) + { + return FIELD_ID_DRAW_DATE_TIME; + } + } + } + + // map postfix of service name to field ID + DBG_ASSERT(!sFieldName.isEmpty(), "no TextField service found!"); + return MapFieldName(sFieldName, xPropSet); +} + +enum FieldIdEnum XMLTextFieldExport::MapFieldName( + std::u16string_view sFieldName, // field (master) name + const Reference & xPropSet) // for subtype +{ + // we'll proceed in 2 steps: + // a) map service name to preliminary FIELD_ID + // b) map those prelim. FIELD_IDs that correspond to several field types + // (in our (XML) world) to final FIELD IDs + + + // a) find prelim. FIELD_ID via aFieldServiceMapping + + // check for non-empty service name + DBG_ASSERT(!sFieldName.empty(), "no valid service name!"); + enum FieldIdEnum nToken = FIELD_ID_UNKNOWN; + if (!sFieldName.empty()) + { + // map name to prelim. ID + bool bRet = SvXMLUnitConverter::convertEnum( + nToken, sFieldName, aFieldServiceNameMapping); + + // check return + DBG_ASSERT(bRet, "Unknown field service name encountered!"); + } + + // b) map prelim. to final FIELD_IDs + switch (nToken) { + case FIELD_ID_VARIABLE_SET: + if (GetBoolProperty(gsPropertyIsInput, xPropSet)) + { + nToken = FIELD_ID_VARIABLE_INPUT; + } + else + { + switch (GetIntProperty(gsPropertySubType, xPropSet)) + { + case SetVariableType::STRING: // text field + case SetVariableType::VAR: // num field + nToken = FIELD_ID_VARIABLE_SET; + break; + case SetVariableType::SEQUENCE: + nToken = FIELD_ID_SEQUENCE; + break; + case SetVariableType::FORMULA: + default: + nToken = FIELD_ID_UNKNOWN; + break; + } + } + break; + + case FIELD_ID_VARIABLE_GET: + switch (GetIntProperty(gsPropertySubType, xPropSet)) + { + case SetVariableType::STRING: // text field + case SetVariableType::VAR: // num field + nToken = FIELD_ID_VARIABLE_GET; + break; + case SetVariableType::FORMULA: + nToken = FIELD_ID_EXPRESSION; + break; + case SetVariableType::SEQUENCE: + default: + nToken = FIELD_ID_UNKNOWN; + break; + } + break; + + case FIELD_ID_TIME: + if (GetBoolProperty(gsPropertyIsDate, xPropSet)) + { + nToken = FIELD_ID_DATE; + } + break; + + case FIELD_ID_PAGENUMBER: + // NumberingType not available in non-Writer apps + if (xPropSet->getPropertySetInfo()-> + hasPropertyByName(gsPropertyNumberingType)) + { + if (NumberingType::CHAR_SPECIAL == GetIntProperty( + gsPropertyNumberingType, xPropSet)) + { + nToken = FIELD_ID_PAGESTRING; + } + } + break; + + case FIELD_ID_DOCINFO_CREATION_TIME: + if (GetBoolProperty(gsPropertyIsDate, xPropSet)) + { + nToken = FIELD_ID_DOCINFO_CREATION_DATE; + } + break; + + case FIELD_ID_DOCINFO_PRINT_TIME: + if (GetBoolProperty(gsPropertyIsDate, xPropSet)) + { + nToken = FIELD_ID_DOCINFO_PRINT_DATE; + } + break; + + case FIELD_ID_DOCINFO_SAVE_TIME: + if (GetBoolProperty(gsPropertyIsDate, xPropSet)) + { + nToken = FIELD_ID_DOCINFO_SAVE_DATE; + } + break; + + case FIELD_ID_REF_REFERENCE: + switch (GetInt16Property(gsPropertyReferenceFieldSource, xPropSet)) + { + case ReferenceFieldSource::REFERENCE_MARK: + nToken = FIELD_ID_REF_REFERENCE; + break; + case ReferenceFieldSource::SEQUENCE_FIELD: + nToken = FIELD_ID_REF_SEQUENCE; + break; + case ReferenceFieldSource::BOOKMARK: + nToken = FIELD_ID_REF_BOOKMARK; + break; + case ReferenceFieldSource::FOOTNOTE: + nToken = FIELD_ID_REF_FOOTNOTE; + break; + case ReferenceFieldSource::ENDNOTE: + nToken = FIELD_ID_REF_ENDNOTE; + break; + default: + nToken = FIELD_ID_UNKNOWN; + break; + } + break; + + case FIELD_ID_COMBINED_CHARACTERS: + case FIELD_ID_SCRIPT: + case FIELD_ID_ANNOTATION: + case FIELD_ID_BIBLIOGRAPHY: + case FIELD_ID_DDE: + case FIELD_ID_MACRO: + case FIELD_ID_REFPAGE_SET: + case FIELD_ID_REFPAGE_GET: + case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PARAGRAPHS: + case FIELD_ID_COUNT_WORDS: + case FIELD_ID_COUNT_CHARACTERS: + case FIELD_ID_COUNT_TABLES: + case FIELD_ID_COUNT_GRAPHICS: + case FIELD_ID_COUNT_OBJECTS: + case FIELD_ID_CONDITIONAL_TEXT: + case FIELD_ID_HIDDEN_TEXT: + case FIELD_ID_HIDDEN_PARAGRAPH: + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + case FIELD_ID_DOCINFO_DESCRIPTION: + case FIELD_ID_DOCINFO_CUSTOM: + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + case FIELD_ID_DOCINFO_TITLE: + case FIELD_ID_DOCINFO_SUBJECT: + case FIELD_ID_DOCINFO_KEYWORDS: + case FIELD_ID_DOCINFO_REVISION: + case FIELD_ID_DOCINFO_EDIT_DURATION: + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + case FIELD_ID_TEXT_INPUT: + case FIELD_ID_USER_INPUT: + case FIELD_ID_AUTHOR: + case FIELD_ID_SENDER: + case FIELD_ID_PLACEHOLDER: + case FIELD_ID_USER_GET: + case FIELD_ID_DATABASE_NEXT: + case FIELD_ID_DATABASE_SELECT: + case FIELD_ID_DATABASE_DISPLAY: + case FIELD_ID_DATABASE_NAME: + case FIELD_ID_DATABASE_NUMBER: + case FIELD_ID_TEMPLATE_NAME: + case FIELD_ID_CHAPTER: + case FIELD_ID_FILE_NAME: + case FIELD_ID_META: + case FIELD_ID_SHEET_NAME: + case FIELD_ID_PAGENAME: + case FIELD_ID_MEASURE: + case FIELD_ID_URL: + case FIELD_ID_TABLE_FORMULA: + case FIELD_ID_DROP_DOWN: + ; // these field IDs are final + break; + + default: + nToken = FIELD_ID_UNKNOWN; + } + + // ... and return final FIELD_ID + return nToken; +} + +// is string or numeric field? +bool XMLTextFieldExport::IsStringField( + FieldIdEnum nFieldType, + const Reference & xPropSet) +{ + switch (nFieldType) { + + case FIELD_ID_VARIABLE_GET: + case FIELD_ID_VARIABLE_SET: + case FIELD_ID_VARIABLE_INPUT: + { + // depends on field sub type + return ( GetIntProperty(gsPropertySubType, xPropSet) == + SetVariableType::STRING ); + } + + case FIELD_ID_USER_GET: + case FIELD_ID_USER_INPUT: + { + Reference xTextField(xPropSet, UNO_QUERY); + DBG_ASSERT(xTextField.is(), "field is no XTextField!"); + bool bRet = GetBoolProperty(gsPropertyIsExpression, + GetMasterPropertySet(xTextField)); + return !bRet; + } + + case FIELD_ID_META: + return 0 > GetIntProperty(gsPropertyNumberFormat, xPropSet); + + case FIELD_ID_DATABASE_DISPLAY: + // TODO: depends on... ??? + // workaround #no-bug#: no data type + return 5100 == GetIntProperty(gsPropertyNumberFormat, xPropSet); + + case FIELD_ID_TABLE_FORMULA: + // legacy field: always a number field (because it always has + // a number format) + return false; + + case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PARAGRAPHS: + case FIELD_ID_COUNT_WORDS: + case FIELD_ID_COUNT_CHARACTERS: + case FIELD_ID_COUNT_TABLES: + case FIELD_ID_COUNT_GRAPHICS: + case FIELD_ID_COUNT_OBJECTS: + case FIELD_ID_DOCINFO_SAVE_TIME: + case FIELD_ID_DOCINFO_SAVE_DATE: + case FIELD_ID_DOCINFO_CREATION_DATE: + case FIELD_ID_DOCINFO_CREATION_TIME: + case FIELD_ID_DOCINFO_PRINT_TIME: + case FIELD_ID_DOCINFO_PRINT_DATE: + case FIELD_ID_DOCINFO_EDIT_DURATION: + case FIELD_ID_DOCINFO_REVISION: + case FIELD_ID_DATABASE_NUMBER: + case FIELD_ID_EXPRESSION: + case FIELD_ID_SEQUENCE: + case FIELD_ID_DATE: + case FIELD_ID_TIME: + case FIELD_ID_PAGENUMBER: + case FIELD_ID_REFPAGE_SET: + case FIELD_ID_REFPAGE_GET: + case FIELD_ID_DOCINFO_CUSTOM: + // always number + return false; + + case FIELD_ID_COMBINED_CHARACTERS: + case FIELD_ID_BIBLIOGRAPHY: + case FIELD_ID_DDE: + case FIELD_ID_REF_REFERENCE: + case FIELD_ID_REF_SEQUENCE: + case FIELD_ID_REF_BOOKMARK: + case FIELD_ID_REF_FOOTNOTE: + case FIELD_ID_REF_ENDNOTE: + case FIELD_ID_MACRO: + case FIELD_ID_TEMPLATE_NAME: + case FIELD_ID_CHAPTER: + case FIELD_ID_FILE_NAME: + case FIELD_ID_CONDITIONAL_TEXT: + case FIELD_ID_HIDDEN_TEXT: + case FIELD_ID_HIDDEN_PARAGRAPH: + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + case FIELD_ID_DOCINFO_DESCRIPTION: + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + case FIELD_ID_DOCINFO_TITLE: + case FIELD_ID_DOCINFO_SUBJECT: + case FIELD_ID_DOCINFO_KEYWORDS: + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + case FIELD_ID_DATABASE_NAME: + case FIELD_ID_TEXT_INPUT: + case FIELD_ID_SENDER: + case FIELD_ID_AUTHOR: + case FIELD_ID_PAGENAME: + case FIELD_ID_PAGESTRING: + case FIELD_ID_SHEET_NAME: + case FIELD_ID_MEASURE: + case FIELD_ID_URL: + case FIELD_ID_DROP_DOWN: + // always string: + return true; + + case FIELD_ID_SCRIPT: + case FIELD_ID_ANNOTATION: + case FIELD_ID_DATABASE_NEXT: + case FIELD_ID_DATABASE_SELECT: + case FIELD_ID_PLACEHOLDER: + case FIELD_ID_UNKNOWN: + case FIELD_ID_DRAW_HEADER: + case FIELD_ID_DRAW_FOOTER: + case FIELD_ID_DRAW_DATE_TIME: + default: + OSL_FAIL("unknown field type/field has no content"); + return true; // invalid info; string in case of doubt + } +} + +/// export the styles needed by the given field. Called on first pass +/// through document +void XMLTextFieldExport::ExportFieldAutoStyle( + const Reference & rTextField, const bool bProgress, + const bool bRecursive ) +{ + // get property set + Reference xPropSet(rTextField, UNO_QUERY); + + // add field master to list of used field masters (if desired) + if (nullptr != pUsedMasters) + { + Reference xDepField(rTextField, UNO_QUERY); + if (xDepField.is()) + { + // The direct parent may be just the table cell, while we want the topmost parent, e.g. + // a header text. + Reference xOurText = GetToplevelText(rTextField->getAnchor()->getText()); + + map, set >::iterator aMapIter = + pUsedMasters->find(xOurText); + + // insert a list for our XText (if necessary) + if (aMapIter == pUsedMasters->end()) + { + set aSet; + (*pUsedMasters)[xOurText] = aSet; + aMapIter = pUsedMasters->find(xOurText); + } + + // insert this text field master + OUString sFieldMasterName = GetStringProperty( + gsPropertyInstanceName, xDepField->getTextFieldMaster()); + if (!sFieldMasterName.isEmpty()) + aMapIter->second.insert( sFieldMasterName ); + } + // else: no dependent field -> no master -> ignore + } + + // get Field ID + FieldIdEnum nToken = GetFieldID(rTextField, xPropSet); + + // export the character style for all fields + // with one exception: combined character fields export their own + // text style below + Reference xRangePropSet(rTextField->getAnchor(), UNO_QUERY); + if (FIELD_ID_COMBINED_CHARACTERS != nToken) + { + GetExport().GetTextParagraphExport()->Add( + XmlStyleFamily::TEXT_TEXT, xRangePropSet); + } + + // process special styles for each field (e.g. data styles) + switch (nToken) { + + case FIELD_ID_DATABASE_DISPLAY: + { + sal_Int32 nFormat = GetIntProperty(gsPropertyNumberFormat, xPropSet); + // workaround: #no-bug#; see IsStringField(...) + if ( (5100 != nFormat) && + !GetBoolProperty(gsPropertyIsDataBaseFormat, xPropSet) ) + { + GetExport().addDataStyle(nFormat); + } + break; + } + + case FIELD_ID_DATE: + case FIELD_ID_TIME: + { + // date and time fields are always number fields, but the + // NumberFormat property is optional (e.g. Calc doesn't + // support it) + Reference xPropSetInfo( + xPropSet->getPropertySetInfo() ); + if ( xPropSetInfo->hasPropertyByName( gsPropertyNumberFormat ) ) + { + sal_Int32 nFormat = + GetIntProperty(gsPropertyNumberFormat, xPropSet); + + // nFormat may be -1 for numeric fields that display their + // variable name. (Maybe this should be a field type, then?) + if (nFormat != -1) + { + if( ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + xPropSet, xPropSetInfo, false ) ) + { + nFormat = + GetExport().dataStyleForceSystemLanguage(nFormat); + } + + GetExport().addDataStyle( nFormat, + nToken == FIELD_ID_TIME ); + } + } + } + break; + + case FIELD_ID_META: + // recurse into content (does not export element, so can be done first) + if (bRecursive) + { + bool dummy_for_autostyles(true); + ExportMetaField(xPropSet, true, bProgress, dummy_for_autostyles); + } + [[fallthrough]]; + case FIELD_ID_DOCINFO_PRINT_TIME: + case FIELD_ID_DOCINFO_PRINT_DATE: + case FIELD_ID_DOCINFO_CREATION_DATE: + case FIELD_ID_DOCINFO_CREATION_TIME: + case FIELD_ID_DOCINFO_SAVE_TIME: + case FIELD_ID_DOCINFO_SAVE_DATE: + case FIELD_ID_DOCINFO_EDIT_DURATION: + case FIELD_ID_VARIABLE_SET: + case FIELD_ID_VARIABLE_GET: + case FIELD_ID_VARIABLE_INPUT: + case FIELD_ID_USER_GET: + case FIELD_ID_EXPRESSION: + case FIELD_ID_TABLE_FORMULA: + case FIELD_ID_DOCINFO_CUSTOM: + // register number format, if this is a numeric field + if (! IsStringField(nToken, xPropSet)) { + + sal_Int32 nFormat = + GetIntProperty(gsPropertyNumberFormat, xPropSet); + + // nFormat may be -1 for numeric fields that display their + // variable name. (Maybe this should be a field type, then?) + if (nFormat != -1) + { + // handle formats for fixed language fields + // for all these fields (except table formula) + if( ( nToken != FIELD_ID_TABLE_FORMULA ) && + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + xPropSet, xPropSet->getPropertySetInfo(), + false ) ) + { + nFormat = + GetExport().dataStyleForceSystemLanguage(nFormat); + } + + GetExport().addDataStyle(nFormat); + } + } + break; + + case FIELD_ID_COMBINED_CHARACTERS: + { + // export text style with the addition of the combined characters + DBG_ASSERT(nullptr != pCombinedCharactersPropertyState, + "need proper PropertyState for combined characters"); + o3tl::span aStates( pCombinedCharactersPropertyState.get(), 1 ); + GetExport().GetTextParagraphExport()->Add( + XmlStyleFamily::TEXT_TEXT, xRangePropSet, + aStates); + break; + } + + case FIELD_ID_SCRIPT: + case FIELD_ID_ANNOTATION: + case FIELD_ID_BIBLIOGRAPHY: + case FIELD_ID_DDE: + case FIELD_ID_REF_REFERENCE: + case FIELD_ID_REF_SEQUENCE: + case FIELD_ID_REF_BOOKMARK: + case FIELD_ID_REF_FOOTNOTE: + case FIELD_ID_REF_ENDNOTE: + case FIELD_ID_MACRO: + case FIELD_ID_REFPAGE_SET: + case FIELD_ID_REFPAGE_GET: + case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PARAGRAPHS: + case FIELD_ID_COUNT_WORDS: + case FIELD_ID_COUNT_CHARACTERS: + case FIELD_ID_COUNT_TABLES: + case FIELD_ID_COUNT_GRAPHICS: + case FIELD_ID_COUNT_OBJECTS: + case FIELD_ID_CONDITIONAL_TEXT: + case FIELD_ID_HIDDEN_TEXT: + case FIELD_ID_HIDDEN_PARAGRAPH: + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + case FIELD_ID_DOCINFO_DESCRIPTION: + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + case FIELD_ID_DOCINFO_TITLE: + case FIELD_ID_DOCINFO_SUBJECT: + case FIELD_ID_DOCINFO_KEYWORDS: + case FIELD_ID_DOCINFO_REVISION: + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + case FIELD_ID_SEQUENCE: + case FIELD_ID_PAGENAME: + case FIELD_ID_PAGENUMBER: + case FIELD_ID_PAGESTRING: + case FIELD_ID_AUTHOR: + case FIELD_ID_SENDER: + case FIELD_ID_PLACEHOLDER: + case FIELD_ID_USER_INPUT: + case FIELD_ID_TEXT_INPUT: + case FIELD_ID_DATABASE_NEXT: + case FIELD_ID_DATABASE_SELECT: + case FIELD_ID_DATABASE_NAME: + case FIELD_ID_DATABASE_NUMBER: + case FIELD_ID_TEMPLATE_NAME: + case FIELD_ID_CHAPTER: + case FIELD_ID_FILE_NAME: + case FIELD_ID_SHEET_NAME: + case FIELD_ID_MEASURE: + case FIELD_ID_URL: + case FIELD_ID_DROP_DOWN: + case FIELD_ID_DRAW_DATE_TIME: + case FIELD_ID_DRAW_FOOTER: + case FIELD_ID_DRAW_HEADER: + ; // no formats for these fields! + break; + + case FIELD_ID_UNKNOWN: + default: + OSL_FAIL("unknown field type!"); + // ignore -> no format for unknown + break; + } +} + +/// export the given field to XML. Called on second pass through document +void XMLTextFieldExport::ExportField( + const Reference & rTextField, bool bProgress, + bool & rPrevCharIsSpace) +{ + // get property set + Reference xPropSet(rTextField, UNO_QUERY); + + // get property set of range (for the attributes) + Reference xRangePropSet(rTextField->getAnchor(), UNO_QUERY); + + // get Field ID + enum FieldIdEnum nToken = GetFieldID(rTextField, xPropSet); + + // special treatment for combined characters field, because it is + // exported as a style + const XMLPropertyState* aStates[] = { pCombinedCharactersPropertyState.get(), nullptr }; + const XMLPropertyState **pStates = + FIELD_ID_COMBINED_CHARACTERS == nToken + ? aStates + : nullptr; + + // find out whether we need to set the style + bool bIsUICharStyle; + bool bHasAutoStyle; + OUString sStyle = GetExport().GetTextParagraphExport()-> + FindTextStyle( xRangePropSet, bIsUICharStyle, bHasAutoStyle, pStates ); + bool bHasStyle = !sStyle.isEmpty(); + + { + Reference xRangePropSetInfo; + XMLTextCharStyleNamesElementExport aCharStylesExport( + GetExport(), bIsUICharStyle && + GetExport().GetTextParagraphExport() + ->GetCharStyleNamesPropInfoCache().hasProperty( + xRangePropSet, xRangePropSetInfo ), bHasAutoStyle, + xRangePropSet, gsPropertyCharStyleNames ); + + // export span with style (if necessary) + // (except for combined characters field) + if( bHasStyle ) + { + // export element + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyle ) ); + } + SvXMLElementExport aSpan( GetExport(), bHasStyle, + XML_NAMESPACE_TEXT, XML_SPAN, + false, false); + + // finally, export the field itself + ExportFieldHelper( rTextField, xPropSet, xRangePropSet, nToken, + bProgress, rPrevCharIsSpace); + } +} + +/// export the given field to XML. Called on second pass through document +void XMLTextFieldExport::ExportFieldHelper( + const Reference & rTextField, + const Reference & rPropSet, + const Reference &, + enum FieldIdEnum nToken, + bool bProgress, + bool & rPrevCharIsSpace) +{ + // get property set info (because some attributes are not support + // in all implementations) + Reference xPropSetInfo(rPropSet->getPropertySetInfo()); + + OUString sPresentation = rTextField->getPresentation(false); + + // process each field type + switch (nToken) { + case FIELD_ID_AUTHOR: + // author field: fixed, field (sub-)type + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_FIXED, + (GetBoolProperty(gsPropertyIsFixed, rPropSet) ? XML_TRUE : XML_FALSE) ); + } + ExportElement(MapAuthorFieldName(rPropSet), sPresentation); + break; + + case FIELD_ID_SENDER: + // sender field: fixed, field (sub-)type + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), true); + ExportElement(MapSenderFieldName(rPropSet), sPresentation); + break; + + case FIELD_ID_PLACEHOLDER: + // placeholder field: type, name, description + ProcessString(XML_PLACEHOLDER_TYPE, + MapPlaceholderType( + GetInt16Property(gsPropertyPlaceholderType, rPropSet))); + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint,rPropSet), true); + ExportElement(XML_PLACEHOLDER, sPresentation); + break; + + case FIELD_ID_VARIABLE_SET: + { + // variable set field: name, visible, format&value + ProcessString(XML_NAME, + GetStringProperty(gsPropertyVariableName, rPropSet)); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ProcessString(XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation); + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation, + GetDoubleProperty(gsPropertyValue, rPropSet), + true, true, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + ExportElement(XML_VARIABLE_SET, sPresentation); + break; + } + case FIELD_ID_VARIABLE_GET: + { + // variable get field: name, format&value + ProcessString(XML_NAME, + GetStringProperty(gsPropertyContent, rPropSet)); + bool bCmd = GetBoolProperty(gsPropertyIsShowFormula, rPropSet); + ProcessDisplay(true, bCmd); + // show style, unless name will be shown + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + "", u"", 0.0, // values not used + false, + false, + !bCmd, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + ExportElement(XML_VARIABLE_GET, sPresentation); + break; + } + case FIELD_ID_VARIABLE_INPUT: + // variable input field: name, description, format&value + ProcessString(XML_NAME, + GetStringProperty(gsPropertyVariableName, rPropSet)); + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint , rPropSet)); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ProcessString(XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation); + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation, + GetDoubleProperty(gsPropertyValue, rPropSet), + true, true, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + ExportElement(XML_VARIABLE_INPUT, sPresentation); + break; + + case FIELD_ID_USER_GET: + // user field: name, hidden, style + { + bool bCmd = GetBoolProperty(gsPropertyIsShowFormula, rPropSet); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + bCmd); + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + "", u"", 0.0, // values not used + false, false, !bCmd, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + + // name from FieldMaster + ProcessString(XML_NAME, + GetStringProperty(gsPropertyName, + GetMasterPropertySet(rTextField))); + ExportElement(XML_USER_FIELD_GET, sPresentation); + break; + } + + case FIELD_ID_USER_INPUT: + // user input field: name (from FieldMaster), description +// ProcessString(XML_NAME, +// GetStringProperty(sPropertyName, +// GetMasterPropertySet(rTextField))); + ProcessString(XML_NAME, + GetStringProperty(gsPropertyContent, rPropSet)); + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint, rPropSet)); + ExportElement(XML_USER_FIELD_INPUT, sPresentation); + break; + + case FIELD_ID_SEQUENCE: + { + // sequence field: name, formula, seq-format + OUString sName = GetStringProperty(gsPropertyVariableName, rPropSet); + // TODO: use reference name only if actually being referenced. + ProcessString(XML_REF_NAME, + MakeSequenceRefName( + GetInt16Property(gsPropertySequenceValue, rPropSet), + sName)); + ProcessString(XML_NAME, sName); + ProcessString(XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation); + ProcessNumberingType(GetInt16Property(gsPropertyNumberingType, + rPropSet)); + ExportElement(XML_SEQUENCE, sPresentation); + break; + } + + case FIELD_ID_EXPRESSION: + { + // formula field: formula, format&value + bool bCmd = GetBoolProperty(gsPropertyIsShowFormula, rPropSet); + ProcessString(XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation); + ProcessDisplay(true, bCmd); + ProcessValueAndType(IsStringField(nToken, rPropSet), + GetIntProperty(gsPropertyNumberFormat, rPropSet), + GetStringProperty(gsPropertyContent, rPropSet), + sPresentation, + GetDoubleProperty(gsPropertyValue, rPropSet), + !bCmd, !bCmd, !bCmd, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + ExportElement(XML_EXPRESSION, sPresentation); + break; + } + + case FIELD_ID_TEXT_INPUT: + // text input field: description and string-value + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint, rPropSet)); + ProcessString(XML_HELP, + GetStringProperty(gsPropertyHelp, rPropSet), true); + ProcessString(XML_HINT, + GetStringProperty(gsPropertyTooltip, rPropSet), true); + ExportElement(XML_TEXT_INPUT, sPresentation); + break; + + case FIELD_ID_TIME: + // all properties (except IsDate) are optional! + if (xPropSetInfo->hasPropertyByName(gsPropertyNumberFormat)) + { + ProcessValueAndType(false, + GetIntProperty(gsPropertyNumberFormat,rPropSet), + "", u"", 0.0, // not used + false, false, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ), + true); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyDateTimeValue)) + { + // no value -> current time + ProcessTimeOrDateTime(XML_TIME_VALUE, + GetDateTimeProperty(gsPropertyDateTimeValue, + rPropSet)); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyDateTime)) + { + // no value -> current time + ProcessTimeOrDateTime(XML_TIME_VALUE, + GetDateTimeProperty(gsPropertyDateTime,rPropSet)); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), + false); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyAdjust)) + { + // adjust value given as integer in minutes + ProcessDateTime(XML_TIME_ADJUST, + GetIntProperty(gsPropertyAdjust, rPropSet), + false, true); + } + ExportElement(XML_TIME, sPresentation); + break; + + case FIELD_ID_DATE: + // all properties (except IsDate) are optional! + if (xPropSetInfo->hasPropertyByName(gsPropertyNumberFormat)) + { + ProcessValueAndType(false, + GetIntProperty(gsPropertyNumberFormat,rPropSet), + "", u"", 0.0, // not used + false, false, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyDateTimeValue)) + { + // no value -> current date + ProcessDateTime(XML_DATE_VALUE, + GetDateTimeProperty(gsPropertyDateTimeValue, + rPropSet)); + } + // TODO: remove double-handling after SRC614 + else if (xPropSetInfo->hasPropertyByName(gsPropertyDateTime)) + { + ProcessDateTime(XML_DATE_VALUE, + GetDateTimeProperty(gsPropertyDateTime,rPropSet)); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), + false); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyAdjust)) + { + // adjust value given as number of days + ProcessDateTime(XML_DATE_ADJUST, + GetIntProperty(gsPropertyAdjust, rPropSet), + true, true); + } + ExportElement(XML_DATE, sPresentation); + break; + + case FIELD_ID_PAGENUMBER: + // all properties are optional + if (xPropSetInfo->hasPropertyByName(gsPropertyNumberingType)) + { + ProcessNumberingType(GetInt16Property(gsPropertyNumberingType, + rPropSet)); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyOffset)) + { + sal_Int32 nAdjust = GetIntProperty(gsPropertyOffset, rPropSet); + + if (xPropSetInfo->hasPropertyByName(gsPropertySubType)) + { + // property SubType used in MapPageNumberName + ProcessString(XML_SELECT_PAGE, + MapPageNumberName(rPropSet, nAdjust)); + } + ProcessIntegerDef(XML_PAGE_ADJUST, nAdjust, 0); + } + ExportElement(XML_PAGE_NUMBER, sPresentation); + break; + + case FIELD_ID_PAGESTRING: + { + ProcessString(XML_STRING_VALUE, + GetStringProperty(gsPropertyUserText, rPropSet), + sPresentation); + sal_Int32 nDummy = 0; // MapPageNumberName need int + ProcessString(XML_SELECT_PAGE, MapPageNumberName(rPropSet, nDummy)); + ExportElement(XML_PAGE_CONTINUATION, sPresentation); + break; + } + + case FIELD_ID_DATABASE_NAME: + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, rPropSet)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, rPropSet)); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ExportDataBaseElement(XML_DATABASE_NAME, sPresentation, + rPropSet, xPropSetInfo); + break; + + case FIELD_ID_DATABASE_NUMBER: + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, rPropSet)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, rPropSet)); + ProcessNumberingType( + GetInt16Property(gsPropertyNumberingType,rPropSet)); + ProcessInteger(XML_VALUE, + GetIntProperty(gsPropertySetNumber, rPropSet)); + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ExportDataBaseElement(XML_DATABASE_ROW_NUMBER, sPresentation, + rPropSet, xPropSetInfo); + break; + + case FIELD_ID_DATABASE_NEXT: + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, rPropSet)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, rPropSet)); + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for database next field"); + ExportDataBaseElement(XML_DATABASE_NEXT, OUString(), + rPropSet, xPropSetInfo); + break; + + case FIELD_ID_DATABASE_SELECT: + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, rPropSet)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, rPropSet)); + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + ProcessInteger(XML_ROW_NUMBER, + GetIntProperty(gsPropertySetNumber, rPropSet)); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for database select field"); + ExportDataBaseElement(XML_DATABASE_ROW_SELECT, OUString(), + rPropSet, xPropSetInfo); + break; + + case FIELD_ID_DATABASE_DISPLAY: + { + // get database, table and column name from field master + const Reference & xMaster = GetMasterPropertySet(rTextField); + ProcessString(XML_TABLE_NAME, + GetStringProperty(gsPropertyDataTableName, xMaster)); + ProcessCommandType(GetIntProperty(gsPropertyDataCommandType, xMaster)); + ProcessString(XML_COLUMN_NAME, + GetStringProperty(gsPropertyDataColumnName, xMaster)); + // export number format if available (happens only for numbers!) + if (!GetBoolProperty(gsPropertyIsDataBaseFormat, rPropSet)) + { + ProcessValueAndType(false, // doesn't happen for text + GetIntProperty(gsPropertyNumberFormat,rPropSet), + "", u"", 0.0, // not used + false, false, true, false); + } + ProcessDisplay(GetBoolProperty(gsPropertyIsVisible, rPropSet), + false); + ExportDataBaseElement(XML_DATABASE_DISPLAY, sPresentation, + xMaster, xMaster->getPropertySetInfo()); + break; + } + + case FIELD_ID_DOCINFO_REVISION: + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), false); + ExportElement(MapDocInfoFieldName(nToken), sPresentation); + break; + + case FIELD_ID_DOCINFO_EDIT_DURATION: + case FIELD_ID_DOCINFO_SAVE_TIME: + case FIELD_ID_DOCINFO_CREATION_TIME: + case FIELD_ID_DOCINFO_PRINT_TIME: + case FIELD_ID_DOCINFO_SAVE_DATE: + case FIELD_ID_DOCINFO_CREATION_DATE: + case FIELD_ID_DOCINFO_PRINT_DATE: + ProcessValueAndType(false, + GetIntProperty(gsPropertyNumberFormat, rPropSet), + "", u"", 0.0, + false, false, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false ) ); + + // todo: export date/time value, but values not available -> core bug + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), false); + ExportElement(MapDocInfoFieldName(nToken), sPresentation); + break; + + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + case FIELD_ID_DOCINFO_DESCRIPTION: + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + case FIELD_ID_DOCINFO_TITLE: + case FIELD_ID_DOCINFO_SUBJECT: + case FIELD_ID_DOCINFO_KEYWORDS: + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), false); + } + ExportElement(MapDocInfoFieldName(nToken), sPresentation); + break; + + case FIELD_ID_DOCINFO_CUSTOM: + { + ProcessValueAndType(false, // doesn't happen for text + GetIntProperty(gsPropertyNumberFormat,rPropSet), + "", u"", 0.0, // not used + false, false, true, + ! GetOptionalBoolProperty( + gsPropertyIsFixedLanguage, + rPropSet, xPropSetInfo, false )); + uno::Any aAny = rPropSet->getPropertyValue( gsPropertyName ); + OUString sName; + aAny >>= sName; + ProcessString(XML_NAME, sName); + ProcessBoolean(XML_FIXED, GetBoolProperty(gsPropertyIsFixed, rPropSet), false); + ExportElement(XML_USER_DEFINED, sPresentation); + break; + } + + case FIELD_ID_COUNT_PAGES: + case FIELD_ID_COUNT_PARAGRAPHS: + case FIELD_ID_COUNT_WORDS: + case FIELD_ID_COUNT_CHARACTERS: + case FIELD_ID_COUNT_TABLES: + case FIELD_ID_COUNT_GRAPHICS: + case FIELD_ID_COUNT_OBJECTS: + // all properties optional (applies to pages only, but I'll do + // it for all for sake of common implementation) + if (xPropSetInfo->hasPropertyByName(gsPropertyNumberingType)) + { + ProcessNumberingType(GetInt16Property(gsPropertyNumberingType, + rPropSet)); + } + ExportElement(MapCountFieldName(nToken), sPresentation); + break; + + case FIELD_ID_CONDITIONAL_TEXT: + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + ProcessString(XML_STRING_VALUE_IF_TRUE, + GetStringProperty(gsPropertyTrueContent, rPropSet)); + ProcessString(XML_STRING_VALUE_IF_FALSE, + GetStringProperty(gsPropertyFalseContent, rPropSet)); + ProcessBoolean(XML_CURRENT_VALUE, + GetBoolProperty(gsPropertyIsConditionTrue, rPropSet), + false); + ExportElement(XML_CONDITIONAL_TEXT, sPresentation); + break; + + case FIELD_ID_HIDDEN_TEXT: + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + ProcessString(XML_STRING_VALUE, + GetStringProperty(gsPropertyContent, rPropSet)); + ProcessBoolean(XML_IS_HIDDEN, + GetBoolProperty(gsPropertyIsHidden, rPropSet), + false); + ExportElement(XML_HIDDEN_TEXT, sPresentation); + break; + + case FIELD_ID_HIDDEN_PARAGRAPH: + ProcessString(XML_CONDITION, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyCondition, rPropSet)); + ProcessBoolean(XML_IS_HIDDEN, + GetBoolProperty(gsPropertyIsHidden, rPropSet), + false); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for hidden paragraph field"); + ExportElement(XML_HIDDEN_PARAGRAPH); + break; + + case FIELD_ID_TEMPLATE_NAME: + ProcessString(XML_DISPLAY, + MapTemplateDisplayFormat( + GetInt16Property(gsPropertyFileFormat, rPropSet))); + ExportElement(XML_TEMPLATE_NAME, sPresentation); + break; + + case FIELD_ID_CHAPTER: + ProcessString(XML_DISPLAY, + MapChapterDisplayFormat( + GetInt16Property(gsPropertyChapterFormat, rPropSet))); + // API numbers 0..9, we number 1..10 + ProcessInteger(XML_OUTLINE_LEVEL, + GetInt8Property(gsPropertyLevel, rPropSet) + 1); + ExportElement(XML_CHAPTER, sPresentation); + break; + + case FIELD_ID_FILE_NAME: + // all properties are optional + if (xPropSetInfo->hasPropertyByName(gsPropertyFileFormat)) + { + ProcessString(XML_DISPLAY, + MapFilenameDisplayFormat( + GetInt16Property(gsPropertyFileFormat, rPropSet))); + } + if (xPropSetInfo->hasPropertyByName(gsPropertyIsFixed)) + { + ProcessBoolean(XML_FIXED, + GetBoolProperty(gsPropertyIsFixed, rPropSet), + false); + } + ExportElement(XML_FILE_NAME, sPresentation); + break; + + case FIELD_ID_REFPAGE_SET: + ProcessBoolean(XML_ACTIVE, + GetBoolProperty(gsPropertyOn, rPropSet), true); + ProcessIntegerDef(XML_PAGE_ADJUST, + GetInt16Property(gsPropertyOffset, rPropSet), 0); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation page variable field"); + ExportElement(XML_PAGE_VARIABLE_SET); + break; + + case FIELD_ID_REFPAGE_GET: + ProcessNumberingType( + GetInt16Property(gsPropertyNumberingType, rPropSet)); + ExportElement(XML_PAGE_VARIABLE_GET, sPresentation); + break; + + case FIELD_ID_MACRO: + ExportMacro( rPropSet, sPresentation ); + break; + + case FIELD_ID_REF_SEQUENCE: + // reference to sequence: format, name, find value (and element) + // was: if (nSeqNumber != -1) ... + ProcessString(XML_REFERENCE_FORMAT, + MapReferenceType(GetInt16Property( + gsPropertyReferenceFieldPart, rPropSet)), + XML_TEMPLATE); + ProcessString(XML_REF_NAME, + MakeSequenceRefName( + GetInt16Property(gsPropertySequenceNumber, rPropSet), + GetStringProperty(gsPropertySourceName, rPropSet) ) ); + if (xPropSetInfo->hasPropertyByName(gsPropertyReferenceFieldLanguage) && + GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + // export text:reference-language attribute, if not empty + ProcessString(XML_REFERENCE_LANGUAGE, + GetStringProperty(gsPropertyReferenceFieldLanguage, rPropSet), true, XML_NAMESPACE_LO_EXT); + } + ExportElement( + MapReferenceSource( + GetInt16Property(gsPropertyReferenceFieldSource, rPropSet)), + sPresentation); + break; + + case FIELD_ID_REF_REFERENCE: + case FIELD_ID_REF_BOOKMARK: + // reference to bookmarks, references: format, name (and element) + ProcessString(XML_REFERENCE_FORMAT, + MapReferenceType(GetInt16Property( + gsPropertyReferenceFieldPart, rPropSet)), + XML_TEMPLATE); + ProcessString(XML_REF_NAME, + GetStringProperty(gsPropertySourceName, rPropSet)); + if (xPropSetInfo->hasPropertyByName(gsPropertyReferenceFieldLanguage) && + GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + // export text:reference-language attribute, if not empty + ProcessString(XML_REFERENCE_LANGUAGE, + GetStringProperty(gsPropertyReferenceFieldLanguage, rPropSet), true, XML_NAMESPACE_LO_EXT); + } + ExportElement( + MapReferenceSource(GetInt16Property( + gsPropertyReferenceFieldSource, rPropSet)), + sPresentation); + break; + + case FIELD_ID_REF_FOOTNOTE: + case FIELD_ID_REF_ENDNOTE: + // reference to end-/footnote: format, generate name, (and element) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + FIELD_ID_REF_ENDNOTE==nToken ? XML_ENDNOTE : XML_FOOTNOTE ); + ProcessString(XML_REFERENCE_FORMAT, + MapReferenceType(GetInt16Property( + gsPropertyReferenceFieldPart, rPropSet)), + XML_TEMPLATE); + ProcessString(XML_REF_NAME, + MakeFootnoteRefName(GetInt16Property( + gsPropertySequenceNumber, rPropSet))); + if (xPropSetInfo->hasPropertyByName(gsPropertyReferenceFieldLanguage) && + GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + // export text:reference-language attribute, if not empty + ProcessString(XML_REFERENCE_LANGUAGE, + GetStringProperty(gsPropertyReferenceFieldLanguage, rPropSet), true, XML_NAMESPACE_LO_EXT); + } + ExportElement( + MapReferenceSource(GetInt16Property( + gsPropertyReferenceFieldSource, rPropSet)), + sPresentation); + break; + + case FIELD_ID_DDE: + // name from field master + ProcessString(XML_CONNECTION_NAME, + + GetStringProperty(gsPropertyName, + GetMasterPropertySet(rTextField))); + ExportElement(XML_DDE_CONNECTION, sPresentation); + break; + + case FIELD_ID_SHEET_NAME: + // name of spreadsheet (Calc only) + ExportElement(XML_SHEET_NAME, sPresentation); + break; + + case FIELD_ID_PAGENAME: + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_LO_EXT, XML_PAGE_NAME, false, false ); + GetExport().Characters( sPresentation ); + } + break; + } + + case FIELD_ID_URL: + { + // this field is a special case because it gets mapped onto a + // hyperlink, rather than one of the regular text field. + ProcessString(XML_HREF, GetExport().GetRelativeReference(GetStringProperty(gsPropertyURL, rPropSet)), + false, XML_NAMESPACE_XLINK); + ProcessString(XML_TARGET_FRAME_NAME, + GetStringProperty(gsPropertyTargetFrame,rPropSet), + true, XML_NAMESPACE_OFFICE); + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE ); + SvXMLElementExport aUrlField(rExport, XML_NAMESPACE_TEXT, XML_A, + false, false); + GetExport().Characters(sPresentation); + break; + } + + case FIELD_ID_BIBLIOGRAPHY: + { + ProcessBibliographyData(rPropSet); + ExportElement(XML_BIBLIOGRAPHY_MARK, sPresentation); + break; + } + + case FIELD_ID_SCRIPT: + ProcessString(XML_LANGUAGE, + GetStringProperty(gsPropertyScriptType, rPropSet), + true, XML_NAMESPACE_SCRIPT); + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for script field"); + if (GetBoolProperty(gsPropertyURLContent, rPropSet)) + { + ProcessString(XML_HREF, + GetExport().GetRelativeReference(GetStringProperty(gsPropertyContent, rPropSet)), + false, XML_NAMESPACE_XLINK); + ExportElement(XML_SCRIPT); + } + else + { + ExportElement(XML_SCRIPT, + GetStringProperty(gsPropertyContent, rPropSet)); + } + break; + + case FIELD_ID_ANNOTATION: + { + // check for empty presentation (just in case) + DBG_ASSERT(sPresentation.isEmpty(), + "Unexpected presentation for annotation field"); + + bool bRemovePersonalInfo = SvtSecurityOptions::IsOptionSet( + SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ); + + // annotation element + content + OUString aName; + rPropSet->getPropertyValue(gsPropertyName) >>= aName; + if (!aName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, aName); + } + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) + { + bool b = GetBoolProperty("Resolved", rPropSet); + OUString aResolvedText; + OUStringBuffer aResolvedTextBuffer; + ::sax::Converter::convertBool(aResolvedTextBuffer, b); + aResolvedText = aResolvedTextBuffer.makeStringAndClear(); + + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_RESOLVED, aResolvedText); + } + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_OFFICE, + XML_ANNOTATION, false, true); + + // author + OUString aAuthor( GetStringProperty(gsPropertyAuthor, rPropSet) ); + if( !aAuthor.isEmpty() ) + { + SvXMLElementExport aCreatorElem( GetExport(), XML_NAMESPACE_DC, + XML_CREATOR, true, + false ); + GetExport().Characters( bRemovePersonalInfo + ? "Author" + OUString::number( rExport.GetInfoID(aAuthor) ) + : aAuthor ); + } + + // date time + util::DateTime aDate( GetDateTimeProperty(gsPropertyDateTimeValue, rPropSet) ); + if ( !bRemovePersonalInfo ) + { + OUStringBuffer aBuffer; + ::sax::Converter::convertDateTime(aBuffer, aDate, nullptr, true); + SvXMLElementExport aDateElem( GetExport(), XML_NAMESPACE_DC, + XML_DATE, true, + false ); + GetExport().Characters(aBuffer.makeStringAndClear()); + } + + if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + // initials + OUString aInitials( GetStringProperty(gsPropertyInitials, rPropSet) ); + if( !aInitials.isEmpty() ) + { + // ODF 1.3 OFFICE-3776 export meta:creator-initials for ODF 1.3 + SvXMLElementExport aCreatorElem( GetExport(), + (SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()) + ? XML_NAMESPACE_META + : XML_NAMESPACE_LO_EXT, + + (SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()) + ? XML_CREATOR_INITIALS + : XML_SENDER_INITIALS, + true, false ); + GetExport().Characters( bRemovePersonalInfo + ? OUString::number( rExport.GetInfoID(aInitials) ) + : aInitials); + } + } + + css::uno::Reference < css::text::XText > xText; + try + { + css::uno::Any aRet = rPropSet->getPropertyValue(gsPropertyTextRange); + aRet >>= xText; + } + catch ( css::uno::Exception& ) + {} + + if ( xText.is() ) + GetExport().GetTextParagraphExport()->exportText( xText ); + else + ProcessParagraphSequence(GetStringProperty(gsPropertyContent,rPropSet)); + break; + } + + case FIELD_ID_COMBINED_CHARACTERS: + { + // The style with the combined characters attribute has + // already been handled in the ExportField method. So all that + // is left to do now is to export the characters. + GetExport().Characters(sPresentation); + break; + } + + case FIELD_ID_META: + { + ExportMetaField(rPropSet, false, bProgress, rPrevCharIsSpace); + break; + } + + case FIELD_ID_MEASURE: + { + ProcessString(XML_KIND, MapMeasureKind(GetInt16Property(gsPropertyMeasureKind, rPropSet))); + ExportElement( XML_MEASURE, sPresentation ); + break; + } + + case FIELD_ID_TABLE_FORMULA: + ProcessString( XML_FORMULA, XML_NAMESPACE_OOOW, + GetStringProperty(gsPropertyContent, rPropSet) ); + ProcessDisplay( true, + GetBoolProperty(gsPropertyIsShowFormula, rPropSet) ); + ProcessValueAndType( false, + GetIntProperty(gsPropertyNumberFormat, rPropSet), + "", u"", 0.0f, + false, false, true, + false ); + ExportElement( XML_TABLE_FORMULA, sPresentation ); + break; + + case FIELD_ID_DROP_DOWN: + { + // tdf#133555 don't export in strict ODF versions that don't have it + if (GetExport().getSaneDefaultVersion() <= SvtSaveOptions::ODFSVER_012) + { + break; + } + ProcessString(XML_NAME, GetStringProperty(gsPropertyName, rPropSet)); + ProcessString(XML_HELP, + GetStringProperty(gsPropertyHelp, rPropSet), true); + ProcessString(XML_HINT, + GetStringProperty(gsPropertyTooltip, rPropSet), true); + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, XML_DROP_DOWN, + false, false ); + ProcessStringSequence + (GetStringSequenceProperty( gsPropertyItems, rPropSet ), + GetStringProperty( gsPropertySelectedItem, rPropSet ) ); + + GetExport().Characters( sPresentation ); + } + break; + + case FIELD_ID_DRAW_HEADER: + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_PRESENTATION, XML_HEADER, false, false ); + } + break; + + case FIELD_ID_DRAW_FOOTER: + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_PRESENTATION, XML_FOOTER, false, false ); + } + break; + + case FIELD_ID_DRAW_DATE_TIME: + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_PRESENTATION, XML_DATE_TIME, false, false ); + } + break; + + + case FIELD_ID_UNKNOWN: + default: + OSL_FAIL("unknown field type encountered!"); + // always export content + GetExport().Characters(sPresentation); + } +} + + +/// export field declarations / field masters +void XMLTextFieldExport::ExportFieldDeclarations() +{ + Reference xEmptyText; + ExportFieldDeclarations(xEmptyText); +} + +/// export field declarations / field masters +void XMLTextFieldExport::ExportFieldDeclarations( + const Reference & rText ) +{ + // store lists for decl elements + vector aVarName; + vector aUserName; + vector aSeqName; + vector aDdeName; + + // get text fields supplier and field master name access + Reference xTextFieldsSupp(GetExport().GetModel(), + UNO_QUERY); + if( !xTextFieldsSupp.is() ) + return; + + Reference xFieldMasterNameAccess = + xTextFieldsSupp->getTextFieldMasters(); + + // where to get the text field masters from? + // a) we get a specific XText: then use pUsedMasters + // b) the XText is empty: then export all text fields + Sequence aFieldMasters; + if (rText.is()) + { + // export only used masters + DBG_ASSERT(nullptr != pUsedMasters, + "field masters must be recorded in order to be " + "written out separately" ); + if (nullptr != pUsedMasters) + { + map, set > ::iterator aMapIter = + pUsedMasters->find(rText); + if (aMapIter != pUsedMasters->end()) + { + // found the set of used field masters + aFieldMasters = comphelper::containerToSequence(aMapIter->second); + pUsedMasters->erase(rText); + } + // else: XText not found -> ignore + } + // else: no field masters have been recorded -> ignore + } + else + { + // no XText: export all! + aFieldMasters = xFieldMasterNameAccess->getElementNames(); + } + + for(const OUString& sFieldMaster : std::as_const(aFieldMasters)) { + + // workaround for #no-bug# + if ( sFieldMaster.startsWithIgnoreAsciiCase( + "com.sun.star.text.FieldMaster.DataBase.") ) + { + continue; + } + + + OUString sFieldMasterType; + OUString sVarName; + ExplodeFieldMasterName(sFieldMaster, sFieldMasterType, sVarName); + + // get XPropertySet of this field master + Reference xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sFieldMaster); + aAny >>= xPropSet; + + // save interesting field masters + if (sFieldMasterType == FIELD_SERVICE_SETEXP) + { + sal_Int32 nType = GetIntProperty(gsPropertySubType, xPropSet); + + // sequence or variable? + if ( SetVariableType::SEQUENCE == nType ) + { + aSeqName.push_back( sFieldMaster ); + } + else + { + aVarName.push_back( sFieldMaster ); + } + } + else if (sFieldMasterType == FIELD_SERVICE_USER) + { + aUserName.push_back( sFieldMaster ); + } + else if (sFieldMasterType == FIELD_SERVICE_DDE) + { + aDdeName.push_back( sFieldMaster ); + } + else + { + ; // ignore + } + } + + // now process fields: + + // variable field masters: + if ( !aVarName.empty() ) + { + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, + XML_VARIABLE_DECLS, + true, true ); + + for (const auto& sName : aVarName) + { + // get field master property set + Reference xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sName); + aAny >>= xPropSet; + + // field name and type + OUString sFieldMasterType; + OUString sVarName; + ExplodeFieldMasterName(sName, sFieldMasterType, sVarName); + + // determine string/numeric field + bool bIsString = ( GetIntProperty(gsPropertySubType, xPropSet) + == SetVariableType::STRING ); + + // get dependent field property set + Reference xFieldPropSet; + if (GetDependentFieldPropertySet(xPropSet, xFieldPropSet)) + { + // process value and type. + ProcessValueAndType( + bIsString, + GetIntProperty(gsPropertyNumberFormat, xFieldPropSet), + "", u"", 0.0, + false, true, false, false); + } + else + { + // If no dependent field is found, only string and + // float types can be supported + + // number format: 0 is default number format for 1st + // language. should be: getDefaultNumberFormat(Locale) + // from NumberFormats + ProcessValueAndType( + bIsString, + 0, "", u"", 0.0, + false, true, false, false); + } + + ProcessString(XML_NAME, sVarName); + ExportElement(XML_VARIABLE_DECL, true); + } + } + // else: no declarations element + + // sequence field masters: + if ( !aSeqName.empty() ) + { + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, + XML_SEQUENCE_DECLS, + true, true ); + + for (const auto& sName : aSeqName) + { + // get field master property set + Reference xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sName); + aAny >>= xPropSet; + + // field name and type + OUString sFieldMasterType; + OUString sVarName; + ExplodeFieldMasterName(sName, sFieldMasterType, sVarName); + + // outline level + sal_Int32 nLevel = 1 + GetIntProperty( + gsPropertyChapterNumberingLevel, xPropSet); + DBG_ASSERT(nLevel >= 0, "illegal outline level"); + DBG_ASSERT(nLevel < 127, "possible illegal outline level"); + ProcessInteger(XML_DISPLAY_OUTLINE_LEVEL, nLevel); + + // separation character + if (nLevel > 0) { + ProcessString(XML_SEPARATION_CHARACTER, GetStringProperty( + gsPropertyNumberingSeparator, xPropSet)); + } + ProcessString(XML_NAME, sVarName); + ExportElement(XML_SEQUENCE_DECL, true); + } + } + // else: no declarations element + + // user field masters: + if ( !aUserName.empty() ) + { + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, + XML_USER_FIELD_DECLS, + true, true ); + + for (const auto& sName : aUserName) + { + // get field master property set + Reference xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sName); + aAny >>= xPropSet; + + // field name and type + OUString sFieldMasterType; + OUString sVarName; + ExplodeFieldMasterName(sName, sFieldMasterType, sVarName); + + if (GetBoolProperty(gsPropertyIsExpression, xPropSet)) + { + // expression: + ProcessValueAndType( + false, + 0, "", u"", + GetDoubleProperty(gsPropertyValue, xPropSet), + true, + true, + false, + false); + } + else + { + // string: write regardless of default + ProcessString(XML_VALUE_TYPE, XML_STRING, + XML_NAMESPACE_OFFICE); + ProcessString(XML_STRING_VALUE, + GetStringProperty(gsPropertyContent, xPropSet), + false, XML_NAMESPACE_OFFICE ); + } + ProcessString(XML_NAME, sVarName); + ExportElement(XML_USER_FIELD_DECL, true); + } + } + // else: no declarations element + + // DDE field masters: + if ( aDdeName.empty() ) + return; + + SvXMLElementExport aElem( GetExport(), + XML_NAMESPACE_TEXT, + XML_DDE_CONNECTION_DECLS, + true, true ); + + for (const auto& sName : aDdeName) + { + // get field master property set + Reference xPropSet; + Any aAny = xFieldMasterNameAccess->getByName(sName); + aAny >>= xPropSet; + + // check if this connection is being used by a field + Reference xDummy; + if (GetDependentFieldPropertySet(xPropSet, xDummy)) + { + + ProcessString(XML_NAME, + GetStringProperty(gsPropertyName, xPropSet), + false, XML_NAMESPACE_OFFICE); + + // export elements; can't use ProcessString because + // elements are in office namespace + ProcessString(XML_DDE_APPLICATION, + GetStringProperty(gsPropertyDDECommandType, + xPropSet), + false, XML_NAMESPACE_OFFICE); + ProcessString(XML_DDE_TOPIC, + GetStringProperty(gsPropertyDDECommandFile, + xPropSet), + false, XML_NAMESPACE_OFFICE); + ProcessString(XML_DDE_ITEM, + GetStringProperty(gsPropertyDDECommandElement, + xPropSet), + false, XML_NAMESPACE_OFFICE); + bool bIsAutomaticUpdate = GetBoolProperty( + gsPropertyIsAutomaticUpdate, xPropSet); + if (bIsAutomaticUpdate) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, + XML_AUTOMATIC_UPDATE, + XML_TRUE); + } + + ExportElement(XML_DDE_CONNECTION_DECL, true); + } + // else: no dependent field -> no export of field declaration + } + // else: no declarations element +} + +void XMLTextFieldExport::SetExportOnlyUsedFieldDeclarations( + bool bExportOnlyUsed) +{ + pUsedMasters.reset(); + + // create used masters set (if none is used) + if (bExportOnlyUsed) + pUsedMasters.reset( new map, set > ); +} + +void XMLTextFieldExport::ExportElement(enum XMLTokenEnum eElementName, + bool bAddSpace) +{ + // can't call ExportElement(eElementName, const OUString&) with empty + // string because xmlprinter only uses empty tags if no content + // (not even empty content) was written. + + DBG_ASSERT(XML_TOKEN_INVALID != eElementName, "invalid element name!"); + if (XML_TOKEN_INVALID != eElementName) + { + // Element + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + eElementName, bAddSpace, bAddSpace ); + } // else: ignore +} + +void XMLTextFieldExport::ExportElement(enum XMLTokenEnum eElementName, + const OUString& sContent) +{ + DBG_ASSERT(eElementName != XML_TOKEN_INVALID, "invalid element name!"); + if (eElementName != XML_TOKEN_INVALID) + { + // Element + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + eElementName, false, false ); + // export content + GetExport().Characters(sContent); + } else { + // always export content + GetExport().Characters(sContent); + } +} + +void XMLTextFieldExport::ExportMacro( + const Reference & rPropSet, + const OUString& rContent ) +{ + // some strings we'll need + OUString sEventType( "EventType" ); + + + // the description attribute + ProcessString(XML_DESCRIPTION, + GetStringProperty(gsPropertyHint, rPropSet), + rContent); + + // the element + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_EXECUTE_MACRO, false, false ); + + // the -macro: + + // 1) build sequence of PropertyValues + Sequence aSeq; + OUString sName; + rPropSet->getPropertyValue("ScriptURL") >>= sName; + + // if the ScriptURL property is not empty then this is a Scripting + // Framework URL, otherwise treat it as a Basic Macro + if (!sName.isEmpty()) + { + OUString sScript( "Script" ); + aSeq = Sequence + { + comphelper::makePropertyValue(sEventType, sScript), + comphelper::makePropertyValue(sScript, sName) + }; + } + else + { + aSeq = Sequence + { + comphelper::makePropertyValue(sEventType, OUString("StarBasic")), + comphelper::makePropertyValue("Library", rPropSet->getPropertyValue( "MacroLibrary" )), + comphelper::makePropertyValue("MacroName", rPropSet->getPropertyValue( "MacroName" )) + }; + } + + // 2) export the sequence + GetExport().GetEventExport().ExportSingleEvent( aSeq, "OnClick", false ); + + // and finally, the field presentation + GetExport().Characters(rContent); +} + +void XMLTextFieldExport::ExportMetaField( + const Reference & i_xMeta, + bool i_bAutoStyles, bool i_bProgress, + bool & rPrevCharIsSpace) +{ + bool doExport(!i_bAutoStyles); // do not export element if autostyles + // check version >= 1.2 + switch (GetExport().getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: doExport = false; break; + default: break; + } + + const Reference < XEnumerationAccess > xEA( i_xMeta, UNO_QUERY_THROW ); + const Reference < XEnumeration > xTextEnum( xEA->createEnumeration() ); + + if (doExport) + { + const Reference xMeta( i_xMeta, UNO_QUERY_THROW ); + + // style:data-style-name + ProcessValueAndType(false, + GetIntProperty(gsPropertyNumberFormat, i_xMeta), + "", u"", 0.0, false, false, true, + false ); + + // text:meta-field without xml:id is invalid + xMeta->ensureMetadataReference(); + + // xml:id for RDF metadata + GetExport().AddAttributeXmlId(xMeta); + } + + SvXMLElementExport aElem( GetExport(), doExport, + XML_NAMESPACE_TEXT, XML_META_FIELD, false, false ); + + // recurse to export content + GetExport().GetTextParagraphExport()-> + exportTextRangeEnumeration(xTextEnum, i_bAutoStyles, i_bProgress, rPrevCharIsSpace); +} + +/// export all data-style related attributes +void XMLTextFieldExport::ProcessValueAndType( + bool bIsString, /// do we process a string or a number? + sal_Int32 nFormatKey, /// format key for NumberFormatter; inv. if string + const OUString& sContent, /// string content; possibly invalid + std::u16string_view sDefault, /// default string + double fValue, /// float content; possibly invalid + bool bExportValue, /// export value attribute? + bool bExportValueType, /// export value-type attribute? + bool bExportStyle, /// export style-attribute? + bool bForceSystemLanguage, /// export language attributes? + bool bTimeStyle) // exporting a time style? +{ + // String or number? + if (bIsString) + { + + // string: attributes value-type=string, string-value=... + + if (bExportValue || bExportValueType) + { + XMLNumberFormatAttributesExportHelper::SetNumberFormatAttributes( + GetExport(), sContent, sDefault, bExportValue); + } + + } + else + { + + // number: value-type=..., value...=..., data-style-name=... + + DBG_ASSERT(bExportValueType || !bExportValue, "value w/o value type not supported!"); + + // take care of illegal formats + // (shouldn't happen, but does if document is corrupted) + if (-1 != nFormatKey) + { + if (bExportValue || bExportValueType) + { + XMLNumberFormatAttributesExportHelper:: + SetNumberFormatAttributes( + GetExport(), nFormatKey, fValue, bExportValue); + } + + if (bExportStyle) + { + // don't export language (if desired) + if( bForceSystemLanguage ) + nFormatKey = + GetExport().dataStyleForceSystemLanguage( nFormatKey ); + + OUString sDataStyleName = + GetExport().getDataStyleName(nFormatKey, bTimeStyle); + if( !sDataStyleName.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_DATA_STYLE_NAME, + sDataStyleName ); + } // else: ignore (no valid number format) + } // else: ignore (no number format) + } + } +} + + +/// process display related properties +void XMLTextFieldExport::ProcessDisplay(bool bIsVisible, + bool bIsCommand) +{ + enum XMLTokenEnum eValue; + + if (bIsVisible) + { + eValue = bIsCommand ? XML_FORMULA : XML_VALUE; + } + else + { + eValue = XML_NONE; + } + + // omit attribute if default + if (eValue != XML_VALUE) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_DISPLAY, eValue); + } +} + + +/// export boolean property +void XMLTextFieldExport::ProcessBoolean(enum XMLTokenEnum eName, + bool bBool, bool bDefault) +{ + SAL_WARN_IF( eName == XML_TOKEN_INVALID, "xmloff.text", "invalid element token"); + if ( XML_TOKEN_INVALID == eName ) + return; + + // write attribute (if different than default) + // negate to force 0/1 values (and make sal_Bool comparable) + if ((!bBool) != (!bDefault)) { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, eName, + (bBool ? XML_TRUE : XML_FALSE) ); + } +} + + +/// export string attribute +void XMLTextFieldExport::ProcessString(enum XMLTokenEnum eName, + const OUString& sValue, + bool bOmitEmpty, + sal_uInt16 nPrefix) +{ + SAL_WARN_IF( eName == XML_TOKEN_INVALID, "xmloff.text", "invalid element token"); + if ( XML_TOKEN_INVALID == eName ) + return; + + // check for empty string, if applicable + if ( bOmitEmpty && sValue.isEmpty() ) + return; + + // write attribute + GetExport().AddAttribute(nPrefix, eName, sValue); +} + +void XMLTextFieldExport::ProcessString(enum XMLTokenEnum eName, + sal_uInt16 nValuePrefix, + const OUString& sValue) +{ + OUString sQValue = + GetExport().GetNamespaceMap().GetQNameByKey( nValuePrefix, sValue, false ); + ProcessString( eName, sQValue ); +} + +/// export a string attribute +void XMLTextFieldExport::ProcessString(enum XMLTokenEnum eName, + const OUString& sValue, + std::u16string_view sDefault) +{ + if (sValue != sDefault) + { + ProcessString(eName, sValue); + } +} + +/// export a string attribute +void XMLTextFieldExport::ProcessString(enum XMLTokenEnum eName, + sal_uInt16 nValuePrefix, + const OUString& sValue, + std::u16string_view sDefault) +{ + if (sValue != sDefault) + { + ProcessString(eName, nValuePrefix, sValue); + } +} + + +/// export string attribute +void XMLTextFieldExport::ProcessString( + enum XMLTokenEnum eName, + enum XMLTokenEnum eValue, + sal_uInt16 nPrefix) +{ + SAL_WARN_IF( eName == XML_TOKEN_INVALID, "xmloff.text", "invalid element token" ); + SAL_WARN_IF( eValue == XML_TOKEN_INVALID, "xmloff.text", "invalid value token" ); + if ( XML_TOKEN_INVALID == eName ) + return; + + GetExport().AddAttribute(nPrefix, eName, eValue); +} + +/// export a string attribute +void XMLTextFieldExport::ProcessString( + enum XMLTokenEnum eName, + enum XMLTokenEnum eValue, + enum XMLTokenEnum eDefault) +{ + if ( eValue != eDefault ) + ProcessString( eName, eValue); +} + + +/// export a string as a sequence of paragraphs +void XMLTextFieldExport::ProcessParagraphSequence( + std::u16string_view sParagraphSequence) +{ + // iterate over all string-pieces separated by return (0x0a) and + // put each inside a paragraph element. + SvXMLTokenEnumerator aEnumerator(sParagraphSequence, char(0x0a)); + std::u16string_view aSubString; + while (aEnumerator.getNextToken(aSubString)) + { + SvXMLElementExport aParagraph( + GetExport(), XML_NAMESPACE_TEXT, XML_P, true, false); + GetExport().Characters(OUString(aSubString)); + } +} + +// export an integer attribute +void XMLTextFieldExport::ProcessInteger(enum XMLTokenEnum eName, + sal_Int32 nNum) +{ + SAL_WARN_IF( eName == XML_TOKEN_INVALID, "xmloff.text", "invalid element token"); + if ( XML_TOKEN_INVALID == eName ) + return; + + GetExport().AddAttribute(XML_NAMESPACE_TEXT, eName, + OUString::number(nNum)); +} + +/// export an integer attribute, omit if default +void XMLTextFieldExport::ProcessIntegerDef(enum XMLTokenEnum eName, + sal_Int32 nNum, sal_Int32 nDefault) +{ + if (nNum != nDefault) + ProcessInteger(eName, nNum); +} + + +/// export a numbering type +void XMLTextFieldExport::ProcessNumberingType(sal_Int16 nNumberingType) +{ + // process only if real format (not: like page descriptor) + if (NumberingType::PAGE_DESCRIPTOR == nNumberingType) + return; + + OUStringBuffer sTmp( 10 ); + // number type: num format + GetExport().GetMM100UnitConverter().convertNumFormat( sTmp, + nNumberingType ); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sTmp.makeStringAndClear() ); + // and letter sync, if applicable + SvXMLUnitConverter::convertNumLetterSync( sTmp, nNumberingType ); + + if (!sTmp.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_LETTER_SYNC, + sTmp.makeStringAndClear() ); + } + // else: like page descriptor => ignore +} + + +/// export a date, time, or duration +void XMLTextFieldExport::ProcessDateTime(enum XMLTokenEnum eName, + double dValue, + bool bIsDate, + bool bIsDuration, + bool bOmitDurationIfZero, + sal_uInt16 nPrefix) +{ + // truncate for date granularity + if (bIsDate) + { + dValue = ::rtl::math::approxFloor(dValue); + } + + OUStringBuffer aBuffer; + if (bIsDuration) + { + // date/time duration handle bOmitDurationIfZero + if (!bOmitDurationIfZero || dValue != 0.0) + { + ::sax::Converter::convertDuration(aBuffer, dValue); + } + } + else + { + // date/time value + rExport.GetMM100UnitConverter().convertDateTime(aBuffer, dValue); + } + + // output attribute + ProcessString(eName, aBuffer.makeStringAndClear(), true, nPrefix); +} + +/// export a date or time +void XMLTextFieldExport::ProcessDateTime(enum XMLTokenEnum eName, + const util::DateTime& rTime) +{ + OUStringBuffer aBuffer; + + util::DateTime aDateTime(rTime); + + // date/time value + ::sax::Converter::convertDateTime(aBuffer, aDateTime, nullptr); + + // output attribute + ProcessString(eName, aBuffer.makeStringAndClear(), true); +} + +/// export a date, time, or duration +void XMLTextFieldExport::ProcessDateTime(enum XMLTokenEnum eName, + sal_Int32 nMinutes, + bool bIsDate, + bool bIsDuration) +{ + // handle bOmitDurationIfZero here, because we can precisely compare ints + if (!(bIsDuration && (nMinutes==0))) + { + ProcessDateTime(eName, static_cast(nMinutes) / double(24*60), + bIsDate, bIsDuration); + } +} + +/// export a time or dateTime +void XMLTextFieldExport::ProcessTimeOrDateTime(enum XMLTokenEnum eName, + const util::DateTime& rTime) +{ + OUStringBuffer aBuffer; + + // date/time value + ::sax::Converter::convertTimeOrDateTime(aBuffer, rTime); + + // output attribute + ProcessString(eName, aBuffer.makeStringAndClear(), true); +} + + +SvXMLEnumMapEntry const aBibliographyDataTypeMap[] = +{ + { XML_ARTICLE, BibliographyDataType::ARTICLE }, + { XML_BOOK, BibliographyDataType::BOOK }, + { XML_BOOKLET, BibliographyDataType::BOOKLET }, + { XML_CONFERENCE, BibliographyDataType::CONFERENCE }, + { XML_CUSTOM1, BibliographyDataType::CUSTOM1 }, + { XML_CUSTOM2, BibliographyDataType::CUSTOM2 }, + { XML_CUSTOM3, BibliographyDataType::CUSTOM3 }, + { XML_CUSTOM4, BibliographyDataType::CUSTOM4 }, + { XML_CUSTOM5, BibliographyDataType::CUSTOM5 }, + { XML_EMAIL, BibliographyDataType::EMAIL }, + { XML_INBOOK, BibliographyDataType::INBOOK }, + { XML_INCOLLECTION, BibliographyDataType::INCOLLECTION }, + { XML_INPROCEEDINGS, BibliographyDataType::INPROCEEDINGS }, + { XML_JOURNAL, BibliographyDataType::JOURNAL }, + { XML_MANUAL, BibliographyDataType::MANUAL }, + { XML_MASTERSTHESIS, BibliographyDataType::MASTERSTHESIS }, + { XML_MISC, BibliographyDataType::MISC }, + { XML_PHDTHESIS, BibliographyDataType::PHDTHESIS }, + { XML_PROCEEDINGS, BibliographyDataType::PROCEEDINGS }, + { XML_TECHREPORT, BibliographyDataType::TECHREPORT }, + { XML_UNPUBLISHED, BibliographyDataType::UNPUBLISHED }, + { XML_WWW, BibliographyDataType::WWW }, + { XML_TOKEN_INVALID, 0 } +}; + + +void XMLTextFieldExport::ProcessBibliographyData( + const Reference& rPropSet) +{ + // get the values + Any aAny = rPropSet->getPropertyValue(gsPropertyFields); + Sequence aValues; + aAny >>= aValues; + + // one attribute per value (unless empty) + for (const auto& rProp : std::as_const(aValues)) + { + if( rProp.Name == "BibiliographicType" ) + { + sal_Int16 nTypeId = 0; + rProp.Value >>= nTypeId; + OUStringBuffer sBuf; + + if (SvXMLUnitConverter::convertEnum(sBuf, nTypeId, + aBibliographyDataTypeMap)) + { + rExport.AddAttribute(XML_NAMESPACE_TEXT, + XML_BIBLIOGRAPHY_TYPE, + sBuf.makeStringAndClear()); + } + // else: ignore this argument + } + else + { + OUString sStr; + rProp.Value >>= sStr; + + if (!sStr.isEmpty()) + { + XMLTokenEnum eElement = MapBibliographyFieldName(rProp.Name); + if (eElement == XML_URL || eElement == XML_LOCAL_URL) + { + sStr = GetExport().GetRelativeReference(sStr); + } + sal_uInt16 nPrefix = XML_NAMESPACE_TEXT; + if (eElement == XML_LOCAL_URL) + { + nPrefix = XML_NAMESPACE_LO_EXT; + } + rExport.AddAttribute(nPrefix, eElement, sStr); + } + } + } +} + +/// export CommandTypeAttribute +void XMLTextFieldExport::ProcessCommandType( + sal_Int32 nCommandType) +{ + enum XMLTokenEnum eToken = XML_TOKEN_INVALID; + switch( nCommandType ) + { + case sdb::CommandType::TABLE: eToken = XML_TABLE; break; + case sdb::CommandType::QUERY: eToken = XML_QUERY; break; + case sdb::CommandType::COMMAND: eToken = XML_COMMAND; break; + } + + if( eToken != XML_TOKEN_INVALID ) + rExport.AddAttribute( XML_NAMESPACE_TEXT, XML_TABLE_TYPE, eToken ); +} + + +void XMLTextFieldExport::ProcessStringSequence( + const Sequence& rSequence, + const OUString& sSelected ) +{ + // find selected element + sal_Int32 nSelected = comphelper::findValue(rSequence, sSelected); + + // delegate to ProcessStringSequence(OUString,sal_Int32) + ProcessStringSequence( rSequence, nSelected ); +} + +void XMLTextFieldExport::ProcessStringSequence( + const Sequence& rSequence, + sal_Int32 nSelected ) +{ + sal_Int32 nLength = rSequence.getLength(); + const OUString* pSequence = rSequence.getConstArray(); + for( sal_Int32 i = 0; i < nLength; i++ ) + { + if( i == nSelected ) + rExport.AddAttribute( XML_NAMESPACE_TEXT, + XML_CURRENT_SELECTED, XML_TRUE ); + rExport.AddAttribute( XML_NAMESPACE_TEXT, XML_VALUE, pSequence[i] ); + SvXMLElementExport aElement( rExport, XML_NAMESPACE_TEXT, XML_LABEL, + false, false ); + } +} + +void XMLTextFieldExport::ExportDataBaseElement( + enum XMLTokenEnum eElementName, + const OUString& sPresentation, + const Reference& rPropertySet, + const Reference& rPropertySetInfo ) +{ + SAL_WARN_IF( eElementName == XML_TOKEN_INVALID, "xmloff.text", "need token" ); + SAL_WARN_IF( !rPropertySet.is(), "xmloff.text", "need property set" ); + SAL_WARN_IF( !rPropertySetInfo.is(), "xmloff.text", "need property set info" ); + + // get database properties + OUString sDataBaseName; + OUString sDataBaseURL; + OUString sStr; + if( ( rPropertySet->getPropertyValue( gsPropertyDataBaseName ) >>= sStr ) + && !sStr.isEmpty() ) + { + sDataBaseName = sStr; + } + else if( rPropertySetInfo->hasPropertyByName( gsPropertyDataBaseURL ) && + (rPropertySet->getPropertyValue( gsPropertyDataBaseURL ) >>= sStr) && + !sStr.isEmpty() ) + { + sDataBaseURL = sStr; + } + + // add database name property (if present) + if( !sDataBaseName.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_TEXT, XML_DATABASE_NAME, + sDataBaseName ); + SvXMLElementExport aDataBaseElement( GetExport(), + XML_NAMESPACE_TEXT, eElementName, + false, false ); + + // write URL as children + if( !sDataBaseURL.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sDataBaseURL ); + SvXMLElementExport aDataSourceElement( + GetExport(), XML_NAMESPACE_FORM, XML_CONNECTION_RESOURCE, + false, false ); + } + + // write presentation + rExport.Characters( sPresentation ); +} + + +// explode a field master name into field type and field name +void XMLTextFieldExport::ExplodeFieldMasterName( + std::u16string_view sMasterName, OUString& sFieldType, OUString& sVarName) +{ + sal_Int32 nLength = gsFieldMasterPrefix.getLength(); + size_t nSeparator = sMasterName.find('.', nLength); + + // '.' found? + if (nSeparator == o3tl::make_unsigned(nLength) || nSeparator == std::u16string_view::npos) { + SAL_WARN("xmloff.text", "no field var name!"); + } + else + { + sFieldType = sMasterName.substr(nLength, nSeparator-nLength); + sVarName = sMasterName.substr(nSeparator+1); + } +} + + +// for XDependentTextFields, get PropertySet of FieldMaster +Reference XMLTextFieldExport::GetMasterPropertySet( + const Reference & rTextField) +{ + // name, value => get Property set of TextFieldMaster + Reference xDep(rTextField, UNO_QUERY); + return xDep->getTextFieldMaster(); +} + +// get PropertySet of (any; the first) dependent field +bool XMLTextFieldExport::GetDependentFieldPropertySet( + const Reference & xMaster, + Reference & xField) +{ + Any aAny; + Sequence > aFields; + aAny = xMaster->getPropertyValue(gsPropertyDependentTextFields); + aAny >>= aFields; + + // any fields? + if (aFields.hasElements()) + { + // get first one and return + Reference xTField = aFields[0]; + xField.set(xTField, UNO_QUERY); + DBG_ASSERT(xField.is(), + "Surprisingly, this TextField refuses to be a PropertySet!"); + return true; + } + else + { + return false; + } +} + + +/// map placeholder type +enum XMLTokenEnum XMLTextFieldExport::MapPlaceholderType(sal_uInt16 nType) +{ + enum XMLTokenEnum eType = XML_TEXT; + + switch (nType) + { + case PlaceholderType::TEXT: + eType = XML_TEXT; + break; + + case PlaceholderType::TABLE: + eType = XML_TABLE; + break; + + case PlaceholderType::TEXTFRAME: + eType = XML_TEXT_BOX; + break; + + case PlaceholderType::GRAPHIC: + eType = XML_IMAGE; + break; + + case PlaceholderType::OBJECT: + eType = XML_OBJECT; + break; + + default: + // unknown placeholder: XML_TEXT + OSL_FAIL("unknown placeholder type"); + } + + return eType; +} + + +/// element name for author fields +enum XMLTokenEnum XMLTextFieldExport::MapAuthorFieldName( + const Reference & xPropSet) +{ + // Initials or full name? + return GetBoolProperty(gsPropertyFullName, xPropSet) + ? XML_AUTHOR_NAME : XML_AUTHOR_INITIALS; +} + +enum XMLTokenEnum XMLTextFieldExport::MapPageNumberName( + const Reference & xPropSet, + sal_Int32& nOffset) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + PageNumberType ePage; + Any aAny = xPropSet->getPropertyValue(gsPropertySubType); + ePage = *o3tl::doAccess(aAny); + + switch (ePage) + { + case PageNumberType_PREV: + eName = XML_PREVIOUS; + nOffset += 1; + break; + case PageNumberType_CURRENT: + eName = XML_CURRENT; + break; + case PageNumberType_NEXT: + eName = XML_NEXT; + nOffset -= 1; + break; + default: + OSL_FAIL("unknown page number type"); + eName = XML_TOKEN_INVALID; + break; + } + + return eName; +} + +/// map TemplateDisplayFormat to XML +enum XMLTokenEnum XMLTextFieldExport::MapTemplateDisplayFormat(sal_Int16 nFormat) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + switch (nFormat) + { + case TemplateDisplayFormat::FULL: + eName = XML_FULL; + break; + case TemplateDisplayFormat::PATH: + eName = XML_PATH; + break; + case TemplateDisplayFormat::NAME: + eName = XML_NAME; + break; + case TemplateDisplayFormat::NAME_AND_EXT: + eName = XML_NAME_AND_EXTENSION; + break; + case TemplateDisplayFormat::AREA: + eName = XML_AREA; + break; + case TemplateDisplayFormat::TITLE: + eName = XML_TITLE; + break; + default: + OSL_FAIL("unknown template display format"); + eName = XML_TOKEN_INVALID; + break; + } + + return eName; +} + +/// map count/statistics field token to XML name +enum XMLTokenEnum XMLTextFieldExport::MapCountFieldName(FieldIdEnum nToken) +{ + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + switch (nToken) + { + case FIELD_ID_COUNT_PAGES: + eElement = XML_PAGE_COUNT; + break; + case FIELD_ID_COUNT_PARAGRAPHS: + eElement = XML_PARAGRAPH_COUNT; + break; + case FIELD_ID_COUNT_WORDS: + eElement = XML_WORD_COUNT; + break; + case FIELD_ID_COUNT_CHARACTERS: + eElement = XML_CHARACTER_COUNT; + break; + case FIELD_ID_COUNT_TABLES: + eElement = XML_TABLE_COUNT; + break; + case FIELD_ID_COUNT_GRAPHICS: + eElement = XML_IMAGE_COUNT; + break; + case FIELD_ID_COUNT_OBJECTS: + eElement = XML_OBJECT_COUNT; + break; + default: + OSL_FAIL("no count field token"); + eElement = XML_TOKEN_INVALID; + break; + } + + return eElement; +} + +/// map ChapterDisplayFormat to XML string +enum XMLTokenEnum XMLTextFieldExport::MapChapterDisplayFormat(sal_Int16 nFormat) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + switch (nFormat) + { + case ChapterFormat::NAME: + eName = XML_NAME; + break; + case ChapterFormat::NUMBER: + eName = XML_NUMBER; + break; + case ChapterFormat::NAME_NUMBER: + eName = XML_NUMBER_AND_NAME; + break; + case ChapterFormat::NO_PREFIX_SUFFIX: + eName = XML_PLAIN_NUMBER_AND_NAME; + break; + case ChapterFormat::DIGIT: + eName = XML_PLAIN_NUMBER; + break; + default: + OSL_FAIL("unknown chapter display format"); + eName = XML_TOKEN_INVALID; + break; + } + + return eName; +} + + +/// map FilenameDisplayFormat to XML attribute names +enum XMLTokenEnum XMLTextFieldExport::MapFilenameDisplayFormat(sal_Int16 nFormat) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + switch (nFormat) + { + case FilenameDisplayFormat::FULL: + eName = XML_FULL; + break; + case FilenameDisplayFormat::PATH: + eName = XML_PATH; + break; + case FilenameDisplayFormat::NAME: + eName = XML_NAME; + break; + case FilenameDisplayFormat::NAME_AND_EXT: + eName = XML_NAME_AND_EXTENSION; + break; + default: + OSL_FAIL("unknown filename display format"); + } + + return eName; +} + + +/// map ReferenceFieldPart to XML string +enum XMLTokenEnum XMLTextFieldExport::MapReferenceType(sal_Int16 nType) +{ + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + switch (nType) + { + case ReferenceFieldPart::PAGE: + eElement = XML_PAGE; + break; + case ReferenceFieldPart::CHAPTER: + eElement = XML_CHAPTER; + break; + case ReferenceFieldPart::TEXT: + eElement = XML_TEXT; + break; + case ReferenceFieldPart::UP_DOWN: + eElement = XML_DIRECTION; + break; + case ReferenceFieldPart::CATEGORY_AND_NUMBER: + eElement = XML_CATEGORY_AND_VALUE; + break; + case ReferenceFieldPart::ONLY_CAPTION: + eElement = XML_CAPTION; + break; + case ReferenceFieldPart::ONLY_SEQUENCE_NUMBER: + eElement = XML_VALUE; + break; + case ReferenceFieldPart::PAGE_DESC: + // small hack: this value never gets written, because + // XML_TEMPLATE is default + eElement = XML_TEMPLATE; + break; + // Core implementation for direct cross-references (#i81002#) + case ReferenceFieldPart::NUMBER: + eElement = XML_NUMBER; + break; + case ReferenceFieldPart::NUMBER_NO_CONTEXT: + eElement = XML_NUMBER_NO_SUPERIOR; + break; + case ReferenceFieldPart::NUMBER_FULL_CONTEXT: + eElement = XML_NUMBER_ALL_SUPERIOR; + break; + default: + OSL_FAIL("unknown reference type"); + eElement = XML_TEMPLATE; + break; + } + + return eElement; +} + +/// map ReferenceFieldPart to XML string +enum XMLTokenEnum XMLTextFieldExport::MapReferenceSource(sal_Int16 nType) +{ + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + switch (nType) + { + case ReferenceFieldSource::REFERENCE_MARK: + eElement = XML_REFERENCE_REF; + break; + case ReferenceFieldSource::SEQUENCE_FIELD: + eElement = XML_SEQUENCE_REF; + break; + case ReferenceFieldSource::BOOKMARK: + eElement = XML_BOOKMARK_REF; + break; + case ReferenceFieldSource::FOOTNOTE: + case ReferenceFieldSource::ENDNOTE: + eElement = XML_NOTE_REF; + break; + default: + OSL_FAIL("unknown reference source"); + break; + } + + return eElement; +} + + +/// element name for sender fields +enum XMLTokenEnum XMLTextFieldExport::MapSenderFieldName( + const Reference & xPropSet) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + // sub-field type + switch (GetInt16Property(gsPropertyFieldSubType, xPropSet)) + { + case UserDataPart::COMPANY : + eName = XML_SENDER_COMPANY; + break; + case UserDataPart::FIRSTNAME : + eName = XML_SENDER_FIRSTNAME; + break; + case UserDataPart::NAME : + eName = XML_SENDER_LASTNAME; + break; + case UserDataPart::SHORTCUT : + eName = XML_SENDER_INITIALS; + break; + case UserDataPart::STREET : + eName = XML_SENDER_STREET; + break; + case UserDataPart::COUNTRY : + eName = XML_SENDER_COUNTRY; + break; + case UserDataPart::ZIP : + eName = XML_SENDER_POSTAL_CODE; + break; + case UserDataPart::CITY : + eName = XML_SENDER_CITY; + break; + case UserDataPart::TITLE : + eName = XML_SENDER_TITLE; + break; + case UserDataPart::POSITION : + eName = XML_SENDER_POSITION; + break; + case UserDataPart::PHONE_PRIVATE : + eName = XML_SENDER_PHONE_PRIVATE; + break; + case UserDataPart::PHONE_COMPANY : + eName = XML_SENDER_PHONE_WORK; + break; + case UserDataPart::FAX : + eName = XML_SENDER_FAX; + break; + case UserDataPart::EMAIL : + eName = XML_SENDER_EMAIL; + break; + case UserDataPart::STATE : + eName = XML_SENDER_STATE_OR_PROVINCE; + break; + default: + SAL_WARN("xmloff.text", "unknown sender type"); + eName = XML_TOKEN_INVALID; + break; + } + + return eName; +} + +enum XMLTokenEnum XMLTextFieldExport::MapDocInfoFieldName( + enum FieldIdEnum nToken) +{ + enum XMLTokenEnum eElement = XML_TOKEN_INVALID; + + switch (nToken) + { + case FIELD_ID_DOCINFO_CREATION_AUTHOR: + eElement = XML_INITIAL_CREATOR; + break; + case FIELD_ID_DOCINFO_CREATION_DATE: + eElement = XML_CREATION_DATE; + break; + case FIELD_ID_DOCINFO_CREATION_TIME: + eElement = XML_CREATION_TIME; + break; + case FIELD_ID_DOCINFO_DESCRIPTION: + eElement = XML_DESCRIPTION; + break; + case FIELD_ID_DOCINFO_PRINT_TIME: + eElement = XML_PRINT_TIME; + break; + case FIELD_ID_DOCINFO_PRINT_DATE: + eElement = XML_PRINT_DATE; + break; + case FIELD_ID_DOCINFO_PRINT_AUTHOR: + eElement = XML_PRINTED_BY; + break; + case FIELD_ID_DOCINFO_TITLE: + eElement = XML_TITLE; + break; + case FIELD_ID_DOCINFO_SUBJECT: + eElement = XML_SUBJECT; + break; + case FIELD_ID_DOCINFO_KEYWORDS: + eElement = XML_KEYWORDS; + break; + case FIELD_ID_DOCINFO_REVISION: + eElement = XML_EDITING_CYCLES; + break; + case FIELD_ID_DOCINFO_EDIT_DURATION: + eElement = XML_EDITING_DURATION; + break; + case FIELD_ID_DOCINFO_SAVE_TIME: + eElement = XML_MODIFICATION_TIME; + break; + case FIELD_ID_DOCINFO_SAVE_DATE: + eElement = XML_MODIFICATION_DATE; + break; + case FIELD_ID_DOCINFO_SAVE_AUTHOR: + eElement = XML_CREATOR; + break; + default: + SAL_WARN("xmloff.text", "unknown docinfo field type!"); + eElement = XML_TOKEN_INVALID; + break; + } + + return eElement; +} + +enum XMLTokenEnum XMLTextFieldExport::MapBibliographyFieldName(std::u16string_view sName) +{ + enum XMLTokenEnum eName = XML_TOKEN_INVALID; + + if( sName == u"Identifier" ) + { + eName = XML_IDENTIFIER; + } + else if( sName == u"BibiliographicType" ) + { + eName = XML_BIBLIOGRAPHY_TYPE; + } + else if( sName == u"Address" ) + { + eName = XML_ADDRESS; + } + else if( sName == u"Annote" ) + { + eName = XML_ANNOTE; + } + else if( sName == u"Author" ) + { + eName = XML_AUTHOR; + } + else if( sName == u"Booktitle" ) + { + eName = XML_BOOKTITLE; + } + else if( sName == u"Chapter" ) + { + eName = XML_CHAPTER; + } + else if( sName == u"Edition" ) + { + eName = XML_EDITION; + } + else if( sName == u"Editor" ) + { + eName = XML_EDITOR; + } + else if( sName == u"Howpublished" ) + { + eName = XML_HOWPUBLISHED; + } + else if( sName == u"Institution" ) + { + eName = XML_INSTITUTION; + } + else if( sName == u"Journal" ) + { + eName = XML_JOURNAL; + } + else if( sName == u"Month" ) + { + eName = XML_MONTH; + } + else if( sName == u"Note" ) + { + eName = XML_NOTE; + } + else if( sName == u"Number" ) + { + eName = XML_NUMBER; + } + else if( sName == u"Organizations" ) + { + eName = XML_ORGANIZATIONS; + } + else if( sName == u"Pages" ) + { + eName = XML_PAGES; + } + else if( sName == u"Publisher" ) + { + eName = XML_PUBLISHER; + } + else if( sName == u"School" ) + { + eName = XML_SCHOOL; + } + else if( sName == u"Series" ) + { + eName = XML_SERIES; + } + else if( sName == u"Title" ) + { + eName = XML_TITLE; + } + else if( sName == u"Report_Type" ) + { + eName = XML_REPORT_TYPE; + } + else if( sName == u"Volume" ) + { + eName = XML_VOLUME; + } + else if( sName == u"Year" ) + { + eName = XML_YEAR; + } + else if( sName == u"URL" ) + { + eName = XML_URL; + } + else if( sName == u"Custom1" ) + { + eName = XML_CUSTOM1; + } + else if( sName == u"Custom2" ) + { + eName = XML_CUSTOM2; + } + else if( sName == u"Custom3" ) + { + eName = XML_CUSTOM3; + } + else if( sName == u"Custom4" ) + { + eName = XML_CUSTOM4; + } + else if( sName == u"Custom5" ) + { + eName = XML_CUSTOM5; + } + else if( sName == u"ISBN" ) + { + eName = XML_ISBN; + } + else if (sName == u"LocalURL") + { + eName = XML_LOCAL_URL; + } + else + { + SAL_WARN("xmloff.text", "Unknown bibliography info data"); + eName = XML_TOKEN_INVALID; + } + + return eName; +} + +enum XMLTokenEnum XMLTextFieldExport::MapMeasureKind(sal_Int16 nKind) +{ + switch( nKind ) + { + case 0: + return XML_VALUE; + case 1: + return XML_UNIT; + } + return XML_GAP; +} + +OUString XMLTextFieldExport::MakeFootnoteRefName( + sal_Int16 nSeqNo) +{ + // generate foot-/endnote ID + return "ftn" + OUString::number(static_cast(nSeqNo)); +} + +OUString XMLTextFieldExport::MakeSequenceRefName( + sal_Int16 nSeqNo, + std::u16string_view rSeqName) +{ + // generate foot-/endnote ID + return OUString::Concat("ref") +rSeqName + OUString::number(static_cast(nSeqNo)); +} + + +// Property accessor helper functions + + +// to be relegated (does that word exist?) to a more appropriate place + + +bool GetBoolProperty( + const OUString& sPropName, + const Reference & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + bool bBool = *o3tl::doAccess(aAny); + return bBool; +} + +bool GetOptionalBoolProperty( + const OUString& sPropName, + const Reference & xPropSet, + const Reference & xPropSetInfo, + bool bDefault) +{ + return xPropSetInfo->hasPropertyByName( sPropName ) + ? GetBoolProperty( sPropName, xPropSet ) : bDefault; +} + +double GetDoubleProperty( + const OUString& sPropName, + const Reference & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + double fDouble = 0.0; + aAny >>= fDouble; + return fDouble; +} + +OUString GetStringProperty( + const OUString& sPropName, + const Reference & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + OUString sString; + aAny >>= sString; + return sString; +} + +sal_Int32 GetIntProperty( + const OUString& sPropName, + const Reference & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + sal_Int32 nInt = 0; + aAny >>= nInt; + return nInt; +} + +sal_Int16 GetInt16Property( + const OUString& sPropName, + const Reference & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + sal_Int16 nInt = 0; + aAny >>= nInt; + return nInt; +} + +sal_Int8 GetInt8Property( + const OUString& sPropName, + const Reference & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + sal_Int8 nInt = 0; + aAny >>= nInt; + return nInt; +} + +util::DateTime GetDateTimeProperty( + const OUString& sPropName, + const Reference & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + util::DateTime aTime; + aAny >>= aTime; + return aTime; +} + +Sequence GetStringSequenceProperty( + const OUString& sPropName, + const Reference & xPropSet) +{ + Any aAny = xPropSet->getPropertyValue(sPropName); + Sequence aSequence; + aAny >>= aSequence; + return aSequence; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtfldi.cxx b/xmloff/source/text/txtfldi.cxx new file mode 100644 index 000000000..7e99d0c38 --- /dev/null +++ b/xmloff/source/text/txtfldi.cxx @@ -0,0 +1,3628 @@ +/* -*- 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 . + */ + + +/** @#file + * + * Import of all text fields except those from txtvfldi.cxx + * (variable related text fields and database display fields) + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + + +// SO API string constants + + +// service prefix and service names +constexpr OUStringLiteral sAPI_textfield_prefix = u"com.sun.star.text.TextField."; +constexpr char16_t sAPI_fieldmaster_prefix[] = u"com.sun.star.text.FieldMaster."; +constexpr OUStringLiteral sAPI_presentation_prefix = u"com.sun.star.presentation.TextField."; + +constexpr OUStringLiteral sAPI_date_time = u"DateTime"; +constexpr OUStringLiteral sAPI_page_number = u"PageNumber"; +constexpr OUStringLiteral sAPI_docinfo_change_date_time = u"DocInfo.ChangeDateTime"; +constexpr OUStringLiteral sAPI_docinfo_create_date_time = u"DocInfo.CreateDateTime"; +constexpr OUStringLiteral sAPI_docinfo_custom = u"DocInfo.Custom"; +constexpr OUStringLiteral sAPI_docinfo_print_date_time = u"DocInfo.PrintDateTime"; +constexpr OUStringLiteral sAPI_dde = u"DDE"; +constexpr OUStringLiteral sAPI_url = u"URL"; + +// property names +constexpr OUStringLiteral sAPI_is_fixed = u"IsFixed"; +constexpr OUStringLiteral sAPI_content = u"Content"; +constexpr OUStringLiteral sAPI_author = u"Author"; +constexpr OUStringLiteral sAPI_hint = u"Hint"; +constexpr OUStringLiteral sAPI_name = u"Name"; +constexpr OUStringLiteral sAPI_sub_type = u"SubType"; +constexpr OUStringLiteral sAPI_date_time_value = u"DateTimeValue"; +constexpr OUStringLiteral sAPI_number_format = u"NumberFormat"; +constexpr OUStringLiteral sAPI_numbering_type = u"NumberingType"; +constexpr OUStringLiteral sAPI_offset = u"Offset"; +constexpr OUStringLiteral sAPI_condition = u"Condition"; +constexpr OUStringLiteral sAPI_set_number = u"SetNumber"; +constexpr OUStringLiteral sAPI_file_format = u"FileFormat"; +constexpr OUStringLiteral sAPI_is_date = u"IsDate"; +constexpr OUStringLiteral sAPI_current_presentation = u"CurrentPresentation"; +constexpr OUStringLiteral sAPI_is_hidden = u"IsHidden"; +constexpr OUStringLiteral sAPI_is_fixed_language = u"IsFixedLanguage"; + +constexpr OUStringLiteral sAPI_true = u"TRUE"; + + +XMLTextFieldImportContext::XMLTextFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + const OUString& pService) +: SvXMLImportContext( rImport ) +, sServiceName(pService) +, rTextImportHelper(rHlp) +, sServicePrefix(sAPI_textfield_prefix) +, bValid(false) +{ +} + +void XMLTextFieldImportContext::startFastElement( + sal_Int32 /*nElement*/, + const Reference & xAttrList) +{ + // process attributes + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + ProcessAttribute(aIter.getToken(), aIter.toView() ); +} + +OUString const & XMLTextFieldImportContext::GetContent() +{ + if (sContent.isEmpty()) + { + sContent = sContentBuffer.makeStringAndClear(); + } + + return sContent; +} + +void XMLTextFieldImportContext::endFastElement(sal_Int32 ) +{ + if (bValid) + { + + // create field/Service + Reference xPropSet; + if (CreateField(xPropSet, sServicePrefix + GetServiceName())) + { + // set field properties + PrepareField(xPropSet); + + // attach field to document + Reference xTextContent(xPropSet, UNO_QUERY); + + // workaround for #80606# + try + { + rTextImportHelper.InsertTextContent(xTextContent); + } + catch (const lang::IllegalArgumentException&) + { + // ignore + } + return; + } + } + + // in case of error: write element content + rTextImportHelper.InsertString(GetContent()); +} + +void XMLTextFieldImportContext::characters(const OUString& rContent) +{ + sContentBuffer.append(rContent); +} + +bool XMLTextFieldImportContext::CreateField( + Reference & xField, + const OUString& rServiceName) +{ + // instantiate new XTextField: + // ask import for model, model is factory, ask factory to create service + + Reference xFactory(GetImport().GetModel(),UNO_QUERY); + if( xFactory.is() ) + { + Reference xIfc = xFactory->createInstance(rServiceName); + if( xIfc.is() ) + { + Reference xTmp( xIfc, UNO_QUERY ); + + xField = xTmp; + } else { + return false; // can't create instance + } + } else { + return false; // can't get MultiServiceFactory + } + + return true; +} + +/// create the appropriate field context from +XMLTextFieldImportContext* +XMLTextFieldImportContext::CreateTextFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp, + sal_Int32 nToken) +{ + XMLTextFieldImportContext* pContext = nullptr; + + switch (nToken) + { + case XML_ELEMENT(TEXT, XML_SENDER_FIRSTNAME): + case XML_ELEMENT(TEXT, XML_SENDER_LASTNAME): + case XML_ELEMENT(LO_EXT, XML_SENDER_INITIALS): + case XML_ELEMENT(TEXT, XML_SENDER_INITIALS): + case XML_ELEMENT(TEXT, XML_SENDER_TITLE): + case XML_ELEMENT(TEXT, XML_SENDER_POSITION): + case XML_ELEMENT(TEXT, XML_SENDER_EMAIL): + case XML_ELEMENT(TEXT, XML_SENDER_PHONE_PRIVATE): + + case XML_ELEMENT(TEXT, XML_SENDER_FAX): + case XML_ELEMENT(TEXT, XML_SENDER_COMPANY): + case XML_ELEMENT(TEXT, XML_SENDER_PHONE_WORK): + case XML_ELEMENT(TEXT, XML_SENDER_STREET): + case XML_ELEMENT(TEXT, XML_SENDER_CITY): + case XML_ELEMENT(TEXT, XML_SENDER_POSTAL_CODE): + case XML_ELEMENT(TEXT, XML_SENDER_COUNTRY): + case XML_ELEMENT(TEXT, XML_SENDER_STATE_OR_PROVINCE): + pContext = + new XMLSenderFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_AUTHOR_NAME): + case XML_ELEMENT(TEXT, XML_AUTHOR_INITIALS): + pContext = + new XMLAuthorFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_PLACEHOLDER): + pContext = + new XMLPlaceholderFieldImportContext( rImport, rHlp); + break; + case XML_ELEMENT(TEXT, XML_SEQUENCE): + pContext = + new XMLSequenceFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_TEXT_INPUT): + pContext = + new XMLTextInputFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_EXPRESSION): + pContext = + new XMLExpressionFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_VARIABLE_SET): + pContext = + new XMLVariableSetFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_VARIABLE_INPUT): + pContext = + new XMLVariableInputFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_VARIABLE_GET): + pContext = + new XMLVariableGetFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_USER_FIELD_GET): + pContext = new XMLUserFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_USER_FIELD_INPUT): + pContext = new XMLUserFieldInputImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_TIME): + pContext = new XMLTimeFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_PAGE_CONTINUATION_STRING): + case XML_ELEMENT(TEXT, XML_PAGE_CONTINUATION): + pContext = new XMLPageContinuationImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_PAGE_NUMBER): + pContext = new XMLPageNumberImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_DATE): + pContext = new XMLDateFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_DATABASE_NAME): + pContext = new XMLDatabaseNameImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DATABASE_NEXT): + pContext = new XMLDatabaseNextImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DATABASE_ROW_SELECT): + pContext = new XMLDatabaseSelectImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DATABASE_ROW_NUMBER): + pContext = new XMLDatabaseNumberImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DATABASE_DISPLAY): + pContext = new XMLDatabaseDisplayImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_CONDITIONAL_TEXT): + pContext = new XMLConditionalTextImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_HIDDEN_TEXT): + pContext = new XMLHiddenTextImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_HIDDEN_PARAGRAPH): + pContext = new XMLHiddenParagraphImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + case XML_ELEMENT(TEXT, XML_TITLE): + case XML_ELEMENT(TEXT, XML_SUBJECT): + case XML_ELEMENT(TEXT, XML_KEYWORDS): + pContext = new XMLSimpleDocInfoImportContext( rImport, rHlp, + nToken, true, + false ); + break; + case XML_ELEMENT(TEXT, XML_INITIAL_CREATOR): + case XML_ELEMENT(TEXT, XML_PRINTED_BY): + case XML_ELEMENT(TEXT, XML_CREATOR): + pContext = new XMLSimpleDocInfoImportContext( rImport, rHlp, + nToken, false, + true ); + break; + + case XML_ELEMENT(TEXT, XML_CREATION_DATE): + case XML_ELEMENT(TEXT, XML_CREATION_TIME): + case XML_ELEMENT(TEXT, XML_PRINT_DATE): + case XML_ELEMENT(TEXT, XML_PRINT_TIME): + case XML_ELEMENT(TEXT, XML_MODIFICATION_DATE): + case XML_ELEMENT(TEXT, XML_MODIFICATION_TIME): + case XML_ELEMENT(TEXT, XML_EDITING_DURATION): + pContext = new XMLDateTimeDocInfoImportContext( rImport, rHlp, + nToken ); + break; + + case XML_ELEMENT(TEXT, XML_EDITING_CYCLES): + pContext = new XMLRevisionDocInfoImportContext( rImport, rHlp, + nToken ); + break; + + case XML_ELEMENT(TEXT, XML_USER_DEFINED): + pContext = new XMLUserDocInfoImportContext( rImport, rHlp, + nToken ); + break; + + case XML_ELEMENT(TEXT, XML_FILE_NAME): + pContext = new XMLFileNameImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_CHAPTER): + pContext = new XMLChapterImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_TEMPLATE_NAME): + pContext = new XMLTemplateNameImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_WORD_COUNT): + case XML_ELEMENT(TEXT, XML_PARAGRAPH_COUNT): + case XML_ELEMENT(TEXT, XML_TABLE_COUNT): + case XML_ELEMENT(TEXT, XML_CHARACTER_COUNT): + case XML_ELEMENT(TEXT, XML_IMAGE_COUNT): + case XML_ELEMENT(TEXT, XML_OBJECT_COUNT): + case XML_ELEMENT(TEXT, XML_PAGE_COUNT): + pContext = new XMLCountFieldImportContext( rImport, rHlp, nToken); + break; + + case XML_ELEMENT(TEXT, XML_PAGE_VARIABLE_GET): + pContext = new XMLPageVarGetFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_PAGE_VARIABLE_SET): + pContext = new XMLPageVarSetFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_EXECUTE_MACRO): + pContext = new XMLMacroFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_DDE_CONNECTION): + pContext = new XMLDdeFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_REFERENCE_REF): + case XML_ELEMENT(TEXT, XML_BOOKMARK_REF): + case XML_ELEMENT(TEXT, XML_NOTE_REF): + case XML_ELEMENT(TEXT, XML_SEQUENCE_REF): + pContext = new XMLReferenceFieldImportContext( rImport, rHlp, nToken ); + break; + + case XML_ELEMENT(TEXT, XML_SHEET_NAME): + pContext = new XMLSheetNameImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_PAGE_NAME): + case XML_ELEMENT(LO_EXT, XML_PAGE_NAME): + pContext = new XMLPageNameFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY_MARK): + pContext = new XMLBibliographyFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(OFFICE, XML_ANNOTATION): + case XML_ELEMENT(OFFICE, XML_ANNOTATION_END): + pContext = new XMLAnnotationImportContext( rImport, rHlp, nToken); + break; + + case XML_ELEMENT(TEXT, XML_SCRIPT): + pContext = new XMLScriptImportContext( rImport, rHlp); + break; + + case XML_ELEMENT(TEXT, XML_MEASURE): + pContext = new XMLMeasureFieldImportContext( rImport, rHlp ); + break; + + case XML_ELEMENT(TEXT, XML_TABLE_FORMULA): + pContext = new XMLTableFormulaImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(TEXT, XML_DROP_DOWN): + pContext = new XMLDropDownFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(PRESENTATION, XML_HEADER): + pContext = new XMLHeaderFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(PRESENTATION, XML_FOOTER): + pContext = new XMLFooterFieldImportContext( rImport, rHlp ); + break; + case XML_ELEMENT(PRESENTATION, XML_DATE_TIME): + pContext = new XMLDateTimeFieldImportContext( rImport, rHlp ); + break; + + default: + // ignore! May not even be a textfield. + // (Reminder: This method is called inside default:-branch) + pContext = nullptr; + break; + } + + return pContext; +} + + +void XMLTextFieldImportContext::ForceUpdate( + const Reference & rPropertySet) +{ + // force update + Reference xUpdate(rPropertySet, UNO_QUERY); + if (xUpdate.is()) + { + xUpdate->update(); + } + else + { + OSL_FAIL("Expected XUpdatable support!"); + } +} + + +// XMLSenderFieldImportContext + + +constexpr OUStringLiteral gsPropertyFieldSubType(u"UserDataType"); + +XMLSenderFieldImportContext::XMLSenderFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) + : XMLTextFieldImportContext(rImport, rHlp, "ExtendedUser") + , nSubType(0) + , sPropertyFixed(sAPI_is_fixed) + , sPropertyContent(sAPI_content) + , bFixed(true) +{ +} + +void XMLSenderFieldImportContext::startFastElement( + sal_Int32 nElement, + const Reference & xAttrList) +{ + bValid = true; + switch (nElement) { + case XML_ELEMENT(TEXT, XML_SENDER_FIRSTNAME): + nSubType = UserDataPart::FIRSTNAME; + break; + case XML_ELEMENT(TEXT, XML_SENDER_LASTNAME): + nSubType = UserDataPart::NAME; + break; + case XML_ELEMENT(LO_EXT, XML_SENDER_INITIALS): + case XML_ELEMENT(TEXT, XML_SENDER_INITIALS): + nSubType = UserDataPart::SHORTCUT; + break; + case XML_ELEMENT(TEXT, XML_SENDER_TITLE): + nSubType = UserDataPart::TITLE; + break; + case XML_ELEMENT(TEXT, XML_SENDER_POSITION): + nSubType = UserDataPart::POSITION; + break; + case XML_ELEMENT(TEXT, XML_SENDER_EMAIL): + nSubType = UserDataPart::EMAIL; + break; + case XML_ELEMENT(TEXT, XML_SENDER_PHONE_PRIVATE): + nSubType = UserDataPart::PHONE_PRIVATE; + break; + case XML_ELEMENT(TEXT, XML_SENDER_FAX): + nSubType = UserDataPart::FAX; + break; + case XML_ELEMENT(TEXT, XML_SENDER_COMPANY): + nSubType = UserDataPart::COMPANY; + break; + case XML_ELEMENT(TEXT, XML_SENDER_PHONE_WORK): + nSubType = UserDataPart::PHONE_COMPANY; + break; + case XML_ELEMENT(TEXT, XML_SENDER_STREET): + nSubType = UserDataPart::STREET; + break; + case XML_ELEMENT(TEXT, XML_SENDER_CITY): + nSubType = UserDataPart::CITY; + break; + case XML_ELEMENT(TEXT, XML_SENDER_POSTAL_CODE): + nSubType = UserDataPart::ZIP; + break; + case XML_ELEMENT(TEXT, XML_SENDER_COUNTRY): + nSubType = UserDataPart::COUNTRY; + break; + case XML_ELEMENT(TEXT, XML_SENDER_STATE_OR_PROVINCE): + nSubType = UserDataPart::STATE; + break; + default: + bValid = false; + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + break; + } + + // process Attributes + XMLTextFieldImportContext::startFastElement(nElement, xAttrList); +} + +void XMLSenderFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue) +{ + if (XML_ELEMENT(TEXT, XML_FIXED) == nAttrToken) { + + // set bVal + bool bVal(false); + bool const bRet = ::sax::Converter::convertBool(bVal, sAttrValue); + + // set bFixed if successful + if (bRet) { + bFixed = bVal; + } + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLSenderFieldImportContext::PrepareField( + const Reference & rPropSet) +{ + // set members + rPropSet->setPropertyValue(gsPropertyFieldSubType, Any(nSubType)); + + // set fixed + rPropSet->setPropertyValue(sPropertyFixed, Any(bFixed)); + + // set content if fixed + if (!bFixed) + return; + + // in organizer or styles-only mode: force update + if (GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropSet); + } + else + { + rPropSet->setPropertyValue(sPropertyContent, Any(GetContent())); + } +} + + +// XMLAuthorFieldImportContext + +constexpr OUStringLiteral gsPropertyAuthorFullName(u"FullName"); + +XMLAuthorFieldImportContext::XMLAuthorFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLSenderFieldImportContext(rImport, rHlp) +, bAuthorFullName(true) +, sPropertyFixed(sAPI_is_fixed) +, sPropertyContent(sAPI_content) +{ + // overwrite service name from XMLSenderFieldImportContext + SetServiceName(sAPI_author); +} + +void XMLAuthorFieldImportContext::startFastElement( + sal_Int32 nElement, + const Reference & xAttrList) +{ + bAuthorFullName = ( XML_ELEMENT(TEXT, XML_AUTHOR_INITIALS) != nElement); + bValid = true; + + // process Attributes + XMLTextFieldImportContext::startFastElement(nElement, xAttrList); +} + +void XMLAuthorFieldImportContext::ProcessAttribute(sal_Int32 nAttrToken, std::string_view sAttrValue) +{ + if(nAttrToken == XML_ELEMENT(TEXT, XML_FIXED)) + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + bFixed = bTmp; + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLAuthorFieldImportContext::PrepareField( + const Reference & rPropSet) +{ + // set members + Any aAny; + rPropSet->setPropertyValue(gsPropertyAuthorFullName, Any(bAuthorFullName)); + + rPropSet->setPropertyValue(sPropertyFixed, Any(bFixed)); + + // set content if fixed + if (!bFixed) + return; + + // organizer or styles-only mode: force update + if (GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropSet); + } + else + { + aAny <<= GetContent(); + rPropSet->setPropertyValue(sPropertyContent, aAny); + } +} + + +// page continuation string + + +SvXMLEnumMapEntry const lcl_aSelectPageAttrMap[] = +{ + { XML_PREVIOUS, PageNumberType_PREV }, + { XML_CURRENT, PageNumberType_CURRENT }, + { XML_NEXT, PageNumberType_NEXT }, + { XML_TOKEN_INVALID, PageNumberType(0) }, +}; + +constexpr OUStringLiteral gsPropertyUserText(u"UserText"); + +XMLPageContinuationImportContext::XMLPageContinuationImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, sAPI_page_number) +, sPropertySubType(sAPI_sub_type) +, sPropertyNumberingType(sAPI_numbering_type) +, eSelectPage(PageNumberType_CURRENT) +, sStringOK(false) +{ + bValid = true; +} + +void XMLPageContinuationImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch(nAttrToken) + { + case XML_ELEMENT(TEXT, XML_SELECT_PAGE): + { + PageNumberType nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, sAttrValue, + lcl_aSelectPageAttrMap) + && (PageNumberType_CURRENT != nTmp) ) + { + eSelectPage = nTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_STRING_VALUE): + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + sString = OUString::fromUtf8(sAttrValue); + sStringOK = true; + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLPageContinuationImportContext::PrepareField( + const Reference & xPropertySet) +{ + Any aAny; + + xPropertySet->setPropertyValue(sPropertySubType, Any(eSelectPage)); + + aAny <<= (sStringOK ? sString : GetContent()); + xPropertySet->setPropertyValue(gsPropertyUserText, aAny); + + aAny <<= style::NumberingType::CHAR_SPECIAL; + xPropertySet->setPropertyValue(sPropertyNumberingType, aAny); +} + + +// page number field + + +XMLPageNumberImportContext::XMLPageNumberImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, sAPI_page_number) +, sPropertySubType(sAPI_sub_type) +, sPropertyNumberingType(sAPI_numbering_type) +, sPropertyOffset(sAPI_offset) +, sNumberSync(GetXMLToken(XML_FALSE)) +, nPageAdjust(0) +, eSelectPage(PageNumberType_CURRENT) +, sNumberFormatOK(false) +{ + bValid = true; +} + +void XMLPageNumberImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumberFormat = OUString::fromUtf8(sAttrValue); + sNumberFormatOK = true; + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumberSync = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(TEXT, XML_SELECT_PAGE): + SvXMLUnitConverter::convertEnum(eSelectPage, sAttrValue, + lcl_aSelectPageAttrMap); + break; + case XML_ELEMENT(TEXT, XML_PAGE_ADJUST): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, sAttrValue)) + { + nPageAdjust = static_cast(nTmp); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLPageNumberImportContext::PrepareField( + const Reference & xPropertySet) +{ + // all properties are optional + Reference xPropertySetInfo( + xPropertySet->getPropertySetInfo()); + + if (xPropertySetInfo->hasPropertyByName(sPropertyNumberingType)) + { + sal_Int16 nNumType; + if( sNumberFormatOK ) + { + nNumType= style::NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumberFormat, + sNumberSync ); + } + else + nNumType = style::NumberingType::PAGE_DESCRIPTOR; + + xPropertySet->setPropertyValue(sPropertyNumberingType, Any(nNumType)); + } + + if (xPropertySetInfo->hasPropertyByName(sPropertyOffset)) + { + // adjust offset + switch (eSelectPage) + { + case PageNumberType_PREV: + nPageAdjust--; + break; + case PageNumberType_CURRENT: + break; + case PageNumberType_NEXT: + nPageAdjust++; + break; + default: + SAL_WARN("xmloff.text", "unknown page number type"); + } + xPropertySet->setPropertyValue(sPropertyOffset, Any(nPageAdjust)); + } + + if (xPropertySetInfo->hasPropertyByName(sPropertySubType)) + { + xPropertySet->setPropertyValue(sPropertySubType, Any(eSelectPage)); + } +} + + +// Placeholder + + +constexpr OUStringLiteral gsPropertyPlaceholderType(u"PlaceHolderType"); +constexpr OUStringLiteral gsPropertyPlaceholder(u"PlaceHolder"); + +XMLPlaceholderFieldImportContext::XMLPlaceholderFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, "JumpEdit") +, sPropertyHint(sAPI_hint) +, nPlaceholderType(PlaceholderType::TEXT) +{ +} + +/// process attribute values +void XMLPlaceholderFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) { + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + sDescription = OUString::fromUtf8(sAttrValue); + break; + + case XML_ELEMENT(TEXT, XML_PLACEHOLDER_TYPE): + bValid = true; + if (IsXMLToken(sAttrValue, XML_TABLE)) + { + nPlaceholderType = PlaceholderType::TABLE; + } + else if (IsXMLToken(sAttrValue, XML_TEXT)) + { + nPlaceholderType = PlaceholderType::TEXT; + } + else if (IsXMLToken(sAttrValue, XML_TEXT_BOX)) + { + nPlaceholderType = PlaceholderType::TEXTFRAME; + } + else if (IsXMLToken(sAttrValue, XML_IMAGE)) + { + nPlaceholderType = PlaceholderType::GRAPHIC; + } + else if (IsXMLToken(sAttrValue, XML_OBJECT)) + { + nPlaceholderType = PlaceholderType::OBJECT; + } + else + { + bValid = false; + } + break; + + default: + // ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLPlaceholderFieldImportContext::PrepareField( + const Reference & xPropertySet) { + + Any aAny; + xPropertySet->setPropertyValue(sPropertyHint, Any(sDescription)); + + // remove <...> around content (if present) + OUString aContent = GetContent(); + sal_Int32 nStart = 0; + sal_Int32 nLength = aContent.getLength(); + if (aContent.startsWith("<")) + { + --nLength; + ++nStart; + } + if (aContent.endsWith(">")) + { + --nLength; + } + aAny <<= aContent.copy(nStart, nLength); + xPropertySet->setPropertyValue(gsPropertyPlaceholder, aAny); + + xPropertySet->setPropertyValue(gsPropertyPlaceholderType, Any(nPlaceholderType)); +} + + +// time field + +constexpr OUStringLiteral gsPropertyAdjust(u"Adjust"); + +XMLTimeFieldImportContext::XMLTimeFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, sAPI_date_time) +, sPropertyNumberFormat(sAPI_number_format) +, sPropertyFixed(sAPI_is_fixed) +, sPropertyDateTimeValue(sAPI_date_time_value) +, sPropertyDateTime(sAPI_date_time) +, sPropertyIsDate(sAPI_is_date) +, sPropertyIsFixedLanguage(sAPI_is_fixed_language) +, nAdjust(0) +, nFormatKey(0) +, bTimeOK(false) +, bFormatOK(false) +, bFixed(false) +, bIsDate(false) +, bIsDefaultLanguage( true ) +{ + bValid = true; // always valid! +} + +void XMLTimeFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_TIME_VALUE): + case XML_ELEMENT(OFFICE, XML_TIME_VALUE): + { + if (::sax::Converter::parseTimeOrDateTime(aDateTimeValue, sAttrValue)) + { + bTimeOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_FIXED): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bFixed = bTmp; + } + break; + } + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + { + sal_Int32 nKey = GetImportHelper().GetDataStyleKey( + OUString::fromUtf8(sAttrValue), &bIsDefaultLanguage); + if (-1 != nKey) + { + nFormatKey = nKey; + bFormatOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_TIME_ADJUST): + { + double fTmp; + + if (::sax::Converter::convertDuration(fTmp, sAttrValue)) + { + // convert to minutes + nAdjust = static_cast(::rtl::math::approxFloor(fTmp * 60 * 24)); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLTimeFieldImportContext::PrepareField( + const Reference & rPropertySet) +{ + // all properties are optional (except IsDate) + Reference xPropertySetInfo( + rPropertySet->getPropertySetInfo()); + + if (xPropertySetInfo->hasPropertyByName(sPropertyFixed)) + { + rPropertySet->setPropertyValue(sPropertyFixed, Any(bFixed)); + } + + rPropertySet->setPropertyValue(sPropertyIsDate, Any(bIsDate)); + + if (xPropertySetInfo->hasPropertyByName(gsPropertyAdjust)) + { + rPropertySet->setPropertyValue(gsPropertyAdjust, Any(nAdjust)); + } + + // set value + if (bFixed) + { + // organizer or styles-only mode: force update + if (GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropertySet); + } + else + { + // normal mode: set value (if present) + if (bTimeOK) + { + if (xPropertySetInfo->hasPropertyByName(sPropertyDateTimeValue)) + { + rPropertySet->setPropertyValue(sPropertyDateTimeValue, Any(aDateTimeValue)); + } + else if (xPropertySetInfo->hasPropertyByName(sPropertyDateTime)) + { + rPropertySet->setPropertyValue(sPropertyDateTime, Any(aDateTimeValue)); + } + } + } + } + + if (bFormatOK && + xPropertySetInfo->hasPropertyByName(sPropertyNumberFormat)) + { + rPropertySet->setPropertyValue(sPropertyNumberFormat, Any(nFormatKey)); + + if( xPropertySetInfo->hasPropertyByName( sPropertyIsFixedLanguage ) ) + { + bool bIsFixedLanguage = ! bIsDefaultLanguage; + rPropertySet->setPropertyValue( sPropertyIsFixedLanguage, Any(bIsFixedLanguage) ); + } + } +} + + +// date field + + +XMLDateFieldImportContext::XMLDateFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTimeFieldImportContext(rImport, rHlp) +{ + bIsDate = true; // always a date! +} + +void XMLDateFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DATE_VALUE): + case XML_ELEMENT(OFFICE, XML_DATE_VALUE): + { + if (::sax::Converter::parseDateTime(aDateTimeValue, sAttrValue)) + { + bTimeOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_DATE_ADJUST): + // delegate to superclass, pretending it was a time-adjust attr. + XMLTimeFieldImportContext::ProcessAttribute( + XML_ELEMENT(TEXT, XML_TIME_ADJUST), + sAttrValue); + break; + case XML_ELEMENT(TEXT, XML_TIME_VALUE): + case XML_ELEMENT(OFFICE, XML_TIME_VALUE): + case XML_ELEMENT(TEXT, XML_TIME_ADJUST): + ; // ignore time-adjust and time-value attributes + break; + default: + // all others: delegate to super-class + return XMLTimeFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + } +} + + +// database field superclass + + +constexpr OUStringLiteral gsPropertyDataBaseName(u"DataBaseName"); +constexpr OUStringLiteral gsPropertyDataBaseURL(u"DataBaseURL"); +constexpr OUStringLiteral gsPropertyTableName(u"DataTableName"); +constexpr OUStringLiteral gsPropertyDataCommandType(u"DataCommandType"); +constexpr OUStringLiteral gsPropertyIsVisible(u"IsVisible"); + +XMLDatabaseFieldImportContext::XMLDatabaseFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + const OUString& pServiceName, bool bUseDisplay) +: XMLTextFieldImportContext(rImport, rHlp, pServiceName) +, m_nCommandType( sdb::CommandType::TABLE ) +, m_bCommandTypeOK(false) +, m_bDisplay( true ) +, m_bDisplayOK( false ) +, m_bUseDisplay( bUseDisplay ) +, m_bDatabaseOK(false) +, m_bDatabaseNameOK(false) +, m_bDatabaseURLOK(false) +, m_bTableOK(false) +{ +} + +void XMLDatabaseFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DATABASE_NAME): + m_sDatabaseName = OUString::fromUtf8(sAttrValue); + m_bDatabaseOK = true; + m_bDatabaseNameOK = true; + break; + case XML_ELEMENT(TEXT, XML_TABLE_NAME): + m_sTableName = OUString::fromUtf8(sAttrValue); + m_bTableOK = true; + break; + case XML_ELEMENT(TEXT, XML_TABLE_TYPE): + if( IsXMLToken( sAttrValue, XML_TABLE ) ) + { + m_nCommandType = sdb::CommandType::TABLE; + m_bCommandTypeOK = true; + } + else if( IsXMLToken( sAttrValue, XML_QUERY ) ) + { + m_nCommandType = sdb::CommandType::QUERY; + m_bCommandTypeOK = true; + } + else if( IsXMLToken( sAttrValue, XML_COMMAND ) ) + { + m_nCommandType = sdb::CommandType::COMMAND; + m_bCommandTypeOK = true; + } + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + if( IsXMLToken( sAttrValue, XML_NONE ) ) + { + m_bDisplay = false; + m_bDisplayOK = true; + } + else if( IsXMLToken( sAttrValue, XML_VALUE ) ) + { + m_bDisplay = true; + m_bDisplayOK = true; + } + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLDatabaseFieldImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if (nElement == XML_ELEMENT(FORM, XML_CONNECTION_RESOURCE) ) + { + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + { + m_sDatabaseURL = aIter.toString(); + m_bDatabaseOK = true; + m_bDatabaseURLOK = true; + } + break; + default:; + } + } + + // we call ProcessAttribute in order to set bValid appropriately + ProcessAttribute( XML_TOKEN_INVALID, "" ); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + + +void XMLDatabaseFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(gsPropertyTableName, Any(m_sTableName)); + + if( m_bDatabaseNameOK ) + { + xPropertySet->setPropertyValue(gsPropertyDataBaseName, Any(m_sDatabaseName)); + } + else if( m_bDatabaseURLOK ) + { + xPropertySet->setPropertyValue(gsPropertyDataBaseURL, Any(m_sDatabaseURL)); + } + + // #99980# load/save command type for all fields; also load + // old documents without command type + if( m_bCommandTypeOK ) + { + xPropertySet->setPropertyValue( gsPropertyDataCommandType, Any(m_nCommandType) ); + } + + if( m_bUseDisplay && m_bDisplayOK ) + { + xPropertySet->setPropertyValue( gsPropertyIsVisible, Any(m_bDisplay) ); + } +} + + +// database name field + + +XMLDatabaseNameImportContext::XMLDatabaseNameImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLDatabaseFieldImportContext(rImport, rHlp, "DatabaseName", true) +{ +} + +void XMLDatabaseNameImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + // delegate to superclass and check for success + XMLDatabaseFieldImportContext::ProcessAttribute(nAttrToken, sAttrValue); + bValid = m_bDatabaseOK && m_bTableOK; +} + + +// database next field + + +XMLDatabaseNextImportContext::XMLDatabaseNextImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + const OUString& pServiceName) : + XMLDatabaseFieldImportContext(rImport, rHlp, pServiceName, false), + sPropertyCondition(sAPI_condition), + sTrue(sAPI_true), + bConditionOK(false) +{ +} + +XMLDatabaseNextImportContext::XMLDatabaseNextImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) +: XMLDatabaseFieldImportContext(rImport, rHlp, "DatabaseNextSet", false) +, sPropertyCondition(sAPI_condition) +, sTrue(sAPI_true) +, bConditionOK(false) +{ +} + +void XMLDatabaseNextImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + if (XML_ELEMENT(TEXT, XML_CONDITION) == nAttrToken) + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrValueQName( + OUString::fromUtf8(sAttrValue), &sTmp ); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCondition = sTmp; + bConditionOK = true; + } + else + sCondition = OUString::fromUtf8(sAttrValue); + } + else + { + XMLDatabaseFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + } + + bValid = m_bDatabaseOK && m_bTableOK; +} + +void XMLDatabaseNextImportContext::PrepareField( + const Reference & xPropertySet) +{ + Any aAny; + + aAny <<= bConditionOK ? sCondition : sTrue; + xPropertySet->setPropertyValue(sPropertyCondition, aAny); + + XMLDatabaseFieldImportContext::PrepareField(xPropertySet); +} + + +// database select field + + +XMLDatabaseSelectImportContext::XMLDatabaseSelectImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLDatabaseNextImportContext(rImport, rHlp, "DatabaseNumberOfSet"), + sPropertySetNumber(sAPI_set_number), + nNumber(0), + bNumberOK(false) +{ +} + +void XMLDatabaseSelectImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if (XML_ELEMENT(TEXT, XML_ROW_NUMBER) == nAttrToken) + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( nTmp, sAttrValue + /* , nMin, nMax ??? */ )) + { + nNumber = nTmp; + bNumberOK = true; + } + } + else + { + XMLDatabaseNextImportContext::ProcessAttribute(nAttrToken, sAttrValue); + } + + bValid = m_bTableOK && m_bDatabaseOK && bNumberOK; +} + +void XMLDatabaseSelectImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertySetNumber, Any(nNumber)); + + XMLDatabaseNextImportContext::PrepareField(xPropertySet); +} + + +// database display row number field + + +XMLDatabaseNumberImportContext::XMLDatabaseNumberImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLDatabaseFieldImportContext(rImport, rHlp, "DatabaseSetNumber", true), + sPropertyNumberingType( + sAPI_numbering_type), + sPropertySetNumber(sAPI_set_number), + sNumberFormat("1"), + sNumberSync(GetXMLToken(XML_FALSE)), + nValue(0), + bValueOK(false) +{ +} + +void XMLDatabaseNumberImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumberFormat = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumberSync = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(TEXT, XML_VALUE_TYPE): + case XML_ELEMENT(OFFICE, XML_VALUE_TYPE): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( nTmp, sAttrValue )) + { + nValue = nTmp; + bValueOK = true; + } + break; + } + default: + XMLDatabaseFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + } + + bValid = m_bTableOK && m_bDatabaseOK; +} + +void XMLDatabaseNumberImportContext::PrepareField( + const Reference & xPropertySet) +{ + sal_Int16 nNumType = style::NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumberFormat, + sNumberSync ); + xPropertySet->setPropertyValue(sPropertyNumberingType, Any(nNumType)); + + if (bValueOK) + { + xPropertySet->setPropertyValue(sPropertySetNumber, Any(nValue)); + } + + XMLDatabaseFieldImportContext::PrepareField(xPropertySet); +} + + +// Simple doc info fields + + +XMLSimpleDocInfoImportContext::XMLSimpleDocInfoImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nElementToken, + bool bContent, bool bAuthor) +: XMLTextFieldImportContext(rImport, rHlp, MapTokenToServiceName(nElementToken) ) +, sPropertyFixed(sAPI_is_fixed) +, sPropertyContent(sAPI_content) +, sPropertyAuthor(sAPI_author) +, sPropertyCurrentPresentation(sAPI_current_presentation) +, bFixed(false) +, bHasAuthor(bAuthor) +, bHasContent(bContent) +{ + bValid = true; +} + +void XMLSimpleDocInfoImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if (XML_ELEMENT(TEXT, XML_FIXED) == nAttrToken) + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bFixed = bTmp; + } + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLSimpleDocInfoImportContext::PrepareField( + const Reference & rPropertySet) +{ + // title field in Calc has no Fixed property + Reference xPropertySetInfo(rPropertySet->getPropertySetInfo()); + if (!xPropertySetInfo->hasPropertyByName(sPropertyFixed)) + return; + + Any aAny; + rPropertySet->setPropertyValue(sPropertyFixed, Any(bFixed)); + + // set Content and CurrentPresentation (if fixed) + if (!bFixed) + return; + + // in organizer-mode or styles-only-mode, only force update + if (GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropertySet); + } + else + { + // set content (author, if that's the name) and current + // presentation + aAny <<= GetContent(); + + if (bFixed && bHasAuthor) + { + rPropertySet->setPropertyValue(sPropertyAuthor, aAny); + } + + if (bFixed && bHasContent) + { + rPropertySet->setPropertyValue(sPropertyContent, aAny); + } + + rPropertySet->setPropertyValue(sPropertyCurrentPresentation, aAny); + } +} + +OUString XMLSimpleDocInfoImportContext::MapTokenToServiceName( + sal_Int32 nElementToken) +{ + OUString pServiceName; + + switch(nElementToken) + { + case XML_ELEMENT(TEXT, XML_INITIAL_CREATOR): + pServiceName = "DocInfo.CreateAuthor"; + break; + case XML_ELEMENT(TEXT, XML_CREATION_DATE): + pServiceName = sAPI_docinfo_create_date_time; + break; + case XML_ELEMENT(TEXT, XML_CREATION_TIME): + pServiceName = sAPI_docinfo_create_date_time; + break; + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + pServiceName = "DocInfo.Description"; + break; + case XML_ELEMENT(TEXT, XML_EDITING_DURATION): + pServiceName = "DocInfo.EditTime"; + break; + case XML_ELEMENT(TEXT, XML_USER_DEFINED): + pServiceName = sAPI_docinfo_custom; + break; + case XML_ELEMENT(TEXT, XML_PRINTED_BY): + pServiceName = "DocInfo.PrintAuthor"; + break; + case XML_ELEMENT(TEXT, XML_PRINT_DATE): + pServiceName = sAPI_docinfo_print_date_time; + break; + case XML_ELEMENT(TEXT, XML_PRINT_TIME): + pServiceName = sAPI_docinfo_print_date_time; + break; + case XML_ELEMENT(TEXT, XML_KEYWORDS): + pServiceName = "DocInfo.KeyWords"; + break; + case XML_ELEMENT(TEXT, XML_SUBJECT): + pServiceName = "DocInfo.Subject"; + break; + case XML_ELEMENT(TEXT, XML_EDITING_CYCLES): + pServiceName = "DocInfo.Revision"; + break; + case XML_ELEMENT(TEXT, XML_CREATOR): + pServiceName = "DocInfo.ChangeAuthor"; + break; + case XML_ELEMENT(TEXT, XML_MODIFICATION_DATE): + pServiceName = sAPI_docinfo_change_date_time; + break; + case XML_ELEMENT(TEXT, XML_MODIFICATION_TIME): + pServiceName = sAPI_docinfo_change_date_time; + break; + case XML_ELEMENT(TEXT, XML_TITLE): + pServiceName = "DocInfo.Title"; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + assert(false); + } + + return pServiceName; +} + + +// revision field + +constexpr OUStringLiteral sPropertyRevision(u"Revision"); + +XMLRevisionDocInfoImportContext::XMLRevisionDocInfoImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, sal_Int32 nElement) : + XMLSimpleDocInfoImportContext(rImport, rHlp, nElement, false, false) +{ + bValid = true; +} + +void XMLRevisionDocInfoImportContext::PrepareField( + const Reference & rPropertySet) +{ + XMLSimpleDocInfoImportContext::PrepareField(rPropertySet); + + // set revision number + // if fixed, if not in organizer-mode, if not in styles-only-mode + if (!bFixed) + return; + + if ( GetImport().GetTextImport()->IsOrganizerMode() || + GetImport().GetTextImport()->IsStylesOnlyMode() ) + { + ForceUpdate(rPropertySet); + } + else + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber(nTmp, GetContent())) + { + rPropertySet->setPropertyValue(sPropertyRevision, Any(nTmp)); + } + } +} + + +// DocInfo fields with date/time attributes + + +XMLDateTimeDocInfoImportContext::XMLDateTimeDocInfoImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, sal_Int32 nElement) + : XMLSimpleDocInfoImportContext(rImport, rHlp, nElement, false, false) + , sPropertyNumberFormat(sAPI_number_format) + , sPropertyIsDate(sAPI_is_date) + , sPropertyIsFixedLanguage(sAPI_is_fixed_language) + , nFormat(0) + , bFormatOK(false) + , bIsDate(false) + , bHasDateTime(false) + , bIsDefaultLanguage(true) +{ + // we allow processing of EDIT_DURATION here, because import of actual + // is not supported anyway. If it was, we'd need an extra import class + // because times and time durations are presented differently! + + bValid = true; + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_CREATION_DATE): + case XML_ELEMENT(TEXT, XML_PRINT_DATE): + case XML_ELEMENT(TEXT, XML_MODIFICATION_DATE): + bIsDate = true; + bHasDateTime = true; + break; + case XML_ELEMENT(TEXT, XML_CREATION_TIME): + case XML_ELEMENT(TEXT, XML_PRINT_TIME): + case XML_ELEMENT(TEXT, XML_MODIFICATION_TIME): + bIsDate = false; + bHasDateTime = true; + break; + case XML_ELEMENT(TEXT, XML_EDITING_DURATION): + bIsDate = false; + bHasDateTime = false; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + OSL_FAIL("XMLDateTimeDocInfoImportContext needs date/time doc. fields"); + bValid = false; + break; + } +} + +void XMLDateTimeDocInfoImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + { + sal_Int32 nKey = GetImportHelper().GetDataStyleKey( + OUString::fromUtf8(sAttrValue), &bIsDefaultLanguage); + if (-1 != nKey) + { + nFormat = nKey; + bFormatOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_FIXED): + XMLSimpleDocInfoImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + default: + // ignore -> we can't set date/time value anyway! + break; + } +} + +void XMLDateTimeDocInfoImportContext::PrepareField( + const Reference & xPropertySet) +{ + // process fixed and presentation + XMLSimpleDocInfoImportContext::PrepareField(xPropertySet); + + if (bHasDateTime) + { + xPropertySet->setPropertyValue(sPropertyIsDate, Any(bIsDate)); + } + + if (bFormatOK) + { + xPropertySet->setPropertyValue(sPropertyNumberFormat, Any(nFormat)); + + if( xPropertySet->getPropertySetInfo()-> + hasPropertyByName( sPropertyIsFixedLanguage ) ) + { + bool bIsFixedLanguage = ! bIsDefaultLanguage; + xPropertySet->setPropertyValue( sPropertyIsFixedLanguage, Any(bIsFixedLanguage) ); + } + } + + // can't set date/time/duration value! Sorry. +} + + +// user defined docinfo fields + + +XMLUserDocInfoImportContext::XMLUserDocInfoImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nElement) : + XMLSimpleDocInfoImportContext(rImport, rHlp, nElement, false, false) + , sPropertyName(sAPI_name) + , sPropertyNumberFormat(sAPI_number_format) + , sPropertyIsFixedLanguage(sAPI_is_fixed_language) + , nFormat(0) + , bFormatOK(false) + , bIsDefaultLanguage( true ) +{ + bValid = false; +} + +void XMLUserDocInfoImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + { + sal_Int32 nKey = GetImportHelper().GetDataStyleKey( + OUString::fromUtf8(sAttrValue), &bIsDefaultLanguage); + if (-1 != nKey) + { + nFormat = nKey; + bFormatOK = true; + } + break; + } + case XML_ELEMENT(TEXT, XML_NAME): + { + if (!bValid) + { + SetServiceName(sAPI_docinfo_custom ); + aName = OUString::fromUtf8(sAttrValue); + bValid = true; + } + break; + } + + default: + XMLSimpleDocInfoImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + } +} + +void XMLUserDocInfoImportContext::PrepareField( + const css::uno::Reference & xPropertySet) +{ + if ( !aName.isEmpty() ) + { + xPropertySet->setPropertyValue(sPropertyName, Any(aName)); + } + Reference xPropertySetInfo( + xPropertySet->getPropertySetInfo()); + if (bFormatOK && + xPropertySetInfo->hasPropertyByName(sPropertyNumberFormat)) + { + xPropertySet->setPropertyValue(sPropertyNumberFormat, Any(nFormat)); + + if( xPropertySetInfo->hasPropertyByName( sPropertyIsFixedLanguage ) ) + { + bool bIsFixedLanguage = ! bIsDefaultLanguage; + xPropertySet->setPropertyValue( sPropertyIsFixedLanguage, Any(bIsFixedLanguage) ); + } + } + + // call superclass to handle "fixed" + XMLSimpleDocInfoImportContext::PrepareField(xPropertySet); +} + + +// import hidden paragraph fields + + +XMLHiddenParagraphImportContext::XMLHiddenParagraphImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "HiddenParagraph"), + sPropertyCondition(sAPI_condition), + sPropertyIsHidden(sAPI_is_hidden), + bIsHidden(false) +{ +} + +void XMLHiddenParagraphImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if ( XML_ELEMENT(TEXT, XML_CONDITION) == nAttrToken) + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrValueQName( + OUString::fromUtf8(sAttrValue), &sTmp ); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCondition = sTmp; + bValid = true; + } + else + sCondition = OUString::fromUtf8(sAttrValue); + } + else if ( XML_ELEMENT(TEXT, XML_IS_HIDDEN) == nAttrToken) + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bIsHidden = bTmp; + } + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLHiddenParagraphImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertyCondition, Any(sCondition)); + xPropertySet->setPropertyValue(sPropertyIsHidden, Any(bIsHidden)); +} + + +// import conditional text () + +constexpr OUStringLiteral gsPropertyTrueContent(u"TrueContent"); +constexpr OUStringLiteral gsPropertyFalseContent(u"FalseContent"); +constexpr OUStringLiteral gsPropertyIsConditionTrue(u"IsConditionTrue"); + +XMLConditionalTextImportContext::XMLConditionalTextImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "ConditionalText"), + sPropertyCondition(sAPI_condition), + sPropertyCurrentPresentation(sAPI_current_presentation), + bConditionOK(false), + bTrueOK(false), + bFalseOK(false), + bCurrentValue(false) +{ +} + +void XMLConditionalTextImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_CONDITION): + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). + GetKeyByAttrValueQName(OUString::fromUtf8(sAttrValue), &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCondition = sTmp; + bConditionOK = true; + } + else + sCondition = OUString::fromUtf8(sAttrValue); + } + break; + case XML_ELEMENT(TEXT, XML_STRING_VALUE_IF_FALSE): + sFalseContent = OUString::fromUtf8(sAttrValue); + bFalseOK = true; + break; + case XML_ELEMENT(TEXT, XML_STRING_VALUE_IF_TRUE): + sTrueContent = OUString::fromUtf8(sAttrValue); + bTrueOK = true; + break; + case XML_ELEMENT(TEXT, XML_CURRENT_VALUE): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bCurrentValue = bTmp; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } + + bValid = bConditionOK && bFalseOK && bTrueOK; +} + +void XMLConditionalTextImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertyCondition, Any(sCondition)); + xPropertySet->setPropertyValue(gsPropertyFalseContent, Any(sFalseContent)); + xPropertySet->setPropertyValue(gsPropertyTrueContent, Any(sTrueContent)); + xPropertySet->setPropertyValue(gsPropertyIsConditionTrue, Any(bCurrentValue)); + xPropertySet->setPropertyValue(sPropertyCurrentPresentation, Any(GetContent())); +} + + +// hidden text + + +XMLHiddenTextImportContext::XMLHiddenTextImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "HiddenText"), + sPropertyCondition(sAPI_condition), + sPropertyContent(sAPI_content), + sPropertyIsHidden(sAPI_is_hidden), + bConditionOK(false), + bStringOK(false), + bIsHidden(false) +{ +} + +void XMLHiddenTextImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_CONDITION): + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). + GetKeyByAttrValueQName(OUString::fromUtf8(sAttrValue), &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sCondition = sTmp; + bConditionOK = true; + } + else + sCondition = OUString::fromUtf8(sAttrValue); + } + break; + case XML_ELEMENT(TEXT, XML_STRING_VALUE): + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + sString = OUString::fromUtf8(sAttrValue); + bStringOK = true; + break; + case XML_ELEMENT(TEXT, XML_IS_HIDDEN): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bIsHidden = bTmp; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } + + bValid = bConditionOK && bStringOK; +} + +void XMLHiddenTextImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertyCondition, Any(sCondition)); + xPropertySet->setPropertyValue(sPropertyContent, Any(sString)); + xPropertySet->setPropertyValue(sPropertyIsHidden, Any(bIsHidden)); +} + + +// file name fields + + +const SvXMLEnumMapEntry aFilenameDisplayMap[] = +{ + { XML_PATH, FilenameDisplayFormat::PATH }, + { XML_NAME, FilenameDisplayFormat::NAME }, + { XML_NAME_AND_EXTENSION, FilenameDisplayFormat::NAME_AND_EXT }, + { XML_FULL, FilenameDisplayFormat::FULL }, + { XML_TOKEN_INVALID, 0 } +}; + +XMLFileNameImportContext::XMLFileNameImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "FileName"), + sPropertyFixed(sAPI_is_fixed), + sPropertyFileFormat(sAPI_file_format), + sPropertyCurrentPresentation( + sAPI_current_presentation), + nFormat(FilenameDisplayFormat::FULL), + bFixed(false) +{ + bValid = true; +} + +void XMLFileNameImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_FIXED): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bFixed = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_DISPLAY): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, sAttrValue, + aFilenameDisplayMap)) + { + nFormat = nTmp; + } + break; + } + default: + // unknown attribute: ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLFileNameImportContext::PrepareField( + const Reference & xPropertySet) +{ + // properties are optional + Reference xPropertySetInfo( + xPropertySet->getPropertySetInfo()); + + if (xPropertySetInfo->hasPropertyByName(sPropertyFixed)) + { + xPropertySet->setPropertyValue(sPropertyFixed, Any(bFixed)); + } + + if (xPropertySetInfo->hasPropertyByName(sPropertyFileFormat)) + { + xPropertySet->setPropertyValue(sPropertyFileFormat, Any(nFormat)); + } + + if (xPropertySetInfo->hasPropertyByName(sPropertyCurrentPresentation)) + { + xPropertySet->setPropertyValue(sPropertyCurrentPresentation, Any(GetContent())); + } +} + + +// template name field + + +const SvXMLEnumMapEntry aTemplateDisplayMap[] = +{ + { XML_FULL, TemplateDisplayFormat::FULL }, + { XML_PATH, TemplateDisplayFormat::PATH }, + { XML_NAME, TemplateDisplayFormat::NAME }, + { XML_NAME_AND_EXTENSION, TemplateDisplayFormat::NAME_AND_EXT }, + { XML_AREA, TemplateDisplayFormat::AREA }, + { XML_TITLE, TemplateDisplayFormat::TITLE }, + { XML_TOKEN_INVALID, 0 } +}; + + +XMLTemplateNameImportContext::XMLTemplateNameImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "TemplateName"), + sPropertyFileFormat(sAPI_file_format), + nFormat(TemplateDisplayFormat::FULL) +{ + bValid = true; +} + +void XMLTemplateNameImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DISPLAY): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, sAttrValue, + aTemplateDisplayMap)) + { + nFormat = nTmp; + } + break; + } + default: + // unknown attribute: ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLTemplateNameImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(sPropertyFileFormat, Any(nFormat)); +} + + +// import chapter fields + + +const SvXMLEnumMapEntry aChapterDisplayMap[] = +{ + { XML_NAME, ChapterFormat::NAME }, + { XML_NUMBER, ChapterFormat::NUMBER }, + { XML_NUMBER_AND_NAME, ChapterFormat::NAME_NUMBER }, + { XML_PLAIN_NUMBER_AND_NAME, ChapterFormat::NO_PREFIX_SUFFIX }, + { XML_PLAIN_NUMBER, ChapterFormat::DIGIT }, + { XML_TOKEN_INVALID, 0 } +}; + +constexpr OUStringLiteral gsPropertyChapterFormat(u"ChapterFormat"); +constexpr OUStringLiteral gsPropertyLevel(u"Level"); + +XMLChapterImportContext::XMLChapterImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "Chapter"), + nFormat(ChapterFormat::NAME_NUMBER), + nLevel(0) +{ + bValid = true; +} + +void XMLChapterImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DISPLAY): + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum(nTmp, sAttrValue, + aChapterDisplayMap)) + { + nFormat = static_cast(nTmp); + } + break; + } + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( + nTmp, sAttrValue, 1, + GetImport().GetTextImport()->GetChapterNumbering()->getCount() + )) + { + // API numbers 0..9, we number 1..10 + nLevel = static_cast(nTmp); + nLevel--; + } + break; + } + default: + // unknown attribute: ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLChapterImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(gsPropertyChapterFormat, Any(nFormat)); + xPropertySet->setPropertyValue(gsPropertyLevel, Any(nLevel)); +} + + +// counting fields + + +XMLCountFieldImportContext::XMLCountFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nElement) : + XMLTextFieldImportContext(rImport, rHlp, MapTokenToServiceName(nElement)), + sPropertyNumberingType( + sAPI_numbering_type), + bNumberFormatOK(false) +{ + bValid = true; +} + +void XMLCountFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumberFormat = OUString::fromUtf8(sAttrValue); + bNumberFormatOK = true; + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sLetterSync = OUString::fromUtf8(sAttrValue); + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLCountFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + // properties optional + // (only page count, but do for all to save common implementation) + + if (!xPropertySet->getPropertySetInfo()-> + hasPropertyByName(sPropertyNumberingType)) + return; + + sal_Int16 nNumType; + if( bNumberFormatOK ) + { + nNumType= style::NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumberFormat, + sLetterSync ); + } + else + nNumType = style::NumberingType::PAGE_DESCRIPTOR; + xPropertySet->setPropertyValue(sPropertyNumberingType, Any(nNumType)); +} + +OUString XMLCountFieldImportContext::MapTokenToServiceName( + sal_Int32 nElement) +{ + OUString pServiceName; + + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_WORD_COUNT): + pServiceName = "WordCount"; + break; + case XML_ELEMENT(TEXT, XML_PARAGRAPH_COUNT): + pServiceName = "ParagraphCount"; + break; + case XML_ELEMENT(TEXT, XML_TABLE_COUNT): + pServiceName = "TableCount"; + break; + case XML_ELEMENT(TEXT, XML_CHARACTER_COUNT): + pServiceName = "CharacterCount"; + break; + case XML_ELEMENT(TEXT, XML_IMAGE_COUNT): + pServiceName = "GraphicObjectCount"; + break; + case XML_ELEMENT(TEXT, XML_OBJECT_COUNT): + pServiceName = "EmbeddedObjectCount"; + break; + case XML_ELEMENT(TEXT, XML_PAGE_COUNT): + pServiceName = "PageCount"; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + assert(false); + } + + return pServiceName; +} + + +// page variable import + + +XMLPageVarGetFieldImportContext::XMLPageVarGetFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "ReferencePageGet"), + bNumberFormatOK(false) +{ + bValid = true; +} + +void XMLPageVarGetFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumberFormat = OUString::fromUtf8(sAttrValue); + bNumberFormatOK = true; + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sLetterSync = OUString::fromUtf8(sAttrValue); + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLPageVarGetFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + sal_Int16 nNumType; + if( bNumberFormatOK ) + { + nNumType= style::NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, + sNumberFormat, + sLetterSync ); + } + else + nNumType = style::NumberingType::PAGE_DESCRIPTOR; + xPropertySet->setPropertyValue(sAPI_numbering_type, Any(nNumType)); + + // display old content (#96657#) + xPropertySet->setPropertyValue( sAPI_current_presentation, Any(GetContent()) ); +} + + +// page variable set fields + + +XMLPageVarSetFieldImportContext::XMLPageVarSetFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "ReferencePageSet"), + nAdjust(0), + bActive(true) +{ + bValid = true; +} + +void XMLPageVarSetFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_ACTIVE): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, sAttrValue)) + { + bActive = bTmp; + } + break; + } + case XML_ELEMENT(TEXT, XML_PAGE_ADJUST): + { + sal_Int32 nTmp(0); + if (::sax::Converter::convertNumber(nTmp, sAttrValue)) + { + nAdjust = static_cast(nTmp); + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLPageVarSetFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue("On", Any(bActive)); + xPropertySet->setPropertyValue(sAPI_offset, Any(nAdjust)); +} + + +// macro fields + + +XMLMacroFieldImportContext::XMLMacroFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "Macro"), + bDescriptionOK(false) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLMacroFieldImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + // create events context and remember it! + xEventContext = new XMLEventsImportContext( GetImport() ); + bValid = true; + return xEventContext; + } + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +void XMLMacroFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + sDescription = OUString::fromUtf8(sAttrValue); + bDescriptionOK = true; + break; + case XML_ELEMENT(TEXT, XML_NAME): + sMacro = OUString::fromUtf8(sAttrValue); + bValid = true; + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLMacroFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + Any aAny; + aAny <<= (bDescriptionOK ? sDescription : GetContent()); + xPropertySet->setPropertyValue(sAPI_hint, aAny); + + // if we have an events child element, we'll look for the OnClick + // event if not, it may be an old (pre-638i) document. Then, we'll + // have to look at the name attribute. + OUString sMacroName; + OUString sLibraryName; + OUString sScriptURL; + + if ( xEventContext.is() ) + { + // get event sequence + XMLEventsImportContext* pEvents = xEventContext.get(); + Sequence aValues; + pEvents->GetEventSequence( "OnClick", aValues ); + + for( const auto& rValue : std::as_const(aValues) ) + { + if ( rValue.Name == "ScriptType" ) + { + // ignore ScriptType + } + else if ( rValue.Name == "Library" ) + { + rValue.Value >>= sLibraryName; + } + else if ( rValue.Name == "MacroName" ) + { + rValue.Value >>= sMacroName; + } + if ( rValue.Name == "Script" ) + { + rValue.Value >>= sScriptURL; + } + } + } + else + { + // disassemble old-style macro-name: Everything before the + // third-last dot is the library + sal_Int32 nPos = sMacro.getLength() + 1; // the loop starts with nPos-- + const sal_Unicode* pBuf = sMacro.getStr(); + for( sal_Int32 i = 0; (i < 3) && (nPos > 0); i++ ) + { + nPos--; + while ( (pBuf[nPos] != '.') && (nPos > 0) ) + nPos--; + } + + if (nPos > 0) + { + sLibraryName = sMacro.copy(0, nPos); + sMacroName = sMacro.copy(nPos+1); + } + else + sMacroName = sMacro; + } + + xPropertySet->setPropertyValue("ScriptURL", Any(sScriptURL)); + xPropertySet->setPropertyValue("MacroName", Any(sMacroName)); + xPropertySet->setPropertyValue("MacroLibrary", Any(sLibraryName)); +} + + +// reference field import + + +XMLReferenceFieldImportContext::XMLReferenceFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nToken) +: XMLTextFieldImportContext(rImport, rHlp, "GetReference") +, nElementToken(nToken) +, nSource(0) +, nType(ReferenceFieldPart::PAGE_DESC) +, bNameOK(false) +, bTypeOK(false) +{ +} + +SvXMLEnumMapEntry const lcl_aReferenceTypeTokenMap[] = +{ + { XML_PAGE, ReferenceFieldPart::PAGE}, + { XML_CHAPTER, ReferenceFieldPart::CHAPTER }, + { XML_TEXT, ReferenceFieldPart::TEXT }, + { XML_DIRECTION, ReferenceFieldPart::UP_DOWN }, + { XML_CATEGORY_AND_VALUE, ReferenceFieldPart::CATEGORY_AND_NUMBER }, + { XML_CAPTION, ReferenceFieldPart::ONLY_CAPTION }, + { XML_VALUE, ReferenceFieldPart::ONLY_SEQUENCE_NUMBER }, + // Core implementation for direct cross-references (#i81002#) + { XML_NUMBER, ReferenceFieldPart::NUMBER }, + { XML_NUMBER_NO_SUPERIOR, ReferenceFieldPart::NUMBER_NO_CONTEXT }, + { XML_NUMBER_ALL_SUPERIOR, ReferenceFieldPart::NUMBER_FULL_CONTEXT }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLReferenceFieldImportContext::startFastElement( + sal_Int32 nElement, + const Reference & xAttrList) +{ + bTypeOK = true; + switch (nElementToken) + { + case XML_ELEMENT(TEXT, XML_REFERENCE_REF): + nSource = ReferenceFieldSource::REFERENCE_MARK; + break; + case XML_ELEMENT(TEXT, XML_BOOKMARK_REF): + nSource = ReferenceFieldSource::BOOKMARK; + break; + case XML_ELEMENT(TEXT, XML_NOTE_REF): + nSource = ReferenceFieldSource::FOOTNOTE; + break; + case XML_ELEMENT(TEXT, XML_SEQUENCE_REF): + nSource = ReferenceFieldSource::SEQUENCE_FIELD; + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + bTypeOK = false; + break; + } + + XMLTextFieldImportContext::startFastElement(nElement, xAttrList); +} + + +void XMLReferenceFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_NOTE_CLASS): + if( IsXMLToken( sAttrValue, XML_ENDNOTE ) ) + nSource = ReferenceFieldSource::ENDNOTE; + break; + case XML_ELEMENT(TEXT, XML_REF_NAME): + sName = OUString::fromUtf8(sAttrValue); + bNameOK = true; + break; + case XML_ELEMENT(TEXT, XML_REFERENCE_FORMAT): + { + sal_uInt16 nToken; + if (SvXMLUnitConverter::convertEnum(nToken, sAttrValue, + lcl_aReferenceTypeTokenMap)) + { + nType = nToken; + } + + // check for sequence-only-attributes + if ( (XML_ELEMENT(TEXT, XML_SEQUENCE_REF) != nElementToken) && + ( (nType == ReferenceFieldPart::CATEGORY_AND_NUMBER) || + (nType == ReferenceFieldPart::ONLY_CAPTION) || + (nType == ReferenceFieldPart::ONLY_SEQUENCE_NUMBER) ) ) + { + nType = ReferenceFieldPart::PAGE_DESC; + } + + break; + } + case XML_ELEMENT(LO_EXT, XML_REFERENCE_LANGUAGE): + case XML_ELEMENT(TEXT, XML_REFERENCE_LANGUAGE): + sLanguage = OUString::fromUtf8(sAttrValue); + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } + + // bValid: we need proper element type and name + bValid = bTypeOK && bNameOK; +} + +void XMLReferenceFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue("ReferenceFieldPart", Any(nType)); + + xPropertySet->setPropertyValue("ReferenceFieldSource", Any(nSource)); + + xPropertySet->setPropertyValue("ReferenceFieldLanguage", Any(sLanguage)); + switch (nElementToken) + { + case XML_ELEMENT(TEXT, XML_REFERENCE_REF): + case XML_ELEMENT(TEXT, XML_BOOKMARK_REF): + xPropertySet->setPropertyValue("SourceName", Any(sName)); + break; + + case XML_ELEMENT(TEXT, XML_NOTE_REF): + GetImportHelper().ProcessFootnoteReference(sName, xPropertySet); + break; + + case XML_ELEMENT(TEXT, XML_SEQUENCE_REF): + GetImportHelper().ProcessSequenceReference(sName, xPropertySet); + break; + } + + xPropertySet->setPropertyValue(sAPI_current_presentation, Any(GetContent())); +} + + +// field declarations container + +XMLDdeFieldDeclsImportContext::XMLDdeFieldDeclsImportContext(SvXMLImport& rImport) : + SvXMLImportContext(rImport) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLDdeFieldDeclsImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + if ( nElement == XML_ELEMENT(TEXT, XML_DDE_CONNECTION_DECL) ) + { + return new XMLDdeFieldDeclImportContext(GetImport()); + } + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return nullptr; +} + + +// import dde field declaration + + +XMLDdeFieldDeclImportContext::XMLDdeFieldDeclImportContext(SvXMLImport& rImport) +: SvXMLImportContext(rImport) +{ +} + +void XMLDdeFieldDeclImportContext::startFastElement( + sal_Int32 /*nElement*/, + const Reference & xAttrList) +{ + OUString sName; + OUString sCommandApplication; + OUString sCommandTopic; + OUString sCommandItem; + + bool bUpdate = false; + bool bNameOK = false; + bool bCommandApplicationOK = false; + bool bCommandTopicOK = false; + bool bCommandItemOK = false; + + // process attributes + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(OFFICE, XML_NAME): + sName = aIter.toString(); + bNameOK = true; + break; + case XML_ELEMENT(OFFICE, XML_DDE_APPLICATION): + sCommandApplication = aIter.toString(); + bCommandApplicationOK = true; + break; + case XML_ELEMENT(OFFICE, XML_DDE_TOPIC): + sCommandTopic = aIter.toString(); + bCommandTopicOK = true; + break; + case XML_ELEMENT(OFFICE, XML_DDE_ITEM): + sCommandItem = aIter.toString(); + bCommandItemOK = true; + break; + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_UPDATE): + { + bool bTmp(false); + if (::sax::Converter::convertBool(bTmp, aIter.toView()) ) + { + bUpdate = bTmp; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + // valid data? + if (!(bNameOK && bCommandApplicationOK && bCommandTopicOK && bCommandItemOK)) + return; + + // create DDE TextFieldMaster + Reference xFactory(GetImport().GetModel(), + UNO_QUERY); + if( !xFactory.is() ) + return; + + /* #i6432# There might be multiple occurrences of one DDE + declaration if it is used in more than one of + header/footer/body. createInstance will throw an exception if we + try to create the second, third, etc. instance of such a + declaration. Thus we ignore the exception. Otherwise this will + lead to an unloadable document. */ + try + { + Reference xIfc = + xFactory->createInstance(OUString::Concat(sAPI_fieldmaster_prefix) + sAPI_dde); + if( xIfc.is() ) + { + Reference xPropSet( xIfc, UNO_QUERY ); + if (xPropSet.is() && + xPropSet->getPropertySetInfo()->hasPropertyByName( + "DDECommandType")) + { + xPropSet->setPropertyValue(sAPI_name, Any(sName)); + + xPropSet->setPropertyValue("DDECommandType", Any(sCommandApplication)); + + xPropSet->setPropertyValue("DDECommandFile", Any(sCommandTopic)); + + xPropSet->setPropertyValue("DDECommandElement", + Any(sCommandItem)); + + xPropSet->setPropertyValue("IsAutomaticUpdate", + Any(bUpdate)); + } + // else: ignore (can't get XPropertySet, or DDE + // properties are not supported) + } + // else: ignore + } + catch (const Exception&) + { + //ignore + } + // else: ignore + // else: ignore +} + + +// DDE field import + + +XMLDdeFieldImportContext::XMLDdeFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, sAPI_dde), + sPropertyContent(sAPI_content) +{ +} + +void XMLDdeFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if ( XML_ELEMENT(TEXT, XML_CONNECTION_NAME) == nAttrToken) + { + sName = OUString::fromUtf8(sAttrValue); + bValid = true; + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + + +void XMLDdeFieldImportContext::endFastElement(sal_Int32 ) +{ + if (!bValid) + return; + + // find master + OUString sMasterName = OUString::Concat(sAPI_fieldmaster_prefix) + sAPI_dde + "." + sName; + + Reference xTextFieldsSupp(GetImport().GetModel(), + UNO_QUERY); + Reference xFieldMasterNameAccess = + xTextFieldsSupp->getTextFieldMasters(); + + if (!xFieldMasterNameAccess->hasByName(sMasterName)) + return; + + Reference xMaster; + Any aAny = xFieldMasterNameAccess->getByName(sMasterName); + aAny >>= xMaster; + //apply the content to the master + xMaster->setPropertyValue( sPropertyContent, uno::Any( GetContent())); + // master exists: create text field and attach + Reference xField; + OUString sFieldName = OUString::Concat(sAPI_textfield_prefix) + sAPI_dde; + if (!CreateField(xField, sFieldName)) + return; + + Reference xDepTextField(xField,UNO_QUERY); + xDepTextField->attachTextFieldMaster(xMaster); + + // attach field to document + Reference xTextContent(xField, UNO_QUERY); + if (xTextContent.is()) + { + GetImportHelper().InsertTextContent(xTextContent); + + // we're lucky. nothing else to prepare. + } + // else: fail, because text content could not be created + // else: fail, because field could not be created + // else: fail, because no master was found (faulty document?!) + // not valid: ignore +} + +void XMLDdeFieldImportContext::PrepareField( + const Reference &) +{ + // empty, since not needed. +} + + +// sheet name fields + + +XMLSheetNameImportContext::XMLSheetNameImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "SheetName") +{ + bValid = true; // always valid! +} + +void XMLSheetNameImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue) +{ + // no attributes -> nothing to be done + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLSheetNameImportContext::PrepareField( + const Reference &) +{ + // no attributes -> nothing to be done +} + +/** import page|slide name fields () */ + +XMLPageNameFieldImportContext::XMLPageNameFieldImportContext( + SvXMLImport& rImport, /// XML Import + XMLTextImportHelper& rHlp) /// Text import helper +: XMLTextFieldImportContext(rImport, rHlp, "PageName" ) +{ + bValid = true; +} + +/// process attribute values +void XMLPageNameFieldImportContext::ProcessAttribute( sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +/// prepare XTextField for insertion into document +void XMLPageNameFieldImportContext::PrepareField( + const css::uno::Reference &) +{ +} + + +// URL fields (Calc, Impress, Draw) + + +XMLUrlFieldImportContext::XMLUrlFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, sAPI_url), + bFrameOK(false) +{ +} + +void XMLUrlFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(XLINK, XML_HREF): + sURL = GetImport().GetAbsoluteReference( OUString::fromUtf8(sAttrValue) ); + bValid = true; + break; + case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME): + sFrame = OUString::fromUtf8(sAttrValue); + bFrameOK = true; + break; + default: + // ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLUrlFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(sAPI_url, Any(sURL)); + + if (bFrameOK) + { + xPropertySet->setPropertyValue("TargetFrame", Any(sFrame)); + } + + xPropertySet->setPropertyValue("Representation", Any(GetContent())); +} + + +XMLBibliographyFieldImportContext::XMLBibliographyFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "Bibliography") +{ + bValid = true; +} + +// TODO: this is the same map as is used in the text field export +SvXMLEnumMapEntry const aBibliographyDataTypeMap[] = +{ + { XML_ARTICLE, BibliographyDataType::ARTICLE }, + { XML_BOOK, BibliographyDataType::BOOK }, + { XML_BOOKLET, BibliographyDataType::BOOKLET }, + { XML_CONFERENCE, BibliographyDataType::CONFERENCE }, + { XML_CUSTOM1, BibliographyDataType::CUSTOM1 }, + { XML_CUSTOM2, BibliographyDataType::CUSTOM2 }, + { XML_CUSTOM3, BibliographyDataType::CUSTOM3 }, + { XML_CUSTOM4, BibliographyDataType::CUSTOM4 }, + { XML_CUSTOM5, BibliographyDataType::CUSTOM5 }, + { XML_EMAIL, BibliographyDataType::EMAIL }, + { XML_INBOOK, BibliographyDataType::INBOOK }, + { XML_INCOLLECTION, BibliographyDataType::INCOLLECTION }, + { XML_INPROCEEDINGS, BibliographyDataType::INPROCEEDINGS }, + { XML_JOURNAL, BibliographyDataType::JOURNAL }, + { XML_MANUAL, BibliographyDataType::MANUAL }, + { XML_MASTERSTHESIS, BibliographyDataType::MASTERSTHESIS }, + { XML_MISC, BibliographyDataType::MISC }, + { XML_PHDTHESIS, BibliographyDataType::PHDTHESIS }, + { XML_PROCEEDINGS, BibliographyDataType::PROCEEDINGS }, + { XML_TECHREPORT, BibliographyDataType::TECHREPORT }, + { XML_UNPUBLISHED, BibliographyDataType::UNPUBLISHED }, + { XML_WWW, BibliographyDataType::WWW }, + { XML_TOKEN_INVALID, 0 } +}; + + +// we'll process attributes on our own and for fit the standard +// textfield mechanism, because our attributes have zero overlap with +// all the other textfields. +void XMLBibliographyFieldImportContext::startFastElement( + sal_Int32 /*nElement*/, + const Reference & xAttrList) +{ + // iterate over attributes + for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) ) + { + if (IsTokenInNamespace(aIter.getToken(), XML_NAMESPACE_TEXT) + || IsTokenInNamespace(aIter.getToken(), XML_NAMESPACE_LO_EXT)) + { + auto nToken = aIter.getToken() & TOKEN_MASK; + PropertyValue aValue; + aValue.Name = OUString::createFromAscii( + MapBibliographyFieldName(nToken)); + Any aAny; + + // special treatment for bibliography type + // biblio vs bibilio: #96658#; also read old documents + if (nToken == XML_BIBILIOGRAPHIC_TYPE || + nToken == XML_BIBLIOGRAPHY_TYPE ) + { + sal_uInt16 nTmp; + if (SvXMLUnitConverter::convertEnum( + nTmp, aIter.toView(), + aBibliographyDataTypeMap)) + { + aAny <<= static_cast(nTmp); + aValue.Value = aAny; + + aValues.push_back(aValue); + } + } + else + { + OUString aStringValue = aIter.toString(); + if (nToken == XML_URL || nToken == XML_LOCAL_URL) + { + aStringValue = GetImport().GetAbsoluteReference(aStringValue); + } + aAny <<= aStringValue; + aValue.Value = aAny; + + aValues.push_back(aValue); + } + } + // else: unknown namespace -> ignore + } +} + +void XMLBibliographyFieldImportContext::ProcessAttribute( + sal_Int32 , + std::string_view ) +{ + // attributes are handled in StartElement + assert(false && "This should not have happened."); +} + + +void XMLBibliographyFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + // convert vector into sequence + sal_Int32 nCount = aValues.size(); + Sequence aValueSequence(nCount); + auto aValueSequenceRange = asNonConstRange(aValueSequence); + for(sal_Int32 i = 0; i < nCount; i++) + { + aValueSequenceRange[i] = aValues[i]; + } + + // set sequence + xPropertySet->setPropertyValue("Fields", Any(aValueSequence)); +} + +const char* XMLBibliographyFieldImportContext::MapBibliographyFieldName( + sal_Int32 nElement) +{ + const char* pName = nullptr; + + switch (nElement & TOKEN_MASK) + { + case XML_IDENTIFIER: + pName = "Identifier"; + break; + case XML_BIBILIOGRAPHIC_TYPE: + case XML_BIBLIOGRAPHY_TYPE: + // biblio... vs bibilio...: #96658#: also read old documents + pName = "BibiliographicType"; + break; + case XML_ADDRESS: + pName = "Address"; + break; + case XML_ANNOTE: + pName = "Annote"; + break; + case XML_AUTHOR: + pName = "Author"; + break; + case XML_BOOKTITLE: + pName = "Booktitle"; + break; + case XML_CHAPTER: + pName = "Chapter"; + break; + case XML_EDITION: + pName = "Edition"; + break; + case XML_EDITOR: + pName = "Editor"; + break; + case XML_HOWPUBLISHED: + pName = "Howpublished"; + break; + case XML_INSTITUTION: + pName = "Institution"; + break; + case XML_JOURNAL: + pName = "Journal"; + break; + case XML_MONTH: + pName = "Month"; + break; + case XML_NOTE: + pName = "Note"; + break; + case XML_NUMBER: + pName = "Number"; + break; + case XML_ORGANIZATIONS: + pName = "Organizations"; + break; + case XML_PAGES: + pName = "Pages"; + break; + case XML_PUBLISHER: + pName = "Publisher"; + break; + case XML_SCHOOL: + pName = "School"; + break; + case XML_SERIES: + pName = "Series"; + break; + case XML_TITLE: + pName = "Title"; + break; + case XML_REPORT_TYPE: + pName = "Report_Type"; + break; + case XML_VOLUME: + pName = "Volume"; + break; + case XML_YEAR: + pName = "Year"; + break; + case XML_URL: + pName = "URL"; + break; + case XML_CUSTOM1: + pName = "Custom1"; + break; + case XML_CUSTOM2: + pName = "Custom2"; + break; + case XML_CUSTOM3: + pName = "Custom3"; + break; + case XML_CUSTOM4: + pName = "Custom4"; + break; + case XML_CUSTOM5: + pName = "Custom5"; + break; + case XML_ISBN: + pName = "ISBN"; + break; + case XML_LOCAL_URL: + pName = "LocalURL"; + break; + default: + assert(false && "Unknown bibliography info data"); + pName = nullptr; + } + return pName; +} + +// Annotation Field + + +XMLAnnotationImportContext::XMLAnnotationImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp, + sal_Int32 nElement) : + XMLTextFieldImportContext(rImport, rHlp, "Annotation"), + mnElement(nElement) +{ + bValid = true; + + // remember old list item and block (#91964#) and reset them + // for the text frame + // do this in the constructor, not in CreateChildContext (#i93392#) + GetImport().GetTextImport()->PushListContext(); +} + +void XMLAnnotationImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if (nAttrToken == XML_ELEMENT(OFFICE, XML_NAME)) + aName = OUString::fromUtf8(sAttrValue); + else if (nAttrToken == XML_ELEMENT(LO_EXT, XML_RESOLVED)) + aResolved = OUString::fromUtf8(sAttrValue); + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLAnnotationImportContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + if( nElement == XML_ELEMENT(DC, XML_CREATOR) ) + return new XMLStringBufferImportContext(GetImport(), aAuthorBuffer); + else if( nElement == XML_ELEMENT(DC, XML_DATE) ) + return new XMLStringBufferImportContext(GetImport(), aDateBuffer); + else if (nElement == XML_ELEMENT(TEXT,XML_SENDER_INITIALS) || + nElement == XML_ELEMENT(LO_EXT, XML_SENDER_INITIALS) || + nElement == XML_ELEMENT(META, XML_CREATOR_INITIALS)) + return new XMLStringBufferImportContext(GetImport(), aInitialsBuffer); + + try + { + bool bOK = true; + if ( !mxField.is() ) + bOK = CreateField( mxField, sServicePrefix + GetServiceName() ); + if (bOK) + { + Any aAny = mxField->getPropertyValue( "TextRange" ); + Reference< XText > xText; + aAny >>= xText; + if( xText.is() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport = GetImport().GetTextImport(); + if( !mxCursor.is() ) + { + mxOldCursor = xTxtImport->GetCursor(); + mxCursor = xText->createTextCursor(); + } + + if( mxCursor.is() ) + { + xTxtImport->SetCursor( mxCursor ); + return xTxtImport->CreateTextChildContext( GetImport(), nElement, xAttrList ); + } + } + } + } + catch (const Exception&) + { + } + + return new XMLStringBufferImportContext(GetImport(), aTextBuffer); +} + +void XMLAnnotationImportContext::endFastElement(sal_Int32 /*nElement*/) +{ + DBG_ASSERT(!GetServiceName().isEmpty(), "no service name for element!"); + if( mxCursor.is() ) + { + // delete addition newline + mxCursor->gotoEnd( false ); + mxCursor->goLeft( 1, true ); + mxCursor->setString( "" ); + + // reset cursor + GetImport().GetTextImport()->ResetCursor(); + } + + if( mxOldCursor.is() ) + GetImport().GetTextImport()->SetCursor( mxOldCursor ); + + // reinstall old list item #91964# + GetImport().GetTextImport()->PopListContext(); + + if ( bValid ) + { + if ( mnElement == XML_ELEMENT(OFFICE, XML_ANNOTATION_END) ) + { + // Search for a previous annotation with the same name. + uno::Reference< text::XTextContent > xPrevField; + { + Reference xTextFieldsSupplier(GetImport().GetModel(), UNO_QUERY); + uno::Reference xFieldsAccess(xTextFieldsSupplier->getTextFields()); + uno::Reference xFields(xFieldsAccess->createEnumeration()); + while (xFields->hasMoreElements()) + { + uno::Reference xCurrField(xFields->nextElement(), uno::UNO_QUERY); + uno::Reference const xInfo( + xCurrField->getPropertySetInfo()); + if (xInfo->hasPropertyByName(sAPI_name)) + { + OUString aFieldName; + xCurrField->getPropertyValue(sAPI_name) >>= aFieldName; + if (aFieldName == aName) + { + xPrevField.set( xCurrField, uno::UNO_QUERY ); + break; + } + } + } + } + if ( xPrevField.is() ) + { + // So we are ending a previous annotation, + // let's create a text range covering the old and the current position. + uno::Reference xText = GetImportHelper().GetText(); + uno::Reference xCursor = + xText->createTextCursorByRange(GetImportHelper().GetCursorAsRange()); + try + { + xCursor->gotoRange(xPrevField->getAnchor(), true); + } + catch (const uno::RuntimeException&) + { + // Losing the start of the anchor is better than not opening the document at + // all. + TOOLS_WARN_EXCEPTION( + "xmloff.text", + "XMLAnnotationImportContext::endFastElement: gotoRange() failed: "); + } + + xText->insertTextContent(xCursor, xPrevField, !xCursor->isCollapsed()); + } + } + else + { + if ( mxField.is() || CreateField( mxField, sServicePrefix + GetServiceName() ) ) + { + // set field properties + PrepareField( mxField ); + + // attach field to document + Reference < XTextContent > xTextContent( mxField, UNO_QUERY ); + + // workaround for #80606# + try + { + GetImportHelper().InsertTextContent( xTextContent ); + } + catch (const lang::IllegalArgumentException&) + { + // ignore + } + } + } + } + else + GetImportHelper().InsertString(GetContent()); +} + +void XMLAnnotationImportContext::PrepareField( + const Reference & xPropertySet ) +{ + // import (possibly empty) author + OUString sAuthor( aAuthorBuffer.makeStringAndClear() ); + xPropertySet->setPropertyValue(sAPI_author, Any(sAuthor)); + + // import (possibly empty) initials + OUString sInitials( aInitialsBuffer.makeStringAndClear() ); + xPropertySet->setPropertyValue("Initials", Any(sInitials)); + + //import resolved flag + bool bTmp(false); + (void)::sax::Converter::convertBool(bTmp, aResolved); + xPropertySet->setPropertyValue("Resolved", Any(bTmp)); + + util::DateTime aDateTime; + if (::sax::Converter::parseDateTime(aDateTime, aDateBuffer)) + { + /* + Date aDate; + aDate.Year = aDateTime.Year; + aDate.Month = aDateTime.Month; + aDate.Day = aDateTime.Day; + xPropertySet->setPropertyValue(sPropertyDate, makeAny(aDate)); + */ + // why is there no UNO_NAME_DATE_TIME, but only UNO_NAME_DATE_TIME_VALUE? + xPropertySet->setPropertyValue(sAPI_date_time_value, Any(aDateTime)); + } + aDateBuffer.setLength(0); + + OUString sBuffer = aTextBuffer.makeStringAndClear(); + if ( sBuffer.getLength() ) + { + // delete last paragraph mark (if necessary) + if (char(0x0a) == sBuffer[sBuffer.getLength()-1]) + sBuffer = sBuffer.copy(0, sBuffer.getLength()-1); + xPropertySet->setPropertyValue(sAPI_content, Any(sBuffer)); + } + + if (!aName.isEmpty()) + xPropertySet->setPropertyValue(sAPI_name, Any(aName)); +} + + +// script field + + +XMLScriptImportContext::XMLScriptImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) +: XMLTextFieldImportContext(rImport, rHlp, "Script") +, bContentOK(false) +{ +} + +void XMLScriptImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(XLINK, XML_HREF): + sContent = GetImport().GetAbsoluteReference( OUString::fromUtf8(sAttrValue) ); + bContentOK = true; + break; + + case XML_ELEMENT(SCRIPT, XML_LANGUAGE): + sScriptType = OUString::fromUtf8(sAttrValue); + break; + + default: + // ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } + + // always valid (even without ScriptType; cf- #96531#) + bValid = true; +} + +void XMLScriptImportContext::PrepareField( + const Reference & xPropertySet) +{ + // if href attribute was present, we use it. Else we use element content + if (! bContentOK) + { + sContent = GetContent(); + } + xPropertySet->setPropertyValue(sAPI_content, Any(sContent)); + + // URL or script text? We use URL if we have an href-attribute + xPropertySet->setPropertyValue("URLContent", Any(bContentOK)); + + xPropertySet->setPropertyValue("ScriptType", Any(sScriptType)); +} + + +// measure field + + +XMLMeasureFieldImportContext::XMLMeasureFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "Measure"), + mnKind( 0 ) +{ +} + +void XMLMeasureFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_KIND): + if( IsXMLToken( sAttrValue, XML_VALUE ) ) + { + mnKind = 0; bValid = true; + } + else if( IsXMLToken( sAttrValue, XML_UNIT ) ) + { + mnKind = 1; bValid = true; + } + else if( IsXMLToken( sAttrValue, XML_GAP ) ) + { + mnKind = 2; bValid = true; + } + break; + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } +} + +void XMLMeasureFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue("Kind", Any(mnKind)); +} + + +// dropdown field + + +XMLDropDownFieldImportContext::XMLDropDownFieldImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext( rImport, rHlp, "DropDown" ), + nSelected( -1 ), + bNameOK( false ), + bHelpOK(false), + bHintOK(false) +{ + bValid = true; +} + +static bool lcl_ProcessLabel( + const Reference& xAttrList, + OUString& rLabel, + bool& rIsSelected ) +{ + bool bValid = false; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_VALUE): + { + rLabel = aIter.toString(); + bValid = true; + break; + } + case XML_ELEMENT(TEXT, XML_CURRENT_SELECTED): + { + bool bTmp(false); + if (::sax::Converter::convertBool( bTmp, aIter.toView() )) + rIsSelected = bTmp; + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + return bValid; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLDropDownFieldImportContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(TEXT, XML_LABEL) ) + { + OUString sLabel; + bool bIsSelected = false; + if( lcl_ProcessLabel( xAttrList, sLabel, bIsSelected ) ) + { + if( bIsSelected ) + nSelected = static_cast( aLabels.size() ); + aLabels.push_back( sLabel ); + } + } + return new SvXMLImportContext( GetImport() ); +} + +void XMLDropDownFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + if( nAttrToken == XML_ELEMENT(TEXT, XML_NAME)) + { + sName = OUString::fromUtf8(sAttrValue); + bNameOK = true; + } + else if (nAttrToken == XML_ELEMENT(TEXT, XML_HELP)) + { + sHelp = OUString::fromUtf8(sAttrValue); + bHelpOK = true; + } + else if (nAttrToken == XML_ELEMENT(TEXT, XML_HINT)) + { + sHint = OUString::fromUtf8(sAttrValue); + bHintOK = true; + } + else + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +void XMLDropDownFieldImportContext::PrepareField( + const Reference& xPropertySet) +{ + // create sequence + sal_Int32 nLength = static_cast( aLabels.size() ); + Sequence aSequence( nLength ); + OUString* pSequence = aSequence.getArray(); + for( sal_Int32 n = 0; n < nLength; n++ ) + pSequence[n] = aLabels[n]; + + // now set values: + + xPropertySet->setPropertyValue( "Items", Any(aSequence) ); + + if( nSelected >= 0 && nSelected < nLength ) + { + xPropertySet->setPropertyValue( "SelectedItem", Any(pSequence[nSelected]) ); + } + + // set name + if( bNameOK ) + { + xPropertySet->setPropertyValue( "Name", Any(sName) ); + } + // set help + if( bHelpOK ) + { + xPropertySet->setPropertyValue( "Help", Any(sHelp) ); + } + // set hint + if( bHintOK ) + { + xPropertySet->setPropertyValue( "Tooltip", Any(sHint) ); + } + +} + +/** import header fields () */ + +XMLHeaderFieldImportContext::XMLHeaderFieldImportContext( + SvXMLImport& rImport, /// XML Import + XMLTextImportHelper& rHlp) /// Text import helper +: XMLTextFieldImportContext(rImport, rHlp, "Header" ) +{ + sServicePrefix = sAPI_presentation_prefix; + bValid = true; +} + +/// process attribute values +void XMLHeaderFieldImportContext::ProcessAttribute( sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +/// prepare XTextField for insertion into document +void XMLHeaderFieldImportContext::PrepareField(const Reference &) +{ +} + +/** import footer fields () */ + +XMLFooterFieldImportContext::XMLFooterFieldImportContext( + SvXMLImport& rImport, /// XML Import + XMLTextImportHelper& rHlp) /// Text import helper +: XMLTextFieldImportContext(rImport, rHlp, "Footer" ) +{ + sServicePrefix = sAPI_presentation_prefix; + bValid = true; +} + +/// process attribute values +void XMLFooterFieldImportContext::ProcessAttribute( sal_Int32 nAttrToken, std::string_view sAttrValue) +{ + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +/// prepare XTextField for insertion into document +void XMLFooterFieldImportContext::PrepareField(const Reference &) +{ +} + + +/** import footer fields () */ + +XMLDateTimeFieldImportContext::XMLDateTimeFieldImportContext( + SvXMLImport& rImport, /// XML Import + XMLTextImportHelper& rHlp) /// Text import helper +: XMLTextFieldImportContext(rImport, rHlp, "DateTime" ) +{ + sServicePrefix = sAPI_presentation_prefix; + bValid = true; +} + +/// process attribute values +void XMLDateTimeFieldImportContext::ProcessAttribute( sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); +} + +/// prepare XTextField for insertion into document +void XMLDateTimeFieldImportContext::PrepareField( + const css::uno::Reference< + css::beans::XPropertySet> &) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtftne.cxx b/xmloff/source/text/txtftne.cxx new file mode 100644 index 000000000..333ec7c6f --- /dev/null +++ b/xmloff/source/text/txtftne.cxx @@ -0,0 +1,344 @@ +/* -*- 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 . + */ + + +/** @#file + * + * This file implements XMLTextParagraphExport methods to export + * - footnotes + * - endnotes + * - footnote configuration elements + * - endnote configuration elements + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "XMLTextCharStyleNamesElementExport.hxx" +#include +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::container; +using namespace ::xmloff::token; + + +void XMLTextParagraphExport::exportTextFootnote( + const Reference & rPropSet, + const OUString& rText, + bool bAutoStyles, bool bIsProgress ) +{ + // get footnote and associated text + Any aAny = rPropSet->getPropertyValue(gsFootnote); + Reference xFootnote; + aAny >>= xFootnote; + Reference xText(xFootnote, UNO_QUERY); + + // are we an endnote? + Reference xServiceInfo( xFootnote, UNO_QUERY ); + bool bIsEndnote = xServiceInfo->supportsService(gsTextEndnoteService); + + if (bAutoStyles) + { + // handle formatting of citation mark + Add( XmlStyleFamily::TEXT_TEXT, rPropSet ); + + // handle formatting within footnote + exportTextFootnoteHelper(xFootnote, xText, rText, + bAutoStyles, bIsEndnote, bIsProgress ); + } + else + { + // create span (for citation mark) if necessary; footnote content + // will be handled via exportTextFootnoteHelper, exportText + bool bIsUICharStyle = false; + bool bHasAutoStyle = false; + + OUString sStyle = FindTextStyle( rPropSet, bIsUICharStyle, bHasAutoStyle ); + + { + XMLTextCharStyleNamesElementExport aCharStylesExport( + GetExport(), bIsUICharStyle && + aCharStyleNamesPropInfoCache.hasProperty( + rPropSet ), bHasAutoStyle, + rPropSet, gsCharStyleNames ); + if( !sStyle.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyle ) ); + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_SPAN, false, false ); + exportTextFootnoteHelper(xFootnote, xText, rText, + bAutoStyles, bIsEndnote, bIsProgress ); + } + else + { + exportTextFootnoteHelper(xFootnote, xText, rText, + bAutoStyles, bIsEndnote, bIsProgress ); + } + } + } +} + + +void XMLTextParagraphExport::exportTextFootnoteHelper( + const Reference & rFootnote, + const Reference & rText, + const OUString& rTextString, + bool bAutoStyles, + bool bIsEndnote, + bool bIsProgress ) +{ + if (bAutoStyles) + { + exportText(rText, bAutoStyles, bIsProgress, true ); + } + else + { + // export reference Id (for reference fields) + Reference xPropSet(rFootnote, UNO_QUERY); + Any aAny = xPropSet->getPropertyValue(gsReferenceId); + sal_Int32 nNumber = 0; + aAny >>= nNumber; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_ID, + "ftn" + OUString::number(nNumber)); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + GetXMLToken( bIsEndnote ? XML_ENDNOTE + : XML_FOOTNOTE ) ); + + SvXMLElementExport aNote(GetExport(), XML_NAMESPACE_TEXT, + XML_NOTE, false, false); + { + // handle label vs. automatic numbering + OUString sLabel = rFootnote->getLabel(); + if (!sLabel.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_LABEL, + sLabel); + } + // else: automatic numbering -> no attribute + + SvXMLElementExport aCite(GetExport(), XML_NAMESPACE_TEXT, + XML_NOTE_CITATION, false, false); + GetExport().Characters(rTextString); + } + + { + SvXMLElementExport aBody(GetExport(), XML_NAMESPACE_TEXT, + XML_NOTE_BODY, false, false); + exportText(rText, bAutoStyles, bIsProgress, true ); + } + } +} + + +void XMLTextParagraphExport::exportTextFootnoteConfiguration() +{ + // footnote settings + Reference aFootnotesSupplier(GetExport().GetModel(), + UNO_QUERY); + Reference aFootnoteConfiguration( + aFootnotesSupplier->getFootnoteSettings()); + exportTextFootnoteConfigurationHelper(aFootnoteConfiguration, false); + + // endnote settings + Reference aEndnotesSupplier(GetExport().GetModel(), + UNO_QUERY); + Reference aEndnoteConfiguration( + aEndnotesSupplier->getEndnoteSettings()); + exportTextFootnoteConfigurationHelper(aEndnoteConfiguration, true); +} + + +static void lcl_exportString( + SvXMLExport& rExport, + const Reference & rPropSet, + const OUString& sProperty, + sal_uInt16 nPrefix, + enum XMLTokenEnum eElement, + bool bEncodeName) +{ + SAL_WARN_IF( eElement == XML_TOKEN_INVALID, "xmloff", "need element token"); + + Any aAny = rPropSet->getPropertyValue(sProperty); + OUString sTmp; + aAny >>= sTmp; + if (!sTmp.isEmpty()) + { + if( bEncodeName ) + sTmp = rExport.EncodeStyleName( sTmp ); + rExport.AddAttribute(nPrefix, eElement, sTmp); + } +} + +void XMLTextParagraphExport::exportTextFootnoteConfigurationHelper( + const Reference & rFootnoteConfig, + bool bIsEndnote) +{ + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + GetXMLToken( bIsEndnote ? XML_ENDNOTE + : XML_FOOTNOTE ) ); + // default/paragraph style + lcl_exportString( GetExport(), rFootnoteConfig, + gsParaStyleName, + XML_NAMESPACE_TEXT, XML_DEFAULT_STYLE_NAME, + true); + + // citation style + lcl_exportString( GetExport(), rFootnoteConfig, + gsCharStyleName, + XML_NAMESPACE_TEXT, XML_CITATION_STYLE_NAME, + true); + + // citation body style + lcl_exportString( GetExport(), rFootnoteConfig, + gsAnchorCharStyleName, + XML_NAMESPACE_TEXT, XML_CITATION_BODY_STYLE_NAME, + true); + + // page style + lcl_exportString( GetExport(), rFootnoteConfig, + gsPageStyleName, + XML_NAMESPACE_TEXT, XML_MASTER_PAGE_NAME, + true ); + + // prefix + lcl_exportString( GetExport(), rFootnoteConfig, gsPrefix, + XML_NAMESPACE_STYLE, XML_NUM_PREFIX, false); + + // suffix + lcl_exportString( GetExport(), rFootnoteConfig, gsSuffix, + XML_NAMESPACE_STYLE, XML_NUM_SUFFIX, false); + + + Any aAny; + + // numbering style + OUStringBuffer sBuffer; + aAny = rFootnoteConfig->getPropertyValue(gsNumberingType); + sal_Int16 nNumbering = 0; + aAny >>= nNumbering; + GetExport().GetMM100UnitConverter().convertNumFormat( sBuffer, nNumbering); + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_FORMAT, + sBuffer.makeStringAndClear() ); + SvXMLUnitConverter::convertNumLetterSync( sBuffer, nNumbering); + if (!sBuffer.isEmpty() ) + { + GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_NUM_LETTER_SYNC, + sBuffer.makeStringAndClear()); + } + + // StartAt / start-value + aAny = rFootnoteConfig->getPropertyValue(gsStartAt); + sal_Int16 nOffset = 0; + aAny >>= nOffset; + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_START_VALUE, + OUString::number(nOffset)); + + // some properties are for footnotes only + if (!bIsEndnote) + { + // footnotes position + aAny = rFootnoteConfig->getPropertyValue( + gsPositionEndOfDoc); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_FOOTNOTES_POSITION, + ( (*o3tl::doAccess(aAny)) ? + XML_DOCUMENT : XML_PAGE ) ); + + aAny = rFootnoteConfig->getPropertyValue(gsFootnoteCounting); + sal_Int16 nTmp = 0; + aAny >>= nTmp; + enum XMLTokenEnum eElement; + switch (nTmp) + { + case FootnoteNumbering::PER_PAGE: + eElement = XML_PAGE; + break; + case FootnoteNumbering::PER_CHAPTER: + eElement = XML_CHAPTER; + break; + case FootnoteNumbering::PER_DOCUMENT: + default: + eElement = XML_DOCUMENT; + break; + } + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_START_NUMBERING_AT, eElement); + } + + // element + SvXMLElementExport aFootnoteConfigElement( + GetExport(), XML_NAMESPACE_TEXT, + XML_NOTES_CONFIGURATION, + true, true); + + // two element for footnote content + if (bIsEndnote) + return; + + OUString sTmp; + + // end notice / quo vadis + aAny = rFootnoteConfig->getPropertyValue(gsEndNotice); + aAny >>= sTmp; + + if (!sTmp.isEmpty()) + { + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_TEXT, + XML_FOOTNOTE_CONTINUATION_NOTICE_FORWARD, + true, false); + GetExport().Characters(sTmp); + } + + // begin notice / ergo sum + aAny = rFootnoteConfig->getPropertyValue(gsBeginNotice); + aAny >>= sTmp; + + if (!sTmp.isEmpty()) + { + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_TEXT, + XML_FOOTNOTE_CONTINUATION_NOTICE_BACKWARD, + true, false); + GetExport().Characters(sTmp); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtimp.cxx b/xmloff/source/text/txtimp.cxx new file mode 100644 index 000000000..aad6c61a7 --- /dev/null +++ b/xmloff/source/text/txtimp.cxx @@ -0,0 +1,2450 @@ +/* -*- 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "txtparai.hxx" +#include +#include +#include +#include +#include +#include "XMLTextListItemContext.hxx" +#include "XMLTextListBlockContext.hxx" +#include "XMLTextFrameContext.hxx" +#include "XMLTextFrameHyperlinkContext.hxx" +#include "XMLSectionImportContext.hxx" +#include "XMLIndexTOCContext.hxx" +#include +#include "XMLTrackedChangesImportContext.hxx" +#include "XMLChangeImportContext.hxx" +#include "XMLAutoMarkFileContext.hxx" +#include + +#include "XMLCalculationSettingsContext.hxx" +#include +#include +#include +#include +// XML import: reconstruction of assignment of paragraph style to outline levels (#i69629#) +#include +#include +#include +#include + +using ::com::sun::star::ucb::XAnyCompare; + +using namespace ::std; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::lang; +using namespace ::xmloff::token; +using namespace ::com::sun::star::ucb; + + +// maximum allowed length of combined characters field +#define MAX_COMBINED_CHARACTERS 6 + +struct XMLTextImportHelper::Impl +{ + std::optional< std::vector > m_xPrevFrmNames; + std::optional< std::vector > m_xNextFrmNames; + std::unique_ptr m_xTextListsHelper; + + rtl::Reference m_xAutoStyles; + + rtl::Reference< SvXMLImportPropertyMapper > m_xParaImpPrMap; + rtl::Reference< SvXMLImportPropertyMapper > m_xTextImpPrMap; + rtl::Reference< SvXMLImportPropertyMapper > m_xFrameImpPrMap; + rtl::Reference< SvXMLImportPropertyMapper > m_xSectionImpPrMap; + rtl::Reference< SvXMLImportPropertyMapper > m_xRubyImpPrMap; + + std::unique_ptr m_xRenameMap; + + /* Change and extend data structure: + - data structure contains candidates of paragraph styles, which + will be assigned to the outline style + - data structure contains more than one candidate for each list level + of the outline style (#i69629#) + */ + std::unique_ptr< std::vector< OUString > []> + m_xOutlineStylesCandidates; + + // start range, xml:id, RDFa stuff + typedef std::tuple< + uno::Reference, OUString, + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > > + BookmarkMapEntry_t; + /// start ranges for open bookmarks + std::map< OUString, BookmarkMapEntry_t > m_BookmarkStartRanges; + + std::vector< OUString > m_BookmarkVector; + + /// name of the last 'open' redline that started between paragraphs + OUString m_sOpenRedlineIdentifier; + + // Used for frame deduplication, the name of the last frame imported directly before the current one + OUString msLastImportedFrameName; + + std::map< OUString, bool > m_bBookmarkHidden; + std::map< OUString, OUString > m_sBookmarkCondition; + + uno::Reference m_xText; + uno::Reference m_xCursor; + uno::Reference m_xCursorAsRange; + uno::Reference m_xParaStyles; + uno::Reference m_xTextStyles; + uno::Reference m_xNumStyles; + uno::Reference m_xFrameStyles; + uno::Reference m_xPageStyles; + uno::Reference m_xCellStyles; + uno::Reference m_xChapterNumbering; + uno::Reference m_xTextFrames; + uno::Reference m_xGraphics; + uno::Reference m_xObjects; + uno::Reference m_xServiceFactory; + + SvXMLImport & m_rSvXMLImport; + + bool m_bInsertMode : 1; + bool m_bStylesOnlyMode : 1; + bool m_bBlockMode : 1; + bool m_bProgress : 1; + bool m_bOrganizerMode : 1; + bool m_bBodyContentStarted : 1; + + /// Are we inside a element (deleted redline section) + bool m_bInsideDeleteContext : 1; + + typedef ::std::pair< OUString, OUString> field_name_type_t; + typedef ::std::pair< OUString, OUString > field_param_t; + typedef ::std::vector< field_param_t > field_params_t; + typedef ::std::tuple, uno::Reference> field_stack_item_t; + typedef ::std::stack< field_stack_item_t > field_stack_t; + + field_stack_t m_FieldStack; + + OUString m_sCellParaStyleDefault; + + std::optional> m_xCrossRefHeadingBookmarkMap; + + Impl( uno::Reference const& rModel, + SvXMLImport & rImport, + bool const bInsertMode, bool const bStylesOnlyMode, + bool const bProgress, bool const bBlockMode, + bool const bOrganizerMode) + : m_xTextListsHelper( new XMLTextListsHelper() ) + // XML import: reconstruction of assignment of paragraph style to outline levels (#i69629#) + , m_xServiceFactory( rModel, UNO_QUERY ) + , m_rSvXMLImport( rImport ) + , m_bInsertMode( bInsertMode ) + , m_bStylesOnlyMode( bStylesOnlyMode ) + , m_bBlockMode( bBlockMode ) + , m_bProgress( bProgress ) + , m_bOrganizerMode( bOrganizerMode ) + , m_bBodyContentStarted( true ) + , m_bInsideDeleteContext( false ) + { + } + Impl(const Impl&) = delete; + Impl& operator=(const Impl&) = delete; + + void InitOutlineStylesCandidates() + { + if (!m_xOutlineStylesCandidates) + { + size_t const size(m_xChapterNumbering->getCount()); + m_xOutlineStylesCandidates.reset( + new ::std::vector< OUString >[size] ); + } + } + +}; + + +uno::Reference< text::XText > & XMLTextImportHelper::GetText() +{ + return m_xImpl->m_xText; +} + +uno::Reference< text::XTextCursor > & XMLTextImportHelper::GetCursor() +{ + return m_xImpl->m_xCursor; +} + +uno::Reference< text::XTextRange > & XMLTextImportHelper::GetCursorAsRange() +{ + return m_xImpl->m_xCursorAsRange; +} + +bool XMLTextImportHelper::IsInsertMode() const +{ + return m_xImpl->m_bInsertMode; +} + +bool XMLTextImportHelper::IsStylesOnlyMode() const +{ + return m_xImpl->m_bStylesOnlyMode; +} + +bool XMLTextImportHelper::IsBlockMode() const +{ + return m_xImpl->m_bBlockMode; +} + +bool XMLTextImportHelper::IsOrganizerMode() const +{ + return m_xImpl->m_bOrganizerMode; +} + +bool XMLTextImportHelper::IsProgress() const +{ + return m_xImpl->m_bProgress; +} + +uno::Reference const& +XMLTextImportHelper::GetParaStyles() const +{ + return m_xImpl->m_xParaStyles; +} + +uno::Reference const& +XMLTextImportHelper::GetTextStyles() const +{ + return m_xImpl->m_xTextStyles; +} + +uno::Reference const& +XMLTextImportHelper::GetNumberingStyles() const +{ + return m_xImpl->m_xNumStyles; +} + +uno::Reference const& +XMLTextImportHelper::GetFrameStyles() const +{ + return m_xImpl->m_xFrameStyles; +} + +uno::Reference const& +XMLTextImportHelper::GetPageStyles() const +{ + return m_xImpl->m_xPageStyles; +} + +uno::Reference const& +XMLTextImportHelper::GetCellStyles() const +{ + return m_xImpl->m_xCellStyles; +} + +uno::Reference const& +XMLTextImportHelper::GetChapterNumbering() const +{ + return m_xImpl->m_xChapterNumbering; +} + +rtl::Reference< SvXMLImportPropertyMapper > const& +XMLTextImportHelper::GetParaImportPropertySetMapper() const +{ + return m_xImpl->m_xParaImpPrMap; +} + +rtl::Reference< SvXMLImportPropertyMapper > const& +XMLTextImportHelper::GetTextImportPropertySetMapper() const +{ + return m_xImpl->m_xTextImpPrMap; +} + +rtl::Reference< SvXMLImportPropertyMapper > const& +XMLTextImportHelper::GetSectionImportPropertySetMapper() const +{ + return m_xImpl->m_xSectionImpPrMap; +} + +rtl::Reference< SvXMLImportPropertyMapper > const& +XMLTextImportHelper::GetRubyImportPropertySetMapper() const +{ + return m_xImpl->m_xRubyImpPrMap; +} + +void XMLTextImportHelper::SetInsideDeleteContext(bool const bNew) +{ + m_xImpl->m_bInsideDeleteContext = bNew; +} + +bool XMLTextImportHelper::IsInsideDeleteContext() const +{ + return m_xImpl->m_bInsideDeleteContext; +} + +SvXMLImport & XMLTextImportHelper::GetXMLImport() +{ + return m_xImpl->m_rSvXMLImport; +} + +XMLTextListsHelper & XMLTextImportHelper::GetTextListHelper() +{ + return *m_xImpl->m_xTextListsHelper; +} + +namespace +{ + class FieldParamImporter + { + public: + typedef pair field_param_t; + typedef vector field_params_t; + FieldParamImporter(const field_params_t* const pInParams, Reference const & xOutParams) + : m_pInParams(pInParams) + , m_xOutParams(xOutParams) + { }; + void Import(); + + private: + const field_params_t* const m_pInParams; + Reference m_xOutParams; + }; + + void FieldParamImporter::Import() + { + ::std::vector vListEntries; + ::std::map vOutParams; + for(const auto& rCurrent : *m_pInParams) + { + if(rCurrent.first == ODF_FORMDROPDOWN_RESULT) + { + // sal_Int32 + vOutParams[rCurrent.first] <<= rCurrent.second.toInt32(); + } + else if(rCurrent.first == ODF_FORMCHECKBOX_RESULT) + { + // bool + vOutParams[rCurrent.first] <<= rCurrent.second.toBoolean(); + } + else if(rCurrent.first == ODF_FORMDROPDOWN_LISTENTRY) + { + // sequence + vListEntries.push_back(rCurrent.second); + } + else + vOutParams[rCurrent.first] <<= rCurrent.second; + } + if(!vListEntries.empty()) + { + Sequence vListEntriesSeq(vListEntries.size()); + copy(vListEntries.begin(), vListEntries.end(), vListEntriesSeq.getArray()); + vOutParams[OUString(ODF_FORMDROPDOWN_LISTENTRY)] <<= vListEntriesSeq; + } + for(const auto& rCurrent : vOutParams) + { + try + { + m_xOutParams->insertByName(rCurrent.first, rCurrent.second); + } + catch(const ElementExistException&) + { + SAL_INFO("xmloff.text", "duplicate fieldmark param"); + } + } + } +} + +XMLTextImportHelper::XMLTextImportHelper( + uno::Reference const& rModel, + SvXMLImport& rImport, + bool const bInsertMode, bool const bStylesOnlyMode, + bool const bProgress, bool const bBlockMode, + bool const bOrganizerMode) + : m_xImpl( new Impl(rModel, rImport, bInsertMode, bStylesOnlyMode, + bProgress, bBlockMode, bOrganizerMode) ) + , m_xBackpatcherImpl( MakeBackpatcherImpl() ) +{ + static constexpr OUStringLiteral s_PropNameDefaultListId = u"DefaultListId"; + + Reference< XChapterNumberingSupplier > xCNSupplier( rModel, UNO_QUERY ); + + if (xCNSupplier.is()) + { + // note: m_xChapterNumbering is accessed to import some fields + m_xImpl->m_xChapterNumbering = xCNSupplier->getChapterNumberingRules(); + // the AutoCorrect document doesn't have a proper outline numbering + if (!IsBlockMode() && m_xImpl->m_xChapterNumbering.is()) + { + Reference< XPropertySet > const xNumRuleProps( + m_xImpl->m_xChapterNumbering, UNO_QUERY); + if ( xNumRuleProps.is() ) + { + Reference< XPropertySetInfo > xNumRulePropSetInfo( + xNumRuleProps->getPropertySetInfo()); + if (xNumRulePropSetInfo.is() && + xNumRulePropSetInfo->hasPropertyByName( + s_PropNameDefaultListId)) + { + OUString sListId; + xNumRuleProps->getPropertyValue(s_PropNameDefaultListId) + >>= sListId; + assert( !sListId.isEmpty() && + "no default list id found at chapter numbering rules instance. Serious defect." ); + if ( !sListId.isEmpty() ) + { + Reference< XNamed > const xChapterNumNamed( + m_xImpl->m_xChapterNumbering, UNO_QUERY); + if ( xChapterNumNamed.is() ) + { + m_xImpl->m_xTextListsHelper->KeepListAsProcessed( + sListId, + xChapterNumNamed->getName(), + OUString() ); + } + } + } + } + } + } + + Reference< XStyleFamiliesSupplier > xFamiliesSupp( rModel, UNO_QUERY ); +// SAL_WARN_IF( !xFamiliesSupp.is(), "xmloff", "no chapter numbering supplier" ); for clipboard there may be documents without styles + + if( xFamiliesSupp.is() ) + { + Reference< XNameAccess > xFamilies(xFamiliesSupp->getStyleFamilies()); + + static const OUStringLiteral aParaStyles(u"ParagraphStyles"); + if( xFamilies->hasByName( aParaStyles ) ) + { + m_xImpl->m_xParaStyles.set(xFamilies->getByName(aParaStyles), + UNO_QUERY); + } + + static const OUStringLiteral aCharStyles(u"CharacterStyles"); + if( xFamilies->hasByName( aCharStyles ) ) + { + m_xImpl->m_xTextStyles.set(xFamilies->getByName(aCharStyles), + UNO_QUERY); + } + + static const OUStringLiteral aNumStyles(u"NumberingStyles"); + if( xFamilies->hasByName( aNumStyles ) ) + { + m_xImpl->m_xNumStyles.set(xFamilies->getByName(aNumStyles), + UNO_QUERY); + } + + static const OUStringLiteral aFrameStyles(u"FrameStyles"); + if( xFamilies->hasByName( aFrameStyles ) ) + { + m_xImpl->m_xFrameStyles.set(xFamilies->getByName(aFrameStyles), + UNO_QUERY); + } + + static const OUStringLiteral aPageStyles(u"PageStyles"); + if( xFamilies->hasByName( aPageStyles ) ) + { + m_xImpl->m_xPageStyles.set(xFamilies->getByName(aPageStyles), + UNO_QUERY); + } + + static const OUStringLiteral aCellStyles(u"CellStyles"); + if( xFamilies->hasByName( aCellStyles ) ) + { + m_xImpl->m_xCellStyles.set(xFamilies->getByName(aCellStyles), + UNO_QUERY); + } + } + + Reference < XTextFramesSupplier > xTFS( rModel, UNO_QUERY ); + if( xTFS.is() ) + { + m_xImpl->m_xTextFrames.set(xTFS->getTextFrames()); + } + + Reference < XTextGraphicObjectsSupplier > xTGOS( rModel, UNO_QUERY ); + if( xTGOS.is() ) + { + m_xImpl->m_xGraphics.set(xTGOS->getGraphicObjects()); + } + + Reference < XTextEmbeddedObjectsSupplier > xTEOS( rModel, UNO_QUERY ); + if( xTEOS.is() ) + { + m_xImpl->m_xObjects.set(xTEOS->getEmbeddedObjects()); + } + + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::PARA, false ); + m_xImpl->m_xParaImpPrMap = + new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = new XMLTextPropertySetMapper( TextPropMap::TEXT, false ); + m_xImpl->m_xTextImpPrMap = + new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = new XMLTextPropertySetMapper( TextPropMap::FRAME, false ); + m_xImpl->m_xFrameImpPrMap = + new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = new XMLTextPropertySetMapper( TextPropMap::SECTION, false ); + m_xImpl->m_xSectionImpPrMap = + new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = new XMLTextPropertySetMapper( TextPropMap::RUBY, false ); + m_xImpl->m_xRubyImpPrMap = + new SvXMLImportPropertyMapper( pPropMapper, rImport ); +} + +XMLTextImportHelper::~XMLTextImportHelper() +{ +} + +void XMLTextImportHelper::dispose() +{ + if (m_xImpl->m_xAutoStyles) + m_xImpl->m_xAutoStyles->dispose(); +} + +SvXMLImportPropertyMapper *XMLTextImportHelper::CreateShapeExtPropMapper(SvXMLImport& rImport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::FRAME, false ); + return new XMLTextImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper *XMLTextImportHelper::CreateParaExtPropMapper(SvXMLImport& rImport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::SHAPE_PARA, false ); + return new XMLTextImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper *XMLTextImportHelper::CreateParaDefaultExtPropMapper(SvXMLImport& rImport) +{ + XMLPropertySetMapper* pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::SHAPE_PARA, false ); + SvXMLImportPropertyMapper* pImportMapper = new XMLTextImportPropertyMapper( pPropMapper, rImport ); + + pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TEXT_ADDITIONAL_DEFAULTS, false ); + pImportMapper->ChainImportMapper( new XMLTextImportPropertyMapper( pPropMapper, rImport ) ); + + return pImportMapper; +} + +SvXMLImportPropertyMapper* + XMLTextImportHelper::CreateTableDefaultExtPropMapper( + SvXMLImport& rImport ) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TABLE_DEFAULTS, false ); + return new SvXMLImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper* + XMLTextImportHelper::CreateTableRowDefaultExtPropMapper( + SvXMLImport& rImport ) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TABLE_ROW_DEFAULTS, false ); + return new SvXMLImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper* + XMLTextImportHelper::CreateTableCellExtPropMapper( + SvXMLImport& rImport ) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::CELL, false ); + return new XMLTextImportPropertyMapper( pPropMapper, rImport ); +} + +SvXMLImportPropertyMapper* +XMLTextImportHelper::CreateDrawingPageExtPropMapper(SvXMLImport& rImport) +{ + rtl::Reference const pFactory(new XMLPageMasterPropHdlFactory); + XMLPropertySetMapper *const pPropMapper( + new XMLPropertySetMapper(g_XMLPageMasterDrawingPageStyleMap, pFactory, false)); + return new SvXMLImportPropertyMapper(pPropMapper, rImport); +} + +void XMLTextImportHelper::SetCursor( const Reference < XTextCursor > & rCursor ) +{ + m_xImpl->m_xCursor.set(rCursor); + m_xImpl->m_xText.set(rCursor->getText()); + m_xImpl->m_xCursorAsRange = rCursor; +} + +void XMLTextImportHelper::ResetCursor() +{ + m_xImpl->m_xCursor.set(nullptr); + m_xImpl->m_xText.set(nullptr); + m_xImpl->m_xCursorAsRange.set(nullptr); +} + + +bool XMLTextImportHelper::HasFrameByName( const OUString& rName ) const +{ + return (m_xImpl->m_xTextFrames.is() && + m_xImpl->m_xTextFrames->hasByName(rName)) + || (m_xImpl->m_xGraphics.is() && + m_xImpl->m_xGraphics->hasByName(rName)) + || (m_xImpl->m_xObjects.is() && + m_xImpl->m_xObjects->hasByName(rName)); +} + +bool XMLTextImportHelper::IsDuplicateFrame(const OUString& sName, sal_Int32 nX, sal_Int32 nY, sal_Int32 nWidth, sal_Int32 nHeight) const +{ + if (HasFrameByName(sName)) + { + uno::Reference xOtherFrame; + if(m_xImpl->m_xTextFrames.is() && m_xImpl->m_xTextFrames->hasByName(sName)) + xOtherFrame.set(m_xImpl->m_xTextFrames->getByName(sName), uno::UNO_QUERY); + else if(m_xImpl->m_xGraphics.is() && m_xImpl->m_xGraphics->hasByName(sName)) + xOtherFrame.set(m_xImpl->m_xGraphics->getByName(sName), uno::UNO_QUERY); + else if (m_xImpl->m_xObjects.is() && m_xImpl->m_xObjects->hasByName(sName)) + xOtherFrame.set(m_xImpl->m_xObjects->getByName(sName), uno::UNO_QUERY); + + Reference< XPropertySetInfo > xPropSetInfo = xOtherFrame->getPropertySetInfo(); + if(xPropSetInfo->hasPropertyByName("Width")) + { + sal_Int32 nOtherWidth = 0; + xOtherFrame->getPropertyValue("Width") >>= nOtherWidth; + if(nWidth != nOtherWidth) + return false; + } + + if (xPropSetInfo->hasPropertyByName("Height")) + { + sal_Int32 nOtherHeight = 0; + xOtherFrame->getPropertyValue("Height") >>= nOtherHeight; + if (nHeight != nOtherHeight) + return false; + } + + if (xPropSetInfo->hasPropertyByName("HoriOrientPosition")) + { + sal_Int32 nOtherX = 0; + xOtherFrame->getPropertyValue("HoriOrientPosition") >>= nOtherX; + if (nX != nOtherX) + return false; + } + + if (xPropSetInfo->hasPropertyByName("VertOrientPosition")) + { + sal_Int32 nOtherY = 0; + xOtherFrame->getPropertyValue("VertOrientPosition") >>= nOtherY; + if (nY != nOtherY) + return false; + } + + // In some case, position is not defined for frames, so check whether the two frames follow each other (are anchored to the same position) + return m_xImpl->msLastImportedFrameName == sName; + } + return false; +} + +void XMLTextImportHelper::StoreLastImportedFrameName(const OUString& rName) +{ + m_xImpl->msLastImportedFrameName = rName; +} + +void XMLTextImportHelper::ClearLastImportedTextFrameName() +{ + m_xImpl->msLastImportedFrameName.clear(); +} + +void XMLTextImportHelper::InsertString( const OUString& rChars ) +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + if (m_xImpl->m_xText.is()) + { + m_xImpl->m_xText->insertString(m_xImpl->m_xCursorAsRange, + rChars, false); + } +} + +void XMLTextImportHelper::InsertString( const OUString& rChars, + bool& rIgnoreLeadingSpace ) +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + if (!m_xImpl->m_xText.is()) + return; + + sal_Int32 nLen = rChars.getLength(); + OUStringBuffer sChars( nLen ); + + for( sal_Int32 i=0; i < nLen; i++ ) + { + sal_Unicode c = rChars[i]; + switch( c ) + { + case 0x20: + case 0x09: + case 0x0a: + case 0x0d: + if( !rIgnoreLeadingSpace ) + sChars.append( u' ' ); + rIgnoreLeadingSpace = true; + break; + default: + rIgnoreLeadingSpace = false; + sChars.append( c ); + break; + } + } + m_xImpl->m_xText->insertString(m_xImpl->m_xCursorAsRange, + sChars.makeStringAndClear(), false); +} + +void XMLTextImportHelper::InsertControlCharacter( sal_Int16 nControl ) +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + if (m_xImpl->m_xText.is()) + { + m_xImpl->m_xText->insertControlCharacter( + m_xImpl->m_xCursorAsRange, nControl, false); + } +} + +void XMLTextImportHelper::InsertTextContent( + Reference < XTextContent > const & xContent ) +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + if (m_xImpl->m_xText.is()) + { + // note: this may throw IllegalArgumentException and callers handle it + m_xImpl->m_xText->insertTextContent( m_xImpl->m_xCursorAsRange, xContent, false); + } +} + +void XMLTextImportHelper::DeleteParagraph() +{ + assert(m_xImpl->m_xText.is()); + assert(m_xImpl->m_xCursor.is()); + assert(m_xImpl->m_xCursorAsRange.is()); + + bool bDelete = true; + Reference < XEnumerationAccess > const xEnumAccess( + m_xImpl->m_xCursor, UNO_QUERY); + if( xEnumAccess.is() ) + { + Reference < XEnumeration > xEnum(xEnumAccess->createEnumeration()); + SAL_WARN_IF(!xEnum->hasMoreElements(), "xmloff.text", + "empty text enumeration"); + if( xEnum->hasMoreElements() ) + { + Reference < XComponent > xComp( xEnum->nextElement(), UNO_QUERY ); + assert(xComp.is()); + if( xComp.is() ) + { + xComp->dispose(); + bDelete = false; + } + } + } + if( bDelete ) + { + if (m_xImpl->m_xCursor->goLeft( 1, true )) + { + m_xImpl->m_xText->insertString(m_xImpl->m_xCursorAsRange, + "", true); + } + } +} + +OUString XMLTextImportHelper::ConvertStarFonts( const OUString& rChars, + const OUString& rStyleName, + sal_uInt8& rFlags, + bool bPara, + SvXMLImport& rImport ) const +{ + OUStringBuffer sChars( rChars ); + bool bConverted = false; + for( sal_Int32 j=0; j= 0xf000 && c <= 0xf0ff ) + { + if( (rFlags & CONV_STAR_FONT_FLAGS_VALID) == 0 ) + { + XMLTextStyleContext *pStyle = nullptr; + XmlStyleFamily nFamily = bPara ? XmlStyleFamily::TEXT_PARAGRAPH + : XmlStyleFamily::TEXT_TEXT; + if (!rStyleName.isEmpty() && m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles-> + FindStyleChildContext( nFamily, rStyleName, + true ); + pStyle = const_cast( dynamic_cast< const XMLTextStyleContext* >(pTempStyle)); + } + + if( pStyle ) + { + sal_Int32 nCount = pStyle->GetProperties_().size(); + if( nCount ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + m_xImpl->m_xAutoStyles->GetImportPropertyMapper(nFamily); + if( xImpPrMap.is() ) + { + rtl::Reference rPropMapper = + xImpPrMap->getPropertySetMapper(); + for( sal_Int32 i=0; i < nCount; i++ ) + { + const XMLPropertyState& rProp = pStyle->GetProperties_()[i]; + sal_Int32 nIdx = rProp.mnIndex; + sal_uInt32 nContextId = rPropMapper->GetEntryContextId(nIdx); + if( CTF_FONTFAMILYNAME == nContextId ) + { + rFlags &= ~(CONV_FROM_STAR_BATS|CONV_FROM_STAR_MATH); + OUString sFontName; + rProp.maValue >>= sFontName; + if( sFontName.equalsIgnoreAsciiCase( "StarBats" ) ) + rFlags |= CONV_FROM_STAR_BATS; + else if( sFontName.equalsIgnoreAsciiCase( "StarMath" ) ) + rFlags |= CONV_FROM_STAR_MATH; + break; + } + } + } + } + + } + + rFlags |= CONV_STAR_FONT_FLAGS_VALID; + } + if( (rFlags & CONV_FROM_STAR_BATS ) != 0 ) + { + sChars[j] = rImport.ConvStarBatsCharToStarSymbol( c ); + bConverted = true; + } + else if( (rFlags & CONV_FROM_STAR_MATH ) != 0 ) + { + sChars[j] = rImport.ConvStarMathCharToStarSymbol( c ); + bConverted = true; + } + } + } + + return bConverted ? sChars.makeStringAndClear() : rChars; +} + +/* Helper method to determine, if a paragraph style has a list style (inclusive + an empty one) inherits a list style (inclusive an empty one) from one of its parents (#i69629#) +*/ +/* Apply special case, that found list style equals the chapter numbering, also + to the found list styles of the parent styles. (#i73973#) +*/ +static bool lcl_HasListStyle( const OUString& sStyleName, + const Reference < XNameContainer >& xParaStyles, + SvXMLImport const & rImport, + const OUString& sNumberingStyleName, + std::u16string_view sOutlineStyleName ) +{ + bool bRet( false ); + + if ( !xParaStyles->hasByName( sStyleName ) ) + { + // error case + return true; + } + + Reference< XPropertyState > xPropState( xParaStyles->getByName( sStyleName ), + UNO_QUERY ); + if ( !xPropState.is() ) + { + // error case + return false; + } + + if ( xPropState->getPropertyState( sNumberingStyleName ) == PropertyState_DIRECT_VALUE ) + { + // list style found + bRet = true; + // special case: the set list style equals the chapter numbering + Reference< XPropertySet > xPropSet( xPropState, UNO_QUERY ); + if ( xPropSet.is() ) + { + OUString sListStyle; + xPropSet->getPropertyValue( sNumberingStyleName ) >>= sListStyle; + if ( !sListStyle.isEmpty() && + sListStyle == sOutlineStyleName ) + { + bRet = false; + } + } + } + else + { + // Tools.Outline settings lost on Save (#i77708#) + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + // Don't use UPD for versioning: xmloff/source/text/txtstyli.cxx and txtimp.cxx (#i86058#) + const bool bBuildIdFound = rImport.getBuildIds( nUPD, nBuild ); + // search list style at parent + Reference xStyle( xPropState, UNO_QUERY ); + while ( xStyle.is() ) + { + OUString aParentStyle( xStyle->getParentStyle() ); + if ( !aParentStyle.isEmpty() ) + { + aParentStyle = + rImport.GetStyleDisplayName( XmlStyleFamily::TEXT_PARAGRAPH, + aParentStyle ); + } + if ( aParentStyle.isEmpty() || !xParaStyles->hasByName( aParentStyle ) ) + { + // no list style found + break; + } + else + { + xPropState.set( xParaStyles->getByName( aParentStyle ), + UNO_QUERY ); + if ( !xPropState.is() ) + { + // error case + return true; + } + if ( xPropState->getPropertyState( sNumberingStyleName ) == PropertyState_DIRECT_VALUE ) + { + // list style found + bRet = true; + // Special case: the found list style equals the chapter numbering (#i73973#) + Reference< XPropertySet > xPropSet( xPropState, UNO_QUERY ); + if ( xPropSet.is() ) + { + OUString sListStyle; + xPropSet->getPropertyValue( sNumberingStyleName ) >>= sListStyle; + if ( !sListStyle.isEmpty() && + sListStyle == sOutlineStyleName ) + { + bRet = false; + } + // Special handling for text documents from OOo version prior OOo 2.4 (#i77708#) + /* Check explicitly on certain versions and on import of + text documents in OpenOffice.org file format (#i86058#) + */ + else if ( sListStyle.isEmpty() && + ( rImport.IsTextDocInOOoFileFormat() || + ( bBuildIdFound && + ( ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0 + ( nUPD == 680 && nBuild <= 9238 ) ) ) ) ) // OOo 2.0 - OOo 2.3.1 + { + bRet = false; + } + } + break; + } + else + { + // search list style at parent + Reference xParentStyle(xPropState, UNO_QUERY); + if (xStyle == xParentStyle) + { + // error case + return true; + } + xStyle = xParentStyle; + } + } + } + } + + return bRet; +} +OUString XMLTextImportHelper::SetStyleAndAttrs( + SvXMLImport const & rImport, + const Reference < XTextCursor >& rCursor, + const OUString& rStyleName, + bool bPara, + bool bOutlineLevelAttrFound, + sal_Int8 nOutlineLevel, + // Numberings/Bullets in table not visible after save/reload (#i80724#) + bool bSetListAttrs, + bool bOutlineContentVisible) +{ + static constexpr OUStringLiteral s_NumberingRules = u"NumberingRules"; + static constexpr OUStringLiteral s_NumberingIsNumber = u"NumberingIsNumber"; + static constexpr OUStringLiteral s_NumberingLevel = u"NumberingLevel"; + static constexpr OUStringLiteral s_ParaIsNumberingRestart = u"ParaIsNumberingRestart"; + static constexpr OUStringLiteral s_NumberingStartValue = u"NumberingStartValue"; + static constexpr OUStringLiteral s_PropNameListId = u"ListId"; + static constexpr OUStringLiteral s_PageDescName = u"PageDescName"; + static constexpr OUStringLiteral s_OutlineLevel = u"OutlineLevel"; + + const XmlStyleFamily nFamily = bPara ? XmlStyleFamily::TEXT_PARAGRAPH + : XmlStyleFamily::TEXT_TEXT; + XMLTextStyleContext *pStyle = nullptr; + OUString sStyleName( rStyleName ); + if (!sStyleName.isEmpty() && m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( nFamily, sStyleName, true ); + pStyle = const_cast(dynamic_cast< const XMLTextStyleContext* >(pTempStyle)); + } + if( pStyle ) + sStyleName = pStyle->GetParentName(); + + Reference < XPropertySet > xPropSet( rCursor, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo( + xPropSet->getPropertySetInfo()); + + // style + if( !sStyleName.isEmpty() ) + { + sStyleName = rImport.GetStyleDisplayName( nFamily, sStyleName ); + const OUString rPropName = bPara ? OUString("ParaStyleName") : OUString("CharStyleName"); + const Reference < XNameContainer > & rStyles = bPara + ? m_xImpl->m_xParaStyles + : m_xImpl->m_xTextStyles; + if( rStyles.is() && + xPropSetInfo->hasPropertyByName( rPropName ) && + rStyles->hasByName( sStyleName ) ) + { + xPropSet->setPropertyValue( rPropName, Any(sStyleName) ); + } + else + sStyleName.clear(); + } + + /* The outline level needs to be only applied as list level, if the heading + is not inside a list and if it by default applies the outline style. (#i70748#) + */ + bool bApplyOutlineLevelAsListLevel( false ); + // Numberings/Bullets in table not visible after save/reload (#i80724#) + if (bSetListAttrs && bPara + && xPropSetInfo->hasPropertyByName( s_NumberingRules)) + { + // Set numbering rules + Reference< XIndexReplace > const xNumRules( + xPropSet->getPropertyValue(s_NumberingRules), UNO_QUERY); + + XMLTextListBlockContext * pListBlock(nullptr); + XMLTextListItemContext * pListItem(nullptr); + XMLNumberedParaContext * pNumberedParagraph(nullptr); + GetTextListHelper().ListContextTop( + pListBlock, pListItem, pNumberedParagraph); + + assert(!(pListBlock && pNumberedParagraph) && "XMLTextImportHelper::" + "SetStyleAndAttrs: both list and numbered-paragraph???"); + + Reference < XIndexReplace > xNewNumRules; + sal_Int8 nLevel(-1); + OUString sListId; + sal_Int16 nStartValue(-1); + bool bNumberingIsNumber(true); + + if (pListBlock) { + + if (!pListItem) { + bNumberingIsNumber = false; // list-header + } + // consider text:style-override property of + xNewNumRules.set( + (pListItem != nullptr && pListItem->HasNumRulesOverride()) + ? pListItem->GetNumRulesOverride() + : pListBlock->GetNumRules() ); + nLevel = static_cast(pListBlock->GetLevel()); + + if ( pListItem && pListItem->HasStartValue() ) { + nStartValue = pListItem->GetStartValue(); + } + + // Inconsistent behavior regarding lists (#i92811#) + sListId = m_xImpl->m_xTextListsHelper->GetListIdForListBlock( + *pListBlock); + } + else if (pNumberedParagraph) + { + xNewNumRules.set(pNumberedParagraph->GetNumRules()); + nLevel = static_cast(pNumberedParagraph->GetLevel()); + sListId = pNumberedParagraph->GetListId(); + nStartValue = pNumberedParagraph->GetStartValue(); + } + + + if (pListBlock || pNumberedParagraph) + { + // Assure that list style of automatic paragraph style is applied at paragraph. (#i101349#) + bool bApplyNumRules = pStyle && pStyle->IsListStyleSet(); + if ( !bApplyNumRules ) + { + bool bSameNumRules = xNewNumRules == xNumRules; + if( !bSameNumRules && xNewNumRules.is() && xNumRules.is() ) + { + // If the interface pointers are different, then this does + // not mean that the num rules are different. Further tests + // are required then. However, if only one num rule is + // set, no tests are required of course. + Reference< XNamed > xNewNamed( xNewNumRules, UNO_QUERY ); + Reference< XNamed > xNamed( xNumRules, UNO_QUERY ); + if( xNewNamed.is() && xNamed.is() ) + { + bSameNumRules = xNewNamed->getName() == xNamed->getName(); + } + else + { + Reference< XAnyCompare > xNumRuleCompare( xNumRules, UNO_QUERY ); + if( xNumRuleCompare.is() ) + { + bSameNumRules = (xNumRuleCompare->compare( Any(xNumRules), Any(xNewNumRules) ) == 0); + } + } + } + bApplyNumRules = !bSameNumRules; + } + + if ( bApplyNumRules ) + { + // #102607# This may except when xNewNumRules contains + // a Writer-NumRule-Implementation bug gets applied to + // a shape. Since this may occur inside a document + // (e.g. when edited), this must be handled + // gracefully. + try + { + xPropSet->setPropertyValue( + s_NumberingRules, Any(xNewNumRules) ); + } + catch(const Exception&) + { + ; // I would really like to use a warning here, + // but I can't access the XMLErrorHandler from + // here. + } + } + + if (!bNumberingIsNumber && + xPropSetInfo->hasPropertyByName(s_NumberingIsNumber)) + { + xPropSet->setPropertyValue(s_NumberingIsNumber, Any(false)); + } + + xPropSet->setPropertyValue( s_NumberingLevel, Any(nLevel) ); + + if( pListBlock && pListBlock->IsRestartNumbering() ) + { + // TODO: property missing + if (xPropSetInfo->hasPropertyByName(s_ParaIsNumberingRestart)) + { + xPropSet->setPropertyValue(s_ParaIsNumberingRestart, + Any(true) ); + } + pListBlock->ResetRestartNumbering(); + } + + if ( 0 <= nStartValue && + xPropSetInfo->hasPropertyByName(s_NumberingStartValue)) + { + xPropSet->setPropertyValue(s_NumberingStartValue, + Any(nStartValue)); + } + + if (xPropSetInfo->hasPropertyByName(s_PropNameListId)) + { + if (!sListId.isEmpty()) { + xPropSet->setPropertyValue(s_PropNameListId, + Any(sListId) ); + } + } + + GetTextListHelper().SetListItem( nullptr ); + } + else + { + /* If the paragraph is not in a list but its style, remove it from + the list. Do not remove it, if the list of the style is + the chapter numbering rule. + */ + if( xNumRules.is() ) + { + bool bRemove( true ); + // Special handling for document from OOo 2.x (#i70748#) + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = rImport.getBuildIds( nUPD, nBuild ); + if ( ( bBuildIdFound && nUPD == 680 ) || + !pStyle || !pStyle->IsListStyleSet() ) + { + if (m_xImpl->m_xChapterNumbering.is()) + { + Reference< XNamed > xNumNamed( xNumRules, UNO_QUERY ); + Reference< XNamed > const xChapterNumNamed ( + m_xImpl->m_xChapterNumbering, UNO_QUERY); + if ( xNumNamed.is() && xChapterNumNamed.is() && + xNumNamed->getName() == xChapterNumNamed->getName() ) + { + bRemove = false; + // RFE: inserting headings into text documents (#i70748#) + bApplyOutlineLevelAsListLevel = true; + } + } + } + else + { + SAL_INFO_IF(!pStyle->GetListStyle().isEmpty(), + "xmloff.text", + "automatic paragraph style with list style name, but paragraph not in list???"); + } + if ( bRemove ) + { + xPropSet->setPropertyValue( s_NumberingRules, Any() ); + } + } + } + } + + // hard paragraph properties + if( pStyle ) + { + pStyle->FillPropertySet( xPropSet ); + if( bPara && pStyle->HasMasterPageName() && + xPropSetInfo->hasPropertyByName(s_PageDescName)) + { + OUString sDisplayName( + rImport.GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, + pStyle->GetMasterPageName()) ); + if( sDisplayName.isEmpty() || + (m_xImpl->m_xPageStyles.is() && + m_xImpl->m_xPageStyles->hasByName( sDisplayName))) + { + xPropSet->setPropertyValue(s_PageDescName, + Any(sDisplayName)); + } + } + if( bPara && !pStyle->GetDropCapStyleName().isEmpty() && + m_xImpl->m_xTextStyles.is()) + { + OUString sDisplayName( + rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, + pStyle->GetDropCapStyleName()) ); + if (m_xImpl->m_xTextStyles->hasByName(sDisplayName) && + xPropSetInfo->hasPropertyByName("DropCapCharStyleName")) + { + xPropSet->setPropertyValue("DropCapCharStyleName", Any(sDisplayName)); + } + } + + // combined characters special treatment + if (!bPara && pStyle->HasCombinedCharactersLetter()) + { + // insert combined characters text field + if (m_xImpl->m_xServiceFactory.is()) + { + uno::Reference const xTmp( + m_xImpl->m_xServiceFactory->createInstance( + "com.sun.star.text.TextField.CombinedCharacters"), UNO_QUERY); + if( xTmp.is() ) + { + // fix cursor if larger than possible for + // combined characters field + if (rCursor->getString().getLength() > + MAX_COMBINED_CHARACTERS) + { + rCursor->gotoRange(rCursor->getStart(), false); + rCursor->goRight(MAX_COMBINED_CHARACTERS, true); + } + + // set field value (the combined character string) + xTmp->setPropertyValue("Content", + Any(rCursor->getString())); + + // insert the field over it's original text + Reference xTextContent(xTmp, UNO_QUERY); + if (m_xImpl->m_xText.is() && rCursor.is()) + { + // #i107225# the combined characters need to be inserted first + // the selected text has to be removed afterwards + m_xImpl->m_xText->insertTextContent( rCursor->getStart(), xTextContent, true ); + + if( !rCursor->getString().isEmpty() ) + { + try + { + uno::Reference< text::XTextCursor > xCrsr = rCursor->getText()->createTextCursorByRange( rCursor->getStart() ); + xCrsr->goLeft( 1, true ); + uno::Reference< beans::XPropertySet> xCrsrProperties( xCrsr, uno::UNO_QUERY_THROW ); + //the hard properties of the removed text need to be applied to the combined characters field + pStyle->FillPropertySet( xCrsrProperties ); + xCrsr->collapseToEnd(); + xCrsr->gotoRange( rCursor->getEnd(), true ); + xCrsr->setString( OUString() ); + } + catch(const uno::Exception&) + { + } + } + } + } + } + } + } + + // outline level; set after list style has been set + // Complete re-worked and corrected: (#i53198#) + // - set outline level at paragraph + // - set numbering level at paragraph, if none is already set + // - assure that style is marked as an outline style for the corresponding + // outline level. + // - DO NOT set type of numbering rule to outline. + // - DO NOT set numbering rule directly at the paragraph. + + // Some minor rework and adjust access to paragraph styles (#i70748#) + if ( bPara ) + { + // Headings not numbered anymore in 3.1 (#i103817#) + sal_Int16 nCurrentOutlineLevelInheritedFromParagraphStyle = 0; + const bool bHasOutlineLevelProp( + xPropSetInfo->hasPropertyByName(s_OutlineLevel)); + if ( bHasOutlineLevelProp ) + { + xPropSet->getPropertyValue(s_OutlineLevel) + >>= nCurrentOutlineLevelInheritedFromParagraphStyle; + } + if ( nOutlineLevel > 0 ) + { + if ( bHasOutlineLevelProp ) + { + // In case that the value equals the value of its paragraph style + // attribute outline level, the paragraph attribute value is left unset + if ( nCurrentOutlineLevelInheritedFromParagraphStyle != nOutlineLevel ) + { + xPropSet->setPropertyValue( s_OutlineLevel, + Any( static_cast(nOutlineLevel) ) ); + } + } + if (!bOutlineContentVisible) + { + uno::Sequence aGrabBag; + xPropSet->getPropertyValue("ParaInteropGrabBag") >>= aGrabBag; + sal_Int32 length = aGrabBag.getLength(); + aGrabBag.realloc(length + 1); + auto pGrabBag = aGrabBag.getArray(); + pGrabBag[length].Name = "OutlineContentVisibleAttr"; + pGrabBag[length].Value <<= bool(bOutlineContentVisible); + xPropSet->setPropertyValue("ParaInteropGrabBag", uno::Any(aGrabBag)); + } + // RFE: inserting headings into text documents (#i70748#) + if ( bApplyOutlineLevelAsListLevel ) + { + sal_Int16 nNumLevel = -1; + xPropSet->getPropertyValue( s_NumberingLevel ) >>= nNumLevel; + if ( nNumLevel == -1 || + nNumLevel != (nOutlineLevel - 1) ) + { + xPropSet->setPropertyValue( s_NumberingLevel, + Any( static_cast(nOutlineLevel - 1) ) ); + } + } + /* Correction: (#i69629#) + - for text document from version OOo 2.0.4/SO 8 PU4 and earlier + the paragraph style of a heading should be assigned to the + corresponding list level of the outline style. + - for other text documents the paragraph style of a heading is only + a candidate for an assignment to the list level of the outline + style, if it has no direct list style property and (if exists) the + automatic paragraph style has also no direct list style set. + */ + if (m_xImpl->m_xParaStyles.is() && m_xImpl->m_xParaStyles->hasByName(sStyleName)) + { + bool bOutlineStyleCandidate( false ); + + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = rImport.getBuildIds( nUPD, nBuild ); + // Lost outline numbering in master document (#i73509#) + // Check explicitly on certain versions (#i86058#) + if ( rImport.IsTextDocInOOoFileFormat() || + ( bBuildIdFound && + ( nUPD == 645 || nUPD == 641 ) ) ) + { + bOutlineStyleCandidate = true; + } + else if ( nUPD == 680 && nBuild <= 9073 ) /* BuildId of OOo 2.0.4/SO8 PU4 */ + { + bOutlineStyleCandidate = bOutlineLevelAttrFound; + } + if ( bOutlineStyleCandidate ) + { + AddOutlineStyleCandidate( nOutlineLevel, sStyleName ); + } + // Assure that heading applies the outline style (#i103817#) + if ( ( !pStyle || !pStyle->IsListStyleSet() ) && + !bOutlineStyleCandidate && + m_xImpl->m_xChapterNumbering.is()) + { + if ( !lcl_HasListStyle( sStyleName, + m_xImpl->m_xParaStyles, GetXMLImport(), + u"NumberingStyleName", + u"" ) ) + { + // heading not in a list --> apply outline style + xPropSet->setPropertyValue( s_NumberingRules, + Any(m_xImpl->m_xChapterNumbering) ); + xPropSet->setPropertyValue( s_NumberingLevel, + Any(static_cast(nOutlineLevel - 1))); + } + } + } + } + //handle for text:p,if the paragraphstyle outlinelevel is set to[1~10] + else if( bHasOutlineLevelProp ) + { + if ( nCurrentOutlineLevelInheritedFromParagraphStyle != 0 ) + { + xPropSet->setPropertyValue(s_OutlineLevel, + Any( sal_Int16(0) )); + } + } + } + + return sStyleName; +} + +void XMLTextImportHelper::FindOutlineStyleName( OUString& rStyleName, + sal_Int8 nOutlineLevel ) +{ + // style name empty? + if( !rStyleName.isEmpty() ) + return; + + // Empty? Then we need o do stuff. Let's do error checking first. + if (m_xImpl->m_xChapterNumbering.is() && + ( nOutlineLevel > 0 ) && + (nOutlineLevel <= m_xImpl->m_xChapterNumbering->getCount())) + { + nOutlineLevel--; // for the remainder, the level's are 0-based + + // empty style name: look-up previously used name + + // if we don't have a previously used name, we'll use the default + m_xImpl->InitOutlineStylesCandidates(); + if (m_xImpl->m_xOutlineStylesCandidates[nOutlineLevel].empty()) + { + // no other name used previously? Then use default + + // iterate over property value sequence to find the style name + Sequence aProperties; + m_xImpl->m_xChapterNumbering->getByIndex( nOutlineLevel ) + >>= aProperties; + auto pProp = std::find_if(std::cbegin(aProperties), std::cend(aProperties), + [](const PropertyValue& rProp) { return rProp.Name == "HeadingStyleName"; }); + if (pProp != std::cend(aProperties)) + { + OUString aOutlineStyle; + pProp->Value >>= aOutlineStyle; + m_xImpl->m_xOutlineStylesCandidates[nOutlineLevel] + .push_back( aOutlineStyle ); + } + } + + // finally, we'll use the previously used style name for this + // format (or the default we've just put into that style) + // take last added one (#i71249#) + rStyleName = + m_xImpl->m_xOutlineStylesCandidates[nOutlineLevel].back(); + } + // else: nothing we can do, so we'll leave it empty + // else: we already had a style name, so we let it pass. +} + +void XMLTextImportHelper::AddOutlineStyleCandidate( const sal_Int8 nOutlineLevel, + const OUString& rStyleName ) +{ + if (!rStyleName.isEmpty() + && m_xImpl->m_xChapterNumbering.is() + && (nOutlineLevel > 0) + && (nOutlineLevel <= m_xImpl->m_xChapterNumbering->getCount())) + { + m_xImpl->InitOutlineStylesCandidates(); + m_xImpl->m_xOutlineStylesCandidates[nOutlineLevel-1].push_back( + rStyleName); + } +} + +void XMLTextImportHelper::SetOutlineStyles( bool bSetEmptyLevels ) +{ + if (!(m_xImpl->m_xOutlineStylesCandidates != nullptr || bSetEmptyLevels) || + !m_xImpl->m_xChapterNumbering.is() || + IsInsertMode()) + return; + + bool bChooseLastOne( false ); + { + if ( GetXMLImport().IsTextDocInOOoFileFormat() ) + { + bChooseLastOne = true; + } + else + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + if ( GetXMLImport().getBuildIds( nUPD, nBuild ) ) + { + // check explicitly on certain versions + bChooseLastOne = ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0 + ( nUPD == 680 && nBuild <= 9073 ); // OOo 2.0 - OOo 2.0.4 + } + } + } + + OUString sOutlineStyleName; + { + Reference xChapterNumRule( + m_xImpl->m_xChapterNumbering, UNO_QUERY); + xChapterNumRule->getPropertyValue("Name") >>= sOutlineStyleName; + } + + const sal_Int32 nCount = m_xImpl->m_xChapterNumbering->getCount(); + /* First collect all paragraph styles chosen for assignment to each + list level of the outline style, then perform the intrinsic assignment. + Reason: The assignment of a certain paragraph style to a list level + of the outline style causes side effects on the children + paragraph styles in Writer. (#i106218#) + */ + ::std::vector sChosenStyles(nCount); + for( sal_Int32 i=0; i < nCount; ++i ) + { + if ( bSetEmptyLevels || + (m_xImpl->m_xOutlineStylesCandidates && + !m_xImpl->m_xOutlineStylesCandidates[i].empty())) + { + // determine, which candidate is one to be assigned to the list + // level of the outline style + if (m_xImpl->m_xOutlineStylesCandidates && + !m_xImpl->m_xOutlineStylesCandidates[i].empty()) + { + if ( bChooseLastOne ) + { + sChosenStyles[i] = + m_xImpl->m_xOutlineStylesCandidates[i].back(); + } + else + { + for (size_t j = 0; + j < m_xImpl->m_xOutlineStylesCandidates[i].size(); + ++j) + { + if (!lcl_HasListStyle( + m_xImpl->m_xOutlineStylesCandidates[i][j], + m_xImpl->m_xParaStyles, + GetXMLImport(), + "NumberingStyleName", + sOutlineStyleName)) + { + sChosenStyles[i] = + m_xImpl->m_xOutlineStylesCandidates[i][j]; + break; + } + } + } + } + } + } + // Trashed outline numbering in ODF 1.1 text document created by OOo 3.x (#i106218#) + Sequence < PropertyValue > aProps( 1 ); + PropertyValue *pProps = aProps.getArray(); + pProps->Name = "HeadingStyleName"; + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + // Paragraph style assignments in Outline of template lost from second level on (#i107610#) + if ( bSetEmptyLevels || !sChosenStyles[i].isEmpty() ) + { + pProps->Value <<= sChosenStyles[i]; + m_xImpl->m_xChapterNumbering->replaceByIndex(i, + Any( aProps )); + } + } + +} + +void XMLTextImportHelper::SetHyperlink( + SvXMLImport const & rImport, + const Reference < XTextCursor >& rCursor, + const OUString& rHRef, + const OUString& rName, + const OUString& rTargetFrameName, + const OUString& rStyleName, + const OUString& rVisitedStyleName, + XMLEventsImportContext* pEvents) +{ + static constexpr OUStringLiteral s_HyperLinkURL = u"HyperLinkURL"; + static constexpr OUStringLiteral s_HyperLinkName = u"HyperLinkName"; + static constexpr OUStringLiteral s_HyperLinkTarget = u"HyperLinkTarget"; + static constexpr OUStringLiteral s_UnvisitedCharStyleName = u"UnvisitedCharStyleName"; + static constexpr OUStringLiteral s_VisitedCharStyleName = u"VisitedCharStyleName"; + static constexpr OUStringLiteral s_HyperLinkEvents = u"HyperLinkEvents"; + + Reference < XPropertySet > xPropSet( rCursor, UNO_QUERY ); + Reference < XPropertySetInfo > xPropSetInfo( + xPropSet->getPropertySetInfo()); + if (!xPropSetInfo.is() || !xPropSetInfo->hasPropertyByName(s_HyperLinkURL)) + return; + + xPropSet->setPropertyValue(s_HyperLinkURL, Any(rHRef)); + + if (xPropSetInfo->hasPropertyByName(s_HyperLinkName)) + { + xPropSet->setPropertyValue(s_HyperLinkName, Any(rName)); + } + + if (xPropSetInfo->hasPropertyByName(s_HyperLinkTarget)) + { + xPropSet->setPropertyValue(s_HyperLinkTarget, + Any(rTargetFrameName)); + } + + if ( (pEvents != nullptr) && + xPropSetInfo->hasPropertyByName(s_HyperLinkEvents)) + { + // The API treats events at hyperlinks differently from most + // other properties: You have to set a name replace with the + // events in it. The easiest way to do this is to 1) get + // events, 2) set new ones, and 3) then put events back. + uno::Reference const xReplace( + xPropSet->getPropertyValue(s_HyperLinkEvents), UNO_QUERY); + if (xReplace.is()) + { + // set events + pEvents->SetEvents(xReplace); + + // put events + xPropSet->setPropertyValue(s_HyperLinkEvents, Any(xReplace)); + } + } + + if (!m_xImpl->m_xTextStyles.is()) + return; + + OUString sDisplayName( + rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, rStyleName ) ); + if( !sDisplayName.isEmpty() && + xPropSetInfo->hasPropertyByName(s_UnvisitedCharStyleName) && + m_xImpl->m_xTextStyles->hasByName(sDisplayName)) + { + xPropSet->setPropertyValue(s_UnvisitedCharStyleName, + Any(sDisplayName)); + } + + sDisplayName = + rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, rVisitedStyleName ); + if( !sDisplayName.isEmpty() && + xPropSetInfo->hasPropertyByName(s_VisitedCharStyleName) && + m_xImpl->m_xTextStyles->hasByName(sDisplayName)) + { + xPropSet->setPropertyValue(s_VisitedCharStyleName, + Any(sDisplayName)); + } +} + +void XMLTextImportHelper::SetRuby( + SvXMLImport const & rImport, + const Reference < XTextCursor >& rCursor, + const OUString& rStyleName, + const OUString& rTextStyleName, + const OUString& rText ) +{ + Reference xPropSet(rCursor, UNO_QUERY); + + OUString sRubyText("RubyText"); + + // if we have one Ruby property, we assume all of them are present + if (!xPropSet.is() || + !xPropSet->getPropertySetInfo()->hasPropertyByName( sRubyText )) + return; + + // the ruby text + xPropSet->setPropertyValue(sRubyText, Any(rText)); + + // the ruby style (ruby-adjust) + if (!rStyleName.isEmpty() && m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::TEXT_RUBY, + rStyleName, true ); + XMLPropStyleContext *pStyle = const_cast(dynamic_cast< const XMLPropStyleContext* >(pTempStyle)); + + if (nullptr != pStyle) + pStyle->FillPropertySet( xPropSet ); + } + + // the ruby text character style + if (m_xImpl->m_xTextStyles.is()) + { + OUString sDisplayName( + rImport.GetStyleDisplayName( + XmlStyleFamily::TEXT_TEXT, rTextStyleName ) ); + if( (!sDisplayName.isEmpty()) && + m_xImpl->m_xTextStyles->hasByName( sDisplayName )) + { + xPropSet->setPropertyValue("RubyCharStyleName", Any(sDisplayName)); + } + } +} + +void XMLTextImportHelper::SetAutoStyles( SvXMLStylesContext *pStyles ) +{ + m_xImpl->m_xAutoStyles = pStyles; +} + +SvXMLImportContext *XMLTextImportHelper::CreateTextChildContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< XFastAttributeList > & xAttrList, + XMLTextType eType ) +{ + SvXMLImportContext *pContext = nullptr; + + bool bContent = true; + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_H): + case XML_ELEMENT(TEXT, XML_P): + case XML_ELEMENT(LO_EXT, XML_P): + pContext = new XMLParaContext( rImport, + nElement, + xAttrList ); + if (m_xImpl->m_bProgress && XMLTextType::Shape != eType) + { + rImport.GetProgressBarHelper()->Increment(); + } + break; + // #i52127# + case XML_ELEMENT(TEXT, XML_NUMBERED_PARAGRAPH): + pContext = new XMLNumberedParaContext( + rImport, nElement, xAttrList ); + break; + case XML_ELEMENT(TEXT, XML_LIST): + pContext = new XMLTextListBlockContext( rImport, *this, + xAttrList ); + break; + case XML_ELEMENT(TABLE,XML_TABLE): + case XML_ELEMENT(LO_EXT, XML_TABLE): + if( XMLTextType::Body == eType || + XMLTextType::TextBox == eType || + XMLTextType::Section == eType || + XMLTextType::HeaderFooter == eType || + XMLTextType::ChangedRegion == eType || + XMLTextType::Cell == eType ) + pContext = CreateTableChildContext( rImport, nElement, xAttrList ); + break; + case XML_ELEMENT(TEXT, XML_SEQUENCE_DECLS): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::HeaderFooter == eType ) + { + pContext = new XMLVariableDeclsImportContext( + rImport, *this, VarTypeSequence); + bContent = false; + } + break; + case XML_ELEMENT(TEXT, XML_VARIABLE_DECLS): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::HeaderFooter == eType ) + { + pContext = new XMLVariableDeclsImportContext( + rImport, *this, VarTypeSimple); + bContent = false; + } + break; + case XML_ELEMENT(TEXT, XML_USER_FIELD_DECLS): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted)|| + XMLTextType::HeaderFooter == eType ) + { + pContext = new XMLVariableDeclsImportContext( + rImport, *this, VarTypeUserField); + bContent = false; + } + break; + case XML_ELEMENT(TEXT, XML_DDE_CONNECTION_DECLS): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::HeaderFooter == eType ) + { + pContext = new XMLDdeFieldDeclsImportContext(rImport); + bContent = false; + } + break; + case XML_ELEMENT(DRAW, XML_FRAME): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::TextBox == eType || + XMLTextType::ChangedRegion == eType ) + { + TextContentAnchorType eAnchorType = + XMLTextType::TextBox == eType ? TextContentAnchorType_AT_FRAME + : TextContentAnchorType_AT_PAGE; + pContext = new XMLTextFrameContext( rImport, xAttrList, + eAnchorType ); + bContent = false; + } + break; + case XML_ELEMENT(DRAW, XML_A): + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::TextBox == eType || + XMLTextType::ChangedRegion == eType) + { + TextContentAnchorType eAnchorType = + XMLTextType::TextBox == eType ? TextContentAnchorType_AT_FRAME + : TextContentAnchorType_AT_PAGE; + pContext = new XMLTextFrameHyperlinkContext( rImport, nElement, + xAttrList, + eAnchorType ); + bContent = false; + } + break; + case XML_ELEMENT(TEXT, XML_INDEX_TITLE): + case XML_ELEMENT(TEXT, XML_SECTION): + pContext = new XMLSectionImportContext( rImport ); + break; + case XML_ELEMENT(TEXT, XML_TABLE_OF_CONTENT): + case XML_ELEMENT(TEXT, XML_OBJECT_INDEX): + case XML_ELEMENT(TEXT, XML_TABLE_INDEX): + case XML_ELEMENT(TEXT, XML_ILLUSTRATION_INDEX): + case XML_ELEMENT(TEXT, XML_USER_INDEX): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX): + case XML_ELEMENT(TEXT, XML_BIBLIOGRAPHY): + if( XMLTextType::Shape != eType ) + pContext = new XMLIndexTOCContext( rImport, nElement ); + break; + case XML_ELEMENT(TEXT, XML_TRACKED_CHANGES): + pContext = new XMLTrackedChangesImportContext( rImport ); + bContent = false; + break; + case XML_ELEMENT(TEXT, XML_CHANGE): + case XML_ELEMENT(TEXT, XML_CHANGE_START): + case XML_ELEMENT(TEXT, XML_CHANGE_END): + pContext = new XMLChangeImportContext( + rImport, + ((nElement == XML_ELEMENT(TEXT, XML_CHANGE_END)) + ? XMLChangeImportContext::Element::END + : (nElement == XML_ELEMENT(TEXT, XML_CHANGE_START)) + ? XMLChangeImportContext::Element::START + : XMLChangeImportContext::Element::POINT), + true); + break; + case XML_ELEMENT(OFFICE, XML_FORMS): + pContext = xmloff::OFormLayerXMLImport::createOfficeFormsContext(rImport); + bContent = false; + break; + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_AUTO_MARK_FILE): + if( XMLTextType::Body == eType ) + { + pContext = new XMLAutoMarkFileContext(rImport); + } + bContent = false; + break; + case XML_ELEMENT(TABLE, XML_CALCULATION_SETTINGS): + pContext = new XMLCalculationSettingsContext ( rImport, nElement, xAttrList); + bContent = false; + break; + + default: + if ((XMLTextType::Body == eType && m_xImpl->m_bBodyContentStarted) || + XMLTextType::TextBox == eType || + XMLTextType::ChangedRegion == eType ) + { + Reference < XShapes > xShapes; + pContext = XMLShapeImportHelper::CreateGroupChildContext( + rImport, nElement, xAttrList, xShapes ); + bContent = false; + } + } + + // handle open redlines + if ( (XML_ELEMENT(TEXT, XML_CHANGE) != nElement) && + (XML_ELEMENT(TEXT, XML_CHANGE_END) != nElement) && + (XML_ELEMENT(TEXT, XML_CHANGE_START) != nElement) ) + { +// ResetOpenRedlineId(); + } + + if( XMLTextType::Body == eType && bContent ) + { + m_xImpl->m_bBodyContentStarted = false; + } + + if( nElement != XML_ELEMENT(DRAW, XML_FRAME) ) + ClearLastImportedTextFrameName(); + + if (!pContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return pContext; +} + +SvXMLImportContext *XMLTextImportHelper::CreateTableChildContext( + SvXMLImport&, + sal_Int32 /*nElement*/, + const Reference< XFastAttributeList > & ) +{ + return nullptr; +} + +/// get data style key for use with NumberFormat property +sal_Int32 XMLTextImportHelper::GetDataStyleKey(const OUString& sStyleName, + bool* pIsSystemLanguage ) +{ + if (!m_xImpl->m_xAutoStyles.is()) + return -1; + + const SvXMLStyleContext* pStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::DATA_STYLE, + sStyleName, true ); + + // get appropriate context + + + // first check if it's an Impress and draw only number format + // this is needed since it's also a SvXMLNumFormatContext, + // that was needed to support them for controls in impress/draw also + const SdXMLNumberFormatImportContext* pSdNumStyle = dynamic_cast( pStyle ); + if( pSdNumStyle ) + { + return pSdNumStyle->GetDrawKey(); + } + else + { + SvXMLNumFormatContext* pNumStyle = const_cast(dynamic_cast( pStyle ) ); + if( pNumStyle ) + { + if( pIsSystemLanguage != nullptr ) + *pIsSystemLanguage = pNumStyle->IsSystemLanguage(); + + // return key + return pNumStyle->GetKey(); + } + } + return -1; +} + +const SvxXMLListStyleContext *XMLTextImportHelper::FindAutoListStyle( const OUString& rName ) const +{ + const SvxXMLListStyleContext *pStyle = nullptr; + if (m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::TEXT_LIST, rName, + true ); + pStyle = dynamic_cast< const SvxXMLListStyleContext* >(pTempStyle); + } + + return pStyle; +} + +XMLPropStyleContext *XMLTextImportHelper::FindAutoFrameStyle( const OUString& rName ) const +{ + XMLPropStyleContext *pStyle = nullptr; + if (m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( XmlStyleFamily::SD_GRAPHICS_ID, rName, + true ); + pStyle = const_cast(dynamic_cast< const XMLPropStyleContext* >(pTempStyle)); + } + + return pStyle; +} + +XMLPropStyleContext* XMLTextImportHelper::FindSectionStyle( + const OUString& rName ) const +{ + XMLPropStyleContext* pStyle = nullptr; + if (m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( + XmlStyleFamily::TEXT_SECTION, + rName, true ); + pStyle = const_cast(dynamic_cast< const XMLPropStyleContext* >(pTempStyle)); + } + + return pStyle; +} + +XMLPropStyleContext* XMLTextImportHelper::FindPageMaster( + const OUString& rName ) const +{ + XMLPropStyleContext* pStyle = nullptr; + if (m_xImpl->m_xAutoStyles.is()) + { + const SvXMLStyleContext* pTempStyle = + m_xImpl->m_xAutoStyles->FindStyleChildContext( + XmlStyleFamily::PAGE_MASTER, + rName, true ); + pStyle = const_cast(dynamic_cast< const XMLPropStyleContext* >(pTempStyle)); + } + + return pStyle; +} + +XMLPropStyleContext * XMLTextImportHelper::FindDrawingPage(OUString const& rName) const +{ + if (!m_xImpl->m_xAutoStyles.is()) + { + return nullptr; + } + SvXMLStyleContext const* pStyle( + m_xImpl->m_xAutoStyles->FindStyleChildContext( + XmlStyleFamily::SD_DRAWINGPAGE_ID, rName, true)); + assert(pStyle == nullptr || dynamic_cast(pStyle) != nullptr); + return const_cast(static_cast(pStyle)); +} + +void XMLTextImportHelper::PushListContext() +{ + GetTextListHelper().PushListContext(static_cast(nullptr)); +} + +void XMLTextImportHelper::PopListContext() +{ + GetTextListHelper().PopListContext(); +} + + +SvI18NMap& XMLTextImportHelper::GetRenameMap() +{ + if (!m_xImpl->m_xRenameMap) + { + m_xImpl->m_xRenameMap.reset( new SvI18NMap ); + } + return *m_xImpl->m_xRenameMap; +} + +void XMLTextImportHelper::InsertBookmarkStartRange( + const OUString & sName, + const Reference & rRange, + OUString const& i_rXmlId, + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > & i_rpRDFaAttributes) +{ + m_xImpl->m_BookmarkStartRanges[sName] = + std::make_tuple(rRange, i_rXmlId, i_rpRDFaAttributes); + m_xImpl->m_BookmarkVector.push_back(sName); +} + +bool XMLTextImportHelper::FindAndRemoveBookmarkStartRange( + const OUString & sName, + Reference & o_rRange, + OUString & o_rXmlId, + std::shared_ptr< ::xmloff::ParsedRDFaAttributes > & o_rpRDFaAttributes) +{ + if (m_xImpl->m_BookmarkStartRanges.count(sName)) + { + Impl::BookmarkMapEntry_t & rEntry = + (*m_xImpl->m_BookmarkStartRanges.find(sName)).second; + o_rRange.set(std::get<0>(rEntry)); + o_rXmlId = std::get<1>(rEntry); + o_rpRDFaAttributes = std::get<2>(rEntry); + m_xImpl->m_BookmarkStartRanges.erase(sName); + auto it = std::find(m_xImpl->m_BookmarkVector.begin(), m_xImpl->m_BookmarkVector.end(), sName); + if (it!=m_xImpl->m_BookmarkVector.end()) + { + m_xImpl->m_BookmarkVector.erase(it); + } + return true; + } + else + { + return false; + } +} + +void XMLTextImportHelper::pushFieldCtx( const OUString& name, const OUString& type ) +{ + m_xImpl->m_FieldStack.push(Impl::field_stack_item_t( + Impl::field_name_type_t(name, type), Impl::field_params_t(), uno::Reference{}, GetCursor()->getStart())); +} + +uno::Reference +XMLTextImportHelper::popFieldCtx() +{ + uno::Reference xRet; + if ( !m_xImpl->m_FieldStack.empty() ) + { + xRet = std::get<2>(m_xImpl->m_FieldStack.top()); + m_xImpl->m_FieldStack.pop(); + } + else + { + SAL_INFO("xmloff.text", "unexpected fieldmark end"); + } + return xRet; +} + +void XMLTextImportHelper::addFieldParam( const OUString& name, const OUString& value ) +{ + assert(!m_xImpl->m_FieldStack.empty()); + Impl::field_stack_item_t & FieldStackItem(m_xImpl->m_FieldStack.top()); + std::get<1>(FieldStackItem).emplace_back( name, value ); +} + +::std::pair XMLTextImportHelper::getCurrentFieldType() const +{ + assert(!m_xImpl->m_FieldStack.empty()); + return std::get<0>(m_xImpl->m_FieldStack.top()); +} + +uno::Reference XMLTextImportHelper::getCurrentFieldStart() const +{ + assert(!m_xImpl->m_FieldStack.empty()); + return std::get<3>(m_xImpl->m_FieldStack.top()); +} + +bool XMLTextImportHelper::hasCurrentFieldSeparator() const +{ + assert(!m_xImpl->m_FieldStack.empty()); + return std::get<2>(m_xImpl->m_FieldStack.top()).is(); +} + +bool XMLTextImportHelper::hasCurrentFieldCtx() const +{ + return !m_xImpl->m_FieldStack.empty(); +} + +void XMLTextImportHelper::setCurrentFieldParamsTo(css::uno::Reference< css::text::XFormField> const &xFormField) +{ + assert(!m_xImpl->m_FieldStack.empty()); + if (xFormField.is()) + { + FieldParamImporter(&std::get<1>(m_xImpl->m_FieldStack.top()), + xFormField->getParameters()).Import(); + std::get<2>(m_xImpl->m_FieldStack.top()) = xFormField; + } +} + + +void XMLTextImportHelper::ConnectFrameChains( + const OUString& rFrmName, + const OUString& rNextFrmName, + const Reference < XPropertySet >& rFrmPropSet ) +{ + if( rFrmName.isEmpty() ) + return; + + if( !rNextFrmName.isEmpty() ) + { + OUString sNextFrmName(GetRenameMap().Get( XML_TEXT_RENAME_TYPE_FRAME, + rNextFrmName )); + if (m_xImpl->m_xTextFrames.is() + && m_xImpl->m_xTextFrames->hasByName(sNextFrmName)) + { + rFrmPropSet->setPropertyValue("ChainNextName", + Any(sNextFrmName)); + } + else + { + if (!m_xImpl->m_xPrevFrmNames) + { + m_xImpl->m_xPrevFrmNames.emplace(); + m_xImpl->m_xNextFrmNames.emplace(); + } + m_xImpl->m_xPrevFrmNames->push_back(rFrmName); + m_xImpl->m_xNextFrmNames->push_back(sNextFrmName); + } + } + if (!m_xImpl->m_xPrevFrmNames || m_xImpl->m_xPrevFrmNames->empty()) + return; + + for(std::vector::iterator i = m_xImpl->m_xPrevFrmNames->begin(), j = m_xImpl->m_xNextFrmNames->begin(); i != m_xImpl->m_xPrevFrmNames->end() && j != m_xImpl->m_xNextFrmNames->end(); ++i, ++j) + { + if((*j) == rFrmName) + { + // The previous frame must exist, because it existing than + // inserting the entry + rFrmPropSet->setPropertyValue("ChainPrevName", Any(*i)); + + i = m_xImpl->m_xPrevFrmNames->erase(i); + j = m_xImpl->m_xNextFrmNames->erase(j); + + // There cannot be more than one previous frames + break; + } + } +} + +bool XMLTextImportHelper::IsInFrame() const +{ + static constexpr OUStringLiteral s_TextFrame = u"TextFrame"; + + bool bIsInFrame = false; + + // are we currently in a text frame? yes, if the cursor has a + // TextFrame property and it's non-NULL + Reference xPropSet(const_cast(this)->GetCursor(), UNO_QUERY); + if (xPropSet.is()) + { + if (xPropSet->getPropertySetInfo()->hasPropertyByName(s_TextFrame)) + { + uno::Reference const xFrame( + xPropSet->getPropertyValue(s_TextFrame), UNO_QUERY); + + if (xFrame.is()) + { + bIsInFrame = true; + } + } + } + + return bIsInFrame; +} + +bool XMLTextImportHelper::IsInHeaderFooter() const +{ + return false; +} + +Reference< XPropertySet> XMLTextImportHelper::createAndInsertOLEObject( + SvXMLImport&, + const OUString& /*rHRef*/, + const OUString& /*rStyleName*/, + const OUString& /*rTblName*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} + +Reference< XPropertySet> XMLTextImportHelper::createAndInsertOOoLink( + SvXMLImport&, + const OUString& /*rHRef*/, + const OUString& /*rStyleName*/, + const OUString& /*rTblName*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} + +Reference< XPropertySet> XMLTextImportHelper::createAndInsertApplet( + const OUString& /*rCode*/, + const OUString& /*rName*/, + bool /*bMayScript*/, + const OUString& /*rHRef*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} +Reference< XPropertySet> XMLTextImportHelper::createAndInsertPlugin( + const OUString& /*rMimeType*/, + const OUString& /*rHRef*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} +Reference< XPropertySet> XMLTextImportHelper::createAndInsertFloatingFrame( + const OUString& /*rName*/, + const OUString& /*rHRef*/, + const OUString& /*rStyleName*/, + sal_Int32 /*nWidth*/, sal_Int32 /*nHeight*/ ) +{ + Reference< XPropertySet> xPropSet; + return xPropSet; +} + +void XMLTextImportHelper::endAppletOrPlugin( + const Reference < XPropertySet> &, + std::map < const OUString, OUString > &) +{ +} +// redline helper: dummy implementation to be overridden in sw/filter/xml +void XMLTextImportHelper::RedlineAdd( const OUString& /*rType*/, + const OUString& /*rId*/, + const OUString& /*rAuthor*/, + const OUString& /*rComment*/, + const util::DateTime& /*rDateTime*/, + bool /*bMergeLastPara*/) +{ + // dummy implementation: do nothing +} + +Reference XMLTextImportHelper::RedlineCreateText( + Reference & /*rOldCursor*/, + const OUString& /*rId*/) +{ + // dummy implementation: do nothing + Reference xRet; + return xRet; +} + +void XMLTextImportHelper::RedlineSetCursor( + const OUString& /*rId*/, + bool /*bStart*/, + bool /*bIsOutsideOfParagraph*/) +{ + // dummy implementation: do nothing +} + +void XMLTextImportHelper::RedlineAdjustStartNodeCursor() +{ + // dummy implementation: do nothing +} + +void XMLTextImportHelper::SetShowChanges( bool ) +{ + // dummy implementation: do nothing +} + +void XMLTextImportHelper::SetRecordChanges( bool ) +{ + // dummy implementation: do nothing +} +void XMLTextImportHelper::SetChangesProtectionKey(const Sequence &) +{ + // dummy implementation: do nothing +} + + +OUString const & XMLTextImportHelper::GetOpenRedlineId() const +{ + return m_xImpl->m_sOpenRedlineIdentifier; +} + +void XMLTextImportHelper::SetOpenRedlineId( OUString const & rId) +{ + m_xImpl->m_sOpenRedlineIdentifier = rId; +} + +void XMLTextImportHelper::ResetOpenRedlineId() +{ + SetOpenRedlineId(""); +} + +void +XMLTextImportHelper::SetCellParaStyleDefault(OUString const& rNewValue) +{ + m_xImpl->m_sCellParaStyleDefault = rNewValue; +} + +OUString const& XMLTextImportHelper::GetCellParaStyleDefault() const +{ + return m_xImpl->m_sCellParaStyleDefault; +} + +void XMLTextImportHelper::AddCrossRefHeadingMapping(OUString const& rFrom, OUString const& rTo) +{ + if (!m_xImpl->m_xCrossRefHeadingBookmarkMap) + { + m_xImpl->m_xCrossRefHeadingBookmarkMap.emplace(); + } + m_xImpl->m_xCrossRefHeadingBookmarkMap->insert(std::make_pair(rFrom, rTo)); +} + +// tdf#94804: hack to map cross reference fields that reference duplicate marks +// note that we can't really check meta:generator for this since the file might +// be round-tripped by different versions preserving duplicates => always map +void XMLTextImportHelper::MapCrossRefHeadingFieldsHorribly() +{ + if (!m_xImpl->m_xCrossRefHeadingBookmarkMap) + { + return; + } + + uno::Reference const xFieldsSupplier( + m_xImpl->m_rSvXMLImport.GetModel(), uno::UNO_QUERY); + if (!xFieldsSupplier.is()) + { + return; + } + uno::Reference const xFieldsEA( + xFieldsSupplier->getTextFields()); + uno::Reference const xFields( + xFieldsEA->createEnumeration()); + while (xFields->hasMoreElements()) + { + uno::Reference const xFieldInfo( + xFields->nextElement(), uno::UNO_QUERY); + if (!xFieldInfo->supportsService("com.sun.star.text.textfield.GetReference")) + { + continue; + } + uno::Reference const xField( + xFieldInfo, uno::UNO_QUERY); + sal_uInt16 nType(0); + xField->getPropertyValue("ReferenceFieldSource") >>= nType; + if (text::ReferenceFieldSource::BOOKMARK != nType) + { + continue; + } + OUString name; + xField->getPropertyValue("SourceName") >>= name; + auto const iter(m_xImpl->m_xCrossRefHeadingBookmarkMap->find(name)); + if (iter == m_xImpl->m_xCrossRefHeadingBookmarkMap->end()) + { + continue; + } + xField->setPropertyValue("SourceName", uno::Any(iter->second)); + } +} + +void XMLTextImportHelper::setBookmarkAttributes(OUString const& bookmark, bool hidden, OUString const& condition) +{ + m_xImpl->m_bBookmarkHidden[bookmark] = hidden; + m_xImpl->m_sBookmarkCondition[bookmark] = condition; +} + +bool XMLTextImportHelper::getBookmarkHidden(OUString const& bookmark) const +{ + return m_xImpl->m_bBookmarkHidden[bookmark]; +} + +const OUString& XMLTextImportHelper::getBookmarkCondition(OUString const& bookmark) const +{ + return m_xImpl->m_sBookmarkCondition[bookmark]; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtimppr.cxx b/xmloff/source/text/txtimppr.cxx new file mode 100644 index 000000000..dcf9d1d3e --- /dev/null +++ b/xmloff/source/text/txtimppr.cxx @@ -0,0 +1,848 @@ +/* -*- 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define XML_LINE_LEFT 0 +#define XML_LINE_RIGHT 1 +#define XML_LINE_TOP 2 +#define XML_LINE_BOTTOM 3 + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::table; +using namespace ::com::sun::star::text; + +bool XMLTextImportPropertyMapper::handleSpecialItem( + XMLPropertyState& rProperty, + ::std::vector< XMLPropertyState >& rProperties, + const OUString& rValue, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap ) const +{ + bool bRet = false; + sal_Int32 nIndex = rProperty.mnIndex; + switch( getPropertySetMapper()->GetEntryContextId( nIndex ) ) + { + case CTF_FONTNAME: + case CTF_FONTNAME_CJK: + case CTF_FONTNAME_CTL: + if( GetImport().GetFontDecls() != nullptr ) + { + assert(( + ( CTF_FONTFAMILYNAME == + getPropertySetMapper()->GetEntryContextId(nIndex+1) && + CTF_FONTSTYLENAME == + getPropertySetMapper()->GetEntryContextId(nIndex+2) && + CTF_FONTFAMILY == + getPropertySetMapper()->GetEntryContextId(nIndex+3) && + CTF_FONTPITCH == + getPropertySetMapper()->GetEntryContextId(nIndex+4) && + CTF_FONTCHARSET == + getPropertySetMapper()->GetEntryContextId(nIndex+5) ) || + ( CTF_FONTFAMILYNAME_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+1) && + CTF_FONTSTYLENAME_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+2) && + CTF_FONTFAMILY_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+3) && + CTF_FONTPITCH_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+4) && + CTF_FONTCHARSET_CJK == + getPropertySetMapper()->GetEntryContextId(nIndex+5) ) || + ( CTF_FONTFAMILYNAME_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+1) && + CTF_FONTSTYLENAME_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+2) && + CTF_FONTFAMILY_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+3) && + CTF_FONTPITCH_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+4) && + CTF_FONTCHARSET_CTL == + getPropertySetMapper()->GetEntryContextId(nIndex+5) ) + ) && "illegal property map" ); + + GetImport().GetFontDecls()->FillProperties( + rValue, rProperties, + rProperty.mnIndex+1, rProperty.mnIndex+2, + rProperty.mnIndex+3, rProperty.mnIndex+4, + rProperty.mnIndex+5 ); + bRet = false; // the property hasn't been filled + } + break; + + // If we want to do StarMath/StarSymbol font conversion, then we'll + // want these special items to be treated just like regular ones... + // For the Writer, we'll catch and convert them in _FillPropertySet; + // the other apps probably don't care. For the other apps, we just + // imitate the default non-special-item mechanism. + case CTF_FONTFAMILYNAME: + case CTF_FONTFAMILYNAME_CJK: + case CTF_FONTFAMILYNAME_CTL: + bRet = getPropertySetMapper()->importXML( rValue, rProperty, + rUnitConverter ); + break; + + case CTF_TEXT_DISPLAY: + bRet = getPropertySetMapper()->importXML( rValue, rProperty, + rUnitConverter ); + if( SvXMLImport::OOo_2x == GetImport().getGeneratorVersion() ) + { + bool bHidden = false; + rProperty.maValue >>= bHidden; + bHidden = !bHidden; + rProperty.maValue <<= bHidden; + } + break; + default: + bRet = SvXMLImportPropertyMapper::handleSpecialItem( rProperty, + rProperties, rValue, rUnitConverter, rNamespaceMap ); + break; + } + + return bRet; +} + +XMLTextImportPropertyMapper::XMLTextImportPropertyMapper( + const rtl::Reference< XMLPropertySetMapper >& rMapper, + SvXMLImport& rImp ) : + SvXMLImportPropertyMapper( rMapper, rImp ), + nSizeTypeIndex( -2 ), + nWidthTypeIndex( -2 ) +{ +} + +XMLTextImportPropertyMapper::~XMLTextImportPropertyMapper() +{ +} + +void XMLTextImportPropertyMapper::FontFinished( + XMLPropertyState *pFontFamilyNameState, + XMLPropertyState *pFontStyleNameState, + XMLPropertyState *pFontFamilyState, + XMLPropertyState *pFontPitchState, + XMLPropertyState *pFontCharsetState ) +{ + if( pFontFamilyNameState && pFontFamilyNameState->mnIndex != -1 ) + { + OUString sName; + pFontFamilyNameState->maValue >>= sName; + if( sName.isEmpty() ) + pFontFamilyNameState->mnIndex = -1; + } + if( !pFontFamilyNameState || pFontFamilyNameState->mnIndex == -1 ) + { + if( pFontStyleNameState ) + pFontStyleNameState->mnIndex = -1; + if( pFontFamilyState ) + pFontFamilyState->mnIndex = -1; + if( pFontPitchState ) + pFontPitchState->mnIndex = -1; + if( pFontCharsetState ) + pFontCharsetState->mnIndex = -1; + } +} + +/** since the properties "CharFontFamilyName", "CharFontStyleName", "CharFontFamily", + "CharFontPitch" and "CharFontSet" and their CJK and CTL counterparts are only + usable as a union, we add defaults to all values that are not set as long as we + have an "CharFontFamilyName" + + #99928# CL */ +void XMLTextImportPropertyMapper::FontDefaultsCheck( + XMLPropertyState const * pFontFamilyName, + XMLPropertyState const * pFontStyleName, + XMLPropertyState const * pFontFamily, + XMLPropertyState const * pFontPitch, + XMLPropertyState const * pFontCharSet, + std::optional* ppNewFontStyleName, + std::optional* ppNewFontFamily, + std::optional* ppNewFontPitch, + std::optional* ppNewFontCharSet ) const +{ + if( pFontFamilyName ) + { + Any aAny; + + if( !pFontStyleName ) + { + aAny <<= OUString(); + #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pFontFamilyName->mnIndex + 1 ); + assert(nTmp == CTF_FONTSTYLENAME || nTmp == CTF_FONTSTYLENAME_CJK || nTmp == CTF_FONTSTYLENAME_CTL); + #endif + ppNewFontStyleName->emplace( pFontFamilyName->mnIndex + 1, aAny ); + } + + if( !pFontFamily ) + { + aAny <<= sal_Int16(css::awt::FontFamily::DONTKNOW); + + #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pFontFamilyName->mnIndex + 2 ); + assert(nTmp == CTF_FONTFAMILY || nTmp == CTF_FONTFAMILY_CJK || nTmp == CTF_FONTFAMILY_CTL); + #endif + ppNewFontFamily->emplace( pFontFamilyName->mnIndex + 2, aAny ); + } + + if( !pFontPitch ) + { + aAny <<= sal_Int16(css::awt::FontPitch::DONTKNOW); + #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pFontFamilyName->mnIndex + 3 ); + assert(nTmp == CTF_FONTPITCH || nTmp == CTF_FONTPITCH_CJK || nTmp == CTF_FONTPITCH_CTL); + #endif + ppNewFontPitch->emplace( pFontFamilyName->mnIndex + 3, aAny ); + } + + if( !pFontCharSet ) + { + aAny <<= static_cast(osl_getThreadTextEncoding()); + #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pFontFamilyName->mnIndex + 4 ); + assert(nTmp == CTF_FONTCHARSET || nTmp == CTF_FONTCHARSET_CJK || nTmp == CTF_FONTCHARSET_CTL); + #endif + ppNewFontCharSet->emplace( pFontFamilyName->mnIndex + 4, aAny ); + } + } + + (void) this; // avoid loplugin:staticmethods +} + +namespace { +//fdo#58730 The [UL|LR]Space class has a deficiency where "100%" also serves as +//a flag that the value is an absolute value so we can't truly handle an +//up/lower space property which wants to specify its 200% upper but 100% lower +//of its parent (try typing 100% vs 200% into the edit style dialog and revisit +//your style). So on xml load that ends up meaning 200%, 0 lower. This is a +//crock. + +//On import clear 100% all-margins relative sizes. +bool +isNotDefaultRelSize(const XMLPropertyState* pRelState, const rtl::Reference& rPrMap) +{ + if (rPrMap->GetEntryContextId(pRelState->mnIndex) == CTF_PARAMARGINALL_REL) + { + sal_Int32 nTemp = 0; + pRelState->maValue >>= nTemp; + return nTemp != 100; + } + return true; +} + +/** + * Separate compressed border attributes. + * During export, border attributes are compressed if there are equal to all four side. + * Since Writer hasn't the same compressed attributes, but has distinct ones for all + * four side, we have to duplicate the compressed attribute during import. +**/ +void lcl_SeparateBorder( + sal_uInt16 nIndex, XMLPropertyState const * pAllBorderDistance, + XMLPropertyState* pBorderDistances[4], XMLPropertyState* pNewBorderDistances[4], + XMLPropertyState const * pAllBorder, XMLPropertyState* pBorders[4], + XMLPropertyState* pNewBorders[4], XMLPropertyState* pAllBorderWidth, + XMLPropertyState* pBorderWidths[4] +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + , const rtl::Reference< XMLPropertySetMapper >& rMapper +#endif +) +{ + if( pAllBorderDistance && !pBorderDistances[nIndex] ) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = rMapper->GetEntryContextId( + pAllBorderDistance->mnIndex + nIndex + 1 ); + if (CTF_CHARALLBORDERDISTANCE == + rMapper->GetEntryContextId(pAllBorderDistance->mnIndex)) + { + assert(nTmp >= CTF_CHARLEFTBORDERDISTANCE && + nTmp <= CTF_CHARBOTTOMBORDERDISTANCE); + } + else + { + assert(nTmp >= CTF_LEFTBORDERDISTANCE && + nTmp <= CTF_BOTTOMBORDERDISTANCE); + } +#endif + pNewBorderDistances[nIndex] = + new XMLPropertyState( pAllBorderDistance->mnIndex + nIndex + 1, + pAllBorderDistance->maValue ); + pBorderDistances[nIndex] = pNewBorderDistances[nIndex]; + } + if( pAllBorder && !pBorders[nIndex] ) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = rMapper->GetEntryContextId( + pAllBorder->mnIndex + nIndex + 1 ); + if (CTF_CHARALLBORDER == + rMapper->GetEntryContextId(pAllBorder->mnIndex)) + { + assert(nTmp >= CTF_CHARLEFTBORDER && nTmp <= CTF_CHARBOTTOMBORDER); + } + else + { + assert(nTmp >= CTF_LEFTBORDER && nTmp <= CTF_BOTTOMBORDER); + } +#endif + pNewBorders[nIndex] = new XMLPropertyState( pAllBorder->mnIndex + nIndex + 1, + pAllBorder->maValue ); + pBorders[nIndex] = pNewBorders[nIndex]; + } + if( !pBorderWidths[nIndex] ) + pBorderWidths[nIndex] = pAllBorderWidth; + else + pBorderWidths[nIndex]->mnIndex = -1; + + if( !(pBorders[nIndex] && pBorderWidths[nIndex]) ) + return; + + table::BorderLine2 aBorderLine; + pBorders[nIndex]->maValue >>= aBorderLine; + + table::BorderLine2 aBorderLineWidth; + pBorderWidths[nIndex]->maValue >>= aBorderLineWidth; + + aBorderLine.OuterLineWidth = aBorderLineWidth.OuterLineWidth; + aBorderLine.InnerLineWidth = aBorderLineWidth.InnerLineWidth; + aBorderLine.LineDistance = aBorderLineWidth.LineDistance; + aBorderLine.LineWidth = aBorderLineWidth.LineWidth; + + pBorders[nIndex]->maValue <<= aBorderLine; +} + +} + +void XMLTextImportPropertyMapper::finished( + ::std::vector< XMLPropertyState >& rProperties, + sal_Int32 /*nStartIndex*/, sal_Int32 /*nEndIndex*/ ) const +{ + bool bHasAnyHeight = false; + bool bHasAnyMinHeight = false; + bool bHasAnyWidth = false; + bool bHasAnyMinWidth = false; + + XMLPropertyState* pFontFamilyName = nullptr; + XMLPropertyState* pFontStyleName = nullptr; + XMLPropertyState* pFontFamily = nullptr; + XMLPropertyState* pFontPitch = nullptr; + XMLPropertyState* pFontCharSet = nullptr; + std::optional pNewFontStyleName; + std::optional pNewFontFamily; + std::optional pNewFontPitch; + std::optional pNewFontCharSet; + XMLPropertyState* pFontFamilyNameCJK = nullptr; + XMLPropertyState* pFontStyleNameCJK = nullptr; + XMLPropertyState* pFontFamilyCJK = nullptr; + XMLPropertyState* pFontPitchCJK = nullptr; + XMLPropertyState* pFontCharSetCJK = nullptr; + std::optional pNewFontStyleNameCJK; + std::optional pNewFontFamilyCJK; + std::optional pNewFontPitchCJK; + std::optional pNewFontCharSetCJK; + XMLPropertyState* pFontFamilyNameCTL = nullptr; + XMLPropertyState* pFontStyleNameCTL = nullptr; + XMLPropertyState* pFontFamilyCTL = nullptr; + XMLPropertyState* pFontPitchCTL = nullptr; + XMLPropertyState* pFontCharSetCTL = nullptr; + std::optional pNewFontStyleNameCTL; + std::optional pNewFontFamilyCTL; + std::optional pNewFontPitchCTL; + std::optional pNewFontCharSetCTL; + XMLPropertyState* pAllBorderDistance = nullptr; + XMLPropertyState* pBorderDistances[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pNewBorderDistances[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllBorder = nullptr; + XMLPropertyState* pBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pAllBorderWidth = nullptr; + XMLPropertyState* pBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharAllBorderDistance = nullptr; + XMLPropertyState* pCharBorderDistances[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharNewBorderDistances[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharAllBorder = nullptr; + XMLPropertyState* pCharBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharNewBorders[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pCharAllBorderWidth = nullptr; + XMLPropertyState* pCharBorderWidths[4] = { nullptr, nullptr, nullptr, nullptr }; + XMLPropertyState* pVertOrient = nullptr; + XMLPropertyState* pVertOrientRelAsChar = nullptr; + XMLPropertyState* pBackTransparency = nullptr; // transparency in % + XMLPropertyState* pBackTransparent = nullptr; // transparency as boolean + XMLPropertyState* pAllParaMargin = nullptr; + XMLPropertyState* pParaMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + ::std::optional pNewParaMargins[4]; + XMLPropertyState* pAllMargin = nullptr; + XMLPropertyState* pMargins[4] = { nullptr, nullptr, nullptr, nullptr }; + ::std::optional pNewMargins[4]; + XMLPropertyState* pFillStyle(nullptr); + XMLPropertyState* pFillColor(nullptr); + + for( auto& rProperty : rProperties ) + { + XMLPropertyState* property = &rProperty; + if( -1 == property->mnIndex ) + continue; + + switch( getPropertySetMapper()->GetEntryContextId( property->mnIndex ) ) + { + case CTF_FONTFAMILYNAME: pFontFamilyName = property; break; + case CTF_FONTSTYLENAME: pFontStyleName = property; break; + case CTF_FONTFAMILY: pFontFamily = property; break; + case CTF_FONTPITCH: pFontPitch = property; break; + case CTF_FONTCHARSET: pFontCharSet = property; break; + + case CTF_FONTFAMILYNAME_CJK: pFontFamilyNameCJK = property; break; + case CTF_FONTSTYLENAME_CJK: pFontStyleNameCJK = property; break; + case CTF_FONTFAMILY_CJK: pFontFamilyCJK = property; break; + case CTF_FONTPITCH_CJK: pFontPitchCJK = property; break; + case CTF_FONTCHARSET_CJK: pFontCharSetCJK = property; break; + + case CTF_FONTFAMILYNAME_CTL: pFontFamilyNameCTL = property; break; + case CTF_FONTSTYLENAME_CTL: pFontStyleNameCTL = property; break; + case CTF_FONTFAMILY_CTL: pFontFamilyCTL = property; break; + case CTF_FONTPITCH_CTL: pFontPitchCTL = property; break; + case CTF_FONTCHARSET_CTL: pFontCharSetCTL = property; break; + + case CTF_ALLBORDERDISTANCE: pAllBorderDistance = property; break; + case CTF_LEFTBORDERDISTANCE: pBorderDistances[XML_LINE_LEFT] = property; break; + case CTF_RIGHTBORDERDISTANCE: pBorderDistances[XML_LINE_RIGHT] = property; break; + case CTF_TOPBORDERDISTANCE: pBorderDistances[XML_LINE_TOP] = property; break; + case CTF_BOTTOMBORDERDISTANCE: pBorderDistances[XML_LINE_BOTTOM] = property; break; + case CTF_ALLBORDER: pAllBorder = property; break; + case CTF_LEFTBORDER: pBorders[XML_LINE_LEFT] = property; break; + case CTF_RIGHTBORDER: pBorders[XML_LINE_RIGHT] = property; break; + case CTF_TOPBORDER: pBorders[XML_LINE_TOP] = property; break; + case CTF_BOTTOMBORDER: pBorders[XML_LINE_BOTTOM] = property; break; + case CTF_ALLBORDERWIDTH: pAllBorderWidth = property; break; + case CTF_LEFTBORDERWIDTH: pBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_RIGHTBORDERWIDTH: pBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_TOPBORDERWIDTH: pBorderWidths[XML_LINE_TOP] = property; break; + case CTF_BOTTOMBORDERWIDTH: pBorderWidths[XML_LINE_BOTTOM] = property; break; + + case CTF_CHARALLBORDERDISTANCE: pCharAllBorderDistance = property; break; + case CTF_CHARLEFTBORDERDISTANCE: pCharBorderDistances[XML_LINE_LEFT] = property; break; + case CTF_CHARRIGHTBORDERDISTANCE: pCharBorderDistances[XML_LINE_RIGHT] = property; break; + case CTF_CHARTOPBORDERDISTANCE: pCharBorderDistances[XML_LINE_TOP] = property; break; + case CTF_CHARBOTTOMBORDERDISTANCE: pCharBorderDistances[XML_LINE_BOTTOM] = property; break; + case CTF_CHARALLBORDER: pCharAllBorder = property; break; + case CTF_CHARLEFTBORDER: pCharBorders[XML_LINE_LEFT] = property; break; + case CTF_CHARRIGHTBORDER: pCharBorders[XML_LINE_RIGHT] = property; break; + case CTF_CHARTOPBORDER: pCharBorders[XML_LINE_TOP] = property; break; + case CTF_CHARBOTTOMBORDER: pCharBorders[XML_LINE_BOTTOM] = property; break; + case CTF_CHARALLBORDERWIDTH: pCharAllBorderWidth = property; break; + case CTF_CHARLEFTBORDERWIDTH: pCharBorderWidths[XML_LINE_LEFT] = property; break; + case CTF_CHARRIGHTBORDERWIDTH: pCharBorderWidths[XML_LINE_RIGHT] = property; break; + case CTF_CHARTOPBORDERWIDTH: pCharBorderWidths[XML_LINE_TOP] = property; break; + case CTF_CHARBOTTOMBORDERWIDTH: pCharBorderWidths[XML_LINE_BOTTOM] = property; break; + + case CTF_ANCHORTYPE: break; + case CTF_VERTICALPOS: pVertOrient = property; break; + case CTF_VERTICALREL_ASCHAR: pVertOrientRelAsChar = property; break; + + case CTF_FRAMEHEIGHT_MIN_ABS: + case CTF_FRAMEHEIGHT_MIN_REL: +// case CTF_SYNCHEIGHT_MIN: + bHasAnyMinHeight = true; + [[fallthrough]]; + case CTF_FRAMEHEIGHT_ABS: + case CTF_FRAMEHEIGHT_REL: +// case CTF_SYNCHEIGHT: + bHasAnyHeight = true; break; + case CTF_FRAMEWIDTH_MIN_ABS: + case CTF_FRAMEWIDTH_MIN_REL: + bHasAnyMinWidth = true; + [[fallthrough]]; + case CTF_FRAMEWIDTH_ABS: + case CTF_FRAMEWIDTH_REL: + bHasAnyWidth = true; break; + case CTF_BACKGROUND_TRANSPARENCY: pBackTransparency = property; break; + case CTF_BACKGROUND_TRANSPARENT: pBackTransparent = property; break; + case CTF_FILLSTYLE: pFillStyle = property; break; + case CTF_FILLCOLOR: pFillColor = property; break; + case CTF_PARAMARGINALL: + case CTF_PARAMARGINALL_REL: + pAllParaMargin = property; break; + case CTF_PARALEFTMARGIN: + case CTF_PARALEFTMARGIN_REL: + pParaMargins[XML_LINE_LEFT] = property; break; + case CTF_PARARIGHTMARGIN: + case CTF_PARARIGHTMARGIN_REL: + pParaMargins[XML_LINE_RIGHT] = property; break; + case CTF_PARATOPMARGIN: + case CTF_PARATOPMARGIN_REL: + pParaMargins[XML_LINE_TOP] = property; break; + case CTF_PARABOTTOMMARGIN: + case CTF_PARABOTTOMMARGIN_REL: + pParaMargins[XML_LINE_BOTTOM] = property; break; + case CTF_MARGINALL: + pAllMargin = property; break; + case CTF_MARGINLEFT: + pMargins[XML_LINE_LEFT] = property; break; + case CTF_MARGINRIGHT: + pMargins[XML_LINE_RIGHT] = property; break; + case CTF_MARGINTOP: + pMargins[XML_LINE_TOP] = property; break; + case CTF_MARGINBOTTOM: + pMargins[XML_LINE_BOTTOM] = property; break; + } + } + + if( pFontFamilyName || pFontStyleName || pFontFamily || + pFontPitch || pFontCharSet ) + FontFinished( pFontFamilyName, pFontStyleName, pFontFamily, + pFontPitch, pFontCharSet ); + if( pFontFamilyNameCJK || pFontStyleNameCJK || pFontFamilyCJK || + pFontPitchCJK || pFontCharSetCJK ) + FontFinished( pFontFamilyNameCJK, pFontStyleNameCJK, pFontFamilyCJK, + pFontPitchCJK, pFontCharSetCJK ); + if( pFontFamilyNameCTL || pFontStyleNameCTL || pFontFamilyCTL || + pFontPitchCTL || pFontCharSetCTL ) + FontFinished( pFontFamilyNameCTL, pFontStyleNameCTL, pFontFamilyCTL, + pFontPitchCTL, pFontCharSetCTL ); + + for (sal_uInt16 i = 0; i < 4; i++) + { + if (pAllParaMargin && !pParaMargins[i] + && isNotDefaultRelSize(pAllParaMargin, getPropertySetMapper())) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pAllParaMargin->mnIndex + (2*i) + 2 ); + assert(nTmp >= CTF_PARALEFTMARGIN && + nTmp <= CTF_PARABOTTOMMARGIN_REL); +#endif + pNewParaMargins[i].emplace( + pAllParaMargin->mnIndex + (2*i) + 2, pAllParaMargin->maValue); + } + if (pAllMargin && !pMargins[i]) + { +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + sal_Int16 nTmp = getPropertySetMapper()->GetEntryContextId( + pAllMargin->mnIndex + i + 1 ); + assert(nTmp >= CTF_MARGINLEFT && nTmp <= CTF_MARGINBOTTOM); +#endif + pNewMargins[i].emplace( + pAllMargin->mnIndex + i + 1, pAllMargin->maValue); + } + + lcl_SeparateBorder( + i, pAllBorderDistance, pBorderDistances, pNewBorderDistances, + pAllBorder, pBorders, pNewBorders, + pAllBorderWidth, pBorderWidths +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + , getPropertySetMapper() +#endif + ); + + lcl_SeparateBorder( + i, pCharAllBorderDistance, pCharBorderDistances, + pCharNewBorderDistances, pCharAllBorder, pCharBorders, + pCharNewBorders, pCharAllBorderWidth, pCharBorderWidths +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + , getPropertySetMapper() +#endif + ); + } + + if (pAllParaMargin) + { + pAllParaMargin->mnIndex = -1; + } + if (pAllMargin) + { + pAllMargin->mnIndex = -1; + } + + if( pAllBorderDistance ) + pAllBorderDistance->mnIndex = -1; + + if( pAllBorder ) + pAllBorder->mnIndex = -1; + + if( pAllBorderWidth ) + pAllBorderWidth->mnIndex = -1; + + if( pCharAllBorderDistance ) + pCharAllBorderDistance->mnIndex = -1; + + if( pCharAllBorder ) + pCharAllBorder->mnIndex = -1; + + if( pCharAllBorderWidth ) + pCharAllBorderWidth->mnIndex = -1; + + if( pVertOrient && pVertOrientRelAsChar ) + { + sal_Int16 nVertOrient; + pVertOrient->maValue >>= nVertOrient; + sal_Int16 nVertOrientRel = 0; + pVertOrientRelAsChar->maValue >>= nVertOrientRel; + switch( nVertOrient ) + { + case VertOrientation::TOP: + nVertOrient = nVertOrientRel; + break; + case VertOrientation::CENTER: + switch( nVertOrientRel ) + { + case VertOrientation::CHAR_TOP: + nVertOrient = VertOrientation::CHAR_CENTER; + break; + case VertOrientation::LINE_TOP: + nVertOrient = VertOrientation::LINE_CENTER; + break; + } + break; + case VertOrientation::BOTTOM: + switch( nVertOrientRel ) + { + case VertOrientation::CHAR_TOP: + nVertOrient = VertOrientation::CHAR_BOTTOM; + break; + case VertOrientation::LINE_TOP: + nVertOrient = VertOrientation::LINE_BOTTOM; + break; + } + break; + } + pVertOrient->maValue <<= nVertOrient; + pVertOrientRelAsChar->mnIndex = -1; + } + + FontDefaultsCheck( pFontFamilyName, + pFontStyleName, pFontFamily, pFontPitch, pFontCharSet, + &pNewFontStyleName, &pNewFontFamily, &pNewFontPitch, &pNewFontCharSet ); + + FontDefaultsCheck( pFontFamilyNameCJK, + pFontStyleNameCJK, pFontFamilyCJK, pFontPitchCJK, pFontCharSetCJK, + &pNewFontStyleNameCJK, &pNewFontFamilyCJK, &pNewFontPitchCJK, &pNewFontCharSetCJK ); + + FontDefaultsCheck( pFontFamilyNameCTL, + pFontStyleNameCTL, pFontFamilyCTL, pFontPitchCTL, pFontCharSetCTL, + &pNewFontStyleNameCTL, &pNewFontFamilyCTL, &pNewFontPitchCTL, &pNewFontCharSetCTL ); + + if (pFillStyle && !pFillColor && pBackTransparent + && drawing::FillStyle_SOLID == pFillStyle->maValue.get() + && pBackTransparent->maValue.get()) + { + // fo:background="transparent", draw:fill="solid" without draw:fill-color + // prevent getSvxBrushItemFromSourceSet from adding bogus default color + pFillStyle->mnIndex = -1; + } + + // #i5775# don't overwrite %transparency with binary transparency + if( ( pBackTransparency != nullptr ) && ( pBackTransparent != nullptr ) ) + { + if( ! *o3tl::doAccess(pBackTransparent->maValue) ) + pBackTransparent->mnIndex = -1; + } + + + // insert newly created properties. This invalidates all iterators! + // Most of the pXXX variables in this method are iterators and will be + // invalidated!!! + + if( pNewFontStyleName ) + { + rProperties.push_back( *pNewFontStyleName ); + pNewFontStyleName.reset(); + } + + if( pNewFontFamily ) + { + rProperties.push_back( *pNewFontFamily ); + pNewFontFamily.reset(); + } + + if( pNewFontPitch ) + { + rProperties.push_back( *pNewFontPitch ); + pNewFontPitch.reset(); + } + + if( pNewFontCharSet ) + { + rProperties.push_back( *pNewFontCharSet ); + pNewFontCharSet.reset(); + } + + if( pNewFontStyleNameCJK ) + { + rProperties.push_back( *pNewFontStyleNameCJK ); + pNewFontStyleNameCJK.reset(); + } + + if( pNewFontFamilyCJK ) + { + rProperties.push_back( *pNewFontFamilyCJK ); + pNewFontFamilyCJK.reset(); + } + + if( pNewFontPitchCJK ) + { + rProperties.push_back( *pNewFontPitchCJK ); + pNewFontPitchCJK.reset(); + } + + if( pNewFontCharSetCJK ) + { + rProperties.push_back( *pNewFontCharSetCJK ); + pNewFontCharSetCJK.reset(); + } + + if( pNewFontStyleNameCTL) + { + rProperties.push_back( *pNewFontStyleNameCTL ); + pNewFontStyleNameCTL.reset(); + } + + if( pNewFontFamilyCTL ) + { + rProperties.push_back( *pNewFontFamilyCTL ); + pNewFontFamilyCTL.reset(); + } + + if( pNewFontPitchCTL ) + { + rProperties.push_back( *pNewFontPitchCTL ); + pNewFontPitchCTL.reset(); + } + + if( pNewFontCharSetCTL ) + { + rProperties.push_back( *pNewFontCharSetCTL ); + pNewFontCharSetCTL.reset(); + } + + for (sal_uInt16 i=0; i<4; i++) + { + if (pNewParaMargins[i]) + { + rProperties.push_back(*pNewParaMargins[i]); + } + if (pNewMargins[i]) + { + rProperties.push_back(*pNewMargins[i]); + } + if( pNewBorderDistances[i] ) + { + rProperties.push_back( *pNewBorderDistances[i] ); + delete pNewBorderDistances[i]; + } + if( pNewBorders[i] ) + { + rProperties.push_back( *pNewBorders[i] ); + delete pNewBorders[i]; + } + if( pCharNewBorderDistances[i] ) + { + rProperties.push_back( *pCharNewBorderDistances[i] ); + delete pCharNewBorderDistances[i]; + } + if( pCharNewBorders[i] ) + { + rProperties.push_back( *pCharNewBorders[i] ); + delete pCharNewBorders[i]; + } + } + + if( bHasAnyHeight ) + { + if( nSizeTypeIndex == -2 ) + { + const_cast < XMLTextImportPropertyMapper * > ( this ) + ->nSizeTypeIndex = -1; + sal_Int32 nPropCount = getPropertySetMapper()->GetEntryCount(); + for( sal_Int32 j=0; j < nPropCount; j++ ) + { + if( CTF_SIZETYPE == getPropertySetMapper() + ->GetEntryContextId( j ) ) + { + const_cast < XMLTextImportPropertyMapper * > ( this ) + ->nSizeTypeIndex = j; + break; + } + } + } + if( nSizeTypeIndex != -1 ) + { + XMLPropertyState aSizeTypeState( nSizeTypeIndex ); + aSizeTypeState.maValue <<= static_cast( bHasAnyMinHeight + ? SizeType::MIN + : SizeType::FIX); + rProperties.push_back( aSizeTypeState ); + } + } + + if( !bHasAnyWidth ) + return; + + if( nWidthTypeIndex == -2 ) + { + const_cast < XMLTextImportPropertyMapper * > ( this ) + ->nWidthTypeIndex = -1; + sal_Int32 nCount = getPropertySetMapper()->GetEntryCount(); + for( sal_Int32 j=0; j < nCount; j++ ) + { + if( CTF_FRAMEWIDTH_TYPE == getPropertySetMapper() + ->GetEntryContextId( j ) ) + { + const_cast < XMLTextImportPropertyMapper * > ( this ) + ->nWidthTypeIndex = j; + break; + } + } + } + if( nWidthTypeIndex != -1 ) + { + XMLPropertyState aSizeTypeState( nWidthTypeIndex ); + aSizeTypeState.maValue <<= static_cast( bHasAnyMinWidth + ? SizeType::MIN + : SizeType::FIX); + rProperties.push_back( aSizeTypeState ); + } + + // DO NOT USE ITERATORS/POINTERS INTO THE rProperties-VECTOR AFTER + // THIS LINE. All iterators into the rProperties-vector, especially all + // pXXX-type variables set in the first switch statement of this method, + // may have been invalidated by the above push_back() calls! +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtlists.cxx b/xmloff/source/text/txtlists.cxx new file mode 100644 index 000000000..9b3b46f17 --- /dev/null +++ b/xmloff/source/text/txtlists.cxx @@ -0,0 +1,499 @@ +/* -*- 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 +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include "XMLTextListItemContext.hxx" +#include "XMLTextListBlockContext.hxx" +#include "txtparai.hxx" + + +using namespace ::com::sun::star; + + +XMLTextListsHelper::XMLTextListsHelper() + // Inconsistent behavior regarding lists (#i92811#) +{ +} + +void XMLTextListsHelper::PushListContext( + XMLTextListBlockContext *i_pListBlock) +{ + mListStack.emplace(i_pListBlock, + static_cast(nullptr), + static_cast(nullptr)); +} + +void XMLTextListsHelper::PushListContext( + XMLNumberedParaContext *i_pNumberedParagraph) +{ + mListStack.emplace( + static_cast(nullptr), + static_cast(nullptr), i_pNumberedParagraph); +} + +void XMLTextListsHelper::PopListContext() +{ + assert(mListStack.size()); + if ( !mListStack.empty()) + mListStack.pop(); +} + +void XMLTextListsHelper::ListContextTop( + XMLTextListBlockContext*& o_pListBlockContext, + XMLTextListItemContext*& o_pListItemContext, + XMLNumberedParaContext*& o_pNumberedParagraphContext ) +{ + if ( !mListStack.empty() ) { + o_pListBlockContext = + static_cast(std::get<0>(mListStack.top()).get()); + o_pListItemContext = + static_cast(std::get<1>(mListStack.top()).get()); + o_pNumberedParagraphContext = + static_cast(std::get<2>(mListStack.top()).get()); + } +} + +void XMLTextListsHelper::SetListItem( XMLTextListItemContext *i_pListItem ) +{ + // may be cleared by ListBlockContext for upper list... + if (i_pListItem) { + assert(mListStack.size()); + assert(std::get<0>(mListStack.top()).is() && + "internal error: SetListItem: mListStack has no ListBlock"); + assert(!std::get<1>(mListStack.top()).is() && + "error: SetListItem: list item already exists"); + } + if ( !mListStack.empty() ) { + std::get<1>(mListStack.top()) = i_pListItem; + } +} + +// Handling for parameter (#i92811#) +void XMLTextListsHelper::KeepListAsProcessed( const OUString& sListId, + const OUString& sListStyleName, + const OUString& sContinueListId, + const OUString& sListStyleDefaultListId ) +{ + if ( IsListProcessed( sListId ) ) + { + assert(false && + " - list id already added" ); + return; + } + + if ( !mpProcessedLists ) + { + mpProcessedLists = std::make_unique(); + } + + ::std::pair< OUString, OUString > + aListData( sListStyleName, sContinueListId ); + (*mpProcessedLists)[ sListId ] = aListData; + + msLastProcessedListId = sListId; + msListStyleOfLastProcessedList = sListStyleName; + + // Remember what is the last list id of this list style. + if (!mpStyleNameLastListIds) + { + mpStyleNameLastListIds = std::make_unique>(); + } + (*mpStyleNameLastListIds)[sListStyleName] = sListId; + + // Inconsistent behavior regarding lists (#i92811#) + if ( sListStyleDefaultListId.isEmpty()) + return; + + if ( !mpMapListIdToListStyleDefaultListId ) + { + mpMapListIdToListStyleDefaultListId = std::make_unique(); + } + + if ( mpMapListIdToListStyleDefaultListId->find( sListStyleName ) == + mpMapListIdToListStyleDefaultListId->end() ) + { + ::std::pair< OUString, OUString > + aListIdMapData( sListId, sListStyleDefaultListId ); + (*mpMapListIdToListStyleDefaultListId)[ sListStyleName ] = + aListIdMapData; + } +} + +bool XMLTextListsHelper::IsListProcessed( const OUString& sListId ) const +{ + if ( !mpProcessedLists ) + { + return false; + } + + return mpProcessedLists->find( sListId ) != mpProcessedLists->end(); +} + +OUString XMLTextListsHelper::GetListStyleOfProcessedList( + const OUString& sListId ) const +{ + if ( mpProcessedLists ) + { + tMapForLists::const_iterator aIter = mpProcessedLists->find( sListId ); + if ( aIter != mpProcessedLists->end() ) + { + return (*aIter).second.first; + } + } + + return OUString(); +} + +OUString XMLTextListsHelper::GetContinueListIdOfProcessedList( + const OUString& sListId ) const +{ + if ( mpProcessedLists ) + { + tMapForLists::const_iterator aIter = mpProcessedLists->find( sListId ); + if ( aIter != mpProcessedLists->end() ) + { + return (*aIter).second.second; + } + } + + return OUString(); +} + + +OUString XMLTextListsHelper::GenerateNewListId() const +{ + static bool bHack = (getenv("LIBO_ONEWAY_STABLE_ODF_EXPORT") != nullptr); + OUString sTmpStr( "list" ); + + if (bHack) + { + static sal_Int64 nIdCounter = SAL_CONST_INT64(5000000000); + sTmpStr += OUString::number(nIdCounter++); + } + else + { + // Value of xml:id in element has to be a valid ID type (#i92478#) + DateTime aDateTime( DateTime::SYSTEM ); + sal_Int64 n = aDateTime.GetTime(); + n += aDateTime.GetDateUnsigned(); + n += comphelper::rng::uniform_int_distribution(0, std::numeric_limits::max()); + // Value of xml:id in element has to be a valid ID type (#i92478#) + sTmpStr += OUString::number( n ); + } + + OUString sNewListId( sTmpStr ); + if ( mpProcessedLists ) + { + tools::Long nHitCount = 0; + while ( mpProcessedLists->find( sNewListId ) != mpProcessedLists->end() ) + { + ++nHitCount; + sNewListId = sTmpStr + OUString::number( nHitCount ); + } + } + + return sNewListId; +} + +// Provide list id for a certain list block for import (#i92811#) +OUString XMLTextListsHelper::GetListIdForListBlock( XMLTextListBlockContext const & rListBlock ) +{ + OUString sListBlockListId( rListBlock.GetContinueListId() ); + if ( sListBlockListId.isEmpty() ) + { + sListBlockListId = rListBlock.GetListId(); + } + + if ( mpMapListIdToListStyleDefaultListId ) + { + if ( !sListBlockListId.isEmpty() ) + { + const OUString sListStyleName = + GetListStyleOfProcessedList( sListBlockListId ); + + tMapForLists::const_iterator aIter = + mpMapListIdToListStyleDefaultListId->find( sListStyleName ); + if ( aIter != mpMapListIdToListStyleDefaultListId->end() ) + { + if ( (*aIter).second.first == sListBlockListId ) + { + sListBlockListId = (*aIter).second.second; + } + } + } + } + + return sListBlockListId; +} + +void XMLTextListsHelper::StoreLastContinuingList( const OUString& sListId, + const OUString& sContinuingListId ) +{ + if ( !mpContinuingLists ) + { + mpContinuingLists = std::make_unique(); + } + + (*mpContinuingLists)[ sListId ] = sContinuingListId; +} + +OUString XMLTextListsHelper::GetLastContinuingListId( + const OUString& sListId ) const +{ + if ( mpContinuingLists ) + { + tMapForContinuingLists::const_iterator aIter = + mpContinuingLists->find( sListId ); + if ( aIter != mpContinuingLists->end() ) + { + return (*aIter).second; + } + } + + return sListId; +} + +void XMLTextListsHelper::PushListOnStack( const OUString& sListId, + const OUString& sListStyleName ) +{ + if ( !mpListStack ) + { + mpListStack = std::make_unique(); + } + ::std::pair< OUString, OUString > + aListData( sListId, sListStyleName ); + mpListStack->push_back( aListData ); +} +void XMLTextListsHelper::PopListFromStack() +{ + if ( mpListStack && + !mpListStack->empty() ) + { + mpListStack->pop_back(); + } +} + +bool XMLTextListsHelper::EqualsToTopListStyleOnStack( std::u16string_view sListId ) const +{ + return mpListStack && sListId == mpListStack->back().second; +} + +OUString +XMLTextListsHelper::GetNumberedParagraphListId( + const sal_uInt16 i_Level, + std::u16string_view i_StyleName) +{ + if (i_StyleName.empty()) { + SAL_INFO("xmloff.text", "invalid numbered-paragraph: no style-name"); + } + if (!i_StyleName.empty() + && (i_Level < mLastNumberedParagraphs.size()) + && (mLastNumberedParagraphs[i_Level].first == i_StyleName) ) + { + assert(!mLastNumberedParagraphs[i_Level].second.isEmpty() && + "internal error: numbered-paragraph style-name but no list-id?"); + return mLastNumberedParagraphs[i_Level].second; + } else { + return GenerateNewListId(); + } +} + +static void +ClampLevel(uno::Reference const& i_xNumRules, + sal_Int16 & io_rLevel) +{ + assert(i_xNumRules.is()); + if (i_xNumRules.is()) { + const sal_Int32 nLevelCount( i_xNumRules->getCount() ); + if ( io_rLevel >= nLevelCount ) { + io_rLevel = sal::static_int_cast< sal_Int16 >(nLevelCount-1); + } + } +} + +uno::Reference +XMLTextListsHelper::EnsureNumberedParagraph( + SvXMLImport & i_rImport, + const OUString& i_ListId, + sal_Int16 & io_rLevel, const OUString& i_StyleName) +{ + assert(!i_ListId.isEmpty()); + assert(io_rLevel >= 0); + NumParaList_t & rNPList( mNPLists[i_ListId] ); + const OUString none; // default + if ( rNPList.empty() ) { + // create default list style for top level + sal_Int16 lev(0); + rNPList.emplace_back(none, + MakeNumRule(i_rImport, nullptr, none, none, lev) ); + } + // create num rule first because this might clamp the level... + uno::Reference xNumRules; + if ((0 == io_rLevel) || rNPList.empty() || !i_StyleName.isEmpty()) { + // no parent to inherit from, or explicit style given => new numrules! + // index of parent: level - 1, but maybe that does not exist + const size_t parent( std::min(static_cast(io_rLevel), + rNPList.size()) - 1 ); + xNumRules = MakeNumRule(i_rImport, + io_rLevel > 0 ? rNPList[parent].second : nullptr, + io_rLevel > 0 ? rNPList[parent].first : none, + i_StyleName, io_rLevel); + } else { + // no style given, but has a parent => reuse parent numrules! + ClampLevel(rNPList.back().second, io_rLevel); + } + if (static_cast(io_rLevel) + 1U > rNPList.size()) { + // new level: need to enlarge + for (size_t i = rNPList.size(); + i < o3tl::make_unsigned(io_rLevel); ++i) + { + NumParaList_t::value_type const rule(rNPList.back()); + rNPList.push_back(rule); + } + NumParaList_t::value_type const rule(rNPList.back()); + rNPList.push_back(xNumRules.is() + ? ::std::make_pair(i_StyleName, xNumRules) + : rule); + } else { + // old level: no need to enlarge; possibly shrink + if (xNumRules.is()) { + rNPList[io_rLevel] = std::make_pair(i_StyleName, xNumRules); + } + if (static_cast(io_rLevel) + 1U < rNPList.size()) { + rNPList.erase(rNPList.begin() + io_rLevel + 1, rNPList.end()); + } + } + // remember the list id + if (mLastNumberedParagraphs.size() <= o3tl::make_unsigned(io_rLevel)) { + mLastNumberedParagraphs.resize(io_rLevel+1); + } + mLastNumberedParagraphs[io_rLevel] = std::make_pair(i_StyleName, i_ListId); + return rNPList.back().second; +} + +/** extracted from the XMLTextListBlockContext constructor */ +uno::Reference +XMLTextListsHelper::MakeNumRule( + SvXMLImport & i_rImport, + const uno::Reference& i_rNumRule, + std::u16string_view i_ParentStyleName, + const OUString& i_StyleName, + sal_Int16 & io_rLevel, + bool* o_pRestartNumbering, + bool* io_pSetDefaults) +{ + uno::Reference xNumRules(i_rNumRule); + if ( !i_StyleName.isEmpty() && i_StyleName != i_ParentStyleName ) + { + const OUString sDisplayStyleName( + i_rImport.GetStyleDisplayName( XmlStyleFamily::TEXT_LIST, + i_StyleName) ); + const uno::Reference < container::XNameContainer >& rNumStyles( + i_rImport.GetTextImport()->GetNumberingStyles() ); + if( rNumStyles.is() && rNumStyles->hasByName( sDisplayStyleName ) ) + { + uno::Reference < style::XStyle > xStyle; + uno::Any any = rNumStyles->getByName( sDisplayStyleName ); + any >>= xStyle; + + uno::Reference< beans::XPropertySet > xPropSet( xStyle, + uno::UNO_QUERY ); + any = xPropSet->getPropertyValue("NumberingRules"); + any >>= xNumRules; + } + else + { + const SvxXMLListStyleContext *pListStyle( + i_rImport.GetTextImport()->FindAutoListStyle( i_StyleName ) ); + if( pListStyle ) + { + xNumRules = pListStyle->GetNumRules(); + if( !xNumRules.is() ) + { + pListStyle->CreateAndInsertAuto(); + xNumRules = pListStyle->GetNumRules(); + } + } + } + } + + bool bSetDefaults(io_pSetDefaults && *io_pSetDefaults); + if ( !xNumRules.is() ) + { + // If no style name has been specified for this style and for any + // parent or if no num rule with the specified name exists, + // create a new one. + + xNumRules = + SvxXMLListStyleContext::CreateNumRule( i_rImport.GetModel() ); + SAL_INFO_IF(xNumRules.is(), "xmloff.core", "cannot create numrules"); + if ( !xNumRules.is() ) + return xNumRules; + + // Because it is a new num rule, numbering must not be restarted. + if (o_pRestartNumbering) *o_pRestartNumbering = false; + bSetDefaults = true; + if (io_pSetDefaults) *io_pSetDefaults = bSetDefaults; + } + + ClampLevel(xNumRules, io_rLevel); + + if ( bSetDefaults ) + { + // Because there is no list style sheet for this style, a default + // format must be set for any level of this num rule. + SvxXMLListStyleContext::SetDefaultStyle( xNumRules, io_rLevel, + false ); + } + + return xNumRules; +} + +OUString XMLTextListsHelper::GetLastIdOfStyleName(const OUString& sListStyleName) const +{ + if (!mpStyleNameLastListIds) + { + return {}; + } + + auto it = mpStyleNameLastListIds->find(sListStyleName); + if (it == mpStyleNameLastListIds->end()) + { + return {}; + } + + return it->second; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx new file mode 100644 index 000000000..e310d4c9c --- /dev/null +++ b/xmloff/source/text/txtparae.cxx @@ -0,0 +1,4123 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include "txtexppr.hxx" +#include +#include "XMLAnchorTypePropHdl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include "XMLTextNumRuleInfo.hxx" +#include +#include +#include "XMLSectionExport.hxx" +#include "XMLIndexMarkExport.hxx" +#include +#include "XMLRedlineExport.hxx" +#include +#include +#include "XMLTextCharStyleNamesElementExport.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace ::std; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::graphic; +using namespace ::xmloff; +using namespace ::xmloff::token; + +// Implement Title/Description Elements UI (#i73249#) +constexpr OUStringLiteral gsTitle(u"Title"); +constexpr OUStringLiteral gsDescription(u"Description"); +constexpr OUStringLiteral gsAnchorPageNo(u"AnchorPageNo"); +constexpr OUStringLiteral gsAnchorType(u"AnchorType"); +constexpr OUStringLiteral gsBookmark(u"Bookmark"); +constexpr OUStringLiteral gsChainNextName(u"ChainNextName"); +constexpr OUStringLiteral gsContourPolyPolygon(u"ContourPolyPolygon"); +constexpr OUStringLiteral gsDocumentIndexMark(u"DocumentIndexMark"); +constexpr OUStringLiteral gsFrame(u"Frame"); +constexpr OUStringLiteral gsGraphicFilter(u"GraphicFilter"); +constexpr OUStringLiteral gsGraphicRotation(u"GraphicRotation"); +constexpr OUStringLiteral gsHeight(u"Height"); +constexpr OUStringLiteral gsHoriOrient(u"HoriOrient"); +constexpr OUStringLiteral gsHoriOrientPosition(u"HoriOrientPosition"); +constexpr OUStringLiteral gsHyperLinkName(u"HyperLinkName"); +constexpr OUStringLiteral gsHyperLinkTarget(u"HyperLinkTarget"); +constexpr OUStringLiteral gsHyperLinkURL(u"HyperLinkURL"); +constexpr OUStringLiteral gsIsAutomaticContour(u"IsAutomaticContour"); +constexpr OUStringLiteral gsIsCollapsed(u"IsCollapsed"); +constexpr OUStringLiteral gsIsPixelContour(u"IsPixelContour"); +constexpr OUStringLiteral gsIsStart(u"IsStart"); +constexpr OUStringLiteral gsIsSyncHeightToWidth(u"IsSyncHeightToWidth"); +constexpr OUStringLiteral gsIsSyncWidthToHeight(u"IsSyncWidthToHeight"); +constexpr OUStringLiteral gsNumberingRules(u"NumberingRules"); +constexpr OUStringLiteral gsParaConditionalStyleName(u"ParaConditionalStyleName"); +constexpr OUStringLiteral gsParagraphService(u"com.sun.star.text.Paragraph"); +constexpr OUStringLiteral gsRedline(u"Redline"); +constexpr OUStringLiteral gsReferenceMark(u"ReferenceMark"); +constexpr OUStringLiteral gsRelativeHeight(u"RelativeHeight"); +constexpr OUStringLiteral gsRelativeWidth(u"RelativeWidth"); +constexpr OUStringLiteral gsRuby(u"Ruby"); +constexpr OUStringLiteral gsRubyCharStyleName(u"RubyCharStyleName"); +constexpr OUStringLiteral gsRubyText(u"RubyText"); +constexpr OUStringLiteral gsServerMap(u"ServerMap"); +constexpr OUStringLiteral gsShapeService(u"com.sun.star.drawing.Shape"); +constexpr OUStringLiteral gsSizeType(u"SizeType"); +constexpr OUStringLiteral gsSoftPageBreak( u"SoftPageBreak" ); +constexpr OUStringLiteral gsTableService(u"com.sun.star.text.TextTable"); +constexpr OUStringLiteral gsText(u"Text"); +constexpr OUStringLiteral gsTextContentService(u"com.sun.star.text.TextContent"); +constexpr OUStringLiteral gsTextEmbeddedService(u"com.sun.star.text.TextEmbeddedObject"); +constexpr OUStringLiteral gsTextField(u"TextField"); +constexpr OUStringLiteral gsTextFieldService(u"com.sun.star.text.TextField"); +constexpr OUStringLiteral gsTextFrameService(u"com.sun.star.text.TextFrame"); +constexpr OUStringLiteral gsTextGraphicService(u"com.sun.star.text.TextGraphicObject"); +constexpr OUStringLiteral gsTextPortionType(u"TextPortionType"); +constexpr OUStringLiteral gsUnvisitedCharStyleName(u"UnvisitedCharStyleName"); +constexpr OUStringLiteral gsVertOrient(u"VertOrient"); +constexpr OUStringLiteral gsVertOrientPosition(u"VertOrientPosition"); +constexpr OUStringLiteral gsVisitedCharStyleName(u"VisitedCharStyleName"); +constexpr OUStringLiteral gsWidth(u"Width"); +constexpr OUStringLiteral gsWidthType( u"WidthType" ); +constexpr OUStringLiteral gsTextFieldStart( u"TextFieldStart" ); +constexpr OUStringLiteral gsTextFieldSep(u"TextFieldSeparator"); +constexpr OUStringLiteral gsTextFieldEnd( u"TextFieldEnd" ); +constexpr OUStringLiteral gsTextFieldStartEnd( u"TextFieldStartEnd" ); + +namespace +{ + class TextContentSet + { + public: + typedef list> contents_t; + typedef back_insert_iterator inserter_t; + typedef contents_t::const_iterator const_iterator_t; + + inserter_t getInserter() + { return back_insert_iterator(m_vTextContents); }; + const_iterator_t getBegin() const + { return m_vTextContents.begin(); }; + const_iterator_t getEnd() const + { return m_vTextContents.end(); }; + + private: + contents_t m_vTextContents; + }; + + struct FrameRefHash + { + size_t operator()(const Reference& rFrame) const + { return sal::static_int_cast(reinterpret_cast(rFrame.get())); } + }; + + bool lcl_TextContentsUnfiltered(const Reference&) + { return true; }; + + bool lcl_ShapeFilter(const Reference& xTxtContent) + { + Reference xShape(xTxtContent, UNO_QUERY); + if(!xShape.is()) + return false; + Reference xServiceInfo(xTxtContent, UNO_QUERY); + return !xServiceInfo->supportsService("com.sun.star.text.TextFrame") && + !xServiceInfo->supportsService("com.sun.star.text.TextGraphicObject") && + !xServiceInfo->supportsService("com.sun.star.text.TextEmbeddedObject"); + }; + + class BoundFrames + { + public: + typedef bool (*filter_t)(const Reference&); + BoundFrames( + const Reference& rEnumAccess, + const filter_t& rFilter) + : m_xEnumAccess(rEnumAccess) + { + Fill(rFilter); + }; + BoundFrames() + {}; + const TextContentSet& GetPageBoundContents() const + { return m_vPageBounds; }; + const TextContentSet* GetFrameBoundContents(const Reference& rParentFrame) const + { + framebound_map_t::const_iterator it = m_vFrameBoundsOf.find(rParentFrame); + if(it == m_vFrameBoundsOf.end()) + return nullptr; + return &(it->second); + }; + Reference createEnumeration() const + { + if(!m_xEnumAccess.is()) + return Reference(); + return m_xEnumAccess->createEnumeration(); + }; + + private: + typedef std::unordered_map< + Reference, + TextContentSet, + FrameRefHash> framebound_map_t; + TextContentSet m_vPageBounds; + framebound_map_t m_vFrameBoundsOf; + const Reference m_xEnumAccess; + void Fill(const filter_t& rFilter); + }; + + class FieldParamExporter + { + public: + FieldParamExporter(SvXMLExport* const pExport, Reference const & xFieldParams) + : m_pExport(pExport) + , m_xFieldParams(xFieldParams) + { }; + void Export(); + + private: + SvXMLExport* const m_pExport; + const Reference m_xFieldParams; + + void ExportParameter(const OUString& sKey, const OUString& sValue); + }; + + struct HyperlinkData + { + OUString href, name, targetFrame, ustyleName, vstyleName; + bool serverMap = false; + css::uno::Reference events; + + HyperlinkData() = default; + HyperlinkData(const css::uno::Reference& rPropSet); + + bool operator==(const HyperlinkData&); + bool operator!=(const HyperlinkData& rOther) { return !operator==(rOther); } + + bool addHyperlinkAttributes(SvXMLExport& rExport); + void exportEvents(SvXMLExport& rExport); + }; + + HyperlinkData::HyperlinkData(const css::uno::Reference& rPropSet) + { + const css::uno::Reference xPropState(rPropSet, UNO_QUERY); + const auto xPropSetInfo(rPropSet->getPropertySetInfo()); + if (xPropSetInfo->hasPropertyByName(gsHyperLinkURL) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkURL))) + { + rPropSet->getPropertyValue(gsHyperLinkURL) >>= href; + } + + if (href.isEmpty()) + return; + + if (xPropSetInfo->hasPropertyByName(gsHyperLinkName) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkName))) + { + rPropSet->getPropertyValue(gsHyperLinkName) >>= name; + } + + if (xPropSetInfo->hasPropertyByName(gsHyperLinkTarget) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsHyperLinkTarget))) + { + rPropSet->getPropertyValue(gsHyperLinkTarget) >>= targetFrame; + } + + if (xPropSetInfo->hasPropertyByName(gsServerMap) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE == xPropState->getPropertyState(gsServerMap))) + { + serverMap = *o3tl::doAccess(rPropSet->getPropertyValue(gsServerMap)); + } + + if (xPropSetInfo->hasPropertyByName(gsUnvisitedCharStyleName) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE + == xPropState->getPropertyState(gsUnvisitedCharStyleName))) + { + rPropSet->getPropertyValue(gsUnvisitedCharStyleName) >>= ustyleName; + } + + if (xPropSetInfo->hasPropertyByName(gsVisitedCharStyleName) + && (!xPropState.is() + || PropertyState_DIRECT_VALUE + == xPropState->getPropertyState(gsVisitedCharStyleName))) + { + rPropSet->getPropertyValue(gsVisitedCharStyleName) >>= vstyleName; + } + + static constexpr OUStringLiteral sHyperLinkEvents(u"HyperLinkEvents"); + if (xPropSetInfo->hasPropertyByName(sHyperLinkEvents)) + { + events.set(rPropSet->getPropertyValue(sHyperLinkEvents), uno::UNO_QUERY); + } + } + + bool HyperlinkData::operator==(const HyperlinkData& rOther) + { + if (href != rOther.href || name != rOther.name || targetFrame != rOther.targetFrame + || ustyleName != rOther.ustyleName || vstyleName != rOther.vstyleName + || serverMap != rOther.serverMap) + return false; + + if (events == rOther.events) + return true; + if (!events || !rOther.events) + return false; + + const css::uno::Sequence aNames = events->getElementNames(); + if (aNames != rOther.events->getElementNames()) + return false; + for (const auto& rName : aNames) + { + const css::uno::Any aAny = events->getByName(rName); + const css::uno::Any aOtherAny = rOther.events->getByName(rName); + if (aAny != aOtherAny) + return false; + } + return true; + } + + bool HyperlinkData::addHyperlinkAttributes(SvXMLExport& rExport) + { + if (href.isEmpty()) + { + // hyperlink without a URL does not make sense + OSL_ENSURE(false, "hyperlink without a URL --> no export to ODF"); + return false; + } + + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, rExport.GetRelativeReference(href)); + + if (!name.isEmpty()) + rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, name); + + if (!targetFrame.isEmpty()) + { + rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_TARGET_FRAME_NAME, targetFrame); + enum XMLTokenEnum eTok = targetFrame == "_blank" ? XML_NEW : XML_REPLACE; + rExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, eTok); + } + + if (serverMap) + rExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_SERVER_MAP, XML_TRUE); + + if (!ustyleName.isEmpty()) + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, + rExport.EncodeStyleName(ustyleName)); + + if (!vstyleName.isEmpty()) + rExport.AddAttribute(XML_NAMESPACE_TEXT, XML_VISITED_STYLE_NAME, + rExport.EncodeStyleName(vstyleName)); + + return true; + } + + void HyperlinkData::exportEvents(SvXMLExport& rExport) + { + // export events (if supported) + if (events) + rExport.GetEventExport().Export(events, false); + } +} + +namespace xmloff +{ + class BoundFrameSets + { + public: + explicit BoundFrameSets(const Reference& rModel); + const BoundFrames* GetTexts() const + { return m_pTexts.get(); }; + const BoundFrames* GetGraphics() const + { return m_pGraphics.get(); }; + const BoundFrames* GetEmbeddeds() const + { return m_pEmbeddeds.get(); }; + const BoundFrames* GetShapes() const + { return m_pShapes.get(); }; + private: + unique_ptr m_pTexts; + unique_ptr m_pGraphics; + unique_ptr m_pEmbeddeds; + unique_ptr m_pShapes; + }; +} + +#ifdef DBG_UTIL +static bool txtparae_bContainsIllegalCharacters = false; +#endif + +// The following map shows which property values are required: + +// property auto style pass export + +// ParaStyleName if style exists always +// ParaConditionalStyleName if style exists always +// NumberingRules if style exists always +// TextSection always always +// ParaChapterNumberingLevel never always +// NumberingIsNumber never always + +// The conclusion is that for auto styles the first three properties +// should be queried using a multi property set if, and only if, an +// auto style needs to be exported. TextSection should be queried by +// an individual call to getPropertyvalue, because this seems to be +// less expensive than querying the first three properties if they aren't +// required. + +// For the export pass all properties can be queried using a multi property +// set. + +static const char* aParagraphPropertyNamesAuto[] = +{ + "NumberingRules", + "ParaConditionalStyleName", + "ParaStyleName", + nullptr +}; + +namespace { + +enum eParagraphPropertyNamesEnumAuto +{ + NUMBERING_RULES_AUTO = 0, + PARA_CONDITIONAL_STYLE_NAME_AUTO = 1, + PARA_STYLE_NAME_AUTO = 2 +}; + +} + +static const char* aParagraphPropertyNames[] = +{ + "NumberingIsNumber", + "NumberingStyleName", + "OutlineLevel", + "ParaConditionalStyleName", + "ParaStyleName", + "TextSection", + "OutlineContentVisible", + nullptr +}; + +namespace { + +enum eParagraphPropertyNamesEnum +{ + NUMBERING_IS_NUMBER = 0, + PARA_NUMBERING_STYLENAME = 1, + PARA_OUTLINE_LEVEL=2, + PARA_CONDITIONAL_STYLE_NAME = 3, + PARA_STYLE_NAME = 4, + TEXT_SECTION = 5, + PARA_OUTLINE_CONTENT_VISIBLE = 6 +}; + +} + +void BoundFrames::Fill(const filter_t& rFilter) +{ + if(!m_xEnumAccess.is()) + return; + const Reference< XEnumeration > xEnum = m_xEnumAccess->createEnumeration(); + if(!xEnum.is()) + return; + static const OUStringLiteral our_sAnchorType(u"AnchorType"); + static const OUStringLiteral our_sAnchorFrame(u"AnchorFrame"); + while(xEnum->hasMoreElements()) + { + Reference xPropSet(xEnum->nextElement(), UNO_QUERY); + Reference xTextContent(xPropSet, UNO_QUERY); + if(!xPropSet.is() || !xTextContent.is()) + continue; + TextContentAnchorType eAnchor; + xPropSet->getPropertyValue(our_sAnchorType) >>= eAnchor; + if(TextContentAnchorType_AT_PAGE != eAnchor && TextContentAnchorType_AT_FRAME != eAnchor) + continue; + if(!rFilter(xTextContent)) + continue; + + TextContentSet::inserter_t pInserter = m_vPageBounds.getInserter(); + if(TextContentAnchorType_AT_FRAME == eAnchor) + { + Reference xAnchorTxtFrame( + xPropSet->getPropertyValue(our_sAnchorFrame), + uno::UNO_QUERY); + pInserter = m_vFrameBoundsOf[xAnchorTxtFrame].getInserter(); + } + *pInserter++ = xTextContent; + } +} + +BoundFrameSets::BoundFrameSets(const Reference& rModel) + : m_pTexts(new BoundFrames()) + , m_pGraphics(new BoundFrames()) + , m_pEmbeddeds(new BoundFrames()) + , m_pShapes(new BoundFrames()) +{ + const Reference xTFS(rModel, UNO_QUERY); + const Reference xGOS(rModel, UNO_QUERY); + const Reference xEOS(rModel, UNO_QUERY); + const Reference xDPS(rModel, UNO_QUERY); + if(xTFS.is()) + m_pTexts.reset(new BoundFrames( + Reference(xTFS->getTextFrames(), UNO_QUERY), + &lcl_TextContentsUnfiltered)); + if(xGOS.is()) + m_pGraphics.reset(new BoundFrames( + Reference(xGOS->getGraphicObjects(), UNO_QUERY), + &lcl_TextContentsUnfiltered)); + if(xEOS.is()) + m_pEmbeddeds.reset(new BoundFrames( + Reference(xEOS->getEmbeddedObjects(), UNO_QUERY), + &lcl_TextContentsUnfiltered)); + if(xDPS.is()) + m_pShapes.reset(new BoundFrames( + Reference(xDPS->getDrawPage(), UNO_QUERY), + &lcl_ShapeFilter)); +}; + +void FieldParamExporter::Export() +{ + const Type aStringType = ::cppu::UnoType::get(); + const Type aBoolType = cppu::UnoType::get(); + const Type aSeqType = cppu::UnoType>::get(); + const Type aIntType = ::cppu::UnoType::get(); + const Sequence vParameters(m_xFieldParams->getElementNames()); + for(const auto & rParameter : vParameters) + { + const Any aValue = m_xFieldParams->getByName(rParameter); + const Type& aValueType = aValue.getValueType(); + if(aValueType == aStringType) + { + OUString sValue; + aValue >>= sValue; + ExportParameter(rParameter,sValue); + + if ( rParameter == ODF_OLE_PARAM ) + { + // Save the OLE object + Reference< embed::XStorage > xTargetStg = m_pExport->GetTargetStorage(); + if (xTargetStg.is()) { + Reference< embed::XStorage > xDstStg = xTargetStg->openStorageElement( + "OLELinks", embed::ElementModes::WRITE ); + + if ( !xDstStg->hasByName( sValue ) ) { + Reference< XStorageBasedDocument > xStgDoc ( + m_pExport->GetModel( ), UNO_QUERY ); + Reference< embed::XStorage > xDocStg = xStgDoc->getDocumentStorage(); + Reference< embed::XStorage > xOleStg = xDocStg->openStorageElement( + "OLELinks", embed::ElementModes::READ ); + + xOleStg->copyElementTo( sValue, xDstStg, sValue ); + Reference< embed::XTransactedObject > xTransact( xDstStg, UNO_QUERY ); + if ( xTransact.is( ) ) + xTransact->commit( ); + } + } else { + SAL_WARN("xmloff", "no target storage"); + } + } + } + else if(aValueType == aBoolType) + { + bool bValue = false; + aValue >>= bValue; + ExportParameter(rParameter, OUString::boolean(bValue) ); + } + else if(aValueType == aSeqType) + { + Sequence vValue; + aValue >>= vValue; + for(const OUString & i : std::as_const(vValue)) + { + ExportParameter(rParameter, i); + } + } + else if(aValueType == aIntType) + { + sal_Int32 nValue = 0; + aValue >>= nValue; + ExportParameter(rParameter, OUString::number(nValue)); + } + } +} + +void FieldParamExporter::ExportParameter(const OUString& sKey, const OUString& sValue) +{ + m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_NAME, sKey); + m_pExport->AddAttribute(XML_NAMESPACE_FIELD, XML_VALUE, sValue); + m_pExport->StartElement(XML_NAMESPACE_FIELD, XML_PARAM, false); + m_pExport->EndElement(XML_NAMESPACE_FIELD, XML_PARAM, false); +} + +void XMLTextParagraphExport::Add( XmlStyleFamily nFamily, + const Reference < XPropertySet > & rPropSet, + const o3tl::span aAddStates, + bool bDontSeek ) +{ + rtl::Reference < SvXMLExportPropertyMapper > xPropMapper; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + xPropMapper = GetParaPropMapper(); + break; + case XmlStyleFamily::TEXT_TEXT: + xPropMapper = GetTextPropMapper(); + break; + case XmlStyleFamily::TEXT_FRAME: + xPropMapper = GetAutoFramePropMapper(); + break; + case XmlStyleFamily::TEXT_SECTION: + xPropMapper = GetSectionPropMapper(); + break; + case XmlStyleFamily::TEXT_RUBY: + xPropMapper = GetRubyPropMapper(); + break; + default: break; + } + SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" ); + + vector< XMLPropertyState > aPropStates = + xPropMapper->Filter(GetExport(), rPropSet); + + aPropStates.insert( aPropStates.end(), aAddStates.begin(), aAddStates.end() ); + + if( aPropStates.empty() ) + return; + + Reference< XPropertySetInfo > xPropSetInfo(rPropSet->getPropertySetInfo()); + OUString sParent, sCondParent; + sal_uInt16 nIgnoreProps = 0; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + if( xPropSetInfo->hasPropertyByName( gsParaStyleName ) ) + { + rPropSet->getPropertyValue( gsParaStyleName ) >>= sParent; + } + if( xPropSetInfo->hasPropertyByName( gsParaConditionalStyleName ) ) + { + rPropSet->getPropertyValue( gsParaConditionalStyleName ) >>= sCondParent; + } + if( xPropSetInfo->hasPropertyByName( gsNumberingRules ) ) + { + Reference < XIndexReplace > xNumRule(rPropSet->getPropertyValue( gsNumberingRules ), uno::UNO_QUERY); + if( xNumRule.is() && xNumRule->getCount() ) + { + Reference < XNamed > xNamed( xNumRule, UNO_QUERY ); + OUString sName; + if( xNamed.is() ) + sName = xNamed->getName(); + bool bAdd = sName.isEmpty(); + if( !bAdd ) + { + Reference < XPropertySet > xNumPropSet( xNumRule, + UNO_QUERY ); + if( xNumPropSet.is() && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "IsAutomatic" ) ) + { + bAdd = *o3tl::doAccess(xNumPropSet->getPropertyValue( "IsAutomatic" )); + // Check on outline style (#i73361#) + if ( bAdd && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "NumberingIsOutline" ) ) + { + bAdd = !(*o3tl::doAccess(xNumPropSet->getPropertyValue( "NumberingIsOutline" ))); + } + } + else + { + bAdd = true; + } + } + if( bAdd ) + maListAutoPool.Add( xNumRule ); + } + } + break; + case XmlStyleFamily::TEXT_TEXT: + { + // Get parent and remove hyperlinks (they aren't of interest) + rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper()); + for( ::std::vector< XMLPropertyState >::iterator i(aPropStates.begin()); + nIgnoreProps < 2 && i != aPropStates.end(); ) + { + if( i->mnIndex == -1 ) + { + ++i; + continue; + } + + switch( xPM->GetEntryContextId(i->mnIndex) ) + { + case CTF_CHAR_STYLE_NAME: + case CTF_HYPERLINK_URL: + i->mnIndex = -1; + nIgnoreProps++; + i = aPropStates.erase( i ); + break; + default: + ++i; + break; + } + } + } + break; + case XmlStyleFamily::TEXT_FRAME: + if( xPropSetInfo->hasPropertyByName( gsFrameStyleName ) ) + { + rPropSet->getPropertyValue( gsFrameStyleName ) >>= sParent; + } + break; + case XmlStyleFamily::TEXT_SECTION: + case XmlStyleFamily::TEXT_RUBY: + ; // section styles have no parents + break; + default: break; + } + if (aPropStates.size() - nIgnoreProps) + { + GetAutoStylePool().Add( nFamily, sParent, std::vector(aPropStates), bDontSeek ); + if( !sCondParent.isEmpty() && sParent != sCondParent ) + GetAutoStylePool().Add( nFamily, sCondParent, std::move(aPropStates) ); + } +} + +static bool lcl_validPropState( const XMLPropertyState& rState ) +{ + return rState.mnIndex != -1; +} + +void XMLTextParagraphExport::Add( XmlStyleFamily nFamily, + MultiPropertySetHelper& rPropSetHelper, + const Reference < XPropertySet > & rPropSet) +{ + rtl::Reference < SvXMLExportPropertyMapper > xPropMapper; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + xPropMapper = GetParaPropMapper(); + break; + default: break; + } + SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" ); + + vector aPropStates(xPropMapper->Filter(GetExport(), rPropSet)); + + if( rPropSetHelper.hasProperty( NUMBERING_RULES_AUTO ) ) + { + Reference < XIndexReplace > xNumRule(rPropSetHelper.getValue( NUMBERING_RULES_AUTO, + rPropSet, true ), uno::UNO_QUERY); + if( xNumRule.is() && xNumRule->getCount() ) + { + Reference < XNamed > xNamed( xNumRule, UNO_QUERY ); + OUString sName; + if( xNamed.is() ) + sName = xNamed->getName(); + bool bAdd = sName.isEmpty(); + if( !bAdd ) + { + Reference < XPropertySet > xNumPropSet( xNumRule, + UNO_QUERY ); + if( xNumPropSet.is() && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "IsAutomatic" ) ) + { + bAdd = *o3tl::doAccess(xNumPropSet->getPropertyValue( "IsAutomatic" )); + // Check on outline style (#i73361#) + if ( bAdd && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "NumberingIsOutline" ) ) + { + bAdd = !(*o3tl::doAccess(xNumPropSet->getPropertyValue( "NumberingIsOutline" ))); + } + } + else + { + bAdd = true; + } + } + if( bAdd ) + maListAutoPool.Add( xNumRule ); + } + } + + if( aPropStates.empty() ) + return; + + OUString sParent, sCondParent; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + if( rPropSetHelper.hasProperty( PARA_STYLE_NAME_AUTO ) ) + { + rPropSetHelper.getValue( PARA_STYLE_NAME_AUTO, rPropSet, + true ) >>= sParent; + } + if( rPropSetHelper.hasProperty( PARA_CONDITIONAL_STYLE_NAME_AUTO ) ) + { + rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME_AUTO, + rPropSet, true ) >>= sCondParent; + } + + break; + default: break; + } + + if( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) ) + { + GetAutoStylePool().Add( nFamily, sParent, std::vector(aPropStates) ); + if( !sCondParent.isEmpty() && sParent != sCondParent ) + GetAutoStylePool().Add( nFamily, sCondParent, std::move(aPropStates) ); + } +} + +OUString XMLTextParagraphExport::Find( + XmlStyleFamily nFamily, + const Reference < XPropertySet > & rPropSet, + const OUString& rParent, + const o3tl::span aAddStates) const +{ + OUString sName( rParent ); + rtl::Reference < SvXMLExportPropertyMapper > xPropMapper; + switch( nFamily ) + { + case XmlStyleFamily::TEXT_PARAGRAPH: + xPropMapper = GetParaPropMapper(); + break; + case XmlStyleFamily::TEXT_FRAME: + xPropMapper = GetAutoFramePropMapper(); + break; + case XmlStyleFamily::TEXT_SECTION: + xPropMapper = GetSectionPropMapper(); + break; + case XmlStyleFamily::TEXT_RUBY: + xPropMapper = GetRubyPropMapper(); + break; + default: break; + } + SAL_WARN_IF( !xPropMapper.is(), "xmloff", "There is the property mapper?" ); + if( !xPropMapper.is() ) + return sName; + vector aPropStates(xPropMapper->Filter(GetExport(), rPropSet)); + aPropStates.insert( aPropStates.end(), aAddStates.begin(), aAddStates.end() ); + if( std::any_of( aPropStates.begin(), aPropStates.end(), lcl_validPropState ) ) + sName = GetAutoStylePool().Find( nFamily, sName, aPropStates ); + + return sName; +} + +OUString XMLTextParagraphExport::FindTextStyle( + const Reference < XPropertySet > & rPropSet, + bool& rbHasCharStyle, + bool& rbHasAutoStyle, + const XMLPropertyState** ppAddStates ) const +{ + rtl::Reference < SvXMLExportPropertyMapper > xPropMapper(GetTextPropMapper()); + vector aPropStates(xPropMapper->Filter(GetExport(), rPropSet)); + + // Get parent and remove hyperlinks (they aren't of interest) + OUString sName; + rbHasCharStyle = rbHasAutoStyle = false; + sal_uInt16 nIgnoreProps = 0; + rtl::Reference< XMLPropertySetMapper > xPM(xPropMapper->getPropertySetMapper()); + ::std::vector< XMLPropertyState >::iterator aFirstDel = aPropStates.end(); + ::std::vector< XMLPropertyState >::iterator aSecondDel = aPropStates.end(); + + for( ::std::vector< XMLPropertyState >::iterator + i = aPropStates.begin(); + nIgnoreProps < 2 && i != aPropStates.end(); + ++i ) + { + if( i->mnIndex == -1 ) + continue; + + switch( xPM->GetEntryContextId(i->mnIndex) ) + { + case CTF_CHAR_STYLE_NAME: + i->maValue >>= sName; + i->mnIndex = -1; + rbHasCharStyle = !sName.isEmpty(); + if( nIgnoreProps ) + aSecondDel = i; + else + aFirstDel = i; + nIgnoreProps++; + break; + case CTF_HYPERLINK_URL: + i->mnIndex = -1; + if( nIgnoreProps ) + aSecondDel = i; + else + aFirstDel = i; + nIgnoreProps++; + break; + } + } + if( ppAddStates ) + { + while( *ppAddStates ) + { + aPropStates.push_back( **ppAddStates ); + ppAddStates++; + } + } + if (aPropStates.size() - nIgnoreProps) + { + // erase the character style, otherwise the autostyle cannot be found! + // erase the hyperlink, otherwise the autostyle cannot be found! + if ( nIgnoreProps ) + { + // If two elements of a vector have to be deleted, + // we should delete the second one first. + if( --nIgnoreProps ) + aPropStates.erase( aSecondDel ); + aPropStates.erase( aFirstDel ); + } + sName = GetAutoStylePool().Find( + XmlStyleFamily::TEXT_TEXT, + OUString(), // AutoStyles should not have parents! + aPropStates ); + rbHasAutoStyle = true; + } + + return sName; +} + +// adjustments to support lists independent from list style +void XMLTextParagraphExport::exportListChange( + const XMLTextNumRuleInfo& rPrevInfo, + const XMLTextNumRuleInfo& rNextInfo ) +{ + // end a list + if ( rPrevInfo.GetLevel() > 0 ) + { + sal_Int16 nListLevelsToBeClosed = 0; + if ( !rNextInfo.BelongsToSameList( rPrevInfo ) || + rNextInfo.GetLevel() <= 0 ) + { + // close complete previous list + nListLevelsToBeClosed = rPrevInfo.GetLevel(); + } + else if ( rPrevInfo.GetLevel() > rNextInfo.GetLevel() ) + { + // close corresponding sub lists + SAL_WARN_IF( rNextInfo.GetLevel() <= 0, "xmloff", + " 0> not hold. Serious defect." ); + nListLevelsToBeClosed = rPrevInfo.GetLevel() - rNextInfo.GetLevel(); + } + + if ( nListLevelsToBeClosed > 0 && + maListElements.size() >= sal::static_int_cast< sal_uInt32 >( 2 * nListLevelsToBeClosed ) ) + { + do { + for(size_t j = 0; j < 2; ++j) + { + OUString aElem(maListElements.back()); + maListElements.pop_back(); + GetExport().EndElement(aElem, true); + } + + // remove closed list from list stack + mpTextListsHelper->PopListFromStack(); + + --nListLevelsToBeClosed; + } while ( nListLevelsToBeClosed > 0 ); + } + } + + const bool bExportODF = + bool( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ); + const SvtSaveOptions::ODFSaneDefaultVersion eODFDefaultVersion = + GetExport().getSaneDefaultVersion(); + + // start a new list + if ( rNextInfo.GetLevel() > 0 ) + { + bool bRootListToBeStarted = false; + sal_Int16 nListLevelsToBeOpened = 0; + if ( !rPrevInfo.BelongsToSameList( rNextInfo ) || + rPrevInfo.GetLevel() <= 0 ) + { + // new root list + bRootListToBeStarted = true; + nListLevelsToBeOpened = rNextInfo.GetLevel(); + } + else if ( rNextInfo.GetLevel() > rPrevInfo.GetLevel() ) + { + // open corresponding sub lists + SAL_WARN_IF( rPrevInfo.GetLevel() <= 0, "xmloff", + " 0> not hold. Serious defect." ); + nListLevelsToBeOpened = rNextInfo.GetLevel() - rPrevInfo.GetLevel(); + } + + if ( nListLevelsToBeOpened > 0 ) + { + const OUString& sListStyleName( rNextInfo.GetNumRulesName() ); + // Currently only the text documents support . + // Thus, for other document types is empty. + const OUString& sListId( rNextInfo.GetListId() ); + bool bExportListStyle( true ); + bool bRestartNumberingAtContinuedList( false ); + sal_Int32 nRestartValueForContinuedList( -1 ); + bool bContinueingPreviousSubList = !bRootListToBeStarted && + rNextInfo.IsContinueingPreviousSubTree(); + do { + GetExport().CheckAttrList(); + + if ( bRootListToBeStarted ) + { + if ( !mpTextListsHelper->IsListProcessed( sListId ) ) + { + if ( bExportODF && + eODFDefaultVersion >= SvtSaveOptions::ODFSVER_012 && + !sListId.isEmpty() && !rNextInfo.IsListIdDefault() ) + { + /* Property text:id at element has to be + replaced by property xml:id (#i92221#) + */ + GetExport().AddAttribute( XML_NAMESPACE_XML, + XML_ID, + sListId ); + } + mpTextListsHelper->KeepListAsProcessed( sListId, + sListStyleName, + OUString() ); + } + else + { + const OUString sNewListId( + mpTextListsHelper->GenerateNewListId() ); + if ( bExportODF && + eODFDefaultVersion >= SvtSaveOptions::ODFSVER_012 && + !sListId.isEmpty() && !rNextInfo.IsListIdDefault() ) + { + /* Property text:id at element has to be + replaced by property xml:id (#i92221#) + */ + GetExport().AddAttribute( XML_NAMESPACE_XML, + XML_ID, + sNewListId ); + } + + const OUString sContinueListId = + mpTextListsHelper->GetLastContinuingListId( sListId ); + // store that list with list id is last list, + // which has continued list with list id + mpTextListsHelper->StoreLastContinuingList( sListId, + sNewListId ); + if ( sListStyleName == + mpTextListsHelper->GetListStyleOfLastProcessedList() && + // Inconsistent behavior regarding lists (#i92811#) + sContinueListId == + mpTextListsHelper->GetLastProcessedListId() && + !rNextInfo.IsRestart() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_CONTINUE_NUMBERING, + XML_TRUE ); + } + else + { + if ( bExportODF && + eODFDefaultVersion >= SvtSaveOptions::ODFSVER_012 && + !sListId.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_CONTINUE_LIST, + sContinueListId ); + } + + if ( rNextInfo.IsRestart() && + ( nListLevelsToBeOpened != 1 || + !rNextInfo.HasStartValue() ) ) + { + bRestartNumberingAtContinuedList = true; + nRestartValueForContinuedList = + rNextInfo.GetListLevelStartValue(); + } + } + + mpTextListsHelper->KeepListAsProcessed( sNewListId, + sListStyleName, + sContinueListId ); + } + + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sListStyleName ) ); + bExportListStyle = false; + + bRootListToBeStarted = false; + } + else if ( bExportListStyle && + !mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sListStyleName ) ); + bExportListStyle = false; + + } + else + { + // rhbz#746174: also export list restart for non root list + if (rNextInfo.IsRestart() && !rNextInfo.HasStartValue()) + { + bRestartNumberingAtContinuedList = true; + nRestartValueForContinuedList = + rNextInfo.GetListLevelStartValue(); + } + } + + if ( bContinueingPreviousSubList ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_CONTINUE_NUMBERING, XML_TRUE ); + bContinueingPreviousSubList = false; + } + + enum XMLTokenEnum eLName = XML_LIST; + + OUString aElem(GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(eLName) ) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement(aElem, false); + + maListElements.push_back(aElem); + + mpTextListsHelper->PushListOnStack( sListId, + sListStyleName ); + + // or + GetExport().CheckAttrList(); + + /* Export start value at correct list item (#i97309#) */ + if ( nListLevelsToBeOpened == 1 ) + { + if ( rNextInfo.HasStartValue() ) + { + OUStringBuffer aBuffer; + aBuffer.append( static_cast(rNextInfo.GetStartValue()) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, + aBuffer.makeStringAndClear() ); + } + else if (bRestartNumberingAtContinuedList) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_START_VALUE, + OUString::number(nRestartValueForContinuedList) ); + bRestartNumberingAtContinuedList = false; + } + } + + eLName = ( rNextInfo.IsNumbered() || nListLevelsToBeOpened > 1 ) + ? XML_LIST_ITEM + : XML_LIST_HEADER; + aElem = GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(eLName) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement(aElem, false); + maListElements.push_back(aElem); + + // export of element for last opened , if requested + if ( GetExport().exportTextNumberElement() && + eLName == XML_LIST_ITEM && nListLevelsToBeOpened == 1 && // last iteration --> last opened + !rNextInfo.ListLabelString().isEmpty() ) + { + const OUString aTextNumberElem = + GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(XML_NUMBER) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement( aTextNumberElem, false ); + GetExport().Characters( rNextInfo.ListLabelString() ); + GetExport().EndElement( aTextNumberElem, true ); + } + --nListLevelsToBeOpened; + } while ( nListLevelsToBeOpened > 0 ); + } + } + + bool bEndElement = false; + + if ( rNextInfo.GetLevel() > 0 && + rNextInfo.IsNumbered() && + rPrevInfo.BelongsToSameList( rNextInfo ) && + rPrevInfo.GetLevel() >= rNextInfo.GetLevel() ) + { + assert(maListElements.size() >= 2 && "list elements missing"); + bEndElement = maListElements.size() >= 2; + } + + if (!bEndElement) + return; + + // close previous list-item + GetExport().EndElement(maListElements.back(), true ); + maListElements.pop_back(); + + // Only for sub lists (#i103745#) + if ( rNextInfo.IsRestart() && !rNextInfo.HasStartValue() && + rNextInfo.GetLevel() != 1 ) + { + // start new sub list respectively list on same list level + GetExport().EndElement(maListElements.back(), true ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement(maListElements.back(), false); + } + + // open new list-item + GetExport().CheckAttrList(); + if( rNextInfo.HasStartValue() ) + { + OUStringBuffer aBuffer; + aBuffer.append( static_cast(rNextInfo.GetStartValue()) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, + aBuffer.makeStringAndClear() ); + } + // Handle restart without start value on list level 1 (#i103745#) + else if ( rNextInfo.IsRestart() && /*!rNextInfo.HasStartValue() &&*/ + rNextInfo.GetLevel() == 1 ) + { + OUStringBuffer aBuffer; + aBuffer.append( static_cast(rNextInfo.GetListLevelStartValue()) ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_START_VALUE, + aBuffer.makeStringAndClear() ); + } + if ( ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) && + GetExport().getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012) + { + const OUString& sListStyleName( rNextInfo.GetNumRulesName() ); + if ( !mpTextListsHelper->EqualsToTopListStyleOnStack( sListStyleName ) ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_STYLE_OVERRIDE, + GetExport().EncodeStyleName( sListStyleName ) ); + } + } + OUString aElem( GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(XML_LIST_ITEM) ) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement(aElem, false ); + maListElements.push_back(aElem); + + // export of element for , if requested + if ( GetExport().exportTextNumberElement() && + !rNextInfo.ListLabelString().isEmpty() ) + { + const OUString aTextNumberElem = + GetExport().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + GetXMLToken(XML_NUMBER) ); + GetExport().IgnorableWhitespace(); + GetExport().StartElement( aTextNumberElem, false ); + GetExport().Characters( rNextInfo.ListLabelString() ); + GetExport().EndElement( aTextNumberElem, true ); + } + +} + +struct XMLTextParagraphExport::Impl +{ + typedef ::std::map, sal_Int32> FieldMarkMap_t; + FieldMarkMap_t m_FieldMarkMap; + + explicit Impl() {} + sal_Int32 AddFieldMarkStart(Reference const& i_xFieldMark) + { + assert(m_FieldMarkMap.find(i_xFieldMark) == m_FieldMarkMap.end()); + sal_Int32 const ret(m_FieldMarkMap.size()); + m_FieldMarkMap.insert(::std::make_pair(i_xFieldMark, ret)); + return ret; + } + sal_Int32 GetFieldMarkIndex(Reference const& i_xFieldMark) + { + FieldMarkMap_t::const_iterator const it( + m_FieldMarkMap.find(i_xFieldMark)); + // rely on SwXFieldmark::CreateXFieldmark returning the same instance + // because the Reference in m_FieldMarkMap will keep it alive + assert(it != m_FieldMarkMap.end()); + return it->second; + } +}; + +XMLTextParagraphExport::XMLTextParagraphExport( + SvXMLExport& rExp, + SvXMLAutoStylePoolP & rASP + ) : + XMLStyleExport( rExp, &rASP ), + m_xImpl(new Impl), + rAutoStylePool( rASP ), + pBoundFrameSets(new BoundFrameSets(GetExport().GetModel())), + maListAutoPool( GetExport() ), + bProgress( false ), + bBlock( false ), + bOpenRuby( false ), + mpTextListsHelper( nullptr ), + mbCollected(false), + aCharStyleNamesPropInfoCache( gsCharStyleNames ) +{ + rtl::Reference < XMLPropertySetMapper > xPropMapper(new XMLTextPropertySetMapper( TextPropMap::PARA, true )); + xParaPropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + + OUString sFamily( GetXMLToken(XML_PARAGRAPH) ); + OUString aPrefix(u'P'); + rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_PARAGRAPH, sFamily, + xParaPropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::TEXT, true ); + xTextPropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + sFamily = GetXMLToken(XML_TEXT); + aPrefix = "T"; + rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_TEXT, sFamily, + xTextPropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::AUTO_FRAME, true ); + xAutoFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + sFamily = XML_STYLE_FAMILY_SD_GRAPHICS_NAME; + aPrefix = "fr"; + rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_FRAME, sFamily, + xAutoFramePropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::SECTION, true ); + xSectionPropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + sFamily = GetXMLToken( XML_SECTION ); + aPrefix = "Sect" ; + rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_SECTION, sFamily, + xSectionPropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::RUBY, true ); + xRubyPropMapper = new SvXMLExportPropertyMapper( xPropMapper ); + sFamily = GetXMLToken( XML_RUBY ); + aPrefix = "Ru"; + rAutoStylePool.AddFamily( XmlStyleFamily::TEXT_RUBY, sFamily, + xRubyPropMapper, aPrefix ); + + xPropMapper = new XMLTextPropertySetMapper( TextPropMap::FRAME, true ); + xFramePropMapper = new XMLTextExportPropertySetMapper( xPropMapper, + GetExport() ); + + pSectionExport.reset( new XMLSectionExport( rExp, *this ) ); + pIndexMarkExport.reset( new XMLIndexMarkExport( rExp ) ); + + if( ! IsBlockMode() && + Reference( GetExport().GetModel(), UNO_QUERY ).is()) + pRedlineExport.reset( new XMLRedlineExport( rExp ) ); + + // The text field helper needs a pre-constructed XMLPropertyState + // to export the combined characters field. We construct that + // here, because we need the text property mapper to do it. + + // construct Any value, then find index + sal_Int32 nIndex = xTextPropMapper->getPropertySetMapper()->FindEntryIndex( + "", XML_NAMESPACE_STYLE, + GetXMLToken(XML_TEXT_COMBINE)); + pFieldExport.reset( new XMLTextFieldExport( rExp, std::make_unique( nIndex, uno::Any(true) ) ) ); + PushNewTextListsHelper(); +} + +XMLTextParagraphExport::~XMLTextParagraphExport() +{ + pRedlineExport.reset(); + pIndexMarkExport.reset(); + pSectionExport.reset(); + pFieldExport.reset(); +#ifdef DBG_UTIL + txtparae_bContainsIllegalCharacters = false; +#endif + PopTextListsHelper(); + SAL_WARN_IF( !maTextListsHelperStack.empty(), "xmloff", + "misusage of text lists helper stack - it is not empty. Serious defect" ); +} + +SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateShapeExtPropMapper( + SvXMLExport& rExport ) +{ + rtl::Reference < XMLPropertySetMapper > xPropMapper = + new XMLTextPropertySetMapper( TextPropMap::SHAPE, true ); + return new XMLTextExportPropertySetMapper( xPropMapper, rExport ); +} + +SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateCharExtPropMapper( + SvXMLExport& rExport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TEXT, true ); + return new XMLTextExportPropertySetMapper( pPropMapper, rExport ); +} + +SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaExtPropMapper( + SvXMLExport& rExport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::SHAPE_PARA, true ); + return new XMLTextExportPropertySetMapper( pPropMapper, rExport ); +} + +SvXMLExportPropertyMapper *XMLTextParagraphExport::CreateParaDefaultExtPropMapper( + SvXMLExport& rExport) +{ + XMLPropertySetMapper *pPropMapper = + new XMLTextPropertySetMapper( TextPropMap::TEXT_ADDITIONAL_DEFAULTS, true ); + return new XMLTextExportPropertySetMapper( pPropMapper, rExport ); +} + +void XMLTextParagraphExport::exportPageFrames( bool bIsProgress ) +{ + const TextContentSet& rTexts = pBoundFrameSets->GetTexts()->GetPageBoundContents(); + const TextContentSet& rGraphics = pBoundFrameSets->GetGraphics()->GetPageBoundContents(); + const TextContentSet& rEmbeddeds = pBoundFrameSets->GetEmbeddeds()->GetPageBoundContents(); + const TextContentSet& rShapes = pBoundFrameSets->GetShapes()->GetPageBoundContents(); + for(TextContentSet::const_iterator_t it = rTexts.getBegin(); + it != rTexts.getEnd(); + ++it) + exportTextFrame(*it, false/*bAutoStyles*/, bIsProgress, true); + for(TextContentSet::const_iterator_t it = rGraphics.getBegin(); + it != rGraphics.getEnd(); + ++it) + exportTextGraphic(*it, false/*bAutoStyles*/); + for(TextContentSet::const_iterator_t it = rEmbeddeds.getBegin(); + it != rEmbeddeds.getEnd(); + ++it) + exportTextEmbedded(*it, false/*bAutoStyles*/); + for(TextContentSet::const_iterator_t it = rShapes.getBegin(); + it != rShapes.getEnd(); + ++it) + exportShape(*it, false/*bAutoStyles*/); +} + +void XMLTextParagraphExport::exportFrameFrames( + bool bAutoStyles, + bool bIsProgress, + const Reference < XTextFrame > *pParentTxtFrame ) +{ + const TextContentSet* const pTexts = pBoundFrameSets->GetTexts()->GetFrameBoundContents(*pParentTxtFrame); + if(pTexts) + for(TextContentSet::const_iterator_t it = pTexts->getBegin(); + it != pTexts->getEnd(); + ++it) + exportTextFrame(*it, bAutoStyles, bIsProgress, true); + const TextContentSet* const pGraphics = pBoundFrameSets->GetGraphics()->GetFrameBoundContents(*pParentTxtFrame); + if(pGraphics) + for(TextContentSet::const_iterator_t it = pGraphics->getBegin(); + it != pGraphics->getEnd(); + ++it) + exportTextGraphic(*it, bAutoStyles); + const TextContentSet* const pEmbeddeds = pBoundFrameSets->GetEmbeddeds()->GetFrameBoundContents(*pParentTxtFrame); + if(pEmbeddeds) + for(TextContentSet::const_iterator_t it = pEmbeddeds->getBegin(); + it != pEmbeddeds->getEnd(); + ++it) + exportTextEmbedded(*it, bAutoStyles); + const TextContentSet* const pShapes = pBoundFrameSets->GetShapes()->GetFrameBoundContents(*pParentTxtFrame); + if(pShapes) + for(TextContentSet::const_iterator_t it = pShapes->getBegin(); + it != pShapes->getEnd(); + ++it) + exportShape(*it, bAutoStyles); +} + +// bookmarks, reference marks (and TOC marks) are the same except for the +// element names. We use the same method for export and it an array with +// the proper element names +const enum XMLTokenEnum lcl_XmlReferenceElements[] = { + XML_REFERENCE_MARK, XML_REFERENCE_MARK_START, XML_REFERENCE_MARK_END }; +const enum XMLTokenEnum lcl_XmlBookmarkElements[] = { + XML_BOOKMARK, XML_BOOKMARK_START, XML_BOOKMARK_END }; + +// This function replaces the text portion iteration during auto style +// collection. +void XMLTextParagraphExport::collectTextAutoStylesOptimized( bool bIsProgress ) +{ + GetExport().GetShapeExport(); // make sure the graphics styles family is added + + if (mbCollected) + return; + + const bool bAutoStyles = true; + const bool bExportContent = false; + + // Export AutoStyles: + Reference< XAutoStylesSupplier > xAutoStylesSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xAutoStylesSupp.is() ) + { + Reference< XAutoStyles > xAutoStyleFamilies = xAutoStylesSupp->getAutoStyles(); + const auto collectFamily = [this, &xAutoStyleFamilies](const OUString& sName, + XmlStyleFamily nFamily) { + Any aAny = xAutoStyleFamilies->getByName( sName ); + Reference< XAutoStyleFamily > xAutoStyles = *o3tl::doAccess>(aAny); + Reference < XEnumeration > xAutoStylesEnum( xAutoStyles->createEnumeration() ); + + while ( xAutoStylesEnum->hasMoreElements() ) + { + aAny = xAutoStylesEnum->nextElement(); + Reference< XAutoStyle > xAutoStyle = *o3tl::doAccess>(aAny); + Reference < XPropertySet > xPSet( xAutoStyle, uno::UNO_QUERY ); + Add( nFamily, xPSet, {}, true ); + } + }; + collectFamily("CharacterStyles", XmlStyleFamily::TEXT_TEXT); + collectFamily("RubyStyles", XmlStyleFamily::TEXT_RUBY); + collectFamily("ParagraphStyles", XmlStyleFamily::TEXT_PARAGRAPH); + } + + // Export Field AutoStyles: + Reference< XTextFieldsSupplier > xTextFieldsSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xTextFieldsSupp.is() ) + { + Reference< XEnumerationAccess > xTextFields = xTextFieldsSupp->getTextFields(); + Reference < XEnumeration > xTextFieldsEnum( xTextFields->createEnumeration() ); + + while ( xTextFieldsEnum->hasMoreElements() ) + { + Any aAny = xTextFieldsEnum->nextElement(); + Reference< XTextField > xTextField = *o3tl::doAccess>(aAny); + exportTextField( xTextField, bAutoStyles, bIsProgress, + !xAutoStylesSupp.is(), nullptr ); + try + { + Reference < XPropertySet > xSet( xTextField, UNO_QUERY ); + Reference < XText > xText; + Any a = xSet->getPropertyValue("TextRange"); + a >>= xText; + if ( xText.is() ) + { + exportText( xText, true, bIsProgress, bExportContent ); + GetExport().GetTextParagraphExport() + ->collectTextAutoStyles( xText ); + } + } + catch (Exception&) + { + } + } + } + + // Export text frames: + Reference xTextFramesEnum = pBoundFrameSets->GetTexts()->createEnumeration(); + if(xTextFramesEnum.is()) + while(xTextFramesEnum->hasMoreElements()) + { + Reference xTxtCntnt(xTextFramesEnum->nextElement(), UNO_QUERY); + if(xTxtCntnt.is()) + exportTextFrame(xTxtCntnt, bAutoStyles, bIsProgress, bExportContent); + } + + // Export graphic objects: + Reference xGraphicsEnum = pBoundFrameSets->GetGraphics()->createEnumeration(); + if(xGraphicsEnum.is()) + while(xGraphicsEnum->hasMoreElements()) + { + Reference xTxtCntnt(xGraphicsEnum->nextElement(), UNO_QUERY); + if(xTxtCntnt.is()) + exportTextGraphic(xTxtCntnt, true); + } + + // Export embedded objects: + Reference xEmbeddedsEnum = pBoundFrameSets->GetEmbeddeds()->createEnumeration(); + if(xEmbeddedsEnum.is()) + while(xEmbeddedsEnum->hasMoreElements()) + { + Reference xTxtCntnt(xEmbeddedsEnum->nextElement(), UNO_QUERY); + if(xTxtCntnt.is()) + exportTextEmbedded(xTxtCntnt, true); + } + + // Export shapes: + Reference xShapesEnum = pBoundFrameSets->GetShapes()->createEnumeration(); + if(xShapesEnum.is()) + while(xShapesEnum->hasMoreElements()) + { + Reference xTxtCntnt(xShapesEnum->nextElement(), UNO_QUERY); + if(xTxtCntnt.is()) + { + Reference xServiceInfo(xTxtCntnt, UNO_QUERY); + if( xServiceInfo->supportsService(gsShapeService)) + exportShape(xTxtCntnt, true); + } + } + + sal_Int32 nCount; + // AutoStyles for sections + Reference< XTextSectionsSupplier > xSectionsSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xSectionsSupp.is() ) + { + Reference< XIndexAccess > xSections( xSectionsSupp->getTextSections(), UNO_QUERY ); + if ( xSections.is() ) + { + nCount = xSections->getCount(); + for( sal_Int32 i = 0; i < nCount; ++i ) + { + Any aAny = xSections->getByIndex( i ); + Reference< XTextSection > xSection = *o3tl::doAccess>(aAny); + Reference < XPropertySet > xPSet( xSection, uno::UNO_QUERY ); + Add( XmlStyleFamily::TEXT_SECTION, xPSet ); + } + } + } + + // AutoStyles for tables (Note: suppress autostyle collection for paragraphs in exportTable) + Reference< XTextTablesSupplier > xTablesSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xTablesSupp.is() ) + { + Reference< XIndexAccess > xTables( xTablesSupp->getTextTables(), UNO_QUERY ); + if ( xTables.is() ) + { + nCount = xTables->getCount(); + for( sal_Int32 i = 0; i < nCount; ++i ) + { + Any aAny = xTables->getByIndex( i ); + Reference< XTextTable > xTable = *o3tl::doAccess>(aAny); + exportTable( xTable, true, true ); + } + } + } + + Reference< XNumberingRulesSupplier > xNumberingRulesSupp( GetExport().GetModel(), UNO_QUERY ); + if ( xNumberingRulesSupp.is() ) + { + Reference< XIndexAccess > xNumberingRules = xNumberingRulesSupp->getNumberingRules(); + nCount = xNumberingRules->getCount(); + // Custom outline assignment lost after re-importing sxw (#i73361#) + for( sal_Int32 i = 0; i < nCount; ++i ) + { + Reference< XIndexReplace > xNumRule( xNumberingRules->getByIndex( i ), UNO_QUERY ); + if( xNumRule.is() && xNumRule->getCount() ) + { + Reference < XNamed > xNamed( xNumRule, UNO_QUERY ); + OUString sName; + if( xNamed.is() ) + sName = xNamed->getName(); + bool bAdd = sName.isEmpty(); + if( !bAdd ) + { + Reference < XPropertySet > xNumPropSet( xNumRule, + UNO_QUERY ); + if( xNumPropSet.is() && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "IsAutomatic" ) ) + { + bAdd = *o3tl::doAccess(xNumPropSet->getPropertyValue( "IsAutomatic" )); + // Check on outline style (#i73361#) + if ( bAdd && + xNumPropSet->getPropertySetInfo() + ->hasPropertyByName( "NumberingIsOutline" ) ) + { + bAdd = !(*o3tl::doAccess(xNumPropSet->getPropertyValue( "NumberingIsOutline" ))); + } + } + else + { + bAdd = true; + } + } + if( bAdd ) + maListAutoPool.Add( xNumRule ); + } + } + } + mbCollected = true; +} + +void XMLTextParagraphExport::exportText( + const Reference < XText > & rText, + bool bAutoStyles, + bool bIsProgress, + bool bExportParagraph, + TextPNS eExtensionNS) +{ + if( bAutoStyles ) + GetExport().GetShapeExport(); // make sure the graphics styles family + // is added + Reference < XEnumerationAccess > xEA( rText, UNO_QUERY ); + if( ! xEA.is() ) + return; + + Reference < XEnumeration > xParaEnum(xEA->createEnumeration()); + Reference < XPropertySet > xPropertySet( rText, UNO_QUERY ); + Reference < XTextSection > xBaseSection; + + // #97718# footnotes don't supply paragraph enumerations in some cases + // This is always a bug, but at least we don't want to crash. + SAL_WARN_IF( !xParaEnum.is(), "xmloff", "We need a paragraph enumeration" ); + if( ! xParaEnum.is() ) + return; + + if (xPropertySet.is()) + { + Reference < XPropertySetInfo > xInfo ( xPropertySet->getPropertySetInfo() ); + + if( xInfo.is() ) + { + if (xInfo->hasPropertyByName( gsTextSection )) + { + xPropertySet->getPropertyValue(gsTextSection) >>= xBaseSection ; + } + } + } + + // #96530# Export redlines at start & end of XText before & after + // exporting the text content enumeration + if( !bAutoStyles && (pRedlineExport != nullptr) ) + pRedlineExport->ExportStartOrEndRedline( xPropertySet, true ); + exportTextContentEnumeration( xParaEnum, bAutoStyles, xBaseSection, + bIsProgress, bExportParagraph, nullptr, eExtensionNS ); + if( !bAutoStyles && (pRedlineExport != nullptr) ) + pRedlineExport->ExportStartOrEndRedline( xPropertySet, false ); +} + +void XMLTextParagraphExport::exportText( + const Reference < XText > & rText, + const Reference < XTextSection > & rBaseSection, + bool bAutoStyles, + bool bIsProgress, + bool bExportParagraph) +{ + if( bAutoStyles ) + GetExport().GetShapeExport(); // make sure the graphics styles family + // is added + Reference < XEnumerationAccess > xEA( rText, UNO_QUERY ); + Reference < XEnumeration > xParaEnum(xEA->createEnumeration()); + + // #98165# don't continue without a paragraph enumeration + if( ! xParaEnum.is() ) + return; + + // #96530# Export redlines at start & end of XText before & after + // exporting the text content enumeration + Reference xPropertySet; + if( !bAutoStyles && (pRedlineExport != nullptr) ) + { + xPropertySet.set(rText, uno::UNO_QUERY ); + pRedlineExport->ExportStartOrEndRedline( xPropertySet, true ); + } + exportTextContentEnumeration( xParaEnum, bAutoStyles, rBaseSection, + bIsProgress, bExportParagraph ); + if( !bAutoStyles && (pRedlineExport != nullptr) ) + pRedlineExport->ExportStartOrEndRedline( xPropertySet, false ); +} + +void XMLTextParagraphExport::exportTextContentEnumeration( + const Reference < XEnumeration > & rContEnum, + bool bAutoStyles, + const Reference < XTextSection > & rBaseSection, + bool bIsProgress, + bool bExportParagraph, + const Reference < XPropertySet > *pRangePropSet, + TextPNS eExtensionNS ) +{ + SAL_WARN_IF( !rContEnum.is(), "xmloff", "No enumeration to export!" ); + bool bHasMoreElements = rContEnum->hasMoreElements(); + if( !bHasMoreElements ) + return; + + XMLTextNumRuleInfo aPrevNumInfo; + XMLTextNumRuleInfo aNextNumInfo; + + bool bHasContent = false; + Reference xCurrentTextSection(rBaseSection); + + MultiPropertySetHelper aPropSetHelper( + bAutoStyles ? aParagraphPropertyNamesAuto : + aParagraphPropertyNames ); + + bool bHoldElement = false; + Reference < XTextContent > xTxtCntnt; + while( bHoldElement || bHasMoreElements ) + { + if (bHoldElement) + { + bHoldElement = false; + } + else + { + xTxtCntnt.set(rContEnum->nextElement(), uno::UNO_QUERY); + + aPropSetHelper.resetValues(); + + } + + Reference xServiceInfo( xTxtCntnt, UNO_QUERY ); + if( xServiceInfo->supportsService( gsParagraphService ) ) + { + if( bAutoStyles ) + { + exportListAndSectionChange( xCurrentTextSection, xTxtCntnt, + aPrevNumInfo, aNextNumInfo, + bAutoStyles ); + } + else + { + /* Pass list auto style pool to instance + Pass info about request to export element + to instance (#i69627#) + */ + aNextNumInfo.Set( xTxtCntnt, + GetExport().writeOutlineStyleAsNormalListStyle(), + GetListAutoStylePool(), + GetExport().exportTextNumberElement() ); + + exportListAndSectionChange( xCurrentTextSection, aPropSetHelper, + TEXT_SECTION, xTxtCntnt, + aPrevNumInfo, aNextNumInfo, + bAutoStyles ); + } + + // if we found a mute section: skip all section content + if (pSectionExport->IsMuteSection(xCurrentTextSection)) + { + // Make sure headings are exported anyway. + if( !bAutoStyles ) + pSectionExport->ExportMasterDocHeadingDummies(); + + while (rContEnum->hasMoreElements() && + XMLSectionExport::IsInSection( xCurrentTextSection, + xTxtCntnt, true )) + { + xTxtCntnt.set(rContEnum->nextElement(), uno::UNO_QUERY); + aPropSetHelper.resetValues(); + aNextNumInfo.Reset(); + } + // the first non-mute element still needs to be processed + bHoldElement = + ! XMLSectionExport::IsInSection( xCurrentTextSection, + xTxtCntnt, false ); + } + else + exportParagraph( xTxtCntnt, bAutoStyles, bIsProgress, + bExportParagraph, aPropSetHelper, eExtensionNS ); + bHasContent = true; + } + else if( xServiceInfo->supportsService( gsTableService ) ) + { + if( !bAutoStyles ) + { + aNextNumInfo.Reset(); + } + + exportListAndSectionChange( xCurrentTextSection, xTxtCntnt, + aPrevNumInfo, aNextNumInfo, + bAutoStyles ); + + if (! pSectionExport->IsMuteSection(xCurrentTextSection)) + { + // export start + end redlines (for wholly redlined tables) + if ((! bAutoStyles) && (nullptr != pRedlineExport)) + pRedlineExport->ExportStartOrEndRedline(xTxtCntnt, true); + + exportTable( xTxtCntnt, bAutoStyles, bIsProgress ); + + if ((! bAutoStyles) && (nullptr != pRedlineExport)) + pRedlineExport->ExportStartOrEndRedline(xTxtCntnt, false); + } + else if( !bAutoStyles ) + { + // Make sure headings are exported anyway. + pSectionExport->ExportMasterDocHeadingDummies(); + } + + bHasContent = true; + } + else if( xServiceInfo->supportsService( gsTextFrameService ) ) + { + exportTextFrame( xTxtCntnt, bAutoStyles, bIsProgress, true, pRangePropSet ); + } + else if( xServiceInfo->supportsService( gsTextGraphicService ) ) + { + exportTextGraphic( xTxtCntnt, bAutoStyles, pRangePropSet ); + } + else if( xServiceInfo->supportsService( gsTextEmbeddedService ) ) + { + exportTextEmbedded( xTxtCntnt, bAutoStyles, pRangePropSet ); + } + else if( xServiceInfo->supportsService( gsShapeService ) ) + { + exportShape( xTxtCntnt, bAutoStyles, pRangePropSet ); + } + else + { + SAL_WARN_IF( xTxtCntnt.is(), "xmloff", "unknown text content" ); + } + + if( !bAutoStyles ) + { + aPrevNumInfo = aNextNumInfo; + } + + bHasMoreElements = rContEnum->hasMoreElements(); + } + + if( bHasContent && !bAutoStyles ) + { + aNextNumInfo.Reset(); + + // close open lists and sections; no new styles + exportListAndSectionChange( xCurrentTextSection, rBaseSection, + aPrevNumInfo, aNextNumInfo, + bAutoStyles ); + } +} + +void XMLTextParagraphExport::exportParagraph( + const Reference < XTextContent > & rTextContent, + bool bAutoStyles, bool bIsProgress, bool bExportParagraph, + MultiPropertySetHelper& rPropSetHelper, TextPNS eExtensionNS) +{ + sal_Int16 nOutlineLevel = -1; + + if( bIsProgress ) + { + ProgressBarHelper *pProgress = GetExport().GetProgressBarHelper(); + pProgress->SetValue( pProgress->GetValue()+1 ); + } + + // get property set or multi property set and initialize helper + Reference xMultiPropSet( rTextContent, UNO_QUERY ); + Reference xPropSet( rTextContent, UNO_QUERY ); + + // check for supported properties + if( !rPropSetHelper.checkedProperties() ) + rPropSetHelper.hasProperties( xPropSet->getPropertySetInfo() ); + +// if( xMultiPropSet.is() ) +// rPropSetHelper.getValues( xMultiPropSet ); +// else +// rPropSetHelper.getValues( xPropSet ); + + if( bExportParagraph ) + { + if( bAutoStyles ) + { + Add( XmlStyleFamily::TEXT_PARAGRAPH, rPropSetHelper, xPropSet ); + } + else + { + // xml:id for RDF metadata + GetExport().AddAttributeXmlId(rTextContent); + GetExport().AddAttributesRDFa(rTextContent); + + OUString sStyle; + if( rPropSetHelper.hasProperty( PARA_STYLE_NAME ) ) + { + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( PARA_STYLE_NAME, + xMultiPropSet ) >>= sStyle; + else + rPropSetHelper.getValue( PARA_STYLE_NAME, + xPropSet ) >>= sStyle; + } + + if( rTextContent.is() ) + { + const OUString& rIdentifier = GetExport().getInterfaceToIdentifierMapper().getIdentifier( rTextContent ); + if( !rIdentifier.isEmpty() ) + { + // FIXME: this is just temporary until EditEngine + // paragraphs implement XMetadatable. + // then that must be used and not the mapper, because + // when both can be used we get two xml:id! + uno::Reference const xMeta(rTextContent, + uno::UNO_QUERY); + OSL_ENSURE(!xMeta.is(), "paragraph that implements " + "XMetadatable used in interfaceToIdentifierMapper?"); + GetExport().AddAttributeIdLegacy(XML_NAMESPACE_TEXT, + rIdentifier); + } + } + + OUString sAutoStyle = Find( XmlStyleFamily::TEXT_PARAGRAPH, xPropSet, sStyle ); + if ( sAutoStyle.isEmpty() ) + sAutoStyle = sStyle; + if( !sAutoStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sAutoStyle ) ); + + if( rPropSetHelper.hasProperty( PARA_CONDITIONAL_STYLE_NAME ) ) + { + OUString sCondStyle; + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME, + xMultiPropSet ) >>= sCondStyle; + else + rPropSetHelper.getValue( PARA_CONDITIONAL_STYLE_NAME, + xPropSet ) >>= sCondStyle; + if( sCondStyle != sStyle ) + { + sCondStyle = Find( XmlStyleFamily::TEXT_PARAGRAPH, xPropSet, + sCondStyle ); + if( !sCondStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_COND_STYLE_NAME, + GetExport().EncodeStyleName( sCondStyle ) ); + } + } + + if( rPropSetHelper.hasProperty( PARA_OUTLINE_LEVEL ) ) + { + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( PARA_OUTLINE_LEVEL, + xMultiPropSet ) >>= nOutlineLevel; + else + rPropSetHelper.getValue( PARA_OUTLINE_LEVEL, + xPropSet ) >>= nOutlineLevel; + + if( 0 < nOutlineLevel ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_OUTLINE_LEVEL, + OUString::number( sal_Int32( nOutlineLevel) ) ); + + if ( rPropSetHelper.hasProperty( PARA_OUTLINE_CONTENT_VISIBLE ) ) + { + uno::Sequence propList; + bool bIsOutlineContentVisible = true; + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( + PARA_OUTLINE_CONTENT_VISIBLE, xMultiPropSet ) >>= propList; + else + rPropSetHelper.getValue( + PARA_OUTLINE_CONTENT_VISIBLE, xPropSet ) >>= propList; + for (const auto& rProp : std::as_const(propList)) + { + OUString propName = rProp.Name; + if (propName == "OutlineContentVisibleAttr") + { + rProp.Value >>= bIsOutlineContentVisible; + break; + } + } + if (!bIsOutlineContentVisible) + { + GetExport().AddAttribute( XML_NAMESPACE_LO_EXT, + XML_OUTLINE_CONTENT_VISIBLE, + XML_FALSE); + } + } + + if( rPropSetHelper.hasProperty( NUMBERING_IS_NUMBER ) ) + { + bool bIsNumber = false; + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( + NUMBERING_IS_NUMBER, xMultiPropSet ) >>= bIsNumber; + else + rPropSetHelper.getValue( + NUMBERING_IS_NUMBER, xPropSet ) >>= bIsNumber; + + OUString sListStyleName; + if( xMultiPropSet.is() ) + rPropSetHelper.getValue( + PARA_NUMBERING_STYLENAME, xMultiPropSet ) >>= sListStyleName; + else + rPropSetHelper.getValue( + PARA_NUMBERING_STYLENAME, xPropSet ) >>= sListStyleName; + + bool bAssignedtoOutlineStyle = false; + { + Reference< XChapterNumberingSupplier > xCNSupplier( GetExport().GetModel(), UNO_QUERY ); + + if (xCNSupplier.is()) + { + Reference< XIndexReplace > xNumRule ( xCNSupplier->getChapterNumberingRules() ); + SAL_WARN_IF( !xNumRule.is(), "xmloff", "no chapter numbering rules" ); + + if (xNumRule.is()) + { + Reference< XPropertySet > xNumRulePropSet( xNumRule, UNO_QUERY ); + OUString sOutlineName; + xNumRulePropSet->getPropertyValue( + "Name" ) >>= sOutlineName; + bAssignedtoOutlineStyle = ( sListStyleName == sOutlineName ); + } + } + } + + if( ! bIsNumber && bAssignedtoOutlineStyle ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, + XML_IS_LIST_HEADER, + XML_TRUE ); + } + + { + bool bIsRestartNumbering = false; + + Reference< XPropertySetInfo > + xPropSetInfo(xMultiPropSet.is() ? + xMultiPropSet->getPropertySetInfo(): + xPropSet->getPropertySetInfo()); + + if (xPropSetInfo-> + hasPropertyByName("ParaIsNumberingRestart")) + { + xPropSet->getPropertyValue("ParaIsNumberingRestart") + >>= bIsRestartNumbering; + } + + if (bIsRestartNumbering) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_RESTART_NUMBERING, + XML_TRUE); + + if (xPropSetInfo-> + hasPropertyByName("NumberingStartValue")) + { + sal_Int32 nStartValue = 0; + + xPropSet->getPropertyValue("NumberingStartValue") + >>= nStartValue; + + GetExport(). + AddAttribute(XML_NAMESPACE_TEXT, + XML_START_VALUE, + OUString::number(nStartValue)); + } + } + } + } + } + } + } + + Reference < XEnumerationAccess > xEA( rTextContent, UNO_QUERY ); + Reference < XEnumeration > xTextEnum = xEA->createEnumeration(); + const bool bHasPortions = xTextEnum.is(); + + Reference < XEnumeration> xContentEnum; + Reference < XContentEnumerationAccess > xCEA( rTextContent, UNO_QUERY ); + if( xCEA.is() ) + xContentEnum.set(xCEA->createContentEnumeration( gsTextContentService )); + const bool bHasContentEnum = xContentEnum.is() && + xContentEnum->hasMoreElements(); + + Reference < XTextSection > xSection; + if( bHasContentEnum ) + { + // For the auto styles, the multi property set helper is only used + // if hard attributes are existing. Therefore, it seems to be a better + // strategy to have the TextSection property separate, because otherwise + // we always retrieve the style names even if they are not required. + if( bAutoStyles ) + { + if( xPropSet->getPropertySetInfo()->hasPropertyByName( gsTextSection ) ) + { + xSection.set(xPropSet->getPropertyValue( gsTextSection ), uno::UNO_QUERY); + } + } + else + { + if( rPropSetHelper.hasProperty( TEXT_SECTION ) ) + { + xSection.set(rPropSetHelper.getValue( TEXT_SECTION ), uno::UNO_QUERY); + } + } + } + + bool bPrevCharIsSpace(true); // true because whitespace at start is ignored + + if( bAutoStyles ) + { + if( bHasContentEnum ) + exportTextContentEnumeration( + xContentEnum, bAutoStyles, xSection, + bIsProgress ); + if ( bHasPortions ) + { + exportTextRangeEnumeration(xTextEnum, bAutoStyles, bIsProgress, bPrevCharIsSpace); + } + } + else + { + enum XMLTokenEnum eElem = + 0 < nOutlineLevel ? XML_H : XML_P; + SvXMLElementExport aElem( GetExport(), eExtensionNS == TextPNS::EXTENSION ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_TEXT, eElem, + true, false ); + if( bHasContentEnum ) + { + exportTextContentEnumeration( + xContentEnum, bAutoStyles, xSection, + bIsProgress ); + } + exportTextRangeEnumeration(xTextEnum, bAutoStyles, bIsProgress, bPrevCharIsSpace); + } +} + +void XMLTextParagraphExport::exportTextRangeEnumeration( + const Reference < XEnumeration > & rTextEnum, + bool bAutoStyles, bool bIsProgress, + bool & rPrevCharIsSpace) +{ + static const char sFieldMarkName[] = "__FieldMark_"; + + /* This is used for exporting to strict OpenDocument 1.2, in which case traditional + * bookmarks are used instead of fieldmarks. */ + FieldmarkType openFieldMark = NONE; + + std::optional oTextA; + HyperlinkData aHyperlinkData; + + while( rTextEnum->hasMoreElements() ) + { + Reference xPropSet(rTextEnum->nextElement(), UNO_QUERY); + Reference < XTextRange > xTxtRange(xPropSet, uno::UNO_QUERY); + Reference xPropInfo(xPropSet->getPropertySetInfo()); + + if (!bAutoStyles) + { + if (HyperlinkData aNewHyperlinkData(xPropSet); aNewHyperlinkData != aHyperlinkData) + { + aHyperlinkData = aNewHyperlinkData; + oTextA.reset(); + if (aHyperlinkData.addHyperlinkAttributes(GetExport())) + { + oTextA.emplace(GetExport(), true, XML_NAMESPACE_TEXT, XML_A, false, false); + aHyperlinkData.exportEvents(GetExport()); + } + } + } + + if (xPropInfo->hasPropertyByName(gsTextPortionType)) + { + OUString sType; + xPropSet->getPropertyValue(gsTextPortionType) >>= sType; + + if( sType == gsText) + { + exportTextRange( xTxtRange, bAutoStyles, + rPrevCharIsSpace, openFieldMark); + } + else if( sType == gsTextField) + { + exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace); + } + else if ( sType == "Annotation" ) + { + exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace); + } + else if ( sType == "AnnotationEnd" ) + { + if (!bAutoStyles) + { + Reference xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + const OUString& rName = xBookmark->getName(); + if (!rName.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_OFFICE, XML_NAME, rName); + } + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_OFFICE, XML_ANNOTATION_END, false, false ); + } + } + else if( sType == gsFrame ) + { + Reference < XEnumeration> xContentEnum; + Reference < XContentEnumerationAccess > xCEA( xTxtRange, + UNO_QUERY ); + if( xCEA.is() ) + xContentEnum.set(xCEA->createContentEnumeration( + gsTextContentService )); + // frames are never in sections + Reference xSection; + if( xContentEnum.is() ) + exportTextContentEnumeration( xContentEnum, + bAutoStyles, + xSection, bIsProgress, true, + &xPropSet ); + + } + else if (sType == gsFootnote) + { + exportTextFootnote(xPropSet, + xTxtRange->getString(), + bAutoStyles, bIsProgress ); + } + else if (sType == gsBookmark) + { + exportTextMark(xPropSet, + gsBookmark, + lcl_XmlBookmarkElements, + bAutoStyles); + } + else if (sType == gsReferenceMark) + { + exportTextMark(xPropSet, + gsReferenceMark, + lcl_XmlReferenceElements, + bAutoStyles); + } + else if (sType == gsDocumentIndexMark) + { + pIndexMarkExport->ExportIndexMark(xPropSet, bAutoStyles); + } + else if (sType == gsRedline) + { + if (nullptr != pRedlineExport) + pRedlineExport->ExportChange(xPropSet, bAutoStyles); + } + else if (sType == gsRuby) + { + exportRuby(xPropSet, bAutoStyles); + } + else if (sType == "InContentMetadata") + { + exportMeta(xPropSet, bAutoStyles, bIsProgress, rPrevCharIsSpace); + } + else if (sType == "ContentControl") + { + ExportContentControl(xPropSet, bAutoStyles, bIsProgress, rPrevCharIsSpace); + } + else if (sType == gsTextFieldStart) + { + Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + + /* As of now, textmarks are a proposed extension to the OpenDocument standard. */ + if (!bAutoStyles) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + Reference xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (xBookmark.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName()); + } + + if (xFormField.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_FIELD, XML_TYPE, xFormField->getFieldType()); + } + + GetExport().StartElement(XML_NAMESPACE_FIELD, XML_FIELDMARK_START, false); + if (xFormField.is()) + { + FieldParamExporter(&GetExport(), xFormField->getParameters()).Export(); + } + GetExport().EndElement(XML_NAMESPACE_FIELD, XML_FIELDMARK_START, false); + } + /* The OpenDocument standard does not include support for TextMarks for now, so use bookmarks instead. */ + else + { + if (xFormField.is()) + { + OUString sName; + Reference< css::container::XNameAccess > xParameters = xFormField->getParameters(); + if (xParameters.is() && xParameters->hasByName("Name")) + { + const Any aValue = xParameters->getByName("Name"); + aValue >>= sName; + } + if (sName.isEmpty()) + { // name attribute is mandatory, so have to pull a + // rabbit out of the hat here + sName = sFieldMarkName + OUString::number( + m_xImpl->AddFieldMarkStart(xFormField)); + } + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, + sName); + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_TEXT, XML_BOOKMARK_START, + false, false ); + const OUString sFieldType = xFormField->getFieldType(); + if (sFieldType == ODF_FORMTEXT) + { + openFieldMark = TEXT; + } + else if (sFieldType == ODF_FORMCHECKBOX) + { + openFieldMark = CHECK; + } + else + { + openFieldMark = NONE; + } + } + } + } + } + else if (sType == gsTextFieldSep) + { + Reference const xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (!bAutoStyles) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_FIELD, XML_FIELDMARK_SEPARATOR, + false, false ); + } + } + } + else if (sType == gsTextFieldEnd) + { + if (!bAutoStyles) + { + Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_FIELD, XML_FIELDMARK_END, + false, false ); + } + else + { + if (xFormField.is()) + { + OUString sName; + Reference< css::container::XNameAccess > xParameters = xFormField->getParameters(); + if (xParameters.is() && xParameters->hasByName("Name")) + { + const Any aValue = xParameters->getByName("Name"); + aValue >>= sName; + } + if (sName.isEmpty()) + { // name attribute is mandatory, so have to pull a + // rabbit out of the hat here + sName = sFieldMarkName + OUString::number( + m_xImpl->GetFieldMarkIndex(xFormField)); + } + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, + sName); + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_TEXT, XML_BOOKMARK_END, + false, false ); + } + } + } + } + else if (sType == gsTextFieldStartEnd) + { + if (!bAutoStyles) + { + if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) + { + Reference xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (xBookmark.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName()); + } + Reference< css::text::XFormField > xFormField(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (xFormField.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_FIELD, XML_TYPE, xFormField->getFieldType()); + } + GetExport().StartElement(XML_NAMESPACE_FIELD, XML_FIELDMARK, false); + if (xFormField.is()) + { + FieldParamExporter(&GetExport(), xFormField->getParameters()).Export(); + } + GetExport().EndElement(XML_NAMESPACE_FIELD, XML_FIELDMARK, false); + } + else + { + Reference xBookmark(xPropSet->getPropertyValue(gsBookmark), UNO_QUERY); + if (xBookmark.is()) + { + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, xBookmark->getName()); + SvXMLElementExport aElem( GetExport(), !bAutoStyles, + XML_NAMESPACE_TEXT, XML_BOOKMARK, + false, false ); + } + } + } + } + else if (sType == gsSoftPageBreak) + { + if (!bAutoStyles) + exportSoftPageBreak(); + } + else if (sType == "LineBreak") + { + if (!bAutoStyles) + exportTextLineBreak(xPropSet); + } + else { + OSL_FAIL("unknown text portion type"); + } + } + else + { + Reference xServiceInfo( xTxtRange, UNO_QUERY ); + if( xServiceInfo->supportsService( gsTextFieldService ) ) + { + exportTextField(xTxtRange, bAutoStyles, bIsProgress, &rPrevCharIsSpace); + } + else + { + // no TextPortionType property -> non-Writer app -> text + exportTextRange(xTxtRange, bAutoStyles, rPrevCharIsSpace, openFieldMark); + } + } + } + +// now that there are nested enumerations for meta(-field), this may be valid! +// SAL_WARN_IF( bOpenRuby, "xmloff", "Red Alert: Ruby still open!" ); +} + +void XMLTextParagraphExport::exportTable( + const Reference < XTextContent > &, + bool /*bAutoStyles*/, bool /*bIsProgress*/ ) +{ +} + +void XMLTextParagraphExport::exportTextField( + const Reference < XTextRange > & rTextRange, + bool bAutoStyles, bool bIsProgress, bool *const pPrevCharIsSpace) +{ + Reference < XPropertySet > xPropSet( rTextRange, UNO_QUERY ); + // non-Writer apps need not support Property TextField, so test first + if (!xPropSet->getPropertySetInfo()->hasPropertyByName( gsTextField )) + return; + + Reference < XTextField > xTxtFld(xPropSet->getPropertyValue( gsTextField ), uno::UNO_QUERY); + SAL_WARN_IF( !xTxtFld.is(), "xmloff", "text field missing" ); + if( xTxtFld.is() ) + { + exportTextField(xTxtFld, bAutoStyles, bIsProgress, true, pPrevCharIsSpace); + } + else + { + // write only characters + GetExport().Characters(rTextRange->getString()); + } +} + +void XMLTextParagraphExport::exportTextField( + const Reference < XTextField > & xTextField, + const bool bAutoStyles, const bool bIsProgress, + const bool bRecursive, bool *const pPrevCharIsSpace) +{ + if ( bAutoStyles ) + { + pFieldExport->ExportFieldAutoStyle( xTextField, bIsProgress, + bRecursive ); + } + else + { + assert(pPrevCharIsSpace); + pFieldExport->ExportField(xTextField, bIsProgress, *pPrevCharIsSpace); + } +} + +void XMLTextParagraphExport::exportSoftPageBreak() +{ + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_SOFT_PAGE_BREAK, false, + false ); +} + +void XMLTextParagraphExport::exportTextLineBreak( + const uno::Reference& xPropSet) +{ + static const XMLTokenEnum aLineBreakClears[] = { + XML_NONE, + XML_LEFT, + XML_RIGHT, + XML_ALL, + }; + + uno::Reference xLineBreak; + xPropSet->getPropertyValue("LineBreak") >>= xLineBreak; + if (!xLineBreak.is()) + { + return; + } + + uno::Reference xLineBreakProps(xLineBreak, uno::UNO_QUERY); + if (!xLineBreakProps.is()) + { + return; + } + + sal_Int16 eClear{}; + xLineBreakProps->getPropertyValue("Clear") >>= eClear; + if (eClear >= 0 && o3tl::make_unsigned(eClear) < SAL_N_ELEMENTS(aLineBreakClears)) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CLEAR, + GetXMLToken(aLineBreakClears[eClear])); + } + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_TEXT, XML_LINE_BREAK, + /*bIgnWSOutside=*/false, /*bIgnWSInside=*/false); +} + +void XMLTextParagraphExport::exportTextMark( + const Reference & rPropSet, + const OUString& rProperty, + const ::xmloff::token::XMLTokenEnum pElements[], + bool bAutoStyles) +{ + // mib said: "Hau wech!" + + // (Originally, I'd export a span element in case the (book|reference)mark + // was formatted. This actually makes a difference in case some pervert + // sets a point reference mark in the document and, say, formats it bold. + // This basically meaningless formatting will now been thrown away + // (aka cleaned up), since mib said: ... dvo + + if (bAutoStyles) + return; + + // name element + Reference xName(rPropSet->getPropertyValue(rProperty), UNO_QUERY); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, XML_NAME, + xName->getName()); + + // start, end, or point-reference? + sal_Int8 nElement; + if( *o3tl::doAccess(rPropSet->getPropertyValue(gsIsCollapsed)) ) + { + nElement = 0; + } + else + { + nElement = *o3tl::doAccess(rPropSet->getPropertyValue(gsIsStart)) ? 1 : 2; + } + + // bookmark, bookmark-start: xml:id and RDFa for RDF metadata + if( nElement < 2 ) { + GetExport().AddAttributeXmlId(xName); + const uno::Reference xTextContent( + xName, uno::UNO_QUERY_THROW); + GetExport().AddAttributesRDFa(xTextContent); + } + + // bookmark-start: add attributes hidden and condition + if (nElement == 1) + { + Reference bkmkProps(rPropSet->getPropertyValue(rProperty), UNO_QUERY); + Reference bkmkPropInfo = bkmkProps->getPropertySetInfo(); + OUString sHidden("BookmarkHidden"); + if (bkmkPropInfo->hasPropertyByName(sHidden)) + { + bool bHidden = false; + bkmkProps->getPropertyValue(sHidden) >>= bHidden; + if (bHidden) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, "hidden", "true"); + OUString sCondition("BookmarkCondition"); + if (bkmkPropInfo->hasPropertyByName(sCondition)) + { + OUString sBookmarkCondition; + bkmkProps->getPropertyValue(sCondition) >>= sBookmarkCondition; + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, "condition", sBookmarkCondition); + } + } + } + } + + // export element + assert(pElements != nullptr); + assert(0 <= nElement && nElement <= 2); + SvXMLElementExport aElem(GetExport(), + XML_NAMESPACE_TEXT, pElements[nElement], + false, false); + // else: no styles. (see above) +} + +static bool lcl_txtpara_isBoundAsChar( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo ) +{ + bool bIsBoundAsChar = false; + OUString sAnchorType( "AnchorType" ); + if( rPropSetInfo->hasPropertyByName( sAnchorType ) ) + { + TextContentAnchorType eAnchor; + rPropSet->getPropertyValue( sAnchorType ) >>= eAnchor; + bIsBoundAsChar = TextContentAnchorType_AS_CHARACTER == eAnchor; + } + + return bIsBoundAsChar; +} + +XMLShapeExportFlags XMLTextParagraphExport::addTextFrameAttributes( + const Reference < XPropertySet >& rPropSet, + bool bShape, + basegfx::B2DPoint* pCenter, + OUString* pMinHeightValue, + OUString* pMinWidthValue) +{ + XMLShapeExportFlags nShapeFeatures = SEF_DEFAULT; + + // draw:name (#97662#: not for shapes, since those names will be + // treated in the shape export) + if( !bShape ) + { + Reference < XNamed > xNamed( rPropSet, UNO_QUERY ); + if( xNamed.is() ) + { + OUString sName( xNamed->getName() ); + if( !sName.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, + xNamed->getName() ); + } + } + + OUStringBuffer sValue; + + // text:anchor-type + TextContentAnchorType eAnchor = TextContentAnchorType_AT_PARAGRAPH; + rPropSet->getPropertyValue( gsAnchorType ) >>= eAnchor; + { + XMLAnchorTypePropHdl aAnchorTypeHdl; + OUString sTmp; + aAnchorTypeHdl.exportXML( sTmp, uno::Any(eAnchor), + GetExport().GetMM100UnitConverter() ); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_ANCHOR_TYPE, sTmp ); + } + + // text:anchor-page-number + if( TextContentAnchorType_AT_PAGE == eAnchor ) + { + sal_Int16 nPage = 0; + rPropSet->getPropertyValue( gsAnchorPageNo ) >>= nPage; + SAL_WARN_IF(nPage <= 0, "xmloff", + "ERROR: writing invalid anchor-page-number 0"); + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_ANCHOR_PAGE_NUMBER, + OUString::number( nPage ) ); + } + else + { + nShapeFeatures |= XMLShapeExportFlags::NO_WS; + } + + // OD 2004-06-01 #i27691# - correction: no export of svg:x, if object + // is anchored as-character. + if ( !bShape && + eAnchor != TextContentAnchorType_AS_CHARACTER ) + { + // svg:x + sal_Int16 nHoriOrient = HoriOrientation::NONE; + rPropSet->getPropertyValue( gsHoriOrient ) >>= nHoriOrient; + if( HoriOrientation::NONE == nHoriOrient ) + { + sal_Int32 nPos = 0; + rPropSet->getPropertyValue( gsHoriOrientPosition ) >>= nPos; + GetExport().GetMM100UnitConverter().convertMeasureToXML( + sValue, nPos ); + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_X, + sValue.makeStringAndClear() ); + if(nullptr != pCenter) + { + // add left edge to Center + pCenter->setX(pCenter->getX() + nPos); + } + } + } + else if( TextContentAnchorType_AS_CHARACTER == eAnchor ) + nShapeFeatures = (nShapeFeatures & ~XMLShapeExportFlags::X); + + if( !bShape || TextContentAnchorType_AS_CHARACTER == eAnchor ) + { + // svg:y + sal_Int16 nVertOrient = VertOrientation::NONE; + rPropSet->getPropertyValue( gsVertOrient ) >>= nVertOrient; + if( VertOrientation::NONE == nVertOrient ) + { + sal_Int32 nPos = 0; + rPropSet->getPropertyValue( gsVertOrientPosition ) >>= nPos; + GetExport().GetMM100UnitConverter().convertMeasureToXML( + sValue, nPos ); + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_Y, + sValue.makeStringAndClear() ); + if(nullptr != pCenter) + { + // add top edge to Center + pCenter->setY(pCenter->getY() + nPos); + } + } + if( bShape ) + nShapeFeatures = (nShapeFeatures & ~XMLShapeExportFlags::Y); + } + + Reference< XPropertySetInfo > xPropSetInfo(rPropSet->getPropertySetInfo()); + + bool bSyncWidth = false; + if (xPropSetInfo->hasPropertyByName(gsIsSyncWidthToHeight)) + { + bSyncWidth = *o3tl::doAccess(rPropSet->getPropertyValue(gsIsSyncWidthToHeight)); + } + sal_Int16 nRelWidth = 0; + if (!bSyncWidth && xPropSetInfo->hasPropertyByName(gsRelativeWidth)) + { + rPropSet->getPropertyValue(gsRelativeWidth) >>= nRelWidth; + } + bool bSyncHeight = false; + if (xPropSetInfo->hasPropertyByName(gsIsSyncHeightToWidth)) + { + bSyncHeight = *o3tl::doAccess(rPropSet->getPropertyValue(gsIsSyncHeightToWidth)); + } + sal_Int16 nRelHeight = 0; + if (!bSyncHeight && xPropSetInfo->hasPropertyByName(gsRelativeHeight)) + { + rPropSet->getPropertyValue(gsRelativeHeight) >>= nRelHeight; + } + awt::Size aLayoutSize; + if ((nRelWidth > 0 || nRelHeight > 0) && xPropSetInfo->hasPropertyByName("LayoutSize")) + { + rPropSet->getPropertyValue("LayoutSize") >>= aLayoutSize; + } + + bool bUseLayoutSize = true; + if (bSyncWidth && bSyncHeight) + { + // This is broken, width depends on height and height depends on width. Don't use the + // invalid layout size we got. + bUseLayoutSize = false; + } + + // svg:width + sal_Int16 nWidthType = SizeType::FIX; + if( xPropSetInfo->hasPropertyByName( gsWidthType ) ) + { + rPropSet->getPropertyValue( gsWidthType ) >>= nWidthType; + } + if( xPropSetInfo->hasPropertyByName( gsWidth ) ) + { + sal_Int32 nWidth = 0; + // VAR size will be written as zero min-size + if( SizeType::VARIABLE != nWidthType ) + { + rPropSet->getPropertyValue( gsWidth ) >>= nWidth; + } + GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, nWidth); + if( SizeType::FIX != nWidthType ) + { + assert(pMinWidthValue); + if (pMinWidthValue) + { + *pMinWidthValue = sValue.makeStringAndClear(); + } + } + else + { + if ((nRelWidth > 0 || bSyncWidth) && bUseLayoutSize) + { + // Relative width: write the layout size for the fallback width. + sValue.setLength(0); + GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, aLayoutSize.Width); + } + + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_WIDTH, + sValue.makeStringAndClear() ); + if(nullptr != pCenter) + { + // add half width to Center + pCenter->setX(pCenter->getX() + (0.5 * nWidth)); + } + } + } + if( xPropSetInfo->hasPropertyByName( gsIsSyncWidthToHeight ) ) + { + if( bSyncWidth ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH, + XML_SCALE ); + } + if( !bSyncWidth && xPropSetInfo->hasPropertyByName( gsRelativeWidth ) ) + { + SAL_WARN_IF( nRelWidth < 0 || nRelWidth > 254, "xmloff", + "Got illegal relative width from API" ); + if( nRelWidth > 0 ) + { + ::sax::Converter::convertPercent( sValue, nRelWidth ); + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_WIDTH, + sValue.makeStringAndClear() ); + } + } + + // svg:height, fo:min-height or style:rel-height + sal_Int16 nSizeType = SizeType::FIX; + if( xPropSetInfo->hasPropertyByName( gsSizeType ) ) + { + rPropSet->getPropertyValue( gsSizeType ) >>= nSizeType; + } + if( xPropSetInfo->hasPropertyByName( gsHeight ) ) + { + sal_Int32 nHeight = 0; + if( SizeType::VARIABLE != nSizeType ) + { + rPropSet->getPropertyValue( gsHeight ) >>= nHeight; + } + GetExport().GetMM100UnitConverter().convertMeasureToXML( sValue, + nHeight ); + if( SizeType::FIX != nSizeType && 0==nRelHeight && !bSyncHeight && + pMinHeightValue ) + { + *pMinHeightValue = sValue.makeStringAndClear(); + } + else + { + if ((nRelHeight > 0 || bSyncHeight) && bUseLayoutSize) + { + // Relative height: write the layout size for the fallback height. + sValue.setLength(0); + GetExport().GetMM100UnitConverter().convertMeasureToXML(sValue, aLayoutSize.Height); + } + + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_HEIGHT, + sValue.makeStringAndClear() ); + if(nullptr != pCenter) + { + // add half height to Center + pCenter->setY(pCenter->getY() + (0.5 * nHeight)); + } + } + } + if( bSyncHeight ) + { + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_HEIGHT, + SizeType::MIN == nSizeType ? XML_SCALE_MIN : XML_SCALE ); + + } + else if( nRelHeight > 0 ) + { + ::sax::Converter::convertPercent( sValue, nRelHeight ); + if( SizeType::MIN == nSizeType ) + { + assert(pMinHeightValue); + if (pMinHeightValue) + { + *pMinHeightValue = sValue.makeStringAndClear(); + } + } + else + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_REL_HEIGHT, + sValue.makeStringAndClear() ); + } + + OUString sZOrder( "ZOrder" ); + if( xPropSetInfo->hasPropertyByName( sZOrder ) ) + { + sal_Int32 nZIndex = 0; + rPropSet->getPropertyValue( sZOrder ) >>= nZIndex; + if( -1 != nZIndex ) + { + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_ZINDEX, + OUString::number( nZIndex ) ); + } + } + + return nShapeFeatures; +} + +void XMLTextParagraphExport::exportAnyTextFrame( + const Reference < XTextContent > & rTxtCntnt, + FrameType eType, + bool bAutoStyles, + bool bIsProgress, + bool bExportContent, + const Reference < XPropertySet > *pRangePropSet) +{ + Reference < XPropertySet > xPropSet( rTxtCntnt, UNO_QUERY ); + + if( bAutoStyles ) + { + if( FrameType::Embedded == eType ) + _collectTextEmbeddedAutoStyles( xPropSet ); + // No text frame style for shapes (#i28745#) + else if ( FrameType::Shape != eType ) + Add( XmlStyleFamily::TEXT_FRAME, xPropSet ); + + if( pRangePropSet && lcl_txtpara_isBoundAsChar( xPropSet, + xPropSet->getPropertySetInfo() ) ) + Add( XmlStyleFamily::TEXT_TEXT, *pRangePropSet ); + + switch( eType ) + { + case FrameType::Text: + { + // frame bound frames + if ( bExportContent ) + { + Reference < XTextFrame > xTxtFrame( rTxtCntnt, UNO_QUERY ); + Reference < XText > xTxt(xTxtFrame->getText()); + exportFrameFrames( true, bIsProgress, &xTxtFrame ); + exportText( xTxt, bAutoStyles, bIsProgress, true ); + } + } + break; + case FrameType::Shape: + { + Reference < XShape > xShape( rTxtCntnt, UNO_QUERY ); + GetExport().GetShapeExport()->collectShapeAutoStyles( xShape ); + } + break; + default: + break; + } + } + else + { + Reference< XPropertySetInfo > xPropSetInfo(xPropSet->getPropertySetInfo()); + { + bool bAddCharStyles = pRangePropSet && + lcl_txtpara_isBoundAsChar( xPropSet, xPropSetInfo ); + + bool bIsUICharStyle; + bool bHasAutoStyle = false; + + OUString sStyle; + + if( bAddCharStyles ) + sStyle = FindTextStyle( *pRangePropSet, bIsUICharStyle, bHasAutoStyle ); + else + bIsUICharStyle = false; + + bool bDoSomething = bIsUICharStyle + && aCharStyleNamesPropInfoCache.hasProperty( *pRangePropSet ); + XMLTextCharStyleNamesElementExport aCharStylesExport( + GetExport(), bDoSomething, bHasAutoStyle, + bDoSomething ? *pRangePropSet : Reference(), + gsCharStyleNames ); + + if( !sStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sStyle ) ); + { + SvXMLElementExport aElem( GetExport(), !sStyle.isEmpty(), + XML_NAMESPACE_TEXT, XML_SPAN, false, false ); + { + SvXMLElementExport aElement( GetExport(), + FrameType::Shape != eType && + HyperlinkData(xPropSet).addHyperlinkAttributes(GetExport()), + XML_NAMESPACE_DRAW, XML_A, false, false ); + switch( eType ) + { + case FrameType::Text: + _exportTextFrame( xPropSet, xPropSetInfo, bIsProgress ); + break; + case FrameType::Graphic: + _exportTextGraphic( xPropSet, xPropSetInfo ); + break; + case FrameType::Embedded: + _exportTextEmbedded( xPropSet, xPropSetInfo ); + break; + case FrameType::Shape: + { + Reference < XShape > xShape( rTxtCntnt, UNO_QUERY ); + XMLShapeExportFlags nFeatures = + addTextFrameAttributes( xPropSet, true ); + GetExport().GetShapeExport() + ->exportShape( xShape, nFeatures ); + } + break; + } + } + } + } + } +} + +void XMLTextParagraphExport::_exportTextFrame( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo, + bool bIsProgress ) +{ + Reference < XTextFrame > xTxtFrame( rPropSet, UNO_QUERY ); + Reference < XText > xTxt(xTxtFrame->getText()); + + OUString sStyle; + if( rPropSetInfo->hasPropertyByName( gsFrameStyleName ) ) + { + rPropSet->getPropertyValue( gsFrameStyleName ) >>= sStyle; + } + + OUString aMinHeightValue; + OUString sMinWidthValue; + OUString sAutoStyle = Find( XmlStyleFamily::TEXT_FRAME, rPropSet, sStyle ); + if ( sAutoStyle.isEmpty() ) + sAutoStyle = sStyle; + if( !sAutoStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME, + GetExport().EncodeStyleName( sAutoStyle ) ); + addTextFrameAttributes(rPropSet, false, nullptr, &aMinHeightValue, &sMinWidthValue); + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, + XML_FRAME, false, true ); + + if( !aMinHeightValue.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_MIN_HEIGHT, + aMinHeightValue ); + + if (!sMinWidthValue.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_FO, XML_MIN_WIDTH, + sMinWidthValue ); + } + + // draw:chain-next-name + if( rPropSetInfo->hasPropertyByName( gsChainNextName ) ) + { + OUString sNext; + if( (rPropSet->getPropertyValue( gsChainNextName ) >>= sNext) && !sNext.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, + XML_CHAIN_NEXT_NAME, + sNext ); + } + + { + SvXMLElementExport aElement( GetExport(), XML_NAMESPACE_DRAW, + XML_TEXT_BOX, true, true ); + + // frames bound to frame + exportFrameFrames( false, bIsProgress, &xTxtFrame ); + + exportText( xTxt, false, bIsProgress, true ); + } + + // script:events + Reference xEventsSupp( xTxtFrame, UNO_QUERY ); + GetExport().GetEventExport().Export(xEventsSupp); + + // image map + GetExport().GetImageMapExport().Export( rPropSet ); + + // svg:title and svg:desc (#i73249#) + exportTitleAndDescription( rPropSet, rPropSetInfo ); +} + +void XMLTextParagraphExport::exportContour( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo ) +{ + if( !rPropSetInfo->hasPropertyByName( gsContourPolyPolygon ) ) + { + return; + } + + PointSequenceSequence aSourcePolyPolygon; + rPropSet->getPropertyValue( gsContourPolyPolygon ) >>= aSourcePolyPolygon; + const basegfx::B2DPolyPolygon aPolyPolygon( + basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon( + aSourcePolyPolygon)); + const sal_uInt32 nPolygonCount(aPolyPolygon.count()); + + if(!nPolygonCount) + { + return; + } + + const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange()); + bool bPixel(false); + + if( rPropSetInfo->hasPropertyByName( gsIsPixelContour ) ) + { + bPixel = *o3tl::doAccess(rPropSet->getPropertyValue( gsIsPixelContour )); + } + + // svg: width + OUStringBuffer aStringBuffer( 10 ); + + if(bPixel) + { + ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth())); + } + else + { + GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getWidth())); + } + + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStringBuffer.makeStringAndClear()); + + // svg: height + if(bPixel) + { + ::sax::Converter::convertMeasurePx(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight())); + } + else + { + GetExport().GetMM100UnitConverter().convertMeasureToXML(aStringBuffer, basegfx::fround(aPolyPolygonRange.getHeight())); + } + + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStringBuffer.makeStringAndClear()); + + // svg:viewbox + SdXMLImExViewBox aViewBox(0.0, 0.0, aPolyPolygonRange.getWidth(), aPolyPolygonRange.getHeight()); + GetExport().AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString()); + enum XMLTokenEnum eElem = XML_TOKEN_INVALID; + + if(1 == nPolygonCount ) + { + // simple polygon shape, can be written as svg:points sequence + const OUString aPointString( + basegfx::utils::exportToSvgPoints( + aPolyPolygon.getB2DPolygon(0))); + + // write point array + GetExport().AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString); + eElem = XML_CONTOUR_POLYGON; + } + else + { + // polypolygon, needs to be written as a svg:path sequence + const OUString aPolygonString( + basegfx::utils::exportToSvgD( + aPolyPolygon, + true, // bUseRelativeCoordinates + false, // bDetectQuadraticBeziers: not used in old, but maybe activated now + true)); // bHandleRelativeNextPointCompatible + + // write point array + GetExport().AddAttribute( XML_NAMESPACE_SVG, XML_D, aPolygonString); + eElem = XML_CONTOUR_PATH; + } + + if( rPropSetInfo->hasPropertyByName( gsIsAutomaticContour ) ) + { + bool bTmp = *o3tl::doAccess(rPropSet->getPropertyValue( + gsIsAutomaticContour )); + GetExport().AddAttribute( XML_NAMESPACE_DRAW, + XML_RECREATE_ON_EDIT, bTmp ? XML_TRUE : XML_FALSE ); + } + + // write object now + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, eElem, + true, true ); +} + +void XMLTextParagraphExport::_exportTextGraphic( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo ) +{ + OUString sStyle; + if( rPropSetInfo->hasPropertyByName( gsFrameStyleName ) ) + { + rPropSet->getPropertyValue( gsFrameStyleName ) >>= sStyle; + } + + OUString sAutoStyle = Find( XmlStyleFamily::TEXT_FRAME, rPropSet, sStyle ); + if ( sAutoStyle.isEmpty() ) + sAutoStyle = sStyle; + if( !sAutoStyle.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_STYLE_NAME, + GetExport().EncodeStyleName( sAutoStyle ) ); + + // check if we need to use svg:transform + sal_Int16 nRotation(0); + rPropSet->getPropertyValue( gsGraphicRotation ) >>= nRotation; + const bool bUseRotation(0 != nRotation); + basegfx::B2DPoint aCenter(0.0, 0.0); + + // add TextFrame attributes like svg:x/y/width/height, also get back + // object's center point if rotation is used and has to be exported + addTextFrameAttributes(rPropSet, false, bUseRotation ? &aCenter : nullptr); + + // svg:transform + if(bUseRotation) + { + // RotateFlyFrameFix: im/export full 'draw:transform' using existing tooling. + // Currently only rotation is used, but combinations with 'draw:transform' + // may be necessary in the future, so that svg:x/svg:y/svg:width/svg:height + // may be extended/replaced with 'draw:transform' (see draw objects) + SdXMLImExTransform2D aSdXMLImExTransform2D; + + // Convert from 10th degree integer to deg. + // CAUTION: internal rotation is classically mathematically 'wrong' defined by ignoring that + // we have a right-handed coordinate system, so need to correct this by mirroring + // the rotation to get the correct transformation. See also case XML_TOK_TEXT_FRAME_TRANSFORM + // in XMLTextFrameContext_Impl::XMLTextFrameContext_Impl and #i78696# + // CAUTION-II: due to tdf#115782 it is better for current ODF to indeed write it with the wrong + // orientation as in all other cases - ARGH! We will need to correct this in future ODF ASAP! + const double fRotate(basegfx::deg2rad<10>(nRotation)); + + // transform to rotation center which is the object's center + aSdXMLImExTransform2D.AddTranslate(-aCenter); + + // add rotation itself + // tdf#115529 but correct value modulo 2PI to have it positive and in the range of [0.0 .. 2PI[ + aSdXMLImExTransform2D.AddRotate(basegfx::normalizeToRange(fRotate, 2 * M_PI)); + + // back-transform after rotation + aSdXMLImExTransform2D.AddTranslate(aCenter); + + // Note: using GetTwipUnitConverter instead of GetMM100UnitConverter may be needed, + // but is not generally available (as it should be, a 'current' UnitConverter should + // be available at GetExport() - and maybe was once). May have to be addressed as soon + // as translate transformations are used here. + GetExport().AddAttribute( + XML_NAMESPACE_DRAW, + XML_TRANSFORM, + aSdXMLImExTransform2D.GetExportString(GetExport().GetMM100UnitConverter())); + } + + // original content + SvXMLElementExport aElem(GetExport(), XML_NAMESPACE_DRAW, XML_FRAME, false, true); + + { + // xlink:href + uno::Reference xGraphic; + rPropSet->getPropertyValue("Graphic") >>= xGraphic; + + OUString sInternalURL; + OUString sOutMimeType; + + if (xGraphic.is()) + { + sInternalURL = GetExport().AddEmbeddedXGraphic(xGraphic, sOutMimeType); + } + + // If there still is no url, then graphic is empty + if (!sInternalURL.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + + // draw:filter-name + OUString sGrfFilter; + rPropSet->getPropertyValue( gsGraphicFilter ) >>= sGrfFilter; + if( !sGrfFilter.isEmpty() ) + GetExport().AddAttribute( XML_NAMESPACE_DRAW, XML_FILTER_NAME, + sGrfFilter ); + + if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + if (sOutMimeType.isEmpty()) + { + GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType); + } + if (!sOutMimeType.isEmpty()) + { // ODF 1.3 OFFICE-3943 + GetExport().AddAttribute( + SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", sOutMimeType); + } + } + + + // optional office:binary-data + if (xGraphic.is()) + { + SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, false, true ); + GetExport().AddEmbeddedXGraphicAsBase64(xGraphic); + } + } + + const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get(); + if (bAddReplacementImages) + { + // replacement graphic for backwards compatibility, but + // only for SVG and metafiles currently + uno::Reference xReplacementGraphic; + rPropSet->getPropertyValue("ReplacementGraphic") >>= xReplacementGraphic; + + OUString sInternalURL; + OUString sOutMimeType; + + //Resolves: fdo#62461 put preferred image first above, followed by + //fallback here + if (xReplacementGraphic.is()) + { + sInternalURL = GetExport().AddEmbeddedXGraphic(xReplacementGraphic, sOutMimeType); + } + + // If there is no url, then graphic is empty + if (!sInternalURL.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED); + GetExport().AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD); + } + + if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012) + { + if (sOutMimeType.isEmpty()) + { + GetExport().GetGraphicMimeTypeFromStream(xReplacementGraphic, sOutMimeType); + } + if (!sOutMimeType.isEmpty()) + { // ODF 1.3 OFFICE-3943 + GetExport().AddAttribute( + SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion() + ? XML_NAMESPACE_DRAW + : XML_NAMESPACE_LO_EXT, + "mime-type", sOutMimeType); + } + } + + + // optional office:binary-data + if (xReplacementGraphic.is()) + { + SvXMLElementExport aElement(GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, true, true); + GetExport().AddEmbeddedXGraphicAsBase64(xReplacementGraphic); + } + } + + // script:events + Reference xEventsSupp( rPropSet, UNO_QUERY ); + GetExport().GetEventExport().Export(xEventsSupp); + + // image map + GetExport().GetImageMapExport().Export( rPropSet ); + + // svg:title and svg:desc (#i73249#) + exportTitleAndDescription( rPropSet, rPropSetInfo ); + + // draw:contour + exportContour( rPropSet, rPropSetInfo ); +} + +void XMLTextParagraphExport::_collectTextEmbeddedAutoStyles(const Reference < XPropertySet > & ) +{ + SAL_WARN( "xmloff", "no API implementation available" ); +} + +void XMLTextParagraphExport::_exportTextEmbedded( + const Reference < XPropertySet > &, + const Reference < XPropertySetInfo > & ) +{ + SAL_WARN( "xmloff", "no API implementation available" ); +} + +void XMLTextParagraphExport::exportEvents( const Reference < XPropertySet > & rPropSet ) +{ + // script:events + Reference xEventsSupp( rPropSet, UNO_QUERY ); + GetExport().GetEventExport().Export(xEventsSupp); + + // image map + if (rPropSet->getPropertySetInfo()->hasPropertyByName("ImageMap")) + GetExport().GetImageMapExport().Export( rPropSet ); +} + +// Implement Title/Description Elements UI (#i73249#) +void XMLTextParagraphExport::exportTitleAndDescription( + const Reference < XPropertySet > & rPropSet, + const Reference < XPropertySetInfo > & rPropSetInfo ) +{ + // svg:title + if( rPropSetInfo->hasPropertyByName( gsTitle ) ) + { + OUString sObjTitle; + rPropSet->getPropertyValue( gsTitle ) >>= sObjTitle; + if( !sObjTitle.isEmpty() ) + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_SVG, + XML_TITLE, true, false ); + GetExport().Characters( sObjTitle ); + } + } + + // svg:description + if( rPropSetInfo->hasPropertyByName( gsDescription ) ) + { + OUString sObjDesc; + rPropSet->getPropertyValue( gsDescription ) >>= sObjDesc; + if( !sObjDesc.isEmpty() ) + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_SVG, + XML_DESC, true, false ); + GetExport().Characters( sObjDesc ); + } + } +} + +void XMLTextParagraphExport::exportTextRangeSpan( + const css::uno::Reference< css::text::XTextRange > & rTextRange, + Reference< XPropertySet > const & xPropSet, + Reference < XPropertySetInfo > & xPropSetInfo, + const bool bIsUICharStyle, + const bool bHasAutoStyle, + const OUString& sStyle, + bool& rPrevCharIsSpace, + FieldmarkType& openFieldMark ) +{ + XMLTextCharStyleNamesElementExport aCharStylesExport( + GetExport(), + bIsUICharStyle && aCharStyleNamesPropInfoCache.hasProperty( xPropSet, xPropSetInfo ), + bHasAutoStyle, + xPropSet, + gsCharStyleNames ); + + if ( !sStyle.isEmpty() ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_STYLE_NAME, GetExport().EncodeStyleName( sStyle ) ); + } + { + SvXMLElementExport aElement( GetExport(), !sStyle.isEmpty(), XML_NAMESPACE_TEXT, XML_SPAN, false, false ); + const OUString aText( rTextRange->getString() ); + SvXMLElementExport aElem2( GetExport(), TEXT == openFieldMark, + XML_NAMESPACE_TEXT, XML_TEXT_INPUT, + false, false ); + exportCharacterData(aText, rPrevCharIsSpace); + openFieldMark = NONE; + } +} + +void XMLTextParagraphExport::exportTextRange( + const Reference< XTextRange > & rTextRange, + bool bAutoStyles, + bool& rPrevCharIsSpace, + FieldmarkType& openFieldMark ) +{ + Reference< XPropertySet > xPropSet( rTextRange, UNO_QUERY ); + if ( bAutoStyles ) + { + Add( XmlStyleFamily::TEXT_TEXT, xPropSet ); + } + else + { + bool bIsUICharStyle = false; + bool bHasAutoStyle = false; + const OUString sStyle( + FindTextStyle( xPropSet, bIsUICharStyle, bHasAutoStyle ) ); + + Reference < XPropertySetInfo > xPropSetInfo; + exportTextRangeSpan( rTextRange, xPropSet, xPropSetInfo, bIsUICharStyle, bHasAutoStyle, sStyle, rPrevCharIsSpace, openFieldMark ); + } +} + +void XMLTextParagraphExport::exportCharacterData(const OUString& rText, + bool& rPrevCharIsSpace ) +{ + sal_Int32 nExpStartPos = 0; + sal_Int32 nEndPos = rText.getLength(); + sal_Int32 nSpaceChars = 0; + for( sal_Int32 nPos = 0; nPos < nEndPos; nPos++ ) + { + sal_Unicode cChar = rText[nPos]; + bool bExpCharAsText = true; + bool bExpCharAsElement = false; + bool bCurrCharIsSpace = false; + switch( cChar ) + { + case 0x0009: // Tab + case 0x000A: // LF + // These characters are exported as text. + bExpCharAsElement = true; + bExpCharAsText = false; + break; + case 0x000D: + break; // legal character + case 0x0020: // Blank + if( rPrevCharIsSpace ) + { + // If the previous character is a space character, + // too, export a special space element. + bExpCharAsText = false; + } + bCurrCharIsSpace = true; + break; + default: + if( cChar < 0x0020 ) + { +#ifdef DBG_UTIL + OSL_ENSURE( txtparae_bContainsIllegalCharacters || + cChar >= 0x0020, + "illegal character in text content" ); + txtparae_bContainsIllegalCharacters = true; +#endif + bExpCharAsText = false; + } + break; + } + + // If the current character is not exported as text + // the text that has not been exported by now has to be exported now. + if( nPos > nExpStartPos && !bExpCharAsText ) + { + SAL_WARN_IF( 0 != nSpaceChars, "xmloff", "pending spaces" ); + OUString sExp( rText.copy( nExpStartPos, nPos - nExpStartPos ) ); + GetExport().Characters( sExp ); + nExpStartPos = nPos; + } + + // If there are spaces left that have not been exported and the + // current character is not a space , the pending spaces have to be + // exported now. + if( nSpaceChars > 0 && !bCurrCharIsSpace ) + { + SAL_WARN_IF( nExpStartPos != nPos, "xmloff", " pending characters" ); + + if( nSpaceChars > 1 ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_C, + OUString::number(nSpaceChars) ); + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_S, false, false ); + + nSpaceChars = 0; + } + + // If the current character has to be exported as a special + // element, the element will be exported now. + if( bExpCharAsElement ) + { + switch( cChar ) + { + case 0x0009: // Tab + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_TAB, false, + false ); + } + break; + case 0x000A: // LF + { + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, + XML_LINE_BREAK, false, + false ); + } + break; + } + } + + // If the current character is a space, and the previous one + // is a space, too, the number of pending spaces is incremented + // only. + if( bCurrCharIsSpace && rPrevCharIsSpace ) + nSpaceChars++; + rPrevCharIsSpace = bCurrCharIsSpace; + + // If the current character is not exported as text, the start + // position for text is the position behind the current position. + if( !bExpCharAsText ) + { + SAL_WARN_IF( nExpStartPos != nPos, "xmloff", "wrong export start pos" ); + nExpStartPos = nPos+1; + } + } + + if( nExpStartPos < nEndPos ) + { + SAL_WARN_IF( 0 != nSpaceChars, "xmloff", " pending spaces " ); + OUString sExp( rText.copy( nExpStartPos, nEndPos - nExpStartPos ) ); + GetExport().Characters( sExp ); + } + + // If there are some spaces left, they have to be exported now. + if( nSpaceChars > 0 ) + { + if( nSpaceChars > 1 ) + { + GetExport().AddAttribute( XML_NAMESPACE_TEXT, XML_C, + OUString::number(nSpaceChars) ); + } + + SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_TEXT, XML_S, + false, false ); + } +} + +void XMLTextParagraphExport::exportTextDeclarations() +{ + pFieldExport->ExportFieldDeclarations(); + + // get XPropertySet from the document and ask for AutoMarkFileURL. + // If it exists, export the auto-mark-file element. + Reference xPropertySet( GetExport().GetModel(), UNO_QUERY ); + if (!xPropertySet.is()) + return; + + OUString sUrl; + OUString sIndexAutoMarkFileURL( + "IndexAutoMarkFileURL"); + if (!xPropertySet->getPropertySetInfo()->hasPropertyByName( + sIndexAutoMarkFileURL)) + return; + + xPropertySet->getPropertyValue(sIndexAutoMarkFileURL) >>= sUrl; + if (!sUrl.isEmpty()) + { + GetExport().AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, + GetExport().GetRelativeReference(sUrl) ); + SvXMLElementExport aAutoMarkElement( + GetExport(), XML_NAMESPACE_TEXT, + XML_ALPHABETICAL_INDEX_AUTO_MARK_FILE, + true, true ); + } +} + +void XMLTextParagraphExport::exportTextDeclarations( + const Reference & rText ) +{ + pFieldExport->ExportFieldDeclarations(rText); +} + +void XMLTextParagraphExport::exportUsedDeclarations() +{ + pFieldExport->SetExportOnlyUsedFieldDeclarations( false/*bOnlyUsed*/ ); +} + +void XMLTextParagraphExport::exportTrackedChanges(bool bAutoStyles) +{ + if (nullptr != pRedlineExport) + pRedlineExport->ExportChangesList( bAutoStyles ); +} + +void XMLTextParagraphExport::exportTrackedChanges( + const Reference & rText, + bool bAutoStyle) +{ + if (nullptr != pRedlineExport) + pRedlineExport->ExportChangesList(rText, bAutoStyle); +} + +void XMLTextParagraphExport::recordTrackedChangesForXText( + const Reference & rText ) +{ + if (nullptr != pRedlineExport) + pRedlineExport->SetCurrentXText(rText); +} + +void XMLTextParagraphExport::recordTrackedChangesNoXText() +{ + if (nullptr != pRedlineExport) + pRedlineExport->SetCurrentXText(); +} + +void XMLTextParagraphExport::exportTableAutoStyles() {} + +void XMLTextParagraphExport::exportTextAutoStyles() +{ + // tdf#135942: do not collect styles during their export: this may modify iterated containers + mbCollected = true; + exportTableAutoStyles(); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_PARAGRAPH ); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_TEXT ); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_FRAME ); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_SECTION ); + + GetAutoStylePool().exportXML( XmlStyleFamily::TEXT_RUBY ); + + maListAutoPool.exportXML(); +} + +void XMLTextParagraphExport::exportRuby( + const Reference & rPropSet, + bool bAutoStyles ) +{ + // early out: a collapsed ruby makes no sense + if (*o3tl::doAccess(rPropSet->getPropertyValue(gsIsCollapsed))) + return; + + // start value ? + bool bStart = *o3tl::doAccess(rPropSet->getPropertyValue(gsIsStart)); + + if (bAutoStyles) + { + // ruby auto styles + if (bStart) + Add( XmlStyleFamily::TEXT_RUBY, rPropSet ); + } + else + { + if (bStart) + { + // ruby start + + // we can only start a ruby if none is open + assert(!bOpenRuby && "Can't open a ruby inside of ruby!"); + if( bOpenRuby ) + return; + + // save ruby text + ruby char style + rPropSet->getPropertyValue(gsRubyText) >>= sOpenRubyText; + rPropSet->getPropertyValue(gsRubyCharStyleName) >>= sOpenRubyCharStyle; + + // ruby style + GetExport().CheckAttrList(); + OUString sStyleName(Find(XmlStyleFamily::TEXT_RUBY, rPropSet, "")); + SAL_WARN_IF(sStyleName.isEmpty(), "xmloff", "Can't find ruby style!"); + GetExport().AddAttribute(XML_NAMESPACE_TEXT, + XML_STYLE_NAME, sStyleName); + + // export and start elements + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_RUBY, false); + GetExport().ClearAttrList(); + GetExport().StartElement( XML_NAMESPACE_TEXT, XML_RUBY_BASE, + false ); + bOpenRuby = true; + } + else + { + // ruby end + + // check for an open ruby + assert(bOpenRuby && "Can't close a ruby if none is open!"); + if( !bOpenRuby ) + return; + + // close + GetExport().EndElement(XML_NAMESPACE_TEXT, XML_RUBY_BASE, + false); + + // write the ruby text (with char style) + { + if (!sOpenRubyCharStyle.isEmpty()) + GetExport().AddAttribute( + XML_NAMESPACE_TEXT, XML_STYLE_NAME, + GetExport().EncodeStyleName( sOpenRubyCharStyle) ); + + SvXMLElementExport aRubyElement( + GetExport(), XML_NAMESPACE_TEXT, XML_RUBY_TEXT, + false, false); + + GetExport().Characters(sOpenRubyText); + } + + // and finally, close the ruby + GetExport().EndElement(XML_NAMESPACE_TEXT, XML_RUBY, false); + bOpenRuby = false; + } + } +} + +void XMLTextParagraphExport::exportMeta( + const Reference & i_xPortion, + bool i_bAutoStyles, bool i_isProgress, bool & rPrevCharIsSpace) +{ + bool doExport(!i_bAutoStyles); // do not export element if autostyles + // check version >= 1.2 + switch (GetExport().getSaneDefaultVersion()) { + case SvtSaveOptions::ODFSVER_011: // fall through + case SvtSaveOptions::ODFSVER_010: doExport = false; break; + default: break; + } + + const Reference< XTextContent > xTextContent( + i_xPortion->getPropertyValue("InContentMetadata"), UNO_QUERY_THROW); + const Reference< XEnumerationAccess > xEA( xTextContent, UNO_QUERY_THROW ); + const Reference< XEnumeration > xTextEnum( xEA->createEnumeration() ); + + if (doExport) + { + const Reference xMeta(xTextContent, UNO_QUERY_THROW); + + // text:meta with neither xml:id nor RDFa is invalid + xMeta->ensureMetadataReference(); + + // xml:id and RDFa for RDF metadata + GetExport().AddAttributeXmlId(xMeta); + GetExport().AddAttributesRDFa(xTextContent); + } + + SvXMLElementExport aElem( GetExport(), doExport, + XML_NAMESPACE_TEXT, XML_META, false, false ); + + // recurse to export content + exportTextRangeEnumeration(xTextEnum, i_bAutoStyles, i_isProgress, rPrevCharIsSpace); +} + +void XMLTextParagraphExport::ExportContentControl( + const uno::Reference& xPortion, bool bAutoStyles, bool isProgress, + bool& rPrevCharIsSpace) +{ + // Do not export the element in the autostyle case. + bool bExport = !bAutoStyles; + if (!(GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)) + { + bExport = false; + } + + uno::Reference xTextContent(xPortion->getPropertyValue("ContentControl"), + uno::UNO_QUERY_THROW); + uno::Reference xEA(xTextContent, uno::UNO_QUERY_THROW); + uno::Reference xTextEnum = xEA->createEnumeration(); + + uno::Reference xPropertySet(xTextContent, uno::UNO_QUERY_THROW); + if (bExport) + { + bool bShowingPlaceHolder = false; + xPropertySet->getPropertyValue("ShowingPlaceHolder") >>= bShowingPlaceHolder; + if (bShowingPlaceHolder) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bShowingPlaceHolder); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOWING_PLACE_HOLDER, + aBuffer.makeStringAndClear()); + } + + bool bCheckbox = false; + xPropertySet->getPropertyValue("Checkbox") >>= bCheckbox; + if (bCheckbox) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bCheckbox); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKBOX, aBuffer.makeStringAndClear()); + } + + bool bChecked = false; + xPropertySet->getPropertyValue("Checked") >>= bChecked; + if (bChecked) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bChecked); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKED, aBuffer.makeStringAndClear()); + } + + OUString aCheckedState; + xPropertySet->getPropertyValue("CheckedState") >>= aCheckedState; + if (!aCheckedState.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CHECKED_STATE, aCheckedState); + } + + OUString aUncheckedState; + xPropertySet->getPropertyValue("UncheckedState") >>= aUncheckedState; + if (!aUncheckedState.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_UNCHECKED_STATE, aUncheckedState); + } + + bool bPicture = false; + xPropertySet->getPropertyValue("Picture") >>= bPicture; + if (bPicture) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bPicture); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_PICTURE, + aBuffer.makeStringAndClear()); + } + + bool bDate = false; + xPropertySet->getPropertyValue("Date") >>= bDate; + if (bDate) + { + OUStringBuffer aBuffer; + sax::Converter::convertBool(aBuffer, bDate); + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE, aBuffer.makeStringAndClear()); + } + + OUString aDateFormat; + xPropertySet->getPropertyValue("DateFormat") >>= aDateFormat; + if (!aDateFormat.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE_FORMAT, aDateFormat); + } + + OUString aDateLanguage; + xPropertySet->getPropertyValue("DateLanguage") >>= aDateLanguage; + if (!aDateLanguage.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DATE_RFC_LANGUAGE_TAG, aDateLanguage); + } + OUString aCurrentDate; + xPropertySet->getPropertyValue("CurrentDate") >>= aCurrentDate; + if (!aCurrentDate.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_CURRENT_DATE, aCurrentDate); + } + } + + SvXMLElementExport aElem(GetExport(), bExport, XML_NAMESPACE_LO_EXT, XML_CONTENT_CONTROL, false, + false); + + if (bExport) + { + // Export list items of dropdowns. + uno::Sequence aListItems; + xPropertySet->getPropertyValue("ListItems") >>= aListItems; + for (const auto& rListItem : aListItems) + { + comphelper::SequenceAsHashMap aMap(rListItem); + auto it = aMap.find("DisplayText"); + OUString aValue; + if (it != aMap.end() && (it->second >>= aValue) && !aValue.isEmpty()) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_DISPLAY_TEXT, aValue); + } + + it = aMap.find("Value"); + if (it != aMap.end() && (it->second >>= aValue)) + { + GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_VALUE, aValue); + } + + SvXMLElementExport aItem(GetExport(), bExport, XML_NAMESPACE_LO_EXT, XML_LIST_ITEM, false, + false); + } + } + + // Recurse to export content. + exportTextRangeEnumeration(xTextEnum, bAutoStyles, isProgress, rPrevCharIsSpace); +} + +void XMLTextParagraphExport::PreventExportOfControlsInMuteSections( + const Reference & rShapes, + const rtl::Reference& xFormExport ) +{ + // check parameters ad pre-conditions + if( ( ! rShapes.is() ) || ( ! xFormExport.is() ) ) + { + // if we don't have shapes or a form export, there's nothing to do + return; + } + SAL_WARN_IF( pSectionExport == nullptr, "xmloff", "We need the section export." ); + + Reference xShapesEnum = pBoundFrameSets->GetShapes()->createEnumeration(); + if(!xShapesEnum.is()) + return; + while( xShapesEnum->hasMoreElements() ) + { + // now we need to check + // 1) if this is a control shape, and + // 2) if it's in a mute section + // if both answers are 'yes', notify the form layer export + + // we join accessing the shape and testing for control + Reference xControlShape(xShapesEnum->nextElement(), UNO_QUERY); + if( xControlShape.is() ) + { + // Reference xPropSet( xControlShape, UNO_QUERY ); + // Reference xTextContent; + // xPropSet->getPropertyValue("TextRange") >>= xTextContent; + + Reference xTextContent( xControlShape, UNO_QUERY ); + if( xTextContent.is() ) + { + if( pSectionExport->IsMuteSection( xTextContent, false ) ) + { + // Ah, we've found a shape that + // 1) is a control shape + // 2) is anchored in a mute section + // so: don't export it! + xFormExport->excludeFromExport( + xControlShape->getControl() ); + } + // else: not in mute section -> should be exported -> nothing + // to do + } + // else: no anchor -> ignore + } + // else: no control shape -> nothing to do + } +} + +void XMLTextParagraphExport::PushNewTextListsHelper() +{ + maTextListsHelperStack.emplace_back( new XMLTextListsHelper() ); + mpTextListsHelper = maTextListsHelperStack.back().get(); +} + +void XMLTextParagraphExport::PopTextListsHelper() +{ + mpTextListsHelper = nullptr; + maTextListsHelperStack.pop_back(); + if ( !maTextListsHelperStack.empty() ) + { + mpTextListsHelper = maTextListsHelperStack.back().get(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtparai.cxx b/xmloff/source/text/txtparai.cxx new file mode 100644 index 000000000..99ffbc281 --- /dev/null +++ b/xmloff/source/text/txtparai.cxx @@ -0,0 +1,2107 @@ +/* -*- 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 + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include "txtparai.hxx" +#include +#include "XMLFootnoteImportContext.hxx" +#include "XMLTextMarkImportContext.hxx" +#include "XMLTextFrameContext.hxx" +#include +#include "XMLTextFrameHyperlinkContext.hxx" +#include +#include "XMLChangeImportContext.hxx" +#include + +#include "txtparaimphint.hxx" +#include "xmllinebreakcontext.hxx" +#include "xmlcontentcontrolcontext.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; + +class XMLHints_Impl +{ +private: + + std::vector> m_Hints; + std::unordered_map m_IndexHintsById; + uno::Reference m_xCrossRefHeadingBookmark; + +public: + void push_back(std::unique_ptr pHint) + { + m_Hints.push_back(std::move(pHint)); + } + + void push_back(std::unique_ptr pHint) + { + m_IndexHintsById.emplace(pHint->GetID(), pHint.get()); + m_Hints.push_back(std::move(pHint)); + } + + std::vector> const& GetHints() const + { + return m_Hints; + } + + XMLIndexMarkHint_Impl* GetIndexHintById(const OUString& sID) + { + auto it = m_IndexHintsById.find(sID); + return it == m_IndexHintsById.end() ? nullptr : it->second; + } + + uno::Reference & GetCrossRefHeadingBookmark() + { + return m_xCrossRefHeadingBookmark; + } +}; + + +XMLCharContext::XMLCharContext( + SvXMLImport& rImport, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + sal_Unicode c, + bool bCount ) : + SvXMLImportContext( rImport ) + ,m_nControl(0) + ,m_nCount(1) + ,m_c(c) +{ + if( !bCount ) + return; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_C) ) + { + sal_Int32 nTmp = aIter.toInt32(); + if( nTmp > 0 ) + { + if( nTmp > SAL_MAX_UINT16 ) + m_nCount = SAL_MAX_UINT16; + else + m_nCount = static_cast(nTmp); + } + } + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } +} + +XMLCharContext::XMLCharContext( + SvXMLImport& rImp, + sal_Int16 nControl ) : + SvXMLImportContext( rImp ) + ,m_nControl(nControl) + ,m_nCount(0) + ,m_c(0) +{ +} + +XMLCharContext::~XMLCharContext() +{ +} +void XMLCharContext::endFastElement(sal_Int32 ) +{ + if ( !m_nCount ) + InsertControlCharacter( m_nControl ); + else + { + if( 1U == m_nCount ) + { + OUString sBuff( &m_c, 1 ); + InsertString(sBuff); + } + else + { + OUStringBuffer sBuff(static_cast(m_nCount)); + while( m_nCount-- ) + sBuff.append( &m_c, 1 ); + + InsertString(sBuff.makeStringAndClear() ); + } + } +} +void XMLCharContext::InsertControlCharacter(sal_Int16 _nControl) +{ + GetImport().GetTextImport()->InsertControlCharacter( _nControl ); +} +void XMLCharContext::InsertString(const OUString& _sString) +{ + GetImport().GetTextImport()->InsertString( _sString ); +} + +namespace { + +/** import start of reference () */ +class XMLStartReferenceContext_Impl : public SvXMLImportContext +{ +public: + + // Do everything in constructor. Well ... + XMLStartReferenceContext_Impl ( + SvXMLImport& rImport, + XMLHints_Impl& rHints, + const Reference & xAttrList); + + static bool FindName( + const Reference & xAttrList, + OUString& rName); +}; + +} + +XMLStartReferenceContext_Impl::XMLStartReferenceContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints, + const Reference & xAttrList) : + SvXMLImportContext(rImport) +{ + OUString sName; + + if (FindName(xAttrList, sName)) + { + std::unique_ptr pHint(new XMLReferenceHint_Impl( + sName, rImport.GetTextImport()->GetCursor()->getStart())); + + // degenerates to point reference, if no end is found! + pHint->SetEnd(rImport.GetTextImport()->GetCursor()->getStart() ); + + rHints.push_back(std::move(pHint)); + } +} + +bool XMLStartReferenceContext_Impl::FindName( + const Reference & xAttrList, + OUString& rName) +{ + bool bNameOK( false ); + + // find name attribute first + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_NAME) ) + { + rName = aIter.toString(); + bNameOK = true; + break; + } + } + + return bNameOK; +} + +namespace { + +/** import end of reference () */ +class XMLEndReferenceContext_Impl : public SvXMLImportContext +{ +public: + + // Do everything in constructor. Well ... + XMLEndReferenceContext_Impl( + SvXMLImport& rImport, + const XMLHints_Impl& rHints, + const Reference & xAttrList); +}; + +} + +XMLEndReferenceContext_Impl::XMLEndReferenceContext_Impl( + SvXMLImport& rImport, + const XMLHints_Impl& rHints, + const Reference & xAttrList) : + SvXMLImportContext(rImport) +{ + OUString sName; + + // borrow from XMLStartReferenceContext_Impl + if (!XMLStartReferenceContext_Impl::FindName(xAttrList, sName)) + return; + + // search for reference start + for (const auto& rHintPtr : rHints.GetHints()) + { + XMLHint_Impl *const pHint = rHintPtr.get(); + if ( pHint->IsReference() && + sName == static_cast(pHint)->GetRefName() ) + { + // set end and stop searching + pHint->SetEnd(GetImport().GetTextImport()-> + GetCursor()->getStart() ); + break; + } + } + // else: no start (in this paragraph) -> ignore +} + +namespace { + +class XMLImpHyperlinkContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + XMLHyperlinkHint_Impl *mpHint; + + bool& mrbIgnoreLeadingSpace; + +public: + + + XMLImpHyperlinkContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ); + + virtual ~XMLImpHyperlinkContext_Impl() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +} + +XMLImpHyperlinkContext_Impl::XMLImpHyperlinkContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ) + : SvXMLImportContext( rImport ) + , m_rHints( rHints ) + , mpHint( new XMLHyperlinkHint_Impl( GetImport().GetTextImport()->GetCursorAsRange()->getStart() ) ) + , mrbIgnoreLeadingSpace( rIgnLeadSpace ) +{ + OUString sShow; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + OUString sValue = aIter.toString(); + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + mpHint->SetHRef( GetImport().GetAbsoluteReference( sValue ) ); + break; + case XML_ELEMENT(OFFICE, XML_NAME): + mpHint->SetName( sValue ); + break; + case XML_ELEMENT(OFFICE, XML_TARGET_FRAME_NAME): + mpHint->SetTargetFrameName( sValue ); + break; + case XML_ELEMENT(XLINK, XML_SHOW): + sShow = sValue; + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + mpHint->SetStyleName( sValue ); + break; + case XML_ELEMENT(TEXT, XML_VISITED_STYLE_NAME): + mpHint->SetVisitedStyleName( sValue ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !sShow.isEmpty() && mpHint->GetTargetFrameName().isEmpty() ) + { + if( IsXMLToken( sShow, XML_NEW ) ) + mpHint->SetTargetFrameName( + "_blank" ); + else if( IsXMLToken( sShow, XML_REPLACE ) ) + mpHint->SetTargetFrameName( + "_self" ); + } + + if ( mpHint->GetHRef().isEmpty() ) + { + // hyperlink without a URL is not imported. + delete mpHint; + mpHint = nullptr; + } + else + { + m_rHints.push_back(std::unique_ptr(mpHint)); + } +} + +XMLImpHyperlinkContext_Impl::~XMLImpHyperlinkContext_Impl() +{ + if (mpHint) + mpHint->SetEnd( GetImport().GetTextImport() + ->GetCursorAsRange()->getStart() ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpHyperlinkContext_Impl::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + XMLEventsImportContext* pCtxt = new XMLEventsImportContext(GetImport()); + if (mpHint) + mpHint->SetEventsContext(pCtxt); + return pCtxt; + } + else + { + return XMLImpSpanContext_Impl::CreateSpanContext( + GetImport(), nElement, xAttrList, + m_rHints, mrbIgnoreLeadingSpace ); + } +} + +void XMLImpHyperlinkContext_Impl::characters( const OUString& rChars ) +{ + GetImport().GetTextImport()->InsertString( rChars, mrbIgnoreLeadingSpace ); +} + +namespace { + +class XMLImpRubyBaseContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + + bool& rIgnoreLeadingSpace; + +public: + + + XMLImpRubyBaseContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +} + +XMLImpRubyBaseContext_Impl::XMLImpRubyBaseContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > &, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ) + : SvXMLImportContext( rImport ) + , m_rHints( rHints ) + , rIgnoreLeadingSpace( rIgnLeadSpace ) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpRubyBaseContext_Impl::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + return XMLImpSpanContext_Impl::CreateSpanContext( GetImport(), nElement, xAttrList, + m_rHints, rIgnoreLeadingSpace ); +} + +void XMLImpRubyBaseContext_Impl::characters( const OUString& rChars ) +{ + GetImport().GetTextImport()->InsertString( rChars, rIgnoreLeadingSpace ); +} + +namespace { + +class XMLImpRubyContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + + bool& rIgnoreLeadingSpace; + + Reference < XTextRange > m_xStart; + OUString m_sStyleName; + OUString m_sTextStyleName; + OUString m_sText; + +public: + + + XMLImpRubyContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + void SetTextStyleName( const OUString& s ) { m_sTextStyleName = s; } + void AppendText( std::u16string_view s ) { m_sText += s; } +}; + +class XMLImpRubyTextContext_Impl : public SvXMLImportContext +{ + XMLImpRubyContext_Impl & m_rRubyContext; + +public: + + + XMLImpRubyTextContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLImpRubyContext_Impl & rParent ); + + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +} + +XMLImpRubyTextContext_Impl::XMLImpRubyTextContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLImpRubyContext_Impl & rParent ) + : SvXMLImportContext( rImport ) + , m_rRubyContext( rParent ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + m_rRubyContext.SetTextStyleName( aIter.toString() ); + break; + } + } +} + +void XMLImpRubyTextContext_Impl::characters( const OUString& rChars ) +{ + m_rRubyContext.AppendText( rChars ); +} + + +XMLImpRubyContext_Impl::XMLImpRubyContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace ) + : SvXMLImportContext( rImport ) + , m_rHints( rHints ) + , rIgnoreLeadingSpace( rIgnLeadSpace ) + , m_xStart( GetImport().GetTextImport()->GetCursorAsRange()->getStart() ) +{ + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + m_sStyleName = aIter.toString(); + break; + } + } +} + +void XMLImpRubyContext_Impl::endFastElement(sal_Int32 ) +{ + const rtl::Reference < XMLTextImportHelper > xTextImport( + GetImport().GetTextImport()); + const Reference < XTextCursor > xAttrCursor( + xTextImport->GetText()->createTextCursorByRange( m_xStart )); + if (!xAttrCursor.is()) + { + SAL_WARN("xmloff.text", "cannot insert ruby"); + return; + } + xAttrCursor->gotoRange(xTextImport->GetCursorAsRange()->getStart(), + true); + xTextImport->SetRuby( GetImport(), xAttrCursor, + m_sStyleName, m_sTextStyleName, m_sText ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpRubyContext_Impl::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + if( nElement == XML_ELEMENT(TEXT, XML_RUBY_BASE) ) + return new XMLImpRubyBaseContext_Impl( GetImport(), nElement, + xAttrList, + m_rHints, + rIgnoreLeadingSpace ); + else if( nElement == XML_ELEMENT(TEXT, XML_RUBY_TEXT) ) + return new XMLImpRubyTextContext_Impl( GetImport(), nElement, + xAttrList, + *this ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return nullptr; +} + +namespace { + +/** for text:meta and text:meta-field + */ +class XMLMetaImportContextBase : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + + bool& m_rIgnoreLeadingSpace; + + /// start position + Reference m_xStart; + +protected: + OUString m_XmlId; + +public: + + XMLMetaImportContextBase( + SvXMLImport& i_rImport, + const sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ); + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const Reference & i_xAttrList) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL characters( const OUString& i_rChars ) override; + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter); + + virtual void InsertMeta(const Reference & i_xInsertionRange) + = 0; +}; + +} + +XMLMetaImportContextBase::XMLMetaImportContextBase( + SvXMLImport& i_rImport, + const sal_Int32 /*i_nElement*/, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ) + : SvXMLImportContext( i_rImport ) + , m_rHints( i_rHints ) + , m_rIgnoreLeadingSpace( i_rIgnoreLeadingSpace ) + , m_xStart( GetImport().GetTextImport()->GetCursorAsRange()->getStart() ) +{ +} + +void XMLMetaImportContextBase::startFastElement( + sal_Int32 /*nElement*/, + const Reference & xAttrList) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + ProcessAttribute(aIter); +} + +void XMLMetaImportContextBase::endFastElement(sal_Int32 ) +{ + SAL_WARN_IF(!m_xStart.is(), "xmloff.text", "no mxStart?"); + if (!m_xStart.is()) return; + + const Reference xEndRange( + GetImport().GetTextImport()->GetCursorAsRange()->getStart() ); + + // create range for insertion + const Reference xInsertionCursor( + GetImport().GetTextImport()->GetText()->createTextCursorByRange( + xEndRange) ); + xInsertionCursor->gotoRange(m_xStart, true); + + InsertMeta(xInsertionCursor); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLMetaImportContextBase::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + return XMLImpSpanContext_Impl::CreateSpanContext( GetImport(), nElement, + xAttrList, m_rHints, m_rIgnoreLeadingSpace ); +} + +void XMLMetaImportContextBase::characters( const OUString& i_rChars ) +{ + GetImport().GetTextImport()->InsertString(i_rChars, m_rIgnoreLeadingSpace); +} + +void XMLMetaImportContextBase::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + if ( aIter.getToken() == XML_ELEMENT(XML, XML_ID) ) + m_XmlId = aIter.toString(); + else + XMLOFF_WARN_UNKNOWN("xmloff", aIter); +} + +namespace { + +/** text:meta */ +class XMLMetaImportContext : public XMLMetaImportContextBase +{ + // RDFa + bool m_bHaveAbout; + OUString m_sAbout; + OUString m_sProperty; + OUString m_sContent; + OUString m_sDatatype; + +public: + + XMLMetaImportContext( + SvXMLImport& i_rImport, + sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ); + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void InsertMeta(const Reference & i_xInsertionRange) override; +}; + +} + +XMLMetaImportContext::XMLMetaImportContext( + SvXMLImport& i_rImport, + sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ) + : XMLMetaImportContextBase( i_rImport, nElement, + i_rHints, i_rIgnoreLeadingSpace ) + , m_bHaveAbout(false) +{ +} + +void XMLMetaImportContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + // RDFa + case XML_ELEMENT(XHTML, XML_ABOUT): + m_sAbout = aIter.toString(); + m_bHaveAbout = true; + break; + case XML_ELEMENT(XHTML, XML_PROPERTY): + m_sProperty = aIter.toString(); + break; + case XML_ELEMENT(XHTML, XML_CONTENT): + m_sContent = aIter.toString(); + break; + case XML_ELEMENT(XHTML, XML_DATATYPE): + m_sDatatype = aIter.toString(); + break; + default: + XMLMetaImportContextBase::ProcessAttribute(aIter); + } +} + +void XMLMetaImportContext::InsertMeta( + const Reference & i_xInsertionRange) +{ + SAL_WARN_IF(m_bHaveAbout == m_sProperty.isEmpty(), "xmloff.text", "XMLMetaImportContext::InsertMeta: invalid RDFa?"); + if (!m_XmlId.isEmpty() || (m_bHaveAbout && !m_sProperty.isEmpty())) + { + // insert mark + const uno::Reference xMeta( + XMLTextMarkImportContext::CreateAndInsertMark( + GetImport(), + "com.sun.star.text.InContentMetadata", + OUString(), + i_xInsertionRange, m_XmlId), + uno::UNO_QUERY); + SAL_WARN_IF(!xMeta.is(), "xmloff.text", "cannot insert Meta?"); + + if (xMeta.is() && m_bHaveAbout) + { + GetImport().AddRDFa(xMeta, + m_sAbout, m_sProperty, m_sContent, m_sDatatype); + } + } + else + { + SAL_INFO("xmloff.text", "invalid : no xml:id, no valid RDFa"); + } +} + +namespace { + +/** text:meta-field */ +class XMLMetaFieldImportContext : public XMLMetaImportContextBase +{ + OUString m_DataStyleName; + +public: + + XMLMetaFieldImportContext( + SvXMLImport& i_rImport, + sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ); + + virtual void ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) override; + + virtual void InsertMeta(const Reference & i_xInsertionRange) override; +}; + +} + +XMLMetaFieldImportContext::XMLMetaFieldImportContext( + SvXMLImport& i_rImport, + sal_Int32 nElement, + XMLHints_Impl& i_rHints, + bool & i_rIgnoreLeadingSpace ) + : XMLMetaImportContextBase( i_rImport, nElement, + i_rHints, i_rIgnoreLeadingSpace ) +{ +} + +void XMLMetaFieldImportContext::ProcessAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + m_DataStyleName = aIter.toString(); + break; + default: + XMLMetaImportContextBase::ProcessAttribute(aIter); + } +} + +void XMLMetaFieldImportContext::InsertMeta( + const Reference & i_xInsertionRange) +{ + if (!m_XmlId.isEmpty()) // valid? + { + // insert mark + const Reference xPropertySet( + XMLTextMarkImportContext::CreateAndInsertMark( + GetImport(), + "com.sun.star.text.textfield.MetadataField", + OUString(), + i_xInsertionRange, m_XmlId), + UNO_QUERY); + SAL_WARN_IF(!xPropertySet.is(), "xmloff.text", "cannot insert MetaField?"); + if (!xPropertySet.is()) return; + + if (!m_DataStyleName.isEmpty()) + { + bool isDefaultLanguage(true); + + const sal_Int32 nKey( GetImport().GetTextImport()->GetDataStyleKey( + m_DataStyleName, & isDefaultLanguage) ); + + if (-1 != nKey) + { + OUString sPropertyIsFixedLanguage("IsFixedLanguage"); + xPropertySet->setPropertyValue("NumberFormat", Any(nKey)); + if ( xPropertySet->getPropertySetInfo()-> + hasPropertyByName( sPropertyIsFixedLanguage ) ) + { + xPropertySet->setPropertyValue( sPropertyIsFixedLanguage, + Any(!isDefaultLanguage) ); + } + } + } + } + else + { + SAL_INFO("xmloff.text", "invalid : no xml:id"); + } +} + +namespace { + +/** + * Process index marks. + * + * All *-mark-end index marks should instantiate *this* class (because + * it doesn't process attributes other than ID), while the *-mark and + * *-mark-start classes should instantiate the appropriate subclasses. + */ +class XMLIndexMarkImportContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + OUString sID; + +public: + + XMLIndexMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints); + + void SAL_CALL startFastElement(sal_Int32 nElement, const Reference & xAttrList) override; + +protected: + + /// process all attributes + void ProcessAttributes(sal_Int32 nElement, const Reference & xAttrList, + Reference& rPropSet); + + /** + * All marks can be created immediately. Since we don't care about + * the element content, ProcessAttribute should set the properties + * immediately. + * + * This method tolerates an empty PropertySet; subclasses however + * are not expected to. + */ + virtual void ProcessAttribute(sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference& rPropSet); + + static void GetServiceName(OUString& sServiceName, + sal_Int32 nElement); + + bool CreateMark(Reference& rPropSet, + const OUString& rServiceName); +}; + +} + +XMLIndexMarkImportContext_Impl::XMLIndexMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints) + : SvXMLImportContext(rImport) + , m_rHints(rHints) +{ +} + +void XMLIndexMarkImportContext_Impl::startFastElement( + sal_Int32 nElement, + const Reference & xAttrList) +{ + // get Cursor position (needed for all cases) + Reference xPos( + GetImport().GetTextImport()->GetCursor()->getStart()); + Reference xMark; + + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_TOC_MARK): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK): + { + // single mark: create mark and insert + OUString sService; + GetServiceName(sService, nElement); + if (CreateMark(xMark, sService)) + { + ProcessAttributes(nElement, xAttrList, xMark); + m_rHints.push_back( + std::make_unique(xMark, xPos)); + } + // else: can't create mark -> ignore + break; + } + + case XML_ELEMENT(TEXT, XML_TOC_MARK_START): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START): + { + // start: create mark and insert (if ID is found) + OUString sService; + GetServiceName(sService, nElement); + if (CreateMark(xMark, sService)) + { + ProcessAttributes(nElement, xAttrList, xMark); + if (!sID.isEmpty()) + { + // process only if we find an ID + m_rHints.push_back( + std::make_unique(xMark, xPos, sID)); + } + // else: no ID -> we'll never find the end -> ignore + } + // else: can't create mark -> ignore + break; + } + + case XML_ELEMENT(TEXT, XML_TOC_MARK_END): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END): + { + // end: search for ID and set end of mark + + // call process attributes with empty XPropertySet: + ProcessAttributes(nElement, xAttrList, xMark); + if (!sID.isEmpty()) + { + // if we have an ID, find the hint and set the end position + XMLIndexMarkHint_Impl *const pHint = m_rHints.GetIndexHintById(sID); + if (pHint) + // set end and stop searching + pHint->SetEnd(xPos); + } + // else: no ID -> ignore + break; + } + + default: + SAL_WARN("xmloff.text", "unknown index mark type!"); + break; + } +} + +void XMLIndexMarkImportContext_Impl::ProcessAttributes( + sal_Int32 nElement, + const Reference & xAttrList, + Reference& rPropSet) +{ + // process attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + ProcessAttribute(nElement, aIter, rPropSet); + } +} + +void XMLIndexMarkImportContext_Impl::ProcessAttribute( + sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference& rPropSet) +{ + // we only know ID + string-value attribute; + // (former: marks, latter: -start + -end-marks) + // the remainder is handled in sub-classes + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_TOC_MARK): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK): + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_STRING_VALUE) ) + { + rPropSet->setPropertyValue("AlternativeText", uno::Any(aIter.toString())); + } + // else: ignore! + break; + + case XML_ELEMENT(TEXT, XML_TOC_MARK_START): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_TOC_MARK_END): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END): + if ( aIter.getToken() == XML_ELEMENT(TEXT, XML_ID) ) + { + sID = aIter.toString(); + } + // else: ignore + break; + + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + break; + } +} + + +void XMLIndexMarkImportContext_Impl::GetServiceName( + OUString& sServiceName, + sal_Int32 nElement) +{ + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_TOC_MARK): + case XML_ELEMENT(TEXT, XML_TOC_MARK_START): + case XML_ELEMENT(TEXT, XML_TOC_MARK_END): + { + sServiceName = "com.sun.star.text.ContentIndexMark"; + break; + } + + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END): + { + sServiceName = "com.sun.star.text.UserIndexMark"; + break; + } + + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END): + { + sServiceName = "com.sun.star.text.DocumentIndexMark"; + break; + } + + default: + { + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + sServiceName.clear(); + break; + } + } +} + +bool XMLIndexMarkImportContext_Impl::CreateMark( + Reference& rPropSet, + const OUString& rServiceName) +{ + Reference + xFactory(GetImport().GetModel(), UNO_QUERY); + + if( xFactory.is() ) + { + Reference xPropSet( xFactory->createInstance(rServiceName), UNO_QUERY ); + if (xPropSet.is()) + rPropSet = xPropSet; + return true; + } + + return false; +} + +namespace { + +class XMLTOCMarkImportContext_Impl : public XMLIndexMarkImportContext_Impl +{ +public: + + XMLTOCMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints); + +protected: + + /** process outline level */ + virtual void ProcessAttribute(sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference& rPropSet) override; +}; + +} + +XMLTOCMarkImportContext_Impl::XMLTOCMarkImportContext_Impl( + SvXMLImport& rImport, XMLHints_Impl& rHints) : + XMLIndexMarkImportContext_Impl(rImport, rHints) +{ +} + +void XMLTOCMarkImportContext_Impl::ProcessAttribute( + sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference& rPropSet) +{ + SAL_WARN_IF(!rPropSet.is(), "xmloff.text", "need PropertySet"); + + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + // outline level: set Level property + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( nTmp, aIter.toView() ) + && nTmp >= 1 + && nTmp < GetImport().GetTextImport()-> + GetChapterNumbering()->getCount() ) + { + rPropSet->setPropertyValue("Level", uno::Any(static_cast(nTmp - 1))); + } + // else: value out of range -> ignore + break; + } + default: + // else: delegate to superclass + XMLIndexMarkImportContext_Impl::ProcessAttribute( + nElement, aIter, rPropSet); + } +} + +namespace { + +class XMLUserIndexMarkImportContext_Impl : public XMLIndexMarkImportContext_Impl +{ +public: + + XMLUserIndexMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints); + +protected: + + /** process index name */ + virtual void ProcessAttribute(sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference& rPropSet) override; +}; + +} + +XMLUserIndexMarkImportContext_Impl::XMLUserIndexMarkImportContext_Impl( + SvXMLImport& rImport, XMLHints_Impl& rHints) : + XMLIndexMarkImportContext_Impl(rImport, rHints) +{ +} + +void XMLUserIndexMarkImportContext_Impl::ProcessAttribute( + sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference& rPropSet) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_INDEX_NAME): + rPropSet->setPropertyValue("UserIndexName", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + // outline level: set Level property + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( + nTmp, aIter.toView(), 0, + GetImport().GetTextImport()->GetChapterNumbering()->getCount())) + { + rPropSet->setPropertyValue("Level", uno::Any(static_cast(nTmp - 1))); + } + // else: value out of range -> ignore + break; + } + default: + // else: unknown text property: delegate to super class + XMLIndexMarkImportContext_Impl::ProcessAttribute( + nElement, aIter, rPropSet); + } +} + +namespace { + +class XMLAlphaIndexMarkImportContext_Impl : public XMLIndexMarkImportContext_Impl +{ +public: + + XMLAlphaIndexMarkImportContext_Impl( + SvXMLImport& rImport, + XMLHints_Impl& rHints); + +protected: + + /** process primary + secondary keys */ + virtual void ProcessAttribute(sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference& rPropSet) override; +}; + +} + +XMLAlphaIndexMarkImportContext_Impl::XMLAlphaIndexMarkImportContext_Impl( + SvXMLImport& rImport, XMLHints_Impl& rHints) : + XMLIndexMarkImportContext_Impl(rImport, rHints) +{ +} + +void XMLAlphaIndexMarkImportContext_Impl::ProcessAttribute( + sal_Int32 nElement, + const sax_fastparser::FastAttributeList::FastAttributeIter & aIter, + Reference& rPropSet) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_KEY1): + rPropSet->setPropertyValue("PrimaryKey", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_KEY2): + rPropSet->setPropertyValue("SecondaryKey", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_KEY1_PHONETIC): + rPropSet->setPropertyValue("PrimaryKeyReading", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_KEY2_PHONETIC): + rPropSet->setPropertyValue("SecondaryKeyReading", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_STRING_VALUE_PHONETIC): + rPropSet->setPropertyValue("TextReading", uno::Any(aIter.toString())); + break; + case XML_ELEMENT(TEXT, XML_MAIN_ENTRY): + { + bool bMainEntry = false; + bool bTmp(false); + + if (::sax::Converter::convertBool(bTmp, aIter.toView())) + bMainEntry = bTmp; + + rPropSet->setPropertyValue("IsMainEntry", uno::Any(bMainEntry)); + break; + } + default: + XMLIndexMarkImportContext_Impl::ProcessAttribute( + nElement, aIter, rPropSet); + } +} + + +XMLImpSpanContext_Impl::XMLImpSpanContext_Impl( + SvXMLImport& rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace, + sal_uInt8 nSFConvFlags) +: SvXMLImportContext( rImport ) +, m_rHints( rHints ) +, pHint( nullptr ) +, rIgnoreLeadingSpace( rIgnLeadSpace ) +, nStarFontsConvFlags( nSFConvFlags & (CONV_FROM_STAR_BATS|CONV_FROM_STAR_MATH) ) +{ + OUString aStyleName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(TEXT, XML_STYLE_NAME) ) + { + aStyleName = aIter.toString(); + break; + } + } + + if( !aStyleName.isEmpty() ) + { + pHint = new XMLStyleHint_Impl( aStyleName, + GetImport().GetTextImport()->GetCursorAsRange()->getStart() ); + m_rHints.push_back(std::unique_ptr(pHint)); + } +} + +void XMLImpSpanContext_Impl::endFastElement(sal_Int32 ) +{ + if (!pHint) + return; + + Reference xCrsrRange(GetImport().GetTextImport()->GetCursorAsRange()); + if (!xCrsrRange.is()) + return; // Robust (defective file) + + pHint->SetEnd(xCrsrRange->getStart()); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpSpanContext_Impl::CreateSpanContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnoreLeadingSpace, + sal_uInt8 nStarFontsConvFlags + ) +{ + SvXMLImportContext *pContext = nullptr; + + switch( nElement ) + { + case XML_ELEMENT(TEXT, XML_SPAN): + pContext = new XMLImpSpanContext_Impl( rImport, nElement, + xAttrList, + rHints, + rIgnoreLeadingSpace + ,nStarFontsConvFlags + ); + break; + + case XML_ELEMENT(TEXT, XML_TAB): + pContext = new XMLCharContext( rImport, xAttrList, + 0x0009, false ); + rIgnoreLeadingSpace = false; + break; + + case XML_ELEMENT(TEXT, XML_LINE_BREAK): + if (xAttrList->hasAttribute(XML_ELEMENT(LO_EXT, XML_CLEAR))) + { + pContext = new SvXMLLineBreakContext(rImport, *rImport.GetTextImport()); + } + else + { + pContext = new XMLCharContext(rImport, ControlCharacter::LINE_BREAK); + } + rIgnoreLeadingSpace = false; + break; + + case XML_ELEMENT(TEXT, XML_S): + pContext = new XMLCharContext( rImport, xAttrList, 0x0020, true ); + rIgnoreLeadingSpace = false; + break; + + case XML_ELEMENT(TEXT, XML_A): + { + // test for HyperLinkURL property. If present, insert link as + // text property (StarWriter), else try to insert as text + // field (StarCalc, StarDraw, ...) + Reference< beans::XPropertySet > xPropSet( rImport.GetTextImport()->GetCursor(), UNO_QUERY ); + + if ( xPropSet->getPropertySetInfo()->hasPropertyByName( "HyperLinkURL" ) ) + { + pContext = new XMLImpHyperlinkContext_Impl( + rImport, + nElement, + xAttrList, + rHints, + rIgnoreLeadingSpace ); + } + else + { + pContext = new XMLUrlFieldImportContext(rImport, *rImport.GetTextImport()); + //whitespace handling like other fields + rIgnoreLeadingSpace = false; + + } + break; + } + + case XML_ELEMENT(TEXT, XML_RUBY): + pContext = new XMLImpRubyContext_Impl( rImport, nElement, + xAttrList, + rHints, + rIgnoreLeadingSpace ); + break; + + case XML_ELEMENT(TEXT, XML_NOTE): + if (rImport.GetTextImport()->IsInFrame()) + { + // we must not insert footnotes into text frames + pContext = new SvXMLImportContext( rImport ); + } + else + { + pContext = new XMLFootnoteImportContext(rImport, *rImport.GetTextImport()); + } + rIgnoreLeadingSpace = false; + break; + + case XML_ELEMENT(TEXT, XML_REFERENCE_MARK): + case XML_ELEMENT(TEXT, XML_BOOKMARK): + case XML_ELEMENT(TEXT, XML_BOOKMARK_START): + case XML_ELEMENT(TEXT, XML_BOOKMARK_END): + pContext = new XMLTextMarkImportContext(rImport, *rImport.GetTextImport(), + rHints.GetCrossRefHeadingBookmark()); + break; + + case XML_ELEMENT(FIELD, XML_FIELDMARK): + case XML_ELEMENT(FIELD, XML_FIELDMARK_START): + case XML_ELEMENT(FIELD, XML_FIELDMARK_SEPARATOR): + case XML_ELEMENT(FIELD, XML_FIELDMARK_END): + pContext = new XMLTextMarkImportContext(rImport, *rImport.GetTextImport(), + rHints.GetCrossRefHeadingBookmark()); + break; + + case XML_ELEMENT(TEXT, XML_REFERENCE_MARK_START): + pContext = new XMLStartReferenceContext_Impl( rImport, + rHints, xAttrList ); + break; + + case XML_ELEMENT(TEXT, XML_REFERENCE_MARK_END): + pContext = new XMLEndReferenceContext_Impl( rImport, + rHints, xAttrList ); + break; + + case XML_ELEMENT(DRAW, XML_FRAME): + { + Reference < XTextRange > xAnchorPos = + rImport.GetTextImport()->GetCursor()->getStart(); + XMLTextFrameContext *pTextFrameContext = + new XMLTextFrameContext(rImport, + xAttrList, + TextContentAnchorType_AS_CHARACTER ); + // Remove check for text content. (#i33242#) + // Check for text content is done on the processing of the hint + if( TextContentAnchorType_AT_CHARACTER == + pTextFrameContext->GetAnchorType() ) + { + rHints.push_back(std::make_unique( + pTextFrameContext, xAnchorPos)); + } + pContext = pTextFrameContext; + rIgnoreLeadingSpace = false; + } + break; + case XML_ELEMENT(DRAW, XML_A): + { + Reference < XTextRange > xAnchorPos(rImport.GetTextImport()->GetCursor()->getStart()); + pContext = + new XMLTextFrameHyperlinkContext( rImport, nElement, + xAttrList, + TextContentAnchorType_AS_CHARACTER ); + rHints.push_back( + std::make_unique(pContext, xAnchorPos)); + } + break; + + case XML_ELEMENT(TEXT, XML_TOC_MARK): + case XML_ELEMENT(TEXT, XML_TOC_MARK_START): + pContext = new XMLTOCMarkImportContext_Impl( + rImport, rHints); + break; + + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_START): + pContext = new XMLUserIndexMarkImportContext_Impl( + rImport, rHints); + break; + + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_START): + pContext = new XMLAlphaIndexMarkImportContext_Impl( + rImport, rHints); + break; + + case XML_ELEMENT(TEXT, XML_TOC_MARK_END): + case XML_ELEMENT(TEXT, XML_USER_INDEX_MARK_END): + case XML_ELEMENT(TEXT, XML_ALPHABETICAL_INDEX_MARK_END): + pContext = new XMLIndexMarkImportContext_Impl( + rImport, rHints); + break; + + case XML_ELEMENT(TEXT, XML_CHANGE_START): + case XML_ELEMENT(TEXT, XML_CHANGE_END): + case XML_ELEMENT(TEXT, XML_CHANGE): + pContext = new XMLChangeImportContext( + rImport, + ((nElement == XML_ELEMENT(TEXT, XML_CHANGE_END)) + ? XMLChangeImportContext::Element::END + : (nElement == XML_ELEMENT(TEXT, XML_CHANGE_START)) + ? XMLChangeImportContext::Element::START + : XMLChangeImportContext::Element::POINT), + false); + break; + + case XML_ELEMENT(TEXT, XML_META): + pContext = new XMLMetaImportContext(rImport, nElement, + rHints, rIgnoreLeadingSpace ); + break; + + case XML_ELEMENT(TEXT, XML_META_FIELD): + pContext = new XMLMetaFieldImportContext(rImport, nElement, + rHints, rIgnoreLeadingSpace ); + break; + + case XML_ELEMENT(LO_EXT, XML_CONTENT_CONTROL): + pContext = new XMLContentControlContext(rImport, nElement, rHints, rIgnoreLeadingSpace); + break; + + default: + // none of the above? then it's probably a text field! + pContext = XMLTextFieldImportContext::CreateTextFieldImportContext( + rImport, *rImport.GetTextImport(), nElement); + // #108784# import draw elements (except control shapes in headers) + if( pContext == nullptr && + !( rImport.GetTextImport()->IsInHeaderFooter() && + nElement == XML_ELEMENT(DRAW, XML_CONTROL ) ) ) + { + Reference < XShapes > xShapes; + SvXMLShapeContext* pShapeContext = XMLShapeImportHelper::CreateGroupChildContext( + rImport, nElement, xAttrList, xShapes ); + pContext = pShapeContext; + // OD 2004-04-20 #i26791# - keep shape in a text frame hint to + // adjust its anchor position, if it's at-character anchored + Reference < XTextRange > xAnchorPos = + rImport.GetTextImport()->GetCursor()->getStart(); + rHints.push_back( + std::make_unique(pShapeContext, xAnchorPos)); + } + // Behind fields, shapes and any unknown content blanks aren't ignored + rIgnoreLeadingSpace = false; + } + + if (!pContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + return pContext; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLImpSpanContext_Impl::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + return CreateSpanContext( GetImport(), nElement, xAttrList, + m_rHints, rIgnoreLeadingSpace + ,nStarFontsConvFlags + ); +} + +void XMLImpSpanContext_Impl::characters( const OUString& rChars ) +{ + OUString sStyleName; + if( pHint ) + sStyleName = pHint->GetStyleName(); + OUString sChars = + GetImport().GetTextImport()->ConvertStarFonts( rChars, sStyleName, + nStarFontsConvFlags, + false, GetImport() ); + GetImport().GetTextImport()->InsertString( sChars, rIgnoreLeadingSpace ); +} + + +XMLParaContext::XMLParaContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const Reference< xml::sax::XFastAttributeList > & xAttrList ) : + SvXMLImportContext( rImport ), + xStart( rImport.GetTextImport()->GetCursorAsRange()->getStart() ), + m_bHaveAbout(false), + nOutlineLevel( (nElement & TOKEN_MASK) == XML_H ? 1 : -1 ), + // Lost outline numbering in master document (#i73509#) + mbOutlineLevelAttrFound( false ), + mbOutlineContentVisible(true), + bIgnoreLeadingSpace( true ), + bHeading( (nElement & TOKEN_MASK) == XML_H ), + bIsListHeader( false ), + bIsRestart (false), + nStartValue(0), + nStarFontsConvFlags( 0 ) +{ + bool bHaveXmlId( false ); + OUString aCondStyleName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XML, XML_ID): + m_sXmlId = aIter.toString(); + bHaveXmlId = true; + break; + case XML_ELEMENT(XHTML, XML_ABOUT): + m_sAbout = aIter.toString(); + m_bHaveAbout = true; + break; + case XML_ELEMENT(XHTML, XML_PROPERTY): + m_sProperty = aIter.toString(); + break; + case XML_ELEMENT(XHTML, XML_CONTENT): + m_sContent = aIter.toString(); + break; + case XML_ELEMENT(XHTML, XML_DATATYPE): + m_sDatatype = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_ID): + if (!bHaveXmlId) { m_sXmlId = aIter.toString(); } + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + sStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_COND_STYLE_NAME): + aCondStyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_OUTLINE_LEVEL): + { + sal_Int32 nTmp = aIter.toInt32(); + if( nTmp > 0 ) + { + if( nTmp > 127 ) + nTmp = 127; + nOutlineLevel = static_cast(nTmp); + } + // Lost outline numbering in master document (#i73509#) + mbOutlineLevelAttrFound = true; + } + break; + case XML_ELEMENT(LO_EXT, XML_OUTLINE_CONTENT_VISIBLE): + { + bool bBool(false); + if (::sax::Converter::convertBool(bBool, aIter.toView())) + mbOutlineContentVisible = bBool; + } + break; + case XML_ELEMENT(TEXT, XML_IS_LIST_HEADER): + { + bool bBool(false); + if (::sax::Converter::convertBool(bBool, aIter.toView())) + bIsListHeader = bBool; + } + break; + case XML_ELEMENT(TEXT, XML_RESTART_NUMBERING): + { + bool bBool(false); + if (::sax::Converter::convertBool(bBool, aIter.toView())) + bIsRestart = bBool; + } + break; + case XML_ELEMENT(TEXT, XML_START_VALUE): + { + nStartValue = sal::static_int_cast< sal_Int16 >(aIter.toInt32()); + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( !aCondStyleName.isEmpty() ) + sStyleName = aCondStyleName; +} + +void XMLParaContext::endFastElement(sal_Int32 ) +{ + rtl::Reference < XMLTextImportHelper > xTxtImport( + GetImport().GetTextImport()); + Reference xEnd; + try + { + Reference const xCrsrRange(xTxtImport->GetCursorAsRange()); + if (!xCrsrRange.is()) + return; // Robust (defective file) + xEnd = xCrsrRange->getStart(); + } + catch (uno::Exception const&) + { + SAL_INFO("xmloff.text", "XMLParaContext: cursor disposed?"); + return; + } + + // if we have an id set for this paragraph, get a cursor for this + // paragraph and register it with the given identifier + // FIXME: this is just temporary, and should be removed when + // EditEngine paragraphs implement XMetadatable! + if (!m_sXmlId.isEmpty()) + { + Reference < XTextCursor > xIdCursor( xTxtImport->GetText()->createTextCursorByRange( xStart ) ); + if( xIdCursor.is() ) + { + xIdCursor->gotoRange( xEnd, true ); + GetImport().getInterfaceToIdentifierMapper().registerReference( + m_sXmlId, Reference( xIdCursor, UNO_QUERY )); + } + } + + // insert a paragraph break + xTxtImport->InsertControlCharacter( ControlCharacter::APPEND_PARAGRAPH ); + + // create a cursor that select the whole last paragraph + Reference < XTextCursor > xAttrCursor; + try { + xAttrCursor = xTxtImport->GetText()->createTextCursorByRange( xStart ); + if( !xAttrCursor.is() ) + return; // Robust (defective file) + } catch (const uno::Exception &) { + // createTextCursorByRange() likes to throw runtime exception, even + // though it just means 'we were unable to create the cursor' + return; + } + xAttrCursor->gotoRange( xEnd, true ); + + // xml:id for RDF metadata + if (!m_sXmlId.isEmpty() || m_bHaveAbout || !m_sProperty.isEmpty()) + { + try { + const uno::Reference xEA + (xAttrCursor, uno::UNO_QUERY_THROW); + const uno::Reference xEnum( + xEA->createEnumeration(), uno::UNO_SET_THROW); + SAL_WARN_IF(!xEnum->hasMoreElements(), "xmloff.text", "xml:id: no paragraph?"); + if (xEnum->hasMoreElements()) { + uno::Reference xMeta; + xEnum->nextElement() >>= xMeta; + SAL_WARN_IF(!xMeta.is(), "xmloff.text", "xml:id: not XMetadatable"); + GetImport().SetXmlId(xMeta, m_sXmlId); + if (m_bHaveAbout) + { + GetImport().AddRDFa(xMeta, + m_sAbout, m_sProperty, m_sContent, m_sDatatype); + } + SAL_WARN_IF(xEnum->hasMoreElements(), "xmloff.text", "xml:id: > 1 paragraph?"); + } + } catch (const uno::Exception &) { + SAL_INFO("xmloff.text", "XMLParaContext::~XMLParaContext: exception"); + } + } + + OUString const sCellParaStyleName(xTxtImport->GetCellParaStyleDefault()); + if( !sCellParaStyleName.isEmpty() ) + { + /* Suppress handling of outline and list attributes, + because of side effects of method (#i80724#) + */ + xTxtImport->SetStyleAndAttrs( GetImport(), xAttrCursor, + sCellParaStyleName, + true, + false, -1, // suppress outline handling + false ); // suppress list attributes handling + } + + // #103445# for headings without style name, find the proper style + if( bHeading && sStyleName.isEmpty() ) + xTxtImport->FindOutlineStyleName( sStyleName, nOutlineLevel ); + + // set style and hard attributes at the previous paragraph + // Add parameter (#i73509#) + sStyleName = xTxtImport->SetStyleAndAttrs( GetImport(), xAttrCursor, + sStyleName, + true, + mbOutlineLevelAttrFound, + bHeading ? nOutlineLevel : -1, + true, + mbOutlineContentVisible); + + // handle list style header + if (bHeading && (bIsListHeader || bIsRestart)) + { + Reference xPropSet( xAttrCursor, UNO_QUERY ); + + if (xPropSet.is()) + { + if (bIsListHeader) + { + OUString sNumberingIsNumber + ("NumberingIsNumber"); + if(xPropSet->getPropertySetInfo()-> + hasPropertyByName(sNumberingIsNumber)) + { + xPropSet->setPropertyValue + (sNumberingIsNumber, Any( false ) ); + } + } + if (bIsRestart) + { + OUString sParaIsNumberingRestart + ("ParaIsNumberingRestart"); + OUString sNumberingStartValue + ("NumberingStartValue"); + if (xPropSet->getPropertySetInfo()-> + hasPropertyByName(sParaIsNumberingRestart)) + { + xPropSet->setPropertyValue + (sParaIsNumberingRestart, Any(true)); + } + + if (xPropSet->getPropertySetInfo()-> + hasPropertyByName(sNumberingStartValue)) + { + xPropSet->setPropertyValue + (sNumberingStartValue, Any(nStartValue)); + } + } + + } + } + + if (m_xHints) + { + bool bSetNoFormatAttr = false; + uno::Reference xCursorProps(xAttrCursor, uno::UNO_QUERY); + if (m_xHints->GetHints().size() > 1) + { + // We have multiple hints, then make try to ask the cursor to not upgrade our character + // attributes to paragraph-level formatting, which would lead to incorrect rendering. + uno::Reference xCursorPropsInfo = xCursorProps->getPropertySetInfo(); + bSetNoFormatAttr = xCursorPropsInfo->hasPropertyByName("NoFormatAttr"); + } + if (bSetNoFormatAttr) + { + xCursorProps->setPropertyValue("NoFormatAttr", uno::Any(true)); + } + for (const auto & i : m_xHints->GetHints()) + { + XMLHint_Impl *const pHint = i.get(); + xAttrCursor->gotoRange( pHint->GetStart(), false ); + xAttrCursor->gotoRange( pHint->GetEnd(), true ); + switch( pHint->GetType() ) + { + case XMLHintType::XML_HINT_STYLE: + { + const OUString& rStyleName = + static_cast(pHint)->GetStyleName(); + if( !rStyleName.isEmpty() ) + xTxtImport->SetStyleAndAttrs( GetImport(), + xAttrCursor, rStyleName, + false ); + } + break; + case XMLHintType::XML_HINT_REFERENCE: + { + const OUString& rRefName = + static_cast(pHint)->GetRefName(); + if( !rRefName.isEmpty() ) + { + if( !pHint->GetEnd().is() ) + pHint->SetEnd(xEnd); + + // reference name uses rStyleName member + // borrow from XMLTextMarkImportContext + XMLTextMarkImportContext::CreateAndInsertMark( + GetImport(), + "com.sun.star.text.ReferenceMark", + rRefName, + xAttrCursor); + } + } + break; + case XMLHintType::XML_HINT_HYPERLINK: + { + const XMLHyperlinkHint_Impl *pHHint = + static_cast(pHint); + xTxtImport->SetHyperlink( GetImport(), + xAttrCursor, + pHHint->GetHRef(), + pHHint->GetName(), + pHHint->GetTargetFrameName(), + pHHint->GetStyleName(), + pHHint->GetVisitedStyleName(), + pHHint->GetEventsContext() ); + } + break; + case XMLHintType::XML_HINT_INDEX_MARK: + { + Reference xMark( + static_cast(pHint)->GetMark()); + Reference xContent(xMark, UNO_QUERY); + try + { + xTxtImport->GetText()->insertTextContent( + xAttrCursor, xContent, true ); + } + catch (uno::RuntimeException const&) + { + TOOLS_INFO_EXCEPTION("xmloff.text", "could not insert index mark, presumably in editengine text"); + } + } + break; + case XMLHintType::XML_HINT_TEXT_FRAME: + { + const XMLTextFrameHint_Impl *pFHint = + static_cast(pHint); + // Check for text content (#i33242#) + Reference < XTextContent > xTextContent = + pFHint->GetTextContent(); + if ( xTextContent.is() ) + { + /* Core impl. of the unification of drawing objects and + Writer fly frames (#i26791#) + */ + if ( pFHint->IsBoundAtChar() ) + { + xTextContent->attach( xAttrCursor ); + } + } + /* Consider, that hint can also contain a shape - + e.g. drawing object of type 'Text'. (#i33242#) + */ + else + { + Reference < XShape > xShape = pFHint->GetShape(); + if ( xShape.is() ) + { + // determine anchor type + Reference < XPropertySet > xPropSet( xShape, UNO_QUERY ); + TextContentAnchorType eAnchorType = + TextContentAnchorType_AT_PARAGRAPH; + { + Any aAny = xPropSet->getPropertyValue( "AnchorType" ); + aAny >>= eAnchorType; + } + if ( TextContentAnchorType_AT_CHARACTER == eAnchorType ) + { + // set anchor position for at-character anchored objects + xPropSet->setPropertyValue("TextRange", Any(xAttrCursor)); + } + } + } + } + break; + /* Core impl. of the unification of drawing objects and + Writer fly frames (#i26791#) + */ + case XMLHintType::XML_HINT_DRAW: + { + const XMLDrawHint_Impl *pDHint = + static_cast(pHint); + // Improvement: hint directly provides the shape. (#i33242#) + const Reference < XShape >& xShape = pDHint->GetShape(); + if ( xShape.is() ) + { + // determine anchor type + Reference < XPropertySet > xPropSet( xShape, UNO_QUERY ); + TextContentAnchorType eAnchorType = TextContentAnchorType_AT_PARAGRAPH; + { + Any aAny = xPropSet->getPropertyValue( "AnchorType" ); + aAny >>= eAnchorType; + } + if ( TextContentAnchorType_AT_CHARACTER == eAnchorType ) + { + // set anchor position for at-character anchored objects + xPropSet->setPropertyValue("TextRange", Any(xAttrCursor)); + } + } + } + break; + default: + SAL_WARN( "xmloff.text", "What's this" ); + break; + } + } + if (bSetNoFormatAttr) + { + xCursorProps->setPropertyValue("NoFormatAttr", uno::Any(false)); + } + } + m_xHints.reset(); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLParaContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if (!m_xHints) + m_xHints.reset(new XMLHints_Impl); + return XMLImpSpanContext_Impl::CreateSpanContext( + GetImport(), nElement, xAttrList, + *m_xHints, bIgnoreLeadingSpace, + nStarFontsConvFlags); +} + +void XMLParaContext::characters( const OUString& rChars ) +{ + OUString sChars = + GetImport().GetTextImport()->ConvertStarFonts( rChars, sStyleName, + nStarFontsConvFlags, + true, GetImport() ); + GetImport().GetTextImport()->InsertString( sChars, bIgnoreLeadingSpace ); +} + + +XMLNumberedParaContext::XMLNumberedParaContext( + SvXMLImport& i_rImport, + sal_Int32 /*nElement*/, + const Reference< xml::sax::XFastAttributeList > & xAttrList ) : + SvXMLImportContext( i_rImport ), + m_Level(0), + m_StartValue(-1) +{ + OUString StyleName; + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch( aIter.getToken() ) + { + case XML_ELEMENT(XML, XML_ID): +//FIXME: there is no UNO API for lists + break; + case XML_ELEMENT(TEXT, XML_LIST_ID): + m_ListId = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_LEVEL): + { + sal_Int32 nTmp = aIter.toInt32(); + if ( nTmp >= 1 && nTmp <= SHRT_MAX ) { + m_Level = static_cast(nTmp) - 1; + } + } + break; + case XML_ELEMENT(TEXT, XML_STYLE_NAME): + StyleName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_CONTINUE_NUMBERING): + // this attribute is deprecated +// ContinueNumbering = IsXMLToken(sValue, XML_TRUE); + break; + case XML_ELEMENT(TEXT, XML_START_VALUE): + { + sal_Int32 nTmp = aIter.toInt32(); + if ( nTmp >= 0 && nTmp <= SHRT_MAX ) { + m_StartValue = static_cast(nTmp); + } + } + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + XMLTextListsHelper& rTextListsHelper( + i_rImport.GetTextImport()->GetTextListHelper() ); + if (m_ListId.isEmpty()) + { + SAL_WARN_IF(0 <= i_rImport.GetODFVersion().compareTo(u"1.2"), "xmloff.text", "invalid numbered-paragraph: no list-id (1.2)"); + m_ListId = rTextListsHelper.GetNumberedParagraphListId(m_Level, + StyleName); + SAL_WARN_IF(m_ListId.isEmpty(), "xmloff.text", "numbered-paragraph: no ListId"); + if (m_ListId.isEmpty()) { + return; + } + } + m_xNumRules = rTextListsHelper.EnsureNumberedParagraph( i_rImport, + m_ListId, m_Level, StyleName); + + SAL_WARN_IF(!m_xNumRules.is(), "xmloff.text", "numbered-paragraph: no NumRules"); + + i_rImport.GetTextImport()->GetTextListHelper().PushListContext( this ); +} + +void XMLNumberedParaContext::endFastElement(sal_Int32 ) +{ + if (!m_ListId.isEmpty()) { + GetImport().GetTextImport()->PopListContext(); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLNumberedParaContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + switch (nElement) + { + case XML_ELEMENT(TEXT, XML_H): + case XML_ELEMENT(LO_EXT, XML_H): + case XML_ELEMENT(TEXT, XML_P): + case XML_ELEMENT(LO_EXT, XML_P): + return new XMLParaContext( GetImport(), nElement, xAttrList ); + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtparai.hxx b/xmloff/source/text/txtparai.hxx new file mode 100644 index 000000000..66c64181c --- /dev/null +++ b/xmloff/source/text/txtparai.hxx @@ -0,0 +1,145 @@ +/* -*- 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 +#include +#include + +class XMLHints_Impl; +namespace com::sun::star { + namespace text { class XTextRange; } + namespace xml::sax { class XAttributeList; } +} + +#define CONV_FROM_STAR_BATS 1 +#define CONV_FROM_STAR_MATH 2 +#define CONV_STAR_FONT_FLAGS_VALID 4 + +class XMLParaContext : public SvXMLImportContext +{ + css::uno::Reference < css::text::XTextRange > xStart; + OUString sStyleName; + OUString m_sXmlId; + OUString m_sAbout; + OUString m_sProperty; + OUString m_sContent; + OUString m_sDatatype; + bool m_bHaveAbout; + sal_Int8 nOutlineLevel; + std::unique_ptr m_xHints; + // Lost outline numbering in master document (#i73509#) + bool mbOutlineLevelAttrFound; + bool mbOutlineContentVisible; + bool bIgnoreLeadingSpace; + bool bHeading; + bool bIsListHeader; + bool bIsRestart; + sal_Int16 nStartValue; + sal_uInt8 nStarFontsConvFlags; + +public: + + + XMLParaContext( SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL characters( const OUString& rChars ) override; + +}; + +class XMLNumberedParaContext : public SvXMLImportContext +{ + /// text:list-level MINUS 1 + sal_Int16 m_Level; + /// text:start-value + sal_Int16 m_StartValue; + /// text:list-id + OUString m_ListId; + /// text:style-name + css::uno::Reference< css::container::XIndexReplace > m_xNumRules; + +public: + + + XMLNumberedParaContext( SvXMLImport& i_rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & i_xAttrList ); + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + sal_Int16 GetLevel() const { return m_Level; } + const css::uno::Reference< css::container::XIndexReplace >& GetNumRules() const + { return m_xNumRules; } + const OUString& GetListId() const { return m_ListId; } + sal_Int16 GetStartValue() const { return m_StartValue; } + +}; + +class XMLHints_Impl; +class XMLStyleHint_Impl; + +class XMLImpSpanContext_Impl : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + XMLStyleHint_Impl *pHint; + + bool& rIgnoreLeadingSpace; + + sal_uInt8 nStarFontsConvFlags; + +public: + + + XMLImpSpanContext_Impl( + SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace, + sal_uInt8 nSFConvFlags + ); + + static css::uno::Reference< css::xml::sax::XFastContextHandler > CreateSpanContext( + SvXMLImport& rImport, + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList, + XMLHints_Impl& rHints, + bool& rIgnLeadSpace, + sal_uInt8 nStarFontsConvFlags = 0 + ); + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtparaimphint.hxx b/xmloff/source/text/txtparaimphint.hxx new file mode 100644 index 000000000..f60b87be5 --- /dev/null +++ b/xmloff/source/text/txtparaimphint.hxx @@ -0,0 +1,240 @@ +/* -*- 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 +#include "XMLTextFrameContext.hxx" +#include "XMLTextFrameHyperlinkContext.hxx" +#include + +enum class XMLHintType +{ + XML_HINT_STYLE = 1, + XML_HINT_REFERENCE = 2, + XML_HINT_HYPERLINK = 3, + // There is no 4 defined here + XML_HINT_INDEX_MARK = 5, + XML_HINT_TEXT_FRAME = 6, + // Core impl. of the unification of drawing objects and Writer fly frames (#i26791#) + XML_HINT_DRAW = 7 +}; + +class XMLHint_Impl +{ + css::uno::Reference < css::text::XTextRange > xStart; + css::uno::Reference < css::text::XTextRange > xEnd; + + XMLHintType nType; + +public: + + XMLHint_Impl( XMLHintType nTyp, + const css::uno::Reference < css::text::XTextRange > & rS, + const css::uno::Reference < css::text::XTextRange > & rE ) : + xStart( rS ), + xEnd( rE ), + nType( nTyp ) + { + } + + virtual ~XMLHint_Impl() {} + + const css::uno::Reference < css::text::XTextRange > & GetStart() const { return xStart; } + const css::uno::Reference < css::text::XTextRange > & GetEnd() const { return xEnd; } + void SetEnd( const css::uno::Reference < css::text::XTextRange > & rPos ) { xEnd = rPos; } + + // We don't use virtual methods to differ between the sub classes, + // because this seems to be too expensive if compared to inline methods. + XMLHintType GetType() const { return nType; } + bool IsReference() const { return XMLHintType::XML_HINT_REFERENCE==nType; } +}; + +class XMLStyleHint_Impl : public XMLHint_Impl +{ + OUString sStyleName; + +public: + + XMLStyleHint_Impl( const OUString& rStyleName, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_STYLE, rPos, rPos ), + sStyleName( rStyleName ) + { + } + + const OUString& GetStyleName() const { return sStyleName; } +}; + +class XMLReferenceHint_Impl : public XMLHint_Impl +{ + OUString sRefName; + +public: + + XMLReferenceHint_Impl( const OUString& rRefName, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_REFERENCE, rPos, rPos ), + sRefName( rRefName ) + { + } + + const OUString& GetRefName() const { return sRefName; } +}; + +class XMLHyperlinkHint_Impl : public XMLHint_Impl +{ + OUString sHRef; + OUString sName; + OUString sTargetFrameName; + OUString sStyleName; + OUString sVisitedStyleName; + rtl::Reference mxEvents; + +public: + + XMLHyperlinkHint_Impl( const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_HYPERLINK, rPos, rPos ) + { + } + + void SetHRef( const OUString& s ) { sHRef = s; } + const OUString& GetHRef() const { return sHRef; } + void SetName( const OUString& s ) { sName = s; } + const OUString& GetName() const { return sName; } + void SetTargetFrameName( const OUString& s ) { sTargetFrameName = s; } + const OUString& GetTargetFrameName() const { return sTargetFrameName; } + void SetStyleName( const OUString& s ) { sStyleName = s; } + const OUString& GetStyleName() const { return sStyleName; } + void SetVisitedStyleName( const OUString& s ) { sVisitedStyleName = s; } + const OUString& GetVisitedStyleName() const { return sVisitedStyleName; } + XMLEventsImportContext* GetEventsContext() const + { + return mxEvents.get(); + } + void SetEventsContext( XMLEventsImportContext* pCtxt ) + { + mxEvents.set(pCtxt); + } +}; + +class XMLIndexMarkHint_Impl : public XMLHint_Impl +{ + const css::uno::Reference xIndexMarkPropSet; + + const OUString sID; + +public: + + XMLIndexMarkHint_Impl( const css::uno::Reference < css::beans::XPropertySet > & rPropSet, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_INDEX_MARK, rPos, rPos ), + xIndexMarkPropSet( rPropSet ), + sID() + { + } + + XMLIndexMarkHint_Impl( const css::uno::Reference < css::beans::XPropertySet > & rPropSet, + const css::uno::Reference < css::text::XTextRange > & rPos, + const OUString& sIDString) : + XMLHint_Impl( XMLHintType::XML_HINT_INDEX_MARK, rPos, rPos ), + xIndexMarkPropSet( rPropSet ), + sID(sIDString) + { + } + + const css::uno::Reference & GetMark() const + { return xIndexMarkPropSet; } + const OUString& GetID() const { return sID; } +}; + +class XMLTextFrameHint_Impl : public XMLHint_Impl +{ + // OD 2004-04-20 #i26791# + SvXMLImportContextRef xContext; + +public: + + XMLTextFrameHint_Impl( SvXMLImportContext* pContext, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_TEXT_FRAME, rPos, rPos ), + xContext( pContext ) + { + } + + css::uno::Reference < css::text::XTextContent > GetTextContent() const + { + css::uno::Reference < css::text::XTextContent > xTxt; + SvXMLImportContext *pContext = xContext.get(); + if (XMLTextFrameContext *pFrameContext = dynamic_cast(pContext)) + xTxt = pFrameContext->GetTextContent(); + else if (XMLTextFrameHyperlinkContext *pLinkContext = dynamic_cast(pContext)) + xTxt = pLinkContext->GetTextContent(); + + return xTxt; + } + + // Frame "to character": anchor moves from first to last char after saving (#i33242#) + css::uno::Reference < css::drawing::XShape > GetShape() const + { + css::uno::Reference < css::drawing::XShape > xShape; + SvXMLImportContext *pContext = xContext.get(); + if (XMLTextFrameContext *pFrameContext = dynamic_cast(pContext)) + xShape = pFrameContext->GetShape(); + else if(XMLTextFrameHyperlinkContext *pLinkContext = dynamic_cast(pContext)) + xShape = pLinkContext->GetShape(); + + return xShape; + } + + bool IsBoundAtChar() const + { + bool bRet = false; + SvXMLImportContext *pContext = xContext.get(); + if (XMLTextFrameContext *pFrameContext = dynamic_cast(pContext)) + bRet = css::text::TextContentAnchorType_AT_CHARACTER == + pFrameContext->GetAnchorType(); + else if (XMLTextFrameHyperlinkContext *pLinkContext = dynamic_cast(pContext)) + bRet = css::text::TextContentAnchorType_AT_CHARACTER == + pLinkContext->GetAnchorType(); + return bRet; + } +}; + +// Core impl. of the unification of drawing objects and Writer fly frames (#i26791#) +class XMLDrawHint_Impl : public XMLHint_Impl +{ + SvXMLImportContextRef xContext; + +public: + + XMLDrawHint_Impl( SvXMLShapeContext* pContext, + const css::uno::Reference < css::text::XTextRange > & rPos ) : + XMLHint_Impl( XMLHintType::XML_HINT_DRAW, rPos, rPos ), + xContext( pContext ) + { + } + + // Frame "to character": anchor moves from first to last char after saving (#i33242#) + css::uno::Reference < css::drawing::XShape > const & GetShape() const + { + return static_cast(xContext.get())->getShape(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtprhdl.cxx b/xmloff/source/text/txtprhdl.cxx new file mode 100644 index 000000000..22fbe4174 --- /dev/null +++ b/xmloff/source/text/txtprhdl.cxx @@ -0,0 +1,1468 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "XMLAnchorTypePropHdl.hxx" +#include +#include +#include +#include +#include +#include "txtprhdl.hxx" +#include +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::text; +using namespace ::xmloff::token; +using namespace ::com::sun::star::drawing; + +SvXMLEnumMapEntry const pXML_HoriPos_Enum[] = +{ + { XML_FROM_LEFT, HoriOrientation::NONE }, + { XML_FROM_INSIDE, HoriOrientation::NONE }, // import only + { XML_LEFT, HoriOrientation::LEFT }, + { XML_INSIDE, HoriOrientation::LEFT }, // import only + { XML_CENTER, HoriOrientation::CENTER }, + { XML_RIGHT, HoriOrientation::RIGHT }, + { XML_OUTSIDE, HoriOrientation::RIGHT }, // import only + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_HoriPosMirrored_Enum[] = +{ + { XML_FROM_INSIDE, HoriOrientation::NONE }, + { XML_INSIDE, HoriOrientation::LEFT }, + { XML_CENTER, HoriOrientation::CENTER }, + { XML_OUTSIDE, HoriOrientation::RIGHT }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_HoriRel_Enum[] = +{ + { XML_PARAGRAPH, RelOrientation::FRAME }, + { XML_PARAGRAPH_CONTENT, RelOrientation::PRINT_AREA }, + { XML_PAGE, RelOrientation::PAGE_FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PAGE_PRINT_AREA }, + { XML_PARAGRAPH_START_MARGIN, RelOrientation::FRAME_LEFT }, + { XML_PARAGRAPH_END_MARGIN, RelOrientation::FRAME_RIGHT }, + { XML_PAGE_START_MARGIN, RelOrientation::PAGE_LEFT }, + { XML_PAGE_END_MARGIN, RelOrientation::PAGE_RIGHT }, + { XML_CHAR, RelOrientation::CHAR }, + { XML_FRAME, RelOrientation::FRAME }, // import only + { XML_FRAME_CONTENT, RelOrientation::PRINT_AREA }, // import only + { XML_FRAME_START_MARGIN, RelOrientation::FRAME_LEFT }, // import only + { XML_FRAME_END_MARGIN, RelOrientation::FRAME_RIGHT }, // import only + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_HoriRelFrame_Enum[] = +{ + { XML_FRAME, RelOrientation::FRAME }, + { XML_FRAME_CONTENT, RelOrientation::PRINT_AREA }, + { XML_PAGE, RelOrientation::PAGE_FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PAGE_PRINT_AREA }, + { XML_FRAME_START_MARGIN, RelOrientation::FRAME_LEFT }, + { XML_FRAME_END_MARGIN, RelOrientation::FRAME_RIGHT }, + { XML_PAGE_START_MARGIN, RelOrientation::PAGE_LEFT }, + { XML_PAGE_END_MARGIN, RelOrientation::PAGE_RIGHT }, + { XML_CHAR, RelOrientation::CHAR }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_HoriMirror_Enum[] = +{ + { XML_FROM_LEFT, false }, + { XML_FROM_INSIDE, true }, + { XML_LEFT, false }, + { XML_INSIDE, true }, + { XML_CENTER, false }, + { XML_RIGHT, false }, + { XML_OUTSIDE, true }, + { XML_TOKEN_INVALID, false } +}; + +SvXMLEnumMapEntry const pXML_VertPosAtChar_Enum[] = +{ + { XML_FROM_TOP, VertOrientation::NONE }, + { XML_TOP, VertOrientation::TOP }, + { XML_TOP, VertOrientation::CHAR_TOP }, // export only + { XML_TOP, VertOrientation::LINE_TOP }, // export only + { XML_MIDDLE, VertOrientation::CENTER }, + { XML_MIDDLE, VertOrientation::CHAR_CENTER }, // export only + { XML_MIDDLE, VertOrientation::LINE_CENTER }, // export only + { XML_BOTTOM, VertOrientation::BOTTOM }, + { XML_BELOW, VertOrientation::CHAR_BOTTOM }, // export only + { XML_BOTTOM, VertOrientation::LINE_BOTTOM }, // export only + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_VertRel_Enum[] = +{ + { XML_PARAGRAPH, RelOrientation::FRAME }, + { XML_PARAGRAPH_CONTENT, RelOrientation::PRINT_AREA }, + { XML_CHAR, RelOrientation::CHAR }, + // DVO, OD 17.09.2003 #i18732# - allow vertical alignment at page + { XML_PAGE, RelOrientation::PAGE_FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PAGE_PRINT_AREA }, + { XML_PAGE_CONTENT_TOP, RelOrientation::PAGE_PRINT_AREA_TOP }, + { XML_PAGE_CONTENT_BOTTOM, RelOrientation::PAGE_PRINT_AREA_BOTTOM }, + { XML_FRAME, RelOrientation::FRAME }, // import only + { XML_FRAME_CONTENT, RelOrientation::PRINT_AREA }, // import only + // OD 13.11.2003 #i22341# - new vertical alignment at top of line + { XML_LINE, RelOrientation::TEXT_LINE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_VertRelPage_Enum[] = +{ + { XML_PAGE, RelOrientation::FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PRINT_AREA }, + { XML_PAGE, RelOrientation::PAGE_FRAME }, + { XML_PAGE_CONTENT, RelOrientation::PAGE_PRINT_AREA }, + { XML_PAGE_CONTENT_TOP, RelOrientation::PAGE_PRINT_AREA_TOP }, + { XML_PAGE_CONTENT_BOTTOM, RelOrientation::PAGE_PRINT_AREA_BOTTOM }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_VertRelFrame_Enum[] = +{ + { XML_FRAME, RelOrientation::FRAME }, + { XML_FRAME_CONTENT, RelOrientation::PRINT_AREA }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_VertRelAsChar_Enum[] = +{ + { XML_BASELINE, VertOrientation::TOP }, + { XML_BASELINE, VertOrientation::CENTER }, // export only + { XML_BASELINE, VertOrientation::BOTTOM }, // export only + { XML_TEXT, VertOrientation::CHAR_TOP }, + { XML_TEXT, VertOrientation::CHAR_CENTER }, // export only + { XML_TEXT, VertOrientation::CHAR_BOTTOM }, // export only + { XML_LINE, VertOrientation::LINE_TOP }, + { XML_LINE, VertOrientation::LINE_CENTER }, // export only + { XML_LINE, VertOrientation::LINE_BOTTOM }, // export only + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_RubyAdjust_Enum[] = +{ + { XML_LEFT, RubyAdjust_LEFT }, + { XML_CENTER, RubyAdjust_CENTER }, + { XML_RIGHT, RubyAdjust_RIGHT }, + { XML_DISTRIBUTE_LETTER, RubyAdjust_BLOCK }, + { XML_DISTRIBUTE_SPACE, RubyAdjust_INDENT_BLOCK }, + { XML_TOKEN_INVALID, RubyAdjust(0) } +}; + +SvXMLEnumMapEntry const pXML_RubyPosition_Enum[] = +{ + { XML_ABOVE, RubyPosition::ABOVE}, + { XML_BELOW, RubyPosition::BELOW}, + { XML_INTER_CHARACTER, RubyPosition::INTER_CHARACTER}, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_FontRelief_Enum[] = +{ + { XML_NONE, FontRelief::NONE }, + { XML_ENGRAVED, FontRelief::ENGRAVED }, + { XML_EMBOSSED, FontRelief::EMBOSSED }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_ParaVerticalAlign_Enum[] = +{ + { XML_TOP, ParagraphVertAlign::TOP }, + { XML_MIDDLE, ParagraphVertAlign::CENTER }, + { XML_BOTTOM, ParagraphVertAlign::BOTTOM }, + { XML_BASELINE, ParagraphVertAlign::BASELINE }, + { XML_AUTO, ParagraphVertAlign::AUTOMATIC }, + { XML_TOKEN_INVALID, 0 } +}; + +// OD 2004-05-05 #i28701# +SvXMLEnumMapEntry const pXML_WrapInfluenceOnPosition_Enum[] = +{ + // Tokens have been renamed and has been added (#i35017#) + { XML_ONCE_SUCCESSIVE, WrapInfluenceOnPosition::ONCE_SUCCESSIVE }, + { XML_ONCE_CONCURRENT, WrapInfluenceOnPosition::ONCE_CONCURRENT }, + { XML_ITERATIVE, WrapInfluenceOnPosition::ITERATIVE }, + { XML_TOKEN_INVALID, 0 } +}; + +SvXMLEnumMapEntry const pXML_VerticalAlign_Enum[] = +{ + { XML_TOP, drawing::TextVerticalAdjust_TOP }, + { XML_MIDDLE, drawing::TextVerticalAdjust_CENTER }, + { XML_BOTTOM, drawing::TextVerticalAdjust_BOTTOM }, + { XML_JUSTIFY, drawing::TextVerticalAdjust_BLOCK }, + { XML_TOKEN_INVALID, drawing::TextVerticalAdjust(0) } +}; + +SvXMLEnumMapEntry const pXML_ThemeColor_Enum[] = +{ + { XML_DK1, 0 }, + { XML_LT1, 1 }, + { XML_DK2, 2 }, + { XML_LT2, 3 }, + { XML_ACCENT1, 4 }, + { XML_ACCENT2, 5 }, + { XML_ACCENT3, 6 }, + { XML_ACCENT4, 7 }, + { XML_ACCENT5, 8 }, + { XML_ACCENT6, 9 }, + { XML_HLINK, 10 }, + { XML_FOLHLINK, 11 }, + { XML_TOKEN_INVALID, 0 } +}; + +namespace { + +class XMLDropCapPropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool equals( + const css::uno::Any& r1, + const css::uno::Any& r2 ) const override; + + /// TabStops will be imported/exported as XML-Elements. So the Import/Export-work must be done at another place. + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLDropCapPropHdl_Impl::equals( + const Any& r1, + const Any& r2 ) const +{ + DropCapFormat aFormat1, aFormat2; + r1 >>= aFormat1; + r2 >>= aFormat2; + + return (aFormat1.Lines <=1 && aFormat2.Lines <=1) || + (aFormat1.Lines == aFormat2.Lines && + aFormat1.Count == aFormat2.Count && + aFormat1.Distance == aFormat2.Distance); +} + +bool XMLDropCapPropHdl_Impl::importXML( + const OUString&, + Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "drop caps are an element import property" ); + return false; +} + +bool XMLDropCapPropHdl_Impl::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "drop caps are an element export property" ); + return false; +} + +namespace { + +class XMLOpaquePropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLOpaquePropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + if( IsXMLToken( rStrImpValue, XML_FOREGROUND ) ) + bVal = true; + else if( !IsXMLToken( rStrImpValue, XML_BACKGROUND ) ) + bRet = false; + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLOpaquePropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess(rValue) ) + rStrExpValue = GetXMLToken( XML_FOREGROUND ); + else + rStrExpValue = GetXMLToken( XML_BACKGROUND ); + + return true; +} + +namespace { + +class XMLContourModePropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLContourModePropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + if( IsXMLToken( rStrImpValue, XML_OUTSIDE ) ) + bVal = true; + else if( ! IsXMLToken( rStrImpValue, XML_FULL ) ) + bRet = false; + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLContourModePropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess(rValue) ) + rStrExpValue = GetXMLToken( XML_OUTSIDE ); + else + rStrExpValue = GetXMLToken( XML_FULL ); + + return true; +} + +namespace { + +class XMLParagraphOnlyPropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLParagraphOnlyPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + + if( ! IsXMLToken( rStrImpValue, XML_NO_LIMIT ) ) + { + sal_Int32 nValue = 0; + bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + bVal = 1 == nValue; + } + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLParagraphOnlyPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess(rValue) ) + rStrExpValue = GetXMLToken( XML_1 ); + else + rStrExpValue = GetXMLToken( XML_NO_LIMIT ); + + return true; +} + +SvXMLEnumMapEntry const pXML_Wrap_Enum[] = +{ + { XML_NONE, WrapTextMode_NONE }, + { XML_RUN_THROUGH, WrapTextMode_THROUGH }, + { XML_PARALLEL, WrapTextMode_PARALLEL }, + { XML_DYNAMIC, WrapTextMode_DYNAMIC }, + { XML_LEFT, WrapTextMode_LEFT }, + { XML_RIGHT, WrapTextMode_RIGHT }, + { XML_TOKEN_INVALID, WrapTextMode(0) } +}; + +namespace { + +class XMLWrapPropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLWrapPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + WrapTextMode nWrap; + bool bRet = SvXMLUnitConverter::convertEnum( nWrap, rStrImpValue, + pXML_Wrap_Enum ); + + if( bRet ) + rValue <<= nWrap; + + return bRet; +} + +bool XMLWrapPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut; + WrapTextMode eVal; + + rValue >>= eVal; + + bool bRet = SvXMLUnitConverter::convertEnum( aOut, eVal, pXML_Wrap_Enum, XML_NONE ); + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +namespace { + +class XMLFrameProtectPropHdl_Impl : public XMLPropertyHandler +{ + const OUString sVal; +public: + explicit XMLFrameProtectPropHdl_Impl( enum XMLTokenEnum eVal ) : + sVal( GetXMLToken(eVal) ) {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLFrameProtectPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + if( ! IsXMLToken( rStrImpValue, XML_NONE ) ) + { + bRet = false; + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + std::u16string_view aToken; + while( aTokenEnum.getNextToken( aToken ) ) + { + bRet = true; + if( aToken == sVal ) + { + bVal = true; + break; + } + } + } + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLFrameProtectPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess(rValue) ) + { + if( rStrExpValue.isEmpty() || + IsXMLToken( rStrExpValue, XML_NONE ) ) + { + rStrExpValue = sVal; + } + else + { + rStrExpValue += " " + sVal; + } + } + else if( rStrExpValue.isEmpty() ) + { + rStrExpValue = GetXMLToken( XML_NONE ); + } + + return true; +} + +SvXMLEnumMapEntry const pXML_Anchor_Enum[] = +{ + { XML_CHAR, TextContentAnchorType_AT_CHARACTER }, + { XML_PAGE, TextContentAnchorType_AT_PAGE }, + { XML_FRAME, TextContentAnchorType_AT_FRAME }, + { XML_PARAGRAPH, TextContentAnchorType_AT_PARAGRAPH }, + { XML_AS_CHAR, TextContentAnchorType_AS_CHARACTER }, + { XML_TOKEN_INVALID, TextContentAnchorType(0) } +}; + +bool XMLAnchorTypePropHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + TextContentAnchorType nAnchor; + bool bRet = SvXMLUnitConverter::convertEnum( nAnchor, rStrImpValue, + pXML_Anchor_Enum ); + + if( bRet ) + rValue <<= nAnchor; + + return bRet; +} + +bool XMLAnchorTypePropHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut; + TextContentAnchorType eVal; + + rValue >>= eVal; + + bool bRet = SvXMLUnitConverter::convertEnum( aOut, eVal, pXML_Anchor_Enum, XML_PARAGRAPH ); + + rStrExpValue = aOut.makeStringAndClear(); + + return bRet; +} + +XMLAnchorTypePropHdl::~XMLAnchorTypePropHdl() +{ +} + +bool XMLAnchorTypePropHdl::convert( std::string_view rStrImpValue, + TextContentAnchorType& rType ) +{ + TextContentAnchorType nAnchor; + bool bRet = SvXMLUnitConverter::convertEnum( nAnchor, rStrImpValue, + pXML_Anchor_Enum ); + if( bRet ) + rType = nAnchor; + return bRet; +} + +XMLTextColumnsPropertyHandler::~XMLTextColumnsPropertyHandler () +{ +} + +bool XMLTextColumnsPropertyHandler::equals( + const Any& r1, + const Any& r2 ) const +{ + Reference < XTextColumns > xColumns1; + r1 >>= xColumns1; + + Reference < XTextColumns > xColumns2; + r2 >>= xColumns2; + + if (!xColumns1 || !xColumns2) + return (!xColumns1 && !xColumns2); + + if( xColumns1->getColumnCount() != xColumns2->getColumnCount() || + xColumns1->getReferenceValue() != xColumns2->getReferenceValue() ) + return false; + + const Sequence < TextColumn > aColumns1 = xColumns1->getColumns(); + const Sequence < TextColumn > aColumns2 = xColumns2->getColumns(); + + return std::equal(aColumns1.begin(), aColumns1.end(), aColumns2.begin(), aColumns2.end(), + [](const TextColumn& a, const TextColumn& b) { + return a.Width == b.Width + && a.LeftMargin == b.LeftMargin + && a.RightMargin == b.RightMargin; + }); +} + +bool XMLTextColumnsPropertyHandler::importXML( + const OUString&, + Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "columns are an element import property" ); + return false; +} + +bool XMLTextColumnsPropertyHandler::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "columns are an element export property" ); + return false; +} + +namespace { + +class XMLHoriMirrorPropHdl_Impl : public XMLPropertyHandler +{ +public: + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLHoriMirrorPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool nHoriMirror; + bool bRet = SvXMLUnitConverter::convertEnum( nHoriMirror, rStrImpValue, + pXML_HoriMirror_Enum ); + + if( bRet ) + { + rValue <<= nHoriMirror; + } + + return bRet; +} + +bool XMLHoriMirrorPropHdl_Impl::exportXML( + OUString&, + const Any&, + const SvXMLUnitConverter& ) const +{ + SAL_WARN( "xmloff", "HorMirror property shouldn't be exported" ); + + return false; +} + +namespace { + +class XMLGrfMirrorPropHdl_Impl : public XMLPropertyHandler +{ + const OUString sVal; + bool bHori; + +public: + XMLGrfMirrorPropHdl_Impl( enum XMLTokenEnum eVal, bool bH ) : + sVal( GetXMLToken( eVal ) ), + bHori( bH ) {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLGrfMirrorPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + bool bVal = false; + if( ! IsXMLToken( rStrImpValue, XML_NONE ) ) + { + bRet = false; + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + std::u16string_view aToken; + while( aTokenEnum.getNextToken( aToken ) ) + { + bRet = true; + if( aToken == sVal || + (bHori && IsXMLToken( aToken, XML_HORIZONTAL ) ) ) + { + bVal = true; + break; + } + } + } + + if( bRet ) + rValue <<= bVal; + + return bRet; +} + +bool XMLGrfMirrorPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( *o3tl::doAccess(rValue) ) + { + if( rStrExpValue.isEmpty() || + IsXMLToken( rStrExpValue, XML_NONE ) ) + { + rStrExpValue = sVal; + } + else if( bHori && + /* XML_HORIZONTAL_ON_LEFT_PAGES and XML_HORIZONTAL_ON_RIGHT_PAGES + are replaced by XML_HORIZONTAL_ON_EVEN and XML_HORIZONTAL_ON_ODD. + (#i49139#) + */ + ( IsXMLToken( rStrExpValue, XML_HORIZONTAL_ON_EVEN ) || + IsXMLToken( rStrExpValue, XML_HORIZONTAL_ON_ODD ) )) + { + rStrExpValue = GetXMLToken( XML_HORIZONTAL ); + } + else + { + rStrExpValue += " " + sVal; + } + } + else if( rStrExpValue.isEmpty() ) + { + rStrExpValue = GetXMLToken( XML_NONE ); + } + + return true; +} + +SvXMLEnumMapEntry const pXML_Emphasize_Enum[] = +{ + { XML_NONE, FontEmphasis::NONE }, + { XML_DOT, FontEmphasis::DOT_ABOVE }, + { XML_CIRCLE, FontEmphasis::CIRCLE_ABOVE }, + { XML_DISC, FontEmphasis::DISK_ABOVE }, + { XML_ACCENT, FontEmphasis::ACCENT_ABOVE }, + { XML_TOKEN_INVALID, 0 } +}; + +namespace { + +class XMLTextEmphasizePropHdl_Impl : public XMLPropertyHandler +{ +public: + XMLTextEmphasizePropHdl_Impl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextEmphasizePropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = true; + sal_uInt16 nVal = FontEmphasis::NONE; + bool bBelow = false; + bool bHasPos = false, bHasType = false; + std::u16string_view aToken; + + SvXMLTokenEnumerator aTokenEnum( rStrImpValue ); + while( aTokenEnum.getNextToken( aToken ) ) + { + if( !bHasPos && IsXMLToken( aToken, XML_ABOVE ) ) + { + bBelow = false; + bHasPos = true; + } + else if( !bHasPos && IsXMLToken( aToken, XML_BELOW ) ) + { + bBelow = true; + bHasPos = true; + } + else if( !bHasType && + SvXMLUnitConverter::convertEnum( nVal, aToken, + pXML_Emphasize_Enum )) + { + bHasType = true; + } + else + { + bRet = false; + break; + } + } + + if( bRet ) + { + if( FontEmphasis::NONE != nVal && bBelow ) + nVal += 10; + rValue <<= static_cast(nVal); + } + + return bRet; +} + +bool XMLTextEmphasizePropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + OUStringBuffer aOut( 15 ); + bool bRet = true; + sal_uInt16 nType = sal_uInt16(); + if( rValue >>= nType ) + { + bool bBelow = false; + if( nType > 10 ) + { + bBelow = true; + nType -= 10; + } + bRet = SvXMLUnitConverter::convertEnum( aOut, nType, + pXML_Emphasize_Enum, + XML_DOT ); + if( bRet ) + { + if( nType != 0 ) + { + enum XMLTokenEnum ePos = bBelow ? XML_BELOW : XML_ABOVE; + aOut.append( ' ' ); + aOut.append( GetXMLToken(ePos) ); + } + rStrExpValue = aOut.makeStringAndClear(); + } + } + + return bRet; +} + +namespace { + +class XMLTextCombineCharPropHdl_Impl : public XMLPropertyHandler +{ +public: + XMLTextCombineCharPropHdl_Impl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextCombineCharPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + if( !rStrImpValue.isEmpty() ) + rValue <<= rStrImpValue.copy( 0, 1 ); + else + rValue <<= rStrImpValue; + + return true; +} + +bool XMLTextCombineCharPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + rValue >>= rStrExpValue; + + // #i114107# attribute of type "character": export only if length is 1 + return (1 == rStrExpValue.getLength()); +} + +namespace { + +class XMLTextRelWidthHeightPropHdl_Impl : public XMLPropertyHandler +{ +public: + XMLTextRelWidthHeightPropHdl_Impl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextRelWidthHeightPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue; + bool const bRet = ::sax::Converter::convertPercent( nValue, rStrImpValue ); + if( bRet ) + rValue <<= static_cast(nValue); + + return bRet; +} + +bool XMLTextRelWidthHeightPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + sal_Int16 nValue = sal_Int16(); + if( (rValue >>= nValue) && nValue > 0 ) + { + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + rStrExpValue = aOut.makeStringAndClear(); + + bRet = true; + } + + return bRet; +} + +namespace { + +class XMLTextSyncWidthHeightPropHdl_Impl : public XMLPropertyHandler +{ + const OUString sValue; + +public: + explicit XMLTextSyncWidthHeightPropHdl_Impl( enum XMLTokenEnum eValue ) : + sValue( GetXMLToken(eValue) ) {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextSyncWidthHeightPropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + rValue <<= (rStrImpValue == sValue); + + return true; +} + +bool XMLTextSyncWidthHeightPropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + bool bRet = false; + if( *o3tl::doAccess(rValue) ) + { + rStrExpValue = sValue; + bRet = true; + } + + return bRet; +} + +namespace { + +class XMLTextRotationAnglePropHdl_Impl : public XMLPropertyHandler +{ + +public: + XMLTextRotationAnglePropHdl_Impl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLTextRotationAnglePropHdl_Impl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue; + bool const bRet = ::sax::Converter::convertNumber( nValue, rStrImpValue ); + if( bRet ) + { + nValue = (nValue % 360 ); + if( nValue < 0 ) + nValue = 360 + nValue; + sal_Int16 nAngle; + if( nValue < 45 || nValue > 315 ) + nAngle = 0; + else if( nValue < 180 ) + nAngle = 900; + else /* if nValue <= 315 ) */ + nAngle = 2700; + rValue <<= nAngle; + } + + return bRet; +} + +bool XMLTextRotationAnglePropHdl_Impl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int16 nAngle = sal_Int16(); + bool bRet = ( rValue >>= nAngle ); + if( bRet ) + { + rStrExpValue = OUString::number( nAngle / 10 ); + } + OSL_ENSURE( bRet, "illegal rotation angle" ); + + return bRet; +} + +namespace { + +class XMLNumber8OneBasedHdl : public XMLPropertyHandler +{ + +public: + XMLNumber8OneBasedHdl() {} + + virtual bool importXML( + const OUString& rStrImpValue, + css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; + virtual bool exportXML( + OUString& rStrExpValue, + const css::uno::Any& rValue, + const SvXMLUnitConverter& ) const override; +}; + +} + +bool XMLNumber8OneBasedHdl::importXML( + const OUString& rStrImpValue, + Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int32 nValue = 0; + bool const bRet = ::sax::Converter::convertNumber(nValue, rStrImpValue); + if( bRet ) + rValue <<= static_cast( nValue - 1 ); + return bRet; +} + +bool XMLNumber8OneBasedHdl::exportXML( + OUString& rStrExpValue, + const Any& rValue, + const SvXMLUnitConverter& ) const +{ + sal_Int8 nValue = sal_Int8(); + bool bRet = ( rValue >>= nValue ); + if( bRet ) + { + rStrExpValue = OUString::number( nValue + 1 ); + } + return bRet; +} + +namespace { + +class XMLGraphicPropertyHandler : public XMLPropertyHandler +{ +public: + XMLGraphicPropertyHandler() {} + + virtual bool importXML(const OUString& , uno::Any& , const SvXMLUnitConverter& ) const override + { + SAL_WARN( "xmloff", "drop caps are an element import property" ); + return false; + } + + virtual bool exportXML(OUString& , const uno::Any& , const SvXMLUnitConverter& ) const override + { + SAL_WARN( "xmloff", "drop caps are an element import property" ); + return false; + } + + virtual bool equals(const css::uno::Any& rAny1, const css::uno::Any& rAny2) const override; +}; + +} + +bool XMLGraphicPropertyHandler::equals(const Any& rAny1, const Any& rAny2) const +{ + uno::Reference xGraphic1; + uno::Reference xGraphic2; + rAny1 >>= xGraphic1; + rAny2 >>= xGraphic2; + Graphic aGraphic1(xGraphic1); + Graphic aGraphic2(xGraphic2); + + return aGraphic1 == aGraphic2; +} + +static const XMLPropertyHandler *GetPropertyHandler + ( sal_Int32 nType ) +{ + const XMLPropertyHandler* pHdl = nullptr; + switch( nType ) + { + case XML_TYPE_TEXT_DROPCAP: + pHdl = new XMLDropCapPropHdl_Impl; + break; + case XML_TYPE_TEXT_WRAP: + pHdl = new XMLWrapPropHdl_Impl; + break; + case XML_TYPE_TEXT_PARAGRAPH_ONLY: + pHdl = new XMLParagraphOnlyPropHdl_Impl; + break; + case XML_TYPE_TEXT_WRAP_OUTSIDE: + pHdl = new XMLContourModePropHdl_Impl; + break; + case XML_TYPE_TEXT_OPAQUE: + pHdl = new XMLOpaquePropHdl_Impl; + break; + case XML_TYPE_TEXT_PROTECT_CONTENT: + pHdl = new XMLFrameProtectPropHdl_Impl( XML_CONTENT ); + break; + case XML_TYPE_TEXT_PROTECT_SIZE: + pHdl = new XMLFrameProtectPropHdl_Impl( XML_SIZE ); + break; + case XML_TYPE_TEXT_PROTECT_POSITION: + pHdl = new XMLFrameProtectPropHdl_Impl( XML_POSITION ); + break; + case XML_TYPE_TEXT_ANCHOR_TYPE: + pHdl = new XMLAnchorTypePropHdl; + break; + case XML_TYPE_TEXT_COLUMNS: + pHdl = new XMLTextColumnsPropertyHandler; + break; + case XML_TYPE_TEXT_HORIZONTAL_POS: + pHdl = new XMLConstantsPropertyHandler( pXML_HoriPos_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_HORIZONTAL_POS_MIRRORED: + pHdl = new XMLConstantsPropertyHandler( pXML_HoriPosMirrored_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_HORIZONTAL_REL: + pHdl = new XMLConstantsPropertyHandler( pXML_HoriRel_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_HORIZONTAL_REL_FRAME: + pHdl = new XMLConstantsPropertyHandler( pXML_HoriRelFrame_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_HORIZONTAL_MIRROR: + pHdl = new XMLHoriMirrorPropHdl_Impl; + break; + case XML_TYPE_TEXT_VERTICAL_POS_AT_CHAR: + pHdl = new XMLConstantsPropertyHandler( pXML_VertPosAtChar_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_VERTICAL_REL: + pHdl = new XMLConstantsPropertyHandler( pXML_VertRel_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_VERTICAL_REL_PAGE: + pHdl = new XMLConstantsPropertyHandler( pXML_VertRelPage_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_VERTICAL_REL_FRAME: + pHdl = new XMLConstantsPropertyHandler( pXML_VertRelFrame_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_VERTICAL_REL_AS_CHAR: + pHdl = new XMLConstantsPropertyHandler( pXML_VertRelAsChar_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_MIRROR_VERTICAL: + pHdl = new XMLGrfMirrorPropHdl_Impl( XML_VERTICAL, false ); + break; + case XML_TYPE_TEXT_MIRROR_HORIZONTAL_LEFT: + // XML_HORIZONTAL_ON_LEFT_PAGES is replaced by XML_HORIZONTAL_ON_EVEN. (#i49139#) + pHdl = new XMLGrfMirrorPropHdl_Impl( XML_HORIZONTAL_ON_EVEN, true ); + break; + case XML_TYPE_TEXT_MIRROR_HORIZONTAL_RIGHT: + // XML_HORIZONTAL_ON_RIGHT_PAGES is replaced by XML_HORIZONTAL_ON_ODD. (#i49139#) + pHdl = new XMLGrfMirrorPropHdl_Impl( XML_HORIZONTAL_ON_ODD, true ); + break; + case XML_TYPE_TEXT_CLIP: + pHdl = new XMLClipPropertyHandler( false ); + break; + case XML_TYPE_TEXT_CLIP11: + pHdl = new XMLClipPropertyHandler( true ); + break; + case XML_TYPE_TEXT_EMPHASIZE: + pHdl = new XMLTextEmphasizePropHdl_Impl; + break; + case XML_TYPE_TEXT_COMBINE: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_LINES ), + GetXMLToken( XML_NONE ) ); + break; + case XML_TYPE_TEXT_COMBINE_CHARACTERS: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_LETTERS ), + GetXMLToken( XML_NONE ) ); + break; + case XML_TYPE_TEXT_COMBINECHAR: + pHdl = new XMLTextCombineCharPropHdl_Impl; + break; + case XML_TYPE_TEXT_AUTOSPACE: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_IDEOGRAPH_ALPHA ), + GetXMLToken( XML_NONE ) ); + break; + case XML_TYPE_TEXT_PUNCTUATION_WRAP: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_HANGING ), + GetXMLToken( XML_SIMPLE ) ); + break; + case XML_TYPE_TEXT_LINE_BREAK: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_STRICT ), + GetXMLToken( XML_NORMAL ) ); + break; + case XML_TYPE_TEXT_REL_WIDTH_HEIGHT: + pHdl = new XMLTextRelWidthHeightPropHdl_Impl; + break; + case XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT: + pHdl = new XMLTextSyncWidthHeightPropHdl_Impl( XML_SCALE ); + break; + case XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT_MIN: + pHdl = new XMLTextSyncWidthHeightPropHdl_Impl( XML_SCALE_MIN ); + break; + case XML_TYPE_TEXT_RUBY_ADJUST: + pHdl = new XMLConstantsPropertyHandler( pXML_RubyAdjust_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_FONT_RELIEF: + pHdl = new XMLConstantsPropertyHandler( pXML_FontRelief_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_ROTATION_ANGLE: + pHdl = new XMLTextRotationAnglePropHdl_Impl; + break; + case XML_TYPE_TEXT_ROTATION_SCALE: + pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken( XML_FIXED ), + GetXMLToken( XML_LINE_HEIGHT ) ); + break; + case XML_TYPE_TEXT_VERTICAL_ALIGN: + pHdl = new XMLConstantsPropertyHandler( pXML_ParaVerticalAlign_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_RUBY_POSITION: + pHdl = new XMLConstantsPropertyHandler( pXML_RubyPosition_Enum, XML_TOKEN_INVALID ); + break; + case XML_TYPE_TEXT_RUBY_IS_ABOVE: + pHdl = new XMLNamedBoolPropertyHdl(::xmloff::token::XML_ABOVE, ::xmloff::token::XML_BELOW); + break; + // OD 2004-05-05 #i28701# + case XML_TYPE_WRAP_INFLUENCE_ON_POSITION: + pHdl = new XMLConstantsPropertyHandler( pXML_WrapInfluenceOnPosition_Enum, + XML_TOKEN_INVALID ); + break; + case XML_TYPE_BORDER_MODEL: + pHdl = new XMLNamedBoolPropertyHdl( xmloff::token::XML_COLLAPSING, + xmloff::token::XML_SEPARATING ); + break; + case XML_TYPE_TEXT_LINE_MODE: + pHdl = new XMLNamedBoolPropertyHdl( + ::xmloff::token::XML_SKIP_WHITE_SPACE, + ::xmloff::token::XML_CONTINUOUS); + break; + case XML_TYPE_TEXT_KEEP: + pHdl = new XMLNamedBoolPropertyHdl( + ::xmloff::token::XML_ALWAYS, + ::xmloff::token::XML_AUTO); + break; + case XML_TYPE_TEXT_NKEEP: + pHdl = new XMLNamedBoolPropertyHdl( + ::xmloff::token::XML_AUTO, + ::xmloff::token::XML_ALWAYS); + break; + case XML_TYPE_TEXT_NUMBER8_ONE_BASED: + pHdl = new XMLNumber8OneBasedHdl(); + break; + case XML_TYPE_VERTICAL_ALIGN: + pHdl = new XMLConstantsPropertyHandler( pXML_VerticalAlign_Enum, XML_TOKEN_INVALID ); + break; + + case XML_SW_TYPE_FILLSTYLE: + pHdl = new XMLEnumPropertyHdl( aXML_FillStyle_EnumMap); + break; + case XML_SW_TYPE_FILLBITMAPSIZE: + pHdl = new XMLFillBitmapSizePropertyHandler(); + break; + case XML_SW_TYPE_LOGICAL_SIZE: + pHdl = new XMLBitmapLogicalSizePropertyHandler(); + break; + case XML_SW_TYPE_BITMAP_REFPOINT: + pHdl = new XMLEnumPropertyHdl( aXML_RefPoint_EnumMap); + break; + case XML_SW_TYPE_BITMAP_MODE: + pHdl = new XMLEnumPropertyHdl( aXML_BitmapMode_EnumMap); + break; + case XML_SW_TYPE_BITMAPREPOFFSETX: + case XML_SW_TYPE_BITMAPREPOFFSETY: + pHdl = new XMLBitmapRepeatOffsetPropertyHandler(XML_SW_TYPE_BITMAPREPOFFSETX == nType); + break; + case XML_TYPE_GRAPHIC: + pHdl = new XMLGraphicPropertyHandler; + break; + case XML_TYPE_THEME_COLOR: + pHdl = new XMLConstantsPropertyHandler(pXML_ThemeColor_Enum, XML_TOKEN_INVALID); + break; + default: + { + OSL_ENSURE(false, "XMLPropertyHandler missing (!)"); + break; + } + } + + return pHdl; +} + +XMLTextPropertyHandlerFactory::XMLTextPropertyHandlerFactory() +{ +} + +const XMLPropertyHandler *XMLTextPropertyHandlerFactory::GetPropertyHandler( + sal_Int32 nType ) const +{ + const XMLPropertyHandler *pHdl = + XMLPropertyHandlerFactory::GetPropertyHandler( nType ); + + if( !pHdl ) + { + const XMLPropertyHandler *pNewHdl = ::GetPropertyHandler( nType ); + + if( pNewHdl ) + PutHdlCache( nType, pNewHdl ); + + pHdl = pNewHdl; + } + + return pHdl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtprhdl.hxx b/xmloff/source/text/txtprhdl.hxx new file mode 100644 index 000000000..632d4fe88 --- /dev/null +++ b/xmloff/source/text/txtprhdl.hxx @@ -0,0 +1,31 @@ +/* -*- 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 + +class XMLTextPropertyHandlerFactory : public XMLPropertyHandlerFactory +{ +public: + XMLTextPropertyHandlerFactory(); + + virtual const XMLPropertyHandler* GetPropertyHandler(sal_Int32 nType) const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtprmap.cxx b/xmloff/source/text/txtprmap.cxx new file mode 100644 index 000000000..66bda55a8 --- /dev/null +++ b/xmloff/source/text/txtprmap.cxx @@ -0,0 +1,1154 @@ +/* -*- 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 +#include +#include +#include +#include +#include "txtprhdl.hxx" +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +#define M_E_( a, p, l, t, c ) \ + { a, XML_NAMESPACE_##p, XML_##l, t, c, SvtSaveOptions::ODFSVER_010, false } + +#define M_EV_( a, p, l, t, c, v ) \ + { a, XML_NAMESPACE_##p, XML_##l, t, c, v, false } + +#define M_ED_( a, p, l, t, c ) \ + { a, XML_NAMESPACE_##p, XML_##l, (t) | MID_FLAG_DEFAULT_ITEM_EXPORT, c, SvtSaveOptions::ODFSVER_010, false } + +// text properties +#define MT_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_TEXT), c ) +#define MT_ED( a, p, l, t, c ) \ + M_ED_( a, p, l, (t|XML_TYPE_PROP_TEXT), c ) + +// paragraph properties +#define MP_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_PARAGRAPH), c ) +#define MP_ED( a, p, l, t, c ) \ + M_ED_( a, p, l, (t|XML_TYPE_PROP_PARAGRAPH), c ) + +// graphic properties +#define MG_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_GRAPHIC), c ) +#define MG_ED( a, p, l, t, c ) \ + M_ED_( a, p, l, (t|XML_TYPE_PROP_GRAPHIC), c ) +#define MG_EV( a, p, l, t, c, v ) \ + M_EV_( a, p, l, (t|XML_TYPE_PROP_GRAPHIC), c, v ) + +// section properties +#define MS_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_SECTION), c ) + +// ruby properties +#define MR_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_RUBY), c ) +#define MR_EV( a, p, l, t, c, v ) \ + M_EV_( a, p, l, (t|XML_TYPE_PROP_RUBY), c, v ) + +// cell properties +#define MC_E( a, p, l, t, c ) \ + M_E_( a, p, l, (t|XML_TYPE_PROP_TABLE_CELL), c ) + +#define MAP_ODF13(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_013, false } + +// extensions import/export +#define MAP_EXT(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false } +// extensions import only +#define MAP_EXT_I(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, true } + +#define M_END() { nullptr, 0, XML_TOKEN_INVALID, 0, 0, SvtSaveOptions::ODFSVER_010, false } + +#define MAP_(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_010, false } +#define GMAP(name,prefix,token,type,context) MAP_(name,prefix,token,static_cast(type|XML_TYPE_PROP_GRAPHIC),context) + +XMLPropertyMapEntry const aXMLParaPropMap[] = +{ + // RES_UNKNOWNATR_CONTAINER + MP_E( "ParaUserDefinedAttributes", TEXT, XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + + // fill attributes for paragraph backgrounds + // #i125045# moved to the front to be able to exclude these in lcl_txtprmap_getMap + // for TextPropMap::SHAPE_PARA to not have these double for Shapes (which already have these) + GMAP( "FillStyle", XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, 0 ), + GMAP( "FillColor", XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( "FillColor2", XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( "FillGradientName", XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLGRADIENTNAME ), + GMAP( "FillGradientStepCount", XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0 ), + GMAP( "FillHatchName", XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLHATCHNAME ), + GMAP( "FillBackground", XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + GMAP( "FillBitmapName", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLBITMAPNAME ), + GMAP( "FillTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( "FillTransparenceGradientName", XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLTRANSNAME ), + GMAP( "FillBitmapSizeX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapSizeY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapMode", XML_NAMESPACE_STYLE,XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapPositionOffsetX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + GMAP( "FillBitmapPositionOffsetY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + GMAP( "FillBitmapRectanglePoint", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, 0 ), + GMAP( "FillBitmapOffsetX", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_X ), + GMAP( "FillBitmapOffsetY", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_Y ), + + // RES_LR_SPACE + // !!! DO NOT REORDER THE MARGINS !!! + MP_E( "ParaLeftMargin", FO, MARGIN, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARAMARGINALL ), + MP_E( "ParaLeftMarginRelative", FO, MARGIN, XML_TYPE_PERCENT16, CTF_PARAMARGINALL_REL ), + MP_E( "ParaLeftMargin", FO, MARGIN_LEFT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARALEFTMARGIN ), + MP_E( "ParaLeftMarginRelative", FO, MARGIN_LEFT, XML_TYPE_PERCENT16, CTF_PARALEFTMARGIN_REL ), + MP_E( "ParaRightMargin", FO, MARGIN_RIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARARIGHTMARGIN ), + MP_E( "ParaRightMarginRelative", FO, MARGIN_RIGHT, XML_TYPE_PERCENT16, CTF_PARARIGHTMARGIN_REL ), + // RES_UL_SPACE + MP_E( "ParaTopMargin", FO, MARGIN_TOP, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARATOPMARGIN ), + MP_E( "ParaTopMarginRelative", FO, MARGIN_TOP, XML_TYPE_PERCENT16, CTF_PARATOPMARGIN_REL ), + MP_E( "ParaBottomMargin", FO, MARGIN_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARABOTTOMMARGIN ), + MP_E( "ParaBottomMarginRelative",FO, MARGIN_BOTTOM, XML_TYPE_PERCENT16, CTF_PARABOTTOMMARGIN_REL ), + MAP_ODF13( "ParaContextMargin", XML_NAMESPACE_STYLE, XML_CONTEXTUAL_SPACING, XML_TYPE_BOOL|XML_TYPE_PROP_PARAGRAPH, 0 ), // ODF 1.3 OFFICE-3767 and was written by LO<=4.2 + MAP_ODF13( "ParaContextMargin", XML_NAMESPACE_LO_EXT, XML_CONTEXTUAL_SPACING, XML_TYPE_BOOL|XML_TYPE_PROP_PARAGRAPH, 0 ), // extension namespace + // RES_CHRATR_CASEMAP + MT_E( "CharCaseMap", FO, FONT_VARIANT, XML_TYPE_TEXT_CASEMAP_VAR, 0 ), + MT_E( "CharCaseMap", FO, TEXT_TRANSFORM, XML_TYPE_TEXT_CASEMAP, 0 ), + // RES_CHRATR_COLOR + MT_ED( "CharColor", FO, COLOR, XML_TYPE_COLORAUTO|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharColor", STYLE, USE_WINDOW_FONT_COLOR, XML_TYPE_ISAUTOCOLOR|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_EXT_I("CharTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16 | XML_TYPE_PROP_TEXT, 0), + MAP_EXT("CharTransparence", XML_NAMESPACE_LO_EXT, XML_OPACITY, XML_TYPE_NEG_PERCENT16 | XML_TYPE_PROP_TEXT, 0), + MAP_EXT("CharColorTheme", XML_NAMESPACE_LO_EXT, XML_THEME_COLOR, XML_TYPE_THEME_COLOR, 0), + MAP_EXT("CharColorLumMod", XML_NAMESPACE_LO_EXT, XML_COLOR_LUM_MOD, XML_TYPE_PERCENT100 | XML_TYPE_PROP_TEXT, 0), + MAP_EXT("CharColorLumOff", XML_NAMESPACE_LO_EXT, XML_COLOR_LUM_OFF, XML_TYPE_PERCENT100 | XML_TYPE_PROP_TEXT, 0), + // RES_CHRATR_CONTOUR + MT_E( "CharContoured", STYLE, TEXT_OUTLINE, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_CROSSEDOUT + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_STYLE, XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY, 0), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_TYPE, XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY, 0), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_WIDTH, XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY, 0), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_TEXT, XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY, 0), + // RES_CHRATR_ESCAPEMENT + MT_E( "CharEscapement", STYLE, TEXT_POSITION, XML_TYPE_TEXT_ESCAPEMENT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( "CharEscapementHeight", STYLE, TEXT_POSITION, XML_TYPE_TEXT_ESCAPEMENT_HEIGHT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + // RES_CHRATR_FONT + MT_ED( "CharFontName", STYLE, FONT_NAME, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME ), + MT_ED( "CharFontName", FO, FONT_FAMILY, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME ), + MT_ED( "CharFontStyleName",STYLE, FONT_STYLE_NAME, XML_TYPE_STRING, CTF_FONTSTYLENAME ), + MT_ED( "CharFontFamily", STYLE, FONT_FAMILY_GENERIC,XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY ), + MT_ED( "CharFontPitch", STYLE, FONT_PITCH, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH ), + MT_ED( "CharFontCharSet", STYLE, FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET ), + // RES_CHRATR_FONTSIZE + MT_ED( "CharHeight", FO, FONT_SIZE, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT ), + MT_ED( "CharPropHeight",FO, FONT_SIZE, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL ), + MT_ED( "CharDiffHeight",STYLE,FONT_SIZE_REL, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF ), + // RES_CHRATR_KERNING + MT_E( "CharKerning", FO, LETTER_SPACING, XML_TYPE_TEXT_KERNING, 0 ), + // RES_CHRATR_LANGUAGE + MT_ED( "CharLocale", STYLE, RFC_LANGUAGE_TAG, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocale", FO, LANGUAGE, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocale", FO, SCRIPT, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocale", FO, COUNTRY, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_POSTURE + MT_E( "CharPosture", FO, FONT_STYLE, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_UNUSED1 + // RES_CHRATR_SHADOWED + MT_E( "CharShadowed", FO, TEXT_SHADOW, XML_TYPE_TEXT_SHADOWED, 0 ), + // RES_CHRATR_UNDERLINE + MT_E( "CharUnderline", STYLE, TEXT_UNDERLINE_STYLE, XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, CTF_UNDERLINE ), + MT_E( "CharUnderline", STYLE, TEXT_UNDERLINE_TYPE, XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharUnderline", STYLE, TEXT_UNDERLINE_WIDTH, XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharUnderlineColor", STYLE, TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, CTF_UNDERLINE_COLOR ), + MT_E( "CharUnderlineHasColor", STYLE, TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, CTF_UNDERLINE_HASCOLOR ), + // RES_CHRATR_WEIGHT + MT_E( "CharWeight", FO, FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_RSID + { "Rsid", XML_NAMESPACE_OFFICE_EXT, XML_RSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + // RES_PARATR_RSID + { "ParRsid", XML_NAMESPACE_OFFICE_EXT, XML_PARRSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + // RES_CHRATR_WORDLINEMODE + MT_E( "CharWordMode", STYLE, TEXT_UNDERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharWordMode", STYLE, TEXT_OVERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharWordMode", STYLE, TEXT_LINE_THROUGH_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_AUTOKERN + MT_E( "CharAutoKerning", STYLE, LETTER_KERNING, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_BLINK + MT_E( "CharFlash", STYLE, TEXT_BLINKING, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_NOHYPHEN + // TODO: not used? + // RES_CHRATR_UNUSED2 + // RES_CHRATR_BACKGROUND + MT_E( "CharBackColor", FO, BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, CTF_CHAR_BACKGROUND ), + MT_E( "CharBackTransparent", FO, BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE, CTF_CHAR_BACKGROUND_TRANSPARENCY), + MT_E( "CharBackColor", FO, TEXT_BACKGROUND_COLOR, XML_TYPE_COLOR|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_OLDTEXTBACKGROUND ), + // RES_CHRATR_CJK_FONT + MT_ED( "CharFontNameAsian", STYLE, FONT_NAME_ASIAN, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CJK ), + MT_ED( "CharFontNameAsian", STYLE, FONT_FAMILY_ASIAN, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CJK ), + MT_ED( "CharFontStyleNameAsian",STYLE, FONT_STYLE_NAME_ASIAN, XML_TYPE_STRING, CTF_FONTSTYLENAME_CJK ), + MT_ED( "CharFontFamilyAsian", STYLE, FONT_FAMILY_GENERIC_ASIAN,XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CJK ), + MT_ED( "CharFontPitchAsian", STYLE, FONT_PITCH_ASIAN, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CJK ), + MT_ED( "CharFontCharSetAsian", STYLE, FONT_CHARSET_ASIAN, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CJK ), + // RES_CHRATR_CJK_FONTSIZE + MT_ED( "CharHeightAsian", STYLE, FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_CJK ), + MT_ED( "CharPropHeightAsian",STYLE, FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL_CJK ), + MT_ED( "CharDiffHeightAsian",STYLE,FONT_SIZE_REL_ASIAN, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF_CJK ), + // RES_CHRATR_CJK_LANGUAGE + MT_ED( "CharLocaleAsian", STYLE, RFC_LANGUAGE_TAG_ASIAN, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleAsian", STYLE, LANGUAGE_ASIAN, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleAsian", STYLE, SCRIPT_ASIAN, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleAsian", STYLE, COUNTRY_ASIAN, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_CJK_POSTURE + MT_E( "CharPostureAsian", STYLE, FONT_STYLE_ASIAN, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CJK_WEIGHT + MT_E( "CharWeightAsian", STYLE, FONT_WEIGHT_ASIAN, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_CTL_FONT + MT_ED( "CharFontNameComplex", STYLE, FONT_NAME_COMPLEX, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CTL ), + MT_ED( "CharFontNameComplex", STYLE, FONT_FAMILY_COMPLEX, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CTL ), + MT_ED( "CharFontStyleNameComplex",STYLE, FONT_STYLE_NAME_COMPLEX, XML_TYPE_STRING, CTF_FONTSTYLENAME_CTL ), + MT_ED( "CharFontFamilyComplex", STYLE, FONT_FAMILY_GENERIC_COMPLEX,XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CTL ), + MT_ED( "CharFontPitchComplex", STYLE, FONT_PITCH_COMPLEX, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CTL ), + MT_ED( "CharFontCharSetComplex", STYLE, FONT_CHARSET_COMPLEX, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CTL ), + // RES_CHRATR_CTL_FONTSIZE + MT_ED( "CharHeightComplex", STYLE, FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_CTL ), + MT_ED( "CharPropHeightComplex",STYLE, FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL_CTL ), + MT_ED( "CharDiffHeightComplex",STYLE,FONT_SIZE_REL_COMPLEX, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF_CTL ), + // RES_CHRATR_CTL_LANGUAGE + MT_ED( "CharLocaleComplex", STYLE, RFC_LANGUAGE_TAG_COMPLEX, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleComplex", STYLE, LANGUAGE_COMPLEX, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleComplex", STYLE, SCRIPT_COMPLEX, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleComplex", STYLE, COUNTRY_COMPLEX, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_CTL_POSTURE + MT_E( "CharPostureComplex", STYLE, FONT_STYLE_COMPLEX, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CTL_WEIGHT + MT_E( "CharWeightComplex", STYLE, FONT_WEIGHT_COMPLEX, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_ROTATE + MT_E( "CharRotation", STYLE, TEXT_ROTATION_ANGLE, XML_TYPE_TEXT_ROTATION_ANGLE, 0 ), + MT_E( "CharRotationIsFitToLine", STYLE, TEXT_ROTATION_SCALE, XML_TYPE_TEXT_ROTATION_SCALE, 0 ), + // RES_CHRATR_EMPHASIS_MARK + MT_E( "CharEmphasis", STYLE, TEXT_EMPHASIZE, XML_TYPE_TEXT_EMPHASIZE, 0 ), + // RES_CHRATR_TWO_LINES + MT_E( "CharCombineIsOn", STYLE, TEXT_COMBINE, XML_TYPE_TEXT_COMBINE, 0 ), + MT_E( "CharCombinePrefix", STYLE, TEXT_COMBINE_START_CHAR, XML_TYPE_TEXT_COMBINECHAR, 0 ), + MT_E( "CharCombineSuffix", STYLE, TEXT_COMBINE_END_CHAR, XML_TYPE_TEXT_COMBINECHAR, 0 ), + // RES_CHRATR_SCALEW + MT_E( "CharScaleWidth", STYLE, TEXT_SCALE, XML_TYPE_PERCENT16, 0 ), + //RES_CHRATR_RELIEF + MT_E( "CharRelief", STYLE, FONT_RELIEF, XML_TYPE_TEXT_FONT_RELIEF, 0 ), + // RES_CHRATR_HIDDEN + MT_E( "CharHidden", TEXT, DISPLAY, XML_TYPE_TEXT_HIDDEN_AS_DISPLAY|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_TEXT_DISPLAY ), + // RES_CHRATR_OVERLINE + MT_E( "CharOverline", STYLE, TEXT_OVERLINE_STYLE, XML_TYPE_TEXT_OVERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharOverline", STYLE, TEXT_OVERLINE_TYPE, XML_TYPE_TEXT_OVERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharOverline", STYLE, TEXT_OVERLINE_WIDTH, XML_TYPE_TEXT_OVERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharOverlineColor", STYLE, TEXT_OVERLINE_COLOR, XML_TYPE_TEXT_OVERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( "CharOverlineHasColor", STYLE, TEXT_OVERLINE_COLOR, XML_TYPE_TEXT_OVERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + // RES_CHRATR_BOX + MAP_EXT( "CharLeftBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERWIDTH ), + MAP_EXT( "CharLeftBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERWIDTH ), + MAP_EXT( "CharRightBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERWIDTH ), + MAP_EXT( "CharTopBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERWIDTH ), + MAP_EXT( "CharBottomBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERWIDTH ), + MAP_EXT_I( "CharLeftBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERWIDTH ), + MAP_EXT_I( "CharLeftBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERWIDTH ), + MAP_EXT_I( "CharRightBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERWIDTH ), + MAP_EXT_I( "CharTopBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERWIDTH ), + MAP_EXT_I( "CharBottomBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERWIDTH ), + + MAP_EXT( "CharLeftBorderDistance", XML_NAMESPACE_LO_EXT, XML_PADDING, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERDISTANCE ), + MAP_EXT( "CharLeftBorderDistance", XML_NAMESPACE_LO_EXT, XML_PADDING_LEFT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERDISTANCE ), + MAP_EXT( "CharRightBorderDistance", XML_NAMESPACE_LO_EXT, XML_PADDING_RIGHT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERDISTANCE ), + MAP_EXT( "CharTopBorderDistance", XML_NAMESPACE_LO_EXT, XML_PADDING_TOP, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERDISTANCE ), + MAP_EXT( "CharBottomBorderDistance",XML_NAMESPACE_LO_EXT, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERDISTANCE ), + MAP_EXT_I( "CharLeftBorderDistance", XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERDISTANCE ), + MAP_EXT_I( "CharLeftBorderDistance", XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERDISTANCE ), + MAP_EXT_I( "CharRightBorderDistance", XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERDISTANCE ), + MAP_EXT_I( "CharTopBorderDistance", XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERDISTANCE ), + MAP_EXT_I( "CharBottomBorderDistance",XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERDISTANCE ), + + MAP_EXT( "CharLeftBorder", XML_NAMESPACE_LO_EXT, XML_BORDER, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDER ), + MAP_EXT( "CharLeftBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LEFT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDER ), + MAP_EXT( "CharRightBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_RIGHT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDER ), + MAP_EXT( "CharTopBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_TOP, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDER ), + MAP_EXT( "CharBottomBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_BOTTOM, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDER ), + MAP_EXT_I( "CharLeftBorder", XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDER ), + MAP_EXT_I( "CharLeftBorder", XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDER ), + MAP_EXT_I( "CharRightBorder", XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDER ), + MAP_EXT_I( "CharTopBorder", XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDER ), + MAP_EXT_I( "CharBottomBorder", XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDER ), + // RES_CHRATR_SHADOW + MAP_EXT( "CharShadowFormat", XML_NAMESPACE_LO_EXT, XML_SHADOW, XML_TYPE_TEXT_SHADOW|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT_I( "CharShadowFormat", XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW|XML_TYPE_PROP_TEXT, 0 ), + // RES_CHRATR_HIGHLIGHT + MT_E( "CharHighlight", FO, BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY| MID_FLAG_NO_PROPERTY_IMPORT, CTF_CHAR_HIGHLIGHT ), + // RES_TXTATR_INETFMT + // TODO + // RES_TXTATR_REFMARK + // TODO + // RES_TXTATR_TOXMARK + // TODO + // RES_TXTATR_CHARFMT +// M_E_SI( TEXT, style_name, RES_TXTATR_CHARFMT, 0 ), + // RES_TXTATR_CJK_RUBY + // TODO + // RES_TXTATR_FIELD + // TODO + // RES_TXTATR_FLYCNT + // TODO + // RES_TXTATR_FTN + // TODO + // RES_TXTATR_SOFTHYPH + // TODO + // RES_TXTATR_HARDBLANK + // TODO + + // RES_PARATR_LINESPACING + MP_E( "ParaLineSpacing", FO, LINE_HEIGHT, XML_TYPE_LINE_SPACE_FIXED, 0 ), + MP_E( "ParaLineSpacing", STYLE, LINE_HEIGHT_AT_LEAST, XML_TYPE_LINE_SPACE_MINIMUM, 0 ), + MP_E( "ParaLineSpacing", STYLE, LINE_SPACING, XML_TYPE_LINE_SPACE_DISTANCE, 0 ), + // RES_PARATR_ADJUST + MP_E( "ParaAdjust", FO, TEXT_ALIGN, XML_TYPE_TEXT_ADJUST, CTF_SD_SHAPE_PARA_ADJUST ), + MP_E( "ParaLastLineAdjust", FO, TEXT_ALIGN_LAST, XML_TYPE_TEXT_ADJUSTLAST, CTF_PARA_ADJUSTLAST ), + MP_E( "ParaExpandSingleWord",STYLE, JUSTIFY_SINGLE_WORD,XML_TYPE_BOOL, 0 ), + // RES_PARATR_SPLIT + MP_E( "ParaSplit", FO, KEEP_TOGETHER, XML_TYPE_TEXT_SPLIT, 0 ), + // RES_PARATR_ORPHANS + MP_E( "ParaOrphans", FO, ORPHANS, XML_TYPE_NUMBER8, 0 ), + // RES_PARATR_WIDOWS + MP_E( "ParaWidows", FO, WIDOWS, XML_TYPE_NUMBER8, 0 ), + // RES_PARATR_TABSTOP + MP_ED( "ParaTabStops", STYLE, TAB_STOPS, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_TABSTOP, CTF_TABSTOP ), // this is not really a string! + // RES_PARATR_HYPHENZONE + MT_E( "ParaIsHyphenation", FO, HYPHENATE, XML_TYPE_BOOL, 0 ), + MT_E( "ParaHyphenationMaxLeadingChars", FO, HYPHENATION_REMAIN_CHAR_COUNT, XML_TYPE_NUMBER16_NO_ZERO, 0 ), + MT_E( "ParaHyphenationMaxTrailingChars",FO, HYPHENATION_PUSH_CHAR_COUNT, XML_TYPE_NUMBER16_NO_ZERO, 0 ), + MP_E( "ParaHyphenationMaxHyphens", FO, HYPHENATION_LADDER_COUNT, XML_TYPE_NUMBER16_NONE, 0 ), + MAP_EXT( "ParaHyphenationNoCaps", XML_NAMESPACE_LO_EXT, XML_HYPHENATION_NO_CAPS, XML_TYPE_BOOL|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( "ParaHyphenationNoLastWord", XML_NAMESPACE_LO_EXT, XML_HYPHENATION_NO_LAST_WORD, XML_TYPE_BOOL|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( "ParaHyphenationMinWordLength", XML_NAMESPACE_LO_EXT, XML_HYPHENATION_WORD_CHAR_COUNT, XML_TYPE_NUMBER16_NONE|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT( "ParaHyphenationZone", XML_NAMESPACE_LO_EXT, XML_HYPHENATION_ZONE, XML_TYPE_NUMBER16_NONE|XML_TYPE_PROP_TEXT, 0 ), + // RES_PARATR_DROP + MP_E( "DropCapWholeWord", STYLE, LENGTH, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_DROPCAPWHOLEWORD ), + MP_E( "DropCapCharStyleName", STYLE, STYLE_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_DROPCAPCHARSTYLE ), + MP_E( "DropCapFormat", STYLE, DROP_CAP, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_DROPCAP, CTF_DROPCAPFORMAT ), + // RES_PARATR_REGISTER + MP_E( "ParaRegisterModeActive", STYLE, REGISTER_TRUE, XML_TYPE_BOOL, 0 ), + // RES_PARATR_NUMRULE + MP_E( "NumberingStyleName", STYLE, LIST_STYLE_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STYLENAME, CTF_NUMBERINGSTYLENAME ), + + // RES_FILL_ORDER + // not required + // RES_FRM_SIZE + // not required + // RES_PAPER_BIN + // not required + // RES_LR_SPACE + + MP_E( "ParaFirstLineIndent", FO, TEXT_INDENT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_PARAFIRSTLINE ), + MP_E( "ParaFirstLineIndentRelative", FO, TEXT_INDENT, XML_TYPE_PERCENT, CTF_PARAFIRSTLINE_REL ), + MP_E( "ParaIsAutoFirstLineIndent", STYLE, AUTO_TEXT_INDENT, XML_TYPE_BOOL, 0 ), + // RES_PAGEDESC + MP_E( "PageDescName", STYLE, MASTER_PAGE_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STYLENAME, CTF_PAGEDESCNAME ), + MP_E( "PageNumberOffset", STYLE, PAGE_NUMBER, XML_TYPE_NUMBER16_AUTO|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_PAGENUMBEROFFSET ), + // RES_BREAK : TODO: does this work? + MP_E( "BreakType", FO, BREAK_BEFORE, XML_TYPE_TEXT_BREAKBEFORE|MID_FLAG_MULTI_PROPERTY, 0 ), + MP_E( "BreakType", FO, BREAK_AFTER, XML_TYPE_TEXT_BREAKAFTER, 0 ), + // RES_CNTNT + // not required + // RES_HEADER + // not required + // RES_FOOTER + // not required + // RES_PRINT + // not required + // RES_OPAQUE + // not required + // RES_PROTECT + // not required + // RES_SURROUND + // not required + // RES_VERT_ORIENT + // not required + // RES_HORI_ORIENT + // not required + // RES_ANCHOR + // not required + // RES_BACKGROUND + // DO NOT REORDER these! + MP_E( "ParaBackColor", FO, BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, 0 ), + MP_E( "ParaBackTransparent", FO, BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + MP_E( "ParaBackGraphicLocation", STYLE, POSITION, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BUILDIN_CMP_ONLY, CTF_BACKGROUND_POS ), + MP_E( "ParaBackGraphicFilter",STYLE, FILTER_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_BACKGROUND_FILTER ), + MP_E( "ParaBackGraphic", STYLE, BACKGROUND_IMAGE, MID_FLAG_ELEMENT_ITEM|XML_TYPE_GRAPHIC, CTF_BACKGROUND_URL ), + + // RES_BOX + MP_E( "LeftBorder", STYLE, BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_ALLBORDERWIDTH ), + MP_E( "LeftBorder", STYLE, BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_LEFTBORDERWIDTH ), + MP_E( "RightBorder", STYLE, BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_RIGHTBORDERWIDTH ), + MP_E( "TopBorder", STYLE, BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_TOPBORDERWIDTH ), + MP_E( "BottomBorder", STYLE, BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_BOTTOMBORDERWIDTH ), + + MP_E( "LeftBorderDistance", FO, PADDING, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_ALLBORDERDISTANCE ), // need special import filtering + MP_E( "LeftBorderDistance", FO, PADDING_LEFT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_LEFTBORDERDISTANCE ), + MP_E( "RightBorderDistance", FO, PADDING_RIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_RIGHTBORDERDISTANCE ), + MP_E( "TopBorderDistance", FO, PADDING_TOP, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_TOPBORDERDISTANCE ), + MP_E( "BottomBorderDistance",FO, PADDING_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_BOTTOMBORDERDISTANCE ), + + MP_E( "LeftBorder", FO, BORDER, XML_TYPE_BORDER, CTF_ALLBORDER ), + MP_E( "LeftBorder", FO, BORDER_LEFT, XML_TYPE_BORDER, CTF_LEFTBORDER ), + MP_E( "RightBorder", FO, BORDER_RIGHT, XML_TYPE_BORDER, CTF_RIGHTBORDER ), + MP_E( "TopBorder", FO, BORDER_TOP, XML_TYPE_BORDER, CTF_TOPBORDER ), + MP_E( "BottomBorder", FO, BORDER_BOTTOM, XML_TYPE_BORDER, CTF_BOTTOMBORDER ), + // RES_SHADOW + MP_E( "ParaShadowFormat", STYLE, SHADOW, XML_TYPE_TEXT_SHADOW, 0 ), + // RES_FRMMACRO + // not required + // RES_COL + // not required + // RES_KEEP + MP_E( "ParaKeepTogether", FO, KEEP_WITH_NEXT, XML_TYPE_TEXT_KEEP, 0 ), + // RES_URL + // not required + // RES_EDIT_IN_READONLY + // not required + // RES_LAYOUT_SPLIT + // not required + // RES_CHAIN + // not required + + // RES_LINENUMBER + MP_E( "ParaLineNumberCount", TEXT, NUMBER_LINES, XML_TYPE_BOOL, 0 ), + MP_E( "ParaLineNumberStartValue", TEXT, LINE_NUMBER, XML_TYPE_NUMBER, 0 ), + + // RES_FTN_AT_TXTEND + // not required + // RES_END_AT_TXTEND + // not required + MP_ED( "ParaIsCharacterDistance", STYLE, TEXT_AUTOSPACE, XML_TYPE_TEXT_AUTOSPACE, 0 ), + MP_ED( "ParaIsHangingPunctuation", STYLE, PUNCTUATION_WRAP, XML_TYPE_TEXT_PUNCTUATION_WRAP, 0 ), + MP_ED( "ParaIsForbiddenRules", STYLE, LINE_BREAK, XML_TYPE_TEXT_LINE_BREAK, 0 ), + MP_E( "TabStopDistance", STYLE, TAB_STOP_DISTANCE, XML_TYPE_MEASURE, 0 ), + + // RES_PARATR_VERTALIGN + MP_E( "ParaVertAlignment", STYLE, VERTICAL_ALIGN, XML_TYPE_TEXT_VERTICAL_ALIGN, 0 ), + + // RES_PARATR_SNAPTOGRID + MP_E( "SnapToGrid", STYLE, SNAP_TO_LAYOUT_GRID, XML_TYPE_BOOL, 0 ), + + MP_ED( "WritingMode", STYLE, WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT, CTF_TEXTWRITINGMODE ), + + MP_E( "ParaIsConnectBorder", STYLE, JOIN_BORDER, XML_TYPE_BOOL, 0 ), + + MP_E( "DefaultOutlineLevel", STYLE, DEFAULT_OUTLINE_LEVEL, XML_TYPE_TEXT_NUMBER8_ONE_BASED|MID_FLAG_SPECIAL_ITEM_EXPORT|MID_FLAG_NO_PROPERTY_IMPORT, CTF_DEFAULT_OUTLINE_LEVEL ), + + MP_ED( "FontIndependentLineSpacing", STYLE, FONT_INDEPENDENT_LINE_SPACING, XML_TYPE_BOOL, 0 ), + + M_END() +}; + + +XMLPropertyMapEntry const aXMLAdditionalTextDefaultsMap[] = +{ + // RES_FOLLOW_TEXT_FLOW - DVO #i18732# + MG_ED( "IsFollowingTextFlow", STYLE, FLOW_WITH_TEXT, XML_TYPE_BOOL, 0 ), + + // #i28701# - RES_WRAP_INFLUENCE_ON_OBJPOS + MG_ED( "WrapInfluenceOnPosition", DRAW, WRAP_INFLUENCE_ON_POSITION, XML_TYPE_WRAP_INFLUENCE_ON_POSITION, 0 ), + + M_END() +}; + +XMLPropertyMapEntry const aXMLTextPropMap[] = +{ + // RES_CHRATR_CASEMAP + MT_E( "CharCaseMap", FO, FONT_VARIANT, XML_TYPE_TEXT_CASEMAP_VAR, 0 ), + MT_E( "CharCaseMap", FO, TEXT_TRANSFORM, XML_TYPE_TEXT_CASEMAP, 0 ), + // RES_CHRATR_COLOR + MT_ED( "CharColor", FO, COLOR, XML_TYPE_COLORAUTO|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharColor", STYLE, USE_WINDOW_FONT_COLOR, XML_TYPE_ISAUTOCOLOR|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_EXT_I("CharTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16 | XML_TYPE_PROP_TEXT, 0), + MAP_EXT("CharTransparence", XML_NAMESPACE_LO_EXT, XML_OPACITY, XML_TYPE_NEG_PERCENT16 | XML_TYPE_PROP_TEXT, 0), + MAP_EXT("CharColorTheme", XML_NAMESPACE_LO_EXT, XML_THEME_COLOR, XML_TYPE_THEME_COLOR | XML_TYPE_PROP_TEXT, 0), + MAP_EXT("CharColorLumMod", XML_NAMESPACE_LO_EXT, XML_COLOR_LUM_MOD, XML_TYPE_PERCENT100 | XML_TYPE_PROP_TEXT, 0), + MAP_EXT("CharColorLumOff", XML_NAMESPACE_LO_EXT, XML_COLOR_LUM_OFF, XML_TYPE_PERCENT100 | XML_TYPE_PROP_TEXT, 0), + // RES_CHRATR_CONTOUR + MT_E( "CharContoured", STYLE, TEXT_OUTLINE, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_CROSSEDOUT + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_STYLE, XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY, 0), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_TYPE, XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY, 0), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_WIDTH, XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY, 0), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_TEXT, XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY, 0), + // RES_CHRATR_ESCAPEMENT + MT_E( "CharEscapement", STYLE, TEXT_POSITION, XML_TYPE_TEXT_ESCAPEMENT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( "CharEscapementHeight", STYLE, TEXT_POSITION, XML_TYPE_TEXT_ESCAPEMENT_HEIGHT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + // RES_CHRATR_FONT + MT_ED( "CharFontName", STYLE, FONT_NAME, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME ), + MT_ED( "CharFontName", FO, FONT_FAMILY, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME ), + MT_ED( "CharFontStyleName",STYLE, FONT_STYLE_NAME, XML_TYPE_STRING, CTF_FONTSTYLENAME ), + MT_ED( "CharFontFamily", STYLE, FONT_FAMILY_GENERIC,XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY ), + MT_ED( "CharFontPitch", STYLE, FONT_PITCH, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH ), + MT_ED( "CharFontCharSet", STYLE, FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET ), + // RES_CHRATR_FONTSIZE + MT_ED( "CharHeight", FO, FONT_SIZE, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT ), + MT_ED( "CharPropHeight",FO, FONT_SIZE, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL ), + MT_ED( "CharDiffHeight",STYLE,FONT_SIZE_REL, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF ), + // RES_CHRATR_KERNING + MT_E( "CharKerning", FO, LETTER_SPACING, XML_TYPE_TEXT_KERNING, 0 ), + // RES_CHRATR_LANGUAGE + MT_ED( "CharLocale", STYLE, RFC_LANGUAGE_TAG, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocale", FO, LANGUAGE, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocale", FO, SCRIPT, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocale", FO, COUNTRY, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_POSTURE + MT_E( "CharPosture", FO, FONT_STYLE, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_UNUSED1 + // RES_CHRATR_SHADOWED + MT_E( "CharShadowed", FO, TEXT_SHADOW, XML_TYPE_TEXT_SHADOWED, 0 ), + // VALIDATED UP TO THIS LINE + // RES_CHRATR_UNDERLINE + MT_E( "CharUnderline", STYLE, TEXT_UNDERLINE_STYLE, XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, CTF_UNDERLINE ), + MT_E( "CharUnderline", STYLE, TEXT_UNDERLINE_TYPE, XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharUnderline", STYLE, TEXT_UNDERLINE_WIDTH, XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharUnderlineColor", STYLE, TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, CTF_UNDERLINE_COLOR ), + MT_E( "CharUnderlineHasColor", STYLE, TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, CTF_UNDERLINE_HASCOLOR ), + // RES_CHRATR_WEIGHT + MT_E( "CharWeight", FO, FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_RSID + { "Rsid", XML_NAMESPACE_OFFICE_EXT, XML_RSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + // RES_PARATR_RSID + { "ParRsid", XML_NAMESPACE_OFFICE_EXT, XML_PARRSID, XML_TYPE_HEX|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + // RES_CHRATR_WORDLINEMODE + MT_E( "CharWordMode", STYLE, TEXT_UNDERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharWordMode", STYLE, TEXT_OVERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharWordMode", STYLE, TEXT_LINE_THROUGH_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_AUTOKERN + MT_E( "CharAutoKerning", STYLE, LETTER_KERNING, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_BLINK + MT_E( "CharFlash", STYLE, TEXT_BLINKING, XML_TYPE_BOOL, 0 ), + // RES_CHRATR_NOHYPHEN + // TODO: not used? + // RES_CHRATR_UNUSED2 + // RES_CHRATR_BACKGROUND + MT_E( "CharBackColor", FO, BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, CTF_CHAR_BACKGROUND ), + MT_E( "CharBackTransparent", FO, BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE, CTF_CHAR_BACKGROUND_TRANSPARENCY), + { "CharShadingValue", XML_NAMESPACE_LO_EXT, XML_CHAR_SHADING_VALUE, XML_TYPE_NUMBER|XML_TYPE_PROP_TEXT, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, false }, + MT_E( "CharBackColor", FO, TEXT_BACKGROUND_COLOR, XML_TYPE_COLOR|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_OLDTEXTBACKGROUND ), + // RES_CHRATR_CJK_FONT + MT_ED( "CharFontNameAsian", STYLE, FONT_NAME_ASIAN, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CJK ), + MT_ED( "CharFontNameAsian", STYLE, FONT_FAMILY_ASIAN, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CJK ), + MT_ED( "CharFontStyleNameAsian",STYLE, FONT_STYLE_NAME_ASIAN, XML_TYPE_STRING, CTF_FONTSTYLENAME_CJK ), + MT_ED( "CharFontFamilyAsian", STYLE, FONT_FAMILY_GENERIC_ASIAN,XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CJK ), + MT_ED( "CharFontPitchAsian", STYLE, FONT_PITCH_ASIAN, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CJK ), + MT_ED( "CharFontCharSetAsian", STYLE, FONT_CHARSET_ASIAN, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CJK ), + // RES_CHRATR_CJK_FONTSIZE + MT_ED( "CharHeightAsian", STYLE, FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_CJK ), + MT_ED( "CharPropHeightAsian",STYLE, FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL_CJK ), + MT_ED( "CharDiffHeightAsian",STYLE,FONT_SIZE_REL_ASIAN, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF_CJK ), + // RES_CHRATR_CJK_LANGUAGE + MT_ED( "CharLocaleAsian", STYLE, RFC_LANGUAGE_TAG_ASIAN, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleAsian", STYLE, LANGUAGE_ASIAN, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleAsian", STYLE, SCRIPT_ASIAN, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleAsian", STYLE, COUNTRY_ASIAN, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_CJK_POSTURE + MT_E( "CharPostureAsian", STYLE, FONT_STYLE_ASIAN, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CJK_WEIGHT + MT_E( "CharWeightAsian", STYLE, FONT_WEIGHT_ASIAN, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_CTL_FONT + MT_ED( "CharFontNameComplex", STYLE, FONT_NAME_COMPLEX, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CTL ), + MT_ED( "CharFontNameComplex", STYLE, FONT_FAMILY_COMPLEX, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CTL ), + MT_ED( "CharFontStyleNameComplex",STYLE, FONT_STYLE_NAME_COMPLEX, XML_TYPE_STRING, CTF_FONTSTYLENAME_CTL ), + MT_ED( "CharFontFamilyComplex", STYLE, FONT_FAMILY_GENERIC_COMPLEX,XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CTL ), + MT_ED( "CharFontPitchComplex", STYLE, FONT_PITCH_COMPLEX, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CTL ), + MT_ED( "CharFontCharSetComplex", STYLE, FONT_CHARSET_COMPLEX, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CTL ), + // RES_CHRATR_CTL_FONTSIZE + MT_ED( "CharHeightComplex", STYLE, FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_CTL ), + MT_ED( "CharPropHeightComplex",STYLE, FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT_PROP|MID_FLAG_MULTI_PROPERTY, CTF_CHARHEIGHT_REL_CTL ), + MT_ED( "CharDiffHeightComplex",STYLE,FONT_SIZE_REL_COMPLEX, XML_TYPE_CHAR_HEIGHT_DIFF, CTF_CHARHEIGHT_DIFF_CTL ), + // RES_CHRATR_CTL_LANGUAGE + MT_ED( "CharLocaleComplex", STYLE, RFC_LANGUAGE_TAG_COMPLEX, XML_TYPE_CHAR_RFC_LANGUAGE_TAG|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleComplex", STYLE, LANGUAGE_COMPLEX, XML_TYPE_CHAR_LANGUAGE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleComplex", STYLE, SCRIPT_COMPLEX, XML_TYPE_CHAR_SCRIPT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharLocaleComplex", STYLE, COUNTRY_COMPLEX, XML_TYPE_CHAR_COUNTRY|MID_FLAG_MERGE_PROPERTY, 0 ), + // RES_CHRATR_CTL_POSTURE + MT_E( "CharPostureComplex", STYLE, FONT_STYLE_COMPLEX, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CTL_WEIGHT + MT_E( "CharWeightComplex", STYLE, FONT_WEIGHT_COMPLEX, XML_TYPE_TEXT_WEIGHT, 0 ), + // RES_CHRATR_ROTATE + MT_E( "CharRotation", STYLE, TEXT_ROTATION_ANGLE, XML_TYPE_TEXT_ROTATION_ANGLE, 0 ), + MT_E( "CharRotationIsFitToLine", STYLE, TEXT_ROTATION_SCALE, XML_TYPE_TEXT_ROTATION_SCALE, 0 ), + // RES_CHRATR_EMPHASIS_MARK + MT_E( "CharEmphasis", STYLE, TEXT_EMPHASIZE, XML_TYPE_TEXT_EMPHASIZE, 0 ), + // RES_CHRATR_TWO_LINES + MT_E( "CharCombineIsOn", STYLE, TEXT_COMBINE, XML_TYPE_TEXT_COMBINE|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( "CharCombinePrefix", STYLE, TEXT_COMBINE_START_CHAR, XML_TYPE_TEXT_COMBINECHAR, 0 ), + MT_E( "CharCombineSuffix", STYLE, TEXT_COMBINE_END_CHAR, XML_TYPE_TEXT_COMBINECHAR, 0 ), + // RES_CHRATR_SCALEW + MT_E( "CharScaleWidth", STYLE, TEXT_SCALE, XML_TYPE_PERCENT16, 0 ), + // combined characters field, does not correspond to a property + MT_E( "", STYLE, TEXT_COMBINE, XML_TYPE_TEXT_COMBINE_CHARACTERS|MID_FLAG_NO_PROPERTY, CTF_COMBINED_CHARACTERS_FIELD ), + //RES_CHRATR_RELIEF + MT_E( "CharRelief", STYLE, FONT_RELIEF, XML_TYPE_TEXT_FONT_RELIEF, 0 ), + // RES_CHRATR_HIDDEN + MT_E( "CharHidden", TEXT, DISPLAY, XML_TYPE_TEXT_HIDDEN_AS_DISPLAY|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_TEXT_DISPLAY ), + // RES_CHRATR_OVERLINE + MT_E( "CharOverline", STYLE, TEXT_OVERLINE_STYLE, XML_TYPE_TEXT_OVERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharOverline", STYLE, TEXT_OVERLINE_TYPE, XML_TYPE_TEXT_OVERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharOverline", STYLE, TEXT_OVERLINE_WIDTH, XML_TYPE_TEXT_OVERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharOverlineColor", STYLE, TEXT_OVERLINE_COLOR, XML_TYPE_TEXT_OVERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( "CharOverlineHasColor", STYLE, TEXT_OVERLINE_COLOR, XML_TYPE_TEXT_OVERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + // RES_CHRATR_BOX + MAP_EXT( "CharLeftBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERWIDTH ), + MAP_EXT( "CharLeftBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERWIDTH ), + MAP_EXT( "CharRightBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERWIDTH ), + MAP_EXT( "CharTopBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERWIDTH ), + MAP_EXT( "CharBottomBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERWIDTH ), + MAP_EXT_I( "CharLeftBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERWIDTH ), + MAP_EXT_I( "CharLeftBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERWIDTH ), + MAP_EXT_I( "CharRightBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERWIDTH ), + MAP_EXT_I( "CharTopBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERWIDTH ), + MAP_EXT_I( "CharBottomBorder", XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERWIDTH ), + + MAP_EXT( "CharLeftBorderDistance", XML_NAMESPACE_LO_EXT, XML_PADDING, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERDISTANCE ), + MAP_EXT( "CharLeftBorderDistance", XML_NAMESPACE_LO_EXT, XML_PADDING_LEFT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERDISTANCE ), + MAP_EXT( "CharRightBorderDistance", XML_NAMESPACE_LO_EXT, XML_PADDING_RIGHT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERDISTANCE ), + MAP_EXT( "CharTopBorderDistance", XML_NAMESPACE_LO_EXT, XML_PADDING_TOP, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERDISTANCE ), + MAP_EXT( "CharBottomBorderDistance",XML_NAMESPACE_LO_EXT, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERDISTANCE ), + MAP_EXT_I( "CharLeftBorderDistance", XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDERDISTANCE ), + MAP_EXT_I( "CharLeftBorderDistance", XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDERDISTANCE ), + MAP_EXT_I( "CharRightBorderDistance", XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDERDISTANCE ), + MAP_EXT_I( "CharTopBorderDistance", XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDERDISTANCE ), + MAP_EXT_I( "CharBottomBorderDistance",XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDERDISTANCE ), + + MAP_EXT( "CharLeftBorder", XML_NAMESPACE_LO_EXT, XML_BORDER, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDER ), + MAP_EXT( "CharLeftBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_LEFT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDER ), + MAP_EXT( "CharRightBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_RIGHT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDER ), + MAP_EXT( "CharTopBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_TOP, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDER ), + MAP_EXT( "CharBottomBorder", XML_NAMESPACE_LO_EXT, XML_BORDER_BOTTOM, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDER ), + MAP_EXT_I( "CharLeftBorder", XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARALLBORDER ), + MAP_EXT_I( "CharLeftBorder", XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARLEFTBORDER ), + MAP_EXT_I( "CharRightBorder", XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARRIGHTBORDER ), + MAP_EXT_I( "CharTopBorder", XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARTOPBORDER ), + MAP_EXT_I( "CharBottomBorder", XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER|XML_TYPE_PROP_TEXT, CTF_CHARBOTTOMBORDER ), + // RES_CHRATR_SHADOW + MAP_EXT( "CharShadowFormat", XML_NAMESPACE_LO_EXT, XML_SHADOW, XML_TYPE_TEXT_SHADOW|XML_TYPE_PROP_TEXT, 0 ), + MAP_EXT_I( "CharShadowFormat", XML_NAMESPACE_STYLE, XML_SHADOW, XML_TYPE_TEXT_SHADOW|XML_TYPE_PROP_TEXT, 0 ), + // RES_CHRATR_HIGHLIGHT + MT_E( "CharHighlight", FO, BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY|MID_FLAG_NO_PROPERTY_IMPORT, CTF_CHAR_HIGHLIGHT ), + // RES_TXTATR_INETFMT + MT_E( "HyperLinkURL", TEXT, XMLNS, XML_TYPE_STRING|MID_FLAG_NO_PROPERTY_IMPORT, CTF_HYPERLINK_URL ), + // RES_TXTATR_REFMARK + // TODO + // RES_TXTATR_TOXMARK + // TODO + // RES_TXTATR_CHARFMT + MT_E( "CharStyleName", TEXT, STYLE_NAME, XML_TYPE_STRING|MID_FLAG_NO_PROPERTY_IMPORT, CTF_CHAR_STYLE_NAME ), + // RES_TXTATR_CJK_RUBY + // TODO + // RES_TXTATR_FIELD + // TODO + // RES_TXTATR_FLYCNT + // TODO + // RES_TXTATR_FTN + // TODO + // RES_TXTATR_SOFTHYPH + // TODO + // RES_TXTATR_HARDBLANK + // TODO + // RES_UNKNOWNATR_CONTAINER + MT_E( "TextUserDefinedAttributes", TEXT, XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + MT_ED( "ParaIsCharacterDistance", STYLE, TEXT_AUTOSPACE, XML_TYPE_TEXT_AUTOSPACE, 0 ), + MT_ED( "ParaIsHangingPunctuation", STYLE, PUNCTUATION_WRAP, XML_TYPE_TEXT_PUNCTUATION_WRAP, 0 ), + MT_ED( "ParaIsForbiddenRules", STYLE, LINE_BREAK, XML_TYPE_TEXT_LINE_BREAK, 0 ), + MT_E( "TabStopDistance", STYLE, TAB_STOP_DISTANCE, XML_TYPE_MEASURE, 0 ), + + M_END() +}; + +XMLPropertyMapEntry const aXMLFramePropMap[] = +{ + // RES_FILL_ORDER + // TODO: not required??? + // RES_FRM_SIZE + MG_ED( "Width", SVG, WIDTH, XML_TYPE_MEASURE, CTF_FRAMEWIDTH_ABS ), + MG_ED( "Width", FO, MIN_WIDTH, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_FRAMEWIDTH_MIN_ABS ), + MG_ED( "RelativeWidth", FO, MIN_WIDTH, XML_TYPE_TEXT_REL_WIDTH_HEIGHT, CTF_FRAMEWIDTH_MIN_REL ), + MG_ED( "RelativeWidth", STYLE, REL_WIDTH, XML_TYPE_TEXT_REL_WIDTH_HEIGHT, CTF_FRAMEWIDTH_REL ), + MG_ED( "WidthType", FO, TEXT_BOX, XML_TYPE_NUMBER16|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FRAMEWIDTH_TYPE ), +// M_ED( "RelativeWidth", STYLE, REL_WIDTH, XML_TYPE_TEXT_REL_WIDTH_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0 ), +// M_ED( "IsSyncWidthToHeight",STYLE, REL_WIDTH, XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0 ), + + MG_ED( "Height", SVG, HEIGHT, XML_TYPE_MEASURE, CTF_FRAMEHEIGHT_ABS ), + MG_ED( "Height", FO, MIN_HEIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, CTF_FRAMEHEIGHT_MIN_ABS ), + MG_ED( "RelativeHeight", FO, MIN_HEIGHT, XML_TYPE_TEXT_REL_WIDTH_HEIGHT, CTF_FRAMEHEIGHT_MIN_REL ), + MG_ED( "RelativeHeight", STYLE, REL_HEIGHT, XML_TYPE_TEXT_REL_WIDTH_HEIGHT, CTF_FRAMEHEIGHT_REL ), +// M_ED( "RelativeHeight", STYLE, REL_HEIGHT, XML_TYPE_TEXT_REL_WIDTH_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_FRAMEHEIGHT_REL ), +// M_ED( "IsSyncHeightToWidth",STYLE, REL_HEIGHT, XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT|MID_FLAG_MULTI_PROPERTY, CTF_SYNCHEIGHT ), +// M_ED( "IsSyncHeightToWidth",STYLE, REL_HEIGHT, XML_TYPE_TEXT_SYNC_WIDTH_HEIGHT_MIN, CTF_SYNCHEIGHT_MIN ), + MG_ED( "SizeType", FO, TEXT_BOX, XML_TYPE_NUMBER16|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SIZETYPE ), + // RES_PAPER_BIN + // not required + // RES_ANCHOR + // moved to here because it is not used for automatic styles + MG_ED( "AnchorType", TEXT, ANCHOR_TYPE, XML_TYPE_TEXT_ANCHOR_TYPE, CTF_ANCHORTYPE ), + // AnchorPage number is not required for styles! + MG_ED( "HoriOrientPosition", SVG, X, XML_TYPE_MEASURE, 0 ), + MG_ED( "VertOrientPosition", SVG, Y, XML_TYPE_MEASURE, 0 ), + // ***** The map for automatic styles starts here ***** + // RES_LR_SPACE + MG_E( "LeftMargin", FO, MARGIN, XML_TYPE_MEASURE, CTF_MARGINALL ), + MG_E( "LeftMargin", FO, MARGIN_LEFT, XML_TYPE_MEASURE, CTF_MARGINLEFT ), + MG_E( "RightMargin", FO, MARGIN_RIGHT, XML_TYPE_MEASURE, CTF_MARGINRIGHT ), + // RES_UL_SPACE + MG_E( "TopMargin", FO, MARGIN_TOP, XML_TYPE_MEASURE, CTF_MARGINTOP ), + MG_E( "BottomMargin", FO, MARGIN_BOTTOM, XML_TYPE_MEASURE, CTF_MARGINBOTTOM ), + // RES_PAGEDESC + // not required + // RES_BREAK + // not required + // RES_CNTNT + // not required (accessed using API) + // RES_HEADER + // not required + // RES_FOOTER + // not required + // RES_PRINT + MG_E( "Print", STYLE, PRINT_CONTENT, XML_TYPE_BOOL, 0 ), + // RES_OPAQUE + MG_ED( "Opaque", STYLE, RUN_THROUGH, XML_TYPE_TEXT_OPAQUE, 0 ), + // RES_PROTECT + MG_E( "ContentProtected", STYLE, PROTECT, XML_TYPE_TEXT_PROTECT_CONTENT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_E( "SizeProtected", STYLE, PROTECT, XML_TYPE_TEXT_PROTECT_SIZE|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_E( "PositionProtected", STYLE, PROTECT, XML_TYPE_TEXT_PROTECT_POSITION|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + // RES_SURROUND + MG_ED( "TextWrap", STYLE, WRAP, XML_TYPE_TEXT_WRAP, CTF_WRAP ), + MG_ED( "SurroundAnchorOnly", STYLE, NUMBER_WRAPPED_PARAGRAPHS, XML_TYPE_TEXT_PARAGRAPH_ONLY, CTF_WRAP_PARAGRAPH_ONLY ), + MG_E( "SurroundContour", STYLE, WRAP_CONTOUR, XML_TYPE_BOOL, CTF_WRAP_CONTOUR ), + MG_E( "ContourOutside", STYLE, WRAP_CONTOUR_MODE, XML_TYPE_TEXT_WRAP_OUTSIDE, CTF_WRAP_CONTOUR_MODE ), + // RES_VERT_ORIENT + MG_ED( "VertOrient", STYLE, VERTICAL_POS, XML_TYPE_TEXT_VERTICAL_POS, CTF_VERTICALPOS ), + MG_ED( "VertOrient", STYLE, VERTICAL_POS, XML_TYPE_TEXT_VERTICAL_POS_AT_CHAR, CTF_VERTICALPOS_ATCHAR ), + MG_ED( "VertOrient", STYLE, VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_AS_CHAR|MID_FLAG_MULTI_PROPERTY, CTF_VERTICALREL_ASCHAR ), + MG_ED( "VertOrientRelation", STYLE, VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL, CTF_VERTICALREL ), + MG_ED( "VertOrientRelation", STYLE, VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_PAGE|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_VERTICALREL_PAGE ), + MG_ED( "VertOrientRelation", STYLE, VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_VERTICALREL_FRAME ), + MAP_EXT_I( "VertOrientRelation", XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL|XML_TYPE_PROP_GRAPHIC|MID_FLAG_DEFAULT_ITEM_EXPORT, CTF_VERTICALREL ), + MAP_EXT_I( "VertOrientRelation", XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_PAGE|MID_FLAG_SPECIAL_ITEM_IMPORT|XML_TYPE_PROP_GRAPHIC|MID_FLAG_DEFAULT_ITEM_EXPORT, CTF_VERTICALREL_PAGE ), + MAP_EXT_I( "VertOrientRelation", XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT|XML_TYPE_PROP_GRAPHIC|MID_FLAG_DEFAULT_ITEM_EXPORT, CTF_VERTICALREL_FRAME ), + // RES_HORI_ORIENT + MG_ED( "HoriOrient", STYLE, HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_POS|MID_FLAG_MULTI_PROPERTY, CTF_HORIZONTALPOS ), + MG_ED( "PageToggle", STYLE, HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_MIRROR, CTF_HORIZONTALMIRROR ), + MG_ED( "HoriOrient", STYLE, HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_POS_MIRRORED|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_HORIZONTALPOS_MIRRORED ), + MG_ED( "HoriOrientRelation", STYLE, HORIZONTAL_REL, XML_TYPE_TEXT_HORIZONTAL_REL, CTF_HORIZONTALREL ), + MG_ED( "HoriOrientRelation", STYLE, HORIZONTAL_REL, XML_TYPE_TEXT_HORIZONTAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_HORIZONTALREL_FRAME ), + // RES_ANCHOR + // see above + // RES_BACKGROUND + // DO NOT REORDER these! + MG_ED( "BackColorRGB", FO, BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_ED( "BackTransparent", FO, BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, CTF_BACKGROUND_TRANSPARENT ), + MG_ED( "BackColorTransparency", STYLE, BACKGROUND_TRANSPARENCY, XML_TYPE_PERCENT8, CTF_BACKGROUND_TRANSPARENCY ), + + MG_E( "BackGraphicTransparency", STYLE, BACKGROUND_IMAGE_TRANSPARENCY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_PERCENT8, CTF_BACKGROUND_TRANSPARENCY ), + MG_E( "BackGraphicLocation", STYLE, POSITION, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BUILDIN_CMP_ONLY, CTF_BACKGROUND_POS ), + MG_E( "BackGraphicFilter",STYLE, FILTER_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_BACKGROUND_FILTER ), + MG_E( "BackGraphic", STYLE, BACKGROUND_IMAGE, MID_FLAG_ELEMENT_ITEM|XML_TYPE_GRAPHIC, CTF_BACKGROUND_URL ), + + // fill attributes + GMAP( "FillStyle", XML_NAMESPACE_DRAW, XML_FILL, XML_SW_TYPE_FILLSTYLE, 0 ), + GMAP( "FillColor", XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( "FillColor2", XML_NAMESPACE_DRAW, XML_SECONDARY_FILL_COLOR, XML_TYPE_COLOR, 0 ), + GMAP( "FillGradientName", XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLGRADIENTNAME ), + GMAP( "FillGradientStepCount", XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_TYPE_NUMBER16, 0 ), + GMAP( "FillHatchName", XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLHATCHNAME ), + GMAP( "FillBackground", XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_TYPE_BOOL, 0 ), + GMAP( "FillBitmapName", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLBITMAPNAME ), + GMAP( "FillTransparence", XML_NAMESPACE_DRAW, XML_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // exists in SW, too + GMAP( "FillTransparenceGradientName", XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_TYPE_STYLENAME|MID_FLAG_NO_PROPERTY_IMPORT, CTF_FILLTRANSNAME ), + GMAP( "FillBitmapSizeX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapSizeY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_FILLBITMAPSIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapLogicalSize", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_SW_TYPE_LOGICAL_SIZE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapMode", XML_NAMESPACE_STYLE,XML_REPEAT, XML_SW_TYPE_BITMAP_MODE|MID_FLAG_MULTI_PROPERTY, 0 ), + GMAP( "FillBitmapPositionOffsetX", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_TYPE_PERCENT, 0 ), + GMAP( "FillBitmapPositionOffsetY", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_TYPE_PERCENT, 0 ), + GMAP( "FillBitmapRectanglePoint", XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_SW_TYPE_BITMAP_REFPOINT, 0 ), + GMAP( "FillBitmapOffsetX", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETX|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_X ), + GMAP( "FillBitmapOffsetY", XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_SW_TYPE_BITMAPREPOFFSETY|MID_FLAG_MULTI_PROPERTY, CTF_REPEAT_OFFSET_Y ), + + // RES_BOX + MG_ED( "LeftBorder", STYLE, BORDER_LINE_WIDTH, XML_TYPE_BORDER_WIDTH, CTF_ALLBORDERWIDTH ), + MG_ED( "LeftBorder", STYLE, BORDER_LINE_WIDTH_LEFT, XML_TYPE_BORDER_WIDTH, CTF_LEFTBORDERWIDTH ), + MG_ED( "RightBorder", STYLE, BORDER_LINE_WIDTH_RIGHT, XML_TYPE_BORDER_WIDTH, CTF_RIGHTBORDERWIDTH ), + MG_ED( "TopBorder", STYLE, BORDER_LINE_WIDTH_TOP, XML_TYPE_BORDER_WIDTH, CTF_TOPBORDERWIDTH ), + MG_ED( "BottomBorder", STYLE, BORDER_LINE_WIDTH_BOTTOM, XML_TYPE_BORDER_WIDTH, CTF_BOTTOMBORDERWIDTH ), + + MG_ED( "LeftBorderDistance", FO, PADDING, XML_TYPE_MEASURE, CTF_ALLBORDERDISTANCE ), // need special import filtering + MG_ED( "LeftBorderDistance", FO, PADDING_LEFT, XML_TYPE_MEASURE, CTF_LEFTBORDERDISTANCE ), + MG_ED( "RightBorderDistance", FO, PADDING_RIGHT, XML_TYPE_MEASURE, CTF_RIGHTBORDERDISTANCE ), + MG_ED( "TopBorderDistance", FO, PADDING_TOP, XML_TYPE_MEASURE, CTF_TOPBORDERDISTANCE ), + MG_ED( "BottomBorderDistance",FO, PADDING_BOTTOM, XML_TYPE_MEASURE, CTF_BOTTOMBORDERDISTANCE ), + + // There is an additional property for controls! + MG_ED( "LeftBorder", FO, BORDER, XML_TYPE_BORDER|MID_FLAG_MULTI_PROPERTY, CTF_ALLBORDER ), + MG_ED( "LeftBorder", FO, BORDER_LEFT, XML_TYPE_BORDER, CTF_LEFTBORDER ), + MG_ED( "RightBorder", FO, BORDER_RIGHT, XML_TYPE_BORDER, CTF_RIGHTBORDER ), + MG_ED( "TopBorder", FO, BORDER_TOP, XML_TYPE_BORDER, CTF_TOPBORDER ), + MG_ED( "BottomBorder", FO, BORDER_BOTTOM, XML_TYPE_BORDER, CTF_BOTTOMBORDER ), + // RES_SHADOW + MG_E( "ShadowFormat", STYLE, SHADOW, XML_TYPE_TEXT_SHADOW, 0 ), + MG_E( "ShadowTransparence", DRAW, SHADOW_OPACITY, XML_TYPE_NEG_PERCENT, 0 ), + // RES_FRMMACRO + // TODO + // RES_COL + MG_E( "TextColumns", STYLE, COLUMNS, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_COLUMNS, CTF_TEXTCOLUMNS ), + // RES_KEEP + // not required + // RES_URL + // not required (exported as draw:a element) + // RES_EDIT_IN_READONLY + MG_ED( "EditInReadonly", STYLE, EDITABLE, XML_TYPE_BOOL, 0 ), + // RES_LAYOUT_SPLIT + // not required + // RES_CHAIN + // not required (exported at text:text-box element) + // RES_LINENUMBER + // not required + // RES_FTN_AT_TXTEND + // not required + // RES_END_AT_TXTEND + // not required + // RES_COLUMNBALANCE + // TODO + // RES_UNKNOWNATR_CONTAINER +// M_E_SE( TEXT, xmlns, RES_UNKNOWNATR_CONTAINER, 0 ), + // RES_GRFATR_MIRRORGRF (vertical MUST be processed after horizontal!) + MG_E( "HoriMirroredOnEvenPages", STYLE, MIRROR, XML_TYPE_TEXT_MIRROR_HORIZONTAL_LEFT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_E( "HoriMirroredOnOddPages", STYLE, MIRROR, XML_TYPE_TEXT_MIRROR_HORIZONTAL_RIGHT|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + MG_E( "VertMirrored", STYLE, MIRROR, XML_TYPE_TEXT_MIRROR_VERTICAL|MID_FLAG_MERGE_ATTRIBUTE|MID_FLAG_MULTI_PROPERTY, 0 ), + // RES_GRFATR_CROPGRF + MG_EV( "GraphicCrop", FO, CLIP, XML_TYPE_TEXT_CLIP, CTF_TEXT_CLIP, SvtSaveOptions::ODFSVER_012 ), + MG_E( "GraphicCrop", FO, CLIP, XML_TYPE_TEXT_CLIP11, CTF_TEXT_CLIP11 ), + // RES_GRFATR_ROTATION + // not required (exported as svg:transform attribute) + // RES_GRFATR_LUMINANCE + MG_E( "AdjustLuminance", DRAW, LUMINANCE, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_CONTRAST + MG_E( "AdjustContrast", DRAW, CONTRAST, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_CHANNELR + MG_E( "AdjustRed", DRAW, RED, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_CHANNELG + MG_E( "AdjustGreen", DRAW, GREEN, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_CHANNELB + MG_E( "AdjustBlue", DRAW, BLUE, XML_TYPE_PERCENT16, 0 ), // signed? + // RES_GRFATR_GAMMA + MG_E( "Gamma", DRAW, GAMMA, XML_TYPE_DOUBLE_PERCENT, 0 ), // signed? + // RES_GRFATR_INVERT + MG_E( "GraphicIsInverted", DRAW, COLOR_INVERSION, XML_TYPE_BOOL, 0 ), + // RES_GRFATR_TRANSPARENCY + MG_E( "Transparency", DRAW, IMAGE_OPACITY, XML_TYPE_NEG_PERCENT16|MID_FLAG_MULTI_PROPERTY, 0 ), // #i25616# + // RES_GRFATR_DRAWMODE + MG_E( "GraphicColorMode", DRAW, COLOR_MODE, XML_TYPE_COLOR_MODE, 0 ), + MG_E( "WritingMode", STYLE, WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT, 0 ), + MAP_EXT_I("WritingMode", XML_NAMESPACE_LO_EXT, XML_WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT|XML_TYPE_PROP_GRAPHIC, 0), + // RES_FOLLOW_TEXT_FLOW - DVO #i18732# + MG_E( "IsFollowingTextFlow", DRAW, FLOW_WITH_TEXT, XML_TYPE_BOOL|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_OLD_FLOW_WITH_TEXT ), + MG_E( "IsFollowingTextFlow", STYLE, FLOW_WITH_TEXT, XML_TYPE_BOOL, 0 ), + // #i28701# - RES_WRAP_INFLUENCE_ON_OBJPOS + MG_E( "WrapInfluenceOnPosition", DRAW, WRAP_INFLUENCE_ON_POSITION, XML_TYPE_WRAP_INFLUENCE_ON_POSITION, 0 ), + MAP_EXT("AllowOverlap", XML_NAMESPACE_LO_EXT, XML_ALLOW_OVERLAP, XML_TYPE_BOOL|XML_TYPE_PROP_GRAPHIC, 0), + + // special entries for floating frames + MG_E( "", DRAW, FRAME_DISPLAY_SCROLLBAR, XML_TYPE_BOOL|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_DISPLAY_SCROLLBAR ), + MG_E( "", DRAW, FRAME_DISPLAY_BORDER, XML_TYPE_BOOL|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_DISPLAY_BORDER ), + MG_E( "", DRAW, FRAME_MARGIN_HORIZONTAL, XML_TYPE_MEASURE_PX|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_MARGIN_HORI ), + MG_E( "", DRAW, FRAME_MARGIN_VERTICAL, XML_TYPE_MEASURE_PX|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_FRAME_MARGIN_VERT ), + MG_E( "", DRAW, VISIBLE_AREA_LEFT, XML_TYPE_MEASURE|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_VIS_AREA_LEFT ), + MG_E( "", DRAW, VISIBLE_AREA_TOP, XML_TYPE_MEASURE|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_VIS_AREA_TOP ), + MG_E( "", DRAW, VISIBLE_AREA_WIDTH, XML_TYPE_MEASURE|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_VIS_AREA_WIDTH ), + MG_E( "", DRAW, VISIBLE_AREA_HEIGHT, XML_TYPE_MEASURE|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_VIS_AREA_HEIGHT ), + MG_E( "", DRAW, DRAW_ASPECT, XML_TYPE_TEXT_DRAW_ASPECT|MID_FLAG_NO_PROPERTY|MID_FLAG_MULTI_PROPERTY, CTF_OLE_DRAW_ASPECT ), + MG_E( "UserDefinedAttributes", TEXT, XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + MAP_EXT("RelativeWidthRelation", XML_NAMESPACE_LO_EXT, XML_REL_WIDTH_REL, XML_TYPE_TEXT_HORIZONTAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_RELWIDTHREL), + MAP_EXT("RelativeHeightRelation", XML_NAMESPACE_LO_EXT, XML_REL_HEIGHT_REL, XML_TYPE_TEXT_VERTICAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_RELHEIGHTREL), + MG_E("TextVerticalAdjust", DRAW, TEXTAREA_VERTICAL_ALIGN, XML_TYPE_VERTICAL_ALIGN, 0), + + M_END() +}; + +XMLPropertyMapEntry const aXMLShapePropMap[] = +{ + // RES_LR_SPACE + MG_E( "LeftMargin", FO, MARGIN_LEFT, XML_TYPE_MEASURE, 0), + MG_E( "RightMargin", FO, MARGIN_RIGHT, XML_TYPE_MEASURE, 0 ), + // RES_UL_SPACE + MG_E( "TopMargin", FO, MARGIN_TOP, XML_TYPE_MEASURE, 0 ), + MG_E( "BottomMargin", FO, MARGIN_BOTTOM, XML_TYPE_MEASURE, 0 ), + // RES_OPAQUE + MG_ED( "Opaque", STYLE, RUN_THROUGH, XML_TYPE_TEXT_OPAQUE, 0 ), + // RES_SURROUND + MG_E( "TextWrap", STYLE, WRAP, XML_TYPE_TEXT_WRAP, CTF_WRAP ), + MG_E( "SurroundAnchorOnly", STYLE, NUMBER_WRAPPED_PARAGRAPHS, XML_TYPE_TEXT_PARAGRAPH_ONLY, CTF_WRAP_PARAGRAPH_ONLY ), + MG_E( "SurroundContour", STYLE, WRAP_CONTOUR, XML_TYPE_BOOL, CTF_WRAP_CONTOUR ), + MG_E( "ContourOutside", STYLE, WRAP_CONTOUR_MODE, XML_TYPE_TEXT_WRAP_OUTSIDE, CTF_WRAP_CONTOUR_MODE ), + // Use own CTF ids for positioning attributes (#i28749#) + // RES_VERT_ORIENT + MG_E( "VertOrient", STYLE, VERTICAL_POS, XML_TYPE_TEXT_VERTICAL_POS, CTF_SHAPE_VERTICALPOS ), + // Add property for at-character anchored shapes (#i26791#) + MG_E( "VertOrient", STYLE, VERTICAL_POS, XML_TYPE_TEXT_VERTICAL_POS_AT_CHAR, CTF_SHAPE_VERTICALPOS_ATCHAR ), + MG_E( "VertOrient", STYLE, VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_AS_CHAR|MID_FLAG_MULTI_PROPERTY, CTF_VERTICALREL_ASCHAR ), + MG_E( "VertOrientRelation", STYLE, VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL, CTF_SHAPE_VERTICALREL ), + MG_E( "VertOrientRelation", STYLE, VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_PAGE|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SHAPE_VERTICALREL_PAGE ), + MG_E( "VertOrientRelation", STYLE, VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SHAPE_VERTICALREL_FRAME ), + MAP_EXT_I( "VertOrientRelation", XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_VERTICALREL ), + MAP_EXT_I( "VertOrientRelation", XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_PAGE|MID_FLAG_SPECIAL_ITEM_IMPORT|XML_TYPE_PROP_GRAPHIC, CTF_VERTICALREL_PAGE ), + MAP_EXT_I( "VertOrientRelation", XML_NAMESPACE_LO_EXT, XML_VERTICAL_REL, XML_TYPE_TEXT_VERTICAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT|XML_TYPE_PROP_GRAPHIC, CTF_VERTICALREL_FRAME ), + // RES_HORI_ORIENT + MG_E( "HoriOrient", STYLE, HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_POS|MID_FLAG_MULTI_PROPERTY, CTF_SHAPE_HORIZONTALPOS ), + MG_E( "PageToggle", STYLE, HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_MIRROR, CTF_SHAPE_HORIZONTALMIRROR ), + MG_E( "HoriOrient", STYLE, HORIZONTAL_POS, XML_TYPE_TEXT_HORIZONTAL_POS_MIRRORED|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SHAPE_HORIZONTALPOS_MIRRORED ), + MG_E( "HoriOrientRelation", STYLE, HORIZONTAL_REL, XML_TYPE_TEXT_HORIZONTAL_REL, CTF_SHAPE_HORIZONTALREL ), + MG_E( "HoriOrientRelation", STYLE, HORIZONTAL_REL, XML_TYPE_TEXT_HORIZONTAL_REL_FRAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_SHAPE_HORIZONTALREL_FRAME ), + // RES_WRAP_INFLUENCE_ON_OBJPOS (#i28701#) + MG_ED( "WrapInfluenceOnPosition", DRAW, WRAP_INFLUENCE_ON_POSITION, XML_TYPE_WRAP_INFLUENCE_ON_POSITION, 0 ), + MAP_EXT("AllowOverlap", XML_NAMESPACE_LO_EXT, XML_ALLOW_OVERLAP, XML_TYPE_BOOL|XML_TYPE_PROP_GRAPHIC, 0), + // UserDefinedAttributes is already contained in the map this one is + // chained to. + + // RES_FOLLOW_TEXT_FLOW (#i26791#) + MG_ED( "IsFollowingTextFlow", STYLE, FLOW_WITH_TEXT, XML_TYPE_BOOL, 0 ), + + // RES_FRM_SIZE + MAP_EXT("RelativeWidthRelation", XML_NAMESPACE_LO_EXT, XML_REL_WIDTH_REL, XML_TYPE_TEXT_HORIZONTAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_RELWIDTHREL), + MAP_EXT("RelativeHeightRelation", XML_NAMESPACE_LO_EXT, XML_REL_HEIGHT_REL, XML_TYPE_TEXT_VERTICAL_REL|XML_TYPE_PROP_GRAPHIC, CTF_RELHEIGHTREL), + + M_END() +}; + +XMLPropertyMapEntry const aXMLSectionPropMap[] = +{ + // RES_COL + MS_E( "TextColumns", STYLE, COLUMNS, MID_FLAG_ELEMENT_ITEM|XML_TYPE_TEXT_COLUMNS, CTF_TEXTCOLUMNS ), + + // RES_BACKGROUND + // DO NOT REORDER these! + MS_E( "BackColor", FO, BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, 0 ), + MS_E( "BackTransparent", FO, BACKGROUND_COLOR, XML_TYPE_ISTRANSPARENT|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + MS_E( "BackGraphicLocation", STYLE, POSITION, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BUILDIN_CMP_ONLY, CTF_BACKGROUND_POS ), + MS_E( "BackGraphicFilter",STYLE, FILTER_NAME, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_BACKGROUND_FILTER ), + MS_E( "BackGraphic", STYLE, BACKGROUND_IMAGE, MID_FLAG_ELEMENT_ITEM|XML_TYPE_GRAPHIC, CTF_BACKGROUND_URL ), + + // move protect-flag into section element +// M_E( "IsProtected", STYLE, PROTECT, XML_TYPE_BOOL, 0 ), + + MS_E( "DontBalanceTextColumns", TEXT, DONT_BALANCE_TEXT_COLUMNS, XML_TYPE_BOOL, 0 ), + + MS_E( "WritingMode", STYLE, WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT, 0 ), + + MS_E( "SectionLeftMargin", FO, MARGIN_LEFT, XML_TYPE_MEASURE, 0), + MS_E( "SectionRightMargin", FO, MARGIN_RIGHT, XML_TYPE_MEASURE, 0), + + // section footnote settings + MS_E( "FootnoteIsOwnNumbering", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_SECTION_FOOTNOTE_NUM_OWN ), + MS_E( "FootnoteIsRestartNumbering", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_SECTION_FOOTNOTE_NUM_RESTART ), + MS_E( "FootnoteRestartNumberingAt", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_NUMBER16,CTF_SECTION_FOOTNOTE_NUM_RESTART_AT ), + MS_E( "FootnoteNumberingType", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_NUMBER16,CTF_SECTION_FOOTNOTE_NUM_TYPE ), + MS_E( "FootnoteNumberingPrefix", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_SECTION_FOOTNOTE_NUM_PREFIX ), + MS_E( "FootnoteNumberingSuffix", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_SECTION_FOOTNOTE_NUM_SUFFIX ), + MS_E( "FootnoteIsCollectAtTextEnd", TEXT, NOTES_CONFIGURATION, MID_FLAG_ELEMENT_ITEM|XML_TYPE_BOOL, CTF_SECTION_FOOTNOTE_END ), + + // section footnote settings + MS_E( "EndnoteIsOwnNumbering", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_SECTION_ENDNOTE_NUM_OWN ), + MS_E( "EndnoteIsRestartNumbering", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_BOOL, CTF_SECTION_ENDNOTE_NUM_RESTART ), + MS_E( "EndnoteRestartNumberingAt", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_NUMBER16,CTF_SECTION_ENDNOTE_NUM_RESTART_AT ), + MS_E( "EndnoteNumberingType", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_NUMBER16,CTF_SECTION_ENDNOTE_NUM_TYPE ), + MS_E( "EndnoteNumberingPrefix", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_SECTION_ENDNOTE_NUM_PREFIX ), + MS_E( "EndnoteNumberingSuffix", TEXT, _EMPTY, MID_FLAG_SPECIAL_ITEM|XML_TYPE_STRING, CTF_SECTION_ENDNOTE_NUM_SUFFIX ), + MS_E( "EndnoteIsCollectAtTextEnd", TEXT, NOTES_CONFIGURATION, MID_FLAG_ELEMENT_ITEM|XML_TYPE_BOOL, CTF_SECTION_ENDNOTE_END ), + MS_E( "UserDefinedAttributes", TEXT, XMLNS, XML_TYPE_ATTRIBUTE_CONTAINER | MID_FLAG_SPECIAL_ITEM, 0 ), + // RES_EDIT_IN_READONLY + MS_E( "EditInReadonly", STYLE, EDITABLE, XML_TYPE_BOOL, 0 ), + M_END() +}; + +XMLPropertyMapEntry const aXMLRubyPropMap[] = +{ + MR_E( "RubyAdjust", STYLE, RUBY_ALIGN, XML_TYPE_TEXT_RUBY_ADJUST, 0 ), + MR_E( "RubyIsAbove", STYLE, RUBY_POSITION, XML_TYPE_TEXT_RUBY_IS_ABOVE, 0 ), + MR_EV( "RubyPosition", LO_EXT, RUBY_POSITION, XML_TYPE_TEXT_RUBY_POSITION, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED), + M_END() +}; + + +XMLPropertyMapEntry const aXMLTableDefaultsMap[] = +{ + // RES_COLLAPSING_BORDERS: only occurs in tables, but we need to + // read/write the default for this item + M_ED_( "CollapsingBorders", TABLE, BORDER_MODEL, XML_TYPE_PROP_TABLE | XML_TYPE_BORDER_MODEL | MID_FLAG_NO_PROPERTY_IMPORT, CTF_BORDER_MODEL ), + + M_END() +}; + +XMLPropertyMapEntry const aXMLTableRowDefaultsMap[] = +{ + // RES_ROW_SPLIT: only occurs in table rows, but we need to + // read/write the default for this item + M_ED_( "IsSplitAllowed", FO, KEEP_TOGETHER, XML_TYPE_PROP_TABLE_ROW | XML_TYPE_TEXT_NKEEP | MID_FLAG_NO_PROPERTY_IMPORT, CTF_KEEP_TOGETHER ), + + M_END() +}; + +XMLPropertyMapEntry const aXMLCellPropMap[] = +{ + MC_E( "BackColor", FO, BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( "LeftBorder", FO, BORDER_LEFT, XML_TYPE_BORDER, 0 ), + MC_E( "RightBorder", FO, BORDER_RIGHT, XML_TYPE_BORDER, 0 ), + MC_E( "TopBorder", FO, BORDER_TOP, XML_TYPE_BORDER, 0 ), + MC_E( "BottomBorder", FO, BORDER_BOTTOM, XML_TYPE_BORDER, 0 ), + MC_E( "BorderDistance", FO, PADDING, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( "LeftBorderDistance", FO, PADDING_LEFT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( "RightBorderDistance", FO, PADDING_RIGHT, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( "TopBorderDistance", FO, PADDING_TOP, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( "BottomBorderDistance", FO, PADDING_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_MULTI_PROPERTY, 0 ), + MC_E( "VertOrient", STYLE, VERTICAL_ALIGN, XML_TYPE_TEXT_VERTICAL_POS, 0 ), + MC_E( "WritingMode", STYLE, WRITING_MODE, XML_TYPE_TEXT_WRITING_MODE_WITH_DEFAULT, 0 ), + MC_E( "NumberFormat", STYLE, DATA_STYLE_NAME, XML_TYPE_NUMBER|MID_FLAG_SPECIAL_ITEM_EXPORT, 0 ), + // paragraph properties + MP_E( "ParaAdjust", FO, TEXT_ALIGN, XML_TYPE_TEXT_ADJUST, 0 ), + // text properties + MT_ED( "CharColor", FO, COLOR, XML_TYPE_COLORAUTO|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_ED( "CharColor", STYLE, USE_WINDOW_FONT_COLOR, XML_TYPE_ISAUTOCOLOR|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharShadowed", FO, TEXT_SHADOW, XML_TYPE_TEXT_SHADOWED, 0 ), + MT_E( "CharContoured", STYLE, TEXT_OUTLINE, XML_TYPE_BOOL, 0 ), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_STYLE, XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_TYPE, XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_WIDTH, XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharStrikeout", STYLE, TEXT_LINE_THROUGH_TEXT, XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharUnderline", STYLE, TEXT_UNDERLINE_STYLE, XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharUnderline", STYLE, TEXT_UNDERLINE_TYPE, XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharUnderline", STYLE, TEXT_UNDERLINE_WIDTH, XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MT_E( "CharUnderlineColor", STYLE, TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( "CharUnderlineHasColor",STYLE, TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + // STANDARD FONT + MT_ED( "CharHeight", FO, FONT_SIZE, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( "CharWeight", FO, FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + MT_E( "CharPosture", FO, FONT_STYLE, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_FONT + MT_ED( "CharFontName", STYLE, FONT_NAME, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME ), + MT_ED( "CharFontName", FO, FONT_FAMILY, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME ), + MT_ED( "CharFontStyleName", STYLE, FONT_STYLE_NAME, XML_TYPE_STRING, CTF_FONTSTYLENAME ), + MT_ED( "CharFontFamily", STYLE, FONT_FAMILY_GENERIC,XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY ), + MT_ED( "CharFontPitch", STYLE, FONT_PITCH, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH ), + MT_ED( "CharFontCharSet", STYLE, FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET ), + // CJK FONT + MT_ED( "CharHeightAsian", STYLE, FONT_SIZE_ASIAN, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( "CharWeightAsian", STYLE, FONT_WEIGHT_ASIAN, XML_TYPE_TEXT_WEIGHT, 0 ), + MT_E( "CharPostureAsian", STYLE, FONT_STYLE_ASIAN, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CJK_FONT + MT_ED( "CharFontNameAsian", STYLE, FONT_NAME_ASIAN, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CJK ), + MT_ED( "CharFontNameAsian", STYLE, FONT_FAMILY_ASIAN, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CJK ), + MT_ED( "CharFontStyleNameAsian", STYLE, FONT_STYLE_NAME_ASIAN, XML_TYPE_STRING, CTF_FONTSTYLENAME_CJK ), + MT_ED( "CharFontFamilyAsian", STYLE, FONT_FAMILY_GENERIC_ASIAN, XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CJK ), + MT_ED( "CharFontPitchAsian", STYLE, FONT_PITCH_ASIAN, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CJK ), + MT_ED( "CharFontCharSetAsian", STYLE, FONT_CHARSET_ASIAN, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CJK ), + // CTL FONT + MT_ED( "CharHeightComplex", STYLE, FONT_SIZE_COMPLEX, XML_TYPE_CHAR_HEIGHT|MID_FLAG_MULTI_PROPERTY, 0 ), + MT_E( "CharWeightComplex", STYLE, FONT_WEIGHT_COMPLEX, XML_TYPE_TEXT_WEIGHT, 0 ), + MT_E( "CharPostureComplex", STYLE, FONT_STYLE_COMPLEX, XML_TYPE_TEXT_POSTURE, 0 ), + // RES_CHRATR_CTL_FONT + MT_ED( "CharFontNameComplex", STYLE, FONT_NAME_COMPLEX, XML_TYPE_STRING|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTNAME_CTL ), + MT_ED( "CharFontNameComplex", STYLE, FONT_FAMILY_COMPLEX, XML_TYPE_TEXT_FONTFAMILYNAME|MID_FLAG_SPECIAL_ITEM_IMPORT, CTF_FONTFAMILYNAME_CTL ), + MT_ED( "CharFontStyleNameComplex",STYLE, FONT_STYLE_NAME_COMPLEX, XML_TYPE_STRING, CTF_FONTSTYLENAME_CTL ), + MT_ED( "CharFontFamilyComplex", STYLE, FONT_FAMILY_GENERIC_COMPLEX,XML_TYPE_TEXT_FONTFAMILY, CTF_FONTFAMILY_CTL ), + MT_ED( "CharFontPitchComplex", STYLE, FONT_PITCH_COMPLEX, XML_TYPE_TEXT_FONTPITCH, CTF_FONTPITCH_CTL ), + MT_ED( "CharFontCharSetComplex", STYLE, FONT_CHARSET_COMPLEX, XML_TYPE_TEXT_FONTENCODING, CTF_FONTCHARSET_CTL ), + + M_END() +}; + +static XMLPropertyMapEntry const *lcl_txtprmap_getMap( TextPropMap nType ) +{ + XMLPropertyMapEntry const *pMap = nullptr; + switch( nType ) + { + case TextPropMap::TEXT: + pMap = aXMLTextPropMap; + break; + case TextPropMap::SHAPE_PARA: + // #i125045# use [21] instead of [1] for text props for Shapes, indices + // [1..20] contain the DrawingLayer FillStyle attributes corresponding to + // [XATTR_FILL_FIRST .. XATTR_FILL_LAST] and would be double since Shapes + // already contain these (usually in aXMLSDProperties) + pMap = &(aXMLParaPropMap[21]); + assert( pMap->meXMLName == XML_MARGIN && " shape para map changed" ); + break; + case TextPropMap::PARA: + pMap = aXMLParaPropMap; + break; + case TextPropMap::FRAME: + pMap = aXMLFramePropMap; + break; + case TextPropMap::AUTO_FRAME: + pMap = &(aXMLFramePropMap[13]); + assert( pMap->meXMLName == XML_MARGIN && " frame map changed" ); + break; + case TextPropMap::SHAPE: + pMap = aXMLShapePropMap; + break; + case TextPropMap::SECTION: + pMap = aXMLSectionPropMap; + break; + case TextPropMap::RUBY: + pMap = aXMLRubyPropMap; + break; + case TextPropMap::TEXT_ADDITIONAL_DEFAULTS: + pMap = aXMLAdditionalTextDefaultsMap; + break; + case TextPropMap::TABLE_DEFAULTS: + pMap = aXMLTableDefaultsMap; + break; + case TextPropMap::TABLE_ROW_DEFAULTS: + pMap = aXMLTableRowDefaultsMap; + break; + case TextPropMap::CELL: + pMap = aXMLCellPropMap; + break; + } + SAL_WARN_IF( !pMap, "xmloff", "illegal map type" ); + return pMap; +} + +const XMLPropertyMapEntry* XMLTextPropertySetMapper::getPropertyMapForType( TextPropMap _nType ) +{ + return lcl_txtprmap_getMap( _nType ); +} + +XMLTextPropertySetMapper::XMLTextPropertySetMapper( TextPropMap nType, bool bForExport ) : + XMLPropertySetMapper( lcl_txtprmap_getMap( nType ), + new XMLTextPropertyHandlerFactory, bForExport ) +{ +} + +XMLTextPropertySetMapper::~XMLTextPropertySetMapper() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtsecte.cxx b/xmloff/source/text/txtsecte.cxx new file mode 100644 index 000000000..9f27040ec --- /dev/null +++ b/xmloff/source/text/txtsecte.cxx @@ -0,0 +1,204 @@ +/* -*- 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 + +#include + +#include +#include +#include "XMLTextNumRuleInfo.hxx" +#include "XMLSectionExport.hxx" +#include "XMLRedlineExport.hxx" +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::uno; +using namespace ::std; + +using ::com::sun::star::beans::XPropertySet; + +void XMLTextParagraphExport::exportListAndSectionChange( + Reference & rPrevSection, + const Reference & rNextSectionContent, + const XMLTextNumRuleInfo& rPrevRule, + const XMLTextNumRuleInfo& rNextRule, + bool bAutoStyles) +{ + Reference xNextSection; + + // first: get current XTextSection + Reference xPropSet(rNextSectionContent, UNO_QUERY); + if (xPropSet.is()) + { + if (xPropSet->getPropertySetInfo()->hasPropertyByName(gsTextSection)) + { + xPropSet->getPropertyValue(gsTextSection) >>= xNextSection; + } + // else: no current section + } + + exportListAndSectionChange(rPrevSection, xNextSection, + rPrevRule, rNextRule, bAutoStyles); +} + +void XMLTextParagraphExport::exportListAndSectionChange( + Reference & rPrevSection, + MultiPropertySetHelper& rPropSetHelper, + sal_Int16 nTextSectionId, + const Reference & rNextSectionContent, + const XMLTextNumRuleInfo& rPrevRule, + const XMLTextNumRuleInfo& rNextRule, + bool bAutoStyles) +{ + Reference xNextSection; + + // first: get current XTextSection + Reference xPropSet(rNextSectionContent, UNO_QUERY); + if (xPropSet.is()) + { + if( !rPropSetHelper.checkedProperties() ) + rPropSetHelper.hasProperties( xPropSet->getPropertySetInfo() ); + if( rPropSetHelper.hasProperty( nTextSectionId )) + { + xNextSection.set(rPropSetHelper.getValue( nTextSectionId , xPropSet, + true ), uno::UNO_QUERY); + } + // else: no current section + } + + exportListAndSectionChange(rPrevSection, xNextSection, + rPrevRule, rNextRule, bAutoStyles); +} + +void XMLTextParagraphExport::exportListAndSectionChange( + Reference & rPrevSection, + const Reference & rNextSection, + const XMLTextNumRuleInfo& rPrevRule, + const XMLTextNumRuleInfo& rNextRule, + bool bAutoStyles) +{ + // old != new? -> maybe we have to start or end a new section + if (rPrevSection != rNextSection) + { + // a new section started, or an old one gets closed! + + // close old list + XMLTextNumRuleInfo aEmptyNumRuleInfo; + if ( !bAutoStyles ) + exportListChange(rPrevRule, aEmptyNumRuleInfo); + + // Build stacks of old and new sections + // Sections on top of mute sections should not be on the stack + vector< Reference > aOldStack; + Reference aCurrent(rPrevSection); + while(aCurrent.is()) + { + // if we have a mute section, ignore all its children + // (all previous ones) + if (pSectionExport->IsMuteSection(aCurrent)) + aOldStack.clear(); + + aOldStack.push_back(aCurrent); + aCurrent.set(aCurrent->getParentSection()); + } + + vector< Reference > aNewStack; + aCurrent.set(rNextSection); + bool bMute = false; + while(aCurrent.is()) + { + // if we have a mute section, ignore all its children + // (all previous ones) + if (pSectionExport->IsMuteSection(aCurrent)) + { + aNewStack.clear(); + bMute = true; + } + + aNewStack.push_back(aCurrent); + aCurrent.set(aCurrent->getParentSection()); + } + + // compare the two stacks + vector > ::reverse_iterator aOld = + aOldStack.rbegin(); + vector > ::reverse_iterator aNew = + aNewStack.rbegin(); + // compare bottom sections and skip equal section + while ( (aOld != aOldStack.rend()) && + (aNew != aNewStack.rend()) && + (*aOld) == (*aNew) ) + { + ++aOld; + ++aNew; + } + + // close all elements of aOld ... + // (order: newest to oldest) + if (aOld != aOldStack.rend()) + { + vector > ::iterator aOldForward( + aOldStack.begin()); + while ((aOldForward != aOldStack.end()) && + (*aOldForward != *aOld)) + { + if ( !bAutoStyles && (nullptr != pRedlineExport) ) + pRedlineExport->ExportStartOrEndRedline(*aOldForward, + false); + pSectionExport->ExportSectionEnd(*aOldForward, bAutoStyles); + ++aOldForward; + } + if (aOldForward != aOldStack.end()) + { + if ( !bAutoStyles && (nullptr != pRedlineExport) ) + pRedlineExport->ExportStartOrEndRedline(*aOldForward, + false); + pSectionExport->ExportSectionEnd(*aOldForward, bAutoStyles); + } + } + + // ...then open all of aNew + // (order: oldest to newest) + while (aNew != aNewStack.rend()) + { + if ( !bAutoStyles && (nullptr != pRedlineExport) ) + pRedlineExport->ExportStartOrEndRedline(*aNew, true); + pSectionExport->ExportSectionStart(*aNew, bAutoStyles); + ++aNew; + } + + // start new list + if ( !bAutoStyles && !bMute ) + exportListChange(aEmptyNumRuleInfo, rNextRule); + } + else + { + // list change, if sections have not changed + if ( !bAutoStyles ) + exportListChange(rPrevRule, rNextRule); + } + + // save old section (old numRule gets saved in calling method) + rPrevSection.set(rNextSection); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtstyle.cxx b/xmloff/source/text/txtstyle.cxx new file mode 100644 index 000000000..fd04a925b --- /dev/null +++ b/xmloff/source/text/txtstyle.cxx @@ -0,0 +1,164 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "XMLSectionExport.hxx" +#include "XMLLineNumberingExport.hxx" +#include "txtexppr.hxx" +#include + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::beans; +using namespace ::xmloff::token; + +void XMLTextParagraphExport::exportStyleAttributes( + const css::uno::Reference< css::style::XStyle > & rStyle ) +{ + Reference< XPropertySet > xPropSet( rStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo( + xPropSet->getPropertySetInfo()); + if( xPropSetInfo->hasPropertyByName( gsCategory ) ) + { + sal_Int16 nCategory = 0; + xPropSet->getPropertyValue( gsCategory ) >>= nCategory; + enum XMLTokenEnum eValue = XML_TOKEN_INVALID; + if( -1 != nCategory ) + { + switch( nCategory ) + { + case ParagraphStyleCategory::TEXT: + eValue = XML_TEXT; + break; + case ParagraphStyleCategory::CHAPTER: + eValue = XML_CHAPTER; + break; + case ParagraphStyleCategory::LIST: + eValue = XML_LIST; + break; + case ParagraphStyleCategory::INDEX: + eValue = XML_INDEX; + break; + case ParagraphStyleCategory::EXTRA: + eValue = XML_EXTRA; + break; + case ParagraphStyleCategory::HTML: + eValue = XML_HTML; + break; + } + } + if( eValue != XML_TOKEN_INVALID ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, XML_CLASS, eValue); + } + if( xPropSetInfo->hasPropertyByName( gsPageDescName ) ) + { + Reference< XPropertyState > xPropState( xPropSet, uno::UNO_QUERY ); + if( PropertyState_DIRECT_VALUE == + xPropState->getPropertyState( gsPageDescName ) ) + { + OUString sName; + xPropSet->getPropertyValue( gsPageDescName ) >>= sName; + // fix for #i5551# if( sName.getLength() > 0 ) + GetExport().AddAttribute( XML_NAMESPACE_STYLE, + XML_MASTER_PAGE_NAME, + GetExport().EncodeStyleName( sName ) ); + } + } + if( bProgress ) + { + ProgressBarHelper *pProgress = GetExport().GetProgressBarHelper(); + pProgress->SetValue( pProgress->GetValue()+2 ); + } +} + +void XMLTextParagraphExport::exportNumStyles( bool bUsed ) +{ + SvxXMLNumRuleExport aNumRuleExport( GetExport() ); + aNumRuleExport.exportStyles( bUsed, &maListAutoPool, !IsBlockMode() ); +} + +void XMLTextParagraphExport::exportTextStyles( bool bUsed, bool bProg ) +{ + bool bOldProg = bProgress; + bProgress = bProg; + + Reference < lang::XMultiServiceFactory > xFactory (GetExport().GetModel(), UNO_QUERY); + if (xFactory.is()) + { + Reference < XPropertySet > xPropSet (xFactory->createInstance ( "com.sun.star.text.Defaults" ), UNO_QUERY); + if (xPropSet.is()) + { + exportDefaultStyle( xPropSet, GetXMLToken(XML_PARAGRAPH), GetParaPropMapper()); + + exportDefaultStyle( + xPropSet, + GetXMLToken(XML_TABLE), + new XMLTextExportPropertySetMapper( + new XMLTextPropertySetMapper( + TextPropMap::TABLE_DEFAULTS, true ), + GetExport() ) ); + + exportDefaultStyle( + xPropSet, + GetXMLToken(XML_TABLE_ROW), + new XMLTextExportPropertySetMapper( + new XMLTextPropertySetMapper( + TextPropMap::TABLE_ROW_DEFAULTS, true ), + GetExport() ) ); + } + } + exportStyleFamily( "ParagraphStyles", GetXMLToken(XML_PARAGRAPH), GetParaPropMapper(), + bUsed, XmlStyleFamily::TEXT_PARAGRAPH); + exportStyleFamily( "CharacterStyles", GetXMLToken(XML_TEXT), GetTextPropMapper(), + bUsed, XmlStyleFamily::TEXT_TEXT ); + // get shape export to make sure the frame family is added correctly. + GetExport().GetShapeExport(); + exportStyleFamily( "FrameStyles", OUString(XML_STYLE_FAMILY_SD_GRAPHICS_NAME), xFramePropMapper, + bUsed, XmlStyleFamily::TEXT_FRAME); + exportNumStyles( bUsed ); + if( !IsBlockMode() ) + { + exportTextFootnoteConfiguration(); + XMLSectionExport::ExportBibliographyConfiguration(GetExport()); + XMLLineNumberingExport aLineNumberingExport(GetExport()); + aLineNumberingExport.Export(); + } + + bProgress = bOldProg; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtstyli.cxx b/xmloff/source/text/txtstyli.cxx new file mode 100644 index 000000000..f64199e05 --- /dev/null +++ b/xmloff/source/text/txtstyli.cxx @@ -0,0 +1,634 @@ +/* -*- 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 "XMLTextPropertySetContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +#include +#include + + +using namespace ::std; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::container; +using namespace ::xmloff::token; + +const SvXMLEnumMapEntry aCategoryMap[] = +{ + { XML_TEXT, ParagraphStyleCategory::TEXT }, + { XML_CHAPTER, ParagraphStyleCategory::CHAPTER }, + { XML_LIST, ParagraphStyleCategory::LIST }, + { XML_INDEX, ParagraphStyleCategory::INDEX }, + { XML_EXTRA, ParagraphStyleCategory::EXTRA }, + { XML_HTML, ParagraphStyleCategory::HTML }, + { XML_TOKEN_INVALID, 0 } +}; + +void XMLTextStyleContext::SetAttribute( sal_Int32 nElement, + const OUString& rValue ) +{ + switch (nElement) + { + case XML_ELEMENT(STYLE, XML_AUTO_UPDATE): + { + if( IsXMLToken( rValue, XML_TRUE ) ) + m_isAutoUpdate = true; + break; + } + case XML_ELEMENT(STYLE, XML_LIST_STYLE_NAME): + { + m_sListStyleName = rValue; + // Inherited paragraph style lost information about unset numbering (#i69523#) + m_bListStyleSet = true; + break; + } + case XML_ELEMENT(STYLE, XML_MASTER_PAGE_NAME): + { + m_sMasterPageName = rValue; + m_bHasMasterPageName = true; + break; + } + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + m_sDataStyleName = rValue; + break; + case XML_ELEMENT(STYLE, XML_CLASS): + m_sCategoryVal = rValue; + break; + case XML_ELEMENT(STYLE, XML_DEFAULT_OUTLINE_LEVEL): + { + sal_Int32 nTmp; + if (::sax::Converter::convertNumber( nTmp, rValue ) && + 0 <= nTmp && nTmp <= 10 ) + { + m_nOutlineLevel = static_cast(nTmp); + } + break; + } + case XML_ELEMENT(STYLE, XML_LIST_LEVEL): + { + sal_Int32 nTmp; + // The spec is positiveInteger (1-based), but the implementation is 0-based. + if (sax::Converter::convertNumber(nTmp, rValue) && nTmp > 0 && nTmp <= 10) + { + m_aListLevel.emplace(--nTmp); + } + break; + } + default: + XMLPropStyleContext::SetAttribute( nElement, rValue ); + } +} + +XMLTextStyleContext::XMLTextStyleContext( SvXMLImport& rImport, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily, + bool bDefaultStyle ) +: XMLPropStyleContext( rImport, rStyles, nFamily, bDefaultStyle ) +, m_nOutlineLevel( -1 ) +, m_isAutoUpdate( false ) +, m_bHasMasterPageName( false ) +, m_bHasCombinedCharactersLetter( false ) +// Inherited paragraph style lost information about unset numbering (#i69523#) +, m_bListStyleSet( false ) +{ +} + +XMLTextStyleContext::~XMLTextStyleContext() +{} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTextStyleContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_STYLE) ) + { + sal_Int32 nLocalName = nElement & TOKEN_MASK; + sal_uInt32 nFamily = 0; + if( nLocalName == XML_TEXT_PROPERTIES ) + nFamily = XML_TYPE_PROP_TEXT; + else if( nLocalName == XML_PARAGRAPH_PROPERTIES ) + nFamily = XML_TYPE_PROP_PARAGRAPH; + else if( nLocalName == XML_SECTION_PROPERTIES ) + nFamily = XML_TYPE_PROP_SECTION; + else if( IsDefaultStyle() && nLocalName == XML_TABLE_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE; + else if( IsDefaultStyle() && nLocalName == XML_TABLE_ROW_PROPERTIES ) + nFamily = XML_TYPE_PROP_TABLE_ROW; + if( nFamily ) + { + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = + GetStyles()->GetImportPropertyMapper( GetFamily() ); + if( xImpPrMap.is() ) + return new XMLTextPropertySetContext( GetImport(), nElement, xAttrList, + nFamily, + GetProperties(), + xImpPrMap, + m_sDropCapTextStyleName); + } + } + else if ( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + // create and remember events import context + // (for delayed processing of events) + m_xEventContext.set(new XMLEventsImportContext( GetImport() )); + return m_xEventContext; + } + + return XMLPropStyleContext::createFastChildContext( nElement, xAttrList ); +} + +void XMLTextStyleContext::CreateAndInsert( bool bOverwrite ) +{ + XMLPropStyleContext::CreateAndInsert( bOverwrite ); + Reference < XStyle > xStyle = GetStyle(); + if( !xStyle.is() || !(bOverwrite || IsNew()) ) + return; + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + + OUString const sIsAutoUpdate("IsAutoUpdate"); + if( xPropSetInfo->hasPropertyByName( sIsAutoUpdate ) ) + { + xPropSet->setPropertyValue( sIsAutoUpdate, Any(m_isAutoUpdate) ); + } + + sal_uInt16 nCategory = ParagraphStyleCategory::TEXT; + if( XmlStyleFamily::TEXT_PARAGRAPH == GetFamily() && + !m_sCategoryVal.isEmpty() && xStyle->isUserDefined() && + xPropSetInfo->hasPropertyByName("Category") && + SvXMLUnitConverter::convertEnum( nCategory, m_sCategoryVal, aCategoryMap)) + { + xPropSet->setPropertyValue("Category", Any(static_cast(nCategory))); + } + + // tell the style about it's events (if applicable) + if (m_xEventContext.is()) + { + // pass events into event supplier + Reference xEventsSupplier(xStyle,UNO_QUERY); + m_xEventContext->SetEvents(xEventsSupplier); + m_xEventContext.clear(); + } + + // XML import: reconstruction of assignment of paragraph style to outline levels (#i69629#) + if (m_nOutlineLevel > 0) + { + GetImport().GetTextImport()->AddOutlineStyleCandidate(m_nOutlineLevel, + GetDisplayName() ); + } +} + +void XMLTextStyleContext::SetDefaults( ) +{ + if( ( GetFamily() == XmlStyleFamily::TEXT_PARAGRAPH ) || + ( GetFamily() == XmlStyleFamily::TABLE_TABLE ) || + ( GetFamily() == XmlStyleFamily::TABLE_ROW ) ) + { + Reference < XMultiServiceFactory > xFactory ( GetImport().GetModel(), UNO_QUERY); + if (xFactory.is()) + { + Reference < XInterface > xInt = xFactory->createInstance( "com.sun.star.text.Defaults" ); + Reference < XPropertySet > xProperties ( xInt, UNO_QUERY ); + if ( xProperties.is() ) + FillPropertySet ( xProperties ); + } + } +} + +void XMLTextStyleContext::Finish( bool bOverwrite ) +{ + XMLPropStyleContext::Finish( bOverwrite ); + + Reference < XStyle > xStyle = GetStyle(); + // Consider set empty list style (#i69523#) + if ( !( m_bListStyleSet || + m_nOutlineLevel >= 0 || + !m_sDropCapTextStyleName.isEmpty() || + m_bHasMasterPageName ) || + !xStyle.is() || + !( bOverwrite || IsNew() ) ) + return; + + Reference < XPropertySet > xPropSet( xStyle, UNO_QUERY ); + Reference< XPropertySetInfo > xPropSetInfo = + xPropSet->getPropertySetInfo(); + + OUString const sOutlineLevel("OutlineLevel"); + if( xPropSetInfo->hasPropertyByName( sOutlineLevel )) + { + if (m_nOutlineLevel >= 0) + { + xPropSet->setPropertyValue( sOutlineLevel, Any(m_nOutlineLevel) ); + } + } + + // Consider set empty list style (#i69523#) + OUString const sNumberingStyleName("NumberingStyleName"); + if (m_bListStyleSet && + xPropSetInfo->hasPropertyByName( sNumberingStyleName ) ) + { + /* Only for text document from version prior OOo 2.1 resp. SO 8 PU5: + - Do not apply list style, if paragraph style has a default outline + level > 0 and thus, will be assigned to the corresponding list + level of the outline style. (#i70223#) + */ + bool bApplyListStyle( true ); + if (m_nOutlineLevel > 0) + { + if ( GetImport().IsTextDocInOOoFileFormat() ) + { + bApplyListStyle = false; + } + else + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + // Check explicitly on certain versions (#i86058#) + if ( GetImport().getBuildIds( nUPD, nBuild ) && + ( ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0 + ( nUPD == 680 && nBuild <= 9073 ) ) ) // OOo 2.0 - OOo 2.0.4 + { + bApplyListStyle = false; + } + } + } + + if ( bApplyListStyle ) + { + if (m_sListStyleName.isEmpty()) + { + xPropSet->setPropertyValue(sNumberingStyleName, Any(m_sListStyleName)); /* empty string */ + } + else + { + // change list style name to display name + OUString sDisplayListStyleName( + GetImport().GetStyleDisplayName(XmlStyleFamily::TEXT_LIST, + m_sListStyleName)); + // The families container must exist + const Reference < XNameContainer >& rNumStyles = + GetImport().GetTextImport()->GetNumberingStyles(); + // if( rNumStyles.is() && rNumStyles->hasByName( sDisplayListStyleName ) && + // xPropSetInfo->hasPropertyByName( sNumberingStyleName ) ) + if ( rNumStyles.is() && + rNumStyles->hasByName( sDisplayListStyleName ) ) + { + xPropSet->setPropertyValue( sNumberingStyleName, Any(sDisplayListStyleName) ); + } + } + + if (m_aListLevel.has_value()) + { + xPropSet->setPropertyValue("NumberingLevel", uno::Any(*m_aListLevel)); + } + } + } + + if (!m_sDropCapTextStyleName.isEmpty()) + { + // change list style name to display name + OUString sDisplayDropCapTextStyleName( + GetImport().GetStyleDisplayName( XmlStyleFamily::TEXT_TEXT, + m_sDropCapTextStyleName)); + // The families container must exist + const Reference < XNameContainer >& rTextStyles = + GetImport().GetTextImport()->GetTextStyles(); + if( rTextStyles.is() && + rTextStyles->hasByName( sDisplayDropCapTextStyleName ) && + xPropSetInfo->hasPropertyByName("DropCapCharStyleName")) + { + xPropSet->setPropertyValue("DropCapCharStyleName", Any(sDisplayDropCapTextStyleName)); + } + } + + if (!m_bHasMasterPageName) + return; + + OUString sDisplayName( + GetImport().GetStyleDisplayName( + XmlStyleFamily::MASTER_PAGE, m_sMasterPageName)); + // The families container must exist + const Reference < XNameContainer >& rPageStyles = + GetImport().GetTextImport()->GetPageStyles(); + + OUString const sPageDescName("PageDescName"); + if( ( sDisplayName.isEmpty() || + (rPageStyles.is() && + rPageStyles->hasByName( sDisplayName )) ) && + xPropSetInfo->hasPropertyByName( sPageDescName ) ) + { + xPropSet->setPropertyValue( sPageDescName, Any(sDisplayName) ); + } +} + +void XMLTextStyleContext::FillPropertySet( + const Reference & rPropSet ) +{ + // imitate the FillPropertySet of the super class, so we get a chance to + // catch the combined characters attribute + + // imitate XMLPropStyleContext::FillPropertySet(...) + SvXMLStylesContext* pSvXMLStylesContext = GetStyles(); + rtl::Reference < SvXMLImportPropertyMapper > xImpPrMap = pSvXMLStylesContext->GetImportPropertyMapper(GetFamily()); + DBG_ASSERT(xImpPrMap.is(),"Where is the import prop mapper?"); + + if(!xImpPrMap.is()) + return; + + // imitate SvXMLImportPropertyMapper::FillPropertySet(...) + // The reason for this is that we have no other way to + // efficiently intercept the value of combined characters. To + // get that value, we could iterate through the map once more, + // but instead we chose to insert the code into this + // iteration. I haven't been able to come up with a much more + // intelligent solution. + struct ContextID_Index_Pair aContextIDs[] = + { + { CTF_COMBINED_CHARACTERS_FIELD, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_KEEP_TOGETHER, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_BORDER_MODEL, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_TEXT_DISPLAY, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FONTFAMILYNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FONTFAMILYNAME_CJK, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FONTFAMILYNAME_CTL, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + + //UUU need special handling for DrawingLayer FillStyle names + { CTF_FILLGRADIENTNAME, -1, drawing::FillStyle::FillStyle_GRADIENT }, + { CTF_FILLTRANSNAME, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE }, + { CTF_FILLHATCHNAME, -1, drawing::FillStyle::FillStyle_HATCH }, + { CTF_FILLBITMAPNAME, -1, drawing::FillStyle::FillStyle_BITMAP }, + + { -1, -1, drawing::FillStyle::FillStyle_MAKE_FIXED_SIZE } + }; + + // the style families associated with the same index modulo 4 + static const XmlStyleFamily aFamilies[] = + { + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_GRADIENT_ID, + XmlStyleFamily::SD_HATCH_ID, + XmlStyleFamily::SD_FILL_IMAGE_ID + }; + + // get property set info + Reference< XPropertySetInfo > xInfo; + rtl::Reference< XMLPropertySetMapper > rPropMapper; + bool bAutomatic = false; + + if(pSvXMLStylesContext->IsAutomaticStyle() && + (XmlStyleFamily::TEXT_TEXT == GetFamily() || XmlStyleFamily::TEXT_PARAGRAPH == GetFamily())) + { + bAutomatic = true; + + if( !GetAutoName().isEmpty() ) + { + OUString sAutoProp = ( GetFamily() == XmlStyleFamily::TEXT_TEXT ) ? + OUString( "CharAutoStyleName" ): + OUString( "ParaAutoStyleName" ); + + try + { + if(!xInfo.is()) + { + xInfo = rPropSet->getPropertySetInfo(); + } + + if ( xInfo->hasPropertyByName( sAutoProp ) ) + { + rPropSet->setPropertyValue( sAutoProp, Any(GetAutoName()) ); + } + else + { + bAutomatic = false; + } + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff.text"); + bAutomatic = false; + } + } + } + + if( bAutomatic ) + { + xImpPrMap->CheckSpecialContext( GetProperties(), rPropSet, aContextIDs ); + } + else + { + xImpPrMap->FillPropertySet( GetProperties(), rPropSet, aContextIDs ); + } + + sal_Int32 nIndex = aContextIDs[0].nIndex; + + // have we found a combined characters + if ( nIndex != -1 ) + { + Any& rAny = GetProperties()[nIndex].maValue; + bool bVal = *o3tl::doAccess(rAny); + m_bHasCombinedCharactersLetter = bVal; + } + + // keep-together: the application default is different from + // the file format default. Hence, if we always set this + // value; if we didn't find one, we'll set to false, the file + // format default. + // border-model: same + if(IsDefaultStyle() && XmlStyleFamily::TABLE_ROW == GetFamily()) + { + OUString sIsSplitAllowed("IsSplitAllowed"); + SAL_WARN_IF( !rPropSet->getPropertySetInfo()->hasPropertyByName( sIsSplitAllowed ), "xmloff", "property missing?" ); + rPropSet->setPropertyValue( + sIsSplitAllowed, + (aContextIDs[1].nIndex == -1) ? Any( false ) : GetProperties()[aContextIDs[1].nIndex].maValue ); + } + + if(IsDefaultStyle() && XmlStyleFamily::TABLE_TABLE == GetFamily()) + { + OUString sCollapsingBorders("CollapsingBorders"); + SAL_WARN_IF( !rPropSet->getPropertySetInfo()->hasPropertyByName( sCollapsingBorders ), "xmloff", "property missing?" ); + rPropSet->setPropertyValue( + sCollapsingBorders, + (aContextIDs[2].nIndex == -1) + ? Any( false ) + : GetProperties()[aContextIDs[2].nIndex].maValue ); + } + + + // iterate over aContextIDs entries, start with 3, prev ones are already used above + for(sal_uInt16 i(3); aContextIDs[i].nContextID != -1; i++) + { + nIndex = aContextIDs[i].nIndex; + + if ( nIndex != -1 ) + { + // Found! + struct XMLPropertyState& rState = GetProperties()[nIndex]; + + switch(aContextIDs[i].nContextID) + { + case CTF_FILLGRADIENTNAME: + case CTF_FILLTRANSNAME: + case CTF_FILLHATCHNAME: + case CTF_FILLBITMAPNAME: + { + // DrawingLayer FillStyle name needs to be mapped to DisplayName + OUString sStyleName; + rState.maValue >>= sStyleName; + + // translate the used name from ODF intern to the name used in the Model + sStyleName = GetImport().GetStyleDisplayName(aFamilies[i - 7], sStyleName); + + if(bAutomatic) + { + // in this case the rPropSet got not really filled since above the call to + // CheckSpecialContext was used and not FillPropertySet, thus the below call to + // setPropertyValue can fail/will not be useful (e.g. when the rPropSet + // is a SwXTextCursor). + // This happens for AutoStyles which are already filled in XMLPropStyleContext::CreateAndInsert, + // thus the whole mechanism based on _ContextID_Index_Pair will not work + // in that case. Thus the slots which need to be converted already get + // converted there (it's called first) and not here (see + // translateNameBasedDrawingLayerFillStyleDefinitionsToStyleDisplayNames) + // For convenience, still Write back the corrected value to the XMLPropertyState entry + rState.maValue <<= sStyleName; + break; + } + + if (::xmloff::IsIgnoreFillStyleNamedItem(rPropSet, aContextIDs[i].nExpectedFillStyle)) + { + SAL_INFO("xmloff.style", "XMLTextStyleContext: dropping fill named item: " << sStyleName); + break; // ignore it, it's not used + } + + // Still needed if it's not an AutomaticStyle (!) + try + { + if(!rPropMapper.is()) + { + rPropMapper = xImpPrMap->getPropertySetMapper(); + } + + // set property + const OUString& rPropertyName = rPropMapper->GetEntryAPIName(rState.mnIndex); + + if(!xInfo.is()) + { + xInfo = rPropSet->getPropertySetInfo(); + } + + if(xInfo->hasPropertyByName(rPropertyName)) + { + rPropSet->setPropertyValue(rPropertyName,Any(sStyleName)); + } + } + catch(css::lang::IllegalArgumentException& e) + { + Sequence aSeq { sStyleName }; + GetImport().SetError(XMLERROR_STYLE_PROP_VALUE | XMLERROR_FLAG_WARNING, aSeq, e.Message, nullptr); + } + break; + } + default: + { + // check for StarBats and StarMath fonts + Any rAny = rState.maValue; + sal_Int32 nMapperIndex = rState.mnIndex; + + // Now check for font name in rState and set corrected value, + // if necessary. + OUString sFontName; + rAny >>= sFontName; + + if ( !sFontName.isEmpty() ) + { + if ( sFontName.equalsIgnoreAsciiCase( "StarBats" ) || + sFontName.equalsIgnoreAsciiCase( "StarMath" ) ) + { + // construct new value + sFontName = "StarSymbol"; + Any aAny(rAny); + aAny <<= sFontName; + + if(!rPropMapper.is()) + { + rPropMapper = xImpPrMap->getPropertySetMapper(); + } + + // set property + OUString rPropertyName(rPropMapper->GetEntryAPIName(nMapperIndex)); + + if(!xInfo.is()) + { + xInfo = rPropSet->getPropertySetInfo(); + } + + if(xInfo->hasPropertyByName(rPropertyName)) + { + rPropSet->setPropertyValue(rPropertyName,aAny); + } + } + // else: "normal" style name -> no correction is necessary + } + // else: no style name found -> illegal value -> ignore + } + } + } + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/txtvfldi.cxx b/xmloff/source/text/txtvfldi.cxx new file mode 100644 index 000000000..8725435a6 --- /dev/null +++ b/xmloff/source/text/txtvfldi.cxx @@ -0,0 +1,1247 @@ +/* -*- 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 . + */ + + +/** @#file + * + * export of all variable related text fields (and database display field) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + + +// service names +constexpr char16_t sAPI_fieldmaster_prefix[] = u"com.sun.star.text.FieldMaster."; +constexpr OUStringLiteral sAPI_get_expression = u"GetExpression"; +constexpr OUStringLiteral sAPI_set_expression = u"SetExpression"; +constexpr OUStringLiteral sAPI_user = u"User"; +constexpr OUStringLiteral sAPI_database = u"com.sun.star.text.TextField.Database"; + +// property names +constexpr OUStringLiteral sAPI_content = u"Content"; +constexpr OUStringLiteral sAPI_sub_type = u"SubType"; +constexpr OUStringLiteral sAPI_number_format = u"NumberFormat"; +constexpr OUStringLiteral sAPI_is_visible = u"IsVisible"; +constexpr OUStringLiteral sAPI_current_presentation = u"CurrentPresentation"; + + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::style; +using namespace ::xmloff::token; + + +// XMLVarFieldImportContext: superclass for all variable related fields + + +XMLVarFieldImportContext::XMLVarFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + const OUString& pServiceName, + bool bFormula, bool bFormulaDefault, + bool bDescription, bool bHelp, bool bHint, bool bVisible, + bool bIsDisplayFormula, + bool bType, bool bStyle, bool bValue, + bool bPresentation) : + XMLTextFieldImportContext(rImport, rHlp, pServiceName), + aValueHelper(rImport, rHlp, bType, bStyle, bValue, false), + bDisplayFormula(false), + bDisplayNone(false), + bFormulaOK(false), + bDescriptionOK(false), + bHelpOK(false), + bHintOK(false), + bDisplayOK(false), + bSetFormula(bFormula), + bSetFormulaDefault(bFormulaDefault), + bSetDescription(bDescription), + bSetHelp(bHelp), + bSetHint(bHint), + bSetVisible(bVisible), + bSetDisplayFormula(bIsDisplayFormula), + bSetPresentation(bPresentation) +{ +} + +void XMLVarFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_NAME): + sName = OUString::fromUtf8(sAttrValue); + bValid = true; // we assume: field with name is valid! + break; + case XML_ELEMENT(TEXT, XML_DESCRIPTION): + sDescription = OUString::fromUtf8(sAttrValue); + bDescriptionOK = true; + break; + case XML_ELEMENT(TEXT, XML_HELP): + sHelp = OUString::fromUtf8(sAttrValue); + bHelpOK = true; + break; + case XML_ELEMENT(TEXT, XML_HINT): + sHint = OUString::fromUtf8(sAttrValue); + bHintOK = true; + break; + case XML_ELEMENT(TEXT, XML_FORMULA): + { + OUString sTmp; + sal_uInt16 nPrefix = GetImport().GetNamespaceMap(). + GetKeyByAttrValueQName(OUString::fromUtf8(sAttrValue), &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sFormula = sTmp; + bFormulaOK = true; + } + else + sFormula = OUString::fromUtf8(sAttrValue); + } + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + if (IsXMLToken(sAttrValue, XML_FORMULA)) + { + bDisplayFormula = true; + bDisplayNone = false; + bDisplayOK = true; + } + else if (IsXMLToken(sAttrValue, XML_VALUE)) + { + bDisplayFormula = false; + bDisplayNone = false; + bDisplayOK = true; + } + else if (IsXMLToken(sAttrValue, XML_NONE)) + { + bDisplayFormula = false; + bDisplayNone = true; + bDisplayOK = true; + } // else: no change + DBG_ASSERT(!(bDisplayFormula && bDisplayNone), + "illegal display values"); + break; + default: + // delegate all others to value helper + aValueHelper.ProcessAttribute(nAttrToken, sAttrValue); + break; + } +} + +void XMLVarFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + // bSetName: not implemented + + if (bSetFormula) + { + if (!bFormulaOK && bSetFormulaDefault) + { + sFormula = GetContent(); + bFormulaOK = true; + } + + if (bFormulaOK) + { + xPropertySet->setPropertyValue(sAPI_content, Any(sFormula)); + } + } + + if (bSetDescription && bDescriptionOK) + { + xPropertySet->setPropertyValue("Hint", Any(sDescription)); + } + + if (bSetHelp && bHelpOK) + { + xPropertySet->setPropertyValue("Help", Any(sHelp)); + } + + if (bSetHint && bHintOK) + { + xPropertySet->setPropertyValue("Tooltip", Any(sHint)); + } + + if (bSetVisible && bDisplayOK) + { + bool bTmp = !bDisplayNone; + xPropertySet->setPropertyValue(sAPI_is_visible, Any(bTmp)); + } + + // workaround for #no-bug#: display formula by default + if (xPropertySet->getPropertySetInfo()-> + hasPropertyByName("IsShowFormula") && + !bSetDisplayFormula) + { + bDisplayFormula = false; + bSetDisplayFormula = true; + } + + + if (bSetDisplayFormula) + { + bool bTmp = bDisplayFormula && bDisplayOK; + xPropertySet->setPropertyValue("IsShowFormula", Any(bTmp)); + } + + // delegate to value helper + aValueHelper.SetDefault(GetContent()); + aValueHelper.PrepareField(xPropertySet); + + // finally, set the current presentation + if (bSetPresentation) + { + Any aAny; + aAny <<= GetContent(); + xPropertySet->setPropertyValue(sAPI_current_presentation, aAny); + } +} + + +// variable set fields + + +XMLSetVarFieldImportContext::XMLSetVarFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + const OUString& pServiceName, VarType eVarType, + bool bFormula, bool bFormulaDefault, + bool bDescription, bool bHelp, bool bHint, bool bVisible, bool bIsDisplayFormula, + bool bType, bool bStyle, bool bValue, bool bPresentation) : + XMLVarFieldImportContext(rImport, rHlp, pServiceName, + bFormula, bFormulaDefault, + bDescription, bHelp, bHint, bVisible, bIsDisplayFormula, + bType, bStyle, bValue, bPresentation), + eFieldType(eVarType) +{ +} + +void XMLSetVarFieldImportContext::endFastElement(sal_Int32 ) +{ + // should we call PrepareField on the field, or rather on it's master? + // currently: call on field (just like superclass) + // possible alternatives: call on master + // call field or master depending on variable + // PrepareMaster() in addition to PrepareField() + + DBG_ASSERT(!GetServiceName().isEmpty(), "no service name for element!"); + + if (bValid) + { + DBG_ASSERT(!GetName().isEmpty(), "variable name needed!"); + + // find field master + Reference xMaster; + if (FindFieldMaster(xMaster)) + { + // create field/Service + Reference xPropSet; + if (CreateField(xPropSet, "com.sun.star.text.TextField." + GetServiceName())) + { + Reference xDepTextField(xPropSet, UNO_QUERY); + if (xDepTextField.is()) + { + // attach field to field master + xDepTextField->attachTextFieldMaster(xMaster); + + // attach field to document + Reference xTextContent(xPropSet, UNO_QUERY); + if (xTextContent.is()) + { + try { + // insert, set field properties and exit! + GetImportHelper().InsertTextContent(xTextContent); + PrepareField(xPropSet); + } catch (lang::IllegalArgumentException & /*e*/) + { + // ignore e: #i54023# + }; + return; + } + } + } + } + } + + // above: exit on success; so for all error cases we end up here! + // write element content + GetImportHelper().InsertString(GetContent()); +} + +bool XMLSetVarFieldImportContext::FindFieldMaster( + Reference & xMaster) +{ + // currently: delegate to XMLVariableDeclImportContext; + // should eventually go here + return XMLVariableDeclImportContext::FindFieldMaster(xMaster, + GetImport(), + GetImportHelper(), + GetName(), + eFieldType); +} + + +// sequence field + + +XMLSequenceFieldImportContext::XMLSequenceFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLSetVarFieldImportContext(rImport, rHlp, sAPI_set_expression, + VarTypeSequence, + // formula + true, true, + false, false, false, false, + false, + false, false, false, true), + + sNumFormat(OUString('1')), + sNumFormatSync(GetXMLToken(XML_FALSE)), + bRefNameOK(false) +{ +} + +void XMLSequenceFieldImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(STYLE, XML_NUM_FORMAT): + sNumFormat = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(STYLE, XML_NUM_LETTER_SYNC): + sNumFormatSync = OUString::fromUtf8(sAttrValue); + break; + case XML_ELEMENT(TEXT, XML_REF_NAME): + sRefName = OUString::fromUtf8(sAttrValue); + bRefNameOK = true; + break; + default: + // delegate to super class (name, formula) + XMLSetVarFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + } // switch +} + +void XMLSequenceFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + // delegate to super class (formula) + XMLSetVarFieldImportContext::PrepareField(xPropertySet); + + // set format + sal_Int16 nNumType = NumberingType::ARABIC; + GetImport().GetMM100UnitConverter().convertNumFormat( nNumType, sNumFormat, sNumFormatSync ); + xPropertySet->setPropertyValue(sAPI_number_format, Any(nNumType)); + + // handle reference name + if (bRefNameOK) + { + Any aAny = xPropertySet->getPropertyValue("SequenceValue"); + sal_Int16 nValue = 0; + aAny >>= nValue; + GetImportHelper().InsertSequenceID(sRefName, GetName(), nValue); + } +} + + +// variable set field + + +XMLVariableSetFieldImportContext::XMLVariableSetFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLSetVarFieldImportContext(rImport, rHlp, sAPI_set_expression, + VarTypeSimple, + // formula, value&type, style, + // display none + true, true, + false, false, false, + true, false, + true, true, true, + true) +{ +} + +void XMLVariableSetFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + // set type + Any aAny; + aAny <<= (IsStringValue()? SetVariableType::STRING : SetVariableType::VAR); + xPropertySet->setPropertyValue(sAPI_sub_type, aAny); + + // the remainder is handled by super class + XMLSetVarFieldImportContext::PrepareField(xPropertySet); +} + + +// variable input field + + +XMLVariableInputFieldImportContext::XMLVariableInputFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLSetVarFieldImportContext(rImport, rHlp, sAPI_set_expression, + VarTypeSimple, + // description, display none/formula, + // value&type, style, formula + true, true, + true, true, true, + true, false, + true, true, true, + true) +{ +} + +void XMLVariableInputFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + // set type (input field) + Any aAny; + xPropertySet->setPropertyValue("Input", Any(true)); + + // set type + aAny <<= (IsStringValue()? SetVariableType::STRING : SetVariableType::VAR); + xPropertySet->setPropertyValue(sAPI_sub_type, aAny); + + // the remainder is handled by super class + XMLSetVarFieldImportContext::PrepareField(xPropertySet); +} + + +// user field + + +XMLUserFieldImportContext::XMLUserFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLSetVarFieldImportContext(rImport, rHlp, sAPI_user, + VarTypeUserField, + // display none/formula, style + false, false, + false, false, false, true, + true, + false, true, false, + false) +{ +} + + +// user input field + + +// bug: doesn't work (SO API lacking) +XMLUserFieldInputImportContext::XMLUserFieldInputImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLVarFieldImportContext(rImport, rHlp, "InputUser", + // description, style + false, false, + true, false, false, + false, false, + false /*???*/, true, false, + false) +{ +} + +void XMLUserFieldInputImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(sAPI_content, Any(GetName())); + + // delegate to super class + XMLVarFieldImportContext::PrepareField(xPropertySet); +} + + +// variable get field + + +XMLVariableGetFieldImportContext::XMLVariableGetFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLVarFieldImportContext(rImport, rHlp, sAPI_get_expression, + // style, display formula + false, false, + false, false, false, + false, true, + true, true, false, + true) +{ +} + +void XMLVariableGetFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + // set name + xPropertySet->setPropertyValue(sAPI_content, Any(GetName())); + + // the remainder is handled by super class + XMLVarFieldImportContext::PrepareField(xPropertySet); +} + + +// expression field + + +XMLExpressionFieldImportContext::XMLExpressionFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLVarFieldImportContext(rImport, rHlp, sAPI_get_expression, + // formula, type, style, display formula + true, true, + false, false, false, + false, true, + true, true, false, + true) +{ + bValid = true; // always valid +} + + +void XMLExpressionFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + xPropertySet->setPropertyValue(sAPI_sub_type, Any(sal_Int16(SetVariableType::FORMULA))); + + // delegate to super class + XMLVarFieldImportContext::PrepareField(xPropertySet); +} + + +// text input field + + +XMLTextInputFieldImportContext::XMLTextInputFieldImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLVarFieldImportContext(rImport, rHlp, "Input", + // description + false, false, + true, true, true, + false, false, + false, false, false, + false) +{ + bValid = true; // always valid +} + +void XMLTextInputFieldImportContext::PrepareField( + const Reference & xPropertySet) +{ + XMLVarFieldImportContext::PrepareField(xPropertySet); + + xPropertySet->setPropertyValue(sAPI_content, Any(GetContent())); +} + + +// table formula field + + +XMLTableFormulaImportContext::XMLTableFormulaImportContext( + SvXMLImport& rImport, + XMLTextImportHelper& rHlp) : + XMLTextFieldImportContext(rImport, rHlp, "TableFormula"), + aValueHelper(rImport, rHlp, false, true, false, true), + bIsShowFormula(false) +{ +} + +void XMLTableFormulaImportContext::ProcessAttribute( + sal_Int32 nAttrToken, + std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_FORMULA): + aValueHelper.ProcessAttribute( nAttrToken, sAttrValue ); + bValid = true; // we need a formula! + break; + + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + aValueHelper.ProcessAttribute( nAttrToken, sAttrValue ); + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + if ( sAttrValue == "formula" ) + bIsShowFormula = true; + break; + default: + // unknown attribute -> ignore + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + break; + } +} + +void XMLTableFormulaImportContext::PrepareField( + const Reference & xPropertySet) +{ + // set format and formula + aValueHelper.PrepareField( xPropertySet ); + + Any aAny; + + // set 'show formula' and presentation + xPropertySet->setPropertyValue( "IsShowFormula", Any(bIsShowFormula) ); + + aAny <<= GetContent(); + xPropertySet->setPropertyValue( "CurrentPresentation", aAny ); +} + + +// variable declarations + +// Should be adapted to XMLVarField-/XMLSetVarFieldImportContext scheme! + + +// declaration container import () + + +XMLVariableDeclsImportContext::XMLVariableDeclsImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, enum VarType eVarType) : + SvXMLImportContext(rImport), + eVarDeclsContextType(eVarType), + rImportHelper(rHlp) +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XMLVariableDeclsImportContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( IsTokenInNamespace(nElement, XML_NAMESPACE_TEXT) ) + { + enum XMLTokenEnum eElementName; + switch (eVarDeclsContextType) + { + case VarTypeSequence: + eElementName = XML_SEQUENCE_DECL; + break; + case VarTypeSimple: + eElementName = XML_VARIABLE_DECL; + break; + case VarTypeUserField: + eElementName = XML_USER_FIELD_DECL; + break; + default: + OSL_FAIL("unknown field type!"); + eElementName = XML_SEQUENCE_DECL; + break; + } + + if( nElement == XML_ELEMENT(TEXT, eElementName) ) + { + return new XMLVariableDeclImportContext( + GetImport(), rImportHelper, nElement, xAttrList, + eVarDeclsContextType); + } + } + + // if no context was created, use default context + return nullptr; +} + + +// declaration import ( elements) + + +XMLVariableDeclImportContext::XMLVariableDeclImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp, + sal_Int32 nElement, + const Reference & xAttrList, + enum VarType eVarType) : + SvXMLImportContext(rImport) +{ + // bug?? which properties for userfield/userfieldmaster + XMLValueImportHelper aValueHelper(rImport, rHlp, true, false, true, false); + sal_Unicode cSeparationChar('.'); + + sal_Int8 nNumLevel(-1); + OUString sName; + + if (nElement != XML_ELEMENT(TEXT, XML_SEQUENCE_DECL) && + nElement != XML_ELEMENT(TEXT, XML_VARIABLE_DECL) && + nElement != XML_ELEMENT(TEXT, XML_USER_FIELD_DECL) ) + return; + + // TODO: check validity (need name!) + + // parse attributes + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(TEXT, XML_NAME): + sName = aIter.toString(); + break; + case XML_ELEMENT(TEXT, XML_DISPLAY_OUTLINE_LEVEL): + { + sal_Int32 nLevel; + bool const bRet = ::sax::Converter::convertNumber( + nLevel, aIter.toView(), 0, + GetImport().GetTextImport()->GetChapterNumbering()-> + getCount()); + if (bRet) + { + nNumLevel = static_cast< sal_Int8 >( nLevel-1 ); // API numbers -1..9 + } + break; + } + case XML_ELEMENT(TEXT, XML_SEPARATION_CHARACTER): + cSeparationChar = + static_cast(aIter.toString().toChar()); + break; + + default: + // delegate to value helper + aValueHelper.ProcessAttribute(aIter.getToken(), aIter.toView()); + break; + } + } + + Reference xFieldMaster; + if (!FindFieldMaster(xFieldMaster, GetImport(), rHlp, + sName, eVarType)) + return; + + // now we have a field master: process attributes! + Any aAny; + + switch (eVarType) + { + case VarTypeSequence: + xFieldMaster->setPropertyValue("ChapterNumberingLevel", Any(nNumLevel)); + + if (nNumLevel >= 0) + { + OUString sStr(&cSeparationChar, 1); + xFieldMaster->setPropertyValue( + "NumberingSeparator", Any(sStr)); + } + break; + case VarTypeSimple: + { + // set string or non-string SubType (#93192#) + // The SubType was already set in the FindFieldMaster + // method, but it needs to be adjusted if it's a string. + aAny <<= aValueHelper.IsStringValue() + ? SetVariableType::STRING : SetVariableType::VAR; + xFieldMaster->setPropertyValue(sAPI_sub_type, aAny); + } + break; + case VarTypeUserField: + { + bool bTmp = !aValueHelper.IsStringValue(); + xFieldMaster->setPropertyValue("IsExpression", Any(bTmp)); + aValueHelper.PrepareField(xFieldMaster); + break; + } + default: + OSL_FAIL("unknown varfield type"); + } // switch +} + + +bool XMLVariableDeclImportContext::FindFieldMaster( + Reference & xMaster, SvXMLImport& rImport, + XMLTextImportHelper& rImportHelper, + const OUString& sVarName, enum VarType eVarType) +{ + static sal_Int32 nCollisionCount = 0; + + // rename field + // currently: no family in use! Use 0. + OUString sName = rImportHelper.GetRenameMap().Get( + sal::static_int_cast< sal_uInt16 >(eVarType), sVarName); + + // get text fields supplier and field masters + Reference xTextFieldsSupp(rImport.GetModel(), + UNO_QUERY); + Reference xFieldMasterNameAccess = + xTextFieldsSupp->getTextFieldMasters(); + + OUString sVarServiceName = + OUString::Concat(sAPI_fieldmaster_prefix) + + sAPI_set_expression + + "." + + sName; + + OUString sUserServiceName = + OUString::Concat(sAPI_fieldmaster_prefix) + + sAPI_user + + "." + + sName; + + if (xFieldMasterNameAccess->hasByName(sVarServiceName)) { + // variable field master already in document + + Any aAny = xFieldMasterNameAccess->getByName(sVarServiceName); + aAny >>= xMaster; + + aAny = xMaster->getPropertyValue(sAPI_sub_type); + sal_Int16 nType = 0; + aAny >>= nType; + + enum VarType eFMVarType = + (SetVariableType::SEQUENCE == nType) ? + VarTypeSequence : VarTypeSimple; + + if (eFMVarType != eVarType) + { + ++nCollisionCount; + OUString sNew(sName + "_renamed_" + OUString::number(nCollisionCount)); + + // FIXME! can't find if name is taken already!!!! + + rImportHelper.GetRenameMap().Add( + sal::static_int_cast< sal_uInt16 >(eVarType), sName, sNew); + + // call FindFieldMaster recursively to create new master + return FindFieldMaster(xMaster, rImport, rImportHelper, + sNew, eVarType); + } + } else if (xFieldMasterNameAccess->hasByName(sUserServiceName)) { + // user field: get field master + Any aAny = xFieldMasterNameAccess->getByName(sUserServiceName); + aAny >>= xMaster; + + if (VarTypeUserField != eVarType) { + ++nCollisionCount; + // find new name that is not taken + OUString sNew(sName + "_renamed_" + OUString::number(nCollisionCount)); + + // FIXME! can't find if name is taken already!!!! + + rImportHelper.GetRenameMap().Add( + sal::static_int_cast< sal_uInt16 >(eVarType), sName, sNew); + + // call FindFieldMaster recursively to create new master + return FindFieldMaster(xMaster, rImport, rImportHelper, + sNew, eVarType); + } + } else { + // field name not used: create field master + + // import -> model is MultiServiceFactory -> createInstance + Reference + xFactory(rImport.GetModel(),UNO_QUERY); + if( xFactory.is() ) { + + OUString sService = sAPI_fieldmaster_prefix + + ((eVarType==VarTypeUserField) ? + OUString(sAPI_user) : OUString(sAPI_set_expression)); + Reference xIfc = + xFactory->createInstance( sService ); + if (xIfc.is()) { + Reference xTmp( xIfc, UNO_QUERY ); + xMaster = xTmp; + + // set name + xMaster->setPropertyValue("Name", Any(sName)); + + if (eVarType != VarTypeUserField) { + // set subtype for setexp field + Any aAny; + aAny <<= ((eVarType == VarTypeSimple) ? + SetVariableType::VAR : + SetVariableType::SEQUENCE); + xMaster->setPropertyValue(sAPI_sub_type, aAny); + } // else : user field: no subtype + + } else { + return false; + } + } else { + return false; + } + } + + DBG_ASSERT(xMaster.is(), "no field master found!?!"); + return true; +} + + +// Database Display field import + + +XMLDatabaseDisplayImportContext::XMLDatabaseDisplayImportContext( + SvXMLImport& rImport, XMLTextImportHelper& rHlp) : + XMLDatabaseFieldImportContext(rImport, rHlp, sAPI_database, false), + aValueHelper(rImport, rHlp, false, true, false, false), + bColumnOK(false), + bDisplay( true ), + bDisplayOK( false ) +{ +} + +void XMLDatabaseDisplayImportContext::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_COLUMN_NAME): + sColumnName = OUString::fromUtf8(sAttrValue); + bColumnOK = true; + break; + case XML_ELEMENT(TEXT, XML_DISPLAY): + { + bool bNone = IsXMLToken( sAttrValue, XML_NONE ); + bool bValue = IsXMLToken( sAttrValue, XML_VALUE ); + bDisplay = bValue; + bDisplayOK = bNone || bValue; + } + break; + case XML_ELEMENT(TEXT, XML_DATABASE_NAME): + case XML_ELEMENT(TEXT, XML_TABLE_NAME): + case XML_ELEMENT(TEXT, XML_TABLE_TYPE): + // handled by super class + XMLDatabaseFieldImportContext::ProcessAttribute(nAttrToken, + sAttrValue); + break; + default: + // remainder handled by value helper + aValueHelper.ProcessAttribute(nAttrToken, sAttrValue); + break; + } + + bValid = m_bTableOK && m_bDatabaseOK && bColumnOK; +} + +void XMLDatabaseDisplayImportContext::endFastElement(sal_Int32 ) +{ + // we have an EndElement of our own, because database fields need + // to be attached to a field master before they can be inserted into + // the document. Database stuff (database, table, column) all goes + // to the field master, value & style go to the field. + + if (bValid) + { + + // so here goes: we start with the master + Reference xMaster; + + // create and prepare field master first + if (CreateField(xMaster, + "com.sun.star.text.FieldMaster.Database")) + { + Any aAny; + xMaster->setPropertyValue("DataColumnName", Any(sColumnName)); + + // fieldmaster takes database, table and column name + XMLDatabaseFieldImportContext::PrepareField(xMaster); + + // create field + Reference xField; + if (CreateField(xField, + sAPI_database)) + { + // attach field master + Reference xDepField(xField, UNO_QUERY); + if (xDepField.is()) + { + // attach field to field master + xDepField->attachTextFieldMaster(xMaster); + + // attach field to document + Reference xTextContent(xField, UNO_QUERY); + if (xTextContent.is()) + { + // insert, set field properties and exit! + try + { + GetImportHelper().InsertTextContent(xTextContent); + + // prepare field: format from database? + bool bTmp = !aValueHelper.IsFormatOK(); + xField->setPropertyValue("DataBaseFormat", Any(bTmp)); + + // value, value-type and format done by value helper + aValueHelper.PrepareField(xField); + + // visibility + if( bDisplayOK ) + { + xField->setPropertyValue(sAPI_is_visible, Any(bDisplay)); + } + + // set presentation + aAny <<= GetContent(); + xField->setPropertyValue(sAPI_current_presentation, aAny); + + // success! + return; + } + catch (const lang::IllegalArgumentException&) + { + TOOLS_WARN_EXCEPTION("xmloff.text", "Failed to insert text content"); + } + } + } + } + } + } + + // above: exit on success; so for all error cases we end up here! + // write element content + GetImportHelper().InsertString(GetContent()); +} + + +// value import helper + +namespace { + +enum ValueType +{ + XML_VALUE_TYPE_STRING, + XML_VALUE_TYPE_FLOAT, + XML_VALUE_TYPE_CURRENCY, + XML_VALUE_TYPE_PERCENTAGE, + XML_VALUE_TYPE_DATE, + XML_VALUE_TYPE_TIME, + XML_VALUE_TYPE_BOOLEAN +}; + +} + +SvXMLEnumMapEntry const aValueTypeMap[] = +{ + { XML_FLOAT, XML_VALUE_TYPE_FLOAT }, + { XML_CURRENCY, XML_VALUE_TYPE_CURRENCY }, + { XML_PERCENTAGE, XML_VALUE_TYPE_PERCENTAGE }, + { XML_DATE, XML_VALUE_TYPE_DATE }, + { XML_TIME, XML_VALUE_TYPE_TIME }, + { XML_BOOLEAN, XML_VALUE_TYPE_BOOLEAN }, + { XML_STRING, XML_VALUE_TYPE_STRING }, + { XML_TOKEN_INVALID, ValueType(0) } +}; + +XMLValueImportHelper::XMLValueImportHelper( + SvXMLImport& rImprt, + XMLTextImportHelper& rHlp, + bool bType, bool bStyle, bool bValue, bool bFormula) : + + rImport(rImprt), + rHelper(rHlp), + + fValue(0.0), + nFormatKey(0), + bIsDefaultLanguage(true), + + bStringType(false), + bFormatOK(false), + bStringValueOK(false), + bFormulaOK(false), + + bSetType(bType), + bSetValue(bValue), + bSetStyle(bStyle), + bSetFormula(bFormula) +{ +} + +void XMLValueImportHelper::ProcessAttribute( + sal_Int32 nAttrToken, std::string_view sAttrValue ) +{ + switch (nAttrToken) + { + case XML_ELEMENT(TEXT, XML_VALUE_TYPE): // #i32362#: src680m48++ saves text:value-type + case XML_ELEMENT(OFFICE, XML_VALUE_TYPE): + { + // convert enum + ValueType eValueType = XML_VALUE_TYPE_STRING; + bool bRet = SvXMLUnitConverter::convertEnum( + eValueType, sAttrValue, aValueTypeMap); + + if (bRet) { + switch (eValueType) + { + case XML_VALUE_TYPE_STRING: + bStringType = true; + break; + case XML_VALUE_TYPE_FLOAT: + case XML_VALUE_TYPE_CURRENCY: + case XML_VALUE_TYPE_PERCENTAGE: + case XML_VALUE_TYPE_DATE: + case XML_VALUE_TYPE_TIME: + case XML_VALUE_TYPE_BOOLEAN: + bStringType = false; + break; + + default: + OSL_FAIL("unknown value type"); + } + } + break; + } + + case XML_ELEMENT(TEXT, XML_VALUE): + case XML_ELEMENT(OFFICE, XML_VALUE): + { + double fTmp; + bool const bRet = ::sax::Converter::convertDouble(fTmp,sAttrValue); + if (bRet) { + fValue = fTmp; + } + break; + } + + case XML_ELEMENT(TEXT, XML_TIME_VALUE): + case XML_ELEMENT(OFFICE, XML_TIME_VALUE): + { + double fTmp; + bool const bRet = + ::sax::Converter::convertDuration(fTmp, sAttrValue); + if (bRet) { + fValue = fTmp; + } + break; + } + + case XML_ELEMENT(TEXT, XML_DATE_VALUE): + case XML_ELEMENT(OFFICE, XML_DATE_VALUE): + { + double fTmp; + bool bRet = rImport.GetMM100UnitConverter(). + convertDateTime(fTmp,sAttrValue); + if (bRet) { + fValue = fTmp; + } + break; + } + + case XML_ELEMENT(OFFICE, XML_BOOLEAN_VALUE): + { + bool bTmp(false); + bool bRet = ::sax::Converter::convertBool(bTmp, sAttrValue); + if (bRet) { + fValue = (bTmp ? 1.0 : 0.0); + } + else + { + double fTmp; + bRet = ::sax::Converter::convertDouble(fTmp, sAttrValue); + if (bRet) { + fValue = fTmp; + } + } + break; + } + + case XML_ELEMENT(TEXT, XML_STRING_VALUE): + case XML_ELEMENT(OFFICE, XML_STRING_VALUE): + sValue = OUString::fromUtf8(sAttrValue); + bStringValueOK = true; + break; + + case XML_ELEMENT(TEXT, XML_FORMULA): + { + OUString sTmp; + sal_uInt16 nPrefix = rImport.GetNamespaceMap(). + GetKeyByAttrValueQName(OUString::fromUtf8(sAttrValue), &sTmp); + if( XML_NAMESPACE_OOOW == nPrefix ) + { + sFormula = sTmp; + bFormulaOK = true; + } + else + sFormula = OUString::fromUtf8(sAttrValue); + } + break; + + case XML_ELEMENT(STYLE, XML_DATA_STYLE_NAME): + { + sal_Int32 nKey = rHelper.GetDataStyleKey( + OUString::fromUtf8(sAttrValue), &bIsDefaultLanguage); + if (-1 != nKey) + { + nFormatKey = nKey; + bFormatOK = true; + } + break; + } + default: + XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttrToken, sAttrValue); + } // switch +} + +void XMLValueImportHelper::PrepareField( + const Reference & xPropertySet) +{ + Any aAny; + + if (bSetType) + { + // ??? how to set type? + } + + if (bSetFormula) + { + aAny <<= !bFormulaOK ? sDefault : sFormula; + xPropertySet->setPropertyValue(sAPI_content, aAny); + } + + // format/style + if (bSetStyle && bFormatOK) + { + xPropertySet->setPropertyValue(sAPI_number_format, Any(nFormatKey)); + + if( xPropertySet->getPropertySetInfo()-> + hasPropertyByName( "IsFixedLanguage" ) ) + { + bool bIsFixedLanguage = ! bIsDefaultLanguage; + xPropertySet->setPropertyValue( "IsFixedLanguage", Any(bIsFixedLanguage) ); + } + } + + // value: string or float + if (bSetValue) + { + if (bStringType) + { + aAny <<= !bStringValueOK ? sDefault : sValue; + xPropertySet->setPropertyValue(sAPI_content, aAny); + } + else + { + xPropertySet->setPropertyValue("Value", Any(fValue)); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/xmlcontentcontrolcontext.cxx b/xmloff/source/text/xmlcontentcontrolcontext.cxx new file mode 100644 index 000000000..a597a28a6 --- /dev/null +++ b/xmloff/source/text/xmlcontentcontrolcontext.cxx @@ -0,0 +1,273 @@ +/* -*- 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 "xmlcontentcontrolcontext.hxx" + +#include + +#include +#include +#include +#include +#include +#include + +#include "XMLTextMarkImportContext.hxx" +#include "txtparai.hxx" + +using namespace com::sun::star; +using namespace xmloff::token; + +XMLContentControlContext::XMLContentControlContext(SvXMLImport& rImport, sal_Int32 /*nElement*/, + XMLHints_Impl& rHints, bool& rIgnoreLeadingSpace) + : SvXMLImportContext(rImport) + , m_rHints(rHints) + , m_rIgnoreLeadingSpace(rIgnoreLeadingSpace) + , m_xStart(GetImport().GetTextImport()->GetCursorAsRange()->getStart()) +{ +} + +void XMLContentControlContext::startFastElement( + sal_Int32 /*nElement*/, const uno::Reference& xAttrList) +{ + for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + bool bTmp = false; + + switch (rIter.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_SHOWING_PLACE_HOLDER): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bShowingPlaceHolder = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_CHECKBOX): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bCheckbox = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_CHECKED): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bChecked = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_CHECKED_STATE): + { + m_aCheckedState = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_UNCHECKED_STATE): + { + m_aUncheckedState = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_PICTURE): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bPicture = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_DATE): + { + if (sax::Converter::convertBool(bTmp, rIter.toView())) + { + m_bDate = bTmp; + } + break; + } + case XML_ELEMENT(LO_EXT, XML_DATE_FORMAT): + { + m_aDateFormat = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_DATE_RFC_LANGUAGE_TAG): + { + m_aDateLanguage = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_CURRENT_DATE): + { + m_aCurrentDate = rIter.toString(); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", rIter); + } + } +} + +void XMLContentControlContext::endFastElement(sal_Int32) +{ + if (!m_xStart.is()) + { + SAL_WARN("xmloff.text", "XMLContentControlContext::endFastElement: no m_xStart"); + return; + } + + uno::Reference xEndRange + = GetImport().GetTextImport()->GetCursorAsRange()->getStart(); + + // Create range for insertion. + uno::Reference xInsertionCursor + = GetImport().GetTextImport()->GetText()->createTextCursorByRange(xEndRange); + xInsertionCursor->gotoRange(m_xStart, /*bExpand=*/true); + + uno::Reference xContentControl + = XMLTextMarkImportContext::CreateAndInsertMark( + GetImport(), "com.sun.star.text.ContentControl", OUString(), xInsertionCursor); + if (!xContentControl.is()) + { + SAL_WARN("xmloff.text", "cannot insert content control"); + return; + } + + uno::Reference xPropertySet(xContentControl, uno::UNO_QUERY); + if (!xPropertySet.is()) + { + return; + } + + if (m_bShowingPlaceHolder) + { + xPropertySet->setPropertyValue("ShowingPlaceHolder", uno::Any(m_bShowingPlaceHolder)); + } + + if (m_bCheckbox) + { + xPropertySet->setPropertyValue("Checkbox", uno::Any(m_bCheckbox)); + } + if (m_bChecked) + { + xPropertySet->setPropertyValue("Checked", uno::Any(m_bChecked)); + } + if (!m_aCheckedState.isEmpty()) + { + xPropertySet->setPropertyValue("CheckedState", uno::Any(m_aCheckedState)); + } + if (!m_aUncheckedState.isEmpty()) + { + xPropertySet->setPropertyValue("UncheckedState", uno::Any(m_aUncheckedState)); + } + if (!m_aListItems.empty()) + { + xPropertySet->setPropertyValue("ListItems", + uno::Any(comphelper::containerToSequence(m_aListItems))); + } + + if (m_bPicture) + { + xPropertySet->setPropertyValue("Picture", uno::Any(m_bPicture)); + } + + if (m_bDate) + { + xPropertySet->setPropertyValue("Date", uno::Any(m_bDate)); + } + if (!m_aDateFormat.isEmpty()) + { + xPropertySet->setPropertyValue("DateFormat", uno::Any(m_aDateFormat)); + } + if (!m_aDateLanguage.isEmpty()) + { + xPropertySet->setPropertyValue("DateLanguage", uno::Any(m_aDateLanguage)); + } + if (!m_aCurrentDate.isEmpty()) + { + xPropertySet->setPropertyValue("CurrentDate", uno::Any(m_aCurrentDate)); + } +} + +css::uno::Reference +XMLContentControlContext::createFastChildContext( + sal_Int32 nElement, const uno::Reference& xAttrList) +{ + switch (nElement) + { + case XML_ELEMENT(LO_EXT, XML_LIST_ITEM): + return new XMLListItemContext(GetImport(), *this); + break; + default: + break; + } + + return XMLImpSpanContext_Impl::CreateSpanContext(GetImport(), nElement, xAttrList, m_rHints, + m_rIgnoreLeadingSpace); +} + +void XMLContentControlContext::characters(const OUString& rChars) +{ + GetImport().GetTextImport()->InsertString(rChars, m_rIgnoreLeadingSpace); +} + +void XMLContentControlContext::AppendListItem(const css::beans::PropertyValues& rListItem) +{ + m_aListItems.push_back(rListItem); +} + +XMLListItemContext::XMLListItemContext(SvXMLImport& rImport, + XMLContentControlContext& rContentControl) + : SvXMLImportContext(rImport) + , m_rContentControl(rContentControl) +{ +} + +void XMLListItemContext::startFastElement( + sal_Int32 /*nElement*/, const uno::Reference& xAttrList) +{ + OUString aDisplayText; + OUString aValue; + + for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList)) + { + switch (rIter.getToken()) + { + case XML_ELEMENT(LO_EXT, XML_DISPLAY_TEXT): + { + aDisplayText = rIter.toString(); + break; + } + case XML_ELEMENT(LO_EXT, XML_VALUE): + { + aValue = rIter.toString(); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", rIter); + } + } + + uno::Sequence aListItem = { + comphelper::makePropertyValue("DisplayText", uno::Any(aDisplayText)), + comphelper::makePropertyValue("Value", uno::Any(aValue)), + }; + m_rContentControl.AppendListItem(aListItem); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/xmlcontentcontrolcontext.hxx b/xmloff/source/text/xmlcontentcontrolcontext.hxx new file mode 100644 index 000000000..2c3ecfb9c --- /dev/null +++ b/xmloff/source/text/xmlcontentcontrolcontext.hxx @@ -0,0 +1,84 @@ +/* -*- 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 + +#include + +#include +#include + +class XMLHints_Impl; + +/// Imports . +class XMLContentControlContext : public SvXMLImportContext +{ + XMLHints_Impl& m_rHints; + + bool& m_rIgnoreLeadingSpace; + + css::uno::Reference m_xStart; + + bool m_bShowingPlaceHolder = false; + + bool m_bCheckbox = false; + bool m_bChecked = false; + OUString m_aCheckedState; + OUString m_aUncheckedState; + std::vector m_aListItems; + bool m_bPicture = false; + bool m_bDate = false; + OUString m_aDateFormat; + OUString m_aDateLanguage; + OUString m_aCurrentDate; + +public: + XMLContentControlContext(SvXMLImport& rImport, sal_Int32 nElement, XMLHints_Impl& rHints, + bool& rIgnoreLeadingSpace); + + void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference& xAttrList) override; + + void SAL_CALL endFastElement(sal_Int32 nElement) override; + + css::uno::Reference SAL_CALL createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference& rAttrList) override; + + void SAL_CALL characters(const OUString& rChars) override; + + void AppendListItem(const css::beans::PropertyValues& rListItem); +}; + +/// Imports inside . +class XMLListItemContext : public SvXMLImportContext +{ + XMLContentControlContext& m_rContentControl; + +public: + XMLListItemContext(SvXMLImport& rImport, XMLContentControlContext& rContentControl); + + void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference& xAttrList) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/xmllinebreakcontext.cxx b/xmloff/source/text/xmllinebreakcontext.cxx new file mode 100644 index 000000000..52bf7920e --- /dev/null +++ b/xmloff/source/text/xmllinebreakcontext.cxx @@ -0,0 +1,59 @@ +/* -*- 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 "xmllinebreakcontext.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace xmloff::token; + +namespace +{ +const SvXMLEnumMapEntry pXML_LineBreakClear_Enum[] = { + { XML_NONE, 0 }, { XML_LEFT, 1 }, { XML_RIGHT, 2 }, { XML_ALL, 3 }, { XML_TOKEN_INVALID, 0 } +}; +} + +SvXMLLineBreakContext::SvXMLLineBreakContext(SvXMLImport& rImport, XMLTextImportHelper& rHelper) + : SvXMLImportContext(rImport) + , m_rHelper(rHelper) +{ +} + +void SvXMLLineBreakContext::startFastElement( + sal_Int32 /*nElement*/, const uno::Reference& xAttrList) +{ + uno::Reference xFactory(GetImport().GetModel(), uno::UNO_QUERY); + if (!xFactory.is()) + return; + + uno::Reference xLineBreak( + xFactory->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); + + sal_Int16 eClear = 0; + OUString aClear = xAttrList->getValue(XML_ELEMENT(LO_EXT, XML_CLEAR)); + if (SvXMLUnitConverter::convertEnum(eClear, aClear, pXML_LineBreakClear_Enum)) + { + uno::Reference xLineBreakProps(xLineBreak, uno::UNO_QUERY); + xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); + } + + m_rHelper.InsertTextContent(xLineBreak); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/text/xmllinebreakcontext.hxx b/xmloff/source/text/xmllinebreakcontext.hxx new file mode 100644 index 000000000..ef1f744bb --- /dev/null +++ b/xmloff/source/text/xmllinebreakcontext.hxx @@ -0,0 +1,31 @@ +/* -*- 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 +#include + +class XMLTextImportHelper; + +/// Handles when the attribute is present. +class XMLOFF_DLLPUBLIC SvXMLLineBreakContext : public SvXMLImportContext +{ + XMLTextImportHelper& m_rHelper; + +public: + SvXMLLineBreakContext(SvXMLImport& rImport, XMLTextImportHelper& rHelper); + +protected: + void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference& xAttrList) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/token/tokens.hxx.head b/xmloff/source/token/tokens.hxx.head new file mode 100644 index 000000000..3a9710606 --- /dev/null +++ b/xmloff/source/token/tokens.hxx.head @@ -0,0 +1,15 @@ +/* -*- 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/. + */ + +#ifndef XMLOFF_TOKEN_TOKENS_HXX +#define XMLOFF_TOKEN_TOKENS_HXX + +#include + +namespace xmloff { diff --git a/xmloff/source/token/tokens.hxx.tail b/xmloff/source/token/tokens.hxx.tail new file mode 100644 index 000000000..2f0f49ca2 --- /dev/null +++ b/xmloff/source/token/tokens.hxx.tail @@ -0,0 +1,6 @@ + +const sal_Int32 XML_TOKEN_INVALID = css::xml::sax::FastToken::DONTKNOW; + +} // namespace xmloff + +#endif diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt new file mode 100644 index 000000000..568122e0f --- /dev/null +++ b/xmloff/source/token/tokens.txt @@ -0,0 +1,3251 @@ +TOKEN_START_DUMMY +CDATA +WS_DUMMY +xml +xmlns +XML_PI_DUMMY +XML_DOCTYPE_PREFIX_DUMMY +XML_DOCTYPE_SUFFIX_DUMMY +N_XML_DUMMY +office +N_OFFICE_DUMMY +N_OFFICE_OLD_DUMMY +NP_META_DUMMY +N_META_DUMMY +N_META_OLD_DUMMY +NP_STYLE_DUMMY +N_STYLE_DUMMY +N_STYLE_OLD_DUMMY +NP_NUMBER_DUMMY +N_NUMBER_DUMMY +N_NUMBER_OLD_DUMMY +NP_TEXT_DUMMY +N_TEXT_DUMMY +N_TEXT_OLD_DUMMY +NP_TABLE_DUMMY +N_TABLE_DUMMY +N_TABLE_OLD_DUMMY +NP_DRAW_DUMMY +N_DRAW_DUMMY +dr3d +N_DR3D_DUMMY +N_DRAW_OLD_DUMMY +NP_PRESENTATION_DUMMY +N_PRESENTATION_DUMMY +N_PRESENTATION_OLD_DUMMY +NP_CHART_DUMMY +N_CHART_DUMMY +config +N_CONFIG_DUMMY +N_CHART_OLD_DUMMY +fo +N_FO_OLD_DUMMY +N_FO_DUMMY +xlink +N_XLINK_DUMMY +N_XLINK_OLD_DUMMY +dc +N_DC_DUMMY +svg +N_SVG_DUMMY +NP_FORM_DUMMY +N_FORM_DUMMY +NP_SCRIPT_DUMMY +N_SCRIPT_DUMMY +tcd +N_TCD_DUMMY +xforms +N_XFORMS_1_0_DUMMY +xsd +N_XSD_DUMMY +xsi +N_XSI_DUMMY +NP_BLOCK_LIST_DUMMY +N_BLOCK_LIST_DUMMY +NP_MATH_DUMMY +N_MATH_DUMMY +VL +N_VERSIONS_LIST_DUMMY +of +N_OF_DUMMY +xhtml +N_XHTML_DUMMY +grddl +N_GRDDL_DUMMY +dsigooo +N_DSIG_OOO_DUMMY +dsig +N_DSIG_DUMMY +ds +N_DS_DUMMY +xades132 +N_XADES132_DUMMY +xades141 +N_XADES141_DUMMY +officeooo +N_OFFICE_EXT_DUMMY +formx +N_FORMX_DUMMY +tableooo +N_TABLE_EXT_DUMMY +drawooo +N_DRAW_EXT_DUMMY +css3t +N_CSS3TEXT_DUMMY +calcext +N_CALC_EXT_DUMMY +loext +N_LO_EXT_DUMMY +N_FIELD_DUMMY +NP_FIELD_DUMMY +m +cm +pt +pc +ft +1 +10 +2 +3 +4 +5 +6 +7 +8 +9 +A +I +IBM437 +IBM850 +IBM860 +IBM861 +IBM863 +IBM865 +ISO-8859-1 +ole2 +_COLON_DUMMY +_EMPTY_DUMMY +_unknown_ +a +abbreviated-name +above +abs +accent +accentunder +acceptance-state +accepted +action +active +active-split-range +active-table +actuate +add-in +add-in-name +address +adjustment +algorithm +align +all +allow-empty-cell +allow-deletes +allow-inserts +allow-updates +alphabetical-index +alphabetical-index-auto-mark-file +alphabetical-index-entry-template +alphabetical-index-mark +alphabetical-index-mark-end +alphabetical-index-mark-start +alphabetical-index-source +alphabetical-separators +alternate +am-pm +ambient-color +anchor-page-number +anchor-type +and +animation +animation-delay +animation-direction +animation-repeat +animation-start-inside +animation-steps +animation-stop-inside +animations +annotation +annotation-end +annotations +annote +appear +applet +applet-name +application-data +application-xml +apply +apply-design-mode +apply-style-name +aqua +arc +arccos +archive +arcsin +arctan +area +area-circle +area-polygon +area-rectangle +article +as-char +ascending +attached-axis +attractive +author +author-initials +author-name +auto +auto-complete +auto-grow-height +auto-grow-width +auto-reload +auto-text +auto-text-events +auto-text-group +auto-text-indent +auto-update +automatic +automatic-find-labels +automatic-focus +automatic-order +automatic-styles +automatic-update +autosize +average +averaged-abscissa +axis +axis-color +back-scale +backface-culling +background +background-color +background-image +no-repeat +bar +base64Binary +base-cell-address +baseline +before-date-time +below +between-date-times +bevel +bevelled +bibiliographic-type +bibliography +bibliography-configuration +bibliography-data-field +bibliography-entry-template +bibliography-mark +bibliography-source +bibliography-type +bind-styles-to-content +bitmap +bitmap-table +black +blend +blinking +block +block-list +blue +body +bold +book +booklet +bookmark +bookmark-end +bookmark-ref +bookmark-start +booktitle +boolean +boolean-style +boolean-value +border +border-bottom +border-color +border-left +border-line-width +border-line-width-bottom +border-line-width-left +border-line-width-right +border-line-width-top +border-right +border-top +both +bottom +bottom-left +BOTTOM_PERCENT_DUMMY +bottom-right +BOTTOM_VALUES_DUMMY +bottom-arc +bottom-circle +bound-column +break-after +break-before +break-inside +bubble +bullet-char +bullet-relative-size +butt +button1 +button2 +button3 +button4 +buttons +button-type +bvar +c +calculation-settings +calendar +capitalize-entries +can-add-comment +caption +caption-point-x +caption-point-y +caption-sequence-format +caption-sequence-name +case-sensitive +capitalize +lowercase +small-caps +uppercase +categories +category +category-and-value +cell-address +cell-content-change +cell-content-deletion +cell-count +cell-protect +cell-range-address +cell-range-address-list +cell-range-source +center +central +chain-next-name +change +change-deletion +change-end +change-id +change-info +change-start +change-track-table-cell +change-view-conditions +change-view-settings +changed-region +chapter +char +char-shading-value +character-count +chart +charts +checkerboard +chg-author +chg-comment +chg-date-time +ci +circle +citation-body-style-name +citation-style-name +class +class-id +clip +clockwise +close +close-horizontal +close-vertical +cn +code +codebase +collapse +color +color-axis +color-first +color-high +color-inversion +color-last +color-low +color-markers +color-mode +color-negative +color-series +color-scale +color-scale-entry +color-table +column +column-count +column-gap +column-name +column-sep +column-width +columnalign +columns +avoid +combine-entries +combine-entries-with-dash +combine-entries-with-pp +comma-separated +command +comment +compose +cond-style-name +condition +condition-source +condition-source-range-address +conditional-text +conditional-format +conditional-formats +cone +conference +config-item +config-item-map-entry +config-item-map-indexed +config-item-map-named +config-item-set +configuration-settings +conjugate +connect-bars +connection-name +connector +consecutive-numbering +consolidation +constant +contains-error +contains-header +content +content-validation +content-validation-name +content-validations +contextual-spacing +continue +continue-numbering +contour-path +contour-polygon +contrast +control +conversion-mode +conversion-type +convert-empty-to-null +copy-back +copy-formulas +copy-outline-levels +copy-results-only +copy-styles +corner-radius +correct +cos +cosh +cot +coth +count +count-empty-lines +count-in-floating-frames +counter-clockwise +counterclockwise +countnums +country +country-asian +country-complex +covered-table-cell +create-date +create-date-string +creation-date +creation-time +creator +csc +csch +cube +cuboid +currency +currency-style +currency-symbol +current +current-value +cursor-position +cursor-position-x +cursor-position-y +curve +custom1 +custom2 +custom3 +custom4 +custom5 +custom-iconset +custom-iconset-index +custom-iconset-name +custom-label-field +custom-label-pos-x +custom-label-pos-y +custom-leader-lines +cut +cut-offs +cut_offs +cx +cy +cylinder +d +dash +dash-dot +dash-dot-dot +dash-table +dashed +data +data-bar +data-bar-entry +data-cell-range-address +data-label +data-label-guid +data-label-number +data-label-symbol +data-label-text +data-label-series +data-labels-cell-range +data-pilot-source +data-pilot-field +data-pilot-grand-total +data-pilot-level +data-pilot-member +data-pilot-members +data-pilot-subtotal +data-pilot-subtotals +data-pilot-table +data-pilot-tables +data-point +data-range +data-stream-source +data-style +data-style-name +data-type +database-display +database-name +database-next +database-range +database-ranges +database-row-number +database-select +database-source-query +database-source-sql +database-source-table +database-table-name +date +date-axis +date-is +date-adjust +date-style +date-time +date-time-update +date-time-visible +date-value +datetime +day +day-of-week +dde-application +dde-connection +dde-connection-decl +dde-connection-decls +dde-item +dde-link +dde-links +dde-source +dde-topic +decimal-places +decimal-replacement +declare +decorate-words-only +decorative +deep +default +default-button +default-cell-style-name +default-style +default-style-name +degree +delay +delay-for-repeat +delete-columns +delete-rows +deletion +deletions +denomalign +denominator-value +dependence +dependences +dependencies +depth +desc +descending +description +detective +determinant +diff +diffuse-color +dim +direction +disabled +disc +display +display-border +display-details +display-duplicates +display-empty +display-empty-cells-as +display-filter-buttons +display-formula +display-hidden +display-label +display-levels +display-name +display-outline-level +display-x-axis +dissolve +distance +distance-after-sep +distance-before-sep +distribute +distribute-letter +distribute-space +divide +document +document-content +document-meta +document-settings +document-statistic +document-styles +domain +dot +dots1 +dots1-length +dots2 +dots2-length +dotted +double +double-sided +double-thin +down +draft +draw +ole-draw-aspect +drawing +drawings +drawpool +dropdown +drop-cap +dynamic +echo-char +edge-rounding +editable +editing-cycles +editing-duration +edition +editor +effect +ellipse +email +embed +embedded-visible-area +embossed +emissive-color +empty +empty-line-refresh +enable-numbering +enabled +encoding +enctype +end +end-angle +end-cell-address +end-color +end-column +end-glue-point +end-guide +end-intensity +end-line-spacing-horizontal +end-line-spacing-vertical +end-position +end-row +end-shape +end-table +end-x +end-y +endless +endnote +endnote-body +endnote-citation +endnote-ref +endnotes-configuration +engraved +entry +eq +equal-author +equal-comment +equal-date +era +ergo-sum +error-category +error-lower-indicator +error-lower-limit +error-macro +error-margin +error-message +error-percentage +error-upper-indicator +error-upper-limit +sub +super +even-page +event +event-name +events +execute +execute-macro +exists +exp +exponential +expression +extra +extrude +factorial +fade +fade-from-bottom +fade-from-center +fade-from-left +fade-from-lowerleft +fade-from-lowerright +fade-from-right +fade-from-top +fade-from-upperleft +fade-from-upperright +fade-out +fade-to-center +false +family +fast +fence +field-number +file-name +fill +fill-character +fill-color +fill-gradient-name +fill-hatch-name +fill-hatch-solid +fill-image +fill-image-height +fill-image-name +fill-image-ref-point +fill-image-ref-point-x +fill-image-ref-point-y +fill-image-width +fill-rule +filter +filter-and +filter-condition +filter-name +filter-options +filter-or +filter-set-item +fine-dashed +first-date-time +first-page +first-page-number +fit-to-contour +fit-to-size +fix +fixed +flat +float +floating-frame +floor +fn +focal-length +focus-on-click +font-char-width +font-charset +font-charset-asian +font-charset-complex +font-color +font-decl +font-decls +font-family +font-family-asian +font-family-complex +font-family-generic +font-family-generic-asian +font-family-generic-complex +font-kerning +font-name +font-name-asian +font-name-complex +font-pitch +font-pitch-asian +font-pitch-complex +font-relief +font-size +font-size-asian +font-size-complex +font-size-rel +font-size-rel-asian +font-size-rel-complex +font-style +font-style-asian +font-style-complex +font-style-name +font-style-name-asian +font-style-name-complex +font-variant +font-weight +font-weight-asian +font-weight-complex +font-width +font-word-line-mode +fontfamily +fontsize +fontstyle +fontweight +fontwork-adjust +fontwork-distance +fontwork-form +fontwork-hide-form +fontwork-mirror +fontwork-outline +fontwork-shadow +fontwork-shadow-color +fontwork-shadow-offset-x +fontwork-shadow-offset-y +fontwork-shadow-transparence +fontwork-start +fontwork-style +footer +footer-first +footer-left +footer-style +footer-visible +footnote +footnote-body +footnote-citation +footnote-continuation-notice-backward +footnote-continuation-notice-forward +footnote-max-height +footnote-ref +footnote-sep +footnotes-configuration +footnotes-position +for +forall +force-manual +foreground +foreign-object +format-change +format-source +formatting-entry +forms +formula +formula-hidden +formulas +fraction +frame +frame-content +frame-display-border +frame-display-scrollbar +frame-end-margin +frame-margin-horizontal +frame-margin-vertical +frame-name +frame-start-margin +freeze +freeze-position +from-another-table +from-bottom +from-center +from-inside +from-left +from-lower-left +from-lower-right +from-right +from-same-table +from-top +from-upper-left +from-upper-right +fuchsia +full +full-screen +function +fx +fy +g +gamma +gap +gap-width +gcd +generator +geq +glow-radius +glow-color +glow-transparency +gouraud +gradient +angle +gradient-step-count +gradient-style +gradient-table +axial +ellipsoid +radial +rectangular +square +gradientTransform +grand-total +graphic +gray +green +greyscale +grid +groove +group-by-field-number +group-name +grouping +gt +guide-distance +guide-overhang +h +hanging +has-persistent-data +hatch +hatch-table +triple +header +header-first +header-left +header-style +headers +height +help +help-file-name +help-id +help-message +hidden +hidden-and-protected +hidden-paragraph +hidden-text +hide +hide-legend +hide-shape +hide-text +highlighted-range +hint +horizontal +horizontalstrike +horizontal-lines +horizontal-on-left-pages +horizontal-on-right-pages +horizontal-pos +horizontal-rel +horizontal-scrollbar-width +horizontal-segments +horizontal-split-mode +horizontal-split-position +horizontal-stripes +hours +howpublished +href +html +hyperlink +hyperlink-behaviour +hyphenate +hyphenation-keep +hyphenation-ladder-count +hyphenation-push-char-count +hyphenation-remain-char-count +hyphenation-no-caps +hyphenation-no-last-word +hyphenation-word-char-count +hyphenation-zone +i +icon +icon-set +icon-set-type +id +ident +identifier +identify-categories +ideograph-alpha +ignore-case +ignore-empty-rows +ignore-result +ignore-selected-page +illustration-index +illustration-index-entry-template +illustration-index-source +image +image-count +image-map +implies +in +in-range +inbook +incollection +increment +index +index-body +index-entry-bibliography +index-entry-chapter +index-entry-chapter-number +index-entry-link-end +index-entry-link-start +index-entry-page-number +index-entry-span +index-entry-tab-stop +index-entry-template +index-entry-text +index-name +index-scope +index-source-style +index-source-styles +index-title +index-title-template +information +initial-creator +inproceedings +input-required +insert-columns +insert-rows +insertion +insertion-cut-off +insertion-position +inset +inside +institution +int +intensity +inter-character +intersect +interval +interval-major +interval-minor +into-english-number +inverse +is-active +is-data-layout-field +is-hidden +is-selection +isbn +italic +item +iteration +journal +justified +justify +justify-single-word +keep-with-next +key +key1 +key2 +keyword +keywords +kind +km +label +label-arrangement +label-cell-address +label-cell-range-address +label-fill +label-fill-color +label-range +label-ranges +label-string +label-stroke +label-stroke-color +label-stroke-opacity +label-stroke-width +lambda +landscape +lang +language +language-asian +language-complex +laser +last-column-spanned +last-page +last-row-spanned +layer +layer-set +leader-char +left +left-outside +left-text +left-top-position +left-arc +left-circle +legend +legend-position +length +leq +let-text +keep-text +letter-kerning +letter-spacing +letters +level +library +library-embedded +library-linked +light +lighting-mode +lime +limit +line +line-break +clear +line-distance +line-height +line-height-at-least +line-number +line-skew +line-spacing +line-style +line-width +linear +linearGradient +linenumbering-configuration +linenumbering-separator +lines +lines-used +linked-cell +link-to-source-data +list +list-block +list-header +list-info +list-item +list-level +list-level-style-bullet +list-level-style-image +list-level-style-number +list-linkage-type +list-name +list-style +list-style-name +ln +locked +log +logarithmic +logbase +long +low +lowlimit +lr-tb +lt +ltr +luminance +macro-name +maction +main-entry-style-name +major +major-origin +maligngroup +malignmark +manual +manual-min +manual-max +map +margin-bottom +margin-left +margin-right +margin-top +margins +marker +markers +marker-end +marker-end-center +marker-end-width +marker-start +marker-start-center +marker-start-width +marker-table +maroon +master-page +master-page-name +master-styles +mastersthesis +match +math +matrix +matrix-covered +matrixrow +max +max-axis-type +max-edge +max-height +max-length +max-width +maximum +maximum-difference +may-break-between-rows +may-script +mean +mean-value +measure +measure-align +measure-vertical-align +median +medium +menclose +merror +message-type +meta +mfenced +mfrac +mi +middle +mime-type +min +min-axis-type +min-denominator-digits +min-edge +min-exponent-digits +min-height +min-integer-digits +min-label-distance +min-label-width +min-length +min-line-height +min-numerator-digits +min-row-height +min-width +minimum +minor +minus +minutes +mirror +mirrored +misc +miter +mm +mmultiscripts +mn +mo +mode +modern +modification-date +modification-time +modulate +module +moment +mono +month +mouse-as-pen +mouse-visible +move +move-from-bottom +move-from-left +move-from-right +move-from-top +move-protect +move-short +movement +movement-cut-off +mover +moving-average +mpadded +mphantom +mprescripts +mroot +mrow +ms +mspace +msqrt +mstyle +msub +msubsup +msup +mtable +mtd +mtext +mtr +multi-deletion-spanned +multi-line +multiple +munder +munderover +name +name-and-extension +named-expression +named-expressions +named-range +navigation-mode +navy +negative +negative-color +neq +new +next +next-page +next-style-name +no-limit +no-wrap +NOEMPTY_DUMMY +nohref +NOMATCH_DUMMY +non-whitespace-character-count +none +normal +normals-direction +normals-kind +not +not-equal-date +notation +note +notes +notin +notprsubset +notsubset +null-date +null-year +num-format +num-letter-sync +num-list-format +num-prefix +num-suffix +numalign +number +number-and-name +number-columns-repeated +number-columns-spanned +number-lines +number-matrix-columns-spanned +number-matrix-rows-spanned +number-position +number-rows-repeated +number-rows-spanned +number-style +number-wrapped-paragraphs +numbered-entries +object +object-count +object-index +object-index-entry-template +object-index-source +object-name +object-ole +objects +odd-page +offset +olive +onLoad +onRequest +on-update-keep-size +on-update-keep-styles +online +online-text +open +open-horizontal +open-vertical +operation +operator +optimal +option +or +order +ordered-list +organizations +orientation +orientation-landscape +orientation-portrait +origin +orphans +outline-content-visible +outline-level +outline-level-style +outline-style +outset +outside +overlap +overlay +p +package-name +padding +padding-bottom +padding-left +padding-right +padding-top +page +page-adjust +page-breaks-on-group-change +page-content +page-continuation-string +page-count +page-end-margin +page-height +page-master +page-master-name +page-name +page-number +page-number-visible +page-start-margin +page-step-size +page-style-name +page-thumbnail +page-usage +page-variable-get +page-variable-set +page-view-zoom-value +page-width +pages +paper-tray-number +paragraph +paragraph-content +paragraph-count +paragraph-end-margin +paragraph-start-margin +parallel +param +parent-style-name +parse-sql-statement +parsed +partialdiff +password +passwort +path +path-id +pause +pending +percentage +percentage-style +perspective +phdthesis +phong +velocity-x +velocity-y +density +bounciness +pie-offset +placeholder +placeholder-type +placing +plain-number +plain-number-and-name +play-full +plot-area +plugin +plus +points +polygon +polyline +polynomial +pool-id +portrait +position +position-bottom +position-left +position-right +position-top +positive-color +oblique +power +precision-as-shown +prefix +infix +postfix +presentation +orgchart +outline +presentation-page-layout +presentation-page-layout-name +previous +previous-page +print +print-content +print-date +print-orientation +print-page-order +print-range +print-ranges +print-time +printable +printed-by +prior +proceedings +product +projection +properties +protect +protected +protection-key +protection-key-digest-algorithm +protection-key-digest-algorithm-2 +prsubset +publisher +punctuation-wrap +purple +pyramid +qrcode +qrcode-border +qrcode-errorcorrection +qrcode-type +quarter +query-name +quo-vadis +quotient +r +radar +random +range-address +range-usable-as +recreate-on-edit +rect +red +ref-name +reference +reference-end +reference-format +reference-mark +reference-mark-end +reference-mark-start +reference-ref +reference-start +reference-type +refresh-delay +region-center +region-left +region-right +register-true +register-truth-ref-style-name +rejected +rejecting-change-id +rejection +rel-column-width +rel-height +rel-height-rel +rel-width +rel-width-rel +relative +relative-tab-stop-position +reln +rem +remove-dependents +remove-precedents +repeat +repeat-column +repeat-row +repeated +replace +report-type +restart-on-page +revision +ridge +right +right-outside +right-text +right-to-left +right-arc +right-circle +ring +role +roll-from-bottom +roll-from-left +roll-from-right +roman +root +rotate +rotation +rotation-align +rotation-angle +round +row +row-height +row-number +rows +rsid +paragraph-rsid +ruby +ruby-align +ruby-base +ruby-position +ruby-text +run-through +rx +ry +s +scale +scale-min +scale-text +scale-to +scale-to-pages +scatter +scenario +scenario-ranges +scene +school +scientific-number +score-spaces +script +script-asian +script-complex +scroll +sdev +search-criteria-must-apply-to-whole-cell +sec +sech +second-date-time +seconds +section +section-desc +section-name +section-source +select-page +select-protected-cells +select-unprotected-cells +selector +semantics +semi-automatic +sender-city +sender-company +sender-country +sender-email +sender-fax +sender-firstname +sender-initials +sender-lastname +sender-phone-private +sender-phone-work +sender-position +sender-postal-code +sender-state-or-province +sender-street +sender-title +sep +separation-character +separator +sequence +sequence-decl +sequence-decls +sequence-ref +series +series-source +server-map +set +setdiff +settings +shade-mode +shadow +shadow-color +shadow-offset-x +shadow-offset-y +shadow-slant +shadow-transparency +shadow-blur +shape +shape-id +shapes +sheet-name +shininess +short +show +show-accepted-changes +show-changes +show-changes-by-author +show-changes-by-author-name +show-changes-by-comment +show-changes-by-comment-text +show-changes-by-datetime +show-changes-by-datetime-first-datetime +show-changes-by-datetime-mode +show-changes-by-datetime-second-datetime +show-changes-by-ranges +show-changes-by-ranges-list +show-logo +show-rejected-changes +show-shape +show-text +show-unit +show-value +shows +side-by-side +silver +simple +sin +since-date-time +since-save +sinh +size +size-protect +slant +slant-x +slant-y +slide +slow +softedge-radius +solid +solid-type +sort +sort-ascending +sort-by +sort-by-position +sort-groups +sort-key +sound +source-cell-range +source-cell-range-addresses +source-field-name +source-name +source-range-address +source-service +space-before +sparkline-groups +sparkline-group +sparklines +sparkline +span +specular +specular-color +speed +sphere +spiral +spiral-in +spiral-inward-left +spiral-inward-right +spiral-out +spiral-outward-left +spiral-outward-right +spiralin-left +spiralin-right +spiralout-left +spiralout-right +splines +split +split-column +split-position +split-row +spreadsheet +spreadMethod +sql-statement +stacked +stagger-even +stagger-odd +standard +standard-deviation +starbasic +start +start-angle +start-color +start-column +start-glue-point +start-guide +start-intensity +start-line-spacing-horizontal +start-line-spacing-vertical +start-numbering-at +start-page +start-position +start-row +start-scale +start-shape +start-table +start-value +start-with-navigator +state +statistics +status +stay-on-top +stdev +stdevp +steps +step-size +stock +stock-updown-bars +stock-with-volume +stop +stop-color +stop-opacity +stretch +stretch-from-bottom +stretch-from-left +stretch-from-right +stretch-from-top +stretchy +strict +string +string-value +string-value-if-false +string-value-if-true +stripes +stroke +stroke-color +stroke-dash +stroke-linecap +stroke-linejoin +stroke-opacity +stroke-width +structure-protected +style +style-name +styles +stylesheet +sub-table +subject +subset +subtitle +subtotal-field +subtotal-rule +subtotal-rules +sub-view-size +suffix +sum +swiss +symbol +symbol-height +symbol-image-name +symbol-width +system +tab-color +tab-cycle +tab-index +tab-stop +tab-stop-distance +tab-stops +table +table-background +table-cell +table-centering +table-column +table-column-group +table-columns +table-count +table-header +table-header-columns +table-header-rows +table-index +table-index-entry-template +table-index-source +table-name +table-of-content +table-of-content-entry-template +table-of-content-source +table-page +table-protection +table-row +table-row-group +table-rows +table-source +table-view +tables +tan +tanh +target-cell-address +target-frame +target-frame-name +target-range-address +tb-rl +teal +techreport +template +template-name +tendsto +texture-filter +texture-generation-mode-x +texture-generation-mode-y +texture-kind +texture-mode +text +text-align +text-align-last +text-align-source +text-autospace +text-background-color +text-blinking +text-box +text-changes-only +text-color +text-combine +text-combine-end-char +text-combine-start-char +text-content +text-conversion-dictionary +text-crossing-out +text-emphasize +text-global +text-indent +text-input +text-justify +text-outline +text-only +text-position +text-rotation-angle +text-rotation-scale +text-scale +text-shadow +text-style +text-transform +text-underline +text-underline-color +textarea-horizontal-align +textarea-vertical-align +textual +thick +thin +three-dimensional +thumbnail +tick-marks-major-inner +tick-marks-major-outer +tick-marks-minor-inner +tick-marks-minor-outer +tile-repeat-offset +time +time-adjust +time-style +time-value +times +title +to-another-table +to-bottom +to-center +to-left +to-lower-left +to-lower-right +to-right +to-top +to-upper-left +to-upper-right +toc-mark +toc-mark-end +toc-mark-start +toggle +top +top-left +TOP_PERCENT_DUMMY +top-right +TOP_VALUES_DUMMY +top-arc +top-circle +trace-dependents +trace-errors +trace-precedents +track-changes +tracked-changes +tracked-changes-view-settings +transform +transition-on-click +transparency +transparency-name +transparent +transpose +true +truncate-on-overflow +try-staggering-first +tspan +ttb +type +dot-dash +dot-dot-dash +long-dash +show-sign-date +signatureline +signing-instructions +single +small-wave +suggested-signer-email +suggested-signer-name +suggested-signer-title +wave +unformatted-text +union +unit +unordered-list +unpublished +up +uplimit +upright +url +use +use-caption +use-cell-protection +use-chart-objects +use-condition +use-draw-objects +use-floating-frames +use-graphics +use-image-objects +use-index-marks +use-index-source-styles +use-keys-as-entries +use-label +use-math-objects +use-objects +use-optimal-column-width +use-optimal-row-height +use-other-objects +use-spreadsheet-objects +use-styles +use-tables +use-window-font-color +used-hierarchy +user-defined +user-field-decl +user-field-decls +user-field-get +user-field-input +user-index +user-index-entry-template +user-index-mark +user-index-mark-end +user-index-mark-start +user-index-source +user-transformed +username +validation +value +value-type +values-cell-range-address +var +variable +variable-decl +variable-decls +variable-get +variable-input +variable-set +variance +varp +vector +verb +version +version-entry +version-list +vertical +vertical-align +vertical-justify +vertical-lines +vertical-pos +vertical-rel +vertical-segments +vertical-split-mode +vertical-split-position +vertical-stripes +view +viewBox +view-id +view-settings +visibility +visible +visible-area +visible-area-height +visible-area-left +visible-area-top +visible-area-width +visited-style-name +visual-effect +volatile +volume +vpn +vrp +vup +wall +warning +watermark +wavyline +wavyline-from-bottom +wavyline-from-left +wavyline-from-right +wavyline-from-top +week-of-year +white +whole-page +widows +width +window-font-color +word +word-count +wrap +wrap-contour +wrap-contour-mode +wrap-option +writing-mode +www +x +x1 +x2 +x-mac-roman +x-symbol +x-system +xor +y +y1 +y2 +year +yellow +zero-values +z-index +zoom-type +zoom-value +enable +use-regular-expressions +use-wildcards +data-source-has-labels +link-data-style-to-source +sort-algorithm +straight-line +angled-line +angled-connector-line +APPLICATION_X_WWW_FORM_URLENCODED_DUMMY +MULTIPART_FORMDATA_DUMMY +APPLICATION_TEXT_DUMMY +get +post +query +parent +records +push +submit +reset +value-list +sql +sql-pass-through +table-fields +unchecked +checked +unknown +roll-from-top +binary-data +notify-on-update-of-table +0 +play +handout-master +text-style-name +escape-direction +glue-point +primary-x +secondary-x +primary-y +secondary-y +primary-z +caption-type +caption-angle-type +caption-angle +caption-gap +caption-escape-direction +caption-escape +caption-line-length +caption-fit-line-length +free +transition-type +transition-style +transition-speed +duration +background-size +background-objects-visible +background-visible +move-from-upperleft +move-from-upperright +move-from-lowerright +move-from-lowerleft +uncover-to-left +uncover-to-upperleft +uncover-to-top +uncover-to-upperright +uncover-to-right +uncover-to-lowerright +uncover-to-bottom +uncover-to-lowerleft +vertical-checkerboard +horizontal-checkerboard +notify-on-update-of-ranges +byte +macro +location +application +symbol-image +text-overlap +spline-order +spline-resolution +paper-tray-name +column-mapping +row-mapping +table-formula +embedded-text +merge-last-paragraph +stock-loss-marker +stock-gain-marker +stock-range-line +rl-tb +tb-lr +bt-lr +lr +rl +tb +layout-grid-color +layout-grid-lines +layout-grid-base-height +layout-grid-ruby-height +layout-grid-mode +layout-grid-ruby-below +layout-grid-print +layout-grid-display +default-page-layout +layout-grid-standard-mode +layout-grid-base-width +layout-grid-snap-to-characters +layout-grid-snap-to +snap-to-layout-grid +dont-balance-text-columns +glyph-orientation-vertical +marked-invalid +regression-curve +regression-type +regression-name +regression-extrapolate-forward +regression-extrapolate-backward +regression-max-degree +regression-min-degree +regression-moving-type +regression-period +regression-force-intercept +regression-intercept-value +regression-x-name +regression-y-name +error-indicator +table-type +display-factor +transliteration-format +transliteration-language +transliteration-country +transliteration-style +key1-phonetic +key2-phonetic +string-value-phonetic +background-transparency +background-image-transparency +dynamic-spacing +main-entry +use-outline-level +close-front +close-back +drop-down +current-selected +join-border +display-list +no +unsorted +font-independent-line-spacing +sorted-ascending +database +datasource +data-source +queries +reports +report +as-template +connection-resource +suppress-version-columns +java-driver-class +extension +is-first-row-header-line +show-deleted +is-table-name-length-limited +system-driver-settings +enable-sql92-check +append-table-alias-name +parameter-name-substitution +ignore-driver-privileges +boolean-comparison-mode +use-catalog +base-dn +max-row-count +login +user-name +is-password-required +login-timeout +delimiter +field +decimal +thousand +table-filter +table-filter-pattern +table-type-filter +auto-increment +additional-column-statement +row-retrieving-statement +data-source-settings +data-source-setting +data-source-setting-value +data-source-setting-is-list +data-source-setting-type +data-source-setting-name +component +component-collection +query-collection +update-table +filter-statement +order-statement +escape-processing +keys +indices +type-name +precision +is-nullable +is-autoincrement +default-value +referenced-table-name +update-rule +delete-rule +key-columns +key-column +related-column-name +catalog-name +is-unique +is-clustered +index-columns +index-column +is-ascending +schema-name +db +N_DB_DUMMY +apply-filter +apply-order +automatic-print-range +selection +selection-indexes +scale-to-X +scale-to-Y +keep-together +use-header-name +use-footer-name +use-date-time-name +display-header +display-footer +display-page-number +display-date-time +source +current-date +header-decl +footer-decl +date-time-decl +selected-page +flow-with-text +with-tab +custom-shape +engine +enhanced-geometry +text-rotate-angle +mirror-vertical +mirror-horizontal +extrusion-allowed +text-path-allowed +concentric-gradient-fill-allowed +extrusion +extrusion-brightness +extrusion-depth +extrusion-diffusion +extrusion-number-of-line-segments +extrusion-light-face +extrusion-first-light-harsh +extrusion-second-light-harsh +extrusion-first-light-level +extrusion-second-light-level +extrusion-first-light-direction +extrusion-second-light-direction +extrusion-metal +extrusion-metal-type +extrusion-rotation-angle +extrusion-rotation-center +extrusion-shininess +extrusion-skew +extrusion-specularity +extrusion-specularity-loext +extrusion-projection-mode +extrusion-viewpoint +extrusion-origin +extrusion-color +secondary-fill-color +enhanced-path +path-stretchpoint-x +path-stretchpoint-y +text-areas +glue-points +glue-point-type +glue-point-leaving-direction +text-path +text-path-mode +text-path-scale +text-path-same-letter-heights +modifiers +equation +xstretch +ystretch +hasstroke +hasfill +logwidth +logheight +handle +handle-mirror-vertical +handle-mirror-horizontal +handle-switched +handle-position +handle-range-x-minimum +handle-range-x-maximum +handle-range-y-minimum +handle-range-y-maximum +handle-polar +handle-radius-range-minimum +handle-radius-range-maximum +rectangle +roundrectangle +oval +cloud +boundingcube +wireframe +segments +word-wrap +collapsing +separating +border-model +data-pilot-field-reference +member-difference +member-percentage +member-percentage-difference +running-total +row-percentage +column-percentage +total-percentage +field-name +member-type +named +member-name +display-member-mode +member-count +data-field +data-pilot-display-info +sort-mode +data-pilot-sort-info +add-empty-lines +tabular-layout +outline-subtotals-top +outline-subtotals-bottom +layout-mode +data-pilot-layout-info +symbol-color +3d +image-position +image-align +diagonal-bl-tr +diagonal-bl-tr-width +diagonal-tl-br +diagonal-tl-br-width +repeat-content +shrink-to-fit +wrap-influence-on-position +once-successive +once-concurrent +allow-overlap +N_OFFICE_OOO_DUMMY +N_META_OOO_DUMMY +N_STYLE_OOO_DUMMY +N_NUMBER_OOO_DUMMY +N_TEXT_OOO_DUMMY +N_TABLE_OOO_DUMMY +N_DRAW_OOO_DUMMY +N_DR3D_OOO_DUMMY +N_PRESENTATION_OOO_DUMMY +N_PRESENTATION_OASIS_DUMMY +N_CHART_OOO_DUMMY +N_CONFIG_OOO_DUMMY +N_FORM_OOO_DUMMY +N_SCRIPT_OOO_DUMMY +global +note-class +note-citation +note-body +notes-configuration +note-ref +is-sub-table +page-layout +page-layout-name +graphic-properties +drawing-page-properties +page-layout-properties +header-footer-properties +text-properties +paragraph-properties +ruby-properties +section-properties +table-properties +table-column-properties +table-row-properties +table-cell-properties +list-level-properties +chart-properties +drawing-page +graphics +tab +text-underline-mode +text-line-through-mode +continuous +skip-white-space +scripts +font-face-decls +font-face +font-face-src +font-face-uri +font-face-format +font-adornments +inch +space-after +start-indent +end-indent +interval-minor-divisor +date-string +text-underline-style +text-underline-type +text-underline-width +text-overline-type +text-overline-style +text-overline-width +text-overline-color +text-overline-mode +text-line-through-style +text-line-through-type +text-line-through-width +text-line-through-text +leader-style +leader-text +bold-dotted +bold-dash +bold-long-dash +bold-dot-dash +bold-dot-dot-dash +bold-wave +double-wave +double-line +thick-line +single-line +slash +text-line-through-color +text-line-through-text-style +leader-color +leader-type +leader-width +leader-text-style +opacity +opacity-name +shadow-opacity +always +count-in-text-boxes +ooo +N_OOO_DUMMY +ooow +N_OOOW_DUMMY +oooc +N_OOOC_DUMMY +dom +N_DOM_DUMMY +event-listeners +event-listener +form +void +property +property-name +list-property +list-value +column-style-name +textarea +fixed-text +file +formatted-text +button +checkbox +radio +listbox +combobox +image-frame +value-range +generic-control +service-name +property-type +integer +property-is-void +property-is-list +property-value +mimetype +database-row-select +control-implementation +interpolation +cubic-spline +b-spline +step-start +step-end +step-center-x +step-center-y +GNM_STEP_START_DUMMY +GNM_STEP_END_DUMMY +GNM_STEP_CENTER_X_DUMMY +GNM_STEP_CENTER_Y_DUMMY +N_DB_OASIS_DUMMY +show-filter-button +drill-down-on-double-click +header-grid-layout +grouped-by +days +months +quarters +years +date-start +date-end +step +data-pilot-groups +data-pilot-group +data-pilot-group-member +japanese-candle-stick +named-symbol +diamond +arrow-down +arrow-up +arrow-right +arrow-left +bow-tie +hourglass +symbol-name +symbol-type +image-opacity +default-outline-level +show-details +show-empty +repeat-item-labels +iterative +X +dlg +N_DLG_DUMMY +script-data +libraries +source-code +readonly +z +dimension +validation-name +screen +printer +model +schema +bind +instance +submission +ref +src +method +nodeset +indent +omit-xml-declaration +standalone +cdata-section-elements +required +relevant +calculate +constraint +maxOccurs +minOccurs +p3ptype +mediatype +includenamespaceprefixes +base +targetNamespace +simpleType +restriction +maxLength +minLength +minInclusive +minExclusive +maxInclusive +maxExclusive +pattern +enumeration +whiteSpace +totalDigits +fractionDigits +preserve +anyURI +dateTime +main-etry +remove +hold +transition +inherit +fillDefault +restart +restartDefault +whenNotActive +never +accelerate +decelerate +autoReverse +indefinite +repeatCount +repeatDur +endsync +first +last +media +dur +begin +whole +from +to +by +values +keyTimes +keySplines +calcMode +discrete +paced +spline +accumulate +additive +multiply +animate +animateMotion +animatePhysics +animateTransform +animateColor +transitionFilter +attributeName +smil +N_SMIL_DUMMY +anim +N_ANIMATION_DUMMY +N_ANIMATION_OOO_DUMMY +par +seq +translate +skewX +skewY +audio +color-interpolation +color-interpolation-direction +hsl +rgb +barWipe +boxWipe +fourBoxWipe +barnDoorWipe +diagonalWipe +bowTieWipe +miscDiagonalWipe +veeWipe +barnVeeWipe +zigZagWipe +barnZigZagWipe +irisWipe +triangleWipe +arrowHeadWipe +pentagonWipe +hexagonWipe +ellipseWipe +eyeWipe +roundRectWipe +starWipe +miscShapeWipe +clockWipe +pinWheelWipe +singleSweepWipe +fanWipe +doubleFanWipe +doubleSweepWipe +saloonDoorWipe +windshieldWipe +snakeWipe +spiralWipe +parallelSnakesWipe +boxSnakesWipe +waterfallWipe +pushWipe +slideWipe +blindsWipe +randomBarWipe +checkerBoardWipe +zoom +leftToRight +topToBottom +topLeft +topRight +bottomRight +bottomLeft +topCenter +rightCenter +bottomCenter +leftCenter +cornersIn +cornersOut +diagonalBottomLeft +diagonalTopLeft +doubleBarnDoor +doubleDiamond +fourPoint +fivePoint +sixPoint +heart +keyhole +clockwiseTwelve +clockwiseThree +clockwiseSix +clockwiseNine +twoBladeVertical +twoBladeHorizontal +fourBlade +clockwiseTop +clockwiseRight +clockwiseBottom +clockwiseLeft +clockwiseTopLeft +counterClockwiseBottomLeft +clockwiseBottomRight +counterClockwiseTopRight +centerTop +centerRight +fanOutVertical +fanOutHorizontal +fanInVertical +fanInHorizontal +parallelVertical +parallelDiagonal +oppositeVertical +oppositeHorizontal +parallelDiagonalTopLeft +parallelDiagonalBottomLeft +topLeftHorizontal +topLeftDiagonal +topLeftVertical +topRightDiagonal +bottomRightDiagonal +bottomLeftDiagonal +topLeftClockwise +topRightClockwise +bottomRightClockwise +bottomLeftClockwise +topLeftCounterClockwise +topRightCounterClockwise +bottomRightCounterClockwise +bottomLeftCounterClockwise +verticalTopSame +verticalBottomSame +verticalTopLeftOpposite +verticalBottomLeftOpposite +horizontalLeftSame +horizontalRightSame +horizontalTopLeftOpposite +horizontalTopRightOpposite +diagonalBottomLeftOpposite +diagonalTopLeftOpposite +twoBoxTop +twoBoxBottom +twoBoxLeft +twoBoxRight +fourBoxVertical +fourBoxHorizontal +verticalLeft +verticalRight +horizontalLeft +horizontalRight +fromLeft +fromTop +fromRight +fromBottom +crossfade +fadeToColor +fadeFromColor +fadeOverColor +threeBlade +eightBlade +oneBlade +across +combHorizontal +combVertical +rotateIn +rotateOut +fromTopLeft +fromTopRight +fromBottomLeft +fromBottomRight +subtype +out +forward +reverse +fadeColor +onbegin +onend +click +doubleclick +mouseover +mouseout +node-type +preset-id +preset-sub-type +preset-class +preset-property +custom +entrance +exit +emphasis +motion-path +ole-action +media-call +on-click +with-previous +after-previous +main-sequence +timing-root +interactive-sequence +sub-item +iterate-type +iterate-interval +iterate +by-paragraph +by-word +by-letter +after-effect +master +group-id +targetElement +toggle-pause +master-element +stop-audio +audio-level +URN_OASIS_NAMES_TC_DUMMY +opendocument +1_0_DUMMY +is-list-header +N_SVG_COMPAT_DUMMY +N_FO_COMPAT_DUMMY +N_SMIL_COMPAT_DUMMY +N_SMIL_OLD_DUMMY +xforms-submission +xforms-list-source +URI_W3_PREFIX_DUMMY +URI_XFORMS_SUFFIX_DUMMY +horizontal-on-even +N_RPT_OASIS_DUMMY +N_RPT_DUMMY +group +groups +report-header +page-header +detail +page-footer +report-footer +start-new-column +reset-page-number +print-header-on-each-page +sort-expression +group-expression +group-header +group-footer +header-on-new-page +footer-on-new-page +page-print-option +pre-evaluated +command-type +master-fields +detail-fields +conditional-print-expression +report-component +print-repeated-values +repeat-section +force-new-column +group-on +force-new-page +group-interval +print-when-group-change +report-element +list-source +list-source-type +image-data +selected +current-state +is-tristate +all-pages +not-with-report-header +not-with-report-footer +not-with-report-header-nor-footer +before-section +after-section +before-after-section +prefix-characters +quartal +week +whole-group +with-first-detail +top-down +bottom-up +hour +minute +rpt +format-condition +expression1 +expression2 +equal +not_equal +less +greater +less_equal +greater_equal +between +not_between +table-template +first-row +last-row +first-column +last-column +even-rows +odd-rows +even-columns +odd-columns +first-row-even-column +last-row-even-column +first-row-end-column +first-row-start-column +last-row-end-column +last-row-start-column +horizontal-on-odd +restart-numbering +numbered-paragraph +master-detail-fields +master-detail-field +sub-document +fixed-content +initial-formula +deep-traversing +preserve-IRI +sort-by-x-values +page-continuation +right-angled-axes +soft-page-break +use-soft-page-breaks +percentage-data-style-name +value-and-percentage +group-bars-per-axis +include-hidden-cells +auto-position +auto-size +reverse-direction +label-separator +label-position +avoid-overlap +near-origin +dependency +nav-order +use-first-row-styles +use-last-row-styles +use-first-column-styles +use-last-column-styles +use-banding-rows-styles +use-banding-columns-styles +automatic-content +display-r-square +display-equation +table-representations +table-representation +schema-definition +connection-data +database-description +compound-database +file-based-database +server-database +media-type +hostname +port +local-socket +use-system-user +driver-settings +java-classpath +character-set +application-connection-settings +table-include-filter +default-row-style-name +angle-offset +number-no-superior +number-all-superior +list-level-position-and-space-mode +label-width-and-position +label-alignment +list-level-label-alignment +label-followed-by +listtab +space +nothing +list-tab-stop-position +standard-error +cell-range +error-lower-range +error-upper-range +continue-list +style-override +xforms-settings +meta-field +about +datatype +transformation +list-id +treat-empty-cells +leave-gap +use-zero +ignore +fieldmark +fieldmark-start +fieldmark-separator +fieldmark-end +image-scale +isotropic +anisotropic +axis-position +axis-label-position +near-axis +near-axis-other-side +outside-start +outside-end +tick-mark-position +at-labels +at-axis +at-labels-and-axis +filled-radar +surface +mathvariant +mathsize +mathweight +mathcolor +contains +does-not-contain +begins-with +does-not-begin-with +ends-with +does-not-end-with +chartooo +N_CHART_EXT_DUMMY +coordinate-region +diagonal-bl-tr-widths +diagonal-tl-br-widths +outside-minimum +outside-maximum +legend-expansion +legend-expansion-aspect-ratio +balanced +high +wide +axis-type +date-scale +base-time-unit +major-interval-value +minor-interval-value +major-interval-unit +minor-interval-unit +min-value +max-value +margin +propertry-mapping +provider +data-mappings +data-mapping +frequency +data-transformations +column-remove-transformation +column-split-transformation +column-merge-transformation +column-sort-transformation +column-text-transformation +column-aggregate-transformation +column-number-transformation +sort-param +merge-string +trim +round-up +round-down +log-base-10 +number-square +square-root +even +odd +sign +replace-string +column-replacenull-transformation +column-datetime-transformation +start-of-year +end-of-year +month-name +start-of-month +end-of-month +day-of-year +start-of-quarter +end-of-quarter +star +asterisk +horizontal-bar +vertical-bar +std-weight +rfc-language-tag +rfc-language-tag-asian +rfc-language-tag-complex +data-table-show-horz-border +data-table-show-vert-border +data-table-show-outline +display-units +display-units-built-in-unit +external-data +exponent-interval +forced-exponent-sign +min-decimal-places +max-denominator-value +max-numerator-digits +zeros-numerator-digits +zeros-denominator-digits +integer-fraction-delimiter +reference-language +newline +creator-initials +transliteration-spellout +resolved +page-content-top +page-content-bottom +margin-gutter +local-url +dir +displaystyle +infinity +lspace +mathbackground +maxsize +minsize +movablelimits +rspace +rtl +symmetric +linked-style-name +theme +theme-color +fill-theme-color +dk1 +lt1 +dk2 +lt2 +accent1 +accent2 +accent3 +accent4 +accent5 +accent6 +hlink +folHlink +color-lum-mod +color-lum-off +fill-color-lum-mod +fill-color-lum-off +content-control +showing-place-holder +checked-state +unchecked-state +display-text +picture +date-format +date-rfc-language-tag +fill-use-slide-background +TOKEN_END_DUMMY diff --git a/xmloff/source/transform/ActionMapTypesOASIS.hxx b/xmloff/source/transform/ActionMapTypesOASIS.hxx new file mode 100644 index 000000000..eb9753ab4 --- /dev/null +++ b/xmloff/source/transform/ActionMapTypesOASIS.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/. + * + * 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 + +enum ActionMapTypesOasis +{ + PROP_OASIS_GRAPHIC_ATTR_ACTIONS, + PROP_OASIS_DRAWING_PAGE_ATTR_ACTIONS, + PROP_OASIS_PAGE_LAYOUT_ATTR_ACTIONS, + PROP_OASIS_HEADER_FOOTER_ATTR_ACTIONS, + PROP_OASIS_TEXT_ATTR_ACTIONS, + PROP_OASIS_PARAGRAPH_ATTR_ACTIONS, + PROP_OASIS_SECTION_ATTR_ACTIONS, + PROP_OASIS_TABLE_ATTR_ACTIONS, + PROP_OASIS_TABLE_COLUMN_ATTR_ACTIONS, + PROP_OASIS_TABLE_ROW_ATTR_ACTIONS, + PROP_OASIS_TABLE_CELL_ATTR_ACTIONS, + PROP_OASIS_LIST_LEVEL_ATTR_ACTIONS, + PROP_OASIS_CHART_ATTR_ACTIONS, + MAX_OASIS_PROP_ACTIONS, + OASIS_STYLE_ACTIONS = MAX_OASIS_PROP_ACTIONS, + OASIS_FONT_FACE_ACTIONS, + OASIS_SHAPE_ACTIONS, + OASIS_CONNECTOR_ACTIONS, + OASIS_INDEX_ENTRY_TAB_STOP_ACTIONS, + OASIS_TAB_STOP_ACTIONS, + OASIS_LINENUMBERING_ACTIONS, + OASIS_FOOTNOTE_SEP_ACTIONS, + OASIS_DROP_CAP_ACTIONS, + OASIS_COLUMNS_ACTIONS, + OASIS_TEXT_VALUE_TYPE_ACTIONS, + OASIS_TABLE_VALUE_TYPE_ACTIONS, + OASIS_PARA_ACTIONS, + OASIS_LIST_STYLE_REF_ACTIONS, + OASIS_TEXT_STYLE_REF_ACTIONS, + OASIS_PARA_STYLE_REF_ACTIONS, + OASIS_MASTER_PAGE_REF_ACTIONS, + OASIS_MAP_STYLE_REF_ACTIONS, + OASIS_MASTER_PAGE_ACTIONS, + OASIS_NOTES_ACTIONS, + OASIS_ANNOTATION_ACTIONS, + OASIS_CHANGE_INFO_ACTIONS, + OASIS_FRAME_ELEM_ACTIONS, + OASIS_BACKGROUND_IMAGE_ACTIONS, + OASIS_DDE_CONNECTION_DECL_ACTIONS, + OASIS_EVENT_ACTIONS, + OASIS_DLG_ACTIONS, + OASIS_FORM_CONTROL_ACTIONS, + OASIS_FORM_COLUMN_ACTIONS, + OASIS_FORM_PROP_ACTIONS, + OASIS_XLINK_ACTIONS, + OASIS_CONFIG_ITEM_SET_ACTIONS, + OASIS_FORMULA_ACTIONS, + OASIS_CHART_ACTIONS, + OASIS_FORM_ACTIONS, + OASIS_ALPHABETICAL_INDEX_MARK_ACTIONS, + OASIS_CONTENT_VALIDATION_ACTIONS, + OASIS_DDE_CONV_MODE_ACTIONS, + OASIS_DATAPILOT_MEMBER_ACTIONS, + OASIS_DATAPILOT_LEVEL_ACTIONS, + OASIS_SOURCE_SERVICE_ACTIONS, + OASIS_DRAW_AREA_POLYGON_ACTIONS, + OASIS_SCRIPT_ACTIONS, + OASIS_DATETIME_ACTIONS, + OASIS_TABLE_STYLE_REF_ACTIONS, + OASIS_ANIMATION_ACTIONS, + MAX_OASIS_ACTIONS +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ActionMapTypesOOo.hxx b/xmloff/source/transform/ActionMapTypesOOo.hxx new file mode 100644 index 000000000..53e5e31c4 --- /dev/null +++ b/xmloff/source/transform/ActionMapTypesOOo.hxx @@ -0,0 +1,84 @@ +/* -*- 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 + +enum ActionMapTypesOOo +{ + PROP_OOO_GRAPHIC_ATTR_ACTIONS, + PROP_OOO_GRAPHIC_ELEM_ACTIONS, + PROP_OOO_DRAWING_PAGE_ATTR_ACTIONS, + PROP_OOO_PAGE_LAYOUT_ATTR_ACTIONS, + PROP_OOO_HEADER_FOOTER_ATTR_ACTIONS, + PROP_OOO_TEXT_ATTR_ACTIONS, + PROP_OOO_TEXT_ELEM_ACTIONS, + PROP_OOO_PARAGRAPH_ATTR_ACTIONS, + PROP_OOO_PARAGRAPH_ELEM_ACTIONS, + PROP_OOO_SECTION_ATTR_ACTIONS, + PROP_OOO_TABLE_ATTR_ACTIONS, + PROP_OOO_TABLE_COLUMN_ATTR_ACTIONS, + PROP_OOO_TABLE_ROW_ATTR_ACTIONS, + PROP_OOO_TABLE_CELL_ATTR_ACTIONS, + PROP_OOO_TABLE_CELL_ELEM_ACTIONS, + PROP_OOO_LIST_LEVEL_ATTR_ACTIONS, + PROP_OOO_CHART_ATTR_ACTIONS, + PROP_OOO_CHART_ELEM_ACTIONS, + MAX_OOO_PROP_ACTIONS, + OOO_STYLE_ACTIONS = MAX_OOO_PROP_ACTIONS, + OOO_FONT_DECL_ACTIONS, + OOO_SHAPE_ACTIONS, + OOO_CONNECTOR_ACTIONS, + OOO_INDEX_ENTRY_TAB_STOP_ACTIONS, + OOO_TAB_STOP_ACTIONS, + OOO_LINENUMBERING_ACTIONS, + OOO_FOOTNOTE_SEP_ACTIONS, + OOO_DROP_CAP_ACTIONS, + OOO_COLUMNS_ACTIONS, + OOO_TEXT_VALUE_TYPE_ACTIONS, + OOO_TABLE_VALUE_TYPE_ACTIONS, + OOO_PARA_ACTIONS, + OOO_STYLE_REF_ACTIONS, + OOO_MASTER_PAGE_ACTIONS, + OOO_ANNOTATION_ACTIONS, + OOO_CHANGE_INFO_ACTIONS, + OOO_FRAME_ELEM_ACTIONS, + OOO_FRAME_ATTR_ACTIONS, + OOO_BACKGROUND_IMAGE_ACTIONS, + OOO_DDE_CONNECTION_DECL_ACTIONS, + OOO_EVENT_ACTIONS, + OOO_FORM_CONTROL_ACTIONS, + OOO_FORM_COLUMN_ACTIONS, + OOO_FORM_PROP_ACTIONS, + OOO_XLINK_ACTIONS, + OOO_CONFIG_ITEM_SET_ACTIONS, + OOO_FORMULA_ACTIONS, + OOO_CHART_ACTIONS, + OOO_ERROR_MACRO_ACTIONS, + OOO_DDE_CONV_MODE_ACTIONS, + OOO_ALPHABETICAL_INDEX_MARK_ACTIONS, + OOO_DATAPILOT_MEMBER_ACTIONS, + OOO_DATAPILOT_LEVEL_ACTIONS, + OOO_SOURCE_SERVICE_ACTIONS, + OOO_DRAW_AREA_POLYGON_ACTIONS, + OOO_SCRIPT_ACTIONS, + OOO_ANIMATION_ACTIONS, + MAX_OOO_ACTIONS +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/AttrTransformerAction.hxx b/xmloff/source/transform/AttrTransformerAction.hxx new file mode 100644 index 000000000..e302a9852 --- /dev/null +++ b/xmloff/source/transform/AttrTransformerAction.hxx @@ -0,0 +1,126 @@ +/* -*- 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 "TransformerAction.hxx" + +enum XMLAttrTransformerAction +{ + XML_ATACTION_EOT=XML_TACTION_EOT, // uses for initialization only + XML_ATACTION_COPY, // copy attr + XML_ATACTION_RENAME, // rename attr: + // - param1: namespace + + // token of local name + XML_ATACTION_REMOVE, // remove attr + XML_ATACTION_IN2INCH, // replace "in" with "inch" + XML_ATACTION_INS2INCHS, // replace "in" with "inch" + // multiple times + XML_ATACTION_IN2TWIPS, // replace "in" with "inch" and + // convert value from inch to twips + // but only for writer documents + XML_ATACTION_RENAME_IN2INCH, // replace "in" with "inch" and rename + // attr: + // - param1: namespace + + // token of local name + XML_ATACTION_INCH2IN, // replace "inch" with "in" + XML_ATACTION_INCHS2INS, // replace "inch" with "in" + // multiple times + XML_ATACTION_TWIPS2IN, // replace "inch" with "in" and for writer + // documents convert measure value from twips + // to inch + XML_ATACTION_RENAME_INCH2IN, // replace "inch" with "in" and rename + // attr: + // - param1: namespace + + // token of local name + XML_ATACTION_STYLE_FAMILY, // NOP, used for style:family + XML_ATACTION_DECODE_STYLE_NAME, // NOP, used for style:name + // - param1: style family + XML_ATACTION_STYLE_DISPLAY_NAME, // NOP, used for style:display_name + // - param1: style family + XML_ATACTION_DECODE_STYLE_NAME_REF, // NOP, used for style:name reference + // - param1: style family + XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF, // NOP, used for style:name + // - param1: namespace + + // token of local name + XML_ATACTION_ENCODE_STYLE_NAME, // NOP, used for style:name + XML_ATACTION_ENCODE_STYLE_NAME_REF, // NOP, used for style:name + XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF, // NOP, used for style:name + // - param1: namespace + + // token of local name + // - param2: style family + XML_ATACTION_MOVE_TO_ELEM, // turn attr into an elem + // - param1: namespace + + // token of local name + XML_ATACTION_NEG_PERCENT, // replace % val with 100-% + XML_ATACTION_RENAME_NEG_PERCENT, // replace % val with 100-%, rename attr + // - param1: namespace + + // token of local name + XML_ATACTION_HREF, // xmlink:href + XML_ATACTION_ADD_NAMESPACE_PREFIX, // add a namespace prefix + // - param1: prefix + XML_ATACTION_ADD_APP_NAMESPACE_PREFIX, // add a namespace prefix + // - param1: default prefix + XML_ATACTION_RENAME_ADD_NAMESPACE_PREFIX, // add a namespace prefix + // - param1: namespace + + // token of local name + // - param2: prefix + XML_ATACTION_REMOVE_NAMESPACE_PREFIX,// remove a namespace prefix + // - param1: prefix + XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX,// remove any namespace prefix + XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX,// remove a namespace prefix + // - param1: namespace + + // token of local name + // - param2: prefix + XML_ATACTION_EVENT_NAME, + XML_ATACTION_MACRO_NAME, + XML_ATACTION_MACRO_LOCATION, + XML_ATACTION_DLG_BORDER, + XML_ATACTION_URI_OOO, // a URI in OOo notation + // - param1: pacakage URI are supported + XML_ATACTION_URI_OASIS, // a URI in OASIS notation + // - param1: pacakage URI are supported + XML_ATACTION_RENAME_ATTRIBUTE, // rename up to 3 different possible values of an attribute + // - param1: token of old attribute value (lower 16 bit) + // + token of new attribute value (upper 16 bit) + // - param2: token of old attribute value + // + token of new attribute value + // - param3: token of old attribute value + // + token of new attribute value + // if param2 or param3 are unused they must contain + // XML_TOKEN_INVALID + XML_ATACTION_RNG2ISO_DATETIME, // converts . into , in datetimes + XML_ATACTION_RENAME_RNG2ISO_DATETIME,// converts . into , in datetimes and renames the attribute + // - param1: namespace + + // token of local name + XML_ATACTION_SVG_WIDTH_HEIGHT_OOO, // replace "inch" with "in" and subtracts 1/100th mm + XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS, // replace "in" with "inch" and adds 1/100th mm + XML_ATACTION_DRAW_MIRROR_OOO, // renames draw:mirror to style:mirror and adapts values + // OpenDocument file format: attribute value of wrong (#i49139#) + XML_ATACTION_STYLE_MIRROR_OOO, // adapts style:mirror values + XML_ATACTION_DRAW_MIRROR_OASIS, // renames style:mirror to draw:mirror and adapts values + XML_ATACTION_GAMMA_OASIS, // converts percentage to double value + XML_ATACTION_GAMMA_OOO, // converts double value to percentage + XML_ATACTION_DECODE_ID, // converts strings with non numeric characters to only numeric character ids + XML_ATACTION_OPACITY_FIX, // converts transparency to opacity and back + XML_ATACTION_SHAPEID, // convert shape id + XML_ATACTION_USER_DEFINED=0x40000000,// user defined actions start here +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ChartOASISTContext.cxx b/xmloff/source/transform/ChartOASISTContext.cxx new file mode 100644 index 000000000..314de4031 --- /dev/null +++ b/xmloff/source/transform/ChartOASISTContext.cxx @@ -0,0 +1,131 @@ +/* -*- 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 "ChartOASISTContext.hxx" +#include "MutableAttrList.hxx" +#include +#include "ActionMapTypesOASIS.hxx" +#include "AttrTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLChartOASISTransformerContext::XMLChartOASISTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ) +{ +} + +XMLChartOASISTransformerContext::~XMLChartOASISTransformerContext() +{ +} + +void XMLChartOASISTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OASIS_CHART_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + OUString aAddInName; + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_IN2INCH: + { + OUString aAttrValue( rAttrValue ); + if( XMLTransformerBase::ReplaceSingleInWithInch( + aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_DECODE_STYLE_NAME_REF: + { + OUString aAttrValue( rAttrValue ); + if( XMLTransformerBase::DecodeStyleName(aAttrValue) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX: + OSL_ENSURE( IsXMLToken( aLocalName, XML_CLASS ), + "unexpected class token" ); + { + OUString aChartClass; + sal_uInt16 nValuePrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( + rAttrValue, + &aChartClass ); + if( XML_NAMESPACE_CHART == nValuePrefix ) + { + pMutableAttrList->SetValueByIndex( i, aChartClass ); + } + else if ( XML_NAMESPACE_OOO == nValuePrefix ) + { + pMutableAttrList->SetValueByIndex( i, + GetXMLToken(XML_ADD_IN ) ); + aAddInName = aChartClass; + } + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + if( !aAddInName.isEmpty() ) + { + OUString aAttrQName( GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, + GetXMLToken( XML_ADD_IN_NAME ) ) ); + assert(pMutableAttrList && "coverity[var_deref_model] - pMutableAttrList should be assigned in a superset of the enclosing if condition entry logic"); + pMutableAttrList->AddAttribute( aAttrQName, aAddInName ); + } + + XMLTransformerContext::StartElement( xAttrList ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ChartOASISTContext.hxx b/xmloff/source/transform/ChartOASISTContext.hxx new file mode 100644 index 000000000..08178f3f1 --- /dev/null +++ b/xmloff/source/transform/ChartOASISTContext.hxx @@ -0,0 +1,34 @@ +/* -*- 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 "TransformerContext.hxx" + +class XMLChartOASISTransformerContext : public XMLTransformerContext +{ +public: + XMLChartOASISTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + virtual ~XMLChartOASISTransformerContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ChartOOoTContext.cxx b/xmloff/source/transform/ChartOOoTContext.cxx new file mode 100644 index 000000000..781cb3764 --- /dev/null +++ b/xmloff/source/transform/ChartOOoTContext.cxx @@ -0,0 +1,133 @@ +/* -*- 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 "ChartOOoTContext.hxx" +#include "MutableAttrList.hxx" +#include +#include "ActionMapTypesOOo.hxx" +#include "AttrTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLChartOOoTransformerContext::XMLChartOOoTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ) +{ +} + +XMLChartOOoTransformerContext::~XMLChartOOoTransformerContext() +{ +} + +void XMLChartOOoTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OOO_CHART_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + sal_Int16 nClassName = -1; + OUString aAddInName; + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_INCH2IN: + { + OUString aAttrValue( rAttrValue ); + if( XMLTransformerBase::ReplaceSingleInchWithIn( + aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_ENCODE_STYLE_NAME_REF: + { + OUString aAttrValue( rAttrValue ); + if( GetTransformer().EncodeStyleName(aAttrValue) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_ADD_NAMESPACE_PREFIX: + OSL_ENSURE( ::xmloff::token::IsXMLToken( aLocalName, XML_CLASS ), + "unexpected class token" ); + if( ::xmloff::token::IsXMLToken( rAttrValue, XML_ADD_IN ) ) + { + nClassName = i; + } + else + { + OUString aAttrValue( rAttrValue ); + sal_uInt16 nValPrefix = + static_cast((*aIter).second.m_nParam1); + GetTransformer().AddNamespacePrefix( aAttrValue, + nValPrefix ); + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_REMOVE: + OSL_ENSURE( ::xmloff::token::IsXMLToken( aLocalName, XML_ADD_IN_NAME ), + "unexpected class token" ); + aAddInName = rAttrValue; + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + if( nClassName != -1 && !aAddInName.isEmpty() ) + { + GetTransformer().AddNamespacePrefix( aAddInName, XML_NAMESPACE_OOO ); + pMutableAttrList->SetValueByIndex( nClassName, aAddInName ); + } + + XMLTransformerContext::StartElement( xAttrList ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ChartOOoTContext.hxx b/xmloff/source/transform/ChartOOoTContext.hxx new file mode 100644 index 000000000..aad4856ec --- /dev/null +++ b/xmloff/source/transform/ChartOOoTContext.hxx @@ -0,0 +1,34 @@ +/* -*- 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 "TransformerContext.hxx" + +class XMLChartOOoTransformerContext : public XMLTransformerContext +{ +public: + XMLChartOOoTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + virtual ~XMLChartOOoTransformerContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ChartPlotAreaOASISTContext.cxx b/xmloff/source/transform/ChartPlotAreaOASISTContext.cxx new file mode 100644 index 000000000..b8603f62f --- /dev/null +++ b/xmloff/source/transform/ChartPlotAreaOASISTContext.cxx @@ -0,0 +1,234 @@ +/* -*- 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 "ChartPlotAreaOASISTContext.hxx" +#include "TransformerBase.hxx" +#include +#include +#include +#include "DeepTContext.hxx" +#include "ActionMapTypesOASIS.hxx" +#include "MutableAttrList.hxx" +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; + +namespace { + +class XMLAxisOASISContext : public XMLPersElemContentTContext +{ +public: + XMLAxisOASISContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + ::rtl::Reference< XMLPersAttrListTContext > & rOutCategoriesContext ); + + virtual rtl::Reference CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< xml::sax::XAttributeList >& xAttrList ) override; + + virtual void StartElement( const Reference< xml::sax::XAttributeList >& rAttrList ) override; + virtual void EndElement() override; + +private: + ::rtl::Reference< XMLPersAttrListTContext > & m_rCategoriesContext; + bool m_bHasCategories; +}; + +} + +XMLAxisOASISContext::XMLAxisOASISContext( + XMLTransformerBase& rTransformer, + const OUString& rQName, + ::rtl::Reference< XMLPersAttrListTContext > & rOutCategoriesContext ) : + XMLPersElemContentTContext( rTransformer, rQName ), + m_rCategoriesContext( rOutCategoriesContext ), + m_bHasCategories( false ) +{} + +rtl::Reference XMLAxisOASISContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< xml::sax::XAttributeList >& xAttrList ) +{ + rtl::Reference pContext; + + if( XML_NAMESPACE_CHART == nPrefix && + IsXMLToken( rLocalName, XML_CATEGORIES ) ) + { + // store categories element at parent + m_rCategoriesContext.set( new XMLPersAttrListTContext( GetTransformer(), rQName )); + m_bHasCategories = true; + pContext = m_rCategoriesContext.get(); + } + else + { + pContext = XMLPersElemContentTContext::CreateChildContext( + nPrefix, rLocalName, rQName, xAttrList ); + } + + return pContext; +} + +void XMLAxisOASISContext::StartElement( + const Reference< xml::sax::XAttributeList >& rAttrList ) +{ + Reference< xml::sax::XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_CHART && + IsXMLToken( aLocalName, XML_DIMENSION ) ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + XMLTokenEnum eToken = XML_TOKEN_INVALID; + if( IsXMLToken( rAttrValue, XML_X )) + { + eToken = XML_DOMAIN; + // has to be XML_CATEGORY for axes with a categories + // sub-element. The attribute is changed later (when it is + // known that there is a categories sub-element) in this case. + } + else if( IsXMLToken( rAttrValue, XML_Y )) + { + eToken = XML_VALUE; + } + else if( IsXMLToken( rAttrValue, XML_Z )) + { + eToken = XML_SERIES; + } + else + { + OSL_FAIL( "ChartAxis: Invalid attribute value" ); + } + + if( eToken != XML_TOKEN_INVALID ) + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( XML_CLASS ))); + pMutableAttrList->RenameAttributeByIndex( i, aNewAttrQName ); + + pMutableAttrList->SetValueByIndex( i, GetXMLToken( eToken )); + } + } + } + + XMLPersElemContentTContext::StartElement( xAttrList ); +} + +void XMLAxisOASISContext::EndElement() +{ + // if we have categories, change the "class" attribute + if( m_bHasCategories && + m_rCategoriesContext.is() ) + { + OSL_ENSURE( GetAttrList().is(), "Invalid attribute list" ); + rtl::Reference pMutableAttrList = + new XMLMutableAttributeList( GetAttrList()); + OUString aAttrQName( GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( XML_CLASS ))); + sal_Int16 nIndex = pMutableAttrList->GetIndexByName( aAttrQName ); + if( nIndex != -1 ) + { + OSL_ENSURE( IsXMLToken( pMutableAttrList->getValueByIndex( nIndex ), + XML_DOMAIN ), "Axis Dimension: invalid former value" ); + pMutableAttrList->SetValueByIndex( nIndex, GetXMLToken( XML_CATEGORY )); + OSL_ENSURE( IsXMLToken( pMutableAttrList->getValueByIndex( nIndex ), + XML_CATEGORY ), "Axis Dimension: invalid new value" ); + } + + GetTransformer().GetDocHandler()->startElement( + GetExportQName(), + Reference< xml::sax::XAttributeList >( pMutableAttrList )); + ExportContent(); + GetTransformer().GetDocHandler()->endElement( GetExportQName()); + } + else + Export(); +} + + +XMLChartPlotAreaOASISTContext::XMLChartPlotAreaOASISTContext( + XMLTransformerBase & rTransformer, const OUString & rQName ) : + XMLProcAttrTransformerContext( rTransformer, rQName, OASIS_SHAPE_ACTIONS ) +{ +} + +XMLChartPlotAreaOASISTContext::~XMLChartPlotAreaOASISTContext() +{} + +rtl::Reference XMLChartPlotAreaOASISTContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + rtl::Reference pContext; + + if( XML_NAMESPACE_CHART == nPrefix && + IsXMLToken( rLocalName, XML_AXIS ) ) + { + pContext.set(new XMLAxisOASISContext( GetTransformer(), rQName, m_rCategoriesContext )); + } + else + { + // export (and forget) categories if found in an axis-element + // otherwise export regularly + ExportCategories(); + pContext = XMLProcAttrTransformerContext::CreateChildContext( + nPrefix, rLocalName, rQName, xAttrList ); + } + + return pContext; +} + +void XMLChartPlotAreaOASISTContext::EndElement() +{ + ExportCategories(); + XMLProcAttrTransformerContext::EndElement(); +} + +void XMLChartPlotAreaOASISTContext::ExportCategories() +{ + if( m_rCategoriesContext.is()) + { + m_rCategoriesContext->Export(); + m_rCategoriesContext.clear(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ChartPlotAreaOASISTContext.hxx b/xmloff/source/transform/ChartPlotAreaOASISTContext.hxx new file mode 100644 index 000000000..fb6cae053 --- /dev/null +++ b/xmloff/source/transform/ChartPlotAreaOASISTContext.hxx @@ -0,0 +1,46 @@ +/* -*- 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 "ProcAttrTContext.hxx" +#include "PersAttrListTContext.hxx" +#include + +class XMLChartPlotAreaOASISTContext : public XMLProcAttrTransformerContext +{ +public: + explicit XMLChartPlotAreaOASISTContext( + XMLTransformerBase & rTransformer, const OUString & rQName ); + virtual ~XMLChartPlotAreaOASISTContext() override; + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + + void ExportCategories(); + +private: + ::rtl::Reference< XMLPersAttrListTContext > m_rCategoriesContext; +}; + +// INCLUDED_XMLOFF_SOURCE_TRANSFORM_CHARTPLOTAREAOASISTCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ChartPlotAreaOOoTContext.cxx b/xmloff/source/transform/ChartPlotAreaOOoTContext.cxx new file mode 100644 index 000000000..f2781a25a --- /dev/null +++ b/xmloff/source/transform/ChartPlotAreaOOoTContext.cxx @@ -0,0 +1,211 @@ +/* -*- 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 "ChartPlotAreaOOoTContext.hxx" +#include "TransformerBase.hxx" +#include +#include +#include +#include "DeepTContext.hxx" +#include "ActionMapTypesOOo.hxx" +#include "MutableAttrList.hxx" +#include + +using namespace ::com::sun::star; +using namespace ::xmloff::token; + +using ::com::sun::star::uno::Reference; + +class XMLAxisOOoContext : public XMLPersElemContentTContext +{ +public: + XMLAxisOOoContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual void StartElement( const Reference< xml::sax::XAttributeList >& rAttrList ) override; + + bool IsCategoryAxis() const { return m_bIsCategoryAxis;} + +private: + bool m_bIsCategoryAxis; +}; + +XMLAxisOOoContext::XMLAxisOOoContext( + XMLTransformerBase& rTransformer, + const OUString& rQName ) : + XMLPersElemContentTContext( rTransformer, rQName ), + m_bIsCategoryAxis( false ) +{} + +void XMLAxisOOoContext::StartElement( + const Reference< xml::sax::XAttributeList >& rAttrList ) +{ + Reference< xml::sax::XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName ); + + if( nPrefix == XML_NAMESPACE_CHART && + IsXMLToken( aLocalName, XML_CLASS ) ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + XMLTokenEnum eToken = XML_TOKEN_INVALID; + if( IsXMLToken( rAttrValue, XML_DOMAIN ) || + IsXMLToken( rAttrValue, XML_CATEGORY )) + { + eToken = XML_X; + if( IsXMLToken( rAttrValue, XML_CATEGORY ) ) + m_bIsCategoryAxis = true; + } + else if( IsXMLToken( rAttrValue, XML_VALUE )) + { + eToken = XML_Y; + } + else if( IsXMLToken( rAttrValue, XML_SERIES )) + { + eToken = XML_Z; + } + else + { + OSL_FAIL( "ChartAxis: Invalid attribute value" ); + } + + if( eToken != XML_TOKEN_INVALID ) + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( XML_DIMENSION ))); + pMutableAttrList->RenameAttributeByIndex( i, aNewAttrQName ); + pMutableAttrList->SetValueByIndex( i, GetXMLToken( eToken )); + } + } + } + + XMLPersElemContentTContext::StartElement( xAttrList ); +} + +XMLChartPlotAreaOOoTContext::XMLChartPlotAreaOOoTContext( + XMLTransformerBase & rTransformer, const OUString & rQName ) : + XMLProcAttrTransformerContext( rTransformer, rQName, OOO_SHAPE_ACTIONS ) +{ +} + +rtl::Reference XMLChartPlotAreaOOoTContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const uno::Reference< xml::sax::XAttributeList >& xAttrList ) +{ + rtl::Reference pContext; + + if( XML_NAMESPACE_CHART == nPrefix && + IsXMLToken( rLocalName, XML_AXIS ) ) + { + rtl::Reference pAxisContext( new XMLAxisOOoContext( GetTransformer(), rQName )); + AddContent( pAxisContext ); + pContext = pAxisContext; + } + else if( XML_NAMESPACE_CHART == nPrefix && + IsXMLToken( rLocalName, XML_CATEGORIES ) ) + { + pContext.set(new XMLPersAttrListTContext( GetTransformer(), rQName )); + + // put categories at correct axis + bool bFound =false; + + // iterate over axis elements + for( const auto& rChildContext : m_aChildContexts ) + { + XMLAxisOOoContext * pAxisContext = rChildContext.get(); + if( pAxisContext != nullptr ) + { + // iterate over attributes to find category axis + Reference< xml::sax::XAttributeList > xNewAttrList( pAxisContext->GetAttrList()); + sal_Int16 nAttrCount = xNewAttrList.is() ? xNewAttrList->getLength() : 0; + + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString & rAttrName = xNewAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nNewPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + if( nNewPrefix == XML_NAMESPACE_CHART && + pAxisContext->IsCategoryAxis() && + IsXMLToken( aLocalName, XML_DIMENSION ) ) + { + // category axis found + pAxisContext->AddContent( pContext ); + bFound = true; + break; + } + } + } + + if (bFound) + break; + } + OSL_ENSURE( bFound, "No suitable axis for categories found." ); + } + else + { + ExportContent(); + pContext = XMLProcAttrTransformerContext::CreateChildContext( + nPrefix, rLocalName, rQName, xAttrList ); + } + + return pContext; +} + +void XMLChartPlotAreaOOoTContext::EndElement() +{ + ExportContent(); + XMLProcAttrTransformerContext::EndElement(); +} + +void XMLChartPlotAreaOOoTContext::AddContent(rtl::Reference const & pContext) +{ + OSL_ENSURE( pContext.is() && pContext->IsPersistent(), + "non-persistent context" ); + m_aChildContexts.push_back(pContext); +} + + +void XMLChartPlotAreaOOoTContext::ExportContent() +{ + for( auto& rChildContext : m_aChildContexts ) + { + rChildContext->Export(); + } + + m_aChildContexts.clear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ChartPlotAreaOOoTContext.hxx b/xmloff/source/transform/ChartPlotAreaOOoTContext.hxx new file mode 100644 index 000000000..9a2eb8fe8 --- /dev/null +++ b/xmloff/source/transform/ChartPlotAreaOOoTContext.hxx @@ -0,0 +1,55 @@ +/* -*- 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 + +#include + +#include "ProcAttrTContext.hxx" + +class XMLAxisOOoContext; + +class XMLAxisContextVector : + public ::std::vector< ::rtl::Reference< XMLAxisOOoContext > > +{ +}; + +class XMLChartPlotAreaOOoTContext : public XMLProcAttrTransformerContext +{ +public: + explicit XMLChartPlotAreaOOoTContext( + XMLTransformerBase & rTransformer, const OUString & rQName ); + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + virtual void ExportContent() override; + +private: + void AddContent( rtl::Reference const & pContent ); + + XMLAxisContextVector m_aChildContexts; +}; + +// INCLUDED_XMLOFF_SOURCE_TRANSFORM_CHARTPLOTAREAOOOTCONTEXT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ControlOASISTContext.cxx b/xmloff/source/transform/ControlOASISTContext.cxx new file mode 100644 index 000000000..5dd2067c7 --- /dev/null +++ b/xmloff/source/transform/ControlOASISTContext.cxx @@ -0,0 +1,150 @@ +/* -*- 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 "MutableAttrList.hxx" +#include +#include +#include "ActionMapTypesOASIS.hxx" +#include "AttrTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include "ControlOASISTContext.hxx" +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLControlOASISTransformerContext::XMLControlOASISTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + bool bCreateControl ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rImp.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_FORM, + ::xmloff::token::GetXMLToken( XML_CONTROL ) ) ), + m_bCreateControl( bCreateControl ) +{ +} + +void XMLControlOASISTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OASIS_FORM_CONTROL_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; +// GetTransformer().ProcessAttrList( xAttrList, OOO_SHAPE_ACTIONS, +// sal_True ); + + XMLMutableAttributeList *pControlMutableAttrList = + m_bCreateControl ? new XMLMutableAttributeList : nullptr; + Reference< XAttributeList > xControlAttrList( pControlMutableAttrList ); + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( rAttrList ); + xAttrList = pMutableAttrList; + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_MOVE_TO_ELEM: + if( m_bCreateControl ) + { + pControlMutableAttrList->AddAttribute( rAttrName, + rAttrValue ); + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + } + break; + case XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX: + { + OUString aAttrValue( rAttrValue ); + sal_uInt16 nValPrefix = + static_cast( (*aIter).second.m_nParam2 ); + GetTransformer().RemoveNamespacePrefix( aAttrValue, + nValPrefix ); + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + if( m_bCreateControl ) + { + pControlMutableAttrList->AddAttribute( aNewAttrQName, + aAttrValue ); + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + } + else + { + pMutableAttrList->RenameAttributeByIndex( i, + aNewAttrQName ); + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + } + break; + case XML_ATACTION_URI_OASIS: + { + OUString aAttrValue( rAttrValue ); + if( GetTransformer().ConvertURIToOOo( aAttrValue, + static_cast< bool >((*aIter).second.m_nParam1)) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + if( m_bCreateControl ) + GetTransformer().GetDocHandler()->startElement( m_aElemQName, + xControlAttrList ); + XMLTransformerContext::StartElement( xAttrList ); +} + +void XMLControlOASISTransformerContext::EndElement() +{ + XMLTransformerContext::EndElement(); + if( m_bCreateControl ) + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ControlOASISTContext.hxx b/xmloff/source/transform/ControlOASISTContext.hxx new file mode 100644 index 000000000..26b5baeb0 --- /dev/null +++ b/xmloff/source/transform/ControlOASISTContext.hxx @@ -0,0 +1,39 @@ +/* -*- 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 "TransformerContext.hxx" + +class XMLControlOASISTransformerContext : public XMLTransformerContext +{ + OUString const m_aElemQName; + bool const m_bCreateControl; + +public: + XMLControlOASISTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + bool bCreateControl ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void EndElement() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ControlOOoTContext.cxx b/xmloff/source/transform/ControlOOoTContext.cxx new file mode 100644 index 000000000..1391b7225 --- /dev/null +++ b/xmloff/source/transform/ControlOOoTContext.cxx @@ -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/. + * + * 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 "ControlOOoTContext.hxx" +#include "IgnoreTContext.hxx" +#include "MutableAttrList.hxx" +#include "ActionMapTypesOOo.hxx" +#include "TransformerBase.hxx" + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLControlOOoTransformerContext::XMLControlOOoTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ) +{ +} + +void XMLControlOOoTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + m_xAttrList = new XMLMutableAttributeList( rAttrList, true ); +} + +rtl::Reference XMLControlOOoTransformerContext::CreateChildContext( + sal_uInt16 /*nPrefix*/, + const OUString& /*rLocalName*/, + const OUString& rQName, + const Reference< XAttributeList >& rAttrList ) +{ + rtl::Reference pContext; + + if( m_aElemQName.isEmpty() ) + { + pContext.set(new XMLIgnoreTransformerContext( GetTransformer(), + rQName, + false, false )); + m_aElemQName = rQName; + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) + ->AppendAttributeList( rAttrList ); + GetTransformer().ProcessAttrList( m_xAttrList, + OOO_FORM_CONTROL_ACTIONS, + false ); + GetTransformer().GetDocHandler()->startElement( m_aElemQName, + m_xAttrList ); + } + else + { + pContext.set(new XMLIgnoreTransformerContext( GetTransformer(), + rQName, + true, true )); + } + return pContext; +} + +void XMLControlOOoTransformerContext::EndElement() +{ + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +void XMLControlOOoTransformerContext::Characters( const OUString& rChars ) +{ + // ignore + if( !m_aElemQName.isEmpty() ) + XMLTransformerContext::Characters( rChars ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ControlOOoTContext.hxx b/xmloff/source/transform/ControlOOoTContext.hxx new file mode 100644 index 000000000..34cb4e31d --- /dev/null +++ b/xmloff/source/transform/ControlOOoTContext.hxx @@ -0,0 +1,46 @@ +/* -*- 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 "TransformerContext.hxx" + +class XMLControlOOoTransformerContext : public XMLTransformerContext +{ + css::uno::Reference< css::xml::sax::XAttributeList > m_xAttrList; + + OUString m_aElemQName; + +public: + XMLControlOOoTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void EndElement() override; + + virtual void Characters( const OUString& rChars ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/CreateElemTContext.cxx b/xmloff/source/transform/CreateElemTContext.cxx new file mode 100644 index 000000000..218852972 --- /dev/null +++ b/xmloff/source/transform/CreateElemTContext.cxx @@ -0,0 +1,114 @@ +/* -*- 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 + +#include + +#include "CreateElemTContext.hxx" +#include "MutableAttrList.hxx" +#include "TransformerBase.hxx" +#include "TransformerActions.hxx" +#include "FlatTContext.hxx" +#include "AttrTransformerAction.hxx" +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLCreateElemTransformerContext::XMLCreateElemTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nActionMap ) : + XMLTransformerContext( rImp, rQName ), + m_nActionMap( nActionMap ) +{ +} + +void XMLCreateElemTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + Reference< XAttributeList > xAttrList( rAttrList ); + + std::vector> aChildContexts; + + rtl::Reference pMutableAttrList; + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( m_nActionMap ); + OSL_ENSURE( pActions, "go no actions" ); + if( pActions ) + { + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; ++i ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + sal_uInt32 nAction = (*aIter).second.m_nActionType; + switch( nAction ) + { + case XML_ATACTION_MOVE_TO_ELEM: + { + OUString aElemQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + rtl::Reference pContext( + new XMLPersTextContentTContext( GetTransformer(), + aElemQName )); + pContext->Characters( rAttrValue ); + aChildContexts.push_back(pContext); + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + } + XMLTransformerContext::StartElement( xAttrList ); + + for (auto const & i: aChildContexts) + { + i->Export(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/CreateElemTContext.hxx b/xmloff/source/transform/CreateElemTContext.hxx new file mode 100644 index 000000000..6d70e88ee --- /dev/null +++ b/xmloff/source/transform/CreateElemTContext.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/. + * + * 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 "TransformerContext.hxx" + +class XMLCreateElemTransformerContext : public XMLTransformerContext +{ + sal_uInt16 const m_nActionMap; + +public: + XMLCreateElemTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nActionMap ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/DeepTContext.cxx b/xmloff/source/transform/DeepTContext.cxx new file mode 100644 index 000000000..05a4c9900 --- /dev/null +++ b/xmloff/source/transform/DeepTContext.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 "DeepTContext.hxx" +#include "TransformerActions.hxx" +#include "ElemTransformerAction.hxx" +#include "PersMixedContentTContext.hxx" +#include "TransformerBase.hxx" +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +void XMLPersElemContentTContext::AddContent( rtl::Reference const & pContext ) +{ + OSL_ENSURE( pContext.is() && pContext->IsPersistent(), + "non-persistent context" ); + m_aChildContexts.push_back(pContext); +} + +XMLPersElemContentTContext::XMLPersElemContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLPersAttrListTContext( rImp, rQName ) +{ +} + +XMLPersElemContentTContext::XMLPersElemContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nActionMap ) : + XMLPersAttrListTContext( rImp, rQName, nActionMap ) +{ +} + +XMLPersElemContentTContext::XMLPersElemContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ) : + XMLPersAttrListTContext( rImp, rQName, nPrefix, eToken ) +{ +} + +XMLPersElemContentTContext::XMLPersElemContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap ) : + XMLPersAttrListTContext( rImp, rQName, nPrefix, eToken, nActionMap ) +{ +} + +XMLPersElemContentTContext::~XMLPersElemContentTContext() +{ +} + +rtl::Reference XMLPersElemContentTContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& ) +{ + rtl::Reference pContext; + + XMLTransformerActions::key_type aKey( nPrefix, rLocalName ); + XMLTransformerActions::const_iterator aIter = + GetTransformer().GetElemActions().find( aKey ); + + if( aIter != GetTransformer().GetElemActions().end() ) + { + switch( (*aIter).second.m_nActionType ) + { + case XML_ETACTION_COPY: + pContext.set(new XMLPersMixedContentTContext( GetTransformer(), + rQName )); + break; + case XML_ETACTION_COPY_TEXT: + pContext.set(new XMLPersMixedContentTContext( GetTransformer(), + rQName )); + break; + case XML_ETACTION_RENAME_ELEM: + pContext.set(new XMLPersMixedContentTContext( GetTransformer(), rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1() )); + break; + case XML_ETACTION_RENAME_ELEM_PROC_ATTRS: + pContext.set(new XMLPersMixedContentTContext( GetTransformer(), rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1(), + static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) )); + break; + case XML_ETACTION_RENAME_ELEM_ADD_PROC_ATTR: + { + rtl::Reference pMC( + new XMLPersMixedContentTContext( GetTransformer(), rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1(), + static_cast< sal_uInt16 >( + (*aIter).second.m_nParam3 >> 16 ) )); + pMC->AddAttribute( + (*aIter).second.GetQNamePrefixFromParam2(), + (*aIter).second.GetQNameTokenFromParam2(), + static_cast< ::xmloff::token::XMLTokenEnum >( + (*aIter).second.m_nParam3 & 0xffff ) ); + pContext = pMC; + } + break; + case XML_ETACTION_PROC_ATTRS: + pContext.set(new XMLPersMixedContentTContext( GetTransformer(), rQName, + static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) )); + break; + default: + pContext = GetTransformer().CreateUserDefinedContext( + (*aIter).second, rQName, true ); + OSL_ENSURE( pContext.is() && pContext->IsPersistent(), + "unknown or not persistent action" ); + if( pContext.is() && !pContext->IsPersistent() ) + { + pContext.clear(); + } + break; + } + } + + // default is copying + if( !pContext.is() ) + pContext.set(new XMLPersMixedContentTContext( GetTransformer(), rQName )); + m_aChildContexts.push_back(pContext); + + return pContext; +} + +void XMLPersElemContentTContext::ExportContent() +{ + for (auto const & i: m_aChildContexts) + { + i->Export(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/DeepTContext.hxx b/xmloff/source/transform/DeepTContext.hxx new file mode 100644 index 000000000..af6d41255 --- /dev/null +++ b/xmloff/source/transform/DeepTContext.hxx @@ -0,0 +1,71 @@ +/* -*- 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 + +#include +#include "PersAttrListTContext.hxx" + +class XMLPersElemContentTContext : public XMLPersAttrListTContext +{ + std::vector> m_aChildContexts; + +public: + // element content persistence only + XMLPersElemContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + // element content persistence + attribute processing + XMLPersElemContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nActionMap ); + + // element content persistence + renaming + XMLPersElemContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ); + + // element content persistence + renaming + attribute processing + XMLPersElemContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap ); + + virtual ~XMLPersElemContentTContext() override; + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + void AddContent( rtl::Reference const & pContent ); + + bool HasElementContent() const + { + return !m_aChildContexts.empty(); + } + + virtual void ExportContent() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/DlgOASISTContext.cxx b/xmloff/source/transform/DlgOASISTContext.cxx new file mode 100644 index 000000000..24b8a868e --- /dev/null +++ b/xmloff/source/transform/DlgOASISTContext.cxx @@ -0,0 +1,98 @@ +/* -*- 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 "DlgOASISTContext.hxx" +#include "MutableAttrList.hxx" +#include "ActionMapTypesOASIS.hxx" +#include "AttrTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLDlgOASISTransformerContext::XMLDlgOASISTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ) +{ +} + +XMLDlgOASISTransformerContext::~XMLDlgOASISTransformerContext() +{ +} + +void XMLDlgOASISTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OASIS_DLG_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_DLG_BORDER: + { + if ( rAttrValue != GetXMLToken( XML_NONE ) && + rAttrValue != GetXMLToken( XML_SIMPLE ) && + rAttrValue != GetXMLToken( XML_3D ) ) + { + pMutableAttrList->SetValueByIndex( + i, GetXMLToken( XML_NONE ) ); + } + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + XMLTransformerContext::StartElement( xAttrList ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/DlgOASISTContext.hxx b/xmloff/source/transform/DlgOASISTContext.hxx new file mode 100644 index 000000000..338ea97b6 --- /dev/null +++ b/xmloff/source/transform/DlgOASISTContext.hxx @@ -0,0 +1,34 @@ +/* -*- 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 "TransformerContext.hxx" + +class XMLDlgOASISTransformerContext : public XMLTransformerContext +{ +public: + XMLDlgOASISTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + virtual ~XMLDlgOASISTransformerContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/DocumentTContext.cxx b/xmloff/source/transform/DocumentTContext.cxx new file mode 100644 index 000000000..894146897 --- /dev/null +++ b/xmloff/source/transform/DocumentTContext.cxx @@ -0,0 +1,128 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +#include "TransformerBase.hxx" +#include "MutableAttrList.hxx" + +#include "DocumentTContext.hxx" + + +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::beans; + +XMLDocumentTransformerContext::XMLDocumentTransformerContext( XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ) +{ +} + +void XMLDocumentTransformerContext::StartElement( const Reference< XAttributeList >& rAttrList ) +{ + Reference< XAttributeList > xAttrList( rAttrList ); + + bool bMimeFound = false; + OUString aClass; + OUString aClassQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OFFICE, GetXMLToken(XML_CLASS ) ) ); + + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + if( XML_NAMESPACE_OFFICE == nPrefix && + IsXMLToken( aLocalName, XML_MIMETYPE ) ) + { + const OUString& rValue = xAttrList->getValueByIndex( i ); + static const char * aTmp[] = + { + "application/vnd.oasis.openoffice.", + "application/x-vnd.oasis.openoffice.", + "application/vnd.oasis.opendocument.", + "application/x-vnd.oasis.document.", + nullptr + }; + for (int k=0; aTmp[k]; k++) + { + OUString sTmpString = OUString::createFromAscii(aTmp[k]); + if( rValue.matchAsciiL( aTmp[k], sTmpString.getLength() ) ) + { + aClass = rValue.copy( sTmpString.getLength() ); + break; + } + } + + if( !pMutableAttrList ) + { + pMutableAttrList = new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + pMutableAttrList->SetValueByIndex( i, aClass ); + pMutableAttrList->RenameAttributeByIndex(i, aClassQName ); + bMimeFound = true; + break; + } + } + + if( !bMimeFound ) + { + const Reference< XPropertySet > rPropSet = + GetTransformer().GetPropertySet(); + + if( rPropSet.is() ) + { + Reference< XPropertySetInfo > xPropSetInfo( + rPropSet->getPropertySetInfo() ); + OUString aPropName("Class"); + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( aPropName ) ) + { + Any aAny = rPropSet->getPropertyValue( aPropName ); + aAny >>= aClass; + } + } + + if( !aClass.isEmpty() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + + pMutableAttrList->AddAttribute( aClassQName, aClass ); + } + } + XMLTransformerContext::StartElement( xAttrList ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/DocumentTContext.hxx b/xmloff/source/transform/DocumentTContext.hxx new file mode 100644 index 000000000..50434cb3e --- /dev/null +++ b/xmloff/source/transform/DocumentTContext.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/. + * + * 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 "TransformerContext.hxx" + +class XMLDocumentTransformerContext : public XMLTransformerContext +{ +public: + // A contexts constructor does anything that is required if an element + // starts. Namespace processing has been done already. + // Note that virtual methods cannot be used inside constructors. Use + // StartElement instead if this is required. + XMLDocumentTransformerContext(XMLTransformerBase& rTransformer, const OUString& rQName); + + // StartElement is called after a context has been constructed and + // before an elements context is parsed. It may be used for actions that + // require virtual methods. The default is to do nothing. + virtual void + StartElement(const css::uno::Reference& xAttrList) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ElemTransformerAction.hxx b/xmloff/source/transform/ElemTransformerAction.hxx new file mode 100644 index 000000000..abd29f2fb --- /dev/null +++ b/xmloff/source/transform/ElemTransformerAction.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/. + * + * 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 "TransformerAction.hxx" + +enum XMLElemTransformerAction +{ + XML_ETACTION_EOT=XML_TACTION_EOT, // uses for initialization only + XML_ETACTION_COPY, // copy all (default) + // for persistent elements: keep + // elem content + XML_ETACTION_COPY_TEXT, // copy all + // for persistent elements: keep + // text content + XML_ETACTION_COPY_CONTENT, // ignore elem, process content + XML_ETACTION_RENAME_ELEM, // rename element: + // - param1: namespace + + // token of local name + XML_ETACTION_RENAME_ELEM_PROC_ATTRS,// rename element and proc attr: + // - param1: elem namespace + + // token of local name + // - param2: attr acation map + XML_ETACTION_RENAME_ELEM_ADD_ATTR, // rename element and add attr: + // - param1: elem namespace + + // token of local name + // - param2: attr namespace + + // token of local name + // - param3: attr value + XML_ETACTION_RENAME_ELEM_ADD_PROC_ATTR, // rename element and add attr: + // - param1: elem namespace + + // token of local name + // - param2: attr namespace + + // token of local name + // - param3: attr value (low) + // attr action map (high) + XML_ETACTION_RENAME_ELEM_PROC_ATTRS_COND,// rename element and proc attr + // if child of another: + // - param1: elem namespace + + // token of new local name + // - param2: attr acation map + // - param3: namespace + + // token of parent element + XML_ETACTION_PROC_ATTRS, // proc attr: + // - param1: attr acation map + XML_ETACTION_MOVE_ATTRS_TO_ELEMS, // turn some attributes into elems + // - param1: action map specifying + // the attrs that shall be moved + XML_ETACTION_MOVE_ELEMS_TO_ATTRS, // turn some elems into attrs + // - param1: action map specifying + // the elems that shall be moved + XML_ETACTION_PROC_ATTRS_COND, // proc attr if child of another: + // - param1: namespace + + // token of parent element + // - param2: attr acation map + XML_ETACTION_EXTRACT_CHARACTERS, // takes the characters of the current + // element and all child elements + // and put them together into the + // current element + // the child elements are removed + XML_ETACTION_MOVE_TO_ATTR, // turn elem into an attr: + // - param1: namespace + + // token of local name + XML_ETACTION_MOVE_TO_ATTR_RNG2ISO_DATETIME, // turn elem into an attr and convert . to , in datetimes + // - param1: namespace + + // token of local name + XML_ETACTION_USER_DEFINED=0x40000000// user defined actions start here +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/EventMap.cxx b/xmloff/source/transform/EventMap.cxx new file mode 100644 index 000000000..3cfa08a15 --- /dev/null +++ b/xmloff/source/transform/EventMap.cxx @@ -0,0 +1,103 @@ +/* -*- 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 "EventMap.hxx" +#include + + +XMLTransformerEventMapEntry const aTransformerEventMap[] = +{ + { XML_NAMESPACE_DOM, "select", "on-select" }, + { XML_NAMESPACE_OFFICE, "insert-start", "on-insert-start" }, + { XML_NAMESPACE_OFFICE, "insert-done", "on-insert-done" }, + { XML_NAMESPACE_OFFICE, "mail-merge", "on-mail-merge" }, + { XML_NAMESPACE_OFFICE, "alpha-char-input", "on-alpha-char-input" }, + { XML_NAMESPACE_OFFICE, "non-alpha-char-input", "on-non-alpha-char-input" }, + { XML_NAMESPACE_DOM, "resize", "on-resize" }, + { XML_NAMESPACE_OFFICE, "move", "on-move" }, + { XML_NAMESPACE_OFFICE, "page-count-change", "on-page-count-change" }, + { XML_NAMESPACE_DOM, "mouseover", "on-mouse-over" }, + { XML_NAMESPACE_DOM, "click", "on-click" }, + { XML_NAMESPACE_DOM, "mouseout", "on-mouse-out" }, + { XML_NAMESPACE_OFFICE, "load-error", "on-load-error" }, + { XML_NAMESPACE_OFFICE, "load-cancel", "on-load-cancel" }, + { XML_NAMESPACE_OFFICE, "load-done", "on-load-done" }, + { XML_NAMESPACE_DOM, "load", "on-load" }, + { XML_NAMESPACE_DOM, "unload", "on-unload" }, + { XML_NAMESPACE_OFFICE, "start-app", "on-start-app" }, + { XML_NAMESPACE_OFFICE, "close-app", "on-close-app" }, + { XML_NAMESPACE_OFFICE, "new", "on-new" }, + { XML_NAMESPACE_OFFICE, "save", "on-save" }, + { XML_NAMESPACE_OFFICE, "save-as", "on-save-as" }, + { XML_NAMESPACE_DOM, "DOMFocusIn", "on-focus" }, + { XML_NAMESPACE_DOM, "DOMFocusOut", "on-unfocus" }, + { XML_NAMESPACE_OFFICE, "print", "on-print" }, + { XML_NAMESPACE_DOM, "error", "on-error" }, + { XML_NAMESPACE_OFFICE, "load-finished", "on-load-finished" }, + { XML_NAMESPACE_OFFICE, "save-finished", "on-save-finished" }, + { XML_NAMESPACE_OFFICE, "modify-changed", "on-modify-changed" }, + { XML_NAMESPACE_OFFICE, "prepare-unload", "on-prepare-unload" }, + { XML_NAMESPACE_OFFICE, "new-mail", "on-new-mail" }, + { XML_NAMESPACE_OFFICE, "toggle-fullscreen", "on-toggle-fullscreen" }, + { XML_NAMESPACE_OFFICE, "save-done", "on-save-done" }, + { XML_NAMESPACE_OFFICE, "save-as-done", "on-save-as-done" }, + { XML_NAMESPACE_OFFICE, "create", "on-create" }, + { XML_NAMESPACE_OFFICE, "save-as-failed", "on-save-as-failed" }, + { XML_NAMESPACE_OFFICE, "save-failed", "on-save-failed" }, + { XML_NAMESPACE_OFFICE, "copy-to-failed", "on-copy-to-failed" }, + { XML_NAMESPACE_OFFICE, "title-changed", "on-title-changed" }, + + { XML_NAMESPACE_FORM, "approveaction", "on-approveaction" }, + { XML_NAMESPACE_FORM, "performaction", "on-performaction" }, + { XML_NAMESPACE_DOM, "change", "on-change" }, + { XML_NAMESPACE_FORM, "textchange", "on-textchange" }, + { XML_NAMESPACE_FORM, "itemstatechange", "on-itemstatechange" }, + { XML_NAMESPACE_DOM, "keydown", "on-keydown" }, + { XML_NAMESPACE_DOM, "keyup", "on-keyup" }, + { XML_NAMESPACE_FORM, "mousedrag", "on-mousedrag" }, + { XML_NAMESPACE_DOM, "mousemove", "on-mousemove" }, + { XML_NAMESPACE_DOM, "mousedown", "on-mousedown" }, + { XML_NAMESPACE_DOM, "mouseup", "on-mouseup" }, + { XML_NAMESPACE_FORM, "approvereset", "on-approvereset" }, + { XML_NAMESPACE_DOM, "reset", "on-reset" }, + { XML_NAMESPACE_DOM, "submit", "on-submit" }, + { XML_NAMESPACE_FORM, "approveupdate", "on-approveupdate" }, + { XML_NAMESPACE_FORM, "update", "on-update" }, + { XML_NAMESPACE_FORM, "startreload", "on-startreload" }, + { XML_NAMESPACE_FORM, "reload", "on-reload" }, + { XML_NAMESPACE_FORM, "startunload", "on-startunload" }, + { XML_NAMESPACE_FORM, "confirmdelete", "on-confirmdelete" }, + { XML_NAMESPACE_FORM, "approverowchange", "on-approverowchange" }, + { XML_NAMESPACE_FORM, "rowchange", "on-rowchange" }, + { XML_NAMESPACE_FORM, "approvecursormove", "on-approvecursormove" }, + { XML_NAMESPACE_FORM, "cursormove", "on-cursormove" }, + { XML_NAMESPACE_FORM, "supplyparameter", "on-supplyparameter" }, + { XML_NAMESPACE_FORM, "adjust", "on-adjust" }, + { 0, nullptr, nullptr } +}; + +XMLTransformerEventMapEntry const aFormTransformerEventMap[] = +{ + { XML_NAMESPACE_DOM, "mouseover", "on-mouseover" }, + { XML_NAMESPACE_DOM, "mouseout", "on-mouseout" }, + { XML_NAMESPACE_DOM, "DOMFocusOut", "on-blur" }, + { 0, nullptr, nullptr } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/EventMap.hxx b/xmloff/source/transform/EventMap.hxx new file mode 100644 index 000000000..11d20e185 --- /dev/null +++ b/xmloff/source/transform/EventMap.hxx @@ -0,0 +1,34 @@ +/* -*- 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 + +struct XMLTransformerEventMapEntry +{ + sal_uInt16 const m_nOASISPrefix; + const char* m_pOASISName; + const char* m_pOOoName; +}; + +extern XMLTransformerEventMapEntry const aTransformerEventMap[]; +extern XMLTransformerEventMapEntry const aFormTransformerEventMap[]; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/EventOASISTContext.cxx b/xmloff/source/transform/EventOASISTContext.cxx new file mode 100644 index 000000000..ea922b7ff --- /dev/null +++ b/xmloff/source/transform/EventOASISTContext.cxx @@ -0,0 +1,334 @@ +/* -*- 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 "EventOASISTContext.hxx" +#include "EventMap.hxx" +#include "MutableAttrList.hxx" +#include +#include "ActionMapTypesOASIS.hxx" +#include "AttrTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include +#include +#include + +// Used to parse Scripting Framework URLs +#include +#include +#include + +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +class XMLTransformerOASISEventMap_Impl: + public std::unordered_map< NameKey_Impl, OUString, + NameHash_Impl, NameHash_Impl > +{ +public: + explicit XMLTransformerOASISEventMap_Impl( XMLTransformerEventMapEntry const *pInit ); +}; + +XMLTransformerOASISEventMap_Impl::XMLTransformerOASISEventMap_Impl( XMLTransformerEventMapEntry const *pInit ) +{ + if( !pInit ) + return; + + XMLTransformerOASISEventMap_Impl::key_type aKey; + XMLTransformerOASISEventMap_Impl::mapped_type aData; + while( pInit->m_pOASISName ) + { + aKey.m_nPrefix = pInit->m_nOASISPrefix; + aKey.m_aLocalName = OUString::createFromAscii(pInit->m_pOASISName); + + OSL_ENSURE( find( aKey ) == end(), "duplicate event map entry" ); + + aData = OUString::createFromAscii(pInit->m_pOOoName); + + XMLTransformerOASISEventMap_Impl::value_type aVal( aKey, aData ); + + insert( aVal ); + ++pInit; + } +} + +XMLEventOASISTransformerContext::XMLEventOASISTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLRenameElemTransformerContext( rImp, rQName, + rImp.GetNamespaceMap().GetKeyByAttrName( rQName ), XML_EVENT ) +{ +} + +XMLEventOASISTransformerContext::~XMLEventOASISTransformerContext() +{ +} + +XMLTransformerOASISEventMap_Impl + *XMLEventOASISTransformerContext::CreateEventMap() +{ + return new XMLTransformerOASISEventMap_Impl( aTransformerEventMap ); +} + +XMLTransformerOASISEventMap_Impl + *XMLEventOASISTransformerContext::CreateFormEventMap() +{ + return new XMLTransformerOASISEventMap_Impl( aFormTransformerEventMap ); +} + +void XMLEventOASISTransformerContext::FlushEventMap( + XMLTransformerOASISEventMap_Impl *p ) +{ + delete p; +} + +OUString XMLEventOASISTransformerContext::GetEventName( + sal_uInt16 nPrefix, + const OUString& rName, + XMLTransformerOASISEventMap_Impl& rMap, + XMLTransformerOASISEventMap_Impl *pMap2) +{ + XMLTransformerOASISEventMap_Impl::key_type aKey( nPrefix, rName ); + if( pMap2 ) + { + XMLTransformerOASISEventMap_Impl::const_iterator aIter = + pMap2->find( aKey ); + if( aIter != pMap2->end() ) + return (*aIter).second; + } + + XMLTransformerOASISEventMap_Impl::const_iterator aIter = rMap.find( aKey ); + if( aIter == rMap.end() ) + return rName; + else + return (*aIter).second; +} + +static bool ParseURL( + const OUString& rAttrValue, + OUString* pName, OUString* pLocation ) +{ + Reference< css::uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + + Reference< css::uri::XUriReferenceFactory > xFactory = css::uri::UriReferenceFactory::create(xContext); + + Reference< css::uri::XVndSunStarScriptUrl > xUrl ( xFactory->parse( rAttrValue ), UNO_QUERY ); + + if ( xUrl.is() ) + { + const OUString& aLanguageKey = GetXMLToken( XML_LANGUAGE ); + if ( xUrl.is() && xUrl->hasParameter( aLanguageKey ) ) + { + OUString aLanguage = xUrl->getParameter( aLanguageKey ); + + if ( aLanguage.equalsIgnoreAsciiCase("basic") ) + { + *pName = xUrl->getName(); + + OUString tmp = + xUrl->getParameter( GetXMLToken( XML_LOCATION ) ); + + const OUString& doc = GetXMLToken( XML_DOCUMENT ); + + if ( tmp.equalsIgnoreAsciiCase( doc ) ) + { + *pLocation = doc; + } + else + { + *pLocation = GetXMLToken( XML_APPLICATION ); + } + return true; + } + } + } + return false; +} + +void XMLEventOASISTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + SAL_INFO("xmloff.transform", "XMLEventOASISTransformerContext::StartElement"); + + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OASIS_EVENT_ACTIONS ); + SAL_WARN_IF( pActions == nullptr, "xmloff.transform", "got no actions" ); + + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_HREF: + { + OUString aName, aLocation; + + bool bNeedsTransform = + ParseURL( rAttrValue, &aName, &aLocation ); + + if ( bNeedsTransform ) + { + pMutableAttrList->RemoveAttributeByIndex( i ); + + OUString aAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_SCRIPT, + ::xmloff::token::GetXMLToken( XML_MACRO_NAME ) ) ); + + pMutableAttrList->AddAttribute( aAttrQName, aName ); + + sal_Int16 idx = pMutableAttrList->GetIndexByName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_SCRIPT, + GetXMLToken( XML_LANGUAGE ) ) ); + + pMutableAttrList->SetValueByIndex( idx, + "StarBasic" ); + + OUString aLocQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_SCRIPT, + GetXMLToken( XML_LOCATION ) ) ); + + pMutableAttrList->AddAttribute( aLocQName, aLocation ); + } + } + break; + case XML_ATACTION_EVENT_NAME: + { + // Check if the event belongs to a form or control by + // checking the 2nd ancestor element, f.i.: + // + const XMLTransformerContext *pObjContext = + GetTransformer().GetAncestorContext( 1 ); + bool bForm = pObjContext && + + pObjContext->HasNamespace(XML_NAMESPACE_FORM ); + pMutableAttrList->SetValueByIndex( i, + GetTransformer().GetEventName( rAttrValue, + bForm ) ); + } + break; + case XML_ATACTION_REMOVE_NAMESPACE_PREFIX: + { + OUString aAttrValue( rAttrValue ); + sal_uInt16 nValPrefix = + static_cast((*aIter).second.m_nParam1); + if( GetTransformer().RemoveNamespacePrefix( + aAttrValue, nValPrefix ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_MACRO_NAME: + { + OUString aName, aLocation; + bool bNeedsTransform = + ParseURL( rAttrValue, &aName, &aLocation ); + + if ( bNeedsTransform ) + { + pMutableAttrList->SetValueByIndex( i, aName ); + + sal_Int16 idx = pMutableAttrList->GetIndexByName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_SCRIPT, + GetXMLToken( XML_LANGUAGE ) ) ); + + pMutableAttrList->SetValueByIndex( idx, + "StarBasic" ); + + OUString aLocQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_SCRIPT, + GetXMLToken( XML_LOCATION ) ) ); + + pMutableAttrList->AddAttribute( aLocQName, aLocation ); + } + else + { + const OUString& rApp = GetXMLToken( XML_APPLICATION ); + const OUString& rDoc = GetXMLToken( XML_DOCUMENT ); + OUString aAttrValue; + if( rAttrValue.getLength() > rApp.getLength()+1 && + o3tl::equalsIgnoreAsciiCase(rAttrValue.subView(0,rApp.getLength()), rApp) && + ':' == rAttrValue[rApp.getLength()] ) + { + aLocation = rApp; + aAttrValue = rAttrValue.copy( rApp.getLength()+1 ); + } + else if( rAttrValue.getLength() > rDoc.getLength()+1 && + o3tl::equalsIgnoreAsciiCase(rAttrValue.subView(0,rDoc.getLength()), rDoc) && + ':' == rAttrValue[rDoc.getLength()] ) + { + aLocation= rDoc; + aAttrValue = rAttrValue.copy( rDoc.getLength()+1 ); + } + if( !aAttrValue.isEmpty() ) + pMutableAttrList->SetValueByIndex( i, + aAttrValue ); + if( !aLocation.isEmpty() ) + { + OUString aAttrQName( GetTransformer().GetNamespaceMap(). + GetQNameByKey( XML_NAMESPACE_SCRIPT, + ::xmloff::token::GetXMLToken( XML_LOCATION ) ) ); + pMutableAttrList->AddAttribute( aAttrQName, aLocation ); + // draw bug + aAttrQName = GetTransformer().GetNamespaceMap(). + GetQNameByKey( XML_NAMESPACE_SCRIPT, + ::xmloff::token::GetXMLToken( XML_LIBRARY ) ); + pMutableAttrList->AddAttribute( aAttrQName, aLocation ); + } + } + } + break; + case XML_ATACTION_COPY: + break; + default: + SAL_WARN( "xmloff.transform", "unknown action" ); + break; + } + } + } + + XMLRenameElemTransformerContext::StartElement( xAttrList ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/EventOASISTContext.hxx b/xmloff/source/transform/EventOASISTContext.hxx new file mode 100644 index 000000000..53cf0dbf2 --- /dev/null +++ b/xmloff/source/transform/EventOASISTContext.hxx @@ -0,0 +1,44 @@ +/* -*- 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 "RenameElemTContext.hxx" + +class XMLTransformerOASISEventMap_Impl; + +class XMLEventOASISTransformerContext : public XMLRenameElemTransformerContext +{ +public: + XMLEventOASISTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + virtual ~XMLEventOASISTransformerContext() override; + + static XMLTransformerOASISEventMap_Impl *CreateFormEventMap(); + static XMLTransformerOASISEventMap_Impl *CreateEventMap(); + static void FlushEventMap( XMLTransformerOASISEventMap_Impl *p ); + static OUString GetEventName( sal_uInt16 nPrefix, + const OUString& rName, + XMLTransformerOASISEventMap_Impl& rMap, + XMLTransformerOASISEventMap_Impl* pMap2 ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/EventOOoTContext.cxx b/xmloff/source/transform/EventOOoTContext.cxx new file mode 100644 index 000000000..1611e6b7a --- /dev/null +++ b/xmloff/source/transform/EventOOoTContext.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/. + * + * 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 "EventOOoTContext.hxx" +#include "EventMap.hxx" +#include "MutableAttrList.hxx" +#include "ActionMapTypesOOo.hxx" +#include "AttrTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include + +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +class XMLTransformerOOoEventMap_Impl: + public std::unordered_map< OUString, NameKey_Impl > +{ +public: + + void AddMap( XMLTransformerEventMapEntry const *pInit ); + + XMLTransformerOOoEventMap_Impl( XMLTransformerEventMapEntry const *pInit, + XMLTransformerEventMapEntry const *pInit2 ); +}; + +void XMLTransformerOOoEventMap_Impl::AddMap( XMLTransformerEventMapEntry const *pInit ) +{ + XMLTransformerOOoEventMap_Impl::key_type aKey; + XMLTransformerOOoEventMap_Impl::mapped_type aData; + while( pInit->m_pOOoName ) + { + aKey = OUString::createFromAscii(pInit->m_pOOoName); + + OSL_ENSURE( find( aKey ) == end(), "duplicate event map entry" ); + + aData.m_nPrefix = pInit->m_nOASISPrefix; + aData.m_aLocalName = OUString::createFromAscii(pInit->m_pOASISName); + + XMLTransformerOOoEventMap_Impl::value_type aVal( aKey, aData ); + + if( !insert( aVal ).second ) + { + OSL_FAIL( "duplicate OOo event name entry" ); + } + + ++pInit; + } +} + +XMLTransformerOOoEventMap_Impl::XMLTransformerOOoEventMap_Impl( + XMLTransformerEventMapEntry const *pInit, + XMLTransformerEventMapEntry const *pInit2 ) +{ + if( pInit ) + AddMap( pInit ); + if( pInit2 ) + AddMap( pInit2 ); +} + +XMLEventOOoTransformerContext::XMLEventOOoTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + bool bPersistent ) : + XMLPersElemContentTContext( rImp, rQName, + rImp.GetNamespaceMap().GetKeyByAttrValueQName(rQName, nullptr), + XML_EVENT_LISTENER), + m_bPersistent( bPersistent ) +{ +} + +XMLEventOOoTransformerContext::~XMLEventOOoTransformerContext() +{ +} + +XMLTransformerOOoEventMap_Impl + *XMLEventOOoTransformerContext::CreateEventMap() +{ + return new XMLTransformerOOoEventMap_Impl( aTransformerEventMap, + aFormTransformerEventMap ); +} + +void XMLEventOOoTransformerContext::FlushEventMap( + XMLTransformerOOoEventMap_Impl *p ) +{ + delete p; +} + +sal_uInt16 XMLEventOOoTransformerContext::GetEventName( + const OUString& rName, + OUString& rNewName, + XMLTransformerOOoEventMap_Impl& rMap ) +{ + const XMLTransformerOOoEventMap_Impl::key_type& aKey( rName ); + XMLTransformerOOoEventMap_Impl::const_iterator aIter = rMap.find( aKey ); + if( aIter == rMap.end() ) + { + rNewName = rName; + return XML_NAMESPACE_UNKNOWN; + } + else + { + rNewName = (*aIter).second.m_aLocalName; + return (*aIter).second.m_nPrefix; + } +} + +void XMLEventOOoTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OOO_EVENT_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + OUString aLocation, aMacroName; + sal_Int16 nMacroName = -1; + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_HREF: + // TODO + break; + case XML_ATACTION_EVENT_NAME: + pMutableAttrList->SetValueByIndex( i, + GetTransformer().GetEventName( rAttrValue ) ); + break; + case XML_ATACTION_ADD_NAMESPACE_PREFIX: + { + OUString aAttrValue( rAttrValue ); + sal_uInt16 nValPrefix = + static_cast((*aIter).second.m_nParam1); + GetTransformer().AddNamespacePrefix( aAttrValue, + nValPrefix ); + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_MACRO_LOCATION: + aLocation = rAttrValue; + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + break; + case XML_ATACTION_MACRO_NAME: + aMacroName = rAttrValue; + nMacroName = i; + break; + case XML_ATACTION_COPY: + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + if( nMacroName != -1 && !aLocation.isEmpty() ) + { + if( !IsXMLToken( aLocation, XML_APPLICATION ) ) + aLocation = GetXMLToken( XML_DOCUMENT ); + OUString sTmp = aLocation + ":" + aMacroName; + pMutableAttrList->SetValueByIndex( nMacroName, sTmp ); + } + + if( m_bPersistent ) + XMLPersElemContentTContext::StartElement( xAttrList ); + else + GetTransformer().GetDocHandler()->startElement( GetExportQName(), xAttrList ); +} + +void XMLEventOOoTransformerContext::EndElement() +{ + if( m_bPersistent ) + XMLPersElemContentTContext::EndElement(); + else + GetTransformer().GetDocHandler()->endElement( GetExportQName() ); +} + +rtl::Reference XMLEventOOoTransformerContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& xAttrList ) +{ + if( m_bPersistent ) + return XMLPersElemContentTContext::CreateChildContext(nPrefix, rLocalName, rQName, xAttrList); + else + return XMLTransformerContext::CreateChildContext(nPrefix, rLocalName, rQName, xAttrList); +} + +bool XMLEventOOoTransformerContext::IsPersistent() const +{ + return m_bPersistent; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/EventOOoTContext.hxx b/xmloff/source/transform/EventOOoTContext.hxx new file mode 100644 index 000000000..19461d310 --- /dev/null +++ b/xmloff/source/transform/EventOOoTContext.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/. + * + * 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 "DeepTContext.hxx" + +class XMLTransformerOOoEventMap_Impl; + +class XMLEventOOoTransformerContext : public XMLPersElemContentTContext +{ + bool const m_bPersistent; + +public: + XMLEventOOoTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + bool bPersistent ); + virtual ~XMLEventOOoTransformerContext() override; + + static XMLTransformerOOoEventMap_Impl *CreateEventMap(); + static void FlushEventMap( XMLTransformerOOoEventMap_Impl *p ); + static sal_uInt16 GetEventName( const OUString& rName, + OUString& rNewName, + XMLTransformerOOoEventMap_Impl& rMap ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual bool IsPersistent() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FamilyType.hxx b/xmloff/source/transform/FamilyType.hxx new file mode 100644 index 000000000..15c0e9e24 --- /dev/null +++ b/xmloff/source/transform/FamilyType.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/. + * + * 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 + +enum XMLFamilyType +{ + XML_FAMILY_TYPE_GRAPHIC, + XML_FAMILY_TYPE_PRESENTATION, + XML_FAMILY_TYPE_DRAWING_PAGE, + XML_FAMILY_TYPE_MASTER_PAGE, + XML_FAMILY_TYPE_PAGE_LAYOUT, + XML_FAMILY_TYPE_HEADER_FOOTER, + XML_FAMILY_TYPE_TEXT, + XML_FAMILY_TYPE_PARAGRAPH, + XML_FAMILY_TYPE_RUBY, + XML_FAMILY_TYPE_SECTION, + XML_FAMILY_TYPE_TABLE, + XML_FAMILY_TYPE_TABLE_COLUMN, + XML_FAMILY_TYPE_TABLE_ROW, + XML_FAMILY_TYPE_TABLE_CELL, + XML_FAMILY_TYPE_LIST, + XML_FAMILY_TYPE_CHART, + XML_FAMILY_TYPE_DATA, + XML_FAMILY_TYPE_GRADIENT, + XML_FAMILY_TYPE_HATCH, + XML_FAMILY_TYPE_FILL_IMAGE, + XML_FAMILY_TYPE_STROKE_DASH, + XML_FAMILY_TYPE_MARKER, + XML_FAMILY_TYPE_END +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FlatTContext.cxx b/xmloff/source/transform/FlatTContext.cxx new file mode 100644 index 000000000..0b00a0314 --- /dev/null +++ b/xmloff/source/transform/FlatTContext.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/. + * + * 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 "FlatTContext.hxx" +#include "TransformerBase.hxx" + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +XMLPersTextContentTContext::XMLPersTextContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLPersAttrListTContext( rImp, rQName ) +{ +} + +XMLPersTextContentTContext::XMLPersTextContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ) : + XMLPersAttrListTContext( rImp, rQName, nPrefix, eToken ) +{ +} + +XMLPersTextContentTContext::~XMLPersTextContentTContext() +{ +} + +void XMLPersTextContentTContext::Characters( const OUString& rChars ) +{ + m_aCharacters += rChars; +} + +void XMLPersTextContentTContext::ExportContent() +{ + GetTransformer().GetDocHandler()->characters( m_aCharacters ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FlatTContext.hxx b/xmloff/source/transform/FlatTContext.hxx new file mode 100644 index 000000000..8a6787c26 --- /dev/null +++ b/xmloff/source/transform/FlatTContext.hxx @@ -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/. + * + * 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 "PersAttrListTContext.hxx" + + +class XMLPersTextContentTContext : public XMLPersAttrListTContext +{ + OUString m_aCharacters; + +public: + // A contexts constructor does anything that is required if an element + // starts. Namespace processing has been done already. + // Note that virtual methods cannot be used inside constructors. Use + // StartElement instead if this is required. + XMLPersTextContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + // attr list/text content persistence + renaming + XMLPersTextContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ); + + // A contexts destructor does anything that is required if an element + // ends. By default, nothing is done. + // Note that virtual methods cannot be used inside destructors. Use + // EndElement instead if this is required. + virtual ~XMLPersTextContentTContext() override; + + // This method is called for all characters that are contained in the + // current element. + virtual void Characters( const OUString& rChars ) override; + + virtual void ExportContent() override; + + const OUString& GetTextContent() const { return m_aCharacters; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FormPropOASISTContext.cxx b/xmloff/source/transform/FormPropOASISTContext.cxx new file mode 100644 index 000000000..6b29f0da9 --- /dev/null +++ b/xmloff/source/transform/FormPropOASISTContext.cxx @@ -0,0 +1,211 @@ +/* -*- 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 "MutableAttrList.hxx" +#include +#include +#include "ActionMapTypesOASIS.hxx" +#include "AttrTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include "FormPropOASISTContext.hxx" +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLTokenEnum XMLFormPropOASISTransformerContext::GetValueType( + const OUString& rValue ) +{ + XMLTokenEnum eRet = XML_DOUBLE; + bool bNeg = false; + sal_uInt32 nVal = 0; + + sal_Int32 nPos = 0; + sal_Int32 nLen = rValue.getLength(); + + // skip white space + while( nPos < nLen && ' ' == rValue[nPos] ) + nPos++; + + if( nPos < nLen && '-' == rValue[nPos] ) + { + bNeg = true; + nPos++; + } + + // get number + bool bOverflow = false; + while( nPos < nLen && + '0' <= rValue[nPos] && + '9' >= rValue[nPos] ) + { + nVal *= 10; + nVal += (rValue[nPos] - '0'); + bOverflow |= (nVal > (bNeg ? 2147483648UL : 2147483647UL)); + nPos++; + } + + // skip white space + while( nPos < nLen && ' ' == rValue[nPos] ) + nPos++; + + if( nPos == nLen ) + { + // It's an integer number + if( bOverflow ) + eRet = XML_LONG; + else if( nVal > (bNeg ? 32768UL : 32767UL) ) + eRet = XML_INT; + else + eRet = XML_SHORT; + } + + return eRet; +} + +XMLFormPropOASISTransformerContext::XMLFormPropOASISTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + XMLTokenEnum eLocalName ) : + XMLRenameElemTransformerContext( rImp, rQName, XML_NAMESPACE_FORM, + XML_PROPERTY ), + m_bIsList( XML_LIST_PROPERTY == eLocalName), + m_bIsListValue( XML_LIST_VALUE == eLocalName) +{ +} + +XMLFormPropOASISTransformerContext::~XMLFormPropOASISTransformerContext() +{ +} + +void XMLFormPropOASISTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OASIS_FORM_PROP_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + rtl::Reference pMutableAttrList = + new XMLMutableAttributeList( rAttrList ); + Reference< XAttributeList > xAttrList( pMutableAttrList ); + + sal_Int16 nValueTypeAttr = -1; + OUString aValue; + bool bIsVoid = false; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_RENAME: + if( IsXMLToken( aLocalName, XML_VALUE_TYPE ) ) + { + if( IsXMLToken( rAttrValue, XML_FLOAT ) ) + { + nValueTypeAttr = i; + } + else if( IsXMLToken( rAttrValue, XML_VOID ) ) + { + pMutableAttrList->SetValueByIndex( i, + GetXMLToken( XML_SHORT ) ); + bIsVoid = true; + } + } + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + pMutableAttrList->RenameAttributeByIndex( i, aNewAttrQName ); + } + break; + case XML_ATACTION_REMOVE: + if( !IsXMLToken( aLocalName, XML_CURRENCY ) ) + aValue = rAttrValue; + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + if( m_bIsList ) + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_FORM, + GetXMLToken( XML_PROPERTY_IS_LIST ) ) ); + pMutableAttrList->AddAttribute( aNewAttrQName, + GetXMLToken( XML_TRUE ) ); + } + + if( nValueTypeAttr != -1 ) + pMutableAttrList->SetValueByIndex( nValueTypeAttr, + GetXMLToken( GetValueType( aValue ) ) ); + + if( !m_bIsListValue ) + XMLRenameElemTransformerContext::StartElement( xAttrList ); + if( m_bIsList ) + return; + + pMutableAttrList = new XMLMutableAttributeList; + xAttrList = pMutableAttrList; + if( bIsVoid ) + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_FORM, GetXMLToken( XML_PROPERTY_IS_VOID ) ) ); + pMutableAttrList->AddAttribute( aNewAttrQName, + GetXMLToken( XML_TRUE ) ); + } + + OUString aValueElemQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_FORM, GetXMLToken( XML_PROPERTY_VALUE ) ) ); + GetTransformer().GetDocHandler()->startElement( aValueElemQName, + xAttrList ); + GetTransformer().GetDocHandler()->characters( aValue ); + GetTransformer().GetDocHandler()->endElement( aValueElemQName ); +} + +void XMLFormPropOASISTransformerContext::EndElement() +{ + if( !m_bIsListValue ) + XMLRenameElemTransformerContext::EndElement(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FormPropOASISTContext.hxx b/xmloff/source/transform/FormPropOASISTContext.hxx new file mode 100644 index 000000000..5a656a629 --- /dev/null +++ b/xmloff/source/transform/FormPropOASISTContext.hxx @@ -0,0 +1,43 @@ +/* -*- 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 "RenameElemTContext.hxx" + +class XMLFormPropOASISTransformerContext : + public XMLRenameElemTransformerContext +{ + bool const m_bIsList; + bool const m_bIsListValue; + + static ::xmloff::token::XMLTokenEnum GetValueType( const OUString& rValue ); + +public: + XMLFormPropOASISTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + ::xmloff::token::XMLTokenEnum eLocalName ); + + virtual ~XMLFormPropOASISTransformerContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FormPropOOoTContext.cxx b/xmloff/source/transform/FormPropOOoTContext.cxx new file mode 100644 index 000000000..1f5c6086d --- /dev/null +++ b/xmloff/source/transform/FormPropOOoTContext.cxx @@ -0,0 +1,250 @@ +/* -*- 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 "MutableAttrList.hxx" +#include +#include +#include "IgnoreTContext.hxx" +#include "ActionMapTypesOOo.hxx" +#include "AttrTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include "FormPropOOoTContext.hxx" +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +class XMLFormPropValueTContext_Impl : public XMLTransformerContext +{ + OUString m_aCharacters; + bool m_bIsVoid; + +public: + // element content persistence only + XMLFormPropValueTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void EndElement() override; + + virtual void Characters( const OUString& rChars ) override; + + virtual bool IsPersistent() const override; + + bool IsVoid() const { return m_bIsVoid; } + const OUString& GetTextContent() const { return m_aCharacters; } +}; + +XMLFormPropValueTContext_Impl::XMLFormPropValueTContext_Impl( + XMLTransformerBase& rTransformer, + const OUString& rQName ) : + XMLTransformerContext( rTransformer, rQName ), + m_bIsVoid( false ) +{ +} + +void XMLFormPropValueTContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = rAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + if( XML_NAMESPACE_FORM == nPrefix && + IsXMLToken( aLocalName, XML_PROPERTY_IS_VOID ) && + IsXMLToken( rAttrList->getValueByIndex( i ), XML_TRUE ) ) + m_bIsVoid = true; + } +} + +void XMLFormPropValueTContext_Impl::EndElement() +{ +} + +void XMLFormPropValueTContext_Impl::Characters( const OUString& rChars ) +{ + m_aCharacters += rChars; +} + +bool XMLFormPropValueTContext_Impl::IsPersistent() const +{ + return true; +} + +XMLFormPropOOoTransformerContext::XMLFormPropOOoTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rQName ), + m_nValueTypeAttr( -1 ), + m_eValueToken( XML_VALUE ), + m_eValueTypeToken( XML_TOKEN_END ), + m_bIsList( false ) +{ +} + +XMLFormPropOOoTransformerContext::~XMLFormPropOOoTransformerContext() +{ +} + +rtl::Reference XMLFormPropOOoTransformerContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& ) +{ + rtl::Reference pContext; + + if( XML_NAMESPACE_FORM == nPrefix && + IsXMLToken( rLocalName, XML_PROPERTY_VALUE ) ) + { + if( m_bIsList ) + { + pContext.set(new XMLFormPropValueTContext_Impl( GetTransformer(), + rQName )); + } + else if( !m_xValueContext.is() ) + { + m_xValueContext= + new XMLFormPropValueTContext_Impl( GetTransformer(), rQName ); + pContext = m_xValueContext; + } + } + + // default is ignore + if( !pContext.is() ) + pContext.set(new XMLIgnoreTransformerContext( GetTransformer(), rQName, + true, true )); + return pContext; +} + +void XMLFormPropOOoTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OOO_FORM_PROP_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + rtl::Reference pMutableAttrList = + new XMLMutableAttributeList( rAttrList, true ); + m_xAttrList = pMutableAttrList; + + OUString aValueType; + sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = rAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + const OUString& rAttrValue = rAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_RENAME: + if( IsXMLToken( aLocalName, XML_PROPERTY_TYPE ) ) + { + aValueType = rAttrValue; + m_nValueTypeAttr = i; + } + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + pMutableAttrList->RenameAttributeByIndex( i, aNewAttrQName ); + } + break; + case XML_ATACTION_REMOVE: + if( IsXMLToken( aLocalName, XML_PROPERTY_IS_LIST ) ) + { + m_aElemQName = + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_FORM, GetXMLToken( XML_LIST_PROPERTY ) ); + m_bIsList = true; + } + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + if( !aValueType.isEmpty() ) + { + if( IsXMLToken( aValueType, XML_STRING ) ) + m_eValueToken = XML_STRING_VALUE; + else if( IsXMLToken( aValueType, XML_BOOLEAN ) ) + m_eValueToken = XML_BOOLEAN_VALUE; + else if( IsXMLToken( aValueType, XML_SHORT ) || + IsXMLToken( aValueType, XML_INT ) || + IsXMLToken( aValueType, XML_LONG ) || + IsXMLToken( aValueType, XML_DOUBLE ) ) + m_eValueTypeToken = XML_FLOAT; + } +} + +void XMLFormPropOOoTransformerContext::EndElement() +{ + if( m_xValueContext.is() ) + { + if( m_xValueContext->IsVoid() ) + { + m_eValueTypeToken = XML_VOID; + } + else + { + OUString aAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OFFICE, GetXMLToken(m_eValueToken) ) ); + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) + ->AddAttribute( aAttrQName, m_xValueContext->GetTextContent() ); + } + } + + if( m_nValueTypeAttr != -1 && m_eValueTypeToken != XML_TOKEN_END ) + { + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) + ->SetValueByIndex( m_nValueTypeAttr , + GetXMLToken( m_eValueTypeToken ) ); + } + + GetTransformer().GetDocHandler()->startElement( m_aElemQName, m_xAttrList ); + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FormPropOOoTContext.hxx b/xmloff/source/transform/FormPropOOoTContext.hxx new file mode 100644 index 000000000..ca0df6bdc --- /dev/null +++ b/xmloff/source/transform/FormPropOOoTContext.hxx @@ -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/. + * + * 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 +#include "TransformerContext.hxx" + +class XMLFormPropValueTContext_Impl; + +class XMLFormPropOOoTransformerContext : public XMLTransformerContext +{ + css::uno::Reference< css::xml::sax::XAttributeList > m_xAttrList; + + ::rtl::Reference< XMLFormPropValueTContext_Impl > m_xValueContext; + + OUString m_aElemQName; + + sal_Int16 m_nValueTypeAttr; + + ::xmloff::token::XMLTokenEnum m_eValueToken; + ::xmloff::token::XMLTokenEnum m_eValueTypeToken; + + bool m_bIsList; + +public: + XMLFormPropOOoTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual ~XMLFormPropOOoTransformerContext() override; + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FrameOASISTContext.cxx b/xmloff/source/transform/FrameOASISTContext.cxx new file mode 100644 index 000000000..e2c2295c8 --- /dev/null +++ b/xmloff/source/transform/FrameOASISTContext.cxx @@ -0,0 +1,187 @@ +/* -*- 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 "FrameOASISTContext.hxx" +#include "IgnoreTContext.hxx" +#include "MutableAttrList.hxx" +#include +#include "ActionMapTypesOASIS.hxx" +#include "ElemTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +bool XMLFrameOASISTransformerContext::IsLinkedEmbeddedObject( + std::u16string_view rLocalName, + const Reference< XAttributeList >& rAttrList ) +{ + if( !(IsXMLToken( rLocalName, XML_OBJECT ) || + IsXMLToken( rLocalName, XML_OBJECT_OLE) ) ) + return false; + + sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + OUString aAttrName( rAttrList->getNameByIndex( i ) ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( aAttrName, + &aLocalName ); + if( XML_NAMESPACE_XLINK == nPrefix && + IsXMLToken( aLocalName, XML_HREF ) ) + { + OUString sHRef( rAttrList->getValueByIndex( i ) ); + if (sHRef.isEmpty()) + { + // When the href is empty then the object is not linked but + // a placeholder. + return false; + } + GetTransformer().ConvertURIToOOo( sHRef, true ); + return sHRef.isEmpty() || '#' != sHRef[0]; + } + } + + return false; +} + + +XMLFrameOASISTransformerContext::XMLFrameOASISTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ), + m_bIgnoreElement( false ) +{ +} + +XMLFrameOASISTransformerContext::~XMLFrameOASISTransformerContext() +{ +} + +void XMLFrameOASISTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + m_xAttrList = new XMLMutableAttributeList( rAttrList, true ); + + sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = rAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, &aLocalName ); + + if( (nPrefix == XML_NAMESPACE_PRESENTATION) && IsXMLToken( aLocalName, XML_CLASS ) ) + { + const OUString& rAttrValue = rAttrList->getValueByIndex( i ); + if( IsXMLToken( rAttrValue, XML_HEADER ) || IsXMLToken( rAttrValue, XML_FOOTER ) || + IsXMLToken( rAttrValue, XML_PAGE_NUMBER ) || IsXMLToken( rAttrValue, XML_DATE_TIME ) ) + { + m_bIgnoreElement = true; + break; + } + } + } +} + +rtl::Reference XMLFrameOASISTransformerContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& rAttrList ) +{ + rtl::Reference pContext; + + if( m_bIgnoreElement ) + { + // do not export the frame element and all of its children + pContext.set(new XMLIgnoreTransformerContext( GetTransformer(), + rQName, + true, true )); + } + else + { + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OASIS_FRAME_ELEM_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + XMLTransformerActions::key_type aKey( nPrefix, rLocalName ); + XMLTransformerActions::const_iterator aIter = pActions->find( aKey ); + + if( aIter != pActions->end() ) + { + switch( (*aIter).second.m_nActionType ) + { + case XML_ETACTION_COPY: + if( m_aElemQName.isEmpty() && + !IsLinkedEmbeddedObject( rLocalName, rAttrList ) ) + { + pContext.set(new XMLIgnoreTransformerContext( GetTransformer(), + rQName, + false, false )); + m_aElemQName = rQName; + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) + ->AppendAttributeList( rAttrList ); + GetTransformer().ProcessAttrList( m_xAttrList, + OASIS_SHAPE_ACTIONS, + false ); + GetTransformer().GetDocHandler()->startElement( m_aElemQName, m_xAttrList ); + } + else + { + pContext.set(new XMLIgnoreTransformerContext( GetTransformer(), + rQName, + true, true )); + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + // default is copying + if( !pContext.is() ) + pContext = XMLTransformerContext::CreateChildContext( nPrefix, + rLocalName, + rQName, + rAttrList ); + + return pContext; +} + +void XMLFrameOASISTransformerContext::EndElement() +{ + if( !m_bIgnoreElement ) + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +void XMLFrameOASISTransformerContext::Characters( const OUString& rChars ) +{ + // ignore + if( !m_aElemQName.isEmpty() && !m_bIgnoreElement ) + XMLTransformerContext::Characters( rChars ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FrameOASISTContext.hxx b/xmloff/source/transform/FrameOASISTContext.hxx new file mode 100644 index 000000000..d7ffaedb3 --- /dev/null +++ b/xmloff/source/transform/FrameOASISTContext.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/. + * + * 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 "TransformerContext.hxx" + +class XMLFrameOASISTransformerContext : public XMLTransformerContext +{ + css::uno::Reference< css::xml::sax::XAttributeList > m_xAttrList; + + OUString m_aElemQName; + + bool m_bIgnoreElement; + + bool IsLinkedEmbeddedObject( + std::u16string_view rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList >& rAttrList ); + +public: + XMLFrameOASISTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual ~XMLFrameOASISTransformerContext() override; + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void EndElement() override; + + virtual void Characters( const OUString& rChars ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FrameOOoTContext.cxx b/xmloff/source/transform/FrameOOoTContext.cxx new file mode 100644 index 000000000..a8cbd5a8f --- /dev/null +++ b/xmloff/source/transform/FrameOOoTContext.cxx @@ -0,0 +1,157 @@ +/* -*- 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 "FrameOOoTContext.hxx" +#include "MutableAttrList.hxx" +#include +#include +#include "ActionMapTypesOOo.hxx" +#include "AttrTransformerAction.hxx" +#include "ElemTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "TransformerBase.hxx" +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLFrameOOoTransformerContext::XMLFrameOOoTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLPersElemContentTContext( rImp, rQName ), + m_aElemQName( rImp.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_DRAW, + ::xmloff::token::GetXMLToken( XML_FRAME ) ) ) +{ +} + +void XMLFrameOOoTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OOO_FRAME_ATTR_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList = + GetTransformer().ProcessAttrList( xAttrList, OOO_SHAPE_ACTIONS, + true ); + if( !pMutableAttrList ) + pMutableAttrList = new XMLMutableAttributeList( rAttrList ); + xAttrList = pMutableAttrList; + + rtl::Reference pFrameMutableAttrList = + new XMLMutableAttributeList; + Reference< XAttributeList > xFrameAttrList( pFrameMutableAttrList ); + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_MOVE_TO_ELEM: + pFrameMutableAttrList->AddAttribute( rAttrName, rAttrValue ); + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + GetTransformer().GetDocHandler()->startElement( m_aElemQName, + xFrameAttrList ); + XMLTransformerContext::StartElement( xAttrList ); +} + +rtl::Reference XMLFrameOOoTransformerContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& rAttrList ) +{ + rtl::Reference pContext; + + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OOO_FRAME_ELEM_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + XMLTransformerActions::key_type aKey( nPrefix, rLocalName ); + XMLTransformerActions::const_iterator aIter = pActions->find( aKey ); + + if( aIter != pActions->end() ) + { + switch( (*aIter).second.m_nActionType ) + { + case XML_ETACTION_COPY: + case XML_ETACTION_COPY_TEXT: + case XML_ETACTION_RENAME_ELEM: + // the ones in the list have to be persistent + + pContext = XMLPersElemContentTContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ); + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + + // default is copying + if( !pContext.is() ) + pContext = XMLTransformerContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ); + + return pContext; +} + +void XMLFrameOOoTransformerContext::EndElement() +{ + XMLTransformerContext::EndElement(); + ExportContent(); + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +void XMLFrameOOoTransformerContext::Characters( const OUString& rChars ) +{ + XMLTransformerContext::Characters( rChars ); +} + +bool XMLFrameOOoTransformerContext::IsPersistent() const +{ + // this context stores some of its child elements, but is not persistent + // itself. + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/FrameOOoTContext.hxx b/xmloff/source/transform/FrameOOoTContext.hxx new file mode 100644 index 000000000..44d360699 --- /dev/null +++ b/xmloff/source/transform/FrameOOoTContext.hxx @@ -0,0 +1,46 @@ +/* -*- 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 "DeepTContext.hxx" + +class XMLFrameOOoTransformerContext : public XMLPersElemContentTContext +{ + OUString const m_aElemQName; + +public: + XMLFrameOOoTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void EndElement() override; + + virtual void Characters( const OUString& rChars ) override; + + virtual bool IsPersistent() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/IgnoreTContext.cxx b/xmloff/source/transform/IgnoreTContext.cxx new file mode 100644 index 000000000..db4e212ea --- /dev/null +++ b/xmloff/source/transform/IgnoreTContext.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 "IgnoreTContext.hxx" +#include "TransformerBase.hxx" + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +XMLIgnoreTransformerContext::XMLIgnoreTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + bool bIgnoreChars, + bool bIgnoreElems ) : + XMLTransformerContext( rImp, rQName ), + m_bIgnoreCharacters( bIgnoreChars ), + m_bIgnoreElements( bIgnoreElems ), + m_bAllowCharactersRecursive( false ), + m_bRecursiveUse( false ) +{ +} + +XMLIgnoreTransformerContext::XMLIgnoreTransformerContext( + XMLTransformerBase& rTransformer, + const OUString& rQName, + bool bAllowCharactersRecursive ) : + XMLTransformerContext( rTransformer, rQName ), + m_bIgnoreCharacters( false ), + m_bIgnoreElements( false ), + m_bAllowCharactersRecursive( bAllowCharactersRecursive ), + m_bRecursiveUse( true ) +{ +} + +rtl::Reference XMLIgnoreTransformerContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& xAttrList ) +{ + rtl::Reference pContext; + if( m_bIgnoreElements ) + pContext.set(new XMLIgnoreTransformerContext( GetTransformer(), + rQName, true, + true )); + else if (m_bRecursiveUse) + pContext.set(new XMLIgnoreTransformerContext( GetTransformer(), + rQName, m_bAllowCharactersRecursive )); + else + pContext = XMLTransformerContext::CreateChildContext( + nPrefix, rLocalName, rQName, xAttrList ); + + return pContext; +} + +void XMLIgnoreTransformerContext::StartElement( const Reference< XAttributeList >& ) +{ + // ignore +} + +void XMLIgnoreTransformerContext::EndElement() +{ + // ignore +} + +void XMLIgnoreTransformerContext::Characters( const OUString& rChars ) +{ + if( !m_bIgnoreCharacters ) + GetTransformer().GetDocHandler()->characters( rChars ); + else if ( m_bRecursiveUse && m_bAllowCharactersRecursive ) + GetTransformer().GetDocHandler()->characters( rChars ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/IgnoreTContext.hxx b/xmloff/source/transform/IgnoreTContext.hxx new file mode 100644 index 000000000..2f349cfb3 --- /dev/null +++ b/xmloff/source/transform/IgnoreTContext.hxx @@ -0,0 +1,71 @@ +/* -*- 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 "TransformerContext.hxx" + + +class XMLIgnoreTransformerContext : public XMLTransformerContext +{ + bool const m_bIgnoreCharacters; + bool const m_bIgnoreElements; + bool const m_bAllowCharactersRecursive; + bool const m_bRecursiveUse; + +public: + // A contexts constructor does anything that is required if an element + // starts. Namespace processing has been done already. + // Note that virtual methods cannot be used inside constructors. Use + // StartElement instead if this is required. + XMLIgnoreTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + bool bIgnoreCharacters, + bool bIgnoreElements ); + // A contexts constructor does anything that is required if an element + // starts. Namespace processing has been done already. + // Note that virtual methods cannot be used inside constructors. Use + // StartElement instead if this is required. + XMLIgnoreTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + bool bAllowCharactersRecursive ); + + // Create a children element context. By default, the import's + // CreateContext method is called to create a new default context. + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + // StartElement is called after a context has been constructed and + // before an elements context is parsed. It may be used for actions that + // require virtual methods. The default is to do nothing. + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + // EndElement is called before a context will be destructed, but + // after an elements context has been parsed. It may be used for actions + // that require virtual methods. The default is to do nothing. + virtual void EndElement() override; + + // This method is called for all characters that are contained in the + // current element. The default is to ignore them. + virtual void Characters( const OUString& rChars ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/MergeElemTContext.cxx b/xmloff/source/transform/MergeElemTContext.cxx new file mode 100644 index 000000000..e853240f9 --- /dev/null +++ b/xmloff/source/transform/MergeElemTContext.cxx @@ -0,0 +1,280 @@ +/* -*- 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 "MergeElemTContext.hxx" +#include "MutableAttrList.hxx" +#include "TransformerBase.hxx" +#include "TransformerActions.hxx" +#include "ElemTransformerAction.hxx" +#include "IgnoreTContext.hxx" +#include +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +namespace { + +class XMLParagraphTransformerContext : public XMLTransformerContext +{ +public: + XMLParagraphTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + // Create a children element context. By default, the import's + // CreateContext method is called to create a new default context. + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +} + +XMLParagraphTransformerContext::XMLParagraphTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ) +{ +} + +rtl::Reference XMLParagraphTransformerContext::CreateChildContext( + sal_uInt16 /*nPrefix*/, + const OUString& /*rLocalName*/, + const OUString& rQName, + const Reference< XAttributeList >& ) +{ + return new XMLIgnoreTransformerContext( GetTransformer(), + rQName, true ); +} + +namespace { + +class XMLPersTextContentRNGTransformTContext : public XMLPersTextContentTContext +{ +public: + XMLPersTextContentRNGTransformTContext( + XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ); + + virtual void Characters( const OUString& rChars ) override; +}; + +} + +XMLPersTextContentRNGTransformTContext::XMLPersTextContentRNGTransformTContext( + XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ) : + XMLPersTextContentTContext( + rTransformer, rQName, nPrefix, eToken ) +{} + +void XMLPersTextContentRNGTransformTContext::Characters( const OUString& rChars ) +{ + OUString aConvChars( rChars ); + XMLTransformerBase::ConvertRNGDateTimeToISO( aConvChars ); + XMLPersTextContentTContext::Characters( aConvChars ); +} + + +void XMLMergeElemTransformerContext::ExportStartElement() +{ + for( const auto& rChildContext : m_aChildContexts ) + { + XMLPersTextContentTContext *pContext = rChildContext.get(); + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) + ->AddAttribute( pContext->GetExportQName(), + pContext->GetTextContent() ); + } + XMLTransformerContext::StartElement( m_xAttrList ); + + m_bStartElementExported = true; +} + +XMLMergeElemTransformerContext::XMLMergeElemTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nActionMap ) : + XMLTransformerContext( rImp, rQName ), + m_nActionMap( nActionMap ), + m_bStartElementExported( false ) +{ +} + +void XMLMergeElemTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + rtl::Reference pMutableAttrList = + new XMLMutableAttributeList( rAttrList, true ); + m_xAttrList = pMutableAttrList; + + sal_Int16 nAttrCount = m_xAttrList.is() ? m_xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = m_xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + bool bRemove = true; + if( XML_NAMESPACE_OFFICE == nPrefix) + { + if (IsXMLToken( aLocalName, XML_DISPLAY ) ) + bRemove = false; + else if (IsXMLToken( aLocalName, XML_AUTHOR ) ) + bRemove = false; + else if (IsXMLToken( aLocalName, XML_CREATE_DATE ) ) + bRemove = false; + else if (IsXMLToken( aLocalName, XML_CREATE_DATE_STRING ) ) + bRemove = false; + } + if (bRemove) + { + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + } + } +} + +rtl::Reference XMLMergeElemTransformerContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& rAttrList ) +{ + rtl::Reference pContext; + + if( !m_bStartElementExported ) + { + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( m_nActionMap ); + OSL_ENSURE( pActions, "go no actions" ); + if( pActions ) + { + XMLTransformerActions::key_type aKey( nPrefix, rLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + + if( aIter != pActions->end() ) + { + switch( (*aIter).second.m_nActionType ) + { + case XML_ETACTION_MOVE_TO_ATTR_RNG2ISO_DATETIME: + { + rtl::Reference pTC( + new XMLPersTextContentRNGTransformTContext( + GetTransformer(), rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1() )); + m_aChildContexts.push_back(pTC); + pContext = pTC; + } + break; + case XML_ETACTION_MOVE_TO_ATTR: + { + rtl::Reference pTC( + new XMLPersTextContentTContext( + GetTransformer(), rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1() )); + m_aChildContexts.push_back(pTC); + pContext = pTC; + } + break; + case XML_ETACTION_EXTRACT_CHARACTERS: + { + if( !m_bStartElementExported ) + ExportStartElement(); + pContext.set( + new XMLParagraphTransformerContext( GetTransformer(), + rQName)); + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + } + else + { + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( m_nActionMap ); + OSL_ENSURE( pActions, "go no actions" ); + if( pActions ) + { + XMLTransformerActions::key_type aKey( nPrefix, rLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + + if( aIter != pActions->end() ) + { + switch( (*aIter).second.m_nActionType ) + { + case XML_ETACTION_EXTRACT_CHARACTERS: + { + if( !m_bStartElementExported ) + ExportStartElement(); + pContext.set( + new XMLParagraphTransformerContext( GetTransformer(), + rQName)); + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + } + + // default is copying + if( !pContext.is() ) + { + if( !m_bStartElementExported ) + ExportStartElement(); + pContext = XMLTransformerContext::CreateChildContext( nPrefix, + rLocalName, + rQName, + rAttrList ); + } + + return pContext; +} + +void XMLMergeElemTransformerContext::EndElement() +{ + if( !m_bStartElementExported ) + ExportStartElement(); + XMLTransformerContext::EndElement(); +} + +void XMLMergeElemTransformerContext::Characters( const OUString& ) +{ + // ignore +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/MergeElemTContext.hxx b/xmloff/source/transform/MergeElemTContext.hxx new file mode 100644 index 000000000..9e6cc6f97 --- /dev/null +++ b/xmloff/source/transform/MergeElemTContext.hxx @@ -0,0 +1,55 @@ +/* -*- 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 +#include "FlatTContext.hxx" +#include + +typedef ::std::vector< ::rtl::Reference< XMLPersTextContentTContext> > + XMLPersTextContentTContextVector; + +class XMLMergeElemTransformerContext : public XMLTransformerContext +{ + css::uno::Reference< css::xml::sax::XAttributeList > m_xAttrList; + XMLPersTextContentTContextVector m_aChildContexts; + sal_uInt16 const m_nActionMap; + bool m_bStartElementExported; + + void ExportStartElement(); + +public: + XMLMergeElemTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nActionMap ); + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void EndElement() override; + + virtual void Characters( const OUString& rChars ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/MetaTContext.cxx b/xmloff/source/transform/MetaTContext.cxx new file mode 100644 index 000000000..1e2ca46e5 --- /dev/null +++ b/xmloff/source/transform/MetaTContext.cxx @@ -0,0 +1,131 @@ +/* -*- 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 +#include +#include +#include +#include +#include + +#include "TransformerBase.hxx" +#include "MutableAttrList.hxx" +#include "MetaTContext.hxx" + +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +XMLTokenEnum const aMetaTokens[] = +{ + XML_GENERATOR, + XML_TITLE, + XML_DESCRIPTION, + XML_SUBJECT, + XML_INITIAL_CREATOR, + XML_CREATION_DATE, + XML_CREATOR, + XML_DATE, + XML_PRINTED_BY, + XML_PRINT_DATE, + XML_KEYWORD, + XML_LANGUAGE, + XML_EDITING_CYCLES, + XML_EDITING_DURATION, + XML_HYPERLINK_BEHAVIOUR, + XML_AUTO_RELOAD, + XML_TEMPLATE, + XML_USER_DEFINED, + XML_DOCUMENT_STATISTIC, + XML_TOKEN_END +}; + +XMLMetaTransformerContext::XMLMetaTransformerContext( XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ) +{ +} + +XMLMetaTransformerContext::~XMLMetaTransformerContext() +{ +} + +rtl::Reference XMLMetaTransformerContext::CreateChildContext( + sal_uInt16 /*nPrefix*/, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& ) +{ + rtl::Reference pContext( + new XMLPersTextContentTContext( GetTransformer(), rQName )); + XMLMetaContexts_Impl::value_type aVal( rLocalName, pContext ); + m_aContexts.insert( aVal ); + + return pContext; +} + +void XMLMetaTransformerContext::EndElement() +{ + // export everything in the correct order + OUString aKeywordsQName; + XMLTokenEnum const *pToken = aMetaTokens; + while( *pToken != XML_TOKEN_END ) + { + const OUString& rToken = GetXMLToken( *pToken ); + XMLMetaContexts_Impl::const_iterator aIter = + m_aContexts.find( rToken ); + if( aIter != m_aContexts.end() ) + { + if( XML_KEYWORD == *pToken ) + { + aKeywordsQName = + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_META, GetXMLToken(XML_KEYWORDS ) ); + + Reference< XAttributeList > xAttrList = + new XMLMutableAttributeList; + GetTransformer().GetDocHandler()->startElement( aKeywordsQName, + xAttrList ); + } + + // All elements may occur multiple times + XMLMetaContexts_Impl::const_iterator aEndIter = + m_aContexts.upper_bound( rToken ); + while( aIter != aEndIter ) + { + (*aIter).second->Export(); + ++aIter; + } + + if( XML_KEYWORD == *pToken ) + GetTransformer().GetDocHandler()->endElement( aKeywordsQName ); + } + pToken++; + } + + GetTransformer().GetDocHandler()->endElement( GetQName() ); +} + +void XMLMetaTransformerContext::Characters( const OUString& ) +{ + // ignore them +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/MetaTContext.hxx b/xmloff/source/transform/MetaTContext.hxx new file mode 100644 index 000000000..23b5dc29f --- /dev/null +++ b/xmloff/source/transform/MetaTContext.hxx @@ -0,0 +1,66 @@ +/* -*- 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 +#include + +#include "FlatTContext.hxx" + +typedef ::std::multimap< OUString, + ::rtl::Reference< XMLPersTextContentTContext > > XMLMetaContexts_Impl; + + +class XMLMetaTransformerContext : public XMLTransformerContext +{ + XMLMetaContexts_Impl m_aContexts; + +public: + // A contexts constructor does anything that is required if an element + // starts. Namespace processing has been done already. + // Note that virtual methods cannot be used inside constructors. Use + // StartElement instead if this is required. + XMLMetaTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + // A contexts destructor does anything that is required if an element + // ends. By default, nothing is done. + // Note that virtual methods cannot be used inside destructors. Use + // EndElement instead if this is required. + virtual ~XMLMetaTransformerContext() override; + + // Create a children element context. By default, the import's + // CreateContext method is called to create a new default context. + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + // EndElement is called before a context will be destructed, but + // after an elements context has been parsed. It may be used for actions + // that require virtual methods. The default is to do nothing. + virtual void EndElement() override; + + // This method is called for all characters that are contained in the + // current element. The default is to ignore them. + virtual void Characters( const OUString& rChars ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/MutableAttrList.cxx b/xmloff/source/transform/MutableAttrList.cxx new file mode 100644 index 000000000..f6fc026ae --- /dev/null +++ b/xmloff/source/transform/MutableAttrList.cxx @@ -0,0 +1,163 @@ +/* -*- 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 +#include +#include "MutableAttrList.hxx" + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; + +SvXMLAttributeList *XMLMutableAttributeList::GetMutableAttrList() +{ + if( !m_pMutableAttrList ) + { + m_pMutableAttrList = new SvXMLAttributeList( m_xAttrList ); + m_xAttrList = m_pMutableAttrList; + } + + return m_pMutableAttrList.get(); +} + +XMLMutableAttributeList::XMLMutableAttributeList() : + m_pMutableAttrList( new SvXMLAttributeList ) +{ + m_xAttrList = m_pMutableAttrList; +} + +XMLMutableAttributeList::XMLMutableAttributeList( const Reference< + XAttributeList> & rAttrList, bool bClone ) : + m_xAttrList( rAttrList.is() ? rAttrList : new SvXMLAttributeList ) +{ + if( bClone ) + GetMutableAttrList(); +} + + +XMLMutableAttributeList::~XMLMutableAttributeList() +{ + m_xAttrList = nullptr; +} + +const css::uno::Sequence& XMLMutableAttributeList::getUnoTunnelId() noexcept +{ + static const comphelper::UnoIdInit theXMLMutableAttributeListUnoTunnelId; + return theXMLMutableAttributeListUnoTunnelId.getSeq(); +} + +// XUnoTunnel +sal_Int64 SAL_CALL XMLMutableAttributeList::getSomething( + const Sequence< sal_Int8 >& rId ) +{ + return comphelper::getSomethingImpl(rId, this); +} + +sal_Int16 SAL_CALL XMLMutableAttributeList::getLength() +{ + return m_xAttrList->getLength(); +} + + +OUString SAL_CALL XMLMutableAttributeList::getNameByIndex(sal_Int16 i) +{ + return m_xAttrList->getNameByIndex( i ); +} + + +OUString SAL_CALL XMLMutableAttributeList::getTypeByIndex(sal_Int16 i) +{ + return m_xAttrList->getTypeByIndex( i ); +} + +OUString SAL_CALL XMLMutableAttributeList::getValueByIndex(sal_Int16 i) +{ + return m_xAttrList->getValueByIndex( i ); +} + +OUString SAL_CALL XMLMutableAttributeList::getTypeByName( + const OUString& rName ) +{ + return m_xAttrList->getTypeByName( rName ); +} + +OUString SAL_CALL XMLMutableAttributeList::getValueByName( + const OUString& rName) +{ + return m_xAttrList->getValueByName( rName ); +} + + +Reference< XCloneable > XMLMutableAttributeList::createClone() +{ + // A cloned list will be a read only list! + Reference< XCloneable > r = new SvXMLAttributeList( m_xAttrList ); + return r; +} + +void XMLMutableAttributeList::SetValueByIndex( sal_Int16 i, + const OUString& rValue ) +{ + GetMutableAttrList()->SetValueByIndex( i, rValue ); +} + +void XMLMutableAttributeList::AddAttribute( const OUString &rName , + const OUString &rValue ) +{ + GetMutableAttrList()->AddAttribute( rName, rValue ); +} + +void XMLMutableAttributeList::RemoveAttributeByIndex( sal_Int16 i ) +{ + GetMutableAttrList()->RemoveAttributeByIndex( i ); +} + +void XMLMutableAttributeList::RenameAttributeByIndex( sal_Int16 i, + const OUString& rNewName ) +{ + GetMutableAttrList()->RenameAttributeByIndex( i, rNewName ); +} + +void XMLMutableAttributeList::AppendAttributeList( + const Reference< css::xml::sax::XAttributeList >& r ) +{ + GetMutableAttrList()->AppendAttributeList( r ); +} + +sal_Int16 XMLMutableAttributeList::GetIndexByName( const OUString& rName ) const +{ + sal_Int16 nIndex = -1; + if( m_pMutableAttrList ) + { + nIndex = m_pMutableAttrList->GetIndexByName( rName ); + } + else + { + sal_Int16 nCount = m_xAttrList->getLength(); + for( sal_Int16 i=0; nIndex==-1 && igetNameByIndex(i) == rName ) + nIndex = i; + } + } + return nIndex; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/MutableAttrList.hxx b/xmloff/source/transform/MutableAttrList.hxx new file mode 100644 index 000000000..c025ffc5c --- /dev/null +++ b/xmloff/source/transform/MutableAttrList.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/. + * + * 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 +#include +#include + +#include +#include + +class SvXMLAttributeList; + +class XMLMutableAttributeList : public ::cppu::WeakImplHelper< + css::xml::sax::XAttributeList, + css::util::XCloneable, + css::lang::XUnoTunnel> +{ + css::uno::Reference< css::xml::sax::XAttributeList> m_xAttrList; + + rtl::Reference m_pMutableAttrList; + + SvXMLAttributeList *GetMutableAttrList(); + +public: + XMLMutableAttributeList(); + XMLMutableAttributeList( const css::uno::Reference< + css::xml::sax::XAttributeList> & rAttrList, + bool bClone=false ); + virtual ~XMLMutableAttributeList() override; + + // XUnoTunnel + static const css::uno::Sequence& getUnoTunnelId() noexcept; + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + + // css::xml::sax::XAttributeList + virtual sal_Int16 SAL_CALL getLength() override; + virtual OUString SAL_CALL getNameByIndex(sal_Int16 i) override; + virtual OUString SAL_CALL getTypeByIndex(sal_Int16 i) override; + virtual OUString SAL_CALL getTypeByName(const OUString& aName) override; + virtual OUString SAL_CALL getValueByIndex(sal_Int16 i) override; + virtual OUString SAL_CALL getValueByName(const OUString& aName) override; + + // css::util::XCloneable + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone() override; + + // methods that are not contained in any interface + void SetValueByIndex( sal_Int16 i, const OUString& rValue ); + void AddAttribute( const OUString &sName , const OUString &sValue ); +// void Clear(); + void RemoveAttributeByIndex( sal_Int16 i ); + void RenameAttributeByIndex( sal_Int16 i, const OUString& rNewName ); + void AppendAttributeList( const css::uno::Reference< css::xml::sax::XAttributeList > & ); + + sal_Int16 GetIndexByName( const OUString& rName ) const; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/NotesTContext.cxx b/xmloff/source/transform/NotesTContext.cxx new file mode 100644 index 000000000..9cd3b2e57 --- /dev/null +++ b/xmloff/source/transform/NotesTContext.cxx @@ -0,0 +1,217 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include + +#include "TransformerBase.hxx" +#include "TransformerActions.hxx" +#include "AttrTransformerAction.hxx" +#include "ActionMapTypesOASIS.hxx" +#include "MutableAttrList.hxx" +#include "RenameElemTContext.hxx" +#include "FlatTContext.hxx" + +#include "NotesTContext.hxx" + +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +XMLNotesTransformerContext::XMLNotesTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + XMLTokenEnum eToken, bool bPersistent ) : + XMLPersElemContentTContext( rImp, rQName ), + m_bEndNote( false ), + m_bPersistent( bPersistent ), + m_eTypeToken( eToken ) +{ +} + +XMLNotesTransformerContext::~XMLNotesTransformerContext() +{ +} + +void XMLNotesTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OASIS_NOTES_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_STYLE_FAMILY: + { + if( IsXMLToken( rAttrValue, XML_FOOTNOTE ) ) + { + } + else if( IsXMLToken( rAttrValue, XML_ENDNOTE ) ) + { + m_bEndNote = true; + } + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + } + break; + case XML_ATACTION_DECODE_STYLE_NAME: + case XML_ATACTION_DECODE_STYLE_NAME_REF: + { + OUString aAttrValue( rAttrValue ); + if( XMLTransformerBase::DecodeStyleName(aAttrValue) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + } + } + } + + XMLTokenEnum eToken = XML_FOOTNOTE; + switch( m_eTypeToken ) + { + case XML_NOTE: + eToken = (m_bEndNote ? XML_ENDNOTE : XML_FOOTNOTE); + break; + case XML_NOTES_CONFIGURATION: + eToken = (m_bEndNote ? XML_ENDNOTES_CONFIGURATION + : XML_FOOTNOTES_CONFIGURATION); + break; + case XML_NOTE_REF: + eToken = (m_bEndNote ? XML_ENDNOTE_REF : XML_FOOTNOTE_REF); + break; + default: + OSL_ENSURE( XML_NOTE==m_eTypeToken, "invalid note type" ); + break; + } + + SetExportQName( GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, + ::xmloff::token::GetXMLToken( eToken ) ) ); + if( m_bPersistent ) + XMLPersElemContentTContext::StartElement( xAttrList ); + else + GetTransformer().GetDocHandler()->startElement( GetExportQName(), + xAttrList ); +} + +void XMLNotesTransformerContext::EndElement() +{ + if( m_bPersistent ) + { + XMLPersElemContentTContext::EndElement(); + } + else + { + GetTransformer().GetDocHandler()->endElement( GetExportQName() ); + } +} + +rtl::Reference XMLNotesTransformerContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& rAttrList ) +{ + rtl::Reference pContext; + if( XML_NOTE == m_eTypeToken ) + { + if( XML_NAMESPACE_TEXT == nPrefix ) + { + XMLTokenEnum eToken ( XML_TOKEN_INVALID ); + if( IsXMLToken( rLocalName, XML_NOTE_CITATION ) ) + { + eToken = m_bEndNote ? XML_ENDNOTE_CITATION + : XML_FOOTNOTE_CITATION; + } + else if( IsXMLToken( rLocalName, XML_NOTE_BODY ) ) + { + eToken = m_bEndNote ? XML_ENDNOTE_BODY + : XML_FOOTNOTE_BODY; + } + + if( XML_TOKEN_INVALID != eToken ) + { + if( m_bPersistent ) + { + pContext.set(new XMLPersTextContentTContext( + GetTransformer(), rQName, + XML_NAMESPACE_TEXT, + eToken )); + AddContent( pContext ); + + } + else + { + pContext.set(new XMLRenameElemTransformerContext( + GetTransformer(), rQName, + XML_NAMESPACE_TEXT, + eToken )); + } + } + } + } + + if( !pContext.is() ) + { + pContext = m_bPersistent + ? XMLPersElemContentTContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ) + : XMLTransformerContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ); + } + + return pContext; +} + +bool XMLNotesTransformerContext::IsPersistent() const +{ + return m_bPersistent; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/NotesTContext.hxx b/xmloff/source/transform/NotesTContext.hxx new file mode 100644 index 000000000..b6bfbf880 --- /dev/null +++ b/xmloff/source/transform/NotesTContext.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/. + * + * 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 "DeepTContext.hxx" + +class XMLNotesTransformerContext : public XMLPersElemContentTContext +{ + bool m_bEndNote; + bool const m_bPersistent; + ::xmloff::token::XMLTokenEnum m_eTypeToken; + +public: + XMLNotesTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + ::xmloff::token::XMLTokenEnum m_eToken, + bool bPersistent ); + + virtual ~XMLNotesTransformerContext() override; + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + + virtual bool IsPersistent() const override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/OOo2Oasis.cxx b/xmloff/source/transform/OOo2Oasis.cxx new file mode 100644 index 000000000..12fe384a5 --- /dev/null +++ b/xmloff/source/transform/OOo2Oasis.cxx @@ -0,0 +1,2098 @@ +/* -*- 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "MutableAttrList.hxx" +#include "DeepTContext.hxx" +#include "StyleOOoTContext.hxx" +#include "FrameOOoTContext.hxx" +#include "EventOOoTContext.hxx" +#include "ControlOOoTContext.hxx" +#include "FormPropOOoTContext.hxx" +#include "ChartOOoTContext.hxx" +#include "ChartPlotAreaOOoTContext.hxx" +#include "ElemTransformerAction.hxx" +#include "AttrTransformerAction.hxx" +#include "PropertyActionsOOo.hxx" +#include "TransformerActions.hxx" +#include "OOo2Oasis.hxx" +#include +#include +#include + +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::beans; + +namespace { + +enum XMLUserDefinedTransformerAction +{ + XML_ETACTION_DOCUMENT=XML_ETACTION_USER_DEFINED, + XML_ETACTION_BODY, + XML_ETACTION_STYLE, + XML_ETACTION_STYLE_RENAME, + XML_ETACTION_FRAME, + XML_ETACTION_EVENT, + XML_ETACTION_TAB_STOP, + XML_ETACTION_FORM_CONTROL, + XML_ETACTION_FORM_PROPERTY, + XML_ETACTION_CHART, + XML_ETACTION_TRACKED_CHANGES, + XML_ETACTION_CHART_PLOT_AREA, + XML_ETACTION_DOCUMENT_RENAME, + XML_ETACTION_TABLE +}; + +} + +#define ENTRY3( n, l, a, p1, p2, p3 ) \ + { XML_NAMESPACE_##n, XML_##l, a, p1, p2, p3 } +#define ENTRY3QQN( n, l, a, n1, l1, n2, l2, p3 ) \ + ENTRY3( n, l, a, XMLTransformerActionInit::QNameParam( n1, l1 ), \ + XMLTransformerActionInit::QNameParam( n2, l2 ), p3 ) + +#define ENTRY2( n, l, a, p1, p2 ) \ + ENTRY3( n, l, a, p1, p2, 0 ) +#define ENTRY2QN( n, l, a, n1, l1, p2 ) \ + ENTRY2( n, l, a, XMLTransformerActionInit::QNameParam( n1, l1 ), p2 ) + +#define ENTRY1( n, l, a, p1 ) \ + ENTRY3( n, l, a, p1, 0, 0 ) +#define ENTRY1Q( n, l, a, n1, l1 ) \ + ENTRY1( n, l, a, XMLTransformerActionInit::QNameParam( n1, l1 ) ) + +#define ENTRY0( n, l, a ) \ + ENTRY3( n, l, a, 0, 0, 0 ) + +// BM: a macro to put two tokens into one sal_Int32 for the action +// XML_ATACTION_RENAME_ATTRIBUTE +static constexpr sal_Int32 RENAME_ENTRY( XMLTokenEnum f, XMLTokenEnum s ) +{ + return static_cast< sal_Int32 >(f) | (static_cast< sal_Int32 >(s) << 16); +} + +XMLTransformerActionInit const aActionTable[] = +{ + // remove office:class from and + ENTRY0( OFFICE, DOCUMENT, XML_ETACTION_DOCUMENT ), + ENTRY0( OFFICE, DOCUMENT_CONTENT, XML_ETACTION_DOCUMENT ), + ENTRY0( OFFICE, DOCUMENT_STYLES, XML_ETACTION_DOCUMENT ), + ENTRY0( OFFICE, DOCUMENT_SETTINGS, XML_ETACTION_DOCUMENT ), + ENTRY1Q( OFFICE, AUTO_TEXT_EVENTS, XML_ETACTION_DOCUMENT_RENAME, + XML_NAMESPACE_OOO, XML_AUTO_TEXT_EVENTS), + + // remove + ENTRY0( META, KEYWORDS, XML_ETACTION_COPY_CONTENT ), + + // rename to + ENTRY1Q( OFFICE, SCRIPT, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OFFICE, XML_SCRIPTS ), + + // rename to and process attributes + ENTRY2QN( OFFICE, SCRIPT_DATA, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_OFFICE, XML_SCRIPT, + OOO_SCRIPT_ACTIONS ), + + // rename to + ENTRY1Q( SCRIPT, LIBRARIES, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OOO, XML_LIBRARIES ), + + // rename to and process attributes + ENTRY2QN( SCRIPT, LIBRARY_LINKED, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_OOO, XML_LIBRARY_LINKED, + OOO_SCRIPT_ACTIONS ), + + // rename to and process attributes + ENTRY2QN( SCRIPT, LIBRARY_EMBEDDED, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_OOO, XML_LIBRARY_EMBEDDED, + OOO_SCRIPT_ACTIONS ), + + // rename to and process attributes + ENTRY2QN( SCRIPT, MODULE, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_OOO, XML_MODULE, + OOO_SCRIPT_ACTIONS ), + + // rename to + ENTRY1Q( SCRIPT, SOURCE_CODE, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OOO, XML_SOURCE_CODE ), + + // rename to , + // rename to , process attrs + ENTRY1Q( OFFICE, FONT_DECLS, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OFFICE, XML_FONT_FACE_DECLS ), + ENTRY2QN( STYLE, FONT_DECL, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_STYLE, XML_FONT_FACE, + OOO_FONT_DECL_ACTIONS ), + + // add genre element + ENTRY0( OFFICE, BODY, XML_ETACTION_BODY ), + + // rename to + ENTRY2QN( STYLE, PAGE_MASTER, XML_ETACTION_STYLE_RENAME, + XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT, + XML_FAMILY_TYPE_PAGE_LAYOUT ), + ENTRY1( STYLE, MASTER_PAGE, XML_ETACTION_PROC_ATTRS, + OOO_MASTER_PAGE_ACTIONS ), + + // split into and do other + // styles processing + ENTRY1( STYLE, STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_END ), + ENTRY1( STYLE, DEFAULT_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_END ), + ENTRY1( NUMBER, NUMBER_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, CURRENCY_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, PERCENTAGE_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, DATE_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, TIME_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, BOOLEAN_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, TEXT_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_DATA ), + ENTRY1( TEXT, LIST_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_LIST ), +// ENTRY0( TEXT, OUTLINE_STYLE, STYLE ), + ENTRY1( STYLE, HEADER_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_HEADER_FOOTER ), + ENTRY1( STYLE, FOOTER_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_HEADER_FOOTER ), + ENTRY1( TEXT, LIST_LEVEL_STYLE_NUMBER, XML_ETACTION_STYLE, XML_FAMILY_TYPE_LIST ), + ENTRY1( TEXT, LIST_LEVEL_STYLE_BULLET, XML_ETACTION_STYLE, XML_FAMILY_TYPE_LIST ), + ENTRY1( TEXT, LIST_LEVEL_STYLE_IMAGE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_LIST ), + ENTRY1( TEXT, OUTLINE_LEVEL_STYLE, XML_ETACTION_STYLE, XML_FAMILY_TYPE_LIST ), + ENTRY1( DRAW, GRADIENT, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_GRADIENT ), + ENTRY1( DRAW, FILL_IMAGE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_FILL_IMAGE ), + ENTRY2QN( DRAW, TRANSPARENCY, XML_ETACTION_STYLE_RENAME, + XML_NAMESPACE_DRAW, XML_OPACITY, + XML_FAMILY_TYPE_GRADIENT ), + ENTRY1( DRAW, MARKER, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_MARKER ), + ENTRY1( DRAW, HATCH, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_HATCH ), + ENTRY1( DRAW, STROKE_DASH, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_STROKE_DASH ), + + // rename 's text:level to text:outline-level + // process : process style-name attributes, + ENTRY1( TEXT, H, XML_ETACTION_PROC_ATTRS, OOO_PARA_ACTIONS ), + ENTRY1( TEXT, P, XML_ETACTION_PROC_ATTRS, OOO_PARA_ACTIONS ), + + // rename and to + ENTRY2QN( TEXT, UNORDERED_LIST, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_TEXT, XML_LIST, + OOO_STYLE_REF_ACTIONS ), + ENTRY2QN( TEXT, ORDERED_LIST, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_TEXT, XML_LIST, + OOO_STYLE_REF_ACTIONS ), + + // rename to + ENTRY3QQN( TEXT, FOOTNOTE, XML_ETACTION_RENAME_ELEM_ADD_ATTR, + XML_NAMESPACE_TEXT, XML_NOTE, + XML_NAMESPACE_TEXT, XML_NOTE_CLASS, XML_FOOTNOTE ), + ENTRY1Q( TEXT, FOOTNOTE_BODY, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TEXT, XML_NOTE_BODY ), + ENTRY1Q( TEXT, FOOTNOTE_CITATION, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TEXT, XML_NOTE_CITATION ), + ENTRY3QQN( TEXT, FOOTNOTES_CONFIGURATION, + XML_ETACTION_RENAME_ELEM_ADD_PROC_ATTR, + XML_NAMESPACE_TEXT, XML_NOTES_CONFIGURATION, + XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + XML_FOOTNOTE | (OOO_STYLE_REF_ACTIONS << 16) ), + + // rename to + ENTRY3QQN( TEXT, ENDNOTE, XML_ETACTION_RENAME_ELEM_ADD_ATTR, + XML_NAMESPACE_TEXT, XML_NOTE, + XML_NAMESPACE_TEXT, XML_NOTE_CLASS, XML_ENDNOTE ), + ENTRY1Q( TEXT, ENDNOTE_BODY, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TEXT, XML_NOTE_BODY ), + ENTRY1Q( TEXT, ENDNOTE_CITATION, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TEXT, XML_NOTE_CITATION ), + ENTRY3QQN( TEXT, ENDNOTES_CONFIGURATION, + XML_ETACTION_RENAME_ELEM_ADD_PROC_ATTR, + XML_NAMESPACE_TEXT, XML_NOTES_CONFIGURATION, + XML_NAMESPACE_TEXT, XML_NOTE_CLASS, + XML_ENDNOTE | (OOO_STYLE_REF_ACTIONS << 16) ), + + // rename and to + ENTRY3QQN( TEXT, ENDNOTE_REF, XML_ETACTION_RENAME_ELEM_ADD_ATTR, + XML_NAMESPACE_TEXT, XML_NOTE_REF, + XML_NAMESPACE_TEXT, XML_NOTE_CLASS, XML_ENDNOTE ), + ENTRY3QQN( TEXT, FOOTNOTE_REF, XML_ETACTION_RENAME_ELEM_ADD_ATTR, + XML_NAMESPACE_TEXT, XML_NOTE_REF, + XML_NAMESPACE_TEXT, XML_NOTE_CLASS, XML_FOOTNOTE ), + + // rename to + ENTRY1Q( TEXT, TAB_STOP, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TEXT, XML_TAB ), + + // replace with + ENTRY3QQN( TABLE, SUB_TABLE, XML_ETACTION_RENAME_ELEM_ADD_ATTR, + XML_NAMESPACE_TABLE, XML_TABLE, + XML_NAMESPACE_TABLE, XML_IS_SUB_TABLE, XML_TRUE ), + + // process *:style-name attributes + ENTRY1( TEXT, SECTION, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, SPAN, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, A, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, RUBY, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, RUBY_TEXT, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, DATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, TIME, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, VARIABLE_GET, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, USER_FIELD_GET, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, USER_FIELD_INPUT, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, CREATION_DATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, CREATION_TIME, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, PRINT_TIME, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, PRINT_DATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, EDITING_DURATION, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, MODIFICATION_TIME, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, MODIFICATION_DATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, DATABASE_DISPLAY, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, TABLE_FORMULA, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_TITLE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, TABLE_OF_CONTENT, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, TABLE_OF_CONTENT_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, ILLUSTRATION_INDEX, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, ILLUSTRATION_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, TABLE_INDEX, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, TABLE_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, OBJECT_INDEX, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, OBJECT_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, USER_INDEX, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, USER_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, ALPHABETICAL_INDEX, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, ALPHABETICAL_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, BIBLIOGRAPHY, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, BIBLIOGRAPHY_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_SOURCE_STYLE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_TITLE_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_CHAPTER, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY2QN( TEXT, INDEX_ENTRY_CHAPTER_NUMBER, + XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_TEXT, XML_INDEX_ENTRY_CHAPTER, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_TEXT, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_PAGE_NUMBER, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_SPAN, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_BIBLIOGRAPHY, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_LINK_START, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_LINK_END, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( STYLE, HANDOUT_MASTER, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( DRAW, PAGE, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( STYLE, MAP, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( PRESENTATION, NOTES, XML_ETACTION_PROC_ATTRS, + OOO_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( STYLE, PRESENTATION_PAGE_LAYOUT, XML_ETACTION_PROC_ATTRS, + OOO_MASTER_PAGE_ACTIONS ), + /* Consider also attribute table:style-name for , + and . (#i40011#, #i40015#) + */ + ENTRY0( TABLE, TABLE, XML_ETACTION_TABLE ), + ENTRY1( TABLE, TABLE_ROW, XML_ETACTION_PROC_ATTRS, OOO_STYLE_REF_ACTIONS ), + ENTRY1( TABLE, TABLE_COLUMN, XML_ETACTION_PROC_ATTRS, OOO_STYLE_REF_ACTIONS ), + + // split frame elements + ENTRY0( DRAW, TEXT_BOX, XML_ETACTION_FRAME ), + ENTRY0( DRAW, IMAGE, XML_ETACTION_FRAME ), + ENTRY0( DRAW, OBJECT, XML_ETACTION_FRAME ), + ENTRY0( DRAW, OBJECT_OLE, XML_ETACTION_FRAME ), + ENTRY0( DRAW, APPLET, XML_ETACTION_FRAME ), + ENTRY0( DRAW, PLUGIN, XML_ETACTION_FRAME ), + ENTRY0( DRAW, FLOATING_FRAME, XML_ETACTION_FRAME ), + ENTRY0( SVG, DESC, XML_ETACTION_COPY_TEXT ), + + // process events + ENTRY1Q( OFFICE, EVENTS, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS ), + ENTRY0( SCRIPT, EVENT, XML_ETACTION_EVENT ), + ENTRY0( PRESENTATION, EVENT, XML_ETACTION_EVENT ), + + // process length attributes + ENTRY1( DRAW, RECT, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, LINE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, POLYLINE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, POLYGON, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, PATH, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, CIRCLE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, ELLIPSE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, CONNECTOR, XML_ETACTION_PROC_ATTRS, OOO_CONNECTOR_ACTIONS ), + ENTRY1( DRAW, CAPTION, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, CONTROL, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, PAGE_THUMBNAIL, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, MEASURE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, G, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), +// ENTRY1( DRAW, TEXT_BOX, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( PRESENTATION, PLACEHOLDER, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, CONTOUR_POLYGON, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, CONTOUR_PATH, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, AREA_RECTANGLE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, AREA_CIRCLE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DRAW, AREA_POLYGON, XML_ETACTION_PROC_ATTRS, OOO_DRAW_AREA_POLYGON_ACTIONS ), + ENTRY1( DRAW, GLUE_POINT, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DR3D, SCENE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DR3D, CUBE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DR3D, SPHERE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DR3D, EXTRUDE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( DR3D, ROTATE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, TITLE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, SUBTITLE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, FOOTER, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, LEGEND, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, WALL, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, FLOOR, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, AXIS, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, GRID, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, SERIES, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, DATA_POINT, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, MEAN_VALUE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, ERROR_INDICATOR, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, REGRESSION_CURVE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, STOCK_GAIN_MARKER, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, STOCK_LOSS_MARKER, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + ENTRY1( CHART, STOCK_RANGE_LINE, XML_ETACTION_PROC_ATTRS, OOO_SHAPE_ACTIONS ), + + ENTRY0( CHART, CHART, XML_ETACTION_CHART ), + ENTRY0( CHART, PLOT_AREA, XML_ETACTION_CHART_PLOT_AREA ), + + ENTRY1Q( TEXT, TRACKED_CHANGES, XML_ETACTION_TRACKED_CHANGES, + XML_NAMESPACE_TEXT, XML_PROTECTION_KEY ), + ENTRY1Q( TABLE, TRACKED_CHANGES, XML_ETACTION_TRACKED_CHANGES, + XML_NAMESPACE_TABLE, XML_PROTECTION_KEY ), + + ENTRY1( TEXT, INDEX_ENTRY_TAB_STOP, XML_ETACTION_PROC_ATTRS, + OOO_INDEX_ENTRY_TAB_STOP_ACTIONS ), + ENTRY0( STYLE, TAB_STOP, XML_ETACTION_TAB_STOP ), + ENTRY1( STYLE, BACKGROUND_IMAGE, XML_ETACTION_PROC_ATTRS, + OOO_BACKGROUND_IMAGE_ACTIONS ), + ENTRY1( TEXT, LINENUMBERING_CONFIGURATION, XML_ETACTION_PROC_ATTRS, + OOO_LINENUMBERING_ACTIONS ), + ENTRY1( STYLE, FOOTNOTE_SEP, XML_ETACTION_PROC_ATTRS, + OOO_FOOTNOTE_SEP_ACTIONS ), + ENTRY1( STYLE, DROP_CAP, XML_ETACTION_PROC_ATTRS, OOO_DROP_CAP_ACTIONS ), + ENTRY1( STYLE, COLUMNS, XML_ETACTION_PROC_ATTRS, OOO_COLUMNS_ACTIONS ), + ENTRY1( STYLE, COLUMN, XML_ETACTION_PROC_ATTRS, OOO_COLUMNS_ACTIONS ), + + // rename office:value-* to *:value-* + ENTRY1( TEXT, VARIABLE_DECL, XML_ETACTION_PROC_ATTRS, + OOO_TEXT_VALUE_TYPE_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, VARIABLE_SET, XML_ETACTION_PROC_ATTRS, + OOO_TEXT_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TEXT, VARIABLE_INPUT, XML_ETACTION_PROC_ATTRS, + OOO_TEXT_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TEXT, USER_FIELD_DECL, XML_ETACTION_PROC_ATTRS, + OOO_TEXT_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TEXT, EXPRESSION, XML_ETACTION_PROC_ATTRS, + OOO_TEXT_VALUE_TYPE_ACTIONS), /* generated entry */ +// ENTRY1( TEXT, USER_DEFINED, XML_ETACTION_PROC_ATTRS, +// OOO_TEXT_VALUE_TYPE_ACTIONS), /* text:user-defined has no attrs so far */ + ENTRY1( TABLE, TABLE_CELL, XML_ETACTION_PROC_ATTRS, + OOO_TABLE_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TABLE, COVERED_TABLE_CELL, XML_ETACTION_PROC_ATTRS, + OOO_TABLE_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TABLE, CHANGE_TRACK_TABLE_CELL, XML_ETACTION_PROC_ATTRS, + OOO_TABLE_VALUE_TYPE_ACTIONS), /* generated entry */ +// ENTRY1( FORM, PROPERTY, XML_ETACTION_PROC_ATTRS, +// OOO_VALUE_TYPE_ACTIONS), /* TODO: generated entry */ +// ENTRY1( FORM, LIST_PROPERTY, XML_ETACTION_PROC_ATTRS, +// OOO_VALUE_TYPE_ACTIONS), /* generated entry */ + + ENTRY1( OFFICE, ANNOTATION, XML_ETACTION_MOVE_ATTRS_TO_ELEMS, + OOO_ANNOTATION_ACTIONS ), /* generated entry */ + ENTRY1( OFFICE, CHANGE_INFO, XML_ETACTION_MOVE_ATTRS_TO_ELEMS, + OOO_CHANGE_INFO_ACTIONS ), /* generated entry */ + + ENTRY1( TEXT, DDE_CONNECTION_DECL, XML_ETACTION_PROC_ATTRS, + OOO_DDE_CONNECTION_DECL_ACTIONS ), + + ENTRY0( FORM, CONTROL, XML_ETACTION_FORM_CONTROL ), + ENTRY1( FORM, COLUMN, XML_ETACTION_PROC_ATTRS, + OOO_FORM_COLUMN_ACTIONS ), + ENTRY0( FORM, PROPERTY, XML_ETACTION_FORM_PROPERTY ), + + // process xlink:href + ENTRY1( META, TEMPLATE, XML_ETACTION_PROC_ATTRS, + OOO_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( META, AUTO_RELOAD, XML_ETACTION_PROC_ATTRS, + OOO_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, SECTION_SOURCE, XML_ETACTION_PROC_ATTRS, + OOO_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, SCRIPT, XML_ETACTION_PROC_ATTRS, + OOO_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, ALPHABETICAL_INDEX_AUTO_MARK_FILE, XML_ETACTION_PROC_ATTRS, + OOO_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TABLE, TABLE_SOURCE, XML_ETACTION_PROC_ATTRS, + OOO_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TABLE, CELL_RANGE_SOURCE, XML_ETACTION_PROC_ATTRS, + OOO_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( DRAW, A, XML_ETACTION_PROC_ATTRS, + OOO_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( PRESENTATION, SOUND, XML_ETACTION_PROC_ATTRS, + OOO_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( FORM, FORM, XML_ETACTION_PROC_ATTRS, + OOO_FORM_CONTROL_ACTIONS ), + ENTRY2QN( STYLE, SYMBOL_IMAGE, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_CHART, XML_SYMBOL_IMAGE, + OOO_BACKGROUND_IMAGE_ACTIONS ), + + ENTRY2QN( CONFIG, CONFIG_ITEM_SET, XML_ETACTION_PROC_ATTRS_COND, + XML_NAMESPACE_OFFICE, XML_SETTINGS, + OOO_CONFIG_ITEM_SET_ACTIONS ), + + // add namespace prefix + // text:formula + ENTRY1( TEXT, SEQUENCE, XML_ETACTION_PROC_ATTRS, + OOO_FORMULA_ACTIONS ), /* generated entry */ + // text:condition + ENTRY1( TEXT, DATABASE_NEXT, XML_ETACTION_PROC_ATTRS, + OOO_FORMULA_ACTIONS ), /* generated entry */ + // text:condition + ENTRY2QN( TEXT, DATABASE_SELECT, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_TEXT, XML_DATABASE_ROW_SELECT, + OOO_FORMULA_ACTIONS ), + // text:condition + ENTRY1( TEXT, CONDITIONAL_TEXT, XML_ETACTION_PROC_ATTRS, + OOO_FORMULA_ACTIONS ), /* generated entry */ + // text:condition + ENTRY1( TEXT, HIDDEN_TEXT, XML_ETACTION_PROC_ATTRS, + OOO_FORMULA_ACTIONS ), /* generated entry */ + // text:condition + ENTRY1( TEXT, HIDDEN_PARAGRAPH, XML_ETACTION_PROC_ATTRS, + OOO_FORMULA_ACTIONS ), /* generated entry */ + // table:condition + ENTRY1( TABLE, CONTENT_VALIDATION, XML_ETACTION_PROC_ATTRS, + OOO_FORMULA_ACTIONS ), /* generated entry */ + + // rename to + ENTRY1Q( TABLE, DEPENDENCES, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TABLE, XML_DEPENDENCIES ), + ENTRY1Q( TABLE, DEPENDENCE, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TABLE, XML_DEPENDENCY ), + + // process table::error-macro + ENTRY1( TABLE, ERROR_MACRO, XML_ETACTION_PROC_ATTRS, + OOO_ERROR_MACRO_ACTIONS ), + + // process table::conversion-mode + ENTRY1( TABLE, CONVERSION_MODE, XML_ETACTION_PROC_ATTRS, + OOO_DDE_CONV_MODE_ACTIONS ), + + // fix + ENTRY1( TEXT, ALPHABETICAL_INDEX_MARK, XML_ETACTION_PROC_ATTRS, + OOO_ALPHABETICAL_INDEX_MARK_ACTIONS ), + ENTRY1( TEXT, ALPHABETICAL_INDEX_MARK_START, XML_ETACTION_PROC_ATTRS, + OOO_ALPHABETICAL_INDEX_MARK_ACTIONS ), + + // process table::data-pilot-member + ENTRY1( TABLE, DATA_PILOT_MEMBER, XML_ETACTION_PROC_ATTRS, + OOO_DATAPILOT_MEMBER_ACTIONS ), + + // process table::data-pilot-level + ENTRY1( TABLE, DATA_PILOT_LEVEL, XML_ETACTION_PROC_ATTRS, + OOO_DATAPILOT_LEVEL_ACTIONS ), + + // process table::source-service + ENTRY1( TABLE, SOURCE_SERVICE, XML_ETACTION_PROC_ATTRS, + OOO_SOURCE_SERVICE_ACTIONS ), + + // fix id strings in old animation elements + ENTRY1( PRESENTATION, DIM, XML_ETACTION_PROC_ATTRS, OOO_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, PLAY, XML_ETACTION_PROC_ATTRS, OOO_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, SHOW_TEXT, XML_ETACTION_PROC_ATTRS, OOO_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, SHOW_SHAPE, XML_ETACTION_PROC_ATTRS, OOO_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, HIDE_TEXT, XML_ETACTION_PROC_ATTRS, OOO_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, HIDE_SHAPE, XML_ETACTION_PROC_ATTRS, OOO_ANIMATION_ACTIONS ), + + ENTRY0( OFFICE, TOKEN_INVALID, XML_ETACTION_EOT ) +}; + +// XML_ETACTION_STYLE +XMLTransformerActionInit const aStyleActionTable[] = +{ + ENTRY0( STYLE, FAMILY, XML_ATACTION_STYLE_FAMILY ), + ENTRY0( STYLE, NAME, XML_ATACTION_ENCODE_STYLE_NAME ), + ENTRY0( STYLE, PARENT_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( STYLE, NEXT_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( STYLE, LIST_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( STYLE, MASTER_PAGE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( STYLE, DATA_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( DRAW, NAME, XML_ATACTION_ENCODE_STYLE_NAME ), + ENTRY0( DRAW, DISTANCE, XML_ATACTION_INCH2IN ), + ENTRY0( DRAW, DOTS1_LENGTH, XML_ATACTION_INCH2IN ), + ENTRY0( DRAW, DOTS2_LENGTH, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, WIDTH, XML_ATACTION_SVG_WIDTH_HEIGHT_OOO ), + ENTRY0( SVG, HEIGHT, XML_ATACTION_SVG_WIDTH_HEIGHT_OOO ), + ENTRY0( DRAW, START, XML_ATACTION_NEG_PERCENT ), + ENTRY0( DRAW, END, XML_ATACTION_NEG_PERCENT ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OOO, sal_uInt32(true) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_FRAME_ELEM_ACTIONS +XMLTransformerActionInit const aFrameElemActionTable[] = +{ + ENTRY1Q( OFFICE, EVENTS, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS ), + ENTRY0( DRAW, GLUE_POINT, XML_ETACTION_COPY ), + ENTRY0( DRAW, IMAGE_MAP, XML_ETACTION_COPY ), + ENTRY0( SVG, DESC, XML_ETACTION_COPY_TEXT ), + ENTRY0( DRAW, CONTOUR_POLYGON, XML_ETACTION_COPY ), + ENTRY0( DRAW, CONTOUR_PATH, XML_ETACTION_COPY ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ETACTION_EOT ) +}; + +// OOO_FRAME_ATTR_ACTIONS +XMLTransformerActionInit const aFrameAttrActionTable[] = +{ + ENTRY0( DRAW, ZINDEX, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( DRAW, ID, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( DRAW, LAYER, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( DRAW, STYLE_NAME, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( PRESENTATION, STYLE_NAME, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( DRAW, TRANSFORM, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( DRAW, NAME, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( TABLE, END_CELL_ADDRESS, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( TABLE, END_X, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( TABLE, END_Y, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( TABLE, TABLE_BACKGROUND, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( TEXT, ANCHOR_TYPE, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( TEXT, ANCHOR_PAGE_NUMBER, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( DRAW, TEXT_STYLE_NAME, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( SVG, X, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( SVG, Y, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( SVG, WIDTH, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( SVG, HEIGHT, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( STYLE, REL_WIDTH, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( STYLE, REL_HEIGHT, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( PRESENTATION, CLASS, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( PRESENTATION, PLACEHOLDER, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( PRESENTATION, USER_TRANSFORMED, XML_ATACTION_MOVE_TO_ELEM ), /* generated entry */ + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_EVENT_ELEM_ACTIONS +XMLTransformerActionInit const aEventActionTable[] = +{ + ENTRY0( XLINK, HREF, XML_ATACTION_HREF ), + ENTRY1( SCRIPT, LANGUAGE, XML_ATACTION_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_OOO ), + ENTRY0( SCRIPT, EVENT_NAME, XML_ATACTION_EVENT_NAME ), + ENTRY0( SCRIPT, MACRO_NAME, XML_ATACTION_MACRO_NAME ), + ENTRY0( SCRIPT, LOCATION, XML_ATACTION_MACRO_LOCATION ), + ENTRY0( SCRIPT, LIBRARY, XML_ATACTION_MACRO_LOCATION ), // bug in draw + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OOO_MASTER_PAGE_ACTIONS +XMLTransformerActionInit const aMasterPageActionTable[] = +{ + ENTRY0( STYLE, NAME, XML_ATACTION_ENCODE_STYLE_NAME ), + ENTRY0( STYLE, NEXT_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY1Q( STYLE, PAGE_MASTER_NAME, XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF, + XML_NAMESPACE_STYLE, XML_PAGE_LAYOUT_NAME ), + ENTRY0( DRAW, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +XMLTransformerActionInit const aFontDeclActionTable[] = +{ + ENTRY1Q( FO, FONT_FAMILY, XML_ATACTION_RENAME, + XML_NAMESPACE_SVG, XML_FONT_FAMILY ), + ENTRY1Q( STYLE, FONT_STYLE_NAME, XML_ATACTION_RENAME, + XML_NAMESPACE_STYLE, XML_FONT_ADORNMENTS ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OOO_PARA_ACTIONS +XMLTransformerActionInit const aParaActionTable[] = +{ + ENTRY0( TEXT, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( TEXT, COND_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), +// ENTRY0( TEXT, CLASS_NAMES, XML_ATACTION_REMOVE ), + ENTRY1Q( TEXT, LEVEL, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_OUTLINE_LEVEL ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OOO_STYLE_REF_ACTIONS +XMLTransformerActionInit const aStyleRefActionTable[] = +{ + ENTRY0( TEXT, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( TEXT, VISITED_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( TEXT, MAIN_ENTRY_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( TEXT, CITATION_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( TEXT, CITATION_BODY_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( TEXT, DEFAULT_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( TEXT, MASTER_PAGE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( STYLE, DATA_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( STYLE, APPLY_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( STYLE, PAGE_LAYOUT_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( TABLE, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( TABLE, DEFAULT_CELL_STYLE_NAME, + XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( DRAW, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( DRAW, MASTER_PAGE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( PRESENTATION, PRESENTATION_PAGE_LAYOUT_NAME, + XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OOO, sal_uInt32(false) ), + ENTRY1( TEXT, CONDITION, XML_ATACTION_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_OOOW ), + ENTRY1( TEXT, FORMULA, XML_ATACTION_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_OOOW ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_SHAPE_ACTIONS +// !!ATTENTION!! If you change something here, please also change +// aConnectorActionTable if appropriate +XMLTransformerActionInit const aShapeActionTable[] = +{ + ENTRY0( SVG, X, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, Y, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, X1, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, Y1, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, X2, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, Y2, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, CX, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, CY, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, R, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, RX, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, RY, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, WIDTH, XML_ATACTION_SVG_WIDTH_HEIGHT_OOO ), + ENTRY0( SVG, HEIGHT, XML_ATACTION_SVG_WIDTH_HEIGHT_OOO ), + ENTRY0( FO, MIN_WIDTH, XML_ATACTION_INCH2IN ), + ENTRY0( FO, MIN_HEIGHT, XML_ATACTION_INCH2IN ), + ENTRY0( FO, MAX_WIDTH, XML_ATACTION_INCH2IN ), + ENTRY0( FO, MAX_HEIGHT, XML_ATACTION_INCH2IN ), + ENTRY0( DRAW, CORNER_RADIUS, XML_ATACTION_INCH2IN ), + ENTRY0( DRAW, LINE_SKEW, XML_ATACTION_INCHS2INS ), + ENTRY0( DRAW, CAPTION_POINT_X, XML_ATACTION_INCH2IN ), + ENTRY0( DRAW, CAPTION_POINT_Y, XML_ATACTION_INCH2IN ), + ENTRY0( DRAW, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( DRAW, TEXT_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( DRAW, END_X, XML_ATACTION_INCH2IN ), + ENTRY0( DRAW, END_Y, XML_ATACTION_INCH2IN ), + ENTRY0( PRESENTATION, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( DR3D, DISTANCE, XML_ATACTION_INCH2IN ), + ENTRY0( DR3D, FOCAL_LENGTH, XML_ATACTION_INCH2IN ), + ENTRY1Q( FORM, ID, XML_ATACTION_RENAME, + XML_NAMESPACE_DRAW, XML_CONTROL ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OOO, sal_uInt32(true) ), + + // BM: needed by chart:legend. The legend needs also the draw actions. As + // there is no merge mechanism, all actions have to be in the same table + ENTRY2( CHART, LEGEND_POSITION, XML_ATACTION_RENAME_ATTRIBUTE, + RENAME_ENTRY( XML_LEFT, XML_START ), + RENAME_ENTRY( XML_RIGHT, XML_END )), + ENTRY0( DRAW, ID, XML_ATACTION_SHAPEID ), + ENTRY0( DRAW, START_SHAPE, XML_ATACTION_SHAPEID ), + ENTRY0( DRAW, END_SHAPE, XML_ATACTION_SHAPEID ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +XMLTransformerActionInit const aConnectorActionTable[] = +{ + ENTRY0( SVG, X1, XML_ATACTION_TWIPS2IN ), + ENTRY0( SVG, Y1, XML_ATACTION_TWIPS2IN ), + ENTRY0( SVG, X2, XML_ATACTION_TWIPS2IN ), + ENTRY0( SVG, Y2, XML_ATACTION_TWIPS2IN ), + ENTRY0( SVG, WIDTH, XML_ATACTION_SVG_WIDTH_HEIGHT_OOO ), + ENTRY0( SVG, HEIGHT, XML_ATACTION_SVG_WIDTH_HEIGHT_OOO ), + ENTRY0( FO, MIN_WIDTH, XML_ATACTION_INCH2IN ), + ENTRY0( FO, MIN_HEIGHT, XML_ATACTION_INCH2IN ), + ENTRY0( FO, MAX_WIDTH, XML_ATACTION_INCH2IN ), + ENTRY0( FO, MAX_HEIGHT, XML_ATACTION_INCH2IN ), + ENTRY0( DRAW, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( DRAW, TEXT_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( DRAW, END_X, XML_ATACTION_INCH2IN ), + ENTRY0( DRAW, END_Y, XML_ATACTION_INCH2IN ), + ENTRY0( PRESENTATION, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY1Q( FORM, ID, XML_ATACTION_RENAME, + XML_NAMESPACE_DRAW, XML_CONTROL ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OOO, sal_uInt32(true) ), + ENTRY0( DRAW, ID, XML_ATACTION_SHAPEID ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_INDEX_ENTRY_TAB_STOP_ACTIONS +XMLTransformerActionInit const aIndexEntryTabStopActionTable[] = +{ + ENTRY0( STYLE, POSITION, XML_ATACTION_INCH2IN ), + ENTRY0( TEXT, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_TAB_STOP_ACTIONS +XMLTransformerActionInit const aTabStopActionTable[] = +{ + ENTRY0( STYLE, POSITION, XML_ATACTION_INCH2IN ), + ENTRY1Q( STYLE, LEADER_CHAR, XML_ATACTION_RENAME, + XML_NAMESPACE_STYLE, XML_LEADER_TEXT ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_LINENUMBERING_ACTIONS +XMLTransformerActionInit const aLineNumberingActionTable[] = +{ + ENTRY0( TEXT, OFFSET, XML_ATACTION_INCH2IN ), + ENTRY0( TEXT, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY1Q( TEXT, COUNT_IN_FLOATING_FRAMES, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_COUNT_IN_TEXT_BOXES ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +XMLTransformerActionInit const aFootnoteSepActionTable[] = +{ + ENTRY0( STYLE, WIDTH, XML_ATACTION_INCH2IN ), + ENTRY0( STYLE, DISTANCE_BEFORE_SEP, XML_ATACTION_INCH2IN ), + ENTRY0( STYLE, DISTANCE_AFTER_SEP, XML_ATACTION_INCH2IN ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_DROP_CAP_ACTIONS +XMLTransformerActionInit const aDropCapActionTable[] = +{ + ENTRY0( STYLE, DISTANCE, XML_ATACTION_INCH2IN ), + ENTRY0( STYLE, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +XMLTransformerActionInit const aColumnsActionTable[] = +{ + ENTRY0( STYLE, COLUMN_GAP, XML_ATACTION_INCH2IN ), +// ENTRY0( STYLE, SPACE_BEFORE, XML_ATACTION_INCH2IN ), +// ENTRY0( STYLE, SPACE_AFTER, XML_ATACTION_INCH2IN ), + ENTRY1Q( FO, MARGIN_LEFT, XML_ATACTION_RENAME_INCH2IN, + XML_NAMESPACE_FO, XML_START_INDENT ), + ENTRY1Q( FO, MARGIN_RIGHT, XML_ATACTION_RENAME_INCH2IN, + XML_NAMESPACE_FO, XML_END_INDENT ), + ENTRY0( STYLE, WIDTH, XML_ATACTION_INCH2IN ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_TEXT_VALUE_TYPE_ACTIONS +XMLTransformerActionInit const aTextValueTypeActionTable[] = +{ + ENTRY1Q( TEXT, VALUE_TYPE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_VALUE_TYPE ), + ENTRY1Q( TEXT, VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_VALUE ), + ENTRY1Q( TEXT, CURRENCY, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_CURRENCY ), + ENTRY1Q( TEXT, DATE_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_DATE_VALUE ), + ENTRY1Q( TEXT, TIME_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_TIME_VALUE ), + ENTRY1Q( TEXT, BOOLEAN_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE ), + ENTRY1Q( TEXT, STRING_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_STRING_VALUE ), + ENTRY0( STYLE, DATA_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY1( TEXT, FORMULA, XML_ATACTION_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_OOOW ), + ENTRY0( TEXT, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_TABLE_VALUE_TYPE_ACTIONS +XMLTransformerActionInit const aTableValueTypeActionTable[] = +{ + ENTRY1Q( TABLE, VALUE_TYPE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_VALUE_TYPE ), + ENTRY1Q( TABLE, VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_VALUE ), + ENTRY1Q( TABLE, CURRENCY, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_CURRENCY ), + ENTRY1Q( TABLE, DATE_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_DATE_VALUE ), + ENTRY1Q( TABLE, TIME_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_TIME_VALUE ), + ENTRY1Q( TABLE, BOOLEAN_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE ), + ENTRY1Q( TABLE, STRING_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_STRING_VALUE ), + ENTRY0( TABLE, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY1( TABLE, FORMULA, XML_ATACTION_ADD_APP_NAMESPACE_PREFIX, + XML_NAMESPACE_OOOW ), + ENTRY1Q( TABLE, VALIDATION_NAME, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_CONTENT_VALIDATION_NAME ), + ENTRY0( TABLE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OOO_ANNOTATION_ACTIONS +XMLTransformerActionInit const aAnnotationActionTable[] = +{ + ENTRY1Q( OFFICE, AUTHOR, XML_ATACTION_MOVE_TO_ELEM, + XML_NAMESPACE_DC, XML_CREATOR ), + ENTRY1Q( OFFICE, CREATE_DATE, XML_ATACTION_MOVE_TO_ELEM, + XML_NAMESPACE_DC, XML_DATE ), + ENTRY1Q( OFFICE, CREATE_DATE_STRING, XML_ATACTION_MOVE_TO_ELEM, + XML_NAMESPACE_META, XML_DATE_STRING ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OOO_CHANGE_INFO_ACTIONS +XMLTransformerActionInit const aChangeInfoActionTable[] = +{ + ENTRY1Q( OFFICE, CHG_AUTHOR, XML_ATACTION_MOVE_TO_ELEM, + XML_NAMESPACE_DC, XML_CREATOR ), + ENTRY1Q( OFFICE, CHG_DATE_TIME, XML_ATACTION_MOVE_TO_ELEM, + XML_NAMESPACE_DC, XML_DATE ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_BACKGROUND_IMAGE_ACTIONS +XMLTransformerActionInit const aBackgroundImageActionTable[] = +{ + ENTRY1Q( DRAW, TRANSPARENCY, XML_ATACTION_RENAME_NEG_PERCENT, + XML_NAMESPACE_DRAW, XML_OPACITY ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OOO, sal_uInt32(true) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +/* OOO_BACKGROUND_IMAGE_ACTIONS for OpenOffice.org text documents + OpenOffice.org text documents, written by OpenOffice.org, contain + wrong value for the transparency of the background graphic (#i50322#) +*/ +XMLTransformerActionInit const aWriterBackgroundImageActionTable[] = +{ + ENTRY1Q( DRAW, TRANSPARENCY, XML_ATACTION_WRITER_BACK_GRAPHIC_TRANSPARENCY, XML_NAMESPACE_DRAW, XML_OPACITY ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OOO, sal_uInt32(true) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_DDE_CONNECTION_DECL +XMLTransformerActionInit const aDDEConnectionDeclActionTable[] = +{ + ENTRY1Q( TEXT, NAME, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_NAME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_FORM_CONTROL_ACTIONS +XMLTransformerActionInit const aFormControlActionTable[] = +{ + ENTRY2QN( FORM, SERVICE_NAME, + XML_ATACTION_RENAME_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_FORM, XML_CONTROL_IMPLEMENTATION, + XML_NAMESPACE_OOO ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OOO, sal_uInt32(false) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_FORM_COLUMN_ACTIONS +XMLTransformerActionInit const aFormColumnActionTable[] = +{ + ENTRY1Q( FORM, COLUMN_STYLE_NAME, XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF, + XML_NAMESPACE_FORM, XML_TEXT_STYLE_NAME ), + ENTRY2QN( FORM, SERVICE_NAME, + XML_ATACTION_RENAME_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_FORM, XML_CONTROL_IMPLEMENTATION, + XML_NAMESPACE_OOO ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_FORM_PROP_ACTIONS +XMLTransformerActionInit const aFormPropActionTable[] = +{ + ENTRY1Q( FORM, PROPERTY_TYPE, XML_ATACTION_RENAME, + XML_NAMESPACE_OFFICE, XML_VALUE_TYPE ), + ENTRY0( FORM, PROPERTY_IS_LIST, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_XLINK_ACTIONS +XMLTransformerActionInit const aXLinkActionTable[] = +{ + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OOO, sal_uInt32(false) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_CONFIG_ITEM_SET_ACTIONS +XMLTransformerActionInit const aConfigItemSetActionTable[] = +{ + ENTRY1( CONFIG, NAME, XML_ATACTION_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_OOO ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_FORMULA_ACTIONS +XMLTransformerActionInit const aFormulaActionTable[] = +{ + ENTRY1( TEXT, CONDITION, XML_ATACTION_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_OOOW ), + ENTRY1( TEXT, FORMULA, XML_ATACTION_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_OOOW ), + ENTRY1( TABLE, CONDITION, XML_ATACTION_ADD_APP_NAMESPACE_PREFIX, + XML_NAMESPACE_OOOW ), + ENTRY1( TABLE, FORMULA, XML_ATACTION_ADD_APP_NAMESPACE_PREFIX, + XML_NAMESPACE_OOOW ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_ERROR_MACRO_ACTIONS +XMLTransformerActionInit const aErrorMacroActionTable[] = +{ + ENTRY0( TABLE, NAME, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_DDE_CONV_MODE_ACTIONS +XMLTransformerActionInit const aDDEConvModeActionTable[] = +{ + ENTRY1Q( TABLE, LET_TEXT, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_KEEP_TEXT ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_DATAPILOT_MEMBER_ACTIONS +XMLTransformerActionInit const aDataPilotMemberActionTable[] = +{ + ENTRY1Q( TABLE, DISPLAY_DETAILS, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_SHOW_DETAILS ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_DATAPILOT_LEVEL_ACTIONS +XMLTransformerActionInit const aDataPilotLevelActionTable[] = +{ + ENTRY1Q( TABLE, DISPLAY_EMPTY, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_SHOW_EMPTY ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_SOURCE_SERVICE_ACTIONS +XMLTransformerActionInit const aSourceServiceActionTable[] = +{ + ENTRY1Q( TABLE, USERNAME, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_USER_NAME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_ANIMATION_ACTIONS +XMLTransformerActionInit const aAnimationsActionTable[] = +{ + ENTRY0( DRAW, SHAPE_ID, XML_ATACTION_SHAPEID ), + ENTRY0( PRESENTATION, PATH_ID, XML_ATACTION_SHAPEID ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_DRAW_AREA_POLYGON_ACTIONS (to be added to OOO_SHAPE_ACTIONS) +XMLTransformerActionInit const aDrawAreaPolygonActionTable[] = +{ + ENTRY1Q( SVG, POINTS, XML_ATACTION_RENAME, + XML_NAMESPACE_DRAW, XML_POINTS ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_CHART_ACTIONS +XMLTransformerActionInit const aChartActionTable[] = +{ + ENTRY1( CHART, CLASS, XML_ATACTION_ADD_NAMESPACE_PREFIX, + XML_NAMESPACE_CHART ), + ENTRY0( CHART, ADD_IN_NAME, XML_ATACTION_REMOVE ), + ENTRY0( SVG, WIDTH, XML_ATACTION_INCH2IN ), + ENTRY0( SVG, HEIGHT, XML_ATACTION_INCH2IN ), + ENTRY0( CHART, STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_ALPHABETICAL_INDEX_MARK_ACTIONS +XMLTransformerActionInit const aAlphabeticalIndexMarkActionTable[] = +{ + ENTRY1Q( TEXT, MAIN_ETRY, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_MAIN_ENTRY ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_SCRIPT_ACTIONS +XMLTransformerActionInit const aScriptActionTable[] = +{ + ENTRY1( SCRIPT, LANGUAGE, XML_ATACTION_ADD_NAMESPACE_PREFIX, XML_NAMESPACE_OOO ), + ENTRY1Q( SCRIPT, NAME, XML_ATACTION_RENAME, XML_NAMESPACE_OOO, XML_NAME ), + ENTRY1Q( SCRIPT, READONLY, XML_ATACTION_RENAME, XML_NAMESPACE_OOO, XML_READONLY ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +XMLTokenEnum const aTokenMap[] = +{ + XML_NONE, XML_SINGLE, XML_DOUBLE, XML_BOLD, XML_BOLD_DOTTED, + XML_BOLD_DASH, XML_BOLD_LONG_DASH, XML_BOLD_DOT_DASH, + XML_BOLD_DOT_DOT_DASH, XML_BOLD_WAVE, XML_DOUBLE_WAVE, + XML_SINGLE_LINE, XML_DOUBLE_LINE, XML_THICK_LINE, XML_SLASH, XML_uX, + XML_TOKEN_END +}; + +namespace { + +class XMLDocumentTransformerContext_Impl : public XMLTransformerContext +{ + OUString const m_aElemQName; + OUString m_aOldClass; + +public: + XMLDocumentTransformerContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + XMLDocumentTransformerContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +} + +XMLDocumentTransformerContext_Impl::XMLDocumentTransformerContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rQName ) +{ +} +XMLDocumentTransformerContext_Impl::XMLDocumentTransformerContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName , + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rImp.GetNamespaceMap().GetQNameByKey( nPrefix, + ::xmloff::token::GetXMLToken( eToken ) ) ) +{ +} + +void XMLDocumentTransformerContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + Reference< XAttributeList > xAttrList( rAttrList ); + + m_aOldClass = GetTransformer().GetClass(); + + rtl::Reference pMutableAttrList; + bool bOOo = false, bOOoW = false, bOOoC = false, + bDOM=false, bDC = false, bSVG = false; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + if( XML_NAMESPACE_OFFICE == nPrefix && + IsXMLToken( aLocalName, XML_CLASS ) ) + { + const OUString& rValue = xAttrList->getValueByIndex( i ); + GetTransformer().SetClass( rValue ); + + pMutableAttrList = new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + OUString sMime = "application/vnd.oasis.opendocument." + rValue; + pMutableAttrList->SetValueByIndex( i, sMime ); + OUString aNewAttrQName( GetTransformer().GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_OFFICE, ::xmloff::token::GetXMLToken( XML_MIMETYPE ) ) ); + pMutableAttrList->RenameAttributeByIndex(i, aNewAttrQName ); + break; + } + else if( XML_NAMESPACE_XMLNS == nPrefix ) + { + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + if( IsXMLToken( rAttrValue, XML_N_OOO ) ) + bOOo = true; + else if( IsXMLToken( rAttrValue, XML_N_OOOW ) ) + bOOoW = true; + else if( IsXMLToken( rAttrValue, XML_N_OOOC ) ) + bOOoC = true; + else if( IsXMLToken( rAttrValue, XML_N_DOM ) ) + bDOM = true; + else if( IsXMLToken( rAttrValue, XML_N_DC ) ) + bDC = true; + else if( IsXMLToken( rAttrValue, XML_N_SVG ) ) + bSVG = true; + } + } + if( !(bOOo && bOOoW && bOOoC && bDOM && bDC && bSVG) ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + if( !bOOo ) + pMutableAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetAttrNameByKey( + XML_NAMESPACE_OOO ), + GetTransformer().GetNamespaceMap().GetNameByKey( + XML_NAMESPACE_OOO ) ); + if( !bOOoW ) + pMutableAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetAttrNameByKey( + XML_NAMESPACE_OOOW ), + GetTransformer().GetNamespaceMap().GetNameByKey( + XML_NAMESPACE_OOOW ) ); + if( !bOOoC ) + pMutableAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetAttrNameByKey( + XML_NAMESPACE_OOOC ), + GetTransformer().GetNamespaceMap().GetNameByKey( + XML_NAMESPACE_OOOC ) ); + if( !bDOM ) + pMutableAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetAttrNameByKey( + XML_NAMESPACE_DOM ), + GetTransformer().GetNamespaceMap().GetNameByKey( + XML_NAMESPACE_DOM ) ); + if( !bDC ) + pMutableAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetAttrNameByKey( + XML_NAMESPACE_DC ), + GetTransformer().GetNamespaceMap().GetNameByKey( + XML_NAMESPACE_DC ) ); + if( !bSVG ) + pMutableAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetAttrNameByKey( + XML_NAMESPACE_SVG ), + GetTransformer().GetNamespaceMap().GetNameByKey( + XML_NAMESPACE_SVG ) ); + } + + GetTransformer().GetDocHandler()->startElement( m_aElemQName, xAttrList ); +} + +void XMLDocumentTransformerContext_Impl::EndElement() +{ + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); + + GetTransformer().SetClass( m_aOldClass ); +} + +namespace { + +class XMLBodyTransformerContext_Impl : public XMLTransformerContext +{ + OUString m_aClassQName; + +public: + XMLBodyTransformerContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +} + +XMLBodyTransformerContext_Impl::XMLBodyTransformerContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ) +{ +} + +void XMLBodyTransformerContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerContext::StartElement( rAttrList ); + + rtl::Reference pMutableAttrList = + new XMLMutableAttributeList( rAttrList ); + Reference< XAttributeList > xAttrList = pMutableAttrList; + OUString aClass( GetTransformer().GetClass() ); + if( aClass.isEmpty() ) + { + aClass = GetXMLToken( XML_TEXT ); + } + else if( IsXMLToken( aClass, XML_TEXT_GLOBAL ) ) + { + OUString aGlobalQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TEXT, GetXMLToken(XML_GLOBAL ) ) ); + pMutableAttrList->AddAttribute( aGlobalQName, GetXMLToken(XML_TRUE) ); + + aClass = GetXMLToken( XML_TEXT ); + } + + m_aClassQName = GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_OFFICE, aClass ); + GetTransformer().GetDocHandler()->startElement( m_aClassQName, + xAttrList ); +} + +void XMLBodyTransformerContext_Impl::EndElement() +{ + GetTransformer().GetDocHandler()->endElement( m_aClassQName ); + XMLTransformerContext::EndElement(); +} + +namespace { + +class XMLTabStopOOoTContext_Impl : public XMLPersElemContentTContext +{ +public: + XMLTabStopOOoTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +} + +XMLTabStopOOoTContext_Impl::XMLTabStopOOoTContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLPersElemContentTContext( rImp, rQName ) +{ +} + +void XMLTabStopOOoTContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OOO_TAB_STOP_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_RENAME: + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + pMutableAttrList->RenameAttributeByIndex( i, + aNewAttrQName ); + } + if( IsXMLToken( aLocalName, XML_LEADER_CHAR ) && + !rAttrValue.isEmpty() && + rAttrValue[0] != ' ' ) + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + ::xmloff::token::GetXMLToken(XML_LEADER_STYLE) ) ); + pMutableAttrList->AddAttribute( aNewAttrQName, + GetXMLToken( XML_SOLID ) ); + } + break; + case XML_ATACTION_INCH2IN: + { + OUString aAttrValue( rAttrValue ); + if( XMLTransformerBase::ReplaceSingleInchWithIn( + aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + XMLPersElemContentTContext::StartElement( xAttrList ); +} + +namespace { + +class XMLTrackedChangesOOoTContext_Impl : public XMLTransformerContext +{ + sal_uInt16 const m_nPrefix; + XMLTokenEnum const m_eToken; + +public: + XMLTrackedChangesOOoTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + XMLTokenEnum eToken ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +} + +XMLTrackedChangesOOoTContext_Impl::XMLTrackedChangesOOoTContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + XMLTokenEnum eToken ) : + XMLTransformerContext( rImp, rQName ), + m_nPrefix( nPrefix ), + m_eToken( eToken ) +{ +} + +void XMLTrackedChangesOOoTContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = rAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + if( m_nPrefix == nPrefix && IsXMLToken( aLocalName, m_eToken ) ) + { + const Reference< XPropertySet > rPropSet = + GetTransformer().GetPropertySet(); + OSL_ENSURE( rPropSet.is(), "no info property set" ); + if( rPropSet.is() ) + { + OUString aPropName("RedlineProtectionKey"); + Reference< XPropertySetInfo > xPropSetInfo( + rPropSet->getPropertySetInfo() ); + if( xPropSetInfo.is() && + xPropSetInfo->hasPropertyByName( aPropName ) ) + { + Sequence < sal_Int8 > aKey; + ::comphelper::Base64::decode( aKey, + rAttrList->getValueByIndex( i ) ); + rPropSet->setPropertyValue( aPropName, Any( aKey ) ); + } + else + { + OSL_ENSURE( false, "RedineProtectionKey is missing" ); + } + } + break; + } + } + XMLTransformerContext::StartElement( rAttrList ); +} + +namespace { + +class XMLTableOOoTransformerContext_Impl : public XMLTransformerContext +{ + OUString const m_aElemQName; + +public: + XMLTableOOoTransformerContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +} + +XMLTableOOoTransformerContext_Impl::XMLTableOOoTransformerContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rQName ) +{ +} + +void XMLTableOOoTransformerContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + // Perform OOO_STYLE_REF_ACTIONS for all applications (#i50521#) + Reference< XAttributeList > xAttrList( rAttrList ); + XMLMutableAttributeList* pMutableAttrList = + GetTransformer().ProcessAttrList( xAttrList, OOO_STYLE_REF_ACTIONS, false ); + if( rAttrList->getLength() && IsXMLToken( GetTransformer().GetClass(), XML_SPREADSHEET ) ) + { + bool bPrintRanges(false); + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + if( XML_NAMESPACE_TABLE == nPrefix && + IsXMLToken( aLocalName, XML_PRINT_RANGES ) ) + { + bPrintRanges = true; + } + } + if (!bPrintRanges && pMutableAttrList) + { + xAttrList = pMutableAttrList; + pMutableAttrList->AddAttribute(GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TABLE, + GetXMLToken( XML_PRINT ) ), GetXMLToken ( XML_FALSE )); + } + } + + GetTransformer().GetDocHandler()->startElement( m_aElemQName, xAttrList ); +} + +void XMLTableOOoTransformerContext_Impl::EndElement() +{ + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +XMLTransformerContext *OOo2OasisTransformer::CreateUserDefinedContext( + const TransformerAction_Impl& rAction, + const OUString& rQName, + bool bPersistent ) +{ + switch( rAction.m_nActionType ) + { + case XML_ETACTION_DOCUMENT: + return new XMLDocumentTransformerContext_Impl( *this, rQName ); + case XML_ETACTION_DOCUMENT_RENAME: + return new XMLDocumentTransformerContext_Impl( *this, rQName, + rAction.GetQNamePrefixFromParam1(), + rAction.GetQNameTokenFromParam1() ); + case XML_ETACTION_BODY: + return new XMLBodyTransformerContext_Impl( *this, rQName ); + case XML_ETACTION_STYLE: + return new XMLStyleOOoTContext( *this, rQName, + static_cast< XMLFamilyType >( rAction.m_nParam1 ), + bPersistent ); + case XML_ETACTION_STYLE_RENAME: + return new XMLStyleOOoTContext( *this, rQName, + static_cast< XMLFamilyType >( rAction.m_nParam2 ), + rAction.GetQNamePrefixFromParam1(), + rAction.GetQNameTokenFromParam1(), + bPersistent ); + case XML_ETACTION_FRAME: + return new XMLFrameOOoTransformerContext( *this, rQName ); + case XML_ETACTION_EVENT: + return new XMLEventOOoTransformerContext( *this, rQName, bPersistent ); + case XML_ETACTION_TAB_STOP: + return new XMLTabStopOOoTContext_Impl( *this, rQName ); + case XML_ETACTION_FORM_CONTROL: + return new XMLControlOOoTransformerContext( *this, rQName ); + case XML_ETACTION_FORM_PROPERTY: + return new XMLFormPropOOoTransformerContext( *this, rQName ); +#if !ENABLE_WASM_STRIP_CHART + case XML_ETACTION_CHART: + return new XMLChartOOoTransformerContext( *this, rQName ); + case XML_ETACTION_CHART_PLOT_AREA: + return new XMLChartPlotAreaOOoTContext( *this, rQName ); +#endif + case XML_ETACTION_TRACKED_CHANGES: + return new XMLTrackedChangesOOoTContext_Impl( *this, rQName, + rAction.GetQNamePrefixFromParam1(), + rAction.GetQNameTokenFromParam1() ); + case XML_ETACTION_TABLE: + return new XMLTableOOoTransformerContext_Impl( *this, rQName ); + default: + OSL_ENSURE( false, "no user defined context found!" ); + } + + // default is copying + return new XMLTransformerContext( *this, rQName ); +} + +XMLTransformerActions *OOo2OasisTransformer::GetUserDefinedActions( + sal_uInt16 n ) +{ + XMLTransformerActions *pActions = nullptr; + if( n < MAX_OOO_ACTIONS ) + { + if( !m_aActions[n] ) + { + if( nAdd( aDrawAreaPolygonActionTable ); + break; + case OOO_SCRIPT_ACTIONS: + m_aActions[OOO_SCRIPT_ACTIONS].reset( + new XMLTransformerActions( aScriptActionTable ) ); + break; + case OOO_ANIMATION_ACTIONS: + m_aActions[OOO_ANIMATION_ACTIONS].reset( + new XMLTransformerActions( aAnimationsActionTable ) ); + break; + } + } + pActions = m_aActions[n].get(); + } + + return pActions; +} + +OUString OOo2OasisTransformer::GetEventName( const OUString& rName, bool ) +{ + if( !m_pEventMap ) + m_pEventMap = XMLEventOOoTransformerContext::CreateEventMap(); + + OUString aNewName; + sal_uInt16 nPrefix = XMLEventOOoTransformerContext::GetEventName( rName, + aNewName, *m_pEventMap ); + if( XML_NAMESPACE_UNKNOWN != nPrefix ) + aNewName = GetNamespaceMap().GetQNameByKey( nPrefix, aNewName ); + else + aNewName = rName; + + return aNewName; +} + +OOo2OasisTransformer::OOo2OasisTransformer( OUString const & rImplName, + OUString const & rSubServiceName ) + noexcept : + XMLTransformerBase( aActionTable, aTokenMap ), + m_aImplName(rImplName), + m_aSubServiceName(rSubServiceName), + m_pEventMap( nullptr ) +{ + GetNamespaceMap().Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE_OOO), XML_NAMESPACE_OFFICE ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_META), GetXMLToken(XML_N_META_OOO), XML_NAMESPACE_META ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_META), GetXMLToken(XML_N_META), XML_NAMESPACE_META ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE_OOO), XML_NAMESPACE_STYLE ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_NUMBER), GetXMLToken(XML_N_NUMBER_OOO), XML_NAMESPACE_NUMBER ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_NUMBER), GetXMLToken(XML_N_NUMBER), XML_NAMESPACE_NUMBER ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_CONFIG), GetXMLToken(XML_N_CONFIG_OOO), XML_NAMESPACE_CONFIG ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_CONFIG), GetXMLToken(XML_N_CONFIG), XML_NAMESPACE_CONFIG ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_TEXT), GetXMLToken(XML_N_TEXT_OOO), XML_NAMESPACE_TEXT ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_TEXT), GetXMLToken(XML_N_TEXT), XML_NAMESPACE_TEXT ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_TABLE), GetXMLToken(XML_N_TABLE_OOO), XML_NAMESPACE_TABLE ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_TABLE), GetXMLToken(XML_N_TABLE), XML_NAMESPACE_TABLE ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_DRAW), GetXMLToken(XML_N_DRAW_OOO), XML_NAMESPACE_DRAW ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_DRAW), GetXMLToken(XML_N_DRAW), XML_NAMESPACE_DRAW ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_DR3D), GetXMLToken(XML_N_DR3D_OOO), XML_NAMESPACE_DR3D ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_DR3D), GetXMLToken(XML_N_DR3D), XML_NAMESPACE_DR3D ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_PRESENTATION), GetXMLToken(XML_N_PRESENTATION_OOO), XML_NAMESPACE_PRESENTATION ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_PRESENTATION), GetXMLToken(XML_N_PRESENTATION), XML_NAMESPACE_PRESENTATION ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_CHART), GetXMLToken(XML_N_CHART_OOO), XML_NAMESPACE_CHART ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_CHART), GetXMLToken(XML_N_CHART), XML_NAMESPACE_CHART ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_FORM), GetXMLToken(XML_N_FORM_OOO), XML_NAMESPACE_FORM ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_FORM), GetXMLToken(XML_N_FORM), XML_NAMESPACE_FORM ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_SCRIPT), GetXMLToken(XML_N_SCRIPT_OOO), XML_NAMESPACE_SCRIPT ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_SCRIPT), GetXMLToken(XML_N_SCRIPT), XML_NAMESPACE_SCRIPT ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_FO), GetXMLToken(XML_N_FO), XML_NAMESPACE_FO ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_FO), GetXMLToken(XML_N_FO_COMPAT), XML_NAMESPACE_FO ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG), XML_NAMESPACE_SVG ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG_COMPAT), XML_NAMESPACE_SVG ); + + for(auto & rp : m_aActions) + rp.reset(); +} + +OOo2OasisTransformer::~OOo2OasisTransformer() noexcept +{ + for(auto & rp : m_aActions) + rp.reset(); + XMLEventOOoTransformerContext::FlushEventMap( m_pEventMap ); +} + +Any OOo2OasisTransformer::queryInterface( const Type& rType ) +{ + Any aRet; + if ( rType == cppu::UnoType::get()) + { + Reference xThis( this ); + aRet <<= xThis; + } + else if ( rType == cppu::UnoType::get()) + { + Reference xThis( this ); + aRet <<= xThis; + } + else + { + aRet = XMLTransformerBase::queryInterface(rType); + } + + return aRet; +} + +// XImporter +void SAL_CALL OOo2OasisTransformer::setTargetDocument( + const Reference< XComponent >& xDoc ) +{ + if( !GetDocHandler().is() ) + { + // if initialize hasn't been called, then we have to call it now + // to get the sub component initialized. + Sequence aArgs( 0 ); + Initialize( aArgs ); + } + + mxModel.set( xDoc, UNO_QUERY ); + + Reference< XImporter > xImp( GetDocHandler(), UNO_QUERY ); + OSL_ENSURE( xImp.is(), "doc handler is not an importer" ); + if( xImp.is() ) + xImp->setTargetDocument( xDoc ); +} + +// XFilter +sal_Bool SAL_CALL OOo2OasisTransformer::filter( + const Sequence< PropertyValue >& aDescriptor ) +{ + Reference< XFilter> xFilter( GetDocHandler(), UNO_QUERY ); + OSL_ENSURE( xFilter.is(), "doc handler is not a filter" ); + if( xFilter.is() ) + return xFilter->filter( aDescriptor ); + + return false; +} + +void SAL_CALL OOo2OasisTransformer::cancel( ) +{ + Reference< XFilter> xFilter( GetDocHandler(), UNO_QUERY ); + OSL_ENSURE( xFilter.is(), "doc handler is not a filter" ); + if( xFilter.is() ) + xFilter->cancel(); +} + +// XInitialize +void SAL_CALL OOo2OasisTransformer::initialize( + const Sequence< Any >& rArguments ) +{ + Initialize( rArguments ); +} + +void SAL_CALL OOo2OasisTransformer::startDocument() +{ + if( !GetDocHandler().is() ) + { + // if initialize hasn't been called, then we have to call it now + // to get the sub component initialized. + Sequence aArgs( 0 ); + Initialize( aArgs ); + } + + XMLTransformerBase::startDocument(); +} + +void OOo2OasisTransformer::Initialize( + const Sequence< Any >& rArguments ) +{ + OSL_ENSURE( !GetDocHandler().is(), "duplication initialization" ); + + Reference< XInterface > xFilter; + if( !m_aSubServiceName.isEmpty() ) + { + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + // get filter component + xFilter = + xContext->getServiceManager()->createInstanceWithArgumentsAndContext(m_aSubServiceName, rArguments, xContext); + SAL_WARN_IF(!xFilter, "xmloff", "could not instantiate " << m_aSubServiceName); + } + else + SAL_WARN("xmloff", "no subservice name"); + + if (xFilter.is()) + { + Sequence aArgs( 1 + rArguments.getLength() ); + auto pArgs = aArgs.getArray(); + pArgs[0] <<= xFilter; + std::copy(rArguments.begin(), rArguments.end(), std::next(pArgs)); + XMLTransformerBase::initialize( aArgs ); + + OSL_ENSURE( GetDocHandler() == xFilter, + "duplicate doc handler" ); + } + else + { + XMLTransformerBase::initialize( rArguments ); + } +} + +const css::uno::Sequence& OOo2OasisTransformer::getUnoTunnelId() noexcept +{ + static const comphelper::UnoIdInit theOOo2OasisTransformerUnoTunnelId; + return theOOo2OasisTransformerUnoTunnelId.getSeq(); +} + +// XUnoTunnel +sal_Int64 SAL_CALL OOo2OasisTransformer::getSomething( const Sequence< sal_Int8 >& rId ) +{ + return comphelper::getSomethingImpl(rId, this); +} + +// XServiceInfo +OUString SAL_CALL OOo2OasisTransformer::getImplementationName() +{ + return m_aImplName; +} + +sal_Bool SAL_CALL OOo2OasisTransformer::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL OOo2OasisTransformer::getSupportedServiceNames( ) +{ + return { }; +} + +// XTypeProvider +Sequence< css::uno::Type > SAL_CALL OOo2OasisTransformer::getTypes() +{ + return cppu::OTypeCollection( + cppu::UnoType::get(), + cppu::UnoType::get(), + XMLTransformerBase::getTypes() + ).getTypes(); +} + +// Service registration + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +xmloff_OOo2OasisTransformer_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + return cppu::acquire(new OOo2OasisTransformer("com.sun.star.comp.OOo2OasisTransformer", OUString())); +} + +#define OOO_IMPORTER( className, implName, subServiceName ) \ +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* \ +xmloff_##className##_get_implementation( \ + css::uno::XComponentContext* , css::uno::Sequence const&) \ +{ \ + return cppu::acquire(new OOo2OasisTransformer( \ + implName, \ + subServiceName )); \ +} + +OOO_IMPORTER( XMLWriterImportOOO, + "com.sun.star.comp.Writer.XMLImporter", + "com.sun.star.comp.Writer.XMLOasisImporter" ) +OOO_IMPORTER( XMLWriterStylesImportOOO, + "com.sun.star.comp.Writer.XMLStylesImporter", + "com.sun.star.comp.Writer.XMLOasisStylesImporter" ) +OOO_IMPORTER( XMLWriterContentImportOOO, + "com.sun.star.comp.Writer.XMLContentImporter", + "com.sun.star.comp.Writer.XMLOasisContentImporter" ) +OOO_IMPORTER( XMLWriterMetaImportOOO, + "com.sun.star.comp.Writer.XMLMetaImporter", + "com.sun.star.comp.Writer.XMLOasisMetaImporter" ) +OOO_IMPORTER( XMLWriterSettingsImportOOO, + "com.sun.star.comp.Writer.XMLSettingsImporter", + "com.sun.star.comp.Writer.XMLOasisSettingsImporter" ) + +OOO_IMPORTER( XMLImpressImportOOO, + "com.sun.star.comp.Impress.XMLImporter", + "com.sun.star.comp.Impress.XMLOasisImporter" ) +OOO_IMPORTER( XMLImpressStylesImportOOO, + "com.sun.star.comp.Impress.XMLStylesImporter", + "com.sun.star.comp.Impress.XMLOasisStylesImporter" ) +OOO_IMPORTER( XMLImpressContentImportOOO, + "com.sun.star.comp.Impress.XMLContentImporter", + "com.sun.star.comp.Impress.XMLOasisContentImporter" ) +OOO_IMPORTER( XMLImpressMetaImportOOO, + "com.sun.star.comp.Impress.XMLMetaImporter", + "com.sun.star.comp.Impress.XMLOasisMetaImporter" ) +OOO_IMPORTER( XMLImpressSettingsImportOOO, + "com.sun.star.comp.Impress.XMLSettingsImporter", + "com.sun.star.comp.Impress.XMLOasisSettingsImporter" ) + +OOO_IMPORTER( XMLDrawImportOOO, + "com.sun.star.comp.Draw.XMLImporter", + "com.sun.star.comp.Draw.XMLOasisImporter" ) +OOO_IMPORTER( XMLDrawStylesImportOOO, + "com.sun.star.comp.Draw.XMLStylesImporter", + "com.sun.star.comp.Draw.XMLOasisStylesImporter" ) +OOO_IMPORTER( XMLDrawContentImportOOO, + "com.sun.star.comp.Draw.XMLContentImporter", + "com.sun.star.comp.Draw.XMLOasisContentImporter" ) +OOO_IMPORTER( XMLDrawMetaImportOOO, + "com.sun.star.comp.Draw.XMLMetaImporter", + "com.sun.star.comp.Draw.XMLOasisMetaImporter" ) +OOO_IMPORTER( XMLDrawSettingsImportOOO, + "com.sun.star.comp.Draw.XMLSettingsImporter", + "com.sun.star.comp.Draw.XMLOasisSettingsImporter" ) + +OOO_IMPORTER( XMLCalcImportOOO, + "com.sun.star.comp.Calc.XMLImporter", + "com.sun.star.comp.Calc.XMLOasisImporter" ) +OOO_IMPORTER( XMLCalcStylesImportOOO, + "com.sun.star.comp.Calc.XMLStylesImporter", + "com.sun.star.comp.Calc.XMLOasisStylesImporter" ) +OOO_IMPORTER( XMLCalcContentImportOOO, + "com.sun.star.comp.Calc.XMLContentImporter", + "com.sun.star.comp.Calc.XMLOasisContentImporter" ) +OOO_IMPORTER( XMLCalcMetaImportOOO, + "com.sun.star.comp.Calc.XMLMetaImporter", + "com.sun.star.comp.Calc.XMLOasisMetaImporter" ) +OOO_IMPORTER( XMLCalcSettingsImportOOO, + "com.sun.star.comp.Calc.XMLSettingsImporter", + "com.sun.star.comp.Calc.XMLOasisSettingsImporter" ) + +OOO_IMPORTER( XMLChartImportOOO, + "com.sun.star.comp.Chart.XMLImporter", + "com.sun.star.comp.Chart.XMLOasisImporter" ) +OOO_IMPORTER( XMLChartStylesImportOOO, + "com.sun.star.comp.Chart.XMLStylesImporter", + "com.sun.star.comp.Chart.XMLOasisStylesImporter" ) +OOO_IMPORTER( XMLChartContentImportOOO, + "com.sun.star.comp.Chart.XMLContentImporter", + "com.sun.star.comp.Chart.XMLOasisContentImporter" ) + +OOO_IMPORTER( XMLMathMetaImportOOO, + "com.sun.star.comp.Math.XMLMetaImporter", + "com.sun.star.comp.Math.XMLOasisMetaImporter" ) +OOO_IMPORTER( XMLMathSettingsImportOOO, + "com.sun.star.comp.Math.XMLSettingsImporter", + "com.sun.star.comp.Math.XMLOasisSettingsImporter" ) + +OOO_IMPORTER( XMLMetaImportOOO, + "com.sun.star.document.XMLMetaImporter", + "com.sun.star.document.XMLOasisMetaImporter" ) + +OOO_IMPORTER( XMLAutoTextEventImportOOO, + "com.sun.star.comp.Writer.XMLAutotextEventsImporter", + "com.sun.star.comp.Writer.XMLOasisAutotextEventsImporter" ) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/OOo2Oasis.hxx b/xmloff/source/transform/OOo2Oasis.hxx new file mode 100644 index 000000000..43d69853f --- /dev/null +++ b/xmloff/source/transform/OOo2Oasis.hxx @@ -0,0 +1,102 @@ +/* -*- 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 +#include +#include "ActionMapTypesOOo.hxx" +#include "TransformerBase.hxx" + +class XMLTransformerOOoEventMap_Impl; + +class OOo2OasisTransformer : + public XMLTransformerBase, + public css::document::XImporter, + public css::document::XFilter +{ + OUString const m_aImplName; + OUString const m_aSubServiceName; + + std::unique_ptr m_aActions[MAX_OOO_ACTIONS]; + XMLTransformerOOoEventMap_Impl *m_pEventMap; +protected: + + virtual XMLTransformerContext *CreateUserDefinedContext( + const TransformerAction_Impl& rAction, + const OUString& rQName, + bool bPersistent=false ) override; + + virtual XMLTransformerActions *GetUserDefinedActions( sal_uInt16 n ) override; + +public: + OOo2OasisTransformer( OUString const & rImplName, + OUString const & rSubServiceName ) noexcept; + virtual ~OOo2OasisTransformer() noexcept override; + + // XInterface + + // (XInterface methods need to be implemented to disambiguate + // between those inherited through XMLTransformerBase and + // the new interfaces). + + virtual css::uno::Any SAL_CALL queryInterface( + const css::uno::Type& aType ) override; + + virtual void SAL_CALL acquire( ) noexcept override + { XMLTransformerBase::acquire(); }; + + virtual void SAL_CALL release( ) noexcept override + { XMLTransformerBase::release(); }; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XUnoTunnel + static const css::uno::Sequence& getUnoTunnelId() noexcept; + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + + // XImporter + virtual void SAL_CALL setTargetDocument( const css::uno::Reference< css::lang::XComponent >& xDoc ) override; + + // XFilter + virtual sal_Bool SAL_CALL filter( const css::uno::Sequence< css::beans::PropertyValue >& aDescriptor ) override; + virtual void SAL_CALL cancel( ) override; + + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + void Initialize( const css::uno::Sequence< css::uno::Any >& aArguments ); + + // css::xml::sax::XDocumentHandler + virtual void SAL_CALL startDocument() override; + + virtual OUString GetEventName( const OUString& rName, + bool bForm = false ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/Oasis2OOo.cxx b/xmloff/source/transform/Oasis2OOo.cxx new file mode 100644 index 000000000..7a74d2ab4 --- /dev/null +++ b/xmloff/source/transform/Oasis2OOo.cxx @@ -0,0 +1,1984 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "DeepTContext.hxx" +#include "MetaTContext.hxx" +#include "DocumentTContext.hxx" +#include "NotesTContext.hxx" +#include "StyleOASISTContext.hxx" +#include "FrameOASISTContext.hxx" +#include "EventOASISTContext.hxx" +#include "DlgOASISTContext.hxx" +#include "ControlOASISTContext.hxx" +#include "FormPropOASISTContext.hxx" +#include "ChartOASISTContext.hxx" +#include "ChartPlotAreaOASISTContext.hxx" +#include "MutableAttrList.hxx" +#include "ElemTransformerAction.hxx" +#include "AttrTransformerAction.hxx" +#include "TransformerActions.hxx" +#include "FamilyType.hxx" +#include +#include "Oasis2OOo.hxx" +#include + +using namespace ::osl; +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::xml::sax; +using namespace ::com::sun::star::beans; + +namespace { + +enum XMLUserDefinedTransformerAction +{ + XML_ETACTION_META=XML_ETACTION_USER_DEFINED, + XML_ETACTION_DOCUMENT, + XML_ETACTION_BODY, + XML_ETACTION_NOTES, + XML_ETACTION_TABLE, + XML_ETACTION_STYLE, + XML_ETACTION_STYLE_RENAME, + XML_ETACTION_FRAME, + XML_ETACTION_EVENT, + XML_ETACTION_DLG, + XML_ETACTION_TAB_STOP, + XML_ETACTION_FORM_CONTROL, + XML_ETACTION_FORM_PROPERTY, + XML_ETACTION_CONFIG_ITEM, + XML_ETACTION_TRACKED_CHANGES, + XML_ETACTION_CHART, + XML_ETACTION_CHART_PLOT_AREA +}; + +} + +#define ENTRY3( n, l, a, p1, p2, p3 ) \ + { XML_NAMESPACE_##n, XML_##l, a, p1, p2, p3 } +#define ENTRY3QNQ( n, l, a, n1, l1, p2, n3, l3 ) \ + ENTRY3( n, l, a, XMLTransformerActionInit::QNameParam( n1, l1 ), \ + p2, XMLTransformerActionInit::QNameParam( n3, l3 ) ) + +#define ENTRY2( n, l, a, p1, p2 ) \ + ENTRY3( n, l, a, p1, p2, 0 ) +#define ENTRY2QN( n, l, a, n1, l1, p2 ) \ + ENTRY2( n, l, a, XMLTransformerActionInit::QNameParam( n1, l1 ), p2 ) + +#define ENTRY1( n, l, a, p1 ) \ + ENTRY3( n, l, a, p1, 0, 0 ) +#define ENTRY1Q( n, l, a, p1, t1 ) \ + ENTRY1( n, l, a, XMLTransformerActionInit::QNameParam( p1, t1 ) ) + +#define ENTRY0( n, l, a ) \ + ENTRY3( n, l, a, 0, 0, 0 ) + +// a macro to put two tokens into one sal_Int32 for the action +// XML_ATACTION_RENAME_ATTRIBUTE +static constexpr sal_Int32 RENAME_ENTRY( XMLTokenEnum f, XMLTokenEnum s ) +{ + return static_cast< sal_Int32 >(f) | (static_cast< sal_Int32 >(s) << 16); +} + +XMLTransformerActionInit const aActionTable[] = +{ + // add office:class from and + ENTRY0( OFFICE, DOCUMENT, XML_ETACTION_DOCUMENT ), + ENTRY0( OFFICE, DOCUMENT_CONTENT, XML_ETACTION_DOCUMENT ), + ENTRY1Q( OOO, AUTO_TEXT_EVENTS, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OFFICE, XML_AUTO_TEXT_EVENTS), + + // add + ENTRY0( OFFICE, META, XML_ETACTION_META ), + + // rename to + ENTRY1Q( OFFICE, SCRIPTS, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OFFICE, XML_SCRIPT ), + + // rename to and process attributes + ENTRY2QN( OFFICE, SCRIPT, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_OFFICE, XML_SCRIPT_DATA, + OASIS_SCRIPT_ACTIONS ), + + // rename to + ENTRY1Q( OOO, LIBRARIES, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_SCRIPT, XML_LIBRARIES ), + + // rename to and process attributes + ENTRY2QN( OOO, LIBRARY_LINKED, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_SCRIPT, XML_LIBRARY_LINKED, + OASIS_SCRIPT_ACTIONS ), + + // rename to and process attributes + ENTRY2QN( OOO, LIBRARY_EMBEDDED, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_SCRIPT, XML_LIBRARY_EMBEDDED, + OASIS_SCRIPT_ACTIONS ), + + // rename to and process attributes + ENTRY2QN( OOO, MODULE, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_SCRIPT, XML_MODULE, + OASIS_SCRIPT_ACTIONS ), + + // rename to + ENTRY1Q( OOO, SOURCE_CODE, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_SCRIPT, XML_SOURCE_CODE ), + + ENTRY0( OFFICE, BODY, XML_ETACTION_BODY ), + + // rename to , + // rename to , process attrs + ENTRY1Q( OFFICE, FONT_FACE_DECLS, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OFFICE, XML_FONT_DECLS ), + ENTRY2QN( STYLE, FONT_FACE, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_STYLE, XML_FONT_DECL, + OASIS_FONT_FACE_ACTIONS ), + + // remove genre element + ENTRY0( OFFICE, TEXT, XML_ETACTION_COPY_CONTENT ), + ENTRY0( OFFICE, DRAWING, XML_ETACTION_COPY_CONTENT ), + ENTRY0( OFFICE, PRESENTATION, XML_ETACTION_COPY_CONTENT ), + ENTRY0( OFFICE, SPREADSHEET, XML_ETACTION_COPY_CONTENT ), + ENTRY0( OFFICE, CHART, XML_ETACTION_COPY_CONTENT ), + ENTRY0( OFFICE, IMAGE, XML_ETACTION_COPY_CONTENT ), + + // rename to + // ENTRY1Q( STYLE, PAGE_LAYOUT, RENAME_ELEM, + // XML_NAMESPACE_STYLE, XML_PAGE_MASTER ), + ENTRY1( STYLE, MASTER_PAGE, XML_ETACTION_PROC_ATTRS, + OASIS_MASTER_PAGE_ACTIONS ), + + // merge into and do other + // styles processing + ENTRY1( STYLE, STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_END ), + ENTRY1( STYLE, DEFAULT_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_END ), + ENTRY2QN( STYLE, PAGE_LAYOUT, XML_ETACTION_STYLE_RENAME, + XML_NAMESPACE_STYLE, XML_PAGE_MASTER, + XML_FAMILY_TYPE_PAGE_LAYOUT ), + ENTRY1( NUMBER, NUMBER_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, CURRENCY_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, PERCENTAGE_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, DATE_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, TIME_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, BOOLEAN_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_DATA ), + ENTRY1( NUMBER, TEXT_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_DATA ), + ENTRY1( TEXT, LIST_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_LIST ), +// ENTRY0( TEXT, OUTLINE_STYLE, STYLE ), + + ENTRY1( STYLE, HEADER_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_HEADER_FOOTER ), + ENTRY1( STYLE, FOOTER_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_HEADER_FOOTER ), + ENTRY1( TEXT, LIST_LEVEL_STYLE_NUMBER, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_LIST ), + ENTRY1( TEXT, LIST_LEVEL_STYLE_BULLET, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_LIST ), + ENTRY1( TEXT, LIST_LEVEL_STYLE_IMAGE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_LIST ), + ENTRY1( TEXT, OUTLINE_LEVEL_STYLE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_LIST ), + ENTRY1( DRAW, GRADIENT, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_GRADIENT ), + ENTRY1( DRAW, FILL_IMAGE, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_FILL_IMAGE ), + ENTRY2QN( DRAW, OPACITY, XML_ETACTION_STYLE_RENAME, + XML_NAMESPACE_DRAW, XML_TRANSPARENCY, + XML_FAMILY_TYPE_GRADIENT ), + ENTRY1( DRAW, MARKER, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_MARKER ), + ENTRY1( DRAW, HATCH, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_HATCH ), + ENTRY1( DRAW, STROKE_DASH, XML_ETACTION_STYLE, + XML_FAMILY_TYPE_STROKE_DASH ), + + // process : process style-name attributes, + // rename 's text:outline-level to text:level, + ENTRY1( TEXT, H, XML_ETACTION_PROC_ATTRS, OASIS_PARA_ACTIONS ), + ENTRY1( TEXT, P, XML_ETACTION_PROC_ATTRS, OASIS_PARA_ACTIONS ), + + // process 's text:style-name attributes + // rename to or + // TODO: All list currently are renamed to + ENTRY2QN( TEXT, LIST, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_TEXT, XML_ORDERED_LIST, + OASIS_LIST_STYLE_REF_ACTIONS ), + + // rename to or + ENTRY1( TEXT, NOTES_CONFIGURATION, XML_ETACTION_NOTES, + XML_NOTES_CONFIGURATION), + ENTRY1( TEXT, NOTE, XML_ETACTION_NOTES, XML_NOTE ), + + // rename and to + ENTRY1( TEXT, NOTE_REF, XML_ETACTION_NOTES, XML_NOTE_REF ), + + // rename to + ENTRY1Q( TEXT, TAB, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TEXT, XML_TAB_STOP ), + + // replace with + ENTRY0( TABLE, TABLE, XML_ETACTION_TABLE ), + + // merge frame element + ENTRY0( DRAW, FRAME, XML_ETACTION_FRAME ), + + // process events + ENTRY1Q( OFFICE, EVENT_LISTENERS, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_OFFICE, XML_EVENTS ), + ENTRY0( SCRIPT, EVENT_LISTENER, XML_ETACTION_EVENT ), + ENTRY0( SCRIPT, EVENT, XML_ETACTION_EVENT ), + ENTRY0( PRESENTATION, EVENT_LISTENER, XML_ETACTION_EVENT ), + + // process Basic dialogs + ENTRY0( DLG, STYLE, XML_ETACTION_DLG ), + + // process length attributes + ENTRY1( DRAW, RECT, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, LINE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, POLYLINE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, POLYGON, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, PATH, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, CIRCLE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, ELLIPSE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, CONNECTOR, XML_ETACTION_PROC_ATTRS, OASIS_CONNECTOR_ACTIONS ), + ENTRY1( DRAW, CAPTION, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, MEASURE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, CONTROL, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, PAGE_THUMBNAIL, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, G, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), +// ENTRY1( DRAW, FRAME, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, TEXT_BOX, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( PRESENTATION, PLACEHOLDER, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, CONTOUR_POLYGON, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, CONTOUR_PATH, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, AREA_RECTANGLE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, AREA_CIRCLE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DRAW, AREA_POLYGON, XML_ETACTION_PROC_ATTRS, OASIS_DRAW_AREA_POLYGON_ACTIONS ), + ENTRY1( DRAW, GLUE_POINT, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DR3D, SCENE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DR3D, CUBE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DR3D, SPHERE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DR3D, EXTRUDE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( DR3D, ROTATE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, TITLE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, SUBTITLE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, FOOTER, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, LEGEND, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, WALL, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, FLOOR, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, AXIS, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, GRID, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, SERIES, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, DATA_POINT, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, MEAN_VALUE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, ERROR_INDICATOR, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, REGRESSION_CURVE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, STOCK_GAIN_MARKER, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, STOCK_LOSS_MARKER, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + ENTRY1( CHART, STOCK_RANGE_LINE, XML_ETACTION_PROC_ATTRS, OASIS_SHAPE_ACTIONS ), + + ENTRY0( CHART, CHART, XML_ETACTION_CHART ), + ENTRY0( CHART, PLOT_AREA, XML_ETACTION_CHART_PLOT_AREA ), + + ENTRY0( CONFIG, CONFIG_ITEM, XML_ETACTION_CONFIG_ITEM ), + ENTRY1Q( TEXT, TRACKED_CHANGES, XML_ETACTION_TRACKED_CHANGES, + XML_NAMESPACE_TEXT, XML_PROTECTION_KEY ), + ENTRY1Q( TABLE, TRACKED_CHANGES, XML_ETACTION_TRACKED_CHANGES, + XML_NAMESPACE_TABLE, XML_PROTECTION_KEY ), + + ENTRY1( TEXT, INDEX_ENTRY_TAB_STOP, XML_ETACTION_PROC_ATTRS, + OASIS_INDEX_ENTRY_TAB_STOP_ACTIONS ), + ENTRY0( STYLE, TAB_STOP, XML_ETACTION_TAB_STOP ), + ENTRY1( STYLE, BACKGROUND_IMAGE, XML_ETACTION_PROC_ATTRS, + OASIS_BACKGROUND_IMAGE_ACTIONS ), + ENTRY1( TEXT, LINENUMBERING_CONFIGURATION, XML_ETACTION_PROC_ATTRS, + OASIS_LINENUMBERING_ACTIONS ), + ENTRY1( STYLE, FOOTNOTE_SEP, XML_ETACTION_PROC_ATTRS, + OASIS_FOOTNOTE_SEP_ACTIONS ), + ENTRY1( STYLE, DROP_CAP, XML_ETACTION_PROC_ATTRS, OASIS_DROP_CAP_ACTIONS ), + ENTRY1( STYLE, COLUMNS, XML_ETACTION_PROC_ATTRS, OASIS_COLUMNS_ACTIONS ), + ENTRY1( STYLE, COLUMN, XML_ETACTION_PROC_ATTRS, OASIS_COLUMNS_ACTIONS ), + + // process *:style-name attributes + ENTRY1( STYLE, MAP, XML_ETACTION_PROC_ATTRS, OASIS_MAP_STYLE_REF_ACTIONS ), + ENTRY1( TEXT, SPAN, XML_ETACTION_PROC_ATTRS, OASIS_TEXT_STYLE_REF_ACTIONS ), + ENTRY1( TEXT, A, XML_ETACTION_PROC_ATTRS, OASIS_TEXT_STYLE_REF_ACTIONS ), + ENTRY1( TEXT, RUBY_TEXT, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_STYLE_REF_ACTIONS ), + ENTRY1( TEXT, TABLE_OF_CONTENT_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OASIS_PARA_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, ILLUSTRATION_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OASIS_PARA_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, TABLE_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OASIS_PARA_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, OBJECT_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OASIS_PARA_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, USER_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OASIS_PARA_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, ALPHABETICAL_INDEX_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OASIS_PARA_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, BIBLIOGRAPHY_ENTRY_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OASIS_PARA_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_SOURCE_STYLE, XML_ETACTION_PROC_ATTRS, + OASIS_PARA_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_TITLE_TEMPLATE, XML_ETACTION_PROC_ATTRS, + OASIS_PARA_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY3QNQ( TEXT, INDEX_ENTRY_CHAPTER, + XML_ETACTION_RENAME_ELEM_PROC_ATTRS_COND, + XML_NAMESPACE_TEXT, XML_INDEX_ENTRY_CHAPTER_NUMBER, + OASIS_TEXT_STYLE_REF_ACTIONS , + XML_NAMESPACE_TEXT, XML_TABLE_OF_CONTENT_ENTRY_TEMPLATE), + ENTRY1( TEXT, INDEX_ENTRY_TEXT, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_PAGE_NUMBER, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_SPAN, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_BIBLIOGRAPHY, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_LINK_START, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, INDEX_ENTRY_LINK_END, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_STYLE_REF_ACTIONS ), /* generated entry */ + ENTRY1( DRAW, PAGE, XML_ETACTION_PROC_ATTRS, + OASIS_MASTER_PAGE_REF_ACTIONS ), /* generated entry */ + // Conversion of attribute for and + // (#i40011#, #i40015#) + ENTRY1( TABLE, TABLE_ROW, XML_ETACTION_PROC_ATTRS, + OASIS_TABLE_STYLE_REF_ACTIONS ), + ENTRY1( TABLE, TABLE_COLUMN, XML_ETACTION_PROC_ATTRS, + OASIS_TABLE_STYLE_REF_ACTIONS ), + + // rename office:value-* to *:value-* + ENTRY1( TEXT, VARIABLE_DECL, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_VALUE_TYPE_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, VARIABLE_SET, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TEXT, VARIABLE_INPUT, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TEXT, USER_FIELD_DECL, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TEXT, EXPRESSION, XML_ETACTION_PROC_ATTRS, + OASIS_TEXT_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TEXT, USER_DEFINED, XML_ETACTION_PROC_ATTRS, + OASIS_DATETIME_ACTIONS ), // Add OASIS_TEXT_VALUE_TYPE_ACTIONS if attrs are added to text:user-defined + ENTRY1( TABLE, TABLE_CELL, XML_ETACTION_PROC_ATTRS, + OASIS_TABLE_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TABLE, COVERED_TABLE_CELL, XML_ETACTION_PROC_ATTRS, + OASIS_TABLE_VALUE_TYPE_ACTIONS), /* generated entry */ + ENTRY1( TABLE, CHANGE_TRACK_TABLE_CELL, XML_ETACTION_PROC_ATTRS, + OASIS_TABLE_VALUE_TYPE_ACTIONS), /* generated entry */ +// ENTRY1( FORM, PROPERTY, XML_ETACTION_PROC_ATTRS, +// OASIS_VALUE_TYPE_ACTIONS), /* TODO: generated entry */ +// ENTRY1( FORM, LIST_PROPERTY, XML_ETACTION_PROC_ATTRS, +// OASIS_VALUE_TYPE_ACTIONS), /* generated entry */ + + ENTRY1( OFFICE, ANNOTATION, XML_ETACTION_MOVE_ELEMS_TO_ATTRS, + OASIS_ANNOTATION_ACTIONS ), /* generated entry */ + ENTRY1( OFFICE, CHANGE_INFO, XML_ETACTION_MOVE_ELEMS_TO_ATTRS, + OASIS_CHANGE_INFO_ACTIONS ), /* generated entry */ + + ENTRY1( TEXT, DDE_CONNECTION_DECL, XML_ETACTION_PROC_ATTRS, + OASIS_DDE_CONNECTION_DECL_ACTIONS ), + + ENTRY0( FORM, TEXT, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, TEXTAREA, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, FIXED_TEXT, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, FILE, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, PASSWORD, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, FORMATTED_TEXT, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, BUTTON, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, IMAGE, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, CHECKBOX, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, RADIO, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, LISTBOX, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, COMBOBOX, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, FRAME, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, HIDDEN, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, IMAGE_FRAME, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, GRID, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, VALUE_RANGE, XML_ETACTION_FORM_CONTROL ), + ENTRY0( FORM, GENERIC_CONTROL, XML_ETACTION_FORM_CONTROL ), + ENTRY1( FORM, COLUMN, XML_ETACTION_PROC_ATTRS, + OASIS_FORM_COLUMN_ACTIONS ), + ENTRY1( FORM, PROPERTY, XML_ETACTION_FORM_PROPERTY, XML_PROPERTY ), + ENTRY1( FORM, LIST_PROPERTY, XML_ETACTION_FORM_PROPERTY, + XML_LIST_PROPERTY ), + ENTRY1( FORM, LIST_VALUE, XML_ETACTION_FORM_PROPERTY, XML_LIST_VALUE ), + + // process xlink:href + ENTRY1( META, TEMPLATE, XML_ETACTION_PROC_ATTRS, + OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( META, AUTO_RELOAD, XML_ETACTION_PROC_ATTRS, + OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, SECTION_SOURCE, XML_ETACTION_PROC_ATTRS, + OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, SCRIPT, XML_ETACTION_PROC_ATTRS, + OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TEXT, ALPHABETICAL_INDEX_AUTO_MARK_FILE, XML_ETACTION_PROC_ATTRS, + OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TABLE, TABLE_SOURCE, XML_ETACTION_PROC_ATTRS, + OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( TABLE, CELL_RANGE_SOURCE, XML_ETACTION_PROC_ATTRS, + OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( DRAW, A, XML_ETACTION_PROC_ATTRS, + OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( PRESENTATION, SOUND, XML_ETACTION_PROC_ATTRS, + OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY1( FORM, FORM, XML_ETACTION_PROC_ATTRS, + OASIS_FORM_ACTIONS ), /* generated entry */ +// ENTRY1( SVG, FONT_FACE_URI, XML_ETACTION_PROC_ATTRS, +// OASIS_XLINK_ACTIONS ), /* generated entry */ +// ENTRY1( SVG, DEFINITION_SRC, XML_ETACTION_PROC_ATTRS, +// OASIS_XLINK_ACTIONS ), /* generated entry */ + ENTRY2QN( CHART, SYMBOL_IMAGE, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_STYLE, XML_SYMBOL_IMAGE, + OASIS_BACKGROUND_IMAGE_ACTIONS ), +// OASIS_XLINK_ACTIONS ), /* generated entry */ +// events don't have real URIs +// ENTRY1( PRESENTATION, EVENT_LISTENER, XML_ETACTION_PROC_ATTRS, +// OASIS_XLINK_ACTIONS ), /* generated entry */ +// ENTRY1( SCRIPT, EVENT_LISTENER, XML_ETACTION_PROC_ATTRS, +// OASIS_XLINK_ACTIONS ), /* generated entry */ + + // add namespace prefix to name + ENTRY1( CONFIG, CONFIG_ITEM_SET, XML_ETACTION_PROC_ATTRS, + OASIS_CONFIG_ITEM_SET_ACTIONS ), + + // add namespace prefix to formula and condition + // text:condition + ENTRY1( TEXT, SECTION, XML_ETACTION_PROC_ATTRS, + OASIS_FORMULA_ACTIONS ), /* generated entry */ + // text:formula + ENTRY1( TEXT, SEQUENCE, XML_ETACTION_PROC_ATTRS, + OASIS_FORMULA_ACTIONS ), /* generated entry */ + // text:condition + ENTRY1( TEXT, DATABASE_NEXT, XML_ETACTION_PROC_ATTRS, + OASIS_FORMULA_ACTIONS ), /* generated entry */ + // text:condition + ENTRY2QN( TEXT, DATABASE_ROW_SELECT, XML_ETACTION_RENAME_ELEM_PROC_ATTRS, + XML_NAMESPACE_TEXT, XML_DATABASE_SELECT, + OASIS_FORMULA_ACTIONS ), /* generated entry */ + // text:condition + ENTRY1( TEXT, CONDITIONAL_TEXT, XML_ETACTION_PROC_ATTRS, + OASIS_FORMULA_ACTIONS ), /* generated entry */ + // text:condition + ENTRY1( TEXT, HIDDEN_TEXT, XML_ETACTION_PROC_ATTRS, + OASIS_FORMULA_ACTIONS ), /* generated entry */ + // text:condition + ENTRY1( TEXT, HIDDEN_PARAGRAPH, XML_ETACTION_PROC_ATTRS, + OASIS_FORMULA_ACTIONS ), /* generated entry */ + // text:formula + ENTRY1( TEXT, TABLE_FORMULA, XML_ETACTION_PROC_ATTRS, + OASIS_FORMULA_ACTIONS ), /* generated entry */ + + // process table::content-validation + ENTRY1( TABLE, CONTENT_VALIDATION, XML_ETACTION_PROC_ATTRS, + OASIS_CONTENT_VALIDATION_ACTIONS ), + + // rename to + ENTRY1Q( TABLE, DEPENDENCIES, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TABLE, XML_DEPENDENCES ), + ENTRY1Q( TABLE, DEPENDENCY, XML_ETACTION_RENAME_ELEM, + XML_NAMESPACE_TABLE, XML_DEPENDENCE ), + + // process table::conversion-mode + ENTRY1( TABLE, CONVERSION_MODE, XML_ETACTION_PROC_ATTRS, + OASIS_DDE_CONV_MODE_ACTIONS ), + + // process table::data-pilot-member + ENTRY1( TABLE, DATA_PILOT_MEMBER, XML_ETACTION_PROC_ATTRS, + OASIS_DATAPILOT_MEMBER_ACTIONS ), + + // process table::data-pilot-level + ENTRY1( TABLE, DATA_PILOT_LEVEL, XML_ETACTION_PROC_ATTRS, + OASIS_DATAPILOT_LEVEL_ACTIONS ), + + // process table::source-service + ENTRY1( TABLE, SOURCE_SERVICE, XML_ETACTION_PROC_ATTRS, + OASIS_SOURCE_SERVICE_ACTIONS ), + + // entries for date time change (#i36576#) + ENTRY1( TEXT, DATE, XML_ETACTION_PROC_ATTRS, OASIS_DATETIME_ACTIONS ), + ENTRY1( TEXT, CREATION_DATE, XML_ETACTION_PROC_ATTRS, + OASIS_DATETIME_ACTIONS ), + ENTRY1( TEXT, TIME, XML_ETACTION_PROC_ATTRS, OASIS_DATETIME_ACTIONS ), + ENTRY1( TEXT, CREATION_TIME, XML_ETACTION_PROC_ATTRS, + OASIS_DATETIME_ACTIONS ), + ENTRY1( TEXT, PRINT_TIME, XML_ETACTION_PROC_ATTRS, OASIS_DATETIME_ACTIONS ), + ENTRY1( TEXT, MODIFICATION_TIME, XML_ETACTION_PROC_ATTRS, + OASIS_DATETIME_ACTIONS ), + ENTRY1( TEXT, EDITING_DURATION, XML_ETACTION_PROC_ATTRS, + OASIS_DATETIME_ACTIONS ), + ENTRY1( FORM, TIME, XML_ETACTION_PROC_ATTRS, OASIS_DATETIME_ACTIONS ), + ENTRY1( PRESENTATION, SETTINGS, XML_ETACTION_PROC_ATTRS, + OASIS_DATETIME_ACTIONS ), + + // fix + ENTRY1( TEXT, ALPHABETICAL_INDEX_MARK, XML_ETACTION_PROC_ATTRS, + OASIS_ALPHABETICAL_INDEX_MARK_ACTIONS ), + ENTRY1( TEXT, ALPHABETICAL_INDEX_MARK_START, XML_ETACTION_PROC_ATTRS, + OASIS_ALPHABETICAL_INDEX_MARK_ACTIONS ), + + // fix id strings in old animation elements + ENTRY1( PRESENTATION, DIM, XML_ETACTION_PROC_ATTRS, OASIS_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, PLAY, XML_ETACTION_PROC_ATTRS, OASIS_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, SHOW_TEXT, XML_ETACTION_PROC_ATTRS, OASIS_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, SHOW_SHAPE, XML_ETACTION_PROC_ATTRS, OASIS_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, HIDE_TEXT, XML_ETACTION_PROC_ATTRS, OASIS_ANIMATION_ACTIONS ), + ENTRY1( PRESENTATION, HIDE_SHAPE, XML_ETACTION_PROC_ATTRS, OASIS_ANIMATION_ACTIONS ), + + ENTRY0( OFFICE, TOKEN_INVALID, XML_ETACTION_EOT ) +}; + +// XML_ETACTION_STYLE +XMLTransformerActionInit const aStyleActionTable[] = +{ + ENTRY0( STYLE, FAMILY, XML_ATACTION_STYLE_FAMILY ), + ENTRY1( STYLE, NAME, XML_ATACTION_DECODE_STYLE_NAME, + XML_FAMILY_TYPE_END ), + ENTRY1( STYLE, DISPLAY_NAME, XML_ATACTION_STYLE_DISPLAY_NAME, + XML_FAMILY_TYPE_END ), + ENTRY1( STYLE, PARENT_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_END ), + ENTRY1( STYLE, NEXT_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_END ), + ENTRY1( STYLE, LIST_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_LIST ), + ENTRY1( STYLE, MASTER_PAGE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_MASTER_PAGE ), + ENTRY0( STYLE, DEFAULT_OUTLINE_LEVEL, XML_ATACTION_REMOVE ), + ENTRY1( TEXT, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_TEXT ), // list level styles + ENTRY1( DRAW, NAME, XML_ATACTION_DECODE_STYLE_NAME, + XML_FAMILY_TYPE_END ), + ENTRY1( DRAW, DISPLAY_NAME, XML_ATACTION_STYLE_DISPLAY_NAME, + XML_FAMILY_TYPE_END ), + ENTRY0( DRAW, DISTANCE, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, DOTS1_LENGTH, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, DOTS2_LENGTH, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, WIDTH, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, HEIGHT, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, START, XML_ATACTION_NEG_PERCENT ), + ENTRY0( DRAW, END, XML_ATACTION_NEG_PERCENT ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OASIS, sal_uInt32(true) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_FRAME_ELEM_ACTIONS +XMLTransformerActionInit const aFrameActionTable[] = +{ + ENTRY0( DRAW, TEXT_BOX, XML_ETACTION_COPY ), + ENTRY0( DRAW, IMAGE, XML_ETACTION_COPY ), + ENTRY0( DRAW, OBJECT, XML_ETACTION_COPY ), + ENTRY0( DRAW, OBJECT_OLE, XML_ETACTION_COPY ), + ENTRY0( DRAW, APPLET, XML_ETACTION_COPY ), + ENTRY0( DRAW, PLUGIN, XML_ETACTION_COPY ), + ENTRY0( DRAW, FLOATING_FRAME, XML_ETACTION_COPY ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_EVENT_ELEM_ACTIONS +XMLTransformerActionInit const aEventActionTable[] = +{ + ENTRY0( XLINK, HREF, XML_ATACTION_HREF ), + ENTRY1( SCRIPT, LANGUAGE, XML_ATACTION_REMOVE_NAMESPACE_PREFIX, + XML_NAMESPACE_OOO ), + ENTRY0( SCRIPT, EVENT_NAME, XML_ATACTION_EVENT_NAME ), + ENTRY0( SCRIPT, MACRO_NAME, XML_ATACTION_MACRO_NAME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_EVENT_ELEM_ACTIONS +XMLTransformerActionInit const aDlgActionTable[] = +{ + ENTRY0( DLG, BORDER, XML_ATACTION_DLG_BORDER ) +}; + +// action table for OASIS_MASTER_PAGE_ACTIONS +XMLTransformerActionInit const aMasterPageActionTable[] = +{ + ENTRY1( STYLE, NAME, XML_ATACTION_DECODE_STYLE_NAME, + XML_FAMILY_TYPE_MASTER_PAGE ), + ENTRY1( STYLE, DISPLAY_NAME, XML_ATACTION_STYLE_DISPLAY_NAME, + XML_FAMILY_TYPE_MASTER_PAGE ), + ENTRY1( STYLE, NEXT_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_MASTER_PAGE ), + ENTRY1Q( STYLE, PAGE_LAYOUT_NAME, XML_ATACTION_RENAME, + XML_NAMESPACE_STYLE, XML_PAGE_MASTER_NAME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OASIS_TEXT_STYLE_REF_ACTIONS +XMLTransformerActionInit const aTextStyleRefActionTable[] = +{ + ENTRY1( TEXT, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_TEXT ), + ENTRY1( TEXT, VISITED_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_TEXT ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OASIS, sal_uInt32(false) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OASIS_PARA_STYLE_REF_ACTIONS +XMLTransformerActionInit const aParaStyleRefActionTable[] = +{ + ENTRY1( TEXT, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_PARAGRAPH ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OASIS_LIST_STYLE_REF_ACTIONS +XMLTransformerActionInit const aListStyleRefActionTable[] = +{ + ENTRY1( TEXT, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_LIST ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OASIS_MASTER_PAGE_REF_ACTIONS +XMLTransformerActionInit const aMasterPageRefActionTable[] = +{ + ENTRY1( DRAW, MASTER_PAGE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_MASTER_PAGE ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OASIS_MAP_STYLE_REF_ACTIONS +XMLTransformerActionInit const aMapStyleRefActionTable[] = +{ + ENTRY1( STYLE, APPLY_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_END ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OASIS_TABLE_STYLE_REF_ACTIONS (#i40011#, #i40015#) +XMLTransformerActionInit const aTableStyleRefActionTable[] = +{ + ENTRY1( TABLE, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_END ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +XMLTransformerActionInit const aFontFaceActionTable[] = +{ + ENTRY1Q( SVG, FONT_FAMILY, XML_ATACTION_RENAME, + XML_NAMESPACE_FO, XML_FONT_FAMILY ), + ENTRY1Q( STYLE, FONT_ADORNMENTS, XML_ATACTION_RENAME, + XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OASIS_PARA_ACTIONS +XMLTransformerActionInit const aParaActionTable[] = +{ + ENTRY1( TEXT, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_PARAGRAPH ), + ENTRY1( TEXT, COND_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_PARAGRAPH ), + ENTRY1Q( TEXT, OUTLINE_LEVEL, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_LEVEL ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// !!ATTENTION!! If you change something here, please also change +// aConnectorActionTable if appropriate +XMLTransformerActionInit const aShapeActionTable[] = +{ + ENTRY1( DRAW, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_GRAPHIC ), + ENTRY1( DRAW, TEXT_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_PARAGRAPH ), + ENTRY1( PRESENTATION, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_PRESENTATION ), + ENTRY0( SVG, X, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, Y, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, X1, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, Y1, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, X2, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, Y2, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, CX, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, CY, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, END_X, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, END_Y, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, R, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, RX, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, RY, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, WIDTH, XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS ), + ENTRY0( SVG, HEIGHT, XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS ), + ENTRY0( FO, MIN_WIDTH, XML_ATACTION_IN2INCH ), + ENTRY0( FO, MIN_HEIGHT, XML_ATACTION_IN2INCH ), + ENTRY0( FO, MAX_WIDTH, XML_ATACTION_IN2INCH ), + ENTRY0( FO, MAX_HEIGHT, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, CORNER_RADIUS, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, LINE_SKEW, XML_ATACTION_INS2INCHS ), + ENTRY0( DRAW, CAPTION_POINT_X, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, CAPTION_POINT_Y, XML_ATACTION_IN2INCH ), + ENTRY0( DR3D, DISTANCE, XML_ATACTION_IN2INCH ), + ENTRY0( DR3D, FOCAL_LENGTH, XML_ATACTION_IN2INCH ), + ENTRY1Q( DRAW, CONTROL, XML_ATACTION_RENAME, + XML_NAMESPACE_FORM, XML_ID ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OASIS, sal_uInt32(true) ), + + // needed by chart:legend. The legend needs also the draw actions. As + // there is no merge mechanism, all actions have to be in the same table + ENTRY2( CHART, LEGEND_POSITION, XML_ATACTION_RENAME_ATTRIBUTE, + RENAME_ENTRY( XML_START, XML_LEFT ), + RENAME_ENTRY( XML_END, XML_RIGHT )), + + ENTRY0( DRAW, ID, XML_ATACTION_DECODE_ID ), + + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_ANIMATION_ACTIONS +XMLTransformerActionInit const aAnimationActionTable[] = +{ + ENTRY0( DRAW, SHAPE_ID, XML_ATACTION_DECODE_ID ), + ENTRY0( PRESENTATION, DELAY, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( PRESENTATION, PAUSE, XML_ATACTION_RNG2ISO_DATETIME ), + + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OOO_CONNECTOR_ACTIONS +XMLTransformerActionInit const aConnectorActionTable[] = +{ + ENTRY1( DRAW, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_GRAPHIC ), + ENTRY1( DRAW, TEXT_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_PARAGRAPH ), + ENTRY1( PRESENTATION, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_PRESENTATION ), + ENTRY0( SVG, X1, XML_ATACTION_IN2TWIPS ), + ENTRY0( SVG, Y1, XML_ATACTION_IN2TWIPS ), + ENTRY0( SVG, X2, XML_ATACTION_IN2TWIPS ), + ENTRY0( SVG, Y2, XML_ATACTION_IN2TWIPS ), + ENTRY0( DRAW, END_X, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, END_Y, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, WIDTH, XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS ), + ENTRY0( SVG, HEIGHT, XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS ), + ENTRY0( FO, MIN_WIDTH, XML_ATACTION_IN2INCH ), + ENTRY0( FO, MIN_HEIGHT, XML_ATACTION_IN2INCH ), + ENTRY0( FO, MAX_WIDTH, XML_ATACTION_IN2INCH ), + ENTRY0( FO, MAX_HEIGHT, XML_ATACTION_IN2INCH ), + ENTRY0( DRAW, LINE_SKEW, XML_ATACTION_INS2INCHS ), + ENTRY1Q( DRAW, CONTROL, XML_ATACTION_RENAME, + XML_NAMESPACE_FORM, XML_ID ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OASIS, sal_uInt32(true) ), + ENTRY0( DRAW, START_SHAPE, XML_ATACTION_DECODE_ID ), + ENTRY0( DRAW, END_SHAPE, XML_ATACTION_DECODE_ID ), + + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_INDEX_ENTRY_TAB_STOP_ACTIONS +XMLTransformerActionInit const aIndexEntryTabStopActionTable[] = +{ + ENTRY0( STYLE, POSITION, XML_ATACTION_IN2INCH ), + ENTRY1( TEXT, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_TEXT ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_TAB_STOP_ACTIONS +XMLTransformerActionInit const aTabStopActionTable[] = +{ + ENTRY0( STYLE, POSITION, XML_ATACTION_IN2INCH ), + ENTRY1Q( STYLE, LEADER_TEXT, XML_ATACTION_RENAME, + XML_NAMESPACE_STYLE, XML_LEADER_CHAR ), + ENTRY0( STYLE, LEADER_STYLE, XML_ATACTION_REMOVE ), + ENTRY0( STYLE, LEADER_TYPE, XML_ATACTION_REMOVE ), + ENTRY0( STYLE, LEADER_WIDTH, XML_ATACTION_REMOVE ), + ENTRY0( STYLE, LEADER_COLOR, XML_ATACTION_REMOVE ), + ENTRY0( STYLE, LEADER_TEXT_STYLE, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_LINENUMBERING_ACTIONS +XMLTransformerActionInit const aLineNumberingActionTable[] = +{ + ENTRY0( TEXT, OFFSET, XML_ATACTION_IN2INCH ), + ENTRY1( TEXT, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_TEXT ), + ENTRY1Q( TEXT, COUNT_IN_TEXT_BOXES , XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_COUNT_IN_FLOATING_FRAMES), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +XMLTransformerActionInit const aFootnoteSepActionTable[] = +{ + ENTRY0( STYLE, WIDTH, XML_ATACTION_IN2INCH ), + ENTRY0( STYLE, DISTANCE_BEFORE_SEP, XML_ATACTION_IN2INCH ), + ENTRY0( STYLE, DISTANCE_AFTER_SEP, XML_ATACTION_IN2INCH ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_NOTES_ACTIONS (processed by special context) +XMLTransformerActionInit const aNotesActionTable[] = +{ + ENTRY0( TEXT, NOTE_CLASS, XML_ATACTION_STYLE_FAMILY ), + ENTRY1( TEXT, CITATION_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_TEXT ), + ENTRY1( TEXT, CITATION_BODY_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_TEXT ), + ENTRY1( TEXT, DEFAULT_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_PARAGRAPH ), + ENTRY1( TEXT, MASTER_PAGE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_MASTER_PAGE ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_DROP_CAP_ACTIONS +XMLTransformerActionInit const aDropCapActionTable[] = +{ + ENTRY0( STYLE, DISTANCE, XML_ATACTION_IN2INCH ), + ENTRY1( STYLE, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_TEXT ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +XMLTransformerActionInit const aColumnsActionTable[] = +{ + ENTRY0( STYLE, COLUMN_GAP, XML_ATACTION_IN2INCH ), + ENTRY0( STYLE, SPACE_BEFORE, XML_ATACTION_REMOVE ), + ENTRY0( STYLE, SPACE_AFTER, XML_ATACTION_REMOVE ), + ENTRY1Q( FO, START_INDENT, XML_ATACTION_RENAME_IN2INCH, + XML_NAMESPACE_FO, XML_MARGIN_LEFT ), + ENTRY1Q( FO, END_INDENT, XML_ATACTION_RENAME_IN2INCH, + XML_NAMESPACE_FO, XML_MARGIN_RIGHT ), + ENTRY0( STYLE, WIDTH, XML_ATACTION_IN2INCH ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_TEXT_VALUE_TYPE_ACTIONS +XMLTransformerActionInit const aTextValueTypeActionTable[] = +{ + ENTRY1Q( OFFICE, VALUE_TYPE, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_VALUE_TYPE ), + ENTRY1Q( OFFICE, VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_VALUE ), + ENTRY1Q( OFFICE, CURRENCY, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_CURRENCY ), + ENTRY1Q( OFFICE, DATE_VALUE, XML_ATACTION_RENAME_RNG2ISO_DATETIME, + XML_NAMESPACE_TEXT, XML_DATE_VALUE ), + ENTRY1Q( OFFICE, TIME_VALUE, XML_ATACTION_RENAME_RNG2ISO_DATETIME, + XML_NAMESPACE_TEXT, XML_TIME_VALUE ), + ENTRY1Q( OFFICE, BOOLEAN_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_BOOLEAN_VALUE ), + ENTRY1Q( OFFICE, STRING_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_STRING_VALUE ), + ENTRY0( TEXT, FORMULA, XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_TABLE_VALUE_TYPE_ACTIONS +XMLTransformerActionInit const aTableValueTypeActionTable[] = +{ + ENTRY1Q( OFFICE, VALUE_TYPE, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_VALUE_TYPE ), + ENTRY1Q( OFFICE, VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_VALUE ), + ENTRY1Q( OFFICE, CURRENCY, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_CURRENCY ), + ENTRY1Q( OFFICE, DATE_VALUE, XML_ATACTION_RENAME_RNG2ISO_DATETIME, + XML_NAMESPACE_TABLE, XML_DATE_VALUE ), + ENTRY1Q( OFFICE, TIME_VALUE, XML_ATACTION_RENAME_RNG2ISO_DATETIME, + XML_NAMESPACE_TABLE, XML_TIME_VALUE ), + ENTRY1Q( OFFICE, BOOLEAN_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_BOOLEAN_VALUE ), + ENTRY1Q( OFFICE, STRING_VALUE, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_STRING_VALUE ), + ENTRY1( TABLE, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_TABLE_CELL ), + ENTRY0( TABLE, FORMULA, XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX ), + ENTRY1Q( TABLE, CONTENT_VALIDATION_NAME, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_VALIDATION_NAME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// action table for OASIS_ANNOTATION_ACTIONS +XMLTransformerActionInit const aAnnotationActionTable[] = +{ + ENTRY1Q( DC, CREATOR, XML_ETACTION_MOVE_TO_ATTR, + XML_NAMESPACE_OFFICE, XML_AUTHOR ), + ENTRY1Q( DC, DATE, XML_ETACTION_MOVE_TO_ATTR_RNG2ISO_DATETIME, + XML_NAMESPACE_OFFICE, XML_CREATE_DATE ), + ENTRY1Q( META, DATE_STRING, XML_ETACTION_MOVE_TO_ATTR, + XML_NAMESPACE_OFFICE, XML_CREATE_DATE_STRING ), + ENTRY0( TEXT, P, XML_ETACTION_EXTRACT_CHARACTERS ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ETACTION_EOT ) +}; + +// action table for OASIS_CHANGE_INFO_ACTIONS +XMLTransformerActionInit const aChangeInfoActionTable[] = +{ + ENTRY1Q( DC, CREATOR, XML_ETACTION_MOVE_TO_ATTR, + XML_NAMESPACE_OFFICE, XML_CHG_AUTHOR ), + ENTRY1Q( DC, DATE, XML_ETACTION_MOVE_TO_ATTR_RNG2ISO_DATETIME, + XML_NAMESPACE_OFFICE, XML_CHG_DATE_TIME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ETACTION_EOT ) +}; + +// OASIS_BACKGROUND_IMAGE_ACTIONS +XMLTransformerActionInit const aBackgroundImageActionTable[] = +{ + ENTRY1Q( DRAW, OPACITY, XML_ATACTION_RENAME_NEG_PERCENT, + XML_NAMESPACE_DRAW, XML_TRANSPARENCY ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OASIS, sal_uInt32(true) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_DDE_CONNECTION_DECL +XMLTransformerActionInit const aDDEConnectionDeclActionTable[] = +{ + ENTRY1Q( OFFICE, NAME, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_NAME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_FORM_CONTROL_ACTIONS +XMLTransformerActionInit const aFormControlActionTable[] = +{ + ENTRY0( FORM, NAME, XML_ATACTION_MOVE_TO_ELEM ), + ENTRY2QN( FORM, CONTROL_IMPLEMENTATION, + XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX, + XML_NAMESPACE_FORM, XML_SERVICE_NAME, + XML_NAMESPACE_OOO ), + ENTRY0( FORM, ID, XML_ATACTION_MOVE_TO_ELEM ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OASIS, sal_uInt32(false) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_FORM_COLUMN_ACTIONS +XMLTransformerActionInit const aFormColumnActionTable[] = +{ + ENTRY1Q( FORM, TEXT_STYLE_NAME, XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF, + XML_NAMESPACE_FORM, XML_COLUMN_STYLE_NAME ), + ENTRY2QN( FORM, CONTROL_IMPLEMENTATION, + XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX, + XML_NAMESPACE_FORM, XML_SERVICE_NAME, + XML_NAMESPACE_OOO ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_FORM_PROP_ACTIONS +XMLTransformerActionInit const aFormPropActionTable[] = +{ + ENTRY1Q( OFFICE, VALUE_TYPE, XML_ATACTION_RENAME, + XML_NAMESPACE_FORM, XML_PROPERTY_TYPE ), + ENTRY0( OFFICE, VALUE, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, STRING_VALUE, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, BOOLEAN_VALUE, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, DATE_VALUE, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, TIME_VALUE, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, CURRENCY, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_XLINK_ACTIONS +XMLTransformerActionInit const aXLinkActionTable[] = +{ + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OASIS, sal_uInt32(false) ), + ENTRY0( TABLE, REFRESH_DELAY, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_CONFIG_ITEM_SET_ACTIONS +XMLTransformerActionInit const aConfigItemSetActionTable[] = +{ + ENTRY1( CONFIG, NAME, XML_ATACTION_REMOVE_NAMESPACE_PREFIX, + XML_NAMESPACE_OOO ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_FORMULA_ACTIONS +XMLTransformerActionInit const aFormulaActionTable[] = +{ + ENTRY0( TEXT, CONDITION, XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX ), + ENTRY0( TEXT, FORMULA, XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX ), + ENTRY0( TABLE, CONDITION, XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX ), + ENTRY0( TABLE, FORMULA, XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_CONTENT_VALIDATION_ACTIONS +XMLTransformerActionInit const aContentValidationActionTable[] = +{ + ENTRY0( TABLE, CONDITION, XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX ), + ENTRY0( TABLE, DISPLAY_LIST, XML_ATACTION_REMOVE ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_DDE_CONV_MODE_ACTIONS +XMLTransformerActionInit const aDDEConvModeActionTable[] = +{ + ENTRY1Q( TABLE, KEEP_TEXT, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_LET_TEXT ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_DATAPILOT_MEMBER_ACTIONS +XMLTransformerActionInit const aDataPilotMemberActionTable[] = +{ + ENTRY1Q( TABLE, SHOW_DETAILS, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_DISPLAY_DETAILS ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_DATAPILOT_LEVEL_ACTIONS +XMLTransformerActionInit const aDataPilotLevelActionTable[] = +{ + ENTRY1Q( TABLE, SHOW_EMPTY, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_DISPLAY_EMPTY ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_SOURCE_SERVICE_ACTIONS +XMLTransformerActionInit const aSourceServiceActionTable[] = +{ + ENTRY1Q( TABLE, USER_NAME, XML_ATACTION_RENAME, + XML_NAMESPACE_TABLE, XML_USERNAME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_CHART_ACTIONS +XMLTransformerActionInit const aChartActionTable[] = +{ + ENTRY0( CHART, CLASS, XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX ), + ENTRY1( DRAW, STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_GRAPHIC ), + ENTRY0( SVG, WIDTH, XML_ATACTION_IN2INCH ), + ENTRY0( SVG, HEIGHT, XML_ATACTION_IN2INCH ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_FORM_ACTIONS +XMLTransformerActionInit const aFormActionTable[] = +{ + ENTRY2QN( FORM, CONTROL_IMPLEMENTATION, + XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX, + XML_NAMESPACE_FORM, XML_SERVICE_NAME, + XML_NAMESPACE_OOO ), + ENTRY1( XLINK, HREF, XML_ATACTION_URI_OASIS, sal_uInt32(false) ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_ALPHABETICAL_INDEX_MARK_ACTIONS +XMLTransformerActionInit const aAlphabeticalIndexMarkActionTable[] = +{ + ENTRY1Q( TEXT, MAIN_ENTRY, XML_ATACTION_RENAME, + XML_NAMESPACE_TEXT, XML_MAIN_ETRY ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_DRAW_AREA_POLYGON_ACTIONS (to be added to OASIS_SHAPE_ACTIONS) +XMLTransformerActionInit const aDrawAreaPolygonActionTable[] = +{ + ENTRY1Q( DRAW, POINTS, XML_ATACTION_RENAME, + XML_NAMESPACE_SVG, XML_POINTS ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_SCRIPT_ACTIONS +XMLTransformerActionInit const aScriptActionTable[] = +{ + ENTRY1( SCRIPT, LANGUAGE, XML_ATACTION_REMOVE_NAMESPACE_PREFIX, XML_NAMESPACE_OOO ), + ENTRY1Q( OOO, NAME, XML_ATACTION_RENAME, XML_NAMESPACE_SCRIPT, XML_NAME ), + ENTRY1Q( OOO, READONLY, XML_ATACTION_RENAME, XML_NAMESPACE_SCRIPT, XML_READONLY ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +// OASIS_DATETIME_ACTIONS +XMLTransformerActionInit const aDateTimeActionTable[] = +{ + ENTRY0( TEXT, DATE_VALUE, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( TEXT, TIME_VALUE, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( TEXT, DATE_ADJUST, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( TEXT, TIME_ADJUST, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( TEXT, DURATION, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( OFFICE, DATE_VALUE, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( OFFICE, TIME_VALUE, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( FORM, VALUE, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( FORM, CURRENT_VALUE, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( TABLE, DATE_START, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( TABLE, DATE_END, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( TABLE, REFRESH_DELAY, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( PRESENTATION, DELAY, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( PRESENTATION, PAUSE, XML_ATACTION_RNG2ISO_DATETIME ), + ENTRY0( OFFICE, TOKEN_INVALID, XML_ATACTION_EOT ) +}; + +XMLTokenEnum const aTokenMap[] = +{ + XML_NONE, XML_SOLID, XML_DOTTED, XML_DASH, XML_LONG_DASH, XML_DOT_DASH, + XML_DOT_DOT_DASH, XML_WAVE, XML_SMALL_WAVE, XML_TOKEN_END +}; + +namespace { + +class XMLTableTransformerContext_Impl : public XMLTransformerContext +{ + OUString m_aElemQName; + +public: + XMLTableTransformerContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +} + +XMLTableTransformerContext_Impl::XMLTableTransformerContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rQName ) +{ +} + +void XMLTableTransformerContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + Reference< XAttributeList > xAttrList( rAttrList ); + + rtl::Reference pMutableAttrList; + + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + if( XML_NAMESPACE_TABLE == nPrefix ) + { + if ( IsXMLToken( aLocalName, XML_IS_SUB_TABLE ) ) + { + const OUString& rValue = xAttrList->getValueByIndex( i ); + if( IsXMLToken( rValue, XML_TRUE ) ) + { + m_aElemQName = GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_TABLE, + ::xmloff::token::GetXMLToken( XML_SUB_TABLE ) ); + if ( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + pMutableAttrList->RemoveAttributeByIndex( i ); + } + // #i50521# - no break here for safety reason. + } + // Convert attribute table:style-name for (#i40011#, #i40015#) + else if ( IsXMLToken( aLocalName, XML_STYLE_NAME ) ) + { + const OUString& rValue = xAttrList->getValueByIndex( i ); + OUString aAttrValue( rValue ); + if( XMLTransformerBase::DecodeStyleName(aAttrValue) ) + { + if ( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + } + else if( IsXMLToken( aLocalName, XML_PRINT ) ) + { + if ( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + pMutableAttrList->RemoveAttributeByIndex( i ); + } + } + } + + GetTransformer().GetDocHandler()->startElement( m_aElemQName, xAttrList ); +} + +void XMLTableTransformerContext_Impl::EndElement() +{ + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +namespace { + +class XMLBodyOASISTransformerContext_Impl : public XMLTransformerContext +{ + bool m_bFirstChild; + +public: + XMLBodyOASISTransformerContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +} + +XMLBodyOASISTransformerContext_Impl::XMLBodyOASISTransformerContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ), + m_bFirstChild( false ) +{ +} + +void XMLBodyOASISTransformerContext_Impl::StartElement( + const Reference< XAttributeList >& ) +{ +} + +rtl::Reference XMLBodyOASISTransformerContext_Impl::CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) +{ + if (!m_bFirstChild) + { + m_bFirstChild = true; + XMLTransformerContext::StartElement(xAttrList); + } + + return XMLTransformerContext::CreateChildContext(nPrefix, rLocalName, rQName, xAttrList); +} + +void XMLBodyOASISTransformerContext_Impl::EndElement() +{ + if (!m_bFirstChild) + XMLTransformerContext::StartElement(Reference< XAttributeList >()); + + XMLTransformerContext::EndElement(); +} + +namespace { + +class XMLTabStopOASISTContext_Impl : public XMLPersElemContentTContext +{ +public: + XMLTabStopOASISTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +} + +XMLTabStopOASISTContext_Impl::XMLTabStopOASISTContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLPersElemContentTContext( rImp, rQName ) +{ +} + +void XMLTabStopOASISTContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OASIS_TAB_STOP_ACTIONS ); + SAL_WARN_IF( nullptr == pActions, "xmloff.transform", "got no actions" ); + + sal_Unicode cStyleLeaderChar = 0; + sal_Int16 nLeaderText = -1; + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_REMOVE: + if( IsXMLToken( aLocalName, XML_LEADER_STYLE ) ) + { + if( IsXMLToken( rAttrValue, XML_NONE ) ) + cStyleLeaderChar = ' '; + else if( IsXMLToken( rAttrValue, XML_DOTTED ) ) + cStyleLeaderChar = '.'; + else + cStyleLeaderChar = 0; + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + } + break; + case XML_ATACTION_RENAME: + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + pMutableAttrList->RenameAttributeByIndex( i, + aNewAttrQName ); + } + if( IsXMLToken( aLocalName, XML_LEADER_TEXT ) ) + { + if( rAttrValue.getLength() > 1 ) + { + OUString aAttrValue( rAttrValue.copy( 0, 1 ) ); + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + nLeaderText = i; + } + } + break; + case XML_ATACTION_IN2INCH: + { + OUString aAttrValue( rAttrValue ); + if( XMLTransformerBase::ReplaceSingleInWithInch( + aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + default: + SAL_WARN( "xmloff.transform", "unknown action" ); + break; + } + } + } + + if( cStyleLeaderChar && ' ' != cStyleLeaderChar ) + { + if( nLeaderText != -1 ) + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + ::xmloff::token::GetXMLToken( XML_LEADER_CHAR ) ) ); + pMutableAttrList->AddAttribute( aNewAttrQName, + OUString( cStyleLeaderChar ) ); + } + } + else + { + if( nLeaderText != -1 ) + pMutableAttrList->RemoveAttributeByIndex( nLeaderText ); + } + + XMLPersElemContentTContext::StartElement( xAttrList ); +} + +namespace { + +class XMLConfigItemTContext_Impl : public XMLTransformerContext +{ + OUString m_aContent; + bool m_bIsRedlineProtectionKey; + bool m_bIsCursorX; + bool m_bIsCursorY; + +public: + XMLConfigItemTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + + virtual void Characters( const OUString& rChars ) override; +}; + +} + +XMLConfigItemTContext_Impl::XMLConfigItemTContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ), + m_bIsRedlineProtectionKey( false ), + m_bIsCursorX( false ), + m_bIsCursorY( false ) +{ +} + +void XMLConfigItemTContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = rAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + if( XML_NAMESPACE_CONFIG == nPrefix ) + { + if ( IsXMLToken( aLocalName, XML_NAME ) ) + { + const OUString& rValue = rAttrList->getValueByIndex( i ); + if( rValue == "RedlineProtectionKey" ) + m_bIsRedlineProtectionKey = true; + else if( rValue == "CursorPositionX" ) + m_bIsCursorX = true; + else if( rValue == "CursorPositionY" ) + m_bIsCursorY = true; + + break; + } + } + } + + XMLTransformerContext::StartElement( rAttrList ); +} + +void XMLConfigItemTContext_Impl::Characters( const OUString& rChars ) +{ + OUString sChars(rChars); + if (m_bIsRedlineProtectionKey) + m_aContent += rChars; + else if (m_bIsCursorX || m_bIsCursorY) + { + sal_Int32 nPos = rChars.toInt32(); + if (m_bIsCursorX && nPos > 255) + nPos = 255; + else if (m_bIsCursorY && nPos > 31999) + nPos = 31999; + + sChars = OUString::number(nPos); + } + + XMLTransformerContext::Characters( sChars ); +} + +void XMLConfigItemTContext_Impl::EndElement() +{ + + if( m_bIsRedlineProtectionKey ) + { + const Reference< XPropertySet > rPropSet = + GetTransformer().GetPropertySet(); + if( rPropSet.is() ) + { + OUString aPropName("RedlineProtectionKey"); + Reference< XPropertySetInfo > xPropSetInfo( + rPropSet->getPropertySetInfo() ); + if( xPropSetInfo.is() && + xPropSetInfo->hasPropertyByName( aPropName ) ) + { + Sequence < sal_Int8 > aKey; + ::comphelper::Base64::decode( aKey, m_aContent ); + rPropSet->setPropertyValue( aPropName, Any( aKey ) ); + } + } + } + XMLTransformerContext::EndElement(); +} + +namespace { + +class XMLTrackedChangesOASISTContext_Impl : public XMLTransformerContext +{ + OUString const m_aAttrQName; + +public: + + XMLTrackedChangesOASISTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + XMLTokenEnum eToken ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +} + +XMLTrackedChangesOASISTContext_Impl::XMLTrackedChangesOASISTContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + XMLTokenEnum eToken ) : + XMLTransformerContext( rImp, rQName ), + m_aAttrQName( rImp.GetNamespaceMap().GetQNameByKey( nPrefix, + GetXMLToken(eToken)) ) +{ +} + +void XMLTrackedChangesOASISTContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + Reference< XAttributeList > xAttrList( rAttrList ); + const Reference< XPropertySet > rPropSet = + GetTransformer().GetPropertySet(); + if( rPropSet.is() ) + { + OUString aPropName("RedlineProtectionKey"); + Reference< XPropertySetInfo > xPropSetInfo( + rPropSet->getPropertySetInfo() ); + if( xPropSetInfo.is() && + xPropSetInfo->hasPropertyByName( aPropName ) ) + { + Any aAny = rPropSet->getPropertyValue( aPropName); + Sequence < sal_Int8 > aKey; + aAny >>= aKey; + if( aKey.hasElements() ) + { + OUStringBuffer aBuffer; + ::comphelper::Base64::encode( aBuffer, aKey ); + rtl::Reference pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + pMutableAttrList->AddAttribute( m_aAttrQName, + aBuffer.makeStringAndClear() ); + } + } + } + XMLTransformerContext::StartElement( xAttrList ); +} + +XMLTransformerContext *Oasis2OOoTransformer::CreateUserDefinedContext( + const TransformerAction_Impl& rAction, + const OUString& rQName, + bool bPersistent ) +{ + switch( rAction.m_nActionType ) + { + case XML_ETACTION_META: + return new XMLMetaTransformerContext( *this, rQName ); + case XML_ETACTION_DOCUMENT: + return new XMLDocumentTransformerContext( *this, rQName ); + case XML_ETACTION_BODY: + return new XMLBodyOASISTransformerContext_Impl( *this, rQName ); + case XML_ETACTION_NOTES: + return new XMLNotesTransformerContext( *this, rQName, + static_cast< XMLTokenEnum>( rAction.m_nParam1 ), bPersistent ); + case XML_ETACTION_TABLE: + return new XMLTableTransformerContext_Impl( *this, rQName ); + case XML_ETACTION_STYLE: + return new XMLStyleOASISTContext( *this, rQName, bPersistent ); + case XML_ETACTION_STYLE_RENAME: + return new XMLStyleOASISTContext( *this, rQName, + rAction.GetQNamePrefixFromParam1(), + rAction.GetQNameTokenFromParam1(), bPersistent ); + case XML_ETACTION_FRAME: + return new XMLFrameOASISTransformerContext( *this, rQName ); + case XML_ETACTION_EVENT: + return new XMLEventOASISTransformerContext( *this, rQName ); + case XML_ETACTION_DLG: + return new XMLDlgOASISTransformerContext( *this, rQName ); + case XML_ETACTION_TAB_STOP: + return new XMLTabStopOASISTContext_Impl( *this, rQName ); + case XML_ETACTION_FORM_CONTROL: + { + const XMLTransformerContext *pCurrent = GetCurrentContext(); + return new XMLControlOASISTransformerContext( *this, rQName, + pCurrent && pCurrent->HasQName( XML_NAMESPACE_FORM, + XML_FORM ) ); + } + case XML_ETACTION_FORM_PROPERTY: + return new XMLFormPropOASISTransformerContext( *this, rQName, + static_cast< XMLTokenEnum >( rAction.m_nParam1 ) ); + case XML_ETACTION_CHART: + return new XMLChartOASISTransformerContext( *this, rQName ); + case XML_ETACTION_CONFIG_ITEM: + return new XMLConfigItemTContext_Impl( *this, rQName ); + case XML_ETACTION_TRACKED_CHANGES: + return new XMLTrackedChangesOASISTContext_Impl( *this, rQName, + rAction.GetQNamePrefixFromParam1(), + rAction.GetQNameTokenFromParam1() ); + case XML_ETACTION_CHART_PLOT_AREA: + return new XMLChartPlotAreaOASISTContext( *this, rQName ); + default: + SAL_WARN( "xmloff.transform", "no user defined context found!" ); + break; + } + + // default is copying + return new XMLTransformerContext( *this, rQName ); +} + +XMLTransformerActions *Oasis2OOoTransformer::GetUserDefinedActions( + sal_uInt16 n ) +{ + XMLTransformerActions *pActions = nullptr; + if( n < MAX_OASIS_ACTIONS ) + { + if( !m_aActions[n] ) + { + if( nAdd( aDrawAreaPolygonActionTable ); + break; + case OASIS_SCRIPT_ACTIONS: + m_aActions[OASIS_SCRIPT_ACTIONS].reset( + new XMLTransformerActions( aScriptActionTable ) ); + break; + case OASIS_DATETIME_ACTIONS: + m_aActions[OASIS_DATETIME_ACTIONS].reset( + new XMLTransformerActions( aDateTimeActionTable ) ); + break; + // Bugdoc with table won't load correctly (#i40011#, #i40015#) + case OASIS_TABLE_STYLE_REF_ACTIONS: + m_aActions[OASIS_TABLE_STYLE_REF_ACTIONS].reset( + new XMLTransformerActions( aTableStyleRefActionTable ) ); + break; + case OASIS_ANIMATION_ACTIONS: + m_aActions[OASIS_ANIMATION_ACTIONS].reset( + new XMLTransformerActions( aAnimationActionTable ) ); + break; + } + } + pActions = m_aActions[n].get(); + } + + return pActions; +} + +OUString Oasis2OOoTransformer::GetEventName( const OUString& rName, + bool bForm ) +{ + if( bForm && !m_pFormEventMap ) + m_pFormEventMap = + XMLEventOASISTransformerContext::CreateFormEventMap(); + if( !m_pEventMap ) + m_pEventMap = XMLEventOASISTransformerContext::CreateEventMap(); + + OUString aMacroName; + sal_uInt16 nPrefix = + GetNamespaceMap().GetKeyByAttrName( rName, &aMacroName ); + return XMLEventOASISTransformerContext::GetEventName( + nPrefix, aMacroName, *m_pEventMap, + bForm ? m_pFormEventMap : nullptr ); +} + +Oasis2OOoTransformer::Oasis2OOoTransformer() noexcept : + XMLTransformerBase( aActionTable, aTokenMap ), + m_pEventMap( nullptr ), + m_pFormEventMap( nullptr ) +{ + GetNamespaceMap().Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE_OOO), XML_NAMESPACE_OFFICE ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_META), GetXMLToken(XML_N_META), XML_NAMESPACE_META ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_META), GetXMLToken(XML_N_META_OOO), XML_NAMESPACE_META ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE_OOO), XML_NAMESPACE_STYLE ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_NUMBER), GetXMLToken(XML_N_NUMBER), XML_NAMESPACE_NUMBER ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_NUMBER), GetXMLToken(XML_N_NUMBER_OOO), XML_NAMESPACE_NUMBER ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_CONFIG), GetXMLToken(XML_N_CONFIG), XML_NAMESPACE_CONFIG ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_CONFIG), GetXMLToken(XML_N_CONFIG_OOO), XML_NAMESPACE_CONFIG ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_TEXT), GetXMLToken(XML_N_TEXT), XML_NAMESPACE_TEXT ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_TEXT), GetXMLToken(XML_N_TEXT_OOO), XML_NAMESPACE_TEXT ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_TABLE), GetXMLToken(XML_N_TABLE), XML_NAMESPACE_TABLE ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_TABLE), GetXMLToken(XML_N_TABLE_OOO), XML_NAMESPACE_TABLE ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_DRAW), GetXMLToken(XML_N_DRAW), XML_NAMESPACE_DRAW ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_DRAW), GetXMLToken(XML_N_DRAW_OOO), XML_NAMESPACE_DRAW ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_DR3D), GetXMLToken(XML_N_DR3D), XML_NAMESPACE_DR3D ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_DR3D), GetXMLToken(XML_N_DR3D_OOO), XML_NAMESPACE_DR3D ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_PRESENTATION), GetXMLToken(XML_N_PRESENTATION), XML_NAMESPACE_PRESENTATION ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_PRESENTATION), GetXMLToken(XML_N_PRESENTATION_OOO), XML_NAMESPACE_PRESENTATION ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_CHART), GetXMLToken(XML_N_CHART), XML_NAMESPACE_CHART ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_CHART), GetXMLToken(XML_N_CHART_OOO), XML_NAMESPACE_CHART ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_FORM), GetXMLToken(XML_N_FORM), XML_NAMESPACE_FORM ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_FORM), GetXMLToken(XML_N_FORM_OOO), XML_NAMESPACE_FORM ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_SCRIPT), GetXMLToken(XML_N_SCRIPT), XML_NAMESPACE_SCRIPT ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_SCRIPT), GetXMLToken(XML_N_SCRIPT_OOO), XML_NAMESPACE_SCRIPT ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_DLG), GetXMLToken(XML_N_DLG), XML_NAMESPACE_DLG ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_DLG), GetXMLToken(XML_N_DLG), XML_NAMESPACE_DLG ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_FO), GetXMLToken(XML_N_FO_COMPAT), XML_NAMESPACE_FO ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_FO), GetXMLToken(XML_N_FO), XML_NAMESPACE_FO ); + + GetNamespaceMap().Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG_COMPAT), XML_NAMESPACE_SVG ); + GetReplaceNamespaceMap().Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG), XML_NAMESPACE_SVG ); + + for(auto & rp : m_aActions) + rp.reset(); +} + +Oasis2OOoTransformer::~Oasis2OOoTransformer() noexcept +{ + for(auto & rp : m_aActions) + rp.reset(); + XMLEventOASISTransformerContext::FlushEventMap( m_pEventMap ); + XMLEventOASISTransformerContext::FlushEventMap( m_pFormEventMap ); +} + +const css::uno::Sequence& Oasis2OOoTransformer::getUnoTunnelId() noexcept +{ + static const class comphelper::UnoIdInit theOasis2OOoTransformerUnoTunnelId; + return theOasis2OOoTransformerUnoTunnelId.getSeq(); +} + +// XUnoTunnel +sal_Int64 SAL_CALL Oasis2OOoTransformer::getSomething( const Sequence< sal_Int8 >& rId ) +{ + return comphelper::getSomethingImpl(rId, this); +} + +// XServiceInfo +OUString SAL_CALL Oasis2OOoTransformer::getImplementationName() +{ + return "com.sun.star.comp.Oasis2OOoTransformer"; +} + +sal_Bool SAL_CALL Oasis2OOoTransformer::supportsService( const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +Sequence< OUString > SAL_CALL Oasis2OOoTransformer::getSupportedServiceNames( ) +{ + return { }; +} + +// Service registration + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +xmloff_Oasis2OOoTransformer_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + SAL_INFO("xmloff.transform", "Creating Oasis2OOoTransformer"); + return cppu::acquire(new Oasis2OOoTransformer); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/Oasis2OOo.hxx b/xmloff/source/transform/Oasis2OOo.hxx new file mode 100644 index 000000000..fe3db7cea --- /dev/null +++ b/xmloff/source/transform/Oasis2OOo.hxx @@ -0,0 +1,59 @@ +/* -*- 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 "ActionMapTypesOASIS.hxx" +#include "TransformerBase.hxx" + +class XMLTransformerOASISEventMap_Impl; + +class Oasis2OOoTransformer : public XMLTransformerBase +{ + std::unique_ptr m_aActions[MAX_OASIS_ACTIONS]; + XMLTransformerOASISEventMap_Impl *m_pEventMap; + XMLTransformerOASISEventMap_Impl *m_pFormEventMap; + +protected: + + virtual XMLTransformerContext *CreateUserDefinedContext( + const TransformerAction_Impl& rAction, + const OUString& rQName, + bool bPersistent=false ) override; + + virtual XMLTransformerActions *GetUserDefinedActions( sal_uInt16 n ) override; + +public: + Oasis2OOoTransformer () noexcept; + virtual ~Oasis2OOoTransformer() noexcept override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XUnoTunnel + static const css::uno::Sequence& getUnoTunnelId() noexcept; + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + + virtual OUString GetEventName( const OUString& rName, + bool bForm = false ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/PersAttrListTContext.cxx b/xmloff/source/transform/PersAttrListTContext.cxx new file mode 100644 index 000000000..53e20b0a3 --- /dev/null +++ b/xmloff/source/transform/PersAttrListTContext.cxx @@ -0,0 +1,174 @@ +/* -*- 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 +#include "IgnoreTContext.hxx" +#include "TransformerBase.hxx" +#include "MutableAttrList.hxx" +#include +#include "PersAttrListTContext.hxx" + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::xml::sax; + +void XMLPersAttrListTContext::AddAttribute( + sal_uInt16 nAPrefix, + ::xmloff::token::XMLTokenEnum eAToken, + ::xmloff::token::XMLTokenEnum eVToken ) +{ + const OUString& aAttrValue( ::xmloff::token::GetXMLToken( eVToken ) ); + AddAttribute( nAPrefix, eAToken, aAttrValue ); +} + +void XMLPersAttrListTContext::AddAttribute( + sal_uInt16 nAPrefix, + ::xmloff::token::XMLTokenEnum eAToken, + const OUString & rValue ) +{ + OUString aAttrQName( GetTransformer().GetNamespaceMap().GetQNameByKey( + nAPrefix, ::xmloff::token::GetXMLToken( eAToken ) ) ); + const OUString& aAttrValue( rValue ); + + rtl::Reference pMutableAttrList; + if( m_xAttrList.is() ) + { + pMutableAttrList = + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ); + } + else + { + pMutableAttrList = new XMLMutableAttributeList ; + m_xAttrList = pMutableAttrList; + } + + pMutableAttrList->AddAttribute( aAttrQName, aAttrValue ); +} + +XMLPersAttrListTContext::XMLPersAttrListTContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rQName ), + m_nActionMap( INVALID_ACTIONS ) +{ +} + +XMLPersAttrListTContext::XMLPersAttrListTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nActionMap ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rQName ), + m_nActionMap( nActionMap ) +{ +} + +XMLPersAttrListTContext::XMLPersAttrListTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rImp.GetNamespaceMap().GetQNameByKey( nPrefix, + ::xmloff::token::GetXMLToken( eToken ) ) ), + m_nActionMap( INVALID_ACTIONS ) +{ +} + +XMLPersAttrListTContext::XMLPersAttrListTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rImp.GetNamespaceMap().GetQNameByKey( nPrefix, + ::xmloff::token::GetXMLToken( eToken ) ) ), + m_nActionMap( nActionMap ) +{ +} + +rtl::Reference XMLPersAttrListTContext::CreateChildContext( + sal_uInt16 /*nPrefix*/, + const OUString& /*rLocalName*/, + const OUString& rQName, + const Reference< XAttributeList >& ) +{ + // ignore all child elements + return new XMLIgnoreTransformerContext( GetTransformer(), + rQName, true, true ); +} + +void XMLPersAttrListTContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLMutableAttributeList *pMutableAttrList = nullptr; + + Reference< XAttributeList > xAttrList( rAttrList ); + if( m_nActionMap != INVALID_ACTIONS ) + { + pMutableAttrList = + GetTransformer().ProcessAttrList( xAttrList, m_nActionMap, + true ); + } + + if( m_xAttrList.is() ) + { + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) + ->AppendAttributeList( xAttrList ); + } + else if( pMutableAttrList ) + { + m_xAttrList = xAttrList; + } + else + { + m_xAttrList = new XMLMutableAttributeList( rAttrList, true ); + } +} + +void XMLPersAttrListTContext::EndElement() +{ + // ignore for now +} + +void XMLPersAttrListTContext::Characters( const OUString& ) +{ +} + +bool XMLPersAttrListTContext::IsPersistent() const +{ + return true; +} + +void XMLPersAttrListTContext::Export() +{ + GetTransformer().GetDocHandler()->startElement( m_aElemQName, m_xAttrList ); + ExportContent(); + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +void XMLPersAttrListTContext::ExportContent() +{ + // nothing to export +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/PersAttrListTContext.hxx b/xmloff/source/transform/PersAttrListTContext.hxx new file mode 100644 index 000000000..41ac5a113 --- /dev/null +++ b/xmloff/source/transform/PersAttrListTContext.hxx @@ -0,0 +1,103 @@ +/* -*- 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 +#include "TransformerContext.hxx" + + +class XMLPersAttrListTContext : public XMLTransformerContext +{ + + css::uno::Reference< css::xml::sax::XAttributeList > m_xAttrList; + OUString m_aElemQName; + sal_uInt16 const m_nActionMap; + +protected: + + void SetExportQName( const OUString& r ) { m_aElemQName = r; } + +public: + // A contexts constructor does anything that is required if an element + // starts. Namespace processing has been done already. + // Note that virtual methods cannot be used inside constructors. Use + // StartElement instead if this is required. + XMLPersAttrListTContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + // attr list persistence + attribute processing + XMLPersAttrListTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nActionMap ); + + // attr list persistence + renaming + XMLPersAttrListTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ); + + // attr list persistence + renaming + attribute processing + XMLPersAttrListTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap ); + + // Create a children element context. By default, the import's + // CreateContext method is called to create a new default context. + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + // StartElement is called after a context has been constructed and + // before an elements context is parsed. It may be used for actions that + // require virtual methods. The default is to do nothing. + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + // EndElement is called before a context will be destructed, but + // after an elements context has been parsed. It may be used for actions + // that require virtual methods. The default is to do nothing. + virtual void EndElement() override; + + // This method is called for all characters that are contained in the + // current element. + virtual void Characters( const OUString& rChars ) override; + + virtual bool IsPersistent() const override; + virtual void Export() override; + virtual void ExportContent() override; + + const OUString& GetExportQName() const { return m_aElemQName; } + + void AddAttribute( sal_uInt16 nAPrefix, + ::xmloff::token::XMLTokenEnum eAToken, + ::xmloff::token::XMLTokenEnum eVToken ); + + void AddAttribute( sal_uInt16 nAPrefix, + ::xmloff::token::XMLTokenEnum eAToken, + const OUString & rValue ); + + const css::uno::Reference< css::xml::sax::XAttributeList >& + GetAttrList() const { return m_xAttrList; } + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/PersMixedContentTContext.cxx b/xmloff/source/transform/PersMixedContentTContext.cxx new file mode 100644 index 000000000..f892530ac --- /dev/null +++ b/xmloff/source/transform/PersMixedContentTContext.cxx @@ -0,0 +1,139 @@ +/* -*- 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 "TransformerBase.hxx" +#include "PersMixedContentTContext.hxx" + +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +namespace { + +class XMLPersTextTContext_Impl : public XMLTransformerContext +{ + OUString m_aCharacters; + +public: + XMLPersTextTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rChars ); + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + virtual void Characters( const OUString& rChars ) override; + + virtual bool IsPersistent() const override; + virtual void Export() override; +}; + +} + +XMLPersTextTContext_Impl::XMLPersTextTContext_Impl( + XMLTransformerBase& rImp, + const OUString& rChars ) : + XMLTransformerContext( rImp, OUString() ), + m_aCharacters( rChars ) +{ +} + +rtl::Reference XMLPersTextTContext_Impl::CreateChildContext( + sal_uInt16, + const OUString&, + const OUString&, + const Reference< XAttributeList >& ) +{ + OSL_ENSURE( false, "illegal call to CreateChildContext" ); + return {}; +} + +void XMLPersTextTContext_Impl::StartElement( + const Reference< XAttributeList >& ) +{ + OSL_ENSURE( false, "illegal call to StartElement" ); +} + +void XMLPersTextTContext_Impl::EndElement() +{ + OSL_ENSURE( false, "illegal call to EndElement" ); +} + +bool XMLPersTextTContext_Impl::IsPersistent() const +{ + return true; +} + +void XMLPersTextTContext_Impl::Characters( const OUString& rChars ) +{ + m_aCharacters += rChars; +} + +void XMLPersTextTContext_Impl::Export() +{ + GetTransformer().GetDocHandler()->characters( m_aCharacters ); +} + +XMLPersMixedContentTContext::XMLPersMixedContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLPersElemContentTContext( rImp, rQName ) +{ +} + +XMLPersMixedContentTContext::XMLPersMixedContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nActionMap ) : + XMLPersElemContentTContext( rImp, rQName, nActionMap ) +{ +} + +XMLPersMixedContentTContext::XMLPersMixedContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ) : + XMLPersElemContentTContext( rImp, rQName, nPrefix, eToken ) +{ +} + +XMLPersMixedContentTContext::XMLPersMixedContentTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap ) : + XMLPersElemContentTContext( rImp, rQName, nPrefix, eToken, nActionMap ) +{ +} + +XMLPersMixedContentTContext::~XMLPersMixedContentTContext() +{ +} + +void XMLPersMixedContentTContext::Characters( const OUString& rChars ) +{ + AddContent( new XMLPersTextTContext_Impl( GetTransformer(), rChars ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/PersMixedContentTContext.hxx b/xmloff/source/transform/PersMixedContentTContext.hxx new file mode 100644 index 000000000..b8f6016cf --- /dev/null +++ b/xmloff/source/transform/PersMixedContentTContext.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/. + * + * 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 "DeepTContext.hxx" + +class XMLPersMixedContentTContext : public XMLPersElemContentTContext +{ +public: + // mixed content persistence only + XMLPersMixedContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + // mixed content persistence + attribute processing + XMLPersMixedContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nActionMap ); + + // mixed content persistence + renaming + XMLPersMixedContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ); + + // mixed content persistence + renaming + attribute processing + XMLPersMixedContentTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap ); + + virtual void Characters( const OUString& rChars ) override; + + virtual ~XMLPersMixedContentTContext() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ProcAddAttrTContext.cxx b/xmloff/source/transform/ProcAddAttrTContext.cxx new file mode 100644 index 000000000..d15002ad2 --- /dev/null +++ b/xmloff/source/transform/ProcAddAttrTContext.cxx @@ -0,0 +1,66 @@ +/* -*- 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 "ProcAddAttrTContext.hxx" +#include "MutableAttrList.hxx" +#include "TransformerBase.hxx" +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLProcAddAttrTransformerContext::XMLProcAddAttrTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap, + sal_uInt16 nAPrefix, + ::xmloff::token::XMLTokenEnum eAToken, + ::xmloff::token::XMLTokenEnum eVToken ) : + XMLProcAttrTransformerContext( rImp, rQName, nPrefix, eToken, nActionMap ), + m_aAttrQName( rImp.GetNamespaceMap().GetQNameByKey( nAPrefix, + ::xmloff::token::GetXMLToken( eAToken ) ) ), + m_aAttrValue( ::xmloff::token::GetXMLToken( eVToken ) ) +{ +} + +XMLProcAddAttrTransformerContext::~XMLProcAddAttrTransformerContext() +{ +} + +void XMLProcAddAttrTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList = + GetTransformer().ProcessAttrList( xAttrList, GetActionMap(), + false ); + if( !pMutableAttrList ) + { + pMutableAttrList = new XMLMutableAttributeList; + xAttrList = pMutableAttrList; + } + pMutableAttrList->AddAttribute( m_aAttrQName, m_aAttrValue ); + GetTransformer().GetDocHandler()->startElement( GetElemQName(), xAttrList ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ProcAddAttrTContext.hxx b/xmloff/source/transform/ProcAddAttrTContext.hxx new file mode 100644 index 000000000..8088aec26 --- /dev/null +++ b/xmloff/source/transform/ProcAddAttrTContext.hxx @@ -0,0 +1,44 @@ +/* -*- 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 "ProcAttrTContext.hxx" + +class XMLProcAddAttrTransformerContext : public XMLProcAttrTransformerContext +{ + OUString const m_aAttrQName; + OUString const m_aAttrValue; + +public: + XMLProcAddAttrTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap, + sal_uInt16 nAPrefix, + ::xmloff::token::XMLTokenEnum eAToken, + ::xmloff::token::XMLTokenEnum eVToken ); + + virtual ~XMLProcAddAttrTransformerContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ProcAttrTContext.cxx b/xmloff/source/transform/ProcAttrTContext.cxx new file mode 100644 index 000000000..6dbab0048 --- /dev/null +++ b/xmloff/source/transform/ProcAttrTContext.cxx @@ -0,0 +1,65 @@ +/* -*- 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 "ProcAttrTContext.hxx" +#include "TransformerBase.hxx" +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; +using namespace ::xmloff::token; + +XMLProcAttrTransformerContext::XMLProcAttrTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nActionMap ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rQName ), + m_nActionMap( nActionMap ) +{ +} + +XMLProcAttrTransformerContext::XMLProcAttrTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rImp.GetNamespaceMap().GetQNameByKey( nPrefix, + ::xmloff::token::GetXMLToken( eToken ) ) ), + m_nActionMap( nActionMap ) +{ +} + +void XMLProcAttrTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + Reference< XAttributeList > xAttrList( rAttrList ); + GetTransformer().ProcessAttrList( xAttrList, m_nActionMap, false ); + GetTransformer().GetDocHandler()->startElement( m_aElemQName, xAttrList ); +} + +void XMLProcAttrTransformerContext::EndElement() +{ + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/ProcAttrTContext.hxx b/xmloff/source/transform/ProcAttrTContext.hxx new file mode 100644 index 000000000..e298d1095 --- /dev/null +++ b/xmloff/source/transform/ProcAttrTContext.hxx @@ -0,0 +1,50 @@ +/* -*- 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 +#include "TransformerContext.hxx" + +class XMLProcAttrTransformerContext : public XMLTransformerContext +{ + OUString const m_aElemQName; + sal_uInt16 const m_nActionMap; + +protected: + + const OUString& GetElemQName() const { return m_aElemQName; } + sal_uInt16 GetActionMap() const { return m_nActionMap; } + +public: + XMLProcAttrTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nActionMap ); + + XMLProcAttrTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nActionMap ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/PropType.hxx b/xmloff/source/transform/PropType.hxx new file mode 100644 index 000000000..e02a5eed5 --- /dev/null +++ b/xmloff/source/transform/PropType.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/. + * + * 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 + +enum XMLPropType +{ + XML_PROP_TYPE_GRAPHIC, + XML_PROP_TYPE_DRAWING_PAGE, + XML_PROP_TYPE_PAGE_LAYOUT, + XML_PROP_TYPE_HEADER_FOOTER, + XML_PROP_TYPE_TEXT, + XML_PROP_TYPE_PARAGRAPH, + XML_PROP_TYPE_RUBY, + XML_PROP_TYPE_SECTION, + XML_PROP_TYPE_TABLE, + XML_PROP_TYPE_TABLE_COLUMN, + XML_PROP_TYPE_TABLE_ROW, + XML_PROP_TYPE_TABLE_CELL, + XML_PROP_TYPE_LIST_LEVEL, + XML_PROP_TYPE_CHART, + XML_PROP_TYPE_END +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/PropertyActionsOASIS.cxx b/xmloff/source/transform/PropertyActionsOASIS.cxx new file mode 100644 index 000000000..8860f3d22 --- /dev/null +++ b/xmloff/source/transform/PropertyActionsOASIS.cxx @@ -0,0 +1,545 @@ +/* -*- 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 +#include "FamilyType.hxx" +#include "PropertyActionsOASIS.hxx" + +using namespace ::xmloff::token; + +#define NO_PARAMS 0, 0, 0 + +XMLTransformerActionInit const aGraphicPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_SVG, XML_STROKE_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_MARKER_START_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_MARKER_END_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_SHADOW_OFFSET_X, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_SHADOW_OFFSET_Y, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_SHADOW_OPACITY, + XML_ATACTION_RENAME_NEG_PERCENT, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_DRAW, + XML_SHADOW_TRANSPARENCY), 0, 0 }, + { XML_NAMESPACE_DRAW, XML_GUIDE_OVERHANG, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_START_GUIDE, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_END_GUIDE, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE, XML_ATACTION_CAPTION_ESCAPE_OASIS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_LINE_LENGTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_DEPTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MAX_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MAX_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_TOP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INS2INCHS, + NO_PARAMS }, + { XML_NAMESPACE_FO, XML_CLIP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ +// { XML_NAMESPACE_STYLE, XML_WRAP_DYNAMIC_THRESHOLD, XML_ATACTION_REMOVE, +// NO_PARAMS }, /* generated entry */ // TODO + { XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_START_LINE_SPACING_HORIZONTAL, XML_ATACTION_IN2INCH, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_START_LINE_SPACING_VERTICAL, XML_ATACTION_IN2INCH, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_END_LINE_SPACING_HORIZONTAL, XML_ATACTION_IN2INCH, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_END_LINE_SPACING_VERTICAL, XML_ATACTION_IN2INCH, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_LINE_DISTANCE, XML_ATACTION_IN2INCH, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_GUIDE_DISTANCE, XML_ATACTION_IN2INCH, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_GAP, XML_ATACTION_IN2INCH, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_X, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_Y, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_STROKE_DASH, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_STROKE_DASH, 0, 0 }, + { XML_NAMESPACE_DRAW, XML_MARKER_START, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_MARKER, 0, 0 }, + { XML_NAMESPACE_DRAW, XML_MARKER_END, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_MARKER, 0, 0 }, + { XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_GRADIENT, 0, 0 }, + + // #i25616# + { XML_NAMESPACE_DRAW, XML_OPACITY, XML_OPTACTION_OPACITY, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_IMAGE_OPACITY, XML_OPTACTION_IMAGE_OPACITY, NO_PARAMS }, + + { XML_NAMESPACE_DRAW, XML_STROKE_LINEJOIN, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_SVG, + XML_STROKE_LINEJOIN), 0, 0 }, + { XML_NAMESPACE_DRAW, XML_OPACITY_NAME, + XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_DRAW, + XML_TRANSPARENCY_NAME), + XML_FAMILY_TYPE_GRADIENT, 0 }, + { XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_HATCH, 0, 0 }, + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + XML_FAMILY_TYPE_FILL_IMAGE, 0, 0 }, + + // Font work properties + { XML_NAMESPACE_DRAW, XML_FONTWORK_DISTANCE, XML_ATACTION_IN2INCH, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_START, XML_ATACTION_IN2INCH, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_OFFSET_X, XML_ATACTION_IN2INCH, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_OFFSET_Y, XML_ATACTION_IN2INCH, NO_PARAMS }, + + { XML_NAMESPACE_DRAW, XML_AUTO_GROW_WIDTH, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_DRAW, + XML_AUTO_GROW_HEIGHT ), 0, 0 }, + { XML_NAMESPACE_DRAW, XML_AUTO_GROW_HEIGHT, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_DRAW, + XML_AUTO_GROW_WIDTH ), 0, 0 }, + { XML_NAMESPACE_PRESENTATION, XML_DURATION, XML_ATACTION_RNG2ISO_DATETIME, NO_PARAMS }, + { XML_NAMESPACE_TEXT, XML_ANIMATION_DELAY, XML_ATACTION_RNG2ISO_DATETIME, NO_PARAMS }, + + { XML_NAMESPACE_STYLE, XML_PROTECT, XML_ATACTION_DECODE_PROTECT, NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_MIRROR, XML_ATACTION_DRAW_MIRROR_OASIS, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_GAMMA, XML_ATACTION_GAMMA_OASIS, NO_PARAMS }, + { XML_NAMESPACE_SVG, XML_STROKE_OPACITY, XML_ATACTION_OPACITY_FIX, NO_PARAMS }, + + { XML_NAMESPACE_STYLE, XML_FLOW_WITH_TEXT, XML_ATACTION_REMOVE, + NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_WRAP_INFLUENCE_ON_POSITION, XML_ATACTION_REMOVE, + NO_PARAMS }, + + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aDrawingPagePropertyOASISAttrActionTable[] = +{ + // style-graphic-fill-properties-attlist + { XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, + NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_ATACTION_IN2INCH, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_ATACTION_IN2INCH, NO_PARAMS }, /* generated entry */ + + { XML_NAMESPACE_PRESENTATION, XML_DISPLAY_HEADER, XML_ATACTION_REMOVE, NO_PARAMS }, + { XML_NAMESPACE_PRESENTATION, XML_DISPLAY_FOOTER, XML_ATACTION_REMOVE, NO_PARAMS }, + { XML_NAMESPACE_PRESENTATION, XML_DISPLAY_PAGE_NUMBER, XML_ATACTION_REMOVE, NO_PARAMS }, + { XML_NAMESPACE_PRESENTATION, XML_DISPLAY_DATE_TIME, XML_ATACTION_REMOVE, NO_PARAMS }, + + { XML_NAMESPACE_SMIL, XML_TYPE, XML_ATACTION_REMOVE, NO_PARAMS }, + { XML_NAMESPACE_SMIL, XML_SUBTYPE, XML_ATACTION_REMOVE, NO_PARAMS }, + { XML_NAMESPACE_SMIL, XML_DIRECTION, XML_ATACTION_REMOVE, NO_PARAMS }, + { XML_NAMESPACE_SMIL, XML_FADECOLOR, XML_ATACTION_REMOVE, NO_PARAMS }, + + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aPageLayoutPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_FO, XML_PAGE_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PAGE_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_TOP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INS2INCHS, + NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_FOOTNOTE_MAX_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_BASE_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_RUBY_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_REGISTER_TRUTH_REF_STYLE_NAME, XML_ATACTION_DECODE_STYLE_NAME_REF, XML_FAMILY_TYPE_PARAGRAPH, 0, 0 }, + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aHeaderFooterPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_SVG, XML_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_TOP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INS2INCHS, + NO_PARAMS }, + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTextPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_FO, XML_FONT_SIZE, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_ASIAN, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_COMPLEX, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL_ASIAN, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL_COMPLEX, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_LETTER_SPACING, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_TEXT_SHADOW, XML_ATACTION_INS2INCHS, + NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_TYPE, + XML_OPTACTION_UNDERLINE_TYPE, NO_PARAMS }, /* new attribute */ + { XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_STYLE, + XML_OPTACTION_UNDERLINE_STYLE, NO_PARAMS }, /* new attribute */ + { XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_WIDTH, + XML_OPTACTION_UNDERLINE_WIDTH, NO_PARAMS }, /* new attribute */ + { XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_MODE, + XML_OPTACTION_LINE_MODE, NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TYPE, + XML_OPTACTION_LINETHROUGH_TYPE, NO_PARAMS }, /* new entry*/ + { XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_STYLE, + XML_OPTACTION_LINETHROUGH_STYLE, NO_PARAMS }, /* new entry*/ + { XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_WIDTH, + XML_OPTACTION_LINETHROUGH_WIDTH, NO_PARAMS }, /* new entry*/ + { XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_COLOR, + XML_ATACTION_REMOVE, NO_PARAMS }, /* new entry*/ + { XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TEXT, + XML_OPTACTION_LINETHROUGH_TEXT, NO_PARAMS }, /* new entry*/ + { XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TEXT_STYLE, + XML_ATACTION_REMOVE, NO_PARAMS }, /* new entry*/ + { XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_MODE, + XML_OPTACTION_LINE_MODE, NO_PARAMS }, + { XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_STYLE, + XML_TEXT_BACKGROUND_COLOR ), 0, 0 }, + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aParagraphPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_FO, XML_TEXT_ALIGN, XML_OPTACTION_CONTROL_TEXT_ALIGN, + NO_PARAMS }, + { XML_NAMESPACE_FO, XML_LINE_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LINE_HEIGHT_AT_LEAST, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LINE_SPACING, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TAB_STOP_DISTANCE, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_TEXT_INDENT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INS2INCHS, + NO_PARAMS }, + { XML_NAMESPACE_FO, XML_KEEP_WITH_NEXT, XML_OPTACTION_KEEP_WITH_NEXT, + NO_PARAMS }, + { XML_NAMESPACE_FO, XML_KEEP_TOGETHER, XML_OPTACTION_KEEP_TOGETHER, + NO_PARAMS }, +// { XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_OPTACTION_DRAW_WRITING_MODE, 0 }, + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aSectionPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTablePropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_KEEP_WITH_NEXT, XML_OPTACTION_KEEP_WITH_NEXT, + NO_PARAMS }, + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTableColumnPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_COLUMN_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTableRowPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_ROW_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_MIN_ROW_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTableCellPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_VERTICAL_ALIGN, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_FO, + XML_VERTICAL_ALIGN ), 0, 0 }, + { XML_NAMESPACE_FO, XML_BORDER, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_TOP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIAGONAL_BL_TR, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIAGONAL_BL_TR_WIDTH, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIAGONAL_TL_BR, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIAGONAL_TL_BR_WIDTH, XML_ATACTION_INS2INCHS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIRECTION, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_FO, + XML_DIRECTION), 0, 0 }, + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INS2INCHS, + NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_REPEAT_CONTENT, XML_ATACTION_REMOVE, + NO_PARAMS }, /* new entry*/ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aListLevelPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_TEXT, XML_SPACE_BEFORE, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_MIN_LABEL_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_MIN_LABEL_DISTANCE, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aChartPropertyOASISAttrActionTable[] = +{ + { XML_NAMESPACE_CHART, XML_SYMBOL_WIDTH, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_SYMBOL_HEIGHT, XML_ATACTION_IN2INCH, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIRECTION, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_FO, + XML_DIRECTION ), 0, 0 }, + { XML_NAMESPACE_CHART, XML_INTERPOLATION, XML_OPTACTION_INTERPOLATION, NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_TEXT, + XML_ROTATION_ANGLE ), 0, 0 }, + { XML_NAMESPACE_CHART, XML_INTERVAL_MAJOR, XML_OPTACTION_INTERVAL_MAJOR, NO_PARAMS }, + { XML_NAMESPACE_CHART, XML_INTERVAL_MINOR_DIVISOR, XML_OPTACTION_INTERVAL_MINOR_DIVISOR, + NO_PARAMS }, + { XML_NAMESPACE_CHART, XML_JAPANESE_CANDLE_STICK, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_CHART, + XML_STOCK_UPDOWN_BARS ), 0, 0 }, + { XML_NAMESPACE_CHART, XML_SYMBOL_TYPE, XML_OPTACTION_SYMBOL_TYPE, NO_PARAMS }, + { XML_NAMESPACE_CHART, XML_SYMBOL_NAME, XML_OPTACTION_SYMBOL_NAME, NO_PARAMS }, + + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/PropertyActionsOASIS.hxx b/xmloff/source/transform/PropertyActionsOASIS.hxx new file mode 100644 index 000000000..6fb80d57b --- /dev/null +++ b/xmloff/source/transform/PropertyActionsOASIS.hxx @@ -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/. + * + * 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 "TransformerActionInit.hxx" +#include "AttrTransformerAction.hxx" + +enum XMLPropOASISTransformerAction +{ + XML_OPTACTION_LINE_MODE = XML_ATACTION_USER_DEFINED, + XML_OPTACTION_UNDERLINE_TYPE, + XML_OPTACTION_UNDERLINE_STYLE, + XML_OPTACTION_UNDERLINE_WIDTH, + XML_OPTACTION_LINETHROUGH_TYPE, + XML_OPTACTION_LINETHROUGH_STYLE, + XML_OPTACTION_LINETHROUGH_WIDTH, + XML_OPTACTION_LINETHROUGH_TEXT, + XML_OPTACTION_KEEP_WITH_NEXT, + XML_OPTACTION_INTERPOLATION, + XML_OPTACTION_INTERVAL_MAJOR, + XML_OPTACTION_INTERVAL_MINOR_DIVISOR, + XML_OPTACTION_SYMBOL_TYPE, + XML_OPTACTION_SYMBOL_NAME, + XML_OPTACTION_OPACITY, + XML_OPTACTION_IMAGE_OPACITY, + XML_OPTACTION_KEEP_TOGETHER, + XML_OPTACTION_CONTROL_TEXT_ALIGN, + XML_ATACTION_CAPTION_ESCAPE_OASIS, + XML_ATACTION_DECODE_PROTECT +}; + +extern XMLTransformerActionInit const aGraphicPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aDrawingPagePropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aPageLayoutPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aHeaderFooterPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aTextPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aParagraphPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aSectionPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aTablePropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aTableColumnPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aTableRowPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aTableCellPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aListLevelPropertyOASISAttrActionTable[]; +extern XMLTransformerActionInit const aChartPropertyOASISAttrActionTable[]; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/PropertyActionsOOo.cxx b/xmloff/source/transform/PropertyActionsOOo.cxx new file mode 100644 index 000000000..cc6fc0e6b --- /dev/null +++ b/xmloff/source/transform/PropertyActionsOOo.cxx @@ -0,0 +1,1058 @@ +/* -*- 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 +#include "PropType.hxx" +#include "PropertyActionsOOo.hxx" + +using namespace ::xmloff::token; + +#define NO_PARAMS 0, 0, 0 + +XMLTransformerActionInit const aGraphicPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_DRAW, XML_STROKE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_STROKE_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_STROKE_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_MARKER_START_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_MARKER_END_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_MARKER_START_CENTER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_MARKER_END_CENTER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_STROKE_OPACITY, XML_ATACTION_OPACITY_FIX, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_STROKE_LINEJOIN, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_DRAW, + XML_STROKE_LINEJOIN), 0, 0 }, + { XML_NAMESPACE_TEXT, XML_ANIMATION, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_ANIMATION_DIRECTION, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_ANIMATION_START_INSIDE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_ANIMATION_STOP_INSIDE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_ANIMATION_REPEAT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_ANIMATION_DELAY, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_ANIMATION_STEPS, XML_ATACTION_COPY, + NO_PARAMS }, /* TODO: missing in OASIS spec */ + { XML_NAMESPACE_DRAW, XML_AUTO_GROW_WIDTH, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_DRAW, + XML_AUTO_GROW_HEIGHT ), 0, 0 }, + { XML_NAMESPACE_DRAW, XML_AUTO_GROW_HEIGHT, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_DRAW, + XML_AUTO_GROW_WIDTH ), 0, 0 }, + { XML_NAMESPACE_DRAW, XML_FIT_TO_SIZE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_TEXTAREA_VERTICAL_ALIGN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_TEXTAREA_HORIZONTAL_ALIGN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_COLOR_MODE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_COLOR_INVERSION, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_LUMINANCE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CONTRAST, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_GAMMA, XML_ATACTION_GAMMA_OOO, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_RED, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_GREEN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_BLUE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_SHADOW, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_SHADOW_OFFSET_X, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_SHADOW_OFFSET_Y, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_SHADOW_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_SHADOW_TRANSPARENCY, + XML_ATACTION_RENAME_NEG_PERCENT, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_DRAW, + XML_SHADOW_OPACITY), 0, 0 }, + { XML_NAMESPACE_DRAW, XML_START_LINE_SPACING_HORIZONTAL, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_START_LINE_SPACING_VERTICAL, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_END_LINE_SPACING_HORIZONTAL, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_END_LINE_SPACING_VERTICAL, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_LINE_DISTANCE, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_GUIDE_OVERHANG, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_GUIDE_DISTANCE, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_START_GUIDE, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_END_GUIDE, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_PLACING, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_PARALLEL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_MEASURE_ALIGN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_MEASURE_VERTICAL_ALIGN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_UNIT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_SHOW_UNIT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_DECIMAL_PLACES, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_TYPE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_ANGLE_TYPE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_ANGLE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_GAP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE_DIRECTION, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_ESCAPE, XML_ATACTION_CAPTION_ESCAPE_OOO, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_LINE_LENGTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_CAPTION_FIT_LINE_LENGTH, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_HORIZONTAL_SEGMENTS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_VERTICAL_SEGMENTS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_EDGE_ROUNDING, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ +// { XML_NAMESPACE_DR3D, XML_EDGE_ROUNDING_MODE, XML_ATACTION_COPY, +// NO_PARAMS }, /* TODO: does not exist! */ + { XML_NAMESPACE_DR3D, XML_BACK_SCALE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_DEPTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_BACKFACE_CULLING, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_NORMALS_KIND, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_NORMALS_DIRECTION, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_TEX_GENERATION_MODE_X, XML_ATACTION_COPY, + NO_PARAMS }, + { XML_NAMESPACE_DR3D, XML_TEX_GENERATION_MODE_Y, XML_ATACTION_COPY, + NO_PARAMS }, + { XML_NAMESPACE_DR3D, XML_END_ANGLE, XML_ATACTION_COPY, + NO_PARAMS }, + { XML_NAMESPACE_DR3D, XML_TEX_KIND, XML_ATACTION_COPY, + NO_PARAMS }, + { XML_NAMESPACE_DR3D, XML_TEX_FILTER, XML_ATACTION_COPY, + NO_PARAMS }, + { XML_NAMESPACE_DR3D, XML_TEX_MODE, XML_ATACTION_COPY, + NO_PARAMS }, + { XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_EMISSIVE_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_SPECULAR_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_SHININESS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DR3D, XML_SHADOW, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_REL_WIDTH, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_REL_HEIGHT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MIN_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MAX_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MAX_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_INCH2IN_DUPLICATE, + XML_PROP_TYPE_PARAGRAPH, 0, 0 }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_INCH2IN_DUPLICATE, + XML_PROP_TYPE_PARAGRAPH, 0, 0 }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_INCH2IN_DUPLICATE, + XML_PROP_TYPE_PARAGRAPH, 0, 0 }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_INCH2IN_DUPLICATE, + XML_PROP_TYPE_PARAGRAPH, 0, 0 }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BACKGROUND_TRANSPARENCY, XML_ATACTION_COPY, + NO_PARAMS }, + { XML_NAMESPACE_FO, XML_BORDER, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INCHS2INS, + NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_PRINT_CONTENT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_PROTECT, XML_ATACTION_PROTECT, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_HORIZONTAL_POS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_X, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_HORIZONTAL_REL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_VERTICAL_POS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_SVG, XML_Y, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_VERTICAL_REL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_ANCHOR_TYPE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_ANCHOR_PAGE_NUMBER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_EDITABLE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_WRAP, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ +// { XML_NAMESPACE_STYLE, XML_WRAP_DYNAMIC_THRESHOLD, XML_ATACTION_COPY, +// NO_PARAMS }, /* new attribute */ + { XML_NAMESPACE_STYLE, XML_NUMBER_WRAPPED_PARAGRAPHS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_WRAP_CONTOUR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_WRAP_CONTOUR_MODE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_RUN_THROUGH, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FLOW_WITH_TEXT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ +// { XML_NAMESPACE_STYLE, XML_OVERFLOW_BEHAVIOR, XML_ATACTION_COPY, +// NO_PARAMS }, /* new attribute */ + /* Rename attribute values of : (#i49139#) + horizontal-on-left-pages --> horizontal-on-even + horizontal-on-right-pages --> horizontal-on-odd + */ + { XML_NAMESPACE_STYLE, XML_MIRROR, XML_ATACTION_STYLE_MIRROR_OOO, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_CLIP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FRAME_DISPLAY_SCROLLBAR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FRAME_DISPLAY_BORDER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FRAME_MARGIN_HORIZONTAL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FRAME_MARGIN_VERTICAL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_VISIBLE_AREA_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_STROKE_DASH, XML_ATACTION_ENCODE_STYLE_NAME_REF, + NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_MARKER_START, XML_ATACTION_ENCODE_STYLE_NAME_REF, + NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_MARKER_END, XML_ATACTION_ENCODE_STYLE_NAME_REF, + NO_PARAMS }, + // style-graphic-fill-properties-attlist + { XML_NAMESPACE_DRAW, XML_FILL, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_COLOR, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF, + NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_GRADIENT_STEP_COUNT, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF, + NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_REPEAT, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_ATACTION_INCH2IN, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_ATACTION_INCH2IN, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_X, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT_Y, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_REF_POINT, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_TILE_REPEAT_OFFSET, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + + // #i25616# + { XML_NAMESPACE_DRAW, XML_TRANSPARENCY, XML_PTACTION_TRANSPARENCY, NO_PARAMS }, + + { XML_NAMESPACE_DRAW, XML_TRANSPARENCY_NAME, + XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_DRAW, + XML_OPACITY_NAME), 0, 0 }, + + { XML_NAMESPACE_DRAW, XML_MOVE_PROTECT, XML_ATACTION_MOVE_PROTECT, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_SIZE_PROTECT, XML_ATACTION_SIZE_PROTECT, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FIT_TO_CONTOUR, XML_ATACTION_COPY, NO_PARAMS }, + + // Font work properties + { XML_NAMESPACE_DRAW, XML_FONTWORK_STYLE, XML_ATACTION_COPY, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_ADJUST, XML_ATACTION_COPY, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_DISTANCE, XML_ATACTION_INCH2IN, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_START, XML_ATACTION_INCH2IN, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_MIRROR, XML_ATACTION_COPY, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_OUTLINE, XML_ATACTION_COPY, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW, XML_ATACTION_COPY, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_COLOR, XML_ATACTION_COPY, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_OFFSET_X, XML_ATACTION_INCH2IN, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_OFFSET_Y, XML_ATACTION_INCH2IN, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_FORM, XML_ATACTION_COPY, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_HIDE_FORM, XML_ATACTION_COPY, NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FONTWORK_SHADOW_TRANSPARENCE, XML_ATACTION_COPY, NO_PARAMS }, + + { XML_NAMESPACE_DRAW, XML_WRAP_INFLUENCE_ON_POSITION, XML_ATACTION_COPY, NO_PARAMS }, // new in OOo 2.0 + + { XML_NAMESPACE_DRAW, XML_MIRROR, XML_ATACTION_DRAW_MIRROR_OOO, + NO_PARAMS }, /* generated entry */ + + // b6242385: read writing-mode for text frames + { XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_ATACTION_COPY, NO_PARAMS }, + + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aGraphicPropertyOOoElemActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_COLUMNS, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_LIST_STYLE, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aDrawingPagePropertyOOoAttrActionTable[] = +{ + // style-graphic-fill-properties-attlist + { XML_NAMESPACE_DRAW, XML_FILL_GRADIENT_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF, + NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FILL_HATCH_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_HATCH_SOLID, XML_ATACTION_COPY, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF, + NO_PARAMS }, + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_WIDTH, XML_ATACTION_INCH2IN, NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_FILL_IMAGE_HEIGHT, XML_ATACTION_INCH2IN, NO_PARAMS }, /* generated entry */ +// { XML_NAMESPACE_DRAW, XML_OPACITY_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF, +// NO_PARAMS }, + + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aPageLayoutPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_FO, XML_PAGE_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PAGE_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INCHS2INS, + NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_FOOTNOTE_MAX_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_BASE_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LAYOUT_GRID_RUBY_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_REGISTER_TRUTH_REF_STYLE_NAME, XML_ATACTION_ENCODE_STYLE_NAME_REF, NO_PARAMS }, + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aHeaderFooterPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_SVG, XML_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MIN_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INCHS2INS, + NO_PARAMS }, + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTextPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_FO, XML_FONT_VARIANT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_TEXT_TRANSFORM, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_USE_WINDOW_FONT_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_OUTLINE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_CROSSING_OUT, XML_PTACTION_LINETHROUGH, + NO_PARAMS }, /* TODO: rename */ + { XML_NAMESPACE_STYLE, XML_TEXT_POSITION, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_NAME, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_NAME_ASIAN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_NAME_COMPLEX, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_FONT_FAMILY, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_FAMILY_ASIAN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_FAMILY_COMPLEX, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC_ASIAN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC_COMPLEX, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME_ASIAN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME_COMPLEX, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_PITCH, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_PITCH_ASIAN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_PITCH_COMPLEX, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_CHARSET, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_FONT_SIZE, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_ASIAN, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_COMPLEX, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL_ASIAN, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_SIZE_REL_COMPLEX, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ +// { XML_NAMESPACE_STYLE, XML_SCRIPT_TYPE, XML_ATACTION_COPY, +// NO_PARAMS }, /* new attribute*/ + { XML_NAMESPACE_FO, XML_LETTER_SPACING, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_LANGUAGE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LANGUAGE_ASIAN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LANGUAGE_COMPLEX, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_COUNTRY, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_COUNTRY_ASIAN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_COUNTRY_COMPLEX, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_FONT_STYLE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_STYLE_ASIAN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_STYLE_COMPLEX, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_RELIEF, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_TEXT_SHADOW, XML_ATACTION_INCHS2INS, + NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE, XML_PTACTION_UNDERLINE, + NO_PARAMS }, /* TODO: rename */ + { XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_FONT_WEIGHT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_WEIGHT_ASIAN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_FONT_WEIGHT_COMPLEX, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_SCORE_SPACES, + XML_PTACTION_LINE_MODE, NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_LETTER_KERNING, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_BLINKING, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_BACKGROUND_COLOR, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_FO, + XML_BACKGROUND_COLOR ), 0, 0 }, + { XML_NAMESPACE_STYLE, XML_TEXT_COMBINE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_COMBINE_START_CHAR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_COMBINE_END_CHAR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_EMPHASIZE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_SCALE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_ROTATION_ANGLE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_ROTATION_SCALE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_DISPLAY, XML_ATACTION_COPY, + NO_PARAMS }, /* new in OOo 2.0 */ + { XML_NAMESPACE_FO, XML_HYPHENATE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_HYPHENATION_REMAIN_CHAR_COUNT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_HYPHENATION_PUSH_CHAR_COUNT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_STYLE, XML_ATACTION_REMOVE, + NO_PARAMS }, /* #i113645# */ + { XML_NAMESPACE_STYLE, XML_TEXT_OVERLINE_COLOR, XML_ATACTION_REMOVE, + NO_PARAMS }, /* #i113645# */ + { XML_NAMESPACE_FO, XML_WRAP_OPTION, XML_ATACTION_REMOVE, + NO_PARAMS }, /* #i116555# */ + + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTextPropertyOOoElemActionTable[] = +{ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + + +XMLTransformerActionInit const aParagraphPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_FO, XML_LINE_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LINE_HEIGHT_AT_LEAST, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LINE_SPACING, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_TEXT_ALIGN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_TEXT_ALIGN_LAST, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_ALIGN, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_FO, XML_TEXT_ALIGN ), 0, 0 }, + { XML_NAMESPACE_STYLE, XML_JUSTIFY_SINGLE_WORD, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BREAK_INSIDE, XML_PTACTION_BREAK_INSIDE, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_WIDOWS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_ORPHANS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TAB_STOP_DISTANCE, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_HYPHENATION_KEEP, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_HYPHENATION_LADDER_COUNT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_REGISTER_TRUE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_TEXT_INDENT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_AUTO_TEXT_INDENT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BREAK_BEFORE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BREAK_AFTER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INCHS2INS, + NO_PARAMS }, + { XML_NAMESPACE_FO, XML_KEEP_WITH_NEXT, XML_PTACTION_KEEP_WITH_NEXT, + NO_PARAMS }, + { XML_NAMESPACE_TEXT, XML_NUMBER_LINES, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_LINE_NUMBER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_VERTICAL_ALIGN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_DRAW, XML_WRITING_MODE, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_STYLE, + XML_WRITING_MODE ), 0, 0 }, +// { XML_NAMESPACE_STYLE, XML_WRITING_MODE_AUTOMATIC, XML_ATACTION_COPY, +// NO_PARAMS }, /* new attribute */ + { XML_NAMESPACE_STYLE, XML_SNAP_TO_LAYOUT_GRID, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_PAGE_NUMBER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BACKGROUND_TRANSPARENCY, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_AUTOSPACE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_PUNCTUATION_WRAP, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_LINE_BREAK, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_ENABLE_NUMBERING, XML_ATACTION_COPY, + NO_PARAMS }, /* TODO: undocumented*/ + { XML_NAMESPACE_STYLE, XML_FONT_INDEPENDENT_LINE_SPACING, XML_ATACTION_COPY, + NO_PARAMS }, + { XML_NAMESPACE_STYLE, XML_DEFAULT_OUTLINE_LEVEL, XML_ATACTION_REMOVE, + NO_PARAMS }, /* i41811: style-default-outline was exported as property */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aParagraphPropertyOOoElemActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_TAB_STOPS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DROP_CAP, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aSectionPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTablePropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_MARGIN_BOTTOM, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_KEEP_WITH_NEXT, XML_PTACTION_KEEP_WITH_NEXT, + NO_PARAMS }, + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTableColumnPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_COLUMN_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTableRowPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_ROW_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_MIN_ROW_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTableCellPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_FO, XML_VERTICAL_ALIGN, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_STYLE, + XML_VERTICAL_ALIGN ), 0, 0 }, + { XML_NAMESPACE_FO, XML_TEXT_ALIGN, XML_ATACTION_COPY_DUPLICATE, + XML_PROP_TYPE_PARAGRAPH, 0, 0 }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_TEXT_ALIGN_SOURCE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_DIRECTION, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_STYLE, + XML_DIRECTION), 0, 0 }, + { XML_NAMESPACE_STYLE, XML_GLYPH_ORIENTATION_VERTICAL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_SHADOW, XML_ATACTION_INCHS2INS, + NO_PARAMS }, + { XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_TOP, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_BOTTOM, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_LEFT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_BORDER_LINE_WIDTH_RIGHT, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIAGONAL_BL_TR, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIAGONAL_BL_TR_WIDTH, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIAGONAL_TL_BR, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIAGONAL_TL_BR_WIDTH, XML_ATACTION_INCHS2INS, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_TOP, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_WRAP_OPTION, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_REPEAT_CONTENT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_ROTATION_ALIGN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_CELL_PROTECT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_PRINT_CONTENT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DECIMAL_PLACES, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aTableCellPropertyOOoElemActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_BACKGROUND_IMAGE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aListLevelPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_TEXT, XML_SPACE_BEFORE, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_MIN_LABEL_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_MIN_LABEL_DISTANCE, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aChartPropertyOOoAttrActionTable[] = +{ + { XML_NAMESPACE_CHART, XML_SCALE_TEXT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_THREE_DIMENSIONAL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_DEEP, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ +// { XML_NAMESPACE_CHART, XML_SYMBOL_TYPE, XML_ATACTION_COPY, +// NO_PARAMS }, /* new attribute */ +// { XML_NAMESPACE_CHART, XML_SYMBOL_TYPE, XML_ATACTION_COPY, +// NO_PARAMS }, /* new attribute */ +// { XML_NAMESPACE_CHART, XML_SYMBOL_TYPE, XML_ATACTION_COPY, +// NO_PARAMS }, /* new attribute */ +// { XML_NAMESPACE_CHART, XML_SYMBOL_NAME, XML_ATACTION_COPY, +// NO_PARAMS }, /* new attribute */ +// { XML_NAMESPACE_CHART, XML_SYMBOL_TYPE, XML_ATACTION_COPY, +// NO_PARAMS }, /* new attribute */ + { XML_NAMESPACE_XLINK, XML_HREF, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_SYMBOL_WIDTH, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_SYMBOL_HEIGHT, XML_ATACTION_INCH2IN, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_VERTICAL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_CONNECT_BARS, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_GAP_WIDTH, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_OVERLAP, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ +// { XML_NAMESPACE_CHART, XML_JAPANESE_CANDLE_STICK, XML_ATACTION_COPY, +// NO_PARAMS }, /* TODO: renamed? */ +// { XML_NAMESPACE_CHART, XML_INTERPOLATION, XML_ATACTION_COPY, +// NO_PARAMS }, /* TODO: renamed? */ + { XML_NAMESPACE_CHART, XML_SPLINE_ORDER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_SPLINE_RESOLUTION, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_PIE_OFFSET, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_LINES, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_SOLID_TYPE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_STACKED, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_PERCENTAGE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_LINK_DATA_STYLE_TO_SOURCE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_VISIBLE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_LOGARITHMIC, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_MAXIMUM, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_MINIMUM, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_ORIGIN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_TICK_MARKS_MAJOR_INNER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_TICK_MARKS_MAJOR_OUTER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_TICK_MARKS_MINOR_INNER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_TICK_MARKS_MINOR_OUTER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_DISPLAY_LABEL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_TEXT_OVERLAP, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_TEXT, XML_LINE_BREAK, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_LABEL_ARRANGEMENT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_DIRECTION, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_DATA_LABEL_NUMBER, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_DATA_LABEL_TEXT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_DATA_LABEL_SYMBOL, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_MEAN_VALUE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_ERROR_CATEGORY, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_ERROR_PERCENTAGE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_ERROR_MARGIN, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_ERROR_LOWER_LIMIT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_ERROR_UPPER_LIMIT, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_ERROR_UPPER_INDICATOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_ERROR_LOWER_INDICATOR, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_SERIES_SOURCE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_CHART, XML_REGRESSION_TYPE, XML_ATACTION_COPY, + NO_PARAMS }, /* generated entry */ + { XML_NAMESPACE_FO, XML_DIRECTION, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_STYLE, + XML_DIRECTION ), 0, 0 }, + { XML_NAMESPACE_CHART, XML_SPLINES, XML_PTACTION_SPLINES, NO_PARAMS }, + { XML_NAMESPACE_TEXT, XML_ROTATION_ANGLE, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_STYLE, + XML_ROTATION_ANGLE ), 0, 0 }, + { XML_NAMESPACE_CHART, XML_INTERVAL_MAJOR, XML_PTACTION_INTERVAL_MAJOR, NO_PARAMS }, + { XML_NAMESPACE_CHART, XML_INTERVAL_MINOR, XML_PTACTION_INTERVAL_MINOR, NO_PARAMS }, + + { XML_NAMESPACE_CHART, XML_STOCK_UPDOWN_BARS, XML_ATACTION_RENAME, + XMLTransformerActionInit::QNameParam( XML_NAMESPACE_CHART, + XML_JAPANESE_CANDLE_STICK ), 0, 0 }, + { XML_NAMESPACE_CHART, XML_SYMBOL, XML_PTACTION_SYMBOL, NO_PARAMS }, + + // note: chart:symbol-image-name was only used before 6.0 beta + { XML_NAMESPACE_CHART, XML_SYMBOL_IMAGE_NAME, XML_PTACTION_SYMBOL_IMAGE_NAME, NO_PARAMS }, + + // #i32368# property should no longer be used as XML-property (in OASIS + // format), but is still ex-/imported for compatibility with the OOo file format + { XML_NAMESPACE_CHART, XML_LINES_USED, XML_ATACTION_COPY, NO_PARAMS }, + // #i32366# property should no longer be used as XML-property (in OASIS + // format), but is still ex-/imported for compatibility with the OOo file format + { XML_NAMESPACE_CHART, XML_STOCK_WITH_VOLUME, XML_ATACTION_COPY, NO_PARAMS }, + + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +XMLTransformerActionInit const aChartPropertyOOoElemActionTable[] = +{ + { XML_NAMESPACE_STYLE, XML_SYMBOL_IMAGE, XML_ATACTION_COPY, NO_PARAMS }, + { XML_NAMESPACE_OFFICE, XML_TOKEN_INVALID, XML_ATACTION_EOT, NO_PARAMS } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/PropertyActionsOOo.hxx b/xmloff/source/transform/PropertyActionsOOo.hxx new file mode 100644 index 000000000..e88bb1096 --- /dev/null +++ b/xmloff/source/transform/PropertyActionsOOo.hxx @@ -0,0 +1,67 @@ +/* -*- 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 "TransformerActionInit.hxx" +#include "AttrTransformerAction.hxx" + +enum XMLPropOOOTransformerAction +{ + XML_PTACTION_LINE_MODE = XML_ATACTION_USER_DEFINED, + XML_PTACTION_UNDERLINE, + XML_PTACTION_LINETHROUGH, + XML_PTACTION_KEEP_WITH_NEXT, + XML_PTACTION_SPLINES, + XML_ATACTION_INCH2IN_DUPLICATE, + XML_PTACTION_INTERVAL_MAJOR, + XML_PTACTION_INTERVAL_MINOR, + XML_ATACTION_COPY_DUPLICATE, + XML_PTACTION_SYMBOL, + XML_PTACTION_SYMBOL_IMAGE_NAME, + XML_PTACTION_TRANSPARENCY, + XML_PTACTION_BREAK_INSIDE, + XML_ATACTION_CAPTION_ESCAPE_OOO, + XML_ATACTION_MOVE_PROTECT, + XML_ATACTION_SIZE_PROTECT, + XML_ATACTION_PROTECT, + // No image transparency info in label document (#i50322#) + XML_ATACTION_WRITER_BACK_GRAPHIC_TRANSPARENCY +}; + +extern XMLTransformerActionInit const aGraphicPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aGraphicPropertyOOoElemActionTable[]; +extern XMLTransformerActionInit const aDrawingPagePropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aPageLayoutPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aHeaderFooterPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aTextPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aTextPropertyOOoElemActionTable[]; +extern XMLTransformerActionInit const aParagraphPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aParagraphPropertyOOoElemActionTable[]; +extern XMLTransformerActionInit const aSectionPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aTablePropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aTableColumnPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aTableRowPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aTableCellPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aTableCellPropertyOOoElemActionTable[]; +extern XMLTransformerActionInit const aListLevelPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aChartPropertyOOoAttrActionTable[]; +extern XMLTransformerActionInit const aChartPropertyOOoElemActionTable[]; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/RenameElemTContext.cxx b/xmloff/source/transform/RenameElemTContext.cxx new file mode 100644 index 000000000..5800d9346 --- /dev/null +++ b/xmloff/source/transform/RenameElemTContext.cxx @@ -0,0 +1,80 @@ +/* -*- 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 "RenameElemTContext.hxx" +#include "MutableAttrList.hxx" +#include "TransformerBase.hxx" +#include + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +XMLRenameElemTransformerContext::XMLRenameElemTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rImp.GetNamespaceMap().GetQNameByKey( nPrefix, + ::xmloff::token::GetXMLToken( eToken ) ) ) +{ +} + +XMLRenameElemTransformerContext::XMLRenameElemTransformerContext( + XMLTransformerBase& rImp, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nAPrefix, + ::xmloff::token::XMLTokenEnum eAToken, + ::xmloff::token::XMLTokenEnum eVToken ) : + XMLTransformerContext( rImp, rQName ), + m_aElemQName( rImp.GetNamespaceMap().GetQNameByKey( nPrefix, + ::xmloff::token::GetXMLToken( eToken ) ) ), + m_aAttrQName( rImp.GetNamespaceMap().GetQNameByKey( nAPrefix, + ::xmloff::token::GetXMLToken( eAToken ) ) ), + m_aAttrValue( ::xmloff::token::GetXMLToken( eVToken ) ) +{ +} + +XMLRenameElemTransformerContext::~XMLRenameElemTransformerContext() +{ +} + +void XMLRenameElemTransformerContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + Reference< XAttributeList > xAttrList( rAttrList ); + if( !m_aAttrQName.isEmpty() ) + { + rtl::Reference pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + pMutableAttrList->AddAttribute( m_aAttrQName, m_aAttrValue ); + } + GetTransformer().GetDocHandler()->startElement( m_aElemQName, xAttrList ); +} + +void XMLRenameElemTransformerContext::EndElement() +{ + GetTransformer().GetDocHandler()->endElement( m_aElemQName ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/RenameElemTContext.hxx b/xmloff/source/transform/RenameElemTContext.hxx new file mode 100644 index 000000000..70fe9d682 --- /dev/null +++ b/xmloff/source/transform/RenameElemTContext.hxx @@ -0,0 +1,61 @@ +/* -*- 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 +#include "TransformerContext.hxx" + + +class XMLRenameElemTransformerContext : public XMLTransformerContext +{ + OUString const m_aElemQName; + OUString const m_aAttrQName; + OUString const m_aAttrValue; + +public: + // The following constructor renames the element names "rQName" + // to bPrefix/eToken + XMLRenameElemTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ); + + // The following constructor renames the element names "rQName" + // to bPrefix/eToken and adds an attribute nAPrefix/eAToken that has + // the value eVToken. + XMLRenameElemTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + sal_uInt16 nAPrefix, + ::xmloff::token::XMLTokenEnum eAToken, + ::xmloff::token::XMLTokenEnum eVToken ); + + // A contexts destructor does anything that is required if an element + // ends. By default, nothing is done. + // Note that virtual methods cannot be used inside destructors. Use + // EndElement instead if this is required. + virtual ~XMLRenameElemTransformerContext() override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/StyleOASISTContext.cxx b/xmloff/source/transform/StyleOASISTContext.cxx new file mode 100644 index 000000000..75dd62db6 --- /dev/null +++ b/xmloff/source/transform/StyleOASISTContext.cxx @@ -0,0 +1,973 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "PropType.hxx" +#include "DeepTContext.hxx" +#include "TransformerBase.hxx" +#include "TransformerActions.hxx" +#include "ActionMapTypesOASIS.hxx" +#include "MutableAttrList.hxx" +#include "PropertyActionsOASIS.hxx" +#include "StyleOASISTContext.hxx" +#include + +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +const sal_uInt16 aAttrActionMaps[XML_PROP_TYPE_END] = +{ + PROP_OASIS_GRAPHIC_ATTR_ACTIONS, + PROP_OASIS_DRAWING_PAGE_ATTR_ACTIONS, // DRAWING_PAGE + PROP_OASIS_PAGE_LAYOUT_ATTR_ACTIONS, + PROP_OASIS_HEADER_FOOTER_ATTR_ACTIONS, + PROP_OASIS_TEXT_ATTR_ACTIONS, + PROP_OASIS_PARAGRAPH_ATTR_ACTIONS, + MAX_OASIS_PROP_ACTIONS, // RUBY + PROP_OASIS_SECTION_ATTR_ACTIONS, + PROP_OASIS_TABLE_ATTR_ACTIONS, + PROP_OASIS_TABLE_COLUMN_ATTR_ACTIONS, + PROP_OASIS_TABLE_ROW_ATTR_ACTIONS, + PROP_OASIS_TABLE_CELL_ATTR_ACTIONS, + PROP_OASIS_LIST_LEVEL_ATTR_ACTIONS, + PROP_OASIS_CHART_ATTR_ACTIONS +}; + +class XMLPropertiesTContext_Impl : public XMLPersElemContentTContext +{ + css::uno::Reference< css::xml::sax::XAttributeList > m_xAttrList; + + XMLPropType m_ePropType; + bool const m_bControlStyle; + +public: + + void SetQNameAndPropType( const OUString& rQName, + XMLPropType ePropType ) + { + m_ePropType = ePropType; + XMLTransformerContext::SetQName( rQName ); + }; + + XMLPropertiesTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName, + XMLPropType eP, + bool _bControlStyle ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void Export() override; + + static XMLPropType GetPropType( std::u16string_view rLocalName ); + + static OUString const & MergeUnderline( XMLTokenEnum eUnderline, + bool bBold, bool bDouble ); + static OUString const & MergeLineThrough( XMLTokenEnum eLineThrough, + bool bBold, bool bDouble, + sal_Unicode c ); +}; + +XMLPropertiesTContext_Impl::XMLPropertiesTContext_Impl( + XMLTransformerBase& rImp, const OUString& rQName, XMLPropType eP, + bool _bControlStyle ) : + XMLPersElemContentTContext( rImp, rQName, XML_NAMESPACE_STYLE, + XML_PROPERTIES), + m_ePropType( eP ), + m_bControlStyle( _bControlStyle ) +{ +} + +void XMLPropertiesTContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = nullptr; + sal_uInt16 nActionMap = aAttrActionMaps[m_ePropType]; + if( nActionMap < MAX_OASIS_PROP_ACTIONS ) + { + pActions = GetTransformer().GetUserDefinedActions( nActionMap ); + OSL_ENSURE( pActions, "go no actions" ); + } + + if( pActions ) + { + rtl::Reference pAttrList; + if( !m_xAttrList.is() ) + { + pAttrList = new XMLMutableAttributeList(); + m_xAttrList = pAttrList; + } + else + { + pAttrList = + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ); + } + + XMLTokenEnum eUnderline = XML_TOKEN_END; + bool bBoldUnderline = false, bDoubleUnderline = false; + XMLTokenEnum eLineThrough = XML_TOKEN_END; + bool bBoldLineThrough = false, bDoubleLineThrough = false; + sal_Unicode cLineThroughChar = 0; + + bool bIntervalMinorFound = false; + double fIntervalMajor = 0.0; + sal_Int32 nIntervalMinorDivisor = 0; + + // #i25616# + OUString aOpacityValueRemember; + OUString aImageOpacityValueRemember; + + sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = rAttrList->getNameByIndex( i ); + const OUString& rAttrValue = rAttrList->getValueByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_REMOVE: + break; + case XML_ATACTION_COPY: + pAttrList->AddAttribute( rAttrName, rAttrValue ); + break; + case XML_ATACTION_RENAME: + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + pAttrList->AddAttribute( aNewAttrQName, rAttrValue ); + } + break; + case XML_ATACTION_IN2INCH: + { + OUString aAttrValue( rAttrValue ); + XMLTransformerBase::ReplaceSingleInWithInch( + aAttrValue ); + pAttrList->AddAttribute( rAttrName, aAttrValue ); + } + break; + case XML_ATACTION_INS2INCHS: + { + OUString aAttrValue( rAttrValue ); + XMLTransformerBase::ReplaceInWithInch( + aAttrValue ); + pAttrList->AddAttribute( rAttrName, aAttrValue ); + } + break; + case XML_ATACTION_DECODE_STYLE_NAME_REF: + { + OUString aAttrValue( rAttrValue ); + XMLTransformerBase::DecodeStyleName(aAttrValue); + pAttrList->AddAttribute( rAttrName, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF: + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + OUString aAttrValue( rAttrValue ); + XMLTransformerBase::DecodeStyleName(aAttrValue); + pAttrList->AddAttribute( aNewAttrQName, aAttrValue ); + } + break; + case XML_ATACTION_NEG_PERCENT: + { + OUString aAttrValue( rAttrValue ); + XMLTransformerBase::NegPercent(aAttrValue); + pAttrList->AddAttribute( rAttrName, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_NEG_PERCENT: + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + OUString aAttrValue( rAttrValue ); + XMLTransformerBase::NegPercent(aAttrValue); + pAttrList->AddAttribute( aNewAttrQName, aAttrValue ); + } + break; + case XML_OPTACTION_LINE_MODE: + { + bool bWordMode = + IsXMLToken( rAttrValue, XML_SKIP_WHITE_SPACE ); + OUString aAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_FO, + GetXMLToken( XML_SCORE_SPACES ) ) ); + sal_Int16 nIndex = + pAttrList->GetIndexByName( aAttrQName ); + if( -1 != nIndex ) + { + if( bWordMode ) + { + const OUString& rOldValue = + pAttrList->getValueByIndex( nIndex ); + if( !IsXMLToken( rOldValue, XML_TRUE ) ) + { + pAttrList->SetValueByIndex( nIndex, + GetXMLToken( XML_TRUE ) ); + } + } + } + else + { + const OUString& aAttrValue( GetXMLToken( bWordMode + ? XML_FALSE + : XML_TRUE ) ); + pAttrList->AddAttribute( aAttrQName, aAttrValue ); + } + } + break; + case XML_OPTACTION_KEEP_WITH_NEXT: + { + const OUString& aAttrValue( GetXMLToken( + IsXMLToken( rAttrValue, XML_ALWAYS ) + ? XML_TRUE + : XML_FALSE) ); + pAttrList->AddAttribute( rAttrName, aAttrValue ); + } + break; + case XML_OPTACTION_UNDERLINE_WIDTH: + if( IsXMLToken( rAttrValue, XML_BOLD ) ) + bBoldUnderline = true; + break; + case XML_OPTACTION_UNDERLINE_TYPE: + if( IsXMLToken( rAttrValue, XML_DOUBLE ) ) + bDoubleUnderline = true; + break; + case XML_OPTACTION_UNDERLINE_STYLE: + eUnderline = GetTransformer().GetToken( rAttrValue ); + break; + case XML_OPTACTION_LINETHROUGH_WIDTH: + if( IsXMLToken( rAttrValue, XML_BOLD ) ) + bBoldLineThrough = true; + break; + case XML_OPTACTION_LINETHROUGH_TYPE: + if( IsXMLToken( rAttrValue, XML_DOUBLE ) ) + bDoubleLineThrough = true; + break; + case XML_OPTACTION_LINETHROUGH_STYLE: + eLineThrough = GetTransformer().GetToken( rAttrValue ); + break; + case XML_OPTACTION_LINETHROUGH_TEXT: + if( !rAttrValue.isEmpty() ) + cLineThroughChar = rAttrValue[0]; + break; + case XML_OPTACTION_INTERPOLATION: + { + // 0: none (default) + sal_Int32 nSplineType = 0; + if( IsXMLToken( rAttrValue, XML_CUBIC_SPLINE )) + nSplineType = 1; + else if( IsXMLToken( rAttrValue, XML_B_SPLINE )) + nSplineType = 2; + + pAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, + GetXMLToken( XML_SPLINES )), + OUString::number( nSplineType )); + } + break; + case XML_OPTACTION_INTERVAL_MAJOR: + pAttrList->AddAttribute( rAttrName, rAttrValue ); + ::sax::Converter::convertDouble(fIntervalMajor, rAttrValue); + break; + case XML_OPTACTION_INTERVAL_MINOR_DIVISOR: + ::sax::Converter::convertNumber(nIntervalMinorDivisor, rAttrValue); + bIntervalMinorFound = true; + break; + case XML_OPTACTION_SYMBOL_TYPE: + { + // if symbol_type is "named-symbol" the "symbol" + // property is set in the action XML_OPTACTION_SYMBOL_NAME + sal_Int32 nSymbolType = 0; + if( IsXMLToken( rAttrValue, XML_NONE )) + nSymbolType = -3; + else if( IsXMLToken( rAttrValue, XML_AUTOMATIC )) + nSymbolType = -2; + else if( IsXMLToken( rAttrValue, XML_IMAGE )) + nSymbolType = -1; + + if( nSymbolType < 0 ) + pAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, + GetXMLToken( XML_SYMBOL )), + OUString::number( nSymbolType )); + } + break; + case XML_OPTACTION_SYMBOL_NAME: + { + // assume "symbol-type" == "named-symbol" + sal_Int32 nSymbolType = -3; // NONE + // "square" just has an awkward token-name + if( IsXMLToken( rAttrValue, XML_GRADIENTSTYLE_SQUARE )) + nSymbolType = 0; + else if( IsXMLToken( rAttrValue, XML_DIAMOND )) + nSymbolType = 1; + else if( IsXMLToken( rAttrValue, XML_ARROW_DOWN )) + nSymbolType = 2; + else if( IsXMLToken( rAttrValue, XML_ARROW_UP )) + nSymbolType = 3; + else if( IsXMLToken( rAttrValue, XML_ARROW_RIGHT )) + nSymbolType = 4; + else if( IsXMLToken( rAttrValue, XML_ARROW_LEFT )) + nSymbolType = 5; + else if( IsXMLToken( rAttrValue, XML_BOW_TIE )) + nSymbolType = 6; + else if( IsXMLToken( rAttrValue, XML_HOURGLASS )) + nSymbolType = 7; + else if( IsXMLToken( rAttrValue, XML_CIRCLE )) + nSymbolType = 8; + else if( IsXMLToken( rAttrValue, XML_STAR )) + nSymbolType = 9; + else if( IsXMLToken( rAttrValue, XML_X )) + nSymbolType = 10; + else if( IsXMLToken( rAttrValue, XML_PLUS )) + nSymbolType = 11; + else if( IsXMLToken( rAttrValue, XML_ASTERISK )) + nSymbolType = 12; + else if( IsXMLToken( rAttrValue, XML_HORIZONTAL_BAR )) + nSymbolType = 13; + else if( IsXMLToken( rAttrValue, XML_VERTICAL_BAR )) + nSymbolType = 14; + + if( nSymbolType >= 0 ) + pAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, + GetXMLToken( XML_SYMBOL )), + OUString::number( nSymbolType )); + } + break; + // #i25616# + case XML_OPTACTION_OPACITY: + aOpacityValueRemember = rAttrValue; + XMLTransformerBase::NegPercent(aOpacityValueRemember); + break; + + // #i25616# + case XML_OPTACTION_IMAGE_OPACITY: + aImageOpacityValueRemember = rAttrValue; + XMLTransformerBase::NegPercent(aImageOpacityValueRemember); + break; + + case XML_OPTACTION_KEEP_TOGETHER: + pAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE,GetXMLToken(XML_BREAK_INSIDE)), + GetXMLToken( + IsXMLToken( rAttrValue, XML_ALWAYS ) + ? XML_COLUMNSPLIT_AVOID + : XML_AUTO ) ); + break; + + case XML_OPTACTION_CONTROL_TEXT_ALIGN: + if ( m_bControlStyle ) + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + ::xmloff::token::GetXMLToken( + XML_TEXT_ALIGN ) ) ); + pAttrList->AddAttribute( aNewAttrQName, rAttrValue ); + } + else + { + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_FO, + ::xmloff::token::GetXMLToken( + XML_TEXT_ALIGN ) ) ); + pAttrList->AddAttribute( aNewAttrQName, rAttrValue ); + } + break; + + case XML_ATACTION_CAPTION_ESCAPE_OASIS: + { + OUString aAttrValue( rAttrValue ); + if( aAttrValue.indexOf( '%' ) != -1 ) + { + sal_Int32 nValue = 0; + ::sax::Converter::convertPercent(nValue, rAttrValue); + if( nValue ) + { + nValue *= 100; + OUStringBuffer aOut; + ::sax::Converter::convertPercent(aOut, nValue); + aAttrValue = aOut.makeStringAndClear(); + } + } + else + { + XMLTransformerBase::ReplaceSingleInWithInch( aAttrValue ); + } + + pAttrList->AddAttribute( rAttrName, aAttrValue ); + } + break; + + case XML_ATACTION_DECODE_PROTECT: + { + pAttrList->AddAttribute( rAttrName, rAttrValue ); + + if( rAttrValue.indexOf( GetXMLToken( XML_SIZE ) ) != -1 ) + pAttrList->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DRAW, + GetXMLToken( XML_SIZE_PROTECT )), GetXMLToken( XML_TRUE ) ); + + if( rAttrValue.indexOf( GetXMLToken( XML_POSITION ) ) != -1 ) + pAttrList->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DRAW, + GetXMLToken( XML_MOVE_PROTECT )), GetXMLToken( XML_TRUE ) ); + } + break; + + case XML_ATACTION_DRAW_MIRROR_OASIS: // renames style:mirror to draw:mirror and adapts values + { + // keep original for writer graphic objects + // Adapts attribute values (#i49139#) + OUStringBuffer aNewAttrValue; + SvXMLTokenEnumerator aTokenEnum( rAttrValue ); + std::u16string_view aToken; + while( aTokenEnum.getNextToken( aToken ) ) + { + if ( !aNewAttrValue.isEmpty() ) + { + aNewAttrValue.append(" "); + } + + if ( IsXMLToken( aToken, XML_HORIZONTAL_ON_EVEN ) ) + { + aNewAttrValue.append(GetXMLToken( XML_HORIZONTAL_ON_LEFT_PAGES )); + } + else if ( IsXMLToken( aToken, XML_HORIZONTAL_ON_ODD ) ) + { + aNewAttrValue.append(GetXMLToken( XML_HORIZONTAL_ON_RIGHT_PAGES )); + } + else + { + aNewAttrValue.append(aToken); + } + } + pAttrList->AddAttribute( rAttrName, aNewAttrValue.makeStringAndClear() ); + + // create old draw:mirror for drawing graphic objects + const OUString& aAttrValue( GetXMLToken( IsXMLToken( rAttrValue, XML_HORIZONTAL ) ? XML_TRUE : XML_FALSE ) ); + pAttrList->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DRAW, + GetXMLToken( XML_MIRROR )), aAttrValue ); + } + break; + case XML_ATACTION_GAMMA_OASIS: // converts percentage value to double + { + sal_Int32 nValue; + ::sax::Converter::convertPercent( nValue, rAttrValue ); + const double fValue = static_cast(nValue) / 100.0; + pAttrList->AddAttribute( rAttrName, OUString::number( fValue ) ); + } + break; + case XML_ATACTION_OPACITY_FIX: + { + sal_Int32 nValue; + if( rAttrValue.indexOf( '%' ) != -1 ) + { + ::sax::Converter::convertPercent(nValue, rAttrValue); + } + else + { + nValue = sal_Int32( rAttrValue.toDouble() * 100.0 ); + } + nValue = 100 - nValue; + + OUStringBuffer aOut; + ::sax::Converter::convertPercent(aOut, nValue); + pAttrList->AddAttribute( rAttrName, aOut.makeStringAndClear() ); + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + else + { + pAttrList->AddAttribute( rAttrName, rAttrValue ); + } + } + if( XML_TOKEN_END != eUnderline ) + pAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_UNDERLINE ) ), + MergeUnderline( eUnderline, bBoldUnderline, + bDoubleUnderline ) ); + if( XML_TOKEN_END != eLineThrough ) + pAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_CROSSING_OUT ) ), + MergeLineThrough( eLineThrough, bBoldLineThrough, + bDoubleLineThrough, cLineThroughChar ) ); + if( bIntervalMinorFound ) + { + double fIntervalMinor = 0.0; + if( nIntervalMinorDivisor != 0) + fIntervalMinor = fIntervalMajor / static_cast< double >( nIntervalMinorDivisor ); + + OUStringBuffer aBuf; + ::sax::Converter::convertDouble( aBuf, fIntervalMinor ); + pAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, + GetXMLToken( XML_INTERVAL_MINOR )), + aBuf.makeStringAndClear()); + } + + // #i25616# + if(!aOpacityValueRemember.isEmpty() || !aImageOpacityValueRemember.isEmpty()) + { + pAttrList->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_DRAW, + GetXMLToken( XML_TRANSPARENCY ) ), + !aImageOpacityValueRemember.isEmpty() + ? aImageOpacityValueRemember : aOpacityValueRemember ); + } + } + else + { + if( !m_xAttrList.is() ) + { + m_xAttrList = new XMLMutableAttributeList( rAttrList, true ); + } + else + { + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) + ->AppendAttributeList( rAttrList ); + } + } +} + +void XMLPropertiesTContext_Impl::Export() +{ + GetTransformer().GetDocHandler()->startElement( GetExportQName(), m_xAttrList ); + ExportContent(); + GetTransformer().GetDocHandler()->endElement( GetExportQName() ); +} + +XMLPropType XMLPropertiesTContext_Impl::GetPropType( std::u16string_view rLocalName ) +{ + XMLPropType eProp = XML_PROP_TYPE_END; + if( IsXMLToken( rLocalName, XML_GRAPHIC_PROPERTIES ) ) + eProp = XML_PROP_TYPE_GRAPHIC; + else if( IsXMLToken( rLocalName, XML_DRAWING_PAGE_PROPERTIES ) ) + eProp = XML_PROP_TYPE_DRAWING_PAGE; + else if( IsXMLToken( rLocalName, XML_PAGE_LAYOUT_PROPERTIES ) ) + eProp = XML_PROP_TYPE_PAGE_LAYOUT; + else if( IsXMLToken( rLocalName, XML_HEADER_FOOTER_PROPERTIES ) ) + eProp = XML_PROP_TYPE_HEADER_FOOTER; + else if( IsXMLToken( rLocalName, XML_TEXT_PROPERTIES ) ) + eProp = XML_PROP_TYPE_TEXT; + else if( IsXMLToken( rLocalName, XML_PARAGRAPH_PROPERTIES ) ) + eProp = XML_PROP_TYPE_PARAGRAPH; + else if( IsXMLToken( rLocalName, XML_RUBY_PROPERTIES ) ) + eProp = XML_PROP_TYPE_RUBY; + else if( IsXMLToken( rLocalName, XML_SECTION_PROPERTIES ) ) + eProp = XML_PROP_TYPE_SECTION; + else if( IsXMLToken( rLocalName, XML_TABLE_PROPERTIES ) ) + eProp = XML_PROP_TYPE_TABLE; + else if( IsXMLToken( rLocalName, XML_TABLE_COLUMN_PROPERTIES ) ) + eProp = XML_PROP_TYPE_TABLE_COLUMN; + else if( IsXMLToken( rLocalName, XML_TABLE_ROW_PROPERTIES ) ) + eProp = XML_PROP_TYPE_TABLE_ROW; + else if( IsXMLToken( rLocalName, XML_TABLE_CELL_PROPERTIES ) ) + eProp = XML_PROP_TYPE_TABLE_CELL; + else if( IsXMLToken( rLocalName, XML_LIST_LEVEL_PROPERTIES ) ) + eProp = XML_PROP_TYPE_LIST_LEVEL; + else if( IsXMLToken( rLocalName, XML_CHART_PROPERTIES ) ) + eProp = XML_PROP_TYPE_CHART; + + return eProp; +} + +OUString const & XMLPropertiesTContext_Impl::MergeUnderline( + XMLTokenEnum eUnderline, bool bBold, bool bDouble ) +{ + if( bDouble ) + { + switch( eUnderline ) + { + case XML_WAVE: + eUnderline = XML_DOUBLE_WAVE; + break; + default: + eUnderline = XML_DOUBLE; + break; + } + } + else if( bBold ) + { + switch( eUnderline ) + { + case XML_NONE: + case XML_SOLID: + eUnderline = XML_BOLD; + break; + case XML_DOTTED: + eUnderline = XML_BOLD_DOTTED; + break; + case XML_DASH: + eUnderline = XML_BOLD_DASH; + break; + case XML_LONG_DASH: + eUnderline = XML_BOLD_LONG_DASH; + break; + case XML_DOT_DASH: + eUnderline = XML_BOLD_DOT_DASH; + break; + case XML_DOT_DOT_DASH: + eUnderline = XML_BOLD_DOT_DOT_DASH; + break; + case XML_WAVE: + eUnderline = XML_BOLD_WAVE; + break; + default: + OSL_FAIL( "xmloff::XMLPropertiesTContext_Impl::MergeUnderline(), missing underline case!" ); + break; + } + } + else + { + switch( eUnderline ) + { + case XML_SOLID: + eUnderline = XML_SINGLE; + break; + case XML_NONE: + eUnderline = XML_NONE; + break; + default: + OSL_FAIL( "xmloff::XMLPropertiesTContext_Impl::MergeUnderline(), missing underline case!" ); + break; + } + } + + return GetXMLToken( eUnderline ); +} + +OUString const & XMLPropertiesTContext_Impl::MergeLineThrough( + XMLTokenEnum eLineThrough, bool bBold, bool bDouble, + sal_Unicode c ) +{ + if( c ) + eLineThrough = c=='/' ? XML_SLASH : XML_uX; + else if( bDouble ) + eLineThrough = XML_DOUBLE_LINE; + else if( bBold ) + eLineThrough = XML_THICK_LINE; + else if( XML_NONE != eLineThrough ) + eLineThrough = XML_SINGLE_LINE; + + return GetXMLToken( eLineThrough ); +} + +XMLStyleOASISTContext::XMLStyleOASISTContext(XMLTransformerBase& rImp, + const OUString& rQName, bool bPersistent) + : XMLPersElemContentTContext(rImp, rQName) + , m_bPersistent(bPersistent) + , m_bControlStyle(false) +{ +} + +XMLStyleOASISTContext::XMLStyleOASISTContext( + XMLTransformerBase& rImp, const OUString& rQName, + sal_uInt16 nPrefix, ::xmloff::token::XMLTokenEnum eToken, + bool bPersistent) + : XMLPersElemContentTContext(rImp, rQName, nPrefix, eToken) + , m_bPersistent(bPersistent) + , m_bControlStyle(false) +{ +} + +XMLStyleOASISTContext::~XMLStyleOASISTContext() +{ +} + +rtl::Reference XMLStyleOASISTContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& rAttrList ) +{ + rtl::Reference pContext; + + if( XML_NAMESPACE_STYLE == nPrefix || XML_NAMESPACE_LO_EXT == nPrefix ) + { + XMLPropType ePropType = + XMLPropertiesTContext_Impl::GetPropType( rLocalName ); + if( XML_PROP_TYPE_END != ePropType ) + { + // if no properties context exist start a new one. + if( !m_xPropContext.is() ) + m_xPropContext = new XMLPropertiesTContext_Impl( + GetTransformer(), rQName, ePropType, m_bControlStyle ); + else + m_xPropContext->SetQNameAndPropType( rQName, ePropType ); + pContext = m_xPropContext; + } + } + if( !pContext.is() ) + { + // if a properties context exist close it + if( m_xPropContext.is() && !m_bPersistent ) + { + m_xPropContext->Export(); + m_xPropContext = nullptr; + } + + pContext = m_bPersistent + ? XMLPersElemContentTContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ) + : XMLTransformerContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ); + } + + return pContext; +} + +void XMLStyleOASISTContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OASIS_STYLE_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + sal_Int16 nFamilyAttr = -1; + m_bControlStyle = false; + + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_STYLE_FAMILY: + if( IsXMLToken( rAttrValue, XML_GRAPHIC ) ) + { + pMutableAttrList->SetValueByIndex( + i, GetXMLToken(XML_GRAPHICS) ); + } + else + { + if( IsXMLToken( rAttrValue, XML_PARAGRAPH ) ) + nFamilyAttr = i; + } + + break; + case XML_ATACTION_STYLE_DISPLAY_NAME: + case XML_ATACTION_REMOVE: + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + break; + case XML_ATACTION_DECODE_STYLE_NAME: + m_bControlStyle = rAttrValue.startsWith( "ctrl" ); + [[fallthrough]]; + case XML_ATACTION_DECODE_STYLE_NAME_REF: + { + OUString aAttrValue( rAttrValue ); + if( XMLTransformerBase::DecodeStyleName(aAttrValue) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_IN2INCH: + { + OUString aAttrValue( rAttrValue ); + if( XMLTransformerBase::ReplaceSingleInWithInch( + aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_NEG_PERCENT: + { + OUString aAttrValue( rAttrValue ); + if( XMLTransformerBase::NegPercent(aAttrValue) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_URI_OASIS: + { + OUString aAttrValue( rAttrValue ); + if( GetTransformer().ConvertURIToOOo( aAttrValue, + static_cast< bool >((*aIter).second.m_nParam1))) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + + if( m_bControlStyle && nFamilyAttr != -1 ) + pMutableAttrList->SetValueByIndex( nFamilyAttr, GetXMLToken( XML_CONTROL ) ); + + if( m_bPersistent ) + XMLPersElemContentTContext::StartElement( xAttrList ); + else + GetTransformer().GetDocHandler()->startElement( GetExportQName(), xAttrList ); +} + +void XMLStyleOASISTContext::EndElement() +{ + if( m_bPersistent ) + { + XMLPersElemContentTContext::EndElement(); + } + else + { + // if a properties context exist close it + if( m_xPropContext.is() ) + { + m_xPropContext->Export(); + m_xPropContext = nullptr; + } + GetTransformer().GetDocHandler()->endElement( GetExportQName() ); + } +} + +void XMLStyleOASISTContext::Characters( const OUString& ) +{ + // element content only: +} + +void XMLStyleOASISTContext::ExportContent() +{ + if( m_xPropContext.is() ) + m_xPropContext->Export(); + XMLPersElemContentTContext::ExportContent(); +} + +bool XMLStyleOASISTContext::IsPersistent() const +{ + return m_bPersistent; +} + +XMLTransformerActions *XMLStyleOASISTContext::CreateTransformerActions( + sal_uInt16 nType ) +{ + XMLTransformerActionInit const *pInit = nullptr; + + switch( nType ) + { + case PROP_OASIS_GRAPHIC_ATTR_ACTIONS: + pInit = aGraphicPropertyOASISAttrActionTable; + break; + case PROP_OASIS_DRAWING_PAGE_ATTR_ACTIONS: + pInit = aDrawingPagePropertyOASISAttrActionTable; + break; + case PROP_OASIS_PAGE_LAYOUT_ATTR_ACTIONS: + pInit = aPageLayoutPropertyOASISAttrActionTable; + break; + case PROP_OASIS_HEADER_FOOTER_ATTR_ACTIONS: + pInit = aHeaderFooterPropertyOASISAttrActionTable; + break; + case PROP_OASIS_TEXT_ATTR_ACTIONS: + pInit = aTextPropertyOASISAttrActionTable; + break; + case PROP_OASIS_PARAGRAPH_ATTR_ACTIONS: + pInit = aParagraphPropertyOASISAttrActionTable; + break; + case PROP_OASIS_SECTION_ATTR_ACTIONS: + pInit = aSectionPropertyOASISAttrActionTable; + break; + case PROP_OASIS_TABLE_ATTR_ACTIONS: + pInit = aTablePropertyOASISAttrActionTable; + break; + case PROP_OASIS_TABLE_COLUMN_ATTR_ACTIONS: + pInit = aTableColumnPropertyOASISAttrActionTable; + break; + case PROP_OASIS_TABLE_ROW_ATTR_ACTIONS: + pInit = aTableRowPropertyOASISAttrActionTable; + break; + case PROP_OASIS_TABLE_CELL_ATTR_ACTIONS: + pInit = aTableCellPropertyOASISAttrActionTable; + break; + case PROP_OASIS_LIST_LEVEL_ATTR_ACTIONS: + pInit = aListLevelPropertyOASISAttrActionTable; + break; + case PROP_OASIS_CHART_ATTR_ACTIONS: + pInit = aChartPropertyOASISAttrActionTable; + break; + } + + XMLTransformerActions *pActions = nullptr; + if( pInit ) + pActions = new XMLTransformerActions( pInit ); + + return pActions; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/StyleOASISTContext.hxx b/xmloff/source/transform/StyleOASISTContext.hxx new file mode 100644 index 000000000..0cc3cf2fd --- /dev/null +++ b/xmloff/source/transform/StyleOASISTContext.hxx @@ -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/. + * + * 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 +#include "DeepTContext.hxx" + + +class XMLTransformerActions; +class XMLPropertiesTContext_Impl; +class XMLStyleOASISTContext : public XMLPersElemContentTContext +{ + ::rtl::Reference< XMLPropertiesTContext_Impl > m_xPropContext; + + bool const m_bPersistent; + bool m_bControlStyle; + +public: + XMLStyleOASISTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + bool bPersistent ); + XMLStyleOASISTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + bool bPersistent ); + + virtual ~XMLStyleOASISTContext() override; + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + virtual void Characters( const OUString& rChars ) override; + + virtual void ExportContent() override; + + virtual bool IsPersistent() const override; + + static XMLTransformerActions *CreateTransformerActions( sal_uInt16 nType ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/StyleOOoTContext.cxx b/xmloff/source/transform/StyleOOoTContext.cxx new file mode 100644 index 000000000..c9c9220ad --- /dev/null +++ b/xmloff/source/transform/StyleOOoTContext.cxx @@ -0,0 +1,1342 @@ +/* -*- 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 +#include +#include + +#include + +#include +#include +#include +#include "PropType.hxx" +#include "DeepTContext.hxx" +#include "RenameElemTContext.hxx" +#include "ActionMapTypesOOo.hxx" +#include "MutableAttrList.hxx" +#include "TransformerActions.hxx" +#include "PropertyActionsOOo.hxx" +#include "TransformerBase.hxx" + +#include "StyleOOoTContext.hxx" +#include +#include +#include +#include +#include +#include + +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +const sal_uInt16 MAX_PROP_TYPES = 4; +#define ENTRY4(a,b,c,d) \ + { XML_PROP_TYPE_##a, XML_PROP_TYPE_##b, \ + XML_PROP_TYPE_##c, XML_PROP_TYPE_##d } +#define ENTRY3(a,b,c) \ + { XML_PROP_TYPE_##a, XML_PROP_TYPE_##b, \ + XML_PROP_TYPE_##c, XML_PROP_TYPE_END } +#define ENTRY2(a,b) \ + { XML_PROP_TYPE_##a, XML_PROP_TYPE_##b, \ + XML_PROP_TYPE_END, XML_PROP_TYPE_END } +#define ENTRY1(a) \ + { XML_PROP_TYPE_##a, XML_PROP_TYPE_##END, \ + XML_PROP_TYPE_END, XML_PROP_TYPE_END } + +const std::array aPropTypes[XML_FAMILY_TYPE_END] = +{ + ENTRY3( GRAPHIC, PARAGRAPH, TEXT ), // XML_FAMILY_TYPE_GRAPHIC, + ENTRY3( GRAPHIC, PARAGRAPH, TEXT ), // XML_FAMILY_TYPE_PRESENTATION, + ENTRY1( DRAWING_PAGE ), // XML_FAMILY_TYPE_DRAWING_PAGE, + ENTRY1( END ), // XML_FAMILY_TYPE_MASTER_PAGE + ENTRY1( PAGE_LAYOUT ), // XML_FAMILY_TYPE_PAGE_LAYOUT, + ENTRY1( HEADER_FOOTER ), // XML_FAMILY_TYPE_HEADER_FOOTER + ENTRY1( TEXT ), // XML_FAMILY_TYPE_TEXT, + ENTRY2( PARAGRAPH, TEXT ), // XML_FAMILY_TYPE_PARAGRAPH, + ENTRY1( RUBY ), //XML_FAMILY_TYPE_RUBY, + ENTRY1( SECTION ), // XML_FAMILY_TYPE_SECTION, + ENTRY1( TABLE ), // XML_FAMILY_TYPE_TABLE, + ENTRY1( TABLE_COLUMN ), // XML_FAMILY_TYPE_TABLE_COLUMN, + ENTRY1( TABLE_ROW ), // XML_FAMILY_TYPE_TABLE_ROW, + ENTRY3( TABLE_CELL, PARAGRAPH, TEXT ), // XML_FAMILY_TYPE_TABLE_CELL, + ENTRY1( LIST_LEVEL ), // XML_FAMILY_TYPE_LIST, + ENTRY4( CHART, GRAPHIC, PARAGRAPH, TEXT ), // XML_FAMILY_TYPE_CHART, + ENTRY1( TEXT ), // XML_FAMILY_TYPE_DATA, + ENTRY1( END ), // XML_FAMILY_TYPE_GRADIENT, + ENTRY1( END ), // XML_FAMILY_TYPE_HATCH, + ENTRY1( END ), // XML_FAMILY_TYPE_FILL_IMAGE, + ENTRY1( END ), // XML_FAMILY_TYPE_STROKE_DASH, + ENTRY1( END ), // XML_FAMILY_TYPE_MARKER, +}; + +const XMLTokenEnum aPropTokens[XML_PROP_TYPE_END] = +{ + XML_GRAPHIC_PROPERTIES, + XML_DRAWING_PAGE_PROPERTIES, + XML_PAGE_LAYOUT_PROPERTIES, + XML_HEADER_FOOTER_PROPERTIES, + XML_TEXT_PROPERTIES, + XML_PARAGRAPH_PROPERTIES, + XML_RUBY_PROPERTIES, + XML_SECTION_PROPERTIES, + XML_TABLE_PROPERTIES, + XML_TABLE_COLUMN_PROPERTIES, + XML_TABLE_ROW_PROPERTIES, + XML_TABLE_CELL_PROPERTIES, + XML_LIST_LEVEL_PROPERTIES, + XML_CHART_PROPERTIES +}; + +const sal_uInt16 aAttrActionMaps[XML_PROP_TYPE_END] = +{ + PROP_OOO_GRAPHIC_ATTR_ACTIONS, + PROP_OOO_DRAWING_PAGE_ATTR_ACTIONS, // DRAWING_PAGE + PROP_OOO_PAGE_LAYOUT_ATTR_ACTIONS, + PROP_OOO_HEADER_FOOTER_ATTR_ACTIONS, + PROP_OOO_TEXT_ATTR_ACTIONS, + PROP_OOO_PARAGRAPH_ATTR_ACTIONS, + MAX_OOO_PROP_ACTIONS, // RUBY + PROP_OOO_SECTION_ATTR_ACTIONS, + PROP_OOO_TABLE_ATTR_ACTIONS, + PROP_OOO_TABLE_COLUMN_ATTR_ACTIONS, + PROP_OOO_TABLE_ROW_ATTR_ACTIONS, + PROP_OOO_TABLE_CELL_ATTR_ACTIONS, + PROP_OOO_LIST_LEVEL_ATTR_ACTIONS, + PROP_OOO_CHART_ATTR_ACTIONS +}; + +const sal_uInt16 aElemActionMaps[XML_PROP_TYPE_END] = +{ + PROP_OOO_GRAPHIC_ELEM_ACTIONS, + MAX_OOO_PROP_ACTIONS, + MAX_OOO_PROP_ACTIONS, + MAX_OOO_PROP_ACTIONS, + PROP_OOO_TEXT_ELEM_ACTIONS, + PROP_OOO_PARAGRAPH_ELEM_ACTIONS, + MAX_OOO_PROP_ACTIONS, + MAX_OOO_PROP_ACTIONS, + MAX_OOO_PROP_ACTIONS, + MAX_OOO_PROP_ACTIONS, + MAX_OOO_PROP_ACTIONS, + PROP_OOO_TABLE_CELL_ELEM_ACTIONS, + MAX_OOO_PROP_ACTIONS, + PROP_OOO_CHART_ELEM_ACTIONS +}; + +namespace { + +class XMLTypedPropertiesOOoTContext_Impl : public XMLPersElemContentTContext +{ + css::uno::Reference< css::xml::sax::XAttributeList > m_xAttrList; + +public: + XMLTypedPropertiesOOoTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + using XMLPersAttrListTContext::AddAttribute; + void AddAttribute( const OUString &sName , + const OUString &sValue ); + void AddAttribute( sal_uInt16 nPrefix, XMLTokenEnum eToken, + const OUString &sValue ); + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& rAttrList ) override; + + virtual void Export() override; +}; + +} + +XMLTypedPropertiesOOoTContext_Impl::XMLTypedPropertiesOOoTContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName ) : + XMLPersElemContentTContext( rImp, rQName ), + m_xAttrList( new XMLMutableAttributeList() ) +{ +} + +void XMLTypedPropertiesOOoTContext_Impl::AddAttribute( + const OUString &sName , + const OUString &sValue ) +{ + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) + ->AddAttribute( sName, sValue ); +} + +void XMLTypedPropertiesOOoTContext_Impl::AddAttribute( + sal_uInt16 nPrefix, XMLTokenEnum eToken, + const OUString &sValue ) +{ + OUString sName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + nPrefix, ::xmloff::token::GetXMLToken( eToken ) ) ); + static_cast< XMLMutableAttributeList * >( m_xAttrList.get() ) + ->AddAttribute( sName, sValue ); +} + +void XMLTypedPropertiesOOoTContext_Impl::StartElement( + const Reference< XAttributeList >& ) +{ + // empty, ignore even the attribute list +} + +void XMLTypedPropertiesOOoTContext_Impl::Export() +{ + if( m_xAttrList->getLength() || HasElementContent() ) + { + GetTransformer().GetDocHandler()->startElement( GetQName(), m_xAttrList ); + ExportContent(); + GetTransformer().GetDocHandler()->endElement( GetQName() ); + } +} + +namespace { + +class XMLPropertiesOOoTContext_Impl : public XMLTransformerContext +{ + ::rtl::Reference < XMLTypedPropertiesOOoTContext_Impl > + m_aPropContexts[MAX_PROP_TYPES]; + + using XMLPropTypes = std::array; + + XMLPropTypes const & m_rPropTypes; + + bool const m_bPersistent; + + XMLTypedPropertiesOOoTContext_Impl *GetPropContextAndAction( + TransformerAction_Impl& rAction, + sal_uInt16 nPrefix, const OUString& rLocalName, + bool bElem ); + + XMLTypedPropertiesOOoTContext_Impl *GetPropContext( + XMLPropType eType ); + +public: + XMLPropertiesOOoTContext_Impl( XMLTransformerBase& rTransformer, + const OUString& rQName, + const XMLPropTypes& rTypes, + bool bPersistent ); + + rtl::Reference CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& rAttrList ) override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& rAttrList ) override; + + virtual void EndElement() override; + + virtual void Characters( const OUString& rChars ) override; + + virtual void Export() override; + + virtual bool IsPersistent() const override; +}; + +} + +XMLTypedPropertiesOOoTContext_Impl + *XMLPropertiesOOoTContext_Impl::GetPropContext( + XMLPropType eType ) +{ + sal_uInt16 nIndex = MAX_PROP_TYPES; + for( sal_uInt16 i=0; i< MAX_PROP_TYPES; i++ ) + { + if( m_rPropTypes[i] == eType ) + { + nIndex = i; + break; + } + } + if( MAX_PROP_TYPES == nIndex ) + return nullptr; + + if( !m_aPropContexts[nIndex].is() ) + { + m_aPropContexts[nIndex] = + new XMLTypedPropertiesOOoTContext_Impl( + GetTransformer(), + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + ::xmloff::token::GetXMLToken( + aPropTokens[m_rPropTypes[nIndex]] ) )); + } + + return m_aPropContexts[nIndex].get(); +} + +XMLTypedPropertiesOOoTContext_Impl + *XMLPropertiesOOoTContext_Impl::GetPropContextAndAction( + TransformerAction_Impl& rAction, + sal_uInt16 nPrefix, const OUString& rLocalName, + bool bElem ) +{ + rAction.m_nActionType = XML_ATACTION_COPY; + sal_uInt16 nIndex = 0; + + XMLTransformerActions::key_type aKey( nPrefix, rLocalName ); + sal_uInt16 i=0; + while( i < MAX_PROP_TYPES && XML_PROP_TYPE_END!=m_rPropTypes[i]) + { + sal_uInt16 nActionMap = + (bElem ? aElemActionMaps : aAttrActionMaps)[m_rPropTypes[i]]; + if( nActionMap < MAX_OOO_PROP_ACTIONS ) + { + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( nActionMap ); + OSL_ENSURE( pActions, "go no actions" ); + if( pActions ) + { + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + + if( aIter != pActions->end() ) + { + rAction = (*aIter).second; + nIndex = i; + break; + } + } + } + ++i; + } + +#ifdef DBG_UTIL + if( !( XML_NAMESPACE_NONE == nPrefix || + (XML_NAMESPACE_UNKNOWN_FLAG & nPrefix) || + XML_PROP_TYPE_END==m_rPropTypes[1] || + (i" ); + } +#endif + + if( !m_aPropContexts[nIndex].is() ) + { + m_aPropContexts[nIndex] = + new XMLTypedPropertiesOOoTContext_Impl( + GetTransformer(), + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + ::xmloff::token::GetXMLToken( + aPropTokens[m_rPropTypes[nIndex]] ) )); + } + + return m_aPropContexts[nIndex].get(); +} + +XMLPropertiesOOoTContext_Impl::XMLPropertiesOOoTContext_Impl( + XMLTransformerBase& rImp, + const OUString& rQName, + const XMLPropTypes& rTypes, + bool bPersistent ) : + XMLTransformerContext( rImp, rQName ), + // remember the types that belong to the attribute and element lists + m_rPropTypes(rTypes), + m_bPersistent( bPersistent ) +{ +} + +rtl::Reference XMLPropertiesOOoTContext_Impl::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& rAttrList ) +{ + TransformerAction_Impl aAction; + return GetPropContextAndAction( aAction, nPrefix, rLocalName, true ) + ->CreateChildContext( nPrefix, rLocalName, rQName, rAttrList ); +} + +void XMLPropertiesOOoTContext_Impl::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTypedPropertiesOOoTContext_Impl * pIntervalMinorDivisorContext = nullptr; + double fIntervalMajor = 0.0; + double fIntervalMinor = 0.0; + bool bMoveProtect = false; + bool bSizeProtect = false; + OUString aProtectAttrValue; + XMLTypedPropertiesOOoTContext_Impl * pProtectContext = nullptr; + + /* Attribute has to be priority over attribute . + The filter from OpenDocument file format to OpenOffice.org file format + produces styles with both attributes. (#i49139#) + */ + bool bExistStyleMirror( false ); + OUStringBuffer aStyleMirrorAttrValue; + bool bExistDrawMirror( false ); + OUString aDrawMirrorAttrValue; + XMLTypedPropertiesOOoTContext_Impl* pMirrorContext( nullptr ); + + sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString sAttrName = rAttrList->getNameByIndex( i ); + const OUString sAttrValue = rAttrList->getValueByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( sAttrName, + &aLocalName ); + TransformerAction_Impl aAction; + XMLTypedPropertiesOOoTContext_Impl *pContext = + GetPropContextAndAction( aAction, nPrefix, aLocalName, false ); + switch( aAction.m_nActionType ) + { + case XML_ATACTION_REMOVE: + break; + case XML_ATACTION_COPY: + pContext->AddAttribute( sAttrName, sAttrValue ); + break; + case XML_ATACTION_COPY_DUPLICATE: + { + pContext->AddAttribute( sAttrName, sAttrValue ); + XMLTypedPropertiesOOoTContext_Impl *pContext2 = + GetPropContext( static_cast(aAction.m_nParam1) ); + if( pContext2 ) + pContext2->AddAttribute( sAttrName, sAttrValue ); + } + break; + case XML_ATACTION_RENAME: + { + pContext->AddAttribute( aAction.GetQNamePrefixFromParam1(), + aAction.GetQNameTokenFromParam1(), + sAttrValue ); + } + break; + case XML_ATACTION_ENCODE_STYLE_NAME_REF: + { + OUString aAttrValue( sAttrValue ); + GetTransformer().EncodeStyleName(aAttrValue); + pContext->AddAttribute( sAttrName, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF: + { + OUString aAttrValue( sAttrValue ); + GetTransformer().EncodeStyleName(aAttrValue); + pContext->AddAttribute( aAction.GetQNamePrefixFromParam1(), + aAction.GetQNameTokenFromParam1(), + aAttrValue ); + } + break; + case XML_ATACTION_NEG_PERCENT: + { + OUString aAttrValue( sAttrValue ); + XMLTransformerBase::NegPercent(aAttrValue); + pContext->AddAttribute( sAttrName, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_NEG_PERCENT: + { + OUString aAttrValue( sAttrValue ); + XMLTransformerBase::NegPercent(aAttrValue); + pContext->AddAttribute( aAction.GetQNamePrefixFromParam1(), + aAction.GetQNameTokenFromParam1(), + aAttrValue ); + } + break; + case XML_ATACTION_INCH2IN: + { + OUString aAttrValue( sAttrValue ); + XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue ); + pContext->AddAttribute( sAttrName, aAttrValue ); + } + break; + case XML_ATACTION_INCH2IN_DUPLICATE: + { + OUString aAttrValue( sAttrValue ); + XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue ); + pContext->AddAttribute( sAttrName, aAttrValue ); + XMLTypedPropertiesOOoTContext_Impl *pContext2 = + GetPropContext( static_cast(aAction.m_nParam1) ); + if( pContext2 ) + pContext2->AddAttribute( sAttrName, aAttrValue ); + } + break; + case XML_ATACTION_INCHS2INS: + { + OUString aAttrValue( sAttrValue ); + XMLTransformerBase::ReplaceInchWithIn( aAttrValue ); + pContext->AddAttribute( sAttrName, aAttrValue ); + } + break; + case XML_PTACTION_LINE_MODE: + { + const OUString& aAttrValue( GetXMLToken( + IsXMLToken( sAttrValue, XML_TRUE ) + ? XML_CONTINUOUS + : XML_SKIP_WHITE_SPACE) ); + OUString aAttrQName( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_UNDERLINE_MODE ) ) ); + pContext->AddAttribute( aAttrQName, aAttrValue ); + + aAttrQName = + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_LINE_THROUGH_MODE ) ); + pContext->AddAttribute( aAttrQName, aAttrValue ); + } + break; + case XML_PTACTION_KEEP_WITH_NEXT: + { + const OUString& aAttrValue( GetXMLToken( + IsXMLToken( sAttrValue, XML_TRUE ) + ? XML_ALWAYS + : XML_AUTO) ); + pContext->AddAttribute( sAttrName, aAttrValue ); + } + break; + case XML_PTACTION_UNDERLINE: + { + XMLTokenEnum eToken = GetTransformer().GetToken( sAttrValue ); + bool bBold = false, bDouble = false; + switch( eToken ) + { + case XML_SINGLE: + eToken = XML_SOLID; + break; + case XML_DOUBLE: + eToken = XML_SOLID; + bDouble = true; + break; + case XML_BOLD: + eToken = XML_SOLID; + bBold = true; + break; + case XML_BOLD_DOTTED: + eToken = XML_DOTTED; + bBold = true; + break; + case XML_BOLD_DASH: + eToken = XML_DASH; + bBold = true; + break; + case XML_BOLD_LONG_DASH: + eToken = XML_LONG_DASH; + bBold = true; + break; + case XML_BOLD_DOT_DASH: + eToken = XML_DOT_DASH; + bBold = true; + break; + case XML_BOLD_DOT_DOT_DASH: + eToken = XML_DOT_DOT_DASH; + bBold = true; + break; + case XML_BOLD_WAVE: + eToken = XML_WAVE; + bBold = true; + break; + case XML_DOUBLE_WAVE: + eToken = XML_WAVE; + bDouble = true; + break; + case XML_NONE: + eToken = XML_NONE; + bDouble = false; + break; + default: + OSL_FAIL( "xmloff::XMLPropertiesOOoTContext_Impl::StartElement(), unknown underline token!" ); + break; + } + pContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_UNDERLINE_STYLE ) ), + eToken != XML_TOKEN_END ? GetXMLToken( eToken ) + : sAttrValue ); + if( bDouble ) + pContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_UNDERLINE_TYPE ) ), + GetXMLToken( XML_DOUBLE ) ); + if( bBold ) + pContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_UNDERLINE_WIDTH ) ), + GetXMLToken( XML_BOLD ) ); + } + break; + case XML_PTACTION_LINETHROUGH: + { + XMLTokenEnum eToken = GetTransformer().GetToken( sAttrValue ); + bool bBold = false, bDouble = false; + sal_Unicode c = 0; + switch( eToken ) + { + case XML_SINGLE_LINE: + eToken = XML_SOLID; + break; + case XML_DOUBLE_LINE: + eToken = XML_SOLID; + bDouble = true; + break; + case XML_THICK_LINE: + eToken = XML_SOLID; + bBold = true; + break; + case XML_SLASH: + eToken = XML_SOLID; + c = '/'; + break; + case XML_uX: + eToken = XML_SOLID; + c = 'X'; + break; + default: + break; + } + pContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_LINE_THROUGH_STYLE ) ), + eToken != XML_TOKEN_END ? GetXMLToken( eToken ) + : sAttrValue ); + if( bDouble ) + pContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_LINE_THROUGH_TYPE ) ), + GetXMLToken( XML_DOUBLE ) ); + if( bBold ) + pContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_LINE_THROUGH_WIDTH ) ), + GetXMLToken( XML_BOLD ) ); + if( c ) + pContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, + GetXMLToken( XML_TEXT_LINE_THROUGH_TEXT ) ), + OUString( c ) ); + } + break; + case XML_PTACTION_SPLINES: + { + sal_Int32 nSplineType = sAttrValue.toInt32(); + OUString aNewAttrName = GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( XML_INTERPOLATION ) ); + + switch( nSplineType ) + { + // straight lines + case 0: + pContext->AddAttribute( + aNewAttrName, GetXMLToken( XML_NONE )); + break; + // cubic spline + case 1: + pContext->AddAttribute( + aNewAttrName, GetXMLToken( XML_CUBIC_SPLINE )); + break; + // B-spline + case 2: + pContext->AddAttribute( + aNewAttrName, GetXMLToken( XML_B_SPLINE )); + break; + + default: + OSL_FAIL( "invalid spline type" ); + pContext->AddAttribute( + aNewAttrName, GetXMLToken( XML_NONE )); + break; + } + } + break; + case XML_PTACTION_INTERVAL_MAJOR: + pContext->AddAttribute( sAttrName, sAttrValue ); + ::sax::Converter::convertDouble( fIntervalMajor, sAttrValue ); + break; + case XML_PTACTION_INTERVAL_MINOR: + ::sax::Converter::convertDouble( fIntervalMinor, sAttrValue ); + pIntervalMinorDivisorContext = pContext; + break; + case XML_PTACTION_SYMBOL: + { + sal_Int32 nSymbolType = sAttrValue.toInt32(); + OUString aNewAttrName = GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( XML_SYMBOL_TYPE ) ); + + if( nSymbolType >= 0 ) + { + pContext->AddAttribute( aNewAttrName, GetXMLToken( XML_NAMED_SYMBOL )); + enum XMLTokenEnum eToken = XML_TOKEN_INVALID; + switch( nSymbolType ) + { + // SYMBOL0 + case 0: + // "square" has an awkward token name + eToken = XML_GRADIENTSTYLE_SQUARE; + break; + // SYMBOL1 + case 1: + eToken = XML_DIAMOND; + break; + // SYMBOL2 + case 2: + eToken = XML_ARROW_DOWN; + break; + // SYMBOL3 + case 3: + eToken = XML_ARROW_UP; + break; + // SYMBOL4 + case 4: + eToken = XML_ARROW_RIGHT; + break; + // SYMBOL5 + case 5: + eToken = XML_ARROW_LEFT; + break; + // SYMBOL6 + case 6: + eToken = XML_BOW_TIE; + break; + // SYMBOL7 + case 7: + eToken = XML_HOURGLASS; + break; + case 8: + eToken = XML_CIRCLE; + break; + case 9: + eToken = XML_STAR; + break; + case 10: + eToken = XML_X; + break; + case 11: + eToken = XML_PLUS; + break; + case 12: + eToken = XML_ASTERISK; + break; + case 13: + eToken = XML_HORIZONTAL_BAR; + break; + case 14: + eToken = XML_VERTICAL_BAR; + break; + default: + OSL_FAIL( "invalid named symbol" ); + break; + } + + if( eToken != XML_TOKEN_INVALID ) + { + pContext->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( XML_SYMBOL_NAME )), + GetXMLToken( eToken )); + } + } + else + { + switch( nSymbolType ) + { + // NONE + case -3: + pContext->AddAttribute( + aNewAttrName, GetXMLToken( XML_NONE )); + break; + // AUTO + case -2: + pContext->AddAttribute( + aNewAttrName, GetXMLToken( XML_AUTOMATIC )); + break; + // BITMAPURL + case -1: + pContext->AddAttribute( + aNewAttrName, GetXMLToken( XML_IMAGE )); + break; + default: + OSL_FAIL( "invalid symbol type" ); + pContext->AddAttribute( + aNewAttrName, GetXMLToken( XML_NONE )); + break; + } + } + } + break; + case XML_PTACTION_SYMBOL_IMAGE_NAME: + { + // create an xlink:href element for URI attribute + XMLPersAttrListTContext *pSymbolImageContext = new XMLPersAttrListTContext( + GetTransformer(), GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, GetXMLToken( XML_SYMBOL_IMAGE ))); + rtl::Reference xSymbolImageContext(pSymbolImageContext); + + OUString aAttrValue( sAttrValue ); + if( GetTransformer().ConvertURIToOASIS( aAttrValue, true )) + { + pSymbolImageContext->AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aAttrValue ); + pContext->AddContent(xSymbolImageContext); + } + } + break; + + // #i25616# + case XML_PTACTION_TRANSPARENCY : + { + OUString aAttrValue( sAttrValue ); + XMLTransformerBase::NegPercent(aAttrValue); + pContext->AddAttribute( XML_NAMESPACE_DRAW, + XML_OPACITY, + aAttrValue ); + pContext->AddAttribute( XML_NAMESPACE_DRAW, + XML_IMAGE_OPACITY, + aAttrValue ); + } + break; + + case XML_PTACTION_BREAK_INSIDE: + { + pContext->AddAttribute( + XML_NAMESPACE_FO, XML_KEEP_TOGETHER, + GetXMLToken( + IsXMLToken( sAttrValue, XML_COLUMNSPLIT_AVOID ) + ? XML_ALWAYS + : XML_AUTO ) ); + } + break; + case XML_ATACTION_CAPTION_ESCAPE_OOO: + { + OUString aAttrValue( sAttrValue ); + if( aAttrValue.indexOf( '%' ) != -1 ) + { + sal_Int32 nValue = 0; + ::sax::Converter::convertPercent( nValue, sAttrValue ); + if( nValue ) + { + nValue /= 100; + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + aAttrValue = aOut.makeStringAndClear(); + } + } + else + { + XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue ); + } + + pContext->AddAttribute( sAttrName, aAttrValue ); + } + break; + case XML_ATACTION_MOVE_PROTECT: + bMoveProtect = IsXMLToken( sAttrValue, XML_TRUE ); + pProtectContext = pContext; + break; + case XML_ATACTION_SIZE_PROTECT: + bSizeProtect = IsXMLToken( sAttrValue, XML_TRUE ); + pProtectContext = pContext; + break; + case XML_ATACTION_PROTECT: + aProtectAttrValue = sAttrValue; + pProtectContext = pContext; + break; + case XML_ATACTION_DRAW_MIRROR_OOO: // renames draw:mirror to style:mirror and adapts values + { + // OpenDocument file format: attribute value of wrong (#i49139#) + aDrawMirrorAttrValue = + GetXMLToken( IsXMLToken( sAttrValue, XML_TRUE ) + ? XML_HORIZONTAL : XML_NONE ); + bExistDrawMirror = true; + pMirrorContext = pContext; + } + break; + // OpenDocument file format: attribute value of wrong (#i49139#) + case XML_ATACTION_STYLE_MIRROR_OOO: // adapts style:mirror values + { + SvXMLTokenEnumerator aTokenEnum( sAttrValue ); + std::u16string_view aToken; + while( aTokenEnum.getNextToken( aToken ) ) + { + if ( !aStyleMirrorAttrValue.isEmpty() ) + { + aStyleMirrorAttrValue.append(" "); + } + + if ( IsXMLToken( aToken, XML_HORIZONTAL_ON_LEFT_PAGES ) ) + { + aStyleMirrorAttrValue.append(GetXMLToken( XML_HORIZONTAL_ON_EVEN )); + } + else if ( IsXMLToken( aToken, XML_HORIZONTAL_ON_RIGHT_PAGES ) ) + { + aStyleMirrorAttrValue.append(GetXMLToken( XML_HORIZONTAL_ON_ODD )); + } + else + { + aStyleMirrorAttrValue.append(aToken); + } + } + bExistStyleMirror = true; + pMirrorContext = pContext; + } + break; + case XML_ATACTION_GAMMA_OOO: // converts double value to percentage + { + double fValue = sAttrValue.toDouble(); + sal_Int32 nValue = static_cast((fValue * 100.0) + ( fValue > 0 ? 0.5 : - 0.5 ) ); + + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + OUString aAttrValue( aOut.makeStringAndClear() ); + pContext->AddAttribute( sAttrName, aAttrValue ); + } + break; + case XML_ATACTION_OPACITY_FIX: + { + sal_Int32 nValue; + if( sAttrValue.indexOf( '%' ) != -1 ) + { + ::sax::Converter::convertPercent( nValue, sAttrValue ); + } + else + { + nValue = sal_Int32( sAttrValue.toDouble() * 100.0 ); + } + nValue = 100 - nValue; + + OUStringBuffer aOut; + ::sax::Converter::convertPercent( aOut, nValue ); + pContext->AddAttribute( sAttrName, aOut.makeStringAndClear() ); + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + + // OpenDocument file format: attribute value of wrong (#i49139#) + if ( bExistStyleMirror ) + { + pMirrorContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, GetXMLToken( XML_MIRROR ) ), + aStyleMirrorAttrValue.makeStringAndClear()); + } + else if ( bExistDrawMirror ) + { + pMirrorContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_STYLE, GetXMLToken( XML_MIRROR ) ), + aDrawMirrorAttrValue); + } + + if (bMoveProtect || bSizeProtect || !aProtectAttrValue.isEmpty()) + { + if( (bMoveProtect ||bSizeProtect) && IsXMLToken( aProtectAttrValue, XML_NONE ) ) + aProtectAttrValue.clear(); + + const OUString& rPosition = GetXMLToken( XML_POSITION ); + if( bMoveProtect && -1 == aProtectAttrValue.indexOf( rPosition ) ) + { + if( !aProtectAttrValue.isEmpty() ) + aProtectAttrValue += " "; + aProtectAttrValue += rPosition; + } + + const OUString& rSize = GetXMLToken( XML_SIZE ); + if( bSizeProtect && -1 == aProtectAttrValue.indexOf( rSize ) ) + { + if( !aProtectAttrValue.isEmpty() ) + aProtectAttrValue += " "; + aProtectAttrValue += rSize; + } + + assert(pProtectContext && "coverity[var_deref_model] - pProtectContext should be assigned in a superset of the enclosing if condition entry logic"); + pProtectContext->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_STYLE, GetXMLToken( XML_PROTECT ) ), aProtectAttrValue ); + } + + if( !pIntervalMinorDivisorContext ) + return; + + if( fIntervalMinor != 0.0 ) + { + sal_Int32 nIntervalMinorDivisor = static_cast< sal_Int32 >( + ::rtl::math::round( fIntervalMajor / fIntervalMinor )); + + pIntervalMinorDivisorContext->AddAttribute( + GetTransformer().GetNamespaceMap().GetQNameByKey( + XML_NAMESPACE_CHART, + GetXMLToken( XML_INTERVAL_MINOR_DIVISOR )), + OUString::number( nIntervalMinorDivisor )); + } +} + +void XMLPropertiesOOoTContext_Impl::EndElement() +{ + if( !m_bPersistent ) + Export(); +} + +void XMLPropertiesOOoTContext_Impl::Characters( const OUString& ) +{ + // ignore them +} + +void XMLPropertiesOOoTContext_Impl::Export() +{ + + for(rtl::Reference & rPropContext : m_aPropContexts) + { + if( rPropContext.is() ) + rPropContext->Export(); + } +} + +bool XMLPropertiesOOoTContext_Impl::IsPersistent() const +{ + return m_bPersistent; +} + +XMLStyleOOoTContext::XMLStyleOOoTContext( XMLTransformerBase& rImp, + const OUString& rQName, + XMLFamilyType eT, + bool bPersistent ) : + XMLPersElemContentTContext( rImp, rQName ), + m_eFamily( eT ), + m_bPersistent( bPersistent ) +{ +} + +XMLStyleOOoTContext::XMLStyleOOoTContext( + XMLTransformerBase& rImp, + const OUString& rQName, + XMLFamilyType eT, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + bool bPersistent ) : + XMLPersElemContentTContext( rImp, rQName, nPrefix, eToken ), + m_eFamily( eT ), + m_bPersistent( bPersistent ) +{ +} + +XMLStyleOOoTContext::~XMLStyleOOoTContext() +{ +} + +rtl::Reference XMLStyleOOoTContext::CreateChildContext( + sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& rAttrList ) +{ + rtl::Reference pContext; + + if( XML_NAMESPACE_STYLE == nPrefix && + IsXMLToken( rLocalName, XML_PROPERTIES ) ) + { + if( aPropTypes[m_eFamily][0] == XML_PROP_TYPE_END ) + { + OSL_ENSURE( false, "unexpected properties element" ); + pContext = m_bPersistent + ? XMLPersElemContentTContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ) + : XMLTransformerContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ); + } + else if( aPropTypes[m_eFamily][1] == XML_PROP_TYPE_END ) + { + sal_uInt16 nActionMap = + aAttrActionMaps[aPropTypes[m_eFamily][0]]; + if( nActionMap < MAX_OOO_PROP_ACTIONS ) + { + pContext.set(new XMLPropertiesOOoTContext_Impl( + GetTransformer(), rQName, + aPropTypes[m_eFamily], m_bPersistent )); + } + else + { + if( m_bPersistent ) + pContext.set(new XMLPersElemContentTContext( + GetTransformer(), rQName, + XML_NAMESPACE_STYLE, + aPropTokens[aPropTypes[m_eFamily][0]] )); + else + pContext.set(new XMLRenameElemTransformerContext( + GetTransformer(), rQName, + XML_NAMESPACE_STYLE, + aPropTokens[aPropTypes[m_eFamily][0]] )); + } + } + else + { + pContext.set(new XMLPropertiesOOoTContext_Impl( + GetTransformer(), rQName, + aPropTypes[m_eFamily], m_bPersistent)); + } + + if( m_bPersistent ) + AddContent( pContext ); + } + else + { + pContext = m_bPersistent + ? XMLPersElemContentTContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ) + : XMLTransformerContext::CreateChildContext( + nPrefix, rLocalName, rQName, rAttrList ); + } + + return pContext; +} + +void XMLStyleOOoTContext::StartElement( + const Reference< XAttributeList >& rAttrList ) +{ + XMLTransformerActions *pActions = + GetTransformer().GetUserDefinedActions( OOO_STYLE_ACTIONS ); + OSL_ENSURE( pActions, "go no actions" ); + + Reference< XAttributeList > xAttrList( rAttrList ); + rtl::Reference pMutableAttrList; + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString sAttrName = xAttrList->getNameByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = + GetTransformer().GetNamespaceMap().GetKeyByAttrName( sAttrName, + &aLocalName ); + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = + new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + const OUString sAttrValue = xAttrList->getValueByIndex( i ); + switch( (*aIter).second.m_nActionType ) + { + case XML_ATACTION_STYLE_FAMILY: + { + bool bControl = false; + if( XML_FAMILY_TYPE_END == m_eFamily ) + { + if( IsXMLToken( sAttrValue, XML_GRAPHICS ) ) + m_eFamily = XML_FAMILY_TYPE_GRAPHIC; + else if( IsXMLToken( sAttrValue, XML_PRESENTATION ) ) + m_eFamily = XML_FAMILY_TYPE_PRESENTATION; + else if( IsXMLToken( sAttrValue, XML_DRAWING_PAGE ) ) + m_eFamily = XML_FAMILY_TYPE_DRAWING_PAGE; + else if( IsXMLToken( sAttrValue, XML_TEXT) ) + m_eFamily = XML_FAMILY_TYPE_TEXT; + else if( IsXMLToken( sAttrValue, XML_PARAGRAPH) ) + m_eFamily = XML_FAMILY_TYPE_PARAGRAPH; + else if( IsXMLToken( sAttrValue, XML_RUBY) ) + m_eFamily = XML_FAMILY_TYPE_RUBY; + else if( IsXMLToken( sAttrValue, XML_SECTION) ) + m_eFamily = XML_FAMILY_TYPE_SECTION; + else if( IsXMLToken( sAttrValue, XML_TABLE) ) + m_eFamily = XML_FAMILY_TYPE_TABLE; + else if( IsXMLToken( sAttrValue, XML_TABLE_COLUMN) ) + m_eFamily = XML_FAMILY_TYPE_TABLE_COLUMN; + else if( IsXMLToken( sAttrValue, XML_TABLE_ROW) ) + m_eFamily = XML_FAMILY_TYPE_TABLE_ROW; + else if( IsXMLToken( sAttrValue, XML_TABLE_CELL) ) + m_eFamily = XML_FAMILY_TYPE_TABLE_CELL; + else if( IsXMLToken( sAttrValue, XML_CHART) ) + m_eFamily = XML_FAMILY_TYPE_CHART; + else if( IsXMLToken( sAttrValue, XML_CONTROL) ) + { + m_eFamily = XML_FAMILY_TYPE_PARAGRAPH; + bControl = true; + } + } + if( XML_FAMILY_TYPE_GRAPHIC == m_eFamily ) + { + pMutableAttrList->SetValueByIndex( i, + GetXMLToken( XML_GRAPHIC ) ); + } + else if( bControl ) + { + pMutableAttrList->SetValueByIndex( i, + GetXMLToken( XML_PARAGRAPH ) ); + } + } + break; + case XML_ATACTION_INCH2IN: + { + OUString aAttrValue( sAttrValue ); + if( XMLTransformerBase::ReplaceSingleInchWithIn( + aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_ENCODE_STYLE_NAME: + { + OUString aAttrValue( sAttrValue ); + if( GetTransformer().EncodeStyleName(aAttrValue) ) + { + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + OUString aNewAttrQName( + GetTransformer().GetNamespaceMap(). + GetQNameByKey( + nPrefix, ::xmloff::token::GetXMLToken( + XML_DISPLAY_NAME ) ) ); + pMutableAttrList->AddAttribute( aNewAttrQName, + sAttrValue ); + } + } + break; + case XML_ATACTION_ENCODE_STYLE_NAME_REF: + { + OUString aAttrValue( sAttrValue ); + if( GetTransformer().EncodeStyleName(aAttrValue) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_NEG_PERCENT: + { + OUString aAttrValue( sAttrValue ); + if( XMLTransformerBase::NegPercent(aAttrValue) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_URI_OOO: + { + OUString aAttrValue( sAttrValue ); + if( GetTransformer().ConvertURIToOASIS( aAttrValue, + static_cast< bool >((*aIter).second.m_nParam1))) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + } + if( XML_FAMILY_TYPE_END == m_eFamily ) + m_eFamily = XML_FAMILY_TYPE_TEXT; + if( m_bPersistent ) + XMLPersElemContentTContext::StartElement( xAttrList ); + else + GetTransformer().GetDocHandler()->startElement( GetExportQName(), xAttrList ); +} + +void XMLStyleOOoTContext::EndElement() +{ + if( m_bPersistent ) + XMLPersElemContentTContext::EndElement(); + else + GetTransformer().GetDocHandler()->endElement( GetExportQName() ); +} + +void XMLStyleOOoTContext::Characters( const OUString& ) +{ + // element content only: +} + +bool XMLStyleOOoTContext::IsPersistent() const +{ + return m_bPersistent; +} + +XMLTransformerActions *XMLStyleOOoTContext::CreateTransformerActions( + sal_uInt16 nType ) +{ + XMLTransformerActionInit const *pInit = nullptr; + + switch( nType ) + { + case PROP_OOO_GRAPHIC_ATTR_ACTIONS: + pInit = aGraphicPropertyOOoAttrActionTable; + break; + case PROP_OOO_GRAPHIC_ELEM_ACTIONS: + pInit = aGraphicPropertyOOoElemActionTable; + break; + case PROP_OOO_DRAWING_PAGE_ATTR_ACTIONS: + pInit = aDrawingPagePropertyOOoAttrActionTable; + break; + case PROP_OOO_PAGE_LAYOUT_ATTR_ACTIONS: + pInit = aPageLayoutPropertyOOoAttrActionTable; + break; + case PROP_OOO_HEADER_FOOTER_ATTR_ACTIONS: + pInit = aHeaderFooterPropertyOOoAttrActionTable; + break; + case PROP_OOO_TEXT_ATTR_ACTIONS: + pInit = aTextPropertyOOoAttrActionTable; + break; + case PROP_OOO_TEXT_ELEM_ACTIONS: + pInit = aTextPropertyOOoElemActionTable; + break; + case PROP_OOO_PARAGRAPH_ATTR_ACTIONS: + pInit = aParagraphPropertyOOoAttrActionTable; + break; + case PROP_OOO_PARAGRAPH_ELEM_ACTIONS: + pInit = aParagraphPropertyOOoElemActionTable; + break; + case PROP_OOO_SECTION_ATTR_ACTIONS: + pInit = aSectionPropertyOOoAttrActionTable; + break; + case PROP_OOO_TABLE_ATTR_ACTIONS: + pInit = aTablePropertyOOoAttrActionTable; + break; + case PROP_OOO_TABLE_COLUMN_ATTR_ACTIONS: + pInit = aTableColumnPropertyOOoAttrActionTable; + break; + case PROP_OOO_TABLE_ROW_ATTR_ACTIONS: + pInit = aTableRowPropertyOOoAttrActionTable; + break; + case PROP_OOO_TABLE_CELL_ATTR_ACTIONS: + pInit = aTableCellPropertyOOoAttrActionTable; + break; + case PROP_OOO_TABLE_CELL_ELEM_ACTIONS: + pInit = aTableCellPropertyOOoElemActionTable; + break; + case PROP_OOO_LIST_LEVEL_ATTR_ACTIONS: + pInit = aListLevelPropertyOOoAttrActionTable; + break; + case PROP_OOO_CHART_ATTR_ACTIONS: + pInit = aChartPropertyOOoAttrActionTable; + break; + case PROP_OOO_CHART_ELEM_ACTIONS: + pInit = aChartPropertyOOoElemActionTable; + break; + } + + XMLTransformerActions *pActions = nullptr; + if( pInit ) + pActions = new XMLTransformerActions( pInit ); + + return pActions; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/StyleOOoTContext.hxx b/xmloff/source/transform/StyleOOoTContext.hxx new file mode 100644 index 000000000..f242d66c0 --- /dev/null +++ b/xmloff/source/transform/StyleOOoTContext.hxx @@ -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/. + * + * 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 +#include "FamilyType.hxx" +#include "DeepTContext.hxx" + + +class XMLTransformerActions; + +class XMLStyleOOoTContext : public XMLPersElemContentTContext +{ + XMLFamilyType m_eFamily; + + bool const m_bPersistent; + +public: + XMLStyleOOoTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + XMLFamilyType eType, + bool bPersistent ); + XMLStyleOOoTContext( XMLTransformerBase& rTransformer, + const OUString& rQName, + XMLFamilyType eType, + sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken, + bool bPersistent ); + + virtual ~XMLStyleOOoTContext() override; + + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ) override; + virtual void EndElement() override; + virtual void Characters( const OUString& rChars ) override; + virtual bool IsPersistent() const override; + + static XMLTransformerActions *CreateTransformerActions( sal_uInt16 nType ); + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/Transformer.hxx b/xmloff/source/transform/Transformer.hxx new file mode 100644 index 000000000..84647a5b4 --- /dev/null +++ b/xmloff/source/transform/Transformer.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/. + * + * 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 +#include +#include +#include +#include + +class XMLTransformer : public ::cppu::WeakImplHelper< + css::xml::sax::XExtendedDocumentHandler, + css::lang::XServiceInfo, + css::lang::XInitialization, + css::lang::XUnoTunnel> +{ +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerAction.hxx b/xmloff/source/transform/TransformerAction.hxx new file mode 100644 index 000000000..373e32a90 --- /dev/null +++ b/xmloff/source/transform/TransformerAction.hxx @@ -0,0 +1,25 @@ +/* -*- 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 + +#define XML_TACTION_EOT 0x0000 +#define XML_TACTION_END 0xffff + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerActionInit.hxx b/xmloff/source/transform/TransformerActionInit.hxx new file mode 100644 index 000000000..41ed6e771 --- /dev/null +++ b/xmloff/source/transform/TransformerActionInit.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 + + +struct XMLTransformerActionInit +{ + sal_uInt16 const m_nPrefix; + ::xmloff::token::XMLTokenEnum const m_eLocalName; + sal_uInt32 const m_nActionType; + sal_uInt32 const m_nParam1; + sal_uInt32 const m_nParam2; + sal_uInt32 const m_nParam3; + + static sal_uInt32 QNameParam( sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eLocalName ) + { + return (static_cast< sal_uInt32 >( nPrefix ) << 16) + + static_cast< sal_uInt32 >( eLocalName ); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerActions.cxx b/xmloff/source/transform/TransformerActions.cxx new file mode 100644 index 000000000..870822f40 --- /dev/null +++ b/xmloff/source/transform/TransformerActions.cxx @@ -0,0 +1,84 @@ +/* -*- 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 "TransformerActions.hxx" + +#include + + +using namespace ::osl; +using namespace ::xmloff::token; +using namespace ::com::sun::star::uno; + +XMLTransformerActions::XMLTransformerActions( XMLTransformerActionInit const *pInit ) +{ + if( !pInit ) + return; + + XMLTransformerActions::key_type aKey; + XMLTransformerActions::mapped_type aData; + while( pInit->m_nActionType != XML_TACTION_EOT ) + { + aKey.m_nPrefix = pInit->m_nPrefix; + aKey.SetLocalName( pInit->m_eLocalName ); + + OSL_ENSURE( find( aKey ) == end(), "duplicate action map entry" ); + + aData.m_nActionType = pInit->m_nActionType; + aData.m_nParam1 = pInit->m_nParam1; + aData.m_nParam2 = pInit->m_nParam2; + aData.m_nParam3 = pInit->m_nParam3; + XMLTransformerActions::value_type aVal( aKey, aData ); + + insert( aVal ); + ++pInit; + } +} + +XMLTransformerActions::~XMLTransformerActions() +{ +} + +void XMLTransformerActions::Add( XMLTransformerActionInit const *pInit ) +{ + if( !pInit ) + return; + + XMLTransformerActions::key_type aKey; + XMLTransformerActions::mapped_type aData; + while( pInit->m_nActionType != XML_TACTION_EOT ) + { + aKey.m_nPrefix = pInit->m_nPrefix; + aKey.SetLocalName( pInit->m_eLocalName ); + XMLTransformerActions::iterator aIter = find( aKey ); + if( aIter == end() ) + { + aData.m_nActionType = pInit->m_nActionType; + aData.m_nParam1 = pInit->m_nParam1; + aData.m_nParam2 = pInit->m_nParam2; + aData.m_nParam3 = pInit->m_nParam3; + XMLTransformerActions::value_type aVal( aKey, aData ); + insert( aVal ); + } + + ++pInit; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerActions.hxx b/xmloff/source/transform/TransformerActions.hxx new file mode 100644 index 000000000..a8bfb7722 --- /dev/null +++ b/xmloff/source/transform/TransformerActions.hxx @@ -0,0 +1,131 @@ +/* -*- 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 +#include +#include "TransformerActionInit.hxx" +#include "TransformerAction.hxx" +#include +#include + +struct NameKey_Impl +{ + sal_uInt16 m_nPrefix; + OUString m_aLocalName; + + NameKey_Impl( sal_uInt16 nPrfx, const OUString& rLclNm ) : + m_nPrefix( nPrfx ), + m_aLocalName( rLclNm ) + { + } + + NameKey_Impl() : + m_nPrefix( XML_NAMESPACE_UNKNOWN ) + { + } + + void SetLocalName( ::xmloff::token::XMLTokenEnum eLclNm ) + { + m_aLocalName = ::xmloff::token::GetXMLToken( eLclNm ); + } +}; + +struct NameHash_Impl +{ + inline size_t operator()( const NameKey_Impl& r ) const; + inline bool operator()( const NameKey_Impl& r1, + const NameKey_Impl& r2 ) const; +}; + +inline size_t NameHash_Impl::operator()( const NameKey_Impl& r ) const +{ + std::size_t seed = 0; + o3tl::hash_combine(seed, r.m_nPrefix); + o3tl::hash_combine(seed, r.m_aLocalName.hashCode()); + return seed; +} + +inline bool NameHash_Impl::operator()( + const NameKey_Impl& r1, + const NameKey_Impl& r2 ) const +{ + return r1.m_nPrefix == r2.m_nPrefix && r1.m_aLocalName == r2.m_aLocalName; +} + +struct TransformerAction_Impl +{ + sal_uInt32 m_nActionType; + sal_uInt32 m_nParam1; + sal_uInt32 m_nParam2; + sal_uInt32 m_nParam3; + + TransformerAction_Impl() : + m_nActionType( XML_TACTION_EOT ), + m_nParam1( 0 ), + m_nParam2( 0 ), + m_nParam3( 0 ) + { + } + + sal_uInt16 GetQNamePrefixFromParam1() const + { + return static_cast< sal_uInt16 >( m_nParam1 >> 16 ); + } + + sal_uInt16 GetQNamePrefixFromParam2() const + { + return static_cast< sal_uInt16 >( m_nParam2 >> 16 ); + } + + sal_uInt16 GetQNamePrefixFromParam3() const + { + return static_cast< sal_uInt16 >( m_nParam3 >> 16 ); + } + + ::xmloff::token::XMLTokenEnum GetQNameTokenFromParam1() const + { + return static_cast< ::xmloff::token::XMLTokenEnum>( m_nParam1 & 0xffff ); + } + + ::xmloff::token::XMLTokenEnum GetQNameTokenFromParam2() const + { + return static_cast< ::xmloff::token::XMLTokenEnum>( m_nParam2 & 0xffff ); + } + + ::xmloff::token::XMLTokenEnum GetQNameTokenFromParam3() const + { + return static_cast< ::xmloff::token::XMLTokenEnum>( m_nParam3 & 0xffff ); + } + +}; + +class XMLTransformerActions : + public std::unordered_map< NameKey_Impl, TransformerAction_Impl, + NameHash_Impl, NameHash_Impl > +{ +public: + explicit XMLTransformerActions( XMLTransformerActionInit const *pInit ); + ~XMLTransformerActions(); + + void Add( XMLTransformerActionInit const *pInit ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerBase.cxx b/xmloff/source/transform/TransformerBase.cxx new file mode 100644 index 000000000..90f8b1988 --- /dev/null +++ b/xmloff/source/transform/TransformerBase.cxx @@ -0,0 +1,1409 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "IgnoreTContext.hxx" +#include "RenameElemTContext.hxx" +#include "ProcAttrTContext.hxx" +#include "ProcAddAttrTContext.hxx" +#include "MergeElemTContext.hxx" +#include "CreateElemTContext.hxx" +#include "MutableAttrList.hxx" +#include "TransformerActions.hxx" +#include "ElemTransformerAction.hxx" +#include "PropertyActionsOOo.hxx" +#include "TransformerTokenMap.hxx" + +#include "TransformerBase.hxx" +#include + +using namespace ::osl; +using namespace ::xmloff::token; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::xml::sax; + +namespace +{ +bool lcl_ConvertAttr( OUString & rOutAttribute, sal_Int32 nParam ) +{ + bool bResult = false; + enum XMLTokenEnum eTokenToRename = + static_cast< enum XMLTokenEnum >( nParam & 0xffff ); + if( eTokenToRename != XML_TOKEN_INVALID && + IsXMLToken( rOutAttribute, eTokenToRename )) + { + enum XMLTokenEnum eReplacementToken = + static_cast< enum XMLTokenEnum >( nParam >> 16 ); + rOutAttribute = GetXMLToken( eReplacementToken ); + bResult = true; + } + return bResult; +} +} // anonymous namespace + +XMLTransformerContext *XMLTransformerBase::CreateContext( sal_uInt16 nPrefix, + const OUString& rLocalName, const OUString& rQName ) +{ + XMLTransformerActions::key_type aKey( nPrefix, rLocalName ); + XMLTransformerActions::const_iterator aIter = + GetElemActions().find( aKey ); + + if( aIter != GetElemActions().end() ) + { + sal_uInt32 nActionType = (*aIter).second.m_nActionType; + if( (nActionType & XML_ETACTION_USER_DEFINED) != 0 ) + { + XMLTransformerContext *pContext = + CreateUserDefinedContext( (*aIter).second, + rQName ); + OSL_ENSURE( pContext && !pContext->IsPersistent(), + "unknown or not persistent action" ); + return pContext; + } + + switch( nActionType ) + { + case XML_ETACTION_COPY_CONTENT: + return new XMLIgnoreTransformerContext( *this, rQName, false, + false ); + case XML_ETACTION_COPY: + return new XMLTransformerContext( *this, rQName ); + case XML_ETACTION_RENAME_ELEM: + return new XMLRenameElemTransformerContext( *this, rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1() ); + case XML_ETACTION_RENAME_ELEM_ADD_ATTR: + return new XMLRenameElemTransformerContext( *this, rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1(), + (*aIter).second.GetQNamePrefixFromParam2(), + (*aIter).second.GetQNameTokenFromParam2(), + static_cast< XMLTokenEnum >( (*aIter).second.m_nParam3 ) ); + case XML_ETACTION_RENAME_ELEM_PROC_ATTRS: + return new XMLProcAttrTransformerContext( *this, rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1(), + static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) ); + case XML_ETACTION_RENAME_ELEM_ADD_PROC_ATTR: + return new XMLProcAddAttrTransformerContext( *this, rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1(), + static_cast< sal_uInt16 >( + (*aIter).second.m_nParam3 >> 16 ), + (*aIter).second.GetQNamePrefixFromParam2(), + (*aIter).second.GetQNameTokenFromParam2(), + static_cast< XMLTokenEnum >( + (*aIter).second.m_nParam3 & 0xffff ) ); + case XML_ETACTION_RENAME_ELEM_PROC_ATTRS_COND: + { + const XMLTransformerContext *pCurrent = GetCurrentContext(); + if( pCurrent->HasQName( + (*aIter).second.GetQNamePrefixFromParam3(), + (*aIter).second.GetQNameTokenFromParam3() ) ) + return new XMLProcAttrTransformerContext( *this, rQName, + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1(), + static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) ); + else + return new XMLProcAttrTransformerContext( *this, rQName, + static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) ); + } + case XML_ETACTION_PROC_ATTRS: + return new XMLProcAttrTransformerContext( *this, rQName, + static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) ); + case XML_ETACTION_PROC_ATTRS_COND: + { + const XMLTransformerContext *pCurrent = GetCurrentContext(); + if( pCurrent->HasQName( + (*aIter).second.GetQNamePrefixFromParam1(), + (*aIter).second.GetQNameTokenFromParam1() ) ) + return new XMLProcAttrTransformerContext( *this, rQName, + static_cast< sal_uInt16 >( (*aIter).second.m_nParam2 ) ); + } + break; + case XML_ETACTION_MOVE_ATTRS_TO_ELEMS: + return new XMLCreateElemTransformerContext( *this, rQName, + static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) ); + case XML_ETACTION_MOVE_ELEMS_TO_ATTRS: + return new XMLMergeElemTransformerContext( *this, rQName, + static_cast< sal_uInt16 >( (*aIter).second.m_nParam1 ) ); + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + } + + // default is copying + return new XMLTransformerContext( *this, rQName ); +} + +XMLTransformerActions *XMLTransformerBase::GetUserDefinedActions( sal_uInt16 ) +{ + return nullptr; +} + +XMLTransformerBase::XMLTransformerBase( XMLTransformerActionInit const *pInit, + ::xmloff::token::XMLTokenEnum const *pTKMapInit ) + noexcept : + m_pNamespaceMap( new SvXMLNamespaceMap ), + m_ElemActions( pInit ), + m_TokenMap( pTKMapInit ) +{ + GetNamespaceMap().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK ); + GetNamespaceMap().Add( GetXMLToken(XML_NP_DC), GetXMLToken(XML_N_DC), XML_NAMESPACE_DC ); + GetNamespaceMap().Add( GetXMLToken(XML_NP_MATH), GetXMLToken(XML_N_MATH), XML_NAMESPACE_MATH ); + GetNamespaceMap().Add( GetXMLToken(XML_NP_OOO), GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO ); + GetNamespaceMap().Add( GetXMLToken(XML_NP_DOM), GetXMLToken(XML_N_DOM), XML_NAMESPACE_DOM ); + GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOW), GetXMLToken(XML_N_OOOW), XML_NAMESPACE_OOOW ); + GetNamespaceMap().Add( GetXMLToken(XML_NP_OOOC), GetXMLToken(XML_N_OOOC), XML_NAMESPACE_OOOC ); +} + +XMLTransformerBase::~XMLTransformerBase() noexcept +{ +} + +void SAL_CALL XMLTransformerBase::startDocument() +{ + m_xHandler->startDocument(); +} + +void SAL_CALL XMLTransformerBase::endDocument() +{ + m_xHandler->endDocument(); +} + +void SAL_CALL XMLTransformerBase::startElement( const OUString& rName, + const Reference< XAttributeList >& rAttrList ) +{ + std::unique_ptr pRewindMap; + + // Process namespace attributes. This must happen before creating the + // context, because namespace declaration apply to the element name itself. + rtl::Reference pMutableAttrList; + Reference< XAttributeList > xAttrList( rAttrList ); + sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; i++ ) + { + const OUString& rAttrName = xAttrList->getNameByIndex( i ); + if( ( rAttrName.getLength() >= 5 ) && + ( rAttrName.startsWith( GetXMLToken(XML_XMLNS) ) ) && + ( rAttrName.getLength() == 5 || ':' == rAttrName[5] ) ) + { + if( !pRewindMap ) + { + pRewindMap = std::move(m_pNamespaceMap); + m_pNamespaceMap.reset( new SvXMLNamespaceMap( *pRewindMap ) ); + } + const OUString& rAttrValue = xAttrList->getValueByIndex( i ); + + OUString aPrefix( ( rAttrName.getLength() == 5 ) + ? OUString() + : rAttrName.copy( 6 ) ); + // Add namespace, but only if it is known. + sal_uInt16 nKey = m_pNamespaceMap->AddIfKnown( aPrefix, rAttrValue ); + // If namespace is unknown, try to match a name with similar + // TC Id and version + if( XML_NAMESPACE_UNKNOWN == nKey ) + { + OUString aTestName( rAttrValue ); + if( SvXMLNamespaceMap::NormalizeOasisURN( aTestName ) ) + nKey = m_pNamespaceMap->AddIfKnown( aPrefix, aTestName ); + } + // If that namespace is not known, too, add it as unknown + if( XML_NAMESPACE_UNKNOWN == nKey ) + nKey = m_pNamespaceMap->Add( aPrefix, rAttrValue ); + + const OUString& rRepName = m_vReplaceNamespaceMap.GetNameByKey( nKey ); + if( !rRepName.isEmpty() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = new XMLMutableAttributeList( xAttrList ); + xAttrList = pMutableAttrList; + } + + pMutableAttrList->SetValueByIndex( i, rRepName ); + } + } + } + + // Get element's namespace and local name. + OUString aLocalName; + sal_uInt16 nPrefix = + m_pNamespaceMap->GetKeyByAttrName( rName, &aLocalName ); + + // If there are contexts already, call a CreateChildContext at the topmost + // context. Otherwise, create a default context. + ::rtl::Reference < XMLTransformerContext > xContext; + if( !m_vContexts.empty() ) + { + xContext = m_vContexts.back()->CreateChildContext( nPrefix, + aLocalName, + rName, + xAttrList ); + } + else + { + xContext = CreateContext( nPrefix, aLocalName, rName ); + } + + OSL_ENSURE( xContext.is(), "XMLTransformerBase::startElement: missing context" ); + if( !xContext.is() ) + xContext = new XMLTransformerContext( *this, rName ); + + // Remember old namespace map. + if( pRewindMap ) + xContext->PutRewindMap( std::move(pRewindMap) ); + + // Push context on stack. + m_vContexts.push_back( xContext ); + + // Call a startElement at the new context. + xContext->StartElement( xAttrList ); +} + +void SAL_CALL XMLTransformerBase::endElement( const OUString& +#if OSL_DEBUG_LEVEL > 0 +rName +#endif +) +{ + if( m_vContexts.empty() ) + return; + + // Get topmost context + ::rtl::Reference< XMLTransformerContext > xContext = m_vContexts.back(); + +#if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE( xContext->GetQName() == rName, + "XMLTransformerBase::endElement: popped context has wrong lname" ); +#endif + + // Call a EndElement at the current context. + xContext->EndElement(); + + // and remove it from the stack. + m_vContexts.pop_back(); + + // Get a namespace map to rewind. + std::unique_ptr pRewindMap = xContext->TakeRewindMap(); + + // Delete the current context. + xContext = nullptr; + + // Rewind a namespace map. + if( pRewindMap ) + { + m_pNamespaceMap = std::move( pRewindMap ); + } +} + +void SAL_CALL XMLTransformerBase::characters( const OUString& rChars ) +{ + if( !m_vContexts.empty() ) + { + m_vContexts.back()->Characters( rChars ); + } +} + +void SAL_CALL XMLTransformerBase::ignorableWhitespace( const OUString& rWhitespaces ) +{ + m_xHandler->ignorableWhitespace( rWhitespaces ); +} + +void SAL_CALL XMLTransformerBase::processingInstruction( const OUString& rTarget, + const OUString& rData ) +{ + m_xHandler->processingInstruction( rTarget, rData ); +} + +void SAL_CALL XMLTransformerBase::setDocumentLocator( const Reference< XLocator >& ) +{ +} + +// XExtendedDocumentHandler +void SAL_CALL XMLTransformerBase::startCDATA() +{ +} + +void SAL_CALL XMLTransformerBase::endCDATA() +{ +} + +void SAL_CALL XMLTransformerBase::comment( const OUString& /*rComment*/ ) +{ +} + +void SAL_CALL XMLTransformerBase::allowLineBreak() +{ +} + +void SAL_CALL XMLTransformerBase::unknown( const OUString& /*rString*/ ) +{ +} + +// XInitialize +void SAL_CALL XMLTransformerBase::initialize( const Sequence< Any >& aArguments ) +{ + for( const auto& rArgument : aArguments ) + { + // use isAssignableFrom instead of comparing the types to + // allow XExtendedDocumentHandler instead of XDocumentHandler (used in + // writeOasis2OOoLibraryElement in sfx2). + // The Any shift operator can't be used to query the type because it + // uses queryInterface, and the model also has a XPropertySet interface. + + css::uno::Reference< XFastDocumentHandler > xFastHandler; + if( (rArgument >>= xFastHandler) && xFastHandler ) + { + SvXMLImport *pFastHandler = static_cast( xFastHandler.get() ); + m_xHandler.set( new SvXMLLegacyToFastDocHandler( pFastHandler ) ); + } + // document handler + else if( cppu::UnoType::get().isAssignableFrom( rArgument.getValueType() ) ) + { + m_xHandler.set( rArgument, UNO_QUERY ); + } + // property set to transport data across + else if( cppu::UnoType::get().isAssignableFrom( rArgument.getValueType() ) ) + m_xPropSet.set( rArgument, UNO_QUERY ); + // xmodel + else if( cppu::UnoType::get().isAssignableFrom( rArgument.getValueType() ) ) + mxModel.set( rArgument, UNO_QUERY ); + } + + if( m_xPropSet.is() ) + { + Any aAny; + OUString sRelPath, sName; + Reference< XPropertySetInfo > xPropSetInfo = + m_xPropSet->getPropertySetInfo(); + OUString sPropName( "StreamRelPath" ); + if( xPropSetInfo->hasPropertyByName(sPropName) ) + { + aAny = m_xPropSet->getPropertyValue(sPropName); + aAny >>= sRelPath; + } + sPropName = "StreamName"; + if( xPropSetInfo->hasPropertyByName(sPropName) ) + { + aAny = m_xPropSet->getPropertyValue(sPropName); + aAny >>= sName; + } + if( !sName.isEmpty() ) + { + m_aExtPathPrefix = "../"; + + // If there is a rel path within a package, then append + // additional '../'. If the rel path contains an ':', then it is + // an absolute URI (or invalid URI, because zip files don't + // permit ':'), and it will be ignored. + if( !sRelPath.isEmpty() ) + { + sal_Int32 nColPos = sRelPath.indexOf( ':' ); + OSL_ENSURE( -1 == nColPos, + "StreamRelPath contains ':', absolute URI?" ); + + if( -1 == nColPos ) + { + OUString sTmp = m_aExtPathPrefix; + sal_Int32 nPos = 0; + do + { + m_aExtPathPrefix += sTmp; + nPos = sRelPath.indexOf( '/', nPos + 1 ); + } + while( -1 != nPos ); + } + } + + } + } + + assert(m_xHandler.is()); // can't do anything without that +} + +static sal_Int16 lcl_getUnit( const OUString& rValue ) +{ + if( rValue.endsWithIgnoreAsciiCase( "cm" ) ) + return util::MeasureUnit::CM; + else if ( rValue.endsWithIgnoreAsciiCase( "mm" ) ) + return util::MeasureUnit::MM; + else + return util::MeasureUnit::INCH; +} + +XMLMutableAttributeList *XMLTransformerBase::ProcessAttrList( + Reference< XAttributeList >& rAttrList, sal_uInt16 nActionMap, + bool bClone ) +{ + rtl::Reference pMutableAttrList; + XMLTransformerActions *pActions = GetUserDefinedActions( nActionMap ); + OSL_ENSURE( pActions, "go no actions" ); + if( pActions ) + { + sal_Int16 nAttrCount = rAttrList.is() ? rAttrList->getLength() : 0; + for( sal_Int16 i=0; i < nAttrCount; ++i ) + { + const OUString& rAttrName = rAttrList->getNameByIndex( i ); + const OUString& rAttrValue = rAttrList->getValueByIndex( i ); + OUString aLocalName; + sal_uInt16 nPrefix = GetNamespaceMap().GetKeyByAttrName( rAttrName, + &aLocalName ); + + XMLTransformerActions::key_type aKey( nPrefix, aLocalName ); + XMLTransformerActions::const_iterator aIter = + pActions->find( aKey ); + if( aIter != pActions->end() ) + { + if( !pMutableAttrList ) + { + pMutableAttrList = new XMLMutableAttributeList( rAttrList, + bClone ); + rAttrList = pMutableAttrList; + } + + sal_uInt32 nAction = (*aIter).second.m_nActionType; + bool bRename = false; + switch( nAction ) + { + case XML_ATACTION_RENAME: + bRename = true; + break; + case XML_ATACTION_COPY: + break; + case XML_ATACTION_REMOVE: + case XML_ATACTION_STYLE_DISPLAY_NAME: + pMutableAttrList->RemoveAttributeByIndex( i ); + --i; + --nAttrCount; + break; + case XML_ATACTION_RENAME_IN2INCH: + bRename = true; + [[fallthrough]]; + case XML_ATACTION_IN2INCH: + { + OUString aAttrValue( rAttrValue ); + if( ReplaceSingleInWithInch( aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_INS2INCHS: + { + OUString aAttrValue( rAttrValue ); + if( ReplaceInWithInch( aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_INCH2IN: + bRename = true; + [[fallthrough]]; + case XML_ATACTION_INCH2IN: + { + OUString aAttrValue( rAttrValue ); + if( ReplaceSingleInchWithIn( aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_INCHS2INS: + { + OUString aAttrValue( rAttrValue ); + if( ReplaceInchWithIn( aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_TWIPS2IN: + { + OUString aAttrValue( rAttrValue ); + + XMLTransformerBase::ReplaceSingleInchWithIn( aAttrValue ); + if( isWriter() ) + { + sal_Int16 const nDestUnit = lcl_getUnit(aAttrValue); + + // convert twips value to inch + sal_Int32 nMeasure; + if (::sax::Converter::convertMeasure(nMeasure, + aAttrValue)) + { + nMeasure = static_cast(convertTwipToMm100(nMeasure)); + + OUStringBuffer aBuffer; + ::sax::Converter::convertMeasure(aBuffer, + nMeasure, util::MeasureUnit::MM_100TH, + nDestUnit ); + aAttrValue = aBuffer.makeStringAndClear(); + } + } + + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_DECODE_STYLE_NAME_REF: + bRename = true; + [[fallthrough]]; + case XML_ATACTION_DECODE_STYLE_NAME: + case XML_ATACTION_DECODE_STYLE_NAME_REF: + { + OUString aAttrValue( rAttrValue ); + if( DecodeStyleName(aAttrValue) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_ENCODE_STYLE_NAME: + { + OUString aAttrValue( rAttrValue ); + if( EncodeStyleName(aAttrValue) ) + { + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + OUString aNewAttrQName( + GetNamespaceMap().GetQNameByKey( + nPrefix, + ::xmloff::token::GetXMLToken( + XML_DISPLAY_NAME ) ) ); + pMutableAttrList->AddAttribute( aNewAttrQName, + rAttrValue ); + } + } + break; + case XML_ATACTION_RENAME_ENCODE_STYLE_NAME_REF: + bRename = true; + [[fallthrough]]; + case XML_ATACTION_ENCODE_STYLE_NAME_REF: + { + OUString aAttrValue( rAttrValue ); + if( EncodeStyleName(aAttrValue) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_NEG_PERCENT: + bRename = true; + [[fallthrough]]; + case XML_ATACTION_NEG_PERCENT: + { + OUString aAttrValue( rAttrValue ); + if( NegPercent( aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_ADD_NAMESPACE_PREFIX: + bRename = true; + [[fallthrough]]; + case XML_ATACTION_ADD_NAMESPACE_PREFIX: + { + OUString aAttrValue( rAttrValue ); + sal_uInt16 nValPrefix = + static_cast( + bRename ? (*aIter).second.m_nParam2 + : (*aIter).second.m_nParam1); + AddNamespacePrefix( aAttrValue, nValPrefix ); + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_ADD_APP_NAMESPACE_PREFIX: + { + OUString aAttrValue( rAttrValue ); + sal_uInt16 nValPrefix = + static_cast((*aIter).second.m_nParam1); + if( IsXMLToken( GetClass(), XML_SPREADSHEET ) ) + nValPrefix = XML_NAMESPACE_OOOC; + else if( IsXMLToken( GetClass(), XML_TEXT ) ) + nValPrefix = XML_NAMESPACE_OOOW; + AddNamespacePrefix( aAttrValue, nValPrefix ); + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_REMOVE_NAMESPACE_PREFIX: + bRename = true; + [[fallthrough]]; + case XML_ATACTION_REMOVE_NAMESPACE_PREFIX: + { + OUString aAttrValue( rAttrValue ); + sal_uInt16 nValPrefix = + static_cast( + bRename ? (*aIter).second.m_nParam2 + : (*aIter).second.m_nParam1); + if( RemoveNamespacePrefix( aAttrValue, nValPrefix ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_REMOVE_ANY_NAMESPACE_PREFIX: + { + OUString aAttrValue( rAttrValue ); + if( RemoveNamespacePrefix( aAttrValue ) ) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_URI_OOO: + { + OUString aAttrValue( rAttrValue ); + if( ConvertURIToOASIS( aAttrValue, + static_cast< bool >((*aIter).second.m_nParam1))) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_URI_OASIS: + { + OUString aAttrValue( rAttrValue ); + if( ConvertURIToOOo( aAttrValue, + static_cast< bool >((*aIter).second.m_nParam1))) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_ATTRIBUTE: + { + OUString aAttrValue( rAttrValue ); + RenameAttributeValue( + aAttrValue, + (*aIter).second.m_nParam1, + (*aIter).second.m_nParam2, + (*aIter).second.m_nParam3 ); + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_RNG2ISO_DATETIME: + { + OUString aAttrValue( rAttrValue ); + if( ConvertRNGDateTimeToISO( aAttrValue )) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_RENAME_RNG2ISO_DATETIME: + { + OUString aAttrValue( rAttrValue ); + if( ConvertRNGDateTimeToISO( aAttrValue )) + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + bRename = true; + } + break; + case XML_ATACTION_IN2TWIPS: + { + OUString aAttrValue( rAttrValue ); + XMLTransformerBase::ReplaceSingleInWithInch( aAttrValue ); + + if( isWriter() ) + { + sal_Int16 const nDestUnit = lcl_getUnit(aAttrValue); + + // convert inch value to twips and export as faked inch + sal_Int32 nMeasure; + if (::sax::Converter::convertMeasure(nMeasure, + aAttrValue)) + { + nMeasure = o3tl::toTwips(nMeasure, o3tl::Length::mm100); + + OUStringBuffer aBuffer; + ::sax::Converter::convertMeasure( aBuffer, + nMeasure, util::MeasureUnit::MM_100TH, + nDestUnit ); + aAttrValue = aBuffer.makeStringAndClear(); + } + } + + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_SVG_WIDTH_HEIGHT_OOO: + { + OUString aAttrValue( rAttrValue ); + ReplaceSingleInchWithIn( aAttrValue ); + + sal_Int16 const nDestUnit = lcl_getUnit( aAttrValue ); + + sal_Int32 nMeasure; + if (::sax::Converter::convertMeasure(nMeasure, + aAttrValue)) + { + + if( nMeasure > 0 ) + nMeasure -= 1; + else if( nMeasure < 0 ) + nMeasure += 1; + + + OUStringBuffer aBuffer; + ::sax::Converter::convertMeasure(aBuffer, nMeasure, + util::MeasureUnit::MM_100TH, nDestUnit); + aAttrValue = aBuffer.makeStringAndClear(); + } + + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_SVG_WIDTH_HEIGHT_OASIS: + { + OUString aAttrValue( rAttrValue ); + ReplaceSingleInWithInch( aAttrValue ); + + sal_Int16 const nDestUnit = lcl_getUnit( aAttrValue ); + + sal_Int32 nMeasure; + if (::sax::Converter::convertMeasure(nMeasure, + aAttrValue)) + { + + if( nMeasure > 0 ) + nMeasure += 1; + else if( nMeasure < 0 ) + nMeasure -= 1; + + + OUStringBuffer aBuffer; + ::sax::Converter::convertMeasure(aBuffer, nMeasure, + util::MeasureUnit::MM_100TH, nDestUnit ); + aAttrValue = aBuffer.makeStringAndClear(); + } + + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + break; + case XML_ATACTION_DECODE_ID: + { + const sal_Int32 nLen = rAttrValue.getLength(); + OUStringBuffer aBuffer; + + sal_Int32 pos; + for( pos = 0; pos < nLen; pos++ ) + { + sal_Unicode c = rAttrValue[pos]; + if( (c >= '0') && (c <= '9') ) + aBuffer.append( c ); + else + aBuffer.append( static_cast(c) ); + } + + pMutableAttrList->SetValueByIndex( i, aBuffer.makeStringAndClear() ); + } + break; + // #i50322# - special handling for the + // transparency of writer background graphics. + case XML_ATACTION_WRITER_BACK_GRAPHIC_TRANSPARENCY: + { + // determine, if it's the transparency of a document style + XMLTransformerContext* pFirstContext = m_vContexts[0].get(); + OUString aFirstContextLocalName; + /* sal_uInt16 nFirstContextPrefix = */ + GetNamespaceMap().GetKeyByAttrName( pFirstContext->GetQName(), + &aFirstContextLocalName ); + bool bIsDocumentStyle( + ::xmloff::token::IsXMLToken( aFirstContextLocalName, + XML_DOCUMENT_STYLES ) ); + // no conversion of transparency value for document + // styles, because former OpenOffice.org version writes + // writes always a transparency value of 100% and doesn't + // read the value. Thus, it's interpreted as 0% + if ( !bIsDocumentStyle ) + { + OUString aAttrValue( rAttrValue ); + NegPercent(aAttrValue); + pMutableAttrList->SetValueByIndex( i, aAttrValue ); + } + bRename = true; + } + break; + case XML_ATACTION_SHAPEID: + { + OUString sNewValue = "shape" + rAttrValue; + pMutableAttrList->SetValueByIndex( i, sNewValue ); + break; + } + + default: + OSL_ENSURE( false, "unknown action" ); + break; + } + + if( bRename ) + { + OUString aNewAttrQName( + GetNamespaceMap().GetQNameByKey( + (*aIter).second.GetQNamePrefixFromParam1(), + ::xmloff::token::GetXMLToken( + (*aIter).second.GetQNameTokenFromParam1()) ) ); + pMutableAttrList->RenameAttributeByIndex( i, + aNewAttrQName ); + } + } + } + } + + return pMutableAttrList.get(); +} + +bool XMLTransformerBase::ReplaceSingleInchWithIn( OUString& rValue ) +{ + bool bRet = false; + sal_Int32 nPos = rValue.getLength(); + while( nPos && rValue[nPos-1] <= ' ' ) + --nPos; + if( nPos > 2 && + ('c'==rValue[nPos-2] || 'C'==rValue[nPos-2]) && + ('h'==rValue[nPos-1] || 'H'==rValue[nPos-1]) ) + { + rValue =rValue.copy( 0, nPos-2 ); + bRet = true; + } + + return bRet; +} + +bool XMLTransformerBase::ReplaceInchWithIn( OUString& rValue ) +{ + bool bRet = false; + sal_Int32 nPos = 1; + while( nPos < rValue.getLength()-3 ) + { + sal_Unicode c = rValue[nPos]; + if( 'i'==c || 'I'==c ) + { + c = rValue[nPos-1]; + if( (c >= '0' && c <= '9') || '.' == c ) + { + c = rValue[nPos+1]; + if( 'n'==c || 'N'==c ) + { + c = rValue[nPos+2]; + if( 'c'==c || 'C'==c ) + { + c = rValue[nPos+3]; + if( 'h'==c || 'H'==c ) + { + rValue = rValue.replaceAt( nPos, + 4, GetXMLToken(XML_IN) ); + nPos += 2; + bRet = true; + continue; + } + } + } + } + } + ++nPos; + } + + return bRet; +} + +bool XMLTransformerBase::ReplaceSingleInWithInch( OUString& rValue ) +{ + bool bRet = false; + + sal_Int32 nPos = rValue.getLength(); + while( nPos && rValue[nPos-1] <= ' ' ) + --nPos; + if( nPos > 2 && + ('i'==rValue[nPos-2] || + 'I'==rValue[nPos-2]) && + ('n'==rValue[nPos-1] || + 'N'==rValue[nPos-1]) ) + { + nPos -= 2; + rValue = rValue.replaceAt( nPos, rValue.getLength() - nPos, + GetXMLToken(XML_INCH) ); + bRet = true; + } + + return bRet; +} + +bool XMLTransformerBase::ReplaceInWithInch( OUString& rValue ) +{ + bool bRet = false; + sal_Int32 nPos = 1; + while( nPos < rValue.getLength()-1 ) + { + sal_Unicode c = rValue[nPos]; + if( 'i'==c || 'I'==c ) + { + c = rValue[nPos-1]; + if( (c >= '0' && c <= '9') || '.' == c ) + { + c = rValue[nPos+1]; + if( 'n'==c || 'N'==c ) + { + rValue = rValue.replaceAt( nPos, + 2, GetXMLToken(XML_INCH) ); + nPos += 4; + bRet = true; + continue; + } + } + } + ++nPos; + } + + return bRet; +} + +bool XMLTransformerBase::EncodeStyleName( OUString& rName ) const +{ + static const char aHexTab[] = "0123456789abcdef"; + + bool bEncoded = false; + + sal_Int32 nLen = rName.getLength(); + OUStringBuffer aBuffer( nLen ); + + for( sal_Int32 i = 0; i < nLen; i++ ) + { + sal_Unicode c = rName[i]; + bool bValidChar = false; + if( c < 0x00ffU ) + { + bValidChar = + (c >= 0x0041 && c <= 0x005a) || + (c >= 0x0061 && c <= 0x007a) || + (c >= 0x00c0 && c <= 0x00d6) || + (c >= 0x00d8 && c <= 0x00f6) || + (c >= 0x00f8 && c <= 0x00ff) || + ( i > 0 && ( (c >= 0x0030 && c <= 0x0039) || + c == 0x00b7 || c == '-' || c == '.') ); + } + else + { + if( (c >= 0xf900U && c <= 0xfffeU) || + (c >= 0x20ddU && c <= 0x20e0U)) + { + bValidChar = false; + } + else if( (c >= 0x02bbU && c <= 0x02c1U) || c == 0x0559 || + c == 0x06e5 || c == 0x06e6 ) + { + bValidChar = true; + } + else if( c == 0x0387 ) + { + bValidChar = i > 0; + } + else + { + if( !xCharClass.is() ) + { + const_cast < XMLTransformerBase * >(this) + ->xCharClass = CharacterClassification::create( comphelper::getProcessComponentContext() ); + } + sal_Int16 nType = xCharClass->getType( rName, i ); + + switch( nType ) + { + case UnicodeType::UPPERCASE_LETTER: // Lu + case UnicodeType::LOWERCASE_LETTER: // Ll + case UnicodeType::TITLECASE_LETTER: // Lt + case UnicodeType::OTHER_LETTER: // Lo + case UnicodeType::LETTER_NUMBER: // Nl + bValidChar = true; + break; + case UnicodeType::NON_SPACING_MARK: // Ms + case UnicodeType::ENCLOSING_MARK: // Me + case UnicodeType::COMBINING_SPACING_MARK: //Mc + case UnicodeType::MODIFIER_LETTER: // Lm + case UnicodeType::DECIMAL_DIGIT_NUMBER: // Nd + bValidChar = i > 0; + break; + } + } + } + if( bValidChar ) + { + aBuffer.append( c ); + } + else + { + aBuffer.append( '_' ); + if( c > 0x0fff ) + aBuffer.append( static_cast< sal_Unicode >( + aHexTab[ (c >> 12) & 0x0f ] ) ); + if( c > 0x00ff ) + aBuffer.append( static_cast< sal_Unicode >( + aHexTab[ (c >> 8) & 0x0f ] ) ); + if( c > 0x000f ) + aBuffer.append( static_cast< sal_Unicode >( + aHexTab[ (c >> 4) & 0x0f ] ) ); + aBuffer.append( static_cast< sal_Unicode >( + aHexTab[ c & 0x0f ] ) ); + aBuffer.append( '_' ); + bEncoded = true; + } + } + + if( aBuffer.getLength() > (1<<15)-1 ) + bEncoded = false; + + if( bEncoded ) + rName = aBuffer.makeStringAndClear(); + return bEncoded; +} + +bool XMLTransformerBase::DecodeStyleName( OUString& rName ) +{ + bool bEncoded = false; + + sal_Int32 nLen = rName.getLength(); + OUStringBuffer aBuffer( nLen ); + + bool bWithinHex = false; + sal_Unicode cEnc = 0; + for( sal_Int32 i = 0; i < nLen; i++ ) + { + sal_Unicode c = rName[i]; + if( '_' == c ) + { + if( bWithinHex ) + { + aBuffer.append( cEnc ); + cEnc = 0; + } + else + { + bEncoded = true; + } + bWithinHex = !bWithinHex; + } + else if( bWithinHex ) + { + sal_Unicode cDigit; + if( c >= '0' && c <= '9' ) + { + cDigit = c - '0'; + } + else if( c >= 'a' && c <= 'f' ) + { + cDigit = c - 'a' + 10; + } + else if( c >= 'A' && c <= 'F' ) + { + cDigit = c - 'A' + 10; + } + else + { + // error + bEncoded = false; + break; + } + cEnc = (cEnc << 4) + cDigit; + } + else + { + aBuffer.append( c ); + } + } + + if( bEncoded ) + rName = aBuffer.makeStringAndClear(); + return bEncoded; +} + +bool XMLTransformerBase::NegPercent( OUString& rValue ) +{ + bool bRet = false; + bool bNeg = false; + double nVal = 0; + + sal_Int32 nPos = 0; + sal_Int32 nLen = rValue.getLength(); + + // skip white space + while( nPos < nLen && ' ' == rValue[nPos] ) + nPos++; + + if( nPos < nLen && '-' == rValue[nPos] ) + { + bNeg = true; + nPos++; + } + + // get number + while( nPos < nLen && + '0' <= rValue[nPos] && + '9' >= rValue[nPos] ) + { + // TODO: check overflow! + nVal *= 10; + nVal += (rValue[nPos] - '0'); + nPos++; + } + if( nPos < nLen && '.' == rValue[nPos] ) + { + nPos++; + double nDiv = 1.; + + while( nPos < nLen && + '0' <= rValue[nPos] && + '9' >= rValue[nPos] ) + { + // TODO: check overflow! + nDiv *= 10; + nVal += ( static_cast(rValue[nPos] - '0') / nDiv ); + nPos++; + } + } + + // skip white space + while( nPos < nLen && ' ' == rValue[nPos] ) + nPos++; + + if( nPos < nLen && '%' == rValue[nPos] ) + { + if( bNeg ) + nVal = -nVal; + nVal += .5; + + sal_Int32 nIntVal = 100 - static_cast( nVal ); + + rValue = OUString::number(nIntVal) + "%"; + + bRet = true; + } + + return bRet; +} + +void XMLTransformerBase::AddNamespacePrefix( OUString& rName, + sal_uInt16 nPrefix ) const +{ + rName = GetNamespaceMap().GetQNameByKey( nPrefix, rName, false ); +} + +bool XMLTransformerBase::RemoveNamespacePrefix( OUString& rName, + sal_uInt16 nPrefixOnly ) const +{ + OUString aLocalName; + sal_uInt16 nPrefix = + GetNamespaceMap().GetKeyByAttrValueQName(rName, &aLocalName); + bool bRet = XML_NAMESPACE_UNKNOWN != nPrefix && + (USHRT_MAX == nPrefixOnly || nPrefix == nPrefixOnly); + if( bRet ) + rName = aLocalName; + + return bRet; +} + +bool XMLTransformerBase::ConvertURIToOASIS( OUString& rURI, + bool bSupportPackage ) const +{ + bool bRet = false; + if( !m_aExtPathPrefix.isEmpty() && !rURI.isEmpty() ) + { + bool bRel = false; + switch( rURI[0] ) + { + case '#': + // no rel path, but + // for package URIs, the '#' has to be removed + if( bSupportPackage ) + { + rURI = rURI.copy( 1 ); + bRet = true; + } + break; + case '/': + // no rel path; nothing to do + break; + case '.': + // a rel path; to keep URI simple, remove './', if there + bRel = true; + if( rURI.getLength() > 1 && '/' == rURI[1] ) + { + rURI = rURI.copy( 2 ); + bRet = true; + } + break; + default: + // check for a RFC2396 schema + { + bRel = true; + sal_Int32 nPos = 1; + sal_Int32 nLen = rURI.getLength(); + while( nPos < nLen ) + { + switch( rURI[nPos] ) + { + case '/': + // a relative path segment + nPos = nLen; // leave loop + break; + case ':': + // a schema + bRel = false; + nPos = nLen; // leave loop + break; + default: + // we don't care about any other characters + break; + } + ++nPos; + } + } + } + + if( bRel ) + { + rURI = m_aExtPathPrefix + rURI; + bRet = true; + } + } + + return bRet; +} + +bool XMLTransformerBase::ConvertURIToOOo( OUString& rURI, + bool bSupportPackage ) const +{ + bool bRet = false; + if( !rURI.isEmpty() ) + { + bool bPackage = false; + switch( rURI[0] ) + { + case '/': + // no rel path; nothing to do + break; + case '.': + // a rel path + if( rURI.startsWith( m_aExtPathPrefix ) ) + { + // an external URI; remove '../' + rURI = rURI.copy( m_aExtPathPrefix.getLength() ); + bRet = true; + } + else + { + bPackage = true; + } + break; + default: + // check for a RFC2396 schema + { + bPackage = true; + sal_Int32 nPos = 1; + sal_Int32 nLen = rURI.getLength(); + while( nPos < nLen ) + { + switch( rURI[nPos] ) + { + case '/': + // a relative path segment within the package + nPos = nLen - 1; // leave loop + break; + case ':': + // a schema + bPackage = false; + nPos = nLen - 1; // leave loop + break; + default: + // we don't care about any other characters + break; + } + ++nPos; + } + } + } + + if( bPackage && bSupportPackage ) + { + OUString sTmp( '#' ); + if( rURI.startsWith( "./" ) ) + rURI = rURI.copy( 2 ); + sTmp += rURI; + rURI = sTmp; + bRet = true; + } + } + + return bRet; +} + +bool XMLTransformerBase::RenameAttributeValue( + OUString& rOutAttributeValue, + sal_Int32 nParam1, + sal_Int32 nParam2, + sal_Int32 nParam3 ) +{ + return ( lcl_ConvertAttr( rOutAttributeValue, nParam1) || + lcl_ConvertAttr( rOutAttributeValue, nParam2) || + lcl_ConvertAttr( rOutAttributeValue, nParam3) ); +} + +// static +bool XMLTransformerBase::ConvertRNGDateTimeToISO( OUString& rDateTime ) +{ + if( !rDateTime.isEmpty() && + rDateTime.indexOf( '.' ) != -1 ) + { + rDateTime = rDateTime.replace( '.', ','); + return true; + } + + return false; +} + +XMLTokenEnum XMLTransformerBase::GetToken( const OUString& rStr ) const +{ + XMLTransformerTokenMap::const_iterator aIter = + m_TokenMap.find( rStr ); + if( aIter == m_TokenMap.end() ) + return XML_TOKEN_END; + else + return (*aIter).second; +} + + +const XMLTransformerContext *XMLTransformerBase::GetCurrentContext() const +{ + OSL_ENSURE( !m_vContexts.empty(), "empty stack" ); + + + return m_vContexts.empty() ? nullptr : m_vContexts.back().get(); +} + +const XMLTransformerContext *XMLTransformerBase::GetAncestorContext( + sal_uInt32 n ) const +{ + auto nSize = m_vContexts.size(); + + OSL_ENSURE( nSize > n + 2 , "invalid context" ); + + return nSize > n + 2 ? m_vContexts[nSize - (n + 2)].get() : nullptr; +} + +bool XMLTransformerBase::isWriter() const +{ + Reference< XServiceInfo > xSI( mxModel, UNO_QUERY ); + return xSI.is() && + ( xSI->supportsService("com.sun.star.text.TextDocument") || + xSI->supportsService("com.sun.star.text.WebDocument") || + xSI->supportsService("com.sun.star.text.GlobalDocument") ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerBase.hxx b/xmloff/source/transform/TransformerBase.hxx new file mode 100644 index 000000000..8fb4e6adf --- /dev/null +++ b/xmloff/source/transform/TransformerBase.hxx @@ -0,0 +1,179 @@ +/* -*- 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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "Transformer.hxx" +#include "TransformerActions.hxx" +#include "TransformerTokenMap.hxx" + +namespace com::sun::star { + namespace i18n { class XCharacterClassification; } +} + +class SvXMLNamespaceMap; +class XMLTransformerContext; +class XMLTransformerActions; +struct XMLTransformerActionInit; +struct TransformerAction_Impl; +class XMLMutableAttributeList; + +const sal_uInt16 INVALID_ACTIONS = 0xffff; + +class XMLTransformerBase : public XMLTransformer +{ + friend class XMLTransformerContext; + + css::uno::Reference< css::xml::sax::XDocumentHandler > m_xHandler; // the handlers + css::uno::Reference< css::beans::XPropertySet > m_xPropSet; + css::uno::Reference< css::i18n::XCharacterClassification > xCharClass; + + OUString m_aExtPathPrefix; + OUString m_aClass; + + std::unique_ptr m_pNamespaceMap; + SvXMLNamespaceMap m_vReplaceNamespaceMap; + std::vector> m_vContexts; + XMLTransformerActions m_ElemActions; + XMLTransformerTokenMap const m_TokenMap; + +protected: + css::uno::Reference< css::frame::XModel > mxModel; + + // This method is called after the namespace map has been updated, but + // before a context for the current element has been pushed. + XMLTransformerContext *CreateContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName ); + +public: + XMLTransformerBase( XMLTransformerActionInit const *pInit, + ::xmloff::token::XMLTokenEnum const *pTKMapInit ) noexcept; + virtual ~XMLTransformerBase() noexcept override; + + // css::xml::sax::XDocumentHandler + virtual void SAL_CALL startDocument() override; + virtual void SAL_CALL endDocument() override; + virtual void SAL_CALL startElement(const OUString& aName, + const css::uno::Reference< css::xml::sax::XAttributeList > & xAttribs) override; + virtual void SAL_CALL endElement(const OUString& aName) override; + virtual void SAL_CALL characters(const OUString& aChars) override; + virtual void SAL_CALL ignorableWhitespace(const OUString& aWhitespaces) override; + virtual void SAL_CALL processingInstruction(const OUString& aTarget, + const OUString& aData) override; + virtual void SAL_CALL setDocumentLocator(const css::uno::Reference< css::xml::sax::XLocator > & xLocator) override; + + // css::xml::sax::XExtendedDocumentHandler + virtual void SAL_CALL startCDATA() override; + virtual void SAL_CALL endCDATA() override; + virtual void SAL_CALL comment(const OUString& sComment) override; + virtual void SAL_CALL allowLineBreak() override; + virtual void SAL_CALL unknown(const OUString& sString) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // C++ + const css::uno::Reference< css::xml::sax::XDocumentHandler > & GetDocHandler() const { return m_xHandler; } + + const css::uno::Reference< css::beans::XPropertySet > & GetPropertySet() const { return m_xPropSet; } + + + SvXMLNamespaceMap& GetNamespaceMap() { return *m_pNamespaceMap; } + const SvXMLNamespaceMap& GetNamespaceMap() const { return *m_pNamespaceMap; } + SvXMLNamespaceMap& GetReplaceNamespaceMap() { return m_vReplaceNamespaceMap; } + + XMLTransformerActions& GetElemActions() { return m_ElemActions; } + virtual XMLTransformerActions *GetUserDefinedActions( sal_uInt16 n ); + virtual XMLTransformerContext *CreateUserDefinedContext( + const TransformerAction_Impl& rAction, + const OUString& rQName, + bool bPersistent=false ) = 0; + virtual OUString GetEventName( const OUString& rName, + bool bForm = false ) = 0; + + + XMLMutableAttributeList *ProcessAttrList( css::uno::Reference< css::xml::sax::XAttributeList >& rAttrList, + sal_uInt16 nActionMap, bool bClone ); + + static bool ReplaceSingleInchWithIn( OUString& rValue ); + static bool ReplaceSingleInWithInch( OUString& rValue ); + static bool ReplaceInchWithIn( OUString& rValue ); + static bool ReplaceInWithInch( OUString& rValue ); + + bool EncodeStyleName( OUString& rName ) const; + static bool DecodeStyleName( OUString& rName ); + static bool NegPercent( OUString& rValue ); + + void AddNamespacePrefix( OUString& rName, + sal_uInt16 nPrefix ) const; + bool RemoveNamespacePrefix( OUString& rName, + sal_uInt16 nPrefixOnly=0xffffU ) const; + + bool ConvertURIToOASIS( OUString& rURI, + bool bSupportPackage ) const; + bool ConvertURIToOOo( OUString& rURI, + bool bSupportPackage ) const; + + /** renames the given rOutAttributeValue if one of the parameters contains a + matching token in its lower 16 bits. The value is converted to the + token that is given in the upper 16 bits of the matching parameter. + */ + static bool RenameAttributeValue( OUString& rOutAttributeValue, + sal_Int32 nParam1, + sal_Int32 nParam2, + sal_Int32 nParam3 ); + + /** converts the '.' that separates fractions of seconds in a dateTime + string into a ',' that was used in the OOo format + + @param rDateTime + A dateTime string that will be parsed and changed in case a match + was found. + @return if the given string was changed + */ + static bool ConvertRNGDateTimeToISO( OUString& rDateTime ); + + ::xmloff::token::XMLTokenEnum GetToken( const OUString& rStr ) const; + + const XMLTransformerContext *GetCurrentContext() const; + const XMLTransformerContext *GetAncestorContext( sal_uInt32 i ) const; + + // C++ + void SetClass( const OUString& r ) { m_aClass = r; } + const OUString& GetClass() const { return m_aClass; } + + bool isWriter() const; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerContext.cxx b/xmloff/source/transform/TransformerContext.cxx new file mode 100644 index 000000000..f4669aac4 --- /dev/null +++ b/xmloff/source/transform/TransformerContext.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 +#include +#include +#include + +#include "TransformerBase.hxx" + +#include "TransformerContext.hxx" + + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::xml::sax; + +bool XMLTransformerContext::HasQName( sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ) const +{ + OUString aLocalName; + return GetTransformer().GetNamespaceMap().GetKeyByAttrName( m_aQName, + &aLocalName ) == nPrefix && + ::xmloff::token::IsXMLToken( aLocalName, eToken ); +} + +bool XMLTransformerContext::HasNamespace( sal_uInt16 nPrefix ) const +{ + return GetTransformer().GetNamespaceMap().GetKeyByAttrName( m_aQName ) == nPrefix; +} + +XMLTransformerContext::XMLTransformerContext( XMLTransformerBase& rImp, + const OUString& rQName ) + : m_rTransformer(rImp) + , m_aQName(rQName) +{ +} + +rtl::Reference XMLTransformerContext::CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const Reference< XAttributeList >& ) +{ + return m_rTransformer.CreateContext( nPrefix, rLocalName, rQName ); +} + +void XMLTransformerContext::StartElement( const Reference< XAttributeList >& rAttrList ) +{ + m_rTransformer.GetDocHandler()->startElement( m_aQName, rAttrList ); +} + +void XMLTransformerContext::EndElement() +{ + GetTransformer().GetDocHandler()->endElement( m_aQName ); +} + +void XMLTransformerContext::Characters( const OUString& rChars ) +{ + m_rTransformer.GetDocHandler()->characters( rChars ); +} + +bool XMLTransformerContext::IsPersistent() const +{ + return false; +} + +void XMLTransformerContext::Export() +{ + OSL_ENSURE( false, "context is not persistent" ); +} + +void XMLTransformerContext::ExportContent() +{ + OSL_ENSURE( false, "context is not persistent" ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerContext.hxx b/xmloff/source/transform/TransformerContext.hxx new file mode 100644 index 000000000..97df7498a --- /dev/null +++ b/xmloff/source/transform/TransformerContext.hxx @@ -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/. + * + * 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 +#include +#include +#include +#include +#include +#include + +class SvXMLNamespaceMap; +class XMLTransformerBase; + +class XMLTransformerContext : public ::salhelper::SimpleReferenceObject +{ + friend class XMLTransformerBase; + + XMLTransformerBase& m_rTransformer; + + OUString m_aQName; + + std::unique_ptr m_xRewindMap; + + std::unique_ptr TakeRewindMap() { return std::move(m_xRewindMap); } + void PutRewindMap( std::unique_ptr p ) { m_xRewindMap = std::move(p); } + +protected: + + XMLTransformerBase& GetTransformer() { return m_rTransformer; } + const XMLTransformerBase& GetTransformer() const { return m_rTransformer; } + + void SetQName( const OUString& rQName ) { m_aQName = rQName; } + +public: + const OUString& GetQName() const { return m_aQName; } + bool HasQName( sal_uInt16 nPrefix, + ::xmloff::token::XMLTokenEnum eToken ) const; + bool HasNamespace( sal_uInt16 nPrefix ) const; + + // A contexts constructor does anything that is required if an element + // starts. Namespace processing has been done already. + // Note that virtual methods cannot be used inside constructors. Use + // StartElement instead if this is required. + XMLTransformerContext( XMLTransformerBase& rTransformer, + const OUString& rQName ); + + // Create a children element context. By default, the import's + // CreateContext method is called to create a new default context. + virtual rtl::Reference CreateChildContext( sal_uInt16 nPrefix, + const OUString& rLocalName, + const OUString& rQName, + const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ); + + // StartElement is called after a context has been constructed and + // before an elements context is parsed. It may be used for actions that + // require virtual methods. The default is to do nothing. + virtual void StartElement( const css::uno::Reference< css::xml::sax::XAttributeList >& xAttrList ); + + // EndElement is called before a context will be destructed, but + // after an elements context has been parsed. It may be used for actions + // that require virtual methods. The default is to do nothing. + virtual void EndElement(); + + // This method is called for all characters that are contained in the + // current element. The default is to ignore them. + virtual void Characters( const OUString& rChars ); + + // Is the current context a persistent one (i.e. one that saves is content + // rather than exporting it directly? + virtual bool IsPersistent() const; + + // Export the whole element. By default, nothing is done here + virtual void Export(); + + // Export the element content. By default, nothing is done here + virtual void ExportContent(); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerTokenMap.cxx b/xmloff/source/transform/TransformerTokenMap.cxx new file mode 100644 index 000000000..fc1147114 --- /dev/null +++ b/xmloff/source/transform/TransformerTokenMap.cxx @@ -0,0 +1,38 @@ +/* -*- 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 "TransformerTokenMap.hxx" + +using namespace ::xmloff::token; + +XMLTransformerTokenMap::XMLTransformerTokenMap( XMLTokenEnum const *pInit ) +{ + if( pInit ) + { + while( *pInit != XML_TOKEN_END ) + { + XMLTransformerTokenMap::value_type aVal( GetXMLToken( *pInit ), + *pInit ); + insert( aVal ); + ++pInit; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/TransformerTokenMap.hxx b/xmloff/source/transform/TransformerTokenMap.hxx new file mode 100644 index 000000000..ae810dc66 --- /dev/null +++ b/xmloff/source/transform/TransformerTokenMap.hxx @@ -0,0 +1,32 @@ +/* -*- 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 +#include +#include + +class XMLTransformerTokenMap : public std::unordered_map +{ +public: + explicit XMLTransformerTokenMap(::xmloff::token::XMLTokenEnum const* pInit); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/transform/xof.component b/xmloff/source/transform/xof.component new file mode 100644 index 000000000..5039731f5 --- /dev/null +++ b/xmloff/source/transform/xof.component @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xmloff/source/transform/xof.component.chart b/xmloff/source/transform/xof.component.chart new file mode 100644 index 000000000..77713a8b7 --- /dev/null +++ b/xmloff/source/transform/xof.component.chart @@ -0,0 +1,11 @@ +# 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/. + +com.sun.star.comp.Chart.XMLContentImporter +com.sun.star.comp.Chart.XMLImporter +com.sun.star.comp.Chart.XMLStylesImporter +com.sun.star.comp.Oasis2OOoTransformer +com.sun.star.comp.OOo2OasisTransformer diff --git a/xmloff/source/xforms/SchemaContext.cxx b/xmloff/source/xforms/SchemaContext.cxx new file mode 100644 index 000000000..573805a25 --- /dev/null +++ b/xmloff/source/xforms/SchemaContext.cxx @@ -0,0 +1,62 @@ +/* -*- 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 "SchemaContext.hxx" + +#include "SchemaSimpleTypeContext.hxx" + +#include +#include +#include +#include +#include + +#include + +using com::sun::star::uno::Reference; +using com::sun::star::xml::sax::XFastAttributeList; +using com::sun::star::xforms::XDataTypeRepository; +using namespace xmloff::token; + + +SchemaContext::SchemaContext( + SvXMLImport& rImport, + const Reference& rRepository ) : + TokenContext( rImport ), + mxRepository( rRepository ) +{ +} + +void SchemaContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & ) +{ +} + +SvXMLImportContext* SchemaContext::HandleChild( + sal_Int32 nElementToken, + const Reference& ) +{ + if ( nElementToken == XML_ELEMENT(XSD, XML_SIMPLETYPE) ) + return new SchemaSimpleTypeContext( GetImport(), mxRepository ); + else + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaContext.hxx b/xmloff/source/xforms/SchemaContext.hxx new file mode 100644 index 000000000..e6896e760 --- /dev/null +++ b/xmloff/source/xforms/SchemaContext.hxx @@ -0,0 +1,53 @@ +/* -*- 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 "TokenContext.hxx" +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XDataTypeRepository; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the data type declarations from an xsd:schema element */ +class SchemaContext : public TokenContext +{ + css::uno::Reference mxRepository; + +public: + SchemaContext( SvXMLImport& rImport, + const css::uno::Reference& rRepository ); + + // implement TokenContext methods: + +protected: + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaRestrictionContext.cxx b/xmloff/source/xforms/SchemaRestrictionContext.cxx new file mode 100644 index 000000000..2785ad9e9 --- /dev/null +++ b/xmloff/source/xforms/SchemaRestrictionContext.cxx @@ -0,0 +1,335 @@ +/* -*- 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 "SchemaRestrictionContext.hxx" +#include "xformsapi.hxx" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Exception; +using com::sun::star::uno::Any; +using namespace com::sun::star; +using com::sun::star::util::Duration; +using com::sun::star::xml::sax::XFastAttributeList; +using com::sun::star::xforms::XDataTypeRepository; +using namespace xmloff::token; + + +SchemaRestrictionContext::SchemaRestrictionContext( + SvXMLImport& rImport, + Reference const & rRepository, + const OUString& sTypeName ) : + TokenContext( rImport ), + mxRepository( rRepository ), + msTypeName( sTypeName ) +{ + SAL_WARN_IF( !mxRepository.is(), "xmloff", "need repository" ); +} + +void SchemaRestrictionContext::CreateDataType() +{ + // only do something if we don't have a data type already + if( mxDataType.is() ) + return; + + SAL_WARN_IF( msBaseName.isEmpty(), "xmloff", "no base name?" ); + SAL_WARN_IF( !mxRepository.is(), "xmloff", "no repository?" ); + + try + { + mxDataType = + mxRepository->cloneDataType( + xforms_getBasicTypeName( mxRepository, + GetImport().GetNamespaceMap(), + msBaseName ), + msTypeName ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff", "exception during type creation"); + } + SAL_WARN_IF( !mxDataType.is(), "xmloff", "can't create type" ); +} + +void SchemaRestrictionContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken() & TOKEN_MASK) + { + case XML_BASE: + msBaseName = aIter.toString(); + break; + } +} + +typedef Any (*convert_t)( const OUString& ); + +static Any xforms_string( const OUString& rValue ) +{ + return Any( rValue ); +} + +static Any xforms_int32( const OUString& rValue ) +{ + sal_Int32 nValue; + bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue ); + return bSuccess ? Any( nValue ) : Any(); +} + +static Any xforms_int16( const OUString& rValue ) +{ + sal_Int32 nValue; + bool bSuccess = ::sax::Converter::convertNumber( nValue, rValue ); + return bSuccess ? Any( static_cast( nValue ) ) : Any(); +} + +static Any xforms_whitespace( const OUString& rValue ) +{ + Any aValue; + if( IsXMLToken( rValue, XML_PRESERVE ) ) + aValue <<= css::xsd::WhiteSpaceTreatment::Preserve; + else if( IsXMLToken( rValue, XML_REPLACE ) ) + aValue <<= css::xsd::WhiteSpaceTreatment::Replace; + else if( IsXMLToken( rValue, XML_COLLAPSE ) ) + aValue <<= css::xsd::WhiteSpaceTreatment::Collapse; + return aValue; +} + +static Any xforms_double( const OUString& rValue ) +{ + double fValue; + bool bSuccess = ::sax::Converter::convertDouble( fValue, rValue ); + return bSuccess ? Any( fValue ) : Any(); +} + +static Any xforms_date( const OUString& rValue ) +{ + Any aAny; + + // parse ISO date + sal_Int32 nPos1 = rValue.indexOf( '-' ); + sal_Int32 nPos2 = rValue.indexOf( '-', nPos1 + 1 ); + if( nPos1 > 0 && nPos2 > 0 ) + { + util::Date aDate; + aDate.Year = static_cast( + o3tl::toInt32(rValue.subView( 0, nPos1 )) ); + aDate.Month = static_cast( + o3tl::toInt32(rValue.subView( nPos1 + 1, nPos2 - nPos1 - 1 )) ); + aDate.Day = static_cast( + o3tl::toInt32(rValue.subView( nPos2 + 1 )) ); + aAny <<= aDate; + } + return aAny; +} + +static Any xforms_dateTime( const OUString& rValue ) +{ + util::DateTime aDateTime; + bool const bSuccess = ::sax::Converter::parseDateTime(aDateTime, rValue); + return bSuccess ? Any( aDateTime ) : Any(); +} + +static Any xforms_time( const OUString& rValue ) +{ + Any aAny; + Duration aDuration; + if (::sax::Converter::convertDuration( aDuration, rValue )) + { + css::util::Time aTime; + aTime.Hours = aDuration.Hours; + aTime.Minutes = aDuration.Minutes; + aTime.Seconds = aDuration.Seconds; + aTime.NanoSeconds = aDuration.NanoSeconds; + aAny <<= aTime; + } + return aAny; +} + + +SvXMLImportContext* SchemaRestrictionContext::HandleChild( + sal_Int32 nElementToken, + const Reference& xAttrList ) +{ + // find value + OUString sValue; + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( ( aIter.getToken() & TOKEN_MASK) == XML_VALUE ) + { + sValue = aIter.toString(); + break; + } + } + + // determine property name + suitable converter + OUString sPropertyName; + convert_t pConvert = nullptr; + switch( nElementToken & TOKEN_MASK ) + { + case XML_LENGTH: + sPropertyName = "Length"; + pConvert = &xforms_int32; + break; + case XML_MINLENGTH: + sPropertyName = "MinLength"; + pConvert = &xforms_int32; + break; + case XML_MAXLENGTH: + sPropertyName = "MaxLength"; + pConvert = &xforms_int32; + break; + case XML_TOTALDIGITS: + sPropertyName = "TotalDigits"; + pConvert = &xforms_int32; + break; + case XML_FRACTIONDIGITS: + sPropertyName = "FractionDigits"; + pConvert = &xforms_int32; + break; + case XML_PATTERN: + sPropertyName = "Pattern"; + pConvert = &xforms_string; + break; + case XML_WHITESPACE: + sPropertyName = "WhiteSpace"; + pConvert = &xforms_whitespace; + break; + case XML_MININCLUSIVE: + case XML_MINEXCLUSIVE: + case XML_MAXINCLUSIVE: + case XML_MAXEXCLUSIVE: + { + // these attributes are mapped to different properties. + // To determine the property name, we use an attribute + // dependent prefix and a type dependent suffix. The + // converter is only type dependent. + + // first, attribute-dependent prefix + switch( nElementToken & TOKEN_MASK ) + { + case XML_MININCLUSIVE: + sPropertyName = "MinInclusive"; + break; + case XML_MINEXCLUSIVE: + sPropertyName = "MinExclusive"; + break; + case XML_MAXINCLUSIVE: + sPropertyName = "MaxInclusive"; + break; + case XML_MAXEXCLUSIVE: + sPropertyName = "MaxExclusive"; + break; + } + + // second, type-dependent suffix + converter + switch( xforms_getTypeClass( mxRepository, + GetImport().GetNamespaceMap(), + msBaseName ) ) + { + case css::xsd::DataTypeClass::DECIMAL: + case css::xsd::DataTypeClass::DOUBLE: + case css::xsd::DataTypeClass::FLOAT: + sPropertyName += "Double"; + pConvert = &xforms_double; + break; + case css::xsd::DataTypeClass::DATETIME: + sPropertyName += "DateTime"; + pConvert = &xforms_dateTime; + break; + case css::xsd::DataTypeClass::DATE: + sPropertyName += "Date"; + pConvert = &xforms_date; + break; + case css::xsd::DataTypeClass::TIME: + sPropertyName += "Time"; + pConvert = &xforms_time; + break; + case css::xsd::DataTypeClass::gYear: + case css::xsd::DataTypeClass::gDay: + case css::xsd::DataTypeClass::gMonth: + sPropertyName += "Int"; + pConvert = &xforms_int16; + break; + + case css::xsd::DataTypeClass::STRING: + case css::xsd::DataTypeClass::anyURI: + case css::xsd::DataTypeClass::BOOLEAN: + // invalid: These shouldn't have min/max-inclusive + break; + + /* data types not yet supported: + case css::xsd::DataTypeClass::DURATION: + case css::xsd::DataTypeClass::gYearMonth: + case css::xsd::DataTypeClass::gMonthDay: + case css::xsd::DataTypeClass::hexBinary: + case css::xsd::DataTypeClass::base64Binary: + case css::xsd::DataTypeClass::QName: + case css::xsd::DataTypeClass::NOTATION: + */ + } + } + break; + + default: + OSL_FAIL( "unknown facet" ); + } + + // finally, set the property + CreateDataType(); + if( mxDataType.is() + && !sPropertyName.isEmpty() + && pConvert != nullptr + && mxDataType->getPropertySetInfo()->hasPropertyByName(sPropertyName) ) + { + try + { + mxDataType->setPropertyValue( sPropertyName, pConvert( sValue ) ); + } + catch( const Exception& ) + { + ; // can't set property? Then ignore. + } + } + + return new SvXMLImportContext( GetImport() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaRestrictionContext.hxx b/xmloff/source/xforms/SchemaRestrictionContext.hxx new file mode 100644 index 000000000..47cf4b088 --- /dev/null +++ b/xmloff/source/xforms/SchemaRestrictionContext.hxx @@ -0,0 +1,60 @@ +/* -*- 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 "TokenContext.hxx" +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XDataTypeRepository; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xsd:restriction element */ +class SchemaRestrictionContext : public TokenContext +{ + css::uno::Reference mxRepository; + css::uno::Reference mxDataType; + OUString const msTypeName; + OUString msBaseName; + +public: + SchemaRestrictionContext( SvXMLImport& rImport, + css::uno::Reference const & rRepository, + const OUString& sTypeName ); + +private: + // create mxDataType (if not already present) + void CreateDataType(); + + // implement TokenContext methods: + + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaSimpleTypeContext.cxx b/xmloff/source/xforms/SchemaSimpleTypeContext.cxx new file mode 100644 index 000000000..cd2451930 --- /dev/null +++ b/xmloff/source/xforms/SchemaSimpleTypeContext.cxx @@ -0,0 +1,74 @@ +/* -*- 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 "SchemaSimpleTypeContext.hxx" + +#include "SchemaRestrictionContext.hxx" +#include +#include +#include +#include +#include + +#include +#include + +using com::sun::star::uno::Reference; +using com::sun::star::xml::sax::XFastAttributeList; +using com::sun::star::xforms::XDataTypeRepository; +using namespace xmloff::token; + + +SchemaSimpleTypeContext::SchemaSimpleTypeContext( + SvXMLImport& rImport, + const Reference& rRepository ) : + TokenContext( rImport ), + mxRepository( rRepository ) +{ +} + +void SchemaSimpleTypeContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken() & TOKEN_MASK) + { + case XML_NAME: + msTypeName = aIter.toString(); + break; + } +} + +SvXMLImportContext* SchemaSimpleTypeContext::HandleChild( + sal_Int32 nElementToken, + const Reference& ) +{ + switch( nElementToken ) + { + case XML_ELEMENT(XSD, XML_RESTRICTION): + return new SchemaRestrictionContext( GetImport(), + mxRepository, msTypeName ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/SchemaSimpleTypeContext.hxx b/xmloff/source/xforms/SchemaSimpleTypeContext.hxx new file mode 100644 index 000000000..3489e2a6c --- /dev/null +++ b/xmloff/source/xforms/SchemaSimpleTypeContext.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/. + * + * 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 "TokenContext.hxx" +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XDataTypeRepository; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xsd:simpleType element */ +class SchemaSimpleTypeContext : public TokenContext +{ + css::uno::Reference mxRepository; + OUString msTypeName; + +public: + SchemaSimpleTypeContext( SvXMLImport& rImport, + const css::uno::Reference& rRepository ); + + // implement TokenContext methods: + +protected: + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/TokenContext.cxx b/xmloff/source/xforms/TokenContext.cxx new file mode 100644 index 000000000..928ea8788 --- /dev/null +++ b/xmloff/source/xforms/TokenContext.cxx @@ -0,0 +1,90 @@ +/* -*- 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 +#include + +#include "TokenContext.hxx" +#include +#include +#include +#include + +#include + +using com::sun::star::uno::Reference; + +TokenContext::TokenContext( SvXMLImport& rImport ) + : SvXMLImportContext( rImport ) +{ +} + +void TokenContext::startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // iterate over attributes + // - if in map: call HandleAttribute + // - xmlns:... : ignore + // - other: warning + + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + HandleAttribute( aIter ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > TokenContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // call handle child, and pass down arguments + SvXMLImportContext* pContext = HandleChild( nElement, xAttrList ); + // error handling: create default context and generate warning + if( pContext == nullptr ) + { + GetImport().SetError( XMLERROR_UNKNOWN_ELEMENT, SvXMLImport::getNameFromToken( nElement ) ); + } + return pContext; +} + + css::uno::Reference< css::xml::sax::XFastContextHandler > TokenContext::createUnknownChildContext( + const OUString& Namespace, const OUString& Name, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + GetImport().SetError( XMLERROR_UNKNOWN_ELEMENT, Namespace + " " + Name ); + return nullptr; +} + +static bool lcl_IsWhiteSpace( sal_Unicode c ) +{ + return c == ' ' + || c == u'\x0009' + || c == u'\x000A' + || c == u'\x000D'; +} + +void TokenContext::characters( const OUString& rCharacters ) +{ + // get iterators for string data + const sal_Unicode* pBegin = rCharacters.getStr(); + const sal_Unicode* pEnd = &( pBegin[ rCharacters.getLength() ] ); + + // raise error if non-whitespace character is found + if( !::std::all_of( pBegin, pEnd, lcl_IsWhiteSpace ) ) + GetImport().SetError( XMLERROR_UNKNOWN_CHARACTERS, rCharacters ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/TokenContext.hxx b/xmloff/source/xforms/TokenContext.hxx new file mode 100644 index 000000000..84ed18ab5 --- /dev/null +++ b/xmloff/source/xforms/TokenContext.hxx @@ -0,0 +1,74 @@ +/* -*- 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 +#include + +namespace com::sun::star { + namespace xml::sax { class XFastAttributeList; } + namespace uno { template class Reference; } +} + +class SvXMLImport; + +/** handle attributes through an SvXMLTokenMap */ +class TokenContext : public SvXMLImportContext +{ +public: + TokenContext( SvXMLImport& rImport ); + + // implement SvXMLImportContext methods: + + /** call HandleAttribute for each attribute in the token map; + * create a warning for all others. Classes that wish to override + * StartElement need to call the parent method. */ + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + + /** call HandleChild for each child element in the token map; + * create a warning for all others. Classes that wish to override + * CreateChildContext may want to call the parent method for + * handling of defaults. */ + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( + const OUString& Namespace, const OUString& Name, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override; + + /** Create a warning for all non-namespace character + * content. Classes that wish to deal with character content have + * to override this method anyway, and will thus get rid of the + * warnings. */ + virtual void SAL_CALL characters( const OUString& rChars ) override; + +protected: + /** will be called for each attribute */ + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) = 0; + + /** will be called for each child element */ + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference& xAttrList ) = 0; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsBindContext.cxx b/xmloff/source/xforms/XFormsBindContext.cxx new file mode 100644 index 000000000..9c799d53f --- /dev/null +++ b/xmloff/source/xforms/XFormsBindContext.cxx @@ -0,0 +1,155 @@ +/* -*- 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 "XFormsBindContext.hxx" + +#include "xformsapi.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Any; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::container::XNameContainer; +using com::sun::star::xml::sax::XFastAttributeList; +using com::sun::star::xforms::XModel2; +using namespace xmloff::token; + +// helper function; see below +static void lcl_fillNamespaceContainer( const SvXMLNamespaceMap&, + Reference const & ); + +XFormsBindContext::XFormsBindContext( + SvXMLImport& rImport, + const Reference& xModel ) : + TokenContext( rImport ), + mxModel( xModel ) +{ + // attach binding to model + mxBinding = mxModel->createBinding(); + SAL_WARN_IF( !mxBinding.is(), "xmloff", "can't create binding" ); + mxModel->getBindings()->insert( Any( mxBinding ) ); +} + +void XFormsBindContext::HandleAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_NODESET: + xforms_setValue( mxBinding, "BindingExpression", aIter.toString() ); + break; + case XML_ID: + xforms_setValue( mxBinding, "BindingID", aIter.toString() ); + break; + case XML_READONLY: + xforms_setValue( mxBinding, "ReadonlyExpression", aIter.toString() ); + break; + case XML_RELEVANT: + xforms_setValue( mxBinding, "RelevantExpression", aIter.toString() ); + break; + case XML_REQUIRED: + xforms_setValue( mxBinding, "RequiredExpression", aIter.toString() ); + break; + case XML_CONSTRAINT: + xforms_setValue( mxBinding, "ConstraintExpression", aIter.toString() ); + break; + case XML_CALCULATE: + xforms_setValue( mxBinding, "CalculateExpression", aIter.toString() ); + break; + case XML_TYPE: + xforms_setValue( mxBinding, "Type", + xforms_getTypeName( mxModel->getDataTypeRepository(), + GetImport().GetNamespaceMap(), + aIter.toString() ) ); + break; + default: + assert( false && "should not happen" ); + break; + } +} + +void XFormsBindContext::startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + // we need to register the namespaces + Reference xContainer( + mxBinding->getPropertyValue( "BindingNamespaces" ), + UNO_QUERY ); + + SAL_WARN_IF( !xContainer.is(), "xmloff", "binding should have a namespace container" ); + if( xContainer.is() ) + lcl_fillNamespaceContainer( GetImport().GetNamespaceMap(), xContainer); + + // call super-class for attribute handling + TokenContext::startFastElement( nElement, xAttrList ); +} + +/** will be called for each child element */ +SvXMLImportContext* XFormsBindContext::HandleChild( + sal_Int32, + const Reference& ) +{ + assert( false && "no children supported" ); + return nullptr; +} + + +static void lcl_fillNamespaceContainer( + const SvXMLNamespaceMap& aMap, + Reference const & xContainer ) +{ + sal_uInt16 nKeyIter = aMap.GetFirstKey(); + do + { + // get prefix and namespace + const OUString& sPrefix = aMap.GetPrefixByKey( nKeyIter ); + const OUString& sNamespace = aMap.GetNameByKey( nKeyIter ); + + // as a hack, we will ignore our own 'default' namespaces + SAL_WARN_IF( sPrefix.isEmpty(), "xmloff", "no prefix?" ); + if( !sPrefix.startsWith("_") && + nKeyIter >= XML_NAMESPACE_META_SO52) + { + // insert prefix (use replace if already known) + if( xContainer->hasByName( sPrefix ) ) + xContainer->replaceByName( sPrefix, Any( sNamespace ) ); + else + xContainer->insertByName( sPrefix, Any( sNamespace ) ); + } + + // proceed to next + nKeyIter = aMap.GetNextKey( nKeyIter ); + } + while( nKeyIter != XML_NAMESPACE_UNKNOWN ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsBindContext.hxx b/xmloff/source/xforms/XFormsBindContext.hxx new file mode 100644 index 000000000..5aa784674 --- /dev/null +++ b/xmloff/source/xforms/XFormsBindContext.hxx @@ -0,0 +1,59 @@ +/* -*- 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 "TokenContext.hxx" +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XModel2; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xforms:binding element */ +class XFormsBindContext : public TokenContext +{ + const css::uno::Reference mxModel; + css::uno::Reference mxBinding; + +public: + XFormsBindContext( SvXMLImport& rImport, + const css::uno::Reference& xModel ); + + // implement SvXMLImportContext & TokenContext methods: + + virtual void SAL_CALL startFastElement( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override; + +protected: + virtual void HandleAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference& xAttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsInstanceContext.cxx b/xmloff/source/xforms/XFormsInstanceContext.cxx new file mode 100644 index 000000000..37d56a94a --- /dev/null +++ b/xmloff/source/xforms/XFormsInstanceContext.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/. + * + * 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 "XFormsInstanceContext.hxx" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Any; +using com::sun::star::uno::Sequence; +using com::sun::star::xforms::XModel2; +using com::sun::star::beans::PropertyValue; +using com::sun::star::xml::sax::XAttributeList; + +using xmloff::token::XML_SRC; +using xmloff::token::XML_ID; + +XFormsInstanceContext::XFormsInstanceContext( + SvXMLImport& rImport, + const Reference & xModel ) : + TokenContext( rImport ), + mxModel( xModel ) +{ + SAL_WARN_IF( !mxModel.is(), "xmloff", "need model" ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XFormsInstanceContext::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + SvXMLImportContext* pContext = nullptr; + + // only the first element child of an xforms:instance element + // is used as an instance. The other children remainder must be + // ignored. + if( mxInstance.is() ) + { + const OUString& rLocalName = SvXMLImport::getNameFromToken( nElement ); + GetImport().SetError( XMLERROR_XFORMS_ONLY_ONE_INSTANCE_ELEMENT, rLocalName ); + } + else + { + // create new DomBuilderContext. Save reference to tree in Model. + DomBuilderContext* pInstance = new DomBuilderContext( GetImport(), nElement ); + mxInstance = pInstance->getTree(); + pContext = pInstance; + } + + SAL_WARN_IF( pContext == nullptr, "xmloff", "no context!" ); + return pContext; + +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > XFormsInstanceContext::createUnknownChildContext( + const OUString & rNamespace, const OUString &rName, const css::uno::Reference< css::xml::sax::XFastAttributeList > & /*Attribs*/) +{ + SvXMLImportContext* pContext = nullptr; + + // only the first element child of an xforms:instance element + // is used as an instance. The other children remainder must be + // ignored. + if( mxInstance.is() ) + { + GetImport().SetError( XMLERROR_XFORMS_ONLY_ONE_INSTANCE_ELEMENT, rName ); + } + else + { + // create new DomBuilderContext. Save reference to tree in Model. + DomBuilderContext* pInstance = new DomBuilderContext( GetImport(), rNamespace, rName ); + mxInstance = pInstance->getTree(); + pContext = pInstance; + } + + SAL_WARN_IF( pContext == nullptr, "xmloff", "no context!" ); + return pContext; + +} + +void XFormsInstanceContext::endFastElement(sal_Int32 ) +{ + Sequence aSequence( 3 ); + PropertyValue* pSequence = aSequence.getArray(); + pSequence[0].Name = "Instance"; + pSequence[0].Value <<= mxInstance; + pSequence[1].Name = "ID"; + pSequence[1].Value <<= msId; + pSequence[2].Name = "URL"; + pSequence[2].Value <<= msURL; + + mxModel->getInstances()->insert( Any( aSequence ) ); +} + +void XFormsInstanceContext::endUnknownElement(const OUString & /*Namespace*/, const OUString & /*Name*/) +{ + Sequence aSequence( 3 ); + PropertyValue* pSequence = aSequence.getArray(); + pSequence[0].Name = "Instance"; + pSequence[0].Value <<= mxInstance; + pSequence[1].Name = "ID"; + pSequence[1].Value <<= msId; + pSequence[2].Name = "URL"; + pSequence[2].Value <<= msURL; + + mxModel->getInstances()->insert( Any( aSequence ) ); +} + +void XFormsInstanceContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_SRC: + msURL = aIter.toString(); + break; + case XML_ID: + msId = aIter.toString(); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + assert( false && "this should not happen" ); + break; + } +} + +SvXMLImportContext* XFormsInstanceContext::HandleChild( + sal_Int32, + const Reference& ) +{ + assert( false && "to be handled by CreateChildContext" ); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsInstanceContext.hxx b/xmloff/source/xforms/XFormsInstanceContext.hxx new file mode 100644 index 000000000..7583c2da3 --- /dev/null +++ b/xmloff/source/xforms/XFormsInstanceContext.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 "TokenContext.hxx" +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace xml::dom { class XDocument; } + namespace beans { class XPropertySet; } + namespace xforms { class XModel2; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xforms:instance element */ +class XFormsInstanceContext : public TokenContext +{ + css::uno::Reference mxModel; + css::uno::Reference mxInstance; + OUString msId; + OUString msURL; + +public: + XFormsInstanceContext( SvXMLImport& rImport, + const css::uno::Reference & xModel ); + + // implement SvXMLImportContext & TokenContext methods: + // We override CreateChildContext, because we want to read + // arbitrary DOM elements. For the attributes, we use the + // TokenContext mechanism. + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createUnknownChildContext( + const OUString& Namespace, const OUString& Name, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override; + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + virtual void SAL_CALL endUnknownElement(const OUString & Namespace, const OUString & Name) override; + +protected: + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsModelContext.cxx b/xmloff/source/xforms/XFormsModelContext.cxx new file mode 100644 index 000000000..479909fb5 --- /dev/null +++ b/xmloff/source/xforms/XFormsModelContext.cxx @@ -0,0 +1,110 @@ +/* -*- 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 "XFormsModelContext.hxx" + +#include "XFormsBindContext.hxx" +#include "XFormsSubmissionContext.hxx" +#include "XFormsInstanceContext.hxx" +#include "SchemaContext.hxx" +#include "xformsapi.hxx" + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +using com::sun::star::util::XUpdatable; +using namespace com::sun::star::uno; +using namespace xmloff::token; + + +XFormsModelContext::XFormsModelContext( SvXMLImport& rImport ) : + TokenContext( rImport ), + mxModel( xforms_createXFormsModel() ) +{ +} + +void XFormsModelContext::HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() & TOKEN_MASK) + { + case XML_ID: + mxModel->setPropertyValue( "ID", Any( aIter.toString() ) ); + break; + case XML_SCHEMA: + GetImport().SetError( XMLERROR_XFORMS_NO_SCHEMA_SUPPORT ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + assert( false && "this should not happen" ); + break; + } +} + +SvXMLImportContext* XFormsModelContext::HandleChild( + sal_Int32 nElementToken, + const Reference& ) +{ + SvXMLImportContext* pContext = nullptr; + + switch( nElementToken ) + { + case XML_ELEMENT(XFORMS, XML_INSTANCE): + pContext = new XFormsInstanceContext( GetImport(), mxModel ); + break; + case XML_ELEMENT(XFORMS, XML_BIND): + pContext = new XFormsBindContext( GetImport(), mxModel ); + break; + case XML_ELEMENT(XFORMS, XML_SUBMISSION): + pContext = new XFormsSubmissionContext( GetImport(), mxModel ); + break; + case XML_ELEMENT(XSD, XML_SCHEMA): + pContext = new SchemaContext( GetImport(), mxModel->getDataTypeRepository() ); + break; + default: + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElementToken); + assert( false && "Boooo!" ); + break; + } + + return pContext; +} + +void XFormsModelContext::endFastElement(sal_Int32 ) +{ + // update before putting model into document + Reference xUpdate( mxModel, UNO_QUERY ); + if( xUpdate.is() ) + xUpdate->update(); + + GetImport().initXForms(); + xforms_addXFormsModel( GetImport().GetModel(), mxModel ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsModelContext.hxx b/xmloff/source/xforms/XFormsModelContext.hxx new file mode 100644 index 000000000..0579850df --- /dev/null +++ b/xmloff/source/xforms/XFormsModelContext.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/. + * + * 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 "TokenContext.hxx" +#include +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xforms:model element */ +class XFormsModelContext : public TokenContext +{ + css::uno::Reference mxModel; + +public: + XFormsModelContext( SvXMLImport& rImport ); + + // implement SvXMLImportContext & TokenContext methods: + + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + +protected: + virtual void HandleAttribute(const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference& xAttrList ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsModelExport.hxx b/xmloff/source/xforms/XFormsModelExport.hxx new file mode 100644 index 000000000..03d83e97c --- /dev/null +++ b/xmloff/source/xforms/XFormsModelExport.hxx @@ -0,0 +1,33 @@ +/* -*- 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 + +class SvXMLExport; +namespace com::sun::star { + namespace uno { template class Reference; } + namespace beans { class XPropertySet; } +} + +void exportXFormsModel( SvXMLExport&, + const css::uno::Reference& ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsSubmissionContext.cxx b/xmloff/source/xforms/XFormsSubmissionContext.cxx new file mode 100644 index 000000000..2e57d5f43 --- /dev/null +++ b/xmloff/source/xforms/XFormsSubmissionContext.cxx @@ -0,0 +1,137 @@ +/* -*- 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 "XFormsSubmissionContext.hxx" + +#include "xformsapi.hxx" + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +using com::sun::star::xml::sax::XAttributeList; +using com::sun::star::xforms::XModel2; + +using namespace com::sun::star::uno; +using namespace xmloff::token; + + +XFormsSubmissionContext::XFormsSubmissionContext( + SvXMLImport& rImport, + const Reference& xModel ) : + TokenContext( rImport ) +{ + // register submission with model + SAL_WARN_IF( !xModel.is(), "xmloff", "need model" ); + mxSubmission = xModel->createSubmission().get(); + SAL_WARN_IF( !mxSubmission.is(), "xmloff", "can't create submission" ); + xModel->getSubmissions()->insert( Any( mxSubmission ) ); +} + +namespace { + +Any toBool( std::string_view rValue ) +{ + Any aValue; + bool bValue(false); + if (::sax::Converter::convertBool( bValue, rValue )) + { + aValue <<= bValue; + } + return aValue; +} + +} // namespace + +void XFormsSubmissionContext::HandleAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_ID: + xforms_setValue( mxSubmission, "ID", aIter.toString() ); + break; + case XML_BIND: + xforms_setValue( mxSubmission, "Bind", aIter.toString() ); + break; + case XML_REF: + xforms_setValue( mxSubmission, "Ref", aIter.toString() ); + break; + case XML_ACTION: + xforms_setValue( mxSubmission, "Action", aIter.toString() ); + break; + case XML_METHOD: + xforms_setValue( mxSubmission, "Method", aIter.toString() ); + break; + case XML_VERSION: + xforms_setValue( mxSubmission, "Version", aIter.toString() ); + break; + case XML_INDENT: + xforms_setValue( mxSubmission, "Indent", toBool( aIter.toView() ) ); + break; + case XML_MEDIATYPE: + xforms_setValue( mxSubmission, "MediaType", aIter.toString() ); + break; + case XML_ENCODING: + xforms_setValue( mxSubmission, "Encoding", aIter.toString() ); + break; + case XML_OMIT_XML_DECLARATION: + xforms_setValue( mxSubmission, "OmitXmlDeclaration", + toBool( aIter.toView() ) ); + break; + case XML_STANDALONE: + xforms_setValue( mxSubmission, "Standalone", toBool( aIter.toView() ) ); + break; + case XML_CDATA_SECTION_ELEMENTS: + xforms_setValue( mxSubmission, "CDataSectionElement", aIter.toString() ); + break; + case XML_REPLACE: + xforms_setValue( mxSubmission, "Replace", aIter.toString() ); + break; + case XML_SEPARATOR: + xforms_setValue( mxSubmission, "Separator", aIter.toString() ); + break; + case XML_INCLUDENAMESPACEPREFIXES: + xforms_setValue( mxSubmission, "IncludeNamespacePrefixes", aIter.toString() ); + break; + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + assert( false && "unknown attribute" ); + break; + } +} + +/** will be called for each child element */ +SvXMLImportContext* XFormsSubmissionContext::HandleChild( + sal_Int32, + const Reference& ) +{ + assert( false && "no children supported" ); + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/XFormsSubmissionContext.hxx b/xmloff/source/xforms/XFormsSubmissionContext.hxx new file mode 100644 index 000000000..b000db0eb --- /dev/null +++ b/xmloff/source/xforms/XFormsSubmissionContext.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/. + * + * 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 "TokenContext.hxx" +#include + +namespace com::sun::star { + namespace xml::sax { class XAttributeList; } + namespace beans { class XPropertySet; } + namespace xforms { class XModel2; } +} + +class SvXMLImport; +class SvXMLImportContext; + +/** import the xforms:submission element */ +class XFormsSubmissionContext : public TokenContext +{ + css::uno::Reference mxSubmission; + +public: + XFormsSubmissionContext( SvXMLImport& rImport, + const css::uno::Reference& xModel ); + + // implement TokenContext methods: + +protected: + virtual void HandleAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) override; + + virtual SvXMLImportContext* HandleChild( + sal_Int32 nElementToken, + const css::uno::Reference& xAttrList ) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/xformsapi.cxx b/xmloff/source/xforms/xformsapi.cxx new file mode 100644 index 000000000..d8345275c --- /dev/null +++ b/xmloff/source/xforms/xformsapi.cxx @@ -0,0 +1,296 @@ +/* -*- 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 "xformsapi.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +using com::sun::star::uno::Reference; +using com::sun::star::uno::Sequence; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::beans::XPropertySet; +using com::sun::star::container::XNameAccess; +using com::sun::star::xforms::XFormsSupplier; +using com::sun::star::xforms::XDataTypeRepository; +using com::sun::star::xforms::Model; +using com::sun::star::xforms::XModel2; +using com::sun::star::container::XNameContainer; +using com::sun::star::uno::Any; +using com::sun::star::uno::Exception; + +using namespace com::sun::star; +using namespace xmloff::token; + +Reference xforms_createXFormsModel() +{ + Reference xModel = Model::create( comphelper::getProcessComponentContext() ); + + return xModel; +} + +void xforms_addXFormsModel( + const Reference& xDocument, + const Reference& xModel ) +{ + bool bSuccess = false; + try + { + Reference xSupplier( xDocument, UNO_QUERY ); + if( xSupplier.is() ) + { + Reference xForms = xSupplier->getXForms(); + if( xForms.is() ) + { + OUString sName; + xModel->getPropertyValue("ID") >>= sName; + xForms->insertByName( sName, Any( xModel ) ); + bSuccess = true; + } + } + } + catch( const Exception& ) + { + ; // no success! + } + + // TODO: implement proper error handling + SAL_WARN_IF( !bSuccess, "xmloff", "can't import model" ); +} + +static Reference lcl_findXFormsBindingOrSubmission( + Reference const & xDocument, + const OUString& rBindingID, + bool bBinding ) +{ + // find binding by iterating over all models, and look for the + // given binding ID + + Reference xRet; + try + { + // get supplier + Reference xSupplier( xDocument, UNO_QUERY ); + if( xSupplier.is() ) + { + // get XForms models + Reference xForms = xSupplier->getXForms(); + if( xForms.is() ) + { + // iterate over all models + const Sequence aNames = xForms->getElementNames(); + for( const auto& rName : aNames ) + { + Reference xModel( + xForms->getByName( rName ), UNO_QUERY ); + if( xModel.is() ) + { + // ask model for bindings + Reference xBindings( + bBinding + ? xModel->getBindings() + : xModel->getSubmissions(), + UNO_QUERY_THROW ); + + // finally, ask binding for name + if( xBindings->hasByName( rBindingID ) ) + xRet.set( xBindings->getByName( rBindingID ), + UNO_QUERY ); + } + + if (xRet.is()) + break; + } + } + } + } + catch( const Exception& ) + { + ; // no success! + } + + // TODO: if (!xRet.is()) rImport.SetError(...); + + return xRet; +} + +Reference xforms_findXFormsBinding( + Reference const & xDocument, + const OUString& rBindingID ) +{ + return lcl_findXFormsBindingOrSubmission( xDocument, rBindingID, true ); +} + +Reference xforms_findXFormsSubmission( + Reference const & xDocument, + const OUString& rBindingID ) +{ + return lcl_findXFormsBindingOrSubmission( xDocument, rBindingID, false ); +} + +void xforms_setValueAny( Reference const & xPropertySet, + const OUString& rName, + const Any& rAny ) +{ + xPropertySet->setPropertyValue( rName, rAny ); +} + +#define TOKEN_MAP_ENTRY(NAMESPACE,TOKEN) { XML_NAMESPACE_##NAMESPACE, xmloff::token::XML_##TOKEN, xmloff::token::XML_##TOKEN } +const SvXMLTokenMapEntry aTypes[] = +{ + TOKEN_MAP_ENTRY( XSD, STRING ), + TOKEN_MAP_ENTRY( XSD, DECIMAL ), + TOKEN_MAP_ENTRY( XSD, DOUBLE ), + TOKEN_MAP_ENTRY( XSD, FLOAT ), + TOKEN_MAP_ENTRY( XSD, BOOLEAN ), + TOKEN_MAP_ENTRY( XSD, ANYURI ), + TOKEN_MAP_ENTRY( XSD, DATETIME_XSD ), + TOKEN_MAP_ENTRY( XSD, DATE ), + TOKEN_MAP_ENTRY( XSD, TIME ), + TOKEN_MAP_ENTRY( XSD, YEAR ), + TOKEN_MAP_ENTRY( XSD, MONTH ), + TOKEN_MAP_ENTRY( XSD, DAY ), + XML_TOKEN_MAP_END +}; + +sal_uInt16 xforms_getTypeClass( + const Reference& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ) +{ + // translate name into token for local name + OUString sLocalName; + sal_uInt16 nPrefix = rNamespaceMap.GetKeyByAttrValueQName(rXMLName, &sLocalName); + static const SvXMLTokenMap aMap( aTypes ); + sal_uInt16 nToken = aMap.Get( nPrefix, sLocalName ); + + sal_uInt16 nTypeClass = css::xsd::DataTypeClass::STRING; + if( nToken != XML_TOK_UNKNOWN ) + { + // we found an XSD name: then get the proper API name for it + SAL_WARN_IF( !xRepository.is(), "xmloff", "can't find type without repository"); + switch( nToken ) + { + case XML_STRING: + nTypeClass = css::xsd::DataTypeClass::STRING; + break; + case XML_ANYURI: + nTypeClass = css::xsd::DataTypeClass::anyURI; + break; + case XML_DECIMAL: + nTypeClass = css::xsd::DataTypeClass::DECIMAL; + break; + case XML_DOUBLE: + nTypeClass = css::xsd::DataTypeClass::DOUBLE; + break; + case XML_FLOAT: + nTypeClass = css::xsd::DataTypeClass::FLOAT; + break; + case XML_BOOLEAN: + nTypeClass = css::xsd::DataTypeClass::BOOLEAN; + break; + case XML_DATETIME_XSD: + nTypeClass = css::xsd::DataTypeClass::DATETIME; + break; + case XML_DATE: + nTypeClass = css::xsd::DataTypeClass::DATE; + break; + case XML_TIME: + nTypeClass = css::xsd::DataTypeClass::TIME; + break; + case XML_YEAR: + nTypeClass = css::xsd::DataTypeClass::gYear; + break; + case XML_DAY: + nTypeClass = css::xsd::DataTypeClass::gDay; + break; + case XML_MONTH: + nTypeClass = css::xsd::DataTypeClass::gMonth; + break; + + /* data types not yet supported: + nTypeClass = css::xsd::DataTypeClass::DURATION; + nTypeClass = css::xsd::DataTypeClass::gYearMonth; + nTypeClass = css::xsd::DataTypeClass::gMonthDay; + nTypeClass = css::xsd::DataTypeClass::hexBinary; + nTypeClass = css::xsd::DataTypeClass::base64Binary; + nTypeClass = css::xsd::DataTypeClass::QName; + nTypeClass = css::xsd::DataTypeClass::NOTATION; + */ + } + } + + return nTypeClass; +} + + +OUString xforms_getTypeName( + const Reference& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ) +{ + OUString sLocalName; + sal_uInt16 nPrefix = rNamespaceMap.GetKeyByAttrValueQName(rXMLName, &sLocalName); + static const SvXMLTokenMap aMap( aTypes ); + sal_uInt16 nToken = aMap.Get( nPrefix, sLocalName ); + return ( nToken == XML_TOK_UNKNOWN ) + ? rXMLName + : xforms_getBasicTypeName( xRepository, rNamespaceMap, rXMLName ); +} + +OUString xforms_getBasicTypeName( + const Reference& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ) +{ + OUString sTypeName = rXMLName; + try + { + sTypeName = + xRepository->getBasicDataType( + xforms_getTypeClass( xRepository, rNamespaceMap, rXMLName ) ) + ->getName(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("xmloff", "exception during type creation"); + } + return sTypeName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/xformsapi.hxx b/xmloff/source/xforms/xformsapi.hxx new file mode 100644 index 000000000..ba66e985b --- /dev/null +++ b/xmloff/source/xforms/xformsapi.hxx @@ -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/. + * + * 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 + + +// this is a collection of several functions to make dealing with the XForms +// API a little easier + + +#include + +namespace com::sun::star { + namespace beans { class XPropertySet; } + namespace frame { class XModel; } + namespace uno { template class Reference; } + namespace xforms { class XDataTypeRepository; class XModel2; } +} +class SvXMLNamespaceMap; + +css::uno::Reference xforms_createXFormsModel(); + +void xforms_addXFormsModel( + const css::uno::Reference& xDocument, + const css::uno::Reference& xModel ); + +css::uno::Reference xforms_findXFormsBinding( css::uno::Reference const &, const OUString& ); + +css::uno::Reference xforms_findXFormsSubmission( css::uno::Reference const &, const OUString& ); + +void xforms_setValueAny( + css::uno::Reference const & xPropSet, + const OUString& rName, + const css::uno::Any& rAny ); + +template +inline void xforms_setValue( + const css::uno::Reference& xPropSet, + const OUString& rName, + const T& aValue ) +{ + xforms_setValueAny( xPropSet, rName, css::uno::Any( aValue ) ); +} +template<> +inline void xforms_setValue( + const css::uno::Reference& xPropSet, + const OUString& rName, + const css::uno::Any& aValue ) +{ + xforms_setValueAny( xPropSet, rName, aValue ); +} + +sal_uInt16 xforms_getTypeClass( + const css::uno::Reference& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ); + +OUString xforms_getTypeName( + const css::uno::Reference& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ); + +OUString xforms_getBasicTypeName( + const css::uno::Reference& xRepository, + const SvXMLNamespaceMap& rNamespaceMap, + const OUString& rXMLName ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/xformsexport.cxx b/xmloff/source/xforms/xformsexport.cxx new file mode 100644 index 000000000..363a8f674 --- /dev/null +++ b/xmloff/source/xforms/xformsexport.cxx @@ -0,0 +1,802 @@ +/* -*- 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 + +#include "XFormsModelExport.hxx" + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace xmloff::token; + +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::XPropertySetInfo; +using com::sun::star::container::XIndexAccess; +using com::sun::star::container::XNameAccess; +using com::sun::star::container::XNameContainer; +using com::sun::star::container::XEnumerationAccess; +using com::sun::star::container::XEnumeration; +using com::sun::star::xml::dom::XDocument; +using com::sun::star::form::binding::XBindableValue; +using com::sun::star::form::binding::XListEntrySink; +using com::sun::star::form::submission::XSubmissionSupplier; +using com::sun::star::beans::PropertyValue; +using com::sun::star::xforms::XDataTypeRepository; +using com::sun::star::xforms::XFormsSupplier; +using com::sun::star::util::Duration; + +void exportXForms( SvXMLExport& rExport ) +{ + Reference xSupplier( rExport.GetModel(), UNO_QUERY ); + if( !xSupplier.is() ) + return; + + Reference xForms = xSupplier->getXForms(); + if( xForms.is() ) + { + const Sequence aNames = xForms->getElementNames(); + + for( const auto& rName : aNames ) + { + Reference xModel( xForms->getByName( rName ), + UNO_QUERY ); + exportXFormsModel( rExport, xModel ); + } + } +} + + +static void exportXFormsInstance( SvXMLExport&, const Sequence& ); +static void exportXFormsBinding( SvXMLExport&, const Reference& ); +static void exportXFormsSubmission( SvXMLExport&, const Reference& ); +static void exportXFormsSchemas( SvXMLExport&, const Reference& ); + + +typedef OUString (*convert_t)( const Any& ); + +namespace { + +struct ExportTable +{ + const char* pPropertyName; + sal_uInt16 const nNamespace; + sal_uInt16 nToken; + convert_t const aConverter; +}; + +} + +static void lcl_export( const Reference& rPropertySet, + SvXMLExport& rExport, + const ExportTable* pTable ); + +#define TABLE_ENTRY(NAME,NAMESPACE,TOKEN,CONVERTER) { NAME,XML_NAMESPACE_##NAMESPACE,xmloff::token::XML_##TOKEN, CONVERTER } +#define TABLE_END { nullptr, 0, 0, nullptr } + +// any conversion functions +static OUString xforms_string( const Any& ); +static OUString xforms_bool( const Any& ); +static OUString xforms_whitespace( const Any& ); +template static OUString xforms_convert( const Any& ); +template static OUString xforms_convertRef( const Any& ); + +static void xforms_formatDate( OUStringBuffer& aBuffer, const util::Date& aDate ); +static void xforms_formatTime( OUStringBuffer& aBuffer, const css::util::Time& aTime ); +static void xforms_formatDateTime( OUStringBuffer& aBuffer, const util::DateTime& aDateTime ); + +static void convertNumber(OUStringBuffer & b, sal_Int32 n) { + b.append(n); +} + +convert_t const xforms_int32 = &xforms_convert; +convert_t const xforms_double = &xforms_convert; +convert_t const xforms_dateTime = &xforms_convertRef; +convert_t const xforms_date = &xforms_convertRef; +convert_t const xforms_time = &xforms_convertRef; + +// other functions +static OUString lcl_getXSDType( SvXMLExport const & rExport, + const Reference& xType ); + + +// the model + + +const ExportTable aXFormsModelTable[] = +{ + TABLE_ENTRY( "ID", NONE, ID, xforms_string ), + TABLE_ENTRY( "SchemaRef", NONE, SCHEMA, xforms_string ), + TABLE_END +}; + +void exportXFormsModel( SvXMLExport& rExport, + const Reference& xModelPropSet ) +{ + // no model -> don't do anything! + Reference xModel( xModelPropSet, UNO_QUERY ); + if( ! xModel.is() || ! xModelPropSet.is() ) + return; + + lcl_export( xModelPropSet, rExport, aXFormsModelTable ); + SvXMLElementExport aModelElement( rExport, XML_NAMESPACE_XFORMS, XML_MODEL, + true, true ); + + // instances + Reference xInstances( xModel->getInstances(), + UNO_QUERY_THROW); + sal_Int32 nCount = xInstances->getCount(); + sal_Int32 i = 0; + for( i = 0; i < nCount; i++ ) + { + Sequence aInstance; + xInstances->getByIndex( i ) >>= aInstance; + exportXFormsInstance( rExport, aInstance ); + } + + + // bindings + Reference xBindings( xModel->getBindings(), UNO_QUERY_THROW); + nCount = xBindings->getCount(); + for( i = 0; i < nCount; i++ ) + { + Reference aBinding( xBindings->getByIndex( i ), + UNO_QUERY_THROW ); + exportXFormsBinding( rExport, aBinding ); + } + + // submissions + Reference xSubmissions( xModel->getSubmissions(), + UNO_QUERY_THROW ); + nCount = xSubmissions->getCount(); + for( i = 0; i < nCount; i++ ) + { + Reference xSubmission( xSubmissions->getByIndex( i ), + UNO_QUERY_THROW ); + exportXFormsSubmission( rExport, xSubmission ); + } + + // schemas + exportXFormsSchemas( rExport, xModel ); +} + + +// the instance + + +void exportXFormsInstance( SvXMLExport& rExport, + const Sequence& xInstance ) +{ + OUString sId; + OUString sURL; + Reference xDoc; + + for( const auto& rProp : xInstance ) + { + OUString sName = rProp.Name; + const Any& rAny = rProp.Value; + if ( sName == "ID" ) + rAny >>= sId; + else if ( sName == "URL" ) + rAny >>= sURL; + else if ( sName == "Instance" ) + rAny >>= xDoc; + } + + if( !sId.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_ID, sId ); + + if( !sURL.isEmpty() ) + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_SRC, sURL ); + + SvXMLElementExport aElem( rExport, XML_NAMESPACE_XFORMS, XML_INSTANCE, + true, true ); + rExport.IgnorableWhitespace(); + if( xDoc.is() ) + { + exportDom( rExport, xDoc ); + } +} + + +// the binding + + +const ExportTable aXFormsBindingTable[] = +{ + TABLE_ENTRY( "BindingID", NONE, ID, xforms_string ), + TABLE_ENTRY( "BindingExpression", NONE, NODESET, xforms_string ), + TABLE_ENTRY( "ReadonlyExpression", NONE, READONLY, xforms_string ), + TABLE_ENTRY( "RelevantExpression", NONE, RELEVANT, xforms_string ), + TABLE_ENTRY( "RequiredExpression", NONE, REQUIRED, xforms_string ), + TABLE_ENTRY( "ConstraintExpression", NONE, CONSTRAINT, xforms_string ), + TABLE_ENTRY( "CalculateExpression", NONE, CALCULATE, xforms_string ), + // type handled separately, for type name <-> XSD type conversion + // TABLE_ENTRY( "Type", NONE, TYPE, xforms_string ), + TABLE_END +}; + +void exportXFormsBinding( SvXMLExport& rExport, + const Reference& xBinding ) +{ + // name check; generate binding ID if necessary + { + OUString sName; + xBinding->getPropertyValue( "BindingID" ) >>= sName; + if( sName.isEmpty() ) + { + // if we don't have a name yet, generate one on the fly + sal_Int64 nId = reinterpret_cast( xBinding.get() ); + sName = "bind_" + OUString::number( nId , 16 ); + xBinding->setPropertyValue( "BindingID", Any(sName)); + } + } + + lcl_export( xBinding, rExport, aXFormsBindingTable ); + + // handle type attribute + { + OUString sTypeName; + xBinding->getPropertyValue( "Type" ) >>= sTypeName; + + try + { + // now get type, and determine whether it's a standard type. If + // so, export the XSD name + Reference xModel( + xBinding->getPropertyValue( "Model" ), + UNO_QUERY ); + Reference xRepository( + xModel.is() ? xModel->getDataTypeRepository() : Reference() ); + if( xRepository.is() ) + { + Reference xDataType = + xRepository->getDataType( sTypeName ); + + // if it's a basic data type, write out the XSD name + // for the XSD type class + bool bIsBasic = false; + xDataType->getPropertyValue( "IsBasic" ) >>= bIsBasic; + if( bIsBasic ) + sTypeName = lcl_getXSDType( rExport, xDataType ); + } + } + catch( Exception& ) + { + ; // ignore; just use typename + } + + // now that we have the proper type name, write out the attribute + if( !sTypeName.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_TYPE, + sTypeName ); + } + } + + // we need to ensure all the namespaces in the binding will work correctly. + // to do so, we will write out all missing namespace declaractions. + const SvXMLNamespaceMap& rMap = rExport.GetNamespaceMap(); + Reference xNamespaces( + xBinding->getPropertyValue( "ModelNamespaces" ), UNO_QUERY); + if( xNamespaces.is() ) + { + // iterate over Prefixes for this binding + const Sequence aPrefixes = xNamespaces->getElementNames(); + for( const OUString& rPrefix : aPrefixes ) + { + OUString sURI; + xNamespaces->getByName( rPrefix ) >>= sURI; + + // check whether prefix/URI pair is in map; else write declaration + // (we don't need to change the map, since this element has no + // other content) + sal_uInt16 nKey = rMap.GetKeyByPrefix( rPrefix ); + if( nKey == XML_NAMESPACE_UNKNOWN || + rMap.GetNameByKey( nKey ) != sURI ) + { + // add declaration if it doesn't already exist + SvXMLAttributeList& rAttrList = rExport.GetAttrList(); + OUString sName = "xmlns:" + rPrefix; + sal_Int16 nFound = rAttrList.GetIndexByName(sName); + // duplicate xmlns:script, http://openoffice.org/2000/script seen + assert(nFound == -1 || rAttrList.getValueByIndex(nFound) == sURI); + if (nFound != -1) + continue; + rAttrList.AddAttribute(sName, sURI); + } + } + } + + SvXMLElementExport aElement( rExport, XML_NAMESPACE_XFORMS, XML_BIND, + true, true ); +} + + +// the submission + + +const ExportTable aXFormsSubmissionTable[] = +{ + TABLE_ENTRY( "ID", NONE, ID, xforms_string ), + TABLE_ENTRY( "Bind", NONE, BIND, xforms_string ), + TABLE_ENTRY( "Ref", NONE, REF, xforms_string ), + TABLE_ENTRY( "Action", NONE, ACTION, xforms_string ), + TABLE_ENTRY( "Method", NONE, METHOD, xforms_string ), + TABLE_ENTRY( "Version", NONE, VERSION, xforms_string ), + TABLE_ENTRY( "Indent", NONE, INDENT, xforms_bool ), + TABLE_ENTRY( "MediaType", NONE, MEDIATYPE, xforms_string ), + TABLE_ENTRY( "Encoding", NONE, ENCODING, xforms_string ), + TABLE_ENTRY( "OmitXmlDeclaration", NONE, OMIT_XML_DECLARATION, xforms_bool ), + TABLE_ENTRY( "Standalone", NONE, STANDALONE, xforms_bool ), + TABLE_ENTRY( "CDataSectionElement", NONE, CDATA_SECTION_ELEMENTS, xforms_string ), + TABLE_ENTRY( "Replace", NONE, REPLACE, xforms_string ), + TABLE_ENTRY( "Separator", NONE, SEPARATOR, xforms_string ), + TABLE_ENTRY( "IncludeNamespacePrefixes", NONE, INCLUDENAMESPACEPREFIXES, xforms_string ), + TABLE_END +}; + +void exportXFormsSubmission( SvXMLExport& rExport, + const Reference& xSubmission ) +{ + lcl_export( xSubmission, rExport, aXFormsSubmissionTable ); + SvXMLElementExport aElement( rExport, XML_NAMESPACE_XFORMS, XML_SUBMISSION, + true, true ); +} + + +// export data types as XSD schema + + +const ExportTable aDataTypeFacetTable[] = +{ + TABLE_ENTRY( "Length", XSD, LENGTH, xforms_int32 ), + TABLE_ENTRY( "MinLength", XSD, MINLENGTH, xforms_int32 ), + TABLE_ENTRY( "MaxLength", XSD, MAXLENGTH, xforms_int32 ), + TABLE_ENTRY( "MinInclusiveInt", XSD, MININCLUSIVE, xforms_int32 ), + TABLE_ENTRY( "MinExclusiveInt", XSD, MINEXCLUSIVE, xforms_int32 ), + TABLE_ENTRY( "MaxInclusiveInt", XSD, MAXINCLUSIVE, xforms_int32 ), + TABLE_ENTRY( "MaxExclusiveInt", XSD, MAXEXCLUSIVE, xforms_int32 ), + TABLE_ENTRY( "MinInclusiveDouble", XSD, MININCLUSIVE, xforms_double ), + TABLE_ENTRY( "MinExclusiveDouble", XSD, MINEXCLUSIVE, xforms_double ), + TABLE_ENTRY( "MaxInclusiveDouble", XSD, MAXINCLUSIVE, xforms_double ), + TABLE_ENTRY( "MaxExclusiveDouble", XSD, MAXEXCLUSIVE, xforms_double ), + TABLE_ENTRY( "MinInclusiveDate", XSD, MININCLUSIVE, xforms_date ), + TABLE_ENTRY( "MinExclusiveDate", XSD, MINEXCLUSIVE, xforms_date ), + TABLE_ENTRY( "MaxInclusiveDate", XSD, MAXINCLUSIVE, xforms_date ), + TABLE_ENTRY( "MaxExclusiveDate", XSD, MAXEXCLUSIVE, xforms_date ), + TABLE_ENTRY( "MinInclusiveTime", XSD, MININCLUSIVE, xforms_time ), + TABLE_ENTRY( "MinExclusiveTime", XSD, MINEXCLUSIVE, xforms_time ), + TABLE_ENTRY( "MaxInclusiveTime", XSD, MAXINCLUSIVE, xforms_time ), + TABLE_ENTRY( "MaxExclusiveTime", XSD, MAXEXCLUSIVE, xforms_time ), + TABLE_ENTRY( "MinInclusiveDateTime", XSD, MININCLUSIVE, xforms_dateTime ), + TABLE_ENTRY( "MinExclusiveDateTime", XSD, MINEXCLUSIVE, xforms_dateTime ), + TABLE_ENTRY( "MaxInclusiveDateTime", XSD, MAXINCLUSIVE, xforms_dateTime ), + TABLE_ENTRY( "MaxExclusiveDateTime", XSD, MAXEXCLUSIVE, xforms_dateTime ), + TABLE_ENTRY( "Pattern", XSD, PATTERN, xforms_string ), + // ??? XML_ENUMERATION, + TABLE_ENTRY( "WhiteSpace", XSD, WHITESPACE, xforms_whitespace ), + TABLE_ENTRY( "TotalDigits", XSD, TOTALDIGITS, xforms_int32 ), + TABLE_ENTRY( "FractionDigits", XSD, FRACTIONDIGITS, xforms_int32 ), + TABLE_END +}; + +// export facets through table; use the same table as lcl_export does +static void lcl_exportDataTypeFacets( SvXMLExport& rExport, + const Reference& rPropertySet, + const ExportTable* pTable ) +{ + Reference xInfo = rPropertySet->getPropertySetInfo(); + for( const ExportTable* pCurrent = pTable; + pCurrent->pPropertyName != nullptr; + pCurrent++ ) + { + OUString sName( OUString::createFromAscii( pCurrent->pPropertyName ) ); + if( xInfo->hasPropertyByName( sName ) ) + { + OUString sValue = (*pCurrent->aConverter)( + rPropertySet->getPropertyValue( sName ) ); + + if( !sValue.isEmpty() ) + { + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_VALUE, sValue ); + SvXMLElementExport aFacet( + rExport, + pCurrent->nNamespace, + static_cast( pCurrent->nToken ), + true, true ); + } + } + } +} + +static OUString lcl_getXSDType( SvXMLExport const & rExport, + const Reference& xType ) +{ + // we use string as default... + XMLTokenEnum eToken = XML_STRING; + + sal_uInt16 nDataTypeClass = 0; + xType->getPropertyValue( "TypeClass" ) >>= nDataTypeClass; + switch( nDataTypeClass ) + { + case css::xsd::DataTypeClass::STRING: + eToken = XML_STRING; + break; + case css::xsd::DataTypeClass::anyURI: + eToken = XML_ANYURI; + break; + case css::xsd::DataTypeClass::DECIMAL: + eToken = XML_DECIMAL; + break; + case css::xsd::DataTypeClass::DOUBLE: + eToken = XML_DOUBLE; + break; + case css::xsd::DataTypeClass::FLOAT: + eToken = XML_FLOAT; + break; + case css::xsd::DataTypeClass::BOOLEAN: + eToken = XML_BOOLEAN; + break; + case css::xsd::DataTypeClass::DATETIME: + eToken = XML_DATETIME_XSD; + break; + case css::xsd::DataTypeClass::TIME: + eToken = XML_TIME; + break; + case css::xsd::DataTypeClass::DATE: + eToken = XML_DATE; + break; + case css::xsd::DataTypeClass::gYear: + eToken = XML_YEAR; + break; + case css::xsd::DataTypeClass::gDay: + eToken = XML_DAY; + break; + case css::xsd::DataTypeClass::gMonth: + eToken = XML_MONTH; + break; + case css::xsd::DataTypeClass::DURATION: + case css::xsd::DataTypeClass::gYearMonth: + case css::xsd::DataTypeClass::gMonthDay: + case css::xsd::DataTypeClass::hexBinary: + case css::xsd::DataTypeClass::base64Binary: + case css::xsd::DataTypeClass::QName: + case css::xsd::DataTypeClass::NOTATION: + default: + OSL_FAIL( "unknown data type" ); + } + + return rExport.GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_XSD, + GetXMLToken( eToken ) ); +} + +static void lcl_exportDataType( SvXMLExport& rExport, + const Reference& xType ) +{ + // we do not need to export basic types; exit if we have one + bool bIsBasic = false; + xType->getPropertyValue( "IsBasic" ) >>= bIsBasic; + if( bIsBasic ) + return; + + // no basic type -> export + + // + OUString sName; + xType->getPropertyValue( "Name" ) >>= sName; + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_NAME, sName ); + SvXMLElementExport aSimpleType( rExport, + XML_NAMESPACE_XSD, XML_SIMPLETYPE, + true, true ); + + // + rExport.AddAttribute( XML_NAMESPACE_NONE, XML_BASE, + lcl_getXSDType( rExport, xType ) ); + SvXMLElementExport aRestriction( rExport, + XML_NAMESPACE_XSD, + XML_RESTRICTION, + true, true ); + + // export facets + lcl_exportDataTypeFacets( rExport, + xType, + aDataTypeFacetTable ); +} + +void exportXFormsSchemas( SvXMLExport& rExport, + const Reference& xModel ) +{ + // TODO: for now, we'll fake this... + { + SvXMLElementExport aSchemaElem( rExport, XML_NAMESPACE_XSD, XML_SCHEMA, + true, true ); + + // now get data type repository, and export + Reference xTypes = xModel->getDataTypeRepository(); + if( xTypes.is() ) + { + Reference xEnum = xTypes->createEnumeration(); + SAL_WARN_IF( !xEnum.is(), "xmloff", "no enum?" ); + while( xEnum->hasMoreElements() ) + { + Reference xType( xEnum->nextElement(), UNO_QUERY ); + lcl_exportDataType( rExport, xType ); + } + } + } + + // export other, 'foreign' schemas + Reference xPropSet( xModel, UNO_QUERY ); + if( xPropSet.is() ) + { + Reference xDocument( + xPropSet->getPropertyValue( "ForeignSchema" ), + UNO_QUERY ); + + if( xDocument.is() ) + exportDom( rExport, xDocument ); + } +} + + +// helper functions + + +static void lcl_export( const Reference& rPropertySet, + SvXMLExport& rExport, + const ExportTable* pTable ) +{ + for( const ExportTable* pCurrent = pTable; + pCurrent->pPropertyName != nullptr; + pCurrent++ ) + { + Any aAny = rPropertySet->getPropertyValue( + OUString::createFromAscii( pCurrent->pPropertyName ) ); + OUString sValue = (*pCurrent->aConverter)( aAny ); + + if( !sValue.isEmpty() ) + rExport.AddAttribute( + pCurrent->nNamespace, + static_cast( pCurrent->nToken ), + sValue ); + } +} + + +// any conversion functions + + +template +OUString xforms_convert( const Any& rAny ) +{ + OUStringBuffer aBuffer; + T aData = T(); + if( rAny >>= aData ) + { + FUNC( aBuffer, aData ); + } + return aBuffer.makeStringAndClear(); +} + +template +OUString xforms_convertRef( const Any& rAny ) +{ + OUStringBuffer aBuffer; + T aData; + if( rAny >>= aData ) + { + FUNC( aBuffer, aData ); + } + return aBuffer.makeStringAndClear(); +} + +OUString xforms_string( const Any& rAny ) +{ + OUString aResult; + rAny >>= aResult; + return aResult; +} + +OUString xforms_bool( const Any& rAny ) +{ + bool bResult = bool(); + if( rAny >>= bResult ) + return GetXMLToken( bResult ? XML_TRUE : XML_FALSE ); + OSL_FAIL( "expected boolean value" ); + return OUString(); +} + +void xforms_formatDate( OUStringBuffer& aBuffer, const util::Date& rDate ) +{ + aBuffer.append( OUString::number( rDate.Year ) + + "-" + OUString::number( rDate.Month ) + + "-" + OUString::number( rDate.Day ) ); +} + +void xforms_formatTime( OUStringBuffer& aBuffer, const css::util::Time& rTime ) +{ + Duration aDuration; + aDuration.Hours = rTime.Hours; + aDuration.Minutes = rTime.Minutes; + aDuration.Seconds = rTime.Seconds; + aDuration.NanoSeconds = rTime.NanoSeconds; + ::sax::Converter::convertDuration( aBuffer, aDuration ); +} + +void xforms_formatDateTime( OUStringBuffer& aBuffer, const util::DateTime& aDateTime ) +{ + ::sax::Converter::convertDateTime(aBuffer, aDateTime, nullptr); +} + +OUString xforms_whitespace( const Any& rAny ) +{ + OUString sResult; + sal_uInt16 n = sal_uInt16(); + if( rAny >>= n ) + { + switch( n ) + { + case css::xsd::WhiteSpaceTreatment::Preserve: + sResult = GetXMLToken( XML_PRESERVE ); + break; + case css::xsd::WhiteSpaceTreatment::Replace: + sResult = GetXMLToken( XML_REPLACE ); + break; + case css::xsd::WhiteSpaceTreatment::Collapse: + sResult = GetXMLToken( XML_COLLAPSE ); + break; + } + } + return sResult; +} + + +/// return name of Binding +static OUString lcl_getXFormsBindName( const Reference& xBinding ) +{ + OUString sProp( "BindingID" ); + + OUString sReturn; + if( xBinding.is() && + xBinding->getPropertySetInfo()->hasPropertyByName( sProp ) ) + { + xBinding->getPropertyValue( sProp ) >>= sReturn; + } + return sReturn; +} + +// return name of binding +OUString getXFormsBindName( const Reference& xControl ) +{ + Reference xBindable( xControl, UNO_QUERY ); + return xBindable.is() + ? lcl_getXFormsBindName( + Reference( xBindable->getValueBinding(), UNO_QUERY )) + : OUString(); +} + +// return name of list binding +OUString getXFormsListBindName( const Reference& xControl ) +{ + Reference xListEntrySink( xControl, UNO_QUERY ); + return xListEntrySink.is() + ? lcl_getXFormsBindName( + Reference( xListEntrySink->getListEntrySource(), + UNO_QUERY ) ) + : OUString(); +} + +OUString getXFormsSubmissionName( const Reference& xBinding ) +{ + OUString sReturn; + + Reference xSubmissionSupplier( xBinding, UNO_QUERY ); + if( xSubmissionSupplier.is() ) + { + Reference xPropertySet( + xSubmissionSupplier->getSubmission(), UNO_QUERY ); + OUString sProp( "ID" ); + if( xPropertySet.is() && + xPropertySet->getPropertySetInfo()->hasPropertyByName( sProp ) ) + { + xPropertySet->getPropertyValue( sProp ) >>= sReturn; + } + } + + return sReturn; +} + +void getXFormsSettings( const Reference< XNameAccess >& _rXForms, Sequence< PropertyValue >& _out_rSettings ) +{ + _out_rSettings = Sequence< PropertyValue >(); + + OSL_PRECOND( _rXForms.is(), "getXFormsSettings: invalid XForms container!" ); + if ( !_rXForms.is() ) + return; + + try + { + // we want to export some special properties of our XForms models as config-item-map-named, + // which implies we need a PropertyValue whose value is an XNameAccess, whose keys + // are the names of the XForm models, and which in turn provides named sequences of + // PropertyValues - which denote the actual property values of the given named model. + + const Sequence< OUString > aModelNames( _rXForms->getElementNames() ); + + Reference< XNameContainer > xModelSettings = document::NamedPropertyValues::create( comphelper::getProcessComponentContext() ); + + for ( auto const & modelName : aModelNames ) + { + Reference< XPropertySet > xModelProps( _rXForms->getByName( modelName ), UNO_QUERY_THROW ); + + static constexpr OUStringLiteral sExternalData = u"ExternalData"; + Sequence aModelSettings{ comphelper::makePropertyValue( + sExternalData, xModelProps->getPropertyValue(sExternalData)) }; + + xModelSettings->insertByName( modelName, Any( aModelSettings ) ); + } + + if ( xModelSettings->hasElements() ) + { + _out_rSettings = { comphelper::makePropertyValue("XFormModels", xModelSettings) }; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/xforms/xformsimport.cxx b/xmloff/source/xforms/xformsimport.cxx new file mode 100644 index 000000000..69daa630b --- /dev/null +++ b/xmloff/source/xforms/xformsimport.cxx @@ -0,0 +1,184 @@ +/* -*- 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 "XFormsModelContext.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xformsapi.hxx" +#include +#include + +using std::pair; +using com::sun::star::uno::Reference; +using com::sun::star::uno::Exception; +using com::sun::star::uno::UNO_QUERY; +using com::sun::star::uno::UNO_QUERY_THROW; +using com::sun::star::uno::UNO_SET_THROW; +using com::sun::star::uno::Sequence; +using com::sun::star::beans::XPropertySet; +using com::sun::star::beans::XPropertySetInfo; +using com::sun::star::beans::PropertyValue; +using com::sun::star::frame::XModel; +using com::sun::star::container::XNameAccess; +using com::sun::star::form::binding::XValueBinding; +using com::sun::star::form::binding::XBindableValue; +using com::sun::star::form::binding::XListEntrySource; +using com::sun::star::form::binding::XListEntrySink; +using com::sun::star::form::submission::XSubmission; +using com::sun::star::form::submission::XSubmissionSupplier; + +SvXMLImportContext* createXFormsModelContext( + SvXMLImport& rImport ) +{ + return new XFormsModelContext( rImport ); +} + +void bindXFormsValueBinding(Reference const& xModel, + const pair, OUString>& aPair) +{ + Reference xBindable( + aPair.first, + UNO_QUERY ); + Reference xBinding( + xforms_findXFormsBinding( xModel, aPair.second ), + UNO_QUERY ); + + if( xBindable.is() && xBinding.is() ) + { + try + { + xBindable->setValueBinding( xBinding ); + } + catch( const Exception& ) + { + // ignore problems during binding + // TODO: call XML error handling + } + } +} + +void bindXFormsListBinding(Reference const& xModel, + const ::pair, OUString>& aPair) +{ + Reference xListEntrySink( + aPair.first, + UNO_QUERY ); + Reference xListEntrySource( + xforms_findXFormsBinding( xModel, aPair.second ), + UNO_QUERY ); + + if( xListEntrySink.is() && xListEntrySource.is() ) + { + try + { + xListEntrySink->setListEntrySource( xListEntrySource ); + } + catch( const Exception& ) + { + // ignore problems during binding + // TODO: call XML error handling + } + } +} + +void bindXFormsSubmission(Reference const& xModel, + const pair, OUString>& aPair) +{ + Reference xSubmissionSupp( aPair.first, UNO_QUERY ); + Reference xSubmission( + xforms_findXFormsSubmission( xModel, aPair.second ), + UNO_QUERY ); + + if( xSubmissionSupp.is() && xSubmission.is() ) + { + try + { + xSubmissionSupp->setSubmission( xSubmission ); + } + catch( const Exception& ) + { + // ignore problems during binding + // TODO: call XML error handling + } + } +} + +void applyXFormsSettings( const Reference< XNameAccess >& _rXForms, const Sequence< PropertyValue >& _rSettings ) +{ + OSL_PRECOND( _rXForms.is(), "applyXFormsSettings: invalid XForms container!" ); + if ( !_rXForms.is() ) + return; + + Reference< XNameAccess > xModelSettings( ::comphelper::NamedValueCollection::get( _rSettings, u"XFormModels" ), UNO_QUERY ); + if ( !xModelSettings.is() ) + { + OSL_FAIL( "applyXFormsSettings: wrong type for the XFormModels settings!" ); + return; + } + + try + { + const Sequence< OUString > aSettingsForModels( xModelSettings->getElementNames() ); + for ( auto const & modelName : aSettingsForModels ) + { + // the settings for this particular model + Sequence< PropertyValue > aModelSettings; + OSL_VERIFY( xModelSettings->getByName( modelName ) >>= aModelSettings ); + + // the model itself + if ( !_rXForms->hasByName( modelName ) ) + { + OSL_FAIL( "applyXFormsSettings: have settings for a non-existent XForms model!" ); + continue; + } + + // propagate the settings, being tolerant by omitting properties which are not supported + Reference< XPropertySet > xModelProps( _rXForms->getByName( modelName ), UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xModelPSI( xModelProps->getPropertySetInfo(), UNO_SET_THROW ); + + for ( auto const & setting : std::as_const(aModelSettings) ) + { + if ( !xModelPSI->hasPropertyByName( setting.Name ) ) + { + OSL_FAIL( "applyXFormsSettings: non-existent model property!" ); + continue; + } + + xModelProps->setPropertyValue( setting.Name, setting.Value ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3