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