Bump version to 4.1-6
[LibreOffice.git] / writerfilter / source / dmapper / DomainMapperTableHandler.cxx
bloba79bc79e51f5d58967d906dd5f70858132804523
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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/XCellRange.hpp>
28 #include <com/sun/star/text/HoriOrientation.hpp>
29 #include <com/sun/star/text/RelOrientation.hpp>
30 #include <com/sun/star/text/SizeType.hpp>
31 #include <dmapperLoggers.hxx>
33 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
34 #include <PropertyMapHelper.hxx>
35 #include <rtl/ustring.hxx>
36 #endif
38 namespace writerfilter {
39 namespace dmapper {
41 using namespace ::com::sun::star;
42 using namespace ::std;
44 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
45 static void lcl_printProperties( PropertyMapPtr pProps )
47 if( pProps.get() )
49 dmapper_logger->startElement("properties");
51 PropertyMap::const_iterator aMapIter = pProps->begin();
52 PropertyMap::const_iterator aEndIter = pProps->end();
53 PropertyNameSupplier& rPropSupplier = PropertyNameSupplier::GetPropertyNameSupplier();
54 for( ; aMapIter != aEndIter; ++aMapIter )
56 SAL_INFO("writerfilter", rPropSupplier.GetName(aMapIter->first.eId));
58 table::BorderLine2 aLine;
59 sal_Int32 nColor;
60 if ( aMapIter->second >>= aLine )
62 dmapper_logger->startElement("borderline");
63 dmapper_logger->attribute("color", aLine.Color);
64 dmapper_logger->attribute("inner", aLine.InnerLineWidth);
65 dmapper_logger->attribute("outer", aLine.OuterLineWidth);
66 dmapper_logger->endElement();
68 else if ( aMapIter->second >>= nColor )
70 dmapper_logger->startElement("color");
71 dmapper_logger->attribute("number", nColor);
72 dmapper_logger->endElement();
76 dmapper_logger->endElement();
79 #endif
81 DomainMapperTableHandler::DomainMapperTableHandler(TextReference_t xText, DomainMapper_Impl& rDMapper_Impl)
82 : m_xText(xText),
83 m_rDMapper_Impl( rDMapper_Impl ),
84 m_nCellIndex(0),
85 m_nRowIndex(0)
89 DomainMapperTableHandler::~DomainMapperTableHandler()
93 void DomainMapperTableHandler::startTable(unsigned int nRows,
94 unsigned int /*nDepth*/,
95 TablePropertyMapPtr pProps)
97 m_aTableProperties = pProps;
98 m_pTableSeq = TableSequencePointer_t(new TableSequence_t(nRows));
99 m_nRowIndex = 0;
101 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
102 dmapper_logger->startElement("tablehandler.table");
103 dmapper_logger->attribute("rows", nRows);
105 if (pProps.get() != NULL)
106 pProps->dumpXml( dmapper_logger );
107 #endif
112 PropertyMapPtr lcl_SearchParentStyleSheetAndMergeProperties(const StyleSheetEntryPtr pStyleSheet, StyleSheetTablePtr pStyleSheetTable)
114 PropertyMapPtr pRet;
115 if(!pStyleSheet->sBaseStyleIdentifier.isEmpty())
117 const StyleSheetEntryPtr pParentStyleSheet = pStyleSheetTable->FindStyleSheetByISTD( pStyleSheet->sBaseStyleIdentifier );
118 pRet = lcl_SearchParentStyleSheetAndMergeProperties( pParentStyleSheet, pStyleSheetTable );
120 else
122 pRet.reset( new PropertyMap );
125 pRet->InsertProps(pStyleSheet->pProperties);
127 return pRet;
130 void lcl_mergeBorder( PropertyIds nId, PropertyMapPtr pOrig, PropertyMapPtr pDest )
132 PropertyDefinition aDef( nId, false );
133 PropertyMap::iterator pOrigIt = pOrig->find( aDef );
135 if ( pOrigIt != pOrig->end( ) )
137 pDest->Insert( nId, false, pOrigIt->second, false );
141 void lcl_computeCellBorders( PropertyMapPtr pTableBorders, PropertyMapPtr pCellProps,
142 sal_Int32 nCell, sal_Int32 nRow, bool bIsEndCol, bool bIsEndRow )
144 PropertyDefinition aVertPDef( META_PROP_VERTICAL_BORDER, false );
145 PropertyDefinition aHorizPDef( META_PROP_HORIZONTAL_BORDER, false );
147 PropertyMap::iterator aVerticalIter = pCellProps->find( aVertPDef );
148 PropertyMap::iterator aHorizontalIter = pCellProps->find( aHorizPDef );
150 // Handle the vertical and horizontal borders
151 bool bHasVert = ( aVerticalIter != pCellProps->end( ) );
152 uno::Any aVertProp;
153 if ( !bHasVert )
155 aVerticalIter = pTableBorders->find( aVertPDef );
156 bHasVert = ( aVerticalIter != pTableBorders->end( ) );
157 if ( bHasVert )
158 aVertProp = aVerticalIter->second;
160 else
162 aVertProp = aVerticalIter->second;
163 pCellProps->erase( aVerticalIter );
166 bool bHasHoriz = ( aHorizontalIter != pCellProps->end( ) );
167 uno::Any aHorizProp;
168 if ( !bHasHoriz )
170 aHorizontalIter = pTableBorders->find( aHorizPDef );
171 bHasHoriz = ( aHorizontalIter != pTableBorders->end( ) );
172 if ( bHasHoriz )
173 aHorizProp = aHorizontalIter->second;
175 else
177 aHorizProp = aHorizontalIter->second;
178 pCellProps->erase( aHorizontalIter );
181 if ( nCell == 0 )
183 lcl_mergeBorder( PROP_LEFT_BORDER, pTableBorders, pCellProps );
184 if ( bHasVert )
185 pCellProps->Insert( PROP_RIGHT_BORDER, false, aVertProp, false );
188 if ( bIsEndCol )
190 lcl_mergeBorder( PROP_RIGHT_BORDER, pTableBorders, pCellProps );
191 if ( bHasVert )
192 pCellProps->Insert( PROP_LEFT_BORDER, false, aVertProp, false );
195 if ( nCell > 0 && !bIsEndCol )
197 if ( bHasVert )
199 pCellProps->Insert( PROP_RIGHT_BORDER, false, aVertProp, false );
200 pCellProps->Insert( PROP_LEFT_BORDER, false, aVertProp, false );
204 if ( nRow == 0 )
206 lcl_mergeBorder( PROP_TOP_BORDER, pTableBorders, pCellProps );
207 if ( bHasHoriz )
208 pCellProps->Insert( PROP_BOTTOM_BORDER, false, aHorizProp, false );
211 if ( bIsEndRow )
213 lcl_mergeBorder( PROP_BOTTOM_BORDER, pTableBorders, pCellProps );
214 if ( bHasHoriz )
215 pCellProps->Insert( PROP_TOP_BORDER, false, aHorizProp, false );
218 if ( nRow > 0 && !bIsEndRow )
220 if ( bHasHoriz )
222 pCellProps->Insert( PROP_TOP_BORDER, false, aHorizProp, false );
223 pCellProps->Insert( PROP_BOTTOM_BORDER, false, aHorizProp, false );
228 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
230 void lcl_debug_BorderLine(table::BorderLine & rLine)
232 dmapper_logger->startElement("BorderLine");
233 dmapper_logger->attribute("Color", rLine.Color);
234 dmapper_logger->attribute("InnerLineWidth", rLine.InnerLineWidth);
235 dmapper_logger->attribute("OuterLineWidth", rLine.OuterLineWidth);
236 dmapper_logger->attribute("LineDistance", rLine.LineDistance);
237 dmapper_logger->endElement();
240 void lcl_debug_TableBorder(table::TableBorder & rBorder)
242 dmapper_logger->startElement("TableBorder");
243 lcl_debug_BorderLine(rBorder.TopLine);
244 dmapper_logger->attribute("IsTopLineValid", rBorder.IsTopLineValid);
245 lcl_debug_BorderLine(rBorder.BottomLine);
246 dmapper_logger->attribute("IsBottomLineValid", rBorder.IsBottomLineValid);
247 lcl_debug_BorderLine(rBorder.LeftLine);
248 dmapper_logger->attribute("IsLeftLineValid", rBorder.IsLeftLineValid);
249 lcl_debug_BorderLine(rBorder.RightLine);
250 dmapper_logger->attribute("IsRightLineValid", rBorder.IsRightLineValid);
251 lcl_debug_BorderLine(rBorder.VerticalLine);
252 dmapper_logger->attribute("IsVerticalLineValid", rBorder.IsVerticalLineValid);
253 lcl_debug_BorderLine(rBorder.HorizontalLine);
254 dmapper_logger->attribute("IsHorizontalLineValid", rBorder.IsHorizontalLineValid);
255 dmapper_logger->attribute("Distance", rBorder.Distance);
256 dmapper_logger->attribute("IsDistanceValid", rBorder.IsDistanceValid);
257 dmapper_logger->endElement();
259 #endif
261 struct WRITERFILTER_DLLPRIVATE TableInfo
263 sal_Int32 nLeftBorderDistance;
264 sal_Int32 nRightBorderDistance;
265 sal_Int32 nTopBorderDistance;
266 sal_Int32 nBottomBorderDistance;
267 sal_Int32 nTblLook;
268 sal_Int32 nNestLevel;
269 PropertyMapPtr pTableDefaults;
270 PropertyMapPtr pTableBorders;
271 TableStyleSheetEntry* pTableStyle;
272 TablePropertyValues_t aTableProperties;
274 TableInfo()
275 : nLeftBorderDistance(DEF_BORDER_DIST)
276 , nRightBorderDistance(DEF_BORDER_DIST)
277 , nTopBorderDistance(0)
278 , nBottomBorderDistance(0)
279 , nTblLook(0x4a0)
280 , nNestLevel(0)
281 , pTableDefaults(new PropertyMap)
282 , pTableBorders(new PropertyMap)
283 , pTableStyle(NULL)
289 namespace
292 bool lcl_extractTableBorderProperty(PropertyMapPtr pTableProperties, const PropertyIds nId, TableInfo& rInfo, table::BorderLine2& rLine)
294 PropertyMap::iterator aTblBorderIter = pTableProperties->find( PropertyDefinition(nId, false) );
295 if( aTblBorderIter != pTableProperties->end() )
297 OSL_VERIFY(aTblBorderIter->second >>= rLine);
299 rInfo.pTableBorders->Insert( nId, false, uno::makeAny( rLine ) );
300 PropertyMap::iterator pIt = rInfo.pTableDefaults->find( PropertyDefinition( nId, false ) );
301 if ( pIt != rInfo.pTableDefaults->end( ) )
302 rInfo.pTableDefaults->erase( pIt );
304 return true;
307 return false;
312 TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo & rInfo, uno::Sequence<beans::PropertyValue>& rFrameProperties)
314 // will receive the table style if any
315 TableStyleSheetEntry* pTableStyle = NULL;
317 if( m_aTableProperties.get() )
319 //create properties from the table attributes
320 //...pPropMap->Insert( PROP_LEFT_MARGIN, false, uno::makeAny( m_nLeftMargin - m_nGapHalf ));
321 //pPropMap->Insert( PROP_HORI_ORIENT, false, uno::makeAny( text::HoriOrientation::RIGHT ));
322 sal_Int32 nGapHalf = 0;
323 sal_Int32 nLeftMargin = 0;
324 sal_Int32 nTableWidth = 0;
325 sal_Int32 nTableWidthType = text::SizeType::FIX;
327 PropertyMap::iterator aTableStyleIter =
328 m_aTableProperties->find( PropertyDefinition( META_PROP_TABLE_STYLE_NAME, false ) );
329 if(aTableStyleIter != m_aTableProperties->end())
331 // Apply table style properties recursively
332 OUString sTableStyleName;
333 aTableStyleIter->second >>= sTableStyleName;
334 StyleSheetTablePtr pStyleSheetTable = m_rDMapper_Impl.GetStyleSheetTable();
335 const StyleSheetEntryPtr pStyleSheet = pStyleSheetTable->FindStyleSheetByISTD( sTableStyleName );
336 pTableStyle = dynamic_cast<TableStyleSheetEntry*>( pStyleSheet.get( ) );
337 m_aTableProperties->erase( aTableStyleIter );
339 if( pStyleSheet )
341 // First get the style properties, then the table ones
342 PropertyMapPtr pTableProps( m_aTableProperties );
343 TablePropertyMapPtr pEmptyProps( new TablePropertyMap );
345 m_aTableProperties = pEmptyProps;
347 PropertyMapPtr pMergedProperties = lcl_SearchParentStyleSheetAndMergeProperties(pStyleSheet, pStyleSheetTable);
349 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
350 dmapper_logger->startElement("mergedProps");
351 pMergedProperties->dumpXml( dmapper_logger );
352 dmapper_logger->endElement();
353 #endif
355 m_aTableProperties->InsertProps(pMergedProperties);
356 m_aTableProperties->InsertProps(pTableProps);
358 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
359 dmapper_logger->startElement("TableProperties");
360 m_aTableProperties->dumpXml( dmapper_logger );
361 dmapper_logger->endElement();
362 #endif
366 PropertyMap::iterator const aTblLookIter =
367 m_aTableProperties->find(PropertyDefinition(PROP_TBL_LOOK, false));
368 if(aTblLookIter != m_aTableProperties->end())
370 aTblLookIter->second >>= rInfo.nTblLook;
371 m_aTableProperties->erase( aTblLookIter );
374 // Set the table default attributes for the cells
375 rInfo.pTableDefaults->InsertProps(m_aTableProperties);
377 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
378 dmapper_logger->startElement("TableDefaults");
379 rInfo.pTableDefaults->dumpXml( dmapper_logger );
380 dmapper_logger->endElement();
381 #endif
383 m_aTableProperties->getValue( TablePropertyMap::GAP_HALF, nGapHalf );
384 m_aTableProperties->getValue( TablePropertyMap::LEFT_MARGIN, nLeftMargin );
386 m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_LEFT,
387 rInfo.nLeftBorderDistance );
388 m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_RIGHT,
389 rInfo.nRightBorderDistance );
390 m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_TOP,
391 rInfo.nTopBorderDistance );
392 m_aTableProperties->getValue( TablePropertyMap::CELL_MAR_BOTTOM,
393 rInfo.nBottomBorderDistance );
395 table::TableBorderDistances aDistances;
396 aDistances.IsTopDistanceValid =
397 aDistances.IsBottomDistanceValid =
398 aDistances.IsLeftDistanceValid =
399 aDistances.IsRightDistanceValid = sal_True;
400 aDistances.TopDistance = static_cast<sal_Int16>( rInfo.nTopBorderDistance );
401 aDistances.BottomDistance = static_cast<sal_Int16>( rInfo.nBottomBorderDistance );
402 aDistances.LeftDistance = static_cast<sal_Int16>( rInfo.nLeftBorderDistance );
403 aDistances.RightDistance = static_cast<sal_Int16>( rInfo.nRightBorderDistance );
405 m_aTableProperties->Insert( PROP_TABLE_BORDER_DISTANCES, false, uno::makeAny( aDistances ) );
407 // Set table above/bottom spacing to 0.
408 // TODO: handle 'Around' text wrapping mode
409 m_aTableProperties->Insert( PROP_TOP_MARGIN, true, uno::makeAny( sal_Int32( 0 ) ) );
410 m_aTableProperties->Insert( PROP_BOTTOM_MARGIN, true, uno::makeAny( sal_Int32( 0 ) ) );
412 //table border settings
413 table::TableBorder aTableBorder;
414 table::BorderLine2 aBorderLine, aLeftBorder;
416 if (lcl_extractTableBorderProperty(m_aTableProperties, PROP_TOP_BORDER, rInfo, aBorderLine))
418 aTableBorder.TopLine = aBorderLine;
419 aTableBorder.IsTopLineValid = sal_True;
421 if (lcl_extractTableBorderProperty(m_aTableProperties, PROP_BOTTOM_BORDER, rInfo, aBorderLine))
423 aTableBorder.BottomLine = aBorderLine;
424 aTableBorder.IsBottomLineValid = sal_True;
426 if (lcl_extractTableBorderProperty(m_aTableProperties, PROP_LEFT_BORDER, rInfo, aLeftBorder))
428 aTableBorder.LeftLine = aLeftBorder;
429 aTableBorder.IsLeftLineValid = sal_True;
430 // Only top level table position depends on border width
431 if (rInfo.nNestLevel == 1)
433 if (!rFrameProperties.hasElements())
434 rInfo.nLeftBorderDistance += aLeftBorder.LineWidth * 0.5;
435 else
437 // If this is a floating table, then the position of the frame should be adjusted, instead.
438 for (sal_Int32 i = 0; i < rFrameProperties.getLength(); ++i)
440 beans::PropertyValue& rPropertyValue = rFrameProperties[i];
441 if (rPropertyValue.Name == "HoriOrientPosition")
443 sal_Int32 nValue = rPropertyValue.Value.get<sal_Int32>();
444 nValue -= aLeftBorder.LineWidth * 0.5;
445 rPropertyValue.Value <<= nValue;
446 break;
452 if (lcl_extractTableBorderProperty(m_aTableProperties, PROP_RIGHT_BORDER, rInfo, aBorderLine))
454 aTableBorder.RightLine = aBorderLine;
455 aTableBorder.IsRightLineValid = sal_True;
457 if (lcl_extractTableBorderProperty(m_aTableProperties, META_PROP_HORIZONTAL_BORDER, rInfo, aBorderLine))
459 aTableBorder.HorizontalLine = aBorderLine;
460 aTableBorder.IsHorizontalLineValid = sal_True;
462 if (lcl_extractTableBorderProperty(m_aTableProperties, META_PROP_VERTICAL_BORDER, rInfo, aBorderLine))
464 aTableBorder.VerticalLine = aBorderLine;
465 aTableBorder.IsVerticalLineValid = sal_True;
468 aTableBorder.Distance = 0;
469 aTableBorder.IsDistanceValid = sal_False;
471 m_aTableProperties->Insert( PROP_TABLE_BORDER, false, uno::makeAny( aTableBorder ) );
473 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
474 lcl_debug_TableBorder(aTableBorder);
475 #endif
477 // Table position in Office is computed in 2 different ways :
478 // - top level tables: the goal is to have in-cell text starting at table indent pos (tblInd),
479 // so table's position depends on table's cells margin
480 // - nested tables: the goal is to have left-most border starting at table_indent pos
481 if (rInfo.nNestLevel > 1)
483 m_aTableProperties->Insert( PROP_LEFT_MARGIN, false, uno::makeAny( nLeftMargin - nGapHalf ));
485 else
487 m_aTableProperties->Insert( PROP_LEFT_MARGIN, false, uno::makeAny( nLeftMargin - nGapHalf - rInfo.nLeftBorderDistance ));
490 m_aTableProperties->getValue( TablePropertyMap::TABLE_WIDTH, nTableWidth );
491 m_aTableProperties->getValue( TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType );
492 if( nTableWidthType == text::SizeType::FIX )
494 if( nTableWidth > 0 )
495 m_aTableProperties->Insert( PROP_WIDTH, false, uno::makeAny( nTableWidth ));
497 else
499 m_aTableProperties->Insert( PROP_RELATIVE_WIDTH, false, uno::makeAny( sal_Int16( nTableWidth ) ) );
500 m_aTableProperties->Insert( PROP_IS_WIDTH_RELATIVE, false, uno::makeAny( sal_Bool( sal_True ) ) );
503 sal_Int32 nHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
504 m_aTableProperties->getValue( TablePropertyMap::HORI_ORIENT, nHoriOrient ) ;
505 m_aTableProperties->Insert( PROP_HORI_ORIENT, false, uno::makeAny( sal_Int16(nHoriOrient) ) );
507 //fill default value - if not available
508 const PropertyMap::const_iterator aRepeatIter =
509 m_aTableProperties->find( PropertyDefinition( PROP_HEADER_ROW_COUNT, false ) );
510 if( aRepeatIter == m_aTableProperties->end() )
511 m_aTableProperties->Insert( PROP_HEADER_ROW_COUNT, false, uno::makeAny( (sal_Int32)0 ));
513 rInfo.aTableProperties = m_aTableProperties->GetPropertyValues();
515 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
516 dmapper_logger->startElement("debug.tableprops");
517 m_aTableProperties->dumpXml( dmapper_logger );
518 dmapper_logger->endElement();
519 #endif
523 return pTableStyle;
526 #define CNF_FIRST_ROW 0x800
527 #define CNF_LAST_ROW 0x400
528 #define CNF_FIRST_COLUMN 0x200
529 #define CNF_LAST_COLUMN 0x100
530 #define CNF_ODD_VBAND 0x080
531 #define CNF_EVEN_VBAND 0x040
532 #define CNF_ODD_HBAND 0x020
533 #define CNF_EVEN_HBAND 0x010
534 #define CNF_FIRST_ROW_LAST_COLUMN 0x008
535 #define CNF_FIRST_ROW_FIRST_COLUMN 0x004
536 #define CNF_LAST_ROW_LAST_COLUMN 0x002
537 #define CNF_LAST_ROW_FIRST_COLUMN 0x001
539 CellPropertyValuesSeq_t DomainMapperTableHandler::endTableGetCellProperties(TableInfo & rInfo, std::vector<HorizontallyMergedCell>& rMerges)
541 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
542 dmapper_logger->startElement("getCellProperties");
543 #endif
545 CellPropertyValuesSeq_t aCellProperties( m_aCellProperties.size() );
547 if ( !m_aCellProperties.size() )
549 #ifdef DEBUG_DOMAINMAPPER
550 dmapper_logger->endElement();
551 #endif
552 return aCellProperties;
554 // std::vector< std::vector<PropertyMapPtr> > m_aCellProperties
555 PropertyMapVector2::const_iterator aRowOfCellsIterator = m_aCellProperties.begin();
556 PropertyMapVector2::const_iterator aRowOfCellsIteratorEnd = m_aCellProperties.end();
557 PropertyMapVector2::const_iterator aLastRowIterator = m_aCellProperties.end() - 1;
558 sal_Int32 nRow = 0;
560 //it's a uno::Sequence< beans::PropertyValues >*
561 RowPropertyValuesSeq_t* pCellProperties = aCellProperties.getArray();
562 while( aRowOfCellsIterator != aRowOfCellsIteratorEnd )
564 //aRowOfCellsIterator points to a vector of PropertyMapPtr
565 PropertyMapVector1::const_iterator aCellIterator = aRowOfCellsIterator->begin();
566 PropertyMapVector1::const_iterator aCellIteratorEnd = aRowOfCellsIterator->end();
568 sal_Int32 nRowStyleMask = 0;
570 if (aRowOfCellsIterator==m_aCellProperties.begin())
572 if(rInfo.nTblLook&0x20)
573 nRowStyleMask |= CNF_FIRST_ROW; // first row style used
575 else if (aRowOfCellsIterator==aLastRowIterator)
577 if(rInfo.nTblLook&0x40)
578 nRowStyleMask |= CNF_LAST_ROW; // last row style used
580 if(!nRowStyleMask) // if no row style used yet
582 // banding used only if not first and or last row style used
583 if(!(rInfo.nTblLook&0x200))
584 { // hbanding used
585 int n = nRow + 1;
586 if(rInfo.nTblLook&0x20)
587 n++;
588 if(n & 1)
589 nRowStyleMask = CNF_ODD_HBAND;
590 else
591 nRowStyleMask = CNF_EVEN_HBAND;
595 sal_Int32 nCell = 0;
596 pCellProperties[nRow].realloc( aRowOfCellsIterator->size() );
597 beans::PropertyValues* pSingleCellProperties = pCellProperties[nRow].getArray();
598 while( aCellIterator != aCellIteratorEnd )
600 PropertyMapPtr pAllCellProps( new PropertyMap );
602 PropertyMapVector1::const_iterator aLastCellIterator = aRowOfCellsIterator->end() - 1;
603 bool bIsEndCol = aCellIterator == aLastCellIterator;
604 bool bIsEndRow = aRowOfCellsIterator == aLastRowIterator;
606 //aCellIterator points to a PropertyMapPtr;
607 if( aCellIterator->get() )
609 if ( rInfo.pTableDefaults->size( ) )
610 pAllCellProps->InsertProps(rInfo.pTableDefaults);
612 sal_Int32 nCellStyleMask = 0;
613 if (aCellIterator==aRowOfCellsIterator->begin())
615 if(rInfo.nTblLook&0x80)
616 nCellStyleMask = CNF_FIRST_COLUMN; // first col style used
618 else if (bIsEndCol)
620 if(rInfo.nTblLook&0x100)
621 nCellStyleMask = CNF_LAST_COLUMN; // last col style used
623 if(!nCellStyleMask) // if no cell style is used yet
625 if(!(rInfo.nTblLook&0x400))
626 { // vbanding used
627 int n = nCell + 1;
628 if(rInfo.nTblLook&0x80)
629 n++;
630 if(n & 1)
631 nCellStyleMask = CNF_ODD_VBAND;
632 else
633 nCellStyleMask = CNF_EVEN_VBAND;
636 sal_Int32 nCnfStyleMask = nCellStyleMask + nRowStyleMask;
637 if(nCnfStyleMask == CNF_FIRST_COLUMN + CNF_FIRST_ROW)
638 nCnfStyleMask |= CNF_FIRST_ROW_FIRST_COLUMN;
639 else if(nCnfStyleMask == CNF_FIRST_COLUMN + CNF_LAST_ROW)
640 nCnfStyleMask |= CNF_LAST_ROW_FIRST_COLUMN;
641 else if(nCnfStyleMask == CNF_LAST_COLUMN + CNF_FIRST_ROW)
642 nCnfStyleMask |= CNF_FIRST_ROW_LAST_COLUMN;
643 else if(nCnfStyleMask == CNF_LAST_COLUMN + CNF_LAST_ROW)
644 nCnfStyleMask |= CNF_LAST_ROW_LAST_COLUMN;
646 if ( rInfo.pTableStyle )
648 PropertyMapPtr pStyleProps = rInfo.pTableStyle->GetProperties( nCnfStyleMask );
649 pAllCellProps->InsertProps( pStyleProps );
652 // Remove properties from style/row that aren't allowed in cells
653 const PropertyMap::iterator aDefaultRepeatIt =
654 pAllCellProps->find(
655 PropertyDefinition( PROP_HEADER_ROW_COUNT, false ) );
656 if ( aDefaultRepeatIt != pAllCellProps->end( ) )
657 pAllCellProps->erase( aDefaultRepeatIt );
659 // Then add the cell properties
660 pAllCellProps->InsertProps(*aCellIterator);
661 aCellIterator->get( )->swap( *pAllCellProps.get( ) );
663 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
664 dmapper_logger->startElement("cell");
665 dmapper_logger->attribute("cell", nCell);
666 dmapper_logger->attribute("row", nRow);
667 #endif
669 lcl_computeCellBorders( rInfo.pTableBorders, *aCellIterator, nCell, nRow, bIsEndCol, bIsEndRow );
671 //now set the default left+right border distance TODO: there's an sprm containing the default distance!
672 const PropertyMap::const_iterator aLeftDistanceIter =
673 aCellIterator->get()->find( PropertyDefinition(PROP_LEFT_BORDER_DISTANCE, false) );
674 if( aLeftDistanceIter == aCellIterator->get()->end() )
675 aCellIterator->get()->Insert( PROP_LEFT_BORDER_DISTANCE, false,
676 uno::makeAny(rInfo.nLeftBorderDistance ) );
677 const PropertyMap::const_iterator aRightDistanceIter =
678 aCellIterator->get()->find( PropertyDefinition(PROP_RIGHT_BORDER_DISTANCE, false) );
679 if( aRightDistanceIter == aCellIterator->get()->end() )
680 aCellIterator->get()->Insert( PROP_RIGHT_BORDER_DISTANCE, false,
681 uno::makeAny((sal_Int32) rInfo.nRightBorderDistance ) );
683 const PropertyMap::const_iterator aTopDistanceIter =
684 aCellIterator->get()->find( PropertyDefinition(PROP_TOP_BORDER_DISTANCE, false) );
685 if( aTopDistanceIter == aCellIterator->get()->end() )
686 aCellIterator->get()->Insert( PROP_TOP_BORDER_DISTANCE, false,
687 uno::makeAny((sal_Int32) rInfo.nTopBorderDistance ) );
689 const PropertyMap::const_iterator aBottomDistanceIter =
690 aCellIterator->get()->find( PropertyDefinition(PROP_BOTTOM_BORDER_DISTANCE, false) );
691 if( aBottomDistanceIter == aCellIterator->get()->end() )
692 aCellIterator->get()->Insert( PROP_BOTTOM_BORDER_DISTANCE, false,
693 uno::makeAny((sal_Int32) rInfo.nBottomBorderDistance ) );
695 // Horizontal merge is not an UNO property, extract that info here to rMerges, and then remove it from the map.
696 const PropertyMap::const_iterator aHorizontalMergeIter = aCellIterator->get()->find(PropertyDefinition(PROP_HORIZONTAL_MERGE, false));
697 if (aHorizontalMergeIter != aCellIterator->get()->end())
699 if (aHorizontalMergeIter->second.get<sal_Bool>())
701 // first cell in a merge
702 HorizontallyMergedCell aMerge(nRow, nCell);
703 rMerges.push_back(aMerge);
705 else if (!rMerges.empty())
707 // resuming an earlier merge
708 HorizontallyMergedCell& rMerge = rMerges.back();
709 rMerge.m_nLastRow = nRow;
710 rMerge.m_nLastCol = nCell;
712 aCellIterator->get()->erase(PropertyDefinition(PROP_HORIZONTAL_MERGE, false));
714 pSingleCellProperties[nCell] = aCellIterator->get()->GetPropertyValues();
715 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
716 dmapper_logger->endElement();
717 #endif
719 ++nCell;
720 ++aCellIterator;
722 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
723 //-->debug cell properties
725 OUString sNames;
726 const uno::Sequence< beans::PropertyValues > aDebugCurrentRow = aCellProperties[nRow];
727 sal_Int32 nDebugCells = aDebugCurrentRow.getLength();
728 (void) nDebugCells;
729 for( sal_Int32 nDebugCell = 0; nDebugCell < nDebugCells; ++nDebugCell)
731 const uno::Sequence< beans::PropertyValue >& aDebugCellProperties = aDebugCurrentRow[nDebugCell];
732 sal_Int32 nDebugCellProperties = aDebugCellProperties.getLength();
733 for( sal_Int32 nDebugProperty = 0; nDebugProperty < nDebugCellProperties; ++nDebugProperty)
735 const OUString sName = aDebugCellProperties[nDebugProperty].Name;
736 sNames += sName;
737 sNames += OUString('-');
739 sNames += OUString('\n');
741 (void)sNames;
743 //--<
744 #endif
745 ++nRow;
746 ++aRowOfCellsIterator;
749 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
750 dmapper_logger->endElement();
751 #endif
753 return aCellProperties;
756 RowPropertyValuesSeq_t DomainMapperTableHandler::endTableGetRowProperties()
758 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
759 dmapper_logger->startElement("getRowProperties");
760 #endif
762 RowPropertyValuesSeq_t aRowProperties( m_aRowProperties.size() );
763 PropertyMapVector1::const_iterator aRowIter = m_aRowProperties.begin();
764 PropertyMapVector1::const_iterator aRowIterEnd = m_aRowProperties.end();
765 sal_Int32 nRow = 0;
766 while( aRowIter != aRowIterEnd )
768 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
769 dmapper_logger->startElement("rowProps.row");
770 #endif
771 if( aRowIter->get() )
773 //set default to 'break across pages"
774 if( aRowIter->get()->find( PropertyDefinition( PROP_IS_SPLIT_ALLOWED, false )) == aRowIter->get()->end())
775 aRowIter->get()->Insert( PROP_IS_SPLIT_ALLOWED, false, uno::makeAny(sal_True ) );
777 aRowProperties[nRow] = (*aRowIter)->GetPropertyValues();
778 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
779 ((*aRowIter)->dumpXml( dmapper_logger ));
780 lcl_DumpPropertyValues(dmapper_logger, aRowProperties[nRow]);
781 #endif
783 ++nRow;
784 ++aRowIter;
785 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
786 dmapper_logger->endElement();
787 #endif
790 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
791 dmapper_logger->endElement();
792 #endif
794 return aRowProperties;
797 // Apply paragraph property to each paragraph within a cell.
798 static void lcl_ApplyCellParaProps(uno::Reference<table::XCell> xCell, uno::Any aBottomMargin)
800 uno::Reference<container::XEnumerationAccess> xEnumerationAccess(xCell, uno::UNO_QUERY);
801 uno::Reference<container::XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
802 while (xEnumeration->hasMoreElements())
804 uno::Reference<beans::XPropertySet> xParagraph(xEnumeration->nextElement(), uno::UNO_QUERY);
805 uno::Reference<beans::XPropertyState> xPropertyState(xParagraph, uno::UNO_QUERY);
806 // Don't apply in case direct formatting is already present.
807 // TODO: probably paragraph style has priority over table style here.
808 if (xPropertyState.is() && xPropertyState->getPropertyState("ParaBottomMargin") == beans::PropertyState_DEFAULT_VALUE)
809 xParagraph->setPropertyValue("ParaBottomMargin", aBottomMargin);
813 void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel)
815 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
816 dmapper_logger->startElement("tablehandler.endTable");
817 #endif
819 // If we want to make this table a floating one.
820 uno::Sequence<beans::PropertyValue> aFrameProperties = m_rDMapper_Impl.getTableManager().getCurrentTablePosition();
821 TableInfo aTableInfo;
822 aTableInfo.nNestLevel = nestedTableLevel;
823 aTableInfo.pTableStyle = endTableGetTableStyle(aTableInfo, aFrameProperties);
824 // expands to uno::Sequence< Sequence< beans::PropertyValues > >
826 std::vector<HorizontallyMergedCell> aMerges;
827 CellPropertyValuesSeq_t aCellProperties = endTableGetCellProperties(aTableInfo, aMerges);
829 RowPropertyValuesSeq_t aRowProperties = endTableGetRowProperties();
831 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
832 lcl_DumpPropertyValueSeq(dmapper_logger, aRowProperties);
833 #endif
835 if (m_pTableSeq->getLength() > 0)
837 uno::Reference<text::XTextRange> xStart;
838 uno::Reference<text::XTextRange> xEnd;
840 bool bFloating = aFrameProperties.hasElements();
841 // Additional checks: if we can do this.
842 if (bFloating && (*m_pTableSeq)[0].getLength() > 0 && (*m_pTableSeq)[0][0].getLength() > 0)
844 xStart = (*m_pTableSeq)[0][0][0];
845 uno::Sequence< uno::Sequence< uno::Reference<text::XTextRange> > >& rLastRow = (*m_pTableSeq)[m_pTableSeq->getLength() - 1];
846 uno::Sequence< uno::Reference<text::XTextRange> >& rLastCell = rLastRow[rLastRow.getLength() - 1];
847 xEnd = rLastCell[1];
849 uno::Reference<text::XTextTable> xTable;
852 if (m_xText.is())
854 xTable = m_xText->convertToTable(*m_pTableSeq,
855 aCellProperties,
856 aRowProperties,
857 aTableInfo.aTableProperties);
859 if (xTable.is())
861 m_xTableRange = xTable->getAnchor( );
863 if (!aMerges.empty())
865 // Perform horizontal merges in reverse order, so the fact that merging changes the position of cells won't cause a problem for us.
866 for (std::vector<HorizontallyMergedCell>::reverse_iterator it = aMerges.rbegin(); it != aMerges.rend(); ++it)
868 uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY_THROW);
869 uno::Reference<beans::XPropertySet> xCell(xCellRange->getCellByPosition(it->m_nFirstCol, it->m_nFirstRow), uno::UNO_QUERY_THROW);
870 OUString aFirst = xCell->getPropertyValue("CellName").get<OUString>();
871 xCell.set(xCellRange->getCellByPosition(it->m_nLastCol, it->m_nLastRow), uno::UNO_QUERY_THROW);
872 OUString aLast = xCell->getPropertyValue("CellName").get<OUString>();
874 uno::Reference<text::XTextTableCursor> xCursor = xTable->createCursorByCellName(aFirst);
875 xCursor->gotoCellByName(aLast, true);
876 xCursor->mergeRange();
881 // OOXML table style may container paragraph properties, apply these now.
882 for (int i = 0; i < aTableInfo.aTableProperties.getLength(); ++i)
884 if (aTableInfo.aTableProperties[i].Name == "ParaBottomMargin")
886 uno::Reference<table::XCellRange> xCellRange(xTable, uno::UNO_QUERY);
887 uno::Any aBottomMargin = aTableInfo.aTableProperties[i].Value;
888 sal_Int32 nRows = aCellProperties.getLength();
889 for (sal_Int32 nRow = 0; nRow < nRows; ++nRow)
891 const uno::Sequence< beans::PropertyValues > aCurrentRow = aCellProperties[nRow];
892 sal_Int32 nCells = aCurrentRow.getLength();
893 for (sal_Int32 nCell = 0; nCell < nCells; ++nCell)
894 lcl_ApplyCellParaProps(xCellRange->getCellByPosition(nCell, nRow), aBottomMargin);
896 break;
901 catch ( const lang::IllegalArgumentException &e )
903 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
904 fprintf( stderr, "Conversion to table error: %s\n",
905 OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr() );
906 dmapper_logger->chars(std::string("failed to import table!"));
907 #else
908 (void)e;
909 #endif
911 catch ( const uno::Exception &e )
913 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
914 fprintf( stderr, "Exception during table creation: %s\n",
915 OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8 ).getStr( ) );
916 #else
917 (void) e;
918 #endif
921 // If we have a table with a start and an end position, we should make it a floating one.
922 if (xTable.is() && xStart.is() && xEnd.is())
924 uno::Reference<beans::XPropertySet> xTableProperties(xTable, uno::UNO_QUERY);
925 sal_Bool bIsRelative = sal_False;
926 xTableProperties->getPropertyValue("IsWidthRelative") >>= bIsRelative;
927 if (!bIsRelative)
929 aFrameProperties.realloc(aFrameProperties.getLength() + 1);
930 aFrameProperties[aFrameProperties.getLength() - 1].Name = "Width";
931 aFrameProperties[aFrameProperties.getLength() - 1].Value = xTableProperties->getPropertyValue("Width");
933 else
935 aFrameProperties.realloc(aFrameProperties.getLength() + 1);
936 aFrameProperties[aFrameProperties.getLength() - 1].Name = "FrameWidthPercent";
937 aFrameProperties[aFrameProperties.getLength() - 1].Value = xTableProperties->getPropertyValue("RelativeWidth");
939 // Applying the relative width to the frame, needs to have the table width to be 100% of the frame width
940 xTableProperties->setPropertyValue("RelativeWidth", uno::makeAny(sal_Int16(100)));
943 // A non-zero left margin would move the table out of the frame, move the frame itself instead.
944 xTableProperties->setPropertyValue("LeftMargin", uno::makeAny(sal_Int32(0)));
946 // In case the document ends with a table, we're called after
947 // SectionPropertyMap::CloseSectionGroup(), so we'll have no idea
948 // about the text area width, nor can fix this by delaying the text
949 // frame conversion: just do it here.
950 // Also, we the anchor is within a table, then do it here as well,
951 // as xStart/xEnd would not point to the start/end at conversion
952 // time anyway.
953 sal_Int32 nTableWidth = 0;
954 m_aTableProperties->getValue(TablePropertyMap::TABLE_WIDTH, nTableWidth);
955 if (m_rDMapper_Impl.GetSectionContext() && nestedTableLevel <= 1)
956 m_rDMapper_Impl.m_aPendingFloatingTables.push_back(FloatingTableInfo(xStart, xEnd, aFrameProperties, nTableWidth));
957 else
958 m_xText->convertToTextFrame(xStart, xEnd, aFrameProperties);
962 m_aTableProperties.reset();
963 m_aCellProperties.clear();
964 m_aRowProperties.clear();
966 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
967 dmapper_logger->endElement();
968 dmapper_logger->endElement();
969 #endif
972 void DomainMapperTableHandler::startRow(unsigned int nCells,
973 TablePropertyMapPtr pProps)
975 m_aRowProperties.push_back( pProps );
976 m_aCellProperties.push_back( PropertyMapVector1() );
978 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
979 dmapper_logger->startElement("table.row");
980 dmapper_logger->attribute("cells", nCells);
981 if (pProps != NULL)
982 pProps->dumpXml(dmapper_logger);
983 #endif
985 m_pRowSeq = RowSequencePointer_t(new RowSequence_t(nCells));
986 m_nCellIndex = 0;
989 void DomainMapperTableHandler::endRow()
991 (*m_pTableSeq)[m_nRowIndex] = *m_pRowSeq;
992 ++m_nRowIndex;
993 m_nCellIndex = 0;
994 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
995 dmapper_logger->endElement();
996 #endif
999 void DomainMapperTableHandler::startCell(const Handle_t & start,
1000 TablePropertyMapPtr pProps )
1002 sal_uInt32 nRow = m_aRowProperties.size();
1003 if ( pProps.get( ) )
1004 m_aCellProperties[nRow - 1].push_back( pProps );
1005 else
1007 // Adding an empty cell properties map to be able to get
1008 // the table defaults properties
1009 TablePropertyMapPtr pEmptyProps( new TablePropertyMap( ) );
1010 m_aCellProperties[nRow - 1].push_back( pEmptyProps );
1013 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
1014 dmapper_logger->startElement("table.cell");
1015 dmapper_logger->startElement("table.cell.start");
1016 dmapper_logger->chars(toString(start));
1017 dmapper_logger->endElement();
1018 lcl_printProperties( pProps );
1019 #endif
1021 //add a new 'row' of properties
1022 m_pCellSeq = CellSequencePointer_t(new CellSequence_t(2));
1023 if (!start.get())
1024 return;
1025 (*m_pCellSeq)[0] = start->getStart();
1028 void DomainMapperTableHandler::endCell(const Handle_t & end)
1030 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
1031 dmapper_logger->startElement("table.cell.end");
1032 dmapper_logger->chars(toString(end));
1033 dmapper_logger->endElement();
1034 dmapper_logger->endElement();
1035 #endif
1037 if (!end.get())
1038 return;
1039 (*m_pCellSeq)[1] = end->getEnd();
1040 (*m_pRowSeq)[m_nCellIndex] = *m_pCellSeq;
1041 ++m_nCellIndex;
1046 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */