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