Bug Summary

File:home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx
Warning:line 1583, column 38
Called C++ object pointer is null

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 swtable.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/table/swtable.cxx

/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.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 <hints.hxx>
22#include <editeng/lrspitem.hxx>
23#include <editeng/shaditem.hxx>
24#include <editeng/adjustitem.hxx>
25#include <editeng/colritem.hxx>
26#include <sfx2/linkmgr.hxx>
27#include <fmtfsize.hxx>
28#include <fmtornt.hxx>
29#include <fmtpdsc.hxx>
30#include <fldbas.hxx>
31#include <fmtfld.hxx>
32#include <frmatr.hxx>
33#include <doc.hxx>
34#include <IDocumentLinksAdministration.hxx>
35#include <IDocumentRedlineAccess.hxx>
36#include <IDocumentFieldsAccess.hxx>
37#include <docary.hxx>
38#include <frame.hxx>
39#include <swtable.hxx>
40#include <ndtxt.hxx>
41#include <tabcol.hxx>
42#include <tabfrm.hxx>
43#include <cellfrm.hxx>
44#include <rowfrm.hxx>
45#include <swserv.hxx>
46#include <expfld.hxx>
47#include <mdiexp.hxx>
48#include <cellatr.hxx>
49#include <txatbase.hxx>
50#include <htmltbl.hxx>
51#include <swtblfmt.hxx>
52#include <ndindex.hxx>
53#include <tblrwcl.hxx>
54#include <shellres.hxx>
55#include <viewsh.hxx>
56#include <redline.hxx>
57#include <vector>
58#include <calbck.hxx>
59
60#ifdef DBG_UTIL
61#define CHECK_TABLE(t) (t).CheckConsistency();
62#else
63#define CHECK_TABLE(t)
64#endif
65
66using namespace com::sun::star;
67
68
69#define COLFUZZY20 20
70
71static void ChgTextToNum( SwTableBox& rBox, const OUString& rText, const Color* pCol,
72 bool bChgAlign, sal_uLong nNdPos );
73
74inline const Color* SwTableBox::GetSaveUserColor() const
75{
76 return mpUserColor.get();
77}
78
79inline const Color* SwTableBox::GetSaveNumFormatColor() const
80{
81 return mpNumFormatColor.get();
82}
83
84inline void SwTableBox::SetSaveUserColor(const Color* p )
85{
86 if (p)
87 mpUserColor.reset(new Color(*p));
88 else
89 mpUserColor.reset();
90}
91
92inline void SwTableBox::SetSaveNumFormatColor( const Color* p )
93{
94 if (p)
95 mpNumFormatColor.reset(new Color(*p));
96 else
97 mpNumFormatColor.reset();
98}
99
100long SwTableBox::getRowSpan() const
101{
102 return mnRowSpan;
103}
104
105void SwTableBox::setRowSpan( long nNewRowSpan )
106{
107 mnRowSpan = nNewRowSpan;
108}
109
110bool SwTableBox::getDummyFlag() const
111{
112 return mbDummyFlag;
113}
114
115void SwTableBox::setDummyFlag( bool bDummy )
116{
117 mbDummyFlag = bDummy;
118}
119
120//JP 15.09.98: Bug 55741 - Keep tabs (front and rear)
121static OUString& lcl_TabToBlankAtSttEnd( OUString& rText )
122{
123 sal_Unicode c;
124 sal_Int32 n;
125
126 for( n = 0; n < rText.getLength() && ' ' >= ( c = rText[n] ); ++n )
127 if( '\x9' == c )
128 rText = rText.replaceAt( n, 1, " " );
129 for( n = rText.getLength(); n && ' ' >= ( c = rText[--n] ); )
130 if( '\x9' == c )
131 rText = rText.replaceAt( n, 1, " " );
132 return rText;
133}
134
135static OUString& lcl_DelTabsAtSttEnd( OUString& rText )
136{
137 sal_Unicode c;
138 sal_Int32 n;
139 OUStringBuffer sBuff(rText);
140
141 for( n = 0; n < sBuff.getLength() && ' ' >= ( c = sBuff[ n ]); ++n )
142 {
143 if( '\x9' == c )
144 sBuff.remove( n--, 1 );
145 }
146 for( n = sBuff.getLength(); n && ' ' >= ( c = sBuff[ --n ]); )
147 {
148 if( '\x9' == c )
149 sBuff.remove( n, 1 );
150 }
151 rText = sBuff.makeStringAndClear();
152 return rText;
153}
154
155void InsTableBox( SwDoc& rDoc, SwTableNode* pTableNd,
156 SwTableLine* pLine, SwTableBoxFormat* pBoxFrameFormat,
157 SwTableBox* pBox,
158 sal_uInt16 nInsPos, sal_uInt16 nCnt )
159{
160 OSL_ENSURE( pBox->GetSttNd(), "Box with no start node" )do { if (true && (!(pBox->GetSttNd()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
":" "160" ": "), "%s", "Box with no start node"); } } while (
false)
;
161 SwNodeIndex aIdx( *pBox->GetSttNd(), +1 );
162 SwContentNode* pCNd = aIdx.GetNode().GetContentNode();
163 if( !pCNd )
164 pCNd = rDoc.GetNodes().GoNext( &aIdx );
165 OSL_ENSURE( pCNd, "Box with no content node" )do { if (true && (!(pCNd))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
":" "165" ": "), "%s", "Box with no content node"); } } while
(false)
;
166
167 if( pCNd->IsTextNode() )
168 {
169 if( pBox->GetSaveNumFormatColor() && pCNd->GetpSwAttrSet() )
170 {
171 SwAttrSet aAttrSet( *pCNd->GetpSwAttrSet() );
172 if( pBox->GetSaveUserColor() )
173 aAttrSet.Put( SvxColorItem( *pBox->GetSaveUserColor(), RES_CHRATR_COLOR ));
174 else
175 aAttrSet.ClearItem( RES_CHRATR_COLOR );
176 rDoc.GetNodes().InsBoxen( pTableNd, pLine, pBoxFrameFormat,
177 static_cast<SwTextNode*>(pCNd)->GetTextColl(),
178 &aAttrSet, nInsPos, nCnt );
179 }
180 else
181 rDoc.GetNodes().InsBoxen( pTableNd, pLine, pBoxFrameFormat,
182 static_cast<SwTextNode*>(pCNd)->GetTextColl(),
183 pCNd->GetpSwAttrSet(),
184 nInsPos, nCnt );
185 }
186 else
187 rDoc.GetNodes().InsBoxen( pTableNd, pLine, pBoxFrameFormat,
188 rDoc.GetDfltTextFormatColl(), nullptr,
189 nInsPos, nCnt );
190
191 long nRowSpan = pBox->getRowSpan();
192 if( nRowSpan != 1 )
193 {
194 SwTableBoxes& rTableBoxes = pLine->GetTabBoxes();
195 for( sal_uInt16 i = 0; i < nCnt; ++i )
196 {
197 pBox = rTableBoxes[ i + nInsPos ];
198 pBox->setRowSpan( nRowSpan );
199 }
200 }
201}
202
203SwTable::SwTable()
204 : SwClient( nullptr ),
205 m_pTableNode( nullptr ),
206 m_nGraphicsThatResize( 0 ),
207 m_nRowsToRepeat( 1 ),
208 m_bModifyLocked( false ),
209 m_bNewModel( true )
210{
211 // default value set in the options
212 m_eTableChgMode = GetTableChgDefaultMode();
213}
214
215SwTable::SwTable( const SwTable& rTable )
216 : SwClient( rTable.GetFrameFormat() ),
217 m_pTableNode( nullptr ),
218 m_eTableChgMode( rTable.m_eTableChgMode ),
219 m_nGraphicsThatResize( 0 ),
220 m_nRowsToRepeat( rTable.GetRowsToRepeat() ),
221 maTableStyleName(rTable.maTableStyleName),
222 m_bModifyLocked( false ),
223 m_bNewModel( rTable.m_bNewModel )
224{
225}
226
227void DelBoxNode( SwTableSortBoxes const & rSortCntBoxes )
228{
229 for (size_t n = 0; n < rSortCntBoxes.size(); ++n)
230 {
231 rSortCntBoxes[ n ]->m_pStartNode = nullptr;
232 }
233}
234
235SwTable::~SwTable()
236{
237 if( m_xRefObj.is() )
238 {
239 SwDoc* pDoc = GetFrameFormat()->GetDoc();
240 if( !pDoc->IsInDtor() ) // then remove from the list
241 pDoc->getIDocumentLinksAdministration().GetLinkManager().RemoveServer( m_xRefObj.get() );
242
243 m_xRefObj->Closed();
244 }
245
246 // the table can be deleted if it's the last client of the FrameFormat
247 SwTableFormat* pFormat = GetFrameFormat();
248 pFormat->Remove( this ); // remove
249
250 if( !pFormat->HasWriterListeners() )
251 pFormat->GetDoc()->DelTableFrameFormat( pFormat ); // and delete
252
253 // Delete the pointers from the SortArray of the boxes. The objects
254 // are preserved and are deleted by the lines/boxes arrays dtor.
255 // Note: unfortunately not enough, pointers to the StartNode of the
256 // section need deletion.
257 DelBoxNode(m_TabSortContentBoxes);
258 m_TabSortContentBoxes.clear();
259}
260
261namespace
262{
263
264template<class T>
265T lcl_MulDiv64(sal_uInt64 nA, sal_uInt64 nM, sal_uInt64 nD)
266{
267 return static_cast<T>((nA*nM)/nD);
268}
269
270}
271
272static void FormatInArr( std::vector<SwFormat*>& rFormatArr, SwFormat* pBoxFormat )
273{
274 std::vector<SwFormat*>::const_iterator it = std::find( rFormatArr.begin(), rFormatArr.end(), pBoxFormat );
275 if ( it == rFormatArr.end() )
276 rFormatArr.push_back( pBoxFormat );
277}
278
279static void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld,
280 const long nNew, std::vector<SwFormat*>& rFormatArr );
281
282static void lcl_ModifyLines( SwTableLines &rLines, const long nOld,
283 const long nNew, std::vector<SwFormat*>& rFormatArr, const bool bCheckSum )
284{
285 for ( size_t i = 0; i < rLines.size(); ++i )
286 ::lcl_ModifyBoxes( rLines[i]->GetTabBoxes(), nOld, nNew, rFormatArr );
287 if( bCheckSum )
288 {
289 for(SwFormat* pFormat : rFormatArr)
290 {
291 const SwTwips nBox = lcl_MulDiv64<SwTwips>(pFormat->GetFrameSize().GetWidth(), nNew, nOld);
292 SwFormatFrameSize aNewBox( SwFrameSize::Variable, nBox, 0 );
293 pFormat->LockModify();
294 pFormat->SetFormatAttr( aNewBox );
295 pFormat->UnlockModify();
296 }
297 }
298}
299
300static void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld,
301 const long nNew, std::vector<SwFormat*>& rFormatArr )
302{
303 sal_uInt64 nSum = 0; // To avoid rounding errors we summarize all box widths
304 sal_uInt64 nOriginalSum = 0; // Sum of original widths
305 for ( size_t i = 0; i < rBoxes.size(); ++i )
306 {
307 SwTableBox &rBox = *rBoxes[i];
308 if ( !rBox.GetTabLines().empty() )
309 {
310 // For SubTables the rounding problem will not be solved :-(
311 ::lcl_ModifyLines( rBox.GetTabLines(), nOld, nNew, rFormatArr, false );
312 }
313 // Adjust the box
314 SwFrameFormat *pFormat = rBox.GetFrameFormat();
315 sal_uInt64 nBox = pFormat->GetFrameSize().GetWidth();
316 nOriginalSum += nBox;
317 nBox *= nNew;
318 nBox /= nOld;
319 const sal_uInt64 nWishedSum = lcl_MulDiv64<sal_uInt64>(nOriginalSum, nNew, nOld) - nSum;
320 if( nWishedSum > 0 )
321 {
322 if( nBox == nWishedSum )
323 FormatInArr( rFormatArr, pFormat );
324 else
325 {
326 nBox = nWishedSum;
327 pFormat = rBox.ClaimFrameFormat();
328 SwFormatFrameSize aNewBox( SwFrameSize::Variable, static_cast< SwTwips >(nBox), 0 );
329 pFormat->LockModify();
330 pFormat->SetFormatAttr( aNewBox );
331 pFormat->UnlockModify();
332 }
333 }
334 else {
335 OSL_FAIL( "Rounding error" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
":" "335" ": "), "%s", "Rounding error"); } } while (false)
;
336 }
337 nSum += nBox;
338 }
339}
340
341void SwTable::SwClientNotify(const SwModify&, const SfxHint& rHint)
342{
343 auto pLegacy = dynamic_cast<const sw::LegacyModifyHint*>(&rHint);
344 if(!pLegacy)
345 return;
346 // catch SSize changes, to adjust the lines/boxes
347 const sal_uInt16 nWhich = pLegacy->GetWhich();
348 const SwFormatFrameSize* pNewSize = nullptr, *pOldSize = nullptr;
349 switch(nWhich)
350 {
351 case RES_ATTRSET_CHG:
352 {
353 if (pLegacy->m_pOld && pLegacy->m_pNew
354 && SfxItemState::SET == static_cast<const SwAttrSetChg*>(pLegacy->m_pNew)->GetChgSet()->GetItemState(
355 RES_FRM_SIZE,
356 false,
357 reinterpret_cast<const SfxPoolItem**>(&pNewSize)))
358 {
359 pOldSize = &static_cast<const SwAttrSetChg*>(pLegacy->m_pOld)->GetChgSet()->GetFrameSize();
360 }
361 }
362 break;
363 case RES_FRM_SIZE:
364 {
365 pOldSize = static_cast<const SwFormatFrameSize*>(pLegacy->m_pOld);
366 pNewSize = static_cast<const SwFormatFrameSize*>(pLegacy->m_pNew);
367 }
368 break;
369 default:
370 CheckRegistration(pLegacy->m_pOld);
371 }
372 if (pOldSize && pNewSize && !m_bModifyLocked)
373 AdjustWidths(pOldSize->GetWidth(), pNewSize->GetWidth());
374}
375
376void SwTable::AdjustWidths( const long nOld, const long nNew )
377{
378 std::vector<SwFormat*> aFormatArr;
379 aFormatArr.reserve( m_aLines[0]->GetTabBoxes().size() );
380 ::lcl_ModifyLines( m_aLines, nOld, nNew, aFormatArr, true );
381}
382
383static void lcl_RefreshHidden( SwTabCols &rToFill, size_t nPos )
384{
385 for ( size_t i = 0; i < rToFill.Count(); ++i )
386 {
387 if ( std::abs(static_cast<long>(nPos) - rToFill[i]) <= COLFUZZY20 )
388 {
389 rToFill.SetHidden( i, false );
390 break;
391 }
392 }
393}
394
395static void lcl_SortedTabColInsert( SwTabCols &rToFill, const SwTableBox *pBox,
396 const SwFrameFormat *pTabFormat, const bool bHidden,
397 const bool bRefreshHidden )
398{
399 const long nWish = pTabFormat->GetFrameSize().GetWidth();
400 OSL_ENSURE(nWish, "weird <= 0 width frmfrm")do { if (true && (!(nWish))) { sal_detail_logFormat((
SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
":" "400" ": "), "%s", "weird <= 0 width frmfrm"); } } while
(false)
;
401
402 // The value for the left edge of the box is calculated from the
403 // widths of the previous boxes.
404 long nPos = 0;
405 long nLeftMin = 0;
406 long nRightMax = 0;
407 if (nWish != 0) //fdo#33012 0 width frmfmt
408 {
409 SwTwips nSum = 0;
410 const SwTableBox *pCur = pBox;
411 const SwTableLine *pLine = pBox->GetUpper();
412 const long nAct = rToFill.GetRight() - rToFill.GetLeft(); // +1 why?
413
414 while ( pLine )
415 {
416 const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
417 for ( size_t i = 0; i < rBoxes.size(); ++i )
418 {
419 const SwTwips nWidth = rBoxes[i]->GetFrameFormat()->GetFrameSize().GetWidth();
420 nSum += nWidth;
421 const long nTmp = lcl_MulDiv64<long>(nSum, nAct, nWish);
422
423 if (rBoxes[i] != pCur)
424 {
425 if ( pLine == pBox->GetUpper() || 0 == nLeftMin )
426 nLeftMin = nTmp - nPos;
427 nPos = nTmp;
428 }
429 else
430 {
431 nSum -= nWidth;
432 if ( 0 == nRightMax )
433 nRightMax = nTmp - nPos;
434 break;
435 }
436 }
437 pCur = pLine->GetUpper();
438 pLine = pCur ? pCur->GetUpper() : nullptr;
439 }
440 }
441
442 bool bInsert = !bRefreshHidden;
443 for ( size_t j = 0; bInsert && (j < rToFill.Count()); ++j )
444 {
445 long nCmp = rToFill[j];
446 if ( (nPos >= ((nCmp >= COLFUZZY20) ? nCmp - COLFUZZY20 : nCmp)) &&
447 (nPos <= (nCmp + COLFUZZY20)) )
448 {
449 bInsert = false; // Already has it.
450 }
451 else if ( nPos < nCmp )
452 {
453 bInsert = false;
454 rToFill.Insert( nPos, bHidden, j );
455 }
456 }
457 if ( bInsert )
458 rToFill.Insert( nPos, bHidden, rToFill.Count() );
459 else if ( bRefreshHidden )
460 ::lcl_RefreshHidden( rToFill, nPos );
461
462 if ( !bHidden || bRefreshHidden )
463 return;
464
465 // calculate minimum/maximum values for the existing entries:
466 nLeftMin = nPos - nLeftMin;
467 nRightMax = nPos + nRightMax;
468
469 // check if nPos is entry:
470 bool bFoundPos = false;
471 bool bFoundMax = false;
472 for ( size_t j = 0; !(bFoundPos && bFoundMax ) && j < rToFill.Count(); ++j )
473 {
474 SwTabColsEntry& rEntry = rToFill.GetEntry( j );
475 long nCmp = rToFill[j];
476
477 if ( (nPos >= ((nCmp >= COLFUZZY20) ? nCmp - COLFUZZY20 : nCmp)) &&
478 (nPos <= (nCmp + COLFUZZY20)) )
479 {
480 // check if nLeftMin is > old minimum for entry nPos:
481 const long nOldMin = rEntry.nMin;
482 if ( nLeftMin > nOldMin )
483 rEntry.nMin = nLeftMin;
484 // check if nRightMin is < old maximum for entry nPos:
485 const long nOldMax = rEntry.nMax;
486 if ( nRightMax < nOldMax )
487 rEntry.nMax = nRightMax;
488
489 bFoundPos = true;
490 }
491 else if ( (nRightMax >= ((nCmp >= COLFUZZY20) ? nCmp - COLFUZZY20 : nCmp)) &&
492 (nRightMax <= (nCmp + COLFUZZY20)) )
493 {
494 // check if nPos is > old minimum for entry nRightMax:
495 const long nOldMin = rEntry.nMin;
496 if ( nPos > nOldMin )
497 rEntry.nMin = nPos;
498
499 bFoundMax = true;
500 }
501 }
502}
503
504static void lcl_ProcessBoxGet( const SwTableBox *pBox, SwTabCols &rToFill,
505 const SwFrameFormat *pTabFormat, bool bRefreshHidden )
506{
507 if ( !pBox->GetTabLines().empty() )
508 {
509 const SwTableLines &rLines = pBox->GetTabLines();
510 for ( size_t i = 0; i < rLines.size(); ++i )
511 {
512 const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
513 for ( size_t j = 0; j < rBoxes.size(); ++j )
514 ::lcl_ProcessBoxGet( rBoxes[j], rToFill, pTabFormat, bRefreshHidden);
515 }
516 }
517 else
518 ::lcl_SortedTabColInsert( rToFill, pBox, pTabFormat, false, bRefreshHidden );
519}
520
521static void lcl_ProcessLineGet( const SwTableLine *pLine, SwTabCols &rToFill,
522 const SwFrameFormat *pTabFormat )
523{
524 for ( size_t i = 0; i < pLine->GetTabBoxes().size(); ++i )
525 {
526 const SwTableBox *pBox = pLine->GetTabBoxes()[i];
527 if ( pBox->GetSttNd() )
528 ::lcl_SortedTabColInsert( rToFill, pBox, pTabFormat, true, false );
529 else
530 for ( size_t j = 0; j < pBox->GetTabLines().size(); ++j )
531 ::lcl_ProcessLineGet( pBox->GetTabLines()[j], rToFill, pTabFormat );
532 }
533}
534
535void SwTable::GetTabCols( SwTabCols &rToFill, const SwTableBox *pStart,
536 bool bRefreshHidden, bool bCurRowOnly ) const
537{
538 // Optimization: if bHidden is set, we only update the Hidden Array.
539 if ( bRefreshHidden )
540 {
541 // remove corrections
542 for ( size_t i = 0; i < rToFill.Count(); ++i )
543 {
544 SwTabColsEntry& rEntry = rToFill.GetEntry( i );
545 rEntry.nPos -= rToFill.GetLeft();
546 rEntry.nMin -= rToFill.GetLeft();
547 rEntry.nMax -= rToFill.GetLeft();
548 }
549
550 // All are hidden, so add the visible ones.
551 for ( size_t i = 0; i < rToFill.Count(); ++i )
552 rToFill.SetHidden( i, true );
553 }
554 else
555 {
556 rToFill.Remove( 0, rToFill.Count() );
557 }
558
559 // Insertion cases:
560 // 1. All boxes which are inferior to Line which is superior to the Start,
561 // as well as their inferior boxes if present.
562 // 2. Starting from the Line, the superior box plus its neighbours; but no inferiors.
563 // 3. Apply 2. to the Line superior to the chain of boxes,
564 // until the Line's superior is not a box but the table.
565 // Only those boxes are inserted that don't contain further rows. The insertion
566 // function takes care to avoid duplicates. In order to achieve this, we work
567 // with some degree of fuzzyness (to avoid rounding errors).
568 // Only the left edge of the boxes are inserted.
569 // Finally, the first entry is removed again, because it's already
570 // covered by the border.
571 // 4. Scan the table again and insert _all_ boxes, this time as hidden.
572
573 const SwFrameFormat *pTabFormat = GetFrameFormat();
574
575 // 1.
576 const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
577
578 for ( size_t i = 0; i < rBoxes.size(); ++i )
579 ::lcl_ProcessBoxGet( rBoxes[i], rToFill, pTabFormat, bRefreshHidden );
580
581 // 2. and 3.
582 const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
583 pStart->GetUpper()->GetUpper()->GetUpper() : nullptr;
584 while ( pLine )
585 {
586 const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
587 for ( size_t k = 0; k < rBoxes2.size(); ++k )
588 ::lcl_SortedTabColInsert( rToFill, rBoxes2[k],
589 pTabFormat, false, bRefreshHidden );
590 pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : nullptr;
591 }
592
593 if ( !bRefreshHidden )
594 {
595 // 4.
596 if ( !bCurRowOnly )
597 {
598 for ( size_t i = 0; i < m_aLines.size(); ++i )
599 ::lcl_ProcessLineGet( m_aLines[i], rToFill, pTabFormat );
600 }
601
602 rToFill.Remove( 0 );
603 }
604
605 // Now the coordinates are relative to the left table border - i.e.
606 // relative to SwTabCols.nLeft. However, they are expected
607 // relative to the left document border, i.e. SwTabCols.nLeftMin.
608 // So all values need to be extended by nLeft.
609 for ( size_t i = 0; i < rToFill.Count(); ++i )
610 {
611 SwTabColsEntry& rEntry = rToFill.GetEntry( i );
612 rEntry.nPos += rToFill.GetLeft();
613 rEntry.nMin += rToFill.GetLeft();
614 rEntry.nMax += rToFill.GetLeft();
615 }
616}
617
618// Structure for parameter passing
619struct Parm
620{
621 const SwTabCols &rNew;
622 const SwTabCols &rOld;
623 long nNewWish,
624 nOldWish;
625 std::deque<SwTableBox*> aBoxArr;
626 SwShareBoxFormats aShareFormats;
627
628 Parm( const SwTabCols &rN, const SwTabCols &rO )
629 : rNew( rN ), rOld( rO ), nNewWish(0), nOldWish(0)
630 {}
631};
632
633static void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm );
634
635static void lcl_ProcessLine( SwTableLine *pLine, Parm &rParm )
636{
637 SwTableBoxes &rBoxes = pLine->GetTabBoxes();
638 for ( size_t i = rBoxes.size(); i > 0; )
639 {
640 --i;
641 ::lcl_ProcessBoxSet( rBoxes[i], rParm );
642 }
643}
644
645static void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm )
646{
647 if ( !pBox->GetTabLines().empty() )
648 {
649 SwTableLines &rLines = pBox->GetTabLines();
650 for ( size_t i = rLines.size(); i > 0; )
651 {
652 --i;
653 lcl_ProcessLine( rLines[i], rParm );
654 }
655 }
656 else
657 {
658 // Search the old TabCols for the current position (calculate from
659 // left and right edge). Adjust the box if the values differ from
660 // the new TabCols. If the adjusted edge has no neighbour we also
661 // adjust all superior boxes.
662
663 const long nOldAct = rParm.rOld.GetRight() -
664 rParm.rOld.GetLeft(); // +1 why?
665
666 // The value for the left edge of the box is calculated from the
667 // widths of the previous boxes plus the left edge.
668 long nLeft = rParm.rOld.GetLeft();
669 const SwTableBox *pCur = pBox;
670 const SwTableLine *pLine = pBox->GetUpper();
671
672 while ( pLine )
673 {
674 const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
675 for ( size_t i = 0; (i < rBoxes.size()) && (rBoxes[i] != pCur); ++i)
676 {
677 nLeft += lcl_MulDiv64<long>(
678 rBoxes[i]->GetFrameFormat()->GetFrameSize().GetWidth(),
679 nOldAct, rParm.nOldWish);
680 }
681 pCur = pLine->GetUpper();
682 pLine = pCur ? pCur->GetUpper() : nullptr;
683 }
684 long nLeftDiff = 0;
685 long nRightDiff = 0;
686 if ( nLeft != rParm.rOld.GetLeft() ) // There are still boxes before this.
687 {
688 // Right edge is left edge plus width.
689 const long nWidth = lcl_MulDiv64<long>(
690 pBox->GetFrameFormat()->GetFrameSize().GetWidth(),
691 nOldAct, rParm.nOldWish);
692 const long nRight = nLeft + nWidth;
693 size_t nLeftPos = 0;
694 size_t nRightPos = 0;
695 bool bFoundLeftPos = false;
696 bool bFoundRightPos = false;
697 for ( size_t i = 0; i < rParm.rOld.Count(); ++i )
698 {
699 if ( nLeft >= (rParm.rOld[i] - COLFUZZY20) &&
700 nLeft <= (rParm.rOld[i] + COLFUZZY20) )
701 {
702 nLeftPos = i;
703 bFoundLeftPos = true;
704 }
705 else if ( nRight >= (rParm.rOld[i] - COLFUZZY20) &&
706 nRight <= (rParm.rOld[i] + COLFUZZY20) )
707 {
708 nRightPos = i;
709 bFoundRightPos = true;
710 }
711 }
712 nLeftDiff = bFoundLeftPos ?
713 rParm.rOld[nLeftPos] - rParm.rNew[nLeftPos] : 0;
714 nRightDiff= bFoundRightPos ?
715 rParm.rNew[nRightPos] - rParm.rOld[nRightPos] : 0;
716 }
717 else // The first box.
718 {
719 nLeftDiff = rParm.rOld.GetLeft() - rParm.rNew.GetLeft();
720 if ( rParm.rOld.Count() )
721 {
722 // Calculate the difference to the edge touching the first box.
723 const long nWidth = lcl_MulDiv64<long>(
724 pBox->GetFrameFormat()->GetFrameSize().GetWidth(),
725 nOldAct, rParm.nOldWish);
726 const long nTmp = nWidth + rParm.rOld.GetLeft();
727 for ( size_t i = 0; i < rParm.rOld.Count(); ++i )
728 {
729 if ( nTmp >= (rParm.rOld[i] - COLFUZZY20) &&
730 nTmp <= (rParm.rOld[i] + COLFUZZY20) )
731 {
732 nRightDiff = rParm.rNew[i] - rParm.rOld[i];
733 break;
734 }
735 }
736 }
737 }
738
739 if( pBox->getRowSpan() == 1 )
740 {
741 const sal_uInt16 nPos = pBox->GetUpper()->GetBoxPos( pBox );
742 SwTableBoxes& rTableBoxes = pBox->GetUpper()->GetTabBoxes();
743 if( nPos && rTableBoxes[ nPos - 1 ]->getRowSpan() != 1 )
744 nLeftDiff = 0;
745 if( nPos + 1 < static_cast<sal_uInt16>(rTableBoxes.size()) &&
746 rTableBoxes[ nPos + 1 ]->getRowSpan() != 1 )
747 nRightDiff = 0;
748 }
749 else
750 nLeftDiff = nRightDiff = 0;
751
752 if ( nLeftDiff || nRightDiff )
753 {
754 // The difference is the actual difference amount. For stretched
755 // tables, it does not make sense to adjust the attributes of the
756 // boxes by this amount. The difference amount needs to be converted
757 // accordingly.
758 long nTmp = rParm.rNew.GetRight() - rParm.rNew.GetLeft(); // +1 why?
759 nLeftDiff *= rParm.nNewWish;
760 nLeftDiff /= nTmp;
761 nRightDiff *= rParm.nNewWish;
762 nRightDiff /= nTmp;
763 long nDiff = nLeftDiff + nRightDiff;
764
765 // Adjust the box and all superiors by the difference amount.
766 while ( pBox )
767 {
768 SwFormatFrameSize aFormatFrameSize( pBox->GetFrameFormat()->GetFrameSize() );
769 aFormatFrameSize.SetWidth( aFormatFrameSize.GetWidth() + nDiff );
770 if ( aFormatFrameSize.GetWidth() < 0 )
771 aFormatFrameSize.SetWidth( -aFormatFrameSize.GetWidth() );
772 rParm.aShareFormats.SetSize( *pBox, aFormatFrameSize );
773
774 // The outer cells of the last row are responsible to adjust a surrounding cell.
775 // Last line check:
776 if ( pBox->GetUpper()->GetUpper() &&
777 pBox->GetUpper() != pBox->GetUpper()->GetUpper()->GetTabLines().back())
778 {
779 pBox = nullptr;
780 }
781 else
782 {
783 // Middle cell check:
784 if ( pBox != pBox->GetUpper()->GetTabBoxes().front() )
785 nDiff = nRightDiff;
786
787 if ( pBox != pBox->GetUpper()->GetTabBoxes().back() )
788 nDiff -= nRightDiff;
789
790 pBox = nDiff ? pBox->GetUpper()->GetUpper() : nullptr;
791 }
792 }
793 }
794 }
795}
796
797static void lcl_ProcessBoxPtr( SwTableBox *pBox, std::deque<SwTableBox*> &rBoxArr,
798 bool bBefore )
799{
800 if ( !pBox->GetTabLines().empty() )
801 {
802 const SwTableLines &rLines = pBox->GetTabLines();
803 for ( size_t i = 0; i < rLines.size(); ++i )
804 {
805 const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
806 for ( size_t j = 0; j < rBoxes.size(); ++j )
807 ::lcl_ProcessBoxPtr( rBoxes[j], rBoxArr, bBefore );
808 }
809 }
810 else if ( bBefore )
811 rBoxArr.push_front( pBox );
812 else
813 rBoxArr.push_back( pBox );
814}
815
816static void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm );
817
818static void lcl_AdjustLines( SwTableLines &rLines, const long nDiff, Parm &rParm )
819{
820 for ( size_t i = 0; i < rLines.size(); ++i )
821 {
822 SwTableBox *pBox = rLines[i]->GetTabBoxes()
823 [rLines[i]->GetTabBoxes().size()-1];
824 lcl_AdjustBox( pBox, nDiff, rParm );
825 }
826}
827
828static void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm )
829{
830 if ( !pBox->GetTabLines().empty() )
831 ::lcl_AdjustLines( pBox->GetTabLines(), nDiff, rParm );
832
833 // Adjust the size of the box.
834 SwFormatFrameSize aFormatFrameSize( pBox->GetFrameFormat()->GetFrameSize() );
835 aFormatFrameSize.SetWidth( aFormatFrameSize.GetWidth() + nDiff );
836
837 rParm.aShareFormats.SetSize( *pBox, aFormatFrameSize );
838}
839
840void SwTable::SetTabCols( const SwTabCols &rNew, const SwTabCols &rOld,
841 const SwTableBox *pStart, bool bCurRowOnly )
842{
843 CHECK_TABLE( *this )
844
845 SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>()); // delete HTML-Layout
846
847 // FME: Made rOld const. The caller is responsible for passing correct
848 // values of rOld. Therefore we do not have to call GetTabCols anymore:
849 //GetTabCols( rOld, pStart );
850
851 Parm aParm( rNew, rOld );
852
853 OSL_ENSURE( rOld.Count() == rNew.Count(), "Number of columns changed.")do { if (true && (!(rOld.Count() == rNew.Count()))) {
sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
":" "853" ": "), "%s", "Number of columns changed."); } } while
(false)
;
854
855 // Convert the edges. We need to adjust the size of the table and some boxes.
856 // For the size adjustment, we must not make use of the Modify, since that'd
857 // adjust all boxes, which we really don't want.
858 SwFrameFormat *pFormat = GetFrameFormat();
859 aParm.nOldWish = aParm.nNewWish = pFormat->GetFrameSize().GetWidth();
860 if ( (rOld.GetLeft() != rNew.GetLeft()) ||
861 (rOld.GetRight()!= rNew.GetRight()) )
862 {
863 LockModify();
864 {
865 SvxLRSpaceItem aLR( pFormat->GetLRSpace() );
866 SvxShadowItem aSh( pFormat->GetShadow() );
867
868 SwTwips nShRight = aSh.CalcShadowSpace( SvxShadowItemSide::RIGHT );
869 SwTwips nShLeft = aSh.CalcShadowSpace( SvxShadowItemSide::LEFT );
870
871 aLR.SetLeft ( rNew.GetLeft() - nShLeft );
872 aLR.SetRight( rNew.GetRightMax() - rNew.GetRight() - nShRight );
873 pFormat->SetFormatAttr( aLR );
874
875 // The alignment of the table needs to be adjusted accordingly.
876 // This is done by preserving the exact positions that have been
877 // set by the user.
878 SwFormatHoriOrient aOri( pFormat->GetHoriOrient() );
879 if( text::HoriOrientation::NONE != aOri.GetHoriOrient() &&
880 text::HoriOrientation::CENTER != aOri.GetHoriOrient() )
881 {
882 const bool bLeftDist = rNew.GetLeft() != nShLeft;
883 const bool bRightDist = rNew.GetRight() + nShRight != rNew.GetRightMax();
884 if(!bLeftDist && !bRightDist)
885 aOri.SetHoriOrient( text::HoriOrientation::FULL );
886 else if(!bRightDist && rNew.GetLeft() > nShLeft )
887 aOri.SetHoriOrient( text::HoriOrientation::RIGHT );
888 else if(!bLeftDist && rNew.GetRight() + nShRight < rNew.GetRightMax())
889 aOri.SetHoriOrient( text::HoriOrientation::LEFT );
890 else
891 aOri.SetHoriOrient( text::HoriOrientation::LEFT_AND_WIDTH );
892 }
893 pFormat->SetFormatAttr( aOri );
894 }
895 const long nAct = rOld.GetRight() - rOld.GetLeft(); // +1 why?
896 long nTabDiff = 0;
897
898 if ( rOld.GetLeft() != rNew.GetLeft() )
899 {
900 nTabDiff = rOld.GetLeft() - rNew.GetLeft();
901 nTabDiff *= aParm.nOldWish;
902 nTabDiff /= nAct;
903 }
904 if ( rOld.GetRight() != rNew.GetRight() )
905 {
906 long nDiff = rNew.GetRight() - rOld.GetRight();
907 nDiff *= aParm.nOldWish;
908 nDiff /= nAct;
909 nTabDiff += nDiff;
910 if( !IsNewModel() )
911 ::lcl_AdjustLines( GetTabLines(), nDiff, aParm );
912 }
913
914 // Adjust the size of the table, watch out for stretched tables.
915 if ( nTabDiff )
916 {
917 aParm.nNewWish += nTabDiff;
918 if ( aParm.nNewWish < 0 )
919 aParm.nNewWish = USHRT_MAX(32767 *2 +1); // Oops! Have to roll back.
920 SwFormatFrameSize aSz( pFormat->GetFrameSize() );
921 if ( aSz.GetWidth() != aParm.nNewWish )
922 {
923 aSz.SetWidth( aParm.nNewWish );
924 aSz.SetWidthPercent( 0 );
925 pFormat->SetFormatAttr( aSz );
926 }
927 }
928 UnlockModify();
929 }
930
931 if( IsNewModel() )
932 NewSetTabCols( aParm, rNew, rOld, pStart, bCurRowOnly );
933 else
934 {
935 if ( bCurRowOnly )
936 {
937 // To adjust the current row, we need to process all its boxes,
938 // similar to the filling of the TabCols (see GetTabCols()).
939 // Unfortunately we again have to take care to adjust the boxes
940 // from back to front, respectively from outer to inner.
941 // The best way to achieve this is probably to track the boxes
942 // in a PtrArray.
943 const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
944 for ( size_t i = 0; i < rBoxes.size(); ++i )
945 ::lcl_ProcessBoxPtr( rBoxes[i], aParm.aBoxArr, false );
946
947 const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
948 pStart->GetUpper()->GetUpper()->GetUpper() : nullptr;
949 const SwTableBox *pExcl = pStart->GetUpper()->GetUpper();
950 while ( pLine )
951 {
952 const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
953 bool bBefore = true;
954 for ( size_t i = 0; i < rBoxes2.size(); ++i )
955 {
956 if ( rBoxes2[i] != pExcl )
957 ::lcl_ProcessBoxPtr( rBoxes2[i], aParm.aBoxArr, bBefore );
958 else
959 bBefore = false;
960 }
961 pExcl = pLine->GetUpper();
962 pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : nullptr;
963 }
964 // After we've inserted a bunch of boxes (hopefully all and in
965 // correct order), we just need to process them in reverse order.
966 for ( int j = aParm.aBoxArr.size()-1; j >= 0; --j )
967 {
968 SwTableBox *pBox = aParm.aBoxArr[j];
969 ::lcl_ProcessBoxSet( pBox, aParm );
970 }
971 }
972 else
973 {
974 // Adjusting the entire table is 'easy'. All boxes without lines are
975 // adjusted, as are their superiors. Of course we need to process
976 // in reverse order to prevent fooling ourselves!
977 SwTableLines &rLines = GetTabLines();
978 for ( size_t i = rLines.size(); i > 0; )
979 {
980 --i;
981 ::lcl_ProcessLine( rLines[i], aParm );
982 }
983 }
984 }
985
986#ifdef DBG_UTIL
987 {
988 // do some checking for correct table widths
989 SwTwips nSize = GetFrameFormat()->GetFrameSize().GetWidth();
990 for (size_t n = 0; n < m_aLines.size(); ++n)
991 {
992 CheckBoxWidth( *m_aLines[ n ], nSize );
993 }
994 }
995#endif
996}
997
998typedef std::pair<sal_uInt16, sal_uInt16> ColChange;
999typedef std::list< ColChange > ChangeList;
1000
1001static void lcl_AdjustWidthsInLine( SwTableLine* pLine, ChangeList& rOldNew,
1002 Parm& rParm, sal_uInt16 nColFuzzy )
1003{
1004 ChangeList::iterator pCurr = rOldNew.begin();
1005 if( pCurr == rOldNew.end() )
1006 return;
1007 const size_t nCount = pLine->GetTabBoxes().size();
1008 SwTwips nBorder = 0;
1009 SwTwips nRest = 0;
1010 for( size_t i = 0; i < nCount; ++i )
1011 {
1012 SwTableBox* pBox = pLine->GetTabBoxes()[i];
1013 SwTwips nWidth = pBox->GetFrameFormat()->GetFrameSize().GetWidth();
1014 SwTwips nNewWidth = nWidth - nRest;
1015 nRest = 0;
1016 nBorder += nWidth;
1017 if( pCurr != rOldNew.end() && nBorder + nColFuzzy >= pCurr->first )
1018 {
1019 nBorder -= nColFuzzy;
1020 while( pCurr != rOldNew.end() && nBorder > pCurr->first )
1021 ++pCurr;
1022 if( pCurr != rOldNew.end() )
1023 {
1024 nBorder += nColFuzzy;
1025 if( nBorder + nColFuzzy >= pCurr->first )
1026 {
1027 if( pCurr->second == pCurr->first )
1028 nRest = 0;
1029 else
1030 nRest = pCurr->second - nBorder;
1031 nNewWidth += nRest;
1032 ++pCurr;
1033 }
1034 }
1035 }
1036 if( nNewWidth != nWidth )
1037 {
1038 if( nNewWidth < 0 )
1039 {
1040 nRest += 1 - nNewWidth;
1041 nNewWidth = 1;
1042 }
1043 SwFormatFrameSize aFormatFrameSize( pBox->GetFrameFormat()->GetFrameSize() );
1044 aFormatFrameSize.SetWidth( nNewWidth );
1045 rParm.aShareFormats.SetSize( *pBox, aFormatFrameSize );
1046 }
1047 }
1048}
1049
1050static void lcl_CalcNewWidths( std::vector<sal_uInt16> &rSpanPos, ChangeList& rChanges,
1051 SwTableLine* pLine, long nWish, long nWidth, bool bTop )
1052{
1053 if( rChanges.empty() )
1054 {
1055 rSpanPos.clear();
1056 return;
1057 }
1058 if( rSpanPos.empty() )
1059 {
1060 rChanges.clear();
1061 return;
1062 }
1063 std::vector<sal_uInt16> aNewSpanPos;
1064 ChangeList aNewChanges;
1065 ChangeList::iterator pCurr = rChanges.begin();
1066 aNewChanges.push_back( *pCurr ); // Nullposition
1067 std::vector<sal_uInt16>::iterator pSpan = rSpanPos.begin();
1068 sal_uInt16 nCurr = 0;
1069 SwTwips nOrgSum = 0;
1070 bool bRowSpan = false;
1071 sal_uInt16 nRowSpanCount = 0;
1072 const size_t nCount = pLine->GetTabBoxes().size();
1073 for( size_t nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
1074 {
1075 SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
1076 SwTwips nCurrWidth = pBox->GetFrameFormat()->GetFrameSize().GetWidth();
1077 const long nRowSpan = pBox->getRowSpan();
1078 const bool bCurrRowSpan = bTop ? nRowSpan < 0 :
1079 ( nRowSpan > 1 || nRowSpan < -1 );
1080 if( bRowSpan || bCurrRowSpan )
1081 aNewSpanPos.push_back( nRowSpanCount );
1082 bRowSpan = bCurrRowSpan;
1083 nOrgSum += nCurrWidth;
1084 const sal_uInt16 nPos = lcl_MulDiv64<sal_uInt16>(
1085 lcl_MulDiv64<sal_uInt64>(nOrgSum, nWidth, nWish),
1086 nWish, nWidth);
1087 while( pCurr != rChanges.end() && pCurr->first < nPos )
1088 {
1089 ++nCurr;
1090 ++pCurr;
1091 }
1092 bool bNew = true;
1093 if( pCurr != rChanges.end() && pCurr->first <= nPos &&
1094 pCurr->first != pCurr->second )
1095 {
1096 pSpan = std::find_if(pSpan, rSpanPos.end(),
1097 [nCurr](const sal_uInt16 nSpan) { return nSpan >= nCurr; });
1098 if( pSpan != rSpanPos.end() && *pSpan == nCurr )
1099 {
1100 aNewChanges.push_back( *pCurr );
1101 ++nRowSpanCount;
1102 bNew = false;
1103 }
1104 }
1105 if( bNew )
1106 {
1107 ColChange aTmp( nPos, nPos );
1108 aNewChanges.push_back( aTmp );
1109 ++nRowSpanCount;
1110 }
1111 }
1112
1113 pCurr = aNewChanges.begin();
1114 ChangeList::iterator pLast = pCurr;
1115 ChangeList::iterator pLeftMove = pCurr;
1116 while( pCurr != aNewChanges.end() )
1117 {
1118 if( pLeftMove == pCurr )
1119 {
1120 while( ++pLeftMove != aNewChanges.end() && pLeftMove->first <= pLeftMove->second )
1121 ;
1122 }
1123 if( pCurr->second == pCurr->first )
1124 {
1125 if( pLeftMove != aNewChanges.end() && pCurr->second > pLeftMove->second )
1126 {
1127 if( pLeftMove->first == pLast->first )
1128 pCurr->second = pLeftMove->second;
1129 else
1130 {
1131 pCurr->second = lcl_MulDiv64<sal_uInt16>(
1132 pCurr->first - pLast->first,
1133 pLeftMove->second - pLast->second,
1134 pLeftMove->first - pLast->first) + pLast->second;
1135 }
1136 }
1137 pLast = pCurr;
1138 ++pCurr;
1139 }
1140 else if( pCurr->second > pCurr->first )
1141 {
1142 pLast = pCurr;
1143 ++pCurr;
1144 ChangeList::iterator pNext = pCurr;
1145 while( pNext != pLeftMove && pNext->second == pNext->first &&
1146 pNext->second < pLast->second )
1147 ++pNext;
1148 while( pCurr != pNext )
1149 {
1150 if( pNext == aNewChanges.end() || pNext->first == pLast->first )
1151 pCurr->second = pLast->second;
1152 else
1153 {
1154 pCurr->second = lcl_MulDiv64<sal_uInt16>(
1155 pCurr->first - pLast->first,
1156 pNext->second - pLast->second,
1157 pNext->first - pLast->first) + pLast->second;
1158 }
1159 ++pCurr;
1160 }
1161 pLast = pCurr;
1162 }
1163 else
1164 {
1165 pLast = pCurr;
1166 ++pCurr;
1167 }
1168 }
1169
1170 rChanges.swap(aNewChanges);
1171 rSpanPos.swap(aNewSpanPos);
1172}
1173
1174void SwTable::NewSetTabCols( Parm &rParm, const SwTabCols &rNew,
1175 const SwTabCols &rOld, const SwTableBox *pStart, bool bCurRowOnly )
1176{
1177#if OSL_DEBUG_LEVEL1 > 1
1178 static int nCallCount = 0;
1179 ++nCallCount;
1180#endif
1181 // First step: evaluate which lines have been moved/which widths changed
1182 ChangeList aOldNew;
1183 const long nNewWidth = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1184 const long nOldWidth = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1185 if( nNewWidth < 1 || nOldWidth < 1 )
1186 return;
1187 for( size_t i = 0; i <= rOld.Count(); ++i )
1188 {
1189 long nNewPos;
1190 long nOldPos;
1191 if( i == rOld.Count() )
1192 {
1193 nOldPos = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1194 nNewPos = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1195 }
1196 else
1197 {
1198 nOldPos = rOld[i] - rParm.rOld.GetLeft();
1199 nNewPos = rNew[i] - rParm.rNew.GetLeft();
1200 }
1201 nNewPos = lcl_MulDiv64<long>(nNewPos, rParm.nNewWish, nNewWidth);
1202 nOldPos = lcl_MulDiv64<long>(nOldPos, rParm.nOldWish, nOldWidth);
1203 if( nOldPos != nNewPos && nNewPos > 0 && nOldPos > 0 )
1204 {
1205 ColChange aChg( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) );
1206 aOldNew.push_back( aChg );
1207 }
1208 }
1209 // Finished first step
1210 int nCount = aOldNew.size();
1211 if( !nCount )
1212 return; // no change, nothing to do
1213 SwTableLines &rLines = GetTabLines();
1214 if( bCurRowOnly )
1215 {
1216 const SwTableLine* pCurrLine = pStart->GetUpper();
1217 sal_uInt16 nCurr = rLines.GetPos( pCurrLine );
1218 if( nCurr >= USHRT_MAX(32767 *2 +1) )
1219 return;
1220
1221 ColChange aChg( 0, 0 );
1222 aOldNew.push_front( aChg );
1223 std::vector<sal_uInt16> aRowSpanPos;
1224 if( nCurr )
1225 {
1226 ChangeList aCopy;
1227 sal_uInt16 nPos = 0;
1228 for( const auto& rCop : aOldNew )
1229 {
1230 aCopy.push_back( rCop );
1231 aRowSpanPos.push_back( nPos++ );
1232 }
1233 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1234 rParm.nOldWish, nOldWidth, true );
1235 bool bGoOn = !aRowSpanPos.empty();
1236 sal_uInt16 j = nCurr;
1237 while( bGoOn )
1238 {
1239 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[--j],
1240 rParm.nOldWish, nOldWidth, true );
1241 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1242 bGoOn = !aRowSpanPos.empty() && j > 0;
1243 }
1244 aRowSpanPos.clear();
1245 }
1246 if( nCurr+1 < static_cast<sal_uInt16>(rLines.size()) )
1247 {
1248 ChangeList aCopy;
1249 sal_uInt16 nPos = 0;
1250 for( const auto& rCop : aOldNew )
1251 {
1252 aCopy.push_back( rCop );
1253 aRowSpanPos.push_back( nPos++ );
1254 }
1255 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1256 rParm.nOldWish, nOldWidth, false );
1257 bool bGoOn = !aRowSpanPos.empty();
1258 sal_uInt16 j = nCurr;
1259 while( bGoOn )
1260 {
1261 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[++j],
1262 rParm.nOldWish, nOldWidth, false );
1263 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1264 bGoOn = !aRowSpanPos.empty() && j+1 < static_cast<sal_uInt16>(rLines.size());
1265 }
1266 }
1267 ::lcl_AdjustWidthsInLine( rLines[nCurr], aOldNew, rParm, COLFUZZY20 );
1268 }
1269 else
1270 {
1271 for( size_t i = 0; i < rLines.size(); ++i )
1272 ::lcl_AdjustWidthsInLine( rLines[i], aOldNew, rParm, COLFUZZY20 );
1273 }
1274 CHECK_TABLE( *this )
1275}
1276
1277// return the pointer of the box specified.
1278static bool lcl_IsValidRowName( const OUString& rStr )
1279{
1280 bool bIsValid = true;
1281 sal_Int32 nLen = rStr.getLength();
1282 for( sal_Int32 i = 0; i < nLen && bIsValid; ++i )
1283 {
1284 const sal_Unicode cChar = rStr[i];
1285 if (cChar < '0' || cChar > '9')
1286 bIsValid = false;
1287 }
1288 return bIsValid;
1289}
1290
1291// #i80314#
1292// add 3rd parameter and its handling
1293sal_uInt16 SwTable::GetBoxNum( OUString& rStr, bool bFirstPart,
1294 const bool bPerformValidCheck )
1295{
1296 sal_uInt16 nRet = 0;
1297 if( bFirstPart ) // true == column; false == row
1298 {
1299 sal_Int32 nPos = 0;
1300 // the first one uses letters for addressing!
1301 bool bFirst = true;
1302 sal_uInt32 num = 0;
1303 bool overflow = false;
1304 while (nPos<rStr.getLength())
1305 {
1306 sal_Unicode cChar = rStr[nPos];
1307 if ((cChar<'A' || cChar>'Z') && (cChar<'a' || cChar>'z'))
1308 break;
1309 cChar -= 'A';
1310 if( cChar >= 26 )
1311 cChar -= 'a' - '[';
1312 if( bFirst )
1313 bFirst = false;
1314 else
1315 ++num;
1316 num = num * 52 + cChar;
1317 if (num > SAL_MAX_UINT16((sal_uInt16) 0xFFFF)) {
1318 overflow = true;
1319 }
1320 ++nPos;
1321 }
1322 nRet = overflow ? SAL_MAX_UINT16((sal_uInt16) 0xFFFF) : num;
1323 rStr = rStr.copy( nPos ); // Remove char from String
1324 }
1325 else
1326 {
1327 const sal_Int32 nPos = rStr.indexOf( "." );
1328 if ( nPos<0 )
1329 {
1330 nRet = 0;
1331 if ( !bPerformValidCheck || lcl_IsValidRowName( rStr ) )
1332 {
1333 nRet = static_cast<sal_uInt16>(rStr.toInt32());
1334 }
1335 rStr.clear();
1336 }
1337 else
1338 {
1339 nRet = 0;
1340 const OUString aText( rStr.copy( 0, nPos ) );
1341 if ( !bPerformValidCheck || lcl_IsValidRowName( aText ) )
1342 {
1343 nRet = static_cast<sal_uInt16>(aText.toInt32());
1344 }
1345 rStr = rStr.copy( nPos+1 );
1346 }
1347 }
1348 return nRet;
1349}
1350
1351// #i80314#
1352// add 2nd parameter and its handling
1353const SwTableBox* SwTable::GetTableBox( const OUString& rName,
1354 const bool bPerformValidCheck ) const
1355{
1356 const SwTableBox* pBox = nullptr;
1357 const SwTableLine* pLine;
1358 const SwTableLines* pLines;
1359
1360 sal_uInt16 nLine, nBox;
1361 OUString aNm( rName );
1362 while( !aNm.isEmpty() )
1363 {
1364 nBox = SwTable::GetBoxNum( aNm, nullptr == pBox, bPerformValidCheck );
1365 // first box ?
1366 if( !pBox )
1367 pLines = &GetTabLines();
1368 else
1369 {
1370 pLines = &pBox->GetTabLines();
1371 if( nBox )
1372 --nBox;
1373 }
1374
1375 nLine = SwTable::GetBoxNum( aNm, false, bPerformValidCheck );
1376
1377 // determine line
1378 if( !nLine || nLine > pLines->size() )
1379 return nullptr;
1380 pLine = (*pLines)[ nLine-1 ];
1381
1382 // determine box
1383 const SwTableBoxes* pBoxes = &pLine->GetTabBoxes();
1384 if( nBox >= pBoxes->size() )
1385 return nullptr;
1386 pBox = (*pBoxes)[ nBox ];
1387 }
1388
1389 // check if the box found has any contents
1390 if( pBox && !pBox->GetSttNd() )
1391 {
1392 OSL_FAIL( "Box without content, looking for the next one!" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
":" "1392" ": "), "%s", "Box without content, looking for the next one!"
); } } while (false)
;
1393 // "drop this" until the first box
1394 while( !pBox->GetTabLines().empty() )
1395 pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
1396 }
1397 return pBox;
1398}
1399
1400SwTableBox* SwTable::GetTableBox( sal_uLong nSttIdx )
1401{
1402 // For optimizations, don't always process the entire SortArray.
1403 // Converting text to table, tries certain conditions
1404 // to ask for a table box of a table that is not yet having a format
1405 if(!GetFrameFormat())
1406 return nullptr;
1407 SwTableBox* pRet = nullptr;
1408 SwNodes& rNds = GetFrameFormat()->GetDoc()->GetNodes();
1409 sal_uLong nIndex = nSttIdx + 1;
1410 SwContentNode* pCNd = nullptr;
1411 SwTableNode* pTableNd = nullptr;
1412
1413 while ( nIndex < rNds.Count() )
1414 {
1415 pTableNd = rNds[ nIndex ]->GetTableNode();
1416 if ( pTableNd )
1417 break;
1418
1419 pCNd = rNds[ nIndex ]->GetContentNode();
1420 if ( pCNd )
1421 break;
1422
1423 ++nIndex;
1424 }
1425
1426 if ( pCNd || pTableNd )
1427 {
1428 SwModify* pModify = pCNd;
1429 // #144862# Better handling of table in table
1430 if ( pTableNd && pTableNd->GetTable().GetFrameFormat() )
1431 pModify = pTableNd->GetTable().GetFrameFormat();
1432
1433 SwFrame* pFrame = pModify ? SwIterator<SwFrame,SwModify>(*pModify).First() : nullptr;
1434 while ( pFrame && !pFrame->IsCellFrame() )
1435 pFrame = pFrame->GetUpper();
1436 if ( pFrame )
1437 pRet = const_cast<SwTableBox*>(static_cast<SwCellFrame*>(pFrame)->GetTabBox());
1438 }
1439
1440 // In case the layout doesn't exist yet or anything else goes wrong.
1441 if ( !pRet )
1442 {
1443 for (size_t n = m_TabSortContentBoxes.size(); n; )
1444 {
1445 if (m_TabSortContentBoxes[ --n ]->GetSttIdx() == nSttIdx)
1446 {
1447 return m_TabSortContentBoxes[ n ];
1448 }
1449 }
1450 }
1451 return pRet;
1452}
1453
1454bool SwTable::IsTableComplex() const
1455{
1456 // Returns true for complex tables, i.e. tables that contain nestings,
1457 // like containing boxes not part of the first line, e.g. results of
1458 // splits/merges which lead to more complex structures.
1459 for (size_t n = 0; n < m_TabSortContentBoxes.size(); ++n)
1460 {
1461 if (m_TabSortContentBoxes[ n ]->GetUpper()->GetUpper())
1462 {
1463 return true;
1464 }
1465 }
1466 return false;
1467}
1468
1469SwTableLine::SwTableLine( SwTableLineFormat *pFormat, sal_uInt16 nBoxes,
1470 SwTableBox *pUp )
1471 : SwClient( pFormat ),
1472 m_aBoxes(),
1473 m_pUpper( pUp )
1474{
1475 m_aBoxes.reserve( nBoxes );
1476}
1477
1478SwTableLine::~SwTableLine()
1479{
1480 for (size_t i = 0; i < m_aBoxes.size(); ++i)
1481 {
1482 delete m_aBoxes[i];
1483 }
1484 // the TabelleLine can be deleted if it's the last client of the FrameFormat
1485 SwModify* pMod = GetFrameFormat();
1486 pMod->Remove( this ); // remove,
1487 if( !pMod->HasWriterListeners() )
1488 delete pMod; // and delete
1489}
1490
1491SwFrameFormat* SwTableLine::ClaimFrameFormat()
1492{
1493 // This method makes sure that this object is an exclusive SwTableLine client
1494 // of an SwTableLineFormat object
1495 // If other SwTableLine objects currently listen to the same SwTableLineFormat as
1496 // this one, something needs to be done
1497 SwTableLineFormat *pRet = static_cast<SwTableLineFormat*>(GetFrameFormat());
1498 SwIterator<SwTableLine,SwFormat> aIter( *pRet );
1499 for( SwTableLine* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1500 {
1501 if ( pLast != this )
1502 {
1503 // found another SwTableLine that is a client of the current Format
1504 // create a new Format as a copy and use it for this object
1505 SwTableLineFormat *pNewFormat = pRet->GetDoc()->MakeTableLineFormat();
1506 *pNewFormat = *pRet;
1507
1508 // register SwRowFrames that know me as clients at the new Format
1509 SwIterator<SwRowFrame,SwFormat> aFrameIter( *pRet );
1510 for( SwRowFrame* pFrame = aFrameIter.First(); pFrame; pFrame = aFrameIter.Next() )
1511 if( pFrame->GetTabLine() == this )
1512 pFrame->RegisterToFormat( *pNewFormat );
1513
1514 // register myself
1515 pNewFormat->Add( this );
1516 pRet = pNewFormat;
1517 break;
1518 }
1519 }
1520
1521 return pRet;
1522}
1523
1524void SwTableLine::ChgFrameFormat( SwTableLineFormat *pNewFormat )
1525{
1526 SwFrameFormat *pOld = GetFrameFormat();
1527 SwIterator<SwRowFrame,SwFormat> aIter( *pOld );
1528
1529 // First, re-register the Frames.
1530 for( SwRowFrame* pRow = aIter.First(); pRow; pRow = aIter.Next() )
1531 {
1532 if( pRow->GetTabLine() == this )
1533 {
1534 pRow->RegisterToFormat( *pNewFormat );
1535
1536 pRow->InvalidateSize();
1537 pRow->InvalidatePrt_();
1538 pRow->SetCompletePaint();
1539 pRow->ReinitializeFrameSizeAttrFlags();
1540
1541 // #i35063#
1542 // consider 'split row allowed' attribute
1543 SwTabFrame* pTab = pRow->FindTabFrame();
1544 bool bInFollowFlowRow = false;
1545 const bool bInFirstNonHeadlineRow = pTab->IsFollow() &&
1546 pRow == pTab->GetFirstNonHeadlineRow();
1547 if ( bInFirstNonHeadlineRow ||
1548 !pRow->GetNext() ||
1549 ( bInFollowFlowRow = pRow->IsInFollowFlowRow() ) ||
1550 nullptr != pRow->IsInSplitTableRow() )
1551 {
1552 if ( bInFirstNonHeadlineRow || bInFollowFlowRow )
1553 pTab = pTab->FindMaster();
1554
1555 pTab->SetRemoveFollowFlowLinePending( true );
1556 pTab->InvalidatePos();
1557 }
1558 }
1559 }
1560
1561 // Now, re-register self.
1562 pNewFormat->Add( this );
1563
1564 if ( !pOld->HasWriterListeners() )
1565 delete pOld;
1566}
1567
1568SwTwips SwTableLine::GetTableLineHeight( bool& bLayoutAvailable ) const
1569{
1570 SwTwips nRet = 0;
1571 bLayoutAvailable = false;
1572 SwIterator<SwRowFrame,SwFormat> aIter( *GetFrameFormat() );
1
Calling constructor for 'SwIterator<SwRowFrame, SwFormat, sw::IteratorMode::Exact>'
16
Returning from constructor for 'SwIterator<SwRowFrame, SwFormat, sw::IteratorMode::Exact>'
1573 // A row could appear several times in headers/footers so only one chain of master/follow tables
1574 // will be accepted...
1575 const SwTabFrame* pChain = nullptr; // My chain
1576 for( SwRowFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
17
Calling 'SwIterator::First'
29
Returning from 'SwIterator::First'
30
Loop condition is true. Entering loop body
1577 {
1578 if( pLast->GetTabLine() == this )
31
Assuming the condition is true
32
Taking true branch
1579 {
1580 const SwTabFrame* pTab = pLast->FindTabFrame();
33
Calling 'SwFrame::FindTabFrame'
38
Returning from 'SwFrame::FindTabFrame'
39
'pTab' initialized here
1581 bLayoutAvailable = ( pTab && pTab->IsVertical() ) ?
40
Assuming 'pTab' is null
1582 ( 0 < pTab->getFrameArea().Height() ) :
1583 ( 0 < pTab->getFrameArea().Width() );
41
Called C++ object pointer is null
1584
1585 // The first one defines the chain, if a chain is defined, only members of the chain
1586 // will be added.
1587 if (pTab && (!pChain || pChain->IsAnFollow( pTab ) || pTab->IsAnFollow(pChain)))
1588 {
1589 pChain = pTab; // defines my chain (even it is already)
1590 if( pTab->IsVertical() )
1591 nRet += pLast->getFrameArea().Width();
1592 else
1593 nRet += pLast->getFrameArea().Height();
1594 // Optimization, if there are no master/follows in my chain, nothing more to add
1595 if( !pTab->HasFollow() && !pTab->IsFollow() )
1596 break;
1597 // This is not an optimization, this is necessary to avoid double additions of
1598 // repeating rows
1599 if( pTab->IsInHeadline(*pLast) )
1600 break;
1601 }
1602 }
1603 }
1604 return nRet;
1605}
1606
1607SwTableBox::SwTableBox( SwTableBoxFormat* pFormat, sal_uInt16 nLines, SwTableLine *pUp )
1608 : SwClient(nullptr)
1609 , m_aLines()
1610 , m_pStartNode(nullptr)
1611 , m_pUpper(pUp)
1612 , mnRowSpan(1)
1613 , mbDummyFlag(false)
1614 , mbDirectFormatting(false)
1615{
1616 m_aLines.reserve( nLines );
1617 CheckBoxFormat( pFormat )->Add( this );
1618}
1619
1620SwTableBox::SwTableBox( SwTableBoxFormat* pFormat, const SwNodeIndex &rIdx,
1621 SwTableLine *pUp )
1622 : SwClient(nullptr)
1623 , m_aLines()
1624 , m_pUpper(pUp)
1625 , mnRowSpan(1)
1626 , mbDummyFlag(false)
1627 , mbDirectFormatting(false)
1628{
1629 CheckBoxFormat( pFormat )->Add( this );
1630
1631 m_pStartNode = rIdx.GetNode().GetStartNode();
1632
1633 // insert into the table
1634 const SwTableNode* pTableNd = m_pStartNode->FindTableNode();
1635 assert(pTableNd && "In which table is that box?")(static_cast <bool> (pTableNd && "In which table is that box?"
) ? void (0) : __assert_fail ("pTableNd && \"In which table is that box?\""
, "/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
, 1635, __extension__ __PRETTY_FUNCTION__))
;
1636 SwTableSortBoxes& rSrtArr = const_cast<SwTableSortBoxes&>(pTableNd->GetTable().
1637 GetTabSortBoxes());
1638 SwTableBox* p = this; // error: &this
1639 rSrtArr.insert( p ); // insert
1640}
1641
1642SwTableBox::SwTableBox( SwTableBoxFormat* pFormat, const SwStartNode& rSttNd, SwTableLine *pUp )
1643 : SwClient(nullptr)
1644 , m_aLines()
1645 , m_pStartNode(&rSttNd)
1646 , m_pUpper(pUp)
1647 , mnRowSpan(1)
1648 , mbDummyFlag(false)
1649 , mbDirectFormatting(false)
1650{
1651 CheckBoxFormat( pFormat )->Add( this );
1652
1653 // insert into the table
1654 const SwTableNode* pTableNd = m_pStartNode->FindTableNode();
1655 OSL_ENSURE( pTableNd, "In which table is the box?" )do { if (true && (!(pTableNd))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
":" "1655" ": "), "%s", "In which table is the box?"); } } while
(false)
;
1656 SwTableSortBoxes& rSrtArr = const_cast<SwTableSortBoxes&>(pTableNd->GetTable().
1657 GetTabSortBoxes());
1658 SwTableBox* p = this; // error: &this
1659 rSrtArr.insert( p ); // insert
1660}
1661
1662void SwTableBox::RemoveFromTable()
1663{
1664 if (m_pStartNode) // box containing contents?
1665 {
1666 // remove from table
1667 const SwTableNode* pTableNd = m_pStartNode->FindTableNode();
1668 assert(pTableNd && "In which table is that box?")(static_cast <bool> (pTableNd && "In which table is that box?"
) ? void (0) : __assert_fail ("pTableNd && \"In which table is that box?\""
, "/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
, 1668, __extension__ __PRETTY_FUNCTION__))
;
1669 SwTableSortBoxes& rSrtArr = const_cast<SwTableSortBoxes&>(pTableNd->GetTable().
1670 GetTabSortBoxes());
1671 SwTableBox *p = this; // error: &this
1672 rSrtArr.erase( p ); // remove
1673 m_pStartNode = nullptr; // clear it so this is only run once
1674 }
1675}
1676
1677SwTableBox::~SwTableBox()
1678{
1679 if (!GetFrameFormat()->GetDoc()->IsInDtor())
1680 {
1681 RemoveFromTable();
1682 }
1683
1684 // the TabelleBox can be deleted if it's the last client of the FrameFormat
1685 SwModify* pMod = GetFrameFormat();
1686 pMod->Remove( this ); // remove,
1687 if( !pMod->HasWriterListeners() )
1688 delete pMod; // and delete
1689}
1690
1691SwTableBoxFormat* SwTableBox::CheckBoxFormat( SwTableBoxFormat* pFormat )
1692{
1693 // We might need to create a new format here, because the box must be
1694 // added to the format solely if pFormat has a value or form.
1695 if( SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_VALUE, false ) ||
1696 SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_FORMULA, false ) )
1697 {
1698 SwTableBox* pOther = SwIterator<SwTableBox,SwFormat>( *pFormat ).First();
1699 if( pOther )
1700 {
1701 SwTableBoxFormat* pNewFormat = pFormat->GetDoc()->MakeTableBoxFormat();
1702 pNewFormat->LockModify();
1703 *pNewFormat = *pFormat;
1704
1705 // Remove values and formulas
1706 pNewFormat->ResetFormatAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1707 pNewFormat->UnlockModify();
1708
1709 pFormat = pNewFormat;
1710 }
1711 }
1712 return pFormat;
1713}
1714
1715SwFrameFormat* SwTableBox::ClaimFrameFormat()
1716{
1717 // This method makes sure that this object is an exclusive SwTableBox client
1718 // of an SwTableBoxFormat object
1719 // If other SwTableBox objects currently listen to the same SwTableBoxFormat as
1720 // this one, something needs to be done
1721 SwTableBoxFormat *pRet = static_cast<SwTableBoxFormat*>(GetFrameFormat());
1722 SwIterator<SwTableBox,SwFormat> aIter( *pRet );
1723 for( SwTableBox* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1724 {
1725 if ( pLast != this )
1726 {
1727 // Found another SwTableBox object
1728 // create a new Format as a copy and assign me to it
1729 // don't copy values and formulas
1730 SwTableBoxFormat* pNewFormat = pRet->GetDoc()->MakeTableBoxFormat();
1731 pNewFormat->LockModify();
1732 *pNewFormat = *pRet;
1733 pNewFormat->ResetFormatAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1734 pNewFormat->UnlockModify();
1735
1736 // re-register SwCellFrame objects that know me
1737 SwIterator<SwCellFrame,SwFormat> aFrameIter( *pRet );
1738 for( SwCellFrame* pCell = aFrameIter.First(); pCell; pCell = aFrameIter.Next() )
1739 if( pCell->GetTabBox() == this )
1740 pCell->RegisterToFormat( *pNewFormat );
1741
1742 // re-register myself
1743 pNewFormat->Add( this );
1744 pRet = pNewFormat;
1745 break;
1746 }
1747 }
1748 return pRet;
1749}
1750
1751void SwTableBox::ChgFrameFormat( SwTableBoxFormat* pNewFormat, bool bNeedToReregister )
1752{
1753 SwFrameFormat *pOld = GetFrameFormat();
1754 SwIterator<SwCellFrame,SwFormat> aIter( *pOld );
1755
1756 // tdf#84635 We set bNeedToReregister=false to avoid a quadratic slowdown on loading large tables,
1757 // and since we are creating the table for the first time, no re-registration is necessary.
1758
1759 // First, re-register the Frames.
1760 if (bNeedToReregister)
1761 for( SwCellFrame* pCell = aIter.First(); pCell; pCell = aIter.Next() )
1762 {
1763 if( pCell->GetTabBox() == this )
1764 {
1765 pCell->RegisterToFormat( *pNewFormat );
1766 pCell->InvalidateSize();
1767 pCell->InvalidatePrt_();
1768 pCell->SetCompletePaint();
1769 pCell->SetDerivedVert( false );
1770 pCell->CheckDirChange();
1771
1772 // #i47489#
1773 // make sure that the row will be formatted, in order
1774 // to have the correct Get(Top|Bottom)MarginForLowers values
1775 // set at the row.
1776 const SwTabFrame* pTab = pCell->FindTabFrame();
1777 if ( pTab && pTab->IsCollapsingBorders() )
1778 {
1779 SwFrame* pRow = pCell->GetUpper();
1780 pRow->InvalidateSize_();
1781 pRow->InvalidatePrt_();
1782 }
1783 }
1784 }
1785
1786 // Now, re-register self.
1787 pNewFormat->Add( this );
1788
1789 if( !pOld->HasWriterListeners() )
1790 delete pOld;
1791}
1792
1793// Return the name of this box. This is determined dynamically
1794// resulting from the position in the lines/boxes/tables.
1795void sw_GetTableBoxColStr( sal_uInt16 nCol, OUString& rNm )
1796{
1797 const sal_uInt16 coDiff = 52; // 'A'-'Z' 'a' - 'z'
1798
1799 do {
1800 const sal_uInt16 nCalc = nCol % coDiff;
1801 if( nCalc >= 26 )
1802 rNm = OUStringChar( sal_Unicode('a' - 26 + nCalc) ) + rNm;
1803 else
1804 rNm = OUStringChar( sal_Unicode('A' + nCalc) ) + rNm;
1805
1806 nCol = nCol - nCalc;
1807 if( 0 == nCol )
1808 break;
1809 nCol /= coDiff;
1810 --nCol;
1811 } while( true );
1812}
1813
1814Point SwTableBox::GetCoordinates() const
1815{
1816 if( !m_pStartNode ) // box without content?
1817 {
1818 // search for the next first box?
1819 return Point( 0, 0 );
1820 }
1821
1822 const SwTable& rTable = m_pStartNode->FindTableNode()->GetTable();
1823 sal_uInt16 nX, nY;
1824 const SwTableBox* pBox = this;
1825 do {
1826 const SwTableLine* pLine = pBox->GetUpper();
1827 // at the first level?
1828 const SwTableLines* pLines = pLine->GetUpper()
1829 ? &pLine->GetUpper()->GetTabLines() : &rTable.GetTabLines();
1830
1831 nY = pLines->GetPos( pLine ) + 1 ;
1832 nX = pBox->GetUpper()->GetBoxPos( pBox ) + 1;
1833 pBox = pLine->GetUpper();
1834 } while( pBox );
1835 return Point( nX, nY );
1836}
1837
1838OUString SwTableBox::GetName() const
1839{
1840 if( !m_pStartNode ) // box without content?
1841 {
1842 // search for the next first box?
1843 return OUString();
1844 }
1845
1846 const SwTable& rTable = m_pStartNode->FindTableNode()->GetTable();
1847 sal_uInt16 nPos;
1848 OUString sNm, sTmp;
1849 const SwTableBox* pBox = this;
1850 do {
1851 const SwTableLine* pLine = pBox->GetUpper();
1852 // at the first level?
1853 const SwTableLines* pLines = pLine->GetUpper()
1854 ? &pLine->GetUpper()->GetTabLines() : &rTable.GetTabLines();
1855
1856 nPos = pLines->GetPos( pLine ) + 1;
1857 sTmp = OUString::number( nPos );
1858 if( !sNm.isEmpty() )
1859 sNm = sTmp + "." + sNm;
1860 else
1861 sNm = sTmp;
1862
1863 nPos = pBox->GetUpper()->GetBoxPos( pBox );
1864 sTmp = OUString::number(nPos + 1);
1865 pBox = pLine->GetUpper();
1866 if( nullptr != pBox )
1867 sNm = sTmp + "." + sNm;
1868 else
1869 sw_GetTableBoxColStr( nPos, sNm );
1870
1871 } while( pBox );
1872 return sNm;
1873}
1874
1875bool SwTableBox::IsInHeadline( const SwTable* pTable ) const
1876{
1877 if( !GetUpper() ) // should only happen upon merge.
1878 return false;
1879
1880 if( !pTable )
1881 pTable = &m_pStartNode->FindTableNode()->GetTable();
1882
1883 const SwTableLine* pLine = GetUpper();
1884 while( pLine->GetUpper() )
1885 pLine = pLine->GetUpper()->GetUpper();
1886
1887 // Headerline?
1888 return pTable->GetTabLines()[ 0 ] == pLine;
1889}
1890
1891sal_uLong SwTableBox::GetSttIdx() const
1892{
1893 return m_pStartNode ? m_pStartNode->GetIndex() : 0;
1894}
1895
1896 // retrieve information from the client
1897bool SwTable::GetInfo( SfxPoolItem& rInfo ) const
1898{
1899 switch( rInfo.Which() )
1900 {
1901 case RES_AUTOFMT_DOCNODE:
1902 {
1903 const SwTableNode* pNode = GetTableNode();
1904 if (pNode && &pNode->GetNodes() == static_cast<SwAutoFormatGetDocNode&>(rInfo).pNodes)
1905 {
1906 if (!m_TabSortContentBoxes.empty())
1907 {
1908 SwNodeIndex aIdx( *m_TabSortContentBoxes[0]->GetSttNd() );
1909 GetFrameFormat()->GetDoc()->GetNodes().GoNext( &aIdx );
1910 }
1911 return false;
1912 }
1913 break;
1914 }
1915 case RES_FINDNEARESTNODE:
1916 if( GetFrameFormat() &&
1917 GetFrameFormat()->GetFormatAttr( RES_PAGEDESC ).GetPageDesc() &&
1918 !m_TabSortContentBoxes.empty() &&
1919 m_TabSortContentBoxes[0]->GetSttNd()->GetNodes().IsDocNodes() )
1920 static_cast<SwFindNearestNode&>(rInfo).CheckNode( *
1921 m_TabSortContentBoxes[0]->GetSttNd()->FindTableNode() );
1922 break;
1923
1924 case RES_CONTENT_VISIBLE:
1925 static_cast<SwPtrMsgPoolItem&>(rInfo).pObject = SwIterator<SwFrame,SwFormat>( *GetFrameFormat() ).First();
1926 return false;
1927 }
1928 return true;
1929}
1930
1931SwTable * SwTable::FindTable( SwFrameFormat const*const pFormat )
1932{
1933 return pFormat
1934 ? SwIterator<SwTable,SwFormat>(*pFormat).First()
1935 : nullptr;
1936}
1937
1938SwTableNode* SwTable::GetTableNode() const
1939{
1940 return !GetTabSortBoxes().empty() ?
1941 const_cast<SwTableNode*>(GetTabSortBoxes()[ 0 ]->GetSttNd()->FindTableNode()) :
1942 m_pTableNode;
1943}
1944
1945void SwTable::SetRefObject( SwServerObject* pObj )
1946{
1947 if( m_xRefObj.is() )
1948 m_xRefObj->Closed();
1949
1950 m_xRefObj = pObj;
1951}
1952
1953void SwTable::SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout> const& r)
1954{
1955 m_xHTMLLayout = r;
1956}
1957
1958static void ChgTextToNum( SwTableBox& rBox, const OUString& rText, const Color* pCol,
1959 bool bChgAlign )
1960{
1961 sal_uLong nNdPos = rBox.IsValidNumTextNd();
1962 ChgTextToNum( rBox,rText,pCol,bChgAlign,nNdPos);
1963}
1964void ChgTextToNum( SwTableBox& rBox, const OUString& rText, const Color* pCol,
1965 bool bChgAlign,sal_uLong nNdPos )
1966{
1967
1968 if( ULONG_MAX(9223372036854775807L *2UL+1UL) == nNdPos )
1969 return;
1970
1971 SwDoc* pDoc = rBox.GetFrameFormat()->GetDoc();
1972 SwTextNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTextNode();
1973 const SfxPoolItem* pItem;
1974
1975 // assign adjustment
1976 if( bChgAlign )
1977 {
1978 pItem = &pTNd->SwContentNode::GetAttr( RES_PARATR_ADJUST );
1979 SvxAdjust eAdjust = static_cast<const SvxAdjustItem*>(pItem)->GetAdjust();
1980 if( SvxAdjust::Left == eAdjust || SvxAdjust::Block == eAdjust )
1981 {
1982 SvxAdjustItem aAdjust( *static_cast<const SvxAdjustItem*>(pItem) );
1983 aAdjust.SetAdjust( SvxAdjust::Right );
1984 pTNd->SetAttr( aAdjust );
1985 }
1986 }
1987
1988 // assign color or save "user color"
1989 if( !pTNd->GetpSwAttrSet() || SfxItemState::SET != pTNd->GetpSwAttrSet()->
1990 GetItemState( RES_CHRATR_COLOR, false, &pItem ))
1991 pItem = nullptr;
1992
1993 const Color* pOldNumFormatColor = rBox.GetSaveNumFormatColor();
1994 const Color* pNewUserColor = pItem ? &static_cast<const SvxColorItem*>(pItem)->GetValue() : nullptr;
1995
1996 if( ( pNewUserColor && pOldNumFormatColor &&
1997 *pNewUserColor == *pOldNumFormatColor ) ||
1998 ( !pNewUserColor && !pOldNumFormatColor ))
1999 {
2000 // Keep the user color, set updated values, delete old NumFormatColor if needed
2001 if( pCol )
2002 // if needed, set the color
2003 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2004 else if( pItem )
2005 {
2006 pNewUserColor = rBox.GetSaveUserColor();
2007 if( pNewUserColor )
2008 pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2009 else
2010 pTNd->ResetAttr( RES_CHRATR_COLOR );
2011 }
2012 }
2013 else
2014 {
2015 // Save user color, set NumFormat color if needed, but never reset the color
2016 rBox.SetSaveUserColor( pNewUserColor );
2017
2018 if( pCol )
2019 // if needed, set the color
2020 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2021
2022 }
2023 rBox.SetSaveNumFormatColor( pCol );
2024
2025 if( pTNd->GetText() != rText )
2026 {
2027 // Exchange text. Bugfix to keep Tabs (front and back!) and annotations (inword comment anchors)
2028 const OUString& rOrig = pTNd->GetText();
2029 sal_Int32 n;
2030
2031 for( n = 0; n < rOrig.getLength() && ('\x9' == rOrig[n] || CH_TXTATR_INWORDu'\xFFF9' == rOrig[n]); ++n )
2032 ;
2033 for( ; n < rOrig.getLength() && '\x01' == rOrig[n]; ++n )
2034 ;
2035 SwIndex aIdx( pTNd, n );
2036 for( n = rOrig.getLength(); n && ('\x9' == rOrig[--n] || CH_TXTATR_INWORDu'\xFFF9' == rOrig[n]); )
2037 ;
2038 sal_Int32 nEndPos = n;
2039 n -= aIdx.GetIndex() - 1;
2040
2041 // Reset DontExpand-Flags before exchange, to retrigger expansion
2042 {
2043 SwIndex aResetIdx( aIdx, n );
2044 pTNd->DontExpandFormat( aResetIdx, false, false );
2045 }
2046
2047 if( !pDoc->getIDocumentRedlineAccess().IsIgnoreRedline() && !pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty() )
2048 {
2049 SwPaM aTemp(*pTNd, 0, *pTNd, rOrig.getLength());
2050 pDoc->getIDocumentRedlineAccess().DeleteRedline(aTemp, true, RedlineType::Any);
2051 }
2052
2053 // preserve comments inside of the number by deleting number portions starting from the back
2054 sal_Int32 nCommentPos = pTNd->GetText().lastIndexOf( CH_TXTATR_INWORDu'\xFFF9', nEndPos );
2055 while( nCommentPos > aIdx.GetIndex() )
2056 {
2057 pTNd->EraseText( SwIndex(pTNd, nCommentPos+1), nEndPos - nCommentPos, SwInsertFlags::EMPTYEXPAND );
2058 // find the next non-sequential comment anchor
2059 do
2060 {
2061 nEndPos = nCommentPos;
2062 n = nEndPos - aIdx.GetIndex();
2063 nCommentPos = pTNd->GetText().lastIndexOf( CH_TXTATR_INWORDu'\xFFF9', nEndPos );
2064 --nEndPos;
2065 }
2066 while( nCommentPos > aIdx.GetIndex() && nCommentPos == nEndPos );
2067 }
2068
2069 pTNd->EraseText( aIdx, n, SwInsertFlags::EMPTYEXPAND );
2070 pTNd->InsertText( rText, aIdx, SwInsertFlags::EMPTYEXPAND );
2071
2072 if( pDoc->getIDocumentRedlineAccess().IsRedlineOn() )
2073 {
2074 SwPaM aTemp(*pTNd, 0, *pTNd, rText.getLength());
2075 pDoc->getIDocumentRedlineAccess().AppendRedline(new SwRangeRedline(RedlineType::Insert, aTemp), true);
2076 }
2077 }
2078
2079 // assign vertical orientation
2080 if( bChgAlign &&
2081 ( SfxItemState::SET != rBox.GetFrameFormat()->GetItemState(
2082 RES_VERT_ORIENT, true, &pItem ) ||
2083 text::VertOrientation::TOP == static_cast<const SwFormatVertOrient*>(pItem)->GetVertOrient() ))
2084 {
2085 rBox.GetFrameFormat()->SetFormatAttr( SwFormatVertOrient( 0, text::VertOrientation::BOTTOM ));
2086 }
2087
2088}
2089
2090static void ChgNumToText( SwTableBox& rBox, sal_uLong nFormat )
2091{
2092 sal_uLong nNdPos = rBox.IsValidNumTextNd( false );
2093 if( ULONG_MAX(9223372036854775807L *2UL+1UL) == nNdPos )
2094 return;
2095
2096 SwDoc* pDoc = rBox.GetFrameFormat()->GetDoc();
2097 SwTextNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTextNode();
2098 bool bChgAlign = pDoc->IsInsTableAlignNum();
2099 const SfxPoolItem* pItem;
2100
2101 const Color* pCol = nullptr;
2102 if( getSwDefaultTextFormat() != nFormat )
2103 {
2104 // special text format:
2105 OUString sTmp;
2106 const OUString sText( pTNd->GetText() );
2107 pDoc->GetNumberFormatter()->GetOutputString( sText, nFormat, sTmp, &pCol );
2108 if( sText != sTmp )
2109 {
2110 // exchange text
2111 SwIndex aIdx( pTNd, sText.getLength() );
2112 // Reset DontExpand-Flags before exchange, to retrigger expansion
2113 pTNd->DontExpandFormat( aIdx, false, false );
2114 aIdx = 0;
2115 pTNd->EraseText( aIdx, SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF), SwInsertFlags::EMPTYEXPAND );
2116 pTNd->InsertText( sTmp, aIdx, SwInsertFlags::EMPTYEXPAND );
2117 }
2118 }
2119
2120 const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet();
2121
2122 // assign adjustment
2123 if( bChgAlign && pAttrSet && SfxItemState::SET == pAttrSet->GetItemState(
2124 RES_PARATR_ADJUST, false, &pItem ) &&
2125 SvxAdjust::Right == static_cast<const SvxAdjustItem*>(pItem)->GetAdjust() )
2126 {
2127 pTNd->SetAttr( SvxAdjustItem( SvxAdjust::Left, RES_PARATR_ADJUST ) );
2128 }
2129
2130 // assign color or save "user color"
2131 if( !pAttrSet || SfxItemState::SET != pAttrSet->
2132 GetItemState( RES_CHRATR_COLOR, false, &pItem ))
2133 pItem = nullptr;
2134
2135 const Color* pOldNumFormatColor = rBox.GetSaveNumFormatColor();
2136 const Color* pNewUserColor = pItem ? &static_cast<const SvxColorItem*>(pItem)->GetValue() : nullptr;
2137
2138 if( ( pNewUserColor && pOldNumFormatColor &&
2139 *pNewUserColor == *pOldNumFormatColor ) ||
2140 ( !pNewUserColor && !pOldNumFormatColor ))
2141 {
2142 // Keep the user color, set updated values, delete old NumFormatColor if needed
2143 if( pCol )
2144 // if needed, set the color
2145 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2146 else if( pItem )
2147 {
2148 pNewUserColor = rBox.GetSaveUserColor();
2149 if( pNewUserColor )
2150 pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2151 else
2152 pTNd->ResetAttr( RES_CHRATR_COLOR );
2153 }
2154 }
2155 else
2156 {
2157 // Save user color, set NumFormat color if needed, but never reset the color
2158 rBox.SetSaveUserColor( pNewUserColor );
2159
2160 if( pCol )
2161 // if needed, set the color
2162 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2163
2164 }
2165 rBox.SetSaveNumFormatColor( pCol );
2166
2167 // assign vertical orientation
2168 if( bChgAlign &&
2169 SfxItemState::SET == rBox.GetFrameFormat()->GetItemState(
2170 RES_VERT_ORIENT, false, &pItem ) &&
2171 text::VertOrientation::BOTTOM == static_cast<const SwFormatVertOrient*>(pItem)->GetVertOrient() )
2172 {
2173 rBox.GetFrameFormat()->SetFormatAttr( SwFormatVertOrient( 0, text::VertOrientation::TOP ));
2174 }
2175
2176}
2177
2178// for detection of modifications (mainly TableBoxAttribute)
2179void SwTableBoxFormat::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
2180{
2181 if( !IsModifyLocked() && GetDoc() && !GetDoc()->IsInDtor())
2182 {
2183 const SwTableBoxNumFormat *pNewFormat = nullptr;
2184 const SwTableBoxFormula *pNewFormula = nullptr;
2185 const SwTableBoxValue *pNewVal = nullptr;
2186 sal_uLong nOldFormat = getSwDefaultTextFormat();
2187
2188 switch( pNew ? pNew->Which() : 0 )
2189 {
2190 case RES_ATTRSET_CHG:
2191 {
2192 const SfxItemSet& rSet = *static_cast<const SwAttrSetChg*>(pNew)->GetChgSet();
2193 if( SfxItemState::SET == rSet.GetItemState( RES_BOXATR_FORMAT,
2194 false, reinterpret_cast<const SfxPoolItem**>(&pNewFormat) ) )
2195 nOldFormat = static_cast<const SwAttrSetChg*>(pOld)->
2196 GetChgSet()->Get( RES_BOXATR_FORMAT ).GetValue();
2197 rSet.GetItemState( RES_BOXATR_FORMULA, false,
2198 reinterpret_cast<const SfxPoolItem**>(&pNewFormula) );
2199 rSet.GetItemState( RES_BOXATR_VALUE, false,
2200 reinterpret_cast<const SfxPoolItem**>(&pNewVal) );
2201 break;
2202 }
2203 case RES_BOXATR_FORMAT:
2204 pNewFormat = static_cast<const SwTableBoxNumFormat*>(pNew);
2205 nOldFormat = static_cast<const SwTableBoxNumFormat*>(pOld)->GetValue();
2206 break;
2207 case RES_BOXATR_FORMULA:
2208 pNewFormula = static_cast<const SwTableBoxFormula*>(pNew);
2209 break;
2210 case RES_BOXATR_VALUE:
2211 pNewVal = static_cast<const SwTableBoxValue*>(pNew);
2212 break;
2213 }
2214
2215 // something changed and some BoxAttribut remained in the set!
2216 if( pNewFormat || pNewFormula || pNewVal )
2217 {
2218 GetDoc()->getIDocumentFieldsAccess().SetFieldsDirty(true, nullptr, 0);
2219
2220 if( SfxItemState::SET == GetItemState( RES_BOXATR_FORMAT, false ) ||
2221 SfxItemState::SET == GetItemState( RES_BOXATR_VALUE, false ) ||
2222 SfxItemState::SET == GetItemState( RES_BOXATR_FORMULA, false ) )
2223 {
2224 // fetch the box
2225 SwIterator<SwTableBox,SwFormat> aIter( *this );
2226 SwTableBox* pBox = aIter.First();
2227 if( pBox )
2228 {
2229 OSL_ENSURE( !aIter.Next(), "zero or more than one box at format" )do { if (true && (!(!aIter.Next()))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/table/swtable.cxx"
":" "2229" ": "), "%s", "zero or more than one box at format"
); } } while (false)
;
2230
2231 sal_uLong nNewFormat;
2232 if( pNewFormat )
2233 {
2234 nNewFormat = pNewFormat->GetValue();
2235 // new formatting
2236 // is it newer or has the current been removed?
2237 if( SfxItemState::SET != GetItemState( RES_BOXATR_VALUE, false ))
2238 pNewFormat = nullptr;
2239 }
2240 else
2241 {
2242 // fetch the current Item
2243 (void)GetItemState(RES_BOXATR_FORMAT, false, reinterpret_cast<const SfxPoolItem**>(&pNewFormat));
2244 nOldFormat = GetTableBoxNumFormat().GetValue();
2245 nNewFormat = pNewFormat ? pNewFormat->GetValue() : nOldFormat;
2246 }
2247
2248 // is it newer or has the current been removed?
2249 if( pNewVal )
2250 {
2251 if( GetDoc()->GetNumberFormatter()->IsTextFormat(nNewFormat) )
2252 nOldFormat = 0;
2253 else
2254 {
2255 if( SfxItemState::SET == GetItemState( RES_BOXATR_VALUE, false ))
2256 nOldFormat = getSwDefaultTextFormat();
2257 else
2258 nNewFormat = getSwDefaultTextFormat();
2259 }
2260 }
2261
2262 // Logic:
2263 // Value change: -> "simulate" a format change!
2264 // Format change:
2265 // Text -> !Text or format change:
2266 // - align right for horizontal alignment, if LEFT or JUSTIFIED
2267 // - align bottom for vertical alignment, if TOP is set, or default
2268 // - replace text (color? negative numbers RED?)
2269 // !Text -> Text:
2270 // - align left for horizontal alignment, if RIGHT
2271 // - align top for vertical alignment, if BOTTOM is set
2272 SvNumberFormatter* pNumFormatr = GetDoc()->GetNumberFormatter();
2273 bool bNewIsTextFormat = pNumFormatr->IsTextFormat( nNewFormat );
2274
2275 if( (!bNewIsTextFormat && nOldFormat != nNewFormat) || pNewFormula )
2276 {
2277 bool bIsNumFormat = false;
2278 OUString aOrigText;
2279 bool bChgText = true;
2280 double fVal = 0;
2281 if( !pNewVal && SfxItemState::SET != GetItemState(
2282 RES_BOXATR_VALUE, false, reinterpret_cast<const SfxPoolItem**>(&pNewVal) ))
2283 {
2284 // so far, no value has been set, so try to evaluate the content
2285 sal_uLong nNdPos = pBox->IsValidNumTextNd();
2286 if( ULONG_MAX(9223372036854775807L *2UL+1UL) != nNdPos )
2287 {
2288 sal_uInt32 nTmpFormatIdx = nNewFormat;
2289 OUString aText( GetDoc()->GetNodes()[ nNdPos ]
2290 ->GetTextNode()->GetRedlineText());
2291 aOrigText = aText;
2292 if( aText.isEmpty() )
2293 bChgText = false;
2294 else
2295 {
2296 // Keep Tabs
2297 lcl_TabToBlankAtSttEnd( aText );
2298
2299 // JP 22.04.98: Bug 49659 -
2300 // Special casing for percent
2301 if( SvNumFormatType::PERCENT ==
2302 pNumFormatr->GetType( nNewFormat ))
2303 {
2304 sal_uInt32 nTmpFormat = 0;
2305 if( GetDoc()->IsNumberFormat(
2306 aText, nTmpFormat, fVal ))
2307 {
2308 if( SvNumFormatType::NUMBER ==
2309 pNumFormatr->GetType( nTmpFormat ))
2310 aText += "%";
2311
2312 bIsNumFormat = GetDoc()->IsNumberFormat(
2313 aText, nTmpFormatIdx, fVal );
2314 }
2315 }
2316 else
2317 bIsNumFormat = GetDoc()->IsNumberFormat(
2318 aText, nTmpFormatIdx, fVal );
2319
2320 if( bIsNumFormat )
2321 {
2322 // directly assign value - without Modify
2323 bool bIsLockMod = IsModifyLocked();
2324 LockModify();
2325 SetFormatAttr( SwTableBoxValue( fVal ));
2326 if( !bIsLockMod )
2327 UnlockModify();
2328 }
2329 }
2330 }
2331 }
2332 else
2333 {
2334 fVal = pNewVal->GetValue();
2335 bIsNumFormat = true;
2336 }
2337
2338 // format contents with the new value assigned and write to paragraph
2339 const Color* pCol = nullptr;
2340 OUString sNewText;
2341 if( DBL_MAX1.7976931348623157e+308 == fVal )
2342 {
2343 sNewText = SwViewShell::GetShellRes()->aCalc_Error;
2344 }
2345 else
2346 {
2347 if (bIsNumFormat)
2348 pNumFormatr->GetOutputString( fVal, nNewFormat, sNewText, &pCol );
2349 else
2350 {
2351 // Original text could not be parsed as
2352 // number/date/time/..., so keep the text.
2353#if 0
2354 // Actually the text should be formatted
2355 // according to the format, which may include
2356 // additional text from the format, for example
2357 // in {0;-0;"BAD: "@}. But other places when
2358 // entering a new value or changing text or
2359 // changing to a different format of type Text
2360 // don't do this (yet?).
2361 pNumFormatr->GetOutputString( aOrigText, nNewFormat, sNewText, &pCol );
2362#else
2363 sNewText = aOrigText;
2364#endif
2365 }
2366
2367 if( !bChgText )
2368 {
2369 sNewText.clear();
2370 }
2371 }
2372
2373 // across all boxes
2374 ChgTextToNum( *pBox, sNewText, pCol,
2375 GetDoc()->IsInsTableAlignNum() );
2376
2377 }
2378 else if( bNewIsTextFormat && nOldFormat != nNewFormat )
2379 {
2380 ChgNumToText( *pBox, nNewFormat );
2381 }
2382 }
2383 }
2384 }
2385 }
2386 // call base class
2387 SwFrameFormat::Modify( pOld, pNew );
2388}
2389
2390bool SwTableBoxFormat::supportsFullDrawingLayerFillAttributeSet() const
2391{
2392 return false;
2393}
2394
2395bool SwTableFormat::supportsFullDrawingLayerFillAttributeSet() const
2396{
2397 return false;
2398}
2399
2400bool SwTableLineFormat::supportsFullDrawingLayerFillAttributeSet() const
2401{
2402 return false;
2403}
2404
2405bool SwTableBox::HasNumContent( double& rNum, sal_uInt32& rFormatIndex,
2406 bool& rIsEmptyTextNd ) const
2407{
2408 bool bRet = false;
2409 sal_uLong nNdPos = IsValidNumTextNd();
2410 if( ULONG_MAX(9223372036854775807L *2UL+1UL) != nNdPos )
2411 {
2412 OUString aText( m_pStartNode->GetNodes()[ nNdPos ]->GetTextNode()->GetRedlineText() );
2413 // Keep Tabs
2414 lcl_TabToBlankAtSttEnd( aText );
2415 rIsEmptyTextNd = aText.isEmpty();
2416 SvNumberFormatter* pNumFormatr = GetFrameFormat()->GetDoc()->GetNumberFormatter();
2417
2418 const SfxPoolItem* pItem;
2419 if( SfxItemState::SET == GetFrameFormat()->GetItemState( RES_BOXATR_FORMAT, false, &pItem ))
2420 {
2421 rFormatIndex = static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue();
2422 // Special casing for percent
2423 if( !rIsEmptyTextNd && SvNumFormatType::PERCENT == pNumFormatr->GetType( rFormatIndex ))
2424 {
2425 sal_uInt32 nTmpFormat = 0;
2426 if( GetFrameFormat()->GetDoc()->IsNumberFormat( aText, nTmpFormat, rNum ) &&
2427 SvNumFormatType::NUMBER == pNumFormatr->GetType( nTmpFormat ))
2428 aText += "%";
2429 }
2430 }
2431 else
2432 rFormatIndex = 0;
2433
2434 bRet = GetFrameFormat()->GetDoc()->IsNumberFormat( aText, rFormatIndex, rNum );
2435 }
2436 else
2437 rIsEmptyTextNd = false;
2438 return bRet;
2439}
2440
2441bool SwTableBox::IsNumberChanged() const
2442{
2443 bool bRet = true;
2444
2445 if( SfxItemState::SET == GetFrameFormat()->GetItemState( RES_BOXATR_FORMULA, false ))
2446 {
2447 const SwTableBoxNumFormat *pNumFormat;
2448 const SwTableBoxValue *pValue;
2449
2450 if( SfxItemState::SET != GetFrameFormat()->GetItemState( RES_BOXATR_VALUE, false,
2451 reinterpret_cast<const SfxPoolItem**>(&pValue) ))
2452 pValue = nullptr;
2453 if( SfxItemState::SET != GetFrameFormat()->GetItemState( RES_BOXATR_FORMAT, false,
2454 reinterpret_cast<const SfxPoolItem**>(&pNumFormat) ))
2455 pNumFormat = nullptr;
2456
2457 sal_uLong nNdPos;
2458 if( pNumFormat && pValue && ULONG_MAX(9223372036854775807L *2UL+1UL) != ( nNdPos = IsValidNumTextNd() ) )
2459 {
2460 OUString sNewText, sOldText( m_pStartNode->GetNodes()[ nNdPos ]->
2461 GetTextNode()->GetRedlineText() );
2462 lcl_DelTabsAtSttEnd( sOldText );
2463
2464 const Color* pCol = nullptr;
2465 GetFrameFormat()->GetDoc()->GetNumberFormatter()->GetOutputString(
2466 pValue->GetValue(), pNumFormat->GetValue(), sNewText, &pCol );
2467
2468 bRet = sNewText != sOldText ||
2469 !( ( !pCol && !GetSaveNumFormatColor() ) ||
2470 ( pCol && GetSaveNumFormatColor() &&
2471 *pCol == *GetSaveNumFormatColor() ));
2472 }
2473 }
2474 return bRet;
2475}
2476
2477sal_uLong SwTableBox::IsValidNumTextNd( bool bCheckAttr ) const
2478{
2479 sal_uLong nPos = ULONG_MAX(9223372036854775807L *2UL+1UL);
2480 if( m_pStartNode )
2481 {
2482 SwNodeIndex aIdx( *m_pStartNode );
2483 sal_uLong nIndex = aIdx.GetIndex();
2484 const sal_uLong nIndexEnd = m_pStartNode->GetNodes()[ nIndex ]->EndOfSectionIndex();
2485 const SwTextNode *pTextNode = nullptr;
2486 while( ++nIndex < nIndexEnd )
2487 {
2488 const SwNode* pNode = m_pStartNode->GetNodes()[nIndex];
2489 if( pNode->IsTableNode() )
2490 {
2491 pTextNode = nullptr;
2492 break;
2493 }
2494 if( pNode->IsTextNode() )
2495 {
2496 if( pTextNode )
2497 {
2498 pTextNode = nullptr;
2499 break;
2500 }
2501 else
2502 {
2503 pTextNode = pNode->GetTextNode();
2504 nPos = nIndex;
2505 }
2506 }
2507 }
2508 if( pTextNode )
2509 {
2510 if( bCheckAttr )
2511 {
2512 const SwpHints* pHts = pTextNode->GetpSwpHints();
2513 // do some tests if there's only text in the node!
2514 // Flys/fields/...
2515 if( pHts )
2516 {
2517 sal_Int32 nNextSetField = 0;
2518 for( size_t n = 0; n < pHts->Count(); ++n )
2519 {
2520 const SwTextAttr* pAttr = pHts->Get(n);
2521 if( RES_TXTATR_NOEND_BEGIN <= pAttr->Which() )
2522 {
2523 if ( (pAttr->GetStart() == nNextSetField)
2524 && (pAttr->Which() == RES_TXTATR_FIELD))
2525 {
2526 // #i104949# hideous hack for report builder:
2527 // it inserts hidden variable-set fields at
2528 // the beginning of para in cell, but they
2529 // should not turn cell into text cell
2530 const SwField* pField = pAttr->GetFormatField().GetField();
2531 if (pField &&
2532 (pField->GetTypeId() == SwFieldTypesEnum::Set) &&
2533 (0 != (static_cast<SwSetExpField const*>
2534 (pField)->GetSubType() &
2535 nsSwExtendedSubType::SUB_INVISIBLE)))
2536 {
2537 nNextSetField = pAttr->GetStart() + 1;
2538 continue;
2539 }
2540 }
2541 else if( RES_TXTATR_ANNOTATION == pAttr->Which() )
2542 {
2543 continue;
2544 }
2545 nPos = ULONG_MAX(9223372036854775807L *2UL+1UL);
2546 break;
2547 }
2548 }
2549 }
2550 }
2551 }
2552 else
2553 nPos = ULONG_MAX(9223372036854775807L *2UL+1UL);
2554 }
2555 return nPos;
2556}
2557
2558// is this a Formula box or one with numeric content (AutoSum)
2559sal_uInt16 SwTableBox::IsFormulaOrValueBox() const
2560{
2561 sal_uInt16 nWhich = 0;
2562 const SwTextNode* pTNd;
2563 SwFrameFormat* pFormat = GetFrameFormat();
2564 if( SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_FORMULA, false ))
2565 nWhich = RES_BOXATR_FORMULA;
2566 else if( SfxItemState::SET == pFormat->GetItemState( RES_BOXATR_VALUE, false ) &&
2567 !pFormat->GetDoc()->GetNumberFormatter()->IsTextFormat(
2568 pFormat->GetTableBoxNumFormat().GetValue() ))
2569 nWhich = RES_BOXATR_VALUE;
2570 else if( m_pStartNode && m_pStartNode->GetIndex() + 2 == m_pStartNode->EndOfSectionIndex()
2571 && nullptr != ( pTNd = m_pStartNode->GetNodes()[ m_pStartNode->GetIndex() + 1 ]
2572 ->GetTextNode() ) && pTNd->GetText().isEmpty())
2573 nWhich = USHRT_MAX(32767 *2 +1);
2574
2575 return nWhich;
2576}
2577
2578void SwTableBox::ActualiseValueBox()
2579{
2580 const SfxPoolItem *pFormatItem, *pValItem;
2581 SwFrameFormat* pFormat = GetFrameFormat();
2582 if( SfxItemState::SET != pFormat->GetItemState( RES_BOXATR_FORMAT, true, &pFormatItem )
2583 || SfxItemState::SET != pFormat->GetItemState( RES_BOXATR_VALUE, true, &pValItem ))
2584 return;
2585
2586 const sal_uLong nFormatId = static_cast<const SwTableBoxNumFormat*>(pFormatItem)->GetValue();
2587 sal_uLong nNdPos = ULONG_MAX(9223372036854775807L *2UL+1UL);
2588 SvNumberFormatter* pNumFormatr = pFormat->GetDoc()->GetNumberFormatter();
2589
2590 if( !pNumFormatr->IsTextFormat( nFormatId ) &&
2591 ULONG_MAX(9223372036854775807L *2UL+1UL) != (nNdPos = IsValidNumTextNd()) )
2592 {
2593 double fVal = static_cast<const SwTableBoxValue*>(pValItem)->GetValue();
2594 const Color* pCol = nullptr;
2595 OUString sNewText;
2596 pNumFormatr->GetOutputString( fVal, nFormatId, sNewText, &pCol );
2597
2598 const OUString& rText = m_pStartNode->GetNodes()[ nNdPos ]->GetTextNode()->GetText();
2599 if( rText != sNewText )
2600 ChgTextToNum( *this, sNewText, pCol, false ,nNdPos);
2601 }
2602}
2603
2604struct SwTableCellInfo::Impl
2605{
2606 const SwTable * m_pTable;
2607 const SwCellFrame * m_pCellFrame;
2608 const SwTabFrame * m_pTabFrame;
2609 typedef o3tl::sorted_vector<const SwTableBox *> TableBoxes_t;
2610 TableBoxes_t m_HandledTableBoxes;
2611
2612public:
2613 Impl()
2614 : m_pTable(nullptr), m_pCellFrame(nullptr), m_pTabFrame(nullptr)
2615 {
2616 }
2617
2618 void setTable(const SwTable * pTable)
2619 {
2620 m_pTable = pTable;
2621 SwFrameFormat * pFrameFormat = m_pTable->GetFrameFormat();
2622 m_pTabFrame = SwIterator<SwTabFrame,SwFormat>(*pFrameFormat).First();
2623 if (m_pTabFrame && m_pTabFrame->IsFollow())
2624 m_pTabFrame = m_pTabFrame->FindMaster(true);
2625 }
2626
2627 const SwCellFrame * getCellFrame() const { return m_pCellFrame; }
2628
2629 const SwFrame * getNextFrameInTable(const SwFrame * pFrame);
2630 const SwCellFrame * getNextCellFrame(const SwFrame * pFrame);
2631 const SwCellFrame * getNextTableBoxsCellFrame(const SwFrame * pFrame);
2632 bool getNext();
2633};
2634
2635const SwFrame * SwTableCellInfo::Impl::getNextFrameInTable(const SwFrame * pFrame)
2636{
2637 const SwFrame * pResult = nullptr;
2638
2639 if (((! pFrame->IsTabFrame()) || pFrame == m_pTabFrame) && pFrame->GetLower())
2640 pResult = pFrame->GetLower();
2641 else if (pFrame->GetNext())
2642 pResult = pFrame->GetNext();
2643 else
2644 {
2645 while (pFrame->GetUpper() != nullptr)
2646 {
2647 pFrame = pFrame->GetUpper();
2648
2649 if (pFrame->IsTabFrame())
2650 {
2651 m_pTabFrame = static_cast<const SwTabFrame *>(pFrame)->GetFollow();
2652 pResult = m_pTabFrame;
2653 break;
2654 }
2655 else if (pFrame->GetNext())
2656 {
2657 pResult = pFrame->GetNext();
2658 break;
2659 }
2660 }
2661 }
2662
2663 return pResult;
2664}
2665
2666const SwCellFrame * SwTableCellInfo::Impl::getNextCellFrame(const SwFrame * pFrame)
2667{
2668 const SwCellFrame * pResult = nullptr;
2669
2670 while ((pFrame = getNextFrameInTable(pFrame)) != nullptr)
2671 {
2672 if (pFrame->IsCellFrame())
2673 {
2674 pResult = static_cast<const SwCellFrame *>(pFrame);
2675 break;
2676 }
2677 }
2678
2679 return pResult;
2680}
2681
2682const SwCellFrame * SwTableCellInfo::Impl::getNextTableBoxsCellFrame(const SwFrame * pFrame)
2683{
2684 const SwCellFrame * pResult = nullptr;
2685
2686 while ((pFrame = getNextCellFrame(pFrame)) != nullptr)
2687 {
2688 const SwCellFrame * pCellFrame = static_cast<const SwCellFrame *>(pFrame);
2689 const SwTableBox * pTabBox = pCellFrame->GetTabBox();
2690 auto aIt = m_HandledTableBoxes.insert(pTabBox);
2691 if (aIt.second)
2692 {
2693 pResult = pCellFrame;
2694 break;
2695 }
2696 }
2697
2698 return pResult;
2699}
2700
2701const SwCellFrame * SwTableCellInfo::getCellFrame() const
2702{
2703 return m_pImpl->getCellFrame();
2704}
2705
2706bool SwTableCellInfo::Impl::getNext()
2707{
2708 if (m_pCellFrame == nullptr)
2709 {
2710 if (m_pTabFrame != nullptr)
2711 m_pCellFrame = Impl::getNextTableBoxsCellFrame(m_pTabFrame);
2712 }
2713 else
2714 m_pCellFrame = Impl::getNextTableBoxsCellFrame(m_pCellFrame);
2715
2716 return m_pCellFrame != nullptr;
2717}
2718
2719SwTableCellInfo::SwTableCellInfo(const SwTable * pTable)
2720 : m_pImpl(std::make_unique<Impl>())
2721{
2722 m_pImpl->setTable(pTable);
2723}
2724
2725SwTableCellInfo::~SwTableCellInfo()
2726{
2727}
2728
2729bool SwTableCellInfo::getNext()
2730{
2731 return m_pImpl->getNext();
2732}
2733
2734SwRect SwTableCellInfo::getRect() const
2735{
2736 SwRect aRet;
2737
2738 if (getCellFrame() != nullptr)
2739 aRet = getCellFrame()->getFrameArea();
2740
2741 return aRet;
2742}
2743
2744const SwTableBox * SwTableCellInfo::getTableBox() const
2745{
2746 const SwTableBox * pRet = nullptr;
2747
2748 if (getCellFrame() != nullptr)
2749 pRet = getCellFrame()->GetTabBox();
2750
2751 return pRet;
2752}
2753
2754void SwTable::RegisterToFormat( SwFormat& rFormat )
2755{
2756 rFormat.Add( this );
2757}
2758
2759bool SwTable::HasLayout() const
2760{
2761 const SwFrameFormat* pFrameFormat = GetFrameFormat();
2762 //a table in a clipboard document doesn't have any layout information
2763 return pFrameFormat && SwIterator<SwTabFrame,SwFormat>(*pFrameFormat).First();
2764}
2765
2766void SwTableLine::RegisterToFormat( SwFormat& rFormat )
2767{
2768 rFormat.Add( this );
2769}
2770
2771void SwTableBox::RegisterToFormat( SwFormat& rFormat )
2772{
2773 rFormat.Add( this );
2774}
2775
2776// free's any remaining child objects
2777SwTableLines::~SwTableLines()
2778{
2779 for ( const_iterator it = begin(); it != end(); ++it )
2780 delete *it;
2781}
2782
2783/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/inc/calbck.hxx

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#ifndef INCLUDED_SW_INC_CALBCK_HXX
21#define INCLUDED_SW_INC_CALBCK_HXX
22
23#include <cassert>
24
25#include <svl/hint.hxx>
26#include <svl/broadcast.hxx>
27#include <svl/poolitem.hxx>
28#include "swdllapi.h"
29#include "ring.hxx"
30#include <type_traits>
31#include <vector>
32#include <memory>
33
34class SwModify;
35class SfxPoolItem;
36
37/*
38 SwModify and SwClient cooperate in propagating attribute changes.
39 If an attribute changes, the change is notified to all dependent
40 formats and other interested objects, e.g. Nodes. The clients will detect
41 if the change affects them. It could be that the changed attribute is
42 overruled in the receiving object so that its change does not become
43 effective or that the receiver is not interested in the particular attribute
44 in general (though probably in other attributes of the SwModify object they
45 are registered in).
46 As SwModify objects are derived from SwClient, they can create a chain of SwClient
47 objects where changes can get propagated through.
48 Each SwClient can be registered at only one SwModify object, while each SwModify
49 object is connected to a list of SwClient objects. If an object derived from SwClient
50 wants to get notifications from more than one SwModify object, it must create additional
51 SwClient objects. The SwDepend class allows to handle their notifications in the same
52 notification callback as it forwards the Modify() calls it receives to a "master"
53 SwClient implementation.
54 The SwIterator class allows to iterate over the SwClient objects registered at an
55 SwModify. For historical reasons its ability to use TypeInfo to restrict this iteration
56 to objects of a particular type created a lot of code that misuses SwClient-SwModify
57 relationships that basically should be used only for Modify/Notify callbacks.
58 This is still subject to refactoring.
59 */
60
61namespace sw
62{
63 class ClientIteratorBase;
64 struct LegacyModifyHint final: SfxHint
65 {
66 LegacyModifyHint(const SfxPoolItem* pOld, const SfxPoolItem* pNew) : m_pOld(pOld), m_pNew(pNew) {};
67 sal_uInt16 GetWhich() const { return m_pOld ? m_pOld->Which() : m_pNew ? m_pNew->Which() : 0; };
68 virtual ~LegacyModifyHint() override;
69 const SfxPoolItem* m_pOld;
70 const SfxPoolItem* m_pNew;
71 };
72 struct ModifyChangedHint final: SfxHint
73 {
74 ModifyChangedHint(const SwModify* pNew) : m_pNew(pNew) {};
75 virtual ~ModifyChangedHint() override;
76 const SwModify* m_pNew;
77 };
78 // Observer pattern using svl implementation
79 // use this instead of SwClient/SwModify wherever possible
80 // In writer layout, this might not always be possible,
81 // but for listeners outside of it (e.g. unocore) this should be used.
82 // The only "magic" signal this class issues is a ModifyChangedHint
83 // proclaiming its death. It does NOT however provide a new SwModify for
84 // listeners to switch to like the old SwModify/SwClient did, as that leads
85 // to madness.
86 class SW_DLLPUBLIC__attribute__ ((visibility("default"))) BroadcasterMixin {
87 SvtBroadcaster m_aNotifier;
88 public:
89 BroadcasterMixin() = default;
90 BroadcasterMixin(BroadcasterMixin const &) = default;
91 BroadcasterMixin& operator=(const BroadcasterMixin&)
92 {
93 return *this; // Listeners are never copied or moved.
94 }
95 SvtBroadcaster& GetNotifier() { return m_aNotifier; }
96 };
97 /// refactoring out the same of the more sane SwClient functionality
98 class SW_DLLPUBLIC__attribute__ ((visibility("default"))) WriterListener
99 {
100 friend class ::SwModify;
101 friend class ::sw::ClientIteratorBase;
102 private:
103 WriterListener* m_pLeft;
104 WriterListener* m_pRight; ///< double-linked list of other clients
105
106 WriterListener(WriterListener const&) = delete;
107 WriterListener& operator=(WriterListener const&) = delete;
108
109 protected:
110 WriterListener()
111 : m_pLeft(nullptr), m_pRight(nullptr)
112 {}
113 virtual ~WriterListener() COVERITY_NOEXCEPT_FALSE {}
114 virtual void SwClientNotify( const SwModify&, const SfxHint& rHint) =0;
115 public:
116 bool IsLast() const { return !m_pLeft && !m_pRight; }
117 };
118 enum class IteratorMode { Exact, UnwrapMulti };
119}
120
121// SwClient
122class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwClient : public ::sw::WriterListener
123{
124 // avoids making the details of the linked list and the callback method public
125 friend class SwModify;
126 friend class sw::ClientIteratorBase;
127 template<typename E, typename S, sw::IteratorMode> friend class SwIterator;
128
129 SwModify *m_pRegisteredIn; ///< event source
130
131protected:
132 // single argument ctors shall be explicit.
133 inline explicit SwClient( SwModify* pToRegisterIn );
134
135 // write access to pRegisteredIn shall be granted only to the object itself (protected access)
136 SwModify* GetRegisteredInNonConst() const { return m_pRegisteredIn; }
137
138public:
139 SwClient() : m_pRegisteredIn(nullptr) {}
140 SwClient(SwClient&&) noexcept;
141 virtual ~SwClient() override;
142 // callbacks received from SwModify (friend class - so these methods can be private)
143 // should be called only from SwModify the client is registered in
144 // mba: IMHO this method should be pure virtual
145 // DO NOT USE IN NEW CODE! use SwClientNotify instead.
146 virtual void Modify(const SfxPoolItem* pOldValue, const SfxPoolItem* pNewValue);
147 // when overriding this, you MUST call SwClient::SwClientModify() in the override!
148 virtual void SwClientNotify(const SwModify&, const SfxHint& rHint) override;
149
150 // in case an SwModify object is destroyed that itself is registered in another SwModify,
151 // its SwClient objects can decide to get registered to the latter instead by calling this method
152 std::unique_ptr<sw::ModifyChangedHint> CheckRegistration( const SfxPoolItem* pOldValue );
153
154 // controlled access to Modify method
155 // mba: this is still considered a hack and it should be fixed; the name makes grep-ing easier
156 virtual void ModifyNotification( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue ) { Modify ( pOldValue, pNewValue ); }
157 void SwClientNotifyCall( const SwModify& rModify, const SfxHint& rHint ) { SwClientNotify( rModify, rHint ); }
158
159 const SwModify* GetRegisteredIn() const { return m_pRegisteredIn; }
160 SwModify* GetRegisteredIn() { return m_pRegisteredIn; }
161 void EndListeningAll();
162 void StartListeningToSameModifyAs(const SwClient&);
163
164
165 // get information about attribute
166 virtual bool GetInfo( SfxPoolItem& ) const { return true; }
167};
168
169
170// SwModify
171
172// class has a doubly linked list for dependencies
173class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwModify: public SwClient
174{
175 friend class sw::ClientIteratorBase;
176 template<typename E, typename S, sw::IteratorMode> friend class SwIterator;
177 sw::WriterListener* m_pWriterListeners; // the start of the linked list of clients
178 bool m_bModifyLocked : 1; // don't broadcast changes now
179 bool m_bLockClientList : 1; // may be set when this instance notifies its clients
180 bool m_bInCache : 1;
181 bool m_bInSwFntCache : 1;
182
183 // mba: IMHO this method should be pure virtual
184 // DO NOT USE IN NEW CODE! use CallSwClientNotify instead.
185 virtual void Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew) override
186 { NotifyClients( pOld, pNew ); };
187
188 SwModify(SwModify const &) = delete;
189 SwModify &operator =(const SwModify&) = delete;
190public:
191 SwModify()
192 : SwClient(), m_pWriterListeners(nullptr), m_bModifyLocked(false), m_bLockClientList(false), m_bInCache(false), m_bInSwFntCache(false)
193 {}
194
195 // broadcasting: send notifications to all clients
196 // DO NOT USE IN NEW CODE! use CallSwClientNotify instead.
197 void NotifyClients( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue );
198 // the same, but without setting m_bModifyLocked or checking for any of the flags
199 // DO NOT USE IN NEW CODE! use CallSwClientNotify instead.
200 void ModifyBroadcast( const SfxPoolItem *pOldValue, const SfxPoolItem *pNewValue)
201 { CallSwClientNotify( sw::LegacyModifyHint{ pOldValue, pNewValue } ); };
202
203 // a more universal broadcasting mechanism
204 virtual void CallSwClientNotify( const SfxHint& rHint ) const;
205
206 virtual ~SwModify() override;
207
208 void Add(SwClient *pDepend);
209 SwClient* Remove(SwClient *pDepend);
210 bool HasWriterListeners() const { return m_pWriterListeners; }
211
212 // get information about attribute
213 virtual bool GetInfo( SfxPoolItem& ) const override;
214
215 void LockModify() { m_bModifyLocked = true; }
216 void UnlockModify() { m_bModifyLocked = false; }
217 void SetInCache( bool bNew ) { m_bInCache = bNew; }
218 void SetInSwFntCache( bool bNew ) { m_bInSwFntCache = bNew; }
219 void SetInDocDTOR();
220 bool IsModifyLocked() const { return m_bModifyLocked; }
221 bool IsInCache() const { return m_bInCache; }
222 bool IsInSwFntCache() const { return m_bInSwFntCache; }
223
224 void CheckCaching( const sal_uInt16 nWhich );
225 bool HasOnlyOneListener() const { return m_pWriterListeners && m_pWriterListeners->IsLast(); }
226};
227
228template<typename TElementType, typename TSource, sw::IteratorMode eMode> class SwIterator;
229
230namespace sw
231{
232 // this class is part of the migration: it still forwards the "old"
233 // SwModify events and announces them both to the old SwClients still
234 // registered and also to the new SvtListeners.
235 // Still: in the long run the SwClient/SwModify interface should not be
236 // used anymore, in which case a BroadcasterMixin should be enough instead
237 // then.
238 class SW_DLLPUBLIC__attribute__ ((visibility("default"))) BroadcastingModify : public SwModify, public BroadcasterMixin {
239 public:
240 virtual void CallSwClientNotify(const SfxHint& rHint) const override;
241 };
242 // this should be hidden but sadly SwIterator template needs it...
243 class ListenerEntry final : public SwClient
244 {
245 private:
246 template<typename E, typename S, sw::IteratorMode> friend class ::SwIterator;
247 SwClient *m_pToTell;
248
249 public:
250 ListenerEntry(SwClient *const pTellHim, SwModify *const pDepend)
251 : SwClient(pDepend), m_pToTell(pTellHim)
252 {}
253 ListenerEntry(ListenerEntry const &) = delete;
254 ListenerEntry& operator=(ListenerEntry const&) = delete;
255 ListenerEntry(ListenerEntry&& other) noexcept
256 : SwClient(std::move(other))
257 , m_pToTell(other.m_pToTell)
258 { }
259 ListenerEntry& operator=(ListenerEntry&& other) noexcept
260 {
261 m_pToTell = other.m_pToTell;
262 other.GetRegisteredIn()->Add(this);
263 other.EndListeningAll();
264 return *this;
265 }
266
267 /** get Client information */
268 virtual bool GetInfo( SfxPoolItem& rInfo) const override;
269 private:
270 virtual void Modify(const SfxPoolItem* pOldValue, const SfxPoolItem *pNewValue) override;
271 virtual void SwClientNotify(const SwModify& rModify, const SfxHint& rHint) override;
272 };
273
274 class SW_DLLPUBLIC__attribute__ ((visibility("default"))) WriterMultiListener final
275 {
276 SwClient& m_rToTell;
277 std::vector<ListenerEntry> m_vDepends;
278 public:
279 WriterMultiListener(SwClient& rToTell);
280 WriterMultiListener& operator=(WriterMultiListener const&) = delete; // MSVC2015 workaround
281 WriterMultiListener(WriterMultiListener const&) = delete; // MSVC2015 workaround
282 ~WriterMultiListener();
283 void StartListening(SwModify* pDepend);
284 void EndListening(SwModify* pDepend);
285 bool IsListeningTo(const SwModify* const pDepend) const;
286 void EndListeningAll();
287 };
288 class ClientIteratorBase : public sw::Ring< ::sw::ClientIteratorBase >
289 {
290 friend SwClient* SwModify::Remove(SwClient*);
291 friend void SwModify::Add(SwClient*);
292 protected:
293 const SwModify& m_rRoot;
294 // the current object in an iteration
295 WriterListener* m_pCurrent;
296 // in case the current object is already removed, the next object in the list
297 // is marked down to become the current object in the next step
298 // this is necessary because iteration requires access to members of the current object
299 WriterListener* m_pPosition;
300 static SW_DLLPUBLIC__attribute__ ((visibility("default"))) ClientIteratorBase* s_pClientIters;
301
302 ClientIteratorBase( const SwModify& rModify )
303 : m_rRoot(rModify)
304 {
305 MoveTo(s_pClientIters);
3
Calling 'Ring::MoveTo'
14
Returning from 'Ring::MoveTo'
306 s_pClientIters = this;
307 m_pCurrent = m_pPosition = m_rRoot.m_pWriterListeners;
308 }
309 WriterListener* GetLeftOfPos() { return m_pPosition->m_pLeft; }
310 WriterListener* GetRightOfPos() { return m_pPosition->m_pRight; }
311 WriterListener* GoStart()
312 {
313 m_pPosition = m_rRoot.m_pWriterListeners;
314 if(m_pPosition)
315 while( m_pPosition->m_pLeft )
316 m_pPosition = m_pPosition->m_pLeft;
317 m_pCurrent = m_pPosition;
318 return m_pCurrent;
319 }
320 ~ClientIteratorBase() override
321 {
322 assert(s_pClientIters)(static_cast <bool> (s_pClientIters) ? void (0) : __assert_fail
("s_pClientIters", "/home/maarten/src/libreoffice/core/sw/inc/calbck.hxx"
, 322, __extension__ __PRETTY_FUNCTION__))
;
323 if(s_pClientIters == this)
324 s_pClientIters = unique() ? nullptr : GetNextInRing();
325 MoveTo(nullptr);
326 }
327 // return "true" if an object was removed from a client chain in iteration
328 // adding objects to a client chain in iteration is forbidden
329 // SwModify::Add() asserts this
330 bool IsChanged() const { return m_pPosition != m_pCurrent; }
331 // ensures the iterator to point at a current client
332 WriterListener* Sync() { m_pCurrent = m_pPosition; return m_pCurrent; }
333 };
334}
335
336template<typename TElementType, typename TSource,
337 sw::IteratorMode eMode = sw::IteratorMode::Exact> class SwIterator final
338 : private sw::ClientIteratorBase
339{
340 //static_assert(!std::is_base_of<SwPageDesc,TSource>::value, "SwPageDesc as TSource is deprecated.");
341 static_assert(std::is_base_of<SwClient,TElementType>::value, "TElementType needs to be derived from SwClient.");
342 static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify.");
343public:
344 SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
2
Calling constructor for 'ClientIteratorBase'
15
Returning from constructor for 'ClientIteratorBase'
345 TElementType* First()
346 {
347 GoStart();
348 if(!m_pPosition)
18
Assuming field 'm_pPosition' is non-null, which participates in a condition later
19
Taking false branch
349 return nullptr;
350 m_pCurrent = nullptr;
351 return Next();
20
Calling 'SwIterator::Next'
27
Returning from 'SwIterator::Next'
28
Returning pointer, which participates in a condition later
352 }
353 TElementType* Next()
354 {
355 if(!IsChanged())
21
Taking false branch
356 m_pPosition = GetRightOfPos();
357 sw::WriterListener *pCurrent(m_pPosition);
358 while (m_pPosition)
22
Loop condition is true. Entering loop body
359 {
360 if (eMode
22.1
0 is not equal to UnwrapMulti
22.1
0 is not equal to UnwrapMulti
22.1
0 is not equal to UnwrapMulti
22.1
0 is not equal to UnwrapMulti
22.1
0 is not equal to UnwrapMulti
== sw::IteratorMode::UnwrapMulti)
23
Taking false branch
361 {
362 if (auto const pLE = dynamic_cast<sw::ListenerEntry const*>(m_pPosition))
363 {
364 pCurrent = pLE->m_pToTell;
365 }
366 }
367 if (dynamic_cast<const TElementType *>(pCurrent) == nullptr)
24
Taking false branch
368 {
369 m_pPosition = GetRightOfPos();
370 pCurrent = m_pPosition;
371 }
372 else
373 break;
25
Execution continues on line 375
374 }
375 Sync();
376 return static_cast<TElementType*>(pCurrent);
26
Returning pointer (loaded from 'pCurrent'), which participates in a condition later
377 }
378 using sw::ClientIteratorBase::IsChanged;
379};
380
381template< typename TSource > class SwIterator<SwClient, TSource> final : private sw::ClientIteratorBase
382{
383 static_assert(std::is_base_of<SwModify,TSource>::value, "TSource needs to be derived from SwModify");
384public:
385 SwIterator( const TSource& rSrc ) : sw::ClientIteratorBase(rSrc) {}
386 SwClient* First()
387 { return static_cast<SwClient*>(GoStart()); }
388 SwClient* Next()
389 {
390 if(!IsChanged())
391 m_pPosition = GetRightOfPos();
392 return static_cast<SwClient*>(Sync());
393 }
394 using sw::ClientIteratorBase::IsChanged;
395};
396
397SwClient::SwClient( SwModify* pToRegisterIn )
398 : m_pRegisteredIn( nullptr )
399{
400 if(pToRegisterIn)
401 pToRegisterIn->Add(this);
402}
403
404#endif
405
406/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/inc/ring.hxx

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#ifndef INCLUDED_SW_INC_RING_HXX
20#define INCLUDED_SW_INC_RING_HXX
21
22#include <utility>
23#include <sal/types.h>
24#include <iterator>
25#include <type_traits>
26#include <boost/iterator/iterator_facade.hpp>
27#include <boost/intrusive/circular_list_algorithms.hpp>
28
29namespace sw
30{
31 template <typename value_type> class RingContainer;
32 template <typename value_type> class RingIterator;
33 /**
34 * An intrusive container class double linking the contained nodes
35 * @example sw/qa/core/uwriter.cxx
36 */
37 template <typename value_type>
38 class SAL_WARN_UNUSED__attribute__((warn_unused)) Ring
39 {
40 public:
41 typedef typename std::add_const<value_type>::type const_value_type;
42 typedef RingContainer<value_type> ring_container;
43 typedef RingContainer<const_value_type> const_ring_container;
44 virtual ~Ring() COVERITY_NOEXCEPT_FALSE
45 { unlink(); };
46 /** algo::unlink is buggy! don't call it directly! */
47 void unlink()
48 {
49 algo::unlink(this);
5
Calling 'circular_list_algorithms::unlink'
10
Returning from 'circular_list_algorithms::unlink'
50 m_pNext = this; // don't leave pointers to old list behind!
51 m_pPrev = this;
52 }
53 /**
54 * Removes this item from its current ring container and adds it to
55 * another ring container. If the item was not alone in the original
56 * ring container, the other items in the ring will stay in the old
57 * ring container.
58 * Note: the newly created item will be inserted just before item pDestRing.
59 * @param pDestRing the container to add this item to
60 */
61 void MoveTo( value_type* pDestRing );
62 /** @return a stl-like container with begin()/end() for iteration */
63 ring_container GetRingContainer();
64 /** @return a stl-like container with begin()/end() for const iteration */
65 const_ring_container GetRingContainer() const;
66
67 protected:
68 /**
69 * Creates a new item in a ring container all by itself.
70 * Note: Ring instances can newer be outside a container. At most, they
71 * are alone in one.
72 */
73 Ring()
74 : m_pNext(this)
75 , m_pPrev(this)
76 { }
77 /**
78 * Creates a new item and add it to an existing ring container.
79 * Note: the newly created item will be inserted just before item pRing.
80 * @param pRing ring container to add the created item to
81 */
82 Ring( value_type* pRing );
83 /** @return the next item in the ring container */
84 value_type* GetNextInRing()
85 { return static_cast<value_type *>(m_pNext); }
86 /** @return the previous item in the ring container */
87 value_type* GetPrevInRing()
88 { return static_cast<value_type *>(m_pPrev); }
89 /** @return the next item in the ring container */
90 const_value_type* GetNextInRing() const
91 { return static_cast<value_type *>(m_pNext); }
92 /** @return the previous item in the ring container */
93 const_value_type* GetPrevInRing() const
94 { return static_cast<value_type *>(m_pPrev); }
95 /** @return true if and only if this item is alone in its ring */
96 bool unique() const
97 { return algo::unique(static_cast< const_value_type* >(this)); }
98
99 private:
100 /** internal implementation class -- not for external use */
101 struct Ring_node_traits
102 {
103 typedef Ring node;
104 typedef Ring* node_ptr;
105 typedef const Ring* const_node_ptr;
106 static node_ptr get_next(const_node_ptr n) { return const_cast<node_ptr>(n)->m_pNext; };
107 static void set_next(node_ptr n, node_ptr next) { n->m_pNext = next; };
108 static node_ptr get_previous(const_node_ptr n) { return const_cast<node_ptr>(n)->m_pPrev; };
109 static void set_previous(node_ptr n, node_ptr previous) { n->m_pPrev = previous; };
110 };
111 friend ring_container;
112 friend const_ring_container;
113 friend typename ring_container::iterator;
114 friend typename ring_container::const_iterator;
115 friend typename const_ring_container::iterator;
116 friend typename const_ring_container::const_iterator;
117 friend class boost::iterator_core_access;
118 typedef boost::intrusive::circular_list_algorithms<Ring_node_traits> algo;
119 Ring* m_pNext;
120 Ring* m_pPrev;
121 };
122
123 template <typename value_type>
124 inline Ring<value_type>::Ring( value_type* pObj )
125 : m_pNext(this)
126 , m_pPrev(this)
127 {
128 if( pObj )
129 {
130 algo::link_before(pObj, this);
131 }
132 }
133
134 template <typename value_type>
135 inline void Ring<value_type>::MoveTo(value_type* pDestRing)
136 {
137 value_type* pThis = static_cast< value_type* >(this);
138 unlink();
4
Calling 'Ring::unlink'
11
Returning from 'Ring::unlink'
139 // insert into "new"
140 if (pDestRing)
12
Assuming 'pDestRing' is null
13
Taking false branch
141 {
142 algo::link_before(pDestRing, pThis);
143 }
144 }
145
146 /**
147 * helper class that provides Svalue_typeL-style container iteration to the ring
148 */
149 template <typename value_type>
150 class SAL_WARN_UNUSED__attribute__((warn_unused)) RingContainer final
151 {
152 private:
153 /** the item in the ring where iteration starts */
154 value_type* m_pStart;
155 typedef typename std::remove_const<value_type>::type nonconst_value_type;
156
157 public:
158 RingContainer( value_type* pRing ) : m_pStart(pRing) {};
159 typedef RingIterator<value_type> iterator;
160 typedef RingIterator<const value_type> const_iterator;
161 /**
162 * iterator access
163 * @code
164 * for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
165 * do_stuff(rCurrentPaM); // this gets called on every SwPaM in the same ring as pPaM
166 * @endcode
167 */
168 iterator begin();
169 iterator end();
170 const_iterator begin() const;
171 const_iterator end() const;
172 /** @return the number of elements in the container */
173 size_t size() const
174 { return std::distance(begin(), end()); }
175 /**
176 * Merges two ring containers. All item from both ring containers will
177 * be in the same ring container in the end.
178 * Note: The items of this ring container will be inserted just before
179 * item pDestRing
180 * @param pDestRing the container to merge this container with
181 */
182 void merge( RingContainer< value_type > aDestRing )
183 {
184 // first check that we aren't merged already, swapping would
185 // actually un-merge in this case!
186 assert(m_pStart->m_pPrev != aDestRing.m_pStart)(static_cast <bool> (m_pStart->m_pPrev != aDestRing.
m_pStart) ? void (0) : __assert_fail ("m_pStart->m_pPrev != aDestRing.m_pStart"
, "/home/maarten/src/libreoffice/core/sw/inc/ring.hxx", 186, __extension__
__PRETTY_FUNCTION__))
;
187 assert(m_pStart != aDestRing.m_pStart->m_pPrev)(static_cast <bool> (m_pStart != aDestRing.m_pStart->
m_pPrev) ? void (0) : __assert_fail ("m_pStart != aDestRing.m_pStart->m_pPrev"
, "/home/maarten/src/libreoffice/core/sw/inc/ring.hxx", 187, __extension__
__PRETTY_FUNCTION__))
;
188 std::swap(m_pStart->m_pPrev->m_pNext, aDestRing.m_pStart->m_pPrev->m_pNext);
189 std::swap(m_pStart->m_pPrev, aDestRing.m_pStart->m_pPrev);
190 }
191 };
192
193 template <typename value_type>
194 class RingIterator final : public boost::iterator_facade<
195 RingIterator<value_type>
196 , value_type
197 , boost::forward_traversal_tag
198 >
199 {
200 private:
201 typedef typename std::remove_const<value_type>::type nonconst_value_type;
202 public:
203 RingIterator()
204 : m_pCurrent(nullptr)
205 , m_pStart(nullptr)
206 {}
207 explicit RingIterator(nonconst_value_type* pRing, bool bStart = true)
208 : m_pCurrent(nullptr)
209 , m_pStart(pRing)
210 {
211 if(!bStart)
212 m_pCurrent = m_pStart;
213 }
214
215 private:
216 friend class boost::iterator_core_access;
217 void increment()
218 { m_pCurrent = m_pCurrent ? m_pCurrent->GetNextInRing() : m_pStart->GetNextInRing(); }
219 bool equal(RingIterator const& other) const
220 {
221 // we never want to compare iterators from
222 // different rings or starting points
223 assert(m_pStart == other.m_pStart)(static_cast <bool> (m_pStart == other.m_pStart) ? void
(0) : __assert_fail ("m_pStart == other.m_pStart", "/home/maarten/src/libreoffice/core/sw/inc/ring.hxx"
, 223, __extension__ __PRETTY_FUNCTION__))
;
224 return m_pCurrent == other.m_pCurrent;
225 }
226 value_type& dereference() const
227 { return m_pCurrent ? *m_pCurrent : * m_pStart; }
228 /**
229 * value_type is:
230 * - pointing to the current item in the iteration in general
231 * - nullptr if on the first item (begin())
232 * - m_pStart when beyond the last item (end())
233 */
234 nonconst_value_type* m_pCurrent;
235 /** the first item of the iteration */
236 nonconst_value_type* m_pStart;
237 };
238
239 template <typename value_type>
240 inline typename Ring<value_type>::ring_container Ring<value_type>::GetRingContainer()
241 { return Ring<value_type>::ring_container(static_cast< value_type* >(this)); };
242
243 template <typename value_type>
244 inline typename Ring<value_type>::const_ring_container Ring<value_type>::GetRingContainer() const
245 { return Ring<value_type>::const_ring_container(static_cast< const_value_type* >(this)); };
246
247 template <typename value_type>
248 inline typename RingContainer<value_type>::iterator RingContainer<value_type>::begin()
249 { return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart)); };
250
251 template <typename value_type>
252 inline typename RingContainer<value_type>::iterator RingContainer<value_type>::end()
253 { return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
254
255 template <typename value_type>
256 inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::begin() const
257 { return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart)); };
258
259 template <typename value_type>
260 inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::end() const
261 { return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
262}
263#endif
264
265/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost/boost/intrusive/circular_list_algorithms.hpp

