xref: /AOO41X/main/sw/source/core/fields/cellfml.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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->GetFld().GetFld();
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