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