1/////////////////////////////////////////////////////////////////////////////
2//
3// (C) Copyright Olaf Krzikalla 2004-2006.
4// (C) Copyright Ion Gaztanaga 2006-2014
5//
6// Distributed under the Boost Software License, Version 1.0.
7// (See accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9//
10// See http://www.boost.org/libs/intrusive for documentation.
11//
12/////////////////////////////////////////////////////////////////////////////
13
14#ifndef BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP
15#define BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP
16
17#include <boost/intrusive/detail/config_begin.hpp>
18#include <boost/intrusive/intrusive_fwd.hpp>
19#include <boost/intrusive/detail/algo_type.hpp>
20#include <boost/core/no_exceptions_support.hpp>
21#include <cstddef>
22
23#if defined(BOOST_HAS_PRAGMA_ONCE)
24# pragma once
25#endif
26
27namespace boost {
28namespace intrusive {
29
30//! circular_list_algorithms provides basic algorithms to manipulate nodes
31//! forming a circular doubly linked list. An empty circular list is formed by a node
32//! whose pointers point to itself.
33//!
34//! circular_list_algorithms is configured with a NodeTraits class, which encapsulates the
35//! information about the node to be manipulated. NodeTraits must support the
36//! following interface:
37//!
38//! <b>Typedefs</b>:
39//!
40//! <tt>node</tt>: The type of the node that forms the circular list
41//!
42//! <tt>node_ptr</tt>: A pointer to a node
43//!
44//! <tt>const_node_ptr</tt>: A pointer to a const node
45//!
46//! <b>Static functions</b>:
47//!
48//! <tt>static node_ptr get_previous(const_node_ptr n);</tt>
49//!
50//! <tt>static void set_previous(node_ptr n, node_ptr prev);</tt>
51//!
52//! <tt>static node_ptr get_next(const_node_ptr n);</tt>
53//!
54//! <tt>static void set_next(node_ptr n, node_ptr next);</tt>
55template<class NodeTraits>
56class circular_list_algorithms
57{
58 public:
59 typedef typename NodeTraits::node node;
60 typedef typename NodeTraits::node_ptr node_ptr;
61 typedef typename NodeTraits::const_node_ptr const_node_ptr;
62 typedef NodeTraits node_traits;
63
64 //! <b>Effects</b>: Constructs an non-used list element, so that
65 //! inited(this_node) == true
66 //!
67 //! <b>Complexity</b>: Constant
68 //!
69 //! <b>Throws</b>: Nothing.
70 BOOST_INTRUSIVE_FORCEINLINEinline static void init(node_ptr this_node)
71 {
72 const node_ptr null_node = node_ptr();
73 NodeTraits::set_next(this_node, null_node);
74 NodeTraits::set_previous(this_node, null_node);
75 }
76
77 //! <b>Effects</b>: Returns true is "this_node" is in a non-used state
78 //! as if it was initialized by the "init" function.
79 //!
80 //! <b>Complexity</b>: Constant
81 //!
82 //! <b>Throws</b>: Nothing.
83 BOOST_INTRUSIVE_FORCEINLINEinline static bool inited(const const_node_ptr &this_node)
84 { return !NodeTraits::get_next(this_node); }
85
86 //! <b>Effects</b>: Constructs an empty list, making this_node the only
87 //! node of the circular list:
88 //! <tt>NodeTraits::get_next(this_node) == NodeTraits::get_previous(this_node)
89 //! == this_node</tt>.
90 //!
91 //! <b>Complexity</b>: Constant
92 //!
93 //! <b>Throws</b>: Nothing.
94 BOOST_INTRUSIVE_FORCEINLINEinline static void init_header(node_ptr this_node)
95 {
96 NodeTraits::set_next(this_node, this_node);
97 NodeTraits::set_previous(this_node, this_node);
98 }
99
100
101 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
102 //!
103 //! <b>Effects</b>: Returns true is "this_node" is the only node of a circular list:
104 //! <tt>return NodeTraits::get_next(this_node) == this_node</tt>
105 //!
106 //! <b>Complexity</b>: Constant
107 //!
108 //! <b>Throws</b>: Nothing.
109 BOOST_INTRUSIVE_FORCEINLINEinline static bool unique(const const_node_ptr &this_node)
110 {
111 node_ptr next = NodeTraits::get_next(this_node);
112 return !next || next == this_node;
113 }
114
115 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
116 //!
117 //! <b>Effects</b>: Returns the number of nodes in a circular list. If the circular list
118 //! is empty, returns 1.
119 //!
120 //! <b>Complexity</b>: Linear
121 //!
122 //! <b>Throws</b>: Nothing.
123 static std::size_t count(const const_node_ptr &this_node)
124 {
125 std::size_t result = 0;
126 const_node_ptr p = this_node;
127 do{
128 p = NodeTraits::get_next(p);
129 ++result;
130 }while (p != this_node);
131 return result;
132 }
133
134 //! <b>Requires</b>: this_node must be in a circular list or be an empty circular list.
135 //!
136 //! <b>Effects</b>: Unlinks the node from the circular list.
137 //!
138 //! <b>Complexity</b>: Constant
139 //!
140 //! <b>Throws</b>: Nothing.
141 BOOST_INTRUSIVE_FORCEINLINEinline static node_ptr unlink(node_ptr this_node)
142 {
143 node_ptr next(NodeTraits::get_next(this_node));
144 node_ptr prev(NodeTraits::get_previous(this_node));
145 NodeTraits::set_next(prev, next);
6
Calling 'Ring_node_traits::set_next'
7
Returning from 'Ring_node_traits::set_next'
146 NodeTraits::set_previous(next, prev);
8
Calling 'Ring_node_traits::set_previous'
9
Returning from 'Ring_node_traits::set_previous'
147 return next;
148 }
149
150 //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.
151 //!
152 //! <b>Effects</b>: Unlinks the node [b, e) from the circular list.
153 //!
154 //! <b>Complexity</b>: Constant
155 //!
156 //! <b>Throws</b>: Nothing.
157 BOOST_INTRUSIVE_FORCEINLINEinline static void unlink(node_ptr b, node_ptr e)
158 {
159 if (b != e) {
160 node_ptr prevb(NodeTraits::get_previous(b));
161 NodeTraits::set_previous(e, prevb);
162 NodeTraits::set_next(prevb, e);
163 }
164 }
165
166 //! <b>Requires</b>: nxt_node must be a node of a circular list.
167 //!
168 //! <b>Effects</b>: Links this_node before nxt_node in the circular list.
169 //!
170 //! <b>Complexity</b>: Constant
171 //!
172 //! <b>Throws</b>: Nothing.
173 BOOST_INTRUSIVE_FORCEINLINEinline static void link_before(node_ptr nxt_node, node_ptr this_node)
174 {
175 node_ptr prev(NodeTraits::get_previous(nxt_node));
176 NodeTraits::set_previous(this_node, prev);
177 NodeTraits::set_next(this_node, nxt_node);
178 //nxt_node might be an alias for prev->next_
179 //so use it before NodeTraits::set_next(prev, ...)
180 //is called and the reference changes its value
181 NodeTraits::set_previous(nxt_node, this_node);
182 NodeTraits::set_next(prev, this_node);
183 }
184
185 //! <b>Requires</b>: prev_node must be a node of a circular list.
186 //!
187 //! <b>Effects</b>: Links this_node after prev_node in the circular list.
188 //!
189 //! <b>Complexity</b>: Constant
190 //!
191 //! <b>Throws</b>: Nothing.
192 BOOST_INTRUSIVE_FORCEINLINEinline static void link_after(node_ptr prev_node, node_ptr this_node)
193 {
194 node_ptr next(NodeTraits::get_next(prev_node));
195 NodeTraits::set_previous(this_node, prev_node);
196 NodeTraits::set_next(this_node, next);
197 //prev_node might be an alias for next->next_
198 //so use it before update it before NodeTraits::set_previous(next, ...)
199 //is called and the reference changes it's value
200 NodeTraits::set_next(prev_node, this_node);
201 NodeTraits::set_previous(next, this_node);
202 }
203
204 //! <b>Requires</b>: this_node and other_node must be nodes inserted
205 //! in circular lists or be empty circular lists.
206 //!
207 //! <b>Effects</b>: Swaps the position of the nodes: this_node is inserted in
208 //! other_nodes position in the second circular list and the other_node is inserted
209 //! in this_node's position in the first circular list.
210 //!
211 //! <b>Complexity</b>: Constant
212 //!
213 //! <b>Throws</b>: Nothing.
214 static void swap_nodes(node_ptr this_node, node_ptr other_node)
215 {
216 if (other_node == this_node)
217 return;
218 bool this_inited = inited(this_node);
219 bool other_inited = inited(other_node);
220 if(this_inited){
221 init_header(this_node);
222 }
223 if(other_inited){
224 init_header(other_node);
225 }
226
227 node_ptr next_this(NodeTraits::get_next(this_node));
228 node_ptr prev_this(NodeTraits::get_previous(this_node));
229 node_ptr next_other(NodeTraits::get_next(other_node));
230 node_ptr prev_other(NodeTraits::get_previous(other_node));
231 //these first two swaps must happen before the other two
232 swap_prev(next_this, next_other);
233 swap_next(prev_this, prev_other);
234 swap_next(this_node, other_node);
235 swap_prev(this_node, other_node);
236
237 if(this_inited){
238 init(other_node);
239 }
240 if(other_inited){
241 init(this_node);
242 }
243 }
244
245 //! <b>Requires</b>: b and e must be nodes of the same circular list or an empty range.
246 //! and p must be a node of a different circular list or may not be an iterator in
247 // [b, e).
248 //!
249 //! <b>Effects</b>: Removes the nodes from [b, e) range from their circular list and inserts
250 //! them before p in p's circular list.
251 //!
252 //! <b>Complexity</b>: Constant
253 //!
254 //! <b>Throws</b>: Nothing.
255 static void transfer(node_ptr p, node_ptr b, node_ptr e)
256 {
257 if (b != e) {
258 node_ptr prev_p(NodeTraits::get_previous(p));
259 node_ptr prev_b(NodeTraits::get_previous(b));
260 node_ptr prev_e(NodeTraits::get_previous(e));
261 NodeTraits::set_next(prev_e, p);
262 NodeTraits::set_previous(p, prev_e);
263 NodeTraits::set_next(prev_b, e);
264 NodeTraits::set_previous(e, prev_b);
265 NodeTraits::set_next(prev_p, b);
266 NodeTraits::set_previous(b, prev_p);
267 }
268 }
269
270 //! <b>Requires</b>: i must a node of a circular list
271 //! and p must be a node of a different circular list.
272 //!
273 //! <b>Effects</b>: Removes the node i from its circular list and inserts
274 //! it before p in p's circular list.
275 //! If p == i or p == NodeTraits::get_next(i), this function is a null operation.
276 //!
277 //! <b>Complexity</b>: Constant
278 //!
279 //! <b>Throws</b>: Nothing.
280 static void transfer(node_ptr p, node_ptr i)
281 {
282 node_ptr n(NodeTraits::get_next(i));
283 if(n != p && i != p){
284 node_ptr prev_p(NodeTraits::get_previous(p));
285 node_ptr prev_i(NodeTraits::get_previous(i));
286 NodeTraits::set_next(prev_p, i);
287 NodeTraits::set_previous(i, prev_p);
288 NodeTraits::set_next(i, p);
289 NodeTraits::set_previous(p, i);
290 NodeTraits::set_previous(n, prev_i);
291 NodeTraits::set_next(prev_i, n);
292
293 }
294 }
295
296 //! <b>Effects</b>: Reverses the order of elements in the list.
297 //!
298 //! <b>Throws</b>: Nothing.
299 //!
300 //! <b>Complexity</b>: This function is linear time.
301 static void reverse(node_ptr p)
302 {
303 node_ptr f(NodeTraits::get_next(p));
304 node_ptr i(NodeTraits::get_next(f)), e(p);
305
306 while(i != e) {
307 node_ptr n = i;
308 i = NodeTraits::get_next(i);
309 transfer(f, n, i);
310 f = n;
311 }
312 }
313
314 //! <b>Effects</b>: Moves the node p n positions towards the end of the list.
315 //!
316 //! <b>Throws</b>: Nothing.
317 //!
318 //! <b>Complexity</b>: Linear to the number of moved positions.
319 static void move_backwards(node_ptr p, std::size_t n)
320 {
321 //Null shift, nothing to do
322 if(!n) return;
323 node_ptr first = NodeTraits::get_next(p);
324 //size() == 0 or 1, nothing to do
325 if(first == NodeTraits::get_previous(p)) return;
326 unlink(p);
327 //Now get the new first node
328 while(n--){
329 first = NodeTraits::get_next(first);
330 }
331 link_before(first, p);
332 }
333
334 //! <b>Effects</b>: Moves the node p n positions towards the beginning of the list.
335 //!
336 //! <b>Throws</b>: Nothing.
337 //!
338 //! <b>Complexity</b>: Linear to the number of moved positions.
339 static void move_forward(node_ptr p, std::size_t n)
340 {
341 //Null shift, nothing to do
342 if(!n) return;
343 node_ptr last = NodeTraits::get_previous(p);
344 //size() == 0 or 1, nothing to do
345 if(last == NodeTraits::get_next(p)) return;
346
347 unlink(p);
348 //Now get the new last node
349 while(n--){
350 last = NodeTraits::get_previous(last);
351 }
352 link_after(last, p);
353 }
354
355 //! <b>Requires</b>: f and l must be in a circular list.
356 //!
357 //! <b>Effects</b>: Returns the number of nodes in the range [f, l).
358 //!
359 //! <b>Complexity</b>: Linear
360 //!
361 //! <b>Throws</b>: Nothing.
362 static std::size_t distance(const const_node_ptr &f, const const_node_ptr &l)
363 {
364 const_node_ptr i(f);
365 std::size_t result = 0;
366 while(i != l){
367 i = NodeTraits::get_next(i);
368 ++result;
369 }
370 return result;
371 }
372
373 struct stable_partition_info
374 {
375 std::size_t num_1st_partition;
376 std::size_t num_2nd_partition;
377 node_ptr beg_2st_partition;
378 };
379
380 template<class Pred>
381 static void stable_partition(node_ptr beg, node_ptr end, Pred pred, stable_partition_info &info)
382 {
383 node_ptr bcur = node_traits::get_previous(beg);
384 node_ptr cur = beg;
385 node_ptr new_f = end;
386
387 std::size_t num1 = 0, num2 = 0;
388 while(cur != end){
389 if(pred(cur)){
390 ++num1;
391 bcur = cur;
392 cur = node_traits::get_next(cur);
393 }
394 else{
395 ++num2;
396 node_ptr last_to_remove = bcur;
397 new_f = cur;
398 bcur = cur;
399 cur = node_traits::get_next(cur);
400 BOOST_TRY{ try{
401 //Main loop
402 while(cur != end){
403 if(pred(cur)){ //Might throw
404 ++num1;
405 //Process current node
406 node_traits::set_next (last_to_remove, cur);
407 node_traits::set_previous(cur, last_to_remove);
408 last_to_remove = cur;
409 node_ptr nxt = node_traits::get_next(cur);
410 node_traits::set_next (bcur, nxt);
411 node_traits::set_previous(nxt, bcur);
412 cur = nxt;
413 }
414 else{
415 ++num2;
416 bcur = cur;
417 cur = node_traits::get_next(cur);
418 }
419 }
420 }
421 BOOST_CATCH(...)catch(...){
422 node_traits::set_next (last_to_remove, new_f);
423 node_traits::set_previous(new_f, last_to_remove);
424 BOOST_RETHROWthrow;;
425 }
426 BOOST_CATCH_END}
427 node_traits::set_next(last_to_remove, new_f);
428 node_traits::set_previous(new_f, last_to_remove);
429 break;
430 }
431 }
432 info.num_1st_partition = num1;
433 info.num_2nd_partition = num2;
434 info.beg_2st_partition = new_f;
435 }
436
437 private:
438 BOOST_INTRUSIVE_FORCEINLINEinline static void swap_prev(node_ptr this_node, node_ptr other_node)
439 {
440 node_ptr temp(NodeTraits::get_previous(this_node));
441 NodeTraits::set_previous(this_node, NodeTraits::get_previous(other_node));
442 NodeTraits::set_previous(other_node, temp);
443 }
444
445 BOOST_INTRUSIVE_FORCEINLINEinline static void swap_next(node_ptr this_node, node_ptr other_node)
446 {
447 node_ptr temp(NodeTraits::get_next(this_node));
448 NodeTraits::set_next(this_node, NodeTraits::get_next(other_node));
449 NodeTraits::set_next(other_node, temp);
450 }
451};
452
453/// @cond
454
455template<class NodeTraits>
456struct get_algo<CircularListAlgorithms, NodeTraits>
457{
458 typedef circular_list_algorithms<NodeTraits> type;
459};
460
461/// @endcond
462
463} //namespace intrusive
464} //namespace boost
465
466#include <boost/intrusive/detail/config_end.hpp>
467
468#endif //BOOST_INTRUSIVE_CIRCULAR_LIST_ALGORITHMS_HPP

