1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
38 namespace writerfilter
{
41 using namespace ::com::sun::star
;
42 using namespace ::std
;
44 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
45 static void lcl_printProperties( PropertyMapPtr pProps
)
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
;
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();
81 DomainMapperTableHandler::DomainMapperTableHandler(TextReference_t xText
, DomainMapper_Impl
& rDMapper_Impl
)
83 m_rDMapper_Impl( rDMapper_Impl
),
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
));
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
);
112 PropertyMapPtr
lcl_SearchParentStyleSheetAndMergeProperties(const StyleSheetEntryPtr pStyleSheet
, StyleSheetTablePtr pStyleSheetTable
)
115 if(!pStyleSheet
->sBaseStyleIdentifier
.isEmpty())
117 const StyleSheetEntryPtr pParentStyleSheet
= pStyleSheetTable
->FindStyleSheetByISTD( pStyleSheet
->sBaseStyleIdentifier
);
118 pRet
= lcl_SearchParentStyleSheetAndMergeProperties( pParentStyleSheet
, pStyleSheetTable
);
122 pRet
.reset( new PropertyMap
);
125 pRet
->InsertProps(pStyleSheet
->pProperties
);
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( ) );
155 aVerticalIter
= pTableBorders
->find( aVertPDef
);
156 bHasVert
= ( aVerticalIter
!= pTableBorders
->end( ) );
158 aVertProp
= aVerticalIter
->second
;
162 aVertProp
= aVerticalIter
->second
;
163 pCellProps
->erase( aVerticalIter
);
166 bool bHasHoriz
= ( aHorizontalIter
!= pCellProps
->end( ) );
170 aHorizontalIter
= pTableBorders
->find( aHorizPDef
);
171 bHasHoriz
= ( aHorizontalIter
!= pTableBorders
->end( ) );
173 aHorizProp
= aHorizontalIter
->second
;
177 aHorizProp
= aHorizontalIter
->second
;
178 pCellProps
->erase( aHorizontalIter
);
183 lcl_mergeBorder( PROP_LEFT_BORDER
, pTableBorders
, pCellProps
);
185 pCellProps
->Insert( PROP_RIGHT_BORDER
, false, aVertProp
, false );
190 lcl_mergeBorder( PROP_RIGHT_BORDER
, pTableBorders
, pCellProps
);
192 pCellProps
->Insert( PROP_LEFT_BORDER
, false, aVertProp
, false );
195 if ( nCell
> 0 && !bIsEndCol
)
199 pCellProps
->Insert( PROP_RIGHT_BORDER
, false, aVertProp
, false );
200 pCellProps
->Insert( PROP_LEFT_BORDER
, false, aVertProp
, false );
206 lcl_mergeBorder( PROP_TOP_BORDER
, pTableBorders
, pCellProps
);
208 pCellProps
->Insert( PROP_BOTTOM_BORDER
, false, aHorizProp
, false );
213 lcl_mergeBorder( PROP_BOTTOM_BORDER
, pTableBorders
, pCellProps
);
215 pCellProps
->Insert( PROP_TOP_BORDER
, false, aHorizProp
, false );
218 if ( nRow
> 0 && !bIsEndRow
)
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();
261 struct WRITERFILTER_DLLPRIVATE TableInfo
263 sal_Int32 nLeftBorderDistance
;
264 sal_Int32 nRightBorderDistance
;
265 sal_Int32 nTopBorderDistance
;
266 sal_Int32 nBottomBorderDistance
;
268 sal_Int32 nNestLevel
;
269 PropertyMapPtr pTableDefaults
;
270 PropertyMapPtr pTableBorders
;
271 TableStyleSheetEntry
* pTableStyle
;
272 TablePropertyValues_t aTableProperties
;
275 : nLeftBorderDistance(DEF_BORDER_DIST
)
276 , nRightBorderDistance(DEF_BORDER_DIST
)
277 , nTopBorderDistance(0)
278 , nBottomBorderDistance(0)
281 , pTableDefaults(new PropertyMap
)
282 , pTableBorders(new PropertyMap
)
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
);
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
);
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();
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();
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();
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;
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
;
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
);
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
));
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
));
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();
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");
545 CellPropertyValuesSeq_t
aCellProperties( m_aCellProperties
.size() );
547 if ( !m_aCellProperties
.size() )
549 #ifdef DEBUG_DOMAINMAPPER
550 dmapper_logger
->endElement();
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;
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))
586 if(rInfo
.nTblLook
&0x20)
589 nRowStyleMask
= CNF_ODD_HBAND
;
591 nRowStyleMask
= CNF_EVEN_HBAND
;
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
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))
628 if(rInfo
.nTblLook
&0x80)
631 nCellStyleMask
= CNF_ODD_VBAND
;
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
=
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
);
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();
722 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
723 //-->debug cell properties
726 const uno::Sequence
< beans::PropertyValues
> aDebugCurrentRow
= aCellProperties
[nRow
];
727 sal_Int32 nDebugCells
= aDebugCurrentRow
.getLength();
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
;
737 sNames
+= OUString('-');
739 sNames
+= OUString('\n');
746 ++aRowOfCellsIterator
;
749 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
750 dmapper_logger
->endElement();
753 return aCellProperties
;
756 RowPropertyValuesSeq_t
DomainMapperTableHandler::endTableGetRowProperties()
758 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
759 dmapper_logger
->startElement("getRowProperties");
762 RowPropertyValuesSeq_t
aRowProperties( m_aRowProperties
.size() );
763 PropertyMapVector1::const_iterator aRowIter
= m_aRowProperties
.begin();
764 PropertyMapVector1::const_iterator aRowIterEnd
= m_aRowProperties
.end();
766 while( aRowIter
!= aRowIterEnd
)
768 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
769 dmapper_logger
->startElement("rowProps.row");
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
]);
785 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
786 dmapper_logger
->endElement();
790 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
791 dmapper_logger
->endElement();
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");
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
);
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];
849 uno::Reference
<text::XTextTable
> xTable
;
854 xTable
= m_xText
->convertToTable(*m_pTableSeq
,
857 aTableInfo
.aTableProperties
);
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
);
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!"));
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( ) );
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
;
929 aFrameProperties
.realloc(aFrameProperties
.getLength() + 1);
930 aFrameProperties
[aFrameProperties
.getLength() - 1].Name
= "Width";
931 aFrameProperties
[aFrameProperties
.getLength() - 1].Value
= xTableProperties
->getPropertyValue("Width");
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
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
));
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();
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
);
982 pProps
->dumpXml(dmapper_logger
);
985 m_pRowSeq
= RowSequencePointer_t(new RowSequence_t(nCells
));
989 void DomainMapperTableHandler::endRow()
991 (*m_pTableSeq
)[m_nRowIndex
] = *m_pRowSeq
;
994 #ifdef DEBUG_DMAPPER_TABLE_HANDLER
995 dmapper_logger
->endElement();
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
);
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
);
1021 //add a new 'row' of properties
1022 m_pCellSeq
= CellSequencePointer_t(new CellSequence_t(2));
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();
1039 (*m_pCellSeq
)[1] = end
->getEnd();
1040 (*m_pRowSeq
)[m_nCellIndex
] = *m_pCellSeq
;
1046 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */