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  if (bOptimize)
453  nHeight = 0;
454  SwIterator<SwFrame,SwFormat> aIter( *pLn->GetFrameFormat() );
455  SwFrame* pFrame = aIter.First();
456  while ( pFrame )
457  {
458  nHeight = std::max( nHeight, pFrame->getFrameArea().Height() );
459  pFrame = aIter.Next();
460  }
461  nTotalHeight += nHeight;
462  }
463 
464  if ( bOptimize )
465  nHeight = nTotalHeight / aRowArr.size();
466 
467  SwFormatFrameSize aNew( SwFrameSize::Minimum, 0, nHeight );
468 
469  if (GetIDocumentUndoRedo().DoesUndo())
470  {
472  std::make_unique<SwUndoAttrTable>(*pTableNd));
473  }
474 
475  std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
476  aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
477  for( auto pLn : aRowArr )
478  ::lcl_ProcessRowSize( aFormatCmp, pLn, aNew );
479 
481  }
482  bRet = true;
483  }
484  }
485  return bRet;
486 }
487 
488 void SwDoc::SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew )
489 {
490  SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
491  if( !pTableNd )
492  return;
493 
494  std::vector<SwTableLine*> aRowArr; // For Lines collecting
495  ::lcl_CollectLines( aRowArr, rCursor, true );
496 
497  if( aRowArr.empty() )
498  return;
499 
501  {
502  GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
503  }
504 
505  std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
506  aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
507 
508  for( auto pLn : aRowArr )
509  ::lcl_ProcessRowAttr( aFormatCmp, pLn, rNew );
510 
512 }
513 
514 bool SwDoc::GetRowBackground( const SwCursor& rCursor, std::unique_ptr<SvxBrushItem>& rToFill )
515 {
516  bool bRet = false;
517  SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
518  if( pTableNd )
519  {
520  std::vector<SwTableLine*> aRowArr; // For Lines collecting
521  ::lcl_CollectLines( aRowArr, rCursor, true );
522 
523  if( !aRowArr.empty() )
524  {
525  rToFill = aRowArr[0]->GetFrameFormat()->makeBackgroundBrushItem();
526 
527  bRet = true;
528  for ( std::vector<SwTableLine*>::size_type i = 1; i < aRowArr.size(); ++i )
529  {
530  std::unique_ptr<SvxBrushItem> aAlternative(aRowArr[i]->GetFrameFormat()->makeBackgroundBrushItem());
531 
532  if ( rToFill && aAlternative && *rToFill != *aAlternative )
533  {
534  bRet = false;
535  break;
536  }
537  }
538  }
539  }
540  return bRet;
541 }
542 
543 void SwDoc::SetRowNotTracked( const SwCursor& rCursor, const SvxPrintItem &rNew, bool bAll )
544 {
545  SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
546  if( !pTableNd )
547  return;
548 
549  std::vector<SwTableLine*> aRowArr; // For Lines collecting
550  if ( bAll )
551  {
552  const SwTableLines &rLines = pTableNd->GetTable().GetTabLines();
553  aRowArr.insert(aRowArr.end(), rLines.begin(), rLines.end());
554  }
555  else
556  ::lcl_CollectLines( aRowArr, rCursor, true );
557 
558  if( aRowArr.empty() )
559  return;
560 
562  {
563  GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
564  }
565 
566  std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
567  aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
568 
569  for( auto pLn : aRowArr )
570  {
571  ::lcl_ProcessRowAttr( aFormatCmp, pLn, rNew );
572  // as a workaround for the rows without text content,
573  // add a redline with invisible text CH_TXT_TRACKED_DUMMY_CHAR
574  // (unless the table is part of a bigger deletion, where the
575  // new redline can cause a problem)
576  if ( !bAll &&
577  // HasTextChangesOnly == false, i.e. a tracked row insertion or deletion
578  !rNew.GetValue() && pLn->IsEmpty() )
579  {
580  SwNodeIndex aInsPos( *(pLn->GetTabBoxes()[0]->GetSttNd()), 1 );
583  SwPaM aPaM(aInsPos);
585  OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
586  aPaM.SetMark();
587  aPaM.GetMark()->nContent.Assign(aPaM.GetContentNode(), 0);
590  }
591  }
592 
594 }
595 
596 static void InsertCell( std::vector<SwCellFrame*>& rCellArr, SwCellFrame* pCellFrame )
597 {
598  if( rCellArr.end() == std::find( rCellArr.begin(), rCellArr.end(), pCellFrame ) )
599  rCellArr.push_back( pCellFrame );
600 }
601 
602 static void lcl_CollectCells( std::vector<SwCellFrame*> &rArr, const SwRect &rUnion,
603  SwTabFrame *pTab )
604 {
605  SwLayoutFrame *pCell = pTab->FirstCell();
606  do
607  {
608  // If the Cell contains a CellFrame, we need to use it
609  // in order to get to the Cell
610  while ( !pCell->IsCellFrame() )
611  pCell = pCell->GetUpper();
612  OSL_ENSURE( pCell, "Frame is not a Cell" );
613  if ( rUnion.Overlaps( pCell->getFrameArea() ) )
614  ::InsertCell( rArr, static_cast<SwCellFrame*>(pCell) );
615 
616  // Make sure the Cell is left (Areas)
617  SwLayoutFrame *pTmp = pCell;
618  do
619  { pTmp = pTmp->GetNextLayoutLeaf();
620  } while ( pCell->IsAnLower( pTmp ) );
621  pCell = pTmp;
622  } while( pCell && pTab->IsAnLower( pCell ) );
623 }
624 
625 void SwDoc::SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet )
626 {
627  SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
628  SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
629  if( !pTableNd )
630  return ;
631 
632  SwLayoutFrame *pStart, *pEnd;
633  ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
634 
635  SwSelUnions aUnions;
636  ::MakeSelUnions( aUnions, pStart, pEnd );
637 
638  if( aUnions.empty() )
639  return;
640 
641  SwTable& rTable = pTableNd->GetTable();
642  if (GetIDocumentUndoRedo().DoesUndo())
643  {
644  GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoAttrTable>(*pTableNd) );
645  }
646 
647  std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
648  aFormatCmp.reserve( 255 );
649  const SvxBoxItem* pSetBox;
650  const SvxBoxInfoItem *pSetBoxInfo;
651 
652  const SvxBorderLine* pLeft = nullptr;
653  const SvxBorderLine* pRight = nullptr;
654  const SvxBorderLine* pTop = nullptr;
655  const SvxBorderLine* pBottom = nullptr;
656  const SvxBorderLine* pHori = nullptr;
657  const SvxBorderLine* pVert = nullptr;
658  bool bHoriValid = true, bVertValid = true,
659  bTopValid = true, bBottomValid = true,
660  bLeftValid = true, bRightValid = true;
661 
662  // The Flags in the BoxInfo Item decide whether a BorderLine is valid!
663  if( SfxItemState::SET == rSet.GetItemState( SID_ATTR_BORDER_INNER, false,
664  reinterpret_cast<const SfxPoolItem**>(&pSetBoxInfo)) )
665  {
666  pHori = pSetBoxInfo->GetHori();
667  pVert = pSetBoxInfo->GetVert();
668 
669  bHoriValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::HORI);
670  bVertValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::VERT);
671 
672  // Do we want to evaluate these?
673  bTopValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::TOP);
674  bBottomValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
675  bLeftValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::LEFT);
676  bRightValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::RIGHT);
677  }
678 
679  if( SfxItemState::SET == rSet.GetItemState( RES_BOX, false,
680  reinterpret_cast<const SfxPoolItem**>(&pSetBox)) )
681  {
682  pLeft = pSetBox->GetLeft();
683  pRight = pSetBox->GetRight();
684  pTop = pSetBox->GetTop();
685  pBottom = pSetBox->GetBottom();
686  }
687  else
688  {
689  // Not set, thus not valid values
690  bTopValid = bBottomValid = bLeftValid = bRightValid = false;
691  pSetBox = nullptr;
692  }
693 
694  bool bFirst = true;
695  for ( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
696  {
697  SwSelUnion *pUnion = &aUnions[i];
698  SwTabFrame *pTab = pUnion->GetTable();
699  const SwRect &rUnion = pUnion->GetUnion();
700  const bool bLast = (i == aUnions.size() - 1);
701 
702  std::vector<SwCellFrame*> aCellArr;
703  aCellArr.reserve( 255 );
704  ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
705 
706  // All Cell Borders that match the UnionRect or extend it are
707  // Outer Borders. All others are Inner Borders.
708 
709  // New: The Outer Borders can, depending on whether it's a
710  // Start/Middle/Follow Table (for Selection via FollowTabs),
711  // also not be Outer Borders.
712  // Outer Borders are set on the left, right, at the top and at the bottom.
713  // Inner Borders are only set at the top and on the left.
714  for ( auto pCell : aCellArr )
715  {
716  const bool bVert = pTab->IsVertical();
717  const bool bRTL = pTab->IsRightToLeft();
718  bool bTopOver, bLeftOver, bRightOver, bBottomOver;
719  if ( bVert )
720  {
721  bTopOver = pCell->getFrameArea().Right() >= rUnion.Right();
722  bLeftOver = pCell->getFrameArea().Top() <= rUnion.Top();
723  bRightOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
724  bBottomOver = pCell->getFrameArea().Left() <= rUnion.Left();
725  }
726  else
727  {
728  bTopOver = pCell->getFrameArea().Top() <= rUnion.Top();
729  bLeftOver = pCell->getFrameArea().Left() <= rUnion.Left();
730  bRightOver = pCell->getFrameArea().Right() >= rUnion.Right();
731  bBottomOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
732  }
733 
734  if ( bRTL )
735  {
736  bool bTmp = bRightOver;
737  bRightOver = bLeftOver;
738  bLeftOver = bTmp;
739  }
740 
741  // Do not set anything by default in HeadlineRepeats
742  if ( pTab->IsFollow() &&
743  ( pTab->IsInHeadline( *pCell ) ||
744  // Same holds for follow flow rows
745  pCell->IsInFollowFlowRow() ) )
746  continue;
747 
748  SvxBoxItem aBox( pCell->GetFormat()->GetBox() );
749 
750  sal_Int16 nType = 0;
751 
752  // Top Border
753  if( bTopValid )
754  {
755  if ( bFirst && bTopOver )
756  {
757  aBox.SetLine( pTop, SvxBoxItemLine::TOP );
758  nType |= 0x0001;
759  }
760  else if ( bHoriValid )
761  {
762  aBox.SetLine( nullptr, SvxBoxItemLine::TOP );
763  nType |= 0x0002;
764  }
765  }
766 
767  // Fix fdo#62470 correct the input for RTL table
768  if (bRTL)
769  {
770  if( bLeftOver && bRightOver)
771  {
772  if ( bLeftValid )
773  {
774  aBox.SetLine( pLeft, SvxBoxItemLine::RIGHT );
775  nType |= 0x0010;
776  }
777  if ( bRightValid )
778  {
779  aBox.SetLine( pRight, SvxBoxItemLine::LEFT );
780  nType |= 0x0004;
781  }
782  }
783  else
784  {
785  if ( bLeftValid )
786  {
787  aBox.SetLine( bRightOver ? pLeft : nullptr, SvxBoxItemLine::RIGHT );
788  if (bVertValid)
789  nType |= 0x0020;
790  else
791  nType |= 0x0010;
792  }
793  if ( bLeftOver )
794  {
795  if ( bRightValid )
796  {
797  aBox.SetLine( pRight, SvxBoxItemLine::LEFT );
798  nType |= 0x0004;
799  }
800  }
801  else if ( bVertValid )
802  {
803  aBox.SetLine( pVert, SvxBoxItemLine::LEFT );
804  nType |= 0x0008;
805  }
806  }
807  }
808  else
809  {
810  // Left Border
811  if ( bLeftOver )
812  {
813  if( bLeftValid )
814  {
815  aBox.SetLine( pLeft, SvxBoxItemLine::LEFT );
816  nType |= 0x0004;
817  }
818  }
819  else if( bVertValid )
820  {
821  aBox.SetLine( pVert, SvxBoxItemLine::LEFT );
822  nType |= 0x0008;
823  }
824 
825  // Right Border
826  if( bRightValid )
827  {
828  if ( bRightOver )
829  {
830  aBox.SetLine( pRight, SvxBoxItemLine::RIGHT );
831  nType |= 0x0010;
832  }
833  else if ( bVertValid )
834  {
835  aBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
836  nType |= 0x0020;
837  }
838  }
839  }
840 
841  // Bottom Border
842  if ( bLast && bBottomOver )
843  {
844  if( bBottomValid )
845  {
846  aBox.SetLine( pBottom, SvxBoxItemLine::BOTTOM );
847  nType |= 0x0040;
848  }
849  }
850  else if( bHoriValid )
851  {
852  aBox.SetLine( pHori, SvxBoxItemLine::BOTTOM );
853  nType |= 0x0080;
854  }
855 
856  if( pSetBox )
857  {
859  aBox.SetDistance( pSetBox->GetDistance( k ), k );
860  }
861 
862  SwTableBox *pBox = const_cast<SwTableBox*>(pCell->GetTabBox());
863  SwFrameFormat *pNewFormat = SwTableFormatCmp::FindNewFormat( aFormatCmp, pBox->GetFrameFormat(), nType );
864  if ( nullptr != pNewFormat )
865  pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(pNewFormat) );
866  else
867  {
868  SwFrameFormat *pOld = pBox->GetFrameFormat();
869  SwFrameFormat *pNew = pBox->ClaimFrameFormat();
870  pNew->SetFormatAttr( aBox );
871  aFormatCmp.push_back(std::make_unique<SwTableFormatCmp>(pOld, pNew, nType));
872  }
873  }
874 
875  bFirst = false;
876  }
877 
878  SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
879  if( pTableLayout )
880  {
882  SwTabFrame* pTabFrame = pFrame->ImplFindTabFrame();
883 
884  pTableLayout->BordersChanged(
885  pTableLayout->GetBrowseWidthByTabFrame( *pTabFrame ) );
886  }
887  ::ClearFEShellTabCols(*this, nullptr);
889 }
890 
891 static void lcl_SetLineStyle( SvxBorderLine *pToSet,
892  const Color *pColor, const SvxBorderLine *pBorderLine)
893 {
894  if ( pBorderLine )
895  {
896  if ( !pColor )
897  {
898  Color aTmp( pToSet->GetColor() );
899  *pToSet = *pBorderLine;
900  pToSet->SetColor( aTmp );
901  }
902  else
903  *pToSet = *pBorderLine;
904  }
905  if ( pColor )
906  pToSet->SetColor( *pColor );
907 }
908 
909 void SwDoc::SetTabLineStyle( const SwCursor& rCursor,
910  const Color* pColor, bool bSetLine,
911  const SvxBorderLine* pBorderLine )
912 {
913  SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
914  SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
915  if( !pTableNd )
916  return ;
917 
918  SwLayoutFrame *pStart, *pEnd;
919  ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
920 
921  SwSelUnions aUnions;
922  ::MakeSelUnions( aUnions, pStart, pEnd );
923 
924  if( aUnions.empty() )
925  return;
926 
927  SwTable& rTable = pTableNd->GetTable();
928  if (GetIDocumentUndoRedo().DoesUndo())
929  {
930  GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
931  }
932 
933  const SvxBorderLine aDefaultBorder(pColor, SvxBorderLineWidth::VeryThin);
934 
935  for( auto &rU : aUnions )
936  {
937  SwSelUnion *pUnion = &rU;
938  SwTabFrame *pTab = pUnion->GetTable();
939  std::vector<SwCellFrame*> aCellArr;
940  aCellArr.reserve( 255 );
941  ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
942 
943  for ( auto pCell : aCellArr )
944  {
945  // Do not set anything by default in HeadlineRepeats
946  if ( pTab->IsFollow() && pTab->IsInHeadline( *pCell ) )
947  continue;
948 
949  const_cast<SwTableBox*>(pCell->GetTabBox())->ClaimFrameFormat();
950  SwFrameFormat *pFormat = pCell->GetFormat();
951  std::unique_ptr<SvxBoxItem> aBox(pFormat->GetBox().Clone());
952 
953  SvxBorderLine* pTop = const_cast<SvxBorderLine*>(aBox->GetTop());
954  SvxBorderLine* pBot = const_cast<SvxBorderLine*>(aBox->GetBottom());
955  SvxBorderLine* pLeft = const_cast<SvxBorderLine*>(aBox->GetLeft());
956  SvxBorderLine* pRight = const_cast<SvxBorderLine*>(aBox->GetRight());
957 
958  if ( !pBorderLine && bSetLine )
959  {
960  aBox.reset(::GetDfltAttr(RES_BOX)->Clone());
961  }
962  else if (pColor && !pBorderLine && !pTop && !pBot && !pLeft && !pRight)
963  {
964  aBox->SetLine(&aDefaultBorder, SvxBoxItemLine::TOP);
965  aBox->SetLine(&aDefaultBorder, SvxBoxItemLine::BOTTOM);
966  aBox->SetLine(&aDefaultBorder, SvxBoxItemLine::LEFT);
967  aBox->SetLine(&aDefaultBorder, SvxBoxItemLine::RIGHT);
968  }
969  else
970  {
971  if (pTop)
972  ::lcl_SetLineStyle(pTop, pColor, pBorderLine);
973  if (pBot)
974  ::lcl_SetLineStyle(pBot, pColor, pBorderLine);
975  if (pLeft)
976  ::lcl_SetLineStyle(pLeft, pColor, pBorderLine);
977  if (pRight)
978  ::lcl_SetLineStyle(pRight, pColor, pBorderLine);
979  }
980  pFormat->SetFormatAttr( *aBox );
981  }
982  }
983 
984  SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
985  if( pTableLayout )
986  {
988  SwTabFrame* pTabFrame = pFrame->ImplFindTabFrame();
989 
990  pTableLayout->BordersChanged(
991  pTableLayout->GetBrowseWidthByTabFrame( *pTabFrame ) );
992  }
993  ::ClearFEShellTabCols(*this, nullptr);
995 }
996 
997 void SwDoc::GetTabBorders( const SwCursor& rCursor, SfxItemSet& rSet )
998 {
999  SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
1000  SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
1001  if( !pTableNd )
1002  return ;
1003 
1004  SwLayoutFrame *pStart, *pEnd;
1005  ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
1006 
1007  SwSelUnions aUnions;
1008  ::MakeSelUnions( aUnions, pStart, pEnd );
1009 
1010  if( aUnions.empty() )
1011  return;
1012 
1013  SvxBoxItem aSetBox ( rSet.Get(RES_BOX ) );
1014  SvxBoxInfoItem aSetBoxInfo( rSet.Get(SID_ATTR_BORDER_INNER) );
1015 
1016  bool bTopSet = false,
1017  bBottomSet = false,
1018  bLeftSet = false,
1019  bRightSet = false,
1020  bHoriSet = false,
1021  bVertSet = false,
1022  bDistanceSet = false,
1023  bRTLTab = false;
1024 
1025  aSetBoxInfo.ResetFlags();
1026 
1027  for ( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
1028  {
1029  SwSelUnion *pUnion = &aUnions[i];
1030  const SwTabFrame *pTab = pUnion->GetTable();
1031  const SwRect &rUnion = pUnion->GetUnion();
1032  const bool bFirst = i == 0;
1033  const bool bLast = (i == aUnions.size() - 1);
1034 
1035  std::vector<SwCellFrame*> aCellArr;
1036  aCellArr.reserve(255);
1037  ::lcl_CollectCells( aCellArr, rUnion, const_cast<SwTabFrame*>(pTab) );
1038 
1039  for ( auto pCell : aCellArr )
1040  {
1041  const bool bVert = pTab->IsVertical();
1042  const bool bRTL = bRTLTab = pTab->IsRightToLeft();
1043  bool bTopOver, bLeftOver, bRightOver, bBottomOver;
1044  if ( bVert )
1045  {
1046  bTopOver = pCell->getFrameArea().Right() >= rUnion.Right();
1047  bLeftOver = pCell->getFrameArea().Top() <= rUnion.Top();
1048  bRightOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
1049  bBottomOver = pCell->getFrameArea().Left() <= rUnion.Left();
1050  }
1051  else
1052  {
1053  bTopOver = pCell->getFrameArea().Top() <= rUnion.Top();
1054  bLeftOver = pCell->getFrameArea().Left() <= rUnion.Left();
1055  bRightOver = pCell->getFrameArea().Right() >= rUnion.Right();
1056  bBottomOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
1057  }
1058 
1059  if ( bRTL )
1060  {
1061  bool bTmp = bRightOver;
1062  bRightOver = bLeftOver;
1063  bLeftOver = bTmp;
1064  }
1065 
1066  const SwFrameFormat *pFormat = pCell->GetFormat();
1067  const SvxBoxItem &rBox = pFormat->GetBox();
1068 
1069  // Top Border
1070  if ( bFirst && bTopOver )
1071  {
1072  if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::TOP))
1073  {
1074  if ( !bTopSet )
1075  { bTopSet = true;
1076  aSetBox.SetLine( rBox.GetTop(), SvxBoxItemLine::TOP );
1077  }
1078  else if ((aSetBox.GetTop() && rBox.GetTop() &&
1079  (*aSetBox.GetTop() != *rBox.GetTop())) ||
1080  ((!aSetBox.GetTop()) != (!rBox.GetTop()))) // != expression is true, if one and only one of the two pointers is !0
1081  {
1082  aSetBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, false );
1083  aSetBox.SetLine( nullptr, SvxBoxItemLine::TOP );
1084  }
1085  }
1086  }
1087 
1088  // Left Border
1089  if ( bLeftOver )
1090  {
1091  if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::LEFT))
1092  {
1093  if ( !bLeftSet )
1094  { bLeftSet = true;
1095  aSetBox.SetLine( rBox.GetLeft(), SvxBoxItemLine::LEFT );
1096  }
1097  else if ((aSetBox.GetLeft() && rBox.GetLeft() &&
1098  (*aSetBox.GetLeft() != *rBox.GetLeft())) ||
1099  ((!aSetBox.GetLeft()) != (!rBox.GetLeft())))
1100  {
1101  aSetBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, false );
1102  aSetBox.SetLine( nullptr, SvxBoxItemLine::LEFT );
1103  }
1104  }
1105  }
1106  else
1107  {
1108  if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::VERT))
1109  {
1110  if ( !bVertSet )
1111  { bVertSet = true;
1112  aSetBoxInfo.SetLine( rBox.GetLeft(), SvxBoxInfoItemLine::VERT );
1113  }
1114  else if ((aSetBoxInfo.GetVert() && rBox.GetLeft() &&
1115  (*aSetBoxInfo.GetVert() != *rBox.GetLeft())) ||
1116  ((!aSetBoxInfo.GetVert()) != (!rBox.GetLeft())))
1117  { aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::VERT, false );
1118  aSetBoxInfo.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
1119  }
1120  }
1121  }
1122 
1123  // Right Border
1124  if ( aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::RIGHT) && bRightOver )
1125  {
1126  if ( !bRightSet )
1127  { bRightSet = true;
1128  aSetBox.SetLine( rBox.GetRight(), SvxBoxItemLine::RIGHT );
1129  }
1130  else if ((aSetBox.GetRight() && rBox.GetRight() &&
1131  (*aSetBox.GetRight() != *rBox.GetRight())) ||
1132  (!aSetBox.GetRight() != !rBox.GetRight()))
1133  { aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::RIGHT, false );
1134  aSetBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
1135  }
1136  }
1137 
1138  // Bottom Border
1139  if ( bLast && bBottomOver )
1140  {
1141  if ( aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::BOTTOM) )
1142  {
1143  if ( !bBottomSet )
1144  { bBottomSet = true;
1145  aSetBox.SetLine( rBox.GetBottom(), SvxBoxItemLine::BOTTOM );
1146  }
1147  else if ((aSetBox.GetBottom() && rBox.GetBottom() &&
1148  (*aSetBox.GetBottom() != *rBox.GetBottom())) ||
1149  (!aSetBox.GetBottom() != !rBox.GetBottom()))
1150  { aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, false );
1151  aSetBox.SetLine( nullptr, SvxBoxItemLine::BOTTOM );
1152  }
1153  }
1154  }
1155  // In all Lines, except for the last one, the horizontal Line
1156  // is taken from the Bottom Line.
1157  else
1158  {
1159  if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::HORI))
1160  {
1161  if ( !bHoriSet )
1162  { bHoriSet = true;
1163  aSetBoxInfo.SetLine( rBox.GetBottom(), SvxBoxInfoItemLine::HORI );
1164  }
1165  else if ((aSetBoxInfo.GetHori() && rBox.GetBottom() &&
1166  (*aSetBoxInfo.GetHori() != *rBox.GetBottom())) ||
1167  ((!aSetBoxInfo.GetHori()) != (!rBox.GetBottom())))
1168  {
1169  aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::HORI, false );
1170  aSetBoxInfo.SetLine( nullptr, SvxBoxInfoItemLine::HORI );
1171  }
1172  }
1173  }
1174 
1175  // Distance to text
1176  if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::DISTANCE))
1177  {
1178  if( !bDistanceSet ) // Set on first iteration
1179  {
1180  bDistanceSet = true;
1182  aSetBox.SetDistance( rBox.GetDistance( k ), k );
1183  }
1184  else
1185  {
1187  if( aSetBox.GetDistance( k ) !=
1188  rBox.GetDistance( k ) )
1189  {
1190  aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::DISTANCE, false );
1191  aSetBox.SetAllDistances(0);
1192  break;
1193  }
1194  }
1195  }
1196  }
1197  }
1198 
1199  // fdo#62470 fix the reading for table format.
1200  if ( bRTLTab )
1201  {
1202  SvxBoxItem aTempBox ( rSet.Get(RES_BOX ) );
1203  SvxBoxInfoItem aTempBoxInfo( rSet.Get(SID_ATTR_BORDER_INNER) );
1204 
1205  aTempBox.SetLine( aSetBox.GetRight(), SvxBoxItemLine::RIGHT);
1206  aSetBox.SetLine( aSetBox.GetLeft(), SvxBoxItemLine::RIGHT);
1207  aSetBox.SetLine( aTempBox.GetRight(), SvxBoxItemLine::LEFT);
1208 
1209  aTempBoxInfo.SetValid( SvxBoxInfoItemValidFlags::LEFT, aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::LEFT) );
1210  aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::LEFT, aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::RIGHT) );
1211  aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::RIGHT, aTempBoxInfo.IsValid(SvxBoxInfoItemValidFlags::LEFT) );
1212  }
1213 
1214  rSet.Put( aSetBox );
1215  rSet.Put( aSetBoxInfo );
1216 }
1217 
1218 void SwDoc::SetBoxAttr( const SwCursor& rCursor, const SfxPoolItem &rNew )
1219 {
1220  SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1221  SwSelBoxes aBoxes;
1222  if( !(pTableNd && ::lcl_GetBoxSel( rCursor, aBoxes, true )) )
1223  return;
1224 
1225  SwTable& rTable = pTableNd->GetTable();
1226  if (GetIDocumentUndoRedo().DoesUndo())
1227  {
1228  GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoAttrTable>(*pTableNd) );
1229  }
1230 
1231  std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
1232  aFormatCmp.reserve(std::max<size_t>(255, aBoxes.size()));
1233  for (size_t i = 0; i < aBoxes.size(); ++i)
1234  {
1235  SwTableBox *pBox = aBoxes[i];
1236 
1237  SwFrameFormat *pNewFormat = SwTableFormatCmp::FindNewFormat( aFormatCmp, pBox->GetFrameFormat(), 0 );
1238  if ( nullptr != pNewFormat )
1239  pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(pNewFormat) );
1240  else
1241  {
1242  SwFrameFormat *pOld = pBox->GetFrameFormat();
1243  SwFrameFormat *pNew = pBox->ClaimFrameFormat();
1244  pNew->SetFormatAttr( rNew );
1245  aFormatCmp.push_back(std::make_unique<SwTableFormatCmp>(pOld, pNew, 0));
1246  }
1247 
1248  pBox->SetDirectFormatting(true);
1249  }
1250 
1251  SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
1252  if( pTableLayout )
1253  {
1255  SwTabFrame* pTabFrame = pFrame->ImplFindTabFrame();
1256 
1257  pTableLayout->Resize(
1258  pTableLayout->GetBrowseWidthByTabFrame( *pTabFrame ), true );
1259  }
1261 }
1262 
1263 bool SwDoc::GetBoxAttr( const SwCursor& rCursor, std::unique_ptr<SfxPoolItem>& rToFill )
1264 {
1265  // tdf#144843 calling GetBoxAttr *requires* object
1266  assert(rToFill && "requires object here");
1267  bool bRet = false;
1268  SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1269  SwSelBoxes aBoxes;
1270  if( pTableNd && lcl_GetBoxSel( rCursor, aBoxes ))
1271  {
1272  bRet = true;
1273  bool bOneFound = false;
1274  const sal_uInt16 nWhich = rToFill->Which();
1275  for (size_t i = 0; i < aBoxes.size(); ++i)
1276  {
1277  switch ( nWhich )
1278  {
1279  case RES_BACKGROUND:
1280  {
1281  std::unique_ptr<SvxBrushItem> xBack =
1282  aBoxes[i]->GetFrameFormat()->makeBackgroundBrushItem();
1283  if( !bOneFound )
1284  {
1285  rToFill = std::move(xBack);
1286  bOneFound = true;
1287  }
1288  else if( *rToFill != *xBack )
1289  bRet = false;
1290  }
1291  break;
1292 
1293  case RES_FRAMEDIR:
1294  {
1295  const SvxFrameDirectionItem& rDir =
1296  aBoxes[i]->GetFrameFormat()->GetFrameDir();
1297  if( !bOneFound )
1298  {
1299  rToFill.reset(rDir.Clone());
1300  bOneFound = true;
1301  }
1302  else if( rToFill && *rToFill != rDir )
1303  bRet = false;
1304  }
1305  break;
1306  case RES_VERT_ORIENT:
1307  {
1308  const SwFormatVertOrient& rOrient =
1309  aBoxes[i]->GetFrameFormat()->GetVertOrient();
1310  if( !bOneFound )
1311  {
1312  rToFill.reset(rOrient.Clone());
1313  bOneFound = true;
1314  }
1315  else if( rToFill && *rToFill != rOrient )
1316  bRet = false;
1317  }
1318  break;
1319  }
1320 
1321  if ( !bRet )
1322  break;
1323  }
1324  }
1325  return bRet;
1326 }
1327 
1328 void SwDoc::SetBoxAlign( const SwCursor& rCursor, sal_uInt16 nAlign )
1329 {
1330  OSL_ENSURE( nAlign == text::VertOrientation::NONE ||
1331  nAlign == text::VertOrientation::CENTER ||
1332  nAlign == text::VertOrientation::BOTTOM, "Wrong alignment" );
1333  SwFormatVertOrient aVertOri( 0, nAlign );
1334  SetBoxAttr( rCursor, aVertOri );
1335 }
1336 
1337 sal_uInt16 SwDoc::GetBoxAlign( const SwCursor& rCursor )
1338 {
1339  sal_uInt16 nAlign = USHRT_MAX;
1340  SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1341  SwSelBoxes aBoxes;
1342  if( pTableNd && ::lcl_GetBoxSel( rCursor, aBoxes ))
1343  {
1344  for (size_t i = 0; i < aBoxes.size(); ++i)
1345  {
1346  const SwFormatVertOrient &rOri =
1347  aBoxes[i]->GetFrameFormat()->GetVertOrient();
1348  if( USHRT_MAX == nAlign )
1349  nAlign = o3tl::narrowing<sal_uInt16>(rOri.GetVertOrient());
1350  else if( rOri.GetVertOrient() != nAlign )
1351  {
1352  nAlign = USHRT_MAX;
1353  break;
1354  }
1355  }
1356  }
1357  return nAlign;
1358 }
1359 
1360 static sal_uInt16 lcl_CalcCellFit( const SwLayoutFrame *pCell )
1361 {
1362  SwTwips nRet = 0;
1363  const SwFrame *pFrame = pCell->Lower(); // The whole Line
1364  SwRectFnSet aRectFnSet(pCell);
1365  while ( pFrame )
1366  {
1367  const SwTwips nAdd = aRectFnSet.GetWidth(pFrame->getFrameArea()) -
1368  aRectFnSet.GetWidth(pFrame->getFramePrintArea());
1369 
1370  // pFrame does not necessarily have to be a SwTextFrame!
1371  const SwTwips nCalcFitToContent = pFrame->IsTextFrame() ?
1372  const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pFrame))->CalcFitToContent() :
1373  aRectFnSet.GetWidth(pFrame->getFramePrintArea());
1374 
1375  nRet = std::max( nRet, nCalcFitToContent + nAdd );
1376  pFrame = pFrame->GetNext();
1377  }
1378  // Surrounding border as well as left and Right Border also need to be respected
1379  nRet += aRectFnSet.GetWidth(pCell->getFrameArea()) -
1380  aRectFnSet.GetWidth(pCell->getFramePrintArea());
1381 
1382  // To compensate for the accuracy of calculation later on in SwTable::SetTabCols
1383  // we keep adding up a little.
1384  nRet += COLFUZZY;
1385  return o3tl::narrowing<sal_uInt16>(std::max( SwTwips(MINLAY), nRet ));
1386 }
1387 
1388 /* The Line is within the Selection but not outlined by the TabCols.
1389  *
1390  * That means that the Line has been "split" by other Cells due to the
1391  * two-dimensional representation used. Thus, we have to distribute the cell's
1392  * default or minimum value amongst the Cell it has been split by.
1393  *
1394  * First, we collect the Columns (not the Column separators) which overlap
1395  * with the Cell. We then distribute the desired value according to the
1396  * amount of overlapping amongst the Cells.
1397  *
1398  * A Cell's default value stays the same if it already has a larger value than
1399  * the desired one. It's overwritten if it's smaller.
1400  */
1401 static void lcl_CalcSubColValues( std::vector<sal_uInt16> &rToFill, const SwTabCols &rCols,
1402  const SwLayoutFrame *pCell, const SwLayoutFrame *pTab,
1403  bool bWishValues )
1404 {
1405  const sal_uInt16 nWish = bWishValues ?
1406  ::lcl_CalcCellFit( pCell ) :
1407  MINLAY + sal_uInt16(pCell->getFrameArea().Width() - pCell->getFramePrintArea().Width());
1408 
1409  SwRectFnSet aRectFnSet(pTab);
1410 
1411  for ( size_t i = 0 ; i <= rCols.Count(); ++i )
1412  {
1413  tools::Long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1];
1414  tools::Long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1415  nColLeft += rCols.GetLeftMin();
1416  nColRight += rCols.GetLeftMin();
1417 
1418  // Adapt values to the proportions of the Table (Follows)
1419  if ( rCols.GetLeftMin() != aRectFnSet.GetLeft(pTab->getFrameArea()) )
1420  {
1421  const tools::Long nDiff = aRectFnSet.GetLeft(pTab->getFrameArea()) - rCols.GetLeftMin();
1422  nColLeft += nDiff;
1423  nColRight += nDiff;
1424  }
1425  const tools::Long nCellLeft = aRectFnSet.GetLeft(pCell->getFrameArea());
1426  const tools::Long nCellRight = aRectFnSet.GetRight(pCell->getFrameArea());
1427 
1428  // Calculate overlapping value
1429  tools::Long nWidth = 0;
1430  if ( nColLeft <= nCellLeft && nColRight >= (nCellLeft+COLFUZZY) )
1431  nWidth = nColRight - nCellLeft;
1432  else if ( nColLeft <= (nCellRight-COLFUZZY) && nColRight >= nCellRight )
1433  nWidth = nCellRight - nColLeft;
1434  else if ( nColLeft >= nCellLeft && nColRight <= nCellRight )
1435  nWidth = nColRight - nColLeft;
1436  if ( nWidth && pCell->getFrameArea().Width() )
1437  {
1438  tools::Long nTmp = nWidth * nWish / pCell->getFrameArea().Width();
1439  if ( o3tl::make_unsigned(nTmp) > rToFill[i] )
1440  rToFill[i] = sal_uInt16(nTmp);
1441  }
1442  }
1443 }
1444 
1463 static void lcl_CalcColValues( std::vector<sal_uInt16> &rToFill, const SwTabCols &rCols,
1464  const SwLayoutFrame *pStart, const SwLayoutFrame *pEnd,
1465  bool bWishValues )
1466 {
1467  SwSelUnions aUnions;
1468  ::MakeSelUnions( aUnions, pStart, pEnd,
1470 
1471  for ( auto &rU : aUnions )
1472  {
1473  SwSelUnion *pSelUnion = &rU;
1474  const SwTabFrame *pTab = pSelUnion->GetTable();
1475  const SwRect &rUnion = pSelUnion->GetUnion();
1476 
1477  SwRectFnSet aRectFnSet(pTab);
1478  bool bRTL = pTab->IsRightToLeft();
1479 
1480  const SwLayoutFrame *pCell = pTab->FirstCell();
1481  if (!pCell)
1482  continue;
1483  do
1484  {
1485  if ( pCell->IsCellFrame() && pCell->FindTabFrame() == pTab && ::IsFrameInTableSel( rUnion, pCell ) )
1486  {
1487  const tools::Long nCLeft = aRectFnSet.GetLeft(pCell->getFrameArea());
1488  const tools::Long nCRight = aRectFnSet.GetRight(pCell->getFrameArea());
1489 
1490  bool bNotInCols = true;
1491 
1492  for ( size_t i = 0; i <= rCols.Count(); ++i )
1493  {
1494  sal_uInt16 nFit = rToFill[i];
1495  tools::Long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1];
1496  tools::Long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1497 
1498  if ( bRTL )
1499  {
1500  tools::Long nTmpRight = nColRight;
1501  nColRight = rCols.GetRight() - nColLeft;
1502  nColLeft = rCols.GetRight() - nTmpRight;
1503  }
1504 
1505  nColLeft += rCols.GetLeftMin();
1506  nColRight += rCols.GetLeftMin();
1507 
1508  // Adapt values to the proportions of the Table (Follows)
1509  tools::Long nLeftA = nColLeft;
1510  tools::Long nRightA = nColRight;
1511  if ( rCols.GetLeftMin() != sal_uInt16(aRectFnSet.GetLeft(pTab->getFrameArea())) )
1512  {
1513  const tools::Long nDiff = aRectFnSet.GetLeft(pTab->getFrameArea()) - rCols.GetLeftMin();
1514  nLeftA += nDiff;
1515  nRightA += nDiff;
1516  }
1517 
1518  // We don't want to take a too close look
1519  if ( ::IsSame(nCLeft, nLeftA) && ::IsSame(nCRight, nRightA))
1520  {
1521  bNotInCols = false;
1522  if ( bWishValues )
1523  {
1524  const sal_uInt16 nWish = ::lcl_CalcCellFit( pCell );
1525  if ( nWish > nFit )
1526  nFit = nWish;
1527  }
1528  else
1529  { const sal_uInt16 nMin = MINLAY + sal_uInt16(pCell->getFrameArea().Width() -
1530  pCell->getFramePrintArea().Width());
1531  if ( !nFit || nMin < nFit )
1532  nFit = nMin;
1533  }
1534  if ( rToFill[i] < nFit )
1535  rToFill[i] = nFit;
1536  }
1537  }
1538  if ( bNotInCols )
1539  ::lcl_CalcSubColValues( rToFill, rCols, pCell, pTab, bWishValues );
1540  }
1541  do {
1542  pCell = pCell->GetNextLayoutLeaf();
1543  } while( pCell && pCell->getFrameArea().Width() == 0 );
1544  } while ( pCell && pTab->IsAnLower( pCell ) );
1545  }
1546 }
1547 
1548 void SwDoc::AdjustCellWidth( const SwCursor& rCursor,
1549  const bool bBalance,
1550  const bool bNoShrink )
1551 {
1552  // Check whether the current Cursor has it's Point/Mark in a Table
1553  SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
1554  SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
1555  if( !pTableNd )
1556  return ;
1557 
1558  SwLayoutFrame *pStart, *pEnd;
1559  ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
1560 
1561  // Collect TabCols; we reset the Table with them
1562  SwFrame* pBoxFrame = pStart;
1563  while( pBoxFrame && !pBoxFrame->IsCellFrame() )
1564  pBoxFrame = pBoxFrame->GetUpper();
1565 
1566  if ( !pBoxFrame )
1567  return; // Robust
1568 
1569  SwTabCols aTabCols;
1570  GetTabCols( aTabCols, static_cast<SwCellFrame*>(pBoxFrame) );
1571 
1572  if ( ! aTabCols.Count() )
1573  return;
1574 
1575  std::vector<sal_uInt16> aWish(aTabCols.Count() + 1);
1576  std::vector<sal_uInt16> aMins(aTabCols.Count() + 1);
1577 
1578  ::lcl_CalcColValues( aWish, aTabCols, pStart, pEnd, /*bWishValues=*/true );
1579 
1580  // It's more robust if we calculate the minimum values for the whole Table
1581  const SwTabFrame *pTab = pStart->ImplFindTabFrame();
1582  pStart = const_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame const *>(pTab->FirstCell()));
1583  pEnd = const_cast<SwLayoutFrame*>(pTab->FindLastContentOrTable()->GetUpper());
1584  while( !pEnd->IsCellFrame() )
1585  pEnd = pEnd->GetUpper();
1586  ::lcl_CalcColValues( aMins, aTabCols, pStart, pEnd, /*bWishValues=*/false );
1587 
1588  sal_uInt16 nSelectedWidth = 0, nCols = 0;
1589  float fTotalWish = 0;
1590  if ( bBalance || bNoShrink )
1591  {
1592  // Find the combined size of the selected columns
1593  for ( size_t i = 0; i <= aTabCols.Count(); ++i )
1594  {
1595  if ( aWish[i] )
1596  {
1597  if ( i == 0 )
1598  nSelectedWidth += aTabCols[i] - aTabCols.GetLeft();
1599  else if ( i == aTabCols.Count() )
1600  nSelectedWidth += aTabCols.GetRight() - aTabCols[i-1];
1601  else
1602  nSelectedWidth += aTabCols[i] - aTabCols[i-1];
1603  ++nCols;
1604  }
1605  fTotalWish += aWish[i];
1606  }
1607  const sal_uInt16 nEqualWidth = nSelectedWidth / nCols;
1608  // bBalance: Distribute the width evenly
1609  for (sal_uInt16 & rn : aWish)
1610  if ( rn && bBalance )
1611  rn = nEqualWidth;
1612  }
1613 
1614  const tools::Long nOldRight = aTabCols.GetRight();
1615 
1616  // In order to make the implementation easier, but still use the available
1617  // space properly, we do this twice.
1618 
1619  // The problem: The first column is getting wider, the others get slimmer
1620  // only afterwards.
1621  // The first column's desired width would be discarded as it would cause
1622  // the Table's width to exceed the maximum width.
1623  const sal_uInt16 nEqualWidth = (aTabCols.GetRight() - aTabCols.GetLeft()) / (aTabCols.Count() + 1);
1624  const sal_Int16 nTablePadding = nSelectedWidth - fTotalWish;
1625  for ( int k = 0; k < 2; ++k )
1626  {
1627  for ( size_t i = 0; i <= aTabCols.Count(); ++i )
1628  {
1629  // bNoShrink: distribute excess space proportionately on pass 2.
1630  if ( bNoShrink && k && nTablePadding > 0 && fTotalWish > 0 )
1631  aWish[i] += round( aWish[i] / fTotalWish * nTablePadding );
1632 
1633  // First pass is primarily a shrink pass. Give all columns a chance
1634  // to grow by requesting the maximum width as "balanced".
1635  // Second pass is a first-come, first-served chance to max out.
1636  int nDiff = k ? aWish[i] : std::min(aWish[i], nEqualWidth);
1637  if ( nDiff )
1638  {
1639  int nMin = aMins[i];
1640  if ( nMin > nDiff )
1641  nDiff = nMin;
1642 
1643  if ( i == 0 )
1644  {
1645  if( aTabCols.Count() )
1646  nDiff -= aTabCols[0] - aTabCols.GetLeft();
1647  else
1648  nDiff -= aTabCols.GetRight() - aTabCols.GetLeft();
1649  }
1650  else if ( i == aTabCols.Count() )
1651  nDiff -= aTabCols.GetRight() - aTabCols[i-1];
1652  else
1653  nDiff -= aTabCols[i] - aTabCols[i-1];
1654 
1655  tools::Long nTabRight = aTabCols.GetRight() + nDiff;
1656  const tools::Long nMaxRight = std::max(aTabCols.GetRightMax(), nOldRight);
1657 
1658  // If the Table would become (or is already) too wide,
1659  // restrict the column growth to the allowed maximum.
1660  if (!bBalance && nTabRight > nMaxRight)
1661  {
1662  const tools::Long nTmpD = nTabRight - nMaxRight;
1663  nDiff -= nTmpD;
1664  nTabRight -= nTmpD;
1665  }
1666 
1667  // all the remaining columns need to be shifted by the same amount
1668  for ( size_t i2 = i; i2 < aTabCols.Count(); ++i2 )
1669  aTabCols[i2] += nDiff;
1670  aTabCols.SetRight( nTabRight );
1671  }
1672  }
1673  }
1674 
1675  const tools::Long nNewRight = aTabCols.GetRight();
1676 
1677  SwFrameFormat *pFormat = pTableNd->GetTable().GetFrameFormat();
1678  const sal_Int16 nOriHori = pFormat->GetHoriOrient().GetHoriOrient();
1679 
1680  // We can leave the "real" work to the SwTable now
1681  SetTabCols( aTabCols, false, static_cast<SwCellFrame*>(pBoxFrame) );
1682 
1683  // Alignment might have been changed in SetTabCols; restore old value
1684  const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient();
1685  SwFormatHoriOrient aHori( rHori );
1686  if ( aHori.GetHoriOrient() != nOriHori )
1687  {
1688  aHori.SetHoriOrient( nOriHori );
1689  pFormat->SetFormatAttr( aHori );
1690  }
1691 
1692  // We switch to left-adjusted for automatic width
1693  // We adjust the right border for Border attributes
1694  if( !bBalance && nNewRight < nOldRight )
1695  {
1696  if( aHori.GetHoriOrient() == text::HoriOrientation::FULL )
1697  {
1698  aHori.SetHoriOrient( text::HoriOrientation::LEFT );
1699  pFormat->SetFormatAttr( aHori );
1700  }
1701  }
1702 
1704 }
1705 
1706 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsAnLower(const SwFrame *) const
Definition: findfrm.cxx:210
bool GetValue() const
SwNodeOffset min(const SwNodeOffset &a, const SwNodeOffset &b)
Definition: nodeoffset.hxx:35
Base class of the Writer layout elements.
Definition: frame.hxx:315
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:159
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
static const sal_Int16 VeryThin
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:224
void Right(const tools::Long nRight)
Definition: swrect.hxx:202
bool IsFollow() const
Definition: flowfrm.hxx:166
static void GetTabBorders(const SwCursor &rCursor, SfxItemSet &rSet)
Definition: ndtbl1.cxx:997
void SetHeight(tools::Long n)
virtual const SwRootFrame * GetCurrentLayout() const =0
static sal_uInt16 GetBoxAlign(const SwCursor &rCursor)
Definition: ndtbl1.cxx:1337
static void lcl_SetLineStyle(SvxBorderLine *pToSet, const Color *pColor, const SvxBorderLine *pBorderLine)
Definition: ndtbl1.cxx:891
virtual void SetRedlineFlags_intern(RedlineFlags eMode)=0
Set a new redline mode.
void Left(const tools::Long nLeft)
Definition: swrect.hxx:197
SwNodeIndex nNode
Definition: pam.hxx:38
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:3390
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:210
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:1210
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1475
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:358
SwNode & GetNode() const
Definition: ndindex.hxx:121
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
iterator begin()
Definition: swtable.hxx:78
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
SwNodeOffset abs(const SwNodeOffset &a)
Definition: nodeoffset.hxx:34
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:315
SwTableFormat * GetFrameFormat()
Definition: swtable.hxx:205
Value in Var-direction gives minimum (can be exceeded but not be less).
size_type size() const
Definition: swtable.hxx:77
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:230
constexpr TypedWhichId< SwFormatVertOrient > RES_VERT_ORIENT(102)
void ChgFrameFormat(SwTableLineFormat *pNewFormat)
Definition: swtable.cxx:1508
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:1548
void SetHoriOrient(sal_Int16 eNew)
Definition: fmtornt.hxx:89
SwIndex nContent
Definition: pam.hxx:39
void SetBoxAttr(const SwCursor &rCursor, const SfxPoolItem &rNew)
Definition: ndtbl1.cxx:1218
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:488
void Width(tools::Long nNew)
Definition: swrect.hxx:189
const FndBoxes_t & GetBoxes() const
Definition: tblsel.hxx:203
iterator insert(iterator aIt, SwTableLine *pLine)
Definition: swtable.hxx:87
const SwTable & GetTable() const
Definition: node.hxx:500
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:1263
SwPaM * GetNext()
Definition: pam.hxx:265
void SetBoxAlign(const SwCursor &rCursor, sal_uInt16 nAlign)
Definition: ndtbl1.cxx:1328
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:137
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:501
#define CH_TXT_TRACKED_DUMMY_CHAR
Definition: hintids.hxx:188
static void lcl_CalcSubColValues(std::vector< sal_uInt16 > &rToFill, const SwTabCols &rCols, const SwLayoutFrame *pCell, const SwLayoutFrame *pTab, bool bWishValues)
Definition: ndtbl1.cxx:1401
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:213
const SwPosition * GetPoint() const
Definition: pam.hxx:208
bool empty() const
Definition: swtable.hxx:76
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:625
static void InsertCell(std::vector< SwCellFrame * > &rCellArr, SwCellFrame *pCellFrame)
Definition: ndtbl1.cxx:596
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:1463
SwContentNode * GetContentNode()
Definition: node.hxx:619
SwNodeOffset GetIndex() const
Definition: node.hxx:292
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxInfoItemLine nLine)
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:1765
sal_Int16 GetHoriOrient() const
Definition: fmtornt.hxx:87
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:394
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:381
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:1695
const Point & GetMkPos() const
Definition: viscrs.hxx:148
virtual SvxBoxItem * Clone(SfxItemPool *pPool=nullptr) const override
Marks a node in the document model.
Definition: ndindex.hxx:32
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:458
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:1360
static std::unique_ptr< SwFormatRowSplit > GetRowSplit(const SwCursor &rCursor)
Definition: ndtbl1.cxx:349
SwTableLines & GetTabLines()
Definition: swtable.hxx:202
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:113
SwTableLines & GetTabLines()
Definition: swtable.hxx:451
void SetTabLineStyle(const SwCursor &rCursor, const Color *pColor, bool bSetLine, const editeng::SvxBorderLine *pBorderLine)
Definition: ndtbl1.cxx:909
const SwCellFrame * FirstCell() const
Calls ContainsAny first to reach the innermost cell.
Definition: findfrm.cxx:116
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:211
SwTableBoxes & GetTabBoxes()
Definition: swtable.hxx:369
#define COLFUZZY
Definition: ndtbl1.cxx:60
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
std::vector< SwTableBox * > SwTableBoxes
Definition: swtable.hxx:106
constexpr TypedWhichId< SvxBrushItem > RES_BACKGROUND(105)
void ChgFrameFormat(SwTableBoxFormat *pNewFormat, bool bNeedToReregister=true)
Definition: swtable.cxx:1931
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:462
SwHTMLTableLayout * GetHTMLTableLayout()
Definition: swtable.hxx:178
std::vector< SwSelUnion > SwSelUnions
Definition: tblsel.hxx:138
const SwTableBox * GetBox() const
Definition: tblsel.hxx:175
SvxBoxItemLine
void SetRowNotTracked(const SwCursor &rCursor, const SvxPrintItem &rNotTracked, bool bAll=false)
rNotTracked = false means that the row was deleted or inserted with its tracked cell content bAll: de...
Definition: ndtbl1.cxx:543
static void lcl_CollectCells(std::vector< SwCellFrame * > &rArr, const SwRect &rUnion, SwTabFrame *pTab)
Definition: ndtbl1.cxx:602
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:206
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:419
bool BalanceRowHeight(const SwCursor &rCursor, bool bTstOnly, const bool bOptimize)
Adjustment of Rowheights.
Definition: ndtbl1.cxx:435
const Point & GetPtPos() const
Definition: viscrs.hxx:146
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:1895
constexpr TypedWhichId< SvxBoxItem > RES_BOX(106)
const SwStartNode * FindTableBoxStartNode() const
Definition: node.hxx:198
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:357
SwTableBox * GetUpper()
Definition: swtable.hxx:377
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
iterator end()
Definition: swtable.hxx:80
sal_uInt16 GetBrowseWidthByTabFrame(const SwTabFrame &rTabFrame) const
Calculates available width by table-frame.
Definition: htmltbl.cxx:342
std::pair< const_iterator, bool > insert(Value &&x)
SwTableLine * GetUpper()
Definition: swtable.hxx:454
tools::Long GetRight() const
Definition: tabcol.hxx:79
bool Overlaps(const SwRect &rRect) const
Definition: swrect.hxx:374
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:514
Base class of the Writer document model elements.
Definition: node.hxx:81