xref: /trunk/main/sw/source/core/fields/cellfml.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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