Clean up uses of Any::getValue() in sw
[LibreOffice.git] / sw / source / filter / xml / xmltble.cxx
blobf4b89d1985eb1bdf124be2a0d07f414b3a3752a7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
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>
35 #include <list>
36 #include "swtable.hxx"
37 #include "doc.hxx"
38 #include "pam.hxx"
39 #include "frmfmt.hxx"
40 #include "wrtswtbl.hxx"
41 #include "fmtfsize.hxx"
42 #include "fmtornt.hxx"
43 #include "cellatr.hxx"
44 #include "ddefld.hxx"
45 #include "swddetbl.hxx"
46 #include <ndole.hxx>
47 #include <xmloff/nmspmap.hxx>
48 #include <sfx2/linkmgr.hxx>
49 #include "unotbl.hxx"
50 #include "xmltexte.hxx"
51 #include "xmlexp.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;
63 using table::XCell;
64 using ::std::vector;
65 using ::std::advance;
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
73 OUString sStyleName;
74 sal_uInt32 nRelWidth;
76 public:
78 explicit SwXMLTableColumn_Impl(sal_uInt32 nPosition)
79 : SwWriteTableCol(nPosition)
80 , nRelWidth(0UL)
81 {};
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();
95 if( !n )
96 n = (sal_Int32)lhs->GetRelWidth() - (sal_Int32)rhs->GetRelWidth();
97 return n < 0;
101 class SwXMLTableColumns_Impl : public o3tl::sorted_vector<SwXMLTableColumn_Impl*, o3tl::less_ptr_to<SwXMLTableColumn_Impl> > {
102 public:
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;
112 sal_uInt32 nWidth;
114 public:
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 ) :
127 pLines( &rLines ),
128 nWidth( 0UL )
130 #if OSL_DEBUG_LEVEL > 0
131 sal_uInt32 nEndCPos = 0U;
132 #endif
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 )
152 delete pCol;
154 if( nBox==nBoxes-1U )
156 OSL_ENSURE( nLine==0U && nWidth==0UL,
157 "parent width will be lost" );
158 nWidth = nCPos;
161 else
163 #if OSL_DEBUG_LEVEL > 0
164 sal_uInt32 nCheckPos =
165 nCPos + SwWriteTable::GetBoxWidth( pBox );
166 if( !nEndCPos )
168 nEndCPos = nCheckPos;
170 #endif
171 nCPos = nWidth;
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" );
178 #endif
184 typedef vector< SwFrameFormat* > SwXMLFrameFormats_Impl;
186 class SwXMLTableFrameFormatsSort_Impl
188 private:
189 SwXMLFrameFormats_Impl aFormatList;
190 public:
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,
198 sal_uInt32 nLine )
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 )
217 return false;
219 // order is: -/brush, size/-, size/brush
220 bool bInsert = true;
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,
230 &pItem ) )
232 if( !pFrameSize )
233 break;
235 pTestFrameSize = static_cast<const SwFormatFrameSize *>(pItem);
237 else
239 if( pFrameSize )
240 continue;
243 if( SfxItemState::SET == rTestSet.GetItemState( RES_BACKGROUND, false,
244 &pItem ) )
246 if( !pBrush )
247 break;
249 pTestBrush = static_cast<const SvxBrushItem *>(pItem);
251 else
253 if( pBrush )
254 continue;
257 if( SfxItemState::SET == rTestSet.GetItemState( RES_ROW_SPLIT, false,
258 &pItem ) )
260 if( !pRowSplit )
261 break;
263 pTestRowSplit = static_cast<const SwFormatRowSplit *>(pItem);
265 else
267 if( pRowSplit )
268 continue;
271 if( pFrameSize &&
272 ( pFrameSize->GetHeightSizeType() != pTestFrameSize->GetHeightSizeType() ||
273 pFrameSize->GetHeight() != pTestFrameSize->GetHeight() ) )
274 continue;
276 if( pBrush && (*pBrush != *pTestBrush) )
277 continue;
279 if( pRowSplit && (!pRowSplit->GetValue() != !pTestRowSplit->GetValue()) )
280 continue;
282 // found!
283 rFrameFormat.SetName( pTestFormat->GetName() );
284 bInsert = false;
285 break;
288 if( bInsert )
290 rFrameFormat.SetName( rNamePrefix + "." + OUString::number(nLine+1UL) );
291 if ( i != aFormatList.end() ) ++i;
292 aFormatList.insert( i, &rFrameFormat );
295 return bInsert;
298 static OUString lcl_xmltble_appendBoxPrefix(const OUString& rNamePrefix,
299 sal_uInt32 nCol, sal_uInt32 nRow, bool bTop )
301 if( bTop )
303 OUString sTmp;
304 sw_GetTableBoxColStr( (sal_uInt16)nCol, sTmp );
305 return rNamePrefix + "." + sTmp + OUString::number(nRow + 1);
307 return rNamePrefix
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,
326 &pItem ) )
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,
336 false, &pItem ) )
337 pNumFormat = static_cast<const SwTableBoxNumFormat *>(pItem);
338 if ( SfxItemState::SET == rItemSet.GetItemState( RES_FRAMEDIR,
339 false, &pItem ) )
340 pFrameDir = static_cast<const SvxFrameDirectionItem *>(pItem);
341 if ( SfxItemState::SET == rItemSet.GetItemState( RES_UNKNOWNATR_CONTAINER,
342 false, &pItem ) )
343 pAttCnt = static_cast<const SvXMLAttrContainerItem *>(pItem);
345 // empty styles have not to be exported
346 if( !pVertOrient && !pBrush && !pBox && !pNumFormat && !pFrameDir && !pAttCnt )
347 return false;
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
355 bool bInsert = true;
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,
368 &pItem ) )
370 if( !pVertOrient )
371 break;
373 pTestVertOrient = static_cast<const SwFormatVertOrient *>(pItem);
375 else
377 if( pVertOrient )
378 continue;
381 if( SfxItemState::SET == rTestSet.GetItemState( RES_BACKGROUND, false,
382 &pItem ) )
384 if( !pBrush )
385 break;
387 pTestBrush = static_cast<const SvxBrushItem *>(pItem);
389 else
391 if( pBrush )
392 continue;
395 if( SfxItemState::SET == rTestSet.GetItemState( RES_BOX, false, &pItem ) )
397 if( !pBox )
398 break;
400 pTestBox = static_cast<const SvxBoxItem *>(pItem);
402 else
404 if( pBox )
405 continue;
408 if ( SfxItemState::SET == rTestSet.GetItemState( RES_BOXATR_FORMAT,
409 false, &pItem ) )
411 if( !pNumFormat )
412 break;
414 pTestNumFormat = static_cast<const SwTableBoxNumFormat *>(pItem);
416 else
418 if( pNumFormat )
419 continue;
423 if ( SfxItemState::SET == rTestSet.GetItemState( RES_FRAMEDIR,
424 false, &pItem ) )
426 if( !pFrameDir )
427 break;
429 pTestFrameDir = static_cast<const SvxFrameDirectionItem *>(pItem);
431 else
433 if( pFrameDir )
434 continue;
438 if ( SfxItemState::SET == rTestSet.GetItemState( RES_UNKNOWNATR_CONTAINER,
439 false, &pItem ) )
441 if( !pAttCnt )
442 break;
444 pTestAttCnt = static_cast<const SvXMLAttrContainerItem *>(pItem);
446 else
448 if ( pAttCnt )
449 continue;
453 if( pVertOrient &&
454 pVertOrient->GetVertOrient() != pTestVertOrient->GetVertOrient() )
455 continue;
457 if( pBrush && ( *pBrush != *pTestBrush ) )
458 continue;
460 if( pBox && ( *pBox != *pTestBox ) )
461 continue;
463 if( pNumFormat && pNumFormat->GetValue() != pTestNumFormat->GetValue() )
464 continue;
466 if( pFrameDir && pFrameDir->GetValue() != pTestFrameDir->GetValue() )
467 continue;
469 if( pAttCnt && ( *pAttCnt != *pTestAttCnt ) )
470 continue;
472 // found!
473 rFrameFormat.SetName( pTestFormat->GetName() );
474 bInsert = false;
475 break;
478 if( bInsert )
480 rFrameFormat.SetName( lcl_xmltble_appendBoxPrefix( rNamePrefix, nCol, nRow, bTop ) );
481 if ( i != aFormatList.end() ) ++i;
482 aFormatList.insert( i, &rFrameFormat );
485 return bInsert;
488 class SwXMLTableInfo_Impl
490 const SwTable *m_pTable;
491 Reference<XTextSection> m_xBaseSection;
492 bool m_bBaseSectionValid;
493 sal_uInt32 m_nPrefix;
495 public:
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) :
510 m_pTable(pTable),
511 m_bBaseSectionValid(false),
512 m_nPrefix(nPrefix)
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 )
525 // <style:style ...>
526 CheckAttrList();
528 // style:name="..."
529 bool bEncoded = false;
530 AddAttribute( XML_NAMESPACE_STYLE, XML_NAME,
531 EncodeStyleName( rCol.GetStyleName(), &bEncoded ) );
532 if( 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,
540 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,
560 true, true );
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,
572 bool bTop )
574 // pass 1: calculate columns
575 SwXMLTableLines_Impl *pLines = new SwXMLTableLines_Impl( rLines );
576 if( !pTableLines )
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.
598 if( nBaseWidth )
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.
607 if( nAbsWidth )
609 sal_uInt32 nColAbsWidth = nWidth;
610 if( nBaseWidth )
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() );
624 else
626 if( bTop )
628 OUString sTmp;
629 sw_GetTableBoxColStr( nColumn, sTmp );
630 pColumn->SetStyleName( rNamePrefix + "." + sTmp );
632 else
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;
656 size_t nCol = 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 );
663 else
664 nCPos = pLines->GetWidth();
666 // Und ihren Index
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();
674 if( pBoxSttNd )
676 SwFrameFormat *pFrameFormat2 = pBox->GetFrameFormat();
677 if( rExpCells.AddCell( *pFrameFormat2, rNamePrefix, nOldCol, nLine,
678 bTop) )
679 ExportFormat( *pFrameFormat2, XML_TABLE_CELL );
681 Reference < XCell > xCell = SwXCell::CreateXCell(
682 const_cast<SwFrameFormat *>(rTableInfo.GetTableFormat()),
683 pBox,
684 const_cast<SwTable *>(rTableInfo.GetTable()) );
685 if (xCell.is())
687 Reference < XText > xText( xCell, UNO_QUERY );
688 if( !rTableInfo.IsBaseSectionValid() )
690 Reference<XPropertySet> xCellPropertySet( xCell,
691 UNO_QUERY );
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() );
706 else {
707 OSL_FAIL("here should be a XCell");
710 else
712 ExportTableLinesAutoStyles( pBox->GetTabLines(),
713 nAbsWidth, nBaseWidth,
714 lcl_xmltble_appendBoxPrefix( rNamePrefix,
715 nOldCol, nLine, bTop ),
716 rExpCols, rExpRows, rExpCells,
717 rTableInfo );
720 nCol++;
725 void SwXMLExport::ExportTableAutoStyles( const SwTableNode& rTableNd )
727 const SwTable& rTable = rTableNd.GetTable();
728 const SwFrameFormat *pTableFormat = rTable.GetFrameFormat();
730 if( pTableFormat )
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;
741 if( bFixAbsWidth )
743 nBaseWidth = nAbsWidth;
744 nAbsWidth = pTableFormat->FindLayoutRect(true).Width();
745 if( !nAbsWidth )
747 // TODO?
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,
758 aTableInfo, true);
762 void SwXMLExport::ExportTableBox( const SwTableBox& rBox,
763 sal_uInt32 nColSpan,
764 sal_uInt32 nRowSpan,
765 SwXMLTableInfo_Impl& rTableInfo )
767 const SwStartNode *pBoxSttNd = rBox.GetSttNd();
768 if( pBoxSttNd )
770 const SwFrameFormat *pFrameFormat = rBox.GetFrameFormat();
771 if( pFrameFormat )
773 const OUString sName = pFrameFormat->GetName();
774 if( !sName.isEmpty() )
776 AddAttribute( XML_NAMESPACE_TABLE, XML_STYLE_NAME, EncodeStyleName(sName) );
781 if( nRowSpan != 1 )
783 AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED,
784 OUString::number(nRowSpan) );
787 if( nColSpan != 1 )
789 AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED,
790 OUString::number(nColSpan) );
794 if( pBoxSttNd )
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()) );
802 if (xCell.is())
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 );
816 // formula
817 AddAttribute(XML_NAMESPACE_TABLE, XML_FORMULA, sQValue );
820 // value and format (if NumberFormat != -1)
821 Reference<XPropertySet> xCellPropertySet(xCell,
822 UNO_QUERY);
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)
831 // text format
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
845 // cell protection
846 aAny = xCellPropertySet->getPropertyValue(g_sIsProtected);
847 if (*o3tl::doAccess<bool>(aAny))
849 AddAttribute( XML_NAMESPACE_TABLE, XML_PROTECTED,
850 XML_TRUE );
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(),
869 IsShowProgress() );
871 else
873 OSL_FAIL("here should be a XCell");
874 ClearAttrList();
877 else
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();
904 if( pFrameFormat )
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;
919 size_t nCol = 0U;
920 for( size_t nBox=0U; nBox<nBoxes; ++nBox )
922 const SwTableBox *pBox = rBoxes[nBox];
924 // NEW TABLES
925 const long nRowSpan = pBox->getRowSpan();
926 if( nRowSpan < 1 )
928 SvXMLElementExport aElem2( *this, rTableInfo.GetPrefix(),
929 XML_COVERED_TABLE_CELL, true,
930 false );
933 if( nBox < nBoxes-1U )
934 nCPos = nCPos + SwWriteTable::GetBoxWidth( pBox );
935 else
936 nCPos = rLines.GetWidth();
938 // Und ihren Index
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
951 nCol = nOldCol;
954 const sal_uInt32 nColSpan = nCol - nOldCol + 1U;
956 if ( nRowSpan >= 1 )
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,
963 false );
966 nCol++;
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() )
978 return;
980 SwXMLTableLines_Impl* pLines = nullptr;
981 size_t nInfoPos;
982 for( nInfoPos=0; nInfoPos < pTableLines->size(); nInfoPos++ )
984 if( pTableLines->at( nInfoPos )->GetLines() == &rLines )
986 pLines = pTableLines->at( nInfoPos );
987 break;
990 OSL_ENSURE( pLines,
991 "SwXMLExport::ExportTableLines: table columns info missing" );
992 OSL_ENSURE( 0==nInfoPos,
993 "SwXMLExport::ExportTableLines: table columns infos are unsorted" );
994 if( !pLines )
995 return;
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;
1013 while( pColumn )
1015 nColumn++;
1016 SwXMLTableColumn_Impl *pNextColumn =
1017 (nColumn < nColumns) ? rCols[nColumn] : nullptr;
1018 if( pNextColumn &&
1019 pNextColumn->GetStyleName() == pColumn->GetStyleName() )
1021 nColRep++;
1023 else
1025 AddAttribute( XML_NAMESPACE_TABLE, XML_STYLE_NAME,
1026 EncodeStyleName(pColumn->GetStyleName()) );
1028 if( nColRep > 1 )
1030 AddAttribute( XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED,
1031 OUString::number(nColRep) );
1035 SvXMLElementExport aElem( *this, rTableInfo.GetPrefix(), XML_TABLE_COLUMN, true, true );
1038 nColRep = 1;
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 );
1061 delete pLines;
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 );
1073 else
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();
1116 // connection name
1117 AddAttribute( XML_NAMESPACE_OFFICE, XML_NAME,
1118 pDDEFieldType->GetName() );
1120 // DDE command
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) );
1129 // auto update
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" );
1168 if( pXTable )
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" );
1176 if( bAutoStyles )
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 );
1188 else
1190 static_cast<SwXMLExport&>(GetExport()).ExportTable( *pTableNd );
1195 static_cast<SwXMLExport&>(GetExport()).SetShowProgress( bOldShowProgress );
1198 void SwXMLExport::DeleteTableLines()
1200 if ( pTableLines )
1202 for (SwXMLTableLines_Impl* p : *pTableLines)
1203 delete p;
1204 pTableLines->clear();
1205 delete pTableLines;
1209 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */