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 <com/sun/star/text/XTextTable.hpp>
21 #include <com/sun/star/text/XTextSection.hpp>
23 #include <hintids.hxx>
24 #include <rtl/ustrbuf.hxx>
25 #include <xmloff/xmlnmspe.hxx>
26 #include <xmloff/xmltoken.hxx>
27 #include <xmloff/xmluconv.hxx>
28 #include <xmloff/numehelp.hxx>
29 #include <svl/zforlist.hxx>
30 #include <editeng/brushitem.hxx>
31 #include <editeng/boxitem.hxx>
32 #include <editeng/xmlcnitm.hxx>
33 #include <fmtrowsplt.hxx>
34 #include <editeng/frmdiritem.hxx>
36 #include "swtable.hxx"
40 #include "wrtswtbl.hxx"
41 #include "fmtfsize.hxx"
42 #include "fmtornt.hxx"
43 #include "cellatr.hxx"
45 #include "swddetbl.hxx"
47 #include <xmloff/nmspmap.hxx>
48 #include <sfx2/linkmgr.hxx>
50 #include "xmltexte.hxx"
52 #include <o3tl/any.hxx>
53 #include <o3tl/sorted_vector.hxx>
54 #include <textboxhelper.hxx>
56 using namespace ::com::sun::star
;
57 using namespace ::com::sun::star::uno
;
58 using namespace ::com::sun::star::text
;
59 using namespace ::com::sun::star::beans
;
60 using namespace ::com::sun::star::lang
;
61 using namespace ::com::sun::star::container
;
62 using namespace ::xmloff::token
;
67 // string constants for table cell export
68 static const char g_sNumberFormat
[] = "NumberFormat";
69 static const char g_sIsProtected
[] = "IsProtected";
71 class SwXMLTableColumn_Impl
: public SwWriteTableCol
78 explicit SwXMLTableColumn_Impl(sal_uInt32 nPosition
)
79 : SwWriteTableCol(nPosition
)
83 void SetStyleName( const OUString
& rName
) { sStyleName
= rName
; }
84 const OUString
& GetStyleName() const { return sStyleName
; }
86 void SetRelWidth( sal_uInt32 nSet
) { nRelWidth
= nSet
; }
87 sal_uInt32
GetRelWidth() const { return nRelWidth
; }
90 struct SwXMLTableColumnCmpWidth_Impl
92 bool operator()( SwXMLTableColumn_Impl
* const& lhs
, SwXMLTableColumn_Impl
* const& rhs
) const
94 sal_Int32 n
= (sal_Int32
)lhs
->GetWidthOpt() - (sal_Int32
)rhs
->GetWidthOpt();
96 n
= (sal_Int32
)lhs
->GetRelWidth() - (sal_Int32
)rhs
->GetRelWidth();
101 class SwXMLTableColumns_Impl
: public o3tl::sorted_vector
<SwXMLTableColumn_Impl
*, o3tl::less_ptr_to
<SwXMLTableColumn_Impl
> > {
103 ~SwXMLTableColumns_Impl() { DeleteAndDestroyAll(); }
106 class SwXMLTableColumnsSortByWidth_Impl
: public o3tl::sorted_vector
<SwXMLTableColumn_Impl
*, SwXMLTableColumnCmpWidth_Impl
> {};
108 class SwXMLTableLines_Impl
110 SwXMLTableColumns_Impl aCols
;
111 const SwTableLines
*pLines
;
116 explicit SwXMLTableLines_Impl( const SwTableLines
& rLines
);
118 ~SwXMLTableLines_Impl() {}
120 sal_uInt32
GetWidth() const { return nWidth
; }
121 const SwTableLines
*GetLines() const { return pLines
; }
123 const SwXMLTableColumns_Impl
& GetColumns() const { return aCols
; }
126 SwXMLTableLines_Impl::SwXMLTableLines_Impl( const SwTableLines
& rLines
) :
130 #if OSL_DEBUG_LEVEL > 0
131 sal_uInt32 nEndCPos
= 0U;
133 const size_t nLines
= rLines
.size();
134 for( size_t nLine
=0U; nLine
<nLines
; ++nLine
)
136 const SwTableLine
*pLine
= rLines
[nLine
];
137 const SwTableBoxes
& rBoxes
= pLine
->GetTabBoxes();
138 const size_t nBoxes
= rBoxes
.size();
140 sal_uInt32 nCPos
= 0U;
141 for( size_t nBox
=0U; nBox
<nBoxes
; ++nBox
)
143 const SwTableBox
*pBox
= rBoxes
[nBox
];
145 if( nBox
< nBoxes
-1U || nWidth
==0UL )
147 nCPos
= nCPos
+ SwWriteTable::GetBoxWidth( pBox
);
148 SwXMLTableColumn_Impl
*pCol
=
149 new SwXMLTableColumn_Impl( nCPos
);
151 if( !aCols
.insert( pCol
).second
)
154 if( nBox
==nBoxes
-1U )
156 OSL_ENSURE( nLine
==0U && nWidth
==0UL,
157 "parent width will be lost" );
163 #if OSL_DEBUG_LEVEL > 0
164 sal_uInt32 nCheckPos
=
165 nCPos
+ SwWriteTable::GetBoxWidth( pBox
);
168 nEndCPos
= nCheckPos
;
172 #if OSL_DEBUG_LEVEL > 0
173 SwXMLTableColumn_Impl
aCol( nWidth
);
174 OSL_ENSURE( aCols
.find(&aCol
) != aCols
.end(), "couldn't find last column" );
175 OSL_ENSURE( SwXMLTableColumn_Impl(nCheckPos
) ==
176 SwXMLTableColumn_Impl(nCPos
),
177 "rows have different total widths" );
184 typedef vector
< SwFrameFormat
* > SwXMLFrameFormats_Impl
;
186 class SwXMLTableFrameFormatsSort_Impl
189 SwXMLFrameFormats_Impl aFormatList
;
191 bool AddRow( SwFrameFormat
& rFrameFormat
, const OUString
& rNamePrefix
, sal_uInt32 nLine
);
192 bool AddCell( SwFrameFormat
& rFrameFormat
, const OUString
& rNamePrefix
,
193 sal_uInt32 nCol
, sal_uInt32 nRow
, bool bTop
);
196 bool SwXMLTableFrameFormatsSort_Impl::AddRow( SwFrameFormat
& rFrameFormat
,
197 const OUString
& rNamePrefix
,
200 const SwFormatFrameSize
*pFrameSize
= nullptr;
201 const SwFormatRowSplit
* pRowSplit
= nullptr;
202 const SvxBrushItem
*pBrush
= nullptr;
204 const SfxItemSet
& rItemSet
= rFrameFormat
.GetAttrSet();
205 const SfxPoolItem
*pItem
;
206 if( SfxItemState::SET
== rItemSet
.GetItemState( RES_FRM_SIZE
, false, &pItem
) )
207 pFrameSize
= static_cast<const SwFormatFrameSize
*>(pItem
);
209 if( SfxItemState::SET
== rItemSet
.GetItemState( RES_ROW_SPLIT
, false, &pItem
) )
210 pRowSplit
= static_cast<const SwFormatRowSplit
*>(pItem
);
212 if( SfxItemState::SET
== rItemSet
.GetItemState( RES_BACKGROUND
, false, &pItem
) )
213 pBrush
= static_cast<const SvxBrushItem
*>(pItem
);
215 // empty styles have not to be exported
216 if( !pFrameSize
&& !pBrush
&& !pRowSplit
)
219 // order is: -/brush, size/-, size/brush
221 SwXMLFrameFormats_Impl::iterator i
;
222 for( i
= aFormatList
.begin(); i
< aFormatList
.end(); ++i
)
224 const SwFormatFrameSize
*pTestFrameSize
= nullptr;
225 const SwFormatRowSplit
* pTestRowSplit
= nullptr;
226 const SvxBrushItem
*pTestBrush
= nullptr;
227 const SwFrameFormat
*pTestFormat
= *i
;
228 const SfxItemSet
& rTestSet
= pTestFormat
->GetAttrSet();
229 if( SfxItemState::SET
== rTestSet
.GetItemState( RES_FRM_SIZE
, false,
235 pTestFrameSize
= static_cast<const SwFormatFrameSize
*>(pItem
);
243 if( SfxItemState::SET
== rTestSet
.GetItemState( RES_BACKGROUND
, false,
249 pTestBrush
= static_cast<const SvxBrushItem
*>(pItem
);
257 if( SfxItemState::SET
== rTestSet
.GetItemState( RES_ROW_SPLIT
, false,
263 pTestRowSplit
= static_cast<const SwFormatRowSplit
*>(pItem
);
272 ( pFrameSize
->GetHeightSizeType() != pTestFrameSize
->GetHeightSizeType() ||
273 pFrameSize
->GetHeight() != pTestFrameSize
->GetHeight() ) )
276 if( pBrush
&& (*pBrush
!= *pTestBrush
) )
279 if( pRowSplit
&& (!pRowSplit
->GetValue() != !pTestRowSplit
->GetValue()) )
283 rFrameFormat
.SetName( pTestFormat
->GetName() );
290 rFrameFormat
.SetName( rNamePrefix
+ "." + OUString::number(nLine
+1UL) );
291 if ( i
!= aFormatList
.end() ) ++i
;
292 aFormatList
.insert( i
, &rFrameFormat
);
298 static OUString
lcl_xmltble_appendBoxPrefix(const OUString
& rNamePrefix
,
299 sal_uInt32 nCol
, sal_uInt32 nRow
, bool bTop
)
304 sw_GetTableBoxColStr( (sal_uInt16
)nCol
, sTmp
);
305 return rNamePrefix
+ "." + sTmp
+ OUString::number(nRow
+ 1);
308 + "." + OUString::number(nCol
+ 1)
309 + "." + OUString::number(nRow
+ 1);
312 bool SwXMLTableFrameFormatsSort_Impl::AddCell( SwFrameFormat
& rFrameFormat
,
313 const OUString
& rNamePrefix
,
314 sal_uInt32 nCol
, sal_uInt32 nRow
, bool bTop
)
316 const SwFormatVertOrient
*pVertOrient
= nullptr;
317 const SvxBrushItem
*pBrush
= nullptr;
318 const SvxBoxItem
*pBox
= nullptr;
319 const SwTableBoxNumFormat
*pNumFormat
= nullptr;
320 const SvxFrameDirectionItem
*pFrameDir
= nullptr;
321 const SvXMLAttrContainerItem
*pAttCnt
= nullptr;
323 const SfxItemSet
& rItemSet
= rFrameFormat
.GetAttrSet();
324 const SfxPoolItem
*pItem
;
325 if( SfxItemState::SET
== rItemSet
.GetItemState( RES_VERT_ORIENT
, false,
327 pVertOrient
= static_cast<const SwFormatVertOrient
*>(pItem
);
329 if( SfxItemState::SET
== rItemSet
.GetItemState( RES_BACKGROUND
, false, &pItem
) )
330 pBrush
= static_cast<const SvxBrushItem
*>(pItem
);
332 if( SfxItemState::SET
== rItemSet
.GetItemState( RES_BOX
, false, &pItem
) )
333 pBox
= static_cast<const SvxBoxItem
*>(pItem
);
335 if ( SfxItemState::SET
== rItemSet
.GetItemState( RES_BOXATR_FORMAT
,
337 pNumFormat
= static_cast<const SwTableBoxNumFormat
*>(pItem
);
338 if ( SfxItemState::SET
== rItemSet
.GetItemState( RES_FRAMEDIR
,
340 pFrameDir
= static_cast<const SvxFrameDirectionItem
*>(pItem
);
341 if ( SfxItemState::SET
== rItemSet
.GetItemState( RES_UNKNOWNATR_CONTAINER
,
343 pAttCnt
= static_cast<const SvXMLAttrContainerItem
*>(pItem
);
345 // empty styles have not to be exported
346 if( !pVertOrient
&& !pBrush
&& !pBox
&& !pNumFormat
&& !pFrameDir
&& !pAttCnt
)
349 // order is: -/-/-/num,
350 // -/-/box/-, --/-/box/num,
351 // -/brush/-/-, -/brush/-/num, -/brush/box/-, -/brush/box/num,
352 // vert/-/-/-, vert/-/-/num, vert/-/box/-, ver/-/box/num,
353 // vert/brush/-/-, vert/brush/-/num, vert/brush/box/-,
354 // vert/brush/box/num
356 SwXMLFrameFormats_Impl::iterator i
;
357 for( i
= aFormatList
.begin(); i
< aFormatList
.end(); ++i
)
359 const SwFormatVertOrient
*pTestVertOrient
= nullptr;
360 const SvxBrushItem
*pTestBrush
= nullptr;
361 const SvxBoxItem
*pTestBox
= nullptr;
362 const SwTableBoxNumFormat
*pTestNumFormat
= nullptr;
363 const SvxFrameDirectionItem
*pTestFrameDir
= nullptr;
364 const SvXMLAttrContainerItem
*pTestAttCnt
= nullptr;
365 const SwFrameFormat
* pTestFormat
= *i
;
366 const SfxItemSet
& rTestSet
= pTestFormat
->GetAttrSet();
367 if( SfxItemState::SET
== rTestSet
.GetItemState( RES_VERT_ORIENT
, false,
373 pTestVertOrient
= static_cast<const SwFormatVertOrient
*>(pItem
);
381 if( SfxItemState::SET
== rTestSet
.GetItemState( RES_BACKGROUND
, false,
387 pTestBrush
= static_cast<const SvxBrushItem
*>(pItem
);
395 if( SfxItemState::SET
== rTestSet
.GetItemState( RES_BOX
, false, &pItem
) )
400 pTestBox
= static_cast<const SvxBoxItem
*>(pItem
);
408 if ( SfxItemState::SET
== rTestSet
.GetItemState( RES_BOXATR_FORMAT
,
414 pTestNumFormat
= static_cast<const SwTableBoxNumFormat
*>(pItem
);
423 if ( SfxItemState::SET
== rTestSet
.GetItemState( RES_FRAMEDIR
,
429 pTestFrameDir
= static_cast<const SvxFrameDirectionItem
*>(pItem
);
438 if ( SfxItemState::SET
== rTestSet
.GetItemState( RES_UNKNOWNATR_CONTAINER
,
444 pTestAttCnt
= static_cast<const SvXMLAttrContainerItem
*>(pItem
);
454 pVertOrient
->GetVertOrient() != pTestVertOrient
->GetVertOrient() )
457 if( pBrush
&& ( *pBrush
!= *pTestBrush
) )
460 if( pBox
&& ( *pBox
!= *pTestBox
) )
463 if( pNumFormat
&& pNumFormat
->GetValue() != pTestNumFormat
->GetValue() )
466 if( pFrameDir
&& pFrameDir
->GetValue() != pTestFrameDir
->GetValue() )
469 if( pAttCnt
&& ( *pAttCnt
!= *pTestAttCnt
) )
473 rFrameFormat
.SetName( pTestFormat
->GetName() );
480 rFrameFormat
.SetName( lcl_xmltble_appendBoxPrefix( rNamePrefix
, nCol
, nRow
, bTop
) );
481 if ( i
!= aFormatList
.end() ) ++i
;
482 aFormatList
.insert( i
, &rFrameFormat
);
488 class SwXMLTableInfo_Impl
490 const SwTable
*m_pTable
;
491 Reference
<XTextSection
> m_xBaseSection
;
492 bool m_bBaseSectionValid
;
493 sal_uInt32 m_nPrefix
;
497 inline SwXMLTableInfo_Impl( const SwTable
*pTable
, sal_uInt16 nPrefix
);
499 const SwTable
*GetTable() const { return m_pTable
; }
500 const SwFrameFormat
*GetTableFormat() const { return m_pTable
->GetFrameFormat(); }
502 bool IsBaseSectionValid() const { return m_bBaseSectionValid
; }
503 const Reference
<XTextSection
>& GetBaseSection() const { return m_xBaseSection
; }
504 inline void SetBaseSection( const Reference
< XTextSection
>& rBase
);
505 /// The namespace (table or loext) that should be used for the elements.
506 sal_uInt16
GetPrefix() const { return m_nPrefix
; }
509 inline SwXMLTableInfo_Impl::SwXMLTableInfo_Impl(const SwTable
*pTable
, sal_uInt16 nPrefix
) :
511 m_bBaseSectionValid(false),
516 inline void SwXMLTableInfo_Impl::SetBaseSection(
517 const Reference
< XTextSection
>& rBaseSection
)
519 m_xBaseSection
= rBaseSection
;
520 m_bBaseSectionValid
= true;
523 void SwXMLExport::ExportTableColumnStyle( const SwXMLTableColumn_Impl
& rCol
)
529 bool bEncoded
= false;
530 AddAttribute( XML_NAMESPACE_STYLE
, XML_NAME
,
531 EncodeStyleName( rCol
.GetStyleName(), &bEncoded
) );
533 AddAttribute( XML_NAMESPACE_STYLE
, XML_DISPLAY_NAME
, rCol
.GetStyleName() );
535 // style:family="table-column"
536 AddAttribute( XML_NAMESPACE_STYLE
, XML_FAMILY
, XML_TABLE_COLUMN
);
539 SvXMLElementExport
aElem( *this, XML_NAMESPACE_STYLE
, XML_STYLE
, true,
541 OUStringBuffer sValue
;
542 if( rCol
.GetWidthOpt() )
544 GetTwipUnitConverter().convertMeasureToXML( sValue
,
545 rCol
.GetWidthOpt() );
546 AddAttribute( XML_NAMESPACE_STYLE
, XML_COLUMN_WIDTH
,
547 sValue
.makeStringAndClear() );
549 if( rCol
.GetRelWidth() )
551 sValue
.append( (sal_Int32
)rCol
.GetRelWidth() );
552 sValue
.append( '*' );
553 AddAttribute( XML_NAMESPACE_STYLE
, XML_REL_COLUMN_WIDTH
,
554 sValue
.makeStringAndClear() );
558 SvXMLElementExport
aElemExport( *this, XML_NAMESPACE_STYLE
,
559 XML_TABLE_COLUMN_PROPERTIES
,
565 void SwXMLExport::ExportTableLinesAutoStyles( const SwTableLines
& rLines
,
566 sal_uInt32 nAbsWidth
, sal_uInt32 nBaseWidth
,
567 const OUString
& rNamePrefix
,
568 SwXMLTableColumnsSortByWidth_Impl
& rExpCols
,
569 SwXMLTableFrameFormatsSort_Impl
& rExpRows
,
570 SwXMLTableFrameFormatsSort_Impl
& rExpCells
,
571 SwXMLTableInfo_Impl
& rTableInfo
,
574 // pass 1: calculate columns
575 SwXMLTableLines_Impl
*pLines
= new SwXMLTableLines_Impl( rLines
);
577 pTableLines
= new SwXMLTableLinesCache_Impl();
579 pTableLines
->push_back( pLines
);
581 // pass 2: export column styles
583 const SwXMLTableColumns_Impl
& rCols
= pLines
->GetColumns();
584 sal_uInt32 nCPos
= 0U;
585 const size_t nColumns
= rCols
.size();
586 for( size_t nColumn
=0U; nColumn
<nColumns
; ++nColumn
)
588 SwXMLTableColumn_Impl
*pColumn
= rCols
[nColumn
];
590 sal_uInt32 nOldCPos
= nCPos
;
591 nCPos
= pColumn
->GetPos();
593 sal_uInt32 nWidth
= nCPos
- nOldCPos
;
595 // If a base width is given, the table has either an automatic
596 // or margin alignment, or an percentage width. In either case,
597 // relative widths should be exported.
600 pColumn
->SetRelWidth( nWidth
);
603 // If an absolute width is given, the table either has a fixed
604 // width, or the current width is known from the layout. In the
605 // later case, a base width is set in addition and must be used
606 // to "absolutize" the relative column width.
609 sal_uInt32 nColAbsWidth
= nWidth
;
612 nColAbsWidth
*= nAbsWidth
;
613 nColAbsWidth
+= (nBaseWidth
/2UL);
614 nColAbsWidth
/= nBaseWidth
;
616 pColumn
->SetWidthOpt( nColAbsWidth
, false );
619 SwXMLTableColumnsSortByWidth_Impl::const_iterator it
= rExpCols
.find( pColumn
);
620 if( it
!= rExpCols
.end() )
622 pColumn
->SetStyleName( (*it
)->GetStyleName() );
629 sw_GetTableBoxColStr( nColumn
, sTmp
);
630 pColumn
->SetStyleName( rNamePrefix
+ "." + sTmp
);
634 pColumn
->SetStyleName( rNamePrefix
+ "." + OUString::number(nColumn
+ 1U) );
636 ExportTableColumnStyle( *pColumn
);
637 rExpCols
.insert( pColumn
);
642 // pass 3: export line/rows
643 const size_t nLines
= rLines
.size();
644 for( size_t nLine
=0U; nLine
<nLines
; ++nLine
)
646 SwTableLine
*pLine
= rLines
[nLine
];
648 SwFrameFormat
*pFrameFormat
= pLine
->GetFrameFormat();
649 if( rExpRows
.AddRow( *pFrameFormat
, rNamePrefix
, nLine
) )
650 ExportFormat( *pFrameFormat
, XML_TABLE_ROW
);
652 const SwTableBoxes
& rBoxes
= pLine
->GetTabBoxes();
653 const size_t nBoxes
= rBoxes
.size();
655 sal_uInt32 nCPos
= 0U;
657 for( size_t nBox
=0U; nBox
<nBoxes
; nBox
++ )
659 SwTableBox
*pBox
= rBoxes
[nBox
];
661 if( nBox
< nBoxes
-1U )
662 nCPos
= nCPos
+ SwWriteTable::GetBoxWidth( pBox
);
664 nCPos
= pLines
->GetWidth();
667 const size_t nOldCol
= nCol
;
668 SwXMLTableColumn_Impl
aCol( nCPos
);
669 SwXMLTableColumns_Impl::const_iterator it
= pLines
->GetColumns().find( &aCol
);
670 OSL_ENSURE( it
!= pLines
->GetColumns().end(), "couldn't find column" );
671 nCol
= it
- pLines
->GetColumns().begin();
673 const SwStartNode
*pBoxSttNd
= pBox
->GetSttNd();
676 SwFrameFormat
*pFrameFormat2
= pBox
->GetFrameFormat();
677 if( rExpCells
.AddCell( *pFrameFormat2
, rNamePrefix
, nOldCol
, nLine
,
679 ExportFormat( *pFrameFormat2
, XML_TABLE_CELL
);
681 Reference
< XCell
> xCell
= SwXCell::CreateXCell(
682 const_cast<SwFrameFormat
*>(rTableInfo
.GetTableFormat()),
684 const_cast<SwTable
*>(rTableInfo
.GetTable()) );
687 Reference
< XText
> xText( xCell
, UNO_QUERY
);
688 if( !rTableInfo
.IsBaseSectionValid() )
690 Reference
<XPropertySet
> xCellPropertySet( xCell
,
692 Any aAny
= xCellPropertySet
->getPropertyValue("TextSection");
693 Reference
< XTextSection
> xTextSection
;
694 aAny
>>= xTextSection
;
695 rTableInfo
.SetBaseSection( xTextSection
);
698 const bool bExportContent
= bool(getExportFlags() & SvXMLExportFlags::CONTENT
);
699 if ( !bExportContent
)
701 // AUTOSTYLES - not needed anymore if we are currently exporting content.xml
702 GetTextParagraphExport()->collectTextAutoStyles(
703 xText
, rTableInfo
.GetBaseSection(), IsShowProgress() );
707 OSL_FAIL("here should be a XCell");
712 ExportTableLinesAutoStyles( pBox
->GetTabLines(),
713 nAbsWidth
, nBaseWidth
,
714 lcl_xmltble_appendBoxPrefix( rNamePrefix
,
715 nOldCol
, nLine
, bTop
),
716 rExpCols
, rExpRows
, rExpCells
,
725 void SwXMLExport::ExportTableAutoStyles( const SwTableNode
& rTableNd
)
727 const SwTable
& rTable
= rTableNd
.GetTable();
728 const SwFrameFormat
*pTableFormat
= rTable
.GetFrameFormat();
732 sal_Int16 eTabHoriOri
= pTableFormat
->GetHoriOrient().GetHoriOrient();
733 const SwFormatFrameSize
& rFrameSize
= pTableFormat
->GetFrameSize();
735 sal_uInt32 nAbsWidth
= rFrameSize
.GetSize().Width();
736 sal_uInt32 nBaseWidth
= 0UL;
737 sal_Int8 nPrcWidth
= rFrameSize
.GetWidthPercent();
739 bool bFixAbsWidth
= nPrcWidth
!= 0 || /*text::*/HoriOrientation::NONE
== eTabHoriOri
740 || /*text::*/HoriOrientation::FULL
== eTabHoriOri
;
743 nBaseWidth
= nAbsWidth
;
744 nAbsWidth
= pTableFormat
->FindLayoutRect(true).Width();
750 ExportTableFormat( *pTableFormat
, nAbsWidth
);
752 SwXMLTableColumnsSortByWidth_Impl aExpCols
;
753 SwXMLTableFrameFormatsSort_Impl aExpRows
;
754 SwXMLTableFrameFormatsSort_Impl aExpCells
;
755 SwXMLTableInfo_Impl
aTableInfo( &rTable
, XML_NAMESPACE_TABLE
);
756 ExportTableLinesAutoStyles( rTable
.GetTabLines(), nAbsWidth
, nBaseWidth
,
757 pTableFormat
->GetName(), aExpCols
, aExpRows
, aExpCells
,
762 void SwXMLExport::ExportTableBox( const SwTableBox
& rBox
,
765 SwXMLTableInfo_Impl
& rTableInfo
)
767 const SwStartNode
*pBoxSttNd
= rBox
.GetSttNd();
770 const SwFrameFormat
*pFrameFormat
= rBox
.GetFrameFormat();
773 const OUString sName
= pFrameFormat
->GetName();
774 if( !sName
.isEmpty() )
776 AddAttribute( XML_NAMESPACE_TABLE
, XML_STYLE_NAME
, EncodeStyleName(sName
) );
783 AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_ROWS_SPANNED
,
784 OUString::number(nRowSpan
) );
789 AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_COLUMNS_SPANNED
,
790 OUString::number(nColSpan
) );
796 // start node -> normal cell
797 // get cell range for table
798 Reference
<XCell
> xCell
= SwXCell::CreateXCell( const_cast<SwFrameFormat
*>(rTableInfo
.GetTableFormat()),
799 const_cast<SwTableBox
*>(&rBox
),
800 const_cast<SwTable
*>(rTableInfo
.GetTable()) );
804 Reference
<XText
> xText( xCell
, UNO_QUERY
);
806 // get formula (and protection)
807 const OUString sCellFormula
= xCell
->getFormula();
809 // if this cell has a formula, export it
810 // (with value and number format)
811 if (!sCellFormula
.isEmpty())
813 const OUString sQValue
=
814 GetNamespaceMap().GetQNameByKey(
815 XML_NAMESPACE_OOOW
, sCellFormula
, false );
817 AddAttribute(XML_NAMESPACE_TABLE
, XML_FORMULA
, sQValue
);
820 // value and format (if NumberFormat != -1)
821 Reference
<XPropertySet
> xCellPropertySet(xCell
,
823 if (xCellPropertySet
.is())
825 sal_Int32 nNumberFormat
= 0;
826 Any aAny
= xCellPropertySet
->getPropertyValue(g_sNumberFormat
);
827 aAny
>>= nNumberFormat
;
829 if (css::util::NumberFormat::TEXT
== nNumberFormat
)
832 AddAttribute( XML_NAMESPACE_OFFICE
,
833 XML_VALUE_TYPE
, XML_STRING
);
835 else if ( (-1 != nNumberFormat
) && !xText
->getString().isEmpty() )
837 // number format key:
838 // (export values only if cell contains text;)
839 XMLNumberFormatAttributesExportHelper::
840 SetNumberFormatAttributes(
841 *this, nNumberFormat
, xCell
->getValue() );
843 // else: invalid key; ignore
846 aAny
= xCellPropertySet
->getPropertyValue(g_sIsProtected
);
847 if (*o3tl::doAccess
<bool>(aAny
))
849 AddAttribute( XML_NAMESPACE_TABLE
, XML_PROTECTED
,
853 if( !rTableInfo
.IsBaseSectionValid() )
855 aAny
= xCellPropertySet
->getPropertyValue("TextSection");
856 Reference
< XTextSection
> xTextSection
;
857 aAny
>>= xTextSection
;
858 rTableInfo
.SetBaseSection( xTextSection
);
862 // export cell element
863 SvXMLElementExport
aElem( *this, rTableInfo
.GetPrefix(),
864 XML_TABLE_CELL
, true, true );
866 // export cell content
867 GetTextParagraphExport()->exportText( xText
,
868 rTableInfo
.GetBaseSection(),
873 OSL_FAIL("here should be a XCell");
879 // no start node -> merged cells: export subtable in cell
880 SvXMLElementExport
aElem( *this, XML_NAMESPACE_TABLE
,
881 XML_TABLE_CELL
, true, true );
883 AddAttribute( XML_NAMESPACE_TABLE
, XML_IS_SUB_TABLE
,
884 GetXMLToken( XML_TRUE
) );
886 SvXMLElementExport
aElemExport( *this, XML_NAMESPACE_TABLE
,
887 XML_TABLE
, true, true );
888 ExportTableLines( rBox
.GetTabLines(), rTableInfo
);
894 void SwXMLExport::ExportTableLine( const SwTableLine
& rLine
,
895 const SwXMLTableLines_Impl
& rLines
,
896 SwXMLTableInfo_Impl
& rTableInfo
)
898 if( rLine
.hasSoftPageBreak() )
900 SvXMLElementExport
aElem( *this, XML_NAMESPACE_TEXT
,
901 XML_SOFT_PAGE_BREAK
, true, true );
903 const SwFrameFormat
*pFrameFormat
= rLine
.GetFrameFormat();
906 const OUString sName
= pFrameFormat
->GetName();
907 if( !sName
.isEmpty() )
909 AddAttribute( XML_NAMESPACE_TABLE
, XML_STYLE_NAME
, EncodeStyleName(sName
) );
914 SvXMLElementExport
aElem( *this, rTableInfo
.GetPrefix(), XML_TABLE_ROW
, true, true );
915 const SwTableBoxes
& rBoxes
= rLine
.GetTabBoxes();
916 const size_t nBoxes
= rBoxes
.size();
918 sal_uInt32 nCPos
= 0U;
920 for( size_t nBox
=0U; nBox
<nBoxes
; ++nBox
)
922 const SwTableBox
*pBox
= rBoxes
[nBox
];
925 const long nRowSpan
= pBox
->getRowSpan();
928 SvXMLElementExport
aElem2( *this, rTableInfo
.GetPrefix(),
929 XML_COVERED_TABLE_CELL
, true,
933 if( nBox
< nBoxes
-1U )
934 nCPos
= nCPos
+ SwWriteTable::GetBoxWidth( pBox
);
936 nCPos
= rLines
.GetWidth();
939 const size_t nOldCol
= nCol
;
940 SwXMLTableColumn_Impl
aCol( nCPos
);
941 SwXMLTableColumns_Impl::const_iterator it
= rLines
.GetColumns().find( &aCol
);
942 OSL_ENSURE( it
!= rLines
.GetColumns().end(), "couldn't find column" );
943 nCol
= it
- rLines
.GetColumns().begin();
945 // #i95726# - Some fault tolerance, if table is somehow corrupted.
946 if ( nCol
< nOldCol
)
948 OSL_FAIL( "table and/or table information seems to be corrupted." );
949 // NOTE: nOldCol is not necessarily a valid index into
950 // GetColumns(), but that doesn't matter here
954 const sal_uInt32 nColSpan
= nCol
- nOldCol
+ 1U;
957 ExportTableBox( *pBox
, nColSpan
, static_cast< sal_uInt32
>(nRowSpan
), rTableInfo
);
959 for( size_t i
=nOldCol
; i
<nCol
; ++i
)
961 SvXMLElementExport
aElemExport( *this, rTableInfo
.GetPrefix(),
962 XML_COVERED_TABLE_CELL
, true,
971 void SwXMLExport::ExportTableLines( const SwTableLines
& rLines
,
972 SwXMLTableInfo_Impl
& rTableInfo
,
973 sal_uInt32 nHeaderRows
)
975 OSL_ENSURE( pTableLines
&& !pTableLines
->empty(),
976 "SwXMLExport::ExportTableLines: table columns infos missing" );
977 if( !pTableLines
|| pTableLines
->empty() )
980 SwXMLTableLines_Impl
* pLines
= nullptr;
982 for( nInfoPos
=0; nInfoPos
< pTableLines
->size(); nInfoPos
++ )
984 if( pTableLines
->at( nInfoPos
)->GetLines() == &rLines
)
986 pLines
= pTableLines
->at( nInfoPos
);
991 "SwXMLExport::ExportTableLines: table columns info missing" );
992 OSL_ENSURE( 0==nInfoPos
,
993 "SwXMLExport::ExportTableLines: table columns infos are unsorted" );
997 SwXMLTableLinesCache_Impl::iterator it
= pTableLines
->begin();
998 advance( it
, nInfoPos
);
999 pTableLines
->erase( it
);
1001 if( pTableLines
->empty() )
1003 delete pTableLines
;
1004 pTableLines
= nullptr;
1007 // pass 2: export columns
1008 const SwXMLTableColumns_Impl
& rCols
= pLines
->GetColumns();
1009 size_t nColumn
= 0U;
1010 const size_t nColumns
= rCols
.size();
1011 sal_Int32 nColRep
= 1;
1012 SwXMLTableColumn_Impl
*pColumn
= (nColumns
> 0) ? rCols
[0U] : nullptr;
1016 SwXMLTableColumn_Impl
*pNextColumn
=
1017 (nColumn
< nColumns
) ? rCols
[nColumn
] : nullptr;
1019 pNextColumn
->GetStyleName() == pColumn
->GetStyleName() )
1025 AddAttribute( XML_NAMESPACE_TABLE
, XML_STYLE_NAME
,
1026 EncodeStyleName(pColumn
->GetStyleName()) );
1030 AddAttribute( XML_NAMESPACE_TABLE
, XML_NUMBER_COLUMNS_REPEATED
,
1031 OUString::number(nColRep
) );
1035 SvXMLElementExport
aElem( *this, rTableInfo
.GetPrefix(), XML_TABLE_COLUMN
, true, true );
1040 pColumn
= pNextColumn
;
1043 // pass 3: export line/rows
1044 const size_t nLines
= rLines
.size();
1045 // export header rows, if present
1046 if( nHeaderRows
> 0 )
1048 SvXMLElementExport
aElem( *this, XML_NAMESPACE_TABLE
,
1049 XML_TABLE_HEADER_ROWS
, true, true );
1051 OSL_ENSURE( nHeaderRows
<= nLines
, "more headers then lines?" );
1052 for( size_t nLine
= 0U; nLine
< nHeaderRows
; ++nLine
)
1053 ExportTableLine( *(rLines
[nLine
]), *pLines
, rTableInfo
);
1055 // export remaining rows
1056 for( size_t nLine
= nHeaderRows
; nLine
< nLines
; ++nLine
)
1058 ExportTableLine( *(rLines
[nLine
]), *pLines
, rTableInfo
);
1064 static void lcl_xmltble_ClearName_Line( SwTableLine
* pLine
);
1066 static void lcl_xmltble_ClearName_Box( SwTableBox
* pBox
)
1068 if( !pBox
->GetSttNd() )
1070 for( SwTableLine
* pLine
: pBox
->GetTabLines() )
1071 lcl_xmltble_ClearName_Line( pLine
);
1075 SwFrameFormat
*pFrameFormat
= pBox
->GetFrameFormat();
1076 if( pFrameFormat
&& !pFrameFormat
->GetName().isEmpty() )
1077 pFrameFormat
->SetName( OUString() );
1081 void lcl_xmltble_ClearName_Line( SwTableLine
* pLine
)
1083 for( SwTableBox
* pBox
: pLine
->GetTabBoxes() )
1084 lcl_xmltble_ClearName_Box( pBox
);
1087 void SwXMLExport::ExportTable( const SwTableNode
& rTableNd
)
1089 const SwTable
& rTable
= rTableNd
.GetTable();
1090 const SwFrameFormat
*pTableFormat
= rTable
.GetFrameFormat();
1091 if( pTableFormat
&& !pTableFormat
->GetName().isEmpty() )
1093 AddAttribute( XML_NAMESPACE_TABLE
, XML_NAME
, pTableFormat
->GetName() );
1094 AddAttribute( XML_NAMESPACE_TABLE
, XML_STYLE_NAME
,
1095 EncodeStyleName( pTableFormat
->GetName() ) );
1098 sal_uInt16 nPrefix
= XML_NAMESPACE_TABLE
;
1099 if (const SwFrameFormat
* pFlyFormat
= rTableNd
.GetFlyFormat())
1101 std::set
<const SwFrameFormat
*> aTextBoxes
= SwTextBoxHelper::findTextBoxes(rTableNd
.GetDoc());
1102 if (aTextBoxes
.find(pFlyFormat
) != aTextBoxes
.end())
1103 nPrefix
= XML_NAMESPACE_LO_EXT
;
1107 SvXMLElementExport
aElem( *this, nPrefix
, XML_TABLE
, true, true );
1109 // export DDE source (if this is a DDE table)
1110 if ( dynamic_cast<const SwDDETable
*>( &rTable
) != nullptr )
1112 // get DDE Field Type (contains the DDE connection)
1113 const SwDDEFieldType
* pDDEFieldType
=
1114 static_cast<const SwDDETable
&>(rTable
).GetDDEFieldType();
1117 AddAttribute( XML_NAMESPACE_OFFICE
, XML_NAME
,
1118 pDDEFieldType
->GetName() );
1121 const OUString sCmd
= pDDEFieldType
->GetCmd();
1122 AddAttribute( XML_NAMESPACE_OFFICE
, XML_DDE_APPLICATION
,
1123 sCmd
.getToken(0, sfx2::cTokenSeparator
) );
1124 AddAttribute( XML_NAMESPACE_OFFICE
, XML_DDE_ITEM
,
1125 sCmd
.getToken(1, sfx2::cTokenSeparator
) );
1126 AddAttribute( XML_NAMESPACE_OFFICE
, XML_DDE_TOPIC
,
1127 sCmd
.getToken(2, sfx2::cTokenSeparator
) );
1130 if (pDDEFieldType
->GetType() == SfxLinkUpdateMode::ALWAYS
)
1132 AddAttribute( XML_NAMESPACE_OFFICE
,
1133 XML_AUTOMATIC_UPDATE
, XML_TRUE
);
1136 // DDE source element (always empty)
1137 SvXMLElementExport
aSource(*this, XML_NAMESPACE_OFFICE
,
1138 XML_DDE_SOURCE
, true, false);
1141 SwXMLTableInfo_Impl
aTableInfo( &rTable
, nPrefix
);
1142 ExportTableLines( rTable
.GetTabLines(), aTableInfo
, rTable
.GetRowsToRepeat() );
1144 for( SwTableLine
*pLine
: ((SwTable
&)rTable
).GetTabLines() )
1145 lcl_xmltble_ClearName_Line( pLine
);
1149 void SwXMLTextParagraphExport::exportTable(
1150 const Reference
< XTextContent
> & rTextContent
,
1151 bool bAutoStyles
, bool _bProgress
)
1153 bool bOldShowProgress
= static_cast<SwXMLExport
&>(GetExport()).IsShowProgress();
1154 static_cast<SwXMLExport
&>(GetExport()).SetShowProgress( _bProgress
);
1156 Reference
< XTextTable
> xTextTable( rTextContent
, UNO_QUERY
);
1157 OSL_ENSURE( xTextTable
.is(), "text table missing" );
1158 if( xTextTable
.is() )
1160 SwXTextTable
*pXTable
= nullptr;
1161 Reference
<XUnoTunnel
> xTableTunnel( rTextContent
, UNO_QUERY
);
1162 if( xTableTunnel
.is() )
1164 pXTable
= reinterpret_cast< SwXTextTable
* >(
1165 sal::static_int_cast
< sal_IntPtr
>( xTableTunnel
->getSomething( SwXTextTable::getUnoTunnelId() )));
1166 OSL_ENSURE( pXTable
, "SwXTextTable missing" );
1170 SwFrameFormat
*const pFormat
= pXTable
->GetFrameFormat();
1171 OSL_ENSURE( pFormat
, "table format missing" );
1172 const SwTable
*pTable
= SwTable::FindTable( pFormat
);
1173 OSL_ENSURE( pTable
, "table missing" );
1174 const SwTableNode
*pTableNd
= pTable
->GetTableNode();
1175 OSL_ENSURE( pTableNd
, "table node missing" );
1178 SwNodeIndex
aIdx( *pTableNd
);
1179 // AUTOSTYLES: Optimization: Do not export table autostyle if
1180 // we are currently exporting the content.xml stuff and
1181 // the table is located in header/footer:
1182 // During the flat XML export (used e.g. by .sdw-export)
1183 // ALL flags are set at the same time.
1184 const bool bExportStyles
= bool( GetExport().getExportFlags() & SvXMLExportFlags::STYLES
);
1185 if ( bExportStyles
|| !pFormat
->GetDoc()->IsInHeaderFooter( aIdx
) )
1186 static_cast<SwXMLExport
&>(GetExport()).ExportTableAutoStyles( *pTableNd
);
1190 static_cast<SwXMLExport
&>(GetExport()).ExportTable( *pTableNd
);
1195 static_cast<SwXMLExport
&>(GetExport()).SetShowProgress( bOldShowProgress
);
1198 void SwXMLExport::DeleteTableLines()
1202 for (SwXMLTableLines_Impl
* p
: *pTableLines
)
1204 pTableLines
->clear();
1209 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */