update credits
[LibreOffice.git] / sw / source / filter / xml / xmltbli.cxx
blobdd8b358d2c289619165b24c4450101f860fcad32
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 <limits.h>
23 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
24 #include <com/sun/star/text/XTextTable.hpp>
25 #include <com/sun/star/table/XCellRange.hpp>
26 #include <svl/itemset.hxx>
27 #include <svl/zformat.hxx>
28 #include <sax/tools/converter.hxx>
29 #include <xmloff/xmlnmspe.hxx>
30 #include <xmloff/xmltkmap.hxx>
31 #include <xmloff/nmspmap.hxx>
33 #include <xmloff/families.hxx>
34 #include <xmloff/xmluconv.hxx>
35 #include <xmloff/i18nmap.hxx>
36 #include <editeng/protitem.hxx>
37 #include "poolfmt.hxx"
38 #include "fmtfsize.hxx"
39 #include "fmtornt.hxx"
40 #include "fmtfordr.hxx"
41 #include "doc.hxx"
42 #include "swtable.hxx"
43 #include "swtblfmt.hxx"
44 #include "pam.hxx"
45 #include "unotbl.hxx"
46 #include "unotextrange.hxx"
47 #include "unocrsr.hxx"
48 #include "cellatr.hxx"
49 #include "swddetbl.hxx"
50 #include "ddefld.hxx"
51 #include <sfx2/linkmgr.hxx> // for cTokenSeparator
52 #include "xmlimp.hxx"
53 #include "xmltbli.hxx"
55 // for locking SolarMutex: svapp + mutex
56 #include <vcl/svapp.hxx>
57 #include <osl/mutex.hxx>
58 #include "ndtxt.hxx"
60 using namespace ::com::sun::star;
61 using namespace ::com::sun::star::uno;
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::text;
64 using namespace ::com::sun::star::frame;
65 using namespace ::com::sun::star::table;
66 using namespace ::com::sun::star::xml::sax;
67 using namespace ::xmloff::token;
68 using ::boost::unordered_map;
70 enum SwXMLTableElemTokens
72 XML_TOK_TABLE_HEADER_COLS,
73 XML_TOK_TABLE_COLS,
74 XML_TOK_TABLE_COL,
75 XML_TOK_TABLE_HEADER_ROWS,
76 XML_TOK_TABLE_ROWS,
77 XML_TOK_TABLE_ROW,
78 XML_TOK_OFFICE_DDE_SOURCE,
79 XML_TOK_TABLE_ELEM_END=XML_TOK_UNKNOWN
82 enum SwXMLTableCellAttrTokens
84 XML_TOK_TABLE_XMLID,
85 XML_TOK_TABLE_STYLE_NAME,
86 XML_TOK_TABLE_NUM_COLS_SPANNED,
87 XML_TOK_TABLE_NUM_ROWS_SPANNED,
88 XML_TOK_TABLE_NUM_COLS_REPEATED,
89 XML_TOK_TABLE_FORMULA,
90 XML_TOK_TABLE_VALUE,
91 XML_TOK_TABLE_TIME_VALUE,
92 XML_TOK_TABLE_DATE_VALUE,
93 XML_TOK_TABLE_BOOLEAN_VALUE,
94 XML_TOK_TABLE_PROTECTED,
95 XML_TOK_TABLE_STRING_VALUE,
96 XML_TOK_TABLE_VALUE_TYPE,
97 XML_TOK_TABLE_CELL_ATTR_END=XML_TOK_UNKNOWN
100 static SvXMLTokenMapEntry aTableElemTokenMap[] =
102 { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS,
103 XML_TOK_TABLE_HEADER_COLS },
104 { XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS, XML_TOK_TABLE_COLS },
105 { XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, XML_TOK_TABLE_COL },
106 { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS,
107 XML_TOK_TABLE_HEADER_ROWS },
108 { XML_NAMESPACE_TABLE, XML_TABLE_ROWS, XML_TOK_TABLE_ROWS },
109 { XML_NAMESPACE_TABLE, XML_TABLE_ROW, XML_TOK_TABLE_ROW },
110 { XML_NAMESPACE_OFFICE, XML_DDE_SOURCE,
111 XML_TOK_OFFICE_DDE_SOURCE },
113 // There are slight differences between <table:table-columns> and
114 // <table:table-columns-groups>. However, none of these are
115 // supported in Writer (they are Calc-only features), so we
116 // support column groups by simply using the <table:table-columns>
117 // token for column groups, too.
118 { XML_NAMESPACE_TABLE, XML_TABLE_COLUMN_GROUP, XML_TOK_TABLE_COLS },
120 XML_TOKEN_MAP_END
123 static SvXMLTokenMapEntry aTableCellAttrTokenMap[] =
125 { XML_NAMESPACE_XML, XML_ID, XML_TOK_TABLE_XMLID },
126 { XML_NAMESPACE_TABLE, XML_STYLE_NAME, XML_TOK_TABLE_STYLE_NAME },
127 { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, XML_TOK_TABLE_NUM_COLS_SPANNED },
128 { XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, XML_TOK_TABLE_NUM_ROWS_SPANNED },
129 { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, XML_TOK_TABLE_NUM_COLS_REPEATED },
130 { XML_NAMESPACE_TABLE, XML_FORMULA, XML_TOK_TABLE_FORMULA },
131 { XML_NAMESPACE_OFFICE, XML_VALUE, XML_TOK_TABLE_VALUE },
132 { XML_NAMESPACE_OFFICE, XML_TIME_VALUE, XML_TOK_TABLE_TIME_VALUE },
133 { XML_NAMESPACE_OFFICE, XML_DATE_VALUE, XML_TOK_TABLE_DATE_VALUE },
134 { XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, XML_TOK_TABLE_BOOLEAN_VALUE },
135 { XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TOK_TABLE_PROTECTED },
136 { XML_NAMESPACE_TABLE, XML_PROTECT, XML_TOK_TABLE_PROTECTED }, // for backwards compatibility with SRC629 (and before)
137 { XML_NAMESPACE_OFFICE, XML_STRING_VALUE, XML_TOK_TABLE_STRING_VALUE },
138 { XML_NAMESPACE_OFFICE, XML_VALUE_TYPE, XML_TOK_TABLE_VALUE_TYPE },
139 XML_TOKEN_MAP_END
142 const SvXMLTokenMap& SwXMLImport::GetTableElemTokenMap()
144 if( !pTableElemTokenMap )
145 pTableElemTokenMap = new SvXMLTokenMap( aTableElemTokenMap );
147 return *pTableElemTokenMap;
150 const SvXMLTokenMap& SwXMLImport::GetTableCellAttrTokenMap()
152 if( !pTableCellAttrTokenMap )
153 pTableCellAttrTokenMap = new SvXMLTokenMap( aTableCellAttrTokenMap );
155 return *pTableCellAttrTokenMap;
158 // ---------------------------------------------------------------------
160 class SwXMLTableCell_Impl
162 OUString aStyleName;
164 OUString mXmlId;
165 OUString m_StringValue;
167 OUString sFormula; // cell formula; valid if length > 0
168 double dValue; // formula value
170 SvXMLImportContextRef xSubTable;
172 const SwStartNode *pStartNode;
173 sal_uInt32 nRowSpan;
174 sal_uInt32 nColSpan;
176 sal_Bool bProtected : 1;
177 sal_Bool bHasValue; // determines whether dValue attribute is valid
178 sal_Bool mbCovered;
179 bool m_bHasStringValue;
181 public:
183 SwXMLTableCell_Impl( sal_uInt32 nRSpan=1UL, sal_uInt32 nCSpan=1UL ) :
184 pStartNode( 0 ),
185 nRowSpan( nRSpan ),
186 nColSpan( nCSpan ),
187 bProtected( sal_False ),
188 mbCovered( sal_False )
189 , m_bHasStringValue(false)
192 inline void Set( const OUString& rStyleName,
193 sal_uInt32 nRSpan, sal_uInt32 nCSpan,
194 const SwStartNode *pStNd, SwXMLTableContext *pTable,
195 sal_Bool bProtect,
196 const OUString* pFormula,
197 sal_Bool bHasValue,
198 sal_Bool bCovered,
199 double dVal,
200 OUString const*const pStringValue,
201 OUString const& i_rXmlId);
203 bool IsUsed() const { return pStartNode!=0 ||
204 xSubTable.Is() || bProtected;}
206 sal_uInt32 GetRowSpan() const { return nRowSpan; }
207 void SetRowSpan( sal_uInt32 nSet ) { nRowSpan = nSet; }
208 sal_uInt32 GetColSpan() const { return nColSpan; }
209 const OUString& GetStyleName() const { return aStyleName; }
210 const OUString& GetFormula() const { return sFormula; }
211 double GetValue() const { return dValue; }
212 sal_Bool HasValue() const { return bHasValue; }
213 sal_Bool IsProtected() const { return bProtected; }
214 sal_Bool IsCovered() const { return mbCovered; }
215 bool HasStringValue() const { return m_bHasStringValue; }
216 OUString const* GetStringValue() const {
217 return (m_bHasStringValue) ? &m_StringValue : 0;
219 const OUString& GetXmlId() const { return mXmlId; }
221 const SwStartNode *GetStartNode() const { return pStartNode; }
222 inline void SetStartNode( const SwStartNode *pSttNd );
224 inline SwXMLTableContext *GetSubTable() const;
226 inline void Dispose();
229 inline void SwXMLTableCell_Impl::Set( const OUString& rStyleName,
230 sal_uInt32 nRSpan, sal_uInt32 nCSpan,
231 const SwStartNode *pStNd,
232 SwXMLTableContext *pTable,
233 sal_Bool bProtect,
234 const OUString* pFormula,
235 sal_Bool bHasVal,
236 sal_Bool bCov,
237 double dVal,
238 OUString const*const pStringValue,
239 OUString const& i_rXmlId )
241 aStyleName = rStyleName;
242 nRowSpan = nRSpan;
243 nColSpan = nCSpan;
244 pStartNode = pStNd;
245 xSubTable = pTable;
246 dValue = dVal;
247 bHasValue = bHasVal;
248 mbCovered = bCov;
249 if (pStringValue)
251 m_StringValue = *pStringValue;
253 m_bHasStringValue = (pStringValue != 0);
254 bProtected = bProtect;
256 if (!mbCovered) // ensure uniqueness
258 mXmlId = i_rXmlId;
261 // set formula, if valid
262 if (pFormula != NULL)
264 sFormula = *pFormula;
268 inline void SwXMLTableCell_Impl::SetStartNode( const SwStartNode *pSttNd )
270 pStartNode = pSttNd;
271 xSubTable = 0;
274 inline SwXMLTableContext *SwXMLTableCell_Impl::GetSubTable() const
276 return (SwXMLTableContext *)&xSubTable;
279 inline void SwXMLTableCell_Impl::Dispose()
281 if( xSubTable.Is() )
282 xSubTable = 0;
285 // ---------------------------------------------------------------------
287 typedef boost::ptr_vector<SwXMLTableCell_Impl> SwXMLTableCells_Impl;
289 class SwXMLTableRow_Impl
291 OUString aStyleName;
292 OUString aDfltCellStyleName;
293 OUString mXmlId;
295 SwXMLTableCells_Impl aCells;
297 sal_Bool bSplitable;
299 public:
301 SwXMLTableRow_Impl( const OUString& rStyleName, sal_uInt32 nCells,
302 const OUString *pDfltCellStyleName = 0,
303 const OUString& i_rXmlId = OUString() );
304 ~SwXMLTableRow_Impl() {}
306 inline const SwXMLTableCell_Impl *GetCell( sal_uInt32 nCol ) const;
307 inline SwXMLTableCell_Impl *GetCell( sal_uInt32 nCol );
309 inline void Set( const OUString& rStyleName,
310 const OUString& rDfltCellStyleName,
311 const OUString& i_rXmlId );
313 void Expand( sal_uInt32 nCells, sal_Bool bOneCell );
315 void SetSplitable( sal_Bool bSet ) { bSplitable = bSet; }
316 sal_Bool IsSplitable() const { return bSplitable; }
318 const OUString& GetStyleName() const { return aStyleName; }
319 const OUString& GetDefaultCellStyleName() const { return aDfltCellStyleName; }
320 const OUString& GetXmlId() const { return mXmlId; }
322 void Dispose();
325 SwXMLTableRow_Impl::SwXMLTableRow_Impl( const OUString& rStyleName,
326 sal_uInt32 nCells,
327 const OUString *pDfltCellStyleName,
328 const OUString& i_rXmlId ) :
329 aStyleName( rStyleName ),
330 mXmlId( i_rXmlId ),
331 bSplitable( sal_False )
333 if( pDfltCellStyleName )
334 aDfltCellStyleName = *pDfltCellStyleName;
335 OSL_ENSURE( nCells <= USHRT_MAX,
336 "SwXMLTableRow_Impl::SwXMLTableRow_Impl: too many cells" );
337 if( nCells > USHRT_MAX )
338 nCells = USHRT_MAX;
340 for( sal_uInt16 i=0U; i<nCells; i++ )
342 aCells.push_back( new SwXMLTableCell_Impl );
346 inline const SwXMLTableCell_Impl *SwXMLTableRow_Impl::GetCell( sal_uInt32 nCol ) const
348 OSL_ENSURE( nCol < USHRT_MAX,
349 "SwXMLTableRow_Impl::GetCell: column number is to big" );
350 // #i95726# - some fault tolerance
351 OSL_ENSURE( nCol < aCells.size(),
352 "SwXMLTableRow_Impl::GetCell: column number is out of bound" );
353 return nCol < aCells.size() ? &aCells[(sal_uInt16)nCol] : 0;
356 inline SwXMLTableCell_Impl *SwXMLTableRow_Impl::GetCell( sal_uInt32 nCol )
358 OSL_ENSURE( nCol < USHRT_MAX,
359 "SwXMLTableRow_Impl::GetCell: column number is to big" );
360 // #i95726# - some fault tolerance
361 OSL_ENSURE( nCol < aCells.size(),
362 "SwXMLTableRow_Impl::GetCell: column number is out of bound" );
363 return nCol < aCells.size() ? &aCells[(sal_uInt16)nCol] : 0;
366 void SwXMLTableRow_Impl::Expand( sal_uInt32 nCells, sal_Bool bOneCell )
368 OSL_ENSURE( nCells <= USHRT_MAX,
369 "SwXMLTableRow_Impl::Expand: too many cells" );
370 if( nCells > USHRT_MAX )
371 nCells = USHRT_MAX;
373 sal_uInt32 nColSpan = nCells - aCells.size();
374 for( sal_uInt16 i=aCells.size(); i<nCells; i++ )
376 aCells.push_back( new SwXMLTableCell_Impl( 1UL,
377 bOneCell ? nColSpan : 1UL ) );
378 nColSpan--;
381 OSL_ENSURE( nCells<=aCells.size(),
382 "SwXMLTableRow_Impl::Expand: wrong number of cells" );
385 inline void SwXMLTableRow_Impl::Set( const OUString& rStyleName,
386 const OUString& rDfltCellStyleName,
387 const OUString& i_rXmlId )
389 aStyleName = rStyleName;
390 aDfltCellStyleName = rDfltCellStyleName;
391 mXmlId = i_rXmlId;
394 void SwXMLTableRow_Impl::Dispose()
396 for( sal_uInt16 i=0; i < aCells.size(); i++ )
397 aCells[i].Dispose();
400 // ---------------------------------------------------------------------
402 class SwXMLTableCellContext_Impl : public SvXMLImportContext
404 OUString aStyleName;
405 OUString sFormula;
406 OUString sSaveParaDefault;
407 OUString mXmlId;
408 OUString m_StringValue;
410 SvXMLImportContextRef xMyTable;
412 double fValue;
413 sal_Bool bHasValue;
414 bool m_bHasStringValue;
415 bool m_bValueTypeIsString;
416 sal_Bool bProtect;
418 sal_uInt32 nRowSpan;
419 sal_uInt32 nColSpan;
420 sal_uInt32 nColRepeat;
422 sal_Bool bHasTextContent : 1;
423 sal_Bool bHasTableContent : 1;
425 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
427 sal_Bool HasContent() const { return bHasTextContent || bHasTableContent; }
428 inline void _InsertContent();
429 inline void InsertContent();
430 inline void InsertContentIfNotThere();
431 inline void InsertContent( SwXMLTableContext *pTable );
433 public:
435 SwXMLTableCellContext_Impl(
436 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
437 const Reference< xml::sax::XAttributeList > & xAttrList,
438 SwXMLTableContext *pTable );
440 virtual ~SwXMLTableCellContext_Impl();
442 virtual SvXMLImportContext *CreateChildContext(
443 sal_uInt16 nPrefix, const OUString& rLocalName,
444 const Reference< xml::sax::XAttributeList > & xAttrList );
445 virtual void EndElement();
447 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
450 SwXMLTableCellContext_Impl::SwXMLTableCellContext_Impl(
451 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
452 const Reference< xml::sax::XAttributeList > & xAttrList,
453 SwXMLTableContext *pTable ) :
454 SvXMLImportContext( rImport, nPrfx, rLName ),
455 sFormula(),
456 xMyTable( pTable ),
457 fValue( 0.0 ),
458 bHasValue( sal_False ),
459 m_bHasStringValue(false),
460 m_bValueTypeIsString(false),
461 bProtect( sal_False ),
462 nRowSpan( 1UL ),
463 nColSpan( 1UL ),
464 nColRepeat( 1UL ),
465 bHasTextContent( sal_False ),
466 bHasTableContent( sal_False )
468 sSaveParaDefault = GetImport().GetTextImport()->GetCellParaStyleDefault();
469 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
470 for( sal_Int16 i=0; i < nAttrCount; i++ )
472 const OUString& rAttrName = xAttrList->getNameByIndex( i );
474 OUString aLocalName;
475 sal_uInt16 nPrefix =
476 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
477 &aLocalName );
478 const OUString& rValue = xAttrList->getValueByIndex( i );
479 const SvXMLTokenMap& rTokenMap =
480 GetSwImport().GetTableCellAttrTokenMap();
481 switch( rTokenMap.Get( nPrefix, aLocalName ) )
483 case XML_TOK_TABLE_XMLID:
484 mXmlId = rValue;
485 break;
486 case XML_TOK_TABLE_STYLE_NAME:
487 aStyleName = rValue;
488 GetImport().GetTextImport()->SetCellParaStyleDefault(rValue);
489 break;
490 case XML_TOK_TABLE_NUM_COLS_SPANNED:
491 nColSpan = (sal_uInt32)rValue.toInt32();
492 if( nColSpan < 1UL )
493 nColSpan = 1UL;
494 break;
495 case XML_TOK_TABLE_NUM_ROWS_SPANNED:
496 nRowSpan = (sal_uInt32)rValue.toInt32();
497 if( nRowSpan < 1UL )
498 nRowSpan = 1UL;
499 break;
500 case XML_TOK_TABLE_NUM_COLS_REPEATED:
501 nColRepeat = (sal_uInt32)rValue.toInt32();
502 if( nColRepeat < 1UL )
503 nColRepeat = 1UL;
504 break;
505 case XML_TOK_TABLE_FORMULA:
507 OUString sTmp;
508 sal_uInt16 nPrefix2 = GetImport().GetNamespaceMap().
509 _GetKeyByAttrName( rValue, &sTmp, sal_False );
510 sFormula = XML_NAMESPACE_OOOW == nPrefix2 ? sTmp : rValue;
512 break;
513 case XML_TOK_TABLE_VALUE:
515 double fTmp;
516 if (::sax::Converter::convertDouble(fTmp, rValue))
518 fValue = fTmp;
519 bHasValue = sal_True;
522 break;
523 case XML_TOK_TABLE_TIME_VALUE:
525 double fTmp;
526 if (::sax::Converter::convertDuration(fTmp, rValue))
528 fValue = fTmp;
529 bHasValue = sal_True;
532 break;
533 case XML_TOK_TABLE_DATE_VALUE:
535 double fTmp;
536 if (GetImport().GetMM100UnitConverter().convertDateTime(fTmp,
537 rValue))
539 fValue = fTmp;
540 bHasValue = sal_True;
543 break;
544 case XML_TOK_TABLE_BOOLEAN_VALUE:
546 bool bTmp(false);
547 if (::sax::Converter::convertBool(bTmp, rValue))
549 fValue = (bTmp ? 1.0 : 0.0);
550 bHasValue = sal_True;
553 break;
554 case XML_TOK_TABLE_PROTECTED:
556 bool bTmp(false);
557 if (::sax::Converter::convertBool(bTmp, rValue))
559 bProtect = bTmp;
562 break;
563 case XML_TOK_TABLE_STRING_VALUE:
565 m_StringValue = rValue;
566 m_bHasStringValue = true;
568 break;
569 case XML_TOK_TABLE_VALUE_TYPE:
571 if ("string" == rValue)
573 m_bValueTypeIsString = true;
575 // ignore other types - it would be correct to require
576 // matching value-type and $type-value attributes,
577 // but we've been reading those without checking forever.
579 break;
584 SwXMLTableCellContext_Impl::~SwXMLTableCellContext_Impl()
588 inline void SwXMLTableCellContext_Impl::_InsertContent()
590 SwStartNode const*const pStartNode( GetTable()->InsertTableSection(0,
591 (m_bHasStringValue && m_bValueTypeIsString &&
592 !aStyleName.isEmpty()) ? & aStyleName : 0) );
593 GetTable()->InsertCell( aStyleName, nRowSpan, nColSpan,
594 pStartNode,
595 mXmlId,
596 NULL, bProtect, &sFormula, bHasValue, fValue,
597 (m_bHasStringValue && m_bValueTypeIsString) ? &m_StringValue : 0);
600 inline void SwXMLTableCellContext_Impl::InsertContent()
602 OSL_ENSURE( !HasContent(), "content already there" );
603 bHasTextContent = sal_True;
604 _InsertContent();
607 inline void SwXMLTableCellContext_Impl::InsertContentIfNotThere()
609 if( !HasContent() )
610 InsertContent();
613 inline void SwXMLTableCellContext_Impl::InsertContent(
614 SwXMLTableContext *pTable )
616 GetTable()->InsertCell( aStyleName, nRowSpan, nColSpan, 0, mXmlId, pTable, bProtect );
617 bHasTableContent = sal_True;
620 SvXMLImportContext *SwXMLTableCellContext_Impl::CreateChildContext(
621 sal_uInt16 nPrefix,
622 const OUString& rLocalName,
623 const Reference< xml::sax::XAttributeList > & xAttrList )
625 SvXMLImportContext *pContext = 0;
627 OUString sXmlId;
628 sal_Bool bSubTable = sal_False;
629 if( XML_NAMESPACE_TABLE == nPrefix &&
630 IsXMLToken( rLocalName, XML_TABLE ) )
632 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
633 for( sal_Int16 i=0; i < nAttrCount; i++ )
635 const OUString& rAttrName = xAttrList->getNameByIndex( i );
637 OUString aLocalName;
638 sal_uInt16 nPrefix2 =
639 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
640 &aLocalName );
641 if( XML_NAMESPACE_TABLE == nPrefix2 &&
642 IsXMLToken( aLocalName, XML_IS_SUB_TABLE ) &&
643 IsXMLToken( xAttrList->getValueByIndex( i ), XML_TRUE ) )
645 bSubTable = sal_True;
647 else if ( (XML_NAMESPACE_XML == nPrefix2) &&
648 IsXMLToken( aLocalName, XML_ID ) )
650 sXmlId = xAttrList->getValueByIndex( i );
652 //FIXME: RDFa
656 if( bSubTable )
658 if( !HasContent() )
660 SwXMLTableContext *pTblContext =
661 new SwXMLTableContext( GetSwImport(), nPrefix, rLocalName,
662 xAttrList, GetTable(), sXmlId );
663 pContext = pTblContext;
664 if( GetTable()->IsValid() )
665 InsertContent( pTblContext );
667 GetTable()->SetHasSubTables( true );
670 else
672 if( GetTable()->IsValid() )
673 InsertContentIfNotThere();
674 // fdo#60842: "office:string-value" overrides text content -> no import
675 if (!(m_bValueTypeIsString && m_bHasStringValue))
677 pContext = GetImport().GetTextImport()->CreateTextChildContext(
678 GetImport(), nPrefix, rLocalName, xAttrList,
679 XML_TEXT_TYPE_CELL );
683 if( !pContext )
684 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
686 return pContext;
689 void SwXMLTableCellContext_Impl::EndElement()
691 if( GetTable()->IsValid() )
693 if( bHasTextContent )
695 GetImport().GetTextImport()->DeleteParagraph();
696 if( nColRepeat > 1 && nColSpan == 1 )
698 // The original text is invalid after deleting the last
699 // paragraph
700 Reference < XTextCursor > xSrcTxtCursor =
701 GetImport().GetTextImport()->GetText()->createTextCursor();
702 xSrcTxtCursor->gotoEnd( sal_True );
704 // Until we have an API for copying we have to use the core.
705 Reference<XUnoTunnel> xSrcCrsrTunnel( xSrcTxtCursor, UNO_QUERY);
706 OSL_ENSURE( xSrcCrsrTunnel.is(), "missing XUnoTunnel for Cursor" );
707 OTextCursorHelper *pSrcTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
708 sal::static_int_cast< sal_IntPtr >( xSrcCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )));
709 OSL_ENSURE( pSrcTxtCrsr, "SwXTextCursor missing" );
710 SwDoc *pDoc = pSrcTxtCrsr->GetDoc();
711 const SwPaM *pSrcPaM = pSrcTxtCrsr->GetPaM();
713 while( nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
715 _InsertContent();
717 Reference<XUnoTunnel> xDstCrsrTunnel(
718 GetImport().GetTextImport()->GetCursor(), UNO_QUERY);
719 OSL_ENSURE( xDstCrsrTunnel.is(),
720 "missing XUnoTunnel for Cursor" );
721 OTextCursorHelper *pDstTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
722 sal::static_int_cast< sal_IntPtr >( xDstCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )) );
723 OSL_ENSURE( pDstTxtCrsr, "SwXTextCursor missing" );
724 SwPaM aSrcPaM( *pSrcPaM->GetPoint(),
725 *pSrcPaM->GetMark() );
726 SwPosition aDstPos( *pDstTxtCrsr->GetPaM()->GetPoint() );
727 pDoc->CopyRange( aSrcPaM, aDstPos, false );
729 nColRepeat--;
733 else if( !bHasTableContent )
735 InsertContent();
736 if( nColRepeat > 1 && nColSpan == 1 )
738 while( nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
740 _InsertContent();
741 nColRepeat--;
746 GetImport().GetTextImport()->SetCellParaStyleDefault(sSaveParaDefault);
749 // ---------------------------------------------------------------------
751 class SwXMLTableColContext_Impl : public SvXMLImportContext
753 SvXMLImportContextRef xMyTable;
755 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
757 public:
759 SwXMLTableColContext_Impl(
760 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
761 const Reference< xml::sax::XAttributeList > & xAttrList,
762 SwXMLTableContext *pTable );
764 virtual ~SwXMLTableColContext_Impl();
766 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
769 SwXMLTableColContext_Impl::SwXMLTableColContext_Impl(
770 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
771 const Reference< xml::sax::XAttributeList > & xAttrList,
772 SwXMLTableContext *pTable ) :
773 SvXMLImportContext( rImport, nPrfx, rLName ),
774 xMyTable( pTable )
776 sal_uInt32 nColRep = 1UL;
777 OUString aStyleName, aDfltCellStyleName;
779 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
780 for( sal_Int16 i=0; i < nAttrCount; i++ )
782 const OUString& rAttrName = xAttrList->getNameByIndex( i );
784 OUString aLocalName;
785 sal_uInt16 nPrefix =
786 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
787 &aLocalName );
788 const OUString& rValue = xAttrList->getValueByIndex( i );
789 if( XML_NAMESPACE_TABLE == nPrefix )
791 if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
792 aStyleName = rValue;
793 else if( IsXMLToken( aLocalName, XML_NUMBER_COLUMNS_REPEATED ) )
794 nColRep = (sal_uInt32)rValue.toInt32();
795 else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
796 aDfltCellStyleName = rValue;
798 else if ( (XML_NAMESPACE_XML == nPrefix) &&
799 IsXMLToken( aLocalName, XML_ID ) )
801 (void) rValue;
802 //FIXME where to put this??? columns do not actually exist in writer...
806 sal_Int32 nWidth = MINLAY;
807 bool bRelWidth = true;
808 if( !aStyleName.isEmpty() )
810 const SfxPoolItem *pItem;
811 const SfxItemSet *pAutoItemSet = 0;
812 if( GetSwImport().FindAutomaticStyle(
813 XML_STYLE_FAMILY_TABLE_COLUMN,
814 aStyleName, &pAutoItemSet ) &&
815 pAutoItemSet &&
816 SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_FRM_SIZE, sal_False,
817 &pItem ) )
819 const SwFmtFrmSize *pSize = ((const SwFmtFrmSize *)pItem);
820 nWidth = pSize->GetWidth();
821 bRelWidth = ATT_VAR_SIZE == pSize->GetHeightSizeType();
825 if( nWidth )
827 while( nColRep-- && GetTable()->IsInsertColPossible() )
828 GetTable()->InsertColumn( nWidth, bRelWidth, &aDfltCellStyleName );
832 SwXMLTableColContext_Impl::~SwXMLTableColContext_Impl()
836 // ---------------------------------------------------------------------
838 class SwXMLTableColsContext_Impl : public SvXMLImportContext
840 SvXMLImportContextRef xMyTable;
842 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
844 public:
846 SwXMLTableColsContext_Impl(
847 SwXMLImport& rImport, sal_uInt16 nPrfx,
848 const OUString& rLName,
849 const Reference< xml::sax::XAttributeList > & xAttrList,
850 SwXMLTableContext *pTable );
852 virtual ~SwXMLTableColsContext_Impl();
854 virtual SvXMLImportContext *CreateChildContext(
855 sal_uInt16 nPrefix, const OUString& rLocalName,
856 const Reference< xml::sax::XAttributeList > & xAttrList );
858 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
861 SwXMLTableColsContext_Impl::SwXMLTableColsContext_Impl(
862 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
863 const Reference< xml::sax::XAttributeList > &,
864 SwXMLTableContext *pTable ) :
865 SvXMLImportContext( rImport, nPrfx, rLName ),
866 xMyTable( pTable )
870 SwXMLTableColsContext_Impl::~SwXMLTableColsContext_Impl()
874 SvXMLImportContext *SwXMLTableColsContext_Impl::CreateChildContext(
875 sal_uInt16 nPrefix,
876 const OUString& rLocalName,
877 const Reference< xml::sax::XAttributeList > & xAttrList )
879 SvXMLImportContext *pContext = 0;
881 if( XML_NAMESPACE_TABLE == nPrefix &&
882 IsXMLToken( rLocalName, XML_TABLE_COLUMN ) &&
883 GetTable()->IsInsertColPossible() )
884 pContext = new SwXMLTableColContext_Impl( GetSwImport(), nPrefix,
885 rLocalName, xAttrList,
886 GetTable() );
888 if( !pContext )
889 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
891 return pContext;
894 // ---------------------------------------------------------------------
896 class SwXMLTableRowContext_Impl : public SvXMLImportContext
898 SvXMLImportContextRef xMyTable;
900 sal_uInt32 nRowRepeat;
902 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
904 public:
906 SwXMLTableRowContext_Impl(
907 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
908 const Reference< xml::sax::XAttributeList > & xAttrList,
909 SwXMLTableContext *pTable, sal_Bool bInHead=sal_False );
911 virtual ~SwXMLTableRowContext_Impl();
913 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
914 const OUString& rLocalName,
915 const Reference< xml::sax::XAttributeList > & xAttrList );
917 virtual void EndElement();
919 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
922 SwXMLTableRowContext_Impl::SwXMLTableRowContext_Impl( SwXMLImport& rImport,
923 sal_uInt16 nPrfx,
924 const OUString& rLName,
925 const Reference< xml::sax::XAttributeList > & xAttrList,
926 SwXMLTableContext *pTable,
927 sal_Bool bInHead ) :
928 SvXMLImportContext( rImport, nPrfx, rLName ),
929 xMyTable( pTable ),
930 nRowRepeat( 1 )
932 OUString aStyleName, aDfltCellStyleName;
933 OUString sXmlId;
935 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
936 for( sal_Int16 i=0; i < nAttrCount; i++ )
938 const OUString& rAttrName = xAttrList->getNameByIndex( i );
940 OUString aLocalName;
941 sal_uInt16 nPrefix =
942 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
943 &aLocalName );
944 const OUString& rValue = xAttrList->getValueByIndex( i );
945 if( XML_NAMESPACE_TABLE == nPrefix )
947 if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
949 aStyleName = rValue;
951 else if( IsXMLToken( aLocalName, XML_NUMBER_ROWS_REPEATED ) )
953 nRowRepeat = (sal_uInt32)rValue.toInt32();
954 if( nRowRepeat < 1UL )
955 nRowRepeat = 1UL;
957 else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
959 aDfltCellStyleName = rValue;
962 else if ( (XML_NAMESPACE_XML == nPrefix) &&
963 IsXMLToken( aLocalName, XML_ID ) )
965 sXmlId = rValue;
968 if( GetTable()->IsValid() )
969 GetTable()->InsertRow( aStyleName, aDfltCellStyleName, bInHead,
970 sXmlId );
973 void SwXMLTableRowContext_Impl::EndElement()
975 if( GetTable()->IsValid() )
977 GetTable()->FinishRow();
979 if( nRowRepeat > 1UL )
980 GetTable()->InsertRepRows( nRowRepeat );
984 SwXMLTableRowContext_Impl::~SwXMLTableRowContext_Impl()
988 SvXMLImportContext *SwXMLTableRowContext_Impl::CreateChildContext(
989 sal_uInt16 nPrefix, const OUString& rLocalName,
990 const Reference< xml::sax::XAttributeList > & xAttrList )
992 SvXMLImportContext *pContext = 0;
994 if( XML_NAMESPACE_TABLE == nPrefix )
996 if( IsXMLToken( rLocalName, XML_TABLE_CELL ) )
998 if( !GetTable()->IsValid() || GetTable()->IsInsertCellPossible() )
999 pContext = new SwXMLTableCellContext_Impl( GetSwImport(),
1000 nPrefix,
1001 rLocalName,
1002 xAttrList,
1003 GetTable() );
1005 else if( IsXMLToken( rLocalName, XML_COVERED_TABLE_CELL ) )
1006 pContext = new SvXMLImportContext( GetImport(), nPrefix,
1007 rLocalName );
1010 if( !pContext )
1011 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1013 return pContext;
1016 // ---------------------------------------------------------------------
1018 class SwXMLTableRowsContext_Impl : public SvXMLImportContext
1020 SvXMLImportContextRef xMyTable;
1022 sal_Bool bHeader;
1024 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
1026 public:
1028 SwXMLTableRowsContext_Impl( SwXMLImport& rImport, sal_uInt16 nPrfx,
1029 const OUString& rLName,
1030 const Reference< xml::sax::XAttributeList > & xAttrList,
1031 SwXMLTableContext *pTable,
1032 sal_Bool bHead );
1034 virtual ~SwXMLTableRowsContext_Impl();
1036 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
1037 const OUString& rLocalName,
1038 const Reference< xml::sax::XAttributeList > & xAttrList );
1040 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
1043 SwXMLTableRowsContext_Impl::SwXMLTableRowsContext_Impl( SwXMLImport& rImport,
1044 sal_uInt16 nPrfx,
1045 const OUString& rLName,
1046 const Reference< xml::sax::XAttributeList > &,
1047 SwXMLTableContext *pTable,
1048 sal_Bool bHead ) :
1049 SvXMLImportContext( rImport, nPrfx, rLName ),
1050 xMyTable( pTable ),
1051 bHeader( bHead )
1055 SwXMLTableRowsContext_Impl::~SwXMLTableRowsContext_Impl()
1059 SvXMLImportContext *SwXMLTableRowsContext_Impl::CreateChildContext(
1060 sal_uInt16 nPrefix,
1061 const OUString& rLocalName,
1062 const Reference< xml::sax::XAttributeList > & xAttrList )
1064 SvXMLImportContext *pContext = 0;
1066 if( XML_NAMESPACE_TABLE == nPrefix &&
1067 IsXMLToken( rLocalName, XML_TABLE_ROW ) &&
1068 GetTable()->IsInsertRowPossible() )
1069 pContext = new SwXMLTableRowContext_Impl( GetSwImport(), nPrefix,
1070 rLocalName, xAttrList,
1071 GetTable(),
1072 bHeader );
1074 if( !pContext )
1075 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1077 return pContext;
1080 // ---------------------------------------------------------------------
1082 class SwXMLDDETableContext_Impl : public SvXMLImportContext
1084 OUString sConnectionName;
1085 OUString sDDEApplication;
1086 OUString sDDEItem;
1087 OUString sDDETopic;
1088 sal_Bool bIsAutomaticUpdate;
1090 public:
1092 TYPEINFO();
1094 SwXMLDDETableContext_Impl(
1095 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName);
1097 ~SwXMLDDETableContext_Impl();
1099 virtual void StartElement(
1100 const Reference<xml::sax::XAttributeList> & xAttrList);
1102 OUString& GetConnectionName() { return sConnectionName; }
1103 OUString& GetDDEApplication() { return sDDEApplication; }
1104 OUString& GetDDEItem() { return sDDEItem; }
1105 OUString& GetDDETopic() { return sDDETopic; }
1106 sal_Bool GetIsAutomaticUpdate() { return bIsAutomaticUpdate; }
1109 TYPEINIT1( SwXMLDDETableContext_Impl, SvXMLImportContext );
1111 SwXMLDDETableContext_Impl::SwXMLDDETableContext_Impl(
1112 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName) :
1113 SvXMLImportContext(rImport, nPrfx, rLName),
1114 sConnectionName(),
1115 sDDEApplication(),
1116 sDDEItem(),
1117 sDDETopic(),
1118 bIsAutomaticUpdate(sal_False)
1122 SwXMLDDETableContext_Impl::~SwXMLDDETableContext_Impl()
1126 void SwXMLDDETableContext_Impl::StartElement(
1127 const Reference<xml::sax::XAttributeList> & xAttrList)
1129 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
1130 for( sal_Int16 i = 0; i < nAttrCount; i++ )
1132 const OUString& rAttrName = xAttrList->getNameByIndex( i );
1134 OUString aLocalName;
1135 sal_uInt16 nPrefix =
1136 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
1137 &aLocalName );
1138 const OUString& rValue = xAttrList->getValueByIndex( i );
1140 if (XML_NAMESPACE_OFFICE == nPrefix)
1142 if ( IsXMLToken( aLocalName, XML_DDE_APPLICATION ) )
1144 sDDEApplication = rValue;
1146 else if ( IsXMLToken( aLocalName, XML_DDE_TOPIC ) )
1148 sDDETopic = rValue;
1150 else if ( IsXMLToken( aLocalName, XML_DDE_ITEM ) )
1152 sDDEItem = rValue;
1154 else if ( IsXMLToken( aLocalName, XML_NAME ) )
1156 sConnectionName = rValue;
1158 else if ( IsXMLToken( aLocalName, XML_AUTOMATIC_UPDATE ) )
1160 bool bTmp(false);
1161 if (::sax::Converter::convertBool(bTmp, rValue))
1163 bIsAutomaticUpdate = bTmp;
1166 // else: unknown attribute
1168 // else: unknown attribute namespace
1172 // generate a new name for DDE field type (called by lcl_GetDDEFieldType below)
1173 static String lcl_GenerateFldTypeName(OUString sPrefix, SwTableNode* pTableNode)
1175 String sPrefixStr(sPrefix);
1177 if (sPrefixStr.Len() == 0)
1179 sPrefixStr = OUString('_');
1182 // increase count until we find a name that is not yet taken
1183 String sName;
1184 sal_Int32 nCount = 0;
1187 // this is crazy, but just in case all names are taken: exit gracefully
1188 if (nCount < 0)
1189 return sName;
1191 nCount++;
1192 sName = sPrefixStr;
1193 sName += OUString::number(nCount);
1196 while (NULL != pTableNode->GetDoc()->GetFldType(RES_DDEFLD, sName, false));
1198 return sName;
1201 // set table properties
1202 static SwDDEFieldType* lcl_GetDDEFieldType(SwXMLDDETableContext_Impl* pContext,
1203 SwTableNode* pTableNode)
1205 // make command string
1206 String sCommand(pContext->GetDDEApplication());
1207 sCommand += sfx2::cTokenSeparator;
1208 sCommand += String(pContext->GetDDEItem());
1209 sCommand += sfx2::cTokenSeparator;
1210 sCommand += String(pContext->GetDDETopic());
1212 sal_uInt16 nType = static_cast< sal_uInt16 >(pContext->GetIsAutomaticUpdate() ? sfx2::LINKUPDATE_ALWAYS
1213 : sfx2::LINKUPDATE_ONCALL);
1215 String sName(pContext->GetConnectionName());
1217 // field type to be returned
1218 SwDDEFieldType* pType = NULL;
1220 // valid name?
1221 if (sName.Len() == 0)
1223 sName = lcl_GenerateFldTypeName(pContext->GetDDEApplication(),
1224 pTableNode);
1226 else
1228 // check for existing DDE field type with the same name
1229 SwDDEFieldType* pOldType = (SwDDEFieldType*)pTableNode->GetDoc()->GetFldType(RES_DDEFLD, sName, false);
1230 if (NULL != pOldType)
1232 // same values -> return old type
1233 if ( (pOldType->GetCmd() == sCommand) &&
1234 (pOldType->GetType() == nType) )
1236 // same name, same values -> return old type!
1237 pType = pOldType;
1239 else
1241 // same name, different values -> think of new name
1242 sName = lcl_GenerateFldTypeName(pContext->GetDDEApplication(),
1243 pTableNode);
1246 // no old type -> create new one
1249 // create new field type (unless we already have one)
1250 if (NULL == pType)
1252 // create new field type and return
1253 SwDDEFieldType aDDEFieldType(sName, sCommand, nType);
1254 pType = (SwDDEFieldType*)pTableNode->
1255 GetDoc()->InsertFldType(aDDEFieldType);
1258 OSL_ENSURE(NULL != pType, "We really want a SwDDEFieldType here!");
1259 return pType;
1263 // ---------------------------------------------------------------------
1265 class TableBoxIndex
1267 public:
1268 OUString msName;
1269 sal_Int32 mnWidth;
1270 sal_Bool mbProtected;
1272 TableBoxIndex( const OUString& rName, sal_Int32 nWidth,
1273 sal_Bool bProtected ) :
1274 msName( rName ),
1275 mnWidth( nWidth ),
1276 mbProtected( bProtected )
1279 bool operator== ( const TableBoxIndex& rArg ) const
1281 return (rArg.mnWidth == mnWidth) &&
1282 (rArg.mbProtected == mbProtected) &&
1283 (rArg.msName == msName);
1287 class TableBoxIndexHasher
1289 public:
1290 size_t operator() (const TableBoxIndex& rArg) const
1292 return rArg.msName.hashCode() + rArg.mnWidth + rArg.mbProtected;
1299 typedef boost::ptr_vector<SwXMLTableRow_Impl> SwXMLTableRows_Impl;
1301 const SwXMLTableCell_Impl *SwXMLTableContext::GetCell( sal_uInt32 nRow,
1302 sal_uInt32 nCol ) const
1304 return (*pRows)[(sal_uInt16)nRow].GetCell( (sal_uInt16)nCol );
1307 SwXMLTableCell_Impl *SwXMLTableContext::GetCell( sal_uInt32 nRow,
1308 sal_uInt32 nCol )
1310 return (*pRows)[(sal_uInt16)nRow].GetCell( (sal_uInt16)nCol );
1313 TYPEINIT1( SwXMLTableContext, XMLTextTableContext );
1315 SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
1316 sal_uInt16 nPrfx,
1317 const OUString& rLName,
1318 const Reference< xml::sax::XAttributeList > & xAttrList ) :
1319 XMLTextTableContext( rImport, nPrfx, rLName ),
1320 pColumnDefaultCellStyleNames( 0 ),
1321 pRows( new SwXMLTableRows_Impl ),
1322 pTableNode( 0 ),
1323 pBox1( 0 ),
1324 pSttNd1( 0 ),
1325 pBoxFmt( 0 ),
1326 pLineFmt( 0 ),
1327 pSharedBoxFormats(NULL),
1328 pDDESource(NULL),
1329 bFirstSection( true ),
1330 bRelWidth( true ),
1331 bHasSubTables( false ),
1332 nHeaderRows( 0 ),
1333 nCurRow( 0UL ),
1334 nCurCol( 0UL ),
1335 nWidth( 0UL )
1337 OUString aName;
1338 OUString sXmlId;
1340 // this method will modify the document directly -> lock SolarMutex
1341 SolarMutexGuard aGuard;
1343 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
1344 for( sal_Int16 i=0; i < nAttrCount; i++ )
1346 const OUString& rAttrName = xAttrList->getNameByIndex( i );
1348 OUString aLocalName;
1349 sal_uInt16 nPrefix =
1350 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
1351 &aLocalName );
1352 const OUString& rValue = xAttrList->getValueByIndex( i );
1353 if( XML_NAMESPACE_TABLE == nPrefix )
1355 if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
1356 aStyleName = rValue;
1357 else if( IsXMLToken( aLocalName, XML_NAME ) )
1358 aName = rValue;
1359 else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
1360 aDfltCellStyleName = rValue;
1362 else if ( (XML_NAMESPACE_XML == nPrefix) &&
1363 IsXMLToken( aLocalName, XML_ID ) )
1365 sXmlId = rValue;
1369 SwDoc *pDoc = SwImport::GetDocFromXMLImport( GetSwImport() );
1371 String sTblName;
1372 if( !aName.isEmpty() )
1374 const SwTableFmt *pTblFmt = pDoc->FindTblFmtByName( aName );
1375 if( !pTblFmt )
1376 sTblName = aName;
1378 if( !sTblName.Len() )
1380 sTblName = pDoc->GetUniqueTblName();
1381 GetImport().GetTextImport()
1382 ->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_TABLE, aName, sTblName );
1385 Reference< XTextTable > xTable;
1386 const SwXTextTable *pXTable = 0;
1387 Reference<XMultiServiceFactory> xFactory( GetImport().GetModel(),
1388 UNO_QUERY );
1389 OSL_ENSURE( xFactory.is(), "factory missing" );
1390 if( xFactory.is() )
1392 OUString sService( "com.sun.star.text.TextTable" );
1393 Reference<XInterface> xIfc = xFactory->createInstance( sService );
1394 OSL_ENSURE( xIfc.is(), "Couldn't create a table" );
1396 if( xIfc.is() )
1397 xTable = Reference< XTextTable > ( xIfc, UNO_QUERY );
1400 if( xTable.is() )
1402 xTable->initialize( 1, 1 );
1406 xTextContent = Reference< XTextContent >( xTable, UNO_QUERY );
1407 GetImport().GetTextImport()->InsertTextContent( xTextContent );
1409 catch( IllegalArgumentException& )
1411 xTable = 0;
1415 if( xTable.is() )
1417 //FIXME
1418 // xml:id for RDF metadata
1419 GetImport().SetXmlId(xTable, sXmlId);
1421 Reference<XUnoTunnel> xTableTunnel( xTable, UNO_QUERY);
1422 if( xTableTunnel.is() )
1424 pXTable = reinterpret_cast< SwXTextTable * >(
1425 sal::static_int_cast< sal_IntPtr >( xTableTunnel->getSomething( SwXTextTable::getUnoTunnelId() )));
1426 OSL_ENSURE( pXTable, "SwXTextTable missing" );
1429 Reference < XCellRange > xCellRange( xTable, UNO_QUERY );
1430 Reference < XCell > xCell = xCellRange->getCellByPosition( 0, 0 );
1431 Reference < XText> xText( xCell, UNO_QUERY );
1432 xOldCursor = GetImport().GetTextImport()->GetCursor();
1433 GetImport().GetTextImport()->SetCursor( xText->createTextCursor() );
1435 // take care of open redlines for tables
1436 GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(sal_True);
1438 if( pXTable )
1440 SwFrmFmt *pTblFrmFmt = pXTable->GetFrmFmt();
1441 OSL_ENSURE( pTblFrmFmt, "table format missing" );
1442 SwTable *pTbl = SwTable::FindTable( pTblFrmFmt );
1443 OSL_ENSURE( pTbl, "table missing" );
1444 pTableNode = pTbl->GetTableNode();
1445 OSL_ENSURE( pTableNode, "table node missing" );
1447 pTblFrmFmt->SetName( sTblName );
1449 SwTableLine *pLine1 = pTableNode->GetTable().GetTabLines()[0U];
1450 pBox1 = pLine1->GetTabBoxes()[0U];
1451 pSttNd1 = pBox1->GetSttNd();
1455 SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
1456 sal_uInt16 nPrfx,
1457 const OUString& rLName,
1458 const Reference< xml::sax::XAttributeList > &,
1459 SwXMLTableContext *pTable,
1460 OUString const & i_rXmlId ) :
1461 XMLTextTableContext( rImport, nPrfx, rLName ),
1462 mXmlId( i_rXmlId ),
1463 pColumnDefaultCellStyleNames( 0 ),
1464 pRows( new SwXMLTableRows_Impl ),
1465 pTableNode( pTable->pTableNode ),
1466 pBox1( 0 ),
1467 pSttNd1( 0 ),
1468 pBoxFmt( 0 ),
1469 pLineFmt( 0 ),
1470 pSharedBoxFormats(NULL),
1471 xParentTable( pTable ),
1472 pDDESource(NULL),
1473 bFirstSection( false ),
1474 bRelWidth( true ),
1475 bHasSubTables( false ),
1476 nHeaderRows( 0 ),
1477 nCurRow( 0UL ),
1478 nCurCol( 0UL ),
1479 nWidth( 0UL )
1483 SwXMLTableContext::~SwXMLTableContext()
1485 delete pColumnDefaultCellStyleNames;
1486 delete pSharedBoxFormats;
1487 delete pRows;
1489 // close redlines on table end nodes
1490 GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(sal_False);
1493 SvXMLImportContext *SwXMLTableContext::CreateChildContext( sal_uInt16 nPrefix,
1494 const OUString& rLocalName,
1495 const Reference< xml::sax::XAttributeList > & xAttrList )
1497 SvXMLImportContext *pContext = 0;
1499 const SvXMLTokenMap& rTokenMap = GetSwImport().GetTableElemTokenMap();
1500 sal_Bool bHeader = sal_False;
1501 switch( rTokenMap.Get( nPrefix, rLocalName ) )
1503 case XML_TOK_TABLE_HEADER_COLS:
1504 case XML_TOK_TABLE_COLS:
1505 if( IsValid() )
1506 pContext = new SwXMLTableColsContext_Impl( GetSwImport(), nPrefix,
1507 rLocalName, xAttrList,
1508 this );
1509 break;
1510 case XML_TOK_TABLE_COL:
1511 if( IsValid() && IsInsertColPossible() )
1512 pContext = new SwXMLTableColContext_Impl( GetSwImport(), nPrefix,
1513 rLocalName, xAttrList,
1514 this );
1515 break;
1516 case XML_TOK_TABLE_HEADER_ROWS:
1517 bHeader = sal_True;
1518 case XML_TOK_TABLE_ROWS:
1519 pContext = new SwXMLTableRowsContext_Impl( GetSwImport(), nPrefix,
1520 rLocalName, xAttrList,
1521 this, bHeader );
1522 break;
1523 case XML_TOK_TABLE_ROW:
1524 if( IsInsertRowPossible() )
1525 pContext = new SwXMLTableRowContext_Impl( GetSwImport(), nPrefix,
1526 rLocalName, xAttrList,
1527 this );
1528 break;
1529 case XML_TOK_OFFICE_DDE_SOURCE:
1530 // save context for later processing (discard old context, if approp.)
1531 if( IsValid() )
1533 if (pDDESource != NULL)
1535 pDDESource->ReleaseRef();
1537 pDDESource = new SwXMLDDETableContext_Impl( GetSwImport(), nPrefix,
1538 rLocalName );
1539 pDDESource->AddRef();
1540 pContext = pDDESource;
1542 break;
1545 if( !pContext )
1546 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1548 return pContext;
1551 void SwXMLTableContext::InsertColumn( sal_Int32 nWidth2, bool bRelWidth2,
1552 const OUString *pDfltCellStyleName )
1554 OSL_ENSURE( nCurCol < USHRT_MAX,
1555 "SwXMLTableContext::InsertColumn: no space left" );
1556 if( nCurCol >= USHRT_MAX )
1557 return;
1559 if( nWidth2 < MINLAY )
1560 nWidth2 = MINLAY;
1561 else if( nWidth2 > USHRT_MAX )
1562 nWidth2 = USHRT_MAX;
1563 aColumnWidths.push_back( ColumnWidthInfo(nWidth2, bRelWidth2) );
1564 if( (pDfltCellStyleName && !pDfltCellStyleName->isEmpty()) ||
1565 pColumnDefaultCellStyleNames )
1567 if( !pColumnDefaultCellStyleNames )
1569 pColumnDefaultCellStyleNames = new std::vector<String>;
1570 sal_uLong nCount = aColumnWidths.size() - 1;
1571 while( nCount-- )
1572 pColumnDefaultCellStyleNames->push_back(String());
1575 if(pDfltCellStyleName)
1576 pColumnDefaultCellStyleNames->push_back(*pDfltCellStyleName);
1577 else
1578 pColumnDefaultCellStyleNames->push_back(String());
1582 sal_Int32 SwXMLTableContext::GetColumnWidth( sal_uInt32 nCol,
1583 sal_uInt32 nColSpan ) const
1585 sal_uInt32 nLast = nCol+nColSpan;
1586 if( nLast > aColumnWidths.size() )
1587 nLast = aColumnWidths.size();
1589 sal_Int32 nWidth2 = 0L;
1590 for( sal_uInt32 i=nCol; i < nLast; ++i )
1591 nWidth2 += aColumnWidths[i].width;
1593 return nWidth2;
1596 OUString SwXMLTableContext::GetColumnDefaultCellStyleName( sal_uInt32 nCol ) const
1598 if( pColumnDefaultCellStyleNames && nCol < pColumnDefaultCellStyleNames->size())
1599 return (*pColumnDefaultCellStyleNames)[static_cast<size_t>(nCol)];
1601 return OUString();
1604 void SwXMLTableContext::InsertCell( const OUString& rStyleName,
1605 sal_uInt32 nRowSpan, sal_uInt32 nColSpan,
1606 const SwStartNode *pStartNode,
1607 const OUString & i_rXmlId,
1608 SwXMLTableContext *pTable,
1609 sal_Bool bProtect,
1610 const OUString* pFormula,
1611 sal_Bool bHasValue,
1612 double fValue,
1613 OUString const*const pStringValue )
1615 OSL_ENSURE( nCurCol < GetColumnCount(),
1616 "SwXMLTableContext::InsertCell: row is full" );
1617 OSL_ENSURE( nCurRow < USHRT_MAX,
1618 "SwXMLTableContext::InsertCell: table is full" );
1619 if( nCurCol >= USHRT_MAX || nCurRow > USHRT_MAX )
1620 return;
1622 OSL_ENSURE( nRowSpan >=1UL, "SwXMLTableContext::InsertCell: row span is 0" );
1623 if( 0UL == nRowSpan )
1624 nRowSpan = 1UL;
1625 OSL_ENSURE( nColSpan >=1UL, "SwXMLTableContext::InsertCell: col span is 0" );
1626 if( 0UL == nColSpan )
1627 nColSpan = 1UL;
1629 sal_uInt32 i, j;
1631 // Until it is possible to add columns here, fix the column span.
1632 sal_uInt32 nColsReq = nCurCol + nColSpan;
1633 if( nColsReq > GetColumnCount() )
1635 nColSpan = GetColumnCount() - nCurCol;
1636 nColsReq = GetColumnCount();
1639 // Check whether there are cells from a previous line already that reach
1640 // into the current row.
1641 if( nCurRow > 0UL && nColSpan > 1UL )
1643 SwXMLTableRow_Impl *pCurRow = &(*pRows)[(sal_uInt16)nCurRow];
1644 sal_uInt32 nLastCol = GetColumnCount() < nColsReq ? GetColumnCount()
1645 : nColsReq;
1646 for( i=nCurCol+1UL; i<nLastCol; i++ )
1648 if( pCurRow->GetCell(i)->IsUsed() )
1650 // If this cell is used, the column span is truncated
1651 nColSpan = i - nCurCol;
1652 nColsReq = i;
1653 break;
1658 sal_uInt32 nRowsReq = nCurRow + nRowSpan;
1659 if( nRowsReq > USHRT_MAX )
1661 nRowSpan = USHRT_MAX - nCurRow;
1662 nRowsReq = USHRT_MAX;
1665 // Add columns (if # required columns greater than # columns):
1666 // This should never happen, since we require column definitions!
1667 if ( nColsReq > GetColumnCount() )
1669 for( i=GetColumnCount(); i<nColsReq; i++ )
1671 aColumnWidths.push_back( ColumnWidthInfo(MINLAY, sal_True) );
1673 // adjust columns in *all* rows, if columns must be inserted
1674 for( i=0; i<pRows->size(); i++ )
1675 (*pRows)[(sal_uInt16)i].Expand( nColsReq, i<nCurRow );
1678 // Add rows
1679 if( pRows->size() < nRowsReq )
1681 OUString aStyleName2;
1682 for( i = pRows->size(); i < nRowsReq; ++i )
1683 pRows->push_back( new SwXMLTableRow_Impl(aStyleName2, GetColumnCount()) );
1686 OUString sStyleName( rStyleName );
1687 if( sStyleName.isEmpty() )
1689 sStyleName = (*pRows)[(sal_uInt16)nCurRow].GetDefaultCellStyleName();
1690 if( sStyleName.isEmpty() && HasColumnDefaultCellStyleNames() )
1692 sStyleName = GetColumnDefaultCellStyleName( nCurCol );
1693 if( sStyleName.isEmpty() )
1694 sStyleName = aDfltCellStyleName;
1698 // Fill the cells
1699 for( i=nColSpan; i>0UL; i-- )
1701 for( j=nRowSpan; j>0UL; j-- )
1703 const bool bCovered = i != nColSpan || j != nRowSpan;
1704 GetCell( nRowsReq-j, nColsReq-i )
1705 ->Set( sStyleName, j, i, pStartNode,
1706 pTable, bProtect, pFormula, bHasValue, bCovered, fValue,
1707 pStringValue, i_rXmlId );
1711 // Set current col to the next (free) column
1712 nCurCol = nColsReq;
1713 while( nCurCol<GetColumnCount() && GetCell(nCurRow,nCurCol)->IsUsed() )
1714 nCurCol++;
1717 void SwXMLTableContext::InsertRow( const OUString& rStyleName,
1718 const OUString& rDfltCellStyleName,
1719 bool bInHead,
1720 const OUString & i_rXmlId )
1722 OSL_ENSURE( nCurRow < USHRT_MAX,
1723 "SwXMLTableContext::InsertRow: no space left" );
1724 if( nCurRow >= USHRT_MAX )
1725 return;
1727 // Make sure there is at least one column.
1728 if( 0==nCurRow && 0UL == GetColumnCount() )
1729 InsertColumn( USHRT_MAX, sal_True );
1731 if( nCurRow < pRows->size() )
1733 // The current row has already been inserted because of a row span
1734 // of a previous row.
1735 (*pRows)[(sal_uInt16)nCurRow].Set(
1736 rStyleName, rDfltCellStyleName, i_rXmlId );
1738 else
1740 // add a new row
1741 pRows->push_back( new SwXMLTableRow_Impl( rStyleName, GetColumnCount(),
1742 &rDfltCellStyleName, i_rXmlId ) );
1745 // We start at the first column ...
1746 nCurCol=0UL;
1748 // ... but this cell may be occupied already.
1749 while( nCurCol<GetColumnCount() && GetCell(nCurRow,nCurCol)->IsUsed() )
1750 nCurCol++;
1752 if( bInHead && nHeaderRows == nCurRow )
1753 nHeaderRows++;
1756 void SwXMLTableContext::InsertRepRows( sal_uInt32 nCount )
1758 const SwXMLTableRow_Impl *pSrcRow = &(*pRows)[(sal_uInt16)nCurRow-1];
1759 while( nCount > 1 && IsInsertRowPossible() )
1761 InsertRow( pSrcRow->GetStyleName(), pSrcRow->GetDefaultCellStyleName(),
1762 false );
1763 while( nCurCol < GetColumnCount() )
1765 if( !GetCell(nCurRow,nCurCol)->IsUsed() )
1767 const SwXMLTableCell_Impl *pSrcCell =
1768 GetCell( nCurRow-1, nCurCol );
1769 InsertCell( pSrcCell->GetStyleName(), 1U,
1770 pSrcCell->GetColSpan(),
1771 InsertTableSection(),
1772 OUString(),
1773 0, pSrcCell->IsProtected(),
1774 &pSrcCell->GetFormula(),
1775 pSrcCell->HasValue(), pSrcCell->GetValue(),
1776 pSrcCell->GetStringValue() );
1779 FinishRow();
1780 nCount--;
1784 void SwXMLTableContext::FinishRow()
1786 // Insert an empty cell at the end of the line if the row is not complete
1787 if( nCurCol < GetColumnCount() )
1789 OUString aStyleName2;
1790 InsertCell( aStyleName2, 1U, GetColumnCount() - nCurCol,
1791 InsertTableSection() );
1794 // Move to the next row.
1795 nCurRow++;
1798 const SwStartNode *SwXMLTableContext::GetPrevStartNode( sal_uInt32 nRow,
1799 sal_uInt32 nCol ) const
1801 const SwXMLTableCell_Impl *pPrevCell = 0;
1802 if( GetColumnCount() == nCol )
1804 // The last cell is the right one here.
1805 pPrevCell = GetCell( pRows->size()-1U, GetColumnCount()-1UL );
1807 else if( nCol > 0UL )
1809 // The previous cell in this row.
1810 pPrevCell = GetCell( nRow, nCol-1UL );
1812 else if( nRow > 0UL )
1814 // The last cell from the previous row.
1815 pPrevCell = GetCell( nRow-1UL, GetColumnCount()-1UL );
1818 const SwStartNode *pSttNd = 0;
1819 if( pPrevCell )
1821 if( pPrevCell->GetStartNode() )
1822 pSttNd = pPrevCell->GetStartNode();
1823 // #i95726# - Some fault tolerance
1824 // else
1825 else if ( pPrevCell->GetSubTable() )
1826 pSttNd = pPrevCell->GetSubTable()->GetLastStartNode();
1828 OSL_ENSURE( pSttNd != 0,
1829 "table corrupt" );
1832 return pSttNd;
1835 void SwXMLTableContext::FixRowSpan( sal_uInt32 nRow, sal_uInt32 nCol,
1836 sal_uInt32 nColSpan )
1838 sal_uInt32 nLastCol = nCol + nColSpan;
1839 for( sal_uInt16 i = (sal_uInt16)nCol; i < nLastCol; i++ )
1841 sal_uInt32 j = nRow;
1842 sal_uInt32 nRowSpan = 1UL;
1843 SwXMLTableCell_Impl *pCell = GetCell( j, i );
1844 while( pCell && pCell->GetRowSpan() > 1UL )
1846 pCell->SetRowSpan( nRowSpan++ );
1847 pCell = j > 0UL ? GetCell( --j, i ) : 0;
1852 void SwXMLTableContext::ReplaceWithEmptyCell( sal_uInt32 nRow, sal_uInt32 nCol, bool bRows )
1854 const SwStartNode *pPrevSttNd = GetPrevStartNode( nRow, nCol );
1855 const SwStartNode *pSttNd = InsertTableSection( pPrevSttNd );
1857 const SwXMLTableCell_Impl *pCell = GetCell( nRow, nCol );
1858 sal_uInt32 nLastRow = bRows ? nRow + pCell->GetRowSpan() : nRow + 1;
1859 sal_uInt32 nLastCol = nCol + pCell->GetColSpan();
1861 for( sal_uInt32 i=nRow; i<nLastRow; i++ )
1863 SwXMLTableRow_Impl *pRow = &(*pRows)[(sal_uInt16)i];
1864 for( sal_uInt32 j=nCol; j<nLastCol; j++ )
1865 pRow->GetCell( j )->SetStartNode( pSttNd );
1870 SwTableBox *SwXMLTableContext::NewTableBox( const SwStartNode *pStNd,
1871 SwTableLine *pUpper )
1873 // The topmost table is the only table that maintains the two members
1874 // pBox1 and bFirstSection.
1875 if( xParentTable.Is() )
1876 return ((SwXMLTableContext *)&xParentTable)->NewTableBox( pStNd,
1877 pUpper );
1879 SwTableBox *pBox;
1881 if( pBox1 &&
1882 pBox1->GetSttNd() == pStNd )
1884 // if the StartNode is equal to the StartNode of the initially
1885 // created box, we use this box
1886 pBox = pBox1;
1887 pBox->SetUpper( pUpper );
1888 pBox1 = 0;
1890 else
1891 pBox = new SwTableBox( pBoxFmt, *pStNd, pUpper );
1893 return pBox;
1896 SwTableBoxFmt* SwXMLTableContext::GetSharedBoxFormat(
1897 SwTableBox* pBox,
1898 const OUString& rStyleName,
1899 sal_Int32 nColumnWidth,
1900 sal_Bool bProtected,
1901 sal_Bool bMayShare,
1902 sal_Bool& bNew,
1903 bool* pModifyLocked )
1905 if ( pSharedBoxFormats == NULL )
1906 pSharedBoxFormats = new map_BoxFmt();
1908 SwTableBoxFmt* pBoxFmt2;
1910 TableBoxIndex aKey( rStyleName, nColumnWidth, bProtected );
1911 map_BoxFmt::iterator aIter = pSharedBoxFormats->find( aKey );
1912 if ( aIter == pSharedBoxFormats->end() )
1914 // unknown format so far -> construct a new one
1916 // get the old format, and reset all attributes
1917 // (but preserve FillOrder)
1918 pBoxFmt2 = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
1919 SwFmtFillOrder aFillOrder( pBoxFmt2->GetFillOrder() );
1920 pBoxFmt2->ResetAllFmtAttr(); // #i73790# - method renamed
1921 pBoxFmt2->SetFmtAttr( aFillOrder );
1922 bNew = sal_True; // it's a new format now
1924 // share this format, if allowed
1925 if ( bMayShare )
1926 (*pSharedBoxFormats)[ aKey ] = pBoxFmt2;
1928 else
1930 // set the shared format
1931 pBoxFmt2 = aIter->second;
1932 pBox->ChgFrmFmt( pBoxFmt2 );
1933 bNew = sal_False; // copied from an existing format
1935 // claim it, if we are not allowed to share
1936 if ( !bMayShare )
1937 pBoxFmt2 = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
1940 // lock format (if so desired)
1941 if ( pModifyLocked != NULL )
1943 (*pModifyLocked) = pBoxFmt2->IsModifyLocked();
1944 pBoxFmt2->LockModify();
1947 return pBoxFmt2;
1950 SwTableBox *SwXMLTableContext::MakeTableBox( SwTableLine *pUpper,
1951 sal_uInt32 nTopRow,
1952 sal_uInt32 nLeftCol,
1953 sal_uInt32 nBottomRow,
1954 sal_uInt32 nRightCol )
1956 //FIXME: here would be a great place to handle XmlId for cell
1957 SwTableBox *pBox = new SwTableBox( pBoxFmt, 0, pUpper );
1959 sal_uInt32 nColSpan = nRightCol - nLeftCol;
1960 sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
1962 // TODO: Share formats!
1963 SwFrmFmt *pFrmFmt = pBox->ClaimFrmFmt();
1964 SwFmtFillOrder aFillOrder( pFrmFmt->GetFillOrder() );
1965 pFrmFmt->ResetAllFmtAttr(); // #i73790# - method renamed
1966 pFrmFmt->SetFmtAttr( aFillOrder );
1968 pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nColWidth ) );
1970 SwTableLines& rLines = pBox->GetTabLines();
1971 bool bSplitted = false;
1973 while( !bSplitted )
1975 sal_uInt32 nStartRow = nTopRow;
1976 sal_uInt32 i;
1978 for( i = nTopRow; i < nBottomRow; i++ )
1980 // Could the table be splitted behind the current row?
1981 sal_Bool bSplit = sal_True;
1982 SwXMLTableRow_Impl *pRow = &(*pRows)[(sal_uInt16)i];
1983 for( sal_uInt32 j=nLeftCol; j<nRightCol; j++ )
1985 bSplit = ( 1UL == pRow->GetCell(j)->GetRowSpan() );
1986 if( !bSplit )
1987 break;
1989 if( bSplit && (nStartRow>nTopRow || i+1UL<nBottomRow) )
1991 SwTableLine *pLine =
1992 MakeTableLine( pBox, nStartRow, nLeftCol, i+1UL,
1993 nRightCol );
1995 rLines.push_back( pLine );
1997 nStartRow = i+1UL;
1998 bSplitted = true;
2001 if( !bSplitted )
2003 // No splitting was possible. That for, we have to force it.
2004 // Ruthless!
2006 nStartRow = nTopRow;
2007 while( nStartRow < nBottomRow )
2009 sal_uInt32 nMaxRowSpan = 0UL;
2010 SwXMLTableRow_Impl *pStartRow = &(*pRows)[(sal_uInt16)nStartRow];
2011 const SwXMLTableCell_Impl *pCell;
2012 for( i=nLeftCol; i<nRightCol; i++ )
2013 if( ( pCell=pStartRow->GetCell(i),
2014 pCell->GetRowSpan() > nMaxRowSpan ) )
2015 nMaxRowSpan = pCell->GetRowSpan();
2017 nStartRow += nMaxRowSpan;
2018 if( nStartRow<nBottomRow )
2020 SwXMLTableRow_Impl *pPrevRow =
2021 &(*pRows)[(sal_uInt16)nStartRow-1U];
2022 i = nLeftCol;
2023 while( i < nRightCol )
2025 if( pPrevRow->GetCell(i)->GetRowSpan() > 1UL )
2027 const SwXMLTableCell_Impl *pCell2 =
2028 GetCell( nStartRow, i );
2029 const sal_uInt32 nColSpan2 = pCell2->GetColSpan();
2030 FixRowSpan( nStartRow-1UL, i, nColSpan2 );
2031 ReplaceWithEmptyCell( nStartRow, i, true );
2032 i += nColSpan2;
2034 else
2036 i++;
2041 // und jetzt nochmal von vorne ...
2045 return pBox;
2048 SwTableBox *SwXMLTableContext::MakeTableBox(
2049 SwTableLine *pUpper, const SwXMLTableCell_Impl *pCell,
2050 sal_uInt32 /*nTopRow*/, sal_uInt32 nLeftCol, sal_uInt32 /*nBottomRow*/,
2051 sal_uInt32 nRightCol )
2053 //FIXME: here would be a great place to handle XmlId for cell
2054 SwTableBox *pBox;
2055 sal_uInt32 nColSpan = nRightCol - nLeftCol;
2056 sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
2058 if( pCell->GetStartNode() )
2060 pBox = NewTableBox( pCell->GetStartNode(), pUpper );
2062 else
2064 // and it is a table: therefore we build a new box and
2065 // put the rows of the table into the rows of the box
2066 pBox = new SwTableBox( pBoxFmt, 0, pUpper );
2067 pCell->GetSubTable()->MakeTable( pBox, nColWidth );
2070 // Share formats!
2071 OUString sStyleName = pCell->GetStyleName();
2072 bool bModifyLocked;
2073 sal_Bool bNew;
2074 SwTableBoxFmt *pBoxFmt2 = GetSharedBoxFormat(
2075 pBox, sStyleName, nColWidth, pCell->IsProtected(),
2076 pCell->GetStartNode() && pCell->GetFormula().isEmpty() &&
2077 ! pCell->HasValue(),
2078 bNew, &bModifyLocked );
2080 // if a new format was created, then we need to set the style
2081 if ( bNew )
2083 // set style
2084 const SfxItemSet *pAutoItemSet = 0;
2085 if( pCell->GetStartNode() && !sStyleName.isEmpty() &&
2086 GetSwImport().FindAutomaticStyle(
2087 XML_STYLE_FAMILY_TABLE_CELL, sStyleName, &pAutoItemSet ) )
2089 if( pAutoItemSet )
2090 pBoxFmt2->SetFmtAttr( *pAutoItemSet );
2094 if( pCell->GetStartNode() )
2096 if (pCell->HasStringValue())
2098 SwNodeIndex const aNodeIndex(*(pCell->GetStartNode()), 1);
2099 SwTxtNode *const pTxtNode(aNodeIndex.GetNode().GetTxtNode());
2100 SAL_WARN_IF(!pTxtNode, "sw", "Should have a text node in cell?");
2101 if (pTxtNode)
2103 SAL_WARN_IF(!pTxtNode->GetTxt().isEmpty(), "sw",
2104 "why text here?");
2105 pTxtNode->InsertText(*pCell->GetStringValue(),
2106 SwIndex(pTxtNode, 0));
2110 // try to rescue broken documents with a certain pattern
2111 // if: 1) the cell has a default number format (number 0)
2112 // 2) the call has no formula
2113 // 3) the value is 0.0
2114 // 4) the text doesn't look anything like 0.0
2115 // [read: length > 10, or length smaller 10 and no 0 in it]
2116 // then make it a text cell!
2117 bool bSuppressNumericContent = false;
2118 if( pCell->HasValue() && (pCell->GetValue() == 0.0) &&
2119 pCell->GetFormula().isEmpty() &&
2120 !sStyleName.isEmpty() )
2122 // default num format?
2123 const SfxPoolItem* pItem = NULL;
2124 if( pBoxFmt2->GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem )
2125 == SFX_ITEM_SET )
2127 const SwTblBoxNumFormat* pNumFormat =
2128 static_cast<const SwTblBoxNumFormat*>( pItem );
2129 if( ( pNumFormat != NULL ) && ( pNumFormat->GetValue() == 0 ) )
2131 // only one text node?
2132 SwNodeIndex aNodeIndex( *(pCell->GetStartNode()), 1 );
2133 if( ( aNodeIndex.GetNode().EndOfSectionIndex() -
2134 aNodeIndex.GetNode().StartOfSectionIndex() ) == 2 )
2136 SwTxtNode* pTxtNode= aNodeIndex.GetNode().GetTxtNode();
2137 if( pTxtNode != NULL )
2139 // check text: does it look like some form of 0.0?
2140 const String& rText = pTxtNode->GetTxt();
2141 if( ( rText.Len() > 10 ) ||
2142 ( rText.Search( '0' ) == STRING_NOTFOUND ) )
2144 bSuppressNumericContent = true;
2148 else
2149 bSuppressNumericContent = true; // several nodes
2154 if( bSuppressNumericContent )
2156 // suppress numeric content? Then reset number format!
2157 pBoxFmt2->ResetFmtAttr( RES_BOXATR_FORMULA );
2158 pBoxFmt2->ResetFmtAttr( RES_BOXATR_FORMAT );
2159 pBoxFmt2->ResetFmtAttr( RES_BOXATR_VALUE );
2161 else
2163 // the normal case: set formula and value (if available)
2165 const OUString& rFormula = pCell->GetFormula();
2166 if (!rFormula.isEmpty())
2168 // formula cell: insert formula if valid
2169 SwTblBoxFormula aFormulaItem( rFormula );
2170 pBoxFmt2->SetFmtAttr( aFormulaItem );
2172 else if (!pCell->HasValue() && pCell->HasStringValue())
2174 // Check for another inconsistency:
2175 // No value but a non-textual format, i.e. a number format
2176 // Solution: the number format will be removed,
2177 // the cell gets the default text format.
2178 const SfxPoolItem* pItem = NULL;
2179 if( pBoxFmt->GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem )
2180 == SFX_ITEM_SET )
2182 const SwDoc* pDoc = pBoxFmt->GetDoc();
2183 const SvNumberFormatter* pNumberFormatter = pDoc ?
2184 pDoc->GetNumberFormatter() : 0;
2185 const SwTblBoxNumFormat* pNumFormat =
2186 static_cast<const SwTblBoxNumFormat*>( pItem );
2187 if( pNumFormat != NULL && pNumberFormatter &&
2188 !pNumberFormatter->GetEntry( pNumFormat->GetValue() )->IsTextFormat() )
2189 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2192 // always insert value, even if default
2193 if( pCell->HasValue() )
2195 SwTblBoxValue aValueItem( pCell->GetValue() );
2196 pBoxFmt2->SetFmtAttr( aValueItem );
2200 // update cell content depend on the default language
2201 pBox->ActualiseValueBox();
2204 // table cell protection
2205 if( pCell->IsProtected() )
2207 SvxProtectItem aProtectItem( RES_PROTECT );
2208 aProtectItem.SetCntntProtect( sal_True );
2209 pBoxFmt2->SetFmtAttr( aProtectItem );
2212 // restore old modify-lock state
2213 if (! bModifyLocked)
2214 pBoxFmt2->UnlockModify();
2216 pBoxFmt2->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nColWidth ) );
2218 return pBox;
2221 SwTableLine *SwXMLTableContext::MakeTableLine( SwTableBox *pUpper,
2222 sal_uInt32 nTopRow,
2223 sal_uInt32 nLeftCol,
2224 sal_uInt32 nBottomRow,
2225 sal_uInt32 nRightCol )
2227 //FIXME: here would be a great place to handle XmlId for row
2228 SwTableLine *pLine;
2229 if( !pUpper && 0UL==nTopRow )
2231 pLine = pTableNode->GetTable().GetTabLines()[0U];
2233 else
2235 pLine = new SwTableLine( pLineFmt, 0, pUpper );
2238 // TODO: Share formats!
2239 SwFrmFmt *pFrmFmt = pLine->ClaimFrmFmt();
2240 SwFmtFillOrder aFillOrder( pFrmFmt->GetFillOrder() );
2241 pFrmFmt->ResetAllFmtAttr(); // #i73790# - method renamed
2242 pFrmFmt->SetFmtAttr( aFillOrder );
2244 const SfxItemSet *pAutoItemSet = 0;
2245 const OUString& rStyleName = (*pRows)[(sal_uInt16)nTopRow].GetStyleName();
2246 if( 1UL == (nBottomRow - nTopRow) &&
2247 !rStyleName.isEmpty() &&
2248 GetSwImport().FindAutomaticStyle(
2249 XML_STYLE_FAMILY_TABLE_ROW, rStyleName, &pAutoItemSet ) )
2251 if( pAutoItemSet )
2252 pFrmFmt->SetFmtAttr( *pAutoItemSet );
2255 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2257 sal_uInt32 nStartCol = nLeftCol;
2258 while( nStartCol < nRightCol )
2260 for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
2261 (*pRows)[(sal_uInt16)nRow].SetSplitable( sal_True );
2263 sal_uInt32 nCol = nStartCol;
2264 sal_uInt32 nSplitCol = nRightCol;
2265 bool bSplitted = false;
2266 while( !bSplitted )
2268 OSL_ENSURE( nCol < nRightCol, "Zu weit gelaufen" );
2270 // Can be split after current HTML table column?
2271 // If yes, can the created region still be split to
2272 // rows if the next column is added to it?
2273 sal_Bool bSplit = sal_True;
2274 sal_Bool bHoriSplitMayContinue = sal_False;
2275 sal_Bool bHoriSplitPossible = sal_False;
2277 if ( bHasSubTables )
2279 // Convert row spans if the table has subtables:
2280 for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
2282 SwXMLTableCell_Impl *pCell = GetCell(nRow,nCol);
2283 // Could the table fragment be splitted horizontally behind
2284 // the current line?
2285 sal_Bool bHoriSplit = (*pRows)[(sal_uInt16)nRow].IsSplitable() &&
2286 nRow+1UL < nBottomRow &&
2287 1UL == pCell->GetRowSpan();
2288 (*pRows)[(sal_uInt16)nRow].SetSplitable( bHoriSplit );
2290 // Could the table fragment be splitted vertically behind the
2291 // current column (uptp the current line?
2292 bSplit &= ( 1UL == pCell->GetColSpan() );
2293 if( bSplit )
2295 bHoriSplitPossible |= bHoriSplit;
2297 // Could the current table fragment be splitted
2298 // horizontally behind the next collumn, too?
2299 bHoriSplit &= (nCol+1UL < nRightCol &&
2300 1UL == GetCell(nRow,nCol+1UL)->GetRowSpan());
2301 bHoriSplitMayContinue |= bHoriSplit;
2305 else
2307 // No subtabels: We use the new table model.
2308 SwXMLTableCell_Impl *pCell = GetCell(nTopRow,nCol);
2310 // #i95726# - some fault tolerance
2311 if ( pCell == 0 )
2313 OSL_FAIL( "table seems to be corrupt." );
2314 break;
2317 // Could the table fragment be splitted vertically behind the
2318 // current column (uptp the current line?
2319 bSplit = 1UL == pCell->GetColSpan();
2322 #if OSL_DEBUG_LEVEL > 0
2323 if( nCol == nRightCol-1UL )
2325 OSL_ENSURE( bSplit, "Split-Flag falsch" );
2326 if ( bHasSubTables )
2328 OSL_ENSURE( !bHoriSplitMayContinue,
2329 "HoriSplitMayContinue-Flag falsch" );
2330 SwXMLTableCell_Impl *pTmpCell = GetCell( nTopRow, nStartCol );
2331 OSL_ENSURE( pTmpCell->GetRowSpan() != (nBottomRow-nTopRow) ||
2332 !bHoriSplitPossible, "HoriSplitPossible-Flag falsch" );
2335 #endif
2337 OSL_ENSURE( !bHasSubTables || !bHoriSplitMayContinue || bHoriSplitPossible,
2338 "bHoriSplitMayContinue, aber nicht bHoriSplitPossible" );
2340 if( bSplit )
2342 SwTableBox* pBox = 0;
2343 SwXMLTableCell_Impl *pCell = GetCell( nTopRow, nStartCol );
2344 // #i95726# - some fault tolerance
2345 if( ( !bHasSubTables || ( pCell->GetRowSpan() == (nBottomRow-nTopRow) ) ) &&
2346 pCell->GetColSpan() == (nCol+1UL-nStartCol) &&
2347 ( pCell->GetStartNode() || pCell->GetSubTable() ) )
2349 // insert new empty cell for covered cells:
2350 long nBoxRowSpan = 1;
2351 if ( !bHasSubTables )
2353 nBoxRowSpan = pCell->GetRowSpan();
2354 if ( pCell->IsCovered() )
2356 nBoxRowSpan = -1 * nBoxRowSpan;
2357 ReplaceWithEmptyCell( nTopRow, nStartCol, false );
2361 // The remaining box neither contains lines nor rows (i.e.
2362 // is a content box
2363 nSplitCol = nCol + 1UL;
2365 pBox = MakeTableBox( pLine, pCell,
2366 nTopRow, nStartCol,
2367 nBottomRow, nSplitCol );
2369 if ( 1 != nBoxRowSpan )
2370 pBox->setRowSpan( nBoxRowSpan );
2372 bSplitted = true;
2374 else if( bHasSubTables && bHoriSplitPossible && bHoriSplitMayContinue )
2376 // The table fragment could be splitted behind the current
2377 // column, and the remaining fragment could be divided
2378 // into lines. Anyway, it could be that this applies to
2379 // the next column, too. That for, we check the next
2380 // column but rememeber the current one as a good place to
2381 // split.
2382 nSplitCol = nCol + 1UL;
2384 else if ( bHasSubTables )
2386 // If the table resulting table fragment could be divided
2387 // into lines if spllitting behind the current column, but
2388 // this doesn't apply for thr next column, we split begind
2389 // the current column. This applies for the last column,
2390 // too.
2391 // If the resulting box cannot be splitted into rows,
2392 // the split at the last split position we remembered.
2393 if( bHoriSplitPossible || nSplitCol > nCol+1 )
2395 OSL_ENSURE( !bHoriSplitMayContinue,
2396 "bHoriSplitMayContinue==sal_True" );
2397 OSL_ENSURE( bHoriSplitPossible || nSplitCol == nRightCol,
2398 "bHoriSplitPossible-Flag sollte gesetzt sein" );
2400 nSplitCol = nCol + 1UL;
2403 pBox = MakeTableBox( pLine, nTopRow, nStartCol,
2404 nBottomRow, nSplitCol );
2405 bSplitted = true;
2408 OSL_ENSURE( bHasSubTables || pBox, "Colspan trouble" );
2410 if( pBox )
2411 rBoxes.push_back( pBox );
2413 nCol++;
2415 nStartCol = nSplitCol;
2418 return pLine;
2421 void SwXMLTableContext::_MakeTable( SwTableBox *pBox )
2423 // fix column widths
2424 std::vector<ColumnWidthInfo>::iterator colIter;
2425 sal_uInt32 nCols = GetColumnCount();
2427 // If there are empty rows (because of some row span of previous rows)
2428 // the have to be deleted. The previous rows have to be truncated.
2430 if( pRows->size() > nCurRow )
2432 SwXMLTableRow_Impl *pPrevRow = &(*pRows)[(sal_uInt16)nCurRow-1U];
2433 const SwXMLTableCell_Impl *pCell;
2434 for( sal_uLong i = 0; i < aColumnWidths.size(); ++i )
2436 if( ( pCell=pPrevRow->GetCell(i), pCell->GetRowSpan() > 1UL ) )
2438 FixRowSpan( nCurRow-1UL, i, 1UL );
2441 for( sal_uLong i = pRows->size()-1UL; i>=nCurRow; --i )
2442 pRows->pop_back();
2445 if( pRows->empty() )
2447 OUString aStyleName2;
2448 InsertCell( aStyleName2, 1U, nCols, InsertTableSection() );
2451 // TODO: Do we have to keep both values, the relative and the absolute
2452 // width?
2453 sal_Int32 nAbsWidth = 0L;
2454 sal_Int32 nMinAbsColWidth = 0L;
2455 sal_Int32 nRelWidth = 0L;
2456 sal_Int32 nMinRelColWidth = 0L;
2457 sal_uInt32 nRelCols = 0UL;
2458 for( colIter = aColumnWidths.begin(); colIter < aColumnWidths.end(); ++colIter)
2460 if( colIter->isRelative )
2462 nRelWidth += colIter->width;
2463 if( 0L == nMinRelColWidth || colIter->width < nMinRelColWidth )
2464 nMinRelColWidth = colIter->width;
2465 nRelCols++;
2467 else
2469 nAbsWidth += colIter->width;
2470 if( 0L == nMinAbsColWidth || colIter->width < nMinAbsColWidth )
2471 nMinAbsColWidth = colIter->width;
2474 sal_uInt32 nAbsCols = nCols - nRelCols;
2476 if( bRelWidth )
2478 // If there a columns that have an absolute width, we have to
2479 // calculate a relative one for them.
2480 if( nAbsCols > 0UL )
2482 // All column that have absolute widths get relative widths;
2483 // these widths relate to each over like the original absolute
2484 // widths. The smallest column gets a width that hat the same
2485 // value as the smallest column that has an relative width
2486 // already.
2487 if( 0L == nMinRelColWidth )
2488 nMinRelColWidth = nMinAbsColWidth;
2490 for( colIter = aColumnWidths.begin(); nAbsCols > 0UL && colIter < aColumnWidths.end(); ++colIter)
2492 if( !colIter->isRelative )
2494 sal_Int32 nRelCol = ( colIter->width * nMinRelColWidth) / nMinAbsColWidth;
2495 colIter->width = nRelCol;
2496 colIter->isRelative = true;
2497 nRelWidth += nRelCol;
2498 nAbsCols--;
2503 if( !nWidth )
2505 // This happens only for percentage values for the table itself.
2506 // In this case, the columns get the correct width even if the
2507 // the sum of the relative withs is smaller than the available
2508 // width in TWIP. Therfore, we can use the relative width.
2510 nWidth = nRelWidth > USHRT_MAX ? USHRT_MAX : nRelWidth;
2512 if( nRelWidth != nWidth && nRelWidth && nCols )
2514 double n = (double)nWidth / (double)nRelWidth;
2515 nRelWidth = 0L;
2516 for( colIter = aColumnWidths.begin(); colIter < aColumnWidths.end() - 1; ++colIter)
2518 sal_Int32 nW = (sal_Int32)( colIter->width * n);
2519 colIter->width = (sal_uInt16)nW;
2520 nRelWidth += nW;
2522 aColumnWidths.back().width = (nWidth-nRelWidth);
2525 else
2527 // If there are columns that have relative widths, we have to
2528 // calculate a absolute widths for them.
2529 if( nRelCols > 0UL )
2531 // The absolute space that is available for all columns with a
2532 // relative width.
2533 sal_Int32 nAbsForRelWidth =
2534 nWidth > nAbsWidth ? nWidth - nAbsWidth : (sal_Int32)0L;
2536 // The relative width that has to be distributed in addition to
2537 // equally widthed columns.
2538 sal_Int32 nExtraRel = nRelWidth - (nRelCols * nMinRelColWidth);
2540 // The absolute space that may be distributed in addition to
2541 // minumum widthed columns.
2542 sal_Int32 nMinAbs = nRelCols * MINLAY;
2543 sal_Int32 nExtraAbs =
2544 nAbsForRelWidth > nMinAbs ? nAbsForRelWidth - nMinAbs : (sal_Int32)0L;
2546 bool bMin = false; // Do all columns get the mininum width?
2547 bool bMinExtra = false; // Do all columns get the minimum width plus
2548 // some extra space?
2550 if( nAbsForRelWidth <= nMinAbs )
2552 // If there is not enough space left for all columns to
2553 // get the minimum width, they get the minimum width, anyway.
2554 nAbsForRelWidth = nMinAbs;
2555 bMin = true;
2557 else if( nAbsForRelWidth <= (nRelWidth * MINLAY) /
2558 nMinRelColWidth )
2560 // If there is enougth space for all columns to get the
2561 // minimum width, but not to get a width that takes the
2562 // relative width into account, each column gets the minimum
2563 // width plus some extra space that is based on the additional
2564 // space that is available.
2565 bMinExtra = true;
2567 // Otherwise, if there is enouth space for every column, every
2568 // column gets this space.
2570 for( colIter = aColumnWidths.begin(); nRelCols > 0UL && colIter < aColumnWidths.end(); ++colIter )
2572 if( colIter->isRelative )
2574 sal_Int32 nAbsCol;
2575 if( 1UL == nRelCols )
2577 // The last column that has a relative width gets
2578 // all absolute space that is left.
2579 nAbsCol = nAbsForRelWidth;
2581 else
2583 if( bMin )
2585 nAbsCol = MINLAY;
2587 else if( bMinExtra )
2589 sal_Int32 nExtraRelCol = colIter->width - nMinRelColWidth;
2590 nAbsCol = MINLAY + (nExtraRelCol * nExtraAbs) /
2591 nExtraRel;
2593 else
2595 nAbsCol = ( colIter->width * nAbsForRelWidth) / nRelWidth;
2598 colIter->width = nAbsCol;
2599 colIter->isRelative = false;
2600 nAbsForRelWidth -= nAbsCol;
2601 nAbsWidth += nAbsCol;
2602 nRelCols--;
2607 if( nCols && nAbsWidth )
2609 if( nAbsWidth < nWidth )
2611 // If the table's width is larger than the sum of the absolute
2612 // column widths, every column get some extra width.
2613 sal_Int32 nExtraAbs = nWidth - nAbsWidth;
2614 sal_Int32 nAbsLastCol = aColumnWidths.back().width + nExtraAbs;
2615 for( colIter = aColumnWidths.begin(); colIter < aColumnWidths.end()-1UL; ++colIter )
2617 sal_Int32 nAbsCol = colIter->width;
2618 sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
2619 nAbsWidth;
2620 nAbsCol += nExtraAbsCol;
2621 colIter->width = nAbsCol;
2622 nAbsLastCol -= nExtraAbsCol;
2624 aColumnWidths.back().width = nAbsLastCol;
2626 else if( nAbsWidth > nWidth )
2628 // If the table's width is smaller than the sum of the absolute
2629 // column widths, every column needs to shrink.
2630 // Every column gets the minimum width plus some extra width.
2631 sal_Int32 nExtraAbs = nWidth - (nCols * MINLAY);
2632 sal_Int32 nAbsLastCol = MINLAY + nExtraAbs;
2633 for( colIter = aColumnWidths.begin(); colIter < aColumnWidths.end()-1UL; ++colIter )
2635 sal_Int32 nAbsCol = colIter->width;
2636 sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
2637 nAbsWidth;
2638 nAbsCol = MINLAY + nExtraAbsCol;
2639 colIter->width = nAbsCol;
2640 nAbsLastCol -= nExtraAbsCol;
2642 aColumnWidths.back().width = nAbsLastCol;
2647 SwTableLines& rLines =
2648 pBox ? pBox->GetTabLines()
2649 : pTableNode->GetTable().GetTabLines();
2651 sal_uInt32 nStartRow = 0UL;
2652 sal_uInt32 nRows = pRows->size();
2653 for(sal_uInt32 i=0UL; i<nRows; ++i )
2655 // Could we split the table behind the current line?
2656 bool bSplit = true;
2657 if ( bHasSubTables )
2659 SwXMLTableRow_Impl *pRow = &(*pRows)[(sal_uInt16)i];
2660 for( sal_uInt32 j=0UL; j<nCols; j++ )
2662 bSplit = ( 1UL == pRow->GetCell(j)->GetRowSpan() );
2663 if( !bSplit )
2664 break;
2668 if( bSplit )
2670 SwTableLine *pLine =
2671 MakeTableLine( pBox, nStartRow, 0UL, i+1UL, nCols );
2672 if( pBox || nStartRow>0UL )
2673 rLines.push_back( pLine );
2674 nStartRow = i+1UL;
2679 void SwXMLTableContext::MakeTable()
2681 // this method will modify the document directly -> lock SolarMutex
2682 // This will call all other MakeTable*(..) methods, so
2683 // those don't need to be locked separately.
2684 SolarMutexGuard aGuard;
2686 // #i97274# handle invalid tables
2687 if (!pRows || pRows->empty() || !GetColumnCount())
2689 OSL_FAIL("invalid table: no cells; deleting...");
2690 pTableNode->GetDoc()->DeleteSection( pTableNode );
2691 pTableNode = 0;
2692 pBox1 = 0;
2693 pSttNd1 = 0;
2694 return;
2697 SwXMLImport& rSwImport = GetSwImport();
2699 SwFrmFmt *pFrmFmt = pTableNode->GetTable().GetFrmFmt();
2701 sal_Int16 eHoriOrient = text::HoriOrientation::FULL;
2702 bool bSetHoriOrient = false;
2704 sal_uInt16 nPrcWidth = 0U;
2706 pTableNode->GetTable().SetRowsToRepeat( nHeaderRows );
2707 pTableNode->GetTable().SetTableModel( !bHasSubTables );
2709 const SfxItemSet *pAutoItemSet = 0;
2710 if( !aStyleName.isEmpty() &&
2711 rSwImport.FindAutomaticStyle(
2712 XML_STYLE_FAMILY_TABLE_TABLE, aStyleName, &pAutoItemSet ) &&
2713 pAutoItemSet )
2715 const SfxPoolItem *pItem;
2716 const SvxLRSpaceItem *pLRSpace = 0;
2717 if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_LR_SPACE, sal_False,
2718 &pItem ) )
2719 pLRSpace = (const SvxLRSpaceItem *)pItem;
2721 if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_HORI_ORIENT, sal_False,
2722 &pItem ) )
2724 eHoriOrient = ((const SwFmtHoriOrient *)pItem)->GetHoriOrient();
2725 switch( eHoriOrient )
2727 case text::HoriOrientation::FULL:
2728 if( pLRSpace )
2730 eHoriOrient = text::HoriOrientation::NONE;
2731 bSetHoriOrient = true;
2733 break;
2734 case text::HoriOrientation::LEFT:
2735 if( pLRSpace )
2737 eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
2738 bSetHoriOrient = true;
2740 break;
2741 default:
2745 else
2747 bSetHoriOrient = true;
2750 const SwFmtFrmSize *pSize = 0;
2751 if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_FRM_SIZE, sal_False,
2752 &pItem ) )
2753 pSize = (const SwFmtFrmSize *)pItem;
2755 switch( eHoriOrient )
2757 case text::HoriOrientation::FULL:
2758 case text::HoriOrientation::NONE:
2759 // For text::HoriOrientation::NONE we would prefere to use the sum
2760 // of the relative column widths as reference width.
2761 // Unfortunately this works only if this sum interpreted as
2762 // twip value is larger than the space that is avaialable.
2763 // We don't know that space, so we have to use USHRT_MAX, too.
2764 // Even if a size is speczified, it will be ignored!
2765 nWidth = USHRT_MAX;
2766 break;
2767 default:
2768 if( pSize )
2770 if( pSize->GetWidthPercent() )
2772 // The width will be set in _MakeTable
2773 nPrcWidth = pSize->GetWidthPercent();
2775 else
2777 nWidth = pSize->GetWidth();
2778 if( nWidth < (sal_Int32)GetColumnCount() * MINLAY )
2780 nWidth = GetColumnCount() * MINLAY;
2782 else if( nWidth > USHRT_MAX )
2784 nWidth = USHRT_MAX;
2786 bRelWidth = false;
2789 else
2791 eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH == eHoriOrient
2792 ? text::HoriOrientation::NONE : text::HoriOrientation::FULL;
2793 bSetHoriOrient = true;
2794 nWidth = USHRT_MAX;
2796 break;
2799 pFrmFmt->SetFmtAttr( *pAutoItemSet );
2801 else
2803 bSetHoriOrient = true;
2804 nWidth = USHRT_MAX;
2807 SwTableLine *pLine1 = pTableNode->GetTable().GetTabLines()[0U];
2808 OSL_ENSURE( pBox1 == pLine1->GetTabBoxes()[0U],
2809 "Why is box 1 change?" );
2810 pBox1->pSttNd = pSttNd1;
2811 pLine1->GetTabBoxes().erase( pLine1->GetTabBoxes().begin() );
2813 pLineFmt = (SwTableLineFmt*)pLine1->GetFrmFmt();
2814 pBoxFmt = (SwTableBoxFmt*)pBox1->GetFrmFmt();
2816 _MakeTable( 0 );
2818 if( bSetHoriOrient )
2819 pFrmFmt->SetFmtAttr( SwFmtHoriOrient( 0, eHoriOrient ) );
2821 // This must be after the call to _MakeTable, because nWidth might be
2822 // changed there.
2823 pFrmFmt->LockModify();
2824 SwFmtFrmSize aSize( ATT_VAR_SIZE, nWidth );
2825 aSize.SetWidthPercent( (sal_Int8)nPrcWidth );
2826 pFrmFmt->SetFmtAttr( aSize );
2827 pFrmFmt->UnlockModify();
2830 for( sal_uInt16 i=0; i<pRows->size(); i++ )
2831 (*pRows)[i].Dispose();
2833 // now that table is complete, change into DDE table (if appropriate)
2834 if (NULL != pDDESource)
2836 // change existing table into DDE table:
2837 // 1) Get DDE field type (get data from dde-source context),
2838 SwDDEFieldType* pFldType = lcl_GetDDEFieldType( pDDESource,
2839 pTableNode );
2841 // 2) release the DDE source context,
2842 pDDESource->ReleaseRef();
2844 // 3) create new DDE table, and
2845 SwDDETable* pDDETable = new SwDDETable( pTableNode->GetTable(),
2846 pFldType, sal_False );
2848 // 4) set new (DDE)table at node.
2849 pTableNode->SetNewTable(pDDETable, sal_False);
2852 // ??? this is always false: root frame is only created in ViewShell::Init
2853 if( pTableNode->GetDoc()->GetCurrentViewShell() ) //swmod 071108//swmod 071225
2855 pTableNode->DelFrms();
2856 SwNodeIndex aIdx( *pTableNode->EndOfSectionNode(), 1 );
2857 pTableNode->MakeFrms( &aIdx );
2861 void SwXMLTableContext::MakeTable( SwTableBox *pBox, sal_Int32 nW )
2863 //FIXME: here would be a great place to handle XmlId for subtable
2864 pLineFmt = GetParentTable()->pLineFmt;
2865 pBoxFmt = GetParentTable()->pBoxFmt;
2866 nWidth = nW;
2867 bRelWidth = GetParentTable()->bRelWidth;
2869 _MakeTable( pBox );
2871 for (size_t i=0; i < pRows->size(); ++i) // i113600, to break the cyclic reference to SwXMLTableContext object
2872 (*pRows)[i].Dispose();
2875 const SwStartNode *SwXMLTableContext::InsertTableSection(
2876 const SwStartNode *const pPrevSttNd,
2877 OUString const*const pStringValueStyleName)
2879 // The topmost table is the only table that maintains the two members
2880 // pBox1 and bFirstSection.
2881 if( xParentTable.Is() )
2882 return static_cast<SwXMLTableContext *>(&xParentTable)
2883 ->InsertTableSection(pPrevSttNd, pStringValueStyleName);
2885 const SwStartNode *pStNd;
2886 Reference<XUnoTunnel> xCrsrTunnel( GetImport().GetTextImport()->GetCursor(),
2887 UNO_QUERY);
2888 OSL_ENSURE( xCrsrTunnel.is(), "missing XUnoTunnel for Cursor" );
2889 OTextCursorHelper *pTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
2890 sal::static_int_cast< sal_IntPtr >( xCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )));
2891 OSL_ENSURE( pTxtCrsr, "SwXTextCursor missing" );
2893 if( bFirstSection )
2895 // The Cursor already is in the first section
2896 pStNd = pTxtCrsr->GetPaM()->GetNode()->FindTableBoxStartNode();
2897 bFirstSection = false;
2898 OUString sStyleName("Standard");
2899 GetImport().GetTextImport()->SetStyleAndAttrs( GetImport(),
2900 GetImport().GetTextImport()->GetCursor(), sStyleName, sal_True );
2902 else
2904 SwDoc* pDoc = SwImport::GetDocFromXMLImport( GetSwImport() );
2905 const SwEndNode *pEndNd = pPrevSttNd ? pPrevSttNd->EndOfSectionNode()
2906 : pTableNode->EndOfSectionNode();
2907 // #i78921# - make code robust
2908 OSL_ENSURE( pDoc, "<SwXMLTableContext::InsertTableSection(..)> - no <pDoc> at <SwXTextCursor> instance - <SwXTextCurosr> doesn't seem to be registered at a <SwUnoCrsr> instance." );
2909 if ( !pDoc )
2911 pDoc = const_cast<SwDoc*>(pEndNd->GetDoc());
2913 sal_uInt32 nOffset = pPrevSttNd ? 1UL : 0UL;
2914 SwNodeIndex aIdx( *pEndNd, nOffset );
2915 SwTxtFmtColl *pColl =
2916 pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD, false );
2917 pStNd = pDoc->GetNodes().MakeTextSection( aIdx, SwTableBoxStartNode,
2918 pColl );
2919 // Consider the case that a table is defined without a row.
2920 if( !pPrevSttNd && pBox1 != NULL )
2923 pBox1->pSttNd = pStNd;
2924 SwCntntNode *pCNd = pDoc->GetNodes()[ pStNd->GetIndex() + 1 ]
2925 ->GetCntntNode();
2926 SwPosition aPos( *pCNd );
2927 aPos.nContent.Assign( pCNd, 0U );
2929 const uno::Reference< text::XTextRange > xTextRange =
2930 SwXTextRange::CreateXTextRange( *pDoc, aPos, 0 );
2931 Reference < XText > xText = xTextRange->getText();
2932 Reference < XTextCursor > xTextCursor =
2933 xText->createTextCursorByRange( xTextRange );
2934 GetImport().GetTextImport()->SetCursor( xTextCursor );
2938 if (pStringValueStyleName)
2939 { // fdo#62147: apply style to paragraph on string-value cell
2940 GetImport().GetTextImport()->SetStyleAndAttrs( GetImport(),
2941 GetImport().GetTextImport()->GetCursor(), *pStringValueStyleName,
2942 true, false, -1, false); // parameters same as sCellParaStyleName
2945 return pStNd;
2948 void SwXMLTableContext::EndElement()
2950 if( IsValid() && !xParentTable.Is() )
2952 MakeTable();
2953 GetImport().GetTextImport()->SetCursor( xOldCursor );
2957 Reference < XTextContent > SwXMLTableContext::GetXTextContent() const
2959 return xTextContent;
2962 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */