LibreOffice Module sw (master)  1
node2lay.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 #include <calbck.hxx>
21 #include <node.hxx>
22 #include <ndindex.hxx>
23 #include <swtable.hxx>
24 #include <ftnfrm.hxx>
25 #include <sectfrm.hxx>
26 #include <frmfmt.hxx>
27 #include <cntfrm.hxx>
28 #include <tabfrm.hxx>
29 #include <frmtool.hxx>
30 #include <section.hxx>
31 #include <node2lay.hxx>
32 
38 {
39  std::unique_ptr<SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti>> pIter;
41  std::vector<SwFrame*> mvUpperFrames; // To collect the Upper
42  sal_uLong const nIndex; // The Index of the to-be-inserted Nodes
43  bool bMaster : 1; // true => only Master, false => only Frames without Follow
44  bool bInit : 1; // Did we already call First() at SwClient?
45 
46  SwNode2LayImpl(const SwNode2LayImpl&) = delete;
47  SwNode2LayImpl& operator=(const SwNode2LayImpl&) = delete;
48 
49 public:
50  SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, bool bSearch );
51  SwFrame* NextFrame(); // Returns the next "useful" Frame
52  SwLayoutFrame* UpperFrame( SwFrame* &rpFrame, const SwNode &rNode );
53  void SaveUpperFrames(); // Saves (and locks if needed) the pUpper
54  // Inserts a Frame under every pUpper of the array
55  void RestoreUpperFrames( SwNodes& rNds, sal_uLong nStt, sal_uLong nEnd );
56 
57  SwFrame* GetFrame( const Point* pDocPos ) const;
58 };
59 
60 static SwNode* GoNextWithFrame(const SwNodes& rNodes, SwNodeIndex *pIdx)
61 {
62  if( pIdx->GetIndex() >= rNodes.Count() - 1 )
63  return nullptr;
64 
65  SwNodeIndex aTmp(*pIdx, +1);
66  SwNode* pNd = nullptr;
67  while( aTmp < rNodes.Count()-1 )
68  {
69  pNd = &aTmp.GetNode();
70  bool bFound = false;
71  if ( pNd->IsContentNode() )
72  // sw_redlinehide: assume that it's OK to find a node with the same
73  // frame as the caller's one
74  bFound = SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*static_cast<SwContentNode*>(pNd)).First();
75  else if ( pNd->IsTableNode() )
76  bFound = SwIterator<SwFrame,SwFormat>(*static_cast<SwTableNode*>(pNd)->GetTable().GetFrameFormat()).First() ;
77  else if( pNd->IsEndNode() && !pNd->StartOfSectionNode()->IsSectionNode() )
78  {
79  pNd = nullptr;
80  break;
81  }
82  if ( bFound )
83  break;
84  ++aTmp;
85  }
86 
87  if( aTmp == rNodes.Count()-1 )
88  pNd = nullptr;
89  else if( pNd )
90  (*pIdx) = aTmp;
91  return pNd;
92 }
93 
95 {
96  if( !pIdx->GetIndex() )
97  return nullptr;
98 
99  SwNodeIndex aTmp( *pIdx, -1 );
100  SwNode* pNd(nullptr);
101  while( aTmp.GetIndex() )
102  {
103  pNd = &aTmp.GetNode();
104  bool bFound = false;
105  if ( pNd->IsContentNode() )
106  // sw_redlinehide: assume that it's OK to find a node with the same
107  // frame as the caller's one
108  bFound = SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*static_cast<SwContentNode*>(pNd)).First();
109  else if ( pNd->IsTableNode() )
110  bFound = SwIterator<SwFrame,SwFormat>(*static_cast<SwTableNode*>(pNd)->GetTable().GetFrameFormat()).First();
111  else if( pNd->IsStartNode() && !pNd->IsSectionNode() )
112  {
113  pNd = nullptr;
114  break;
115  }
116  if ( bFound )
117  break;
118  --aTmp;
119  }
120 
121  if( !aTmp.GetIndex() )
122  pNd = nullptr;
123  else if( pNd )
124  (*pIdx) = aTmp;
125  return pNd;
126 }
127 
137 SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, bool bSearch )
138  : nIndex( nIdx ), bInit( false )
139 {
140  const SwNode* pNd;
141  if( bSearch || rNode.IsSectionNode() )
142  {
143  // Find the next Content/TableNode that contains a Frame, so that we can add
144  // ourselves before/after it
145  if( !bSearch && rNode.GetIndex() < nIndex )
146  {
147  SwNodeIndex aTmp( *rNode.EndOfSectionNode(), +1 );
148  pNd = GoPreviousWithFrame( &aTmp );
149  if( pNd && rNode.GetIndex() > pNd->GetIndex() )
150  pNd = nullptr; // Do not go over the limits
151  bMaster = false;
152  }
153  else
154  {
155  SwNodeIndex aTmp( rNode, -1 );
156  pNd = GoNextWithFrame( rNode.GetNodes(), &aTmp );
157  bMaster = true;
158  if( !bSearch && pNd && rNode.EndOfSectionIndex() < pNd->GetIndex() )
159  pNd = nullptr; // Do not go over the limits
160  }
161  }
162  else
163  {
164  pNd = &rNode;
165  bMaster = nIndex < rNode.GetIndex();
166  }
167  if( pNd )
168  {
169  if( pNd->IsContentNode() )
170  pMod = const_cast<SwModify*>(static_cast<SwModify const *>(pNd->GetContentNode()));
171  else
172  {
173  assert(pNd->IsTableNode());
175  }
177  }
178  else
179  {
180  pIter = nullptr;
181  pMod = nullptr;
182  }
183 }
184 
200 {
201  SwFrame* pRet;
202  if( !pIter )
203  return nullptr;
204  if( !bInit )
205  {
206  pRet = pIter->First();
207  bInit = true;
208  }
209  else
210  pRet = pIter->Next();
211  while( pRet )
212  {
213  SwFlowFrame* pFlow = SwFlowFrame::CastFlowFrame( pRet );
214  assert(pFlow);
215  // Follows are pretty volatile, thus we ignore them.
216  // Even if we insert after the Frame, we start from the Master
217  // and iterate through it until the last Follow
218  if( !pFlow->IsFollow() )
219  {
220  if( !bMaster )
221  {
222  while( pFlow->HasFollow() )
223  pFlow = pFlow->GetFollow();
224  pRet = &(pFlow->GetFrame());
225  }
226  if( pRet->IsInSct() )
227  {
228  SwSectionFrame* pSct = pRet->FindSctFrame();
229  // ATTENTION: If we are in a Footnote, from a Layout point of view
230  // it could be located in a Section with columns, although it
231  // should be outside of it when looking at the Nodes.
232  // Thus, when dealing with Footnotes, we need to check whether the
233  // SectionFrame is also located within the Footnote and not outside of it.
234  if( !pRet->IsInFootnote() || pSct->IsInFootnote() )
235  {
236  assert(pSct && pSct->GetSection());
237  SwSectionNode* pNd = pSct->GetSection()->GetFormat()->GetSectionNode();
238  assert(pNd);
239  // If the result Frame is located within a Section Frame
240  // whose Section does not contain the Node, we return with
241  // the SectionFrame, else we return with the Content/TabFrame
242  if( bMaster )
243  {
244  if( pNd->GetIndex() >= nIndex )
245  pRet = pSct;
246  }
247  else if( pNd->EndOfSectionIndex() < nIndex )
248  pRet = pSct;
249  }
250  }
251  return pRet;
252  }
253  pRet = pIter->Next();
254  }
255  return nullptr;
256 }
257 
259 {
260  SwFrame* pFrame;
261  while( nullptr != (pFrame = NextFrame()) )
262  {
263  SwFrame* pPrv = pFrame->GetPrev();
264  pFrame = pFrame->GetUpper();
265  if( pFrame )
266  {
267  if( pFrame->IsFootnoteFrame() )
268  static_cast<SwFootnoteFrame*>(pFrame)->ColLock();
269  else if( pFrame->IsInSct() )
270  pFrame->FindSctFrame()->ColLock();
271  if( pPrv && pPrv->IsSctFrame() )
272  static_cast<SwSectionFrame*>(pPrv)->LockJoin();
273  mvUpperFrames.push_back( pPrv );
274  mvUpperFrames.push_back( pFrame );
275  }
276  }
277  pIter.reset();
278  pMod = nullptr;
279 }
280 
282 {
283  rpFrame = NextFrame();
284  if( !rpFrame )
285  return nullptr;
286  SwLayoutFrame* pUpper = rpFrame->GetUpper();
287  if( rpFrame->IsSctFrame() )
288  {
289  const SwNode* pNode = rNode.StartOfSectionNode();
290  if( pNode->IsSectionNode() )
291  {
292  SwFrame* pFrame = bMaster ? rpFrame->FindPrev() : rpFrame->FindNext();
293  if( pFrame && pFrame->IsSctFrame() )
294  {
295  // pFrame could be a "dummy"-section
296  if( static_cast<SwSectionFrame*>(pFrame)->GetSection() &&
297  (&static_cast<const SwSectionNode*>(pNode)->GetSection() ==
298  static_cast<SwSectionFrame*>(pFrame)->GetSection()) )
299  {
300  // #i22922# - consider columned sections
301  // 'Go down' the section frame as long as the layout frame
302  // is found, which would contain content.
303  while ( pFrame->IsLayoutFrame() &&
304  static_cast<SwLayoutFrame*>(pFrame)->Lower() &&
305  !static_cast<SwLayoutFrame*>(pFrame)->Lower()->IsFlowFrame() &&
306  static_cast<SwLayoutFrame*>(pFrame)->Lower()->IsLayoutFrame() )
307  {
308  pFrame = static_cast<SwLayoutFrame*>(pFrame)->Lower();
309  }
310  assert(pFrame->IsLayoutFrame());
311  rpFrame = bMaster ? nullptr
312  : static_cast<SwLayoutFrame*>(pFrame)->Lower();
313  assert((!rpFrame || rpFrame->IsFlowFrame()) &&
314  "<SwNode2LayImpl::UpperFrame(..)> - expected sibling isn't a flow frame." );
315  return static_cast<SwLayoutFrame*>(pFrame);
316  }
317 
318  pUpper = new SwSectionFrame(const_cast<SwSectionNode*>(static_cast<const SwSectionNode*>(pNode))->GetSection(), rpFrame);
319  pUpper->Paste( rpFrame->GetUpper(),
320  bMaster ? rpFrame : rpFrame->GetNext() );
321  static_cast<SwSectionFrame*>(pUpper)->Init();
322  rpFrame = nullptr;
323  // 'Go down' the section frame as long as the layout frame
324  // is found, which would contain content.
325  while ( pUpper->Lower() &&
326  !pUpper->Lower()->IsFlowFrame() &&
327  pUpper->Lower()->IsLayoutFrame() )
328  {
329  pUpper = static_cast<SwLayoutFrame*>(pUpper->Lower());
330  }
331  return pUpper;
332  }
333  }
334  }
335  if( !bMaster )
336  rpFrame = rpFrame->GetNext();
337  return pUpper;
338 }
339 
341 {
342  SwNode* pNd;
343  SwDoc *pDoc = rNds.GetDoc();
344  bool bFirst = true;
345  for( ; nStt < nEnd; ++nStt )
346  {
347  SwFrame* pNew = nullptr;
348  SwFrame* pNxt;
349  SwLayoutFrame* pUp;
350  if( (pNd = rNds[nStt])->IsContentNode() )
351  for( std::vector<SwFrame*>::size_type n = 0; n < mvUpperFrames.size(); )
352  {
353  pNxt = mvUpperFrames[n++];
354  if( bFirst && pNxt && pNxt->IsSctFrame() )
355  static_cast<SwSectionFrame*>(pNxt)->UnlockJoin();
356  pUp = static_cast<SwLayoutFrame*>(mvUpperFrames[n++]);
357  if( pNxt )
358  pNxt = pNxt->GetNext();
359  else
360  pNxt = pUp->Lower();
361  pNew = static_cast<SwContentNode*>(pNd)->MakeFrame( pUp );
362  pNew->Paste( pUp, pNxt );
363  mvUpperFrames[n-2] = pNew;
364  }
365  else if( pNd->IsTableNode() )
366  for( std::vector<SwFrame*>::size_type x = 0; x < mvUpperFrames.size(); )
367  {
368  pNxt = mvUpperFrames[x++];
369  if( bFirst && pNxt && pNxt->IsSctFrame() )
370  static_cast<SwSectionFrame*>(pNxt)->UnlockJoin();
371  pUp = static_cast<SwLayoutFrame*>(mvUpperFrames[x++]);
372  if( pNxt )
373  pNxt = pNxt->GetNext();
374  else
375  pNxt = pUp->Lower();
376  pNew = static_cast<SwTableNode*>(pNd)->MakeFrame( pUp );
377  assert(pNew->IsTabFrame());
378  pNew->Paste( pUp, pNxt );
379  static_cast<SwTabFrame*>(pNew)->RegistFlys();
380  mvUpperFrames[x-2] = pNew;
381  }
382  else if( pNd->IsSectionNode() )
383  {
384  nStt = pNd->EndOfSectionIndex();
385  for( std::vector<SwFrame*>::size_type x = 0; x < mvUpperFrames.size(); )
386  {
387  pNxt = mvUpperFrames[x++];
388  if( bFirst && pNxt && pNxt->IsSctFrame() )
389  static_cast<SwSectionFrame*>(pNxt)->UnlockJoin();
390  pUp = static_cast<SwLayoutFrame*>(mvUpperFrames[x++]);
391  OSL_ENSURE( pUp->GetUpper() || pUp->IsFlyFrame(), "Lost Upper" );
392  ::InsertCnt_( pUp, pDoc, pNd->GetIndex(), false, nStt+1, pNxt );
393  pNxt = pUp->GetLastLower();
394  mvUpperFrames[x-2] = pNxt;
395  }
396  }
397  bFirst = false;
398  }
399  for( std::vector<SwFrame*>::size_type x = 0; x < mvUpperFrames.size(); ++x )
400  {
401  SwFrame* pTmp = mvUpperFrames[++x];
402  if( pTmp->IsFootnoteFrame() )
403  static_cast<SwFootnoteFrame*>(pTmp)->ColUnlock();
404  else if ( pTmp->IsInSct() )
405  {
406  SwSectionFrame* pSctFrame = pTmp->FindSctFrame();
407  pSctFrame->ColUnlock();
408  // #i18103# - invalidate size of section in order to
409  // assure, that the section is formatted, unless it was 'Collocked'
410  // from its 'collection' until its 'restoration'.
411  pSctFrame->InvalidateSize_();
412  }
413  }
414 }
415 
416 SwFrame* SwNode2LayImpl::GetFrame( const Point* pDocPos ) const
417 {
418  // test if change of member pIter -> pMod broke anything
419  std::pair<Point, bool> tmp;
420  if (pDocPos)
421  {
422  tmp.first = *pDocPos;
423  tmp.second = false;
424  }
425  return pMod ? ::GetFrameOfModify(nullptr, *pMod, FRM_ALL, nullptr, pDocPos ? &tmp : nullptr) : nullptr;
426 }
427 
429  : pImpl( new SwNode2LayImpl( rNd, nIdx, false ) )
430 {
431 }
432 
434  : pImpl( new SwNode2LayImpl( rNd, rNd.GetIndex(), true ) )
435 {
436  pImpl->SaveUpperFrames();
437 }
438 
440  SwNodes& rNds, sal_uLong const nStt, sal_uLong const nEnd)
441 {
442  pImpl->RestoreUpperFrames( rNds, nStt, nEnd );
443 }
444 
446 {
447  return pImpl->NextFrame();
448 }
449 
451 {
452  return pImpl->UpperFrame( rpFrame, rNode );
453 }
454 
456 {
457 }
458 
460 {
461 }
462 
463 SwFrame* SwNode2Layout::GetFrame( const Point* pDocPos ) const
464 {
465  return pImpl->GetFrame( pDocPos );
466 }
467 
468 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:682
Base class of the Writer layout elements.
Definition: frame.hxx:295
Base class that provides the general functionalities for frames that are allowed at page breaks (flow...
Definition: flowfrm.hxx:58
sal_uLong GetIndex() const
Definition: node.hxx:282
bool IsFollow() const
Definition: flowfrm.hxx:166
sal_uLong Count() const
Definition: ndarr.hxx:143
bool IsSectionNode() const
Definition: node.hxx:644
void Init()
bool IsInSct() const
Definition: frame.hxx:943
void RestoreUpperFrames(SwNodes &rNds, sal_uLong nStt, sal_uLong nEnd)
Definition: node2lay.cxx:340
std::unique_ptr< SwIterator< SwFrame, SwModify, sw::IteratorMode::UnwrapMulti > > pIter
Definition: node2lay.cxx:39
void ColLock()
Definition: sectfrm.hxx:86
bool IsInFootnote() const
Definition: frame.hxx:925
sal_uIntPtr sal_uLong
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:30
void InvalidateSize_()
Definition: frame.hxx:749
SwFrame * GetFrame(const Point *pDocPos) const
Definition: node2lay.cxx:463
Definition: doc.hxx:185
SwFrame * FindPrev()
Definition: frame.hxx:1131
bool HasFollow() const
Definition: flowfrm.hxx:165
SwFrame * NextFrame()
Returns the next "useful" Frame.
Definition: node2lay.cxx:199
SwModify * pMod
Definition: node2lay.cxx:40
void SaveUpperFrames()
Definition: node2lay.cxx:258
virtual void Paste(SwFrame *pParent, SwFrame *pSibling=nullptr) override
Definition: wsfrm.cxx:1296
SwNode & GetNode() const
Definition: ndindex.hxx:118
SwSectionFormat * GetFormat()
Definition: section.hxx:337
sal_uLong const nIndex
Definition: node2lay.cxx:42
SwFrame * FindNext()
Definition: frame.hxx:1117
static SwFlowFrame * CastFlowFrame(SwFrame *pFrame)
Definition: flowfrm.cxx:2601
float x
bool IsFootnoteFrame() const
Definition: frame.hxx:1178
std::unique_ptr< SwNode2LayImpl > pImpl
Definition: node2lay.hxx:56
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:201
bool IsFlyFrame() const
Definition: frame.hxx:1186
SwTableNode * GetTableNode()
Definition: node.hxx:599
void InsertCnt_(SwLayoutFrame *pLay, SwDoc *pDoc, sal_uLong nIndex, bool bPages=false, sal_uLong nEndIndex=0, SwFrame *pPrv=nullptr)
Definition: frmtool.cxx:1322
std::vector< SwFrame * > mvUpperFrames
Definition: node2lay.cxx:41
SwSectionNode * GetSectionNode()
Definition: section.cxx:1007
sal_uLong GetIndex() const
Definition: ndindex.hxx:151
bool IsStartNode() const
Definition: node.hxx:624
#define FRM_ALL
Definition: frame.hxx:100
const SwTable & GetTable() const
Definition: node.hxx:497
std::unique_ptr< SwNode2LayImpl > pImpl
Definition: node2lay.hxx:70
bool IsSctFrame() const
Definition: frame.hxx:1190
bool IsFlowFrame() const
Definition: frame.hxx:1218
const SwFrame & GetFrame() const
Definition: flowfrm.hxx:151
virtual void Paste(SwFrame *pParent, SwFrame *pSibling=nullptr)=0
SwNode2Layout(const SwNode &rNd, sal_uLong nIdx)
Use this ctor for inserting before/after rNd.
Definition: node2lay.cxx:428
bool IsContentNode() const
Definition: node.hxx:628
SwNode2LayImpl & operator=(const SwNode2LayImpl &)=delete
SwFrame * NextFrame()
Definition: node2lay.cxx:445
const SwFrame * GetLastLower() const
Definition: findfrm.cxx:1817
const SwStartNode * StartOfSectionNode() const
Definition: node.hxx:131
SwNode2LayoutSaveUpperFrames(const SwNode &rNd)
Use this ctor for collecting the UpperFrames.
Definition: node2lay.cxx:433
const SwFrame * Lower() const
Definition: layfrm.hxx:100
SwContentNode * GetContentNode()
Definition: node.hxx:615
SwLayoutFrame * UpperFrame(SwFrame *&rpFrame, const SwNode &rNode)
Definition: node2lay.cxx:281
SwSection * GetSection()
Definition: sectfrm.hxx:84
SwLayoutFrame * GetUpper()
Definition: frame.hxx:656
SwFrame * GetPrev()
Definition: frame.hxx:655
Marks a node in the document model.
Definition: ndindex.hxx:31
bool IsEndNode() const
Definition: node.hxx:632
SwNodes & GetNodes()
Node is in which nodes-array/doc?
Definition: node.hxx:693
SwLayoutFrame * UpperFrame(SwFrame *&rpFrame, const SwNode &rNode)
Definition: node2lay.cxx:450
SwSectionFrame * FindSctFrame()
Definition: frame.hxx:1091
SwDoc * GetDoc()
Which Doc contains the nodes-array?
Definition: ndarr.hxx:305
void RestoreUpperFrames(SwNodes &rNds, sal_uLong nStt, sal_uLong nEnd)
Definition: node2lay.cxx:439
bool IsLayoutFrame() const
Definition: frame.hxx:1146
sal_uLong EndOfSectionIndex() const
Definition: node.hxx:677
static SwNode * GoPreviousWithFrame(SwNodeIndex *pIdx)
Definition: node2lay.cxx:94
bool IsTabFrame() const
Definition: frame.hxx:1194
void ColUnlock()
Definition: sectfrm.hxx:87
The SwNode2LayImpl class does the actual work, the SwNode2Layout class is just the public interface...
Definition: node2lay.cxx:37
SwFrame * GetFrame(const Point *pDocPos) const
Definition: node2lay.cxx:416
static SwNode * GoNextWithFrame(const SwNodes &rNodes, SwNodeIndex *pIdx)
Definition: node2lay.cxx:60
bool IsTableNode() const
Definition: node.hxx:640
void RegistFlys(SwPageFrame *, const SwLayoutFrame *)
Definition: frmtool.cxx:2908
SwNode2LayImpl(const SwNode2LayImpl &)=delete
const SwFlowFrame * GetFollow() const
Definition: flowfrm.hxx:168
void ColLock()
Definition: frame.hxx:429
SwFrame * GetFrameOfModify(const SwRootFrame *pLayout, SwModify const &, SwFrameType const nFrameType, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr)
SwFrame * GetNext()
Definition: frame.hxx:654
Base class of the Writer document model elements.
Definition: node.hxx:79