/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/


#ifdef _MSC_VER
#pragma hdrstop
#endif

#include <float.h>

#include <fmtfld.hxx>
#include <txtfld.hxx>
#include <frmfmt.hxx>
#include <cntfrm.hxx>
#include <tabfrm.hxx>

#include <horiornt.hxx>

#include <doc.hxx>
#include <ndtxt.hxx>
#include <tblsel.hxx>
#include <cellfml.hxx>
#include <calc.hxx>
#include <expfld.hxx>
#include <usrfld.hxx>
#include <flddat.hxx>
#include <cellatr.hxx>
#include <ndindex.hxx>
#include <hints.hxx>
namespace binfilter {

const sal_Unicode cRelTrenner = ',';
const sal_Unicode cRelKennung = '';        // CTRL-R

const USHORT cMAXSTACKSIZE = 50;

/*N*/ const SwFrm* lcl_GetBoxFrm( const SwTableBox& rBox );


/*************************************************************************
|*
|*  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 ?)
|*
|*************************************************************************/

/*N*/ double SwTableBox::GetValue( SwTblCalcPara& rCalcPara ) const
/*N*/ {
/*N*/   double nRet = 0;
/*N*/
/*N*/   if( rCalcPara.rCalc.IsCalcError() )
/*?*/       return nRet;            // schon ein Fehler in der Berechnung
/*N*/
/*N*/   rCalcPara.rCalc.SetCalcError( CALC_SYNTAX );    // default immer Fehler
/*N*/
/*N*/   // keine Content Box ?
/*N*/   if( !pSttNd  )
/*?*/       return nRet;
/*N*/
/*N*/   if( rCalcPara.IncStackCnt() )
/*?*/       return nRet;
/*N*/
/*N*/   rCalcPara.SetLastTblBox( this );
/*N*/
/*N*/   // wird eine Rekursion erzeugt ?
/*N*/   SwTableBox* pBox = (SwTableBox*)this;
/*N*/   if( rCalcPara.pBoxStk->Seek_Entry( pBox ))
/*?*/       return nRet;            // steht schon auf dem Stack: FEHLER
/*N*/
/*N*/   // bei dieser Box nochmal aufsetzen
/*N*/   rCalcPara.SetLastTblBox( this );
/*N*/
/*N*/   rCalcPara.pBoxStk->Insert( pBox );      // eintragen
/*N*/   do {        // Middle-Check-Loop, damit aus dieser gesprungen werden kann
/*N*/               // hier aufgespannt, damit am Ende der Box-Pointer aus dem
/*N*/               // Stack ausgetragen wird
/*N*/       SwDoc* pDoc = GetFrmFmt()->GetDoc();
/*N*/
/*N*/       const SfxPoolItem* pItem;
/*N*/       if( SFX_ITEM_SET == GetFrmFmt()->GetItemState(
/*N*/                               RES_BOXATR_FORMULA, FALSE, &pItem ) )
/*N*/       {
/*?*/           rCalcPara.rCalc.SetCalcError( CALC_NOERR ); // wieder zuruecksetzen
/*?*/           if( ((SwTblBoxFormula*)pItem)->IsValid() )
/*?*/               nRet = GetFrmFmt()->GetTblBoxValue().GetValue();
/*?*/           break;
/*N*/       }
/*N*/       else if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetItemState(
/*N*/                               RES_BOXATR_VALUE, FALSE, &pItem ) )
/*N*/       {
/*?*/           rCalcPara.rCalc.SetCalcError( CALC_NOERR ); // wieder zuruecksetzen
/*?*/           nRet = ((SwTblBoxValue*)pItem)->GetValue();
/*?*/           break;
/*N*/       }
/*N*/
/*N*/       SwTxtNode* pTxtNd = pDoc->GetNodes()[ pSttNd->GetIndex() + 1 ]->GetTxtNode();
/*N*/       if( !pTxtNd )
/*?*/           break;
/*N*/
/*N*/       xub_StrLen nSttPos = 0;
/*N*/       const String& rTxt = pTxtNd->GetTxt();
/*N*/       while( nSttPos < rTxt.Len() &&
/*N*/               ( ' ' ==  rTxt.GetChar( nSttPos ) || '\t' ==  rTxt.GetChar( nSttPos ) ) )
/*?*/           ++nSttPos;
/*N*/
/*N*/       // beginnt an erster Position ein "RechenFeld", dann erfrage den Wert
/*N*/       // von diesem
/*N*/       sal_Unicode cChr;
/*N*/       if( nSttPos < rTxt.Len() &&
/*N*/           ( CH_TXTATR_BREAKWORD == ( cChr = rTxt.GetChar(nSttPos)) ||
/*N*/             CH_TXTATR_INWORD == cChr ))
/*N*/       {
/*N*/           SwIndex aIdx( pTxtNd, nSttPos );
/*N*/           SwTxtFld* pTxtFld = pTxtNd->GetTxtFld( aIdx );
/*N*/           if( !pTxtFld )
/*?*/               break;
/*N*/
/*N*/           rCalcPara.rCalc.SetCalcError( CALC_NOERR ); // wieder zuruecksetzen
/*N*/
/*N*/           const SwField* pFld = pTxtFld->GetFld().GetFld();
/*N*/           switch( pFld->GetTyp()->Which()  )
/*N*/           {
/*N*/           case RES_SETEXPFLD:
/*?*/               nRet = ((SwSetExpField*)pFld)->GetValue();
/*?*/               break;
/*?*/           case RES_USERFLD:
/*?*/               nRet = ((SwUserFieldType*)pFld)->GetValue();
/*?*/               break;
/*N*/           case RES_TABLEFLD:
/*N*/               {
/*N*/                   SwTblField* pTblFld = (SwTblField*)pFld;
/*N*/                   if( !pTblFld->IsValid() )       // ist der Wert gueltig ??
/*N*/                   {
/*N*/                       // die richtige Tabelle mitgeben!
/*N*/                       const SwTable* pTmp = rCalcPara.pTbl;
/*N*/                       rCalcPara.pTbl = &pTxtNd->FindTableNode()->GetTable();
/*N*/                       pTblFld->CalcField( rCalcPara );
/*N*/                       rCalcPara.pTbl = pTmp;
/*N*/                   }
/*N*/                   nRet = pTblFld->GetValue();
/*N*/               }
/*N*/               break;
/*N*/
/*N*/           case RES_DATETIMEFLD:
/*?*/               nRet = ((SwDateTimeField*)pFld)->GetValue();
/*?*/               break;
/*?*/
/*?*/           case RES_JUMPEDITFLD:
/*?*/               nRet = 0;
/*?*/               break;
/*?*/
/*?*/           default:
/*?*/               nRet = rCalcPara.rCalc.Calculate( pFld->Expand() ).GetDouble();
/*N*/           }
/*N*/       }
/*N*/       else
/*N*/       {
/*N*/           // Ergebnis ist 0 und kein Fehler!
/*N*/           rCalcPara.rCalc.SetCalcError( CALC_NOERR ); // wieder zuruecksetzen
/*N*/
/*N*/           double aNum;
/*N*/           String sTxt( rTxt.Copy( nSttPos ) );
/*N*/           sal_uInt32 nFmtIndex = GetFrmFmt()->GetTblBoxNumFmt().GetValue();
/*N*/
/*N*/           SvNumberFormatter* pNumFmtr = pDoc->GetNumberFormatter();
/*N*/
/*N*/           if( NUMBERFORMAT_TEXT == nFmtIndex )
/*N*/               nFmtIndex = 0;
/*N*/           // JP 22.04.98: Bug 49659 - Sonderbehandlung fuer Prozent
/*?*/           else if( sTxt.Len() &&
/*?*/                   NUMBERFORMAT_PERCENT == pNumFmtr->GetType( nFmtIndex ))
/*?*/           {
/*?*/               sal_uInt32 nTmpFmt = 0;
/*?*/               if( pNumFmtr->IsNumberFormat( sTxt, nTmpFmt, aNum ) &&
/*?*/                   NUMBERFORMAT_NUMBER == pNumFmtr->GetType( nTmpFmt ))
/*?*/                   sTxt += '%';
/*?*/           }
/*N*/
/*N*/           if( pNumFmtr->IsNumberFormat( sTxt, nFmtIndex, aNum ))
/*N*/               nRet = aNum;
/*N*/       }
/*N*/
/*N*/ // ?? sonst ist das ein Fehler
/*N*/   } while( FALSE );
/*N*/
/*N*/   if( !rCalcPara.IsStackOverFlow() )
/*N*/   {
/*N*/       rCalcPara.pBoxStk->Remove( pBox );      // raus aus dem Stack
/*N*/       rCalcPara.DecStackCnt();
/*N*/   }
/*N*/
/*N*/   //JP 12.01.99: mit Fehlererkennung, Bug 60794
/*N*/   if( DBL_MAX == nRet )
/*?*/       rCalcPara.rCalc.SetCalcError( CALC_SYNTAX );    // Fehler setzen
/*N*/
/*N*/   return nRet;
/*N*/ }


