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