LibreOffice Module sw (master)  1
tblsel.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 <editeng/boxitem.hxx>
21 #include <editeng/protitem.hxx>
22 #include <osl/diagnose.h>
23 
24 #include <hintids.hxx>
25 #include <fmtanchr.hxx>
26 #include <fmtfsize.hxx>
27 #include <frmatr.hxx>
28 #include <tblsel.hxx>
29 #include <crsrsh.hxx>
30 #include <doc.hxx>
31 #include <IDocumentUndoRedo.hxx>
33 #include <pam.hxx>
34 #include <ndtxt.hxx>
35 #include <swtable.hxx>
36 #include <cntfrm.hxx>
37 #include <tabfrm.hxx>
38 #include <rowfrm.hxx>
39 #include <cellfrm.hxx>
40 #include <rootfrm.hxx>
41 #include <viscrs.hxx>
42 #include <swtblfmt.hxx>
43 #include <UndoTable.hxx>
44 #include <sectfrm.hxx>
45 #include <frmtool.hxx>
46 #include <calbck.hxx>
47 #include <frameformats.hxx>
48 #include <deque>
49 #include <memory>
50 
51 // see also swtable.cxx
52 #define COLFUZZY 20L
53 
54 // macros, determining how table boxes are merged:
55 // - 1. remove empty lines, all boxes separated with blanks,
56 // all lines separated with ParaBreak
57 // - 2. remove all empty lines and remove all empty boxes at beginning and end,
58 // all boxes separated with Blank,
59 // all lines separated with ParaBreak
60 // - 3. remove all empty boxes, all boxes separated with blanks,
61 // all lines separated with ParaBreak
62 
63 #undef DEL_ONLY_EMPTY_LINES
64 #undef DEL_EMPTY_BOXES_AT_START_AND_END
65 
66 namespace {
67 
68 struct CmpLPt
69 {
70  Point aPos;
71  const SwTableBox* pSelBox;
72  bool bVert;
73 
74  CmpLPt( const Point& rPt, const SwTableBox* pBox, bool bVertical );
75 
76  bool operator<( const CmpLPt& rCmp ) const
77  {
78  if ( bVert )
79  return X() > rCmp.X() || ( X() == rCmp.X() && Y() < rCmp.Y() );
80  else
81  return Y() < rCmp.Y() || ( Y() == rCmp.Y() && X() < rCmp.X() );
82  }
83 
84  tools::Long X() const { return aPos.X(); }
85  tools::Long Y() const { return aPos.Y(); }
86 };
87 
88 }
89 
91 
92 namespace {
93 
94 struct Sort_CellFrame
95 {
96  const SwCellFrame* pFrame;
97 
98  explicit Sort_CellFrame( const SwCellFrame& rCFrame )
99  : pFrame( &rCFrame ) {}
100 };
101 
102 }
103 
104 static const SwLayoutFrame *lcl_FindCellFrame( const SwLayoutFrame *pLay )
105 {
106  while ( pLay && !pLay->IsCellFrame() )
107  pLay = pLay->GetUpper();
108  return pLay;
109 }
110 
112 {
113  // ensure we leave the cell (sections)
114  const SwLayoutFrame *pTmp = pLay;
115  do {
116  pTmp = pTmp->GetNextLayoutLeaf();
117  } while( pLay->IsAnLower( pTmp ) );
118 
119  while( pTmp && !pTmp->IsCellFrame() )
120  pTmp = pTmp->GetUpper();
121  return pTmp;
122 }
123 
124 void GetTableSelCrs( const SwCursorShell &rShell, SwSelBoxes& rBoxes )
125 {
126  rBoxes.clear();
127  if( rShell.IsTableMode() && const_cast<SwCursorShell&>(rShell).UpdateTableSelBoxes())
128  {
129  rBoxes.insert(rShell.GetTableCursor()->GetSelectedBoxes());
130  }
131 }
132 
133 void GetTableSelCrs( const SwTableCursor& rTableCursor, SwSelBoxes& rBoxes )
134 {
135  rBoxes.clear();
136 
137  if (rTableCursor.IsChgd() || !rTableCursor.GetSelectedBoxesCount())
138  {
139  SwTableCursor* pTCursor = const_cast<SwTableCursor*>(&rTableCursor);
141  }
142 
143  if (rTableCursor.GetSelectedBoxesCount())
144  {
145  rBoxes.insert(rTableCursor.GetSelectedBoxes());
146  }
147 }
148 
149 void GetTableSel( const SwCursorShell& rShell, SwSelBoxes& rBoxes,
150  const SwTableSearchType eSearchType )
151 {
152  // get start and end cell
153  if ( !rShell.IsTableMode() )
154  rShell.GetCursor();
155 
156  GetTableSel( *rShell.getShellCursor(false), rBoxes, eSearchType );
157 }
158 
159 void GetTableSel( const SwCursor& rCursor, SwSelBoxes& rBoxes,
160  const SwTableSearchType eSearchType )
161 {
162  // get start and end cell
163  OSL_ENSURE( rCursor.GetContentNode() && rCursor.GetContentNode( false ),
164  "Tabselection not on Cnt." );
165 
166  // Row-selection:
167  // Check for complex tables. If Yes, search selected boxes via
168  // the layout. Otherwise via the table structure (for macros !!)
169  const SwContentNode* pContentNd = rCursor.GetNode().GetContentNode();
170  const SwTableNode* pTableNd = pContentNd ? pContentNd->FindTableNode() : nullptr;
171  if( pTableNd && pTableNd->GetTable().IsNewModel() )
172  {
173  SwTable::SearchType eSearch;
174  switch( SwTableSearchType::Col & eSearchType )
175  {
176  case SwTableSearchType::Row: eSearch = SwTable::SEARCH_ROW; break;
177  case SwTableSearchType::Col: eSearch = SwTable::SEARCH_COL; break;
178  default: eSearch = SwTable::SEARCH_NONE; break;
179  }
180  const bool bChkP( SwTableSearchType::Protect & eSearchType );
181  pTableNd->GetTable().CreateSelection( rCursor, rBoxes, eSearch, bChkP );
182  return;
183  }
184  if( SwTableSearchType::Row == ((~SwTableSearchType::Protect ) & eSearchType ) &&
185  pTableNd && !pTableNd->GetTable().IsTableComplex() )
186  {
187  const SwTable& rTable = pTableNd->GetTable();
188  const SwTableLines& rLines = rTable.GetTabLines();
189 
190  const SwNode& rMarkNode = rCursor.GetNode( false );
191  const SwNodeOffset nMarkSectionStart = rMarkNode.StartOfSectionIndex();
192  const SwTableBox* pMarkBox = rTable.GetTableBox( nMarkSectionStart );
193 
194  OSL_ENSURE( pMarkBox, "Point in table, mark outside?" );
195 
196  const SwTableLine* pLine = pMarkBox ? pMarkBox->GetUpper() : nullptr;
197  sal_uInt16 nSttPos = rLines.GetPos( pLine );
198  OSL_ENSURE( USHRT_MAX != nSttPos, "Where is my row in the table?" );
199  pLine = rTable.GetTableBox( rCursor.GetNode().StartOfSectionIndex() )->GetUpper();
200  sal_uInt16 nEndPos = rLines.GetPos( pLine );
201  OSL_ENSURE( USHRT_MAX != nEndPos, "Where is my row in the table?" );
202  // pb: #i20193# if tableintable then nSttPos == nEndPos == USHRT_MAX
203  if ( nSttPos != USHRT_MAX && nEndPos != USHRT_MAX )
204  {
205  if( nEndPos < nSttPos ) // exchange
206  {
207  sal_uInt16 nTmp = nSttPos; nSttPos = nEndPos; nEndPos = nTmp;
208  }
209 
210  bool bChkProtected( SwTableSearchType::Protect & eSearchType );
211  for( ; nSttPos <= nEndPos; ++nSttPos )
212  {
213  pLine = rLines[ nSttPos ];
214  for( auto n = pLine->GetTabBoxes().size(); n ; )
215  {
216  SwTableBox* pBox = pLine->GetTabBoxes()[ --n ];
217  // check for cell protection??
218  if( !bChkProtected ||
220  rBoxes.insert( pBox );
221  }
222  }
223  }
224  }
225  else
226  {
227  Point aPtPos, aMkPos;
228  const SwShellCursor* pShCursor = dynamic_cast<const SwShellCursor*>(&rCursor);
229  if( pShCursor )
230  {
231  aPtPos = pShCursor->GetPtPos();
232  aMkPos = pShCursor->GetMkPos();
233  }
234  const SwContentNode *pCntNd = rCursor.GetContentNode();
235  std::pair<Point, bool> tmp(aPtPos, true);
236  const SwLayoutFrame *pStart = pCntNd ?
237  pCntNd->getLayoutFrame(pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp)->GetUpper() : nullptr;
238  pCntNd = rCursor.GetContentNode(false);
239  tmp.first = aMkPos;
240  const SwLayoutFrame *pEnd = pCntNd ?
241  pCntNd->getLayoutFrame(pCntNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp)->GetUpper() : nullptr;
242  if( pStart && pEnd )
243  GetTableSel( pStart, pEnd, rBoxes, nullptr, eSearchType );
244  }
245 }
246 
247 void GetTableSel( const SwLayoutFrame* pStart, const SwLayoutFrame* pEnd,
248  SwSelBoxes& rBoxes, SwCellFrames* pCells,
249  const SwTableSearchType eSearchType )
250 {
251  const SwTabFrame* pStartTab = pStart->FindTabFrame();
252  if ( !pStartTab )
253  {
254  OSL_FAIL( "GetTableSel without start table" );
255  return;
256  }
257 
258  bool bChkProtected( SwTableSearchType::Protect & eSearchType );
259 
260  // #i55421# Reduced value 10
261  int nLoopMax = 10;
262 
263  do {
264  bool bTableIsValid = true;
265 
266  // First, compute tables and rectangles
267  SwSelUnions aUnions;
268  ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
269 
270  Point aCurrentTopLeft( LONG_MAX, LONG_MAX );
271  Point aCurrentTopRight( 0, LONG_MAX );
272  Point aCurrentBottomLeft( LONG_MAX, 0 );
273  Point aCurrentBottomRight( 0, 0 );
274  const SwCellFrame* pCurrentTopLeftFrame = nullptr;
275  const SwCellFrame* pCurrentTopRightFrame = nullptr;
276  const SwCellFrame* pCurrentBottomLeftFrame = nullptr;
277  const SwCellFrame* pCurrentBottomRightFrame = nullptr;
278 
279  // Now find boxes for each entry and emit
280  for (size_t i = 0; i < aUnions.size() && bTableIsValid; ++i)
281  {
282  SwSelUnion *pUnion = &aUnions[i];
283  const SwTabFrame *pTable = pUnion->GetTable();
284 
285  if( !pTable->isFrameAreaDefinitionValid() && nLoopMax )
286  {
287  bTableIsValid = false;
288  break;
289  }
290 
291  // Skip any repeated headlines in the follow:
292  const SwLayoutFrame* pRow = pTable->IsFollow() ?
293  pTable->GetFirstNonHeadlineRow() :
294  static_cast<const SwLayoutFrame*>(pTable->Lower());
295 
296  while( pRow && bTableIsValid )
297  {
298  if( !pRow->isFrameAreaDefinitionValid() && nLoopMax )
299  {
300  bTableIsValid = false;
301  break;
302  }
303 
304  if ( pRow->getFrameArea().Overlaps( pUnion->GetUnion() ) )
305  {
306  const SwLayoutFrame *pCell = pRow->FirstCell();
307 
308  while (pCell && pRow->IsAnLower(pCell))
309  {
310  if( !pCell->isFrameAreaDefinitionValid() && nLoopMax )
311  {
312  bTableIsValid = false;
313  break;
314  }
315 
316  OSL_ENSURE( pCell->IsCellFrame(), "Frame without Cell" );
317  if( ::IsFrameInTableSel( pUnion->GetUnion(), pCell ) )
318  {
319  SwTableBox* pBox = const_cast<SwTableBox*>(
320  static_cast<const SwCellFrame*>(pCell)->GetTabBox());
321  // check for cell protection??
322  if( !bChkProtected ||
324  rBoxes.insert( pBox );
325 
326  if ( pCells )
327  {
328  const Point aTopLeft( pCell->getFrameArea().TopLeft() );
329  const Point aTopRight( pCell->getFrameArea().TopRight() );
330  const Point aBottomLeft( pCell->getFrameArea().BottomLeft() );
331  const Point aBottomRight( pCell->getFrameArea().BottomRight() );
332 
333  if ( aTopLeft.getY() < aCurrentTopLeft.getY() ||
334  ( aTopLeft.getY() == aCurrentTopLeft.getY() &&
335  aTopLeft.getX() < aCurrentTopLeft.getX() ) )
336  {
337  aCurrentTopLeft = aTopLeft;
338  pCurrentTopLeftFrame = static_cast<const SwCellFrame*>( pCell );
339  }
340 
341  if ( aTopRight.getY() < aCurrentTopRight.getY() ||
342  ( aTopRight.getY() == aCurrentTopRight.getY() &&
343  aTopRight.getX() > aCurrentTopRight.getX() ) )
344  {
345  aCurrentTopRight = aTopRight;
346  pCurrentTopRightFrame = static_cast<const SwCellFrame*>( pCell );
347  }
348 
349  if ( aBottomLeft.getY() > aCurrentBottomLeft.getY() ||
350  ( aBottomLeft.getY() == aCurrentBottomLeft.getY() &&
351  aBottomLeft.getX() < aCurrentBottomLeft.getX() ) )
352  {
353  aCurrentBottomLeft = aBottomLeft;
354  pCurrentBottomLeftFrame = static_cast<const SwCellFrame*>( pCell );
355  }
356 
357  if ( aBottomRight.getY() > aCurrentBottomRight.getY() ||
358  ( aBottomRight.getY() == aCurrentBottomRight.getY() &&
359  aBottomRight.getX() > aCurrentBottomRight.getX() ) )
360  {
361  aCurrentBottomRight = aBottomRight;
362  pCurrentBottomRightFrame = static_cast<const SwCellFrame*>( pCell );
363  }
364 
365  }
366  }
367  if ( pCell->GetNext() )
368  {
369  pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
370  if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
371  pCell = pCell->FirstCell();
372  }
373  else
374  pCell = ::lcl_FindNextCellFrame( pCell );
375  }
376  }
377  pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
378  }
379  }
380 
381  if ( pCells )
382  {
383  pCells->clear();
384  pCells->push_back( const_cast< SwCellFrame* >(pCurrentTopLeftFrame) );
385  pCells->push_back( const_cast< SwCellFrame* >(pCurrentTopRightFrame) );
386  pCells->push_back( const_cast< SwCellFrame* >(pCurrentBottomLeftFrame) );
387  pCells->push_back( const_cast< SwCellFrame* >(pCurrentBottomRightFrame) );
388  }
389 
390  if( bTableIsValid )
391  break;
392 
393  SwDeletionChecker aDelCheck( pStart );
394 
395  // otherwise quickly "calculate" the table layout and start over
396  SwTabFrame *pTable = aUnions.front().GetTable();
397  while( pTable )
398  {
399  if( pTable->isFrameAreaDefinitionValid() )
400  {
401  pTable->InvalidatePos();
402  }
403 
404  pTable->SetONECalcLowers();
405  pTable->Calc(pTable->getRootFrame()->GetCurrShell()->GetOut());
406  pTable->SetCompletePaint();
407 
408  pTable = pTable->GetFollow();
409  if( nullptr == pTable )
410  break;
411  }
412 
413  // --> Make code robust, check if pStart has
414  // been deleted due to the formatting of the table:
415  if ( aDelCheck.HasBeenDeleted() )
416  {
417  OSL_FAIL( "Current box has been deleted during GetTableSel()" );
418  break;
419  }
420 
421  rBoxes.clear();
422  --nLoopMax;
423 
424  } while( true );
425  OSL_ENSURE( nLoopMax, "Table layout is still invalid!" );
426 }
427 
428 bool ChkChartSel( const SwNode& rSttNd, const SwNode& rEndNd )
429 {
430  const SwTableNode* pTNd = rSttNd.FindTableNode();
431  if( !pTNd )
432  return false;
433 
434  Point aNullPos;
435  SwNodeIndex aIdx( rSttNd );
436  const SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
437  if( !pCNd )
438  pCNd = aIdx.GetNodes().GoNextSection( &aIdx, false, false );
439 
440  // if table is invisible, return
441  // (layout needed for forming table selection further down, so we can't
442  // continue with invisible tables)
443  // #i22135# - Also the content of the table could be
444  // invisible - e.g. in a hidden section
445  // Robust: check, if content was found (e.g. empty table cells)
446  if ( !pCNd || pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) == nullptr )
447  return false;
448 
449  std::pair<Point, bool> tmp(aNullPos, true);
450  const SwLayoutFrame *const pStart = pCNd->getLayoutFrame(
452  nullptr, &tmp)->GetUpper();
453  OSL_ENSURE( pStart, "without frame nothing works" );
454 
455  aIdx = rEndNd;
456  pCNd = aIdx.GetNode().GetContentNode();
457  if( !pCNd )
458  pCNd = aIdx.GetNodes().GoNextSection( &aIdx, false, false );
459 
460  // #i22135# - Robust: check, if content was found and if it's visible
461  if ( !pCNd || pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) == nullptr )
462  {
463  return false;
464  }
465 
466  const SwLayoutFrame *const pEnd = pCNd->getLayoutFrame(
468  nullptr, &tmp)->GetUpper();
469  OSL_ENSURE( pEnd, "without frame nothing works" );
470 
471  bool bValidChartSel;
472  // #i55421# Reduced value 10
473  int nLoopMax = 10; //JP 28.06.99: max 100 loops - Bug 67292
474 
475  do {
476  bool bTableIsValid = true;
477  bValidChartSel = true;
478 
479  sal_uInt16 nRowCells = USHRT_MAX;
480 
481  // First, compute tables and rectangles
482  SwSelUnions aUnions;
483  ::MakeSelUnions( aUnions, pStart, pEnd, SwTableSearchType::NoUnionCorrect );
484 
485  // find boxes for each entry and emit
486  for( auto & rSelUnion : aUnions )
487  {
488  if (!bTableIsValid || !bValidChartSel)
489  break;
490 
491  SwSelUnion *pUnion = &rSelUnion;
492  const SwTabFrame *pTable = pUnion->GetTable();
493 
494  SwRectFnSet aRectFnSet(pTable);
495  bool bRTL = pTable->IsRightToLeft();
496 
497  if( !pTable->isFrameAreaDefinitionValid() && nLoopMax )
498  {
499  bTableIsValid = false;
500  break;
501  }
502 
503  std::deque< Sort_CellFrame > aCellFrames;
504 
505  // Skip any repeated headlines in the follow:
506  const SwLayoutFrame* pRow = pTable->IsFollow() ?
507  pTable->GetFirstNonHeadlineRow() :
508  static_cast<const SwLayoutFrame*>(pTable->Lower());
509 
510  while( pRow && bTableIsValid && bValidChartSel )
511  {
512  if( !pRow->isFrameAreaDefinitionValid() && nLoopMax )
513  {
514  bTableIsValid = false;
515  break;
516  }
517 
518  if( pRow->getFrameArea().Overlaps( pUnion->GetUnion() ) )
519  {
520  const SwLayoutFrame *pCell = pRow->FirstCell();
521 
522  while (pCell && pRow->IsAnLower(pCell))
523  {
524  if( !pCell->isFrameAreaDefinitionValid() && nLoopMax )
525  {
526  bTableIsValid = false;
527  break;
528  }
529 
530  OSL_ENSURE( pCell->IsCellFrame(), "Frame without Cell" );
531  const SwRect& rUnion = pUnion->GetUnion(),
532  & rFrameRect = pCell->getFrameArea();
533 
534  const tools::Long nUnionRight = rUnion.Right();
535  const tools::Long nUnionBottom = rUnion.Bottom();
536  const tools::Long nFrameRight = rFrameRect.Right();
537  const tools::Long nFrameBottom = rFrameRect.Bottom();
538 
539  // ignore if FrameRect is outside the union
540 
541  const tools::Long nXFuzzy = aRectFnSet.IsVert() ? 0 : 20;
542  const tools::Long nYFuzzy = aRectFnSet.IsVert() ? 20 : 0;
543 
544  if( !( rUnion.Top() + nYFuzzy > nFrameBottom ||
545  nUnionBottom < rFrameRect.Top() + nYFuzzy ||
546  rUnion.Left() + nXFuzzy > nFrameRight ||
547  nUnionRight < rFrameRect.Left() + nXFuzzy ))
548  {
549  // ok, rUnion is _not_ completely outside of rFrameRect
550 
551  // if not completely inside the union, then
552  // for Chart it is an invalid selection
553  if( rUnion.Left() <= rFrameRect.Left() + nXFuzzy &&
554  rFrameRect.Left() <= nUnionRight &&
555  rUnion.Left() <= nFrameRight &&
556  nFrameRight <= nUnionRight + nXFuzzy &&
557  rUnion.Top() <= rFrameRect.Top() + nYFuzzy &&
558  rFrameRect.Top() <= nUnionBottom &&
559  rUnion.Top() <= nFrameBottom &&
560  nFrameBottom <= nUnionBottom+ nYFuzzy )
561 
562  aCellFrames.emplace_back( *static_cast<const SwCellFrame*>(pCell) );
563  else
564  {
565  bValidChartSel = false;
566  break;
567  }
568  }
569  if ( pCell->GetNext() )
570  {
571  pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
572  if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
573  pCell = pCell->FirstCell();
574  }
575  else
576  pCell = ::lcl_FindNextCellFrame( pCell );
577  }
578  }
579  pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
580  }
581 
582  if( !bValidChartSel )
583  break;
584 
585  // all cells of the (part) table together. Now check if
586  // they're all adjacent
587  size_t n;
588  sal_uInt16 nCellCnt = 0;
589  tools::Long nYPos = LONG_MAX;
590  tools::Long nXPos = 0;
591  tools::Long nHeight = 0;
592 
593  for( n = 0 ; n < aCellFrames.size(); ++n )
594  {
595  const Sort_CellFrame& rCF = aCellFrames[ n ];
596  if( aRectFnSet.GetTop(rCF.pFrame->getFrameArea()) != nYPos )
597  {
598  // new row
599  if( n )
600  {
601  if( USHRT_MAX == nRowCells ) // 1. row change
602  nRowCells = nCellCnt;
603  else if( nRowCells != nCellCnt )
604  {
605  bValidChartSel = false;
606  break;
607  }
608  }
609  nCellCnt = 1;
610  nYPos = aRectFnSet.GetTop(rCF.pFrame->getFrameArea());
611  nHeight = aRectFnSet.GetHeight(rCF.pFrame->getFrameArea());
612 
613  nXPos = bRTL ?
614  aRectFnSet.GetLeft(rCF.pFrame->getFrameArea()) :
615  aRectFnSet.GetRight(rCF.pFrame->getFrameArea());
616  }
617  else if( nXPos == ( bRTL ?
618  aRectFnSet.GetRight(rCF.pFrame->getFrameArea()) :
619  aRectFnSet.GetLeft(rCF.pFrame->getFrameArea()) ) &&
620  nHeight == aRectFnSet.GetHeight(rCF.pFrame->getFrameArea()) )
621  {
622  nXPos += ( bRTL ? -1 : 1 ) *
623  aRectFnSet.GetWidth(rCF.pFrame->getFrameArea());
624  ++nCellCnt;
625  }
626  else
627  {
628  bValidChartSel = false;
629  break;
630  }
631  }
632  if( bValidChartSel )
633  {
634  if( USHRT_MAX == nRowCells )
635  nRowCells = nCellCnt;
636  else if( nRowCells != nCellCnt )
637  bValidChartSel = false;
638  }
639  }
640 
641  if( bTableIsValid )
642  break;
643 
644  // otherwise quickly "calculate" table layout and start over
645  SwTabFrame *pTable = aUnions.front().GetTable();
646 
647  for( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
648  {
649  if( pTable->isFrameAreaDefinitionValid() )
650  {
651  pTable->InvalidatePos();
652  }
653 
654  pTable->SetONECalcLowers();
655  pTable->Calc(pTable->getRootFrame()->GetCurrShell()->GetOut());
656  pTable->SetCompletePaint();
657 
658  pTable = pTable->GetFollow();
659  if( nullptr == pTable )
660  break;
661  }
662  --nLoopMax;
663  } while( true );
664 
665  OSL_ENSURE( nLoopMax, "table layout is still invalid!" );
666 
667  return bValidChartSel;
668 }
669 
670 bool IsFrameInTableSel( const SwRect& rUnion, const SwFrame* pCell )
671 {
672  OSL_ENSURE( pCell->IsCellFrame(), "Frame without Gazelle" );
673 
674  if( pCell->FindTabFrame()->IsVertical() )
675  return rUnion.Right() >= pCell->getFrameArea().Right() &&
676  rUnion.Left() <= pCell->getFrameArea().Left() &&
677  (( rUnion.Top() <= pCell->getFrameArea().Top()+20 &&
678  rUnion.Bottom() > pCell->getFrameArea().Top() ) ||
679  ( rUnion.Top() >= pCell->getFrameArea().Top() &&
680  rUnion.Bottom() < pCell->getFrameArea().Bottom() ));
681 
682  return
683  rUnion.Top() <= pCell->getFrameArea().Top() &&
684  rUnion.Bottom() >= pCell->getFrameArea().Bottom() &&
685 
686  (( rUnion.Left() <= pCell->getFrameArea().Left()+20 &&
687  rUnion.Right() > pCell->getFrameArea().Left() ) ||
688 
689  ( rUnion.Left() >= pCell->getFrameArea().Left() &&
690  rUnion.Right() < pCell->getFrameArea().Right() ));
691 }
692 
693 bool GetAutoSumSel( const SwCursorShell& rShell, SwCellFrames& rBoxes )
694 {
695  SwShellCursor* pCursor = rShell.m_pCurrentCursor;
696  if ( rShell.IsTableMode() )
697  pCursor = rShell.m_pTableCursor;
698 
699  std::pair<Point, bool> tmp(pCursor->GetPtPos(), true);
700  const SwLayoutFrame *const pStart = pCursor->GetContentNode()->getLayoutFrame(
701  rShell.GetLayout(), nullptr, &tmp)->GetUpper();
702  tmp.first = pCursor->GetMkPos();
703  const SwLayoutFrame *const pEnd = pCursor->GetContentNode(false)->getLayoutFrame(
704  rShell.GetLayout(), nullptr, &tmp)->GetUpper();
705 
706  const SwLayoutFrame* pSttCell = pStart;
707  while( pSttCell && !pSttCell->IsCellFrame() )
708  pSttCell = pSttCell->GetUpper();
709 
710  // First, compute tables and rectangles
711  SwSelUnions aUnions;
712 
713  // by default, first test above and then to the left
714  ::MakeSelUnions( aUnions, pStart, pEnd, SwTableSearchType::Col );
715 
716  bool bTstRow = true, bFound = false;
717 
718  // 1. check if box above contains value/formula
719  for( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
720  {
721  SwSelUnion *pUnion = &aUnions[i];
722  const SwTabFrame *pTable = pUnion->GetTable();
723 
724  // Skip any repeated headlines in the follow:
725  const SwLayoutFrame* pRow = pTable->IsFollow() ?
726  pTable->GetFirstNonHeadlineRow() :
727  static_cast<const SwLayoutFrame*>(pTable->Lower());
728 
729  while( pRow )
730  {
731  if( pRow->getFrameArea().Overlaps( pUnion->GetUnion() ) )
732  {
733  const SwCellFrame* pUpperCell = nullptr;
734  const SwLayoutFrame *pCell = pRow->FirstCell();
735 
736  while( pCell && pRow->IsAnLower( pCell ) )
737  {
738  if( pCell == pSttCell )
739  {
740  sal_uInt16 nWhichId = 0;
741  for( size_t n = rBoxes.size(); n; )
742  {
743  nWhichId = rBoxes[ --n ]->GetTabBox()->IsFormulaOrValueBox();
744  if( USHRT_MAX != nWhichId )
745  break;
746  }
747 
748  // all boxes together, do not check the
749  // row, if a formula or value was found
750  bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId;
751  bFound = true;
752  break;
753  }
754 
755  OSL_ENSURE( pCell->IsCellFrame(), "Frame without cell" );
756  if( ::IsFrameInTableSel( pUnion->GetUnion(), pCell ) )
757  pUpperCell = static_cast<const SwCellFrame*>(pCell);
758 
759  if( pCell->GetNext() )
760  {
761  pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
762  if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
763  pCell = pCell->FirstCell();
764  }
765  else
766  pCell = ::lcl_FindNextCellFrame( pCell );
767  }
768 
769  if( pUpperCell )
770  rBoxes.push_back( const_cast< SwCellFrame* >(pUpperCell) );
771  }
772  if( bFound )
773  {
774  i = aUnions.size();
775  break;
776  }
777  pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
778  }
779  }
780 
781  // 2. check if box on left contains value/formula
782  if( bTstRow )
783  {
784  bFound = false;
785 
786  rBoxes.clear();
787  aUnions.clear();
788  ::MakeSelUnions( aUnions, pStart, pEnd, SwTableSearchType::Row );
789 
790  for( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
791  {
792  SwSelUnion *pUnion = &aUnions[i];
793  const SwTabFrame *pTable = pUnion->GetTable();
794 
795  // Skip any repeated headlines in the follow:
796  const SwLayoutFrame* pRow = pTable->IsFollow() ?
797  pTable->GetFirstNonHeadlineRow() :
798  static_cast<const SwLayoutFrame*>(pTable->Lower());
799 
800  while( pRow )
801  {
802  if( pRow->getFrameArea().Overlaps( pUnion->GetUnion() ) )
803  {
804  const SwLayoutFrame *pCell = pRow->FirstCell();
805 
806  while( pCell && pRow->IsAnLower( pCell ) )
807  {
808  if( pCell == pSttCell )
809  {
810  sal_uInt16 nWhichId = 0;
811  for( size_t n = rBoxes.size(); n; )
812  {
813  nWhichId = rBoxes[ --n ]
815  if( USHRT_MAX != nWhichId )
816  break;
817  }
818 
819  // all boxes together, do not check the
820  // row if a formula or value was found
821  bFound = 0 != nWhichId && USHRT_MAX != nWhichId;
822  bTstRow = false;
823  break;
824  }
825 
826  OSL_ENSURE( pCell->IsCellFrame(), "Frame without cell" );
827  if( ::IsFrameInTableSel( pUnion->GetUnion(), pCell ) )
828  {
829  SwCellFrame* pC = const_cast<SwCellFrame*>(static_cast<const SwCellFrame*>(pCell));
830  rBoxes.push_back( pC );
831  }
832  if( pCell->GetNext() )
833  {
834  pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
835  if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
836  pCell = pCell->FirstCell();
837  }
838  else
839  pCell = ::lcl_FindNextCellFrame( pCell );
840  }
841  }
842  if( !bTstRow )
843  {
844  i = aUnions.size();
845  break;
846  }
847 
848  pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
849  }
850  }
851  }
852 
853  return bFound;
854 }
855 
856 bool HasProtectedCells( const SwSelBoxes& rBoxes )
857 {
858  bool bRet = false;
859  for (size_t n = 0; n < rBoxes.size(); ++n)
860  {
861  if( rBoxes[ n ]->GetFrameFormat()->GetProtect().IsContentProtected() )
862  {
863  bRet = true;
864  break;
865  }
866  }
867  return bRet;
868 }
869 
870 CmpLPt::CmpLPt( const Point& rPt, const SwTableBox* pBox, bool bVertical )
871  : aPos( rPt ), pSelBox( pBox ), bVert( bVertical )
872 {}
873 
874 static void lcl_InsTableBox( SwTableNode* pTableNd, SwDoc* pDoc, SwTableBox* pBox,
875  sal_uInt16 nInsPos, sal_uInt16 nCnt = 1 )
876 {
877  OSL_ENSURE( pBox->GetSttNd(), "Box without Start-Node" );
878  SwContentNode* pCNd = pDoc->GetNodes()[ pBox->GetSttIdx() + 1 ]
879  ->GetContentNode();
880  if( pCNd && pCNd->IsTextNode() )
881  pDoc->GetNodes().InsBoxen( pTableNd, pBox->GetUpper(),
882  static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat()),
883  static_cast<SwTextNode*>(pCNd)->GetTextColl(),
884  pCNd->GetpSwAttrSet(),
885  nInsPos, nCnt );
886  else
887  pDoc->GetNodes().InsBoxen( pTableNd, pBox->GetUpper(),
888  static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat()),
889  pDoc->GetDfltTextFormatColl(), nullptr,
890  nInsPos, nCnt );
891 }
892 
893 bool IsEmptyBox( const SwTableBox& rBox, SwPaM& rPam )
894 {
895  rPam.GetPoint()->nNode = *rBox.GetSttNd()->EndOfSectionNode();
897  rPam.SetMark();
898  rPam.GetPoint()->nNode = *rBox.GetSttNd();
899  rPam.Move( fnMoveForward, GoInContent );
900  bool bRet = *rPam.GetMark() == *rPam.GetPoint()
901  && ( rBox.GetSttNd()->GetIndex() + 1 == rPam.GetPoint()->nNode.GetIndex() );
902 
903  if( bRet )
904  {
905  // now check for paragraph bound flies
906  const SwFrameFormats& rFormats = *rPam.GetDoc().GetSpzFrameFormats();
907  SwNodeOffset nSttIdx = rPam.GetPoint()->nNode.GetIndex(),
908  nEndIdx = rBox.GetSttNd()->EndOfSectionIndex(),
909  nIdx;
910 
911  for( auto pFormat : rFormats )
912  {
913  const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
914  const SwPosition* pAPos = rAnchor.GetContentAnchor();
915  if (pAPos &&
916  ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
917  (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId())) &&
918  nSttIdx <= ( nIdx = pAPos->nNode.GetIndex() ) &&
919  nIdx < nEndIdx )
920  {
921  bRet = false;
922  break;
923  }
924  }
925  }
926  return bRet;
927 }
928 
929 void GetMergeSel( const SwPaM& rPam, SwSelBoxes& rBoxes,
930  SwTableBox** ppMergeBox, SwUndoTableMerge* pUndo )
931 {
932  rBoxes.clear();
933 
934  OSL_ENSURE( rPam.GetContentNode() && rPam.GetContentNode( false ),
935  "Tabselection not on Cnt." );
936 
937 //JP 24.09.96: Merge with repeating TableHeadLines does not work properly.
938 // Why not use point 0,0? Then it is assured the first
939 // headline is contained.
940  Point aPt( 0, 0 );
941 
942  const SwContentNode* pCntNd = rPam.GetContentNode();
943  std::pair<Point, bool> const tmp(aPt, true);
944  const SwLayoutFrame *const pStart = pCntNd->getLayoutFrame(
946  nullptr, &tmp)->GetUpper();
947  pCntNd = rPam.GetContentNode(false);
948  const SwLayoutFrame *const pEnd = pCntNd->getLayoutFrame(
950  nullptr, &tmp)->GetUpper();
951 
952  // First, compute tables and rectangles
953  SwSelUnions aUnions;
954  ::MakeSelUnions( aUnions, pStart, pEnd );
955  if( aUnions.empty() )
956  return;
957 
958  const SwTable *pTable = aUnions.front().GetTable()->GetTable();
959  SwDoc* pDoc = const_cast<SwDoc*>(pStart->GetFormat()->GetDoc());
960  SwTableNode* pTableNd = const_cast<SwTableNode*>(pTable->GetTabSortBoxes()[ 0 ]->
961  GetSttNd()->FindTableNode());
962 
963  MergePos aPosArr; // Sort-Array with the frame positions
964  tools::Long nWidth;
965  SwTableBox* pLastBox = nullptr;
966 
967  SwRectFnSet aRectFnSet(pStart->GetUpper());
968 
969  for ( auto & rSelUnion : aUnions )
970  {
971  const SwTabFrame *pTabFrame = rSelUnion.GetTable();
972 
973  SwRect &rUnion = rSelUnion.GetUnion();
974 
975  // Skip any repeated headlines in the follow:
976  const SwLayoutFrame* pRow = pTabFrame->IsFollow() ?
977  pTabFrame->GetFirstNonHeadlineRow() :
978  static_cast<const SwLayoutFrame*>(pTabFrame->Lower());
979 
980  while ( pRow )
981  {
982  if ( pRow->getFrameArea().Overlaps( rUnion ) )
983  {
984  const SwLayoutFrame *pCell = pRow->FirstCell();
985 
986  while ( pCell && pRow->IsAnLower( pCell ) )
987  {
988  OSL_ENSURE( pCell->IsCellFrame(), "Frame without cell" );
989  // overlap in full width?
990  if( rUnion.Top() <= pCell->getFrameArea().Top() &&
991  rUnion.Bottom() >= pCell->getFrameArea().Bottom() )
992  {
993  SwTableBox* pBox = const_cast<SwTableBox*>(static_cast<const SwCellFrame*>(pCell)->GetTabBox());
994 
995  // only overlap to the right?
996  if( ( rUnion.Left() - COLFUZZY ) <= pCell->getFrameArea().Left() &&
997  ( rUnion.Right() - COLFUZZY ) > pCell->getFrameArea().Left() )
998  {
999  if( ( rUnion.Right() + COLFUZZY ) < pCell->getFrameArea().Right() )
1000  {
1001  sal_uInt16 nInsPos = pBox->GetUpper()->GetBoxPos( pBox )+1;
1002  lcl_InsTableBox( pTableNd, pDoc, pBox, nInsPos );
1003  pBox->ClaimFrameFormat();
1004  SwFormatFrameSize aNew(
1005  pBox->GetFrameFormat()->GetFrameSize() );
1006  nWidth = rUnion.Right() - pCell->getFrameArea().Left();
1007  nWidth = nWidth * aNew.GetWidth() /
1008  pCell->getFrameArea().Width();
1009  tools::Long nTmpWidth = aNew.GetWidth() - nWidth;
1010  aNew.SetWidth( nWidth );
1011  pBox->GetFrameFormat()->SetFormatAttr( aNew );
1012  // this box is selected
1013  pLastBox = pBox;
1014  rBoxes.insert( pBox );
1015  aPosArr.insert(
1016  CmpLPt( aRectFnSet.GetPos(pCell->getFrameArea()),
1017  pBox, aRectFnSet.IsVert() ) );
1018 
1019  pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1020  aNew.SetWidth( nTmpWidth );
1021  pBox->ClaimFrameFormat();
1022  pBox->GetFrameFormat()->SetFormatAttr( aNew );
1023 
1024  if( pUndo )
1025  pUndo->AddNewBox( pBox->GetSttIdx() );
1026  }
1027  else
1028  {
1029  // this box is selected
1030  pLastBox = pBox;
1031  rBoxes.insert( pBox );
1032  aPosArr.insert(
1033  CmpLPt( aRectFnSet.GetPos(pCell->getFrameArea()),
1034  pBox, aRectFnSet.IsVert() ) );
1035  }
1036  }
1037  // overlapping on left- or right-side
1038  else if( ( rUnion.Left() - COLFUZZY ) >= pCell->getFrameArea().Left() &&
1039  ( rUnion.Right() + COLFUZZY ) < pCell->getFrameArea().Right() )
1040  {
1041  sal_uInt16 nInsPos = pBox->GetUpper()->GetBoxPos( pBox )+1;
1042  lcl_InsTableBox( pTableNd, pDoc, pBox, nInsPos, 2 );
1043  pBox->ClaimFrameFormat();
1044  SwFormatFrameSize aNew(
1045  pBox->GetFrameFormat()->GetFrameSize() );
1046  tools::Long nLeft = rUnion.Left() - pCell->getFrameArea().Left();
1047  nLeft = nLeft * aNew.GetWidth() /
1048  pCell->getFrameArea().Width();
1049  tools::Long nRight = pCell->getFrameArea().Right() - rUnion.Right();
1050  nRight = nRight * aNew.GetWidth() /
1051  pCell->getFrameArea().Width();
1052  nWidth = aNew.GetWidth() - nLeft - nRight;
1053 
1054  aNew.SetWidth( nLeft );
1055  pBox->GetFrameFormat()->SetFormatAttr( aNew );
1056 
1057  if( const SvxBoxItem* pItem = pBox->GetFrameFormat()->GetAttrSet()
1058  .GetItemIfSet( RES_BOX, false ))
1059  {
1060  SvxBoxItem aBox( *pItem );
1061  aBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
1062  pBox->GetFrameFormat()->SetFormatAttr( aBox );
1063  }
1064 
1065  pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1066  aNew.SetWidth( nWidth );
1067  pBox->ClaimFrameFormat();
1068  pBox->GetFrameFormat()->SetFormatAttr( aNew );
1069 
1070  if( pUndo )
1071  pUndo->AddNewBox( pBox->GetSttIdx() );
1072 
1073  // this box is selected
1074  pLastBox = pBox;
1075  rBoxes.insert( pBox );
1076  aPosArr.insert(
1077  CmpLPt( aRectFnSet.GetPos(pCell->getFrameArea()),
1078  pBox, aRectFnSet.IsVert() ) );
1079 
1080  pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos+1 ];
1081  aNew.SetWidth( nRight );
1082  pBox->ClaimFrameFormat();
1083  pBox->GetFrameFormat()->SetFormatAttr( aNew );
1084 
1085  if( pUndo )
1086  pUndo->AddNewBox( pBox->GetSttIdx() );
1087  }
1088  // is right side of box part of the selected area?
1089  else if( ( pCell->getFrameArea().Right() - COLFUZZY ) < rUnion.Right() &&
1090  ( pCell->getFrameArea().Right() - COLFUZZY ) > rUnion.Left() &&
1091  ( pCell->getFrameArea().Left() + COLFUZZY ) < rUnion.Left() )
1092  {
1093  // then we should insert a new box and adjust the widths
1094  sal_uInt16 nInsPos = pBox->GetUpper()->GetBoxPos( pBox )+1;
1095  lcl_InsTableBox( pTableNd, pDoc, pBox, nInsPos );
1096 
1097  SwFormatFrameSize aNew(pBox->GetFrameFormat()->GetFrameSize() );
1098  tools::Long nLeft = rUnion.Left() - pCell->getFrameArea().Left(),
1099  nRight = pCell->getFrameArea().Right() - rUnion.Left();
1100 
1101  nLeft = nLeft * aNew.GetWidth() /
1102  pCell->getFrameArea().Width();
1103  nRight = nRight * aNew.GetWidth() /
1104  pCell->getFrameArea().Width();
1105 
1106  aNew.SetWidth( nLeft );
1107  pBox->ClaimFrameFormat()->SetFormatAttr( aNew );
1108 
1109  // this box is selected
1110  pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ];
1111  aNew.SetWidth( nRight );
1112  pBox->ClaimFrameFormat();
1113  pBox->GetFrameFormat()->SetFormatAttr( aNew );
1114 
1115  pLastBox = pBox;
1116  rBoxes.insert( pBox );
1117  aPosArr.insert( CmpLPt( Point( rUnion.Left(),
1118  pCell->getFrameArea().Top()), pBox, aRectFnSet.IsVert() ));
1119 
1120  if( pUndo )
1121  pUndo->AddNewBox( pBox->GetSttIdx() );
1122  }
1123  }
1124  if ( pCell->GetNext() )
1125  {
1126  pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
1127  // --> Check if table cell is not empty
1128  if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
1129  pCell = pCell->FirstCell();
1130  }
1131  else
1132  pCell = ::lcl_FindNextCellFrame( pCell );
1133  }
1134  }
1135  pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
1136  }
1137  }
1138 
1139  // no SSelection / no boxes found
1140  if( 1 >= rBoxes.size() )
1141  return;
1142 
1143  // now search all horizontally adjacent boxes and connect
1144  // their contents with blanks. All vertically adjacent will be tied
1145  // together as paragraphs
1146 
1147  // 1. Solution: map array and all on same Y-level
1148  // are separated with blanks
1149  // all others are separated with paragraphs
1150  bool bCalcWidth = true;
1151  const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox;
1152 
1153  // JP 27.03.98: Optimise - if boxes on one row are empty,
1154  // then do not insert blanks or carriage returns
1155  //Block to assure SwPaM, SwPosition are deleted from stack
1156  {
1157  SwPaM aPam( pDoc->GetNodes() );
1158 
1159 #if defined( DEL_ONLY_EMPTY_LINES )
1160  nWidth = pFirstBox->GetFrameFormat()->GetFrameSize().GetWidth();
1161  bool bEmptyLine = sal_True;
1162  sal_uInt16 n, nSttPos = 0;
1163 
1164  for( n = 0; n < aPosArr.Count(); ++n )
1165  {
1166  const CmpLPt& rPt = aPosArr[ n ];
1167  if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // same Y level?
1168  {
1169  if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam ))
1170  bEmptyLine = sal_False;
1171  if( bCalcWidth )
1172  nWidth += rPt.pSelBox->GetFrameFormat()->GetFrameSize().GetWidth();
1173  }
1174  else
1175  {
1176  if( bCalcWidth && n )
1177  bCalcWidth = false; // one line is ready
1178 
1179  if( bEmptyLine && nSttPos < n )
1180  {
1181  // now complete line is empty and should not
1182  // be filled with blanks and be inserted as paragraph
1183  if( pUndo )
1184  for( sal_uInt16 i = nSttPos; i < n; ++i )
1185  pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1186 
1187  aPosArr.Remove( nSttPos, n - nSttPos );
1188  n = nSttPos;
1189  }
1190  else
1191  nSttPos = n;
1192 
1193  bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam );
1194  }
1195  }
1196  if( bEmptyLine && nSttPos < n )
1197  {
1198  if( pUndo )
1199  for( sal_uInt16 i = nSttPos; i < n; ++i )
1200  pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1201  aPosArr.Remove( nSttPos, n - nSttPos );
1202  }
1203 #elif defined( DEL_EMPTY_BOXES_AT_START_AND_END )
1204 
1205  nWidth = pFirstBox->GetFrameFormat()->GetFrameSize().GetWidth();
1206  sal_uInt16 n, nSttPos = 0, nSEndPos = 0, nESttPos = 0;
1207 
1208  for( n = 0; n < aPosArr.Count(); ++n )
1209  {
1210  const CmpLPt& rPt = aPosArr[ n ];
1211  if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // same Y level?
1212  {
1213  bool bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam );
1214  if( bEmptyBox )
1215  {
1216  if( nSEndPos == n ) // beginning is empty
1217  nESttPos = ++nSEndPos;
1218  }
1219  else // end could be empty
1220  nESttPos = n+1;
1221 
1222  if( bCalcWidth )
1223  nWidth += rPt.pSelBox->GetFrameFormat()->GetFrameSize().GetWidth();
1224  }
1225  else
1226  {
1227  if( bCalcWidth && n )
1228  bCalcWidth = false; // one line ready
1229 
1230  // first those at the beginning
1231  if( nSttPos < nSEndPos )
1232  {
1233  // now the beginning of the line is empty and should
1234  // not be filled with blanks
1235  if( pUndo )
1236  for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
1237  pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1238 
1239  sal_uInt16 nCnt = nSEndPos - nSttPos;
1240  aPosArr.Remove( nSttPos, nCnt );
1241  nESttPos -= nCnt;
1242  n -= nCnt;
1243  }
1244 
1245  if( nESttPos < n )
1246  {
1247  // now the beginning of the line is empty and should
1248  // not be filled with blanks
1249  if( pUndo )
1250  for( sal_uInt16 i = nESttPos; i < n; ++i )
1251  pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1252 
1253  sal_uInt16 nCnt = n - nESttPos;
1254  aPosArr.Remove( nESttPos, nCnt );
1255  n -= nCnt;
1256  }
1257 
1258  nSttPos = nSEndPos = nESttPos = n;
1259  if( IsEmptyBox( *aPosArr[n].pSelBox, aPam ))
1260  ++nSEndPos;
1261  else
1262  ++nESttPos;
1263  }
1264  }
1265 
1266  // first those at the beginning
1267  if( nSttPos < nSEndPos )
1268  {
1269  // now the beginning of the line is empty and should
1270  // not be filled with blanks
1271  if( pUndo )
1272  for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
1273  pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1274 
1275  sal_uInt16 nCnt = nSEndPos - nSttPos;
1276  aPosArr.Remove( nSttPos, nCnt );
1277  nESttPos -= nCnt;
1278  n -= nCnt;
1279  }
1280  if( nESttPos < n )
1281  {
1282  // now the beginning of the line is empty and should
1283  // not be filled with blanks
1284  if( pUndo )
1285  for( sal_uInt16 i = nESttPos; i < n; ++i )
1286  pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
1287 
1288  sal_uInt16 nCnt = n - nESttPos;
1289  aPosArr.Remove( nESttPos, nCnt );
1290  }
1291 #else
1292 // DEL_ALL_EMPTY_BOXES
1293 
1294  nWidth = 0;
1295  tools::Long nY = !aPosArr.empty() ?
1296  ( aRectFnSet.IsVert() ?
1297  aPosArr[ 0 ].X() :
1298  aPosArr[ 0 ].Y() ) :
1299  0;
1300 
1301  for( MergePos::size_type n = 0; n < aPosArr.size(); ++n )
1302  {
1303  const CmpLPt& rPt = aPosArr[ n ];
1304  if( bCalcWidth )
1305  {
1306  if( nY == ( aRectFnSet.IsVert() ? rPt.X() : rPt.Y() ) ) // same Y level?
1307  nWidth += rPt.pSelBox->GetFrameFormat()->GetFrameSize().GetWidth();
1308  else
1309  bCalcWidth = false; // one line ready
1310  }
1311 
1312  if( IsEmptyBox( *rPt.pSelBox, aPam ) )
1313  {
1314  if( pUndo )
1315  pUndo->SaveCollection( *rPt.pSelBox );
1316 
1317  aPosArr.erase( aPosArr.begin() + n );
1318  --n;
1319  }
1320  }
1321 #endif
1322  }
1323 
1324  // first create new box
1325  {
1326  SwTableBox* pTmpBox = rBoxes[0];
1327  SwTableLine* pInsLine = pTmpBox->GetUpper();
1328  sal_uInt16 nInsPos = pInsLine->GetBoxPos( pTmpBox );
1329 
1330  lcl_InsTableBox( pTableNd, pDoc, pTmpBox, nInsPos );
1331  (*ppMergeBox) = pInsLine->GetTabBoxes()[ nInsPos ];
1332  pInsLine->GetTabBoxes().erase( pInsLine->GetTabBoxes().begin() + nInsPos ); // remove again
1333  (*ppMergeBox)->SetUpper( nullptr );
1334  (*ppMergeBox)->ClaimFrameFormat();
1335 
1336  // define the border: the upper/left side of the first box,
1337  // the lower/right side of the last box:
1338  if( pLastBox && pFirstBox )
1339  {
1340  SvxBoxItem aBox( pFirstBox->GetFrameFormat()->GetBox() );
1341  const SvxBoxItem& rBox = pLastBox->GetFrameFormat()->GetBox();
1342  aBox.SetLine( rBox.GetRight(), SvxBoxItemLine::RIGHT );
1343  aBox.SetLine( rBox.GetBottom(), SvxBoxItemLine::BOTTOM );
1344  if( aBox.GetLeft() || aBox.GetTop() ||
1345  aBox.GetRight() || aBox.GetBottom() )
1346  (*ppMergeBox)->GetFrameFormat()->SetFormatAttr( aBox );
1347  }
1348  }
1349 
1350  //Block to delete SwPaM, SwPosition from stack
1351  if( !aPosArr.empty() )
1352  {
1353  SwPosition aInsPos( *(*ppMergeBox)->GetSttNd() );
1354  SwNodeIndex& rInsPosNd = aInsPos.nNode;
1355 
1356  SwPaM aPam( aInsPos );
1357 
1358  for( const auto &rPt : aPosArr )
1359  {
1360  aPam.GetPoint()->nNode.Assign( *rPt.pSelBox->GetSttNd()->
1361  EndOfSectionNode(), SwNodeOffset(-1) );
1362  SwContentNode* pCNd = aPam.GetContentNode();
1363  aPam.GetPoint()->nContent.Assign( pCNd, pCNd ? pCNd->Len() : 0 );
1364 
1365  SwNodeIndex aSttNdIdx( *rPt.pSelBox->GetSttNd(), 1 );
1366  // one node should be kept in the box (otherwise the
1367  // section would be deleted during a move)
1368  bool const bUndo(pDoc->GetIDocumentUndoRedo().DoesUndo());
1369  if( pUndo )
1370  {
1371  pDoc->GetIDocumentUndoRedo().DoUndo(false);
1372  }
1374  if( pUndo )
1375  {
1376  pDoc->GetIDocumentUndoRedo().DoUndo(bUndo);
1377  }
1378  SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode );
1379  ++rInsPosNd;
1380  if( pUndo )
1381  pUndo->MoveBoxContent( *pDoc, aRg, rInsPosNd );
1382  else
1383  {
1384  pDoc->getIDocumentContentOperations().MoveNodeRange( aRg, rInsPosNd,
1386  }
1387  // where is now aInsPos ??
1388 
1389  if( bCalcWidth )
1390  bCalcWidth = false; // one line is ready
1391 
1392  // skip the first TextNode
1393  rInsPosNd.Assign( pDoc->GetNodes(),
1394  rInsPosNd.GetNode().EndOfSectionIndex() - 2 );
1395  SwTextNode* pTextNd = rInsPosNd.GetNode().GetTextNode();
1396  if( pTextNd )
1397  aInsPos.nContent.Assign(pTextNd, pTextNd->GetText().getLength());
1398  }
1399 
1400  // the MergeBox should contain the complete text
1401  // now erase the initial TextNode
1402  OSL_ENSURE( (*ppMergeBox)->GetSttIdx()+2 <
1403  (*ppMergeBox)->GetSttNd()->EndOfSectionIndex(),
1404  "empty box" );
1405  SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 );
1406  pDoc->GetNodes().Delete( aIdx );
1407  }
1408 
1409  // set width of the box
1410  (*ppMergeBox)->GetFrameFormat()->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nWidth, 0 ));
1411  if( pUndo )
1412  pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() );
1413 }
1414 
1415 static bool lcl_CheckCol(FndBox_ const&, bool* pPara);
1416 
1417 static bool lcl_CheckRow( const FndLine_& rFndLine, bool* pPara )
1418 {
1419  for (auto const& it : rFndLine.GetBoxes())
1420  {
1421  lcl_CheckCol(*it, pPara);
1422  }
1423  return *pPara;
1424 }
1425 
1426 static bool lcl_CheckCol( FndBox_ const& rFndBox, bool* pPara )
1427 {
1428  if (!rFndBox.GetBox()->GetSttNd())
1429  {
1430  if (rFndBox.GetLines().size() !=
1431  rFndBox.GetBox()->GetTabLines().size())
1432  {
1433  *pPara = false;
1434  }
1435  else
1436  {
1437  for (auto const& rpFndLine : rFndBox.GetLines())
1438  {
1439  lcl_CheckRow( *rpFndLine, pPara );
1440  }
1441  }
1442  }
1443  // is box protected ??
1444  else if (rFndBox.GetBox()->GetFrameFormat()->GetProtect().IsContentProtected())
1445  *pPara = false;
1446  return *pPara;
1447 }
1448 
1450 {
1451  SwSelBoxes aBoxes;
1452 //JP 24.09.96: Merge with repeating TableHeadLines does not work properly.
1453 // Why not use point 0,0? Then it is assured the first
1454 // headline is contained.
1455 
1456  Point aPt;
1457  const SwContentNode* pCntNd = rPam.GetContentNode();
1458  std::pair<Point, bool> tmp(aPt, true);
1459  const SwLayoutFrame *const pStart = pCntNd->getLayoutFrame(
1461  nullptr, &tmp)->GetUpper();
1462  pCntNd = rPam.GetContentNode(false);
1463  const SwLayoutFrame *const pEnd = pCntNd->getLayoutFrame(
1465  nullptr, &tmp)->GetUpper();
1466  GetTableSel( pStart, pEnd, aBoxes, nullptr );
1467  return CheckMergeSel( aBoxes );
1468 }
1469 
1471 {
1473  if( !rBoxes.empty() )
1474  {
1475  eRet = TableMergeErr::Ok;
1476 
1477  FndBox_ aFndBox( nullptr, nullptr );
1478  FndPara aPara( rBoxes, &aFndBox );
1479  const SwTableNode* pTableNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode();
1480  ForEach_FndLineCopyCol( const_cast<SwTableLines&>(pTableNd->GetTable().GetTabLines()), &aPara );
1481  if( !aFndBox.GetLines().empty() )
1482  {
1483  bool bMergeSelOk = true;
1484  FndBox_* pFndBox = &aFndBox;
1485  FndLine_* pFndLine = nullptr;
1486  while( pFndBox && 1 == pFndBox->GetLines().size() )
1487  {
1488  pFndLine = pFndBox->GetLines().front().get();
1489  if( 1 == pFndLine->GetBoxes().size() )
1490  pFndBox = pFndLine->GetBoxes().front().get();
1491  else
1492  pFndBox = nullptr;
1493  }
1494  if( pFndBox )
1495  {
1496  for (auto const& it : pFndBox->GetLines())
1497  {
1498  lcl_CheckRow(*it, &bMergeSelOk);
1499  }
1500  }
1501  else if( pFndLine )
1502  {
1503  for (auto const& it : pFndLine->GetBoxes())
1504  {
1505  lcl_CheckCol(*it, &bMergeSelOk);
1506  }
1507  }
1508  if( !bMergeSelOk )
1510  }
1511  else
1513  }
1514  return eRet;
1515 }
1516 
1517 static SwTwips lcl_CalcWish( const SwLayoutFrame *pCell, tools::Long nWish,
1518  const tools::Long nAct )
1519 {
1520  const SwLayoutFrame *pTmp = pCell;
1521  if ( !nWish )
1522  nWish = 1;
1523 
1524  const bool bRTL = pCell->IsRightToLeft();
1525  SwTwips nRet = bRTL ?
1526  nAct - pCell->getFrameArea().Width() :
1527  0;
1528 
1529  while ( pTmp )
1530  {
1531  while ( pTmp->GetPrev() )
1532  {
1533  pTmp = static_cast<const SwLayoutFrame*>(pTmp->GetPrev());
1534  sal_Int64 nTmp = pTmp->GetFormat()->GetFrameSize().GetWidth();
1535  // multiply in 64-bit to avoid overflow here!
1536  nRet += ( bRTL ? -1 : 1 ) * nTmp * nAct / nWish;
1537  }
1538  pTmp = pTmp->GetUpper()->GetUpper();
1539  if ( pTmp && !pTmp->IsCellFrame() )
1540  pTmp = nullptr;
1541  }
1542  return nRet;
1543 }
1544 
1545 static void lcl_FindStartEndRow( const SwLayoutFrame *&rpStart,
1546  const SwLayoutFrame *&rpEnd,
1547  const bool bChkProtected )
1548 {
1549  // Put Start at beginning of a row.
1550  // Put End at the end of its row.
1551  rpStart = static_cast<const SwLayoutFrame*>(rpStart->GetUpper()->Lower());
1552  while ( rpEnd->GetNext() )
1553  rpEnd = static_cast<const SwLayoutFrame*>(rpEnd->GetNext());
1554 
1555  std::deque<const SwLayoutFrame *> aSttArr, aEndArr;
1556  const SwLayoutFrame *pTmp;
1557  for( pTmp = rpStart; (SwFrameType::Cell|SwFrameType::Row) & pTmp->GetType();
1558  pTmp = pTmp->GetUpper() )
1559  {
1560  aSttArr.push_front( pTmp );
1561  }
1562  for( pTmp = rpEnd; (SwFrameType::Cell|SwFrameType::Row) & pTmp->GetType();
1563  pTmp = pTmp->GetUpper() )
1564  {
1565  aEndArr.push_front( pTmp );
1566  }
1567 
1568  for( std::deque<const SwLayoutFrame *>::size_type n = 0; n < aEndArr.size() && n < aSttArr.size(); ++n )
1569  if( aSttArr[ n ] != aEndArr[ n ] )
1570  {
1571  // first unequal line or box - all odds are
1572  if( n & 1 ) // 1, 3, 5, ... are boxes
1573  {
1574  rpStart = aSttArr[ n ];
1575  rpEnd = aEndArr[ n ];
1576  }
1577  else // 0, 2, 4, ... are lines
1578  {
1579  // check if start & end line are the first & last Line of the
1580  // box. If not return these cells.
1581  // Else the whole line with all Boxes has to be deleted.
1582  rpStart = aSttArr[ n+1 ];
1583  rpEnd = aEndArr[ n+1 ];
1584  if( n )
1585  {
1586  const SwCellFrame* pCellFrame = static_cast<const SwCellFrame*>(aSttArr[ n-1 ]);
1587  const SwTableLines& rLns = pCellFrame->
1588  GetTabBox()->GetTabLines();
1589  if( rLns[ 0 ] == static_cast<const SwRowFrame*>(aSttArr[ n ])->GetTabLine() &&
1590  rLns[ rLns.size() - 1 ] ==
1591  static_cast<const SwRowFrame*>(aEndArr[ n ])->GetTabLine() )
1592  {
1593  rpStart = rpEnd = pCellFrame;
1594  while ( rpStart->GetPrev() )
1595  rpStart = static_cast<const SwLayoutFrame*>(rpStart->GetPrev());
1596  while ( rpEnd->GetNext() )
1597  rpEnd = static_cast<const SwLayoutFrame*>(rpEnd->GetNext());
1598  }
1599  }
1600  }
1601  break;
1602  }
1603 
1604  if( !bChkProtected ) // protected cell ?
1605  return;
1606 
1607  // Beginning and end should not be in protected cells
1608  while ( rpStart->GetFormat()->GetProtect().IsContentProtected() )
1609  rpStart = static_cast<const SwLayoutFrame*>(rpStart->GetNext());
1610  while ( rpEnd->GetFormat()->GetProtect().IsContentProtected() )
1611  rpEnd = static_cast<const SwLayoutFrame*>(rpEnd->GetPrev());
1612 }
1613 
1614 static void lcl_FindStartEndCol( const SwLayoutFrame *&rpStart,
1615  const SwLayoutFrame *&rpEnd,
1616  const bool bChkProtected )
1617 {
1618  // Beginning and end vertical till the border of the table;
1619  // Consider the whole table, including master and follows.
1620  // In order to start we need the mother-tableFrame
1621  if( !rpStart )
1622  return;
1623  const SwTabFrame *pOrg = rpStart->FindTabFrame();
1624  const SwTabFrame *pTab = pOrg;
1625 
1626  SwRectFnSet aRectFnSet(pTab);
1627 
1628  bool bRTL = pTab->IsRightToLeft();
1629  const tools::Long nTmpWish = pOrg->GetFormat()->GetFrameSize().GetWidth();
1630  const tools::Long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1;
1631 
1632  while ( pTab->IsFollow() )
1633  {
1634  const SwFrame *pTmp = pTab->FindPrev();
1635  OSL_ENSURE( pTmp->IsTabFrame(), "Predecessor of Follow is not Master." );
1636  pTab = static_cast<const SwTabFrame*>(pTmp);
1637  }
1638 
1639  SwTwips nSX = 0;
1640  SwTwips nSX2 = 0;
1641 
1642  if ( pTab->GetTable()->IsNewModel() )
1643  {
1644  nSX = aRectFnSet.GetLeft(rpStart->getFrameArea());
1645  nSX2 = aRectFnSet.GetRight(rpStart->getFrameArea());
1646  }
1647  else
1648  {
1649  const SwTwips nPrtWidth = aRectFnSet.GetWidth(pTab->getFramePrintArea());
1650  nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + aRectFnSet.GetPrtLeft(*pTab);
1651  nSX2 = nSX + (rpStart->GetFormat()->GetFrameSize().GetWidth() * nPrtWidth / nWish);
1652  }
1653 
1654  const SwLayoutFrame *pTmp = pTab->FirstCell();
1655 
1656  while ( pTmp &&
1657  (!pTmp->IsCellFrame() ||
1658  ( ( ! bRTL && aRectFnSet.GetLeft(pTmp->getFrameArea()) < nSX &&
1659  aRectFnSet.GetRight(pTmp->getFrameArea())< nSX2 ) ||
1660  ( bRTL && aRectFnSet.GetLeft(pTmp->getFrameArea()) > nSX &&
1661  aRectFnSet.GetRight(pTmp->getFrameArea())> nSX2 ) ) ) )
1662  pTmp = pTmp->GetNextLayoutLeaf();
1663 
1664  if ( pTmp )
1665  rpStart = pTmp;
1666 
1667  pTab = pOrg;
1668 
1669  const SwTabFrame* pLastValidTab = pTab;
1670  while ( pTab->GetFollow() )
1671  {
1672 
1673  // Check if pTab->GetFollow() is a valid follow table:
1674  // Only follow tables with at least on non-FollowFlowLine
1675  // should be considered.
1676 
1677  if ( pTab->HasFollowFlowLine() )
1678  {
1679  pTab = pTab->GetFollow();
1680  const SwFrame* pTmpRow = pTab->GetFirstNonHeadlineRow();
1681  if ( pTmpRow && pTmpRow->GetNext() )
1682  pLastValidTab = pTab;
1683  }
1684  else
1685  pLastValidTab = pTab = pTab->GetFollow();
1686  }
1687  pTab = pLastValidTab;
1688 
1689  SwTwips nEX = 0;
1690 
1691  if ( pTab->GetTable()->IsNewModel() )
1692  {
1693  nEX = aRectFnSet.GetLeft(rpEnd->getFrameArea());
1694  }
1695  else
1696  {
1697  const SwTwips nPrtWidth = aRectFnSet.GetWidth(pTab->getFramePrintArea());
1698  nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + aRectFnSet.GetPrtLeft(*pTab);
1699  }
1700 
1701  SwFrame const*const pLastContent = pTab->FindLastContentOrTable();
1702  rpEnd = pLastContent ? pLastContent->GetUpper() : nullptr;
1703  // --> Made code robust. If pTab does not have a lower,
1704  // we would crash here.
1705  if ( !pLastContent ) return;
1706 
1707  while( !rpEnd->IsCellFrame() )
1708  rpEnd = rpEnd->GetUpper();
1709 
1710  while ( ( bRTL && aRectFnSet.GetLeft(rpEnd->getFrameArea()) < nEX ) ||
1711  ( ! bRTL && aRectFnSet.GetLeft(rpEnd->getFrameArea()) > nEX ) )
1712  {
1713  const SwLayoutFrame* pTmpLeaf = rpEnd->GetPrevLayoutLeaf();
1714  if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) )
1715  break;
1716  rpEnd = pTmpLeaf;
1717  }
1718 
1719  if( !bChkProtected ) // check for protected cell ?
1720  return;
1721 
1722  // Beginning and end should not be in protected cells.
1723  // If necessary we should search backwards again
1724  while ( rpStart->GetFormat()->GetProtect().IsContentProtected() )
1725  {
1726  const SwLayoutFrame *pTmpLeaf = rpStart->GetNextLayoutLeaf();
1727  while ( pTmpLeaf && aRectFnSet.GetLeft(pTmpLeaf->getFrameArea()) > nEX ) // first skip line
1728  pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1729  while ( pTmpLeaf && aRectFnSet.GetLeft(pTmpLeaf->getFrameArea()) < nSX &&
1730  aRectFnSet.GetRight(pTmpLeaf->getFrameArea())< nSX2 )
1731  pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf();
1732  const SwTabFrame *pTmpTab = rpStart->FindTabFrame();
1733  if ( !pTmpTab->IsAnLower( pTmpLeaf ) )
1734  {
1735  pTmpTab = pTmpTab->GetFollow();
1736  rpStart = pTmpTab->FirstCell();
1737  while ( rpStart &&
1738  aRectFnSet.GetLeft(rpStart->getFrameArea()) < nSX &&
1739  aRectFnSet.GetRight(rpStart->getFrameArea())< nSX2 )
1740  rpStart = rpStart->GetNextLayoutLeaf();
1741  }
1742  else
1743  rpStart = pTmpLeaf;
1744  }
1745  while ( rpEnd->GetFormat()->GetProtect().IsContentProtected() )
1746  {
1747  const SwLayoutFrame *pTmpLeaf = rpEnd->GetPrevLayoutLeaf();
1748  while ( pTmpLeaf && aRectFnSet.GetLeft(pTmpLeaf->getFrameArea()) < nEX ) // skip the line for now
1749  pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1750  while ( pTmpLeaf && aRectFnSet.GetLeft(pTmpLeaf->getFrameArea()) > nEX )
1751  pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf();
1752  const SwTabFrame *pTmpTab = rpEnd->FindTabFrame();
1753  if ( !pTmpLeaf || !pTmpTab->IsAnLower( pTmpLeaf ) )
1754  {
1755  pTmpTab = static_cast<const SwTabFrame*>(pTmpTab->FindPrev());
1756  OSL_ENSURE( pTmpTab->IsTabFrame(), "Predecessor of Follow not Master.");
1757  rpEnd = pTmpTab->FindLastContentOrTable()->GetUpper();
1758  while( !rpEnd->IsCellFrame() )
1759  rpEnd = rpEnd->GetUpper();
1760  while ( aRectFnSet.GetLeft(rpEnd->getFrameArea()) > nEX )
1761  rpEnd = rpEnd->GetPrevLayoutLeaf();
1762  }
1763  else
1764  rpEnd = pTmpLeaf;
1765  }
1766 }
1767 
1768 void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrame *pStart,
1769  const SwLayoutFrame *pEnd, const SwTableSearchType eSearchType )
1770 {
1771  while ( pStart && !pStart->IsCellFrame() )
1772  pStart = pStart->GetUpper();
1773  while ( pEnd && !pEnd->IsCellFrame() )
1774  pEnd = pEnd->GetUpper();
1775 
1776  if ( !pStart || !pEnd )
1777  {
1778  OSL_FAIL( "MakeSelUnions with pStart or pEnd not in CellFrame" );
1779  return;
1780  }
1781 
1782  const SwTabFrame *pTable = pStart->FindTabFrame();
1783  const SwTabFrame *pEndTable = pEnd->FindTabFrame();
1784  if( !pTable || !pEndTable )
1785  return;
1786  bool bExchange = false;
1787 
1788  if ( pTable != pEndTable )
1789  {
1790  if ( !pTable->IsAnFollow( pEndTable ) )
1791  {
1792  OSL_ENSURE( pEndTable->IsAnFollow( pTable ), "Tabchain in knots." );
1793  bExchange = true;
1794  }
1795  }
1796  else
1797  {
1798  SwRectFnSet aRectFnSet(pTable);
1799  tools::Long nSttTop = aRectFnSet.GetTop(pStart->getFrameArea());
1800  tools::Long nEndTop = aRectFnSet.GetTop(pEnd->getFrameArea());
1801  if( nSttTop == nEndTop )
1802  {
1803  if( aRectFnSet.GetLeft(pStart->getFrameArea()) >
1804  aRectFnSet.GetLeft(pEnd->getFrameArea()) )
1805  bExchange = true;
1806  }
1807  else if( aRectFnSet.IsVert() == ( nSttTop < nEndTop ) )
1808  bExchange = true;
1809  }
1810  if ( bExchange )
1811  {
1812  const SwLayoutFrame *pTmp = pStart;
1813  pStart = pEnd;
1814  pEnd = pTmp;
1815  // do no resort pTable and pEndTable, set new below
1816  // MA: 28. Dec. 93 Bug: 5190
1817  }
1818 
1819  // Beginning and end now nicely sorted, if required we
1820  // should move them
1821  if( SwTableSearchType::Row == ((~SwTableSearchType::Protect ) & eSearchType ) )
1822  ::lcl_FindStartEndRow( pStart, pEnd, bool(SwTableSearchType::Protect & eSearchType) );
1823  else if( SwTableSearchType::Col == ((~SwTableSearchType::Protect ) & eSearchType ) )
1824  ::lcl_FindStartEndCol( pStart, pEnd, bool(SwTableSearchType::Protect & eSearchType) );
1825 
1826  if ( !pEnd || !pStart ) return; // Made code robust.
1827 
1828  // retrieve again, as they have been moved
1829  pTable = pStart->FindTabFrame();
1830  pEndTable = pEnd->FindTabFrame();
1831 
1832  const tools::Long nStSz = pStart->GetFormat()->GetFrameSize().GetWidth();
1833  const tools::Long nEdSz = pEnd->GetFormat()->GetFrameSize().GetWidth();
1834  const tools::Long nWish = std::max( tools::Long(1), pTable->GetFormat()->GetFrameSize().GetWidth() );
1835  while ( pTable )
1836  {
1837  SwRectFnSet aRectFnSet(pTable);
1838  const tools::Long nOfst = aRectFnSet.GetPrtLeft(*pTable);
1839  const tools::Long nPrtWidth = aRectFnSet.GetWidth(pTable->getFramePrintArea());
1840  tools::Long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst;
1841  tools::Long nEd1 = ::lcl_CalcWish( pEnd, nWish, nPrtWidth ) + nOfst;
1842 
1843  if ( nSt1 <= nEd1 )
1844  nEd1 += static_cast<tools::Long>((nEdSz * nPrtWidth) / nWish) - 1;
1845  else
1846  nSt1 += static_cast<tools::Long>((nStSz * nPrtWidth) / nWish) - 1;
1847 
1848  tools::Long nSt2;
1849  tools::Long nEd2;
1850  if( pTable->IsAnLower( pStart ) )
1851  nSt2 = aRectFnSet.GetTop(pStart->getFrameArea());
1852  else
1853  nSt2 = aRectFnSet.GetTop(pTable->getFrameArea());
1854  if( pTable->IsAnLower( pEnd ) )
1855  nEd2 = aRectFnSet.GetBottom(pEnd->getFrameArea());
1856  else
1857  nEd2 = aRectFnSet.GetBottom(pTable->getFrameArea());
1858  Point aSt, aEd;
1859  if( nSt1 > nEd1 )
1860  {
1861  tools::Long nTmp = nSt1;
1862  nSt1 = nEd1;
1863  nEd1 = nTmp;
1864  }
1865  if( nSt2 > nEd2 )
1866  {
1867  tools::Long nTmp = nSt2;
1868  nSt2 = nEd2;
1869  nEd2 = nTmp;
1870  }
1871  if( aRectFnSet.IsVert() )
1872  {
1873  aSt = Point( nSt2, nSt1 );
1874  aEd = Point( nEd2, nEd1 );
1875  }
1876  else
1877  {
1878  aSt = Point( nSt1, nSt2 );
1879  aEd = Point( nEd1, nEd2 );
1880  }
1881 
1882  const Point aDiff( aEd - aSt );
1883  SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) );
1884  aUnion.Justify();
1885 
1886  if( !(SwTableSearchType::NoUnionCorrect & eSearchType ))
1887  {
1888  // Unfortunately the union contains rounding errors now, therefore
1889  // erroneous results could occur during split/merge.
1890  // To prevent these we will determine the first and last row
1891  // within the union and use their values for a new union
1892  const SwLayoutFrame* pRow = pTable->IsFollow() ?
1893  pTable->GetFirstNonHeadlineRow() :
1894  static_cast<const SwLayoutFrame*>(pTable->Lower());
1895 
1896  while ( pRow && !pRow->getFrameArea().Overlaps( aUnion ) )
1897  pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
1898 
1899  // #i31976#
1900  // A follow flow row may contain empty cells. These are not
1901  // considered by FirstCell(). Therefore we have to find
1902  // the first cell manually:
1903  const SwFrame* pTmpCell = nullptr;
1904  if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() )
1905  {
1906  const SwFrame* pTmpRow = pRow;
1907  while ( pTmpRow && pTmpRow->IsRowFrame() )
1908  {
1909  pTmpCell = static_cast<const SwRowFrame*>(pTmpRow)->Lower();
1910  pTmpRow = static_cast<const SwCellFrame*>(pTmpCell)->Lower();
1911  }
1912  OSL_ENSURE( !pTmpCell || pTmpCell->IsCellFrame(), "Lower of rowframe != cellframe?!" );
1913  }
1914 
1915  const SwLayoutFrame* pFirst = pTmpCell ?
1916  static_cast<const SwLayoutFrame*>(pTmpCell) :
1917  pRow ?
1918  pRow->FirstCell() :
1919  nullptr;
1920 
1921  while ( pFirst && !::IsFrameInTableSel( aUnion, pFirst ) )
1922  {
1923  if ( pFirst->GetNext() )
1924  {
1925  pFirst = static_cast<const SwLayoutFrame*>(pFirst->GetNext());
1926  if ( pFirst->Lower() && pFirst->Lower()->IsRowFrame() )
1927  pFirst = pFirst->FirstCell();
1928  }
1929  else
1930  pFirst = ::lcl_FindNextCellFrame( pFirst );
1931  }
1932  const SwLayoutFrame* pLast = nullptr;
1933  SwFrame const*const pLastContent = pTable->FindLastContentOrTable();
1934  if ( pLastContent )
1935  pLast = ::lcl_FindCellFrame( pLastContent->GetUpper() );
1936 
1937  while ( pLast && !::IsFrameInTableSel( aUnion, pLast ) )
1938  pLast = ::lcl_FindCellFrame( pLast->GetPrevLayoutLeaf() );
1939 
1940  if ( pFirst && pLast ) //Robust
1941  {
1942  aUnion = pFirst->getFrameArea();
1943  aUnion.Union( pLast->getFrameArea() );
1944  }
1945  else
1946  aUnion.Width( 0 );
1947  }
1948 
1949  if( aRectFnSet.GetWidth(aUnion) )
1950  {
1951  rUnions.emplace_back(aUnion, const_cast<SwTabFrame*>(pTable));
1952  }
1953 
1954  pTable = pTable->GetFollow();
1955  if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) )
1956  pTable = nullptr;
1957  }
1958 }
1959 
1960 bool CheckSplitCells( const SwCursorShell& rShell, sal_uInt16 nDiv,
1961  const SwTableSearchType eSearchType )
1962 {
1963  if( !rShell.IsTableMode() )
1964  rShell.GetCursor();
1965 
1966  return CheckSplitCells( *rShell.getShellCursor(false), nDiv, eSearchType );
1967 }
1968 
1969 bool CheckSplitCells( const SwCursor& rCursor, sal_uInt16 nDiv,
1970  const SwTableSearchType eSearchType )
1971 {
1972  if( 1 >= nDiv )
1973  return false;
1974 
1975  sal_uInt16 nMinValue = nDiv * MINLAY;
1976 
1977  // Get start and end cell
1978  Point aPtPos, aMkPos;
1979  const SwShellCursor* pShCursor = dynamic_cast<const SwShellCursor*>(&rCursor);
1980  if( pShCursor )
1981  {
1982  aPtPos = pShCursor->GetPtPos();
1983  aMkPos = pShCursor->GetMkPos();
1984  }
1985 
1986  const SwContentNode* pCntNd = rCursor.GetContentNode();
1987  std::pair<Point, bool> tmp(aPtPos, true);
1988  const SwLayoutFrame *const pStart = pCntNd->getLayoutFrame(
1990  nullptr, &tmp)->GetUpper();
1991  pCntNd = rCursor.GetContentNode(false);
1992  tmp.first = aMkPos;
1993  const SwLayoutFrame *const pEnd = pCntNd->getLayoutFrame(
1995  nullptr, &tmp)->GetUpper();
1996 
1997  SwRectFnSet aRectFnSet(pStart->GetUpper());
1998 
1999  // First, compute tables and rectangles
2000  SwSelUnions aUnions;
2001 
2002  ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType );
2003 
2004  // now search boxes for each entry and emit
2005  for ( const auto& rSelUnion : aUnions )
2006  {
2007  const SwTabFrame *pTable = rSelUnion.GetTable();
2008 
2009  // Skip any repeated headlines in the follow:
2010  const SwLayoutFrame* pRow = pTable->IsFollow() ?
2011  pTable->GetFirstNonHeadlineRow() :
2012  static_cast<const SwLayoutFrame*>(pTable->Lower());
2013 
2014  while ( pRow )
2015  {
2016  if ( pRow->getFrameArea().Overlaps( rSelUnion.GetUnion() ) )
2017  {
2018  const SwLayoutFrame *pCell = pRow->FirstCell();
2019 
2020  while ( pCell && pRow->IsAnLower( pCell ) )
2021  {
2022  OSL_ENSURE( pCell->IsCellFrame(), "Frame without cell" );
2023  if( ::IsFrameInTableSel( rSelUnion.GetUnion(), pCell ) )
2024  {
2025  if( aRectFnSet.GetWidth(pCell->getFrameArea()) < nMinValue )
2026  return false;
2027  }
2028 
2029  if ( pCell->GetNext() )
2030  {
2031  pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext());
2032  if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
2033  pCell = pCell->FirstCell();
2034  }
2035  else
2036  pCell = ::lcl_FindNextCellFrame( pCell );
2037  }
2038  }
2039  pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
2040  }
2041  }
2042  return true;
2043 }
2044 
2045 // These Classes copy the current table selections (rBoxes),
2046 // into a new structure, retaining the table structure
2047 // new: SS for targeted erasing/restoring of the layout
2048 
2049 static void lcl_InsertRow( SwTableLine const &rLine, SwLayoutFrame *pUpper, SwFrame *pSibling )
2050 {
2051  SwRowFrame *pRow = new SwRowFrame( rLine, pUpper );
2052  if ( pUpper->IsTabFrame() && static_cast<SwTabFrame*>(pUpper)->IsFollow() )
2053  {
2054  SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pUpper);
2055  pTabFrame->FindMaster()->InvalidatePos(); //can absorb the line
2056 
2057  if ( pSibling && pTabFrame->IsInHeadline( *pSibling ) )
2058  {
2059  // Skip any repeated headlines in the follow:
2060  pSibling = pTabFrame->GetFirstNonHeadlineRow();
2061  }
2062  }
2063  pRow->Paste( pUpper, pSibling );
2064  pRow->RegistFlys();
2065 }
2066 
2067 static void FndBoxCopyCol( SwTableBox* pBox, FndPara* pFndPara )
2068 {
2069  std::unique_ptr<FndBox_> pFndBox(new FndBox_( pBox, pFndPara->pFndLine ));
2070  if( !pBox->GetTabLines().empty() )
2071  {
2072  FndPara aPara( *pFndPara, pFndBox.get() );
2073  ForEach_FndLineCopyCol( pFndBox->GetBox()->GetTabLines(), &aPara );
2074  if( pFndBox->GetLines().empty() )
2075  {
2076  return;
2077  }
2078  }
2079  else
2080  {
2081  if( pFndPara->rBoxes.find( pBox ) == pFndPara->rBoxes.end())
2082  {
2083  return;
2084  }
2085  }
2086  pFndPara->pFndLine->GetBoxes().push_back( std::move(pFndBox) );
2087 }
2088 
2089 static void FndLineCopyCol( SwTableLine* pLine, FndPara* pFndPara )
2090 {
2091  std::unique_ptr<FndLine_> pFndLine(new FndLine_(pLine, pFndPara->pFndBox));
2092  FndPara aPara(*pFndPara, pFndLine.get());
2093  for( auto& rpBox : pFndLine->GetLine()->GetTabBoxes() )
2094  FndBoxCopyCol(rpBox, &aPara );
2095  if( !pFndLine->GetBoxes().empty() )
2096  {
2097  pFndPara->pFndBox->GetLines().push_back( std::move(pFndLine) );
2098  }
2099 }
2100 
2102 {
2103  for( SwTableLines::iterator it = rLines.begin(); it != rLines.end(); ++it )
2104  FndLineCopyCol( *it, pFndPara );
2105 }
2106 
2107 void FndBox_::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable )
2108 {
2109  // Set pointers to lines before and after the area to process.
2110  // If the first/last lines are contained in the area, then the pointers
2111  // are 0. We first search for the positions of the first/last affected
2112  // lines in array of the SwTable. In order to use 0 for 'no line'
2113  // we adjust the positions by 1.
2114 
2115  sal_uInt16 nStPos = USHRT_MAX;
2116  sal_uInt16 nEndPos= 0;
2117 
2118  for (size_t i = 0; i < rBoxes.size(); ++i)
2119  {
2120  SwTableLine *pLine = rBoxes[i]->GetUpper();
2121  while ( pLine->GetUpper() )
2122  pLine = pLine->GetUpper()->GetUpper();
2123  const sal_uInt16 nPos = rTable.GetTabLines().GetPos(
2124  const_cast<const SwTableLine*&>(pLine) ) + 1;
2125 
2126  OSL_ENSURE( nPos != USHRT_MAX, "TableLine not found." );
2127 
2128  if( nStPos > nPos )
2129  nStPos = nPos;
2130 
2131  if( nEndPos < nPos )
2132  nEndPos = nPos;
2133  }
2134  if (USHRT_MAX != nStPos && nStPos > 1)
2135  m_pLineBefore = rTable.GetTabLines()[nStPos - 2];
2136  if ( nEndPos < rTable.GetTabLines().size() )
2137  m_pLineBehind = rTable.GetTabLines()[nEndPos];
2138 }
2139 
2140 void FndBox_::SetTableLines( const SwTable &rTable )
2141 {
2142  // Set pointers to lines before and after the area to process.
2143  // If the first/last lines are contained in the area, then the pointers
2144  // are 0. The positions of the first/last affected lines in the array
2145  // of the SwTable are in FndBox. In order to use 0 for 'no line'
2146  // we adjust the positions by 1.
2147 
2148  if( GetLines().empty() )
2149  return;
2150 
2151  SwTableLine* pTmpLine = GetLines().front()->GetLine();
2152  sal_uInt16 nPos = rTable.GetTabLines().GetPos( pTmpLine );
2153  OSL_ENSURE( USHRT_MAX != nPos, "Line is not in table" );
2154  if( nPos )
2155  m_pLineBefore = rTable.GetTabLines()[ nPos - 1 ];
2156 
2157  pTmpLine = GetLines().back()->GetLine();
2158  nPos = rTable.GetTabLines().GetPos( pTmpLine );
2159  OSL_ENSURE( USHRT_MAX != nPos, "Line is not in the table" );
2160  if( ++nPos < rTable.GetTabLines().size() )
2161  m_pLineBehind = rTable.GetTabLines()[nPos];
2162 }
2163 
2164 inline void UnsetFollow( SwFlowFrame *pTab )
2165 {
2166  pTab->m_pPrecede = nullptr;
2167 }
2168 
2170 {
2171  // All lines between pLineBefore and pLineBehind should be cut
2172  // from the layout and erased.
2173  // If this creates empty Follows we should destroy these.
2174  // If a master is destroyed, the follow should become master.
2175  // Always a TabFrame should remain.
2176 
2177  sal_uInt16 nStPos = 0;
2178  sal_uInt16 nEndPos= rTable.GetTabLines().size() - 1;
2179  if( rTable.IsNewModel() && m_pLineBefore )
2180  rTable.CheckRowSpan( m_pLineBefore, true );
2181  if ( m_pLineBefore )
2182  {
2183  nStPos = rTable.GetTabLines().GetPos(
2184  const_cast<const SwTableLine*&>(m_pLineBefore) );
2185  OSL_ENSURE( nStPos != USHRT_MAX, "The fox stole the line!" );
2186  ++nStPos;
2187  }
2188  if( rTable.IsNewModel() && m_pLineBehind )
2189  rTable.CheckRowSpan( m_pLineBehind, false );
2190  if ( m_pLineBehind )
2191  {
2192  nEndPos = rTable.GetTabLines().GetPos(
2193  const_cast<const SwTableLine*&>(m_pLineBehind) );
2194  OSL_ENSURE( nEndPos != USHRT_MAX, "The fox stole the line!" );
2195  if (nEndPos != 0)
2196  --nEndPos;
2197  }
2198 
2199  for ( sal_uInt16 i = nStPos; i <= nEndPos; ++i)
2200  {
2201  SwFrameFormat *pFormat = rTable.GetTabLines()[i]->GetFrameFormat();
2202  SwIterator<SwRowFrame,SwFormat> aIter( *pFormat );
2203  for ( SwRowFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
2204  {
2205  if ( pFrame->GetTabLine() == rTable.GetTabLines()[i] )
2206  {
2207  bool bDel = true;
2208  SwTabFrame *pUp = !pFrame->GetPrev() && !pFrame->GetNext() ?
2209  static_cast<SwTabFrame*>(pFrame->GetUpper()) : nullptr;
2210  if ( !pUp )
2211  {
2212  const sal_uInt16 nRepeat =
2213  static_cast<SwTabFrame*>(pFrame->GetUpper())->GetTable()->GetRowsToRepeat();
2214  if ( nRepeat > 0 &&
2215  static_cast<SwTabFrame*>(pFrame->GetUpper())->IsFollow() )
2216  {
2217  if ( !pFrame->GetNext() )
2218  {
2219  SwRowFrame* pFirstNonHeadline =
2220  static_cast<SwTabFrame*>(pFrame->GetUpper())->GetFirstNonHeadlineRow();
2221  if ( pFirstNonHeadline == pFrame )
2222  {
2223  pUp = static_cast<SwTabFrame*>(pFrame->GetUpper());
2224  }
2225  }
2226  }
2227  }
2228  if ( pUp )
2229  {
2230  SwTabFrame *pFollow = pUp->GetFollow();
2231  SwTabFrame *pPrev = pUp->IsFollow() ? pUp : nullptr;
2232  if ( pPrev )
2233  {
2234  SwFrame *pTmp = pPrev->FindPrev();
2235  OSL_ENSURE( pTmp->IsTabFrame(),
2236  "Predecessor of Follow is no Master.");
2237  pPrev = static_cast<SwTabFrame*>(pTmp);
2238  }
2239  if ( pPrev )
2240  {
2241  pPrev->SetFollow( pFollow );
2242  // #i60340# Do not transfer the
2243  // flag from pUp to pPrev. pUp may still have the
2244  // flag set although there is not more follow flow
2245  // line associated with pUp.
2246  pPrev->SetFollowFlowLine( false );
2247  }
2248  else if ( pFollow )
2249  ::UnsetFollow( pFollow );
2250 
2251  // A TableFrame should always remain!
2252  if ( pPrev || pFollow )
2253  {
2254  // OD 26.08.2003 #i18103# - if table is in a section,
2255  // lock the section, to avoid its delete.
2256  {
2257  SwSectionFrame* pSctFrame = pUp->FindSctFrame();
2258  bool bOldSectLock = false;
2259  if ( pSctFrame )
2260  {
2261  bOldSectLock = pSctFrame->IsColLocked();
2262  pSctFrame->ColLock();
2263  }
2264  pUp->Cut();
2265  if ( pSctFrame && !bOldSectLock )
2266  {
2267  pSctFrame->ColUnlock();
2268  }
2269  }
2270  SwFrame::DestroyFrame(pUp);
2271  bDel = false; // Row goes to /dev/null.
2272  }
2273  }
2274  if ( bDel )
2275  {
2276  SwFrame* pTabFrame = pFrame->GetUpper();
2277  if ( pTabFrame->IsTabFrame() &&
2278  !pFrame->GetNext() &&
2279  static_cast<SwTabFrame*>(pTabFrame)->GetFollow() )
2280  {
2281  // We do not delete the follow flow line,
2282  // this will be done automatically in the
2283  // next turn.
2284  static_cast<SwTabFrame*>(pTabFrame)->SetFollowFlowLine( false );
2285  }
2286  pFrame->Cut();
2287  SwFrame::DestroyFrame(pFrame);
2288  }
2289  }
2290  }
2291  }
2292 }
2293 
2294 static bool lcl_IsLineOfTableFrame( const SwTabFrame& rTable, const SwFrame& rChk )
2295 {
2296  const SwTabFrame* pTableFrame = rChk.FindTabFrame();
2297  if( pTableFrame->IsFollow() )
2298  pTableFrame = pTableFrame->FindMaster( true );
2299  return &rTable == pTableFrame;
2300 }
2301 
2302 static void lcl_UpdateRepeatedHeadlines( SwTabFrame& rTabFrame, bool bCalcLowers )
2303 {
2304  OSL_ENSURE( rTabFrame.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" );
2305 
2306  // Delete remaining headlines:
2307  SwRowFrame* pLower = nullptr;
2308  while ( nullptr != ( pLower = static_cast<SwRowFrame*>(rTabFrame.Lower()) ) && pLower->IsRepeatedHeadline() )
2309  {
2310  pLower->Cut();
2311  SwFrame::DestroyFrame(pLower);
2312  }
2313 
2314  // Insert fresh set of headlines:
2315  pLower = static_cast<SwRowFrame*>(rTabFrame.Lower());
2316  SwTable& rTable = *rTabFrame.GetTable();
2317  const sal_uInt16 nRepeat = rTable.GetRowsToRepeat();
2318  for ( sal_uInt16 nIdx = 0; nIdx < nRepeat; ++nIdx )
2319  {
2320  SwRowFrame* pHeadline = new SwRowFrame( *rTable.GetTabLines()[ nIdx ], &rTabFrame );
2321  pHeadline->SetRepeatedHeadline( true );
2322  pHeadline->Paste( &rTabFrame, pLower );
2323  pHeadline->RegistFlys();
2324  }
2325 
2326  if ( bCalcLowers )
2327  rTabFrame.SetCalcLowers();
2328 }
2329 
2331 {
2332  // All lines between pLineBefore and pLineBehind should be re-generated in layout.
2333  // And this for all instances of a table (for example in header/footer).
2334  sal_uInt16 nStPos = 0;
2335  sal_uInt16 nEndPos= rTable.GetTabLines().size() - 1;
2336  SwRootFrame* pLayout =
2338  bool bHideChanges = pLayout && pLayout->IsHideRedlines();
2339 
2340  if ( m_pLineBefore )
2341  {
2342  nStPos = rTable.GetTabLines().GetPos(
2343  const_cast<const SwTableLine*&>(m_pLineBefore) );
2344  OSL_ENSURE( nStPos != USHRT_MAX, "Fox stole the line!" );
2345  ++nStPos;
2346 
2347  }
2348  if ( m_pLineBehind )
2349  {
2350  nEndPos = rTable.GetTabLines().GetPos(
2351  const_cast<const SwTableLine*&>(m_pLineBehind) );
2352  OSL_ENSURE( nEndPos != USHRT_MAX, "Fox stole the line!" );
2353  --nEndPos;
2354  }
2355  // now big insert operation for all tables.
2356  SwIterator<SwTabFrame,SwFormat> aTabIter( *rTable.GetFrameFormat() );
2357  for ( SwTabFrame *pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
2358  {
2359  if ( !pTable->IsFollow() )
2360  {
2361  SwRowFrame *pSibling = nullptr;
2362  SwFrame *pUpperFrame = nullptr;
2363  int i;
2364  for ( i = rTable.GetTabLines().size()-1;
2365  i >= 0 && !pSibling; --i )
2366  {
2368  rTable.GetTabLines()[o3tl::narrowing<sal_uInt16>(i)];
2370  pSibling = aIter.First();
2371  while ( pSibling && (
2372  pSibling->GetTabLine() != pLine ||
2373  !lcl_IsLineOfTableFrame( *pTable, *pSibling ) ||
2374  pSibling->IsRepeatedHeadline() ||
2375  // #i53647# If !pLineBehind,
2376  // IsInSplitTableRow() should be checked.
2377  ( m_pLineBehind && pSibling->IsInFollowFlowRow() ) ||
2378  (!m_pLineBehind && pSibling->IsInSplitTableRow() ) ) )
2379  {
2380  pSibling = aIter.Next();
2381  }
2382  }
2383  if ( pSibling )
2384  {
2385  pUpperFrame = pSibling->GetUpper();
2386  if ( !m_pLineBehind )
2387  pSibling = nullptr;
2388  }
2389  else
2390 // ???? or is this the last Follow of the table ????
2391  pUpperFrame = pTable;
2392 
2393  SwRedlineTable::size_type nRedlinePos = 0;
2394  for ( sal_uInt16 j = nStPos; j <= nEndPos; ++j )
2395  {
2396  SwTableLine * pLine = rTable.GetTabLines()[j];
2397  if ( !bHideChanges || !pLine->IsDeleted(nRedlinePos) )
2398  ::lcl_InsertRow( *pLine,
2399  static_cast<SwLayoutFrame*>(pUpperFrame), pSibling );
2400  }
2401  if ( pUpperFrame->IsTabFrame() )
2402  static_cast<SwTabFrame*>(pUpperFrame)->SetCalcLowers();
2403  }
2404  else if ( rTable.GetRowsToRepeat() > 0 )
2405  {
2406  // Insert new headlines:
2407  lcl_UpdateRepeatedHeadlines( *pTable, true );
2408  }
2409  }
2410 }
2411 
2412 void FndBox_::MakeNewFrames( SwTable &rTable, const sal_uInt16 nNumber,
2413  const bool bBehind )
2414 {
2415  // Create Frames for newly inserted lines
2416  // bBehind == true: before pLineBehind
2417  // == false: after pLineBefore
2418  const sal_uInt16 nBfPos = m_pLineBefore ?
2419  rTable.GetTabLines().GetPos( const_cast<const SwTableLine*&>(m_pLineBefore) ) :
2420  USHRT_MAX;
2421  const sal_uInt16 nBhPos = m_pLineBehind ?
2422  rTable.GetTabLines().GetPos( const_cast<const SwTableLine*&>(m_pLineBehind) ) :
2423  USHRT_MAX;
2424 
2425  //nNumber: how often did we insert
2426  //nCnt: how many were inserted nNumber times
2427 
2428  const sal_uInt16 nCnt =
2429  ((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().size()) -
2430  (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1);
2431 
2432  // search the Master-TabFrame
2433  SwIterator<SwTabFrame,SwFormat> aTabIter( *rTable.GetFrameFormat() );
2434  SwTabFrame *pTable;
2435  for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
2436  {
2437  if( !pTable->IsFollow() )
2438  {
2439  SwRowFrame* pSibling = nullptr;
2440  SwLayoutFrame *pUpperFrame = nullptr;
2441  if ( bBehind )
2442  {
2443  if ( m_pLineBehind )
2444  {
2446  pSibling = aIter.First();
2447  while ( pSibling && (
2448  // only consider row frames associated with pLineBehind:
2449  pSibling->GetTabLine() != m_pLineBehind ||
2450  // only consider row frames that are in pTables Master-Follow chain:
2451  !lcl_IsLineOfTableFrame( *pTable, *pSibling ) ||
2452  // only consider row frames that are not repeated headlines:
2453  pSibling->IsRepeatedHeadline() ||
2454  // only consider row frames that are not follow flow rows
2455  pSibling->IsInFollowFlowRow() ) )
2456  {
2457  pSibling = aIter.Next();
2458  }
2459  }
2460  if ( pSibling )
2461  pUpperFrame = pSibling->GetUpper();
2462  else
2463  {
2464  while( pTable->GetFollow() )
2465  pTable = pTable->GetFollow();
2466  pUpperFrame = pTable;
2467  }
2468  const sal_uInt16 nMax = nBhPos != USHRT_MAX ?
2469  nBhPos : rTable.GetTabLines().size();
2470 
2471  sal_uInt16 i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt;
2472 
2473  for ( ; i < nMax; ++i )
2474  ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrame, pSibling );
2475  if ( pUpperFrame->IsTabFrame() )
2476  static_cast<SwTabFrame*>(pUpperFrame)->SetCalcLowers();
2477  }
2478  else // insert before
2479  {
2480  sal_uInt16 i;
2481 
2482  // We are looking for the frame that is behind the row frame
2483  // that should be inserted.
2484  for ( i = 0; !pSibling; ++i )
2485  {
2486  SwTableLine* pLine = m_pLineBefore ? m_pLineBefore : rTable.GetTabLines()[i];
2487 
2489  pSibling = aIter.First();
2490 
2491  while ( pSibling && (
2492  // only consider row frames associated with pLineBefore:
2493  pSibling->GetTabLine() != pLine ||
2494  // only consider row frames that are in pTables Master-Follow chain:
2495  !lcl_IsLineOfTableFrame( *pTable, *pSibling ) ||
2496  // only consider row frames that are not repeated headlines:
2497  pSibling->IsRepeatedHeadline() ||
2498  // 1. case: pLineBefore == 0:
2499  // only consider row frames that are not follow flow rows
2500  // 2. case: pLineBefore != 0:
2501  // only consider row frames that are not split table rows
2502  // #i37476# If !pLineBefore,
2503  // check IsInFollowFlowRow instead of IsInSplitTableRow.
2504  ( ( !m_pLineBefore && pSibling->IsInFollowFlowRow() ) ||
2505  ( m_pLineBefore && pSibling->IsInSplitTableRow() ) ) ) )
2506  {
2507  pSibling = aIter.Next();
2508  }
2509  }
2510 
2511  pUpperFrame = pSibling->GetUpper();
2512  if ( m_pLineBefore )
2513  pSibling = static_cast<SwRowFrame*>( pSibling->GetNext() );
2514 
2515  sal_uInt16 nMax = nBhPos != USHRT_MAX ?
2516  nBhPos - nCnt :
2517  rTable.GetTabLines().size() - nCnt;
2518 
2519  i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0;
2520  for ( ; i < nMax; ++i )
2521  ::lcl_InsertRow( *rTable.GetTabLines()[i],
2522  pUpperFrame, pSibling );
2523  if ( pUpperFrame->IsTabFrame() )
2524  static_cast<SwTabFrame*>(pUpperFrame)->SetCalcLowers();
2525  }
2526  }
2527  }
2528 
2529  // If necessary headlines should be processed. In order to
2530  // not to fragment good code, we iterate once more.
2531  const sal_uInt16 nRowsToRepeat = rTable.GetRowsToRepeat();
2532  if ( !(nRowsToRepeat > 0 &&
2533  ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) ||
2534  ( bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) )) )
2535  return;
2536 
2537  for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() )
2538  {
2539  if ( pTable->Lower() )
2540  {
2541  if ( pTable->IsFollow() )
2542  {
2543  lcl_UpdateRepeatedHeadlines( *pTable, true );
2544  }
2545 
2546  OSL_ENSURE( static_cast<SwRowFrame*>(pTable->Lower())->GetTabLine() ==
2547  rTable.GetTabLines()[0], "MakeNewFrames: Table corruption!" );
2548  }
2549  }
2550 }
2551 
2552 bool FndBox_::AreLinesToRestore( const SwTable &rTable ) const
2553 {
2554  // Should we call MakeFrames here?
2555 
2556  if ( !m_pLineBefore && !m_pLineBehind && !rTable.GetTabLines().empty() )
2557  return true;
2558 
2559  sal_uInt16 nBfPos;
2560  if(m_pLineBefore)
2561  {
2562  const SwTableLine* rLBefore = const_cast<const SwTableLine*>(m_pLineBefore);
2563  nBfPos = rTable.GetTabLines().GetPos( rLBefore );
2564  }
2565  else
2566  nBfPos = USHRT_MAX;
2567 
2568  sal_uInt16 nBhPos;
2569  if(m_pLineBehind)
2570  {
2571  const SwTableLine* rLBehind = const_cast<const SwTableLine*>(m_pLineBehind);
2572  nBhPos = rTable.GetTabLines().GetPos( rLBehind );
2573  }
2574  else
2575  nBhPos = USHRT_MAX;
2576 
2577  if ( nBfPos == nBhPos ) // Should never occur.
2578  {
2579  OSL_FAIL( "Table, erase but not on any area !?!" );
2580  return false;
2581  }
2582 
2583  if ( rTable.GetRowsToRepeat() > 0 )
2584  {
2585  // oops: should the repeated headline have been deleted??
2587  for( SwTabFrame* pTable = aIter.First(); pTable; pTable = aIter.Next() )
2588  {
2589  if( pTable->IsFollow() )
2590  {
2591  // Insert new headlines:
2592  lcl_UpdateRepeatedHeadlines( *pTable, false );
2593  }
2594  }
2595  }
2596 
2597  // Some adjacent lines at the beginning of the table have been deleted:
2598  if ( nBfPos == USHRT_MAX && nBhPos == 0 )
2599  return false;
2600 
2601  // Some adjacent lines at the end of the table have been deleted:
2602  if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().size() - 1) )
2603  return false;
2604 
2605  // Some adjacent lines in the middle of the table have been deleted:
2606  if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos )
2607  return false;
2608 
2609  // The structure of the deleted lines is more complex due to split lines.
2610  // A call of MakeFrames() is necessary.
2611  return true;
2612 }
2613 
2614 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsAnLower(const SwFrame *) const
Definition: findfrm.cxx:231
vcl::RenderContext * GetOut() const
Definition: viewsh.hxx:339
bool IsTableComplex() const
Definition: swtable.cxx:1446
const SwEndNode * EndOfSectionNode() const
Definition: node.hxx:692
Base class of the Writer layout elements.
Definition: frame.hxx:314
Base class that provides the general functionalities for frames that are allowed at page breaks (flow...
Definition: flowfrm.hxx:58
const FndLines_t & GetLines() const
Definition: tblsel.hxx:173
virtual sal_Int32 Len() const
Definition: node.cxx:1243
tools::Long GetWidth() const
tools::Long GetRight(const SwRect &rRect) const
Definition: frame.hxx:1379
virtual void Cut() override
Definition: tabfrm.cxx:3730
void CreateSelection(const SwPaM &rPam, SwSelBoxes &rBoxes, const SearchType eSearchType, bool bProtect) const
void SwTable::CreateSelection(..) fills the selection structure with table cells for a given SwPaM...
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:224
void Right(const tools::Long nRight)
Definition: swrect.hxx:202
const SwSelBoxes & rBoxes
Definition: tblsel.hxx:215
SwShellCursor * m_pCurrentCursor
current cursor
Definition: crsrsh.hxx:181
bool GoInContent(SwPaM &rPam, SwMoveFnCollection const &fnMove)
Definition: pam.cxx:968
bool IsFollow() const
Definition: flowfrm.hxx:166
void SetCalcLowers()
Definition: tabfrm.hxx:168
const SwSelBoxes & GetSelectedBoxes() const
Definition: swcrsr.hxx:280
SwNodeOffset EndOfSectionIndex() const
Definition: node.hxx:687
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
Marks a position in the document model.
Definition: pam.hxx:36
SwRect GetUnion(const SwRect &rRect) const
Definition: swrect.hxx:382
SwRect & Union(const SwRect &rRect)
Definition: swrect.cxx:35
const SwTableBox * GetTableBox(const OUString &rName, const bool bPerformValidCheck=false) const
Definition: swtable.cxx:1345
const OUString & GetText() const
Definition: ndtxt.hxx:218
virtual const SwRootFrame * GetCurrentLayout() const =0
void AddNewBox(SwNodeOffset nSttNdIdx)
Definition: UndoTable.hxx:233
void ColLock()
Definition: sectfrm.hxx:99
bool IsColLocked() const
Definition: frame.hxx:886
SwNodeOffset StartOfSectionIndex() const
Definition: node.hxx:683
const SwTable * GetTable() const
Definition: tabfrm.hxx:158
void Left(const tools::Long nLeft)
Definition: swrect.hxx:197
SwNodeIndex nNode
Definition: pam.hxx:38
bool IsTableMode() const
Definition: crsrsh.hxx:648
void SetCompletePaint() const
Definition: frame.hxx:994
SwFrameType GetType() const
Definition: frame.hxx:519
SwShellCursor * getShellCursor(bool bBlock)
Delivers the current shell cursor.
Definition: crsrsh.cxx:3048
static void lcl_InsertRow(SwTableLine const &rLine, SwLayoutFrame *pUpper, SwFrame *pSibling)
Definition: tblsel.cxx:2049
long Long
const SwRect & getFramePrintArea() const
Definition: frame.hxx:180
#define MINLAY
Definition: swtypes.hxx:62
const SwPosition * GetMark() const
Definition: pam.hxx:210
bool AreLinesToRestore(const SwTable &rTable) const
Definition: tblsel.cxx:2552
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:46
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1210
sal_Int64 n
SwFrame * FindPrev()
Definition: frame.hxx:1155
Definition: doc.hxx:187
static void lcl_UpdateRepeatedHeadlines(SwTabFrame &rTabFrame, bool bCalcLowers)
Definition: tblsel.cxx:2302
bool ChkChartSel(const SwNode &rSttNd, const SwNode &rEndNd)
Definition: tblsel.cxx:428
const SwShellTableCursor * GetTableCursor() const
Definition: crsrsh.hxx:650
TElementType * Next()
Definition: calbck.hxx:364
void DelFrames(SwTable &rTable)
Definition: tblsel.cxx:2169
void InvalidatePos()
Definition: frame.hxx:1043
void GetMergeSel(const SwPaM &rPam, SwSelBoxes &rBoxes, SwTableBox **ppMergeBox, SwUndoTableMerge *pUndo)
Definition: tblsel.cxx:929
const_iterator find(const Value &x) const
SwTableLine is one table row in the document model.
Definition: swtable.hxx:357
virtual void Paste(SwFrame *pParent, SwFrame *pSibling=nullptr) override
Definition: wsfrm.cxx:1337
SwNode & GetNode() const
Definition: ndindex.hxx:128
bool HasProtectedCells(const SwSelBoxes &rBoxes)
Definition: tblsel.cxx:856
bool IsVert() const
Definition: frame.hxx:1366
sal_uInt16 GetRowsToRepeat() const
Definition: swtable.hxx:196
static void DestroyFrame(SwFrame *const pFrame)
this is the only way to delete a SwFrame instance
Definition: ssfrm.cxx:388
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
virtual void Calc(vcl::RenderContext *pRenderContext) const
Definition: trvlfrm.cxx:1788
bool IsCellFrame() const
Definition: frame.hxx:1226
Of course Writer needs its own rectangles.
Definition: swrect.hxx:34
iterator begin()
Definition: swtable.hxx:77
tools::Long GetWidth(const SwRect &rRect) const
Definition: frame.hxx:1380
void UnsetFollow(SwFlowFrame *pTab)
Definition: tblsel.cxx:2164
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
void CheckRowSpan(SwTableLine *&rpLine, bool bUp) const
SwTable::CheckRowSpan(..) looks for the next line without an overlapping to the previous line...
The root element of a Writer document layout.
Definition: rootfrm.hxx:81
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:204
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:743
bool isFrameAreaDefinitionValid() const
Definition: frame.hxx:171
SwNodeOffset GetSttIdx() const
Definition: swtable.cxx:2051
size_type size() const
Definition: swtable.hxx:76
void ForEach_FndLineCopyCol(SwTableLines &rLines, FndPara *pFndPara)
This creates a structure mirroring the SwTable structure that contains all rows and non-leaf boxes (a...
Definition: tblsel.cxx:2101
const SvxBoxItem & GetBox(bool=true) const
Definition: frmatr.hxx:84
void GetTableSelCrs(const SwCursorShell &rShell, SwSelBoxes &rBoxes)
Definition: tblsel.cxx:124
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:230
tools::Long GetTop(const SwRect &rRect) const
Definition: frame.hxx:1376
static const SwLayoutFrame * lcl_FindNextCellFrame(const SwLayoutFrame *pLay)
Definition: tblsel.cxx:111
std::deque< SwCellFrame * > SwCellFrames
Definition: tblsel.hxx:41
Point TopLeft() const
Definition: swrect.hxx:254
sal_uInt16 IsFormulaOrValueBox() const
Definition: swtable.cxx:2739
TableMergeErr
Definition: tblenum.hxx:63
static bool lcl_IsLineOfTableFrame(const SwTabFrame &rTable, const SwFrame &rChk)
Definition: tblsel.cxx:2294
bool IsEmptyBox(const SwTableBox &rBox, SwPaM &rPam)
Definition: tblsel.cxx:893
const SwLayoutFrame * GetPrevLayoutLeaf() const
Definition: frame.hxx:1024
const SwTableBox * GetTabBox() const
Definition: cellfrm.hxx:52
SwIndex nContent
Definition: pam.hxx:39
const SwRect & getFrameArea() const
Definition: frame.hxx:179
const SwTextFormatColl * GetDfltTextFormatColl() const
Definition: doc.hxx:775
bool InsBoxen(SwTableNode *, SwTableLine *, SwTableBoxFormat *, SwTextFormatColl *, const SfxItemSet *pAutoAttr, sal_uInt16 nInsPos, sal_uInt16 nCnt=1)
Insert a new box in the line before InsPos.
Definition: ndtbl.cxx:235
virtual void DoUndo(bool const bDoUndo)=0
Enable/Disable Undo.
void SetONECalcLowers()
Definition: tabfrm.hxx:170
tools::Long GetPrtLeft(const SwFrame &rFrame) const
Definition: frame.hxx:1410
void Width(tools::Long nNew)
Definition: swrect.hxx:189
const FndBoxes_t & GetBoxes() const
Definition: tblsel.hxx:203
const SwTable & GetTable() const
Definition: node.hxx:506
SwNodeOffset GetIndex() const
Definition: ndindex.hxx:161
tools::Long GetLeft(const SwRect &rRect) const
Definition: frame.hxx:1378
size_type size() const
SwShellTableCursor * m_pTableCursor
table Cursor; only in tables when the selection lays over 2 columns
Definition: crsrsh.hxx:187
virtual bool DoesUndo() const =0
Is Undo enabled?
helper class to check if a frame has been deleted during an operation WARNING! This should only be us...
Definition: frmtool.hxx:605
bool IsDeleted(SwRedlineTable::size_type &rRedlinePos) const
Definition: swtable.cxx:1755
Specific frame formats (frames, DrawObjects).
void MakeFrames(SwTable &rTable)
Definition: tblsel.cxx:2330
Point BottomRight() const
Definition: swrect.hxx:266
std::vector< SwTableLine * >::iterator iterator
Definition: swtable.hxx:69
SwTableSortBoxes & GetTabSortBoxes()
Definition: swtable.hxx:262
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:137
bool Move(SwMoveFnCollection const &fnMove=fnMoveForward, SwGoInDoc fnGo=GoInContent)
Movement of cursor.
Definition: pam.cxx:502
SwFrame * FindLastContentOrTable()
Definition: tabfrm.cxx:3534
Style of a layout element.
Definition: frmfmt.hxx:59
SwTableSearchType
Definition: tblsel.hxx:58
SwNodeIndex & Assign(SwNodes const &rNds, SwNodeOffset)
Definition: ndindex.hxx:281
SwTabFrame * FindMaster(bool bFirstMaster=false) const
Definition: flowfrm.cxx:773
void SetFollowFlowLine(bool bNew)
Definition: tabfrm.hxx:175
SwTableLine * m_pLineBehind
For deleting/restoring the layout.
Definition: tblsel.hxx:164
virtual void Cut() override
Definition: tabfrm.cxx:4728
void SetTableLines(const SwSelBoxes &rBoxes, const SwTable &rTable)
Definition: tblsel.cxx:2107
int i
void GetTableSel(const SwCursorShell &rShell, SwSelBoxes &rBoxes, const SwTableSearchType eSearchType)
Definition: tblsel.cxx:149
SwDoc & GetDoc()
Definition: node.hxx:213
const SwPosition * GetPoint() const
Definition: pam.hxx:208
bool empty() const
Definition: swtable.hxx:75
const SwRect & GetUnion() const
Definition: tblsel.hxx:130
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:206
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
void MoveBoxContent(SwDoc &rDoc, SwNodeRange &rRg, SwNodeIndex &rPos)
Definition: untbl.cxx:2009
static void lcl_FindStartEndCol(const SwLayoutFrame *&rpStart, const SwLayoutFrame *&rpEnd, const bool bChkProtected)
Definition: tblsel.cxx:1614
const SwTabFrame * GetTable() const
Definition: tblsel.hxx:132
const SwFrame * Lower() const
Definition: layfrm.hxx:101
TElementType * First()
Definition: calbck.hxx:356
SwContentNode * GetContentNode()
Definition: node.hxx:625
SwNodeOffset GetIndex() const
Definition: node.hxx:292
vector_type::size_type size_type
Definition: docary.hxx:222
tools::Long GetHeight(const SwRect &rRect) const
Definition: frame.hxx:1381
FlyAnchors.
Definition: fmtanchr.hxx:34
void SetFollow(SwFlowFrame *const pFollow)
Definition: flowfrm.cxx:91
bool IsChgd() const
Definition: swcrsr.hxx:298
SwLayoutFrame * GetUpper()
Definition: frame.hxx:678
void RegistFlys(SwPageFrame *pPage=nullptr)
Register Flys after a line was created AND inserted Must be called by the creator; the Fly is inserte...
Definition: tabfrm.cxx:3949
#define sal_True
bool IsRowFrame() const
Definition: frame.hxx:1222
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:380
bool operator<(const wwFont &r1, const wwFont &r2)
Definition: wrtw8sty.cxx:849
SwFrame * GetPrev()
Definition: frame.hxx:677
const Point & GetMkPos() const
Definition: viscrs.hxx:155
bool IsContentProtected() const
const SwRowFrame * IsInFollowFlowRow() const
Definition: findfrm.cxx:1842
SwFlowFrame * m_pPrecede
Definition: flowfrm.hxx:118
void SetRepeatedHeadline(bool bNew)
Definition: rowfrm.hxx:91
Marks a node in the document model.
Definition: ndindex.hxx:30
void MakeSelUnions(SwSelUnions &rUnions, const SwLayoutFrame *pStart, const SwLayoutFrame *pEnd, const SwTableSearchType eSearchType)
Definition: tblsel.cxx:1768
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:457
const_iterator end() const
bool empty() const
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:139
sal_uInt16 GetBoxPos(const SwTableBox *pBox) const
Definition: swtable.hxx:370
virtual bool MoveNodeRange(SwNodeRange &, SwNodeIndex &, SwMoveFlags)=0
bool MakeTableCursors(SwTableCursor &)
Calculates the cells included from the current selection.
Definition: trvlfrm.cxx:1860
SwTableLines & GetTabLines()
Definition: swtable.hxx:201
tools::Long SwTwips
Definition: swtypes.hxx:51
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:405
const long LONG_MAX
SwTable is one table in the document model, containing rows (which contain cells).
Definition: swtable.hxx:112
#define Y
SwTableLines & GetTabLines()
Definition: swtable.hxx:450
SwSectionFrame * FindSctFrame()
Definition: frame.hxx:1115
const SwCellFrame * FirstCell() const
Calls ContainsAny first to reach the innermost cell.
Definition: findfrm.cxx:116
const_iterator begin() const
SwTableLine * m_pLineBefore
For deleting/restoring the layout.
Definition: tblsel.hxx:163
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:448
bool GetAutoSumSel(const SwCursorShell &rShell, SwCellFrames &rBoxes)
Definition: tblsel.cxx:693
static const SwLayoutFrame * lcl_FindCellFrame(const SwLayoutFrame *pLay)
Definition: tblsel.cxx:104
static void lcl_InsTableBox(SwTableNode *pTableNd, SwDoc *pDoc, SwTableBox *pBox, sal_uInt16 nInsPos, sal_uInt16 nCnt=1)
Definition: tblsel.cxx:874
static SwTwips lcl_CalcWish(const SwLayoutFrame *pCell, tools::Long nWish, const tools::Long nAct)
Definition: tblsel.cxx:1517
void Bottom(const tools::Long nBottom)
Definition: swrect.hxx:211
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
void MakeNewFrames(SwTable &rTable, const sal_uInt16 nNumber, const bool bBehind)
Definition: tblsel.cxx:2412
SwTableBoxes & GetTabBoxes()
Definition: swtable.hxx:368
bool CheckSplitCells(const SwCursorShell &rShell, sal_uInt16 nDiv, const SwTableSearchType eSearchType)
Definition: tblsel.cxx:1960
void Justify()
Definition: swrect.cxx:94
SwRowFrame * GetFirstNonHeadlineRow() const
Definition: tabfrm.cxx:5790
static bool lcl_CheckRow(const FndLine_ &rFndLine, bool *pPara)
Definition: tblsel.cxx:1417
SwCursor * GetCursor(bool bMakeTableCursor=true) const
Return pointer to the current shell cursor.
Definition: crsrsh.cxx:195
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:471
bool IsTabFrame() const
Definition: frame.hxx:1218
bool IsFrameInTableSel(const SwRect &rUnion, const SwFrame *pCell)
Definition: tblsel.cxx:670
void ColUnlock()
Definition: sectfrm.hxx:100
const SwNodes & GetNodes() const
Definition: ndindex.hxx:165
FndBox_ * pFndBox
Definition: tblsel.hxx:217
SwMoveFnCollection const & fnMoveForward
SwPam::Move()/Find() default argument.
Definition: paminit.cxx:59
std::vector< SwSelUnion > SwSelUnions
Definition: tblsel.hxx:138
const SwTableBox * GetBox() const
Definition: tblsel.hxx:175
static bool lcl_CheckCol(FndBox_ const &, bool *pPara)
Definition: tblsel.cxx:1426
void SaveCollection(const SwTableBox &rBox)
Definition: untbl.cxx:2041
SwNodes & GetNodes()
Definition: doc.hxx:408
size_t GetSelectedBoxesCount() const
Definition: swcrsr.hxx:279
bool IsRightToLeft() const
Definition: frame.hxx:987
void Top(const tools::Long nTop)
Definition: swrect.hxx:206
#define sal_False
bool HasBeenDeleted() const
return true if mpFrame != 0 and mpFrame is not client of pRegIn false otherwise
Definition: frmtool.cxx:4007
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:418
void Delete(const SwNodeIndex &rPos, SwNodeOffset nNodes=SwNodeOffset(1))
delete nodes
Definition: nodes.cxx:1085
const Point & GetPtPos() const
Definition: viscrs.hxx:153
o3tl::strong_int< sal_Int32, struct Tag_SwNodeOffset > SwNodeOffset
Definition: nodeoffset.hxx:16
bool IsHideRedlines() const
Replacement for sw::DocumentRedlineManager::GetRedlineFlags() (this is layout-level redline hiding)...
Definition: rootfrm.hxx:421
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1903
bool IsAnFollow(const SwFlowFrame *pFlow) const
Definition: flowfrm.cxx:726
virtual bool AppendTextNode(SwPosition &rPos)=0
constexpr TypedWhichId< SvxBoxItem > RES_BOX(106)
const SwFormatFrameSize & GetFrameSize(bool=true) const
Definition: fmtfsize.hxx:104
SwMoveFnCollection const & fnMoveBackward
Definition: paminit.cxx:58
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:358
SwTableBox * GetUpper()
Definition: swtable.hxx:376
const SwTabFrame * GetFollow() const
Definition: tabfrm.hxx:250
Point TopRight() const
Definition: swrect.hxx:258
bool IsVertical() const
Definition: frame.hxx:973
tools::Long GetBottom(const SwRect &rRect) const
Definition: frame.hxx:1377
SwContentNode * GoNextSection(SwNodeIndex *, bool bSkipHidden=true, bool bSkipProtect=true) const
Go to next content-node that is not protected or hidden (Both set FALSE ==> GoNext/GoPrevious!!!).
Definition: nodes.cxx:1919
const SvxProtectItem & GetProtect(bool=true) const
Definition: frmatr.hxx:82
sal_uInt16 GetPos(const SwTableLine *pBox) const
Definition: swtable.hxx:98
SwDoc & GetDoc() const
Definition: pam.hxx:244
A layout frame is a frame that contains other frames (m_pLower), e.g. SwPageFrame or SwTabFrame...
Definition: layfrm.hxx:35
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:476
const SwLayoutFrame * GetNextLayoutLeaf() const
Definition: frame.hxx:1020
iterator end()
Definition: swtable.hxx:79
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:136
Frame is variable in Var-direction.
std::pair< const_iterator, bool > insert(Value &&x)
#define COLFUZZY
Definition: tblsel.cxx:52
std::vector< Value >::size_type size_type
FndLine_ * pFndLine
Definition: tblsel.hxx:216
bool IsNewModel() const
Definition: swtable.hxx:188
SwRootFrame * GetLayout() const
Definition: viewsh.cxx:2172
SwTableLine * GetUpper()
Definition: swtable.hxx:453
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:206
bool HasFollowFlowLine() const
Definition: tabfrm.hxx:174
bool Overlaps(const SwRect &rRect) const
Definition: swrect.hxx:374
static void lcl_FindStartEndRow(const SwLayoutFrame *&rpStart, const SwLayoutFrame *&rpEnd, const bool bChkProtected)
Definition: tblsel.cxx:1545
SwRootFrame * getRootFrame()
Definition: frame.hxx:679
SwCellFrame is one table cell in the document layout.
Definition: cellfrm.hxx:30
sal_uInt16 nPos
static void FndLineCopyCol(SwTableLine *pLine, FndPara *pFndPara)
Definition: tblsel.cxx:2089
o3tl::sorted_vector< CmpLPt > MergePos
Definition: tblsel.cxx:90
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:864
size_type erase(const Value &x)
SwRowFrame is one table row in the document layout.
Definition: rowfrm.hxx:28
bool IsInHeadline(const SwFrame &rFrame) const
Definition: tabfrm.cxx:5771
Point BottomLeft() const
Definition: swrect.hxx:262
virtual const SwFrameFormat * GetFormat() const
Definition: ssfrm.cxx:399
SwTabFrame * FindTabFrame()
Definition: frame.hxx:1099
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)
SwFrame * GetNext()
Definition: frame.hxx:676
static void FndBoxCopyCol(SwTableBox *pBox, FndPara *pFndPara)
Definition: tblsel.cxx:2067
TableMergeErr CheckMergeSel(const SwPaM &rPam)
Definition: tblsel.cxx:1449
Base class of the Writer document model elements.
Definition: node.hxx:81