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 
21 #include <memory>
22 #include <vector>
23 
24 #include <com/sun/star/table/XTable.hpp>
25 #include <com/sun/star/table/XMergeableCellRange.hpp>
26 
27 #include <tools/stream.hxx>
28 #include <tools/UnitConversion.hxx>
29 #include <svtools/rtftoken.h>
30 
31 #include <svx/svdetc.hxx>
32 #include <editeng/outlobj.hxx>
33 
34 #include <cell.hxx>
35 #include <svx/svdotable.hxx>
36 #include <svx/svdoutl.hxx>
37 #include <editeng/editeng.hxx>
38 #include <editeng/editdata.hxx>
39 #include <svx/svdmodel.hxx>
40 #include <editeng/svxrtf.hxx>
41 #include <sal/log.hxx>
42 #include <tools/debug.hxx>
43 #include <tools/diagnose_ex.h>
44 
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::table;
47 using namespace ::com::sun::star::container;
48 using namespace ::com::sun::star::beans;
49 
50 namespace sdr::table {
51 
52 namespace {
53 
54 struct RTFCellDefault
55 {
56     SfxItemSet          maItemSet;
57     sal_Int32           mnRowSpan;
58     sal_Int32           mnColSpan;   // MergeCell if >1, merged cells if 0
59     sal_Int32           mnCellX;
60 
RTFCellDefaultsdr::table::__anonc0803c7b0111::RTFCellDefault61     explicit RTFCellDefault( SfxItemPool* pPool ) : maItemSet( *pPool ), mnRowSpan(1), mnColSpan(1), mnCellX(0) {}
62 };
63 
64 }
65 
66 typedef std::vector< std::shared_ptr< RTFCellDefault > > RTFCellDefaultVector;
67 
68 namespace {
69 
70 struct RTFCellInfo
71 {
72     SfxItemSet          maItemSet;
73     sal_Int32           mnStartPara;
74     sal_Int32           mnParaCount;
75     sal_Int32           mnCellX;
76     sal_Int32           mnRowSpan;
77     std::shared_ptr< RTFCellInfo > mxVMergeCell;
78 
RTFCellInfosdr::table::__anonc0803c7b0211::RTFCellInfo79     explicit RTFCellInfo( SfxItemPool& rPool ) : maItemSet(  rPool ), mnStartPara(0), mnParaCount(0), mnCellX(0), mnRowSpan(1) {}
80 };
81 
82 }
83 
84 typedef std::shared_ptr< RTFCellInfo > RTFCellInfoPtr;
85 typedef std::vector< RTFCellInfoPtr > RTFColumnVector;
86 
87 typedef std::shared_ptr< RTFColumnVector > RTFColumnVectorPtr;
88 
89 class SdrTableRTFParser
90 {
91 public:
92     explicit SdrTableRTFParser( SdrTableObj& rTableObj );
93 
94     void Read( SvStream& rStream );
95 
96     void ProcToken( RtfImportInfo* pInfo );
97 
98     void NextRow();
99     void NextColumn();
100     void NewCellRow();
101 
102     void InsertCell( RtfImportInfo const * pInfo );
103     void InsertColumnEdge( sal_Int32 nEdge );
104 
105     void FillTable();
106 
107     DECL_LINK( RTFImportHdl, RtfImportInfo&, void );
108 
109 private:
110     SdrTableObj&    mrTableObj;
111     std::unique_ptr<SdrOutliner> mpOutliner;
112     SfxItemPool&    mrItemPool;
113 
114     RTFCellDefaultVector maDefaultList;
115     RTFCellDefaultVector::iterator maDefaultIterator;
116 
117     int             mnLastToken;
118     bool            mbNewDef;
119 
120     sal_Int32       mnStartPara;
121 
122     sal_Int32       mnRowCnt;
123     sal_Int32       mnLastEdge;
124     sal_Int32       mnVMergeIdx;
125 
126     std::vector< sal_Int32 > maColumnEdges;
127     std::vector< sal_Int32 >::iterator maLastEdge;
128     std::vector< RTFColumnVectorPtr > maRows;
129 
130     std::unique_ptr<RTFCellDefault> mpInsDefault;
131     RTFCellDefault* mpActDefault;
132     RTFCellDefault* mpDefMerge;
133 
134     Reference< XTable > mxTable;
135 
136     RTFColumnVectorPtr mxLastRow;
137     // Copy assignment is forbidden and not implemented.
138     SdrTableRTFParser (const SdrTableRTFParser &) = delete;
139     SdrTableRTFParser & operator= (const SdrTableRTFParser &) = delete;
140 };
141 
SdrTableRTFParser(SdrTableObj & rTableObj)142 SdrTableRTFParser::SdrTableRTFParser( SdrTableObj& rTableObj )
143 : mrTableObj( rTableObj )
144 , mpOutliner( SdrMakeOutliner( OutlinerMode::TextObject, rTableObj.getSdrModelFromSdrObject() ) )
145 , mrItemPool( rTableObj.getSdrModelFromSdrObject().GetItemPool() )
146 , mnLastToken( 0 )
147 , mbNewDef( false )
148 , mnStartPara( 0 )
149 , mnRowCnt( 0 )
150 , mnLastEdge( 0 )
151 , mnVMergeIdx ( 0 )
152 , mpActDefault( nullptr )
153 , mpDefMerge( nullptr )
154 , mxTable( rTableObj.getTable() )
155 {
156     mpOutliner->SetUpdateMode(true);
157     mpOutliner->SetStyleSheet( 0, mrTableObj.GetStyleSheet() );
158     mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
159 }
160 
Read(SvStream & rStream)161 void SdrTableRTFParser::Read( SvStream& rStream )
162 {
163     EditEngine& rEdit = const_cast< EditEngine& >( mpOutliner->GetEditEngine() );
164 
165     Link<RtfImportInfo&,void> aOldLink( rEdit.GetRtfImportHdl() );
166     rEdit.SetRtfImportHdl( LINK( this, SdrTableRTFParser, RTFImportHdl ) );
167     mpOutliner->Read( rStream, OUString(), EETextFormat::Rtf );
168     rEdit.SetRtfImportHdl( aOldLink );
169 
170     FillTable();
171 }
172 
IMPL_LINK(SdrTableRTFParser,RTFImportHdl,RtfImportInfo &,rInfo,void)173 IMPL_LINK( SdrTableRTFParser, RTFImportHdl, RtfImportInfo&, rInfo, void )
174 {
175     switch ( rInfo.eState )
176     {
177         case RtfImportState::NextToken:
178             ProcToken( &rInfo );
179             break;
180         case RtfImportState::UnknownAttr:
181             ProcToken( &rInfo );
182             break;
183         case RtfImportState::Start:
184         {
185             SvxRTFParser* pParser = static_cast<SvxRTFParser*>(rInfo.pParser);
186             pParser->SetAttrPool( &mrItemPool );
187             RTFPardAttrMapIds& rMap = pParser->GetPardMap();
188             rMap.nBox = SDRATTR_TABLE_BORDER;
189         }
190             break;
191         case RtfImportState::End:
192             if ( rInfo.aSelection.nEndPos )
193             {
194                 mpActDefault = nullptr;
195                 rInfo.nToken = RTF_PAR;
196                 rInfo.aSelection.nEndPara++;
197                 ProcToken( &rInfo );
198             }
199             break;
200         case RtfImportState::SetAttr:
201         case RtfImportState::InsertText:
202         case RtfImportState::InsertPara:
203             break;
204         default:
205             SAL_WARN( "svx.table","unknown ImportInfo.eState");
206     }
207 }
208 
NextRow()209 void SdrTableRTFParser::NextRow()
210 {
211     mxLastRow = maRows.back();
212     mnVMergeIdx = 0;
213     ++mnRowCnt;
214 }
215 
InsertCell(RtfImportInfo const * pInfo)216 void SdrTableRTFParser::InsertCell( RtfImportInfo const * pInfo )
217 {
218 
219     RTFCellInfoPtr xCellInfo = std::make_shared<RTFCellInfo>(mrItemPool);
220 
221     xCellInfo->mnStartPara = mnStartPara;
222     xCellInfo->mnParaCount = pInfo->aSelection.nEndPara - 1 - mnStartPara;
223     xCellInfo->mnCellX = mpActDefault->mnCellX;
224     xCellInfo->mnRowSpan = mpActDefault->mnRowSpan;
225 
226 
227     if ( mxLastRow != nullptr )
228     {
229         sal_Int32 nSize = mxLastRow->size();
230         while( mnVMergeIdx < nSize &&
231              (*mxLastRow)[mnVMergeIdx]->mnCellX < xCellInfo->mnCellX )
232             ++mnVMergeIdx;
233 
234         if ( xCellInfo->mnRowSpan == 0 && mnVMergeIdx < nSize )
235         {
236             RTFCellInfoPtr xLastCell( (*mxLastRow)[mnVMergeIdx] );
237             if (xLastCell->mnRowSpan)
238                 xCellInfo->mxVMergeCell = xLastCell;
239             else
240                 xCellInfo->mxVMergeCell = xLastCell->mxVMergeCell;
241         }
242     }
243 
244     if( !maRows.empty() )
245     {
246         RTFColumnVectorPtr xColumn( maRows.back() );
247         if ( xCellInfo->mxVMergeCell )
248         {
249             if ( xColumn->empty() ||
250                     xColumn->back()->mxVMergeCell != xCellInfo->mxVMergeCell )
251                 xCellInfo->mxVMergeCell->mnRowSpan++;
252         }
253 
254         xColumn->push_back( xCellInfo );
255     }
256 
257     mnStartPara = pInfo->aSelection.nEndPara - 1;
258 }
259 
InsertColumnEdge(sal_Int32 nEdge)260 void SdrTableRTFParser::InsertColumnEdge( sal_Int32 nEdge )
261 {
262     auto aNextEdge = std::lower_bound( maLastEdge, maColumnEdges.end(), nEdge );
263 
264     if ( aNextEdge == maColumnEdges.end() || nEdge != *aNextEdge )
265     {
266         maLastEdge = maColumnEdges.insert( aNextEdge , nEdge );
267         mnLastEdge = nEdge;
268     }
269 }
270 
FillTable()271 void SdrTableRTFParser::FillTable()
272 {
273     try
274     {
275         sal_Int32 nColCount = mxTable->getColumnCount();
276         Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_SET_THROW );
277         sal_Int32 nColMax = maColumnEdges.size();
278         if( nColCount < nColMax )
279         {
280             xCols->insertByIndex( nColCount, nColMax - nColCount );
281             nColCount = mxTable->getColumnCount();
282         }
283 
284         static const OUStringLiteral sWidth(u"Width");
285         sal_Int32 nCol, nLastEdge = 0;
286         for( nCol = 0; nCol < nColCount; nCol++ )
287         {
288             Reference< XPropertySet > xSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW );
289             sal_Int32 nWidth = maColumnEdges[nCol] - nLastEdge;
290 
291             xSet->setPropertyValue( sWidth, Any( nWidth ) );
292             nLastEdge += nWidth;
293         }
294 
295         const sal_Int32 nRowCount = mxTable->getRowCount();
296         if( nRowCount < mnRowCnt )
297         {
298             Reference< XTableRows > xRows( mxTable->getRows(), UNO_SET_THROW );
299             xRows->insertByIndex( nRowCount, mnRowCnt - nRowCount );
300         }
301 
302         for( sal_Int32 nRow = 0; nRow < static_cast<sal_Int32>(maRows.size()); nRow++ )
303         {
304             RTFColumnVectorPtr xColumn( maRows[nRow] );
305             nCol = 0;
306             auto aEdge = maColumnEdges.begin();
307             for( sal_Int32 nIdx = 0; nCol < nColMax && nIdx < static_cast<sal_Int32>(xColumn->size()); nIdx++ )
308             {
309                 RTFCellInfoPtr xCellInfo( (*xColumn)[nIdx] );
310 
311                 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
312                 if( xCell.is() && xCellInfo )
313                 {
314                     const SfxPoolItem *pPoolItem = nullptr;
315                     if( xCellInfo->maItemSet.GetItemState(SDRATTR_TABLE_BORDER,false,&pPoolItem)==SfxItemState::SET)
316                         xCell->SetMergedItem( *pPoolItem );
317 
318                     std::unique_ptr<OutlinerParaObject> pTextObject(mpOutliner->CreateParaObject( xCellInfo->mnStartPara, xCellInfo->mnParaCount ));
319                     if( pTextObject )
320                     {
321                         SdrOutliner& rOutliner=mrTableObj.ImpGetDrawOutliner();
322                         rOutliner.SetUpdateMode(true);
323                         rOutliner.SetText( *pTextObject );
324                         mrTableObj.NbcSetOutlinerParaObjectForText( rOutliner.CreateParaObject(), xCell.get() );
325                     }
326 
327                     sal_Int32 nLastRow = nRow;
328                     if ( xCellInfo->mnRowSpan )
329                         nLastRow += xCellInfo->mnRowSpan - 1;
330 
331                     aEdge = std::lower_bound( aEdge, maColumnEdges.end(), xCellInfo->mnCellX );
332                     sal_Int32 nLastCol = nCol;
333                     if ( aEdge != maColumnEdges.end() )
334                     {
335                         nLastCol = std::distance( maColumnEdges.begin(), aEdge);
336                         ++aEdge;
337                     }
338 
339                     if ( nLastCol > nCol || nLastRow > nRow )
340                     {
341                          Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( nCol, nRow, nLastCol, nLastRow ) ), UNO_QUERY_THROW );
342                          if( xRange->isMergeable() )
343                              xRange->merge();
344                     }
345                     nCol = nLastCol + 1;
346                 }
347             }
348         }
349 
350         tools::Rectangle aRect( mrTableObj.GetSnapRect() );
351         aRect.SetRight( aRect.Left() + nLastEdge );
352         mrTableObj.NbcSetSnapRect( aRect );
353 
354     }
355     catch( Exception& )
356     {
357         TOOLS_WARN_EXCEPTION("svx", "");
358     }
359 }
360 
NewCellRow()361 void SdrTableRTFParser::NewCellRow()
362 {
363     if( mbNewDef )
364     {
365         mbNewDef = false;
366 
367         maRows.push_back( std::make_shared<std::vector<std::shared_ptr<RTFCellInfo>>>( ) );
368     }
369     mpDefMerge = nullptr;
370     maDefaultIterator = maDefaultList.begin();
371 
372     NextColumn();
373 
374     DBG_ASSERT( mpActDefault, "NewCellRow: pActDefault==0" );
375 }
376 
NextColumn()377 void SdrTableRTFParser::NextColumn()
378 {
379     if( maDefaultIterator != maDefaultList.end() )
380         mpActDefault = (*maDefaultIterator++).get();
381     else
382         mpActDefault = nullptr;
383 }
384 
ProcToken(RtfImportInfo * pInfo)385 void SdrTableRTFParser::ProcToken( RtfImportInfo* pInfo )
386 {
387     switch ( pInfo->nToken )
388     {
389         case RTF_TROWD:         // denotes table row default, before RTF_CELLX
390         {
391             maDefaultList.clear();
392             mpDefMerge = nullptr;
393             mnLastToken = pInfo->nToken;
394             maLastEdge = maColumnEdges.begin();
395             mnLastEdge = 0;
396         }
397         break;
398         case RTF_CLMGF:         // The first cell of cells to be merged
399         {
400             mpDefMerge = mpInsDefault.get();
401             mnLastToken = pInfo->nToken;
402         }
403         break;
404         case RTF_CLMRG:         // A cell to be merged with the preceding cell
405         {
406             if ( !mpDefMerge )
407                 mpDefMerge = maDefaultList.back().get();
408             DBG_ASSERT( mpDefMerge, "RTF_CLMRG: pDefMerge==0" );
409             if( mpDefMerge )
410                 mpDefMerge->mnColSpan++;
411             mpInsDefault->mnColSpan = 0;
412             mnLastToken = pInfo->nToken;
413         }
414         break;
415         case RTF_CLVMGF:
416         {
417             mnLastToken = pInfo->nToken;
418         }
419         break;
420         case RTF_CLVMRG:
421         {
422             mpInsDefault->mnRowSpan = 0;
423             mnLastToken = pInfo->nToken;
424         }
425         break;
426         case RTF_CELLX:         // closes cell default
427         {
428             mbNewDef = true;
429             std::shared_ptr<RTFCellDefault> pDefault( mpInsDefault.release() );
430             maDefaultList.push_back( pDefault );
431 
432 
433             const sal_Int32 nSize = convertTwipToMm100(pInfo->nTokenValue);
434             if ( nSize > mnLastEdge )
435                 InsertColumnEdge( nSize );
436 
437             pDefault->mnCellX = nSize;
438             // Record cellx in the first merged cell.
439             if ( mpDefMerge && pDefault->mnColSpan == 0 )
440                 mpDefMerge->mnCellX = nSize;
441 
442             mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
443 
444             mnLastToken = pInfo->nToken;
445         }
446         break;
447         case RTF_INTBL:         // before the first RTF_CELL
448         {
449             if ( mnLastToken != RTF_INTBL && mnLastToken != RTF_CELL && mnLastToken != RTF_PAR )
450             {
451                 NewCellRow();
452                 mnLastToken = pInfo->nToken;
453             }
454         }
455         break;
456         case RTF_CELL:          // denotes the end of a cell.
457         {
458             DBG_ASSERT( mpActDefault, "RTF_CELL: pActDefault==0" );
459             if ( mbNewDef || !mpActDefault )
460                 NewCellRow();
461             if ( !mpActDefault )
462                 mpActDefault = mpInsDefault.get();
463             if ( mpActDefault->mnColSpan > 0 )
464             {
465                 InsertCell(pInfo);
466             }
467             NextColumn();
468             mnLastToken = pInfo->nToken;
469         }
470         break;
471         case RTF_ROW:           // means the end of a row
472         {
473             NextRow();
474             mnLastToken = pInfo->nToken;
475         }
476         break;
477         case RTF_PAR:           // Paragraph
478             mnLastToken = pInfo->nToken;
479             break;
480         default:
481         {   // do not set nLastToken
482             switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
483             {
484                 case RTF_SHADINGDEF:
485 //                  ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(pInfo->nToken, mpInsDefault->maItemSet, sal_True );
486                 break;
487                 case RTF_BRDRDEF:
488                     static_cast<SvxRTFParser*>(pInfo->pParser)->ReadBorderAttr(pInfo->nToken, mpInsDefault->maItemSet, true );
489                 break;
490             }
491         }
492     }
493 }
494 
ImportAsRTF(SvStream & rStream,SdrTableObj & rObj)495 void ImportAsRTF( SvStream& rStream, SdrTableObj& rObj )
496 {
497     SdrTableRTFParser aParser( rObj );
498     aParser.Read( rStream );
499 }
500 
501 }
502 
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
504