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