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 <editeng/eeitem.hxx>
31 #include <svx/svdetc.hxx>
32 #include <editeng/fhgtitem.hxx>
33 #include <editeng/outlobj.hxx>
34 
35 #include <cell.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>
44 
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;
49 
50 namespace sdr { namespace table {
51 
52 namespace {
53 
54 struct RTFCellDefault
55 {
57  sal_Int32 mnRowSpan;
58  sal_Int32 mnColSpan; // MergeCell if >1, merged cells if 0
59  sal_Int32 mnCellX;
60 
61  explicit RTFCellDefault( SfxItemPool* pPool ) : maItemSet( *pPool ), mnRowSpan(1), mnColSpan(1), mnCellX(0) {}
62 };
63 
64 }
65 
66 typedef std::vector< std::shared_ptr< RTFCellDefault > > RTFCellDefaultVector;
67 
68 namespace {
69 
70 struct RTFCellInfo
71 {
72  SfxItemSet const maItemSet;
73  sal_Int32 mnStartPara;
74  sal_Int32 mnParaCount;
75  sal_Int32 mnCellX;
76  sal_Int32 mnRowSpan;
77  std::shared_ptr< RTFCellInfo > mxVMergeCell;
78 
79  explicit RTFCellInfo( SfxItemPool& rPool ) : maItemSet( rPool ), mnStartPara(0), mnParaCount(0), mnCellX(0), mnRowSpan(1) {}
80 };
81 
82 }
83 
84 typedef std::shared_ptr< RTFCellInfo > RTFCellInfoPtr;
85 typedef std::vector< RTFCellInfoPtr > RTFColumnVector;
86 
87 typedef std::shared_ptr< RTFColumnVector > RTFColumnVectorPtr;
88 
90 {
91 public:
92  explicit SdrTableRTFParser( SdrTableObj& rTableObj );
93 
94  void Read( SvStream& rStream );
95 
96  void ProcToken( RtfImportInfo* pInfo );
97 
98  void NextRow();
99  void NextColumn();
100  void NewCellRow();
101 
102  void InsertCell( RtfImportInfo const * pInfo );
103  void InsertColumnEdge( sal_Int32 nEdge );
104 
105  void FillTable();
106 
107  DECL_LINK( RTFImportHdl, RtfImportInfo&, void );
108 
109 private:
111  std::unique_ptr<SdrOutliner> mpOutliner;
113 
114  RTFCellDefaultVector maDefaultList;
115  RTFCellDefaultVector::iterator maDefaultIterator;
116 
118  bool mbNewDef;
119 
120  sal_Int32 mnStartPara;
121 
122  sal_Int32 mnRowCnt;
123  sal_Int32 mnLastEdge;
124  sal_Int32 mnVMergeIdx;
125 
126  std::vector< sal_Int32 > maColumnEdges;
127  std::vector< sal_Int32 >::iterator maLastEdge;
128  std::vector< RTFColumnVectorPtr > maRows;
129 
130  std::unique_ptr<RTFCellDefault> mpInsDefault;
131  RTFCellDefault* mpActDefault;
132  RTFCellDefault* mpDefMerge;
133 
134  Reference< XTable > mxTable;
135 
136  RTFColumnVectorPtr mxLastRow;
137  // Copy assignment is forbidden and not implemented.
138  SdrTableRTFParser (const SdrTableRTFParser &) = delete;
139  SdrTableRTFParser & operator= (const SdrTableRTFParser &) = delete;
140 };
141 
143 : mrTableObj( rTableObj )
144 , mpOutliner( SdrMakeOutliner( OutlinerMode::TextObject, rTableObj.getSdrModelFromSdrObject() ) )
145 , mrItemPool( rTableObj.getSdrModelFromSdrObject().GetItemPool() )
146 , mnLastToken( 0 )
147 , mbNewDef( false )
148 , mnStartPara( 0 )
149 , mnRowCnt( 0 )
150 , mnLastEdge( 0 )
151 , mnVMergeIdx ( 0 )
152 , mpActDefault( nullptr )
153 , mpDefMerge( nullptr )
154 , mxTable( rTableObj.getTable() )
155 {
156  mpOutliner->SetUpdateMode(true);
157  mpOutliner->SetStyleSheet( 0, mrTableObj.GetStyleSheet() );
158  mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
159 }
160 
162 {
163  EditEngine& rEdit = const_cast< EditEngine& >( mpOutliner->GetEditEngine() );
164 
165  Link<RtfImportInfo&,void> aOldLink( rEdit.GetRtfImportHdl() );
166  rEdit.SetRtfImportHdl( LINK( this, SdrTableRTFParser, RTFImportHdl ) );
167  mpOutliner->Read( rStream, OUString(), EETextFormat::Rtf );
168  rEdit.SetRtfImportHdl( aOldLink );
169 
170  FillTable();
171 }
172 
173 IMPL_LINK( SdrTableRTFParser, RTFImportHdl, RtfImportInfo&, rInfo, void )
174 {
175  switch ( rInfo.eState )
176  {
177  case RtfImportState::NextToken:
178  ProcToken( &rInfo );
179  break;
180  case RtfImportState::UnknownAttr:
181  ProcToken( &rInfo );
182  break;
183  case RtfImportState::Start:
184  {
185  SvxRTFParser* pParser = static_cast<SvxRTFParser*>(rInfo.pParser);
186  pParser->SetAttrPool( &mrItemPool );
187  RTFPardAttrMapIds& rMap = pParser->GetPardMap();
188  rMap.nBox = 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( new 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  {
246  RTFColumnVectorPtr xColumn( maRows.back() );
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 
260 void SdrTableRTFParser::InsertColumnEdge( sal_Int32 nEdge )
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  const OUString sWidth("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  {
304  RTFColumnVectorPtr xColumn( maRows[nRow] );
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.get() )
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::unique_ptr<OutlinerParaObject> pTextObject(mpOutliner->CreateParaObject( xCellInfo->mnStartPara, xCellInfo->mnParaCount ));
319  if( pTextObject )
320  {
322  rOutliner.SetUpdateMode(true);
323  rOutliner.SetText( *pTextObject );
324  mrTableObj.NbcSetOutlinerParaObjectForText( rOutliner.CreateParaObject(), xCell.get() );
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  OSL_FAIL("sdr::table::SdrTableRTFParser::InsertCell(), exception caught!" );
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() )
380  mpActDefault = (*maDefaultIterator++).get();
381  else
382  mpActDefault = nullptr;
383 }
384 
385 static long TwipsToHundMM( long nIn )
386 {
387  long nRet = OutputDevice::LogicToLogic( nIn, MapUnit::MapTwip, MapUnit::Map100thMM );
388  return nRet;
389 }
390 
392 {
393  switch ( pInfo->nToken )
394  {
395  case RTF_TROWD: // denotes table row default, before RTF_CELLX
396  {
397  maDefaultList.clear();
398  mpDefMerge = nullptr;
399  mnLastToken = pInfo->nToken;
400  maLastEdge = maColumnEdges.begin();
401  mnLastEdge = 0;
402  }
403  break;
404  case RTF_CLMGF: // The first cell of cells to be merged
405  {
406  mpDefMerge = mpInsDefault.get();
407  mnLastToken = pInfo->nToken;
408  }
409  break;
410  case RTF_CLMRG: // A cell to be merged with the preceding cell
411  {
412  if ( !mpDefMerge )
413  mpDefMerge = maDefaultList.back().get();
414  DBG_ASSERT( mpDefMerge, "RTF_CLMRG: pDefMerge==0" );
415  if( mpDefMerge )
416  mpDefMerge->mnColSpan++;
417  mpInsDefault->mnColSpan = 0;
418  mnLastToken = pInfo->nToken;
419  }
420  break;
421  case RTF_CLVMGF:
422  {
423  mnLastToken = pInfo->nToken;
424  }
425  break;
426  case RTF_CLVMRG:
427  {
428  mpInsDefault->mnRowSpan = 0;
429  mnLastToken = pInfo->nToken;
430  }
431  break;
432  case RTF_CELLX: // closes cell default
433  {
434  mbNewDef = true;
435  std::shared_ptr<RTFCellDefault> pDefault( mpInsDefault.release() );
436  maDefaultList.push_back( pDefault );
437 
438 
439  const sal_Int32 nSize = TwipsToHundMM( pInfo->nTokenValue );
440  if ( nSize > mnLastEdge )
441  InsertColumnEdge( nSize );
442 
443  pDefault->mnCellX = nSize;
444  // Record cellx in the first merged cell.
445  if ( mpDefMerge && pDefault->mnColSpan == 0 )
446  mpDefMerge->mnCellX = nSize;
447 
448  mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
449 
450  mnLastToken = pInfo->nToken;
451  }
452  break;
453  case RTF_INTBL: // before the first RTF_CELL
454  {
456  {
457  NewCellRow();
458  mnLastToken = pInfo->nToken;
459  }
460  }
461  break;
462  case RTF_CELL: // denotes the end of a cell.
463  {
464  DBG_ASSERT( mpActDefault, "RTF_CELL: pActDefault==0" );
465  if ( mbNewDef || !mpActDefault )
466  NewCellRow();
467  if ( !mpActDefault )
468  mpActDefault = mpInsDefault.get();
469  if ( mpActDefault->mnColSpan > 0 )
470  {
471  InsertCell(pInfo);
472  }
473  NextColumn();
474  mnLastToken = pInfo->nToken;
475  }
476  break;
477  case RTF_ROW: // means the end of a row
478  {
479  NextRow();
480  mnLastToken = pInfo->nToken;
481  }
482  break;
483  case RTF_PAR: // Paragraph
484  mnLastToken = pInfo->nToken;
485  break;
486  default:
487  { // do not set nLastToken
488  switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
489  {
490  case RTF_SHADINGDEF:
491 // ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(pInfo->nToken, mpInsDefault->maItemSet, sal_True );
492  break;
493  case RTF_BRDRDEF:
494  static_cast<SvxRTFParser*>(pInfo->pParser)->ReadBorderAttr(pInfo->nToken, mpInsDefault->maItemSet, true );
495  break;
496  }
497  }
498  }
499 }
500 
502 {
503  SdrTableRTFParser aParser( rObj );
504  aParser.Read( rStream );
505 }
506 
507 } }
508 
509 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const int nColCount
OutlinerMode
#define SDRATTR_TABLE_BORDER
Definition: svddef.hxx:399
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:1795
virtual void NbcSetSnapRect(const tools::Rectangle &rRect) override
Definition: svdotable.cxx:1801
SfxStyleSheet * GetStyleSheet() const
Definition: svdobj.cxx:2162
std::shared_ptr< RTFColumnVector > RTFColumnVectorPtr
IMPL_LINK(SdrTableRTFParser, RTFImportHdl, RtfImportInfo &, rInfo, void)
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: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:338
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 void ImportAsRTF(SvStream &rStrm, SdrTableObj &rObj)
static long TwipsToHundMM(long nIn)
SfxItemSet maItemSet
RTF_SHADINGDEF
SdrOutliner & ImpGetDrawOutliner() const
Definition: svdotext.cxx:1152
void ProcToken(RtfImportInfo *pInfo)
std::vector< sal_Int32 > maColumnEdges
void InsertColumnEdge(sal_Int32 nEdge)