LibreOffice Module svx (master) 1
tablertfimporter.cxx
Go to the documentation of this file.
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>
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/editids.hrc>
41#include <editeng/svxrtf.hxx>
42#include <sal/log.hxx>
43#include <tools/debug.hxx>
45
46using namespace ::com::sun::star::uno;
47using namespace ::com::sun::star::table;
48using namespace ::com::sun::star::container;
49using namespace ::com::sun::star::beans;
50
51namespace sdr::table {
52
53namespace {
54
55struct RTFCellDefault
56{
58 sal_Int32 mnRowSpan;
59 sal_Int32 mnColSpan; // MergeCell if >1, merged cells if 0
60 sal_Int32 mnCellX;
61
62 explicit RTFCellDefault( SfxItemPool* pPool ) : maItemSet( *pPool ), mnRowSpan(1), mnColSpan(1), mnCellX(0) {}
63};
64
65}
66
67typedef std::vector< std::shared_ptr< RTFCellDefault > > RTFCellDefaultVector;
68
69namespace {
70
71struct RTFCellInfo
72{
74 sal_Int32 mnStartPara;
75 sal_Int32 mnParaCount;
76 sal_Int32 mnCellX;
77 sal_Int32 mnRowSpan;
78 std::shared_ptr< RTFCellInfo > mxVMergeCell;
79
80 explicit RTFCellInfo( SfxItemPool& rPool ) : maItemSet( rPool ), mnStartPara(0), mnParaCount(0), mnCellX(0), mnRowSpan(1) {}
81};
82
83}
84
85typedef std::shared_ptr< RTFCellInfo > RTFCellInfoPtr;
86typedef std::vector< RTFCellInfoPtr > RTFColumnVector;
87
88typedef std::shared_ptr< RTFColumnVector > RTFColumnVectorPtr;
89
91{
92public:
93 explicit SdrTableRTFParser( SdrTableObj& rTableObj );
94
95 void Read( SvStream& rStream );
96
97 void ProcToken( RtfImportInfo* pInfo );
98
99 void NextRow();
100 void NextColumn();
101 void NewCellRow();
102
103 void InsertCell( RtfImportInfo const * pInfo );
104 void InsertColumnEdge( sal_Int32 nEdge );
105
106 void FillTable();
107
108 DECL_LINK( RTFImportHdl, RtfImportInfo&, void );
109
110private:
112 std::unique_ptr<SdrOutliner> mpOutliner;
114
116 RTFCellDefaultVector::iterator maDefaultIterator;
117
120
121 sal_Int32 mnStartPara;
122
123 sal_Int32 mnRowCnt;
124 sal_Int32 mnLastEdge;
125 sal_Int32 mnVMergeIdx;
126
127 std::vector< sal_Int32 > maColumnEdges;
128 std::vector< sal_Int32 >::iterator maLastEdge;
129 std::vector< RTFColumnVectorPtr > maRows;
130
131 std::unique_ptr<RTFCellDefault> mpInsDefault;
132 RTFCellDefault* mpActDefault;
133 RTFCellDefault* mpDefMerge;
134
135 Reference< XTable > mxTable;
136
138 // Copy assignment is forbidden and not implemented.
141};
142
144: mrTableObj( rTableObj )
145, mpOutliner( SdrMakeOutliner( OutlinerMode::TextObject, rTableObj.getSdrModelFromSdrObject() ) )
146, mrItemPool( rTableObj.getSdrModelFromSdrObject().GetItemPool() )
147, mnLastToken( 0 )
148, mbNewDef( false )
149, mnStartPara( 0 )
150, mnRowCnt( 0 )
151, mnLastEdge( 0 )
152, mnVMergeIdx ( 0 )
153, mpActDefault( nullptr )
154, mpDefMerge( nullptr )
155, mxTable( rTableObj.getTable() )
156{
157 mpOutliner->SetUpdateLayout(true);
158 mpOutliner->SetStyleSheet( 0, mrTableObj.GetStyleSheet() );
159 mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
160}
161
163{
164 EditEngine& rEdit = const_cast< EditEngine& >( mpOutliner->GetEditEngine() );
165
166 Link<RtfImportInfo&,void> aOldLink( rEdit.GetRtfImportHdl() );
167 rEdit.SetRtfImportHdl( LINK( this, SdrTableRTFParser, RTFImportHdl ) );
168 mpOutliner->Read( rStream, OUString(), EETextFormat::Rtf );
169 rEdit.SetRtfImportHdl( aOldLink );
170
171 FillTable();
172}
173
174IMPL_LINK( SdrTableRTFParser, RTFImportHdl, RtfImportInfo&, rInfo, void )
175{
176 switch ( rInfo.eState )
177 {
178 case RtfImportState::NextToken:
179 ProcToken( &rInfo );
180 break;
181 case RtfImportState::UnknownAttr:
182 ProcToken( &rInfo );
183 break;
184 case RtfImportState::Start:
185 {
186 SvxRTFParser* pParser = static_cast<SvxRTFParser*>(rInfo.pParser);
187 pParser->SetAttrPool( &mrItemPool );
188 pParser->SetPardMap(SID_ATTR_BORDER_OUTER, 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
210{
211 mxLastRow = maRows.back();
212 mnVMergeIdx = 0;
213 ++mnRowCnt;
214}
215
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 {
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
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
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 constexpr 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 {
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::optional<OutlinerParaObject> pTextObject(mpOutliner->CreateParaObject( xCellInfo->mnStartPara, xCellInfo->mnParaCount ));
319 if( pTextObject )
320 {
322 rOutliner.SetUpdateLayout(true);
323 rOutliner.SetText( *pTextObject );
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
351 aRect.SetRight( aRect.Left() + nLastEdge );
352 mrTableObj.NbcSetSnapRect( aRect );
353
354 }
355 catch( Exception& )
356 {
357 TOOLS_WARN_EXCEPTION("svx", "");
358 }
359}
360
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;
371
372 NextColumn();
373
374 DBG_ASSERT( mpActDefault, "NewCellRow: pActDefault==0" );
375}
376
378{
379 if( maDefaultIterator != maDefaultList.end() )
381 else
382 mpActDefault = nullptr;
383}
384
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 {
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 )
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
495void 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: */
constexpr auto convertTwipToMm100(N n)
const Link< RtfImportInfo &, void > & GetRtfImportHdl() const
void SetRtfImportHdl(const Link< RtfImportInfo &, void > &rLink)
void SetText(const OutlinerParaObject &)
std::optional< OutlinerParaObject > CreateParaObject(sal_Int32 nStartPara=0, sal_Int32 nParaCount=EE_PARA_ALL) const
bool SetUpdateLayout(bool bUpdate)
SfxStyleSheet * GetStyleSheet() const
Definition: svdobj.cxx:2244
SdrOutliner & ImpGetDrawOutliner() const
Definition: svdotext.cxx:1194
void NbcSetOutlinerParaObjectForText(std::optional< OutlinerParaObject > pTextObject, SdrText *pText)
Definition: svdotext.cxx:1435
void SetPardMap(TypedWhichId< T > wid, TypedWhichId< T > widTrue)
void SetAttrPool(SfxItemPool *pNewPool)
virtual void NbcSetSnapRect(const tools::Rectangle &rRect) override
Definition: svdotable.cxx:1765
virtual const tools::Rectangle & GetSnapRect() const override
Definition: svdotable.cxx:1759
void InsertColumnEdge(sal_Int32 nEdge)
SdrTableRTFParser(const SdrTableRTFParser &)=delete
void ProcToken(RtfImportInfo *pInfo)
void InsertCell(RtfImportInfo const *pInfo)
RTFCellDefaultVector::iterator maDefaultIterator
std::vector< RTFColumnVectorPtr > maRows
SdrTableRTFParser & operator=(const SdrTableRTFParser &)=delete
std::unique_ptr< SdrOutliner > mpOutliner
SdrTableRTFParser(SdrTableObj &rTableObj)
DECL_LINK(RTFImportHdl, RtfImportInfo &, void)
void Read(SvStream &rStream)
std::vector< sal_Int32 > maColumnEdges
std::unique_ptr< RTFCellDefault > mpInsDefault
RTFCellDefaultVector maDefaultList
std::vector< sal_Int32 >::iterator maLastEdge
constexpr void SetRight(tools::Long v)
constexpr tools::Long Left() const
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
float u
Reference< XColumn > xColumn
#define SAL_WARN(area, stream)
@ Exception
std::vector< std::shared_ptr< RTFCellDefault > > RTFCellDefaultVector
std::vector< RTFCellInfoPtr > RTFColumnVector
IMPL_LINK(SdrTableRTFParser, RTFImportHdl, RtfImportInfo &, rInfo, void)
void ImportAsRTF(SvStream &rStream, SdrTableObj &rObj)
std::shared_ptr< RTFCellInfo > RTFCellInfoPtr
std::shared_ptr< RTFColumnVector > RTFColumnVectorPtr
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
OutlinerMode
RTF_BRDRDEF
RTF_TABLEDEF
RTF_SHADINGDEF
RTF_CLVMRG
RTF_TROWD
RTF_ROW
RTF_INTBL
RTF_CLMRG
RTF_CELL
RTF_CLMGF
RTF_CELLX
RTF_CLVMGF
RTF_PAR
sal_Int32 nEndPara
ESelection aSelection
SvParser< int > * pParser
constexpr TypedWhichId< SvxBoxItem > SDRATTR_TABLE_BORDER(SDRATTR_TABLE_FIRST+0)
std::unique_ptr< SdrOutliner > SdrMakeOutliner(OutlinerMode nOutlinerMode, SdrModel &rModel)
Create an Outliner with the engine-global default settings on the heap.
Definition: svdetc.cxx:332
std::shared_ptr< RTFCellInfo > mxVMergeCell
sal_Int32 mnColSpan
sal_Int32 mnCellX
sal_Int32 mnStartPara
sal_Int32 mnRowSpan
sal_Int32 mnParaCount
SfxItemSet maItemSet