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 <svtools/rtftoken.h>
30 #include <editeng/eeitem.hxx>
31 #include <svx/svdetc.hxx>
32 #include <editeng/fhgtitem.hxx>
33 #include <editeng/outlobj.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
{
56 sal_Int32 mnColSpan
; // MergeCell if >1, merged cells if 0
59 explicit RTFCellDefault( SfxItemPool
* pPool
) : maItemSet( *pPool
), mnRowSpan(1), mnColSpan(1), mnCellX(0) {}
62 typedef std::vector
< std::shared_ptr
< RTFCellDefault
> > RTFCellDefaultVector
;
66 SfxItemSet
const maItemSet
;
67 sal_Int32 mnStartPara
;
68 sal_Int32 mnParaCount
;
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
84 explicit SdrTableRTFParser( SdrTableObj
& rTableObj
);
86 void Read( SvStream
& rStream
);
88 void ProcToken( RtfImportInfo
* pInfo
);
94 void InsertCell( RtfImportInfo
const * pInfo
);
95 void InsertColumnEdge( sal_Int32 nEdge
);
99 DECL_LINK( RTFImportHdl
, RtfImportInfo
&, void );
102 SdrTableObj
& mrTableObj
;
103 std::unique_ptr
<SdrOutliner
> mpOutliner
;
104 SfxItemPool
& mrItemPool
;
106 RTFCellDefaultVector maDefaultList
;
107 RTFCellDefaultVector::iterator maDefaultIterator
;
112 sal_Int32 mnStartPara
;
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() )
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
);
165 IMPL_LINK( SdrTableRTFParser
, RTFImportHdl
, RtfImportInfo
&, rInfo
, void )
167 switch ( rInfo
.eState
)
169 case RtfImportState::NextToken
:
172 case RtfImportState::UnknownAttr
:
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
;
183 case RtfImportState::End
:
184 if ( rInfo
.aSelection
.nEndPos
)
186 mpActDefault
= nullptr;
187 rInfo
.nToken
= RTF_PAR
;
188 rInfo
.aSelection
.nEndPara
++;
192 case RtfImportState::SetAttr
:
193 case RtfImportState::InsertText
:
194 case RtfImportState::InsertPara
:
197 SAL_WARN( "svx.table","unknown ImportInfo.eState");
201 void SdrTableRTFParser::NextRow()
203 mxLastRow
= maRows
.back();
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
)
226 if ( xCellInfo
->mnRowSpan
== 0 && mnVMergeIdx
< nSize
)
228 RTFCellInfoPtr
xLastCell( (*mxLastRow
)[mnVMergeIdx
] );
229 if (xLastCell
->mnRowSpan
)
230 xCellInfo
->mxVMergeCell
= xLastCell
;
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
);
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
) );
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
] );
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
));
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
);
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() )
342 tools::Rectangle
aRect( mrTableObj
.GetSnapRect() );
343 aRect
.SetRight( aRect
.Left() + nLastEdge
);
344 mrTableObj
.NbcSetSnapRect( aRect
);
349 OSL_FAIL("sdr::table::SdrTableRTFParser::InsertCell(), exception caught!" );
353 void SdrTableRTFParser::NewCellRow()
359 maRows
.push_back( std::make_shared
<std::vector
<std::shared_ptr
<RTFCellInfo
>>>( ) );
361 mpDefMerge
= nullptr;
362 maDefaultIterator
= maDefaultList
.begin();
366 DBG_ASSERT( mpActDefault
, "NewCellRow: pActDefault==0" );
369 void SdrTableRTFParser::NextColumn()
371 if( maDefaultIterator
!= maDefaultList
.end() )
372 mpActDefault
= (*maDefaultIterator
++).get();
374 mpActDefault
= nullptr;
377 static long TwipsToHundMM( long nIn
)
379 long nRet
= OutputDevice::LogicToLogic( nIn
, MapUnit::MapTwip
, MapUnit::Map100thMM
);
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();
396 case RTF_CLMGF
: // The first cell of cells to be merged
398 mpDefMerge
= mpInsDefault
.get();
399 mnLastToken
= pInfo
->nToken
;
402 case RTF_CLMRG
: // A cell to be merged with the preceding cell
405 mpDefMerge
= maDefaultList
.back().get();
406 DBG_ASSERT( mpDefMerge
, "RTF_CLMRG: pDefMerge==0" );
408 mpDefMerge
->mnColSpan
++;
409 mpInsDefault
->mnColSpan
= 0;
410 mnLastToken
= pInfo
->nToken
;
415 mnLastToken
= pInfo
->nToken
;
420 mpInsDefault
->mnRowSpan
= 0;
421 mnLastToken
= pInfo
->nToken
;
424 case RTF_CELLX
: // closes cell default
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
;
445 case RTF_INTBL
: // before the first RTF_CELL
447 if ( mnLastToken
!= RTF_INTBL
&& mnLastToken
!= RTF_CELL
&& mnLastToken
!= RTF_PAR
)
450 mnLastToken
= pInfo
->nToken
;
454 case RTF_CELL
: // denotes the end of a cell.
456 DBG_ASSERT( mpActDefault
, "RTF_CELL: pActDefault==0" );
457 if ( mbNewDef
|| !mpActDefault
)
460 mpActDefault
= mpInsDefault
.get();
461 if ( mpActDefault
->mnColSpan
> 0 )
466 mnLastToken
= pInfo
->nToken
;
469 case RTF_ROW
: // means the end of a row
472 mnLastToken
= pInfo
->nToken
;
475 case RTF_PAR
: // Paragraph
476 mnLastToken
= pInfo
->nToken
;
479 { // do not set nLastToken
480 switch ( pInfo
->nToken
& ~(0xff | RTF_TABLEDEF
) )
483 // ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(pInfo->nToken, mpInsDefault->maItemSet, sal_True );
486 static_cast<SvxRTFParser
*>(pInfo
->pParser
)->ReadBorderAttr(pInfo
->nToken
, mpInsDefault
->maItemSet
, true );
493 void SdrTableObj::ImportAsRTF( SvStream
& rStream
, SdrTableObj
& rObj
)
495 SdrTableRTFParser
aParser( rObj
);
496 aParser
.Read( rStream
);
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */