1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <editeng/boxitem.hxx>
21 #include <editeng/protitem.hxx>
22 #include <osl/diagnose.h>
24 #include <hintids.hxx>
25 #include <fmtanchr.hxx>
26 #include <fmtfsize.hxx>
31 #include <IDocumentUndoRedo.hxx>
32 #include <IDocumentLayoutAccess.hxx>
35 #include <swtable.hxx>
39 #include <cellfrm.hxx>
40 #include <rootfrm.hxx>
42 #include <swtblfmt.hxx>
43 #include <UndoTable.hxx>
44 #include <sectfrm.hxx>
45 #include <frmtool.hxx>
47 #include <frameformats.hxx>
51 // see also swtable.cxx
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
63 #undef DEL_ONLY_EMPTY_LINES
64 #undef DEL_EMPTY_BOXES_AT_START_AND_END
71 const SwTableBox
* pSelBox
;
74 CmpLPt( const Point
& rPt
, const SwTableBox
* pBox
, bool bVertical
);
76 bool operator<( const CmpLPt
& rCmp
) const
79 return X() > rCmp
.X() || ( X() == rCmp
.X() && Y() < rCmp
.Y() );
81 return Y() < rCmp
.Y() || ( Y() == rCmp
.Y() && X() < rCmp
.X() );
84 tools::Long
X() const { return aPos
.X(); }
85 tools::Long
Y() const { return aPos
.Y(); }
90 typedef o3tl::sorted_vector
<CmpLPt
> MergePos
;
96 const SwCellFrame
* pFrame
;
98 explicit Sort_CellFrame( const SwCellFrame
& rCFrame
)
99 : pFrame( &rCFrame
) {}
104 static const SwLayoutFrame
*lcl_FindCellFrame( const SwLayoutFrame
*pLay
)
106 while ( pLay
&& !pLay
->IsCellFrame() )
107 pLay
= pLay
->GetUpper();
111 static const SwLayoutFrame
*lcl_FindNextCellFrame( const SwLayoutFrame
*pLay
)
113 // ensure we leave the cell (sections)
114 const SwLayoutFrame
*pTmp
= pLay
;
116 pTmp
= pTmp
->GetNextLayoutLeaf();
117 } while( pLay
->IsAnLower( pTmp
) );
119 while( pTmp
&& !pTmp
->IsCellFrame() )
120 pTmp
= pTmp
->GetUpper();
124 void GetTableSelCrs( const SwCursorShell
&rShell
, SwSelBoxes
& rBoxes
)
127 if( rShell
.IsTableMode() && const_cast<SwCursorShell
&>(rShell
).UpdateTableSelBoxes())
129 rBoxes
.insert(rShell
.GetTableCursor()->GetSelectedBoxes());
133 void GetTableSelCrs( const SwTableCursor
& rTableCursor
, SwSelBoxes
& rBoxes
)
137 if (rTableCursor
.IsChgd() || !rTableCursor
.GetSelectedBoxesCount())
139 SwTableCursor
* pTCursor
= const_cast<SwTableCursor
*>(&rTableCursor
);
140 pTCursor
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout()->MakeTableCursors( *pTCursor
);
143 if (rTableCursor
.GetSelectedBoxesCount())
145 rBoxes
.insert(rTableCursor
.GetSelectedBoxes());
149 void GetTableSel( const SwCursorShell
& rShell
, SwSelBoxes
& rBoxes
,
150 const SwTableSearchType eSearchType
)
152 // get start and end cell
153 if ( !rShell
.IsTableMode() )
156 GetTableSel( *rShell
.getShellCursor(false), rBoxes
, eSearchType
);
159 void GetTableSel( const SwCursor
& rCursor
, SwSelBoxes
& rBoxes
,
160 const SwTableSearchType eSearchType
)
162 // get start and end cell
163 OSL_ENSURE( rCursor
.GetPointContentNode() && rCursor
.GetMarkContentNode(),
164 "Tabselection not on Cnt." );
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() )
173 SwTable::SearchType eSearch
;
174 switch( SwTableSearchType::Col
& eSearchType
)
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;
180 const bool bChkP( SwTableSearchType::Protect
& eSearchType
);
181 pTableNd
->GetTable().CreateSelection( rCursor
, rBoxes
, eSearch
, bChkP
);
184 if( SwTableSearchType::Row
== ((~SwTableSearchType::Protect
) & eSearchType
) &&
185 pTableNd
&& !pTableNd
->GetTable().IsTableComplex() )
187 const SwTable
& rTable
= pTableNd
->GetTable();
188 const SwTableLines
& rLines
= rTable
.GetTabLines();
190 const SwNode
& rMarkNode
= rCursor
.GetMarkNode();
191 const SwNodeOffset nMarkSectionStart
= rMarkNode
.StartOfSectionIndex();
192 const SwTableBox
* pMarkBox
= rTable
.GetTableBox( nMarkSectionStart
);
194 OSL_ENSURE( pMarkBox
, "Point in table, mark outside?" );
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
)
205 if( nEndPos
< nSttPos
) // exchange
206 std::swap( nSttPos
, nEndPos
);
208 bool bChkProtected( SwTableSearchType::Protect
& eSearchType
);
209 for( ; nSttPos
<= nEndPos
; ++nSttPos
)
211 pLine
= rLines
[ nSttPos
];
212 for( auto n
= pLine
->GetTabBoxes().size(); n
; )
214 SwTableBox
* pBox
= pLine
->GetTabBoxes()[ --n
];
215 // check for cell protection??
216 if( !bChkProtected
||
217 !pBox
->GetFrameFormat()->GetProtect().IsContentProtected() )
218 rBoxes
.insert( pBox
);
225 Point aPtPos
, aMkPos
;
226 const SwShellCursor
* pShCursor
= dynamic_cast<const SwShellCursor
*>(&rCursor
);
229 aPtPos
= pShCursor
->GetPtPos();
230 aMkPos
= pShCursor
->GetMkPos();
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();
238 const SwLayoutFrame
*pEnd
= pCntNd
?
239 pCntNd
->getLayoutFrame(pCntNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp
)->GetUpper() : nullptr;
241 GetTableSel( pStart
, pEnd
, rBoxes
, nullptr, eSearchType
);
245 void GetTableSel( const SwLayoutFrame
* pStart
, const SwLayoutFrame
* pEnd
,
246 SwSelBoxes
& rBoxes
, SwCellFrames
* pCells
,
247 const SwTableSearchType eSearchType
)
249 const SwTabFrame
* pStartTab
= pStart
->FindTabFrame();
252 OSL_FAIL( "GetTableSel without start table" );
256 bool bChkProtected( SwTableSearchType::Protect
& eSearchType
);
258 // #i55421# Reduced value 10
262 bool bTableIsValid
= true;
264 // First, compute tables and rectangles
266 ::MakeSelUnions( aUnions
, pStart
, pEnd
, eSearchType
);
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;
277 // Now find boxes for each entry and emit
278 for (size_t i
= 0; i
< aUnions
.size() && bTableIsValid
; ++i
)
280 SwSelUnion
*pUnion
= &aUnions
[i
];
281 const SwTabFrame
*pTable
= pUnion
->GetTable();
283 if( !pTable
->isFrameAreaDefinitionValid() && nLoopMax
)
285 bTableIsValid
= false;
289 // Skip any repeated headlines in the follow:
290 const SwLayoutFrame
* pRow
= pTable
->IsFollow() ?
291 pTable
->GetFirstNonHeadlineRow() :
292 static_cast<const SwLayoutFrame
*>(pTable
->Lower());
294 while( pRow
&& bTableIsValid
)
296 if( !pRow
->isFrameAreaDefinitionValid() && nLoopMax
)
298 bTableIsValid
= false;
302 if ( pRow
->getFrameArea().Overlaps( pUnion
->GetUnion() ) )
304 const SwLayoutFrame
*pCell
= pRow
->FirstCell();
306 while (pCell
&& pRow
->IsAnLower(pCell
))
308 if( !pCell
->isFrameAreaDefinitionValid() && nLoopMax
)
310 bTableIsValid
= false;
314 OSL_ENSURE( pCell
->IsCellFrame(), "Frame without Cell" );
315 if( ::IsFrameInTableSel( pUnion
->GetUnion(), pCell
) )
317 SwTableBox
* pBox
= const_cast<SwTableBox
*>(
318 static_cast<const SwCellFrame
*>(pCell
)->GetTabBox());
319 // check for cell protection??
320 if( !bChkProtected
||
321 !pBox
->GetFrameFormat()->GetProtect().IsContentProtected() )
322 rBoxes
.insert( pBox
);
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() );
331 if ( aTopLeft
.getY() < aCurrentTopLeft
.getY() ||
332 ( aTopLeft
.getY() == aCurrentTopLeft
.getY() &&
333 aTopLeft
.getX() < aCurrentTopLeft
.getX() ) )
335 aCurrentTopLeft
= aTopLeft
;
336 pCurrentTopLeftFrame
= static_cast<const SwCellFrame
*>( pCell
);
339 if ( aTopRight
.getY() < aCurrentTopRight
.getY() ||
340 ( aTopRight
.getY() == aCurrentTopRight
.getY() &&
341 aTopRight
.getX() > aCurrentTopRight
.getX() ) )
343 aCurrentTopRight
= aTopRight
;
344 pCurrentTopRightFrame
= static_cast<const SwCellFrame
*>( pCell
);
347 if ( aBottomLeft
.getY() > aCurrentBottomLeft
.getY() ||
348 ( aBottomLeft
.getY() == aCurrentBottomLeft
.getY() &&
349 aBottomLeft
.getX() < aCurrentBottomLeft
.getX() ) )
351 aCurrentBottomLeft
= aBottomLeft
;
352 pCurrentBottomLeftFrame
= static_cast<const SwCellFrame
*>( pCell
);
355 if ( aBottomRight
.getY() > aCurrentBottomRight
.getY() ||
356 ( aBottomRight
.getY() == aCurrentBottomRight
.getY() &&
357 aBottomRight
.getX() > aCurrentBottomRight
.getX() ) )
359 aCurrentBottomRight
= aBottomRight
;
360 pCurrentBottomRightFrame
= static_cast<const SwCellFrame
*>( pCell
);
365 if ( pCell
->GetNext() )
367 pCell
= static_cast<const SwLayoutFrame
*>(pCell
->GetNext());
368 if ( pCell
->Lower() && pCell
->Lower()->IsRowFrame() )
369 pCell
= pCell
->FirstCell();
372 pCell
= ::lcl_FindNextCellFrame( pCell
);
375 pRow
= static_cast<const SwLayoutFrame
*>(pRow
->GetNext());
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
) );
391 SwDeletionChecker
aDelCheck( pStart
);
393 // otherwise quickly "calculate" the table layout and start over
394 SwTabFrame
*pTable
= aUnions
.front().GetTable();
397 if( pTable
->isFrameAreaDefinitionValid() )
399 pTable
->InvalidatePos();
402 pTable
->SetONECalcLowers();
403 pTable
->Calc(pTable
->getRootFrame()->GetCurrShell()->GetOut());
404 pTable
->SetCompletePaint();
406 pTable
= pTable
->GetFollow();
407 if( nullptr == pTable
)
411 // --> Make code robust, check if pStart has
412 // been deleted due to the formatting of the table:
413 if ( aDelCheck
.HasBeenDeleted() )
415 OSL_FAIL( "Current box has been deleted during GetTableSel()" );
423 OSL_ENSURE( nLoopMax
, "Table layout is still invalid!" );
426 bool ChkChartSel( const SwNode
& rSttNd
, const SwNode
& rEndNd
)
428 const SwTableNode
* pTNd
= rSttNd
.FindTableNode();
433 SwNodeIndex
aIdx( rSttNd
);
434 const SwContentNode
* pCNd
= aIdx
.GetNode().GetContentNode();
436 pCNd
= aIdx
.GetNodes().GoNextSection( &aIdx
, false, false );
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 )
447 std::pair
<Point
, bool> tmp(aNullPos
, true);
448 const SwLayoutFrame
*const pStart
= pCNd
->getLayoutFrame(
449 pCNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
450 nullptr, &tmp
)->GetUpper();
451 OSL_ENSURE( pStart
, "without frame nothing works" );
454 pCNd
= aIdx
.GetNode().GetContentNode();
456 pCNd
= aIdx
.GetNodes().GoNextSection( &aIdx
, false, false );
458 // #i22135# - Robust: check, if content was found and if it's visible
459 if ( !pCNd
|| pCNd
->getLayoutFrame( pCNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) == nullptr )
464 const SwLayoutFrame
*const pEnd
= pCNd
->getLayoutFrame(
465 pCNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
466 nullptr, &tmp
)->GetUpper();
467 OSL_ENSURE( pEnd
, "without frame nothing works" );
470 // #i55421# Reduced value 10
471 int nLoopMax
= 10; //JP 28.06.99: max 100 loops - Bug 67292
474 bool bTableIsValid
= true;
475 bValidChartSel
= true;
477 sal_uInt16 nRowCells
= USHRT_MAX
;
479 // First, compute tables and rectangles
481 ::MakeSelUnions( aUnions
, pStart
, pEnd
, SwTableSearchType::NoUnionCorrect
);
483 // find boxes for each entry and emit
484 for( auto & rSelUnion
: aUnions
)
486 if (!bTableIsValid
|| !bValidChartSel
)
489 SwSelUnion
*pUnion
= &rSelUnion
;
490 const SwTabFrame
*pTable
= pUnion
->GetTable();
492 SwRectFnSet
aRectFnSet(pTable
);
493 bool bRTL
= pTable
->IsRightToLeft();
495 if( !pTable
->isFrameAreaDefinitionValid() && nLoopMax
)
497 bTableIsValid
= false;
501 std::deque
< Sort_CellFrame
> aCellFrames
;
503 // Skip any repeated headlines in the follow:
504 const SwLayoutFrame
* pRow
= pTable
->IsFollow() ?
505 pTable
->GetFirstNonHeadlineRow() :
506 static_cast<const SwLayoutFrame
*>(pTable
->Lower());
508 while( pRow
&& bTableIsValid
&& bValidChartSel
)
510 if( !pRow
->isFrameAreaDefinitionValid() && nLoopMax
)
512 bTableIsValid
= false;
516 if( pRow
->getFrameArea().Overlaps( pUnion
->GetUnion() ) )
518 const SwLayoutFrame
*pCell
= pRow
->FirstCell();
520 while (pCell
&& pRow
->IsAnLower(pCell
))
522 if( !pCell
->isFrameAreaDefinitionValid() && nLoopMax
)
524 bTableIsValid
= false;
528 OSL_ENSURE( pCell
->IsCellFrame(), "Frame without Cell" );
529 const SwRect
& rUnion
= pUnion
->GetUnion(),
530 & rFrameRect
= pCell
->getFrameArea();
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();
537 // ignore if FrameRect is outside the union
539 const tools::Long nXFuzzy
= aRectFnSet
.IsVert() ? 0 : 20;
540 const tools::Long nYFuzzy
= aRectFnSet
.IsVert() ? 20 : 0;
542 if( !( rUnion
.Top() + nYFuzzy
> nFrameBottom
||
543 nUnionBottom
< rFrameRect
.Top() + nYFuzzy
||
544 rUnion
.Left() + nXFuzzy
> nFrameRight
||
545 nUnionRight
< rFrameRect
.Left() + nXFuzzy
))
547 // ok, rUnion is _not_ completely outside of rFrameRect
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
)
560 aCellFrames
.emplace_back( *static_cast<const SwCellFrame
*>(pCell
) );
563 bValidChartSel
= false;
567 if ( pCell
->GetNext() )
569 pCell
= static_cast<const SwLayoutFrame
*>(pCell
->GetNext());
570 if ( pCell
->Lower() && pCell
->Lower()->IsRowFrame() )
571 pCell
= pCell
->FirstCell();
574 pCell
= ::lcl_FindNextCellFrame( pCell
);
577 pRow
= static_cast<const SwLayoutFrame
*>(pRow
->GetNext());
580 if( !bValidChartSel
)
583 // all cells of the (part) table together. Now check if
584 // they're all adjacent
586 sal_uInt16 nCellCnt
= 0;
587 tools::Long nYPos
= LONG_MAX
;
588 tools::Long nXPos
= 0;
589 tools::Long nHeight
= 0;
591 for( n
= 0 ; n
< aCellFrames
.size(); ++n
)
593 const Sort_CellFrame
& rCF
= aCellFrames
[ n
];
594 if( aRectFnSet
.GetTop(rCF
.pFrame
->getFrameArea()) != nYPos
)
599 if( USHRT_MAX
== nRowCells
) // 1. row change
600 nRowCells
= nCellCnt
;
601 else if( nRowCells
!= nCellCnt
)
603 bValidChartSel
= false;
608 nYPos
= aRectFnSet
.GetTop(rCF
.pFrame
->getFrameArea());
609 nHeight
= aRectFnSet
.GetHeight(rCF
.pFrame
->getFrameArea());
612 aRectFnSet
.GetLeft(rCF
.pFrame
->getFrameArea()) :
613 aRectFnSet
.GetRight(rCF
.pFrame
->getFrameArea());
615 else if( nXPos
== ( bRTL
?
616 aRectFnSet
.GetRight(rCF
.pFrame
->getFrameArea()) :
617 aRectFnSet
.GetLeft(rCF
.pFrame
->getFrameArea()) ) &&
618 nHeight
== aRectFnSet
.GetHeight(rCF
.pFrame
->getFrameArea()) )
620 nXPos
+= ( bRTL
? -1 : 1 ) *
621 aRectFnSet
.GetWidth(rCF
.pFrame
->getFrameArea());
626 bValidChartSel
= false;
632 if( USHRT_MAX
== nRowCells
)
633 nRowCells
= nCellCnt
;
634 else if( nRowCells
!= nCellCnt
)
635 bValidChartSel
= false;
642 // otherwise quickly "calculate" table layout and start over
643 SwTabFrame
*pTable
= aUnions
.front().GetTable();
645 for( SwSelUnions::size_type i
= 0; i
< aUnions
.size(); ++i
)
647 if( pTable
->isFrameAreaDefinitionValid() )
649 pTable
->InvalidatePos();
652 pTable
->SetONECalcLowers();
653 pTable
->Calc(pTable
->getRootFrame()->GetCurrShell()->GetOut());
654 pTable
->SetCompletePaint();
656 pTable
= pTable
->GetFollow();
657 if( nullptr == pTable
)
663 OSL_ENSURE( nLoopMax
, "table layout is still invalid!" );
665 return bValidChartSel
;
668 bool IsFrameInTableSel( const SwRect
& rUnion
, const SwFrame
* pCell
)
670 OSL_ENSURE( pCell
->IsCellFrame(), "Frame without Gazelle" );
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() ));
681 rUnion
.Top() <= pCell
->getFrameArea().Top() &&
682 rUnion
.Bottom() >= pCell
->getFrameArea().Bottom() &&
684 (( rUnion
.Left() <= pCell
->getFrameArea().Left()+20 &&
685 rUnion
.Right() > pCell
->getFrameArea().Left() ) ||
687 ( rUnion
.Left() >= pCell
->getFrameArea().Left() &&
688 rUnion
.Right() < pCell
->getFrameArea().Right() ));
691 bool GetAutoSumSel( const SwCursorShell
& rShell
, SwCellFrames
& rBoxes
)
693 SwShellCursor
* pCursor
= rShell
.m_pCurrentCursor
;
694 if ( rShell
.IsTableMode() )
695 pCursor
= rShell
.m_pTableCursor
;
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();
704 const SwLayoutFrame
* pSttCell
= pStart
;
705 while( pSttCell
&& !pSttCell
->IsCellFrame() )
706 pSttCell
= pSttCell
->GetUpper();
708 // First, compute tables and rectangles
711 // by default, first test above and then to the left
712 ::MakeSelUnions( aUnions
, pStart
, pEnd
, SwTableSearchType::Col
);
714 bool bTstRow
= true, bFound
= false;
716 // 1. check if box above contains value/formula
717 for( SwSelUnions::size_type i
= 0; i
< aUnions
.size(); ++i
)
719 SwSelUnion
*pUnion
= &aUnions
[i
];
720 const SwTabFrame
*pTable
= pUnion
->GetTable();
722 // Skip any repeated headlines in the follow:
723 const SwLayoutFrame
* pRow
= pTable
->IsFollow() ?
724 pTable
->GetFirstNonHeadlineRow() :
725 static_cast<const SwLayoutFrame
*>(pTable
->Lower());
729 if( pRow
->getFrameArea().Overlaps( pUnion
->GetUnion() ) )
731 const SwCellFrame
* pUpperCell
= nullptr;
732 const SwLayoutFrame
*pCell
= pRow
->FirstCell();
734 while( pCell
&& pRow
->IsAnLower( pCell
) )
736 if( pCell
== pSttCell
)
738 sal_uInt16 nWhichId
= 0;
739 for( size_t n
= rBoxes
.size(); n
; )
741 nWhichId
= rBoxes
[ --n
]->GetTabBox()->IsFormulaOrValueBox();
742 if( USHRT_MAX
!= nWhichId
)
746 // all boxes together, do not check the
747 // row, if a formula or value was found
748 bTstRow
= 0 == nWhichId
|| USHRT_MAX
== nWhichId
;
753 OSL_ENSURE( pCell
->IsCellFrame(), "Frame without cell" );
754 if( ::IsFrameInTableSel( pUnion
->GetUnion(), pCell
) )
755 pUpperCell
= static_cast<const SwCellFrame
*>(pCell
);
757 if( pCell
->GetNext() )
759 pCell
= static_cast<const SwLayoutFrame
*>(pCell
->GetNext());
760 if ( pCell
->Lower() && pCell
->Lower()->IsRowFrame() )
761 pCell
= pCell
->FirstCell();
764 pCell
= ::lcl_FindNextCellFrame( pCell
);
768 rBoxes
.push_back( const_cast< SwCellFrame
* >(pUpperCell
) );
775 pRow
= static_cast<const SwLayoutFrame
*>(pRow
->GetNext());
779 // 2. check if box on left contains value/formula
786 ::MakeSelUnions( aUnions
, pStart
, pEnd
, SwTableSearchType::Row
);
788 for( SwSelUnions::size_type i
= 0; i
< aUnions
.size(); ++i
)
790 SwSelUnion
*pUnion
= &aUnions
[i
];
791 const SwTabFrame
*pTable
= pUnion
->GetTable();
793 // Skip any repeated headlines in the follow:
794 const SwLayoutFrame
* pRow
= pTable
->IsFollow() ?
795 pTable
->GetFirstNonHeadlineRow() :
796 static_cast<const SwLayoutFrame
*>(pTable
->Lower());
800 if( pRow
->getFrameArea().Overlaps( pUnion
->GetUnion() ) )
802 const SwLayoutFrame
*pCell
= pRow
->FirstCell();
804 while( pCell
&& pRow
->IsAnLower( pCell
) )
806 if( pCell
== pSttCell
)
808 sal_uInt16 nWhichId
= 0;
809 for( size_t n
= rBoxes
.size(); n
; )
811 nWhichId
= rBoxes
[ --n
]
812 ->GetTabBox()->IsFormulaOrValueBox();
813 if( USHRT_MAX
!= nWhichId
)
817 // all boxes together, do not check the
818 // row if a formula or value was found
819 bFound
= 0 != nWhichId
&& USHRT_MAX
!= nWhichId
;
824 OSL_ENSURE( pCell
->IsCellFrame(), "Frame without cell" );
825 if( ::IsFrameInTableSel( pUnion
->GetUnion(), pCell
) )
827 SwCellFrame
* pC
= const_cast<SwCellFrame
*>(static_cast<const SwCellFrame
*>(pCell
));
828 rBoxes
.push_back( pC
);
830 if( pCell
->GetNext() )
832 pCell
= static_cast<const SwLayoutFrame
*>(pCell
->GetNext());
833 if ( pCell
->Lower() && pCell
->Lower()->IsRowFrame() )
834 pCell
= pCell
->FirstCell();
837 pCell
= ::lcl_FindNextCellFrame( pCell
);
846 pRow
= static_cast<const SwLayoutFrame
*>(pRow
->GetNext());
854 bool HasProtectedCells( const SwSelBoxes
& rBoxes
)
857 for (size_t n
= 0; n
< rBoxes
.size(); ++n
)
859 if( rBoxes
[ n
]->GetFrameFormat()->GetProtect().IsContentProtected() )
868 CmpLPt::CmpLPt( const Point
& rPt
, const SwTableBox
* pBox
, bool bVertical
)
869 : aPos( rPt
), pSelBox( pBox
), bVert( bVertical
)
872 static void lcl_InsTableBox( SwTableNode
* pTableNd
, SwDoc
* pDoc
, SwTableBox
* pBox
,
873 sal_uInt16 nInsPos
, sal_uInt16 nCnt
= 1 )
875 OSL_ENSURE( pBox
->GetSttNd(), "Box without Start-Node" );
876 SwContentNode
* pCNd
= pDoc
->GetNodes()[ pBox
->GetSttIdx() + 1 ]
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(),
885 pDoc
->GetNodes().InsBoxen( pTableNd
, pBox
->GetUpper(),
886 static_cast<SwTableBoxFormat
*>(pBox
->GetFrameFormat()),
887 pDoc
->GetDfltTextFormatColl(), nullptr,
891 bool IsEmptyBox( const SwTableBox
& rBox
, SwPaM
& rPam
)
893 rPam
.GetPoint()->Assign( *rBox
.GetSttNd()->EndOfSectionNode() );
894 rPam
.Move( fnMoveBackward
, GoInContent
);
896 rPam
.GetPoint()->Assign( *rBox
.GetSttNd() );
897 rPam
.Move( fnMoveForward
, GoInContent
);
898 bool bRet
= *rPam
.GetMark() == *rPam
.GetPoint()
899 && ( rBox
.GetSttNd()->GetIndex() + 1 == rPam
.GetPoint()->GetNodeIndex() );
903 // now check for paragraph bound flies
904 const sw::SpzFrameFormats
& rFormats
= *rPam
.GetDoc().GetSpzFrameFormats();
905 SwNodeOffset nSttIdx
= rPam
.GetPoint()->GetNodeIndex(),
906 nEndIdx
= rBox
.GetSttNd()->EndOfSectionIndex(),
909 for( auto pFormat
: rFormats
)
911 const SwFormatAnchor
& rAnchor
= pFormat
->GetAnchor();
912 const SwNode
* pAnchorNode
= rAnchor
.GetAnchorNode();
914 ((RndStdIds::FLY_AT_PARA
== rAnchor
.GetAnchorId()) ||
915 (RndStdIds::FLY_AT_CHAR
== rAnchor
.GetAnchorId())) &&
916 nSttIdx
<= ( nIdx
= pAnchorNode
->GetIndex() ) &&
927 void GetMergeSel( const SwPaM
& rPam
, SwSelBoxes
& rBoxes
,
928 SwTableBox
** ppMergeBox
, SwUndoTableMerge
* pUndo
)
932 OSL_ENSURE( rPam
.GetPointContentNode() && rPam
.GetMarkContentNode(),
933 "Tabselection not on Cnt." );
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.
940 const SwContentNode
* pCntNd
= rPam
.GetPointContentNode();
941 std::pair
<Point
, bool> const tmp(aPt
, true);
942 const SwLayoutFrame
*const pStart
= pCntNd
->getLayoutFrame(
943 pCntNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
944 nullptr, &tmp
)->GetUpper();
945 pCntNd
= rPam
.GetMarkContentNode();
946 const SwLayoutFrame
*const pEnd
= pCntNd
->getLayoutFrame(
947 pCntNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
948 nullptr, &tmp
)->GetUpper();
950 // First, compute tables and rectangles
952 ::MakeSelUnions( aUnions
, pStart
, pEnd
);
953 if( aUnions
.empty() )
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());
961 MergePos aPosArr
; // Sort-Array with the frame positions
963 SwTableBox
* pLastBox
= nullptr;
965 SwRectFnSet
aRectFnSet(pStart
->GetUpper());
967 for ( auto & rSelUnion
: aUnions
)
969 const SwTabFrame
*pTabFrame
= rSelUnion
.GetTable();
971 SwRect
&rUnion
= rSelUnion
.GetUnion();
973 // Skip any repeated headlines in the follow:
974 const SwLayoutFrame
* pRow
= pTabFrame
->IsFollow() ?
975 pTabFrame
->GetFirstNonHeadlineRow() :
976 static_cast<const SwLayoutFrame
*>(pTabFrame
->Lower());
980 if ( pRow
->getFrameArea().Overlaps( rUnion
) )
982 const SwLayoutFrame
*pCell
= pRow
->FirstCell();
984 while ( pCell
&& pRow
->IsAnLower( pCell
) )
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() )
991 SwTableBox
* pBox
= const_cast<SwTableBox
*>(static_cast<const SwCellFrame
*>(pCell
)->GetTabBox());
993 // only overlap to the right?
994 if( ( rUnion
.Left() - COLFUZZY
) <= pCell
->getFrameArea().Left() &&
995 ( rUnion
.Right() - COLFUZZY
) > pCell
->getFrameArea().Left() )
997 if( ( rUnion
.Right() + COLFUZZY
) < pCell
->getFrameArea().Right() )
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
1012 rBoxes
.insert( pBox
);
1014 CmpLPt( aRectFnSet
.GetPos(pCell
->getFrameArea()),
1015 pBox
, aRectFnSet
.IsVert() ) );
1017 pBox
= pBox
->GetUpper()->GetTabBoxes()[ nInsPos
];
1018 aNew
.SetWidth( nTmpWidth
);
1019 pBox
->ClaimFrameFormat();
1020 pBox
->GetFrameFormat()->SetFormatAttr( aNew
);
1023 pUndo
->AddNewBox( pBox
->GetSttIdx() );
1027 // this box is selected
1029 rBoxes
.insert( pBox
);
1031 CmpLPt( aRectFnSet
.GetPos(pCell
->getFrameArea()),
1032 pBox
, aRectFnSet
.IsVert() ) );
1035 // overlapping on left- or right-side
1036 else if( ( rUnion
.Left() - COLFUZZY
) >= pCell
->getFrameArea().Left() &&
1037 ( rUnion
.Right() + COLFUZZY
) < pCell
->getFrameArea().Right() )
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
;
1052 aNew
.SetWidth( nLeft
);
1053 pBox
->GetFrameFormat()->SetFormatAttr( aNew
);
1055 if( const SvxBoxItem
* pItem
= pBox
->GetFrameFormat()->GetAttrSet()
1056 .GetItemIfSet( RES_BOX
, false ))
1058 SvxBoxItem
aBox( *pItem
);
1059 aBox
.SetLine( nullptr, SvxBoxItemLine::RIGHT
);
1060 pBox
->GetFrameFormat()->SetFormatAttr( aBox
);
1063 pBox
= pBox
->GetUpper()->GetTabBoxes()[ nInsPos
];
1064 aNew
.SetWidth( nWidth
);
1065 pBox
->ClaimFrameFormat();
1066 pBox
->GetFrameFormat()->SetFormatAttr( aNew
);
1069 pUndo
->AddNewBox( pBox
->GetSttIdx() );
1071 // this box is selected
1073 rBoxes
.insert( pBox
);
1075 CmpLPt( aRectFnSet
.GetPos(pCell
->getFrameArea()),
1076 pBox
, aRectFnSet
.IsVert() ) );
1078 pBox
= pBox
->GetUpper()->GetTabBoxes()[ nInsPos
+1 ];
1079 aNew
.SetWidth( nRight
);
1080 pBox
->ClaimFrameFormat();
1081 pBox
->GetFrameFormat()->SetFormatAttr( aNew
);
1084 pUndo
->AddNewBox( pBox
->GetSttIdx() );
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() )
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
);
1095 SwFormatFrameSize
aNew(pBox
->GetFrameFormat()->GetFrameSize() );
1096 tools::Long nLeft
= rUnion
.Left() - pCell
->getFrameArea().Left(),
1097 nRight
= pCell
->getFrameArea().Right() - rUnion
.Left();
1099 nLeft
= nLeft
* aNew
.GetWidth() /
1100 pCell
->getFrameArea().Width();
1101 nRight
= nRight
* aNew
.GetWidth() /
1102 pCell
->getFrameArea().Width();
1104 aNew
.SetWidth( nLeft
);
1105 pBox
->ClaimFrameFormat()->SetFormatAttr( aNew
);
1107 // this box is selected
1108 pBox
= pBox
->GetUpper()->GetTabBoxes()[ nInsPos
];
1109 aNew
.SetWidth( nRight
);
1110 pBox
->ClaimFrameFormat();
1111 pBox
->GetFrameFormat()->SetFormatAttr( aNew
);
1114 rBoxes
.insert( pBox
);
1115 aPosArr
.insert( CmpLPt( Point( rUnion
.Left(),
1116 pCell
->getFrameArea().Top()), pBox
, aRectFnSet
.IsVert() ));
1119 pUndo
->AddNewBox( pBox
->GetSttIdx() );
1122 if ( pCell
->GetNext() )
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();
1130 pCell
= ::lcl_FindNextCellFrame( pCell
);
1133 pRow
= static_cast<const SwLayoutFrame
*>(pRow
->GetNext());
1137 // no SSelection / no boxes found
1138 if( 1 >= rBoxes
.size() )
1141 // now search all horizontally adjacent boxes and connect
1142 // their contents with blanks. All vertically adjacent will be tied
1143 // together as paragraphs
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
;
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
1155 SwPaM
aPam( pDoc
->GetNodes() );
1157 #if defined( DEL_ONLY_EMPTY_LINES )
1158 nWidth
= pFirstBox
->GetFrameFormat()->GetFrameSize().GetWidth();
1159 bool bEmptyLine
= sal_True
;
1160 sal_uInt16 n
, nSttPos
= 0;
1162 for( n
= 0; n
< aPosArr
.Count(); ++n
)
1164 const CmpLPt
& rPt
= aPosArr
[ n
];
1165 if( n
&& aPosArr
[ n
- 1 ].Y() == rPt
.Y() ) // same Y level?
1167 if( bEmptyLine
&& !IsEmptyBox( *rPt
.pSelBox
, aPam
))
1168 bEmptyLine
= sal_False
;
1170 nWidth
+= rPt
.pSelBox
->GetFrameFormat()->GetFrameSize().GetWidth();
1174 if( bCalcWidth
&& n
)
1175 bCalcWidth
= false; // one line is ready
1177 if( bEmptyLine
&& nSttPos
< n
)
1179 // now complete line is empty and should not
1180 // be filled with blanks and be inserted as paragraph
1182 for( sal_uInt16 i
= nSttPos
; i
< n
; ++i
)
1183 pUndo
->SaveCollection( *aPosArr
[ i
].pSelBox
);
1185 aPosArr
.Remove( nSttPos
, n
- nSttPos
);
1191 bEmptyLine
= IsEmptyBox( *aPosArr
[n
].pSelBox
, aPam
);
1194 if( bEmptyLine
&& nSttPos
< n
)
1197 for( sal_uInt16 i
= nSttPos
; i
< n
; ++i
)
1198 pUndo
->SaveCollection( *aPosArr
[ i
].pSelBox
);
1199 aPosArr
.Remove( nSttPos
, n
- nSttPos
);
1201 #elif defined( DEL_EMPTY_BOXES_AT_START_AND_END )
1203 nWidth
= pFirstBox
->GetFrameFormat()->GetFrameSize().GetWidth();
1204 sal_uInt16 n
, nSttPos
= 0, nSEndPos
= 0, nESttPos
= 0;
1206 for( n
= 0; n
< aPosArr
.Count(); ++n
)
1208 const CmpLPt
& rPt
= aPosArr
[ n
];
1209 if( n
&& aPosArr
[ n
- 1 ].Y() == rPt
.Y() ) // same Y level?
1211 bool bEmptyBox
= IsEmptyBox( *rPt
.pSelBox
, aPam
);
1214 if( nSEndPos
== n
) // beginning is empty
1215 nESttPos
= ++nSEndPos
;
1217 else // end could be empty
1221 nWidth
+= rPt
.pSelBox
->GetFrameFormat()->GetFrameSize().GetWidth();
1225 if( bCalcWidth
&& n
)
1226 bCalcWidth
= false; // one line ready
1228 // first those at the beginning
1229 if( nSttPos
< nSEndPos
)
1231 // now the beginning of the line is empty and should
1232 // not be filled with blanks
1234 for( sal_uInt16 i
= nSttPos
; i
< nSEndPos
; ++i
)
1235 pUndo
->SaveCollection( *aPosArr
[ i
].pSelBox
);
1237 sal_uInt16 nCnt
= nSEndPos
- nSttPos
;
1238 aPosArr
.Remove( nSttPos
, nCnt
);
1245 // now the beginning of the line is empty and should
1246 // not be filled with blanks
1248 for( sal_uInt16 i
= nESttPos
; i
< n
; ++i
)
1249 pUndo
->SaveCollection( *aPosArr
[ i
].pSelBox
);
1251 sal_uInt16 nCnt
= n
- nESttPos
;
1252 aPosArr
.Remove( nESttPos
, nCnt
);
1256 nSttPos
= nSEndPos
= nESttPos
= n
;
1257 if( IsEmptyBox( *aPosArr
[n
].pSelBox
, aPam
))
1264 // first those at the beginning
1265 if( nSttPos
< nSEndPos
)
1267 // now the beginning of the line is empty and should
1268 // not be filled with blanks
1270 for( sal_uInt16 i
= nSttPos
; i
< nSEndPos
; ++i
)
1271 pUndo
->SaveCollection( *aPosArr
[ i
].pSelBox
);
1273 sal_uInt16 nCnt
= nSEndPos
- nSttPos
;
1274 aPosArr
.Remove( nSttPos
, nCnt
);
1280 // now the beginning of the line is empty and should
1281 // not be filled with blanks
1283 for( sal_uInt16 i
= nESttPos
; i
< n
; ++i
)
1284 pUndo
->SaveCollection( *aPosArr
[ i
].pSelBox
);
1286 sal_uInt16 nCnt
= n
- nESttPos
;
1287 aPosArr
.Remove( nESttPos
, nCnt
);
1290 // DEL_ALL_EMPTY_BOXES
1293 tools::Long nY
= !aPosArr
.empty() ?
1294 ( aRectFnSet
.IsVert() ?
1296 aPosArr
[ 0 ].Y() ) :
1299 for( MergePos::size_type n
= 0; n
< aPosArr
.size(); ++n
)
1301 const CmpLPt
& rPt
= aPosArr
[ n
];
1304 if( nY
== ( aRectFnSet
.IsVert() ? rPt
.X() : rPt
.Y() ) ) // same Y level?
1305 nWidth
+= rPt
.pSelBox
->GetFrameFormat()->GetFrameSize().GetWidth();
1307 bCalcWidth
= false; // one line ready
1310 if( IsEmptyBox( *rPt
.pSelBox
, aPam
) )
1313 pUndo
->SaveCollection( *rPt
.pSelBox
);
1315 aPosArr
.erase( aPosArr
.begin() + n
);
1322 // first create new box
1324 SwTableBox
* pTmpBox
= rBoxes
[0];
1325 SwTableLine
* pInsLine
= pTmpBox
->GetUpper();
1326 sal_uInt16 nInsPos
= pInsLine
->GetBoxPos( pTmpBox
);
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();
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
)
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
);
1348 //Block to delete SwPaM, SwPosition from stack
1349 if( !aPosArr
.empty() )
1351 SwPosition
aInsPos( *(*ppMergeBox
)->GetSttNd() );
1353 SwPaM
aPam( aInsPos
);
1355 for( const auto &rPt
: aPosArr
)
1357 aPam
.GetPoint()->Assign( *rPt
.pSelBox
->GetSttNd()->
1358 EndOfSectionNode(), SwNodeOffset(-1) );
1359 SwContentNode
* pCNd
= aPam
.GetPointContentNode();
1361 aPam
.GetPoint()->SetContent( pCNd
->Len() );
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());
1369 pDoc
->GetIDocumentUndoRedo().DoUndo(false);
1371 pDoc
->getIDocumentContentOperations().AppendTextNode( *aPam
.GetPoint() );
1374 pDoc
->GetIDocumentUndoRedo().DoUndo(bUndo
);
1376 SwNodeRange
aRg( aSttNdIdx
.GetNode(), aPam
.GetPoint()->GetNode() );
1377 aInsPos
.Adjust(SwNodeOffset(1));
1379 pUndo
->MoveBoxContent( *pDoc
, aRg
, aInsPos
.GetNode() );
1382 pDoc
->getIDocumentContentOperations().MoveNodeRange( aRg
, aInsPos
.GetNode(),
1383 SwMoveFlags::DEFAULT
);
1385 // where is now aInsPos ??
1388 bCalcWidth
= false; // one line is ready
1390 // skip the first TextNode
1391 aInsPos
.Assign( *pDoc
->GetNodes()[ aInsPos
.GetNode().EndOfSectionIndex() - 2] );
1392 SwTextNode
* pTextNd
= aInsPos
.GetNode().GetTextNode();
1394 aInsPos
.SetContent( pTextNd
->GetText().getLength());
1397 // the MergeBox should contain the complete text
1398 // now erase the initial TextNode
1399 OSL_ENSURE( (*ppMergeBox
)->GetSttIdx()+2 <
1400 (*ppMergeBox
)->GetSttNd()->EndOfSectionIndex(),
1402 SwNodeIndex
aIdx( *(*ppMergeBox
)->GetSttNd()->EndOfSectionNode(), -1 );
1403 pDoc
->GetNodes().Delete( aIdx
);
1406 // set width of the box
1407 (*ppMergeBox
)->GetFrameFormat()->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable
, nWidth
, 0 ));
1409 pUndo
->AddNewBox( (*ppMergeBox
)->GetSttIdx() );
1412 static bool lcl_CheckCol(FndBox_
const&, bool* pPara
);
1414 static bool lcl_CheckRow( const FndLine_
& rFndLine
, bool* pPara
)
1416 for (auto const& it
: rFndLine
.GetBoxes())
1418 lcl_CheckCol(*it
, pPara
);
1423 static bool lcl_CheckCol( FndBox_
const& rFndBox
, bool* pPara
)
1425 if (!rFndBox
.GetBox()->GetSttNd())
1427 if (rFndBox
.GetLines().size() !=
1428 rFndBox
.GetBox()->GetTabLines().size())
1434 for (auto const& rpFndLine
: rFndBox
.GetLines())
1436 lcl_CheckRow( *rpFndLine
, pPara
);
1440 // is box protected ??
1441 else if (rFndBox
.GetBox()->GetFrameFormat()->GetProtect().IsContentProtected())
1446 TableMergeErr
CheckMergeSel( const SwPaM
& rPam
)
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.
1454 const SwContentNode
* pCntNd
= rPam
.GetPointContentNode();
1455 std::pair
<Point
, bool> tmp(aPt
, true);
1456 const SwLayoutFrame
*const pStart
= pCntNd
->getLayoutFrame(
1457 pCntNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
1458 nullptr, &tmp
)->GetUpper();
1459 pCntNd
= rPam
.GetMarkContentNode();
1460 const SwLayoutFrame
*const pEnd
= pCntNd
->getLayoutFrame(
1461 pCntNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
1462 nullptr, &tmp
)->GetUpper();
1463 GetTableSel( pStart
, pEnd
, aBoxes
, nullptr );
1464 return CheckMergeSel( aBoxes
);
1467 TableMergeErr
CheckMergeSel( const SwSelBoxes
& rBoxes
)
1469 TableMergeErr eRet
= TableMergeErr::NoSelection
;
1470 if( !rBoxes
.empty() )
1472 eRet
= TableMergeErr::Ok
;
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() )
1480 bool bMergeSelOk
= true;
1481 FndBox_
* pFndBox
= &aFndBox
;
1482 FndLine_
* pFndLine
= nullptr;
1483 while( pFndBox
&& 1 == pFndBox
->GetLines().size() )
1485 pFndLine
= pFndBox
->GetLines().front().get();
1486 if( 1 == pFndLine
->GetBoxes().size() )
1487 pFndBox
= pFndLine
->GetBoxes().front().get();
1493 for (auto const& it
: pFndBox
->GetLines())
1495 lcl_CheckRow(*it
, &bMergeSelOk
);
1500 for (auto const& it
: pFndLine
->GetBoxes())
1502 lcl_CheckCol(*it
, &bMergeSelOk
);
1506 eRet
= TableMergeErr::TooComplex
;
1509 eRet
= TableMergeErr::NoSelection
;
1514 static SwTwips
lcl_CalcWish( const SwLayoutFrame
*pCell
, tools::Long nWish
,
1515 const tools::Long nAct
)
1517 const SwLayoutFrame
*pTmp
= pCell
;
1521 const bool bRTL
= pCell
->IsRightToLeft();
1522 SwTwips nRet
= bRTL
?
1523 nAct
- pCell
->getFrameArea().Width() :
1528 while ( pTmp
->GetPrev() )
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
;
1535 pTmp
= pTmp
->GetUpper()->GetUpper();
1536 if ( pTmp
&& !pTmp
->IsCellFrame() )
1542 static void lcl_FindStartEndRow( const SwLayoutFrame
*&rpStart
,
1543 const SwLayoutFrame
*&rpEnd
,
1544 const bool bChkProtected
)
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());
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() )
1557 aSttArr
.push_front( pTmp
);
1559 for( pTmp
= rpEnd
; (SwFrameType::Cell
|SwFrameType::Row
) & pTmp
->GetType();
1560 pTmp
= pTmp
->GetUpper() )
1562 aEndArr
.push_front( pTmp
);
1565 for( std::deque
<const SwLayoutFrame
*>::size_type n
= 0; n
< aEndArr
.size() && n
< aSttArr
.size(); ++n
)
1566 if( aSttArr
[ n
] != aEndArr
[ n
] )
1568 // first unequal line or box - all odds are
1569 if( n
& 1 ) // 1, 3, 5, ... are boxes
1571 rpStart
= aSttArr
[ n
];
1572 rpEnd
= aEndArr
[ n
];
1574 else // 0, 2, 4, ... are lines
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 ];
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() )
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());
1601 if( !bChkProtected
) // protected cell ?
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());
1611 static void lcl_FindStartEndCol( const SwLayoutFrame
*&rpStart
,
1612 const SwLayoutFrame
*&rpEnd
,
1613 const bool bChkProtected
)
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
1620 const SwTabFrame
*pOrg
= rpStart
->FindTabFrame();
1621 const SwTabFrame
*pTab
= pOrg
;
1623 SwRectFnSet
aRectFnSet(pTab
);
1625 bool bRTL
= pTab
->IsRightToLeft();
1626 const tools::Long nTmpWish
= pOrg
->GetFormat()->GetFrameSize().GetWidth();
1627 const tools::Long nWish
= ( nTmpWish
> 0 ) ? nTmpWish
: 1;
1629 while ( pTab
->IsFollow() )
1631 const SwFrame
*pTmp
= pTab
->FindPrev();
1632 OSL_ENSURE( pTmp
->IsTabFrame(), "Predecessor of Follow is not Master." );
1633 pTab
= static_cast<const SwTabFrame
*>(pTmp
);
1639 if ( pTab
->GetTable()->IsNewModel() )
1641 nSX
= aRectFnSet
.GetLeft(rpStart
->getFrameArea());
1642 nSX2
= aRectFnSet
.GetRight(rpStart
->getFrameArea());
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
);
1651 const SwLayoutFrame
*pTmp
= pTab
->FirstCell();
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();
1666 const SwTabFrame
* pLastValidTab
= pTab
;
1667 while ( pTab
->GetFollow() )
1670 // Check if pTab->GetFollow() is a valid follow table:
1671 // Only follow tables with at least on non-FollowFlowLine
1672 // should be considered.
1674 if ( pTab
->HasFollowFlowLine() )
1676 pTab
= pTab
->GetFollow();
1677 const SwFrame
* pTmpRow
= pTab
->GetFirstNonHeadlineRow();
1678 if ( pTmpRow
&& pTmpRow
->GetNext() )
1679 pLastValidTab
= pTab
;
1682 pLastValidTab
= pTab
= pTab
->GetFollow();
1684 pTab
= pLastValidTab
;
1688 if ( pTab
->GetTable()->IsNewModel() )
1690 nEX
= aRectFnSet
.GetLeft(rpEnd
->getFrameArea());
1694 const SwTwips nPrtWidth
= aRectFnSet
.GetWidth(pTab
->getFramePrintArea());
1695 nEX
= ::lcl_CalcWish( rpEnd
, nWish
, nPrtWidth
) + aRectFnSet
.GetPrtLeft(*pTab
);
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;
1704 while( !rpEnd
->IsCellFrame() )
1705 rpEnd
= rpEnd
->GetUpper();
1707 while ( ( bRTL
&& aRectFnSet
.GetLeft(rpEnd
->getFrameArea()) < nEX
) ||
1708 ( ! bRTL
&& aRectFnSet
.GetLeft(rpEnd
->getFrameArea()) > nEX
) )
1710 const SwLayoutFrame
* pTmpLeaf
= rpEnd
->GetPrevLayoutLeaf();
1711 if( !pTmpLeaf
|| !pTab
->IsAnLower( pTmpLeaf
) )
1716 if( !bChkProtected
) // check for protected cell ?
1719 // Beginning and end should not be in protected cells.
1720 // If necessary we should search backwards again
1721 while ( rpStart
->GetFormat()->GetProtect().IsContentProtected() )
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
) )
1732 pTmpTab
= pTmpTab
->GetFollow();
1733 rpStart
= pTmpTab
->FirstCell();
1735 aRectFnSet
.GetLeft(rpStart
->getFrameArea()) < nSX
&&
1736 aRectFnSet
.GetRight(rpStart
->getFrameArea())< nSX2
)
1737 rpStart
= rpStart
->GetNextLayoutLeaf();
1742 while ( rpEnd
->GetFormat()->GetProtect().IsContentProtected() )
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
) )
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();
1765 void MakeSelUnions( SwSelUnions
& rUnions
, const SwLayoutFrame
*pStart
,
1766 const SwLayoutFrame
*pEnd
, const SwTableSearchType eSearchType
)
1768 while ( pStart
&& !pStart
->IsCellFrame() )
1769 pStart
= pStart
->GetUpper();
1770 while ( pEnd
&& !pEnd
->IsCellFrame() )
1771 pEnd
= pEnd
->GetUpper();
1773 if ( !pStart
|| !pEnd
)
1775 OSL_FAIL( "MakeSelUnions with pStart or pEnd not in CellFrame" );
1779 const SwTabFrame
*pTable
= pStart
->FindTabFrame();
1780 const SwTabFrame
*pEndTable
= pEnd
->FindTabFrame();
1781 if( !pTable
|| !pEndTable
)
1783 bool bExchange
= false;
1785 if ( pTable
!= pEndTable
)
1787 if ( !pTable
->IsAnFollow( pEndTable
) )
1789 OSL_ENSURE( pEndTable
->IsAnFollow( pTable
), "Tabchain in knots." );
1795 SwRectFnSet
aRectFnSet(pTable
);
1796 tools::Long nSttTop
= aRectFnSet
.GetTop(pStart
->getFrameArea());
1797 tools::Long nEndTop
= aRectFnSet
.GetTop(pEnd
->getFrameArea());
1798 if( nSttTop
== nEndTop
)
1800 if( aRectFnSet
.GetLeft(pStart
->getFrameArea()) >
1801 aRectFnSet
.GetLeft(pEnd
->getFrameArea()) )
1804 else if( aRectFnSet
.IsVert() == ( nSttTop
< nEndTop
) )
1809 const SwLayoutFrame
*pTmp
= pStart
;
1812 // do no resort pTable and pEndTable, set new below
1813 // MA: 28. Dec. 93 Bug: 5190
1816 // Beginning and end now nicely sorted, if required we
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
) );
1823 if ( !pEnd
|| !pStart
) return; // Made code robust.
1825 // retrieve again, as they have been moved
1826 pTable
= pStart
->FindTabFrame();
1827 pEndTable
= pEnd
->FindTabFrame();
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() );
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
;
1841 nEd1
+= static_cast<tools::Long
>((nEdSz
* nPrtWidth
) / nWish
) - 1;
1843 nSt1
+= static_cast<tools::Long
>((nStSz
* nPrtWidth
) / nWish
) - 1;
1847 if( pTable
->IsAnLower( pStart
) )
1848 nSt2
= aRectFnSet
.GetTop(pStart
->getFrameArea());
1850 nSt2
= aRectFnSet
.GetTop(pTable
->getFrameArea());
1851 if( pTable
->IsAnLower( pEnd
) )
1852 nEd2
= aRectFnSet
.GetBottom(pEnd
->getFrameArea());
1854 nEd2
= aRectFnSet
.GetBottom(pTable
->getFrameArea());
1857 std::swap( nSt1
, nEd1
);
1859 std::swap( nSt2
, nEd2
);
1860 if( aRectFnSet
.IsVert() )
1862 aSt
= Point( nSt2
, nSt1
);
1863 aEd
= Point( nEd2
, nEd1
);
1867 aSt
= Point( nSt1
, nSt2
);
1868 aEd
= Point( nEd1
, nEd2
);
1871 const Point
aDiff( aEd
- aSt
);
1872 SwRect
aUnion( aSt
, Size( aDiff
.X(), aDiff
.Y() ) );
1875 if( !(SwTableSearchType::NoUnionCorrect
& eSearchType
))
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());
1885 while ( pRow
&& !pRow
->getFrameArea().Overlaps( aUnion
) )
1886 pRow
= static_cast<const SwLayoutFrame
*>(pRow
->GetNext());
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() )
1895 const SwFrame
* pTmpRow
= pRow
;
1896 while ( pTmpRow
&& pTmpRow
->IsRowFrame() )
1898 pTmpCell
= static_cast<const SwRowFrame
*>(pTmpRow
)->Lower();
1899 pTmpRow
= static_cast<const SwCellFrame
*>(pTmpCell
)->Lower();
1901 OSL_ENSURE( !pTmpCell
|| pTmpCell
->IsCellFrame(), "Lower of rowframe != cellframe?!" );
1904 const SwLayoutFrame
* pFirst
= pTmpCell
?
1905 static_cast<const SwLayoutFrame
*>(pTmpCell
) :
1910 while ( pFirst
&& !::IsFrameInTableSel( aUnion
, pFirst
) )
1912 if ( pFirst
->GetNext() )
1914 pFirst
= static_cast<const SwLayoutFrame
*>(pFirst
->GetNext());
1915 if ( pFirst
->Lower() && pFirst
->Lower()->IsRowFrame() )
1916 pFirst
= pFirst
->FirstCell();
1919 pFirst
= ::lcl_FindNextCellFrame( pFirst
);
1921 const SwLayoutFrame
* pLast
= nullptr;
1922 SwFrame
const*const pLastContent
= pTable
->FindLastContentOrTable();
1924 pLast
= ::lcl_FindCellFrame( pLastContent
->GetUpper() );
1926 while ( pLast
&& !::IsFrameInTableSel( aUnion
, pLast
) )
1927 pLast
= ::lcl_FindCellFrame( pLast
->GetPrevLayoutLeaf() );
1929 if ( pFirst
&& pLast
) //Robust
1931 aUnion
= pFirst
->getFrameArea();
1932 aUnion
.Union( pLast
->getFrameArea() );
1938 if( aRectFnSet
.GetWidth(aUnion
) )
1940 rUnions
.emplace_back(aUnion
, const_cast<SwTabFrame
*>(pTable
));
1943 pTable
= pTable
->GetFollow();
1944 if ( pTable
!= pEndTable
&& pEndTable
->IsAnFollow( pTable
) )
1949 bool CheckSplitCells( const SwCursorShell
& rShell
, sal_uInt16 nDiv
,
1950 const SwTableSearchType eSearchType
)
1952 if( !rShell
.IsTableMode() )
1955 return CheckSplitCells( *rShell
.getShellCursor(false), nDiv
, eSearchType
);
1958 bool CheckSplitCells( const SwCursor
& rCursor
, sal_uInt16 nDiv
,
1959 const SwTableSearchType eSearchType
)
1964 sal_uInt16 nMinValue
= nDiv
* MINLAY
;
1966 // Get start and end cell
1967 Point aPtPos
, aMkPos
;
1968 const SwShellCursor
* pShCursor
= dynamic_cast<const SwShellCursor
*>(&rCursor
);
1971 aPtPos
= pShCursor
->GetPtPos();
1972 aMkPos
= pShCursor
->GetMkPos();
1975 const SwContentNode
* pCntNd
= rCursor
.GetPointContentNode();
1976 std::pair
<Point
, bool> tmp(aPtPos
, true);
1977 const SwLayoutFrame
*const pStart
= pCntNd
->getLayoutFrame(
1978 pCntNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
1979 nullptr, &tmp
)->GetUpper();
1980 pCntNd
= rCursor
.GetMarkContentNode();
1982 const SwLayoutFrame
*const pEnd
= pCntNd
->getLayoutFrame(
1983 pCntNd
->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(),
1984 nullptr, &tmp
)->GetUpper();
1986 SwRectFnSet
aRectFnSet(pStart
->GetUpper());
1988 // First, compute tables and rectangles
1989 SwSelUnions aUnions
;
1991 ::MakeSelUnions( aUnions
, pStart
, pEnd
, eSearchType
);
1993 // now search boxes for each entry and emit
1994 for ( const auto& rSelUnion
: aUnions
)
1996 const SwTabFrame
*pTable
= rSelUnion
.GetTable();
1998 // Skip any repeated headlines in the follow:
1999 const SwLayoutFrame
* pRow
= pTable
->IsFollow() ?
2000 pTable
->GetFirstNonHeadlineRow() :
2001 static_cast<const SwLayoutFrame
*>(pTable
->Lower());
2005 if ( pRow
->getFrameArea().Overlaps( rSelUnion
.GetUnion() ) )
2007 const SwLayoutFrame
*pCell
= pRow
->FirstCell();
2009 while ( pCell
&& pRow
->IsAnLower( pCell
) )
2011 OSL_ENSURE( pCell
->IsCellFrame(), "Frame without cell" );
2012 if( ::IsFrameInTableSel( rSelUnion
.GetUnion(), pCell
) )
2014 if( aRectFnSet
.GetWidth(pCell
->getFrameArea()) < nMinValue
)
2018 if ( pCell
->GetNext() )
2020 pCell
= static_cast<const SwLayoutFrame
*>(pCell
->GetNext());
2021 if ( pCell
->Lower() && pCell
->Lower()->IsRowFrame() )
2022 pCell
= pCell
->FirstCell();
2025 pCell
= ::lcl_FindNextCellFrame( pCell
);
2028 pRow
= static_cast<const SwLayoutFrame
*>(pRow
->GetNext());
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
2038 static void lcl_InsertRow( SwTableLine
const &rLine
, SwLayoutFrame
*pUpper
, SwFrame
*pSibling
)
2040 SwRowFrame
*pRow
= new SwRowFrame( rLine
, pUpper
);
2041 if ( pUpper
->IsTabFrame() && static_cast<SwTabFrame
*>(pUpper
)->IsFollow() )
2043 SwTabFrame
* pTabFrame
= static_cast<SwTabFrame
*>(pUpper
);
2044 pTabFrame
->FindMaster()->InvalidatePos(); //can absorb the line
2046 if ( pSibling
&& pTabFrame
->IsInHeadline( *pSibling
) )
2048 // Skip any repeated headlines in the follow:
2049 pSibling
= pTabFrame
->GetFirstNonHeadlineRow();
2052 pRow
->Paste( pUpper
, pSibling
);
2056 static void FndBoxCopyCol( SwTableBox
* pBox
, FndPara
* pFndPara
)
2058 std::unique_ptr
<FndBox_
> pFndBox(new FndBox_( pBox
, pFndPara
->pFndLine
));
2059 if( !pBox
->GetTabLines().empty() )
2061 FndPara
aPara( *pFndPara
, pFndBox
.get() );
2062 ForEach_FndLineCopyCol( pFndBox
->GetBox()->GetTabLines(), &aPara
);
2063 if( pFndBox
->GetLines().empty() )
2070 if( pFndPara
->rBoxes
.find( pBox
) == pFndPara
->rBoxes
.end())
2075 pFndPara
->pFndLine
->GetBoxes().push_back( std::move(pFndBox
) );
2078 static void FndLineCopyCol( SwTableLine
* pLine
, FndPara
* pFndPara
)
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() )
2086 pFndPara
->pFndBox
->GetLines().push_back( std::move(pFndLine
) );
2090 void ForEach_FndLineCopyCol(SwTableLines
& rLines
, FndPara
* pFndPara
)
2092 for( SwTableLines::iterator it
= rLines
.begin(); it
!= rLines
.end(); ++it
)
2093 FndLineCopyCol( *it
, pFndPara
);
2096 void FndBox_::SetTableLines( const SwSelBoxes
&rBoxes
, const SwTable
&rTable
)
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.
2104 sal_uInt16 nStPos
= USHRT_MAX
;
2105 sal_uInt16 nEndPos
= 0;
2107 for (size_t i
= 0; i
< rBoxes
.size(); ++i
)
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;
2115 OSL_ENSURE( nPos
!= USHRT_MAX
, "TableLine not found." );
2120 if( nEndPos
< nPos
)
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
];
2129 void FndBox_::SetTableLines( const SwTable
&rTable
)
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.
2137 if( GetLines().empty() )
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" );
2144 m_pLineBefore
= rTable
.GetTabLines()[ nPos
- 1 ];
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
];
2153 inline void UnsetFollow( SwFlowFrame
*pTab
)
2155 pTab
->m_pPrecede
= nullptr;
2158 void FndBox_::DelFrames( SwTable
&rTable
)
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.
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
)
2172 nStPos
= rTable
.GetTabLines().GetPos(
2173 const_cast<const SwTableLine
*&>(m_pLineBefore
) );
2174 OSL_ENSURE( nStPos
!= USHRT_MAX
, "The fox stole the line!" );
2177 if( rTable
.IsNewModel() && m_pLineBehind
)
2178 rTable
.CheckRowSpan( m_pLineBehind
, false );
2179 if ( m_pLineBehind
)
2181 nEndPos
= rTable
.GetTabLines().GetPos(
2182 const_cast<const SwTableLine
*&>(m_pLineBehind
) );
2183 OSL_ENSURE( nEndPos
!= USHRT_MAX
, "The fox stole the line!" );
2188 for ( sal_uInt16 i
= nStPos
; i
<= nEndPos
; ++i
)
2190 SwFrameFormat
*pFormat
= rTable
.GetTabLines()[i
]->GetFrameFormat();
2191 SwIterator
<SwRowFrame
,SwFormat
> aIter( *pFormat
);
2192 for ( SwRowFrame
* pFrame
= aIter
.First(); pFrame
; pFrame
= aIter
.Next() )
2194 if ( pFrame
->GetTabLine() == rTable
.GetTabLines()[i
] )
2197 SwTabFrame
*pUp
= !pFrame
->GetPrev() && !pFrame
->GetNext() ?
2198 static_cast<SwTabFrame
*>(pFrame
->GetUpper()) : nullptr;
2201 const sal_uInt16 nRepeat
=
2202 static_cast<SwTabFrame
*>(pFrame
->GetUpper())->GetTable()->GetRowsToRepeat();
2204 static_cast<SwTabFrame
*>(pFrame
->GetUpper())->IsFollow() )
2206 if ( !pFrame
->GetNext() )
2208 SwRowFrame
* pFirstNonHeadline
=
2209 static_cast<SwTabFrame
*>(pFrame
->GetUpper())->GetFirstNonHeadlineRow();
2210 if ( pFirstNonHeadline
== pFrame
)
2212 pUp
= static_cast<SwTabFrame
*>(pFrame
->GetUpper());
2219 SwTabFrame
*pFollow
= pUp
->GetFollow();
2220 SwTabFrame
*pPrev
= pUp
->IsFollow() ? pUp
: nullptr;
2223 SwFrame
*pTmp
= pPrev
->FindPrev();
2224 OSL_ENSURE( pTmp
->IsTabFrame(),
2225 "Predecessor of Follow is no Master.");
2226 pPrev
= static_cast<SwTabFrame
*>(pTmp
);
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 );
2238 ::UnsetFollow( pFollow
);
2240 // A TableFrame should always remain!
2241 if ( pPrev
|| pFollow
)
2243 // OD 26.08.2003 #i18103# - if table is in a section,
2244 // lock the section, to avoid its delete.
2246 SwSectionFrame
* pSctFrame
= pUp
->FindSctFrame();
2247 bool bOldSectLock
= false;
2250 bOldSectLock
= pSctFrame
->IsColLocked();
2251 pSctFrame
->ColLock();
2254 if ( pSctFrame
&& !bOldSectLock
)
2256 pSctFrame
->ColUnlock();
2259 SwFrame::DestroyFrame(pUp
);
2260 bDel
= false; // Row goes to /dev/null.
2265 SwFrame
* pTabFrame
= pFrame
->GetUpper();
2266 if ( pTabFrame
->IsTabFrame() &&
2267 !pFrame
->GetNext() &&
2268 static_cast<SwTabFrame
*>(pTabFrame
)->GetFollow() )
2270 // We do not delete the follow flow line,
2271 // this will be done automatically in the
2273 static_cast<SwTabFrame
*>(pTabFrame
)->SetFollowFlowLine( false );
2276 SwFrame::DestroyFrame(pFrame
);
2283 static bool lcl_IsLineOfTableFrame( const SwTabFrame
& rTable
, const SwFrame
& rChk
)
2285 const SwTabFrame
* pTableFrame
= rChk
.FindTabFrame();
2286 if( pTableFrame
->IsFollow() )
2287 pTableFrame
= pTableFrame
->FindMaster( true );
2288 return &rTable
== pTableFrame
;
2291 static void lcl_UpdateRepeatedHeadlines( SwTabFrame
& rTabFrame
, bool bCalcLowers
)
2293 OSL_ENSURE( rTabFrame
.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" );
2295 // Delete remaining headlines:
2296 SwRowFrame
* pLower
= nullptr;
2297 while ( nullptr != ( pLower
= static_cast<SwRowFrame
*>(rTabFrame
.Lower()) ) && pLower
->IsRepeatedHeadline() )
2300 SwFrame::DestroyFrame(pLower
);
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
)
2309 SwRowFrame
* pHeadline
= new SwRowFrame( *rTable
.GetTabLines()[ nIdx
], &rTabFrame
);
2310 pHeadline
->SetRepeatedHeadline( true );
2311 pHeadline
->Paste( &rTabFrame
, pLower
);
2312 pHeadline
->RegistFlys();
2316 rTabFrame
.SetCalcLowers();
2319 void FndBox_::MakeFrames( SwTable
&rTable
)
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
=
2326 rTable
.GetFrameFormat()->GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout();
2327 bool bHideChanges
= pLayout
&& pLayout
->IsHideRedlines();
2329 if ( m_pLineBefore
)
2331 nStPos
= rTable
.GetTabLines().GetPos(
2332 const_cast<const SwTableLine
*&>(m_pLineBefore
) );
2333 OSL_ENSURE( nStPos
!= USHRT_MAX
, "Fox stole the line!" );
2337 if ( m_pLineBehind
)
2339 nEndPos
= rTable
.GetTabLines().GetPos(
2340 const_cast<const SwTableLine
*&>(m_pLineBehind
) );
2341 OSL_ENSURE( nEndPos
!= USHRT_MAX
, "Fox stole the line!" );
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() )
2348 if ( !pTable
->IsFollow() )
2350 SwRowFrame
*pSibling
= nullptr;
2351 SwFrame
*pUpperFrame
= nullptr;
2353 for ( i
= rTable
.GetTabLines().size()-1;
2354 i
>= 0 && !pSibling
; --i
)
2356 SwTableLine
*pLine
= m_pLineBehind
? m_pLineBehind
:
2357 rTable
.GetTabLines()[o3tl::narrowing
<sal_uInt16
>(i
)];
2358 SwIterator
<SwRowFrame
,SwFormat
> aIter( *pLine
->GetFrameFormat() );
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() ) ) )
2369 pSibling
= aIter
.Next();
2374 pUpperFrame
= pSibling
->GetUpper();
2375 if ( !m_pLineBehind
)
2379 // ???? or is this the last Follow of the table ????
2380 pUpperFrame
= pTable
;
2382 SwRedlineTable::size_type nRedlinePos
= 0;
2383 for ( sal_uInt16 j
= nStPos
; j
<= nEndPos
; ++j
)
2385 SwTableLine
* pLine
= rTable
.GetTabLines()[j
];
2386 if ( !bHideChanges
|| !pLine
->IsDeleted(nRedlinePos
) )
2387 ::lcl_InsertRow( *pLine
,
2388 static_cast<SwLayoutFrame
*>(pUpperFrame
), pSibling
);
2390 if ( pUpperFrame
->IsTabFrame() )
2391 static_cast<SwTabFrame
*>(pUpperFrame
)->SetCalcLowers();
2393 else if ( rTable
.GetRowsToRepeat() > 0 )
2395 // Insert new headlines:
2396 lcl_UpdateRepeatedHeadlines( *pTable
, true );
2401 void FndBox_::MakeNewFrames( SwTable
&rTable
, const sal_uInt16 nNumber
,
2402 const bool bBehind
)
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
) ) :
2410 const sal_uInt16 nBhPos
= m_pLineBehind
?
2411 rTable
.GetTabLines().GetPos( const_cast<const SwTableLine
*&>(m_pLineBehind
) ) :
2414 //nNumber: how often did we insert
2415 //nCnt: how many were inserted nNumber times
2417 const sal_uInt16 nCnt
=
2418 ((nBhPos
!= USHRT_MAX
? nBhPos
: rTable
.GetTabLines().size()) -
2419 (nBfPos
!= USHRT_MAX
? nBfPos
+ 1 : 0)) / (nNumber
+ 1);
2421 // search the Master-TabFrame
2422 SwIterator
<SwTabFrame
,SwFormat
> aTabIter( *rTable
.GetFrameFormat() );
2424 for ( pTable
= aTabIter
.First(); pTable
; pTable
= aTabIter
.Next() )
2426 if( !pTable
->IsFollow() )
2428 SwRowFrame
* pSibling
= nullptr;
2429 SwLayoutFrame
*pUpperFrame
= nullptr;
2432 if ( m_pLineBehind
)
2434 SwIterator
<SwRowFrame
,SwFormat
> aIter( *m_pLineBehind
->GetFrameFormat() );
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() ) )
2446 pSibling
= aIter
.Next();
2450 pUpperFrame
= pSibling
->GetUpper();
2453 while( pTable
->GetFollow() )
2454 pTable
= pTable
->GetFollow();
2455 pUpperFrame
= pTable
;
2457 const sal_uInt16 nMax
= nBhPos
!= USHRT_MAX
?
2458 nBhPos
: rTable
.GetTabLines().size();
2460 sal_uInt16 i
= nBfPos
!= USHRT_MAX
? nBfPos
+ 1 + nCnt
: nCnt
;
2462 for ( ; i
< nMax
; ++i
)
2463 ::lcl_InsertRow( *rTable
.GetTabLines()[i
], pUpperFrame
, pSibling
);
2464 if ( pUpperFrame
->IsTabFrame() )
2465 static_cast<SwTabFrame
*>(pUpperFrame
)->SetCalcLowers();
2467 else // insert before
2471 // We are looking for the frame that is behind the row frame
2472 // that should be inserted.
2473 for ( i
= 0; !pSibling
; ++i
)
2475 SwTableLine
* pLine
= m_pLineBefore
? m_pLineBefore
: rTable
.GetTabLines()[i
];
2477 SwIterator
<SwRowFrame
,SwFormat
> aIter( *pLine
->GetFrameFormat() );
2478 pSibling
= aIter
.First();
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() ) ) ) )
2496 pSibling
= aIter
.Next();
2500 pUpperFrame
= pSibling
->GetUpper();
2501 if ( m_pLineBefore
)
2502 pSibling
= static_cast<SwRowFrame
*>( pSibling
->GetNext() );
2504 sal_uInt16 nMax
= nBhPos
!= USHRT_MAX
?
2506 rTable
.GetTabLines().size() - nCnt
;
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();
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
) ) )) )
2526 for ( pTable
= aTabIter
.First(); pTable
; pTable
= aTabIter
.Next() )
2528 if ( pTable
->Lower() )
2530 if ( pTable
->IsFollow() )
2532 lcl_UpdateRepeatedHeadlines( *pTable
, true );
2535 OSL_ENSURE( static_cast<SwRowFrame
*>(pTable
->Lower())->GetTabLine() ==
2536 rTable
.GetTabLines()[0], "MakeNewFrames: Table corruption!" );
2541 bool FndBox_::AreLinesToRestore( const SwTable
&rTable
) const
2543 // Should we call MakeFrames here?
2545 if ( !m_pLineBefore
&& !m_pLineBehind
&& !rTable
.GetTabLines().empty() )
2551 const SwTableLine
* rLBefore
= const_cast<const SwTableLine
*>(m_pLineBefore
);
2552 nBfPos
= rTable
.GetTabLines().GetPos( rLBefore
);
2560 const SwTableLine
* rLBehind
= const_cast<const SwTableLine
*>(m_pLineBehind
);
2561 nBhPos
= rTable
.GetTabLines().GetPos( rLBehind
);
2566 if ( nBfPos
== nBhPos
) // Should never occur.
2568 OSL_FAIL( "Table, erase but not on any area !?!" );
2572 if ( rTable
.GetRowsToRepeat() > 0 )
2574 // oops: should the repeated headline have been deleted??
2575 SwIterator
<SwTabFrame
,SwFormat
> aIter( *rTable
.GetFrameFormat() );
2576 for( SwTabFrame
* pTable
= aIter
.First(); pTable
; pTable
= aIter
.Next() )
2578 if( pTable
->IsFollow() )
2580 // Insert new headlines:
2581 lcl_UpdateRepeatedHeadlines( *pTable
, false );
2586 // Some adjacent lines at the beginning of the table have been deleted:
2587 if ( nBfPos
== USHRT_MAX
&& nBhPos
== 0 )
2590 // Some adjacent lines at the end of the table have been deleted:
2591 if ( nBhPos
== USHRT_MAX
&& nBfPos
== (rTable
.GetTabLines().size() - 1) )
2594 // Some adjacent lines in the middle of the table have been deleted:
2595 if ( nBfPos
!= USHRT_MAX
&& nBhPos
!= USHRT_MAX
&& (nBfPos
+ 1) == nBhPos
)
2598 // The structure of the deleted lines is more complex due to split lines.
2599 // A call of MakeFrames() is necessary.
2603 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */