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