Line data Source code
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 : #include <boost/optional.hpp>
20 : #include <DomainMapperTableManager.hxx>
21 : #include <BorderHandler.hxx>
22 : #include <CellColorHandler.hxx>
23 : #include <CellMarginHandler.hxx>
24 : #include <ConversionHelper.hxx>
25 : #include <MeasureHandler.hxx>
26 : #include <TDefTableHandler.hxx>
27 : #include <com/sun/star/text/HoriOrientation.hpp>
28 : #include <com/sun/star/text/SizeType.hpp>
29 : #include <com/sun/star/text/TableColumnSeparator.hpp>
30 : #include <com/sun/star/text/VertOrientation.hpp>
31 : #include <com/sun/star/text/WritingMode2.hpp>
32 : #include <o3tl/numeric.hxx>
33 : #include <ooxml/resourceids.hxx>
34 : #include <DomainMapper.hxx>
35 : #include <rtl/math.hxx>
36 :
37 : namespace writerfilter {
38 : namespace dmapper {
39 :
40 : using namespace ::com::sun::star;
41 : using namespace ::std;
42 :
43 4834 : DomainMapperTableManager::DomainMapperTableManager() :
44 : m_nRow(0),
45 : m_nCell(),
46 : m_nGridSpan(1),
47 : m_nGridBefore(0),
48 : m_nGridAfter(0),
49 : m_nCellBorderIndex(0),
50 : m_nHeaderRepeat(0),
51 : m_nTableWidth(0),
52 : m_bIsInShape(false),
53 : m_aTmpPosition(),
54 : m_aTmpTableProperties(),
55 : m_bPushCurrentWidth(false),
56 : m_bRowSizeTypeInserted(false),
57 : m_bHasBtlrCell(false),
58 : m_bTableSizeTypeInserted(false),
59 : m_nLayoutType(0),
60 : m_nMaxFixedWidth(0),
61 4834 : m_pTablePropsHandler(new TablePropertiesHandler())
62 : {
63 4834 : m_pTablePropsHandler->SetTableManager( this );
64 4834 : }
65 :
66 :
67 14502 : DomainMapperTableManager::~DomainMapperTableManager()
68 : {
69 4834 : if ( m_pTablePropsHandler )
70 4834 : delete m_pTablePropsHandler, m_pTablePropsHandler = nullptr;
71 9668 : }
72 :
73 394081 : bool DomainMapperTableManager::attribute(Id nName, Value& rValue)
74 : {
75 394081 : bool bRet = true;
76 :
77 394081 : switch (nName)
78 : {
79 : case NS_ooxml::LN_CT_TblLook_val:
80 : {
81 2583 : TablePropertyMapPtr pPropMap(new TablePropertyMap());
82 2583 : pPropMap->Insert(PROP_TBL_LOOK, uno::makeAny<sal_Int32>(rValue.getInt()));
83 2583 : insertTableProps(pPropMap);
84 2583 : m_aTableLook["val"] = uno::makeAny<sal_Int32>(rValue.getInt());
85 : }
86 2583 : break;
87 : case NS_ooxml::LN_CT_TblLook_noVBand:
88 2140 : m_aTableLook["noVBand"] = uno::makeAny<sal_Int32>(rValue.getInt());
89 2140 : break;
90 : case NS_ooxml::LN_CT_TblLook_noHBand:
91 2140 : m_aTableLook["noHBand"] = uno::makeAny<sal_Int32>(rValue.getInt());
92 2140 : break;
93 : case NS_ooxml::LN_CT_TblLook_lastColumn:
94 2140 : m_aTableLook["lastColumn"] = uno::makeAny<sal_Int32>(rValue.getInt());
95 2140 : break;
96 : case NS_ooxml::LN_CT_TblLook_lastRow:
97 2140 : m_aTableLook["lastRow"] = uno::makeAny<sal_Int32>(rValue.getInt());
98 2140 : break;
99 : case NS_ooxml::LN_CT_TblLook_firstColumn:
100 2140 : m_aTableLook["firstColumn"] = uno::makeAny<sal_Int32>(rValue.getInt());
101 2140 : break;
102 : case NS_ooxml::LN_CT_TblLook_firstRow:
103 2140 : m_aTableLook["firstRow"] = uno::makeAny<sal_Int32>(rValue.getInt());
104 2140 : break;
105 : default:
106 378658 : bRet = false;
107 : }
108 :
109 394081 : return bRet;
110 : }
111 :
112 2583 : void DomainMapperTableManager::finishTableLook()
113 : {
114 2583 : TablePropertyMapPtr pPropMap(new TablePropertyMap());
115 2583 : pPropMap->Insert(META_PROP_TABLE_LOOK, uno::makeAny(m_aTableLook.getAsConstPropertyValueList()));
116 2583 : m_aTableLook.clear();
117 2583 : insertTableProps(pPropMap);
118 2583 : }
119 :
120 487564 : bool DomainMapperTableManager::sprm(Sprm & rSprm)
121 : {
122 : #ifdef DEBUG_WRITERFILTER
123 : TagLogger::getInstance().startElement("tablemanager.sprm");
124 : string sSprm = rSprm.toString();
125 : TagLogger::getInstance().chars(sSprm);
126 : TagLogger::getInstance().endElement();
127 : #endif
128 487564 : bool bRet = TableManager::sprm(rSprm);
129 487564 : if( !bRet )
130 : {
131 435197 : bRet = m_pTablePropsHandler->sprm( rSprm );
132 : }
133 :
134 487564 : if ( !bRet )
135 : {
136 415107 : bRet = true;
137 415107 : sal_uInt32 nSprmId = rSprm.getId();
138 415107 : Value::Pointer_t pValue = rSprm.getValue();
139 415107 : sal_Int32 nIntValue = ((pValue.get() != nullptr) ? pValue->getInt() : 0);
140 415107 : switch ( nSprmId )
141 : {
142 : case NS_ooxml::LN_CT_TblPrBase_tblW:
143 : case NS_ooxml::LN_CT_TblPrBase_tblInd:
144 : {
145 : //contains unit and value
146 2944 : writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
147 2944 : if( pProperties.get())
148 : {
149 2944 : MeasureHandlerPtr pMeasureHandler( new MeasureHandler );
150 2944 : pProperties->resolve(*pMeasureHandler);
151 5888 : TablePropertyMapPtr pPropMap( new TablePropertyMap );
152 2944 : if (nSprmId == sal_uInt32(NS_ooxml::LN_CT_TblPrBase_tblInd))
153 : {
154 0 : pPropMap->setValue( TablePropertyMap::LEFT_MARGIN, pMeasureHandler->getMeasureValue() );
155 : }
156 : else
157 : {
158 2944 : m_nTableWidth = pMeasureHandler->getMeasureValue();
159 2944 : if( m_nTableWidth )
160 : {
161 1969 : pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::FIX );
162 1969 : pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth );
163 : }
164 975 : else if( sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_pct )
165 : {
166 171 : sal_Int32 nPercent = pMeasureHandler->getValue() / 50;
167 171 : if(nPercent > 100)
168 1 : nPercent = 100;
169 171 : pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE );
170 171 : pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, nPercent );
171 : }
172 804 : else if( sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_auto )
173 : {
174 : /*
175 : This attribute specifies the width type of table. This is used as part of the table layout
176 : algorithm specified by the tblLayout element.(See 17.4.64 and 17.4.65 of the ISO/IEC 29500-1:2011.)
177 : If this value is 'auto', the table layout has to use the preferred widths on the table items to generate
178 : the final sizing of the table, but then must use the contents of each cell to determine final column widths.
179 : (See 17.18.87 of the ISO/IEC 29500-1:2011.)
180 : */
181 801 : bool bFixed = true;
182 801 : sal_Int32 nRowFixedWidth = 0;
183 801 : IntVectorPtr pCellWidths = getCurrentCellWidths();
184 : // Step 1. Check whether all cells have fixed widths in the given row of table.
185 2877 : for (std::vector<sal_Int32>::const_iterator aValIter = pCellWidths->begin(); aValIter != pCellWidths->end(); ++aValIter)
186 : {
187 2108 : if (*aValIter == -1)
188 : {
189 32 : bFixed = false;
190 32 : break;
191 : }
192 : // Sum the width of cells to find the total width of given row
193 2076 : nRowFixedWidth += (*aValIter);
194 : }
195 :
196 : // Check whether the total width of given row is compared with the maximum value of rows (m_nMaxFixedWidth).
197 801 : if (!bFixed)
198 : {
199 : // Set the width type of table with 'Auto' and set the width value to 100(%)
200 32 : pPropMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::VARIABLE );
201 32 : pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, 0 );
202 801 : }
203 : }
204 2944 : m_bTableSizeTypeInserted = true;
205 : }
206 : #ifdef DEBUG_WRITERFILTER
207 : pPropMap->dumpXml();
208 : #endif
209 5888 : insertTableProps(pPropMap);
210 2944 : }
211 : }
212 2944 : break;
213 : case NS_ooxml::LN_CT_TrPrBase_tblHeader:
214 : // if nIntValue == 1 then the row is a repeated header line
215 : // to prevent later rows from increasing the repeating m_nHeaderRepeat is set to NULL when repeating stops
216 99 : if( nIntValue > 0 && m_nHeaderRepeat >= 0 )
217 : {
218 99 : ++m_nHeaderRepeat;
219 99 : TablePropertyMapPtr pPropMap( new TablePropertyMap );
220 99 : pPropMap->Insert( PROP_HEADER_ROW_COUNT, uno::makeAny( m_nHeaderRepeat ));
221 99 : insertTableProps(pPropMap);
222 : }
223 : else
224 0 : m_nHeaderRepeat = -1;
225 99 : if (nIntValue)
226 : {
227 : // Store the info that this is a header, we'll need that when we apply table styles.
228 99 : TablePropertyMapPtr pPropMap( new TablePropertyMap );
229 99 : pPropMap->Insert( PROP_TBL_HEADER, uno::makeAny(nIntValue));
230 99 : insertRowProps(pPropMap);
231 : }
232 99 : break;
233 : case NS_ooxml::LN_CT_TblPrBase_tblStyle: //table style name
234 : {
235 1412 : m_sTableStyleName = pValue->getString();
236 1412 : TablePropertyMapPtr pPropMap( new TablePropertyMap );
237 1412 : pPropMap->Insert( META_PROP_TABLE_STYLE_NAME, uno::makeAny( m_sTableStyleName ));
238 1412 : insertTableProps(pPropMap);
239 : }
240 1412 : break;
241 : case NS_ooxml::LN_CT_TblGridBase_gridCol:
242 : {
243 8925 : if (nIntValue == -1)
244 135 : getCurrentGrid()->clear();
245 : else
246 8790 : getCurrentGrid()->push_back( ConversionHelper::convertTwipToMM100( nIntValue ) );
247 : }
248 8925 : break;
249 : case NS_ooxml::LN_CT_TcPrBase_vMerge : //vertical merge
250 : {
251 : // values can be: LN_Value_ST_Merge_restart, LN_Value_ST_Merge_continue, in reality the second one is a 0
252 145 : TablePropertyMapPtr pMergeProps( new TablePropertyMap );
253 145 : pMergeProps->Insert( PROP_VERTICAL_MERGE, uno::makeAny( bool( sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Merge_restart )) );
254 145 : cellProps( pMergeProps);
255 : }
256 145 : break;
257 : case NS_ooxml::LN_CT_TcPrBase_hMerge:
258 : {
259 : // values can be: LN_Value_ST_Merge_restart, LN_Value_ST_Merge_continue, in reality the second one is a 0
260 4 : TablePropertyMapPtr pMergeProps(new TablePropertyMap());
261 4 : pMergeProps->Insert(PROP_HORIZONTAL_MERGE, uno::makeAny(bool(sal::static_int_cast<Id>(nIntValue) == NS_ooxml::LN_Value_ST_Merge_restart)));
262 4 : cellProps(pMergeProps);
263 : }
264 4 : break;
265 : case NS_ooxml::LN_CT_TcPrBase_gridSpan: //number of grid positions spanned by this cell
266 : {
267 : #ifdef DEBUG_WRITERFILTER
268 : TagLogger::getInstance().startElement("tablemanager.GridSpan");
269 : TagLogger::getInstance().attribute("gridSpan", nIntValue);
270 : TagLogger::getInstance().endElement();
271 : #endif
272 290 : m_nGridSpan = nIntValue;
273 : }
274 290 : break;
275 : case NS_ooxml::LN_CT_TcPrBase_textDirection:
276 : {
277 178 : TablePropertyMapPtr pPropMap( new TablePropertyMap );
278 :
279 : // Remember the cell direction, so later in
280 : // DomainMapperTableHandler::endTableGetCellProperties() can we
281 : // handle the combination of the cell direction and paragraph
282 : // alignment as necessary.
283 178 : pPropMap->Insert(PROP_CELL_DIRECTION, uno::Any(sal_Int32(nIntValue)));
284 :
285 178 : bool bInsertCellProps = true;
286 178 : switch ( nIntValue )
287 : {
288 : case NS_ooxml::LN_Value_ST_TextDirection_tbRl:
289 : // Binary filter takes BiDirection into account ( but I have no idea about that here )
290 : // or even what it is. But... here's where to handle it if it becomes an issue
291 2 : pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( text::WritingMode2::TB_RL ));
292 : SAL_INFO( "writerfilter", "Have inserted textDirection " << nIntValue );
293 2 : break;
294 : case NS_ooxml::LN_Value_ST_TextDirection_btLr:
295 : {
296 : // We have to fake this text direction
297 32 : pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( text::WritingMode2::LR_TB ));
298 32 : pPropMap->Insert( PROP_CHAR_ROTATION, uno::makeAny( sal_Int16( 900 ) ));
299 : SAL_INFO( "writerfilter", "Have inserted textDirection " << nIntValue );
300 :
301 : // We're faking a text direction, so don't allow multiple lines.
302 32 : if (!getCellProps() || !getCellProps()->isSet(PROP_VERTICAL_MERGE))
303 : {
304 : // Though in case there will be a vertical merge, don't do this, it hides text that is supposed to be visible.
305 12 : m_bRowSizeTypeInserted = true;
306 : }
307 32 : m_bHasBtlrCell = true;
308 : }
309 32 : break;
310 : case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
311 0 : pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( text::WritingMode2::LR_TB ));
312 0 : break;
313 : case NS_ooxml::LN_Value_ST_TextDirection_tbRlV:
314 0 : pPropMap->Insert( PROP_FRM_DIRECTION, uno::makeAny( text::WritingMode2::TB_RL ));
315 0 : break;
316 : case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
317 : case NS_ooxml::LN_Value_ST_TextDirection_tbLrV:
318 : default:
319 : // Ignore - we can't handle these
320 144 : bInsertCellProps = false;
321 144 : break;
322 : }
323 178 : if ( bInsertCellProps )
324 34 : cellProps( pPropMap );
325 178 : break;
326 : }
327 : case NS_ooxml::LN_CT_TcPrBase_tcW:
328 : {
329 : // Contains unit and value, but unit is not interesting for
330 : // us, later we'll just distribute these values in a
331 : // 0..10000 scale.
332 7929 : writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
333 7929 : if( pProperties.get())
334 : {
335 7929 : MeasureHandlerPtr pMeasureHandler(new MeasureHandler());
336 7929 : pProperties->resolve(*pMeasureHandler);
337 7929 : if (sal::static_int_cast<Id>(pMeasureHandler->getUnit()) == NS_ooxml::LN_Value_ST_TblWidth_auto)
338 118 : getCurrentCellWidths()->push_back(sal_Int32(-1));
339 : else
340 7811 : getCurrentCellWidths()->push_back(pMeasureHandler->getMeasureValue());
341 7929 : if (getTableDepthDifference() > 0)
342 474 : m_bPushCurrentWidth = true;
343 7929 : }
344 : }
345 7929 : break;
346 : case NS_ooxml::LN_CT_TblPrBase_tblpPr:
347 : {
348 304 : writerfilter::Reference<Properties>::Pointer_t pProperties = rSprm.getProps();
349 : // Ignore <w:tblpPr> in shape text, those tables should be always non-floating ones.
350 304 : if (!m_bIsInShape && pProperties.get())
351 : {
352 269 : TablePositionHandlerPtr pHandler = m_aTmpPosition.back();
353 269 : if ( !pHandler )
354 : {
355 269 : m_aTmpPosition.pop_back();
356 269 : pHandler.reset( new TablePositionHandler );
357 269 : m_aTmpPosition.push_back( pHandler );
358 : }
359 269 : pProperties->resolve(*m_aTmpPosition.back());
360 304 : }
361 : }
362 304 : break;
363 : case NS_ooxml::LN_CT_TrPrBase_gridBefore:
364 0 : m_nGridBefore = nIntValue;
365 0 : break;
366 : case NS_ooxml::LN_CT_TrPrBase_gridAfter:
367 9 : m_nGridAfter = nIntValue;
368 9 : break;
369 : case NS_ooxml::LN_CT_TblPrBase_tblCaption:
370 : // To-Do: Not yet preserved
371 12 : break;
372 : case NS_ooxml::LN_CT_TblPrBase_tblDescription:
373 : // To-Do: Not yet preserved
374 0 : break;
375 : case NS_ooxml::LN_CT_TrPrBase_tblCellSpacing:
376 : // To-Do: Not yet preserved
377 80 : break;
378 : case NS_ooxml::LN_CT_TblPrBase_tblCellSpacing:
379 : // To-Do: Not yet preserved
380 105 : break;
381 : case NS_ooxml::LN_CT_TblPrBase_bidiVisual:
382 : {
383 96 : TablePropertyMapPtr pPropMap(new TablePropertyMap());
384 96 : pPropMap->Insert(PROP_WRITING_MODE, uno::makeAny(nIntValue ? text::WritingMode2::RL_TB : text::WritingMode2::LR_TB));
385 96 : insertTableProps(pPropMap);
386 96 : break;
387 : }
388 : default:
389 392575 : bRet = false;
390 :
391 : #ifdef DEBUG_WRITERFILTER
392 : TagLogger::getInstance().element("unhandled");
393 : #endif
394 415107 : }
395 : }
396 487564 : return bRet;
397 : }
398 :
399 14881 : std::shared_ptr< vector<sal_Int32> > DomainMapperTableManager::getCurrentGrid( )
400 : {
401 14881 : return m_aTableGrid.back( );
402 : }
403 :
404 11321 : std::shared_ptr< vector< sal_Int32 > > DomainMapperTableManager::getCurrentSpans( )
405 : {
406 11321 : return m_aGridSpans.back( );
407 : }
408 :
409 11708 : std::shared_ptr< vector< sal_Int32 > > DomainMapperTableManager::getCurrentCellWidths( )
410 : {
411 11708 : return m_aCellWidths.back( );
412 : }
413 :
414 5437 : const uno::Sequence<beans::PropertyValue> DomainMapperTableManager::getCurrentTablePosition( )
415 : {
416 5437 : if ( !m_aTablePositions.empty( ) && m_aTablePositions.back() )
417 43 : return m_aTablePositions.back( )->getTablePosition();
418 : else
419 5394 : return uno::Sequence< beans::PropertyValue >( 0 );
420 : }
421 :
422 665 : TablePositionHandler* DomainMapperTableManager::getCurrentTableRealPosition()
423 : {
424 665 : if ( !m_aTablePositions.empty( ) && m_aTablePositions.back() )
425 86 : return (m_aTablePositions.back( )).get();
426 : else
427 579 : return nullptr;
428 : }
429 :
430 1408 : void DomainMapperTableManager::setIsInShape(bool bIsInShape)
431 : {
432 1408 : m_bIsInShape = bIsInShape;
433 1408 : }
434 :
435 5471 : void DomainMapperTableManager::startLevel( )
436 : {
437 5471 : TableManager::startLevel( );
438 :
439 : // If requested, pop the value that was pushed too early.
440 5471 : boost::optional<sal_Int32> oCurrentWidth;
441 5471 : if (m_bPushCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty())
442 : {
443 450 : oCurrentWidth.reset(m_aCellWidths.back()->back());
444 450 : m_aCellWidths.back()->pop_back();
445 : }
446 :
447 10942 : IntVectorPtr pNewGrid( new vector<sal_Int32> );
448 10942 : IntVectorPtr pNewSpans( new vector<sal_Int32> );
449 10942 : IntVectorPtr pNewCellWidths( new vector<sal_Int32> );
450 10942 : TablePositionHandlerPtr pNewPositionHandler;
451 5471 : m_aTableGrid.push_back( pNewGrid );
452 5471 : m_aGridSpans.push_back( pNewSpans );
453 5471 : m_aCellWidths.push_back( pNewCellWidths );
454 5471 : m_aTablePositions.push_back( pNewPositionHandler );
455 :
456 10942 : TablePositionHandlerPtr pTmpPosition;
457 10942 : TablePropertyMapPtr pTmpProperties( new TablePropertyMap( ) );
458 5471 : m_aTmpPosition.push_back( pTmpPosition );
459 5471 : m_aTmpTableProperties.push_back( pTmpProperties );
460 5471 : m_nCell.push_back( 0 );
461 5471 : m_nTableWidth = 0;
462 5471 : m_nLayoutType = 0;
463 5471 : m_nMaxFixedWidth = 0;
464 :
465 : // And push it back to the right level.
466 5471 : if (oCurrentWidth)
467 5921 : m_aCellWidths.back()->push_back(*oCurrentWidth);
468 5471 : }
469 :
470 5439 : void DomainMapperTableManager::endLevel( )
471 : {
472 5439 : m_aTableGrid.pop_back( );
473 5439 : m_aGridSpans.pop_back( );
474 :
475 : // Do the same trick as in startLevel(): pop the value that was pushed too early.
476 5439 : boost::optional<sal_Int32> oCurrentWidth;
477 5439 : if (m_bPushCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty())
478 43 : oCurrentWidth.reset(m_aCellWidths.back()->back());
479 5439 : m_aCellWidths.pop_back( );
480 : // And push it back to the right level.
481 5439 : if (oCurrentWidth && !m_aCellWidths.empty() && !m_aCellWidths.back()->empty())
482 14 : m_aCellWidths.back()->push_back(*oCurrentWidth);
483 :
484 5439 : m_nCell.pop_back( );
485 5439 : m_nTableWidth = 0;
486 5439 : m_nLayoutType = 0;
487 5439 : m_nMaxFixedWidth = 0;
488 :
489 5439 : m_aTmpPosition.pop_back( );
490 5439 : m_aTmpTableProperties.pop_back( );
491 :
492 5439 : TableManager::endLevel( );
493 : #ifdef DEBUG_WRITERFILTER
494 : TagLogger::getInstance().startElement("dmappertablemanager.endLevel");
495 : PropertyMapPtr pProps = getTableProps();
496 : if (pProps.get() != nullptr)
497 : getTableProps()->dumpXml();
498 :
499 : TagLogger::getInstance().endElement();
500 : #endif
501 :
502 : // Pop back the table position after endLevel as it's used
503 : // in the endTable method called in endLevel.
504 5439 : m_aTablePositions.pop_back();
505 5439 : }
506 :
507 8343 : void DomainMapperTableManager::endOfCellAction()
508 : {
509 : #ifdef DEBUG_WRITERFILTER
510 : TagLogger::getInstance().element("endOFCellAction");
511 : #endif
512 :
513 8343 : getCurrentSpans()->push_back(m_nGridSpan);
514 8343 : m_nGridSpan = 1;
515 8343 : ++m_nCell.back( );
516 8343 : }
517 :
518 2978 : void DomainMapperTableManager::endOfRowAction()
519 : {
520 : #ifdef DEBUG_WRITERFILTER
521 : TagLogger::getInstance().startElement("endOfRowAction");
522 : #endif
523 :
524 : // Compare the table position with the previous ones. We may need to split
525 : // into two tables if those are different. We surely don't want to do anything
526 : // if we don't have any row yet.
527 2978 : TablePositionHandlerPtr pTmpPosition = m_aTmpPosition.back();
528 5956 : TablePropertyMapPtr pTmpTableProperties = m_aTmpTableProperties.back( );
529 5956 : TablePositionHandlerPtr pCurrentPosition = m_aTablePositions.back();
530 6182 : bool bSamePosition = ( pTmpPosition == pCurrentPosition ) ||
531 3517 : ( pTmpPosition && pCurrentPosition && *pTmpPosition == *pCurrentPosition );
532 2978 : if ( !bSamePosition && m_nRow > 0 )
533 : {
534 : // Save the grid infos to have them survive the end/start level
535 5 : IntVectorPtr pTmpTableGrid = m_aTableGrid.back();
536 10 : IntVectorPtr pTmpGridSpans = m_aGridSpans.back();
537 10 : IntVectorPtr pTmpCellWidths = m_aCellWidths.back();
538 :
539 : // endLevel and startLevel are taking care of the non finished row
540 : // to carry it over to the next table
541 5 : setKeepUnfinishedRow( true );
542 5 : endLevel();
543 5 : setKeepUnfinishedRow( false );
544 5 : startLevel();
545 :
546 5 : m_aTableGrid.pop_back();
547 5 : m_aGridSpans.pop_back();
548 5 : m_aCellWidths.pop_back();
549 5 : m_aTableGrid.push_back(pTmpTableGrid);
550 5 : m_aGridSpans.push_back(pTmpGridSpans);
551 10 : m_aCellWidths.push_back(pTmpCellWidths);
552 : }
553 :
554 : // Push the tmp position now that we compared it
555 2978 : m_aTablePositions.pop_back();
556 2978 : m_aTablePositions.push_back( pTmpPosition );
557 2978 : m_aTmpPosition.back().reset( );
558 :
559 :
560 5956 : IntVectorPtr pTableGrid = getCurrentGrid( );
561 5956 : IntVectorPtr pCellWidths = getCurrentCellWidths( );
562 2978 : if(!m_nTableWidth && pTableGrid->size())
563 : {
564 985 : ::std::vector<sal_Int32>::const_iterator aCellIter = pTableGrid->begin();
565 :
566 : #ifdef DEBUG_WRITERFILTER
567 : TagLogger::getInstance().startElement("tableWidth");
568 : #endif
569 :
570 4813 : while( aCellIter != pTableGrid->end() )
571 : {
572 : #ifdef DEBUG_WRITERFILTER
573 : TagLogger::getInstance().startElement("col");
574 : TagLogger::getInstance().attribute("width", *aCellIter);
575 : TagLogger::getInstance().endElement();
576 : #endif
577 :
578 2843 : m_nTableWidth += *aCellIter++;
579 : }
580 :
581 985 : if (m_nTableWidth > 0 && !m_bTableSizeTypeInserted)
582 : {
583 8 : TablePropertyMapPtr pPropMap( new TablePropertyMap );
584 8 : pPropMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth );
585 8 : insertTableProps(pPropMap);
586 : }
587 :
588 : #ifdef DEBUG_WRITERFILTER
589 : TagLogger::getInstance().endElement();
590 : #endif
591 : }
592 :
593 5956 : IntVectorPtr pCurrentSpans = getCurrentSpans( );
594 2978 : if( pCurrentSpans->size() < m_nCell.back( ) )
595 : {
596 : //fill missing elements with '1'
597 0 : pCurrentSpans->insert( pCurrentSpans->end( ), m_nCell.back( ) - pCurrentSpans->size(), 1 );
598 : }
599 :
600 : #ifdef DEBUG_WRITERFILTER
601 : TagLogger::getInstance().startElement("gridSpans");
602 : {
603 : ::std::vector<sal_Int32>::const_iterator aGridSpanIter = pCurrentSpans->begin();
604 : ::std::vector<sal_Int32>::const_iterator aGridSpanIterEnd = pCurrentSpans->end();
605 :
606 : while (aGridSpanIter != aGridSpanIterEnd)
607 : {
608 : TagLogger::getInstance().startElement("gridSpan");
609 : TagLogger::getInstance().attribute("span", *aGridSpanIter);
610 : TagLogger::getInstance().endElement();
611 :
612 : ++aGridSpanIter;
613 : }
614 : }
615 : TagLogger::getInstance().endElement();
616 : #endif
617 :
618 : //calculate number of used grids - it has to match the size of m_aTableGrid
619 2978 : size_t nGrids = 0;
620 2978 : ::std::vector<sal_Int32>::const_iterator aGridSpanIter = pCurrentSpans->begin();
621 11321 : for( ; aGridSpanIter != pCurrentSpans->end(); ++aGridSpanIter)
622 8343 : nGrids += *aGridSpanIter;
623 :
624 : // sj: the grid is having no units... they is containing only relative values.
625 : // a table with a grid of "1:2:1" looks identical as if the table is having
626 : // a grid of "20:40:20" and it doesn't have to do something with the tableWidth
627 : // -> so we have get the sum of each grid entry for the fullWidthRelative:
628 2978 : int nFullWidthRelative = 0;
629 11767 : for (size_t i = 0 ; i < (*pTableGrid.get()).size(); i++ )
630 8789 : nFullWidthRelative += (*pTableGrid.get())[ i ];
631 :
632 2978 : if( pTableGrid->size() == ( m_nGridBefore + nGrids + m_nGridAfter ) && m_nCell.back( ) > 0 )
633 : {
634 : /*
635 : * If table width property set earlier is smaller than the current table width,
636 : * then replace the TABLE_WIDTH property, set earlier.
637 : */
638 2911 : TablePropertyMapPtr propMap = m_aTmpTableProperties.back();
639 2911 : sal_Int32 nTableWidth(0);
640 2911 : sal_Int32 nTableWidthType(text::SizeType::VARIABLE);
641 2911 : propMap->getValue( TablePropertyMap::TABLE_WIDTH, nTableWidth );
642 2911 : propMap->getValue( TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType );
643 2911 : if ((nTableWidthType == text::SizeType::FIX) && (nTableWidth < m_nTableWidth))
644 : {
645 0 : propMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth );
646 : }
647 2911 : if (nTableWidthType == text::SizeType::VARIABLE )
648 : {
649 998 : if(nTableWidth > 100 || nTableWidth <= 0)
650 : {
651 829 : propMap->setValue( TablePropertyMap::TABLE_WIDTH, m_nTableWidth);
652 829 : propMap->setValue( TablePropertyMap::TABLE_WIDTH_TYPE, text::SizeType::FIX);
653 : }
654 : }
655 5822 : uno::Sequence< text::TableColumnSeparator > aSeparators( m_nCell.back( ) - 1 );
656 2911 : text::TableColumnSeparator* pSeparators = aSeparators.getArray();
657 2911 : sal_Int16 nLastRelPos = 0;
658 2911 : sal_uInt32 nBorderGridIndex = m_nGridBefore;
659 :
660 2911 : size_t nWidthsBound = m_nCell.back( ) - 1;
661 2911 : if (nWidthsBound)
662 : {
663 2524 : if (nFullWidthRelative == 0)
664 0 : throw o3tl::divide_by_zero();
665 :
666 2524 : ::std::vector< sal_Int32 >::const_iterator aSpansIter = pCurrentSpans->begin( );
667 7792 : for( size_t nBorder = 0; nBorder < nWidthsBound; ++nBorder )
668 : {
669 5268 : double fGridWidth = 0.;
670 10667 : for ( sal_Int32 nGridCount = *aSpansIter; nGridCount > 0; --nGridCount )
671 5399 : fGridWidth += (*pTableGrid.get())[nBorderGridIndex++];
672 :
673 5268 : sal_Int16 nRelPos = rtl::math::round((fGridWidth * 10000) / nFullWidthRelative);
674 :
675 5268 : pSeparators[nBorder].Position = nRelPos + nLastRelPos;
676 5268 : pSeparators[nBorder].IsVisible = sal_True;
677 5268 : nLastRelPos = nLastRelPos + nRelPos;
678 5268 : ++aSpansIter;
679 : }
680 : }
681 5822 : TablePropertyMapPtr pPropMap( new TablePropertyMap );
682 2911 : pPropMap->Insert( PROP_TABLE_COLUMN_SEPARATORS, uno::makeAny( aSeparators ) );
683 :
684 : #ifdef DEBUG_WRITERFILTER
685 : TagLogger::getInstance().startElement("rowProperties");
686 : pPropMap->dumpXml();
687 : TagLogger::getInstance().endElement();
688 : #endif
689 5822 : insertRowProps(pPropMap);
690 : }
691 138 : else if ( pCellWidths->size() > 0 &&
692 51 : ( m_nLayoutType == NS_ooxml::LN_Value_doc_ST_TblLayout_fixed
693 49 : || pCellWidths->size() == ( m_nGridBefore + nGrids + m_nGridAfter ) )
694 : )
695 : {
696 : // If we're here, then the number of cells does not equal to the amount
697 : // defined by the grid, even after taking care of
698 : // gridSpan/gridBefore/gridAfter. Handle this by ignoring the grid and
699 : // providing the separators based on the provided cell widths, as long
700 : // as we have a fixed layout;
701 : // On the other hand even if the layout is not fixed, but the cell widths
702 : // provided equal the total number of cells, and there are no after/before cells
703 : // then use the cell widths to calculate the column separators.
704 20 : uno::Sequence< text::TableColumnSeparator > aSeparators(pCellWidths->size() - 1);
705 20 : text::TableColumnSeparator* pSeparators = aSeparators.getArray();
706 20 : sal_Int16 nSum = 0;
707 20 : sal_uInt32 nPos = 0;
708 : // Avoid divide by zero (if there's no grid, position using cell widths).
709 20 : if( nFullWidthRelative == 0 )
710 2 : for (size_t i = 0; i < pCellWidths->size(); ++i)
711 1 : nFullWidthRelative += (*pCellWidths.get())[i];
712 :
713 20 : size_t nWidthsBound = pCellWidths->size() - 1;
714 20 : if (nWidthsBound)
715 : {
716 16 : if (nFullWidthRelative == 0)
717 0 : throw o3tl::divide_by_zero();
718 :
719 38 : for (size_t i = 0; i < nWidthsBound; ++i)
720 : {
721 22 : nSum += (*pCellWidths.get())[i];
722 22 : pSeparators[nPos].Position = (nSum * 10000) / nFullWidthRelative; // Relative position
723 22 : pSeparators[nPos].IsVisible = sal_True;
724 22 : nPos++;
725 : }
726 : }
727 :
728 40 : TablePropertyMapPtr pPropMap( new TablePropertyMap );
729 20 : pPropMap->Insert( PROP_TABLE_COLUMN_SEPARATORS, uno::makeAny( aSeparators ) );
730 : #ifdef DEBUG_WRITERFILTER
731 : TagLogger::getInstance().startElement("rowProperties");
732 : pPropMap->dumpXml();
733 : TagLogger::getInstance().endElement();
734 : #endif
735 40 : insertRowProps(pPropMap);
736 : }
737 :
738 : // Now that potentially opened table is closed, save the table properties
739 2978 : TableManager::insertTableProps( pTmpTableProperties );
740 :
741 2978 : m_aTmpTableProperties.pop_back();
742 5956 : TablePropertyMapPtr pEmptyTableProps( new TablePropertyMap() );
743 2978 : m_aTmpTableProperties.push_back( pEmptyTableProps );
744 :
745 2978 : ++m_nRow;
746 2978 : m_nCell.back( ) = 0;
747 2978 : m_nCellBorderIndex = 0;
748 2978 : getCurrentGrid()->clear();
749 2978 : pCurrentSpans->clear();
750 2978 : pCellWidths->clear();
751 :
752 2978 : m_nGridBefore = m_nGridAfter = 0;
753 2978 : m_bRowSizeTypeInserted = false;
754 2978 : m_bHasBtlrCell = false;
755 5956 : m_bTableSizeTypeInserted = false;
756 :
757 : #ifdef DEBUG_WRITERFILTER
758 : TagLogger::getInstance().endElement();
759 : #endif
760 2978 : }
761 :
762 5439 : void DomainMapperTableManager::clearData()
763 : {
764 5439 : m_nRow = m_nCellBorderIndex = m_nHeaderRepeat = m_nTableWidth = m_nLayoutType = 0;
765 5439 : m_sTableStyleName.clear();
766 5439 : m_pTableStyleTextProperies.reset();
767 5439 : }
768 :
769 : }}
770 :
771 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|