Bump version to 6.4-15
[LibreOffice.git] / svx / source / table / tablertfimporter.cxx
blob43b7f44b2e78f7c3cafaffe1a2dacc8f7527dcd6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <memory>
22 #include <vector>
24 #include <com/sun/star/table/XTable.hpp>
25 #include <com/sun/star/table/XMergeableCellRange.hpp>
27 #include <tools/stream.hxx>
28 #include <svtools/rtftoken.h>
30 #include <editeng/eeitem.hxx>
31 #include <svx/svdetc.hxx>
32 #include <editeng/fhgtitem.hxx>
33 #include <editeng/outlobj.hxx>
35 #include <cell.hxx>
36 #include <celltypes.hxx>
37 #include <svx/svdotable.hxx>
38 #include <svx/svdoutl.hxx>
39 #include <editeng/editeng.hxx>
40 #include <editeng/editdata.hxx>
41 #include <svx/svdmodel.hxx>
42 #include <editeng/svxrtf.hxx>
43 #include <sal/log.hxx>
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;
50 namespace sdr { namespace table {
52 struct RTFCellDefault
54 SfxItemSet maItemSet;
55 sal_Int32 mnRowSpan;
56 sal_Int32 mnColSpan; // MergeCell if >1, merged cells if 0
57 sal_Int32 mnCellX;
59 explicit RTFCellDefault( SfxItemPool* pPool ) : maItemSet( *pPool ), mnRowSpan(1), mnColSpan(1), mnCellX(0) {}
62 typedef std::vector< std::shared_ptr< RTFCellDefault > > RTFCellDefaultVector;
64 struct RTFCellInfo
66 SfxItemSet const maItemSet;
67 sal_Int32 mnStartPara;
68 sal_Int32 mnParaCount;
69 sal_Int32 mnCellX;
70 sal_Int32 mnRowSpan;
71 std::shared_ptr< RTFCellInfo > mxVMergeCell;
73 explicit RTFCellInfo( SfxItemPool& rPool ) : maItemSet( rPool ), mnStartPara(0), mnParaCount(0), mnCellX(0), mnRowSpan(1) {}
76 typedef std::shared_ptr< RTFCellInfo > RTFCellInfoPtr;
77 typedef std::vector< RTFCellInfoPtr > RTFColumnVector;
79 typedef std::shared_ptr< RTFColumnVector > RTFColumnVectorPtr;
81 class SdrTableRTFParser
83 public:
84 explicit SdrTableRTFParser( SdrTableObj& rTableObj );
86 void Read( SvStream& rStream );
88 void ProcToken( RtfImportInfo* pInfo );
90 void NextRow();
91 void NextColumn();
92 void NewCellRow();
94 void InsertCell( RtfImportInfo const * pInfo );
95 void InsertColumnEdge( sal_Int32 nEdge );
97 void FillTable();
99 DECL_LINK( RTFImportHdl, RtfImportInfo&, void );
101 private:
102 SdrTableObj& mrTableObj;
103 std::unique_ptr<SdrOutliner> mpOutliner;
104 SfxItemPool& mrItemPool;
106 RTFCellDefaultVector maDefaultList;
107 RTFCellDefaultVector::iterator maDefaultIterator;
109 int mnLastToken;
110 bool mbNewDef;
112 sal_Int32 mnStartPara;
114 sal_Int32 mnRowCnt;
115 sal_Int32 mnLastEdge;
116 sal_Int32 mnVMergeIdx;
118 std::vector< sal_Int32 > maColumnEdges;
119 std::vector< sal_Int32 >::iterator maLastEdge;
120 std::vector< RTFColumnVectorPtr > maRows;
122 std::unique_ptr<RTFCellDefault> mpInsDefault;
123 RTFCellDefault* mpActDefault;
124 RTFCellDefault* mpDefMerge;
126 Reference< XTable > mxTable;
128 RTFColumnVectorPtr mxLastRow;
129 // Copy assignment is forbidden and not implemented.
130 SdrTableRTFParser (const SdrTableRTFParser &) = delete;
131 SdrTableRTFParser & operator= (const SdrTableRTFParser &) = delete;
134 SdrTableRTFParser::SdrTableRTFParser( SdrTableObj& rTableObj )
135 : mrTableObj( rTableObj )
136 , mpOutliner( SdrMakeOutliner( OutlinerMode::TextObject, rTableObj.getSdrModelFromSdrObject() ) )
137 , mrItemPool( rTableObj.getSdrModelFromSdrObject().GetItemPool() )
138 , mnLastToken( 0 )
139 , mbNewDef( false )
140 , mnStartPara( 0 )
141 , mnRowCnt( 0 )
142 , mnLastEdge( 0 )
143 , mnVMergeIdx ( 0 )
144 , mpActDefault( nullptr )
145 , mpDefMerge( nullptr )
146 , mxTable( rTableObj.getTable() )
148 mpOutliner->SetUpdateMode(true);
149 mpOutliner->SetStyleSheet( 0, mrTableObj.GetStyleSheet() );
150 mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
153 void SdrTableRTFParser::Read( SvStream& rStream )
155 EditEngine& rEdit = const_cast< EditEngine& >( mpOutliner->GetEditEngine() );
157 Link<RtfImportInfo&,void> aOldLink( rEdit.GetRtfImportHdl() );
158 rEdit.SetRtfImportHdl( LINK( this, SdrTableRTFParser, RTFImportHdl ) );
159 mpOutliner->Read( rStream, OUString(), EETextFormat::Rtf );
160 rEdit.SetRtfImportHdl( aOldLink );
162 FillTable();
165 IMPL_LINK( SdrTableRTFParser, RTFImportHdl, RtfImportInfo&, rInfo, void )
167 switch ( rInfo.eState )
169 case RtfImportState::NextToken:
170 ProcToken( &rInfo );
171 break;
172 case RtfImportState::UnknownAttr:
173 ProcToken( &rInfo );
174 break;
175 case RtfImportState::Start:
177 SvxRTFParser* pParser = static_cast<SvxRTFParser*>(rInfo.pParser);
178 pParser->SetAttrPool( &mrItemPool );
179 RTFPardAttrMapIds& rMap = pParser->GetPardMap();
180 rMap.nBox = SDRATTR_TABLE_BORDER;
182 break;
183 case RtfImportState::End:
184 if ( rInfo.aSelection.nEndPos )
186 mpActDefault = nullptr;
187 rInfo.nToken = RTF_PAR;
188 rInfo.aSelection.nEndPara++;
189 ProcToken( &rInfo );
191 break;
192 case RtfImportState::SetAttr:
193 case RtfImportState::InsertText:
194 case RtfImportState::InsertPara:
195 break;
196 default:
197 SAL_WARN( "svx.table","unknown ImportInfo.eState");
201 void SdrTableRTFParser::NextRow()
203 mxLastRow = maRows.back();
204 mnVMergeIdx = 0;
205 ++mnRowCnt;
208 void SdrTableRTFParser::InsertCell( RtfImportInfo const * pInfo )
211 RTFCellInfoPtr xCellInfo( new RTFCellInfo(mrItemPool) );
213 xCellInfo->mnStartPara = mnStartPara;
214 xCellInfo->mnParaCount = pInfo->aSelection.nEndPara - 1 - mnStartPara;
215 xCellInfo->mnCellX = mpActDefault->mnCellX;
216 xCellInfo->mnRowSpan = mpActDefault->mnRowSpan;
219 if ( mxLastRow != nullptr )
221 sal_Int32 nSize = mxLastRow->size();
222 while( mnVMergeIdx < nSize &&
223 (*mxLastRow)[mnVMergeIdx]->mnCellX < xCellInfo->mnCellX )
224 ++mnVMergeIdx;
226 if ( xCellInfo->mnRowSpan == 0 && mnVMergeIdx < nSize )
228 RTFCellInfoPtr xLastCell( (*mxLastRow)[mnVMergeIdx] );
229 if (xLastCell->mnRowSpan)
230 xCellInfo->mxVMergeCell = xLastCell;
231 else
232 xCellInfo->mxVMergeCell = xLastCell->mxVMergeCell;
236 if( !maRows.empty() )
238 RTFColumnVectorPtr xColumn( maRows.back() );
239 if ( xCellInfo->mxVMergeCell )
241 if ( xColumn->empty() ||
242 xColumn->back()->mxVMergeCell != xCellInfo->mxVMergeCell )
243 xCellInfo->mxVMergeCell->mnRowSpan++;
246 xColumn->push_back( xCellInfo );
249 mnStartPara = pInfo->aSelection.nEndPara - 1;
252 void SdrTableRTFParser::InsertColumnEdge( sal_Int32 nEdge )
254 auto aNextEdge = std::lower_bound( maLastEdge, maColumnEdges.end(), nEdge );
256 if ( aNextEdge == maColumnEdges.end() || nEdge != *aNextEdge )
258 maLastEdge = maColumnEdges.insert( aNextEdge , nEdge );
259 mnLastEdge = nEdge;
263 void SdrTableRTFParser::FillTable()
267 sal_Int32 nColCount = mxTable->getColumnCount();
268 Reference< XTableColumns > xCols( mxTable->getColumns(), UNO_SET_THROW );
269 sal_Int32 nColMax = maColumnEdges.size();
270 if( nColCount < nColMax )
272 xCols->insertByIndex( nColCount, nColMax - nColCount );
273 nColCount = mxTable->getColumnCount();
276 const OUString sWidth("Width");
277 sal_Int32 nCol, nLastEdge = 0;
278 for( nCol = 0; nCol < nColCount; nCol++ )
280 Reference< XPropertySet > xSet( xCols->getByIndex( nCol ), UNO_QUERY_THROW );
281 sal_Int32 nWidth = maColumnEdges[nCol] - nLastEdge;
283 xSet->setPropertyValue( sWidth, Any( nWidth ) );
284 nLastEdge += nWidth;
287 const sal_Int32 nRowCount = mxTable->getRowCount();
288 if( nRowCount < mnRowCnt )
290 Reference< XTableRows > xRows( mxTable->getRows(), UNO_SET_THROW );
291 xRows->insertByIndex( nRowCount, mnRowCnt - nRowCount );
294 for( sal_Int32 nRow = 0; nRow < static_cast<sal_Int32>(maRows.size()); nRow++ )
296 RTFColumnVectorPtr xColumn( maRows[nRow] );
297 nCol = 0;
298 auto aEdge = maColumnEdges.begin();
299 for( sal_Int32 nIdx = 0; nCol < nColMax && nIdx < static_cast<sal_Int32>(xColumn->size()); nIdx++ )
301 RTFCellInfoPtr xCellInfo( (*xColumn)[nIdx] );
303 CellRef xCell( dynamic_cast< Cell* >( mxTable->getCellByPosition( nCol, nRow ).get() ) );
304 if( xCell.is() && xCellInfo.get() )
306 const SfxPoolItem *pPoolItem = nullptr;
307 if( xCellInfo->maItemSet.GetItemState(SDRATTR_TABLE_BORDER,false,&pPoolItem)==SfxItemState::SET)
308 xCell->SetMergedItem( *pPoolItem );
310 std::unique_ptr<OutlinerParaObject> pTextObject(mpOutliner->CreateParaObject( xCellInfo->mnStartPara, xCellInfo->mnParaCount ));
311 if( pTextObject )
313 SdrOutliner& rOutliner=mrTableObj.ImpGetDrawOutliner();
314 rOutliner.SetUpdateMode(true);
315 rOutliner.SetText( *pTextObject );
316 mrTableObj.NbcSetOutlinerParaObjectForText( rOutliner.CreateParaObject(), xCell.get() );
319 sal_Int32 nLastRow = nRow;
320 if ( xCellInfo->mnRowSpan )
321 nLastRow += xCellInfo->mnRowSpan - 1;
323 aEdge = std::lower_bound( aEdge, maColumnEdges.end(), xCellInfo->mnCellX );
324 sal_Int32 nLastCol = nCol;
325 if ( aEdge != maColumnEdges.end() )
327 nLastCol = std::distance( maColumnEdges.begin(), aEdge);
328 ++aEdge;
331 if ( nLastCol > nCol || nLastRow > nRow )
333 Reference< XMergeableCellRange > xRange( mxTable->createCursorByRange( mxTable->getCellRangeByPosition( nCol, nRow, nLastCol, nLastRow ) ), UNO_QUERY_THROW );
334 if( xRange->isMergeable() )
335 xRange->merge();
337 nCol = nLastCol + 1;
342 tools::Rectangle aRect( mrTableObj.GetSnapRect() );
343 aRect.SetRight( aRect.Left() + nLastEdge );
344 mrTableObj.NbcSetSnapRect( aRect );
347 catch( Exception& )
349 OSL_FAIL("sdr::table::SdrTableRTFParser::InsertCell(), exception caught!" );
353 void SdrTableRTFParser::NewCellRow()
355 if( mbNewDef )
357 mbNewDef = false;
359 maRows.push_back( std::make_shared<std::vector<std::shared_ptr<RTFCellInfo>>>( ) );
361 mpDefMerge = nullptr;
362 maDefaultIterator = maDefaultList.begin();
364 NextColumn();
366 DBG_ASSERT( mpActDefault, "NewCellRow: pActDefault==0" );
369 void SdrTableRTFParser::NextColumn()
371 if( maDefaultIterator != maDefaultList.end() )
372 mpActDefault = (*maDefaultIterator++).get();
373 else
374 mpActDefault = nullptr;
377 static long TwipsToHundMM( long nIn )
379 long nRet = OutputDevice::LogicToLogic( nIn, MapUnit::MapTwip, MapUnit::Map100thMM );
380 return nRet;
383 void SdrTableRTFParser::ProcToken( RtfImportInfo* pInfo )
385 switch ( pInfo->nToken )
387 case RTF_TROWD: // denotes table row default, before RTF_CELLX
389 maDefaultList.clear();
390 mpDefMerge = nullptr;
391 mnLastToken = pInfo->nToken;
392 maLastEdge = maColumnEdges.begin();
393 mnLastEdge = 0;
395 break;
396 case RTF_CLMGF: // The first cell of cells to be merged
398 mpDefMerge = mpInsDefault.get();
399 mnLastToken = pInfo->nToken;
401 break;
402 case RTF_CLMRG: // A cell to be merged with the preceding cell
404 if ( !mpDefMerge )
405 mpDefMerge = maDefaultList.back().get();
406 DBG_ASSERT( mpDefMerge, "RTF_CLMRG: pDefMerge==0" );
407 if( mpDefMerge )
408 mpDefMerge->mnColSpan++;
409 mpInsDefault->mnColSpan = 0;
410 mnLastToken = pInfo->nToken;
412 break;
413 case RTF_CLVMGF:
415 mnLastToken = pInfo->nToken;
417 break;
418 case RTF_CLVMRG:
420 mpInsDefault->mnRowSpan = 0;
421 mnLastToken = pInfo->nToken;
423 break;
424 case RTF_CELLX: // closes cell default
426 mbNewDef = true;
427 std::shared_ptr<RTFCellDefault> pDefault( mpInsDefault.release() );
428 maDefaultList.push_back( pDefault );
431 const sal_Int32 nSize = TwipsToHundMM( pInfo->nTokenValue );
432 if ( nSize > mnLastEdge )
433 InsertColumnEdge( nSize );
435 pDefault->mnCellX = nSize;
436 // Record cellx in the first merged cell.
437 if ( mpDefMerge && pDefault->mnColSpan == 0 )
438 mpDefMerge->mnCellX = nSize;
440 mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
442 mnLastToken = pInfo->nToken;
444 break;
445 case RTF_INTBL: // before the first RTF_CELL
447 if ( mnLastToken != RTF_INTBL && mnLastToken != RTF_CELL && mnLastToken != RTF_PAR )
449 NewCellRow();
450 mnLastToken = pInfo->nToken;
453 break;
454 case RTF_CELL: // denotes the end of a cell.
456 DBG_ASSERT( mpActDefault, "RTF_CELL: pActDefault==0" );
457 if ( mbNewDef || !mpActDefault )
458 NewCellRow();
459 if ( !mpActDefault )
460 mpActDefault = mpInsDefault.get();
461 if ( mpActDefault->mnColSpan > 0 )
463 InsertCell(pInfo);
465 NextColumn();
466 mnLastToken = pInfo->nToken;
468 break;
469 case RTF_ROW: // means the end of a row
471 NextRow();
472 mnLastToken = pInfo->nToken;
474 break;
475 case RTF_PAR: // Paragraph
476 mnLastToken = pInfo->nToken;
477 break;
478 default:
479 { // do not set nLastToken
480 switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
482 case RTF_SHADINGDEF:
483 // ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(pInfo->nToken, mpInsDefault->maItemSet, sal_True );
484 break;
485 case RTF_BRDRDEF:
486 static_cast<SvxRTFParser*>(pInfo->pParser)->ReadBorderAttr(pInfo->nToken, mpInsDefault->maItemSet, true );
487 break;
493 void SdrTableObj::ImportAsRTF( SvStream& rStream, SdrTableObj& rObj )
495 SdrTableRTFParser aParser( rObj );
496 aParser.Read( rStream );
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */