diff options
Diffstat (limited to 'sw/source/core/fields/cellfml.cxx')
-rw-r--r-- | sw/source/core/fields/cellfml.cxx | 1305 |
1 files changed, 1305 insertions, 0 deletions
diff --git a/sw/source/core/fields/cellfml.cxx b/sw/source/core/fields/cellfml.cxx new file mode 100644 index 000000000000..a425de452149 --- /dev/null +++ b/sw/source/core/fields/cellfml.cxx @@ -0,0 +1,1305 @@ +/************************************************************************* + * + * $RCSfile: cellfml.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-19 00:08:19 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#ifdef PRECOMPILED +#include "core_pch.hxx" +#endif + +#pragma hdrstop + +#include <float.h> +#ifndef _HINTIDS_HXX +#include <hintids.hxx> +#endif + +#ifndef _FMTFLD_HXX //autogen +#include <fmtfld.hxx> +#endif +#ifndef _TXTFLD_HXX //autogen +#include <txtfld.hxx> +#endif +#ifndef _FRMFMT_HXX //autogen +#include <frmfmt.hxx> +#endif +#ifndef _LAYFRM_HXX +#include <layfrm.hxx> +#endif +#ifndef _CNTFRM_HXX +#include <cntfrm.hxx> +#endif +#ifndef _TABFRM_HXX +#include <tabfrm.hxx> +#endif +#ifndef _DOC_HXX +#include <doc.hxx> +#endif +#ifndef _DOCARY_HXX +#include <docary.hxx> +#endif +#ifndef _NDTXT_HXX +#include <ndtxt.hxx> +#endif +#ifndef _SWTABLE_HXX +#include <swtable.hxx> +#endif +#ifndef _TBLSEL_HXX +#include <tblsel.hxx> +#endif +#ifndef _CELLFML_HXX +#include <cellfml.hxx> +#endif +#ifndef _CALC_HXX +#include <calc.hxx> +#endif +#ifndef _EXPFLD_HXX +#include <expfld.hxx> +#endif +#ifndef _USRFLD_HXX +#include <usrfld.hxx> +#endif +#ifndef _FLDDAT_HXX +#include <flddat.hxx> +#endif +#ifndef _CELLATR_HXX +#include <cellatr.hxx> +#endif +#ifndef _NDINDEX_HXX +#include <ndindex.hxx> +#endif +#ifndef _HINTS_HXX +#include <hints.hxx> +#endif + +const sal_Unicode cRelTrenner = ','; +const sal_Unicode cRelKennung = ''; // CTRL-R + +const USHORT cMAXSTACKSIZE = 50; + +const SwFrm* lcl_GetBoxFrm( const SwTableBox& rBox ); +long lcl_GetLongBoxNum( String& rStr ); +const SwTableBox* lcl_RelToBox( const SwTable&, const SwTableBox*, const String& ); +String lcl_BoxNmToRel( const SwTable&, const SwTableNode&, + const String& , const String& , BOOL ); + + +/************************************************************************* +|* +|* double SwTableBox::GetValue() const +|* gebe den Wert dieser Box zurueck. Der Wert ergibt sich aus dem 1. +|* TextNode. Beginnt dieser mit einer Zahl/Formel, so berechne diese; +|* oder mit einem Feld, dann hole den Wert. +|* Alle anderen Bedingungen returnen einen Fehler (oder 0 ?) +|* +|* Ersterstellung JP 30. Jun. 93 +|* Letzte Aenderung JP 30. Jun. 93 +|* +|*************************************************************************/ + +double SwTableBox::GetValue( SwTblCalcPara& rCalcPara ) const +{ + double nRet = 0; + + if( rCalcPara.rCalc.IsCalcError() ) + return nRet; // schon ein Fehler in der Berechnung + + rCalcPara.rCalc.SetCalcError( CALC_SYNTAX ); // default immer Fehler + + // keine Content Box ? + if( !pSttNd ) + return nRet; + + if( rCalcPara.IncStackCnt() ) + return nRet; + + rCalcPara.SetLastTblBox( this ); + + // wird eine Rekursion erzeugt ? + SwTableBox* pBox = (SwTableBox*)this; + if( rCalcPara.pBoxStk->Seek_Entry( pBox )) + return nRet; // steht schon auf dem Stack: FEHLER + + // bei dieser Box nochmal aufsetzen + rCalcPara.SetLastTblBox( this ); + + rCalcPara.pBoxStk->Insert( pBox ); // eintragen + do { // Middle-Check-Loop, damit aus dieser gesprungen werden kann + // hier aufgespannt, damit am Ende der Box-Pointer aus dem + // Stack ausgetragen wird + SwDoc* pDoc = GetFrmFmt()->GetDoc(); + + const SfxPoolItem* pItem; + if( SFX_ITEM_SET == GetFrmFmt()->GetItemState( + RES_BOXATR_FORMULA, FALSE, &pItem ) ) + { + rCalcPara.rCalc.SetCalcError( CALC_NOERR ); // wieder zuruecksetzen + if( !((SwTblBoxFormula*)pItem)->IsValid() ) + { + // dann berechnen + const SwTable* pTmp = rCalcPara.pTbl; + rCalcPara.pTbl = &pBox->GetSttNd()->FindTableNode()->GetTable(); + ((SwTblBoxFormula*)pItem)->Calc( rCalcPara, nRet ); + + if( !rCalcPara.IsStackOverFlow() ) + { + SwFrmFmt* pFmt = pBox->ClaimFrmFmt(); + SfxItemSet aTmp( pDoc->GetAttrPool(), + RES_BOXATR_BEGIN,RES_BOXATR_END-1 ); + aTmp.Put( SwTblBoxValue( nRet ) ); + if( SFX_ITEM_SET != pFmt->GetItemState( RES_BOXATR_FORMAT )) + aTmp.Put( SwTblBoxNumFormat( 0 )); + pFmt->SetAttr( aTmp ); + } + rCalcPara.pTbl = pTmp; + } + else + nRet = GetFrmFmt()->GetTblBoxValue().GetValue(); + break; + } + else if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetItemState( + RES_BOXATR_VALUE, FALSE, &pItem ) ) + { + rCalcPara.rCalc.SetCalcError( CALC_NOERR ); // wieder zuruecksetzen + nRet = ((SwTblBoxValue*)pItem)->GetValue(); + break; + } + + SwTxtNode* pTxtNd = pDoc->GetNodes()[ pSttNd->GetIndex() + 1 ]->GetTxtNode(); + if( !pTxtNd ) + break; + + xub_StrLen nSttPos = 0; + const String& rTxt = pTxtNd->GetTxt(); + while( nSttPos < rTxt.Len() && + ( ' ' == rTxt.GetChar( nSttPos ) || '\t' == rTxt.GetChar( nSttPos ) ) ) + ++nSttPos; + + // beginnt an erster Position ein "RechenFeld", dann erfrage den Wert + // von diesem + sal_Unicode cChr; + if( nSttPos < rTxt.Len() && + ( CH_TXTATR_BREAKWORD == ( cChr = rTxt.GetChar(nSttPos)) || + CH_TXTATR_INWORD == cChr )) + { + SwIndex aIdx( pTxtNd, nSttPos ); + SwTxtFld* pTxtFld = pTxtNd->GetTxtFld( aIdx ); + if( !pTxtFld ) + break; + + rCalcPara.rCalc.SetCalcError( CALC_NOERR ); // wieder zuruecksetzen + + const SwField* pFld = pTxtFld->GetFld().GetFld(); + switch( pFld->GetTyp()->Which() ) + { + case RES_SETEXPFLD: + nRet = ((SwSetExpField*)pFld)->GetValue(); + break; + case RES_USERFLD: + nRet = ((SwUserFieldType*)pFld)->GetValue(); + break; + case RES_TABLEFLD: + { + SwTblField* pTblFld = (SwTblField*)pFld; + if( !pTblFld->IsValid() ) // ist der Wert gueltig ?? + { + // die richtige Tabelle mitgeben! + const SwTable* pTmp = rCalcPara.pTbl; + rCalcPara.pTbl = &pTxtNd->FindTableNode()->GetTable(); + pTblFld->CalcField( rCalcPara ); + rCalcPara.pTbl = pTmp; + } + nRet = pTblFld->GetValue(); + } + break; + + case RES_DATETIMEFLD: + nRet = ((SwDateTimeField*)pFld)->GetValue(); + break; + + case RES_JUMPEDITFLD: + //JP 14.09.98: Bug 56112 - der Platzhalter kann nie einen + // gueltigen Inhalt haben! + nRet = 0; + break; + + default: + nRet = rCalcPara.rCalc.Calculate( pFld->Expand() ).GetDouble(); + } + } + else + { + // Ergebnis ist 0 und kein Fehler! + rCalcPara.rCalc.SetCalcError( CALC_NOERR ); // wieder zuruecksetzen + + double aNum; + String sTxt( rTxt.Copy( nSttPos ) ); + ULONG nFmtIndex = GetFrmFmt()->GetTblBoxNumFmt().GetValue(); + + SvNumberFormatter* pNumFmtr = pDoc->GetNumberFormatter(); + + if( NUMBERFORMAT_TEXT == nFmtIndex ) + nFmtIndex = 0; + // JP 22.04.98: Bug 49659 - Sonderbehandlung fuer Prozent + else if( sTxt.Len() && + NUMBERFORMAT_PERCENT == pNumFmtr->GetType( nFmtIndex )) + { + ULONG nTmpFmt = 0; + if( pNumFmtr->IsNumberFormat( sTxt, nTmpFmt, aNum ) && + NUMBERFORMAT_NUMBER == pNumFmtr->GetType( nTmpFmt )) + sTxt += '%'; + } + + if( pNumFmtr->IsNumberFormat( sTxt, nFmtIndex, aNum )) + nRet = aNum; + } + +// ?? sonst ist das ein Fehler + } while( FALSE ); + + if( !rCalcPara.IsStackOverFlow() ) + { + rCalcPara.pBoxStk->Remove( pBox ); // raus aus dem Stack + rCalcPara.DecStackCnt(); + } + + //JP 12.01.99: mit Fehlererkennung, Bug 60794 + if( DBL_MAX == nRet ) + rCalcPara.rCalc.SetCalcError( CALC_SYNTAX ); // Fehler setzen + + return nRet; +} + +/* */ + +// Struktur, die zum TabelleRechnen benoetigt wird + +SwTblCalcPara::SwTblCalcPara( SwCalc& rCalculator, const SwTable& rTable ) + : rCalc( rCalculator ), pTbl( &rTable ), nStackCnt( 0 ), + nMaxSize( cMAXSTACKSIZE ), pLastTblBox( 0 ) +{ + pBoxStk = new SwTableSortBoxes; +} + +SwTblCalcPara::~SwTblCalcPara() +{ + delete pBoxStk; +} + +BOOL SwTblCalcPara::CalcWithStackOverflow() +{ + // falls ein StackUeberlauf erkannt wurde, sollte mit + // der letzten Box noch mal aufgesetzt werden. Irgend + // ein Weg sollte dann + USHORT nSaveMaxSize = nMaxSize; + + nMaxSize = cMAXSTACKSIZE - 5; + USHORT nCnt = 0; + SwTableBoxes aStackOverFlows; + do { + SwTableBox* pBox = (SwTableBox*)pLastTblBox; + nStackCnt = 0; + rCalc.SetCalcError( CALC_NOERR ); + aStackOverFlows.C40_INSERT( SwTableBox, pBox, nCnt++ ); + + pBoxStk->Remove( pBox ); + pBox->GetValue( *this ); + } while( IsStackOverFlow() ); + + nMaxSize = cMAXSTACKSIZE - 3; // es muss mind. 1 Stufe tiefer gehen! + + // falls Rekursionen erkannt wurden + nStackCnt = 0; + rCalc.SetCalcError( CALC_NOERR ); + pBoxStk->Remove( USHORT(0), pBoxStk->Count() ); + + while( !rCalc.IsCalcError() && nCnt ) + { + aStackOverFlows[ --nCnt ]->GetValue( *this ); + if( IsStackOverFlow() && !CalcWithStackOverflow() ) + break; + } + + nMaxSize = nSaveMaxSize; + aStackOverFlows.Remove( 0, aStackOverFlows.Count() ); + return !rCalc.IsCalcError(); +} + +/* */ + +SwTableFormula::SwTableFormula( const String& rFormel ) + : sFormel( rFormel ) +{ + eNmType = EXTRNL_NAME; + bValidValue = FALSE; +} + +void SwTableFormula::_MakeFormel( const SwTable& rTbl, String& rNewStr, + String& rFirstBox, String* pLastBox, void* pPara ) const +{ + SwTblCalcPara* pCalcPara = (SwTblCalcPara*)pPara; + if( pCalcPara->rCalc.IsCalcError() ) // ist schon Fehler gesetzt ? + return; + + SwTableBox* pSttBox, *pEndBox = 0; + + rFirstBox.Erase(0,1); // Kennung fuer Box loeschen + // ein Bereich in dieser Klammer ? + if( pLastBox ) + { + //TODOUNICODE: does it work? +// pEndBox = (SwTableBox*)(long)(*pLastBox); + pEndBox = (SwTableBox*)pLastBox->ToInt32(); + + // ist das ueberhaupt ein gueltiger Pointer ?? + if( !rTbl.GetTabSortBoxes().Seek_Entry( pEndBox )) + pEndBox = 0; + rFirstBox.Erase( 0, pLastBox->Len()+1 ); + } + //TODOUNICODE: does it work? +// pSttBox = (SwTableBox*)(long)rFirstBox; + pSttBox = (SwTableBox*)rFirstBox.ToInt32(); + // ist das ueberhaupt ein gueltiger Pointer ?? + if( !rTbl.GetTabSortBoxes().Seek_Entry( pSttBox )) + pSttBox = 0; + + rNewStr += ' '; + if( pEndBox && pSttBox ) // Bereich ? + { + // hole ueber das Layout alle "selectierten" Boxen und berechne + // deren Werte + SwSelBoxes aBoxes; + GetBoxes( *pSttBox, *pEndBox, aBoxes ); + + rNewStr += '('; + for( USHORT n = 0; n < aBoxes.Count() && + !pCalcPara->rCalc.IsCalcError(); ++n ) + { + if( n ) + rNewStr += cListDelim; + rNewStr += pCalcPara->rCalc.GetStrResult( + aBoxes[n]->GetValue( *pCalcPara ), FALSE ); + } + rNewStr += ')'; + } + else if( pSttBox && !pLastBox ) // nur die StartBox ? + //JP 12.01.99: und keine EndBox in der Formel! + // Berechne den Wert der Box + rNewStr += pCalcPara->rCalc.GetStrResult( + pSttBox->GetValue( *pCalcPara ), FALSE ); + else + pCalcPara->rCalc.SetCalcError( CALC_SYNTAX ); // Fehler setzen + rNewStr += ' '; +} + +void SwTableFormula::RelNmsToBoxNms( const SwTable& rTbl, String& rNewStr, + String& rFirstBox, String* pLastBox, void* pPara ) const +{ + // relativen Namen zu Box-Namen (externe Darstellung) + SwNode* pNd = (SwNode*)pPara; + ASSERT( pNd, "Feld steht in keinem TextNode" ); + const SwTableBox *pRelBox, *pBox = (SwTableBox *)rTbl.GetTblBox( + pNd->FindTableBoxStartNode()->GetIndex() ); + + rNewStr += rFirstBox.Copy(0,1); // Kennung fuer Box erhalten + rFirstBox.Erase(0,1); + if( pLastBox ) + { + if( 0 != ( pRelBox = lcl_RelToBox( rTbl, pBox, *pLastBox )) ) + rNewStr += pRelBox->GetName(); + else + rNewStr.AppendAscii("A1"); + rNewStr += ':'; + rFirstBox.Erase( 0, pLastBox->Len()+1 ); + } + + if( 0 != ( pRelBox = lcl_RelToBox( rTbl, pBox, rFirstBox )) ) + rNewStr += pRelBox->GetName(); + else + rNewStr.AppendAscii("A1"); + + // Kennung fuer Box erhalten + rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 ); +} + +void SwTableFormula::RelBoxNmsToPtr( const SwTable& rTbl, String& rNewStr, + String& rFirstBox, String* pLastBox, void* pPara ) const +{ + // relativen Namen zu Box-Pointern (interne Darstellung) + SwNode* pNd = (SwNode*)pPara; + ASSERT( pNd, "Feld steht in keinem Node" ); + const SwTableBox *pRelBox, *pBox = (SwTableBox*)rTbl.GetTblBox( + pNd->FindTableBoxStartNode()->GetIndex() ); + + rNewStr += rFirstBox.Copy(0,1); // Kennung fuer Box erhalten + rFirstBox.Erase(0,1); + if( pLastBox ) + { + if( 0 != ( pRelBox = lcl_RelToBox( rTbl, pBox, *pLastBox )) ) + rNewStr += String::CreateFromInt32( (long)pRelBox ); + else + rNewStr += '0'; + rNewStr += ':'; + rFirstBox.Erase( 0, pLastBox->Len()+1 ); + } + + if( 0 != ( pRelBox = lcl_RelToBox( rTbl, pBox, rFirstBox )) ) + rNewStr += String::CreateFromInt32( (long)pRelBox ); + else + rNewStr += '0'; + + // Kennung fuer Box erhalten + rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 ); +} + + +void SwTableFormula::BoxNmsToRelNm( const SwTable& rTbl, String& rNewStr, + String& rFirstBox, String* pLastBox, void* pPara ) const +{ + // Box-Namen (externe Darstellung) zu relativen Namen + SwNode* pNd = (SwNode*)pPara; + ASSERT( pNd, "Feld steht in keinem Node" ); + const SwTableNode* pTblNd = pNd->FindTableNode(); + + String sRefBoxNm; + if( &pTblNd->GetTable() == &rTbl ) + { + const SwTableBox *pBox = rTbl.GetTblBox( + pNd->FindTableBoxStartNode()->GetIndex() ); + ASSERT( pBox, "Feld steht in keiner Tabelle" ); + sRefBoxNm = pBox->GetName(); + } + + rNewStr += rFirstBox.Copy(0,1); // Kennung fuer Box erhalten + rFirstBox.Erase(0,1); + if( pLastBox ) + { + rNewStr += lcl_BoxNmToRel( rTbl, *pTblNd, sRefBoxNm, *pLastBox, + eNmType == EXTRNL_NAME ); + rNewStr += ':'; + rFirstBox.Erase( 0, pLastBox->Len()+1 ); + } + + rNewStr += lcl_BoxNmToRel( rTbl, *pTblNd, sRefBoxNm, rFirstBox, + eNmType == EXTRNL_NAME ); + + // Kennung fuer Box erhalten + rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 ); +} + + +void SwTableFormula::PtrToBoxNms( const SwTable& rTbl, String& rNewStr, + String& rFirstBox, String* pLastBox, void* ) const +{ + // ein Bereich in dieser Klammer ? + SwTableBox* pBox; + + rNewStr += rFirstBox.Copy(0,1); // Kennung fuer Box erhalten + rFirstBox.Erase(0,1); + if( pLastBox ) + { +// pBox = (SwTableBox*)(long)(*pLastBox); + pBox = (SwTableBox*)pLastBox->ToInt32(); + + // ist das ueberhaupt ein gueltiger Pointer ?? + if( rTbl.GetTabSortBoxes().Seek_Entry( pBox )) + rNewStr += pBox->GetName(); + else + rNewStr += '?'; + rNewStr += ':'; + rFirstBox.Erase( 0, pLastBox->Len()+1 ); + } + +// pBox = (SwTableBox*)(long)rFirstBox; + pBox = (SwTableBox*)rFirstBox.ToInt32(); + // ist das ueberhaupt ein gueltiger Pointer ?? + if( rTbl.GetTabSortBoxes().Seek_Entry( pBox )) + rNewStr += pBox->GetName(); + else + rNewStr += '?'; + + // Kennung fuer Box erhalten + rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 ); +} + +void SwTableFormula::BoxNmsToPtr( const SwTable& rTbl, String& rNewStr, + String& rFirstBox, String* pLastBox, void* ) const +{ + // ein Bereich in dieser Klammer ? + const SwTableBox* pBox; + + rNewStr += rFirstBox.Copy(0,1); // Kennung fuer Box erhalten + rFirstBox.Erase(0,1); + if( pLastBox ) + { + pBox = rTbl.GetTblBox( *pLastBox ); + rNewStr += String::CreateFromInt32( (long)pBox ); + rNewStr += ':'; + rFirstBox.Erase( 0, pLastBox->Len()+1 ); + } + + pBox = rTbl.GetTblBox( rFirstBox ); + rNewStr += String::CreateFromInt32( (long)pBox ); + + // Kennung fuer Box erhalten + rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 ); +} + + // erzeuge die externe (fuer UI) Formel +void SwTableFormula::PtrToBoxNm( const SwTable* pTbl ) +{ + const SwNode* pNd = 0; + FnScanFormel fnFormel = 0; + switch( eNmType) + { + case INTRNL_NAME: + if( pTbl ) + fnFormel = &SwTableFormula::PtrToBoxNms; + break; + case REL_NAME: + if( pTbl ) + { + fnFormel = &SwTableFormula::RelNmsToBoxNms; + pNd = GetNodeOfFormula(); + } + break; + case EXTRNL_NAME: + return; + } + sFormel = ScanString( fnFormel, *pTbl, (void*)pNd ); + eNmType = EXTRNL_NAME; +} + + // erzeuge die interne (in CORE) Formel +void SwTableFormula::BoxNmToPtr( const SwTable* pTbl ) +{ + const SwNode* pNd = 0; + FnScanFormel fnFormel = 0; + switch( eNmType) + { + case EXTRNL_NAME: + if( pTbl ) + fnFormel = &SwTableFormula::BoxNmsToPtr; + break; + case REL_NAME: + if( pTbl ) + { + fnFormel = &SwTableFormula::RelBoxNmsToPtr; + pNd = GetNodeOfFormula(); + } + break; + case INTRNL_NAME: + return; + } + sFormel = ScanString( fnFormel, *pTbl, (void*)pNd ); + eNmType = INTRNL_NAME; +} + + // erzeuge die relative (fuers Kopieren) Formel +void SwTableFormula::ToRelBoxNm( const SwTable* pTbl ) +{ + const SwNode* pNd = 0; + FnScanFormel fnFormel = 0; + switch( eNmType) + { + case INTRNL_NAME: + case EXTRNL_NAME: + if( pTbl ) + { + fnFormel = &SwTableFormula::BoxNmsToRelNm; + pNd = GetNodeOfFormula(); + } + break; + case REL_NAME: + return; + } + sFormel = ScanString( fnFormel, *pTbl, (void*)pNd ); + eNmType = REL_NAME; +} + + +String SwTableFormula::ScanString( FnScanFormel fnFormel, const SwTable& rTbl, + void* pPara ) const +{ + String aStr; + USHORT nFml = 0, nStt = 0, nEnd = 0, nTrenner; + + do { + // falls der Formel ein Name vorangestellt ist, diese Tabelle + // benutzen !! + const SwTable* pTbl = &rTbl; + + nStt = sFormel.Search( '<', nFml ); + if( STRING_NOTFOUND != nStt ) + { + while( STRING_NOTFOUND != nStt && + ( ' ' == sFormel.GetChar( nStt + 1 ) || + '=' == sFormel.GetChar( nStt + 1 ) ) ) + nStt = sFormel.Search( '<', nStt + 1 ); + + if( STRING_NOTFOUND != nStt ) + nEnd = sFormel.Search( '>', nStt+1 ); + } + if( STRING_NOTFOUND == nStt || STRING_NOTFOUND == nEnd ) + { + // den Rest setzen und beenden + aStr.Insert( sFormel, nFml, sFormel.Len() - nFml ); + break; + } + aStr.Insert( sFormel, nFml, nStt - nFml ); // Anfang schreiben + + if( fnFormel != NULL ) + { + // ist ein TabellenName vorangestellt ?? + // JP 16.02.99: SplitMergeBoxNm behandeln den Namen selbst + // JP 22.02.99: der CAST muss fuer den Linux-Compiler sein + // JP 28.06.99: rel. BoxName have no preceding tablename! + if( fnFormel != (FnScanFormel)&SwTableFormula::_SplitMergeBoxNm && + 1 < sFormel.Len() && cRelKennung != sFormel.GetChar( 1 ) && + STRING_NOTFOUND != ( nTrenner = sFormel.Search( '.', nStt )) + && nTrenner < nEnd ) + { + String sTblNm( sFormel.Copy( nStt, nEnd - nStt )); + + // falls im Namen schon die Punkte enthalten sind, + // treten diese immer paarig auf!!! (A1.1.1 !!) + if( (sTblNm.GetTokenCount( '.' ) - 1 ) & 1 ) + { + sTblNm.Erase( nTrenner - nStt ); + + // beim Bauen der Formel ist der TabellenName unerwuenscht + //JP 22.02.99: der CAST muss fuer den Linux-Compiler sein + if( fnFormel != (FnScanFormel)&SwTableFormula::_MakeFormel ) + aStr += sTblNm; + nStt = nTrenner; + + sTblNm.Erase( 0, 1 ); // Trenner loeschen + if( sTblNm != rTbl.GetFrmFmt()->GetName() ) + { + // dann suchen wir uns mal unsere Tabelle: + const SwTable* pFnd = FindTable( + *rTbl.GetFrmFmt()->GetDoc(), + sTblNm ); + if( pFnd ) + pTbl = pFnd; + // ?? + ASSERT( pFnd, "Tabelle nicht gefunden, was nun?" ); + } + } + } + + String sBox( sFormel.Copy( nStt, nEnd - nStt + 1 )); + // ein Bereich in dieser Klammer ? + if( STRING_NOTFOUND != ( nTrenner = sFormel.Search( ':', nStt )) + && nTrenner < nEnd ) + { + // ohne die Anfangsklammer + String aFirstBox( sFormel.Copy( nStt+1, nTrenner - nStt - 1 )); + (this->*fnFormel)( *pTbl, aStr, sBox, &aFirstBox, pPara ); + } + else + (this->*fnFormel)( *pTbl, aStr, sBox, 0, pPara ); + } + + nFml = nEnd+1; + } while( TRUE ); + return aStr; +} + +const SwTable* SwTableFormula::FindTable( SwDoc& rDoc, const String& rNm ) const +{ + const SwFrmFmts& rTblFmts = *rDoc.GetTblFrmFmts(); + const SwTable* pTmpTbl, *pRet = 0; + for( USHORT nFmtCnt = rTblFmts.Count(); nFmtCnt; ) + { + SwFrmFmt* pFmt = rTblFmts[ --nFmtCnt ]; + // falls wir von Sw3Writer gerufen werden, dann ist dem + // FormatNamen eine Nummer anhaengig + SwTableBox* pFBox; + if( COMPARE_EQUAL == rNm.CompareTo( pFmt->GetName(), + pFmt->GetName().Search( 0x0a ) ) && + 0 != ( pTmpTbl = SwTable::FindTable( pFmt ) ) && + 0 != (pFBox = pTmpTbl->GetTabSortBoxes()[0] ) && + pFBox->GetSttNd() && + pFBox->GetSttNd()->GetNodes().IsDocNodes() ) + { + // eine Tabelle im normalen NodesArr + pRet = pTmpTbl; + break; + } + } + return pRet; +} + +/* */ + +const SwFrm* lcl_GetBoxFrm( const SwTableBox& rBox ) +{ +/* + + // oder besser ueber die Box den Frame suchen + + SwClientIter aIter( *pBox->GetFrmFmt() ); + ULONG nMinPos = ULONG_MAX; + const SwFrm* pFnd = 0; + for( SwFrm* pF = (SwFrm*)aIter.First( TYPE( SwCellFrm )); pF; + pF = (SwFrm*)aIter.Next() ) + { + if( pF->Frm().Y() < + } +*/ + + SwNodeIndex aIdx( *rBox.GetSttNd() ); + SwCntntNode* pCNd = aIdx.GetNodes().GoNext( &aIdx ); + ASSERT( pCNd, "Box hat keinen TextNode" ); + Point aPt; // den im Layout 1. Frame returnen - Tab.Kopfzeile !! + return pCNd->GetFrm( &aPt, NULL, FALSE ); +} + +long lcl_GetLongBoxNum( String& rStr ) +{ + USHORT nPos; + long nRet; + if( STRING_NOTFOUND == ( nPos = rStr.Search( cRelTrenner ) )) + { + nRet = rStr.ToInt32(); + rStr.Erase(); + } + else + { + nRet = rStr.Copy( 0, nPos ).ToInt32(); + rStr.Erase( 0, nPos+1 ); + } + return nRet; +} + +const SwTableBox* lcl_RelToBox( const SwTable& rTbl, + const SwTableBox* pRefBox, + const String& rGetName ) +{ + // hole die Line + const SwTableBox* pBox = 0; + String sGetName( rGetName ); + + // ist es denn wirklich eine relative Angabe?? + if( cRelKennung == sGetName.GetChar(0) ) // ja, ... + { + if( !pRefBox ) + return 0; + + sGetName.Erase( 0, 1 ); + + const SwTableLines* pLines = (SwTableLines*)&rTbl.GetTabLines(); + const SwTableBoxes* pBoxes; + const SwTableLine* pLine; + + // bestimme erst mal die Start-Werte der Box: + pBox = (SwTableBox*)pRefBox; + pLine = pBox->GetUpper(); + while( pLine->GetUpper() ) + { + pBox = pLine->GetUpper(); + pLine = pBox->GetUpper(); + } + USHORT nSttBox = pLine->GetTabBoxes().GetPos( pBox ); + USHORT nSttLine = rTbl.GetTabLines().GetPos( pLine ); + + long nBoxOffset = lcl_GetLongBoxNum( sGetName ) + nSttBox; + long nLineOffset = lcl_GetLongBoxNum( sGetName ) + nSttLine; + + if( nBoxOffset < 0 || nBoxOffset >= USHRT_MAX || + nLineOffset < 0 || nLineOffset >= USHRT_MAX ) + return 0; + + if( nLineOffset >= long(pLines->Count()) ) + return 0; + + pLine = (*pLines)[ USHORT(nLineOffset) ]; + + // dann suche die Box + pBoxes = &pLine->GetTabBoxes(); + if( nBoxOffset >= long(pBoxes->Count()) ) + return 0; + pBox = (*pBoxes)[ USHORT(nBoxOffset) ]; + + while( sGetName.Len() ) + { + nSttBox = SwTable::_GetBoxNum( sGetName ); + pLines = &pBox->GetTabLines(); + if( nSttBox ) + --nSttBox; + + nSttLine = SwTable::_GetBoxNum( sGetName ); + + // bestimme die Line + if( !nSttLine || nSttLine > pLines->Count() ) + break; + pLine = (*pLines)[ nSttLine-1 ]; + + // bestimme die Box + pBoxes = &pLine->GetTabBoxes(); + if( nSttBox >= pBoxes->Count() ) + break; + pBox = (*pBoxes)[ nSttBox ]; + } + + if( pBox ) + { + if( !pBox->GetSttNd() ) + // "herunterfallen lassen" bis zur ersten Box + while( pBox->GetTabLines().Count() ) + pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0]; + } + } + else + { + // sonst ist es eine absolute externe Darstellung: + pBox = rTbl.GetTblBox( sGetName ); + } + return pBox; +} + +String lcl_BoxNmToRel( const SwTable& rTbl, const SwTableNode& rTblNd, + const String& rRefBoxNm, const String& rGetStr, + BOOL bExtrnlNm ) +{ + String sCpy( rRefBoxNm ); + String sTmp( rGetStr ); + if( !bExtrnlNm ) + { + // in die Externe Darstellung umwandeln. +// SwTableBox* pBox = (SwTableBox*)(long)sTmp; + SwTableBox* pBox = (SwTableBox*)sTmp.ToInt32(); + if( !rTbl.GetTabSortBoxes().Seek_Entry( pBox )) + return '?'; + sTmp = pBox->GetName(); + } + + // sollte die es eine Tabellen uebergreifende Formel sein, dann behalte + // die externe Darstellung bei: + if( &rTbl == &rTblNd.GetTable() ) + { + long nBox = SwTable::_GetBoxNum( sTmp, TRUE ); + nBox -= SwTable::_GetBoxNum( sCpy, TRUE ); + long nLine = SwTable::_GetBoxNum( sTmp ); + nLine -= SwTable::_GetBoxNum( sCpy ); + + sCpy = sTmp; //JP 01.11.95: den Rest aus dem BoxNamen anhaengen + + sTmp = cRelKennung; + sTmp += String::CreateFromInt32( nBox ); + sTmp += cRelTrenner; + sTmp += String::CreateFromInt32( nLine ); + + if( sCpy.Len() ) + { + sTmp += cRelTrenner; + sTmp += sCpy; + } + } + + if( sTmp.Len() && '>' == sTmp.GetChar( sTmp.Len() - 1 )) + sTmp.Erase( sTmp.Len()-1 ); + + return sTmp; +} + +USHORT SwTableFormula::GetBoxesOfFormula( const SwTable& rTbl, + SwSelBoxes& rBoxes ) +{ + if( rBoxes.Count() ) + rBoxes.Remove( USHORT(0), rBoxes.Count() ); + + BoxNmToPtr( &rTbl ); + ScanString( &SwTableFormula::_GetFmlBoxes, rTbl, &rBoxes ); + return rBoxes.Count(); +} + +void SwTableFormula::_GetFmlBoxes( const SwTable& rTbl, String& rNewStr, + String& rFirstBox, String* pLastBox, void* pPara ) const +{ + SwSelBoxes* pBoxes = (SwSelBoxes*)pPara; + SwTableBox* pSttBox, *pEndBox = 0; + + rFirstBox.Erase(0,1); // Kennung fuer Box loeschen + // ein Bereich in dieser Klammer ? + if( pLastBox ) + { +// pEndBox = (SwTableBox*)(long)(*pLastBox); + pEndBox = (SwTableBox*)pLastBox->ToInt32(); + + // ist das ueberhaupt ein gueltiger Pointer ?? + if( !rTbl.GetTabSortBoxes().Seek_Entry( pEndBox )) + pEndBox = 0; + rFirstBox.Erase( 0, pLastBox->Len()+1 ); + } + +// pSttBox = (SwTableBox*)(long)rFirstBox; + pSttBox = (SwTableBox*)rFirstBox.ToInt32(); + // ist das ueberhaupt ein gueltiger Pointer ?? + if( !rTbl.GetTabSortBoxes().Seek_Entry( pSttBox )) + pSttBox = 0; + + if( pEndBox && pSttBox ) // Bereich ? + { + // ueber das Layout alle "selectierten" Boxen und berechne + // deren Werte + SwSelBoxes aBoxes; + GetBoxes( *pSttBox, *pEndBox, aBoxes ); + pBoxes->Insert( &aBoxes ); + } + else if( pSttBox ) // nur die StartBox ? + pBoxes->Insert( pSttBox ); +} + +void SwTableFormula::GetBoxes( const SwTableBox& rSttBox, + const SwTableBox& rEndBox, + SwSelBoxes& rBoxes ) const +{ + // hole ueber das Layout alle "selektierten" Boxen + const SwLayoutFrm *pStt, *pEnd; + const SwFrm* pFrm = lcl_GetBoxFrm( rSttBox ); + pStt = pFrm ? pFrm->GetUpper() : 0; + pEnd = ( 0 != (pFrm = lcl_GetBoxFrm( rEndBox ))) ? pFrm->GetUpper() : 0; + if( !pStt || !pEnd ) + return ; // no valid selection + + GetTblSel( pStt, pEnd, rBoxes ); + + const SwTable* pTbl = pStt->FindTabFrm()->GetTable(); + + // filter die Kopfzeilen-Boxen heraus: + if( pTbl->IsHeadlineRepeat() ) + do { // middle-check loop + const SwTableLine* pHeadLine = pTbl->GetTabLines()[0]; + const SwTableLine* pLine = rSttBox.GetUpper(); + while( pLine->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + + if( pLine == pHeadLine ) + break; // Headline mit im Bereich ! + // vielleicht ist ja Start und Ende vertauscht + pLine = rEndBox.GetUpper(); + while ( pLine->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + if( pLine == pHeadLine ) + break; // Headline mit im Bereich ! + + const SwTabFrm *pTable = pStt->FindTabFrm(); + const SwTabFrm *pEndTable = pEnd->FindTabFrm(); + if( pTable == pEndTable ) // keine gespl. Tabelle + break; + + // dann mal die Tabellenkoepfe raus: + for( USHORT n = 0; n < rBoxes.Count(); ++n ) + { + while( (pLine = rBoxes[n]->GetUpper())->GetUpper() ) + pLine = pLine->GetUpper()->GetUpper(); + + if( pLine == pHeadLine ) + rBoxes.Remove( n--, 1 ); + } + } while( FALSE ); +} + + // sind alle Boxen gueltig, auf die sich die Formel bezieht? +void SwTableFormula::_HasValidBoxes( const SwTable& rTbl, String& rNewStr, + String& rFirstBox, String* pLastBox, void* pPara ) const +{ + BOOL* pBValid = (BOOL*)pPara; + if( *pBValid ) // einmal falsch, immer falsch + { + SwTableBox* pSttBox, *pEndBox = 0; + rFirstBox.Erase(0,1); // Kennung fuer Box loeschen + + // ein Bereich in dieser Klammer ? + if( pLastBox ) + rFirstBox.Erase( 0, pLastBox->Len()+1 ); + + switch( eNmType) + { + case INTRNL_NAME: + if( pLastBox ) + { +// pEndBox = (SwTableBox*)(long)(*pLastBox); + pEndBox = (SwTableBox*)pLastBox->ToInt32(); + } +// pSttBox = (SwTableBox*)(long)rFirstBox; + pSttBox = (SwTableBox*)rFirstBox.ToInt32(); + break; + + case REL_NAME: + { + const SwNode* pNd = GetNodeOfFormula(); + const SwTableBox* pBox = !pNd ? 0 + : (SwTableBox *)rTbl.GetTblBox( + pNd->FindTableBoxStartNode()->GetIndex() ); + if( pLastBox ) + pEndBox = (SwTableBox*)lcl_RelToBox( rTbl, pBox, *pLastBox ); + pSttBox = (SwTableBox*)lcl_RelToBox( rTbl, pBox, rFirstBox ); + } + break; + + case EXTRNL_NAME: + if( pLastBox ) + pEndBox = (SwTableBox*)rTbl.GetTblBox( *pLastBox ); + pSttBox = (SwTableBox*)rTbl.GetTblBox( rFirstBox ); + break; + } + + // sind das gueltige Pointer ? + if( ( pLastBox && + ( !pEndBox || !rTbl.GetTabSortBoxes().Seek_Entry( pEndBox ) ) ) || + ( !pSttBox || !rTbl.GetTabSortBoxes().Seek_Entry( pSttBox ) ) ) + *pBValid = FALSE; + } +} + +BOOL SwTableFormula::HasValidBoxes() const +{ + BOOL bRet = TRUE; + const SwNode* pNd = GetNodeOfFormula(); + if( pNd && 0 != ( pNd = pNd->FindTableNode() ) ) + ScanString( &SwTableFormula::_HasValidBoxes, + ((SwTableNode*)pNd)->GetTable(), &bRet ); + return bRet; +} + + +USHORT SwTableFormula::GetLnPosInTbl( const SwTable& rTbl, const SwTableBox* pBox ) +{ + USHORT nRet = USHRT_MAX; + if( pBox ) + { + const SwTableLine* pLn = pBox->GetUpper(); + while( pLn->GetUpper() ) + pLn = pLn->GetUpper()->GetUpper(); + nRet = rTbl.GetTabLines().GetPos( pLn ); + } + return nRet; +} + +void SwTableFormula::_SplitMergeBoxNm( const SwTable& rTbl, String& rNewStr, + String& rFirstBox, String* pLastBox, void* pPara ) const +{ + SwTableFmlUpdate& rTblUpd = *(SwTableFmlUpdate*)pPara; + + rNewStr += rFirstBox.Copy(0,1); // Kennung fuer Box erhalten + rFirstBox.Erase(0,1); + + String sTblNm; + const SwTable* pTbl = &rTbl; + + String* pTblNmBox = pLastBox ? pLastBox : &rFirstBox; + + USHORT nLastBoxLen = pTblNmBox->Len(); + USHORT nTrenner = pTblNmBox->Search( '.' ); + if( STRING_NOTFOUND != nTrenner && + // falls im Namen schon die Punkte enthalten sind, + // treten diese immer paarig auf!!! (A1.1.1 !!) + (pTblNmBox->GetTokenCount( '.' ) - 1 ) & 1 ) + { + sTblNm = pTblNmBox->Copy( 0, nTrenner ); + pTblNmBox->Erase( 0, nTrenner + 1);// den Punkt entfernen + const SwTable* pFnd = FindTable( *rTbl.GetFrmFmt()->GetDoc(), sTblNm ); + if( pFnd ) + pTbl = pFnd; + + if( TBL_MERGETBL == rTblUpd.eFlags ) + { + if( pFnd ) + { + if( pFnd == rTblUpd.DATA.pDelTbl ) + { + if( rTblUpd.pTbl != &rTbl ) // es ist nicht die akt. + (rNewStr += rTblUpd.pTbl->GetFrmFmt()->GetName() ) + += '.'; // den neuen Tabellen Namen setzen + rTblUpd.bModified = TRUE; + } + else if( pFnd != rTblUpd.pTbl || + ( rTblUpd.pTbl != &rTbl && &rTbl != rTblUpd.DATA.pDelTbl)) + (rNewStr += sTblNm ) += '.'; // den Tabellen Namen behalten + else + rTblUpd.bModified = TRUE; + } + else + (rNewStr += sTblNm ) += '.'; // den Tabellen Namen behalten + + } + } + if( pTblNmBox == pLastBox ) + rFirstBox.Erase( 0, nLastBoxLen + 1 ); + + SwTableBox* pSttBox, *pEndBox = 0; + switch( eNmType ) + { + case INTRNL_NAME: + if( pLastBox ) + { +// pEndBox = (SwTableBox*)(long)(*pLastBox); + pEndBox = (SwTableBox*)pLastBox->ToInt32(); + } +// pSttBox = (SwTableBox*)(long)rFirstBox; + pSttBox = (SwTableBox*)rFirstBox.ToInt32(); + break; + + case REL_NAME: + { + const SwNode* pNd = GetNodeOfFormula(); + const SwTableBox* pBox = pNd ? pTbl->GetTblBox( + pNd->FindTableBoxStartNode()->GetIndex() ) : 0; + if( pLastBox ) + pEndBox = (SwTableBox*)lcl_RelToBox( *pTbl, pBox, *pLastBox ); + pSttBox = (SwTableBox*)lcl_RelToBox( *pTbl, pBox, rFirstBox ); + } + break; + + case EXTRNL_NAME: + if( pLastBox ) + pEndBox = (SwTableBox*)pTbl->GetTblBox( *pLastBox ); + pSttBox = (SwTableBox*)pTbl->GetTblBox( rFirstBox ); + break; + } + + if( pLastBox && !pTbl->GetTabSortBoxes().Seek_Entry( pEndBox )) + pEndBox = 0; + if( !pTbl->GetTabSortBoxes().Seek_Entry( pSttBox )) + pSttBox = 0; + + if( TBL_SPLITTBL == rTblUpd.eFlags ) + { + // wo liegen die Boxen, in der "alten" oder in der neuen Tabelle? + BOOL bInNewTbl = FALSE; + if( pLastBox ) + { + // das ist die "erste" Box in der Selektion. Die bestimmt ob die + // Formel in der alten oder neuen Tabelle steht. + USHORT nEndLnPos = SwTableFormula::GetLnPosInTbl( *pTbl, pEndBox ), + nSttLnPos = SwTableFormula::GetLnPosInTbl( *pTbl, pSttBox ); + + if( USHRT_MAX != nSttLnPos && USHRT_MAX != nEndLnPos && + rTblUpd.nSplitLine <= nSttLnPos == + rTblUpd.nSplitLine <= nEndLnPos ) + { + // bleiben in der gleichen Tabelle + bInNewTbl = rTblUpd.nSplitLine <= nEndLnPos && + pTbl == rTblUpd.pTbl; + } + else + { + // das ist aufjedenfall eine ungueltige Formel, also fuers + // Undo auf Modified setzen + rTblUpd.bModified = TRUE; + if( pEndBox ) + bInNewTbl = USHRT_MAX != nEndLnPos && + rTblUpd.nSplitLine <= nEndLnPos && + pTbl == rTblUpd.pTbl; + } + } + else + { + USHORT nSttLnPos = SwTableFormula::GetLnPosInTbl( *pTbl, pSttBox ); + // dann landet das Teil in der neuen Tabelle? + bInNewTbl = USHRT_MAX != nSttLnPos && + rTblUpd.nSplitLine <= nSttLnPos && + pTbl == rTblUpd.pTbl; + } + + // wenn die Formel selbst in der neuen Tabellen landet + if( rTblUpd.bBehindSplitLine ) + { + if( !bInNewTbl ) + { + rTblUpd.bModified = TRUE; + ( rNewStr += rTblUpd.pTbl->GetFrmFmt()->GetName() ) += '.'; + } + else if( sTblNm.Len() ) + ( rNewStr += sTblNm ) += '.'; + } + else if( bInNewTbl ) + { + rTblUpd.bModified = TRUE; + ( rNewStr += *rTblUpd.DATA.pNewTblNm ) += '.'; + } + else if( sTblNm.Len() ) + ( rNewStr += sTblNm ) += '.'; + } + + if( pLastBox ) + ( rNewStr += String::CreateFromInt32((long)pEndBox )) += ':'; + ( rNewStr += String::CreateFromInt32((long)pSttBox )) + += rFirstBox.GetChar( rFirstBox.Len() - 1 ); +} + + // erzeuge die externe Formel, beachte aber das die Formel + // in einer gesplitteten/gemergten Tabelle landet +void SwTableFormula::ToSplitMergeBoxNm( SwTableFmlUpdate& rTblUpd ) +{ + const SwTable* pTbl; + const SwNode* pNd = GetNodeOfFormula(); + if( pNd && 0 != ( pNd = pNd->FindTableNode() )) + pTbl = &((SwTableNode*)pNd)->GetTable(); + else + pTbl = rTblUpd.pTbl; + + sFormel = ScanString( &SwTableFormula::_SplitMergeBoxNm, *pTbl, (void*)&rTblUpd ); + eNmType = INTRNL_NAME; +} + + |