1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: cellfml.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
36 #include <hintids.hxx>
47 #include <swtable.hxx>
49 #include <cellfml.hxx>
54 #include <cellatr.hxx>
55 #include <ndindex.hxx>
57 const sal_Unicode cRelTrenner
= ',';
58 const sal_Unicode cRelKennung
= '\x12'; // CTRL-R
60 const USHORT cMAXSTACKSIZE
= 50;
62 const SwFrm
* lcl_GetBoxFrm( const SwTableBox
& rBox
);
63 long lcl_GetLongBoxNum( String
& rStr
);
64 const SwTableBox
* lcl_RelToBox( const SwTable
&, const SwTableBox
*, const String
& );
65 String
lcl_BoxNmToRel( const SwTable
&, const SwTableNode
&,
66 const String
& , const String
& , BOOL
);
69 /*************************************************************************
71 |* double SwTableBox::GetValue() const
72 |* gebe den Wert dieser Box zurueck. Der Wert ergibt sich aus dem 1.
73 |* TextNode. Beginnt dieser mit einer Zahl/Formel, so berechne diese;
74 |* oder mit einem Feld, dann hole den Wert.
75 |* Alle anderen Bedingungen returnen einen Fehler (oder 0 ?)
77 |* Ersterstellung JP 30. Jun. 93
78 |* Letzte Aenderung JP 30. Jun. 93
80 |*************************************************************************/
82 double SwTableBox::GetValue( SwTblCalcPara
& rCalcPara
) const
86 if( rCalcPara
.rCalc
.IsCalcError() )
87 return nRet
; // schon ein Fehler in der Berechnung
89 rCalcPara
.rCalc
.SetCalcError( CALC_SYNTAX
); // default immer Fehler
91 // keine Content Box ?
95 if( rCalcPara
.IncStackCnt() )
98 rCalcPara
.SetLastTblBox( this );
100 // wird eine Rekursion erzeugt ?
101 SwTableBox
* pBox
= (SwTableBox
*)this;
102 if( rCalcPara
.pBoxStk
->Seek_Entry( pBox
))
103 return nRet
; // steht schon auf dem Stack: FEHLER
105 // bei dieser Box nochmal aufsetzen
106 rCalcPara
.SetLastTblBox( this );
108 rCalcPara
.pBoxStk
->Insert( pBox
); // eintragen
109 do { // Middle-Check-Loop, damit aus dieser gesprungen werden kann
110 // hier aufgespannt, damit am Ende der Box-Pointer aus dem
111 // Stack ausgetragen wird
112 SwDoc
* pDoc
= GetFrmFmt()->GetDoc();
114 const SfxPoolItem
* pItem
;
115 if( SFX_ITEM_SET
== GetFrmFmt()->GetItemState(
116 RES_BOXATR_FORMULA
, FALSE
, &pItem
) )
118 rCalcPara
.rCalc
.SetCalcError( CALC_NOERR
); // wieder zuruecksetzen
119 if( !((SwTblBoxFormula
*)pItem
)->IsValid() )
122 const SwTable
* pTmp
= rCalcPara
.pTbl
;
123 rCalcPara
.pTbl
= &pBox
->GetSttNd()->FindTableNode()->GetTable();
124 ((SwTblBoxFormula
*)pItem
)->Calc( rCalcPara
, nRet
);
126 if( !rCalcPara
.IsStackOverFlow() )
128 SwFrmFmt
* pFmt
= pBox
->ClaimFrmFmt();
129 SfxItemSet
aTmp( pDoc
->GetAttrPool(),
130 RES_BOXATR_BEGIN
,RES_BOXATR_END
-1 );
131 aTmp
.Put( SwTblBoxValue( nRet
) );
132 if( SFX_ITEM_SET
!= pFmt
->GetItemState( RES_BOXATR_FORMAT
))
133 aTmp
.Put( SwTblBoxNumFormat( 0 ));
134 pFmt
->SetFmtAttr( aTmp
);
136 rCalcPara
.pTbl
= pTmp
;
139 nRet
= GetFrmFmt()->GetTblBoxValue().GetValue();
142 else if( SFX_ITEM_SET
== pBox
->GetFrmFmt()->GetItemState(
143 RES_BOXATR_VALUE
, FALSE
, &pItem
) )
145 rCalcPara
.rCalc
.SetCalcError( CALC_NOERR
); // wieder zuruecksetzen
146 nRet
= ((SwTblBoxValue
*)pItem
)->GetValue();
150 SwTxtNode
* pTxtNd
= pDoc
->GetNodes()[ pSttNd
->GetIndex() + 1 ]->GetTxtNode();
154 xub_StrLen nSttPos
= 0;
155 const String
& rTxt
= pTxtNd
->GetTxt();
156 while( nSttPos
< rTxt
.Len() &&
157 ( ' ' == rTxt
.GetChar( nSttPos
) || '\t' == rTxt
.GetChar( nSttPos
) ) )
160 // beginnt an erster Position ein "RechenFeld", dann erfrage den Wert
162 sal_Unicode
const Char
= rTxt
.GetChar(nSttPos
);
163 if ( nSttPos
< rTxt
.Len() &&
164 ( CH_TXTATR_BREAKWORD
== Char
|| CH_TXTATR_INWORD
== Char
) )
166 SwIndex
aIdx( pTxtNd
, nSttPos
);
167 SwTxtFld
* const pTxtFld
= static_cast<SwTxtFld
*>(
168 pTxtNd
->GetTxtAttrForCharAt(aIdx
.GetIndex(), RES_TXTATR_FIELD
));
172 rCalcPara
.rCalc
.SetCalcError( CALC_NOERR
); // wieder zuruecksetzen
174 const SwField
* pFld
= pTxtFld
->GetFld().GetFld();
175 switch( pFld
->GetTyp()->Which() )
178 nRet
= ((SwSetExpField
*)pFld
)->GetValue();
181 nRet
= ((SwUserFieldType
*)pFld
)->GetValue();
185 SwTblField
* pTblFld
= (SwTblField
*)pFld
;
186 if( !pTblFld
->IsValid() ) // ist der Wert gueltig ??
188 // die richtige Tabelle mitgeben!
189 const SwTable
* pTmp
= rCalcPara
.pTbl
;
190 rCalcPara
.pTbl
= &pTxtNd
->FindTableNode()->GetTable();
191 pTblFld
->CalcField( rCalcPara
);
192 rCalcPara
.pTbl
= pTmp
;
194 nRet
= pTblFld
->GetValue();
198 case RES_DATETIMEFLD
:
199 nRet
= ((SwDateTimeField
*)pFld
)->GetValue();
202 case RES_JUMPEDITFLD
:
203 //JP 14.09.98: Bug 56112 - der Platzhalter kann nie einen
204 // gueltigen Inhalt haben!
209 nRet
= rCalcPara
.rCalc
.Calculate( pFld
->Expand() ).GetDouble();
214 // Ergebnis ist 0 und kein Fehler!
215 rCalcPara
.rCalc
.SetCalcError( CALC_NOERR
); // wieder zuruecksetzen
218 String
sTxt( rTxt
.Copy( nSttPos
) );
219 sal_uInt32 nFmtIndex
= GetFrmFmt()->GetTblBoxNumFmt().GetValue();
221 SvNumberFormatter
* pNumFmtr
= pDoc
->GetNumberFormatter();
223 if( NUMBERFORMAT_TEXT
== nFmtIndex
)
225 // JP 22.04.98: Bug 49659 - Sonderbehandlung fuer Prozent
226 else if( sTxt
.Len() &&
227 NUMBERFORMAT_PERCENT
== pNumFmtr
->GetType( nFmtIndex
))
229 sal_uInt32 nTmpFmt
= 0;
230 if( pNumFmtr
->IsNumberFormat( sTxt
, nTmpFmt
, aNum
) &&
231 NUMBERFORMAT_NUMBER
== pNumFmtr
->GetType( nTmpFmt
))
235 if( pNumFmtr
->IsNumberFormat( sTxt
, nFmtIndex
, aNum
))
239 // ?? sonst ist das ein Fehler
242 if( !rCalcPara
.IsStackOverFlow() )
244 rCalcPara
.pBoxStk
->Remove( pBox
); // raus aus dem Stack
245 rCalcPara
.DecStackCnt();
248 //JP 12.01.99: mit Fehlererkennung, Bug 60794
249 if( DBL_MAX
== nRet
)
250 rCalcPara
.rCalc
.SetCalcError( CALC_SYNTAX
); // Fehler setzen
257 // Struktur, die zum TabelleRechnen benoetigt wird
259 SwTblCalcPara::SwTblCalcPara( SwCalc
& rCalculator
, const SwTable
& rTable
)
260 : pLastTblBox( 0 ), nStackCnt( 0 ), nMaxSize( cMAXSTACKSIZE
),
261 rCalc( rCalculator
), pTbl( &rTable
)
263 pBoxStk
= new SwTableSortBoxes
;
266 SwTblCalcPara::~SwTblCalcPara()
271 BOOL
SwTblCalcPara::CalcWithStackOverflow()
273 // falls ein StackUeberlauf erkannt wurde, sollte mit
274 // der letzten Box noch mal aufgesetzt werden. Irgend
275 // ein Weg sollte dann
276 USHORT nSaveMaxSize
= nMaxSize
;
278 nMaxSize
= cMAXSTACKSIZE
- 5;
280 SwTableBoxes aStackOverFlows
;
282 SwTableBox
* pBox
= (SwTableBox
*)pLastTblBox
;
284 rCalc
.SetCalcError( CALC_NOERR
);
285 aStackOverFlows
.C40_INSERT( SwTableBox
, pBox
, nCnt
++ );
287 pBoxStk
->Remove( pBox
);
288 pBox
->GetValue( *this );
289 } while( IsStackOverFlow() );
291 nMaxSize
= cMAXSTACKSIZE
- 3; // es muss mind. 1 Stufe tiefer gehen!
293 // falls Rekursionen erkannt wurden
295 rCalc
.SetCalcError( CALC_NOERR
);
296 pBoxStk
->Remove( USHORT(0), pBoxStk
->Count() );
298 while( !rCalc
.IsCalcError() && nCnt
)
300 aStackOverFlows
[ --nCnt
]->GetValue( *this );
301 if( IsStackOverFlow() && !CalcWithStackOverflow() )
305 nMaxSize
= nSaveMaxSize
;
306 aStackOverFlows
.Remove( 0, aStackOverFlows
.Count() );
307 return !rCalc
.IsCalcError();
312 SwTableFormula::SwTableFormula( const String
& rFormel
)
315 eNmType
= EXTRNL_NAME
;
319 SwTableFormula::~SwTableFormula()
323 void SwTableFormula::_MakeFormel( const SwTable
& rTbl
, String
& rNewStr
,
324 String
& rFirstBox
, String
* pLastBox
, void* pPara
) const
326 SwTblCalcPara
* pCalcPara
= (SwTblCalcPara
*)pPara
;
327 if( pCalcPara
->rCalc
.IsCalcError() ) // ist schon Fehler gesetzt ?
330 SwTableBox
* pSttBox
, *pEndBox
= 0;
332 rFirstBox
.Erase(0,1); // Kennung fuer Box loeschen
333 // ein Bereich in dieser Klammer ?
336 pEndBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(pLastBox
->ToInt64()));
338 // ist das ueberhaupt ein gueltiger Pointer ??
339 if( !rTbl
.GetTabSortBoxes().Seek_Entry( pEndBox
))
341 rFirstBox
.Erase( 0, pLastBox
->Len()+1 );
343 pSttBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(rFirstBox
.ToInt64()));
344 // ist das ueberhaupt ein gueltiger Pointer ??
345 if( !rTbl
.GetTabSortBoxes().Seek_Entry( pSttBox
))
349 if( pEndBox
&& pSttBox
) // Bereich ?
351 // hole ueber das Layout alle "selectierten" Boxen und berechne
354 GetBoxes( *pSttBox
, *pEndBox
, aBoxes
);
358 for( USHORT n
= 0; n
< aBoxes
.Count() &&
359 !pCalcPara
->rCalc
.IsCalcError(); ++n
)
361 const SwTableBox
* pTblBox
= aBoxes
[n
];
362 if ( pTblBox
->getRowSpan() >= 1 )
365 rNewStr
+= cListDelim
;
367 rNewStr
+= pCalcPara
->rCalc
.GetStrResult(
368 pTblBox
->GetValue( *pCalcPara
), FALSE
);
373 else if( pSttBox
&& !pLastBox
) // nur die StartBox ?
375 //JP 12.01.99: und keine EndBox in der Formel!
376 // Berechne den Wert der Box
377 if ( pSttBox
->getRowSpan() >= 1 )
379 rNewStr
+= pCalcPara
->rCalc
.GetStrResult(
380 pSttBox
->GetValue( *pCalcPara
), FALSE
);
384 pCalcPara
->rCalc
.SetCalcError( CALC_SYNTAX
); // Fehler setzen
388 void SwTableFormula::RelNmsToBoxNms( const SwTable
& rTbl
, String
& rNewStr
,
389 String
& rFirstBox
, String
* pLastBox
, void* pPara
) const
391 // relativen Namen zu Box-Namen (externe Darstellung)
392 SwNode
* pNd
= (SwNode
*)pPara
;
393 ASSERT( pNd
, "Feld steht in keinem TextNode" );
394 const SwTableBox
*pRelBox
, *pBox
= (SwTableBox
*)rTbl
.GetTblBox(
395 pNd
->FindTableBoxStartNode()->GetIndex() );
397 rNewStr
+= rFirstBox
.Copy(0,1); // Kennung fuer Box erhalten
398 rFirstBox
.Erase(0,1);
401 if( 0 != ( pRelBox
= lcl_RelToBox( rTbl
, pBox
, *pLastBox
)) )
402 rNewStr
+= pRelBox
->GetName();
404 rNewStr
.AppendAscii("A1");
406 rFirstBox
.Erase( 0, pLastBox
->Len()+1 );
409 if( 0 != ( pRelBox
= lcl_RelToBox( rTbl
, pBox
, rFirstBox
)) )
410 rNewStr
+= pRelBox
->GetName();
412 rNewStr
.AppendAscii("A1");
414 // Kennung fuer Box erhalten
415 rNewStr
+= rFirstBox
.GetChar( rFirstBox
.Len() - 1 );
418 void SwTableFormula::RelBoxNmsToPtr( const SwTable
& rTbl
, String
& rNewStr
,
419 String
& rFirstBox
, String
* pLastBox
, void* pPara
) const
421 // relativen Namen zu Box-Pointern (interne Darstellung)
422 SwNode
* pNd
= (SwNode
*)pPara
;
423 ASSERT( pNd
, "Feld steht in keinem Node" );
424 const SwTableBox
*pRelBox
, *pBox
= (SwTableBox
*)rTbl
.GetTblBox(
425 pNd
->FindTableBoxStartNode()->GetIndex() );
427 rNewStr
+= rFirstBox
.Copy(0,1); // Kennung fuer Box erhalten
428 rFirstBox
.Erase(0,1);
431 if( 0 != ( pRelBox
= lcl_RelToBox( rTbl
, pBox
, *pLastBox
)) )
432 rNewStr
+= String::CreateFromInt64( (sal_PtrDiff
)pRelBox
);
436 rFirstBox
.Erase( 0, pLastBox
->Len()+1 );
439 if( 0 != ( pRelBox
= lcl_RelToBox( rTbl
, pBox
, rFirstBox
)) )
440 rNewStr
+= String::CreateFromInt64( (sal_PtrDiff
)pRelBox
);
444 // Kennung fuer Box erhalten
445 rNewStr
+= rFirstBox
.GetChar( rFirstBox
.Len() - 1 );
449 void SwTableFormula::BoxNmsToRelNm( const SwTable
& rTbl
, String
& rNewStr
,
450 String
& rFirstBox
, String
* pLastBox
, void* pPara
) const
452 // Box-Namen (externe Darstellung) zu relativen Namen
453 SwNode
* pNd
= (SwNode
*)pPara
;
454 ASSERT( pNd
, "Feld steht in keinem Node" );
455 const SwTableNode
* pTblNd
= pNd
->FindTableNode();
458 if( &pTblNd
->GetTable() == &rTbl
)
460 const SwTableBox
*pBox
= rTbl
.GetTblBox(
461 pNd
->FindTableBoxStartNode()->GetIndex() );
462 ASSERT( pBox
, "Feld steht in keiner Tabelle" );
463 sRefBoxNm
= pBox
->GetName();
466 rNewStr
+= rFirstBox
.Copy(0,1); // Kennung fuer Box erhalten
467 rFirstBox
.Erase(0,1);
470 rNewStr
+= lcl_BoxNmToRel( rTbl
, *pTblNd
, sRefBoxNm
, *pLastBox
,
471 eNmType
== EXTRNL_NAME
);
473 rFirstBox
.Erase( 0, pLastBox
->Len()+1 );
476 rNewStr
+= lcl_BoxNmToRel( rTbl
, *pTblNd
, sRefBoxNm
, rFirstBox
,
477 eNmType
== EXTRNL_NAME
);
479 // Kennung fuer Box erhalten
480 rNewStr
+= rFirstBox
.GetChar( rFirstBox
.Len() - 1 );
484 void SwTableFormula::PtrToBoxNms( const SwTable
& rTbl
, String
& rNewStr
,
485 String
& rFirstBox
, String
* pLastBox
, void* ) const
487 // ein Bereich in dieser Klammer ?
490 rNewStr
+= rFirstBox
.Copy(0,1); // Kennung fuer Box erhalten
491 rFirstBox
.Erase(0,1);
494 pBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(pLastBox
->ToInt64()));
496 // ist das ueberhaupt ein gueltiger Pointer ??
497 if( rTbl
.GetTabSortBoxes().Seek_Entry( pBox
))
498 rNewStr
+= pBox
->GetName();
502 rFirstBox
.Erase( 0, pLastBox
->Len()+1 );
505 pBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(rFirstBox
.ToInt64()));
506 // ist das ueberhaupt ein gueltiger Pointer ??
507 if( rTbl
.GetTabSortBoxes().Seek_Entry( pBox
))
508 rNewStr
+= pBox
->GetName();
512 // Kennung fuer Box erhalten
513 rNewStr
+= rFirstBox
.GetChar( rFirstBox
.Len() - 1 );
516 void SwTableFormula::BoxNmsToPtr( const SwTable
& rTbl
, String
& rNewStr
,
517 String
& rFirstBox
, String
* pLastBox
, void* ) const
519 // ein Bereich in dieser Klammer ?
520 const SwTableBox
* pBox
;
522 rNewStr
+= rFirstBox
.Copy(0,1); // Kennung fuer Box erhalten
523 rFirstBox
.Erase(0,1);
526 pBox
= rTbl
.GetTblBox( *pLastBox
);
527 rNewStr
+= String::CreateFromInt64( (sal_PtrDiff
)pBox
);
529 rFirstBox
.Erase( 0, pLastBox
->Len()+1 );
532 pBox
= rTbl
.GetTblBox( rFirstBox
);
533 rNewStr
+= String::CreateFromInt64( (sal_PtrDiff
)pBox
);
535 // Kennung fuer Box erhalten
536 rNewStr
+= rFirstBox
.GetChar( rFirstBox
.Len() - 1 );
539 // erzeuge die externe (fuer UI) Formel
540 void SwTableFormula::PtrToBoxNm( const SwTable
* pTbl
)
542 const SwNode
* pNd
= 0;
543 FnScanFormel fnFormel
= 0;
548 fnFormel
= &SwTableFormula::PtrToBoxNms
;
553 fnFormel
= &SwTableFormula::RelNmsToBoxNms
;
554 pNd
= GetNodeOfFormula();
560 sFormel
= ScanString( fnFormel
, *pTbl
, (void*)pNd
);
561 eNmType
= EXTRNL_NAME
;
564 // erzeuge die interne (in CORE) Formel
565 void SwTableFormula::BoxNmToPtr( const SwTable
* pTbl
)
567 const SwNode
* pNd
= 0;
568 FnScanFormel fnFormel
= 0;
573 fnFormel
= &SwTableFormula::BoxNmsToPtr
;
578 fnFormel
= &SwTableFormula::RelBoxNmsToPtr
;
579 pNd
= GetNodeOfFormula();
585 sFormel
= ScanString( fnFormel
, *pTbl
, (void*)pNd
);
586 eNmType
= INTRNL_NAME
;
589 // erzeuge die relative (fuers Kopieren) Formel
590 void SwTableFormula::ToRelBoxNm( const SwTable
* pTbl
)
592 const SwNode
* pNd
= 0;
593 FnScanFormel fnFormel
= 0;
600 fnFormel
= &SwTableFormula::BoxNmsToRelNm
;
601 pNd
= GetNodeOfFormula();
607 sFormel
= ScanString( fnFormel
, *pTbl
, (void*)pNd
);
612 String
SwTableFormula::ScanString( FnScanFormel fnFormel
, const SwTable
& rTbl
,
616 USHORT nFml
= 0, nStt
= 0, nEnd
= 0, nTrenner
;
619 // falls der Formel ein Name vorangestellt ist, diese Tabelle
621 const SwTable
* pTbl
= &rTbl
;
623 nStt
= sFormel
.Search( '<', nFml
);
624 if( STRING_NOTFOUND
!= nStt
)
626 while( STRING_NOTFOUND
!= nStt
&&
627 ( ' ' == sFormel
.GetChar( nStt
+ 1 ) ||
628 '=' == sFormel
.GetChar( nStt
+ 1 ) ) )
629 nStt
= sFormel
.Search( '<', nStt
+ 1 );
631 if( STRING_NOTFOUND
!= nStt
)
632 nEnd
= sFormel
.Search( '>', nStt
+1 );
634 if( STRING_NOTFOUND
== nStt
|| STRING_NOTFOUND
== nEnd
)
636 // den Rest setzen und beenden
637 aStr
.Insert( sFormel
, nFml
, sFormel
.Len() - nFml
);
640 aStr
.Insert( sFormel
, nFml
, nStt
- nFml
); // Anfang schreiben
642 if( fnFormel
!= NULL
)
644 // ist ein TabellenName vorangestellt ??
645 // JP 16.02.99: SplitMergeBoxNm behandeln den Namen selbst
646 // JP 22.02.99: der CAST muss fuer den Linux-Compiler sein
647 // JP 28.06.99: rel. BoxName have no preceding tablename!
648 if( fnFormel
!= (FnScanFormel
)&SwTableFormula::_SplitMergeBoxNm
&&
649 1 < sFormel
.Len() && cRelKennung
!= sFormel
.GetChar( 1 ) &&
650 STRING_NOTFOUND
!= ( nTrenner
= sFormel
.Search( '.', nStt
))
653 String
sTblNm( sFormel
.Copy( nStt
, nEnd
- nStt
));
655 // falls im Namen schon die Punkte enthalten sind,
656 // treten diese immer paarig auf!!! (A1.1.1 !!)
657 if( (sTblNm
.GetTokenCount( '.' ) - 1 ) & 1 )
659 sTblNm
.Erase( nTrenner
- nStt
);
661 // beim Bauen der Formel ist der TabellenName unerwuenscht
662 //JP 22.02.99: der CAST muss fuer den Linux-Compiler sein
663 if( fnFormel
!= (FnScanFormel
)&SwTableFormula::_MakeFormel
)
667 sTblNm
.Erase( 0, 1 ); // Trenner loeschen
668 if( sTblNm
!= rTbl
.GetFrmFmt()->GetName() )
670 // dann suchen wir uns mal unsere Tabelle:
671 const SwTable
* pFnd
= FindTable(
672 *rTbl
.GetFrmFmt()->GetDoc(),
677 ASSERT( pFnd
, "Tabelle nicht gefunden, was nun?" );
682 String
sBox( sFormel
.Copy( nStt
, nEnd
- nStt
+ 1 ));
683 // ein Bereich in dieser Klammer ?
684 if( STRING_NOTFOUND
!= ( nTrenner
= sFormel
.Search( ':', nStt
))
687 // ohne die Anfangsklammer
688 String
aFirstBox( sFormel
.Copy( nStt
+1, nTrenner
- nStt
- 1 ));
689 (this->*fnFormel
)( *pTbl
, aStr
, sBox
, &aFirstBox
, pPara
);
692 (this->*fnFormel
)( *pTbl
, aStr
, sBox
, 0, pPara
);
700 const SwTable
* SwTableFormula::FindTable( SwDoc
& rDoc
, const String
& rNm
) const
702 const SwFrmFmts
& rTblFmts
= *rDoc
.GetTblFrmFmts();
703 const SwTable
* pTmpTbl
, *pRet
= 0;
704 for( USHORT nFmtCnt
= rTblFmts
.Count(); nFmtCnt
; )
706 SwFrmFmt
* pFmt
= rTblFmts
[ --nFmtCnt
];
707 // falls wir von Sw3Writer gerufen werden, dann ist dem
708 // FormatNamen eine Nummer anhaengig
710 if( COMPARE_EQUAL
== rNm
.CompareTo( pFmt
->GetName(),
711 pFmt
->GetName().Search( 0x0a ) ) &&
712 0 != ( pTmpTbl
= SwTable::FindTable( pFmt
) ) &&
713 0 != (pFBox
= pTmpTbl
->GetTabSortBoxes()[0] ) &&
715 pFBox
->GetSttNd()->GetNodes().IsDocNodes() )
717 // eine Tabelle im normalen NodesArr
727 const SwFrm
* lcl_GetBoxFrm( const SwTableBox
& rBox
)
731 // oder besser ueber die Box den Frame suchen
733 SwClientIter aIter( *pBox->GetFrmFmt() );
734 ULONG nMinPos = ULONG_MAX;
735 const SwFrm* pFnd = 0;
736 for( SwFrm* pF = (SwFrm*)aIter.First( TYPE( SwCellFrm )); pF;
737 pF = (SwFrm*)aIter.Next() )
743 SwNodeIndex
aIdx( *rBox
.GetSttNd() );
744 SwCntntNode
* pCNd
= aIdx
.GetNodes().GoNext( &aIdx
);
745 ASSERT( pCNd
, "Box hat keinen TextNode" );
746 Point aPt
; // den im Layout 1. Frame returnen - Tab.Kopfzeile !!
747 return pCNd
->GetFrm( &aPt
, NULL
, FALSE
);
750 long lcl_GetLongBoxNum( String
& rStr
)
754 if( STRING_NOTFOUND
== ( nPos
= rStr
.Search( cRelTrenner
) ))
756 nRet
= rStr
.ToInt32();
761 nRet
= rStr
.Copy( 0, nPos
).ToInt32();
762 rStr
.Erase( 0, nPos
+1 );
767 const SwTableBox
* lcl_RelToBox( const SwTable
& rTbl
,
768 const SwTableBox
* pRefBox
,
769 const String
& rGetName
)
772 const SwTableBox
* pBox
= 0;
773 String
sGetName( rGetName
);
775 // ist es denn wirklich eine relative Angabe??
776 if( cRelKennung
== sGetName
.GetChar(0) ) // ja, ...
781 sGetName
.Erase( 0, 1 );
783 const SwTableLines
* pLines
= (SwTableLines
*)&rTbl
.GetTabLines();
784 const SwTableBoxes
* pBoxes
;
785 const SwTableLine
* pLine
;
787 // bestimme erst mal die Start-Werte der Box:
788 pBox
= (SwTableBox
*)pRefBox
;
789 pLine
= pBox
->GetUpper();
790 while( pLine
->GetUpper() )
792 pBox
= pLine
->GetUpper();
793 pLine
= pBox
->GetUpper();
795 USHORT nSttBox
= pLine
->GetTabBoxes().GetPos( pBox
);
796 USHORT nSttLine
= rTbl
.GetTabLines().GetPos( pLine
);
798 long nBoxOffset
= lcl_GetLongBoxNum( sGetName
) + nSttBox
;
799 long nLineOffset
= lcl_GetLongBoxNum( sGetName
) + nSttLine
;
801 if( nBoxOffset
< 0 || nBoxOffset
>= USHRT_MAX
||
802 nLineOffset
< 0 || nLineOffset
>= USHRT_MAX
)
805 if( nLineOffset
>= long(pLines
->Count()) )
808 pLine
= (*pLines
)[ USHORT(nLineOffset
) ];
810 // dann suche die Box
811 pBoxes
= &pLine
->GetTabBoxes();
812 if( nBoxOffset
>= long(pBoxes
->Count()) )
814 pBox
= (*pBoxes
)[ USHORT(nBoxOffset
) ];
816 while( sGetName
.Len() )
818 nSttBox
= SwTable::_GetBoxNum( sGetName
);
819 pLines
= &pBox
->GetTabLines();
823 nSttLine
= SwTable::_GetBoxNum( sGetName
);
826 if( !nSttLine
|| nSttLine
> pLines
->Count() )
828 pLine
= (*pLines
)[ nSttLine
-1 ];
831 pBoxes
= &pLine
->GetTabBoxes();
832 if( nSttBox
>= pBoxes
->Count() )
834 pBox
= (*pBoxes
)[ nSttBox
];
839 if( !pBox
->GetSttNd() )
840 // "herunterfallen lassen" bis zur ersten Box
841 while( pBox
->GetTabLines().Count() )
842 pBox
= pBox
->GetTabLines()[0]->GetTabBoxes()[0];
847 // sonst ist es eine absolute externe Darstellung:
848 pBox
= rTbl
.GetTblBox( sGetName
);
853 String
lcl_BoxNmToRel( const SwTable
& rTbl
, const SwTableNode
& rTblNd
,
854 const String
& rRefBoxNm
, const String
& rGetStr
,
857 String
sCpy( rRefBoxNm
);
858 String
sTmp( rGetStr
);
861 // in die Externe Darstellung umwandeln.
862 SwTableBox
* pBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(sTmp
.ToInt64()));
863 if( !rTbl
.GetTabSortBoxes().Seek_Entry( pBox
))
865 sTmp
= pBox
->GetName();
868 // sollte die es eine Tabellen uebergreifende Formel sein, dann behalte
869 // die externe Darstellung bei:
870 if( &rTbl
== &rTblNd
.GetTable() )
872 long nBox
= SwTable::_GetBoxNum( sTmp
, TRUE
);
873 nBox
-= SwTable::_GetBoxNum( sCpy
, TRUE
);
874 long nLine
= SwTable::_GetBoxNum( sTmp
);
875 nLine
-= SwTable::_GetBoxNum( sCpy
);
877 sCpy
= sTmp
; //JP 01.11.95: den Rest aus dem BoxNamen anhaengen
880 sTmp
+= String::CreateFromInt32( nBox
);
882 sTmp
+= String::CreateFromInt32( nLine
);
891 if( sTmp
.Len() && '>' == sTmp
.GetChar( sTmp
.Len() - 1 ))
892 sTmp
.Erase( sTmp
.Len()-1 );
897 USHORT
SwTableFormula::GetBoxesOfFormula( const SwTable
& rTbl
,
901 rBoxes
.Remove( USHORT(0), rBoxes
.Count() );
904 ScanString( &SwTableFormula::_GetFmlBoxes
, rTbl
, &rBoxes
);
905 return rBoxes
.Count();
908 void SwTableFormula::_GetFmlBoxes( const SwTable
& rTbl
, String
& ,
909 String
& rFirstBox
, String
* pLastBox
, void* pPara
) const
911 SwSelBoxes
* pBoxes
= (SwSelBoxes
*)pPara
;
912 SwTableBox
* pSttBox
, *pEndBox
= 0;
914 rFirstBox
.Erase(0,1); // Kennung fuer Box loeschen
915 // ein Bereich in dieser Klammer ?
918 pEndBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(pLastBox
->ToInt64()));
920 // ist das ueberhaupt ein gueltiger Pointer ??
921 if( !rTbl
.GetTabSortBoxes().Seek_Entry( pEndBox
))
923 rFirstBox
.Erase( 0, pLastBox
->Len()+1 );
926 pSttBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(rFirstBox
.ToInt64()));
927 // ist das ueberhaupt ein gueltiger Pointer ??
928 if( !rTbl
.GetTabSortBoxes().Seek_Entry( pSttBox
))
931 if( pEndBox
&& pSttBox
) // Bereich ?
933 // ueber das Layout alle "selectierten" Boxen und berechne
936 GetBoxes( *pSttBox
, *pEndBox
, aBoxes
);
937 pBoxes
->Insert( &aBoxes
);
939 else if( pSttBox
) // nur die StartBox ?
940 pBoxes
->Insert( pSttBox
);
943 void SwTableFormula::GetBoxes( const SwTableBox
& rSttBox
,
944 const SwTableBox
& rEndBox
,
945 SwSelBoxes
& rBoxes
) const
947 // hole ueber das Layout alle "selektierten" Boxen
948 const SwLayoutFrm
*pStt
, *pEnd
;
949 const SwFrm
* pFrm
= lcl_GetBoxFrm( rSttBox
);
950 pStt
= pFrm
? pFrm
->GetUpper() : 0;
951 pEnd
= ( 0 != (pFrm
= lcl_GetBoxFrm( rEndBox
))) ? pFrm
->GetUpper() : 0;
953 return ; // no valid selection
955 GetTblSel( pStt
, pEnd
, rBoxes
, 0 );
957 const SwTable
* pTbl
= pStt
->FindTabFrm()->GetTable();
959 // filter die Kopfzeilen-Boxen heraus:
960 if( pTbl
->GetRowsToRepeat() > 0 )
962 do { // middle-check loop
963 const SwTableLine
* pLine
= rSttBox
.GetUpper();
964 while( pLine
->GetUpper() )
965 pLine
= pLine
->GetUpper()->GetUpper();
967 if( pTbl
->IsHeadline( *pLine
) )
968 break; // Headline mit im Bereich !
970 // vielleicht ist ja Start und Ende vertauscht
971 pLine
= rEndBox
.GetUpper();
972 while ( pLine
->GetUpper() )
973 pLine
= pLine
->GetUpper()->GetUpper();
975 if( pTbl
->IsHeadline( *pLine
) )
976 break; // Headline mit im Bereich !
978 const SwTabFrm
*pTable
= pStt
->FindTabFrm();
979 const SwTabFrm
*pEndTable
= pEnd
->FindTabFrm();
981 if( pTable
== pEndTable
) // keine gespl. Tabelle
984 // dann mal die Tabellenkoepfe raus:
985 for( USHORT n
= 0; n
< rBoxes
.Count(); ++n
)
987 pLine
= rBoxes
[n
]->GetUpper();
988 while( pLine
->GetUpper() )
989 pLine
= pLine
->GetUpper()->GetUpper();
991 if( pTbl
->IsHeadline( *pLine
) )
992 rBoxes
.Remove( n
--, 1 );
998 // sind alle Boxen gueltig, auf die sich die Formel bezieht?
999 void SwTableFormula::_HasValidBoxes( const SwTable
& rTbl
, String
& ,
1000 String
& rFirstBox
, String
* pLastBox
, void* pPara
) const
1002 BOOL
* pBValid
= (BOOL
*)pPara
;
1003 if( *pBValid
) // einmal falsch, immer falsch
1005 SwTableBox
* pSttBox
= 0, *pEndBox
= 0;
1006 rFirstBox
.Erase(0,1); // Kennung fuer Box loeschen
1008 // ein Bereich in dieser Klammer ?
1010 rFirstBox
.Erase( 0, pLastBox
->Len()+1 );
1016 pEndBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(pLastBox
->ToInt64()));
1017 pSttBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(rFirstBox
.ToInt64()));
1022 const SwNode
* pNd
= GetNodeOfFormula();
1023 const SwTableBox
* pBox
= !pNd
? 0
1024 : (SwTableBox
*)rTbl
.GetTblBox(
1025 pNd
->FindTableBoxStartNode()->GetIndex() );
1027 pEndBox
= (SwTableBox
*)lcl_RelToBox( rTbl
, pBox
, *pLastBox
);
1028 pSttBox
= (SwTableBox
*)lcl_RelToBox( rTbl
, pBox
, rFirstBox
);
1034 pEndBox
= (SwTableBox
*)rTbl
.GetTblBox( *pLastBox
);
1035 pSttBox
= (SwTableBox
*)rTbl
.GetTblBox( rFirstBox
);
1039 // sind das gueltige Pointer ?
1041 ( !pEndBox
|| !rTbl
.GetTabSortBoxes().Seek_Entry( pEndBox
) ) ) ||
1042 ( !pSttBox
|| !rTbl
.GetTabSortBoxes().Seek_Entry( pSttBox
) ) )
1047 BOOL
SwTableFormula::HasValidBoxes() const
1050 const SwNode
* pNd
= GetNodeOfFormula();
1051 if( pNd
&& 0 != ( pNd
= pNd
->FindTableNode() ) )
1052 ScanString( &SwTableFormula::_HasValidBoxes
,
1053 ((SwTableNode
*)pNd
)->GetTable(), &bRet
);
1058 USHORT
SwTableFormula::GetLnPosInTbl( const SwTable
& rTbl
, const SwTableBox
* pBox
)
1060 USHORT nRet
= USHRT_MAX
;
1063 const SwTableLine
* pLn
= pBox
->GetUpper();
1064 while( pLn
->GetUpper() )
1065 pLn
= pLn
->GetUpper()->GetUpper();
1066 nRet
= rTbl
.GetTabLines().GetPos( pLn
);
1071 void SwTableFormula::_SplitMergeBoxNm( const SwTable
& rTbl
, String
& rNewStr
,
1072 String
& rFirstBox
, String
* pLastBox
, void* pPara
) const
1074 SwTableFmlUpdate
& rTblUpd
= *(SwTableFmlUpdate
*)pPara
;
1076 rNewStr
+= rFirstBox
.Copy(0,1); // Kennung fuer Box erhalten
1077 rFirstBox
.Erase(0,1);
1080 const SwTable
* pTbl
= &rTbl
;
1082 String
* pTblNmBox
= pLastBox
? pLastBox
: &rFirstBox
;
1084 USHORT nLastBoxLen
= pTblNmBox
->Len();
1085 USHORT nTrenner
= pTblNmBox
->Search( '.' );
1086 if( STRING_NOTFOUND
!= nTrenner
&&
1087 // falls im Namen schon die Punkte enthalten sind,
1088 // treten diese immer paarig auf!!! (A1.1.1 !!)
1089 (pTblNmBox
->GetTokenCount( '.' ) - 1 ) & 1 )
1091 sTblNm
= pTblNmBox
->Copy( 0, nTrenner
);
1092 pTblNmBox
->Erase( 0, nTrenner
+ 1);// den Punkt entfernen
1093 const SwTable
* pFnd
= FindTable( *rTbl
.GetFrmFmt()->GetDoc(), sTblNm
);
1097 if( TBL_MERGETBL
== rTblUpd
.eFlags
)
1101 if( pFnd
== rTblUpd
.DATA
.pDelTbl
)
1103 if( rTblUpd
.pTbl
!= &rTbl
) // es ist nicht die akt.
1104 (rNewStr
+= rTblUpd
.pTbl
->GetFrmFmt()->GetName() )
1105 += '.'; // den neuen Tabellen Namen setzen
1106 rTblUpd
.bModified
= TRUE
;
1108 else if( pFnd
!= rTblUpd
.pTbl
||
1109 ( rTblUpd
.pTbl
!= &rTbl
&& &rTbl
!= rTblUpd
.DATA
.pDelTbl
))
1110 (rNewStr
+= sTblNm
) += '.'; // den Tabellen Namen behalten
1112 rTblUpd
.bModified
= TRUE
;
1115 (rNewStr
+= sTblNm
) += '.'; // den Tabellen Namen behalten
1119 if( pTblNmBox
== pLastBox
)
1120 rFirstBox
.Erase( 0, nLastBoxLen
+ 1 );
1122 SwTableBox
* pSttBox
= 0, *pEndBox
= 0;
1127 pEndBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(pLastBox
->ToInt64()));
1128 pSttBox
= reinterpret_cast<SwTableBox
*>(sal::static_int_cast
<sal_IntPtr
>(rFirstBox
.ToInt64()));
1133 const SwNode
* pNd
= GetNodeOfFormula();
1134 const SwTableBox
* pBox
= pNd
? pTbl
->GetTblBox(
1135 pNd
->FindTableBoxStartNode()->GetIndex() ) : 0;
1137 pEndBox
= (SwTableBox
*)lcl_RelToBox( *pTbl
, pBox
, *pLastBox
);
1138 pSttBox
= (SwTableBox
*)lcl_RelToBox( *pTbl
, pBox
, rFirstBox
);
1144 pEndBox
= (SwTableBox
*)pTbl
->GetTblBox( *pLastBox
);
1145 pSttBox
= (SwTableBox
*)pTbl
->GetTblBox( rFirstBox
);
1149 if( pLastBox
&& !pTbl
->GetTabSortBoxes().Seek_Entry( pEndBox
))
1151 if( !pTbl
->GetTabSortBoxes().Seek_Entry( pSttBox
))
1154 if( TBL_SPLITTBL
== rTblUpd
.eFlags
)
1156 // wo liegen die Boxen, in der "alten" oder in der neuen Tabelle?
1157 BOOL bInNewTbl
= FALSE
;
1160 // das ist die "erste" Box in der Selektion. Die bestimmt ob die
1161 // Formel in der alten oder neuen Tabelle steht.
1162 USHORT nEndLnPos
= SwTableFormula::GetLnPosInTbl( *pTbl
, pEndBox
),
1163 nSttLnPos
= SwTableFormula::GetLnPosInTbl( *pTbl
, pSttBox
);
1165 if( USHRT_MAX
!= nSttLnPos
&& USHRT_MAX
!= nEndLnPos
&&
1166 ((rTblUpd
.nSplitLine
<= nSttLnPos
) ==
1167 (rTblUpd
.nSplitLine
<= nEndLnPos
)) )
1169 // bleiben in der gleichen Tabelle
1170 bInNewTbl
= rTblUpd
.nSplitLine
<= nEndLnPos
&&
1171 pTbl
== rTblUpd
.pTbl
;
1175 // das ist aufjedenfall eine ungueltige Formel, also fuers
1176 // Undo auf Modified setzen
1177 rTblUpd
.bModified
= TRUE
;
1179 bInNewTbl
= USHRT_MAX
!= nEndLnPos
&&
1180 rTblUpd
.nSplitLine
<= nEndLnPos
&&
1181 pTbl
== rTblUpd
.pTbl
;
1186 USHORT nSttLnPos
= SwTableFormula::GetLnPosInTbl( *pTbl
, pSttBox
);
1187 // dann landet das Teil in der neuen Tabelle?
1188 bInNewTbl
= USHRT_MAX
!= nSttLnPos
&&
1189 rTblUpd
.nSplitLine
<= nSttLnPos
&&
1190 pTbl
== rTblUpd
.pTbl
;
1193 // wenn die Formel selbst in der neuen Tabellen landet
1194 if( rTblUpd
.bBehindSplitLine
)
1198 rTblUpd
.bModified
= TRUE
;
1199 ( rNewStr
+= rTblUpd
.pTbl
->GetFrmFmt()->GetName() ) += '.';
1201 else if( sTblNm
.Len() )
1202 ( rNewStr
+= sTblNm
) += '.';
1204 else if( bInNewTbl
)
1206 rTblUpd
.bModified
= TRUE
;
1207 ( rNewStr
+= *rTblUpd
.DATA
.pNewTblNm
) += '.';
1209 else if( sTblNm
.Len() )
1210 ( rNewStr
+= sTblNm
) += '.';
1214 ( rNewStr
+= String::CreateFromInt64((sal_PtrDiff
)pEndBox
)) += ':';
1215 ( rNewStr
+= String::CreateFromInt64((sal_PtrDiff
)pSttBox
))
1216 += rFirstBox
.GetChar( rFirstBox
.Len() - 1 );
1219 // erzeuge die externe Formel, beachte aber das die Formel
1220 // in einer gesplitteten/gemergten Tabelle landet
1221 void SwTableFormula::ToSplitMergeBoxNm( SwTableFmlUpdate
& rTblUpd
)
1223 const SwTable
* pTbl
;
1224 const SwNode
* pNd
= GetNodeOfFormula();
1225 if( pNd
&& 0 != ( pNd
= pNd
->FindTableNode() ))
1226 pTbl
= &((SwTableNode
*)pNd
)->GetTable();
1228 pTbl
= rTblUpd
.pTbl
;
1230 sFormel
= ScanString( &SwTableFormula::_SplitMergeBoxNm
, *pTbl
, (void*)&rTblUpd
);
1231 eNmType
= INTRNL_NAME
;