merge the formfield patch from ooo-build
[ooovba.git] / sw / source / filter / xml / xmltbli.cxx
blob29b774ca9ac5d6199d8a874dd05ff525ae780774
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xmltbli.cxx,v $
10 * $Revision: 1.65 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
36 #include "hintids.hxx"
38 #include <limits.h>
39 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
40 #include <com/sun/star/text/XTextTable.hpp>
41 #include <com/sun/star/table/XCellRange.hpp>
42 #include <svtools/itemset.hxx>
43 #include <svtools/zformat.hxx>
44 #include <xmloff/xmlnmspe.hxx>
45 #include <xmloff/xmltkmap.hxx>
46 #include <xmloff/nmspmap.hxx>
48 #include <xmloff/families.hxx>
49 #include <xmloff/xmluconv.hxx>
50 #include <xmloff/i18nmap.hxx>
51 #include <svx/protitem.hxx>
52 #include "poolfmt.hxx"
53 #include "fmtfsize.hxx"
54 #include "fmtornt.hxx"
55 #include "fmtfordr.hxx"
56 #include "doc.hxx"
57 #include "swtable.hxx"
58 #include "swtblfmt.hxx"
59 #include "pam.hxx"
60 #include "unotbl.hxx"
61 #include "unocrsr.hxx"
62 #include "cellatr.hxx"
63 #include "swddetbl.hxx"
64 #include "ddefld.hxx"
65 #include <sfx2/linkmgr.hxx> // for cTokenSeparator
66 #include "xmlimp.hxx"
67 #include "xmltbli.hxx"
69 // for locking SolarMutex: svapp + mutex
70 #include <vcl/svapp.hxx>
71 #include <vos/mutex.hxx>
72 #include "ndtxt.hxx"
74 using ::rtl::OUString;
75 using namespace ::com::sun::star;
76 using namespace ::com::sun::star::uno;
77 using namespace ::com::sun::star::lang;
78 using namespace ::com::sun::star::text;
79 using namespace ::com::sun::star::frame;
80 using namespace ::com::sun::star::table;
81 using namespace ::com::sun::star::xml::sax;
82 using namespace ::xmloff::token;
83 using ::std::hash_map;
85 enum SwXMLTableElemTokens
87 XML_TOK_TABLE_HEADER_COLS,
88 XML_TOK_TABLE_COLS,
89 XML_TOK_TABLE_COL,
90 XML_TOK_TABLE_HEADER_ROWS,
91 XML_TOK_TABLE_ROWS,
92 XML_TOK_TABLE_ROW,
93 XML_TOK_OFFICE_DDE_SOURCE,
94 XML_TOK_TABLE_ELEM_END=XML_TOK_UNKNOWN
97 enum SwXMLTableCellAttrTokens
99 XML_TOK_TABLE_XMLID,
100 XML_TOK_TABLE_STYLE_NAME,
101 XML_TOK_TABLE_NUM_COLS_SPANNED,
102 XML_TOK_TABLE_NUM_ROWS_SPANNED,
103 XML_TOK_TABLE_NUM_COLS_REPEATED,
104 XML_TOK_TABLE_FORMULA,
105 XML_TOK_TABLE_VALUE,
106 XML_TOK_TABLE_TIME_VALUE,
107 XML_TOK_TABLE_DATE_VALUE,
108 XML_TOK_TABLE_BOOLEAN_VALUE,
109 XML_TOK_TABLE_PROTECTED,
110 XML_TOK_TABLE_STRING_VALUE,
111 XML_TOK_TABLE_CELL_ATTR_END=XML_TOK_UNKNOWN
114 static __FAR_DATA SvXMLTokenMapEntry aTableElemTokenMap[] =
116 { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS,
117 XML_TOK_TABLE_HEADER_COLS },
118 { XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS, XML_TOK_TABLE_COLS },
119 { XML_NAMESPACE_TABLE, XML_TABLE_COLUMN, XML_TOK_TABLE_COL },
120 { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS,
121 XML_TOK_TABLE_HEADER_ROWS },
122 { XML_NAMESPACE_TABLE, XML_TABLE_ROWS, XML_TOK_TABLE_ROWS },
123 { XML_NAMESPACE_TABLE, XML_TABLE_ROW, XML_TOK_TABLE_ROW },
124 { XML_NAMESPACE_OFFICE, XML_DDE_SOURCE,
125 XML_TOK_OFFICE_DDE_SOURCE },
127 // There are slight differences between <table:table-columns> and
128 // <table:table-columns-groups>. However, none of these are
129 // supported in Writer (they are Calc-only features), so we
130 // support column groups by simply using the <table:table-columns>
131 // token for column groups, too.
132 { XML_NAMESPACE_TABLE, XML_TABLE_COLUMN_GROUP, XML_TOK_TABLE_COLS },
134 XML_TOKEN_MAP_END
137 static __FAR_DATA SvXMLTokenMapEntry aTableCellAttrTokenMap[] =
139 { XML_NAMESPACE_XML, XML_ID, XML_TOK_TABLE_XMLID },
140 { XML_NAMESPACE_TABLE, XML_STYLE_NAME, XML_TOK_TABLE_STYLE_NAME },
141 { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, XML_TOK_TABLE_NUM_COLS_SPANNED },
142 { XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, XML_TOK_TABLE_NUM_ROWS_SPANNED },
143 { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, XML_TOK_TABLE_NUM_COLS_REPEATED },
144 { XML_NAMESPACE_TABLE, XML_FORMULA, XML_TOK_TABLE_FORMULA },
145 { XML_NAMESPACE_OFFICE, XML_VALUE, XML_TOK_TABLE_VALUE },
146 { XML_NAMESPACE_OFFICE, XML_TIME_VALUE, XML_TOK_TABLE_TIME_VALUE },
147 { XML_NAMESPACE_OFFICE, XML_DATE_VALUE, XML_TOK_TABLE_DATE_VALUE },
148 { XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, XML_TOK_TABLE_BOOLEAN_VALUE },
149 { XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TOK_TABLE_PROTECTED },
150 { XML_NAMESPACE_TABLE, XML_PROTECT, XML_TOK_TABLE_PROTECTED }, // for backwards compatibility with SRC629 (and before)
151 { XML_NAMESPACE_OFFICE, XML_STRING_VALUE, XML_TOK_TABLE_STRING_VALUE },
152 XML_TOKEN_MAP_END
155 const SvXMLTokenMap& SwXMLImport::GetTableElemTokenMap()
157 if( !pTableElemTokenMap )
158 pTableElemTokenMap = new SvXMLTokenMap( aTableElemTokenMap );
160 return *pTableElemTokenMap;
163 const SvXMLTokenMap& SwXMLImport::GetTableCellAttrTokenMap()
165 if( !pTableCellAttrTokenMap )
166 pTableCellAttrTokenMap = new SvXMLTokenMap( aTableCellAttrTokenMap );
168 return *pTableCellAttrTokenMap;
171 // ---------------------------------------------------------------------
173 class SwXMLTableCell_Impl
175 OUString aStyleName;
177 OUString mXmlId;
179 OUString sFormula; // cell formula; valid if length > 0
180 double dValue; // formula value
182 SvXMLImportContextRef xSubTable;
184 const SwStartNode *pStartNode;
185 sal_uInt32 nRowSpan;
186 sal_uInt32 nColSpan;
188 sal_Bool bProtected : 1;
189 sal_Bool bHasValue; // determines whether dValue attribute is valid
190 sal_Bool mbCovered;
191 sal_Bool mbTextValue;
193 public:
195 SwXMLTableCell_Impl( sal_uInt32 nRSpan=1UL, sal_uInt32 nCSpan=1UL ) :
196 pStartNode( 0 ),
197 nRowSpan( nRSpan ),
198 nColSpan( nCSpan ),
199 bProtected( sal_False ),
200 mbCovered( sal_False )
203 inline void Set( const OUString& rStyleName,
204 sal_uInt32 nRSpan, sal_uInt32 nCSpan,
205 const SwStartNode *pStNd, SwXMLTableContext *pTable,
206 sal_Bool bProtect = sal_False,
207 const OUString* pFormula = NULL,
208 sal_Bool bHasValue = sal_False,
209 sal_Bool mbCovered = sal_False,
210 double dVal = 0.0,
211 sal_Bool mbTextValue = sal_False,
212 OUString const& i_rXmlId = OUString());
214 sal_Bool IsUsed() const { return pStartNode!=0 ||
215 xSubTable.Is() || bProtected;}
217 sal_uInt32 GetRowSpan() const { return nRowSpan; }
218 void SetRowSpan( sal_uInt32 nSet ) { nRowSpan = nSet; }
219 sal_uInt32 GetColSpan() const { return nColSpan; }
220 const OUString& GetStyleName() const { return aStyleName; }
221 const OUString& GetFormula() const { return sFormula; }
222 double GetValue() const { return dValue; }
223 sal_Bool HasValue() const { return bHasValue; }
224 sal_Bool IsProtected() const { return bProtected; }
225 sal_Bool IsCovered() const { return mbCovered; }
226 sal_Bool HasTextValue() const { return mbTextValue; }
227 const OUString& GetXmlId() const { return mXmlId; }
229 const SwStartNode *GetStartNode() const { return pStartNode; }
230 inline void SetStartNode( const SwStartNode *pSttNd );
232 inline SwXMLTableContext *GetSubTable() const;
234 inline void Dispose();
237 inline void SwXMLTableCell_Impl::Set( const OUString& rStyleName,
238 sal_uInt32 nRSpan, sal_uInt32 nCSpan,
239 const SwStartNode *pStNd,
240 SwXMLTableContext *pTable,
241 sal_Bool bProtect,
242 const OUString* pFormula,
243 sal_Bool bHasVal,
244 sal_Bool bCov,
245 double dVal,
246 sal_Bool bTextVal,
247 OUString const& i_rXmlId )
249 aStyleName = rStyleName;
250 nRowSpan = nRSpan;
251 nColSpan = nCSpan;
252 pStartNode = pStNd;
253 xSubTable = pTable;
254 dValue = dVal;
255 bHasValue = bHasVal;
256 mbCovered = bCov;
257 mbTextValue = bTextVal;
258 bProtected = bProtect;
260 if (!mbCovered) // ensure uniqueness
262 mXmlId = i_rXmlId;
265 // set formula, if valid
266 if (pFormula != NULL)
268 sFormula = *pFormula;
272 inline void SwXMLTableCell_Impl::SetStartNode( const SwStartNode *pSttNd )
274 pStartNode = pSttNd;
275 xSubTable = 0;
278 inline SwXMLTableContext *SwXMLTableCell_Impl::GetSubTable() const
280 return (SwXMLTableContext *)&xSubTable;
283 inline void SwXMLTableCell_Impl::Dispose()
285 if( xSubTable.Is() )
286 xSubTable = 0;
289 // ---------------------------------------------------------------------
291 typedef SwXMLTableCell_Impl* SwXMLTableCellPtr;
292 SV_DECL_PTRARR_DEL(SwXMLTableCells_Impl,SwXMLTableCellPtr,5,5)
293 SV_IMPL_PTRARR(SwXMLTableCells_Impl,SwXMLTableCellPtr)
295 class SwXMLTableRow_Impl
297 OUString aStyleName;
298 OUString aDfltCellStyleName;
299 OUString mXmlId;
301 SwXMLTableCells_Impl aCells;
303 sal_Bool bSplitable;
305 public:
307 SwXMLTableRow_Impl( const OUString& rStyleName, sal_uInt32 nCells,
308 const OUString *pDfltCellStyleName = 0,
309 const OUString& i_rXmlId = OUString() );
310 ~SwXMLTableRow_Impl() {}
312 inline SwXMLTableCell_Impl *GetCell( sal_uInt32 nCol ) const;
314 inline void Set( const OUString& rStyleName,
315 const OUString& rDfltCellStyleName,
316 const OUString& i_rXmlId );
318 void Expand( sal_uInt32 nCells, sal_Bool bOneCell );
320 void SetSplitable( sal_Bool bSet ) { bSplitable = bSet; }
321 sal_Bool IsSplitable() const { return bSplitable; }
323 const OUString& GetStyleName() const { return aStyleName; }
324 const OUString& GetDefaultCellStyleName() const { return aDfltCellStyleName; }
325 const OUString& GetXmlId() const { return mXmlId; }
327 void Dispose();
330 SwXMLTableRow_Impl::SwXMLTableRow_Impl( const OUString& rStyleName,
331 sal_uInt32 nCells,
332 const OUString *pDfltCellStyleName,
333 const OUString& i_rXmlId ) :
334 aStyleName( rStyleName ),
335 mXmlId( i_rXmlId ),
336 bSplitable( sal_False )
338 if( pDfltCellStyleName )
339 aDfltCellStyleName = *pDfltCellStyleName;
340 ASSERT( nCells <= USHRT_MAX,
341 "SwXMLTableRow_Impl::SwXMLTableRow_Impl: too many cells" );
342 if( nCells > USHRT_MAX )
343 nCells = USHRT_MAX;
345 for( sal_uInt16 i=0U; i<nCells; i++ )
347 aCells.Insert( new SwXMLTableCell_Impl, aCells.Count() );
351 inline SwXMLTableCell_Impl *SwXMLTableRow_Impl::GetCell( sal_uInt32 nCol ) const
353 ASSERT( nCol < USHRT_MAX,
354 "SwXMLTableRow_Impl::GetCell: column number is to big" );
355 // --> OD 2009-03-19 #i95726# - some fault tolerance
356 // return aCells[(sal_uInt16)nCol];
357 ASSERT( nCol < aCells.Count(),
358 "SwXMLTableRow_Impl::GetCell: column number is out of bound" );
359 return nCol < aCells.Count() ? aCells[(sal_uInt16)nCol] : 0;
360 // <--
363 void SwXMLTableRow_Impl::Expand( sal_uInt32 nCells, sal_Bool bOneCell )
365 ASSERT( nCells <= USHRT_MAX,
366 "SwXMLTableRow_Impl::Expand: too many cells" );
367 if( nCells > USHRT_MAX )
368 nCells = USHRT_MAX;
370 sal_uInt32 nColSpan = nCells - aCells.Count();
371 for( sal_uInt16 i=aCells.Count(); i<nCells; i++ )
373 aCells.Insert( new SwXMLTableCell_Impl( 1UL,
374 bOneCell ? nColSpan : 1UL ),
375 aCells.Count() );
376 nColSpan--;
379 ASSERT( nCells<=aCells.Count(),
380 "SwXMLTableRow_Impl::Expand: wrong number of cells" );
383 inline void SwXMLTableRow_Impl::Set( const OUString& rStyleName,
384 const OUString& rDfltCellStyleName,
385 const OUString& i_rXmlId )
387 aStyleName = rStyleName;
388 aDfltCellStyleName = rDfltCellStyleName;
389 mXmlId = i_rXmlId;
392 void SwXMLTableRow_Impl::Dispose()
394 for( sal_uInt16 i=0; i < aCells.Count(); i++ )
395 aCells[i]->Dispose();
398 // ---------------------------------------------------------------------
400 class SwXMLTableCellContext_Impl : public SvXMLImportContext
402 OUString aStyleName;
403 OUString sFormula;
404 OUString sSaveParaDefault;
405 OUString mXmlId;
407 SvXMLImportContextRef xMyTable;
409 double fValue;
410 sal_Bool bHasValue;
411 sal_Bool bHasTextValue;
412 sal_Bool bProtect;
414 sal_uInt32 nRowSpan;
415 sal_uInt32 nColSpan;
416 sal_uInt32 nColRepeat;
418 sal_Bool bHasTextContent : 1;
419 sal_Bool bHasTableContent : 1;
421 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
423 sal_Bool HasContent() const { return bHasTextContent || bHasTableContent; }
424 inline void _InsertContent();
425 inline void InsertContent();
426 inline void InsertContentIfNotThere();
427 inline void InsertContent( SwXMLTableContext *pTable );
429 public:
431 SwXMLTableCellContext_Impl(
432 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
433 const Reference< xml::sax::XAttributeList > & xAttrList,
434 SwXMLTableContext *pTable );
436 virtual ~SwXMLTableCellContext_Impl();
438 virtual SvXMLImportContext *CreateChildContext(
439 sal_uInt16 nPrefix, const OUString& rLocalName,
440 const Reference< xml::sax::XAttributeList > & xAttrList );
441 virtual void EndElement();
443 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
446 SwXMLTableCellContext_Impl::SwXMLTableCellContext_Impl(
447 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
448 const Reference< xml::sax::XAttributeList > & xAttrList,
449 SwXMLTableContext *pTable ) :
450 SvXMLImportContext( rImport, nPrfx, rLName ),
451 sFormula(),
452 xMyTable( pTable ),
453 fValue( 0.0 ),
454 bHasValue( sal_False ),
455 bHasTextValue( sal_False ),
456 bProtect( sal_False ),
457 nRowSpan( 1UL ),
458 nColSpan( 1UL ),
459 nColRepeat( 1UL ),
460 bHasTextContent( sal_False ),
461 bHasTableContent( sal_False )
463 sSaveParaDefault = GetImport().GetTextImport()->sCellParaStyleDefault;
464 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
465 for( sal_Int16 i=0; i < nAttrCount; i++ )
467 const OUString& rAttrName = xAttrList->getNameByIndex( i );
469 OUString aLocalName;
470 sal_uInt16 nPrefix =
471 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
472 &aLocalName );
473 const OUString& rValue = xAttrList->getValueByIndex( i );
474 const SvXMLTokenMap& rTokenMap =
475 GetSwImport().GetTableCellAttrTokenMap();
476 switch( rTokenMap.Get( nPrefix, aLocalName ) )
478 case XML_TOK_TABLE_XMLID:
479 mXmlId = rValue;
480 break;
481 case XML_TOK_TABLE_STYLE_NAME:
482 aStyleName = rValue;
483 GetImport().GetTextImport()->sCellParaStyleDefault = rValue;
484 break;
485 case XML_TOK_TABLE_NUM_COLS_SPANNED:
486 nColSpan = (sal_uInt32)rValue.toInt32();
487 if( nColSpan < 1UL )
488 nColSpan = 1UL;
489 break;
490 case XML_TOK_TABLE_NUM_ROWS_SPANNED:
491 nRowSpan = (sal_uInt32)rValue.toInt32();
492 if( nRowSpan < 1UL )
493 nRowSpan = 1UL;
494 break;
495 case XML_TOK_TABLE_NUM_COLS_REPEATED:
496 nColRepeat = (sal_uInt32)rValue.toInt32();
497 if( nColRepeat < 1UL )
498 nColRepeat = 1UL;
499 break;
500 case XML_TOK_TABLE_FORMULA:
502 OUString sTmp;
503 sal_uInt16 nPrefix2 = GetImport().GetNamespaceMap().
504 _GetKeyByAttrName( rValue, &sTmp, sal_False );
505 sFormula = XML_NAMESPACE_OOOW == nPrefix2 ? sTmp : rValue;
507 break;
508 case XML_TOK_TABLE_VALUE:
510 double fTmp;
511 if (SvXMLUnitConverter::convertDouble(fTmp, rValue))
513 fValue = fTmp;
514 bHasValue = sal_True;
517 break;
518 case XML_TOK_TABLE_TIME_VALUE:
520 double fTmp;
521 if (SvXMLUnitConverter::convertTime(fTmp, rValue))
523 fValue = fTmp;
524 bHasValue = sal_True;
527 break;
528 case XML_TOK_TABLE_DATE_VALUE:
530 double fTmp;
531 if (GetImport().GetMM100UnitConverter().convertDateTime(fTmp,
532 rValue))
534 fValue = fTmp;
535 bHasValue = sal_True;
538 break;
539 case XML_TOK_TABLE_BOOLEAN_VALUE:
541 sal_Bool bTmp;
542 if (SvXMLUnitConverter::convertBool(bTmp, rValue))
544 fValue = (bTmp ? 1.0 : 0.0);
545 bHasValue = sal_True;
548 break;
549 case XML_TOK_TABLE_PROTECTED:
551 sal_Bool bTmp;
552 if (SvXMLUnitConverter::convertBool(bTmp, rValue))
554 bProtect = bTmp;
557 break;
558 case XML_TOK_TABLE_STRING_VALUE:
560 bHasTextValue = sal_True;
562 break;
567 SwXMLTableCellContext_Impl::~SwXMLTableCellContext_Impl()
571 inline void SwXMLTableCellContext_Impl::_InsertContent()
573 GetTable()->InsertCell( aStyleName, nRowSpan, nColSpan,
574 GetTable()->InsertTableSection(),
575 mXmlId,
576 NULL, bProtect, &sFormula, bHasValue, fValue, bHasTextValue );
579 inline void SwXMLTableCellContext_Impl::InsertContent()
581 ASSERT( !HasContent(), "content already there" );
582 bHasTextContent = sal_True;
583 _InsertContent();
586 inline void SwXMLTableCellContext_Impl::InsertContentIfNotThere()
588 if( !HasContent() )
589 InsertContent();
592 inline void SwXMLTableCellContext_Impl::InsertContent(
593 SwXMLTableContext *pTable )
595 GetTable()->InsertCell( aStyleName, nRowSpan, nColSpan, 0, mXmlId, pTable, bProtect );
596 bHasTableContent = sal_True;
599 SvXMLImportContext *SwXMLTableCellContext_Impl::CreateChildContext(
600 sal_uInt16 nPrefix,
601 const OUString& rLocalName,
602 const Reference< xml::sax::XAttributeList > & xAttrList )
604 SvXMLImportContext *pContext = 0;
606 OUString sXmlId;
607 sal_Bool bSubTable = sal_False;
608 if( XML_NAMESPACE_TABLE == nPrefix &&
609 IsXMLToken( rLocalName, XML_TABLE ) )
611 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
612 for( sal_Int16 i=0; i < nAttrCount; i++ )
614 const OUString& rAttrName = xAttrList->getNameByIndex( i );
616 OUString aLocalName;
617 sal_uInt16 nPrefix2 =
618 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
619 &aLocalName );
620 if( XML_NAMESPACE_TABLE == nPrefix2 &&
621 IsXMLToken( aLocalName, XML_IS_SUB_TABLE ) &&
622 IsXMLToken( xAttrList->getValueByIndex( i ), XML_TRUE ) )
624 bSubTable = sal_True;
626 else if ( (XML_NAMESPACE_XML == nPrefix2) &&
627 IsXMLToken( aLocalName, XML_ID ) )
629 sXmlId = xAttrList->getValueByIndex( i );
631 //FIXME: RDFa
635 if( bSubTable )
637 if( !HasContent() )
639 SwXMLTableContext *pTblContext =
640 new SwXMLTableContext( GetSwImport(), nPrefix, rLocalName,
641 xAttrList, GetTable(), sXmlId );
642 pContext = pTblContext;
643 if( GetTable()->IsValid() )
644 InsertContent( pTblContext );
646 GetTable()->SetHasSubTables( sal_True );
649 else
651 if( GetTable()->IsValid() )
652 InsertContentIfNotThere();
653 pContext = GetImport().GetTextImport()->CreateTextChildContext(
654 GetImport(), nPrefix, rLocalName, xAttrList,
655 XML_TEXT_TYPE_CELL );
658 if( !pContext )
659 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
661 return pContext;
664 void SwXMLTableCellContext_Impl::EndElement()
666 if( GetTable()->IsValid() )
668 if( bHasTextContent )
670 GetImport().GetTextImport()->DeleteParagraph();
671 if( nColRepeat > 1 && nColSpan == 1 )
673 // The original text is invalid after deleting the last
674 // paragraph
675 Reference < XTextCursor > xSrcTxtCursor =
676 GetImport().GetTextImport()->GetText()->createTextCursor();
677 xSrcTxtCursor->gotoEnd( sal_True );
679 // Until we have an API for copying we have to use the core.
680 Reference<XUnoTunnel> xSrcCrsrTunnel( xSrcTxtCursor, UNO_QUERY);
681 ASSERT( xSrcCrsrTunnel.is(), "missing XUnoTunnel for Cursor" );
682 OTextCursorHelper *pSrcTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
683 sal::static_int_cast< sal_IntPtr >( xSrcCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )));
684 ASSERT( pSrcTxtCrsr, "SwXTextCursor missing" );
685 SwDoc *pDoc = pSrcTxtCrsr->GetDoc();
686 const SwPaM *pSrcPaM = pSrcTxtCrsr->GetPaM();
688 while( nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
690 _InsertContent();
692 Reference<XUnoTunnel> xDstCrsrTunnel(
693 GetImport().GetTextImport()->GetCursor(), UNO_QUERY);
694 ASSERT( xDstCrsrTunnel.is(),
695 "missing XUnoTunnel for Cursor" );
696 OTextCursorHelper *pDstTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
697 sal::static_int_cast< sal_IntPtr >( xDstCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )) );
698 ASSERT( pDstTxtCrsr, "SwXTextCursor missing" );
699 SwPaM aSrcPaM( *pSrcPaM->GetPoint(),
700 *pSrcPaM->GetMark() );
701 SwPosition aDstPos( *pDstTxtCrsr->GetPaM()->GetPoint() );
702 pDoc->CopyRange( aSrcPaM, aDstPos, false );
704 nColRepeat--;
708 else if( !bHasTableContent )
710 InsertContent();
711 if( nColRepeat > 1 && nColSpan == 1 )
713 while( nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
715 _InsertContent();
716 nColRepeat--;
721 GetImport().GetTextImport()->sCellParaStyleDefault = sSaveParaDefault;
724 // ---------------------------------------------------------------------
726 class SwXMLTableColContext_Impl : public SvXMLImportContext
728 SvXMLImportContextRef xMyTable;
730 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
732 public:
734 SwXMLTableColContext_Impl(
735 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
736 const Reference< xml::sax::XAttributeList > & xAttrList,
737 SwXMLTableContext *pTable );
739 virtual ~SwXMLTableColContext_Impl();
741 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
744 SwXMLTableColContext_Impl::SwXMLTableColContext_Impl(
745 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
746 const Reference< xml::sax::XAttributeList > & xAttrList,
747 SwXMLTableContext *pTable ) :
748 SvXMLImportContext( rImport, nPrfx, rLName ),
749 xMyTable( pTable )
751 sal_uInt32 nColRep = 1UL;
752 OUString aStyleName, aDfltCellStyleName;
754 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
755 for( sal_Int16 i=0; i < nAttrCount; i++ )
757 const OUString& rAttrName = xAttrList->getNameByIndex( i );
759 OUString aLocalName;
760 sal_uInt16 nPrefix =
761 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
762 &aLocalName );
763 const OUString& rValue = xAttrList->getValueByIndex( i );
764 if( XML_NAMESPACE_TABLE == nPrefix )
766 if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
767 aStyleName = rValue;
768 else if( IsXMLToken( aLocalName, XML_NUMBER_COLUMNS_REPEATED ) )
769 nColRep = (sal_uInt32)rValue.toInt32();
770 else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
771 aDfltCellStyleName = rValue;
773 else if ( (XML_NAMESPACE_XML == nPrefix) &&
774 IsXMLToken( aLocalName, XML_ID ) )
776 (void) rValue;
777 //FIXME where to put this??? columns do not actually exist in writer...
781 sal_Int32 nWidth = MINLAY;
782 sal_Bool bRelWidth = sal_True;
783 if( aStyleName.getLength() )
785 const SfxPoolItem *pItem;
786 const SfxItemSet *pAutoItemSet = 0;
787 if( GetSwImport().FindAutomaticStyle(
788 XML_STYLE_FAMILY_TABLE_COLUMN,
789 aStyleName, &pAutoItemSet ) &&
790 pAutoItemSet &&
791 SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_FRM_SIZE, sal_False,
792 &pItem ) )
794 const SwFmtFrmSize *pSize = ((const SwFmtFrmSize *)pItem);
795 nWidth = pSize->GetWidth();
796 bRelWidth = ATT_VAR_SIZE == pSize->GetHeightSizeType();
800 if( nWidth )
802 while( nColRep-- && GetTable()->IsInsertColPossible() )
803 GetTable()->InsertColumn( nWidth, bRelWidth, &aDfltCellStyleName );
807 SwXMLTableColContext_Impl::~SwXMLTableColContext_Impl()
811 // ---------------------------------------------------------------------
813 class SwXMLTableColsContext_Impl : public SvXMLImportContext
815 SvXMLImportContextRef xMyTable;
816 sal_Bool bHeader;
818 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
820 public:
822 SwXMLTableColsContext_Impl(
823 SwXMLImport& rImport, sal_uInt16 nPrfx,
824 const OUString& rLName,
825 const Reference< xml::sax::XAttributeList > & xAttrList,
826 SwXMLTableContext *pTable,
827 sal_Bool bHead );
829 virtual ~SwXMLTableColsContext_Impl();
831 virtual SvXMLImportContext *CreateChildContext(
832 sal_uInt16 nPrefix, const OUString& rLocalName,
833 const Reference< xml::sax::XAttributeList > & xAttrList );
835 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
838 SwXMLTableColsContext_Impl::SwXMLTableColsContext_Impl(
839 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
840 const Reference< xml::sax::XAttributeList > &,
841 SwXMLTableContext *pTable, sal_Bool bHead ) :
842 SvXMLImportContext( rImport, nPrfx, rLName ),
843 xMyTable( pTable ),
844 bHeader( bHead )
848 SwXMLTableColsContext_Impl::~SwXMLTableColsContext_Impl()
852 SvXMLImportContext *SwXMLTableColsContext_Impl::CreateChildContext(
853 sal_uInt16 nPrefix,
854 const OUString& rLocalName,
855 const Reference< xml::sax::XAttributeList > & xAttrList )
857 SvXMLImportContext *pContext = 0;
859 if( XML_NAMESPACE_TABLE == nPrefix &&
860 IsXMLToken( rLocalName, XML_TABLE_COLUMN ) &&
861 GetTable()->IsInsertColPossible() )
862 pContext = new SwXMLTableColContext_Impl( GetSwImport(), nPrefix,
863 rLocalName, xAttrList,
864 GetTable() );
866 if( !pContext )
867 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
869 return pContext;
872 // ---------------------------------------------------------------------
874 class SwXMLTableRowContext_Impl : public SvXMLImportContext
876 SvXMLImportContextRef xMyTable;
878 sal_uInt32 nRowRepeat;
880 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
882 public:
884 SwXMLTableRowContext_Impl(
885 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
886 const Reference< xml::sax::XAttributeList > & xAttrList,
887 SwXMLTableContext *pTable, sal_Bool bInHead=sal_False );
889 virtual ~SwXMLTableRowContext_Impl();
891 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
892 const OUString& rLocalName,
893 const Reference< xml::sax::XAttributeList > & xAttrList );
895 virtual void EndElement();
897 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
900 SwXMLTableRowContext_Impl::SwXMLTableRowContext_Impl( SwXMLImport& rImport,
901 sal_uInt16 nPrfx,
902 const OUString& rLName,
903 const Reference< xml::sax::XAttributeList > & xAttrList,
904 SwXMLTableContext *pTable,
905 sal_Bool bInHead ) :
906 SvXMLImportContext( rImport, nPrfx, rLName ),
907 xMyTable( pTable ),
908 nRowRepeat( 1 )
910 OUString aStyleName, aDfltCellStyleName;
911 OUString sXmlId;
913 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
914 for( sal_Int16 i=0; i < nAttrCount; i++ )
916 const OUString& rAttrName = xAttrList->getNameByIndex( i );
918 OUString aLocalName;
919 sal_uInt16 nPrefix =
920 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
921 &aLocalName );
922 const OUString& rValue = xAttrList->getValueByIndex( i );
923 if( XML_NAMESPACE_TABLE == nPrefix )
925 if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
927 aStyleName = rValue;
929 else if( IsXMLToken( aLocalName, XML_NUMBER_ROWS_REPEATED ) )
931 nRowRepeat = (sal_uInt32)rValue.toInt32();
932 if( nRowRepeat < 1UL )
933 nRowRepeat = 1UL;
935 else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
937 aDfltCellStyleName = rValue;
940 else if ( (XML_NAMESPACE_XML == nPrefix) &&
941 IsXMLToken( aLocalName, XML_ID ) )
943 sXmlId = rValue;
946 if( GetTable()->IsValid() )
947 GetTable()->InsertRow( aStyleName, aDfltCellStyleName, bInHead,
948 sXmlId );
951 void SwXMLTableRowContext_Impl::EndElement()
953 if( GetTable()->IsValid() )
955 GetTable()->FinishRow();
957 if( nRowRepeat > 1UL )
958 GetTable()->InsertRepRows( nRowRepeat );
962 SwXMLTableRowContext_Impl::~SwXMLTableRowContext_Impl()
966 SvXMLImportContext *SwXMLTableRowContext_Impl::CreateChildContext(
967 sal_uInt16 nPrefix, const OUString& rLocalName,
968 const Reference< xml::sax::XAttributeList > & xAttrList )
970 SvXMLImportContext *pContext = 0;
972 if( XML_NAMESPACE_TABLE == nPrefix )
974 if( IsXMLToken( rLocalName, XML_TABLE_CELL ) )
976 if( !GetTable()->IsValid() || GetTable()->IsInsertCellPossible() )
977 pContext = new SwXMLTableCellContext_Impl( GetSwImport(),
978 nPrefix,
979 rLocalName,
980 xAttrList,
981 GetTable() );
983 else if( IsXMLToken( rLocalName, XML_COVERED_TABLE_CELL ) )
984 pContext = new SvXMLImportContext( GetImport(), nPrefix,
985 rLocalName );
988 if( !pContext )
989 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
991 return pContext;
994 // ---------------------------------------------------------------------
996 class SwXMLTableRowsContext_Impl : public SvXMLImportContext
998 SvXMLImportContextRef xMyTable;
1000 sal_Bool bHeader;
1002 SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
1004 public:
1006 SwXMLTableRowsContext_Impl( SwXMLImport& rImport, sal_uInt16 nPrfx,
1007 const OUString& rLName,
1008 const Reference< xml::sax::XAttributeList > & xAttrList,
1009 SwXMLTableContext *pTable,
1010 sal_Bool bHead );
1012 virtual ~SwXMLTableRowsContext_Impl();
1014 virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
1015 const OUString& rLocalName,
1016 const Reference< xml::sax::XAttributeList > & xAttrList );
1018 SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
1021 SwXMLTableRowsContext_Impl::SwXMLTableRowsContext_Impl( SwXMLImport& rImport,
1022 sal_uInt16 nPrfx,
1023 const OUString& rLName,
1024 const Reference< xml::sax::XAttributeList > &,
1025 SwXMLTableContext *pTable,
1026 sal_Bool bHead ) :
1027 SvXMLImportContext( rImport, nPrfx, rLName ),
1028 xMyTable( pTable ),
1029 bHeader( bHead )
1033 SwXMLTableRowsContext_Impl::~SwXMLTableRowsContext_Impl()
1037 SvXMLImportContext *SwXMLTableRowsContext_Impl::CreateChildContext(
1038 sal_uInt16 nPrefix,
1039 const OUString& rLocalName,
1040 const Reference< xml::sax::XAttributeList > & xAttrList )
1042 SvXMLImportContext *pContext = 0;
1044 if( XML_NAMESPACE_TABLE == nPrefix &&
1045 IsXMLToken( rLocalName, XML_TABLE_ROW ) &&
1046 GetTable()->IsInsertRowPossible() )
1047 pContext = new SwXMLTableRowContext_Impl( GetSwImport(), nPrefix,
1048 rLocalName, xAttrList,
1049 GetTable(),
1050 bHeader );
1052 if( !pContext )
1053 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1055 return pContext;
1058 // ---------------------------------------------------------------------
1060 class SwXMLDDETableContext_Impl : public SvXMLImportContext
1062 OUString sConnectionName;
1063 OUString sDDEApplication;
1064 OUString sDDEItem;
1065 OUString sDDETopic;
1066 sal_Bool bIsAutomaticUpdate;
1068 public:
1070 TYPEINFO();
1072 SwXMLDDETableContext_Impl(
1073 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName);
1075 ~SwXMLDDETableContext_Impl();
1077 virtual void StartElement(
1078 const Reference<xml::sax::XAttributeList> & xAttrList);
1080 OUString& GetConnectionName() { return sConnectionName; }
1081 OUString& GetDDEApplication() { return sDDEApplication; }
1082 OUString& GetDDEItem() { return sDDEItem; }
1083 OUString& GetDDETopic() { return sDDETopic; }
1084 sal_Bool GetIsAutomaticUpdate() { return bIsAutomaticUpdate; }
1087 TYPEINIT1( SwXMLDDETableContext_Impl, SvXMLImportContext );
1089 SwXMLDDETableContext_Impl::SwXMLDDETableContext_Impl(
1090 SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName) :
1091 SvXMLImportContext(rImport, nPrfx, rLName),
1092 sConnectionName(),
1093 sDDEApplication(),
1094 sDDEItem(),
1095 sDDETopic(),
1096 bIsAutomaticUpdate(sal_False)
1100 SwXMLDDETableContext_Impl::~SwXMLDDETableContext_Impl()
1104 void SwXMLDDETableContext_Impl::StartElement(
1105 const Reference<xml::sax::XAttributeList> & xAttrList)
1107 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
1108 for( sal_Int16 i = 0; i < nAttrCount; i++ )
1110 const OUString& rAttrName = xAttrList->getNameByIndex( i );
1112 OUString aLocalName;
1113 sal_uInt16 nPrefix =
1114 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
1115 &aLocalName );
1116 const OUString& rValue = xAttrList->getValueByIndex( i );
1118 if (XML_NAMESPACE_OFFICE == nPrefix)
1120 if ( IsXMLToken( aLocalName, XML_DDE_APPLICATION ) )
1122 sDDEApplication = rValue;
1124 else if ( IsXMLToken( aLocalName, XML_DDE_TOPIC ) )
1126 sDDETopic = rValue;
1128 else if ( IsXMLToken( aLocalName, XML_DDE_ITEM ) )
1130 sDDEItem = rValue;
1132 else if ( IsXMLToken( aLocalName, XML_NAME ) )
1134 sConnectionName = rValue;
1136 else if ( IsXMLToken( aLocalName, XML_AUTOMATIC_UPDATE ) )
1138 sal_Bool bTmp;
1139 if (SvXMLUnitConverter::convertBool(bTmp, rValue))
1141 bIsAutomaticUpdate = bTmp;
1144 // else: unknown attribute
1146 // else: unknown attribute namespace
1150 // generate a new name for DDE field type (called by lcl_GetDDEFieldType below)
1151 String lcl_GenerateFldTypeName(OUString sPrefix, SwTableNode* pTableNode)
1153 String sPrefixStr(sPrefix);
1155 if (sPrefixStr.Len() == 0)
1157 sPrefixStr = String('_');
1159 // else if (sPrefixStr.Copy(0, 1).IsAlphaAscii())
1160 // {
1161 // sPrefixStr.Insert('_', 0);
1162 // }
1163 // else: name is OK.
1165 // increase count until we find a name that is not yet taken
1166 String sName;
1167 sal_Int32 nCount = 0;
1170 // this is crazy, but just in case all names are taken: exit gracefully
1171 if (nCount < 0)
1172 return sName;
1174 nCount++;
1175 sName = sPrefixStr;
1176 sName += String::CreateFromInt32(nCount);
1179 while (NULL != pTableNode->GetDoc()->GetFldType(RES_DDEFLD, sName, false));
1181 return sName;
1184 // set table properties
1185 SwDDEFieldType* lcl_GetDDEFieldType(SwXMLDDETableContext_Impl* pContext,
1186 SwTableNode* pTableNode)
1188 // make command string
1189 String sCommand(pContext->GetDDEApplication());
1190 sCommand += sfx2::cTokenSeperator;
1191 sCommand += String(pContext->GetDDEItem());
1192 sCommand += sfx2::cTokenSeperator;
1193 sCommand += String(pContext->GetDDETopic());
1195 sal_uInt16 nType = static_cast< sal_uInt16 >(pContext->GetIsAutomaticUpdate() ? sfx2::LINKUPDATE_ALWAYS
1196 : sfx2::LINKUPDATE_ONCALL);
1198 String sName(pContext->GetConnectionName());
1200 // field type to be returned
1201 SwDDEFieldType* pType = NULL;
1203 // valid name?
1204 if (sName.Len() == 0)
1206 sName = lcl_GenerateFldTypeName(pContext->GetDDEApplication(),
1207 pTableNode);
1209 else
1211 // check for existing DDE field type with the same name
1212 SwDDEFieldType* pOldType = (SwDDEFieldType*)pTableNode->GetDoc()->GetFldType(RES_DDEFLD, sName, false);
1213 if (NULL != pOldType)
1215 // same values -> return old type
1216 if ( (pOldType->GetCmd() == sCommand) &&
1217 (pOldType->GetType() == nType) )
1219 // same name, same values -> return old type!
1220 pType = pOldType;
1222 else
1224 // same name, different values -> think of new name
1225 sName = lcl_GenerateFldTypeName(pContext->GetDDEApplication(),
1226 pTableNode);
1229 // no old type -> create new one
1232 // create new field type (unless we already have one)
1233 if (NULL == pType)
1235 // create new field type and return
1236 SwDDEFieldType aDDEFieldType(sName, sCommand, nType);
1237 pType = (SwDDEFieldType*)pTableNode->
1238 GetDoc()->InsertFldType(aDDEFieldType);
1241 DBG_ASSERT(NULL != pType, "We really want a SwDDEFieldType here!");
1242 return pType;
1246 // ---------------------------------------------------------------------
1248 class TableBoxIndex
1250 public:
1251 OUString msName;
1252 sal_Int32 mnWidth;
1253 sal_Bool mbProtected;
1255 TableBoxIndex( const OUString& rName, sal_Int32 nWidth,
1256 sal_Bool bProtected ) :
1257 msName( rName ),
1258 mnWidth( nWidth ),
1259 mbProtected( bProtected )
1262 bool operator== ( const TableBoxIndex& rArg ) const
1264 return (rArg.mnWidth == mnWidth) &&
1265 (rArg.mbProtected == mbProtected) &&
1266 (rArg.msName == msName);
1270 class TableBoxIndexHasher
1272 public:
1273 size_t operator() (const TableBoxIndex& rArg) const
1275 return rArg.msName.hashCode() + rArg.mnWidth + rArg.mbProtected;
1282 typedef SwXMLTableRow_Impl* SwXMLTableRowPtr;
1283 SV_DECL_PTRARR_DEL(SwXMLTableRows_Impl,SwXMLTableRowPtr,5,5)
1284 SV_IMPL_PTRARR(SwXMLTableRows_Impl,SwXMLTableRowPtr)
1286 SwXMLTableCell_Impl *SwXMLTableContext::GetCell( sal_uInt32 nRow,
1287 sal_uInt32 nCol ) const
1289 return (*pRows)[(sal_uInt16)nRow]->GetCell( (sal_uInt16)nCol );
1292 TYPEINIT1( SwXMLTableContext, XMLTextTableContext );
1294 SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
1295 sal_uInt16 nPrfx,
1296 const OUString& rLName,
1297 const Reference< xml::sax::XAttributeList > & xAttrList ) :
1298 XMLTextTableContext( rImport, nPrfx, rLName ),
1299 pColumnDefaultCellStyleNames( 0 ),
1300 pRows( new SwXMLTableRows_Impl ),
1301 pTableNode( 0 ),
1302 pBox1( 0 ),
1303 pSttNd1( 0 ),
1304 pBoxFmt( 0 ),
1305 pLineFmt( 0 ),
1306 pSharedBoxFormats(NULL),
1307 pDDESource(NULL),
1308 bFirstSection( sal_True ),
1309 bRelWidth( sal_True ),
1310 bHasSubTables( sal_False ),
1311 nHeaderRows( 0 ),
1312 nCurRow( 0UL ),
1313 nCurCol( 0UL ),
1314 nWidth( 0UL )
1316 OUString aName;
1317 OUString sXmlId;
1319 // this method will modify the document directly -> lock SolarMutex
1320 vos::OGuard aGuard(Application::GetSolarMutex());
1322 sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
1323 for( sal_Int16 i=0; i < nAttrCount; i++ )
1325 const OUString& rAttrName = xAttrList->getNameByIndex( i );
1327 OUString aLocalName;
1328 sal_uInt16 nPrefix =
1329 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
1330 &aLocalName );
1331 const OUString& rValue = xAttrList->getValueByIndex( i );
1332 if( XML_NAMESPACE_TABLE == nPrefix )
1334 if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
1335 aStyleName = rValue;
1336 else if( IsXMLToken( aLocalName, XML_NAME ) )
1337 aName = rValue;
1338 else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
1339 aDfltCellStyleName = rValue;
1341 else if ( (XML_NAMESPACE_XML == nPrefix) &&
1342 IsXMLToken( aLocalName, XML_ID ) )
1344 sXmlId = rValue;
1348 SwDoc *pDoc = SwImport::GetDocFromXMLImport( GetSwImport() );
1350 String sTblName;
1351 if( aName.getLength() )
1353 const SwTableFmt *pTblFmt = pDoc->FindTblFmtByName( aName );
1354 if( !pTblFmt )
1355 sTblName = aName;
1357 if( !sTblName.Len() )
1359 sTblName = pDoc->GetUniqueTblName();
1360 GetImport().GetTextImport()
1361 ->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_TABLE, aName, sTblName );
1364 Reference< XTextTable > xTable;
1365 const SwXTextTable *pXTable = 0;
1366 Reference<XMultiServiceFactory> xFactory( GetImport().GetModel(),
1367 UNO_QUERY );
1368 ASSERT( xFactory.is(), "factory missing" );
1369 if( xFactory.is() )
1371 OUString sService(
1372 RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.TextTable" ) );
1373 Reference<XInterface> xIfc = xFactory->createInstance( sService );
1374 ASSERT( xIfc.is(), "Couldn't create a table" );
1376 if( xIfc.is() )
1377 xTable = Reference< XTextTable > ( xIfc, UNO_QUERY );
1380 if( xTable.is() )
1382 xTable->initialize( 1, 1 );
1386 xTextContent = Reference< XTextContent >( xTable, UNO_QUERY );
1387 GetImport().GetTextImport()->InsertTextContent( xTextContent );
1389 catch( IllegalArgumentException& )
1391 xTable = 0;
1395 if( xTable.is() )
1397 //FIXME
1398 // xml:id for RDF metadata
1399 GetImport().SetXmlId(xTable, sXmlId);
1401 Reference<XUnoTunnel> xTableTunnel( xTable, UNO_QUERY);
1402 if( xTableTunnel.is() )
1404 pXTable = reinterpret_cast< SwXTextTable * >(
1405 sal::static_int_cast< sal_IntPtr >( xTableTunnel->getSomething( SwXTextTable::getUnoTunnelId() )));
1406 ASSERT( pXTable, "SwXTextTable missing" );
1409 Reference < XCellRange > xCellRange( xTable, UNO_QUERY );
1410 Reference < XCell > xCell = xCellRange->getCellByPosition( 0, 0 );
1411 Reference < XText> xText( xCell, UNO_QUERY );
1412 xOldCursor = GetImport().GetTextImport()->GetCursor();
1413 GetImport().GetTextImport()->SetCursor( xText->createTextCursor() );
1415 // take care of open redlines for tables
1416 GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(sal_True);
1418 if( pXTable )
1420 SwFrmFmt *pTblFrmFmt = pXTable->GetFrmFmt();
1421 ASSERT( pTblFrmFmt, "table format missing" );
1422 SwTable *pTbl = SwTable::FindTable( pTblFrmFmt );
1423 ASSERT( pTbl, "table missing" );
1424 pTableNode = pTbl->GetTableNode();
1425 ASSERT( pTableNode, "table node missing" );
1427 pTblFrmFmt->SetName( sTblName );
1429 SwTableLine *pLine1 = pTableNode->GetTable().GetTabLines()[0U];
1430 pBox1 = pLine1->GetTabBoxes()[0U];
1431 pSttNd1 = pBox1->GetSttNd();
1435 SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
1436 sal_uInt16 nPrfx,
1437 const OUString& rLName,
1438 const Reference< xml::sax::XAttributeList > &,
1439 SwXMLTableContext *pTable,
1440 OUString const & i_rXmlId ) :
1441 XMLTextTableContext( rImport, nPrfx, rLName ),
1442 mXmlId( i_rXmlId ),
1443 pColumnDefaultCellStyleNames( 0 ),
1444 pRows( new SwXMLTableRows_Impl ),
1445 pTableNode( pTable->pTableNode ),
1446 pBox1( 0 ),
1447 pSttNd1( 0 ),
1448 pBoxFmt( 0 ),
1449 pLineFmt( 0 ),
1450 pSharedBoxFormats(NULL),
1451 xParentTable( pTable ),
1452 pDDESource(NULL),
1453 bFirstSection( sal_False ),
1454 bRelWidth( sal_True ),
1455 bHasSubTables( sal_False ),
1456 nHeaderRows( 0 ),
1457 nCurRow( 0UL ),
1458 nCurCol( 0UL ),
1459 nWidth( 0UL )
1463 SwXMLTableContext::~SwXMLTableContext()
1465 delete pColumnDefaultCellStyleNames;
1466 delete pSharedBoxFormats;
1467 delete pRows;
1469 // close redlines on table end nodes
1470 GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(sal_False);
1473 SvXMLImportContext *SwXMLTableContext::CreateChildContext( sal_uInt16 nPrefix,
1474 const OUString& rLocalName,
1475 const Reference< xml::sax::XAttributeList > & xAttrList )
1477 SvXMLImportContext *pContext = 0;
1479 const SvXMLTokenMap& rTokenMap = GetSwImport().GetTableElemTokenMap();
1480 sal_Bool bHeader = sal_False;
1481 switch( rTokenMap.Get( nPrefix, rLocalName ) )
1483 case XML_TOK_TABLE_HEADER_COLS:
1484 bHeader = sal_True;
1485 case XML_TOK_TABLE_COLS:
1486 if( IsValid() )
1487 pContext = new SwXMLTableColsContext_Impl( GetSwImport(), nPrefix,
1488 rLocalName, xAttrList,
1489 this, bHeader );
1490 break;
1491 case XML_TOK_TABLE_COL:
1492 if( IsValid() && IsInsertColPossible() )
1493 pContext = new SwXMLTableColContext_Impl( GetSwImport(), nPrefix,
1494 rLocalName, xAttrList,
1495 this );
1496 break;
1497 case XML_TOK_TABLE_HEADER_ROWS:
1498 bHeader = sal_True;
1499 case XML_TOK_TABLE_ROWS:
1500 pContext = new SwXMLTableRowsContext_Impl( GetSwImport(), nPrefix,
1501 rLocalName, xAttrList,
1502 this, bHeader );
1503 break;
1504 case XML_TOK_TABLE_ROW:
1505 if( IsInsertRowPossible() )
1506 pContext = new SwXMLTableRowContext_Impl( GetSwImport(), nPrefix,
1507 rLocalName, xAttrList,
1508 this );
1509 break;
1510 case XML_TOK_OFFICE_DDE_SOURCE:
1511 // save context for later processing (discard old context, if approp.)
1512 if( IsValid() )
1514 if (pDDESource != NULL)
1516 pDDESource->ReleaseRef();
1518 pDDESource = new SwXMLDDETableContext_Impl( GetSwImport(), nPrefix,
1519 rLocalName );
1520 pDDESource->AddRef();
1521 pContext = pDDESource;
1523 break;
1526 if( !pContext )
1527 pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1529 return pContext;
1532 void SwXMLTableContext::InsertColumn( sal_Int32 nWidth2, sal_Bool bRelWidth2,
1533 const OUString *pDfltCellStyleName )
1535 ASSERT( nCurCol < USHRT_MAX,
1536 "SwXMLTableContext::InsertColumn: no space left" );
1537 if( nCurCol >= USHRT_MAX )
1538 return;
1540 if( nWidth2 < MINLAY )
1541 nWidth2 = MINLAY;
1542 else if( nWidth2 > USHRT_MAX )
1543 nWidth2 = USHRT_MAX;
1544 aColumnWidths.Insert( (sal_uInt16)nWidth2, aColumnWidths.Count() );
1545 aColumnRelWidths.Insert( bRelWidth2, aColumnRelWidths.Count() );
1546 if( (pDfltCellStyleName && pDfltCellStyleName->getLength() > 0) ||
1547 pColumnDefaultCellStyleNames )
1549 if( !pColumnDefaultCellStyleNames )
1551 pColumnDefaultCellStyleNames = new SvStringsDtor;
1552 sal_uInt16 nCount = aColumnRelWidths.Count() - 1;
1553 while( nCount-- )
1554 pColumnDefaultCellStyleNames->Insert( new String,
1555 pColumnDefaultCellStyleNames->Count() );
1558 pColumnDefaultCellStyleNames->Insert(
1559 pDfltCellStyleName ? new String( *pDfltCellStyleName ) : new String,
1560 pColumnDefaultCellStyleNames->Count() );
1564 sal_Int32 SwXMLTableContext::GetColumnWidth( sal_uInt32 nCol,
1565 sal_uInt32 nColSpan ) const
1567 sal_uInt32 nLast = nCol+nColSpan;
1568 if( nLast > aColumnWidths.Count() )
1569 nLast = aColumnWidths.Count();
1571 sal_Int32 nWidth2 = 0L;
1572 for( sal_uInt16 i=(sal_uInt16)nCol; i < nLast; i++ )
1573 nWidth2 += aColumnWidths[i];
1575 return nWidth2;
1578 OUString SwXMLTableContext::GetColumnDefaultCellStyleName( sal_uInt32 nCol ) const
1580 OUString sRet;
1581 if( pColumnDefaultCellStyleNames )
1582 sRet = *(*pColumnDefaultCellStyleNames)[(sal_uInt16)nCol];
1584 return sRet;
1587 void SwXMLTableContext::InsertCell( const OUString& rStyleName,
1588 sal_uInt32 nRowSpan, sal_uInt32 nColSpan,
1589 const SwStartNode *pStartNode,
1590 const OUString & i_rXmlId,
1591 SwXMLTableContext *pTable,
1592 sal_Bool bProtect,
1593 const OUString* pFormula,
1594 sal_Bool bHasValue,
1595 double fValue,
1596 sal_Bool bTextValue )
1598 ASSERT( nCurCol < GetColumnCount(),
1599 "SwXMLTableContext::InsertCell: row is full" );
1600 ASSERT( nCurRow < USHRT_MAX,
1601 "SwXMLTableContext::InsertCell: table is full" );
1602 if( nCurCol >= USHRT_MAX || nCurRow > USHRT_MAX )
1603 return;
1605 ASSERT( nRowSpan >=1UL, "SwXMLTableContext::InsertCell: row span is 0" );
1606 if( 0UL == nRowSpan )
1607 nRowSpan = 1UL;
1608 ASSERT( nColSpan >=1UL, "SwXMLTableContext::InsertCell: col span is 0" );
1609 if( 0UL == nColSpan )
1610 nColSpan = 1UL;
1612 sal_uInt32 i, j;
1614 // Until it is possible to add columns here, fix the column span.
1615 sal_uInt32 nColsReq = nCurCol + nColSpan;
1616 if( nColsReq > GetColumnCount() )
1618 nColSpan = GetColumnCount() - nCurCol;
1619 nColsReq = GetColumnCount();
1622 // Check whether there are cells from a previous line already that reach
1623 // into the current row.
1624 if( nCurRow > 0UL && nColSpan > 1UL )
1626 SwXMLTableRow_Impl *pCurRow = (*pRows)[(sal_uInt16)nCurRow];
1627 sal_uInt32 nLastCol = GetColumnCount() < nColsReq ? GetColumnCount()
1628 : nColsReq;
1629 for( i=nCurCol+1UL; i<nLastCol; i++ )
1631 if( pCurRow->GetCell(i)->IsUsed() )
1633 // If this cell is used, the column span is truncated
1634 nColSpan = i - nCurCol;
1635 nColsReq = i;
1636 break;
1641 sal_uInt32 nRowsReq = nCurRow + nRowSpan;
1642 if( nRowsReq > USHRT_MAX )
1644 nRowSpan = USHRT_MAX - nCurRow;
1645 nRowsReq = USHRT_MAX;
1648 // Add columns (if # required columns greater than # columns):
1649 // This should never happen, since we require column definitions!
1650 if ( nColsReq > GetColumnCount() )
1652 for( i=GetColumnCount(); i<nColsReq; i++ )
1654 aColumnWidths.Insert( MINLAY, aColumnWidths.Count() );
1655 aColumnRelWidths.Insert( sal_True, aColumnRelWidths.Count() );
1657 // adjust columns in *all* rows, if columns must be inserted
1658 for( i=0; i<pRows->Count(); i++ )
1659 (*pRows)[(sal_uInt16)i]->Expand( nColsReq, i<nCurRow );
1662 // Add rows
1663 if( pRows->Count() < nRowsReq )
1665 OUString aStyleName2;
1666 for( i = pRows->Count(); i < nRowsReq; ++i )
1667 pRows->Insert( new SwXMLTableRow_Impl(aStyleName2, GetColumnCount()),
1668 pRows->Count() );
1671 OUString sStyleName( rStyleName );
1672 if( !sStyleName.getLength() )
1674 sStyleName = ((*pRows)[(sal_uInt16)nCurRow])->GetDefaultCellStyleName();
1675 if( !sStyleName.getLength() && HasColumnDefaultCellStyleNames() )
1677 sStyleName = GetColumnDefaultCellStyleName( nCurCol );
1678 if( !sStyleName.getLength() )
1679 sStyleName = aDfltCellStyleName;
1683 // Fill the cells
1684 for( i=nColSpan; i>0UL; i-- )
1686 for( j=nRowSpan; j>0UL; j-- )
1688 const bool bCovered = i != nColSpan || j != nRowSpan;
1689 GetCell( nRowsReq-j, nColsReq-i )
1690 ->Set( sStyleName, j, i, pStartNode,
1691 pTable, bProtect, pFormula, bHasValue, bCovered, fValue,
1692 bTextValue, i_rXmlId );
1696 // Set current col to the next (free) column
1697 nCurCol = nColsReq;
1698 while( nCurCol<GetColumnCount() && GetCell(nCurRow,nCurCol)->IsUsed() )
1699 nCurCol++;
1702 void SwXMLTableContext::InsertRow( const OUString& rStyleName,
1703 const OUString& rDfltCellStyleName,
1704 sal_Bool bInHead,
1705 const OUString & i_rXmlId )
1707 ASSERT( nCurRow < USHRT_MAX,
1708 "SwXMLTableContext::InsertRow: no space left" );
1709 if( nCurRow >= USHRT_MAX )
1710 return;
1712 // Make sure there is at least one column.
1713 if( 0==nCurRow && 0UL == GetColumnCount() )
1714 InsertColumn( USHRT_MAX, sal_True );
1716 if( nCurRow < pRows->Count() )
1718 // The current row has already been inserted because of a row span
1719 // of a previous row.
1720 (*pRows)[(sal_uInt16)nCurRow]->Set(
1721 rStyleName, rDfltCellStyleName, i_rXmlId );
1723 else
1725 // add a new row
1726 pRows->Insert( new SwXMLTableRow_Impl( rStyleName, GetColumnCount(),
1727 &rDfltCellStyleName, i_rXmlId ),
1728 pRows->Count() );
1731 // We start at the first column ...
1732 nCurCol=0UL;
1734 // ... but this cell may be occupied already.
1735 while( nCurCol<GetColumnCount() && GetCell(nCurRow,nCurCol)->IsUsed() )
1736 nCurCol++;
1738 if( bInHead && nHeaderRows == nCurRow )
1739 nHeaderRows++;
1742 void SwXMLTableContext::InsertRepRows( sal_uInt32 nCount )
1744 const SwXMLTableRow_Impl *pSrcRow = (*pRows)[(sal_uInt16)nCurRow-1];
1745 while( nCount > 1 && IsInsertRowPossible() )
1747 InsertRow( pSrcRow->GetStyleName(), pSrcRow->GetDefaultCellStyleName(),
1748 sal_False );
1749 while( nCurCol < GetColumnCount() )
1751 if( !GetCell(nCurRow,nCurCol)->IsUsed() )
1753 const SwXMLTableCell_Impl *pSrcCell =
1754 GetCell( nCurRow-1, nCurCol );
1755 InsertCell( pSrcCell->GetStyleName(), 1U,
1756 pSrcCell->GetColSpan(),
1757 InsertTableSection(),
1758 OUString(),
1759 0, pSrcCell->IsProtected(),
1760 &pSrcCell->GetFormula(),
1761 pSrcCell->HasValue(), pSrcCell->GetValue(),
1762 pSrcCell->HasTextValue() );
1765 FinishRow();
1766 nCount--;
1770 void SwXMLTableContext::FinishRow()
1772 // Insert an empty cell at the end of the line if the row is not complete
1773 if( nCurCol < GetColumnCount() )
1775 OUString aStyleName2;
1776 InsertCell( aStyleName2, 1U, GetColumnCount() - nCurCol,
1777 InsertTableSection() );
1780 // Move to the next row.
1781 nCurRow++;
1784 const SwStartNode *SwXMLTableContext::GetPrevStartNode( sal_uInt32 nRow,
1785 sal_uInt32 nCol ) const
1787 const SwXMLTableCell_Impl *pPrevCell = 0;
1788 if( GetColumnCount() == nCol )
1790 // The last cell is the right one here.
1791 pPrevCell = GetCell( pRows->Count()-1U, GetColumnCount()-1UL );
1793 else if( 0UL == nRow )
1795 // There are no vertically merged cells within the first row, so the
1796 // previous cell is the right one always.
1797 if( nCol > 0UL )
1798 pPrevCell = GetCell( nRow, nCol-1UL );
1800 else
1802 // If there is a previous cell in the current row that is not spanned
1803 // from the previous row, its the right one.
1804 const SwXMLTableRow_Impl *pPrevRow = (*pRows)[(sal_uInt16)nRow-1U];
1805 sal_uInt32 i = nCol;
1806 while( !pPrevCell && i > 0UL )
1808 i--;
1809 if( 1UL == pPrevRow->GetCell( i )->GetRowSpan() )
1810 pPrevCell = GetCell( nRow, i );
1813 // Otherwise, the last cell from the previous row is the right one.
1814 if( !pPrevCell )
1815 pPrevCell = pPrevRow->GetCell( GetColumnCount()-1UL );
1818 const SwStartNode *pSttNd = 0;
1819 if( pPrevCell )
1821 if( pPrevCell->GetStartNode() )
1822 pSttNd = pPrevCell->GetStartNode();
1823 // --> OD 2009-03-19 #i95726# - Some fault tolerance
1824 // else
1825 else if ( pPrevCell->GetSubTable() )
1826 // <--
1827 pSttNd = pPrevCell->GetSubTable()->GetLastStartNode();
1829 ASSERT( pSttNd != 0,
1830 "table corrupt" );
1833 return pSttNd;
1836 void SwXMLTableContext::FixRowSpan( sal_uInt32 nRow, sal_uInt32 nCol,
1837 sal_uInt32 nColSpan )
1839 sal_uInt32 nLastCol = nCol + nColSpan;
1840 for( sal_uInt16 i = (sal_uInt16)nCol; i < nLastCol; i++ )
1842 sal_uInt32 j = nRow;
1843 sal_uInt32 nRowSpan = 1UL;
1844 SwXMLTableCell_Impl *pCell = GetCell( j, i );
1845 while( pCell && pCell->GetRowSpan() > 1UL )
1847 pCell->SetRowSpan( nRowSpan++ );
1848 pCell = j > 0UL ? GetCell( --j, i ) : 0;
1853 void SwXMLTableContext::ReplaceWithEmptyCell( sal_uInt32 nRow, sal_uInt32 nCol, bool bRows )
1855 const SwStartNode *pPrevSttNd = GetPrevStartNode( nRow, nCol );
1856 const SwStartNode *pSttNd = InsertTableSection( pPrevSttNd );
1858 const SwXMLTableCell_Impl *pCell = GetCell( nRow, nCol );
1859 sal_uInt32 nLastRow = bRows ? nRow + pCell->GetRowSpan() : nRow + 1;
1860 sal_uInt32 nLastCol = nCol + pCell->GetColSpan();
1862 for( sal_uInt32 i=nRow; i<nLastRow; i++ )
1864 SwXMLTableRow_Impl *pRow = (*pRows)[(sal_uInt16)i];
1865 for( sal_uInt32 j=nCol; j<nLastCol; j++ )
1866 pRow->GetCell( j )->SetStartNode( pSttNd );
1871 SwTableBox *SwXMLTableContext::NewTableBox( const SwStartNode *pStNd,
1872 SwTableLine *pUpper )
1874 // The topmost table is the only table that maintains the two members
1875 // pBox1 and bFirstSection.
1876 if( xParentTable.Is() )
1877 return ((SwXMLTableContext *)&xParentTable)->NewTableBox( pStNd,
1878 pUpper );
1880 SwTableBox *pBox;
1882 if( pBox1 &&
1883 pBox1->GetSttNd() == pStNd )
1885 // wenn der StartNode dem StartNode der initial angelegten Box
1886 // entspricht nehmen wir diese Box
1887 pBox = pBox1;
1888 pBox->SetUpper( pUpper );
1889 pBox1 = 0;
1891 else
1892 pBox = new SwTableBox( pBoxFmt, *pStNd, pUpper );
1894 return pBox;
1897 SwTableBoxFmt* SwXMLTableContext::GetSharedBoxFormat(
1898 SwTableBox* pBox,
1899 const OUString& rStyleName,
1900 sal_Int32 nColumnWidth,
1901 sal_Bool bProtected,
1902 sal_Bool bMayShare,
1903 sal_Bool& bNew,
1904 sal_Bool* pModifyLocked )
1906 if ( pSharedBoxFormats == NULL )
1907 pSharedBoxFormats = new map_BoxFmt();
1909 SwTableBoxFmt* pBoxFmt2;
1911 TableBoxIndex aKey( rStyleName, nColumnWidth, bProtected );
1912 map_BoxFmt::iterator aIter = pSharedBoxFormats->find( aKey );
1913 if ( aIter == pSharedBoxFormats->end() )
1915 // unknown format so far -> construct a new one
1917 // get the old format, and reset all attributes
1918 // (but preserve FillOrder)
1919 pBoxFmt2 = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
1920 SwFmtFillOrder aFillOrder( pBoxFmt2->GetFillOrder() );
1921 // --> OD 2007-01-25 #i73790# - method renamed
1922 pBoxFmt2->ResetAllFmtAttr();
1923 // <--
1924 pBoxFmt2->SetFmtAttr( aFillOrder );
1925 bNew = sal_True; // it's a new format now
1927 // share this format, if allowed
1928 if ( bMayShare )
1929 (*pSharedBoxFormats)[ aKey ] = pBoxFmt2;
1931 else
1933 // set the shared format
1934 pBoxFmt2 = aIter->second;
1935 pBox->ChgFrmFmt( pBoxFmt2 );
1936 bNew = sal_False; // copied from an existing format
1938 // claim it, if we are not allowed to share
1939 if ( !bMayShare )
1940 pBoxFmt2 = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
1943 // lock format (if so desired)
1944 if ( pModifyLocked != NULL )
1946 (*pModifyLocked) = pBoxFmt2->IsModifyLocked();
1947 pBoxFmt2->LockModify();
1950 return pBoxFmt2;
1953 SwTableBox *SwXMLTableContext::MakeTableBox( SwTableLine *pUpper,
1954 sal_uInt32 nTopRow,
1955 sal_uInt32 nLeftCol,
1956 sal_uInt32 nBottomRow,
1957 sal_uInt32 nRightCol )
1959 //FIXME: here would be a great place to handle XmlId for cell
1960 SwTableBox *pBox = new SwTableBox( pBoxFmt, 0, pUpper );
1962 sal_uInt32 nColSpan = nRightCol - nLeftCol;
1963 sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
1965 // TODO: Share formats!
1966 SwFrmFmt *pFrmFmt = pBox->ClaimFrmFmt();
1967 SwFmtFillOrder aFillOrder( pFrmFmt->GetFillOrder() );
1968 // --> OD 2007-01-25 #i73790# - method renamed
1969 pFrmFmt->ResetAllFmtAttr();
1970 // <--
1971 pFrmFmt->SetFmtAttr( aFillOrder );
1973 pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nColWidth ) );
1975 SwTableLines& rLines = pBox->GetTabLines();
1976 sal_Bool bSplitted = sal_False;
1978 while( !bSplitted )
1980 sal_uInt32 nStartRow = nTopRow;
1981 sal_uInt32 i;
1983 for( i = nTopRow; i < nBottomRow; i++ )
1985 // Could the table be splitted behind the current row?
1986 sal_Bool bSplit = sal_True;
1987 SwXMLTableRow_Impl *pRow = (*pRows)[(sal_uInt16)i];
1988 for( sal_uInt32 j=nLeftCol; j<nRightCol; j++ )
1990 bSplit = ( 1UL == pRow->GetCell(j)->GetRowSpan() );
1991 if( !bSplit )
1992 break;
1994 if( bSplit && (nStartRow>nTopRow || i+1UL<nBottomRow) )
1996 SwTableLine *pLine =
1997 MakeTableLine( pBox, nStartRow, nLeftCol, i+1UL,
1998 nRightCol );
2000 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
2002 nStartRow = i+1UL;
2003 bSplitted = sal_True;
2006 if( !bSplitted )
2008 // No splitting was possible. That for, we have to force it.
2009 // Ruthless!
2011 nStartRow = nTopRow;
2012 while( nStartRow < nBottomRow )
2014 sal_uInt32 nMaxRowSpan = 0UL;
2015 SwXMLTableRow_Impl *pStartRow = (*pRows)[(sal_uInt16)nStartRow];
2016 SwXMLTableCell_Impl *pCell;
2017 for( i=nLeftCol; i<nRightCol; i++ )
2018 if( ( pCell=pStartRow->GetCell(i),
2019 pCell->GetRowSpan() > nMaxRowSpan ) )
2020 nMaxRowSpan = pCell->GetRowSpan();
2022 nStartRow += nMaxRowSpan;
2023 if( nStartRow<nBottomRow )
2025 SwXMLTableRow_Impl *pPrevRow =
2026 (*pRows)[(sal_uInt16)nStartRow-1U];
2027 i = nLeftCol;
2028 while( i < nRightCol )
2030 if( pPrevRow->GetCell(i)->GetRowSpan() > 1UL )
2032 const SwXMLTableCell_Impl *pCell2 =
2033 GetCell( nStartRow, i );
2034 const sal_uInt32 nColSpan2 = pCell2->GetColSpan();
2035 FixRowSpan( nStartRow-1UL, i, nColSpan2 );
2036 ReplaceWithEmptyCell( nStartRow, i, true );
2037 i += nColSpan2;
2039 else
2041 i++;
2046 // und jetzt nochmal von vorne ...
2050 return pBox;
2053 SwTableBox *SwXMLTableContext::MakeTableBox(
2054 SwTableLine *pUpper, const SwXMLTableCell_Impl *pCell,
2055 sal_uInt32 /*nTopRow*/, sal_uInt32 nLeftCol, sal_uInt32 /*nBottomRow*/,
2056 sal_uInt32 nRightCol )
2058 //FIXME: here would be a great place to handle XmlId for cell
2059 SwTableBox *pBox;
2060 sal_uInt32 nColSpan = nRightCol - nLeftCol;
2061 sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
2063 if( pCell->GetStartNode() )
2065 pBox = NewTableBox( pCell->GetStartNode(), pUpper );
2067 else
2069 // und die ist eine Tabelle: dann bauen wir eine neue
2070 // Box und fuegen die Zeilen der Tabelle in die Zeilen
2071 // der Box ein
2072 pBox = new SwTableBox( pBoxFmt, 0, pUpper );
2073 pCell->GetSubTable()->MakeTable( pBox, nColWidth );
2076 // Share formats!
2077 OUString sStyleName = pCell->GetStyleName();
2078 sal_Bool bModifyLocked;
2079 sal_Bool bNew;
2080 SwTableBoxFmt *pBoxFmt2 = GetSharedBoxFormat(
2081 pBox, sStyleName, nColWidth, pCell->IsProtected(),
2082 pCell->GetStartNode() && pCell->GetFormula().getLength() == 0 &&
2083 ! pCell->HasValue(),
2084 bNew, &bModifyLocked );
2086 // if a new format was created, then we need to set the style
2087 if ( bNew )
2089 // set style
2090 const SfxItemSet *pAutoItemSet = 0;
2091 if( pCell->GetStartNode() && sStyleName &&
2092 GetSwImport().FindAutomaticStyle(
2093 XML_STYLE_FAMILY_TABLE_CELL, sStyleName, &pAutoItemSet ) )
2095 if( pAutoItemSet )
2096 pBoxFmt2->SetFmtAttr( *pAutoItemSet );
2100 if( pCell->GetStartNode() )
2103 // #104801# try to rescue broken documents with a certain pattern
2104 // if: 1) the cell has a default number format (number 0)
2105 // 2) the call has no formula
2106 // 3) the value is 0.0
2107 // 4) the text doesn't look anything like 0.0
2108 // [read: length > 10, or length smaller 10 and no 0 in it]
2109 // then make it a text cell!
2110 bool bSuppressNumericContent = false;
2111 if( pCell->HasValue() && (pCell->GetValue() == 0.0) &&
2112 (pCell->GetFormula().getLength() == 0) &&
2113 (sStyleName.getLength() != 0) )
2115 // default num format?
2116 const SfxPoolItem* pItem = NULL;
2117 if( pBoxFmt2->GetItemState( RES_BOXATR_FORMAT, FALSE, &pItem )
2118 == SFX_ITEM_SET )
2120 const SwTblBoxNumFormat* pNumFormat =
2121 static_cast<const SwTblBoxNumFormat*>( pItem );
2122 if( ( pNumFormat != NULL ) && ( pNumFormat->GetValue() == 0 ) )
2124 // only one text node?
2125 SwNodeIndex aNodeIndex( *(pCell->GetStartNode()), 1 );
2126 if( ( aNodeIndex.GetNode().EndOfSectionIndex() -
2127 aNodeIndex.GetNode().StartOfSectionIndex() ) == 2 )
2129 SwTxtNode* pTxtNode= aNodeIndex.GetNode().GetTxtNode();
2130 if( pTxtNode != NULL )
2132 // check text: does it look like some form of 0.0?
2133 const String& rText = pTxtNode->GetTxt();
2134 if( ( rText.Len() > 10 ) ||
2135 ( rText.Search( '0' ) == STRING_NOTFOUND ) )
2137 bSuppressNumericContent = true;
2141 else
2142 bSuppressNumericContent = true; // several nodes
2147 if( bSuppressNumericContent )
2149 // suppress numeric content? Then reset number format!
2150 pBoxFmt2->ResetFmtAttr( RES_BOXATR_FORMULA );
2151 pBoxFmt2->ResetFmtAttr( RES_BOXATR_FORMAT );
2152 pBoxFmt2->ResetFmtAttr( RES_BOXATR_VALUE );
2154 else
2156 // the normal case: set formula and value (if available)
2158 const OUString& rFormula = pCell->GetFormula();
2159 if (rFormula.getLength() > 0)
2161 // formula cell: insert formula if valid
2162 SwTblBoxFormula aFormulaItem( rFormula );
2163 pBoxFmt2->SetFmtAttr( aFormulaItem );
2165 else if( !pCell->HasValue() && pCell->HasTextValue() )
2167 // Check for another inconsistency:
2168 // No value but a non-textual format, i.e. a number format
2169 // Solution: the number format will be removed,
2170 // the cell gets the default text format.
2171 const SfxPoolItem* pItem = NULL;
2172 if( pBoxFmt->GetItemState( RES_BOXATR_FORMAT, FALSE, &pItem )
2173 == SFX_ITEM_SET )
2175 const SwDoc* pDoc = pBoxFmt->GetDoc();
2176 const SvNumberFormatter* pNumberFormatter = pDoc ?
2177 pDoc->GetNumberFormatter() : 0;
2178 const SwTblBoxNumFormat* pNumFormat =
2179 static_cast<const SwTblBoxNumFormat*>( pItem );
2180 if( pNumFormat != NULL && pNumberFormatter &&
2181 !pNumberFormatter->GetEntry( pNumFormat->GetValue() )->IsTextFormat() )
2182 pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2185 // always insert value, even if default
2186 if( pCell->HasValue() )
2188 SwTblBoxValue aValueItem( pCell->GetValue() );
2189 pBoxFmt2->SetFmtAttr( aValueItem );
2193 // update cell content depend on the default language
2194 pBox->ActualiseValueBox();
2197 // table cell protection
2198 if( pCell->IsProtected() )
2200 SvxProtectItem aProtectItem( RES_PROTECT );
2201 aProtectItem.SetCntntProtect( sal_True );
2202 pBoxFmt2->SetFmtAttr( aProtectItem );
2205 // restore old modify-lock state
2206 if (! bModifyLocked)
2207 pBoxFmt2->UnlockModify();
2209 pBoxFmt2->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nColWidth ) );
2211 return pBox;
2214 SwTableLine *SwXMLTableContext::MakeTableLine( SwTableBox *pUpper,
2215 sal_uInt32 nTopRow,
2216 sal_uInt32 nLeftCol,
2217 sal_uInt32 nBottomRow,
2218 sal_uInt32 nRightCol )
2220 //FIXME: here would be a great place to handle XmlId for row
2221 SwTableLine *pLine;
2222 if( !pUpper && 0UL==nTopRow )
2224 pLine = pTableNode->GetTable().GetTabLines()[0U];
2226 else
2228 pLine = new SwTableLine( pLineFmt, 0, pUpper );
2231 // TODO: Share formats!
2232 SwFrmFmt *pFrmFmt = pLine->ClaimFrmFmt();
2233 SwFmtFillOrder aFillOrder( pFrmFmt->GetFillOrder() );
2234 // --> OD 2007-01-25 #i73790# - method renamed
2235 pFrmFmt->ResetAllFmtAttr();
2236 // <--
2237 pFrmFmt->SetFmtAttr( aFillOrder );
2239 const SfxItemSet *pAutoItemSet = 0;
2240 const OUString& rStyleName = (*pRows)[(sal_uInt16)nTopRow]->GetStyleName();
2241 if( 1UL == (nBottomRow - nTopRow) &&
2242 rStyleName.getLength() &&
2243 GetSwImport().FindAutomaticStyle(
2244 XML_STYLE_FAMILY_TABLE_ROW, rStyleName, &pAutoItemSet ) )
2246 if( pAutoItemSet )
2247 pFrmFmt->SetFmtAttr( *pAutoItemSet );
2250 SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2252 sal_uInt32 nStartCol = nLeftCol;
2253 while( nStartCol < nRightCol )
2255 for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
2256 (*pRows)[(sal_uInt16)nRow]->SetSplitable( sal_True );
2258 sal_uInt32 nCol = nStartCol;
2259 sal_uInt32 nSplitCol = nRightCol;
2260 sal_Bool bSplitted = sal_False;
2261 while( !bSplitted )
2263 ASSERT( nCol < nRightCol, "Zu weit gelaufen" );
2265 // Kann hinter der aktuellen HTML-Tabellen-Spalte gesplittet
2266 // werden? Wenn ja, koennte der enstehende Bereich auch noch
2267 // in Zeilen zerlegt werden, wenn man die naechste Spalte
2268 // hinzunimmt?
2269 sal_Bool bSplit = sal_True;
2270 sal_Bool bHoriSplitMayContinue = sal_False;
2271 sal_Bool bHoriSplitPossible = sal_False;
2273 if ( bHasSubTables )
2275 // Convert row spans if the table has subtables:
2276 for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
2278 SwXMLTableCell_Impl *pCell = GetCell(nRow,nCol);
2279 // Could the table fragment be splitted horizontally behind
2280 // the current line?
2281 sal_Bool bHoriSplit = (*pRows)[(sal_uInt16)nRow]->IsSplitable() &&
2282 nRow+1UL < nBottomRow &&
2283 1UL == pCell->GetRowSpan();
2284 (*pRows)[(sal_uInt16)nRow]->SetSplitable( bHoriSplit );
2286 // Could the table fragment be splitted vertically behind the
2287 // current column (uptp the current line?
2288 bSplit &= ( 1UL == pCell->GetColSpan() );
2289 if( bSplit )
2291 bHoriSplitPossible |= bHoriSplit;
2293 // Could the current table fragment be splitted
2294 // horizontally behind the next collumn, too?
2295 bHoriSplit &= (nCol+1UL < nRightCol &&
2296 1UL == GetCell(nRow,nCol+1UL)->GetRowSpan());
2297 bHoriSplitMayContinue |= bHoriSplit;
2301 else
2303 // No subtabels: We use the new table model.
2304 SwXMLTableCell_Impl *pCell = GetCell(nTopRow,nCol);
2306 // --> OD 2009-03-19 #i95726# - some fault tolerance
2307 if ( pCell == 0 )
2309 ASSERT( false, "table seems to be corrupt." );
2310 break;
2312 // <--
2314 // Could the table fragment be splitted vertically behind the
2315 // current column (uptp the current line?
2316 bSplit = 1UL == pCell->GetColSpan();
2319 #ifndef PRODUCT
2320 if( nCol == nRightCol-1UL )
2322 ASSERT( bSplit, "Split-Flag falsch" );
2323 if ( bHasSubTables )
2325 ASSERT( !bHoriSplitMayContinue,
2326 "HoriSplitMayContinue-Flag falsch" );
2327 SwXMLTableCell_Impl *pTmpCell = GetCell( nTopRow, nStartCol );
2328 ASSERT( pTmpCell->GetRowSpan() != (nBottomRow-nTopRow) ||
2329 !bHoriSplitPossible, "HoriSplitPossible-Flag falsch" );
2332 #endif
2334 ASSERT( !bHasSubTables || !bHoriSplitMayContinue || bHoriSplitPossible,
2335 "bHoriSplitMayContinue, aber nicht bHoriSplitPossible" );
2337 if( bSplit )
2339 SwTableBox* pBox = 0;
2340 SwXMLTableCell_Impl *pCell = GetCell( nTopRow, nStartCol );
2341 // --> OD 2009-03-19 #i95726# - some fault tolerance
2342 if( ( !bHasSubTables || ( pCell->GetRowSpan() == (nBottomRow-nTopRow) ) ) &&
2343 pCell->GetColSpan() == (nCol+1UL-nStartCol) &&
2344 ( pCell->GetStartNode() || pCell->GetSubTable() ) )
2345 // <--
2347 // insert new empty cell for covered cells:
2348 long nBoxRowSpan = 1;
2349 if ( !bHasSubTables )
2351 nBoxRowSpan = pCell->GetRowSpan();
2352 if ( pCell->IsCovered() )
2354 nBoxRowSpan = -1 * nBoxRowSpan;
2355 ReplaceWithEmptyCell( nTopRow, nStartCol, false );
2359 // The remaining box neither contains lines nor rows (i.e.
2360 // is a content box
2361 nSplitCol = nCol + 1UL;
2363 pBox = MakeTableBox( pLine, pCell,
2364 nTopRow, nStartCol,
2365 nBottomRow, nSplitCol );
2367 if ( 1 != nBoxRowSpan )
2368 pBox->setRowSpan( nBoxRowSpan );
2370 bSplitted = sal_True;
2372 else if( bHasSubTables && bHoriSplitPossible && bHoriSplitMayContinue )
2374 // The table fragment could be splitted behind the current
2375 // column, and the remaining fragment could be divided
2376 // into lines. Anyway, it could be that this applies to
2377 // the next column, too. That for, we check the next
2378 // column but rememeber the current one as a good place to
2379 // split.
2380 nSplitCol = nCol + 1UL;
2382 else if ( bHasSubTables )
2384 // If the table resulting table fragment could be divided
2385 // into lines if spllitting behind the current column, but
2386 // this doesn't apply for thr next column, we split begind
2387 // the current column. This applies for the last column,
2388 // too.
2389 // If the resulting box cannot be splitted into rows,
2390 // the split at the last split position we remembered.
2391 if( bHoriSplitPossible || nSplitCol > nCol+1 )
2393 ASSERT( !bHoriSplitMayContinue,
2394 "bHoriSplitMayContinue==sal_True" );
2395 ASSERT( bHoriSplitPossible || nSplitCol == nRightCol,
2396 "bHoriSplitPossible-Flag sollte gesetzt sein" );
2398 nSplitCol = nCol + 1UL;
2401 pBox = MakeTableBox( pLine, nTopRow, nStartCol,
2402 nBottomRow, nSplitCol );
2403 bSplitted = sal_True;
2406 ASSERT( bHasSubTables || pBox, "Colspan trouble" )
2408 if( pBox )
2409 rBoxes.C40_INSERT( SwTableBox, pBox, rBoxes.Count() );
2411 nCol++;
2413 nStartCol = nSplitCol;
2416 return pLine;
2419 void SwXMLTableContext::_MakeTable( SwTableBox *pBox )
2421 // fix column widths
2422 sal_uInt32 i;
2423 sal_uInt32 nCols = GetColumnCount();
2425 // If there are empty rows (because of some row span of previous rows)
2426 // the have to be deleted. The previous rows have to be truncated.
2428 if( pRows->Count() > nCurRow )
2430 SwXMLTableRow_Impl *pPrevRow = (*pRows)[(sal_uInt16)nCurRow-1U];
2431 SwXMLTableCell_Impl *pCell;
2432 for( i=0UL; i<nCols; i++ )
2434 if( ( pCell=pPrevRow->GetCell(i), pCell->GetRowSpan() > 1UL ) )
2436 FixRowSpan( nCurRow-1UL, i, 1UL );
2439 for( i=(sal_uInt32)pRows->Count()-1UL; i>=nCurRow; i-- )
2440 pRows->DeleteAndDestroy( (sal_uInt16)i );
2443 if( 0UL == pRows->Count() )
2445 OUString aStyleName2;
2446 InsertCell( aStyleName2, 1U, nCols, InsertTableSection() );
2449 // TODO: Do we have to keep both values, the realtive and the absolute
2450 // width?
2451 sal_Int32 nAbsWidth = 0L;
2452 sal_Int32 nMinAbsColWidth = 0L;
2453 sal_Int32 nRelWidth = 0L;
2454 sal_Int32 nMinRelColWidth = 0L;
2455 sal_uInt32 nRelCols = 0UL;
2456 for( i=0U; i < nCols; i++ )
2458 sal_Int32 nColWidth = aColumnWidths[(sal_uInt16)i];
2459 if( aColumnRelWidths[(sal_uInt16)i] )
2461 nRelWidth += nColWidth;
2462 if( 0L == nMinRelColWidth || nColWidth < nMinRelColWidth )
2463 nMinRelColWidth = nColWidth;
2464 nRelCols++;
2466 else
2468 nAbsWidth += nColWidth;
2469 if( 0L == nMinAbsColWidth || nColWidth < nMinAbsColWidth )
2470 nMinAbsColWidth = nColWidth;
2473 sal_uInt32 nAbsCols = nCols - nRelCols;
2475 if( bRelWidth )
2477 // If there a columns that have an absolute width, we have to
2478 // calculate a relative one for them.
2479 if( nAbsCols > 0UL )
2481 // All column that have absolute widths get relative widths;
2482 // these widths relate to each over like the original absolute
2483 // widths. The smallest column gets a width that hat the same
2484 // value as the smallest column that has an relative width
2485 // already.
2486 if( 0L == nMinRelColWidth )
2487 nMinRelColWidth = nMinAbsColWidth;
2489 for( i=0UL; nAbsCols > 0UL && i < nCols; i++ )
2491 if( !aColumnRelWidths[(sal_uInt16)i] )
2493 sal_Int32 nRelCol = (aColumnWidths[(sal_uInt16)i] * nMinRelColWidth) /
2494 nMinAbsColWidth;
2495 aColumnWidths.Replace( (sal_uInt16)nRelCol, (sal_uInt16)i );
2496 nRelWidth += nRelCol;
2497 nAbsCols--;
2502 if( !nWidth )
2504 // This happens only for percentage values for the table itself.
2505 // In this case, the columns get the correct width even if the
2506 // the sum of the relative withs is smaller than the available
2507 // width in TWIP. Therfore, we can use the relative width.
2509 nWidth = nRelWidth > USHRT_MAX ? USHRT_MAX : nRelWidth;
2511 if( nRelWidth != nWidth && nRelWidth && nCols )
2513 double n = (double)nWidth / (double)nRelWidth;
2514 nRelWidth = 0L;
2515 for( i=0U; i < nCols-1UL; i++ )
2517 sal_Int32 nW = (sal_Int32)(aColumnWidths[(sal_uInt16)i] * n);
2518 aColumnWidths.Replace( (sal_uInt16)nW, (sal_uInt16)i );
2519 nRelWidth += nW;
2521 aColumnWidths.Replace( (sal_uInt16)(nWidth-nRelWidth),
2522 (sal_uInt16)nCols-1U );
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 sal_Bool bMin = sal_False; // Do all columns get the mininum width?
2547 sal_Bool bMinExtra = sal_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 = sal_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 = sal_True;
2567 // Otherwise, if there is enouth space for every column, every
2568 // column gets this space.
2570 for( i=0UL; nRelCols > 0UL && i < nCols; i++ )
2572 if( aColumnRelWidths[(sal_uInt16)i] )
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 =
2590 aColumnWidths[(sal_uInt16)i] - nMinRelColWidth;
2591 nAbsCol = MINLAY + (nExtraRelCol * nExtraAbs) /
2592 nExtraRel;
2594 else
2596 nAbsCol = (aColumnWidths[(sal_uInt16)i] * nAbsForRelWidth) /
2597 nRelWidth;
2600 aColumnWidths.Replace( (sal_uInt16)nAbsCol, (sal_uInt16)i );
2601 nAbsForRelWidth -= nAbsCol;
2602 nAbsWidth += nAbsCol;
2603 nRelCols--;
2608 if( nCols && nAbsWidth )
2610 if( nAbsWidth < nWidth )
2612 // If the table's width is larger than the absolute column widths,
2613 // every column get some extra width.
2614 sal_Int32 nExtraAbs = nWidth - nAbsWidth;
2615 sal_Int32 nAbsLastCol =
2616 aColumnWidths[(sal_uInt16)nCols-1U] + nExtraAbs;
2617 for( i=0UL; i < nCols-1UL; i++ )
2619 sal_Int32 nAbsCol = aColumnWidths[(sal_uInt16)i];
2620 sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
2621 nAbsWidth;
2622 nAbsCol += nExtraAbsCol;
2623 aColumnWidths.Replace( (sal_uInt16)nAbsCol, (sal_uInt16)i );
2624 nAbsLastCol -= nExtraAbsCol;
2626 aColumnWidths.Replace( (sal_uInt16)nAbsLastCol, (sal_uInt16)nCols-1U );
2628 else if( nAbsWidth > nWidth )
2630 // If the table's width is smaller than the absolute column
2631 // widths, every column gets the minimum width plus some extra
2632 // width.
2633 sal_Int32 nExtraAbs = nWidth - (nCols * MINLAY);
2634 sal_Int32 nAbsLastCol = MINLAY + nExtraAbs;
2635 for( i=0UL; i < nCols-1UL; i++ )
2637 sal_Int32 nAbsCol = aColumnWidths[(sal_uInt16)i];
2638 sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
2639 nAbsWidth;
2640 nAbsCol = MINLAY + nExtraAbsCol;
2641 aColumnWidths.Replace( (sal_uInt16)nAbsCol, (sal_uInt16)i );
2642 nAbsLastCol -= nExtraAbsCol;
2644 aColumnWidths.Replace( (sal_uInt16)nAbsLastCol, (sal_uInt16)nCols-1U );
2649 SwTableLines& rLines =
2650 pBox ? pBox->GetTabLines()
2651 : pTableNode->GetTable().GetTabLines();
2653 sal_uInt32 nStartRow = 0UL;
2654 sal_uInt32 nRows = pRows->Count();
2655 for( i=0UL; i<nRows; i++ )
2657 // Could we split the table behind the current line?
2658 sal_Bool bSplit = sal_True;
2659 if ( bHasSubTables )
2661 SwXMLTableRow_Impl *pRow = (*pRows)[(sal_uInt16)i];
2662 for( sal_uInt32 j=0UL; j<nCols; j++ )
2664 bSplit = ( 1UL == pRow->GetCell(j)->GetRowSpan() );
2665 if( !bSplit )
2666 break;
2670 if( bSplit )
2672 SwTableLine *pLine =
2673 MakeTableLine( pBox, nStartRow, 0UL, i+1UL, nCols );
2674 if( pBox || nStartRow>0UL )
2675 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
2676 nStartRow = i+1UL;
2681 void SwXMLTableContext::MakeTable()
2683 // this method will modify the document directly -> lock SolarMutex
2684 // This will call all other MakeTable*(..) methods, so
2685 // those don't need to be locked separately.
2686 vos::OGuard aGuard(Application::GetSolarMutex());
2688 // #i97274# handle invalid tables
2689 if (!pRows || !pRows->Count() || !GetColumnCount())
2691 ASSERT(false, "invalid table: no cells; deleting...");
2692 pTableNode->GetDoc()->DeleteSection( pTableNode );
2693 pTableNode = 0;
2694 pBox1 = 0;
2695 pSttNd1 = 0;
2696 return;
2699 SwXMLImport& rSwImport = GetSwImport();
2701 SwFrmFmt *pFrmFmt = pTableNode->GetTable().GetFrmFmt();
2703 sal_Int16 eHoriOrient = text::HoriOrientation::FULL;
2704 sal_Bool bSetHoriOrient = sal_False;
2706 sal_uInt16 nPrcWidth = 0U;
2708 pTableNode->GetTable().SetRowsToRepeat( nHeaderRows );
2709 pTableNode->GetTable().SetTableModel( !bHasSubTables );
2711 const SfxItemSet *pAutoItemSet = 0;
2712 if( aStyleName.getLength() &&
2713 rSwImport.FindAutomaticStyle(
2714 XML_STYLE_FAMILY_TABLE_TABLE, aStyleName, &pAutoItemSet ) &&
2715 pAutoItemSet )
2717 const SfxPoolItem *pItem;
2718 const SvxLRSpaceItem *pLRSpace = 0;
2719 if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_LR_SPACE, sal_False,
2720 &pItem ) )
2721 pLRSpace = (const SvxLRSpaceItem *)pItem;
2723 if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_HORI_ORIENT, sal_False,
2724 &pItem ) )
2726 eHoriOrient = ((const SwFmtHoriOrient *)pItem)->GetHoriOrient();
2727 switch( eHoriOrient )
2729 case text::HoriOrientation::FULL:
2730 if( pLRSpace )
2732 eHoriOrient = text::HoriOrientation::NONE;
2733 bSetHoriOrient = sal_True;
2735 break;
2736 case text::HoriOrientation::LEFT:
2737 if( pLRSpace )
2739 eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
2740 bSetHoriOrient = sal_True;
2742 break;
2743 default:
2747 else
2749 bSetHoriOrient = sal_True;
2752 const SwFmtFrmSize *pSize = 0;
2753 if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_FRM_SIZE, sal_False,
2754 &pItem ) )
2755 pSize = (const SwFmtFrmSize *)pItem;
2757 switch( eHoriOrient )
2759 case text::HoriOrientation::FULL:
2760 case text::HoriOrientation::NONE:
2761 // #78246#: For text::HoriOrientation::NONE we would prefere to use the sum
2762 // of the relative column widths as reference width.
2763 // Unfortunately this works only if this sum interpreted as
2764 // twip value is larger than the space that is avaialable.
2765 // We don't know that space, so we have to use USHRT_MAX, too.
2766 // Even if a size is speczified, it will be ignored!
2767 nWidth = USHRT_MAX;
2768 break;
2769 default:
2770 if( pSize )
2772 if( pSize->GetWidthPercent() )
2774 // The width will be set in _MakeTable
2775 nPrcWidth = pSize->GetWidthPercent();
2777 else
2779 nWidth = pSize->GetWidth();
2780 if( nWidth < (sal_Int32)GetColumnCount() * MINLAY )
2782 nWidth = GetColumnCount() * MINLAY;
2784 else if( nWidth > USHRT_MAX )
2786 nWidth = USHRT_MAX;
2788 bRelWidth = sal_False;
2791 else
2793 eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH == eHoriOrient
2794 ? text::HoriOrientation::NONE : text::HoriOrientation::FULL;
2795 bSetHoriOrient = sal_True;
2796 nWidth = USHRT_MAX;
2798 break;
2801 pFrmFmt->SetFmtAttr( *pAutoItemSet );
2803 else
2805 bSetHoriOrient = sal_True;
2806 nWidth = USHRT_MAX;
2809 SwTableLine *pLine1 = pTableNode->GetTable().GetTabLines()[0U];
2810 DBG_ASSERT( pBox1 == pLine1->GetTabBoxes()[0U],
2811 "Why is box 1 change?" );
2812 pBox1->pSttNd = pSttNd1;
2813 pLine1->GetTabBoxes().Remove(0U);
2815 pLineFmt = (SwTableLineFmt*)pLine1->GetFrmFmt();
2816 pBoxFmt = (SwTableBoxFmt*)pBox1->GetFrmFmt();
2818 _MakeTable( 0 );
2820 if( bSetHoriOrient )
2821 pFrmFmt->SetFmtAttr( SwFmtHoriOrient( 0, eHoriOrient ) );
2823 // This must be after the call to _MakeTable, because nWidth might be
2824 // changed there.
2825 pFrmFmt->LockModify();
2826 SwFmtFrmSize aSize( ATT_VAR_SIZE, nWidth );
2827 aSize.SetWidthPercent( (sal_Int8)nPrcWidth );
2828 pFrmFmt->SetFmtAttr( aSize );
2829 pFrmFmt->UnlockModify();
2832 for( sal_uInt16 i=0; i<pRows->Count(); i++ )
2833 (*pRows)[i]->Dispose();
2835 // now that table is complete, change into DDE table (if appropriate)
2836 if (NULL != pDDESource)
2838 // change existing table into DDE table:
2839 // 1) Get DDE field type (get data from dde-source context),
2840 SwDDEFieldType* pFldType = lcl_GetDDEFieldType( pDDESource,
2841 pTableNode );
2843 // 2) release the DDE source context,
2844 pDDESource->ReleaseRef();
2846 // 3) create new DDE table, and
2847 SwDDETable* pDDETable = new SwDDETable( pTableNode->GetTable(),
2848 pFldType, FALSE );
2850 // 4) set new (DDE)table at node.
2851 pTableNode->SetNewTable(pDDETable, FALSE);
2854 // ??? this is always false: root frame is only created in ViewShell::Init
2855 if( pTableNode->GetDoc()->GetRootFrm() )
2857 pTableNode->DelFrms();
2858 SwNodeIndex aIdx( *pTableNode->EndOfSectionNode(), 1 );
2859 pTableNode->MakeFrms( &aIdx );
2863 void SwXMLTableContext::MakeTable( SwTableBox *pBox, sal_Int32 nW )
2865 //FIXME: here would be a great place to handle XmlId for subtable
2866 pLineFmt = GetParentTable()->pLineFmt;
2867 pBoxFmt = GetParentTable()->pBoxFmt;
2868 nWidth = nW;
2869 bRelWidth = GetParentTable()->bRelWidth;
2871 _MakeTable( pBox );
2874 const SwStartNode *SwXMLTableContext::InsertTableSection(
2875 const SwStartNode *pPrevSttNd )
2877 // The topmost table is the only table that maintains the two members
2878 // pBox1 and bFirstSection.
2879 if( xParentTable.Is() )
2880 return ((SwXMLTableContext *)&xParentTable)->InsertTableSection( pPrevSttNd );
2882 const SwStartNode *pStNd;
2883 Reference<XUnoTunnel> xCrsrTunnel( GetImport().GetTextImport()->GetCursor(),
2884 UNO_QUERY);
2885 ASSERT( xCrsrTunnel.is(), "missing XUnoTunnel for Cursor" );
2886 OTextCursorHelper *pTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
2887 sal::static_int_cast< sal_IntPtr >( xCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )));
2888 ASSERT( pTxtCrsr, "SwXTextCursor missing" );
2890 if( bFirstSection )
2892 // The Cursor already is in the first section
2893 pStNd = pTxtCrsr->GetPaM()->GetNode()->FindTableBoxStartNode();
2894 bFirstSection = sal_False;
2895 OUString sStyleName( RTL_CONSTASCII_USTRINGPARAM("Standard") );
2896 GetImport().GetTextImport()->SetStyleAndAttrs( GetImport(),
2897 GetImport().GetTextImport()->GetCursor(), sStyleName, rtl::OUString(), sal_True );
2899 else
2901 SwDoc* pDoc = SwImport::GetDocFromXMLImport( GetSwImport() );
2902 const SwEndNode *pEndNd = pPrevSttNd ? pPrevSttNd->EndOfSectionNode()
2903 : pTableNode->EndOfSectionNode();
2904 // --> OD 2007-07-02 #i78921# - make code robust
2905 #if OSL_DEBUG_LEVEL > 1
2906 ASSERT( pDoc, "<SwXMLTableContext::InsertTableSection(..)> - no <pDoc> at <SwXTextCursor> instance - <SwXTextCurosr> doesn't seem to be registered at a <SwUnoCrsr> instance." );
2907 #endif
2908 if ( !pDoc )
2910 pDoc = const_cast<SwDoc*>(pEndNd->GetDoc());
2912 // <--
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 // --> FLR 2005-08-30 #125369#
2920 // Consider the case that a table is defined without a row.
2921 if( !pPrevSttNd && pBox1 != NULL )
2922 // <--
2924 pBox1->pSttNd = pStNd;
2925 SwCntntNode *pCNd = pDoc->GetNodes()[ pStNd->GetIndex() + 1 ]
2926 ->GetCntntNode();
2927 SwPosition aPos( *pCNd );
2928 aPos.nContent.Assign( pCNd, 0U );
2930 Reference < XTextRange > xTextRange =
2931 SwXTextRange::CreateTextRangeFromPosition( pDoc, aPos, 0 );
2932 Reference < XText > xText = xTextRange->getText();
2933 Reference < XTextCursor > xTextCursor =
2934 xText->createTextCursorByRange( xTextRange );
2935 GetImport().GetTextImport()->SetCursor( xTextCursor );
2939 return pStNd;
2942 void SwXMLTableContext::EndElement()
2944 if( IsValid() && !xParentTable.Is() )
2946 MakeTable();
2947 GetImport().GetTextImport()->SetCursor( xOldCursor );
2951 Reference < XTextContent > SwXMLTableContext::GetXTextContent() const
2953 return xTextContent;