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