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