xref: /trunk/main/sw/source/core/table/swtable.cxx (revision 28160478)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 #include <ctype.h>
28 #include <float.h>
29 #include <hintids.hxx>
30 #include <hints.hxx>  	// fuer SwAttrSetChg
31 #include <editeng/lrspitem.hxx>
32 #include <editeng/shaditem.hxx>
33 #include <editeng/adjitem.hxx>
34 #include <editeng/colritem.hxx>
35 #include <sfx2/linkmgr.hxx>
36 #include <editeng/boxitem.hxx>
37 #include <fmtfsize.hxx>
38 #include <fmtornt.hxx>
39 #include <fmtpdsc.hxx>
40 #include <fldbas.hxx>
41 #include <fmtfld.hxx>
42 #include <frmatr.hxx>
43 #include <doc.hxx>
44 #include <docary.hxx> 	// fuer RedlineTbl()
45 #include <frame.hxx>
46 #include <swtable.hxx>
47 #include <ndtxt.hxx>
48 #include <tabcol.hxx>
49 #include <tabfrm.hxx>
50 #include <cellfrm.hxx>
51 #include <rowfrm.hxx>
52 #include <swserv.hxx>
53 #include <expfld.hxx>
54 #include <mdiexp.hxx>
55 #include <cellatr.hxx>
56 #include <txatbase.hxx>
57 #include <htmltbl.hxx>
58 #include <swtblfmt.hxx>
59 #include <ndindex.hxx>
60 #include <tblrwcl.hxx>
61 #include <shellres.hxx>
62 #include <viewsh.hxx>
63 #include <redline.hxx>
64 #include <list>
65 #include <switerator.hxx>
66 
67 #ifndef DBG_UTIL
68 #define CHECK_TABLE(t)
69 #else
70 #ifdef DEBUG
71 #define CHECK_TABLE(t) (t).CheckConsistency();
72 #else
73 #define CHECK_TABLE(t)
74 #endif
75 #endif
76 
77 using namespace com::sun::star;
78 
79 TYPEINIT1( SwTable, SwClient );
80 TYPEINIT1( SwTableBox, SwClient );
81 TYPEINIT1( SwTableLine, SwClient );
82 
83 //UUUU
84 TYPEINIT1( SwTableFmt, SwFrmFmt );
85 
SwTableFmt(SwAttrPool & rPool,const sal_Char * pFmtNm,SwFrmFmt * pDrvdFrm)86 SwTableFmt::SwTableFmt(SwAttrPool& rPool,const sal_Char* pFmtNm, SwFrmFmt *pDrvdFrm)
87 :   SwFrmFmt(rPool,pFmtNm,pDrvdFrm,RES_FRMFMT,aTableSetRange)
88 {
89 }
90 
SwTableFmt(SwAttrPool & rPool,const String & rFmtNm,SwFrmFmt * pDrvdFrm)91 SwTableFmt::SwTableFmt(SwAttrPool& rPool,const String &rFmtNm, SwFrmFmt *pDrvdFrm)
92 :   SwFrmFmt(rPool,rFmtNm,pDrvdFrm,RES_FRMFMT,aTableSetRange)
93 {
94 }
95 
~SwTableFmt()96 SwTableFmt::~SwTableFmt()
97 {
98 }
99 
100 //UUUU Do not support for table frames - may change later if support will be added
supportsFullDrawingLayerFillAttributeSet() const101 bool SwTableFmt::supportsFullDrawingLayerFillAttributeSet() const
102 {
103     return false;
104 }
105 
106 //UUUU
107 TYPEINIT1( SwTableBoxFmt, SwFrmFmt );
108 
SwTableBoxFmt(SwAttrPool & rPool,const sal_Char * pFmtNm,SwFrmFmt * pDrvdFrm)109 SwTableBoxFmt::SwTableBoxFmt(SwAttrPool& rPool,const sal_Char* pFmtNm, SwFrmFmt *pDrvdFrm)
110 : SwFrmFmt(rPool,pFmtNm,pDrvdFrm,RES_FRMFMT,aTableBoxSetRange)
111 {
112 }
113 
SwTableBoxFmt(SwAttrPool & rPool,const String & rFmtNm,SwFrmFmt * pDrvdFrm)114 SwTableBoxFmt::SwTableBoxFmt(SwAttrPool& rPool,const String &rFmtNm, SwFrmFmt *pDrvdFrm)
115 :   SwFrmFmt(rPool,rFmtNm,pDrvdFrm,RES_FRMFMT,aTableBoxSetRange)
116 {
117 }
118 
~SwTableBoxFmt()119 SwTableBoxFmt::~SwTableBoxFmt()
120 {
121 }
122 
123 //UUUU Do not support for table frames - may change later if support will be added
supportsFullDrawingLayerFillAttributeSet() const124 bool SwTableBoxFmt::supportsFullDrawingLayerFillAttributeSet() const
125 {
126     return false;
127 }
128 
129 //UUUU
130 TYPEINIT1( SwTableLineFmt, SwFrmFmt );
131 
SwTableLineFmt(SwAttrPool & rPool,const sal_Char * pFmtNm,SwFrmFmt * pDrvdFrm)132 SwTableLineFmt::SwTableLineFmt(SwAttrPool& rPool,const sal_Char* pFmtNm, SwFrmFmt *pDrvdFrm)
133 :   SwFrmFmt(rPool,pFmtNm,pDrvdFrm,RES_FRMFMT,aTableLineSetRange)
134 {
135 }
136 
SwTableLineFmt(SwAttrPool & rPool,const String & rFmtNm,SwFrmFmt * pDrvdFrm)137 SwTableLineFmt::SwTableLineFmt(SwAttrPool& rPool,const String &rFmtNm, SwFrmFmt *pDrvdFrm)
138 :   SwFrmFmt(rPool,rFmtNm,pDrvdFrm,RES_FRMFMT,aTableLineSetRange)
139 {
140 }
141 
~SwTableLineFmt()142 SwTableLineFmt::~SwTableLineFmt()
143 {
144 }
145 
146 //UUUU Do not support for table frames - may change later if support will be added
supportsFullDrawingLayerFillAttributeSet() const147 bool SwTableLineFmt::supportsFullDrawingLayerFillAttributeSet() const
148 {
149     return false;
150 }
151 
152 SV_IMPL_PTRARR(SwTableLines,SwTableLine*);
153 SV_IMPL_PTRARR(SwTableBoxes,SwTableBox*);
154 SV_IMPL_PTRARR_SORT(SwTableSortBoxes,SwTableBoxPtr);
155 
156 SV_IMPL_REF( SwServerObject )
157 
158 #define COLFUZZY 20
159 
160 void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol,
161 					sal_Bool bChgAlign,sal_uLong nNdPos );
162 //----------------------------------
163 
164 class SwTableBox_Impl
165 {
166 	Color *mpUserColor, *mpNumFmtColor;
167     long mnRowSpan;
168     bool mbDummyFlag;
169 
170 	void SetNewCol( Color** ppCol, const Color* pNewCol );
171 public:
SwTableBox_Impl()172 	SwTableBox_Impl() : mpUserColor(0), mpNumFmtColor(0), mnRowSpan(1),
173         mbDummyFlag( false ) {}
~SwTableBox_Impl()174 	~SwTableBox_Impl() { delete mpUserColor; delete mpNumFmtColor; }
175 
GetSaveUserColor() const176 	const Color* GetSaveUserColor()	const		{ return mpUserColor; }
GetSaveNumFmtColor() const177 	const Color* GetSaveNumFmtColor() const 	{ return mpNumFmtColor; }
SetSaveUserColor(const Color * p)178 	void SetSaveUserColor(const Color* p )		{ SetNewCol( &mpUserColor, p ); }
SetSaveNumFmtColor(const Color * p)179 	void SetSaveNumFmtColor( const Color* p )	{ SetNewCol( &mpNumFmtColor, p ); }
getRowSpan() const180     long getRowSpan() const { return mnRowSpan; }
setRowSpan(long nNewRowSpan)181     void setRowSpan( long nNewRowSpan ) { mnRowSpan = nNewRowSpan; }
getDummyFlag() const182     bool getDummyFlag() const { return mbDummyFlag; }
setDummyFlag(bool bDummy)183     void setDummyFlag( bool bDummy ) { mbDummyFlag = bDummy; }
184 };
185 
186 // ----------- Inlines -----------------------------
187 
GetSaveUserColor() const188 inline const Color* SwTableBox::GetSaveUserColor() const
189 {
190 	return pImpl ? pImpl->GetSaveUserColor() : 0;
191 }
192 
GetSaveNumFmtColor() const193 inline const Color* SwTableBox::GetSaveNumFmtColor() const
194 {
195 	return pImpl ? pImpl->GetSaveNumFmtColor() : 0;
196 }
197 
SetSaveUserColor(const Color * p)198 inline void SwTableBox::SetSaveUserColor(const Color* p )
199 {
200 	if( pImpl )
201 		pImpl->SetSaveUserColor( p );
202 	else if( p )
203 		( pImpl = new SwTableBox_Impl ) ->SetSaveUserColor( p );
204 }
205 
SetSaveNumFmtColor(const Color * p)206 inline void SwTableBox::SetSaveNumFmtColor( const Color* p )
207 {
208 	if( pImpl )
209 		pImpl->SetSaveNumFmtColor( p );
210 	else if( p )
211 		( pImpl = new SwTableBox_Impl )->SetSaveNumFmtColor( p );
212 }
213 
getRowSpan() const214 long SwTableBox::getRowSpan() const
215 {
216     return pImpl ? pImpl->getRowSpan() : 1;
217 }
218 
setRowSpan(long nNewRowSpan)219 void SwTableBox::setRowSpan( long nNewRowSpan )
220 {
221     if( !pImpl )
222     {
223         if( nNewRowSpan == 1 )
224             return;
225         pImpl = new SwTableBox_Impl();
226     }
227     pImpl->setRowSpan( nNewRowSpan );
228 }
229 
getDummyFlag() const230 bool SwTableBox::getDummyFlag() const
231 {
232     return pImpl ? pImpl->getDummyFlag() : false;
233 }
234 
setDummyFlag(bool bDummy)235 void SwTableBox::setDummyFlag( bool bDummy )
236 {
237     if( !pImpl )
238     {
239         if( !bDummy )
240             return;
241         pImpl = new SwTableBox_Impl();
242     }
243     pImpl->setDummyFlag( bDummy );
244 }
245 
246 //JP 15.09.98: Bug 55741 - Tabs beibehalten (vorne und hinten)
lcl_TabToBlankAtSttEnd(String & rTxt)247 String& lcl_TabToBlankAtSttEnd( String& rTxt )
248 {
249 	sal_Unicode c;
250 	xub_StrLen n;
251 
252 	for( n = 0; n < rTxt.Len() && ' ' >= ( c = rTxt.GetChar( n )); ++n )
253 		if( '\x9' == c )
254 			rTxt.SetChar( n, ' ' );
255 	for( n = rTxt.Len(); n && ' ' >= ( c = rTxt.GetChar( --n )); )
256 		if( '\x9' == c )
257 			rTxt.SetChar( n, ' ' );
258 	return rTxt;
259 }
260 
lcl_DelTabsAtSttEnd(String & rTxt)261 String& lcl_DelTabsAtSttEnd( String& rTxt )
262 {
263 	sal_Unicode c;
264 	xub_StrLen n;
265 
266 	for( n = 0; n < rTxt.Len() && ' ' >= ( c = rTxt.GetChar( n )); ++n )
267 		if( '\x9' == c )
268 			rTxt.Erase( n--, 1 );
269 	for( n = rTxt.Len(); n && ' ' >= ( c = rTxt.GetChar( --n )); )
270 		if( '\x9' == c )
271 			rTxt.Erase( n, 1 );
272 	return rTxt;
273 }
274 
_InsTblBox(SwDoc * pDoc,SwTableNode * pTblNd,SwTableLine * pLine,SwTableBoxFmt * pBoxFrmFmt,SwTableBox * pBox,sal_uInt16 nInsPos,sal_uInt16 nCnt)275 void _InsTblBox( SwDoc* pDoc, SwTableNode* pTblNd,
276 						SwTableLine* pLine, SwTableBoxFmt* pBoxFrmFmt,
277 						SwTableBox* pBox,
278 						sal_uInt16 nInsPos, sal_uInt16 nCnt )
279 {
280 	ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" );
281 	SwNodeIndex aIdx( *pBox->GetSttNd(), +1 );
282 	SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode();
283 	if( !pCNd )
284 		pCNd = pDoc->GetNodes().GoNext( &aIdx );
285 	ASSERT( pCNd, "Box ohne ContentNode" );
286 
287 	if( pCNd->IsTxtNode() )
288 	{
289 		if( pBox->GetSaveNumFmtColor() && pCNd->GetpSwAttrSet() )
290 		{
291 			SwAttrSet aAttrSet( *pCNd->GetpSwAttrSet() );
292 			if( pBox->GetSaveUserColor() )
293 				aAttrSet.Put( SvxColorItem( *pBox->GetSaveUserColor(), RES_CHRATR_COLOR ));
294 			else
295 				aAttrSet.ClearItem( RES_CHRATR_COLOR );
296 			pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt,
297 									((SwTxtNode*)pCNd)->GetTxtColl(),
298 									&aAttrSet, nInsPos, nCnt );
299 		}
300 		else
301 			pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt,
302 									((SwTxtNode*)pCNd)->GetTxtColl(),
303 									pCNd->GetpSwAttrSet(),
304 									nInsPos, nCnt );
305 	}
306 	else
307 		pDoc->GetNodes().InsBoxen( pTblNd, pLine, pBoxFrmFmt,
308 				(SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0,
309 				nInsPos, nCnt );
310 
311     long nRowSpan = pBox->getRowSpan();
312     if( nRowSpan != 1 )
313     {
314 		SwTableBoxes& rTblBoxes = pLine->GetTabBoxes();
315         for( sal_uInt16 i = 0; i < nCnt; ++i )
316         {
317             pBox = rTblBoxes[ i + nInsPos ];
318             pBox->setRowSpan( nRowSpan );
319         }
320     }
321 }
322 
323 /*************************************************************************
324 |*
325 |*	SwTable::SwTable()
326 |*
327 |*************************************************************************/
SwTable(SwTableFmt * pFmt)328 SwTable::SwTable( SwTableFmt* pFmt )
329 	: SwClient( pFmt ),
330 	pHTMLLayout( 0 ),
331     pTableNode( 0 ),
332 	nGrfsThatResize( 0 ),
333     nRowsToRepeat( 1 ),
334     bModifyLocked( sal_False ),
335     bNewModel( sal_True )
336 {
337 	// default Wert aus den Optionen setzen
338 	eTblChgMode = (TblChgMode)GetTblChgDefaultMode();
339 }
340 
SwTable(const SwTable & rTable)341 SwTable::SwTable( const SwTable& rTable )
342 	: SwClient( rTable.GetFrmFmt() ),
343 	pHTMLLayout( 0 ),
344     pTableNode( 0 ),
345 	eTblChgMode( rTable.eTblChgMode ),
346 	nGrfsThatResize( 0 ),
347     nRowsToRepeat( rTable.GetRowsToRepeat() ),
348     bModifyLocked( sal_False ),
349     bNewModel( rTable.bNewModel )
350 {
351 }
352 
DelBoxNode(SwTableSortBoxes & rSortCntBoxes)353 void DelBoxNode( SwTableSortBoxes& rSortCntBoxes )
354 {
355 	for( sal_uInt16 n = 0; n < rSortCntBoxes.Count(); ++n )
356 		rSortCntBoxes[ n ]->pSttNd = 0;
357 }
358 
~SwTable()359 SwTable::~SwTable()
360 {
361 	if( refObj.Is() )
362 	{
363 		SwDoc* pDoc = GetFrmFmt()->GetDoc();
364 		if( !pDoc->IsInDtor() )			// dann aus der Liste entfernen
365 			pDoc->GetLinkManager().RemoveServer( &refObj );
366 
367 		refObj->Closed();
368 	}
369 
370 	// ist die Tabelle der letzte Client im FrameFormat, kann dieses
371 	// geloescht werden
372 	SwTableFmt* pFmt = (SwTableFmt*)GetFrmFmt();
373 	pFmt->Remove( this );				// austragen,
374 
375 	if( !pFmt->GetDepends() )
376 		pFmt->GetDoc()->DelTblFrmFmt( pFmt );	// und loeschen
377 
378 	// Loesche die Pointer aus dem SortArray der Boxen, die
379 	// Objecte bleiben erhalten und werden vom DTOR der Lines/Boxes
380 	// Arrays geloescht.
381 	//JP: reicht leider nicht, es muessen die Pointer auf den StartNode
382 	//	der Section geloescht werden
383 	DelBoxNode( aSortCntBoxes );
384 	aSortCntBoxes.Remove( (sal_uInt16)0, aSortCntBoxes.Count() );
385 	delete pHTMLLayout;
386 }
387 
388 /*************************************************************************
389 |*
390 |*	SwTable::Modify()
391 |*
392 |*************************************************************************/
FmtInArr(SvPtrarr & rFmtArr,SwFmt * pBoxFmt)393 inline void FmtInArr( SvPtrarr& rFmtArr, SwFmt* pBoxFmt )
394 {
395 	sal_Bool bRet = USHRT_MAX != rFmtArr.GetPos( (VoidPtr)pBoxFmt );
396 	if( !bRet )
397 		rFmtArr.Insert( (VoidPtr)pBoxFmt, rFmtArr.Count() );
398 }
399 
400 void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld,
401 						 const long nNew, SvPtrarr& rFmtArr );
402 
lcl_ModifyLines(SwTableLines & rLines,const long nOld,const long nNew,SvPtrarr & rFmtArr,const bool bCheckSum)403 void lcl_ModifyLines( SwTableLines &rLines, const long nOld,
404 						 const long nNew, SvPtrarr& rFmtArr, const bool bCheckSum )
405 {
406 	for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
407 		::lcl_ModifyBoxes( rLines[i]->GetTabBoxes(), nOld, nNew, rFmtArr );
408     if( bCheckSum )
409     {
410         for( sal_uInt16 i = 0; i < rFmtArr.Count(); ++i )
411         {
412             SwFmt* pFmt = (SwFmt*)rFmtArr[i];
413             sal_uInt64 nBox = pFmt->GetFrmSize().GetWidth();
414             nBox *= nNew;
415             nBox /= nOld;
416 			SwFmtFrmSize aNewBox( ATT_VAR_SIZE, SwTwips(nBox), 0 );
417 			pFmt->LockModify();
418             pFmt->SetFmtAttr( aNewBox );
419 			pFmt->UnlockModify();
420         }
421     }
422 }
423 
lcl_ModifyBoxes(SwTableBoxes & rBoxes,const long nOld,const long nNew,SvPtrarr & rFmtArr)424 void lcl_ModifyBoxes( SwTableBoxes &rBoxes, const long nOld,
425 						 const long nNew, SvPtrarr& rFmtArr )
426 {
427     sal_uInt64 nSum = 0; // To avoid rounding errors we summarize all box widths
428     sal_uInt64 nOriginalSum = 0; // Sum of original widths
429 	for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
430 	{
431 		SwTableBox &rBox = *rBoxes[i];
432 		if ( rBox.GetTabLines().Count() )
433         {
434             // For SubTables the rounding problem will not be solved :-(
435 			::lcl_ModifyLines( rBox.GetTabLines(), nOld, nNew, rFmtArr, false );
436         }
437 		//Die Box anpassen
438 		SwFrmFmt *pFmt = rBox.GetFrmFmt();
439         sal_uInt64 nBox = pFmt->GetFrmSize().GetWidth();
440         nOriginalSum += nBox;
441         nBox *= nNew;
442         nBox /= nOld;
443         sal_uInt64 nWishedSum = nOriginalSum;
444         nWishedSum *= nNew;
445         nWishedSum /= nOld;
446         nWishedSum -= nSum;
447         if( nWishedSum > 0 )
448         {
449             if( nBox == nWishedSum )
450                 FmtInArr( rFmtArr, pFmt );
451             else
452             {
453                 nBox = nWishedSum;
454                 pFmt = rBox.ClaimFrmFmt();
455                 SwFmtFrmSize aNewBox( ATT_VAR_SIZE, static_cast< SwTwips >(nBox), 0 );
456                 pFmt->LockModify();
457                 pFmt->SetFmtAttr( aNewBox );
458                 pFmt->UnlockModify();
459             }
460         }
461         else {
462             ASSERT( false, "Rounding error" );
463         }
464         nSum += nBox;
465 	}
466 }
467 
Modify(const SfxPoolItem * pOld,const SfxPoolItem * pNew)468 void SwTable::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
469 {
470 	// fange SSize Aenderungen ab, um die Lines/Boxen anzupassen
471 	sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0 ;
472 	const SwFmtFrmSize* pNewSize = 0, *pOldSize = 0;
473 
474 	if( RES_ATTRSET_CHG == nWhich )
475 	{
476 		if( SFX_ITEM_SET == ((SwAttrSetChg*)pNew)->GetChgSet()->GetItemState(
477 			RES_FRM_SIZE, sal_False, (const SfxPoolItem**)&pNewSize ))
478 			pOldSize = &((SwAttrSetChg*)pOld)->GetChgSet()->GetFrmSize();
479 	}
480 	else if( RES_FRM_SIZE == nWhich )
481 	{
482 		pOldSize = (const SwFmtFrmSize*)pOld;
483 		pNewSize = (const SwFmtFrmSize*)pNew;
484 	}
485     else
486         CheckRegistration( pOld, pNew );
487 
488 	if( pOldSize || pNewSize )
489 	{
490 		if ( !IsModifyLocked() )
491 		{
492 			ASSERT( pOldSize && pOldSize->Which() == RES_FRM_SIZE &&
493 					pNewSize && pNewSize->Which() == RES_FRM_SIZE,
494 					"Kein Old oder New fuer FmtFrmSize-Modify der SwTable." );
495             AdjustWidths( pOldSize->GetWidth(), pNewSize->GetWidth() );
496 		}
497 	}
498 }
499 
AdjustWidths(const long nOld,const long nNew)500 void SwTable::AdjustWidths( const long nOld, const long nNew )
501 {
502     SvPtrarr aFmtArr( (sal_uInt8)aLines[0]->GetTabBoxes().Count(), 1 );
503     ::lcl_ModifyLines( aLines, nOld, nNew, aFmtArr, true );
504 }
505 
506 /*************************************************************************
507 |*
508 |*	SwTable::GetTabCols()
509 |*
510 |*************************************************************************/
lcl_RefreshHidden(SwTabCols & rToFill,sal_uInt16 nPos)511 void lcl_RefreshHidden( SwTabCols &rToFill, sal_uInt16 nPos )
512 {
513 	for ( sal_uInt16 i = 0; i < rToFill.Count(); ++i )
514 	{
515 		if ( Abs((long)(nPos - rToFill[i])) <= COLFUZZY )
516 		{
517             rToFill.SetHidden( i, sal_False );
518 			break;
519 		}
520 	}
521 }
522 
lcl_SortedTabColInsert(SwTabCols & rToFill,const SwTableBox * pBox,const SwFrmFmt * pTabFmt,const sal_Bool bHidden,const FASTBOOL bRefreshHidden)523 void lcl_SortedTabColInsert( SwTabCols &rToFill, const SwTableBox *pBox,
524                    const SwFrmFmt *pTabFmt, const sal_Bool bHidden,
525 				   const FASTBOOL bRefreshHidden )
526 {
527 	const long nWish = pTabFmt->GetFrmSize().GetWidth();
528 	const long nAct  = rToFill.GetRight() - rToFill.GetLeft();  // +1 why?
529 
530 	//Der Wert fuer die linke Kante der Box errechnet sich aus den
531 	//Breiten der vorhergehenden Boxen.
532 	sal_uInt16 nPos = 0;
533     sal_uInt16 nSum = 0;
534     sal_uInt16 nLeftMin = 0;
535     sal_uInt16 nRightMax = 0;
536 	const SwTableBox  *pCur  = pBox;
537 	const SwTableLine *pLine = pBox->GetUpper();
538 	while ( pLine )
539 	{	const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
540 		for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
541 		{
542             SwTwips nWidth = rBoxes[i]->GetFrmFmt()->GetFrmSize().GetWidth();
543             nSum = (sal_uInt16)(nSum + nWidth);
544 			sal_uInt64 nTmp = nSum;
545             nTmp *= nAct;
546 			nTmp /= nWish;
547             if (rBoxes[i] != pCur)
548             {
549                 if ( pLine == pBox->GetUpper() || 0 == nLeftMin )
550                     nLeftMin = (sal_uInt16)(nTmp - nPos);
551 			    nPos = (sal_uInt16)nTmp;
552             }
553             else
554             {
555                 nSum = (sal_uInt16)(nSum - nWidth);
556                 if ( 0 == nRightMax )
557                     nRightMax = (sal_uInt16)(nTmp - nPos);
558                 break;
559             }
560 		}
561 		pCur  = pLine->GetUpper();
562 		pLine = pCur ? pCur->GetUpper() : 0;
563 	}
564 
565     sal_Bool bInsert = !bRefreshHidden;
566 	for ( sal_uInt16 j = 0; bInsert && (j < rToFill.Count()); ++j )
567 	{
568         long nCmp = rToFill[j];
569 		if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
570 			 (nPos <= (nCmp + COLFUZZY)) )
571 		{
572 			bInsert = sal_False;		//Hat ihn schon.
573 		}
574 		else if ( nPos < nCmp )
575 		{
576     		bInsert = sal_False;
577             rToFill.Insert( nPos, bHidden, j );
578 		}
579 	}
580 	if ( bInsert )
581         rToFill.Insert( nPos, bHidden, rToFill.Count() );
582 	else if ( bRefreshHidden )
583 		::lcl_RefreshHidden( rToFill, nPos );
584 
585     if ( bHidden && !bRefreshHidden )
586     {
587         // calculate minimum/maximum values for the existing entries:
588         nLeftMin = nPos - nLeftMin;
589         nRightMax = nPos + nRightMax;
590 
591         // check if nPos is entry:
592         bool bFoundPos = false;
593         bool bFoundMax = false;
594     	for ( sal_uInt16 j = 0; !(bFoundPos && bFoundMax ) && j < rToFill.Count(); ++j )
595         {
596             SwTabColsEntry& rEntry = rToFill.GetEntry( j );
597             long nCmp = rToFill[j];
598 
599             if ( (nPos >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
600 			     (nPos <= (nCmp + COLFUZZY)) )
601             {
602                 // check if nLeftMin is > old minimum for entry nPos:
603                 const long nOldMin = rEntry.nMin;
604                 if ( nLeftMin > nOldMin )
605                     rEntry.nMin = nLeftMin;
606                 // check if nRightMin is < old maximum for entry nPos:
607                 const long nOldMax = rEntry.nMax;
608                 if ( nRightMax < nOldMax )
609                     rEntry.nMax = nRightMax;
610 
611                 bFoundPos = true;
612             }
613 	    	else if ( (nRightMax >= ((nCmp >= COLFUZZY) ? nCmp - COLFUZZY : nCmp)) &&
614 			          (nRightMax <= (nCmp + COLFUZZY)) )
615             {
616                 // check if nPos is > old minimum for entry nRightMax:
617                 const long nOldMin = rEntry.nMin;
618                 if ( nPos > nOldMin )
619                     rEntry.nMin = nPos;
620 
621                 bFoundMax = true;
622             }
623         }
624     }
625 }
626 
lcl_ProcessBoxGet(const SwTableBox * pBox,SwTabCols & rToFill,const SwFrmFmt * pTabFmt,FASTBOOL bRefreshHidden)627 void lcl_ProcessBoxGet( const SwTableBox *pBox, SwTabCols &rToFill,
628 						const SwFrmFmt *pTabFmt, FASTBOOL bRefreshHidden )
629 {
630 	if ( pBox->GetTabLines().Count() )
631 	{
632 		const SwTableLines &rLines = pBox->GetTabLines();
633 		for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
634 		{	const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
635 			for ( sal_uInt16 j = 0; j < rBoxes.Count(); ++j )
636 				::lcl_ProcessBoxGet( rBoxes[j], rToFill, pTabFmt, bRefreshHidden);
637 		}
638 	}
639 	else
640 		::lcl_SortedTabColInsert( rToFill, pBox, pTabFmt, sal_False, bRefreshHidden );
641 }
642 
lcl_ProcessLineGet(const SwTableLine * pLine,SwTabCols & rToFill,const SwFrmFmt * pTabFmt)643 void lcl_ProcessLineGet( const SwTableLine *pLine, SwTabCols &rToFill,
644 						 const SwFrmFmt *pTabFmt )
645 {
646 	for ( sal_uInt16 i = 0; i < pLine->GetTabBoxes().Count(); ++i )
647 	{
648 		const SwTableBox *pBox = pLine->GetTabBoxes()[i];
649 		if ( pBox->GetSttNd() )
650 			::lcl_SortedTabColInsert( rToFill, pBox, pTabFmt, sal_True, sal_False );
651 		else
652 			for ( sal_uInt16 j = 0; j < pBox->GetTabLines().Count(); ++j )
653 				::lcl_ProcessLineGet( pBox->GetTabLines()[j], rToFill, pTabFmt );
654 	}
655 }
656 
657 // MS: Sonst Absturz auf der DEC-Kiste
658 //
659 #if defined(ALPHA) && defined(WNT)
660 #pragma optimize("", off)
661 #endif
662 
GetTabCols(SwTabCols & rToFill,const SwTableBox * pStart,sal_Bool bRefreshHidden,sal_Bool bCurRowOnly) const663 void SwTable::GetTabCols( SwTabCols &rToFill, const SwTableBox *pStart,
664 			  sal_Bool bRefreshHidden, sal_Bool bCurRowOnly ) const
665 {
666 	//MA 30. Nov. 95: Opt: wenn bHidden gesetzt ist, wird nur das Hidden
667 	//Array aktualisiert.
668 	if ( bRefreshHidden )
669 	{
670 		//Korrekturen entfernen
671 		sal_uInt16 i;
672 		for ( i = 0; i < rToFill.Count(); ++i )
673         {
674             SwTabColsEntry& rEntry = rToFill.GetEntry( i );
675             rEntry.nPos -= rToFill.GetLeft();
676             rEntry.nMin -= rToFill.GetLeft();
677             rEntry.nMax -= rToFill.GetLeft();
678         }
679 
680 		//Alle sind hidden, dann die sichtbaren eintragen.
681         for ( i = 0; i < rToFill.Count(); ++i )
682             rToFill.SetHidden( i, sal_True );
683 	}
684 	else
685 	{
686 		rToFill.Remove( 0, rToFill.Count() );
687     }
688 
689 	//Eingetragen werden:
690 	//1. Alle Boxen unterhalb der dem Start uebergeordneten Line sowie
691 	//	 deren untergeordnete Boxen falls vorhanden.
692 	//2. Ausgehend von der Line die uebergeordnete Box sowie deren Nachbarn;
693 	//	 nicht aber deren untergeordnete.
694 	//3. Mit der der Boxenkette uebergeordneten Line wieder wie 2. bis einer
695 	//	 Line keine Box (sondern die Table) uebergeordnet ist.
696 	//Es werden nur diejenigen Boxen eingetragen, die keine weiteren Zeilen
697 	//enhalten. Die eintragende Funktion sorgt dafuer, dass keine doppelten
698 	//eingetragen werden. Um dies zu gewaehrleisten wird mit einer gewissen
699 	//Unschaerfe gearbeitet (um Rundungsfehler auszuschalten).
700 	//Es werden nur die linken Kanten der Boxen eingetragen.
701 	//Am Schluss wird der Erste wieder ausgetragen denn er ist bereits vom
702 	//Rand abgedeckt.
703 
704 	//4. Nochmalige abscannen der Tabelle und eintragen _aller_ Boxen,
705 	//	 jetzt aber als Hidden.
706 
707 	const SwFrmFmt *pTabFmt = GetFrmFmt();
708 
709 	//1.
710 	const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
711 
712     sal_uInt16 i;
713 	for ( i = 0; i < rBoxes.Count(); ++i )
714 		::lcl_ProcessBoxGet( rBoxes[i], rToFill, pTabFmt, bRefreshHidden );
715 
716 	//2. und 3.
717 	const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
718 								pStart->GetUpper()->GetUpper()->GetUpper() : 0;
719 	while ( pLine )
720 	{
721         const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
722         for ( sal_uInt16 k = 0; k < rBoxes2.Count(); ++k )
723             ::lcl_SortedTabColInsert( rToFill, rBoxes2[k],
724 									  pTabFmt, sal_False, bRefreshHidden );
725 		pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : 0;
726 	}
727 
728 	if ( !bRefreshHidden )
729 	{
730 		//4.
731 		if ( !bCurRowOnly )
732 		{
733 			for ( i = 0; i < aLines.Count(); ++i )
734 				::lcl_ProcessLineGet( aLines[i], rToFill, pTabFmt );
735 		}
736 
737 		rToFill.Remove( 0, 1 );
738     }
739 
740 	//Die Koordinaten sind jetzt relativ zum linken Rand der Tabelle - also
741 	//relativ zum nLeft vom SwTabCols. Die Werte werden aber relativ zum
742 	//linken Rand - also nLeftMin vom SwTabCols - erwartet.
743 	//Alle Werte muessen also um nLeft erweitert werden.
744 	for ( i = 0; i < rToFill.Count(); ++i )
745     {
746         SwTabColsEntry& rEntry = rToFill.GetEntry( i );
747         rEntry.nPos += rToFill.GetLeft();
748         rEntry.nMin += rToFill.GetLeft();
749         rEntry.nMax += rToFill.GetLeft();
750     }
751 }
752 
753 #if defined(ALPHA) && defined(WNT)
754 #pragma optimize("", on)
755 #endif
756 
757 /*************************************************************************
758 |*
759 |*	SwTable::SetTabCols()
760 |*
761 |*************************************************************************/
762 //Struktur zur Parameteruebergabe
763 struct Parm
764 {
765 	const SwTabCols &rNew;
766 	const SwTabCols &rOld;
767 	long nNewWish,
768 		 nOldWish;
769 	SvPtrarr aBoxArr;
770 	SwShareBoxFmts aShareFmts;
771 
ParmParm772 	Parm( const SwTabCols &rN, const SwTabCols &rO ) :
773 		rNew( rN ), rOld( rO ), aBoxArr( 10, 1 ) {}
774 };
BoxInArr(SvPtrarr & rArr,SwTableBox * pBox)775 inline sal_Bool BoxInArr( SvPtrarr& rArr, SwTableBox* pBox )
776 {
777 	sal_Bool bRet = USHRT_MAX != rArr.GetPos( (VoidPtr)pBox );
778 	if( !bRet )
779 		rArr.Insert( (VoidPtr)pBox, rArr.Count() );
780 	return bRet;
781 }
782 
783 void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm );
784 
lcl_ProcessLine(SwTableLine * pLine,Parm & rParm)785 void lcl_ProcessLine( SwTableLine *pLine, Parm &rParm )
786 {
787 	SwTableBoxes &rBoxes = pLine->GetTabBoxes();
788 	for ( int i = rBoxes.Count()-1; i >= 0; --i )
789         ::lcl_ProcessBoxSet( rBoxes[ static_cast< sal_uInt16 >(i) ], rParm );
790 }
791 
lcl_ProcessBoxSet(SwTableBox * pBox,Parm & rParm)792 void lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm )
793 {
794 	if ( pBox->GetTabLines().Count() )
795 	{	SwTableLines &rLines = pBox->GetTabLines();
796 		for ( int i = rLines.Count()-1; i >= 0; --i )
797             lcl_ProcessLine( rLines[ static_cast< sal_uInt16 >(i) ], rParm );
798 	}
799 	else
800 	{
801 		//Aktuelle Position (linke und rechte Kante berechnen) und im
802 		//alten TabCols suchen. Im neuen TabCols die Werte vergleichen und
803 		//wenn es Unterschiede gibt die Box entsprechend anpassen.
804 		//Wenn an der veraenderten Kante kein Nachbar existiert werden auch
805 		//alle uebergeordneten Boxen angepasst.
806 
807 		const long nOldAct = rParm.rOld.GetRight() -
808 							 rParm.rOld.GetLeft(); // +1 why?
809 
810 		//Der Wert fuer die linke Kante der Box errechnet sich aus den
811 		//Breiten der vorhergehenden Boxen plus dem linken Rand
812 		long nLeft = rParm.rOld.GetLeft();
813 		const  SwTableBox  *pCur  = pBox;
814 		const  SwTableLine *pLine = pBox->GetUpper();
815 
816 		while ( pLine )
817 		{	const SwTableBoxes &rBoxes = pLine->GetTabBoxes();
818 			for ( sal_uInt16 i = 0; (i < rBoxes.Count()) && (rBoxes[i] != pCur); ++i)
819 			{
820 				sal_uInt64 nWidth = rBoxes[i]->GetFrmFmt()->
821 										GetFrmSize().GetWidth();
822 				nWidth *= nOldAct;
823 				nWidth /= rParm.nOldWish;
824 				nLeft += (sal_uInt16)nWidth;
825 			}
826 			pCur  = pLine->GetUpper();
827 			pLine = pCur ? pCur->GetUpper() : 0;
828 		}
829 		long nLeftDiff;
830 		long nRightDiff = 0;
831 		if ( nLeft != rParm.rOld.GetLeft() ) //Es gibt noch Boxen davor.
832 		{
833 			//Rechte Kante ist linke Kante plus Breite.
834 			sal_uInt64 nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
835 			nWidth *= nOldAct;
836 			nWidth /= rParm.nOldWish;
837 			long nRight = nLeft + (long)nWidth;
838 			sal_uInt16 nLeftPos  = USHRT_MAX,
839 				   nRightPos = USHRT_MAX;
840 			for ( sal_uInt16 i = 0; i < rParm.rOld.Count(); ++i )
841 			{
842 				if ( nLeft >= (rParm.rOld[i] - COLFUZZY) &&
843 					 nLeft <= (rParm.rOld[i] + COLFUZZY) )
844 					nLeftPos = i;
845 				else if ( nRight >= (rParm.rOld[i] - COLFUZZY) &&
846 						  nRight <= (rParm.rOld[i] + COLFUZZY) )
847 					nRightPos = i;
848 			}
849 			nLeftDiff = nLeftPos != USHRT_MAX ?
850 					(int)rParm.rOld[nLeftPos] - (int)rParm.rNew[nLeftPos] : 0;
851 			nRightDiff= nRightPos!= USHRT_MAX ?
852 					(int)rParm.rNew[nRightPos] - (int)rParm.rOld[nRightPos] : 0;
853 		}
854 		else	//Die erste Box.
855 		{
856 			nLeftDiff = (long)rParm.rOld.GetLeft() - (long)rParm.rNew.GetLeft();
857 			if ( rParm.rOld.Count() )
858 			{
859 				//Differnz zu der Kante berechnen, von der die erste Box
860 				//beruehrt wird.
861 				sal_uInt64 nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
862 				nWidth *= nOldAct;
863 				nWidth /= rParm.nOldWish;
864 				long nTmp = (long)nWidth;
865 				nTmp += rParm.rOld.GetLeft();
866 				sal_uInt16 nLeftPos = USHRT_MAX;
867 				for ( sal_uInt16 i = 0; i < rParm.rOld.Count() &&
868 									nLeftPos == USHRT_MAX; ++i )
869 				{
870 					if ( nTmp >= (rParm.rOld[i] - COLFUZZY) &&
871 						 nTmp <= (rParm.rOld[i] + COLFUZZY) )
872 						nLeftPos = i;
873 				}
874 				if ( nLeftPos != USHRT_MAX )
875 					nRightDiff = (long)rParm.rNew[nLeftPos] -
876 								 (long)rParm.rOld[nLeftPos];
877 			}
878 //MA 11. Feb. 99: #61577# 0 sollte doch gerade richtig sein, weil die
879 //Kante doch schon in SetTabCols() korrigiert wurde.
880 //			else
881 //				nRightDiff = (long)rParm.rNew.GetRight() -
882 //							 (long)rParm.rOld.GetRight();
883 		}
884 
885         if( pBox->getRowSpan() == 1 )
886         {
887             SwTableBoxes& rTblBoxes = pBox->GetUpper()->GetTabBoxes();
888             sal_uInt16 nPos = rTblBoxes.C40_GETPOS( SwTableBox, pBox );
889             if( nPos && rTblBoxes[ nPos - 1 ]->getRowSpan() != 1 )
890                 nLeftDiff = 0;
891             if( nPos + 1 < rTblBoxes.Count() &&
892                 rTblBoxes[ nPos + 1 ]->getRowSpan() != 1 )
893                 nRightDiff = 0;
894         }
895         else
896             nLeftDiff = nRightDiff = 0;
897 
898 		if ( nLeftDiff || nRightDiff )
899 		{
900 			//Die Differenz ist der tatsaechliche Differenzbetrag; die
901 			//Attribute der Boxen um diesen Betrag anzupassen macht keinen
902 			//Sinn wenn die Tabelle gestrecht ist. Der Differenzbetrag muss
903 			//entsprechend umgerechnet werden.
904 			long nTmp = rParm.rNew.GetRight() - rParm.rNew.GetLeft(); // +1 why?
905 			nLeftDiff *= rParm.nNewWish;
906 			nLeftDiff /= nTmp;
907 			nRightDiff *= rParm.nNewWish;
908 			nRightDiff /= nTmp;
909 			long nDiff = nLeftDiff + nRightDiff;
910 
911 			//Box und alle uebergeordneten um den Differenzbetrag anpassen.
912             while ( pBox )
913 			{
914                 SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() );
915                 aFmtFrmSize.SetWidth( aFmtFrmSize.GetWidth() + nDiff );
916                 if ( aFmtFrmSize.GetWidth() < 0 )
917                     aFmtFrmSize.SetWidth( -aFmtFrmSize.GetWidth() );
918                 rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize );
919 
920                 // The outer cells of the last row are responsible to adjust a surrounding cell.
921                 // Last line check:
922                 if ( pBox->GetUpper()->GetUpper() &&
923                      pBox->GetUpper() != pBox->GetUpper()->GetUpper()->GetTabLines()
924                         [pBox->GetUpper()->GetUpper()->GetTabLines().Count()-1])
925                 {
926                    pBox = 0;
927                 }
928                 else
929                 {
930                     // Middle cell check:
931                     if ( pBox != pBox->GetUpper()->GetTabBoxes()[0] )
932                         nDiff = nRightDiff;
933 
934                     if ( pBox != pBox->GetUpper()->GetTabBoxes()
935                                 [pBox->GetUpper()->GetTabBoxes().Count()-1] )
936                         nDiff -= nRightDiff;
937 
938                     pBox = nDiff ? pBox->GetUpper()->GetUpper() : 0;
939                 }
940             }
941 		}
942 	}
943 }
944 
lcl_ProcessBoxPtr(SwTableBox * pBox,SvPtrarr & rBoxArr,sal_Bool bBefore)945 void lcl_ProcessBoxPtr( SwTableBox *pBox, SvPtrarr &rBoxArr,
946 						   sal_Bool bBefore )
947 {
948 	if ( pBox->GetTabLines().Count() )
949 	{
950 		const SwTableLines &rLines = pBox->GetTabLines();
951 		for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
952 		{
953 			const SwTableBoxes &rBoxes = rLines[i]->GetTabBoxes();
954 			for ( sal_uInt16 j = 0; j < rBoxes.Count(); ++j )
955 				::lcl_ProcessBoxPtr( rBoxes[j], rBoxArr, bBefore );
956 		}
957 	}
958 	else if ( bBefore )
959 		rBoxArr.Insert( (VoidPtr)pBox, 0 );
960 	else
961 		rBoxArr.Insert( (VoidPtr)pBox, rBoxArr.Count() );
962 }
963 
964 void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm );
965 
lcl_AdjustLines(SwTableLines & rLines,const long nDiff,Parm & rParm)966 void lcl_AdjustLines( SwTableLines &rLines, const long nDiff, Parm &rParm )
967 {
968 	for ( sal_uInt16 i = 0; i < rLines.Count(); ++i )
969 	{
970 		SwTableBox *pBox = rLines[i]->GetTabBoxes()
971 								[rLines[i]->GetTabBoxes().Count()-1];
972 		lcl_AdjustBox( pBox, nDiff, rParm );
973 	}
974 }
975 
lcl_AdjustBox(SwTableBox * pBox,const long nDiff,Parm & rParm)976 void lcl_AdjustBox( SwTableBox *pBox, const long nDiff, Parm &rParm )
977 {
978 	if ( pBox->GetTabLines().Count() )
979 		::lcl_AdjustLines( pBox->GetTabLines(), nDiff, rParm );
980 
981 	//Groesse der Box anpassen.
982 	SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() );
983 	aFmtFrmSize.SetWidth( aFmtFrmSize.GetWidth() + nDiff );
984 //#30009#		if ( aFmtFrmSize.GetWidth() < 0 )
985 //			aFmtFrmSize.SetWidth( -aFmtFrmSize.GetWidth() );
986 
987 	rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize );
988 }
989 
SetTabCols(const SwTabCols & rNew,const SwTabCols & rOld,const SwTableBox * pStart,sal_Bool bCurRowOnly)990 void SwTable::SetTabCols( const SwTabCols &rNew, const SwTabCols &rOld,
991 						  const SwTableBox *pStart, sal_Bool bCurRowOnly )
992 {
993     CHECK_TABLE( *this )
994 
995 	SetHTMLTableLayout( 0 ); 	// MIB 9.7.97: HTML-Layout loeschen
996 
997     // FME: Made rOld const. The caller is responsible for passing correct
998     // values of rOld. Therefore we do not have to call GetTabCols anymore:
999     //GetTabCols( rOld, pStart );
1000 
1001 	Parm aParm( rNew, rOld );
1002 
1003 	ASSERT( rOld.Count() == rNew.Count(), "Columnanzahl veraendert.");
1004 
1005 	//Raender verarbeiten. Groesse der Tabelle und ein paar Boxen mussen
1006 	//angepasst werden. Bei der Groesseneinstellung darf allerdings das
1007 	//Modify nicht verarbeitet werden - dieses wuerde alle Boxen anpassen
1008 	//und das koennen wir ueberhaupt nicht gebrauchen.
1009 	SwFrmFmt *pFmt = GetFrmFmt();
1010 	aParm.nOldWish = aParm.nNewWish = pFmt->GetFrmSize().GetWidth();
1011 	if ( (rOld.GetLeft() != rNew.GetLeft()) ||
1012 		 (rOld.GetRight()!= rNew.GetRight()) )
1013 	{
1014 		LockModify();
1015 		{
1016 			SvxLRSpaceItem aLR( pFmt->GetLRSpace() );
1017             SvxShadowItem aSh( pFmt->GetShadow() );
1018 
1019             SwTwips nShRight = aSh.CalcShadowSpace( SHADOW_RIGHT );
1020             SwTwips nShLeft = aSh.CalcShadowSpace( SHADOW_LEFT );
1021 
1022 			aLR.SetLeft ( rNew.GetLeft() - nShLeft );
1023             aLR.SetRight( rNew.GetRightMax() - rNew.GetRight() - nShRight );
1024             pFmt->SetFmtAttr( aLR );
1025 
1026 			//Die Ausrichtung der Tabelle muss entsprechend angepasst werden,
1027 			//das geschieht so, dass die Tabelle genauso stehenbleibt wie der
1028 			//Anwender sie gerade hingezuppelt hat.
1029 			SwFmtHoriOrient aOri( pFmt->GetHoriOrient() );
1030 			if(text::HoriOrientation::NONE != aOri.GetHoriOrient())
1031 			{
1032 				const sal_Bool bLeftDist = rNew.GetLeft() != nShLeft;
1033 				const sal_Bool bRightDist = rNew.GetRight() + nShRight != rNew.GetRightMax();
1034 				if(!bLeftDist && !bRightDist)
1035 					aOri.SetHoriOrient( text::HoriOrientation::FULL );
1036 				else if(!bRightDist && rNew.GetLeft() > nShLeft )
1037 					aOri.SetHoriOrient( text::HoriOrientation::RIGHT );
1038 				else if(!bLeftDist && rNew.GetRight() + nShRight < rNew.GetRightMax())
1039 					aOri.SetHoriOrient( text::HoriOrientation::LEFT );
1040 				else
1041 					aOri.SetHoriOrient( text::HoriOrientation::NONE );
1042 			}
1043             pFmt->SetFmtAttr( aOri );
1044 		}
1045 		const long nAct = rOld.GetRight() - rOld.GetLeft(); // +1 why?
1046 		long nTabDiff = 0;
1047 
1048 		if ( rOld.GetLeft() != rNew.GetLeft() )
1049 		{
1050 			nTabDiff = rOld.GetLeft() - rNew.GetLeft();
1051 			nTabDiff *= aParm.nOldWish;
1052 			nTabDiff /= nAct;
1053 		}
1054 		if ( rOld.GetRight() != rNew.GetRight() )
1055 		{
1056 			long nDiff = rNew.GetRight() - rOld.GetRight();
1057 			nDiff *= aParm.nOldWish;
1058 			nDiff /= nAct;
1059 			nTabDiff += nDiff;
1060             if( !IsNewModel() )
1061                 ::lcl_AdjustLines( GetTabLines(), nDiff, aParm );
1062 		}
1063 
1064 		//Groesse der Tabelle anpassen. Es muss beachtet werden, das die
1065 		//Tabelle gestrecht sein kann.
1066 		if ( nTabDiff )
1067 		{
1068 			aParm.nNewWish += nTabDiff;
1069 			if ( aParm.nNewWish < 0 )
1070 				aParm.nNewWish = USHRT_MAX;	//Uuups! Eine Rolle rueckwaerts.
1071 			SwFmtFrmSize aSz( pFmt->GetFrmSize() );
1072 			if ( aSz.GetWidth() != aParm.nNewWish )
1073 			{
1074 				aSz.SetWidth( aParm.nNewWish );
1075 				aSz.SetWidthPercent( 0 );
1076                 pFmt->SetFmtAttr( aSz );
1077 			}
1078 		}
1079 		UnlockModify();
1080 	}
1081 
1082     if( IsNewModel() )
1083         NewSetTabCols( aParm, rNew, rOld, pStart, bCurRowOnly );
1084     else
1085 	{
1086 		if ( bCurRowOnly )
1087 		{
1088 			//Um die aktuelle Zeile anzupassen muessen wir analog zu dem
1089 			//Verfahren zum fuellen der TabCols (siehe GetTabCols()) die
1090 			//Boxen der aktuellen Zeile abklappern.
1091 			//Leider muessen wir auch hier dafuer sorgen, dass die Boxen von
1092 			//hinten nach vorne bzw. von innen nach aussen veraendert werden.
1093 			//Der beste Weg hierzu scheint mir darin zu liegen die
1094 			//entsprechenden Boxen in einem PtrArray vorzumerken.
1095 
1096 			const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes();
1097 			for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i )
1098 				::lcl_ProcessBoxPtr( rBoxes[i], aParm.aBoxArr, sal_False );
1099 
1100 			const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
1101 									pStart->GetUpper()->GetUpper()->GetUpper() : 0;
1102 			const SwTableBox  *pExcl = pStart->GetUpper()->GetUpper();
1103 			while ( pLine )
1104 			{
1105                 const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes();
1106 				sal_Bool bBefore = sal_True;
1107                 for ( sal_uInt16 i = 0; i < rBoxes2.Count(); ++i )
1108 				{
1109                     if ( rBoxes2[i] != pExcl )
1110                         ::lcl_ProcessBoxPtr( rBoxes2[i], aParm.aBoxArr, bBefore );
1111 					else
1112 						bBefore = sal_False;
1113 				}
1114 				pExcl = pLine->GetUpper();
1115 				pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : 0;
1116 			}
1117 			//Nachdem wir haufenweise Boxen (hoffentlich alle und in der richtigen
1118 			//Reihenfolge) eingetragen haben, brauchen diese nur noch rueckwaerts
1119 			//verarbeitet zu werden.
1120             for ( int j = aParm.aBoxArr.Count()-1; j >= 0; --j )
1121 			{
1122                 SwTableBox *pBox = (SwTableBox*)aParm.aBoxArr[ static_cast< sal_uInt16 >(j)];
1123 				::lcl_ProcessBoxSet( pBox, aParm );
1124 			}
1125 		}
1126 		else
1127 		{	//Die gesamte Tabelle anzupassen ist 'einfach'.
1128 			//Es werden alle Boxen, die keine Lines mehr enthalten angepasst.
1129 			//Diese Boxen passen alle uebergeordneten Boxen entsprechend mit an.
1130 			//Um uns nicht selbst hereinzulegen muss natuerlich rueckwaerst
1131 			//gearbeitet werden!
1132 			SwTableLines &rLines = GetTabLines();
1133 			for ( int i = rLines.Count()-1; i >= 0; --i )
1134                 ::lcl_ProcessLine( rLines[ static_cast< sal_uInt16 >(i) ], aParm );
1135 		}
1136 	}
1137 
1138 #ifdef DBG_UTIL
1139 	{
1140 // steht im tblrwcl.cxx
1141 extern void _CheckBoxWidth( const SwTableLine&, SwTwips );
1142 		// checke doch mal ob die Tabellen korrekte Breiten haben
1143 		SwTwips nSize = GetFrmFmt()->GetFrmSize().GetWidth();
1144 		for( sal_uInt16 n = 0; n < aLines.Count(); ++n  )
1145 			_CheckBoxWidth( *aLines[ n ], nSize );
1146 	}
1147 #endif
1148 }
1149 
1150 typedef std::pair<sal_uInt16, sal_uInt16> ColChange;
1151 typedef std::list< ColChange > ChangeList;
1152 
lcl_AdjustWidthsInLine(SwTableLine * pLine,ChangeList & rOldNew,Parm & rParm,sal_uInt16 nColFuzzy)1153 static void lcl_AdjustWidthsInLine( SwTableLine* pLine, ChangeList& rOldNew,
1154     Parm& rParm, sal_uInt16 nColFuzzy )
1155 {
1156     ChangeList::iterator pCurr = rOldNew.begin();
1157     if( pCurr == rOldNew.end() )
1158         return;
1159     sal_uInt16 nCount = pLine->GetTabBoxes().Count();
1160     sal_uInt16 i = 0;
1161     SwTwips nBorder = 0;
1162     SwTwips nRest = 0;
1163     while( i < nCount )
1164     {
1165         SwTableBox* pBox = pLine->GetTabBoxes()[i++];
1166         SwTwips nWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1167         SwTwips nNewWidth = nWidth - nRest;
1168         nRest = 0;
1169         nBorder += nWidth;
1170         if( pCurr != rOldNew.end() && nBorder + nColFuzzy >= pCurr->first )
1171         {
1172             nBorder -= nColFuzzy;
1173             while( pCurr != rOldNew.end() && nBorder > pCurr->first )
1174                 ++pCurr;
1175             if( pCurr != rOldNew.end() )
1176             {
1177                 nBorder += nColFuzzy;
1178                 if( nBorder + nColFuzzy >= pCurr->first )
1179                 {
1180                     if( pCurr->second == pCurr->first )
1181                         nRest = 0;
1182                     else
1183                         nRest = pCurr->second - nBorder;
1184                     nNewWidth += nRest;
1185                     ++pCurr;
1186                 }
1187             }
1188         }
1189         if( nNewWidth != nWidth )
1190         {
1191             if( nNewWidth < 0 )
1192             {
1193                 nRest += 1 - nNewWidth;
1194                 nNewWidth = 1;
1195             }
1196             SwFmtFrmSize aFmtFrmSize( pBox->GetFrmFmt()->GetFrmSize() );
1197             aFmtFrmSize.SetWidth( nNewWidth );
1198             rParm.aShareFmts.SetSize( *pBox, aFmtFrmSize );
1199         }
1200     }
1201 }
1202 
lcl_CalcNewWidths(std::list<sal_uInt16> & rSpanPos,ChangeList & rChanges,SwTableLine * pLine,long nWish,long nWidth,bool bTop)1203 static void lcl_CalcNewWidths( std::list<sal_uInt16> &rSpanPos, ChangeList& rChanges,
1204     SwTableLine* pLine, long nWish, long nWidth, bool bTop )
1205 {
1206     if( !rChanges.size() )
1207     {
1208         rSpanPos.clear();
1209         return;
1210     }
1211     if( !rSpanPos.size() )
1212     {
1213         rChanges.clear();
1214         return;
1215     }
1216     std::list<sal_uInt16> aNewSpanPos;
1217     ChangeList aNewChanges;
1218     ChangeList::iterator pCurr = rChanges.begin();
1219     aNewChanges.push_back( *pCurr ); // Nullposition
1220     std::list<sal_uInt16>::iterator pSpan = rSpanPos.begin();
1221     sal_uInt16 nCurr = 0;
1222     sal_uInt16 nOrgSum = 0;
1223     bool bRowSpan = false;
1224     sal_uInt16 nRowSpanCount = 0;
1225     sal_uInt16 nCount = pLine->GetTabBoxes().Count();
1226     for( sal_uInt16 nCurrBox = 0; nCurrBox < nCount; ++nCurrBox )
1227     {
1228         SwTableBox* pBox = pLine->GetTabBoxes()[nCurrBox];
1229         SwTwips nCurrWidth = pBox->GetFrmFmt()->GetFrmSize().GetWidth();
1230         const long nRowSpan = pBox->getRowSpan();
1231         const bool bCurrRowSpan = bTop ? nRowSpan < 0 :
1232             ( nRowSpan > 1 || nRowSpan < -1 );
1233         if( bRowSpan || bCurrRowSpan )
1234             aNewSpanPos.push_back( nRowSpanCount );
1235         bRowSpan = bCurrRowSpan;
1236         nOrgSum = (sal_uInt16)(nOrgSum + nCurrWidth);
1237         sal_uInt64 nSum = nOrgSum;
1238         nSum *= nWidth;
1239         nSum /= nWish;
1240         nSum *= nWish;
1241         nSum /= nWidth;
1242         sal_uInt16 nPos = (sal_uInt16)nSum;
1243         while( pCurr != rChanges.end() && pCurr->first < nPos )
1244         {
1245 #ifdef DBG_UTIL
1246             sal_uInt16 nTemp = pCurr->first;
1247             nTemp = pCurr->second;
1248 #endif
1249             ++nCurr;
1250             ++pCurr;
1251         }
1252         bool bNew = true;
1253         if( pCurr != rChanges.end() && pCurr->first <= nPos &&
1254             pCurr->first != pCurr->second )
1255         {
1256             while( pSpan != rSpanPos.end() && *pSpan < nCurr )
1257                 ++pSpan;
1258             if( pSpan != rSpanPos.end() && *pSpan == nCurr )
1259             {
1260                 aNewChanges.push_back( *pCurr );
1261                 ++nRowSpanCount;
1262                 bNew = false;
1263             }
1264         }
1265         if( bNew )
1266         {
1267             ColChange aTmp( nPos, nPos );
1268             aNewChanges.push_back( aTmp );
1269             ++nRowSpanCount;
1270         }
1271     }
1272 
1273     pCurr = aNewChanges.begin();
1274     ChangeList::iterator pLast = pCurr;
1275     ChangeList::iterator pLeftMove = pCurr;
1276     while( pCurr != aNewChanges.end() )
1277     {
1278         if( pLeftMove == pCurr )
1279         {
1280             while( ++pLeftMove != aNewChanges.end() && pLeftMove->first <= pLeftMove->second )
1281                 ;
1282         }
1283         if( pCurr->second == pCurr->first )
1284         {
1285             if( pLeftMove != aNewChanges.end() && pCurr->second > pLeftMove->second )
1286             {
1287                 if( pLeftMove->first == pLast->first )
1288                     pCurr->second = pLeftMove->second;
1289                 else
1290                 {
1291                     sal_uInt64 nTmp = pCurr->first - pLast->first;
1292                     nTmp *= pLeftMove->second - pLast->second;
1293                     nTmp /= pLeftMove->first - pLast->first;
1294                     nTmp += pLast->second;
1295                     pCurr->second = (sal_uInt16)nTmp;
1296                 }
1297             }
1298             pLast = pCurr;
1299             ++pCurr;
1300         }
1301         else if( pCurr->second > pCurr->first )
1302         {
1303             pLast = pCurr;
1304             ++pCurr;
1305             ChangeList::iterator pNext = pCurr;
1306             while( pNext != pLeftMove && pNext->second == pNext->first &&
1307                 pNext->second < pLast->second )
1308                 ++pNext;
1309             while( pCurr != pNext )
1310             {
1311                 if( pNext == aNewChanges.end() || pNext->first == pLast->first )
1312                     pCurr->second = pLast->second;
1313                 else
1314                 {
1315                     sal_uInt64 nTmp = pCurr->first - pLast->first;
1316                     nTmp *= pNext->second - pLast->second;
1317                     nTmp /= pNext->first - pLast->first;
1318                     nTmp += pLast->second;
1319                     pCurr->second = (sal_uInt16)nTmp;
1320                 }
1321                 ++pCurr;
1322             }
1323             pLast = pCurr;
1324         }
1325         else
1326         {
1327             pLast = pCurr;
1328             ++pCurr;
1329         }
1330     }
1331 
1332     rChanges.clear();
1333     ChangeList::iterator pCopy = aNewChanges.begin();
1334     while( pCopy != aNewChanges.end() )
1335         rChanges.push_back( *pCopy++ );
1336     rSpanPos.clear();
1337     std::list<sal_uInt16>::iterator pSpCopy = aNewSpanPos.begin();
1338     while( pSpCopy != aNewSpanPos.end() )
1339         rSpanPos.push_back( *pSpCopy++ );
1340 }
1341 
NewSetTabCols(Parm & rParm,const SwTabCols & rNew,const SwTabCols & rOld,const SwTableBox * pStart,sal_Bool bCurRowOnly)1342 void SwTable::NewSetTabCols( Parm &rParm, const SwTabCols &rNew,
1343     const SwTabCols &rOld, const SwTableBox *pStart, sal_Bool bCurRowOnly )
1344 {
1345 #ifdef DBG_UTIL
1346     static int nCallCount = 0;
1347     ++nCallCount;
1348 #endif
1349     // First step: evaluate which lines have been moved/which widths changed
1350     ChangeList aOldNew;
1351     const long nNewWidth = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1352     const long nOldWidth = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1353     if( nNewWidth < 1 || nOldWidth < 1 )
1354         return;
1355     for( sal_uInt16 i = 0; i <= rOld.Count(); ++i )
1356     {
1357         sal_uInt64 nNewPos;
1358         sal_uInt64 nOldPos;
1359         if( i == rOld.Count() )
1360         {
1361             nOldPos = rParm.rOld.GetRight() - rParm.rOld.GetLeft();
1362             nNewPos = rParm.rNew.GetRight() - rParm.rNew.GetLeft();
1363         }
1364         else
1365         {
1366             nOldPos = rOld[i] - rParm.rOld.GetLeft();
1367             nNewPos = rNew[i] - rParm.rNew.GetLeft();
1368         }
1369         nNewPos *= rParm.nNewWish;
1370         nNewPos /= nNewWidth;
1371         nOldPos *= rParm.nOldWish;
1372         nOldPos /= nOldWidth;
1373         if( nOldPos != nNewPos && nNewPos > 0 && nOldPos > 0 )
1374         {
1375             ColChange aChg( (sal_uInt16)nOldPos, (sal_uInt16)nNewPos );
1376             aOldNew.push_back( aChg );
1377         }
1378     }
1379     // Finished first step
1380     int nCount = aOldNew.size();
1381     if( !nCount )
1382         return; // no change, nothing to do
1383     SwTableLines &rLines = GetTabLines();
1384     if( bCurRowOnly )
1385     {
1386         const SwTableLine* pCurrLine = pStart->GetUpper();
1387         sal_uInt16 nCurr = rLines.C40_GETPOS( SwTableLine, pCurrLine );
1388         if( nCurr >= USHRT_MAX )
1389             return;
1390 
1391         ColChange aChg( 0, 0 );
1392         aOldNew.push_front( aChg );
1393         std::list<sal_uInt16> aRowSpanPos;
1394         if( nCurr )
1395         {
1396             ChangeList aCopy;
1397             ChangeList::iterator pCop = aOldNew.begin();
1398             sal_uInt16 nPos = 0;
1399             while( pCop != aOldNew.end() )
1400             {
1401                 aCopy.push_back( *pCop );
1402                 ++pCop;
1403                 aRowSpanPos.push_back( nPos++ );
1404             }
1405             lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1406                 rParm.nOldWish, nOldWidth, true );
1407             bool bGoOn = aRowSpanPos.size() > 0;
1408             sal_uInt16 j = nCurr;
1409             while( bGoOn )
1410             {
1411                 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[--j],
1412                     rParm.nOldWish, nOldWidth, true );
1413                 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1414                 bGoOn = aRowSpanPos.size() > 0 && j > 0;
1415             };
1416             aRowSpanPos.clear();
1417         }
1418         if( nCurr+1 < rLines.Count() )
1419         {
1420             ChangeList aCopy;
1421             ChangeList::iterator pCop = aOldNew.begin();
1422             sal_uInt16 nPos = 0;
1423             while( pCop != aOldNew.end() )
1424             {
1425                 aCopy.push_back( *pCop );
1426                 ++pCop;
1427                 aRowSpanPos.push_back( nPos++ );
1428             }
1429             lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[nCurr],
1430                 rParm.nOldWish, nOldWidth, false );
1431             bool bGoOn = aRowSpanPos.size() > 0;
1432             sal_uInt16 j = nCurr;
1433             while( bGoOn )
1434             {
1435                 lcl_CalcNewWidths( aRowSpanPos, aCopy, rLines[++j],
1436                     rParm.nOldWish, nOldWidth, false );
1437                 lcl_AdjustWidthsInLine( rLines[j], aCopy, rParm, 0 );
1438                 bGoOn = aRowSpanPos.size() > 0 && j+1 < rLines.Count();
1439             };
1440         }
1441         ::lcl_AdjustWidthsInLine( rLines[nCurr], aOldNew, rParm, 1 );
1442     }
1443     else for( sal_uInt16 i = 0; i < rLines.Count(); ++i )
1444         ::lcl_AdjustWidthsInLine( rLines[i], aOldNew, rParm, COLFUZZY );
1445     CHECK_TABLE( *this )
1446 }
1447 
1448 
1449 /*************************************************************************
1450 |*
1451 |*	const SwTableBox* SwTable::GetTblBox( const Strn?ng& rName ) const
1452 |*		gebe den Pointer auf die benannte Box zurueck.
1453 |*
1454 |*************************************************************************/
1455 
IsValidRowName(const String & rStr)1456 sal_Bool IsValidRowName( const String& rStr )
1457 {
1458 	sal_Bool bIsValid = sal_True;
1459 	xub_StrLen nLen = rStr.Len();
1460 	for (xub_StrLen i = 0;  i < nLen && bIsValid;  ++i)
1461 	{
1462 		const sal_Unicode cChar = rStr.GetChar(i);
1463 		if (cChar < '0' || cChar > '9')
1464 			bIsValid = sal_False;
1465 	}
1466 	return bIsValid;
1467 }
1468 
1469 // --> OD 2007-08-03 #i80314#
1470 // add 3rd parameter and its handling
_GetBoxNum(String & rStr,sal_Bool bFirstPart,const bool bPerformValidCheck)1471 sal_uInt16 SwTable::_GetBoxNum( String& rStr, sal_Bool bFirstPart,
1472                             const bool bPerformValidCheck )
1473 {
1474 	sal_uInt16 nRet = 0;
1475 	xub_StrLen nPos = 0;
1476     if( bFirstPart )   // sal_True == column; sal_False == row
1477 	{
1478 		// die 1. ist mit Buchstaben addressiert!
1479 		sal_Unicode cChar;
1480 		sal_Bool bFirst = sal_True;
1481 		while( 0 != ( cChar = rStr.GetChar( nPos )) &&
1482 			   ( (cChar >= 'A' && cChar <= 'Z') ||
1483 			     (cChar >= 'a' && cChar <= 'z') ) )
1484 		{
1485 			if( (cChar -= 'A') >= 26 )
1486 				cChar -= 'a' - '[';
1487 			if( bFirst )
1488 				bFirst = sal_False;
1489 			else
1490 				++nRet;
1491 			nRet = nRet * 52 + cChar;
1492 			++nPos;
1493 		}
1494 		rStr.Erase( 0, nPos );		// Zeichen aus dem String loeschen
1495 	}
1496 	else if( STRING_NOTFOUND == ( nPos = rStr.Search( aDotStr ) ))
1497 	{
1498         nRet = 0;
1499         if ( !bPerformValidCheck || IsValidRowName( rStr ) )
1500         {
1501 			nRet = static_cast<sal_uInt16>(rStr.ToInt32());
1502         }
1503 		rStr.Erase();
1504 	}
1505 	else
1506 	{
1507         nRet = 0;
1508 		String aTxt( rStr.Copy( 0, nPos ) );
1509         if ( !bPerformValidCheck || IsValidRowName( aTxt ) )
1510         {
1511 			nRet = static_cast<sal_uInt16>(aTxt.ToInt32());
1512         }
1513 		rStr.Erase( 0, nPos+1 );
1514 	}
1515 	return nRet;
1516 }
1517 // <--
1518 
1519 // --> OD 2007-08-03 #i80314#
1520 // add 2nd parameter and its handling
GetTblBox(const String & rName,const bool bPerformValidCheck) const1521 const SwTableBox* SwTable::GetTblBox( const String& rName,
1522                                       const bool bPerformValidCheck ) const
1523 {
1524 	const SwTableBox* pBox = 0;
1525 	const SwTableLine* pLine;
1526 	const SwTableLines* pLines;
1527 	const SwTableBoxes* pBoxes;
1528 
1529 	sal_uInt16 nLine, nBox;
1530 	String aNm( rName );
1531 	while( aNm.Len() )
1532 	{
1533         nBox = SwTable::_GetBoxNum( aNm, 0 == pBox, bPerformValidCheck );
1534 		// erste Box ?
1535 		if( !pBox )
1536 			pLines = &GetTabLines();
1537 		else
1538 		{
1539 			pLines = &pBox->GetTabLines();
1540 			if( nBox )
1541 				--nBox;
1542 		}
1543 
1544         nLine = SwTable::_GetBoxNum( aNm, sal_False, bPerformValidCheck );
1545 
1546 		// bestimme die Line
1547 		if( !nLine || nLine > pLines->Count() )
1548 			return 0;
1549 		pLine = (*pLines)[ nLine-1 ];
1550 
1551 		// bestimme die Box
1552 		pBoxes = &pLine->GetTabBoxes();
1553 		if( nBox >= pBoxes->Count() )
1554 			return 0;
1555 		pBox = (*pBoxes)[ nBox ];
1556 	}
1557 
1558 	// abpruefen, ob die gefundene Box auch wirklich eine Inhaltstragende
1559 	// Box ist ??
1560 	if( pBox && !pBox->GetSttNd() )
1561 	{
1562 		ASSERT( sal_False, "Box ohne Inhalt, suche die naechste !!" );
1563 		// "herunterfallen lassen" bis zur ersten Box
1564 		while( pBox->GetTabLines().Count() )
1565 			pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
1566 	}
1567 	return pBox;
1568 }
1569 
GetTblBox(sal_uLong nSttIdx)1570 SwTableBox* SwTable::GetTblBox( sal_uLong nSttIdx )
1571 {
1572 	//MA: Zur Optimierung nicht immer umstaendlich das ganze SortArray abhuenern.
1573     //OS: #102675# converting text to table tries und certain conditions
1574     // to ask for a table box of a table that is not yet having a format
1575     if(!GetFrmFmt())
1576         return 0;
1577     SwTableBox* pRet = 0;
1578     SwNodes& rNds = GetFrmFmt()->GetDoc()->GetNodes();
1579 	sal_uLong nIndex = nSttIdx + 1;
1580 	SwCntntNode* pCNd = 0;
1581     SwTableNode* pTblNd = 0;
1582 
1583     while ( nIndex < rNds.Count() )
1584     {
1585         pTblNd = rNds[ nIndex ]->GetTableNode();
1586         if ( pTblNd )
1587             break;
1588 
1589         pCNd = rNds[ nIndex ]->GetCntntNode();
1590         if ( pCNd )
1591             break;
1592 
1593         ++nIndex;
1594     }
1595 
1596 	if ( pCNd || pTblNd )
1597 	{
1598         SwModify* pModify = pCNd;
1599         // --> FME 2007-3-26 #144862# Better handling of table in table:
1600         if ( pTblNd && pTblNd->GetTable().GetFrmFmt() )
1601             pModify = pTblNd->GetTable().GetFrmFmt();
1602         // <--
1603 
1604         SwFrm* pFrm = SwIterator<SwFrm,SwModify>::FirstElement( *pModify );
1605 		while ( pFrm && !pFrm->IsCellFrm() )
1606 			pFrm = pFrm->GetUpper();
1607 		if ( pFrm )
1608 			pRet = (SwTableBox*)((SwCellFrm*)pFrm)->GetTabBox();
1609 	}
1610 
1611 	//Falls es das Layout noch nicht gibt oder sonstwie etwas schieft geht.
1612 	if ( !pRet )
1613 	{
1614 		for( sal_uInt16 n = aSortCntBoxes.Count(); n; )
1615 			if( aSortCntBoxes[ --n ]->GetSttIdx() == nSttIdx )
1616 				return aSortCntBoxes[ n ];
1617 	}
1618 	return pRet;
1619 }
1620 
IsTblComplex() const1621 sal_Bool SwTable::IsTblComplex() const
1622 {
1623 	// returnt sal_True wenn sich in der Tabelle Verschachtelungen befinden
1624 	// steht eine Box nicht in der obersten Line, da wurde gesplittet/
1625 	// gemergt und die Struktur ist komplexer.
1626 	for( sal_uInt16 n = 0; n < aSortCntBoxes.Count(); ++n )
1627 		if( aSortCntBoxes[ n ]->GetUpper()->GetUpper() )
1628 			return sal_True;
1629 	return sal_False;
1630 }
1631 
1632 
1633 
1634 /*************************************************************************
1635 |*
1636 |*	SwTableLine::SwTableLine()
1637 |*
1638 |*************************************************************************/
SwTableLine(SwTableLineFmt * pFmt,sal_uInt16 nBoxes,SwTableBox * pUp)1639 SwTableLine::SwTableLine( SwTableLineFmt *pFmt, sal_uInt16 nBoxes,
1640 							SwTableBox *pUp )
1641 	: SwClient( pFmt ),
1642 	aBoxes( (sal_uInt8)nBoxes, 1 ),
1643 	pUpper( pUp )
1644 {
1645 }
1646 
~SwTableLine()1647 SwTableLine::~SwTableLine()
1648 {
1649 	// ist die TabelleLine der letzte Client im FrameFormat, kann dieses
1650 	// geloescht werden
1651 	SwModify* pMod = GetFrmFmt();
1652 	pMod->Remove( this );				// austragen,
1653 	if( !pMod->GetDepends() )
1654 		delete pMod;	// und loeschen
1655 }
1656 
1657 /*************************************************************************
1658 |*
1659 |*	SwTableLine::ClaimFrmFmt(), ChgFrmFmt()
1660 |*
1661 |*************************************************************************/
ClaimFrmFmt()1662 SwFrmFmt* SwTableLine::ClaimFrmFmt()
1663 {
1664     // This method makes sure that this object is an exclusive SwTableLine client
1665     // of an SwTableLineFmt object
1666     // If other SwTableLine objects currently listen to the same SwTableLineFmt as
1667     // this one, something needs to be done
1668 	SwTableLineFmt *pRet = (SwTableLineFmt*)GetFrmFmt();
1669 	SwIterator<SwTableLine,SwFmt> aIter( *pRet );
1670 	for( SwTableLine* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1671     {
1672 	    if ( pLast != this )
1673 	    {
1674             // found another SwTableLine that is a client of the current Fmt
1675             // create a new Fmt as a copy and use it for this object
1676 		    SwTableLineFmt *pNewFmt = pRet->GetDoc()->MakeTableLineFmt();
1677 		    *pNewFmt = *pRet;
1678 
1679 		    // register SwRowFrms that know me as clients at the new Fmt
1680             SwIterator<SwRowFrm,SwFmt> aFrmIter( *pRet );
1681 	        for( SwRowFrm* pFrm = aFrmIter.First(); pFrm; pFrm = aFrmIter.Next() )
1682 		        if( pFrm->GetTabLine() == this )
1683                     pFrm->RegisterToFormat( *pNewFmt );
1684 
1685 		    // register myself
1686 		    pNewFmt->Add( this );
1687 		    pRet = pNewFmt;
1688             break;
1689         }
1690 	}
1691 
1692 	return pRet;
1693 }
1694 
ChgFrmFmt(SwTableLineFmt * pNewFmt)1695 void SwTableLine::ChgFrmFmt( SwTableLineFmt *pNewFmt )
1696 {
1697 	SwFrmFmt *pOld = GetFrmFmt();
1698 	SwIterator<SwRowFrm,SwFmt> aIter( *pOld );
1699 
1700 	//Erstmal die Frms ummelden.
1701 	for( SwRowFrm* pRow = aIter.First(); pRow; pRow = aIter.Next() )
1702 	{
1703 		if( pRow->GetTabLine() == this )
1704 		{
1705             pRow->RegisterToFormat( *pNewFmt );
1706 
1707             pRow->InvalidateSize();
1708 			pRow->_InvalidatePrt();
1709 			pRow->SetCompletePaint();
1710 			pRow->ReinitializeFrmSizeAttrFlags();
1711 
1712             // --> FME 2004-10-27 #i35063#
1713             // consider 'split row allowed' attribute
1714             SwTabFrm* pTab = pRow->FindTabFrm();
1715             bool bInFollowFlowRow = false;
1716             const bool bInFirstNonHeadlineRow = pTab->IsFollow() &&
1717                                                 pRow == pTab->GetFirstNonHeadlineRow();
1718             if ( bInFirstNonHeadlineRow ||
1719                  !pRow->GetNext() ||
1720                  0 != ( bInFollowFlowRow = pRow->IsInFollowFlowRow() ) ||
1721                  0 != pRow->IsInSplitTableRow() )
1722             {
1723                 if ( bInFirstNonHeadlineRow || bInFollowFlowRow )
1724                     pTab = pTab->FindMaster();
1725 
1726                 pTab->SetRemoveFollowFlowLinePending( sal_True );
1727                 pTab->InvalidatePos();
1728             }
1729             // <--
1730         }
1731 	}
1732 
1733 	//Jetzt noch mich selbst ummelden.
1734 	pNewFmt->Add( this );
1735 
1736 	if ( !pOld->GetDepends() )
1737 		delete pOld;
1738 }
1739 
GetTableLineHeight(bool & bLayoutAvailable) const1740 SwTwips SwTableLine::GetTableLineHeight( bool& bLayoutAvailable ) const
1741 {
1742     SwTwips nRet = 0;
1743     bLayoutAvailable = false;
1744 	SwIterator<SwRowFrm,SwFmt> aIter( *GetFrmFmt() );
1745     // A row could appear several times in headers/footers so only one chain of master/follow tables
1746     // will be accepted...
1747     const SwTabFrm* pChain = NULL; // My chain
1748 	for( SwRowFrm* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1749     {
1750 		if( pLast->GetTabLine() == this )
1751 		{
1752             const SwTabFrm* pTab = pLast->FindTabFrm();
1753             bLayoutAvailable = ( pTab && pTab->IsVertical() ) ?
1754                                ( 0 < pTab->Frm().Height() ) :
1755                                ( 0 < pTab->Frm().Width() );
1756 
1757             // The first one defines the chain, if a chain is defined, only members of the chain
1758             // will be added.
1759             if( !pChain || pChain->IsAnFollow( pTab ) || pTab->IsAnFollow( pChain ) )
1760             {
1761                 pChain = pTab; // defines my chain (even it is already)
1762                 if( pTab->IsVertical() )
1763                     nRet += pLast->Frm().Width();
1764                 else
1765                     nRet += pLast->Frm().Height();
1766                 // Optimization, if there are no master/follows in my chain, nothing more to add
1767                 if( !pTab->HasFollow() && !pTab->IsFollow() )
1768                     break;
1769                 // This is not an optimization, this is necessary to avoid double additions of
1770                 // repeating rows
1771                 if( pTab->IsInHeadline(*pLast) )
1772                     break;
1773             }
1774         }
1775     }
1776     return nRet;
1777 }
1778 
1779 /*************************************************************************
1780 |*
1781 |*	SwTableBox::SwTableBox()
1782 |*
1783 |*************************************************************************/
SwTableBox(SwTableBoxFmt * pFmt,sal_uInt16 nLines,SwTableLine * pUp)1784 SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, sal_uInt16 nLines, SwTableLine *pUp )
1785 	: SwClient( 0 ),
1786 	aLines( (sal_uInt8)nLines, 1 ),
1787 	pSttNd( 0 ),
1788 	pUpper( pUp ),
1789 	pImpl( 0 )
1790 {
1791 	CheckBoxFmt( pFmt )->Add( this );
1792 }
1793 
SwTableBox(SwTableBoxFmt * pFmt,const SwNodeIndex & rIdx,SwTableLine * pUp)1794 SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, const SwNodeIndex &rIdx,
1795 						SwTableLine *pUp )
1796 	: SwClient( 0 ),
1797 	aLines( 0, 0 ),
1798 	pUpper( pUp ),
1799 	pImpl( 0 )
1800 {
1801 	CheckBoxFmt( pFmt )->Add( this );
1802 
1803     pSttNd = rIdx.GetNode().GetStartNode();
1804 
1805 	// an der Table eintragen
1806 	const SwTableNode* pTblNd = pSttNd->FindTableNode();
1807 	ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" );
1808 	SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable().
1809 								GetTabSortBoxes();
1810 	SwTableBox* p = this;	// error: &this
1811 	rSrtArr.Insert( p );		// eintragen
1812 }
1813 
SwTableBox(SwTableBoxFmt * pFmt,const SwStartNode & rSttNd,SwTableLine * pUp)1814 SwTableBox::SwTableBox( SwTableBoxFmt* pFmt, const SwStartNode& rSttNd, SwTableLine *pUp ) :
1815 	SwClient( 0 ),
1816 	aLines( 0, 0 ),
1817     pSttNd( &rSttNd ),
1818 	pUpper( pUp ),
1819     pImpl( 0 )
1820 {
1821     CheckBoxFmt( pFmt )->Add( this );
1822 
1823 	// an der Table eintragen
1824 	const SwTableNode* pTblNd = pSttNd->FindTableNode();
1825 	ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" );
1826 	SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable().
1827 								GetTabSortBoxes();
1828 	SwTableBox* p = this;	// error: &this
1829 	rSrtArr.Insert( p );		// eintragen
1830 }
1831 
~SwTableBox()1832 SwTableBox::~SwTableBox()
1833 {
1834 	// Inhaltstragende Box ?
1835 	if( !GetFrmFmt()->GetDoc()->IsInDtor() && pSttNd )
1836 	{
1837 		// an der Table austragen
1838 		const SwTableNode* pTblNd = pSttNd->FindTableNode();
1839 		ASSERT( pTblNd, "in welcher Tabelle steht denn die Box?" );
1840 		SwTableSortBoxes& rSrtArr = (SwTableSortBoxes&)pTblNd->GetTable().
1841 									GetTabSortBoxes();
1842 		SwTableBox *p = this;	// error: &this
1843 		rSrtArr.Remove( p );		// austragen
1844 	}
1845 
1846 	// ist die TabelleBox der letzte Client im FrameFormat, kann dieses
1847 	// geloescht werden
1848 	SwModify* pMod = GetFrmFmt();
1849 	pMod->Remove( this );				// austragen,
1850 	if( !pMod->GetDepends() )
1851 		delete pMod;	// und loeschen
1852 
1853 	delete pImpl;
1854 }
1855 
CheckBoxFmt(SwTableBoxFmt * pFmt)1856 SwTableBoxFmt* SwTableBox::CheckBoxFmt( SwTableBoxFmt* pFmt )
1857 {
1858 	// sollte das Format eine Formel oder einen Value tragen, dann muss die
1859 	// Box alleine am Format haengen. Ggfs. muss ein neues angelegt werden.
1860 	if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_False ) ||
1861 		SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA, sal_False ) )
1862 	{
1863 		SwTableBox* pOther = SwIterator<SwTableBox,SwFmt>::FirstElement( *pFmt );
1864 		if( pOther )
1865 		{
1866 			SwTableBoxFmt* pNewFmt = pFmt->GetDoc()->MakeTableBoxFmt();
1867 			pNewFmt->LockModify();
1868 			*pNewFmt = *pFmt;
1869 
1870 			// Values und Formeln entfernen
1871             pNewFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1872 			pNewFmt->UnlockModify();
1873 
1874 			pFmt = pNewFmt;
1875 		}
1876 	}
1877 	return pFmt;
1878 }
1879 
1880 /*************************************************************************
1881 |*
1882 |*	SwTableBox::ClaimFrmFmt(), ChgFrmFmt()
1883 |*
1884 |*************************************************************************/
ClaimFrmFmt()1885 SwFrmFmt* SwTableBox::ClaimFrmFmt()
1886 {
1887     // This method makes sure that this object is an exclusive SwTableBox client
1888     // of an SwTableBoxFmt object
1889     // If other SwTableBox objects currently listen to the same SwTableBoxFmt as
1890     // this one, something needs to be done
1891 	SwTableBoxFmt *pRet = (SwTableBoxFmt*)GetFrmFmt();
1892 	SwIterator<SwTableBox,SwFmt> aIter( *pRet );
1893 	for( SwTableBox* pLast = aIter.First(); pLast; pLast = aIter.Next() )
1894     {
1895 	    if ( pLast != this )
1896         {
1897             // Found another SwTableBox object
1898             // create a new Fmt as a copy and assign me to it
1899 		    // don't copy values and formulas
1900 		    SwTableBoxFmt* pNewFmt = pRet->GetDoc()->MakeTableBoxFmt();
1901 		    pNewFmt->LockModify();
1902 		    *pNewFmt = *pRet;
1903             pNewFmt->ResetFmtAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
1904 		    pNewFmt->UnlockModify();
1905 
1906 		    // re-register SwCellFrm objects that know me
1907             SwIterator<SwCellFrm,SwFmt> aFrmIter( *pRet );
1908 	        for( SwCellFrm* pCell = aFrmIter.First(); pCell; pCell = aFrmIter.Next() )
1909 		        if( pCell->GetTabBox() == this )
1910                     pCell->RegisterToFormat( *pNewFmt );
1911 
1912 		    // re-register myself
1913 		    pNewFmt->Add( this );
1914 		    pRet = pNewFmt;
1915             break;
1916         }
1917     }
1918 	return pRet;
1919 }
1920 
ChgFrmFmt(SwTableBoxFmt * pNewFmt)1921 void SwTableBox::ChgFrmFmt( SwTableBoxFmt* pNewFmt )
1922 {
1923 	SwFrmFmt *pOld = GetFrmFmt();
1924 	SwIterator<SwCellFrm,SwFmt> aIter( *pOld );
1925 
1926 	//Erstmal die Frms ummelden.
1927 	for( SwCellFrm* pCell = aIter.First(); pCell; pCell = aIter.Next() )
1928 	{
1929 		if( pCell->GetTabBox() == this )
1930 		{
1931             pCell->RegisterToFormat( *pNewFmt );
1932 			pCell->InvalidateSize();
1933 			pCell->_InvalidatePrt();
1934 			pCell->SetCompletePaint();
1935             pCell->SetDerivedVert( sal_False );
1936             pCell->CheckDirChange();
1937 
1938             // --> FME 2005-04-15 #i47489#
1939             // make sure that the row will be formatted, in order
1940             // to have the correct Get(Top|Bottom)MarginForLowers values
1941             // set at the row.
1942             const SwTabFrm* pTab = pCell->FindTabFrm();
1943             if ( pTab && pTab->IsCollapsingBorders() )
1944             {
1945                 SwFrm* pRow = pCell->GetUpper();
1946                 pRow->_InvalidateSize();
1947                 pRow->_InvalidatePrt();
1948             }
1949             // <--
1950         }
1951 	}
1952 
1953 	//Jetzt noch mich selbst ummelden.
1954 	pNewFmt->Add( this );
1955 
1956 	if( !pOld->GetDepends() )
1957 		delete pOld;
1958 }
1959 
1960 /*************************************************************************
1961 |*
1962 |*	String SwTableBox::GetName() const
1963 |*		gebe den Namen dieser Box zurueck. Dieser wird dynamisch bestimmt
1964 |*		und ergibt sich aus der Position in den Lines/Boxen/Tabelle
1965 |*
1966 |*************************************************************************/
lcl_GetTblBoxColStr(sal_uInt16 nCol,String & rNm)1967 void lcl_GetTblBoxColStr( sal_uInt16 nCol, String& rNm )
1968 {
1969 	const sal_uInt16 coDiff = 52; 	// 'A'-'Z' 'a' - 'z'
1970     sal_uInt16 nCalc;
1971 
1972 	do {
1973 		nCalc = nCol % coDiff;
1974 		if( nCalc >= 26 )
1975 			rNm.Insert( sal_Unicode('a' - 26 + nCalc ), 0 );
1976 		else
1977 			rNm.Insert( sal_Unicode('A' + nCalc ), 0 );
1978 
1979         if( 0 == (nCol = nCol - nCalc) )
1980 			break;
1981 		nCol /= coDiff;
1982 		--nCol;
1983 	} while( 1 );
1984 }
1985 
GetName() const1986 String SwTableBox::GetName() const
1987 {
1988 	if( !pSttNd )		// keine Content Box ??
1989 	{
1990 		// die naechste erste Box suchen ??
1991 		return aEmptyStr;
1992 	}
1993 
1994 	const SwTable& rTbl = pSttNd->FindTableNode()->GetTable();
1995     sal_uInt16 nPos;
1996 	String sNm, sTmp;
1997 	const SwTableBox* pBox = this;
1998 	do {
1999 		const SwTableBoxes* pBoxes = &pBox->GetUpper()->GetTabBoxes();
2000 		const SwTableLine* pLine = pBox->GetUpper();
2001 		// auf oberstere Ebene ?
2002 		const SwTableLines* pLines = pLine->GetUpper()
2003 				? &pLine->GetUpper()->GetTabLines() : &rTbl.GetTabLines();
2004 
2005 		sTmp = String::CreateFromInt32( nPos = pLines->GetPos( pLine ) + 1 );
2006 		if( sNm.Len() )
2007 			sNm.Insert( aDotStr, 0 ).Insert( sTmp, 0 );
2008 		else
2009 			sNm = sTmp;
2010 
2011 		sTmp = String::CreateFromInt32(( nPos = pBoxes->GetPos( pBox )) + 1 );
2012 		if( 0 != ( pBox = pLine->GetUpper()) )
2013 			sNm.Insert( aDotStr, 0 ).Insert( sTmp, 0 );
2014 		else
2015 			::lcl_GetTblBoxColStr( nPos, sNm );
2016 
2017 	} while( pBox );
2018 	return sNm;
2019 }
2020 
IsInHeadline(const SwTable * pTbl) const2021 sal_Bool SwTableBox::IsInHeadline( const SwTable* pTbl ) const
2022 {
2023 	if( !GetUpper() )			// sollte nur beim Merge vorkommen.
2024 		return sal_False;
2025 
2026 	if( !pTbl )
2027 		pTbl = &pSttNd->FindTableNode()->GetTable();
2028 
2029 	const SwTableLine* pLine = GetUpper();
2030 	while( pLine->GetUpper() )
2031 		pLine = pLine->GetUpper()->GetUpper();
2032 
2033 	// Headerline?
2034 	return pTbl->GetTabLines()[ 0 ] == pLine;
2035 }
2036 
2037 #ifdef DBG_UTIL
2038 
GetSttIdx() const2039 sal_uLong SwTableBox::GetSttIdx() const
2040 {
2041 	return pSttNd ? pSttNd->GetIndex() : 0;
2042 }
2043 #endif
2044 
2045 	// erfrage vom Client Informationen
GetInfo(SfxPoolItem & rInfo) const2046 sal_Bool SwTable::GetInfo( SfxPoolItem& rInfo ) const
2047 {
2048 	switch( rInfo.Which() )
2049 	{
2050 	case RES_AUTOFMT_DOCNODE:
2051     {
2052         const SwTableNode* pTblNode = GetTableNode();
2053         if( pTblNode && &pTblNode->GetNodes() == ((SwAutoFmtGetDocNode&)rInfo).pNodes )
2054         {
2055             if ( aSortCntBoxes.Count() )
2056             {
2057   			    SwNodeIndex aIdx( *aSortCntBoxes[ 0 ]->GetSttNd() );
2058     		    ((SwAutoFmtGetDocNode&)rInfo).pCntntNode =
2059 	    		    			GetFrmFmt()->GetDoc()->GetNodes().GoNext( &aIdx );
2060             }
2061 			return sal_False;
2062 		}
2063 		break;
2064     }
2065 	case RES_FINDNEARESTNODE:
2066         if( GetFrmFmt() && ((SwFmtPageDesc&)GetFrmFmt()->GetFmtAttr(
2067 			RES_PAGEDESC )).GetPageDesc() &&
2068 			aSortCntBoxes.Count() &&
2069 			aSortCntBoxes[ 0 ]->GetSttNd()->GetNodes().IsDocNodes() )
2070 			((SwFindNearestNode&)rInfo).CheckNode( *
2071 				aSortCntBoxes[ 0 ]->GetSttNd()->FindTableNode() );
2072 		break;
2073 
2074 	case RES_CONTENT_VISIBLE:
2075 		{
2076 			((SwPtrMsgPoolItem&)rInfo).pObject = SwIterator<SwFrm,SwFmt>::FirstElement( *GetFrmFmt() );
2077 		}
2078 		return sal_False;
2079 	}
2080 	return sal_True;
2081 }
2082 
FindTable(SwFrmFmt const * const pFmt)2083 SwTable * SwTable::FindTable( SwFrmFmt const*const pFmt )
2084 {
2085     return (pFmt)
2086         ? SwIterator<SwTable,SwFmt>::FirstElement(*pFmt)
2087         : 0;
2088 }
2089 
GetTableNode() const2090 SwTableNode* SwTable::GetTableNode() const
2091 {
2092     return GetTabSortBoxes().Count() ?
2093            (SwTableNode*)GetTabSortBoxes()[ 0 ]->GetSttNd()->FindTableNode() :
2094            pTableNode;
2095 }
2096 
SetRefObject(SwServerObject * pObj)2097 void SwTable::SetRefObject( SwServerObject* pObj )
2098 {
2099 	if( refObj.Is() )
2100 		refObj->Closed();
2101 
2102 	refObj = pObj;
2103 }
2104 
2105 
SetHTMLTableLayout(SwHTMLTableLayout * p)2106 void SwTable::SetHTMLTableLayout( SwHTMLTableLayout *p )
2107 {
2108 	delete pHTMLLayout;
2109 	pHTMLLayout = p;
2110 }
2111 
ChgTextToNum(SwTableBox & rBox,const String & rTxt,const Color * pCol,sal_Bool bChgAlign)2112 void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol,
2113 					sal_Bool bChgAlign )
2114 {
2115     sal_uLong nNdPos = rBox.IsValidNumTxtNd( sal_True );
2116     ChgTextToNum( rBox,rTxt,pCol,bChgAlign,nNdPos);
2117 }
ChgTextToNum(SwTableBox & rBox,const String & rTxt,const Color * pCol,sal_Bool bChgAlign,sal_uLong nNdPos)2118 void ChgTextToNum( SwTableBox& rBox, const String& rTxt, const Color* pCol,
2119 					sal_Bool bChgAlign,sal_uLong nNdPos )
2120 {
2121 
2122 	if( ULONG_MAX != nNdPos )
2123 	{
2124 		SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2125 		SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2126 		const SfxPoolItem* pItem;
2127 
2128 		// Ausrichtung umsetzen
2129 		if( bChgAlign )
2130 		{
2131 			pItem = &pTNd->SwCntntNode::GetAttr( RES_PARATR_ADJUST );
2132 			SvxAdjust eAdjust = ((SvxAdjustItem*)pItem)->GetAdjust();
2133 			if( SVX_ADJUST_LEFT == eAdjust || SVX_ADJUST_BLOCK == eAdjust )
2134 			{
2135 				SvxAdjustItem aAdjust( *(SvxAdjustItem*)pItem );
2136 				aAdjust.SetAdjust( SVX_ADJUST_RIGHT );
2137                 pTNd->SetAttr( aAdjust );
2138 			}
2139 		}
2140 
2141 		// Farbe umsetzen oder "Benutzer Farbe" sichern
2142 		if( !pTNd->GetpSwAttrSet() || SFX_ITEM_SET != pTNd->GetpSwAttrSet()->
2143 			GetItemState( RES_CHRATR_COLOR, sal_False, &pItem ))
2144 			pItem = 0;
2145 
2146 		const Color* pOldNumFmtColor = rBox.GetSaveNumFmtColor();
2147 		const Color* pNewUserColor = pItem ? &((SvxColorItem*)pItem)->GetValue() : 0;
2148 
2149 		if( ( pNewUserColor && pOldNumFmtColor &&
2150 				*pNewUserColor == *pOldNumFmtColor ) ||
2151 			( !pNewUserColor && !pOldNumFmtColor ))
2152 		{
2153 			// User Color nicht veraendern aktuellen Werte setzen
2154 			// ggfs. die alte NumFmtColor loeschen
2155 			if( pCol )
2156 				// ggfs. die Farbe setzen
2157                 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2158 			else if( pItem )
2159 			{
2160 				pNewUserColor = rBox.GetSaveUserColor();
2161 				if( pNewUserColor )
2162                     pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2163 				else
2164                     pTNd->ResetAttr( RES_CHRATR_COLOR );
2165 			}
2166 		}
2167 		else
2168 		{
2169 			// User Color merken, ggfs. die NumFormat Color setzen, aber
2170 			// nie die Farbe zurueck setzen
2171 			rBox.SetSaveUserColor( pNewUserColor );
2172 
2173 			if( pCol )
2174 				// ggfs. die Farbe setzen
2175                 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2176 
2177 		}
2178 		rBox.SetSaveNumFmtColor( pCol );
2179 
2180 		if( pTNd->GetTxt() != rTxt )
2181 		{
2182 			// Text austauschen
2183 			//JP 15.09.98: Bug 55741 - Tabs beibehalten (vorne und hinten!)
2184 			const String& rOrig = pTNd->GetTxt();
2185 			xub_StrLen n;
2186 
2187 			for( n = 0; n < rOrig.Len() && '\x9' == rOrig.GetChar( n ); ++n )
2188 				;
2189             for( ; n < rOrig.Len() && '\x01' == rOrig.GetChar( n ); ++n )
2190 				;
2191 			SwIndex aIdx( pTNd, n );
2192 			for( n = rOrig.Len(); n && '\x9' == rOrig.GetChar( --n ); )
2193 				;
2194 			n -= aIdx.GetIndex() - 1;
2195 
2196 			//JP 06.04.99: Bug 64321 - DontExpand-Flags vorm Austauschen
2197 			//             zuruecksetzen, damit sie wieder aufgespannt werden
2198 			{
2199 				SwIndex aResetIdx( aIdx, n );
2200 				pTNd->DontExpandFmt( aResetIdx, sal_False, sal_False );
2201 			}
2202 
2203             if( !pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() )
2204             {
2205                 SwPaM aTemp(*pTNd, 0, *pTNd, rOrig.Len());
2206                 pDoc->DeleteRedline(aTemp, true, USHRT_MAX);
2207             }
2208 
2209             pTNd->EraseText( aIdx, n,
2210                     IDocumentContentOperations::INS_EMPTYEXPAND );
2211             pTNd->InsertText( rTxt, aIdx,
2212                     IDocumentContentOperations::INS_EMPTYEXPAND );
2213 
2214             if( pDoc->IsRedlineOn() )
2215             {
2216                 SwPaM aTemp(*pTNd, 0, *pTNd, rTxt.Len());
2217                 pDoc->AppendRedline(new SwRedline(nsRedlineType_t::REDLINE_INSERT, aTemp), true);
2218             }
2219 		}
2220 
2221 		// vertikale Ausrichtung umsetzen
2222 		if( bChgAlign &&
2223 			( SFX_ITEM_SET != rBox.GetFrmFmt()->GetItemState(
2224 				RES_VERT_ORIENT, sal_True, &pItem ) ||
2225 				text::VertOrientation::TOP == ((SwFmtVertOrient*)pItem)->GetVertOrient() ))
2226 		{
2227             rBox.GetFrmFmt()->SetFmtAttr( SwFmtVertOrient( 0, text::VertOrientation::BOTTOM ));
2228 		}
2229 	}
2230 }
2231 
ChgNumToText(SwTableBox & rBox,sal_uLong nFmt)2232 void ChgNumToText( SwTableBox& rBox, sal_uLong nFmt )
2233 {
2234 	sal_uLong nNdPos = rBox.IsValidNumTxtNd( sal_False );
2235 	if( ULONG_MAX != nNdPos )
2236 	{
2237 		SwDoc* pDoc = rBox.GetFrmFmt()->GetDoc();
2238 		SwTxtNode* pTNd = pDoc->GetNodes()[ nNdPos ]->GetTxtNode();
2239 		sal_Bool bChgAlign = pDoc->IsInsTblAlignNum();
2240 		const SfxPoolItem* pItem;
2241 
2242 		Color* pCol = 0;
2243 		if( NUMBERFORMAT_TEXT != nFmt )
2244 		{
2245 			// speziellen Textformat:
2246 			String sTmp, sTxt( pTNd->GetTxt() );
2247 			pDoc->GetNumberFormatter()->GetOutputString( sTxt, nFmt, sTmp, &pCol );
2248 			if( sTxt != sTmp )
2249 			{
2250 				// Text austauschen
2251 				SwIndex aIdx( pTNd, sTxt.Len() );
2252 				//JP 06.04.99: Bug 64321 - DontExpand-Flags vorm Austauschen
2253 				//             zuruecksetzen, damit sie wieder aufgespannt werden
2254 				pTNd->DontExpandFmt( aIdx, sal_False, sal_False );
2255 				aIdx = 0;
2256                 pTNd->EraseText( aIdx, STRING_LEN,
2257                         IDocumentContentOperations::INS_EMPTYEXPAND );
2258                 pTNd->InsertText( sTmp, aIdx,
2259                         IDocumentContentOperations::INS_EMPTYEXPAND );
2260             }
2261         }
2262 
2263         const SfxItemSet* pAttrSet = pTNd->GetpSwAttrSet();
2264 
2265 		// Ausrichtung umsetzen
2266 		if( bChgAlign && pAttrSet && SFX_ITEM_SET == pAttrSet->GetItemState(
2267 			RES_PARATR_ADJUST, sal_False, &pItem ) &&
2268 				SVX_ADJUST_RIGHT == ((SvxAdjustItem*)pItem)->GetAdjust() )
2269 		{
2270             pTNd->SetAttr( SvxAdjustItem( SVX_ADJUST_LEFT, RES_PARATR_ADJUST ) );
2271 		}
2272 
2273 		// Farbe umsetzen oder "Benutzer Farbe" sichern
2274 		if( !pAttrSet || SFX_ITEM_SET != pAttrSet->
2275 			GetItemState( RES_CHRATR_COLOR, sal_False, &pItem ))
2276 			pItem = 0;
2277 
2278 		const Color* pOldNumFmtColor = rBox.GetSaveNumFmtColor();
2279 		const Color* pNewUserColor = pItem ? &((SvxColorItem*)pItem)->GetValue() : 0;
2280 
2281 		if( ( pNewUserColor && pOldNumFmtColor &&
2282 				*pNewUserColor == *pOldNumFmtColor ) ||
2283 			( !pNewUserColor && !pOldNumFmtColor ))
2284 		{
2285 			// User Color nicht veraendern aktuellen Werte setzen
2286 			// ggfs. die alte NumFmtColor loeschen
2287 			if( pCol )
2288 				// ggfs. die Farbe setzen
2289                 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2290 			else if( pItem )
2291 			{
2292 				pNewUserColor = rBox.GetSaveUserColor();
2293 				if( pNewUserColor )
2294                     pTNd->SetAttr( SvxColorItem( *pNewUserColor, RES_CHRATR_COLOR ));
2295 				else
2296                     pTNd->ResetAttr( RES_CHRATR_COLOR );
2297 			}
2298 		}
2299 		else
2300 		{
2301 			// User Color merken, ggfs. die NumFormat Color setzen, aber
2302 			// nie die Farbe zurueck setzen
2303 			rBox.SetSaveUserColor( pNewUserColor );
2304 
2305 			if( pCol )
2306 				// ggfs. die Farbe setzen
2307                 pTNd->SetAttr( SvxColorItem( *pCol, RES_CHRATR_COLOR ));
2308 
2309 		}
2310 		rBox.SetSaveNumFmtColor( pCol );
2311 
2312 
2313 		// vertikale Ausrichtung umsetzen
2314 		if( bChgAlign &&
2315 			SFX_ITEM_SET == rBox.GetFrmFmt()->GetItemState(
2316 			RES_VERT_ORIENT, sal_False, &pItem ) &&
2317 			text::VertOrientation::BOTTOM == ((SwFmtVertOrient*)pItem)->GetVertOrient() )
2318 		{
2319             rBox.GetFrmFmt()->SetFmtAttr( SwFmtVertOrient( 0, text::VertOrientation::TOP ));
2320 		}
2321 	}
2322 }
2323 
2324 // zum Erkennen von Veraenderungen (haupts. TableBoxAttribute)
Modify(const SfxPoolItem * pOld,const SfxPoolItem * pNew)2325 void SwTableBoxFmt::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
2326 {
2327 	if( !IsModifyLocked() && !IsInDocDTOR() )
2328 	{
2329         const SwTblBoxNumFormat *pNewFmt = 0;
2330         const SwTblBoxFormula *pNewFml = 0;
2331         const SwTblBoxValue *pNewVal = 0;
2332 		double aOldValue = 0;
2333 		sal_uLong nOldFmt = NUMBERFORMAT_TEXT;
2334 
2335         switch( pNew ? pNew->Which() : 0 )
2336 		{
2337 		case RES_ATTRSET_CHG:
2338 			{
2339 				const SfxItemSet& rSet = *((SwAttrSetChg*)pNew)->GetChgSet();
2340 				if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_FORMAT,
2341 									sal_False, (const SfxPoolItem**)&pNewFmt ) )
2342 					nOldFmt = ((SwTblBoxNumFormat&)((SwAttrSetChg*)pOld)->
2343 							GetChgSet()->Get( RES_BOXATR_FORMAT )).GetValue();
2344 				rSet.GetItemState( RES_BOXATR_FORMULA, sal_False,
2345 									(const SfxPoolItem**)&pNewFml );
2346 				if( SFX_ITEM_SET == rSet.GetItemState( RES_BOXATR_VALUE,
2347 									sal_False, (const SfxPoolItem**)&pNewVal ) )
2348 					aOldValue = ((SwTblBoxValue&)((SwAttrSetChg*)pOld)->
2349 							GetChgSet()->Get( RES_BOXATR_VALUE )).GetValue();
2350 			}
2351 			break;
2352 
2353 		case RES_BOXATR_FORMAT:
2354 			pNewFmt = (SwTblBoxNumFormat*)pNew;
2355 			nOldFmt = ((SwTblBoxNumFormat*)pOld)->GetValue();
2356 			break;
2357 		case RES_BOXATR_FORMULA:
2358 			pNewFml = (SwTblBoxFormula*)pNew;
2359 			break;
2360 		case RES_BOXATR_VALUE:
2361 			pNewVal = (SwTblBoxValue*)pNew;
2362 			aOldValue = ((SwTblBoxValue*)pOld)->GetValue();
2363 			break;
2364 		}
2365 
2366 		// es hat sich etwas getan und im Set ist noch irgendein BoxAttribut
2367 		// vorhanden!
2368 		if( pNewFmt || pNewFml || pNewVal )
2369 		{
2370 			GetDoc()->SetFieldsDirty(true, NULL, 0);
2371 
2372 			if( SFX_ITEM_SET == GetItemState( RES_BOXATR_FORMAT, sal_False ) ||
2373 				SFX_ITEM_SET == GetItemState( RES_BOXATR_VALUE, sal_False ) ||
2374 				SFX_ITEM_SET == GetItemState( RES_BOXATR_FORMULA, sal_False ) )
2375 			{
2376 				// die Box holen
2377 				SwIterator<SwTableBox,SwFmt> aIter( *this );
2378 				SwTableBox* pBox = aIter.First();
2379 				if( pBox )
2380 				{
2381 					ASSERT( !aIter.Next(), "keine Box oder mehrere am Format" );
2382 
2383 					sal_uLong nNewFmt;
2384 					if( pNewFmt )
2385 					{
2386 						nNewFmt = pNewFmt->GetValue();
2387 						// neu Formatieren
2388 						// ist es neuer oder wurde der akt. entfernt?
2389 						if( SFX_ITEM_SET != GetItemState( RES_BOXATR_VALUE, sal_False ))
2390 							pNewFmt = 0;
2391 					}
2392 					else
2393 					{
2394 						// das akt. Item besorgen
2395 						GetItemState( RES_BOXATR_FORMAT, sal_False,
2396 											(const SfxPoolItem**)&pNewFmt );
2397 						nOldFmt = GetTblBoxNumFmt().GetValue();
2398 						nNewFmt = pNewFmt ? pNewFmt->GetValue() : nOldFmt;
2399 					}
2400 
2401 					// ist es neuer oder wurde der akt. entfernt?
2402 					if( pNewVal )
2403 					{
2404 						if( NUMBERFORMAT_TEXT != nNewFmt )
2405 						{
2406 							if( SFX_ITEM_SET == GetItemState(
2407 												RES_BOXATR_VALUE, sal_False ))
2408 								nOldFmt = NUMBERFORMAT_TEXT;
2409 							else
2410 								nNewFmt = NUMBERFORMAT_TEXT;
2411 						}
2412 						else if( NUMBERFORMAT_TEXT == nNewFmt )
2413 							nOldFmt = 0;
2414 					}
2415 
2416 					// Logik:
2417 					// ValueAenderung:	-> "simuliere" eine FormatAenderung!
2418 					// FormatAenderung:
2419 					// Text -> !Text oder FormatAenderung:
2420 					//			- Ausrichtung auf RECHTS, wenn LINKS oder Blocksatz
2421 					//			- vertikale Ausrichtung auf UNTEN wenn OBEN oder nicht
2422 					//				gesetzt ist.
2423 					//			- Text ersetzen (Farbe?? neg. Zahlen ROT??)
2424 					// !Text -> Text:
2425 					//			- Ausrichtung auf LINKS, wenn RECHTS
2426 					//			- vertikale Ausrichtung auf OEBN, wenn UNTEN gesetzt ist
2427 
2428 					SvNumberFormatter* pNumFmtr = GetDoc()->GetNumberFormatter();
2429 					sal_Bool bNewIsTxtFmt = pNumFmtr->IsTextFormat( nNewFmt ) ||
2430 										NUMBERFORMAT_TEXT == nNewFmt;
2431 
2432 					if( (!bNewIsTxtFmt && nOldFmt != nNewFmt) || pNewFml )
2433 					{
2434 						sal_Bool bChgTxt = sal_True;
2435 						double fVal = 0;
2436 						if( !pNewVal && SFX_ITEM_SET != GetItemState(
2437 							RES_BOXATR_VALUE, sal_False, (const SfxPoolItem**)&pNewVal ))
2438 						{
2439 							// es wurde noch nie ein Wert gesetzt, dann versuche
2440 							// doch mal den Inhalt auszuwerten
2441 							sal_uLong nNdPos = pBox->IsValidNumTxtNd( sal_True );
2442 							if( ULONG_MAX != nNdPos )
2443 							{
2444 								sal_uInt32 nTmpFmtIdx = nNewFmt;
2445 								String aTxt( GetDoc()->GetNodes()[ nNdPos ]
2446 												->GetTxtNode()->GetRedlineTxt());
2447 								if( !aTxt.Len() )
2448 									bChgTxt = sal_False;
2449 								else
2450 								{
2451 									//JP 15.09.98: Bug 55741 - Tabs beibehalten
2452 									lcl_TabToBlankAtSttEnd( aTxt );
2453 
2454 									// JP 22.04.98: Bug 49659 -
2455 									//			Sonderbehandlung fuer Prozent
2456 									sal_Bool bIsNumFmt = sal_False;
2457 									if( NUMBERFORMAT_PERCENT ==
2458 										pNumFmtr->GetType( nNewFmt ))
2459 									{
2460 										sal_uInt32 nTmpFmt = 0;
2461 										if( pNumFmtr->IsNumberFormat(
2462 													aTxt, nTmpFmt, fVal ))
2463 										{
2464 											if( NUMBERFORMAT_NUMBER ==
2465 												pNumFmtr->GetType( nTmpFmt ))
2466 												aTxt += '%';
2467 
2468 											bIsNumFmt = pNumFmtr->IsNumberFormat(
2469 														aTxt, nTmpFmtIdx, fVal );
2470 										}
2471 									}
2472 									else
2473 										bIsNumFmt = pNumFmtr->IsNumberFormat(
2474 														aTxt, nTmpFmtIdx, fVal );
2475 
2476 									if( bIsNumFmt )
2477 									{
2478 										// dann setze den Value direkt in den Set -
2479 										// ohne Modify
2480 										int bIsLockMod = IsModifyLocked();
2481 										LockModify();
2482                                         SetFmtAttr( SwTblBoxValue( fVal ));
2483 										if( !bIsLockMod )
2484 											UnlockModify();
2485 									}
2486 								}
2487 							}
2488 						}
2489 						else
2490 							fVal = pNewVal->GetValue();
2491 
2492 						// den Inhalt mit dem neuen Wert Formtieren und in den Absatz
2493 						// schbreiben
2494 						Color* pCol = 0;
2495 						String sNewTxt;
2496 						if( DBL_MAX == fVal )
2497 							sNewTxt = ViewShell::GetShellRes()->aCalc_Error;
2498 						else
2499 						{
2500 							pNumFmtr->GetOutputString( fVal, nNewFmt, sNewTxt, &pCol );
2501 
2502 							if( !bChgTxt )
2503 								sNewTxt.Erase();
2504 						}
2505 
2506 						// ueber alle Boxen
2507 						ChgTextToNum( *pBox, sNewTxt, pCol,
2508 										GetDoc()->IsInsTblAlignNum() );
2509 
2510 					}
2511 					else if( bNewIsTxtFmt && nOldFmt != nNewFmt )
2512 					{
2513 						// auf jedenfall muessen jetzt die Formeln/Values
2514 						// geloescht werden!
2515 	//					LockModify();
2516 	//					ResetAttr( RES_BOXATR_FORMULA, RES_BOXATR_VALUE );
2517 	//					UnlockModify();
2518 
2519 
2520 						ChgNumToText( *pBox, nNewFmt );
2521 					}
2522 				}
2523 			}
2524 		}
2525 	}
2526 	// Und die Basis-Klasse rufen
2527 	SwFrmFmt::Modify( pOld, pNew );
2528 }
2529 
HasNumCntnt(double & rNum,sal_uInt32 & rFmtIndex,sal_Bool & rIsEmptyTxtNd) const2530 sal_Bool SwTableBox::HasNumCntnt( double& rNum, sal_uInt32& rFmtIndex,
2531 							sal_Bool& rIsEmptyTxtNd ) const
2532 {
2533 	sal_Bool bRet = sal_False;
2534 	sal_uLong nNdPos = IsValidNumTxtNd( sal_True );
2535 	if( ULONG_MAX != nNdPos )
2536 	{
2537 		String aTxt( pSttNd->GetNodes()[ nNdPos ]->GetTxtNode()->
2538 							GetRedlineTxt() );
2539 		//JP 15.09.98: Bug 55741 - Tabs beibehalten
2540 		lcl_TabToBlankAtSttEnd( aTxt );
2541 		rIsEmptyTxtNd = 0 == aTxt.Len();
2542 		SvNumberFormatter* pNumFmtr = GetFrmFmt()->GetDoc()->GetNumberFormatter();
2543 
2544 		const SfxPoolItem* pItem;
2545 		if( SFX_ITEM_SET == GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT,
2546 				sal_False, &pItem ))
2547 		{
2548 			rFmtIndex = ((SwTblBoxNumFormat*)pItem)->GetValue();
2549 			// JP 22.04.98: Bug 49659 - Sonderbehandlung fuer Prozent
2550 			if( !rIsEmptyTxtNd &&
2551 				NUMBERFORMAT_PERCENT == pNumFmtr->GetType( rFmtIndex ))
2552 			{
2553 				sal_uInt32 nTmpFmt = 0;
2554 				if( pNumFmtr->IsNumberFormat( aTxt, nTmpFmt, rNum ) &&
2555 					NUMBERFORMAT_NUMBER == pNumFmtr->GetType( nTmpFmt ))
2556 					aTxt += '%';
2557 			}
2558 		}
2559 		else
2560 			rFmtIndex = 0;
2561 
2562 		bRet = pNumFmtr->IsNumberFormat( aTxt, rFmtIndex, rNum );
2563 	}
2564 	else
2565 		rIsEmptyTxtNd = sal_False;
2566 	return bRet;
2567 }
2568 
IsNumberChanged() const2569 sal_Bool SwTableBox::IsNumberChanged() const
2570 {
2571 	sal_Bool bRet = sal_True;
2572 
2573 	if( SFX_ITEM_SET == GetFrmFmt()->GetItemState( RES_BOXATR_FORMULA, sal_False ))
2574 	{
2575 		const SwTblBoxNumFormat *pNumFmt;
2576 		const SwTblBoxValue *pValue;
2577 
2578 		if( SFX_ITEM_SET != GetFrmFmt()->GetItemState( RES_BOXATR_VALUE, sal_False,
2579 			(const SfxPoolItem**)&pValue ))
2580 			pValue = 0;
2581 		if( SFX_ITEM_SET != GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT, sal_False,
2582 			(const SfxPoolItem**)&pNumFmt ))
2583 			pNumFmt = 0;
2584 
2585 		sal_uLong nNdPos;
2586 		if( pNumFmt && pValue &&
2587 			ULONG_MAX != ( nNdPos = IsValidNumTxtNd( sal_True ) ) )
2588 		{
2589 			String sNewTxt, sOldTxt( pSttNd->GetNodes()[ nNdPos ]->
2590 									GetTxtNode()->GetRedlineTxt() );
2591 			lcl_DelTabsAtSttEnd( sOldTxt );
2592 
2593 			Color* pCol = 0;
2594 			GetFrmFmt()->GetDoc()->GetNumberFormatter()->GetOutputString(
2595 				pValue->GetValue(), pNumFmt->GetValue(), sNewTxt, &pCol );
2596 
2597 			bRet = sNewTxt != sOldTxt ||
2598 					!( ( !pCol && !GetSaveNumFmtColor() ) ||
2599 					   ( pCol && GetSaveNumFmtColor() &&
2600 						*pCol == *GetSaveNumFmtColor() ));
2601 		}
2602 	}
2603 	return bRet;
2604 }
2605 
IsValidNumTxtNd(sal_Bool bCheckAttr) const2606 sal_uLong SwTableBox::IsValidNumTxtNd( sal_Bool bCheckAttr ) const
2607 {
2608 	sal_uLong nPos = ULONG_MAX;
2609 	if( pSttNd )
2610 	{
2611 		SwNodeIndex aIdx( *pSttNd );
2612 		sal_uLong nIndex = aIdx.GetIndex();
2613 		const sal_uLong nIndexEnd = pSttNd->GetNodes()[ nIndex ]->EndOfSectionIndex();
2614 		const SwTxtNode *pTextNode = 0;
2615 		while( ++nIndex < nIndexEnd )
2616 		{
2617             const SwNode* pNode = pSttNd->GetNodes()[nIndex];
2618 			if( pNode->IsTableNode() )
2619 			{    /*return ULONG_MAX if the cell contains a table(in table)*/
2620 				pTextNode = 0;
2621 				break;
2622 			}
2623 			if( pNode->IsTxtNode() )
2624 			{
2625 				if( pTextNode )
2626 				{    /*return ULONG_MAX if the cell contains complex paragraphs*/
2627 					pTextNode = 0;
2628 					break;
2629 				}
2630                 else
2631                 {
2632                     pTextNode = pNode->GetTxtNode();
2633                     nPos = nIndex;
2634                 }
2635 			}
2636 		}
2637 		if( pTextNode )
2638 		{
2639 			if( bCheckAttr )
2640 			{
2641 				const SwpHints* pHts = pTextNode->GetpSwpHints();
2642 				const String& rTxt = pTextNode->GetTxt();
2643                 // dann teste doch mal, ob das wirklich nur Text im Node steht!
2644                 // Flys/Felder/..
2645                 if( pHts )
2646                 {
2647                     xub_StrLen nNextSetField = 0;
2648                     for( sal_uInt16 n = 0; n < pHts->Count(); ++n )
2649                     {
2650                         const SwTxtAttr* pAttr = (*pHts)[ n ];
2651                         if( RES_TXTATR_NOEND_BEGIN <= pAttr->Which() ||
2652                             *pAttr->GetStart() ||
2653                             *pAttr->GetAnyEnd() < rTxt.Len() )
2654                         {
2655                             if ( (*pAttr->GetStart() == nNextSetField)
2656                                  && (pAttr->Which() == RES_TXTATR_FIELD))
2657                             {
2658                                 // #i104949# hideous hack for report builder:
2659                                 // it inserts hidden variable-set fields at
2660                                 // the beginning of para in cell, but they
2661                                 // should not turn cell into text cell
2662                                 const SwField* pField = pAttr->GetFmtFld().GetField();
2663                                 if (pField &&
2664                                     (pField->GetTypeId() == TYP_SETFLD) &&
2665                                     (0 != (static_cast<SwSetExpField const*>
2666                                            (pField)->GetSubType() &
2667                                         nsSwExtendedSubType::SUB_INVISIBLE)))
2668                                 {
2669                                     nNextSetField = *pAttr->GetStart() + 1;
2670                                     continue;
2671                                 }
2672                             }
2673                             nPos = ULONG_MAX;
2674                             break;
2675                         }
2676                     }
2677                 }
2678 			}
2679 		}
2680         else
2681             nPos = ULONG_MAX;
2682 	}
2683 	return nPos;
2684 }
2685 
2686 // ist das eine FormelBox oder eine Box mit numerischen Inhalt (AutoSum)
IsFormulaOrValueBox() const2687 sal_uInt16 SwTableBox::IsFormulaOrValueBox() const
2688 {
2689 	sal_uInt16 nWhich = 0;
2690 	const SwTxtNode* pTNd;
2691 	SwFrmFmt* pFmt = GetFrmFmt();
2692 	if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMULA, sal_False ))
2693 		nWhich = RES_BOXATR_FORMULA;
2694 	else if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_False ) &&
2695 			!pFmt->GetDoc()->GetNumberFormatter()->IsTextFormat(
2696 				pFmt->GetTblBoxNumFmt().GetValue() ))
2697 		nWhich = RES_BOXATR_VALUE;
2698 	else if( pSttNd && pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex()
2699 			&& 0 != ( pTNd = pSttNd->GetNodes()[ pSttNd->GetIndex() + 1 ]
2700 			->GetTxtNode() ) && !pTNd->GetTxt().Len() )
2701 		nWhich = USHRT_MAX;
2702 
2703 	return nWhich;
2704 }
2705 
ActualiseValueBox()2706 void SwTableBox::ActualiseValueBox()
2707 {
2708 	const SfxPoolItem *pFmtItem, *pValItem;
2709 	SwFrmFmt* pFmt = GetFrmFmt();
2710 	if( SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_FORMAT, sal_True, &pFmtItem )
2711 		&& SFX_ITEM_SET == pFmt->GetItemState( RES_BOXATR_VALUE, sal_True, &pValItem ))
2712 	{
2713         const sal_uLong nFmtId = ((SwTblBoxNumFormat*)pFmtItem)->GetValue();
2714 		sal_uLong nNdPos = ULONG_MAX;
2715 		SvNumberFormatter* pNumFmtr = pFmt->GetDoc()->GetNumberFormatter();
2716 
2717 		if( !pNumFmtr->IsTextFormat( nFmtId ) &&
2718 			ULONG_MAX != (nNdPos = IsValidNumTxtNd( sal_True )) )
2719 		{
2720 			double fVal = ((SwTblBoxValue*)pValItem)->GetValue();
2721 			Color* pCol = 0;
2722 			String sNewTxt;
2723 			pNumFmtr->GetOutputString( fVal, nFmtId, sNewTxt, &pCol );
2724 
2725 			const String& rTxt = pSttNd->GetNodes()[ nNdPos ]->GetTxtNode()->GetTxt();
2726 			if( rTxt != sNewTxt )
2727 				ChgTextToNum( *this, sNewTxt, pCol, sal_False ,nNdPos);
2728 		}
2729 	}
2730 }
2731 
SetNewCol(Color ** ppCol,const Color * pNewCol)2732 void SwTableBox_Impl::SetNewCol( Color** ppCol, const Color* pNewCol )
2733 {
2734 	if( *ppCol != pNewCol )
2735 	{
2736 		delete *ppCol;
2737 		if( pNewCol )
2738 			*ppCol = new Color( *pNewCol );
2739 		else
2740 			*ppCol = 0;
2741 	}
2742 }
2743 
2744 struct SwTableCellInfo::Impl
2745 {
2746     const SwTable * m_pTable;
2747     const SwCellFrm * m_pCellFrm;
2748     const SwTabFrm * m_pTabFrm;
2749     typedef ::std::set<const SwTableBox *> TableBoxes_t;
2750     TableBoxes_t m_HandledTableBoxes;
2751 
2752 public:
ImplSwTableCellInfo::Impl2753     Impl()
2754         : m_pTable(NULL), m_pCellFrm(NULL), m_pTabFrm(NULL)
2755     {
2756     }
2757 
~ImplSwTableCellInfo::Impl2758     ~Impl() {}
2759 
setTableSwTableCellInfo::Impl2760     void setTable(const SwTable * pTable) {
2761         m_pTable = pTable;
2762         SwFrmFmt * pFrmFmt = m_pTable->GetFrmFmt();
2763         m_pTabFrm = SwIterator<SwTabFrm,SwFmt>::FirstElement(*pFrmFmt);
2764         if (m_pTabFrm->IsFollow())
2765             m_pTabFrm = m_pTabFrm->FindMaster(true);
2766     }
getTableSwTableCellInfo::Impl2767     const SwTable * getTable() const { return m_pTable; }
2768 
getCellFrmSwTableCellInfo::Impl2769     const SwCellFrm * getCellFrm() const { return m_pCellFrm; }
2770 
2771     const SwFrm * getNextFrmInTable(const SwFrm * pFrm);
2772     const SwCellFrm * getNextCellFrm(const SwFrm * pFrm);
2773     const SwCellFrm * getNextTableBoxsCellFrm(const SwFrm * pFrm);
2774     bool getNext();
2775 };
2776 
getNextFrmInTable(const SwFrm * pFrm)2777 const SwFrm * SwTableCellInfo::Impl::getNextFrmInTable(const SwFrm * pFrm)
2778 {
2779     const SwFrm * pResult = NULL;
2780 
2781     if (((! pFrm->IsTabFrm()) || pFrm == m_pTabFrm) && pFrm->GetLower())
2782         pResult = pFrm->GetLower();
2783     else if (pFrm->GetNext())
2784         pResult = pFrm->GetNext();
2785     else
2786     {
2787         while (pFrm->GetUpper() != NULL)
2788         {
2789             pFrm = pFrm->GetUpper();
2790 
2791             if (pFrm->IsTabFrm())
2792             {
2793                 m_pTabFrm = static_cast<const SwTabFrm *>(pFrm)->GetFollow();
2794                 pResult = m_pTabFrm;
2795                 break;
2796             }
2797             else if (pFrm->GetNext())
2798             {
2799                 pResult = pFrm->GetNext();
2800                 break;
2801             }
2802         }
2803     }
2804 
2805     return pResult;
2806 }
2807 
getNextCellFrm(const SwFrm * pFrm)2808 const SwCellFrm * SwTableCellInfo::Impl::getNextCellFrm(const SwFrm * pFrm)
2809 {
2810     const SwCellFrm * pResult = NULL;
2811 
2812     while ((pFrm = getNextFrmInTable(pFrm)) != NULL)
2813     {
2814         if (pFrm->IsCellFrm())
2815         {
2816             pResult = static_cast<const SwCellFrm *>(pFrm);
2817             break;
2818         }
2819     }
2820 
2821     return pResult;
2822 }
2823 
getNextTableBoxsCellFrm(const SwFrm * pFrm)2824 const SwCellFrm * SwTableCellInfo::Impl::getNextTableBoxsCellFrm(const SwFrm * pFrm)
2825 {
2826     const SwCellFrm * pResult = NULL;
2827 
2828     while ((pFrm = getNextCellFrm(pFrm)) != NULL)
2829     {
2830         const SwCellFrm * pCellFrm = static_cast<const SwCellFrm *>(pFrm);
2831         const SwTableBox * pTabBox = pCellFrm->GetTabBox();
2832         TableBoxes_t::const_iterator aIt = m_HandledTableBoxes.find(pTabBox);
2833 
2834         if (aIt == m_HandledTableBoxes.end())
2835         {
2836             pResult = pCellFrm;
2837             m_HandledTableBoxes.insert(pTabBox);
2838             break;
2839         }
2840     }
2841 
2842     return pResult;
2843 }
2844 
getCellFrm() const2845 const SwCellFrm * SwTableCellInfo::getCellFrm() const
2846 {
2847     return m_pImpl->getCellFrm();
2848 }
2849 
getNext()2850 bool SwTableCellInfo::Impl::getNext()
2851 {
2852     if (m_pCellFrm == NULL)
2853     {
2854         if (m_pTabFrm != NULL)
2855             m_pCellFrm = Impl::getNextTableBoxsCellFrm(m_pTabFrm);
2856     }
2857     else
2858         m_pCellFrm = Impl::getNextTableBoxsCellFrm(m_pCellFrm);
2859 
2860     return m_pCellFrm != NULL;
2861 }
2862 
SwTableCellInfo(const SwTable * pTable)2863 SwTableCellInfo::SwTableCellInfo(const SwTable * pTable)
2864 {
2865     m_pImpl.reset(new Impl());
2866     m_pImpl->setTable(pTable);
2867 }
2868 
~SwTableCellInfo()2869 SwTableCellInfo::~SwTableCellInfo()
2870 {
2871 }
2872 
getNext()2873 bool SwTableCellInfo::getNext()
2874 {
2875     return m_pImpl->getNext();
2876 }
2877 
getRect() const2878 SwRect SwTableCellInfo::getRect() const
2879 {
2880     SwRect aRet;
2881 
2882     if (getCellFrm() != NULL)
2883         aRet = getCellFrm()->Frm();
2884 
2885     return aRet;
2886 }
2887 
getTableBox() const2888 const SwTableBox * SwTableCellInfo::getTableBox() const
2889 {
2890     const SwTableBox * pRet = NULL;
2891 
2892     if (getCellFrm() != NULL)
2893         pRet = getCellFrm()->GetTabBox();
2894 
2895     return pRet;
2896 }
2897 
RegisterToFormat(SwFmt & rFmt)2898 void SwTable::RegisterToFormat( SwFmt& rFmt )
2899 {
2900     rFmt.Add( this );
2901 }
2902 
RegisterToFormat(SwFmt & rFmt)2903 void SwTableLine::RegisterToFormat( SwFmt& rFmt )
2904 {
2905     rFmt.Add( this );
2906 }
2907 
RegisterToFormat(SwFmt & rFmt)2908 void SwTableBox::RegisterToFormat( SwFmt& rFmt )
2909 {
2910     rFmt.Add( this );
2911 }
2912 
ForgetFrmFmt()2913 void SwTableBox::ForgetFrmFmt()
2914 {
2915     if ( GetRegisteredIn() )
2916         GetRegisteredInNonConst()->Remove(this);
2917 }
2918 
2919 
2920