xref: /AOO41X/main/sw/source/filter/xml/xmltbli.cxx (revision 56df9a41f5bf3665e6e9154f65f8aff3e6417c65)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_sw.hxx"
24 
25 #include "hintids.hxx"
26 
27 #include <limits.h>
28 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
29 #include <com/sun/star/text/XTextTable.hpp>
30 #include <com/sun/star/table/XCellRange.hpp>
31 #include <svl/itemset.hxx>
32 #include <svl/zformat.hxx>
33 #include <xmloff/xmlnmspe.hxx>
34 #include <xmloff/xmltkmap.hxx>
35 #include <xmloff/nmspmap.hxx>
36 
37 #include <xmloff/families.hxx>
38 #include <xmloff/xmluconv.hxx>
39 #include <xmloff/i18nmap.hxx>
40 #include <editeng/protitem.hxx>
41 #include "poolfmt.hxx"
42 #include "fmtfsize.hxx"
43 #include "fmtornt.hxx"
44 #include "fmtfordr.hxx"
45 #include "doc.hxx"
46 #include "swtable.hxx"
47 #include "swtblfmt.hxx"
48 #include "pam.hxx"
49 #include "unotbl.hxx"
50 #include "unotextrange.hxx"
51 #include "unocrsr.hxx"
52 #include "cellatr.hxx"
53 #include "swddetbl.hxx"
54 #include "ddefld.hxx"
55 #include <sfx2/linkmgr.hxx> // for cTokenSeparator
56 #include "xmlimp.hxx"
57 #include "xmltbli.hxx"
58 
59 // for locking SolarMutex: svapp + mutex
60 #include <vcl/svapp.hxx>
61 #include <vos/mutex.hxx>
62 #include "ndtxt.hxx"
63 
64 using ::rtl::OUString;
65 using namespace ::com::sun::star;
66 using namespace ::com::sun::star::uno;
67 using namespace ::com::sun::star::lang;
68 using namespace ::com::sun::star::text;
69 using namespace ::com::sun::star::frame;
70 using namespace ::com::sun::star::table;
71 using namespace ::com::sun::star::xml::sax;
72 using namespace ::xmloff::token;
73 using ::std::hash_map;
74 
75 enum SwXMLTableElemTokens
76 {
77     XML_TOK_TABLE_HEADER_COLS,
78     XML_TOK_TABLE_COLS,
79     XML_TOK_TABLE_COL,
80     XML_TOK_TABLE_HEADER_ROWS,
81     XML_TOK_TABLE_ROWS,
82     XML_TOK_TABLE_ROW,
83     XML_TOK_OFFICE_DDE_SOURCE,
84     XML_TOK_TABLE_ELEM_END=XML_TOK_UNKNOWN
85 };
86 
87 enum SwXMLTableCellAttrTokens
88 {
89     XML_TOK_TABLE_XMLID,
90     XML_TOK_TABLE_STYLE_NAME,
91     XML_TOK_TABLE_NUM_COLS_SPANNED,
92     XML_TOK_TABLE_NUM_ROWS_SPANNED,
93     XML_TOK_TABLE_NUM_COLS_REPEATED,
94     XML_TOK_TABLE_FORMULA,
95     XML_TOK_TABLE_VALUE,
96     XML_TOK_TABLE_TIME_VALUE,
97     XML_TOK_TABLE_DATE_VALUE,
98     XML_TOK_TABLE_BOOLEAN_VALUE,
99     XML_TOK_TABLE_PROTECTED,
100     XML_TOK_TABLE_STRING_VALUE,
101     XML_TOK_TABLE_CELL_ATTR_END=XML_TOK_UNKNOWN
102 };
103 
104 static __FAR_DATA SvXMLTokenMapEntry aTableElemTokenMap[] =
105 {
106     { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_COLUMNS,
107             XML_TOK_TABLE_HEADER_COLS },
108     { XML_NAMESPACE_TABLE, XML_TABLE_COLUMNS,           XML_TOK_TABLE_COLS },
109     { XML_NAMESPACE_TABLE, XML_TABLE_COLUMN,            XML_TOK_TABLE_COL },
110     { XML_NAMESPACE_TABLE, XML_TABLE_HEADER_ROWS,
111             XML_TOK_TABLE_HEADER_ROWS },
112     { XML_NAMESPACE_TABLE, XML_TABLE_ROWS,              XML_TOK_TABLE_ROWS },
113     { XML_NAMESPACE_TABLE, XML_TABLE_ROW,               XML_TOK_TABLE_ROW },
114     { XML_NAMESPACE_OFFICE, XML_DDE_SOURCE,
115             XML_TOK_OFFICE_DDE_SOURCE },
116 
117     // There are slight differences between <table:table-columns> and
118     // <table:table-columns-groups>. However, none of these are
119     // supported in Writer (they are Calc-only features), so we
120     // support column groups by simply using the <table:table-columns>
121     // token for column groups, too.
122     { XML_NAMESPACE_TABLE, XML_TABLE_COLUMN_GROUP,      XML_TOK_TABLE_COLS },
123 
124     XML_TOKEN_MAP_END
125 };
126 
127 static __FAR_DATA SvXMLTokenMapEntry aTableCellAttrTokenMap[] =
128 {
129     { XML_NAMESPACE_XML, XML_ID, XML_TOK_TABLE_XMLID },
130     { XML_NAMESPACE_TABLE, XML_STYLE_NAME, XML_TOK_TABLE_STYLE_NAME },
131     { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_SPANNED, XML_TOK_TABLE_NUM_COLS_SPANNED },
132     { XML_NAMESPACE_TABLE, XML_NUMBER_ROWS_SPANNED, XML_TOK_TABLE_NUM_ROWS_SPANNED },
133     { XML_NAMESPACE_TABLE, XML_NUMBER_COLUMNS_REPEATED, XML_TOK_TABLE_NUM_COLS_REPEATED },
134     { XML_NAMESPACE_TABLE, XML_FORMULA, XML_TOK_TABLE_FORMULA },
135     { XML_NAMESPACE_OFFICE, XML_VALUE, XML_TOK_TABLE_VALUE },
136     { XML_NAMESPACE_OFFICE, XML_TIME_VALUE, XML_TOK_TABLE_TIME_VALUE },
137     { XML_NAMESPACE_OFFICE, XML_DATE_VALUE, XML_TOK_TABLE_DATE_VALUE },
138     { XML_NAMESPACE_OFFICE, XML_BOOLEAN_VALUE, XML_TOK_TABLE_BOOLEAN_VALUE },
139     { XML_NAMESPACE_TABLE, XML_PROTECTED, XML_TOK_TABLE_PROTECTED },
140     { XML_NAMESPACE_TABLE, XML_PROTECT, XML_TOK_TABLE_PROTECTED }, // for backwards compatibility with SRC629 (and before)
141     { XML_NAMESPACE_OFFICE, XML_STRING_VALUE, XML_TOK_TABLE_STRING_VALUE },
142     XML_TOKEN_MAP_END
143 };
144 
GetTableElemTokenMap()145 const SvXMLTokenMap& SwXMLImport::GetTableElemTokenMap()
146 {
147     if( !pTableElemTokenMap )
148         pTableElemTokenMap = new SvXMLTokenMap( aTableElemTokenMap );
149 
150     return *pTableElemTokenMap;
151 }
152 
GetTableCellAttrTokenMap()153 const SvXMLTokenMap& SwXMLImport::GetTableCellAttrTokenMap()
154 {
155     if( !pTableCellAttrTokenMap )
156         pTableCellAttrTokenMap = new SvXMLTokenMap( aTableCellAttrTokenMap );
157 
158     return *pTableCellAttrTokenMap;
159 }
160 
161 // ---------------------------------------------------------------------
162 
163 class SwXMLTableCell_Impl
164 {
165     OUString aStyleName;
166 
167     OUString mXmlId;
168 
169     OUString sFormula;  // cell formula; valid if length > 0
170     double dValue;      // formula value
171 
172     SvXMLImportContextRef   xSubTable;
173 
174     const SwStartNode *pStartNode;
175     sal_uInt32 nRowSpan;
176     sal_uInt32 nColSpan;
177 
178     sal_Bool bProtected : 1;
179     sal_Bool bHasValue; // determines whether dValue attribute is valid
180     sal_Bool mbCovered;
181     sal_Bool mbTextValue;
182 
183 public:
184 
SwXMLTableCell_Impl(sal_uInt32 nRSpan=1UL,sal_uInt32 nCSpan=1UL)185     SwXMLTableCell_Impl( sal_uInt32 nRSpan=1UL, sal_uInt32 nCSpan=1UL ) :
186         pStartNode( 0 ),
187         nRowSpan( nRSpan ),
188         nColSpan( nCSpan ),
189         bProtected( sal_False ),
190         mbCovered( sal_False )
191         {}
192 
193     inline void Set( const OUString& rStyleName,
194                       sal_uInt32 nRSpan, sal_uInt32 nCSpan,
195                      const SwStartNode *pStNd, SwXMLTableContext *pTable,
196                      sal_Bool bProtect = sal_False,
197                      const OUString* pFormula = NULL,
198                      sal_Bool bHasValue = sal_False,
199                      sal_Bool mbCovered = sal_False,
200                      double dVal = 0.0,
201                      sal_Bool mbTextValue = sal_False,
202                      OUString const& i_rXmlId = OUString());
203 
IsUsed() const204     sal_Bool IsUsed() const { return pStartNode!=0 ||
205                                      xSubTable.Is() || bProtected;}
206 
GetRowSpan() const207     sal_uInt32 GetRowSpan() const { return nRowSpan; }
SetRowSpan(sal_uInt32 nSet)208     void SetRowSpan( sal_uInt32 nSet ) { nRowSpan = nSet; }
GetColSpan() const209     sal_uInt32 GetColSpan() const { return nColSpan; }
GetStyleName() const210     const OUString& GetStyleName() const { return aStyleName; }
GetFormula() const211     const OUString& GetFormula() const { return sFormula; }
GetValue() const212     double GetValue() const { return dValue; }
HasValue() const213     sal_Bool HasValue() const { return bHasValue; }
IsProtected() const214     sal_Bool IsProtected() const { return bProtected; }
IsCovered() const215     sal_Bool IsCovered() const { return mbCovered; }
HasTextValue() const216     sal_Bool HasTextValue() const { return mbTextValue; }
GetXmlId() const217     const OUString& GetXmlId() const { return mXmlId; }
218 
GetStartNode() const219     const SwStartNode *GetStartNode() const { return pStartNode; }
220     inline void SetStartNode( const SwStartNode *pSttNd );
221 
222     inline SwXMLTableContext *GetSubTable() const;
223 
224     inline void Dispose();
225 };
226 
Set(const OUString & rStyleName,sal_uInt32 nRSpan,sal_uInt32 nCSpan,const SwStartNode * pStNd,SwXMLTableContext * pTable,sal_Bool bProtect,const OUString * pFormula,sal_Bool bHasVal,sal_Bool bCov,double dVal,sal_Bool bTextVal,OUString const & i_rXmlId)227 inline void SwXMLTableCell_Impl::Set( const OUString& rStyleName,
228                                       sal_uInt32 nRSpan, sal_uInt32 nCSpan,
229                                       const SwStartNode *pStNd,
230                                       SwXMLTableContext *pTable,
231                                       sal_Bool bProtect,
232                                       const OUString* pFormula,
233                                       sal_Bool bHasVal,
234                                       sal_Bool bCov,
235                                       double dVal,
236                                       sal_Bool bTextVal,
237                                       OUString const& i_rXmlId )
238 {
239     aStyleName = rStyleName;
240     nRowSpan = nRSpan;
241     nColSpan = nCSpan;
242     pStartNode = pStNd;
243     xSubTable = pTable;
244     dValue = dVal;
245     bHasValue = bHasVal;
246     mbCovered = bCov;
247     mbTextValue = bTextVal;
248     bProtected = bProtect;
249 
250     if (!mbCovered) // ensure uniqueness
251     {
252         mXmlId = i_rXmlId;
253     }
254 
255     // set formula, if valid
256     if (pFormula != NULL)
257     {
258         sFormula = *pFormula;
259     }
260 }
261 
SetStartNode(const SwStartNode * pSttNd)262 inline void SwXMLTableCell_Impl::SetStartNode( const SwStartNode *pSttNd )
263 {
264     pStartNode = pSttNd;
265     xSubTable = 0;
266 }
267 
GetSubTable() const268 inline SwXMLTableContext *SwXMLTableCell_Impl::GetSubTable() const
269 {
270     return (SwXMLTableContext *)&xSubTable;
271 }
272 
Dispose()273 inline void SwXMLTableCell_Impl::Dispose()
274 {
275     if( xSubTable.Is() )
276         xSubTable = 0;
277 }
278 
279 // ---------------------------------------------------------------------
280 
281 typedef SwXMLTableCell_Impl* SwXMLTableCellPtr;
282 SV_DECL_PTRARR_DEL(SwXMLTableCells_Impl,SwXMLTableCellPtr,5,5)
283 SV_IMPL_PTRARR(SwXMLTableCells_Impl,SwXMLTableCellPtr)
284 
285 class SwXMLTableRow_Impl
286 {
287     OUString aStyleName;
288     OUString aDfltCellStyleName;
289     OUString mXmlId;
290 
291     SwXMLTableCells_Impl aCells;
292 
293     sal_Bool bSplitable;
294 
295 public:
296 
297     SwXMLTableRow_Impl( const OUString& rStyleName, sal_uInt32 nCells,
298                         const OUString *pDfltCellStyleName = 0,
299                         const OUString& i_rXmlId = OUString() );
~SwXMLTableRow_Impl()300     ~SwXMLTableRow_Impl() {}
301 
302     inline SwXMLTableCell_Impl *GetCell( sal_uInt32 nCol ) const;
303 
304     inline void Set( const OUString& rStyleName,
305                      const OUString& rDfltCellStyleName,
306                      const OUString& i_rXmlId );
307 
308     void Expand( sal_uInt32 nCells, sal_Bool bOneCell );
309 
SetSplitable(sal_Bool bSet)310     void SetSplitable( sal_Bool bSet ) { bSplitable = bSet; }
IsSplitable() const311     sal_Bool IsSplitable() const { return bSplitable; }
312 
GetStyleName() const313     const OUString& GetStyleName() const { return aStyleName; }
GetDefaultCellStyleName() const314     const OUString& GetDefaultCellStyleName() const { return aDfltCellStyleName; }
GetXmlId() const315     const OUString& GetXmlId() const { return mXmlId; }
316 
317     void Dispose();
318 };
319 
SwXMLTableRow_Impl(const OUString & rStyleName,sal_uInt32 nCells,const OUString * pDfltCellStyleName,const OUString & i_rXmlId)320 SwXMLTableRow_Impl::SwXMLTableRow_Impl( const OUString& rStyleName,
321                                         sal_uInt32 nCells,
322                                         const OUString *pDfltCellStyleName,
323                                         const OUString& i_rXmlId ) :
324     aStyleName( rStyleName ),
325     mXmlId( i_rXmlId ),
326     bSplitable( sal_False )
327 {
328     if( pDfltCellStyleName )
329         aDfltCellStyleName = *pDfltCellStyleName;
330     ASSERT( nCells <= USHRT_MAX,
331             "SwXMLTableRow_Impl::SwXMLTableRow_Impl: too many cells" );
332     if( nCells > USHRT_MAX )
333         nCells = USHRT_MAX;
334 
335     for( sal_uInt16 i=0U; i<nCells; i++ )
336     {
337         aCells.Insert( new SwXMLTableCell_Impl, aCells.Count() );
338     }
339 }
340 
GetCell(sal_uInt32 nCol) const341 inline SwXMLTableCell_Impl *SwXMLTableRow_Impl::GetCell( sal_uInt32 nCol ) const
342 {
343     ASSERT( nCol < USHRT_MAX,
344             "SwXMLTableRow_Impl::GetCell: column number is to big" );
345     // --> OD 2009-03-19 #i95726# - some fault tolerance
346 //    return aCells[(sal_uInt16)nCol];
347     ASSERT( nCol < aCells.Count(),
348             "SwXMLTableRow_Impl::GetCell: column number is out of bound" );
349     return nCol < aCells.Count() ? aCells[(sal_uInt16)nCol] : 0;
350     // <--
351 }
352 
Expand(sal_uInt32 nCells,sal_Bool bOneCell)353 void SwXMLTableRow_Impl::Expand( sal_uInt32 nCells, sal_Bool bOneCell )
354 {
355     ASSERT( nCells <= USHRT_MAX,
356             "SwXMLTableRow_Impl::Expand: too many cells" );
357     if( nCells > USHRT_MAX )
358         nCells = USHRT_MAX;
359 
360     sal_uInt32 nColSpan = nCells - aCells.Count();
361     for( sal_uInt16 i=aCells.Count(); i<nCells; i++ )
362     {
363         aCells.Insert( new SwXMLTableCell_Impl( 1UL,
364                                                 bOneCell ? nColSpan : 1UL ),
365                        aCells.Count() );
366         nColSpan--;
367     }
368 
369     ASSERT( nCells<=aCells.Count(),
370             "SwXMLTableRow_Impl::Expand: wrong number of cells" );
371 }
372 
Set(const OUString & rStyleName,const OUString & rDfltCellStyleName,const OUString & i_rXmlId)373 inline void SwXMLTableRow_Impl::Set( const OUString& rStyleName,
374                                      const OUString& rDfltCellStyleName,
375                                      const OUString& i_rXmlId )
376 {
377     aStyleName = rStyleName;
378     aDfltCellStyleName = rDfltCellStyleName;
379     mXmlId = i_rXmlId;
380 }
381 
Dispose()382 void SwXMLTableRow_Impl::Dispose()
383 {
384     for( sal_uInt16 i=0; i < aCells.Count(); i++ )
385         aCells[i]->Dispose();
386 }
387 
388 // ---------------------------------------------------------------------
389 
390 class SwXMLTableCellContext_Impl : public SvXMLImportContext
391 {
392     OUString aStyleName;
393     OUString sFormula;
394     OUString sSaveParaDefault;
395     OUString mXmlId;
396 
397     SvXMLImportContextRef   xMyTable;
398 
399     double fValue;
400     sal_Bool bHasValue;
401     sal_Bool bHasTextValue;
402     sal_Bool bProtect;
403 
404     sal_uInt32                  nRowSpan;
405     sal_uInt32                  nColSpan;
406     sal_uInt32                  nColRepeat;
407 
408     sal_Bool                    bHasTextContent : 1;
409     sal_Bool                    bHasTableContent : 1;
410 
GetTable()411     SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
412 
HasContent() const413     sal_Bool HasContent() const { return bHasTextContent || bHasTableContent; }
414     inline void _InsertContent();
415     inline void InsertContent();
416     inline void InsertContentIfNotThere();
417     inline void InsertContent( SwXMLTableContext *pTable );
418 
419 public:
420 
421     SwXMLTableCellContext_Impl(
422             SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
423             const Reference< xml::sax::XAttributeList > & xAttrList,
424             SwXMLTableContext *pTable );
425 
426     virtual ~SwXMLTableCellContext_Impl();
427 
428     virtual SvXMLImportContext *CreateChildContext(
429             sal_uInt16 nPrefix, const OUString& rLocalName,
430             const Reference< xml::sax::XAttributeList > & xAttrList );
431     virtual void EndElement();
432 
GetSwImport()433     SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
434 };
435 
SwXMLTableCellContext_Impl(SwXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const Reference<xml::sax::XAttributeList> & xAttrList,SwXMLTableContext * pTable)436 SwXMLTableCellContext_Impl::SwXMLTableCellContext_Impl(
437         SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
438         const Reference< xml::sax::XAttributeList > & xAttrList,
439         SwXMLTableContext *pTable ) :
440     SvXMLImportContext( rImport, nPrfx, rLName ),
441     sFormula(),
442     xMyTable( pTable ),
443     fValue( 0.0 ),
444     bHasValue( sal_False ),
445     bHasTextValue( sal_False ),
446     bProtect( sal_False ),
447     nRowSpan( 1UL ),
448     nColSpan( 1UL ),
449     nColRepeat( 1UL ),
450     bHasTextContent( sal_False ),
451     bHasTableContent( sal_False )
452 {
453     sSaveParaDefault = GetImport().GetTextImport()->GetCellParaStyleDefault();
454     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
455     for( sal_Int16 i=0; i < nAttrCount; i++ )
456     {
457         const OUString& rAttrName = xAttrList->getNameByIndex( i );
458 
459         OUString aLocalName;
460         sal_uInt16 nPrefix =
461             GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
462                                                             &aLocalName );
463         const OUString& rValue = xAttrList->getValueByIndex( i );
464         const SvXMLTokenMap& rTokenMap =
465             GetSwImport().GetTableCellAttrTokenMap();
466         switch( rTokenMap.Get( nPrefix, aLocalName ) )
467         {
468         case XML_TOK_TABLE_XMLID:
469             mXmlId = rValue;
470             break;
471         case XML_TOK_TABLE_STYLE_NAME:
472             aStyleName = rValue;
473             GetImport().GetTextImport()->SetCellParaStyleDefault(rValue);
474             break;
475         case XML_TOK_TABLE_NUM_COLS_SPANNED:
476             nColSpan = (sal_uInt32)rValue.toInt32();
477             if( nColSpan < 1UL )
478                 nColSpan = 1UL;
479             break;
480         case XML_TOK_TABLE_NUM_ROWS_SPANNED:
481             nRowSpan = (sal_uInt32)rValue.toInt32();
482             if( nRowSpan < 1UL )
483                 nRowSpan = 1UL;
484             break;
485         case XML_TOK_TABLE_NUM_COLS_REPEATED:
486             nColRepeat = (sal_uInt32)rValue.toInt32();
487             if( nColRepeat < 1UL )
488                 nColRepeat = 1UL;
489             break;
490         case XML_TOK_TABLE_FORMULA:
491             {
492                 OUString sTmp;
493                 sal_uInt16 nPrefix2 = GetImport().GetNamespaceMap().
494                         _GetKeyByAttrName( rValue, &sTmp, sal_False );
495                 sFormula = XML_NAMESPACE_OOOW == nPrefix2 ? sTmp : rValue;
496             }
497             break;
498         case XML_TOK_TABLE_VALUE:
499             {
500                 double fTmp;
501                 if (SvXMLUnitConverter::convertDouble(fTmp, rValue))
502                 {
503                     fValue = fTmp;
504                     bHasValue = sal_True;
505                 }
506             }
507             break;
508         case XML_TOK_TABLE_TIME_VALUE:
509             {
510                 double fTmp;
511                 if (SvXMLUnitConverter::convertTime(fTmp, rValue))
512                 {
513                     fValue = fTmp;
514                     bHasValue = sal_True;
515                 }
516             }
517             break;
518         case XML_TOK_TABLE_DATE_VALUE:
519             {
520                 double fTmp;
521                 if (GetImport().GetMM100UnitConverter().convertDateTime(fTmp,
522                                                                       rValue))
523                 {
524                     fValue = fTmp;
525                     bHasValue = sal_True;
526                 }
527             }
528             break;
529         case XML_TOK_TABLE_BOOLEAN_VALUE:
530             {
531                 sal_Bool bTmp;
532                 if (SvXMLUnitConverter::convertBool(bTmp, rValue))
533                 {
534                     fValue = (bTmp ? 1.0 : 0.0);
535                     bHasValue = sal_True;
536                 }
537             }
538             break;
539         case XML_TOK_TABLE_PROTECTED:
540             {
541                 sal_Bool bTmp;
542                 if (SvXMLUnitConverter::convertBool(bTmp, rValue))
543                 {
544                     bProtect = bTmp;
545                 }
546             }
547             break;
548         case XML_TOK_TABLE_STRING_VALUE:
549             {
550                 bHasTextValue = sal_True;
551             }
552             break;
553         }
554     }
555 }
556 
~SwXMLTableCellContext_Impl()557 SwXMLTableCellContext_Impl::~SwXMLTableCellContext_Impl()
558 {
559 }
560 
_InsertContent()561 inline void SwXMLTableCellContext_Impl::_InsertContent()
562 {
563     GetTable()->InsertCell( aStyleName, nRowSpan, nColSpan,
564                             GetTable()->InsertTableSection(),
565                             mXmlId,
566                             NULL, bProtect, &sFormula, bHasValue, fValue, bHasTextValue );
567 }
568 
InsertContent()569 inline void SwXMLTableCellContext_Impl::InsertContent()
570 {
571     ASSERT( !HasContent(), "content already there" );
572     bHasTextContent = sal_True;
573     _InsertContent();
574 }
575 
InsertContentIfNotThere()576 inline void SwXMLTableCellContext_Impl::InsertContentIfNotThere()
577 {
578     if( !HasContent() )
579         InsertContent();
580 }
581 
InsertContent(SwXMLTableContext * pTable)582 inline void SwXMLTableCellContext_Impl::InsertContent(
583                                                 SwXMLTableContext *pTable )
584 {
585     GetTable()->InsertCell( aStyleName, nRowSpan, nColSpan, 0, mXmlId, pTable, bProtect );
586     bHasTableContent = sal_True;
587 }
588 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const Reference<xml::sax::XAttributeList> & xAttrList)589 SvXMLImportContext *SwXMLTableCellContext_Impl::CreateChildContext(
590         sal_uInt16 nPrefix,
591         const OUString& rLocalName,
592         const Reference< xml::sax::XAttributeList > & xAttrList )
593 {
594     SvXMLImportContext *pContext = 0;
595 
596     OUString sXmlId;
597     sal_Bool bSubTable = sal_False;
598     if( XML_NAMESPACE_TABLE == nPrefix &&
599         IsXMLToken( rLocalName, XML_TABLE ) )
600     {
601         sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
602         for( sal_Int16 i=0; i < nAttrCount; i++ )
603         {
604             const OUString& rAttrName = xAttrList->getNameByIndex( i );
605 
606             OUString aLocalName;
607             sal_uInt16 nPrefix2 =
608                 GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
609                                                                 &aLocalName );
610             if( XML_NAMESPACE_TABLE == nPrefix2 &&
611                 IsXMLToken( aLocalName, XML_IS_SUB_TABLE ) &&
612                 IsXMLToken( xAttrList->getValueByIndex( i ), XML_TRUE ) )
613             {
614                 bSubTable = sal_True;
615             }
616             else if ( (XML_NAMESPACE_XML == nPrefix2) &&
617                      IsXMLToken( aLocalName, XML_ID ) )
618             {
619                 sXmlId = xAttrList->getValueByIndex( i );
620             }
621 //FIXME: RDFa
622         }
623     }
624 
625     if( bSubTable )
626     {
627         if( !HasContent() )
628         {
629             SwXMLTableContext *pTblContext =
630                 new SwXMLTableContext( GetSwImport(), nPrefix, rLocalName,
631                                        xAttrList, GetTable(), sXmlId );
632             pContext = pTblContext;
633             if( GetTable()->IsValid() )
634                 InsertContent( pTblContext );
635 
636             GetTable()->SetHasSubTables( sal_True );
637         }
638     }
639     else
640     {
641         if( GetTable()->IsValid() )
642             InsertContentIfNotThere();
643         pContext = GetImport().GetTextImport()->CreateTextChildContext(
644                         GetImport(), nPrefix, rLocalName, xAttrList,
645                         XML_TEXT_TYPE_CELL );
646     }
647 
648     if( !pContext )
649         pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
650 
651     return pContext;
652 }
653 
EndElement()654 void SwXMLTableCellContext_Impl::EndElement()
655 {
656     if( GetTable()->IsValid() )
657     {
658         if( bHasTextContent )
659         {
660             GetImport().GetTextImport()->DeleteParagraph();
661             if( nColRepeat > 1 && nColSpan == 1 )
662             {
663                 // The original text is invalid after deleting the last
664                 // paragraph
665                 Reference < XTextCursor > xSrcTxtCursor =
666                     GetImport().GetTextImport()->GetText()->createTextCursor();
667                 xSrcTxtCursor->gotoEnd( sal_True );
668 
669                 // Until we have an API for copying we have to use the core.
670                 Reference<XUnoTunnel> xSrcCrsrTunnel( xSrcTxtCursor, UNO_QUERY);
671                 ASSERT( xSrcCrsrTunnel.is(), "missing XUnoTunnel for Cursor" );
672                 OTextCursorHelper *pSrcTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
673                         sal::static_int_cast< sal_IntPtr >( xSrcCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )));
674                 ASSERT( pSrcTxtCrsr, "SwXTextCursor missing" );
675                 SwDoc *pDoc = pSrcTxtCrsr->GetDoc();
676                 const SwPaM *pSrcPaM = pSrcTxtCrsr->GetPaM();
677 
678                 while( nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
679                 {
680                     _InsertContent();
681 
682                     Reference<XUnoTunnel> xDstCrsrTunnel(
683                         GetImport().GetTextImport()->GetCursor(), UNO_QUERY);
684                     ASSERT( xDstCrsrTunnel.is(),
685                             "missing XUnoTunnel for Cursor" );
686                     OTextCursorHelper *pDstTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
687                             sal::static_int_cast< sal_IntPtr >( xDstCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )) );
688                     ASSERT( pDstTxtCrsr, "SwXTextCursor missing" );
689                     SwPaM aSrcPaM( *pSrcPaM->GetPoint(),
690                                    *pSrcPaM->GetMark() );
691                     SwPosition aDstPos( *pDstTxtCrsr->GetPaM()->GetPoint() );
692                     pDoc->CopyRange( aSrcPaM, aDstPos, false );
693 
694                     nColRepeat--;
695                 }
696             }
697         }
698         else if( !bHasTableContent )
699         {
700             InsertContent();
701             if( nColRepeat > 1 && nColSpan == 1 )
702             {
703                 while( nColRepeat > 1 && GetTable()->IsInsertCellPossible() )
704                 {
705                     _InsertContent();
706                     nColRepeat--;
707                 }
708             }
709         }
710     }
711     GetImport().GetTextImport()->SetCellParaStyleDefault(sSaveParaDefault);
712 }
713 
714 // ---------------------------------------------------------------------
715 
716 class SwXMLTableColContext_Impl : public SvXMLImportContext
717 {
718     SvXMLImportContextRef   xMyTable;
719 
GetTable()720     SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
721 
722 public:
723 
724     SwXMLTableColContext_Impl(
725             SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
726             const Reference< xml::sax::XAttributeList > & xAttrList,
727             SwXMLTableContext *pTable );
728 
729     virtual ~SwXMLTableColContext_Impl();
730 
GetSwImport()731     SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
732 };
733 
SwXMLTableColContext_Impl(SwXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const Reference<xml::sax::XAttributeList> & xAttrList,SwXMLTableContext * pTable)734 SwXMLTableColContext_Impl::SwXMLTableColContext_Impl(
735         SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
736         const Reference< xml::sax::XAttributeList > & xAttrList,
737         SwXMLTableContext *pTable ) :
738     SvXMLImportContext( rImport, nPrfx, rLName ),
739     xMyTable( pTable )
740 {
741     sal_uInt32 nColRep = 1UL;
742     OUString aStyleName, aDfltCellStyleName;
743 
744     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
745     for( sal_Int16 i=0; i < nAttrCount; i++ )
746     {
747         const OUString& rAttrName = xAttrList->getNameByIndex( i );
748 
749         OUString aLocalName;
750         sal_uInt16 nPrefix =
751             GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
752                                                             &aLocalName );
753         const OUString& rValue = xAttrList->getValueByIndex( i );
754         if( XML_NAMESPACE_TABLE == nPrefix )
755         {
756             if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
757                 aStyleName = rValue;
758             else if( IsXMLToken( aLocalName, XML_NUMBER_COLUMNS_REPEATED ) )
759                 nColRep = (sal_uInt32)rValue.toInt32();
760             else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
761                 aDfltCellStyleName = rValue;
762         }
763         else if ( (XML_NAMESPACE_XML == nPrefix) &&
764                  IsXMLToken( aLocalName, XML_ID ) )
765         {
766             (void) rValue;
767 //FIXME where to put this??? columns do not actually exist in Writer...
768         }
769     }
770 
771     sal_Int32 nWidth = MINLAY;
772     sal_Bool bRelWidth = sal_True;
773     if( aStyleName.getLength() )
774     {
775         const SfxPoolItem *pItem;
776         const SfxItemSet *pAutoItemSet = 0;
777         if( GetSwImport().FindAutomaticStyle(
778                     XML_STYLE_FAMILY_TABLE_COLUMN,
779                                               aStyleName, &pAutoItemSet ) &&
780             pAutoItemSet &&
781             SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_FRM_SIZE, sal_False,
782                                                         &pItem ) )
783         {
784             const SwFmtFrmSize *pSize = ((const SwFmtFrmSize *)pItem);
785             nWidth = pSize->GetWidth();
786             bRelWidth = ATT_VAR_SIZE == pSize->GetHeightSizeType();
787         }
788     }
789 
790     if( nWidth )
791     {
792         while( nColRep-- && GetTable()->IsInsertColPossible() )
793             GetTable()->InsertColumn( nWidth, bRelWidth, &aDfltCellStyleName );
794     }
795 }
796 
~SwXMLTableColContext_Impl()797 SwXMLTableColContext_Impl::~SwXMLTableColContext_Impl()
798 {
799 }
800 
801 // ---------------------------------------------------------------------
802 
803 class SwXMLTableColsContext_Impl : public SvXMLImportContext
804 {
805     SvXMLImportContextRef   xMyTable;
806     sal_Bool bHeader;
807 
GetTable()808     SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
809 
810 public:
811 
812     SwXMLTableColsContext_Impl(
813             SwXMLImport& rImport, sal_uInt16 nPrfx,
814             const OUString& rLName,
815             const Reference< xml::sax::XAttributeList > & xAttrList,
816             SwXMLTableContext *pTable,
817             sal_Bool bHead );
818 
819     virtual ~SwXMLTableColsContext_Impl();
820 
821     virtual SvXMLImportContext *CreateChildContext(
822             sal_uInt16 nPrefix, const OUString& rLocalName,
823             const Reference< xml::sax::XAttributeList > & xAttrList );
824 
GetSwImport()825     SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
826 };
827 
SwXMLTableColsContext_Impl(SwXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const Reference<xml::sax::XAttributeList> &,SwXMLTableContext * pTable,sal_Bool bHead)828 SwXMLTableColsContext_Impl::SwXMLTableColsContext_Impl(
829         SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
830         const Reference< xml::sax::XAttributeList > &,
831         SwXMLTableContext *pTable, sal_Bool bHead ) :
832     SvXMLImportContext( rImport, nPrfx, rLName ),
833     xMyTable( pTable ),
834     bHeader( bHead )
835 {
836 }
837 
~SwXMLTableColsContext_Impl()838 SwXMLTableColsContext_Impl::~SwXMLTableColsContext_Impl()
839 {
840 }
841 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const Reference<xml::sax::XAttributeList> & xAttrList)842 SvXMLImportContext *SwXMLTableColsContext_Impl::CreateChildContext(
843         sal_uInt16 nPrefix,
844         const OUString& rLocalName,
845         const Reference< xml::sax::XAttributeList > & xAttrList )
846 {
847     SvXMLImportContext *pContext = 0;
848 
849     if( XML_NAMESPACE_TABLE == nPrefix &&
850         IsXMLToken( rLocalName, XML_TABLE_COLUMN ) &&
851         GetTable()->IsInsertColPossible() )
852         pContext = new SwXMLTableColContext_Impl( GetSwImport(), nPrefix,
853                                                   rLocalName, xAttrList,
854                                                   GetTable() );
855 
856     if( !pContext )
857         pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
858 
859     return pContext;
860 }
861 
862 // ---------------------------------------------------------------------
863 
864 class SwXMLTableRowContext_Impl : public SvXMLImportContext
865 {
866     SvXMLImportContextRef   xMyTable;
867 
868     sal_uInt32                  nRowRepeat;
869 
GetTable()870     SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
871 
872 public:
873 
874     SwXMLTableRowContext_Impl(
875             SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName,
876             const Reference< xml::sax::XAttributeList > & xAttrList,
877             SwXMLTableContext *pTable, sal_Bool bInHead=sal_False );
878 
879     virtual ~SwXMLTableRowContext_Impl();
880 
881     virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
882             const OUString& rLocalName,
883             const Reference< xml::sax::XAttributeList > & xAttrList );
884 
885     virtual void EndElement();
886 
GetSwImport()887     SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
888 };
889 
SwXMLTableRowContext_Impl(SwXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const Reference<xml::sax::XAttributeList> & xAttrList,SwXMLTableContext * pTable,sal_Bool bInHead)890 SwXMLTableRowContext_Impl::SwXMLTableRowContext_Impl( SwXMLImport& rImport,
891         sal_uInt16 nPrfx,
892         const OUString& rLName,
893         const Reference< xml::sax::XAttributeList > & xAttrList,
894         SwXMLTableContext *pTable,
895         sal_Bool bInHead ) :
896     SvXMLImportContext( rImport, nPrfx, rLName ),
897     xMyTable( pTable ),
898     nRowRepeat( 1 )
899 {
900     OUString aStyleName, aDfltCellStyleName;
901     OUString sXmlId;
902 
903     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
904     for( sal_Int16 i=0; i < nAttrCount; i++ )
905     {
906         const OUString& rAttrName = xAttrList->getNameByIndex( i );
907 
908         OUString aLocalName;
909         sal_uInt16 nPrefix =
910             GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
911                                                             &aLocalName );
912         const OUString& rValue = xAttrList->getValueByIndex( i );
913         if( XML_NAMESPACE_TABLE == nPrefix )
914         {
915             if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
916             {
917                 aStyleName = rValue;
918             }
919             else if( IsXMLToken( aLocalName, XML_NUMBER_ROWS_REPEATED ) )
920             {
921                 nRowRepeat = (sal_uInt32)rValue.toInt32();
922                 if( nRowRepeat < 1UL )
923                     nRowRepeat = 1UL;
924             }
925             else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
926             {
927                 aDfltCellStyleName = rValue;
928             }
929         }
930         else if ( (XML_NAMESPACE_XML == nPrefix) &&
931                  IsXMLToken( aLocalName, XML_ID ) )
932         {
933             sXmlId = rValue;
934         }
935     }
936     if( GetTable()->IsValid() )
937         GetTable()->InsertRow( aStyleName, aDfltCellStyleName, bInHead,
938                                sXmlId );
939 }
940 
EndElement()941 void SwXMLTableRowContext_Impl::EndElement()
942 {
943     if( GetTable()->IsValid() )
944     {
945         GetTable()->FinishRow();
946 
947         if( nRowRepeat > 1UL )
948             GetTable()->InsertRepRows( nRowRepeat );
949     }
950 }
951 
~SwXMLTableRowContext_Impl()952 SwXMLTableRowContext_Impl::~SwXMLTableRowContext_Impl()
953 {
954 }
955 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const Reference<xml::sax::XAttributeList> & xAttrList)956 SvXMLImportContext *SwXMLTableRowContext_Impl::CreateChildContext(
957         sal_uInt16 nPrefix, const OUString& rLocalName,
958         const Reference< xml::sax::XAttributeList > & xAttrList )
959 {
960     SvXMLImportContext *pContext = 0;
961 
962     if( XML_NAMESPACE_TABLE == nPrefix )
963     {
964         if( IsXMLToken( rLocalName, XML_TABLE_CELL ) )
965         {
966             if( !GetTable()->IsValid() || GetTable()->IsInsertCellPossible() )
967                 pContext = new SwXMLTableCellContext_Impl( GetSwImport(),
968                                                            nPrefix,
969                                                            rLocalName,
970                                                            xAttrList,
971                                                            GetTable() );
972         }
973         else if( IsXMLToken( rLocalName, XML_COVERED_TABLE_CELL ) )
974             pContext = new SvXMLImportContext( GetImport(), nPrefix,
975                                                rLocalName );
976     }
977 
978     if( !pContext )
979         pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
980 
981     return pContext;
982 }
983 
984 // ---------------------------------------------------------------------
985 
986 class SwXMLTableRowsContext_Impl : public SvXMLImportContext
987 {
988     SvXMLImportContextRef   xMyTable;
989 
990     sal_Bool bHeader;
991 
GetTable()992     SwXMLTableContext *GetTable() { return (SwXMLTableContext *)&xMyTable; }
993 
994 public:
995 
996     SwXMLTableRowsContext_Impl( SwXMLImport& rImport, sal_uInt16 nPrfx,
997             const OUString& rLName,
998             const Reference< xml::sax::XAttributeList > & xAttrList,
999             SwXMLTableContext *pTable,
1000             sal_Bool bHead );
1001 
1002     virtual ~SwXMLTableRowsContext_Impl();
1003 
1004     virtual SvXMLImportContext *CreateChildContext( sal_uInt16 nPrefix,
1005             const OUString& rLocalName,
1006             const Reference< xml::sax::XAttributeList > & xAttrList );
1007 
GetSwImport()1008     SwXMLImport& GetSwImport() { return (SwXMLImport&)GetImport(); }
1009 };
1010 
SwXMLTableRowsContext_Impl(SwXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const Reference<xml::sax::XAttributeList> &,SwXMLTableContext * pTable,sal_Bool bHead)1011 SwXMLTableRowsContext_Impl::SwXMLTableRowsContext_Impl( SwXMLImport& rImport,
1012         sal_uInt16 nPrfx,
1013         const OUString& rLName,
1014         const Reference< xml::sax::XAttributeList > &,
1015         SwXMLTableContext *pTable,
1016         sal_Bool bHead ) :
1017     SvXMLImportContext( rImport, nPrfx, rLName ),
1018     xMyTable( pTable ),
1019     bHeader( bHead )
1020 {
1021 }
1022 
~SwXMLTableRowsContext_Impl()1023 SwXMLTableRowsContext_Impl::~SwXMLTableRowsContext_Impl()
1024 {
1025 }
1026 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const Reference<xml::sax::XAttributeList> & xAttrList)1027 SvXMLImportContext *SwXMLTableRowsContext_Impl::CreateChildContext(
1028         sal_uInt16 nPrefix,
1029         const OUString& rLocalName,
1030         const Reference< xml::sax::XAttributeList > & xAttrList )
1031 {
1032     SvXMLImportContext *pContext = 0;
1033 
1034     if( XML_NAMESPACE_TABLE == nPrefix &&
1035         IsXMLToken( rLocalName, XML_TABLE_ROW ) &&
1036         GetTable()->IsInsertRowPossible() )
1037         pContext = new SwXMLTableRowContext_Impl( GetSwImport(), nPrefix,
1038                                                   rLocalName, xAttrList,
1039                                                   GetTable(),
1040                                                   bHeader );
1041 
1042     if( !pContext )
1043         pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1044 
1045     return pContext;
1046 }
1047 
1048 // ---------------------------------------------------------------------
1049 
1050 class SwXMLDDETableContext_Impl : public SvXMLImportContext
1051 {
1052     OUString sConnectionName;
1053     OUString sDDEApplication;
1054     OUString sDDEItem;
1055     OUString sDDETopic;
1056     sal_Bool bIsAutomaticUpdate;
1057 
1058 public:
1059 
1060     TYPEINFO();
1061 
1062     SwXMLDDETableContext_Impl(
1063         SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName);
1064 
1065     ~SwXMLDDETableContext_Impl();
1066 
1067     virtual void StartElement(
1068         const Reference<xml::sax::XAttributeList> & xAttrList);
1069 
GetConnectionName()1070     OUString& GetConnectionName()   { return sConnectionName; }
GetDDEApplication()1071     OUString& GetDDEApplication()   { return sDDEApplication; }
GetDDEItem()1072     OUString& GetDDEItem()          { return sDDEItem; }
GetDDETopic()1073     OUString& GetDDETopic()         { return sDDETopic; }
GetIsAutomaticUpdate()1074     sal_Bool GetIsAutomaticUpdate() { return bIsAutomaticUpdate; }
1075 };
1076 
1077 TYPEINIT1( SwXMLDDETableContext_Impl, SvXMLImportContext );
1078 
SwXMLDDETableContext_Impl(SwXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName)1079 SwXMLDDETableContext_Impl::SwXMLDDETableContext_Impl(
1080     SwXMLImport& rImport, sal_uInt16 nPrfx, const OUString& rLName) :
1081         SvXMLImportContext(rImport, nPrfx, rLName),
1082         sConnectionName(),
1083         sDDEApplication(),
1084         sDDEItem(),
1085         sDDETopic(),
1086         bIsAutomaticUpdate(sal_False)
1087 {
1088 }
1089 
~SwXMLDDETableContext_Impl()1090 SwXMLDDETableContext_Impl::~SwXMLDDETableContext_Impl()
1091 {
1092 }
1093 
StartElement(const Reference<xml::sax::XAttributeList> & xAttrList)1094 void SwXMLDDETableContext_Impl::StartElement(
1095     const Reference<xml::sax::XAttributeList> & xAttrList)
1096 {
1097     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
1098     for( sal_Int16 i = 0; i < nAttrCount; i++ )
1099     {
1100         const OUString& rAttrName = xAttrList->getNameByIndex( i );
1101 
1102         OUString aLocalName;
1103         sal_uInt16 nPrefix =
1104             GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
1105                                                             &aLocalName );
1106         const OUString& rValue = xAttrList->getValueByIndex( i );
1107 
1108         if (XML_NAMESPACE_OFFICE == nPrefix)
1109         {
1110             if ( IsXMLToken( aLocalName, XML_DDE_APPLICATION ) )
1111             {
1112                 sDDEApplication = rValue;
1113             }
1114             else if ( IsXMLToken( aLocalName, XML_DDE_TOPIC ) )
1115             {
1116                 sDDETopic = rValue;
1117             }
1118             else if ( IsXMLToken( aLocalName, XML_DDE_ITEM ) )
1119             {
1120                 sDDEItem = rValue;
1121             }
1122             else if ( IsXMLToken( aLocalName, XML_NAME ) )
1123             {
1124                 sConnectionName = rValue;
1125             }
1126             else if ( IsXMLToken( aLocalName, XML_AUTOMATIC_UPDATE ) )
1127             {
1128                 sal_Bool bTmp;
1129                 if (SvXMLUnitConverter::convertBool(bTmp, rValue))
1130                 {
1131                     bIsAutomaticUpdate = bTmp;
1132                 }
1133             }
1134             // else: unknown attribute
1135         }
1136         // else: unknown attribute namespace
1137     }
1138 }
1139 
1140 // generate a new name for DDE field type (called by lcl_GetDDEFieldType below)
lcl_GenerateFldTypeName(OUString sPrefix,SwTableNode * pTableNode)1141 String lcl_GenerateFldTypeName(OUString sPrefix, SwTableNode* pTableNode)
1142 {
1143     String sPrefixStr(sPrefix);
1144 
1145     if (sPrefixStr.Len() == 0)
1146     {
1147         sPrefixStr = String('_');
1148     }
1149 //  else if (sPrefixStr.Copy(0, 1).IsAlphaAscii())
1150 //  {
1151 //      sPrefixStr.Insert('_', 0);
1152 //  }
1153     // else: name is OK.
1154 
1155     // increase count until we find a name that is not yet taken
1156     String sName;
1157     sal_Int32 nCount = 0;
1158     do
1159     {
1160         // this is crazy, but just in case all names are taken: exit gracefully
1161         if (nCount < 0)
1162             return sName;
1163 
1164         nCount++;
1165         sName = sPrefixStr;
1166         sName += String::CreateFromInt32(nCount);
1167 
1168     }
1169     while (NULL != pTableNode->GetDoc()->GetFldType(RES_DDEFLD, sName, false));
1170 
1171     return sName;
1172 }
1173 
1174 // set table properties
lcl_GetDDEFieldType(SwXMLDDETableContext_Impl * pContext,SwTableNode * pTableNode)1175 SwDDEFieldType* lcl_GetDDEFieldType(SwXMLDDETableContext_Impl* pContext,
1176                                     SwTableNode* pTableNode)
1177 {
1178     // make command string
1179     String sCommand(pContext->GetDDEApplication());
1180     sCommand += sfx2::cTokenSeperator;
1181     sCommand += String(pContext->GetDDEItem());
1182     sCommand += sfx2::cTokenSeperator;
1183     sCommand += String(pContext->GetDDETopic());
1184 
1185     sal_uInt16 nType = static_cast< sal_uInt16 >(pContext->GetIsAutomaticUpdate() ? sfx2::LINKUPDATE_ALWAYS
1186                                                         : sfx2::LINKUPDATE_ONCALL);
1187 
1188     String sName(pContext->GetConnectionName());
1189 
1190     // field type to be returned
1191     SwDDEFieldType* pType = NULL;
1192 
1193     // valid name?
1194     if (sName.Len() == 0)
1195     {
1196         sName = lcl_GenerateFldTypeName(pContext->GetDDEApplication(),
1197                                         pTableNode);
1198     }
1199     else
1200     {
1201         // check for existing DDE field type with the same name
1202         SwDDEFieldType* pOldType = (SwDDEFieldType*)pTableNode->GetDoc()->GetFldType(RES_DDEFLD, sName, false);
1203         if (NULL != pOldType)
1204         {
1205             // same values -> return old type
1206             if ( (pOldType->GetCmd() == sCommand) &&
1207                  (pOldType->GetType() == nType) )
1208             {
1209                 // same name, same values -> return old type!
1210                 pType = pOldType;
1211             }
1212             else
1213             {
1214                 // same name, different values -> think of new name
1215                 sName = lcl_GenerateFldTypeName(pContext->GetDDEApplication(),
1216                                                 pTableNode);
1217             }
1218         }
1219         // no old type -> create new one
1220     }
1221 
1222     // create new field type (unless we already have one)
1223     if (NULL == pType)
1224     {
1225         // create new field type and return
1226         SwDDEFieldType aDDEFieldType(sName, sCommand, nType);
1227         pType = (SwDDEFieldType*)pTableNode->
1228             GetDoc()->InsertFldType(aDDEFieldType);
1229     }
1230 
1231     DBG_ASSERT(NULL != pType, "We really want a SwDDEFieldType here!");
1232     return pType;
1233 }
1234 
1235 
1236 // ---------------------------------------------------------------------
1237 
1238 class TableBoxIndex
1239 {
1240 public:
1241     OUString msName;
1242     sal_Int32 mnWidth;
1243     sal_Bool mbProtected;
1244 
TableBoxIndex(const OUString & rName,sal_Int32 nWidth,sal_Bool bProtected)1245     TableBoxIndex( const OUString& rName, sal_Int32 nWidth,
1246                    sal_Bool bProtected ) :
1247         msName( rName ),
1248         mnWidth( nWidth ),
1249         mbProtected( bProtected )
1250     { }
1251 
operator ==(const TableBoxIndex & rArg) const1252     bool operator== ( const TableBoxIndex& rArg ) const
1253     {
1254         return (rArg.mnWidth == mnWidth) &&
1255             (rArg.mbProtected == mbProtected) &&
1256             (rArg.msName == msName);
1257     }
1258 };
1259 
1260 class TableBoxIndexHasher
1261 {
1262 public:
operator ()(const TableBoxIndex & rArg) const1263     size_t operator() (const TableBoxIndex& rArg) const
1264     {
1265         return rArg.msName.hashCode() + rArg.mnWidth + rArg.mbProtected;
1266     }
1267 };
1268 
1269 
1270 
1271 
1272 typedef SwXMLTableRow_Impl* SwXMLTableRowPtr;
1273 SV_DECL_PTRARR_DEL(SwXMLTableRows_Impl,SwXMLTableRowPtr,5,5)
SV_IMPL_PTRARR(SwXMLTableRows_Impl,SwXMLTableRowPtr)1274 SV_IMPL_PTRARR(SwXMLTableRows_Impl,SwXMLTableRowPtr)
1275 
1276 SwXMLTableCell_Impl *SwXMLTableContext::GetCell( sal_uInt32 nRow,
1277                                                  sal_uInt32 nCol ) const
1278 {
1279     return (*pRows)[(sal_uInt16)nRow]->GetCell( (sal_uInt16)nCol );
1280 }
1281 
1282 TYPEINIT1( SwXMLTableContext, XMLTextTableContext );
1283 
SwXMLTableContext(SwXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const Reference<xml::sax::XAttributeList> & xAttrList)1284 SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
1285         sal_uInt16 nPrfx,
1286         const OUString& rLName,
1287         const Reference< xml::sax::XAttributeList > & xAttrList ) :
1288     XMLTextTableContext( rImport, nPrfx, rLName ),
1289     pColumnDefaultCellStyleNames( 0 ),
1290     pRows( new SwXMLTableRows_Impl ),
1291     pTableNode( 0 ),
1292     pBox1( 0 ),
1293     pSttNd1( 0 ),
1294     pBoxFmt( 0 ),
1295     pLineFmt( 0 ),
1296     pSharedBoxFormats(NULL),
1297     pDDESource(NULL),
1298     bFirstSection( sal_True ),
1299     bRelWidth( sal_True ),
1300     bHasSubTables( sal_False ),
1301     nHeaderRows( 0 ),
1302     nCurRow( 0UL ),
1303     nCurCol( 0UL ),
1304     nWidth( 0UL )
1305 {
1306     OUString aName;
1307     OUString sXmlId;
1308 
1309     // this method will modify the document directly -> lock SolarMutex
1310     vos::OGuard aGuard(Application::GetSolarMutex());
1311 
1312     sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
1313     for( sal_Int16 i=0; i < nAttrCount; i++ )
1314     {
1315         const OUString& rAttrName = xAttrList->getNameByIndex( i );
1316 
1317         OUString aLocalName;
1318         sal_uInt16 nPrefix =
1319             GetImport().GetNamespaceMap().GetKeyByAttrName( rAttrName,
1320                                                             &aLocalName );
1321         const OUString& rValue = xAttrList->getValueByIndex( i );
1322         if( XML_NAMESPACE_TABLE == nPrefix )
1323         {
1324             if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
1325                 aStyleName = rValue;
1326             else if( IsXMLToken( aLocalName, XML_NAME ) )
1327                 aName = rValue;
1328             else if( IsXMLToken( aLocalName, XML_DEFAULT_CELL_STYLE_NAME ) )
1329                 aDfltCellStyleName = rValue;
1330         }
1331         else if ( (XML_NAMESPACE_XML == nPrefix) &&
1332                  IsXMLToken( aLocalName, XML_ID ) )
1333         {
1334             sXmlId = rValue;
1335         }
1336     }
1337 
1338     SwDoc *pDoc = SwImport::GetDocFromXMLImport( GetSwImport() );
1339 
1340     String sTblName;
1341     if( aName.getLength() )
1342     {
1343         const SwTableFmt *pTblFmt = pDoc->FindTblFmtByName( aName );
1344         if( !pTblFmt )
1345             sTblName = aName;
1346     }
1347     if( !sTblName.Len() )
1348     {
1349         sTblName = pDoc->GetUniqueTblName();
1350         GetImport().GetTextImport()
1351             ->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_TABLE, aName, sTblName );
1352     }
1353 
1354     Reference< XTextTable > xTable;
1355     const SwXTextTable *pXTable = 0;
1356     Reference<XMultiServiceFactory> xFactory( GetImport().GetModel(),
1357                                               UNO_QUERY );
1358     ASSERT( xFactory.is(), "factory missing" );
1359     if( xFactory.is() )
1360     {
1361         OUString sService(
1362                 RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.text.TextTable" ) );
1363         Reference<XInterface> xIfc = xFactory->createInstance( sService );
1364         ASSERT( xIfc.is(), "Couldn't create a table" );
1365 
1366         if( xIfc.is() )
1367             xTable = Reference< XTextTable > ( xIfc, UNO_QUERY );
1368     }
1369 
1370     if( xTable.is() )
1371     {
1372         xTable->initialize( 1, 1 );
1373 
1374         try
1375         {
1376             xTextContent = Reference< XTextContent >( xTable, UNO_QUERY );
1377             GetImport().GetTextImport()->InsertTextContent( xTextContent );
1378         }
1379         catch( IllegalArgumentException& )
1380         {
1381             xTable = 0;
1382         }
1383     }
1384 
1385     if( xTable.is() )
1386     {
1387 //FIXME
1388         // xml:id for RDF metadata
1389         GetImport().SetXmlId(xTable, sXmlId);
1390 
1391         Reference<XUnoTunnel> xTableTunnel( xTable, UNO_QUERY);
1392         if( xTableTunnel.is() )
1393         {
1394             pXTable = reinterpret_cast< SwXTextTable * >(
1395                     sal::static_int_cast< sal_IntPtr >( xTableTunnel->getSomething( SwXTextTable::getUnoTunnelId() )));
1396             ASSERT( pXTable, "SwXTextTable missing" );
1397         }
1398 
1399         Reference < XCellRange > xCellRange( xTable, UNO_QUERY );
1400         Reference < XCell > xCell = xCellRange->getCellByPosition( 0, 0 );
1401         Reference < XText> xText( xCell, UNO_QUERY );
1402         xOldCursor = GetImport().GetTextImport()->GetCursor();
1403         GetImport().GetTextImport()->SetCursor( xText->createTextCursor() );
1404 
1405         // take care of open redlines for tables
1406         GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(sal_True);
1407     }
1408     if( pXTable )
1409     {
1410         SwFrmFmt *pTblFrmFmt = pXTable->GetFrmFmt();
1411         ASSERT( pTblFrmFmt, "table format missing" );
1412         SwTable *pTbl = SwTable::FindTable( pTblFrmFmt );
1413         ASSERT( pTbl, "table missing" );
1414         pTableNode = pTbl->GetTableNode();
1415         ASSERT( pTableNode, "table node missing" );
1416 
1417         pTblFrmFmt->SetName( sTblName );
1418 
1419         SwTableLine *pLine1 = pTableNode->GetTable().GetTabLines()[0U];
1420         pBox1 = pLine1->GetTabBoxes()[0U];
1421         pSttNd1 = pBox1->GetSttNd();
1422     }
1423 }
1424 
SwXMLTableContext(SwXMLImport & rImport,sal_uInt16 nPrfx,const OUString & rLName,const Reference<xml::sax::XAttributeList> &,SwXMLTableContext * pTable,OUString const & i_rXmlId)1425 SwXMLTableContext::SwXMLTableContext( SwXMLImport& rImport,
1426         sal_uInt16 nPrfx,
1427         const OUString& rLName,
1428         const Reference< xml::sax::XAttributeList > &,
1429         SwXMLTableContext *pTable,
1430         OUString const & i_rXmlId ) :
1431     XMLTextTableContext( rImport, nPrfx, rLName ),
1432     mXmlId( i_rXmlId ),
1433     pColumnDefaultCellStyleNames( 0 ),
1434     pRows( new SwXMLTableRows_Impl ),
1435     pTableNode( pTable->pTableNode ),
1436     pBox1( 0 ),
1437     pSttNd1( 0 ),
1438     pBoxFmt( 0 ),
1439     pLineFmt( 0 ),
1440     pSharedBoxFormats(NULL),
1441     xParentTable( pTable ),
1442     pDDESource(NULL),
1443     bFirstSection( sal_False ),
1444     bRelWidth( sal_True ),
1445     bHasSubTables( sal_False ),
1446     nHeaderRows( 0 ),
1447     nCurRow( 0UL ),
1448     nCurCol( 0UL ),
1449     nWidth( 0UL )
1450 {
1451 }
1452 
~SwXMLTableContext()1453 SwXMLTableContext::~SwXMLTableContext()
1454 {
1455     delete pColumnDefaultCellStyleNames;
1456     delete pSharedBoxFormats;
1457     delete pRows;
1458 
1459     // close redlines on table end nodes
1460     GetImport().GetTextImport()->RedlineAdjustStartNodeCursor(sal_False);
1461 }
1462 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLocalName,const Reference<xml::sax::XAttributeList> & xAttrList)1463 SvXMLImportContext *SwXMLTableContext::CreateChildContext( sal_uInt16 nPrefix,
1464         const OUString& rLocalName,
1465         const Reference< xml::sax::XAttributeList > & xAttrList )
1466 {
1467     SvXMLImportContext *pContext = 0;
1468 
1469     const SvXMLTokenMap& rTokenMap = GetSwImport().GetTableElemTokenMap();
1470     sal_Bool bHeader = sal_False;
1471     switch( rTokenMap.Get( nPrefix, rLocalName ) )
1472     {
1473     case XML_TOK_TABLE_HEADER_COLS:
1474         bHeader = sal_True;
1475     case XML_TOK_TABLE_COLS:
1476         if( IsValid() )
1477             pContext = new SwXMLTableColsContext_Impl( GetSwImport(), nPrefix,
1478                                                        rLocalName, xAttrList,
1479                                                        this, bHeader );
1480         break;
1481     case XML_TOK_TABLE_COL:
1482         if( IsValid() && IsInsertColPossible() )
1483             pContext = new SwXMLTableColContext_Impl( GetSwImport(), nPrefix,
1484                                                       rLocalName, xAttrList,
1485                                                       this );
1486         break;
1487     case XML_TOK_TABLE_HEADER_ROWS:
1488         bHeader = sal_True;
1489     case XML_TOK_TABLE_ROWS:
1490         pContext = new SwXMLTableRowsContext_Impl( GetSwImport(), nPrefix,
1491                                                    rLocalName, xAttrList,
1492                                                    this, bHeader );
1493         break;
1494     case XML_TOK_TABLE_ROW:
1495         if( IsInsertRowPossible() )
1496             pContext = new SwXMLTableRowContext_Impl( GetSwImport(), nPrefix,
1497                                                       rLocalName, xAttrList,
1498                                                       this );
1499         break;
1500     case XML_TOK_OFFICE_DDE_SOURCE:
1501         // save context for later processing (discard old context, if approp.)
1502         if( IsValid() )
1503         {
1504             if (pDDESource != NULL)
1505             {
1506                 pDDESource->ReleaseRef();
1507             }
1508             pDDESource = new SwXMLDDETableContext_Impl( GetSwImport(), nPrefix,
1509                                                         rLocalName );
1510             pDDESource->AddRef();
1511             pContext = pDDESource;
1512         }
1513         break;
1514     }
1515 
1516     if( !pContext )
1517         pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1518 
1519     return pContext;
1520 }
1521 
InsertColumn(sal_Int32 nWidth2,sal_Bool bRelWidth2,const OUString * pDfltCellStyleName)1522 void SwXMLTableContext::InsertColumn( sal_Int32 nWidth2, sal_Bool bRelWidth2,
1523                                       const OUString *pDfltCellStyleName )
1524 {
1525     ASSERT( nCurCol < USHRT_MAX,
1526             "SwXMLTableContext::InsertColumn: no space left" );
1527     if( nCurCol >= USHRT_MAX )
1528         return;
1529 
1530     if( nWidth2 < MINLAY )
1531         nWidth2 = MINLAY;
1532     else if( nWidth2 > USHRT_MAX )
1533         nWidth2 = USHRT_MAX;
1534     aColumnWidths.Insert( (sal_uInt16)nWidth2, aColumnWidths.Count() );
1535     aColumnRelWidths.push_back( bRelWidth2 );
1536     if( (pDfltCellStyleName && pDfltCellStyleName->getLength() > 0) ||
1537         pColumnDefaultCellStyleNames )
1538     {
1539         if( !pColumnDefaultCellStyleNames )
1540         {
1541             pColumnDefaultCellStyleNames = new SvStringsDtor;
1542             size_t nCount = aColumnRelWidths.size() - 1;
1543             while( nCount-- )
1544                 pColumnDefaultCellStyleNames->Insert( new String,
1545                     pColumnDefaultCellStyleNames->Count() );
1546         }
1547 
1548         pColumnDefaultCellStyleNames->Insert(
1549             pDfltCellStyleName ? new String( *pDfltCellStyleName ) : new String,
1550             pColumnDefaultCellStyleNames->Count() );
1551     }
1552 }
1553 
GetColumnWidth(sal_uInt32 nCol,sal_uInt32 nColSpan) const1554 sal_Int32 SwXMLTableContext::GetColumnWidth( sal_uInt32 nCol,
1555                                              sal_uInt32 nColSpan ) const
1556 {
1557     sal_uInt32 nLast = nCol+nColSpan;
1558     if( nLast > aColumnWidths.Count() )
1559         nLast = aColumnWidths.Count();
1560 
1561     sal_Int32 nWidth2 = 0L;
1562     for( sal_uInt16 i=(sal_uInt16)nCol; i < nLast; i++ )
1563         nWidth2 += aColumnWidths[i];
1564 
1565     return nWidth2;
1566 }
1567 
GetColumnDefaultCellStyleName(sal_uInt32 nCol) const1568 OUString SwXMLTableContext::GetColumnDefaultCellStyleName( sal_uInt32 nCol ) const
1569 {
1570     OUString sRet;
1571     if( pColumnDefaultCellStyleNames )
1572         sRet =  *(*pColumnDefaultCellStyleNames)[(sal_uInt16)nCol];
1573 
1574     return sRet;
1575 }
1576 
InsertCell(const OUString & rStyleName,sal_uInt32 nRowSpan,sal_uInt32 nColSpan,const SwStartNode * pStartNode,const OUString & i_rXmlId,SwXMLTableContext * pTable,sal_Bool bProtect,const OUString * pFormula,sal_Bool bHasValue,double fValue,sal_Bool bTextValue)1577 void SwXMLTableContext::InsertCell( const OUString& rStyleName,
1578                                     sal_uInt32 nRowSpan, sal_uInt32 nColSpan,
1579                                     const SwStartNode *pStartNode,
1580                                     const OUString & i_rXmlId,
1581                                     SwXMLTableContext *pTable,
1582                                     sal_Bool bProtect,
1583                                     const OUString* pFormula,
1584                                     sal_Bool bHasValue,
1585                                     double fValue,
1586                                     sal_Bool bTextValue )
1587 {
1588     ASSERT( nCurCol < GetColumnCount(),
1589             "SwXMLTableContext::InsertCell: row is full" );
1590     ASSERT( nCurRow < USHRT_MAX,
1591             "SwXMLTableContext::InsertCell: table is full" );
1592     if( nCurCol >= USHRT_MAX || nCurRow > USHRT_MAX )
1593         return;
1594 
1595     ASSERT( nRowSpan >=1UL, "SwXMLTableContext::InsertCell: row span is 0" );
1596     if( 0UL == nRowSpan )
1597         nRowSpan = 1UL;
1598     ASSERT( nColSpan >=1UL, "SwXMLTableContext::InsertCell: col span is 0" );
1599     if( 0UL == nColSpan )
1600         nColSpan = 1UL;
1601 
1602     sal_uInt32 i, j;
1603 
1604     // Until it is possible to add columns here, fix the column span.
1605     sal_uInt32 nColsReq = nCurCol + nColSpan;
1606     if( nColsReq > GetColumnCount() )
1607     {
1608         nColSpan = GetColumnCount() - nCurCol;
1609         nColsReq = GetColumnCount();
1610     }
1611 
1612     // Check whether there are cells from a previous line already that reach
1613     // into the current row.
1614     if( nCurRow > 0UL && nColSpan > 1UL )
1615     {
1616         SwXMLTableRow_Impl *pCurRow = (*pRows)[(sal_uInt16)nCurRow];
1617         sal_uInt32 nLastCol = GetColumnCount() < nColsReq ? GetColumnCount()
1618                                                      : nColsReq;
1619         for( i=nCurCol+1UL; i<nLastCol; i++ )
1620         {
1621             if( pCurRow->GetCell(i)->IsUsed() )
1622             {
1623                 // If this cell is used, the column span is truncated
1624                 nColSpan = i - nCurCol;
1625                 nColsReq = i;
1626                 break;
1627             }
1628         }
1629     }
1630 
1631     sal_uInt32 nRowsReq = nCurRow + nRowSpan;
1632     if( nRowsReq > USHRT_MAX )
1633     {
1634         nRowSpan = USHRT_MAX - nCurRow;
1635         nRowsReq = USHRT_MAX;
1636     }
1637 
1638     // Add columns (if # required columns greater than # columns):
1639     // This should never happen, since we require column definitions!
1640     if ( nColsReq > GetColumnCount() )
1641     {
1642         for( i=GetColumnCount(); i<nColsReq; i++ )
1643         {
1644             aColumnWidths.Insert( MINLAY, aColumnWidths.Count() );
1645             aColumnRelWidths.push_back( sal_True );
1646         }
1647         // adjust columns in *all* rows, if columns must be inserted
1648         for( i=0; i<pRows->Count(); i++ )
1649             (*pRows)[(sal_uInt16)i]->Expand( nColsReq, i<nCurRow );
1650     }
1651 
1652     // Add rows
1653     if( pRows->Count() < nRowsReq )
1654     {
1655         OUString aStyleName2;
1656         for( i = pRows->Count(); i < nRowsReq; ++i )
1657             pRows->Insert( new SwXMLTableRow_Impl(aStyleName2, GetColumnCount()),
1658                            pRows->Count() );
1659     }
1660 
1661     OUString sStyleName( rStyleName );
1662     if( !sStyleName.getLength() )
1663     {
1664         sStyleName = ((*pRows)[(sal_uInt16)nCurRow])->GetDefaultCellStyleName();
1665         if( !sStyleName.getLength() && HasColumnDefaultCellStyleNames() )
1666         {
1667             sStyleName = GetColumnDefaultCellStyleName( nCurCol );
1668             if( !sStyleName.getLength() )
1669                 sStyleName = aDfltCellStyleName;
1670         }
1671     }
1672 
1673     // Fill the cells
1674     for( i=nColSpan; i>0UL; i-- )
1675     {
1676         for( j=nRowSpan; j>0UL; j-- )
1677         {
1678             const bool bCovered = i != nColSpan || j != nRowSpan;
1679             GetCell( nRowsReq-j, nColsReq-i )
1680                 ->Set( sStyleName, j, i, pStartNode,
1681                        pTable, bProtect, pFormula, bHasValue, bCovered, fValue,
1682                        bTextValue, i_rXmlId );
1683         }
1684     }
1685 
1686     // Set current col to the next (free) column
1687     nCurCol = nColsReq;
1688     while( nCurCol<GetColumnCount() && GetCell(nCurRow,nCurCol)->IsUsed() )
1689         nCurCol++;
1690 }
1691 
InsertRow(const OUString & rStyleName,const OUString & rDfltCellStyleName,sal_Bool bInHead,const OUString & i_rXmlId)1692 void SwXMLTableContext::InsertRow( const OUString& rStyleName,
1693                                    const OUString& rDfltCellStyleName,
1694                                    sal_Bool bInHead,
1695                                    const OUString & i_rXmlId )
1696 {
1697     ASSERT( nCurRow < USHRT_MAX,
1698             "SwXMLTableContext::InsertRow: no space left" );
1699     if( nCurRow >= USHRT_MAX )
1700         return;
1701 
1702     // Make sure there is at least one column.
1703     if( 0==nCurRow && 0UL == GetColumnCount() )
1704         InsertColumn( USHRT_MAX, sal_True );
1705 
1706     if( nCurRow < pRows->Count() )
1707     {
1708         // The current row has already been inserted because of a row span
1709         // of a previous row.
1710         (*pRows)[(sal_uInt16)nCurRow]->Set(
1711             rStyleName, rDfltCellStyleName, i_rXmlId );
1712     }
1713     else
1714     {
1715         // add a new row
1716         pRows->Insert( new SwXMLTableRow_Impl( rStyleName, GetColumnCount(),
1717                                                &rDfltCellStyleName, i_rXmlId ),
1718                        pRows->Count() );
1719     }
1720 
1721     // We start at the first column ...
1722     nCurCol=0UL;
1723 
1724     // ... but this cell may be occupied already.
1725     while( nCurCol<GetColumnCount() && GetCell(nCurRow,nCurCol)->IsUsed() )
1726         nCurCol++;
1727 
1728     if( bInHead  &&  nHeaderRows == nCurRow )
1729         nHeaderRows++;
1730 }
1731 
InsertRepRows(sal_uInt32 nCount)1732 void SwXMLTableContext::InsertRepRows( sal_uInt32 nCount )
1733 {
1734     const SwXMLTableRow_Impl *pSrcRow = (*pRows)[(sal_uInt16)nCurRow-1];
1735     while( nCount > 1 && IsInsertRowPossible() )
1736     {
1737         InsertRow( pSrcRow->GetStyleName(), pSrcRow->GetDefaultCellStyleName(),
1738                    sal_False );
1739         while( nCurCol < GetColumnCount() )
1740         {
1741             if( !GetCell(nCurRow,nCurCol)->IsUsed() )
1742             {
1743                 const SwXMLTableCell_Impl *pSrcCell =
1744                     GetCell( nCurRow-1, nCurCol );
1745                 InsertCell( pSrcCell->GetStyleName(), 1U,
1746                             pSrcCell->GetColSpan(),
1747                             InsertTableSection(),
1748                             OUString(),
1749                             0, pSrcCell->IsProtected(),
1750                             &pSrcCell->GetFormula(),
1751                             pSrcCell->HasValue(), pSrcCell->GetValue(),
1752                             pSrcCell->HasTextValue() );
1753             }
1754         }
1755         FinishRow();
1756         nCount--;
1757     }
1758 }
1759 
FinishRow()1760 void SwXMLTableContext::FinishRow()
1761 {
1762     // Insert an empty cell at the end of the line if the row is not complete
1763     if( nCurCol < GetColumnCount() )
1764     {
1765         OUString aStyleName2;
1766         InsertCell( aStyleName2, 1U, GetColumnCount() - nCurCol,
1767                     InsertTableSection() );
1768     }
1769 
1770     // Move to the next row.
1771     nCurRow++;
1772 }
1773 
GetPrevStartNode(sal_uInt32 nRow,sal_uInt32 nCol) const1774 const SwStartNode *SwXMLTableContext::GetPrevStartNode( sal_uInt32 nRow,
1775                                                         sal_uInt32 nCol ) const
1776 {
1777     const SwXMLTableCell_Impl *pPrevCell = 0;
1778     if( GetColumnCount() == nCol )
1779     {
1780         // The last cell is the right one here.
1781         pPrevCell = GetCell( pRows->Count()-1U, GetColumnCount()-1UL );
1782     }
1783     else if( 0UL == nRow )
1784     {
1785         // There are no vertically merged cells within the first row, so the
1786         // previous cell is the right one always.
1787         if( nCol > 0UL )
1788             pPrevCell = GetCell( nRow, nCol-1UL );
1789     }
1790     else
1791     {
1792         // If there is a previous cell in the current row that is not spanned
1793         // from the previous row, its the right one.
1794         const SwXMLTableRow_Impl *pPrevRow = (*pRows)[(sal_uInt16)nRow-1U];
1795         sal_uInt32 i = nCol;
1796         while( !pPrevCell &&  i > 0UL )
1797         {
1798             i--;
1799             if( 1UL == pPrevRow->GetCell( i )->GetRowSpan() )
1800                 pPrevCell = GetCell( nRow, i );
1801         }
1802 
1803         // Otherwise, the last cell from the previous row is the right one.
1804         if( !pPrevCell )
1805             pPrevCell = pPrevRow->GetCell( GetColumnCount()-1UL );
1806     }
1807 
1808     const SwStartNode *pSttNd = 0;
1809     if( pPrevCell )
1810     {
1811         if( pPrevCell->GetStartNode() )
1812             pSttNd = pPrevCell->GetStartNode();
1813         // --> OD 2009-03-19 #i95726# - Some fault tolerance
1814 //        else
1815         else if ( pPrevCell->GetSubTable() )
1816         // <--
1817             pSttNd = pPrevCell->GetSubTable()->GetLastStartNode();
1818 
1819         ASSERT( pSttNd != 0,
1820                 "table corrupt" );
1821     }
1822 
1823     return pSttNd;
1824 }
1825 
FixRowSpan(sal_uInt32 nRow,sal_uInt32 nCol,sal_uInt32 nColSpan)1826 void SwXMLTableContext::FixRowSpan( sal_uInt32 nRow, sal_uInt32 nCol,
1827                                     sal_uInt32 nColSpan )
1828 {
1829     sal_uInt32 nLastCol = nCol + nColSpan;
1830     for( sal_uInt16 i = (sal_uInt16)nCol; i < nLastCol; i++ )
1831     {
1832         sal_uInt32 j = nRow;
1833         sal_uInt32 nRowSpan = 1UL;
1834         SwXMLTableCell_Impl *pCell = GetCell( j, i );
1835         while( pCell && pCell->GetRowSpan() > 1UL )
1836         {
1837             pCell->SetRowSpan( nRowSpan++ );
1838             pCell = j > 0UL ? GetCell( --j, i ) : 0;
1839         }
1840     }
1841 }
1842 
ReplaceWithEmptyCell(sal_uInt32 nRow,sal_uInt32 nCol,bool bRows)1843 void SwXMLTableContext::ReplaceWithEmptyCell( sal_uInt32 nRow, sal_uInt32 nCol, bool bRows )
1844 {
1845     const SwStartNode *pPrevSttNd = GetPrevStartNode( nRow, nCol );
1846     const SwStartNode *pSttNd = InsertTableSection( pPrevSttNd );
1847 
1848     const SwXMLTableCell_Impl *pCell = GetCell( nRow, nCol );
1849     sal_uInt32 nLastRow = bRows ? nRow + pCell->GetRowSpan() : nRow + 1;
1850     sal_uInt32 nLastCol = nCol + pCell->GetColSpan();
1851 
1852     for( sal_uInt32 i=nRow; i<nLastRow; i++ )
1853     {
1854         SwXMLTableRow_Impl *pRow = (*pRows)[(sal_uInt16)i];
1855         for( sal_uInt32 j=nCol; j<nLastCol; j++ )
1856             pRow->GetCell( j )->SetStartNode( pSttNd );
1857     }
1858 
1859 }
1860 
NewTableBox(const SwStartNode * pStNd,SwTableLine * pUpper)1861 SwTableBox *SwXMLTableContext::NewTableBox( const SwStartNode *pStNd,
1862                                             SwTableLine *pUpper )
1863 {
1864     // The topmost table is the only table that maintains the two members
1865     // pBox1 and bFirstSection.
1866     if( xParentTable.Is() )
1867         return ((SwXMLTableContext *)&xParentTable)->NewTableBox( pStNd,
1868                                                                   pUpper );
1869 
1870     SwTableBox *pBox;
1871 
1872     if( pBox1 &&
1873         pBox1->GetSttNd() == pStNd )
1874     {
1875         // wenn der StartNode dem StartNode der initial angelegten Box
1876         // entspricht nehmen wir diese Box
1877         pBox = pBox1;
1878         pBox->SetUpper( pUpper );
1879         pBox1 = 0;
1880     }
1881     else
1882         pBox = new SwTableBox( pBoxFmt, *pStNd, pUpper );
1883 
1884     return pBox;
1885 }
1886 
GetSharedBoxFormat(SwTableBox * pBox,const OUString & rStyleName,sal_Int32 nColumnWidth,sal_Bool bProtected,sal_Bool bMayShare,sal_Bool & bNew,sal_Bool * pModifyLocked)1887 SwTableBoxFmt* SwXMLTableContext::GetSharedBoxFormat(
1888     SwTableBox* pBox,
1889     const OUString& rStyleName,
1890     sal_Int32 nColumnWidth,
1891     sal_Bool bProtected,
1892     sal_Bool bMayShare,
1893     sal_Bool& bNew,
1894     sal_Bool* pModifyLocked )
1895 {
1896     if ( pSharedBoxFormats == NULL )
1897         pSharedBoxFormats = new map_BoxFmt();
1898 
1899     SwTableBoxFmt* pBoxFmt2;
1900 
1901     TableBoxIndex aKey( rStyleName, nColumnWidth, bProtected );
1902     map_BoxFmt::iterator aIter = pSharedBoxFormats->find( aKey );
1903     if ( aIter == pSharedBoxFormats->end() )
1904     {
1905         // unknown format so far -> construct a new one
1906 
1907         // get the old format, and reset all attributes
1908         // (but preserve FillOrder)
1909         pBoxFmt2 = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
1910         SwFmtFillOrder aFillOrder( pBoxFmt2->GetFillOrder() );
1911         // --> OD 2007-01-25 #i73790# - method renamed
1912         pBoxFmt2->ResetAllFmtAttr();
1913         // <--
1914         pBoxFmt2->SetFmtAttr( aFillOrder );
1915         bNew = sal_True; // it's a new format now
1916 
1917         // share this format, if allowed
1918         if ( bMayShare )
1919             (*pSharedBoxFormats)[ aKey ] = pBoxFmt2;
1920     }
1921     else
1922     {
1923         // set the shared format
1924         pBoxFmt2 = aIter->second;
1925         pBox->ChgFrmFmt( pBoxFmt2 );
1926         bNew = sal_False; // copied from an existing format
1927 
1928         // claim it, if we are not allowed to share
1929         if ( !bMayShare )
1930             pBoxFmt2 = (SwTableBoxFmt*)pBox->ClaimFrmFmt();
1931     }
1932 
1933     // lock format (if so desired)
1934     if ( pModifyLocked != NULL )
1935     {
1936         (*pModifyLocked) = pBoxFmt2->IsModifyLocked();
1937         pBoxFmt2->LockModify();
1938     }
1939 
1940     return pBoxFmt2;
1941 }
1942 
MakeTableBox(SwTableLine * pUpper,sal_uInt32 nTopRow,sal_uInt32 nLeftCol,sal_uInt32 nBottomRow,sal_uInt32 nRightCol)1943 SwTableBox *SwXMLTableContext::MakeTableBox( SwTableLine *pUpper,
1944                                              sal_uInt32 nTopRow,
1945                                              sal_uInt32 nLeftCol,
1946                                              sal_uInt32 nBottomRow,
1947                                              sal_uInt32 nRightCol )
1948 {
1949 //FIXME: here would be a great place to handle XmlId for cell
1950     SwTableBox *pBox = new SwTableBox( pBoxFmt, 0, pUpper );
1951 
1952     sal_uInt32 nColSpan = nRightCol - nLeftCol;
1953     sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
1954 
1955     // TODO: Share formats!
1956     SwFrmFmt *pFrmFmt = pBox->ClaimFrmFmt();
1957     SwFmtFillOrder aFillOrder( pFrmFmt->GetFillOrder() );
1958     // --> OD 2007-01-25 #i73790# - method renamed
1959     pFrmFmt->ResetAllFmtAttr();
1960     // <--
1961     pFrmFmt->SetFmtAttr( aFillOrder );
1962 
1963     pFrmFmt->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nColWidth ) );
1964 
1965     SwTableLines& rLines = pBox->GetTabLines();
1966     sal_Bool bSplitted = sal_False;
1967 
1968     while( !bSplitted )
1969     {
1970         sal_uInt32 nStartRow = nTopRow;
1971         sal_uInt32 i;
1972 
1973         for( i = nTopRow; i < nBottomRow; i++ )
1974         {
1975             // Could the table be split behind the current row?
1976             sal_Bool bSplit = sal_True;
1977             SwXMLTableRow_Impl *pRow = (*pRows)[(sal_uInt16)i];
1978             for( sal_uInt32 j=nLeftCol; j<nRightCol; j++ )
1979             {
1980                 bSplit = ( 1UL == pRow->GetCell(j)->GetRowSpan() );
1981                 if( !bSplit )
1982                     break;
1983             }
1984             if( bSplit && (nStartRow>nTopRow || i+1UL<nBottomRow) )
1985             {
1986                 SwTableLine *pLine =
1987                     MakeTableLine( pBox, nStartRow, nLeftCol, i+1UL,
1988                                    nRightCol );
1989 
1990                 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
1991 
1992                 nStartRow = i+1UL;
1993                 bSplitted = sal_True;
1994             }
1995         }
1996         if( !bSplitted )
1997         {
1998             // No splitting was possible. That for, we have to force it.
1999             // Ruthless!
2000 
2001             nStartRow = nTopRow;
2002             while( nStartRow < nBottomRow )
2003             {
2004                 sal_uInt32 nMaxRowSpan = 0UL;
2005                 SwXMLTableRow_Impl *pStartRow = (*pRows)[(sal_uInt16)nStartRow];
2006                 SwXMLTableCell_Impl *pCell;
2007                 for( i=nLeftCol; i<nRightCol; i++ )
2008                     if( ( pCell=pStartRow->GetCell(i),
2009                           pCell->GetRowSpan() > nMaxRowSpan ) )
2010                         nMaxRowSpan = pCell->GetRowSpan();
2011 
2012                 nStartRow += nMaxRowSpan;
2013                 if( nStartRow<nBottomRow )
2014                 {
2015                     SwXMLTableRow_Impl *pPrevRow =
2016                                         (*pRows)[(sal_uInt16)nStartRow-1U];
2017                     i = nLeftCol;
2018                     while( i < nRightCol )
2019                     {
2020                         if( pPrevRow->GetCell(i)->GetRowSpan() > 1UL )
2021                         {
2022                             const SwXMLTableCell_Impl *pCell2 =
2023                                 GetCell( nStartRow, i );
2024                             const sal_uInt32 nColSpan2 = pCell2->GetColSpan();
2025                             FixRowSpan( nStartRow-1UL, i, nColSpan2 );
2026                             ReplaceWithEmptyCell( nStartRow, i, true );
2027                             i += nColSpan2;
2028                         }
2029                         else
2030                         {
2031                             i++;
2032                         }
2033                     }
2034                 }
2035             }
2036             // und jetzt nochmal von vorne ...
2037         }
2038     }
2039 
2040     return pBox;
2041 }
2042 
MakeTableBox(SwTableLine * pUpper,const SwXMLTableCell_Impl * pCell,sal_uInt32,sal_uInt32 nLeftCol,sal_uInt32,sal_uInt32 nRightCol)2043 SwTableBox *SwXMLTableContext::MakeTableBox(
2044         SwTableLine *pUpper, const SwXMLTableCell_Impl *pCell,
2045         sal_uInt32 /*nTopRow*/, sal_uInt32 nLeftCol, sal_uInt32 /*nBottomRow*/,
2046         sal_uInt32 nRightCol )
2047 {
2048 //FIXME: here would be a great place to handle XmlId for cell
2049     SwTableBox *pBox;
2050     sal_uInt32 nColSpan = nRightCol - nLeftCol;
2051     sal_Int32 nColWidth = GetColumnWidth( nLeftCol, nColSpan );
2052 
2053     if( pCell->GetStartNode() )
2054     {
2055         pBox = NewTableBox( pCell->GetStartNode(), pUpper );
2056     }
2057     else
2058     {
2059         // und die ist eine Tabelle: dann bauen wir eine neue
2060         // Box und fuegen die Zeilen der Tabelle in die Zeilen
2061         // der Box ein
2062         pBox = new SwTableBox( pBoxFmt, 0, pUpper );
2063         pCell->GetSubTable()->MakeTable( pBox, nColWidth );
2064     }
2065 
2066     // Share formats!
2067     OUString sStyleName = pCell->GetStyleName();
2068     sal_Bool bModifyLocked;
2069     sal_Bool bNew;
2070     SwTableBoxFmt *pBoxFmt2 = GetSharedBoxFormat(
2071         pBox, sStyleName, nColWidth, pCell->IsProtected(),
2072         pCell->GetStartNode() && pCell->GetFormula().getLength() == 0 &&
2073             ! pCell->HasValue(),
2074         bNew, &bModifyLocked );
2075 
2076     // if a new format was created, then we need to set the style
2077     if ( bNew )
2078     {
2079         // set style
2080         const SfxItemSet *pAutoItemSet = 0;
2081         if( pCell->GetStartNode() && !sStyleName.isEmpty() &&
2082             GetSwImport().FindAutomaticStyle(
2083                 XML_STYLE_FAMILY_TABLE_CELL, sStyleName, &pAutoItemSet ) )
2084         {
2085             if( pAutoItemSet )
2086                 pBoxFmt2->SetFmtAttr( *pAutoItemSet );
2087         }
2088     }
2089 
2090     if( pCell->GetStartNode() )
2091     {
2092 
2093         // #104801# try to rescue broken documents with a certain pattern
2094         // if: 1) the cell has a default number format (number 0)
2095         //     2) the call has no formula
2096         //     3) the value is 0.0
2097         //     4) the text doesn't look anything like 0.0
2098         //        [read: length > 10, or length smaller 10 and no 0 in it]
2099         // then make it a text cell!
2100         bool bSuppressNumericContent = false;
2101         if( pCell->HasValue() && (pCell->GetValue() == 0.0) &&
2102             (pCell->GetFormula().getLength() == 0) &&
2103             (sStyleName.getLength() != 0) )
2104         {
2105             // default num format?
2106             const SfxPoolItem* pItem = NULL;
2107             if( pBoxFmt2->GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem )
2108                             == SFX_ITEM_SET )
2109             {
2110                 const SwTblBoxNumFormat* pNumFormat =
2111                     static_cast<const SwTblBoxNumFormat*>( pItem );
2112                 if( ( pNumFormat != NULL ) && ( pNumFormat->GetValue() == 0 ) )
2113                 {
2114                     // only one text node?
2115                     SwNodeIndex aNodeIndex( *(pCell->GetStartNode()), 1 );
2116                     if( ( aNodeIndex.GetNode().EndOfSectionIndex() -
2117                           aNodeIndex.GetNode().StartOfSectionIndex() ) == 2 )
2118                     {
2119                         SwTxtNode* pTxtNode= aNodeIndex.GetNode().GetTxtNode();
2120                         if( pTxtNode != NULL )
2121                         {
2122                             // check text: does it look like some form of 0.0?
2123                             const String& rText = pTxtNode->GetTxt();
2124                             if( ( rText.Len() > 10 ) ||
2125                                 ( rText.Search( '0' ) == STRING_NOTFOUND ) )
2126                             {
2127                                 bSuppressNumericContent = true;
2128                             }
2129                         }
2130                     }
2131                     else
2132                         bSuppressNumericContent = true; // several nodes
2133                 }
2134             }
2135         }
2136 
2137         if( bSuppressNumericContent )
2138         {
2139             // suppress numeric content? Then reset number format!
2140             pBoxFmt2->ResetFmtAttr( RES_BOXATR_FORMULA );
2141             pBoxFmt2->ResetFmtAttr( RES_BOXATR_FORMAT );
2142             pBoxFmt2->ResetFmtAttr( RES_BOXATR_VALUE );
2143         }
2144         else
2145         {
2146             // the normal case: set formula and value (if available)
2147 
2148             const OUString& rFormula = pCell->GetFormula();
2149             if (rFormula.getLength() > 0)
2150             {
2151                 // formula cell: insert formula if valid
2152                 SwTblBoxFormula aFormulaItem( rFormula );
2153                 pBoxFmt2->SetFmtAttr( aFormulaItem );
2154             }
2155             else if( !pCell->HasValue() && pCell->HasTextValue() )
2156             {
2157                 // Check for another inconsistency:
2158                 // No value but a non-textual format, i.e. a number format
2159                 // Solution: the number format will be removed,
2160                 // the cell gets the default text format.
2161                 const SfxPoolItem* pItem = NULL;
2162                 if( pBoxFmt->GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem )
2163                     == SFX_ITEM_SET )
2164                 {
2165                     const SwDoc* pDoc = pBoxFmt->GetDoc();
2166                     const SvNumberFormatter* pNumberFormatter = pDoc ?
2167                         pDoc->GetNumberFormatter() : 0;
2168                     const SwTblBoxNumFormat* pNumFormat =
2169                         static_cast<const SwTblBoxNumFormat*>( pItem );
2170                     if( pNumFormat != NULL && pNumberFormatter &&
2171                         !pNumberFormatter->GetEntry( pNumFormat->GetValue() )->IsTextFormat() )
2172                         pBoxFmt->ResetFmtAttr( RES_BOXATR_FORMAT );
2173                 }
2174             }
2175             // always insert value, even if default
2176             if( pCell->HasValue() )
2177             {
2178                 SwTblBoxValue aValueItem( pCell->GetValue() );
2179                 pBoxFmt2->SetFmtAttr( aValueItem );
2180             }
2181         }
2182 
2183         // update cell content depend on the default language
2184         pBox->ActualiseValueBox();
2185     }
2186 
2187     // table cell protection
2188     if( pCell->IsProtected() )
2189     {
2190         SvxProtectItem aProtectItem( RES_PROTECT );
2191         aProtectItem.SetCntntProtect( sal_True );
2192         pBoxFmt2->SetFmtAttr( aProtectItem );
2193     }
2194 
2195     // restore old modify-lock state
2196     if (! bModifyLocked)
2197         pBoxFmt2->UnlockModify();
2198 
2199     pBoxFmt2->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nColWidth ) );
2200 
2201     return pBox;
2202 }
2203 
MakeTableLine(SwTableBox * pUpper,sal_uInt32 nTopRow,sal_uInt32 nLeftCol,sal_uInt32 nBottomRow,sal_uInt32 nRightCol)2204 SwTableLine *SwXMLTableContext::MakeTableLine( SwTableBox *pUpper,
2205                                                sal_uInt32 nTopRow,
2206                                                sal_uInt32 nLeftCol,
2207                                                sal_uInt32 nBottomRow,
2208                                                sal_uInt32 nRightCol )
2209 {
2210 //FIXME: here would be a great place to handle XmlId for row
2211     SwTableLine *pLine;
2212     if( !pUpper && 0UL==nTopRow )
2213     {
2214         pLine = pTableNode->GetTable().GetTabLines()[0U];
2215     }
2216     else
2217     {
2218         pLine = new SwTableLine( pLineFmt, 0, pUpper );
2219     }
2220 
2221     // TODO: Share formats!
2222     SwFrmFmt *pFrmFmt = pLine->ClaimFrmFmt();
2223     SwFmtFillOrder aFillOrder( pFrmFmt->GetFillOrder() );
2224     // --> OD 2007-01-25 #i73790# - method renamed
2225     pFrmFmt->ResetAllFmtAttr();
2226     // <--
2227     pFrmFmt->SetFmtAttr( aFillOrder );
2228 
2229     const SfxItemSet *pAutoItemSet = 0;
2230     const OUString& rStyleName = (*pRows)[(sal_uInt16)nTopRow]->GetStyleName();
2231     if( 1UL == (nBottomRow - nTopRow) &&
2232         rStyleName.getLength() &&
2233         GetSwImport().FindAutomaticStyle(
2234             XML_STYLE_FAMILY_TABLE_ROW, rStyleName, &pAutoItemSet ) )
2235     {
2236         if( pAutoItemSet )
2237             pFrmFmt->SetFmtAttr( *pAutoItemSet );
2238     }
2239 
2240     SwTableBoxes& rBoxes = pLine->GetTabBoxes();
2241 
2242     sal_uInt32 nStartCol = nLeftCol;
2243     while( nStartCol < nRightCol )
2244     {
2245         for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
2246             (*pRows)[(sal_uInt16)nRow]->SetSplitable( sal_True );
2247 
2248         sal_uInt32 nCol = nStartCol;
2249         sal_uInt32 nSplitCol = nRightCol;
2250         sal_Bool bSplitted = sal_False;
2251         while( !bSplitted )
2252         {
2253             ASSERT( nCol < nRightCol, "Zu weit gelaufen" );
2254 
2255             // Kann hinter der aktuellen HTML-Tabellen-Spalte gesplittet
2256             // werden? Wenn ja, könnte der enstehende Bereich auch noch
2257             // in Zeilen zerlegt werden, wenn man die nächste Spalte
2258             // hinzunimmt?
2259             sal_Bool bSplit = sal_True;
2260             sal_Bool bHoriSplitMayContinue = sal_False;
2261             sal_Bool bHoriSplitPossible = sal_False;
2262 
2263             if ( bHasSubTables )
2264             {
2265                 // Convert row spans if the table has subtables:
2266                 for( sal_uInt32 nRow=nTopRow; nRow<nBottomRow; nRow++ )
2267                 {
2268                     SwXMLTableCell_Impl *pCell = GetCell(nRow,nCol);
2269                     // Could the table fragment be splitted horizontally behind
2270                     // the current line?
2271                     sal_Bool bHoriSplit = (*pRows)[(sal_uInt16)nRow]->IsSplitable() &&
2272                                       nRow+1UL < nBottomRow &&
2273                                       1UL == pCell->GetRowSpan();
2274                     (*pRows)[(sal_uInt16)nRow]->SetSplitable( bHoriSplit );
2275 
2276                     // Could the table fragment be split vertically behind the
2277                     // current column up to the current line?
2278                     bSplit &= ( 1UL == pCell->GetColSpan() );
2279                     if( bSplit )
2280                     {
2281                         bHoriSplitPossible |= bHoriSplit;
2282 
2283                         // Could the current table fragment be split
2284                         // horizontally behind the next column, too?
2285                         bHoriSplit &= (nCol+1UL < nRightCol &&
2286                                        1UL == GetCell(nRow,nCol+1UL)->GetRowSpan());
2287                         bHoriSplitMayContinue |= bHoriSplit;
2288                     }
2289                 }
2290             }
2291             else
2292             {
2293                 // No subtables: We use the new table model.
2294                 SwXMLTableCell_Impl *pCell = GetCell(nTopRow,nCol);
2295 
2296                 // --> OD 2009-03-19 #i95726# - some fault tolerance
2297                 if ( pCell == 0 )
2298                 {
2299                     ASSERT( false, "table seems to be corrupt." );
2300                     break;
2301                 }
2302                 // <--
2303 
2304                 // Could the table fragment be split vertically behind the
2305                 // current column up to the current line?
2306                 bSplit = 1UL == pCell->GetColSpan();
2307             }
2308 
2309 #ifdef DBG_UTIL
2310             if( nCol == nRightCol-1UL )
2311             {
2312                 ASSERT( bSplit, "Split-Flag falsch" );
2313                 if ( bHasSubTables )
2314                 {
2315                     ASSERT( !bHoriSplitMayContinue,
2316                             "HoriSplitMayContinue-Flag falsch" );
2317                     SwXMLTableCell_Impl *pTmpCell = GetCell( nTopRow, nStartCol );
2318                     ASSERT( pTmpCell->GetRowSpan() != (nBottomRow-nTopRow) ||
2319                             !bHoriSplitPossible, "HoriSplitPossible-Flag falsch" );
2320                 }
2321             }
2322 #endif
2323 
2324             ASSERT( !bHasSubTables || !bHoriSplitMayContinue || bHoriSplitPossible,
2325                     "bHoriSplitMayContinue, aber nicht bHoriSplitPossible" );
2326 
2327             if( bSplit )
2328             {
2329                 SwTableBox* pBox = 0;
2330                 SwXMLTableCell_Impl *pCell = GetCell( nTopRow, nStartCol );
2331                 // --> OD 2009-03-19 #i95726# - some fault tolerance
2332                 if( ( !bHasSubTables || ( pCell->GetRowSpan() == (nBottomRow-nTopRow) ) ) &&
2333                     pCell->GetColSpan() == (nCol+1UL-nStartCol) &&
2334                     ( pCell->GetStartNode() || pCell->GetSubTable() ) )
2335                 // <--
2336                 {
2337                     // insert new empty cell for covered cells:
2338                     long nBoxRowSpan = 1;
2339                     if ( !bHasSubTables )
2340                     {
2341                         nBoxRowSpan = pCell->GetRowSpan();
2342                         if ( pCell->IsCovered() )
2343                         {
2344                             nBoxRowSpan = -1 * nBoxRowSpan;
2345                             ReplaceWithEmptyCell( nTopRow, nStartCol, false );
2346                         }
2347                     }
2348 
2349                     // The remaining box neither contains lines nor rows (i.e.
2350                     // is a content box
2351                     nSplitCol = nCol + 1UL;
2352 
2353                     pBox = MakeTableBox( pLine, pCell,
2354                                          nTopRow, nStartCol,
2355                                          nBottomRow, nSplitCol );
2356 
2357                     if ( 1 != nBoxRowSpan )
2358                         pBox->setRowSpan( nBoxRowSpan );
2359 
2360                     bSplitted = sal_True;
2361                 }
2362                 else if( bHasSubTables && bHoriSplitPossible && bHoriSplitMayContinue )
2363                 {
2364                     // The table fragment could be split behind the current
2365                     // column, and the remaining fragment could be divided
2366                     // into lines. Anyway, it could be that this applies to
2367                     // the next column, too. That for, we check the next
2368                     // column but remember the current one as a good place to
2369                     // split.
2370                     nSplitCol = nCol + 1UL;
2371                 }
2372                 else if ( bHasSubTables )
2373                 {
2374                     // If the table resulting table fragment could be divided
2375                     // into lines if splitting behind the current column, but
2376                     // this doesn't apply for the next column, we split behind
2377                     // the current column. This applies for the last column,
2378                     // too.
2379                     // If the resulting box cannot be split into rows,
2380                     // the split at the last split position we remembered.
2381                     if( bHoriSplitPossible || nSplitCol > nCol+1 )
2382                     {
2383                         ASSERT( !bHoriSplitMayContinue,
2384                                 "bHoriSplitMayContinue==sal_True" );
2385                         ASSERT( bHoriSplitPossible || nSplitCol == nRightCol,
2386                                 "bHoriSplitPossible-Flag sollte gesetzt sein" );
2387 
2388                         nSplitCol = nCol + 1UL;
2389                     }
2390 
2391                     pBox = MakeTableBox( pLine, nTopRow, nStartCol,
2392                                          nBottomRow, nSplitCol );
2393                     bSplitted = sal_True;
2394                 }
2395 
2396                 ASSERT( bHasSubTables || pBox, "Colspan trouble" )
2397 
2398                 if( pBox )
2399                     rBoxes.C40_INSERT( SwTableBox, pBox, rBoxes.Count() );
2400             }
2401             nCol++;
2402         }
2403         nStartCol = nSplitCol;
2404     }
2405 
2406     return pLine;
2407 }
2408 
_MakeTable(SwTableBox * pBox)2409 void SwXMLTableContext::_MakeTable( SwTableBox *pBox )
2410 {
2411     // fix column widths
2412     sal_uInt32 i;
2413     sal_uInt32 nCols = GetColumnCount();
2414 
2415     // If there are empty rows (because of some row span of previous rows)
2416     // the have to be deleted. The previous rows have to be truncated.
2417 
2418     if( pRows->Count() > nCurRow )
2419     {
2420         SwXMLTableRow_Impl *pPrevRow = (*pRows)[(sal_uInt16)nCurRow-1U];
2421         SwXMLTableCell_Impl *pCell;
2422         for( i=0UL; i<nCols; i++ )
2423         {
2424             if( ( pCell=pPrevRow->GetCell(i), pCell->GetRowSpan() > 1UL ) )
2425             {
2426                 FixRowSpan( nCurRow-1UL, i, 1UL );
2427             }
2428         }
2429         for( i=(sal_uInt32)pRows->Count()-1UL; i>=nCurRow; i-- )
2430             pRows->DeleteAndDestroy( (sal_uInt16)i );
2431     }
2432 
2433     if( 0UL == pRows->Count() )
2434     {
2435         OUString aStyleName2;
2436         InsertCell( aStyleName2, 1U, nCols, InsertTableSection() );
2437     }
2438 
2439     // TODO: Do we have to keep both values, the relative and the absolute
2440     // width?
2441     sal_Int32 nAbsWidth = 0L;
2442     sal_Int32 nMinAbsColWidth = 0L;
2443     sal_Int32 nRelWidth = 0L;
2444     sal_Int32 nMinRelColWidth = 0L;
2445     sal_uInt32 nRelCols = 0UL;
2446     for( i=0U; i < nCols; i++ )
2447     {
2448         sal_Int32 nColWidth = aColumnWidths[(sal_uInt16)i];
2449         if( aColumnRelWidths[(sal_uInt16)i] )
2450         {
2451             nRelWidth += nColWidth;
2452             if( 0L == nMinRelColWidth || nColWidth < nMinRelColWidth )
2453                 nMinRelColWidth = nColWidth;
2454             nRelCols++;
2455         }
2456         else
2457         {
2458             nAbsWidth += nColWidth;
2459             if( 0L == nMinAbsColWidth || nColWidth < nMinAbsColWidth )
2460                 nMinAbsColWidth = nColWidth;
2461         }
2462     }
2463     sal_uInt32 nAbsCols = nCols - nRelCols;
2464 
2465     if( bRelWidth )
2466     {
2467         // If there a columns that have an absolute width, we have to
2468         // calculate a relative one for them.
2469         if( nAbsCols > 0UL )
2470         {
2471             // All column that have absolute widths get relative widths;
2472             // these widths relate to each over like the original absolute
2473             // widths. The smallest column gets a width that hat the same
2474             // value as the smallest column that has an relative width
2475             // already.
2476             if( 0L == nMinRelColWidth )
2477                 nMinRelColWidth = nMinAbsColWidth;
2478 
2479             for( i=0UL; nAbsCols > 0UL && i < nCols; i++ )
2480             {
2481                 if( !aColumnRelWidths[(sal_uInt16)i] )
2482                 {
2483                     sal_Int32 nRelCol = (aColumnWidths[(sal_uInt16)i] * nMinRelColWidth) /
2484                                    nMinAbsColWidth;
2485                     aColumnWidths.Replace( (sal_uInt16)nRelCol, (sal_uInt16)i );
2486                     nRelWidth += nRelCol;
2487                     nAbsCols--;
2488                 }
2489             }
2490         }
2491 
2492         if( !nWidth )
2493         {
2494             // This happens only for percentage values for the table itself.
2495             // In this case, the columns get the correct width even if the
2496             // the sum of the relative width is smaller than the available
2497             // width in TWIP. Therefore, we can use the relative width.
2498             //
2499             nWidth = nRelWidth > USHRT_MAX ? USHRT_MAX : nRelWidth;
2500         }
2501         if( nRelWidth != nWidth && nRelWidth && nCols )
2502         {
2503             double n = (double)nWidth / (double)nRelWidth;
2504             nRelWidth = 0L;
2505             for( i=0U; i < nCols-1UL; i++ )
2506             {
2507                 sal_Int32 nW = (sal_Int32)(aColumnWidths[(sal_uInt16)i] * n);
2508                 aColumnWidths.Replace( (sal_uInt16)nW, (sal_uInt16)i );
2509                 nRelWidth += nW;
2510             }
2511             aColumnWidths.Replace( (sal_uInt16)(nWidth-nRelWidth),
2512                                    (sal_uInt16)nCols-1U );
2513         }
2514     }
2515     else
2516     {
2517         // If there are columns that have relative widths, we have to
2518         // calculate a absolute widths for them.
2519         if( nRelCols > 0UL )
2520         {
2521             // The absolute space that is available for all columns with a
2522             // relative width.
2523             sal_Int32 nAbsForRelWidth =
2524                     nWidth > nAbsWidth ? nWidth - nAbsWidth : (sal_Int32)0L;
2525 
2526             // The relative width that has to be distributed in addition to
2527             // equally widthed columns.
2528             sal_Int32 nExtraRel = nRelWidth - (nRelCols * nMinRelColWidth);
2529 
2530             // The absolute space that may be distributed in addition to
2531             // minimum widthed columns.
2532             sal_Int32 nMinAbs = nRelCols * MINLAY;
2533             sal_Int32 nExtraAbs =
2534                     nAbsForRelWidth > nMinAbs ? nAbsForRelWidth - nMinAbs : (sal_Int32)0L;
2535 
2536             sal_Bool bMin = sal_False;      // Do all columns get the mininum width?
2537             sal_Bool bMinExtra = sal_False; // Do all columns get the minimum width plus
2538                                     // some extra space?
2539 
2540             if( nAbsForRelWidth <= nMinAbs )
2541             {
2542                 // If there is not enough space left for all columns to
2543                 // get the minimum width, they get the minimum width, anyway.
2544                 nAbsForRelWidth = nMinAbs;
2545                 bMin = sal_True;
2546             }
2547             else if( nAbsForRelWidth <= (nRelWidth * MINLAY) /
2548                                         nMinRelColWidth )
2549             {
2550                 // If there is enough space for all columns to get the
2551                 // minimum width, but not to get a width that takes the
2552                 // relative width into account, each column gets the minimum
2553                 // width plus some extra space that is based on the additional
2554                 // space that is available.
2555                 bMinExtra = sal_True;
2556             }
2557             // Otherwise, if there is enough space for every column, every
2558             // column gets this space.
2559 
2560             for( i=0UL; nRelCols > 0UL && i < nCols; i++ )
2561             {
2562                 if( aColumnRelWidths[(sal_uInt16)i] )
2563                 {
2564                     sal_Int32 nAbsCol;
2565                     if( 1UL == nRelCols )
2566                     {
2567                         // The last column that has a relative width gets
2568                         // all absolute space that is left.
2569                         nAbsCol = nAbsForRelWidth;
2570                     }
2571                     else
2572                     {
2573                         if( bMin )
2574                         {
2575                             nAbsCol = MINLAY;
2576                         }
2577                         else if( bMinExtra )
2578                         {
2579                             sal_Int32 nExtraRelCol =
2580                                 aColumnWidths[(sal_uInt16)i] - nMinRelColWidth;
2581                             nAbsCol = MINLAY + (nExtraRelCol * nExtraAbs) /
2582                                                 nExtraRel;
2583                         }
2584                         else
2585                         {
2586                             nAbsCol = (aColumnWidths[(sal_uInt16)i] * nAbsForRelWidth) /
2587                                       nRelWidth;
2588                         }
2589                     }
2590                     aColumnWidths.Replace( (sal_uInt16)nAbsCol, (sal_uInt16)i );
2591                     nAbsForRelWidth -= nAbsCol;
2592                     nAbsWidth += nAbsCol;
2593                     nRelCols--;
2594                 }
2595             }
2596         }
2597 
2598         if( nCols && nAbsWidth )
2599         {
2600             if( nAbsWidth < nWidth )
2601             {
2602                 // If the table's width is larger than the absolute column widths,
2603                 // every column get some extra width.
2604                 sal_Int32 nExtraAbs = nWidth - nAbsWidth;
2605                 sal_Int32 nAbsLastCol =
2606                         aColumnWidths[(sal_uInt16)nCols-1U] + nExtraAbs;
2607                 for( i=0UL; i < nCols-1UL; i++ )
2608                 {
2609                     sal_Int32 nAbsCol = aColumnWidths[(sal_uInt16)i];
2610                     sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
2611                                              nAbsWidth;
2612                     nAbsCol += nExtraAbsCol;
2613                     aColumnWidths.Replace( (sal_uInt16)nAbsCol, (sal_uInt16)i );
2614                     nAbsLastCol -= nExtraAbsCol;
2615                 }
2616                 aColumnWidths.Replace( (sal_uInt16)nAbsLastCol, (sal_uInt16)nCols-1U );
2617             }
2618             else if( nAbsWidth > nWidth )
2619             {
2620                 // If the table's width is smaller than the absolute column
2621                 // widths, every column gets the minimum width plus some extra
2622                 // width.
2623                 sal_Int32 nExtraAbs = nWidth - (nCols * MINLAY);
2624                 sal_Int32 nAbsLastCol = MINLAY + nExtraAbs;
2625                 for( i=0UL; i < nCols-1UL; i++ )
2626                 {
2627                     sal_Int32 nAbsCol = aColumnWidths[(sal_uInt16)i];
2628                     sal_Int32 nExtraAbsCol = (nAbsCol * nExtraAbs) /
2629                                              nAbsWidth;
2630                     nAbsCol = MINLAY + nExtraAbsCol;
2631                     aColumnWidths.Replace( (sal_uInt16)nAbsCol, (sal_uInt16)i );
2632                     nAbsLastCol -= nExtraAbsCol;
2633                 }
2634                 aColumnWidths.Replace( (sal_uInt16)nAbsLastCol, (sal_uInt16)nCols-1U );
2635             }
2636         }
2637     }
2638 
2639     SwTableLines& rLines =
2640         pBox ? pBox->GetTabLines()
2641              : pTableNode->GetTable().GetTabLines();
2642 
2643     sal_uInt32 nStartRow = 0UL;
2644     sal_uInt32 nRows = pRows->Count();
2645     for( i=0UL; i<nRows; i++ )
2646     {
2647         // Could we split the table behind the current line?
2648         sal_Bool bSplit = sal_True;
2649         if ( bHasSubTables )
2650         {
2651             SwXMLTableRow_Impl *pRow = (*pRows)[(sal_uInt16)i];
2652             for( sal_uInt32 j=0UL; j<nCols; j++ )
2653             {
2654                 bSplit = ( 1UL == pRow->GetCell(j)->GetRowSpan() );
2655                 if( !bSplit )
2656                     break;
2657             }
2658         }
2659 
2660         if( bSplit )
2661         {
2662             SwTableLine *pLine =
2663                 MakeTableLine( pBox, nStartRow, 0UL, i+1UL, nCols );
2664             if( pBox || nStartRow>0UL )
2665                 rLines.C40_INSERT( SwTableLine, pLine, rLines.Count() );
2666             nStartRow = i+1UL;
2667         }
2668     }
2669 }
2670 
MakeTable()2671 void SwXMLTableContext::MakeTable()
2672 {
2673     // this method will modify the document directly -> lock SolarMutex
2674     // This will call all other MakeTable*(..) methods, so
2675     // those don't need to be locked separately.
2676     vos::OGuard aGuard(Application::GetSolarMutex());
2677 
2678     // #i97274# handle invalid tables
2679     if (!pRows || !pRows->Count() || !GetColumnCount())
2680     {
2681         ASSERT(false, "invalid table: no cells; deleting...");
2682         pTableNode->GetDoc()->DeleteSection( pTableNode );
2683         pTableNode = 0;
2684         pBox1 = 0;
2685         pSttNd1 = 0;
2686         return;
2687     }
2688 
2689     SwXMLImport& rSwImport = GetSwImport();
2690 
2691     SwFrmFmt *pFrmFmt = pTableNode->GetTable().GetFrmFmt();
2692 
2693     sal_Int16 eHoriOrient = text::HoriOrientation::FULL;
2694     sal_Bool bSetHoriOrient = sal_False;
2695 
2696     sal_uInt16 nPrcWidth = 0U;
2697 
2698     pTableNode->GetTable().SetRowsToRepeat( nHeaderRows );
2699     pTableNode->GetTable().SetTableModel( !bHasSubTables );
2700 
2701     const SfxItemSet *pAutoItemSet = 0;
2702     if( aStyleName.getLength() &&
2703         rSwImport.FindAutomaticStyle(
2704             XML_STYLE_FAMILY_TABLE_TABLE, aStyleName, &pAutoItemSet ) &&
2705         pAutoItemSet )
2706     {
2707         const SfxPoolItem *pItem;
2708         const SvxLRSpaceItem *pLRSpace = 0;
2709         if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_LR_SPACE, sal_False,
2710                                                         &pItem ) )
2711             pLRSpace = (const SvxLRSpaceItem *)pItem;
2712 
2713         if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_HORI_ORIENT, sal_False,
2714                                                         &pItem ) )
2715         {
2716             eHoriOrient = ((const SwFmtHoriOrient *)pItem)->GetHoriOrient();
2717             switch( eHoriOrient )
2718             {
2719             case text::HoriOrientation::FULL:
2720                 if( pLRSpace )
2721                 {
2722                     eHoriOrient = text::HoriOrientation::NONE;
2723                     bSetHoriOrient = sal_True;
2724                 }
2725                 break;
2726             case text::HoriOrientation::LEFT:
2727                 if( pLRSpace )
2728                 {
2729                     eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH;
2730                     bSetHoriOrient = sal_True;
2731                 }
2732                 break;
2733             default:
2734                 ;
2735             }
2736         }
2737         else
2738         {
2739             bSetHoriOrient = sal_True;
2740         }
2741 
2742         const SwFmtFrmSize *pSize = 0;
2743         if( SFX_ITEM_SET == pAutoItemSet->GetItemState( RES_FRM_SIZE, sal_False,
2744                                                         &pItem ) )
2745             pSize = (const SwFmtFrmSize *)pItem;
2746 
2747         switch( eHoriOrient )
2748         {
2749         case text::HoriOrientation::FULL:
2750         case text::HoriOrientation::NONE:
2751             // #78246#: For text::HoriOrientation::NONE we would prefer to use the sum
2752             // of the relative column widths as reference width.
2753             // Unfortunately this works only if this sum interpreted as
2754             // twip value is larger than the space that is available.
2755             // We don't know that space, so we have to use USHRT_MAX, too.
2756             // Even if a size is specified, it will be ignored!
2757             nWidth = USHRT_MAX;
2758             break;
2759         default:
2760             if( pSize )
2761             {
2762                 if( pSize->GetWidthPercent() )
2763                 {
2764                     // The width will be set in _MakeTable
2765                     nPrcWidth = pSize->GetWidthPercent();
2766                 }
2767                 else
2768                 {
2769                     nWidth = pSize->GetWidth();
2770                     if( nWidth < (sal_Int32)GetColumnCount() * MINLAY )
2771                     {
2772                         nWidth = GetColumnCount() * MINLAY;
2773                     }
2774                     else if( nWidth > USHRT_MAX )
2775                     {
2776                         nWidth = USHRT_MAX;
2777                     }
2778                     bRelWidth = sal_False;
2779                 }
2780             }
2781             else
2782             {
2783                 eHoriOrient = text::HoriOrientation::LEFT_AND_WIDTH == eHoriOrient
2784                                     ? text::HoriOrientation::NONE : text::HoriOrientation::FULL;
2785                 bSetHoriOrient = sal_True;
2786                 nWidth = USHRT_MAX;
2787             }
2788             break;
2789         }
2790 
2791         pFrmFmt->SetFmtAttr( *pAutoItemSet );
2792     }
2793     else
2794     {
2795         bSetHoriOrient = sal_True;
2796         nWidth = USHRT_MAX;
2797     }
2798 
2799     SwTableLine *pLine1 = pTableNode->GetTable().GetTabLines()[0U];
2800     DBG_ASSERT( pBox1 == pLine1->GetTabBoxes()[0U],
2801                 "Why is box 1 change?" );
2802     pBox1->pSttNd = pSttNd1;
2803     pLine1->GetTabBoxes().Remove(0U);
2804 
2805     pLineFmt = (SwTableLineFmt*)pLine1->GetFrmFmt();
2806     pBoxFmt = (SwTableBoxFmt*)pBox1->GetFrmFmt();
2807 
2808     _MakeTable( 0 );
2809 
2810     if( bSetHoriOrient )
2811         pFrmFmt->SetFmtAttr( SwFmtHoriOrient( 0, eHoriOrient ) );
2812 
2813     // This must be after the call to _MakeTable, because nWidth might be
2814     // changed there.
2815     pFrmFmt->LockModify();
2816     SwFmtFrmSize aSize( ATT_VAR_SIZE, nWidth );
2817     aSize.SetWidthPercent( (sal_Int8)nPrcWidth );
2818     pFrmFmt->SetFmtAttr( aSize );
2819     pFrmFmt->UnlockModify();
2820 
2821 
2822     for( sal_uInt16 i=0; i<pRows->Count(); i++ )
2823         (*pRows)[i]->Dispose();
2824 
2825     // now that table is complete, change into DDE table (if appropriate)
2826     if (NULL != pDDESource)
2827     {
2828         // change existing table into DDE table:
2829         // 1) Get DDE field type (get data from dde-source context),
2830         SwDDEFieldType* pFldType = lcl_GetDDEFieldType( pDDESource,
2831                                                         pTableNode );
2832 
2833         // 2) release the DDE source context,
2834         pDDESource->ReleaseRef();
2835 
2836         // 3) create new DDE table, and
2837         SwDDETable* pDDETable = new SwDDETable( pTableNode->GetTable(),
2838                                                 pFldType, sal_False );
2839 
2840         // 4) set new (DDE)table at node.
2841         pTableNode->SetNewTable(pDDETable, sal_False);
2842     }
2843 
2844     // ??? this is always false: root frame is only created in ViewShell::Init
2845     if( pTableNode->GetDoc()->GetCurrentViewShell() )   //swmod 071108//swmod 071225
2846     {
2847         pTableNode->DelFrms();
2848         SwNodeIndex aIdx( *pTableNode->EndOfSectionNode(), 1 );
2849         pTableNode->MakeFrms( &aIdx );
2850     }
2851 }
2852 
MakeTable(SwTableBox * pBox,sal_Int32 nW)2853 void SwXMLTableContext::MakeTable( SwTableBox *pBox, sal_Int32 nW )
2854 {
2855 //FIXME: here would be a great place to handle XmlId for subtable
2856     pLineFmt = GetParentTable()->pLineFmt;
2857     pBoxFmt = GetParentTable()->pBoxFmt;
2858     nWidth = nW;
2859     bRelWidth = GetParentTable()->bRelWidth;
2860 
2861     _MakeTable( pBox );
2862 
2863     for( sal_uInt16 i=0; i<pRows->Count(); i++ ) // i113600, to break the cyclic reference to SwXMLTableContext object
2864         (*pRows)[i]->Dispose();
2865 }
2866 
InsertTableSection(const SwStartNode * pPrevSttNd)2867 const SwStartNode *SwXMLTableContext::InsertTableSection(
2868                                             const SwStartNode *pPrevSttNd )
2869 {
2870     // The topmost table is the only table that maintains the two members
2871     // pBox1 and bFirstSection.
2872     if( xParentTable.Is() )
2873         return ((SwXMLTableContext *)&xParentTable)->InsertTableSection( pPrevSttNd );
2874 
2875     const SwStartNode *pStNd;
2876     Reference<XUnoTunnel> xCrsrTunnel( GetImport().GetTextImport()->GetCursor(),
2877                                        UNO_QUERY);
2878     ASSERT( xCrsrTunnel.is(), "missing XUnoTunnel for Cursor" );
2879     OTextCursorHelper *pTxtCrsr = reinterpret_cast< OTextCursorHelper * >(
2880             sal::static_int_cast< sal_IntPtr >( xCrsrTunnel->getSomething( OTextCursorHelper::getUnoTunnelId() )));
2881     ASSERT( pTxtCrsr, "SwXTextCursor missing" );
2882 
2883     if( bFirstSection )
2884     {
2885         // The Cursor already is in the first section
2886         pStNd = pTxtCrsr->GetPaM()->GetNode()->FindTableBoxStartNode();
2887         bFirstSection = sal_False;
2888         OUString sStyleName( RTL_CONSTASCII_USTRINGPARAM("Standard") );
2889         GetImport().GetTextImport()->SetStyleAndAttrs( GetImport(),
2890             GetImport().GetTextImport()->GetCursor(), sStyleName, sal_True );
2891     }
2892     else
2893     {
2894         SwDoc* pDoc = SwImport::GetDocFromXMLImport( GetSwImport() );
2895         const SwEndNode *pEndNd = pPrevSttNd ? pPrevSttNd->EndOfSectionNode()
2896                                              : pTableNode->EndOfSectionNode();
2897         // --> OD 2007-07-02 #i78921# - make code robust
2898 #if OSL_DEBUG_LEVEL > 1
2899         ASSERT( pDoc, "<SwXMLTableContext::InsertTableSection(..)> - no <pDoc> at <SwXTextCursor> instance - <SwXTextCurosr> doesn't seem to be registered at a <SwUnoCrsr> instance." );
2900 #endif
2901         if ( !pDoc )
2902         {
2903             pDoc = const_cast<SwDoc*>(pEndNd->GetDoc());
2904         }
2905         // <--
2906         sal_uInt32 nOffset = pPrevSttNd ? 1UL : 0UL;
2907         SwNodeIndex aIdx( *pEndNd, nOffset );
2908         SwTxtFmtColl *pColl =
2909             pDoc->GetTxtCollFromPool( RES_POOLCOLL_STANDARD, false );
2910         pStNd = pDoc->GetNodes().MakeTextSection( aIdx, SwTableBoxStartNode,
2911                                                  pColl );
2912         // --> FLR 2005-08-30 #125369#
2913         // Consider the case that a table is defined without a row.
2914         if( !pPrevSttNd && pBox1 != NULL )
2915         // <--
2916         {
2917             pBox1->pSttNd = pStNd;
2918             SwCntntNode *pCNd = pDoc->GetNodes()[ pStNd->GetIndex() + 1 ]
2919                                                             ->GetCntntNode();
2920             SwPosition aPos( *pCNd );
2921             aPos.nContent.Assign( pCNd, 0U );
2922 
2923             const uno::Reference< text::XTextRange > xTextRange =
2924                 SwXTextRange::CreateXTextRange( *pDoc, aPos, 0 );
2925             Reference < XText > xText = xTextRange->getText();
2926             Reference < XTextCursor > xTextCursor =
2927                 xText->createTextCursorByRange( xTextRange );
2928             GetImport().GetTextImport()->SetCursor( xTextCursor );
2929         }
2930     }
2931 
2932     return pStNd;
2933 }
2934 
EndElement()2935 void SwXMLTableContext::EndElement()
2936 {
2937     if( IsValid() && !xParentTable.Is() )
2938     {
2939         MakeTable();
2940         GetImport().GetTextImport()->SetCursor( xOldCursor );
2941     }
2942 }
2943 
GetXTextContent() const2944 Reference < XTextContent > SwXMLTableContext::GetXTextContent() const
2945 {
2946     return xTextContent;
2947 }
2948 
2949 /* vim: set noet sw=4 ts=4: */
2950