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