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 <DomainMapperTableHandler.hxx>
20 : #include <DomainMapper_Impl.hxx>
21 : #include <StyleSheetTable.hxx>
22 : #include <com/sun/star/beans/XPropertyState.hpp>
23 : #include <com/sun/star/container/XEnumerationAccess.hpp>
24 : #include <com/sun/star/table/TableBorderDistances.hpp>
25 : #include <com/sun/star/table/TableBorder.hpp>
26 : #include <com/sun/star/table/BorderLine2.hpp>
27 : #include <com/sun/star/table/BorderLineStyle.hpp>
28 : #include <com/sun/star/table/XCellRange.hpp>
29 : #include <com/sun/star/text/HoriOrientation.hpp>
30 : #include <com/sun/star/text/RelOrientation.hpp>
31 : #include <com/sun/star/text/SizeType.hpp>
32 : #include <com/sun/star/text/VertOrientation.hpp>
33 : #include <com/sun/star/text/XTextRangeCompare.hpp>
34 : #include <com/sun/star/style/ParagraphAdjust.hpp>
35 : #include <TablePositionHandler.hxx>
36 : #include <ConversionHelper.hxx>
37 : #include <util.hxx>
38 : #include <osl/diagnose.h>
39 : #include <comphelper/sequence.hxx>
40 :
41 : #ifdef DEBUG_WRITERFILTER
42 : #include <PropertyMapHelper.hxx>
43 : #include <rtl/ustring.hxx>
44 : #endif
45 :
46 : namespace writerfilter {
47 : namespace dmapper {
48 :
49 : using namespace ::com::sun::star;
50 : using namespace ::std;
51 :
52 : #define DEF_BORDER_DIST 190 //0,19cm
53 :
54 1984 : DomainMapperTableHandler::DomainMapperTableHandler(TextReference_t const& xText,
55 : DomainMapper_Impl& rDMapper_Impl)
56 : : m_xText(xText),
57 : m_rDMapper_Impl( rDMapper_Impl ),
58 : m_nCellIndex(0),
59 1984 : m_nRowIndex(0)
60 : {
61 1984 : }
62 :
63 3968 : DomainMapperTableHandler::~DomainMapperTableHandler()
64 : {
65 3968 : }
66 :
67 5439 : void DomainMapperTableHandler::startTable(unsigned int nRows,
68 : unsigned int /*nDepth*/,
69 : TablePropertyMapPtr pProps)
70 : {
71 5439 : m_aTableProperties = pProps;
72 5439 : m_pTableSeq = TableSequencePointer_t(new TableSequence_t(nRows));
73 5439 : m_nRowIndex = 0;
74 :
75 : #ifdef DEBUG_WRITERFILTER
76 : TagLogger::getInstance().startElement("tablehandler.table");
77 : TagLogger::getInstance().attribute("rows", nRows);
78 :
79 : if (pProps.get() != nullptr)
80 : pProps->dumpXml();
81 : #endif
82 5439 : }
83 :
84 :
85 :
86 449 : PropertyMapPtr lcl_SearchParentStyleSheetAndMergeProperties(const StyleSheetEntryPtr& rStyleSheet, StyleSheetTablePtr pStyleSheetTable)
87 : {
88 449 : PropertyMapPtr pRet;
89 :
90 449 : if (!rStyleSheet)
91 1 : return pRet;
92 :
93 448 : if(!rStyleSheet->sBaseStyleIdentifier.isEmpty())
94 : {
95 230 : const StyleSheetEntryPtr pParentStyleSheet = pStyleSheetTable->FindStyleSheetByISTD(rStyleSheet->sBaseStyleIdentifier);
96 : //a loop in the style hierarchy, bail out
97 230 : if (pParentStyleSheet == rStyleSheet)
98 1 : return pRet;
99 :
100 229 : pRet = lcl_SearchParentStyleSheetAndMergeProperties( pParentStyleSheet, pStyleSheetTable );
101 : }
102 : else
103 : {
104 218 : pRet.reset( new PropertyMap );
105 : }
106 :
107 447 : if (pRet)
108 : {
109 446 : pRet->InsertProps(rStyleSheet->pProperties);
110 : }
111 :
112 447 : return pRet;
113 : }
114 :
115 9063 : void lcl_mergeBorder( PropertyIds nId, PropertyMapPtr pOrig, PropertyMapPtr pDest )
116 : {
117 9063 : boost::optional<PropertyMap::Property> pOrigVal = pOrig->getProperty(nId);
118 :
119 9063 : if ( pOrigVal )
120 : {
121 6040 : pDest->Insert( nId, pOrigVal->second, false );
122 9063 : }
123 9063 : }
124 :
125 8343 : void lcl_computeCellBorders( PropertyMapPtr pTableBorders, PropertyMapPtr pCellProps,
126 : sal_Int32 nCell, sal_Int32 nRow, bool bIsEndCol, bool bIsEndRow )
127 : {
128 8343 : boost::optional<PropertyMap::Property> pVerticalVal = pCellProps->getProperty(META_PROP_VERTICAL_BORDER);
129 16686 : boost::optional<PropertyMap::Property> pHorizontalVal = pCellProps->getProperty(META_PROP_HORIZONTAL_BORDER);
130 :
131 : // Handle the vertical and horizontal borders
132 16686 : uno::Any aVertProp;
133 8343 : if ( !pVerticalVal)
134 : {
135 6295 : pVerticalVal = pTableBorders->getProperty(META_PROP_VERTICAL_BORDER);
136 6295 : if ( pVerticalVal )
137 4363 : aVertProp = pVerticalVal->second;
138 : }
139 : else
140 : {
141 2048 : aVertProp = pVerticalVal->second;
142 2048 : pCellProps->Erase( pVerticalVal->first );
143 : }
144 :
145 16686 : uno::Any aHorizProp;
146 8343 : if ( !pHorizontalVal )
147 : {
148 6036 : pHorizontalVal = pTableBorders->getProperty(META_PROP_HORIZONTAL_BORDER);
149 6036 : if ( pHorizontalVal )
150 4239 : aHorizProp = pHorizontalVal->second;
151 : }
152 : else
153 : {
154 2307 : aHorizProp = pHorizontalVal->second;
155 2307 : pCellProps->Erase( pHorizontalVal->first );
156 : }
157 :
158 8343 : if ( nCell == 0 )
159 : {
160 2975 : lcl_mergeBorder( PROP_LEFT_BORDER, pTableBorders, pCellProps );
161 2975 : if ( pVerticalVal )
162 2206 : pCellProps->Insert( PROP_RIGHT_BORDER, aVertProp, false );
163 : }
164 :
165 8343 : if ( bIsEndCol )
166 : {
167 2975 : lcl_mergeBorder( PROP_RIGHT_BORDER, pTableBorders, pCellProps );
168 2975 : if ( pVerticalVal )
169 2236 : pCellProps->Insert( PROP_LEFT_BORDER, aVertProp, false );
170 : }
171 :
172 8343 : if ( nCell > 0 && !bIsEndCol )
173 : {
174 2788 : if ( pVerticalVal )
175 : {
176 2203 : pCellProps->Insert( PROP_RIGHT_BORDER, aVertProp, false );
177 2203 : pCellProps->Insert( PROP_LEFT_BORDER, aVertProp, false );
178 : }
179 : }
180 :
181 8343 : if ( nRow == 0 )
182 : {
183 1502 : lcl_mergeBorder( PROP_TOP_BORDER, pTableBorders, pCellProps );
184 1502 : if ( pHorizontalVal )
185 811 : pCellProps->Insert( PROP_BOTTOM_BORDER, aHorizProp, false );
186 : }
187 :
188 8343 : if ( bIsEndRow )
189 : {
190 1611 : lcl_mergeBorder( PROP_BOTTOM_BORDER, pTableBorders, pCellProps );
191 1611 : if ( pHorizontalVal )
192 949 : pCellProps->Insert( PROP_TOP_BORDER, aHorizProp, false );
193 : }
194 :
195 8343 : if ( nRow > 0 && !bIsEndRow )
196 : {
197 5895 : if ( pHorizontalVal )
198 : {
199 5049 : pCellProps->Insert( PROP_TOP_BORDER, aHorizProp, false );
200 5049 : pCellProps->Insert( PROP_BOTTOM_BORDER, aHorizProp, false );
201 : }
202 8343 : }
203 8343 : }
204 :
205 : #ifdef DEBUG_WRITERFILTER
206 :
207 : void lcl_debug_BorderLine(table::BorderLine & rLine)
208 : {
209 : TagLogger::getInstance().startElement("BorderLine");
210 : TagLogger::getInstance().attribute("Color", rLine.Color);
211 : TagLogger::getInstance().attribute("InnerLineWidth", rLine.InnerLineWidth);
212 : TagLogger::getInstance().attribute("OuterLineWidth", rLine.OuterLineWidth);
213 : TagLogger::getInstance().attribute("LineDistance", rLine.LineDistance);
214 : TagLogger::getInstance().endElement();
215 : }
216 :
217 : void lcl_debug_TableBorder(table::TableBorder & rBorder)
218 : {
219 : TagLogger::getInstance().startElement("TableBorder");
220 : lcl_debug_BorderLine(rBorder.TopLine);
221 : TagLogger::getInstance().attribute("IsTopLineValid", sal_uInt32(rBorder.IsTopLineValid));
222 : lcl_debug_BorderLine(rBorder.BottomLine);
223 : TagLogger::getInstance().attribute("IsBottomLineValid", sal_uInt32(rBorder.IsBottomLineValid));
224 : lcl_debug_BorderLine(rBorder.LeftLine);
225 : TagLogger::getInstance().attribute("IsLeftLineValid", sal_uInt32(rBorder.IsLeftLineValid));
226 : lcl_debug_BorderLine(rBorder.RightLine);
227 : TagLogger::getInstance().attribute("IsRightLineValid", sal_uInt32(rBorder.IsRightLineValid));
228 : lcl_debug_BorderLine(rBorder.VerticalLine);
229 : TagLogger::getInstance().attribute("IsVerticalLineValid", sal_uInt32(rBorder.IsVerticalLineValid));
230 : lcl_debug_BorderLine(rBorder.HorizontalLine);
231 : TagLogger::getInstance().attribute("IsHorizontalLineValid", sal_uInt32(rBorder.IsHorizontalLineValid));
232 : TagLogger::getInstance().attribute("Distance", rBorder.Distance);
233 : TagLogger::getInstance().attribute("IsDistanceValid", sal_uInt32(rBorder.IsDistanceValid));
234 : TagLogger::getInstance().endElement();
235 : }
236 : #endif
237 :
238 5657 : struct TableInfo
239 : {
240 : sal_Int32 nLeftBorderDistance;
241 : sal_Int32 nRightBorderDistance;
242 : sal_Int32 nTopBorderDistance;
243 : sal_Int32 nBottomBorderDistance;
244 : sal_Int32 nTblLook;
245 : sal_Int32 nNestLevel;
246 : PropertyMapPtr pTableDefaults;
247 : PropertyMapPtr pTableBorders;
248 : TableStyleSheetEntry* pTableStyle;
249 : TablePropertyValues_t aTableProperties;
250 :
251 5657 : TableInfo()
252 : : nLeftBorderDistance(DEF_BORDER_DIST)
253 : , nRightBorderDistance(DEF_BORDER_DIST)
254 : , nTopBorderDistance(0)
255 : , nBottomBorderDistance(0)
256 : , nTblLook(0x4a0)
257 : , nNestLevel(0)
258 5657 : , pTableDefaults(new PropertyMap)
259 5657 : , pTableBorders(new PropertyMap)
260 16971 : , pTableStyle(nullptr)
261 : {
262 5657 : }
263 :
264 : };
265 :
266 : namespace
267 : {
268 :
269 4612 : bool lcl_extractTableBorderProperty(PropertyMapPtr pTableProperties, const PropertyIds nId, TableInfo& rInfo, table::BorderLine2& rLine)
270 : {
271 4612 : if (!pTableProperties)
272 8 : return false;
273 :
274 4604 : const boost::optional<PropertyMap::Property> aTblBorder = pTableProperties->getProperty(nId);
275 4604 : if( aTblBorder )
276 : {
277 2652 : OSL_VERIFY(aTblBorder->second >>= rLine);
278 :
279 2652 : rInfo.pTableBorders->Insert( nId, uno::makeAny( rLine ) );
280 2652 : rInfo.pTableDefaults->Erase( nId );
281 :
282 2652 : return true;
283 : }
284 :
285 1952 : return false;
286 : }
287 :
288 : }
289 :
290 370 : bool lcl_extractHoriOrient(std::vector<beans::PropertyValue>& rFrameProperties, sal_Int32& nHoriOrient)
291 : {
292 : // Shifts the frame left by the given value.
293 530 : for (size_t i = 0; i < rFrameProperties.size(); ++i)
294 : {
295 200 : if (rFrameProperties[i].Name == "HoriOrient")
296 : {
297 40 : nHoriOrient = rFrameProperties[i].Value.get<sal_Int32>();
298 40 : return true;
299 : }
300 : }
301 330 : return false;
302 : }
303 :
304 77 : void lcl_DecrementHoriOrientPosition(std::vector<beans::PropertyValue>& rFrameProperties, sal_Int32 nAmount)
305 : {
306 : // Shifts the frame left by the given value.
307 154 : for (size_t i = 0; i < rFrameProperties.size(); ++i)
308 : {
309 154 : beans::PropertyValue& rPropertyValue = rFrameProperties[i];
310 154 : if (rPropertyValue.Name == "HoriOrientPosition")
311 : {
312 77 : sal_Int32 nValue = rPropertyValue.Value.get<sal_Int32>();
313 77 : nValue -= nAmount;
314 77 : rPropertyValue.Value <<= nValue;
315 154 : return;
316 : }
317 : }
318 : }
319 :
320 5437 : TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo & rInfo, std::vector<beans::PropertyValue>& rFrameProperties)
321 : {
322 : // will receive the table style if any
323 5437 : TableStyleSheetEntry* pTableStyle = nullptr;
324 :
325 5437 : if( m_aTableProperties.get() )
326 : {
327 : //create properties from the table attributes
328 : //...pPropMap->Insert( PROP_LEFT_MARGIN, uno::makeAny( m_nLeftMargin - m_nGapHalf ));
329 : //pPropMap->Insert( PROP_HORI_ORIENT, uno::makeAny( text::HoriOrientation::RIGHT ));
330 622 : sal_Int32 nGapHalf = 0;
331 622 : sal_Int32 nLeftMargin = 0;
332 622 : sal_Int32 nTableWidth = 0;
333 622 : sal_Int32 nTableWidthType = text::SizeType::FIX;
334 :
335 622 : comphelper::SequenceAsHashMap aGrabBag;
336 :
337 622 : if (nullptr != m_rDMapper_Impl.getTableManager().getCurrentTableRealPosition())
338 : {
339 43 : TablePositionHandler *pTablePositions = m_rDMapper_Impl.getTableManager().getCurrentTableRealPosition();
340 :
341 43 : uno::Sequence< beans::PropertyValue > aGrabBagTS( 10 );
342 :
343 43 : aGrabBagTS[0].Name = "bottomFromText";
344 43 : aGrabBagTS[0].Value = uno::makeAny(pTablePositions->getBottomFromText() );
345 :
346 43 : aGrabBagTS[1].Name = "horzAnchor";
347 43 : aGrabBagTS[1].Value = uno::makeAny( pTablePositions->getHorzAnchor() );
348 :
349 43 : aGrabBagTS[2].Name = "leftFromText";
350 43 : aGrabBagTS[2].Value = uno::makeAny( pTablePositions->getLeftFromText() );
351 :
352 43 : aGrabBagTS[3].Name = "rightFromText";
353 43 : aGrabBagTS[3].Value = uno::makeAny( pTablePositions->getRightFromText() );
354 :
355 43 : aGrabBagTS[4].Name = "tblpX";
356 43 : aGrabBagTS[4].Value = uno::makeAny( pTablePositions->getX() );
357 :
358 43 : aGrabBagTS[5].Name = "tblpXSpec";
359 43 : aGrabBagTS[5].Value = uno::makeAny( pTablePositions->getXSpec() );
360 :
361 43 : aGrabBagTS[6].Name = "tblpY";
362 43 : aGrabBagTS[6].Value = uno::makeAny( pTablePositions->getY() );
363 :
364 43 : aGrabBagTS[7].Name = "tblpYSpec";
365 43 : aGrabBagTS[7].Value = uno::makeAny( pTablePositions->getYSpec() );
366 :
367 43 : aGrabBagTS[8].Name = "topFromText";
368 43 : aGrabBagTS[8].Value = uno::makeAny( pTablePositions->getTopFromText() );
369 :
370 43 : aGrabBagTS[9].Name = "vertAnchor";
371 43 : aGrabBagTS[9].Value = uno::makeAny( pTablePositions->getVertAnchor() );
372 :
373 43 : aGrabBag["TablePosition"] = uno::makeAny( aGrabBagTS );
374 : }
375 :
376 1244 : boost::optional<PropertyMap::Property> aTableStyleVal = m_aTableProperties->getProperty(META_PROP_TABLE_STYLE_NAME);
377 622 : if(aTableStyleVal)
378 : {
379 : // Apply table style properties recursively
380 227 : OUString sTableStyleName;
381 227 : aTableStyleVal->second >>= sTableStyleName;
382 454 : StyleSheetTablePtr pStyleSheetTable = m_rDMapper_Impl.GetStyleSheetTable();
383 454 : const StyleSheetEntryPtr pStyleSheet = pStyleSheetTable->FindStyleSheetByISTD( sTableStyleName );
384 227 : pTableStyle = dynamic_cast<TableStyleSheetEntry*>( pStyleSheet.get( ) );
385 227 : m_aTableProperties->Erase( aTableStyleVal->first );
386 :
387 227 : aGrabBag["TableStyleName"] = uno::makeAny( sTableStyleName );
388 :
389 227 : if( pStyleSheet )
390 : {
391 : // First get the style properties, then the table ones
392 220 : PropertyMapPtr pTableProps( m_aTableProperties );
393 440 : TablePropertyMapPtr pEmptyProps( new TablePropertyMap );
394 :
395 220 : m_aTableProperties = pEmptyProps;
396 :
397 440 : PropertyMapPtr pMergedProperties = lcl_SearchParentStyleSheetAndMergeProperties(pStyleSheet, pStyleSheetTable);
398 :
399 220 : table::BorderLine2 aBorderLine;
400 440 : TableInfo rStyleInfo;
401 220 : if (lcl_extractTableBorderProperty(pMergedProperties, PROP_TOP_BORDER, rStyleInfo, aBorderLine))
402 : {
403 196 : aGrabBag["TableStyleTopBorder"] = uno::makeAny( aBorderLine );
404 : }
405 220 : if (lcl_extractTableBorderProperty(pMergedProperties, PROP_BOTTOM_BORDER, rStyleInfo, aBorderLine))
406 : {
407 196 : aGrabBag["TableStyleBottomBorder"] = uno::makeAny( aBorderLine );
408 : }
409 220 : if (lcl_extractTableBorderProperty(pMergedProperties, PROP_LEFT_BORDER, rStyleInfo, aBorderLine))
410 : {
411 190 : aGrabBag["TableStyleLeftBorder"] = uno::makeAny( aBorderLine );
412 : }
413 220 : if (lcl_extractTableBorderProperty(pMergedProperties, PROP_RIGHT_BORDER, rStyleInfo, aBorderLine))
414 : {
415 190 : aGrabBag["TableStyleRightBorder"] = uno::makeAny( aBorderLine );
416 : }
417 :
418 : #ifdef DEBUG_WRITERFILTER
419 : TagLogger::getInstance().startElement("mergedProps");
420 : if (pMergedProperties)
421 : pMergedProperties->dumpXml();
422 : TagLogger::getInstance().endElement();
423 : #endif
424 :
425 220 : m_aTableProperties->InsertProps(pMergedProperties);
426 440 : m_aTableProperties->InsertProps(pTableProps);
427 :
428 : #ifdef DEBUG_WRITERFILTER
429 : TagLogger::getInstance().startElement("TableProperties");
430 : m_aTableProperties->dumpXml();
431 : TagLogger::getInstance().endElement();
432 : #endif
433 227 : }
434 : }
435 :
436 : // This is the one preserving just all the table look attributes.
437 1244 : boost::optional<PropertyMap::Property> oTableLook = m_aTableProperties->getProperty(META_PROP_TABLE_LOOK);
438 622 : if (oTableLook)
439 : {
440 463 : aGrabBag["TableStyleLook"] = oTableLook->second;
441 463 : m_aTableProperties->Erase(oTableLook->first);
442 : }
443 :
444 : // This is just the "val" attribute's numeric value.
445 1244 : const boost::optional<PropertyMap::Property> aTblLook = m_aTableProperties->getProperty(PROP_TBL_LOOK);
446 622 : if(aTblLook)
447 : {
448 463 : aTblLook->second >>= rInfo.nTblLook;
449 463 : m_aTableProperties->Erase( aTblLook->first );
450 : }
451 :
452 : // Set the table default attributes for the cells
453 622 : rInfo.pTableDefaults->InsertProps(m_aTableProperties);
454 :
455 : #ifdef DEBUG_WRITERFILTER
456 : TagLogger::getInstance().startElement("TableDefaults");
457 : rInfo.pTableDefaults->dumpXml();
458 : TagLogger::getInstance().endElement();
459 : #endif
460 :
461 622 : if (!aGrabBag.empty())
462 : {
463 469 : m_aTableProperties->Insert( PROP_TABLE_INTEROP_GRAB_BAG, uno::makeAny( aGrabBag.getAsConstPropertyValueList() ) );
464 : }
465 :
466 622 : m_aTableProperties->getValue( TablePropertyMap::GAP_HALF, nGapHalf );
467 622 : m_aTableProperties->getValue( TablePropertyMap::LEFT_MARGIN, nLeftMargin );
468 :
469 : m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_LEFT,
470 622 : rInfo.nLeftBorderDistance );
471 : m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_RIGHT,
472 622 : rInfo.nRightBorderDistance );
473 : m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_TOP,
474 622 : rInfo.nTopBorderDistance );
475 : m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_BOTTOM,
476 622 : rInfo.nBottomBorderDistance );
477 :
478 622 : table::TableBorderDistances aDistances;
479 : aDistances.IsTopDistanceValid =
480 : aDistances.IsBottomDistanceValid =
481 : aDistances.IsLeftDistanceValid =
482 622 : aDistances.IsRightDistanceValid = sal_True;
483 622 : aDistances.TopDistance = static_cast<sal_Int16>( rInfo.nTopBorderDistance );
484 622 : aDistances.BottomDistance = static_cast<sal_Int16>( rInfo.nBottomBorderDistance );
485 622 : aDistances.LeftDistance = static_cast<sal_Int16>( rInfo.nLeftBorderDistance );
486 622 : aDistances.RightDistance = static_cast<sal_Int16>( rInfo.nRightBorderDistance );
487 :
488 622 : m_aTableProperties->Insert( PROP_TABLE_BORDER_DISTANCES, uno::makeAny( aDistances ) );
489 :
490 622 : if (!rFrameProperties.empty())
491 43 : lcl_DecrementHoriOrientPosition(rFrameProperties, rInfo.nLeftBorderDistance);
492 :
493 : // Set table above/bottom spacing to 0.
494 622 : m_aTableProperties->Insert( PROP_TOP_MARGIN, uno::makeAny( sal_Int32( 0 ) ) );
495 622 : m_aTableProperties->Insert( PROP_BOTTOM_MARGIN, uno::makeAny( sal_Int32( 0 ) ) );
496 :
497 : //table border settings
498 622 : table::TableBorder aTableBorder;
499 622 : table::BorderLine2 aBorderLine, aLeftBorder;
500 :
501 622 : if (lcl_extractTableBorderProperty(m_aTableProperties, PROP_TOP_BORDER, rInfo, aBorderLine))
502 : {
503 324 : aTableBorder.TopLine = aBorderLine;
504 324 : aTableBorder.IsTopLineValid = sal_True;
505 : }
506 622 : if (lcl_extractTableBorderProperty(m_aTableProperties, PROP_BOTTOM_BORDER, rInfo, aBorderLine))
507 : {
508 332 : aTableBorder.BottomLine = aBorderLine;
509 332 : aTableBorder.IsBottomLineValid = sal_True;
510 : }
511 622 : if (lcl_extractTableBorderProperty(m_aTableProperties, PROP_LEFT_BORDER, rInfo, aLeftBorder))
512 : {
513 303 : aTableBorder.LeftLine = aLeftBorder;
514 303 : aTableBorder.IsLeftLineValid = sal_True;
515 : // Only top level table position depends on border width
516 303 : if (rInfo.nNestLevel == 1)
517 : {
518 274 : if (rFrameProperties.empty())
519 240 : rInfo.nLeftBorderDistance += aLeftBorder.LineWidth * 0.5;
520 : else
521 34 : lcl_DecrementHoriOrientPosition(rFrameProperties, aLeftBorder.LineWidth * 0.5);
522 : }
523 : }
524 622 : if (lcl_extractTableBorderProperty(m_aTableProperties, PROP_RIGHT_BORDER, rInfo, aBorderLine))
525 : {
526 300 : aTableBorder.RightLine = aBorderLine;
527 300 : aTableBorder.IsRightLineValid = sal_True;
528 : }
529 622 : if (lcl_extractTableBorderProperty(m_aTableProperties, META_PROP_HORIZONTAL_BORDER, rInfo, aBorderLine))
530 : {
531 313 : aTableBorder.HorizontalLine = aBorderLine;
532 313 : aTableBorder.IsHorizontalLineValid = sal_True;
533 : }
534 622 : if (lcl_extractTableBorderProperty(m_aTableProperties, META_PROP_VERTICAL_BORDER, rInfo, aBorderLine))
535 : {
536 308 : aTableBorder.VerticalLine = aBorderLine;
537 308 : aTableBorder.IsVerticalLineValid = sal_True;
538 : }
539 :
540 622 : aTableBorder.Distance = 0;
541 622 : aTableBorder.IsDistanceValid = sal_False;
542 :
543 622 : m_aTableProperties->Insert( PROP_TABLE_BORDER, uno::makeAny( aTableBorder ) );
544 :
545 : #ifdef DEBUG_WRITERFILTER
546 : lcl_debug_TableBorder(aTableBorder);
547 : #endif
548 :
549 : // Table position in Office is computed in 2 different ways :
550 : // - top level tables: the goal is to have in-cell text starting at table indent pos (tblInd),
551 : // so table's position depends on table's cells margin
552 : // - nested tables: the goal is to have left-most border starting at table_indent pos
553 622 : if (rInfo.nNestLevel > 1)
554 : {
555 60 : m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::makeAny( nLeftMargin - nGapHalf ));
556 : }
557 : else
558 : {
559 562 : m_aTableProperties->Insert( PROP_LEFT_MARGIN, uno::makeAny( nLeftMargin - nGapHalf - rInfo.nLeftBorderDistance ));
560 : }
561 :
562 622 : m_aTableProperties->getValue( TablePropertyMap::TABLE_WIDTH, nTableWidth );
563 622 : m_aTableProperties->getValue( TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType );
564 622 : if( nTableWidthType == text::SizeType::FIX )
565 : {
566 554 : if( nTableWidth > 0 )
567 551 : m_aTableProperties->Insert( PROP_WIDTH, uno::makeAny( nTableWidth ));
568 : }
569 : else
570 : {
571 68 : m_aTableProperties->Insert( PROP_RELATIVE_WIDTH, uno::makeAny( sal_Int16( nTableWidth ) ) );
572 68 : m_aTableProperties->Insert( PROP_IS_WIDTH_RELATIVE, uno::makeAny( true ) );
573 : }
574 :
575 622 : sal_Int32 nHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
576 : // Fetch Horizontal Orientation in rFrameProperties if not set in m_aTableProperties
577 622 : if ( !m_aTableProperties->getValue( TablePropertyMap::HORI_ORIENT, nHoriOrient ) )
578 370 : lcl_extractHoriOrient( rFrameProperties, nHoriOrient );
579 622 : m_aTableProperties->Insert( PROP_HORI_ORIENT, uno::makeAny( sal_Int16(nHoriOrient) ) );
580 : //fill default value - if not available
581 622 : m_aTableProperties->Insert( PROP_HEADER_ROW_COUNT, uno::makeAny( (sal_Int32)0), false);
582 :
583 1244 : rInfo.aTableProperties = m_aTableProperties->GetPropertyValues();
584 :
585 : #ifdef DEBUG_WRITERFILTER
586 : TagLogger::getInstance().startElement("debug.tableprops");
587 : m_aTableProperties->dumpXml();
588 : TagLogger::getInstance().endElement();
589 : #endif
590 :
591 : }
592 :
593 5437 : return pTableStyle;
594 : }
595 :
596 : #define CNF_FIRST_ROW 0x800
597 : #define CNF_LAST_ROW 0x400
598 : #define CNF_FIRST_COLUMN 0x200
599 : #define CNF_LAST_COLUMN 0x100
600 : #define CNF_ODD_VBAND 0x080
601 : #define CNF_EVEN_VBAND 0x040
602 : #define CNF_ODD_HBAND 0x020
603 : #define CNF_EVEN_HBAND 0x010
604 : #define CNF_FIRST_ROW_LAST_COLUMN 0x008
605 : #define CNF_FIRST_ROW_FIRST_COLUMN 0x004
606 : #define CNF_LAST_ROW_LAST_COLUMN 0x002
607 : #define CNF_LAST_ROW_FIRST_COLUMN 0x001
608 :
609 5437 : CellPropertyValuesSeq_t DomainMapperTableHandler::endTableGetCellProperties(TableInfo & rInfo, std::vector<HorizontallyMergedCell>& rMerges)
610 : {
611 : #ifdef DEBUG_WRITERFILTER
612 : TagLogger::getInstance().startElement("getCellProperties");
613 : #endif
614 :
615 5437 : CellPropertyValuesSeq_t aCellProperties( m_aCellProperties.size() );
616 :
617 5437 : if ( !m_aCellProperties.size() )
618 : {
619 : #ifdef DEBUG_WRITERFILTER
620 : TagLogger::getInstance().endElement();
621 : #endif
622 4813 : return aCellProperties;
623 : }
624 : // std::vector< std::vector<PropertyMapPtr> > m_aCellProperties
625 624 : PropertyMapVector2::const_iterator aRowOfCellsIterator = m_aCellProperties.begin();
626 624 : PropertyMapVector2::const_iterator aRowOfCellsIteratorEnd = m_aCellProperties.end();
627 624 : PropertyMapVector2::const_iterator aLastRowIterator = m_aCellProperties.end() - 1;
628 624 : sal_Int32 nRow = 0;
629 :
630 : //it's a uno::Sequence< beans::PropertyValues >*
631 624 : RowPropertyValuesSeq_t* pCellProperties = aCellProperties.getArray();
632 624 : PropertyMapVector1::const_iterator aRowIter = m_aRowProperties.begin();
633 4226 : while( aRowOfCellsIterator != aRowOfCellsIteratorEnd )
634 : {
635 : //aRowOfCellsIterator points to a vector of PropertyMapPtr
636 2978 : PropertyMapVector1::const_iterator aCellIterator = aRowOfCellsIterator->begin();
637 2978 : PropertyMapVector1::const_iterator aCellIteratorEnd = aRowOfCellsIterator->end();
638 :
639 2978 : sal_Int32 nRowStyleMask = 0;
640 :
641 2978 : if (aRowOfCellsIterator==m_aCellProperties.begin())
642 : {
643 624 : if(rInfo.nTblLook&0x20)
644 526 : nRowStyleMask |= CNF_FIRST_ROW; // first row style used
645 : }
646 2354 : else if (aRowOfCellsIterator==aLastRowIterator)
647 : {
648 314 : if(rInfo.nTblLook&0x40)
649 13 : nRowStyleMask |= CNF_LAST_ROW; // last row style used
650 : }
651 2040 : else if (*aRowIter && (*aRowIter)->isSet(PROP_TBL_HEADER))
652 40 : nRowStyleMask |= CNF_FIRST_ROW; // table header implies first row
653 2978 : if(!nRowStyleMask) // if no row style used yet
654 : {
655 : // banding used only if not first and or last row style used
656 2399 : if(!(rInfo.nTblLook&0x200))
657 : { // hbanding used
658 2399 : int n = nRow + 1;
659 2399 : if(rInfo.nTblLook&0x20)
660 1979 : n++;
661 2399 : if(n & 1)
662 1325 : nRowStyleMask = CNF_ODD_HBAND;
663 : else
664 1074 : nRowStyleMask = CNF_EVEN_HBAND;
665 : }
666 : }
667 :
668 2978 : sal_Int32 nCell = 0;
669 2978 : pCellProperties[nRow].realloc( aRowOfCellsIterator->size() );
670 2978 : beans::PropertyValues* pSingleCellProperties = pCellProperties[nRow].getArray();
671 14299 : while( aCellIterator != aCellIteratorEnd )
672 : {
673 8343 : PropertyMapPtr pAllCellProps( new PropertyMap );
674 :
675 8343 : PropertyMapVector1::const_iterator aLastCellIterator = aRowOfCellsIterator->end() - 1;
676 8343 : bool bIsEndCol = aCellIterator == aLastCellIterator;
677 8343 : bool bIsEndRow = aRowOfCellsIterator == aLastRowIterator;
678 :
679 : //aCellIterator points to a PropertyMapPtr;
680 8343 : if( *aCellIterator )
681 : {
682 8343 : pAllCellProps->InsertProps(rInfo.pTableDefaults);
683 :
684 8343 : sal_Int32 nCellStyleMask = 0;
685 8343 : if (aCellIterator==aRowOfCellsIterator->begin())
686 : {
687 2975 : if(rInfo.nTblLook&0x80)
688 2546 : nCellStyleMask = CNF_FIRST_COLUMN; // first col style used
689 : }
690 5368 : else if (bIsEndCol)
691 : {
692 2580 : if(rInfo.nTblLook&0x100)
693 270 : nCellStyleMask = CNF_LAST_COLUMN; // last col style used
694 : }
695 8343 : if(!nCellStyleMask) // if no cell style is used yet
696 : {
697 5527 : if(!(rInfo.nTblLook&0x400))
698 : { // vbanding used
699 1313 : int n = nCell + 1;
700 1313 : if(rInfo.nTblLook&0x80)
701 63 : n++;
702 1313 : if(n & 1)
703 756 : nCellStyleMask = CNF_ODD_VBAND;
704 : else
705 557 : nCellStyleMask = CNF_EVEN_VBAND;
706 : }
707 : }
708 8343 : sal_Int32 nCnfStyleMask = nCellStyleMask + nRowStyleMask;
709 8343 : if(nCnfStyleMask == CNF_FIRST_COLUMN + CNF_FIRST_ROW)
710 561 : nCnfStyleMask |= CNF_FIRST_ROW_FIRST_COLUMN;
711 7782 : else if(nCnfStyleMask == CNF_FIRST_COLUMN + CNF_LAST_ROW)
712 13 : nCnfStyleMask |= CNF_LAST_ROW_FIRST_COLUMN;
713 7769 : else if(nCnfStyleMask == CNF_LAST_COLUMN + CNF_FIRST_ROW)
714 25 : nCnfStyleMask |= CNF_FIRST_ROW_LAST_COLUMN;
715 7744 : else if(nCnfStyleMask == CNF_LAST_COLUMN + CNF_LAST_ROW)
716 12 : nCnfStyleMask |= CNF_LAST_ROW_LAST_COLUMN;
717 :
718 8343 : if ( rInfo.pTableStyle )
719 : {
720 4132 : PropertyMapPtr pStyleProps = rInfo.pTableStyle->GetProperties( nCnfStyleMask );
721 :
722 : // Check if we need to clean up some empty border definitions to match what Word does.
723 : static const PropertyIds pBorders[] =
724 : {
725 : PROP_TOP_BORDER, PROP_LEFT_BORDER, PROP_BOTTOM_BORDER, PROP_RIGHT_BORDER
726 : };
727 20660 : for (size_t i = 0; i < SAL_N_ELEMENTS(pBorders); ++i)
728 : {
729 16528 : boost::optional<PropertyMap::Property> oStyleCellBorder = pStyleProps->getProperty(pBorders[i]);
730 33056 : boost::optional<PropertyMap::Property> oDirectCellBorder = (*aCellIterator)->getProperty(pBorders[i]);
731 16528 : if (oStyleCellBorder && oDirectCellBorder)
732 : {
733 : // We have a cell border from the table style and as direct formatting as well.
734 106 : table::BorderLine2 aStyleCellBorder = oStyleCellBorder->second.get<table::BorderLine2>();
735 106 : table::BorderLine2 aDirectCellBorder = oDirectCellBorder->second.get<table::BorderLine2>();
736 106 : if (aStyleCellBorder.LineStyle != table::BorderLineStyle::NONE && aDirectCellBorder.LineStyle == table::BorderLineStyle::NONE)
737 : {
738 : // The style one would be visible, but then cleared away as direct formatting.
739 : // Delete both, so that table formatting can become visible.
740 8 : pStyleProps->Erase(pBorders[i]);
741 8 : (*aCellIterator)->Erase(pBorders[i]);
742 : }
743 : else
744 : {
745 98 : boost::optional<PropertyMap::Property> oTableBorder = rInfo.pTableBorders->getProperty(pBorders[i]);
746 98 : if (oTableBorder)
747 : {
748 53 : table::BorderLine2 aTableBorder = oTableBorder->second.get<table::BorderLine2>();
749 : // Both style and direct formatting says that the cell has no border.
750 53 : bool bNoCellBorder = aStyleCellBorder.LineStyle == table::BorderLineStyle::NONE && aDirectCellBorder.LineStyle == table::BorderLineStyle::NONE;
751 53 : if (aTableBorder.LineStyle != table::BorderLineStyle::NONE && bNoCellBorder)
752 : {
753 : // But at a table-level, there is a border, then again delete both cell properties.
754 3 : pStyleProps->Erase(pBorders[i]);
755 3 : (*aCellIterator)->Erase(pBorders[i]);
756 : }
757 98 : }
758 : }
759 : }
760 16528 : }
761 :
762 4132 : pAllCellProps->InsertProps( pStyleProps );
763 : }
764 :
765 : // Remove properties from style/row that aren't allowed in cells
766 8343 : pAllCellProps->Erase( PROP_HEADER_ROW_COUNT );
767 8343 : pAllCellProps->Erase( PROP_TBL_HEADER );
768 :
769 : // Then add the cell properties
770 8343 : pAllCellProps->InsertProps(*aCellIterator);
771 8343 : std::swap(*(*aCellIterator), *pAllCellProps );
772 :
773 : #ifdef DEBUG_WRITERFILTER
774 : TagLogger::getInstance().startElement("cell");
775 : TagLogger::getInstance().attribute("cell", nCell);
776 : TagLogger::getInstance().attribute("row", nRow);
777 : #endif
778 :
779 8343 : lcl_computeCellBorders( rInfo.pTableBorders, *aCellIterator, nCell, nRow, bIsEndCol, bIsEndRow );
780 :
781 : //now set the default left+right border distance TODO: there's an sprm containing the default distance!
782 8343 : aCellIterator->get()->Insert( PROP_LEFT_BORDER_DISTANCE,
783 16686 : uno::makeAny(rInfo.nLeftBorderDistance ), false);
784 8343 : aCellIterator->get()->Insert( PROP_RIGHT_BORDER_DISTANCE,
785 16686 : uno::makeAny((sal_Int32) rInfo.nRightBorderDistance ), false);
786 8343 : aCellIterator->get()->Insert( PROP_TOP_BORDER_DISTANCE,
787 16686 : uno::makeAny((sal_Int32) rInfo.nTopBorderDistance ), false);
788 8343 : aCellIterator->get()->Insert( PROP_BOTTOM_BORDER_DISTANCE,
789 16686 : uno::makeAny((sal_Int32) rInfo.nBottomBorderDistance ), false);
790 :
791 : // Horizontal merge is not an UNO property, extract that info here to rMerges, and then remove it from the map.
792 8343 : const boost::optional<PropertyMap::Property> aHorizontalMergeVal = (*aCellIterator)->getProperty(PROP_HORIZONTAL_MERGE);
793 8343 : if (aHorizontalMergeVal)
794 : {
795 4 : if (aHorizontalMergeVal->second.get<sal_Bool>())
796 : {
797 : // first cell in a merge
798 2 : HorizontallyMergedCell aMerge(nRow, nCell);
799 2 : rMerges.push_back(aMerge);
800 : }
801 2 : else if (!rMerges.empty())
802 : {
803 : // resuming an earlier merge
804 2 : HorizontallyMergedCell& rMerge = rMerges.back();
805 2 : rMerge.m_nLastRow = nRow;
806 2 : rMerge.m_nLastCol = nCell;
807 : }
808 4 : (*aCellIterator)->Erase(PROP_HORIZONTAL_MERGE);
809 : }
810 :
811 : // Cell direction is not an UNO Property, either.
812 16686 : const boost::optional<PropertyMap::Property> aCellDirectionVal = (*aCellIterator)->getProperty(PROP_CELL_DIRECTION);
813 8343 : if (aCellDirectionVal)
814 : {
815 34 : if (aCellDirectionVal->second.get<sal_Int32>() == static_cast<sal_Int32>(NS_ooxml::LN_Value_ST_TextDirection_btLr))
816 : {
817 : // btLr, so map ParagraphAdjust_CENTER to VertOrientation::CENTER.
818 32 : uno::Reference<beans::XPropertySet> xPropertySet((*m_pTableSeq)[nRow][nCell][0], uno::UNO_QUERY);
819 32 : if (xPropertySet->getPropertyValue("ParaAdjust").get<sal_Int16>() == style::ParagraphAdjust_CENTER)
820 27 : (*aCellIterator)->Insert(PROP_VERT_ORIENT, uno::makeAny(text::VertOrientation::CENTER));
821 : }
822 34 : (*aCellIterator)->Erase(PROP_CELL_DIRECTION);
823 : }
824 :
825 16686 : pSingleCellProperties[nCell] = (*aCellIterator)->GetPropertyValues();
826 : #ifdef DEBUG_WRITERFILTER
827 : TagLogger::getInstance().endElement();
828 : #endif
829 : }
830 8343 : ++nCell;
831 8343 : ++aCellIterator;
832 8343 : }
833 : #ifdef DEBUG_WRITERFILTER
834 : //-->debug cell properties
835 : {
836 : OUString sNames;
837 : const uno::Sequence< beans::PropertyValues > aDebugCurrentRow = aCellProperties[nRow];
838 : sal_Int32 nDebugCells = aDebugCurrentRow.getLength();
839 : (void) nDebugCells;
840 : for( sal_Int32 nDebugCell = 0; nDebugCell < nDebugCells; ++nDebugCell)
841 : {
842 : const uno::Sequence< beans::PropertyValue >& aDebugCellProperties = aDebugCurrentRow[nDebugCell];
843 : sal_Int32 nDebugCellProperties = aDebugCellProperties.getLength();
844 : for( sal_Int32 nDebugProperty = 0; nDebugProperty < nDebugCellProperties; ++nDebugProperty)
845 : {
846 : const OUString sName = aDebugCellProperties[nDebugProperty].Name;
847 : sNames += sName;
848 : sNames += OUString('-');
849 : }
850 : sNames += OUString('\n');
851 : }
852 : (void)sNames;
853 : }
854 : //--<
855 : #endif
856 2978 : ++nRow;
857 2978 : ++aRowOfCellsIterator;
858 2978 : ++aRowIter;
859 : }
860 :
861 : #ifdef DEBUG_WRITERFILTER
862 : TagLogger::getInstance().endElement();
863 : #endif
864 :
865 624 : return aCellProperties;
866 : }
867 :
868 : /// Do all cells in this row have a CellHideMark property?
869 2941 : bool lcl_hideMarks(PropertyMapVector1& rCellProperties)
870 : {
871 4420 : for (size_t nCell = 0; nCell < rCellProperties.size(); ++nCell)
872 4077 : if (!rCellProperties[nCell]->isSet(PROP_CELL_HIDE_MARK))
873 2598 : return false;
874 343 : return true;
875 : }
876 :
877 : /// Are all cells in this row empty?
878 343 : bool lcl_emptyRow(TableSequence_t& rTableSeq, sal_Int32 nRow)
879 : {
880 343 : if (nRow >= rTableSeq.getLength())
881 : {
882 : SAL_WARN("writerfilter", "m_aCellProperties not in sync with m_pTableSeq?");
883 0 : return false;
884 : }
885 :
886 343 : RowSequence_t rRowSeq = rTableSeq[nRow];
887 343 : if (rRowSeq.getLength() == 0)
888 : {
889 : SAL_WARN("writerfilter", "m_aCellProperties not in sync with m_pTableSeq?");
890 0 : return false;
891 : }
892 :
893 686 : uno::Reference<text::XTextRangeCompare> xTextRangeCompare(rRowSeq[0][0]->getText(), uno::UNO_QUERY);
894 : try
895 : {
896 394 : for (sal_Int32 nCell = 0; nCell < rRowSeq.getLength(); ++nCell)
897 : // See SwXText::Impl::ConvertCell(), we need to compare the start of
898 : // the start and the end of the end. However for our text ranges, only
899 : // the starts are set, so compareRegionStarts() does what we need.
900 381 : if (xTextRangeCompare->compareRegionStarts(rRowSeq[nCell][0], rRowSeq[nCell][1]) != 0)
901 326 : return false;
902 : }
903 8 : catch (const lang::IllegalArgumentException& e)
904 : {
905 : SAL_WARN("writerfilter", "compareRegionStarts() failed: " << e.Message);
906 4 : return false;
907 : }
908 356 : return true;
909 : }
910 :
911 5437 : RowPropertyValuesSeq_t DomainMapperTableHandler::endTableGetRowProperties()
912 : {
913 : #ifdef DEBUG_WRITERFILTER
914 : TagLogger::getInstance().startElement("getRowProperties");
915 : #endif
916 :
917 : static const int MINLAY = 23; // sw/inc/swtypes.hxx, minimal possible size of frames.
918 5437 : RowPropertyValuesSeq_t aRowProperties( m_aRowProperties.size() );
919 5437 : PropertyMapVector1::const_iterator aRowIter = m_aRowProperties.begin();
920 5437 : PropertyMapVector1::const_iterator aRowIterEnd = m_aRowProperties.end();
921 5437 : sal_Int32 nRow = 0;
922 13852 : while( aRowIter != aRowIterEnd )
923 : {
924 : #ifdef DEBUG_WRITERFILTER
925 : TagLogger::getInstance().startElement("rowProps.row");
926 : #endif
927 2978 : if( aRowIter->get() )
928 : {
929 : //set default to 'break across pages"
930 2941 : (*aRowIter)->Insert( PROP_IS_SPLIT_ALLOWED, uno::makeAny(sal_True ), false );
931 : // tblHeader is only our property, remove before the property map hits UNO
932 2941 : (*aRowIter)->Erase(PROP_TBL_HEADER);
933 :
934 2941 : if (lcl_hideMarks(m_aCellProperties[nRow]) && lcl_emptyRow(*m_pTableSeq, nRow))
935 : {
936 : // We have CellHideMark on all cells, and also all cells are empty:
937 : // Set the row height to minimal as Word does.
938 13 : (*aRowIter)->Insert(PROP_SIZE_TYPE, uno::makeAny(text::SizeType::FIX));
939 13 : (*aRowIter)->Insert(PROP_HEIGHT, uno::makeAny(static_cast<sal_Int32>(ConversionHelper::convertTwipToMM100(MINLAY))));
940 : }
941 :
942 2941 : aRowProperties[nRow] = (*aRowIter)->GetPropertyValues();
943 : #ifdef DEBUG_WRITERFILTER
944 : (*aRowIter)->dumpXml();
945 : lcl_DumpPropertyValues(aRowProperties[nRow]);
946 : #endif
947 : }
948 2978 : ++nRow;
949 2978 : ++aRowIter;
950 : #ifdef DEBUG_WRITERFILTER
951 : TagLogger::getInstance().endElement();
952 : #endif
953 : }
954 :
955 : #ifdef DEBUG_WRITERFILTER
956 : TagLogger::getInstance().endElement();
957 : #endif
958 :
959 5437 : return aRowProperties;
960 : }
961 :
962 : // Apply paragraph property to each paragraph within a cell.
963 2933 : static void lcl_ApplyCellParaProps(uno::Reference<table::XCell> const& xCell,
964 : const uno::Any& rBottomMargin)
965 : {
966 2933 : uno::Reference<container::XEnumerationAccess> xEnumerationAccess(xCell, uno::UNO_QUERY);
967 5866 : uno::Reference<container::XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
968 8939 : while (xEnumeration->hasMoreElements())
969 : {
970 3073 : uno::Reference<beans::XPropertySet> xParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
971 6146 : uno::Reference<beans::XPropertyState> xPropertyState(xParagraph, uno::UNO_QUERY);
972 : // Don't apply in case direct formatting is already present.
973 : // TODO: probably paragraph style has priority over table style here.
974 3073 : if (xPropertyState.is() && xPropertyState->getPropertyState("ParaBottomMargin") == beans::PropertyState_DEFAULT_VALUE)
975 47 : xParagraph->setPropertyValue("ParaBottomMargin", rBottomMargin);
976 6006 : }
977 2933 : }
978 :
979 5437 : void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel)
980 : {
981 : #ifdef DEBUG_WRITERFILTER
982 : TagLogger::getInstance().startElement("tablehandler.endTable");
983 : #endif
984 :
985 : // If we want to make this table a floating one.
986 : std::vector<beans::PropertyValue> aFrameProperties = comphelper::sequenceToContainer<std::vector<beans::PropertyValue> >
987 5437 : (m_rDMapper_Impl.getTableManager().getCurrentTablePosition());
988 10874 : TableInfo aTableInfo;
989 5437 : aTableInfo.nNestLevel = nestedTableLevel;
990 5437 : aTableInfo.pTableStyle = endTableGetTableStyle(aTableInfo, aFrameProperties);
991 : // expands to uno::Sequence< Sequence< beans::PropertyValues > >
992 :
993 10874 : std::vector<HorizontallyMergedCell> aMerges;
994 10874 : CellPropertyValuesSeq_t aCellProperties = endTableGetCellProperties(aTableInfo, aMerges);
995 :
996 10874 : RowPropertyValuesSeq_t aRowProperties = endTableGetRowProperties();
997 :
998 : #ifdef DEBUG_WRITERFILTER
999 : lcl_DumpPropertyValueSeq(aRowProperties);
1000 : #endif
1001 :
1002 5437 : if (m_pTableSeq->getLength() > 0)
1003 : {
1004 622 : uno::Reference<text::XTextRange> xStart;
1005 1244 : uno::Reference<text::XTextRange> xEnd;
1006 :
1007 622 : bool bFloating = !aFrameProperties.empty();
1008 : // Additional checks: if we can do this.
1009 622 : if (bFloating && (*m_pTableSeq)[0].getLength() > 0 && (*m_pTableSeq)[0][0].getLength() > 0)
1010 : {
1011 43 : xStart = (*m_pTableSeq)[0][0][0];
1012 43 : uno::Sequence< uno::Sequence< uno::Reference<text::XTextRange> > >& rLastRow = (*m_pTableSeq)[m_pTableSeq->getLength() - 1];
1013 43 : uno::Sequence< uno::Reference<text::XTextRange> >& rLastCell = rLastRow[rLastRow.getLength() - 1];
1014 43 : xEnd = rLastCell[1];
1015 : }
1016 1244 : uno::Reference<text::XTextTable> xTable;
1017 : try
1018 : {
1019 622 : if (m_xText.is())
1020 : {
1021 1814 : xTable = m_xText->convertToTable(*m_pTableSeq,
1022 : aCellProperties,
1023 : aRowProperties,
1024 1209 : aTableInfo.aTableProperties);
1025 :
1026 604 : if (xTable.is())
1027 : {
1028 603 : m_xTableRange = xTable->getAnchor( );
1029 :
1030 603 : if (!aMerges.empty())
1031 : {
1032 : // Perform horizontal merges in reverse order, so the fact that merging changes the position of cells won't cause a problem for us.
1033 4 : for (std::vector<HorizontallyMergedCell>::reverse_iterator it = aMerges.rbegin(); it != aMerges.rend(); ++it)
1034 : {
1035 2 : uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY_THROW);
1036 4 : uno::Reference<beans::XPropertySet> xCell(xCellRange->getCellByPosition(it->m_nFirstCol, it->m_nFirstRow), uno::UNO_QUERY_THROW);
1037 4 : OUString aFirst = xCell->getPropertyValue("CellName").get<OUString>();
1038 2 : xCell.set(xCellRange->getCellByPosition(it->m_nLastCol, it->m_nLastRow), uno::UNO_QUERY_THROW);
1039 4 : OUString aLast = xCell->getPropertyValue("CellName").get<OUString>();
1040 :
1041 4 : uno::Reference<text::XTextTableCursor> xCursor = xTable->createCursorByCellName(aFirst);
1042 2 : xCursor->gotoCellByName(aLast, true);
1043 2 : xCursor->mergeRange();
1044 2 : }
1045 : }
1046 : }
1047 :
1048 : // OOXML table style may container paragraph properties, apply these now.
1049 6884 : for (int i = 0; i < aTableInfo.aTableProperties.getLength(); ++i)
1050 : {
1051 6445 : if (aTableInfo.aTableProperties[i].Name == "ParaBottomMargin")
1052 : {
1053 165 : uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY);
1054 330 : uno::Any aBottomMargin = aTableInfo.aTableProperties[i].Value;
1055 165 : sal_Int32 nRows = aCellProperties.getLength();
1056 1364 : for (sal_Int32 nRow = 0; nRow < nRows; ++nRow)
1057 : {
1058 1200 : const uno::Sequence< beans::PropertyValues > aCurrentRow = aCellProperties[nRow];
1059 1200 : sal_Int32 nCells = aCurrentRow.getLength();
1060 4133 : for (sal_Int32 nCell = 0; nCell < nCells; ++nCell)
1061 2934 : lcl_ApplyCellParaProps(xCellRange->getCellByPosition(nCell, nRow), aBottomMargin);
1062 1200 : }
1063 329 : break;
1064 : }
1065 : }
1066 : }
1067 : }
1068 1 : catch ( const lang::IllegalArgumentException &e )
1069 : {
1070 : SAL_INFO("writerfilter.dmapper",
1071 : "Conversion to table error: " << e.Message);
1072 : #ifdef DEBUG_WRITERFILTER
1073 : TagLogger::getInstance().chars(std::string("failed to import table!"));
1074 : #endif
1075 : }
1076 1 : catch ( const uno::Exception &e )
1077 : {
1078 : SAL_INFO("writerfilter.dmapper",
1079 : "Exception during table creation: " << e.Message);
1080 : }
1081 :
1082 : // If we have a table with a start and an end position, we should make it a floating one.
1083 622 : if (xTable.is() && xStart.is() && xEnd.is())
1084 : {
1085 43 : uno::Reference<beans::XPropertySet> xTableProperties(xTable, uno::UNO_QUERY);
1086 43 : bool bIsRelative = false;
1087 43 : xTableProperties->getPropertyValue("IsWidthRelative") >>= bIsRelative;
1088 43 : if (!bIsRelative)
1089 : {
1090 38 : beans::PropertyValue aValue;
1091 38 : aValue.Name = "Width";
1092 38 : aValue.Value = xTableProperties->getPropertyValue("Width");
1093 38 : aFrameProperties.push_back(aValue);
1094 : }
1095 : else
1096 : {
1097 5 : beans::PropertyValue aValue;
1098 5 : aValue.Name = "FrameWidthPercent";
1099 5 : aValue.Value = xTableProperties->getPropertyValue("RelativeWidth");
1100 5 : aFrameProperties.push_back(aValue);
1101 :
1102 : // Applying the relative width to the frame, needs to have the table width to be 100% of the frame width
1103 5 : xTableProperties->setPropertyValue("RelativeWidth", uno::makeAny(sal_Int16(100)));
1104 : }
1105 :
1106 : // A non-zero left margin would move the table out of the frame, move the frame itself instead.
1107 43 : xTableProperties->setPropertyValue("LeftMargin", uno::makeAny(sal_Int32(0)));
1108 :
1109 : // In case the document ends with a table, we're called after
1110 : // SectionPropertyMap::CloseSectionGroup(), so we'll have no idea
1111 : // about the text area width, nor can fix this by delaying the text
1112 : // frame conversion: just do it here.
1113 : // Also, when the anchor is within a table, then do it here as well,
1114 : // as xStart/xEnd would not point to the start/end at conversion
1115 : // time anyway.
1116 : // Next exception: it's pointless to delay the conversion if the
1117 : // table is not in the body text.
1118 43 : sal_Int32 nTableWidth = 0;
1119 43 : m_aTableProperties->getValue(TablePropertyMap::TABLE_WIDTH, nTableWidth);
1120 43 : if (m_rDMapper_Impl.GetSectionContext() && nestedTableLevel <= 1 && !m_rDMapper_Impl.IsInHeaderFooter())
1121 37 : m_rDMapper_Impl.m_aPendingFloatingTables.push_back(FloatingTableInfo(xStart, xEnd, comphelper::containerToSequence(aFrameProperties), nTableWidth));
1122 : else
1123 : {
1124 : // m_xText points to the body text, get to current xText from m_rDMapper_Impl, in case e.g. we would be in a header.
1125 6 : uno::Reference<text::XTextAppendAndConvert> xTextAppendAndConvert(m_rDMapper_Impl.GetTopTextAppend(), uno::UNO_QUERY);
1126 6 : if (xTextAppendAndConvert.is())
1127 6 : xTextAppendAndConvert->convertToTextFrame(xStart, xEnd, comphelper::containerToSequence(aFrameProperties));
1128 43 : }
1129 622 : }
1130 : }
1131 :
1132 5437 : m_aTableProperties.reset();
1133 5437 : m_aCellProperties.clear();
1134 10874 : m_aRowProperties.clear();
1135 :
1136 : #ifdef DEBUG_WRITERFILTER
1137 : TagLogger::getInstance().endElement();
1138 : TagLogger::getInstance().endElement();
1139 : #endif
1140 5437 : }
1141 :
1142 2978 : void DomainMapperTableHandler::startRow(unsigned int nCells,
1143 : TablePropertyMapPtr pProps)
1144 : {
1145 2978 : m_aRowProperties.push_back( pProps );
1146 2978 : m_aCellProperties.push_back( PropertyMapVector1() );
1147 :
1148 : #ifdef DEBUG_WRITERFILTER
1149 : TagLogger::getInstance().startElement("table.row");
1150 : TagLogger::getInstance().attribute("cells", nCells);
1151 : if (pProps != nullptr)
1152 : pProps->dumpXml();
1153 : #endif
1154 :
1155 2978 : m_pRowSeq = RowSequencePointer_t(new RowSequence_t(nCells));
1156 2978 : m_nCellIndex = 0;
1157 2978 : }
1158 :
1159 2976 : void DomainMapperTableHandler::endRow()
1160 : {
1161 2976 : (*m_pTableSeq)[m_nRowIndex] = *m_pRowSeq;
1162 2976 : ++m_nRowIndex;
1163 2976 : m_nCellIndex = 0;
1164 : #ifdef DEBUG_WRITERFILTER
1165 : TagLogger::getInstance().endElement();
1166 : #endif
1167 2976 : }
1168 :
1169 8343 : void DomainMapperTableHandler::startCell(const Handle_t & start,
1170 : TablePropertyMapPtr pProps )
1171 : {
1172 8343 : sal_uInt32 nRow = m_aRowProperties.size();
1173 8343 : if ( pProps.get( ) )
1174 6096 : m_aCellProperties[nRow - 1].push_back( pProps );
1175 : else
1176 : {
1177 : // Adding an empty cell properties map to be able to get
1178 : // the table defaults properties
1179 2247 : TablePropertyMapPtr pEmptyProps( new TablePropertyMap( ) );
1180 2247 : m_aCellProperties[nRow - 1].push_back( pEmptyProps );
1181 : }
1182 :
1183 : #ifdef DEBUG_WRITERFILTER
1184 : TagLogger::getInstance().startElement("table.cell");
1185 : TagLogger::getInstance().startElement("table.cell.start");
1186 : TagLogger::getInstance().chars(XTextRangeToString(start));
1187 : TagLogger::getInstance().endElement();
1188 : if (pProps.get())
1189 : pProps->printProperties();
1190 : #endif
1191 :
1192 : //add a new 'row' of properties
1193 8343 : m_pCellSeq = CellSequencePointer_t(new CellSequence_t(2));
1194 8343 : if (!start.get())
1195 8418 : return;
1196 8266 : (*m_pCellSeq)[0] = start->getStart();
1197 : }
1198 :
1199 8341 : void DomainMapperTableHandler::endCell(const Handle_t & end)
1200 : {
1201 : #ifdef DEBUG_WRITERFILTER
1202 : TagLogger::getInstance().startElement("table.cell.end");
1203 : TagLogger::getInstance().chars(XTextRangeToString(end));
1204 : TagLogger::getInstance().endElement();
1205 : TagLogger::getInstance().endElement();
1206 : #endif
1207 :
1208 8341 : if (!end.get())
1209 8418 : return;
1210 8264 : (*m_pCellSeq)[1] = end->getEnd();
1211 8264 : (*m_pRowSeq)[m_nCellIndex] = *m_pCellSeq;
1212 8264 : ++m_nCellIndex;
1213 : }
1214 :
1215 : }}
1216 :
1217 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|