// Struktur, die zum TabelleRechnen benoetigt wird

/*N*/ SwTblCalcPara::SwTblCalcPara( SwCalc& rCalculator, const SwTable& rTable )
/*N*/   : pLastTblBox( 0 )
/*N*/   , nStackCnt( 0 )
/*N*/   , nMaxSize( cMAXSTACKSIZE )
/*N*/   , rCalc( rCalculator )
/*N*/   , pTbl( &rTable )
/*N*/ {
/*N*/   pBoxStk = new SwTableSortBoxes;
/*N*/ }

/*N*/ SwTblCalcPara::~SwTblCalcPara()
/*N*/ {
/*N*/   delete pBoxStk;
/*N*/ }



/*N*/ SwTableFormula::SwTableFormula( const String& rFormel )
/*N*/   : sFormel( rFormel )
/*N*/ {
/*N*/   eNmType = EXTRNL_NAME;
/*N*/   bValidValue = FALSE;
/*N*/ }

/*N*/ void SwTableFormula::_MakeFormel( const SwTable& rTbl, String& rNewStr,
/*N*/                   String& rFirstBox, String* pLastBox, void* pPara ) const
/*N*/ {
/*N*/   SwTblCalcPara* pCalcPara = (SwTblCalcPara*)pPara;
/*N*/   if( pCalcPara->rCalc.IsCalcError() )        // ist schon Fehler gesetzt ?
/*?*/       return;
/*N*/
/*N*/   SwTableBox* pSttBox, *pEndBox = 0;
/*N*/
/*N*/   rFirstBox.Erase(0,1);       // Kennung fuer Box loeschen
/*N*/   // ein Bereich in dieser Klammer ?
/*N*/   if( pLastBox )
/*N*/   {
/*N*/       pEndBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->ToInt64()));
/*N*/
/*N*/       // ist das ueberhaupt ein gueltiger Pointer ??
/*N*/       if( !rTbl.GetTabSortBoxes().Seek_Entry( pEndBox ))
/*?*/           pEndBox = 0;
/*N*/       rFirstBox.Erase( 0, pLastBox->Len()+1 );
/*N*/   }
/*N*/   pSttBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.ToInt64()));
/*N*/   // ist das ueberhaupt ein gueltiger Pointer ??
/*N*/   if( !rTbl.GetTabSortBoxes().Seek_Entry( pSttBox ))
/*?*/       pSttBox = 0;
/*N*/
/*N*/   rNewStr += ' ';
/*N*/   if( pEndBox && pSttBox )    // Bereich ?
/*N*/   {
/*N*/       // hole ueber das Layout alle "selectierten" Boxen und berechne
/*N*/       // deren Werte
/*N*/       SwSelBoxes aBoxes;
/*N*/       GetBoxes( *pSttBox, *pEndBox, aBoxes );
/*N*/
/*N*/       rNewStr += '(';
/*N*/       for( USHORT n = 0; n < aBoxes.Count() &&
/*N*/                          !pCalcPara->rCalc.IsCalcError(); ++n )
/*N*/       {
/*N*/           if( n )
/*N*/               rNewStr += cListDelim;
/*N*/           rNewStr += pCalcPara->rCalc.GetStrResult(
/*N*/                       aBoxes[n]->GetValue( *pCalcPara ), FALSE );
/*N*/       }
/*N*/       rNewStr += ')';
/*N*/   }
/*N*/   else if( pSttBox && !pLastBox )         // nur die StartBox ?
/*N*/                           //JP 12.01.99: und keine EndBox in der Formel!
/*N*/       // Berechne den Wert der Box
/*N*/       rNewStr += pCalcPara->rCalc.GetStrResult(
/*N*/                           pSttBox->GetValue( *pCalcPara ), FALSE );
/*N*/   else
/*?*/       pCalcPara->rCalc.SetCalcError( CALC_SYNTAX );   // Fehler setzen
/*N*/   rNewStr += ' ';
/*N*/ }

