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 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <com/sun/star/text/XTextTable.hpp>
25 #include <com/sun/star/text/XTextSection.hpp>
27 #include <hintids.hxx>
28 #include <rtl/ustrbuf.hxx>
29 #include <xmloff/xmlnamespace.hxx>
30 #include <xmloff/xmltoken.hxx>
31 #include <xmloff/xmluconv.hxx>
32 #include <xmloff/numehelp.hxx>
33 #include <editeng/brushitem.hxx>
34 #include <editeng/boxitem.hxx>
35 #include <editeng/prntitem.hxx>
36 #include <editeng/xmlcnitm.hxx>
37 #include <fmtrowsplt.hxx>
38 #include <editeng/frmdiritem.hxx>
39 #include <swtable.hxx>
42 #include <wrtswtbl.hxx>
43 #include <fmtfsize.hxx>
44 #include <fmtornt.hxx>
45 #include <cellatr.hxx>
47 #include <swddetbl.hxx>
48 #include <xmloff/namespacemap.hxx>
49 #include <sfx2/linkmgr.hxx>
51 #include "xmltexte.hxx"
53 #include <o3tl/any.hxx>
54 #include <o3tl/sorted_vector.hxx>
55 #include <textboxhelper.hxx>
56 #include <SwStyleNameMapper.hxx>
58 using namespace ::com::sun::star
;
59 using namespace ::com::sun::star::uno
;
60 using namespace ::com::sun::star::text
;
61 using namespace ::com::sun::star::beans
;
62 using namespace ::com::sun::star::lang
;
63 using namespace ::com::sun::star::container
;
64 using namespace ::xmloff::token
;
70 class SwXMLTableColumn_Impl
: public SwWriteTableCol
72 OUString m_sStyleName
;
73 sal_uInt32 m_nRelWidth
;
77 explicit SwXMLTableColumn_Impl(sal_uInt32 nPosition
)
78 : SwWriteTableCol(nPosition
)
82 void SetStyleName( const OUString
& rName
) { m_sStyleName
= rName
; }
83 const OUString
& GetStyleName() const { return m_sStyleName
; }
85 void SetRelWidth( sal_uInt32 nSet
) { m_nRelWidth
= nSet
; }
86 sal_uInt32
GetRelWidth() const { return m_nRelWidth
; }
91 struct SwXMLTableColumnCmpWidth_Impl
93 bool operator()( SwXMLTableColumn_Impl
* const& lhs
, SwXMLTableColumn_Impl
* const& rhs
) const
95 sal_Int32 n
= static_cast<sal_Int32
>(lhs
->GetWidthOpt()) - static_cast<sal_Int32
>(rhs
->GetWidthOpt());
97 n
= static_cast<sal_Int32
>(lhs
->GetRelWidth()) - static_cast<sal_Int32
>(rhs
->GetRelWidth());
102 class SwXMLTableColumns_Impl
: public o3tl::sorted_vector
<std::unique_ptr
<SwXMLTableColumn_Impl
>, o3tl::less_uniqueptr_to
<SwXMLTableColumn_Impl
> > {
107 class SwXMLTableColumnsSortByWidth_Impl
: public o3tl::sorted_vector
<SwXMLTableColumn_Impl
*, SwXMLTableColumnCmpWidth_Impl
> {};
109 class SwXMLTableLines_Impl
111 SwXMLTableColumns_Impl m_aCols
;
112 const SwTableLines
*m_pLines
;
117 explicit SwXMLTableLines_Impl( const SwTableLines
& rLines
);
119 sal_uInt32
GetWidth() const { return m_nWidth
; }
120 const SwTableLines
*GetLines() const { return m_pLines
; }
122 const SwXMLTableColumns_Impl
& GetColumns() const { return m_aCols
; }
125 SwXMLTableLines_Impl::SwXMLTableLines_Impl( const SwTableLines
& rLines
) :
129 #if OSL_DEBUG_LEVEL > 0
130 sal_uInt32 nEndCPos
= 0U;
132 const size_t nLines
= rLines
.size();
133 for( size_t nLine
=0U; nLine
<nLines
; ++nLine
)
135 const SwTableLine
*pLine
= rLines
[nLine
];
136 const SwTableBoxes
& rBoxes
= pLine
->GetTabBoxes();
137 const size_t nBoxes
= rBoxes
.size();
139 sal_uInt32 nCPos
= 0U;
140 for( size_t nBox
=0U; nBox
<nBoxes
; ++nBox
)
142 const SwTableBox
*pBox
= rBoxes
[nBox
];
144 if( nBox
< nBoxes
-1U || m_nWidth
==0 )
146 nCPos
= nCPos
+ SwWriteTable::GetBoxWidth( pBox
);
147 std::unique_ptr
<SwXMLTableColumn_Impl
> pCol(
148 new SwXMLTableColumn_Impl( nCPos
));
150 m_aCols
.insert( std::move(pCol
) );
152 if( nBox
==nBoxes
-1U )
154 OSL_ENSURE( nLine
==0U && m_nWidth
==0,
155 "parent width will be lost" );
161 #if OSL_DEBUG_LEVEL > 0
162 sal_uInt32 nCheckPos
=
163 nCPos
+ SwWriteTable::GetBoxWidth( pBox
);
166 nEndCPos
= nCheckPos
;
170 #if OSL_DEBUG_LEVEL > 0
171 SwXMLTableColumn_Impl
aCol( m_nWidth
);
172 OSL_ENSURE( m_aCols
.find(&aCol
) != m_aCols
.end(), "couldn't find last column" );
173 OSL_ENSURE( SwXMLTableColumn_Impl(nCheckPos
) ==
174 SwXMLTableColumn_Impl(nCPos
),
175 "rows have different total widths" );
182 typedef vector
< SwFrameFormat
* > SwXMLFrameFormats_Impl
;
184 class SwXMLTableFrameFormatsSort_Impl
187 SwXMLFrameFormats_Impl m_aFormatList
;
188 SwXMLTextParagraphExport::FormatMap
& m_rFormatMap
;
191 SwXMLTableFrameFormatsSort_Impl(SwXMLTextParagraphExport::FormatMap
& rFormatMap
)
192 : m_rFormatMap(rFormatMap
)
194 ::std::optional
<OUString
> AddRow(SwFrameFormat
& rFrameFormat
, std::u16string_view rNamePrefix
, sal_uInt32 nLine
);
195 ::std::optional
<OUString
> AddCell(SwFrameFormat
& rFrameFormat
, std::u16string_view rNamePrefix
,
196 sal_uInt32 nCol
, sal_uInt32 nRow
, bool bTop
);
199 ::std::optional
<OUString
> SwXMLTableFrameFormatsSort_Impl::AddRow(SwFrameFormat
& rFrameFormat
,
200 std::u16string_view rNamePrefix
,
203 const SfxItemSet
& rItemSet
= rFrameFormat
.GetAttrSet();
205 const SwFormatFrameSize
*pFrameSize
= rItemSet
.GetItemIfSet( RES_FRM_SIZE
, false );
206 const SwFormatRowSplit
* pRowSplit
= rItemSet
.GetItemIfSet( RES_ROW_SPLIT
, false );
207 const SvxBrushItem
*pBrush
= rItemSet
.GetItemIfSet( RES_BACKGROUND
, false );
208 const SvxPrintItem
*pHasTextChangesOnly
= rItemSet
.GetItemIfSet( RES_PRINT
, false);
210 // empty styles have not to be exported
211 if( !pFrameSize
&& !pBrush
&& !pRowSplit
&& !pHasTextChangesOnly
)
213 m_rFormatMap
.try_emplace(&rFrameFormat
); // empty just to enable assert
217 // order is: -/brush, size/-, size/brush
218 SwXMLFrameFormats_Impl::iterator i
;
219 for( i
= m_aFormatList
.begin(); i
< m_aFormatList
.end(); ++i
)
221 const SwFormatFrameSize
*pTestFrameSize
= nullptr;
222 const SwFormatRowSplit
* pTestRowSplit
= nullptr;
223 const SvxBrushItem
*pTestBrush
= nullptr;
224 const SvxPrintItem
*pTestHasTextChangesOnly
= nullptr;
225 const SwFrameFormat
*pTestFormat
= *i
;
226 const SfxItemSet
& rTestSet
= pTestFormat
->GetAttrSet();
227 if( const SwFormatFrameSize
* pItem
= rTestSet
.GetItemIfSet( RES_FRM_SIZE
, false ) )
232 pTestFrameSize
= pItem
;
240 if( const SvxBrushItem
* pItem
= rTestSet
.GetItemIfSet( RES_BACKGROUND
, false) )
253 if( const SwFormatRowSplit
* pItem
= rTestSet
.GetItemIfSet( RES_ROW_SPLIT
, false ) )
258 pTestRowSplit
= pItem
;
266 if( const SvxPrintItem
* pItem
= rTestSet
.GetItemIfSet( RES_PRINT
, false ) )
268 if( !pHasTextChangesOnly
)
271 pTestHasTextChangesOnly
= pItem
;
275 if( pHasTextChangesOnly
)
280 ( pFrameSize
->GetHeightSizeType() != pTestFrameSize
->GetHeightSizeType() ||
281 pFrameSize
->GetHeight() != pTestFrameSize
->GetHeight() ) )
284 if( pBrush
&& (*pBrush
!= *pTestBrush
) )
287 if( pRowSplit
&& (!pRowSplit
->GetValue() != !pTestRowSplit
->GetValue()) )
290 if( pHasTextChangesOnly
&& (!pHasTextChangesOnly
->GetValue() != !pTestHasTextChangesOnly
->GetValue()) )
294 auto const oName(m_rFormatMap
.find(pTestFormat
)->second
);
296 m_rFormatMap
.try_emplace(&rFrameFormat
, oName
);
301 OUString
const name(OUString::Concat(rNamePrefix
) + "." + OUString::number(nLine
+1));
302 m_rFormatMap
.try_emplace(&rFrameFormat
, name
);
303 if ( i
!= m_aFormatList
.end() ) ++i
;
304 m_aFormatList
.insert( i
, &rFrameFormat
);
305 return ::std::optional
<OUString
>(name
);
309 static OUString
lcl_xmltble_appendBoxPrefix(std::u16string_view rNamePrefix
,
310 sal_uInt32 nCol
, sal_uInt32 nRow
, bool bTop
)
315 sw_GetTableBoxColStr( o3tl::narrowing
<sal_uInt16
>(nCol
), sTmp
);
316 return OUString::Concat(rNamePrefix
) + "." + sTmp
+ OUString::number(nRow
+ 1);
318 return OUString::Concat(rNamePrefix
)
319 + "." + OUString::number(nCol
+ 1)
320 + "." + OUString::number(nRow
+ 1);
323 ::std::optional
<OUString
> SwXMLTableFrameFormatsSort_Impl::AddCell(SwFrameFormat
& rFrameFormat
,
324 std::u16string_view rNamePrefix
,
325 sal_uInt32 nCol
, sal_uInt32 nRow
, bool bTop
)
327 const SfxItemSet
& rItemSet
= rFrameFormat
.GetAttrSet();
328 const SwFormatVertOrient
*pVertOrient
= rItemSet
.GetItemIfSet( RES_VERT_ORIENT
, false );
329 const SvxBrushItem
*pBrush
= rItemSet
.GetItemIfSet( RES_BACKGROUND
, false );
330 const SvxBoxItem
*pBox
= rItemSet
.GetItemIfSet( RES_BOX
, false );
331 const SwTableBoxNumFormat
*pNumFormat
= rItemSet
.GetItemIfSet( RES_BOXATR_FORMAT
,
333 const SvxFrameDirectionItem
*pFrameDir
= rItemSet
.GetItemIfSet( RES_FRAMEDIR
,
335 const SvXMLAttrContainerItem
*pAttCnt
= rItemSet
.GetItemIfSet( RES_UNKNOWNATR_CONTAINER
,
337 const SvxPrintItem
*pHasTextChangesOnly
= rItemSet
.GetItemIfSet( RES_PRINT
, false);
339 // empty styles have not to be exported
340 if( !pVertOrient
&& !pBrush
&& !pBox
&& !pNumFormat
&& !pFrameDir
&& !pAttCnt
&&
341 !pHasTextChangesOnly
)
343 m_rFormatMap
.try_emplace(&rFrameFormat
); // empty just to enable assert
347 // order is: -/-/-/num,
348 // -/-/box/-, -/-/box/num,
349 // -/brush/-/-, -/brush/-/num, -/brush/box/-, -/brush/box/num,
350 // vert/-/-/-, vert/-/-/num, vert/-/box/-, ver/-/box/num,
351 // vert/brush/-/-, vert/brush/-/num, vert/brush/box/-,
352 // vert/brush/box/num
353 SwXMLFrameFormats_Impl::iterator i
;
354 for( i
= m_aFormatList
.begin(); i
< m_aFormatList
.end(); ++i
)
356 const SwFormatVertOrient
*pTestVertOrient
= nullptr;
357 const SvxBrushItem
*pTestBrush
= nullptr;
358 const SvxBoxItem
*pTestBox
= nullptr;
359 const SwTableBoxNumFormat
*pTestNumFormat
= nullptr;
360 const SvxFrameDirectionItem
*pTestFrameDir
= nullptr;
361 const SvXMLAttrContainerItem
*pTestAttCnt
= nullptr;
362 const SvxPrintItem
*pTestHasTextChangesOnly
= rItemSet
.GetItemIfSet( RES_PRINT
, false);
363 const SwFrameFormat
* pTestFormat
= *i
;
364 const SfxItemSet
& rTestSet
= pTestFormat
->GetAttrSet();
365 if( const SwFormatVertOrient
* pItem
= rTestSet
.GetItemIfSet( RES_VERT_ORIENT
, false ) )
370 pTestVertOrient
= pItem
;
378 if( const SvxBrushItem
* pItem
= rTestSet
.GetItemIfSet( RES_BACKGROUND
, false ) )
391 if( const SvxBoxItem
* pItem
= rTestSet
.GetItemIfSet( RES_BOX
, false ) )
404 if ( const SwTableBoxNumFormat
* pItem
= rTestSet
.GetItemIfSet( RES_BOXATR_FORMAT
,
410 pTestNumFormat
= pItem
;
419 if ( const SvxFrameDirectionItem
* pItem
= rTestSet
.GetItemIfSet( RES_FRAMEDIR
,
425 pTestFrameDir
= pItem
;
434 if ( const SvXMLAttrContainerItem
* pItem
= rTestSet
.GetItemIfSet( RES_UNKNOWNATR_CONTAINER
,
449 if( const SvxPrintItem
* pItem
= rTestSet
.GetItemIfSet( RES_PRINT
, false ) )
451 if( !pHasTextChangesOnly
)
454 pTestHasTextChangesOnly
= pItem
;
458 if( pHasTextChangesOnly
)
463 pVertOrient
->GetVertOrient() != pTestVertOrient
->GetVertOrient() )
466 if( pBrush
&& ( *pBrush
!= *pTestBrush
) )
469 if( pBox
&& ( *pBox
!= *pTestBox
) )
472 if( pNumFormat
&& pNumFormat
->GetValue() != pTestNumFormat
->GetValue() )
475 if( pFrameDir
&& pFrameDir
->GetValue() != pTestFrameDir
->GetValue() )
478 if( pAttCnt
&& ( *pAttCnt
!= *pTestAttCnt
) )
481 if( pHasTextChangesOnly
&& (!pHasTextChangesOnly
->GetValue() != !pTestHasTextChangesOnly
->GetValue()) )
485 auto const oName(m_rFormatMap
.find(pTestFormat
)->second
);
487 m_rFormatMap
.try_emplace(&rFrameFormat
, oName
);
492 OUString
const name(lcl_xmltble_appendBoxPrefix(rNamePrefix
, nCol
, nRow
, bTop
));
493 m_rFormatMap
.try_emplace(&rFrameFormat
, name
);
494 if ( i
!= m_aFormatList
.end() ) ++i
;
495 m_aFormatList
.insert( i
, &rFrameFormat
);
496 return ::std::optional
<OUString
>(name
);
500 class SwXMLTableInfo_Impl
502 const SwTable
*m_pTable
;
503 Reference
<XTextSection
> m_xBaseSection
;
504 bool m_bBaseSectionValid
;
505 sal_uInt32 m_nPrefix
;
506 SwXMLTextParagraphExport::FormatMap
const& m_rLineFormats
;
507 SwXMLTextParagraphExport::FormatMap
const& m_rBoxFormats
;
511 inline SwXMLTableInfo_Impl( const SwTable
*pTable
, sal_uInt16 nPrefix
,
512 SwXMLTextParagraphExport::FormatMap
const& rLineFormats
,
513 SwXMLTextParagraphExport::FormatMap
const& rBoxFormats
)
515 , m_bBaseSectionValid(false)
517 , m_rLineFormats(rLineFormats
)
518 , m_rBoxFormats(rBoxFormats
)
522 const SwTable
*GetTable() const { return m_pTable
; }
523 const SwFrameFormat
*GetTableFormat() const { return m_pTable
->GetFrameFormat(); }
525 bool IsBaseSectionValid() const { return m_bBaseSectionValid
; }
526 const Reference
<XTextSection
>& GetBaseSection() const { return m_xBaseSection
; }
527 inline void SetBaseSection( const Reference
< XTextSection
>& rBase
);
528 /// The namespace (table or loext) that should be used for the elements.
529 sal_uInt16
GetPrefix() const { return m_nPrefix
; }
530 SwXMLTextParagraphExport::FormatMap
const& GetLineFormats() const { return m_rLineFormats
; }
531 SwXMLTextParagraphExport::FormatMap
const& GetBoxFormats() const { return m_rBoxFormats
; }
534 inline void SwXMLTableInfo_Impl::SetBaseSection(
535 const Reference
< XTextSection
>& rBaseSection
)
537 m_xBaseSection
= rBaseSection
;
538 m_bBaseSectionValid
= true;
541 void SwXMLExport::ExportTableColumnStyle( const SwXMLTableColumn_Impl
& rCol
)
547 bool bEncoded
= false;
548 AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
,
549 EncodeStyleName( rCol
.GetStyleName(), &bEncoded
) );
551 AddAttribute( XML_NAMESPACE_STYLE
, XML_DISPLAY_NAME
, rCol
.GetStyleName() );
553 // style:family="table-column"
554 AddAttribute( XML_NAMESPACE_STYLE
, XML_FAMILY
, XML_TABLE_COLUMN
);
557 SvXMLElementExport
aElem( *this, XML_NAMESPACE_STYLE
, XML_STYLE
, true,
559 if( rCol
.GetWidthOpt() )
561 OUStringBuffer sValue
;
562 GetTwipUnitConverter().convertMeasureToXML( sValue
,
563 rCol
.GetWidthOpt() );
564 AddAttribute( XML_NAMESPACE_STYLE
, XML_COLUMN_WIDTH
,
565 sValue
.makeStringAndClear() );
567 if( rCol
.GetRelWidth() )
569 OUString sValue
= OUString::number(static_cast<sal_Int32
>(rCol
.GetRelWidth()) ) + "*";
570 AddAttribute( XML_NAMESPACE_STYLE
, XML_REL_COLUMN_WIDTH
,
575 SvXMLElementExport
aElemExport( *this, XML_NAMESPACE_STYLE
,
576 XML_TABLE_COLUMN_PROPERTIES
,
582 void SwXMLExport::ExportTableLinesAutoStyles( const SwTableLines
& rLines
,
583 sal_uInt32 nAbsWidth
, sal_uInt32 nBaseWidth
,
584 std::u16string_view rNamePrefix
,
585 SwXMLTableColumnsSortByWidth_Impl
& rExpCols
,
586 SwXMLTableFrameFormatsSort_Impl
& rExpRows
,
587 SwXMLTableFrameFormatsSort_Impl
& rExpCells
,
588 SwXMLTableInfo_Impl
& rTableInfo
,
591 // pass 1: calculate columns
592 SwXMLTableLines_Impl
*pLines
= new SwXMLTableLines_Impl( rLines
);
594 m_pTableLines
.reset(new SwXMLTableLinesCache_Impl
);
596 m_pTableLines
->push_back( pLines
);
598 // pass 2: export column styles
600 const SwXMLTableColumns_Impl
& rCols
= pLines
->GetColumns();
601 sal_uInt32 nCPos
= 0U;
602 const size_t nColumns
= rCols
.size();
603 for( size_t nColumn
=0U; nColumn
<nColumns
; ++nColumn
)
605 SwXMLTableColumn_Impl
*pColumn
= rCols
[nColumn
].get();
607 sal_uInt32 nOldCPos
= nCPos
;
608 nCPos
= pColumn
->GetPos();
610 sal_uInt32 nWidth
= nCPos
- nOldCPos
;
612 // If a base width is given, the table has either an automatic
613 // or margin alignment, or a percentage width. In either case,
614 // relative widths should be exported.
617 pColumn
->SetRelWidth( nWidth
);
620 // If an absolute width is given, the table either has a fixed
621 // width, or the current width is known from the layout. In the
622 // later case, a base width is set in addition and must be used
623 // to "absolutize" the relative column width.
626 sal_uInt32 nColAbsWidth
= nWidth
;
629 nColAbsWidth
*= nAbsWidth
;
630 nColAbsWidth
+= (nBaseWidth
/2UL);
631 nColAbsWidth
/= nBaseWidth
;
633 pColumn
->SetWidthOpt( nColAbsWidth
, false );
636 SwXMLTableColumnsSortByWidth_Impl::const_iterator it
= rExpCols
.find( pColumn
);
637 if( it
!= rExpCols
.end() )
639 pColumn
->SetStyleName( (*it
)->GetStyleName() );
646 sw_GetTableBoxColStr( nColumn
, sTmp
);
647 pColumn
->SetStyleName( OUString::Concat(rNamePrefix
) + "." + sTmp
);
651 pColumn
->SetStyleName(
652 OUString::Concat(rNamePrefix
) + "." + OUString::number(nColumn
+ 1U) );
654 ExportTableColumnStyle( *pColumn
);
655 rExpCols
.insert( pColumn
);
660 // pass 3: export line/rows
661 const size_t nLines
= rLines
.size();
662 for( size_t nLine
=0U; nLine
<nLines
; ++nLine
)
664 SwTableLine
*pLine
= rLines
[nLine
];
666 SwFrameFormat
*pFrameFormat
= pLine
->GetFrameFormat();
667 if (auto oNew
= rExpRows
.AddRow(*pFrameFormat
, rNamePrefix
, nLine
))
669 ExportFormat(*pFrameFormat
, XML_TABLE_ROW
, std::move(oNew
));
672 const SwTableBoxes
& rBoxes
= pLine
->GetTabBoxes();
673 const size_t nBoxes
= rBoxes
.size();
675 sal_uInt32 nCPos
= 0U;
677 for( size_t nBox
=0U; nBox
<nBoxes
; nBox
++ )
679 SwTableBox
*pBox
= rBoxes
[nBox
];
681 if( nBox
< nBoxes
-1U )
682 nCPos
= nCPos
+ SwWriteTable::GetBoxWidth( pBox
);
684 nCPos
= pLines
->GetWidth();
687 const size_t nOldCol
= nCol
;
688 SwXMLTableColumn_Impl
aCol( nCPos
);
689 SwXMLTableColumns_Impl::const_iterator it
= pLines
->GetColumns().find( &aCol
);
690 OSL_ENSURE( it
!= pLines
->GetColumns().end(), "couldn't find column" );
691 nCol
= it
- pLines
->GetColumns().begin();
693 const SwStartNode
*pBoxSttNd
= pBox
->GetSttNd();
696 SwFrameFormat
*pFrameFormat2
= pBox
->GetFrameFormat();
697 if (auto oNew
= rExpCells
.AddCell(*pFrameFormat2
, rNamePrefix
, nOldCol
, nLine
,
700 ExportFormat(*pFrameFormat2
, XML_TABLE_CELL
, std::move(oNew
));
703 Reference
< XCell
> xCell
= SwXCell::CreateXCell(
704 const_cast<SwFrameFormat
*>(rTableInfo
.GetTableFormat()),
706 const_cast<SwTable
*>(rTableInfo
.GetTable()) );
709 Reference
< XText
> xText( xCell
, UNO_QUERY
);
710 if( !rTableInfo
.IsBaseSectionValid() )
712 Reference
<XPropertySet
> xCellPropertySet( xCell
,
714 Any aAny
= xCellPropertySet
->getPropertyValue("TextSection");
715 Reference
< XTextSection
> xTextSection
;
716 aAny
>>= xTextSection
;
717 rTableInfo
.SetBaseSection( xTextSection
);
720 const bool bExportContent
= bool(getExportFlags() & SvXMLExportFlags::CONTENT
);
721 if ( !bExportContent
)
723 // AUTOSTYLES - not needed anymore if we are currently exporting content.xml
724 GetTextParagraphExport()->collectTextAutoStyles(
725 xText
, rTableInfo
.GetBaseSection(), IsShowProgress() );
729 OSL_FAIL("here should be a XCell");
734 ExportTableLinesAutoStyles( pBox
->GetTabLines(),
735 nAbsWidth
, nBaseWidth
,
736 lcl_xmltble_appendBoxPrefix( rNamePrefix
,
737 nOldCol
, nLine
, bTop
),
738 rExpCols
, rExpRows
, rExpCells
,
747 void SwXMLExport::ExportTableAutoStyles(const SwTableNode
& rTableNd
)
749 auto & rFormats(static_cast<SwXMLTextParagraphExport
*>(GetTextParagraphExport().get())->GetTableFormats());
750 auto const it(rFormats
.find(&rTableNd
));
751 assert(it
!= rFormats
.end());
752 SwXMLTextParagraphExport::FormatMap
& rRowFormats(it
->second
.first
);
753 SwXMLTextParagraphExport::FormatMap
& rBoxFormats(it
->second
.second
);
754 const SwTable
& rTable
= rTableNd
.GetTable();
755 const SwFrameFormat
*pTableFormat
= rTable
.GetFrameFormat();
760 sal_Int16 eTabHoriOri
= pTableFormat
->GetHoriOrient().GetHoriOrient();
761 const SwFormatFrameSize
& rFrameSize
= pTableFormat
->GetFrameSize();
763 sal_uInt32 nAbsWidth
= rFrameSize
.GetSize().Width();
764 sal_uInt32 nBaseWidth
= 0;
765 sal_Int8 nPercentWidth
= rFrameSize
.GetWidthPercent();
767 bool bFixAbsWidth
= nPercentWidth
!= 0 || /*text::*/HoriOrientation::NONE
== eTabHoriOri
768 || /*text::*/HoriOrientation::FULL
== eTabHoriOri
;
771 nBaseWidth
= nAbsWidth
;
772 nAbsWidth
= pTableFormat
->FindLayoutRect(true).Width();
778 ExportTableFormat( *pTableFormat
, nAbsWidth
);
780 SwXMLTableColumnsSortByWidth_Impl aExpCols
;
781 SwXMLTableFrameFormatsSort_Impl
aExpRows(rRowFormats
);
782 SwXMLTableFrameFormatsSort_Impl
aExpCells(rBoxFormats
);
783 SwXMLTableInfo_Impl
aTableInfo(&rTable
, XML_NAMESPACE_TABLE
, rRowFormats
, rBoxFormats
);
784 ExportTableLinesAutoStyles( rTable
.GetTabLines(), nAbsWidth
, nBaseWidth
,
785 pTableFormat
->GetName(), aExpCols
, aExpRows
, aExpCells
,
790 void SwXMLExport::ExportTableBox( const SwTableBox
& rBox
,
793 SwXMLTableInfo_Impl
& rTableInfo
)
795 const SwStartNode
*pBoxSttNd
= rBox
.GetSttNd();
798 const SwFrameFormat
*pFrameFormat
= rBox
.GetFrameFormat();
801 auto const it(rTableInfo
.GetBoxFormats().find(pFrameFormat
));
802 assert(it
!= rTableInfo
.GetBoxFormats().end());
805 assert(!it
->second
->isEmpty());
806 AddAttribute(XML_NAMESPACE_TABLE
, XML_STYLE_NAME
, EncodeStyleName(*it
->second
));
813 AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_ROWS_SPANNED
,
814 OUString::number(nRowSpan
) );
819 AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_COLUMNS_SPANNED
,
820 OUString::number(nColSpan
) );
826 // start node -> normal cell
827 // get cell range for table
828 Reference
<XCell
> xCell
= SwXCell::CreateXCell( const_cast<SwFrameFormat
*>(rTableInfo
.GetTableFormat()),
829 const_cast<SwTableBox
*>(&rBox
),
830 const_cast<SwTable
*>(rTableInfo
.GetTable()) );
834 Reference
<XText
> xText( xCell
, UNO_QUERY
);
836 // get formula (and protection)
837 const OUString sCellFormula
= xCell
->getFormula();
839 // if this cell has a formula, export it
840 // (with value and number format)
841 if (!sCellFormula
.isEmpty())
843 const OUString sQValue
=
844 GetNamespaceMap().GetQNameByKey(
845 XML_NAMESPACE_OOOW
, sCellFormula
, false );
847 AddAttribute(XML_NAMESPACE_TABLE
, XML_FORMULA
, sQValue
);
850 // value and format (if NumberFormat != -1)
851 Reference
<XPropertySet
> xCellPropertySet(xCell
,
853 if (xCellPropertySet
.is())
855 sal_Int32 nNumberFormat
= 0;
856 Any aAny
= xCellPropertySet
->getPropertyValue("NumberFormat");
857 aAny
>>= nNumberFormat
;
859 if (static_cast<sal_Int32
>(getSwDefaultTextFormat()) == nNumberFormat
)
862 AddAttribute( XML_NAMESPACE_OFFICE
,
863 XML_VALUE_TYPE
, XML_STRING
);
865 else if ( (-1 != nNumberFormat
) && !xText
->getString().isEmpty() )
867 // number format key:
868 // (export values only if cell contains text;)
869 XMLNumberFormatAttributesExportHelper::
870 SetNumberFormatAttributes(
871 *this, nNumberFormat
, xCell
->getValue() );
873 // else: invalid key; ignore
876 aAny
= xCellPropertySet
->getPropertyValue("IsProtected");
877 if (*o3tl::doAccess
<bool>(aAny
))
879 AddAttribute( XML_NAMESPACE_TABLE
, XML_PROTECTED
,
883 if( !rTableInfo
.IsBaseSectionValid() )
885 aAny
= xCellPropertySet
->getPropertyValue("TextSection");
886 Reference
< XTextSection
> xTextSection
;
887 aAny
>>= xTextSection
;
888 rTableInfo
.SetBaseSection( xTextSection
);
892 // export cell element
893 SvXMLElementExport
aElem( *this, rTableInfo
.GetPrefix(),
894 XML_TABLE_CELL
, true, true );
896 // export cell content
897 GetTextParagraphExport()->exportText( xText
,
898 rTableInfo
.GetBaseSection(),
903 OSL_FAIL("here should be a XCell");
909 // no start node -> merged cells: export subtable in cell
910 SvXMLElementExport
aElem( *this, XML_NAMESPACE_TABLE
,
911 XML_TABLE_CELL
, true, true );
913 AddAttribute( XML_NAMESPACE_TABLE
, XML_IS_SUB_TABLE
,
914 GetXMLToken( XML_TRUE
) );
916 SvXMLElementExport
aElemExport( *this, XML_NAMESPACE_TABLE
,
917 XML_TABLE
, true, true );
918 ExportTableLines( rBox
.GetTabLines(), rTableInfo
);
924 void SwXMLExport::ExportTableLine( const SwTableLine
& rLine
,
925 const SwXMLTableLines_Impl
& rLines
,
926 SwXMLTableInfo_Impl
& rTableInfo
)
928 if( rLine
.hasSoftPageBreak() )
930 SvXMLElementExport
aElem( *this, XML_NAMESPACE_TEXT
,
931 XML_SOFT_PAGE_BREAK
, true, true );
933 const SwFrameFormat
*pFrameFormat
= rLine
.GetFrameFormat();
936 auto const it(rTableInfo
.GetLineFormats().find(pFrameFormat
));
937 assert(it
!= rTableInfo
.GetLineFormats().end());
940 assert(!it
->second
->isEmpty());
941 AddAttribute(XML_NAMESPACE_TABLE
, XML_STYLE_NAME
, EncodeStyleName(*it
->second
));
946 SvXMLElementExport
aElem( *this, rTableInfo
.GetPrefix(), XML_TABLE_ROW
, true, true );
947 const SwTableBoxes
& rBoxes
= rLine
.GetTabBoxes();
948 const size_t nBoxes
= rBoxes
.size();
950 sal_uInt32 nCPos
= 0U;
952 for( size_t nBox
=0U; nBox
<nBoxes
; ++nBox
)
954 const SwTableBox
*pBox
= rBoxes
[nBox
];
957 const sal_Int32 nRowSpan
= pBox
->getRowSpan();
960 // Export style of covered cell, it includes border information.
961 const SwFrameFormat
* pFormat
= pBox
->GetFrameFormat();
964 auto const it(rTableInfo
.GetBoxFormats().find(pFormat
));
965 assert(it
!= rTableInfo
.GetBoxFormats().end());
968 assert(!it
->second
->isEmpty());
969 AddAttribute(XML_NAMESPACE_TABLE
, XML_STYLE_NAME
, EncodeStyleName(*it
->second
));
973 SvXMLElementExport
aElem2( *this, rTableInfo
.GetPrefix(),
974 XML_COVERED_TABLE_CELL
, true,
978 if( nBox
< nBoxes
-1U )
979 nCPos
= nCPos
+ SwWriteTable::GetBoxWidth( pBox
);
981 nCPos
= rLines
.GetWidth();
984 const size_t nOldCol
= nCol
;
985 SwXMLTableColumn_Impl
aCol( nCPos
);
986 SwXMLTableColumns_Impl::const_iterator it
= rLines
.GetColumns().find( &aCol
);
987 OSL_ENSURE( it
!= rLines
.GetColumns().end(), "couldn't find column" );
988 nCol
= it
- rLines
.GetColumns().begin();
990 // #i95726# - Some fault tolerance, if table is somehow corrupted.
991 if ( nCol
< nOldCol
)
993 OSL_FAIL( "table and/or table information seems to be corrupted." );
994 // NOTE: nOldCol is not necessarily a valid index into
995 // GetColumns(), but that doesn't matter here
999 const sal_uInt32 nColSpan
= nCol
- nOldCol
+ 1U;
1001 if ( nRowSpan
>= 1 )
1002 ExportTableBox( *pBox
, nColSpan
, static_cast< sal_uInt32
>(nRowSpan
), rTableInfo
);
1004 for( size_t i
=nOldCol
; i
<nCol
; ++i
)
1006 SvXMLElementExport
aElemExport( *this, rTableInfo
.GetPrefix(),
1007 XML_COVERED_TABLE_CELL
, true,
1016 void SwXMLExport::ExportTableLines( const SwTableLines
& rLines
,
1017 SwXMLTableInfo_Impl
& rTableInfo
,
1018 sal_uInt32 nHeaderRows
)
1020 OSL_ENSURE( m_pTableLines
&& !m_pTableLines
->empty(),
1021 "SwXMLExport::ExportTableLines: table columns infos missing" );
1022 if( !m_pTableLines
|| m_pTableLines
->empty() )
1025 SwXMLTableLines_Impl
* pLines
= nullptr;
1027 for( nInfoPos
=0; nInfoPos
< m_pTableLines
->size(); nInfoPos
++ )
1029 if( m_pTableLines
->at( nInfoPos
)->GetLines() == &rLines
)
1031 pLines
= m_pTableLines
->at( nInfoPos
);
1036 "SwXMLExport::ExportTableLines: table columns info missing" );
1037 OSL_ENSURE( 0==nInfoPos
,
1038 "SwXMLExport::ExportTableLines: table columns infos are unsorted" );
1042 SwXMLTableLinesCache_Impl::iterator it
= m_pTableLines
->begin();
1043 advance( it
, nInfoPos
);
1044 m_pTableLines
->erase( it
);
1046 if( m_pTableLines
->empty() )
1047 m_pTableLines
.reset();
1049 // pass 2: export columns
1050 const SwXMLTableColumns_Impl
& rCols
= pLines
->GetColumns();
1051 size_t nColumn
= 0U;
1052 const size_t nColumns
= rCols
.size();
1053 sal_Int32 nColRep
= 1;
1054 SwXMLTableColumn_Impl
*pColumn
= (nColumns
> 0) ? rCols
.front().get() : nullptr;
1058 SwXMLTableColumn_Impl
*pNextColumn
=
1059 (nColumn
< nColumns
) ? rCols
[nColumn
].get() : nullptr;
1061 pNextColumn
->GetStyleName() == pColumn
->GetStyleName() )
1067 AddAttribute( XML_NAMESPACE_TABLE
, XML_STYLE_NAME
,
1068 EncodeStyleName(pColumn
->GetStyleName()) );
1072 AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_COLUMNS_REPEATED
,
1073 OUString::number(nColRep
) );
1077 SvXMLElementExport
aElem( *this, rTableInfo
.GetPrefix(), XML_TABLE_COLUMN
, true, true );
1082 pColumn
= pNextColumn
;
1085 // pass 3: export line/rows
1086 const size_t nLines
= rLines
.size();
1087 // export header rows, if present
1088 if( nHeaderRows
> 0 )
1090 SvXMLElementExport
aElem( *this, XML_NAMESPACE_TABLE
,
1091 XML_TABLE_HEADER_ROWS
, true, true );
1093 OSL_ENSURE( nHeaderRows
<= nLines
, "more headers then lines?" );
1094 for( size_t nLine
= 0U; nLine
< nHeaderRows
; ++nLine
)
1095 ExportTableLine( *(rLines
[nLine
]), *pLines
, rTableInfo
);
1097 // export remaining rows
1098 for( size_t nLine
= nHeaderRows
; nLine
< nLines
; ++nLine
)
1100 ExportTableLine( *(rLines
[nLine
]), *pLines
, rTableInfo
);
1106 void SwXMLExport::ExportTable( const SwTableNode
& rTableNd
)
1108 ::std::optional
<sal_uInt16
> oPrefix
= XML_NAMESPACE_TABLE
;
1109 if (const SwFrameFormat
* pFlyFormat
= rTableNd
.GetFlyFormat())
1111 if (SwTextBoxHelper::isTextBox(pFlyFormat
, RES_FLYFRMFMT
))
1113 // TODO ODF 1.4 OFFICE-3761
1114 if (getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED
)
1116 oPrefix
= XML_NAMESPACE_LO_EXT
;
1120 oPrefix
.reset(); // no export to OASIS namespace yet
1128 const SwTable
& rTable
= rTableNd
.GetTable();
1129 const SwFrameFormat
*pTableFormat
= rTable
.GetFrameFormat();
1130 if (pTableFormat
&& !pTableFormat
->GetName().isEmpty())
1132 AddAttribute(XML_NAMESPACE_TABLE
, XML_NAME
, pTableFormat
->GetName());
1133 AddAttribute(XML_NAMESPACE_TABLE
, XML_STYLE_NAME
,
1134 EncodeStyleName(pTableFormat
->GetName()));
1137 // table:template-name=
1138 if (!rTable
.GetTableStyleName().isEmpty())
1140 OUString sStyleName
;
1141 SwStyleNameMapper::FillProgName(rTable
.GetTableStyleName(), sStyleName
, SwGetPoolIdFromName::TabStyle
);
1142 AddAttribute(XML_NAMESPACE_TABLE
, XML_TEMPLATE_NAME
, sStyleName
);
1145 SvXMLElementExport
aElem(*this, *oPrefix
, XML_TABLE
, true, true);
1147 // export DDE source (if this is a DDE table)
1148 if ( auto pSwDdeTable
= dynamic_cast<const SwDDETable
*>( &rTable
) )
1150 // get DDE Field Type (contains the DDE connection)
1151 const SwDDEFieldType
* pDDEFieldType
= pSwDdeTable
->GetDDEFieldType();
1154 AddAttribute( XML_NAMESPACE_OFFICE
, XML_NAME
,
1155 pDDEFieldType
->GetName() );
1158 const OUString
& sCmd
= pDDEFieldType
->GetCmd();
1159 sal_Int32 nIdx
{ 0 };
1160 AddAttribute( XML_NAMESPACE_OFFICE
, XML_DDE_APPLICATION
,
1161 sCmd
.getToken(0, sfx2::cTokenSeparator
, nIdx
) );
1162 AddAttribute( XML_NAMESPACE_OFFICE
, XML_DDE_ITEM
,
1163 sCmd
.getToken(0, sfx2::cTokenSeparator
, nIdx
) );
1164 AddAttribute( XML_NAMESPACE_OFFICE
, XML_DDE_TOPIC
,
1165 sCmd
.getToken(0, sfx2::cTokenSeparator
, nIdx
) );
1168 if (pDDEFieldType
->GetType() == SfxLinkUpdateMode::ALWAYS
)
1170 AddAttribute( XML_NAMESPACE_OFFICE
,
1171 XML_AUTOMATIC_UPDATE
, XML_TRUE
);
1174 // DDE source element (always empty)
1175 SvXMLElementExport
aSource(*this, XML_NAMESPACE_OFFICE
,
1176 XML_DDE_SOURCE
, true, false);
1179 auto const& rFormats(static_cast<SwXMLTextParagraphExport
const*>(GetTextParagraphExport().get())->GetTableFormats());
1180 auto const it(rFormats
.find(&rTableNd
));
1181 assert(it
!= rFormats
.end());
1182 SwXMLTableInfo_Impl
aTableInfo(&rTable
, *oPrefix
, it
->second
.first
, it
->second
.second
);
1183 ExportTableLines( rTable
.GetTabLines(), aTableInfo
, rTable
.GetRowsToRepeat() );
1186 void SwXMLTextParagraphExport::exportTableAutoStyles() {
1187 // note: maTableNodes is used here only to keep the iteration order as before
1188 for (const auto* pTableNode
: maTableNodes
)
1190 static_cast<SwXMLExport
&>(GetExport()).ExportTableAutoStyles(*pTableNode
);
1194 void SwXMLTextParagraphExport::CollectTableLinesAutoStyles(const SwTableLines
& rLines
,
1195 SwFrameFormat
& rFormat
, bool _bProgress
)
1197 // Follow SwXMLExport::ExportTableLines/ExportTableLine/ExportTableBox
1198 for (const SwTableLine
* pLine
: rLines
)
1200 for (SwTableBox
* pBox
: pLine
->GetTabBoxes())
1202 if (pBox
->getRowSpan() <= 0)
1204 if (pBox
->GetSttNd())
1206 if (rtl::Reference
<SwXCell
> xCell
= SwXCell::CreateXCell(&rFormat
, pBox
))
1207 exportText(xCell
, true /*bAutoStyles*/, _bProgress
, true /*bExportParagraph*/);
1211 // no start node -> merged cells: export subtable in cell
1212 CollectTableLinesAutoStyles(pBox
->GetTabLines(), rFormat
, _bProgress
);
1218 void SwXMLTextParagraphExport::exportTable(
1219 const Reference
< XTextContent
> & rTextContent
,
1220 bool bAutoStyles
, bool _bProgress
)
1222 bool bOldShowProgress
= static_cast<SwXMLExport
&>(GetExport()).IsShowProgress();
1223 static_cast<SwXMLExport
&>(GetExport()).SetShowProgress( _bProgress
);
1225 Reference
< XTextTable
> xTextTable( rTextContent
, UNO_QUERY
);
1226 OSL_ENSURE( xTextTable
.is(), "text table missing" );
1227 if( xTextTable
.is() )
1229 SwXTextTable
* pXTable
= dynamic_cast<SwXTextTable
*>(rTextContent
.get());
1232 SwFrameFormat
*const pFormat
= pXTable
->GetFrameFormat();
1233 OSL_ENSURE( pFormat
, "table format missing" );
1234 const SwTable
*pTable
= SwTable::FindTable( pFormat
);
1235 OSL_ENSURE( pTable
, "table missing" );
1236 const SwTableNode
*pTableNd
= pTable
->GetTableNode();
1237 OSL_ENSURE( pTableNd
, "table node missing" );
1240 // AUTOSTYLES: Optimization: Do not export table autostyle if
1241 // we are currently exporting the content.xml stuff and
1242 // the table is located in header/footer:
1243 // During the flat XML export (used e.g. by .sdw-export)
1244 // ALL flags are set at the same time.
1245 const bool bExportStyles
= bool( GetExport().getExportFlags() & SvXMLExportFlags::STYLES
);
1246 if (!isAutoStylesCollected()
1247 && (bExportStyles
|| !pFormat
->GetDoc()->IsInHeaderFooter(*pTableNd
)))
1249 maTableNodes
.push_back(pTableNd
);
1250 m_TableFormats
.try_emplace(pTableNd
);
1251 // Collect all tables inside cells of this table, too
1252 CollectTableLinesAutoStyles(pTable
->GetTabLines(), *pFormat
, _bProgress
);
1257 static_cast<SwXMLExport
&>(GetExport()).ExportTable( *pTableNd
);
1262 static_cast<SwXMLExport
&>(GetExport()).SetShowProgress( bOldShowProgress
);
1265 void SwXMLExport::DeleteTableLines()
1267 if ( m_pTableLines
)
1269 for (SwXMLTableLines_Impl
* p
: *m_pTableLines
)
1271 m_pTableLines
->clear();
1272 m_pTableLines
.reset();
1276 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */