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