LCOV - code coverage report
Current view: top level - writerfilter/source/dmapper - DomainMapperTableHandler.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 501 503 99.6 %
Date: 2015-06-13 12:38:46 Functions: 23 23 100.0 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.11