android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / filter / xml / xmltbli.cxx
blob9578b45cdfe7a9b5854bf83765032b34ad188ffd
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 <hintids.hxx>
22 #include <com/sun/star/frame/XModel.hpp>
23 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
24 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
25 #include <com/sun/star/text/XTextTable.hpp>
26 #include <com/sun/star/table/XCellRange.hpp>
27 #include <comphelper/servicehelper.hxx>
28 #include <o3tl/numeric.hxx>
29 #include <o3tl/safeint.hxx>
30 #include <sal/log.hxx>
31 #include <svl/itemset.hxx>
32 #include <svl/numformat.hxx>
33 #include <svl/zformat.hxx>
34 #include <sax/tools/converter.hxx>
35 #include <unotools/configmgr.hxx>
36 #include <utility>
37 #include <xmloff/xmlnamespace.hxx>
38 #include <xmloff/namespacemap.hxx>
40 #include <xmloff/families.hxx>
41 #include <xmloff/xmluconv.hxx>
42 #include <xmloff/i18nmap.hxx>
43 #include <editeng/protitem.hxx>
44 #include <editeng/lrspitem.hxx>
45 #include <poolfmt.hxx>
46 #include <fmtfsize.hxx>
47 #include <fmtornt.hxx>
48 #include <fmtfordr.hxx>
49 #include <doc.hxx>
50 #include <IDocumentFieldsAccess.hxx>
51 #include <IDocumentLayoutAccess.hxx>
52 #include <IDocumentStylePoolAccess.hxx>
53 #include <swtable.hxx>
54 #include <swtblfmt.hxx>
55 #include <pam.hxx>
56 #include <unoprnms.hxx>
57 #include <unotbl.hxx>
58 #include <unotextrange.hxx>
59 #include <cellatr.hxx>
60 #include <swddetbl.hxx>
61 #include <ddefld.hxx>
62 #include <sfx2/linkmgr.hxx>
63 #include "xmlimp.hxx"
64 #include "xmltbli.hxx"
65 #include <vcl/svapp.hxx>
66 #include <ndtxt.hxx>
67 #include <unotextcursor.hxx>
68 #include <SwStyleNameMapper.hxx>
69 #include <IDocumentSettingAccess.hxx>
71 #include <algorithm>
72 #include <vector>
73 #include <memory>
75 #include <limits.h>
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::uno;
80 using namespace ::com::sun::star::lang;
81 using namespace ::com::sun::star::text;
82 using namespace ::com::sun::star::table;
83 using namespace ::com::sun::star::xml::sax;
84 using namespace ::xmloff::token;
86 class SwXMLTableCell_Impl
88 OUString m_aStyleName;
90 OUString m_StringValue;
92 OUString m_sFormula; // cell formula; valid if length > 0
93 double m_dValue; // formula value
95 SvXMLImportContextRef m_xSubTable;
97 const SwStartNode *m_pStartNode;
98 sal_uInt32 m_nRowSpan;
99 sal_uInt32 m_nColSpan;
101 bool m_bProtected : 1;
102 bool m_bHasValue; // determines whether dValue attribute is valid
103 bool mbCovered;
104 bool m_bHasStringValue;
106 public:
108 SwXMLTableCell_Impl( sal_uInt32 nRSpan=1, sal_uInt32 nCSpan=1 ) :
109 m_dValue( 0.0 ),
110 m_pStartNode( nullptr ),
111 m_nRowSpan( nRSpan ),
112 m_nColSpan( nCSpan ),
113 m_bProtected( false ),
114 m_bHasValue( false ),
115 mbCovered( false )
116 , m_bHasStringValue(false)
119 inline void Set( const OUString& rStyleName,
120 sal_uInt32 nRSpan, sal_uInt32 nCSpan,
121 const SwStartNode *pStNd, SwXMLTableContext *pTable,
122 bool bProtect,
123 const OUString* pFormula,
124 bool bHasValue,
125 bool bCovered,
126 double dVal,
127 OUString const*const pStringValue);
129 bool IsUsed() const { return m_pStartNode!=nullptr ||
130 m_xSubTable.is() || m_bProtected;}
132 sal_uInt32 GetRowSpan() const { return m_nRowSpan; }
133 void SetRowSpan( sal_uInt32 nSet ) { m_nRowSpan = nSet; }
134 sal_uInt32 GetColSpan() const { return m_nColSpan; }
135 void SetStyleName(const OUString& rStyleName) { m_aStyleName = rStyleName; }
136 const OUString& GetStyleName() const { return m_aStyleName; }
137 const OUString& GetFormula() const { return m_sFormula; }
138 double GetValue() const { return m_dValue; }
139 bool HasValue() const { return m_bHasValue; }
140 bool IsProtected() const { return m_bProtected; }
141 bool IsCovered() const { return mbCovered; }
142 bool HasStringValue() const { return m_bHasStringValue; }
143 OUString const* GetStringValue() const {
144 return m_bHasStringValue ? &m_StringValue : nullptr;
147 const SwStartNode *GetStartNode() const { return m_pStartNode; }
148 inline void SetStartNode( const SwStartNode *pSttNd );
150 inline SwXMLTableContext *GetSubTable() const;
152 inline void Dispose();
155 inline void SwXMLTableCell_Impl::Set( const OUString& rStyleName,
156 sal_uInt32 nRSpan, sal_uInt32 nCSpan,
157 const SwStartNode *pStNd,
158 SwXMLTableContext *pTable,
159 bool bProtect,
160 const OUString* pFormula,
161 bool bHasVal,
162 bool bCov,
163 double dVal,
164 OUString const*const pStringValue )
166 m_aStyleName = rStyleName;
167 m_nRowSpan = nRSpan;
168 m_nColSpan = nCSpan;
169 m_pStartNode = pStNd;
170 m_xSubTable = pTable;
171 m_dValue = dVal;
172 m_bHasValue = bHasVal;
173 mbCovered = bCov;
174 if (pStringValue)
176 m_StringValue = *pStringValue;
178 m_bHasStringValue = (pStringValue != nullptr);
179 m_bProtected = bProtect;
181 // set formula, if valid
182 if (pFormula != nullptr)
184 m_sFormula = *pFormula;
188 inline void SwXMLTableCell_Impl::SetStartNode( const SwStartNode *pSttNd )
190 m_pStartNode = pSttNd;
191 m_xSubTable = nullptr;
194 inline SwXMLTableContext *SwXMLTableCell_Impl::GetSubTable() const
196 return static_cast<SwXMLTableContext *>(m_xSubTable.get());
199 inline void SwXMLTableCell_Impl::Dispose()
201 if( m_xSubTable.is() )
202 m_xSubTable = nullptr;
205 class SwXMLTableRow_Impl
207 OUString m_aStyleName;
208 OUString m_aDefaultCellStyleName;
209 std::vector<std::unique_ptr<SwXMLTableCell_Impl>> m_Cells;
210 bool m_bSplitable;
212 public:
214 SwXMLTableRow_Impl( OUString aStyleName, sal_uInt32 nCells,
215 const OUString *pDfltCellStyleName = nullptr );
217 inline SwXMLTableCell_Impl *GetCell( sal_uInt32 nCol );
219 inline void Set( const OUString& rStyleName,
220 const OUString& rDfltCellStyleName );
222 void Expand( sal_uInt32 nCells, bool bOneCell );
224 void SetSplitable( bool bSet ) { m_bSplitable = bSet; }
225 bool IsSplitable() const { return m_bSplitable; }
227 const OUString& GetStyleName() const { return m_aStyleName; }
228 const OUString& GetDefaultCellStyleName() const { return m_aDefaultCellStyleName; }
230 void Dispose();
233 SwXMLTableRow_Impl::SwXMLTableRow_Impl( OUString aStyleName,
234 sal_uInt32 nCells,
235 const OUString *pDfltCellStyleName ) :
236 m_aStyleName(std::move( aStyleName )),
237 m_bSplitable( false )
239 if( pDfltCellStyleName )
240 m_aDefaultCellStyleName = *pDfltCellStyleName;
241 OSL_ENSURE( nCells <= USHRT_MAX,
242 "SwXMLTableRow_Impl::SwXMLTableRow_Impl: too many cells" );
243 if( nCells > USHRT_MAX )
244 nCells = USHRT_MAX;
246 for( sal_uInt32 i=0U; i<nCells; ++i )
248 m_Cells.push_back(std::make_unique<SwXMLTableCell_Impl>());
252 inline SwXMLTableCell_Impl *SwXMLTableRow_Impl::GetCell( sal_uInt32 nCol )
254 OSL_ENSURE( nCol < USHRT_MAX,
255 "SwXMLTableRow_Impl::GetCell: column number is too big" );
256 // #i95726# - some fault tolerance
257 OSL_ENSURE( nCol < m_Cells.size(),
258 "SwXMLTableRow_Impl::GetCell: column number is out of bound" );
259 return nCol < m_Cells.size() ? m_Cells[nCol].get() : nullptr;
262 void SwXMLTableRow_Impl::Expand( sal_uInt32 nCells, bool bOneCell )
264 OSL_ENSURE( nCells <= USHRT_MAX,
265 "SwXMLTableRow_Impl::Expand: too many cells" );
266 if( nCells > USHRT_MAX )
267 nCells = USHRT_MAX;
269 sal_uInt32 nColSpan = nCells - m_Cells.size();
270 for (size_t i = m_Cells.size(); i < nCells; ++i)
272 m_Cells.push_back(std::make_unique<SwXMLTableCell_Impl>(
273 1UL, bOneCell ? nColSpan : 1UL));
274 nColSpan--;
277 OSL_ENSURE( nCells <= m_Cells.size(),
278 "SwXMLTableRow_Impl::Expand: wrong number of cells" );
281 inline void SwXMLTableRow_Impl::Set( const OUString& rStyleName,
282 const OUString& rDfltCellStyleName )
284 m_aStyleName = rStyleName;
285 m_aDefaultCellStyleName = rDfltCellStyleName;
288 void SwXMLTableRow_Impl::Dispose()
290 for (auto & pCell : m_Cells)
292 pCell->Dispose();
296 namespace {
298 class SwXMLTableCellContext_Impl : public SvXMLImportContext
300 OUString m_aStyleName;
301 OUString m_sFormula;
302 OUString m_sSaveParaDefault;
303 OUString m_StringValue;
305 SvXMLImportContextRef m_xMyTable;
307 double m_fValue;
308 bool m_bHasValue;
309 bool m_bHasStringValue;
310 bool m_bValueTypeIsString;
311 bool m_bProtect;
313 sal_uInt32 m_nRowSpan;
314 sal_uInt32 m_nColSpan;
315 sal_uInt32 m_nColRepeat;
317 bool m_bHasTextContent : 1;
318 bool m_bHasTableContent : 1;
320 SwXMLTableContext *GetTable() { return static_cast<SwXMLTableContext *>(m_xMyTable.get()); }
322 bool HasContent() const { return m_bHasTextContent || m_bHasTableContent; }
323 inline void InsertContent_();
324 inline void InsertContent();
325 inline void InsertContent( SwXMLTableContext *pTable );
327 public:
329 SwXMLTableCellContext_Impl(
330 SwXMLImport& rImport, sal_Int32 nElement,
331 const Reference< xml::sax::XFastAttributeList > & xAttrList,
332 SwXMLTableContext *pTable );
334 virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(
335 sal_Int32 nElement,
336 const Reference< xml::sax::XFastAttributeList > & xAttrList ) override;
337 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
339 SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
342 /// Handles <table:covered-table-cell>.
343 class SwXMLCoveredTableCellContext : public SvXMLImportContext
345 public:
346 SwXMLCoveredTableCellContext(SwXMLImport& rImport,
347 const Reference<xml::sax::XFastAttributeList>& xAttrList,
348 SwXMLTableContext& rTable);
351 SwXMLCoveredTableCellContext::SwXMLCoveredTableCellContext(
352 SwXMLImport& rImport, const Reference<xml::sax::XFastAttributeList>& xAttrList,
353 SwXMLTableContext& rTable)
354 : SvXMLImportContext(rImport)
356 OUString aStyleName;
357 for (auto& rIter : sax_fastparser::castToFastAttributeList(xAttrList))
359 switch (rIter.getToken())
361 case XML_ELEMENT(TABLE, XML_STYLE_NAME):
362 aStyleName = rIter.toString();
363 break;
367 if (!aStyleName.isEmpty())
369 rTable.InsertCoveredCell(aStyleName);
374 SwXMLTableCellContext_Impl::SwXMLTableCellContext_Impl(
375 SwXMLImport& rImport, sal_Int32 /*nElement*/,
376 const Reference< xml::sax::XFastAttributeList > & xAttrList,
377 SwXMLTableContext *pTable ) :
378 SvXMLImportContext( rImport ),
379 m_xMyTable( pTable ),
380 m_fValue( 0.0 ),
381 m_bHasValue( false ),
382 m_bHasStringValue(false),
383 m_bValueTypeIsString(false),
384 m_bProtect( false ),
385 m_nRowSpan( 1 ),
386 m_nColSpan( 1 ),
387 m_nColRepeat( 1 ),
388 m_bHasTextContent( false ),
389 m_bHasTableContent( false )
391 m_sSaveParaDefault = GetImport().GetTextImport()->GetCellParaStyleDefault();
392 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
394 switch( aIter.getToken() )
396 case XML_ELEMENT(TABLE, XML_STYLE_NAME):
397 m_aStyleName = aIter.toString();
398 GetImport().GetTextImport()->SetCellParaStyleDefault(m_aStyleName);
399 break;
400 case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_SPANNED):
401 m_nColSpan = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
402 if (m_nColSpan > 256)
404 SAL_INFO("sw.xml", "ignoring huge table:number-columns-spanned " << m_nColSpan);
405 m_nColSpan = 1;
407 break;
408 case XML_ELEMENT(TABLE, XML_NUMBER_ROWS_SPANNED):
409 m_nRowSpan = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
410 if (m_nRowSpan > 8192 || (m_nRowSpan > 256 && utl::ConfigManager::IsFuzzing()))
412 SAL_INFO("sw.xml", "ignoring huge table:number-rows-spanned " << m_nRowSpan);
413 m_nRowSpan = 1;
415 break;
416 case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED):
417 m_nColRepeat = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
418 if (m_nColRepeat > 256)
420 SAL_INFO("sw.xml", "ignoring huge table:number-columns-repeated " << m_nColRepeat);
421 m_nColRepeat = 1;
423 break;
424 case XML_ELEMENT(TABLE, XML_FORMULA):
426 OUString sTmp;
427 const sal_uInt16 nPrefix2 = GetImport().GetNamespaceMap().
428 GetKeyByAttrValueQName(aIter.toString(), &sTmp);
429 m_sFormula = XML_NAMESPACE_OOOW == nPrefix2 ? sTmp : aIter.toString();
431 break;
432 case XML_ELEMENT(OFFICE, XML_VALUE):
434 // Writer wrongly uses DBL_MAX to flag error but fails to
435 // check for it after import, so check that here, tdf#139126.
436 double fTmp;
437 if (::sax::Converter::convertDouble(fTmp, aIter.toView()) && fTmp < DBL_MAX)
439 m_fValue = fTmp;
440 m_bHasValue = true;
443 break;
444 case XML_ELEMENT(OFFICE, XML_TIME_VALUE):
446 double fTmp;
447 if (::sax::Converter::convertDuration(fTmp, aIter.toView()))
449 m_fValue = fTmp;
450 m_bHasValue = true;
453 break;
454 case XML_ELEMENT(OFFICE, XML_DATE_VALUE):
456 double fTmp;
457 if (GetImport().GetMM100UnitConverter().convertDateTime(fTmp,
458 aIter.toView()))
460 m_fValue = fTmp;
461 m_bHasValue = true;
464 break;
465 case XML_ELEMENT(OFFICE, XML_BOOLEAN_VALUE):
467 bool bTmp(false);
468 if (::sax::Converter::convertBool(bTmp, aIter.toView()))
470 m_fValue = (bTmp ? 1.0 : 0.0);
471 m_bHasValue = true;
474 break;
475 case XML_ELEMENT(TABLE, XML_PROTECT): // for backwards compatibility with SRC629 (and before)
476 case XML_ELEMENT(TABLE, XML_PROTECTED):
478 bool bTmp(false);
479 if (::sax::Converter::convertBool(bTmp, aIter.toView()))
481 m_bProtect = bTmp;
484 break;
485 case XML_ELEMENT(OFFICE, XML_STRING_VALUE):
487 m_StringValue = aIter.toString();
488 m_bHasStringValue = true;
490 break;
491 case XML_ELEMENT(OFFICE, XML_VALUE_TYPE):
493 if ("string" == aIter.toView())
495 m_bValueTypeIsString = true;
497 // ignore other types - it would be correct to require
498 // matching value-type and $type-value attributes,
499 // but we've been reading those without checking forever.
501 break;
502 default:
503 SAL_WARN("sw", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString());
508 inline void SwXMLTableCellContext_Impl::InsertContent_()
510 SwStartNode const*const pStartNode( GetTable()->InsertTableSection(nullptr,
511 (m_bHasStringValue && m_bValueTypeIsString &&
512 !m_aStyleName.isEmpty()) ? & m_aStyleName : nullptr) );
513 GetTable()->InsertCell( m_aStyleName, m_nRowSpan, m_nColSpan,
514 pStartNode,
515 nullptr, m_bProtect, &m_sFormula, m_bHasValue, m_fValue,
516 (m_bHasStringValue && m_bValueTypeIsString) ? &m_StringValue : nullptr);
519 inline void SwXMLTableCellContext_Impl::InsertContent()
521 OSL_ENSURE( !HasContent(), "content already there" );
522 m_bHasTextContent = true;
523 InsertContent_();
526 inline void SwXMLTableCellContext_Impl::InsertContent(
527 SwXMLTableContext *pTable )
529 GetTable()->InsertCell( m_aStyleName, m_nRowSpan, m_nColSpan, nullptr, pTable, m_bProtect );
530 m_bHasTableContent = true;
533 css::uno::Reference<css::xml::sax::XFastContextHandler> SwXMLTableCellContext_Impl::createFastChildContext(
534 sal_Int32 nElement,
535 const Reference< xml::sax::XFastAttributeList > & xAttrList )
537 SvXMLImportContext *pContext = nullptr;
539 bool bSubTable = false;
540 if( nElement == XML_ELEMENT(TABLE, XML_TABLE) )
542 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
544 if( aIter.getToken() == XML_ELEMENT(TABLE, XML_IS_SUB_TABLE) )
546 if ( IsXMLToken( aIter, XML_TRUE ) )
547 bSubTable = true;
549 else
550 XMLOFF_WARN_UNKNOWN("sw", aIter);
551 //FIXME: RDFa
555 if( bSubTable )
557 if( !HasContent() )
559 SwXMLTableContext *pTableContext =
560 new SwXMLTableContext( GetSwImport(), GetTable() );
561 pContext = pTableContext;
562 if( GetTable()->IsValid() )
563 InsertContent( pTableContext );
565 GetTable()->SetHasSubTables( true );
568 else
570 if( GetTable()->IsValid() && !HasContent() )
571 InsertContent();
572 // fdo#60842: "office:string-value" overrides text content -> no import
573 if (!(m_bValueTypeIsString && m_bHasStringValue))
575 pContext = GetImport().GetTextImport()->CreateTextChildContext(
576 GetImport(), nElement, xAttrList,
577 XMLTextType::Cell );
581 return pContext;
584 void SwXMLTableCellContext_Impl::endFastElement(sal_Int32 )
586 if( GetTable()->IsValid() )
588 if( m_bHasTextContent )
590 GetImport().GetTextImport()->DeleteParagraph();
591 if( m_nColRepeat > 1 && m_nColSpan == 1 )
593 // The original text is invalid after deleting the last
594 // paragraph
595 Reference < XTextCursor > xSrcTextCursor =
596 GetImport().GetTextImport()->GetText()->createTextCursor();
597 xSrcTextCursor->gotoEnd( true );
599 // Until we have an API for copying we have to use the core.
600 OTextCursorHelper *pSrcTextCursor = dynamic_cast<OTextCursorHelper*>(xSrcTextCursor.get());
601 assert(pSrcTextCursor && "SwXTextCursor missing");
602 SwDoc *pDoc = pSrcTextCursor->GetDoc();
603 const SwPaM *pSrcPaM = pSrcTextCursor->GetPaM();
605 while( m_nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
607 InsertContent_();
609 OTextCursorHelper *pDstTextCursor = dynamic_cast<OTextCursorHelper*>(GetImport().GetTextImport()->GetCursor().get());
610 assert(pDstTextCursor && "SwXTextCursor missing");
611 SwPaM aSrcPaM(*pSrcPaM->GetMark(), *pSrcPaM->GetPoint());
612 SwPosition aDstPos( *pDstTextCursor->GetPaM()->GetPoint() );
613 pDoc->getIDocumentContentOperations().CopyRange(aSrcPaM, aDstPos, SwCopyFlags::CheckPosInFly);
615 m_nColRepeat--;
619 else if( !m_bHasTableContent )
621 InsertContent();
622 if( m_nColRepeat > 1 && m_nColSpan == 1 )
624 while( m_nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
626 InsertContent_();
627 m_nColRepeat--;
632 GetImport().GetTextImport()->SetCellParaStyleDefault(m_sSaveParaDefault);
635 namespace {
637 class SwXMLTableColContext_Impl : public SvXMLImportContext
639 SvXMLImportContextRef m_xMyTable;
641 SwXMLTableContext *GetTable() { return static_cast<SwXMLTableContext *>(m_xMyTable.get()); }
643 public:
645 SwXMLTableColContext_Impl(
646 SwXMLImport& rImport,
647 const Reference< xml::sax::XFastAttributeList > & xAttrList,
648 SwXMLTableContext *pTable );
650 SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
655 SwXMLTableColContext_Impl::SwXMLTableColContext_Impl(
656 SwXMLImport& rImport,
657 const Reference< xml::sax::XFastAttributeList > & xAttrList,
658 SwXMLTableContext *pTable ) :
659 SvXMLImportContext( rImport ),
660 m_xMyTable( pTable )
662 sal_uInt32 nColRep = 1;
663 OUString aStyleName, aDfltCellStyleName;
665 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
667 switch (aIter.getToken())
669 case XML_ELEMENT(TABLE, XML_STYLE_NAME):
670 aStyleName = aIter.toString();
671 break;
672 case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED):
674 nColRep = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
675 if (nColRep > 256)
677 SAL_INFO("sw.xml", "ignoring huge table:number-columns-repeated " << nColRep);
678 nColRep = 1;
680 break;
682 case XML_ELEMENT(TABLE, XML_DEFAULT_CELL_STYLE_NAME):
683 aDfltCellStyleName = aIter.toString();
684 break;
685 case XML_ELEMENT(XML, XML_ID):
687 //FIXME where to put this??? columns do not actually exist in writer...
688 break;
690 default:
691 XMLOFF_WARN_UNKNOWN("sw", aIter);
695 sal_Int32 nWidth = MINLAY;
696 bool bRelWidth = true;
697 if( !aStyleName.isEmpty() )
699 const SwFormatFrameSize *pSize;
700 const SfxItemSet *pAutoItemSet = nullptr;
701 if( GetSwImport().FindAutomaticStyle(
702 XmlStyleFamily::TABLE_COLUMN,
703 aStyleName, &pAutoItemSet ) &&
704 pAutoItemSet &&
705 (pSize = pAutoItemSet->GetItemIfSet( RES_FRM_SIZE, false )) )
707 nWidth = pSize->GetWidth();
708 bRelWidth = SwFrameSize::Variable == pSize->GetHeightSizeType();
712 if( nWidth )
714 while( nColRep-- && GetTable()->IsInsertColPossible() )
715 GetTable()->InsertColumn( nWidth, bRelWidth, &aDfltCellStyleName );
719 namespace {
721 class SwXMLTableColsContext_Impl : public SvXMLImportContext
723 SvXMLImportContextRef m_xMyTable;
725 SwXMLTableContext *GetTable() { return static_cast<SwXMLTableContext *>(m_xMyTable.get()); }
727 public:
729 SwXMLTableColsContext_Impl(
730 SwXMLImport& rImport,
731 SwXMLTableContext *pTable );
733 virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
734 sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList ) override;
736 SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
741 SwXMLTableColsContext_Impl::SwXMLTableColsContext_Impl(
742 SwXMLImport& rImport,
743 SwXMLTableContext *pTable ) :
744 SvXMLImportContext( rImport ),
745 m_xMyTable( pTable )
749 css::uno::Reference< css::xml::sax::XFastContextHandler > SwXMLTableColsContext_Impl::createFastChildContext(
750 sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > & xAttrList )
752 SvXMLImportContext *pContext = nullptr;
754 if( nElement == XML_ELEMENT(TABLE, XML_TABLE_COLUMN) &&
755 GetTable()->IsInsertColPossible() )
756 pContext = new SwXMLTableColContext_Impl( GetSwImport(), xAttrList, GetTable() );
757 else
758 XMLOFF_WARN_UNKNOWN_ELEMENT("sw", nElement);
760 return pContext;
763 namespace {
765 class SwXMLTableRowContext_Impl : public SvXMLImportContext
767 SvXMLImportContextRef m_xMyTable;
769 sal_uInt32 m_nRowRepeat;
771 SwXMLTableContext *GetTable() { return static_cast<SwXMLTableContext *>(m_xMyTable.get()); }
773 public:
775 SwXMLTableRowContext_Impl(
776 SwXMLImport& rImport, sal_Int32 nElement,
777 const Reference< xml::sax::XFastAttributeList > & xAttrList,
778 SwXMLTableContext *pTable, bool bInHead=false );
780 virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext( sal_Int32 nElement,
781 const Reference< xml::sax::XFastAttributeList > & xAttrList ) override;
783 virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
785 SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
790 SwXMLTableRowContext_Impl::SwXMLTableRowContext_Impl( SwXMLImport& rImport,
791 sal_Int32 /*nElement*/,
792 const Reference< xml::sax::XFastAttributeList > & xAttrList,
793 SwXMLTableContext *pTable,
794 bool bInHead ) :
795 SvXMLImportContext( rImport ),
796 m_xMyTable( pTable ),
797 m_nRowRepeat( 1 )
799 OUString aStyleName, aDfltCellStyleName;
801 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
803 switch(aIter.getToken())
805 case XML_ELEMENT(TABLE, XML_STYLE_NAME):
806 aStyleName = aIter.toString();
807 break;
808 case XML_ELEMENT(STYLE, XML_NUMBER_ROWS_REPEATED):
810 m_nRowRepeat = static_cast<sal_uInt32>(std::max<sal_Int32>(1, aIter.toInt32()));
811 if (m_nRowRepeat > 8192 || (m_nRowRepeat > 256 && utl::ConfigManager::IsFuzzing()))
813 SAL_INFO("sw.xml", "ignoring huge table:number-rows-repeated " << m_nRowRepeat);
814 m_nRowRepeat = 1;
816 break;
818 case XML_ELEMENT(STYLE, XML_DEFAULT_CELL_STYLE_NAME):
819 aDfltCellStyleName = aIter.toString();
820 break;
821 case XML_ELEMENT(XML, XML_ID):
822 break;
823 default:
824 XMLOFF_WARN_UNKNOWN("sw", aIter);
827 if( GetTable()->IsValid() )
828 GetTable()->InsertRow( aStyleName, aDfltCellStyleName, bInHead );
831 void SwXMLTableRowContext_Impl::endFastElement(sal_Int32 )
833 if( GetTable()->IsValid() )
835 GetTable()->FinishRow();
837 if( m_nRowRepeat > 1 )
838 GetTable()->InsertRepRows( m_nRowRepeat );
842 css::uno::Reference<css::xml::sax::XFastContextHandler> SwXMLTableRowContext_Impl::createFastChildContext(
843 sal_Int32 nElement,
844 const Reference< xml::sax::XFastAttributeList > & xAttrList )
846 SvXMLImportContext *pContext = nullptr;
848 if( nElement == XML_ELEMENT(TABLE, XML_TABLE_CELL) ||
849 nElement == XML_ELEMENT(LO_EXT, XML_TABLE_CELL) )
851 if( !GetTable()->IsValid() || GetTable()->IsInsertCellPossible() )
852 pContext = new SwXMLTableCellContext_Impl( GetSwImport(), nElement,
853 xAttrList,
854 GetTable() );
856 else if( nElement == XML_ELEMENT(TABLE, XML_COVERED_TABLE_CELL) ||
857 nElement == XML_ELEMENT(LO_EXT, XML_COVERED_TABLE_CELL) )
859 if (GetTable()->IsValid() && GetTable()->IsInsertCoveredCellPossible())
861 pContext = new SwXMLCoveredTableCellContext(GetSwImport(), xAttrList, *GetTable());
863 else
865 pContext = new SvXMLImportContext(GetImport());
868 else
869 SAL_WARN("sw", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
871 return pContext;
874 namespace {
876 class SwXMLTableRowsContext_Impl : public SvXMLImportContext
878 SvXMLImportContextRef m_xMyTable;
880 bool m_bHeader;
882 SwXMLTableContext *GetTable() { return static_cast<SwXMLTableContext *>(m_xMyTable.get()); }
884 public:
886 SwXMLTableRowsContext_Impl( SwXMLImport& rImport,
887 SwXMLTableContext *pTable,
888 bool bHead );
890 virtual css::uno::Reference<css::xml::sax::XFastContextHandler> SAL_CALL createFastChildContext(
891 sal_Int32 nElement,
892 const Reference< xml::sax::XFastAttributeList > & xAttrList ) override;
894 SwXMLImport& GetSwImport() { return static_cast<SwXMLImport&>(GetImport()); }
899 SwXMLTableRowsContext_Impl::SwXMLTableRowsContext_Impl( SwXMLImport& rImport,
900 SwXMLTableContext *pTable,
901 bool bHead ) :
902 SvXMLImportContext( rImport ),
903 m_xMyTable( pTable ),
904 m_bHeader( bHead )
908 css::uno::Reference<css::xml::sax::XFastContextHandler> SwXMLTableRowsContext_Impl::createFastChildContext(
909 sal_Int32 nElement,
910 const Reference< xml::sax::XFastAttributeList > & xAttrList )
912 if( nElement== XML_ELEMENT(TABLE, XML_TABLE_ROW ) &&
913 GetTable()->IsInsertRowPossible() )
914 return new SwXMLTableRowContext_Impl( GetSwImport(), nElement,
915 xAttrList,
916 GetTable(),
917 m_bHeader );
918 SAL_WARN("sw", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
919 return nullptr;
922 class SwXMLDDETableContext_Impl : public SvXMLImportContext
924 OUString m_sConnectionName;
925 OUString m_sDDEApplication;
926 OUString m_sDDEItem;
927 OUString m_sDDETopic;
928 bool m_bIsAutomaticUpdate;
930 public:
933 SwXMLDDETableContext_Impl(SwXMLImport& rImport);
935 virtual void SAL_CALL startFastElement(
936 sal_Int32 nElement,
937 const Reference<xml::sax::XFastAttributeList> & xAttrList) override;
939 OUString& GetConnectionName() { return m_sConnectionName; }
940 OUString& GetDDEApplication() { return m_sDDEApplication; }
941 OUString& GetDDEItem() { return m_sDDEItem; }
942 OUString& GetDDETopic() { return m_sDDETopic; }
943 bool GetIsAutomaticUpdate() const { return m_bIsAutomaticUpdate; }
947 SwXMLDDETableContext_Impl::SwXMLDDETableContext_Impl(SwXMLImport& rImport) :
948 SvXMLImportContext(rImport),
949 m_bIsAutomaticUpdate(false)
953 void SwXMLDDETableContext_Impl::startFastElement(
954 sal_Int32 /*nElement*/,
955 const Reference<xml::sax::XFastAttributeList> & xAttrList)
957 for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
959 switch (aIter.getToken())
961 case XML_ELEMENT(OFFICE, XML_DDE_APPLICATION):
962 m_sDDEApplication = aIter.toString();
963 break;
964 case XML_ELEMENT(OFFICE, XML_DDE_TOPIC):
965 m_sDDETopic = aIter.toString();
966 break;
967 case XML_ELEMENT(OFFICE, XML_DDE_ITEM):
968 m_sDDEItem = aIter.toString();
969 break;
970 case XML_ELEMENT(OFFICE, XML_NAME):
971 m_sConnectionName = aIter.toString();
972 break;
973 case XML_ELEMENT(OFFICE, XML_AUTOMATIC_UPDATE):
975 bool bTmp(false);
976 if (::sax::Converter::convertBool(bTmp, aIter.toView()))
978 m_bIsAutomaticUpdate = bTmp;
980 break;
982 default:
983 XMLOFF_WARN_UNKNOWN("sw", aIter);
985 // else: unknown attribute namespace
989 // generate a new name for DDE field type (called by lcl_GetDDEFieldType below)
990 static OUString lcl_GenerateFieldTypeName(const OUString& sPrefix, SwTableNode* pTableNode)
992 const OUString sPrefixStr(sPrefix.isEmpty() ? OUString("_") : sPrefix);
994 // increase count until we find a name that is not yet taken
995 OUString sName;
996 sal_Int32 nCount = 0;
999 // this is crazy, but just in case all names are taken: exit gracefully
1000 if (nCount == SAL_MAX_INT32)
1001 return sName;
1003 ++nCount;
1004 sName = sPrefixStr + OUString::number(nCount);
1006 while (nullptr != pTableNode->GetDoc().getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Dde, sName, false));
1008 return sName;
1011 // set table properties
1012 static SwDDEFieldType* lcl_GetDDEFieldType(SwXMLDDETableContext_Impl* pContext,
1013 SwTableNode* pTableNode)
1015 // make command string
1016 const OUString sCommand(pContext->GetDDEApplication()
1017 + OUStringChar(sfx2::cTokenSeparator)
1018 + pContext->GetDDEItem()
1019 + OUStringChar(sfx2::cTokenSeparator)
1020 + pContext->GetDDETopic());
1022 const SfxLinkUpdateMode nType = pContext->GetIsAutomaticUpdate()
1023 ? SfxLinkUpdateMode::ALWAYS
1024 : SfxLinkUpdateMode::ONCALL;
1026 OUString sName(pContext->GetConnectionName());
1028 // field type to be returned
1029 SwDDEFieldType* pType = nullptr;
1031 // valid name?
1032 if (sName.isEmpty())
1034 sName = lcl_GenerateFieldTypeName(pContext->GetDDEApplication(),
1035 pTableNode);
1037 else
1039 // check for existing DDE field type with the same name
1040 SwDDEFieldType* pOldType = static_cast<SwDDEFieldType*>(pTableNode->GetDoc().getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Dde, sName, false));
1041 if (nullptr != pOldType)
1043 // same values -> return old type
1044 if ( (pOldType->GetCmd() == sCommand) &&
1045 (pOldType->GetType() == nType) )
1047 // same name, same values -> return old type!
1048 pType = pOldType;
1050 else
1052 // same name, different values -> think of new name
1053 sName = lcl_GenerateFieldTypeName(pContext->GetDDEApplication(),
1054 pTableNode);
1057 // no old type -> create new one
1060 // create new field type (unless we already have one)
1061 if (nullptr == pType)
1063 // create new field type and return
1064 SwDDEFieldType aDDEFieldType(sName, sCommand, nType);
1065 pType = static_cast<SwDDEFieldType*>(pTableNode->
1066 GetDoc().getIDocumentFieldsAccess().InsertFieldType(aDDEFieldType));
1069 OSL_ENSURE(nullptr != pType, "We really want a SwDDEFieldType here!");
1070 return pType;
1073 class TableBoxIndex
1075 public:
1076 OUString msName;
1077 sal_Int32 mnWidth;
1078 bool mbProtected;
1080 TableBoxIndex( OUString aName, sal_Int32 nWidth,
1081 bool bProtected ) :
1082 msName(std::move( aName )),
1083 mnWidth( nWidth ),
1084 mbProtected( bProtected )
1087 bool operator== ( const TableBoxIndex& rArg ) const
1089 return (rArg.mnWidth == mnWidth) &&
1090 (rArg.mbProtected == mbProtected) &&
1091 (rArg.msName == msName);
1095 class TableBoxIndexHasher
1097 public:
1098 size_t operator() (const TableBoxIndex& rArg) const
1100 return rArg.msName.hashCode() + rArg.mnWidth + (rArg.mbProtected ? 1 : 0);
1104 const SwXMLTableCell_Impl *SwXMLTableContext::GetCell( sal_uInt32 nRow,
1105 sal_uInt32 nCol ) const
1107 return (*m_pRows)[nRow]->GetCell( nCol );
1110 SwXMLTableCell_Impl *SwXMLTableContext::GetCell( sal_uInt32 nRow,
1111 sal_uInt32 nCol )
1113 return (*m_pRows)[nRow]->GetCell( nCol );
1117 SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
1118 const Reference< xml::sax::XFastAttributeList > & xAttrList ) :
1119 XMLTextTableContext( rImport ),
1120 m_pRows( new SwXMLTableRows_Impl ),
1121 m_pTableNode( nullptr ),
1122 m_pBox1( nullptr ),
1123 m_bOwnsBox1( false ),
1124 m_pSttNd1( nullptr ),
1125 m_pBoxFormat( nullptr ),
1126 m_pLineFormat( nullptr ),
1127 m_bFirstSection( true ),
1128 m_bRelWidth( true ),
1129 m_bHasSubTables( false ),
1130 m_nHeaderRows( 0 ),
1131 m_nCurRow( 0 ),
1132 m_nCurCol( 0 ),
1133 m_nNonMergedCurCol( 0 ),
1134 m_nWidth( 0 )
1136 OUString aName;
1137 OUString sXmlId;
1139 // this method will modify the document directly -> lock SolarMutex
1140 SolarMutexGuard aGuard;
1142 for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
1144 const OUString sValue = aIter.toString();
1145 switch(aIter.getToken())
1147 case XML_ELEMENT(TABLE, XML_STYLE_NAME):
1148 m_aStyleName = sValue;
1149 break;
1150 case XML_ELEMENT(TABLE, XML_NAME):
1151 aName = sValue;
1152 break;
1153 case XML_ELEMENT(TABLE, XML_DEFAULT_CELL_STYLE_NAME):
1154 m_aDfltCellStyleName = sValue;
1155 break;
1156 case XML_ELEMENT(TABLE, XML_TEMPLATE_NAME):
1157 m_aTemplateName = sValue;
1158 break;
1159 case XML_ELEMENT(XML, XML_ID):
1160 sXmlId = sValue;
1161 break;
1162 default:
1163 XMLOFF_WARN_UNKNOWN("sw", aIter);
1167 SwDoc *pDoc = GetSwImport().getDoc();
1169 OUString sTableName;
1170 if( !aName.isEmpty() )
1172 const SwTableFormat *pTableFormat = pDoc->FindTableFormatByName( aName );
1173 if( !pTableFormat )
1174 sTableName = aName;
1176 if( sTableName.isEmpty() )
1178 // Optimization: use import's own map to create unique names, because
1179 // SwDoc::GetUniqueTableName scans all the already present tables,
1180 // builds a bitset using rather complex rules, and that has quadratic
1181 // complexity. Try once, then fallback to SwDoc::GetUniqueTableName
1182 auto& tableNameMap = rImport.GetTableNameMap();
1183 sal_Int32 nextIx = ++tableNameMap[aName];
1184 OUString test = aName.isEmpty()
1185 ? OUString(rImport.GetDefTableName() + OUString::number(nextIx))
1186 : OUString(aName + "_" + OUString::number(nextIx));
1187 if (const SwTableFormat* pExisting = pDoc->FindTableFormatByName(test); !pExisting)
1188 sTableName = test;
1189 else
1190 sTableName = pDoc->GetUniqueTableName();
1191 GetImport().GetTextImport()
1192 ->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_TABLE, aName, sTableName );
1195 Reference< XTextTable > xTable;
1196 SwXTextTable *pXTable = nullptr;
1197 Reference<XMultiServiceFactory> xFactory( GetImport().GetModel(),
1198 UNO_QUERY );
1199 OSL_ENSURE( xFactory.is(), "factory missing" );
1200 if( xFactory.is() )
1202 Reference<XInterface> xIfc = xFactory->createInstance( "com.sun.star.text.TextTable" );
1203 OSL_ENSURE( xIfc.is(), "Couldn't create a table" );
1205 if( xIfc.is() )
1206 xTable.set( xIfc, UNO_QUERY );
1209 if( xTable.is() )
1211 xTable->initialize( 1, 1 );
1212 if (auto xPropSet = xTable.query<css::beans::XPropertySet>())
1213 xPropSet->setPropertyValue(UNO_NAME_TABLE_NAME, css::uno::Any(sTableName));
1217 m_xTextContent = xTable;
1218 GetImport().GetTextImport()->InsertTextContent( m_xTextContent );
1220 catch( IllegalArgumentException& )
1222 xTable = nullptr;
1226 if( xTable.is() )
1228 //FIXME
1229 // xml:id for RDF metadata
1230 GetImport().SetXmlId(xTable, sXmlId);
1232 pXTable = dynamic_cast<SwXTextTable*>(xTable.get());
1234 Reference < XCellRange > xCellRange( xTable, UNO_QUERY );
1235 Reference < XCell > xCell = xCellRange->getCellByPosition( 0, 0 );
1236 Reference < XText> xText( xCell, UNO_QUERY );
1237 m_xOldCursor = GetImport().GetTextImport()->GetCursor();
1238 GetImport().GetTextImport()->SetCursor( xText->createTextCursor() );
1240 // take care of open redlines for tables
1241 GetImport().GetTextImport()->RedlineAdjustStartNodeCursor();
1243 if( !pXTable )
1244 return;
1246 SwFrameFormat *const pTableFrameFormat = pXTable->GetFrameFormat();
1247 OSL_ENSURE( pTableFrameFormat, "table format missing" );
1248 SwTable *pTable = SwTable::FindTable( pTableFrameFormat );
1249 OSL_ENSURE( pTable, "table missing" );
1250 m_pTableNode = pTable->GetTableNode();
1251 OSL_ENSURE( m_pTableNode, "table node missing" );
1253 SwTableLine *pLine1 = m_pTableNode->GetTable().GetTabLines()[0U];
1254 m_pBox1 = pLine1->GetTabBoxes()[0U];
1255 m_pSttNd1 = m_pBox1->GetSttNd();
1258 SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
1259 SwXMLTableContext *pTable ) :
1260 XMLTextTableContext( rImport ),
1261 m_pRows( new SwXMLTableRows_Impl ),
1262 m_pTableNode( pTable->m_pTableNode ),
1263 m_pBox1( nullptr ),
1264 m_bOwnsBox1( false ),
1265 m_pSttNd1( nullptr ),
1266 m_pBoxFormat( nullptr ),
1267 m_pLineFormat( nullptr ),
1268 m_xParentTable( pTable ),
1269 m_bFirstSection( false ),
1270 m_bRelWidth( true ),
1271 m_bHasSubTables( false ),
1272 m_nHeaderRows( 0 ),
1273 m_nCurRow( 0 ),
1274 m_nCurCol( 0 ),
1275 m_nNonMergedCurCol( 0 ),
1276 m_nWidth( 0 )
1280 SwXMLTableContext::~SwXMLTableContext()
1282 if (m_bOwnsBox1)
1283 delete m_pBox1;
1284 m_xColumnDefaultCellStyleNames.reset();
1285 m_pSharedBoxFormats.reset();
1286 m_pRows.reset();
1288 // close redlines on table end nodes
1289 GetImport().GetTextImport()->RedlineAdjustStartNodeCursor();
1292 css::uno::Reference<css::xml::sax::XFastContextHandler> SwXMLTableContext::createFastChildContext(
1293 sal_Int32 nElement,
1294 const Reference< xml::sax::XFastAttributeList > & xAttrList )
1296 bool bHeader = false;
1297 switch (nElement)
1299 case XML_ELEMENT(TABLE, XML_TABLE_ROW):
1300 case XML_ELEMENT(LO_EXT, XML_TABLE_ROW):
1301 if( IsInsertRowPossible() )
1302 return new SwXMLTableRowContext_Impl( GetSwImport(), nElement, xAttrList, this );
1303 break;
1304 case XML_ELEMENT(TABLE, XML_TABLE_HEADER_ROWS):
1305 bHeader = true;
1306 [[fallthrough]];
1307 case XML_ELEMENT(TABLE, XML_TABLE_ROWS):
1308 return new SwXMLTableRowsContext_Impl( GetSwImport(), this, bHeader );
1309 case XML_ELEMENT(TABLE, XML_TABLE_HEADER_COLUMNS):
1310 case XML_ELEMENT(TABLE, XML_TABLE_COLUMNS):
1311 // There are slight differences between <table:table-columns> and
1312 // <table:table-columns-groups>. However, none of these are
1313 // supported in Writer (they are Calc-only features), so we
1314 // support column groups by simply using the <table:table-columns>
1315 // token for column groups, too.
1316 case XML_ELEMENT(TABLE, XML_TABLE_COLUMN_GROUP):
1317 if( IsValid() )
1318 return new SwXMLTableColsContext_Impl( GetSwImport(), this );
1319 break;
1320 case XML_ELEMENT(TABLE, XML_TABLE_COLUMN):
1321 case XML_ELEMENT(LO_EXT, XML_TABLE_COLUMN):
1322 if( IsValid() && IsInsertColPossible() )
1323 return new SwXMLTableColContext_Impl( GetSwImport(), xAttrList,
1324 this );
1325 break;
1326 case XML_ELEMENT(OFFICE, XML_DDE_SOURCE):
1327 // save context for later processing (discard old context, if approp.)
1328 if( IsValid() )
1330 m_xDDESource.set(new SwXMLDDETableContext_Impl( GetSwImport() ));
1331 return m_xDDESource;
1333 break;
1335 return nullptr;
1338 void SwXMLTableContext::InsertColumn( sal_Int32 nWidth2, bool bRelWidth2,
1339 const OUString *pDfltCellStyleName )
1341 OSL_ENSURE( m_nCurCol < USHRT_MAX,
1342 "SwXMLTableContext::InsertColumn: no space left" );
1343 if( m_nCurCol >= USHRT_MAX )
1344 return;
1346 if( nWidth2 < MINLAY )
1347 nWidth2 = MINLAY;
1348 else if( nWidth2 > MAX_WIDTH )
1349 nWidth2 = MAX_WIDTH;
1350 m_aColumnWidths.emplace_back(nWidth2, bRelWidth2 );
1351 if( !((pDfltCellStyleName && !pDfltCellStyleName->isEmpty()) ||
1352 m_xColumnDefaultCellStyleNames) )
1353 return;
1355 if( !m_xColumnDefaultCellStyleNames )
1357 m_xColumnDefaultCellStyleNames.emplace();
1358 sal_uLong nCount = m_aColumnWidths.size() - 1;
1359 while( nCount-- )
1360 m_xColumnDefaultCellStyleNames->push_back(OUString());
1363 if(pDfltCellStyleName)
1364 m_xColumnDefaultCellStyleNames->push_back(*pDfltCellStyleName);
1365 else
1366 m_xColumnDefaultCellStyleNames->push_back(OUString());
1369 sal_Int32 SwXMLTableContext::GetColumnWidth( sal_uInt32 nCol,
1370 sal_uInt32 nColSpan ) const
1372 sal_uInt32 nLast = nCol+nColSpan;
1373 if( nLast > m_aColumnWidths.size() )
1374 nLast = m_aColumnWidths.size();
1376 sal_Int32 nWidth2 = 0;
1377 for( sal_uInt32 i=nCol; i < nLast; ++i )
1378 nWidth2 += m_aColumnWidths[i].width;
1380 return nWidth2;
1383 OUString SwXMLTableContext::GetColumnDefaultCellStyleName( sal_uInt32 nCol ) const
1385 if( m_xColumnDefaultCellStyleNames && nCol < m_xColumnDefaultCellStyleNames->size())
1386 return (*m_xColumnDefaultCellStyleNames)[static_cast<size_t>(nCol)];
1388 return OUString();
1391 void SwXMLTableContext::InsertCell( const OUString& rStyleName,
1392 sal_uInt32 nRowSpan, sal_uInt32 nColSpan,
1393 const SwStartNode *pStartNode,
1394 SwXMLTableContext *pTable,
1395 bool bProtect,
1396 const OUString* pFormula,
1397 bool bHasValue,
1398 double fValue,
1399 OUString const*const pStringValue )
1401 OSL_ENSURE( m_nCurCol < GetColumnCount(),
1402 "SwXMLTableContext::InsertCell: row is full" );
1403 OSL_ENSURE( m_nCurRow < USHRT_MAX,
1404 "SwXMLTableContext::InsertCell: table is full" );
1405 if( m_nCurCol >= USHRT_MAX || m_nCurRow > USHRT_MAX )
1406 return;
1408 OSL_ENSURE( nRowSpan >=1, "SwXMLTableContext::InsertCell: row span is 0" );
1409 if( 0 == nRowSpan )
1410 nRowSpan = 1;
1411 OSL_ENSURE( nColSpan >=1, "SwXMLTableContext::InsertCell: col span is 0" );
1412 if( 0 == nColSpan )
1413 nColSpan = 1;
1415 // Until it is possible to add columns here, fix the column span.
1416 sal_uInt32 nColsReq = m_nCurCol + nColSpan;
1417 if( nColsReq > GetColumnCount() )
1419 nColSpan = GetColumnCount() - m_nCurCol;
1420 nColsReq = GetColumnCount();
1423 // Check whether there are cells from a previous line already that reach
1424 // into the current row.
1425 if( m_nCurRow > 0 && nColSpan > 1 )
1427 SwXMLTableRow_Impl *pCurRow = (*m_pRows)[m_nCurRow].get();
1428 sal_uInt32 nLastCol = GetColumnCount() < nColsReq ? GetColumnCount()
1429 : nColsReq;
1430 for( sal_uInt32 i=m_nCurCol+1; i<nLastCol; ++i )
1432 if( pCurRow->GetCell(i)->IsUsed() )
1434 // If this cell is used, the column span is truncated
1435 nColSpan = i - m_nCurCol;
1436 nColsReq = i;
1437 break;
1442 sal_uInt32 nRowsReq = m_nCurRow + nRowSpan;
1443 if( nRowsReq > USHRT_MAX )
1445 nRowSpan = USHRT_MAX - m_nCurRow;
1446 nRowsReq = USHRT_MAX;
1449 // Add columns (if # required columns greater than # columns):
1450 // This should never happen, since we require column definitions!
1451 if ( nColsReq > GetColumnCount() )
1453 for( sal_uInt32 i=GetColumnCount(); i<nColsReq; ++i )
1455 m_aColumnWidths.emplace_back(MINLAY, true );
1457 // adjust columns in *all* rows, if columns must be inserted
1458 for (size_t i = 0; i < m_pRows->size(); ++i)
1459 (*m_pRows)[i]->Expand( nColsReq, i<m_nCurRow );
1462 // Add rows
1463 if (m_pRows->size() < nRowsReq)
1465 for (size_t i = m_pRows->size(); i < nRowsReq; ++i)
1466 m_pRows->push_back(std::make_unique<SwXMLTableRow_Impl>(
1467 "", GetColumnCount()));
1470 OUString sStyleName( rStyleName );
1471 if( sStyleName.isEmpty() )
1473 sStyleName = (*m_pRows)[m_nCurRow]->GetDefaultCellStyleName();
1474 if( sStyleName.isEmpty() && m_xColumnDefaultCellStyleNames )
1476 sStyleName = GetColumnDefaultCellStyleName( m_nCurCol );
1477 if( sStyleName.isEmpty() )
1478 sStyleName = m_aDfltCellStyleName;
1482 // Fill the cells
1483 for( sal_uInt32 i=nColSpan; i>0; --i )
1485 for( sal_uInt32 j=nRowSpan; j>0; --j )
1487 const bool bCovered = i != nColSpan || j != nRowSpan;
1488 SwXMLTableCell_Impl *pCell = GetCell( nRowsReq-j, nColsReq-i );
1489 if (!pCell)
1490 throw css::lang::IndexOutOfBoundsException();
1491 pCell->Set( sStyleName, j, i, pStartNode,
1492 pTable, bProtect, pFormula, bHasValue, bCovered, fValue,
1493 pStringValue );
1497 // Set current col to the next (free) column
1498 m_nCurCol = nColsReq;
1499 m_nNonMergedCurCol = nColsReq;
1500 while( m_nCurCol<GetColumnCount() && GetCell(m_nCurRow,m_nCurCol)->IsUsed() )
1501 m_nCurCol++;
1504 void SwXMLTableContext::InsertCoveredCell(const OUString& rStyleName)
1506 const IDocumentSettingAccess& rIDSA = GetSwImport().getDoc()->getIDocumentSettingAccess();
1507 bool bWordTableCell = rIDSA.get(DocumentSettingId::TABLE_ROW_KEEP);
1508 if (!bWordTableCell)
1510 // Compatibility flag not active, ignore formatting of covered cells.
1511 return;
1514 SwXMLTableCell_Impl* pCell = GetCell(m_nCurRow, m_nNonMergedCurCol);
1515 ++m_nNonMergedCurCol;
1516 if (!pCell)
1518 return;
1521 pCell->SetStyleName(rStyleName);
1524 void SwXMLTableContext::InsertRow( const OUString& rStyleName,
1525 const OUString& rDfltCellStyleName,
1526 bool bInHead )
1528 OSL_ENSURE( m_nCurRow < USHRT_MAX,
1529 "SwXMLTableContext::InsertRow: no space left" );
1530 if( m_nCurRow >= USHRT_MAX )
1531 return;
1533 // Make sure there is at least one column.
1534 if( 0==m_nCurRow && 0 == GetColumnCount() )
1535 InsertColumn( USHRT_MAX, true );
1537 if (m_nCurRow < m_pRows->size())
1539 // The current row has already been inserted because of a row span
1540 // of a previous row.
1541 (*m_pRows)[m_nCurRow]->Set(
1542 rStyleName, rDfltCellStyleName );
1544 else
1546 // add a new row
1547 m_pRows->push_back(std::make_unique<SwXMLTableRow_Impl>(
1548 rStyleName, GetColumnCount(),
1549 &rDfltCellStyleName));
1552 // We start at the first column ...
1553 m_nCurCol=0;
1554 m_nNonMergedCurCol = 0;
1556 // ... but this cell may be occupied already.
1557 while( m_nCurCol<GetColumnCount() && GetCell(m_nCurRow,m_nCurCol)->IsUsed() )
1558 m_nCurCol++;
1560 if( bInHead && m_nHeaderRows == m_nCurRow )
1561 m_nHeaderRows++;
1564 void SwXMLTableContext::InsertRepRows( sal_uInt32 nCount )
1566 const SwXMLTableRow_Impl *pSrcRow = (*m_pRows)[m_nCurRow-1].get();
1567 while( nCount > 1 && IsInsertRowPossible() )
1569 InsertRow( pSrcRow->GetStyleName(), pSrcRow->GetDefaultCellStyleName(),
1570 false );
1571 while( m_nCurCol < GetColumnCount() )
1573 if( !GetCell(m_nCurRow,m_nCurCol)->IsUsed() )
1575 const SwXMLTableCell_Impl *pSrcCell =
1576 GetCell( m_nCurRow-1, m_nCurCol );
1577 InsertCell( pSrcCell->GetStyleName(), 1U,
1578 pSrcCell->GetColSpan(),
1579 InsertTableSection(),
1580 nullptr, pSrcCell->IsProtected(),
1581 &pSrcCell->GetFormula(),
1582 pSrcCell->HasValue(), pSrcCell->GetValue(),
1583 pSrcCell->GetStringValue() );
1586 FinishRow();
1587 nCount--;
1591 void SwXMLTableContext::FinishRow()
1593 // Insert an empty cell at the end of the line if the row is not complete
1594 if( m_nCurCol < GetColumnCount() )
1596 InsertCell( "", 1U, GetColumnCount() - m_nCurCol,
1597 InsertTableSection() );
1600 // Move to the next row.
1601 m_nCurRow++;
1604 const SwStartNode *SwXMLTableContext::GetPrevStartNode( sal_uInt32 nRow,
1605 sal_uInt32 nCol ) const
1607 const SwXMLTableCell_Impl *pPrevCell = nullptr;
1608 if( GetColumnCount() == nCol )
1610 // The last cell is the right one here.
1611 pPrevCell = GetCell( m_pRows->size() - 1U, GetColumnCount() - 1 );
1613 else if( nCol > 0 )
1615 // The previous cell in this row.
1616 pPrevCell = GetCell( nRow, nCol-1 );
1618 else if( nRow > 0 )
1620 // The last cell from the previous row.
1621 pPrevCell = GetCell( nRow-1, GetColumnCount()-1 );
1624 const SwStartNode *pSttNd = nullptr;
1625 if( pPrevCell )
1627 if( pPrevCell->GetStartNode() )
1628 pSttNd = pPrevCell->GetStartNode();
1629 // #i95726# - Some fault tolerance
1630 // else
1631 else if ( pPrevCell->GetSubTable() )
1632 pSttNd = pPrevCell->GetSubTable()->GetLastStartNode();
1634 OSL_ENSURE( pSttNd != nullptr,
1635 "table corrupt" );
1638 return pSttNd;
1641 void SwXMLTableContext::FixRowSpan( sal_uInt32 nRow, sal_uInt32 nCol,
1642 sal_uInt32 nColSpan )
1644 sal_uInt32 nLastCol = nCol + nColSpan;
1645 for( sal_uInt32 i = nCol; i < nLastCol; i++ )
1647 sal_uInt32 j = nRow;
1648 sal_uInt32 nRowSpan = 1;
1649 SwXMLTableCell_Impl *pCell = GetCell( j, i );
1650 while( pCell && pCell->GetRowSpan() > 1 )
1652 pCell->SetRowSpan( nRowSpan++ );
1653 pCell = j > 0 ? GetCell( --j, i ) : nullptr;
1658 void SwXMLTableContext::ReplaceWithEmptyCell( sal_uInt32 nRow, sal_uInt32 nCol, bool bRows )
1660 const SwStartNode *pPrevSttNd = GetPrevStartNode( nRow, nCol );
1661 const SwStartNode *pSttNd = InsertTableSection( pPrevSttNd );
1663 const SwXMLTableCell_Impl *pCell = GetCell( nRow, nCol );
1664 sal_uInt32 nLastRow = bRows ? nRow + pCell->GetRowSpan() : nRow + 1;
1665 sal_uInt32 nLastCol = nCol + pCell->GetColSpan();
1667 for( sal_uInt32 i=nRow; i<nLastRow; i++ )
1669 SwXMLTableRow_Impl *pRow = (*m_pRows)[i].get();
1670 for( sal_uInt32 j=nCol; j<nLastCol; j++ )
1671 pRow->GetCell( j )->SetStartNode( pSttNd );
1676 SwTableBox *SwXMLTableContext::NewTableBox( const SwStartNode *pStNd,
1677 SwTableLine *pUpper )
1679 // The topmost table is the only table that maintains the two members
1680 // pBox1 and bFirstSection.
1681 if( m_xParentTable.is() )
1682 return static_cast<SwXMLTableContext *>(m_xParentTable.get())->NewTableBox( pStNd,
1683 pUpper );
1685 SwTableBox *pBox;
1687 if( m_pBox1 &&
1688 m_pBox1->GetSttNd() == pStNd )
1690 // if the StartNode is equal to the StartNode of the initially
1691 // created box, we use this box
1692 pBox = m_pBox1;
1693 pBox->SetUpper( pUpper );
1694 m_pBox1 = nullptr;
1695 m_bOwnsBox1 = false;
1697 else
1698 pBox = new SwTableBox( m_pBoxFormat, *pStNd, pUpper );
1700 return pBox;
1703 SwTableBoxFormat* SwXMLTableContext::GetSharedBoxFormat(
1704 SwTableBox* pBox,
1705 const OUString& rStyleName,
1706 sal_Int32 nColumnWidth,
1707 bool bProtected,
1708 bool bMayShare,
1709 bool& bNew,
1710 bool* pModifyLocked )
1712 if ( m_pSharedBoxFormats == nullptr )
1713 m_pSharedBoxFormats.reset(new map_BoxFormat);
1715 SwTableBoxFormat* pBoxFormat2;
1717 TableBoxIndex aKey( rStyleName, nColumnWidth, bProtected );
1718 map_BoxFormat::iterator aIter = m_pSharedBoxFormats->find( aKey );
1719 if ( aIter == m_pSharedBoxFormats->end() )
1721 // unknown format so far -> construct a new one
1723 // get the old format, and reset all attributes
1724 // (but preserve FillOrder)
1725 pBoxFormat2 = static_cast<SwTableBoxFormat*>(pBox->ClaimFrameFormat());
1726 SwFormatFillOrder aFillOrder( pBoxFormat2->GetFillOrder() );
1727 pBoxFormat2->ResetAllFormatAttr(); // #i73790# - method renamed
1728 pBoxFormat2->SetFormatAttr( aFillOrder );
1729 bNew = true; // it's a new format now
1731 // share this format, if allowed
1732 if ( bMayShare )
1733 (*m_pSharedBoxFormats)[ aKey ] = pBoxFormat2;
1735 else
1737 // set the shared format
1738 pBoxFormat2 = aIter->second;
1739 pBox->ChgFrameFormat( pBoxFormat2, /*bNeedToReregister*/false );
1740 bNew = false; // copied from an existing format
1742 // claim it, if we are not allowed to share
1743 if ( !bMayShare )
1744 pBoxFormat2 = static_cast<SwTableBoxFormat*>(pBox->ClaimFrameFormat());
1747 // lock format (if so desired)
1748 if ( pModifyLocked != nullptr )
1750 (*pModifyLocked) = pBoxFormat2->IsModifyLocked();
1751 pBoxFormat2->LockModify();
1754 return pBoxFormat2;
1757 SwTableBox *SwXMLTableContext::MakeTableBox( SwTableLine *pUpper,
1758 sal_uInt32 nTopRow,
1759 sal_uInt32 nLeftCol,
1760 sal_uInt32 nBottomRow,
1761 sal_uInt32 nRightCol )
1763 //FIXME: here would be a great place to handle XmlId for cell
1764 SwTableBox *pBox = new SwTableBox( m_pBoxFormat, 0, pUpper );
1766 sal_uInt32 nColSpan = nRightCol - nLeftCol;
1767 sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
1769 // TODO: Share formats!
1770 SwFrameFormat *pFrameFormat = pBox->ClaimFrameFormat();
1771 SwFormatFillOrder aFillOrder( pFrameFormat->GetFillOrder() );
1772 pFrameFormat->ResetAllFormatAttr(); // #i73790# - method renamed
1773 pFrameFormat->SetFormatAttr( aFillOrder );
1775 pFrameFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nColWidth ) );
1777 SwTableLines& rLines = pBox->GetTabLines();
1778 bool bSplitted = false;
1780 while( !bSplitted )
1782 sal_uInt32 nStartRow = nTopRow;
1783 sal_uInt32 i;
1785 for( i = nTopRow; i < nBottomRow; i++ )
1787 // Could the table be split behind the current row?
1788 bool bSplit = true;
1789 SwXMLTableRow_Impl *pRow = (*m_pRows)[i].get();
1790 for( sal_uInt32 j=nLeftCol; j<nRightCol; j++ )
1792 bSplit = ( 1 == pRow->GetCell(j)->GetRowSpan() );
1793 if( !bSplit )
1794 break;
1796 if( bSplit && (nStartRow>nTopRow || i+1<nBottomRow) )
1798 SwTableLine *pLine =
1799 MakeTableLine( pBox, nStartRow, nLeftCol, i+1,
1800 nRightCol );
1802 rLines.push_back( pLine );
1804 nStartRow = i+1;
1805 bSplitted = true;
1808 if( !bSplitted )
1810 // No splitting was possible. That for, we have to force it.
1811 // Ruthless!
1813 nStartRow = nTopRow;
1814 while( nStartRow < nBottomRow )
1816 sal_uInt32 nMaxRowSpan = 0;
1817 SwXMLTableRow_Impl *pStartRow = (*m_pRows)[nStartRow].get();
1818 const SwXMLTableCell_Impl *pCell;
1819 for( i=nLeftCol; i<nRightCol; i++ )
1821 pCell = pStartRow->GetCell(i);
1822 if( pCell->GetRowSpan() > nMaxRowSpan )
1823 nMaxRowSpan = pCell->GetRowSpan();
1826 nStartRow += nMaxRowSpan;
1827 if( nStartRow<nBottomRow )
1829 SwXMLTableRow_Impl *pPrevRow = (*m_pRows)[nStartRow - 1U].get();
1830 i = nLeftCol;
1831 while( i < nRightCol )
1833 if( pPrevRow->GetCell(i)->GetRowSpan() > 1 )
1835 const SwXMLTableCell_Impl *pCell2 =
1836 GetCell( nStartRow, i );
1837 const sal_uInt32 nColSpan2 = pCell2->GetColSpan();
1838 FixRowSpan( nStartRow-1, i, nColSpan2 );
1839 ReplaceWithEmptyCell( nStartRow, i, true );
1840 i += nColSpan2;
1842 else
1844 i++;
1849 // and now start over again...
1853 return pBox;
1856 SwTableBox *SwXMLTableContext::MakeTableBox(
1857 SwTableLine *pUpper, const SwXMLTableCell_Impl *pCell,
1858 sal_uInt32 nLeftCol, sal_uInt32 nRightCol )
1860 //FIXME: here would be a great place to handle XmlId for cell
1861 SwTableBox *pBox;
1862 sal_uInt32 nColSpan = nRightCol - nLeftCol;
1863 sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
1865 if( pCell->GetStartNode() )
1867 pBox = NewTableBox( pCell->GetStartNode(), pUpper );
1869 else
1871 // and it is a table: therefore we build a new box and
1872 // put the rows of the table into the rows of the box
1873 pBox = new SwTableBox( m_pBoxFormat, 0, pUpper );
1874 pCell->GetSubTable()->MakeTable( pBox, nColWidth );
1877 // Share formats!
1878 const OUString sStyleName = pCell->GetStyleName();
1879 bool bModifyLocked;
1880 bool bNew;
1881 SwTableBoxFormat *pBoxFormat2 = GetSharedBoxFormat(
1882 pBox, sStyleName, nColWidth, pCell->IsProtected(),
1883 pCell->GetStartNode() && pCell->GetFormula().isEmpty() &&
1884 ! pCell->HasValue(),
1885 bNew, &bModifyLocked );
1887 // if a new format was created, then we need to set the style
1888 if ( bNew )
1890 // set style
1891 const SfxItemSet *pAutoItemSet = nullptr;
1892 if( pCell->GetStartNode() && !sStyleName.isEmpty() &&
1893 GetSwImport().FindAutomaticStyle(
1894 XmlStyleFamily::TABLE_CELL, sStyleName, &pAutoItemSet ) )
1896 if( pAutoItemSet )
1897 pBoxFormat2->SetFormatAttr( *pAutoItemSet );
1901 if( pCell->GetStartNode() )
1903 if (pCell->HasStringValue())
1905 SwNodeIndex const aNodeIndex(*(pCell->GetStartNode()), 1);
1906 SwTextNode *const pTextNode(aNodeIndex.GetNode().GetTextNode());
1907 SAL_WARN_IF(!pTextNode, "sw", "Should have a text node in cell?");
1908 if (pTextNode)
1910 SAL_WARN_IF(!pTextNode->GetText().isEmpty(), "sw",
1911 "why text here?");
1912 pTextNode->InsertText(*pCell->GetStringValue(),
1913 SwContentIndex(pTextNode, 0));
1917 // try to rescue broken documents with a certain pattern
1918 // if: 1) the cell has a default number format (number 0)
1919 // 2) the call has no formula
1920 // 3) the value is 0.0
1921 // 4) the text doesn't look anything like 0.0
1922 // [read: length > 10, or length smaller 10 and no 0 in it]
1923 // then make it a text cell!
1924 bool bSuppressNumericContent = false;
1925 if( pCell->HasValue() && (pCell->GetValue() == 0.0) &&
1926 pCell->GetFormula().isEmpty() &&
1927 !sStyleName.isEmpty() )
1929 // default num format?
1930 if( const SwTableBoxNumFormat* pNumFormat = pBoxFormat2->GetItemIfSet( RES_BOXATR_FORMAT, false ) )
1932 if (pNumFormat && (pNumFormat->GetValue() % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1934 // only one text node?
1935 SwNodeIndex aNodeIndex( *(pCell->GetStartNode()), 1 );
1936 if( ( aNodeIndex.GetNode().EndOfSectionIndex() -
1937 aNodeIndex.GetNode().StartOfSectionIndex() ) == SwNodeOffset(2) )
1939 SwTextNode* pTextNode= aNodeIndex.GetNode().GetTextNode();
1940 if( pTextNode != nullptr )
1942 // check text: does it look like some form of 0.0?
1943 const OUString& rText = pTextNode->GetText();
1944 if( ( rText.getLength() > 10 ) ||
1945 ( rText.indexOf( '0' ) == -1 ) )
1947 bSuppressNumericContent = true;
1951 else
1952 bSuppressNumericContent = true; // several nodes
1957 if( bSuppressNumericContent )
1959 // suppress numeric content? Then reset number format!
1960 pBoxFormat2->ResetFormatAttr( RES_BOXATR_FORMULA );
1961 pBoxFormat2->ResetFormatAttr( RES_BOXATR_FORMAT );
1962 pBoxFormat2->ResetFormatAttr( RES_BOXATR_VALUE );
1964 else
1966 // the normal case: set formula and value (if available)
1968 const OUString& rFormula = pCell->GetFormula();
1969 if (!rFormula.isEmpty())
1971 // formula cell: insert formula if valid
1972 SwTableBoxFormula aFormulaItem( rFormula );
1973 pBoxFormat2->SetFormatAttr( aFormulaItem );
1975 else if (!pCell->HasValue() && pCell->HasStringValue())
1977 // Check for another inconsistency:
1978 // No value but a non-textual format, i.e. a number format
1979 // Solution: the number format will be removed,
1980 // the cell gets the default text format.
1981 if( const SwTableBoxNumFormat* pNumFormat = m_pBoxFormat->GetItemIfSet( RES_BOXATR_FORMAT, false ) )
1983 const SwDoc* pDoc = m_pBoxFormat->GetDoc();
1984 const SvNumberFormatter* pNumberFormatter = pDoc ?
1985 pDoc->GetNumberFormatter() : nullptr;
1986 if( pNumFormat != nullptr && pNumberFormatter &&
1987 !pNumberFormatter->GetEntry( pNumFormat->GetValue() )->IsTextFormat() )
1988 m_pBoxFormat->ResetFormatAttr( RES_BOXATR_FORMAT );
1991 // always insert value, even if default
1992 if( pCell->HasValue() )
1994 SwTableBoxValue aValueItem( pCell->GetValue() );
1995 pBoxFormat2->SetFormatAttr( aValueItem );
1999 // update cell content depend on the default language
2000 pBox->ActualiseValueBox();
2003 // table cell protection
2004 if( pCell->IsProtected() )
2006 SvxProtectItem aProtectItem( RES_PROTECT );
2007 aProtectItem.SetContentProtect( true );
2008 pBoxFormat2->SetFormatAttr( aProtectItem );
2011 // restore old modify-lock state
2012 if (! bModifyLocked)
2013 pBoxFormat2->UnlockModify();
2015 pBoxFormat2->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nColWidth ) );
2017 return pBox;
2020 SwTableLine *SwXMLTableContext::MakeTableLine( SwTableBox *pUpper,
2021 sal_uInt32 nTopRow,
2022 sal_uInt32 nLeftCol,
2023 sal_uInt32 nBottomRow,
2024 sal_uInt32 nRightCol )
2026 //FIXME: here would be a great place to handle XmlId for row
2027 SwTableLine *pLine;
2028 if( !pUpper && 0UL==nTopRow )
2030 pLine = m_pTableNode->GetTable().GetTabLines()[0U];
2032 else
2034 pLine = new SwTableLine( m_pLineFormat, 0, pUpper );
2037 // TODO: Share formats!
2038 SwFrameFormat *pFrameFormat = pLine->ClaimFrameFormat();
2039 SwFormatFillOrder aFillOrder( pFrameFormat->GetFillOrder() );
2040 pFrameFormat->ResetAllFormatAttr(); // #i73790# - method renamed
2041 pFrameFormat->SetFormatAttr( aFillOrder );
2043 const SfxItemSet *pAutoItemSet = nullptr;
2044 const OUString& rStyleName = (*m_pRows)[nTopRow]->GetStyleName();
2045 if( 1 == (nBottomRow - nTopRow) &&
2046 !rStyleName.isEmpty() &&
2047 GetSwImport().FindAutomaticStyle(
2048 XmlStyleFamily::TABLE_ROW, rStyleName, &pAutoItemSet ) )
2050 if( pAutoItemSet )
2051 pFrameFormat->SetFormatAttr( *pAutoItemSet );
2054 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2056 sal_uInt32 nStartCol = nLeftCol;
2057 while( nStartCol < nRightCol )
2059 for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
2060 (*m_pRows)[nRow]->SetSplitable( true );
2062 sal_uInt32 nCol = nStartCol;
2063 sal_uInt32 nSplitCol = nRightCol;
2064 bool bSplitted = false;
2065 while( !bSplitted )
2067 OSL_ENSURE( nCol < nRightCol, "Ran too far" );
2069 // Can be split after current HTML table column?
2070 // If yes, can the created region still be split to
2071 // rows if the next column is added to it?
2072 bool bSplit = true;
2073 bool bHoriSplitMayContinue = false;
2074 bool bHoriSplitPossible = false;
2076 if ( m_bHasSubTables )
2078 // Convert row spans if the table has subtables:
2079 for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
2081 SwXMLTableCell_Impl *pCell = GetCell(nRow,nCol);
2082 // Could the table fragment be split horizontally behind
2083 // the current line?
2084 bool bHoriSplit = (*m_pRows)[nRow]->IsSplitable() &&
2085 nRow+1 < nBottomRow &&
2086 1 == pCell->GetRowSpan();
2087 (*m_pRows)[nRow]->SetSplitable( bHoriSplit );
2089 // Could the table fragment be split vertically behind the
2090 // current column (uptp the current line?
2091 bSplit &= ( 1 == pCell->GetColSpan() );
2092 if( bSplit )
2094 bHoriSplitPossible |= bHoriSplit;
2096 // Could the current table fragment be split
2097 // horizontally behind the next column, too?
2098 bHoriSplit &= (nCol+1 < nRightCol &&
2099 1 == GetCell(nRow,nCol+1)->GetRowSpan());
2100 bHoriSplitMayContinue |= bHoriSplit;
2104 else
2106 // No subtables: we use the new table model.
2107 SwXMLTableCell_Impl *pCell = GetCell(nTopRow,nCol);
2109 // #i95726# - some fault tolerance
2110 if ( pCell == nullptr )
2112 OSL_FAIL( "table seems to be corrupt." );
2113 break;
2116 // Could the table fragment be split vertically behind the
2117 // current column (uptp the current line?
2118 bSplit = 1 == pCell->GetColSpan();
2121 #if OSL_DEBUG_LEVEL > 0
2122 if( nCol == nRightCol-1 )
2124 OSL_ENSURE( bSplit, "Split-Flag wrong" );
2125 if ( m_bHasSubTables )
2127 OSL_ENSURE( !bHoriSplitMayContinue,
2128 "HoriSplitMayContinue-Flag wrong" );
2129 SwXMLTableCell_Impl *pTmpCell = GetCell( nTopRow, nStartCol );
2130 OSL_ENSURE( pTmpCell->GetRowSpan() != (nBottomRow-nTopRow) ||
2131 !bHoriSplitPossible, "HoriSplitPossible-Flag wrong" );
2134 #endif
2136 OSL_ENSURE( !m_bHasSubTables || !bHoriSplitMayContinue || bHoriSplitPossible,
2137 "bHoriSplitMayContinue, but not bHoriSplitPossible" );
2139 if( bSplit )
2141 SwTableBox* pBox = nullptr;
2142 SwXMLTableCell_Impl *pCell = GetCell( nTopRow, nStartCol );
2143 // #i95726# - some fault tolerance
2144 if( ( !m_bHasSubTables || ( pCell->GetRowSpan() == (nBottomRow-nTopRow) ) ) &&
2145 pCell->GetColSpan() == (nCol+1-nStartCol) &&
2146 ( pCell->GetStartNode() || pCell->GetSubTable() ) )
2148 // insert new empty cell for covered cells:
2149 sal_Int32 nBoxRowSpan = 1;
2150 if ( !m_bHasSubTables )
2152 nBoxRowSpan = pCell->GetRowSpan();
2153 if ( pCell->IsCovered() )
2155 nBoxRowSpan = -1 * nBoxRowSpan;
2156 ReplaceWithEmptyCell( nTopRow, nStartCol, false );
2160 // The remaining box neither contains lines nor rows (i.e.
2161 // is a content box
2162 nSplitCol = nCol + 1;
2164 pBox = MakeTableBox( pLine, pCell, nStartCol, nSplitCol );
2166 if ( 1 != nBoxRowSpan )
2167 pBox->setRowSpan( nBoxRowSpan );
2169 bSplitted = true;
2171 else if( m_bHasSubTables && bHoriSplitPossible && bHoriSplitMayContinue )
2173 // The table fragment could be split behind the current
2174 // column, and the remaining fragment could be divided
2175 // into lines. Anyway, it could be that this applies to
2176 // the next column, too. That for, we check the next
2177 // column but remember the current one as a good place to
2178 // split.
2179 nSplitCol = nCol + 1;
2181 else if ( m_bHasSubTables )
2183 // If the table resulting table fragment could be divided
2184 // into lines if splitting behind the current column, but
2185 // this doesn't apply for thr next column, we split begind
2186 // the current column. This applies for the last column,
2187 // too.
2188 // If the resulting box cannot be split into rows,
2189 // the split at the last split position we remembered.
2190 if( bHoriSplitPossible || nSplitCol > nCol+1 )
2192 OSL_ENSURE( !bHoriSplitMayContinue,
2193 "bHoriSplitMayContinue==true" );
2194 OSL_ENSURE( bHoriSplitPossible || nSplitCol == nRightCol,
2195 "bHoriSplitPossible flag should be set" );
2197 nSplitCol = nCol + 1;
2200 pBox = MakeTableBox( pLine, nTopRow, nStartCol,
2201 nBottomRow, nSplitCol );
2202 bSplitted = true;
2205 OSL_ENSURE( m_bHasSubTables || pBox, "Colspan trouble" );
2207 if( pBox )
2208 rBoxes.push_back( pBox );
2210 nCol++;
2212 nStartCol = nSplitCol;
2215 return pLine;
2218 void SwXMLTableContext::MakeTable_( SwTableBox *pBox )
2220 // fix column widths
2221 std::vector<ColumnWidthInfo>::iterator colIter;
2222 sal_uInt32 nCols = GetColumnCount();
2224 // If there are empty rows (because of some row span of previous rows)
2225 // the have to be deleted. The previous rows have to be truncated.
2227 if (m_pRows->size() > m_nCurRow)
2229 SwXMLTableRow_Impl *pPrevRow = (*m_pRows)[m_nCurRow - 1U].get();
2230 const SwXMLTableCell_Impl *pCell;
2231 for( size_t i = 0; i < m_aColumnWidths.size(); ++i )
2233 pCell = pPrevRow->GetCell(i);
2234 if( pCell->GetRowSpan() > 1 )
2236 FixRowSpan( m_nCurRow-1, i, 1UL );
2239 for (size_t i = m_pRows->size() - 1; i >= m_nCurRow; --i)
2240 m_pRows->pop_back();
2243 if (m_pRows->empty())
2245 InsertCell( "", 1U, nCols, InsertTableSection() );
2248 // TODO: Do we have to keep both values, the relative and the absolute
2249 // width?
2250 sal_Int32 nAbsWidth = 0;
2251 sal_Int32 nMinAbsColWidth = 0;
2252 sal_Int32 nRelWidth = 0;
2253 sal_Int32 nMinRelColWidth = 0;
2254 sal_uInt32 nRelCols = 0;
2255 for( const auto& rCol : m_aColumnWidths)
2257 if( rCol.isRelative )
2259 nRelWidth += rCol.width;
2260 if( 0 == nMinRelColWidth || rCol.width < nMinRelColWidth )
2261 nMinRelColWidth = rCol.width;
2262 nRelCols++;
2264 else
2266 nAbsWidth += rCol.width;
2267 if( 0 == nMinAbsColWidth || rCol.width < nMinAbsColWidth )
2268 nMinAbsColWidth = rCol.width;
2271 sal_uInt32 nAbsCols = nCols - nRelCols;
2273 if( m_bRelWidth )
2275 // If there a columns that have an absolute width, we have to
2276 // calculate a relative one for them.
2277 if( nAbsCols > 0 )
2279 // All column that have absolute widths get relative widths;
2280 // these widths relate to each over like the original absolute
2281 // widths. The smallest column gets a width that has the same
2282 // value as the smallest column that has a relative width
2283 // already.
2284 if( 0 == nMinRelColWidth )
2285 nMinRelColWidth = nMinAbsColWidth;
2287 for( auto& rCol : m_aColumnWidths)
2289 if( !rCol.isRelative )
2291 if (nMinAbsColWidth == 0)
2292 throw o3tl::divide_by_zero();
2293 sal_Int32 nVal;
2294 if (o3tl::checked_multiply<sal_Int32>(rCol.width, nMinRelColWidth, nVal))
2295 throw std::overflow_error("overflow in multiply");
2296 sal_Int32 nRelCol = nVal / nMinAbsColWidth;
2297 rCol.width = nRelCol;
2298 rCol.isRelative = true;
2299 nRelWidth += nRelCol;
2300 nAbsCols--;
2301 if (nAbsCols <= 0)
2302 break;
2307 if( !m_nWidth )
2309 // This happens only for percentage values for the table itself.
2310 // In this case, the columns get the correct width even if
2311 // the sum of the relative widths is smaller than the available
2312 // width in TWIP. Therefore, we can use the relative width.
2313 m_nWidth = std::min(nRelWidth, MAX_WIDTH);
2315 if( nRelWidth != m_nWidth && nRelWidth && nCols )
2317 double n = static_cast<double>(m_nWidth) / static_cast<double>(nRelWidth);
2318 nRelWidth = 0;
2319 for( colIter = m_aColumnWidths.begin(); colIter < m_aColumnWidths.end() - 1; ++colIter)
2321 sal_Int32 nW = static_cast<sal_Int32>( colIter->width * n);
2322 colIter->width = o3tl::narrowing<sal_uInt16>(nW);
2323 nRelWidth += nW;
2325 m_aColumnWidths.back().width = (m_nWidth-nRelWidth);
2328 else
2330 // If there are columns that have relative widths, we have to
2331 // calculate an absolute widths for them.
2332 if( nRelCols > 0 )
2334 // The absolute space that is available for all columns with a
2335 // relative width.
2336 sal_Int32 nAbsForRelWidth =
2337 m_nWidth > nAbsWidth ? m_nWidth - nAbsWidth : sal_Int32(0L);
2339 // The relative width that has to be distributed in addition to
2340 // equally widthed columns.
2341 sal_Int32 nExtraRel = nRelWidth - (nRelCols * nMinRelColWidth);
2343 // The absolute space that may be distributed in addition to
2344 // minimum widthed columns.
2345 sal_Int32 nMinAbs = nRelCols * MINLAY;
2346 sal_Int32 nExtraAbs =
2347 nAbsForRelWidth > nMinAbs ? nAbsForRelWidth - nMinAbs : sal_Int32(0L);
2349 bool bMin = false; // Do all columns get the minimum width?
2350 bool bMinExtra = false; // Do all columns get the minimum width plus
2351 // some extra space?
2353 if( nAbsForRelWidth <= nMinAbs )
2355 // If there is not enough space left for all columns to
2356 // get the minimum width, they get the minimum width, anyway.
2357 nAbsForRelWidth = nMinAbs;
2358 bMin = true;
2360 else if( nAbsForRelWidth <= (nRelWidth * MINLAY) /
2361 nMinRelColWidth )
2363 // If there is enough space for all columns to get the
2364 // minimum width, but not to get a width that takes the
2365 // relative width into account, each column gets the minimum
2366 // width plus some extra space that is based on the additional
2367 // space that is available.
2368 bMinExtra = true;
2370 // Otherwise, if there is enough space for every column, every
2371 // column gets this space.
2373 for( auto& rCol : m_aColumnWidths )
2375 if( rCol.isRelative )
2377 sal_Int32 nAbsCol;
2378 if( 1 == nRelCols )
2380 // The last column that has a relative width gets
2381 // all absolute space that is left.
2382 nAbsCol = nAbsForRelWidth;
2384 else
2386 if( bMin )
2388 nAbsCol = MINLAY;
2390 else if( bMinExtra )
2392 sal_Int32 nExtraRelCol = rCol.width - nMinRelColWidth;
2393 nAbsCol = MINLAY + (nExtraRelCol * nExtraAbs) /
2394 nExtraRel;
2396 else
2398 nAbsCol = ( rCol.width * nAbsForRelWidth) / nRelWidth;
2401 rCol.width = nAbsCol;
2402 rCol.isRelative = false;
2403 nAbsForRelWidth -= nAbsCol;
2404 nAbsWidth += nAbsCol;
2405 nRelCols--;
2406 if (nRelCols <= 0)
2407 break;
2412 if( nCols && nAbsWidth )
2414 if( nAbsWidth < m_nWidth )
2416 // If the table's width is larger than the sum of the absolute
2417 // column widths, every column get some extra width.
2418 sal_Int32 nExtraAbs = m_nWidth - nAbsWidth;
2419 sal_Int32 nAbsLastCol = m_aColumnWidths.back().width + nExtraAbs;
2420 for( colIter = m_aColumnWidths.begin(); colIter < m_aColumnWidths.end()-1; ++colIter )
2422 sal_Int32 nAbsCol = colIter->width;
2423 sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
2424 nAbsWidth;
2425 nAbsCol += nExtraAbsCol;
2426 colIter->width = nAbsCol;
2427 nAbsLastCol -= nExtraAbsCol;
2429 m_aColumnWidths.back().width = nAbsLastCol;
2431 else if( nAbsWidth > m_nWidth )
2433 // If the table's width is smaller than the sum of the absolute
2434 // column widths, every column needs to shrink.
2435 // Every column gets the minimum width plus some extra width.
2436 sal_Int32 nExtraAbs = m_nWidth - (nCols * MINLAY);
2437 sal_Int32 nAbsLastCol = MINLAY + nExtraAbs;
2438 for( colIter = m_aColumnWidths.begin(); colIter < m_aColumnWidths.end()-1; ++colIter )
2440 sal_Int32 nAbsCol = colIter->width;
2441 sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
2442 nAbsWidth;
2443 nAbsCol = MINLAY + nExtraAbsCol;
2444 colIter->width = nAbsCol;
2445 nAbsLastCol -= nExtraAbsCol;
2447 m_aColumnWidths.back().width = nAbsLastCol;
2452 SwTableLines& rLines =
2453 pBox ? pBox->GetTabLines()
2454 : m_pTableNode->GetTable().GetTabLines();
2456 sal_uInt32 nStartRow = 0;
2457 sal_uInt32 nRows = m_pRows->size();
2458 for(sal_uInt32 i=0; i<nRows; ++i )
2460 // Could we split the table behind the current line?
2461 bool bSplit = true;
2462 if ( m_bHasSubTables )
2464 SwXMLTableRow_Impl *pRow = (*m_pRows)[i].get();
2465 for( sal_uInt32 j=0; j<nCols; j++ )
2467 bSplit = ( 1 == pRow->GetCell(j)->GetRowSpan() );
2468 if( !bSplit )
2469 break;
2473 if( bSplit )
2475 SwTableLine *pLine =
2476 MakeTableLine( pBox, nStartRow, 0UL, i+1, nCols );
2477 if( pBox || nStartRow>0 )
2478 rLines.push_back( pLine );
2479 nStartRow = i+1;
2484 void SwXMLTableContext::MakeTable()
2486 // this method will modify the document directly -> lock SolarMutex
2487 // This will call all other MakeTable*(..) methods, so
2488 // those don't need to be locked separately.
2489 SolarMutexGuard aGuard;
2491 // #i97274# handle invalid tables
2492 if (!m_pRows || m_pRows->empty() || !GetColumnCount())
2494 OSL_FAIL("invalid table: no cells; deleting...");
2495 m_pTableNode->GetDoc().getIDocumentContentOperations().DeleteSection( m_pTableNode );
2496 m_pTableNode = nullptr;
2497 m_pBox1 = nullptr;
2498 m_bOwnsBox1 = false;
2499 m_pSttNd1 = nullptr;
2500 return;
2503 SwXMLImport& rSwImport = GetSwImport();
2505 SwFrameFormat *pFrameFormat = m_pTableNode->GetTable().GetFrameFormat();
2507 sal_Int16 eHoriOrient = text::HoriOrientation::FULL;
2508 bool bSetHoriOrient = false;
2510 sal_uInt8 nPercentWidth = 0U;
2512 OUString sStyleName;
2513 SwStyleNameMapper::FillUIName( m_aTemplateName, sStyleName, SwGetPoolIdFromName::TabStyle );
2514 m_pTableNode->GetTable().SetTableStyleName( sStyleName );
2515 m_pTableNode->GetTable().SetRowsToRepeat( m_nHeaderRows );
2516 m_pTableNode->GetTable().SetTableModel( !m_bHasSubTables );
2518 const SfxItemSet *pAutoItemSet = nullptr;
2519 if( !m_aStyleName.isEmpty() &&
2520 rSwImport.FindAutomaticStyle(
2521 XmlStyleFamily::TABLE_TABLE, m_aStyleName, &pAutoItemSet ) &&
2522 pAutoItemSet )
2524 const SvxLRSpaceItem *pLRSpace =
2525 pAutoItemSet->GetItemIfSet( RES_LR_SPACE, false );
2527 if( const SwFormatHoriOrient* pItem = pAutoItemSet->GetItemIfSet( RES_HORI_ORIENT, false ) )
2529 eHoriOrient = pItem->GetHoriOrient();
2530 switch( eHoriOrient )
2532 case text::HoriOrientation::FULL:
2533 if( pLRSpace )
2535 eHoriOrient = text::HoriOrientation::NONE;
2536 bSetHoriOrient = true;
2538 break;
2539 case text::HoriOrientation::LEFT:
2540 if( pLRSpace )
2542 eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
2543 bSetHoriOrient = true;
2545 break;
2546 default:
2550 else
2552 bSetHoriOrient = true;
2555 const SwFormatFrameSize *pSize =
2556 pAutoItemSet->GetItemIfSet( RES_FRM_SIZE, false );
2558 switch( eHoriOrient )
2560 case text::HoriOrientation::FULL:
2561 case text::HoriOrientation::NONE:
2562 // For text::HoriOrientation::NONE we would prefer to use the sum
2563 // of the relative column widths as reference width.
2564 // Unfortunately this works only if this sum interpreted as
2565 // twip value is larger than the space that is available.
2566 // We don't know that space, so we have to use MAX_WIDTH, too.
2567 // Even if a size is specified, it will be ignored!
2568 m_nWidth = MAX_WIDTH;
2569 break;
2570 default:
2571 if( pSize )
2573 if( pSize->GetWidthPercent() )
2575 // The width will be set in MakeTable_
2576 nPercentWidth = pSize->GetWidthPercent();
2578 else
2580 m_nWidth = pSize->GetWidth();
2581 sal_Int32 const min = static_cast<sal_Int32>(
2582 std::min<sal_uInt32>(GetColumnCount() * MINLAY, MAX_WIDTH));
2583 if( m_nWidth < min )
2585 m_nWidth = min;
2587 else if( m_nWidth > MAX_WIDTH )
2589 m_nWidth = MAX_WIDTH;
2591 m_bRelWidth = false;
2594 else
2596 eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH == eHoriOrient
2597 ? text::HoriOrientation::NONE : text::HoriOrientation::FULL;
2598 bSetHoriOrient = true;
2599 m_nWidth = MAX_WIDTH;
2601 break;
2604 pFrameFormat->SetFormatAttr( *pAutoItemSet );
2606 else
2608 bSetHoriOrient = true;
2609 m_nWidth = MAX_WIDTH;
2612 SwTableLine *pLine1 = m_pTableNode->GetTable().GetTabLines()[0U];
2613 assert(m_pBox1 == pLine1->GetTabBoxes()[0] && !m_bOwnsBox1 && "Why is box 1 change?");
2614 m_pBox1->m_pStartNode = m_pSttNd1;
2615 pLine1->GetTabBoxes().erase( pLine1->GetTabBoxes().begin() );
2616 m_bOwnsBox1 = true;
2618 m_pLineFormat = static_cast<SwTableLineFormat*>(pLine1->GetFrameFormat());
2619 m_pBoxFormat = static_cast<SwTableBoxFormat*>(m_pBox1->GetFrameFormat());
2621 MakeTable_();
2623 if( bSetHoriOrient )
2624 pFrameFormat->SetFormatAttr( SwFormatHoriOrient( 0, eHoriOrient ) );
2626 // This must be after the call to MakeTable_, because nWidth might be
2627 // changed there.
2628 pFrameFormat->LockModify();
2629 SwFormatFrameSize aSize( SwFrameSize::Variable, m_nWidth );
2630 aSize.SetWidthPercent( nPercentWidth );
2631 pFrameFormat->SetFormatAttr( aSize );
2632 pFrameFormat->UnlockModify();
2634 for (std::unique_ptr<SwXMLTableRow_Impl> & rRow : *m_pRows)
2635 rRow->Dispose();
2637 // now that table is complete, change into DDE table (if appropriate)
2638 if (m_xDDESource.is())
2640 // change existing table into DDE table:
2641 // 1) Get DDE field type (get data from dde-source context),
2642 SwDDEFieldType* pFieldType = lcl_GetDDEFieldType( m_xDDESource.get(),
2643 m_pTableNode );
2645 // 2) release the DDE source context,
2646 m_xDDESource.set(nullptr);
2648 // 3) create new DDE table, and
2649 std::unique_ptr<SwDDETable> pDDETable( new SwDDETable( m_pTableNode->GetTable(),
2650 pFieldType, false ) );
2652 // 4) set new (DDE)table at node.
2653 m_pTableNode->SetNewTable(std::move(pDDETable), false);
2656 // ??? this is always false: root frame is only created in SwViewShell::Init
2657 if( m_pTableNode->GetDoc().getIDocumentLayoutAccess().GetCurrentViewShell() )
2659 m_pTableNode->DelFrames();
2660 m_pTableNode->MakeOwnFrames();
2664 void SwXMLTableContext::MakeTable( SwTableBox *pBox, sal_Int32 nW )
2666 //FIXME: here would be a great place to handle XmlId for subtable
2667 m_pLineFormat = GetParentTable()->m_pLineFormat;
2668 m_pBoxFormat = GetParentTable()->m_pBoxFormat;
2669 m_nWidth = nW;
2670 m_bRelWidth = GetParentTable()->m_bRelWidth;
2672 MakeTable_( pBox );
2674 for (std::unique_ptr<SwXMLTableRow_Impl> & rpRow : *m_pRows)
2676 // i#113600, to break the cyclic reference to SwXMLTableContext object
2677 rpRow->Dispose();
2681 const SwStartNode *SwXMLTableContext::InsertTableSection(
2682 const SwStartNode *const pPrevSttNd,
2683 OUString const*const pStringValueStyleName)
2685 // The topmost table is the only table that maintains the two members
2686 // pBox1 and bFirstSection.
2687 if( m_xParentTable.is() )
2688 return static_cast<SwXMLTableContext *>(m_xParentTable.get())
2689 ->InsertTableSection(pPrevSttNd, pStringValueStyleName);
2691 const SwStartNode *pStNd;
2693 if( m_bFirstSection )
2695 Reference<XInterface> xCursorTunnel( GetImport().GetTextImport()->GetCursor(),
2696 UNO_QUERY);
2697 OSL_ENSURE( xCursorTunnel.is(), "missing XUnoTunnel for Cursor" );
2698 OTextCursorHelper *pTextCursor = dynamic_cast<OTextCursorHelper*>(xCursorTunnel.get());
2699 assert(pTextCursor && "SwXTextCursor missing");
2701 // The Cursor already is in the first section
2702 pStNd = pTextCursor->GetPaM()->GetPointNode().FindTableBoxStartNode();
2703 m_bFirstSection = false;
2704 GetImport().GetTextImport()->SetStyleAndAttrs( GetImport(),
2705 GetImport().GetTextImport()->GetCursor(), "Standard", true );
2707 else
2709 SwDoc* pDoc = GetSwImport().getDoc();
2710 const SwEndNode *pEndNd = pPrevSttNd ? pPrevSttNd->EndOfSectionNode()
2711 : m_pTableNode->EndOfSectionNode();
2712 // #i78921# - make code robust
2713 OSL_ENSURE( pDoc, "<SwXMLTableContext::InsertTableSection(..)> - no <pDoc> at <SwXTextCursor> instance - <SwXTextCurosr> doesn't seem to be registered at a <SwUnoCursor> instance." );
2714 if ( !pDoc )
2716 pDoc = &const_cast<SwDoc&>(pEndNd->GetDoc());
2718 SwNodeOffset nOffset(pPrevSttNd ? 1 : 0);
2719 SwNodeIndex aIdx( *pEndNd, nOffset );
2720 SwTextFormatColl *pColl =
2721 pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_STANDARD, false );
2722 pStNd = pDoc->GetNodes().MakeTextSection( aIdx.GetNode(), SwTableBoxStartNode,
2723 pColl );
2724 // Consider the case that a table is defined without a row.
2725 if( !pPrevSttNd && m_pBox1 != nullptr )
2727 m_pBox1->m_pStartNode = pStNd;
2728 SwContentNode *pCNd = pDoc->GetNodes()[ pStNd->GetIndex() + 1 ]
2729 ->GetContentNode();
2730 SwFrameFormat *const pTableFormat = m_pTableNode->GetTable().GetFrameFormat();
2731 rtl::Reference<SwXCell> xParent = SwXCell::CreateXCell( pTableFormat, m_pBox1 );
2732 DBG_TESTSOLARMUTEX();
2733 SwPaM aPam(*pCNd, *pCNd);
2734 rtl::Reference<SwXTextCursor> xTextCursor =
2735 new SwXTextCursor(*pDoc, xParent, CursorType::TableText,
2736 *aPam.GetPoint(), aPam.GetMark());
2737 GetImport().GetTextImport()->SetCursor( static_cast<XWordCursor*>(xTextCursor.get()) );
2741 if (pStringValueStyleName)
2742 { // fdo#62147: apply style to paragraph on string-value cell
2743 GetImport().GetTextImport()->SetStyleAndAttrs( GetImport(),
2744 GetImport().GetTextImport()->GetCursor(), *pStringValueStyleName,
2745 true, false, -1, false); // parameters same as sCellParaStyleName
2748 return pStNd;
2751 void SwXMLTableContext::endFastElement(sal_Int32 )
2753 if( IsValid() && !m_xParentTable.is() )
2755 MakeTable();
2756 GetImport().GetTextImport()->SetCursor( m_xOldCursor );
2760 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */