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