/*N*/ void SwTableFormula::PtrToBoxNms( const SwTable& rTbl, String& rNewStr,
/*N*/                       String& rFirstBox, String* pLastBox, void* ) const
/*N*/ {
/*N*/   // ein Bereich in dieser Klammer ?
/*N*/   SwTableBox* pBox;
/*N*/
/*N*/   rNewStr += rFirstBox.Copy(0,1);     // Kennung fuer Box erhalten
/*N*/   rFirstBox.Erase(0,1);
/*N*/   if( pLastBox )
/*N*/   {
/*N*/       pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(pLastBox->ToInt64()));
/*N*/
/*N*/       // ist das ueberhaupt ein gueltiger Pointer ??
/*N*/       if( rTbl.GetTabSortBoxes().Seek_Entry( pBox ))
/*N*/           rNewStr += pBox->GetName();
/*N*/       else
/*N*/           rNewStr += '?';
/*N*/       rNewStr += ':';
/*N*/       rFirstBox.Erase( 0, pLastBox->Len()+1 );
/*N*/   }
/*N*/
/*N*/   pBox = reinterpret_cast<SwTableBox*>(sal::static_int_cast<sal_IntPtr>(rFirstBox.ToInt64()));
/*N*/   // ist das ueberhaupt ein gueltiger Pointer ??
/*N*/   if( rTbl.GetTabSortBoxes().Seek_Entry( pBox ))
/*N*/       rNewStr += pBox->GetName();
/*N*/   else
/*N*/       rNewStr += '?';
/*N*/
/*N*/   // Kennung fuer Box erhalten
/*N*/   rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 );
/*N*/ }

/*N*/ void SwTableFormula::BoxNmsToPtr( const SwTable& rTbl, String& rNewStr,
/*N*/                       String& rFirstBox, String* pLastBox, void* ) const
/*N*/ {
/*N*/   // ein Bereich in dieser Klammer ?
/*N*/   const SwTableBox* pBox;
/*N*/
/*N*/   rNewStr += rFirstBox.Copy(0,1);     // Kennung fuer Box erhalten
/*N*/   rFirstBox.Erase(0,1);
/*N*/   if( pLastBox )
/*N*/   {
/*N*/       pBox = rTbl.GetTblBox( *pLastBox );
/*N*/       rNewStr += String::CreateFromInt64( (sal_PtrDiff)pBox );
/*N*/       rNewStr += ':';
/*N*/       rFirstBox.Erase( 0, pLastBox->Len()+1 );
/*N*/   }
/*N*/
/*N*/   pBox = rTbl.GetTblBox( rFirstBox );
/*N*/   rNewStr += String::CreateFromInt64( (sal_PtrDiff)pBox );
/*N*/
/*N*/   // Kennung fuer Box erhalten
/*N*/   rNewStr += rFirstBox.GetChar( rFirstBox.Len() - 1 );
/*N*/ }

    // erzeuge die externe (fuer UI) Formel
