LibreOffice Module sw (master) 1
ndtbl1.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 <hintids.hxx>
21#include <editeng/boxitem.hxx>
22#include <editeng/brushitem.hxx>
24#include <fesh.hxx>
25#include <fmtornt.hxx>
26#include <fmtfsize.hxx>
27#include <fmtrowsplt.hxx>
28#include <tabcol.hxx>
29#include <frmatr.hxx>
30#include <cellfrm.hxx>
31#include <tabfrm.hxx>
32#include <cntfrm.hxx>
33#include <txtfrm.hxx>
34#include <svx/svxids.hrc>
35#include <doc.hxx>
36#include <IDocumentUndoRedo.hxx>
37#include <IDocumentState.hxx>
41#include <pam.hxx>
42#include <swcrsr.hxx>
43#include <viscrs.hxx>
44#include <swtable.hxx>
45#include <htmltbl.hxx>
46#include <tblsel.hxx>
47#include <swtblfmt.hxx>
48#include <ndindex.hxx>
49#include <undobj.hxx>
50#include <calbck.hxx>
51#include <UndoTable.hxx>
52#include <o3tl/enumrange.hxx>
53#include <o3tl/safeint.hxx>
54#include <osl/diagnose.h>
55
56using ::editeng::SvxBorderLine;
57using namespace ::com::sun::star;
58
59// See swtable.cxx too
60#define COLFUZZY 20L
61
62static bool IsSame( tools::Long nA, tools::Long nB ) { return std::abs(nA-nB) <= COLFUZZY; }
63
64namespace {
65
66// SwTableLine::ChgFrameFormat may delete old format which doesn't have writer listeners anymore.
67// This may invalidate my pointers, and lead to use-after-free. For this reason, I register myself
68// as a writer listener for the old format here, and take care to delete formats without listeners
69// in my own dtor.
70class SwTableFormatCmp : public SwClient
71{
72public:
73 SwTableFormatCmp( SwFrameFormat *pOld, SwFrameFormat *pNew, sal_Int16 nType );
74 ~SwTableFormatCmp() override;
75
76 static SwFrameFormat* FindNewFormat(std::vector<std::unique_ptr<SwTableFormatCmp>>& rArr,
77 SwFrameFormat const* pOld, sal_Int16 nType);
78
79private:
80 SwFrameFormat *m_pOld, *m_pNew;
81 sal_Int16 m_nType;
82};
83
84}
85
86SwTableFormatCmp::SwTableFormatCmp(SwFrameFormat* pO, SwFrameFormat* pN, sal_Int16 nT)
87 : m_pOld(pO)
88 , m_pNew(pN)
89 , m_nType(nT)
90{
91 if (m_pOld)
92 m_pOld->Add(this);
93}
94
95SwTableFormatCmp::~SwTableFormatCmp()
96{
97 if (m_pOld)
98 {
99 m_pOld->Remove(this);
100 if (!m_pOld->HasWriterListeners())
101 delete m_pOld;
102 }
103}
104
105// static
106SwFrameFormat* SwTableFormatCmp::FindNewFormat(std::vector<std::unique_ptr<SwTableFormatCmp>>& rArr,
107 SwFrameFormat const* pOld, sal_Int16 nType)
108{
109 for (const auto& pCmp : rArr)
110 {
111 if (pCmp->m_pOld == pOld && pCmp->m_nType == nType)
112 return pCmp->m_pNew;
113 }
114 return nullptr;
115}
116
117static void lcl_GetStartEndCell( const SwCursor& rCursor,
118 SwLayoutFrame *&prStart, SwLayoutFrame *&prEnd )
119{
120 OSL_ENSURE( rCursor.GetContentNode() && rCursor.GetContentNode( false ),
121 "Tab selection not at ContentNode" );
122
123 Point aPtPos, aMkPos;
124 const SwShellCursor* pShCursor = dynamic_cast<const SwShellCursor*>(&rCursor);
125 if( pShCursor )
126 {
127 aPtPos = pShCursor->GetPtPos();
128 aMkPos = pShCursor->GetMkPos();
129 }
130
131 // Robust:
132 SwContentNode* pPointNd = rCursor.GetContentNode();
133 SwContentNode* pMarkNd = rCursor.GetContentNode(false);
134
135 std::pair<Point, bool> tmp(aPtPos, true);
136 SwFrame *const pPointFrame = pPointNd ? pPointNd->getLayoutFrame(pPointNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp) : nullptr;
137 tmp.first = aMkPos;
138 SwFrame *const pMarkFrame = pMarkNd ? pMarkNd->getLayoutFrame(pMarkNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp) : nullptr;
139
140 prStart = pPointFrame ? pPointFrame->GetUpper() : nullptr;
141 prEnd = pMarkFrame ? pMarkFrame->GetUpper() : nullptr;
142}
143
144static bool lcl_GetBoxSel( const SwCursor& rCursor, SwSelBoxes& rBoxes,
145 bool bAllCursor = false )
146{
147 const SwTableCursor* pTableCursor =
148 dynamic_cast<const SwTableCursor*>(&rCursor);
149 if( pTableCursor )
150 ::GetTableSelCrs( *pTableCursor, rBoxes );
151 else
152 {
153 const SwPaM *pCurPam = &rCursor, *pSttPam = pCurPam;
154 do {
155 const SwNode* pNd = pCurPam->GetNode().FindTableBoxStartNode();
156 if( pNd )
157 {
158 SwTableBox* pBox = const_cast<SwTableBox*>(pNd->FindTableNode()->GetTable().
159 GetTableBox( pNd->GetIndex() ));
160 rBoxes.insert( pBox );
161 }
162 } while( bAllCursor &&
163 pSttPam != ( pCurPam = pCurPam->GetNext()) );
164 }
165 return !rBoxes.empty();
166}
167
168static void InsertLine( std::vector<SwTableLine*>& rLineArr, SwTableLine* pLine )
169{
170 if( rLineArr.end() == std::find( rLineArr.begin(), rLineArr.end(), pLine ) )
171 rLineArr.push_back( pLine );
172}
173
174static bool lcl_IsAnLower( const SwTableLine *pLine, const SwTableLine *pAssumed )
175{
176 const SwTableLine *pTmp = pAssumed->GetUpper() ?
177 pAssumed->GetUpper()->GetUpper() : nullptr;
178 while ( pTmp )
179 {
180 if ( pTmp == pLine )
181 return true;
182 pTmp = pTmp->GetUpper() ? pTmp->GetUpper()->GetUpper() : nullptr;
183 }
184 return false;
185}
186
187namespace {
188
189struct LinesAndTable
190{
191 std::vector<SwTableLine*> &m_rLines;
192 const SwTable &m_rTable;
193 bool m_bInsertLines;
194
195 LinesAndTable(std::vector<SwTableLine*> &rL, const SwTable &rTable) :
196 m_rLines(rL), m_rTable(rTable), m_bInsertLines(true) {}
197};
198
199}
200
201static bool FindLine_( FndLine_ & rLine, LinesAndTable* pPara );
202
203static bool FindBox_( FndBox_ & rBox, LinesAndTable* pPara )
204{
205 if (!rBox.GetLines().empty())
206 {
207 pPara->m_bInsertLines = true;
208 for (auto const& rpFndLine : rBox.GetLines())
209 {
210 FindLine_(*rpFndLine, pPara);
211 }
212
213 if (pPara->m_bInsertLines)
214 {
215 const SwTableLines &rLines = (rBox.GetBox())
216 ? rBox.GetBox()->GetTabLines()
217 : pPara->m_rTable.GetTabLines();
218 if (rBox.GetLines().size() == rLines.size())
219 {
220 for ( auto pLine : rLines )
221 ::InsertLine(pPara->m_rLines, pLine);
222 }
223 else
224 pPara->m_bInsertLines = false;
225 }
226 }
227 else if (rBox.GetBox())
228 {
229 ::InsertLine(pPara->m_rLines, rBox.GetBox()->GetUpper());
230 }
231 return true;
232}
233
234bool FindLine_( FndLine_& rLine, LinesAndTable* pPara )
235{
236 for (auto const& it : rLine.GetBoxes())
237 {
238 FindBox_(*it, pPara);
239 }
240 return true;
241}
242
243static void lcl_CollectLines( std::vector<SwTableLine*> &rArr, const SwCursor& rCursor, bool bRemoveLines )
244{
245 // Collect the selected Boxes first
246 SwSelBoxes aBoxes;
247 if( !::lcl_GetBoxSel( rCursor, aBoxes ))
248 return ;
249
250 // Copy the selected structure
251 const SwTable &rTable = aBoxes[0]->GetSttNd()->FindTableNode()->GetTable();
252 LinesAndTable aPara( rArr, rTable );
253 FndBox_ aFndBox( nullptr, nullptr );
254 {
255 FndPara aTmpPara( aBoxes, &aFndBox );
256 ForEach_FndLineCopyCol( const_cast<SwTableLines&>(rTable.GetTabLines()), &aTmpPara );
257 }
258
259 // Collect the Lines which only contain selected Boxes
260 ::FindBox_(aFndBox, &aPara);
261
262 // Remove lines, that have a common superordinate row.
263 // (Not for row split)
264 if ( !bRemoveLines )
265 return;
266
267 for ( std::vector<SwTableLine*>::size_type i = 0; i < rArr.size(); ++i )
268 {
269 SwTableLine *pUpLine = rArr[i];
270 for ( std::vector<SwTableLine*>::size_type k = 0; k < rArr.size(); ++k )
271 {
272 if ( k != i && ::lcl_IsAnLower( pUpLine, rArr[k] ) )
273 {
274 rArr.erase( rArr.begin() + k );
275 if ( k <= i )
276 --i;
277 --k;
278 }
279 }
280 }
281}
282
283static void lcl_ProcessRowAttr(std::vector<std::unique_ptr<SwTableFormatCmp>>& rFormatCmp,
284 SwTableLine* pLine, const SfxPoolItem& rNew)
285{
286 SwFrameFormat *pNewFormat = SwTableFormatCmp::FindNewFormat( rFormatCmp, pLine->GetFrameFormat(), 0 );
287 if ( nullptr != pNewFormat )
288 pLine->ChgFrameFormat( static_cast<SwTableLineFormat*>(pNewFormat) );
289 else
290 {
291 SwFrameFormat *pOld = pLine->GetFrameFormat();
292 SwFrameFormat *pNew = pLine->ClaimFrameFormat();
293 pNew->SetFormatAttr( rNew );
294 rFormatCmp.push_back(std::make_unique<SwTableFormatCmp>(pOld, pNew, 0));
295 }
296}
297
298static void lcl_ProcessBoxSize(std::vector<std::unique_ptr<SwTableFormatCmp>>& rFormatCmp,
299 SwTableBox* pBox, const SwFormatFrameSize& rNew);
300
301static void lcl_ProcessRowSize(std::vector<std::unique_ptr<SwTableFormatCmp>>& rFormatCmp,
302 SwTableLine* pLine, const SwFormatFrameSize& rNew)
303{
304 lcl_ProcessRowAttr( rFormatCmp, pLine, rNew );
305 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
306 for ( auto pBox : rBoxes )
307 ::lcl_ProcessBoxSize( rFormatCmp, pBox, rNew );
308}
309
310static void lcl_ProcessBoxSize(std::vector<std::unique_ptr<SwTableFormatCmp>>& rFormatCmp,
311 SwTableBox* pBox, const SwFormatFrameSize& rNew)
312{
313 SwTableLines &rLines = pBox->GetTabLines();
314 if ( !rLines.empty() )
315 {
316 SwFormatFrameSize aSz( rNew );
317 aSz.SetHeight( rNew.GetHeight() ? rNew.GetHeight() / rLines.size() : 0 );
318 for ( auto pLine : rLines )
319 ::lcl_ProcessRowSize( rFormatCmp, pLine, aSz );
320 }
321}
322
323void SwDoc::SetRowSplit( const SwCursor& rCursor, const SwFormatRowSplit &rNew )
324{
325 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
326 if( !pTableNd )
327 return;
328
329 std::vector<SwTableLine*> aRowArr; // For Lines collecting
330 ::lcl_CollectLines( aRowArr, rCursor, false );
331
332 if( aRowArr.empty() )
333 return;
334
335 if (GetIDocumentUndoRedo().DoesUndo())
336 {
337 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
338 }
339
340 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
341 aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
342
343 for( auto pLn : aRowArr )
344 ::lcl_ProcessRowAttr( aFormatCmp, pLn, rNew );
345
347}
348
349std::unique_ptr<SwFormatRowSplit> SwDoc::GetRowSplit( const SwCursor& rCursor )
350{
351 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
352 if( !pTableNd )
353 return nullptr;
354
355 std::vector<SwTableLine*> aRowArr; // For Lines collecting
356 ::lcl_CollectLines( aRowArr, rCursor, false );
357
358 if( aRowArr.empty() )
359 return nullptr;
360
361 SwFormatRowSplit* pSz = &const_cast<SwFormatRowSplit&>(aRowArr[0]->GetFrameFormat()->GetRowSplit());
362
363 for ( auto pLn : aRowArr )
364 {
365 if ( pSz->GetValue() != pLn->GetFrameFormat()->GetRowSplit().GetValue() )
366 {
367 return nullptr;
368 }
369 }
370 return std::make_unique<SwFormatRowSplit>( *pSz );
371}
372
373/* Class: SwDoc
374 * Methods: SetRowHeight(), GetRowHeight()
375 *
376 * The line height is calculated from the Selection.
377 * Starting with every Cell within the Selection, all Cells are iterated
378 * through in an upwards fashion.
379 *
380 * The topmost Line gets the requested value, all Lines below it get
381 * a respective value that is calculated from the relation of the old and
382 * new size of the topmost Line in the lower line's own size.
383 *
384 * All changed Lines may get an own FrameFormat.
385 * Of course we can only touch every Line once.
386 */
387
388void SwDoc::SetRowHeight( const SwCursor& rCursor, const SwFormatFrameSize &rNew )
389{
390 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
391 if( !pTableNd )
392 return;
393
394 std::vector<SwTableLine*> aRowArr; // For Lines collecting
395 ::lcl_CollectLines( aRowArr, rCursor, true );
396
397 if( aRowArr.empty() )
398 return;
399
400 if (GetIDocumentUndoRedo().DoesUndo())
401 {
402 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
403 }
404
405 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
406 aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
407 for ( auto pLn : aRowArr )
408 ::lcl_ProcessRowSize( aFormatCmp, pLn, rNew );
409
411}
412
413std::unique_ptr<SwFormatFrameSize> SwDoc::GetRowHeight( const SwCursor& rCursor )
414{
415 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
416 if( !pTableNd )
417 return nullptr;
418
419 std::vector<SwTableLine*> aRowArr; // For Lines collecting
420 ::lcl_CollectLines( aRowArr, rCursor, true );
421
422 if( aRowArr.empty() )
423 return nullptr;
424
425 SwFormatFrameSize* pSz = &const_cast<SwFormatFrameSize&>(aRowArr[0]->GetFrameFormat()->GetFrameSize());
426
427 for ( auto pLn : aRowArr )
428 {
429 if ( *pSz != pLn->GetFrameFormat()->GetFrameSize() )
430 return nullptr;
431 }
432 return std::make_unique<SwFormatFrameSize>( *pSz );
433}
434
435bool SwDoc::BalanceRowHeight( const SwCursor& rCursor, bool bTstOnly, const bool bOptimize )
436{
437 bool bRet = false;
438 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
439 if( pTableNd )
440 {
441 std::vector<SwTableLine*> aRowArr; // For Lines collecting
442 ::lcl_CollectLines( aRowArr, rCursor, true );
443
444 if( 1 < aRowArr.size() )
445 {
446 if( !bTstOnly )
447 {
448 tools::Long nHeight = 0;
449 sal_Int32 nTotalHeight = 0;
450 for ( auto pLn : aRowArr )
451 {
452 if (bOptimize)
453 nHeight = 0;
454 SwIterator<SwFrame,SwFormat> aIter( *pLn->GetFrameFormat() );
455 SwFrame* pFrame = aIter.First();
456 while ( pFrame )
457 {
458 nHeight = std::max( nHeight, pFrame->getFrameArea().Height() );
459 pFrame = aIter.Next();
460 }
461 nTotalHeight += nHeight;
462 }
463
464 if ( bOptimize )
465 nHeight = nTotalHeight / aRowArr.size();
466
467 SwFormatFrameSize aNew( SwFrameSize::Minimum, 0, nHeight );
468
469 if (GetIDocumentUndoRedo().DoesUndo())
470 {
472 std::make_unique<SwUndoAttrTable>(*pTableNd));
473 }
474
475 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
476 aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
477 for( auto pLn : aRowArr )
478 ::lcl_ProcessRowSize( aFormatCmp, pLn, aNew );
479
481 }
482 bRet = true;
483 }
484 }
485 return bRet;
486}
487
488void SwDoc::SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew )
489{
490 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
491 if( !pTableNd )
492 return;
493
494 std::vector<SwTableLine*> aRowArr; // For Lines collecting
495 ::lcl_CollectLines( aRowArr, rCursor, true );
496
497 if( aRowArr.empty() )
498 return;
499
500 if (GetIDocumentUndoRedo().DoesUndo())
501 {
502 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
503 }
504
505 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
506 aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
507
508 for( auto pLn : aRowArr )
509 ::lcl_ProcessRowAttr( aFormatCmp, pLn, rNew );
510
512}
513
514bool SwDoc::GetRowBackground( const SwCursor& rCursor, std::unique_ptr<SvxBrushItem>& rToFill )
515{
516 bool bRet = false;
517 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
518 if( pTableNd )
519 {
520 std::vector<SwTableLine*> aRowArr; // For Lines collecting
521 ::lcl_CollectLines( aRowArr, rCursor, true );
522
523 if( !aRowArr.empty() )
524 {
525 rToFill = aRowArr[0]->GetFrameFormat()->makeBackgroundBrushItem();
526
527 bRet = true;
528 for ( std::vector<SwTableLine*>::size_type i = 1; i < aRowArr.size(); ++i )
529 {
530 std::unique_ptr<SvxBrushItem> aAlternative(aRowArr[i]->GetFrameFormat()->makeBackgroundBrushItem());
531
532 if ( *rToFill != *aAlternative )
533 {
534 bRet = false;
535 break;
536 }
537 }
538 }
539 }
540 return bRet;
541}
542
543bool SwDoc::HasRowNotTracked( const SwCursor& rCursor )
544{
545 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
546 if( !pTableNd )
547 return false;
548
549 std::vector<SwTableLine*> aRowArr; // For Lines collecting
550 ::lcl_CollectLines( aRowArr, rCursor, true );
551
552 if( aRowArr.empty() )
553 return false;
554
555 for( auto pLn : aRowArr )
556 {
557 auto pHasTextChangesOnlyProp = pLn->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
558 if ( !pHasTextChangesOnlyProp || pHasTextChangesOnlyProp->GetValue() )
559 // there is a not deleted row in the table selection
560 return true;
561 }
562 return false;
563}
564
565void SwDoc::SetRowNotTracked( const SwCursor& rCursor, const SvxPrintItem &rNew, bool bAll )
566{
567 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
568 if( !pTableNd )
569 return;
570
571 std::vector<SwTableLine*> aRowArr; // For Lines collecting
572 if ( bAll )
573 {
574 const SwTableLines &rLines = pTableNd->GetTable().GetTabLines();
575 aRowArr.insert(aRowArr.end(), rLines.begin(), rLines.end());
576 }
577 else
578 ::lcl_CollectLines( aRowArr, rCursor, true );
579
580 if( aRowArr.empty() )
581 return;
582
583 if (GetIDocumentUndoRedo().DoesUndo())
584 {
585 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
586 }
587
588 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
589 aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
590
591 for( auto pLn : aRowArr )
592 {
593 ::lcl_ProcessRowAttr( aFormatCmp, pLn, rNew );
594 // as a workaround for the rows without text content,
595 // add a redline with invisible text CH_TXT_TRACKED_DUMMY_CHAR
596 // (unless the table is part of a bigger deletion, where the
597 // new redline can cause a problem)
598 if ( !bAll &&
599 // HasTextChangesOnly == false, i.e. a tracked row insertion or deletion
600 !rNew.GetValue() && pLn->IsEmpty() )
601 {
602 SwNodeIndex aInsPos( *(pLn->GetTabBoxes()[0]->GetSttNd()), 1 );
605 SwPaM aPaM(aInsPos);
607 OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
608 aPaM.SetMark();
609 aPaM.GetMark()->nContent.Assign(aPaM.GetContentNode(), 0);
612 }
613 }
614
616}
617
618static void InsertCell( std::vector<SwCellFrame*>& rCellArr, SwCellFrame* pCellFrame )
619{
620 if( rCellArr.end() == std::find( rCellArr.begin(), rCellArr.end(), pCellFrame ) )
621 rCellArr.push_back( pCellFrame );
622}
623
624static void lcl_CollectCells( std::vector<SwCellFrame*> &rArr, const SwRect &rUnion,
625 SwTabFrame *pTab )
626{
627 SwLayoutFrame *pCell = pTab->FirstCell();
628 do
629 {
630 // If the Cell contains a CellFrame, we need to use it
631 // in order to get to the Cell
632 while ( !pCell->IsCellFrame() )
633 pCell = pCell->GetUpper();
634 OSL_ENSURE( pCell, "Frame is not a Cell" );
635 if ( rUnion.Overlaps( pCell->getFrameArea() ) )
636 ::InsertCell( rArr, static_cast<SwCellFrame*>(pCell) );
637
638 // Make sure the Cell is left (Areas)
639 SwLayoutFrame *pTmp = pCell;
640 do
641 { pTmp = pTmp->GetNextLayoutLeaf();
642 } while ( pCell->IsAnLower( pTmp ) );
643 pCell = pTmp;
644 } while( pCell && pTab->IsAnLower( pCell ) );
645}
646
647void SwDoc::SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet )
648{
649 SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
650 SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
651 if( !pTableNd )
652 return ;
653
654 SwLayoutFrame *pStart, *pEnd;
655 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
656
657 SwSelUnions aUnions;
658 ::MakeSelUnions( aUnions, pStart, pEnd );
659
660 if( aUnions.empty() )
661 return;
662
663 SwTable& rTable = pTableNd->GetTable();
664 if (GetIDocumentUndoRedo().DoesUndo())
665 {
666 GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoAttrTable>(*pTableNd) );
667 }
668
669 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
670 aFormatCmp.reserve( 255 );
671 const SvxBoxItem* pSetBox;
672 const SvxBoxInfoItem *pSetBoxInfo;
673
674 const SvxBorderLine* pLeft = nullptr;
675 const SvxBorderLine* pRight = nullptr;
676 const SvxBorderLine* pTop = nullptr;
677 const SvxBorderLine* pBottom = nullptr;
678 const SvxBorderLine* pHori = nullptr;
679 const SvxBorderLine* pVert = nullptr;
680 bool bHoriValid = true, bVertValid = true,
681 bTopValid = true, bBottomValid = true,
682 bLeftValid = true, bRightValid = true;
683
684 // The Flags in the BoxInfo Item decide whether a BorderLine is valid!
685 pSetBoxInfo = rSet.GetItemIfSet( SID_ATTR_BORDER_INNER, false );
686 if( pSetBoxInfo )
687 {
688 pHori = pSetBoxInfo->GetHori();
689 pVert = pSetBoxInfo->GetVert();
690
691 bHoriValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::HORI);
692 bVertValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::VERT);
693
694 // Do we want to evaluate these?
695 bTopValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::TOP);
696 bBottomValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
697 bLeftValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::LEFT);
698 bRightValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::RIGHT);
699 }
700
701 pSetBox = rSet.GetItemIfSet( RES_BOX, false );
702 if( pSetBox )
703 {
704 pLeft = pSetBox->GetLeft();
705 pRight = pSetBox->GetRight();
706 pTop = pSetBox->GetTop();
707 pBottom = pSetBox->GetBottom();
708 }
709 else
710 {
711 // Not set, thus not valid values
712 bTopValid = bBottomValid = bLeftValid = bRightValid = false;
713 pSetBox = nullptr;
714 }
715
716 bool bFirst = true;
717 for ( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
718 {
719 SwSelUnion *pUnion = &aUnions[i];
720 SwTabFrame *pTab = pUnion->GetTable();
721 const SwRect &rUnion = pUnion->GetUnion();
722 const bool bLast = (i == aUnions.size() - 1);
723
724 std::vector<SwCellFrame*> aCellArr;
725 aCellArr.reserve( 255 );
726 ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
727
728 // All Cell Borders that match the UnionRect or extend it are
729 // Outer Borders. All others are Inner Borders.
730
731 // New: The Outer Borders can, depending on whether it's a
732 // Start/Middle/Follow Table (for Selection via FollowTabs),
733 // also not be Outer Borders.
734 // Outer Borders are set on the left, right, at the top and at the bottom.
735 // Inner Borders are only set at the top and on the left.
736 for ( auto pCell : aCellArr )
737 {
738 const bool bVert = pTab->IsVertical();
739 const bool bRTL = pTab->IsRightToLeft();
740 bool bTopOver, bLeftOver, bRightOver, bBottomOver;
741 if ( bVert )
742 {
743 bTopOver = pCell->getFrameArea().Right() >= rUnion.Right();
744 bLeftOver = pCell->getFrameArea().Top() <= rUnion.Top();
745 bRightOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
746 bBottomOver = pCell->getFrameArea().Left() <= rUnion.Left();
747 }
748 else
749 {
750 bTopOver = pCell->getFrameArea().Top() <= rUnion.Top();
751 bLeftOver = pCell->getFrameArea().Left() <= rUnion.Left();
752 bRightOver = pCell->getFrameArea().Right() >= rUnion.Right();
753 bBottomOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
754 }
755
756 if ( bRTL )
757 {
758 bool bTmp = bRightOver;
759 bRightOver = bLeftOver;
760 bLeftOver = bTmp;
761 }
762
763 // Do not set anything by default in HeadlineRepeats
764 if ( pTab->IsFollow() &&
765 ( pTab->IsInHeadline( *pCell ) ||
766 // Same holds for follow flow rows
767 pCell->IsInFollowFlowRow() ) )
768 continue;
769
770 SvxBoxItem aBox( pCell->GetFormat()->GetBox() );
771
772 sal_Int16 nType = 0;
773
774 // Top Border
775 if( bTopValid )
776 {
777 if ( bFirst && bTopOver )
778 {
779 aBox.SetLine( pTop, SvxBoxItemLine::TOP );
780 nType |= 0x0001;
781 }
782 else if ( bHoriValid )
783 {
784 aBox.SetLine( nullptr, SvxBoxItemLine::TOP );
785 nType |= 0x0002;
786 }
787 }
788
789 // Fix fdo#62470 correct the input for RTL table
790 if (bRTL)
791 {
792 if( bLeftOver && bRightOver)
793 {
794 if ( bLeftValid )
795 {
796 aBox.SetLine( pLeft, SvxBoxItemLine::RIGHT );
797 nType |= 0x0010;
798 }
799 if ( bRightValid )
800 {
801 aBox.SetLine( pRight, SvxBoxItemLine::LEFT );
802 nType |= 0x0004;
803 }
804 }
805 else
806 {
807 if ( bLeftValid )
808 {
809 aBox.SetLine( bRightOver ? pLeft : nullptr, SvxBoxItemLine::RIGHT );
810 if (bVertValid)
811 nType |= 0x0020;
812 else
813 nType |= 0x0010;
814 }
815 if ( bLeftOver )
816 {
817 if ( bRightValid )
818 {
819 aBox.SetLine( pRight, SvxBoxItemLine::LEFT );
820 nType |= 0x0004;
821 }
822 }
823 else if ( bVertValid )
824 {
825 aBox.SetLine( pVert, SvxBoxItemLine::LEFT );
826 nType |= 0x0008;
827 }
828 }
829 }
830 else
831 {
832 // Left Border
833 if ( bLeftOver )
834 {
835 if( bLeftValid )
836 {
837 aBox.SetLine( pLeft, SvxBoxItemLine::LEFT );
838 nType |= 0x0004;
839 }
840 }
841 else if( bVertValid )
842 {
843 aBox.SetLine( pVert, SvxBoxItemLine::LEFT );
844 nType |= 0x0008;
845 }
846
847 // Right Border
848 if( bRightValid )
849 {
850 if ( bRightOver )
851 {
852 aBox.SetLine( pRight, SvxBoxItemLine::RIGHT );
853 nType |= 0x0010;
854 }
855 else if ( bVertValid )
856 {
857 aBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
858 nType |= 0x0020;
859 }
860 }
861 }
862
863 // Bottom Border
864 if ( bLast && bBottomOver )
865 {
866 if( bBottomValid )
867 {
868 aBox.SetLine( pBottom, SvxBoxItemLine::BOTTOM );
869 nType |= 0x0040;
870 }
871 }
872 else if( bHoriValid )
873 {
874 aBox.SetLine( pHori, SvxBoxItemLine::BOTTOM );
875 nType |= 0x0080;
876 }
877
878 if( pSetBox )
879 {
881 aBox.SetDistance( pSetBox->GetDistance( k ), k );
882 }
883
884 SwTableBox *pBox = const_cast<SwTableBox*>(pCell->GetTabBox());
885 SwFrameFormat *pNewFormat = SwTableFormatCmp::FindNewFormat( aFormatCmp, pBox->GetFrameFormat(), nType );
886 if ( nullptr != pNewFormat )
887 pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(pNewFormat) );
888 else
889 {
890 SwFrameFormat *pOld = pBox->GetFrameFormat();
891 SwFrameFormat *pNew = pBox->ClaimFrameFormat();
892 pNew->SetFormatAttr( aBox );
893 aFormatCmp.push_back(std::make_unique<SwTableFormatCmp>(pOld, pNew, nType));
894 }
895 }
896
897 bFirst = false;
898 }
899
900 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
901 if( pTableLayout )
902 {
904 SwTabFrame* pTabFrame = pFrame->ImplFindTabFrame();
905
906 pTableLayout->BordersChanged(
907 pTableLayout->GetBrowseWidthByTabFrame( *pTabFrame ) );
908 }
909 ::ClearFEShellTabCols(*this, nullptr);
911}
912
913static void lcl_SetLineStyle( SvxBorderLine *pToSet,
914 const Color *pColor, const SvxBorderLine *pBorderLine)
915{
916 if ( pBorderLine )
917 {
918 if ( !pColor )
919 {
920 Color aTmp( pToSet->GetColor() );
921 *pToSet = *pBorderLine;
922 pToSet->SetColor( aTmp );
923 }
924 else
925 *pToSet = *pBorderLine;
926 }
927 if ( pColor )
928 pToSet->SetColor( *pColor );
929}
930
931void SwDoc::SetTabLineStyle( const SwCursor& rCursor,
932 const Color* pColor, bool bSetLine,
933 const SvxBorderLine* pBorderLine )
934{
935 SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
936 SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
937 if( !pTableNd )
938 return ;
939
940 SwLayoutFrame *pStart, *pEnd;
941 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
942
943 SwSelUnions aUnions;
944 ::MakeSelUnions( aUnions, pStart, pEnd );
945
946 if( aUnions.empty() )
947 return;
948
949 SwTable& rTable = pTableNd->GetTable();
950 if (GetIDocumentUndoRedo().DoesUndo())
951 {
952 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
953 }
954
955 SvxBorderLine aDefaultBorder(pBorderLine ? *pBorderLine
956 : SvxBorderLine(pColor, SvxBorderLineWidth::VeryThin));
957 if (pColor && pBorderLine)
958 aDefaultBorder.SetColor(*pColor);
959
960 for( auto &rU : aUnions )
961 {
962 SwSelUnion *pUnion = &rU;
963 SwTabFrame *pTab = pUnion->GetTable();
964 std::vector<SwCellFrame*> aCellArr;
965 aCellArr.reserve( 255 );
966 ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
967
968 for ( auto pCell : aCellArr )
969 {
970 // Do not set anything by default in HeadlineRepeats
971 if ( pTab->IsFollow() && pTab->IsInHeadline( *pCell ) )
972 continue;
973
974 const_cast<SwTableBox*>(pCell->GetTabBox())->ClaimFrameFormat();
975 SwFrameFormat *pFormat = pCell->GetFormat();
976 std::unique_ptr<SvxBoxItem> aBox(pFormat->GetBox().Clone());
977
978 SvxBorderLine* pTop = const_cast<SvxBorderLine*>(aBox->GetTop());
979 SvxBorderLine* pBot = const_cast<SvxBorderLine*>(aBox->GetBottom());
980 SvxBorderLine* pLeft = const_cast<SvxBorderLine*>(aBox->GetLeft());
981 SvxBorderLine* pRight = const_cast<SvxBorderLine*>(aBox->GetRight());
982
983 if ( !pBorderLine && bSetLine )
984 {
985 aBox.reset(::GetDfltAttr(RES_BOX)->Clone());
986 }
987 else if ((pColor || pBorderLine) && !pTop && !pBot && !pLeft && !pRight)
988 {
989 aBox->SetLine(&aDefaultBorder, SvxBoxItemLine::TOP);
990 aBox->SetLine(&aDefaultBorder, SvxBoxItemLine::BOTTOM);
991 aBox->SetLine(&aDefaultBorder, SvxBoxItemLine::LEFT);
992 aBox->SetLine(&aDefaultBorder, SvxBoxItemLine::RIGHT);
993 }
994 else
995 {
996 if (pTop)
997 ::lcl_SetLineStyle(pTop, pColor, pBorderLine);
998 if (pBot)
999 ::lcl_SetLineStyle(pBot, pColor, pBorderLine);
1000 if (pLeft)
1001 ::lcl_SetLineStyle(pLeft, pColor, pBorderLine);
1002 if (pRight)
1003 ::lcl_SetLineStyle(pRight, pColor, pBorderLine);
1004 }
1005 pFormat->SetFormatAttr( *aBox );
1006 }
1007 }
1008
1009 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
1010 if( pTableLayout )
1011 {
1013 SwTabFrame* pTabFrame = pFrame->ImplFindTabFrame();
1014
1015 pTableLayout->BordersChanged(
1016 pTableLayout->GetBrowseWidthByTabFrame( *pTabFrame ) );
1017 }
1018 ::ClearFEShellTabCols(*this, nullptr);
1020}
1021
1022void SwDoc::GetTabBorders( const SwCursor& rCursor, SfxItemSet& rSet )
1023{
1024 SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
1025 SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
1026 if( !pTableNd )
1027 return ;
1028
1029 SwLayoutFrame *pStart, *pEnd;
1030 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
1031
1032 SwSelUnions aUnions;
1033 ::MakeSelUnions( aUnions, pStart, pEnd );
1034
1035 if( aUnions.empty() )
1036 return;
1037
1038 SvxBoxItem aSetBox ( rSet.Get(RES_BOX ) );
1039 SvxBoxInfoItem aSetBoxInfo( rSet.Get(SID_ATTR_BORDER_INNER) );
1040
1041 bool bTopSet = false,
1042 bBottomSet = false,
1043 bLeftSet = false,
1044 bRightSet = false,
1045 bHoriSet = false,
1046 bVertSet = false,
1047 bDistanceSet = false,
1048 bRTLTab = false;
1049
1050 aSetBoxInfo.ResetFlags();
1051
1052 for ( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
1053 {
1054 SwSelUnion *pUnion = &aUnions[i];
1055 const SwTabFrame *pTab = pUnion->GetTable();
1056 const SwRect &rUnion = pUnion->GetUnion();
1057 const bool bFirst = i == 0;
1058 const bool bLast = (i == aUnions.size() - 1);
1059
1060 std::vector<SwCellFrame*> aCellArr;
1061 aCellArr.reserve(255);
1062 ::lcl_CollectCells( aCellArr, rUnion, const_cast<SwTabFrame*>(pTab) );
1063
1064 for ( auto pCell : aCellArr )
1065 {
1066 const bool bVert = pTab->IsVertical();
1067 const bool bRTL = bRTLTab = pTab->IsRightToLeft();
1068 bool bTopOver, bLeftOver, bRightOver, bBottomOver;
1069 if ( bVert )
1070 {
1071 bTopOver = pCell->getFrameArea().Right() >= rUnion.Right();
1072 bLeftOver = pCell->getFrameArea().Top() <= rUnion.Top();
1073 bRightOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
1074 bBottomOver = pCell->getFrameArea().Left() <= rUnion.Left();
1075 }
1076 else
1077 {
1078 bTopOver = pCell->getFrameArea().Top() <= rUnion.Top();
1079 bLeftOver = pCell->getFrameArea().Left() <= rUnion.Left();
1080 bRightOver = pCell->getFrameArea().Right() >= rUnion.Right();
1081 bBottomOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
1082 }
1083
1084 if ( bRTL )
1085 {
1086 bool bTmp = bRightOver;
1087 bRightOver = bLeftOver;
1088 bLeftOver = bTmp;
1089 }
1090
1091 const SwFrameFormat *pFormat = pCell->GetFormat();
1092 const SvxBoxItem &rBox = pFormat->GetBox();
1093
1094 // Top Border
1095 if ( bFirst && bTopOver )
1096 {
1097 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::TOP))
1098 {
1099 if ( !bTopSet )
1100 { bTopSet = true;
1101 aSetBox.SetLine( rBox.GetTop(), SvxBoxItemLine::TOP );
1102 }
1103 else if ((aSetBox.GetTop() && rBox.GetTop() &&
1104 (*aSetBox.GetTop() != *rBox.GetTop())) ||
1105 ((!aSetBox.GetTop()) != (!rBox.GetTop()))) // != expression is true, if one and only one of the two pointers is !0
1106 {
1107 aSetBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, false );
1108 aSetBox.SetLine( nullptr, SvxBoxItemLine::TOP );
1109 }
1110 }
1111 }
1112
1113 // Left Border
1114 if ( bLeftOver )
1115 {
1116 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::LEFT))
1117 {
1118 if ( !bLeftSet )
1119 { bLeftSet = true;
1120 aSetBox.SetLine( rBox.GetLeft(), SvxBoxItemLine::LEFT );
1121 }
1122 else if ((aSetBox.GetLeft() && rBox.GetLeft() &&
1123 (*aSetBox.GetLeft() != *rBox.GetLeft())) ||
1124 ((!aSetBox.GetLeft()) != (!rBox.GetLeft())))
1125 {
1126 aSetBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, false );
1127 aSetBox.SetLine( nullptr, SvxBoxItemLine::LEFT );
1128 }
1129 }
1130 }
1131 else
1132 {
1133 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::VERT))
1134 {
1135 if ( !bVertSet )
1136 { bVertSet = true;
1137 aSetBoxInfo.SetLine( rBox.GetLeft(), SvxBoxInfoItemLine::VERT );
1138 }
1139 else if ((aSetBoxInfo.GetVert() && rBox.GetLeft() &&
1140 (*aSetBoxInfo.GetVert() != *rBox.GetLeft())) ||
1141 ((!aSetBoxInfo.GetVert()) != (!rBox.GetLeft())))
1142 { aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::VERT, false );
1143 aSetBoxInfo.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
1144 }
1145 }
1146 }
1147
1148 // Right Border
1149 if ( aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::RIGHT) && bRightOver )
1150 {
1151 if ( !bRightSet )
1152 { bRightSet = true;
1153 aSetBox.SetLine( rBox.GetRight(), SvxBoxItemLine::RIGHT );
1154 }
1155 else if ((aSetBox.GetRight() && rBox.GetRight() &&
1156 (*aSetBox.GetRight() != *rBox.GetRight())) ||
1157 (!aSetBox.GetRight() != !rBox.GetRight()))
1158 { aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::RIGHT, false );
1159 aSetBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
1160 }
1161 }
1162
1163 // Bottom Border
1164 if ( bLast && bBottomOver )
1165 {
1166 if ( aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::BOTTOM) )
1167 {
1168 if ( !bBottomSet )
1169 { bBottomSet = true;
1170 aSetBox.SetLine( rBox.GetBottom(), SvxBoxItemLine::BOTTOM );
1171 }
1172 else if ((aSetBox.GetBottom() && rBox.GetBottom() &&
1173 (*aSetBox.GetBottom() != *rBox.GetBottom())) ||
1174 (!aSetBox.GetBottom() != !rBox.GetBottom()))
1175 { aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, false );
1176 aSetBox.SetLine( nullptr, SvxBoxItemLine::BOTTOM );
1177 }
1178 }
1179 }
1180 // In all Lines, except for the last one, the horizontal Line
1181 // is taken from the Bottom Line.
1182 else
1183 {
1184 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::HORI))
1185 {
1186 if ( !bHoriSet )
1187 { bHoriSet = true;
1188 aSetBoxInfo.SetLine( rBox.GetBottom(), SvxBoxInfoItemLine::HORI );
1189 }
1190 else if ((aSetBoxInfo.GetHori() && rBox.GetBottom() &&
1191 (*aSetBoxInfo.GetHori() != *rBox.GetBottom())) ||
1192 ((!aSetBoxInfo.GetHori()) != (!rBox.GetBottom())))
1193 {
1194 aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::HORI, false );
1195 aSetBoxInfo.SetLine( nullptr, SvxBoxInfoItemLine::HORI );
1196 }
1197 }
1198 }
1199
1200 // Distance to text
1201 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::DISTANCE))
1202 {
1203 if( !bDistanceSet ) // Set on first iteration
1204 {
1205 bDistanceSet = true;
1207 aSetBox.SetDistance( rBox.GetDistance( k ), k );
1208 }
1209 else
1210 {
1212 if( aSetBox.GetDistance( k ) !=
1213 rBox.GetDistance( k ) )
1214 {
1215 aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::DISTANCE, false );
1216 aSetBox.SetAllDistances(0);
1217 break;
1218 }
1219 }
1220 }
1221 }
1222 }
1223
1224 // fdo#62470 fix the reading for table format.
1225 if ( bRTLTab )
1226 {
1227 SvxBoxItem aTempBox ( rSet.Get(RES_BOX ) );
1228 SvxBoxInfoItem aTempBoxInfo( rSet.Get(SID_ATTR_BORDER_INNER) );
1229
1230 aTempBox.SetLine( aSetBox.GetRight(), SvxBoxItemLine::RIGHT);
1231 aSetBox.SetLine( aSetBox.GetLeft(), SvxBoxItemLine::RIGHT);
1232 aSetBox.SetLine( aTempBox.GetRight(), SvxBoxItemLine::LEFT);
1233
1234 aTempBoxInfo.SetValid( SvxBoxInfoItemValidFlags::LEFT, aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::LEFT) );
1235 aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::LEFT, aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::RIGHT) );
1236 aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::RIGHT, aTempBoxInfo.IsValid(SvxBoxInfoItemValidFlags::LEFT) );
1237 }
1238
1239 rSet.Put( aSetBox );
1240 rSet.Put( aSetBoxInfo );
1241}
1242
1243void SwDoc::SetBoxAttr( const SwCursor& rCursor, const SfxPoolItem &rNew )
1244{
1245 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1246 SwSelBoxes aBoxes;
1247 if( !(pTableNd && ::lcl_GetBoxSel( rCursor, aBoxes, true )) )
1248 return;
1249
1250 SwTable& rTable = pTableNd->GetTable();
1251 if (GetIDocumentUndoRedo().DoesUndo())
1252 {
1253 GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoAttrTable>(*pTableNd) );
1254 }
1255
1256 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
1257 aFormatCmp.reserve(std::max<size_t>(255, aBoxes.size()));
1258 for (size_t i = 0; i < aBoxes.size(); ++i)
1259 {
1260 SwTableBox *pBox = aBoxes[i];
1261
1262 SwFrameFormat *pNewFormat = SwTableFormatCmp::FindNewFormat( aFormatCmp, pBox->GetFrameFormat(), 0 );
1263 if ( nullptr != pNewFormat )
1264 pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(pNewFormat) );
1265 else
1266 {
1267 SwFrameFormat *pOld = pBox->GetFrameFormat();
1268 SwFrameFormat *pNew = pBox->ClaimFrameFormat();
1269 pNew->SetFormatAttr( rNew );
1270 aFormatCmp.push_back(std::make_unique<SwTableFormatCmp>(pOld, pNew, 0));
1271 }
1272
1273 pBox->SetDirectFormatting(true);
1274 }
1275
1276 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
1277 if( pTableLayout )
1278 {
1280 SwTabFrame* pTabFrame = pFrame->ImplFindTabFrame();
1281
1282 pTableLayout->Resize(
1283 pTableLayout->GetBrowseWidthByTabFrame( *pTabFrame ), true );
1284 }
1286}
1287
1288bool SwDoc::GetBoxAttr( const SwCursor& rCursor, std::unique_ptr<SfxPoolItem>& rToFill )
1289{
1290 // tdf#144843 calling GetBoxAttr *requires* object
1291 assert(rToFill && "requires object here");
1292 bool bRet = false;
1293 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1294 SwSelBoxes aBoxes;
1295 if( pTableNd && lcl_GetBoxSel( rCursor, aBoxes ))
1296 {
1297 bRet = true;
1298 bool bOneFound = false;
1299 const sal_uInt16 nWhich = rToFill->Which();
1300 for (size_t i = 0; i < aBoxes.size(); ++i)
1301 {
1302 switch ( nWhich )
1303 {
1304 case RES_BACKGROUND:
1305 {
1306 std::unique_ptr<SvxBrushItem> xBack =
1307 aBoxes[i]->GetFrameFormat()->makeBackgroundBrushItem();
1308 if( !bOneFound )
1309 {
1310 rToFill = std::move(xBack);
1311 bOneFound = true;
1312 }
1313 else if( *rToFill != *xBack )
1314 bRet = false;
1315 }
1316 break;
1317
1318 case RES_FRAMEDIR:
1319 {
1320 const SvxFrameDirectionItem& rDir =
1321 aBoxes[i]->GetFrameFormat()->GetFrameDir();
1322 if( !bOneFound )
1323 {
1324 rToFill.reset(rDir.Clone());
1325 bOneFound = true;
1326 }
1327 else if( rToFill && *rToFill != rDir )
1328 bRet = false;
1329 }
1330 break;
1331 case RES_VERT_ORIENT:
1332 {
1333 const SwFormatVertOrient& rOrient =
1334 aBoxes[i]->GetFrameFormat()->GetVertOrient();
1335 if( !bOneFound )
1336 {
1337 rToFill.reset(rOrient.Clone());
1338 bOneFound = true;
1339 }
1340 else if( rToFill && *rToFill != rOrient )
1341 bRet = false;
1342 }
1343 break;
1344 }
1345
1346 if ( !bRet )
1347 break;
1348 }
1349 }
1350 return bRet;
1351}
1352
1353void SwDoc::SetBoxAlign( const SwCursor& rCursor, sal_uInt16 nAlign )
1354{
1355 OSL_ENSURE( nAlign == text::VertOrientation::NONE ||
1356 nAlign == text::VertOrientation::CENTER ||
1357 nAlign == text::VertOrientation::BOTTOM, "Wrong alignment" );
1358 SwFormatVertOrient aVertOri( 0, nAlign );
1359 SetBoxAttr( rCursor, aVertOri );
1360}
1361
1362sal_uInt16 SwDoc::GetBoxAlign( const SwCursor& rCursor )
1363{
1364 sal_uInt16 nAlign = USHRT_MAX;
1365 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1366 SwSelBoxes aBoxes;
1367 if( pTableNd && ::lcl_GetBoxSel( rCursor, aBoxes ))
1368 {
1369 for (size_t i = 0; i < aBoxes.size(); ++i)
1370 {
1371 const SwFormatVertOrient &rOri =
1372 aBoxes[i]->GetFrameFormat()->GetVertOrient();
1373 if( USHRT_MAX == nAlign )
1374 nAlign = o3tl::narrowing<sal_uInt16>(rOri.GetVertOrient());
1375 else if( rOri.GetVertOrient() != nAlign )
1376 {
1377 nAlign = USHRT_MAX;
1378 break;
1379 }
1380 }
1381 }
1382 return nAlign;
1383}
1384
1385static sal_uInt16 lcl_CalcCellFit( const SwLayoutFrame *pCell )
1386{
1387 SwTwips nRet = 0;
1388 const SwFrame *pFrame = pCell->Lower(); // The whole Line
1389 SwRectFnSet aRectFnSet(pCell);
1390 while ( pFrame )
1391 {
1392 const SwTwips nAdd = aRectFnSet.GetWidth(pFrame->getFrameArea()) -
1393 aRectFnSet.GetWidth(pFrame->getFramePrintArea());
1394
1395 // pFrame does not necessarily have to be a SwTextFrame!
1396 const SwTwips nCalcFitToContent = pFrame->IsTextFrame() ?
1397 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pFrame))->CalcFitToContent() :
1398 aRectFnSet.GetWidth(pFrame->getFramePrintArea());
1399
1400 nRet = std::max( nRet, nCalcFitToContent + nAdd );
1401 pFrame = pFrame->GetNext();
1402 }
1403 // Surrounding border as well as left and Right Border also need to be respected
1404 nRet += aRectFnSet.GetWidth(pCell->getFrameArea()) -
1405 aRectFnSet.GetWidth(pCell->getFramePrintArea());
1406
1407 // To compensate for the accuracy of calculation later on in SwTable::SetTabCols
1408 // we keep adding up a little.
1409 nRet += COLFUZZY;
1410 return o3tl::narrowing<sal_uInt16>(std::max( SwTwips(MINLAY), nRet ));
1411}
1412
1413/* The Line is within the Selection but not outlined by the TabCols.
1414 *
1415 * That means that the Line has been "split" by other Cells due to the
1416 * two-dimensional representation used. Thus, we have to distribute the cell's
1417 * default or minimum value amongst the Cell it has been split by.
1418 *
1419 * First, we collect the Columns (not the Column separators) which overlap
1420 * with the Cell. We then distribute the desired value according to the
1421 * amount of overlapping amongst the Cells.
1422 *
1423 * A Cell's default value stays the same if it already has a larger value than
1424 * the desired one. It's overwritten if it's smaller.
1425 */
1426static void lcl_CalcSubColValues( std::vector<sal_uInt16> &rToFill, const SwTabCols &rCols,
1427 const SwLayoutFrame *pCell, const SwLayoutFrame *pTab,
1428 bool bWishValues )
1429{
1430 const sal_uInt16 nWish = bWishValues ?
1431 ::lcl_CalcCellFit( pCell ) :
1432 MINLAY + sal_uInt16(pCell->getFrameArea().Width() - pCell->getFramePrintArea().Width());
1433
1434 SwRectFnSet aRectFnSet(pTab);
1435
1436 for ( size_t i = 0 ; i <= rCols.Count(); ++i )
1437 {
1438 tools::Long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1];
1439 tools::Long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1440 nColLeft += rCols.GetLeftMin();
1441 nColRight += rCols.GetLeftMin();
1442
1443 // Adapt values to the proportions of the Table (Follows)
1444 if ( rCols.GetLeftMin() != aRectFnSet.GetLeft(pTab->getFrameArea()) )
1445 {
1446 const tools::Long nDiff = aRectFnSet.GetLeft(pTab->getFrameArea()) - rCols.GetLeftMin();
1447 nColLeft += nDiff;
1448 nColRight += nDiff;
1449 }
1450 const tools::Long nCellLeft = aRectFnSet.GetLeft(pCell->getFrameArea());
1451 const tools::Long nCellRight = aRectFnSet.GetRight(pCell->getFrameArea());
1452
1453 // Calculate overlapping value
1454 tools::Long nWidth = 0;
1455 if ( nColLeft <= nCellLeft && nColRight >= (nCellLeft+COLFUZZY) )
1456 nWidth = nColRight - nCellLeft;
1457 else if ( nColLeft <= (nCellRight-COLFUZZY) && nColRight >= nCellRight )
1458 nWidth = nCellRight - nColLeft;
1459 else if ( nColLeft >= nCellLeft && nColRight <= nCellRight )
1460 nWidth = nColRight - nColLeft;
1461 if ( nWidth && pCell->getFrameArea().Width() )
1462 {
1463 tools::Long nTmp = nWidth * nWish / pCell->getFrameArea().Width();
1464 if ( o3tl::make_unsigned(nTmp) > rToFill[i] )
1465 rToFill[i] = sal_uInt16(nTmp);
1466 }
1467 }
1468}
1469
1488static void lcl_CalcColValues( std::vector<sal_uInt16> &rToFill, const SwTabCols &rCols,
1489 const SwLayoutFrame *pStart, const SwLayoutFrame *pEnd,
1490 bool bWishValues )
1491{
1492 SwSelUnions aUnions;
1493 ::MakeSelUnions( aUnions, pStart, pEnd,
1495
1496 for ( auto &rU : aUnions )
1497 {
1498 SwSelUnion *pSelUnion = &rU;
1499 const SwTabFrame *pTab = pSelUnion->GetTable();
1500 const SwRect &rUnion = pSelUnion->GetUnion();
1501
1502 SwRectFnSet aRectFnSet(pTab);
1503 bool bRTL = pTab->IsRightToLeft();
1504
1505 const SwLayoutFrame *pCell = pTab->FirstCell();
1506 if (!pCell)
1507 continue;
1508 do
1509 {
1510 if ( pCell->IsCellFrame() && pCell->FindTabFrame() == pTab && ::IsFrameInTableSel( rUnion, pCell ) )
1511 {
1512 const tools::Long nCLeft = aRectFnSet.GetLeft(pCell->getFrameArea());
1513 const tools::Long nCRight = aRectFnSet.GetRight(pCell->getFrameArea());
1514
1515 bool bNotInCols = true;
1516
1517 for ( size_t i = 0; i <= rCols.Count(); ++i )
1518 {
1519 sal_uInt16 nFit = rToFill[i];
1520 tools::Long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1];
1521 tools::Long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1522
1523 if ( bRTL )
1524 {
1525 tools::Long nTmpRight = nColRight;
1526 nColRight = rCols.GetRight() - nColLeft;
1527 nColLeft = rCols.GetRight() - nTmpRight;
1528 }
1529
1530 nColLeft += rCols.GetLeftMin();
1531 nColRight += rCols.GetLeftMin();
1532
1533 // Adapt values to the proportions of the Table (Follows)
1534 tools::Long nLeftA = nColLeft;
1535 tools::Long nRightA = nColRight;
1536 if ( rCols.GetLeftMin() != sal_uInt16(aRectFnSet.GetLeft(pTab->getFrameArea())) )
1537 {
1538 const tools::Long nDiff = aRectFnSet.GetLeft(pTab->getFrameArea()) - rCols.GetLeftMin();
1539 nLeftA += nDiff;
1540 nRightA += nDiff;
1541 }
1542
1543 // We don't want to take a too close look
1544 if ( ::IsSame(nCLeft, nLeftA) && ::IsSame(nCRight, nRightA))
1545 {
1546 bNotInCols = false;
1547 if ( bWishValues )
1548 {
1549 const sal_uInt16 nWish = ::lcl_CalcCellFit( pCell );
1550 if ( nWish > nFit )
1551 nFit = nWish;
1552 }
1553 else
1554 { const sal_uInt16 nMin = MINLAY + sal_uInt16(pCell->getFrameArea().Width() -
1555 pCell->getFramePrintArea().Width());
1556 if ( !nFit || nMin < nFit )
1557 nFit = nMin;
1558 }
1559 if ( rToFill[i] < nFit )
1560 rToFill[i] = nFit;
1561 }
1562 }
1563 if ( bNotInCols )
1564 ::lcl_CalcSubColValues( rToFill, rCols, pCell, pTab, bWishValues );
1565 }
1566 do {
1567 pCell = pCell->GetNextLayoutLeaf();
1568 } while( pCell && pCell->getFrameArea().Width() == 0 );
1569 } while ( pCell && pTab->IsAnLower( pCell ) );
1570 }
1571}
1572
1574 const bool bBalance,
1575 const bool bNoShrink )
1576{
1577 // Check whether the current Cursor has it's Point/Mark in a Table
1578 SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
1579 SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
1580 if( !pTableNd )
1581 return ;
1582
1583 SwLayoutFrame *pStart, *pEnd;
1584 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
1585
1586 // Collect TabCols; we reset the Table with them
1587 SwFrame* pBoxFrame = pStart;
1588 while( pBoxFrame && !pBoxFrame->IsCellFrame() )
1589 pBoxFrame = pBoxFrame->GetUpper();
1590
1591 if ( !pBoxFrame )
1592 return; // Robust
1593
1594 SwTabCols aTabCols;
1595 GetTabCols( aTabCols, static_cast<SwCellFrame*>(pBoxFrame) );
1596
1597 if ( ! aTabCols.Count() )
1598 return;
1599
1600 std::vector<sal_uInt16> aWish(aTabCols.Count() + 1);
1601 std::vector<sal_uInt16> aMins(aTabCols.Count() + 1);
1602
1603 ::lcl_CalcColValues( aWish, aTabCols, pStart, pEnd, /*bWishValues=*/true );
1604
1605 // It's more robust if we calculate the minimum values for the whole Table
1606 const SwTabFrame *pTab = pStart->ImplFindTabFrame();
1607 pStart = const_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame const *>(pTab->FirstCell()));
1608 pEnd = const_cast<SwLayoutFrame*>(pTab->FindLastContentOrTable()->GetUpper());
1609 while( !pEnd->IsCellFrame() )
1610 pEnd = pEnd->GetUpper();
1611 ::lcl_CalcColValues( aMins, aTabCols, pStart, pEnd, /*bWishValues=*/false );
1612
1613 sal_uInt16 nSelectedWidth = 0, nCols = 0;
1614 float fTotalWish = 0;
1615 if ( bBalance || bNoShrink )
1616 {
1617 // Find the combined size of the selected columns
1618 for ( size_t i = 0; i <= aTabCols.Count(); ++i )
1619 {
1620 if ( aWish[i] )
1621 {
1622 if ( i == 0 )
1623 nSelectedWidth += aTabCols[i] - aTabCols.GetLeft();
1624 else if ( i == aTabCols.Count() )
1625 nSelectedWidth += aTabCols.GetRight() - aTabCols[i-1];
1626 else
1627 nSelectedWidth += aTabCols[i] - aTabCols[i-1];
1628 ++nCols;
1629 }
1630 fTotalWish += aWish[i];
1631 }
1632 const sal_uInt16 nEqualWidth = nSelectedWidth / nCols;
1633 // bBalance: Distribute the width evenly
1634 for (sal_uInt16 & rn : aWish)
1635 if ( rn && bBalance )
1636 rn = nEqualWidth;
1637 }
1638
1639 const tools::Long nOldRight = aTabCols.GetRight();
1640
1641 // In order to make the implementation easier, but still use the available
1642 // space properly, we do this twice.
1643
1644 // The problem: The first column is getting wider, the others get slimmer
1645 // only afterwards.
1646 // The first column's desired width would be discarded as it would cause
1647 // the Table's width to exceed the maximum width.
1648 const sal_uInt16 nEqualWidth = (aTabCols.GetRight() - aTabCols.GetLeft()) / (aTabCols.Count() + 1);
1649 const sal_Int16 nTablePadding = nSelectedWidth - fTotalWish;
1650 for ( int k = 0; k < 2; ++k )
1651 {
1652 for ( size_t i = 0; i <= aTabCols.Count(); ++i )
1653 {
1654 // bNoShrink: distribute excess space proportionately on pass 2.
1655 if ( bNoShrink && k && nTablePadding > 0 && fTotalWish > 0 )
1656 aWish[i] += round( aWish[i] / fTotalWish * nTablePadding );
1657
1658 // First pass is primarily a shrink pass. Give all columns a chance
1659 // to grow by requesting the maximum width as "balanced".
1660 // Second pass is a first-come, first-served chance to max out.
1661 int nDiff = k ? aWish[i] : std::min(aWish[i], nEqualWidth);
1662 if ( nDiff )
1663 {
1664 int nMin = aMins[i];
1665 if ( nMin > nDiff )
1666 nDiff = nMin;
1667
1668 if ( i == 0 )
1669 {
1670 if( aTabCols.Count() )
1671 nDiff -= aTabCols[0] - aTabCols.GetLeft();
1672 else
1673 nDiff -= aTabCols.GetRight() - aTabCols.GetLeft();
1674 }
1675 else if ( i == aTabCols.Count() )
1676 nDiff -= aTabCols.GetRight() - aTabCols[i-1];
1677 else
1678 nDiff -= aTabCols[i] - aTabCols[i-1];
1679
1680 tools::Long nTabRight = aTabCols.GetRight() + nDiff;
1681 const tools::Long nMaxRight = std::max(aTabCols.GetRightMax(), nOldRight);
1682
1683 // If the Table would become (or is already) too wide,
1684 // restrict the column growth to the allowed maximum.
1685 if (!bBalance && nTabRight > nMaxRight)
1686 {
1687 const tools::Long nTmpD = nTabRight - nMaxRight;
1688 nDiff -= nTmpD;
1689 nTabRight -= nTmpD;
1690 }
1691
1692 // all the remaining columns need to be shifted by the same amount
1693 for ( size_t i2 = i; i2 < aTabCols.Count(); ++i2 )
1694 aTabCols[i2] += nDiff;
1695 aTabCols.SetRight( nTabRight );
1696 }
1697 }
1698 }
1699
1700 const tools::Long nNewRight = aTabCols.GetRight();
1701
1702 SwFrameFormat *pFormat = pTableNd->GetTable().GetFrameFormat();
1703 const sal_Int16 nOriHori = pFormat->GetHoriOrient().GetHoriOrient();
1704
1705 // We can leave the "real" work to the SwTable now
1706 SetTabCols( aTabCols, false, static_cast<SwCellFrame*>(pBoxFrame) );
1707
1708 // Alignment might have been changed in SetTabCols; restore old value
1709 const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient();
1710 SwFormatHoriOrient aHori( rHori );
1711 if ( aHori.GetHoriOrient() != nOriHori )
1712 {
1713 aHori.SetHoriOrient( nOriHori );
1714 pFormat->SetFormatAttr( aHori );
1715 }
1716
1717 // We switch to left-adjusted for automatic width
1718 // We adjust the right border for Border attributes
1719 if( !bBalance && nNewRight < nOldRight )
1720 {
1721 if( aHori.GetHoriOrient() == text::HoriOrientation::FULL )
1722 {
1723 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
1724 pFormat->SetFormatAttr( aHori );
1725 }
1726 }
1727
1729}
1730
1731/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
@ NONE
no RedlineFlags
SvxBoxItemLine
const FndLines_t & GetLines() const
Definition: tblsel.hxx:173
const SwTableBox * GetBox() const
Definition: tblsel.hxx:175
const FndBoxes_t & GetBoxes() const
Definition: tblsel.hxx:203
virtual bool DeleteAndJoin(SwPaM &, SwDeleteFlags flags=SwDeleteFlags::Default)=0
complete delete of a given PaM
virtual bool InsertString(const SwPaM &rRg, const OUString &, const SwInsertFlags nInsertMode=SwInsertFlags::EMPTYEXPAND)=0
Insert string into existing text node at position rRg.Point().
virtual const SwRootFrame * GetCurrentLayout() const =0
virtual void SetRedlineFlags_intern(RedlineFlags eMode)=0
Set a new redline mode.
virtual RedlineFlags GetRedlineFlags() const =0
Query the currently set redline mode.
virtual void SetModified()=0
Must be called manually at changes of format.
virtual void AppendUndo(std::unique_ptr< SwUndo > pUndo)=0
Add new Undo action.
bool GetValue() const
const T * GetItemIfSet(TypedWhichId< T > nWhich, bool bSrchInParent=true) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
virtual SfxPoolItem * Clone(SfxItemPool *pPool=nullptr) const=0
static const sal_Int16 VeryThin
bool IsValid(SvxBoxInfoItemValidFlags nValid) const
const editeng::SvxBorderLine * GetHori() const
const editeng::SvxBorderLine * GetVert() const
void SetValid(SvxBoxInfoItemValidFlags nValid, bool bValid=true)
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxInfoItemLine nLine)
const editeng::SvxBorderLine * GetTop() const
virtual SvxBoxItem * Clone(SfxItemPool *pPool=nullptr) const override
const editeng::SvxBorderLine * GetRight() const
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)
const editeng::SvxBorderLine * GetLeft() const
sal_Int16 GetDistance(SvxBoxItemLine nLine, bool bAllowNegative=false) const
void SetDistance(sal_Int16 nNew, SvxBoxItemLine nLine)
const editeng::SvxBorderLine * GetBottom() const
void SetAllDistances(sal_Int16 nNew)
virtual SvxFrameDirectionItem * Clone(SfxItemPool *pPool=nullptr) const override
tools::Long GetHeight() const
void SetHeight(tools::Long n)
SwCellFrame is one table cell in the document layout.
Definition: cellfrm.hxx:31
SwContentFrame is the layout for content nodes: a common base class for text (paragraph) and non-text...
Definition: cntfrm.hxx:58
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1204
void SetRowNotTracked(const SwCursor &rCursor, const SvxPrintItem &rNotTracked, bool bAll=false)
rNotTracked = false means that the row was deleted or inserted with its tracked cell content bAll: de...
Definition: ndtbl1.cxx:565
void SetRowHeight(const SwCursor &rCursor, const SwFormatFrameSize &rNew)
Definition: ndtbl1.cxx:388
void SetTabLineStyle(const SwCursor &rCursor, const Color *pColor, bool bSetLine, const editeng::SvxBorderLine *pBorderLine)
Definition: ndtbl1.cxx:931
static sal_uInt16 GetBoxAlign(const SwCursor &rCursor)
Definition: ndtbl1.cxx:1362
void SetRowSplit(const SwCursor &rCursor, const SwFormatRowSplit &rNew)
Definition: ndtbl1.cxx:323
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:394
bool BalanceRowHeight(const SwCursor &rCursor, bool bTstOnly, const bool bOptimize)
Adjustment of Rowheights.
Definition: ndtbl1.cxx:435
static bool GetRowBackground(const SwCursor &rCursor, std::unique_ptr< SvxBrushItem > &rToFill)
Definition: ndtbl1.cxx:514
static bool GetBoxAttr(const SwCursor &rCursor, std::unique_ptr< SfxPoolItem > &rToFill)
Retrieves a box attribute from the given cursor.
Definition: ndtbl1.cxx:1288
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
static std::unique_ptr< SwFormatFrameSize > GetRowHeight(const SwCursor &rCursor)
Definition: ndtbl1.cxx:413
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
static std::unique_ptr< SwFormatRowSplit > GetRowSplit(const SwCursor &rCursor)
Definition: ndtbl1.cxx:349
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:405
void SetTabCols(const SwTabCols &rNew, bool bCurRowOnly, const SwCellFrame *pBoxFrame)
Definition: ndtbl.cxx:2717
static void GetTabCols(SwTabCols &rFill, const SwCellFrame *pBoxFrame)
Definition: ndtbl.cxx:2528
void SetTabBorders(const SwCursor &rCursor, const SfxItemSet &rSet)
Definition: ndtbl1.cxx:647
void SetBoxAlign(const SwCursor &rCursor, sal_uInt16 nAlign)
Definition: ndtbl1.cxx:1353
void AdjustCellWidth(const SwCursor &rCursor, const bool bBalance, const bool bNoShrink)
Adjusts selected cell widths in such a way, that their content does not need to be wrapped (if possib...
Definition: ndtbl1.cxx:1573
static bool HasRowNotTracked(const SwCursor &rCursor)
don't call SetRowNotTracked() for rows with tracked row change
Definition: ndtbl1.cxx:543
void SetBoxAttr(const SwCursor &rCursor, const SfxPoolItem &rNew)
Definition: ndtbl1.cxx:1243
void SetRowBackground(const SwCursor &rCursor, const SvxBrushItem &rNew)
Definition: ndtbl1.cxx:488
static void GetTabBorders(const SwCursor &rCursor, SfxItemSet &rSet)
Definition: ndtbl1.cxx:1022
bool IsFollow() const
Definition: flowfrm.hxx:166
void SetHoriOrient(sal_Int16 eNew)
Definition: fmtornt.hxx:89
sal_Int16 GetHoriOrient() const
Definition: fmtornt.hxx:87
virtual SwFormatVertOrient * Clone(SfxItemPool *pPool=nullptr) const override
Definition: atrfrm.cxx:1385
sal_Int16 GetVertOrient() const
Definition: fmtornt.hxx:54
const SvxBoxItem & GetBox(bool=true) const
Definition: frmatr.hxx:84
const SwFormatHoriOrient & GetHoriOrient(bool=true) const
Definition: fmtornt.hxx:108
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:448
const SwRect & getFrameArea() const
Definition: frame.hxx:179
const SwRect & getFramePrintArea() const
Definition: frame.hxx:180
Style of a layout element.
Definition: frmfmt.hxx:61
Base class of the Writer layout elements.
Definition: frame.hxx:315
bool IsCellFrame() const
Definition: frame.hxx:1226
bool IsTextFrame() const
Definition: frame.hxx:1234
SwTabFrame * FindTabFrame()
Definition: frame.hxx:1099
SwFrame * GetNext()
Definition: frame.hxx:676
SwTabFrame * ImplFindTabFrame()
Definition: findfrm.cxx:523
bool IsRightToLeft() const
Definition: frame.hxx:987
SwLayoutFrame * GetUpper()
Definition: frame.hxx:678
const SwLayoutFrame * GetNextLayoutLeaf() const
Definition: frame.hxx:1020
bool IsVertical() const
Definition: frame.hxx:973
sal_uInt16 GetBrowseWidthByTabFrame(const SwTabFrame &rTabFrame) const
Calculates available width by table-frame.
Definition: htmltbl.cxx:342
bool Resize(sal_uInt16 nAbsAvail, bool bRecalc=false, bool bForce=false, sal_uLong nDelay=0)
Recalculation of table widths for available width that has been passed.
Definition: htmltbl.cxx:1695
void BordersChanged(sal_uInt16 nAbsAvail)
Definition: htmltbl.cxx:1765
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:206
TElementType * Next()
Definition: calbck.hxx:364
TElementType * First()
Definition: calbck.hxx:356
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
const SwFrame * Lower() const
Definition: layfrm.hxx:101
Marks a node in the document model.
Definition: ndindex.hxx:31
SwNode & GetNode() const
Definition: ndindex.hxx:128
Base class of the Writer document model elements.
Definition: node.hxx:83
SwNodeOffset GetIndex() const
Definition: node.hxx:292
const SwStartNode * FindTableBoxStartNode() const
Definition: node.hxx:198
SwDoc & GetDoc()
Definition: node.hxx:213
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:358
SwContentNode * GetContentNode()
Definition: node.hxx:627
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:138
const SwPosition * GetMark() const
Definition: pam.hxx:210
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:230
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:477
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:224
SwPaM * GetNext()
Definition: pam.hxx:265
const SwPosition * GetPoint() const
Definition: pam.hxx:208
tools::Long GetWidth(const SwRect &rRect) const
Definition: frame.hxx:1380
tools::Long GetLeft(const SwRect &rRect) const
Definition: frame.hxx:1378
tools::Long GetRight(const SwRect &rRect) const
Definition: frame.hxx:1379
Of course Writer needs its own rectangles.
Definition: swrect.hxx:35
void Height(tools::Long nNew)
Definition: swrect.hxx:193
void Top(const tools::Long nTop)
Definition: swrect.hxx:206
void Right(const tools::Long nRight)
Definition: swrect.hxx:202
void Bottom(const tools::Long nBottom)
Definition: swrect.hxx:211
bool Overlaps(const SwRect &rRect) const
Definition: swrect.hxx:374
void Left(const tools::Long nLeft)
Definition: swrect.hxx:197
void Width(tools::Long nNew)
Definition: swrect.hxx:189
const SwRect & GetUnion() const
Definition: tblsel.hxx:130
const SwTabFrame * GetTable() const
Definition: tblsel.hxx:132
const Point & GetPtPos() const
Definition: viscrs.hxx:153
const Point & GetMkPos() const
Definition: viscrs.hxx:155
size_t Count() const
Definition: tabcol.hxx:65
tools::Long GetLeft() const
Definition: tabcol.hxx:78
tools::Long GetLeftMin() const
Definition: tabcol.hxx:77
tools::Long GetRight() const
Definition: tabcol.hxx:79
SwTabFrame is one table in the document layout, containing rows (which contain cells).
Definition: tabfrm.hxx:47
SwFrame * FindLastContentOrTable()
Definition: tabfrm.cxx:3534
bool IsInHeadline(const SwFrame &rFrame) const
Definition: tabfrm.cxx:5771
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:419
SwTableLine * GetUpper()
Definition: swtable.hxx:453
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:457
SwTableLines & GetTabLines()
Definition: swtable.hxx:450
void SetDirectFormatting(bool bDirect)
Set that this table box contains formatting that is not set by the table style.
Definition: swtable.hxx:461
void ChgFrameFormat(SwTableBoxFormat *pNewFormat, bool bNeedToReregister=true)
Definition: swtable.cxx:1939
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1903
SwTableLine is one table row in the document model.
Definition: swtable.hxx:358
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:380
void ChgFrameFormat(SwTableLineFormat *pNewFormat)
Definition: swtable.cxx:1516
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1483
SwTableBoxes & GetTabBoxes()
Definition: swtable.hxx:368
SwTableBox * GetUpper()
Definition: swtable.hxx:376
size_type size() const
Definition: swtable.hxx:76
iterator end()
Definition: swtable.hxx:79
iterator insert(iterator aIt, SwTableLine *pLine)
Definition: swtable.hxx:86
iterator begin()
Definition: swtable.hxx:77
bool empty() const
Definition: swtable.hxx:75
const SwTable & GetTable() const
Definition: node.hxx:506
SwTable is one table in the document model, containing rows (which contain cells).
Definition: swtable.hxx:113
SwTableLines & GetTabLines()
Definition: swtable.hxx:201
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:204
SwHTMLTableLayout * GetHTMLTableLayout()
Definition: swtable.hxx:177
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:163
SwTwips CalcFitToContent()
Simulates a formatting as if there were not right margin or Flys or other obstacles and returns the w...
Definition: txtfrm.cxx:3417
bool empty() const
size_type size() const
std::pair< const_iterator, bool > insert(Value &&x)
void ClearFEShellTabCols(SwDoc &rDoc, SwTabFrame const *const pFrame)
Definition: fetab.cxx:2162
@ Minimum
Value in Var-direction gives minimum (can be exceeded but not be less).
constexpr TypedWhichId< SvxFrameDirectionItem > RES_FRAMEDIR(120)
constexpr TypedWhichId< SvxPrintItem > RES_PRINT(98)
constexpr TypedWhichId< SwFormatVertOrient > RES_VERT_ORIENT(102)
constexpr TypedWhichId< SvxBoxItem > RES_BOX(106)
constexpr TypedWhichId< SvxBrushItem > RES_BACKGROUND(105)
#define CH_TXT_TRACKED_DUMMY_CHAR
Definition: hintids.hxx:190
const SfxPoolItem * GetDfltAttr(sal_uInt16 nWhich)
Get the default attribute from corresponding default attribute table.
Definition: hints.cxx:156
int i
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
long Long
static void lcl_GetStartEndCell(const SwCursor &rCursor, SwLayoutFrame *&prStart, SwLayoutFrame *&prEnd)
Definition: ndtbl1.cxx:117
static bool lcl_GetBoxSel(const SwCursor &rCursor, SwSelBoxes &rBoxes, bool bAllCursor=false)
Definition: ndtbl1.cxx:144
static bool FindBox_(FndBox_ &rBox, LinesAndTable *pPara)
Definition: ndtbl1.cxx:203
static void InsertLine(std::vector< SwTableLine * > &rLineArr, SwTableLine *pLine)
Definition: ndtbl1.cxx:168
#define COLFUZZY
Definition: ndtbl1.cxx:60
static void lcl_CalcColValues(std::vector< sal_uInt16 > &rToFill, const SwTabCols &rCols, const SwLayoutFrame *pStart, const SwLayoutFrame *pEnd, bool bWishValues)
Retrieves new values to set the TabCols.
Definition: ndtbl1.cxx:1488
static bool IsSame(tools::Long nA, tools::Long nB)
Definition: ndtbl1.cxx:62
static void lcl_CollectCells(std::vector< SwCellFrame * > &rArr, const SwRect &rUnion, SwTabFrame *pTab)
Definition: ndtbl1.cxx:624
static sal_uInt16 lcl_CalcCellFit(const SwLayoutFrame *pCell)
Definition: ndtbl1.cxx:1385
static bool lcl_IsAnLower(const SwTableLine *pLine, const SwTableLine *pAssumed)
Definition: ndtbl1.cxx:174
static void lcl_SetLineStyle(SvxBorderLine *pToSet, const Color *pColor, const SvxBorderLine *pBorderLine)
Definition: ndtbl1.cxx:913
static bool FindLine_(FndLine_ &rLine, LinesAndTable *pPara)
Definition: ndtbl1.cxx:234
static void lcl_CollectLines(std::vector< SwTableLine * > &rArr, const SwCursor &rCursor, bool bRemoveLines)
Definition: ndtbl1.cxx:243
static void InsertCell(std::vector< SwCellFrame * > &rCellArr, SwCellFrame *pCellFrame)
Definition: ndtbl1.cxx:618
static void lcl_ProcessBoxSize(std::vector< std::unique_ptr< SwTableFormatCmp > > &rFormatCmp, SwTableBox *pBox, const SwFormatFrameSize &rNew)
Definition: ndtbl1.cxx:310
static void lcl_ProcessRowAttr(std::vector< std::unique_ptr< SwTableFormatCmp > > &rFormatCmp, SwTableLine *pLine, const SfxPoolItem &rNew)
Definition: ndtbl1.cxx:283
static void lcl_CalcSubColValues(std::vector< sal_uInt16 > &rToFill, const SwTabCols &rCols, const SwLayoutFrame *pCell, const SwLayoutFrame *pTab, bool bWishValues)
Definition: ndtbl1.cxx:1426
static void lcl_ProcessRowSize(std::vector< std::unique_ptr< SwTableFormatCmp > > &rFormatCmp, SwTableLine *pLine, const SwFormatFrameSize &rNew)
Definition: ndtbl1.cxx:301
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
Definition: nodeoffset.hxx:35
SwNodeOffset abs(const SwNodeOffset &a)
Definition: nodeoffset.hxx:34
QPRO_FUNC_TYPE nType
static SfxItemSet & rSet
SwNodeIndex nNode
Definition: pam.hxx:38
SwIndex nContent
Definition: pam.hxx:39
std::vector< SwTableBox * > SwTableBoxes
Definition: swtable.hxx:105
#define MINLAY
Definition: swtypes.hxx:62
tools::Long SwTwips
Definition: swtypes.hxx:51
ITableControl & m_rTable
void ForEach_FndLineCopyCol(SwTableLines &rLines, FndPara *pFndPara)
This creates a structure mirroring the SwTable structure that contains all rows and non-leaf boxes (a...
Definition: tblsel.cxx:2101
void GetTableSelCrs(const SwCursorShell &rShell, SwSelBoxes &rBoxes)
Definition: tblsel.cxx:124
void MakeSelUnions(SwSelUnions &rUnions, const SwLayoutFrame *pStart, const SwLayoutFrame *pEnd, const SwTableSearchType eSearchType)
Definition: tblsel.cxx:1768
bool IsFrameInTableSel(const SwRect &rUnion, const SwFrame *pCell)
Definition: tblsel.cxx:670
std::vector< SwSelUnion > SwSelUnions
Definition: tblsel.hxx:138