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