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