/*N*/ void SwTableFormula::PtrToBoxNm( const SwTable* pTbl )
/*N*/ {
/*N*/   const SwNode* pNd = 0;
/*N*/   FnScanFormel fnFormel = 0;
/*N*/   switch( eNmType)
/*N*/   {
/*N*/   case INTRNL_NAME:
/*N*/       if( pTbl )
/*N*/           fnFormel = &SwTableFormula::PtrToBoxNms;
/*N*/       break;
/*N*/   case REL_NAME:
/*?*/       break;
/*N*/   case EXTRNL_NAME:
/*N*/       return;
/*N*/   }
/*?*/   sFormel = ScanString( fnFormel, *pTbl, (void*)pNd );
/*?*/   eNmType = EXTRNL_NAME;
/*N*/ }

    // erzeuge die interne (in CORE) Formel
/*N*/ void SwTableFormula::BoxNmToPtr( const SwTable* pTbl )
/*N*/ {
/*N*/   const SwNode* pNd = 0;
/*N*/   FnScanFormel fnFormel = 0;
/*N*/   switch( eNmType)
/*N*/   {
/*N*/   case EXTRNL_NAME:
/*?*/       if( pTbl )
/*?*/           fnFormel = &SwTableFormula::BoxNmsToPtr;
/*?*/       break;
/*?*/   case REL_NAME:
/*?*/       break;
/*?*/   case INTRNL_NAME:
/*?*/       return;
/*N*/   }
/*N*/   sFormel = ScanString( fnFormel, *pTbl, (void*)pNd );
/*N*/   eNmType = INTRNL_NAME;
/*N*/ }

/*N*/ String SwTableFormula::ScanString( FnScanFormel fnFormel, const SwTable& rTbl,
/*N*/                                   void* pPara ) const
/*N*/ {
/*N*/   String aStr;
/*N*/   USHORT nFml = 0, nStt = 0, nEnd = 0, nTrenner;
/*N*/
/*N*/   do {
/*N*/       // falls der Formel ein Name vorangestellt ist, diese Tabelle
/*N*/       // benutzen !!
/*N*/       const SwTable* pTbl = &rTbl;
/*N*/
/*N*/       nStt = sFormel.Search( '<', nFml );
/*N*/       if( STRING_NOTFOUND != nStt )
/*N*/       {
/*N*/           while( STRING_NOTFOUND != nStt &&
/*N*/               ( ' ' == sFormel.GetChar( nStt + 1 ) ||
/*N*/                 '=' == sFormel.GetChar( nStt + 1 ) ) )
/*?*/               nStt = sFormel.Search( '<', nStt + 1 );
/*N*/
/*N*/           if( STRING_NOTFOUND != nStt )
/*N*/               nEnd = sFormel.Search( '>', nStt+1 );
/*N*/       }
/*N*/       if( STRING_NOTFOUND == nStt || STRING_NOTFOUND == nEnd )
/*N*/       {
/*N*/           // den Rest setzen und beenden
/*N*/           aStr.Insert( sFormel, nFml, sFormel.Len() - nFml );
/*N*/           break;
/*N*/       }
/*N*/       aStr.Insert( sFormel, nFml, nStt - nFml );  // Anfang schreiben
/*N*/
/*N*/       if( fnFormel != NULL )
/*N*/       {
/*N*/           // ist ein TabellenName vorangestellt ??
/*N*/           // JP 16.02.99: SplitMergeBoxNm behandeln den Namen selbst
/*N*/           // JP 22.02.99: der CAST muss fuer den Linux-Compiler sein
/*N*/           // JP 28.06.99: rel. BoxName have no preceding tablename!
/*N*/           if( fnFormel != (FnScanFormel)&SwTableFormula::_SplitMergeBoxNm &&
/*N*/               1 < sFormel.Len() && cRelKennung != sFormel.GetChar( 1 ) &&
/*N*/               STRING_NOTFOUND != ( nTrenner = sFormel.Search( '.', nStt ))
/*N*/               && nTrenner < nEnd )
/*N*/           {
/*?*/               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
/*?*/               }
/*N*/           }
/*N*/
/*N*/           String sBox( sFormel.Copy( nStt, nEnd - nStt + 1 ));
/*N*/           // ein Bereich in dieser Klammer ?
/*N*/           if( STRING_NOTFOUND != ( nTrenner = sFormel.Search( ':', nStt ))
/*N*/               && nTrenner < nEnd )
/*N*/           {
/*N*/               // ohne die Anfangsklammer
/*N*/               String aFirstBox( sFormel.Copy( nStt+1, nTrenner - nStt - 1 ));
/*N*/               (this->*fnFormel)( *pTbl, aStr, sBox, &aFirstBox, pPara );
/*N*/           }
/*N*/           else
/*N*/               (this->*fnFormel)( *pTbl, aStr, sBox, 0, pPara );
/*N*/       }
/*N*/
/*N*/       nFml = nEnd+1;
/*N*/   } while( TRUE );
/*N*/   return aStr;
/*N*/ }



