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