/src/libreoffice/xmloff/source/table/XMLTableExport.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <xmloff/table/XMLTableExport.hxx> |
21 | | |
22 | | #include <sal/config.h> |
23 | | #include <sal/log.hxx> |
24 | | |
25 | | #include <rtl/ustring.hxx> |
26 | | #include <com/sun/star/frame/XModel.hpp> |
27 | | #include <com/sun/star/style/XStyleFamiliesSupplier.hpp> |
28 | | #include <com/sun/star/text/XText.hpp> |
29 | | #include <com/sun/star/table/XCellRange.hpp> |
30 | | #include <com/sun/star/table/XColumnRowRange.hpp> |
31 | | #include <com/sun/star/table/XMergeableCell.hpp> |
32 | | #include <com/sun/star/style/XStyle.hpp> |
33 | | #include <com/sun/star/beans/XPropertyState.hpp> |
34 | | #include <com/sun/star/beans/XPropertySet.hpp> |
35 | | #include <com/sun/star/beans/XPropertySetInfo.hpp> |
36 | | #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
37 | | #include <comphelper/diagnose_ex.hxx> |
38 | | |
39 | | #include <xmloff/xmlnamespace.hxx> |
40 | | #include <xmloff/xmlprmap.hxx> |
41 | | #include <xmloff/xmlexppr.hxx> |
42 | | #include <xmloff/xmlexp.hxx> |
43 | | #include <xmloff/xmltypes.hxx> |
44 | | #include <xmlsdtypes.hxx> |
45 | | #include <xmloff/maptype.hxx> |
46 | | #include <xmloff/prhdlfac.hxx> |
47 | | #include <xmloff/txtprmap.hxx> |
48 | | #include "table.hxx" |
49 | | #include <xmlprop.hxx> |
50 | | |
51 | | using namespace ::xmloff::token; |
52 | | using namespace ::com::sun::star::uno; |
53 | | using namespace ::com::sun::star::lang; |
54 | | using namespace ::com::sun::star::table; |
55 | | using namespace ::com::sun::star::beans; |
56 | | using namespace ::com::sun::star::container; |
57 | | using namespace ::com::sun::star::text; |
58 | | using namespace ::com::sun::star::style; |
59 | | |
60 | 34.7k | #define MAP_(name,prefix,token,type,context) { name, prefix, token, type, context, SvtSaveOptions::ODFSVER_010, false } |
61 | 13.5k | #define CMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TABLE_COLUMN,context) |
62 | 20.3k | #define RMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TABLE_ROW,context) |
63 | 897 | #define CELLMAP(name,prefix,token,type,context) MAP_(name,prefix,token,type|XML_TYPE_PROP_TABLE_CELL,context) |
64 | 13.6k | #define MAP_END { nullptr } |
65 | | |
66 | | const XMLPropertyMapEntry* getColumnPropertiesMap() |
67 | 6.77k | { |
68 | 6.77k | static const XMLPropertyMapEntry aXMLColumnProperties[] = |
69 | 6.77k | { |
70 | 6.77k | CMAP( PROP_Width, XML_NAMESPACE_STYLE, XML_COLUMN_WIDTH, XML_TYPE_MEASURE, 0 ), |
71 | 6.77k | CMAP( PROP_OptimalWidth, XML_NAMESPACE_STYLE, XML_USE_OPTIMAL_COLUMN_WIDTH, XML_TYPE_BOOL, 0 ), |
72 | 6.77k | MAP_END |
73 | 6.77k | }; |
74 | | |
75 | 6.77k | return &aXMLColumnProperties[0]; |
76 | 6.77k | } |
77 | | |
78 | | const XMLPropertyMapEntry* getRowPropertiesMap() |
79 | 6.77k | { |
80 | 6.77k | static const XMLPropertyMapEntry aXMLRowProperties[] = |
81 | 6.77k | { |
82 | 6.77k | RMAP( PROP_Height, XML_NAMESPACE_STYLE, XML_ROW_HEIGHT, XML_TYPE_MEASURE, 0 ), |
83 | 6.77k | RMAP( PROP_MinHeight, XML_NAMESPACE_STYLE, XML_MIN_ROW_HEIGHT, XML_TYPE_MEASURE, 0 ), |
84 | 6.77k | RMAP( PROP_OptimalHeight, XML_NAMESPACE_STYLE, XML_USE_OPTIMAL_ROW_HEIGHT, XML_TYPE_BOOL, 0 ), |
85 | 6.77k | MAP_END |
86 | 6.77k | }; |
87 | | |
88 | 6.77k | return &aXMLRowProperties[0]; |
89 | 6.77k | } |
90 | | |
91 | | const XMLPropertyMapEntry* getCellPropertiesMap() |
92 | 69 | { |
93 | 69 | static const XMLPropertyMapEntry aXMLCellProperties[] = |
94 | 69 | { |
95 | 69 | CELLMAP( PROP_RotateAngle, XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_SD_TYPE_CELL_ROTATION_ANGLE, 0), |
96 | 69 | CELLMAP( PROP_TextVerticalAdjust, XML_NAMESPACE_STYLE, XML_VERTICAL_ALIGN, XML_SD_TYPE_VERTICAL_ALIGN|MID_FLAG_SPECIAL_ITEM_EXPORT, 0), |
97 | 69 | CELLMAP( PROP_BackColor, XML_NAMESPACE_FO, XML_BACKGROUND_COLOR, XML_TYPE_COLORTRANSPARENT|MID_FLAG_SPECIAL_ITEM, 0), |
98 | 69 | CELLMAP( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARALLBORDER), |
99 | 69 | CELLMAP( PROP_LeftBorder, XML_NAMESPACE_FO, XML_BORDER_LEFT, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARLEFTBORDER), |
100 | 69 | CELLMAP( PROP_RightBorder, XML_NAMESPACE_FO, XML_BORDER_RIGHT, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARRIGHTBORDER), |
101 | 69 | CELLMAP( PROP_TopBorder, XML_NAMESPACE_FO, XML_BORDER_TOP, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARTOPBORDER), |
102 | 69 | CELLMAP( PROP_BottomBorder, XML_NAMESPACE_FO, XML_BORDER_BOTTOM, XML_TYPE_BORDER|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARBOTTOMBORDER), |
103 | 69 | CELLMAP( PROP_TextLeftDistance, XML_NAMESPACE_FO, XML_PADDING, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARALLBORDERDISTANCE), |
104 | 69 | CELLMAP( PROP_TextLeftDistance, XML_NAMESPACE_FO, XML_PADDING_LEFT, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARLEFTBORDERDISTANCE), |
105 | 69 | CELLMAP( PROP_TextRightDistance, XML_NAMESPACE_FO, XML_PADDING_RIGHT, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARRIGHTBORDERDISTANCE), |
106 | 69 | CELLMAP( PROP_TextUpperDistance, XML_NAMESPACE_FO, XML_PADDING_TOP, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARTOPBORDERDISTANCE), |
107 | 69 | CELLMAP( PROP_TextLowerDistance, XML_NAMESPACE_FO, XML_PADDING_BOTTOM, XML_TYPE_MEASURE|MID_FLAG_SPECIAL_ITEM_EXPORT, CTF_CHARBOTTOMBORDERDISTANCE), |
108 | 69 | MAP_END |
109 | 69 | }; |
110 | | |
111 | 69 | return &aXMLCellProperties[0]; |
112 | 69 | } |
113 | | |
114 | | namespace { |
115 | | |
116 | | class StringStatisticHelper |
117 | | { |
118 | | private: |
119 | | std::map< OUString, sal_Int32 > mStats; |
120 | | |
121 | | public: |
122 | | void add( const OUString& rStyleName ); |
123 | 0 | void clear() { mStats.clear(); } |
124 | | |
125 | | sal_Int32 getModeString( /* out */ OUString& rModeString ); |
126 | | }; |
127 | | |
128 | | } |
129 | | |
130 | | void StringStatisticHelper::add( const OUString& rStyleName ) |
131 | 0 | { |
132 | 0 | std::map< OUString, sal_Int32 >::iterator iter( mStats.find( rStyleName ) ); |
133 | 0 | if( iter == mStats.end() ) |
134 | 0 | { |
135 | 0 | mStats[rStyleName] = 1; |
136 | 0 | } |
137 | 0 | else |
138 | 0 | { |
139 | 0 | (*iter).second += 1; |
140 | 0 | } |
141 | 0 | } |
142 | | |
143 | | sal_Int32 StringStatisticHelper::getModeString( OUString& rStyleName ) |
144 | 0 | { |
145 | 0 | sal_Int32 nMax = 0; |
146 | 0 | for( const auto& rStatsEntry : mStats ) |
147 | 0 | { |
148 | 0 | if( rStatsEntry.second > nMax ) |
149 | 0 | { |
150 | 0 | rStyleName = rStatsEntry.first; |
151 | 0 | nMax = rStatsEntry.second; |
152 | 0 | } |
153 | 0 | } |
154 | |
|
155 | 0 | return nMax; |
156 | 0 | } |
157 | | |
158 | | namespace { |
159 | | |
160 | | class XMLCellExportPropertyMapper : public SvXMLExportPropertyMapper |
161 | | { |
162 | | public: |
163 | | using SvXMLExportPropertyMapper::SvXMLExportPropertyMapper; |
164 | | /** this method is called for every item that has the |
165 | | MID_FLAG_SPECIAL_ITEM_EXPORT flag set */ |
166 | | virtual void handleSpecialItem(comphelper::AttributeList&, const XMLPropertyState&, const SvXMLUnitConverter&, |
167 | | const SvXMLNamespaceMap&, const std::vector<XMLPropertyState>*, sal_uInt32) const override |
168 | 0 | { |
169 | | // the SpecialItem NumberFormat must not be handled by this method |
170 | 0 | } |
171 | | }; |
172 | | |
173 | | } |
174 | | |
175 | | XMLTableExport::XMLTableExport(SvXMLExport& rExp, const rtl::Reference< SvXMLExportPropertyMapper >& xExportPropertyMapper, const rtl::Reference< XMLPropertyHandlerFactory >& xFactoryRef ) |
176 | 69 | : mrExport( rExp ) |
177 | 69 | , mbExportTables( false ) |
178 | 69 | , mbWriter( false ) |
179 | 69 | { |
180 | 69 | Reference< XMultiServiceFactory > xFac( rExp.GetModel(), UNO_QUERY ); |
181 | 69 | if( xFac.is() ) try |
182 | 69 | { |
183 | 69 | const Sequence< OUString > sSNS( xFac->getAvailableServiceNames() ); |
184 | 69 | const OUString* pSNS = std::find_if(sSNS.begin(), sSNS.end(), |
185 | 4.76k | [](const OUString& rSNS) { |
186 | 4.76k | return rSNS == "com.sun.star.drawing.TableShape" |
187 | 4.69k | || rSNS == "com.sun.star.style.TableStyle"; }); |
188 | 69 | if (pSNS != sSNS.end()) |
189 | 69 | { |
190 | 69 | mbExportTables = true; |
191 | 69 | mbWriter = (*pSNS == "com.sun.star.style.TableStyle"); |
192 | 69 | } |
193 | 69 | } |
194 | 69 | catch(const Exception&) |
195 | 69 | { |
196 | 0 | } |
197 | | |
198 | 69 | if (mbWriter) |
199 | 0 | { |
200 | 0 | mxCellExportPropertySetMapper = new XMLCellExportPropertyMapper(new XMLTextPropertySetMapper(TextPropMap::CELL, true)); |
201 | 0 | } |
202 | 69 | else |
203 | 69 | { |
204 | 69 | mxCellExportPropertySetMapper = xExportPropertyMapper; |
205 | 69 | mxCellExportPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp)); |
206 | 69 | mxCellExportPropertySetMapper->ChainExportMapper(new XMLCellExportPropertyMapper(new XMLPropertySetMapper(getCellPropertiesMap(), xFactoryRef, true))); |
207 | 69 | } |
208 | | |
209 | 69 | mxRowExportPropertySetMapper = new SvXMLExportPropertyMapper( new XMLPropertySetMapper( getRowPropertiesMap(), xFactoryRef, true ) ); |
210 | 69 | mxColumnExportPropertySetMapper = new SvXMLExportPropertyMapper( new XMLPropertySetMapper( getColumnPropertiesMap(), xFactoryRef, true ) ); |
211 | | |
212 | 69 | mrExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_COLUMN, |
213 | 69 | XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME, |
214 | 69 | mxColumnExportPropertySetMapper.get(), |
215 | 69 | XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX); |
216 | 69 | mrExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_ROW, |
217 | 69 | XML_STYLE_FAMILY_TABLE_ROW_STYLES_NAME, |
218 | 69 | mxRowExportPropertySetMapper.get(), |
219 | 69 | XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX); |
220 | 69 | mrExport.GetAutoStylePool()->AddFamily(XmlStyleFamily::TABLE_CELL, |
221 | 69 | XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME, |
222 | 69 | mxCellExportPropertySetMapper.get(), |
223 | 69 | XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX); |
224 | 69 | } |
225 | | |
226 | | XMLTableExport::~XMLTableExport () |
227 | 69 | { |
228 | 69 | } |
229 | | |
230 | | static bool has_states( const std::vector< XMLPropertyState >& xPropStates ) |
231 | 0 | { |
232 | 0 | return std::any_of(xPropStates.cbegin(), xPropStates.cend(), |
233 | 0 | [](const XMLPropertyState& rPropertyState) { return rPropertyState.mnIndex != -1; }); |
234 | 0 | } |
235 | | |
236 | | void XMLTableExport::collectTableAutoStyles(const Reference < XColumnRowRange >& xColumnRowRange) |
237 | 0 | { |
238 | 0 | if( !mbExportTables ) |
239 | 0 | return; |
240 | | |
241 | 0 | auto xTableInfo = std::make_shared<XMLTableInfo>(); |
242 | 0 | maTableInfoMap[xColumnRowRange] = xTableInfo; |
243 | |
|
244 | 0 | try |
245 | 0 | { |
246 | 0 | Reference< XIndexAccess > xIndexAccessCols( xColumnRowRange->getColumns(), UNO_QUERY_THROW ); |
247 | 0 | const sal_Int32 nColumnCount = xIndexAccessCols->getCount(); |
248 | 0 | for( sal_Int32 nColumn = 0; nColumn < nColumnCount; ++nColumn ) try |
249 | 0 | { |
250 | 0 | Reference< XPropertySet > xPropSet( xIndexAccessCols->getByIndex(nColumn) , UNO_QUERY_THROW ); |
251 | 0 | std::vector<XMLPropertyState> aPropStates(mxColumnExportPropertySetMapper->Filter(mrExport, xPropSet)); |
252 | |
|
253 | 0 | if( has_states( aPropStates ) ) |
254 | 0 | { |
255 | 0 | const OUString sStyleName( mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TABLE_COLUMN, std::move(aPropStates)) ); |
256 | 0 | Reference< XInterface > xKey( xPropSet, UNO_QUERY ); |
257 | 0 | xTableInfo->maColumnStyleMap[xKey] = sStyleName; |
258 | 0 | } |
259 | 0 | } |
260 | 0 | catch(const Exception&) |
261 | 0 | { |
262 | 0 | TOOLS_WARN_EXCEPTION("xmloff.table", "exception during column style collection!"); |
263 | 0 | } |
264 | | |
265 | 0 | Reference< XIndexAccess > xIndexAccessRows( xColumnRowRange->getRows(), UNO_QUERY_THROW ); |
266 | 0 | const sal_Int32 nRowCount = xIndexAccessRows->getCount(); |
267 | 0 | xTableInfo->maDefaultRowCellStyles.resize(nRowCount); |
268 | |
|
269 | 0 | StringStatisticHelper aStringStatistic; |
270 | |
|
271 | 0 | for( sal_Int32 nRow = 0; nRow < nRowCount; ++nRow ) |
272 | 0 | try |
273 | 0 | { |
274 | 0 | Reference< XPropertySet > xPropSet( xIndexAccessRows->getByIndex(nRow) , UNO_QUERY_THROW ); |
275 | 0 | std::vector<XMLPropertyState> aRowPropStates(mxRowExportPropertySetMapper->Filter(mrExport, xPropSet)); |
276 | |
|
277 | 0 | if( has_states( aRowPropStates ) ) |
278 | 0 | { |
279 | 0 | const OUString sStyleName( mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TABLE_ROW, std::move(aRowPropStates)) ); |
280 | 0 | Reference< XInterface > xKey( xPropSet, UNO_QUERY ); |
281 | 0 | xTableInfo->maRowStyleMap[xKey] = sStyleName; |
282 | 0 | } |
283 | | |
284 | | // get the current row |
285 | 0 | Reference< XCellRange > xCellRange( xPropSet, UNO_QUERY_THROW ); |
286 | 0 | for ( sal_Int32 nColumn = 0; nColumn < nColumnCount; ++nColumn ) |
287 | 0 | { |
288 | | // get current cell, remarks row index is 0, because we get the range for each row separate |
289 | 0 | Reference< XPropertySet > xCellSet( xCellRange->getCellByPosition(nColumn, 0), UNO_QUERY_THROW ); |
290 | | |
291 | | // get style |
292 | 0 | OUString sParentStyleName; |
293 | 0 | Reference< XPropertySetInfo > xPropertySetInfo( xCellSet->getPropertySetInfo() ); |
294 | 0 | if( xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName(u"Style"_ustr) ) |
295 | 0 | { |
296 | 0 | Reference< XStyle > xStyle( xCellSet->getPropertyValue(u"Style"_ustr), UNO_QUERY ); |
297 | 0 | if( xStyle.is() ) |
298 | 0 | sParentStyleName = xStyle->getName(); |
299 | 0 | } |
300 | | |
301 | | // create auto style, if needed |
302 | 0 | OUString sStyleName; |
303 | 0 | std::vector<XMLPropertyState> aCellPropStates(mxCellExportPropertySetMapper->Filter(mrExport, xCellSet)); |
304 | 0 | if( has_states( aCellPropStates ) ) |
305 | 0 | sStyleName = mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TABLE_CELL, std::move(aCellPropStates)); |
306 | 0 | else |
307 | 0 | sStyleName = sParentStyleName; |
308 | |
|
309 | 0 | if( !sStyleName.isEmpty() ) |
310 | 0 | { |
311 | 0 | Reference< XInterface > xKey( xCellSet, UNO_QUERY ); |
312 | 0 | xTableInfo->maCellStyleMap[xKey] = sStyleName; |
313 | 0 | } |
314 | | |
315 | | // create auto style for text |
316 | 0 | Reference< XText > xText(xCellSet, UNO_QUERY); |
317 | 0 | if(xText.is() && !xText->getString().isEmpty()) |
318 | 0 | GetExport().GetTextParagraphExport()->collectTextAutoStyles( xText ); |
319 | |
|
320 | 0 | aStringStatistic.add( sStyleName ); |
321 | 0 | } |
322 | |
|
323 | 0 | OUString sDefaultCellStyle; |
324 | 0 | if( aStringStatistic.getModeString( sDefaultCellStyle ) > 1 ) |
325 | 0 | xTableInfo->maDefaultRowCellStyles[nRow] = sDefaultCellStyle; |
326 | |
|
327 | 0 | aStringStatistic.clear(); |
328 | 0 | } |
329 | 0 | catch(const Exception&) |
330 | 0 | { |
331 | 0 | TOOLS_WARN_EXCEPTION("xmloff.table", "exception during column style collection!"); |
332 | 0 | } |
333 | 0 | } |
334 | 0 | catch(const Exception&) |
335 | 0 | { |
336 | 0 | TOOLS_WARN_EXCEPTION("xmloff.table", "exception caught!"); |
337 | 0 | } |
338 | 0 | } |
339 | | |
340 | | void XMLTableExport::exportTable( const Reference < XColumnRowRange >& xColumnRowRange ) |
341 | 0 | { |
342 | 0 | if( !mbExportTables ) |
343 | 0 | return; |
344 | | |
345 | 0 | try |
346 | 0 | { |
347 | 0 | std::shared_ptr< XMLTableInfo > xTableInfo( maTableInfoMap[xColumnRowRange] ); |
348 | | |
349 | | // get row and column count |
350 | 0 | Reference< XIndexAccess > xIndexAccess( xColumnRowRange->getRows(), UNO_QUERY_THROW ); |
351 | 0 | Reference< XIndexAccess > xIndexAccessCols( xColumnRowRange->getColumns(), UNO_QUERY_THROW ); |
352 | |
|
353 | 0 | const sal_Int32 rowCount = xIndexAccess->getCount(); |
354 | 0 | const sal_Int32 columnCount = xIndexAccessCols->getCount(); |
355 | |
|
356 | 0 | SvXMLElementExport tableElement( mrExport, XML_NAMESPACE_TABLE, XML_TABLE, true, true ); |
357 | | |
358 | | // export table columns |
359 | 0 | ExportTableColumns( xIndexAccessCols, xTableInfo ); |
360 | | |
361 | | // start iterating rows and columns |
362 | 0 | for ( sal_Int32 rowIndex = 0; rowIndex < rowCount; rowIndex++ ) |
363 | 0 | { |
364 | | // get the current row |
365 | 0 | Reference< XCellRange > xCellRange( xIndexAccess->getByIndex(rowIndex), UNO_QUERY_THROW ); |
366 | |
|
367 | 0 | OUString sDefaultCellStyle; |
368 | | |
369 | | // table:style-name |
370 | 0 | if( xTableInfo ) |
371 | 0 | { |
372 | 0 | Reference< XInterface > xKey( xCellRange, UNO_QUERY ); |
373 | 0 | const OUString sStyleName( xTableInfo->maRowStyleMap[xKey] ); |
374 | 0 | if( !sStyleName.isEmpty() ) |
375 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sStyleName ); |
376 | |
|
377 | 0 | sDefaultCellStyle = xTableInfo->maDefaultRowCellStyles[rowIndex]; |
378 | 0 | if( !sDefaultCellStyle.isEmpty() ) |
379 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_DEFAULT_CELL_STYLE_NAME, sDefaultCellStyle ); |
380 | 0 | } |
381 | | |
382 | | // write row element |
383 | 0 | SvXMLElementExport tableRowElement( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_ROW, true, true ); |
384 | |
|
385 | 0 | for ( sal_Int32 columnIndex = 0; columnIndex < columnCount; columnIndex++ ) |
386 | 0 | { |
387 | | // get current cell, remarks row index is 0, because we get the range for each row separate |
388 | 0 | Reference< XCell > xCell( xCellRange->getCellByPosition(columnIndex, 0), UNO_SET_THROW ); |
389 | | |
390 | | // use XMergeableCell interface from offapi |
391 | 0 | Reference< XMergeableCell > xMergeableCell( xCell, UNO_QUERY_THROW ); |
392 | | |
393 | | // export cell |
394 | 0 | ExportCell( xCell, xTableInfo, sDefaultCellStyle ); |
395 | 0 | } |
396 | 0 | } |
397 | 0 | } |
398 | 0 | catch(const Exception&) |
399 | 0 | { |
400 | 0 | TOOLS_WARN_EXCEPTION("xmloff.table", "" ); |
401 | 0 | } |
402 | 0 | } |
403 | | |
404 | | // Export the table columns |
405 | | |
406 | | void XMLTableExport::ExportTableColumns( const Reference < XIndexAccess >& xtableColumnsIndexAccess, const std::shared_ptr< XMLTableInfo >& rTableInfo ) |
407 | 0 | { |
408 | 0 | const sal_Int32 nColumnCount = xtableColumnsIndexAccess->getCount(); |
409 | 0 | for( sal_Int32 nColumn = 0; nColumn < nColumnCount; ++nColumn ) |
410 | 0 | { |
411 | 0 | Reference< XPropertySet > xColumnProperties( xtableColumnsIndexAccess->getByIndex(nColumn) , UNO_QUERY ); |
412 | 0 | if ( xColumnProperties.is() ) |
413 | 0 | { |
414 | | // table:style-name |
415 | 0 | if( rTableInfo ) |
416 | 0 | { |
417 | 0 | Reference< XInterface > xKey( xColumnProperties, UNO_QUERY ); |
418 | 0 | const OUString sStyleName( rTableInfo->maColumnStyleMap[xKey] ); |
419 | 0 | if( !sStyleName.isEmpty() ) |
420 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sStyleName ); |
421 | 0 | } |
422 | | |
423 | | // TODO: all columns first have to be checked if someone |
424 | | // have identical properties. If yes, attr table:number-columns-repeated |
425 | | // has to be written. |
426 | 0 | SvXMLElementExport tableColumnElement( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, true, true ); |
427 | 0 | } |
428 | 0 | } |
429 | 0 | } |
430 | | |
431 | | // ODF export for a table cell. |
432 | | |
433 | | void XMLTableExport::ExportCell( const Reference < XCell >& xCell, const std::shared_ptr< XMLTableInfo >& rTableInfo, std::u16string_view rDefaultCellStyle ) |
434 | 0 | { |
435 | 0 | bool bIsMerged = false; |
436 | 0 | sal_Int32 nRowSpan = 0; |
437 | 0 | sal_Int32 nColSpan = 0; |
438 | |
|
439 | 0 | try |
440 | 0 | { |
441 | 0 | if( rTableInfo ) |
442 | 0 | { |
443 | | // table:style-name |
444 | 0 | Reference< XInterface > xKey( xCell, UNO_QUERY ); |
445 | 0 | const OUString sStyleName( rTableInfo->maCellStyleMap[xKey] ); |
446 | 0 | if( !sStyleName.isEmpty() && (sStyleName != rDefaultCellStyle) ) |
447 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, sStyleName ); |
448 | 0 | } |
449 | |
|
450 | 0 | Reference< XMergeableCell > xMerge( xCell, UNO_QUERY ); |
451 | 0 | if( xMerge.is() ) |
452 | 0 | { |
453 | 0 | bIsMerged = xMerge->isMerged(); |
454 | 0 | nRowSpan = xMerge->getRowSpan(); |
455 | 0 | nColSpan = xMerge->getColumnSpan(); |
456 | 0 | } |
457 | 0 | SAL_WARN_IF( (nRowSpan < 1) || (nColSpan < 1), "xmloff", "xmloff::XMLTableExport::ExportCell(), illegal row or col span < 1?" ); |
458 | 0 | } |
459 | 0 | catch (const Exception&) |
460 | 0 | { |
461 | 0 | TOOLS_WARN_EXCEPTION("xmloff.table", "exception while exporting a table cell"); |
462 | 0 | } |
463 | | |
464 | | // table:number-columns-repeated |
465 | | // todo |
466 | | |
467 | | // table:number-columns-spanned |
468 | 0 | if( nColSpan > 1 ) |
469 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, OUString::number( nColSpan ) ); |
470 | | |
471 | | // table:number-rows-spanned |
472 | 0 | if( nRowSpan > 1 ) |
473 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, OUString::number( nRowSpan ) ); |
474 | | |
475 | | // <table:table-cell> or <table:covered-table-cell> |
476 | 0 | SvXMLElementExport tableCellElement( mrExport, XML_NAMESPACE_TABLE, bIsMerged ? XML_COVERED_TABLE_CELL : XML_TABLE_CELL, true, true ); |
477 | | |
478 | | // export cells text content |
479 | 0 | ImpExportText( xCell ); |
480 | 0 | } |
481 | | |
482 | | // ODF export of the text contents of a table cell. |
483 | | // Remarks: Up to now we only export text contents! |
484 | | // TODO: Check against nested tables... |
485 | | |
486 | | void XMLTableExport::ImpExportText( const Reference< XCell >& xCell ) |
487 | 0 | { |
488 | 0 | Reference< XText > xText( xCell, UNO_QUERY ); |
489 | 0 | if( xText.is() && !xText->getString().isEmpty()) |
490 | 0 | mrExport.GetTextParagraphExport()->exportText( xText ); |
491 | 0 | } |
492 | | |
493 | | void XMLTableExport::exportTableStyles() |
494 | 45 | { |
495 | 45 | if( !mbExportTables ) |
496 | 0 | return; |
497 | | |
498 | 45 | rtl::Reference<XMLStyleExport> aStEx; |
499 | 45 | OUString sCellStyleName; |
500 | 45 | if (mbWriter) |
501 | 0 | { |
502 | 0 | sCellStyleName = "CellStyles"; |
503 | 0 | aStEx.set(new XMLCellStyleExport(mrExport)); |
504 | 0 | } |
505 | 45 | else |
506 | 45 | { |
507 | | // write graphic family styles |
508 | 45 | sCellStyleName = "cell"; |
509 | 45 | aStEx.set(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get())); |
510 | 45 | } |
511 | | |
512 | 45 | aStEx->exportStyleFamily(sCellStyleName, XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME, mxCellExportPropertySetMapper, true, XmlStyleFamily::TABLE_CELL); |
513 | | |
514 | 45 | exportTableTemplates(); |
515 | 45 | } |
516 | | |
517 | | // Export the collected automatic styles |
518 | | |
519 | | void XMLTableExport::exportAutoStyles() |
520 | 45 | { |
521 | 45 | if( !mbExportTables ) |
522 | 0 | return; |
523 | | |
524 | 45 | mrExport.GetAutoStylePool()->exportXML( XmlStyleFamily::TABLE_COLUMN ); |
525 | 45 | mrExport.GetAutoStylePool()->exportXML( XmlStyleFamily::TABLE_ROW ); |
526 | 45 | mrExport.GetAutoStylePool()->exportXML( XmlStyleFamily::TABLE_CELL ); |
527 | 45 | } |
528 | | |
529 | | const TableStyleElement* getTableStyleMap() |
530 | 0 | { |
531 | 0 | static constexpr struct TableStyleElement gTableStyleElements[] = |
532 | 0 | { |
533 | 0 | { XML_FIRST_ROW, u"first-row"_ustr }, |
534 | 0 | { XML_LAST_ROW, u"last-row"_ustr }, |
535 | 0 | { XML_FIRST_COLUMN, u"first-column"_ustr }, |
536 | 0 | { XML_LAST_COLUMN, u"last-column"_ustr }, |
537 | 0 | { XML_BODY, u"body"_ustr }, |
538 | 0 | { XML_EVEN_ROWS, u"even-rows"_ustr }, |
539 | 0 | { XML_ODD_ROWS, u"odd-rows"_ustr }, |
540 | 0 | { XML_EVEN_COLUMNS, u"even-columns"_ustr }, |
541 | 0 | { XML_ODD_COLUMNS, u"odd-columns"_ustr }, |
542 | 0 | { XML_BACKGROUND, u"background"_ustr }, |
543 | 0 | { XML_TOKEN_END, EMPTY_OUSTRING } |
544 | 0 | }; |
545 | |
|
546 | 0 | return &gTableStyleElements[0]; |
547 | 0 | } |
548 | | |
549 | | const TableStyleElement* getWriterSpecificTableStyleMap() |
550 | 0 | { |
551 | 0 | static constexpr struct TableStyleElement gWriterSpecificTableStyleElements[] = |
552 | 0 | { |
553 | 0 | { XML_FIRST_ROW_EVEN_COLUMN, u"first-row-even-column"_ustr }, |
554 | 0 | { XML_LAST_ROW_EVEN_COLUMN, u"last-row-even-column"_ustr }, |
555 | 0 | { XML_FIRST_ROW_END_COLUMN, u"first-row-end-column"_ustr }, |
556 | 0 | { XML_FIRST_ROW_START_COLUMN, u"first-row-start-column"_ustr }, |
557 | 0 | { XML_LAST_ROW_END_COLUMN, u"last-row-end-column"_ustr }, |
558 | 0 | { XML_LAST_ROW_START_COLUMN, u"last-row-start-column"_ustr }, |
559 | 0 | { XML_TOKEN_END, EMPTY_OUSTRING } |
560 | 0 | }; |
561 | |
|
562 | 0 | return &gWriterSpecificTableStyleElements[0]; |
563 | 0 | } |
564 | | |
565 | | static const TableStyleElement* getWriterSpecificTableStyleAttributes() |
566 | 0 | { |
567 | 0 | static constexpr struct TableStyleElement gWriterSpecifitTableStyleAttributes[] = |
568 | 0 | { |
569 | 0 | { XML_FIRST_ROW_END_COLUMN, u"FirstRowEndColumn"_ustr }, |
570 | 0 | { XML_FIRST_ROW_START_COLUMN, u"FirstRowStartColumn"_ustr }, |
571 | 0 | { XML_LAST_ROW_END_COLUMN, u"LastRowEndColumn"_ustr }, |
572 | 0 | { XML_LAST_ROW_START_COLUMN, u"LastRowStartColumn"_ustr }, |
573 | 0 | { XML_TOKEN_END, EMPTY_OUSTRING } |
574 | 0 | }; |
575 | |
|
576 | 0 | return &gWriterSpecifitTableStyleAttributes[0]; |
577 | 0 | } |
578 | | |
579 | | void XMLTableExport::exportTableTemplates() |
580 | 45 | { |
581 | 45 | if( !mbExportTables ) |
582 | 0 | return; |
583 | | |
584 | 45 | try |
585 | 45 | { |
586 | 45 | Reference< XStyleFamiliesSupplier > xFamiliesSupp( mrExport.GetModel(), UNO_QUERY_THROW ); |
587 | 45 | Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); |
588 | 45 | OUString sFamilyName; |
589 | 45 | if (mbWriter) |
590 | 0 | sFamilyName = "TableStyles"; |
591 | 45 | else |
592 | 45 | sFamilyName = "table"; |
593 | | |
594 | 45 | Reference< XIndexAccess > xTableFamily( xFamilies->getByName( sFamilyName ), UNO_QUERY_THROW ); |
595 | | |
596 | 45 | for( sal_Int32 nIndex = 0; nIndex < xTableFamily->getCount(); nIndex++ ) try |
597 | 0 | { |
598 | 0 | SvtSaveOptions::ODFSaneDefaultVersion eVersion = mrExport.getSaneDefaultVersion(); |
599 | |
|
600 | 0 | Reference< XStyle > xTableStyle( xTableFamily->getByIndex( nIndex ), UNO_QUERY_THROW ); |
601 | 0 | Reference<XPropertySet> xTableStylePropSet( xTableStyle, UNO_QUERY_THROW ); |
602 | 0 | bool bPhysical = false; |
603 | |
|
604 | 0 | try |
605 | 0 | { |
606 | 0 | xTableStylePropSet->getPropertyValue(u"IsPhysical"_ustr) >>= bPhysical; |
607 | 0 | } |
608 | 0 | catch(const Exception&) |
609 | 0 | { |
610 | 0 | } |
611 | |
|
612 | 0 | if (!xTableStyle->isInUse() && !bPhysical) |
613 | 0 | continue; |
614 | | |
615 | 0 | const TableStyleElement* pElements; |
616 | 0 | if (mbWriter) |
617 | 0 | { |
618 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, xTableStyle->getName()); |
619 | 0 | pElements = getWriterSpecificTableStyleAttributes(); |
620 | 0 | while(pElements->meElement != XML_TOKEN_END) |
621 | 0 | { |
622 | 0 | try |
623 | 0 | { |
624 | 0 | OUString sVal; |
625 | 0 | xTableStylePropSet->getPropertyValue(pElements->msStyleName) >>= sVal; |
626 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, pElements->meElement, sVal); |
627 | 0 | } |
628 | 0 | catch(const Exception&) |
629 | 0 | { |
630 | 0 | TOOLS_WARN_EXCEPTION("xmloff", "XMLTableExport::exportTableTemplates(), export Writer specific attributes, exception caught!"); |
631 | 0 | } |
632 | 0 | pElements++; |
633 | 0 | } |
634 | 0 | } |
635 | 0 | else |
636 | 0 | { |
637 | | // checks if any of the extended version of ODF are set |
638 | 0 | if (eVersion == SvtSaveOptions::ODFSVER_012_EXT_COMPAT) |
639 | 0 | { |
640 | | // tdf#106780 historically this wrong attribute was used |
641 | | // for the name; write it if extended because LO < 5.3 can |
642 | | // read only text:style-name, not the correct table:name |
643 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TEXT, XML_STYLE_NAME, xTableStyle->getName()); |
644 | 0 | } |
645 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_NAME, xTableStyle->getName()); |
646 | 0 | } |
647 | | |
648 | 0 | SvXMLElementExport tableTemplate( mrExport, XML_NAMESPACE_TABLE, XML_TABLE_TEMPLATE, true, true ); |
649 | |
|
650 | 0 | Reference< XNameAccess > xStyleNames( xTableStyle, UNO_QUERY_THROW ); |
651 | 0 | pElements = getTableStyleMap(); |
652 | 0 | while( pElements->meElement != XML_TOKEN_END ) |
653 | 0 | { |
654 | 0 | try |
655 | 0 | { |
656 | 0 | Reference< XStyle > xStyle( xStyleNames->getByName( pElements->msStyleName ), UNO_QUERY ); |
657 | 0 | if( xStyle.is() ) |
658 | 0 | { |
659 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, GetExport().EncodeStyleName( xStyle->getName() ) ); |
660 | 0 | SvXMLElementExport element( mrExport, XML_NAMESPACE_TABLE, pElements->meElement, true, true ); |
661 | 0 | } |
662 | 0 | } |
663 | 0 | catch(const Exception&) |
664 | 0 | { |
665 | 0 | TOOLS_WARN_EXCEPTION("xmloff.table", ""); |
666 | 0 | } |
667 | | |
668 | 0 | pElements++; |
669 | 0 | } |
670 | | |
671 | 0 | if (mbWriter && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0)) |
672 | 0 | { |
673 | 0 | pElements = getWriterSpecificTableStyleMap(); |
674 | 0 | while(pElements->meElement != XML_TOKEN_END) |
675 | 0 | { |
676 | 0 | try |
677 | 0 | { |
678 | 0 | Reference<XStyle> xStyle(xStyleNames->getByName(pElements->msStyleName), UNO_QUERY); |
679 | 0 | if(xStyle.is()) |
680 | 0 | { |
681 | 0 | mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_STYLE_NAME, GetExport().EncodeStyleName(xStyle->getName())); |
682 | 0 | SvXMLElementExport element(mrExport, XML_NAMESPACE_LO_EXT, pElements->meElement, true, true); |
683 | 0 | } |
684 | 0 | } |
685 | 0 | catch(const Exception&) |
686 | 0 | { |
687 | 0 | TOOLS_WARN_EXCEPTION("xmloff", "XMLTableExport::exportTableTemplates(), export Writer specific styles, exception caught!"); |
688 | 0 | } |
689 | 0 | pElements++; |
690 | 0 | } |
691 | 0 | } |
692 | 0 | } |
693 | 0 | catch(const Exception&) |
694 | 0 | { |
695 | 0 | TOOLS_WARN_EXCEPTION("xmloff", "XMLTableExport::exportTableDesigns(), exception caught while exporting a table design!"); |
696 | 0 | } |
697 | 45 | } |
698 | 45 | catch(const Exception&) |
699 | 45 | { |
700 | 0 | TOOLS_WARN_EXCEPTION("xmloff", "XMLTableExport::exportTableDesigns()"); |
701 | 0 | } |
702 | 45 | } |
703 | | |
704 | | void XMLCellStyleExport::exportStyleContent(const Reference<XStyle>& /*rStyle*/) |
705 | 0 | { |
706 | 0 | } |
707 | | |
708 | | void XMLCellStyleExport::exportStyleAttributes(const Reference<XStyle>& rStyle) |
709 | 0 | { |
710 | 0 | Reference<XPropertySet> xPropSet(rStyle, UNO_QUERY); |
711 | 0 | if (!xPropSet.is()) |
712 | 0 | return; |
713 | | |
714 | 0 | Reference<XPropertySetInfo> xPropSetInfo(xPropSet->getPropertySetInfo()); |
715 | 0 | static constexpr OUString sNumberFormat(u"NumberFormat"_ustr); |
716 | 0 | if (xPropSetInfo->hasPropertyByName(sNumberFormat)) |
717 | 0 | { |
718 | 0 | Reference<XPropertyState> xPropState(xPropSet, UNO_QUERY); |
719 | 0 | if (xPropState.is() && (PropertyState_DIRECT_VALUE == |
720 | 0 | xPropState->getPropertyState(sNumberFormat))) |
721 | 0 | { |
722 | 0 | sal_Int32 nNumberFormat = 0; |
723 | 0 | if (xPropSet->getPropertyValue(sNumberFormat) >>= nNumberFormat) |
724 | 0 | GetExport().AddAttribute(XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, |
725 | 0 | GetExport().getDataStyleName(nNumberFormat)); |
726 | 0 | } |
727 | 0 | } |
728 | 0 | } |
729 | | |
730 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |