1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <com/sun/star/frame/XModel.hpp>
23 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
24 #include <com/sun/star/table/XTableRows.hpp>
25 #include <com/sun/star/table/XMergeableCell.hpp>
26 #include <com/sun/star/table/XMergeableCellRange.hpp>
27 #include <com/sun/star/table/XTable.hpp>
28 #include <com/sun/star/text/XText.hpp>
29 #include <com/sun/star/container/XNameContainer.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
32 #include <com/sun/star/style/XStyle.hpp>
33 #include <comphelper/sequence.hxx>
34 #include <tools/diagnose_ex.h>
35 
36 #include <xmloff/table/XMLTableImport.hxx>
37 #include <xmloff/xmlprmap.hxx>
38 #include <xmloff/txtimp.hxx>
39 #include <xmloff/xmlimp.hxx>
40 #include <xmloff/namespacemap.hxx>
41 #include <xmloff/xmlstyle.hxx>
42 #include <xmloff/prstylei.hxx>
43 
44 #include <xmloff/xmlnamespace.hxx>
45 #include <xmloff/xmluconv.hxx>
46 #include "table.hxx"
47 
48 #include <sal/log.hxx>
49 
50 #include <memory>
51 
52 using namespace ::xmloff::token;
53 using namespace ::com::sun::star::beans;
54 using namespace ::com::sun::star::uno;
55 using namespace ::com::sun::star::table;
56 using namespace ::com::sun::star::xml::sax;
57 using namespace ::com::sun::star::text;
58 using namespace ::com::sun::star::style;
59 using namespace ::com::sun::star::lang;
60 using namespace ::com::sun::star::container;
61 
62 namespace {
63 
64 struct ColumnInfo
65 {
66     OUString msStyleName;
67     OUString msDefaultCellStyleName;
68 };
69 
70 class XMLProxyContext : public SvXMLImportContext
71 {
72 public:
73     XMLProxyContext( SvXMLImport& rImport, const SvXMLImportContextRef& xParent );
74 
75     virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
76         sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
77 
78 private:
79     SvXMLImportContextRef mxParent;
80 };
81 
82 struct MergeInfo
83 {
84     sal_Int32 mnStartColumn;
85     sal_Int32 mnStartRow;
86     sal_Int32 mnEndColumn;
87     sal_Int32 mnEndRow;
88 
MergeInfo__anonde4651b40111::MergeInfo89     MergeInfo( sal_Int32 nStartColumn, sal_Int32 nStartRow, sal_Int32 nColumnSpan, sal_Int32 nRowSpan )
90         : mnStartColumn( nStartColumn ), mnStartRow( nStartRow ), mnEndColumn( nStartColumn + nColumnSpan - 1 ), mnEndRow( nStartRow + nRowSpan - 1 ) {};
91 };
92 
93 }
94 
95 class XMLTableImportContext : public SvXMLImportContext
96 {
97 public:
98     XMLTableImportContext( const rtl::Reference< XMLTableImport >& xThis, Reference< XColumnRowRange > const & xColumnRowRange );
99 
100     virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
101         sal_Int32 nElement,
102         const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
103 
104     virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
105 
106     void InitColumns();
107 
108     SvXMLImportContextRef ImportColumn( const Reference< XFastAttributeList >& xAttrList );
109     SvXMLImportContext * ImportRow( const Reference< XFastAttributeList >& xAttrList );
110     SvXMLImportContextRef ImportCell( sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList );
111 
112     OUString GetDefaultCellStyleName() const;
113 
114     css::uno::Reference< css::table::XTable > mxTable;
115     Reference< XTableColumns > mxColumns;
116     Reference< XTableRows > mxRows;
117 
118     std::vector< std::shared_ptr< ColumnInfo > > maColumnInfos;
119     sal_Int32 mnCurrentRow;
120     sal_Int32 mnCurrentColumn;
121 
122     // default cell style name for the current row
123     OUString msDefaultCellStyleName;
124 
125     std::vector< std::shared_ptr< MergeInfo > > maMergeInfos;
126 };
127 
128 namespace {
129 
130 class XMLCellImportContext : public SvXMLImportContext
131 {
132 public:
133     XMLCellImportContext( SvXMLImport& rImport,
134                           const Reference< XMergeableCell >& xCell,
135                           const OUString& sDefaultCellStyleName,
136                           sal_Int32 nElement,
137                           const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList );
138 
139     virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
140         sal_Int32 nElement,
141         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
142 
143     virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
144 
getColumnSpan() const145     sal_Int32 getColumnSpan() const { return mnColSpan; }
getRowSpan() const146     sal_Int32 getRowSpan() const { return mnRowSpan; }
getRepeated() const147     sal_Int32 getRepeated() const { return mnRepeated; }
148 
149     Reference< XMergeableCell > mxCell;
150     Reference< XTextCursor >    mxCursor;
151     Reference< XTextCursor >    mxOldCursor;
152     bool                        mbListContextPushed;
153 
154     sal_Int32 mnColSpan, mnRowSpan, mnRepeated;
155 };
156 
157 class XMLTableTemplateContext : public SvXMLStyleContext
158 {
159 public:
160     XMLTableTemplateContext( SvXMLImport& rImport );
161 
162     // Create child element.
163     virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
164         sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
165 
166     virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
167 
168     virtual void CreateAndInsert( bool bOverwrite ) override;
169 protected:
170     virtual void SetAttribute( sal_Int32 nElement,
171                                const OUString& rValue ) override;
172 private:
173     XMLTableTemplate maTableTemplate;
174     OUString msTemplateStyleName;
175 };
176 
177 }
178 
179 
XMLProxyContext(SvXMLImport & rImport,const SvXMLImportContextRef & xParent)180 XMLProxyContext::XMLProxyContext( SvXMLImport& rImport, const SvXMLImportContextRef& xParent )
181 : SvXMLImportContext( rImport )
182 , mxParent( xParent )
183 {
184 }
185 
createFastChildContext(sal_Int32 nElement,const Reference<XFastAttributeList> & xAttrList)186 css::uno::Reference< css::xml::sax::XFastContextHandler > XMLProxyContext::createFastChildContext( sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList )
187 {
188     if( mxParent.is() )
189         return mxParent->createFastChildContext( nElement, xAttrList );
190     return nullptr;
191 }
192 
193 
XMLTableImport(SvXMLImport & rImport,const rtl::Reference<XMLPropertySetMapper> & xCellPropertySetMapper,const rtl::Reference<XMLPropertyHandlerFactory> & xFactoryRef)194 XMLTableImport::XMLTableImport( SvXMLImport& rImport, const rtl::Reference< XMLPropertySetMapper >& xCellPropertySetMapper, const rtl::Reference< XMLPropertyHandlerFactory >& xFactoryRef )
195 : mrImport( rImport )
196 {
197     bool bWriter = false;
198     // check if called by Writer
199     Reference<XMultiServiceFactory> xFac(rImport.GetModel(), UNO_QUERY);
200     if (xFac.is()) try
201     {
202         Sequence<OUString> sSNS = xFac->getAvailableServiceNames();
203         bWriter = comphelper::findValue(sSNS, "com.sun.star.style.TableStyle") != -1;
204     }
205     catch(const Exception&)
206     {
207         SAL_WARN("xmloff.table", "Error while checking available service names");
208     }
209 
210     if (bWriter)
211     {
212         mxCellImportPropertySetMapper = XMLTextImportHelper::CreateTableCellExtPropMapper(rImport);
213     }
214     else
215     {
216         mxCellImportPropertySetMapper = new SvXMLImportPropertyMapper( xCellPropertySetMapper, rImport );
217         mxCellImportPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImport));
218         mxCellImportPropertySetMapper->ChainImportMapper(new SvXMLImportPropertyMapper(new XMLPropertySetMapper(getCellPropertiesMap(), xFactoryRef, true), rImport));
219     }
220 
221     rtl::Reference < XMLPropertySetMapper > xRowMapper( new XMLPropertySetMapper( getRowPropertiesMap(), xFactoryRef, false ) );
222     mxRowImportPropertySetMapper = new SvXMLImportPropertyMapper( xRowMapper, rImport );
223 
224     rtl::Reference < XMLPropertySetMapper > xColMapper( new XMLPropertySetMapper( getColumnPropertiesMap(), xFactoryRef, false ) );
225     mxColumnImportPropertySetMapper = new SvXMLImportPropertyMapper( xColMapper, rImport );
226 }
227 
~XMLTableImport()228 XMLTableImport::~XMLTableImport()
229 {
230 }
231 
CreateTableContext(Reference<XColumnRowRange> const & xColumnRowRange)232 SvXMLImportContext* XMLTableImport::CreateTableContext( Reference< XColumnRowRange > const & xColumnRowRange )
233 {
234     rtl::Reference< XMLTableImport > xThis( this );
235     return new XMLTableImportContext( xThis, xColumnRowRange );
236 }
237 
CreateTableTemplateContext(sal_Int32,const Reference<XFastAttributeList> &)238 SvXMLStyleContext* XMLTableImport::CreateTableTemplateContext( sal_Int32 /*nElement*/, const Reference< XFastAttributeList >& /*xAttrList*/ )
239 {
240     return new XMLTableTemplateContext( mrImport );
241 }
242 
addTableTemplate(const OUString & rsStyleName,XMLTableTemplate & xTableTemplate)243 void XMLTableImport::addTableTemplate( const OUString& rsStyleName, XMLTableTemplate& xTableTemplate )
244 {
245     auto xPtr = std::make_shared<XMLTableTemplate>();
246     xPtr->swap( xTableTemplate );
247     maTableTemplates[rsStyleName] = xPtr;
248 }
249 
insertTabletemplate(const OUString & rsStyleName,bool bOverwrite)250 void XMLTableImport::insertTabletemplate(const OUString& rsStyleName, bool bOverwrite)
251 {
252     XMLTableTemplateMap::iterator it = maTableTemplates.find(rsStyleName);
253     if (it == maTableTemplates.end())
254         return;
255 
256     try
257     {
258         Reference<XStyleFamiliesSupplier> xFamiliesSupp(mrImport.GetModel(), UNO_QUERY_THROW);
259         Reference<XNameAccess> xFamilies(xFamiliesSupp->getStyleFamilies());
260 
261         Reference<XNameContainer> xTableFamily(xFamilies->getByName("TableStyles"), UNO_QUERY_THROW);
262         Reference<XIndexAccess> xCellFamily(xFamilies->getByName("CellStyles"), UNO_QUERY_THROW);
263 
264         const OUString sTemplateName(it->first);
265         Reference<XMultiServiceFactory> xFactory(mrImport.GetModel(), UNO_QUERY_THROW);
266         Reference<XNameReplace> xTemplate(xFactory->createInstance("com.sun.star.style.TableStyle"), UNO_QUERY_THROW);
267 
268         std::shared_ptr<XMLTableTemplate> xT(it->second);
269 
270         for (const auto& rStyle : *xT) try
271         {
272             const OUString sPropName(rStyle.first);
273             const OUString sStyleName(rStyle.second);
274             // Internally unassigned cell styles are stored by display name.
275             // However table-template elements reference cell styles by its encoded name.
276             // This loop is looking for cell style by their encoded names.
277             sal_Int32 nCount = xCellFamily->getCount();
278             for (sal_Int32 i=0; i < nCount; ++i)
279             {
280                 Any xCellStyle = xCellFamily->getByIndex(i);
281                 OUString sEncodedStyleName = mrImport.GetMM100UnitConverter().encodeStyleName(
282                     xCellStyle.get<Reference<XStyle>>()->getName());
283                 if (sEncodedStyleName == sStyleName)
284                 {
285                     xTemplate->replaceByName(sPropName, xCellStyle);
286                     break;
287                 }
288             }
289         }
290         catch (Exception const &)
291         {
292             TOOLS_WARN_EXCEPTION("xmloff.table", "XMLTableImport::insertTabletemplate()");
293         }
294 
295         if (xTemplate.is())
296         {
297             if (xTableFamily->hasByName(sTemplateName) && bOverwrite)
298                xTableFamily->replaceByName(sTemplateName, Any(xTemplate));
299             else
300                xTableFamily->insertByName(sTemplateName, Any(xTemplate));
301         }
302     }
303     catch (Exception&)
304     {
305         TOOLS_WARN_EXCEPTION("xmloff.table", "XMLTableImport::insertTabletemplate()");
306     }
307 }
308 
finishStyles()309 void XMLTableImport::finishStyles()
310 {
311     if( maTableTemplates.empty() )
312         return;
313 
314     try
315     {
316         Reference< XStyleFamiliesSupplier > xFamiliesSupp( mrImport.GetModel(), UNO_QUERY_THROW );
317         Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() );
318 
319         Reference< XNameContainer > xTableFamily( xFamilies->getByName( "table" ), UNO_QUERY_THROW );
320         Reference< XNameAccess > xCellFamily( xFamilies->getByName( "cell" ), UNO_QUERY_THROW );
321 
322         Reference< XSingleServiceFactory > xFactory( xTableFamily, UNO_QUERY_THROW );
323 
324         for( const auto& rTemplate : maTableTemplates ) try
325         {
326             const OUString sTemplateName( rTemplate.first );
327             Reference< XNameReplace > xTemplate( xFactory->createInstance(), UNO_QUERY_THROW );
328 
329             std::shared_ptr< XMLTableTemplate > xT( rTemplate.second );
330 
331             for( const auto& rStyle : *xT ) try
332             {
333                 const OUString sPropName( rStyle.first );
334                 const OUString sStyleName( rStyle.second );
335                 xTemplate->replaceByName( sPropName, xCellFamily->getByName( sStyleName ) );
336             }
337             catch( Exception& )
338             {
339                 TOOLS_WARN_EXCEPTION("xmloff.table", "");
340             }
341 
342             if( xTemplate.is() )
343             {
344                 if( xTableFamily->hasByName( sTemplateName ) )
345                     xTableFamily->replaceByName( sTemplateName, Any( xTemplate ) );
346                 else
347                     xTableFamily->insertByName( sTemplateName, Any( xTemplate ) );
348             }
349 
350         }
351         catch( Exception& )
352         {
353             TOOLS_WARN_EXCEPTION("xmloff.table", "");
354         }
355     }
356     catch( Exception& )
357     {
358         TOOLS_WARN_EXCEPTION("xmloff.table", "");
359     }
360 }
361 
362 
XMLTableImportContext(const rtl::Reference<XMLTableImport> & xImporter,Reference<XColumnRowRange> const & xColumnRowRange)363 XMLTableImportContext::XMLTableImportContext( const rtl::Reference< XMLTableImport >& xImporter, Reference< XColumnRowRange > const & xColumnRowRange )
364 : SvXMLImportContext( xImporter->mrImport )
365 , mxTable( xColumnRowRange, UNO_QUERY )
366 , mxColumns( xColumnRowRange->getColumns() )
367 , mxRows( xColumnRowRange->getRows() )
368 , mnCurrentRow( -1 )
369 , mnCurrentColumn( -1 )
370 {
371 }
372 
ImportColumn(const Reference<XFastAttributeList> & xAttrList)373 SvXMLImportContextRef XMLTableImportContext::ImportColumn( const Reference< XFastAttributeList >& xAttrList )
374 {
375     if( mxColumns.is() && (mnCurrentRow == -1) ) try
376     {
377         auto xInfo = std::make_shared<ColumnInfo>();
378 
379         sal_Int32 nRepeated = 1;
380 
381         // read attributes for the table-column
382         for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
383         {
384             switch (aIter.getToken())
385             {
386                 case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED):
387                     nRepeated = aIter.toInt32();
388                     break;
389                 case XML_ELEMENT(TABLE, XML_STYLE_NAME):
390                     xInfo->msStyleName = aIter.toString();
391                     break;
392                 case XML_ELEMENT(TABLE, XML_DEFAULT_CELL_STYLE_NAME):
393                     xInfo->msDefaultCellStyleName = aIter.toString();
394                     break;
395                 case XML_ELEMENT(XML, XML_ID):
396                     //FIXME: TODO
397                     break;
398             }
399         }
400 
401         if( nRepeated <= 1 )
402         {
403             maColumnInfos.push_back( xInfo );
404         }
405         else
406         {
407             maColumnInfos.insert( maColumnInfos.end(), nRepeated, xInfo );
408         }
409     }
410     catch( Exception& )
411     {
412         TOOLS_WARN_EXCEPTION("xmloff.table", "");
413     }
414 
415     return nullptr;
416 }
417 
InitColumns()418 void XMLTableImportContext::InitColumns()
419 {
420     if( !mxColumns.is() )
421         return;
422 
423     try
424     {
425         const sal_Int32 nCount1 = mxColumns->getCount();
426         const sal_Int32 nCount2 = sal::static_int_cast< sal_Int32 >( maColumnInfos.size() );
427         if( nCount1 < nCount2 )
428             mxColumns->insertByIndex( nCount1, nCount2 - nCount1 );
429 
430         SvXMLStylesContext * pAutoStyles = GetImport().GetShapeImport()->GetAutoStylesContext();
431 
432         for( sal_Int32 nCol = 0; nCol < nCount2; nCol++ )
433         {
434             std::shared_ptr< ColumnInfo > xInfo( maColumnInfos[nCol] );
435 
436             if( pAutoStyles && !xInfo->msStyleName.isEmpty() )
437             {
438                 const XMLPropStyleContext* pStyle =
439                     dynamic_cast< const XMLPropStyleContext* >(
440                         pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_COLUMN, xInfo->msStyleName) );
441 
442                 if( pStyle )
443                 {
444                     Reference< XPropertySet > xColProps( mxColumns->getByIndex(nCol), UNO_QUERY_THROW );
445                     const_cast< XMLPropStyleContext* >( pStyle )->FillPropertySet( xColProps );
446                 }
447             }
448 
449         }
450     }
451     catch( Exception& )
452     {
453         TOOLS_WARN_EXCEPTION("xmloff.table", "");
454     }
455 }
456 
ImportRow(const Reference<XFastAttributeList> & xAttrList)457 SvXMLImportContext * XMLTableImportContext::ImportRow( const Reference< XFastAttributeList >& xAttrList )
458 {
459     if( mxRows.is() )
460     {
461         mnCurrentRow++;
462         if( mnCurrentRow == 0 )
463             InitColumns();      // first init columns
464 
465         mnCurrentColumn = -1;
466 
467         const sal_Int32 nRowCount = mxRows->getCount();
468         if( ( nRowCount - 1) < mnCurrentRow )
469         {
470             const sal_Int32 nCount = mnCurrentRow - nRowCount + 1;
471             mxRows->insertByIndex( nRowCount, nCount );
472         }
473 
474         Reference< XPropertySet > xRowSet( mxRows->getByIndex(mnCurrentRow), UNO_QUERY );
475 
476         OUString sStyleName;
477 
478         // read attributes for the table-row
479         for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
480         {
481             switch(aIter.getToken())
482             {
483                 case XML_ELEMENT(TABLE, XML_STYLE_NAME):
484                     sStyleName = aIter.toString();
485                     break;
486                 case XML_ELEMENT(TABLE, XML_DEFAULT_CELL_STYLE_NAME):
487                     msDefaultCellStyleName = aIter.toString();
488                     break;
489                 case XML_ELEMENT(XML, XML_ID):
490                     //FIXME: TODO
491                     break;
492             }
493         }
494 
495         if( !sStyleName.isEmpty() )
496         {
497             SvXMLStylesContext * pAutoStyles = GetImport().GetShapeImport()->GetAutoStylesContext();
498             if( pAutoStyles )
499             {
500                 const XMLPropStyleContext* pStyle =
501                     dynamic_cast< const XMLPropStyleContext* >(
502                         pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_ROW, sStyleName) );
503 
504                 if( pStyle )
505                 {
506                     const_cast< XMLPropStyleContext* >( pStyle )->FillPropertySet( xRowSet );
507                 }
508             }
509         }
510     }
511 
512     SvXMLImportContextRef xThis( this );
513     return new XMLProxyContext( GetImport(), xThis );
514 }
515 
ImportCell(sal_Int32 nElement,const Reference<XFastAttributeList> & xAttrList)516 SvXMLImportContextRef XMLTableImportContext::ImportCell( sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList )
517 {
518     mnCurrentColumn++;
519     if( mxColumns.is() ) try
520     {
521         if( mxColumns->getCount() <= mnCurrentColumn )
522             mxColumns->insertByIndex( mxColumns->getCount(), mnCurrentColumn - mxColumns->getCount() + 1 );
523 
524         Reference< XMergeableCell > xCell( mxTable->getCellByPosition( mnCurrentColumn, mnCurrentRow ), UNO_QUERY_THROW );
525         XMLCellImportContext* pCellContext = new XMLCellImportContext( GetImport(), xCell, GetDefaultCellStyleName(), nElement, xAttrList );
526 
527         const sal_Int32 nColumnSpan = pCellContext->getColumnSpan();
528         const sal_Int32 nRowSpan = pCellContext->getRowSpan();
529         if( (nColumnSpan > 1) || (nRowSpan > 1) )
530             maMergeInfos.push_back( std::make_shared< MergeInfo >( mnCurrentColumn, mnCurrentRow, nColumnSpan, nRowSpan ) );
531 
532         const sal_Int32 nRepeated = pCellContext->getRepeated();
533         if( nRepeated > 1 )
534         {
535             OSL_FAIL("xmloff::XMLTableImportContext::ImportCell(), import of repeated Cells not implemented (TODO)");
536             mnCurrentColumn  += nRepeated - 1;
537         }
538 
539         return pCellContext;
540     }
541     catch( Exception& )
542     {
543         TOOLS_WARN_EXCEPTION("xmloff.table", "");
544     }
545 
546     return nullptr;
547 }
548 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)549 css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTableImportContext::createFastChildContext(
550     sal_Int32 nElement,
551     const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
552 {
553     switch (nElement)
554     {
555         case XML_ELEMENT(TABLE, XML_TABLE_CELL):
556         case XML_ELEMENT(TABLE, XML_COVERED_TABLE_CELL):
557             return ImportCell( nElement, xAttrList );
558         case XML_ELEMENT(TABLE, XML_TABLE_COLUMN):
559             return ImportColumn( xAttrList );
560         case XML_ELEMENT(TABLE, XML_TABLE_ROW):
561             return ImportRow( xAttrList );
562         case XML_ELEMENT(TABLE, XML_TABLE_COLUMNS):
563         case XML_ELEMENT(TABLE, XML_TABLE_ROWS):
564         {
565             SvXMLImportContextRef xThis( this );
566             return new XMLProxyContext( GetImport(), xThis );
567         }
568     }
569     SAL_WARN("xmloff", "unknown element");
570     return nullptr;
571 }
572 
endFastElement(sal_Int32)573 void XMLTableImportContext::endFastElement(sal_Int32 )
574 {
575     for( const std::shared_ptr< MergeInfo >& xInfo : maMergeInfos )
576     {
577         if( xInfo ) try
578         {
579             Reference< XCellRange > xRange( mxTable->getCellRangeByPosition( xInfo->mnStartColumn, xInfo->mnStartRow, xInfo->mnEndColumn, xInfo->mnEndRow ) );
580             Reference< XMergeableCellRange > xCursor( mxTable->createCursorByRange( xRange ), UNO_QUERY_THROW );
581             xCursor->merge();
582         }
583         catch( Exception& )
584         {
585             TOOLS_WARN_EXCEPTION("xmloff.table", "");
586         }
587     }
588 }
589 
GetDefaultCellStyleName() const590 OUString XMLTableImportContext::GetDefaultCellStyleName() const
591 {
592     OUString sStyleName( msDefaultCellStyleName );
593 
594     // if there is still no style name, try default style name from column
595     if( (sStyleName.isEmpty()) && (mnCurrentColumn < sal::static_int_cast<sal_Int32>(maColumnInfos.size())) )
596         sStyleName = maColumnInfos[mnCurrentColumn]->msDefaultCellStyleName;
597 
598     return sStyleName;
599 }
600 
601 // XMLCellImportContext
602 
XMLCellImportContext(SvXMLImport & rImport,const Reference<XMergeableCell> & xCell,const OUString & sDefaultCellStyleName,sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)603 XMLCellImportContext::XMLCellImportContext( SvXMLImport& rImport,
604     const Reference< XMergeableCell >& xCell,
605     const OUString& sDefaultCellStyleName,
606     sal_Int32 /*nElement*/,
607     const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
608 : SvXMLImportContext( rImport )
609 , mxCell( xCell )
610 , mbListContextPushed( false )
611 , mnColSpan( 1 )
612 , mnRowSpan( 1 )
613 , mnRepeated( 1 )
614 {
615     OUString sStyleName;
616 
617     // read attributes for the table-cell
618     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
619     {
620         switch (aIter.getToken())
621         {
622             case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED):
623                 mnRepeated = aIter.toInt32();
624                 break;
625             case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_SPANNED):
626                 mnColSpan = aIter.toInt32();
627                 break;
628             case XML_ELEMENT(TABLE, XML_NUMBER_ROWS_SPANNED):
629                 mnRowSpan = aIter.toInt32();
630                 break;
631             case XML_ELEMENT(TABLE, XML_STYLE_NAME):
632                 sStyleName = aIter.toString();
633                 break;
634             case XML_ELEMENT(XML, XML_ID):
635 //FIXME: TODO
636                 break;
637 //FIXME: RDFa (table:table-cell)
638             default:
639                 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
640         }
641     }
642 
643     // if there is no style name at the cell, try default style name from row
644     if( sStyleName.isEmpty() )
645         sStyleName = sDefaultCellStyleName;
646 
647     if( sStyleName.isEmpty() )
648         return;
649 
650     SvXMLStylesContext * pAutoStyles = GetImport().GetShapeImport()->GetAutoStylesContext();
651     if( !pAutoStyles )
652         return;
653 
654     const XMLPropStyleContext* pStyle =
655         dynamic_cast< const XMLPropStyleContext* >(
656             pAutoStyles->FindStyleChildContext(XmlStyleFamily::TABLE_CELL, sStyleName) );
657 
658     if( pStyle )
659     {
660         Reference< XPropertySet > xCellSet( mxCell, UNO_QUERY );
661         if( xCellSet.is() )
662             const_cast< XMLPropStyleContext* >( pStyle )->FillPropertySet( xCellSet );
663     }
664 }
665 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)666 css::uno::Reference< css::xml::sax::XFastContextHandler > XMLCellImportContext::createFastChildContext(
667     sal_Int32 nElement,
668     const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
669 {
670     // create text cursor on demand
671     if( !mxCursor.is() )
672     {
673         Reference< XText > xText( mxCell, UNO_QUERY );
674         if( xText.is() )
675         {
676             rtl::Reference < XMLTextImportHelper > xTxtImport( GetImport().GetTextImport() );
677             mxOldCursor = xTxtImport->GetCursor();
678             mxCursor = xText->createTextCursor();
679             if( mxCursor.is() )
680                 xTxtImport->SetCursor( mxCursor );
681 
682             // remember old list item and block (#91964#) and reset them
683             // for the text frame
684             xTxtImport->PushListContext();
685             mbListContextPushed = true;
686         }
687     }
688 
689     SvXMLImportContext * pContext = nullptr;
690 
691     // if we have a text cursor, lets  try to import some text
692     if( mxCursor.is() )
693     {
694         pContext = GetImport().GetTextImport()->CreateTextChildContext( GetImport(), nElement, xAttrList );
695     }
696 
697     if (!pContext)
698         XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
699     return pContext;
700 }
701 
endFastElement(sal_Int32)702 void XMLCellImportContext::endFastElement(sal_Int32 )
703 {
704     if(mxCursor.is())
705     {
706         // delete addition newline
707         mxCursor->gotoEnd( false );
708         mxCursor->goLeft( 1, true );
709         mxCursor->setString( "" );
710 
711         // reset cursor
712         GetImport().GetTextImport()->ResetCursor();
713     }
714 
715     if(mxOldCursor.is())
716         GetImport().GetTextImport()->SetCursor( mxOldCursor );
717 
718     // reinstall old list item (if necessary) #91964#
719     if (mbListContextPushed) {
720         GetImport().GetTextImport()->PopListContext();
721     }
722 }
723 
724 
XMLTableTemplateContext(SvXMLImport & rImport)725 XMLTableTemplateContext::XMLTableTemplateContext( SvXMLImport& rImport )
726 : SvXMLStyleContext( rImport, XmlStyleFamily::TABLE_TEMPLATE_ID, false )
727 {
728 }
729 
SetAttribute(sal_Int32 nElement,const OUString & rValue)730 void XMLTableTemplateContext::SetAttribute( sal_Int32 nElement,
731                                const OUString& rValue )
732 {
733     if( nElement == XML_ELEMENT(TEXT, XML_STYLE_NAME)
734         // Writer specific: according to oasis odf 1.2 prefix should be "table" and element name should be "name"
735         || nElement == XML_ELEMENT(TABLE, XML_NAME) )
736     {
737         msTemplateStyleName = rValue;
738     }
739 }
740 
endFastElement(sal_Int32)741 void XMLTableTemplateContext::endFastElement(sal_Int32 )
742 {
743     rtl::Reference< XMLTableImport > xTableImport( GetImport().GetShapeImport()->GetShapeTableImport() );
744     if( xTableImport.is() )
745         xTableImport->addTableTemplate( msTemplateStyleName, maTableTemplate );
746 }
747 
CreateAndInsert(bool bOverwrite)748 void XMLTableTemplateContext::CreateAndInsert(bool bOverwrite)
749 {
750     rtl::Reference<XMLTableImport> xTableImport(GetImport().GetShapeImport()->GetShapeTableImport());
751     if(xTableImport.is())
752        xTableImport->insertTabletemplate(msTemplateStyleName, bOverwrite);
753 }
754 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)755 css::uno::Reference< css::xml::sax::XFastContextHandler > XMLTableTemplateContext::createFastChildContext(
756     sal_Int32 nElement,
757     const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
758 {
759     if( IsTokenInNamespace(nElement, XML_NAMESPACE_TABLE) )
760     {
761         const TableStyleElement* pElements = getTableStyleMap();
762         sal_Int32 nLocalName = nElement & TOKEN_MASK;
763         while( (pElements->meElement != XML_TOKEN_END) && pElements->meElement != nLocalName)
764             pElements++;
765 
766         if( pElements->meElement != XML_TOKEN_END )
767         {
768             for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
769             {
770                 switch (aIter.getToken())
771                 {
772                     case XML_ELEMENT(TEXT, XML_STYLE_NAME):
773                     case XML_ELEMENT(TABLE, XML_STYLE_NAME):
774                         maTableTemplate[pElements->msStyleName] = aIter.toString();
775                         break;
776                     default:
777                         XMLOFF_WARN_UNKNOWN("xmloff", aIter);
778                 }
779             }
780         }
781     } else if (IsTokenInNamespace(nElement, XML_NAMESPACE_LO_EXT)) // Writer specific cell styles
782     {
783         const TableStyleElement* pElements = getWriterSpecificTableStyleMap();
784         sal_Int32 nLocalName = nElement & TOKEN_MASK;
785         while( (pElements->meElement != XML_TOKEN_END) && pElements->meElement != nLocalName)
786             pElements++;
787 
788         if (pElements->meElement != XML_TOKEN_END)
789         {
790             for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ))
791             {
792                 switch (aIter.getToken())
793                 {
794                     case XML_ELEMENT(TEXT, XML_STYLE_NAME):
795                     case XML_ELEMENT(TABLE, XML_STYLE_NAME):
796                         maTableTemplate[pElements->msStyleName] = aIter.toString();
797                         break;
798                     default:
799                         XMLOFF_WARN_UNKNOWN("xmloff", aIter);
800                 }
801             }
802         }
803     }
804 
805     return nullptr;
806 }
807 
808 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
809