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 <tools/UnitConversion.hxx>
29 #include <svtools/rtftoken.h>
30 
31 #include <svx/svdetc.hxx>
32 #include <editeng/outlobj.hxx>
33 
34 #include <cell.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 <tools/diagnose_ex.h>
45 
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;
50 
51 namespace sdr::table {
52 
53 namespace {
54 
55 struct RTFCellDefault
56 {
58  sal_Int32 mnRowSpan;
59  sal_Int32 mnColSpan; // MergeCell if >1, merged cells if 0
60  sal_Int32 mnCellX;
61 
62  explicit RTFCellDefault( SfxItemPool* pPool ) : maItemSet( *pPool ), mnRowSpan(1), mnColSpan(1), mnCellX(0) {}
63 };
64 
65 }
66 
67 typedef std::vector< std::shared_ptr< RTFCellDefault > > RTFCellDefaultVector;
68 
69 namespace {
70 
71 struct RTFCellInfo
72 {
74  sal_Int32 mnStartPara;
75  sal_Int32 mnParaCount;
76  sal_Int32 mnCellX;
77  sal_Int32 mnRowSpan;
78  std::shared_ptr< RTFCellInfo > mxVMergeCell;
79 
80  explicit RTFCellInfo( SfxItemPool& rPool ) : maItemSet( rPool ), mnStartPara(0), mnParaCount(0), mnCellX(0), mnRowSpan(1) {}
81 };
82 
83 }
84 
85 typedef std::shared_ptr< RTFCellInfo > RTFCellInfoPtr;
86 typedef std::vector< RTFCellInfoPtr > RTFColumnVector;
87 
88 typedef std::shared_ptr< RTFColumnVector > RTFColumnVectorPtr;
89 
91 {
92 public:
93  explicit SdrTableRTFParser( SdrTableObj& rTableObj );
94 
95  void Read( SvStream& rStream );
96 
97  void ProcToken( RtfImportInfo* pInfo );
98 
99  void NextRow();
100  void NextColumn();
101  void NewCellRow();
102 
103  void InsertCell( RtfImportInfo const * pInfo );
104  void InsertColumnEdge( sal_Int32 nEdge );
105 
106  void FillTable();
107 
108  DECL_LINK( RTFImportHdl, RtfImportInfo&, void );
109 
110 private:
112  std::unique_ptr<SdrOutliner> mpOutliner;
114 
115  RTFCellDefaultVector maDefaultList;
116  RTFCellDefaultVector::iterator maDefaultIterator;
117 
119  bool mbNewDef;
120 
121  sal_Int32 mnStartPara;
122 
123  sal_Int32 mnRowCnt;
124  sal_Int32 mnLastEdge;
125  sal_Int32 mnVMergeIdx;
126 
127  std::vector< sal_Int32 > maColumnEdges;
128  std::vector< sal_Int32 >::iterator maLastEdge;
129  std::vector< RTFColumnVectorPtr > maRows;
130 
131  std::unique_ptr<RTFCellDefault> mpInsDefault;
132  RTFCellDefault* mpActDefault;
133  RTFCellDefault* mpDefMerge;
134 
135  Reference< XTable > mxTable;
136 
137  RTFColumnVectorPtr mxLastRow;
138  // Copy assignment is forbidden and not implemented.
139  SdrTableRTFParser (const SdrTableRTFParser &) = delete;
140  SdrTableRTFParser & operator= (const SdrTableRTFParser &) = delete;
141 };
142 
144 : mrTableObj( rTableObj )
145 , mpOutliner( SdrMakeOutliner( OutlinerMode::TextObject, rTableObj.getSdrModelFromSdrObject() ) )
146 , mrItemPool( rTableObj.getSdrModelFromSdrObject().GetItemPool() )
147 , mnLastToken( 0 )
148 , mbNewDef( false )
149 , mnStartPara( 0 )
150 , mnRowCnt( 0 )
151 , mnLastEdge( 0 )
152 , mnVMergeIdx ( 0 )
153 , mpActDefault( nullptr )
154 , mpDefMerge( nullptr )
155 , mxTable( rTableObj.getTable() )
156 {
157  mpOutliner->SetUpdateLayout(true);
158  mpOutliner->SetStyleSheet( 0, mrTableObj.GetStyleSheet() );
159  mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
160 }
161 
163 {
164  EditEngine& rEdit = const_cast< EditEngine& >( mpOutliner->GetEditEngine() );
165 
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 );
170 
171  FillTable();
172 }
173 
174 IMPL_LINK( SdrTableRTFParser, RTFImportHdl, RtfImportInfo&, rInfo, void )
175 {
176  switch ( rInfo.eState )
177  {
178  case RtfImportState::NextToken:
179  ProcToken( &rInfo );
180  break;
181  case RtfImportState::UnknownAttr:
182  ProcToken( &rInfo );
183  break;
184  case RtfImportState::Start:
185  {
186  SvxRTFParser* pParser = static_cast<SvxRTFParser*>(rInfo.pParser);
187  pParser->SetAttrPool( &mrItemPool );
188  pParser->SetPardMap(SID_ATTR_BORDER_OUTER, 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 = std::make_shared<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  static const OUStringLiteral sWidth(u"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 )
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::optional<OutlinerParaObject> pTextObject(mpOutliner->CreateParaObject( xCellInfo->mnStartPara, xCellInfo->mnParaCount ));
319  if( pTextObject )
320  {
322  rOutliner.SetUpdateLayout(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  TOOLS_WARN_EXCEPTION("svx", "");
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 
386 {
387  switch ( pInfo->nToken )
388  {
389  case RTF_TROWD: // denotes table row default, before RTF_CELLX
390  {
391  maDefaultList.clear();
392  mpDefMerge = nullptr;
393  mnLastToken = pInfo->nToken;
394  maLastEdge = maColumnEdges.begin();
395  mnLastEdge = 0;
396  }
397  break;
398  case RTF_CLMGF: // The first cell of cells to be merged
399  {
400  mpDefMerge = mpInsDefault.get();
401  mnLastToken = pInfo->nToken;
402  }
403  break;
404  case RTF_CLMRG: // A cell to be merged with the preceding cell
405  {
406  if ( !mpDefMerge )
407  mpDefMerge = maDefaultList.back().get();
408  DBG_ASSERT( mpDefMerge, "RTF_CLMRG: pDefMerge==0" );
409  if( mpDefMerge )
410  mpDefMerge->mnColSpan++;
411  mpInsDefault->mnColSpan = 0;
412  mnLastToken = pInfo->nToken;
413  }
414  break;
415  case RTF_CLVMGF:
416  {
417  mnLastToken = pInfo->nToken;
418  }
419  break;
420  case RTF_CLVMRG:
421  {
422  mpInsDefault->mnRowSpan = 0;
423  mnLastToken = pInfo->nToken;
424  }
425  break;
426  case RTF_CELLX: // closes cell default
427  {
428  mbNewDef = true;
429  std::shared_ptr<RTFCellDefault> pDefault( mpInsDefault.release() );
430  maDefaultList.push_back( pDefault );
431 
432 
433  const sal_Int32 nSize = convertTwipToMm100(pInfo->nTokenValue);
434  if ( nSize > mnLastEdge )
435  InsertColumnEdge( nSize );
436 
437  pDefault->mnCellX = nSize;
438  // Record cellx in the first merged cell.
439  if ( mpDefMerge && pDefault->mnColSpan == 0 )
440  mpDefMerge->mnCellX = nSize;
441 
442  mpInsDefault.reset( new RTFCellDefault( &mrItemPool ) );
443 
444  mnLastToken = pInfo->nToken;
445  }
446  break;
447  case RTF_INTBL: // before the first RTF_CELL
448  {
450  {
451  NewCellRow();
452  mnLastToken = pInfo->nToken;
453  }
454  }
455  break;
456  case RTF_CELL: // denotes the end of a cell.
457  {
458  DBG_ASSERT( mpActDefault, "RTF_CELL: pActDefault==0" );
459  if ( mbNewDef || !mpActDefault )
460  NewCellRow();
461  if ( !mpActDefault )
462  mpActDefault = mpInsDefault.get();
463  if ( mpActDefault->mnColSpan > 0 )
464  {
465  InsertCell(pInfo);
466  }
467  NextColumn();
468  mnLastToken = pInfo->nToken;
469  }
470  break;
471  case RTF_ROW: // means the end of a row
472  {
473  NextRow();
474  mnLastToken = pInfo->nToken;
475  }
476  break;
477  case RTF_PAR: // Paragraph
478  mnLastToken = pInfo->nToken;
479  break;
480  default:
481  { // do not set nLastToken
482  switch ( pInfo->nToken & ~(0xff | RTF_TABLEDEF) )
483  {
484  case RTF_SHADINGDEF:
485 // ((SvxRTFParser*)pInfo->pParser)->ReadBackgroundAttr(pInfo->nToken, mpInsDefault->maItemSet, sal_True );
486  break;
487  case RTF_BRDRDEF:
488  static_cast<SvxRTFParser*>(pInfo->pParser)->ReadBorderAttr(pInfo->nToken, mpInsDefault->maItemSet, true );
489  break;
490  }
491  }
492  }
493 }
494 
495 void ImportAsRTF( SvStream& rStream, SdrTableObj& rObj )
496 {
497  SdrTableRTFParser aParser( rObj );
498  aParser.Read( rStream );
499 }
500 
501 }
502 
503 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OutlinerMode
RTF_CLMGF
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
constexpr auto convertTwipToMm100(N n)
RTFCellDefaultVector maDefaultList
sal_Int32 mnColSpan
virtual const tools::Rectangle & GetSnapRect() const override
Definition: svdotable.cxx:1785
virtual void NbcSetSnapRect(const tools::Rectangle &rRect) override
Definition: svdotable.cxx:1791
SfxStyleSheet * GetStyleSheet() const
Definition: svdobj.cxx:2225
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)
void NbcSetOutlinerParaObjectForText(std::optional< OutlinerParaObject > pTextObject, SdrText *pText)
Definition: svdotext.cxx:1344
SdrTableRTFParser & operator=(const SdrTableRTFParser &)=delete
sal_Int32 nEndPara
#define TOOLS_WARN_EXCEPTION(area, stream)
void SetText(const OutlinerParaObject &)
#define DBG_ASSERT(sCon, aError)
std::vector< std::shared_ptr< RTFCellDefault > > RTFCellDefaultVector
RTF_BRDRDEF
const Link< RtfImportInfo &, void > & GetRtfImportHdl() const
float u
void SetPardMap(sal_uInt16 wid, sal_uInt16 widTrue)
constexpr void SetRight(tools::Long v)
std::optional< OutlinerParaObject > CreateParaObject(sal_Int32 nStartPara=0, sal_Int32 nParaCount=EE_PARA_ALL) const
SvParser< int > * pParser
RTFCellDefaultVector::iterator maDefaultIterator
RTF_CELLX
std::vector< RTFColumnVectorPtr > maRows
constexpr TypedWhichId< SvxBoxItem > SDRATTR_TABLE_BORDER(SDRATTR_TABLE_FIRST+0)
sal_Int32 mnRowSpan
weld::Entry & rEdit
RTF_TABLEDEF
std::unique_ptr< RTFCellDefault > mpInsDefault
SdrTableRTFParser(SdrTableObj &rTableObj)
std::unique_ptr< SdrOutliner > SdrMakeOutliner(OutlinerMode nOutlinerMode, SdrModel &rModel)
Create an Outliner with the engine-global default settings on the heap.
Definition: svdetc.cxx:333
std::vector< RTFCellInfoPtr > RTFColumnVector
bool SetUpdateLayout(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:1164
void ProcToken(RtfImportInfo *pInfo)
std::vector< sal_Int32 > maColumnEdges
void InsertColumnEdge(sal_Int32 nEdge)