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