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