summaryrefslogtreecommitdiffstats
path: root/xmloff/source/table
diff options
context:
space:
mode:
Diffstat (limited to 'xmloff/source/table')
-rw-r--r--xmloff/source/table/XMLTableExport.cxx730
-rw-r--r--xmloff/source/table/XMLTableImport.cxx787
-rw-r--r--xmloff/source/table/table.hxx38
3 files changed, 1555 insertions, 0 deletions
diff --git a/xmloff/source/table/XMLTableExport.cxx b/xmloff/source/table/XMLTableExport.cxx
new file mode 100644
index 0000000000..73d6fdada7
--- /dev/null
+++ b/xmloff/source/table/XMLTableExport.cxx
@@ -0,0 +1,730 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <xmloff/table/XMLTableExport.hxx>
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <rtl/ustring.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/table/XMergeableCell.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmlprmap.hxx>
+#include <xmloff/xmlexppr.hxx>
+#include <xmloff/xmlexp.hxx>
+#include <xmloff/xmltypes.hxx>
+#include <xmlsdtypes.hxx>
+#include <xmloff/maptype.hxx>
+#include <xmloff/prhdlfac.hxx>
+#include <xmloff/txtprmap.hxx>
+#include "table.hxx"
+#include <xmlprop.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 }
+
+const XMLPropertyMapEntry* getColumnPropertiesMap()
+{
+ static const XMLPropertyMapEntry aXMLColumnProperties[] =
+ {
+ CMAP( PROP_Width, XML_NAMESPACE_STYLE, XML_COLUMN_WIDTH, XML_TYPE_MEASURE, 0 ),
+ CMAP( PROP_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( PROP_Height, XML_NAMESPACE_STYLE, XML_ROW_HEIGHT, XML_TYPE_MEASURE, 0 ),
+ RMAP( PROP_MinHeight, XML_NAMESPACE_STYLE, XML_MIN_ROW_HEIGHT, XML_TYPE_MEASURE, 0 ),
+ RMAP( PROP_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( PROP_RotateAngle, XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_SD_TYPE_CELL_ROTATION_ANGLE, 0),
+ CELLMAP( PROP_TextVerticalAdjust, XML_NAMESPACE_STYLE, XML_VERTICAL_ALIGN, XML_SD_TYPE_VERTICAL_ALIGN|MID_FLAG_SPECIAL_ITEM_EXPORT, 0),
+ CELLMAP( PROP_BackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_SPECIAL_ITEM, 0),
+ CELLMAP( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARALLBORDER),
+ CELLMAP( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARLEFTBORDER),
+ CELLMAP( PROP_RightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARRIGHTBORDER),
+ CELLMAP( PROP_TopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARTOPBORDER),
+ CELLMAP( PROP_BottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARBOTTOMBORDER),
+ CELLMAP( PROP_TextLeftDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARALLBORDERDISTANCE),
+ CELLMAP( PROP_TextLeftDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARLEFTBORDERDISTANCE),
+ CELLMAP( PROP_TextRightDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARRIGHTBORDERDISTANCE),
+ CELLMAP( PROP_TextUpperDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARTOPBORDERDISTANCE),
+ CELLMAP( PROP_TextLowerDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARBOTTOMBORDERDISTANCE),
+ 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(comphelper::AttributeList&, const XMLPropertyState&, const SvXMLUnitConverter&,
+ const SvXMLNamespaceMap&, const std::vector<XMLPropertyState>*, 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 XMLCellExportPropertyMapper(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,
+ XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME,
+ mxColumnExportPropertySetMapper.get(),
+ XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX);
+ mrExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_ROW,
+ XML_STYLE_FAMILY_TABLE_ROW_STYLES_NAME,
+ mxRowExportPropertySetMapper.get(),
+ XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX);
+ mrExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_CELL,
+ XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME,
+ mxCellExportPropertySetMapper.get(),
+ 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<XMLTableInfo>();
+ 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<XMLPropertyState> 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<XMLPropertyState> 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<XMLPropertyState> 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 ) );
+
+ // <table:table-cell> or <table:covered-table-cell>
+ 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<XMLStyleExport> 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, 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 );
+ Reference<XPropertySet> xTableStylePropSet( xTableStyle, UNO_QUERY_THROW );
+ bool bPhysical = false;
+
+ try
+ {
+ xTableStylePropSet->getPropertyValue("IsPhysical") >>= bPhysical;
+ }
+ catch(const Exception&)
+ {
+ }
+
+ if (!xTableStyle->isInUse() && !bPhysical)
+ continue;
+
+ const TableStyleElement* pElements;
+ if (mbWriter)
+ {
+ mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, xTableStyle->getName());
+ 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, xTableStyle->getName());
+ }
+ mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, 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> 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<XStyle>& /*rStyle*/)
+{
+}
+
+void XMLCellStyleExport::exportStyleAttributes(const Reference<XStyle>& rStyle)
+{
+ Reference<XPropertySet> xPropSet(rStyle, UNO_QUERY);
+ if (!xPropSet.is())
+ return;
+
+ Reference<XPropertySetInfo> xPropSetInfo(xPropSet->getPropertySetInfo());
+ static constexpr OUString sNumberFormat(u"NumberFormat"_ustr);
+ if (xPropSetInfo->hasPropertyByName(sNumberFormat))
+ {
+ Reference<XPropertyState> 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 0000000000..40899a4fda
--- /dev/null
+++ b/xmloff/source/table/XMLTableImport.cxx
@@ -0,0 +1,787 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/table/XTableRows.hpp>
+#include <com/sun/star/table/XMergeableCell.hpp>
+#include <com/sun/star/table/XMergeableCellRange.hpp>
+#include <com/sun/star/table/XTable.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/diagnose_ex.hxx>
+
+#include <utility>
+#include <xmloff/table/XMLTableImport.hxx>
+#include <xmloff/xmltypes.hxx>
+#include <xmloff/maptype.hxx>
+#include <xmloff/xmlprmap.hxx>
+#include <xmloff/txtimp.hxx>
+#include <xmloff/xmlimp.hxx>
+#include <xmloff/namespacemap.hxx>
+#include <xmloff/xmlstyle.hxx>
+#include <xmloff/prstylei.hxx>
+
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmluconv.hxx>
+#include "table.hxx"
+
+#include <sal/log.hxx>
+
+#include <memory>
+
+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, 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 XMLCellImportPropertyMapper : public SvXMLImportPropertyMapper
+{
+public:
+ using SvXMLImportPropertyMapper::SvXMLImportPropertyMapper;
+
+ bool handleSpecialItem(
+ XMLPropertyState& rProperty,
+ std::vector< XMLPropertyState >& rProperties,
+ const OUString& rValue,
+ const SvXMLUnitConverter& rUnitConverter,
+ const SvXMLNamespaceMap& /*rNamespaceMap*/) const override
+ {
+ assert(getPropertySetMapper()->GetEntryXMLName(rProperty.mnIndex) == GetXMLToken(XML_BACKGROUND_COLOR));
+ (void)rProperty;
+
+ auto nIndex = getPropertySetMapper()->GetEntryIndex(XML_NAMESPACE_DRAW, GetXMLToken(XML_FILL), 0);
+ XMLPropertyState aFillProperty(nIndex);
+
+ if (IsXMLToken(rValue, XML_TRANSPARENT))
+ {
+ getPropertySetMapper()->importXML(GetXMLToken(XML_NONE), aFillProperty, rUnitConverter);
+ rProperties.push_back(aFillProperty);
+ }
+ else
+ {
+ getPropertySetMapper()->importXML(GetXMLToken(XML_SOLID), aFillProperty, rUnitConverter);
+ rProperties.push_back(aFillProperty);
+
+ nIndex = getPropertySetMapper()->GetEntryIndex(XML_NAMESPACE_DRAW, GetXMLToken(XML_FILL_COLOR), 0);
+ XMLPropertyState aColorProperty(nIndex);
+ getPropertySetMapper()->importXML(rValue, aColorProperty, rUnitConverter);
+ rProperties.push_back(aColorProperty);
+ }
+
+ return false;
+ }
+};
+
+}
+
+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;
+
+protected:
+ virtual void SetAttribute( sal_Int32 nElement,
+ const OUString& rValue ) override;
+private:
+ XMLTableTemplate maTableTemplate;
+ OUString msTemplateStyleName;
+};
+
+}
+
+
+XMLProxyContext::XMLProxyContext( SvXMLImport& rImport, SvXMLImportContextRef xParent )
+: SvXMLImportContext( rImport )
+, mxParent(std::move( 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 )
+, mbWriter( false )
+{
+ // check if called by Writer
+ Reference<XMultiServiceFactory> xFac(rImport.GetModel(), UNO_QUERY);
+ if (xFac.is()) try
+ {
+ Sequence<OUString> sSNS = xFac->getAvailableServiceNames();
+ mbWriter = comphelper::findValue(sSNS, "com.sun.star.style.TableStyle") != -1;
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("xmloff.table", "Error while checking available service names");
+ }
+
+ if (mbWriter)
+ {
+ mxCellImportPropertySetMapper = XMLTextImportHelper::CreateTableCellExtPropMapper(rImport);
+ }
+ else
+ {
+ mxCellImportPropertySetMapper = new SvXMLImportPropertyMapper( xCellPropertySetMapper, rImport );
+ mxCellImportPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImport));
+ mxCellImportPropertySetMapper->ChainImportMapper(new XMLCellImportPropertyMapper(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<XMLTableTemplate>();
+ xPtr->swap( xTableTemplate );
+ maTableTemplates.emplace_back(rsStyleName, xPtr);
+}
+
+void XMLTableImport::finishStyles()
+{
+ if( maTableTemplates.empty() )
+ return;
+
+ try
+ {
+ Reference< XStyleFamiliesSupplier > xFamiliesSupp( mrImport.GetModel(), UNO_QUERY_THROW );
+ Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() );
+
+ const OUString aTableFamily(mbWriter ? u"TableStyles" : u"table");
+ const OUString aCellFamily(mbWriter ? u"CellStyles" : u"cell");
+ Reference< XNameContainer > xTableFamily( xFamilies->getByName( aTableFamily ), UNO_QUERY_THROW );
+ Reference< XNameAccess > xCellFamily( xFamilies->getByName( aCellFamily ), UNO_QUERY_THROW );
+
+ Reference< XSingleServiceFactory > xFactory( xTableFamily, UNO_QUERY );
+ assert(xFactory.is() != mbWriter);
+ Reference< XMultiServiceFactory > xMultiFactory( mrImport.GetModel(), UNO_QUERY_THROW );
+
+ for( const auto& rTemplate : maTableTemplates ) try
+ {
+ const OUString sTemplateName( rTemplate.first );
+ Reference< XNameReplace > xTemplate(xFactory ? xFactory->createInstance() :
+ xMultiFactory->createInstance("com.sun.star.style.TableStyle"), UNO_QUERY_THROW);
+
+ std::shared_ptr< XMLTableTemplate > xT( rTemplate.second );
+
+ for( const auto& rStyle : *xT ) try
+ {
+ const OUString sPropName( rStyle.first );
+ const OUString sStyleName( mrImport.GetStyleDisplayName(XmlStyleFamily::TABLE_CELL, 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<ColumnInfo>();
+
+ 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<sal_Int32>(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 );
+}
+
+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 0000000000..686972065d
--- /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 <xmloff/xmltoken.hxx>
+
+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: */