xref: /aoo41x/main/sw/source/core/fields/cellfml.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <float.h>
33 #include <hintids.hxx>
34 #include <hints.hxx>
35 #include <fmtfld.hxx>
36 #include <txtfld.hxx>
37 #include <frmfmt.hxx>
38 #include <layfrm.hxx>
39 #include <cntfrm.hxx>
40 #include <tabfrm.hxx>
41 #include <doc.hxx>
42 #include <docary.hxx>
43 #include <ndtxt.hxx>
44 #include <swtable.hxx>
45 #include <tblsel.hxx>
46 #include <cellfml.hxx>
47 #include <calc.hxx>
48 #include <expfld.hxx>
49 #include <usrfld.hxx>
50 #include <flddat.hxx>
51 #include <cellatr.hxx>
52 #include <ndindex.hxx>
53 
54 const sal_Unicode cRelTrenner = ',';
55 const sal_Unicode cRelKennung = '';		// CTRL-R
56 
57 const sal_uInt16 cMAXSTACKSIZE = 50;
58 
59 const SwFrm* lcl_GetBoxFrm( const SwTableBox& rBox );
60 long lcl_GetLongBoxNum( String& rStr );
61 const SwTableBox* lcl_RelToBox( const SwTable&, const SwTableBox*, const String& );
62 String lcl_BoxNmToRel( const SwTable&, const SwTableNode&,
63 						const String& , const String& , sal_Bool );
64 
65 
66 /*************************************************************************
67 |*
68 |*	double SwTableBox::GetValue() const
69 |*		gebe den Wert dieser Box zurueck. Der Wert ergibt sich aus dem 1.
70 |*		TextNode. Beginnt dieser mit einer Zahl/Formel, so berechne diese;
71 |*		oder mit einem Feld, dann hole den Wert.
72 |*		Alle anderen Bedingungen returnen einen Fehler (oder 0 ?)
73 |*
74 |*	Ersterstellung		JP 30. Jun. 93
75 |*	Letzte Aenderung	JP 30. Jun. 93
76 |*
77 |*************************************************************************/
78 
79 double SwTableBox::GetValue( SwTblCalcPara& rCalcPara ) const
80 {
81 	double nRet = 0;
82 
83 	if( rCalcPara.rCalc.IsCalcError() )
84 		return nRet;			// schon ein Fehler in der Berechnung
85 
86 	rCalcPara.rCalc.SetCalcError( CALC_SYNTAX );	// default immer Fehler
87 
88 	// keine Content Box ?
89 	if( !pSttNd  )
90 		return nRet;
91 
92 	if( rCalcPara.IncStackCnt() )
93 		return nRet;
94 
95 	rCalcPara.SetLastTblBox( this );
96 
97 	// wird eine Rekursion erzeugt ?
98 	SwTableBox* pBox = (SwTableBox*)this;
99 	if( rCalcPara.pBoxStk->Seek_Entry( pBox ))
100 		return nRet;			// steht schon auf dem Stack: FEHLER
101 
102 	// bei dieser Box nochmal aufsetzen
103 	rCalcPara.SetLastTblBox( this );
104 
105 	rCalcPara.pBoxStk->Insert( pBox );		// eintragen
106 	do {		// Middle-Check-Loop, damit aus dieser gesprungen werden kann
107 				// hier aufgespannt, damit am Ende der Box-Pointer aus dem
108 				// Stack ausgetragen wird
109 		SwDoc* pDoc = GetFrmFmt()->GetDoc();
110 
111 		const SfxPoolItem* pItem;
112 		if( SFX_ITEM_SET == GetFrmFmt()->GetItemState(
113 								RES_BOXATR_FORMULA, sal_False, &pItem ) )
114 		{
115 			rCalcPara.rCalc.SetCalcError( CALC_NOERR );	// wieder zuruecksetzen
116 			if( !((SwTblBoxFormula*)pItem)->IsValid() )
117 			{
118 				// dann berechnen
119 				const SwTable* pTmp = rCalcPara.pTbl;
120 				rCalcPara.pTbl = &pBox->GetSttNd()->FindTableNode()->GetTable();
121 				((SwTblBoxFormula*)pItem)->Calc( rCalcPara, nRet );
122 
123 				if( !rCalcPara.IsStackOverFlow() )
124 				{
125 					SwFrmFmt* pFmt = pBox->ClaimFrmFmt();
126 					SfxItemSet aTmp( pDoc->GetAttrPool(),
127 										RES_BOXATR_BEGIN,RES_BOXATR_END-1 );
128 					aTmp.Put( SwTblBoxValue( nRet ) );
129 					if( SFX_ITEM_SET != pFmt->GetItemState( RES_BOXATR_FORMAT ))
130 						aTmp.Put( SwTblBoxNumFormat( 0 ));
131                     pFmt->SetFmtAttr( aTmp );
132 				}
133 				rCalcPara.pTbl = pTmp;
134 			}
135 			else
136 				nRet = GetFrmFmt()->GetTblBoxValue().GetValue();
137 			break;
138 		}
139 		else if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetItemState(
140 								RES_BOXATR_VALUE, sal_False, &pItem ) )
141 		{
142 			rCalcPara.rCalc.SetCalcError( CALC_NOERR );	// wieder zuruecksetzen
143 			nRet = ((SwTblBoxValue*)pItem)->GetValue();
144 			break;
145 		}
146 
147 		SwTxtNode* pTxtNd = pDoc->GetNodes()[ pSttNd->GetIndex() + 1 ]->GetTxtNode();
148 		if( !pTxtNd )
149 			break;
150 
151 		xub_StrLen nSttPos = 0;
152 		const String& rTxt = pTxtNd->GetTxt();
153 		while( nSttPos < rTxt.Len() &&
154 				( ' ' ==  rTxt.GetChar( nSttPos ) || '\t' ==  rTxt.GetChar( nSttPos ) ) )
155 			++nSttPos;
156 
157 		// beginnt an erster Position ein "RechenFeld", dann erfrage den Wert
158 		// von diesem
159         sal_Unicode const Char = rTxt.GetChar(nSttPos);
160         if ( nSttPos < rTxt.Len() &&
161              ( CH_TXTATR_BREAKWORD == Char || CH_TXTATR_INWORD == Char ) )
162         {
163 			SwIndex aIdx( pTxtNd, nSttPos );
164             SwTxtFld * const pTxtFld = static_cast<SwTxtFld*>(
165                 pTxtNd->GetTxtAttrForCharAt(aIdx.GetIndex(), RES_TXTATR_FIELD));
166 			if( !pTxtFld )
167 				break;
168 
169 			rCalcPara.rCalc.SetCalcError( CALC_NOERR );	// wieder zuruecksetzen
170 
171 			const SwField* pFld = pTxtFld->GetFld().GetFld();
172 			switch( pFld->GetTyp()->Which()  )
173 			{
174 			case RES_SETEXPFLD:
175 				nRet = ((SwSetExpField*)pFld)->GetValue();
176 				break;
177 			case RES_USERFLD:
178 				nRet = ((SwUserFieldType*)pFld)->GetValue();
179 				break;
180 			case RES_TABLEFLD:
181 				{
182 					SwTblField* pTblFld = (SwTblField*)pFld;
183 					if( !pTblFld->IsValid() )		// ist der Wert gueltig ??
184 					{
185 						// die richtige Tabelle mitgeben!
186 						const SwTable* pTmp = rCalcPara.pTbl;
187 						rCalcPara.pTbl = &pTxtNd->FindTableNode()->GetTable();
188 						pTblFld->CalcField( rCalcPara );
189 						rCalcPara.pTbl = pTmp;
190 					}
191 					nRet = pTblFld->GetValue();
192 				}
193 				break;
194 
195 			case RES_DATETIMEFLD:
196 				nRet = ((SwDateTimeField*)pFld)->GetValue();
197 				break;
198 
199 			case RES_JUMPEDITFLD:
200 				//JP 14.09.98: Bug 56112 - der Platzhalter kann nie einen
201 				//				gueltigen Inhalt haben!
202 				nRet = 0;
203 				break;
204 
205 			default:
206                 String const value(pFld->ExpandField(true));
207                 nRet = rCalcPara.rCalc.Calculate(value).GetDouble();
208 			}
209 		}
210 		else
211 		{
212 			// Ergebnis ist 0 und kein Fehler!
213 			rCalcPara.rCalc.SetCalcError( CALC_NOERR );	// wieder zuruecksetzen
214 
215 			double aNum;
216 			String sTxt( rTxt.Copy( nSttPos ) );
217 			sal_uInt32 nFmtIndex = GetFrmFmt()->GetTblBoxNumFmt().GetValue();
218 
219 			SvNumberFormatter* pNumFmtr = pDoc->GetNumberFormatter();
220 
221 			if( NUMBERFORMAT_TEXT == nFmtIndex )
222 				nFmtIndex = 0;
223 			// JP 22.04.98: Bug 49659 - Sonderbehandlung fuer Prozent
224 			else if( sTxt.Len() &&
225 					NUMBERFORMAT_PERCENT == pNumFmtr->GetType( nFmtIndex ))
226 			{
227 				sal_uInt32 nTmpFmt = 0;
228 				if( pNumFmtr->IsNumberFormat( sTxt, nTmpFmt, aNum ) &&
229 					NUMBERFORMAT_NUMBER == pNumFmtr->GetType( nTmpFmt ))
230 					sTxt += '%';
231 			}
232 
233 			if( pNumFmtr->IsNumberFormat( sTxt, nFmtIndex, aNum ))
234 				nRet = aNum;
235 		}
236 
237 // ?? sonst ist das ein Fehler
238 	} while( sal_False );
239 
240 	if( !rCalcPara.IsStackOverFlow() )
241 	{
242 		rCalcPara.pBoxStk->Remove( pBox );		// raus aus dem Stack
243 		rCalcPara.DecStackCnt();
244 	}
245 
246 	//JP 12.01.99: mit Fehlererkennung, Bug 60794
247 	if( DBL_MAX == nRet )
248 		rCalcPara.rCalc.SetCalcError( CALC_SYNTAX );	// Fehler setzen
249 
250 	return nRet;
251 }
252 
253 /*  */
254 
255 // Struktur, die zum TabelleRechnen benoetigt wird
256 
257 SwTblCalcPara::SwTblCalcPara( SwCalc& rCalculator, const SwTable& rTable )
258 	: pLastTblBox( 0 ), nStackCnt( 0 ), nMaxSize( cMAXSTACKSIZE ),
259 	rCalc( rCalculator ), pTbl( &rTable )
260 {
261 	pBoxStk = new SwTableSortBoxes;
262 }
263 
264 SwTblCalcPara::~SwTblCalcPara()
265 {
266 	delete pBoxStk;
267 }
268 
269 sal_Bool SwTblCalcPara::CalcWithStackOverflow()
270 {
271 	// falls ein StackUeberlauf erkannt wurde, sollte mit
272 	// der letzten Box noch mal aufgesetzt werden. Irgend
273 	// ein Weg sollte dann
274 	sal_uInt16 nSaveMaxSize = nMaxSize;
275 
276 	nMaxSize = cMAXSTACKSIZE - 5;
277 	sal_uInt16 nCnt = 0;
278 	SwTableBoxes aStackOverFlows;
279 	do {
280 		SwTableBox* pBox = (SwTableBox*)pLastTblBox;
281 		nStackCnt = 0;
282 		rCalc.SetCalcError( CALC_NOERR );
283 		aStackOverFlows.C40_INSERT( SwTableBox, pBox, nCnt++ );
284 
285 		pBoxStk->Remove( pBox );
286 		pBox->GetValue( *this );
287 	} while( IsStackOverFlow() );
288 
289 	nMaxSize = cMAXSTACKSIZE - 3;		// es muss mind. 1 Stufe tiefer gehen!
290 
291 	// falls Rekursionen erkannt wurden
292 	nStackCnt = 0;
293 	rCalc.SetCalcError( CALC_NOERR );
294 	pBoxStk->Remove( sal_uInt16(0), pBoxStk->Count() );
295 
296 	while( !rCalc.IsCalcError() && nCnt )
297 	{
298 		aStackOverFlows[ --nCnt ]->GetValue( *this );
299 		if( IsStackOverFlow() && !CalcWithStackOverflow() )
300 			break;
301 	}
302 
303 	nMaxSize = nSaveMaxSize;
304 	aStackOverFlows.Remove( 0, aStackOverFlows.Count() );
305 	return !rCalc.IsCalcError();
306 }
307 
308 /*  */
309 
310 SwTableFormula::SwTableFormula( const String& rFormel )
311 	: sFormel( rFormel )
312 {
313 	eNmType = EXTRNL_NAME;
314 	bValidValue = sal_False;
315 }
316 
317 SwTableFormula::~SwTableFormula()
318 {
319 }
320 
321 void SwTableFormula::_MakeFormel( const SwTable& rTbl, String& rNewStr,
322 					String& rFirstBox, String* pLastBox, void* pPara ) const
323 {
324 	SwTblCalcPara* pCalcPara = (SwTblCalcPara*)pPara;
325 	if( pCalcPara->rCalc.IsCalcError() )		// ist schon Fehler gesetzt ?
326 		return;
327 
328 	SwTableBox* pSttBox, *pEndBox = 0;
329 
330 	rFirstBox.Erase(0,1);		// Kennung fuer Box loeschen
331 	// ein Bereich in dieser Klammer ?
332 	if( pLastBox )
333 	{
334 		pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->ToInt64()));
335 
336 		// ist das ueberhaupt ein gueltiger Pointer ??
337 		if( !rTbl.GetTabSortBoxes().Seek_Entry( pEndBox ))
338 			pEndBox = 0;
339 		rFirstBox.Erase( 0, pLastBox->Len()+1 );
340 	}
341 	pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.ToInt64()));
342 	// ist das ueberhaupt ein gueltiger Pointer ??
343 	if( !rTbl.GetTabSortBoxes().Seek_Entry( pSttBox ))
344 		pSttBox = 0;
345 
346 	rNewStr += ' ';
347 	if( pEndBox && pSttBox )	// Bereich ?
348 	{
349 		// hole ueber das Layout alle "selectierten" Boxen und berechne
350 		// deren Werte
351 		SwSelBoxes aBoxes;
352 		GetBoxes( *pSttBox, *pEndBox, aBoxes );
353 
354 		rNewStr += '(';
355         bool bDelim = false;
356 		for( sal_uInt16 n = 0; n < aBoxes.Count() &&
357 						   !pCalcPara->rCalc.IsCalcError(); ++n )
358 		{
359 			const SwTableBox* pTblBox = aBoxes[n];
360             if ( pTblBox->getRowSpan() >= 1 )
361             {
362                 if( bDelim )
363     				rNewStr += cListDelim;
364                 bDelim = true;
365 			    rNewStr += pCalcPara->rCalc.GetStrResult(
366 				    		pTblBox->GetValue( *pCalcPara ), sal_False );
367             }
368 		}
369 		rNewStr += ')';
370 	}
371 	else if( pSttBox && !pLastBox )			// nur die StartBox ?
372     {
373 							//JP 12.01.99: und keine EndBox in der Formel!
374 		// Berechne den Wert der Box
375         if ( pSttBox->getRowSpan() >= 1 )
376         {
377 		    rNewStr += pCalcPara->rCalc.GetStrResult(
378 							pSttBox->GetValue( *pCalcPara ), sal_False );
379         }
380     }
381 	else
382 		pCalcPara->rCalc.SetCalcError( CALC_SYNTAX );	// Fehler setzen
383 	rNewStr += ' ';
384 }
385 
386 void SwTableFormula::RelNmsToBoxNms( const SwTable& rTbl, String& rNewStr,
387 			String& rFirstBox, String* pLastBox, void* pPara ) const
388 {
389 	// relativen Namen zu Box-Namen (externe Darstellung)
390 	SwNode* pNd = (SwNode*)pPara;
391 	ASSERT( pNd, "Feld steht in keinem TextNode" );
392 	const SwTableBox *pRelBox, *pBox = (SwTableBox *)rTbl.GetTblBox(
393 					pNd->FindTableBoxStartNode()->GetIndex() );
394 
395 	rNewStr += rFirstBox.Copy(0,1);		// Kennung fuer Box erhalten
396 	rFirstBox.Erase(0,1);
397 	if( pLastBox )
398 	{
399 		if( 0 != ( pRelBox = lcl_RelToBox( rTbl, pBox, *pLastBox )) )
400 			rNewStr += pRelBox->GetName();
401 		else
402 			rNewStr.AppendAscii("A1");
403 		rNewStr += ':';
404 		rFirstBox.Erase( 0, pLastBox->Len()+1 );
405 	}
406 
407 	if( 0 != ( pRelBox = lcl_RelToBox( rTbl, pBox, rFirstBox )) )
408 		rNewStr += pRelBox->GetName();
409 	else
410 		rNewStr.AppendAscii("A1");
411 
412 	// Kennung fuer Box erhalten
413 	rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 );
414 }
415 
416 void SwTableFormula::RelBoxNmsToPtr( const SwTable& rTbl, String& rNewStr,
417 			String& rFirstBox, String* pLastBox, void* pPara ) const
418 {
419 	// relativen Namen zu Box-Pointern (interne Darstellung)
420 	SwNode* pNd = (SwNode*)pPara;
421 	ASSERT( pNd, "Feld steht in keinem Node" );
422 	const SwTableBox *pRelBox, *pBox = (SwTableBox*)rTbl.GetTblBox(
423 					pNd->FindTableBoxStartNode()->GetIndex() );
424 
425 	rNewStr += rFirstBox.Copy(0,1);		// Kennung fuer Box erhalten
426 	rFirstBox.Erase(0,1);
427 	if( pLastBox )
428 	{
429 		if( 0 != ( pRelBox = lcl_RelToBox( rTbl, pBox, *pLastBox )) )
430 			rNewStr += String::CreateFromInt64( (sal_PtrDiff)pRelBox );
431 		else
432 			rNewStr += '0';
433 		rNewStr += ':';
434 		rFirstBox.Erase( 0, pLastBox->Len()+1 );
435 	}
436 
437 	if( 0 != ( pRelBox = lcl_RelToBox( rTbl, pBox, rFirstBox )) )
438 		rNewStr += String::CreateFromInt64( (sal_PtrDiff)pRelBox );
439 	else
440 		rNewStr += '0';
441 
442 	// Kennung fuer Box erhalten
443 	rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 );
444 }
445 
446 
447 void SwTableFormula::BoxNmsToRelNm( const SwTable& rTbl, String& rNewStr,
448 					String& rFirstBox, String* pLastBox, void* pPara ) const
449 {
450 	// Box-Namen (externe Darstellung) zu relativen Namen
451 	SwNode* pNd = (SwNode*)pPara;
452 	ASSERT( pNd, "Feld steht in keinem Node" );
453 	const SwTableNode* pTblNd = pNd->FindTableNode();
454 
455 	String sRefBoxNm;
456 	if( &pTblNd->GetTable() == &rTbl )
457 	{
458 		const SwTableBox *pBox = rTbl.GetTblBox(
459 				pNd->FindTableBoxStartNode()->GetIndex() );
460 		ASSERT( pBox, "Feld steht in keiner Tabelle" );
461 		sRefBoxNm = pBox->GetName();
462 	}
463 
464 	rNewStr += rFirstBox.Copy(0,1);		// Kennung fuer Box erhalten
465 	rFirstBox.Erase(0,1);
466 	if( pLastBox )
467 	{
468 		rNewStr += lcl_BoxNmToRel( rTbl, *pTblNd, sRefBoxNm, *pLastBox,
469 								eNmType == EXTRNL_NAME );
470 		rNewStr += ':';
471 		rFirstBox.Erase( 0, pLastBox->Len()+1 );
472 	}
473 
474 	rNewStr += lcl_BoxNmToRel( rTbl, *pTblNd, sRefBoxNm, rFirstBox,
475 							eNmType == EXTRNL_NAME );
476 
477 	// Kennung fuer Box erhalten
478 	rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 );
479 }
480 
481 
482 void SwTableFormula::PtrToBoxNms( const SwTable& rTbl, String& rNewStr,
483 						String& rFirstBox, String* pLastBox, void* ) const
484 {
485 	// ein Bereich in dieser Klammer ?
486 	SwTableBox* pBox;
487 
488 	rNewStr += rFirstBox.Copy(0,1);		// Kennung fuer Box erhalten
489 	rFirstBox.Erase(0,1);
490 	if( pLastBox )
491 	{
492 		pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->ToInt64()));
493 
494 		// ist das ueberhaupt ein gueltiger Pointer ??
495 		if( rTbl.GetTabSortBoxes().Seek_Entry( pBox ))
496 			rNewStr += pBox->GetName();
497 		else
498 			rNewStr += '?';
499 		rNewStr += ':';
500 		rFirstBox.Erase( 0, pLastBox->Len()+1 );
501 	}
502 
503 	pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.ToInt64()));
504 	// ist das ueberhaupt ein gueltiger Pointer ??
505 	if( rTbl.GetTabSortBoxes().Seek_Entry( pBox ))
506 		rNewStr += pBox->GetName();
507 	else
508 		rNewStr += '?';
509 
510 	// Kennung fuer Box erhalten
511 	rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 );
512 }
513 
514 void SwTableFormula::BoxNmsToPtr( const SwTable& rTbl, String& rNewStr,
515 						String& rFirstBox, String* pLastBox, void* ) const
516 {
517 	// ein Bereich in dieser Klammer ?
518 	const SwTableBox* pBox;
519 
520 	rNewStr += rFirstBox.Copy(0,1);		// Kennung fuer Box erhalten
521 	rFirstBox.Erase(0,1);
522 	if( pLastBox )
523 	{
524 		pBox = rTbl.GetTblBox( *pLastBox );
525 		rNewStr += String::CreateFromInt64( (sal_PtrDiff)pBox );
526 		rNewStr += ':';
527 		rFirstBox.Erase( 0, pLastBox->Len()+1 );
528 	}
529 
530 	pBox = rTbl.GetTblBox( rFirstBox );
531 	rNewStr += String::CreateFromInt64( (sal_PtrDiff)pBox );
532 
533 	// Kennung fuer Box erhalten
534 	rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 );
535 }
536 
537 	// erzeuge die externe (fuer UI) Formel
538 void SwTableFormula::PtrToBoxNm( const SwTable* pTbl )
539 {
540 	const SwNode* pNd = 0;
541 	FnScanFormel fnFormel = 0;
542 	switch( eNmType)
543 	{
544 	case INTRNL_NAME:
545 		if( pTbl )
546 			fnFormel = &SwTableFormula::PtrToBoxNms;
547 		break;
548 	case REL_NAME:
549 		if( pTbl )
550 		{
551 			fnFormel = &SwTableFormula::RelNmsToBoxNms;
552 			pNd = GetNodeOfFormula();
553 		}
554 		break;
555 	case EXTRNL_NAME:
556 		return;
557 	}
558 	sFormel = ScanString( fnFormel, *pTbl, (void*)pNd );
559 	eNmType = EXTRNL_NAME;
560 }
561 
562 	// erzeuge die interne (in CORE) Formel
563 void SwTableFormula::BoxNmToPtr( const SwTable* pTbl )
564 {
565 	const SwNode* pNd = 0;
566 	FnScanFormel fnFormel = 0;
567 	switch( eNmType)
568 	{
569 	case EXTRNL_NAME:
570 		if( pTbl )
571 			fnFormel = &SwTableFormula::BoxNmsToPtr;
572 		break;
573 	case REL_NAME:
574 		if( pTbl )
575 		{
576 			fnFormel = &SwTableFormula::RelBoxNmsToPtr;
577 			pNd = GetNodeOfFormula();
578 		}
579 		break;
580 	case INTRNL_NAME:
581 		return;
582 	}
583 	sFormel = ScanString( fnFormel, *pTbl, (void*)pNd );
584 	eNmType = INTRNL_NAME;
585 }
586 
587 	// erzeuge die relative (fuers Kopieren) Formel
588 void SwTableFormula::ToRelBoxNm( const SwTable* pTbl )
589 {
590 	const SwNode* pNd = 0;
591 	FnScanFormel fnFormel = 0;
592 	switch( eNmType)
593 	{
594 	case INTRNL_NAME:
595 	case EXTRNL_NAME:
596 		if( pTbl )
597 		{
598 			fnFormel = &SwTableFormula::BoxNmsToRelNm;
599 			pNd = GetNodeOfFormula();
600 		}
601 		break;
602 	case REL_NAME:
603 		return;
604 	}
605 	sFormel = ScanString( fnFormel, *pTbl, (void*)pNd );
606 	eNmType = REL_NAME;
607 }
608 
609 
610 String SwTableFormula::ScanString( FnScanFormel fnFormel, const SwTable& rTbl,
611 									void* pPara ) const
612 {
613 	String aStr;
614 	sal_uInt16 nFml = 0, nStt = 0, nEnd = 0, nTrenner;
615 
616 	do {
617 		// falls der Formel ein Name vorangestellt ist, diese Tabelle
618 		// benutzen !!
619 		const SwTable* pTbl = &rTbl;
620 
621 		nStt = sFormel.Search( '<', nFml );
622 		if( STRING_NOTFOUND != nStt )
623 		{
624 			while( STRING_NOTFOUND != nStt &&
625 				( ' ' == sFormel.GetChar( nStt + 1 ) ||
626 				  '=' == sFormel.GetChar( nStt + 1 ) ) )
627 				nStt = sFormel.Search( '<', nStt + 1 );
628 
629 			if( STRING_NOTFOUND != nStt )
630 				nEnd = sFormel.Search( '>', nStt+1 );
631 		}
632 		if( STRING_NOTFOUND == nStt || STRING_NOTFOUND == nEnd )
633 		{
634 			// den Rest setzen und beenden
635 			aStr.Insert( sFormel, nFml, sFormel.Len() - nFml );
636 			break;
637 		}
638 		aStr.Insert( sFormel, nFml, nStt - nFml );	// Anfang schreiben
639 
640 		if( fnFormel != NULL )
641 		{
642 			// ist ein TabellenName vorangestellt ??
643 			// JP 16.02.99: SplitMergeBoxNm behandeln den Namen selbst
644 			// JP 22.02.99: der CAST muss fuer den Linux-Compiler sein
645 			// JP 28.06.99: rel. BoxName have no preceding tablename!
646 			if( fnFormel != (FnScanFormel)&SwTableFormula::_SplitMergeBoxNm &&
647 				1 < sFormel.Len() && cRelKennung != sFormel.GetChar( 1 ) &&
648 				STRING_NOTFOUND != ( nTrenner = sFormel.Search( '.', nStt ))
649 				&& nTrenner < nEnd )
650 			{
651 				String sTblNm( sFormel.Copy( nStt, nEnd - nStt ));
652 
653 				// falls im Namen schon die Punkte enthalten sind,
654 				// treten diese immer paarig auf!!! (A1.1.1 !!)
655 				if( (sTblNm.GetTokenCount( '.' ) - 1 ) & 1 )
656 				{
657 					sTblNm.Erase( nTrenner - nStt );
658 
659 					// beim Bauen der Formel ist der TabellenName unerwuenscht
660 					//JP 22.02.99: der CAST muss fuer den Linux-Compiler sein
661 					if( fnFormel != (FnScanFormel)&SwTableFormula::_MakeFormel )
662 						aStr += sTblNm;
663 					nStt = nTrenner;
664 
665 					sTblNm.Erase( 0, 1 );	// Trenner loeschen
666 					if( sTblNm != rTbl.GetFrmFmt()->GetName() )
667 					{
668 						// dann suchen wir uns mal unsere Tabelle:
669 						const SwTable* pFnd = FindTable(
670 												*rTbl.GetFrmFmt()->GetDoc(),
671 												sTblNm );
672 						if( pFnd )
673 							pTbl = pFnd;
674 						// ??
675 						ASSERT( pFnd, "Tabelle nicht gefunden, was nun?" );
676 					}
677 				}
678 			}
679 
680 			String sBox( sFormel.Copy( nStt, nEnd - nStt + 1 ));
681 			// ein Bereich in dieser Klammer ?
682 			if( STRING_NOTFOUND != ( nTrenner = sFormel.Search( ':', nStt ))
683 				&& nTrenner < nEnd )
684 			{
685 				// ohne die Anfangsklammer
686 				String aFirstBox( sFormel.Copy( nStt+1, nTrenner - nStt - 1 ));
687 				(this->*fnFormel)( *pTbl, aStr, sBox, &aFirstBox, pPara );
688 			}
689 			else
690 				(this->*fnFormel)( *pTbl, aStr, sBox, 0, pPara );
691 		}
692 
693 		nFml = nEnd+1;
694 	} while( sal_True );
695 	return aStr;
696 }
697 
698 const SwTable* SwTableFormula::FindTable( SwDoc& rDoc, const String& rNm ) const
699 {
700 	const SwFrmFmts& rTblFmts = *rDoc.GetTblFrmFmts();
701 	const SwTable* pTmpTbl, *pRet = 0;
702 	for( sal_uInt16 nFmtCnt = rTblFmts.Count(); nFmtCnt; )
703 	{
704 		SwFrmFmt* pFmt = rTblFmts[ --nFmtCnt ];
705 		// falls wir von Sw3Writer gerufen werden, dann ist dem
706 		// FormatNamen eine Nummer anhaengig
707 		SwTableBox* pFBox;
708 		if( COMPARE_EQUAL == rNm.CompareTo( pFmt->GetName(),
709 										pFmt->GetName().Search( 0x0a ) ) &&
710 			0 != ( pTmpTbl = SwTable::FindTable( pFmt ) ) &&
711 			0 != (pFBox = pTmpTbl->GetTabSortBoxes()[0] ) &&
712 			pFBox->GetSttNd() &&
713 			pFBox->GetSttNd()->GetNodes().IsDocNodes() )
714 		{
715 			// eine Tabelle im normalen NodesArr
716 			pRet = pTmpTbl;
717 			break;
718 		}
719 	}
720 	return pRet;
721 }
722 
723 const SwFrm* lcl_GetBoxFrm( const SwTableBox& rBox )
724 {
725 	SwNodeIndex aIdx( *rBox.GetSttNd() );
726 	SwCntntNode* pCNd = aIdx.GetNodes().GoNext( &aIdx );
727 	ASSERT( pCNd, "Box hat keinen TextNode" );
728 	Point aPt;		// den im Layout 1. Frame returnen - Tab.Kopfzeile !!
729 	return pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aPt, NULL, sal_False );
730 }
731 
732 long lcl_GetLongBoxNum( String& rStr )
733 {
734 	sal_uInt16 nPos;
735 	long nRet;
736 	if( STRING_NOTFOUND == ( nPos = rStr.Search( cRelTrenner ) ))
737 	{
738 		nRet = rStr.ToInt32();
739 		rStr.Erase();
740 	}
741 	else
742 	{
743 		nRet = rStr.Copy( 0, nPos ).ToInt32();
744 		rStr.Erase( 0, nPos+1 );
745 	}
746 	return nRet;
747 }
748 
749 const SwTableBox* lcl_RelToBox( const SwTable& rTbl,
750 									const SwTableBox* pRefBox,
751 									const String& rGetName )
752 {
753 	// hole die Line
754 	const SwTableBox* pBox = 0;
755 	String sGetName( rGetName );
756 
757 	// ist es denn wirklich eine relative Angabe??
758 	if( cRelKennung == sGetName.GetChar(0) )			// ja, ...
759 	{
760 		if( !pRefBox )
761 			return 0;
762 
763 		sGetName.Erase( 0, 1 );
764 
765 		const SwTableLines* pLines = (SwTableLines*)&rTbl.GetTabLines();
766 		const SwTableBoxes* pBoxes;
767 		const SwTableLine* pLine;
768 
769 		// bestimme erst mal die Start-Werte der Box:
770 		pBox = (SwTableBox*)pRefBox;
771 		pLine = pBox->GetUpper();
772 		while( pLine->GetUpper() )
773 		{
774 			pBox = pLine->GetUpper();
775 			pLine = pBox->GetUpper();
776 		}
777 		sal_uInt16 nSttBox = pLine->GetTabBoxes().GetPos( pBox );
778 		sal_uInt16 nSttLine = rTbl.GetTabLines().GetPos( pLine );
779 
780 		long nBoxOffset = lcl_GetLongBoxNum( sGetName ) + nSttBox;
781 		long nLineOffset = lcl_GetLongBoxNum( sGetName ) + nSttLine;
782 
783 		if( nBoxOffset < 0 || nBoxOffset >= USHRT_MAX ||
784 			nLineOffset < 0 || nLineOffset >= USHRT_MAX )
785 			return 0;
786 
787 		if( nLineOffset >= long(pLines->Count()) )
788 			return 0;
789 
790 		pLine = (*pLines)[ sal_uInt16(nLineOffset) ];
791 
792 		// dann suche die Box
793 		pBoxes = &pLine->GetTabBoxes();
794 		if( nBoxOffset >= long(pBoxes->Count()) )
795 			return 0;
796 		pBox = (*pBoxes)[ sal_uInt16(nBoxOffset) ];
797 
798 		while( sGetName.Len() )
799 		{
800 			nSttBox = SwTable::_GetBoxNum( sGetName );
801 			pLines = &pBox->GetTabLines();
802 			if( nSttBox )
803 				--nSttBox;
804 
805 			nSttLine = SwTable::_GetBoxNum( sGetName );
806 
807 			// bestimme die Line
808 			if( !nSttLine || nSttLine > pLines->Count() )
809 				break;
810 			pLine = (*pLines)[ nSttLine-1 ];
811 
812 			// bestimme die Box
813 			pBoxes = &pLine->GetTabBoxes();
814 			if( nSttBox >= pBoxes->Count() )
815 				break;
816 			pBox = (*pBoxes)[ nSttBox ];
817 		}
818 
819 		if( pBox )
820 		{
821 			if( !pBox->GetSttNd() )
822 				// "herunterfallen lassen" bis zur ersten Box
823 				while( pBox->GetTabLines().Count() )
824 					pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
825 		}
826 	}
827 	else
828 	{
829 		// sonst ist es eine absolute externe Darstellung:
830 		pBox = rTbl.GetTblBox( sGetName );
831 	}
832 	return pBox;
833 }
834 
835 String lcl_BoxNmToRel( const SwTable& rTbl, const SwTableNode& rTblNd,
836 							const String& rRefBoxNm, const String& rGetStr,
837 							sal_Bool bExtrnlNm )
838 {
839 	String sCpy( rRefBoxNm );
840 	String sTmp( rGetStr );
841 	if( !bExtrnlNm )
842 	{
843 		// in die Externe Darstellung umwandeln.
844 		SwTableBox* pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(sTmp.ToInt64()));
845 		if( !rTbl.GetTabSortBoxes().Seek_Entry( pBox ))
846 			return '?';
847 		sTmp = pBox->GetName();
848 	}
849 
850 	// sollte die es eine Tabellen uebergreifende Formel sein, dann behalte
851 	// die externe Darstellung bei:
852 	if( &rTbl == &rTblNd.GetTable() )
853 	{
854 		long nBox = SwTable::_GetBoxNum( sTmp, sal_True );
855 		nBox -= SwTable::_GetBoxNum( sCpy, sal_True );
856 		long nLine = SwTable::_GetBoxNum( sTmp );
857 		nLine -= SwTable::_GetBoxNum( sCpy );
858 
859 		sCpy = sTmp;		//JP 01.11.95: den Rest aus dem BoxNamen anhaengen
860 
861 		sTmp = cRelKennung;
862 		sTmp += String::CreateFromInt32( nBox );
863 		sTmp += cRelTrenner;
864 		sTmp += String::CreateFromInt32( nLine );
865 
866 		if( sCpy.Len() )
867 		{
868 			sTmp += cRelTrenner;
869 			sTmp += sCpy;
870 		}
871 	}
872 
873 	if( sTmp.Len() && '>' == sTmp.GetChar( sTmp.Len() - 1 ))
874 		sTmp.Erase( sTmp.Len()-1 );
875 
876 	return sTmp;
877 }
878 
879 sal_uInt16 SwTableFormula::GetBoxesOfFormula( const SwTable& rTbl,
880 										SwSelBoxes& rBoxes )
881 {
882 	if( rBoxes.Count() )
883 		rBoxes.Remove( sal_uInt16(0), rBoxes.Count() );
884 
885 	BoxNmToPtr( &rTbl );
886 	ScanString( &SwTableFormula::_GetFmlBoxes, rTbl, &rBoxes );
887 	return rBoxes.Count();
888 }
889 
890 void SwTableFormula::_GetFmlBoxes( const SwTable& rTbl, String& ,
891 					String& rFirstBox, String* pLastBox, void* pPara ) const
892 {
893 	SwSelBoxes* pBoxes = (SwSelBoxes*)pPara;
894 	SwTableBox* pSttBox, *pEndBox = 0;
895 
896 	rFirstBox.Erase(0,1);		// Kennung fuer Box loeschen
897 	// ein Bereich in dieser Klammer ?
898 	if( pLastBox )
899 	{
900 		pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->ToInt64()));
901 
902 		// ist das ueberhaupt ein gueltiger Pointer ??
903 		if( !rTbl.GetTabSortBoxes().Seek_Entry( pEndBox ))
904 			pEndBox = 0;
905 		rFirstBox.Erase( 0, pLastBox->Len()+1 );
906 	}
907 
908 	pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.ToInt64()));
909 	// ist das ueberhaupt ein gueltiger Pointer ??
910 	if( !rTbl.GetTabSortBoxes().Seek_Entry( pSttBox ))
911 		pSttBox = 0;
912 
913 	if( pEndBox && pSttBox )	// Bereich ?
914 	{
915 		// ueber das Layout alle "selectierten" Boxen und berechne
916 		// deren Werte
917 		SwSelBoxes aBoxes;
918 		GetBoxes( *pSttBox, *pEndBox, aBoxes );
919 		pBoxes->Insert( &aBoxes );
920 	}
921 	else if( pSttBox )			// nur die StartBox ?
922 		pBoxes->Insert( pSttBox );
923 }
924 
925 void SwTableFormula::GetBoxes( const SwTableBox& rSttBox,
926 								const SwTableBox& rEndBox,
927 								SwSelBoxes& rBoxes ) const
928 {
929 	// hole ueber das Layout alle "selektierten" Boxen
930 	const SwLayoutFrm *pStt, *pEnd;
931 	const SwFrm* pFrm = lcl_GetBoxFrm( rSttBox );
932 	pStt = pFrm ? pFrm->GetUpper() : 0;
933 	pEnd = ( 0 != (pFrm = lcl_GetBoxFrm( rEndBox ))) ? pFrm->GetUpper() : 0;
934 	if( !pStt || !pEnd )
935 		return ;			            // no valid selection
936 
937     GetTblSel( pStt, pEnd, rBoxes, 0 );
938 
939 	const SwTable* pTbl = pStt->FindTabFrm()->GetTable();
940 
941 	// filter die Kopfzeilen-Boxen heraus:
942     if( pTbl->GetRowsToRepeat() > 0 )
943     {
944 		do {	// middle-check loop
945             const SwTableLine* pLine = rSttBox.GetUpper();
946 			while( pLine->GetUpper() )
947 				pLine = pLine->GetUpper()->GetUpper();
948 
949             if( pTbl->IsHeadline( *pLine ) )
950                 break;      // Headline mit im Bereich !
951 
952             // vielleicht ist ja Start und Ende vertauscht
953 			pLine = rEndBox.GetUpper();
954 			while ( pLine->GetUpper() )
955 				pLine = pLine->GetUpper()->GetUpper();
956 
957             if( pTbl->IsHeadline( *pLine ) )
958 				break;		// Headline mit im Bereich !
959 
960 			const SwTabFrm *pTable = pStt->FindTabFrm();
961 			const SwTabFrm *pEndTable = pEnd->FindTabFrm();
962 
963             if( pTable == pEndTable )       // keine gespl. Tabelle
964 				break;
965 
966 			// dann mal die Tabellenkoepfe raus:
967 			for( sal_uInt16 n = 0; n < rBoxes.Count(); ++n )
968 			{
969                 pLine = rBoxes[n]->GetUpper();
970 				while( pLine->GetUpper() )
971 					pLine = pLine->GetUpper()->GetUpper();
972 
973                 if( pTbl->IsHeadline( *pLine ) )
974 					rBoxes.Remove( n--, 1 );
975 			}
976 		} while( sal_False );
977     }
978 }
979 
980 	// sind alle Boxen gueltig, auf die sich die Formel bezieht?
981 void SwTableFormula::_HasValidBoxes( const SwTable& rTbl, String& ,
982 					String& rFirstBox, String* pLastBox, void* pPara ) const
983 {
984 	sal_Bool* pBValid = (sal_Bool*)pPara;
985 	if( *pBValid )		// einmal falsch, immer falsch
986 	{
987 		SwTableBox* pSttBox = 0, *pEndBox = 0;
988 		rFirstBox.Erase(0,1);		// Kennung fuer Box loeschen
989 
990 		// ein Bereich in dieser Klammer ?
991 		if( pLastBox )
992 			rFirstBox.Erase( 0, pLastBox->Len()+1 );
993 
994 		switch( eNmType)
995 		{
996 		case INTRNL_NAME:
997 			if( pLastBox )
998 				pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->ToInt64()));
999 			pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.ToInt64()));
1000 			break;
1001 
1002 		case REL_NAME:
1003 			{
1004 				const SwNode* pNd = GetNodeOfFormula();
1005 				const SwTableBox* pBox = !pNd ? 0
1006 											   : (SwTableBox *)rTbl.GetTblBox(
1007 									pNd->FindTableBoxStartNode()->GetIndex() );
1008 				if( pLastBox )
1009 					pEndBox = (SwTableBox*)lcl_RelToBox( rTbl, pBox, *pLastBox );
1010 				pSttBox = (SwTableBox*)lcl_RelToBox( rTbl, pBox, rFirstBox );
1011 			}
1012 			break;
1013 
1014 		case EXTRNL_NAME:
1015 			if( pLastBox )
1016 				pEndBox = (SwTableBox*)rTbl.GetTblBox( *pLastBox );
1017 			pSttBox = (SwTableBox*)rTbl.GetTblBox( rFirstBox );
1018 			break;
1019 		}
1020 
1021 		// sind das gueltige Pointer ?
1022 		if( ( pLastBox &&
1023 			  ( !pEndBox || !rTbl.GetTabSortBoxes().Seek_Entry( pEndBox ) ) ) ||
1024 			( !pSttBox || !rTbl.GetTabSortBoxes().Seek_Entry( pSttBox ) ) )
1025 				*pBValid = sal_False;
1026 	}
1027 }
1028 
1029 sal_Bool SwTableFormula::HasValidBoxes() const
1030 {
1031 	sal_Bool bRet = sal_True;
1032 	const SwNode* pNd = GetNodeOfFormula();
1033 	if( pNd && 0 != ( pNd = pNd->FindTableNode() ) )
1034 		ScanString( &SwTableFormula::_HasValidBoxes,
1035 						((SwTableNode*)pNd)->GetTable(), &bRet );
1036 	return bRet;
1037 }
1038 
1039 
1040 sal_uInt16 SwTableFormula::GetLnPosInTbl( const SwTable& rTbl, const SwTableBox* pBox )
1041 {
1042 	sal_uInt16 nRet = USHRT_MAX;
1043 	if( pBox )
1044 	{
1045 		const SwTableLine* pLn = pBox->GetUpper();
1046 		while( pLn->GetUpper() )
1047 			pLn = pLn->GetUpper()->GetUpper();
1048 		nRet = rTbl.GetTabLines().GetPos( pLn );
1049 	}
1050 	return nRet;
1051 }
1052 
1053 void SwTableFormula::_SplitMergeBoxNm( const SwTable& rTbl, String& rNewStr,
1054 					String& rFirstBox, String* pLastBox, void* pPara ) const
1055 {
1056 	SwTableFmlUpdate& rTblUpd = *(SwTableFmlUpdate*)pPara;
1057 
1058 	rNewStr += rFirstBox.Copy(0,1);		// Kennung fuer Box erhalten
1059 	rFirstBox.Erase(0,1);
1060 
1061 	String sTblNm;
1062 	const SwTable* pTbl = &rTbl;
1063 
1064 	String* pTblNmBox = pLastBox ? pLastBox : &rFirstBox;
1065 
1066 	sal_uInt16 nLastBoxLen = pTblNmBox->Len();
1067 	sal_uInt16 nTrenner = pTblNmBox->Search( '.' );
1068 	if( STRING_NOTFOUND != nTrenner &&
1069 		// falls im Namen schon die Punkte enthalten sind,
1070 		// treten diese immer paarig auf!!! (A1.1.1 !!)
1071 		(pTblNmBox->GetTokenCount( '.' ) - 1 ) & 1 )
1072 	{
1073 		sTblNm = pTblNmBox->Copy( 0, nTrenner );
1074 		pTblNmBox->Erase( 0, nTrenner + 1);// den Punkt entfernen
1075 		const SwTable* pFnd = FindTable( *rTbl.GetFrmFmt()->GetDoc(), sTblNm );
1076 		if( pFnd )
1077 			pTbl = pFnd;
1078 
1079 		if( TBL_MERGETBL == rTblUpd.eFlags )
1080 		{
1081 			if( pFnd )
1082 			{
1083 				if( pFnd == rTblUpd.DATA.pDelTbl )
1084 				{
1085 					if( rTblUpd.pTbl != &rTbl )			// es ist nicht die akt.
1086 						(rNewStr += rTblUpd.pTbl->GetFrmFmt()->GetName() )
1087 							+= '.';	// den neuen Tabellen Namen setzen
1088 					rTblUpd.bModified = sal_True;
1089 				}
1090 				else if( pFnd != rTblUpd.pTbl ||
1091 					( rTblUpd.pTbl != &rTbl && &rTbl != rTblUpd.DATA.pDelTbl))
1092 					(rNewStr += sTblNm ) += '.';	// den Tabellen Namen behalten
1093 				else
1094 					rTblUpd.bModified = sal_True;
1095 			}
1096 			else
1097 				(rNewStr += sTblNm ) += '.';	// den Tabellen Namen behalten
1098 
1099 		}
1100 	}
1101 	if( pTblNmBox == pLastBox )
1102 		rFirstBox.Erase( 0, nLastBoxLen + 1 );
1103 
1104 	SwTableBox* pSttBox = 0, *pEndBox = 0;
1105 	switch( eNmType )
1106 	{
1107 	case INTRNL_NAME:
1108 		if( pLastBox )
1109 			pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->ToInt64()));
1110 		pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.ToInt64()));
1111 		break;
1112 
1113 	case REL_NAME:
1114 		{
1115 			const SwNode* pNd = GetNodeOfFormula();
1116 			const SwTableBox* pBox = pNd ? pTbl->GetTblBox(
1117 							pNd->FindTableBoxStartNode()->GetIndex() ) : 0;
1118 			if( pLastBox )
1119 				pEndBox = (SwTableBox*)lcl_RelToBox( *pTbl, pBox, *pLastBox );
1120 			pSttBox = (SwTableBox*)lcl_RelToBox( *pTbl, pBox, rFirstBox );
1121 		}
1122 		break;
1123 
1124 	case EXTRNL_NAME:
1125 		if( pLastBox )
1126 			pEndBox = (SwTableBox*)pTbl->GetTblBox( *pLastBox );
1127 		pSttBox = (SwTableBox*)pTbl->GetTblBox( rFirstBox );
1128 		break;
1129 	}
1130 
1131 	if( pLastBox && !pTbl->GetTabSortBoxes().Seek_Entry( pEndBox ))
1132 		pEndBox = 0;
1133 	if( !pTbl->GetTabSortBoxes().Seek_Entry( pSttBox ))
1134 		pSttBox = 0;
1135 
1136 	if( TBL_SPLITTBL == rTblUpd.eFlags )
1137 	{
1138 		// wo liegen die Boxen, in der "alten" oder in der neuen Tabelle?
1139 		sal_Bool bInNewTbl = sal_False;
1140 		if( pLastBox )
1141 		{
1142 			// das ist die "erste" Box in der Selektion. Die bestimmt ob die
1143 			// Formel in der alten oder neuen Tabelle steht.
1144 			sal_uInt16 nEndLnPos = SwTableFormula::GetLnPosInTbl( *pTbl, pEndBox ),
1145 					nSttLnPos = SwTableFormula::GetLnPosInTbl( *pTbl, pSttBox );
1146 
1147 			if( USHRT_MAX != nSttLnPos && USHRT_MAX != nEndLnPos &&
1148 				((rTblUpd.nSplitLine <= nSttLnPos) ==
1149 				(rTblUpd.nSplitLine <= nEndLnPos)) )
1150 			{
1151 				// bleiben in der gleichen Tabelle
1152 				bInNewTbl = rTblUpd.nSplitLine <= nEndLnPos &&
1153 									pTbl == rTblUpd.pTbl;
1154 			}
1155 			else
1156 			{
1157 				// das ist aufjedenfall eine ungueltige Formel, also fuers
1158 				// Undo auf Modified setzen
1159 				rTblUpd.bModified = sal_True;
1160 				if( pEndBox )
1161 					bInNewTbl = USHRT_MAX != nEndLnPos &&
1162 									rTblUpd.nSplitLine <= nEndLnPos &&
1163 									pTbl == rTblUpd.pTbl;
1164 			}
1165 		}
1166 		else
1167 		{
1168 			sal_uInt16 nSttLnPos = SwTableFormula::GetLnPosInTbl( *pTbl, pSttBox );
1169 			// dann landet das Teil in der neuen Tabelle?
1170 			bInNewTbl = USHRT_MAX != nSttLnPos &&
1171 							rTblUpd.nSplitLine <= nSttLnPos &&
1172 							pTbl == rTblUpd.pTbl;
1173 		}
1174 
1175 		// wenn die Formel selbst in der neuen Tabellen landet
1176 		if( rTblUpd.bBehindSplitLine )
1177 		{
1178 			if( !bInNewTbl )
1179 			{
1180 				rTblUpd.bModified = sal_True;
1181 				( rNewStr += rTblUpd.pTbl->GetFrmFmt()->GetName() ) += '.';
1182 			}
1183 			else if( sTblNm.Len() )
1184 				( rNewStr += sTblNm ) += '.';
1185 		}
1186 		else if( bInNewTbl )
1187 		{
1188 			rTblUpd.bModified = sal_True;
1189 			( rNewStr += *rTblUpd.DATA.pNewTblNm ) += '.';
1190 		}
1191 		else if( sTblNm.Len() )
1192 			( rNewStr += sTblNm ) += '.';
1193 	}
1194 
1195 	if( pLastBox )
1196 		( rNewStr += String::CreateFromInt64((sal_PtrDiff)pEndBox)) += ':';
1197 	( rNewStr += String::CreateFromInt64((sal_PtrDiff)pSttBox))
1198 			  += rFirstBox.GetChar( rFirstBox.Len() - 1 );
1199 }
1200 
1201 	// erzeuge die externe Formel, beachte aber das die Formel
1202 	// in einer gesplitteten/gemergten Tabelle landet
1203 void SwTableFormula::ToSplitMergeBoxNm( SwTableFmlUpdate& rTblUpd )
1204 {
1205 	const SwTable* pTbl;
1206 	const SwNode* pNd = GetNodeOfFormula();
1207 	if( pNd && 0 != ( pNd = pNd->FindTableNode() ))
1208 		pTbl = &((SwTableNode*)pNd)->GetTable();
1209 	else
1210 		pTbl = rTblUpd.pTbl;
1211 
1212 	sFormel = ScanString( &SwTableFormula::_SplitMergeBoxNm, *pTbl, (void*)&rTblUpd );
1213 	eNmType = INTRNL_NAME;
1214 }
1215 
1216 
1217