1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
24 #include <com/sun/star/table/XTable.hpp>
25 #include <com/sun/star/table/XMergeableCellRange.hpp>
27 #include <tools/stream.hxx>
28 #include <tools/UnitConversion.hxx>
29 #include <svtools/rtftoken.h>
31 #include <svx/svdetc.hxx>
32 #include <editeng/outlobj.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>
44 #include <comphelper/diagnose_ex.hxx>
46 using namespace ::com::sun::star::uno
;
47 using namespace ::com::sun::star::table
;
48 using namespace ::com::sun::star::container
;
49 using namespace ::com::sun::star::beans
;
51 namespace sdr::table
{
59 sal_Int32 mnColSpan
; // MergeCell if >1, merged cells if 0
62 explicit RTFCellDefault( SfxItemPool
* pPool
) : maItemSet( *pPool
), mnRowSpan(1), mnColSpan(1), mnCellX(0) {}
67 typedef std::vector
< std::shared_ptr
< RTFCellDefault
> > RTFCellDefaultVector
;
74 sal_Int32 mnStartPara
;
75 sal_Int32 mnParaCount
;
78 std::shared_ptr
< RTFCellInfo
> mxVMergeCell
;
80 explicit RTFCellInfo( SfxItemPool
& rPool
) : maItemSet( rPool
), mnStartPara(0), mnParaCount(0), mnCellX(0), mnRowSpan(1) {}
85 typedef std::shared_ptr
< RTFCellInfo
> RTFCellInfoPtr
;
86 typedef std::vector
< RTFCellInfoPtr
> RTFColumnVector
;
88 typedef std::shared_ptr
< RTFColumnVector
> RTFColumnVectorPtr
;
90 class SdrTableRTFParser
93 explicit SdrTableRTFParser( SdrTableObj
& rTableObj
);
95 void Read( SvStream
& rStream
);
97 void ProcToken( RtfImportInfo
* pInfo
);
103 void InsertCell( RtfImportInfo
const * pInfo
);
104 void InsertColumnEdge( sal_Int32 nEdge
);
108 DECL_LINK( RTFImportHdl
, RtfImportInfo
&, void );
111 SdrTableObj
& mrTableObj
;
112 std::unique_ptr
<SdrOutliner
> mpOutliner
;
113 SfxItemPool
& mrItemPool
;
115 RTFCellDefaultVector maDefaultList
;
116 RTFCellDefaultVector::iterator maDefaultIterator
;
121 sal_Int32 mnStartPara
;
124 sal_Int32 mnLastEdge
;
125 sal_Int32 mnVMergeIdx
;
127 std::vector
< sal_Int32
> maColumnEdges
;
128 std::vector
< sal_Int32
>::iterator maLastEdge
;
129 std::vector
< RTFColumnVectorPtr
> maRows
;
131 std::unique_ptr
<RTFCellDefault
> mpInsDefault
;
132 RTFCellDefault
* mpActDefault
;
133 RTFCellDefault
* mpDefMerge
;
135 rtl::Reference
< TableModel
> mxTable
;
137 RTFColumnVectorPtr mxLastRow
;
138 // Copy assignment is forbidden and not implemented.
139 SdrTableRTFParser (const SdrTableRTFParser
&) = delete;
140 SdrTableRTFParser
& operator= (const SdrTableRTFParser
&) = delete;
143 SdrTableRTFParser::SdrTableRTFParser( SdrTableObj
& rTableObj
)
144 : mrTableObj( rTableObj
)
145 , mpOutliner( SdrMakeOutliner( OutlinerMode::TextObject
, rTableObj
.getSdrModelFromSdrObject() ) )
146 , mrItemPool( rTableObj
.getSdrModelFromSdrObject().GetItemPool() )
153 , mpActDefault( nullptr )
154 , mpDefMerge( nullptr )
155 , mxTable( rTableObj
.getUnoTable() )
157 mpOutliner
->SetUpdateLayout(true);
158 mpOutliner
->SetStyleSheet( 0, mrTableObj
.GetStyleSheet() );
159 mpInsDefault
.reset( new RTFCellDefault( &mrItemPool
) );
162 void SdrTableRTFParser::Read( SvStream
& rStream
)
164 EditEngine
& rEdit
= const_cast< EditEngine
& >( mpOutliner
->GetEditEngine() );
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
);
174 IMPL_LINK( SdrTableRTFParser
, RTFImportHdl
, RtfImportInfo
&, rInfo
, void )
176 switch ( rInfo
.eState
)
178 case RtfImportState::NextToken
:
181 case RtfImportState::UnknownAttr
:
184 case RtfImportState::Start
:
186 SvxRTFParser
* pParser
= static_cast<SvxRTFParser
*>(rInfo
.pParser
);
187 pParser
->SetAttrPool( &mrItemPool
);
188 pParser
->SetPardMap(SID_ATTR_BORDER_OUTER
, SDRATTR_TABLE_BORDER
);
191 case RtfImportState::End
:
192 if ( rInfo
.aSelection
.end
.nIndex
)
194 mpActDefault
= nullptr;
195 rInfo
.nToken
= RTF_PAR
;
196 rInfo
.aSelection
.end
.nPara
++;
200 case RtfImportState::SetAttr
:
201 case RtfImportState::InsertText
:
202 case RtfImportState::InsertPara
:
205 SAL_WARN( "svx.table","unknown ImportInfo.eState");
209 void SdrTableRTFParser::NextRow()
211 mxLastRow
= maRows
.back();
216 void SdrTableRTFParser::InsertCell( RtfImportInfo
const * pInfo
)
219 RTFCellInfoPtr xCellInfo
= std::make_shared
<RTFCellInfo
>(mrItemPool
);
221 xCellInfo
->mnStartPara
= mnStartPara
;
222 xCellInfo
->mnParaCount
= pInfo
->aSelection
.end
.nPara
- 1 - mnStartPara
;
223 xCellInfo
->mnCellX
= mpActDefault
->mnCellX
;
224 xCellInfo
->mnRowSpan
= mpActDefault
->mnRowSpan
;
227 if ( mxLastRow
!= nullptr )
229 sal_Int32 nSize
= mxLastRow
->size();
230 while( mnVMergeIdx
< nSize
&&
231 (*mxLastRow
)[mnVMergeIdx
]->mnCellX
< xCellInfo
->mnCellX
)
234 if ( xCellInfo
->mnRowSpan
== 0 && mnVMergeIdx
< nSize
)
236 RTFCellInfoPtr
xLastCell( (*mxLastRow
)[mnVMergeIdx
] );
237 if (xLastCell
->mnRowSpan
)
238 xCellInfo
->mxVMergeCell
= std::move(xLastCell
);
240 xCellInfo
->mxVMergeCell
= xLastCell
->mxVMergeCell
;
244 if( !maRows
.empty() )
246 RTFColumnVectorPtr
xColumn( maRows
.back() );
247 if ( xCellInfo
->mxVMergeCell
)
249 if ( xColumn
->empty() ||
250 xColumn
->back()->mxVMergeCell
!= xCellInfo
->mxVMergeCell
)
251 xCellInfo
->mxVMergeCell
->mnRowSpan
++;
254 xColumn
->push_back( xCellInfo
);
257 mnStartPara
= pInfo
->aSelection
.end
.nPara
- 1;
260 void SdrTableRTFParser::InsertColumnEdge( sal_Int32 nEdge
)
262 auto aNextEdge
= std::lower_bound( maLastEdge
, maColumnEdges
.end(), nEdge
);
264 if ( aNextEdge
== maColumnEdges
.end() || nEdge
!= *aNextEdge
)
266 maLastEdge
= maColumnEdges
.insert( aNextEdge
, nEdge
);
271 void SdrTableRTFParser::FillTable()
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
)
280 xCols
->insertByIndex( nColCount
, nColMax
- nColCount
);
281 nColCount
= mxTable
->getColumnCount();
284 static constexpr OUStringLiteral
sWidth(u
"Width");
285 sal_Int32 nCol
, nLastEdge
= 0;
286 for( nCol
= 0; nCol
< nColCount
; nCol
++ )
288 Reference
< XPropertySet
> xSet( xCols
->getByIndex( nCol
), UNO_QUERY_THROW
);
289 sal_Int32 nWidth
= maColumnEdges
[nCol
] - nLastEdge
;
291 xSet
->setPropertyValue( sWidth
, Any( nWidth
) );
295 const sal_Int32 nRowCount
= mxTable
->getRowCount();
296 if( nRowCount
< mnRowCnt
)
298 Reference
< XTableRows
> xRows( mxTable
->getRows(), UNO_SET_THROW
);
299 xRows
->insertByIndex( nRowCount
, mnRowCnt
- nRowCount
);
302 for( sal_Int32 nRow
= 0; nRow
< static_cast<sal_Int32
>(maRows
.size()); nRow
++ )
304 RTFColumnVectorPtr
xColumn( maRows
[nRow
] );
306 auto aEdge
= maColumnEdges
.begin();
307 for( sal_Int32 nIdx
= 0; nCol
< nColMax
&& nIdx
< static_cast<sal_Int32
>(xColumn
->size()); nIdx
++ )
309 RTFCellInfoPtr
xCellInfo( (*xColumn
)[nIdx
] );
311 CellRef
xCell( mxTable
->getCell( nCol
, nRow
) );
312 if( xCell
.is() && xCellInfo
)
314 const SfxPoolItem
*pPoolItem
= nullptr;
315 if( xCellInfo
->maItemSet
.GetItemState(SDRATTR_TABLE_BORDER
,false,&pPoolItem
)==SfxItemState::SET
)
316 xCell
->SetMergedItem( *pPoolItem
);
318 std::optional
<OutlinerParaObject
> pTextObject(mpOutliner
->CreateParaObject( xCellInfo
->mnStartPara
, xCellInfo
->mnParaCount
));
321 SdrOutliner
& rOutliner
=mrTableObj
.ImpGetDrawOutliner();
322 rOutliner
.SetUpdateLayout(true);
323 rOutliner
.SetText( *pTextObject
);
324 mrTableObj
.NbcSetOutlinerParaObjectForText( rOutliner
.CreateParaObject(), xCell
.get() );
327 sal_Int32 nLastRow
= nRow
;
328 if ( xCellInfo
->mnRowSpan
)
329 nLastRow
+= xCellInfo
->mnRowSpan
- 1;
331 aEdge
= std::lower_bound( aEdge
, maColumnEdges
.end(), xCellInfo
->mnCellX
);
332 sal_Int32 nLastCol
= nCol
;
333 if ( aEdge
!= maColumnEdges
.end() )
335 nLastCol
= std::distance( maColumnEdges
.begin(), aEdge
);
339 if ( nLastCol
> nCol
|| nLastRow
> nRow
)
341 Reference
< XMergeableCellRange
> xRange( mxTable
->createCursorByRange( mxTable
->getCellRangeByPosition( nCol
, nRow
, nLastCol
, nLastRow
) ), UNO_QUERY_THROW
);
342 if( xRange
->isMergeable() )
350 tools::Rectangle
aRect( mrTableObj
.GetSnapRect() );
351 aRect
.SetRight( aRect
.Left() + nLastEdge
);
352 mrTableObj
.NbcSetSnapRect( aRect
);
357 TOOLS_WARN_EXCEPTION("svx", "");
361 void SdrTableRTFParser::NewCellRow()
367 maRows
.push_back( std::make_shared
<std::vector
<std::shared_ptr
<RTFCellInfo
>>>( ) );
369 mpDefMerge
= nullptr;
370 maDefaultIterator
= maDefaultList
.begin();
374 DBG_ASSERT( mpActDefault
, "NewCellRow: pActDefault==0" );
377 void SdrTableRTFParser::NextColumn()
379 if( maDefaultIterator
!= maDefaultList
.end() )
380 mpActDefault
= (*maDefaultIterator
++).get();
382 mpActDefault
= nullptr;
385 void SdrTableRTFParser::ProcToken( RtfImportInfo
* pInfo
)
387 switch ( pInfo
->nToken
)
389 case RTF_TROWD
: // denotes table row default, before RTF_CELLX
391 maDefaultList
.clear();
392 mpDefMerge
= nullptr;
393 mnLastToken
= pInfo
->nToken
;
394 maLastEdge
= maColumnEdges
.begin();
398 case RTF_CLMGF
: // The first cell of cells to be merged
400 mpDefMerge
= mpInsDefault
.get();
401 mnLastToken
= pInfo
->nToken
;
404 case RTF_CLMRG
: // A cell to be merged with the preceding cell
407 mpDefMerge
= maDefaultList
.back().get();
408 DBG_ASSERT( mpDefMerge
, "RTF_CLMRG: pDefMerge==0" );
410 mpDefMerge
->mnColSpan
++;
411 mpInsDefault
->mnColSpan
= 0;
412 mnLastToken
= pInfo
->nToken
;
417 mnLastToken
= pInfo
->nToken
;
422 mpInsDefault
->mnRowSpan
= 0;
423 mnLastToken
= pInfo
->nToken
;
426 case RTF_CELLX
: // closes cell default
429 std::shared_ptr
<RTFCellDefault
> pDefault( mpInsDefault
.release() );
430 maDefaultList
.push_back( pDefault
);
433 const sal_Int32 nSize
= convertTwipToMm100(pInfo
->nTokenValue
);
434 if ( nSize
> mnLastEdge
)
435 InsertColumnEdge( nSize
);
437 pDefault
->mnCellX
= nSize
;
438 // Record cellx in the first merged cell.
439 if ( mpDefMerge
&& pDefault
->mnColSpan
== 0 )
440 mpDefMerge
->mnCellX
= nSize
;
442 mpInsDefault
.reset( new RTFCellDefault( &mrItemPool
) );
444 mnLastToken
= pInfo
->nToken
;
447 case RTF_INTBL
: // before the first RTF_CELL
449 if ( mnLastToken
!= RTF_INTBL
&& mnLastToken
!= RTF_CELL
&& mnLastToken
!= RTF_PAR
)
452 mnLastToken
= pInfo
->nToken
;
456 case RTF_CELL
: // denotes the end of a cell.
458 DBG_ASSERT( mpActDefault
, "RTF_CELL: pActDefault==0" );
459 if ( mbNewDef
|| !mpActDefault
)
462 mpActDefault
= mpInsDefault
.get();
463 if ( mpActDefault
->mnColSpan
> 0 )
468 mnLastToken
= pInfo
->nToken
;
471 case RTF_ROW
: // means the end of a row
474 mnLastToken
= pInfo
->nToken
;
477 case RTF_PAR
: // Paragraph
478 mnLastToken
= pInfo
->nToken
;
481 { // do not set nLastToken
482 switch ( pInfo
->nToken
& ~(0xff | RTF_TABLEDEF
) )
485 // ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(pInfo->nToken, mpInsDefault->maItemSet, sal_True );
488 static_cast<SvxRTFParser
*>(pInfo
->pParser
)->ReadBorderAttr(pInfo
->nToken
, mpInsDefault
->maItemSet
, true );
495 void ImportAsRTF( SvStream
& rStream
, SdrTableObj
& rObj
)
497 SdrTableRTFParser
aParser( rObj
);
498 aParser
.Read( rStream
);
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */