Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl1.cxx
Warning:line 1537, column 55
Division by zero

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ndtbl1.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl1.cxx
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>
38#include <IDocumentLayoutAccess.hxx>
39#include <pam.hxx>
40#include <swcrsr.hxx>
41#include <viscrs.hxx>
42#include <swtable.hxx>
43#include <htmltbl.hxx>
44#include <tblsel.hxx>
45#include <swtblfmt.hxx>
46#include <ndindex.hxx>
47#include <undobj.hxx>
48#include <calbck.hxx>
49#include <UndoTable.hxx>
50#include <o3tl/enumrange.hxx>
51#include <o3tl/safeint.hxx>
52
53using ::editeng::SvxBorderLine;
54using namespace ::com::sun::star;
55
56// See swtable.cxx too
57#define COLFUZZY20L 20L
58
59static bool IsSame( long nA, long nB ) { return std::abs(nA-nB) <= COLFUZZY20L; }
60
61namespace {
62
63// SwTableLine::ChgFrameFormat may delete old format which doesn't have writer listeners anymore.
64// This may invalidate my pointers, and lead to use-after-free. For this reason, I register myself
65// as a writer listener for the old format here, and take care to delete formats without listeners
66// in my own dtor.
67class SwTableFormatCmp : public SwClient
68{
69public:
70 SwTableFormatCmp( SwFrameFormat *pOld, SwFrameFormat *pNew, sal_Int16 nType );
71 ~SwTableFormatCmp() override;
72
73 static SwFrameFormat* FindNewFormat(std::vector<std::unique_ptr<SwTableFormatCmp>>& rArr,
74 SwFrameFormat const* pOld, sal_Int16 nType);
75
76private:
77 SwFrameFormat *m_pOld, *m_pNew;
78 sal_Int16 m_nType;
79};
80
81}
82
83SwTableFormatCmp::SwTableFormatCmp(SwFrameFormat* pO, SwFrameFormat* pN, sal_Int16 nT)
84 : m_pOld(pO)
85 , m_pNew(pN)
86 , m_nType(nT)
87{
88 if (m_pOld)
89 m_pOld->Add(this);
90}
91
92SwTableFormatCmp::~SwTableFormatCmp()
93{
94 if (m_pOld)
95 {
96 m_pOld->Remove(this);
97 if (!m_pOld->HasWriterListeners())
98 delete m_pOld;
99 }
100}
101
102// static
103SwFrameFormat* SwTableFormatCmp::FindNewFormat(std::vector<std::unique_ptr<SwTableFormatCmp>>& rArr,
104 SwFrameFormat const* pOld, sal_Int16 nType)
105{
106 for (const auto& pCmp : rArr)
107 {
108 if (pCmp->m_pOld == pOld && pCmp->m_nType == nType)
109 return pCmp->m_pNew;
110 }
111 return nullptr;
112}
113
114static void lcl_GetStartEndCell( const SwCursor& rCursor,
115 SwLayoutFrame *&prStart, SwLayoutFrame *&prEnd )
116{
117 OSL_ENSURE( rCursor.GetContentNode() && rCursor.GetContentNode( false ),do { if (true && (!(rCursor.GetContentNode() &&
rCursor.GetContentNode( false )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl1.cxx"
":" "118" ": "), "%s", "Tab selection not at ContentNode"); }
} while (false)
5
Taking true branch
6
Loop condition is false. Exiting loop
118 "Tab selection not at ContentNode" )do { if (true && (!(rCursor.GetContentNode() &&
rCursor.GetContentNode( false )))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl1.cxx"
":" "118" ": "), "%s", "Tab selection not at ContentNode"); }
} while (false)
;
119
120 Point aPtPos, aMkPos;
121 const SwShellCursor* pShCursor = dynamic_cast<const SwShellCursor*>(&rCursor);
122 if( pShCursor
6.1
'pShCursor' is non-null
)
7
Taking true branch
123 {
124 aPtPos = pShCursor->GetPtPos();
125 aMkPos = pShCursor->GetMkPos();
126 }
127
128 // Robust:
129 SwContentNode* pPointNd = rCursor.GetContentNode();
130 SwContentNode* pMarkNd = rCursor.GetContentNode(false);
131
132 std::pair<Point, bool> tmp(aPtPos, true);
133 SwFrame *const pPointFrame = pPointNd
7.1
'pPointNd' is non-null
? pPointNd->getLayoutFrame(pPointNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp) : nullptr;
8
'?' condition is true
134 tmp.first = aMkPos;
135 SwFrame *const pMarkFrame = pMarkNd
8.1
'pMarkNd' is null
? pMarkNd->getLayoutFrame(pMarkNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, &tmp) : nullptr;
9
'?' condition is false
136
137 prStart = pPointFrame ? pPointFrame->GetUpper() : nullptr;
10
Assuming 'pPointFrame' is non-null
11
'?' condition is true
12
Value assigned to 'pStart', which participates in a condition later
138 prEnd = pMarkFrame
12.1
'pMarkFrame' is null
? pMarkFrame->GetUpper() : nullptr;
13
'?' condition is false
139}
140
141static bool lcl_GetBoxSel( const SwCursor& rCursor, SwSelBoxes& rBoxes,
142 bool bAllCursor = false )
143{
144 const SwTableCursor* pTableCursor =
145 dynamic_cast<const SwTableCursor*>(&rCursor);
146 if( pTableCursor )
147 ::GetTableSelCrs( *pTableCursor, rBoxes );
148 else
149 {
150 const SwPaM *pCurPam = &rCursor, *pSttPam = pCurPam;
151 do {
152 const SwNode* pNd = pCurPam->GetNode().FindTableBoxStartNode();
153 if( pNd )
154 {
155 SwTableBox* pBox = const_cast<SwTableBox*>(pNd->FindTableNode()->GetTable().
156 GetTableBox( pNd->GetIndex() ));
157 rBoxes.insert( pBox );
158 }
159 } while( bAllCursor &&
160 pSttPam != ( pCurPam = pCurPam->GetNext()) );
161 }
162 return !rBoxes.empty();
163}
164
165static void InsertLine( std::vector<SwTableLine*>& rLineArr, SwTableLine* pLine )
166{
167 if( rLineArr.end() == std::find( rLineArr.begin(), rLineArr.end(), pLine ) )
168 rLineArr.push_back( pLine );
169}
170
171static bool lcl_IsAnLower( const SwTableLine *pLine, const SwTableLine *pAssumed )
172{
173 const SwTableLine *pTmp = pAssumed->GetUpper() ?
174 pAssumed->GetUpper()->GetUpper() : nullptr;
175 while ( pTmp )
176 {
177 if ( pTmp == pLine )
178 return true;
179 pTmp = pTmp->GetUpper() ? pTmp->GetUpper()->GetUpper() : nullptr;
180 }
181 return false;
182}
183
184namespace {
185
186struct LinesAndTable
187{
188 std::vector<SwTableLine*> &m_rLines;
189 const SwTable &m_rTable;
190 bool m_bInsertLines;
191
192 LinesAndTable(std::vector<SwTableLine*> &rL, const SwTable &rTable) :
193 m_rLines(rL), m_rTable(rTable), m_bInsertLines(true) {}
194};
195
196}
197
198static bool FindLine_( FndLine_ & rLine, LinesAndTable* pPara );
199
200static bool FindBox_( FndBox_ & rBox, LinesAndTable* pPara )
201{
202 if (!rBox.GetLines().empty())
203 {
204 pPara->m_bInsertLines = true;
205 for (auto const& rpFndLine : rBox.GetLines())
206 {
207 FindLine_(*rpFndLine, pPara);
208 }
209
210 if (pPara->m_bInsertLines)
211 {
212 const SwTableLines &rLines = (rBox.GetBox())
213 ? rBox.GetBox()->GetTabLines()
214 : pPara->m_rTable.GetTabLines();
215 if (rBox.GetLines().size() == rLines.size())
216 {
217 for ( auto pLine : rLines )
218 ::InsertLine(pPara->m_rLines, pLine);
219 }
220 else
221 pPara->m_bInsertLines = false;
222 }
223 }
224 else if (rBox.GetBox())
225 {
226 ::InsertLine(pPara->m_rLines, rBox.GetBox()->GetUpper());
227 }
228 return true;
229}
230
231bool FindLine_( FndLine_& rLine, LinesAndTable* pPara )
232{
233 for (auto const& it : rLine.GetBoxes())
234 {
235 FindBox_(*it, pPara);
236 }
237 return true;
238}
239
240static void lcl_CollectLines( std::vector<SwTableLine*> &rArr, const SwCursor& rCursor, bool bRemoveLines )
241{
242 // Collect the selected Boxes first
243 SwSelBoxes aBoxes;
244 if( !::lcl_GetBoxSel( rCursor, aBoxes ))
245 return ;
246
247 // Copy the selected structure
248 const SwTable &rTable = aBoxes[0]->GetSttNd()->FindTableNode()->GetTable();
249 LinesAndTable aPara( rArr, rTable );
250 FndBox_ aFndBox( nullptr, nullptr );
251 {
252 FndPara aTmpPara( aBoxes, &aFndBox );
253 ForEach_FndLineCopyCol( const_cast<SwTableLines&>(rTable.GetTabLines()), &aTmpPara );
254 }
255
256 // Collect the Lines which only contain selected Boxes
257 ::FindBox_(aFndBox, &aPara);
258
259 // Remove lines, that have a common superordinate row.
260 // (Not for row split)
261 if ( !bRemoveLines )
262 return;
263
264 for ( std::vector<SwTableLine*>::size_type i = 0; i < rArr.size(); ++i )
265 {
266 SwTableLine *pUpLine = rArr[i];
267 for ( std::vector<SwTableLine*>::size_type k = 0; k < rArr.size(); ++k )
268 {
269 if ( k != i && ::lcl_IsAnLower( pUpLine, rArr[k] ) )
270 {
271 rArr.erase( rArr.begin() + k );
272 if ( k <= i )
273 --i;
274 --k;
275 }
276 }
277 }
278}
279
280static void lcl_ProcessRowAttr(std::vector<std::unique_ptr<SwTableFormatCmp>>& rFormatCmp,
281 SwTableLine* pLine, const SfxPoolItem& rNew)
282{
283 SwFrameFormat *pNewFormat = SwTableFormatCmp::FindNewFormat( rFormatCmp, pLine->GetFrameFormat(), 0 );
284 if ( nullptr != pNewFormat )
285 pLine->ChgFrameFormat( static_cast<SwTableLineFormat*>(pNewFormat) );
286 else
287 {
288 SwFrameFormat *pOld = pLine->GetFrameFormat();
289 SwFrameFormat *pNew = pLine->ClaimFrameFormat();
290 pNew->SetFormatAttr( rNew );
291 rFormatCmp.push_back(std::make_unique<SwTableFormatCmp>(pOld, pNew, 0));
292 }
293}
294
295static void lcl_ProcessBoxSize(std::vector<std::unique_ptr<SwTableFormatCmp>>& rFormatCmp,
296 SwTableBox* pBox, const SwFormatFrameSize& rNew);
297
298static void lcl_ProcessRowSize(std::vector<std::unique_ptr<SwTableFormatCmp>>& rFormatCmp,
299 SwTableLine* pLine, const SwFormatFrameSize& rNew)
300{
301 lcl_ProcessRowAttr( rFormatCmp, pLine, rNew );
302 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
303 for ( auto pBox : rBoxes )
304 ::lcl_ProcessBoxSize( rFormatCmp, pBox, rNew );
305}
306
307static void lcl_ProcessBoxSize(std::vector<std::unique_ptr<SwTableFormatCmp>>& rFormatCmp,
308 SwTableBox* pBox, const SwFormatFrameSize& rNew)
309{
310 SwTableLines &rLines = pBox->GetTabLines();
311 if ( !rLines.empty() )
312 {
313 SwFormatFrameSize aSz( rNew );
314 aSz.SetHeight( rNew.GetHeight() ? rNew.GetHeight() / rLines.size() : 0 );
315 for ( auto pLine : rLines )
316 ::lcl_ProcessRowSize( rFormatCmp, pLine, aSz );
317 }
318}
319
320void SwDoc::SetRowSplit( const SwCursor& rCursor, const SwFormatRowSplit &rNew )
321{
322 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
323 if( !pTableNd )
324 return;
325
326 std::vector<SwTableLine*> aRowArr; // For Lines collecting
327 ::lcl_CollectLines( aRowArr, rCursor, false );
328
329 if( aRowArr.empty() )
330 return;
331
332 if (GetIDocumentUndoRedo().DoesUndo())
333 {
334 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
335 }
336
337 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
338 aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
339
340 for( auto pLn : aRowArr )
341 ::lcl_ProcessRowAttr( aFormatCmp, pLn, rNew );
342
343 getIDocumentState().SetModified();
344}
345
346std::unique_ptr<SwFormatRowSplit> SwDoc::GetRowSplit( const SwCursor& rCursor )
347{
348 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
349 if( !pTableNd )
350 return nullptr;
351
352 std::vector<SwTableLine*> aRowArr; // For Lines collecting
353 ::lcl_CollectLines( aRowArr, rCursor, false );
354
355 if( aRowArr.empty() )
356 return nullptr;
357
358 SwFormatRowSplit* pSz = &const_cast<SwFormatRowSplit&>(aRowArr[0]->GetFrameFormat()->GetRowSplit());
359
360 for ( auto pLn : aRowArr )
361 {
362 if ( pSz->GetValue() != pLn->GetFrameFormat()->GetRowSplit().GetValue() )
363 {
364 return nullptr;
365 }
366 }
367 return std::make_unique<SwFormatRowSplit>( *pSz );
368}
369
370/* Class: SwDoc
371 * Methods: SetRowHeight(), GetRowHeight()
372 *
373 * The line height is calculated from the Selection.
374 * Starting with every Cell within the Selection, all Cells are iterated
375 * through in an upwards fashion.
376 *
377 * The topmost Line gets the requested value, all Lines below it get
378 * a respective value that is calculated from the relation of the old and
379 * new size of the topmost Line in the lower line's own size.
380 *
381 * All changed Lines may get an own FrameFormat.
382 * Of course we can only touch every Line once.
383 */
384
385void SwDoc::SetRowHeight( const SwCursor& rCursor, const SwFormatFrameSize &rNew )
386{
387 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
388 if( !pTableNd )
389 return;
390
391 std::vector<SwTableLine*> aRowArr; // For Lines collecting
392 ::lcl_CollectLines( aRowArr, rCursor, true );
393
394 if( aRowArr.empty() )
395 return;
396
397 if (GetIDocumentUndoRedo().DoesUndo())
398 {
399 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
400 }
401
402 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
403 aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
404 for ( auto pLn : aRowArr )
405 ::lcl_ProcessRowSize( aFormatCmp, pLn, rNew );
406
407 getIDocumentState().SetModified();
408}
409
410std::unique_ptr<SwFormatFrameSize> SwDoc::GetRowHeight( const SwCursor& rCursor )
411{
412 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
413 if( !pTableNd )
414 return nullptr;
415
416 std::vector<SwTableLine*> aRowArr; // For Lines collecting
417 ::lcl_CollectLines( aRowArr, rCursor, true );
418
419 if( aRowArr.empty() )
420 return nullptr;
421
422 SwFormatFrameSize* pSz = &const_cast<SwFormatFrameSize&>(aRowArr[0]->GetFrameFormat()->GetFrameSize());
423
424 for ( auto pLn : aRowArr )
425 {
426 if ( *pSz != pLn->GetFrameFormat()->GetFrameSize() )
427 return nullptr;
428 }
429 return std::make_unique<SwFormatFrameSize>( *pSz );
430}
431
432bool SwDoc::BalanceRowHeight( const SwCursor& rCursor, bool bTstOnly, const bool bOptimize )
433{
434 bool bRet = false;
435 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
436 if( pTableNd )
437 {
438 std::vector<SwTableLine*> aRowArr; // For Lines collecting
439 ::lcl_CollectLines( aRowArr, rCursor, true );
440
441 if( 1 < aRowArr.size() )
442 {
443 if( !bTstOnly )
444 {
445 long nHeight = 0;
446 sal_Int32 nTotalHeight = 0;
447 for ( auto pLn : aRowArr )
448 {
449 SwIterator<SwFrame,SwFormat> aIter( *pLn->GetFrameFormat() );
450 SwFrame* pFrame = aIter.First();
451 while ( pFrame )
452 {
453 nHeight = std::max( nHeight, pFrame->getFrameArea().Height() );
454 pFrame = aIter.Next();
455 }
456 nTotalHeight += nHeight;
457 }
458
459 if ( bOptimize )
460 nHeight = nTotalHeight / aRowArr.size();
461
462 SwFormatFrameSize aNew( SwFrameSize::Minimum, 0, nHeight );
463
464 if (GetIDocumentUndoRedo().DoesUndo())
465 {
466 GetIDocumentUndoRedo().AppendUndo(
467 std::make_unique<SwUndoAttrTable>(*pTableNd));
468 }
469
470 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
471 aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
472 for( auto pLn : aRowArr )
473 ::lcl_ProcessRowSize( aFormatCmp, pLn, aNew );
474
475 getIDocumentState().SetModified();
476 }
477 bRet = true;
478 }
479 }
480 return bRet;
481}
482
483void SwDoc::SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew )
484{
485 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
486 if( !pTableNd )
487 return;
488
489 std::vector<SwTableLine*> aRowArr; // For Lines collecting
490 ::lcl_CollectLines( aRowArr, rCursor, true );
491
492 if( aRowArr.empty() )
493 return;
494
495 if (GetIDocumentUndoRedo().DoesUndo())
496 {
497 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
498 }
499
500 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
501 aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) );
502
503 for( auto pLn : aRowArr )
504 ::lcl_ProcessRowAttr( aFormatCmp, pLn, rNew );
505
506 getIDocumentState().SetModified();
507}
508
509bool SwDoc::GetRowBackground( const SwCursor& rCursor, std::unique_ptr<SvxBrushItem>& rToFill )
510{
511 bool bRet = false;
512 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
513 if( pTableNd )
514 {
515 std::vector<SwTableLine*> aRowArr; // For Lines collecting
516 ::lcl_CollectLines( aRowArr, rCursor, true );
517
518 if( !aRowArr.empty() )
519 {
520 rToFill = aRowArr[0]->GetFrameFormat()->makeBackgroundBrushItem();
521
522 bRet = true;
523 for ( std::vector<SwTableLine*>::size_type i = 1; i < aRowArr.size(); ++i )
524 {
525 std::unique_ptr<SvxBrushItem> aAlternative(aRowArr[i]->GetFrameFormat()->makeBackgroundBrushItem());
526
527 if ( rToFill && aAlternative && *rToFill != *aAlternative )
528 {
529 bRet = false;
530 break;
531 }
532 }
533 }
534 }
535 return bRet;
536}
537
538static void InsertCell( std::vector<SwCellFrame*>& rCellArr, SwCellFrame* pCellFrame )
539{
540 if( rCellArr.end() == std::find( rCellArr.begin(), rCellArr.end(), pCellFrame ) )
541 rCellArr.push_back( pCellFrame );
542}
543
544static void lcl_CollectCells( std::vector<SwCellFrame*> &rArr, const SwRect &rUnion,
545 SwTabFrame *pTab )
546{
547 SwLayoutFrame *pCell = pTab->FirstCell();
548 do
549 {
550 // If the Cell contains a CellFrame, we need to use it
551 // in order to get to the Cell
552 while ( !pCell->IsCellFrame() )
553 pCell = pCell->GetUpper();
554 OSL_ENSURE( pCell, "Frame is not a Cell" )do { if (true && (!(pCell))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl1.cxx"
":" "554" ": "), "%s", "Frame is not a Cell"); } } while (false
)
;
555 if ( rUnion.IsOver( pCell->getFrameArea() ) )
556 ::InsertCell( rArr, static_cast<SwCellFrame*>(pCell) );
557
558 // Make sure the Cell is left (Areas)
559 SwLayoutFrame *pTmp = pCell;
560 do
561 { pTmp = pTmp->GetNextLayoutLeaf();
562 } while ( pCell->IsAnLower( pTmp ) );
563 pCell = pTmp;
564 } while( pCell && pTab->IsAnLower( pCell ) );
565}
566
567void SwDoc::SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet )
568{
569 SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
570 SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
571 if( !pTableNd )
572 return ;
573
574 SwLayoutFrame *pStart, *pEnd;
575 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
576
577 SwSelUnions aUnions;
578 ::MakeSelUnions( aUnions, pStart, pEnd );
579
580 if( aUnions.empty() )
581 return;
582
583 SwTable& rTable = pTableNd->GetTable();
584 if (GetIDocumentUndoRedo().DoesUndo())
585 {
586 GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoAttrTable>(*pTableNd) );
587 }
588
589 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
590 aFormatCmp.reserve( 255 );
591 const SvxBoxItem* pSetBox;
592 const SvxBoxInfoItem *pSetBoxInfo;
593
594 const SvxBorderLine* pLeft = nullptr;
595 const SvxBorderLine* pRight = nullptr;
596 const SvxBorderLine* pTop = nullptr;
597 const SvxBorderLine* pBottom = nullptr;
598 const SvxBorderLine* pHori = nullptr;
599 const SvxBorderLine* pVert = nullptr;
600 bool bHoriValid = true, bVertValid = true,
601 bTopValid = true, bBottomValid = true,
602 bLeftValid = true, bRightValid = true;
603
604 // The Flags in the BoxInfo Item decide whether a BorderLine is valid!
605 if( SfxItemState::SET == rSet.GetItemState( SID_ATTR_BORDER_INNERTypedWhichId<SvxBoxInfoItem>( 10000 + 23 ), false,
606 reinterpret_cast<const SfxPoolItem**>(&pSetBoxInfo)) )
607 {
608 pHori = pSetBoxInfo->GetHori();
609 pVert = pSetBoxInfo->GetVert();
610
611 bHoriValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::HORI);
612 bVertValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::VERT);
613
614 // Do we want to evaluate these?
615 bTopValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::TOP);
616 bBottomValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
617 bLeftValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::LEFT);
618 bRightValid = pSetBoxInfo->IsValid(SvxBoxInfoItemValidFlags::RIGHT);
619 }
620
621 if( SfxItemState::SET == rSet.GetItemState( RES_BOX, false,
622 reinterpret_cast<const SfxPoolItem**>(&pSetBox)) )
623 {
624 pLeft = pSetBox->GetLeft();
625 pRight = pSetBox->GetRight();
626 pTop = pSetBox->GetTop();
627 pBottom = pSetBox->GetBottom();
628 }
629 else
630 {
631 // Not set, thus not valid values
632 bTopValid = bBottomValid = bLeftValid = bRightValid = false;
633 pSetBox = nullptr;
634 }
635
636 bool bFirst = true;
637 for ( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
638 {
639 SwSelUnion *pUnion = &aUnions[i];
640 SwTabFrame *pTab = pUnion->GetTable();
641 const SwRect &rUnion = pUnion->GetUnion();
642 const bool bLast = (i == aUnions.size() - 1);
643
644 std::vector<SwCellFrame*> aCellArr;
645 aCellArr.reserve( 255 );
646 ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
647
648 // All Cell Borders that match the UnionRect or extend it are
649 // Outer Borders. All others are Inner Borders.
650
651 // New: The Outer Borders can, depending on whether it's a
652 // Start/Middle/Follow Table (for Selection via FollowTabs),
653 // also not be Outer Borders.
654 // Outer Borders are set on the left, right, at the top and at the bottom.
655 // Inner Borders are only set at the top and on the left.
656 for ( auto pCell : aCellArr )
657 {
658 const bool bVert = pTab->IsVertical();
659 const bool bRTL = pTab->IsRightToLeft();
660 bool bTopOver, bLeftOver, bRightOver, bBottomOver;
661 if ( bVert )
662 {
663 bTopOver = pCell->getFrameArea().Right() >= rUnion.Right();
664 bLeftOver = pCell->getFrameArea().Top() <= rUnion.Top();
665 bRightOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
666 bBottomOver = pCell->getFrameArea().Left() <= rUnion.Left();
667 }
668 else
669 {
670 bTopOver = pCell->getFrameArea().Top() <= rUnion.Top();
671 bLeftOver = pCell->getFrameArea().Left() <= rUnion.Left();
672 bRightOver = pCell->getFrameArea().Right() >= rUnion.Right();
673 bBottomOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
674 }
675
676 if ( bRTL )
677 {
678 bool bTmp = bRightOver;
679 bRightOver = bLeftOver;
680 bLeftOver = bTmp;
681 }
682
683 // Do not set anything by default in HeadlineRepeats
684 if ( pTab->IsFollow() &&
685 ( pTab->IsInHeadline( *pCell ) ||
686 // Same holds for follow flow rows
687 pCell->IsInFollowFlowRow() ) )
688 continue;
689
690 SvxBoxItem aBox( pCell->GetFormat()->GetBox() );
691
692 sal_Int16 nType = 0;
693
694 // Top Border
695 if( bTopValid )
696 {
697 if ( bFirst && bTopOver )
698 {
699 aBox.SetLine( pTop, SvxBoxItemLine::TOP );
700 nType |= 0x0001;
701 }
702 else if ( bHoriValid )
703 {
704 aBox.SetLine( nullptr, SvxBoxItemLine::TOP );
705 nType |= 0x0002;
706 }
707 }
708
709 // Fix fdo#62470 correct the input for RTL table
710 if (bRTL)
711 {
712 if( bLeftOver && bRightOver)
713 {
714 if ( bLeftValid )
715 {
716 aBox.SetLine( pLeft, SvxBoxItemLine::RIGHT );
717 nType |= 0x0010;
718 }
719 if ( bRightValid )
720 {
721 aBox.SetLine( pRight, SvxBoxItemLine::LEFT );
722 nType |= 0x0004;
723 }
724 }
725 else
726 {
727 if ( bLeftValid )
728 {
729 aBox.SetLine( bRightOver ? pLeft : nullptr, SvxBoxItemLine::RIGHT );
730 if (bVertValid)
731 nType |= 0x0020;
732 else
733 nType |= 0x0010;
734 }
735 if ( bLeftOver )
736 {
737 if ( bRightValid )
738 {
739 aBox.SetLine( pRight, SvxBoxItemLine::LEFT );
740 nType |= 0x0004;
741 }
742 }
743 else if ( bVertValid )
744 {
745 aBox.SetLine( pVert, SvxBoxItemLine::LEFT );
746 nType |= 0x0008;
747 }
748 }
749 }
750 else
751 {
752 // Left Border
753 if ( bLeftOver )
754 {
755 if( bLeftValid )
756 {
757 aBox.SetLine( pLeft, SvxBoxItemLine::LEFT );
758 nType |= 0x0004;
759 }
760 }
761 else if( bVertValid )
762 {
763 aBox.SetLine( pVert, SvxBoxItemLine::LEFT );
764 nType |= 0x0008;
765 }
766
767 // Right Border
768 if( bRightValid )
769 {
770 if ( bRightOver )
771 {
772 aBox.SetLine( pRight, SvxBoxItemLine::RIGHT );
773 nType |= 0x0010;
774 }
775 else if ( bVertValid )
776 {
777 aBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
778 nType |= 0x0020;
779 }
780 }
781 }
782
783 // Bottom Border
784 if ( bLast && bBottomOver )
785 {
786 if( bBottomValid )
787 {
788 aBox.SetLine( pBottom, SvxBoxItemLine::BOTTOM );
789 nType |= 0x0040;
790 }
791 }
792 else if( bHoriValid )
793 {
794 aBox.SetLine( pHori, SvxBoxItemLine::BOTTOM );
795 nType |= 0x0080;
796 }
797
798 if( pSetBox )
799 {
800 for( SvxBoxItemLine k : o3tl::enumrange<SvxBoxItemLine>() )
801 aBox.SetDistance( pSetBox->GetDistance( k ), k );
802 }
803
804 SwTableBox *pBox = const_cast<SwTableBox*>(pCell->GetTabBox());
805 SwFrameFormat *pNewFormat = SwTableFormatCmp::FindNewFormat( aFormatCmp, pBox->GetFrameFormat(), nType );
806 if ( nullptr != pNewFormat )
807 pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(pNewFormat) );
808 else
809 {
810 SwFrameFormat *pOld = pBox->GetFrameFormat();
811 SwFrameFormat *pNew = pBox->ClaimFrameFormat();
812 pNew->SetFormatAttr( aBox );
813 aFormatCmp.push_back(std::make_unique<SwTableFormatCmp>(pOld, pNew, nType));
814 }
815 }
816
817 bFirst = false;
818 }
819
820 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
821 if( pTableLayout )
822 {
823 SwContentFrame* pFrame = rCursor.GetContentNode()->getLayoutFrame( rCursor.GetContentNode()->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() );
824 SwTabFrame* pTabFrame = pFrame->ImplFindTabFrame();
825
826 pTableLayout->BordersChanged(
827 pTableLayout->GetBrowseWidthByTabFrame( *pTabFrame ) );
828 }
829 ::ClearFEShellTabCols(*this, nullptr);
830 getIDocumentState().SetModified();
831}
832
833static void lcl_SetLineStyle( SvxBorderLine *pToSet,
834 const Color *pColor, const SvxBorderLine *pBorderLine)
835{
836 if ( pBorderLine )
837 {
838 if ( !pColor )
839 {
840 Color aTmp( pToSet->GetColor() );
841 *pToSet = *pBorderLine;
842 pToSet->SetColor( aTmp );
843 }
844 else
845 *pToSet = *pBorderLine;
846 }
847 if ( pColor )
848 pToSet->SetColor( *pColor );
849}
850
851void SwDoc::SetTabLineStyle( const SwCursor& rCursor,
852 const Color* pColor, bool bSetLine,
853 const SvxBorderLine* pBorderLine )
854{
855 SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
856 SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
857 if( !pTableNd )
858 return ;
859
860 SwLayoutFrame *pStart, *pEnd;
861 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
862
863 SwSelUnions aUnions;
864 ::MakeSelUnions( aUnions, pStart, pEnd );
865
866 if( aUnions.empty() )
867 return;
868
869 SwTable& rTable = pTableNd->GetTable();
870 if (GetIDocumentUndoRedo().DoesUndo())
871 {
872 GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd));
873 }
874
875 for( auto &rU : aUnions )
876 {
877 SwSelUnion *pUnion = &rU;
878 SwTabFrame *pTab = pUnion->GetTable();
879 std::vector<SwCellFrame*> aCellArr;
880 aCellArr.reserve( 255 );
881 ::lcl_CollectCells( aCellArr, pUnion->GetUnion(), pTab );
882
883 for ( auto pCell : aCellArr )
884 {
885 // Do not set anything by default in HeadlineRepeats
886 if ( pTab->IsFollow() && pTab->IsInHeadline( *pCell ) )
887 continue;
888
889 const_cast<SwTableBox*>(pCell->GetTabBox())->ClaimFrameFormat();
890 SwFrameFormat *pFormat = pCell->GetFormat();
891 std::unique_ptr<SvxBoxItem> aBox(pFormat->GetBox().Clone());
892
893 if ( !pBorderLine && bSetLine )
894 {
895 aBox.reset(::GetDfltAttr(RES_BOX)->Clone());
896 }
897 else
898 {
899 if ( aBox->GetTop() )
900 ::lcl_SetLineStyle( const_cast<SvxBorderLine*>(aBox->GetTop()),
901 pColor, pBorderLine );
902 if ( aBox->GetBottom() )
903 ::lcl_SetLineStyle( const_cast<SvxBorderLine*>(aBox->GetBottom()),
904 pColor, pBorderLine );
905 if ( aBox->GetLeft() )
906 ::lcl_SetLineStyle( const_cast<SvxBorderLine*>(aBox->GetLeft()),
907 pColor, pBorderLine );
908 if ( aBox->GetRight() )
909 ::lcl_SetLineStyle( const_cast<SvxBorderLine*>(aBox->GetRight()),
910 pColor, pBorderLine );
911 }
912 pFormat->SetFormatAttr( *aBox );
913 }
914 }
915
916 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
917 if( pTableLayout )
918 {
919 SwContentFrame* pFrame = rCursor.GetContentNode()->getLayoutFrame( rCursor.GetContentNode()->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() );
920 SwTabFrame* pTabFrame = pFrame->ImplFindTabFrame();
921
922 pTableLayout->BordersChanged(
923 pTableLayout->GetBrowseWidthByTabFrame( *pTabFrame ) );
924 }
925 ::ClearFEShellTabCols(*this, nullptr);
926 getIDocumentState().SetModified();
927}
928
929void SwDoc::GetTabBorders( const SwCursor& rCursor, SfxItemSet& rSet )
930{
931 SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
932 SwTableNode* pTableNd = pCntNd ? pCntNd->FindTableNode() : nullptr;
933 if( !pTableNd )
934 return ;
935
936 SwLayoutFrame *pStart, *pEnd;
937 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
938
939 SwSelUnions aUnions;
940 ::MakeSelUnions( aUnions, pStart, pEnd );
941
942 if( aUnions.empty() )
943 return;
944
945 SvxBoxItem aSetBox ( rSet.Get(RES_BOX ) );
946 SvxBoxInfoItem aSetBoxInfo( rSet.Get(SID_ATTR_BORDER_INNERTypedWhichId<SvxBoxInfoItem>( 10000 + 23 )) );
947
948 bool bTopSet = false,
949 bBottomSet = false,
950 bLeftSet = false,
951 bRightSet = false,
952 bHoriSet = false,
953 bVertSet = false,
954 bDistanceSet = false,
955 bRTLTab = false;
956
957 aSetBoxInfo.ResetFlags();
958
959 for ( SwSelUnions::size_type i = 0; i < aUnions.size(); ++i )
960 {
961 SwSelUnion *pUnion = &aUnions[i];
962 const SwTabFrame *pTab = pUnion->GetTable();
963 const SwRect &rUnion = pUnion->GetUnion();
964 const bool bFirst = i == 0;
965 const bool bLast = (i == aUnions.size() - 1);
966
967 std::vector<SwCellFrame*> aCellArr;
968 aCellArr.reserve(255);
969 ::lcl_CollectCells( aCellArr, rUnion, const_cast<SwTabFrame*>(pTab) );
970
971 for ( auto pCell : aCellArr )
972 {
973 const bool bVert = pTab->IsVertical();
974 const bool bRTL = bRTLTab = pTab->IsRightToLeft();
975 bool bTopOver, bLeftOver, bRightOver, bBottomOver;
976 if ( bVert )
977 {
978 bTopOver = pCell->getFrameArea().Right() >= rUnion.Right();
979 bLeftOver = pCell->getFrameArea().Top() <= rUnion.Top();
980 bRightOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
981 bBottomOver = pCell->getFrameArea().Left() <= rUnion.Left();
982 }
983 else
984 {
985 bTopOver = pCell->getFrameArea().Top() <= rUnion.Top();
986 bLeftOver = pCell->getFrameArea().Left() <= rUnion.Left();
987 bRightOver = pCell->getFrameArea().Right() >= rUnion.Right();
988 bBottomOver = pCell->getFrameArea().Bottom() >= rUnion.Bottom();
989 }
990
991 if ( bRTL )
992 {
993 bool bTmp = bRightOver;
994 bRightOver = bLeftOver;
995 bLeftOver = bTmp;
996 }
997
998 const SwFrameFormat *pFormat = pCell->GetFormat();
999 const SvxBoxItem &rBox = pFormat->GetBox();
1000
1001 // Top Border
1002 if ( bFirst && bTopOver )
1003 {
1004 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::TOP))
1005 {
1006 if ( !bTopSet )
1007 { bTopSet = true;
1008 aSetBox.SetLine( rBox.GetTop(), SvxBoxItemLine::TOP );
1009 }
1010 else if ((aSetBox.GetTop() && rBox.GetTop() &&
1011 (*aSetBox.GetTop() != *rBox.GetTop())) ||
1012 ((!aSetBox.GetTop()) != (!rBox.GetTop()))) // != expression is true, if one and only one of the two pointers is !0
1013 {
1014 aSetBoxInfo.SetValid(SvxBoxInfoItemValidFlags::TOP, false );
1015 aSetBox.SetLine( nullptr, SvxBoxItemLine::TOP );
1016 }
1017 }
1018 }
1019
1020 // Left Border
1021 if ( bLeftOver )
1022 {
1023 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::LEFT))
1024 {
1025 if ( !bLeftSet )
1026 { bLeftSet = true;
1027 aSetBox.SetLine( rBox.GetLeft(), SvxBoxItemLine::LEFT );
1028 }
1029 else if ((aSetBox.GetLeft() && rBox.GetLeft() &&
1030 (*aSetBox.GetLeft() != *rBox.GetLeft())) ||
1031 ((!aSetBox.GetLeft()) != (!rBox.GetLeft())))
1032 {
1033 aSetBoxInfo.SetValid(SvxBoxInfoItemValidFlags::LEFT, false );
1034 aSetBox.SetLine( nullptr, SvxBoxItemLine::LEFT );
1035 }
1036 }
1037 }
1038 else
1039 {
1040 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::VERT))
1041 {
1042 if ( !bVertSet )
1043 { bVertSet = true;
1044 aSetBoxInfo.SetLine( rBox.GetLeft(), SvxBoxInfoItemLine::VERT );
1045 }
1046 else if ((aSetBoxInfo.GetVert() && rBox.GetLeft() &&
1047 (*aSetBoxInfo.GetVert() != *rBox.GetLeft())) ||
1048 ((!aSetBoxInfo.GetVert()) != (!rBox.GetLeft())))
1049 { aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::VERT, false );
1050 aSetBoxInfo.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
1051 }
1052 }
1053 }
1054
1055 // Right Border
1056 if ( aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::RIGHT) && bRightOver )
1057 {
1058 if ( !bRightSet )
1059 { bRightSet = true;
1060 aSetBox.SetLine( rBox.GetRight(), SvxBoxItemLine::RIGHT );
1061 }
1062 else if ((aSetBox.GetRight() && rBox.GetRight() &&
1063 (*aSetBox.GetRight() != *rBox.GetRight())) ||
1064 (!aSetBox.GetRight() != !rBox.GetRight()))
1065 { aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::RIGHT, false );
1066 aSetBox.SetLine( nullptr, SvxBoxItemLine::RIGHT );
1067 }
1068 }
1069
1070 // Bottom Border
1071 if ( bLast && bBottomOver )
1072 {
1073 if ( aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::BOTTOM) )
1074 {
1075 if ( !bBottomSet )
1076 { bBottomSet = true;
1077 aSetBox.SetLine( rBox.GetBottom(), SvxBoxItemLine::BOTTOM );
1078 }
1079 else if ((aSetBox.GetBottom() && rBox.GetBottom() &&
1080 (*aSetBox.GetBottom() != *rBox.GetBottom())) ||
1081 (!aSetBox.GetBottom() != !rBox.GetBottom()))
1082 { aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, false );
1083 aSetBox.SetLine( nullptr, SvxBoxItemLine::BOTTOM );
1084 }
1085 }
1086 }
1087 // In all Lines, except for the last one, the horizontal Line
1088 // is taken from the Bottom Line.
1089 else
1090 {
1091 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::HORI))
1092 {
1093 if ( !bHoriSet )
1094 { bHoriSet = true;
1095 aSetBoxInfo.SetLine( rBox.GetBottom(), SvxBoxInfoItemLine::HORI );
1096 }
1097 else if ((aSetBoxInfo.GetHori() && rBox.GetBottom() &&
1098 (*aSetBoxInfo.GetHori() != *rBox.GetBottom())) ||
1099 ((!aSetBoxInfo.GetHori()) != (!rBox.GetBottom())))
1100 {
1101 aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::HORI, false );
1102 aSetBoxInfo.SetLine( nullptr, SvxBoxInfoItemLine::HORI );
1103 }
1104 }
1105 }
1106
1107 // Distance to text
1108 if (aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::DISTANCE))
1109 {
1110 if( !bDistanceSet ) // Set on first iteration
1111 {
1112 bDistanceSet = true;
1113 for( SvxBoxItemLine k : o3tl::enumrange<SvxBoxItemLine>() )
1114 aSetBox.SetDistance( rBox.GetDistance( k ), k );
1115 }
1116 else
1117 {
1118 for( SvxBoxItemLine k : o3tl::enumrange<SvxBoxItemLine>() )
1119 if( aSetBox.GetDistance( k ) !=
1120 rBox.GetDistance( k ) )
1121 {
1122 aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::DISTANCE, false );
1123 aSetBox.SetAllDistances(0);
1124 break;
1125 }
1126 }
1127 }
1128 }
1129 }
1130
1131 // fdo#62470 fix the reading for table format.
1132 if ( bRTLTab )
1133 {
1134 SvxBoxItem aTempBox ( rSet.Get(RES_BOX ) );
1135 SvxBoxInfoItem aTempBoxInfo( rSet.Get(SID_ATTR_BORDER_INNERTypedWhichId<SvxBoxInfoItem>( 10000 + 23 )) );
1136
1137 aTempBox.SetLine( aSetBox.GetRight(), SvxBoxItemLine::RIGHT);
1138 aSetBox.SetLine( aSetBox.GetLeft(), SvxBoxItemLine::RIGHT);
1139 aSetBox.SetLine( aTempBox.GetRight(), SvxBoxItemLine::LEFT);
1140
1141 aTempBoxInfo.SetValid( SvxBoxInfoItemValidFlags::LEFT, aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::LEFT) );
1142 aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::LEFT, aSetBoxInfo.IsValid(SvxBoxInfoItemValidFlags::RIGHT) );
1143 aSetBoxInfo.SetValid( SvxBoxInfoItemValidFlags::RIGHT, aTempBoxInfo.IsValid(SvxBoxInfoItemValidFlags::LEFT) );
1144 }
1145
1146 rSet.Put( aSetBox );
1147 rSet.Put( aSetBoxInfo );
1148}
1149
1150void SwDoc::SetBoxAttr( const SwCursor& rCursor, const SfxPoolItem &rNew )
1151{
1152 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1153 SwSelBoxes aBoxes;
1154 if( !(pTableNd && ::lcl_GetBoxSel( rCursor, aBoxes, true )) )
1155 return;
1156
1157 SwTable& rTable = pTableNd->GetTable();
1158 if (GetIDocumentUndoRedo().DoesUndo())
1159 {
1160 GetIDocumentUndoRedo().AppendUndo( std::make_unique<SwUndoAttrTable>(*pTableNd) );
1161 }
1162
1163 std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp;
1164 aFormatCmp.reserve(std::max<size_t>(255, aBoxes.size()));
1165 for (size_t i = 0; i < aBoxes.size(); ++i)
1166 {
1167 SwTableBox *pBox = aBoxes[i];
1168
1169 SwFrameFormat *pNewFormat = SwTableFormatCmp::FindNewFormat( aFormatCmp, pBox->GetFrameFormat(), 0 );
1170 if ( nullptr != pNewFormat )
1171 pBox->ChgFrameFormat( static_cast<SwTableBoxFormat*>(pNewFormat) );
1172 else
1173 {
1174 SwFrameFormat *pOld = pBox->GetFrameFormat();
1175 SwFrameFormat *pNew = pBox->ClaimFrameFormat();
1176 pNew->SetFormatAttr( rNew );
1177 aFormatCmp.push_back(std::make_unique<SwTableFormatCmp>(pOld, pNew, 0));
1178 }
1179
1180 pBox->SetDirectFormatting(true);
1181 }
1182
1183 SwHTMLTableLayout *pTableLayout = rTable.GetHTMLTableLayout();
1184 if( pTableLayout )
1185 {
1186 SwContentFrame* pFrame = rCursor.GetContentNode()->getLayoutFrame( rCursor.GetContentNode()->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() );
1187 SwTabFrame* pTabFrame = pFrame->ImplFindTabFrame();
1188
1189 pTableLayout->Resize(
1190 pTableLayout->GetBrowseWidthByTabFrame( *pTabFrame ), true );
1191 }
1192 getIDocumentState().SetModified();
1193}
1194
1195bool SwDoc::GetBoxAttr( const SwCursor& rCursor, std::unique_ptr<SfxPoolItem>& rToFill )
1196{
1197 bool bRet = false;
1198 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1199 SwSelBoxes aBoxes;
1200 if( pTableNd && lcl_GetBoxSel( rCursor, aBoxes ))
1201 {
1202 bRet = true;
1203 bool bOneFound = false;
1204 const sal_uInt16 nWhich = rToFill->Which();
1205 for (size_t i = 0; i < aBoxes.size(); ++i)
1206 {
1207 switch ( nWhich )
1208 {
1209 case RES_BACKGROUND:
1210 {
1211 std::unique_ptr<SvxBrushItem> xBack =
1212 aBoxes[i]->GetFrameFormat()->makeBackgroundBrushItem();
1213 if( !bOneFound )
1214 {
1215 rToFill = std::move(xBack);
1216 bOneFound = true;
1217 }
1218 else if( *rToFill != *xBack )
1219 bRet = false;
1220 }
1221 break;
1222
1223 case RES_FRAMEDIR:
1224 {
1225 const SvxFrameDirectionItem& rDir =
1226 aBoxes[i]->GetFrameFormat()->GetFrameDir();
1227 if( !bOneFound )
1228 {
1229 rToFill.reset(rDir.Clone());
1230 bOneFound = true;
1231 }
1232 else if( rToFill && *rToFill != rDir )
1233 bRet = false;
1234 }
1235 break;
1236 case RES_VERT_ORIENT:
1237 {
1238 const SwFormatVertOrient& rOrient =
1239 aBoxes[i]->GetFrameFormat()->GetVertOrient();
1240 if( !bOneFound )
1241 {
1242 rToFill.reset(rOrient.Clone());
1243 bOneFound = true;
1244 }
1245 else if( rToFill && *rToFill != rOrient )
1246 bRet = false;
1247 }
1248 break;
1249 }
1250
1251 if ( !bRet )
1252 break;
1253 }
1254 }
1255 return bRet;
1256}
1257
1258void SwDoc::SetBoxAlign( const SwCursor& rCursor, sal_uInt16 nAlign )
1259{
1260 OSL_ENSURE( nAlign == text::VertOrientation::NONE ||do { if (true && (!(nAlign == text::VertOrientation::
NONE || nAlign == text::VertOrientation::CENTER || nAlign == text
::VertOrientation::BOTTOM))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl1.cxx"
":" "1262" ": "), "%s", "Wrong alignment"); } } while (false
)
1261 nAlign == text::VertOrientation::CENTER ||do { if (true && (!(nAlign == text::VertOrientation::
NONE || nAlign == text::VertOrientation::CENTER || nAlign == text
::VertOrientation::BOTTOM))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl1.cxx"
":" "1262" ": "), "%s", "Wrong alignment"); } } while (false
)
1262 nAlign == text::VertOrientation::BOTTOM, "Wrong alignment" )do { if (true && (!(nAlign == text::VertOrientation::
NONE || nAlign == text::VertOrientation::CENTER || nAlign == text
::VertOrientation::BOTTOM))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/docnode/ndtbl1.cxx"
":" "1262" ": "), "%s", "Wrong alignment"); } } while (false
)
;
1263 SwFormatVertOrient aVertOri( 0, nAlign );
1264 SetBoxAttr( rCursor, aVertOri );
1265}
1266
1267sal_uInt16 SwDoc::GetBoxAlign( const SwCursor& rCursor )
1268{
1269 sal_uInt16 nAlign = USHRT_MAX(32767 *2 +1);
1270 SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode();
1271 SwSelBoxes aBoxes;
1272 if( pTableNd && ::lcl_GetBoxSel( rCursor, aBoxes ))
1273 {
1274 for (size_t i = 0; i < aBoxes.size(); ++i)
1275 {
1276 const SwFormatVertOrient &rOri =
1277 aBoxes[i]->GetFrameFormat()->GetVertOrient();
1278 if( USHRT_MAX(32767 *2 +1) == nAlign )
1279 nAlign = static_cast<sal_uInt16>(rOri.GetVertOrient());
1280 else if( rOri.GetVertOrient() != nAlign )
1281 {
1282 nAlign = USHRT_MAX(32767 *2 +1);
1283 break;
1284 }
1285 }
1286 }
1287 return nAlign;
1288}
1289
1290static sal_uInt16 lcl_CalcCellFit( const SwLayoutFrame *pCell )
1291{
1292 SwTwips nRet = 0;
1293 const SwFrame *pFrame = pCell->Lower(); // The whole Line
1294 SwRectFnSet aRectFnSet(pCell);
1295 while ( pFrame )
1296 {
1297 const SwTwips nAdd = aRectFnSet.GetWidth(pFrame->getFrameArea()) -
1298 aRectFnSet.GetWidth(pFrame->getFramePrintArea());
1299
1300 // pFrame does not necessarily have to be a SwTextFrame!
1301 const SwTwips nCalcFitToContent = pFrame->IsTextFrame() ?
1302 const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pFrame))->CalcFitToContent() :
1303 aRectFnSet.GetWidth(pFrame->getFramePrintArea());
1304
1305 nRet = std::max( nRet, nCalcFitToContent + nAdd );
1306 pFrame = pFrame->GetNext();
1307 }
1308 // Surrounding border as well as left and Right Border also need to be respected
1309 nRet += aRectFnSet.GetWidth(pCell->getFrameArea()) -
1310 aRectFnSet.GetWidth(pCell->getFramePrintArea());
1311
1312 // To compensate for the accuracy of calculation later on in SwTable::SetTabCols
1313 // we keep adding up a little.
1314 nRet += COLFUZZY20L;
1315 return static_cast<sal_uInt16>(std::max( long(MINLAY23), nRet ));
1316}
1317
1318/* The Line is within the Selection but not outlined by the TabCols.
1319 *
1320 * That means that the Line has been "split" by other Cells due to the
1321 * two-dimensional representation used. Thus, we have to distribute the cell's
1322 * default or minimum value amongst the Cell it has been split by.
1323 *
1324 * First, we collect the Columns (not the Column separators) which overlap
1325 * with the Cell. We then distribute the desired value according to the
1326 * amount of overlapping amongst the Cells.
1327 *
1328 * A Cell's default value stays the same if it already has a larger value than
1329 * the desired one. It's overwritten if it's smaller.
1330 */
1331static void lcl_CalcSubColValues( std::vector<sal_uInt16> &rToFill, const SwTabCols &rCols,
1332 const SwLayoutFrame *pCell, const SwLayoutFrame *pTab,
1333 bool bWishValues )
1334{
1335 const sal_uInt16 nWish = bWishValues ?
1336 ::lcl_CalcCellFit( pCell ) :
1337 MINLAY23 + sal_uInt16(pCell->getFrameArea().Width() - pCell->getFramePrintArea().Width());
1338
1339 SwRectFnSet aRectFnSet(pTab);
1340
1341 for ( size_t i = 0 ; i <= rCols.Count(); ++i )
1342 {
1343 long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1];
1344 long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1345 nColLeft += rCols.GetLeftMin();
1346 nColRight += rCols.GetLeftMin();
1347
1348 // Adapt values to the proportions of the Table (Follows)
1349 if ( rCols.GetLeftMin() != aRectFnSet.GetLeft(pTab->getFrameArea()) )
1350 {
1351 const long nDiff = aRectFnSet.GetLeft(pTab->getFrameArea()) - rCols.GetLeftMin();
1352 nColLeft += nDiff;
1353 nColRight += nDiff;
1354 }
1355 const long nCellLeft = aRectFnSet.GetLeft(pCell->getFrameArea());
1356 const long nCellRight = aRectFnSet.GetRight(pCell->getFrameArea());
1357
1358 // Calculate overlapping value
1359 long nWidth = 0;
1360 if ( nColLeft <= nCellLeft && nColRight >= (nCellLeft+COLFUZZY20L) )
1361 nWidth = nColRight - nCellLeft;
1362 else if ( nColLeft <= (nCellRight-COLFUZZY20L) && nColRight >= nCellRight )
1363 nWidth = nCellRight - nColLeft;
1364 else if ( nColLeft >= nCellLeft && nColRight <= nCellRight )
1365 nWidth = nColRight - nColLeft;
1366 if ( nWidth && pCell->getFrameArea().Width() )
1367 {
1368 long nTmp = nWidth * nWish / pCell->getFrameArea().Width();
1369 if ( o3tl::make_unsigned(nTmp) > rToFill[i] )
1370 rToFill[i] = sal_uInt16(nTmp);
1371 }
1372 }
1373}
1374
1375/**
1376 * Retrieves new values to set the TabCols.
1377 *
1378 * We do not iterate over the TabCols' entries, but over the gaps that describe Cells.
1379 * We set TabCol entries for which we did not calculate Cells to 0.
1380 *
1381 * @param bWishValues == true: We calculate the desired value of all affected
1382 * Cells for the current Selection/current Cell.
1383 * If more Cells are within a Column, the highest
1384 * desired value is returned.
1385 * We set TabCol entries for which we did not calculate
1386 * Cells to 0.
1387 *
1388 * @param bWishValues == false: The Selection is expanded vertically.
1389 * We calculate the minimum value for every
1390 * Column in the TabCols that intersects with the
1391 * Selection.
1392 */
1393static void lcl_CalcColValues( std::vector<sal_uInt16> &rToFill, const SwTabCols &rCols,
1394 const SwLayoutFrame *pStart, const SwLayoutFrame *pEnd,
1395 bool bWishValues )
1396{
1397 SwSelUnions aUnions;
1398 ::MakeSelUnions( aUnions, pStart, pEnd,
1399 bWishValues ? SwTableSearchType::NONE : SwTableSearchType::Col );
1400
1401 for ( auto &rU : aUnions )
1402 {
1403 SwSelUnion *pSelUnion = &rU;
1404 const SwTabFrame *pTab = pSelUnion->GetTable();
1405 const SwRect &rUnion = pSelUnion->GetUnion();
1406
1407 SwRectFnSet aRectFnSet(pTab);
1408 bool bRTL = pTab->IsRightToLeft();
1409
1410 const SwLayoutFrame *pCell = pTab->FirstCell();
1411 if (!pCell)
1412 continue;
1413 do
1414 {
1415 if ( pCell->IsCellFrame() && pCell->FindTabFrame() == pTab && ::IsFrameInTableSel( rUnion, pCell ) )
1416 {
1417 const long nCLeft = aRectFnSet.GetLeft(pCell->getFrameArea());
1418 const long nCRight = aRectFnSet.GetRight(pCell->getFrameArea());
1419
1420 bool bNotInCols = true;
1421
1422 for ( size_t i = 0; i <= rCols.Count(); ++i )
1423 {
1424 sal_uInt16 nFit = rToFill[i];
1425 long nColLeft = i == 0 ? rCols.GetLeft() : rCols[i-1];
1426 long nColRight = i == rCols.Count() ? rCols.GetRight() : rCols[i];
1427
1428 if ( bRTL )
1429 {
1430 long nTmpRight = nColRight;
1431 nColRight = rCols.GetRight() - nColLeft;
1432 nColLeft = rCols.GetRight() - nTmpRight;
1433 }
1434
1435 nColLeft += rCols.GetLeftMin();
1436 nColRight += rCols.GetLeftMin();
1437
1438 // Adapt values to the proportions of the Table (Follows)
1439 long nLeftA = nColLeft;
1440 long nRightA = nColRight;
1441 if ( rCols.GetLeftMin() != sal_uInt16(aRectFnSet.GetLeft(pTab->getFrameArea())) )
1442 {
1443 const long nDiff = aRectFnSet.GetLeft(pTab->getFrameArea()) - rCols.GetLeftMin();
1444 nLeftA += nDiff;
1445 nRightA += nDiff;
1446 }
1447
1448 // We don't want to take a too close look
1449 if ( ::IsSame(nCLeft, nLeftA) && ::IsSame(nCRight, nRightA))
1450 {
1451 bNotInCols = false;
1452 if ( bWishValues )
1453 {
1454 const sal_uInt16 nWish = ::lcl_CalcCellFit( pCell );
1455 if ( nWish > nFit )
1456 nFit = nWish;
1457 }
1458 else
1459 { const sal_uInt16 nMin = MINLAY23 + sal_uInt16(pCell->getFrameArea().Width() -
1460 pCell->getFramePrintArea().Width());
1461 if ( !nFit || nMin < nFit )
1462 nFit = nMin;
1463 }
1464 if ( rToFill[i] < nFit )
1465 rToFill[i] = nFit;
1466 }
1467 }
1468 if ( bNotInCols )
1469 ::lcl_CalcSubColValues( rToFill, rCols, pCell, pTab, bWishValues );
1470 }
1471 do {
1472 pCell = pCell->GetNextLayoutLeaf();
1473 } while( pCell && pCell->getFrameArea().Width() == 0 );
1474 } while ( pCell && pTab->IsAnLower( pCell ) );
1475 }
1476}
1477
1478void SwDoc::AdjustCellWidth( const SwCursor& rCursor,
1479 const bool bBalance,
1480 const bool bNoShrink )
1481{
1482 // Check whether the current Cursor has it's Point/Mark in a Table
1483 SwContentNode* pCntNd = rCursor.GetPoint()->nNode.GetNode().GetContentNode();
1484 SwTableNode* pTableNd = pCntNd
0.1
'pCntNd' is non-null
? pCntNd->FindTableNode() : nullptr;
1
'?' condition is true
1485 if( !pTableNd )
2
Assuming 'pTableNd' is non-null
3
Taking false branch
1486 return ;
1487
1488 SwLayoutFrame *pStart, *pEnd;
1489 ::lcl_GetStartEndCell( rCursor, pStart, pEnd );
4
Calling 'lcl_GetStartEndCell'
14
Returning from 'lcl_GetStartEndCell'
1490
1491 // Collect TabCols; we reset the Table with them
1492 SwFrame* pBoxFrame = pStart;
1493 while( pBoxFrame && !pBoxFrame->IsCellFrame() )
15
Assuming 'pBoxFrame' is non-null
16
Loop condition is false. Execution continues on line 1496
1494 pBoxFrame = pBoxFrame->GetUpper();
1495
1496 if ( !pBoxFrame
16.1
'pBoxFrame' is non-null
)
17
Taking false branch
1497 return; // Robust
1498
1499 SwTabCols aTabCols;
1500 GetTabCols( aTabCols, static_cast<SwCellFrame*>(pBoxFrame) );
1501
1502 if ( ! aTabCols.Count() )
18
Assuming the condition is false
19
Taking false branch
1503 return;
1504
1505 std::vector<sal_uInt16> aWish(aTabCols.Count() + 1);
1506 std::vector<sal_uInt16> aMins(aTabCols.Count() + 1);
1507
1508 ::lcl_CalcColValues( aWish, aTabCols, pStart, pEnd, /*bWishValues=*/true );
1509
1510 // It's more robust if we calculate the minimum values for the whole Table
1511 const SwTabFrame *pTab = pStart->ImplFindTabFrame();
1512 pStart = const_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame const *>(pTab->FirstCell()));
1513 pEnd = const_cast<SwLayoutFrame*>(pTab->FindLastContentOrTable()->GetUpper());
1514 while( !pEnd->IsCellFrame() )
20
Loop condition is false. Execution continues on line 1516
1515 pEnd = pEnd->GetUpper();
1516 ::lcl_CalcColValues( aMins, aTabCols, pStart, pEnd, /*bWishValues=*/false );
1517
1518 sal_uInt16 nSelectedWidth = 0, nCols = 0;
21
'nCols' initialized to 0
1519 float fTotalWish = 0;
1520 if ( bBalance || bNoShrink )
22
Assuming 'bBalance' is true
1521 {
1522 // Find the combined size of the selected columns
1523 for ( size_t i = 0; i <= aTabCols.Count(); ++i )
23
Loop condition is true. Entering loop body
26
Assuming the condition is false
27
Loop condition is false. Execution continues on line 1537
1524 {
1525 if ( aWish[i] )
24
Assuming the condition is false
25
Taking false branch
1526 {
1527 if ( i == 0 )
1528 nSelectedWidth += aTabCols[i] - aTabCols.GetLeft();
1529 else if ( i == aTabCols.Count() )
1530 nSelectedWidth += aTabCols.GetRight() - aTabCols[i-1];
1531 else
1532 nSelectedWidth += aTabCols[i] - aTabCols[i-1];
1533 ++nCols;
1534 }
1535 fTotalWish += aWish[i];
1536 }
1537 const sal_uInt16 nEqualWidth = nSelectedWidth / nCols;
28
Division by zero
1538 // bBalance: Distribute the width evenly
1539 for (sal_uInt16 & rn : aWish)
1540 if ( rn && bBalance )
1541 rn = nEqualWidth;
1542 }
1543
1544 const long nOldRight = aTabCols.GetRight();
1545
1546 // In order to make the implementation easier, but still use the available
1547 // space properly, we do this twice.
1548
1549 // The problem: The first column is getting wider, the others get slimmer
1550 // only afterwards.
1551 // The first column's desired width would be discarded as it would cause
1552 // the Table's width to exceed the maximum width.
1553 const sal_uInt16 nEqualWidth = (aTabCols.GetRight() - aTabCols.GetLeft()) / (aTabCols.Count() + 1);
1554 const sal_Int16 nTablePadding = nSelectedWidth - fTotalWish;
1555 for ( int k = 0; k < 2; ++k )
1556 {
1557 for ( size_t i = 0; i <= aTabCols.Count(); ++i )
1558 {
1559 // bNoShrink: distribute excess space proportionately on pass 2.
1560 if ( bNoShrink && k && nTablePadding > 0 && fTotalWish > 0 )
1561 aWish[i] += round( aWish[i] / fTotalWish * nTablePadding );
1562
1563 // First pass is primarily a shrink pass. Give all columns a chance
1564 // to grow by requesting the maximum width as "balanced".
1565 // Second pass is a first-come, first-served chance to max out.
1566 int nDiff = k ? aWish[i] : std::min(aWish[i], nEqualWidth);
1567 if ( nDiff )
1568 {
1569 int nMin = aMins[i];
1570 if ( nMin > nDiff )
1571 nDiff = nMin;
1572
1573 if ( i == 0 )
1574 {
1575 if( aTabCols.Count() )
1576 nDiff -= aTabCols[0] - aTabCols.GetLeft();
1577 else
1578 nDiff -= aTabCols.GetRight() - aTabCols.GetLeft();
1579 }
1580 else if ( i == aTabCols.Count() )
1581 nDiff -= aTabCols.GetRight() - aTabCols[i-1];
1582 else
1583 nDiff -= aTabCols[i] - aTabCols[i-1];
1584
1585 long nTabRight = aTabCols.GetRight() + nDiff;
1586
1587 // If the Table would become too wide, we restrict the
1588 // adjusted amount to the allowed maximum.
1589 if ( !bBalance && nTabRight > aTabCols.GetRightMax() )
1590 {
1591 const long nTmpD = nTabRight - aTabCols.GetRightMax();
1592 nDiff -= nTmpD;
1593 nTabRight -= nTmpD;
1594 }
1595 for ( size_t i2 = i; i2 < aTabCols.Count(); ++i2 )
1596 aTabCols[i2] += nDiff;
1597 aTabCols.SetRight( nTabRight );
1598 }
1599 }
1600 }
1601
1602 const long nNewRight = aTabCols.GetRight();
1603
1604 SwFrameFormat *pFormat = pTableNd->GetTable().GetFrameFormat();
1605 const sal_Int16 nOriHori = pFormat->GetHoriOrient().GetHoriOrient();
1606
1607 // We can leave the "real" work to the SwTable now
1608 SetTabCols( aTabCols, false, static_cast<SwCellFrame*>(pBoxFrame) );
1609
1610 // Alignment might have been changed in SetTabCols; restore old value
1611 const SwFormatHoriOrient &rHori = pFormat->GetHoriOrient();
1612 SwFormatHoriOrient aHori( rHori );
1613 if ( aHori.GetHoriOrient() != nOriHori )
1614 {
1615 aHori.SetHoriOrient( nOriHori );
1616 pFormat->SetFormatAttr( aHori );
1617 }
1618
1619 // We switch to left-adjusted for automatic width
1620 // We adjust the right border for Border attributes
1621 if( !bBalance && nNewRight < nOldRight )
1622 {
1623 if( aHori.GetHoriOrient() == text::HoriOrientation::FULL )
1624 {
1625 aHori.SetHoriOrient( text::HoriOrientation::LEFT );
1626 pFormat->SetFormatAttr( aHori );
1627 }
1628 }
1629
1630 getIDocumentState().SetModified();
1631}
1632
1633/* vim:set shiftwidth=4 softtabstop=4 expandtab: */