/home/maarten/src/libreoffice/core/sw/source/core/inc/frame.hxx

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#ifndef INCLUDED_SW_SOURCE_CORE_INC_FRAME_HXX
21#define INCLUDED_SW_SOURCE_CORE_INC_FRAME_HXX
22
23#include <drawinglayer/primitive2d/baseprimitive2d.hxx>
24#include <editeng/borderline.hxx>
25#include <svl/poolitem.hxx>
26#include <swtypes.hxx>
27#include <swrect.hxx>
28#include <calbck.hxx>
29#include <svl/SfxBroadcaster.hxx>
30#include <o3tl/typed_flags_set.hxx>
31#include <com/sun/star/style/TabStop.hpp>
32#include <basegfx/matrix/b2dhommatrix.hxx>
33#include <vcl/outdev.hxx>
34
35#include <memory>
36
37namespace drawinglayer::processor2d { class BaseProcessor2D; }
38
39class SwLayoutFrame;
40class SwRootFrame;
41class SwPageFrame;
42class SwBodyFrame;
43class SwFlyFrame;
44class SwSectionFrame;
45class SwFootnoteFrame;
46class SwFootnoteBossFrame;
47class SwTabFrame;
48class SwRowFrame;
49class SwContentFrame;
50class SwAttrSet;
51class Color;
52class SwBorderAttrs;
53class SwCache;
54class SvxBrushItem;
55class SvxFormatBreakItem;
56class SwFormatPageDesc;
57class SwSelectionList;
58struct SwPosition;
59struct SwCursorMoveState;
60class SwFormat;
61class SwPrintData;
62class SwSortedObjs;
63class SwAnchoredObject;
64enum class SvxFrameDirection;
65class IDocumentDrawModelAccess;
66
67// Each FrameType is represented here as a bit.
68// The bits must be set in a way that it can be determined with masking of
69// which kind of FrameType an instance is _and_ from what classes it was derived.
70// Each frame has in its base class a member that must be set by the
71// constructors accordingly.
72enum class SwFrameType
73{
74 None = 0x0000,
75 Root = 0x0001,
76 Page = 0x0002,
77 Column = 0x0004,
78 Header = 0x0008,
79 Footer = 0x0010,
80 FtnCont = 0x0020,
81 Ftn = 0x0040,
82 Body = 0x0080,
83 Fly = 0x0100,
84 Section = 0x0200,
85// UNUSED 0x0400
86 Tab = 0x0800,
87 Row = 0x1000,
88 Cell = 0x2000,
89 Txt = 0x4000,
90 NoTxt = 0x8000,
91};
92
93namespace o3tl
94{
95 template<> struct typed_flags<SwFrameType> : is_typed_flags<SwFrameType, 0xfbff> {};
96};
97
98// for internal use some common combinations
99#define FRM_LAYOUTSwFrameType(0x3bFF) SwFrameType(0x3bFF)
100#define FRM_ALLSwFrameType(0xfbff) SwFrameType(0xfbff)
101#define FRM_CNTNT(SwFrameType::Txt | SwFrameType::NoTxt) (SwFrameType::Txt | SwFrameType::NoTxt)
102#define FRM_FTNBOSS(SwFrameType::Page | SwFrameType::Column) (SwFrameType::Page | SwFrameType::Column)
103#define FRM_ACCESSIBLE(SwFrameType::Root | SwFrameType::Page | SwFrameType::Header |
SwFrameType::Footer | SwFrameType::Ftn | SwFrameType::Fly | SwFrameType
::Tab | SwFrameType::Cell | SwFrameType::Txt)
(SwFrameType::Root | SwFrameType::Page | SwFrameType::Header | SwFrameType::Footer | SwFrameType::Ftn | SwFrameType::Fly | SwFrameType::Tab | SwFrameType::Cell | SwFrameType::Txt)
104#define FRM_NEIGHBOUR(SwFrameType::Column | SwFrameType::Cell) (SwFrameType::Column | SwFrameType::Cell)
105#define FRM_NOTE_VERT(SwFrameType::FtnCont | SwFrameType::Ftn | SwFrameType::Section
| SwFrameType::Tab | SwFrameType::Row | SwFrameType::Cell | SwFrameType
::Txt)
(SwFrameType::FtnCont | SwFrameType::Ftn | SwFrameType::Section | SwFrameType::Tab | SwFrameType::Row | SwFrameType::Cell | SwFrameType::Txt)
106#define FRM_HEADFOOT(SwFrameType::Header | SwFrameType::Footer) (SwFrameType::Header | SwFrameType::Footer)
107#define FRM_BODYFTNC(SwFrameType::FtnCont | SwFrameType::Body) (SwFrameType::FtnCont | SwFrameType::Body)
108
109// for GetNextLeaf/GetPrevLeaf.
110enum MakePageType
111{
112 MAKEPAGE_NONE, // do not create page/footnote
113 MAKEPAGE_APPEND, // only append page if needed
114 MAKEPAGE_INSERT, // add or append page if needed
115 MAKEPAGE_FTN, // add footnote if needed
116 MAKEPAGE_NOSECTION // Don't create section frames
117};
118
119namespace drawinglayer::attribute {
120 class SdrAllFillAttributesHelper;
121 typedef std::shared_ptr< SdrAllFillAttributesHelper > SdrAllFillAttributesHelperPtr;
122}
123
124/// Helper class to isolate geometry-defining members of SwFrame
125/// and to control their accesses. Moved to own class to have no
126/// hidden accesses to 'private' members anymore.
127///
128/// Added most important flags about the state of this geometric
129/// information and if it is valid or not
130class SAL_DLLPUBLIC_RTTI__attribute__ ((type_visibility("default"))) SwFrameAreaDefinition
131{
132private:
133 friend void FriendHackInvalidateRowFrame(SwFrameAreaDefinition &);
134
135 // The absolute position and size of the SwFrame in the document.
136 // This values are set by the layouter implementations
137 SwRect maFrameArea;
138
139 // The 'inner' Frame Area defined by a SwRect relative to FrameArea:
140 // When identical to FrameArea, Pos() will be (0, 0) and Size identical.
141 SwRect maFramePrintArea;
142
143 // bitfield
144 bool mbFrameAreaPositionValid : 1;
145 bool mbFrameAreaSizeValid : 1;
146 bool mbFramePrintAreaValid : 1;
147
148 // #i65250#
149 // frame ID is now in general available - used for layout loop control
150 static sal_uInt32 mnLastFrameId;
151 const sal_uInt32 mnFrameId;
152
153protected:
154 // write access to mb*Valid flags
155 void setFrameAreaPositionValid(bool bNew);
156 void setFrameAreaSizeValid(bool bNew);
157 void setFramePrintAreaValid(bool bNew);
158
159public:
160 SwFrameAreaDefinition();
161 virtual ~SwFrameAreaDefinition();
162
163 // read access to mb*Valid flags
164 bool isFrameAreaPositionValid() const { return mbFrameAreaPositionValid; }
165 bool isFrameAreaSizeValid() const { return mbFrameAreaSizeValid; }
166 bool isFramePrintAreaValid() const { return mbFramePrintAreaValid; }
167
168 // syntactic sugar: test whole FrameAreaDefinition
169 bool isFrameAreaDefinitionValid() const { return isFrameAreaPositionValid() && isFrameAreaSizeValid() && isFramePrintAreaValid(); }
170
171 // #i65250#
172 sal_uInt32 GetFrameId() const { return mnFrameId; }
173
174 // read accesses to FrameArea definitions - only const access allowed.
175 // Do *not* const_cast results, it is necessary to track changes. use
176 // the below offered WriteAccess helper classes instead
177 const SwRect& getFrameArea() const { return maFrameArea; }
178 const SwRect& getFramePrintArea() const { return maFramePrintArea; }
179
180 // helper class(es) for FrameArea manipulation. These
181 // have to be used to apply changes to FrameAreas. They hold a copy of the
182 // SwRect for manipulation. It gets written back at destruction. Thus, this
183 // mechanism depends on scope usage, take care. It prevents errors using
184 // different instances of SwFrame in get/set methods which is more safe
185 class FrameAreaWriteAccess : public SwRect
186 {
187 private:
188 SwFrameAreaDefinition& mrTarget;
189
190 FrameAreaWriteAccess(const FrameAreaWriteAccess&) = delete;
191 FrameAreaWriteAccess& operator=(const FrameAreaWriteAccess&) = delete;
192
193 public:
194 FrameAreaWriteAccess(SwFrameAreaDefinition& rTarget) : SwRect(rTarget.getFrameArea()), mrTarget(rTarget) {}
195 ~FrameAreaWriteAccess();
196 void setSwRect(const SwRect& rNew) { *reinterpret_cast< SwRect* >(this) = rNew; }
197 };
198
199 // same helper for FramePrintArea
200 class FramePrintAreaWriteAccess : public SwRect
201 {
202 private:
203 SwFrameAreaDefinition& mrTarget;
204
205 FramePrintAreaWriteAccess(const FramePrintAreaWriteAccess&) = delete;
206 FramePrintAreaWriteAccess& operator=(const FramePrintAreaWriteAccess&) = delete;
207
208 public:
209 FramePrintAreaWriteAccess(SwFrameAreaDefinition& rTarget) : SwRect(rTarget.getFramePrintArea()), mrTarget(rTarget) {}
210 ~FramePrintAreaWriteAccess();
211 void setSwRect(const SwRect& rNew) { *reinterpret_cast< SwRect* >(this) = rNew; }
212 };
213
214 // RotateFlyFrame3 - Support for Transformations
215 // Hand out the Transformations for the current FrameAreaDefinition
216 // for the FrameArea and FramePrintArea.
217 // FramePrintArea is not relative to FrameArea in this
218 // transformation representation (to make it easier to use and understand).
219 // There is no 'set' method since SwFrame is a layout object. For
220 // some cases rotation will be included (used for SwGrfNode in inner
221 // SwFrame of a SwFlyFrame)
222 virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const;
223 virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const;
224
225 // RotateFlyFrame3 - Support for Transformations
226 // Modify current transformations by applying given translation
227 virtual void transform_translate(const Point& rOffset);
228};
229
230/// RotateFlyFrame3: Helper class when you want to make your SwFrame derivate
231/// transformable. It provides some tooling to do so. To use, add as member
232/// (see e.g. SwFlyFreeFrame which uses 'std::unique_ptr< TransformableSwFrame >')
233class TransformableSwFrame
234{
235private:
236 // The SwFrameAreaDefinition to work on
237 SwFrameAreaDefinition& mrSwFrameAreaDefinition;
238
239 // FrameAreaTransformation and FramePrintAreaTransformation
240 // !identity when needed (translate/scale is used (e.g. rotation))
241 basegfx::B2DHomMatrix maFrameAreaTransformation;
242 basegfx::B2DHomMatrix maFramePrintAreaTransformation;
243
244public:
245 TransformableSwFrame(SwFrameAreaDefinition& rSwFrameAreaDefinition)
246 : mrSwFrameAreaDefinition(rSwFrameAreaDefinition),
247 maFrameAreaTransformation(),
248 maFramePrintAreaTransformation()
249 {
250 }
251
252 // get SwFrameArea in transformation form
253 const basegfx::B2DHomMatrix& getLocalFrameAreaTransformation() const
254 {
255 return maFrameAreaTransformation;
256 }
257
258 // get SwFramePrintArea in transformation form
259 const basegfx::B2DHomMatrix& getLocalFramePrintAreaTransformation() const
260 {
261 return maFramePrintAreaTransformation;
262 }
263
264 // Helpers to re-create the untransformed SwRect(s) originally
265 // in the SwFrameAreaDefinition, based on the current Transformations.
266 SwRect getUntransformedFrameArea() const;
267 SwRect getUntransformedFramePrintArea() const;
268
269 // Helper method to re-create FrameAreaTransformations based on the
270 // current FrameAreaDefinition transformed by given rotation and Center
271 void createFrameAreaTransformations(
272 double fRotation,
273 const basegfx::B2DPoint& rCenter);
274
275 // Tooling method to reset the SwRect(s) in the current
276 // SwFrameAreaDefinition which are already adapted to
277 // Transformation back to the untransformed state, using
278 // the getUntransformedFrame*Area calls above when needed.
279 // Only the SwRect(s) are changed back, not the transformations.
280 void restoreFrameAreas();
281
282 // Re-Creates the SwRect(s) as BoundAreas based on the current
283 // set Transformations.
284 void adaptFrameAreasToTransformations();
285
286 // Modify current definitions by applying the given transformation
287 void transform(const basegfx::B2DHomMatrix& aTransform);
288};
289
290/**
291 * Base class of the Writer layout elements.
292 *
293 * This includes not only fly frames, but everything down to the paragraph
294 * level: pages, headers, footers, etc. (Inside a paragraph SwLinePortion
295 * instances are used.)
296 */
297class SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwFrame : public SwFrameAreaDefinition, public SwClient, public SfxBroadcaster
298{
299 // the hidden Frame
300 friend class SwFlowFrame;
301 friend class SwLayoutFrame;
302 friend class SwLooping;
303 friend class SwDeletionChecker; // for GetDep()
304
305 // voids lower during creation of a column
306 friend SwFrame *SaveContent( SwLayoutFrame *, SwFrame* pStart );
307 friend void RestoreContent( SwFrame *, SwLayoutFrame *, SwFrame *pSibling );
308
309 // for validating a mistakenly invalidated one in SwContentFrame::MakeAll
310 friend void ValidateSz( SwFrame *pFrame );
311 // implemented in text/txtftn.cxx, prevents Footnote oscillation
312 friend void ValidateText( SwFrame *pFrame );
313
314 friend void MakeNxt( SwFrame *pFrame, SwFrame *pNxt );
315
316 // cache for (border) attributes
317 static SwCache *mpCache;
318
319 SwRootFrame *mpRoot;
320 SwLayoutFrame *mpUpper;
321 SwFrame *mpNext;
322 SwFrame *mpPrev;
323
324 // sw_redlinehide: hide these dangerous SwClient functions
325 using SwClient::GetRegisteredInNonConst;
326 using SwClient::GetRegisteredIn;
327
328 SwFrame *FindNext_();
329 SwFrame *FindPrev_();
330
331 /** method to determine next content frame in the same environment
332 for a flow frame (content frame, table frame, section frame)
333
334 #i27138# - adding documentation:
335 Travelling downwards through the layout to determine the next content
336 frame in the same environment. There are several environments in a
337 document, which form a closed context regarding this function. These
338 environments are:
339 - Each page header
340 - Each page footer
341 - Each unlinked fly frame
342 - Each group of linked fly frames
343 - All footnotes
344 - All document body frames
345 #i27138# - adding parameter <_bInSameFootnote>
346 Its default value is <false>. If its value is <true>, the environment
347 'All footnotes' is no longer treated. Instead each footnote is treated
348 as an own environment.
349
350 @param _bInSameFootnote
351 input parameter - boolean indicating, that the found next content
352 frame has to be in the same footnote frame. This parameter is only
353 relevant for flow frames in footnotes.
354
355 @return SwContentFrame*
356 pointer to the found next content frame. It's NULL, if none exists.
357 */
358 SwContentFrame* FindNextCnt_( const bool _bInSameFootnote );
359
360 /** method to determine previous content frame in the same environment
361 for a flow frame (content frame, table frame, section frame)
362
363 #i27138#
364 Travelling upwards through the layout to determine the previous content
365 frame in the same environment. There are several environments in a
366 document, which form a closed context regarding this function. These
367 environments are:
368 - Each page header
369 - Each page footer
370 - Each unlinked fly frame
371 - Each group of linked fly frames
372 - All footnotes
373 - All document body frames
374 #i27138# - adding parameter <_bInSameFootnote>
375 Its default value is <false>. If its value is <true>, the environment
376 'All footnotes' is no longer treated. Instead each footnote is treated
377 as an own environment.
378
379 The found previous content frame has to be in the same footnote frame. This is only
380 relevant for flow frames in footnotes.
381
382 @return SwContentFrame*
383 pointer to the found previous content frame. It's NULL, if none exists.
384 */
385 SwContentFrame* FindPrevCnt_();
386
387 void UpdateAttrFrame( const SfxPoolItem*, const SfxPoolItem*, sal_uInt8 & );
388 SwFrame* GetIndNext_();
389 void SetDirFlags( bool bVert );
390
391 const SwLayoutFrame* ImplGetNextLayoutLeaf( bool bFwd ) const;
392
393 SwPageFrame* ImplFindPageFrame();
394
395protected:
396 std::unique_ptr<SwSortedObjs> m_pDrawObjs; // draw objects, can be null
397 SwFrameType mnFrameType; //Who am I?
398
399 bool mbInDtor : 1;
400 bool mbInvalidR2L : 1;
401 bool mbDerivedR2L : 1;
402 bool mbRightToLeft : 1;
403 bool mbInvalidVert : 1;
404 bool mbDerivedVert : 1;
405 bool mbVertical : 1;
406
407 bool mbVertLR : 1;
408 bool mbVertLRBT : 1;
409
410 bool mbValidLineNum : 1;
411 bool mbFixSize : 1;
412
413 // if true, frame will be painted completely even content was changed
414 // only partially. For ContentFrames a border (from Action) will exclusively
415 // painted if <mbCompletePaint> is true.
416 bool mbCompletePaint : 1;
417
418 bool mbRetouche : 1; // frame is responsible for retouching
419
420 bool mbInfInvalid : 1; // InfoFlags are invalid
421 bool mbInfBody : 1; // Frame is in document body
422 bool mbInfTab : 1; // Frame is in a table
423 bool mbInfFly : 1; // Frame is in a Fly
424 bool mbInfFootnote : 1; // Frame is in a footnote
425 bool mbInfSct : 1; // Frame is in a section
426 bool mbColLocked : 1; // lock Grow/Shrink for column-wise section
427 // or fly frames, will be set in Format
428 bool m_isInDestroy : 1;
429 bool mbForbidDelete : 1;
430
431 void ColLock() { mbColLocked = true; }
432 void ColUnlock() { mbColLocked = false; }
433
434 virtual void DestroyImpl();
435 virtual ~SwFrame() override;
436
437 // Only used by SwRootFrame Ctor to get 'this' into mpRoot...
438 void setRootFrame( SwRootFrame* pRoot ) { mpRoot = pRoot; }
439
440 SwPageFrame *InsertPage( SwPageFrame *pSibling, bool bFootnote );
441 void PrepareMake(vcl::RenderContext* pRenderContext);
442 void OptPrepareMake();
443 virtual void MakePos();
444 // Format next frame of table frame to assure keeping attributes.
445 // In case of nested tables method <SwFrame::MakeAll()> is called to
446 // avoid formatting of superior table frame.
447 friend SwFrame* sw_FormatNextContentForKeep( SwTabFrame* pTabFrame );
448
449 virtual void MakeAll(vcl::RenderContext* pRenderContext) = 0;
450 // adjust frames of a page
451 SwTwips AdjustNeighbourhood( SwTwips nDiff, bool bTst = false );
452
453 // change only frame size not the size of PrtArea
454 virtual SwTwips ShrinkFrame( SwTwips, bool bTst = false, bool bInfo = false ) = 0;
455 virtual SwTwips GrowFrame ( SwTwips, bool bTst = false, bool bInfo = false ) = 0;
456
457 /// use these so we can grep for SwFrame's GetRegisteredIn accesses
458 /// beware that SwTextFrame may return sw::WriterMultiListener
459 SwModify *GetDep() { return GetRegisteredInNonConst(); }
460 const SwModify *GetDep() const { return GetRegisteredIn(); }
461
462 SwFrame( SwModify*, SwFrame* );
463
464 void CheckDir( SvxFrameDirection nDir, bool bVert, bool bOnlyBiDi, bool bBrowse );
465
466 /** enumeration for the different invalidations
467 #i28701#
468 */
469 enum InvalidationType
470 {
471 INVALID_SIZE, INVALID_PRTAREA, INVALID_POS, INVALID_LINENUM, INVALID_ALL
472 };
473
474 /** method to determine, if an invalidation is allowed.
475 #i28701
476 */
477 virtual bool InvalidationAllowed( const InvalidationType _nInvalid ) const;
478
479 /** method to perform additional actions on an invalidation
480
481 #i28701#
482 Method has *only* to contain actions, which has to be performed on
483 *every* assignment of the corresponding flag to <false>.
484 */
485 virtual void ActionOnInvalidation( const InvalidationType _nInvalid );
486
487 // draw shadow and borders
488 void PaintShadow( const SwRect&, SwRect&, const SwBorderAttrs& ) const;
489 virtual void Modify( const SfxPoolItem*, const SfxPoolItem* ) override;
490
491 virtual const IDocumentDrawModelAccess& getIDocumentDrawModelAccess( );
492
493public:
494 virtual css::uno::Sequence< css::style::TabStop > GetTabStopInfo( SwTwips )
495 {
496 return css::uno::Sequence< css::style::TabStop >();
497 }
498
499
500 SwFrameType GetType() const { return mnFrameType; }
501
502 static SwCache &GetCache() { return *mpCache; }
503 static SwCache *GetCachePtr() { return mpCache; }
504 static void SetCache( SwCache *pNew ) { mpCache = pNew; }
505
506 // change PrtArea size and FrameSize
507 SwTwips Shrink( SwTwips, bool bTst = false, bool bInfo = false );
508 SwTwips Grow ( SwTwips, bool bTst = false, bool bInfo = false );
509
510 // different methods for inserting in layout tree (for performance reasons)
511
512 // insert before pBehind or at the end of the chain below mpUpper
513 void InsertBefore( SwLayoutFrame* pParent, SwFrame* pBehind );
514 // insert after pBefore or at the beginning of the chain below mpUpper
515 void InsertBehind( SwLayoutFrame *pParent, SwFrame *pBefore );
516 // insert before pBehind or at the end of the chain while considering
517 // the siblings of pSct
518 bool InsertGroupBefore( SwFrame* pParent, SwFrame* pWhere, SwFrame* pSct );
519 void RemoveFromLayout();
520
521 // For internal use only - who ignores this will be put in a sack and has
522 // to stay there for two days
523 // Does special treatment for Get_[Next|Prev]Leaf() (for tables).
524 SwLayoutFrame *GetLeaf( MakePageType eMakePage, bool bFwd );
525 SwLayoutFrame *GetNextLeaf ( MakePageType eMakePage );
526 SwLayoutFrame *GetNextFootnoteLeaf( MakePageType eMakePage );
527 SwLayoutFrame *GetNextSctLeaf( MakePageType eMakePage );
528 SwLayoutFrame *GetNextCellLeaf();
529 SwLayoutFrame *GetPrevLeaf ();
530 SwLayoutFrame *GetPrevFootnoteLeaf( MakePageType eMakeFootnote );
531 SwLayoutFrame *GetPrevSctLeaf();
532 SwLayoutFrame *GetPrevCellLeaf();
533 const SwLayoutFrame *GetLeaf ( MakePageType eMakePage, bool bFwd,
534 const SwFrame *pAnch ) const;
535
536 bool WrongPageDesc( SwPageFrame* pNew );
537
538 //#i28701# - new methods to append/remove drawing objects
539 void AppendDrawObj( SwAnchoredObject& _rNewObj );
540 void RemoveDrawObj( SwAnchoredObject& _rToRemoveObj );
541
542 // work with chain of FlyFrames
543 void AppendFly( SwFlyFrame *pNew );
544 void RemoveFly( SwFlyFrame *pToRemove );
545 const SwSortedObjs *GetDrawObjs() const { return m_pDrawObjs.get(); }
546 SwSortedObjs *GetDrawObjs() { return m_pDrawObjs.get(); }
547 // #i28701# - change purpose of method and adjust its name
548 void InvalidateObjs( const bool _bNoInvaOfAsCharAnchoredObjs = true );
549
550 virtual void PaintSwFrameShadowAndBorder(
551 const SwRect&,
552 const SwPageFrame* pPage,
553 const SwBorderAttrs&) const;
554 void PaintBaBo( const SwRect&, const SwPageFrame *pPage,
555 const bool bOnlyTextBackground = false) const;
556 void PaintSwFrameBackground( const SwRect&, const SwPageFrame *pPage,
557 const SwBorderAttrs &,
558 const bool bLowerMode = false,
559 const bool bLowerBorder = false,
560 const bool bOnlyTextBackground = false ) const;
561 void PaintBorderLine( const SwRect&, const SwRect&, const SwPageFrame*,
562 const Color *pColor,
563 const SvxBorderLineStyle = SvxBorderLineStyle::SOLID ) const;
564
565 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> CreateProcessor2D( ) const;
566 void ProcessPrimitives( const drawinglayer::primitive2d::Primitive2DContainer& rSequence ) const;
567
568 // retouch, not in the area of the given Rect!
569 void Retouch( const SwPageFrame *pPage, const SwRect &rRect ) const;
570
571 bool GetBackgroundBrush(
572 drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes,
573 const SvxBrushItem*& rpBrush,
574 const Color*& rpColor,
575 SwRect &rOrigRect,
576 bool bLowerMode,
577 bool bConsiderTextBox ) const;
578
579 inline void SetCompletePaint() const;
580 inline void ResetCompletePaint() const;
581 bool IsCompletePaint() const { return mbCompletePaint; }
582
583 inline void SetRetouche() const;
584 inline void ResetRetouche() const;
585 bool IsRetouche() const { return mbRetouche; }
586
587 void SetInfFlags();
588 void InvalidateInfFlags() { mbInfInvalid = true; }
589 inline bool IsInDocBody() const; // use InfoFlags, determine flags
590 inline bool IsInFootnote() const; // if necessary
591 inline bool IsInTab() const;
592 inline bool IsInFly() const;
593 inline bool IsInSct() const;
594
595 // If frame is inside a split table row, this function returns
596 // the corresponding row frame in the follow table.
597 const SwRowFrame* IsInSplitTableRow() const;
598
599 // If frame is inside a follow flow row, this function returns
600 // the corresponding row frame master table
601 const SwRowFrame* IsInFollowFlowRow() const;
602
603 bool IsInBalancedSection() const;
604
605 inline bool IsVertical() const;
606 inline bool IsVertLR() const;
607 inline bool IsVertLRBT() const;
608
609 void SetDerivedVert( bool bNew ){ mbDerivedVert = bNew; }
610 void SetInvalidVert( bool bNew) { mbInvalidVert = bNew; }
611 inline bool IsRightToLeft() const;
612 void SetDerivedR2L( bool bNew ) { mbDerivedR2L = bNew; }
613
614 void CheckDirChange();
615 // returns upper left frame position for LTR and
616 // upper right frame position for Asian / RTL frames
617 Point GetFrameAnchorPos( bool bIgnoreFlysAnchoredAtThisFrame ) const;
618
619 /** determine, if frame is moveable in given environment
620
621 method replaced 'old' method <bool IsMoveable() const>.
622 Determines, if frame is moveable in given environment. if no environment
623 is given (parameter _pLayoutFrame == 0), the movability in the actual
624 environment (<GetUpper()) is checked.
625
626 @param _pLayoutFrame
627 input parameter - given environment (layout frame), in which the movability
628 will be checked. If not set ( == 0 ), actual environment is taken.
629
630 @return boolean, indicating, if frame is moveable in given environment
631 */
632 bool IsMoveable( const SwLayoutFrame* _pLayoutFrame = nullptr ) const;
633
634 // Is it permitted for the (Text)Frame to add a footnote in the current
635 // environment (not e.g. for repeating table headlines)
636 bool IsFootnoteAllowed() const;
637
638 virtual void Format( vcl::RenderContext* pRenderContext, const SwBorderAttrs *pAttrs = nullptr );
639
640 virtual void CheckDirection( bool bVert );
641
642 void ReinitializeFrameSizeAttrFlags();
643
644 /// WARNING: this may not return correct RES_PAGEDESC/RES_BREAK items for
645 /// SwTextFrame, use GetBreakItem()/GetPageDescItem() instead
646 const SwAttrSet *GetAttrSet() const;
647 virtual const SvxFormatBreakItem& GetBreakItem() const;
648 virtual const SwFormatPageDesc& GetPageDescItem() const;
649
650 bool HasFixSize() const { return mbFixSize; }
651
652 // check all pages (starting from the given) and correct them if needed
653 static void CheckPageDescs( SwPageFrame *pStart, bool bNotifyFields = true, SwPageFrame** ppPrev = nullptr);
654
655 // might return 0, with and without const
656 SwFrame *GetNext() { return mpNext; }
657 SwFrame *GetPrev() { return mpPrev; }
658 SwLayoutFrame *GetUpper() { return mpUpper; }
659 SwRootFrame *getRootFrame(){ return mpRoot; }
660 SwPageFrame *FindPageFrame() { return IsPageFrame() ? reinterpret_cast<SwPageFrame*>(this) : ImplFindPageFrame(); }
661 SwFrame *FindColFrame();
662 SwRowFrame *FindRowFrame();
663 SwFootnoteBossFrame *FindFootnoteBossFrame( bool bFootnotes = false );
664 SwTabFrame *ImplFindTabFrame();
665 SwFootnoteFrame *ImplFindFootnoteFrame();
666 SwFlyFrame *ImplFindFlyFrame();
667 SwSectionFrame *ImplFindSctFrame();
668 const SwBodyFrame *ImplFindBodyFrame() const;
669 SwFrame *FindFooterOrHeader();
670 SwFrame *GetLower();
671 const SwFrame *GetNext() const { return mpNext; }
672 const SwFrame *GetPrev() const { return mpPrev; }
673 const SwLayoutFrame *GetUpper() const { return mpUpper; }
674 const SwRootFrame *getRootFrame() const { return mpRoot; }
675 inline SwTabFrame *FindTabFrame();
676 inline SwFootnoteFrame *FindFootnoteFrame();
677 inline SwFlyFrame *FindFlyFrame();
678 inline SwSectionFrame *FindSctFrame();
679 inline SwFrame *FindNext();
680 // #i27138# - add parameter <_bInSameFootnote>
681 SwContentFrame* FindNextCnt( const bool _bInSameFootnote = false );
682 inline SwFrame *FindPrev();
683 inline const SwPageFrame *FindPageFrame() const;
684 inline const SwFootnoteBossFrame *FindFootnoteBossFrame( bool bFootnote = false ) const;
685 inline const SwFrame *FindColFrame() const;
686 inline const SwFrame *FindFooterOrHeader() const;
687 inline const SwTabFrame *FindTabFrame() const;
688 inline const SwFootnoteFrame *FindFootnoteFrame() const;
689 inline const SwFlyFrame *FindFlyFrame() const;
690 inline const SwSectionFrame *FindSctFrame() const;
691 inline const SwBodyFrame *FindBodyFrame() const;
692 inline const SwFrame *FindNext() const;
693 // #i27138# - add parameter <_bInSameFootnote>
694 const SwContentFrame* FindNextCnt( const bool _bInSameFootnote = false ) const;
695 inline const SwFrame *FindPrev() const;
696 const SwFrame *GetLower() const;
697
698 SwContentFrame* FindPrevCnt();
699
700 const SwContentFrame* FindPrevCnt() const;
701
702 // #i79774#
703 SwFrame* GetIndPrev_() const;
704 SwFrame* GetIndPrev() const
705 { return ( mpPrev || !IsInSct() ) ? mpPrev : GetIndPrev_(); }
706
707 SwFrame* GetIndNext()
708 { return ( mpNext || !IsInSct() ) ? mpNext : GetIndNext_(); }
709 const SwFrame* GetIndNext() const { return const_cast<SwFrame*>(this)->GetIndNext(); }
710
711 sal_uInt16 GetPhyPageNum() const; // page number without offset
712 sal_uInt16 GetVirtPageNum() const; // page number with offset
713 bool OnRightPage() const { return 0 != GetPhyPageNum() % 2; };
714 bool WannaRightPage() const;
715 bool OnFirstPage() const;
716
717 inline const SwLayoutFrame *GetPrevLayoutLeaf() const;
718 inline const SwLayoutFrame *GetNextLayoutLeaf() const;
719 inline SwLayoutFrame *GetPrevLayoutLeaf();
720 inline SwLayoutFrame *GetNextLayoutLeaf();
721
722 virtual void Calc(vcl::RenderContext* pRenderContext) const; // here might be "formatted"
723 inline void OptCalc() const; // here we assume (for optimization) that
724 // the predecessors are already formatted
725 Point GetRelPos() const;
726
727 // PaintArea is the area where content might be displayed.
728 // The margin of a page or the space between columns belongs to it.
729 SwRect GetPaintArea() const;
730
731 // UnionFrame is the union of Frame- and PrtArea, normally identical
732 // to the FrameArea except in case of negative Prt margins.
733 SwRect UnionFrame( bool bBorder = false ) const;
734
735 virtual Size ChgSize( const Size& aNewSize );
736
737 virtual void Cut() = 0;
738 virtual void Paste( SwFrame* pParent, SwFrame* pSibling = nullptr ) = 0;
739
740 void ValidateLineNum() { mbValidLineNum = true; }
741
742 bool GetValidLineNumFlag()const { return mbValidLineNum; }
743
744 // Only invalidate Frame
745 // #i28701# - add call to method <ActionOnInvalidation(..)>
746 // for all invalidation methods.
747 // #i28701# - use method <InvalidationAllowed(..)> to
748 // decide, if invalidation will to be performed or not.
749 // #i26945# - no additional invalidation, if it's already
750 // invalidate.
751 void InvalidateSize_()
752 {
753 if ( isFrameAreaSizeValid() && InvalidationAllowed( INVALID_SIZE ) )
754 {
755 setFrameAreaSizeValid(false);
756 ActionOnInvalidation( INVALID_SIZE );
757 }
758 }
759 void InvalidatePrt_()
760 {
761 if ( isFramePrintAreaValid() && InvalidationAllowed( INVALID_PRTAREA ) )
762 {
763 setFramePrintAreaValid(false);
764 ActionOnInvalidation( INVALID_PRTAREA );
765 }
766 }
767 void InvalidatePos_()
768 {
769 if ( isFrameAreaPositionValid() && InvalidationAllowed( INVALID_POS ) )
770 {
771 setFrameAreaPositionValid(false);
772 ActionOnInvalidation( INVALID_POS );
773 }
774 }
775 void InvalidateLineNum_()
776 {
777 if ( mbValidLineNum && InvalidationAllowed( INVALID_LINENUM ) )
778 {
779 mbValidLineNum = false;
780 ActionOnInvalidation( INVALID_LINENUM );
781 }
782 }
783 void InvalidateAll_()
784 {
785 if ( ( isFrameAreaSizeValid() || isFramePrintAreaValid() || isFrameAreaPositionValid() ) && InvalidationAllowed( INVALID_ALL ) )
786 {
787 setFrameAreaSizeValid(false);
788 setFrameAreaPositionValid(false);
789 setFramePrintAreaValid(false);
790 ActionOnInvalidation( INVALID_ALL );
791 }
792 }
793 // also notify page at the same time
794 inline void InvalidateSize();
795 inline void InvalidatePrt();
796 inline void InvalidatePos();
797 inline void InvalidateLineNum();
798 inline void InvalidateAll();
799 void ImplInvalidateSize();
800 void ImplInvalidatePrt();
801 void ImplInvalidatePos();
802 void ImplInvalidateLineNum();
803
804 inline void InvalidateNextPos( bool bNoFootnote = false );
805 void ImplInvalidateNextPos( bool bNoFootnote );
806
807 /** method to invalidate printing area of next frame
808 #i11859#
809 */
810 void InvalidateNextPrtArea();
811
812 void InvalidatePage( const SwPageFrame *pPage = nullptr ) const;
813
814 virtual bool FillSelection( SwSelectionList& rList, const SwRect& rRect ) const;
815
816 virtual bool GetModelPositionForViewPoint( SwPosition *, Point&,
817 SwCursorMoveState* = nullptr, bool bTestBackground = false ) const;
818 virtual bool GetCharRect( SwRect &, const SwPosition&,
819 SwCursorMoveState* = nullptr, bool bAllowFarAway = true ) const;
820 virtual void PaintSwFrame( vcl::RenderContext& rRenderContext, SwRect const&,
821 SwPrintData const*const pPrintData = nullptr ) const;
822
823 // HACK: shortcut between frame and formatting
824 // It's your own fault if you cast void* incorrectly! In any case check
825 // the void* for 0.
826 virtual bool Prepare( const PrepareHint ePrep = PrepareHint::Clear,
827 const void *pVoid = nullptr, bool bNotify = true );
828
829 // true if it is the correct class, false otherwise
830 inline bool IsLayoutFrame() const;
831 inline bool IsRootFrame() const;
832 inline bool IsPageFrame() const;
833 inline bool IsColumnFrame() const;
834 inline bool IsFootnoteBossFrame() const; // footnote bosses might be PageFrames or ColumnFrames
835 inline bool IsHeaderFrame() const;
836 inline bool IsFooterFrame() const;
837 inline bool IsFootnoteContFrame() const;
838 inline bool IsFootnoteFrame() const;
839 inline bool IsBodyFrame() const;
840 inline bool IsColBodyFrame() const; // implemented in layfrm.hxx, BodyFrame above ColumnFrame
841 inline bool IsPageBodyFrame() const; // implemented in layfrm.hxx, BodyFrame above PageFrame
842 inline bool IsFlyFrame() const;
843 inline bool IsSctFrame() const;
844 inline bool IsTabFrame() const;
845 inline bool IsRowFrame() const;
846 inline bool IsCellFrame() const;
847 inline bool IsContentFrame() const;
848 inline bool IsTextFrame() const;
849 inline bool IsNoTextFrame() const;
850 // Frames where its PrtArea depends on their neighbors and that are
851 // positioned in the content flow
852 inline bool IsFlowFrame() const;
853 // Frames that are capable of retouching or that might need to retouch behind
854 // themselves
855 inline bool IsRetoucheFrame() const;
856 inline bool IsAccessibleFrame() const;
857
858 void PrepareCursor(); // CursorShell is allowed to call this
859
860 // Is the Frame (or the section containing it) protected? Same for Fly in
861 // Fly in ... and footnotes
862 bool IsProtected() const;
863
864 bool IsColLocked() const { return mbColLocked; }
865 virtual bool IsDeleteForbidden() const { return mbForbidDelete; }
866
867 /// this is the only way to delete a SwFrame instance
868 static void DestroyFrame(SwFrame *const pFrame);
869
870 bool IsInDtor() const { return mbInDtor; }
871
872 // No inline cause we need the function pointers
873 long GetTopMargin() const;
874 long GetBottomMargin() const;
875 long GetLeftMargin() const;
876 long GetRightMargin() const;
877 void SetTopBottomMargins( long, long );
878 void SetLeftRightMargins( long, long );
879 void SetRightLeftMargins( long, long );
880 long GetPrtLeft() const;
881 long GetPrtBottom() const;
882 long GetPrtRight() const;
883 long GetPrtTop() const;
884 bool SetMinLeft( long );
885 bool SetMaxBottom( long );
886 bool SetMaxRight( long );
887 void MakeBelowPos( const SwFrame*, const SwFrame*, bool );
888 void MakeLeftPos( const SwFrame*, const SwFrame*, bool );
889 void MakeRightPos( const SwFrame*, const SwFrame*, bool );
890 bool IsNeighbourFrame() const
891 { return bool(GetType() & FRM_NEIGHBOUR(SwFrameType::Column | SwFrameType::Cell)); }
892
893 // NEW TABLES
894 // Some functions for covered/covering table cells. This way unnecessary
895 // includes can be avoided
896 virtual bool IsLeaveUpperAllowed() const;
897 virtual bool IsCoveredCell() const;
898 bool IsInCoveredCell() const;
899
900 // #i81146# new loop control
901 bool KnowsFormat( const SwFormat& rFormat ) const;
902 void RegisterToFormat( SwFormat& rFormat );
903 void ValidateThisAndAllLowers( const sal_uInt16 nStage );
904
905 void ForbidDelete() { mbForbidDelete = true; }
906 void AllowDelete() { mbForbidDelete = false; }
907
908 drawinglayer::attribute::SdrAllFillAttributesHelperPtr getSdrAllFillAttributesHelper() const;
909 bool supportsFullDrawingLayerFillAttributeSet() const;
910
911public:
912 // if writer is NULL, dumps the layout structure as XML in layout.xml
913 virtual void dumpAsXml(xmlTextWriterPtr writer = nullptr) const;
914 void dumpTopMostAsXml(xmlTextWriterPtr writer = nullptr) const;
915 void dumpInfosAsXml(xmlTextWriterPtr writer) const;
916 virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const;
917 void dumpChildrenAsXml(xmlTextWriterPtr writer) const;
918 bool IsCollapse() const;
919};
920
921inline bool SwFrame::IsInDocBody() const
922{
923 if ( mbInfInvalid )
924 const_cast<SwFrame*>(this)->SetInfFlags();
925 return mbInfBody;
926}
927inline bool SwFrame::IsInFootnote() const
928{
929 if ( mbInfInvalid )
930 const_cast<SwFrame*>(this)->SetInfFlags();
931 return mbInfFootnote;
932}
933inline bool SwFrame::IsInTab() const
934{
935 if ( mbInfInvalid )
936 const_cast<SwFrame*>(this)->SetInfFlags();
937 return mbInfTab;
938}
939inline bool SwFrame::IsInFly() const
940{
941 if ( mbInfInvalid )
942 const_cast<SwFrame*>(this)->SetInfFlags();
943 return mbInfFly;
944}
945inline bool SwFrame::IsInSct() const
946{
947 if ( mbInfInvalid )
948 const_cast<SwFrame*>(this)->SetInfFlags();
949 return mbInfSct;
950}
951bool SwFrame::IsVertical() const
952{
953 if( mbInvalidVert )
954 const_cast<SwFrame*>(this)->SetDirFlags( true );
955 return mbVertical;
956}
957inline bool SwFrame::IsVertLR() const
958{
959 return mbVertLR;
960}
961inline bool SwFrame::IsVertLRBT() const
962{
963 return mbVertLRBT;
964}
965inline bool SwFrame::IsRightToLeft() const
966{
967 if( mbInvalidR2L )
968 const_cast<SwFrame*>(this)->SetDirFlags( false );
969 return mbRightToLeft;
970}
971
972inline void SwFrame::SetCompletePaint() const
973{
974 const_cast<SwFrame*>(this)->mbCompletePaint = true;
975}
976inline void SwFrame::ResetCompletePaint() const
977{
978 const_cast<SwFrame*>(this)->mbCompletePaint = false;
979}
980
981inline void SwFrame::SetRetouche() const
982{
983 const_cast<SwFrame*>(this)->mbRetouche = true;
984}
985inline void SwFrame::ResetRetouche() const
986{
987 const_cast<SwFrame*>(this)->mbRetouche = false;
988}
989
990inline SwLayoutFrame *SwFrame::GetNextLayoutLeaf()
991{
992 return const_cast<SwLayoutFrame*>(static_cast<const SwFrame*>(this)->GetNextLayoutLeaf());
993}
994inline SwLayoutFrame *SwFrame::GetPrevLayoutLeaf()
995{
996 return const_cast<SwLayoutFrame*>(static_cast<const SwFrame*>(this)->GetPrevLayoutLeaf());
997}
998inline const SwLayoutFrame *SwFrame::GetNextLayoutLeaf() const
999{
1000 return ImplGetNextLayoutLeaf( true );
1001}
1002inline const SwLayoutFrame *SwFrame::GetPrevLayoutLeaf() const
1003{
1004 return ImplGetNextLayoutLeaf( false );
1005}
1006
1007inline void SwFrame::InvalidateSize()
1008{
1009 if ( isFrameAreaSizeValid() )
1010 {
1011 ImplInvalidateSize();
1012 }
1013}
1014inline void SwFrame::InvalidatePrt()
1015{
1016 if ( isFramePrintAreaValid() )
1017 {
1018 ImplInvalidatePrt();
1019 }
1020}
1021inline void SwFrame::InvalidatePos()
1022{
1023 if ( isFrameAreaPositionValid() )
1024 {
1025 ImplInvalidatePos();
1026 }
1027}
1028inline void SwFrame::InvalidateLineNum()
1029{
1030 if ( mbValidLineNum )
1031 ImplInvalidateLineNum();
1032}
1033inline void SwFrame::InvalidateAll()
1034{
1035 if ( InvalidationAllowed( INVALID_ALL ) )
1036 {
1037 if ( isFrameAreaDefinitionValid() )
1038 {
1039 ImplInvalidatePos();
1040 }
1041
1042 setFrameAreaSizeValid(false);
1043 setFrameAreaPositionValid(false);
1044 setFramePrintAreaValid(false);
1045
1046 // #i28701#
1047 ActionOnInvalidation( INVALID_ALL );
1048 }
1049}
1050inline void SwFrame::InvalidateNextPos( bool bNoFootnote )
1051{
1052 if ( mpNext && !mpNext->IsSctFrame() )
1053 mpNext->InvalidatePos();
1054 else
1055 ImplInvalidateNextPos( bNoFootnote );
1056}
1057
1058inline void SwFrame::OptCalc() const
1059{
1060 if ( !isFrameAreaPositionValid() || !isFramePrintAreaValid() || !isFrameAreaSizeValid() )
1061 {
1062 const_cast<SwFrame*>(this)->OptPrepareMake();
1063 }
1064}
1065inline const SwPageFrame *SwFrame::FindPageFrame() const
1066{
1067 return const_cast<SwFrame*>(this)->FindPageFrame();
1068}
1069inline const SwFrame *SwFrame::FindColFrame() const
1070{
1071 return const_cast<SwFrame*>(this)->FindColFrame();
1072}
1073inline const SwFrame *SwFrame::FindFooterOrHeader() const
1074{
1075 return const_cast<SwFrame*>(this)->FindFooterOrHeader();
1076}
1077inline SwTabFrame *SwFrame::FindTabFrame()
1078{
1079 return IsInTab() ? ImplFindTabFrame() : nullptr;
34
Assuming the condition is true
35
'?' condition is true
36
Returning pointer, which participates in a condition later
37
Returning pointer
1080}
1081inline const SwFootnoteBossFrame *SwFrame::FindFootnoteBossFrame( bool bFootnote ) const
1082{
1083 return const_cast<SwFrame*>(this)->FindFootnoteBossFrame( bFootnote );
1084}
1085inline SwFootnoteFrame *SwFrame::FindFootnoteFrame()
1086{
1087 return IsInFootnote() ? ImplFindFootnoteFrame() : nullptr;
1088}
1089inline SwFlyFrame *SwFrame::FindFlyFrame()
1090{
1091 return IsInFly() ? ImplFindFlyFrame() : nullptr;
1092}
1093inline SwSectionFrame *SwFrame::FindSctFrame()
1094{
1095 return IsInSct() ? ImplFindSctFrame() : nullptr;
1096}
1097
1098inline const SwBodyFrame *SwFrame::FindBodyFrame() const
1099{
1100 return IsInDocBody() ? ImplFindBodyFrame() : nullptr;
1101}
1102
1103inline const SwTabFrame *SwFrame::FindTabFrame() const
1104{
1105 return IsInTab() ? const_cast<SwFrame*>(this)->ImplFindTabFrame() : nullptr;
1106}
1107inline const SwFootnoteFrame *SwFrame::FindFootnoteFrame() const
1108{
1109 return IsInFootnote() ? const_cast<SwFrame*>(this)->ImplFindFootnoteFrame() : nullptr;
1110}
1111inline const SwFlyFrame *SwFrame::FindFlyFrame() const
1112{
1113 return IsInFly() ? const_cast<SwFrame*>(this)->ImplFindFlyFrame() : nullptr;
1114}
1115inline const SwSectionFrame *SwFrame::FindSctFrame() const
1116{
1117 return IsInSct() ? const_cast<SwFrame*>(this)->ImplFindSctFrame() : nullptr;
1118}
1119inline SwFrame *SwFrame::FindNext()
1120{
1121 if ( mpNext )
1122 return mpNext;
1123 else
1124 return FindNext_();
1125}
1126inline const SwFrame *SwFrame::FindNext() const
1127{
1128 if ( mpNext )
1129 return mpNext;
1130 else
1131 return const_cast<SwFrame*>(this)->FindNext_();
1132}
1133inline SwFrame *SwFrame::FindPrev()
1134{
1135 if ( mpPrev && !mpPrev->IsSctFrame() )
1136 return mpPrev;
1137 else
1138 return FindPrev_();
1139}
1140inline const SwFrame *SwFrame::FindPrev() const
1141{
1142 if ( mpPrev && !mpPrev->IsSctFrame() )
1143 return mpPrev;
1144 else
1145 return const_cast<SwFrame*>(this)->FindPrev_();
1146}
1147
1148inline bool SwFrame::IsLayoutFrame() const
1149{
1150 return bool(GetType() & FRM_LAYOUTSwFrameType(0x3bFF));
1151}
1152inline bool SwFrame::IsRootFrame() const
1153{
1154 return mnFrameType == SwFrameType::Root;
1155}
1156inline bool SwFrame::IsPageFrame() const
1157{
1158 return mnFrameType == SwFrameType::Page;
1159}
1160inline bool SwFrame::IsColumnFrame() const
1161{
1162 return mnFrameType == SwFrameType::Column;
1163}
1164inline bool SwFrame::IsFootnoteBossFrame() const
1165{
1166 return bool(GetType() & FRM_FTNBOSS(SwFrameType::Page | SwFrameType::Column));
1167}
1168inline bool SwFrame::IsHeaderFrame() const
1169{
1170 return mnFrameType == SwFrameType::Header;
1171}
1172inline bool SwFrame::IsFooterFrame() const
1173{
1174 return mnFrameType == SwFrameType::Footer;
1175}
1176inline bool SwFrame::IsFootnoteContFrame() const
1177{
1178 return mnFrameType == SwFrameType::FtnCont;
1179}
1180inline bool SwFrame::IsFootnoteFrame() const
1181{
1182 return mnFrameType == SwFrameType::Ftn;
1183}
1184inline bool SwFrame::IsBodyFrame() const
1185{
1186 return mnFrameType == SwFrameType::Body;
1187}
1188inline bool SwFrame::IsFlyFrame() const
1189{
1190 return mnFrameType == SwFrameType::Fly;
1191}
1192inline bool SwFrame::IsSctFrame() const
1193{
1194 return mnFrameType == SwFrameType::Section;
1195}
1196inline bool SwFrame::IsTabFrame() const
1197{
1198 return mnFrameType == SwFrameType::Tab;
1199}
1200inline bool SwFrame::IsRowFrame() const
1201{
1202 return mnFrameType == SwFrameType::Row;
1203}
1204inline bool SwFrame::IsCellFrame() const
1205{
1206 return mnFrameType == SwFrameType::Cell;
1207}
1208inline bool SwFrame::IsContentFrame() const
1209{
1210 return bool(GetType() & FRM_CNTNT(SwFrameType::Txt | SwFrameType::NoTxt));
1211}
1212inline bool SwFrame::IsTextFrame() const
1213{
1214 return mnFrameType == SwFrameType::Txt;
1215}
1216inline bool SwFrame::IsNoTextFrame() const
1217{
1218 return mnFrameType == SwFrameType::NoTxt;
1219}
1220inline bool SwFrame::IsFlowFrame() const
1221{
1222 return bool(GetType() & (FRM_CNTNT(SwFrameType::Txt | SwFrameType::NoTxt)|SwFrameType::Tab|SwFrameType::Section));
1223}
1224inline bool SwFrame::IsRetoucheFrame() const
1225{
1226 return bool(GetType() & (FRM_CNTNT(SwFrameType::Txt | SwFrameType::NoTxt)|SwFrameType::Tab|SwFrameType::Section|SwFrameType::Ftn));
1227}
1228inline bool SwFrame::IsAccessibleFrame() const
1229{
1230 return bool(GetType() & FRM_ACCESSIBLE(SwFrameType::Root | SwFrameType::Page | SwFrameType::Header |
SwFrameType::Footer | SwFrameType::Ftn | SwFrameType::Fly | SwFrameType
::Tab | SwFrameType::Cell | SwFrameType::Txt)
);
1231}
1232
1233//use this to protect a SwFrame for a given scope from getting deleted
1234class SwFrameDeleteGuard
1235{
1236private:
1237 SwFrame *m_pForbidFrame;
1238public:
1239 //Flag pFrame for SwFrameDeleteGuard lifetime that we shouldn't delete
1240 //it in e.g. SwSectionFrame::MergeNext etc because we will need it
1241 //again after the SwFrameDeleteGuard dtor
1242 explicit SwFrameDeleteGuard(SwFrame* pFrame)
1243 : m_pForbidFrame((pFrame && !pFrame->IsDeleteForbidden()) ?
1244 pFrame : nullptr)
1245 {
1246 if (m_pForbidFrame)
1247 m_pForbidFrame->ForbidDelete();
1248 }
1249
1250 SwFrameDeleteGuard(const SwFrameDeleteGuard&) =delete;
1251
1252 ~SwFrameDeleteGuard()
1253 {
1254 if (m_pForbidFrame)
1255 m_pForbidFrame->AllowDelete();
1256 }
1257
1258 SwFrameDeleteGuard& operator=(const SwFrameDeleteGuard&) =delete;
1259};
1260
1261typedef long (SwFrame::*SwFrameGet)() const;
1262typedef bool (SwFrame::*SwFrameMax)( long );
1263typedef void (SwFrame::*SwFrameMakePos)( const SwFrame*, const SwFrame*, bool );
1264typedef long (*SwOperator)( long, long );
1265typedef void (SwFrame::*SwFrameSet)( long, long );
1266
1267struct SwRectFnCollection
1268{
1269 SwRectGet fnGetTop;
1270 SwRectGet fnGetBottom;
1271 SwRectGet fnGetLeft;
1272 SwRectGet fnGetRight;
1273 SwRectGet fnGetWidth;
1274 SwRectGet fnGetHeight;
1275 SwRectPoint fnGetPos;
1276 SwRectSize fnGetSize;
1277
1278 SwRectSet fnSetTop;
1279 SwRectSet fnSetBottom;
1280 SwRectSet fnSetLeft;
1281 SwRectSet fnSetRight;
1282 SwRectSet fnSetWidth;
1283 SwRectSet fnSetHeight;
1284
1285 SwRectSet fnSubTop;
1286 SwRectSet fnAddBottom;
1287 SwRectSet fnSubLeft;
1288 SwRectSet fnAddRight;
1289 SwRectSet fnAddWidth;
1290 SwRectSet fnAddHeight;
1291
1292 SwRectSet fnSetPosX;
1293 SwRectSet fnSetPosY;
1294
1295 SwFrameGet fnGetTopMargin;
1296 SwFrameGet fnGetBottomMargin;
1297 SwFrameGet fnGetLeftMargin;
1298 SwFrameGet fnGetRightMargin;
1299 SwFrameSet fnSetXMargins;
1300 SwFrameSet fnSetYMargins;
1301 SwFrameGet fnGetPrtTop;
1302 SwFrameGet fnGetPrtBottom;
1303 SwFrameGet fnGetPrtLeft;
1304 SwFrameGet fnGetPrtRight;
1305 SwRectDist fnTopDist;
1306 SwRectDist fnBottomDist;
1307 SwRectDist fnLeftDist;
1308 SwRectDist fnRightDist;
1309 SwFrameMax fnSetLimit;
1310 SwRectMax fnOverStep;
1311
1312 SwRectSetPos fnSetPos;
1313 SwFrameMakePos fnMakePos;
1314 SwOperator fnXDiff;
1315 SwOperator fnYDiff;
1316 SwOperator fnXInc;
1317 SwOperator fnYInc;
1318
1319 SwRectSetTwice fnSetLeftAndWidth;
1320 SwRectSetTwice fnSetTopAndHeight;
1321};
1322
1323typedef SwRectFnCollection* SwRectFn;
1324
1325// This class allows to use proper methods regardless of orientation (LTR/RTL, horizontal or vertical)
1326extern SwRectFn fnRectHori, fnRectVert, fnRectVertL2R, fnRectVertL2RB2T;
1327class SwRectFnSet {
1328public:
1329 explicit SwRectFnSet(const SwFrame *pFrame)
1330 : m_bVert(pFrame->IsVertical())
1331 , m_bVertL2R(pFrame->IsVertLR())
1332 , m_bVertL2RB2T(pFrame->IsVertLRBT())
1333 {
1334 m_fnRect = m_bVert ? (m_bVertL2R ? (m_bVertL2RB2T ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert) : fnRectHori;
1335 }
1336
1337 void Refresh(const SwFrame *pFrame)
1338 {
1339 m_bVert = pFrame->IsVertical();
1340 m_bVertL2R = pFrame->IsVertLR();
1341 m_bVertL2RB2T = pFrame->IsVertLRBT();
1342 m_fnRect = m_bVert ? (m_bVertL2R ? (m_bVertL2RB2T ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert) : fnRectHori;
1343 }
1344
1345 bool IsVert() const { return m_bVert; }
1346 bool IsVertL2R() const { return m_bVertL2R; }
1347 SwRectFn FnRect() const { return m_fnRect; }
1348
1349 bool PosDiff(const SwRect &rRect1, const SwRect &rRect2) const
1350 {
1351 return ((rRect1.*m_fnRect->fnGetTop)() != (rRect2.*m_fnRect->fnGetTop)()
1352 || (rRect1.*m_fnRect->fnGetLeft)() != (rRect2.*m_fnRect->fnGetLeft)());
1353 }
1354
1355 long GetTop (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetTop) (); }
1356 long GetBottom(const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetBottom)(); }
1357 long GetLeft (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetLeft) (); }
1358 long GetRight (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetRight) (); }
1359 long GetWidth (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetWidth) (); }
1360 long GetHeight(const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetHeight)(); }
1361 Point GetPos (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetPos) (); }
1362 Size GetSize (const SwRect& rRect) const { return (rRect.*m_fnRect->fnGetSize) (); }
1363
1364 void SetTop (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetTop) (nNew); }
1365 void SetBottom(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetBottom)(nNew); }
1366 void SetLeft (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetLeft) (nNew); }
1367 void SetRight (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetRight) (nNew); }
1368 void SetWidth (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetWidth) (nNew); }
1369 void SetHeight(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetHeight)(nNew); }
1370
1371 void SubTop (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSubTop) (nNew); }
1372 void AddBottom(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnAddBottom)(nNew); }
1373 void SubLeft (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSubLeft) (nNew); }
1374 void AddRight (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnAddRight) (nNew); }
1375 void AddWidth (SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnAddWidth) (nNew); }
1376 void AddHeight(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnAddHeight)(nNew); }
1377
1378 void SetPosX(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetPosX)(nNew); }
1379 void SetPosY(SwRect& rRect, long nNew) const { (rRect.*m_fnRect->fnSetPosY)(nNew); }
1380
1381 long GetTopMargin (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetTopMargin) (); }
1382 long GetBottomMargin(const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetBottomMargin)(); }
1383 long GetLeftMargin (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetLeftMargin) (); }
1384 long GetRightMargin (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetRightMargin) (); }
1385 void SetXMargins(SwFrame& rFrame, long nLeft, long nRight) const { (rFrame.*m_fnRect->fnSetXMargins)(nLeft, nRight); }
1386 void SetYMargins(SwFrame& rFrame, long nTop, long nBottom) const { (rFrame.*m_fnRect->fnSetYMargins)(nTop, nBottom); }
1387 long GetPrtTop (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetPrtTop) (); }
1388 long GetPrtBottom (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetPrtBottom) (); }
1389 long GetPrtLeft (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetPrtLeft) (); }
1390 long GetPrtRight (const SwFrame& rFrame) const { return (rFrame.*m_fnRect->fnGetPrtRight) (); }
1391 long TopDist (const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnTopDist) (nPos); }
1392 long BottomDist(const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnBottomDist) (nPos); }
1393 long LeftDist (const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnLeftDist) (nPos); }
1394 long RightDist (const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnRightDist) (nPos); }
1395 void SetLimit (SwFrame& rFrame, long nNew) const { (rFrame.*m_fnRect->fnSetLimit) (nNew); }
1396 bool OverStep (const SwRect& rRect, long nPos) const { return (rRect.*m_fnRect->fnOverStep) (nPos); }
1397
1398 void SetPos(SwRect& rRect, const Point& rNew) const { (rRect.*m_fnRect->fnSetPos)(rNew); }
1399 void MakePos(SwFrame& rFrame, const SwFrame* pUp, const SwFrame* pPrv, bool bNotify) const { (rFrame.*m_fnRect->fnMakePos)(pUp, pPrv, bNotify); }
1400 long XDiff(long n1, long n2) const { return (m_fnRect->fnXDiff) (n1, n2); }
1401 long YDiff(long n1, long n2) const { return (m_fnRect->fnYDiff) (n1, n2); }
1402 long XInc (long n1, long n2) const { return (m_fnRect->fnXInc) (n1, n2); }
1403 long YInc (long n1, long n2) const { return (m_fnRect->fnYInc) (n1, n2); }
1404
1405 void SetLeftAndWidth(SwRect& rRect, long nLeft, long nWidth) const { (rRect.*m_fnRect->fnSetLeftAndWidth)(nLeft, nWidth); }
1406 void SetTopAndHeight(SwRect& rRect, long nTop, long nHeight) const { (rRect.*m_fnRect->fnSetTopAndHeight)(nTop, nHeight); }
1407
1408private:
1409 bool m_bVert;
1410 bool m_bVertL2R;
1411 bool m_bVertL2RB2T;
1412 SwRectFn m_fnRect;
1413};
1414
1415#endif
1416
1417/* vim:set shiftwidth=4 softtabstop=4 expandtab: */