/*N*/ const SwFrm* lcl_GetBoxFrm( const SwTableBox& rBox )
/*N*/ {
/*

    // 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() <
    }
*/
/*N*/
/*N*/   SwNodeIndex aIdx( *rBox.GetSttNd() );
/*N*/   SwCntntNode* pCNd = aIdx.GetNodes().GoNext( &aIdx );
/*N*/   OSL_ENSURE( pCNd, "Box hat keinen TextNode" );
/*N*/   Point aPt;      // den im Layout 1. Frame returnen - Tab.Kopfzeile !!
/*N*/   return pCNd->GetFrm( &aPt, NULL, FALSE );
/*N*/ }

/*N*/ void SwTableFormula::GetBoxes( const SwTableBox& rSttBox,
/*N*/                               const SwTableBox& rEndBox,
/*N*/                               SwSelBoxes& rBoxes ) const
/*N*/ {
/*N*/   // hole ueber das Layout alle "selektierten" Boxen
/*N*/   const SwLayoutFrm *pStt, *pEnd;
/*N*/   const SwFrm* pFrm = lcl_GetBoxFrm( rSttBox );
/*N*/   pStt = pFrm ? pFrm->GetUpper() : 0;
/*N*/   pEnd = ( 0 != (pFrm = lcl_GetBoxFrm( rEndBox ))) ? pFrm->GetUpper() : 0;
/*N*/   if( !pStt || !pEnd )
/*?*/       return ;                        // no valid selection
/*N*/
/*N*/   GetTblSel( pStt, pEnd, rBoxes );
/*N*/
/*N*/   const SwTable* pTbl = pStt->FindTabFrm()->GetTable();
/*N*/
/*N*/   // filter die Kopfzeilen-Boxen heraus:
/*N*/   if( pTbl->IsHeadlineRepeat() )
/*N*/       do {    // middle-check loop
/*N*/           const SwTableLine* pHeadLine = pTbl->GetTabLines()[0];
/*N*/           const SwTableLine* pLine = rSttBox.GetUpper();
/*N*/           while( pLine->GetUpper() )
/*?*/               pLine = pLine->GetUpper()->GetUpper();
/*N*/
/*N*/           if( pLine == pHeadLine )
/*?*/               break;      // Headline mit im Bereich !
/*N*/           // vielleicht ist ja Start und Ende vertauscht
/*N*/           pLine = rEndBox.GetUpper();
/*N*/           while ( pLine->GetUpper() )
/*?*/               pLine = pLine->GetUpper()->GetUpper();
/*N*/           if( pLine == pHeadLine )
/*?*/               break;      // Headline mit im Bereich !
/*N*/
/*N*/           const SwTabFrm *pTable = pStt->FindTabFrm();
/*N*/           const SwTabFrm *pEndTable = pEnd->FindTabFrm();
/*N*/           if( pTable == pEndTable )       // keine gespl. Tabelle
/*N*/               break;
/*N*/
/*N*/           // 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 );
/*N*/ }

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
