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 
323 {
326 
327  GCLinePara( SwTableLines& rLns, GCLinePara* pPara = nullptr )
328  : pLns( &rLns ), pShareFormats( pPara ? pPara->pShareFormats : nullptr )
329  {}
330 };
331 
332 static bool lcl_MergeGCLine(SwTableLine* pLine, GCLinePara* pPara);
333 
334 static bool lcl_MergeGCBox(SwTableBox* pTableBox, GCLinePara* pPara)
335 {
336  if( !pTableBox->GetTabLines().empty() )
337  {
338  // ATTENTION: The Line count can change!
339  GCLinePara aPara( pTableBox->GetTabLines(), pPara );
340  for( SwTableLines::size_type n = 0;
341  n < pTableBox->GetTabLines().size() && lcl_MergeGCLine( pTableBox->GetTabLines()[n], &aPara );
342  ++n )
343  ;
344 
345  if( 1 == pTableBox->GetTabLines().size() )
346  {
347  // we have a box with a single line, so we just replace it by the line's boxes
348  SwTableLine* pInsLine = pTableBox->GetUpper();
349  SwTableLine* pCpyLine = pTableBox->GetTabLines()[0];
350  SwTableBoxes::iterator it = std::find( pInsLine->GetTabBoxes().begin(), pInsLine->GetTabBoxes().end(), pTableBox );
351  for( auto pTabBox : pCpyLine->GetTabBoxes() )
352  pTabBox->SetUpper( pInsLine );
353 
354  // remove the old box from its parent line
355  it = pInsLine->GetTabBoxes().erase( it );
356  // insert the nested line's boxes in its place
357  pInsLine->GetTabBoxes().insert( it, pCpyLine->GetTabBoxes().begin(), pCpyLine->GetTabBoxes().end());
358  pCpyLine->GetTabBoxes().clear();
359  // destroy the removed box
360  delete pTableBox;
361 
362  return false; // set up anew
363  }
364  }
365  return true;
366 }
367 
368 static bool lcl_MergeGCLine(SwTableLine* pLn, GCLinePara* pGCPara)
369 {
370  SwTableBoxes::size_type nBoxes = pLn->GetTabBoxes().size();
371  if( nBoxes )
372  {
373  while( 1 == nBoxes )
374  {
375  // We have a Box with Lines
376  SwTableBox* pBox = pLn->GetTabBoxes().front();
377  if( pBox->GetTabLines().empty() )
378  break;
379 
380  SwTableLine* pLine = pBox->GetTabLines()[0];
381 
382  // pLine turns into the current Line (that is rpLine), the rest is moved
383  // into the LinesArray past the current one.
384  // The LinesArray is in pPara!
385  SwTableLines::size_type nLines = pBox->GetTabLines().size();
386 
387  SwTableLines& rLns = *pGCPara->pLns;
388  sal_uInt16 nInsPos = rLns.GetPos( pLn );
389  OSL_ENSURE( USHRT_MAX != nInsPos, "Could not find Line!" );
390 
391  SwTableBox* pUpper = pLn->GetUpper();
392 
393  rLns.erase( rLns.begin() + nInsPos ); // remove the Line from the array
394  rLns.insert( rLns.begin() + nInsPos, pBox->GetTabLines().begin(), pBox->GetTabLines().end() );
395 
396  // JP 31.03.99: Bug 60000
397  // Pass the attributes of the to-be-deleted Lines to the "inserted" one
398  const SfxPoolItem* pItem;
399  if( SfxItemState::SET == pLn->GetFrameFormat()->GetItemState(
400  RES_BACKGROUND, true, &pItem ))
401  {
402  SwTableLines& rBoxLns = pBox->GetTabLines();
403  for( auto pBoxLine : rBoxLns )
404  if( SfxItemState::SET != pBoxLine->GetFrameFormat()->
405  GetItemState( RES_BACKGROUND ))
406  pGCPara->pShareFormats->SetAttr( *pBoxLine, *pItem );
407  }
408 
409  pBox->GetTabLines().erase( pBox->GetTabLines().begin(), pBox->GetTabLines().begin() + nLines ); // Remove Lines from the array
410 
411  delete pLn;
412 
413  // Set the dependency anew
414  while( nLines-- )
415  rLns[ nInsPos++ ]->SetUpper( pUpper );
416 
417  pLn = pLine; // and set up anew
418  nBoxes = pLn->GetTabBoxes().size();
419  }
420 
421  // ATTENTION: The number of boxes can change!
422  for( SwTableBoxes::size_type nLen = 0; nLen < pLn->GetTabBoxes().size(); ++nLen )
423  if( !lcl_MergeGCBox( pLn->GetTabBoxes()[nLen], pGCPara ))
424  --nLen;
425  }
426  return true;
427 }
428 
429 // Clean structure a bit
431 {
432  // ATTENTION: The Line count can change!
433  GCLinePara aPara( GetTabLines() );
434  SwShareBoxFormats aShareFormats;
435  aPara.pShareFormats = &aShareFormats;
436  for( SwTableLines::size_type n = 0; n < GetTabLines().size() &&
437  lcl_MergeGCLine( GetTabLines()[n], &aPara ); ++n )
438  ;
439 }
440 
441 /* 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:334
static sal_uInt16 lcl_FindEndPosOfBorder(const SwCollectTableLineBoxes &rCollTLB, const SvxBorderLine &rBrdLn, size_t &rStt, bool bTop)
Definition: gctable.cxx:95
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
SwShareBoxFormats * pShareFormats
Definition: gctable.cxx:325
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:212
SwTableLines * pLns
Definition: gctable.cxx:324
const editeng::SvxBorderLine * GetTop() const
GCLinePara(SwTableLines &rLns, GCLinePara *pPara=nullptr)
Definition: gctable.cxx:327
Style of a layout element.
Definition: frmfmt.hxx:57
bool empty() const
Definition: swtable.hxx:73
const SwTableBox & GetBox(std::size_t nPos, sal_uInt16 *pWidth=nullptr) const
Definition: tblrwcl.hxx:84
int i
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:2956
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:368
std::vector< SwTableBox * > SwTableBoxes
Definition: swtable.hxx:103
const SwStartNode * GetSttNd() const
Definition: swtable.hxx:439
void GCLines()
Definition: gctable.cxx:430
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:261
SwTableBox is one table cell in the document model.
Definition: swtable.hxx:386
void SetAttr(SwTableBox &rBox, const SfxPoolItem &rItem)
Definition: tblrwcl.cxx:3304
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:1706
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:213
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
sal_Int32 nPos
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
iterator erase(iterator aIt)
Definition: swtable.hxx:82
void SetLine(const editeng::SvxBorderLine *pNew, SvxBoxItemLine nLine)