LibreOffice Module sw (master)  1
gctable.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 <tblrwcl.hxx>
22 #include <algorithm>
23 #include <editeng/borderline.hxx>
24 #include <editeng/boxitem.hxx>
25 #include <osl/diagnose.h>
26 
27 using namespace ::editeng;
28 
29 static const SvxBorderLine* GetLineTB( const SvxBoxItem* pBox, bool bTop )
30 {
31  return bTop ? pBox->GetTop() : pBox->GetBottom();
32 }
33 
35 {
36  const SfxPoolItem* pItem;
37  if( SfxItemState::SET == rFormat.GetItemState( RES_BOX, true, &pItem ) )
38  {
39  const SvxBorderLine* pBrd = static_cast<const SvxBoxItem*>(pItem)->GetLeft();
40  if( pBrd )
41  {
42  if( *pBrdLn == *pBrd )
43  bAnyBorderFnd = true;
44  return true;
45  }
46  }
47  return false;
48 }
49 
50 static bool lcl_GCBorder_ChkBoxBrd_B( const SwTableBox* pBox, SwGCBorder_BoxBrd* pPara );
51 
52 static bool lcl_GCBorder_ChkBoxBrd_L( const SwTableLine* pLine, SwGCBorder_BoxBrd* pPara )
53 {
54  const SwTableBox* pBox = pLine->GetTabBoxes().front();
55  return lcl_GCBorder_ChkBoxBrd_B( pBox, pPara );
56 }
57 
58 static bool lcl_GCBorder_ChkBoxBrd_B( const SwTableBox* pBox, SwGCBorder_BoxBrd* pPara )
59 {
60  if( !pBox->GetTabLines().empty() )
61  {
62  for( auto pLine : pBox->GetTabLines() )
63  {
64  if (!lcl_GCBorder_ChkBoxBrd_L( pLine, pPara ))
65  {
66  return false;
67  }
68  }
69  return true;
70  }
71 
72  return pPara->CheckLeftBorderOfFormat( *pBox->GetFrameFormat() );
73 }
74 
75 static void lcl_GCBorder_GetLastBox_B( const SwTableBox* pBox, SwTableBoxes* pPara );
76 
77 static void lcl_GCBorder_GetLastBox_L( const SwTableLine* pLine, SwTableBoxes* pPara )
78 {
79  const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
80  SwTableBox* pBox = rBoxes.back();
81  lcl_GCBorder_GetLastBox_B( pBox, pPara );
82 }
83 
84 static void lcl_GCBorder_GetLastBox_B( const SwTableBox* pBox, SwTableBoxes* pPara )
85 {
86  const SwTableLines& rLines = pBox->GetTabLines();
87  if( !rLines.empty() )
88  {
89  for( const SwTableLine* pLine : rLines )
90  lcl_GCBorder_GetLastBox_L( pLine, pPara );
91  }
92  else
93  pPara->push_back( const_cast<SwTableBox*>(pBox) );
94 }
95 
96 // Find the "end" of the passed BorderLine. Returns the "Layout"Pos!
97 static sal_uInt16 lcl_FindEndPosOfBorder( const SwCollectTableLineBoxes& rCollTLB,
98  const SvxBorderLine& rBrdLn, size_t& rStt, bool bTop )
99 {
100  sal_uInt16 nPos, nLastPos = 0;
101  for( size_t nEnd = rCollTLB.Count(); rStt < nEnd; ++rStt )
102  {
103  const SfxPoolItem* pItem;
104  const SvxBorderLine* pBrd;
105  const SwTableBox& rBox = rCollTLB.GetBox( rStt, &nPos );
106 
107  if( SfxItemState::SET != rBox.GetFrameFormat()->GetItemState(RES_BOX,true, &pItem ) )
108  break;
109  pBrd = GetLineTB( static_cast<const SvxBoxItem*>(pItem), bTop );
110  if( !pBrd || *pBrd != rBrdLn )
111  break;
112  nLastPos = nPos;
113  }
114  return nLastPos;
115 }
116 
117 static const SvxBorderLine* lcl_GCBorder_GetBorder( const SwTableBox& rBox,
118  bool bTop,
119  const SfxPoolItem** ppItem )
120 {
121  return SfxItemState::SET == rBox.GetFrameFormat()->GetItemState( RES_BOX, true, ppItem )
122  ? GetLineTB( static_cast<const SvxBoxItem*>(*ppItem), bTop )
123  : nullptr;
124 }
125 
126 static void lcl_GCBorder_DelBorder( const SwCollectTableLineBoxes& rCollTLB,
127  size_t& rStt, bool bTop,
128  const SvxBorderLine& rLine,
129  const SfxPoolItem* pItem,
130  sal_uInt16 nEndPos,
131  SwShareBoxFormats* pShareFormats )
132 {
133  SwTableBox* pBox = const_cast<SwTableBox*>(&rCollTLB.GetBox( rStt ));
134  sal_uInt16 nNextPos;
135  const SvxBorderLine* pLn = &rLine;
136 
137  do {
138  if( pLn && *pLn == rLine )
139  {
140  SvxBoxItem aBox( *static_cast<const SvxBoxItem*>(pItem) );
141  if( bTop )
142  aBox.SetLine( nullptr, SvxBoxItemLine::TOP );
143  else
144  aBox.SetLine( nullptr, SvxBoxItemLine::BOTTOM );
145 
146  if( pShareFormats )
147  pShareFormats->SetAttr( *pBox, aBox );
148  else
149  pBox->ClaimFrameFormat()->SetFormatAttr( aBox );
150  }
151 
152  if( ++rStt >= rCollTLB.Count() )
153  break;
154 
155  pBox = const_cast<SwTableBox*>(&rCollTLB.GetBox( rStt, &nNextPos ));
156  if( nNextPos > nEndPos )
157  break;
158 
159  pLn = lcl_GCBorder_GetBorder( *pBox, bTop, &pItem );
160 
161  } while( true );
162 }
163 
164 static void lcl_GC_Box_Border( const SwTableBox* pBox, SwGCLineBorder* pPara );
165 
166 void sw_GC_Line_Border( const SwTableLine* pLine, SwGCLineBorder* pGCPara )
167 {
168  // First the right edge with the left edge of the succeeding Box within this Line
169  {
170  SwGCBorder_BoxBrd aBPara;
171  const SvxBorderLine* pBrd;
172  const SfxPoolItem* pItem;
173  const SwTableBoxes& rBoxes = pLine->GetTabBoxes();
174  for( SwTableBoxes::size_type n = 0, nBoxes = rBoxes.size() - 1; n < nBoxes; ++n )
175  {
176  SwTableBoxes aBoxes;
177  {
178  SwTableBox* pBox = rBoxes[ n ];
179  if( pBox->GetSttNd() )
180  aBoxes.insert( aBoxes.begin(), pBox );
181  else
182  lcl_GCBorder_GetLastBox_B( pBox, &aBoxes );
183  }
184 
185  for( SwTableBoxes::size_type i = aBoxes.size(); i; )
186  {
187  SwTableBox* pBox = aBoxes[ --i ];
188  if( SfxItemState::SET == pBox->GetFrameFormat()->GetItemState( RES_BOX, true, &pItem ) )
189  {
190  pBrd = static_cast<const SvxBoxItem*>(pItem)->GetRight();
191  if( pBrd )
192  {
193  aBPara.SetBorder( *pBrd );
194  const SwTableBox* pNextBox = rBoxes[n+1];
195  if( lcl_GCBorder_ChkBoxBrd_B( pNextBox, &aBPara ) &&
196  aBPara.IsAnyBorderFound() )
197  {
198  SvxBoxItem aBox( *static_cast<const SvxBoxItem*>(pItem) );
199  aBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
200  if( pGCPara->pShareFormats )
201  pGCPara->pShareFormats->SetAttr( *pBox, aBox );
202  else
203  pBox->ClaimFrameFormat()->SetFormatAttr( aBox );
204  }
205  }
206  }
207  }
208 
209  aBoxes.clear();
210  }
211  }
212 
213  // And now the own bottom edge with the succeeding top edge
214  if( !pGCPara->IsLastLine() )
215  {
216  SwCollectTableLineBoxes aBottom( false );
217  SwCollectTableLineBoxes aTop( true );
218 
219  sw_Line_CollectBox( pLine, &aBottom );
220 
221  const SwTableLine* pNextLine = (*pGCPara->pLines)[ pGCPara->nLinePos+1 ];
222  sw_Line_CollectBox( pNextLine, &aTop );
223 
224  // remove all "duplicated" Lines that are the same
225  sal_uInt16 nBtmPos, nTopPos;
226 
227  size_t nSttBtm {0};
228  size_t nSttTop {0};
229  const size_t nEndBtm {aBottom.Count()};
230  const size_t nEndTop {aTop.Count()};
231 
232  const SwTableBox *pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
233  const SwTableBox *pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
234  const SfxPoolItem *pBtmItem = nullptr, *pTopItem = nullptr;
235  const SvxBorderLine *pBtmLine(nullptr), *pTopLine(nullptr);
236  bool bGetTopItem = true, bGetBtmItem = true;
237 
238  do {
239  if( bGetBtmItem )
240  pBtmLine = lcl_GCBorder_GetBorder( *pBtmBox, false, &pBtmItem );
241  if( bGetTopItem )
242  pTopLine = lcl_GCBorder_GetBorder( *pTopBox, true, &pTopItem );
243 
244  if( pTopLine && pBtmLine && *pTopLine == *pBtmLine )
245  {
246  // We can remove one, but which one?
247  const size_t nSavSttBtm {nSttBtm};
248  const size_t nSavSttTop {nSttTop};
249  sal_uInt16 nBtmEndPos = ::lcl_FindEndPosOfBorder( aBottom,
250  *pTopLine, nSttBtm, false );
251  if( !nBtmEndPos ) nBtmEndPos = nBtmPos;
252  sal_uInt16 nTopEndPos = ::lcl_FindEndPosOfBorder( aTop,
253  *pTopLine, nSttTop, true );
254  if( !nTopEndPos ) nTopEndPos = nTopPos;
255 
256  if( nTopEndPos <= nBtmEndPos )
257  {
258  // Delete the TopBorders until BottomEndPos
259  nSttTop = nSavSttTop;
260  if( nTopPos <= nBtmEndPos )
261  lcl_GCBorder_DelBorder( aTop, --nSttTop, true,
262  *pBtmLine, pTopItem, nBtmEndPos,
263  pGCPara->pShareFormats );
264  else
265  nSttBtm = nSavSttBtm;
266  }
267  else
268  {
269  // Else delete the BottomBorders until TopEndPos
270  nSttBtm = nSavSttBtm;
271  if( nBtmPos <= nTopEndPos )
272  lcl_GCBorder_DelBorder( aBottom, --nSttBtm, false,
273  *pTopLine, pBtmItem, nTopEndPos,
274  pGCPara->pShareFormats );
275  else
276  nSttTop = nSavSttTop;
277  }
278  nTopPos = nBtmPos;
279  }
280 
281  if( nTopPos == nBtmPos )
282  {
283  if( nSttBtm >= nEndBtm || nSttTop >= nEndTop )
284  break;
285 
286  pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
287  pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
288  bGetTopItem = bGetBtmItem = true;
289  }
290  else if( nTopPos < nBtmPos )
291  {
292  if( nSttTop >= nEndTop )
293  break;
294  pTopBox = &aTop.GetBox( nSttTop++, &nTopPos );
295  bGetTopItem = true;
296  bGetBtmItem = false;
297  }
298  else
299  {
300  if( nSttBtm >= nEndBtm )
301  break;
302  pBtmBox = &aBottom.GetBox( nSttBtm++, &nBtmPos );
303  bGetTopItem = false;
304  bGetBtmItem = true;
305  }
306 
307  } while( true );
308  }
309 
310  for( const auto& rpBox : pLine->GetTabBoxes() )
311  lcl_GC_Box_Border(rpBox, pGCPara );
312 
313  ++pGCPara->nLinePos;
314 }
315 
316 static void lcl_GC_Box_Border( const SwTableBox* pBox, SwGCLineBorder* pPara )
317 {
318  if( !pBox->GetTabLines().empty() )
319  {
320  SwGCLineBorder aPara( *pBox );
321  aPara.pShareFormats = pPara->pShareFormats;
322  for( const SwTableLine* pLine : pBox->GetTabLines() )
323  sw_GC_Line_Border( pLine, &aPara );
324  }
325 }
326 
327 namespace {
328 
329 struct GCLinePara
330 {
331  SwTableLines* pLns;
332  SwShareBoxFormats* pShareFormats;
333 
334  GCLinePara( SwTableLines& rLns, GCLinePara* pPara = nullptr )
335  : pLns( &rLns ), pShareFormats( pPara ? pPara->pShareFormats : nullptr )
336  {}
337 };
338 
339 }
340 
341 static bool lcl_MergeGCLine(SwTableLine* pLine, GCLinePara* pPara);
342 
343 static bool lcl_MergeGCBox(SwTableBox* pTableBox, GCLinePara* pPara)
344 {
345  if( !pTableBox->GetTabLines().empty() )
346  {
347  // ATTENTION: The Line count can change!
348  GCLinePara aPara( pTableBox->GetTabLines(), pPara );
349  for( SwTableLines::size_type n = 0;
350  n < pTableBox->GetTabLines().size() && lcl_MergeGCLine( pTableBox->GetTabLines()[n], &aPara );
351  ++n )
352  ;
353 
354  if( 1 == pTableBox->GetTabLines().size() )
355  {
356  // we have a box with a single line, so we just replace it by the line's boxes
357  SwTableLine* pInsLine = pTableBox->GetUpper();
358  SwTableLine* pCpyLine = pTableBox->GetTabLines()[0];
359  SwTableBoxes::iterator it = std::find( pInsLine->GetTabBoxes().begin(), pInsLine->GetTabBoxes().end(), pTableBox );
360  for( auto pTabBox : pCpyLine->GetTabBoxes() )
361  pTabBox->SetUpper( pInsLine );
362 
363  // remove the old box from its parent line
364  it = pInsLine->GetTabBoxes().erase( it );
365  // insert the nested line's boxes in its place
366  pInsLine->GetTabBoxes().insert( it, pCpyLine->GetTabBoxes().begin(), pCpyLine->GetTabBoxes().end());
367  pCpyLine->GetTabBoxes().clear();
368  // destroy the removed box
369  delete pTableBox;
370 
371  return false; // set up anew
372  }
373  }
374  return true;
375 }
376 
377 static bool lcl_MergeGCLine(SwTableLine* pLn, GCLinePara* pGCPara)
378 {
379  SwTableBoxes::size_type nBoxes = pLn->GetTabBoxes().size();
380  if( nBoxes )
381  {
382  while( 1 == nBoxes )
383  {
384  // We have a Box with Lines
385  SwTableBox* pBox = pLn->GetTabBoxes().front();
386  if( pBox->GetTabLines().empty() )
387  break;
388 
389  SwTableLine* pLine = pBox->GetTabLines()[0];
390 
391  // pLine turns into the current Line (that is rpLine), the rest is moved
392  // into the LinesArray past the current one.
393  // The LinesArray is in pPara!
394  SwTableLines::size_type nLines = pBox->GetTabLines().size();
395 
396  SwTableLines& rLns = *pGCPara->pLns;
397  sal_uInt16 nInsPos = rLns.GetPos( pLn );
398  OSL_ENSURE( USHRT_MAX != nInsPos, "Could not find Line!" );
399 
400  SwTableBox* pUpper = pLn->GetUpper();
401 
402  rLns.erase( rLns.begin() + nInsPos ); // remove the Line from the array
403  rLns.insert( rLns.begin() + nInsPos, pBox->GetTabLines().begin(), pBox->GetTabLines().end() );
404 
405  // JP 31.03.99: Bug 60000
406  // Pass the attributes of the to-be-deleted Lines to the "inserted" one
407  const SfxPoolItem* pItem;
408  if( SfxItemState::SET == pLn->GetFrameFormat()->GetItemState(
409  RES_BACKGROUND, true, &pItem ))
410  {
411  SwTableLines& rBoxLns = pBox->GetTabLines();
412  for( auto pBoxLine : rBoxLns )
413  if( SfxItemState::SET != pBoxLine->GetFrameFormat()->
414  GetItemState( RES_BACKGROUND ))
415  pGCPara->pShareFormats->SetAttr( *pBoxLine, *pItem );
416  }
417 
418  pBox->GetTabLines().erase( pBox->GetTabLines().begin(), pBox->GetTabLines().begin() + nLines ); // Remove Lines from the array
419 
420  delete pLn;
421 
422  // Set the dependency anew
423  while( nLines-- )
424  rLns[ nInsPos++ ]->SetUpper( pUpper );
425 
426  pLn = pLine; // and set up anew
427  nBoxes = pLn->GetTabBoxes().size();
428  }
429 
430  // ATTENTION: The number of boxes can change!
431  for( SwTableBoxes::size_type nLen = 0; nLen < pLn->GetTabBoxes().size(); ++nLen )
432  if( !lcl_MergeGCBox( pLn->GetTabBoxes()[nLen], pGCPara ))
433  --nLen;
434  }
435  return true;
436 }
437 
438 // Clean structure a bit
440 {
441  // ATTENTION: The Line count can change!
442  GCLinePara aPara( GetTabLines() );
443  SwShareBoxFormats aShareFormats;
444  aPara.pShareFormats = &aShareFormats;
445  for( SwTableLines::size_type n = 0; n < GetTabLines().size() &&
446  lcl_MergeGCLine( GetTabLines()[n], &aPara ); ++n )
447  ;
448 }
449 
450 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::vector< SwTableLine * >::size_type size_type
Definition: swtable.hxx:66
static void lcl_GC_Box_Border(const SwTableBox *pBox, SwGCLineBorder *pPara)
Definition: gctable.cxx:316
static bool lcl_MergeGCBox(SwTableBox *pTableBox, GCLinePara *pPara)
Definition: gctable.cxx:343
static sal_uInt16 lcl_FindEndPosOfBorder(const SwCollectTableLineBoxes &rCollTLB, const SvxBorderLine &rBrdLn, size_t &rStt, bool bTop)
Definition: gctable.cxx:97
sal_Int64 n
SwTableLine is one table row in the document model.
Definition: swtable.hxx:344
sal_uInt16 nLinePos
Definition: tblrwcl.hxx:122
iterator begin()
Definition: swtable.hxx:75
const SwTableLines * pLines
Definition: tblrwcl.hxx:120
size_type size() const
Definition: swtable.hxx:74
SwShareBoxFormats * pShareFormats
Definition: tblrwcl.hxx:121
static const SvxBorderLine * lcl_GCBorder_GetBorder(const SwTableBox &rBox, bool bTop, const SfxPoolItem **ppItem)
Definition: gctable.cxx:117
static void lcl_GCBorder_GetLastBox_L(const SwTableLine *pLine, SwTableBoxes *pPara)
Definition: gctable.cxx:77
static const SvxBorderLine * GetLineTB(const SvxBoxItem *pBox, bool bTop)
Definition: gctable.cxx:29
iterator insert(iterator aIt, SwTableLine *pLine)
Definition: swtable.hxx:84
bool IsLastLine() const
Definition: tblrwcl.hxx:129
Class for SplitTable Collects the uppermost or lowermost Lines of a Box from a Line in an array...
Definition: tblrwcl.hxx:61
const editeng::SvxBorderLine * GetTop() const
Style of a layout element.
Definition: frmfmt.hxx:57
int i
bool empty() const
Definition: swtable.hxx:73
const SwTableBox & GetBox(std::size_t nPos, sal_uInt16 *pWidth=nullptr) const
Definition: tblrwcl.hxx:84
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:366
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
Definition: format.cxx:396
SwFrameFormat * GetFrameFormat()
Definition: swtable.hxx:425
SwTableLines & GetTabLines()
Definition: swtable.hxx:198
SwTableLines & GetTabLines()
Definition: swtable.hxx:418
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:458
bool sw_Line_CollectBox(const SwTableLine *&rpLine, void *pPara)
Definition: ndtbl.cxx:2979
SwTableBoxes & GetTabBoxes()
Definition: swtable.hxx:354
size_t Count() const
Definition: tblrwcl.hxx:83
static bool lcl_MergeGCLine(SwTableLine *pLine, GCLinePara *pPara)
Definition: gctable.cxx:377
std::vector< SwTableBox * > SwTableBoxes
Definition: swtable.hxx:103
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:439
constexpr TypedWhichId< SvxBrushItem > RES_BACKGROUND(105)
void GCLines()
Definition: gctable.cxx:439
static bool lcl_GCBorder_ChkBoxBrd_B(const SwTableBox *pBox, SwGCBorder_BoxBrd *pPara)
Definition: gctable.cxx:58
const o3tl::enumarray< SvxAdjust, unsigned short > aSvxToUnoAdjust USHRT_MAX
Definition: unosett.cxx:253
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:386
void SetAttr(SwTableBox &rBox, const SfxPoolItem &rItem)
Definition: tblrwcl.cxx:3330
bool CheckLeftBorderOfFormat(const SwFrameFormat &rFormat)
Check whether the left Border is the same as the set one.
Definition: gctable.cxx:34
static void lcl_GCBorder_GetLastBox_B(const SwTableBox *pBox, SwTableBoxes *pPara)
Definition: gctable.cxx:84
const editeng::SvxBorderLine * pBrdLn
Definition: tblrwcl.hxx:134
SwFrameFormat * ClaimFrameFormat()
Definition: swtable.cxx:1706
constexpr TypedWhichId< SvxBoxItem > RES_BOX(106)
SwTableBox * GetUpper()
Definition: swtable.hxx:362
void sw_GC_Line_Border(const SwTableLine *pLine, SwGCLineBorder *pGCPara)
Definition: gctable.cxx:166
sal_uInt16 GetPos(const SwTableLine *pBox) const
Definition: swtable.hxx:96
iterator end()
Definition: swtable.hxx:77
bool IsAnyBorderFound() const
Definition: tblrwcl.hxx:148
SwTableLine * GetUpper()
Definition: swtable.hxx:421
void SetBorder(const editeng::SvxBorderLine &rBorderLine)
Definition: tblrwcl.hxx:139
const editeng::SvxBorderLine * GetBottom() const
static void lcl_GCBorder_DelBorder(const SwCollectTableLineBoxes &rCollTLB, size_t &rStt, bool bTop, const SvxBorderLine &rLine, const SfxPoolItem *pItem, sal_uInt16 nEndPos, SwShareBoxFormats *pShareFormats)
Definition: gctable.cxx:126
static bool lcl_GCBorder_ChkBoxBrd_L(const SwTableLine *pLine, SwGCBorder_BoxBrd *pPara)
Definition: gctable.cxx:52
sal_uInt16 nPos
iterator erase(iterator aIt)
Definition: swtable.hxx:82
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)